xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/BPF/BPFAdjustOpt.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1e8d8bef9SDimitry Andric //===---------------- BPFAdjustOpt.cpp - Adjust Optimization --------------===//
2e8d8bef9SDimitry Andric //
3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e8d8bef9SDimitry Andric //
7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
8e8d8bef9SDimitry Andric //
9e8d8bef9SDimitry Andric // Adjust optimization to make the code more kernel verifier friendly.
10e8d8bef9SDimitry Andric //
11e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===//
12e8d8bef9SDimitry Andric 
13e8d8bef9SDimitry Andric #include "BPF.h"
14e8d8bef9SDimitry Andric #include "BPFCORE.h"
15e8d8bef9SDimitry Andric #include "BPFTargetMachine.h"
16e8d8bef9SDimitry Andric #include "llvm/IR/Instruction.h"
17e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h"
18349cc55cSDimitry Andric #include "llvm/IR/IntrinsicsBPF.h"
19e8d8bef9SDimitry Andric #include "llvm/IR/Module.h"
20fe6060f1SDimitry Andric #include "llvm/IR/PatternMatch.h"
21e8d8bef9SDimitry Andric #include "llvm/IR/Type.h"
22e8d8bef9SDimitry Andric #include "llvm/IR/User.h"
23e8d8bef9SDimitry Andric #include "llvm/IR/Value.h"
24e8d8bef9SDimitry Andric #include "llvm/Pass.h"
25e8d8bef9SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h"
26e8d8bef9SDimitry Andric 
27e8d8bef9SDimitry Andric #define DEBUG_TYPE "bpf-adjust-opt"
28e8d8bef9SDimitry Andric 
29e8d8bef9SDimitry Andric using namespace llvm;
30fe6060f1SDimitry Andric using namespace llvm::PatternMatch;
31e8d8bef9SDimitry Andric 
32e8d8bef9SDimitry Andric static cl::opt<bool>
33e8d8bef9SDimitry Andric     DisableBPFserializeICMP("bpf-disable-serialize-icmp", cl::Hidden,
34e8d8bef9SDimitry Andric                             cl::desc("BPF: Disable Serializing ICMP insns."),
35e8d8bef9SDimitry Andric                             cl::init(false));
36e8d8bef9SDimitry Andric 
37e8d8bef9SDimitry Andric static cl::opt<bool> DisableBPFavoidSpeculation(
38e8d8bef9SDimitry Andric     "bpf-disable-avoid-speculation", cl::Hidden,
39e8d8bef9SDimitry Andric     cl::desc("BPF: Disable Avoiding Speculative Code Motion."),
40e8d8bef9SDimitry Andric     cl::init(false));
41e8d8bef9SDimitry Andric 
42e8d8bef9SDimitry Andric namespace {
43e8d8bef9SDimitry Andric 
44e8d8bef9SDimitry Andric class BPFAdjustOpt final : public ModulePass {
45e8d8bef9SDimitry Andric public:
46e8d8bef9SDimitry Andric   static char ID;
47e8d8bef9SDimitry Andric 
48e8d8bef9SDimitry Andric   BPFAdjustOpt() : ModulePass(ID) {}
49e8d8bef9SDimitry Andric   bool runOnModule(Module &M) override;
50e8d8bef9SDimitry Andric };
51e8d8bef9SDimitry Andric 
52e8d8bef9SDimitry Andric class BPFAdjustOptImpl {
53e8d8bef9SDimitry Andric   struct PassThroughInfo {
54e8d8bef9SDimitry Andric     Instruction *Input;
55e8d8bef9SDimitry Andric     Instruction *UsedInst;
56e8d8bef9SDimitry Andric     uint32_t OpIdx;
57e8d8bef9SDimitry Andric     PassThroughInfo(Instruction *I, Instruction *U, uint32_t Idx)
58e8d8bef9SDimitry Andric         : Input(I), UsedInst(U), OpIdx(Idx) {}
59e8d8bef9SDimitry Andric   };
60e8d8bef9SDimitry Andric 
61e8d8bef9SDimitry Andric public:
62e8d8bef9SDimitry Andric   BPFAdjustOptImpl(Module *M) : M(M) {}
63e8d8bef9SDimitry Andric 
64e8d8bef9SDimitry Andric   bool run();
65e8d8bef9SDimitry Andric 
66e8d8bef9SDimitry Andric private:
67e8d8bef9SDimitry Andric   Module *M;
68e8d8bef9SDimitry Andric   SmallVector<PassThroughInfo, 16> PassThroughs;
69e8d8bef9SDimitry Andric 
70349cc55cSDimitry Andric   bool adjustICmpToBuiltin();
71e8d8bef9SDimitry Andric   void adjustBasicBlock(BasicBlock &BB);
72e8d8bef9SDimitry Andric   bool serializeICMPCrossBB(BasicBlock &BB);
73e8d8bef9SDimitry Andric   void adjustInst(Instruction &I);
74e8d8bef9SDimitry Andric   bool serializeICMPInBB(Instruction &I);
75e8d8bef9SDimitry Andric   bool avoidSpeculation(Instruction &I);
76e8d8bef9SDimitry Andric   bool insertPassThrough();
77e8d8bef9SDimitry Andric };
78e8d8bef9SDimitry Andric 
79e8d8bef9SDimitry Andric } // End anonymous namespace
80e8d8bef9SDimitry Andric 
81e8d8bef9SDimitry Andric char BPFAdjustOpt::ID = 0;
82e8d8bef9SDimitry Andric INITIALIZE_PASS(BPFAdjustOpt, "bpf-adjust-opt", "BPF Adjust Optimization",
83e8d8bef9SDimitry Andric                 false, false)
84e8d8bef9SDimitry Andric 
85e8d8bef9SDimitry Andric ModulePass *llvm::createBPFAdjustOpt() { return new BPFAdjustOpt(); }
86e8d8bef9SDimitry Andric 
87e8d8bef9SDimitry Andric bool BPFAdjustOpt::runOnModule(Module &M) { return BPFAdjustOptImpl(&M).run(); }
88e8d8bef9SDimitry Andric 
89e8d8bef9SDimitry Andric bool BPFAdjustOptImpl::run() {
90349cc55cSDimitry Andric   bool Changed = adjustICmpToBuiltin();
91349cc55cSDimitry Andric 
92e8d8bef9SDimitry Andric   for (Function &F : *M)
93e8d8bef9SDimitry Andric     for (auto &BB : F) {
94e8d8bef9SDimitry Andric       adjustBasicBlock(BB);
95e8d8bef9SDimitry Andric       for (auto &I : BB)
96e8d8bef9SDimitry Andric         adjustInst(I);
97e8d8bef9SDimitry Andric     }
98349cc55cSDimitry Andric   return insertPassThrough() || Changed;
99349cc55cSDimitry Andric }
100e8d8bef9SDimitry Andric 
101349cc55cSDimitry Andric // Commit acabad9ff6bf ("[InstCombine] try to canonicalize icmp with
102349cc55cSDimitry Andric // trunc op into mask and cmp") added a transformation to
103349cc55cSDimitry Andric // convert "(conv)a < power_2_const" to "a & <const>" in certain
104349cc55cSDimitry Andric // cases and bpf kernel verifier has to handle the resulted code
105349cc55cSDimitry Andric // conservatively and this may reject otherwise legitimate program.
106349cc55cSDimitry Andric // Here, we change related icmp code to a builtin which will
107349cc55cSDimitry Andric // be restored to original icmp code later to prevent that
108349cc55cSDimitry Andric // InstCombine transformatin.
109349cc55cSDimitry Andric bool BPFAdjustOptImpl::adjustICmpToBuiltin() {
110349cc55cSDimitry Andric   bool Changed = false;
111349cc55cSDimitry Andric   ICmpInst *ToBeDeleted = nullptr;
112349cc55cSDimitry Andric   for (Function &F : *M)
113349cc55cSDimitry Andric     for (auto &BB : F)
114349cc55cSDimitry Andric       for (auto &I : BB) {
115349cc55cSDimitry Andric         if (ToBeDeleted) {
116349cc55cSDimitry Andric           ToBeDeleted->eraseFromParent();
117349cc55cSDimitry Andric           ToBeDeleted = nullptr;
118349cc55cSDimitry Andric         }
119349cc55cSDimitry Andric 
120349cc55cSDimitry Andric         auto *Icmp = dyn_cast<ICmpInst>(&I);
121349cc55cSDimitry Andric         if (!Icmp)
122349cc55cSDimitry Andric           continue;
123349cc55cSDimitry Andric 
124349cc55cSDimitry Andric         Value *Op0 = Icmp->getOperand(0);
125349cc55cSDimitry Andric         if (!isa<TruncInst>(Op0))
126349cc55cSDimitry Andric           continue;
127349cc55cSDimitry Andric 
128349cc55cSDimitry Andric         auto ConstOp1 = dyn_cast<ConstantInt>(Icmp->getOperand(1));
129349cc55cSDimitry Andric         if (!ConstOp1)
130349cc55cSDimitry Andric           continue;
131349cc55cSDimitry Andric 
132349cc55cSDimitry Andric         auto ConstOp1Val = ConstOp1->getValue().getZExtValue();
133349cc55cSDimitry Andric         auto Op = Icmp->getPredicate();
134349cc55cSDimitry Andric         if (Op == ICmpInst::ICMP_ULT || Op == ICmpInst::ICMP_UGE) {
135349cc55cSDimitry Andric           if ((ConstOp1Val - 1) & ConstOp1Val)
136349cc55cSDimitry Andric             continue;
137349cc55cSDimitry Andric         } else if (Op == ICmpInst::ICMP_ULE || Op == ICmpInst::ICMP_UGT) {
138349cc55cSDimitry Andric           if (ConstOp1Val & (ConstOp1Val + 1))
139349cc55cSDimitry Andric             continue;
140349cc55cSDimitry Andric         } else {
141349cc55cSDimitry Andric           continue;
142349cc55cSDimitry Andric         }
143349cc55cSDimitry Andric 
144349cc55cSDimitry Andric         Constant *Opcode =
145349cc55cSDimitry Andric             ConstantInt::get(Type::getInt32Ty(BB.getContext()), Op);
146349cc55cSDimitry Andric         Function *Fn = Intrinsic::getDeclaration(
147349cc55cSDimitry Andric             M, Intrinsic::bpf_compare, {Op0->getType(), ConstOp1->getType()});
148349cc55cSDimitry Andric         auto *NewInst = CallInst::Create(Fn, {Opcode, Op0, ConstOp1});
149*bdd1243dSDimitry Andric         NewInst->insertBefore(&I);
150349cc55cSDimitry Andric         Icmp->replaceAllUsesWith(NewInst);
151349cc55cSDimitry Andric         Changed = true;
152349cc55cSDimitry Andric         ToBeDeleted = Icmp;
153349cc55cSDimitry Andric       }
154349cc55cSDimitry Andric 
155349cc55cSDimitry Andric   return Changed;
156e8d8bef9SDimitry Andric }
157e8d8bef9SDimitry Andric 
158e8d8bef9SDimitry Andric bool BPFAdjustOptImpl::insertPassThrough() {
159e8d8bef9SDimitry Andric   for (auto &Info : PassThroughs) {
160e8d8bef9SDimitry Andric     auto *CI = BPFCoreSharedInfo::insertPassThrough(
161e8d8bef9SDimitry Andric         M, Info.UsedInst->getParent(), Info.Input, Info.UsedInst);
162e8d8bef9SDimitry Andric     Info.UsedInst->setOperand(Info.OpIdx, CI);
163e8d8bef9SDimitry Andric   }
164e8d8bef9SDimitry Andric 
165e8d8bef9SDimitry Andric   return !PassThroughs.empty();
166e8d8bef9SDimitry Andric }
167e8d8bef9SDimitry Andric 
168e8d8bef9SDimitry Andric // To avoid combining conditionals in the same basic block by
169e8d8bef9SDimitry Andric // instrcombine optimization.
170e8d8bef9SDimitry Andric bool BPFAdjustOptImpl::serializeICMPInBB(Instruction &I) {
171e8d8bef9SDimitry Andric   // For:
172e8d8bef9SDimitry Andric   //   comp1 = icmp <opcode> ...;
173e8d8bef9SDimitry Andric   //   comp2 = icmp <opcode> ...;
174e8d8bef9SDimitry Andric   //   ... or comp1 comp2 ...
175e8d8bef9SDimitry Andric   // changed to:
176e8d8bef9SDimitry Andric   //   comp1 = icmp <opcode> ...;
177e8d8bef9SDimitry Andric   //   comp2 = icmp <opcode> ...;
178e8d8bef9SDimitry Andric   //   new_comp1 = __builtin_bpf_passthrough(seq_num, comp1)
179e8d8bef9SDimitry Andric   //   ... or new_comp1 comp2 ...
180fe6060f1SDimitry Andric   Value *Op0, *Op1;
181fe6060f1SDimitry Andric   // Use LogicalOr (accept `or i1` as well as `select i1 Op0, true, Op1`)
182fe6060f1SDimitry Andric   if (!match(&I, m_LogicalOr(m_Value(Op0), m_Value(Op1))))
183e8d8bef9SDimitry Andric     return false;
184fe6060f1SDimitry Andric   auto *Icmp1 = dyn_cast<ICmpInst>(Op0);
185e8d8bef9SDimitry Andric   if (!Icmp1)
186e8d8bef9SDimitry Andric     return false;
187fe6060f1SDimitry Andric   auto *Icmp2 = dyn_cast<ICmpInst>(Op1);
188e8d8bef9SDimitry Andric   if (!Icmp2)
189e8d8bef9SDimitry Andric     return false;
190e8d8bef9SDimitry Andric 
191e8d8bef9SDimitry Andric   Value *Icmp1Op0 = Icmp1->getOperand(0);
192e8d8bef9SDimitry Andric   Value *Icmp2Op0 = Icmp2->getOperand(0);
193e8d8bef9SDimitry Andric   if (Icmp1Op0 != Icmp2Op0)
194e8d8bef9SDimitry Andric     return false;
195e8d8bef9SDimitry Andric 
196e8d8bef9SDimitry Andric   // Now we got two icmp instructions which feed into
197e8d8bef9SDimitry Andric   // an "or" instruction.
198e8d8bef9SDimitry Andric   PassThroughInfo Info(Icmp1, &I, 0);
199e8d8bef9SDimitry Andric   PassThroughs.push_back(Info);
200e8d8bef9SDimitry Andric   return true;
201e8d8bef9SDimitry Andric }
202e8d8bef9SDimitry Andric 
203e8d8bef9SDimitry Andric // To avoid combining conditionals in the same basic block by
204e8d8bef9SDimitry Andric // instrcombine optimization.
205e8d8bef9SDimitry Andric bool BPFAdjustOptImpl::serializeICMPCrossBB(BasicBlock &BB) {
206e8d8bef9SDimitry Andric   // For:
207e8d8bef9SDimitry Andric   //   B1:
208e8d8bef9SDimitry Andric   //     comp1 = icmp <opcode> ...;
209e8d8bef9SDimitry Andric   //     if (comp1) goto B2 else B3;
210e8d8bef9SDimitry Andric   //   B2:
211e8d8bef9SDimitry Andric   //     comp2 = icmp <opcode> ...;
212e8d8bef9SDimitry Andric   //     if (comp2) goto B4 else B5;
213e8d8bef9SDimitry Andric   //   B4:
214e8d8bef9SDimitry Andric   //     ...
215e8d8bef9SDimitry Andric   // changed to:
216e8d8bef9SDimitry Andric   //   B1:
217e8d8bef9SDimitry Andric   //     comp1 = icmp <opcode> ...;
218e8d8bef9SDimitry Andric   //     comp1 = __builtin_bpf_passthrough(seq_num, comp1);
219e8d8bef9SDimitry Andric   //     if (comp1) goto B2 else B3;
220e8d8bef9SDimitry Andric   //   B2:
221e8d8bef9SDimitry Andric   //     comp2 = icmp <opcode> ...;
222e8d8bef9SDimitry Andric   //     if (comp2) goto B4 else B5;
223e8d8bef9SDimitry Andric   //   B4:
224e8d8bef9SDimitry Andric   //     ...
225e8d8bef9SDimitry Andric 
226e8d8bef9SDimitry Andric   // Check basic predecessors, if two of them (say B1, B2) are using
227e8d8bef9SDimitry Andric   // icmp instructions to generate conditions and one is the predesessor
228e8d8bef9SDimitry Andric   // of another (e.g., B1 is the predecessor of B2). Add a passthrough
229e8d8bef9SDimitry Andric   // barrier after icmp inst of block B1.
230e8d8bef9SDimitry Andric   BasicBlock *B2 = BB.getSinglePredecessor();
231e8d8bef9SDimitry Andric   if (!B2)
232e8d8bef9SDimitry Andric     return false;
233e8d8bef9SDimitry Andric 
234e8d8bef9SDimitry Andric   BasicBlock *B1 = B2->getSinglePredecessor();
235e8d8bef9SDimitry Andric   if (!B1)
236e8d8bef9SDimitry Andric     return false;
237e8d8bef9SDimitry Andric 
238e8d8bef9SDimitry Andric   Instruction *TI = B2->getTerminator();
239e8d8bef9SDimitry Andric   auto *BI = dyn_cast<BranchInst>(TI);
240e8d8bef9SDimitry Andric   if (!BI || !BI->isConditional())
241e8d8bef9SDimitry Andric     return false;
242e8d8bef9SDimitry Andric   auto *Cond = dyn_cast<ICmpInst>(BI->getCondition());
243e8d8bef9SDimitry Andric   if (!Cond || B2->getFirstNonPHI() != Cond)
244e8d8bef9SDimitry Andric     return false;
245e8d8bef9SDimitry Andric   Value *B2Op0 = Cond->getOperand(0);
246e8d8bef9SDimitry Andric   auto Cond2Op = Cond->getPredicate();
247e8d8bef9SDimitry Andric 
248e8d8bef9SDimitry Andric   TI = B1->getTerminator();
249e8d8bef9SDimitry Andric   BI = dyn_cast<BranchInst>(TI);
250e8d8bef9SDimitry Andric   if (!BI || !BI->isConditional())
251e8d8bef9SDimitry Andric     return false;
252e8d8bef9SDimitry Andric   Cond = dyn_cast<ICmpInst>(BI->getCondition());
253e8d8bef9SDimitry Andric   if (!Cond)
254e8d8bef9SDimitry Andric     return false;
255e8d8bef9SDimitry Andric   Value *B1Op0 = Cond->getOperand(0);
256e8d8bef9SDimitry Andric   auto Cond1Op = Cond->getPredicate();
257e8d8bef9SDimitry Andric 
258e8d8bef9SDimitry Andric   if (B1Op0 != B2Op0)
259e8d8bef9SDimitry Andric     return false;
260e8d8bef9SDimitry Andric 
261e8d8bef9SDimitry Andric   if (Cond1Op == ICmpInst::ICMP_SGT || Cond1Op == ICmpInst::ICMP_SGE) {
26281ad6265SDimitry Andric     if (Cond2Op != ICmpInst::ICMP_SLT && Cond2Op != ICmpInst::ICMP_SLE)
263e8d8bef9SDimitry Andric       return false;
264e8d8bef9SDimitry Andric   } else if (Cond1Op == ICmpInst::ICMP_SLT || Cond1Op == ICmpInst::ICMP_SLE) {
26581ad6265SDimitry Andric     if (Cond2Op != ICmpInst::ICMP_SGT && Cond2Op != ICmpInst::ICMP_SGE)
26681ad6265SDimitry Andric       return false;
26781ad6265SDimitry Andric   } else if (Cond1Op == ICmpInst::ICMP_ULT || Cond1Op == ICmpInst::ICMP_ULE) {
26881ad6265SDimitry Andric     if (Cond2Op != ICmpInst::ICMP_UGT && Cond2Op != ICmpInst::ICMP_UGE)
26981ad6265SDimitry Andric       return false;
27081ad6265SDimitry Andric   } else if (Cond1Op == ICmpInst::ICMP_UGT || Cond1Op == ICmpInst::ICMP_UGE) {
27181ad6265SDimitry Andric     if (Cond2Op != ICmpInst::ICMP_ULT && Cond2Op != ICmpInst::ICMP_ULE)
272e8d8bef9SDimitry Andric       return false;
273e8d8bef9SDimitry Andric   } else {
274e8d8bef9SDimitry Andric     return false;
275e8d8bef9SDimitry Andric   }
276e8d8bef9SDimitry Andric 
277e8d8bef9SDimitry Andric   PassThroughInfo Info(Cond, BI, 0);
278e8d8bef9SDimitry Andric   PassThroughs.push_back(Info);
279e8d8bef9SDimitry Andric 
280e8d8bef9SDimitry Andric   return true;
281e8d8bef9SDimitry Andric }
282e8d8bef9SDimitry Andric 
283e8d8bef9SDimitry Andric // To avoid speculative hoisting certain computations out of
284e8d8bef9SDimitry Andric // a basic block.
285e8d8bef9SDimitry Andric bool BPFAdjustOptImpl::avoidSpeculation(Instruction &I) {
286e8d8bef9SDimitry Andric   if (auto *LdInst = dyn_cast<LoadInst>(&I)) {
287e8d8bef9SDimitry Andric     if (auto *GV = dyn_cast<GlobalVariable>(LdInst->getOperand(0))) {
288e8d8bef9SDimitry Andric       if (GV->hasAttribute(BPFCoreSharedInfo::AmaAttr) ||
289e8d8bef9SDimitry Andric           GV->hasAttribute(BPFCoreSharedInfo::TypeIdAttr))
290e8d8bef9SDimitry Andric         return false;
291e8d8bef9SDimitry Andric     }
292e8d8bef9SDimitry Andric   }
293e8d8bef9SDimitry Andric 
294e8d8bef9SDimitry Andric   if (!isa<LoadInst>(&I) && !isa<CallInst>(&I))
295e8d8bef9SDimitry Andric     return false;
296e8d8bef9SDimitry Andric 
297e8d8bef9SDimitry Andric   // For:
298e8d8bef9SDimitry Andric   //   B1:
299e8d8bef9SDimitry Andric   //     var = ...
300e8d8bef9SDimitry Andric   //     ...
301e8d8bef9SDimitry Andric   //     /* icmp may not be in the same block as var = ... */
302e8d8bef9SDimitry Andric   //     comp1 = icmp <opcode> var, <const>;
303e8d8bef9SDimitry Andric   //     if (comp1) goto B2 else B3;
304e8d8bef9SDimitry Andric   //   B2:
305e8d8bef9SDimitry Andric   //     ... var ...
306e8d8bef9SDimitry Andric   // change to:
307e8d8bef9SDimitry Andric   //   B1:
308e8d8bef9SDimitry Andric   //     var = ...
309e8d8bef9SDimitry Andric   //     ...
310e8d8bef9SDimitry Andric   //     /* icmp may not be in the same block as var = ... */
311e8d8bef9SDimitry Andric   //     comp1 = icmp <opcode> var, <const>;
312e8d8bef9SDimitry Andric   //     if (comp1) goto B2 else B3;
313e8d8bef9SDimitry Andric   //   B2:
314e8d8bef9SDimitry Andric   //     var = __builtin_bpf_passthrough(seq_num, var);
315e8d8bef9SDimitry Andric   //     ... var ...
316e8d8bef9SDimitry Andric   bool isCandidate = false;
317e8d8bef9SDimitry Andric   SmallVector<PassThroughInfo, 4> Candidates;
318e8d8bef9SDimitry Andric   for (User *U : I.users()) {
319e8d8bef9SDimitry Andric     Instruction *Inst = dyn_cast<Instruction>(U);
320e8d8bef9SDimitry Andric     if (!Inst)
321e8d8bef9SDimitry Andric       continue;
322e8d8bef9SDimitry Andric 
323e8d8bef9SDimitry Andric     // May cover a little bit more than the
324e8d8bef9SDimitry Andric     // above pattern.
325e8d8bef9SDimitry Andric     if (auto *Icmp1 = dyn_cast<ICmpInst>(Inst)) {
326e8d8bef9SDimitry Andric       Value *Icmp1Op1 = Icmp1->getOperand(1);
327e8d8bef9SDimitry Andric       if (!isa<Constant>(Icmp1Op1))
328e8d8bef9SDimitry Andric         return false;
329e8d8bef9SDimitry Andric       isCandidate = true;
330e8d8bef9SDimitry Andric       continue;
331e8d8bef9SDimitry Andric     }
332e8d8bef9SDimitry Andric 
333e8d8bef9SDimitry Andric     // Ignore the use in the same basic block as the definition.
334e8d8bef9SDimitry Andric     if (Inst->getParent() == I.getParent())
335e8d8bef9SDimitry Andric       continue;
336e8d8bef9SDimitry Andric 
337e8d8bef9SDimitry Andric     // use in a different basic block, If there is a call or
338e8d8bef9SDimitry Andric     // load/store insn before this instruction in this basic
339e8d8bef9SDimitry Andric     // block. Most likely it cannot be hoisted out. Skip it.
340e8d8bef9SDimitry Andric     for (auto &I2 : *Inst->getParent()) {
341fe6060f1SDimitry Andric       if (isa<CallInst>(&I2))
342e8d8bef9SDimitry Andric         return false;
343fe6060f1SDimitry Andric       if (isa<LoadInst>(&I2) || isa<StoreInst>(&I2))
344e8d8bef9SDimitry Andric         return false;
345e8d8bef9SDimitry Andric       if (&I2 == Inst)
346e8d8bef9SDimitry Andric         break;
347e8d8bef9SDimitry Andric     }
348e8d8bef9SDimitry Andric 
349e8d8bef9SDimitry Andric     // It should be used in a GEP or a simple arithmetic like
350e8d8bef9SDimitry Andric     // ZEXT/SEXT which is used for GEP.
351e8d8bef9SDimitry Andric     if (Inst->getOpcode() == Instruction::ZExt ||
352e8d8bef9SDimitry Andric         Inst->getOpcode() == Instruction::SExt) {
353e8d8bef9SDimitry Andric       PassThroughInfo Info(&I, Inst, 0);
354e8d8bef9SDimitry Andric       Candidates.push_back(Info);
355e8d8bef9SDimitry Andric     } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
356e8d8bef9SDimitry Andric       // traverse GEP inst to find Use operand index
357e8d8bef9SDimitry Andric       unsigned i, e;
358e8d8bef9SDimitry Andric       for (i = 1, e = GI->getNumOperands(); i != e; ++i) {
359e8d8bef9SDimitry Andric         Value *V = GI->getOperand(i);
360e8d8bef9SDimitry Andric         if (V == &I)
361e8d8bef9SDimitry Andric           break;
362e8d8bef9SDimitry Andric       }
363e8d8bef9SDimitry Andric       if (i == e)
364e8d8bef9SDimitry Andric         continue;
365e8d8bef9SDimitry Andric 
366e8d8bef9SDimitry Andric       PassThroughInfo Info(&I, GI, i);
367e8d8bef9SDimitry Andric       Candidates.push_back(Info);
368e8d8bef9SDimitry Andric     }
369e8d8bef9SDimitry Andric   }
370e8d8bef9SDimitry Andric 
371e8d8bef9SDimitry Andric   if (!isCandidate || Candidates.empty())
372e8d8bef9SDimitry Andric     return false;
373e8d8bef9SDimitry Andric 
374e8d8bef9SDimitry Andric   llvm::append_range(PassThroughs, Candidates);
375e8d8bef9SDimitry Andric   return true;
376e8d8bef9SDimitry Andric }
377e8d8bef9SDimitry Andric 
378e8d8bef9SDimitry Andric void BPFAdjustOptImpl::adjustBasicBlock(BasicBlock &BB) {
379e8d8bef9SDimitry Andric   if (!DisableBPFserializeICMP && serializeICMPCrossBB(BB))
380e8d8bef9SDimitry Andric     return;
381e8d8bef9SDimitry Andric }
382e8d8bef9SDimitry Andric 
383e8d8bef9SDimitry Andric void BPFAdjustOptImpl::adjustInst(Instruction &I) {
384e8d8bef9SDimitry Andric   if (!DisableBPFserializeICMP && serializeICMPInBB(I))
385e8d8bef9SDimitry Andric     return;
386e8d8bef9SDimitry Andric   if (!DisableBPFavoidSpeculation && avoidSpeculation(I))
387e8d8bef9SDimitry Andric     return;
388e8d8bef9SDimitry Andric }
389e8d8bef9SDimitry Andric 
390e8d8bef9SDimitry Andric PreservedAnalyses BPFAdjustOptPass::run(Module &M, ModuleAnalysisManager &AM) {
391e8d8bef9SDimitry Andric   return BPFAdjustOptImpl(&M).run() ? PreservedAnalyses::none()
392e8d8bef9SDimitry Andric                                     : PreservedAnalyses::all();
393e8d8bef9SDimitry Andric }
394