forked from OSchip/llvm-project
[ARM][MachineOutliner] Emit more CFI instructions
This patch make the outliner emit CFI instructions in a few more places: * after LR is restored, but before the return in an outlined function * around save/restore of LR to/from a register at calls to outlined functions * around save/restore of LR to/from the stack at calls to outlined functions The latter two only when the function does NOT spill LR. If the function spills LR, then outliner generated saves/restores around calls are not considered interesting for unwinding the frame. Differential Revision: https://reviews.llvm.org/D89483
This commit is contained in:
parent
bbc3e03032
commit
937ab6a785
|
@ -6071,7 +6071,7 @@ ARMBaseInstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT,
|
|||
}
|
||||
|
||||
void ARMBaseInstrInfo::saveLROnStack(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator &It) const {
|
||||
MachineBasicBlock::iterator It) const {
|
||||
unsigned Opc = Subtarget.isThumb() ? ARM::t2STR_PRE : ARM::STR_PRE_IMM;
|
||||
int Align = -Subtarget.getStackAlignment().value();
|
||||
BuildMI(MBB, It, DebugLoc(), get(Opc), ARM::SP)
|
||||
|
@ -6081,8 +6081,45 @@ void ARMBaseInstrInfo::saveLROnStack(MachineBasicBlock &MBB,
|
|||
.add(predOps(ARMCC::AL));
|
||||
}
|
||||
|
||||
void ARMBaseInstrInfo::emitCFIForLRSaveOnStack(
|
||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator It) const {
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
const MCRegisterInfo *MRI = Subtarget.getRegisterInfo();
|
||||
unsigned DwarfLR = MRI->getDwarfRegNum(ARM::LR, true);
|
||||
int Align = Subtarget.getStackAlignment().value();
|
||||
// Add a CFI saying the stack was moved down.
|
||||
int64_t StackPosEntry =
|
||||
MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, Align));
|
||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION))
|
||||
.addCFIIndex(StackPosEntry)
|
||||
.setMIFlags(MachineInstr::FrameSetup);
|
||||
|
||||
// Add a CFI saying that the LR that we want to find is now higher than
|
||||
// before.
|
||||
int64_t LRPosEntry =
|
||||
MF.addFrameInst(MCCFIInstruction::createOffset(nullptr, DwarfLR, -Align));
|
||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION))
|
||||
.addCFIIndex(LRPosEntry)
|
||||
.setMIFlags(MachineInstr::FrameSetup);
|
||||
}
|
||||
|
||||
void ARMBaseInstrInfo::emitCFIForLRSaveToReg(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator It,
|
||||
Register Reg) const {
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
const MCRegisterInfo *MRI = Subtarget.getRegisterInfo();
|
||||
unsigned DwarfLR = MRI->getDwarfRegNum(ARM::LR, true);
|
||||
unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true);
|
||||
|
||||
int64_t LRPosEntry = MF.addFrameInst(
|
||||
MCCFIInstruction::createRegister(nullptr, DwarfLR, DwarfReg));
|
||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION))
|
||||
.addCFIIndex(LRPosEntry)
|
||||
.setMIFlags(MachineInstr::FrameSetup);
|
||||
}
|
||||
|
||||
void ARMBaseInstrInfo::restoreLRFromStack(
|
||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator &It) const {
|
||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator It) const {
|
||||
unsigned Opc = Subtarget.isThumb() ? ARM::t2LDR_POST : ARM::LDR_POST_IMM;
|
||||
MachineInstrBuilder MIB = BuildMI(MBB, It, DebugLoc(), get(Opc), ARM::LR)
|
||||
.addReg(ARM::SP, RegState::Define)
|
||||
|
@ -6092,6 +6129,39 @@ void ARMBaseInstrInfo::restoreLRFromStack(
|
|||
MIB.addImm(Subtarget.getStackAlignment().value()).add(predOps(ARMCC::AL));
|
||||
}
|
||||
|
||||
void ARMBaseInstrInfo::emitCFIForLRRestoreFromStack(
|
||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator It) const {
|
||||
// Now stack has moved back up...
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
const MCRegisterInfo *MRI = Subtarget.getRegisterInfo();
|
||||
unsigned DwarfLR = MRI->getDwarfRegNum(ARM::LR, true);
|
||||
int64_t StackPosEntry =
|
||||
MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, 0));
|
||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION))
|
||||
.addCFIIndex(StackPosEntry)
|
||||
.setMIFlags(MachineInstr::FrameDestroy);
|
||||
|
||||
// ... and we have restored LR.
|
||||
int64_t LRPosEntry =
|
||||
MF.addFrameInst(MCCFIInstruction::createRestore(nullptr, DwarfLR));
|
||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION))
|
||||
.addCFIIndex(LRPosEntry)
|
||||
.setMIFlags(MachineInstr::FrameDestroy);
|
||||
}
|
||||
|
||||
void ARMBaseInstrInfo::emitCFIForLRRestoreFromReg(
|
||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator It) const {
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
const MCRegisterInfo *MRI = Subtarget.getRegisterInfo();
|
||||
unsigned DwarfLR = MRI->getDwarfRegNum(ARM::LR, true);
|
||||
|
||||
int64_t LRPosEntry =
|
||||
MF.addFrameInst(MCCFIInstruction::createRestore(nullptr, DwarfLR));
|
||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION))
|
||||
.addCFIIndex(LRPosEntry)
|
||||
.setMIFlags(MachineInstr::FrameDestroy);
|
||||
}
|
||||
|
||||
void ARMBaseInstrInfo::buildOutlinedFrame(
|
||||
MachineBasicBlock &MBB, MachineFunction &MF,
|
||||
const outliner::OutlinedFunction &OF) const {
|
||||
|
@ -6133,28 +6203,11 @@ void ARMBaseInstrInfo::buildOutlinedFrame(
|
|||
|
||||
// Insert a save before the outlined region
|
||||
saveLROnStack(MBB, It);
|
||||
|
||||
unsigned StackAlignment = Subtarget.getStackAlignment().value();
|
||||
const TargetSubtargetInfo &STI = MF.getSubtarget();
|
||||
const MCRegisterInfo *MRI = STI.getRegisterInfo();
|
||||
unsigned DwarfReg = MRI->getDwarfRegNum(ARM::LR, true);
|
||||
// Add a CFI saying the stack was moved down.
|
||||
int64_t StackPosEntry = MF.addFrameInst(
|
||||
MCCFIInstruction::cfiDefCfaOffset(nullptr, StackAlignment));
|
||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION))
|
||||
.addCFIIndex(StackPosEntry)
|
||||
.setMIFlags(MachineInstr::FrameSetup);
|
||||
|
||||
// Add a CFI saying that the LR that we want to find is now higher than
|
||||
// before.
|
||||
int64_t LRPosEntry = MF.addFrameInst(
|
||||
MCCFIInstruction::createOffset(nullptr, DwarfReg, StackAlignment));
|
||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION))
|
||||
.addCFIIndex(LRPosEntry)
|
||||
.setMIFlags(MachineInstr::FrameSetup);
|
||||
emitCFIForLRSaveOnStack(MBB, It);
|
||||
|
||||
// Insert a restore before the terminator for the function. Restore LR.
|
||||
restoreLRFromStack(MBB, Et);
|
||||
emitCFIForLRRestoreFromStack(MBB, Et);
|
||||
}
|
||||
|
||||
// If this is a tail call outlined function, then there's already a return.
|
||||
|
@ -6204,6 +6257,7 @@ MachineBasicBlock::iterator ARMBaseInstrInfo::insertOutlinedCall(
|
|||
return It;
|
||||
}
|
||||
|
||||
const ARMFunctionInfo &AFI = *C.getMF()->getInfo<ARMFunctionInfo>();
|
||||
// Can we save to a register?
|
||||
if (C.CallConstructionID == MachineOutlinerRegSave) {
|
||||
unsigned Reg = findRegisterToSaveLRTo(C);
|
||||
|
@ -6211,15 +6265,23 @@ MachineBasicBlock::iterator ARMBaseInstrInfo::insertOutlinedCall(
|
|||
|
||||
// Save and restore LR from that register.
|
||||
copyPhysReg(MBB, It, DebugLoc(), Reg, ARM::LR, true);
|
||||
if (!AFI.isLRSpilled())
|
||||
emitCFIForLRSaveToReg(MBB, It, Reg);
|
||||
CallPt = MBB.insert(It, CallMIB);
|
||||
copyPhysReg(MBB, It, DebugLoc(), ARM::LR, Reg, true);
|
||||
if (!AFI.isLRSpilled())
|
||||
emitCFIForLRRestoreFromReg(MBB, It);
|
||||
It--;
|
||||
return CallPt;
|
||||
}
|
||||
// We have the default case. Save and restore from SP.
|
||||
saveLROnStack(MBB, It);
|
||||
if (!AFI.isLRSpilled())
|
||||
emitCFIForLRSaveOnStack(MBB, It);
|
||||
CallPt = MBB.insert(It, CallMIB);
|
||||
restoreLRFromStack(MBB, It);
|
||||
if (!AFI.isLRSpilled())
|
||||
emitCFIForLRRestoreFromStack(MBB, It);
|
||||
It--;
|
||||
return CallPt;
|
||||
}
|
||||
|
|
|
@ -368,12 +368,33 @@ private:
|
|||
// Adds an instruction which saves the link register on top of the stack into
|
||||
/// the MachineBasicBlock \p MBB at position \p It.
|
||||
void saveLROnStack(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator &It) const;
|
||||
MachineBasicBlock::iterator It) const;
|
||||
|
||||
/// Adds an instruction which restores the link register from the top the
|
||||
/// stack into the MachineBasicBlock \p MBB at position \p It.
|
||||
void restoreLRFromStack(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator &It) const;
|
||||
MachineBasicBlock::iterator It) const;
|
||||
|
||||
/// Emit CFI instructions into the MachineBasicBlock \p MBB at position \p It,
|
||||
/// for the case when the LR is saved on the stack.
|
||||
void emitCFIForLRSaveOnStack(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator It) const;
|
||||
|
||||
/// Emit CFI instructions into the MachineBasicBlock \p MBB at position \p It,
|
||||
/// for the case when the LR is saved in the register \p Reg.
|
||||
void emitCFIForLRSaveToReg(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator It,
|
||||
Register Reg) const;
|
||||
|
||||
/// Emit CFI instructions into the MachineBasicBlock \p MBB at position \p It,
|
||||
/// after the LR is was restored from the stack.
|
||||
void emitCFIForLRRestoreFromStack(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator It) const;
|
||||
|
||||
/// Emit CFI instructions into the MachineBasicBlock \p MBB at position \p It,
|
||||
/// after the LR is was restored from a register.
|
||||
void emitCFIForLRRestoreFromReg(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator It) const;
|
||||
|
||||
unsigned getInstBundleLength(const MachineInstr &MI) const;
|
||||
|
||||
|
|
|
@ -295,7 +295,7 @@ body: |
|
|||
; CHECK: liveins: $r11, $r10, $r9, $r8, $r7, $r6, $r5, $d15, $d14, $d13, $d12, $d11, $d10, $d9, $d8, $lr
|
||||
; CHECK: early-clobber $sp = STR_PRE_IMM killed $lr, $sp, -8, 14 /* CC::al */, $noreg
|
||||
; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 8
|
||||
; CHECK: frame-setup CFI_INSTRUCTION offset $lr, 8
|
||||
; CHECK: frame-setup CFI_INSTRUCTION offset $lr, -8
|
||||
; CHECK: BL @bar, implicit-def dead $lr, implicit $sp
|
||||
; CHECK: $r0 = MOVi 1, 14 /* CC::al */, $noreg, $noreg
|
||||
; CHECK: $r1 = MOVi 1, 14 /* CC::al */, $noreg, $noreg
|
||||
|
@ -320,7 +320,7 @@ body: |
|
|||
; CHECK: liveins: $r11, $r10, $r9, $r8, $r7, $r6, $r5, $d15, $d14, $d13, $d12, $d11, $d10, $d9, $d8, $lr
|
||||
; CHECK: early-clobber $sp = STR_PRE_IMM killed $lr, $sp, -8, 14 /* CC::al */, $noreg
|
||||
; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 8
|
||||
; CHECK: frame-setup CFI_INSTRUCTION offset $lr, 8
|
||||
; CHECK: frame-setup CFI_INSTRUCTION offset $lr, -8
|
||||
; CHECK: BL @bar, implicit-def dead $lr, implicit $sp
|
||||
; CHECK: $r0 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
|
||||
; CHECK: $r1 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
|
||||
|
@ -335,7 +335,7 @@ body: |
|
|||
; CHECK: liveins: $r11, $r10, $r9, $r8, $r6, $r5, $r4, $d15, $d14, $d13, $d12, $d11, $d10, $d9, $d8, $lr
|
||||
; CHECK: early-clobber $sp = t2STR_PRE killed $lr, $sp, -8, 14 /* CC::al */, $noreg
|
||||
; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 8
|
||||
; CHECK: frame-setup CFI_INSTRUCTION offset $lr, 8
|
||||
; CHECK: frame-setup CFI_INSTRUCTION offset $lr, -8
|
||||
; CHECK: tBL 14 /* CC::al */, $noreg, @bar, implicit-def dead $lr, implicit $sp
|
||||
; CHECK: $r0 = t2MOVi 1, 14 /* CC::al */, $noreg, $noreg
|
||||
; CHECK: $r1 = t2MOVi 1, 14 /* CC::al */, $noreg, $noreg
|
||||
|
@ -348,7 +348,7 @@ body: |
|
|||
; CHECK: liveins: $r11, $r10, $r9, $r8, $r6, $r5, $r4, $d15, $d14, $d13, $d12, $d11, $d10, $d9, $d8, $lr
|
||||
; CHECK: early-clobber $sp = t2STR_PRE killed $lr, $sp, -8, 14 /* CC::al */, $noreg
|
||||
; CHECK: frame-setup CFI_INSTRUCTION def_cfa_offset 8
|
||||
; CHECK: frame-setup CFI_INSTRUCTION offset $lr, 8
|
||||
; CHECK: frame-setup CFI_INSTRUCTION offset $lr, -8
|
||||
; CHECK: tBL 14 /* CC::al */, $noreg, @bar, implicit-def dead $lr, implicit $sp
|
||||
; CHECK: $r0 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg
|
||||
; CHECK: $r1 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
; RUN: llc --verify-machineinstrs --force-dwarf-frame-section %s -o - | FileCheck %s
|
||||
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
target triple = "thumbv7m-unknown-unknown-eabi"
|
||||
|
||||
; Derived from
|
||||
; volatile int a, b, c, d, e, f, g, h;
|
||||
;
|
||||
; int x() {
|
||||
; int r = (a + b) / (c + d) + e + f;
|
||||
; return r + 1;
|
||||
; }
|
||||
;
|
||||
;
|
||||
; int y() {
|
||||
; int r = (a + b) / (c + d) + e + f;
|
||||
; return r + 2;
|
||||
; }
|
||||
; Checks that CFI instruction are emitted around saves/restores of
|
||||
; the LR on stack.
|
||||
|
||||
@a = dso_local global i32 0, align 4
|
||||
@b = dso_local global i32 0, align 4
|
||||
@c = dso_local global i32 0, align 4
|
||||
@d = dso_local global i32 0, align 4
|
||||
@e = dso_local global i32 0, align 4
|
||||
@f = dso_local global i32 0, align 4
|
||||
|
||||
define dso_local i32 @x() local_unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = load volatile i32, i32* @a, align 4
|
||||
%1 = load volatile i32, i32* @b, align 4
|
||||
%add = add nsw i32 %1, %0
|
||||
%2 = load volatile i32, i32* @c, align 4
|
||||
%3 = load volatile i32, i32* @d, align 4
|
||||
%add1 = add nsw i32 %3, %2
|
||||
%div = sdiv i32 %add, %add1
|
||||
%4 = load volatile i32, i32* @e, align 4
|
||||
%5 = load volatile i32, i32* @f, align 4
|
||||
%add2 = add i32 %div, 1
|
||||
%add3 = add i32 %add2, %4
|
||||
%add4 = add i32 %add3, %5
|
||||
ret i32 %add4
|
||||
}
|
||||
; CHECK-LABEL: x:
|
||||
; CHECK: str lr, [sp, #-8]!
|
||||
; CHECK-NEXT: .cfi_def_cfa_offset 8
|
||||
; CHECK-NEXT: .cfi_offset lr, -8
|
||||
; CHECK-NEXT: bl OUTLINED_FUNCTION_0
|
||||
; CHECK-NEXT: ldr lr, [sp], #8
|
||||
; CHECK-NEXT: .cfi_def_cfa_offset 0
|
||||
; CHECK-NEXT: .cfi_restore lr
|
||||
|
||||
define dso_local i32 @y() local_unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = load volatile i32, i32* @a, align 4
|
||||
%1 = load volatile i32, i32* @b, align 4
|
||||
%add = add nsw i32 %1, %0
|
||||
%2 = load volatile i32, i32* @c, align 4
|
||||
%3 = load volatile i32, i32* @d, align 4
|
||||
%add1 = add nsw i32 %3, %2
|
||||
%div = sdiv i32 %add, %add1
|
||||
%4 = load volatile i32, i32* @e, align 4
|
||||
%5 = load volatile i32, i32* @f, align 4
|
||||
%add2 = add i32 %div, 2
|
||||
%add3 = add i32 %add2, %4
|
||||
%add4 = add i32 %add3, %5
|
||||
ret i32 %add4
|
||||
}
|
||||
; CHECK-LABEL: y:
|
||||
; CHECK: str lr, [sp, #-8]!
|
||||
; CHECK-NEXT: .cfi_def_cfa_offset 8
|
||||
; CHECK-NEXT: .cfi_offset lr, -8
|
||||
; CHECK-NEXT: bl OUTLINED_FUNCTION_0
|
||||
; CHECK-NEXT: ldr lr, [sp], #8
|
||||
; CHECK-NEXT: .cfi_def_cfa_offset 0
|
||||
; CHECK-NEXT: .cfi_restore lr
|
||||
|
||||
attributes #0 = { minsize nofree norecurse nounwind optsize }
|
|
@ -0,0 +1,73 @@
|
|||
; RUN: llc --verify-machineinstrs --force-dwarf-frame-section %s -o - | FileCheck %s
|
||||
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
target triple = "thumbv7m-unknown-unknown-eabi"
|
||||
|
||||
; Derived from
|
||||
; volatile int a, b, c, d, e, f, g, h;
|
||||
;
|
||||
; int x() {
|
||||
; int r = a + b + c + d + e + f;
|
||||
; return r + 1;
|
||||
; }
|
||||
;
|
||||
;
|
||||
; int y() {
|
||||
; int r = a + b + c + d + e + f;
|
||||
; return r + 2;
|
||||
; }
|
||||
; Check CFI instructions when LR is saved/restored to/from a register.
|
||||
|
||||
@a = dso_local global i32 0, align 4
|
||||
@b = dso_local global i32 0, align 4
|
||||
@c = dso_local global i32 0, align 4
|
||||
@d = dso_local global i32 0, align 4
|
||||
@e = dso_local global i32 0, align 4
|
||||
@f = dso_local global i32 0, align 4
|
||||
|
||||
define dso_local i32 @x() local_unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = load volatile i32, i32* @a, align 4
|
||||
%1 = load volatile i32, i32* @b, align 4
|
||||
%2 = load volatile i32, i32* @c, align 4
|
||||
%3 = load volatile i32, i32* @d, align 4
|
||||
%4 = load volatile i32, i32* @e, align 4
|
||||
%5 = load volatile i32, i32* @f, align 4
|
||||
%add = add i32 %0, 1
|
||||
%add1 = add i32 %add, %1
|
||||
%add2 = add i32 %add1, %2
|
||||
%add3 = add i32 %add2, %3
|
||||
%add4 = add i32 %add3, %4
|
||||
%add5 = add i32 %add4, %5
|
||||
ret i32 %add5
|
||||
}
|
||||
; CHECK-LABEL: x:
|
||||
; CHECK: mov r3, lr
|
||||
; CHECK-NEXT: .cfi_register lr, r3
|
||||
; CHECK-NEXT: bl OUTLINED_FUNCTION_0
|
||||
; CHECK-NEXT: mov lr, r3
|
||||
; CHECK-NEXT: .cfi_restore lr
|
||||
|
||||
define dso_local i32 @y() local_unnamed_addr #0 {
|
||||
entry:
|
||||
%0 = load volatile i32, i32* @a, align 4
|
||||
%1 = load volatile i32, i32* @b, align 4
|
||||
%2 = load volatile i32, i32* @c, align 4
|
||||
%3 = load volatile i32, i32* @d, align 4
|
||||
%4 = load volatile i32, i32* @e, align 4
|
||||
%5 = load volatile i32, i32* @f, align 4
|
||||
%add = add i32 %0, 2
|
||||
%add1 = add i32 %add, %1
|
||||
%add2 = add i32 %add1, %2
|
||||
%add3 = add i32 %add2, %3
|
||||
%add4 = add i32 %add3, %4
|
||||
%add5 = add i32 %add4, %5
|
||||
ret i32 %add5
|
||||
}
|
||||
; CHECK-LABEL: y:
|
||||
; CHECK: mov r3, lr
|
||||
; CHECK-NEXT: .cfi_register lr, r3
|
||||
; CHECK-NEXT: bl OUTLINED_FUNCTION_0
|
||||
; CHECK-NEXT: mov lr, r3
|
||||
; CHECK-NEXT: .cfi_restore lr
|
||||
|
||||
attributes #0 = { minsize nofree norecurse nounwind optsize }
|
|
@ -0,0 +1,78 @@
|
|||
; RUN: llc --verify-machineinstrs --force-dwarf-frame-section %s -o - | FileCheck %s
|
||||
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
|
||||
target triple = "thumbv7m-unknown-unknown-eabi"
|
||||
|
||||
; Derived from
|
||||
; __attribute__((noinline)) int h(int a, int b) { return a + b; }
|
||||
;
|
||||
; int f(int a, int b, int c, int d) {
|
||||
; if (a < 0)
|
||||
; return -1;
|
||||
; a = h(a, b);
|
||||
; return 2 + a * (a + b) / (c + d);
|
||||
; }
|
||||
;
|
||||
; int g(int a, int b, int c, int d) {
|
||||
; if (a < 0)
|
||||
; return -1;
|
||||
; a = h(a, b);
|
||||
; return 1 + a * (a + b) / (c + d);
|
||||
; }
|
||||
; Check CFI instructions inside the outlined function.
|
||||
|
||||
define dso_local i32 @h(i32 %a, i32 %b) local_unnamed_addr #0 {
|
||||
entry:
|
||||
%add = add nsw i32 %b, %a
|
||||
ret i32 %add
|
||||
}
|
||||
|
||||
define dso_local i32 @f(i32 %a, i32 %b, i32 %c, i32 %d) local_unnamed_addr #1 {
|
||||
entry:
|
||||
%cmp = icmp slt i32 %a, 0
|
||||
br i1 %cmp, label %return, label %if.end
|
||||
|
||||
if.end: ; preds = %entry
|
||||
%call = tail call i32 @h(i32 %a, i32 %b) #2
|
||||
%add = add nsw i32 %call, %b
|
||||
%mul = mul nsw i32 %add, %call
|
||||
%add1 = add nsw i32 %d, %c
|
||||
%div = sdiv i32 %mul, %add1
|
||||
%add2 = add nsw i32 %div, 2
|
||||
br label %return
|
||||
|
||||
return: ; preds = %entry, %if.end
|
||||
%retval.0 = phi i32 [ %add2, %if.end ], [ -1, %entry ]
|
||||
ret i32 %retval.0
|
||||
}
|
||||
|
||||
define dso_local i32 @g(i32 %a, i32 %b, i32 %c, i32 %d) local_unnamed_addr #1 {
|
||||
entry:
|
||||
%cmp = icmp slt i32 %a, 0
|
||||
br i1 %cmp, label %return, label %if.end
|
||||
|
||||
if.end: ; preds = %entry
|
||||
%call = tail call i32 @h(i32 %a, i32 %b) #2
|
||||
%add = add nsw i32 %call, %b
|
||||
%mul = mul nsw i32 %add, %call
|
||||
%add1 = add nsw i32 %d, %c
|
||||
%div = sdiv i32 %mul, %add1
|
||||
%add2 = add nsw i32 %div, 1
|
||||
br label %return
|
||||
|
||||
return: ; preds = %entry, %if.end
|
||||
%retval.0 = phi i32 [ %add2, %if.end ], [ -1, %entry ]
|
||||
ret i32 %retval.0
|
||||
}
|
||||
|
||||
; CHECK-LABEL: OUTLINED_FUNCTION_0:
|
||||
; CHECK: str lr, [sp, #-8]!
|
||||
; CHECK-NEXT: .cfi_def_cfa_offset 8
|
||||
; CHECK-NEXT: .cfi_offset lr, -8
|
||||
; CHECK: ldr lr, [sp], #8
|
||||
; CHECK-NEXT: .cfi_def_cfa_offset 0
|
||||
; CHECK-NEXT: .cfi_restore lr
|
||||
; CHECK-NEXT: bx lr
|
||||
|
||||
attributes #0 = { minsize noinline norecurse nounwind optsize readnone }
|
||||
attributes #1 = { minsize norecurse nounwind optsize readnone }
|
||||
attributes #2 = { minsize optsize }
|
Loading…
Reference in New Issue