diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.h b/llvm/lib/Target/ARM/ARMBaseInstrInfo.h --- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.h +++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.h @@ -395,6 +395,16 @@ /// 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; diff --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp --- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp +++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp @@ -5859,6 +5859,113 @@ 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(); @@ -6068,6 +6175,19 @@ 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; } @@ -6083,6 +6203,12 @@ 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; @@ -6218,6 +6344,12 @@ 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); @@ -6232,6 +6364,15 @@ // 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( @@ -6288,6 +6429,8 @@ 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); diff --git a/llvm/test/CodeGen/ARM/machine-outliner-default.mir b/llvm/test/CodeGen/ARM/machine-outliner-default.mir --- a/llvm/test/CodeGen/ARM/machine-outliner-default.mir +++ b/llvm/test/CodeGen/ARM/machine-outliner-default.mir @@ -5,8 +5,6 @@ --- | 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 } @@ -113,121 +111,6 @@ 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: diff --git a/llvm/test/CodeGen/ARM/machine-outliner-no-lr-save.mir b/llvm/test/CodeGen/ARM/machine-outliner-no-lr-save.mir --- a/llvm/test/CodeGen/ARM/machine-outliner-no-lr-save.mir +++ b/llvm/test/CodeGen/ARM/machine-outliner-no-lr-save.mir @@ -4,9 +4,7 @@ --- | 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() @@ -42,33 +40,6 @@ ... --- -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: | @@ -93,33 +64,6 @@ 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: diff --git a/llvm/test/CodeGen/ARM/machine-outliner-stack-fixup-arm.mir b/llvm/test/CodeGen/ARM/machine-outliner-stack-fixup-arm.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/ARM/machine-outliner-stack-fixup-arm.mir @@ -0,0 +1,186 @@ +# 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 diff --git a/llvm/test/CodeGen/ARM/machine-outliner-stack-fixup-thumb.mir b/llvm/test/CodeGen/ARM/machine-outliner-stack-fixup-thumb.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/ARM/machine-outliner-stack-fixup-thumb.mir @@ -0,0 +1,231 @@ +# 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 diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll --- a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll @@ -1,6 +1,4 @@ ; 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 i32 @check_boundaries() #0 { diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll.generated.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll.generated.expected --- a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll.generated.expected +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll.generated.expected @@ -1,6 +1,5 @@ ; 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 i32 @check_boundaries() #0 { @@ -76,14 +75,9 @@ ; 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 @@ -93,14 +87,9 @@ ; 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 @@ -134,3 +123,15 @@ ; 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 diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll.nogenerated.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll.nogenerated.expected --- a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll.nogenerated.expected +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll.nogenerated.expected @@ -1,7 +1,5 @@ ; 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 i32 @check_boundaries() #0 { @@ -18,14 +16,9 @@ ; 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 @@ -35,14 +28,9 @@ ; 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