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 indirect |
11 | // jump/call instruction. |
12 | // |
13 | //===----------------------------------------------------------------------===// |
14 | |
15 | #include "RISCV.h" |
16 | #include "RISCVInstrInfo.h" |
17 | #include "RISCVSubtarget.h" |
18 | #include "llvm/ADT/Statistic.h" |
19 | #include "llvm/CodeGen/MachineFunctionPass.h" |
20 | #include "llvm/CodeGen/MachineInstrBuilder.h" |
21 | #include "llvm/CodeGen/MachineModuleInfo.h" |
22 | |
23 | #define DEBUG_TYPE "riscv-indrect-branch-tracking" |
24 | #define PASS_NAME "RISC-V Indirect Branch Tracking" |
25 | |
26 | using namespace llvm; |
27 | |
28 | cl::opt<uint32_t> PreferredLandingPadLabel( |
29 | "riscv-landing-pad-label" , cl::ReallyHidden, |
30 | cl::desc("Use preferred fixed label for all labels" )); |
31 | |
32 | namespace { |
33 | class RISCVIndirectBranchTracking : public MachineFunctionPass { |
34 | public: |
35 | static char ID; |
36 | RISCVIndirectBranchTracking() : MachineFunctionPass(ID) {} |
37 | |
38 | StringRef getPassName() const override { return PASS_NAME; } |
39 | |
40 | bool runOnMachineFunction(MachineFunction &MF) override; |
41 | |
42 | private: |
43 | const Align LpadAlign = Align(4); |
44 | }; |
45 | |
46 | } // end anonymous namespace |
47 | |
48 | INITIALIZE_PASS(RISCVIndirectBranchTracking, DEBUG_TYPE, PASS_NAME, false, |
49 | false) |
50 | |
51 | char RISCVIndirectBranchTracking::ID = 0; |
52 | |
53 | FunctionPass *llvm::createRISCVIndirectBranchTrackingPass() { |
54 | return new RISCVIndirectBranchTracking(); |
55 | } |
56 | |
57 | static void emitLpad(MachineBasicBlock &MBB, const RISCVInstrInfo *TII, |
58 | uint32_t Label) { |
59 | auto I = MBB.begin(); |
60 | BuildMI(BB&: MBB, I, MIMD: MBB.findDebugLoc(MBBI: I), MCID: TII->get(Opcode: RISCV::AUIPC), DestReg: RISCV::X0) |
61 | .addImm(Val: Label); |
62 | } |
63 | |
64 | bool RISCVIndirectBranchTracking::runOnMachineFunction(MachineFunction &MF) { |
65 | const auto &Subtarget = MF.getSubtarget<RISCVSubtarget>(); |
66 | const RISCVInstrInfo *TII = Subtarget.getInstrInfo(); |
67 | if (!Subtarget.hasStdExtZicfilp()) |
68 | return false; |
69 | |
70 | uint32_t FixedLabel = 0; |
71 | if (PreferredLandingPadLabel.getNumOccurrences() > 0) { |
72 | if (!isUInt<20>(x: PreferredLandingPadLabel)) |
73 | report_fatal_error(reason: "riscv-landing-pad-label=<val>, <val> needs to fit in " |
74 | "unsigned 20-bits" ); |
75 | FixedLabel = PreferredLandingPadLabel; |
76 | } |
77 | |
78 | bool Changed = false; |
79 | for (MachineBasicBlock &MBB : MF) { |
80 | if (&MBB == &MF.front()) { |
81 | Function &F = MF.getFunction(); |
82 | // When trap is taken, landing pad is not needed. |
83 | if (F.hasFnAttribute(Kind: "interrupt" )) |
84 | continue; |
85 | |
86 | if (F.hasAddressTaken() || !F.hasLocalLinkage()) { |
87 | emitLpad(MBB, TII, Label: FixedLabel); |
88 | if (MF.getAlignment() < LpadAlign) |
89 | MF.setAlignment(LpadAlign); |
90 | Changed = true; |
91 | } |
92 | continue; |
93 | } |
94 | |
95 | if (MBB.hasAddressTaken()) { |
96 | emitLpad(MBB, TII, Label: FixedLabel); |
97 | if (MBB.getAlignment() < LpadAlign) |
98 | MBB.setAlignment(LpadAlign); |
99 | Changed = true; |
100 | } |
101 | } |
102 | |
103 | return Changed; |
104 | } |
105 | |