1ddf1864aSYonghong Song //===---------------- BPFAdjustOpt.cpp - Adjust Optimization --------------===//
2ddf1864aSYonghong Song //
3ddf1864aSYonghong Song // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ddf1864aSYonghong Song // See https://llvm.org/LICENSE.txt for license information.
5ddf1864aSYonghong Song // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ddf1864aSYonghong Song //
7ddf1864aSYonghong Song //===----------------------------------------------------------------------===//
8ddf1864aSYonghong Song //
9ddf1864aSYonghong Song // Adjust optimization to make the code more kernel verifier friendly.
10ddf1864aSYonghong Song //
11ddf1864aSYonghong Song //===----------------------------------------------------------------------===//
12ddf1864aSYonghong Song 
13ddf1864aSYonghong Song #include "BPF.h"
14ddf1864aSYonghong Song #include "BPFCORE.h"
15ddf1864aSYonghong Song #include "BPFTargetMachine.h"
16ddf1864aSYonghong Song #include "llvm/IR/Instruction.h"
17ddf1864aSYonghong Song #include "llvm/IR/Instructions.h"
18f63405f6SYonghong Song #include "llvm/IR/IntrinsicsBPF.h"
19ddf1864aSYonghong Song #include "llvm/IR/Module.h"
20e4d751c2SJuneyoung Lee #include "llvm/IR/PatternMatch.h"
21ddf1864aSYonghong Song #include "llvm/IR/Type.h"
22ddf1864aSYonghong Song #include "llvm/IR/User.h"
23ddf1864aSYonghong Song #include "llvm/IR/Value.h"
24ddf1864aSYonghong Song #include "llvm/Pass.h"
25ddf1864aSYonghong Song #include "llvm/Transforms/Utils/BasicBlockUtils.h"
26ddf1864aSYonghong Song 
27ddf1864aSYonghong Song #define DEBUG_TYPE "bpf-adjust-opt"
28ddf1864aSYonghong Song 
29ddf1864aSYonghong Song using namespace llvm;
30e4d751c2SJuneyoung Lee using namespace llvm::PatternMatch;
31ddf1864aSYonghong Song 
32ddf1864aSYonghong Song static cl::opt<bool>
33ddf1864aSYonghong Song     DisableBPFserializeICMP("bpf-disable-serialize-icmp", cl::Hidden,
34ddf1864aSYonghong Song                             cl::desc("BPF: Disable Serializing ICMP insns."),
35ddf1864aSYonghong Song                             cl::init(false));
36ddf1864aSYonghong Song 
37ddf1864aSYonghong Song static cl::opt<bool> DisableBPFavoidSpeculation(
38ddf1864aSYonghong Song     "bpf-disable-avoid-speculation", cl::Hidden,
39ddf1864aSYonghong Song     cl::desc("BPF: Disable Avoiding Speculative Code Motion."),
40ddf1864aSYonghong Song     cl::init(false));
41ddf1864aSYonghong Song 
42ddf1864aSYonghong Song namespace {
43ddf1864aSYonghong Song 
44ddf1864aSYonghong Song class BPFAdjustOpt final : public ModulePass {
4592a67e13SArthur Eubanks public:
4692a67e13SArthur Eubanks   static char ID;
4792a67e13SArthur Eubanks 
BPFAdjustOpt()4892a67e13SArthur Eubanks   BPFAdjustOpt() : ModulePass(ID) {}
4992a67e13SArthur Eubanks   bool runOnModule(Module &M) override;
5092a67e13SArthur Eubanks };
5192a67e13SArthur Eubanks 
5292a67e13SArthur Eubanks class BPFAdjustOptImpl {
53ddf1864aSYonghong Song   struct PassThroughInfo {
54ddf1864aSYonghong Song     Instruction *Input;
55ddf1864aSYonghong Song     Instruction *UsedInst;
56ddf1864aSYonghong Song     uint32_t OpIdx;
PassThroughInfo__anon822520330111::BPFAdjustOptImpl::PassThroughInfo57ddf1864aSYonghong Song     PassThroughInfo(Instruction *I, Instruction *U, uint32_t Idx)
58ddf1864aSYonghong Song         : Input(I), UsedInst(U), OpIdx(Idx) {}
59ddf1864aSYonghong Song   };
60ddf1864aSYonghong Song 
61ddf1864aSYonghong Song public:
BPFAdjustOptImpl(Module * M)6292a67e13SArthur Eubanks   BPFAdjustOptImpl(Module *M) : M(M) {}
63ddf1864aSYonghong Song 
6492a67e13SArthur Eubanks   bool run();
65ddf1864aSYonghong Song 
66ddf1864aSYonghong Song private:
6792a67e13SArthur Eubanks   Module *M;
68ddf1864aSYonghong Song   SmallVector<PassThroughInfo, 16> PassThroughs;
69ddf1864aSYonghong Song 
70f63405f6SYonghong Song   bool adjustICmpToBuiltin();
71ddf1864aSYonghong Song   void adjustBasicBlock(BasicBlock &BB);
72ddf1864aSYonghong Song   bool serializeICMPCrossBB(BasicBlock &BB);
73ddf1864aSYonghong Song   void adjustInst(Instruction &I);
74ddf1864aSYonghong Song   bool serializeICMPInBB(Instruction &I);
75ddf1864aSYonghong Song   bool avoidSpeculation(Instruction &I);
76ddf1864aSYonghong Song   bool insertPassThrough();
77ddf1864aSYonghong Song };
78ddf1864aSYonghong Song 
79ddf1864aSYonghong Song } // End anonymous namespace
80ddf1864aSYonghong Song 
81ddf1864aSYonghong Song char BPFAdjustOpt::ID = 0;
82ddf1864aSYonghong Song INITIALIZE_PASS(BPFAdjustOpt, "bpf-adjust-opt", "BPF Adjust Optimization",
83ddf1864aSYonghong Song                 false, false)
84ddf1864aSYonghong Song 
createBPFAdjustOpt()85ddf1864aSYonghong Song ModulePass *llvm::createBPFAdjustOpt() { return new BPFAdjustOpt(); }
86ddf1864aSYonghong Song 
runOnModule(Module & M)8792a67e13SArthur Eubanks bool BPFAdjustOpt::runOnModule(Module &M) { return BPFAdjustOptImpl(&M).run(); }
8892a67e13SArthur Eubanks 
run()8992a67e13SArthur Eubanks bool BPFAdjustOptImpl::run() {
90f63405f6SYonghong Song   bool Changed = adjustICmpToBuiltin();
91f63405f6SYonghong Song 
9292a67e13SArthur Eubanks   for (Function &F : *M)
93ddf1864aSYonghong Song     for (auto &BB : F) {
94ddf1864aSYonghong Song       adjustBasicBlock(BB);
95ddf1864aSYonghong Song       for (auto &I : BB)
96ddf1864aSYonghong Song         adjustInst(I);
97ddf1864aSYonghong Song     }
98f63405f6SYonghong Song   return insertPassThrough() || Changed;
99f63405f6SYonghong Song }
100ddf1864aSYonghong Song 
101f63405f6SYonghong Song // Commit acabad9ff6bf ("[InstCombine] try to canonicalize icmp with
102f63405f6SYonghong Song // trunc op into mask and cmp") added a transformation to
103f63405f6SYonghong Song // convert "(conv)a < power_2_const" to "a & <const>" in certain
104f63405f6SYonghong Song // cases and bpf kernel verifier has to handle the resulted code
105f63405f6SYonghong Song // conservatively and this may reject otherwise legitimate program.
106f63405f6SYonghong Song // Here, we change related icmp code to a builtin which will
107f63405f6SYonghong Song // be restored to original icmp code later to prevent that
108f63405f6SYonghong Song // InstCombine transformatin.
adjustICmpToBuiltin()109f63405f6SYonghong Song bool BPFAdjustOptImpl::adjustICmpToBuiltin() {
110f63405f6SYonghong Song   bool Changed = false;
111f63405f6SYonghong Song   ICmpInst *ToBeDeleted = nullptr;
112f63405f6SYonghong Song   for (Function &F : *M)
113f63405f6SYonghong Song     for (auto &BB : F)
114f63405f6SYonghong Song       for (auto &I : BB) {
115f63405f6SYonghong Song         if (ToBeDeleted) {
116f63405f6SYonghong Song           ToBeDeleted->eraseFromParent();
117f63405f6SYonghong Song           ToBeDeleted = nullptr;
118f63405f6SYonghong Song         }
119f63405f6SYonghong Song 
120f63405f6SYonghong Song         auto *Icmp = dyn_cast<ICmpInst>(&I);
121f63405f6SYonghong Song         if (!Icmp)
122f63405f6SYonghong Song           continue;
123f63405f6SYonghong Song 
124f63405f6SYonghong Song         Value *Op0 = Icmp->getOperand(0);
125f63405f6SYonghong Song         if (!isa<TruncInst>(Op0))
126f63405f6SYonghong Song           continue;
127f63405f6SYonghong Song 
128f63405f6SYonghong Song         auto ConstOp1 = dyn_cast<ConstantInt>(Icmp->getOperand(1));
129f63405f6SYonghong Song         if (!ConstOp1)
130f63405f6SYonghong Song           continue;
131f63405f6SYonghong Song 
132f63405f6SYonghong Song         auto ConstOp1Val = ConstOp1->getValue().getZExtValue();
133f63405f6SYonghong Song         auto Op = Icmp->getPredicate();
1348fb3f844SYonghong Song         if (Op == ICmpInst::ICMP_ULT || Op == ICmpInst::ICMP_UGE) {
135f63405f6SYonghong Song           if ((ConstOp1Val - 1) & ConstOp1Val)
136f63405f6SYonghong Song             continue;
1378fb3f844SYonghong Song         } else if (Op == ICmpInst::ICMP_ULE || Op == ICmpInst::ICMP_UGT) {
138f63405f6SYonghong Song           if (ConstOp1Val & (ConstOp1Val + 1))
139f63405f6SYonghong Song             continue;
140f63405f6SYonghong Song         } else {
141f63405f6SYonghong Song           continue;
142f63405f6SYonghong Song         }
143f63405f6SYonghong Song 
144f63405f6SYonghong Song         Constant *Opcode =
145f63405f6SYonghong Song             ConstantInt::get(Type::getInt32Ty(BB.getContext()), Op);
146f63405f6SYonghong Song         Function *Fn = Intrinsic::getDeclaration(
147f63405f6SYonghong Song             M, Intrinsic::bpf_compare, {Op0->getType(), ConstOp1->getType()});
148f63405f6SYonghong Song         auto *NewInst = CallInst::Create(Fn, {Opcode, Op0, ConstOp1});
149f63405f6SYonghong Song         BB.getInstList().insert(I.getIterator(), NewInst);
150f63405f6SYonghong Song         Icmp->replaceAllUsesWith(NewInst);
151f63405f6SYonghong Song         Changed = true;
152f63405f6SYonghong Song         ToBeDeleted = Icmp;
153f63405f6SYonghong Song       }
154f63405f6SYonghong Song 
155f63405f6SYonghong Song   return Changed;
156ddf1864aSYonghong Song }
157ddf1864aSYonghong Song 
insertPassThrough()15892a67e13SArthur Eubanks bool BPFAdjustOptImpl::insertPassThrough() {
159ddf1864aSYonghong Song   for (auto &Info : PassThroughs) {
160ddf1864aSYonghong Song     auto *CI = BPFCoreSharedInfo::insertPassThrough(
16192a67e13SArthur Eubanks         M, Info.UsedInst->getParent(), Info.Input, Info.UsedInst);
162ddf1864aSYonghong Song     Info.UsedInst->setOperand(Info.OpIdx, CI);
163ddf1864aSYonghong Song   }
164ddf1864aSYonghong Song 
165ddf1864aSYonghong Song   return !PassThroughs.empty();
166ddf1864aSYonghong Song }
167ddf1864aSYonghong Song 
168ddf1864aSYonghong Song // To avoid combining conditionals in the same basic block by
169ddf1864aSYonghong Song // instrcombine optimization.
serializeICMPInBB(Instruction & I)17092a67e13SArthur Eubanks bool BPFAdjustOptImpl::serializeICMPInBB(Instruction &I) {
171ddf1864aSYonghong Song   // For:
172ddf1864aSYonghong Song   //   comp1 = icmp <opcode> ...;
173ddf1864aSYonghong Song   //   comp2 = icmp <opcode> ...;
174ddf1864aSYonghong Song   //   ... or comp1 comp2 ...
175ddf1864aSYonghong Song   // changed to:
176ddf1864aSYonghong Song   //   comp1 = icmp <opcode> ...;
177ddf1864aSYonghong Song   //   comp2 = icmp <opcode> ...;
178ddf1864aSYonghong Song   //   new_comp1 = __builtin_bpf_passthrough(seq_num, comp1)
179ddf1864aSYonghong Song   //   ... or new_comp1 comp2 ...
180e4d751c2SJuneyoung Lee   Value *Op0, *Op1;
181e4d751c2SJuneyoung Lee   // Use LogicalOr (accept `or i1` as well as `select i1 Op0, true, Op1`)
182e4d751c2SJuneyoung Lee   if (!match(&I, m_LogicalOr(m_Value(Op0), m_Value(Op1))))
183ddf1864aSYonghong Song     return false;
184e4d751c2SJuneyoung Lee   auto *Icmp1 = dyn_cast<ICmpInst>(Op0);
185ddf1864aSYonghong Song   if (!Icmp1)
186ddf1864aSYonghong Song     return false;
187e4d751c2SJuneyoung Lee   auto *Icmp2 = dyn_cast<ICmpInst>(Op1);
188ddf1864aSYonghong Song   if (!Icmp2)
189ddf1864aSYonghong Song     return false;
190ddf1864aSYonghong Song 
191ddf1864aSYonghong Song   Value *Icmp1Op0 = Icmp1->getOperand(0);
192ddf1864aSYonghong Song   Value *Icmp2Op0 = Icmp2->getOperand(0);
193ddf1864aSYonghong Song   if (Icmp1Op0 != Icmp2Op0)
194ddf1864aSYonghong Song     return false;
195ddf1864aSYonghong Song 
196ddf1864aSYonghong Song   // Now we got two icmp instructions which feed into
197ddf1864aSYonghong Song   // an "or" instruction.
198ddf1864aSYonghong Song   PassThroughInfo Info(Icmp1, &I, 0);
199ddf1864aSYonghong Song   PassThroughs.push_back(Info);
200ddf1864aSYonghong Song   return true;
201ddf1864aSYonghong Song }
202ddf1864aSYonghong Song 
203ddf1864aSYonghong Song // To avoid combining conditionals in the same basic block by
204ddf1864aSYonghong Song // instrcombine optimization.
serializeICMPCrossBB(BasicBlock & BB)20592a67e13SArthur Eubanks bool BPFAdjustOptImpl::serializeICMPCrossBB(BasicBlock &BB) {
206ddf1864aSYonghong Song   // For:
207ddf1864aSYonghong Song   //   B1:
208ddf1864aSYonghong Song   //     comp1 = icmp <opcode> ...;
209ddf1864aSYonghong Song   //     if (comp1) goto B2 else B3;
210ddf1864aSYonghong Song   //   B2:
211ddf1864aSYonghong Song   //     comp2 = icmp <opcode> ...;
212ddf1864aSYonghong Song   //     if (comp2) goto B4 else B5;
213ddf1864aSYonghong Song   //   B4:
214ddf1864aSYonghong Song   //     ...
215ddf1864aSYonghong Song   // changed to:
216ddf1864aSYonghong Song   //   B1:
217ddf1864aSYonghong Song   //     comp1 = icmp <opcode> ...;
218ddf1864aSYonghong Song   //     comp1 = __builtin_bpf_passthrough(seq_num, comp1);
219ddf1864aSYonghong Song   //     if (comp1) goto B2 else B3;
220ddf1864aSYonghong Song   //   B2:
221ddf1864aSYonghong Song   //     comp2 = icmp <opcode> ...;
222ddf1864aSYonghong Song   //     if (comp2) goto B4 else B5;
223ddf1864aSYonghong Song   //   B4:
224ddf1864aSYonghong Song   //     ...
225ddf1864aSYonghong Song 
226ddf1864aSYonghong Song   // Check basic predecessors, if two of them (say B1, B2) are using
227ddf1864aSYonghong Song   // icmp instructions to generate conditions and one is the predesessor
228ddf1864aSYonghong Song   // of another (e.g., B1 is the predecessor of B2). Add a passthrough
229ddf1864aSYonghong Song   // barrier after icmp inst of block B1.
230ddf1864aSYonghong Song   BasicBlock *B2 = BB.getSinglePredecessor();
231ddf1864aSYonghong Song   if (!B2)
232ddf1864aSYonghong Song     return false;
233ddf1864aSYonghong Song 
234ddf1864aSYonghong Song   BasicBlock *B1 = B2->getSinglePredecessor();
235ddf1864aSYonghong Song   if (!B1)
236ddf1864aSYonghong Song     return false;
237ddf1864aSYonghong Song 
238ddf1864aSYonghong Song   Instruction *TI = B2->getTerminator();
239ddf1864aSYonghong Song   auto *BI = dyn_cast<BranchInst>(TI);
240ddf1864aSYonghong Song   if (!BI || !BI->isConditional())
241ddf1864aSYonghong Song     return false;
242ddf1864aSYonghong Song   auto *Cond = dyn_cast<ICmpInst>(BI->getCondition());
243ddf1864aSYonghong Song   if (!Cond || B2->getFirstNonPHI() != Cond)
244ddf1864aSYonghong Song     return false;
245ddf1864aSYonghong Song   Value *B2Op0 = Cond->getOperand(0);
246ddf1864aSYonghong Song   auto Cond2Op = Cond->getPredicate();
247ddf1864aSYonghong Song 
248ddf1864aSYonghong Song   TI = B1->getTerminator();
249ddf1864aSYonghong Song   BI = dyn_cast<BranchInst>(TI);
250ddf1864aSYonghong Song   if (!BI || !BI->isConditional())
251ddf1864aSYonghong Song     return false;
252ddf1864aSYonghong Song   Cond = dyn_cast<ICmpInst>(BI->getCondition());
253ddf1864aSYonghong Song   if (!Cond)
254ddf1864aSYonghong Song     return false;
255ddf1864aSYonghong Song   Value *B1Op0 = Cond->getOperand(0);
256ddf1864aSYonghong Song   auto Cond1Op = Cond->getPredicate();
257ddf1864aSYonghong Song 
258ddf1864aSYonghong Song   if (B1Op0 != B2Op0)
259ddf1864aSYonghong Song     return false;
260ddf1864aSYonghong Song 
261ddf1864aSYonghong Song   if (Cond1Op == ICmpInst::ICMP_SGT || Cond1Op == ICmpInst::ICMP_SGE) {
262d2b4a675SYonghong Song     if (Cond2Op != ICmpInst::ICMP_SLT && Cond2Op != ICmpInst::ICMP_SLE)
263ddf1864aSYonghong Song       return false;
264ddf1864aSYonghong Song   } else if (Cond1Op == ICmpInst::ICMP_SLT || Cond1Op == ICmpInst::ICMP_SLE) {
265d2b4a675SYonghong Song     if (Cond2Op != ICmpInst::ICMP_SGT && Cond2Op != ICmpInst::ICMP_SGE)
266ddf1864aSYonghong Song       return false;
267*2e94d8e6SYonghong Song   } else if (Cond1Op == ICmpInst::ICMP_ULT || Cond1Op == ICmpInst::ICMP_ULE) {
268*2e94d8e6SYonghong Song     if (Cond2Op != ICmpInst::ICMP_UGT && Cond2Op != ICmpInst::ICMP_UGE)
269*2e94d8e6SYonghong Song       return false;
270*2e94d8e6SYonghong Song   } else if (Cond1Op == ICmpInst::ICMP_UGT || Cond1Op == ICmpInst::ICMP_UGE) {
271*2e94d8e6SYonghong Song     if (Cond2Op != ICmpInst::ICMP_ULT && Cond2Op != ICmpInst::ICMP_ULE)
272*2e94d8e6SYonghong Song       return false;
273ddf1864aSYonghong Song   } else {
274ddf1864aSYonghong Song     return false;
275ddf1864aSYonghong Song   }
276ddf1864aSYonghong Song 
277ddf1864aSYonghong Song   PassThroughInfo Info(Cond, BI, 0);
278ddf1864aSYonghong Song   PassThroughs.push_back(Info);
279ddf1864aSYonghong Song 
280ddf1864aSYonghong Song   return true;
281ddf1864aSYonghong Song }
282ddf1864aSYonghong Song 
283ddf1864aSYonghong Song // To avoid speculative hoisting certain computations out of
284ddf1864aSYonghong Song // a basic block.
avoidSpeculation(Instruction & I)28592a67e13SArthur Eubanks bool BPFAdjustOptImpl::avoidSpeculation(Instruction &I) {
286ddf1864aSYonghong Song   if (auto *LdInst = dyn_cast<LoadInst>(&I)) {
287ddf1864aSYonghong Song     if (auto *GV = dyn_cast<GlobalVariable>(LdInst->getOperand(0))) {
288ddf1864aSYonghong Song       if (GV->hasAttribute(BPFCoreSharedInfo::AmaAttr) ||
289ddf1864aSYonghong Song           GV->hasAttribute(BPFCoreSharedInfo::TypeIdAttr))
290ddf1864aSYonghong Song         return false;
291ddf1864aSYonghong Song     }
292ddf1864aSYonghong Song   }
293ddf1864aSYonghong Song 
294b557c32aSKazu Hirata   if (!isa<LoadInst>(&I) && !isa<CallInst>(&I))
295ddf1864aSYonghong Song     return false;
296ddf1864aSYonghong Song 
297ddf1864aSYonghong Song   // For:
298ddf1864aSYonghong Song   //   B1:
299ddf1864aSYonghong Song   //     var = ...
300ddf1864aSYonghong Song   //     ...
301ddf1864aSYonghong Song   //     /* icmp may not be in the same block as var = ... */
302ddf1864aSYonghong Song   //     comp1 = icmp <opcode> var, <const>;
303ddf1864aSYonghong Song   //     if (comp1) goto B2 else B3;
304ddf1864aSYonghong Song   //   B2:
305ddf1864aSYonghong Song   //     ... var ...
306ddf1864aSYonghong Song   // change to:
307ddf1864aSYonghong Song   //   B1:
308ddf1864aSYonghong Song   //     var = ...
309ddf1864aSYonghong Song   //     ...
310ddf1864aSYonghong Song   //     /* icmp may not be in the same block as var = ... */
311ddf1864aSYonghong Song   //     comp1 = icmp <opcode> var, <const>;
312ddf1864aSYonghong Song   //     if (comp1) goto B2 else B3;
313ddf1864aSYonghong Song   //   B2:
314ddf1864aSYonghong Song   //     var = __builtin_bpf_passthrough(seq_num, var);
315ddf1864aSYonghong Song   //     ... var ...
316ddf1864aSYonghong Song   bool isCandidate = false;
317ddf1864aSYonghong Song   SmallVector<PassThroughInfo, 4> Candidates;
318ddf1864aSYonghong Song   for (User *U : I.users()) {
319ddf1864aSYonghong Song     Instruction *Inst = dyn_cast<Instruction>(U);
320ddf1864aSYonghong Song     if (!Inst)
321ddf1864aSYonghong Song       continue;
322ddf1864aSYonghong Song 
323ddf1864aSYonghong Song     // May cover a little bit more than the
324ddf1864aSYonghong Song     // above pattern.
325ddf1864aSYonghong Song     if (auto *Icmp1 = dyn_cast<ICmpInst>(Inst)) {
326ddf1864aSYonghong Song       Value *Icmp1Op1 = Icmp1->getOperand(1);
327ddf1864aSYonghong Song       if (!isa<Constant>(Icmp1Op1))
328ddf1864aSYonghong Song         return false;
329ddf1864aSYonghong Song       isCandidate = true;
330ddf1864aSYonghong Song       continue;
331ddf1864aSYonghong Song     }
332ddf1864aSYonghong Song 
333ddf1864aSYonghong Song     // Ignore the use in the same basic block as the definition.
334ddf1864aSYonghong Song     if (Inst->getParent() == I.getParent())
335ddf1864aSYonghong Song       continue;
336ddf1864aSYonghong Song 
337ddf1864aSYonghong Song     // use in a different basic block, If there is a call or
338ddf1864aSYonghong Song     // load/store insn before this instruction in this basic
339ddf1864aSYonghong Song     // block. Most likely it cannot be hoisted out. Skip it.
340ddf1864aSYonghong Song     for (auto &I2 : *Inst->getParent()) {
3418ed16361SKazu Hirata       if (isa<CallInst>(&I2))
342ddf1864aSYonghong Song         return false;
3438ed16361SKazu Hirata       if (isa<LoadInst>(&I2) || isa<StoreInst>(&I2))
344ddf1864aSYonghong Song         return false;
345ddf1864aSYonghong Song       if (&I2 == Inst)
346ddf1864aSYonghong Song         break;
347ddf1864aSYonghong Song     }
348ddf1864aSYonghong Song 
349ddf1864aSYonghong Song     // It should be used in a GEP or a simple arithmetic like
350ddf1864aSYonghong Song     // ZEXT/SEXT which is used for GEP.
351ddf1864aSYonghong Song     if (Inst->getOpcode() == Instruction::ZExt ||
352ddf1864aSYonghong Song         Inst->getOpcode() == Instruction::SExt) {
353ddf1864aSYonghong Song       PassThroughInfo Info(&I, Inst, 0);
354ddf1864aSYonghong Song       Candidates.push_back(Info);
355ddf1864aSYonghong Song     } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
356ddf1864aSYonghong Song       // traverse GEP inst to find Use operand index
357ddf1864aSYonghong Song       unsigned i, e;
358ddf1864aSYonghong Song       for (i = 1, e = GI->getNumOperands(); i != e; ++i) {
359ddf1864aSYonghong Song         Value *V = GI->getOperand(i);
360ddf1864aSYonghong Song         if (V == &I)
361ddf1864aSYonghong Song           break;
362ddf1864aSYonghong Song       }
363ddf1864aSYonghong Song       if (i == e)
364ddf1864aSYonghong Song         continue;
365ddf1864aSYonghong Song 
366ddf1864aSYonghong Song       PassThroughInfo Info(&I, GI, i);
367ddf1864aSYonghong Song       Candidates.push_back(Info);
368ddf1864aSYonghong Song     }
369ddf1864aSYonghong Song   }
370ddf1864aSYonghong Song 
371ddf1864aSYonghong Song   if (!isCandidate || Candidates.empty())
372ddf1864aSYonghong Song     return false;
373ddf1864aSYonghong Song 
374985f899bSKazu Hirata   llvm::append_range(PassThroughs, Candidates);
375ddf1864aSYonghong Song   return true;
376ddf1864aSYonghong Song }
377ddf1864aSYonghong Song 
adjustBasicBlock(BasicBlock & BB)37892a67e13SArthur Eubanks void BPFAdjustOptImpl::adjustBasicBlock(BasicBlock &BB) {
379ddf1864aSYonghong Song   if (!DisableBPFserializeICMP && serializeICMPCrossBB(BB))
380ddf1864aSYonghong Song     return;
381ddf1864aSYonghong Song }
382ddf1864aSYonghong Song 
adjustInst(Instruction & I)38392a67e13SArthur Eubanks void BPFAdjustOptImpl::adjustInst(Instruction &I) {
384ddf1864aSYonghong Song   if (!DisableBPFserializeICMP && serializeICMPInBB(I))
385ddf1864aSYonghong Song     return;
386ddf1864aSYonghong Song   if (!DisableBPFavoidSpeculation && avoidSpeculation(I))
387ddf1864aSYonghong Song     return;
388ddf1864aSYonghong Song }
38992a67e13SArthur Eubanks 
run(Module & M,ModuleAnalysisManager & AM)39092a67e13SArthur Eubanks PreservedAnalyses BPFAdjustOptPass::run(Module &M, ModuleAnalysisManager &AM) {
39192a67e13SArthur Eubanks   return BPFAdjustOptImpl(&M).run() ? PreservedAnalyses::none()
39292a67e13SArthur Eubanks                                     : PreservedAnalyses::all();
39392a67e13SArthur Eubanks }
394