30#include "llvm/IR/IntrinsicsBPF.h"
37#define DEBUG_TYPE "bpf-check-and-opt-ir"
43class BPFCheckAndAdjustIR final :
public ModulePass {
44 bool runOnModule(
Module &
F)
override;
49 virtual void getAnalysisUsage(
AnalysisUsage &AU)
const override;
54 bool removePassThroughBuiltin(
Module &M);
55 bool removeCompareBuiltin(
Module &M);
56 bool sinkMinMax(
Module &M);
57 bool removeGEPBuiltins(
Module &M);
58 bool insertASpaceCasts(
Module &M);
62char BPFCheckAndAdjustIR::ID = 0;
67 return new BPFCheckAndAdjustIR();
70void BPFCheckAndAdjustIR::checkIR(
Module &M) {
103bool BPFCheckAndAdjustIR::removePassThroughBuiltin(
Module &M) {
108 CallInst *ToBeDeleted =
nullptr;
109 for (Function &
F : M)
114 ToBeDeleted =
nullptr;
123 if (!GV->getName().starts_with(
"llvm.bpf.passthrough"))
133bool BPFCheckAndAdjustIR::removeCompareBuiltin(
Module &M) {
138 CallInst *ToBeDeleted =
nullptr;
139 for (Function &
F : M)
144 ToBeDeleted =
nullptr;
153 if (!GV->getName().starts_with(
"llvm.bpf.compare"))
164 auto *ICmp =
new ICmpInst(Opcode, Arg1, Arg2);
195 V = ZExt->getOperand(0);
198 V = SExt->getOperand(0);
210 switch (Called->getIntrinsicID()) {
211 case Intrinsic::smin:
212 case Intrinsic::umin:
213 case Intrinsic::smax:
214 case Intrinsic::umax:
231 if (
Info.SExt->getType() == V->getType())
233 return Builder.CreateSExt(V,
Info.SExt->getType());
236 if (
Info.ZExt->getType() == V->getType())
238 return Builder.CreateZExt(V,
Info.ZExt->getType());
263 bool SecondMinMax = IsMinMaxCall(ICmp->
getOperand(1), Second);
264 if (!(FirstMinMax ^ SecondMinMax))
271 for (
auto &
Info : SinkList) {
277 IID != Intrinsic::smax)
284 bool IsMin = IID == Intrinsic::smin || IID == Intrinsic::umin;
285 bool IsMax = IID == Intrinsic::smax || IID == Intrinsic::umax;
289 assert(IsLess ^ IsGreater);
294 if ((IsLess && IsMin) || (IsGreater && IsMax))
297 Replacement = Builder.CreateLogicalAnd(
LHS,
RHS);
301 Replacement = Builder.CreateLogicalOr(
LHS,
RHS);
307 if (
I &&
I->use_empty())
308 I->eraseFromParent();
343bool BPFCheckAndAdjustIR::sinkMinMax(
Module &M) {
346 for (Function &
F : M) {
347 if (
F.isDeclaration())
350 LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>(
F).getLoopInfo();
352 for (BasicBlock *BB :
L->blocks()) {
354 Loop *BBLoop = LI.getLoopFor(BB);
356 return LI.getLoopFor(
I->getParent()) != BBLoop;
365void BPFCheckAndAdjustIR::getAnalysisUsage(AnalysisUsage &AU)
const {
371 GEP->insertBefore(
Call->getIterator());
372 Load->insertBefore(
Call->getIterator());
373 Call->replaceAllUsesWith(Load);
374 Call->eraseFromParent();
379 GEP->insertBefore(
Call->getIterator());
380 Store->insertBefore(
Call->getIterator());
381 Call->eraseFromParent();
388 for (
auto &Insn : BB)
390 if (
auto *Called =
Call->getCalledFunction())
391 switch (Called->getIntrinsicID()) {
392 case Intrinsic::bpf_getelementptr_and_load:
395 case Intrinsic::bpf_getelementptr_and_store:
413bool BPFCheckAndAdjustIR::removeGEPBuiltins(
Module &M) {
431 auto It = Cache.find(ToWrap);
432 if (It != Cache.end())
433 return It->getSecond();
439 auto *NewGEP =
GEP->clone();
440 NewGEP->insertAfter(
GEP->getIterator());
442 NewGEP->setOperand(
GEP->getPointerOperandIndex(), WrappedPtr);
443 NewGEP->setName(
GEP->getName());
444 Cache[ToWrap] = NewGEP;
450 IB.SetInsertPoint(*InsnPtr->getInsertionPointAfterDef());
452 IB.SetInsertPoint(
F->getEntryBlock().getFirstInsertionPt());
453 auto *ASZeroPtrTy = IB.getPtrTy(0);
454 auto *ACast = IB.CreateAddrSpaceCast(ToWrap, ASZeroPtrTy, ToWrap->
getName());
455 Cache[ToWrap] = ACast;
463 Value *OldOp =
I->getOperand(OpNum);
468 I->setOperand(OpNum, NewOp);
475 if (!OldGEP->use_empty())
477 OldOp = OldGEP->getPointerOperand();
478 OldGEP->eraseFromParent();
485 if (PTy->getAddressSpace() == 0)
499 if (OldDst == NewDst)
508 bool IsVolatile = MS->isVolatile();
510 if (
ID == Intrinsic::memset)
511 return B.CreateMemSet(NewDst, Val, Len,
Align, IsVolatile,
512 MI->getAAMetadata());
514 return B.CreateMemSetInline(NewDst,
Align, Val, Len, IsVolatile,
515 MI->getAAMetadata());
528 if (OldDst == NewDst && OldSrc == NewSrc)
537 bool IsVolatile = MT->isVolatile();
539 return B.CreateMemTransferInst(
ID, NewDst, DstAlign, NewSrc, SrcAlign, Len,
540 IsVolatile,
MI->getAAMetadata());
552 if (OldDst == NewDst && OldSrc == NewSrc)
561 bool IsVolatile = MT->isVolatile();
563 return B.CreateMemMove(NewDst, DstAlign, NewSrc, SrcAlign, Len, IsVolatile,
564 MI->getAAMetadata());
578bool BPFCheckAndAdjustIR::insertASpaceCasts(
Module &M) {
580 for (Function &
F : M) {
581 DenseMap<Value *, Value *> CastsCache;
582 for (BasicBlock &BB :
F) {
587 PtrOpNum =
LD->getPointerOperandIndex();
592 PtrOpNum =
ST->getPointerOperandIndex();
597 PtrOpNum = CmpXchg->getPointerOperandIndex();
602 PtrOpNum = RMW->getPointerOperandIndex();
612 if (!Callee || !
Callee->isIntrinsic())
617 bool IsSet =
ID == Intrinsic::memset ||
ID == Intrinsic::memset_inline;
618 bool IsCpy =
ID == Intrinsic::memcpy ||
ID == Intrinsic::memcpy_inline;
619 bool IsMove =
ID == Intrinsic::memmove;
620 if (!IsSet && !IsCpy && !IsMove)
634 I.replaceAllUsesWith(New);
643 for (GlobalVariable &
G :
M.globals()) {
644 if (
G.getAddressSpace() == 0 ||
G.hasSection())
646 SmallString<16> SecName;
647 raw_svector_ostream OS(SecName);
648 OS <<
".addr_space." <<
G.getAddressSpace();
649 G.setSection(SecName);
651 G.setConstant(
false);
656bool BPFCheckAndAdjustIR::adjustIR(
Module &M) {
657 bool Changed = removePassThroughBuiltin(M);
665bool BPFCheckAndAdjustIR::runOnModule(
Module &M) {
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 Instruction * aspaceMemMove(DenseMap< Value *, Value * > &Cache, CallInst *CI)
static bool sinkMinMaxInBB(BasicBlock &BB, const std::function< bool(Instruction *)> &Filter)
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 void unrollGEPLoad(CallInst *Call)
static bool removeGEPBuiltinsInFunc(Function &F)
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
Analysis containing CSE Info
Module.h This file contains the declarations for the Module class.
Machine Check Debug Module
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
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.
Value * getCalledOperand() const
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.
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...
This class represents a sign extension of integer types.
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.
self_iterator getIterator()
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
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.
ModulePass * createBPFCheckAndAdjustIR()
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...
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.
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.