31#include "llvm/IR/IntrinsicsBPF.h"
39#define DEBUG_TYPE "bpf-check-and-opt-ir"
45class BPFCheckAndAdjustIRLegacy final :
public ModulePass {
46 bool runOnModule(
Module &
F)
override;
55char BPFCheckAndAdjustIRLegacy::ID = 0;
57 "BPF Check And Adjust IR",
false,
false)
60 return new BPFCheckAndAdjustIRLegacy();
107 ToBeDeleted =
nullptr;
116 if (!GV->getName().starts_with(
"llvm.bpf.passthrough"))
120 Call->replaceAllUsesWith(Arg);
137 ToBeDeleted =
nullptr;
146 if (!GV->getName().starts_with(
"llvm.bpf.compare"))
157 auto *ICmp =
new ICmpInst(Opcode, Arg1, Arg2);
158 ICmp->insertBefore(
Call->getIterator());
160 Call->replaceAllUsesWith(ICmp);
188 V = ZExt->getOperand(0);
191 V = SExt->getOperand(0);
203 switch (Called->getIntrinsicID()) {
204 case Intrinsic::smin:
205 case Intrinsic::umin:
206 case Intrinsic::smax:
207 case Intrinsic::umax:
224 if (Info.SExt->getType() == V->getType())
226 return Builder.CreateSExt(V, Info.SExt->getType());
229 if (Info.ZExt->getType() == V->getType())
231 return Builder.CreateZExt(V, Info.ZExt->getType());
256 bool SecondMinMax = IsMinMaxCall(ICmp->
getOperand(1), Second);
257 if (!(FirstMinMax ^ SecondMinMax))
264 for (
auto &Info : SinkList) {
270 IID != Intrinsic::smax)
275 Value *
A = ZeroOrSignExtend(Builder,
MinMax->getArgOperand(0), Info);
276 Value *
B = ZeroOrSignExtend(Builder,
MinMax->getArgOperand(1), Info);
277 bool IsMin = IID == Intrinsic::smin || IID == Intrinsic::umin;
278 bool IsMax = IID == Intrinsic::smax || IID == Intrinsic::umax;
282 assert(IsLess ^ IsGreater);
287 if ((IsLess && IsMin) || (IsGreater && IsMax))
290 Replacement = Builder.CreateLogicalAnd(
LHS,
RHS);
294 Replacement = Builder.CreateLogicalOr(
LHS,
RHS);
300 if (
I &&
I->use_empty())
301 I->eraseFromParent();
341 if (
F.isDeclaration())
359void BPFCheckAndAdjustIRLegacy::getAnalysisUsage(
AnalysisUsage &AU)
const {
365 GEP->insertBefore(
Call->getIterator());
366 Load->insertBefore(
Call->getIterator());
367 Call->replaceAllUsesWith(Load);
368 Call->eraseFromParent();
373 GEP->insertBefore(
Call->getIterator());
374 Store->insertBefore(
Call->getIterator());
375 Call->eraseFromParent();
382 for (
auto &Insn : BB)
384 if (
auto *Called =
Call->getCalledFunction())
385 switch (Called->getIntrinsicID()) {
386 case Intrinsic::bpf_getelementptr_and_load:
389 case Intrinsic::bpf_getelementptr_and_store:
425 auto It = Cache.find(ToWrap);
426 if (It != Cache.end())
427 return It->getSecond();
430 Value *Ptr =
GEP->getPointerOperand();
433 auto *NewGEP =
GEP->clone();
434 NewGEP->insertAfter(
GEP->getIterator());
436 NewGEP->setOperand(
GEP->getPointerOperandIndex(), WrappedPtr);
437 NewGEP->setName(
GEP->getName());
438 Cache[ToWrap] = NewGEP;
444 IB.SetInsertPoint(*InsnPtr->getInsertionPointAfterDef());
446 IB.SetInsertPoint(
F->getEntryBlock().getFirstInsertionPt());
447 auto *ASZeroPtrTy = IB.getPtrTy(0);
448 auto *ACast = IB.CreateAddrSpaceCast(ToWrap, ASZeroPtrTy, ToWrap->
getName());
449 Cache[ToWrap] = ACast;
457 Value *OldOp =
I->getOperand(OpNum);
462 I->setOperand(OpNum, NewOp);
469 if (!OldGEP->use_empty())
471 OldOp = OldGEP->getPointerOperand();
472 OldGEP->eraseFromParent();
479 if (PTy->getAddressSpace() == 0)
493 if (OldDst == NewDst)
502 bool IsVolatile = MS->isVolatile();
504 if (
ID == Intrinsic::memset)
505 return B.CreateMemSet(NewDst, Val, Len,
Align, IsVolatile,
506 MI->getAAMetadata());
508 return B.CreateMemSetInline(NewDst,
Align, Val, Len, IsVolatile,
509 MI->getAAMetadata());
522 if (OldDst == NewDst && OldSrc == NewSrc)
531 bool IsVolatile = MT->isVolatile();
533 return B.CreateMemTransferInst(
ID, NewDst, DstAlign, NewSrc, SrcAlign, Len,
534 IsVolatile,
MI->getAAMetadata());
546 if (OldDst == NewDst && OldSrc == NewSrc)
555 bool IsVolatile = MT->isVolatile();
557 return B.CreateMemMove(NewDst, DstAlign, NewSrc, SrcAlign, Len, IsVolatile,
558 MI->getAAMetadata());
581 PtrOpNum = LD->getPointerOperandIndex();
586 PtrOpNum = ST->getPointerOperandIndex();
591 PtrOpNum = CmpXchg->getPointerOperandIndex();
596 PtrOpNum = RMW->getPointerOperandIndex();
605 Function *Callee = CI->getCalledFunction();
606 if (!Callee || !Callee->isIntrinsic())
611 bool IsSet =
ID == Intrinsic::memset ||
ID == Intrinsic::memset_inline;
612 bool IsCpy =
ID == Intrinsic::memcpy ||
ID == Intrinsic::memcpy_inline;
613 bool IsMove =
ID == Intrinsic::memmove;
614 if (!IsSet && !IsCpy && !IsMove)
628 I.replaceAllUsesWith(New);
638 if (
G.getAddressSpace() == 0 ||
G.hasSection())
642 OS <<
".addr_space." <<
G.getAddressSpace();
643 G.setSection(SecName);
645 G.setConstant(
false);
660bool BPFCheckAndAdjustIRLegacy::runOnModule(
Module &M) {
662 return adjustIR(M, [&](Function &
F) -> LoopInfo & {
663 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)
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.
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.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
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.