15f757f3fSDimitry Andric //===------ BPFPreserveStaticOffset.cpp -----------------------------------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric // 95f757f3fSDimitry Andric // TLDR: replaces llvm.preserve.static.offset + GEP + load / store 105f757f3fSDimitry Andric // with llvm.bpf.getelementptr.and.load / store 115f757f3fSDimitry Andric // 125f757f3fSDimitry Andric // This file implements BPFPreserveStaticOffsetPass transformation. 135f757f3fSDimitry Andric // This transformation address two BPF verifier specific issues: 145f757f3fSDimitry Andric // 155f757f3fSDimitry Andric // (a) Access to the fields of some structural types is allowed only 165f757f3fSDimitry Andric // using load and store instructions with static immediate offsets. 175f757f3fSDimitry Andric // 185f757f3fSDimitry Andric // Examples of such types are `struct __sk_buff` and `struct 195f757f3fSDimitry Andric // bpf_sock_ops`. This is so because offsets of the fields of 205f757f3fSDimitry Andric // these structures do not match real offsets in the running 215f757f3fSDimitry Andric // kernel. During BPF program load LDX and STX instructions 225f757f3fSDimitry Andric // referring to the fields of these types are rewritten so that 235f757f3fSDimitry Andric // offsets match real offsets. For this rewrite to happen field 245f757f3fSDimitry Andric // offsets have to be encoded as immediate operands of the 255f757f3fSDimitry Andric // instructions. 265f757f3fSDimitry Andric // 275f757f3fSDimitry Andric // See kernel/bpf/verifier.c:convert_ctx_access function in the 285f757f3fSDimitry Andric // Linux kernel source tree for details. 295f757f3fSDimitry Andric // 305f757f3fSDimitry Andric // (b) Pointers to context parameters of BPF programs must not be 315f757f3fSDimitry Andric // modified before access. 325f757f3fSDimitry Andric // 335f757f3fSDimitry Andric // During BPF program verification a tag PTR_TO_CTX is tracked for 345f757f3fSDimitry Andric // register values. In case if register with such tag is modified 355f757f3fSDimitry Andric // BPF program is not allowed to read or write memory using this 365f757f3fSDimitry Andric // register. See kernel/bpf/verifier.c:check_mem_access function 375f757f3fSDimitry Andric // in the Linux kernel source tree for details. 385f757f3fSDimitry Andric // 395f757f3fSDimitry Andric // The following sequence of the IR instructions: 405f757f3fSDimitry Andric // 415f757f3fSDimitry Andric // %x = getelementptr %ptr, %constant_offset 425f757f3fSDimitry Andric // %y = load %x 435f757f3fSDimitry Andric // 445f757f3fSDimitry Andric // Is translated as a single machine instruction: 455f757f3fSDimitry Andric // 465f757f3fSDimitry Andric // LDW %ptr, %constant_offset 475f757f3fSDimitry Andric // 485f757f3fSDimitry Andric // In order for cases (a) and (b) to work the sequence %x-%y above has 495f757f3fSDimitry Andric // to be preserved by the IR passes. 505f757f3fSDimitry Andric // 515f757f3fSDimitry Andric // However, several optimization passes might sink `load` instruction 525f757f3fSDimitry Andric // or hoist `getelementptr` instruction so that the instructions are 535f757f3fSDimitry Andric // no longer in sequence. Examples of such passes are: 545f757f3fSDimitry Andric // SimplifyCFGPass, InstCombinePass, GVNPass. 555f757f3fSDimitry Andric // After such modification the verifier would reject the BPF program. 565f757f3fSDimitry Andric // 575f757f3fSDimitry Andric // To avoid this issue the patterns like (load/store (getelementptr ...)) 585f757f3fSDimitry Andric // are replaced by calls to BPF specific intrinsic functions: 595f757f3fSDimitry Andric // - llvm.bpf.getelementptr.and.load 605f757f3fSDimitry Andric // - llvm.bpf.getelementptr.and.store 615f757f3fSDimitry Andric // 625f757f3fSDimitry Andric // These calls are lowered back to (load/store (getelementptr ...)) 635f757f3fSDimitry Andric // by BPFCheckAndAdjustIR pass right before the translation from IR to 645f757f3fSDimitry Andric // machine instructions. 655f757f3fSDimitry Andric // 665f757f3fSDimitry Andric // The transformation is split into the following steps: 675f757f3fSDimitry Andric // - When IR is generated from AST the calls to intrinsic function 685f757f3fSDimitry Andric // llvm.preserve.static.offset are inserted. 695f757f3fSDimitry Andric // - BPFPreserveStaticOffsetPass is executed as early as possible 705f757f3fSDimitry Andric // with AllowPatial set to true, this handles marked GEP chains 715f757f3fSDimitry Andric // with constant offsets. 725f757f3fSDimitry Andric // - BPFPreserveStaticOffsetPass is executed at ScalarOptimizerLateEPCallback 735f757f3fSDimitry Andric // with AllowPatial set to false, this handles marked GEP chains 745f757f3fSDimitry Andric // with offsets that became constant after loop unrolling, e.g. 755f757f3fSDimitry Andric // to handle the following code: 765f757f3fSDimitry Andric // 775f757f3fSDimitry Andric // struct context { int x[4]; } __attribute__((preserve_static_offset)); 785f757f3fSDimitry Andric // 795f757f3fSDimitry Andric // struct context *ctx = ...; 805f757f3fSDimitry Andric // #pragma clang loop unroll(full) 815f757f3fSDimitry Andric // for (int i = 0; i < 4; ++i) 825f757f3fSDimitry Andric // foo(ctx->x[i]); 835f757f3fSDimitry Andric // 845f757f3fSDimitry Andric // The early BPFPreserveStaticOffsetPass run is necessary to allow 855f757f3fSDimitry Andric // additional GVN / CSE opportunities after functions inlining. 865f757f3fSDimitry Andric // The relative order of optimization applied to function: 875f757f3fSDimitry Andric // - early stage (1) 885f757f3fSDimitry Andric // - ... 895f757f3fSDimitry Andric // - function inlining (2) 905f757f3fSDimitry Andric // - ... 915f757f3fSDimitry Andric // - loop unrolling 925f757f3fSDimitry Andric // - ... 935f757f3fSDimitry Andric // - ScalarOptimizerLateEPCallback (3) 945f757f3fSDimitry Andric // 955f757f3fSDimitry Andric // When function A is inlined into function B all optimizations for A 965f757f3fSDimitry Andric // are already done, while some passes remain for B. In case if 975f757f3fSDimitry Andric // BPFPreserveStaticOffsetPass is done at (3) but not done at (1) 985f757f3fSDimitry Andric // the code after (2) would contain a mix of 995f757f3fSDimitry Andric // (load (gep %p)) and (get.and.load %p) usages: 1005f757f3fSDimitry Andric // - the (load (gep %p)) would come from the calling function; 1015f757f3fSDimitry Andric // - the (get.and.load %p) would come from the callee function. 1025f757f3fSDimitry Andric // Thus clobbering CSE / GVN passes done after inlining. 1035f757f3fSDimitry Andric 1045f757f3fSDimitry Andric #include "BPF.h" 1055f757f3fSDimitry Andric #include "BPFCORE.h" 1065f757f3fSDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 1075f757f3fSDimitry Andric #include "llvm/ADT/SmallVector.h" 1085f757f3fSDimitry Andric #include "llvm/IR/Argument.h" 1095f757f3fSDimitry Andric #include "llvm/IR/Attributes.h" 1105f757f3fSDimitry Andric #include "llvm/IR/BasicBlock.h" 1115f757f3fSDimitry Andric #include "llvm/IR/Constants.h" 1125f757f3fSDimitry Andric #include "llvm/IR/DebugInfoMetadata.h" 1135f757f3fSDimitry Andric #include "llvm/IR/DiagnosticInfo.h" 1145f757f3fSDimitry Andric #include "llvm/IR/IRBuilder.h" 1155f757f3fSDimitry Andric #include "llvm/IR/InstIterator.h" 1165f757f3fSDimitry Andric #include "llvm/IR/Instructions.h" 1175f757f3fSDimitry Andric #include "llvm/IR/Intrinsics.h" 1185f757f3fSDimitry Andric #include "llvm/IR/IntrinsicsBPF.h" 119*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h" 1205f757f3fSDimitry Andric #include "llvm/Support/Debug.h" 1215f757f3fSDimitry Andric #include "llvm/Support/ErrorHandling.h" 1225f757f3fSDimitry Andric 1235f757f3fSDimitry Andric #define DEBUG_TYPE "bpf-preserve-static-offset" 1245f757f3fSDimitry Andric 1255f757f3fSDimitry Andric using namespace llvm; 1265f757f3fSDimitry Andric 1275f757f3fSDimitry Andric static const unsigned GepAndLoadFirstIdxArg = 6; 1285f757f3fSDimitry Andric static const unsigned GepAndStoreFirstIdxArg = 7; 1295f757f3fSDimitry Andric 1305f757f3fSDimitry Andric static bool isIntrinsicCall(Value *I, Intrinsic::ID Id) { 1315f757f3fSDimitry Andric if (auto *Call = dyn_cast<CallInst>(I)) 1325f757f3fSDimitry Andric if (Function *Func = Call->getCalledFunction()) 1335f757f3fSDimitry Andric return Func->getIntrinsicID() == Id; 1345f757f3fSDimitry Andric return false; 1355f757f3fSDimitry Andric } 1365f757f3fSDimitry Andric 1375f757f3fSDimitry Andric static bool isPreserveStaticOffsetCall(Value *I) { 1385f757f3fSDimitry Andric return isIntrinsicCall(I, Intrinsic::preserve_static_offset); 1395f757f3fSDimitry Andric } 1405f757f3fSDimitry Andric 1415f757f3fSDimitry Andric static CallInst *isGEPAndLoad(Value *I) { 1425f757f3fSDimitry Andric if (isIntrinsicCall(I, Intrinsic::bpf_getelementptr_and_load)) 1435f757f3fSDimitry Andric return cast<CallInst>(I); 1445f757f3fSDimitry Andric return nullptr; 1455f757f3fSDimitry Andric } 1465f757f3fSDimitry Andric 1475f757f3fSDimitry Andric static CallInst *isGEPAndStore(Value *I) { 1485f757f3fSDimitry Andric if (isIntrinsicCall(I, Intrinsic::bpf_getelementptr_and_store)) 1495f757f3fSDimitry Andric return cast<CallInst>(I); 1505f757f3fSDimitry Andric return nullptr; 1515f757f3fSDimitry Andric } 1525f757f3fSDimitry Andric 1535f757f3fSDimitry Andric template <class T = Instruction> 1545f757f3fSDimitry Andric static DILocation *mergeDILocations(SmallVector<T *> &Insns) { 1555f757f3fSDimitry Andric DILocation *Merged = (*Insns.begin())->getDebugLoc(); 1565f757f3fSDimitry Andric for (T *I : Insns) 1575f757f3fSDimitry Andric Merged = DILocation::getMergedLocation(Merged, I->getDebugLoc()); 1585f757f3fSDimitry Andric return Merged; 1595f757f3fSDimitry Andric } 1605f757f3fSDimitry Andric 1615f757f3fSDimitry Andric static CallInst *makeIntrinsicCall(Module *M, 1625f757f3fSDimitry Andric Intrinsic::BPFIntrinsics Intrinsic, 1635f757f3fSDimitry Andric ArrayRef<Type *> Types, 1645f757f3fSDimitry Andric ArrayRef<Value *> Args) { 1655f757f3fSDimitry Andric 1665f757f3fSDimitry Andric Function *Fn = Intrinsic::getDeclaration(M, Intrinsic, Types); 1675f757f3fSDimitry Andric return CallInst::Create(Fn, Args); 1685f757f3fSDimitry Andric } 1695f757f3fSDimitry Andric 1705f757f3fSDimitry Andric static void setParamElementType(CallInst *Call, unsigned ArgNo, Type *Type) { 1715f757f3fSDimitry Andric LLVMContext &C = Call->getContext(); 1725f757f3fSDimitry Andric Call->addParamAttr(ArgNo, Attribute::get(C, Attribute::ElementType, Type)); 1735f757f3fSDimitry Andric } 1745f757f3fSDimitry Andric 1755f757f3fSDimitry Andric static void setParamReadNone(CallInst *Call, unsigned ArgNo) { 1765f757f3fSDimitry Andric LLVMContext &C = Call->getContext(); 1775f757f3fSDimitry Andric Call->addParamAttr(ArgNo, Attribute::get(C, Attribute::ReadNone)); 1785f757f3fSDimitry Andric } 1795f757f3fSDimitry Andric 1805f757f3fSDimitry Andric static void setParamReadOnly(CallInst *Call, unsigned ArgNo) { 1815f757f3fSDimitry Andric LLVMContext &C = Call->getContext(); 1825f757f3fSDimitry Andric Call->addParamAttr(ArgNo, Attribute::get(C, Attribute::ReadOnly)); 1835f757f3fSDimitry Andric } 1845f757f3fSDimitry Andric 1855f757f3fSDimitry Andric static void setParamWriteOnly(CallInst *Call, unsigned ArgNo) { 1865f757f3fSDimitry Andric LLVMContext &C = Call->getContext(); 1875f757f3fSDimitry Andric Call->addParamAttr(ArgNo, Attribute::get(C, Attribute::WriteOnly)); 1885f757f3fSDimitry Andric } 1895f757f3fSDimitry Andric 1905f757f3fSDimitry Andric namespace { 1915f757f3fSDimitry Andric struct GEPChainInfo { 1925f757f3fSDimitry Andric bool InBounds; 1935f757f3fSDimitry Andric Type *SourceElementType; 1945f757f3fSDimitry Andric SmallVector<Value *> Indices; 1955f757f3fSDimitry Andric SmallVector<GetElementPtrInst *> Members; 1965f757f3fSDimitry Andric 1975f757f3fSDimitry Andric GEPChainInfo() { reset(); } 1985f757f3fSDimitry Andric 1995f757f3fSDimitry Andric void reset() { 2005f757f3fSDimitry Andric InBounds = true; 2015f757f3fSDimitry Andric SourceElementType = nullptr; 2025f757f3fSDimitry Andric Indices.clear(); 2035f757f3fSDimitry Andric Members.clear(); 2045f757f3fSDimitry Andric } 2055f757f3fSDimitry Andric }; 2065f757f3fSDimitry Andric } // Anonymous namespace 2075f757f3fSDimitry Andric 2085f757f3fSDimitry Andric template <class T = std::disjunction<LoadInst, StoreInst>> 2095f757f3fSDimitry Andric static void fillCommonArgs(LLVMContext &C, SmallVector<Value *> &Args, 2105f757f3fSDimitry Andric GEPChainInfo &GEP, T *Insn) { 2115f757f3fSDimitry Andric Type *Int8Ty = Type::getInt8Ty(C); 2125f757f3fSDimitry Andric Type *Int1Ty = Type::getInt1Ty(C); 2135f757f3fSDimitry Andric // Implementation of Align guarantees that ShiftValue < 64 2145f757f3fSDimitry Andric unsigned AlignShiftValue = Log2_64(Insn->getAlign().value()); 2155f757f3fSDimitry Andric Args.push_back(GEP.Members[0]->getPointerOperand()); 2165f757f3fSDimitry Andric Args.push_back(ConstantInt::get(Int1Ty, Insn->isVolatile())); 2175f757f3fSDimitry Andric Args.push_back(ConstantInt::get(Int8Ty, (unsigned)Insn->getOrdering())); 2185f757f3fSDimitry Andric Args.push_back(ConstantInt::get(Int8Ty, (unsigned)Insn->getSyncScopeID())); 2195f757f3fSDimitry Andric Args.push_back(ConstantInt::get(Int8Ty, AlignShiftValue)); 2205f757f3fSDimitry Andric Args.push_back(ConstantInt::get(Int1Ty, GEP.InBounds)); 2215f757f3fSDimitry Andric Args.append(GEP.Indices.begin(), GEP.Indices.end()); 2225f757f3fSDimitry Andric } 2235f757f3fSDimitry Andric 2245f757f3fSDimitry Andric static Instruction *makeGEPAndLoad(Module *M, GEPChainInfo &GEP, 2255f757f3fSDimitry Andric LoadInst *Load) { 2265f757f3fSDimitry Andric SmallVector<Value *> Args; 2275f757f3fSDimitry Andric fillCommonArgs(M->getContext(), Args, GEP, Load); 2285f757f3fSDimitry Andric CallInst *Call = makeIntrinsicCall(M, Intrinsic::bpf_getelementptr_and_load, 2295f757f3fSDimitry Andric {Load->getType()}, Args); 2305f757f3fSDimitry Andric setParamElementType(Call, 0, GEP.SourceElementType); 2315f757f3fSDimitry Andric Call->applyMergedLocation(mergeDILocations(GEP.Members), Load->getDebugLoc()); 2325f757f3fSDimitry Andric Call->setName((*GEP.Members.rbegin())->getName()); 2335f757f3fSDimitry Andric if (Load->isUnordered()) { 2345f757f3fSDimitry Andric Call->setOnlyReadsMemory(); 2355f757f3fSDimitry Andric Call->setOnlyAccessesArgMemory(); 2365f757f3fSDimitry Andric setParamReadOnly(Call, 0); 2375f757f3fSDimitry Andric } 2385f757f3fSDimitry Andric for (unsigned I = GepAndLoadFirstIdxArg; I < Args.size(); ++I) 2395f757f3fSDimitry Andric Call->addParamAttr(I, Attribute::ImmArg); 2405f757f3fSDimitry Andric Call->setAAMetadata(Load->getAAMetadata()); 2415f757f3fSDimitry Andric return Call; 2425f757f3fSDimitry Andric } 2435f757f3fSDimitry Andric 2445f757f3fSDimitry Andric static Instruction *makeGEPAndStore(Module *M, GEPChainInfo &GEP, 2455f757f3fSDimitry Andric StoreInst *Store) { 2465f757f3fSDimitry Andric SmallVector<Value *> Args; 2475f757f3fSDimitry Andric Args.push_back(Store->getValueOperand()); 2485f757f3fSDimitry Andric fillCommonArgs(M->getContext(), Args, GEP, Store); 2495f757f3fSDimitry Andric CallInst *Call = 2505f757f3fSDimitry Andric makeIntrinsicCall(M, Intrinsic::bpf_getelementptr_and_store, 2515f757f3fSDimitry Andric {Store->getValueOperand()->getType()}, Args); 2525f757f3fSDimitry Andric setParamElementType(Call, 1, GEP.SourceElementType); 2535f757f3fSDimitry Andric if (Store->getValueOperand()->getType()->isPointerTy()) 2545f757f3fSDimitry Andric setParamReadNone(Call, 0); 2555f757f3fSDimitry Andric Call->applyMergedLocation(mergeDILocations(GEP.Members), 2565f757f3fSDimitry Andric Store->getDebugLoc()); 2575f757f3fSDimitry Andric if (Store->isUnordered()) { 2585f757f3fSDimitry Andric Call->setOnlyWritesMemory(); 2595f757f3fSDimitry Andric Call->setOnlyAccessesArgMemory(); 2605f757f3fSDimitry Andric setParamWriteOnly(Call, 1); 2615f757f3fSDimitry Andric } 2625f757f3fSDimitry Andric for (unsigned I = GepAndStoreFirstIdxArg; I < Args.size(); ++I) 2635f757f3fSDimitry Andric Call->addParamAttr(I, Attribute::ImmArg); 2645f757f3fSDimitry Andric Call->setAAMetadata(Store->getAAMetadata()); 2655f757f3fSDimitry Andric return Call; 2665f757f3fSDimitry Andric } 2675f757f3fSDimitry Andric 2685f757f3fSDimitry Andric static unsigned getOperandAsUnsigned(CallInst *Call, unsigned ArgNo) { 2695f757f3fSDimitry Andric if (auto *Int = dyn_cast<ConstantInt>(Call->getOperand(ArgNo))) 2705f757f3fSDimitry Andric return Int->getValue().getZExtValue(); 2715f757f3fSDimitry Andric std::string Report; 2725f757f3fSDimitry Andric raw_string_ostream ReportS(Report); 2735f757f3fSDimitry Andric ReportS << "Expecting ConstantInt as argument #" << ArgNo << " of " << *Call 2745f757f3fSDimitry Andric << "\n"; 2755f757f3fSDimitry Andric report_fatal_error(StringRef(Report)); 2765f757f3fSDimitry Andric } 2775f757f3fSDimitry Andric 2785f757f3fSDimitry Andric static GetElementPtrInst *reconstructGEP(CallInst *Call, int Delta) { 2795f757f3fSDimitry Andric SmallVector<Value *> Indices; 2805f757f3fSDimitry Andric Indices.append(Call->data_operands_begin() + 6 + Delta, 2815f757f3fSDimitry Andric Call->data_operands_end()); 2825f757f3fSDimitry Andric Type *GEPPointeeType = Call->getParamElementType(Delta); 2835f757f3fSDimitry Andric auto *GEP = 2845f757f3fSDimitry Andric GetElementPtrInst::Create(GEPPointeeType, Call->getOperand(Delta), 2855f757f3fSDimitry Andric ArrayRef<Value *>(Indices), Call->getName()); 2865f757f3fSDimitry Andric GEP->setIsInBounds(getOperandAsUnsigned(Call, 5 + Delta)); 2875f757f3fSDimitry Andric return GEP; 2885f757f3fSDimitry Andric } 2895f757f3fSDimitry Andric 2905f757f3fSDimitry Andric template <class T = std::disjunction<LoadInst, StoreInst>> 2915f757f3fSDimitry Andric static void reconstructCommon(CallInst *Call, GetElementPtrInst *GEP, T *Insn, 2925f757f3fSDimitry Andric int Delta) { 2935f757f3fSDimitry Andric Insn->setVolatile(getOperandAsUnsigned(Call, 1 + Delta)); 2945f757f3fSDimitry Andric Insn->setOrdering((AtomicOrdering)getOperandAsUnsigned(Call, 2 + Delta)); 2955f757f3fSDimitry Andric Insn->setSyncScopeID(getOperandAsUnsigned(Call, 3 + Delta)); 2965f757f3fSDimitry Andric unsigned AlignShiftValue = getOperandAsUnsigned(Call, 4 + Delta); 2975f757f3fSDimitry Andric Insn->setAlignment(Align(1ULL << AlignShiftValue)); 2985f757f3fSDimitry Andric GEP->setDebugLoc(Call->getDebugLoc()); 2995f757f3fSDimitry Andric Insn->setDebugLoc(Call->getDebugLoc()); 3005f757f3fSDimitry Andric Insn->setAAMetadata(Call->getAAMetadata()); 3015f757f3fSDimitry Andric } 3025f757f3fSDimitry Andric 3035f757f3fSDimitry Andric std::pair<GetElementPtrInst *, LoadInst *> 3045f757f3fSDimitry Andric BPFPreserveStaticOffsetPass::reconstructLoad(CallInst *Call) { 3055f757f3fSDimitry Andric GetElementPtrInst *GEP = reconstructGEP(Call, 0); 3065f757f3fSDimitry Andric Type *ReturnType = Call->getFunctionType()->getReturnType(); 3075f757f3fSDimitry Andric auto *Load = new LoadInst(ReturnType, GEP, "", 3085f757f3fSDimitry Andric /* These would be set in reconstructCommon */ 3095f757f3fSDimitry Andric false, Align(1)); 3105f757f3fSDimitry Andric reconstructCommon(Call, GEP, Load, 0); 3115f757f3fSDimitry Andric return std::pair{GEP, Load}; 3125f757f3fSDimitry Andric } 3135f757f3fSDimitry Andric 3145f757f3fSDimitry Andric std::pair<GetElementPtrInst *, StoreInst *> 3155f757f3fSDimitry Andric BPFPreserveStaticOffsetPass::reconstructStore(CallInst *Call) { 3165f757f3fSDimitry Andric GetElementPtrInst *GEP = reconstructGEP(Call, 1); 3175f757f3fSDimitry Andric auto *Store = new StoreInst(Call->getOperand(0), GEP, 3185f757f3fSDimitry Andric /* These would be set in reconstructCommon */ 3195f757f3fSDimitry Andric false, Align(1)); 3205f757f3fSDimitry Andric reconstructCommon(Call, GEP, Store, 1); 3215f757f3fSDimitry Andric return std::pair{GEP, Store}; 3225f757f3fSDimitry Andric } 3235f757f3fSDimitry Andric 3245f757f3fSDimitry Andric static bool isZero(Value *V) { 3255f757f3fSDimitry Andric auto *CI = dyn_cast<ConstantInt>(V); 3265f757f3fSDimitry Andric return CI && CI->isZero(); 3275f757f3fSDimitry Andric } 3285f757f3fSDimitry Andric 3295f757f3fSDimitry Andric // Given a chain of GEP instructions collect information necessary to 3305f757f3fSDimitry Andric // merge this chain as a single GEP instruction of form: 3315f757f3fSDimitry Andric // getelementptr %<type>, ptr %p, i32 0, <field_idx1>, <field_idx2>, ... 3325f757f3fSDimitry Andric static bool foldGEPChainAsStructAccess(SmallVector<GetElementPtrInst *> &GEPs, 3335f757f3fSDimitry Andric GEPChainInfo &Info) { 3345f757f3fSDimitry Andric if (GEPs.empty()) 3355f757f3fSDimitry Andric return false; 3365f757f3fSDimitry Andric 3375f757f3fSDimitry Andric if (!all_of(GEPs, [=](GetElementPtrInst *GEP) { 3385f757f3fSDimitry Andric return GEP->hasAllConstantIndices(); 3395f757f3fSDimitry Andric })) 3405f757f3fSDimitry Andric return false; 3415f757f3fSDimitry Andric 3425f757f3fSDimitry Andric GetElementPtrInst *First = GEPs[0]; 3435f757f3fSDimitry Andric Info.InBounds = First->isInBounds(); 3445f757f3fSDimitry Andric Info.SourceElementType = First->getSourceElementType(); 3455f757f3fSDimitry Andric Type *ResultElementType = First->getResultElementType(); 3465f757f3fSDimitry Andric Info.Indices.append(First->idx_begin(), First->idx_end()); 3475f757f3fSDimitry Andric Info.Members.push_back(First); 3485f757f3fSDimitry Andric 3495f757f3fSDimitry Andric for (auto *Iter = GEPs.begin() + 1; Iter != GEPs.end(); ++Iter) { 3505f757f3fSDimitry Andric GetElementPtrInst *GEP = *Iter; 3515f757f3fSDimitry Andric if (!isZero(*GEP->idx_begin())) { 3525f757f3fSDimitry Andric Info.reset(); 3535f757f3fSDimitry Andric return false; 3545f757f3fSDimitry Andric } 3555f757f3fSDimitry Andric if (!GEP->getSourceElementType() || 3565f757f3fSDimitry Andric GEP->getSourceElementType() != ResultElementType) { 3575f757f3fSDimitry Andric Info.reset(); 3585f757f3fSDimitry Andric return false; 3595f757f3fSDimitry Andric } 3605f757f3fSDimitry Andric Info.InBounds &= GEP->isInBounds(); 3615f757f3fSDimitry Andric Info.Indices.append(GEP->idx_begin() + 1, GEP->idx_end()); 3625f757f3fSDimitry Andric Info.Members.push_back(GEP); 3635f757f3fSDimitry Andric ResultElementType = GEP->getResultElementType(); 3645f757f3fSDimitry Andric } 3655f757f3fSDimitry Andric 3665f757f3fSDimitry Andric return true; 3675f757f3fSDimitry Andric } 3685f757f3fSDimitry Andric 3695f757f3fSDimitry Andric // Given a chain of GEP instructions collect information necessary to 3705f757f3fSDimitry Andric // merge this chain as a single GEP instruction of form: 3715f757f3fSDimitry Andric // getelementptr i8, ptr %p, i64 %offset 3725f757f3fSDimitry Andric static bool foldGEPChainAsU8Access(SmallVector<GetElementPtrInst *> &GEPs, 3735f757f3fSDimitry Andric GEPChainInfo &Info) { 3745f757f3fSDimitry Andric if (GEPs.empty()) 3755f757f3fSDimitry Andric return false; 3765f757f3fSDimitry Andric 3775f757f3fSDimitry Andric GetElementPtrInst *First = GEPs[0]; 378*0fca6ea1SDimitry Andric const DataLayout &DL = First->getDataLayout(); 3795f757f3fSDimitry Andric LLVMContext &C = First->getContext(); 3805f757f3fSDimitry Andric Type *PtrTy = First->getType()->getScalarType(); 3815f757f3fSDimitry Andric APInt Offset(DL.getIndexTypeSizeInBits(PtrTy), 0); 3825f757f3fSDimitry Andric for (GetElementPtrInst *GEP : GEPs) { 3835f757f3fSDimitry Andric if (!GEP->accumulateConstantOffset(DL, Offset)) { 3845f757f3fSDimitry Andric Info.reset(); 3855f757f3fSDimitry Andric return false; 3865f757f3fSDimitry Andric } 3875f757f3fSDimitry Andric Info.InBounds &= GEP->isInBounds(); 3885f757f3fSDimitry Andric Info.Members.push_back(GEP); 3895f757f3fSDimitry Andric } 3905f757f3fSDimitry Andric Info.SourceElementType = Type::getInt8Ty(C); 3915f757f3fSDimitry Andric Info.Indices.push_back(ConstantInt::get(C, Offset)); 3925f757f3fSDimitry Andric 3935f757f3fSDimitry Andric return true; 3945f757f3fSDimitry Andric } 3955f757f3fSDimitry Andric 3965f757f3fSDimitry Andric static void reportNonStaticGEPChain(Instruction *Insn) { 3975f757f3fSDimitry Andric auto Msg = DiagnosticInfoUnsupported( 3985f757f3fSDimitry Andric *Insn->getFunction(), 3995f757f3fSDimitry Andric Twine("Non-constant offset in access to a field of a type marked " 4005f757f3fSDimitry Andric "with preserve_static_offset might be rejected by BPF verifier") 4015f757f3fSDimitry Andric .concat(Insn->getDebugLoc() 4025f757f3fSDimitry Andric ? "" 4035f757f3fSDimitry Andric : " (pass -g option to get exact location)"), 4045f757f3fSDimitry Andric Insn->getDebugLoc(), DS_Warning); 4055f757f3fSDimitry Andric Insn->getContext().diagnose(Msg); 4065f757f3fSDimitry Andric } 4075f757f3fSDimitry Andric 4085f757f3fSDimitry Andric static bool allZeroIndices(SmallVector<GetElementPtrInst *> &GEPs) { 4095f757f3fSDimitry Andric return GEPs.empty() || all_of(GEPs, [=](GetElementPtrInst *GEP) { 4105f757f3fSDimitry Andric return GEP->hasAllZeroIndices(); 4115f757f3fSDimitry Andric }); 4125f757f3fSDimitry Andric } 4135f757f3fSDimitry Andric 4145f757f3fSDimitry Andric static bool tryToReplaceWithGEPBuiltin(Instruction *LoadOrStoreTemplate, 4155f757f3fSDimitry Andric SmallVector<GetElementPtrInst *> &GEPs, 4165f757f3fSDimitry Andric Instruction *InsnToReplace) { 4175f757f3fSDimitry Andric GEPChainInfo GEPChain; 4185f757f3fSDimitry Andric if (!foldGEPChainAsStructAccess(GEPs, GEPChain) && 4195f757f3fSDimitry Andric !foldGEPChainAsU8Access(GEPs, GEPChain)) { 4205f757f3fSDimitry Andric return false; 4215f757f3fSDimitry Andric } 4225f757f3fSDimitry Andric Module *M = InsnToReplace->getModule(); 4235f757f3fSDimitry Andric if (auto *Load = dyn_cast<LoadInst>(LoadOrStoreTemplate)) { 4245f757f3fSDimitry Andric Instruction *Replacement = makeGEPAndLoad(M, GEPChain, Load); 4255f757f3fSDimitry Andric Replacement->insertBefore(InsnToReplace); 4265f757f3fSDimitry Andric InsnToReplace->replaceAllUsesWith(Replacement); 4275f757f3fSDimitry Andric } 4285f757f3fSDimitry Andric if (auto *Store = dyn_cast<StoreInst>(LoadOrStoreTemplate)) { 4295f757f3fSDimitry Andric Instruction *Replacement = makeGEPAndStore(M, GEPChain, Store); 4305f757f3fSDimitry Andric Replacement->insertBefore(InsnToReplace); 4315f757f3fSDimitry Andric } 4325f757f3fSDimitry Andric return true; 4335f757f3fSDimitry Andric } 4345f757f3fSDimitry Andric 4355f757f3fSDimitry Andric // Check if U->getPointerOperand() == I 4365f757f3fSDimitry Andric static bool isPointerOperand(Value *I, User *U) { 4375f757f3fSDimitry Andric if (auto *L = dyn_cast<LoadInst>(U)) 4385f757f3fSDimitry Andric return L->getPointerOperand() == I; 4395f757f3fSDimitry Andric if (auto *S = dyn_cast<StoreInst>(U)) 4405f757f3fSDimitry Andric return S->getPointerOperand() == I; 4415f757f3fSDimitry Andric if (auto *GEP = dyn_cast<GetElementPtrInst>(U)) 4425f757f3fSDimitry Andric return GEP->getPointerOperand() == I; 4435f757f3fSDimitry Andric if (auto *Call = isGEPAndLoad(U)) 4445f757f3fSDimitry Andric return Call->getArgOperand(0) == I; 4455f757f3fSDimitry Andric if (auto *Call = isGEPAndStore(U)) 4465f757f3fSDimitry Andric return Call->getArgOperand(1) == I; 4475f757f3fSDimitry Andric return false; 4485f757f3fSDimitry Andric } 4495f757f3fSDimitry Andric 4505f757f3fSDimitry Andric static bool isInlineableCall(User *U) { 4515f757f3fSDimitry Andric if (auto *Call = dyn_cast<CallInst>(U)) 4525f757f3fSDimitry Andric return Call->hasFnAttr(Attribute::InlineHint); 4535f757f3fSDimitry Andric return false; 4545f757f3fSDimitry Andric } 4555f757f3fSDimitry Andric 4565f757f3fSDimitry Andric static void rewriteAccessChain(Instruction *Insn, 4575f757f3fSDimitry Andric SmallVector<GetElementPtrInst *> &GEPs, 4585f757f3fSDimitry Andric SmallVector<Instruction *> &Visited, 4595f757f3fSDimitry Andric bool AllowPatial, bool &StillUsed); 4605f757f3fSDimitry Andric 4615f757f3fSDimitry Andric static void rewriteUses(Instruction *Insn, 4625f757f3fSDimitry Andric SmallVector<GetElementPtrInst *> &GEPs, 4635f757f3fSDimitry Andric SmallVector<Instruction *> &Visited, bool AllowPatial, 4645f757f3fSDimitry Andric bool &StillUsed) { 4655f757f3fSDimitry Andric for (User *U : Insn->users()) { 4665f757f3fSDimitry Andric auto *UI = dyn_cast<Instruction>(U); 4675f757f3fSDimitry Andric if (UI && (isPointerOperand(Insn, UI) || isPreserveStaticOffsetCall(UI) || 4685f757f3fSDimitry Andric isInlineableCall(UI))) 4695f757f3fSDimitry Andric rewriteAccessChain(UI, GEPs, Visited, AllowPatial, StillUsed); 4705f757f3fSDimitry Andric else 4715f757f3fSDimitry Andric LLVM_DEBUG({ 4725f757f3fSDimitry Andric llvm::dbgs() << "unsupported usage in BPFPreserveStaticOffsetPass:\n"; 4735f757f3fSDimitry Andric llvm::dbgs() << " Insn: " << *Insn << "\n"; 4745f757f3fSDimitry Andric llvm::dbgs() << " User: " << *U << "\n"; 4755f757f3fSDimitry Andric }); 4765f757f3fSDimitry Andric } 4775f757f3fSDimitry Andric } 4785f757f3fSDimitry Andric 4795f757f3fSDimitry Andric // A DFS traversal of GEP chain trees starting from Root. 4805f757f3fSDimitry Andric // 4815f757f3fSDimitry Andric // Recursion descends through GEP instructions and 4825f757f3fSDimitry Andric // llvm.preserve.static.offset calls. Recursion stops at any other 4835f757f3fSDimitry Andric // instruction. If load or store instruction is reached it is replaced 4845f757f3fSDimitry Andric // by a call to `llvm.bpf.getelementptr.and.load` or 4855f757f3fSDimitry Andric // `llvm.bpf.getelementptr.and.store` intrinsic. 4865f757f3fSDimitry Andric // If `llvm.bpf.getelementptr.and.load/store` is reached the accumulated 4875f757f3fSDimitry Andric // GEPs are merged into the intrinsic call. 4885f757f3fSDimitry Andric // If nested calls to `llvm.preserve.static.offset` are encountered these 4895f757f3fSDimitry Andric // calls are marked for deletion. 4905f757f3fSDimitry Andric // 4915f757f3fSDimitry Andric // Parameters description: 4925f757f3fSDimitry Andric // - Insn - current position in the tree 4935f757f3fSDimitry Andric // - GEPs - GEP instructions for the current branch 4945f757f3fSDimitry Andric // - Visited - a list of visited instructions in DFS order, 4955f757f3fSDimitry Andric // order is important for unused instruction deletion. 4965f757f3fSDimitry Andric // - AllowPartial - when true GEP chains that can't be folded are 4975f757f3fSDimitry Andric // not reported, otherwise diagnostic message is show for such chains. 4985f757f3fSDimitry Andric // - StillUsed - set to true if one of the GEP chains could not be 4995f757f3fSDimitry Andric // folded, makes sense when AllowPartial is false, means that root 5005f757f3fSDimitry Andric // preserve.static.offset call is still in use and should remain 5015f757f3fSDimitry Andric // until the next run of this pass. 5025f757f3fSDimitry Andric static void rewriteAccessChain(Instruction *Insn, 5035f757f3fSDimitry Andric SmallVector<GetElementPtrInst *> &GEPs, 5045f757f3fSDimitry Andric SmallVector<Instruction *> &Visited, 5055f757f3fSDimitry Andric bool AllowPatial, bool &StillUsed) { 5065f757f3fSDimitry Andric auto MarkAndTraverseUses = [&]() { 5075f757f3fSDimitry Andric Visited.push_back(Insn); 5085f757f3fSDimitry Andric rewriteUses(Insn, GEPs, Visited, AllowPatial, StillUsed); 5095f757f3fSDimitry Andric }; 5105f757f3fSDimitry Andric auto TryToReplace = [&](Instruction *LoadOrStore) { 5115f757f3fSDimitry Andric // Do nothing for (preserve.static.offset (load/store ..)) or for 5125f757f3fSDimitry Andric // GEPs with zero indices. Such constructs lead to zero offset and 5135f757f3fSDimitry Andric // are simplified by other passes. 5145f757f3fSDimitry Andric if (allZeroIndices(GEPs)) 5155f757f3fSDimitry Andric return; 5165f757f3fSDimitry Andric if (tryToReplaceWithGEPBuiltin(LoadOrStore, GEPs, Insn)) { 5175f757f3fSDimitry Andric Visited.push_back(Insn); 5185f757f3fSDimitry Andric return; 5195f757f3fSDimitry Andric } 5205f757f3fSDimitry Andric if (!AllowPatial) 5215f757f3fSDimitry Andric reportNonStaticGEPChain(Insn); 5225f757f3fSDimitry Andric StillUsed = true; 5235f757f3fSDimitry Andric }; 5245f757f3fSDimitry Andric if (isa<LoadInst>(Insn) || isa<StoreInst>(Insn)) { 5255f757f3fSDimitry Andric TryToReplace(Insn); 5265f757f3fSDimitry Andric } else if (isGEPAndLoad(Insn)) { 5275f757f3fSDimitry Andric auto [GEP, Load] = 5285f757f3fSDimitry Andric BPFPreserveStaticOffsetPass::reconstructLoad(cast<CallInst>(Insn)); 5295f757f3fSDimitry Andric GEPs.push_back(GEP); 5305f757f3fSDimitry Andric TryToReplace(Load); 5315f757f3fSDimitry Andric GEPs.pop_back(); 5325f757f3fSDimitry Andric delete Load; 5335f757f3fSDimitry Andric delete GEP; 5345f757f3fSDimitry Andric } else if (isGEPAndStore(Insn)) { 5355f757f3fSDimitry Andric // This case can't be merged with the above because 5365f757f3fSDimitry Andric // `delete Load` / `delete Store` wants a concrete type, 5375f757f3fSDimitry Andric // destructor of Instruction is protected. 5385f757f3fSDimitry Andric auto [GEP, Store] = 5395f757f3fSDimitry Andric BPFPreserveStaticOffsetPass::reconstructStore(cast<CallInst>(Insn)); 5405f757f3fSDimitry Andric GEPs.push_back(GEP); 5415f757f3fSDimitry Andric TryToReplace(Store); 5425f757f3fSDimitry Andric GEPs.pop_back(); 5435f757f3fSDimitry Andric delete Store; 5445f757f3fSDimitry Andric delete GEP; 5455f757f3fSDimitry Andric } else if (auto *GEP = dyn_cast<GetElementPtrInst>(Insn)) { 5465f757f3fSDimitry Andric GEPs.push_back(GEP); 5475f757f3fSDimitry Andric MarkAndTraverseUses(); 5485f757f3fSDimitry Andric GEPs.pop_back(); 5495f757f3fSDimitry Andric } else if (isPreserveStaticOffsetCall(Insn)) { 5505f757f3fSDimitry Andric MarkAndTraverseUses(); 5515f757f3fSDimitry Andric } else if (isInlineableCall(Insn)) { 5525f757f3fSDimitry Andric // Preserve preserve.static.offset call for parameters of 5535f757f3fSDimitry Andric // functions that might be inlined. These would be removed on a 5545f757f3fSDimitry Andric // second pass after inlining. 5555f757f3fSDimitry Andric // Might happen when a pointer to a preserve_static_offset 5565f757f3fSDimitry Andric // structure is passed as parameter of a function that would be 5575f757f3fSDimitry Andric // inlined inside a loop that would be unrolled. 5585f757f3fSDimitry Andric if (AllowPatial) 5595f757f3fSDimitry Andric StillUsed = true; 5605f757f3fSDimitry Andric } else { 5615f757f3fSDimitry Andric SmallString<128> Buf; 5625f757f3fSDimitry Andric raw_svector_ostream BufStream(Buf); 5635f757f3fSDimitry Andric BufStream << *Insn; 5645f757f3fSDimitry Andric report_fatal_error( 5655f757f3fSDimitry Andric Twine("Unexpected rewriteAccessChain Insn = ").concat(Buf)); 5665f757f3fSDimitry Andric } 5675f757f3fSDimitry Andric } 5685f757f3fSDimitry Andric 5695f757f3fSDimitry Andric static void removeMarkerCall(Instruction *Marker) { 5705f757f3fSDimitry Andric Marker->replaceAllUsesWith(Marker->getOperand(0)); 5715f757f3fSDimitry Andric Marker->eraseFromParent(); 5725f757f3fSDimitry Andric } 5735f757f3fSDimitry Andric 5745f757f3fSDimitry Andric static bool rewriteAccessChain(Instruction *Marker, bool AllowPatial, 5755f757f3fSDimitry Andric SmallPtrSetImpl<Instruction *> &RemovedMarkers) { 5765f757f3fSDimitry Andric SmallVector<GetElementPtrInst *> GEPs; 5775f757f3fSDimitry Andric SmallVector<Instruction *> Visited; 5785f757f3fSDimitry Andric bool StillUsed = false; 5795f757f3fSDimitry Andric rewriteUses(Marker, GEPs, Visited, AllowPatial, StillUsed); 5805f757f3fSDimitry Andric // Check if Visited instructions could be removed, iterate in 5815f757f3fSDimitry Andric // reverse to unblock instructions higher in the chain. 5825f757f3fSDimitry Andric for (auto V = Visited.rbegin(); V != Visited.rend(); ++V) { 5835f757f3fSDimitry Andric if (isPreserveStaticOffsetCall(*V)) { 5845f757f3fSDimitry Andric removeMarkerCall(*V); 5855f757f3fSDimitry Andric RemovedMarkers.insert(*V); 5865f757f3fSDimitry Andric } else if ((*V)->use_empty()) { 5875f757f3fSDimitry Andric (*V)->eraseFromParent(); 5885f757f3fSDimitry Andric } 5895f757f3fSDimitry Andric } 5905f757f3fSDimitry Andric return StillUsed; 5915f757f3fSDimitry Andric } 5925f757f3fSDimitry Andric 5935f757f3fSDimitry Andric static std::vector<Instruction *> 5945f757f3fSDimitry Andric collectPreserveStaticOffsetCalls(Function &F) { 5955f757f3fSDimitry Andric std::vector<Instruction *> Calls; 5965f757f3fSDimitry Andric for (Instruction &Insn : instructions(F)) 5975f757f3fSDimitry Andric if (isPreserveStaticOffsetCall(&Insn)) 5985f757f3fSDimitry Andric Calls.push_back(&Insn); 5995f757f3fSDimitry Andric return Calls; 6005f757f3fSDimitry Andric } 6015f757f3fSDimitry Andric 6025f757f3fSDimitry Andric bool isPreserveArrayIndex(Value *V) { 6035f757f3fSDimitry Andric return isIntrinsicCall(V, Intrinsic::preserve_array_access_index); 6045f757f3fSDimitry Andric } 6055f757f3fSDimitry Andric 6065f757f3fSDimitry Andric bool isPreserveStructIndex(Value *V) { 6075f757f3fSDimitry Andric return isIntrinsicCall(V, Intrinsic::preserve_struct_access_index); 6085f757f3fSDimitry Andric } 6095f757f3fSDimitry Andric 6105f757f3fSDimitry Andric bool isPreserveUnionIndex(Value *V) { 6115f757f3fSDimitry Andric return isIntrinsicCall(V, Intrinsic::preserve_union_access_index); 6125f757f3fSDimitry Andric } 6135f757f3fSDimitry Andric 6145f757f3fSDimitry Andric static void removePAICalls(Instruction *Marker) { 6155f757f3fSDimitry Andric auto IsPointerOperand = [](Value *Op, User *U) { 6165f757f3fSDimitry Andric if (auto *GEP = dyn_cast<GetElementPtrInst>(U)) 6175f757f3fSDimitry Andric return GEP->getPointerOperand() == Op; 6185f757f3fSDimitry Andric if (isPreserveStaticOffsetCall(U) || isPreserveArrayIndex(U) || 6195f757f3fSDimitry Andric isPreserveStructIndex(U) || isPreserveUnionIndex(U)) 6205f757f3fSDimitry Andric return cast<CallInst>(U)->getArgOperand(0) == Op; 6215f757f3fSDimitry Andric return false; 6225f757f3fSDimitry Andric }; 6235f757f3fSDimitry Andric 6245f757f3fSDimitry Andric SmallVector<Value *, 32> WorkList; 6255f757f3fSDimitry Andric WorkList.push_back(Marker); 6265f757f3fSDimitry Andric do { 6275f757f3fSDimitry Andric Value *V = WorkList.pop_back_val(); 6285f757f3fSDimitry Andric for (User *U : V->users()) 6295f757f3fSDimitry Andric if (IsPointerOperand(V, U)) 6305f757f3fSDimitry Andric WorkList.push_back(U); 6315f757f3fSDimitry Andric auto *Call = dyn_cast<CallInst>(V); 6325f757f3fSDimitry Andric if (!Call) 6335f757f3fSDimitry Andric continue; 6345f757f3fSDimitry Andric if (isPreserveArrayIndex(V)) 6355f757f3fSDimitry Andric BPFCoreSharedInfo::removeArrayAccessCall(Call); 6365f757f3fSDimitry Andric else if (isPreserveStructIndex(V)) 6375f757f3fSDimitry Andric BPFCoreSharedInfo::removeStructAccessCall(Call); 6385f757f3fSDimitry Andric else if (isPreserveUnionIndex(V)) 6395f757f3fSDimitry Andric BPFCoreSharedInfo::removeUnionAccessCall(Call); 6405f757f3fSDimitry Andric } while (!WorkList.empty()); 6415f757f3fSDimitry Andric } 6425f757f3fSDimitry Andric 6435f757f3fSDimitry Andric // Look for sequences: 6445f757f3fSDimitry Andric // - llvm.preserve.static.offset -> getelementptr... -> load 6455f757f3fSDimitry Andric // - llvm.preserve.static.offset -> getelementptr... -> store 6465f757f3fSDimitry Andric // And replace those with calls to intrinsics: 6475f757f3fSDimitry Andric // - llvm.bpf.getelementptr.and.load 6485f757f3fSDimitry Andric // - llvm.bpf.getelementptr.and.store 6495f757f3fSDimitry Andric static bool rewriteFunction(Function &F, bool AllowPartial) { 6505f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "********** BPFPreserveStaticOffsetPass (AllowPartial=" 6515f757f3fSDimitry Andric << AllowPartial << ") ************\n"); 6525f757f3fSDimitry Andric 6535f757f3fSDimitry Andric auto MarkerCalls = collectPreserveStaticOffsetCalls(F); 6545f757f3fSDimitry Andric SmallPtrSet<Instruction *, 16> RemovedMarkers; 6555f757f3fSDimitry Andric 6565f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "There are " << MarkerCalls.size() 6575f757f3fSDimitry Andric << " preserve.static.offset calls\n"); 6585f757f3fSDimitry Andric 6595f757f3fSDimitry Andric if (MarkerCalls.empty()) 6605f757f3fSDimitry Andric return false; 6615f757f3fSDimitry Andric 6625f757f3fSDimitry Andric for (auto *Call : MarkerCalls) 6635f757f3fSDimitry Andric removePAICalls(Call); 6645f757f3fSDimitry Andric 6655f757f3fSDimitry Andric for (auto *Call : MarkerCalls) { 6665f757f3fSDimitry Andric if (RemovedMarkers.contains(Call)) 6675f757f3fSDimitry Andric continue; 6685f757f3fSDimitry Andric bool StillUsed = rewriteAccessChain(Call, AllowPartial, RemovedMarkers); 6695f757f3fSDimitry Andric if (!StillUsed || !AllowPartial) 6705f757f3fSDimitry Andric removeMarkerCall(Call); 6715f757f3fSDimitry Andric } 6725f757f3fSDimitry Andric 6735f757f3fSDimitry Andric return true; 6745f757f3fSDimitry Andric } 6755f757f3fSDimitry Andric 6765f757f3fSDimitry Andric PreservedAnalyses 6775f757f3fSDimitry Andric llvm::BPFPreserveStaticOffsetPass::run(Function &F, 6785f757f3fSDimitry Andric FunctionAnalysisManager &AM) { 6795f757f3fSDimitry Andric return rewriteFunction(F, AllowPartial) ? PreservedAnalyses::none() 6805f757f3fSDimitry Andric : PreservedAnalyses::all(); 6815f757f3fSDimitry Andric } 682