Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
llvm/lib/Target/ARM/ARMBaseInstrInfo.cpp
Show First 20 Lines • Show All 5,672 Lines • ▼ Show 20 Lines | |||||
/// I3 I2 | /// I3 I2 | ||||
/// I3 | /// I3 | ||||
/// BX LR | /// BX LR | ||||
/// | /// | ||||
/// +-------------------------+--------+-----+ | /// +-------------------------+--------+-----+ | ||||
/// | | Thumb2 | ARM | | /// | | Thumb2 | ARM | | ||||
/// +-------------------------+--------+-----+ | /// +-------------------------+--------+-----+ | ||||
/// | Call overhead in Bytes | 4 | 4 | | /// | Call overhead in Bytes | 4 | 4 | | ||||
/// | Frame overhead in Bytes | 4 | 4 | | /// | Frame overhead in Bytes | 2 | 4 | | ||||
/// | Stack fixup required | No | No | | /// | Stack fixup required | No | No | | ||||
/// +-------------------------+--------+-----+ | /// +-------------------------+--------+-----+ | ||||
/// | /// | ||||
/// \p MachineOutlinerRegSave implies that the function should be called with a | /// \p MachineOutlinerRegSave implies that the function should be called with a | ||||
/// save and restore of LR to an available register. This allows us to avoid | /// save and restore of LR to an available register. This allows us to avoid | ||||
/// stack fixups. Note that this outlining variant is compatible with the | /// stack fixups. Note that this outlining variant is compatible with the | ||||
/// NoLRSave case. | /// NoLRSave case. | ||||
/// | /// | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | struct OutlinerCosts { | ||||
int SaveRestoreLROnStack; | int SaveRestoreLROnStack; | ||||
OutlinerCosts(const ARMSubtarget &target) | OutlinerCosts(const ARMSubtarget &target) | ||||
: CallTailCall(target.isThumb() ? 4 : 4), | : CallTailCall(target.isThumb() ? 4 : 4), | ||||
FrameTailCall(target.isThumb() ? 0 : 0), | FrameTailCall(target.isThumb() ? 0 : 0), | ||||
CallThunk(target.isThumb() ? 4 : 4), | CallThunk(target.isThumb() ? 4 : 4), | ||||
FrameThunk(target.isThumb() ? 0 : 0), | FrameThunk(target.isThumb() ? 0 : 0), | ||||
CallNoLRSave(target.isThumb() ? 4 : 4), | CallNoLRSave(target.isThumb() ? 4 : 4), | ||||
FrameNoLRSave(target.isThumb() ? 4 : 4), | FrameNoLRSave(target.isThumb() ? 2 : 4), | ||||
CallRegSave(target.isThumb() ? 8 : 12), | CallRegSave(target.isThumb() ? 8 : 12), | ||||
FrameRegSave(target.isThumb() ? 2 : 4), | FrameRegSave(target.isThumb() ? 2 : 4), | ||||
CallDefault(target.isThumb() ? 8 : 12), | CallDefault(target.isThumb() ? 8 : 12), | ||||
FrameDefault(target.isThumb() ? 2 : 4), | FrameDefault(target.isThumb() ? 2 : 4), | ||||
SaveRestoreLROnStack(target.isThumb() ? 8 : 8) {} | SaveRestoreLROnStack(target.isThumb() ? 8 : 8) {} | ||||
}; | }; | ||||
unsigned | unsigned | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | if (!(FlagsSetInAll & UnsafeRegsDead)) { | ||||
// the case that, say, 1 out of 20 candidates violate the restructions.) | // the case that, say, 1 out of 20 candidates violate the restructions.) | ||||
llvm::erase_if(RepeatedSequenceLocs, CantGuaranteeValueAcrossCall); | llvm::erase_if(RepeatedSequenceLocs, CantGuaranteeValueAcrossCall); | ||||
// If the sequence doesn't have enough candidates left, then we're done. | // If the sequence doesn't have enough candidates left, then we're done. | ||||
if (RepeatedSequenceLocs.size() < 2) | if (RepeatedSequenceLocs.size() < 2) | ||||
return outliner::OutlinedFunction(); | return outliner::OutlinedFunction(); | ||||
} | } | ||||
// We expect the majority of the outlining candidates to be in consensus with | |||||
// regard to return address sign and authentication, and branch target | |||||
// enforcement, in other words, partitioning according to all the four | |||||
// possible combinations of PAC-RET and BTI is going to yield one big subset | |||||
// and three small (likely empty) subsets. That allows us to cull incompatible | |||||
// candidates separately for PAC-RET and BTI. | |||||
// Partition the candidates in two sets: one with BTI enabled and one with BTI | // Partition the candidates in two sets: one with BTI enabled and one with BTI | ||||
// disabled. Remove the candidates from the smaller set. We expect the | // disabled. Remove the candidates from the smaller set. If they are the same | ||||
// majority of the candidates to be in consensus with regard to branch target | // number prefer the non-BTI ones for outlining, since they have less | ||||
// enforcement with just a few oddballs, but if they are the same number | // overhead. | ||||
// prefer the non-BTI ones for outlining, since they have less overhead. | |||||
auto NoBTI = | auto NoBTI = | ||||
llvm::partition(RepeatedSequenceLocs, [](const outliner::Candidate &C) { | llvm::partition(RepeatedSequenceLocs, [](const outliner::Candidate &C) { | ||||
const ARMFunctionInfo &AFI = *C.getMF()->getInfo<ARMFunctionInfo>(); | const ARMFunctionInfo &AFI = *C.getMF()->getInfo<ARMFunctionInfo>(); | ||||
return AFI.branchTargetEnforcement(); | return AFI.branchTargetEnforcement(); | ||||
}); | }); | ||||
if (std::distance(RepeatedSequenceLocs.begin(), NoBTI) > | if (std::distance(RepeatedSequenceLocs.begin(), NoBTI) > | ||||
std::distance(NoBTI, RepeatedSequenceLocs.end())) | std::distance(NoBTI, RepeatedSequenceLocs.end())) | ||||
RepeatedSequenceLocs.erase(NoBTI, RepeatedSequenceLocs.end()); | RepeatedSequenceLocs.erase(NoBTI, RepeatedSequenceLocs.end()); | ||||
else | else | ||||
RepeatedSequenceLocs.erase(RepeatedSequenceLocs.begin(), NoBTI); | RepeatedSequenceLocs.erase(RepeatedSequenceLocs.begin(), NoBTI); | ||||
if (RepeatedSequenceLocs.size() < 2) | |||||
return outliner::OutlinedFunction(); | |||||
// Likewise, partition the candidates according to PAC-RET enablement. | |||||
auto NoPAC = | |||||
llvm::partition(RepeatedSequenceLocs, [](const outliner::Candidate &C) { | |||||
const ARMFunctionInfo &AFI = *C.getMF()->getInfo<ARMFunctionInfo>(); | |||||
// If the function happens to not spill the LR, do not disqualify it | |||||
// from the outlining. | |||||
return AFI.shouldSignReturnAddress(true); | |||||
}); | |||||
if (std::distance(RepeatedSequenceLocs.begin(), NoPAC) > | |||||
std::distance(NoPAC, RepeatedSequenceLocs.end())) | |||||
RepeatedSequenceLocs.erase(NoPAC, RepeatedSequenceLocs.end()); | |||||
else | |||||
RepeatedSequenceLocs.erase(RepeatedSequenceLocs.begin(), NoPAC); | |||||
if (RepeatedSequenceLocs.size() < 2) | if (RepeatedSequenceLocs.size() < 2) | ||||
return outliner::OutlinedFunction(); | return outliner::OutlinedFunction(); | ||||
// At this point, we have only "safe" candidates to outline. Figure out | // At this point, we have only "safe" candidates to outline. Figure out | ||||
// frame + call instruction information. | // frame + call instruction information. | ||||
unsigned LastInstrOpcode = RepeatedSequenceLocs[0].back()->getOpcode(); | unsigned LastInstrOpcode = RepeatedSequenceLocs[0].back()->getOpcode(); | ||||
// Helper lambda which sets call information for every candidate. | // Helper lambda which sets call information for every candidate. | ||||
auto SetCandidateCallInfo = | auto SetCandidateCallInfo = | ||||
[&RepeatedSequenceLocs](unsigned CallID, unsigned NumBytesForCall) { | [&RepeatedSequenceLocs](unsigned CallID, unsigned NumBytesForCall) { | ||||
for (outliner::Candidate &C : RepeatedSequenceLocs) | for (outliner::Candidate &C : RepeatedSequenceLocs) | ||||
C.setCallInfo(CallID, NumBytesForCall); | C.setCallInfo(CallID, NumBytesForCall); | ||||
}; | }; | ||||
OutlinerCosts Costs(Subtarget); | OutlinerCosts Costs(Subtarget); | ||||
const auto &SomeMFI = | const auto &SomeMFI = | ||||
*RepeatedSequenceLocs.front().getMF()->getInfo<ARMFunctionInfo>(); | *RepeatedSequenceLocs.front().getMF()->getInfo<ARMFunctionInfo>(); | ||||
// Adjust costs to account for the BTI instructions. | // Adjust costs to account for the BTI instructions. | ||||
if (SomeMFI.branchTargetEnforcement()) { | if (SomeMFI.branchTargetEnforcement()) { | ||||
Costs.FrameDefault += 4; | Costs.FrameDefault += 4; | ||||
Costs.FrameNoLRSave += 4; | Costs.FrameNoLRSave += 4; | ||||
Costs.FrameRegSave += 4; | Costs.FrameRegSave += 4; | ||||
Costs.FrameTailCall += 4; | Costs.FrameTailCall += 4; | ||||
Costs.FrameThunk += 4; | Costs.FrameThunk += 4; | ||||
} | } | ||||
// Adjust costs to account for sign and authentication instructions. | |||||
if (SomeMFI.shouldSignReturnAddress(true)) { | |||||
Costs.CallDefault += 8; // +PAC instr, +AUT instr | |||||
Costs.SaveRestoreLROnStack += 8; // +PAC instr, +AUT instr | |||||
} | |||||
unsigned FrameID = MachineOutlinerDefault; | unsigned FrameID = MachineOutlinerDefault; | ||||
unsigned NumBytesToCreateFrame = Costs.FrameDefault; | unsigned NumBytesToCreateFrame = Costs.FrameDefault; | ||||
// If the last instruction in any candidate is a terminator, then we should | // If the last instruction in any candidate is a terminator, then we should | ||||
// tail call all of the candidates. | // tail call all of the candidates. | ||||
if (RepeatedSequenceLocs[0].back()->isTerminator()) { | if (RepeatedSequenceLocs[0].back()->isTerminator()) { | ||||
FrameID = MachineOutlinerTailCall; | FrameID = MachineOutlinerTailCall; | ||||
NumBytesToCreateFrame = Costs.FrameTailCall; | NumBytesToCreateFrame = Costs.FrameTailCall; | ||||
▲ Show 20 Lines • Show All 400 Lines • ▼ Show 20 Lines | ARMBaseInstrInfo::getOutliningType(MachineBasicBlock::iterator &MIT, | ||||
// Does this use the stack? | // Does this use the stack? | ||||
if (MI.modifiesRegister(ARM::SP, TRI) || MI.readsRegister(ARM::SP, TRI)) { | if (MI.modifiesRegister(ARM::SP, TRI) || MI.readsRegister(ARM::SP, TRI)) { | ||||
// True if there is no chance that any outlined candidate from this range | // True if there is no chance that any outlined candidate from this range | ||||
// could require stack fixups. That is, both | // could require stack fixups. That is, both | ||||
// * LR is available in the range (No save/restore around call) | // * LR is available in the range (No save/restore around call) | ||||
// * The range doesn't include calls (No save/restore in outlined frame) | // * The range doesn't include calls (No save/restore in outlined frame) | ||||
// are true. | // are true. | ||||
// These conditions also ensure correctness of the return address | |||||
// authentication - we insert sign and authentication instructions only if | |||||
// we save/restore LR on stack, but then this condition ensures that the | |||||
// outlined range does not modify the SP, therefore the SP value used for | |||||
// signing is the same as the one used for authentication. | |||||
// FIXME: This is very restrictive; the flags check the whole block, | // FIXME: This is very restrictive; the flags check the whole block, | ||||
// not just the bit we will try to outline. | // not just the bit we will try to outline. | ||||
bool MightNeedStackFixUp = | bool MightNeedStackFixUp = | ||||
(Flags & (MachineOutlinerMBBFlags::LRUnavailableSomewhere | | (Flags & (MachineOutlinerMBBFlags::LRUnavailableSomewhere | | ||||
MachineOutlinerMBBFlags::HasCalls)); | MachineOutlinerMBBFlags::HasCalls)); | ||||
if (!MightNeedStackFixUp) | if (!MightNeedStackFixUp) | ||||
return outliner::InstrType::Legal; | return outliner::InstrType::Legal; | ||||
Show All 28 Lines | |||||
void ARMBaseInstrInfo::fixupPostOutline(MachineBasicBlock &MBB) const { | void ARMBaseInstrInfo::fixupPostOutline(MachineBasicBlock &MBB) const { | ||||
for (MachineInstr &MI : MBB) { | for (MachineInstr &MI : MBB) { | ||||
checkAndUpdateStackOffset(&MI, Subtarget.getStackAlignment().value(), true); | checkAndUpdateStackOffset(&MI, Subtarget.getStackAlignment().value(), true); | ||||
} | } | ||||
} | } | ||||
void ARMBaseInstrInfo::saveLROnStack(MachineBasicBlock &MBB, | void ARMBaseInstrInfo::saveLROnStack(MachineBasicBlock &MBB, | ||||
MachineBasicBlock::iterator It) const { | MachineBasicBlock::iterator It, bool CFI, | ||||
bool Auth) const { | |||||
int Align = std::max(Subtarget.getStackAlignment().value(), uint64_t(8)); | |||||
assert(Align >= 8 && Align <= 256); | |||||
if (Auth) { | |||||
assert(Subtarget.isThumb2()); | |||||
// Compute PAC in R12. Outlining ensures R12 is dead across the outlined | |||||
// sequence. | |||||
BuildMI(MBB, It, DebugLoc(), get(ARM::t2PAC)) | |||||
.setMIFlags(MachineInstr::FrameSetup); | |||||
BuildMI(MBB, It, DebugLoc(), get(ARM::t2STRD_PRE), ARM::SP) | |||||
.addReg(ARM::R12, RegState::Kill) | |||||
.addReg(ARM::LR, RegState::Kill) | |||||
.addReg(ARM::SP) | |||||
.addImm(-Align) | |||||
.add(predOps(ARMCC::AL)) | |||||
.setMIFlags(MachineInstr::FrameSetup); | |||||
} else { | |||||
unsigned Opc = Subtarget.isThumb() ? ARM::t2STR_PRE : ARM::STR_PRE_IMM; | unsigned Opc = Subtarget.isThumb() ? ARM::t2STR_PRE : ARM::STR_PRE_IMM; | ||||
int Align = -Subtarget.getStackAlignment().value(); | |||||
BuildMI(MBB, It, DebugLoc(), get(Opc), ARM::SP) | BuildMI(MBB, It, DebugLoc(), get(Opc), ARM::SP) | ||||
.addReg(ARM::LR, RegState::Kill) | .addReg(ARM::LR, RegState::Kill) | ||||
.addReg(ARM::SP) | .addReg(ARM::SP) | ||||
.addImm(Align) | .addImm(-Align) | ||||
.add(predOps(ARMCC::AL)); | .add(predOps(ARMCC::AL)) | ||||
.setMIFlags(MachineInstr::FrameSetup); | |||||
} | } | ||||
void ARMBaseInstrInfo::emitCFIForLRSaveOnStack( | if (!CFI) | ||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator It) const { | return; | ||||
MachineFunction &MF = *MBB.getParent(); | MachineFunction &MF = *MBB.getParent(); | ||||
const MCRegisterInfo *MRI = Subtarget.getRegisterInfo(); | |||||
unsigned DwarfLR = MRI->getDwarfRegNum(ARM::LR, true); | // Add a CFI, saying CFA is offset by Align bytes from SP. | ||||
int Align = Subtarget.getStackAlignment().value(); | |||||
// Add a CFI saying the stack was moved down. | |||||
int64_t StackPosEntry = | int64_t StackPosEntry = | ||||
MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, Align)); | MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, Align)); | ||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION)) | BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION)) | ||||
.addCFIIndex(StackPosEntry) | .addCFIIndex(StackPosEntry) | ||||
.setMIFlags(MachineInstr::FrameSetup); | .setMIFlags(MachineInstr::FrameSetup); | ||||
// Add a CFI saying that the LR that we want to find is now higher than | // Add a CFI saying that the LR that we want to find is now higher than | ||||
// before. | // before. | ||||
int64_t LRPosEntry = | int LROffset = Auth ? Align - 4 : Align; | ||||
MF.addFrameInst(MCCFIInstruction::createOffset(nullptr, DwarfLR, -Align)); | const MCRegisterInfo *MRI = Subtarget.getRegisterInfo(); | ||||
unsigned DwarfLR = MRI->getDwarfRegNum(ARM::LR, true); | |||||
int64_t LRPosEntry = MF.addFrameInst( | |||||
MCCFIInstruction::createOffset(nullptr, DwarfLR, -LROffset)); | |||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION)) | BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION)) | ||||
.addCFIIndex(LRPosEntry) | .addCFIIndex(LRPosEntry) | ||||
.setMIFlags(MachineInstr::FrameSetup); | .setMIFlags(MachineInstr::FrameSetup); | ||||
if (Auth) { | |||||
// Add a CFI for the location of the return adddress PAC. | |||||
unsigned DwarfRAC = MRI->getDwarfRegNum(ARM::RA_AUTH_CODE, true); | |||||
int64_t RACPosEntry = MF.addFrameInst( | |||||
MCCFIInstruction::createOffset(nullptr, DwarfRAC, -Align)); | |||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION)) | |||||
.addCFIIndex(RACPosEntry) | |||||
.setMIFlags(MachineInstr::FrameSetup); | |||||
} | |||||
} | } | ||||
void ARMBaseInstrInfo::emitCFIForLRSaveToReg(MachineBasicBlock &MBB, | void ARMBaseInstrInfo::emitCFIForLRSaveToReg(MachineBasicBlock &MBB, | ||||
MachineBasicBlock::iterator It, | MachineBasicBlock::iterator It, | ||||
Register Reg) const { | Register Reg) const { | ||||
MachineFunction &MF = *MBB.getParent(); | MachineFunction &MF = *MBB.getParent(); | ||||
const MCRegisterInfo *MRI = Subtarget.getRegisterInfo(); | const MCRegisterInfo *MRI = Subtarget.getRegisterInfo(); | ||||
unsigned DwarfLR = MRI->getDwarfRegNum(ARM::LR, true); | unsigned DwarfLR = MRI->getDwarfRegNum(ARM::LR, true); | ||||
unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true); | unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true); | ||||
int64_t LRPosEntry = MF.addFrameInst( | int64_t LRPosEntry = MF.addFrameInst( | ||||
MCCFIInstruction::createRegister(nullptr, DwarfLR, DwarfReg)); | MCCFIInstruction::createRegister(nullptr, DwarfLR, DwarfReg)); | ||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION)) | BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION)) | ||||
.addCFIIndex(LRPosEntry) | .addCFIIndex(LRPosEntry) | ||||
.setMIFlags(MachineInstr::FrameSetup); | .setMIFlags(MachineInstr::FrameSetup); | ||||
} | } | ||||
void ARMBaseInstrInfo::restoreLRFromStack( | void ARMBaseInstrInfo::restoreLRFromStack(MachineBasicBlock &MBB, | ||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator It) const { | MachineBasicBlock::iterator It, | ||||
bool CFI, bool Auth) const { | |||||
int Align = Subtarget.getStackAlignment().value(); | |||||
if (Auth) { | |||||
assert(Subtarget.isThumb2()); | |||||
// Restore return address PAC and LR. | |||||
BuildMI(MBB, It, DebugLoc(), get(ARM::t2LDRD_POST)) | |||||
.addReg(ARM::R12, RegState::Define) | |||||
.addReg(ARM::LR, RegState::Define) | |||||
.addReg(ARM::SP, RegState::Define) | |||||
.addReg(ARM::SP) | |||||
.addImm(Align) | |||||
.add(predOps(ARMCC::AL)) | |||||
.setMIFlags(MachineInstr::FrameDestroy); | |||||
// LR authentication is after the CFI instructions, below. | |||||
} else { | |||||
unsigned Opc = Subtarget.isThumb() ? ARM::t2LDR_POST : ARM::LDR_POST_IMM; | unsigned Opc = Subtarget.isThumb() ? ARM::t2LDR_POST : ARM::LDR_POST_IMM; | ||||
MachineInstrBuilder MIB = BuildMI(MBB, It, DebugLoc(), get(Opc), ARM::LR) | MachineInstrBuilder MIB = BuildMI(MBB, It, DebugLoc(), get(Opc), ARM::LR) | ||||
.addReg(ARM::SP, RegState::Define) | .addReg(ARM::SP, RegState::Define) | ||||
.addReg(ARM::SP); | .addReg(ARM::SP); | ||||
if (!Subtarget.isThumb()) | if (!Subtarget.isThumb()) | ||||
MIB.addReg(0); | MIB.addReg(0); | ||||
MIB.addImm(Subtarget.getStackAlignment().value()).add(predOps(ARMCC::AL)); | MIB.addImm(Subtarget.getStackAlignment().value()) | ||||
.add(predOps(ARMCC::AL)) | |||||
.setMIFlags(MachineInstr::FrameDestroy); | |||||
} | } | ||||
void ARMBaseInstrInfo::emitCFIForLRRestoreFromStack( | if (CFI) { | ||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator It) const { | |||||
// Now stack has moved back up... | // Now stack has moved back up... | ||||
MachineFunction &MF = *MBB.getParent(); | MachineFunction &MF = *MBB.getParent(); | ||||
const MCRegisterInfo *MRI = Subtarget.getRegisterInfo(); | const MCRegisterInfo *MRI = Subtarget.getRegisterInfo(); | ||||
unsigned DwarfLR = MRI->getDwarfRegNum(ARM::LR, true); | unsigned DwarfLR = MRI->getDwarfRegNum(ARM::LR, true); | ||||
int64_t StackPosEntry = | int64_t StackPosEntry = | ||||
MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, 0)); | MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, 0)); | ||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION)) | BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION)) | ||||
.addCFIIndex(StackPosEntry) | .addCFIIndex(StackPosEntry) | ||||
.setMIFlags(MachineInstr::FrameDestroy); | .setMIFlags(MachineInstr::FrameDestroy); | ||||
// ... and we have restored LR. | // ... and we have restored LR. | ||||
int64_t LRPosEntry = | int64_t LRPosEntry = | ||||
MF.addFrameInst(MCCFIInstruction::createRestore(nullptr, DwarfLR)); | MF.addFrameInst(MCCFIInstruction::createRestore(nullptr, DwarfLR)); | ||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION)) | BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION)) | ||||
.addCFIIndex(LRPosEntry) | .addCFIIndex(LRPosEntry) | ||||
.setMIFlags(MachineInstr::FrameDestroy); | .setMIFlags(MachineInstr::FrameDestroy); | ||||
if (Auth) { | |||||
unsigned DwarfRAC = MRI->getDwarfRegNum(ARM::RA_AUTH_CODE, true); | |||||
int64_t Entry = | |||||
MF.addFrameInst(MCCFIInstruction::createUndefined(nullptr, DwarfRAC)); | |||||
BuildMI(MBB, It, DebugLoc(), get(ARM::CFI_INSTRUCTION)) | |||||
.addCFIIndex(Entry) | |||||
.setMIFlags(MachineInstr::FrameDestroy); | |||||
} | |||||
} | |||||
if (Auth) | |||||
BuildMI(MBB, It, DebugLoc(), get(ARM::t2AUT)); | |||||
} | } | ||||
void ARMBaseInstrInfo::emitCFIForLRRestoreFromReg( | void ARMBaseInstrInfo::emitCFIForLRRestoreFromReg( | ||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator It) const { | MachineBasicBlock &MBB, MachineBasicBlock::iterator It) const { | ||||
MachineFunction &MF = *MBB.getParent(); | MachineFunction &MF = *MBB.getParent(); | ||||
const MCRegisterInfo *MRI = Subtarget.getRegisterInfo(); | const MCRegisterInfo *MRI = Subtarget.getRegisterInfo(); | ||||
unsigned DwarfLR = MRI->getDwarfRegNum(ARM::LR, true); | unsigned DwarfLR = MRI->getDwarfRegNum(ARM::LR, true); | ||||
Show All 39 Lines | if (llvm::any_of(MBB.instrs(), IsNonTailCall)) { | ||||
// We have to save and restore LR, we need to add it to the liveins if it | // 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 | // is not already part of the set. This is suffient since outlined | ||||
// functions only have one block. | // functions only have one block. | ||||
if (!MBB.isLiveIn(ARM::LR)) | if (!MBB.isLiveIn(ARM::LR)) | ||||
MBB.addLiveIn(ARM::LR); | MBB.addLiveIn(ARM::LR); | ||||
// Insert a save before the outlined region | // Insert a save before the outlined region | ||||
saveLROnStack(MBB, It); | bool Auth = OF.Candidates.front() | ||||
emitCFIForLRSaveOnStack(MBB, It); | .getMF() | ||||
->getInfo<ARMFunctionInfo>() | |||||
->shouldSignReturnAddress(true); | |||||
saveLROnStack(MBB, It, true, Auth); | |||||
// Fix up the instructions in the range, since we're going to modify the | // Fix up the instructions in the range, since we're going to modify the | ||||
// stack. | // stack. | ||||
assert(OF.FrameConstructionID != MachineOutlinerDefault && | assert(OF.FrameConstructionID != MachineOutlinerDefault && | ||||
"Can only fix up stack references once"); | "Can only fix up stack references once"); | ||||
fixupPostOutline(MBB); | fixupPostOutline(MBB); | ||||
// Insert a restore before the terminator for the function. Restore LR. | // Insert a restore before the terminator for the function. Restore LR. | ||||
restoreLRFromStack(MBB, Et); | restoreLRFromStack(MBB, Et, true, Auth); | ||||
emitCFIForLRRestoreFromStack(MBB, Et); | |||||
} | } | ||||
// If this is a tail call outlined function, then there's already a return. | // If this is a tail call outlined function, then there's already a return. | ||||
if (OF.FrameConstructionID == MachineOutlinerTailCall || | if (OF.FrameConstructionID == MachineOutlinerTailCall || | ||||
OF.FrameConstructionID == MachineOutlinerThunk) | OF.FrameConstructionID == MachineOutlinerThunk) | ||||
return; | return; | ||||
// Here we have to insert the return ourselves. Get the correct opcode from | // Here we have to insert the return ourselves. Get the correct opcode from | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | if (C.CallConstructionID == MachineOutlinerRegSave) { | ||||
if (!AFI.isLRSpilled()) | if (!AFI.isLRSpilled()) | ||||
emitCFIForLRRestoreFromReg(MBB, It); | emitCFIForLRRestoreFromReg(MBB, It); | ||||
It--; | It--; | ||||
return CallPt; | return CallPt; | ||||
} | } | ||||
// We have the default case. Save and restore from SP. | // We have the default case. Save and restore from SP. | ||||
if (!MBB.isLiveIn(ARM::LR)) | if (!MBB.isLiveIn(ARM::LR)) | ||||
MBB.addLiveIn(ARM::LR); | MBB.addLiveIn(ARM::LR); | ||||
saveLROnStack(MBB, It); | bool Auth = !AFI.isLRSpilled() && AFI.shouldSignReturnAddress(true); | ||||
if (!AFI.isLRSpilled()) | saveLROnStack(MBB, It, !AFI.isLRSpilled(), Auth); | ||||
emitCFIForLRSaveOnStack(MBB, It); | |||||
CallPt = MBB.insert(It, CallMIB); | CallPt = MBB.insert(It, CallMIB); | ||||
restoreLRFromStack(MBB, It); | restoreLRFromStack(MBB, It, !AFI.isLRSpilled(), Auth); | ||||
if (!AFI.isLRSpilled()) | |||||
emitCFIForLRRestoreFromStack(MBB, It); | |||||
It--; | It--; | ||||
return CallPt; | return CallPt; | ||||
} | } | ||||
bool ARMBaseInstrInfo::shouldOutlineFromFunctionByDefault( | bool ARMBaseInstrInfo::shouldOutlineFromFunctionByDefault( | ||||
MachineFunction &MF) const { | MachineFunction &MF) const { | ||||
return Subtarget.isMClass() && MF.getFunction().hasMinSize(); | return Subtarget.isMClass() && MF.getFunction().hasMinSize(); | ||||
} | } | ||||
Show All 25 Lines |