LLVM 17.0.0git
BPFCheckAndAdjustIR.cpp
Go to the documentation of this file.
1//===------------ BPFCheckAndAdjustIR.cpp - Check and Adjust IR -----------===//
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// Check IR and adjust IR for verifier friendly codes.
10// The following are done for IR checking:
11// - no relocation globals in PHI node.
12// The following are done for IR adjustment:
13// - remove __builtin_bpf_passthrough builtins. Target independent IR
14// optimizations are done and those builtins can be removed.
15//
16//===----------------------------------------------------------------------===//
17
18#include "BPF.h"
19#include "BPFCORE.h"
20#include "BPFTargetMachine.h"
23#include "llvm/IR/Instruction.h"
25#include "llvm/IR/Module.h"
26#include "llvm/IR/Type.h"
27#include "llvm/IR/User.h"
28#include "llvm/IR/Value.h"
29#include "llvm/Pass.h"
31
32#define DEBUG_TYPE "bpf-check-and-opt-ir"
33
34using namespace llvm;
35
36namespace {
37
38class BPFCheckAndAdjustIR final : public ModulePass {
39 bool runOnModule(Module &F) override;
40
41public:
42 static char ID;
43 BPFCheckAndAdjustIR() : ModulePass(ID) {}
44
45private:
46 void checkIR(Module &M);
47 bool adjustIR(Module &M);
48 bool removePassThroughBuiltin(Module &M);
49 bool removeCompareBuiltin(Module &M);
50};
51} // End anonymous namespace
52
53char BPFCheckAndAdjustIR::ID = 0;
54INITIALIZE_PASS(BPFCheckAndAdjustIR, DEBUG_TYPE, "BPF Check And Adjust IR",
55 false, false)
56
58 return new BPFCheckAndAdjustIR();
59}
60
61void BPFCheckAndAdjustIR::checkIR(Module &M) {
62 // Ensure relocation global won't appear in PHI node
63 // This may happen if the compiler generated the following code:
64 // B1:
65 // g1 = @llvm.skb_buff:0:1...
66 // ...
67 // goto B_COMMON
68 // B2:
69 // g2 = @llvm.skb_buff:0:2...
70 // ...
71 // goto B_COMMON
72 // B_COMMON:
73 // g = PHI(g1, g2)
74 // x = load g
75 // ...
76 // If anything likes the above "g = PHI(g1, g2)", issue a fatal error.
77 for (Function &F : M)
78 for (auto &BB : F)
79 for (auto &I : BB) {
80 PHINode *PN = dyn_cast<PHINode>(&I);
81 if (!PN || PN->use_empty())
82 continue;
83 for (int i = 0, e = PN->getNumIncomingValues(); i < e; ++i) {
84 auto *GV = dyn_cast<GlobalVariable>(PN->getIncomingValue(i));
85 if (!GV)
86 continue;
87 if (GV->hasAttribute(BPFCoreSharedInfo::AmaAttr) ||
88 GV->hasAttribute(BPFCoreSharedInfo::TypeIdAttr))
89 report_fatal_error("relocation global in PHI node");
90 }
91 }
92}
93
94bool BPFCheckAndAdjustIR::removePassThroughBuiltin(Module &M) {
95 // Remove __builtin_bpf_passthrough()'s which are used to prevent
96 // certain IR optimizations. Now major IR optimizations are done,
97 // remove them.
98 bool Changed = false;
99 CallInst *ToBeDeleted = nullptr;
100 for (Function &F : M)
101 for (auto &BB : F)
102 for (auto &I : BB) {
103 if (ToBeDeleted) {
104 ToBeDeleted->eraseFromParent();
105 ToBeDeleted = nullptr;
106 }
107
108 auto *Call = dyn_cast<CallInst>(&I);
109 if (!Call)
110 continue;
111 auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand());
112 if (!GV)
113 continue;
114 if (!GV->getName().startswith("llvm.bpf.passthrough"))
115 continue;
116 Changed = true;
117 Value *Arg = Call->getArgOperand(1);
118 Call->replaceAllUsesWith(Arg);
119 ToBeDeleted = Call;
120 }
121 return Changed;
122}
123
124bool BPFCheckAndAdjustIR::removeCompareBuiltin(Module &M) {
125 // Remove __builtin_bpf_compare()'s which are used to prevent
126 // certain IR optimizations. Now major IR optimizations are done,
127 // remove them.
128 bool Changed = false;
129 CallInst *ToBeDeleted = nullptr;
130 for (Function &F : M)
131 for (auto &BB : F)
132 for (auto &I : BB) {
133 if (ToBeDeleted) {
134 ToBeDeleted->eraseFromParent();
135 ToBeDeleted = nullptr;
136 }
137
138 auto *Call = dyn_cast<CallInst>(&I);
139 if (!Call)
140 continue;
141 auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand());
142 if (!GV)
143 continue;
144 if (!GV->getName().startswith("llvm.bpf.compare"))
145 continue;
146
147 Changed = true;
148 Value *Arg0 = Call->getArgOperand(0);
149 Value *Arg1 = Call->getArgOperand(1);
150 Value *Arg2 = Call->getArgOperand(2);
151
152 auto OpVal = cast<ConstantInt>(Arg0)->getValue().getZExtValue();
154
155 auto *ICmp = new ICmpInst(Opcode, Arg1, Arg2);
156 ICmp->insertBefore(Call);
157
158 Call->replaceAllUsesWith(ICmp);
159 ToBeDeleted = Call;
160 }
161 return Changed;
162}
163
164bool BPFCheckAndAdjustIR::adjustIR(Module &M) {
165 bool Changed = removePassThroughBuiltin(M);
166 Changed = removeCompareBuiltin(M) || Changed;
167 return Changed;
168}
169
170bool BPFCheckAndAdjustIR::runOnModule(Module &M) {
171 checkIR(M);
172 return adjustIR(M);
173}
amdgpu Simplify well known AMD library false FunctionCallee Value * Arg
#define DEBUG_TYPE
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
Module.h This file contains the declarations for the Module class.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:38
static constexpr StringRef TypeIdAttr
The attribute attached to globals representing a type id.
Definition: BPFCORE.h:65
static constexpr StringRef AmaAttr
The attribute attached to globals representing a field access.
Definition: BPFCORE.h:63
This class represents a function call, abstracting a target machine's calling convention.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition: InstrTypes.h:711
This instruction compares its operands according to the predicate given to the constructor.
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Definition: Instruction.cpp:82
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition: Pass.h:251
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
unsigned getNumIncomingValues() const
Return the number of incoming edges.
LLVM Value Representation.
Definition: Value.h:74
bool use_empty() const
Definition: Value.h:344
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
ModulePass * createBPFCheckAndAdjustIR()
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:145