diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h --- a/llvm/lib/Target/RISCV/RISCV.h +++ b/llvm/lib/Target/RISCV/RISCV.h @@ -30,6 +30,8 @@ class RISCVSubtarget; class RISCVTargetMachine; +void initializeRISCVCFIFixupPass(PassRegistry &); + FunctionPass *createRISCVCodeGenPreparePass(); void initializeRISCVCodeGenPreparePass(PassRegistry &); diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.h b/llvm/lib/Target/RISCV/RISCVFrameLowering.h --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.h +++ b/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 { diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp @@ -611,6 +611,7 @@ const RISCVRegisterInfo *RI = STI.getRegisterInfo(); MachineFrameInfo &MFI = MF.getFrameInfo(); auto *RVFI = MF.getInfo(); + const RISCVInstrInfo *TII = STI.getInstrInfo(); Register FPReg = getFPReg(STI); Register SPReg = getSPReg(STI); @@ -683,6 +684,51 @@ 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. + 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 +740,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 diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/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" @@ -31,6 +32,7 @@ #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" @@ -111,6 +113,10 @@ // RISC-V supports the MachineOutliner. setMachineOutliner(true); setSupportsDefaultOutlining(true); + + // RISC-V supports fixing up the DWARF unwind information. + if (!getMCAsmInfo()->usesWindowsCFI()) + setCFIFixup(true); } const RISCVSubtarget * diff --git a/llvm/test/CodeGen/RISCV/try_catch.ll b/llvm/test/CodeGen/RISCV/try_catch.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/try_catch.ll @@ -0,0 +1,201 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple riscv64 -enable-shrink-wrap=true < %s \ +; RUN: | FileCheck %s -check-prefix=ENABLE + +target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128" +target triple = "riscv64-unknown-unknown-elf" + +@_ZTIi = external dso_local constant ptr + +; Function Attrs: mustprogress +define weak dso_local void @_Z5threev() local_unnamed_addr #0 { +; ENABLE-LABEL: _Z5threev: +; ENABLE: # %bb.0: +; ENABLE-NEXT: addi sp, sp, -16 +; ENABLE-NEXT: .cfi_def_cfa_offset 16 +; ENABLE-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; ENABLE-NEXT: .cfi_offset ra, -8 +; ENABLE-NEXT: li a0, 4 +; ENABLE-NEXT: call __cxa_allocate_exception +; ENABLE-NEXT: li a1, 7 +; ENABLE-NEXT: sw a1, 0(a0) +; ENABLE-NEXT: lui a1, %hi(_ZTIi) +; ENABLE-NEXT: addi a1, a1, %lo(_ZTIi) +; ENABLE-NEXT: li a2, 0 +; ENABLE-NEXT: call __cxa_throw + %1 = tail call ptr @__cxa_allocate_exception(i64 4) #3 + store i32 7, ptr %1, align 16, !tbaa !4 + tail call void @__cxa_throw(ptr nonnull %1, ptr nonnull @_ZTIi, ptr null) #4 + unreachable +} + +declare dso_local ptr @__cxa_allocate_exception(i64) local_unnamed_addr + +declare dso_local void @__cxa_throw(ptr, ptr, ptr) local_unnamed_addr + +; Function Attrs: mustprogress +define weak dso_local void @_Z3twov() local_unnamed_addr #0 personality ptr @__gxx_personality_v0 { +; CHECK: .cfi_offset ra, -8 +; CHECK-NEXT: .cfi_offset s0, -16 +; CHECK-NEXT: addi s0, sp, 48 +; CHECK-NEXT: .cfi_def_cfa s0, 0 +; CHECK-NEXT: .cfi_remember_state +; ENABLE-LABEL: _Z3twov: +; ENABLE: # %bb.0: +; ENABLE-NEXT: addi sp, sp, -16 +; ENABLE-NEXT: .cfi_def_cfa_offset 16 +; ENABLE-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; ENABLE-NEXT: sd s0, 0(sp) # 8-byte Folded Spill +; ENABLE-NEXT: .cfi_offset ra, -8 +; ENABLE-NEXT: .cfi_offset s0, -16 +; ENABLE-NEXT: .cfi_remember_state +; ENABLE-NEXT: .Ltmp0: +; ENABLE-NEXT: call _Z5threev +; ENABLE-NEXT: .Ltmp1: +; ENABLE-NEXT: # %bb.1: +; ENABLE-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; ENABLE-NEXT: ld s0, 0(sp) # 8-byte Folded Reload +; ENABLE-NEXT: .cfi_restore ra +; ENABLE-NEXT: .cfi_restore s0 +; ENABLE-NEXT: addi sp, sp, 16 +; ENABLE-NEXT: .cfi_def_cfa_offset 0 +; ENABLE-NEXT: ret +; ENABLE-NEXT: .LBB1_2: +; ENABLE-NEXT: .cfi_restore_state +; ENABLE-NEXT: .Ltmp2: +; ENABLE-NEXT: sext.w a1, a1 +; ENABLE-NEXT: li a2, 1 +; ENABLE-NEXT: mv s0, a0 +; ENABLE-NEXT: bne a1, a2, .LBB1_6 +; ENABLE-NEXT: # %bb.3: +; ENABLE-NEXT: mv a0, s0 +; ENABLE-NEXT: call __cxa_begin_catch +; ENABLE-NEXT: li a0, 4 +; ENABLE-NEXT: call __cxa_allocate_exception +; ENABLE-NEXT: li a1, 42 +; ENABLE-NEXT: sw a1, 0(a0) +; ENABLE-NEXT: .Ltmp3: +; ENABLE-NEXT: lui a1, %hi(_ZTIi) +; ENABLE-NEXT: addi a1, a1, %lo(_ZTIi) +; ENABLE-NEXT: li a2, 0 +; ENABLE-NEXT: call __cxa_throw +; ENABLE-NEXT: .Ltmp4: +; ENABLE-NEXT: # %bb.4: +; ENABLE-NEXT: .LBB1_5: +; ENABLE-NEXT: .Ltmp5: +; ENABLE-NEXT: mv s0, a0 +; ENABLE-NEXT: call __cxa_end_catch +; ENABLE-NEXT: .LBB1_6: +; ENABLE-NEXT: mv a0, s0 +; ENABLE-NEXT: call _Unwind_Resume@plt + invoke void @_Z5threev() + to label %12 unwind label %1 + +1: ; preds = %0 + %2 = landingpad { ptr, i32 } + catch ptr @_ZTIi + %3 = extractvalue { ptr, i32 } %2, 1 + %4 = tail call i32 @llvm.eh.typeid.for(ptr nonnull @_ZTIi) #3 + %5 = icmp eq i32 %3, %4 + br i1 %5, label %6, label %13 + +6: ; preds = %1 + ; .cfi_restore_state + %7 = extractvalue { ptr, i32 } %2, 0 + %8 = tail call ptr @__cxa_begin_catch(ptr %7) #3 + %9 = tail call ptr @__cxa_allocate_exception(i64 4) #3 + store i32 42, ptr %9, align 16, !tbaa !4 + invoke void @__cxa_throw(ptr nonnull %9, ptr nonnull @_ZTIi, ptr null) #4 + to label %15 unwind label %10 + +10: ; preds = %6 + %11 = landingpad { ptr, i32 } + cleanup + tail call void @__cxa_end_catch() #3 + br label %13 + +12: ; preds = %0 +; .cfi_def_cfa sp, -48 +; .cfi_restore ra +; .cfi_restore s0 +; add sp, sp, 48 +; .cfi_def_cfa_offset + ret void + +13: ; preds = %10, %1 + %14 = phi { ptr, i32 } [ %11, %10 ], [ %2, %1 ] + resume { ptr, i32 } %14 + +15: ; preds = %6 + unreachable +} + +declare dso_local i32 @__gxx_personality_v0(...) + +; Function Attrs: nofree nosync nounwind memory(none) +declare i32 @llvm.eh.typeid.for(ptr) #1 + +declare dso_local ptr @__cxa_begin_catch(ptr) local_unnamed_addr + +declare dso_local void @__cxa_end_catch() local_unnamed_addr + +; Function Attrs: mustprogress norecurse +define dso_local noundef signext i32 @main() local_unnamed_addr #2 personality ptr @__gxx_personality_v0 { +; ENABLE-LABEL: main: +; ENABLE: # %bb.0: +; ENABLE-NEXT: addi sp, sp, -16 +; ENABLE-NEXT: .cfi_def_cfa_offset 16 +; ENABLE-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; ENABLE-NEXT: .cfi_offset ra, -8 +; ENABLE-NEXT: .cfi_remember_state +; ENABLE-NEXT: .Ltmp6: +; ENABLE-NEXT: call _Z3twov +; ENABLE-NEXT: .Ltmp7: +; ENABLE-NEXT: # %bb.1: +; ENABLE-NEXT: li a0, 0 +; ENABLE-NEXT: .LBB2_2: +; ENABLE-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; ENABLE-NEXT: .cfi_restore ra +; ENABLE-NEXT: addi sp, sp, 16 +; ENABLE-NEXT: .cfi_def_cfa_offset 0 +; ENABLE-NEXT: ret +; ENABLE-NEXT: .LBB2_3: +; ENABLE-NEXT: .cfi_restore_state +; ENABLE-NEXT: .Ltmp8: +; ENABLE-NEXT: call __cxa_begin_catch +; ENABLE-NEXT: call __cxa_end_catch +; ENABLE-NEXT: li a0, -1 +; ENABLE-NEXT: j .LBB2_2 + invoke void @_Z3twov() + to label %5 unwind label %1 + +1: ; preds = %0 + %2 = landingpad { ptr, i32 } + catch ptr null + %3 = extractvalue { ptr, i32 } %2, 0 + %4 = tail call ptr @__cxa_begin_catch(ptr %3) #3 + tail call void @__cxa_end_catch() + br label %5 + +5: ; preds = %0, %1 + %6 = phi i32 [ -1, %1 ], [ 0, %0 ] + ret i32 %6 +} + +attributes #0 = { mustprogress "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv64" "target-features"="+64bit,+a,+c,+m,+relax,-d,-e,-experimental-zawrs,-experimental-zca,-experimental-zcb,-experimental-zcd,-experimental-zcf,-experimental-zihintntl,-experimental-ztso,-experimental-zvfh,-f,-h,-save-restore,-svinval,-svnapot,-svpbmt,-v,-xtheadvdot,-xventanacondops,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zdinx,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zicbom,-zicbop,-zicboz,-zihintpause,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-zmmul,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b" } +attributes #1 = { nofree nosync nounwind memory(none) } +attributes #2 = { mustprogress norecurse "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv64" "target-features"="+64bit,+a,+c,+m,+relax,-d,-e,-experimental-zawrs,-experimental-zca,-experimental-zcb,-experimental-zcd,-experimental-zcf,-experimental-zihintntl,-experimental-ztso,-experimental-zvfh,-f,-h,-save-restore,-svinval,-svnapot,-svpbmt,-v,-xtheadvdot,-xventanacondops,-zba,-zbb,-zbc,-zbkb,-zbkc,-zbkx,-zbs,-zdinx,-zfh,-zfhmin,-zfinx,-zhinx,-zhinxmin,-zicbom,-zicbop,-zicboz,-zihintpause,-zk,-zkn,-zknd,-zkne,-zknh,-zkr,-zks,-zksed,-zksh,-zkt,-zmmul,-zve32f,-zve32x,-zve64d,-zve64f,-zve64x,-zvl1024b,-zvl128b,-zvl16384b,-zvl2048b,-zvl256b,-zvl32768b,-zvl32b,-zvl4096b,-zvl512b,-zvl64b,-zvl65536b,-zvl8192b" } +attributes #3 = { nounwind } +attributes #4 = { noreturn } + +!llvm.module.flags = !{!0, !1, !2} +!llvm.ident = !{!3} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{i32 1, !"target-abi", !"lp64"} +!2 = !{i32 1, !"SmallDataLimit", i32 8} +!3 = !{!"clang version 17.0.0 (https://github.com/llvm/llvm-project.git f559e781b2bd918d8cac8a878639870a8f26196d)"} +!4 = !{!5, !5, i64 0} +!5 = !{!"int", !6, i64 0} +!6 = !{!"omnipotent char", !7, i64 0} +!7 = !{!"Simple C++ TBAA"}