forked from OSchip/llvm-project
[ARM][MachineOutliner] Add calls handling.
Handles calls inside outlined regions, by saving and restoring the link register. Differential Revision: https://reviews.llvm.org/D87136
This commit is contained in:
parent
a8a85166d8
commit
070b96962f
|
@ -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()))
|
||||
|
|
|
@ -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: |
|
||||
|
|
Loading…
Reference in New Issue