Skip to content

Commit 64e67cc

Browse files
author
Yeting Kuo
committed
[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]: riscv-non-isa/riscv-elf-psabi-doc#417
1 parent 408a351 commit 64e67cc

File tree

8 files changed

+211
-0
lines changed

8 files changed

+211
-0
lines changed

llvm/lib/Target/RISCV/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ add_llvm_target(RISCVCodeGen
3636
RISCVExpandPseudoInsts.cpp
3737
RISCVFrameLowering.cpp
3838
RISCVGatherScatterLowering.cpp
39+
RISCVIndirectBranchTracking.cpp
3940
RISCVInsertVSETVLI.cpp
4041
RISCVInsertReadWriteCSR.cpp
4142
RISCVInsertWriteVXRM.cpp

llvm/lib/Target/RISCV/RISCV.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ void initializeRISCVCodeGenPreparePass(PassRegistry &);
3131
FunctionPass *createRISCVDeadRegisterDefinitionsPass();
3232
void initializeRISCVDeadRegisterDefinitionsPass(PassRegistry &);
3333

34+
FunctionPass *createRISCVIndirectBranchTrackingPass();
35+
void initializeRISCVIndirectBranchTrackingPass(PassRegistry &);
36+
3437
FunctionPass *createRISCVISelDag(RISCVTargetMachine &TM,
3538
CodeGenOptLevel OptLevel);
3639

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
//===------ RISCVIndirectBranchTracking.cpp - Enables lpad mechanism ------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// The pass adds LPAD (AUIPC with rs1 = X0) machine instructions at the
10+
// beginning of each basic block or function that is referenced by an indrect
11+
// jump/call instruction.
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "RISCV.h"
16+
#include "RISCVInstrInfo.h"
17+
#include "RISCVSubtarget.h"
18+
#include "RISCVTargetMachine.h"
19+
#include "llvm/ADT/Statistic.h"
20+
#include "llvm/CodeGen/MachineFunctionPass.h"
21+
#include "llvm/CodeGen/MachineInstrBuilder.h"
22+
#include "llvm/CodeGen/MachineModuleInfo.h"
23+
24+
using namespace llvm;
25+
26+
static cl::opt<uint32_t> PreferredLandingPadLabel(
27+
"riscv-landing-pad-label", cl::ReallyHidden,
28+
cl::desc("Use preferred fixed label for all labels"));
29+
30+
namespace {
31+
class RISCVIndirectBranchTrackingPass : public MachineFunctionPass {
32+
public:
33+
RISCVIndirectBranchTrackingPass() : MachineFunctionPass(ID) {}
34+
35+
StringRef getPassName() const override {
36+
return "RISC-V Indirect Branch Tracking";
37+
}
38+
39+
bool runOnMachineFunction(MachineFunction &MF) override;
40+
41+
private:
42+
static char ID;
43+
const Align LpadAlign = Align(4);
44+
};
45+
46+
} // end anonymous namespace
47+
48+
char RISCVIndirectBranchTrackingPass::ID = 0;
49+
50+
FunctionPass *llvm::createRISCVIndirectBranchTrackingPass() {
51+
return new RISCVIndirectBranchTrackingPass();
52+
}
53+
54+
static void emitLpad(MachineBasicBlock &MBB, const RISCVInstrInfo *TII,
55+
uint32_t Label) {
56+
auto I = MBB.begin();
57+
BuildMI(MBB, I, MBB.findDebugLoc(I), TII->get(RISCV::AUIPC), RISCV::X0)
58+
.addImm(Label);
59+
}
60+
61+
bool RISCVIndirectBranchTrackingPass::runOnMachineFunction(
62+
MachineFunction &MF) {
63+
const auto &Subtarget = MF.getSubtarget<RISCVSubtarget>();
64+
const RISCVInstrInfo *TII = Subtarget.getInstrInfo();
65+
if (!Subtarget.hasStdExtZicfilp())
66+
return false;
67+
68+
uint32_t FixedLabel = 0;
69+
if (PreferredLandingPadLabel.getNumOccurrences() > 0) {
70+
if (!isUInt<20>(PreferredLandingPadLabel))
71+
report_fatal_error("riscv-landing-pad-label=<val>, <val> needs to fit in "
72+
"unsigned 20-bits");
73+
Label = PreferredLandingPadLabel;
74+
}
75+
76+
bool Changed = false;
77+
for (MachineBasicBlock &MBB : MF) {
78+
if (&MBB == &MF.front()) {
79+
Function &F = MF.getFunction();
80+
// When trap is taken, landing pad is not needed.
81+
if (F.hasFnAttribute("interrupt"))
82+
continue;
83+
84+
if (F.hasAddressTaken() || !F.hasLocalLinkage()) {
85+
emitLpad(MBB, TII, FixedLabel);
86+
if (MF.getAlignment() < LpadAlign)
87+
MF.setAlignment(LpadAlign);
88+
Changed = true;
89+
}
90+
continue;
91+
}
92+
93+
if (MBB.hasAddressTaken()) {
94+
emitLpad(MBB, TII, FixedLabel);
95+
if (MBB.getAlignment() < LpadAlign)
96+
MBB.setAlignment(LpadAlign);
97+
Changed = true;
98+
}
99+
}
100+
101+
return Changed;
102+
}

llvm/lib/Target/RISCV/RISCVTargetMachine.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ void RISCVPassConfig::addPreEmitPass2() {
518518
// ensuring return instruction is detected correctly.
519519
addPass(createRISCVPushPopOptimizationPass());
520520
}
521+
addPass(createRISCVIndirectBranchTrackingPass());
521522
addPass(createRISCVExpandPseudoPass());
522523

523524
// Schedule the expansion of AMOs at the last possible moment, avoiding the

llvm/test/CodeGen/RISCV/O0-pipeline.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
; CHECK-NEXT: Lazy Machine Block Frequency Analysis
7171
; CHECK-NEXT: Machine Optimization Remark Emitter
7272
; CHECK-NEXT: Stack Frame Layout Analysis
73+
; CHECK-NEXT: RISC-V Indirect Branch Tracking
7374
; CHECK-NEXT: RISC-V pseudo instruction expansion pass
7475
; CHECK-NEXT: RISC-V atomic pseudo instruction expansion pass
7576
; CHECK-NEXT: Unpack machine instruction bundles

llvm/test/CodeGen/RISCV/O3-pipeline.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@
196196
; CHECK-NEXT: Stack Frame Layout Analysis
197197
; CHECK-NEXT: RISC-V Zcmp move merging pass
198198
; CHECK-NEXT: RISC-V Zcmp Push/Pop optimization pass
199+
; CHECK-NEXT: RISC-V Indirect Branch Tracking
199200
; CHECK-NEXT: RISC-V pseudo instruction expansion pass
200201
; CHECK-NEXT: RISC-V atomic pseudo instruction expansion pass
201202
; CHECK-NEXT: Unpack machine instruction bundles

llvm/test/CodeGen/RISCV/jumptable-swguarded.ll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
define void @above_threshold(i32 signext %in, ptr %out) nounwind {
99
; CHECK-LABEL: above_threshold:
1010
; CHECK: # %bb.0: # %entry
11+
; CHECK-NEXT: lpad 0
1112
; CHECK-NEXT: addi a0, a0, -1
1213
; CHECK-NEXT: li a2, 5
1314
; CHECK-NEXT: bltu a2, a0, .LBB0_9

llvm/test/CodeGen/RISCV/lpad.ll

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc -mtriple riscv32 -mattr=+experimental-zicfilp < %s | FileCheck %s --check-prefixes=CHECK,RV32
3+
; RUN: llc -mtriple riscv64 -mattr=+experimental-zicfilp < %s | FileCheck %s --check-prefixes=CHECK,RV64
4+
5+
; Check indirectbr.
6+
@__const.indirctbr.addr = private unnamed_addr constant [2 x ptr] [ptr blockaddress(@indirctbr, %labelA), ptr blockaddress(@indirctbr, %labelB)], align 8
7+
define void @indirctbr(i32 %i, ptr %p) {
8+
; RV32-LABEL: indirctbr:
9+
; RV32: # %bb.0: # %entry
10+
; RV32-NEXT: lpad 0
11+
; RV32-NEXT: slli a0, a0, 2
12+
; RV32-NEXT: lui a2, %hi(.L__const.indirctbr.addr)
13+
; RV32-NEXT: addi a2, a2, %lo(.L__const.indirctbr.addr)
14+
; RV32-NEXT: add a0, a2, a0
15+
; RV32-NEXT: lw a0, 0(a0)
16+
; RV32-NEXT: jr a0
17+
; RV32-NEXT: .p2align 2
18+
; RV32-NEXT: .Ltmp0: # Block address taken
19+
; RV32-NEXT: .LBB0_1: # %labelA
20+
; RV32-NEXT: lpad 0
21+
; RV32-NEXT: li a0, 1
22+
; RV32-NEXT: sw a0, 0(a1)
23+
; RV32-NEXT: .p2align 2
24+
; RV32-NEXT: .Ltmp1: # Block address taken
25+
; RV32-NEXT: .LBB0_2: # %labelB
26+
; RV32-NEXT: lpad 0
27+
; RV32-NEXT: li a0, 2
28+
; RV32-NEXT: sw a0, 0(a1)
29+
; RV32-NEXT: ret
30+
;
31+
; RV64-LABEL: indirctbr:
32+
; RV64: # %bb.0: # %entry
33+
; RV64-NEXT: lpad 0
34+
; RV64-NEXT: sext.w a0, a0
35+
; RV64-NEXT: slli a0, a0, 3
36+
; RV64-NEXT: lui a2, %hi(.L__const.indirctbr.addr)
37+
; RV64-NEXT: addi a2, a2, %lo(.L__const.indirctbr.addr)
38+
; RV64-NEXT: add a0, a2, a0
39+
; RV64-NEXT: ld a0, 0(a0)
40+
; RV64-NEXT: jr a0
41+
; RV64-NEXT: .p2align 2
42+
; RV64-NEXT: .Ltmp0: # Block address taken
43+
; RV64-NEXT: .LBB0_1: # %labelA
44+
; RV64-NEXT: lpad 0
45+
; RV64-NEXT: li a0, 1
46+
; RV64-NEXT: sw a0, 0(a1)
47+
; RV64-NEXT: .p2align 2
48+
; RV64-NEXT: .Ltmp1: # Block address taken
49+
; RV64-NEXT: .LBB0_2: # %labelB
50+
; RV64-NEXT: lpad 0
51+
; RV64-NEXT: li a0, 2
52+
; RV64-NEXT: sw a0, 0(a1)
53+
; RV64-NEXT: ret
54+
entry:
55+
%arrayidx = getelementptr inbounds [2 x ptr], ptr @__const.indirctbr.addr, i64 0, i32 %i
56+
%0 = load ptr, ptr %arrayidx
57+
indirectbr ptr %0, [label %labelA, label %labelB]
58+
59+
labelA: ; preds = %entry
60+
store volatile i32 1, ptr %p
61+
br label %labelB
62+
63+
labelB: ; preds = %labelA, %entry
64+
store volatile i32 2, ptr %p
65+
ret void
66+
}
67+
68+
; Check external linkage function.
69+
define void @external() {
70+
; CHECK-LABEL: external:
71+
; CHECK: # %bb.0:
72+
; CHECK-NEXT: lpad 0
73+
; CHECK-NEXT: ret
74+
ret void
75+
}
76+
77+
; Check internal linkage function.
78+
define internal void @internal() {
79+
; CHECK-LABEL: internal:
80+
; CHECK: # %bb.0:
81+
; CHECK-NEXT: ret
82+
ret void
83+
}
84+
85+
; Check internal linkage function with taken address.
86+
@foo = constant ptr @internal2
87+
define internal void @internal2() {
88+
; CHECK-LABEL: internal2:
89+
; CHECK: # %bb.0:
90+
; CHECK-NEXT: lpad 0
91+
; CHECK-NEXT: ret
92+
ret void
93+
}
94+
95+
; Check interrupt function does not need landing pad.
96+
define void @interrupt() "interrupt"="user" {
97+
; CHECK-LABEL: interrupt:
98+
; CHECK: # %bb.0:
99+
; CHECK-NEXT: mret
100+
ret void
101+
}

0 commit comments

Comments
 (0)