diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt index 5146e519c352944..cbb4c2cedfb97e4 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 80cb3952914963d..5a94ada8f8dd46b 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 1b484d486edcb39..50ca17f7fbc91a9 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 000000000000000..09819f13fd9820d --- /dev/null +++ b/llvm/lib/Target/RISCV/RISCVLandingPadSetup.cpp @@ -0,0 +1,89 @@ +//===------------ 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 this pass only supports 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; + + 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; + } + + // Zicfilp does not check X7 if landing pad label is zero. + if (Label == 0) + 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; + 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 8b3770aeb5d13a5..b6884321f084112 100644 --- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp +++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp @@ -554,6 +554,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 9be03d557bd8d46..7473809a2c5d2e2 100644 --- a/llvm/test/CodeGen/RISCV/O0-pipeline.ll +++ b/llvm/test/CodeGen/RISCV/O0-pipeline.ll @@ -41,6 +41,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 7bad290bf313c83..eaaf86731351ab8 100644 --- a/llvm/test/CodeGen/RISCV/O3-pipeline.ll +++ b/llvm/test/CodeGen/RISCV/O3-pipeline.ll @@ -116,6 +116,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 de82a9ee4e34b42..049715b7dbb6913 100644 --- a/llvm/test/CodeGen/RISCV/lpad.ll +++ b/llvm/test/CodeGen/RISCV/lpad.ll @@ -1,6 +1,10 @@ ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc -mtriple riscv32 -mattr=+experimental-zicfilp < %s | FileCheck %s --check-prefixes=CHECK,RV32 ; RUN: llc -mtriple riscv64 -mattr=+experimental-zicfilp < %s | FileCheck %s --check-prefixes=CHECK,RV64 +; RUN: llc -mtriple riscv32 -mattr=+experimental-zicfilp \ +; RUN: -riscv-landing-pad-label=1 < %s | FileCheck %s --check-prefixes=FIXED-ONE,FIXED-ONE-RV32 +; RUN: llc -mtriple riscv64 -mattr=+experimental-zicfilp \ +; RUN: -riscv-landing-pad-label=1 < %s | FileCheck %s --check-prefixes=FIXED-ONE,FIXED-ONE-RV64 ; Check indirectbr. @__const.indirctbr.addr = private unnamed_addr constant [2 x ptr] [ptr blockaddress(@indirctbr, %labelA), ptr blockaddress(@indirctbr, %labelB)], align 8 @@ -15,13 +19,13 @@ define void @indirctbr(i32 %i, ptr %p) { ; RV32-NEXT: lw a0, 0(a0) ; 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 @@ -39,18 +43,67 @@ define void @indirctbr(i32 %i, ptr %p) { ; RV64-NEXT: ld a0, 0(a0) ; 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 ; RV64-NEXT: sw a0, 0(a1) ; RV64-NEXT: ret +; +; FIXED-ONE-RV32-LABEL: indirctbr: +; FIXED-ONE-RV32: # %bb.0: # %entry +; FIXED-ONE-RV32-NEXT: lpad 1 +; FIXED-ONE-RV32-NEXT: slli a0, a0, 2 +; FIXED-ONE-RV32-NEXT: lui a2, %hi(.L__const.indirctbr.addr) +; FIXED-ONE-RV32-NEXT: addi a2, a2, %lo(.L__const.indirctbr.addr) +; FIXED-ONE-RV32-NEXT: add a0, a2, a0 +; FIXED-ONE-RV32-NEXT: lw a0, 0(a0) +; FIXED-ONE-RV32-NEXT: lui t2, 1 +; FIXED-ONE-RV32-NEXT: jr a0 +; FIXED-ONE-RV32-NEXT: .p2align 2 +; FIXED-ONE-RV32-NEXT: .Ltmp3: # Block address taken +; FIXED-ONE-RV32-NEXT: .LBB0_1: # %labelA +; FIXED-ONE-RV32-NEXT: lpad 1 +; FIXED-ONE-RV32-NEXT: li a0, 1 +; FIXED-ONE-RV32-NEXT: sw a0, 0(a1) +; FIXED-ONE-RV32-NEXT: .p2align 2 +; FIXED-ONE-RV32-NEXT: .Ltmp4: # Block address taken +; FIXED-ONE-RV32-NEXT: .LBB0_2: # %labelB +; FIXED-ONE-RV32-NEXT: lpad 1 +; FIXED-ONE-RV32-NEXT: li a0, 2 +; FIXED-ONE-RV32-NEXT: sw a0, 0(a1) +; FIXED-ONE-RV32-NEXT: ret +; +; FIXED-ONE-RV64-LABEL: indirctbr: +; FIXED-ONE-RV64: # %bb.0: # %entry +; FIXED-ONE-RV64-NEXT: lpad 1 +; FIXED-ONE-RV64-NEXT: sext.w a0, a0 +; FIXED-ONE-RV64-NEXT: slli a0, a0, 3 +; FIXED-ONE-RV64-NEXT: lui a2, %hi(.L__const.indirctbr.addr) +; FIXED-ONE-RV64-NEXT: addi a2, a2, %lo(.L__const.indirctbr.addr) +; FIXED-ONE-RV64-NEXT: add a0, a2, a0 +; FIXED-ONE-RV64-NEXT: ld a0, 0(a0) +; FIXED-ONE-RV64-NEXT: lui t2, 1 +; FIXED-ONE-RV64-NEXT: jr a0 +; FIXED-ONE-RV64-NEXT: .p2align 2 +; FIXED-ONE-RV64-NEXT: .Ltmp3: # Block address taken +; FIXED-ONE-RV64-NEXT: .LBB0_1: # %labelA +; FIXED-ONE-RV64-NEXT: lpad 1 +; FIXED-ONE-RV64-NEXT: li a0, 1 +; FIXED-ONE-RV64-NEXT: sw a0, 0(a1) +; FIXED-ONE-RV64-NEXT: .p2align 2 +; FIXED-ONE-RV64-NEXT: .Ltmp4: # Block address taken +; FIXED-ONE-RV64-NEXT: .LBB0_2: # %labelB +; FIXED-ONE-RV64-NEXT: lpad 1 +; FIXED-ONE-RV64-NEXT: li a0, 2 +; FIXED-ONE-RV64-NEXT: sw a0, 0(a1) +; FIXED-ONE-RV64-NEXT: ret entry: %arrayidx = getelementptr inbounds [2 x ptr], ptr @__const.indirctbr.addr, i64 0, i32 %i %0 = load ptr, ptr %arrayidx @@ -65,12 +118,120 @@ 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: jr a0 +; +; FIXED-ONE-LABEL: call: +; FIXED-ONE: # %bb.0: +; FIXED-ONE-NEXT: lpad 1 +; FIXED-ONE-NEXT: lui t2, 1 +; FIXED-ONE-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: 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: 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 +; +; FIXED-ONE-RV32-LABEL: invoke: +; FIXED-ONE-RV32: # %bb.0: # %entry +; FIXED-ONE-RV32-NEXT: lpad 1 +; FIXED-ONE-RV32-NEXT: addi sp, sp, -16 +; FIXED-ONE-RV32-NEXT: .cfi_def_cfa_offset 16 +; FIXED-ONE-RV32-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; FIXED-ONE-RV32-NEXT: .cfi_offset ra, -4 +; FIXED-ONE-RV32-NEXT: .Ltmp0: +; FIXED-ONE-RV32-NEXT: lui t2, 1 +; FIXED-ONE-RV32-NEXT: jalr a0 +; FIXED-ONE-RV32-NEXT: .Ltmp1: +; FIXED-ONE-RV32-NEXT: .LBB2_1: # %try.cont +; FIXED-ONE-RV32-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; FIXED-ONE-RV32-NEXT: addi sp, sp, 16 +; FIXED-ONE-RV32-NEXT: ret +; FIXED-ONE-RV32-NEXT: .LBB2_2: # %lpad +; FIXED-ONE-RV32-NEXT: .Ltmp2: +; FIXED-ONE-RV32-NEXT: j .LBB2_1 +; +; FIXED-ONE-RV64-LABEL: invoke: +; FIXED-ONE-RV64: # %bb.0: # %entry +; FIXED-ONE-RV64-NEXT: lpad 1 +; FIXED-ONE-RV64-NEXT: addi sp, sp, -16 +; FIXED-ONE-RV64-NEXT: .cfi_def_cfa_offset 16 +; FIXED-ONE-RV64-NEXT: sd ra, 8(sp) # 8-byte Folded Spill +; FIXED-ONE-RV64-NEXT: .cfi_offset ra, -8 +; FIXED-ONE-RV64-NEXT: .Ltmp0: +; FIXED-ONE-RV64-NEXT: lui t2, 1 +; FIXED-ONE-RV64-NEXT: jalr a0 +; FIXED-ONE-RV64-NEXT: .Ltmp1: +; FIXED-ONE-RV64-NEXT: .LBB2_1: # %try.cont +; FIXED-ONE-RV64-NEXT: ld ra, 8(sp) # 8-byte Folded Reload +; FIXED-ONE-RV64-NEXT: addi sp, sp, 16 +; FIXED-ONE-RV64-NEXT: ret +; FIXED-ONE-RV64-NEXT: .LBB2_2: # %lpad +; FIXED-ONE-RV64-NEXT: .Ltmp2: +; FIXED-ONE-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: ; CHECK: # %bb.0: ; CHECK-NEXT: lpad 0 ; CHECK-NEXT: ret +; +; FIXED-ONE-LABEL: external: +; FIXED-ONE: # %bb.0: +; FIXED-ONE-NEXT: lpad 1 +; FIXED-ONE-NEXT: ret ret void } @@ -79,6 +240,10 @@ define internal void @internal() { ; CHECK-LABEL: internal: ; CHECK: # %bb.0: ; CHECK-NEXT: ret +; +; FIXED-ONE-LABEL: internal: +; FIXED-ONE: # %bb.0: +; FIXED-ONE-NEXT: ret ret void } @@ -89,6 +254,11 @@ define internal void @internal2() { ; CHECK: # %bb.0: ; CHECK-NEXT: lpad 0 ; CHECK-NEXT: ret +; +; FIXED-ONE-LABEL: internal2: +; FIXED-ONE: # %bb.0: +; FIXED-ONE-NEXT: lpad 1 +; FIXED-ONE-NEXT: ret ret void } @@ -97,5 +267,9 @@ define void @interrupt() "interrupt"="user" { ; CHECK-LABEL: interrupt: ; CHECK: # %bb.0: ; CHECK-NEXT: mret +; +; FIXED-ONE-LABEL: interrupt: +; FIXED-ONE: # %bb.0: +; FIXED-ONE-NEXT: mret ret void }