Changeset View
Changeset View
Standalone View
Standalone View
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
Show First 20 Lines • Show All 375 Lines • ▼ Show 20 Lines | if (RealStackSize == 0 && !MFI.adjustsStack()) | ||||
return; | return; | ||||
// If the stack pointer has been marked as reserved, then produce an error if | // If the stack pointer has been marked as reserved, then produce an error if | ||||
// the frame requires stack allocation | // the frame requires stack allocation | ||||
if (STI.isRegisterReservedByUser(SPReg)) | if (STI.isRegisterReservedByUser(SPReg)) | ||||
MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ | MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ | ||||
MF.getFunction(), "Stack pointer required, but has been reserved."}); | MF.getFunction(), "Stack pointer required, but has been reserved."}); | ||||
uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); | // This will tell us whether we're adjusting the stack twice or just once. | ||||
Optional<uint64_t> FirstSPAdjustmentAmount = getFirstSPAdjustmentAmount(MF); | |||||
// Split the SP adjustment to reduce the offsets of callee saved spill. | // Split the SP adjustment to reduce the offsets of callee saved spill. | ||||
if (FirstSPAdjustAmount) { | if (FirstSPAdjustmentAmount) { | ||||
StackSize = FirstSPAdjustAmount; | StackSize = FirstSPAdjustmentAmount.getValue(); | ||||
RealStackSize = FirstSPAdjustAmount; | RealStackSize = FirstSPAdjustmentAmount.getValue(); | ||||
} | } | ||||
// Allocate space on the stack if necessary. | // Allocate space on the stack if necessary. | ||||
adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup); | adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup); | ||||
// Emit ".cfi_def_cfa_offset RealStackSize" | // Emit ".cfi_def_cfa_offset RealStackSize" | ||||
unsigned CFIIndex = MF.addFrameInst( | unsigned CFIIndex = MF.addFrameInst( | ||||
MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize)); | MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize)); | ||||
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) | BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) | ||||
.addCFIIndex(CFIIndex); | .addCFIIndex(CFIIndex); | ||||
const auto &CSI = MFI.getCalleeSavedInfo(); | const auto &CSI = MFI.getCalleeSavedInfo(); | ||||
// The frame pointer is callee-saved, and code has been generated for us to | // The frame pointer is callee-saved, and code has been generated for us to | ||||
// save it to the stack. We need to skip over the storing of callee-saved | // save it to the stack. We need to skip over the storing of callee-saved | ||||
// registers as the frame pointer must be modified after it has been saved | // registers as the frame pointer must be modified after it has been saved | ||||
// to the stack, not before. | // to the stack, not before. | ||||
// FIXME: assumes exactly one instruction is used to save each callee-saved | // FIXME: assumes exactly one instruction is used to save each callee-saved | ||||
// register. | // register. | ||||
std::advance(MBBI, getNonLibcallCSI(CSI).size()); | std::advance(MBBI, getNonLibcallCSI(CSI).size()); | ||||
// Iterate over list of callee-saved registers and emit .cfi_offset | // Iterate over list of callee-saved registers and emit .cfi_offset | ||||
// directives. | // directives. | ||||
for (const auto &Entry : CSI) { | for (const auto &Entry : CSI) { | ||||
Register Reg = Entry.getReg(); | |||||
int FrameIdx = Entry.getFrameIdx(); | int FrameIdx = Entry.getFrameIdx(); | ||||
// Offsets are calculated relative to the CFA, so do not need to change if | |||||
// the stack pointer is adjusted twice. | |||||
int64_t Offset; | int64_t Offset; | ||||
// Offsets for objects with fixed locations (IE: those saved by libcall) are | |||||
// simply calculated from the frame index. | |||||
if (FrameIdx < 0) | if (FrameIdx < 0) | ||||
// Offsets for objects with fixed locations (IE: those saved by libcall) | |||||
// are simply calculated from the frame index. | |||||
Offset = FrameIdx * (int64_t) STI.getXLen() / 8; | Offset = FrameIdx * (int64_t) STI.getXLen() / 8; | ||||
else | else | ||||
Offset = MFI.getObjectOffset(Entry.getFrameIdx()) - | Offset = MFI.getObjectOffset(FrameIdx) - RVFI->getLibCallStackSize(); | ||||
RVFI->getLibCallStackSize(); | |||||
Register Reg = Entry.getReg(); | |||||
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( | unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset( | ||||
nullptr, RI->getDwarfRegNum(Reg, true), Offset)); | nullptr, RI->getDwarfRegNum(Reg, true), Offset)); | ||||
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) | BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) | ||||
.addCFIIndex(CFIIndex); | .addCFIIndex(CFIIndex); | ||||
} | } | ||||
// Generate new FP. | // Generate new FP. | ||||
if (hasFP(MF)) { | bool UsesFramePointer = hasFP(MF); | ||||
if (UsesFramePointer) { | |||||
if (STI.isRegisterReservedByUser(FPReg)) | if (STI.isRegisterReservedByUser(FPReg)) | ||||
MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ | MF.getFunction().getContext().diagnose(DiagnosticInfoUnsupported{ | ||||
MF.getFunction(), "Frame pointer required, but has been reserved."}); | MF.getFunction(), "Frame pointer required, but has been reserved."}); | ||||
adjustReg(MBB, MBBI, DL, FPReg, SPReg, | adjustReg(MBB, MBBI, DL, FPReg, SPReg, | ||||
RealStackSize - RVFI->getVarArgsSaveSize(), | RealStackSize - RVFI->getVarArgsSaveSize(), | ||||
MachineInstr::FrameSetup); | MachineInstr::FrameSetup); | ||||
// Emit ".cfi_def_cfa $fp, RVFI->getVarArgsSaveSize()" | // Emit ".cfi_def_cfa $fp, RVFI->getVarArgsSaveSize()" | ||||
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa( | unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa( | ||||
nullptr, RI->getDwarfRegNum(FPReg, true), RVFI->getVarArgsSaveSize())); | nullptr, RI->getDwarfRegNum(FPReg, true), RVFI->getVarArgsSaveSize())); | ||||
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) | BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) | ||||
.addCFIIndex(CFIIndex); | .addCFIIndex(CFIIndex); | ||||
} | } | ||||
// Emit the second SP adjustment after saving callee saved registers. | // Emit the second SP adjustment after saving callee saved registers. | ||||
if (FirstSPAdjustAmount) { | if (FirstSPAdjustmentAmount) { | ||||
uint64_t SecondSPAdjustAmount = MFI.getStackSize() - FirstSPAdjustAmount; | int64_t SecondSPAdjustAmount = | ||||
MFI.getStackSize() - FirstSPAdjustmentAmount.getValue(); | |||||
assert(SecondSPAdjustAmount > 0 && | assert(SecondSPAdjustAmount > 0 && | ||||
"SecondSPAdjustAmount should be greater than zero"); | "SecondSPAdjustAmount should be greater than zero"); | ||||
adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount, | adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount, | ||||
MachineInstr::FrameSetup); | MachineInstr::FrameSetup); | ||||
// If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0", | // If we are using a frame pointer (and thus emitted ".cfi_def_cfa fp, N", | ||||
// don't emit an sp-based .cfi_def_cfa_offset | // above), we don't need to update the cfa offset after doing the second | ||||
if (!hasFP(MF)) { | // stack pointer adjustment. | ||||
// | |||||
// This does not need to care about `getLibCallStackSize` because we know | |||||
// it will be zero if we're splitting the stack. | |||||
if (!UsesFramePointer) { | |||||
// Emit ".cfi_def_cfa_offset StackSize" | // Emit ".cfi_def_cfa_offset StackSize" | ||||
unsigned CFIIndex = MF.addFrameInst( | unsigned CFIIndex = MF.addFrameInst( | ||||
MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize())); | MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize())); | ||||
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) | BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) | ||||
.addCFIIndex(CFIIndex); | .addCFIIndex(CFIIndex); | ||||
} | } | ||||
} | } | ||||
if (hasFP(MF)) { | if (UsesFramePointer) { | ||||
// Realign Stack | // Realign Stack | ||||
const RISCVRegisterInfo *RI = STI.getRegisterInfo(); | const RISCVRegisterInfo *RI = STI.getRegisterInfo(); | ||||
if (RI->needsStackRealignment(MF)) { | if (RI->needsStackRealignment(MF)) { | ||||
Align MaxAlignment = MFI.getMaxAlign(); | Align MaxAlignment = MFI.getMaxAlign(); | ||||
const RISCVInstrInfo *TII = STI.getInstrInfo(); | const RISCVInstrInfo *TII = STI.getInstrInfo(); | ||||
if (isInt<12>(-(int)MaxAlignment.value())) { | if (isInt<12>(-(int)MaxAlignment.value())) { | ||||
BuildMI(MBB, MBBI, DL, TII->get(RISCV::ANDI), SPReg) | BuildMI(MBB, MBBI, DL, TII->get(RISCV::ANDI), SPReg) | ||||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Lines | void RISCVFrameLowering::emitEpilogue(MachineFunction &MF, | ||||
// necessary if the stack pointer was modified, meaning the stack size is | // necessary if the stack pointer was modified, meaning the stack size is | ||||
// unknown. | // unknown. | ||||
if (RI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) { | if (RI->needsStackRealignment(MF) || MFI.hasVarSizedObjects()) { | ||||
assert(hasFP(MF) && "frame pointer should not have been eliminated"); | assert(hasFP(MF) && "frame pointer should not have been eliminated"); | ||||
adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, -FPOffset, | adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg, -FPOffset, | ||||
MachineInstr::FrameDestroy); | MachineInstr::FrameDestroy); | ||||
} | } | ||||
uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); | Optional<uint64_t> FirstSPAdjustmentAmount = getFirstSPAdjustmentAmount(MF); | ||||
if (FirstSPAdjustAmount) { | if (FirstSPAdjustmentAmount) { | ||||
uint64_t SecondSPAdjustAmount = MFI.getStackSize() - FirstSPAdjustAmount; | int64_t SecondSPAdjustAmount = | ||||
StackSize - FirstSPAdjustmentAmount.getValue(); | |||||
assert(SecondSPAdjustAmount > 0 && | assert(SecondSPAdjustAmount > 0 && | ||||
"SecondSPAdjustAmount should be greater than zero"); | "SecondSPAdjustAmount should be greater than zero"); | ||||
adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount, | adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, SecondSPAdjustAmount, | ||||
MachineInstr::FrameDestroy); | MachineInstr::FrameDestroy); | ||||
} | } | ||||
if (FirstSPAdjustAmount) | if (FirstSPAdjustmentAmount) | ||||
StackSize = FirstSPAdjustAmount; | StackSize = FirstSPAdjustmentAmount.getValue(); | ||||
// Deallocate stack | // Deallocate stack | ||||
adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); | adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackSize, MachineInstr::FrameDestroy); | ||||
// Emit epilogue for shadow call stack. | // Emit epilogue for shadow call stack. | ||||
emitSCSEpilogue(MF, MBB, MBBI, DL); | emitSCSEpilogue(MF, MBB, MBBI, DL); | ||||
} | } | ||||
Show All 9 Lines | RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF, int FI, | ||||
// offset). | // offset). | ||||
const auto &CSI = getNonLibcallCSI(MFI.getCalleeSavedInfo()); | const auto &CSI = getNonLibcallCSI(MFI.getCalleeSavedInfo()); | ||||
int MinCSFI = 0; | int MinCSFI = 0; | ||||
int MaxCSFI = -1; | int MaxCSFI = -1; | ||||
int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea() + | int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea() + | ||||
MFI.getOffsetAdjustment(); | MFI.getOffsetAdjustment(); | ||||
uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF); | Optional<uint64_t> FirstSPAdjustmentAmount = getFirstSPAdjustmentAmount(MF); | ||||
if (CSI.size()) { | if (CSI.size()) { | ||||
MinCSFI = CSI[0].getFrameIdx(); | MinCSFI = CSI[0].getFrameIdx(); | ||||
MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); | MaxCSFI = CSI[CSI.size() - 1].getFrameIdx(); | ||||
} | } | ||||
if (FI >= MinCSFI && FI <= MaxCSFI) { | if (FI >= MinCSFI && FI <= MaxCSFI) { | ||||
FrameReg = RISCV::X2; | FrameReg = RISCV::X2; | ||||
if (FirstSPAdjustAmount) | if (FirstSPAdjustmentAmount) | ||||
Offset += FirstSPAdjustAmount; | Offset += FirstSPAdjustmentAmount.getValue(); | ||||
else | else | ||||
Offset += MFI.getStackSize(); | Offset += MFI.getStackSize(); | ||||
} else if (RI->needsStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) { | } else if (RI->needsStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) { | ||||
// If the stack was realigned, the frame pointer is set in order to allow | // If the stack was realigned, the frame pointer is set in order to allow | ||||
// SP to be restored, so we need another base register to record the stack | // SP to be restored, so we need another base register to record the stack | ||||
// after realignment. | // after realignment. | ||||
if (hasBP(MF)) | if (hasBP(MF)) | ||||
FrameReg = RISCVABI::getBPReg(); | FrameReg = RISCVABI::getBPReg(); | ||||
▲ Show 20 Lines • Show All 111 Lines • ▼ Show 20 Lines | if (Amount != 0) { | ||||
adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags); | adjustReg(MBB, MI, DL, SPReg, SPReg, Amount, MachineInstr::NoFlags); | ||||
} | } | ||||
} | } | ||||
return MBB.erase(MI); | return MBB.erase(MI); | ||||
} | } | ||||
// We would like to split the SP adjustment to reduce prologue/epilogue | // Splitting the stack pointer (sp) adjustment may reduce the number or size of | ||||
// as following instructions. In this way, the offset of the callee saved | // instructions in the prologue and epilogue, as shown in the following | ||||
asb: I'm struggling to parse the "reduce prologue/epilogue" bit of this sentence | |||||
// register could fit in a single store. | // instructions. | ||||
// | |||||
// The reason to do this is twofold: so that the offset for the callee-saved | |||||
Did you mean to say "function" here? asb: Did you mean to say "function" here? | |||||
// register saves/restores fits into a single (potentially compressed) | |||||
// instruction; and to ensure the SP adjustment amounts fit into one or two | |||||
// `addi` instructions rather than needing to materialise those immediates with | |||||
// extra instructions. | |||||
// | |||||
// add sp,sp,-2032 | // add sp,sp,-2032 | ||||
// sw ra,2028(sp) | // sw ra,2028(sp) | ||||
// sw s0,2024(sp) | // sw s0,2024(sp) | ||||
// sw s1,2020(sp) | // sw s1,2020(sp) | ||||
// sw s3,2012(sp) | // sw s3,2012(sp) | ||||
// sw s4,2008(sp) | // sw s4,2008(sp) | ||||
// add sp,sp,-64 | // add sp,sp,-64 | ||||
uint64_t | // | ||||
RISCVFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF) const { | // If this function returns `None`, then the sp adjustment should be done in a | ||||
// single step. | |||||
// | |||||
// If this function returns an Optional containing a value, then the value is | |||||
// the first adjustment for the stack pointer (and the second can be calculated | |||||
// by taking the difference between this and the function's StackSize). | |||||
// | |||||
// The returned value should always be between 0 and the function's StackSize - | |||||
// the intention being that both sp adjustments are monotonic. | |||||
Optional<uint64_t> RISCVFrameLowering::getFirstSPAdjustmentAmount( | |||||
const MachineFunction &MF) const { | |||||
Should be a C++ style comment asb: Should be a C++ style comment | |||||
const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); | const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>(); | ||||
const MachineFrameInfo &MFI = MF.getFrameInfo(); | const MachineFrameInfo &MFI = MF.getFrameInfo(); | ||||
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); | const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo(); | ||||
uint64_t StackSize = MFI.getStackSize(); | uint64_t StackSize = MFI.getStackSize(); | ||||
// Disable SplitSPAdjust if save-restore libcall used. The callee saved | // Disable SplitSPAdjust if save-restore libcall used. The callee saved | ||||
// registers will be pushed by the save-restore libcalls, so we don't have to | // registers will be pushed by the save-restore libcalls, so we don't have to | ||||
// split the SP adjustment in this case. | // split the SP adjustment in this case. | ||||
if (RVFI->getLibCallStackSize()) | if (RVFI->getLibCallStackSize() > 0) | ||||
return 0; | return None; | ||||
// Return the FirstSPAdjustAmount if the StackSize can not fit in signed | // Splitting the stack pointer adjustment is most useful for when there are | ||||
// 12-bit and there exists a callee saved register need to be pushed. | // callee-saved registers, allowing them to be saved and restored with minimal | ||||
if (!isInt<12>(StackSize) && (CSI.size() > 0)) { | // instructions. If we don't have any CSRs, then we don't need to split the | ||||
Could be early exit something like: if (CSI.size() == 0) return DoNotSplitSPAdjustment; shiva0217: Could be early exit something like: if (CSI.size() == 0) return DoNotSplitSPAdjustment; | |||||
// FirstSPAdjustAmount is choosed as (2048 - StackAlign) | // stack pointer adjustment. | ||||
// because 2048 will cause sp = sp + 2048 in epilogue split into | if (CSI.size() == 0) | ||||
// multi-instructions. The offset smaller than 2048 can fit in signle | return None; | ||||
// load/store instruction and we have to stick with the stack alignment. | |||||
// 2048 is 16-byte alignment. The stack alignment for RV32 and RV64 is 16, | const RISCVSubtarget &STI = MF.getSubtarget<RISCVSubtarget>(); | ||||
// for RV32E is 4. So (2048 - StackAlign) will satisfy the stack alignment. | bool OptSize = MF.getFunction().hasOptSize(); | ||||
Not Done ReplyInline ActionsCould we extract a static function as getOffsetAddressableLimit(MF, StackAlign)? shiva0217: Could we extract a static function as getOffsetAddressableLimit(MF, StackAlign)? | |||||
return 2048 - getStackAlign().value(); | size_t Saves = CSI.size(); | ||||
// We want to split if the stack size is over a certain threshold. This | |||||
// threshold is set by which instructions are available, as we'd prefer to | |||||
// use the smallest instructions available. When we have compressed | |||||
// instructions we want to balance the benefit of the code size improvement | |||||
Should be 8-bit limit for c.{l,s}wsp with isShiftedUInt<6, 2>(Imm)? shiva0217: Should be 8-bit limit for c.{l,s}wsp with isShiftedUInt<6, 2>(Imm)? | |||||
// against the cost of the additional stack adjustment instruction. | |||||
uint32_t OffsetAddressableLimit; | |||||
if (STI.hasStdExtC() && ((OptSize && Saves > 1) || (!OptSize && Saves > 4))) { | |||||
Should be 9-bit limit for c.{l,s}dsp with isShiftedUInt<6, 3>(Imm)? shiva0217: Should be 9-bit limit for c.{l,s}dsp with isShiftedUInt<6, 3>(Imm)? | |||||
// On RV*C, we want to use c.l{w,d}sp and c.s{w,d}sp for saving and | |||||
// restoring callee-saved registers. | |||||
// | |||||
// On RV32C, the offset in these (the w variants, as the registers are | |||||
// word-sized) have a 8-bit limit. | |||||
// | |||||
// On RV64C, the offset in these (the d variants, as the registers are | |||||
// double-sized) have an 9-bit limit, so we could use 512, but we also | |||||
// want to use c.addi16sp to adjust the stack pointer in the prolog and | |||||
// the epilog, which has a limit of (-512,496), so we use 496. | |||||
OffsetAddressableLimit = STI.is64Bit() ? 496 : 256; | |||||
} else { | |||||
// If we don't have compressed instructions, we want to use the offset in | |||||
// l{d,w} or s{d,w}, which has a 12-bit limit, so 2048. | |||||
// | |||||
// However, we also want to ensure that we can do both "first" stack | |||||
// adjustments in one single instruction, preferrably `addi`. In the | |||||
// prolog, this will be `addi sp, sp, -<limit>` which will fit a limit of | |||||
// 2048, but undoing this in the epilog (`addi sp, sp, 2048`) does not fit | |||||
// into a single instruction. | |||||
// | |||||
// So, in the end we need to choose a value less than 2048, to fit into | |||||
// the limit. We would most prefer the offsets remained as aligned as the | |||||
// stack is, so we choose 2048 - StackAlign. | |||||
OffsetAddressableLimit = 2048 - getStackAlign().value(); | |||||
} | } | ||||
return 0; | |||||
// There's only point in splitting if the stack size is over the threshold | |||||
// we found. | |||||
if (StackSize > OffsetAddressableLimit) | |||||
return OffsetAddressableLimit; | |||||
// Otherwise we'll have no problem addressing these offsets without splitting | |||||
// the stack pointer adjustment. | |||||
return None; | |||||
} | } | ||||
bool RISCVFrameLowering::spillCalleeSavedRegisters( | bool RISCVFrameLowering::spillCalleeSavedRegisters( | ||||
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, | MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, | ||||
ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { | ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const { | ||||
if (CSI.empty()) | if (CSI.empty()) | ||||
return true; | return true; | ||||
▲ Show 20 Lines • Show All 116 Lines • Show Last 20 Lines |
I'm struggling to parse the "reduce prologue/epilogue" bit of this sentence