xref: /llvm-project/llvm/lib/Target/BPF/BPFPreserveStaticOffset.cpp (revision 8e702735090388a3231a863e343f880d0f96fecb)
1030b8cb1SEduard Zingerman //===------ BPFPreserveStaticOffset.cpp -----------------------------------===//
2030b8cb1SEduard Zingerman //
3030b8cb1SEduard Zingerman // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4030b8cb1SEduard Zingerman // See https://llvm.org/LICENSE.txt for license information.
5030b8cb1SEduard Zingerman // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6030b8cb1SEduard Zingerman //
7030b8cb1SEduard Zingerman //===----------------------------------------------------------------------===//
8030b8cb1SEduard Zingerman //
9030b8cb1SEduard Zingerman // TLDR: replaces llvm.preserve.static.offset + GEP + load / store
10030b8cb1SEduard Zingerman //           with llvm.bpf.getelementptr.and.load / store
11030b8cb1SEduard Zingerman //
12030b8cb1SEduard Zingerman // This file implements BPFPreserveStaticOffsetPass transformation.
13030b8cb1SEduard Zingerman // This transformation address two BPF verifier specific issues:
14030b8cb1SEduard Zingerman //
15030b8cb1SEduard Zingerman // (a) Access to the fields of some structural types is allowed only
16030b8cb1SEduard Zingerman //     using load and store instructions with static immediate offsets.
17030b8cb1SEduard Zingerman //
18030b8cb1SEduard Zingerman //     Examples of such types are `struct __sk_buff` and `struct
19030b8cb1SEduard Zingerman //     bpf_sock_ops`.  This is so because offsets of the fields of
20030b8cb1SEduard Zingerman //     these structures do not match real offsets in the running
21030b8cb1SEduard Zingerman //     kernel. During BPF program load LDX and STX instructions
22030b8cb1SEduard Zingerman //     referring to the fields of these types are rewritten so that
23030b8cb1SEduard Zingerman //     offsets match real offsets. For this rewrite to happen field
24030b8cb1SEduard Zingerman //     offsets have to be encoded as immediate operands of the
25030b8cb1SEduard Zingerman //     instructions.
26030b8cb1SEduard Zingerman //
27030b8cb1SEduard Zingerman //     See kernel/bpf/verifier.c:convert_ctx_access function in the
28030b8cb1SEduard Zingerman //     Linux kernel source tree for details.
29030b8cb1SEduard Zingerman //
30030b8cb1SEduard Zingerman // (b) Pointers to context parameters of BPF programs must not be
31030b8cb1SEduard Zingerman //     modified before access.
32030b8cb1SEduard Zingerman //
33030b8cb1SEduard Zingerman //     During BPF program verification a tag PTR_TO_CTX is tracked for
34030b8cb1SEduard Zingerman //     register values. In case if register with such tag is modified
35030b8cb1SEduard Zingerman //     BPF program is not allowed to read or write memory using this
36030b8cb1SEduard Zingerman //     register. See kernel/bpf/verifier.c:check_mem_access function
37030b8cb1SEduard Zingerman //     in the Linux kernel source tree for details.
38030b8cb1SEduard Zingerman //
39030b8cb1SEduard Zingerman // The following sequence of the IR instructions:
40030b8cb1SEduard Zingerman //
41030b8cb1SEduard Zingerman //   %x = getelementptr %ptr, %constant_offset
42030b8cb1SEduard Zingerman //   %y = load %x
43030b8cb1SEduard Zingerman //
44030b8cb1SEduard Zingerman // Is translated as a single machine instruction:
45030b8cb1SEduard Zingerman //
46030b8cb1SEduard Zingerman //   LDW %ptr, %constant_offset
47030b8cb1SEduard Zingerman //
48030b8cb1SEduard Zingerman // In order for cases (a) and (b) to work the sequence %x-%y above has
49030b8cb1SEduard Zingerman // to be preserved by the IR passes.
50030b8cb1SEduard Zingerman //
51030b8cb1SEduard Zingerman // However, several optimization passes might sink `load` instruction
52030b8cb1SEduard Zingerman // or hoist `getelementptr` instruction so that the instructions are
53030b8cb1SEduard Zingerman // no longer in sequence. Examples of such passes are:
54030b8cb1SEduard Zingerman // SimplifyCFGPass, InstCombinePass, GVNPass.
55030b8cb1SEduard Zingerman // After such modification the verifier would reject the BPF program.
56030b8cb1SEduard Zingerman //
57030b8cb1SEduard Zingerman // To avoid this issue the patterns like (load/store (getelementptr ...))
58030b8cb1SEduard Zingerman // are replaced by calls to BPF specific intrinsic functions:
59030b8cb1SEduard Zingerman // - llvm.bpf.getelementptr.and.load
60030b8cb1SEduard Zingerman // - llvm.bpf.getelementptr.and.store
61030b8cb1SEduard Zingerman //
62030b8cb1SEduard Zingerman // These calls are lowered back to (load/store (getelementptr ...))
63030b8cb1SEduard Zingerman // by BPFCheckAndAdjustIR pass right before the translation from IR to
64030b8cb1SEduard Zingerman // machine instructions.
65030b8cb1SEduard Zingerman //
66030b8cb1SEduard Zingerman // The transformation is split into the following steps:
67030b8cb1SEduard Zingerman // - When IR is generated from AST the calls to intrinsic function
68030b8cb1SEduard Zingerman //   llvm.preserve.static.offset are inserted.
69030b8cb1SEduard Zingerman // - BPFPreserveStaticOffsetPass is executed as early as possible
70030b8cb1SEduard Zingerman //   with AllowPatial set to true, this handles marked GEP chains
71030b8cb1SEduard Zingerman //   with constant offsets.
72030b8cb1SEduard Zingerman // - BPFPreserveStaticOffsetPass is executed at ScalarOptimizerLateEPCallback
73030b8cb1SEduard Zingerman //   with AllowPatial set to false, this handles marked GEP chains
74030b8cb1SEduard Zingerman //   with offsets that became constant after loop unrolling, e.g.
75030b8cb1SEduard Zingerman //   to handle the following code:
76030b8cb1SEduard Zingerman //
77030b8cb1SEduard Zingerman // struct context { int x[4]; } __attribute__((preserve_static_offset));
78030b8cb1SEduard Zingerman //
79030b8cb1SEduard Zingerman //   struct context *ctx = ...;
80030b8cb1SEduard Zingerman // #pragma clang loop unroll(full)
81030b8cb1SEduard Zingerman //   for (int i = 0; i < 4; ++i)
82030b8cb1SEduard Zingerman //     foo(ctx->x[i]);
83030b8cb1SEduard Zingerman //
84030b8cb1SEduard Zingerman // The early BPFPreserveStaticOffsetPass run is necessary to allow
85030b8cb1SEduard Zingerman // additional GVN / CSE opportunities after functions inlining.
86030b8cb1SEduard Zingerman // The relative order of optimization applied to function:
87030b8cb1SEduard Zingerman // - early stage (1)
88030b8cb1SEduard Zingerman // - ...
89030b8cb1SEduard Zingerman // - function inlining (2)
90030b8cb1SEduard Zingerman // - ...
91030b8cb1SEduard Zingerman // - loop unrolling
92030b8cb1SEduard Zingerman // - ...
93030b8cb1SEduard Zingerman // - ScalarOptimizerLateEPCallback (3)
94030b8cb1SEduard Zingerman //
95030b8cb1SEduard Zingerman // When function A is inlined into function B all optimizations for A
96030b8cb1SEduard Zingerman // are already done, while some passes remain for B. In case if
97030b8cb1SEduard Zingerman // BPFPreserveStaticOffsetPass is done at (3) but not done at (1)
98030b8cb1SEduard Zingerman // the code after (2) would contain a mix of
99030b8cb1SEduard Zingerman // (load (gep %p)) and (get.and.load %p) usages:
100030b8cb1SEduard Zingerman // - the (load (gep %p)) would come from the calling function;
101030b8cb1SEduard Zingerman // - the (get.and.load %p) would come from the callee function.
102030b8cb1SEduard Zingerman // Thus clobbering CSE / GVN passes done after inlining.
103030b8cb1SEduard Zingerman 
104030b8cb1SEduard Zingerman #include "BPF.h"
105030b8cb1SEduard Zingerman #include "BPFCORE.h"
106030b8cb1SEduard Zingerman #include "llvm/ADT/SmallPtrSet.h"
107030b8cb1SEduard Zingerman #include "llvm/ADT/SmallVector.h"
108030b8cb1SEduard Zingerman #include "llvm/IR/Attributes.h"
109030b8cb1SEduard Zingerman #include "llvm/IR/BasicBlock.h"
110030b8cb1SEduard Zingerman #include "llvm/IR/Constants.h"
111030b8cb1SEduard Zingerman #include "llvm/IR/DebugInfoMetadata.h"
112030b8cb1SEduard Zingerman #include "llvm/IR/DiagnosticInfo.h"
113030b8cb1SEduard Zingerman #include "llvm/IR/IRBuilder.h"
114030b8cb1SEduard Zingerman #include "llvm/IR/InstIterator.h"
115030b8cb1SEduard Zingerman #include "llvm/IR/Instructions.h"
116030b8cb1SEduard Zingerman #include "llvm/IR/Intrinsics.h"
117030b8cb1SEduard Zingerman #include "llvm/IR/IntrinsicsBPF.h"
11874deadf1SNikita Popov #include "llvm/IR/Module.h"
119030b8cb1SEduard Zingerman #include "llvm/Support/Debug.h"
120030b8cb1SEduard Zingerman #include "llvm/Support/ErrorHandling.h"
121030b8cb1SEduard Zingerman 
122030b8cb1SEduard Zingerman #define DEBUG_TYPE "bpf-preserve-static-offset"
123030b8cb1SEduard Zingerman 
124030b8cb1SEduard Zingerman using namespace llvm;
125030b8cb1SEduard Zingerman 
126030b8cb1SEduard Zingerman static const unsigned GepAndLoadFirstIdxArg = 6;
127030b8cb1SEduard Zingerman static const unsigned GepAndStoreFirstIdxArg = 7;
128030b8cb1SEduard Zingerman 
129030b8cb1SEduard Zingerman static bool isIntrinsicCall(Value *I, Intrinsic::ID Id) {
130030b8cb1SEduard Zingerman   if (auto *Call = dyn_cast<CallInst>(I))
131030b8cb1SEduard Zingerman     if (Function *Func = Call->getCalledFunction())
132030b8cb1SEduard Zingerman       return Func->getIntrinsicID() == Id;
133030b8cb1SEduard Zingerman   return false;
134030b8cb1SEduard Zingerman }
135030b8cb1SEduard Zingerman 
136030b8cb1SEduard Zingerman static bool isPreserveStaticOffsetCall(Value *I) {
137030b8cb1SEduard Zingerman   return isIntrinsicCall(I, Intrinsic::preserve_static_offset);
138030b8cb1SEduard Zingerman }
139030b8cb1SEduard Zingerman 
140030b8cb1SEduard Zingerman static CallInst *isGEPAndLoad(Value *I) {
141030b8cb1SEduard Zingerman   if (isIntrinsicCall(I, Intrinsic::bpf_getelementptr_and_load))
142030b8cb1SEduard Zingerman     return cast<CallInst>(I);
143030b8cb1SEduard Zingerman   return nullptr;
144030b8cb1SEduard Zingerman }
145030b8cb1SEduard Zingerman 
146030b8cb1SEduard Zingerman static CallInst *isGEPAndStore(Value *I) {
147030b8cb1SEduard Zingerman   if (isIntrinsicCall(I, Intrinsic::bpf_getelementptr_and_store))
148030b8cb1SEduard Zingerman     return cast<CallInst>(I);
149030b8cb1SEduard Zingerman   return nullptr;
150030b8cb1SEduard Zingerman }
151030b8cb1SEduard Zingerman 
152030b8cb1SEduard Zingerman template <class T = Instruction>
153030b8cb1SEduard Zingerman static DILocation *mergeDILocations(SmallVector<T *> &Insns) {
154030b8cb1SEduard Zingerman   DILocation *Merged = (*Insns.begin())->getDebugLoc();
155030b8cb1SEduard Zingerman   for (T *I : Insns)
156030b8cb1SEduard Zingerman     Merged = DILocation::getMergedLocation(Merged, I->getDebugLoc());
157030b8cb1SEduard Zingerman   return Merged;
158030b8cb1SEduard Zingerman }
159030b8cb1SEduard Zingerman 
160030b8cb1SEduard Zingerman static CallInst *makeIntrinsicCall(Module *M,
161030b8cb1SEduard Zingerman                                    Intrinsic::BPFIntrinsics Intrinsic,
162030b8cb1SEduard Zingerman                                    ArrayRef<Type *> Types,
163030b8cb1SEduard Zingerman                                    ArrayRef<Value *> Args) {
164030b8cb1SEduard Zingerman 
165fa789dffSRahul Joshi   Function *Fn = Intrinsic::getOrInsertDeclaration(M, Intrinsic, Types);
166030b8cb1SEduard Zingerman   return CallInst::Create(Fn, Args);
167030b8cb1SEduard Zingerman }
168030b8cb1SEduard Zingerman 
169030b8cb1SEduard Zingerman static void setParamElementType(CallInst *Call, unsigned ArgNo, Type *Type) {
170030b8cb1SEduard Zingerman   LLVMContext &C = Call->getContext();
171030b8cb1SEduard Zingerman   Call->addParamAttr(ArgNo, Attribute::get(C, Attribute::ElementType, Type));
172030b8cb1SEduard Zingerman }
173030b8cb1SEduard Zingerman 
174030b8cb1SEduard Zingerman static void setParamReadNone(CallInst *Call, unsigned ArgNo) {
175030b8cb1SEduard Zingerman   LLVMContext &C = Call->getContext();
176030b8cb1SEduard Zingerman   Call->addParamAttr(ArgNo, Attribute::get(C, Attribute::ReadNone));
177030b8cb1SEduard Zingerman }
178030b8cb1SEduard Zingerman 
179030b8cb1SEduard Zingerman static void setParamReadOnly(CallInst *Call, unsigned ArgNo) {
180030b8cb1SEduard Zingerman   LLVMContext &C = Call->getContext();
181030b8cb1SEduard Zingerman   Call->addParamAttr(ArgNo, Attribute::get(C, Attribute::ReadOnly));
182030b8cb1SEduard Zingerman }
183030b8cb1SEduard Zingerman 
184030b8cb1SEduard Zingerman static void setParamWriteOnly(CallInst *Call, unsigned ArgNo) {
185030b8cb1SEduard Zingerman   LLVMContext &C = Call->getContext();
186030b8cb1SEduard Zingerman   Call->addParamAttr(ArgNo, Attribute::get(C, Attribute::WriteOnly));
187030b8cb1SEduard Zingerman }
188030b8cb1SEduard Zingerman 
189030b8cb1SEduard Zingerman namespace {
190030b8cb1SEduard Zingerman struct GEPChainInfo {
191030b8cb1SEduard Zingerman   bool InBounds;
192030b8cb1SEduard Zingerman   Type *SourceElementType;
193030b8cb1SEduard Zingerman   SmallVector<Value *> Indices;
194030b8cb1SEduard Zingerman   SmallVector<GetElementPtrInst *> Members;
195030b8cb1SEduard Zingerman 
196030b8cb1SEduard Zingerman   GEPChainInfo() { reset(); }
197030b8cb1SEduard Zingerman 
198030b8cb1SEduard Zingerman   void reset() {
199030b8cb1SEduard Zingerman     InBounds = true;
200030b8cb1SEduard Zingerman     SourceElementType = nullptr;
201030b8cb1SEduard Zingerman     Indices.clear();
202030b8cb1SEduard Zingerman     Members.clear();
203030b8cb1SEduard Zingerman   }
204030b8cb1SEduard Zingerman };
205030b8cb1SEduard Zingerman } // Anonymous namespace
206030b8cb1SEduard Zingerman 
207030b8cb1SEduard Zingerman template <class T = std::disjunction<LoadInst, StoreInst>>
208030b8cb1SEduard Zingerman static void fillCommonArgs(LLVMContext &C, SmallVector<Value *> &Args,
209030b8cb1SEduard Zingerman                            GEPChainInfo &GEP, T *Insn) {
210030b8cb1SEduard Zingerman   Type *Int8Ty = Type::getInt8Ty(C);
211030b8cb1SEduard Zingerman   Type *Int1Ty = Type::getInt1Ty(C);
212030b8cb1SEduard Zingerman   // Implementation of Align guarantees that ShiftValue < 64
213030b8cb1SEduard Zingerman   unsigned AlignShiftValue = Log2_64(Insn->getAlign().value());
214030b8cb1SEduard Zingerman   Args.push_back(GEP.Members[0]->getPointerOperand());
215030b8cb1SEduard Zingerman   Args.push_back(ConstantInt::get(Int1Ty, Insn->isVolatile()));
216030b8cb1SEduard Zingerman   Args.push_back(ConstantInt::get(Int8Ty, (unsigned)Insn->getOrdering()));
217030b8cb1SEduard Zingerman   Args.push_back(ConstantInt::get(Int8Ty, (unsigned)Insn->getSyncScopeID()));
218030b8cb1SEduard Zingerman   Args.push_back(ConstantInt::get(Int8Ty, AlignShiftValue));
219030b8cb1SEduard Zingerman   Args.push_back(ConstantInt::get(Int1Ty, GEP.InBounds));
220030b8cb1SEduard Zingerman   Args.append(GEP.Indices.begin(), GEP.Indices.end());
221030b8cb1SEduard Zingerman }
222030b8cb1SEduard Zingerman 
223030b8cb1SEduard Zingerman static Instruction *makeGEPAndLoad(Module *M, GEPChainInfo &GEP,
224030b8cb1SEduard Zingerman                                    LoadInst *Load) {
225030b8cb1SEduard Zingerman   SmallVector<Value *> Args;
226030b8cb1SEduard Zingerman   fillCommonArgs(M->getContext(), Args, GEP, Load);
227030b8cb1SEduard Zingerman   CallInst *Call = makeIntrinsicCall(M, Intrinsic::bpf_getelementptr_and_load,
228030b8cb1SEduard Zingerman                                      {Load->getType()}, Args);
229030b8cb1SEduard Zingerman   setParamElementType(Call, 0, GEP.SourceElementType);
230030b8cb1SEduard Zingerman   Call->applyMergedLocation(mergeDILocations(GEP.Members), Load->getDebugLoc());
231030b8cb1SEduard Zingerman   Call->setName((*GEP.Members.rbegin())->getName());
232030b8cb1SEduard Zingerman   if (Load->isUnordered()) {
233030b8cb1SEduard Zingerman     Call->setOnlyReadsMemory();
234030b8cb1SEduard Zingerman     Call->setOnlyAccessesArgMemory();
235030b8cb1SEduard Zingerman     setParamReadOnly(Call, 0);
236030b8cb1SEduard Zingerman   }
237030b8cb1SEduard Zingerman   for (unsigned I = GepAndLoadFirstIdxArg; I < Args.size(); ++I)
238030b8cb1SEduard Zingerman     Call->addParamAttr(I, Attribute::ImmArg);
239030b8cb1SEduard Zingerman   Call->setAAMetadata(Load->getAAMetadata());
240030b8cb1SEduard Zingerman   return Call;
241030b8cb1SEduard Zingerman }
242030b8cb1SEduard Zingerman 
243030b8cb1SEduard Zingerman static Instruction *makeGEPAndStore(Module *M, GEPChainInfo &GEP,
244030b8cb1SEduard Zingerman                                     StoreInst *Store) {
245030b8cb1SEduard Zingerman   SmallVector<Value *> Args;
246030b8cb1SEduard Zingerman   Args.push_back(Store->getValueOperand());
247030b8cb1SEduard Zingerman   fillCommonArgs(M->getContext(), Args, GEP, Store);
248030b8cb1SEduard Zingerman   CallInst *Call =
249030b8cb1SEduard Zingerman       makeIntrinsicCall(M, Intrinsic::bpf_getelementptr_and_store,
250030b8cb1SEduard Zingerman                         {Store->getValueOperand()->getType()}, Args);
251030b8cb1SEduard Zingerman   setParamElementType(Call, 1, GEP.SourceElementType);
252030b8cb1SEduard Zingerman   if (Store->getValueOperand()->getType()->isPointerTy())
253030b8cb1SEduard Zingerman     setParamReadNone(Call, 0);
254030b8cb1SEduard Zingerman   Call->applyMergedLocation(mergeDILocations(GEP.Members),
255030b8cb1SEduard Zingerman                             Store->getDebugLoc());
256030b8cb1SEduard Zingerman   if (Store->isUnordered()) {
257030b8cb1SEduard Zingerman     Call->setOnlyWritesMemory();
258030b8cb1SEduard Zingerman     Call->setOnlyAccessesArgMemory();
259030b8cb1SEduard Zingerman     setParamWriteOnly(Call, 1);
260030b8cb1SEduard Zingerman   }
261030b8cb1SEduard Zingerman   for (unsigned I = GepAndStoreFirstIdxArg; I < Args.size(); ++I)
262030b8cb1SEduard Zingerman     Call->addParamAttr(I, Attribute::ImmArg);
263030b8cb1SEduard Zingerman   Call->setAAMetadata(Store->getAAMetadata());
264030b8cb1SEduard Zingerman   return Call;
265030b8cb1SEduard Zingerman }
266030b8cb1SEduard Zingerman 
267030b8cb1SEduard Zingerman static unsigned getOperandAsUnsigned(CallInst *Call, unsigned ArgNo) {
268030b8cb1SEduard Zingerman   if (auto *Int = dyn_cast<ConstantInt>(Call->getOperand(ArgNo)))
269030b8cb1SEduard Zingerman     return Int->getValue().getZExtValue();
270030b8cb1SEduard Zingerman   std::string Report;
271030b8cb1SEduard Zingerman   raw_string_ostream ReportS(Report);
272030b8cb1SEduard Zingerman   ReportS << "Expecting ConstantInt as argument #" << ArgNo << " of " << *Call
273030b8cb1SEduard Zingerman           << "\n";
274030b8cb1SEduard Zingerman   report_fatal_error(StringRef(Report));
275030b8cb1SEduard Zingerman }
276030b8cb1SEduard Zingerman 
277030b8cb1SEduard Zingerman static GetElementPtrInst *reconstructGEP(CallInst *Call, int Delta) {
278030b8cb1SEduard Zingerman   SmallVector<Value *> Indices;
279030b8cb1SEduard Zingerman   Indices.append(Call->data_operands_begin() + 6 + Delta,
280030b8cb1SEduard Zingerman                  Call->data_operands_end());
281030b8cb1SEduard Zingerman   Type *GEPPointeeType = Call->getParamElementType(Delta);
282030b8cb1SEduard Zingerman   auto *GEP =
283030b8cb1SEduard Zingerman       GetElementPtrInst::Create(GEPPointeeType, Call->getOperand(Delta),
284030b8cb1SEduard Zingerman                                 ArrayRef<Value *>(Indices), Call->getName());
285030b8cb1SEduard Zingerman   GEP->setIsInBounds(getOperandAsUnsigned(Call, 5 + Delta));
286030b8cb1SEduard Zingerman   return GEP;
287030b8cb1SEduard Zingerman }
288030b8cb1SEduard Zingerman 
289030b8cb1SEduard Zingerman template <class T = std::disjunction<LoadInst, StoreInst>>
290030b8cb1SEduard Zingerman static void reconstructCommon(CallInst *Call, GetElementPtrInst *GEP, T *Insn,
291030b8cb1SEduard Zingerman                               int Delta) {
292030b8cb1SEduard Zingerman   Insn->setVolatile(getOperandAsUnsigned(Call, 1 + Delta));
293030b8cb1SEduard Zingerman   Insn->setOrdering((AtomicOrdering)getOperandAsUnsigned(Call, 2 + Delta));
294030b8cb1SEduard Zingerman   Insn->setSyncScopeID(getOperandAsUnsigned(Call, 3 + Delta));
295030b8cb1SEduard Zingerman   unsigned AlignShiftValue = getOperandAsUnsigned(Call, 4 + Delta);
296030b8cb1SEduard Zingerman   Insn->setAlignment(Align(1ULL << AlignShiftValue));
297030b8cb1SEduard Zingerman   GEP->setDebugLoc(Call->getDebugLoc());
298030b8cb1SEduard Zingerman   Insn->setDebugLoc(Call->getDebugLoc());
299030b8cb1SEduard Zingerman   Insn->setAAMetadata(Call->getAAMetadata());
300030b8cb1SEduard Zingerman }
301030b8cb1SEduard Zingerman 
302030b8cb1SEduard Zingerman std::pair<GetElementPtrInst *, LoadInst *>
303030b8cb1SEduard Zingerman BPFPreserveStaticOffsetPass::reconstructLoad(CallInst *Call) {
304030b8cb1SEduard Zingerman   GetElementPtrInst *GEP = reconstructGEP(Call, 0);
305030b8cb1SEduard Zingerman   Type *ReturnType = Call->getFunctionType()->getReturnType();
306030b8cb1SEduard Zingerman   auto *Load = new LoadInst(ReturnType, GEP, "",
307030b8cb1SEduard Zingerman                             /* These would be set in reconstructCommon */
308030b8cb1SEduard Zingerman                             false, Align(1));
309030b8cb1SEduard Zingerman   reconstructCommon(Call, GEP, Load, 0);
310030b8cb1SEduard Zingerman   return std::pair{GEP, Load};
311030b8cb1SEduard Zingerman }
312030b8cb1SEduard Zingerman 
313030b8cb1SEduard Zingerman std::pair<GetElementPtrInst *, StoreInst *>
314030b8cb1SEduard Zingerman BPFPreserveStaticOffsetPass::reconstructStore(CallInst *Call) {
315030b8cb1SEduard Zingerman   GetElementPtrInst *GEP = reconstructGEP(Call, 1);
316030b8cb1SEduard Zingerman   auto *Store = new StoreInst(Call->getOperand(0), GEP,
317030b8cb1SEduard Zingerman                               /* These would be set in reconstructCommon */
318030b8cb1SEduard Zingerman                               false, Align(1));
319030b8cb1SEduard Zingerman   reconstructCommon(Call, GEP, Store, 1);
320030b8cb1SEduard Zingerman   return std::pair{GEP, Store};
321030b8cb1SEduard Zingerman }
322030b8cb1SEduard Zingerman 
323030b8cb1SEduard Zingerman static bool isZero(Value *V) {
324030b8cb1SEduard Zingerman   auto *CI = dyn_cast<ConstantInt>(V);
325030b8cb1SEduard Zingerman   return CI && CI->isZero();
326030b8cb1SEduard Zingerman }
327030b8cb1SEduard Zingerman 
328030b8cb1SEduard Zingerman // Given a chain of GEP instructions collect information necessary to
329030b8cb1SEduard Zingerman // merge this chain as a single GEP instruction of form:
330030b8cb1SEduard Zingerman //   getelementptr %<type>, ptr %p, i32 0, <field_idx1>, <field_idx2>, ...
331030b8cb1SEduard Zingerman static bool foldGEPChainAsStructAccess(SmallVector<GetElementPtrInst *> &GEPs,
332030b8cb1SEduard Zingerman                                        GEPChainInfo &Info) {
333030b8cb1SEduard Zingerman   if (GEPs.empty())
334030b8cb1SEduard Zingerman     return false;
335030b8cb1SEduard Zingerman 
336030b8cb1SEduard Zingerman   if (!all_of(GEPs, [=](GetElementPtrInst *GEP) {
337030b8cb1SEduard Zingerman         return GEP->hasAllConstantIndices();
338030b8cb1SEduard Zingerman       }))
339030b8cb1SEduard Zingerman     return false;
340030b8cb1SEduard Zingerman 
341030b8cb1SEduard Zingerman   GetElementPtrInst *First = GEPs[0];
342030b8cb1SEduard Zingerman   Info.InBounds = First->isInBounds();
343030b8cb1SEduard Zingerman   Info.SourceElementType = First->getSourceElementType();
344030b8cb1SEduard Zingerman   Type *ResultElementType = First->getResultElementType();
345030b8cb1SEduard Zingerman   Info.Indices.append(First->idx_begin(), First->idx_end());
346030b8cb1SEduard Zingerman   Info.Members.push_back(First);
347030b8cb1SEduard Zingerman 
348030b8cb1SEduard Zingerman   for (auto *Iter = GEPs.begin() + 1; Iter != GEPs.end(); ++Iter) {
349030b8cb1SEduard Zingerman     GetElementPtrInst *GEP = *Iter;
350030b8cb1SEduard Zingerman     if (!isZero(*GEP->idx_begin())) {
351030b8cb1SEduard Zingerman       Info.reset();
352030b8cb1SEduard Zingerman       return false;
353030b8cb1SEduard Zingerman     }
354030b8cb1SEduard Zingerman     if (!GEP->getSourceElementType() ||
355030b8cb1SEduard Zingerman         GEP->getSourceElementType() != ResultElementType) {
356030b8cb1SEduard Zingerman       Info.reset();
357030b8cb1SEduard Zingerman       return false;
358030b8cb1SEduard Zingerman     }
359030b8cb1SEduard Zingerman     Info.InBounds &= GEP->isInBounds();
360030b8cb1SEduard Zingerman     Info.Indices.append(GEP->idx_begin() + 1, GEP->idx_end());
361030b8cb1SEduard Zingerman     Info.Members.push_back(GEP);
362030b8cb1SEduard Zingerman     ResultElementType = GEP->getResultElementType();
363030b8cb1SEduard Zingerman   }
364030b8cb1SEduard Zingerman 
365030b8cb1SEduard Zingerman   return true;
366030b8cb1SEduard Zingerman }
367030b8cb1SEduard Zingerman 
368030b8cb1SEduard Zingerman // Given a chain of GEP instructions collect information necessary to
369030b8cb1SEduard Zingerman // merge this chain as a single GEP instruction of form:
370030b8cb1SEduard Zingerman //   getelementptr i8, ptr %p, i64 %offset
371030b8cb1SEduard Zingerman static bool foldGEPChainAsU8Access(SmallVector<GetElementPtrInst *> &GEPs,
372030b8cb1SEduard Zingerman                                    GEPChainInfo &Info) {
373030b8cb1SEduard Zingerman   if (GEPs.empty())
374030b8cb1SEduard Zingerman     return false;
375030b8cb1SEduard Zingerman 
376030b8cb1SEduard Zingerman   GetElementPtrInst *First = GEPs[0];
3772d209d96SNikita Popov   const DataLayout &DL = First->getDataLayout();
378030b8cb1SEduard Zingerman   LLVMContext &C = First->getContext();
379030b8cb1SEduard Zingerman   Type *PtrTy = First->getType()->getScalarType();
380030b8cb1SEduard Zingerman   APInt Offset(DL.getIndexTypeSizeInBits(PtrTy), 0);
381030b8cb1SEduard Zingerman   for (GetElementPtrInst *GEP : GEPs) {
382030b8cb1SEduard Zingerman     if (!GEP->accumulateConstantOffset(DL, Offset)) {
383030b8cb1SEduard Zingerman       Info.reset();
384030b8cb1SEduard Zingerman       return false;
385030b8cb1SEduard Zingerman     }
386030b8cb1SEduard Zingerman     Info.InBounds &= GEP->isInBounds();
387030b8cb1SEduard Zingerman     Info.Members.push_back(GEP);
388030b8cb1SEduard Zingerman   }
389030b8cb1SEduard Zingerman   Info.SourceElementType = Type::getInt8Ty(C);
390030b8cb1SEduard Zingerman   Info.Indices.push_back(ConstantInt::get(C, Offset));
391030b8cb1SEduard Zingerman 
392030b8cb1SEduard Zingerman   return true;
393030b8cb1SEduard Zingerman }
394030b8cb1SEduard Zingerman 
395030b8cb1SEduard Zingerman static void reportNonStaticGEPChain(Instruction *Insn) {
396030b8cb1SEduard Zingerman   auto Msg = DiagnosticInfoUnsupported(
397030b8cb1SEduard Zingerman       *Insn->getFunction(),
398030b8cb1SEduard Zingerman       Twine("Non-constant offset in access to a field of a type marked "
399030b8cb1SEduard Zingerman             "with preserve_static_offset might be rejected by BPF verifier")
400030b8cb1SEduard Zingerman           .concat(Insn->getDebugLoc()
401030b8cb1SEduard Zingerman                       ? ""
402030b8cb1SEduard Zingerman                       : " (pass -g option to get exact location)"),
403030b8cb1SEduard Zingerman       Insn->getDebugLoc(), DS_Warning);
404030b8cb1SEduard Zingerman   Insn->getContext().diagnose(Msg);
405030b8cb1SEduard Zingerman }
406030b8cb1SEduard Zingerman 
407030b8cb1SEduard Zingerman static bool allZeroIndices(SmallVector<GetElementPtrInst *> &GEPs) {
408030b8cb1SEduard Zingerman   return GEPs.empty() || all_of(GEPs, [=](GetElementPtrInst *GEP) {
409030b8cb1SEduard Zingerman            return GEP->hasAllZeroIndices();
410030b8cb1SEduard Zingerman          });
411030b8cb1SEduard Zingerman }
412030b8cb1SEduard Zingerman 
413030b8cb1SEduard Zingerman static bool tryToReplaceWithGEPBuiltin(Instruction *LoadOrStoreTemplate,
414030b8cb1SEduard Zingerman                                        SmallVector<GetElementPtrInst *> &GEPs,
415030b8cb1SEduard Zingerman                                        Instruction *InsnToReplace) {
416030b8cb1SEduard Zingerman   GEPChainInfo GEPChain;
417030b8cb1SEduard Zingerman   if (!foldGEPChainAsStructAccess(GEPs, GEPChain) &&
418030b8cb1SEduard Zingerman       !foldGEPChainAsU8Access(GEPs, GEPChain)) {
419030b8cb1SEduard Zingerman     return false;
420030b8cb1SEduard Zingerman   }
421030b8cb1SEduard Zingerman   Module *M = InsnToReplace->getModule();
422030b8cb1SEduard Zingerman   if (auto *Load = dyn_cast<LoadInst>(LoadOrStoreTemplate)) {
423030b8cb1SEduard Zingerman     Instruction *Replacement = makeGEPAndLoad(M, GEPChain, Load);
424*8e702735SJeremy Morse     Replacement->insertBefore(InsnToReplace->getIterator());
425030b8cb1SEduard Zingerman     InsnToReplace->replaceAllUsesWith(Replacement);
426030b8cb1SEduard Zingerman   }
427030b8cb1SEduard Zingerman   if (auto *Store = dyn_cast<StoreInst>(LoadOrStoreTemplate)) {
428030b8cb1SEduard Zingerman     Instruction *Replacement = makeGEPAndStore(M, GEPChain, Store);
429*8e702735SJeremy Morse     Replacement->insertBefore(InsnToReplace->getIterator());
430030b8cb1SEduard Zingerman   }
431030b8cb1SEduard Zingerman   return true;
432030b8cb1SEduard Zingerman }
433030b8cb1SEduard Zingerman 
434030b8cb1SEduard Zingerman // Check if U->getPointerOperand() == I
435030b8cb1SEduard Zingerman static bool isPointerOperand(Value *I, User *U) {
436030b8cb1SEduard Zingerman   if (auto *L = dyn_cast<LoadInst>(U))
437030b8cb1SEduard Zingerman     return L->getPointerOperand() == I;
438030b8cb1SEduard Zingerman   if (auto *S = dyn_cast<StoreInst>(U))
439030b8cb1SEduard Zingerman     return S->getPointerOperand() == I;
440030b8cb1SEduard Zingerman   if (auto *GEP = dyn_cast<GetElementPtrInst>(U))
441030b8cb1SEduard Zingerman     return GEP->getPointerOperand() == I;
442030b8cb1SEduard Zingerman   if (auto *Call = isGEPAndLoad(U))
443030b8cb1SEduard Zingerman     return Call->getArgOperand(0) == I;
444030b8cb1SEduard Zingerman   if (auto *Call = isGEPAndStore(U))
445030b8cb1SEduard Zingerman     return Call->getArgOperand(1) == I;
446030b8cb1SEduard Zingerman   return false;
447030b8cb1SEduard Zingerman }
448030b8cb1SEduard Zingerman 
449030b8cb1SEduard Zingerman static bool isInlineableCall(User *U) {
450030b8cb1SEduard Zingerman   if (auto *Call = dyn_cast<CallInst>(U))
451030b8cb1SEduard Zingerman     return Call->hasFnAttr(Attribute::InlineHint);
452030b8cb1SEduard Zingerman   return false;
453030b8cb1SEduard Zingerman }
454030b8cb1SEduard Zingerman 
455030b8cb1SEduard Zingerman static void rewriteAccessChain(Instruction *Insn,
456030b8cb1SEduard Zingerman                                SmallVector<GetElementPtrInst *> &GEPs,
457030b8cb1SEduard Zingerman                                SmallVector<Instruction *> &Visited,
458030b8cb1SEduard Zingerman                                bool AllowPatial, bool &StillUsed);
459030b8cb1SEduard Zingerman 
460030b8cb1SEduard Zingerman static void rewriteUses(Instruction *Insn,
461030b8cb1SEduard Zingerman                         SmallVector<GetElementPtrInst *> &GEPs,
462030b8cb1SEduard Zingerman                         SmallVector<Instruction *> &Visited, bool AllowPatial,
463030b8cb1SEduard Zingerman                         bool &StillUsed) {
464030b8cb1SEduard Zingerman   for (User *U : Insn->users()) {
465030b8cb1SEduard Zingerman     auto *UI = dyn_cast<Instruction>(U);
466030b8cb1SEduard Zingerman     if (UI && (isPointerOperand(Insn, UI) || isPreserveStaticOffsetCall(UI) ||
467030b8cb1SEduard Zingerman                isInlineableCall(UI)))
468030b8cb1SEduard Zingerman       rewriteAccessChain(UI, GEPs, Visited, AllowPatial, StillUsed);
469030b8cb1SEduard Zingerman     else
470030b8cb1SEduard Zingerman       LLVM_DEBUG({
471030b8cb1SEduard Zingerman         llvm::dbgs() << "unsupported usage in BPFPreserveStaticOffsetPass:\n";
472030b8cb1SEduard Zingerman         llvm::dbgs() << "  Insn: " << *Insn << "\n";
473030b8cb1SEduard Zingerman         llvm::dbgs() << "  User: " << *U << "\n";
474030b8cb1SEduard Zingerman       });
475030b8cb1SEduard Zingerman   }
476030b8cb1SEduard Zingerman }
477030b8cb1SEduard Zingerman 
478030b8cb1SEduard Zingerman // A DFS traversal of GEP chain trees starting from Root.
479030b8cb1SEduard Zingerman //
480030b8cb1SEduard Zingerman // Recursion descends through GEP instructions and
481030b8cb1SEduard Zingerman // llvm.preserve.static.offset calls. Recursion stops at any other
482030b8cb1SEduard Zingerman // instruction. If load or store instruction is reached it is replaced
483030b8cb1SEduard Zingerman // by a call to `llvm.bpf.getelementptr.and.load` or
484030b8cb1SEduard Zingerman // `llvm.bpf.getelementptr.and.store` intrinsic.
485030b8cb1SEduard Zingerman // If `llvm.bpf.getelementptr.and.load/store` is reached the accumulated
486030b8cb1SEduard Zingerman // GEPs are merged into the intrinsic call.
487030b8cb1SEduard Zingerman // If nested calls to `llvm.preserve.static.offset` are encountered these
488030b8cb1SEduard Zingerman // calls are marked for deletion.
489030b8cb1SEduard Zingerman //
490030b8cb1SEduard Zingerman // Parameters description:
491030b8cb1SEduard Zingerman // - Insn - current position in the tree
492030b8cb1SEduard Zingerman // - GEPs - GEP instructions for the current branch
493030b8cb1SEduard Zingerman // - Visited - a list of visited instructions in DFS order,
494030b8cb1SEduard Zingerman //   order is important for unused instruction deletion.
495030b8cb1SEduard Zingerman // - AllowPartial - when true GEP chains that can't be folded are
496030b8cb1SEduard Zingerman //   not reported, otherwise diagnostic message is show for such chains.
497030b8cb1SEduard Zingerman // - StillUsed - set to true if one of the GEP chains could not be
498030b8cb1SEduard Zingerman //   folded, makes sense when AllowPartial is false, means that root
499030b8cb1SEduard Zingerman //   preserve.static.offset call is still in use and should remain
500030b8cb1SEduard Zingerman //   until the next run of this pass.
501030b8cb1SEduard Zingerman static void rewriteAccessChain(Instruction *Insn,
502030b8cb1SEduard Zingerman                                SmallVector<GetElementPtrInst *> &GEPs,
503030b8cb1SEduard Zingerman                                SmallVector<Instruction *> &Visited,
504030b8cb1SEduard Zingerman                                bool AllowPatial, bool &StillUsed) {
505030b8cb1SEduard Zingerman   auto MarkAndTraverseUses = [&]() {
506030b8cb1SEduard Zingerman     Visited.push_back(Insn);
507030b8cb1SEduard Zingerman     rewriteUses(Insn, GEPs, Visited, AllowPatial, StillUsed);
508030b8cb1SEduard Zingerman   };
509030b8cb1SEduard Zingerman   auto TryToReplace = [&](Instruction *LoadOrStore) {
510030b8cb1SEduard Zingerman     // Do nothing for (preserve.static.offset (load/store ..)) or for
511030b8cb1SEduard Zingerman     // GEPs with zero indices. Such constructs lead to zero offset and
512030b8cb1SEduard Zingerman     // are simplified by other passes.
513030b8cb1SEduard Zingerman     if (allZeroIndices(GEPs))
514030b8cb1SEduard Zingerman       return;
515030b8cb1SEduard Zingerman     if (tryToReplaceWithGEPBuiltin(LoadOrStore, GEPs, Insn)) {
516030b8cb1SEduard Zingerman       Visited.push_back(Insn);
517030b8cb1SEduard Zingerman       return;
518030b8cb1SEduard Zingerman     }
519030b8cb1SEduard Zingerman     if (!AllowPatial)
520030b8cb1SEduard Zingerman       reportNonStaticGEPChain(Insn);
521030b8cb1SEduard Zingerman     StillUsed = true;
522030b8cb1SEduard Zingerman   };
523030b8cb1SEduard Zingerman   if (isa<LoadInst>(Insn) || isa<StoreInst>(Insn)) {
524030b8cb1SEduard Zingerman     TryToReplace(Insn);
525030b8cb1SEduard Zingerman   } else if (isGEPAndLoad(Insn)) {
526030b8cb1SEduard Zingerman     auto [GEP, Load] =
527030b8cb1SEduard Zingerman         BPFPreserveStaticOffsetPass::reconstructLoad(cast<CallInst>(Insn));
528030b8cb1SEduard Zingerman     GEPs.push_back(GEP);
529030b8cb1SEduard Zingerman     TryToReplace(Load);
530030b8cb1SEduard Zingerman     GEPs.pop_back();
531030b8cb1SEduard Zingerman     delete Load;
532030b8cb1SEduard Zingerman     delete GEP;
533030b8cb1SEduard Zingerman   } else if (isGEPAndStore(Insn)) {
534030b8cb1SEduard Zingerman     // This  case can't be merged with the above because
535030b8cb1SEduard Zingerman     // `delete Load` / `delete Store` wants a concrete type,
536030b8cb1SEduard Zingerman     // destructor of Instruction is protected.
537030b8cb1SEduard Zingerman     auto [GEP, Store] =
538030b8cb1SEduard Zingerman         BPFPreserveStaticOffsetPass::reconstructStore(cast<CallInst>(Insn));
539030b8cb1SEduard Zingerman     GEPs.push_back(GEP);
540030b8cb1SEduard Zingerman     TryToReplace(Store);
541030b8cb1SEduard Zingerman     GEPs.pop_back();
542030b8cb1SEduard Zingerman     delete Store;
543030b8cb1SEduard Zingerman     delete GEP;
544030b8cb1SEduard Zingerman   } else if (auto *GEP = dyn_cast<GetElementPtrInst>(Insn)) {
545030b8cb1SEduard Zingerman     GEPs.push_back(GEP);
546030b8cb1SEduard Zingerman     MarkAndTraverseUses();
547030b8cb1SEduard Zingerman     GEPs.pop_back();
548030b8cb1SEduard Zingerman   } else if (isPreserveStaticOffsetCall(Insn)) {
549030b8cb1SEduard Zingerman     MarkAndTraverseUses();
550030b8cb1SEduard Zingerman   } else if (isInlineableCall(Insn)) {
551030b8cb1SEduard Zingerman     // Preserve preserve.static.offset call for parameters of
552030b8cb1SEduard Zingerman     // functions that might be inlined. These would be removed on a
553030b8cb1SEduard Zingerman     // second pass after inlining.
554030b8cb1SEduard Zingerman     // Might happen when a pointer to a preserve_static_offset
555030b8cb1SEduard Zingerman     // structure is passed as parameter of a function that would be
556030b8cb1SEduard Zingerman     // inlined inside a loop that would be unrolled.
557030b8cb1SEduard Zingerman     if (AllowPatial)
558030b8cb1SEduard Zingerman       StillUsed = true;
559030b8cb1SEduard Zingerman   } else {
560030b8cb1SEduard Zingerman     SmallString<128> Buf;
561030b8cb1SEduard Zingerman     raw_svector_ostream BufStream(Buf);
562030b8cb1SEduard Zingerman     BufStream << *Insn;
563030b8cb1SEduard Zingerman     report_fatal_error(
564030b8cb1SEduard Zingerman         Twine("Unexpected rewriteAccessChain Insn = ").concat(Buf));
565030b8cb1SEduard Zingerman   }
566030b8cb1SEduard Zingerman }
567030b8cb1SEduard Zingerman 
568030b8cb1SEduard Zingerman static void removeMarkerCall(Instruction *Marker) {
569030b8cb1SEduard Zingerman   Marker->replaceAllUsesWith(Marker->getOperand(0));
570030b8cb1SEduard Zingerman   Marker->eraseFromParent();
571030b8cb1SEduard Zingerman }
572030b8cb1SEduard Zingerman 
573030b8cb1SEduard Zingerman static bool rewriteAccessChain(Instruction *Marker, bool AllowPatial,
574030b8cb1SEduard Zingerman                                SmallPtrSetImpl<Instruction *> &RemovedMarkers) {
575030b8cb1SEduard Zingerman   SmallVector<GetElementPtrInst *> GEPs;
576030b8cb1SEduard Zingerman   SmallVector<Instruction *> Visited;
577030b8cb1SEduard Zingerman   bool StillUsed = false;
578030b8cb1SEduard Zingerman   rewriteUses(Marker, GEPs, Visited, AllowPatial, StillUsed);
579030b8cb1SEduard Zingerman   // Check if Visited instructions could be removed, iterate in
580030b8cb1SEduard Zingerman   // reverse to unblock instructions higher in the chain.
581030b8cb1SEduard Zingerman   for (auto V = Visited.rbegin(); V != Visited.rend(); ++V) {
582030b8cb1SEduard Zingerman     if (isPreserveStaticOffsetCall(*V)) {
583030b8cb1SEduard Zingerman       removeMarkerCall(*V);
584030b8cb1SEduard Zingerman       RemovedMarkers.insert(*V);
585030b8cb1SEduard Zingerman     } else if ((*V)->use_empty()) {
586030b8cb1SEduard Zingerman       (*V)->eraseFromParent();
587030b8cb1SEduard Zingerman     }
588030b8cb1SEduard Zingerman   }
589030b8cb1SEduard Zingerman   return StillUsed;
590030b8cb1SEduard Zingerman }
591030b8cb1SEduard Zingerman 
592030b8cb1SEduard Zingerman static std::vector<Instruction *>
593030b8cb1SEduard Zingerman collectPreserveStaticOffsetCalls(Function &F) {
594030b8cb1SEduard Zingerman   std::vector<Instruction *> Calls;
595030b8cb1SEduard Zingerman   for (Instruction &Insn : instructions(F))
596030b8cb1SEduard Zingerman     if (isPreserveStaticOffsetCall(&Insn))
597030b8cb1SEduard Zingerman       Calls.push_back(&Insn);
598030b8cb1SEduard Zingerman   return Calls;
599030b8cb1SEduard Zingerman }
600030b8cb1SEduard Zingerman 
601030b8cb1SEduard Zingerman bool isPreserveArrayIndex(Value *V) {
602030b8cb1SEduard Zingerman   return isIntrinsicCall(V, Intrinsic::preserve_array_access_index);
603030b8cb1SEduard Zingerman }
604030b8cb1SEduard Zingerman 
605030b8cb1SEduard Zingerman bool isPreserveStructIndex(Value *V) {
606030b8cb1SEduard Zingerman   return isIntrinsicCall(V, Intrinsic::preserve_struct_access_index);
607030b8cb1SEduard Zingerman }
608030b8cb1SEduard Zingerman 
609030b8cb1SEduard Zingerman bool isPreserveUnionIndex(Value *V) {
610030b8cb1SEduard Zingerman   return isIntrinsicCall(V, Intrinsic::preserve_union_access_index);
611030b8cb1SEduard Zingerman }
612030b8cb1SEduard Zingerman 
613030b8cb1SEduard Zingerman static void removePAICalls(Instruction *Marker) {
614030b8cb1SEduard Zingerman   auto IsPointerOperand = [](Value *Op, User *U) {
615030b8cb1SEduard Zingerman     if (auto *GEP = dyn_cast<GetElementPtrInst>(U))
616030b8cb1SEduard Zingerman       return GEP->getPointerOperand() == Op;
617030b8cb1SEduard Zingerman     if (isPreserveStaticOffsetCall(U) || isPreserveArrayIndex(U) ||
618030b8cb1SEduard Zingerman         isPreserveStructIndex(U) || isPreserveUnionIndex(U))
619030b8cb1SEduard Zingerman       return cast<CallInst>(U)->getArgOperand(0) == Op;
620030b8cb1SEduard Zingerman     return false;
621030b8cb1SEduard Zingerman   };
622030b8cb1SEduard Zingerman 
623030b8cb1SEduard Zingerman   SmallVector<Value *, 32> WorkList;
624030b8cb1SEduard Zingerman   WorkList.push_back(Marker);
625030b8cb1SEduard Zingerman   do {
626030b8cb1SEduard Zingerman     Value *V = WorkList.pop_back_val();
627030b8cb1SEduard Zingerman     for (User *U : V->users())
628030b8cb1SEduard Zingerman       if (IsPointerOperand(V, U))
629030b8cb1SEduard Zingerman         WorkList.push_back(U);
630030b8cb1SEduard Zingerman     auto *Call = dyn_cast<CallInst>(V);
631030b8cb1SEduard Zingerman     if (!Call)
632030b8cb1SEduard Zingerman       continue;
633030b8cb1SEduard Zingerman     if (isPreserveArrayIndex(V))
634030b8cb1SEduard Zingerman       BPFCoreSharedInfo::removeArrayAccessCall(Call);
635030b8cb1SEduard Zingerman     else if (isPreserveStructIndex(V))
636030b8cb1SEduard Zingerman       BPFCoreSharedInfo::removeStructAccessCall(Call);
637030b8cb1SEduard Zingerman     else if (isPreserveUnionIndex(V))
638030b8cb1SEduard Zingerman       BPFCoreSharedInfo::removeUnionAccessCall(Call);
639030b8cb1SEduard Zingerman   } while (!WorkList.empty());
640030b8cb1SEduard Zingerman }
641030b8cb1SEduard Zingerman 
642030b8cb1SEduard Zingerman // Look for sequences:
643030b8cb1SEduard Zingerman // - llvm.preserve.static.offset -> getelementptr... -> load
644030b8cb1SEduard Zingerman // - llvm.preserve.static.offset -> getelementptr... -> store
645030b8cb1SEduard Zingerman // And replace those with calls to intrinsics:
646030b8cb1SEduard Zingerman // - llvm.bpf.getelementptr.and.load
647030b8cb1SEduard Zingerman // - llvm.bpf.getelementptr.and.store
648030b8cb1SEduard Zingerman static bool rewriteFunction(Function &F, bool AllowPartial) {
649030b8cb1SEduard Zingerman   LLVM_DEBUG(dbgs() << "********** BPFPreserveStaticOffsetPass (AllowPartial="
650030b8cb1SEduard Zingerman                     << AllowPartial << ") ************\n");
651030b8cb1SEduard Zingerman 
652030b8cb1SEduard Zingerman   auto MarkerCalls = collectPreserveStaticOffsetCalls(F);
653030b8cb1SEduard Zingerman   SmallPtrSet<Instruction *, 16> RemovedMarkers;
654030b8cb1SEduard Zingerman 
655030b8cb1SEduard Zingerman   LLVM_DEBUG(dbgs() << "There are " << MarkerCalls.size()
656030b8cb1SEduard Zingerman                     << " preserve.static.offset calls\n");
657030b8cb1SEduard Zingerman 
658030b8cb1SEduard Zingerman   if (MarkerCalls.empty())
659030b8cb1SEduard Zingerman     return false;
660030b8cb1SEduard Zingerman 
661030b8cb1SEduard Zingerman   for (auto *Call : MarkerCalls)
662030b8cb1SEduard Zingerman     removePAICalls(Call);
663030b8cb1SEduard Zingerman 
664030b8cb1SEduard Zingerman   for (auto *Call : MarkerCalls) {
665030b8cb1SEduard Zingerman     if (RemovedMarkers.contains(Call))
666030b8cb1SEduard Zingerman       continue;
667030b8cb1SEduard Zingerman     bool StillUsed = rewriteAccessChain(Call, AllowPartial, RemovedMarkers);
668030b8cb1SEduard Zingerman     if (!StillUsed || !AllowPartial)
669030b8cb1SEduard Zingerman       removeMarkerCall(Call);
670030b8cb1SEduard Zingerman   }
671030b8cb1SEduard Zingerman 
672030b8cb1SEduard Zingerman   return true;
673030b8cb1SEduard Zingerman }
674030b8cb1SEduard Zingerman 
675030b8cb1SEduard Zingerman PreservedAnalyses
676030b8cb1SEduard Zingerman llvm::BPFPreserveStaticOffsetPass::run(Function &F,
677030b8cb1SEduard Zingerman                                        FunctionAnalysisManager &AM) {
678030b8cb1SEduard Zingerman   return rewriteFunction(F, AllowPartial) ? PreservedAnalyses::none()
679030b8cb1SEduard Zingerman                                           : PreservedAnalyses::all();
680030b8cb1SEduard Zingerman }
681