[llvm] 244ad22 - [ARM][MachineOutliner] Add stack fixup feature

Yvan Roux via llvm-commits llvm-commits at lists.llvm.org
Tue Jan 19 01:59:32 PST 2021


Author: Yvan Roux
Date: 2021-01-19T10:59:09+01:00
New Revision: 244ad228f34363b508cd1096c99d8f1bbe999d85

URL: https://github.com/llvm/llvm-project/commit/244ad228f34363b508cd1096c99d8f1bbe999d85
DIFF: https://github.com/llvm/llvm-project/commit/244ad228f34363b508cd1096c99d8f1bbe999d85.diff

LOG: [ARM][MachineOutliner] Add stack fixup feature

This patch handles cases where we have to save/restore the link register
into the stack and and load/store instruction which use the stack are
part of the outlined region. It checks that there will be no overflow
introduced by the new offset and fixup these instructions accordingly.

Differential Revision: https://reviews.llvm.org/D92934

Added: 
    llvm/test/CodeGen/ARM/machine-outliner-stack-fixup-arm.mir
    llvm/test/CodeGen/ARM/machine-outliner-stack-fixup-thumb.mir

Modified: 
    llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
    llvm/lib/Target/ARM/ARMBaseInstrInfo.h
    llvm/test/CodeGen/ARM/machine-outliner-default.mir
    llvm/test/CodeGen/ARM/machine-outliner-no-lr-save.mir
    llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll
    llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll.generated.expected
    llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/arm_generated_funcs.ll.nogenerated.expected

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index 143bf6641e6f..112eb59e173d 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -5914,6 +5914,112 @@ outliner::OutlinedFunction ARMBaseInstrInfo::getOutliningCandidateInfo(
                                     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();
@@ -6125,6 +6231,19 @@ ARMBaseInstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT,
     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;
   }
 
@@ -6140,6 +6259,12 @@ ARMBaseInstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT,
   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;
@@ -6275,6 +6400,12 @@ void ARMBaseInstrInfo::buildOutlinedFrame(
     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);
@@ -6289,6 +6420,15 @@ void ARMBaseInstrInfo::buildOutlinedFrame(
   // 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(
@@ -6345,6 +6485,8 @@ 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);

diff  --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.h b/llvm/lib/Target/ARM/ARMBaseInstrInfo.h
index b14f7e480856..1b843c428130 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.h
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.h
@@ -404,6 +404,16 @@ class ARMBaseInstrInfo : public ARMGenInstrInfo {
   /// 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/test/CodeGen/ARM/machine-outliner-default.mir b/llvm/test/CodeGen/ARM/machine-outliner-default.mir
index 9db4207d2df7..fa5119c6c4fe 100644
--- 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 @@ body:             |
     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
index 678633dd8345..71a7d4d7a1c1 100644
--- 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 @@ body:             |
 ...
 ---
 
-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 @@ 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:

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
index 000000000000..1f8745cd3f72
--- /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
index 000000000000..7d9b19553b08
--- /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
index cdc7d3b63fba..bae66d456f89 100644
--- 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 dso_local 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
index ddf87ee3a29d..de5571f64361 100644
--- 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 dso_local i32 @check_boundaries() #0 {
@@ -76,14 +75,9 @@ attributes #0 = { noredzone nounwind ssp uwtable "frame-pointer"="all" }
 ; 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 @@ attributes #0 = { noredzone nounwind ssp uwtable "frame-pointer"="all" }
 ; 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 @@ attributes #0 = { noredzone nounwind ssp uwtable "frame-pointer"="all" }
 ; 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
index 316e7743209c..4f623384ade6 100644
--- 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 dso_local i32 @check_boundaries() #0 {
@@ -18,14 +16,9 @@ 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
@@ -35,14 +28,9 @@ define dso_local i32 @check_boundaries() #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


        


More information about the llvm-commits mailing list