116#include "llvm/IR/IntrinsicsBPF.h"
121#define DEBUG_TYPE "bpf-preserve-static-offset"
131 return Func->getIntrinsicID() == Id;
151template <
class T = Instruction>
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());
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};
323 return CI && CI->isZero();
330 GEPChainInfo &Info) {
335 return GEP->hasAllConstantIndices();
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());
344 Info.Members.push_back(
First);
351 if (!
GEP->getSourceElementType() ||
352 GEP->getSourceElementType() != ResultElementType) {
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();
369 GEPChainInfo &Info) {
376 Type *PtrTy =
First->getType()->getScalarType();
383 Info.InBounds &=
GEP->isInBounds();
384 Info.Members.push_back(
GEP);
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;
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;
447 return Call->hasFnAttr(Attribute::InlineHint);
454 bool AllowPatial,
bool &StillUsed);
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) {
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);
612 return GEP->getPointerOperand() ==
Op;
624 if (IsPointerOperand(V, U))
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)
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 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.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< user_iterator > users()
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<X> - 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<X> - 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<X> - 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.