[llvm] [RISCV] Insert simple landing pad for taken address labels. (PR #91855)

Yeting Kuo via llvm-commits llvm-commits at lists.llvm.org
Sat May 11 07:23:13 PDT 2024


https://github.com/yetingk updated https://github.com/llvm/llvm-project/pull/91855

>From a7b428f0bbc085595c849803d78fd6e37db18480 Mon Sep 17 00:00:00 2001
From: Yeting Kuo <yeting.kuo at sifive.com>
Date: Tue, 8 Aug 2023 17:29:45 +0800
Subject: [PATCH] [RISCV] Insert simple landing pad for taken address labels.

This patch implements simple landing pad labels [0]. When Zicfilp enabled, this
patch inserts `lpad 0` at the beginning of basic blocks which are possible to be
landed by indirect jumps.
This patch also supports option riscv-landing-pad-label to make users
cpable to set nonzero fixed labels. Using nonzero fixed label force
setting t2 before indirect jumps. It's less portable but more strict than
original implementation.

[0]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/pull/417
---
 llvm/lib/Target/RISCV/CMakeLists.txt          |   1 +
 llvm/lib/Target/RISCV/RISCV.h                 |   3 +
 .../RISCV/RISCVIndirectBranchTracking.cpp     | 102 ++++++++++++++++++
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp  |   1 +
 llvm/test/CodeGen/RISCV/O0-pipeline.ll        |   1 +
 llvm/test/CodeGen/RISCV/O3-pipeline.ll        |   1 +
 llvm/test/CodeGen/RISCV/lpad.ll               | 101 +++++++++++++++++
 7 files changed, 210 insertions(+)
 create mode 100644 llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp
 create mode 100644 llvm/test/CodeGen/RISCV/lpad.ll

diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index 8715403f3839a..5f22a8f30f627 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -37,6 +37,7 @@ add_llvm_target(RISCVCodeGen
   RISCVFoldMasks.cpp
   RISCVFrameLowering.cpp
   RISCVGatherScatterLowering.cpp
+  RISCVIndirectBranchTracking.cpp
   RISCVInsertVSETVLI.cpp
   RISCVInsertReadWriteCSR.cpp
   RISCVInsertWriteVXRM.cpp
diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h
index d405395dcf9ec..919d2b67671b5 100644
--- a/llvm/lib/Target/RISCV/RISCV.h
+++ b/llvm/lib/Target/RISCV/RISCV.h
@@ -31,6 +31,9 @@ void initializeRISCVCodeGenPreparePass(PassRegistry &);
 FunctionPass *createRISCVDeadRegisterDefinitionsPass();
 void initializeRISCVDeadRegisterDefinitionsPass(PassRegistry &);
 
+FunctionPass *createRISCVIndirectBranchTrackingPass();
+void initializeRISCVIndirectBranchTrackingPass(PassRegistry &);
+
 FunctionPass *createRISCVISelDag(RISCVTargetMachine &TM,
                                  CodeGenOptLevel OptLevel);
 
diff --git a/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp b/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp
new file mode 100644
index 0000000000000..8a426748f3c99
--- /dev/null
+++ b/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp
@@ -0,0 +1,102 @@
+//===------ RISCVIndirectBranchTracking.cpp - Enables lpad mechanism ------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// The pass adds LPAD (AUIPC with rs1 = X0) machine instructions at the
+// beginning of each basic block or function that is referenced by an indrect
+// jump/call instruction.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RISCV.h"
+#include "RISCVInstrInfo.h"
+#include "RISCVSubtarget.h"
+#include "RISCVTargetMachine.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+
+using namespace llvm;
+
+static cl::opt<uint32_t> PreferredLandingPadLabel(
+    "riscv-landing-pad-label", cl::ReallyHidden,
+    cl::desc("Use preferred fixed label for all labels"));
+
+namespace {
+class RISCVIndirectBranchTrackingPass : public MachineFunctionPass {
+public:
+  RISCVIndirectBranchTrackingPass() : MachineFunctionPass(ID) {}
+
+  StringRef getPassName() const override {
+    return "RISC-V Indirect Branch Tracking";
+  }
+
+  bool runOnMachineFunction(MachineFunction &MF) override;
+
+private:
+  static char ID;
+  const Align LpadAlign = Align(4);
+};
+
+} // end anonymous namespace
+
+char RISCVIndirectBranchTrackingPass::ID = 0;
+
+FunctionPass *llvm::createRISCVIndirectBranchTrackingPass() {
+  return new RISCVIndirectBranchTrackingPass();
+}
+
+static void emitLpad(MachineBasicBlock &MBB, const RISCVInstrInfo *TII,
+                     uint32_t Label) {
+  auto I = MBB.begin();
+  BuildMI(MBB, I, MBB.findDebugLoc(I), TII->get(RISCV::AUIPC), RISCV::X0)
+      .addImm(Label);
+}
+
+bool RISCVIndirectBranchTrackingPass::runOnMachineFunction(
+    MachineFunction &MF) {
+  const auto &Subtarget = MF.getSubtarget<RISCVSubtarget>();
+  const RISCVInstrInfo *TII = Subtarget.getInstrInfo();
+  if (!Subtarget.hasStdExtZicfilp())
+    return false;
+
+  uint32_t Label = 0;
+  if (PreferredLandingPadLabel.getNumOccurrences() > 0) {
+    if (!isUInt<20>(PreferredLandingPadLabel))
+      report_fatal_error("riscv-landing-pad-label=<val>, <val> needs to fit in "
+                         "unsigned 20-bits");
+    Label = PreferredLandingPadLabel;
+  }
+
+  // When trap is taken, landing pad is not needed.
+  if (MF.getFunction().hasFnAttribute("interrupt"))
+    return false;
+
+  bool Changed = false;
+  for (MachineBasicBlock &MBB : MF) {
+    if (&MBB == &MF.front()) {
+      Function &F = MF.getFunction();
+      if (F.hasAddressTaken() || !F.hasLocalLinkage()) {
+        emitLpad(MBB, TII, Label);
+        if (MF.getAlignment() < LpadAlign)
+          MF.setAlignment(LpadAlign);
+        Changed = true;
+      }
+      continue;
+    }
+
+    if (MBB.hasAddressTaken()) {
+      emitLpad(MBB, TII, Label);
+      if (MBB.getAlignment() < LpadAlign)
+        MBB.setAlignment(LpadAlign);
+      Changed = true;
+    }
+  }
+
+  return Changed;
+}
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 7b2dcadc41917..cac97876d697a 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -511,6 +511,7 @@ void RISCVPassConfig::addPreEmitPass2() {
     // ensuring return instruction is detected correctly.
     addPass(createRISCVPushPopOptimizationPass());
   }
+  addPass(createRISCVIndirectBranchTrackingPass());
   addPass(createRISCVExpandPseudoPass());
 
   // Schedule the expansion of AMOs at the last possible moment, avoiding the
diff --git a/llvm/test/CodeGen/RISCV/O0-pipeline.ll b/llvm/test/CodeGen/RISCV/O0-pipeline.ll
index c4a7f9562534c..46631aa2cc515 100644
--- a/llvm/test/CodeGen/RISCV/O0-pipeline.ll
+++ b/llvm/test/CodeGen/RISCV/O0-pipeline.ll
@@ -73,6 +73,7 @@
 ; CHECK-NEXT:       Lazy Machine Block Frequency Analysis
 ; CHECK-NEXT:       Machine Optimization Remark Emitter
 ; CHECK-NEXT:       Stack Frame Layout Analysis
+; CHECK-NEXT:       RISC-V Indirect Branch Tracking
 ; CHECK-NEXT:       RISC-V pseudo instruction expansion pass
 ; CHECK-NEXT:       RISC-V atomic pseudo instruction expansion pass
 ; CHECK-NEXT:       Unpack machine instruction bundles
diff --git a/llvm/test/CodeGen/RISCV/O3-pipeline.ll b/llvm/test/CodeGen/RISCV/O3-pipeline.ll
index 4a71d3276d263..2832231363953 100644
--- a/llvm/test/CodeGen/RISCV/O3-pipeline.ll
+++ b/llvm/test/CodeGen/RISCV/O3-pipeline.ll
@@ -196,6 +196,7 @@
 ; CHECK-NEXT:       Stack Frame Layout Analysis
 ; CHECK-NEXT:       RISC-V Zcmp move merging pass
 ; CHECK-NEXT:       RISC-V Zcmp Push/Pop optimization pass 
+; CHECK-NEXT:       RISC-V Indirect Branch Tracking
 ; CHECK-NEXT:       RISC-V pseudo instruction expansion pass
 ; CHECK-NEXT:       RISC-V atomic pseudo instruction expansion pass
 ; CHECK-NEXT:       Unpack machine instruction bundles
diff --git a/llvm/test/CodeGen/RISCV/lpad.ll b/llvm/test/CodeGen/RISCV/lpad.ll
new file mode 100644
index 0000000000000..36bdcde4eef48
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/lpad.ll
@@ -0,0 +1,101 @@
+; 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
+
+; Check indirectbr.
+ at __const.indirctbr.addr = private unnamed_addr constant [2 x ptr] [ptr blockaddress(@indirctbr, %labelA), ptr blockaddress(@indirctbr, %labelB)], align 8
+define void @indirctbr(i32 %i, ptr %p) {
+; RV32-LABEL: indirctbr:
+; RV32:       # %bb.0: # %entry
+; RV32-NEXT:    lpad 0
+; RV32-NEXT:    slli a0, a0, 2
+; RV32-NEXT:    lui a2, %hi(.L__const.indirctbr.addr)
+; RV32-NEXT:    addi a2, a2, %lo(.L__const.indirctbr.addr)
+; RV32-NEXT:    add a0, a2, a0
+; RV32-NEXT:    lw a0, 0(a0)
+; RV32-NEXT:    jr a0
+; RV32-NEXT:    .p2align 2
+; RV32-NEXT:  .Ltmp0: # 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:  .LBB0_2: # %labelB
+; RV32-NEXT:    lpad 0
+; RV32-NEXT:    li a0, 2
+; RV32-NEXT:    sw a0, 0(a1)
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: indirctbr:
+; RV64:       # %bb.0: # %entry
+; RV64-NEXT:    lpad 0
+; RV64-NEXT:    lui a2, %hi(.L__const.indirctbr.addr)
+; RV64-NEXT:    addi a2, a2, %lo(.L__const.indirctbr.addr)
+; RV64-NEXT:    sext.w a0, a0
+; RV64-NEXT:    slli a0, a0, 3
+; RV64-NEXT:    add a0, a2, a0
+; RV64-NEXT:    ld a0, 0(a0)
+; RV64-NEXT:    jr a0
+; RV64-NEXT:    .p2align 2
+; RV64-NEXT:  .Ltmp0: # 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:  .LBB0_2: # %labelB
+; RV64-NEXT:    lpad 0
+; RV64-NEXT:    li a0, 2
+; RV64-NEXT:    sw a0, 0(a1)
+; RV64-NEXT:    ret
+entry:
+  %arrayidx = getelementptr inbounds [2 x ptr], ptr @__const.indirctbr.addr, i64 0, i32 %i
+  %0 = load ptr, ptr %arrayidx
+  indirectbr ptr %0, [label %labelA, label %labelB]
+
+labelA:                                           ; preds = %entry
+  store volatile i32 1, ptr %p
+  br label %labelB
+
+labelB:                                           ; preds = %labelA, %entry
+  store volatile i32 2, ptr %p
+  ret void
+}
+
+; Check external linkage function.
+define void @external() {
+; CHECK-LABEL: external:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    lpad 0
+; CHECK-NEXT:    ret
+  ret void
+}
+
+; Check internal linkage function.
+define internal void @internal() {
+; CHECK-LABEL: internal:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    ret
+  ret void
+}
+
+; Check internal linkage function with taken address.
+ at foo = constant ptr @internal2
+define internal void @internal2() {
+; CHECK-LABEL: internal2:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    lpad 0
+; CHECK-NEXT:    ret
+  ret void
+}
+
+; Check interrupt function does not need landing pad.
+define void @interrupt() "interrupt"="user" {
+; CHECK-LABEL: interrupt:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    mret
+  ret void
+}



More information about the llvm-commits mailing list