diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt index 5146e519c352..cbb4c2cedfb9 100644 --- a/llvm/lib/Target/RISCV/CMakeLists.txt +++ b/llvm/lib/Target/RISCV/CMakeLists.txt @@ -43,6 +43,7 @@ add_llvm_target(RISCVCodeGen RISCVInstrInfo.cpp RISCVISelDAGToDAG.cpp RISCVISelLowering.cpp + RISCVLandingPadSetup.cpp RISCVMachineFunctionInfo.cpp RISCVMergeBaseOffset.cpp RISCVOptWInstrs.cpp diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h index 80cb39529149..5a94ada8f8dd 100644 --- a/llvm/lib/Target/RISCV/RISCV.h +++ b/llvm/lib/Target/RISCV/RISCV.h @@ -34,6 +34,9 @@ void initializeRISCVDeadRegisterDefinitionsPass(PassRegistry &); FunctionPass *createRISCVIndirectBranchTrackingPass(); void initializeRISCVIndirectBranchTrackingPass(PassRegistry &); +FunctionPass *createRISCVLandingPadSetupPass(); +void initializeRISCVLandingPadSetupPass(PassRegistry &); + FunctionPass *createRISCVISelDag(RISCVTargetMachine &TM, CodeGenOptLevel OptLevel); diff --git a/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp b/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp index 1b484d486edc..50ca17f7fbc9 100644 --- a/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp +++ b/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp @@ -23,7 +23,7 @@ using namespace llvm; -static cl::opt PreferredLandingPadLabel( +cl::opt PreferredLandingPadLabel( "riscv-landing-pad-label", cl::ReallyHidden, cl::desc("Use preferred fixed label for all labels")); diff --git a/llvm/lib/Target/RISCV/RISCVLandingPadSetup.cpp b/llvm/lib/Target/RISCV/RISCVLandingPadSetup.cpp new file mode 100644 index 000000000000..e162c7112ae0 --- /dev/null +++ b/llvm/lib/Target/RISCV/RISCVLandingPadSetup.cpp @@ -0,0 +1,85 @@ +//===------------ RISCVLandingPadSetup.cpp ---------------------------------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is a RISC-V pass to setup landing pad labels for indirect jumps. +// Currently it is only supported fixed labels. +// +//===----------------------------------------------------------------------===// + +#include "RISCV.h" +#include "RISCVInstrInfo.h" +#include "RISCVSubtarget.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/InitializePasses.h" + +using namespace llvm; + +#define DEBUG_TYPE "riscv-lpad-setup" +#define PASS_NAME "RISC-V Landing Pad Setup" + +extern cl::opt PreferredLandingPadLabel; + +namespace { + +class RISCVLandingPadSetup : public MachineFunctionPass { +public: + static char ID; + + RISCVLandingPadSetup() : MachineFunctionPass(ID) {} + + bool runOnMachineFunction(MachineFunction &F) override; + + StringRef getPassName() const override { return PASS_NAME; } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + MachineFunctionPass::getAnalysisUsage(AU); + } +}; + +} // end anonymous namespace + +bool RISCVLandingPadSetup::runOnMachineFunction(MachineFunction &MF) { + const auto &STI = MF.getSubtarget(); + const RISCVInstrInfo &TII = *STI.getInstrInfo(); + + if (!STI.hasStdExtZicfilp()) + return false; + + bool Changed = false; + for (MachineBasicBlock &MBB : MF) + for (MachineInstr &MI : llvm::make_early_inc_range(MBB)) { + if (MI.getOpcode() != RISCV::PseudoBRINDNonX7 && + MI.getOpcode() != RISCV::PseudoCALLIndirectNonX7 && + MI.getOpcode() != RISCV::PseudoTAILIndirectNonX7) + continue; + uint32_t Label = 0; + if (PreferredLandingPadLabel.getNumOccurrences() > 0) { + if (!isUInt<20>(PreferredLandingPadLabel)) + report_fatal_error( + "riscv-landing-pad-label=, needs to fit in " + "unsigned 20-bits"); + Label = PreferredLandingPadLabel; + } + BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(RISCV::LUI), RISCV::X7) + .addImm(Label); + MachineInstrBuilder(MF, &MI).addUse(RISCV::X7, RegState::ImplicitKill); + Changed = true; + } + + return Changed; +} + +INITIALIZE_PASS(RISCVLandingPadSetup, DEBUG_TYPE, PASS_NAME, false, false) + +char RISCVLandingPadSetup::ID = 0; + +FunctionPass *llvm::createRISCVLandingPadSetupPass() { + return new RISCVLandingPadSetup(); +} diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp index e5e96fbab45a..cb08ba42a3ea 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -552,6 +552,7 @@ void RISCVPassConfig::addPreRegAlloc() { addPass(createRISCVInsertReadWriteCSRPass()); addPass(createRISCVInsertWriteVXRMPass()); + addPass(createRISCVLandingPadSetupPass()); // Run RISCVInsertVSETVLI after PHI elimination. On O1 and above do it after // register coalescing so needVSETVLIPHI doesn't need to look through COPYs. diff --git a/llvm/test/CodeGen/RISCV/O0-pipeline.ll b/llvm/test/CodeGen/RISCV/O0-pipeline.ll index b17c28e2d81f..9cfdb7e3e694 100644 --- a/llvm/test/CodeGen/RISCV/O0-pipeline.ll +++ b/llvm/test/CodeGen/RISCV/O0-pipeline.ll @@ -43,6 +43,7 @@ ; CHECK-NEXT: RISC-V Pre-RA pseudo instruction expansion pass ; CHECK-NEXT: RISC-V Insert Read/Write CSR Pass ; CHECK-NEXT: RISC-V Insert Write VXRM Pass +; CHECK-NEXT: RISC-V Landing Pad Setup ; CHECK-NEXT: Init Undef Pass ; CHECK-NEXT: Eliminate PHI nodes for register allocation ; CHECK-NEXT: Two-Address instruction pass diff --git a/llvm/test/CodeGen/RISCV/O3-pipeline.ll b/llvm/test/CodeGen/RISCV/O3-pipeline.ll index a283cc6aa3a0..e650cfc6c486 100644 --- a/llvm/test/CodeGen/RISCV/O3-pipeline.ll +++ b/llvm/test/CodeGen/RISCV/O3-pipeline.ll @@ -118,6 +118,7 @@ ; CHECK-NEXT: RISC-V Merge Base Offset ; CHECK-NEXT: RISC-V Insert Read/Write CSR Pass ; CHECK-NEXT: RISC-V Insert Write VXRM Pass +; CHECK-NEXT: RISC-V Landing Pad Setup ; CHECK-NEXT: Detect Dead Lanes ; CHECK-NEXT: Init Undef Pass ; CHECK-NEXT: Process Implicit Definitions diff --git a/llvm/test/CodeGen/RISCV/lpad.ll b/llvm/test/CodeGen/RISCV/lpad.ll index de82a9ee4e34..cc78305a1c87 100644 --- a/llvm/test/CodeGen/RISCV/lpad.ll +++ b/llvm/test/CodeGen/RISCV/lpad.ll @@ -13,15 +13,16 @@ define void @indirctbr(i32 %i, ptr %p) { ; RV32-NEXT: addi a2, a2, %lo(.L__const.indirctbr.addr) ; RV32-NEXT: add a0, a2, a0 ; RV32-NEXT: lw a0, 0(a0) +; RV32-NEXT: lui t2, 0 ; RV32-NEXT: jr a0 ; RV32-NEXT: .p2align 2 -; RV32-NEXT: .Ltmp0: # Block address taken +; RV32-NEXT: .Ltmp3: # Block address taken ; RV32-NEXT: .LBB0_1: # %labelA ; RV32-NEXT: lpad 0 ; RV32-NEXT: li a0, 1 ; RV32-NEXT: sw a0, 0(a1) ; RV32-NEXT: .p2align 2 -; RV32-NEXT: .Ltmp1: # Block address taken +; RV32-NEXT: .Ltmp4: # Block address taken ; RV32-NEXT: .LBB0_2: # %labelB ; RV32-NEXT: lpad 0 ; RV32-NEXT: li a0, 2 @@ -37,15 +38,16 @@ define void @indirctbr(i32 %i, ptr %p) { ; RV64-NEXT: addi a2, a2, %lo(.L__const.indirctbr.addr) ; RV64-NEXT: add a0, a2, a0 ; RV64-NEXT: ld a0, 0(a0) +; RV64-NEXT: lui t2, 0 ; RV64-NEXT: jr a0 ; RV64-NEXT: .p2align 2 -; RV64-NEXT: .Ltmp0: # Block address taken +; RV64-NEXT: .Ltmp3: # Block address taken ; RV64-NEXT: .LBB0_1: # %labelA ; RV64-NEXT: lpad 0 ; RV64-NEXT: li a0, 1 ; RV64-NEXT: sw a0, 0(a1) ; RV64-NEXT: .p2align 2 -; RV64-NEXT: .Ltmp1: # Block address taken +; RV64-NEXT: .Ltmp4: # Block address taken ; RV64-NEXT: .LBB0_2: # %labelB ; RV64-NEXT: lpad 0 ; RV64-NEXT: li a0, 2 @@ -65,6 +67,68 @@ labelB: ; preds = %labelA, %entry ret void } +; Check indirect call. +define void @call(ptr %0) { +; CHECK-LABEL: call: +; CHECK: # %bb.0: +; CHECK-NEXT: lpad 0 +; CHECK-NEXT: lui t2, 0 +; CHECK-NEXT: jr a0 + tail call void %0() + ret void +} + +; Check invoke. +declare dso_local i32 @__gxx_personality_v0(...) +define void @invoke(ptr %f) personality ptr @__gxx_personality_v0 { +; RV32-LABEL: invoke: +; RV32: # %bb.0: # %entry +; RV32-NEXT: lpad 0 +; RV32-NEXT: addi sp, sp, -16 +; RV32-NEXT: .cfi_def_cfa_offset 16 +; RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; RV32-NEXT: .cfi_offset ra, -4 +; RV32-NEXT: .Ltmp0: +; RV32-NEXT: lui t2, 0 +; RV32-NEXT: jalr a0 +; RV32-NEXT: .Ltmp1: +; RV32-NEXT: .LBB2_1: # %try.cont +; RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; RV32-NEXT: addi sp, sp, 16 +; RV32-NEXT: ret +; RV32-NEXT: .LBB2_2: # %lpad +; RV32-NEXT: .Ltmp2: +; RV32-NEXT: j .LBB2_1 +; +; RV64-LABEL: invoke: +; RV64: # %bb.0: # %entry +; RV64-NEXT: lpad 0 +; RV64-NEXT: addi sp, sp, -16 +; RV64-NEXT: .cfi_def_cfa_offset 16 +; RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; RV64-NEXT: .cfi_offset ra, -8 +; RV64-NEXT: .Ltmp0: +; RV64-NEXT: lui t2, 0 +; RV64-NEXT: jalr a0 +; RV64-NEXT: .Ltmp1: +; RV64-NEXT: .LBB2_1: # %try.cont +; RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; RV64-NEXT: addi sp, sp, 16 +; RV64-NEXT: ret +; RV64-NEXT: .LBB2_2: # %lpad +; RV64-NEXT: .Ltmp2: +; RV64-NEXT: j .LBB2_1 +entry: + invoke void %f() to label %try.cont unwind label %lpad + +lpad: + %0 = landingpad { ptr, i32 } cleanup + br label %try.cont + +try.cont: + ret void +} + ; Check external linkage function. define void @external() { ; CHECK-LABEL: external: