[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