summaryrefslogtreecommitdiff
path: root/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/RISCV/RISCVFrameLowering.cpp')
-rw-r--r--llvm/lib/Target/RISCV/RISCVFrameLowering.cpp364
1 files changed, 327 insertions, 37 deletions
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index c60fc3fc6b42b..43adc7426c79d 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -23,6 +23,100 @@
using namespace llvm;
+// Get the ID of the libcall used for spilling and restoring callee saved
+// registers. The ID is representative of the number of registers saved or
+// restored by the libcall, except it is zero-indexed - ID 0 corresponds to a
+// single register.
+static int getLibCallID(const MachineFunction &MF,
+ const std::vector<CalleeSavedInfo> &CSI) {
+ const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
+
+ if (CSI.empty() || !RVFI->useSaveRestoreLibCalls(MF))
+ return -1;
+
+ Register MaxReg = RISCV::NoRegister;
+ for (auto &CS : CSI)
+ // RISCVRegisterInfo::hasReservedSpillSlot assigns negative frame indexes to
+ // registers which can be saved by libcall.
+ if (CS.getFrameIdx() < 0)
+ MaxReg = std::max(MaxReg.id(), CS.getReg());
+
+ if (MaxReg == RISCV::NoRegister)
+ return -1;
+
+ switch (MaxReg) {
+ default:
+ llvm_unreachable("Something has gone wrong!");
+ case /*s11*/ RISCV::X27: return 12;
+ case /*s10*/ RISCV::X26: return 11;
+ case /*s9*/ RISCV::X25: return 10;
+ case /*s8*/ RISCV::X24: return 9;
+ case /*s7*/ RISCV::X23: return 8;
+ case /*s6*/ RISCV::X22: return 7;
+ case /*s5*/ RISCV::X21: return 6;
+ case /*s4*/ RISCV::X20: return 5;
+ case /*s3*/ RISCV::X19: return 4;
+ case /*s2*/ RISCV::X18: return 3;
+ case /*s1*/ RISCV::X9: return 2;
+ case /*s0*/ RISCV::X8: return 1;
+ case /*ra*/ RISCV::X1: return 0;
+ }
+}
+
+// Get the name of the libcall used for spilling callee saved registers.
+// If this function will not use save/restore libcalls, then return a nullptr.
+static const char *
+getSpillLibCallName(const MachineFunction &MF,
+ const std::vector<CalleeSavedInfo> &CSI) {
+ static const char *const SpillLibCalls[] = {
+ "__riscv_save_0",
+ "__riscv_save_1",
+ "__riscv_save_2",
+ "__riscv_save_3",
+ "__riscv_save_4",
+ "__riscv_save_5",
+ "__riscv_save_6",
+ "__riscv_save_7",
+ "__riscv_save_8",
+ "__riscv_save_9",
+ "__riscv_save_10",
+ "__riscv_save_11",
+ "__riscv_save_12"
+ };
+
+ int LibCallID = getLibCallID(MF, CSI);
+ if (LibCallID == -1)
+ return nullptr;
+ return SpillLibCalls[LibCallID];
+}
+
+// Get the name of the libcall used for restoring callee saved registers.
+// If this function will not use save/restore libcalls, then return a nullptr.
+static const char *
+getRestoreLibCallName(const MachineFunction &MF,
+ const std::vector<CalleeSavedInfo> &CSI) {
+ static const char *const RestoreLibCalls[] = {
+ "__riscv_restore_0",
+ "__riscv_restore_1",
+ "__riscv_restore_2",
+ "__riscv_restore_3",
+ "__riscv_restore_4",
+ "__riscv_restore_5",
+ "__riscv_restore_6",
+ "__riscv_restore_7",
+ "__riscv_restore_8",
+ "__riscv_restore_9",
+ "__riscv_restore_10",
+ "__riscv_restore_11",
+ "__riscv_restore_12"
+ };
+
+ int LibCallID = getLibCallID(MF, CSI);
+ if (LibCallID == -1)
+ return nullptr;
+ return RestoreLibCalls[LibCallID];
+}
+
bool RISCVFrameLowering::hasFP(const MachineFunction &MF) const {
const TargetRegisterInfo *RegInfo = MF.getSubtarget().getRegisterInfo();
@@ -48,10 +142,10 @@ void RISCVFrameLowering::determineFrameLayout(MachineFunction &MF) const {
uint64_t FrameSize = MFI.getStackSize();
// Get the alignment.
- unsigned StackAlign = getStackAlignment();
+ Align StackAlign = getStackAlign();
if (RI->needsStackRealignment(MF)) {
- unsigned MaxStackAlign = std::max(StackAlign, MFI.getMaxAlignment());
- FrameSize += (MaxStackAlign - StackAlign);
+ Align MaxStackAlign = std::max(StackAlign, MFI.getMaxAlign());
+ FrameSize += (MaxStackAlign.value() - StackAlign.value());
StackAlign = MaxStackAlign;
}
@@ -105,6 +199,17 @@ static Register getFPReg(const RISCVSubtarget &STI) { return RISCV::X8; }
// Returns the register used to hold the stack pointer.
static Register getSPReg(const RISCVSubtarget &STI) { return RISCV::X2; }
+static SmallVector<CalleeSavedInfo, 8>
+getNonLibcallCSI(const std::vector<CalleeSavedInfo> &CSI) {
+ SmallVector<CalleeSavedInfo, 8> NonLibcallCSI;
+
+ for (auto &CS : CSI)
+ if (CS.getFrameIdx() >= 0)
+ NonLibcallCSI.push_back(CS);
+
+ return NonLibcallCSI;
+}
+
void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineFrameInfo &MFI = MF.getFrameInfo();
@@ -117,6 +222,11 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
Register SPReg = getSPReg(STI);
Register BPReg = RISCVABI::getBPReg();
+ // Since spillCalleeSavedRegisters may have inserted a libcall, skip past
+ // any instructions marked as FrameSetup
+ while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup))
+ ++MBBI;
+
// Debug location must be unknown since the first debug location is used
// to determine the end of the prologue.
DebugLoc DL;
@@ -124,12 +234,38 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
// Determine the correct frame layout
determineFrameLayout(MF);
+ // If libcalls are used to spill and restore callee-saved registers, the frame
+ // has two sections; the opaque section managed by the libcalls, and the
+ // section managed by MachineFrameInfo which can also hold callee saved
+ // registers in fixed stack slots, both of which have negative frame indices.
+ // This gets even more complicated when incoming arguments are passed via the
+ // stack, as these too have negative frame indices. An example is detailed
+ // below:
+ //
+ // | incoming arg | <- FI[-3]
+ // | libcallspill |
+ // | calleespill | <- FI[-2]
+ // | calleespill | <- FI[-1]
+ // | this_frame | <- FI[0]
+ //
+ // For negative frame indices, the offset from the frame pointer will differ
+ // depending on which of these groups the frame index applies to.
+ // The following calculates the correct offset knowing the number of callee
+ // saved registers spilt by the two methods.
+ if (int LibCallRegs = getLibCallID(MF, MFI.getCalleeSavedInfo()) + 1) {
+ // Calculate the size of the frame managed by the libcall. The libcalls are
+ // implemented such that the stack will always be 16 byte aligned.
+ unsigned LibCallFrameSize = alignTo((STI.getXLen() / 8) * LibCallRegs, 16);
+ RVFI->setLibCallStackSize(LibCallFrameSize);
+ }
+
// FIXME (note copied from Lanai): This appears to be overallocating. Needs
// investigation. Get the number of bytes to allocate from the FrameInfo.
uint64_t StackSize = MFI.getStackSize();
+ uint64_t RealStackSize = StackSize + RVFI->getLibCallStackSize();
// Early exit if there is no need to allocate on the stack
- if (StackSize == 0 && !MFI.adjustsStack())
+ if (RealStackSize == 0 && !MFI.adjustsStack())
return;
// If the stack pointer has been marked as reserved, then produce an error if
@@ -140,31 +276,42 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
// Split the SP adjustment to reduce the offsets of callee saved spill.
- if (FirstSPAdjustAmount)
+ if (FirstSPAdjustAmount) {
StackSize = FirstSPAdjustAmount;
+ RealStackSize = FirstSPAdjustAmount;
+ }
// Allocate space on the stack if necessary.
adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);
- // Emit ".cfi_def_cfa_offset StackSize"
+ // Emit ".cfi_def_cfa_offset RealStackSize"
unsigned CFIIndex = MF.addFrameInst(
- MCCFIInstruction::createDefCfaOffset(nullptr, -StackSize));
+ MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
+ const auto &CSI = MFI.getCalleeSavedInfo();
+
// 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
// registers as the frame pointer must be modified after it has been saved
// to the stack, not before.
// FIXME: assumes exactly one instruction is used to save each callee-saved
// register.
- const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
- std::advance(MBBI, CSI.size());
+ std::advance(MBBI, getNonLibcallCSI(CSI).size());
// Iterate over list of callee-saved registers and emit .cfi_offset
// directives.
for (const auto &Entry : CSI) {
- int64_t Offset = MFI.getObjectOffset(Entry.getFrameIdx());
+ int FrameIdx = Entry.getFrameIdx();
+ int64_t Offset;
+ // Offsets for objects with fixed locations (IE: those saved by libcall) are
+ // simply calculated from the frame index.
+ if (FrameIdx < 0)
+ Offset = FrameIdx * (int64_t) STI.getXLen() / 8;
+ else
+ Offset = MFI.getObjectOffset(Entry.getFrameIdx()) -
+ RVFI->getLibCallStackSize();
Register Reg = Entry.getReg();
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, RI->getDwarfRegNum(Reg, true), Offset));
@@ -179,11 +326,12 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
MF.getFunction(), "Frame pointer required, but has been reserved."});
adjustReg(MBB, MBBI, DL, FPReg, SPReg,
- StackSize - RVFI->getVarArgsSaveSize(), MachineInstr::FrameSetup);
+ RealStackSize - RVFI->getVarArgsSaveSize(),
+ MachineInstr::FrameSetup);
- // Emit ".cfi_def_cfa $fp, 0"
- unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa(
- nullptr, RI->getDwarfRegNum(FPReg, true), 0));
+ // Emit ".cfi_def_cfa $fp, RVFI->getVarArgsSaveSize()"
+ unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(
+ nullptr, RI->getDwarfRegNum(FPReg, true), RVFI->getVarArgsSaveSize()));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
@@ -201,7 +349,7 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
if (!hasFP(MF)) {
// Emit ".cfi_def_cfa_offset StackSize"
unsigned CFIIndex = MF.addFrameInst(
- MCCFIInstruction::createDefCfaOffset(nullptr, -MFI.getStackSize()));
+ MCCFIInstruction::cfiDefCfaOffset(nullptr, MFI.getStackSize()));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
}
@@ -211,15 +359,15 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
// Realign Stack
const RISCVRegisterInfo *RI = STI.getRegisterInfo();
if (RI->needsStackRealignment(MF)) {
- unsigned MaxAlignment = MFI.getMaxAlignment();
+ Align MaxAlignment = MFI.getMaxAlign();
const RISCVInstrInfo *TII = STI.getInstrInfo();
- if (isInt<12>(-(int)MaxAlignment)) {
+ if (isInt<12>(-(int)MaxAlignment.value())) {
BuildMI(MBB, MBBI, DL, TII->get(RISCV::ANDI), SPReg)
.addReg(SPReg)
- .addImm(-(int)MaxAlignment);
+ .addImm(-(int)MaxAlignment.value());
} else {
- unsigned ShiftAmount = countTrailingZeros(MaxAlignment);
+ unsigned ShiftAmount = Log2(MaxAlignment);
Register VR =
MF.getRegInfo().createVirtualRegister(&RISCV::GPRRegClass);
BuildMI(MBB, MBBI, DL, TII->get(RISCV::SRLI), VR)
@@ -264,15 +412,26 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
// last instruction.
if (!MBBI->isTerminator())
MBBI = std::next(MBBI);
+
+ // If callee-saved registers are saved via libcall, place stack adjustment
+ // before this call.
+ while (MBBI != MBB.begin() &&
+ std::prev(MBBI)->getFlag(MachineInstr::FrameDestroy))
+ --MBBI;
}
+ const auto &CSI = getNonLibcallCSI(MFI.getCalleeSavedInfo());
+
// Skip to before the restores of callee-saved registers
// FIXME: assumes exactly one instruction is used to restore each
// callee-saved register.
- auto LastFrameDestroy = std::prev(MBBI, MFI.getCalleeSavedInfo().size());
+ auto LastFrameDestroy = MBBI;
+ if (!CSI.empty())
+ LastFrameDestroy = std::prev(MBBI, CSI.size());
uint64_t StackSize = MFI.getStackSize();
- uint64_t FPOffset = StackSize - RVFI->getVarArgsSaveSize();
+ uint64_t RealStackSize = StackSize + RVFI->getLibCallStackSize();
+ uint64_t FPOffset = RealStackSize - RVFI->getVarArgsSaveSize();
// Restore the stack pointer using the value of the frame pointer. Only
// necessary if the stack pointer was modified, meaning the stack size is
@@ -302,7 +461,7 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF,
int FI,
- unsigned &FrameReg) const {
+ Register &FrameReg) const {
const MachineFrameInfo &MFI = MF.getFrameInfo();
const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();
const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
@@ -310,7 +469,7 @@ int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF,
// Callee-saved registers should be referenced relative to the stack
// pointer (positive offset), otherwise use the frame pointer (negative
// offset).
- const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
+ const auto &CSI = getNonLibcallCSI(MFI.getCalleeSavedInfo());
int MinCSFI = 0;
int MaxCSFI = -1;
@@ -330,7 +489,7 @@ int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF,
if (FirstSPAdjustAmount)
Offset += FirstSPAdjustAmount;
else
- Offset += MF.getFrameInfo().getStackSize();
+ Offset += MFI.getStackSize();
} else if (RI->needsStackRealignment(MF) && !MFI.isFixedObjectIndex(FI)) {
// 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
@@ -339,13 +498,20 @@ int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF,
FrameReg = RISCVABI::getBPReg();
else
FrameReg = RISCV::X2;
- Offset += MF.getFrameInfo().getStackSize();
+ Offset += MFI.getStackSize();
+ if (FI < 0)
+ Offset += RVFI->getLibCallStackSize();
} else {
FrameReg = RI->getFrameRegister(MF);
- if (hasFP(MF))
+ if (hasFP(MF)) {
Offset += RVFI->getVarArgsSaveSize();
- else
- Offset += MF.getFrameInfo().getStackSize();
+ if (FI >= 0)
+ Offset -= RVFI->getLibCallStackSize();
+ } else {
+ Offset += MFI.getStackSize();
+ if (FI < 0)
+ Offset += RVFI->getLibCallStackSize();
+ }
}
return Offset;
}
@@ -407,8 +573,8 @@ void RISCVFrameLowering::processFunctionBeforeFrameFinalized(
// still needs an emergency spill slot for branch relaxation. This case
// would currently be missed.
if (!isInt<11>(MFI.estimateStackSize(MF))) {
- int RegScavFI = MFI.CreateStackObject(
- RegInfo->getSpillSize(*RC), RegInfo->getSpillAlignment(*RC), false);
+ int RegScavFI = MFI.CreateStackObject(RegInfo->getSpillSize(*RC),
+ RegInfo->getSpillAlign(*RC), false);
RS->addScavengingFrameIndex(RegScavFI);
}
}
@@ -461,16 +627,17 @@ MachineBasicBlock::iterator RISCVFrameLowering::eliminateCallFramePseudoInstr(
// add sp,sp,-64
uint64_t
RISCVFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF) const {
+ const auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
const MachineFrameInfo &MFI = MF.getFrameInfo();
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
uint64_t StackSize = MFI.getStackSize();
- uint64_t StackAlign = getStackAlignment();
- // FIXME: Disable SplitSPAdjust if save-restore libcall enabled when the patch
- // landing. The callee saved registers will be pushed by the
- // save-restore libcalls, so we don't have to split the SP adjustment
- // in this case.
- //
+ // 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
+ // split the SP adjustment in this case.
+ if (RVFI->getLibCallStackSize())
+ return 0;
+
// Return the FirstSPAdjustAmount if the StackSize can not fit in signed
// 12-bit and there exists a callee saved register need to be pushed.
if (!isInt<12>(StackSize) && (CSI.size() > 0)) {
@@ -480,7 +647,130 @@ RISCVFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF) const {
// 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,
// for RV32E is 4. So (2048 - StackAlign) will satisfy the stack alignment.
- return 2048 - StackAlign;
+ return 2048 - getStackAlign().value();
}
return 0;
}
+
+bool RISCVFrameLowering::spillCalleeSavedRegisters(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
+ ArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
+ if (CSI.empty())
+ return true;
+
+ MachineFunction *MF = MBB.getParent();
+ const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
+ DebugLoc DL;
+ if (MI != MBB.end() && !MI->isDebugInstr())
+ DL = MI->getDebugLoc();
+
+ const char *SpillLibCall = getSpillLibCallName(*MF, CSI);
+ if (SpillLibCall) {
+ // Add spill libcall via non-callee-saved register t0.
+ BuildMI(MBB, MI, DL, TII.get(RISCV::PseudoCALLReg), RISCV::X5)
+ .addExternalSymbol(SpillLibCall, RISCVII::MO_CALL)
+ .setMIFlag(MachineInstr::FrameSetup);
+
+ // Add registers spilled in libcall as liveins.
+ for (auto &CS : CSI)
+ MBB.addLiveIn(CS.getReg());
+ }
+
+ // Manually spill values not spilled by libcall.
+ const auto &NonLibcallCSI = getNonLibcallCSI(CSI);
+ for (auto &CS : NonLibcallCSI) {
+ // Insert the spill to the stack frame.
+ Register Reg = CS.getReg();
+ const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
+ TII.storeRegToStackSlot(MBB, MI, Reg, true, CS.getFrameIdx(), RC, TRI);
+ }
+
+ return true;
+}
+
+bool RISCVFrameLowering::restoreCalleeSavedRegisters(
+ MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
+ MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
+ if (CSI.empty())
+ return true;
+
+ MachineFunction *MF = MBB.getParent();
+ const TargetInstrInfo &TII = *MF->getSubtarget().getInstrInfo();
+ DebugLoc DL;
+ if (MI != MBB.end() && !MI->isDebugInstr())
+ DL = MI->getDebugLoc();
+
+ // Manually restore values not restored by libcall. Insert in reverse order.
+ // loadRegFromStackSlot can insert multiple instructions.
+ const auto &NonLibcallCSI = getNonLibcallCSI(CSI);
+ for (auto &CS : reverse(NonLibcallCSI)) {
+ Register Reg = CS.getReg();
+ const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
+ TII.loadRegFromStackSlot(MBB, MI, Reg, CS.getFrameIdx(), RC, TRI);
+ assert(MI != MBB.begin() && "loadRegFromStackSlot didn't insert any code!");
+ }
+
+ const char *RestoreLibCall = getRestoreLibCallName(*MF, CSI);
+ if (RestoreLibCall) {
+ // Add restore libcall via tail call.
+ MachineBasicBlock::iterator NewMI =
+ BuildMI(MBB, MI, DL, TII.get(RISCV::PseudoTAIL))
+ .addExternalSymbol(RestoreLibCall, RISCVII::MO_CALL)
+ .setMIFlag(MachineInstr::FrameDestroy);
+
+ // Remove trailing returns, since the terminator is now a tail call to the
+ // restore function.
+ if (MI != MBB.end() && MI->getOpcode() == RISCV::PseudoRET) {
+ NewMI->copyImplicitOps(*MF, *MI);
+ MI->eraseFromParent();
+ }
+ }
+
+ return true;
+}
+
+bool RISCVFrameLowering::canUseAsPrologue(const MachineBasicBlock &MBB) const {
+ MachineBasicBlock *TmpMBB = const_cast<MachineBasicBlock *>(&MBB);
+ const MachineFunction *MF = MBB.getParent();
+ const auto *RVFI = MF->getInfo<RISCVMachineFunctionInfo>();
+
+ if (!RVFI->useSaveRestoreLibCalls(*MF))
+ return true;
+
+ // Inserting a call to a __riscv_save libcall requires the use of the register
+ // t0 (X5) to hold the return address. Therefore if this register is already
+ // used we can't insert the call.
+
+ RegScavenger RS;
+ RS.enterBasicBlock(*TmpMBB);
+ return !RS.isRegUsed(RISCV::X5);
+}
+
+bool RISCVFrameLowering::canUseAsEpilogue(const MachineBasicBlock &MBB) const {
+ const MachineFunction *MF = MBB.getParent();
+ MachineBasicBlock *TmpMBB = const_cast<MachineBasicBlock *>(&MBB);
+ const auto *RVFI = MF->getInfo<RISCVMachineFunctionInfo>();
+
+ if (!RVFI->useSaveRestoreLibCalls(*MF))
+ return true;
+
+ // Using the __riscv_restore libcalls to restore CSRs requires a tail call.
+ // This means if we still need to continue executing code within this function
+ // the restore cannot take place in this basic block.
+
+ if (MBB.succ_size() > 1)
+ return false;
+
+ MachineBasicBlock *SuccMBB =
+ MBB.succ_empty() ? TmpMBB->getFallThrough() : *MBB.succ_begin();
+
+ // Doing a tail call should be safe if there are no successors, because either
+ // we have a returning block or the end of the block is unreachable, so the
+ // restore will be eliminated regardless.
+ if (!SuccMBB)
+ return true;
+
+ // The successor can only contain a return, since we would effectively be
+ // replacing the successor with our own tail return at the end of our block.
+ return SuccMBB->isReturnBlock() && SuccMBB->size() == 1;
+}