31#include "llvm/IR/IntrinsicsBPF.h"
39#define DEBUG_TYPE "bpf-check-and-opt-ir"
45class BPFCheckAndAdjustIR final :
public ModulePass {
56 bool removePassThroughBuiltin(
Module &M);
57 bool removeCompareBuiltin(
Module &M);
58 bool sinkMinMax(
Module &M);
59 bool removeGEPBuiltins(
Module &M);
60 bool insertASpaceCasts(
Module &M);
64char BPFCheckAndAdjustIR::ID = 0;
69 return new BPFCheckAndAdjustIR();
72void BPFCheckAndAdjustIR::checkIR(
Module &M) {
105bool BPFCheckAndAdjustIR::removePassThroughBuiltin(
Module &M) {
109 bool Changed =
false;
116 ToBeDeleted =
nullptr;
119 auto *
Call = dyn_cast<CallInst>(&
I);
122 auto *GV = dyn_cast<GlobalValue>(
Call->getCalledOperand());
125 if (!GV->getName().starts_with(
"llvm.bpf.passthrough"))
129 Call->replaceAllUsesWith(Arg);
135bool BPFCheckAndAdjustIR::removeCompareBuiltin(
Module &M) {
139 bool Changed =
false;
146 ToBeDeleted =
nullptr;
149 auto *
Call = dyn_cast<CallInst>(&
I);
152 auto *GV = dyn_cast<GlobalValue>(
Call->getCalledOperand());
155 if (!GV->getName().starts_with(
"llvm.bpf.compare"))
163 auto OpVal = cast<ConstantInt>(Arg0)->getValue().getZExtValue();
166 auto *ICmp =
new ICmpInst(Opcode, Arg1, Arg2);
167 ICmp->insertBefore(Call);
169 Call->replaceAllUsesWith(ICmp);
196 if (
auto *ZExt = dyn_cast<ZExtInst>(V)) {
197 V = ZExt->getOperand(0);
199 }
else if (
auto *SExt = dyn_cast<SExtInst>(V)) {
200 V = SExt->getOperand(0);
204 auto *Call = dyn_cast<CallInst>(V);
208 auto *Called = dyn_cast<Function>(Call->getCalledOperand());
212 switch (Called->getIntrinsicID()) {
213 case Intrinsic::smin:
214 case Intrinsic::umin:
215 case Intrinsic::smax:
216 case Intrinsic::umax:
233 if (
Info.SExt->getType() == V->getType())
238 if (
Info.ZExt->getType() == V->getType())
245 bool Changed =
false;
265 bool SecondMinMax = IsMinMaxCall(ICmp->
getOperand(1), Second);
266 if (!(FirstMinMax ^ SecondMinMax))
273 for (
auto &
Info : SinkList) {
278 if (ICmpInst::isSigned(
P) && IID != Intrinsic::smin &&
279 IID != Intrinsic::smax)
286 bool IsMin = IID == Intrinsic::smin || IID == Intrinsic::umin;
287 bool IsMax = IID == Intrinsic::smax || IID == Intrinsic::umax;
291 assert(IsLess ^ IsGreater);
296 if ((IsLess && IsMin) || (IsGreater && IsMax))
309 if (
I &&
I->use_empty())
310 I->eraseFromParent();
345bool BPFCheckAndAdjustIR::sinkMinMax(
Module &M) {
346 bool Changed =
false;
349 if (
F.isDeclaration())
352 LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>(
F).getLoopInfo();
356 Loop *BBLoop = LI.getLoopFor(BB);
358 return LI.getLoopFor(
I->getParent()) != BBLoop;
367void BPFCheckAndAdjustIR::getAnalysisUsage(
AnalysisUsage &AU)
const {
373 GEP->insertBefore(Call);
374 Load->insertBefore(Call);
375 Call->replaceAllUsesWith(Load);
376 Call->eraseFromParent();
381 GEP->insertBefore(Call);
382 Store->insertBefore(Call);
383 Call->eraseFromParent();
390 for (
auto &
Insn : BB)
391 if (
auto *Call = dyn_cast<CallInst>(&
Insn))
392 if (
auto *Called = Call->getCalledFunction())
393 switch (Called->getIntrinsicID()) {
394 case Intrinsic::bpf_getelementptr_and_load:
397 case Intrinsic::bpf_getelementptr_and_store:
415bool BPFCheckAndAdjustIR::removeGEPBuiltins(
Module &M) {
416 bool Changed =
false;
433 auto It = Cache.
find(ToWrap);
434 if (It != Cache.
end())
435 return It->getSecond();
437 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(ToWrap)) {
440 auto *GEPTy = cast<PointerType>(
GEP->getType());
441 auto *NewGEP =
GEP->clone();
442 NewGEP->insertAfter(
GEP);
443 NewGEP->mutateType(GEPTy->getPointerTo(0));
444 NewGEP->setOperand(
GEP->getPointerOperandIndex(), WrappedPtr);
445 NewGEP->setName(
GEP->getName());
446 Cache[ToWrap] = NewGEP;
451 if (
Instruction *InsnPtr = dyn_cast<Instruction>(ToWrap))
452 IB.SetInsertPoint(*InsnPtr->getInsertionPointAfterDef());
454 IB.SetInsertPoint(
F->getEntryBlock().getFirstInsertionPt());
455 auto *PtrTy = cast<PointerType>(ToWrap->
getType());
456 auto *ASZeroPtrTy = PtrTy->getPointerTo(0);
457 auto *ACast = IB.CreateAddrSpaceCast(ToWrap, ASZeroPtrTy, ToWrap->
getName());
458 Cache[ToWrap] = ACast;
466 Value *OldOp =
I->getOperand(OpNum);
471 I->setOperand(OpNum, NewOp);
475 auto *OldGEP = dyn_cast<GetElementPtrInst>(OldOp);
478 if (!OldGEP->use_empty())
480 OldOp = OldGEP->getPointerOperand();
481 OldGEP->eraseFromParent();
495bool BPFCheckAndAdjustIR::insertASpaceCasts(
Module &M) {
496 bool Changed =
false;
503 if (
auto *LD = dyn_cast<LoadInst>(&
I))
504 PtrOpNum =
LD->getPointerOperandIndex();
505 else if (
auto *ST = dyn_cast<StoreInst>(&
I))
506 PtrOpNum =
ST->getPointerOperandIndex();
507 else if (
auto *CmpXchg = dyn_cast<AtomicCmpXchgInst>(&
I))
508 PtrOpNum = CmpXchg->getPointerOperandIndex();
509 else if (
auto *RMW = dyn_cast<AtomicRMWInst>(&
I))
510 PtrOpNum = RMW->getPointerOperandIndex();
517 Changed |= !CastsCache.
empty();
522 if (
G.getAddressSpace() == 0 ||
G.hasSection())
526 OS <<
".addr_space." <<
G.getAddressSpace();
527 G.setSection(SecName);
529 G.setConstant(
false);
534bool BPFCheckAndAdjustIR::adjustIR(
Module &M) {
535 bool Changed = removePassThroughBuiltin(M);
536 Changed = removeCompareBuiltin(M) || Changed;
537 Changed = sinkMinMax(M) || Changed;
538 Changed = removeGEPBuiltins(M) || Changed;
539 Changed = insertASpaceCasts(M) || Changed;
543bool BPFCheckAndAdjustIR::runOnModule(
Module &M) {
SmallVector< AArch64_IMM::ImmInsnModel, 4 > Insn
ReachingDefAnalysis InstSet & ToRemove
static bool sinkMinMaxInBB(BasicBlock &BB, const std::function< bool(Instruction *)> &Filter)
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< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
Analysis containing CSE Info
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
Module.h This file contains the declarations for the Module class.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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.
This class represents a function call, abstracting a target machine's calling convention.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Predicate getPredicate() const
Return the predicate for this instruction.
iterator find(const_arg_type_t< KeyT > Val)
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.
Value * CreateSExt(Value *V, Type *DestTy, const Twine &Name="")
Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)
Value * CreateLogicalAnd(Value *Cond1, Value *Cond2, const Twine &Name="")
Value * CreateICmp(CmpInst::Predicate P, Value *LHS, Value *RHS, const Twine &Name="")
Value * CreateLogicalOr(Value *Cond1, Value *Cond2, const Twine &Name="")
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
The legacy pass manager's analysis pass to compute loop information.
Represents a single loop in the control flow graph.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
virtual bool runOnModule(Module &M)=0
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
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.
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
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.
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.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
StringRef getName() const
Return a constant reference to the value's name.
This class represents zero extension of integer types.
A raw_ostream that writes to an SmallVector or SmallString.
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.
ModulePass * createBPFCheckAndAdjustIR()
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
@ First
Helpers to iterate all locations in the MemoryEffectsBase class.
ICmpInst::Predicate Predicate
MinMaxSinkInfo(ICmpInst *ICmp, Value *Other, ICmpInst::Predicate Predicate)