LLVM: lib/Target/BPF/BPFPreserveStaticOffset.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
116#include "llvm/IR/IntrinsicsBPF.h"
120
121#define DEBUG_TYPE "bpf-preserve-static-offset"
122
123using namespace llvm;
124
127
130 if (Function *Func = Call->getCalledFunction())
131 return Func->getIntrinsicID() == Id;
132 return false;
133}
134
138
140 if (isIntrinsicCall(I, Intrinsic::bpf_getelementptr_and_load))
142 return nullptr;
143}
144
146 if (isIntrinsicCall(I, Intrinsic::bpf_getelementptr_and_store))
148 return nullptr;
149}
150
151template
153 DebugLoc Merged = (*Insns.begin())->getDebugLoc();
156 return Merged;
157}
158
160 Intrinsic::BPFIntrinsics Intrinsic,
163
166}
167
172
177
182
187
188namespace {
189struct GEPChainInfo {
190 bool InBounds;
191 Type *SourceElementType;
194
195 GEPChainInfo() { reset(); }
196
197 void reset() {
198 InBounds = true;
199 SourceElementType = nullptr;
200 Indices.clear();
201 Members.clear();
202 }
203};
204}
205
206template <class T = std::disjunction<LoadInst, StoreInst>>
208 GEPChainInfo &GEP, T *Insn) {
211
212 unsigned AlignShiftValue = Log2_64(Insn->getAlign().value());
213 Args.push_back(GEP.Members[0]->getPointerOperand());
214 Args.push_back(ConstantInt::get(Int1Ty, Insn->isVolatile()));
215 Args.push_back(ConstantInt::get(Int8Ty, (unsigned)Insn->getOrdering()));
216 Args.push_back(ConstantInt::get(Int8Ty, (unsigned)Insn->getSyncScopeID()));
217 Args.push_back(ConstantInt::get(Int8Ty, AlignShiftValue));
218 Args.push_back(ConstantInt::get(Int1Ty, GEP.InBounds));
219 Args.append(GEP.Indices.begin(), GEP.Indices.end());
220}
221
227 {Load->getType()}, Args);
230 Call->setName((*GEP.Members.rbegin())->getName());
231 if (Load->isUnordered()) {
232 Call->setOnlyReadsMemory();
233 Call->setOnlyAccessesArgMemory();
235 }
237 Call->addParamAttr(I, Attribute::ImmArg);
238 Call->setAAMetadata(Load->getAAMetadata());
240}
241
245 Args.push_back(Store->getValueOperand());
249 {Store->getValueOperand()->getType()}, Args);
251 if (Store->getValueOperand()->getType()->isPointerTy())
254 if (Store->isUnordered()) {
255 Call->setOnlyWritesMemory();
256 Call->setOnlyAccessesArgMemory();
258 }
260 Call->addParamAttr(I, Attribute::ImmArg);
261 Call->setAAMetadata(Store->getAAMetadata());
263}
264
267 return Int->getValue().getZExtValue();
268 std::string Report;
270 ReportS << "Expecting ConstantInt as argument #" << ArgNo << " of " << *Call
271 << "\n";
273}
274
277 Indices.append(Call->data_operands_begin() + 6 + Delta,
278 Call->data_operands_end());
279 Type *GEPPointeeType = Call->getParamElementType(Delta);
280 auto *GEP =
284 return GEP;
285}
286
287template <class T = std::disjunction<LoadInst, StoreInst>>
289 int Delta) {
294 Insn->setAlignment(Align(1ULL << AlignShiftValue));
295 GEP->setDebugLoc(Call->getDebugLoc());
296 Insn->setDebugLoc(Call->getDebugLoc());
297 Insn->setAAMetadata(Call->getAAMetadata());
298}
299
300std::pair<GetElementPtrInst *, LoadInst *>
303 Type *ReturnType = Call->getFunctionType()->getReturnType();
304 auto *Load = new LoadInst(ReturnType, GEP, "",
305
306 false, Align(1));
308 return std::pair{GEP, Load};
309}
310
311std::pair<GetElementPtrInst *, StoreInst *>
315
316 false, Align(1));
318 return std::pair{GEP, Store};
319}
320
323 return CI && CI->isZero();
324}
325
326
327
328
330 GEPChainInfo &Info) {
331 if (GEPs.empty())
332 return false;
333
335 return GEP->hasAllConstantIndices();
336 }))
337 return false;
338
340 Info.InBounds = First->isInBounds();
341 Info.SourceElementType = First->getSourceElementType();
342 Type *ResultElementType = First->getResultElementType();
343 Info.Indices.append(First->idx_begin(), First->idx_end());
345
347 if ((*GEP->idx_begin())) {
348 Info.reset();
349 return false;
350 }
351 if (->getSourceElementType() ||
352 GEP->getSourceElementType() != ResultElementType) {
353 Info.reset();
354 return false;
355 }
356 Info.InBounds &= GEP->isInBounds();
357 Info.Indices.append(GEP->idx_begin() + 1, GEP->idx_end());
358 Info.Members.push_back(GEP);
359 ResultElementType = GEP->getResultElementType();
360 }
361
362 return true;
363}
364
365
366
367
369 GEPChainInfo &Info) {
370 if (GEPs.empty())
371 return false;
372
376 Type *PtrTy = First->getType()->getScalarType();
377 APInt Offset(DL.getIndexTypeSizeInBits(PtrTy), 0);
379 if (->accumulateConstantOffset(DL, Offset)) {
380 Info.reset();
381 return false;
382 }
383 Info.InBounds &= GEP->isInBounds();
384 Info.Members.push_back(GEP);
385 }
387 Info.Indices.push_back(ConstantInt::get(C, Offset));
388
389 return true;
390}
391
395 Twine("Non-constant offset in access to a field of a type marked "
396 "with preserve_static_offset might be rejected by BPF verifier")
398 ? ""
399 : " (pass -g option to get exact location)"),
401}
402
405 return GEP->hasAllZeroIndices();
406 });
407}
408
412 GEPChainInfo GEPChain;
415 return false;
416 }
422 }
426 }
427 return true;
428}
429
430
433 return L->getPointerOperand() == I;
435 return S->getPointerOperand() == I;
437 return GEP->getPointerOperand() == I;
439 return Call->getArgOperand(0) == I;
441 return Call->getArgOperand(1) == I;
442 return false;
443}
444
447 return Call->hasFnAttr(Attribute::InlineHint);
448 return false;
449}
450
454 bool AllowPatial, bool &StillUsed);
455
459 bool &StillUsed) {
465 else
467 llvm::dbgs() << "unsupported usage in BPFPreserveStaticOffsetPass:\n";
468 llvm::dbgs() << " Insn: " << *Insn << "\n";
469 llvm::dbgs() << " User: " << *U << "\n";
470 });
471 }
472}
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
500 bool AllowPatial, bool &StillUsed) {
501 auto MarkAndTraverseUses = [&]() {
503 rewriteUses(Insn, GEPs, Visited, AllowPatial, StillUsed);
504 };
505 auto TryToReplace = [&](Instruction *LoadOrStore) {
506
507
508
510 return;
513 return;
514 }
515 if (!AllowPatial)
517 StillUsed = true;
518 };
520 TryToReplace(Insn);
522 auto [GEP, Load] =
525 TryToReplace(Load);
527 delete Load;
528 delete GEP;
530
531
532
533 auto [GEP, Store] =
536 TryToReplace(Store);
538 delete Store;
539 delete GEP;
542 MarkAndTraverseUses();
545 MarkAndTraverseUses();
547
548
549
550
551
552
553 if (AllowPatial)
554 StillUsed = true;
555 } else {
558 BufStream << *Insn;
560 Twine("Unexpected rewriteAccessChain Insn = ").concat(Buf));
561 }
562}
563
568
573 bool StillUsed = false;
574 rewriteUses(Marker, GEPs, Visited, AllowPatial, StillUsed);
575
576
577 for (auto V = Visited.rbegin(); V != Visited.rend(); ++V) {
580 RemovedMarkers.insert(*V);
581 } else if ((*V)->use_empty()) {
582 (*V)->eraseFromParent();
583 }
584 }
585 return StillUsed;
586}
587
588static std::vector<Instruction *>
590 std::vector<Instruction *> Calls;
593 Calls.push_back(&Insn);
594 return Calls;
595}
596
598 return isIntrinsicCall(V, Intrinsic::preserve_array_access_index);
599}
600
602 return isIntrinsicCall(V, Intrinsic::preserve_struct_access_index);
603}
604
606 return isIntrinsicCall(V, Intrinsic::preserve_union_access_index);
607}
608
610 auto IsPointerOperand = [](Value *Op, User *U) {
612 return GEP->getPointerOperand() == Op;
616 return false;
617 };
618
621 do {
624 if (IsPointerOperand(V, U))
628 continue;
635 } while (!WorkList.empty());
636}
637
638
639
640
641
642
643
645 LLVM_DEBUG(dbgs() << "********** BPFPreserveStaticOffsetPass (AllowPartial="
646 << AllowPartial << ") ************\n");
647
650
651 LLVM_DEBUG(dbgs() << "There are " << MarkerCalls.size()
652 << " preserve.static.offset calls\n");
653
654 if (MarkerCalls.empty())
655 return false;
656
657 for (auto *Call : MarkerCalls)
659
660 for (auto *Call : MarkerCalls) {
662 continue;
664 if (!StillUsed || !AllowPartial)
666 }
667
668 return true;
669}
670
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
This file contains the simple types necessary to represent the attributes associated with functions a...
static CallInst * isGEPAndLoad(Value *I)
Definition BPFPreserveStaticOffset.cpp:139
bool isPreserveUnionIndex(Value *V)
Definition BPFPreserveStaticOffset.cpp:605
bool isPreserveArrayIndex(Value *V)
Definition BPFPreserveStaticOffset.cpp:597
static bool isPreserveStaticOffsetCall(Value *I)
Definition BPFPreserveStaticOffset.cpp:135
static void setParamElementType(CallInst *Call, unsigned ArgNo, Type *Type)
Definition BPFPreserveStaticOffset.cpp:168
static bool foldGEPChainAsU8Access(SmallVector< GetElementPtrInst * > &GEPs, GEPChainInfo &Info)
Definition BPFPreserveStaticOffset.cpp:368
static void fillCommonArgs(LLVMContext &C, SmallVector< Value * > &Args, GEPChainInfo &GEP, T *Insn)
Definition BPFPreserveStaticOffset.cpp:207
static void removePAICalls(Instruction *Marker)
Definition BPFPreserveStaticOffset.cpp:609
static void reportNonStaticGEPChain(Instruction *Insn)
Definition BPFPreserveStaticOffset.cpp:392
static bool foldGEPChainAsStructAccess(SmallVector< GetElementPtrInst * > &GEPs, GEPChainInfo &Info)
Definition BPFPreserveStaticOffset.cpp:329
static const unsigned GepAndStoreFirstIdxArg
Definition BPFPreserveStaticOffset.cpp:126
static void removeMarkerCall(Instruction *Marker)
Definition BPFPreserveStaticOffset.cpp:564
static Instruction * makeGEPAndStore(Module *M, GEPChainInfo &GEP, StoreInst *Store)
Definition BPFPreserveStaticOffset.cpp:242
static void rewriteUses(Instruction *Insn, SmallVector< GetElementPtrInst * > &GEPs, SmallVector< Instruction * > &Visited, bool AllowPatial, bool &StillUsed)
Definition BPFPreserveStaticOffset.cpp:456
static void setParamReadNone(CallInst *Call, unsigned ArgNo)
Definition BPFPreserveStaticOffset.cpp:173
static Instruction * makeGEPAndLoad(Module *M, GEPChainInfo &GEP, LoadInst *Load)
Definition BPFPreserveStaticOffset.cpp:222
static unsigned getOperandAsUnsigned(CallInst *Call, unsigned ArgNo)
Definition BPFPreserveStaticOffset.cpp:265
bool isPreserveStructIndex(Value *V)
Definition BPFPreserveStaticOffset.cpp:601
static void setParamReadOnly(CallInst *Call, unsigned ArgNo)
Definition BPFPreserveStaticOffset.cpp:178
static void rewriteAccessChain(Instruction *Insn, SmallVector< GetElementPtrInst * > &GEPs, SmallVector< Instruction * > &Visited, bool AllowPatial, bool &StillUsed)
Definition BPFPreserveStaticOffset.cpp:497
static bool isInlineableCall(User *U)
Definition BPFPreserveStaticOffset.cpp:445
static const unsigned GepAndLoadFirstIdxArg
Definition BPFPreserveStaticOffset.cpp:125
static DebugLoc mergeDebugLocs(SmallVector< T * > &Insns)
Definition BPFPreserveStaticOffset.cpp:152
static GetElementPtrInst * reconstructGEP(CallInst *Call, int Delta)
Definition BPFPreserveStaticOffset.cpp:275
static CallInst * makeIntrinsicCall(Module *M, Intrinsic::BPFIntrinsics Intrinsic, ArrayRef< Type * > Types, ArrayRef< Value * > Args)
Definition BPFPreserveStaticOffset.cpp:159
static bool allZeroIndices(SmallVector< GetElementPtrInst * > &GEPs)
Definition BPFPreserveStaticOffset.cpp:403
static std::vector< Instruction * > collectPreserveStaticOffsetCalls(Function &F)
Definition BPFPreserveStaticOffset.cpp:589
static bool rewriteFunction(Function &F, bool AllowPartial)
Definition BPFPreserveStaticOffset.cpp:644
static bool tryToReplaceWithGEPBuiltin(Instruction *LoadOrStoreTemplate, SmallVector< GetElementPtrInst * > &GEPs, Instruction *InsnToReplace)
Definition BPFPreserveStaticOffset.cpp:409
static void reconstructCommon(CallInst *Call, GetElementPtrInst *GEP, T *Insn, int Delta)
Definition BPFPreserveStaticOffset.cpp:288
static CallInst * isGEPAndStore(Value *I)
Definition BPFPreserveStaticOffset.cpp:145
static void setParamWriteOnly(CallInst *Call, unsigned ArgNo)
Definition BPFPreserveStaticOffset.cpp:183
static bool isIntrinsicCall(Value *I, Intrinsic::ID Id)
Definition BPFPreserveStaticOffset.cpp:128
static bool isPointerOperand(Value *I, User *U)
Definition BPFPreserveStaticOffset.cpp:431
static bool isIntrinsicCall(const CallBase *Call, Intrinsic::ID IID)
Analysis containing CSE Info
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Module.h This file contains the declarations for the Module class.
static bool isZero(Value *V, const DataLayout &DL, DominatorTree *DT, AssumptionCache *AC)
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
Class for arbitrary precision integers.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
static LLVM_ABI Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)
Return a uniquified Attribute object.
static std::pair< GetElementPtrInst *, StoreInst * > reconstructStore(CallInst *Call)
Definition BPFPreserveStaticOffset.cpp:312
static std::pair< GetElementPtrInst *, LoadInst * > reconstructLoad(CallInst *Call)
Definition BPFPreserveStaticOffset.cpp:301
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Definition BPFPreserveStaticOffset.cpp:672
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
A parsed version of the target data layout string in and methods for querying it.
static LLVM_ABI DebugLoc getMergedLocation(DebugLoc LocA, DebugLoc LocB)
When two instructions are combined into a single instruction we also need to combine the original loc...
Diagnostic information for unsupported feature in backend.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
static GetElementPtrInst * Create(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI void insertBefore(InstListType::iterator InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified position.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
This is an important class for using LLVM in a threaded context.
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
An instruction for reading from memory.
A Module instance is used to store all the information related to an LLVM module.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
reverse_iterator rbegin()
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
StringRef - Represent a constant reference to a string, i.e.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)
Value * getOperand(unsigned i) const
LLVM Value Representation.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
LLVM_ABI LLVMContext & getContext() const
All values hold a context through their type.
self_iterator getIterator()
A raw_ostream that writes to an std::string.
A raw_ostream that writes to an SmallVector or SmallString.
@ C
The default llvm calling convention, compatible with C.
This namespace contains an enum with a value for every intrinsic/builtin function known by LLVM.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
bool all_of(R &&range, UnaryPredicate P)
Provide wrappers to std::all_of which take ranges instead of having to pass begin/end explicitly.
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
unsigned Log2_64(uint64_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&...Ranges)
Returns a concatenated range across two or more ranges.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa - Return true if the parameter to the template is an instance of one of the template type argu...
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast - Return the argument parameter cast to the specified type.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
This struct is a compact representation of a valid (non-zero power of two) alignment.