[llvm] 6b8628a - [ARM][MachineOutliner] Add NoLRSave mode.

Yvan Roux via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 10 23:49:47 PDT 2020


Author: Yvan Roux
Date: 2020-06-11T08:45:46+02:00
New Revision: 6b8628a1f036bc34cb0499e15da6df9a130ec287

URL: https://github.com/llvm/llvm-project/commit/6b8628a1f036bc34cb0499e15da6df9a130ec287
DIFF: https://github.com/llvm/llvm-project/commit/6b8628a1f036bc34cb0499e15da6df9a130ec287.diff

LOG: [ARM][MachineOutliner] Add NoLRSave mode.

Outline chunks of code which don't need a save/restore mechanism of the
link register.

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

Added: 
    llvm/test/CodeGen/ARM/machine-outliner-no-lr-save.mir

Modified: 
    llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index 6c94697665fb..70031d193c6e 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -5560,8 +5560,32 @@ bool llvm::HasLowerConstantMaterializationCost(unsigned Val1, unsigned Val2,
 /// | Frame overhead in Bytes |      0 |   0 |
 /// | Stack fixup required    |     No |  No |
 /// +-------------------------+--------+-----+
+///
+/// \p MachineOutlinerNoLRSave implies that the function should be called using
+/// a BL instruction, but doesn't require LR to be saved and restored. This
+/// happens when LR is known to be dead.
+///
+/// That is,
+///
+/// I1                                OUTLINED_FUNCTION:
+/// I2 --> BL OUTLINED_FUNCTION       I1
+/// I3                                I2
+///                                   I3
+///                                   BX LR
+///
+/// +-------------------------+--------+-----+
+/// |                         | Thumb2 | ARM |
+/// +-------------------------+--------+-----+
+/// | Call overhead in Bytes  |      4 |   4 |
+/// | Frame overhead in Bytes |      4 |   4 |
+/// | Stack fixup required    |     No |  No |
+/// +-------------------------+--------+-----+
 
-enum MachineOutlinerClass { MachineOutlinerTailCall, MachineOutlinerThunk };
+enum MachineOutlinerClass {
+  MachineOutlinerTailCall,
+  MachineOutlinerThunk,
+  MachineOutlinerNoLRSave
+};
 
 enum MachineOutlinerMBBFlags {
   LRUnavailableSomewhere = 0x2,
@@ -5574,12 +5598,16 @@ struct OutlinerCosts {
   const int FrameTailCall;
   const int CallThunk;
   const int FrameThunk;
+  const int CallNoLRSave;
+  const int FrameNoLRSave;
 
   OutlinerCosts(const ARMSubtarget &target)
       : CallTailCall(target.isThumb() ? 4 : 4),
         FrameTailCall(target.isThumb() ? 0 : 0),
         CallThunk(target.isThumb() ? 4 : 4),
-        FrameThunk(target.isThumb() ? 0 : 0) {}
+        FrameThunk(target.isThumb() ? 0 : 0),
+        CallNoLRSave(target.isThumb() ? 4 : 4),
+        FrameNoLRSave(target.isThumb() ? 4 : 4) {}
 };
 
 outliner::OutlinedFunction ARMBaseInstrInfo::getOutliningCandidateInfo(
@@ -5665,8 +5693,29 @@ outliner::OutlinedFunction ARMBaseInstrInfo::getOutliningCandidateInfo(
     FrameID = MachineOutlinerThunk;
     NumBytesToCreateFrame = Costs.FrameThunk;
     SetCandidateCallInfo(MachineOutlinerThunk, Costs.CallThunk);
-  } else
-    return outliner::OutlinedFunction();
+  } else {
+    // We need to decide how to emit calls + frames. We can always emit the same
+    // frame if we don't need to save to the stack.
+    unsigned NumBytesNoStackCalls = 0;
+    std::vector<outliner::Candidate> CandidatesWithoutStackFixups;
+
+    for (outliner::Candidate &C : RepeatedSequenceLocs) {
+      C.initLRU(TRI);
+
+      // Is LR available? If so, we don't need a save.
+      if (C.LRU.available(ARM::LR)) {
+        FrameID = MachineOutlinerNoLRSave;
+        NumBytesNoStackCalls += Costs.CallNoLRSave;
+        C.setCallInfo(MachineOutlinerNoLRSave, Costs.CallNoLRSave);
+        CandidatesWithoutStackFixups.push_back(C);
+      }
+    }
+
+    if (!CandidatesWithoutStackFixups.empty()) {
+      RepeatedSequenceLocs = CandidatesWithoutStackFixups;
+    } else
+      return outliner::OutlinedFunction();
+  }
 
   return outliner::OutlinedFunction(RepeatedSequenceLocs, SequenceSize,
                                     NumBytesToCreateFrame, FrameID);
@@ -5820,6 +5869,25 @@ ARMBaseInstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT,
   if (MI.modifiesRegister(ARM::LR, TRI) || MI.modifiesRegister(ARM::PC, TRI))
     return outliner::InstrType::Illegal;
 
+  // Does this use the stack?
+  if (MI.modifiesRegister(ARM::SP, TRI) || MI.readsRegister(ARM::SP, TRI)) {
+    // True if there is no chance that any outlined candidate from this range
+    // could require stack fixups. That is, both
+    // * LR is available in the range (No save/restore around call)
+    // * The range doesn't include calls (No save/restore in outlined frame)
+    // are true.
+    // FIXME: This is very restrictive; the flags check the whole block,
+    // not just the bit we will try to outline.
+    bool MightNeedStackFixUp =
+        (Flags & (MachineOutlinerMBBFlags::LRUnavailableSomewhere |
+                  MachineOutlinerMBBFlags::HasCalls));
+
+    if (!MightNeedStackFixUp)
+      return outliner::InstrType::Legal;
+
+    return outliner::InstrType::Illegal;
+  }
+
   // Be conservative with IT blocks.
   if (MI.readsRegister(ARM::ITSTATE, TRI) ||
       MI.modifiesRegister(ARM::ITSTATE, TRI))
@@ -5835,6 +5903,10 @@ ARMBaseInstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT,
 void ARMBaseInstrInfo::buildOutlinedFrame(
     MachineBasicBlock &MBB, MachineFunction &MF,
     const outliner::OutlinedFunction &OF) const {
+  // Nothing is needed for tail-calls.
+  if (OF.FrameConstructionID == MachineOutlinerTailCall)
+    return;
+
   // For thunk outlining, rewrite the last instruction from a call to a
   // tail-call.
   if (OF.FrameConstructionID == MachineOutlinerThunk) {
@@ -5851,7 +5923,13 @@ void ARMBaseInstrInfo::buildOutlinedFrame(
     if (isThumb && !Call->getOperand(FuncOp).isReg())
       MIB.add(predOps(ARMCC::AL));
     Call->eraseFromParent();
+    return;
   }
+
+  // Here we have to insert the return ourselves.  Get the correct opcode from
+  // current feature set.
+  BuildMI(MBB, MBB.end(), DebugLoc(), get(Subtarget.getReturnOpcode()))
+      .add(predOps(ARMCC::AL));
 }
 
 MachineBasicBlock::iterator ARMBaseInstrInfo::insertOutlinedCall(

diff  --git a/llvm/test/CodeGen/ARM/machine-outliner-no-lr-save.mir b/llvm/test/CodeGen/ARM/machine-outliner-no-lr-save.mir
new file mode 100644
index 000000000000..950172e8ff6d
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/machine-outliner-no-lr-save.mir
@@ -0,0 +1,139 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -mtriple=arm-- -run-pass=machine-outliner -verify-machineinstrs \
+# RUN: %s -o - | FileCheck %s
+
+--- |
+  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()
+
+  attributes #0 = { minsize optsize }
+  attributes #1 = { minsize optsize "target-features"="+armv7-a,+thumb-mode" }
+...
+---
+
+name:           outline_no_save_ok_arm
+tracksRegLiveness: true
+body:             |
+  ; CHECK-LABEL: name: outline_no_save_ok_arm
+  ; CHECK: bb.0:
+  ; CHECK:   BL @OUTLINED_FUNCTION_1
+  ; CHECK: bb.1:
+  ; CHECK:   BL @OUTLINED_FUNCTION_1
+  ; CHECK: bb.2:
+  ; CHECK:   BX_RET 14 /* CC::al */, $noreg
+  bb.0:
+    $r2 = MOVi 1, 14, $noreg, $noreg
+    $r2 = MOVi 1, 14, $noreg, $noreg
+    $r2 = MOVi 1, 14, $noreg, $noreg
+    $r2 = MOVi 1, 14, $noreg, $noreg
+    $r3 = LDRi12 $sp, 8, 14, $noreg
+  bb.1:
+    $r2 = MOVi 1, 14, $noreg, $noreg
+    $r2 = MOVi 1, 14, $noreg, $noreg
+    $r2 = MOVi 1, 14, $noreg, $noreg
+    $r2 = MOVi 1, 14, $noreg, $noreg
+    $r3 = LDRi12 $sp, 8, 14, $noreg
+  bb.2:
+    BX_RET 14, $noreg
+...
+---
+
+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:             |
+  ; CHECK-LABEL: name: outline_no_save_ok_thumb
+  ; CHECK: bb.0:
+  ; CHECK:   tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_0
+  ; CHECK: bb.1:
+  ; CHECK:   tBL 14 /* CC::al */, $noreg, @OUTLINED_FUNCTION_0
+  ; CHECK: bb.2:
+  ; CHECK:   tBX_RET 14 /* CC::al */, $noreg
+  bb.0:
+    $r2 = t2MOVi 1, 14, $noreg, $noreg
+    $r2 = t2MOVi 1, 14, $noreg, $noreg
+    $r2 = t2MOVi 1, 14, $noreg, $noreg
+    $r2 = t2MOVi 1, 14, $noreg, $noreg
+    t2STRi12 $r2, $sp, 0, 14, $noreg
+  bb.1:
+    $r2 = t2MOVi 1, 14, $noreg, $noreg
+    $r2 = t2MOVi 1, 14, $noreg, $noreg
+    $r2 = t2MOVi 1, 14, $noreg, $noreg
+    $r2 = t2MOVi 1, 14, $noreg, $noreg
+    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:
+    tBX_RET 14, $noreg
+
+  ; CHECK-LABEL: name: OUTLINED_FUNCTION_0
+  ; CHECK: bb.0:
+  ; CHECK:   $r2 = t2MOVi 1, 14 /* CC::al */, $noreg, $noreg
+  ; CHECK:   $r2 = t2MOVi 1, 14 /* CC::al */, $noreg, $noreg
+  ; CHECK:   $r2 = t2MOVi 1, 14 /* CC::al */, $noreg, $noreg
+  ; CHECK:   $r2 = t2MOVi 1, 14 /* CC::al */, $noreg, $noreg
+  ; CHECK:   t2STRi12 $r2, $sp, 0, 14 /* CC::al */, $noreg
+  ; CHECK:   tBX_RET 14 /* CC::al */, $noreg
+
+  ; CHECK-LABEL: name: OUTLINED_FUNCTION_1
+  ; CHECK: bb.0:
+  ; CHECK:   $r2 = MOVi 1, 14 /* CC::al */, $noreg, $noreg
+  ; CHECK:   $r2 = MOVi 1, 14 /* CC::al */, $noreg, $noreg
+  ; CHECK:   $r2 = MOVi 1, 14 /* CC::al */, $noreg, $noreg
+  ; CHECK:   $r2 = MOVi 1, 14 /* CC::al */, $noreg, $noreg
+  ; CHECK:   $r3 = LDRi12 $sp, 8, 14 /* CC::al */, $noreg
+  ; CHECK:   MOVPCLR 14 /* CC::al */, $noreg


        


More information about the llvm-commits mailing list