31#include "llvm/IR/IntrinsicsBPF.h"
40#define DEBUG_TYPE "bpf-check-and-opt-ir"
46class BPFCheckAndAdjustIRLegacy final :
public ModulePass {
47 bool runOnModule(
Module &
F)
override;
56char BPFCheckAndAdjustIRLegacy::ID = 0;
58 "BPF Check And Adjust IR",
false,
false)
61 return new BPFCheckAndAdjustIRLegacy();
108 ToBeDeleted =
nullptr;
117 if (!GV->getName().starts_with(
"llvm.bpf.passthrough"))
121 Call->replaceAllUsesWith(Arg);
138 ToBeDeleted =
nullptr;
147 if (!GV->getName().starts_with(
"llvm.bpf.compare"))
158 auto *ICmp =
new ICmpInst(Opcode, Arg1, Arg2);
159 ICmp->insertBefore(
Call->getIterator());
161 Call->replaceAllUsesWith(ICmp);
189 V = ZExt->getOperand(0);
192 V = SExt->getOperand(0);
204 switch (Called->getIntrinsicID()) {
205 case Intrinsic::smin:
206 case Intrinsic::umin:
207 case Intrinsic::smax:
208 case Intrinsic::umax:
225 if (Info.SExt->getType() == V->getType())
227 return Builder.CreateSExt(V, Info.SExt->getType());
230 if (Info.ZExt->getType() == V->getType())
232 return Builder.CreateZExt(V, Info.ZExt->getType());
257 bool SecondMinMax = IsMinMaxCall(ICmp->
getOperand(1), Second);
258 if (!(FirstMinMax ^ SecondMinMax))
265 for (
auto &Info : SinkList) {
271 IID != Intrinsic::smax)
276 Value *
A = ZeroOrSignExtend(Builder,
MinMax->getArgOperand(0), Info);
277 Value *
B = ZeroOrSignExtend(Builder,
MinMax->getArgOperand(1), Info);
278 bool IsMin = IID == Intrinsic::smin || IID == Intrinsic::umin;
279 bool IsMax = IID == Intrinsic::smax || IID == Intrinsic::umax;
283 assert(IsLess ^ IsGreater);
288 if ((IsLess && IsMin) || (IsGreater && IsMax))
291 Replacement = Builder.CreateLogicalAnd(
LHS,
RHS);
295 Replacement = Builder.CreateLogicalOr(
LHS,
RHS);
304 if (
I &&
I->use_empty())
305 I->eraseFromParent();
345 if (
F.isDeclaration())
363void BPFCheckAndAdjustIRLegacy::getAnalysisUsage(
AnalysisUsage &AU)
const {
369 GEP->insertBefore(
Call->getIterator());
370 Load->insertBefore(
Call->getIterator());
372 Call->eraseFromParent();
377 GEP->insertBefore(
Call->getIterator());
378 Store->insertBefore(
Call->getIterator());
379 Call->eraseFromParent();
386 for (
auto &Insn : BB)
388 if (
auto *Called =
Call->getCalledFunction())
389 switch (Called->getIntrinsicID()) {
390 case Intrinsic::bpf_getelementptr_and_load:
393 case Intrinsic::bpf_getelementptr_and_store:
429 auto It = Cache.find(ToWrap);
430 if (It != Cache.end())
431 return It->getSecond();
434 Value *Ptr =
GEP->getPointerOperand();
437 auto *NewGEP =
GEP->clone();
438 NewGEP->insertAfter(
GEP->getIterator());
440 NewGEP->setOperand(
GEP->getPointerOperandIndex(), WrappedPtr);
441 NewGEP->setName(
GEP->getName());
442 Cache[ToWrap] = NewGEP;
448 IB.SetInsertPoint(*InsnPtr->getInsertionPointAfterDef());
450 IB.SetInsertPoint(
F->getEntryBlock().getFirstInsertionPt());
451 auto *ASZeroPtrTy = IB.getPtrTy(0);
452 auto *ACast = IB.CreateAddrSpaceCast(ToWrap, ASZeroPtrTy, ToWrap->
getName());
453 Cache[ToWrap] = ACast;
461 Value *OldOp =
I->getOperand(OpNum);
466 I->setOperand(OpNum, NewOp);
473 if (!OldGEP->use_empty())
475 OldOp = OldGEP->getPointerOperand();
476 OldGEP->eraseFromParent();
483 if (PTy->getAddressSpace() == 0)
497 if (OldDst == NewDst)
506 bool IsVolatile = MS->isVolatile();
508 if (
ID == Intrinsic::memset)
509 return B.CreateMemSet(NewDst, Val, Len,
Align, IsVolatile,
510 MI->getAAMetadata());
512 return B.CreateMemSetInline(NewDst,
Align, Val, Len, IsVolatile,
513 MI->getAAMetadata());
526 if (OldDst == NewDst && OldSrc == NewSrc)
535 bool IsVolatile = MT->isVolatile();
537 return B.CreateMemTransferInst(
ID, NewDst, DstAlign, NewSrc, SrcAlign, Len,
538 IsVolatile,
MI->getAAMetadata());
550 if (OldDst == NewDst && OldSrc == NewSrc)
559 bool IsVolatile = MT->isVolatile();
561 return B.CreateMemMove(NewDst, DstAlign, NewSrc, SrcAlign, Len, IsVolatile,
562 MI->getAAMetadata());
585 PtrOpNum = LD->getPointerOperandIndex();
590 PtrOpNum = ST->getPointerOperandIndex();
595 PtrOpNum = CmpXchg->getPointerOperandIndex();
600 PtrOpNum = RMW->getPointerOperandIndex();
609 Function *Callee = CI->getCalledFunction();
610 if (!Callee || !Callee->isIntrinsic())
615 bool IsSet =
ID == Intrinsic::memset ||
ID == Intrinsic::memset_inline;
616 bool IsCpy =
ID == Intrinsic::memcpy ||
ID == Intrinsic::memcpy_inline;
617 bool IsMove =
ID == Intrinsic::memmove;
618 if (!IsSet && !IsCpy && !IsMove)
632 I.replaceAllUsesWith(New);
642 if (
G.getAddressSpace() == 0 ||
G.hasSection())
646 OS <<
".addr_space." <<
G.getAddressSpace();
647 G.setSection(SecName);
649 G.setConstant(
false);
664bool BPFCheckAndAdjustIRLegacy::runOnModule(
Module &M) {
666 return adjustIR(M, [&](Function &
F) -> LoopInfo & {
667 return getAnalysis<LoopInfoWrapperPass>(
F).getLoopInfo();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ReachingDefInfo InstSet & ToRemove
static Instruction * aspaceMemSet(Intrinsic::ID ID, DenseMap< Value *, Value * > &Cache, CallInst *CI)
static Instruction * aspaceMemCpy(Intrinsic::ID ID, DenseMap< Value *, Value * > &Cache, CallInst *CI)
static bool insertASpaceCasts(Module &M)
static bool adjustIR(Module &M, function_ref< LoopInfo &(Function &)> GetLoopInfo)
static Instruction * aspaceMemMove(DenseMap< Value *, Value * > &Cache, CallInst *CI)
static bool sinkMinMax(Module &M, function_ref< LoopInfo &(Function &)> GetLoopInfo)
static void checkIR(Module &M)
static bool sinkMinMaxInBB(BasicBlock &BB, const std::function< bool(Instruction *)> &Filter)
static bool removePassThroughBuiltin(Module &M)
static Value * wrapPtrIfASNotZero(DenseMap< Value *, Value * > &Cache, CallInst *CI, Value *P)
static void aspaceWrapOperand(DenseMap< Value *, Value * > &Cache, Instruction *I, unsigned OpNum)
static void unrollGEPStore(CallInst *Call)
static Value * aspaceWrapValue(DenseMap< Value *, Value * > &Cache, Function *F, Value *ToWrap)
static bool removeGEPBuiltins(Module &M)
static void unrollGEPLoad(CallInst *Call)
static bool removeGEPBuiltinsInFunc(Function &F)
static bool removeCompareBuiltin(Module &M)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
Machine Check Debug Module
ModuleAnalysisManager MAM
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file contains the declarations for profiling metadata utility functions.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
static constexpr StringRef TypeIdAttr
The attribute attached to globals representing a type id.
static constexpr StringRef AmaAttr
The attribute attached to globals representing a field access.
static std::pair< GetElementPtrInst *, StoreInst * > reconstructStore(CallInst *Call)
static std::pair< GetElementPtrInst *, LoadInst * > reconstructLoad(CallInst *Call)
LLVM Basic Block Representation.
Represents analyses that only rely on functions' control flow.
Value * getArgOperand(unsigned i) const
This class represents a function call, abstracting a target machine's calling convention.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Predicate getPredicate() const
Return the predicate for this instruction.
This instruction compares its operands according to the predicate given to the constructor.
static bool isGE(Predicate P)
Return true if the predicate is SGE or UGE.
static bool isLT(Predicate P)
Return true if the predicate is SLT or ULT.
static bool isGT(Predicate P)
Return true if the predicate is SGT or UGT.
bool isRelational() const
Return true if the predicate is relational (not EQ or NE).
static bool isLE(Predicate P)
Return true if the predicate is SLE or ULE.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
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.
Analysis pass that exposes the LoopInfo for a function.
LoopT * getLoopFor(const BlockT *BB) const
Return the inner most loop that BB lives in.
Represents a single loop in the control flow graph.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
Value * getIncomingValue(unsigned i) const
Return incoming value number x.
unsigned getNumIncomingValues() const
Return the number of incoming edges.
static PointerType * getUnqual(Type *ElementType)
This constructs a pointer to an object of the specified type in the default address space (address sp...
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.
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
This class represents a sign extension of integer types.
This class represents the LLVM 'select' instruction.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
This class represents zero extension of integer types.
An efficient, type-erasing, non-owning reference to a callable.
A raw_ostream that writes to an SmallVector or SmallString.
Pass manager infrastructure for declaring and invalidating analyses.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
This is an optimization pass for GlobalISel generic memory operations.
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI void setExplicitlyUnknownBranchWeightsIfProfiled(Instruction &I, StringRef PassName, const Function *F=nullptr)
Like setExplicitlyUnknownBranchWeights(...), but only sets unknown branch weights in the new instruct...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
@ Load
The value being inserted comes from a load (InsertElement only).
@ Store
The extracted value is stored (ExtractElement only).
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
ModulePass * createBPFCheckAndAdjustIRLegacyPass()
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
ICmpInst::Predicate Predicate
MinMaxSinkInfo(ICmpInst *ICmp, Value *Other, ICmpInst::Predicate Predicate)
This struct is a compact representation of a valid (non-zero power of two) alignment.
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.