forked from OSchip/llvm-project
MipsDelaySlotFiller: Don't move BUNDLE instructions into the delay slot
Summary: In our CHERI fork we use BUNDLE instructions to ensure that a three-instruction sequence to generate a program-counter-relative value is emitted without reordering or insertions (since that would break the 32-bit offset computation). This sequence is created in MipsExpandPseudo and we use finalizeBundle() to create the BUNDLE instruction. However, the delay slot filler currently breaks this pattern since the BUNDLE will be removed and so all instructions are moved into the delay slot. Since the delay slot only executes the first instruction, this results in incorrect computations (and run-time crashes) if the branch is taken. The original test cases uses CHERI instructions, so for the test case here I simple filled a BUNDLE with a no-op DADDiu $sp_64, -16 and DADDiu $sp_64, 16. Reviewers: atanasyan Reviewed By: atanasyan Subscribers: merge_guards_bot, sdardis, hiraditya, jrtc27, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D70944
This commit is contained in:
parent
0cc4b95985
commit
b91f239485
|
@ -695,6 +695,12 @@ bool MipsDelaySlotFiller::searchRange(MachineBasicBlock &MBB, IterTy Begin,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (CurrI->isBundle()) {
|
||||
LLVM_DEBUG(dbgs() << DEBUG_TYPE ": ignoring BUNDLE instruction: ";
|
||||
CurrI->dump());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (terminateSearch(*CurrI)) {
|
||||
LLVM_DEBUG(dbgs() << DEBUG_TYPE ": should terminate search: ";
|
||||
CurrI->dump());
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
## Check that the delay-slot filler does not attempt to split BUNDLE instructions
|
||||
# RUN: llc %s -start-before=mips-delay-slot-filler -stop-after=mips-delay-slot-filler \
|
||||
# RUN: -verify-machineinstrs -o - | FileCheck %s
|
||||
--- |
|
||||
target datalayout = "E-m:e-i8:8:32-i16:16:32-i64:64-n32:64-S128"
|
||||
target triple = "mips64-unknown-freebsd"
|
||||
declare i8* @func_a(i64 zeroext)
|
||||
declare i8* @func_b(i64 zeroext)
|
||||
; Function Attrs: nounwind
|
||||
define i8* @test(i64 zeroext %nbytes) local_unnamed_addr #0 {
|
||||
entry:
|
||||
%cmp = icmp eq i64 %nbytes, 0
|
||||
br i1 %cmp, label %if.else, label %if.then
|
||||
|
||||
if.then: ; preds = %entry
|
||||
%call = tail call i8* @func_a(i64 zeroext %nbytes)
|
||||
br label %return
|
||||
|
||||
if.else: ; preds = %entry
|
||||
%call1 = tail call i8* @func_b(i64 zeroext 0)
|
||||
br label %return
|
||||
|
||||
return: ; preds = %if.else, %if.then
|
||||
%retval.0 = phi i8* [ %call, %if.then ], [ %call1, %if.else ]
|
||||
ret i8* %retval.0
|
||||
}
|
||||
; Function Attrs: nounwind
|
||||
declare void @llvm.stackprotector(i8*, i8**) #0
|
||||
|
||||
attributes #0 = { nounwind }
|
||||
|
||||
...
|
||||
---
|
||||
name: test
|
||||
alignment: 8
|
||||
exposesReturnsTwice: false
|
||||
legalized: false
|
||||
regBankSelected: false
|
||||
selected: false
|
||||
failedISel: false
|
||||
tracksRegLiveness: true
|
||||
hasWinCFI: false
|
||||
registers: []
|
||||
liveins:
|
||||
- { reg: '$a0_64', virtual-reg: '' }
|
||||
frameInfo:
|
||||
isFrameAddressTaken: false
|
||||
isReturnAddressTaken: false
|
||||
hasStackMap: false
|
||||
hasPatchPoint: false
|
||||
stackSize: 16
|
||||
offsetAdjustment: 0
|
||||
maxAlignment: 8
|
||||
adjustsStack: true
|
||||
hasCalls: true
|
||||
stackProtector: ''
|
||||
maxCallFrameSize: 0
|
||||
cvBytesOfCalleeSavedRegisters: 0
|
||||
hasOpaqueSPAdjustment: false
|
||||
hasVAStart: false
|
||||
hasMustTailInVarArgFunc: false
|
||||
localFrameSize: 0
|
||||
savePoint: ''
|
||||
restorePoint: ''
|
||||
fixedStack: []
|
||||
stack:
|
||||
- { id: 0, name: '', type: spill-slot, offset: -8, size: 8, alignment: 8,
|
||||
stack-id: default, callee-saved-register: '$ra_64', callee-saved-restored: true,
|
||||
debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
|
||||
callSites: []
|
||||
constants: []
|
||||
machineFunctionInfo: {}
|
||||
body: |
|
||||
; CHECK-LABEL: name: test
|
||||
; CHECK: bb.0.entry:
|
||||
; CHECK: successors: %bb.2(0x30000000), %bb.1(0x50000000)
|
||||
; CHECK: $sp_64 = DADDiu $sp_64, -16
|
||||
; CHECK: CFI_INSTRUCTION def_cfa_offset 16
|
||||
; CHECK: SD killed $ra_64, $sp_64, 8 :: (store 8 into %stack.0)
|
||||
; CHECK: CFI_INSTRUCTION offset $ra_64, -8
|
||||
; CHECK: BUNDLE {
|
||||
; CHECK: $sp_64 = DADDiu $sp_64, -16
|
||||
; CHECK: $sp_64 = DADDiu $sp_64, 16
|
||||
; CHECK: }
|
||||
; CHECK: BEQ64 renamable $a0_64, $zero_64, %bb.2, implicit-def $at {
|
||||
; CHECK: NOP
|
||||
; CHECK: }
|
||||
; CHECK: bb.1.if.then:
|
||||
; CHECK: successors: %bb.3(0x80000000)
|
||||
; CHECK: JAL @func_a, csr_n64, implicit-def dead $ra, implicit $a0_64, implicit-def $sp, implicit-def $v0_64 {
|
||||
; CHECK: NOP
|
||||
; CHECK: }
|
||||
; CHECK: J %bb.3, implicit-def dead $at {
|
||||
; CHECK: NOP
|
||||
; CHECK: }
|
||||
; CHECK: bb.2.if.else:
|
||||
; CHECK: successors: %bb.3(0x80000000)
|
||||
; CHECK: JAL @func_b, csr_n64, implicit-def dead $ra, implicit $a0_64, implicit-def $sp, implicit-def $v0_64 {
|
||||
; CHECK: $a0_64 = DADDiu $zero_64, 0
|
||||
; CHECK: }
|
||||
; CHECK: bb.3.return:
|
||||
; CHECK: $ra_64 = LD $sp_64, 8 :: (load 8 from %stack.0)
|
||||
; CHECK: PseudoReturn64 undef $ra_64, implicit $v0_64 {
|
||||
; CHECK: $sp_64 = DADDiu $sp_64, 16
|
||||
; CHECK: }
|
||||
bb.0.entry:
|
||||
successors: %bb.2(0x30000000), %bb.1(0x50000000)
|
||||
liveins: $a0_64, $ra_64
|
||||
|
||||
$sp_64 = DADDiu $sp_64, -16
|
||||
CFI_INSTRUCTION def_cfa_offset 16
|
||||
SD killed $ra_64, $sp_64, 8 :: (store 8 into %stack.0)
|
||||
CFI_INSTRUCTION offset $ra_64, -8
|
||||
; This BUNDLE instruction must not be split by the delay slot filler:
|
||||
BUNDLE {
|
||||
$sp_64 = DADDiu $sp_64, -16
|
||||
$sp_64 = DADDiu $sp_64, 16
|
||||
}
|
||||
BEQ64 renamable $a0_64, $zero_64, %bb.2, implicit-def $at
|
||||
|
||||
bb.1.if.then:
|
||||
successors: %bb.3(0x80000000)
|
||||
liveins: $a0_64
|
||||
|
||||
JAL @func_a, csr_n64, implicit-def dead $ra, implicit $a0_64, implicit-def $sp, implicit-def $v0_64
|
||||
J %bb.3, implicit-def dead $at
|
||||
|
||||
bb.2.if.else:
|
||||
successors: %bb.3(0x80000000)
|
||||
|
||||
$a0_64 = DADDiu $zero_64, 0
|
||||
JAL @func_b, csr_n64, implicit-def dead $ra, implicit $a0_64, implicit-def $sp, implicit-def $v0_64
|
||||
|
||||
bb.3.return:
|
||||
liveins: $v0_64
|
||||
|
||||
$ra_64 = LD $sp_64, 8 :: (load 8 from %stack.0)
|
||||
$sp_64 = DADDiu $sp_64, 16
|
||||
PseudoReturn64 undef $ra_64, implicit $v0_64
|
||||
|
||||
...
|
Loading…
Reference in New Issue