[llvm] 070b969 - [ARM][MachineOutliner] Add calls handling.

Yvan Roux via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 16 01:00:15 PDT 2020


Author: Yvan Roux
Date: 2020-09-16T09:54:26+02:00
New Revision: 070b96962f517772fff4bf3c27cc825b46a136b5

URL: https://github.com/llvm/llvm-project/commit/070b96962f517772fff4bf3c27cc825b46a136b5
DIFF: https://github.com/llvm/llvm-project/commit/070b96962f517772fff4bf3c27cc825b46a136b5.diff

LOG: [ARM][MachineOutliner] Add calls handling.

Handles calls inside outlined regions, by saving and restoring the link
register.

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

Added: 
    

Modified: 
    llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
    llvm/test/CodeGen/ARM/machine-outliner-default.mir

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
index d7d51fdd29ca..d81c8efa1597 100644
--- a/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
+++ b/llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
@@ -5678,6 +5678,7 @@ struct OutlinerCosts {
   const int FrameRegSave;
   const int CallDefault;
   const int FrameDefault;
+  const int SaveRestoreLROnStack;
 
   OutlinerCosts(const ARMSubtarget &target)
       : CallTailCall(target.isThumb() ? 4 : 4),
@@ -5689,7 +5690,8 @@ struct OutlinerCosts {
         CallRegSave(target.isThumb() ? 8 : 12),
         FrameRegSave(target.isThumb() ? 2 : 4),
         CallDefault(target.isThumb() ? 8 : 12),
-        FrameDefault(target.isThumb() ? 2 : 4) {}
+        FrameDefault(target.isThumb() ? 2 : 4),
+        SaveRestoreLROnStack(target.isThumb() ? 8 : 8) {}
 };
 
 unsigned
@@ -5830,10 +5832,28 @@ outliner::OutlinedFunction ARMBaseInstrInfo::getOutliningCandidateInfo(
         C.setCallInfo(MachineOutlinerDefault, Costs.CallDefault);
         SetCandidateCallInfo(MachineOutlinerDefault, Costs.CallDefault);
         CandidatesWithoutStackFixups.push_back(C);
-      }
-    else
+      } else
         return outliner::OutlinedFunction();
     }
+
+    // Does every candidate's MBB contain a call?  If so, then we might have a
+    // call in the range.
+    if (FlagsSetInAll & MachineOutlinerMBBFlags::HasCalls) {
+      // check if the range contains a call.  These require a save + restore of
+      // the link register.
+      if (std::any_of(FirstCand.front(), FirstCand.back(),
+                      [](const MachineInstr &MI) { return MI.isCall(); }))
+        NumBytesToCreateFrame += Costs.SaveRestoreLROnStack;
+
+      // Handle the last instruction separately.  If it is tail call, then the
+      // last instruction is a call, we don't want to save + restore in this
+      // case.  However, it could be possible that the last instruction is a
+      // call without it being valid to tail call this sequence.  We should
+      // consider this as well.
+      else if (FrameID != MachineOutlinerThunk &&
+               FrameID != MachineOutlinerTailCall && FirstCand.back()->isCall())
+        NumBytesToCreateFrame += Costs.SaveRestoreLROnStack;
+    }
     RepeatedSequenceLocs = CandidatesWithoutStackFixups;
   }
 
@@ -5973,6 +5993,23 @@ ARMBaseInstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT,
     return outliner::InstrType::Illegal;
 
   if (MI.isCall()) {
+    // Get the function associated with the call.  Look at each operand and find
+    // the one that represents the calle and get its name.
+    const Function *Callee = nullptr;
+    for (const MachineOperand &MOP : MI.operands()) {
+      if (MOP.isGlobal()) {
+        Callee = dyn_cast<Function>(MOP.getGlobal());
+        break;
+      }
+    }
+
+    // Dont't outline calls to "mcount" like functions, in particular Linux
+    // kernel function tracing relies on it.
+    if (Callee &&
+        (Callee->getName() == "\01__gnu_mcount_nc" ||
+         Callee->getName() == "\01mcount" || Callee->getName() == "__mcount"))
+      return outliner::InstrType::Illegal;
+
     // If we don't know anything about the callee, assume it depends on the
     // stack layout of the caller. In that case, it's only legal to outline
     // as a tail-call. Explicitly list the call instructions we know about so
@@ -5982,7 +6019,29 @@ ARMBaseInstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT,
         Opc == ARM::tBLXr || Opc == ARM::tBLXi)
       UnknownCallOutlineType = outliner::InstrType::LegalTerminator;
 
-    return UnknownCallOutlineType;
+    if (!Callee)
+      return UnknownCallOutlineType;
+
+    // We have a function we have information about.  Check if it's something we
+    // can safely outline.
+    MachineFunction *MF = MI.getParent()->getParent();
+    MachineFunction *CalleeMF = MF->getMMI().getMachineFunction(*Callee);
+
+    // We don't know what's going on with the callee at all.  Don't touch it.
+    if (!CalleeMF)
+      return UnknownCallOutlineType;
+
+    // Check if we know anything about the callee saves on the function. If we
+    // don't, then don't touch it, since that implies that we haven't computed
+    // anything about its stack frame yet.
+    MachineFrameInfo &MFI = CalleeMF->getFrameInfo();
+    if (!MFI.isCalleeSavedInfoValid() || MFI.getStackSize() > 0 ||
+        MFI.getNumObjects() > 0)
+      return UnknownCallOutlineType;
+
+    // At this point, we can say that CalleeMF ought to not pass anything on the
+    // stack. Therefore, we can outline it.
+    return outliner::InstrType::Legal;
   }
 
   // Since calls are handled, don't touch LR or PC
@@ -6045,10 +6104,6 @@ void ARMBaseInstrInfo::restoreLRFromStack(
 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) {
@@ -6065,9 +6120,57 @@ void ARMBaseInstrInfo::buildOutlinedFrame(
     if (isThumb && !Call->getOperand(FuncOp).isReg())
       MIB.add(predOps(ARMCC::AL));
     Call->eraseFromParent();
-    return;
   }
 
+  // Is there a call in the outlined range?
+  auto IsNonTailCall = [](MachineInstr &MI) {
+    return MI.isCall() && !MI.isReturn();
+  };
+  if (std::any_of(MBB.instr_begin(), MBB.instr_end(), IsNonTailCall)) {
+    MachineBasicBlock::iterator It = MBB.begin();
+    MachineBasicBlock::iterator Et = MBB.end();
+
+    if (OF.FrameConstructionID == MachineOutlinerTailCall ||
+        OF.FrameConstructionID == MachineOutlinerThunk)
+      Et = std::prev(MBB.end());
+
+    // We have to save and restore LR, we need to add it to the liveins if it
+    // is not already part of the set.  This is suffient since outlined
+    // functions only have one block.
+    if (!MBB.isLiveIn(ARM::LR))
+      MBB.addLiveIn(ARM::LR);
+
+    // Insert a save before the outlined region
+    saveLROnStack(MBB, It);
+
+    unsigned StackAlignment = Subtarget.getStackAlignment().value();
+    const TargetSubtargetInfo &STI = MF.getSubtarget();
+    const MCRegisterInfo *MRI = STI.getRegisterInfo();
+    unsigned DwarfReg = MRI->getDwarfRegNum(ARM::LR, true);
+    // Add a CFI saying the stack was moved down.
+    int64_t StackPosEntry = MF.addFrameInst(
+        MCCFIInstruction::cfiDefCfaOffset(nullptr, StackAlignment));
+    BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION))
+        .addCFIIndex(StackPosEntry)
+        .setMIFlags(MachineInstr::FrameSetup);
+
+    // Add a CFI saying that the LR that we want to find is now higher than
+    // before.
+    int64_t LRPosEntry = MF.addFrameInst(
+        MCCFIInstruction::createOffset(nullptr, DwarfReg, StackAlignment));
+    BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION))
+        .addCFIIndex(LRPosEntry)
+        .setMIFlags(MachineInstr::FrameSetup);
+
+    // Insert a restore before the terminator for the function.  Restore LR.
+    restoreLRFromStack(MBB, Et);
+  }
+
+  // If this is a tail call outlined function, then there's already a return.
+  if (OF.FrameConstructionID == MachineOutlinerTailCall ||
+      OF.FrameConstructionID == MachineOutlinerThunk)
+    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()))

diff  --git a/llvm/test/CodeGen/ARM/machine-outliner-default.mir b/llvm/test/CodeGen/ARM/machine-outliner-default.mir
index 452d6a96c539..9db4207d2df7 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_call_arm() #0 { ret void }
-  define void @outline_default_KO_call_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()
@@ -118,120 +116,6 @@ body:             |
 ...
 ---
 
-name:           outline_default_KO_call_arm
-tracksRegLiveness: true
-body:             |
-  ; CHECK-LABEL: name: outline_default_KO_call_arm
-  ; CHECK: bb.0:
-  ; CHECK:   liveins: $lr
-  ; CHECK:   BL @bar, implicit-def dead $lr, implicit $sp
-  ; CHECK:   $r0 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r1 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r2 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r3 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r4 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK: bb.1:
-  ; CHECK:   liveins: $lr, $r5, $r6, $r7, $r8, $r9, $r10, $r11
-  ; CHECK:   BL @bar, implicit-def dead $lr, implicit $sp
-  ; CHECK:   $r0 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r1 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r2 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r3 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r4 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK: bb.2:
-  ; CHECK:   liveins: $lr, $r5, $r6, $r7, $r8, $r9, $r10, $r11
-  ; CHECK:   BL @bar, implicit-def dead $lr, implicit $sp
-  ; CHECK:   $r0 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r1 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r2 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r3 = MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r4 = MOVi 2, 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
-    BL @bar, implicit-def dead $lr, implicit $sp
-    $r0 = MOVi 2, 14, $noreg, $noreg
-    $r1 = MOVi 2, 14, $noreg, $noreg
-    $r2 = MOVi 2, 14, $noreg, $noreg
-    $r3 = MOVi 2, 14, $noreg, $noreg
-    $r4 = MOVi 2, 14, $noreg, $noreg
-  bb.1:
-    liveins: $lr, $r5, $r6, $r7, $r8, $r9, $r10, $r11
-    BL @bar, implicit-def dead $lr, implicit $sp
-    $r0 = MOVi 2, 14, $noreg, $noreg
-    $r1 = MOVi 2, 14, $noreg, $noreg
-    $r2 = MOVi 2, 14, $noreg, $noreg
-    $r3 = MOVi 2, 14, $noreg, $noreg
-    $r4 = MOVi 2, 14, $noreg, $noreg
-  bb.2:
-    liveins: $lr, $r5, $r6, $r7, $r8, $r9, $r10, $r11
-    BL @bar, implicit-def dead $lr, implicit $sp
-    $r0 = MOVi 2, 14, $noreg, $noreg
-    $r1 = MOVi 2, 14, $noreg, $noreg
-    $r2 = MOVi 2, 14, $noreg, $noreg
-    $r3 = MOVi 2, 14, $noreg, $noreg
-    $r4 = MOVi 2, 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_call_thumb
-tracksRegLiveness: true
-body:             |
-  ; CHECK-LABEL: name: outline_default_KO_call_thumb
-  ; CHECK: bb.0:
-  ; CHECK:   liveins: $lr
-  ; CHECK:   tBL 14 /* CC::al */, $noreg, @bar, implicit-def dead $lr, implicit $sp
-  ; CHECK:   $r0 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r1 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r2 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK: bb.1:
-  ; CHECK:   liveins: $lr, $r3, $r4, $r5, $r6, $r7, $r8, $r9, $r10, $r11
-  ; CHECK:   tBL 14 /* CC::al */, $noreg, @bar, implicit-def dead $lr, implicit $sp
-  ; CHECK:   $r0 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r1 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r2 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK: bb.2:
-  ; CHECK:   liveins: $lr, $r3, $r4, $r5, $r6, $r7, $r8, $r9, $r10, $r11
-  ; CHECK:   tBL 14 /* CC::al */, $noreg, @bar, implicit-def dead $lr, implicit $sp
-  ; CHECK:   $r0 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r1 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK:   $r2 = t2MOVi 2, 14 /* CC::al */, $noreg, $noreg
-  ; CHECK: bb.3:
-  ; CHECK:   liveins: $lr, $r3, $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
-    tBL 14, $noreg, @bar, implicit-def dead $lr, implicit $sp
-    $r0 = t2MOVi 2, 14, $noreg, $noreg
-    $r1 = t2MOVi 2, 14, $noreg, $noreg
-    $r2 = t2MOVi 2, 14, $noreg, $noreg
-  bb.1:
-    liveins: $lr, $r3, $r4, $r5, $r6, $r7, $r8, $r9, $r10, $r11
-    tBL 14, $noreg, @bar, implicit-def dead $lr, implicit $sp
-    $r0 = t2MOVi 2, 14, $noreg, $noreg
-    $r1 = t2MOVi 2, 14, $noreg, $noreg
-    $r2 = t2MOVi 2, 14, $noreg, $noreg
-  bb.2:
-    liveins: $lr, $r3, $r4, $r5, $r6, $r7, $r8, $r9, $r10, $r11
-    tBL 14, $noreg, @bar, implicit-def dead $lr, implicit $sp
-    $r0 = t2MOVi 2, 14, $noreg, $noreg
-    $r1 = t2MOVi 2, 14, $noreg, $noreg
-    $r2 = t2MOVi 2, 14, $noreg, $noreg
-  bb.3:
-    liveins: $lr, $r3, $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:             |


        


More information about the llvm-commits mailing list