29#include "llvm/IR/IntrinsicsBPF.h"
36#define DEBUG_TYPE "bpf-check-and-opt-ir"
42class BPFCheckAndAdjustIR final :
public ModulePass {
53 bool removePassThroughBuiltin(
Module &M);
54 bool removeCompareBuiltin(
Module &M);
55 bool sinkMinMax(
Module &M);
56 bool removeGEPBuiltins(
Module &M);
57 bool insertASpaceCasts(
Module &M);
61char BPFCheckAndAdjustIR::ID = 0;
66 return new BPFCheckAndAdjustIR();
69void BPFCheckAndAdjustIR::checkIR(
Module &M) {
102bool BPFCheckAndAdjustIR::removePassThroughBuiltin(
Module &M) {
106 bool Changed =
false;
113 ToBeDeleted =
nullptr;
116 auto *
Call = dyn_cast<CallInst>(&
I);
119 auto *GV = dyn_cast<GlobalValue>(
Call->getCalledOperand());
122 if (!GV->getName().starts_with(
"llvm.bpf.passthrough"))
126 Call->replaceAllUsesWith(Arg);
132bool BPFCheckAndAdjustIR::removeCompareBuiltin(
Module &M) {
136 bool Changed =
false;
143 ToBeDeleted =
nullptr;
146 auto *
Call = dyn_cast<CallInst>(&
I);
149 auto *GV = dyn_cast<GlobalValue>(
Call->getCalledOperand());
152 if (!GV->getName().starts_with(
"llvm.bpf.compare"))
160 auto OpVal = cast<ConstantInt>(Arg0)->getValue().getZExtValue();
163 auto *ICmp =
new ICmpInst(Opcode, Arg1, Arg2);
164 ICmp->insertBefore(Call);
166 Call->replaceAllUsesWith(ICmp);
193 if (
auto *ZExt = dyn_cast<ZExtInst>(V)) {
194 V = ZExt->getOperand(0);
196 }
else if (
auto *SExt = dyn_cast<SExtInst>(V)) {
197 V = SExt->getOperand(0);
201 auto *Call = dyn_cast<CallInst>(V);
205 auto *Called = dyn_cast<Function>(Call->getCalledOperand());
209 switch (Called->getIntrinsicID()) {
210 case Intrinsic::smin:
211 case Intrinsic::umin:
212 case Intrinsic::smax:
213 case Intrinsic::umax:
230 if (
Info.SExt->getType() == V->getType())
235 if (
Info.ZExt->getType() == V->getType())
242 bool Changed =
false;
262 bool SecondMinMax = IsMinMaxCall(ICmp->
getOperand(1), Second);
263 if (!(FirstMinMax ^ SecondMinMax))
270 for (
auto &
Info : SinkList) {
275 if (ICmpInst::isSigned(
P) && IID != Intrinsic::smin &&
276 IID != Intrinsic::smax)
283 bool IsMin = IID == Intrinsic::smin || IID == Intrinsic::umin;
284 bool IsMax = IID == Intrinsic::smax || IID == Intrinsic::umax;
288 assert(IsLess ^ IsGreater);
293 if ((IsLess && IsMin) || (IsGreater && IsMax))
306 if (
I &&
I->use_empty())
307 I->eraseFromParent();
342bool BPFCheckAndAdjustIR::sinkMinMax(
Module &M) {
343 bool Changed =
false;
346 if (
F.isDeclaration())
349 LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>(
F).getLoopInfo();
353 Loop *BBLoop = LI.getLoopFor(BB);
355 return LI.getLoopFor(
I->getParent()) != BBLoop;
364void BPFCheckAndAdjustIR::getAnalysisUsage(
AnalysisUsage &AU)
const {
370 GEP->insertBefore(Call);
371 Load->insertBefore(Call);
372 Call->replaceAllUsesWith(Load);
373 Call->eraseFromParent();
378 GEP->insertBefore(Call);
379 Store->insertBefore(Call);
380 Call->eraseFromParent();
387 for (
auto &
Insn : BB)
388 if (
auto *Call = dyn_cast<CallInst>(&
Insn))
389 if (
auto *Called = Call->getCalledFunction())
390 switch (Called->getIntrinsicID()) {
391 case Intrinsic::bpf_getelementptr_and_load:
394 case Intrinsic::bpf_getelementptr_and_store:
412bool BPFCheckAndAdjustIR::removeGEPBuiltins(
Module &M) {
413 bool Changed =
false;
430 auto It = Cache.
find(ToWrap);
431 if (It != Cache.
end())
432 return It->getSecond();
434 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(ToWrap)) {
437 auto *GEPTy = cast<PointerType>(
GEP->getType());
438 auto *NewGEP =
GEP->clone();
439 NewGEP->insertAfter(
GEP);
440 NewGEP->mutateType(PointerType::getUnqual(GEPTy->getContext()));
441 NewGEP->setOperand(
GEP->getPointerOperandIndex(), WrappedPtr);
442 NewGEP->setName(
GEP->getName());
443 Cache[ToWrap] = NewGEP;
448 if (
Instruction *InsnPtr = dyn_cast<Instruction>(ToWrap))
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);
471 auto *OldGEP = dyn_cast<GetElementPtrInst>(OldOp);
474 if (!OldGEP->use_empty())
476 OldOp = OldGEP->getPointerOperand();
477 OldGEP->eraseFromParent();
491bool BPFCheckAndAdjustIR::insertASpaceCasts(
Module &M) {
492 bool Changed =
false;
499 if (
auto *LD = dyn_cast<LoadInst>(&
I))
500 PtrOpNum =
LD->getPointerOperandIndex();
501 else if (
auto *ST = dyn_cast<StoreInst>(&
I))
502 PtrOpNum =
ST->getPointerOperandIndex();
503 else if (
auto *CmpXchg = dyn_cast<AtomicCmpXchgInst>(&
I))
504 PtrOpNum = CmpXchg->getPointerOperandIndex();
505 else if (
auto *RMW = dyn_cast<AtomicRMWInst>(&
I))
506 PtrOpNum = RMW->getPointerOperandIndex();
513 Changed |= !CastsCache.
empty();
518 if (
G.getAddressSpace() == 0 ||
G.hasSection())
522 OS <<
".addr_space." <<
G.getAddressSpace();
523 G.setSection(SecName);
525 G.setConstant(
false);
530bool BPFCheckAndAdjustIR::adjustIR(
Module &M) {
531 bool Changed = removePassThroughBuiltin(M);
532 Changed = removeCompareBuiltin(M) || Changed;
533 Changed = sinkMinMax(M) || Changed;
534 Changed = removeGEPBuiltins(M) || Changed;
535 Changed = insertASpaceCasts(M) || Changed;
539bool 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)