116#include "llvm/IR/IntrinsicsBPF.h"
121#define DEBUG_TYPE "bpf-preserve-static-offset"
129 if (
auto *Call = dyn_cast<CallInst>(
I))
130 if (
Function *Func = Call->getCalledFunction())
131 return Func->getIntrinsicID() == Id;
141 return cast<CallInst>(
I);
147 return cast<CallInst>(
I);
151template <
class T = Instruction>
160 Intrinsic::BPFIntrinsics Intrinsic,
191 Type *SourceElementType;
195 GEPChainInfo() { reset(); }
199 SourceElementType =
nullptr;
206template <
class T = std::disjunction<LoadInst, StoreInst>>
208 GEPChainInfo &
GEP,
T *Insn) {
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());
227 {Load->getType()}, Args);
230 Call->setName((*
GEP.Members.rbegin())->getName());
231 if (Load->isUnordered()) {
232 Call->setOnlyReadsMemory();
233 Call->setOnlyAccessesArgMemory();
237 Call->addParamAttr(
I, Attribute::ImmArg);
238 Call->setAAMetadata(Load->getAAMetadata());
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();
260 Call->addParamAttr(
I, Attribute::ImmArg);
261 Call->setAAMetadata(Store->getAAMetadata());
266 if (
auto *
Int = dyn_cast<ConstantInt>(Call->getOperand(ArgNo)))
267 return Int->getValue().getZExtValue();
270 ReportS <<
"Expecting ConstantInt as argument #" << ArgNo <<
" of " << *Call
277 Indices.
append(Call->data_operands_begin() + 6 + Delta,
278 Call->data_operands_end());
279 Type *GEPPointeeType = Call->getParamElementType(Delta);
287template <
class T = std::disjunction<LoadInst, StoreInst>>
294 Insn->setAlignment(
Align(1ULL << AlignShiftValue));
295 GEP->setDebugLoc(Call->getDebugLoc());
296 Insn->setDebugLoc(Call->getDebugLoc());
297 Insn->setAAMetadata(Call->getAAMetadata());
300std::pair<GetElementPtrInst *, LoadInst *>
303 Type *ReturnType = Call->getFunctionType()->getReturnType();
308 return std::pair{
GEP, Load};
311std::pair<GetElementPtrInst *, StoreInst *>
318 return std::pair{
GEP, Store};
322 auto *CI = dyn_cast<ConstantInt>(V);
323 return CI && CI->isZero();
330 GEPChainInfo &Info) {
335 return GEP->hasAllConstantIndices();
341 Info.SourceElementType =
First->getSourceElementType();
342 Type *ResultElementType =
First->getResultElementType();
351 if (!
GEP->getSourceElementType() ||
352 GEP->getSourceElementType() != ResultElementType) {
356 Info.InBounds &=
GEP->isInBounds();
357 Info.Indices.append(
GEP->idx_begin() + 1,
GEP->idx_end());
359 ResultElementType =
GEP->getResultElementType();
369 GEPChainInfo &Info) {
376 Type *PtrTy =
First->getType()->getScalarType();
383 Info.InBounds &=
GEP->isInBounds();
387 Info.Indices.push_back(ConstantInt::get(
C,
Offset));
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")
399 :
" (pass -g option to get exact location)"),
405 return GEP->hasAllZeroIndices();
412 GEPChainInfo GEPChain;
418 if (
auto *Load = dyn_cast<LoadInst>(LoadOrStoreTemplate)) {
423 if (
auto *Store = dyn_cast<StoreInst>(LoadOrStoreTemplate)) {
432 if (
auto *L = dyn_cast<LoadInst>(U))
433 return L->getPointerOperand() ==
I;
434 if (
auto *S = dyn_cast<StoreInst>(U))
435 return S->getPointerOperand() ==
I;
436 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(U))
437 return GEP->getPointerOperand() ==
I;
439 return Call->getArgOperand(0) ==
I;
441 return Call->getArgOperand(1) ==
I;
446 if (
auto *Call = dyn_cast<CallInst>(U))
447 return Call->hasFnAttr(Attribute::InlineHint);
454 bool AllowPatial,
bool &StillUsed);
461 auto *UI = dyn_cast<Instruction>(U);
467 llvm::dbgs() <<
"unsupported usage in BPFPreserveStaticOffsetPass:\n";
500 bool AllowPatial,
bool &StillUsed) {
501 auto MarkAndTraverseUses = [&]() {
503 rewriteUses(Insn, GEPs, Visited, AllowPatial, StillUsed);
505 auto TryToReplace = [&](
Instruction *LoadOrStore) {
519 if (isa<LoadInst>(Insn) || isa<StoreInst>(Insn)) {
540 }
else if (
auto *
GEP = dyn_cast<GetElementPtrInst>(Insn)) {
542 MarkAndTraverseUses();
545 MarkAndTraverseUses();
560 Twine(
"Unexpected rewriteAccessChain Insn = ").
concat(Buf));
573 bool StillUsed =
false;
574 rewriteUses(Marker, GEPs, Visited, AllowPatial, StillUsed);
577 for (
auto V = Visited.
rbegin(); V != Visited.
rend(); ++V) {
580 RemovedMarkers.
insert(*V);
581 }
else if ((*V)->use_empty()) {
582 (*V)->eraseFromParent();
588static std::vector<Instruction *>
590 std::vector<Instruction *> Calls;
593 Calls.push_back(&Insn);
611 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(U))
612 return GEP->getPointerOperand() ==
Op;
615 return cast<CallInst>(U)->getArgOperand(0) ==
Op;
623 for (
User *U : V->users())
624 if (IsPointerOperand(V, U))
626 auto *Call = dyn_cast<CallInst>(V);
635 }
while (!WorkList.
empty());
645 LLVM_DEBUG(
dbgs() <<
"********** BPFPreserveStaticOffsetPass (AllowPartial="
646 << AllowPartial <<
") ************\n");
652 <<
" preserve.static.offset calls\n");
654 if (MarkerCalls.empty())
657 for (
auto *Call : MarkerCalls)
660 for (
auto *Call : MarkerCalls) {
664 if (!StillUsed || !AllowPartial)
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)
bool isPreserveUnionIndex(Value *V)
bool isPreserveArrayIndex(Value *V)
static bool isPreserveStaticOffsetCall(Value *I)
static void setParamElementType(CallInst *Call, unsigned ArgNo, Type *Type)
static bool foldGEPChainAsU8Access(SmallVector< GetElementPtrInst * > &GEPs, GEPChainInfo &Info)
static void fillCommonArgs(LLVMContext &C, SmallVector< Value * > &Args, GEPChainInfo &GEP, T *Insn)
static void removePAICalls(Instruction *Marker)
static void reportNonStaticGEPChain(Instruction *Insn)
static bool foldGEPChainAsStructAccess(SmallVector< GetElementPtrInst * > &GEPs, GEPChainInfo &Info)
static const unsigned GepAndStoreFirstIdxArg
static void removeMarkerCall(Instruction *Marker)
static Instruction * makeGEPAndStore(Module *M, GEPChainInfo &GEP, StoreInst *Store)
static void rewriteUses(Instruction *Insn, SmallVector< GetElementPtrInst * > &GEPs, SmallVector< Instruction * > &Visited, bool AllowPatial, bool &StillUsed)
static void setParamReadNone(CallInst *Call, unsigned ArgNo)
static Instruction * makeGEPAndLoad(Module *M, GEPChainInfo &GEP, LoadInst *Load)
static unsigned getOperandAsUnsigned(CallInst *Call, unsigned ArgNo)
bool isPreserveStructIndex(Value *V)
static void setParamReadOnly(CallInst *Call, unsigned ArgNo)
static void rewriteAccessChain(Instruction *Insn, SmallVector< GetElementPtrInst * > &GEPs, SmallVector< Instruction * > &Visited, bool AllowPatial, bool &StillUsed)
static bool isInlineableCall(User *U)
static const unsigned GepAndLoadFirstIdxArg
static DebugLoc mergeDebugLocs(SmallVector< T * > &Insns)
static GetElementPtrInst * reconstructGEP(CallInst *Call, int Delta)
static CallInst * makeIntrinsicCall(Module *M, Intrinsic::BPFIntrinsics Intrinsic, ArrayRef< Type * > Types, ArrayRef< Value * > Args)
static bool allZeroIndices(SmallVector< GetElementPtrInst * > &GEPs)
static std::vector< Instruction * > collectPreserveStaticOffsetCalls(Function &F)
static bool rewriteFunction(Function &F, bool AllowPartial)
static bool tryToReplaceWithGEPBuiltin(Instruction *LoadOrStoreTemplate, SmallVector< GetElementPtrInst * > &GEPs, Instruction *InsnToReplace)
static void reconstructCommon(CallInst *Call, GetElementPtrInst *GEP, T *Insn, int Delta)
static CallInst * isGEPAndStore(Value *I)
static void setParamWriteOnly(CallInst *Call, unsigned ArgNo)
static bool isIntrinsicCall(Value *I, Intrinsic::ID Id)
static bool isPointerOperand(Value *I, User *U)
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)
static DebugLoc getDebugLoc(MachineBasicBlock::instr_iterator FirstMI, MachineBasicBlock::instr_iterator LastMI)
Return the first found DebugLoc that has a DILocation, given a range of instructions.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
static SymbolRef::Type getType(const Symbol *Sym)
Class for arbitrary precision integers.
A container for analyses that lazily runs them and caches their results.
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 void removeArrayAccessCall(CallInst *Call)
static void removeStructAccessCall(CallInst *Call)
static void removeUnionAccessCall(CallInst *Call)
static std::pair< GetElementPtrInst *, StoreInst * > reconstructStore(CallInst *Call)
static std::pair< GetElementPtrInst *, LoadInst * > reconstructLoad(CallInst *Call)
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
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.
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.
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)
AtomicOrdering
Atomic ordering for LLVM's memory model.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
DWARFExpression::Operation Op
This struct is a compact representation of a valid (non-zero power of two) alignment.