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 class BPFAdjustOptImpl {
44e8d8bef9SDimitry Andric struct PassThroughInfo {
45e8d8bef9SDimitry Andric Instruction *Input;
46e8d8bef9SDimitry Andric Instruction *UsedInst;
47e8d8bef9SDimitry Andric uint32_t OpIdx;
PassThroughInfo__anonb65f9f030111::BPFAdjustOptImpl::PassThroughInfo48e8d8bef9SDimitry Andric PassThroughInfo(Instruction *I, Instruction *U, uint32_t Idx)
49e8d8bef9SDimitry Andric : Input(I), UsedInst(U), OpIdx(Idx) {}
50e8d8bef9SDimitry Andric };
51e8d8bef9SDimitry Andric
52e8d8bef9SDimitry Andric public:
BPFAdjustOptImpl(Module * M)53e8d8bef9SDimitry Andric BPFAdjustOptImpl(Module *M) : M(M) {}
54e8d8bef9SDimitry Andric
55e8d8bef9SDimitry Andric bool run();
56e8d8bef9SDimitry Andric
57e8d8bef9SDimitry Andric private:
58e8d8bef9SDimitry Andric Module *M;
59e8d8bef9SDimitry Andric SmallVector<PassThroughInfo, 16> PassThroughs;
60e8d8bef9SDimitry Andric
61349cc55cSDimitry Andric bool adjustICmpToBuiltin();
62e8d8bef9SDimitry Andric void adjustBasicBlock(BasicBlock &BB);
63e8d8bef9SDimitry Andric bool serializeICMPCrossBB(BasicBlock &BB);
64e8d8bef9SDimitry Andric void adjustInst(Instruction &I);
65e8d8bef9SDimitry Andric bool serializeICMPInBB(Instruction &I);
66e8d8bef9SDimitry Andric bool avoidSpeculation(Instruction &I);
67e8d8bef9SDimitry Andric bool insertPassThrough();
68e8d8bef9SDimitry Andric };
69e8d8bef9SDimitry Andric
70e8d8bef9SDimitry Andric } // End anonymous namespace
71e8d8bef9SDimitry Andric
run()72e8d8bef9SDimitry Andric bool BPFAdjustOptImpl::run() {
73349cc55cSDimitry Andric bool Changed = adjustICmpToBuiltin();
74349cc55cSDimitry Andric
75e8d8bef9SDimitry Andric for (Function &F : *M)
76e8d8bef9SDimitry Andric for (auto &BB : F) {
77e8d8bef9SDimitry Andric adjustBasicBlock(BB);
78e8d8bef9SDimitry Andric for (auto &I : BB)
79e8d8bef9SDimitry Andric adjustInst(I);
80e8d8bef9SDimitry Andric }
81349cc55cSDimitry Andric return insertPassThrough() || Changed;
82349cc55cSDimitry Andric }
83e8d8bef9SDimitry Andric
84349cc55cSDimitry Andric // Commit acabad9ff6bf ("[InstCombine] try to canonicalize icmp with
85349cc55cSDimitry Andric // trunc op into mask and cmp") added a transformation to
86349cc55cSDimitry Andric // convert "(conv)a < power_2_const" to "a & <const>" in certain
87349cc55cSDimitry Andric // cases and bpf kernel verifier has to handle the resulted code
88349cc55cSDimitry Andric // conservatively and this may reject otherwise legitimate program.
89349cc55cSDimitry Andric // Here, we change related icmp code to a builtin which will
90349cc55cSDimitry Andric // be restored to original icmp code later to prevent that
91349cc55cSDimitry Andric // InstCombine transformatin.
adjustICmpToBuiltin()92349cc55cSDimitry Andric bool BPFAdjustOptImpl::adjustICmpToBuiltin() {
93349cc55cSDimitry Andric bool Changed = false;
94349cc55cSDimitry Andric ICmpInst *ToBeDeleted = nullptr;
95349cc55cSDimitry Andric for (Function &F : *M)
96349cc55cSDimitry Andric for (auto &BB : F)
97349cc55cSDimitry Andric for (auto &I : BB) {
98349cc55cSDimitry Andric if (ToBeDeleted) {
99349cc55cSDimitry Andric ToBeDeleted->eraseFromParent();
100349cc55cSDimitry Andric ToBeDeleted = nullptr;
101349cc55cSDimitry Andric }
102349cc55cSDimitry Andric
103349cc55cSDimitry Andric auto *Icmp = dyn_cast<ICmpInst>(&I);
104349cc55cSDimitry Andric if (!Icmp)
105349cc55cSDimitry Andric continue;
106349cc55cSDimitry Andric
107349cc55cSDimitry Andric Value *Op0 = Icmp->getOperand(0);
108349cc55cSDimitry Andric if (!isa<TruncInst>(Op0))
109349cc55cSDimitry Andric continue;
110349cc55cSDimitry Andric
111349cc55cSDimitry Andric auto ConstOp1 = dyn_cast<ConstantInt>(Icmp->getOperand(1));
112349cc55cSDimitry Andric if (!ConstOp1)
113349cc55cSDimitry Andric continue;
114349cc55cSDimitry Andric
115349cc55cSDimitry Andric auto ConstOp1Val = ConstOp1->getValue().getZExtValue();
116349cc55cSDimitry Andric auto Op = Icmp->getPredicate();
117349cc55cSDimitry Andric if (Op == ICmpInst::ICMP_ULT || Op == ICmpInst::ICMP_UGE) {
118349cc55cSDimitry Andric if ((ConstOp1Val - 1) & ConstOp1Val)
119349cc55cSDimitry Andric continue;
120349cc55cSDimitry Andric } else if (Op == ICmpInst::ICMP_ULE || Op == ICmpInst::ICMP_UGT) {
121349cc55cSDimitry Andric if (ConstOp1Val & (ConstOp1Val + 1))
122349cc55cSDimitry Andric continue;
123349cc55cSDimitry Andric } else {
124349cc55cSDimitry Andric continue;
125349cc55cSDimitry Andric }
126349cc55cSDimitry Andric
127349cc55cSDimitry Andric Constant *Opcode =
128349cc55cSDimitry Andric ConstantInt::get(Type::getInt32Ty(BB.getContext()), Op);
129349cc55cSDimitry Andric Function *Fn = Intrinsic::getDeclaration(
130349cc55cSDimitry Andric M, Intrinsic::bpf_compare, {Op0->getType(), ConstOp1->getType()});
131349cc55cSDimitry Andric auto *NewInst = CallInst::Create(Fn, {Opcode, Op0, ConstOp1});
132*bdd1243dSDimitry Andric NewInst->insertBefore(&I);
133349cc55cSDimitry Andric Icmp->replaceAllUsesWith(NewInst);
134349cc55cSDimitry Andric Changed = true;
135349cc55cSDimitry Andric ToBeDeleted = Icmp;
136349cc55cSDimitry Andric }
137349cc55cSDimitry Andric
138349cc55cSDimitry Andric return Changed;
139e8d8bef9SDimitry Andric }
140e8d8bef9SDimitry Andric
insertPassThrough()141e8d8bef9SDimitry Andric bool BPFAdjustOptImpl::insertPassThrough() {
142e8d8bef9SDimitry Andric for (auto &Info : PassThroughs) {
143e8d8bef9SDimitry Andric auto *CI = BPFCoreSharedInfo::insertPassThrough(
144e8d8bef9SDimitry Andric M, Info.UsedInst->getParent(), Info.Input, Info.UsedInst);
145e8d8bef9SDimitry Andric Info.UsedInst->setOperand(Info.OpIdx, CI);
146e8d8bef9SDimitry Andric }
147e8d8bef9SDimitry Andric
148e8d8bef9SDimitry Andric return !PassThroughs.empty();
149e8d8bef9SDimitry Andric }
150e8d8bef9SDimitry Andric
151e8d8bef9SDimitry Andric // To avoid combining conditionals in the same basic block by
152e8d8bef9SDimitry Andric // instrcombine optimization.
serializeICMPInBB(Instruction & I)153e8d8bef9SDimitry Andric bool BPFAdjustOptImpl::serializeICMPInBB(Instruction &I) {
154e8d8bef9SDimitry Andric // For:
155e8d8bef9SDimitry Andric // comp1 = icmp <opcode> ...;
156e8d8bef9SDimitry Andric // comp2 = icmp <opcode> ...;
157e8d8bef9SDimitry Andric // ... or comp1 comp2 ...
158e8d8bef9SDimitry Andric // changed to:
159e8d8bef9SDimitry Andric // comp1 = icmp <opcode> ...;
160e8d8bef9SDimitry Andric // comp2 = icmp <opcode> ...;
161e8d8bef9SDimitry Andric // new_comp1 = __builtin_bpf_passthrough(seq_num, comp1)
162e8d8bef9SDimitry Andric // ... or new_comp1 comp2 ...
163fe6060f1SDimitry Andric Value *Op0, *Op1;
164fe6060f1SDimitry Andric // Use LogicalOr (accept `or i1` as well as `select i1 Op0, true, Op1`)
165fe6060f1SDimitry Andric if (!match(&I, m_LogicalOr(m_Value(Op0), m_Value(Op1))))
166e8d8bef9SDimitry Andric return false;
167fe6060f1SDimitry Andric auto *Icmp1 = dyn_cast<ICmpInst>(Op0);
168e8d8bef9SDimitry Andric if (!Icmp1)
169e8d8bef9SDimitry Andric return false;
170fe6060f1SDimitry Andric auto *Icmp2 = dyn_cast<ICmpInst>(Op1);
171e8d8bef9SDimitry Andric if (!Icmp2)
172e8d8bef9SDimitry Andric return false;
173e8d8bef9SDimitry Andric
174e8d8bef9SDimitry Andric Value *Icmp1Op0 = Icmp1->getOperand(0);
175e8d8bef9SDimitry Andric Value *Icmp2Op0 = Icmp2->getOperand(0);
176e8d8bef9SDimitry Andric if (Icmp1Op0 != Icmp2Op0)
177e8d8bef9SDimitry Andric return false;
178e8d8bef9SDimitry Andric
179e8d8bef9SDimitry Andric // Now we got two icmp instructions which feed into
180e8d8bef9SDimitry Andric // an "or" instruction.
181e8d8bef9SDimitry Andric PassThroughInfo Info(Icmp1, &I, 0);
182e8d8bef9SDimitry Andric PassThroughs.push_back(Info);
183e8d8bef9SDimitry Andric return true;
184e8d8bef9SDimitry Andric }
185e8d8bef9SDimitry Andric
186e8d8bef9SDimitry Andric // To avoid combining conditionals in the same basic block by
187e8d8bef9SDimitry Andric // instrcombine optimization.
serializeICMPCrossBB(BasicBlock & BB)188e8d8bef9SDimitry Andric bool BPFAdjustOptImpl::serializeICMPCrossBB(BasicBlock &BB) {
189e8d8bef9SDimitry Andric // For:
190e8d8bef9SDimitry Andric // B1:
191e8d8bef9SDimitry Andric // comp1 = icmp <opcode> ...;
192e8d8bef9SDimitry Andric // if (comp1) goto B2 else B3;
193e8d8bef9SDimitry Andric // B2:
194e8d8bef9SDimitry Andric // comp2 = icmp <opcode> ...;
195e8d8bef9SDimitry Andric // if (comp2) goto B4 else B5;
196e8d8bef9SDimitry Andric // B4:
197e8d8bef9SDimitry Andric // ...
198e8d8bef9SDimitry Andric // changed to:
199e8d8bef9SDimitry Andric // B1:
200e8d8bef9SDimitry Andric // comp1 = icmp <opcode> ...;
201e8d8bef9SDimitry Andric // comp1 = __builtin_bpf_passthrough(seq_num, comp1);
202e8d8bef9SDimitry Andric // if (comp1) goto B2 else B3;
203e8d8bef9SDimitry Andric // B2:
204e8d8bef9SDimitry Andric // comp2 = icmp <opcode> ...;
205e8d8bef9SDimitry Andric // if (comp2) goto B4 else B5;
206e8d8bef9SDimitry Andric // B4:
207e8d8bef9SDimitry Andric // ...
208e8d8bef9SDimitry Andric
209e8d8bef9SDimitry Andric // Check basic predecessors, if two of them (say B1, B2) are using
210e8d8bef9SDimitry Andric // icmp instructions to generate conditions and one is the predesessor
211e8d8bef9SDimitry Andric // of another (e.g., B1 is the predecessor of B2). Add a passthrough
212e8d8bef9SDimitry Andric // barrier after icmp inst of block B1.
213e8d8bef9SDimitry Andric BasicBlock *B2 = BB.getSinglePredecessor();
214e8d8bef9SDimitry Andric if (!B2)
215e8d8bef9SDimitry Andric return false;
216e8d8bef9SDimitry Andric
217e8d8bef9SDimitry Andric BasicBlock *B1 = B2->getSinglePredecessor();
218e8d8bef9SDimitry Andric if (!B1)
219e8d8bef9SDimitry Andric return false;
220e8d8bef9SDimitry Andric
221e8d8bef9SDimitry Andric Instruction *TI = B2->getTerminator();
222e8d8bef9SDimitry Andric auto *BI = dyn_cast<BranchInst>(TI);
223e8d8bef9SDimitry Andric if (!BI || !BI->isConditional())
224e8d8bef9SDimitry Andric return false;
225e8d8bef9SDimitry Andric auto *Cond = dyn_cast<ICmpInst>(BI->getCondition());
226e8d8bef9SDimitry Andric if (!Cond || B2->getFirstNonPHI() != Cond)
227e8d8bef9SDimitry Andric return false;
228e8d8bef9SDimitry Andric Value *B2Op0 = Cond->getOperand(0);
229e8d8bef9SDimitry Andric auto Cond2Op = Cond->getPredicate();
230e8d8bef9SDimitry Andric
231e8d8bef9SDimitry Andric TI = B1->getTerminator();
232e8d8bef9SDimitry Andric BI = dyn_cast<BranchInst>(TI);
233e8d8bef9SDimitry Andric if (!BI || !BI->isConditional())
234e8d8bef9SDimitry Andric return false;
235e8d8bef9SDimitry Andric Cond = dyn_cast<ICmpInst>(BI->getCondition());
236e8d8bef9SDimitry Andric if (!Cond)
237e8d8bef9SDimitry Andric return false;
238e8d8bef9SDimitry Andric Value *B1Op0 = Cond->getOperand(0);
239e8d8bef9SDimitry Andric auto Cond1Op = Cond->getPredicate();
240e8d8bef9SDimitry Andric
241e8d8bef9SDimitry Andric if (B1Op0 != B2Op0)
242e8d8bef9SDimitry Andric return false;
243e8d8bef9SDimitry Andric
244e8d8bef9SDimitry Andric if (Cond1Op == ICmpInst::ICMP_SGT || Cond1Op == ICmpInst::ICMP_SGE) {
24581ad6265SDimitry Andric if (Cond2Op != ICmpInst::ICMP_SLT && Cond2Op != ICmpInst::ICMP_SLE)
246e8d8bef9SDimitry Andric return false;
247e8d8bef9SDimitry Andric } else if (Cond1Op == ICmpInst::ICMP_SLT || Cond1Op == ICmpInst::ICMP_SLE) {
24881ad6265SDimitry Andric if (Cond2Op != ICmpInst::ICMP_SGT && Cond2Op != ICmpInst::ICMP_SGE)
24981ad6265SDimitry Andric return false;
25081ad6265SDimitry Andric } else if (Cond1Op == ICmpInst::ICMP_ULT || Cond1Op == ICmpInst::ICMP_ULE) {
25181ad6265SDimitry Andric if (Cond2Op != ICmpInst::ICMP_UGT && Cond2Op != ICmpInst::ICMP_UGE)
25281ad6265SDimitry Andric return false;
25381ad6265SDimitry Andric } else if (Cond1Op == ICmpInst::ICMP_UGT || Cond1Op == ICmpInst::ICMP_UGE) {
25481ad6265SDimitry Andric if (Cond2Op != ICmpInst::ICMP_ULT && Cond2Op != ICmpInst::ICMP_ULE)
255e8d8bef9SDimitry Andric return false;
256e8d8bef9SDimitry Andric } else {
257e8d8bef9SDimitry Andric return false;
258e8d8bef9SDimitry Andric }
259e8d8bef9SDimitry Andric
260e8d8bef9SDimitry Andric PassThroughInfo Info(Cond, BI, 0);
261e8d8bef9SDimitry Andric PassThroughs.push_back(Info);
262e8d8bef9SDimitry Andric
263e8d8bef9SDimitry Andric return true;
264e8d8bef9SDimitry Andric }
265e8d8bef9SDimitry Andric
266e8d8bef9SDimitry Andric // To avoid speculative hoisting certain computations out of
267e8d8bef9SDimitry Andric // a basic block.
avoidSpeculation(Instruction & I)268e8d8bef9SDimitry Andric bool BPFAdjustOptImpl::avoidSpeculation(Instruction &I) {
269e8d8bef9SDimitry Andric if (auto *LdInst = dyn_cast<LoadInst>(&I)) {
270e8d8bef9SDimitry Andric if (auto *GV = dyn_cast<GlobalVariable>(LdInst->getOperand(0))) {
271e8d8bef9SDimitry Andric if (GV->hasAttribute(BPFCoreSharedInfo::AmaAttr) ||
272e8d8bef9SDimitry Andric GV->hasAttribute(BPFCoreSharedInfo::TypeIdAttr))
273e8d8bef9SDimitry Andric return false;
274e8d8bef9SDimitry Andric }
275e8d8bef9SDimitry Andric }
276e8d8bef9SDimitry Andric
277e8d8bef9SDimitry Andric if (!isa<LoadInst>(&I) && !isa<CallInst>(&I))
278e8d8bef9SDimitry Andric return false;
279e8d8bef9SDimitry Andric
280e8d8bef9SDimitry Andric // For:
281e8d8bef9SDimitry Andric // B1:
282e8d8bef9SDimitry Andric // var = ...
283e8d8bef9SDimitry Andric // ...
284e8d8bef9SDimitry Andric // /* icmp may not be in the same block as var = ... */
285e8d8bef9SDimitry Andric // comp1 = icmp <opcode> var, <const>;
286e8d8bef9SDimitry Andric // if (comp1) goto B2 else B3;
287e8d8bef9SDimitry Andric // B2:
288e8d8bef9SDimitry Andric // ... var ...
289e8d8bef9SDimitry Andric // change to:
290e8d8bef9SDimitry Andric // B1:
291e8d8bef9SDimitry Andric // var = ...
292e8d8bef9SDimitry Andric // ...
293e8d8bef9SDimitry Andric // /* icmp may not be in the same block as var = ... */
294e8d8bef9SDimitry Andric // comp1 = icmp <opcode> var, <const>;
295e8d8bef9SDimitry Andric // if (comp1) goto B2 else B3;
296e8d8bef9SDimitry Andric // B2:
297e8d8bef9SDimitry Andric // var = __builtin_bpf_passthrough(seq_num, var);
298e8d8bef9SDimitry Andric // ... var ...
299e8d8bef9SDimitry Andric bool isCandidate = false;
300e8d8bef9SDimitry Andric SmallVector<PassThroughInfo, 4> Candidates;
301e8d8bef9SDimitry Andric for (User *U : I.users()) {
302e8d8bef9SDimitry Andric Instruction *Inst = dyn_cast<Instruction>(U);
303e8d8bef9SDimitry Andric if (!Inst)
304e8d8bef9SDimitry Andric continue;
305e8d8bef9SDimitry Andric
306e8d8bef9SDimitry Andric // May cover a little bit more than the
307e8d8bef9SDimitry Andric // above pattern.
308e8d8bef9SDimitry Andric if (auto *Icmp1 = dyn_cast<ICmpInst>(Inst)) {
309e8d8bef9SDimitry Andric Value *Icmp1Op1 = Icmp1->getOperand(1);
310e8d8bef9SDimitry Andric if (!isa<Constant>(Icmp1Op1))
311e8d8bef9SDimitry Andric return false;
312e8d8bef9SDimitry Andric isCandidate = true;
313e8d8bef9SDimitry Andric continue;
314e8d8bef9SDimitry Andric }
315e8d8bef9SDimitry Andric
316e8d8bef9SDimitry Andric // Ignore the use in the same basic block as the definition.
317e8d8bef9SDimitry Andric if (Inst->getParent() == I.getParent())
318e8d8bef9SDimitry Andric continue;
319e8d8bef9SDimitry Andric
320e8d8bef9SDimitry Andric // use in a different basic block, If there is a call or
321e8d8bef9SDimitry Andric // load/store insn before this instruction in this basic
322e8d8bef9SDimitry Andric // block. Most likely it cannot be hoisted out. Skip it.
323e8d8bef9SDimitry Andric for (auto &I2 : *Inst->getParent()) {
324fe6060f1SDimitry Andric if (isa<CallInst>(&I2))
325e8d8bef9SDimitry Andric return false;
326fe6060f1SDimitry Andric if (isa<LoadInst>(&I2) || isa<StoreInst>(&I2))
327e8d8bef9SDimitry Andric return false;
328e8d8bef9SDimitry Andric if (&I2 == Inst)
329e8d8bef9SDimitry Andric break;
330e8d8bef9SDimitry Andric }
331e8d8bef9SDimitry Andric
332e8d8bef9SDimitry Andric // It should be used in a GEP or a simple arithmetic like
333e8d8bef9SDimitry Andric // ZEXT/SEXT which is used for GEP.
334e8d8bef9SDimitry Andric if (Inst->getOpcode() == Instruction::ZExt ||
335e8d8bef9SDimitry Andric Inst->getOpcode() == Instruction::SExt) {
336e8d8bef9SDimitry Andric PassThroughInfo Info(&I, Inst, 0);
337e8d8bef9SDimitry Andric Candidates.push_back(Info);
338e8d8bef9SDimitry Andric } else if (auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
339e8d8bef9SDimitry Andric // traverse GEP inst to find Use operand index
340e8d8bef9SDimitry Andric unsigned i, e;
341e8d8bef9SDimitry Andric for (i = 1, e = GI->getNumOperands(); i != e; ++i) {
342e8d8bef9SDimitry Andric Value *V = GI->getOperand(i);
343e8d8bef9SDimitry Andric if (V == &I)
344e8d8bef9SDimitry Andric break;
345e8d8bef9SDimitry Andric }
346e8d8bef9SDimitry Andric if (i == e)
347e8d8bef9SDimitry Andric continue;
348e8d8bef9SDimitry Andric
349e8d8bef9SDimitry Andric PassThroughInfo Info(&I, GI, i);
350e8d8bef9SDimitry Andric Candidates.push_back(Info);
351e8d8bef9SDimitry Andric }
352e8d8bef9SDimitry Andric }
353e8d8bef9SDimitry Andric
354e8d8bef9SDimitry Andric if (!isCandidate || Candidates.empty())
355e8d8bef9SDimitry Andric return false;
356e8d8bef9SDimitry Andric
357e8d8bef9SDimitry Andric llvm::append_range(PassThroughs, Candidates);
358e8d8bef9SDimitry Andric return true;
359e8d8bef9SDimitry Andric }
360e8d8bef9SDimitry Andric
adjustBasicBlock(BasicBlock & BB)361e8d8bef9SDimitry Andric void BPFAdjustOptImpl::adjustBasicBlock(BasicBlock &BB) {
362e8d8bef9SDimitry Andric if (!DisableBPFserializeICMP && serializeICMPCrossBB(BB))
363e8d8bef9SDimitry Andric return;
364e8d8bef9SDimitry Andric }
365e8d8bef9SDimitry Andric
adjustInst(Instruction & I)366e8d8bef9SDimitry Andric void BPFAdjustOptImpl::adjustInst(Instruction &I) {
367e8d8bef9SDimitry Andric if (!DisableBPFserializeICMP && serializeICMPInBB(I))
368e8d8bef9SDimitry Andric return;
369e8d8bef9SDimitry Andric if (!DisableBPFavoidSpeculation && avoidSpeculation(I))
370e8d8bef9SDimitry Andric return;
371e8d8bef9SDimitry Andric }
372e8d8bef9SDimitry Andric
run(Module & M,ModuleAnalysisManager & AM)373e8d8bef9SDimitry Andric PreservedAnalyses BPFAdjustOptPass::run(Module &M, ModuleAnalysisManager &AM) {
374e8d8bef9SDimitry Andric return BPFAdjustOptImpl(&M).run() ? PreservedAnalyses::none()
375e8d8bef9SDimitry Andric : PreservedAnalyses::all();
376e8d8bef9SDimitry Andric }
377