32#include "llvm/IR/IntrinsicsBPF.h"
41#define DEBUG_TYPE "bpf-check-and-opt-ir"
47class BPFCheckAndAdjustIRLegacy final :
public ModulePass {
48 bool runOnModule(
Module &
F)
override;
52 BPFCheckAndAdjustIRLegacy() :
ModulePass(ID) {}
57char BPFCheckAndAdjustIRLegacy::ID = 0;
59 "BPF Check And Adjust IR",
false,
false)
62 return new BPFCheckAndAdjustIRLegacy();
109 ToBeDeleted =
nullptr;
118 if (!GV->getName().starts_with(
"llvm.bpf.passthrough"))
122 Call->replaceAllUsesWith(Arg);
139 ToBeDeleted =
nullptr;
148 if (!GV->getName().starts_with(
"llvm.bpf.compare"))
159 auto *ICmp =
new ICmpInst(Opcode, Arg1, Arg2);
160 ICmp->insertBefore(
Call->getIterator());
162 Call->replaceAllUsesWith(ICmp);
190 V = ZExt->getOperand(0);
193 V = SExt->getOperand(0);
205 switch (Called->getIntrinsicID()) {
206 case Intrinsic::smin:
207 case Intrinsic::umin:
208 case Intrinsic::smax:
209 case Intrinsic::umax:
226 if (Info.SExt->getType() == V->getType())
228 return Builder.CreateSExt(V, Info.SExt->getType());
231 if (Info.ZExt->getType() == V->getType())
233 return Builder.CreateZExt(V, Info.ZExt->getType());
258 bool SecondMinMax = IsMinMaxCall(ICmp->
getOperand(1), Second);
259 if (!(FirstMinMax ^ SecondMinMax))
266 for (
auto &Info : SinkList) {
272 IID != Intrinsic::smax)
277 Value *
A = ZeroOrSignExtend(Builder,
MinMax->getArgOperand(0), Info);
278 Value *
B = ZeroOrSignExtend(Builder,
MinMax->getArgOperand(1), Info);
279 bool IsMin = IID == Intrinsic::smin || IID == Intrinsic::umin;
280 bool IsMax = IID == Intrinsic::smax || IID == Intrinsic::umax;
284 assert(IsLess ^ IsGreater);
289 if ((IsLess && IsMin) || (IsGreater && IsMax))
292 Replacement = Builder.CreateLogicalAnd(
LHS,
RHS);
296 Replacement = Builder.CreateLogicalOr(
LHS,
RHS);
305 if (
I &&
I->use_empty())
306 I->eraseFromParent();
346 if (
F.isDeclaration())
364void BPFCheckAndAdjustIRLegacy::getAnalysisUsage(
AnalysisUsage &AU)
const {
370 GEP->insertBefore(
Call->getIterator());
371 Load->insertBefore(
Call->getIterator());
373 Call->eraseFromParent();
378 GEP->insertBefore(
Call->getIterator());
379 Store->insertBefore(
Call->getIterator());
380 Call->eraseFromParent();
387 for (
auto &Insn : BB)
389 if (
auto *Called =
Call->getCalledFunction())
390 switch (Called->getIntrinsicID()) {
391 case Intrinsic::bpf_getelementptr_and_load:
394 case Intrinsic::bpf_getelementptr_and_store:
430 auto It = Cache.find(ToWrap);
431 if (It != Cache.end())
432 return It->getSecond();
435 Value *Ptr =
GEP->getPointerOperand();
438 auto *NewGEP =
GEP->clone();
439 NewGEP->insertAfter(
GEP->getIterator());
441 NewGEP->setOperand(
GEP->getPointerOperandIndex(), WrappedPtr);
442 NewGEP->setName(
GEP->getName());
443 Cache[ToWrap] = NewGEP;
449 IB.SetInsertPoint(*InsnPtr->getInsertionPointAfterDef());
451 IB.SetInsertPoint(
F->getEntryBlock().getFirstInsertionPt());
452 auto *ASZeroPtrTy = IB.getPtrTy(0);
453 auto *ACast = IB.CreateAddrSpaceCast(ToWrap, ASZeroPtrTy, ToWrap->
getName());
454 Cache[ToWrap] = ACast;
462 Value *OldOp =
I->getOperand(OpNum);
467 I->setOperand(OpNum, NewOp);
474 if (!OldGEP->use_empty())
476 OldOp = OldGEP->getPointerOperand();
477 OldGEP->eraseFromParent();
484 if (PTy->getAddressSpace() == 0)
498 if (OldDst == NewDst)
507 bool IsVolatile = MS->isVolatile();
509 if (ID == Intrinsic::memset)
510 return B.CreateMemSet(NewDst, Val, Len,
Align, IsVolatile,
511 MI->getAAMetadata());
513 return B.CreateMemSetInline(NewDst,
Align, Val, Len, IsVolatile,
514 MI->getAAMetadata());
527 if (OldDst == NewDst && OldSrc == NewSrc)
536 bool IsVolatile = MT->isVolatile();
538 return B.CreateMemTransferInst(ID, NewDst, DstAlign, NewSrc, SrcAlign, Len,
539 IsVolatile,
MI->getAAMetadata());
551 if (OldDst == NewDst && OldSrc == NewSrc)
560 bool IsVolatile = MT->isVolatile();
562 return B.CreateMemMove(NewDst, DstAlign, NewSrc, SrcAlign, Len, IsVolatile,
563 MI->getAAMetadata());
586 PtrOpNum = LD->getPointerOperandIndex();
591 PtrOpNum = ST->getPointerOperandIndex();
596 PtrOpNum = CmpXchg->getPointerOperandIndex();
601 PtrOpNum = RMW->getPointerOperandIndex();
610 Function *Callee = CI->getCalledFunction();
611 if (!Callee || !Callee->isIntrinsic())
616 bool IsSet = ID == Intrinsic::memset || ID == Intrinsic::memset_inline;
617 bool IsCpy = ID == Intrinsic::memcpy || ID == Intrinsic::memcpy_inline;
618 bool IsMove = ID == Intrinsic::memmove;
619 if (!IsSet && !IsCpy && !IsMove)
633 I.replaceAllUsesWith(New);
643 if (
G.getAddressSpace() == 0 ||
G.hasSection())
647 OS <<
".addr_space." <<
G.getAddressSpace();
648 G.setSection(SecName);
650 G.setConstant(
false);
670 if (!
SI || !
SI->getNumCases() ||
675 for (
auto &Case :
SI->cases())
676 ++Cnt[Case.getCaseSuccessor()];
678 return A.second <
B.second;
682 Phi.addIncoming(Phi.getIncomingValueForBlock(&BB), &BB);
683 SI->getDefaultDest()->removePredecessor(&BB);
684 SI->setDefaultDest(Dest);
688 if (It->getCaseSuccessor() != Dest) {
712bool BPFCheckAndAdjustIRLegacy::runOnModule(
Module &M) {
715 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 giveSwitchesDefault(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
This file implements a map that provides insertion order iteration.
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.
iterator_range< const_phi_iterator > phis() const
Returns a range that iterates over the phis in the basic block.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
LLVM_ABI void removePredecessor(BasicBlock *Pred, bool KeepOneInputPHIs=false)
Update PHI nodes in this BasicBlock before removal of predecessor Pred.
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.
This class implements a map that also provides access to all stored values in a deterministic order.
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(LLVMContext &C)
This constructs an opaque pointer to an object in the default address space (address space zero).
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.
A wrapper class to simplify modification of SwitchInst cases along with their prof branch_weights met...
LLVM_ABI SwitchInst::CaseIt removeCase(SwitchInst::CaseIt I)
Delegate the call to the underlying SwitchInst::removeCase() and remove correspondent branch weight.
CaseIt case_end()
Returns a read/write iterator that points one past the last in the SwitchInst.
CaseIt case_begin()
Returns a read/write iterator that points to the first case in the SwitchInst.
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.
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)
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...
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
auto max_element(R &&Range)
Provide wrappers to std::max_element which take ranges instead of having to pass begin/end explicitly...
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.