NumBytesToCreateFrame, FrameID);
}
+bool ARMBaseInstrInfo::checkAndUpdateStackOffset(MachineInstr *MI,
+ int64_t Fixup,
+ bool Updt) const {
+ int SPIdx = MI->findRegisterUseOperandIdx(ARM::SP);
+ unsigned AddrMode = (MI->getDesc().TSFlags & ARMII::AddrModeMask);
+ if (SPIdx < 0)
+ // No SP operand
+ return true;
+ else if (SPIdx != 1 && (AddrMode != ARMII::AddrModeT2_i8s4 || SPIdx != 2))
+ // If SP is not the base register we can't do much
+ return false;
+
+ // Stack might be involved but addressing mode doesn't handle any offset.
+ // Rq: AddrModeT1_[1|2|4] don't operate on SP
+ if (AddrMode == ARMII::AddrMode1 // Arithmetic instructions
+ || AddrMode == ARMII::AddrMode4 // Load/Store Multiple
+ || AddrMode == ARMII::AddrMode6 // Neon Load/Store Multiple
+ || AddrMode == ARMII::AddrModeT2_so // SP can't be used as based register
+ || AddrMode == ARMII::AddrModeT2_pc // PCrel access
+ || AddrMode == ARMII::AddrMode2 // Used by PRE and POST indexed LD/ST
+ || AddrMode == ARMII::AddrModeNone)
+ return false;
+
+ unsigned NumOps = MI->getDesc().getNumOperands();
+ unsigned ImmIdx = NumOps - 3;
+
+ const MachineOperand &Offset = MI->getOperand(ImmIdx);
+ assert(Offset.isImm() && "Is not an immediate");
+ int64_t OffVal = Offset.getImm();
+
+ if (OffVal < 0)
+ // Don't override data if the are below SP.
+ return false;
+
+ unsigned NumBits = 0;
+ unsigned Scale = 1;
+
+ switch (AddrMode) {
+ case ARMII::AddrMode3:
+ if (ARM_AM::getAM3Op(OffVal) == ARM_AM::sub)
+ return false;
+ OffVal = ARM_AM::getAM3Offset(OffVal);
+ NumBits = 8;
+ break;
+ case ARMII::AddrMode5:
+ if (ARM_AM::getAM5Op(OffVal) == ARM_AM::sub)
+ return false;
+ OffVal = ARM_AM::getAM5Offset(OffVal);
+ NumBits = 8;
+ Scale = 4;
+ break;
+ case ARMII::AddrMode5FP16:
+ if (ARM_AM::getAM5FP16Op(OffVal) == ARM_AM::sub)
+ return false;
+ OffVal = ARM_AM::getAM5FP16Offset(OffVal);
+ NumBits = 8;
+ Scale = 2;
+ break;
+ case ARMII::AddrModeT2_i8:
+ NumBits = 8;
+ break;
+ case ARMII::AddrModeT2_i8s4:
+ case ARMII::AddrModeT2_ldrex:
+ NumBits = 8;
+ Scale = 4;
+ break;
+ case ARMII::AddrModeT2_i12:
+ case ARMII::AddrMode_i12:
+ NumBits = 12;
+ break;
+ case ARMII::AddrModeT2_i7:
+ NumBits = 7;
+ break;
+ case ARMII::AddrModeT2_i7s2:
+ NumBits = 7;
+ Scale = 2;
+ break;
+ case ARMII::AddrModeT2_i7s4:
+ NumBits = 7;
+ Scale = 4;
+ break;
+ case ARMII::AddrModeT1_s: // SP-relative LD/ST
+ NumBits = 8;
+ Scale = 4;
+ break;
+ default:
+ llvm_unreachable("Unsupported addressing mode!");
+ }
+ // Make sure the offset is encodable for instructions that scale the
+ // immediate.
+ if (((OffVal * Scale + Fixup) & (Scale - 1)) != 0)
+ return false;
+ OffVal += Fixup / Scale;
+
+ unsigned Mask = (1 << NumBits) - 1;
+
+ if (OffVal <= Mask) {
+ if (Updt)
+ MI->getOperand(ImmIdx).setImm(OffVal);
+ return true;
+ }
+
+ return false;
+
+}
+
bool ARMBaseInstrInfo::isFunctionSafeToOutlineFrom(
MachineFunction &MF, bool OutlineFromLinkOnceODRs) const {
const Function &F = MF.getFunction();
if (!MightNeedStackFixUp)
return outliner::InstrType::Legal;
+ // Any modification of SP will break our code to save/restore LR.
+ // FIXME: We could handle some instructions which add a constant offset to
+ // SP, with a bit more work.
+ if (MI.modifiesRegister(ARM::SP, TRI))
+ return outliner::InstrType::Illegal;
+
+ // At this point, we have a stack instruction that we might need to fix up.
+ // up. We'll handle it if it's a load or store.
+ if (checkAndUpdateStackOffset(&MI, Subtarget.getStackAlignment().value(),
+ false))
+ return outliner::InstrType::Legal;
+
+ // We can't fix it up, so don't outline it.
return outliner::InstrType::Illegal;
}
return outliner::InstrType::Legal;
}
+void ARMBaseInstrInfo::fixupPostOutline(MachineBasicBlock &MBB) const {
+ for (MachineInstr &MI : MBB) {
+ checkAndUpdateStackOffset(&MI, Subtarget.getStackAlignment().value(), true);
+ }
+}
+
void ARMBaseInstrInfo::saveLROnStack(MachineBasicBlock &MBB,
MachineBasicBlock::iterator It) const {
unsigned Opc = Subtarget.isThumb() ? ARM::t2STR_PRE : ARM::STR_PRE_IMM;
saveLROnStack(MBB, It);
emitCFIForLRSaveOnStack(MBB, It);
+ // Fix up the instructions in the range, since we're going to modify the
+ // stack.
+ assert(OF.FrameConstructionID != MachineOutlinerDefault &&
+ "Can only fix up stack references once");
+ fixupPostOutline(MBB);
+
// Insert a restore before the terminator for the function. Restore LR.
restoreLRFromStack(MBB, Et);
emitCFIForLRRestoreFromStack(MBB, Et);
// current feature set.
BuildMI(MBB, MBB.end(), DebugLoc(), get(Subtarget.getReturnOpcode()))
.add(predOps(ARMCC::AL));
+
+ // Did we have to modify the stack by saving the link register?
+ if (OF.FrameConstructionID != MachineOutlinerDefault &&
+ OF.Candidates[0].CallConstructionID != MachineOutlinerDefault)
+ return;
+
+ // We modified the stack.
+ // Walk over the basic block and fix up all the stack accesses.
+ fixupPostOutline(MBB);
}
MachineBasicBlock::iterator ARMBaseInstrInfo::insertOutlinedCall(
return CallPt;
}
// We have the default case. Save and restore from SP.
+ if (!MBB.isLiveIn(ARM::LR))
+ MBB.addLiveIn(ARM::LR);
saveLROnStack(MBB, It);
if (!AFI.isLRSpilled())
emitCFIForLRSaveOnStack(MBB, It);
/// after the LR is was restored from a register.
void emitCFIForLRRestoreFromReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator It) const;
+ /// \brief Sets the offsets on outlined instructions in \p MBB which use SP
+ /// so that they will be valid post-outlining.
+ ///
+ /// \param MBB A \p MachineBasicBlock in an outlined function.
+ void fixupPostOutline(MachineBasicBlock &MBB) const;
+
+ /// Returns true if the machine instruction offset can handle the stack fixup
+ /// and updates it if requested.
+ bool checkAndUpdateStackOffset(MachineInstr *MI, int64_t Fixup,
+ bool Updt) const;
unsigned getInstBundleLength(const MachineInstr &MI) const;
--- |
define void @outline_default_arm() #0 { ret void }
define void @outline_default_thumb() #1 { ret void }
- define void @outline_default_KO_stack_arm() #0 { ret void }
- define void @outline_default_KO_stack_thumb() #0 { ret void }
declare void @bar()
attributes #0 = { minsize optsize }
liveins: $lr, $r4, $r5, $r6, $r7, $r8, $r9, $r10, $r11
$r2 = tMOVr $lr, 14, $noreg
tBX_RET 14, $noreg
-...
----
-
-name: outline_default_KO_stack_arm
-tracksRegLiveness: true
-body: |
- ; CHECK-LABEL: name: outline_default_KO_stack_arm
- ; CHECK: bb.0:
- ; CHECK: liveins: $lr
- ; CHECK: $r0 = LDRi12 $sp, 0, 14 /* CC::al */, $noreg
- ; CHECK: $r1 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r2 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r3 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r4 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r5 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: bb.1:
- ; CHECK: liveins: $lr, $r6, $r7, $r8, $r9, $r10, $r11
- ; CHECK: $r0 = LDRi12 $sp, 0, 14 /* CC::al */, $noreg
- ; CHECK: $r1 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r2 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r3 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r4 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r5 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: bb.2:
- ; CHECK: liveins: $lr, $r5, $r6, $r7, $r8, $r9, $r10, $r11
- ; CHECK: $r0 = LDRi12 $sp, 0, 14 /* CC::al */, $noreg
- ; CHECK: $r1 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r2 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r3 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r4 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r5 = MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: bb.3:
- ; CHECK: liveins: $lr, $r5, $r6, $r7, $r8, $r9, $r10, $r11
- ; CHECK: $r2 = MOVr $lr, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: BX_RET 14 /* CC::al */, $noreg
- bb.0:
- liveins: $lr
- $r0 = LDRi12 $sp, 0, 14, $noreg
- $r1 = MOVi 3, 14, $noreg, $noreg
- $r2 = MOVi 3, 14, $noreg, $noreg
- $r3 = MOVi 3, 14, $noreg, $noreg
- $r4 = MOVi 3, 14, $noreg, $noreg
- $r5 = MOVi 3, 14, $noreg, $noreg
- bb.1:
- liveins: $lr, $r6, $r7, $r8, $r9, $r10, $r11
- $r0 = LDRi12 $sp, 0, 14, $noreg
- $r1 = MOVi 3, 14, $noreg, $noreg
- $r2 = MOVi 3, 14, $noreg, $noreg
- $r3 = MOVi 3, 14, $noreg, $noreg
- $r4 = MOVi 3, 14, $noreg, $noreg
- $r5 = MOVi 3, 14, $noreg, $noreg
- bb.2:
- liveins: $lr, $r5, $r6, $r7, $r8, $r9, $r10, $r11
- $r0 = LDRi12 $sp, 0, 14, $noreg
- $r1 = MOVi 3, 14, $noreg, $noreg
- $r2 = MOVi 3, 14, $noreg, $noreg
- $r3 = MOVi 3, 14, $noreg, $noreg
- $r4 = MOVi 3, 14, $noreg, $noreg
- $r5 = MOVi 3, 14, $noreg, $noreg
- bb.3:
- liveins: $lr, $r5, $r6, $r7, $r8, $r9, $r10, $r11
- $r2 = MOVr $lr, 14, $noreg, $noreg
- BX_RET 14, $noreg
-...
----
-
-name: outline_default_KO_stack_thumb
-tracksRegLiveness: true
-body: |
- ; CHECK-LABEL: name: outline_default_KO_stack_thumb
- ; CHECK: bb.0:
- ; CHECK: liveins: $lr
- ; CHECK: $r0 = t2LDRi12 $sp, 0, 14 /* CC::al */, $noreg
- ; CHECK: $r1 = t2MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r2 = t2MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r3 = t2MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: bb.1:
- ; CHECK: liveins: $lr, $r4, $r5, $r6, $r7, $r8, $r9, $r10, $r11
- ; CHECK: $r0 = t2LDRi12 $sp, 0, 14 /* CC::al */, $noreg
- ; CHECK: $r1 = t2MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r2 = t2MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r3 = t2MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: bb.2:
- ; CHECK: liveins: $lr, $r4, $r5, $r6, $r7, $r8, $r9, $r10, $r11
- ; CHECK: $r0 = t2LDRi12 $sp, 0, 14 /* CC::al */, $noreg
- ; CHECK: $r1 = t2MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r2 = t2MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: $r3 = t2MOVi 3, 14 /* CC::al */, $noreg, $noreg
- ; CHECK: bb.3:
- ; CHECK: liveins: $lr, $r4, $r5, $r6, $r7, $r8, $r9, $r10, $r11
- ; CHECK: $r2 = tMOVr $lr, 14 /* CC::al */, $noreg
- ; CHECK: tBX_RET 14 /* CC::al */, $noreg
- bb.0:
- liveins: $lr
- $r0 = t2LDRi12 $sp, 0, 14, $noreg
- $r1 = t2MOVi 3, 14, $noreg, $noreg
- $r2 = t2MOVi 3, 14, $noreg, $noreg
- $r3 = t2MOVi 3, 14, $noreg, $noreg
- bb.1:
- liveins: $lr, $r4, $r5, $r6, $r7, $r8, $r9, $r10, $r11
- $r0 = t2LDRi12 $sp, 0, 14, $noreg
- $r1 = t2MOVi 3, 14, $noreg, $noreg
- $r2 = t2MOVi 3, 14, $noreg, $noreg
- $r3 = t2MOVi 3, 14, $noreg, $noreg
- bb.2:
- liveins: $lr, $r4, $r5, $r6, $r7, $r8, $r9, $r10, $r11
- $r0 = t2LDRi12 $sp, 0, 14, $noreg
- $r1 = t2MOVi 3, 14, $noreg, $noreg
- $r2 = t2MOVi 3, 14, $noreg, $noreg
- $r3 = t2MOVi 3, 14, $noreg, $noreg
- bb.3:
- liveins: $lr, $r4, $r5, $r6, $r7, $r8, $r9, $r10, $r11
- $r2 = tMOVr $lr, 14, $noreg
- tBX_RET 14, $noreg
-
; CHECK-LABEL: name: OUTLINED_FUNCTION_0
; CHECK: bb.0:
--- |
define void @outline_no_save_ok_arm() #0 { ret void }
- define void @outline_no_save_ko_arm() #0 { ret void }
define void @outline_no_save_ok_thumb() #1 { ret void }
- define void @outline_no_save_ko_thumb() #1 { ret void }
declare void @foo()
...
---
-name: outline_no_save_ko_arm
-tracksRegLiveness: true
-body: |
- ; CHECK-LABEL: name: outline_no_save_ko_arm
- ; CHECK-NOT: OUTLINED_FUNCTION
- bb.0:
- liveins: $lr
- $r2 = MOVi 2, 14, $noreg, $noreg
- $r2 = MOVi 2, 14, $noreg, $noreg
- $r2 = MOVi 2, 14, $noreg, $noreg
- $r2 = MOVi 2, 14, $noreg, $noreg
- $r3 = LDRi12 $sp, 8, 14, $noreg
- $r2 = MOVr $lr, 14, $noreg, $noreg
- bb.1:
- $r2 = MOVi 2, 14, $noreg, $noreg
- $r2 = MOVi 2, 14, $noreg, $noreg
- $r2 = MOVi 2, 14, $noreg, $noreg
- $r2 = MOVi 2, 14, $noreg, $noreg
- $r3 = LDRi12 $sp, 8, 14, $noreg
- $r4 = MOVi 4, 14, $noreg, $noreg
- BL @foo
- bb.2:
- liveins: $lr
- BX_RET 14, $noreg
-...
----
-
name: outline_no_save_ok_thumb
tracksRegLiveness: true
body: |
t2STRi12 $r2, $sp, 0, 14, $noreg
bb.2:
tBX_RET 14, $noreg
-...
----
-
-name: outline_no_save_ko_thumb
-tracksRegLiveness: true
-body: |
- ; CHECK-LABEL: name: outline_no_save_ko_thumb
- ; CHECK-NOT: OUTLINED_FUNCTION
- bb.0:
- liveins: $lr
- $r2 = t2MOVi 2, 14, $noreg, $noreg
- $r2 = t2MOVi 2, 14, $noreg, $noreg
- $r2 = t2MOVi 2, 14, $noreg, $noreg
- $r2 = t2MOVi 2, 14, $noreg, $noreg
- t2STRi12 $r2, $sp, 0, 14, $noreg
- $r2 = tMOVr $lr, 14, $noreg
- bb.1:
- $r2 = t2MOVi 2, 14, $noreg, $noreg
- $r2 = t2MOVi 2, 14, $noreg, $noreg
- $r2 = t2MOVi 2, 14, $noreg, $noreg
- $r2 = t2MOVi 2, 14, $noreg, $noreg
- t2STRi12 $r2, $sp, 0, 14, $noreg
- $r4 = t2MOVi 3, 14, $noreg, $noreg
- tBL 14, $noreg, @foo
- bb.2:
- liveins: $lr, $r0, $r6, $r7, $r8, $r9, $r10, $r11
- tBX_RET 14, $noreg
; CHECK-LABEL: name: OUTLINED_FUNCTION_0
; CHECK: bb.0:
--- /dev/null
+# RUN: llc -mtriple=armv7-- -run-pass=prologepilog -run-pass=machine-outliner \
+# RUN: -verify-machineinstrs %s -o - | FileCheck %s
+
+--- |
+ define void @CheckAddrMode_i12() { ret void }
+ define void @CheckAddrMode3() { ret void }
+ define void @CheckAddrMode5() { ret void }
+ define void @CheckAddrMode5FP16() { ret void }
+ define void @foo() { ret void }
+
+...
+---
+
+name: CheckAddrMode_i12
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $r0
+ ; CHECK-LABEL: name: CheckAddrMode_i12
+ ; CHECK: $r1 = MOVr killed $r0, 14 /* CC::al */, $noreg, $noreg
+ ; CHECK-NEXT: BL @OUTLINED_FUNCTION_[[I12:[0-9]+]]
+ ; CHECK-NEXT: $r6 = LDRi12 $sp, 4088, 14 /* CC::al */, $noreg
+ $r1 = MOVr killed $r0, 14, $noreg, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $r1 = LDRi12 $sp, 0, 14, $noreg
+ $r2 = LDRi12 $sp, 8, 14, $noreg
+ $r5 = LDRi12 $sp, 4086, 14, $noreg
+ $r6 = LDRi12 $sp, 4088, 14, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $r1 = LDRi12 $sp, 0, 14, $noreg
+ $r2 = LDRi12 $sp, 8, 14, $noreg
+ $r5 = LDRi12 $sp, 4086, 14, $noreg
+ $r6 = LDRi12 $sp, 4088, 14, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $r1 = LDRi12 $sp, 0, 14, $noreg
+ $r2 = LDRi12 $sp, 8, 14, $noreg
+ $r5 = LDRi12 $sp, 4086, 14, $noreg
+ $r6 = LDRi12 $sp, 4088, 14, $noreg
+ BX_RET 14, $noreg
+...
+---
+
+name: CheckAddrMode3
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $r1
+ ; CHECK-LABEL: name: CheckAddrMode3
+ ; CHECK: $r0 = MOVr killed $r1, 14 /* CC::al */, $noreg, $noreg
+ ; CHECK-NEXT: BL @OUTLINED_FUNCTION_[[I3:[0-9]+]]
+ ; CHECK-NEXT: $r6 = LDRSH $sp, $noreg, 248, 14 /* CC::al */, $noreg
+ $r0 = MOVr killed $r1, 14, $noreg, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $r1 = LDRSH $sp, $noreg, 0, 14, $noreg
+ $r2 = LDRSH $sp, $noreg, 8, 14, $noreg
+ $r5 = LDRSH $sp, $noreg, 247, 14, $noreg
+ $r6 = LDRSH $sp, $noreg, 248, 14, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $r1 = LDRSH $sp, $noreg, 0, 14, $noreg
+ $r2 = LDRSH $sp, $noreg, 8, 14, $noreg
+ $r5 = LDRSH $sp, $noreg, 247, 14, $noreg
+ $r6 = LDRSH $sp, $noreg, 248, 14, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $r1 = LDRSH $sp, $noreg, 0, 14, $noreg
+ $r2 = LDRSH $sp, $noreg, 8, 14, $noreg
+ $r5 = LDRSH $sp, $noreg, 247, 14, $noreg
+ $r6 = LDRSH $sp, $noreg, 248, 14, $noreg
+ BX_RET 14, $noreg
+...
+---
+
+name: CheckAddrMode5
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $r2
+ ; CHECK-LABEL: name: CheckAddrMode5
+ ; CHECK: $r0 = MOVr killed $r2, 14 /* CC::al */, $noreg, $noreg
+ ; CHECK-NEXT: BL @OUTLINED_FUNCTION_[[I5:[0-9]+]]
+ ; CHECK-NEXT: $d5 = VLDRD $sp, 254, 14 /* CC::al */, $noreg
+ $r0 = MOVr killed $r2, 14, $noreg, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $d0 = VLDRD $sp, 0, 14, $noreg
+ $d1 = VLDRD $sp, 8, 14, $noreg
+ $d4 = VLDRD $sp, 253, 14, $noreg
+ $d5 = VLDRD $sp, 254, 14, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $d0 = VLDRD $sp, 0, 14, $noreg
+ $d1 = VLDRD $sp, 8, 14, $noreg
+ $d4 = VLDRD $sp, 253, 14, $noreg
+ $d5 = VLDRD $sp, 254, 14, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $d0 = VLDRD $sp, 0, 14, $noreg
+ $d1 = VLDRD $sp, 8, 14, $noreg
+ $d4 = VLDRD $sp, 253, 14, $noreg
+ $d5 = VLDRD $sp, 254, 14, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $d0 = VLDRD $sp, 0, 14, $noreg
+ $d1 = VLDRD $sp, 8, 14, $noreg
+ $d4 = VLDRD $sp, 253, 14, $noreg
+ $d5 = VLDRD $sp, 254, 14, $noreg
+ BX_RET 14, $noreg
+...
+---
+
+name: CheckAddrMode5FP16
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $r3
+ ; CHECK-LABEL: name: CheckAddrMode5FP16
+ ; CHECK: $r0 = MOVr killed $r3, 14 /* CC::al */, $noreg, $noreg
+ ; CHECK-NEXT: BL @OUTLINED_FUNCTION_[[I5FP16:[0-9]+]]
+ ; CHECK-NEXT: $s6 = VLDRH $sp, 252, 14, $noreg
+ $r0 = MOVr killed $r3, 14, $noreg, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $s1 = VLDRH $sp, 0, 14, $noreg
+ $s2 = VLDRH $sp, 8, 14, $noreg
+ $s5 = VLDRH $sp, 240, 14, $noreg
+ $s6 = VLDRH $sp, 252, 14, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $s1 = VLDRH $sp, 0, 14, $noreg
+ $s2 = VLDRH $sp, 8, 14, $noreg
+ $s5 = VLDRH $sp, 240, 14, $noreg
+ $s6 = VLDRH $sp, 252, 14, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $s1 = VLDRH $sp, 0, 14, $noreg
+ $s2 = VLDRH $sp, 8, 14, $noreg
+ $s5 = VLDRH $sp, 240, 14, $noreg
+ $s6 = VLDRH $sp, 252, 14, $noreg
+ BL @foo, implicit-def dead $lr, implicit $sp
+ $s1 = VLDRH $sp, 0, 14, $noreg
+ $s2 = VLDRH $sp, 8, 14, $noreg
+ $s5 = VLDRH $sp, 240, 14, $noreg
+ $s6 = VLDRH $sp, 252, 14, $noreg
+ BX_RET 14, $noreg
+...
+---
+
+name: foo
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $lr
+
+ BX_RET 14, $noreg
+
+ ;CHECK: name: OUTLINED_FUNCTION_[[I5]]
+ ;CHECK: early-clobber $sp = STR_PRE_IMM killed $lr, $sp, -8, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 8
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $lr, -8
+ ;CHECK-NEXT: BL @foo, implicit-def dead $lr, implicit $sp
+ ;CHECK-NEXT: $d0 = VLDRD $sp, 2, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $d1 = VLDRD $sp, 10, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $d4 = VLDRD $sp, 255, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $lr, $sp = LDR_POST_IMM $sp, $noreg, 8, 14 /* CC::al */, $noreg
+
+ ;CHECK: name: OUTLINED_FUNCTION_[[I5FP16]]
+ ;CHECK: early-clobber $sp = STR_PRE_IMM killed $lr, $sp, -8, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 8
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $lr, -8
+ ;CHECK-NEXT: BL @foo, implicit-def dead $lr, implicit $sp
+ ;CHECK-NEXT: $s1 = VLDRH $sp, 4, 14, $noreg
+ ;CHECK-NEXT: $s2 = VLDRH $sp, 12, 14, $noreg
+ ;CHECK-NEXT: $s5 = VLDRH $sp, 244, 14, $noreg
+ ;CHECK-NEXT: $lr, $sp = LDR_POST_IMM $sp, $noreg, 8, 14 /* CC::al */, $noreg
+
+ ;CHECK: name: OUTLINED_FUNCTION_[[I12]]
+ ;CHECK: early-clobber $sp = STR_PRE_IMM killed $lr, $sp, -8, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 8
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $lr, -8
+ ;CHECK-NEXT: BL @foo, implicit-def dead $lr, implicit $sp
+ ;CHECK-NEXT: $r1 = LDRi12 $sp, 8, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $r2 = LDRi12 $sp, 16, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $r5 = LDRi12 $sp, 4094, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $lr, $sp = LDR_POST_IMM $sp, $noreg, 8, 14 /* CC::al */, $noreg
+
+ ;CHECK: name: OUTLINED_FUNCTION_[[I3]]
+ ;CHECK: early-clobber $sp = STR_PRE_IMM killed $lr, $sp, -8, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 8
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $lr, -8
+ ;CHECK-NEXT: BL @foo, implicit-def dead $lr, implicit $sp
+ ;CHECK-NEXT: $r1 = LDRSH $sp, $noreg, 8, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $r2 = LDRSH $sp, $noreg, 16, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $r5 = LDRSH $sp, $noreg, 255, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $lr, $sp = LDR_POST_IMM $sp, $noreg, 8, 14 /* CC::al */, $noreg
--- /dev/null
+# RUN: llc -mtriple=thumbv7-- -run-pass=prologepilog \
+# RUN: -run-pass=machine-outliner %s -o - | FileCheck %s
+
+--- |
+ define void @CheckAddrModeT2_i12() { ret void }
+ define void @CheckAddrModeT2_i8() { ret void }
+ define void @CheckAddrModeT2_i8s4() { ret void }
+ define void @CheckAddrModeT2_ldrex() { ret void }
+ define void @CheckAddrModeT1_s() { ret void }
+ define void @foo() { ret void }
+
+...
+---
+
+name: CheckAddrModeT2_i12
+tracksRegLiveness: true
+
+body: |
+ bb.0:
+ liveins: $r1
+ ;CHECK-LABEL: name: CheckAddrModeT2_i12
+ ;CHECK: $r0 = tMOVr killed $r1, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_[[I12:[0-9]+]]
+ ;CHECK-NEXT: $r0 = t2LDRi12 $sp, 4088, 14 /* CC::al */, $noreg
+ $r0 = tMOVr killed $r1, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ $r0 = t2LDRi12 $sp, 0, 14, $noreg
+ $r0 = t2LDRi12 $sp, 4, 14, $noreg
+ $r0 = t2LDRi12 $sp, 4086, 14, $noreg
+ $r0 = t2LDRi12 $sp, 4088, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ $r0 = t2LDRi12 $sp, 0, 14, $noreg
+ $r0 = t2LDRi12 $sp, 4, 14, $noreg
+ $r0 = t2LDRi12 $sp, 4086, 14, $noreg
+ $r0 = t2LDRi12 $sp, 4088, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ $r0 = t2LDRi12 $sp, 0, 14, $noreg
+ $r0 = t2LDRi12 $sp, 4, 14, $noreg
+ $r0 = t2LDRi12 $sp, 4086, 14, $noreg
+ $r0 = t2LDRi12 $sp, 4088, 14, $noreg
+ BX_RET 14, $noreg
+...
+---
+
+name: CheckAddrModeT2_i8
+tracksRegLiveness: true
+
+body: |
+ bb.0:
+ liveins: $r1
+ ;CHECK-LABEL: name: CheckAddrModeT2_i8
+ ;CHECK: $r0 = tMOVr $r1, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_[[I8:[0-9]+]]
+ ;CHECK-NEXT: t2STRHi8 $r0, $sp, 248, 14 /* CC::al */, $noreg
+ $r0 = tMOVr $r1, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ t2STRHi8 $r0, $sp, 0, 14, $noreg
+ t2STRHi8 $r0, $sp, 4, 14, $noreg
+ t2STRHi8 $r0, $sp, 247, 14, $noreg
+ t2STRHi8 $r0, $sp, 248, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ t2STRHi8 $r0, $sp, 0, 14, $noreg
+ t2STRHi8 $r0, $sp, 4, 14, $noreg
+ t2STRHi8 $r0, $sp, 247, 14, $noreg
+ t2STRHi8 $r0, $sp, 248, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ t2STRHi8 $r0, $sp, 0, 14, $noreg
+ t2STRHi8 $r0, $sp, 4, 14, $noreg
+ t2STRHi8 $r0, $sp, 247, 14, $noreg
+ t2STRHi8 $r0, $sp, 248, 14, $noreg
+ BX_RET 14, $noreg
+...
+---
+
+name: CheckAddrModeT2_i8s4
+tracksRegLiveness: true
+
+body: |
+ bb.0:
+ liveins: $r1
+ ;CHECK-LABEL: name: CheckAddrModeT2_i8s4
+ ;CHECK: $r0 = tMOVr $r1, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_[[I8S4:[0-9]+]]
+ ;CHECK-NEXT: t2STRDi8 $r0, $r1, $sp, 254, 14 /* CC::al */, $noreg
+ $r0 = tMOVr $r1, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ t2STRDi8 $r0, $r1, $sp, 0, 14, $noreg
+ t2STRDi8 $r0, $r1, $sp, 8, 14, $noreg
+ t2STRDi8 $r0, $r1, $sp, 253, 14, $noreg
+ t2STRDi8 $r0, $r1, $sp, 254, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ t2STRDi8 $r0, $r1, $sp, 0, 14, $noreg
+ t2STRDi8 $r0, $r1, $sp, 8, 14, $noreg
+ t2STRDi8 $r0, $r1, $sp, 253, 14, $noreg
+ t2STRDi8 $r0, $r1, $sp, 254, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ t2STRDi8 $r0, $r1, $sp, 0, 14, $noreg
+ t2STRDi8 $r0, $r1, $sp, 8, 14, $noreg
+ t2STRDi8 $r0, $r1, $sp, 253, 14, $noreg
+ t2STRDi8 $r0, $r1, $sp, 254, 14, $noreg
+ BX_RET 14, $noreg
+...
+---
+
+name: CheckAddrModeT2_ldrex
+tracksRegLiveness: true
+
+body: |
+ bb.0:
+ liveins: $r1
+ ;CHECK-LABEL: name: CheckAddrModeT2_ldrex
+ ;CHECK: $r0 = tMOVr $r1, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_[[LDREX:[0-9]+]]
+ ;CHECK-NEXT: $r1 = t2LDREX $sp, 254, 14 /* CC::al */, $noreg
+ $r0 = tMOVr $r1, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ $r1 = t2LDREX $sp, 0, 14, $noreg
+ $r1 = t2LDREX $sp, 8, 14, $noreg
+ $r1 = t2LDREX $sp, 253, 14, $noreg
+ $r1 = t2LDREX $sp, 254, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ $r1 = t2LDREX $sp, 0, 14, $noreg
+ $r1 = t2LDREX $sp, 8, 14, $noreg
+ $r1 = t2LDREX $sp, 253, 14, $noreg
+ $r1 = t2LDREX $sp, 254, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ $r1 = t2LDREX $sp, 0, 14, $noreg
+ $r1 = t2LDREX $sp, 8, 14, $noreg
+ $r1 = t2LDREX $sp, 253, 14, $noreg
+ $r1 = t2LDREX $sp, 254, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ $r1 = t2LDREX $sp, 0, 14, $noreg
+ $r1 = t2LDREX $sp, 8, 14, $noreg
+ $r1 = t2LDREX $sp, 253, 14, $noreg
+ $r1 = t2LDREX $sp, 254, 14, $noreg
+ BX_RET 14, $noreg
+...
+---
+
+name: CheckAddrModeT1_s
+tracksRegLiveness: true
+
+body: |
+ bb.0:
+ liveins: $r0, $r1
+ ;CHECK-LABEL: name: CheckAddrModeT1_s
+ ;CHECK: $r0 = tMOVr $r1, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_[[T1_S:[0-9]+]]
+ ;CHECK-NEXT: tSTRspi $r0, $sp, 254, 14 /* CC::al */, $noreg
+ $r0 = tMOVr $r1, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ tSTRspi $r0, $sp, 0, 14, $noreg
+ tSTRspi $r0, $sp, 4, 14, $noreg
+ tSTRspi $r0, $sp, 253, 14, $noreg
+ tSTRspi $r0, $sp, 254, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ tSTRspi $r0, $sp, 0, 14, $noreg
+ tSTRspi $r0, $sp, 4, 14, $noreg
+ tSTRspi $r0, $sp, 253, 14, $noreg
+ tSTRspi $r0, $sp, 254, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ tSTRspi $r0, $sp, 0, 14, $noreg
+ tSTRspi $r0, $sp, 4, 14, $noreg
+ tSTRspi $r0, $sp, 253, 14, $noreg
+ tSTRspi $r0, $sp, 254, 14, $noreg
+ tBL 14, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ tSTRspi $r0, $sp, 0, 14, $noreg
+ tSTRspi $r0, $sp, 4, 14, $noreg
+ tSTRspi $r0, $sp, 253, 14, $noreg
+ tSTRspi $r0, $sp, 254, 14, $noreg
+ BX_RET 14, $noreg
+...
+---
+
+name: foo
+tracksRegLiveness: true
+body: |
+ bb.0:
+ liveins: $lr
+
+ BX_RET 14, $noreg
+
+ ;CHECK: name: OUTLINED_FUNCTION_[[LDREX]]
+ ;CHECK: early-clobber $sp = t2STR_PRE killed $lr, $sp, -8, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 8
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $lr, -8
+ ;CHECK-NEXT: tBL 14 /* CC::al */, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ ;CHECK-NEXT: $r1 = t2LDREX $sp, 2, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $r1 = t2LDREX $sp, 10, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $r1 = t2LDREX $sp, 255, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $lr, $sp = t2LDR_POST $sp, 8, 14 /* CC::al */, $noreg
+
+ ;CHECK: name: OUTLINED_FUNCTION_[[I8]]
+ ;CHECK: early-clobber $sp = t2STR_PRE killed $lr, $sp, -8, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 8
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $lr, -8
+ ;CHECK-NEXT: tBL 14 /* CC::al */, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ ;CHECK-NEXT: t2STRHi8 $r0, $sp, 8, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: t2STRHi8 $r0, $sp, 12, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: t2STRHi8 $r0, $sp, 255, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $lr, $sp = t2LDR_POST $sp, 8, 14 /* CC::al */, $noreg
+
+ ;CHECK: name: OUTLINED_FUNCTION_[[I8S4]]
+ ;CHECK: early-clobber $sp = t2STR_PRE killed $lr, $sp, -8, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 8
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $lr, -8
+ ;CHECK-NEXT: tBL 14 /* CC::al */, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ ;CHECK-NEXT: t2STRDi8 $r0, $r1, $sp, 2, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: t2STRDi8 $r0, $r1, $sp, 10, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: t2STRDi8 $r0, $r1, $sp, 255, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $lr, $sp = t2LDR_POST $sp, 8, 14 /* CC::al */, $noreg
+
+ ;CHECK: name: OUTLINED_FUNCTION_[[I12]]
+ ;CHECK: early-clobber $sp = t2STR_PRE killed $lr, $sp, -8, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 8
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $lr, -8
+ ;CHECK-NEXT: tBL 14 /* CC::al */, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ ;CHECK-NEXT: $r0 = t2LDRi12 $sp, 8, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $r0 = t2LDRi12 $sp, 12, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $r0 = t2LDRi12 $sp, 4094, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $lr, $sp = t2LDR_POST $sp, 8, 14 /* CC::al */, $noreg
+
+ ;CHECK: name: OUTLINED_FUNCTION_[[T1_S]]
+ ;CHECK: early-clobber $sp = t2STR_PRE killed $lr, $sp, -8, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 8
+ ;CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $lr, -8
+ ;CHECK-NEXT: tBL 14 /* CC::al */, $noreg, @foo, implicit-def dead $lr, implicit $sp
+ ;CHECK-NEXT: tSTRspi $r0, $sp, 2, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: tSTRspi $r0, $sp, 6, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: tSTRspi $r0, $sp, 255, 14 /* CC::al */, $noreg
+ ;CHECK-NEXT: $lr, $sp = t2LDR_POST $sp, 8, 14 /* CC::al */, $noreg
; RUN: llc -enable-machine-outliner -mtriple=arm-unknown-linux < %s | FileCheck %s
-;
-; NOTE: Machine outliner runs, but doesn't do anything.
@x = global i32 0, align 4
define dso_local i32 @check_boundaries() #0 {
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --include-generated-funcs
; RUN: llc -enable-machine-outliner -mtriple=arm-unknown-linux < %s | FileCheck %s
-; NOTE: Machine outliner runs, but doesn't do anything.
@x = global i32 0, align 4
define dso_local i32 @check_boundaries() #0 {
; CHECK-NEXT: str r0, [sp, #4]
; CHECK-NEXT: b .LBB0_3
; CHECK-NEXT: .LBB0_2:
-; CHECK-NEXT: mov r0, #2
-; CHECK-NEXT: str r0, [sp, #8]
-; CHECK-NEXT: mov r0, #1
-; CHECK-NEXT: str r0, [sp, #12]
-; CHECK-NEXT: mov r0, #3
-; CHECK-NEXT: str r0, [sp, #4]
-; CHECK-NEXT: mov r0, #4
-; CHECK-NEXT: str r0, [sp]
+; CHECK-NEXT: mov r1, lr
+; CHECK-NEXT: bl OUTLINED_FUNCTION_0
+; CHECK-NEXT: mov lr, r1
; CHECK-NEXT: .LBB0_3:
; CHECK-NEXT: ldr r0, [sp, #12]
; CHECK-NEXT: cmp r0, #0
; CHECK-NEXT: str r0, [sp, #4]
; CHECK-NEXT: b .LBB0_6
; CHECK-NEXT: .LBB0_5:
-; CHECK-NEXT: mov r0, #2
-; CHECK-NEXT: str r0, [sp, #8]
-; CHECK-NEXT: mov r0, #1
-; CHECK-NEXT: str r0, [sp, #12]
-; CHECK-NEXT: mov r0, #3
-; CHECK-NEXT: str r0, [sp, #4]
-; CHECK-NEXT: mov r0, #4
-; CHECK-NEXT: str r0, [sp]
+; CHECK-NEXT: mov r1, lr
+; CHECK-NEXT: bl OUTLINED_FUNCTION_0
+; CHECK-NEXT: mov lr, r1
; CHECK-NEXT: .LBB0_6:
; CHECK-NEXT: mov r0, #0
; CHECK-NEXT: add sp, sp, #20
; CHECK-NEXT: @ %bb.1:
; CHECK-NEXT: .LCPI1_0:
; CHECK-NEXT: .long x
+;
+; CHECK-LABEL: OUTLINED_FUNCTION_0:
+; CHECK: @ %bb.0:
+; CHECK-NEXT: mov r0, #2
+; CHECK-NEXT: str r0, [sp, #8]
+; CHECK-NEXT: mov r0, #1
+; CHECK-NEXT: str r0, [sp, #12]
+; CHECK-NEXT: mov r0, #3
+; CHECK-NEXT: str r0, [sp, #4]
+; CHECK-NEXT: mov r0, #4
+; CHECK-NEXT: str r0, [sp]
+; CHECK-NEXT: mov pc, lr
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -enable-machine-outliner -mtriple=arm-unknown-linux < %s | FileCheck %s
-;
-; NOTE: Machine outliner runs, but doesn't do anything.
@x = global i32 0, align 4
define dso_local i32 @check_boundaries() #0 {
; CHECK-NEXT: str r0, [sp, #4]
; CHECK-NEXT: b .LBB0_3
; CHECK-NEXT: .LBB0_2:
-; CHECK-NEXT: mov r0, #2
-; CHECK-NEXT: str r0, [sp, #8]
-; CHECK-NEXT: mov r0, #1
-; CHECK-NEXT: str r0, [sp, #12]
-; CHECK-NEXT: mov r0, #3
-; CHECK-NEXT: str r0, [sp, #4]
-; CHECK-NEXT: mov r0, #4
-; CHECK-NEXT: str r0, [sp]
+; CHECK-NEXT: mov r1, lr
+; CHECK-NEXT: bl OUTLINED_FUNCTION_0
+; CHECK-NEXT: mov lr, r1
; CHECK-NEXT: .LBB0_3:
; CHECK-NEXT: ldr r0, [sp, #12]
; CHECK-NEXT: cmp r0, #0
; CHECK-NEXT: str r0, [sp, #4]
; CHECK-NEXT: b .LBB0_6
; CHECK-NEXT: .LBB0_5:
-; CHECK-NEXT: mov r0, #2
-; CHECK-NEXT: str r0, [sp, #8]
-; CHECK-NEXT: mov r0, #1
-; CHECK-NEXT: str r0, [sp, #12]
-; CHECK-NEXT: mov r0, #3
-; CHECK-NEXT: str r0, [sp, #4]
-; CHECK-NEXT: mov r0, #4
-; CHECK-NEXT: str r0, [sp]
+; CHECK-NEXT: mov r1, lr
+; CHECK-NEXT: bl OUTLINED_FUNCTION_0
+; CHECK-NEXT: mov lr, r1
; CHECK-NEXT: .LBB0_6:
; CHECK-NEXT: mov r0, #0
; CHECK-NEXT: add sp, sp, #20