118#include "llvm/IR/IntrinsicsBPF.h"
123#define DEBUG_TYPE "bpf-preserve-static-offset"
131 if (
auto *Call = dyn_cast<CallInst>(
I))
132 if (
Function *Func = Call->getCalledFunction())
133 return Func->getIntrinsicID() == Id;
143 return cast<CallInst>(
I);
149 return cast<CallInst>(
I);
153template <
class T = Instruction>
162 Intrinsic::BPFIntrinsics Intrinsic,
193 Type *SourceElementType;
197 GEPChainInfo() { reset(); }
201 SourceElementType =
nullptr;
208template <
class T = std::disjunction<LoadInst, StoreInst>>
214 unsigned AlignShiftValue =
Log2_64(
Insn->getAlign().value());
215 Args.push_back(
GEP.Members[0]->getPointerOperand());
216 Args.push_back(ConstantInt::get(Int1Ty,
Insn->isVolatile()));
217 Args.push_back(ConstantInt::get(Int8Ty, (
unsigned)
Insn->getOrdering()));
218 Args.push_back(ConstantInt::get(Int8Ty, (
unsigned)
Insn->getSyncScopeID()));
219 Args.push_back(ConstantInt::get(Int8Ty, AlignShiftValue));
220 Args.push_back(ConstantInt::get(Int1Ty,
GEP.InBounds));
221 Args.append(
GEP.Indices.begin(),
GEP.Indices.end());
229 {Load->getType()}, Args);
232 Call->setName((*
GEP.Members.rbegin())->getName());
233 if (Load->isUnordered()) {
234 Call->setOnlyReadsMemory();
235 Call->setOnlyAccessesArgMemory();
239 Call->addParamAttr(
I, Attribute::ImmArg);
240 Call->setAAMetadata(Load->getAAMetadata());
247 Args.push_back(Store->getValueOperand());
251 {Store->getValueOperand()->
getType()}, Args);
253 if (Store->getValueOperand()->getType()->isPointerTy())
256 Store->getDebugLoc());
257 if (Store->isUnordered()) {
258 Call->setOnlyWritesMemory();
259 Call->setOnlyAccessesArgMemory();
263 Call->addParamAttr(
I, Attribute::ImmArg);
264 Call->setAAMetadata(Store->getAAMetadata());
269 if (
auto *
Int = dyn_cast<ConstantInt>(Call->getOperand(ArgNo)))
270 return Int->getValue().getZExtValue();
273 ReportS <<
"Expecting ConstantInt as argument #" << ArgNo <<
" of " << *Call
280 Indices.
append(Call->data_operands_begin() + 6 + Delta,
281 Call->data_operands_end());
282 Type *GEPPointeeType = Call->getParamElementType(Delta);
290template <
class T = std::disjunction<LoadInst, StoreInst>>
297 Insn->setAlignment(
Align(1ULL << AlignShiftValue));
298 GEP->setDebugLoc(Call->getDebugLoc());
299 Insn->setDebugLoc(Call->getDebugLoc());
300 Insn->setAAMetadata(Call->getAAMetadata());
303std::pair<GetElementPtrInst *, LoadInst *>
306 Type *ReturnType = Call->getFunctionType()->getReturnType();
311 return std::pair{
GEP, Load};
314std::pair<GetElementPtrInst *, StoreInst *>
321 return std::pair{
GEP, Store};
325 auto *CI = dyn_cast<ConstantInt>(V);
326 return CI && CI->isZero();
333 GEPChainInfo &Info) {
338 return GEP->hasAllConstantIndices();
344 Info.SourceElementType =
First->getSourceElementType();
345 Type *ResultElementType =
First->getResultElementType();
349 for (
auto *Iter = GEPs.
begin() + 1; Iter != GEPs.
end(); ++Iter) {
355 if (!
GEP->getSourceElementType() ||
356 GEP->getSourceElementType() != ResultElementType) {
360 Info.InBounds &=
GEP->isInBounds();
361 Info.Indices.append(
GEP->idx_begin() + 1,
GEP->idx_end());
363 ResultElementType =
GEP->getResultElementType();
373 GEPChainInfo &Info) {
380 Type *PtrTy =
First->getType()->getScalarType();
387 Info.InBounds &=
GEP->isInBounds();
391 Info.Indices.push_back(ConstantInt::get(
C,
Offset));
398 *
Insn->getFunction(),
399 Twine(
"Non-constant offset in access to a field of a type marked "
400 "with preserve_static_offset might be rejected by BPF verifier")
403 :
" (pass -g option to get exact location)"),
405 Insn->getContext().diagnose(Msg);
410 return GEP->hasAllZeroIndices();
417 GEPChainInfo GEPChain;
423 if (
auto *Load = dyn_cast<LoadInst>(LoadOrStoreTemplate)) {
428 if (
auto *Store = dyn_cast<StoreInst>(LoadOrStoreTemplate)) {
437 if (
auto *L = dyn_cast<LoadInst>(U))
438 return L->getPointerOperand() ==
I;
439 if (
auto *S = dyn_cast<StoreInst>(U))
440 return S->getPointerOperand() ==
I;
441 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(U))
442 return GEP->getPointerOperand() ==
I;
444 return Call->getArgOperand(0) ==
I;
446 return Call->getArgOperand(1) ==
I;
451 if (
auto *Call = dyn_cast<CallInst>(U))
452 return Call->hasFnAttr(Attribute::InlineHint);
459 bool AllowPatial,
bool &StillUsed);
466 auto *UI = dyn_cast<Instruction>(U);
472 llvm::dbgs() <<
"unsupported usage in BPFPreserveStaticOffsetPass:\n";
505 bool AllowPatial,
bool &StillUsed) {
506 auto MarkAndTraverseUses = [&]() {
510 auto TryToReplace = [&](
Instruction *LoadOrStore) {
524 if (isa<LoadInst>(
Insn) || isa<StoreInst>(
Insn)) {
545 }
else if (
auto *
GEP = dyn_cast<GetElementPtrInst>(
Insn)) {
547 MarkAndTraverseUses();
550 MarkAndTraverseUses();
565 Twine(
"Unexpected rewriteAccessChain Insn = ").
concat(Buf));
578 bool StillUsed =
false;
579 rewriteUses(Marker, GEPs, Visited, AllowPatial, StillUsed);
582 for (
auto V = Visited.
rbegin(); V != Visited.
rend(); ++V) {
585 RemovedMarkers.
insert(*V);
586 }
else if ((*V)->use_empty()) {
587 (*V)->eraseFromParent();
593static std::vector<Instruction *>
595 std::vector<Instruction *> Calls;
598 Calls.push_back(&
Insn);
616 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(U))
617 return GEP->getPointerOperand() ==
Op;
620 return cast<CallInst>(U)->getArgOperand(0) ==
Op;
628 for (
User *U : V->users())
629 if (IsPointerOperand(V, U))
631 auto *Call = dyn_cast<CallInst>(V);
640 }
while (!WorkList.
empty());
650 LLVM_DEBUG(
dbgs() <<
"********** BPFPreserveStaticOffsetPass (AllowPartial="
651 << AllowPartial <<
") ************\n");
657 <<
" preserve.static.offset calls\n");
659 if (MarkerCalls.empty())
662 for (
auto *Call : MarkerCalls)
665 for (
auto *Call : MarkerCalls) {
669 if (!StillUsed || !AllowPartial)
SmallVector< AArch64_IMM::ImmInsnModel, 4 > Insn
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 DILocation * mergeDILocations(SmallVector< T * > &Insns)
static const unsigned GepAndLoadFirstIdxArg
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...
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.
Module.h This file contains the declarations for the Module class.
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 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)
static DILocation * getMergedLocation(DILocation *LocA, DILocation *LocB)
When two instructions are combined into a single instruction we also need to combine the original loc...
A parsed version of the target data layout string in and methods for querying it.
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)
void insertBefore(Instruction *InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified instruction.
const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
This is an important class for using LLVM in a threaded context.
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 IntegerType * getInt1Ty(LLVMContext &C)
static IntegerType * getInt8Ty(LLVMContext &C)
Value * getOperand(unsigned i) const
LLVM Value Representation.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
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.
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
This is an optimization pass for GlobalISel generic memory operations.
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.
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
detail::concat_range< ValueT, RangeTs... > concat(RangeTs &&... Ranges)
Concatenated range across two or more ranges.
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.