Index: llvm/lib/Target/RISCV/RISCV.h =================================================================== --- llvm/lib/Target/RISCV/RISCV.h +++ llvm/lib/Target/RISCV/RISCV.h @@ -30,6 +30,8 @@ class RISCVSubtarget; class RISCVTargetMachine; +void initializeRISCVCFIFixupPass(PassRegistry &); + FunctionPass *createRISCVCodeGenPreparePass(); void initializeRISCVCodeGenPreparePass(PassRegistry &); Index: llvm/lib/Target/RISCV/RISCVFrameLowering.h =================================================================== --- llvm/lib/Target/RISCV/RISCVFrameLowering.h +++ llvm/lib/Target/RISCV/RISCVFrameLowering.h @@ -17,6 +17,8 @@ #include "llvm/Support/TypeSize.h" namespace llvm { + +class MCCFIInstruction; class RISCVSubtarget; class RISCVFrameLowering : public TargetFrameLowering { @@ -30,6 +32,7 @@ void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override; void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; + void resetCFIToInitialState(MachineBasicBlock &MBB) const override; uint64_t getStackSizeWithRVVPadding(const MachineFunction &MF) const; Index: llvm/lib/Target/RISCV/RISCVFrameLowering.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -611,6 +611,8 @@ const RISCVRegisterInfo *RI = STI.getRegisterInfo(); MachineFrameInfo &MFI = MF.getFrameInfo(); auto *RVFI = MF.getInfo(); + const RISCVInstrInfo *TII = STI.getInstrInfo(); + bool EmitCFI = MF.getInfo()->needsAsyncDwarfUnwindInfo(MF); Register FPReg = getFPReg(STI); Register SPReg = getSPReg(STI); @@ -683,6 +685,53 @@ RI->adjustReg(MBB, LastFrameDestroy, DL, SPReg, SPReg, StackOffset::getFixed(SecondSPAdjustAmount), MachineInstr::FrameDestroy, getStackAlign()); + + // Emit ".cfi_def_cfa_offset FirstSPAdjustAmount" if using an sp-based CFA + if (!hasFP(MF)) { + unsigned CFIIndex = MF.addFrameInst( + MCCFIInstruction::cfiDefCfaOffset(nullptr, -FirstSPAdjustAmount)); + BuildMI(MBB, LastFrameDestroy, DL, + TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + } + } + + if (hasFP(MF)) { + // To find the instruction restoring FP from stack. + for (auto &I = LastFrameDestroy; I != MBBI; ++I) { + if (I->mayLoad() && I->getOperand(0).isReg()) { + Register DestReg = I->getOperand(0).getReg(); + if (DestReg == FPReg) { + // If there is frame pointer, after restoring $fp registers, we + // need adjust CFA back to the correct sp-based offset. + // Emit ".cfi_def_cfa $sp, CFAOffset" + uint64_t CFAOffset = + FirstSPAdjustAmount + ? -FirstSPAdjustAmount + RVFI->getVarArgsSaveSize() + : -FPOffset; + unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa( + nullptr, RI->getDwarfRegNum(SPReg, true), CFAOffset)); + BuildMI(MBB, std::next(I), DL, + TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); + break; + } + } + } + } + + // Add CFI directives for callee-saved registers. + // Iterate over list of callee-saved registers and emit .cfi_restore + // directives. + if (EmitCFI) { + for (const auto &Entry : 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); + } } if (FirstSPAdjustAmount) @@ -694,6 +743,13 @@ // Emit epilogue for shadow call stack. emitSCSEpilogue(MF, MBB, MBBI, DL); + + // After restoring $sp, we need to adjust CFA to $(sp + 0) + // Emit ".cfi_def_cfa_offset 0" + unsigned CFIIndex = + MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, 0)); + BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION)) + .addCFIIndex(CFIIndex); } StackOffset @@ -1367,3 +1423,39 @@ TargetStackID::Value RISCVFrameLowering::getStackIDForScalableVectors() const { return TargetStackID::ScalableVector; } + +static void insertCFISameValue(const MCInstrDesc &Desc, MachineFunction &MF, + MachineBasicBlock &MBB, + MachineBasicBlock::iterator InsertPt, + unsigned DwarfReg) { + unsigned CFIIndex = + MF.addFrameInst(MCCFIInstruction::createSameValue(nullptr, DwarfReg)); + BuildMI(MBB, InsertPt, DebugLoc(), Desc).addCFIIndex(CFIIndex); +} + +void RISCVFrameLowering::resetCFIToInitialState(MachineBasicBlock &MBB) const { + + MachineFunction &MF = *MBB.getParent(); + const auto &Subtarget = MF.getSubtarget(); + const TargetInstrInfo &TII = *Subtarget.getInstrInfo(); + const auto &TRI = + static_cast(*Subtarget.getRegisterInfo()); + const auto &MFI = *MF.getInfo(); + + const MCInstrDesc &CFIDesc = TII.get(TargetOpcode::CFI_INSTRUCTION); + DebugLoc DL; + // Reset the CFA to `SP + 0`. + MachineBasicBlock::iterator InsertPt = MBB.begin(); + unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa( + nullptr, TRI.getDwarfRegNum(RISCV::X2, true), 0)); + BuildMI(MBB, InsertPt, DL, CFIDesc).addCFIIndex(CFIIndex); + + // Emit .cfi_same_value for callee-saved registers. + const std::vector &CSI = + MF.getFrameInfo().getCalleeSavedInfo(); + for (const auto &Info : CSI) { + unsigned Reg = Info.getReg(); + insertCFISameValue(CFIDesc, MF, MBB, InsertPt, + TRI.getDwarfRegNum(Reg, true)); + } +} Index: llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h =================================================================== --- llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h +++ llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.h @@ -129,6 +129,8 @@ bool isVectorCall() const { return IsVectorCall; } void setIsVectorCall() { IsVectorCall = true; } + bool needsAsyncDwarfUnwindInfo(const MachineFunction &MF) const; + bool needsDwarfUnwindInfo(const MachineFunction &MF) const; }; } // end namespace llvm Index: llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.cpp +++ llvm/lib/Target/RISCV/RISCVMachineFunctionInfo.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "RISCVMachineFunctionInfo.h" +#include "llvm/MC/MCAsmInfo.h" using namespace llvm; @@ -43,3 +44,16 @@ bool RISCVMachineFunctionInfo::isSExt32Register(Register Reg) const { return is_contained(SExt32Registers, Reg); } + +bool RISCVMachineFunctionInfo::needsDwarfUnwindInfo( + const MachineFunction &MF) const { + return MF.needsFrameMoves(); +} + +bool RISCVMachineFunctionInfo::needsAsyncDwarfUnwindInfo( + const MachineFunction &MF) const { + + const Function &F = MF.getFunction(); + return needsDwarfUnwindInfo(MF) && F.getUWTableKind() == UWTableKind::Async && + !F.hasMinSize(); +} Index: llvm/lib/Target/RISCV/RISCVTargetMachine.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -20,6 +20,7 @@ #include "TargetInfo/RISCVTargetInfo.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/CFIFixup.h" #include "llvm/CodeGen/GlobalISel/IRTranslator.h" #include "llvm/CodeGen/GlobalISel/InstructionSelect.h" #include "llvm/CodeGen/GlobalISel/Legalizer.h" @@ -29,7 +30,9 @@ #include "llvm/CodeGen/Passes.h" #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" #include "llvm/CodeGen/TargetPassConfig.h" +#include "llvm/IR/LegacyPassManager.h" #include "llvm/InitializePasses.h" +#include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/TargetRegistry.h" #include "llvm/Support/FormattedStream.h" #include "llvm/Target/TargetOptions.h" @@ -119,6 +122,10 @@ if (TT.isOSFuchsia() && !TT.isArch64Bit()) report_fatal_error("Fuchsia is only supported for 64-bit"); + + // RISC-V supports fixing up the DWARF unwind information. + if (!getMCAsmInfo()->usesWindowsCFI()) + setCFIFixup(true); } const RISCVSubtarget *