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