29#include "llvm/IR/IntrinsicsBPF.h"
36#define DEBUG_TYPE "bpf-check-and-opt-ir"
42class BPFCheckAndAdjustIR final :
public ModulePass {
43 bool runOnModule(
Module &
F)
override;
48 virtual void getAnalysisUsage(
AnalysisUsage &AU)
const override;
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) {
107 CallInst *ToBeDeleted =
nullptr;
108 for (Function &
F : M)
113 ToBeDeleted =
nullptr;
122 if (!GV->getName().starts_with(
"llvm.bpf.passthrough"))
132bool BPFCheckAndAdjustIR::removeCompareBuiltin(
Module &M) {
137 CallInst *ToBeDeleted =
nullptr;
138 for (Function &
F : M)
143 ToBeDeleted =
nullptr;
152 if (!GV->getName().starts_with(
"llvm.bpf.compare"))
163 auto *ICmp =
new ICmpInst(Opcode, Arg1, Arg2);
194 V = ZExt->getOperand(0);
197 V = SExt->getOperand(0);
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())
232 return Builder.CreateSExt(V,
Info.SExt->getType());
235 if (
Info.ZExt->getType() == V->getType())
237 return Builder.CreateZExt(V,
Info.ZExt->getType());
262 bool SecondMinMax = IsMinMaxCall(ICmp->
getOperand(1), Second);
263 if (!(FirstMinMax ^ SecondMinMax))
270 for (
auto &
Info : SinkList) {
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))
296 Replacement = Builder.CreateLogicalAnd(
LHS,
RHS);
300 Replacement = Builder.CreateLogicalOr(
LHS,
RHS);
306 if (
I &&
I->use_empty())
307 I->eraseFromParent();
342bool BPFCheckAndAdjustIR::sinkMinMax(
Module &M) {
345 for (Function &
F : M) {
346 if (
F.isDeclaration())
349 LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>(
F).getLoopInfo();
351 for (BasicBlock *BB :
L->blocks()) {
353 Loop *BBLoop = LI.getLoopFor(BB);
355 return LI.getLoopFor(
I->getParent()) != BBLoop;
364void BPFCheckAndAdjustIR::getAnalysisUsage(AnalysisUsage &AU)
const {
370 GEP->insertBefore(
Call->getIterator());
371 Load->insertBefore(
Call->getIterator());
372 Call->replaceAllUsesWith(Load);
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:
412bool BPFCheckAndAdjustIR::removeGEPBuiltins(
Module &M) {
430 auto It = Cache.find(ToWrap);
431 if (It != Cache.end())
432 return It->getSecond();
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();
491bool BPFCheckAndAdjustIR::insertASpaceCasts(
Module &M) {
493 for (Function &
F : M) {
494 DenseMap<Value *, Value *> CastsCache;
495 for (BasicBlock &BB :
F) {
496 for (Instruction &
I : BB) {
500 PtrOpNum =
LD->getPointerOperandIndex();
502 PtrOpNum =
ST->getPointerOperandIndex();
504 PtrOpNum = CmpXchg->getPointerOperandIndex();
506 PtrOpNum = RMW->getPointerOperandIndex();
517 for (GlobalVariable &
G :
M.globals()) {
518 if (
G.getAddressSpace() == 0 ||
G.hasSection())
520 SmallString<16> SecName;
521 raw_svector_ostream OS(SecName);
522 OS <<
".addr_space." <<
G.getAddressSpace();
523 G.setSection(SecName);
525 G.setConstant(
false);
530bool BPFCheckAndAdjustIR::adjustIR(
Module &M) {
531 bool Changed = removePassThroughBuiltin(M);
539bool BPFCheckAndAdjustIR::runOnModule(
Module &M) {
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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< 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.
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()
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)