Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RISCV][CFI] add function epilogue cfi information #110810

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
  •  
  •  
  •  
234 changes: 199 additions & 35 deletions llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,25 @@ getRVVCalleeSavedInfo(const MachineFunction &MF,
return RVVCSI;
}

static SmallVector<CalleeSavedInfo, 8>
getPushOrLibCallsSavedInfo(const MachineFunction &MF,
const std::vector<CalleeSavedInfo> &CSI) {
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();

SmallVector<CalleeSavedInfo, 8> PushPopOrLibCallsCSI;
if (!RVFI->useSaveRestoreLibCalls(MF) && !RVFI->isPushable(MF))
return PushPopOrLibCallsCSI;

for (auto &CS : CSI) {
const auto *FII = llvm::find_if(
FixedCSRFIMap, [&](auto P) { return P.first == CS.getReg(); });
if (FII != std::end(FixedCSRFIMap))
PushPopOrLibCallsCSI.push_back(CS);
}

return PushPopOrLibCallsCSI;
}

void RISCVFrameLowering::adjustStackForRVV(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
Expand Down Expand Up @@ -557,6 +576,8 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
// Determine the correct frame layout
determineFrameLayout(MF);

const auto &CSI = MFI.getCalleeSavedInfo();

// 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
Expand All @@ -582,6 +603,23 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
unsigned LibCallFrameSize =
alignTo((STI.getXLen() / 8) * LibCallRegs, getStackAlign());
RVFI->setLibCallStackSize(LibCallFrameSize);

unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::cfiDefCfaOffset(nullptr, LibCallFrameSize));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameSetup);

for (const auto &Entry : getPushOrLibCallsSavedInfo(MF, CSI)) {
int FrameIdx = Entry.getFrameIdx();
int64_t Offset = MFI.getObjectOffset(FrameIdx);
Register Reg = Entry.getReg();
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, RI->getDwarfRegNum(Reg, true), Offset));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameSetup);
}
}

// FIXME (note copied from Lanai): This appears to be overallocating. Needs
Expand Down Expand Up @@ -616,23 +654,38 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
uint64_t Spimm = std::min(alignDown(StackSize, 16), (uint64_t)48);
FirstFrameSetup->getOperand(1).setImm(Spimm);
StackSize -= Spimm;

unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize - StackSize));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameSetup);

for (const auto &Entry : getPushOrLibCallsSavedInfo(MF, CSI)) {
int FrameIdx = Entry.getFrameIdx();
int64_t Offset = MFI.getObjectOffset(FrameIdx);
Register Reg = Entry.getReg();
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
nullptr, RI->getDwarfRegNum(Reg, true), Offset));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameSetup);
}
}

if (StackSize != 0) {
// Allocate space on the stack if necessary.
RI->adjustReg(MBB, MBBI, DL, SPReg, SPReg,
StackOffset::getFixed(-StackSize), MachineInstr::FrameSetup,
getStackAlign());
}

// Emit ".cfi_def_cfa_offset RealStackSize"
unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameSetup);

const auto &CSI = MFI.getCalleeSavedInfo();
// Emit ".cfi_def_cfa_offset RealStackSize"
unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::cfiDefCfaOffset(nullptr, RealStackSize));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameSetup);
}

// 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
Expand All @@ -644,7 +697,7 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,

// Iterate over list of callee-saved registers and emit .cfi_offset
// directives.
for (const auto &Entry : CSI) {
for (const auto &Entry : getUnmanagedCSI(MF, CSI)) {
int FrameIdx = Entry.getFrameIdx();
if (FrameIdx >= 0 &&
MFI.getStackID(FrameIdx) == TargetStackID::ScalableVector)
Expand Down Expand Up @@ -759,19 +812,29 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,
void RISCVFrameLowering::deallocateStack(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
const DebugLoc &DL, uint64_t StackSize,
const DebugLoc &DL,
uint64_t &StackSize,
int64_t CFAOffset) const {
const RISCVRegisterInfo *RI = STI.getRegisterInfo();
const RISCVInstrInfo *TII = STI.getInstrInfo();

RI->adjustReg(MBB, MBBI, DL, SPReg, SPReg, StackOffset::getFixed(StackSize),
MachineInstr::FrameDestroy, getStackAlign());
StackSize = 0;

unsigned CFIIndex =
MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, CFAOffset));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameDestroy);
}

void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
const RISCVRegisterInfo *RI = STI.getRegisterInfo();
MachineFrameInfo &MFI = MF.getFrameInfo();
auto *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
const RISCVInstrInfo *TII = STI.getInstrInfo();

// All calls are tail calls in GHC calling conv, and functions have no
// prologue/epilogue.
Expand Down Expand Up @@ -814,15 +877,25 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
RVFI->getVarArgsSaveSize();
uint64_t RVVStackSize = RVFI->getRVVStackSize();

bool RestoreFP = RI->hasStackRealignment(MF) || MFI.hasVarSizedObjects() ||
!hasReservedCallFrame(MF);

bool RestoreSPFromFP = RI->hasStackRealignment(MF) ||
MFI.hasVarSizedObjects() || !hasReservedCallFrame(MF);
if (RVVStackSize) {
// If RestoreFP the stack pointer will be restored using the frame pointer
// value.
if (!RestoreFP)
// If RestoreSPFromFP the stack pointer will be restored using the frame
// pointer value.
if (!RestoreSPFromFP)
adjustStackForRVV(MF, MBB, LastFrameDestroy, DL, RVVStackSize,
MachineInstr::FrameDestroy);

if (!hasFP(MF)) {
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(
nullptr, RI->getDwarfRegNum(SPReg, true), RealStackSize));
BuildMI(MBB, LastFrameDestroy, DL,
TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameDestroy);
}

emitCalleeSavedRVVEpilogCFI(MBB, LastFrameDestroy);
}

if (FirstSPAdjustAmount) {
Expand All @@ -831,12 +904,21 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
assert(SecondSPAdjustAmount > 0 &&
"SecondSPAdjustAmount should be greater than zero");

// If RestoreFP the stack pointer will be restored using the frame pointer
// value.
if (!RestoreFP)
// If RestoreSPFromFP the stack pointer will be restored using the frame
// pointer value.
if (!RestoreSPFromFP)
RI->adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg,
StackOffset::getFixed(SecondSPAdjustAmount),
MachineInstr::FrameDestroy, getStackAlign());

if (!hasFP(MF)) {
unsigned CFIIndex = MF.addFrameInst(
MCCFIInstruction::cfiDefCfaOffset(nullptr, FirstSPAdjustAmount));
BuildMI(MBB, LastFrameDestroy, DL,
TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameDestroy);
}
}

// Restore the stack pointer using the value of the frame pointer. Only
Expand All @@ -849,14 +931,44 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
// normally it's just checking the variable sized object is present or not
// is enough, but we also don't preserve that at prologue/epilogue when
// have vector objects in stack.
if (RestoreFP) {
if (RestoreSPFromFP) {
assert(hasFP(MF) && "frame pointer should not have been eliminated");

RI->adjustReg(MBB, LastFrameDestroy, DL, SPReg, FPReg,
StackOffset::getFixed(-FPOffset), MachineInstr::FrameDestroy,
getStackAlign());
}

if (hasFP(MF)) {
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(
nullptr, RI->getDwarfRegNum(SPReg, true), RealStackSize));
BuildMI(MBB, LastFrameDestroy, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameDestroy);
}

if (getLibCallID(MF, CSI) != -1) {
// tail __riscv_restore_[0-12] instruction is considered as a terminator,
// therefor it is unnecessary to place any CFI instructions after it. Just
// deallocate stack if needed and return.
if (StackSize != 0)
deallocateStack(MF, MBB, MBBI, DL, StackSize,
RVFI->getLibCallStackSize());

// Emit epilogue for shadow call stack.
emitSCSEpilogue(MF, MBB, MBBI, DL);
return;
}

// Recover callee-saved registers.
for (const auto &Entry : getUnmanagedCSI(MF, CSI)) {
Register Reg = Entry.getReg();
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestore(
nullptr, RI->getDwarfRegNum(Reg, true)));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameDestroy);
}

bool ApplyPop = RVFI->isPushable(MF) && MBBI != MBB.end() &&
MBBI->getOpcode() == RISCV::CM_POP;
if (ApplyPop) {
Expand All @@ -872,12 +984,31 @@ void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
deallocateStack(MF, MBB, MBBI, DL, StackSize,
/*stack_adj of cm.pop instr*/ RealStackSize - StackSize);

++MBBI;
auto NextI = next_nodbg(MBBI, MBB.end());
if (NextI == MBB.end() || NextI->getOpcode() != RISCV::PseudoRET) {
++MBBI;

for (const auto &Entry : getPushOrLibCallsSavedInfo(MF, CSI)) {
Register Reg = Entry.getReg();
unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::createRestore(
nullptr, RI->getDwarfRegNum(Reg, true)));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameDestroy);
}

// Update CFA offset. After CM_POP SP should be equal to CFA, so CFA
// offset should be a zero.
unsigned CFIIndex =
MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, 0));
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameDestroy);
}
}

// Deallocate stack if we didn't already do it during cm.pop handling and
// StackSize isn't a zero
if (StackSize != 0 && !ApplyPop)
// Deallocate stack if StackSize isn't a zero yet
if (StackSize != 0)
deallocateStack(MF, MBB, MBBI, DL, StackSize, 0);

// Emit epilogue for shadow call stack.
Expand Down Expand Up @@ -1564,6 +1695,23 @@ bool RISCVFrameLowering::spillCalleeSavedRegisters(
return true;
}

static unsigned getCaleeSavedRVVNumRegs(const Register &BaseReg) {
return RISCV::VRRegClass.contains(BaseReg) ? 1
: RISCV::VRM2RegClass.contains(BaseReg) ? 2
: RISCV::VRM4RegClass.contains(BaseReg) ? 4
: 8;
}

static MCRegister getRVVBaseRegister(const RISCVRegisterInfo &TRI,
const Register &Reg) {
MCRegister BaseReg = TRI.getSubReg(Reg, RISCV::sub_vrm1_0);
// If it's not a grouped vector register, it doesn't have subregister, so
// the base register is just itself.
if (BaseReg == RISCV::NoRegister)
BaseReg = Reg;
return BaseReg;
}

void RISCVFrameLowering::emitCalleeSavedRVVPrologCFI(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI, bool HasFP) const {
MachineFunction *MF = MBB.getParent();
Expand All @@ -1590,15 +1738,8 @@ void RISCVFrameLowering::emitCalleeSavedRVVPrologCFI(
// Insert the spill to the stack frame.
int FI = CS.getFrameIdx();
if (FI >= 0 && MFI.getStackID(FI) == TargetStackID::ScalableVector) {
MCRegister BaseReg = TRI.getSubReg(CS.getReg(), RISCV::sub_vrm1_0);
// If it's not a grouped vector register, it doesn't have subregister, so
// the base register is just itself.
if (BaseReg == RISCV::NoRegister)
BaseReg = CS.getReg();
unsigned NumRegs = RISCV::VRRegClass.contains(CS.getReg()) ? 1
: RISCV::VRM2RegClass.contains(CS.getReg()) ? 2
: RISCV::VRM4RegClass.contains(CS.getReg()) ? 4
: 8;
MCRegister BaseReg = getRVVBaseRegister(TRI, CS.getReg());
unsigned NumRegs = getCaleeSavedRVVNumRegs(CS.getReg());
for (unsigned i = 0; i < NumRegs; ++i) {
unsigned CFIIndex = MF->addFrameInst(createDefCFAOffset(
TRI, BaseReg + i, -FixedSize, MFI.getObjectOffset(FI) / 8 + i));
Expand All @@ -1610,6 +1751,29 @@ void RISCVFrameLowering::emitCalleeSavedRVVPrologCFI(
}
}

void RISCVFrameLowering::emitCalleeSavedRVVEpilogCFI(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI) const {
MachineFunction *MF = MBB.getParent();
const MachineFrameInfo &MFI = MF->getFrameInfo();
const RISCVRegisterInfo *RI = STI.getRegisterInfo();
const TargetInstrInfo &TII = *STI.getInstrInfo();
const RISCVRegisterInfo &TRI = *STI.getRegisterInfo();
DebugLoc DL = MBB.findDebugLoc(MI);

const auto &RVVCSI = getRVVCalleeSavedInfo(*MF, MFI.getCalleeSavedInfo());
for (auto &CS : RVVCSI) {
MCRegister BaseReg = getRVVBaseRegister(TRI, CS.getReg());
unsigned NumRegs = getCaleeSavedRVVNumRegs(CS.getReg());
for (unsigned i = 0; i < NumRegs; ++i) {
unsigned CFIIndex = MF->addFrameInst(MCCFIInstruction::createRestore(
nullptr, RI->getDwarfRegNum(BaseReg + i, true)));
BuildMI(MBB, MI, DL, TII.get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex)
.setMIFlag(MachineInstr::FrameDestroy);
}
}
}

bool RISCVFrameLowering::restoreCalleeSavedRegisters(
MachineBasicBlock &MBB, MachineBasicBlock::iterator MI,
MutableArrayRef<CalleeSavedInfo> CSI, const TargetRegisterInfo *TRI) const {
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/Target/RISCV/RISCVFrameLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,11 @@ class RISCVFrameLowering : public TargetFrameLowering {
void emitCalleeSavedRVVPrologCFI(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
bool HasFP) const;
void emitCalleeSavedRVVEpilogCFI(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI) const;
void deallocateStack(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI, const DebugLoc &DL,
uint64_t StackSize, int64_t CFAOffset) const;
uint64_t &StackSize, int64_t CFAOffset) const;

std::pair<int64_t, Align>
assignRVVStackObjectOffsets(MachineFunction &MF) const;
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,8 @@ RISCVTargetMachine::RISCVTargetMachine(const Target &T, const Triple &TT,

if (TT.isOSFuchsia() && !TT.isArch64Bit())
report_fatal_error("Fuchsia is only supported for 64-bit");

setCFIFixup(true);
}

const RISCVSubtarget *
Expand Down
Loading