18#include "llvm/IR/IntrinsicsBPF.h"
27#define DEBUG_TYPE "bpf-adjust-opt"
34 cl::desc(
"BPF: Disable Serializing ICMP insns."),
39 cl::desc(
"BPF: Disable Avoiding Speculative Code Motion."),
43class BPFAdjustOptImpl {
44 struct PassThroughInfo {
49 : Input(
I), UsedInst(U), OpIdx(
Idx) {}
53 BPFAdjustOptImpl(
Module *M) :
M(
M) {}
61 bool adjustICmpToBuiltin();
67 bool insertPassThrough();
72bool BPFAdjustOptImpl::run() {
73 bool Changed = adjustICmpToBuiltin();
81 return insertPassThrough() || Changed;
92bool BPFAdjustOptImpl::adjustICmpToBuiltin() {
100 ToBeDeleted =
nullptr;
103 auto *Icmp = dyn_cast<ICmpInst>(&
I);
107 Value *Op0 = Icmp->getOperand(0);
108 if (!isa<TruncInst>(Op0))
111 auto ConstOp1 = dyn_cast<ConstantInt>(Icmp->getOperand(1));
115 auto ConstOp1Val = ConstOp1->getValue().getZExtValue();
116 auto Op = Icmp->getPredicate();
117 if (
Op == ICmpInst::ICMP_ULT ||
Op == ICmpInst::ICMP_UGE) {
118 if ((ConstOp1Val - 1) & ConstOp1Val)
120 }
else if (
Op == ICmpInst::ICMP_ULE ||
Op == ICmpInst::ICMP_UGT) {
121 if (ConstOp1Val & (ConstOp1Val + 1))
130 M, Intrinsic::bpf_compare, {Op0->
getType(), ConstOp1->getType()});
133 Icmp->replaceAllUsesWith(NewInst);
141bool BPFAdjustOptImpl::insertPassThrough() {
142 for (
auto &Info : PassThroughs) {
144 M,
Info.UsedInst->getParent(),
Info.Input,
Info.UsedInst);
145 Info.UsedInst->setOperand(
Info.OpIdx, CI);
148 return !PassThroughs.empty();
153bool BPFAdjustOptImpl::serializeICMPInBB(
Instruction &
I) {
167 auto *Icmp1 = dyn_cast<ICmpInst>(Op0);
170 auto *Icmp2 = dyn_cast<ICmpInst>(Op1);
174 Value *Icmp1Op0 = Icmp1->getOperand(0);
175 Value *Icmp2Op0 = Icmp2->getOperand(0);
176 if (Icmp1Op0 != Icmp2Op0)
181 PassThroughInfo
Info(Icmp1, &
I, 0);
182 PassThroughs.push_back(Info);
188bool BPFAdjustOptImpl::serializeICMPCrossBB(
BasicBlock &BB) {
222 auto *BI = dyn_cast<BranchInst>(TI);
223 if (!BI || !BI->isConditional())
225 auto *
Cond = dyn_cast<ICmpInst>(BI->getCondition());
229 auto Cond2Op =
Cond->getPredicate();
232 BI = dyn_cast<BranchInst>(TI);
233 if (!BI || !BI->isConditional())
235 Cond = dyn_cast<ICmpInst>(BI->getCondition());
239 auto Cond1Op =
Cond->getPredicate();
244 if (Cond1Op == ICmpInst::ICMP_SGT || Cond1Op == ICmpInst::ICMP_SGE) {
245 if (Cond2Op != ICmpInst::ICMP_SLT && Cond2Op != ICmpInst::ICMP_SLE)
247 }
else if (Cond1Op == ICmpInst::ICMP_SLT || Cond1Op == ICmpInst::ICMP_SLE) {
248 if (Cond2Op != ICmpInst::ICMP_SGT && Cond2Op != ICmpInst::ICMP_SGE)
250 }
else if (Cond1Op == ICmpInst::ICMP_ULT || Cond1Op == ICmpInst::ICMP_ULE) {
251 if (Cond2Op != ICmpInst::ICMP_UGT && Cond2Op != ICmpInst::ICMP_UGE)
253 }
else if (Cond1Op == ICmpInst::ICMP_UGT || Cond1Op == ICmpInst::ICMP_UGE) {
254 if (Cond2Op != ICmpInst::ICMP_ULT && Cond2Op != ICmpInst::ICMP_ULE)
261 PassThroughs.push_back(Info);
268bool BPFAdjustOptImpl::avoidSpeculation(
Instruction &
I) {
269 if (
auto *LdInst = dyn_cast<LoadInst>(&
I)) {
270 if (
auto *GV = dyn_cast<GlobalVariable>(LdInst->getOperand(0))) {
277 if (!isa<LoadInst>(&
I) && !isa<CallInst>(&
I))
301 for (
User *U :
I.users()) {
308 if (
auto *Icmp1 = dyn_cast<ICmpInst>(Inst)) {
309 Value *Icmp1Op1 = Icmp1->getOperand(1);
310 if (!isa<Constant>(Icmp1Op1))
324 if (isa<CallInst>(&I2))
326 if (isa<LoadInst>(&I2) || isa<StoreInst>(&I2))
334 if (Inst->
getOpcode() == Instruction::ZExt ||
335 Inst->
getOpcode() == Instruction::SExt) {
336 PassThroughInfo
Info(&
I, Inst, 0);
338 }
else if (
auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
341 for (i = 1, e = GI->getNumOperands(); i != e; ++i) {
342 Value *
V = GI->getOperand(i);
349 PassThroughInfo
Info(&
I, GI, i);
361void BPFAdjustOptImpl::adjustBasicBlock(
BasicBlock &BB) {
static cl::opt< bool > DisableBPFserializeICMP("bpf-disable-serialize-icmp", cl::Hidden, cl::desc("BPF: Disable Serializing ICMP insns."), cl::init(false))
static cl::opt< bool > DisableBPFavoidSpeculation("bpf-disable-avoid-speculation", cl::Hidden, cl::desc("BPF: Disable Avoiding Speculative Code Motion."), cl::init(false))
Analysis containing CSE Info
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
static bool isCandidate(const MachineInstr *MI, Register &DefedReg, Register FrameReg)
Module.h This file contains the declarations for the Module class.
const SmallVectorImpl< MachineOperand > & Cond
A container for analyses that lazily runs them and caches their results.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
static constexpr StringRef TypeIdAttr
The attribute attached to globals representing a type id.
static Instruction * insertPassThrough(Module *M, BasicBlock *BB, Instruction *Input, Instruction *Before)
Insert a bpf passthrough builtin function.
static constexpr StringRef AmaAttr
The attribute attached to globals representing a field access.
LLVM Basic Block Representation.
const Instruction * getFirstNonPHI() const
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
const BasicBlock * getSinglePredecessor() const
Return the predecessor of this block if it has a single predecessor block.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction if the block is well formed or null if the block is not well forme...
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
This is an important base class in LLVM.
This class represents an Operation in the Expression.
This instruction compares its operands according to the predicate given to the constructor.
void insertBefore(Instruction *InsertPos)
Insert an unlinked instruction into a basic block immediately before the specified instruction.
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
A Module instance is used to store all the information related to an LLVM module.
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.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static IntegerType * getInt32Ty(LLVMContext &C)
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
const ParentTy * getParent() const
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
bool match(Val *V, const Pattern &P)
auto m_LogicalOr()
Matches L || R where L and R are arbitrary values.
class_match< Value > m_Value()
Match an arbitrary value and ignore it.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
This is an optimization pass for GlobalISel generic memory operations.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.