Please use GitHub pull requests for new patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
llvm/lib/Target/ARM/ARMFrameLowering.cpp
Show First 20 Lines • Show All 497 Lines • ▼ Show 20 Lines | void ARMFrameLowering::emitPrologue(MachineFunction &MF, | ||||
// All calls are tail calls in GHC calling conv, and functions have no | // All calls are tail calls in GHC calling conv, and functions have no | ||||
// prologue/epilogue. | // prologue/epilogue. | ||||
if (MF.getFunction().getCallingConv() == CallingConv::GHC) | if (MF.getFunction().getCallingConv() == CallingConv::GHC) | ||||
return; | return; | ||||
StackAdjustingInsts DefCFAOffsetCandidates; | StackAdjustingInsts DefCFAOffsetCandidates; | ||||
bool HasFP = hasFP(MF); | bool HasFP = hasFP(MF); | ||||
// Allocate the vararg register save area. | |||||
if (ArgRegsSaveSize) { | |||||
emitSPUpdate(isARM, MBB, MBBI, dl, TII, -ArgRegsSaveSize, | |||||
MachineInstr::FrameSetup); | |||||
DefCFAOffsetCandidates.addInst(std::prev(MBBI), ArgRegsSaveSize, true); | |||||
} | |||||
if (!AFI->hasStackFrame() && | if (!AFI->hasStackFrame() && | ||||
(!STI.isTargetWindows() || !WindowsRequiresStackProbe(MF, NumBytes))) { | (!STI.isTargetWindows() || !WindowsRequiresStackProbe(MF, NumBytes))) { | ||||
if (NumBytes - ArgRegsSaveSize != 0) { | if (NumBytes != 0) { | ||||
emitSPUpdate(isARM, MBB, MBBI, dl, TII, -(NumBytes - ArgRegsSaveSize), | emitSPUpdate(isARM, MBB, MBBI, dl, TII, -NumBytes, | ||||
MachineInstr::FrameSetup); | MachineInstr::FrameSetup); | ||||
DefCFAOffsetCandidates.addInst(std::prev(MBBI), | DefCFAOffsetCandidates.addInst(std::prev(MBBI), NumBytes, true); | ||||
NumBytes - ArgRegsSaveSize, true); | |||||
} | } | ||||
DefCFAOffsetCandidates.emitDefCFAOffsets(MBB, dl, TII, HasFP); | DefCFAOffsetCandidates.emitDefCFAOffsets(MBB, dl, TII, HasFP); | ||||
return; | return; | ||||
} | } | ||||
// Determine spill area sizes. | // Determine spill area sizes. | ||||
for (const CalleeSavedInfo &I : CSI) { | for (const CalleeSavedInfo &I : CSI) { | ||||
unsigned Reg = I.getReg(); | unsigned Reg = I.getReg(); | ||||
Show All 29 Lines | default: | ||||
// This is a DPR. Exclude the aligned DPRCS2 spills. | // This is a DPR. Exclude the aligned DPRCS2 spills. | ||||
if (Reg == ARM::D8) | if (Reg == ARM::D8) | ||||
D8SpillFI = FI; | D8SpillFI = FI; | ||||
if (Reg < ARM::D8 || Reg >= ARM::D8 + AFI->getNumAlignedDPRCS2Regs()) | if (Reg < ARM::D8 || Reg >= ARM::D8 + AFI->getNumAlignedDPRCS2Regs()) | ||||
DPRCSSize += 8; | DPRCSSize += 8; | ||||
} | } | ||||
} | } | ||||
// Move past FPCXT area. | |||||
MachineBasicBlock::iterator LastPush = MBB.end(), GPRCS1Push, GPRCS2Push; | MachineBasicBlock::iterator LastPush = MBB.end(), GPRCS1Push, GPRCS2Push; | ||||
// Move past the PAC computation. | |||||
if (AFI->shouldSignReturnAddress()) | |||||
LastPush = MBBI++; | |||||
// Move past FPCXT area. | |||||
if (FPCXTSaveSize > 0) { | if (FPCXTSaveSize > 0) { | ||||
LastPush = MBBI++; | LastPush = MBBI++; | ||||
DefCFAOffsetCandidates.addInst(LastPush, FPCXTSaveSize, true); | DefCFAOffsetCandidates.addInst(LastPush, FPCXTSaveSize, true); | ||||
} | } | ||||
// Allocate the vararg register save area. | |||||
if (ArgRegsSaveSize) { | |||||
emitSPUpdate(isARM, MBB, MBBI, dl, TII, -ArgRegsSaveSize, | |||||
MachineInstr::FrameSetup); | |||||
LastPush = std::prev(MBBI); | |||||
DefCFAOffsetCandidates.addInst(LastPush, ArgRegsSaveSize, true); | |||||
} | |||||
// Move past area 1. | // Move past area 1. | ||||
if (GPRCS1Size > 0) { | if (GPRCS1Size > 0) { | ||||
GPRCS1Push = LastPush = MBBI++; | GPRCS1Push = LastPush = MBBI++; | ||||
DefCFAOffsetCandidates.addInst(LastPush, GPRCS1Size, true); | DefCFAOffsetCandidates.addInst(LastPush, GPRCS1Size, true); | ||||
} | } | ||||
// Determine starting offsets of spill areas. | // Determine starting offsets of spill areas. | ||||
unsigned FPCXTOffset = NumBytes - ArgRegsSaveSize - FPCXTSaveSize; | unsigned FPCXTOffset = NumBytes - ArgRegsSaveSize - FPCXTSaveSize; | ||||
▲ Show 20 Lines • Show All 203 Lines • ▼ Show 20 Lines | for (const auto &Entry : CSI) { | ||||
int FI = Entry.getFrameIdx(); | int FI = Entry.getFrameIdx(); | ||||
switch (Reg) { | switch (Reg) { | ||||
case ARM::R8: | case ARM::R8: | ||||
case ARM::R9: | case ARM::R9: | ||||
case ARM::R10: | case ARM::R10: | ||||
case ARM::R11: | case ARM::R11: | ||||
case ARM::R12: | case ARM::R12: | ||||
if (STI.splitFramePushPop(MF)) { | if (STI.splitFramePushPop(MF)) { | ||||
unsigned DwarfReg = MRI->getDwarfRegNum(Reg, true); | unsigned DwarfReg = MRI->getDwarfRegNum( | ||||
Reg == ARM::R12 ? ARM::RA_AUTH_CODE : Reg, true); | |||||
unsigned Offset = MFI.getObjectOffset(FI); | unsigned Offset = MFI.getObjectOffset(FI); | ||||
unsigned CFIIndex = MF.addFrameInst( | unsigned CFIIndex = MF.addFrameInst( | ||||
MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset)); | MCCFIInstruction::createOffset(nullptr, DwarfReg, Offset)); | ||||
BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) | BuildMI(MBB, Pos, dl, TII.get(TargetOpcode::CFI_INSTRUCTION)) | ||||
.addCFIIndex(CFIIndex) | .addCFIIndex(CFIIndex) | ||||
.setMIFlags(MachineInstr::FrameSetup); | .setMIFlags(MachineInstr::FrameSetup); | ||||
} | } | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | void ARMFrameLowering::emitEpilogue(MachineFunction &MF, | ||||
if (MF.getFunction().getCallingConv() == CallingConv::GHC) | if (MF.getFunction().getCallingConv() == CallingConv::GHC) | ||||
return; | return; | ||||
// First put ourselves on the first (from top) terminator instructions. | // First put ourselves on the first (from top) terminator instructions. | ||||
MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); | MachineBasicBlock::iterator MBBI = MBB.getFirstTerminator(); | ||||
DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); | DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc(); | ||||
if (!AFI->hasStackFrame()) { | if (!AFI->hasStackFrame()) { | ||||
if (NumBytes - ReservedArgStack != 0) | if (NumBytes + IncomingArgStackToRestore != 0) | ||||
emitSPUpdate(isARM, MBB, MBBI, dl, TII, NumBytes - ReservedArgStack, | emitSPUpdate(isARM, MBB, MBBI, dl, TII, | ||||
NumBytes + IncomingArgStackToRestore, | |||||
MachineInstr::FrameDestroy); | MachineInstr::FrameDestroy); | ||||
} else { | } else { | ||||
// Unwind MBBI to point to first LDR / VLDRD. | // Unwind MBBI to point to first LDR / VLDRD. | ||||
if (MBBI != MBB.begin()) { | if (MBBI != MBB.begin()) { | ||||
do { | do { | ||||
--MBBI; | --MBBI; | ||||
} while (MBBI != MBB.begin() && | } while (MBBI != MBB.begin() && | ||||
MBBI->getFlag(MachineInstr::FrameDestroy)); | MBBI->getFlag(MachineInstr::FrameDestroy)); | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | if (AFI->getDPRCalleeSavedGapSize()) { | ||||
assert(AFI->getDPRCalleeSavedGapSize() == 4 && | assert(AFI->getDPRCalleeSavedGapSize() == 4 && | ||||
"unexpected DPR alignment gap"); | "unexpected DPR alignment gap"); | ||||
emitSPUpdate(isARM, MBB, MBBI, dl, TII, AFI->getDPRCalleeSavedGapSize(), | emitSPUpdate(isARM, MBB, MBBI, dl, TII, AFI->getDPRCalleeSavedGapSize(), | ||||
MachineInstr::FrameDestroy); | MachineInstr::FrameDestroy); | ||||
} | } | ||||
if (AFI->getGPRCalleeSavedArea2Size()) MBBI++; | if (AFI->getGPRCalleeSavedArea2Size()) MBBI++; | ||||
if (AFI->getGPRCalleeSavedArea1Size()) MBBI++; | if (AFI->getGPRCalleeSavedArea1Size()) MBBI++; | ||||
if (AFI->getFPCXTSaveAreaSize()) MBBI++; | |||||
} | |||||
if (ReservedArgStack || IncomingArgStackToRestore) { | if (ReservedArgStack || IncomingArgStackToRestore) { | ||||
assert((int)ReservedArgStack + IncomingArgStackToRestore >= 0 && | assert((int)ReservedArgStack + IncomingArgStackToRestore >= 0 && | ||||
"attempting to restore negative stack amount"); | "attempting to restore negative stack amount"); | ||||
emitSPUpdate(isARM, MBB, MBBI, dl, TII, | emitSPUpdate(isARM, MBB, MBBI, dl, TII, | ||||
ReservedArgStack + IncomingArgStackToRestore, | ReservedArgStack + IncomingArgStackToRestore, | ||||
MachineInstr::FrameDestroy); | MachineInstr::FrameDestroy); | ||||
} | } | ||||
// Validate PAC, It should have been already popped into R12. For CMSE entry | |||||
// function, the validation instruction is emitted during expansion of the | |||||
// tBXNS_RET, since the validation must use the value of SP at function | |||||
// entry, before saving, resp. after restoring, FPCXTNS. | |||||
if (AFI->shouldSignReturnAddress() && !AFI->isCmseNSEntryFunction()) | |||||
BuildMI(MBB, MBBI, DebugLoc(), STI.getInstrInfo()->get(ARM::t2AUT)); | |||||
} | |||||
} | } | ||||
/// getFrameIndexReference - Provide a base+offset reference to an FI slot for | /// getFrameIndexReference - Provide a base+offset reference to an FI slot for | ||||
/// debug info. It's the same as what we use for resolving the code-gen | /// debug info. It's the same as what we use for resolving the code-gen | ||||
/// references for now. FIXME: This can go wrong when references are | /// references for now. FIXME: This can go wrong when references are | ||||
/// SP-relative and simple call frames aren't used. | /// SP-relative and simple call frames aren't used. | ||||
StackOffset ARMFrameLowering::getFrameIndexReference(const MachineFunction &MF, | StackOffset ARMFrameLowering::getFrameIndexReference(const MachineFunction &MF, | ||||
int FI, | int FI, | ||||
▲ Show 20 Lines • Show All 166 Lines • ▼ Show 20 Lines | void ARMFrameLowering::emitPopInst(MachineBasicBlock &MBB, | ||||
unsigned LdmOpc, unsigned LdrOpc, | unsigned LdmOpc, unsigned LdrOpc, | ||||
bool isVarArg, bool NoGap, | bool isVarArg, bool NoGap, | ||||
bool (*Func)(unsigned, bool), | bool (*Func)(unsigned, bool), | ||||
unsigned NumAlignedDPRCS2Regs) const { | unsigned NumAlignedDPRCS2Regs) const { | ||||
MachineFunction &MF = *MBB.getParent(); | MachineFunction &MF = *MBB.getParent(); | ||||
const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); | const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo(); | ||||
const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); | const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); | ||||
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | ||||
bool hasPAC = AFI->shouldSignReturnAddress(); | |||||
DebugLoc DL; | DebugLoc DL; | ||||
bool isTailCall = false; | bool isTailCall = false; | ||||
bool isInterrupt = false; | bool isInterrupt = false; | ||||
bool isTrap = false; | bool isTrap = false; | ||||
bool isCmseEntry = false; | bool isCmseEntry = false; | ||||
if (MBB.end() != MI) { | if (MBB.end() != MI) { | ||||
DL = MI->getDebugLoc(); | DL = MI->getDebugLoc(); | ||||
unsigned RetOpcode = MI->getOpcode(); | unsigned RetOpcode = MI->getOpcode(); | ||||
Show All 16 Lines | for (; i != 0; --i) { | ||||
unsigned Reg = Info.getReg(); | unsigned Reg = Info.getReg(); | ||||
if (!(Func)(Reg, STI.splitFramePushPop(MF))) continue; | if (!(Func)(Reg, STI.splitFramePushPop(MF))) continue; | ||||
// The aligned reloads from area DPRCS2 are not inserted here. | // The aligned reloads from area DPRCS2 are not inserted here. | ||||
if (Reg >= ARM::D8 && Reg < ARM::D8 + NumAlignedDPRCS2Regs) | if (Reg >= ARM::D8 && Reg < ARM::D8 + NumAlignedDPRCS2Regs) | ||||
continue; | continue; | ||||
if (Reg == ARM::LR && !isTailCall && !isVarArg && !isInterrupt && | if (Reg == ARM::LR && !isTailCall && !isVarArg && !isInterrupt && | ||||
!isCmseEntry && !isTrap && AFI->getArgumentStackToRestore() == 0 && | !isCmseEntry && !isTrap && AFI->getArgumentStackToRestore() == 0 && | ||||
STI.hasV5TOps() && MBB.succ_empty()) { | STI.hasV5TOps() && MBB.succ_empty() && !hasPAC) { | ||||
Reg = ARM::PC; | Reg = ARM::PC; | ||||
// Fold the return instruction into the LDM. | // Fold the return instruction into the LDM. | ||||
DeleteRet = true; | DeleteRet = true; | ||||
LdmOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_RET : ARM::LDMIA_RET; | LdmOpc = AFI->isThumbFunction() ? ARM::t2LDMIA_RET : ARM::LDMIA_RET; | ||||
// We 'restore' LR into PC so it is not live out of the return block: | // We 'restore' LR into PC so it is not live out of the return block: | ||||
// Clear Restored bit. | // Clear Restored bit. | ||||
Info.setRestored(false); | Info.setRestored(false); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 332 Lines • ▼ Show 20 Lines | bool ARMFrameLowering::spillCalleeSavedRegisters( | ||||
MachineFunction &MF = *MBB.getParent(); | MachineFunction &MF = *MBB.getParent(); | ||||
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>(); | ||||
unsigned PushOpc = AFI->isThumbFunction() ? ARM::t2STMDB_UPD : ARM::STMDB_UPD; | unsigned PushOpc = AFI->isThumbFunction() ? ARM::t2STMDB_UPD : ARM::STMDB_UPD; | ||||
unsigned PushOneOpc = AFI->isThumbFunction() ? | unsigned PushOneOpc = AFI->isThumbFunction() ? | ||||
ARM::t2STR_PRE : ARM::STR_PRE_IMM; | ARM::t2STR_PRE : ARM::STR_PRE_IMM; | ||||
unsigned FltOpc = ARM::VSTMDDB_UPD; | unsigned FltOpc = ARM::VSTMDDB_UPD; | ||||
unsigned NumAlignedDPRCS2Regs = AFI->getNumAlignedDPRCS2Regs(); | unsigned NumAlignedDPRCS2Regs = AFI->getNumAlignedDPRCS2Regs(); | ||||
// Compute PAC in R12. | |||||
if (AFI->shouldSignReturnAddress()) { | |||||
BuildMI(MBB, MI, DebugLoc(), STI.getInstrInfo()->get(ARM::t2PAC)) | |||||
.setMIFlags(MachineInstr::FrameSetup); | |||||
} | |||||
// Save the non-secure floating point context. | // Save the non-secure floating point context. | ||||
if (llvm::any_of(CSI, [](const CalleeSavedInfo &C) { | if (llvm::any_of(CSI, [](const CalleeSavedInfo &C) { | ||||
return C.getReg() == ARM::FPCXTNS; | return C.getReg() == ARM::FPCXTNS; | ||||
})) { | })) { | ||||
BuildMI(MBB, MI, DebugLoc(), STI.getInstrInfo()->get(ARM::VSTR_FPCXTNS_pre), | BuildMI(MBB, MI, DebugLoc(), STI.getInstrInfo()->get(ARM::VSTR_FPCXTNS_pre), | ||||
ARM::SP) | ARM::SP) | ||||
.addReg(ARM::SP) | .addReg(ARM::SP) | ||||
.addImm(-4) | .addImm(-4) | ||||
▲ Show 20 Lines • Show All 193 Lines • ▼ Show 20 Lines | |||||
bool ARMFrameLowering::enableShrinkWrapping(const MachineFunction &MF) const { | bool ARMFrameLowering::enableShrinkWrapping(const MachineFunction &MF) const { | ||||
// For CMSE entry functions, we want to save the FPCXT_NS immediately | // For CMSE entry functions, we want to save the FPCXT_NS immediately | ||||
// upon function entry (resp. restore it immmediately before return) | // upon function entry (resp. restore it immmediately before return) | ||||
if (STI.hasV8_1MMainlineOps() && | if (STI.hasV8_1MMainlineOps() && | ||||
MF.getInfo<ARMFunctionInfo>()->isCmseNSEntryFunction()) | MF.getInfo<ARMFunctionInfo>()->isCmseNSEntryFunction()) | ||||
return false; | return false; | ||||
// We are disabling shrinkwrapping for now when PAC is enabled, as | |||||
// shrinkwrapping can cause clobbering of r12 when the PAC code is | |||||
// generated. A follow-up patch will fix this in a more performant manner. | |||||
if (MF.getInfo<ARMFunctionInfo>()->shouldSignReturnAddress( | |||||
false /*SpillsLR */)) | |||||
return false; | |||||
return true; | return true; | ||||
} | } | ||||
void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF, | void ARMFrameLowering::determineCalleeSaves(MachineFunction &MF, | ||||
BitVector &SavedRegs, | BitVector &SavedRegs, | ||||
RegScavenger *RS) const { | RegScavenger *RS) const { | ||||
TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); | TargetFrameLowering::determineCalleeSaves(MF, SavedRegs, RS); | ||||
// This tells PEI to spill the FP as if it is any other callee-save register | // This tells PEI to spill the FP as if it is any other callee-save register | ||||
▲ Show 20 Lines • Show All 510 Lines • ▼ Show 20 Lines | bool ARMFrameLowering::assignCalleeSavedSpillSlots( | ||||
// For CMSE entry functions, handle floating-point context as if it was a | // For CMSE entry functions, handle floating-point context as if it was a | ||||
// callee-saved register. | // callee-saved register. | ||||
if (STI.hasV8_1MMainlineOps() && | if (STI.hasV8_1MMainlineOps() && | ||||
MF.getInfo<ARMFunctionInfo>()->isCmseNSEntryFunction()) { | MF.getInfo<ARMFunctionInfo>()->isCmseNSEntryFunction()) { | ||||
CSI.emplace_back(ARM::FPCXTNS); | CSI.emplace_back(ARM::FPCXTNS); | ||||
CSI.back().setRestored(false); | CSI.back().setRestored(false); | ||||
} | } | ||||
// For functions, which sign their return address, upon function entry, the | |||||
// return address PAC is computed in R12. Treat R12 as a callee-saved register | |||||
// in this case. | |||||
const auto &AFI = *MF.getInfo<ARMFunctionInfo>(); | |||||
if (AFI.shouldSignReturnAddress()) { | |||||
// The order of register must match the order we push them, because the | |||||
// PEI assigns frame indices in that order. When compiling for return | |||||
// address sign and authenication, we use split push, therefore the orders | |||||
// we want are: | |||||
// LR, R7, R6, R5, R4, <R12>, R11, R10, R9, R8, D15-D8 | |||||
CSI.insert(find_if(CSI, | |||||
[=](const auto &CS) { | |||||
unsigned Reg = CS.getReg(); | |||||
return Reg == ARM::R10 || Reg == ARM::R11 || | |||||
Reg == ARM::R8 || Reg == ARM::R9 || | |||||
ARM::DPRRegClass.contains(Reg); | |||||
}), | |||||
CalleeSavedInfo(ARM::R12)); | |||||
} | |||||
return false; | return false; | ||||
} | } | ||||
const TargetFrameLowering::SpillSlot * | const TargetFrameLowering::SpillSlot * | ||||
ARMFrameLowering::getCalleeSavedSpillSlots(unsigned &NumEntries) const { | ARMFrameLowering::getCalleeSavedSpillSlots(unsigned &NumEntries) const { | ||||
static const SpillSlot FixedSpillOffsets[] = {{ARM::FPCXTNS, -4}}; | static const SpillSlot FixedSpillOffsets[] = {{ARM::FPCXTNS, -4}}; | ||||
NumEntries = array_lengthof(FixedSpillOffsets); | NumEntries = array_lengthof(FixedSpillOffsets); | ||||
return FixedSpillOffsets; | return FixedSpillOffsets; | ||||
▲ Show 20 Lines • Show All 494 Lines • Show Last 20 Lines |