17#include "llvm/IR/IntrinsicsBPF.h"
26#define DEBUG_TYPE "bpf-adjust-opt"
33 cl::desc(
"BPF: Disable Serializing ICMP insns."),
38 cl::desc(
"BPF: Disable Avoiding Speculative Code Motion."),
42class BPFAdjustOptImpl {
43 struct PassThroughInfo {
48 : Input(
I), UsedInst(U), OpIdx(
Idx) {}
52 BPFAdjustOptImpl(
Module *M) :
M(
M) {}
60 bool adjustICmpToBuiltin();
66 bool insertPassThrough();
71bool BPFAdjustOptImpl::run() {
72 bool Changed = adjustICmpToBuiltin();
80 return insertPassThrough() || Changed;
91bool BPFAdjustOptImpl::adjustICmpToBuiltin() {
99 ToBeDeleted =
nullptr;
102 auto *Icmp = dyn_cast<ICmpInst>(&
I);
106 Value *Op0 = Icmp->getOperand(0);
107 if (!isa<TruncInst>(Op0))
110 auto ConstOp1 = dyn_cast<ConstantInt>(Icmp->getOperand(1));
114 auto ConstOp1Val = ConstOp1->getValue().getZExtValue();
115 auto Op = Icmp->getPredicate();
116 if (
Op == ICmpInst::ICMP_ULT ||
Op == ICmpInst::ICMP_UGE) {
117 if ((ConstOp1Val - 1) & ConstOp1Val)
119 }
else if (
Op == ICmpInst::ICMP_ULE ||
Op == ICmpInst::ICMP_UGT) {
120 if (ConstOp1Val & (ConstOp1Val + 1))
129 M, Intrinsic::bpf_compare, {Op0->
getType(), ConstOp1->getType()});
132 Icmp->replaceAllUsesWith(NewInst);
140bool BPFAdjustOptImpl::insertPassThrough() {
141 for (
auto &Info : PassThroughs) {
143 M,
Info.UsedInst->getParent(),
Info.Input,
Info.UsedInst);
144 Info.UsedInst->setOperand(
Info.OpIdx, CI);
147 return !PassThroughs.empty();
152bool BPFAdjustOptImpl::serializeICMPInBB(
Instruction &
I) {
166 auto *Icmp1 = dyn_cast<ICmpInst>(Op0);
169 auto *Icmp2 = dyn_cast<ICmpInst>(Op1);
173 Value *Icmp1Op0 = Icmp1->getOperand(0);
174 Value *Icmp2Op0 = Icmp2->getOperand(0);
175 if (Icmp1Op0 != Icmp2Op0)
180 PassThroughInfo
Info(Icmp1, &
I, 0);
181 PassThroughs.push_back(Info);
187bool BPFAdjustOptImpl::serializeICMPCrossBB(
BasicBlock &BB) {
221 auto *BI = dyn_cast<BranchInst>(TI);
222 if (!BI || !BI->isConditional())
224 auto *
Cond = dyn_cast<ICmpInst>(BI->getCondition());
228 auto Cond2Op =
Cond->getPredicate();
231 BI = dyn_cast<BranchInst>(TI);
232 if (!BI || !BI->isConditional())
234 Cond = dyn_cast<ICmpInst>(BI->getCondition());
238 auto Cond1Op =
Cond->getPredicate();
243 if (Cond1Op == ICmpInst::ICMP_SGT || Cond1Op == ICmpInst::ICMP_SGE) {
244 if (Cond2Op != ICmpInst::ICMP_SLT && Cond2Op != ICmpInst::ICMP_SLE)
246 }
else if (Cond1Op == ICmpInst::ICMP_SLT || Cond1Op == ICmpInst::ICMP_SLE) {
247 if (Cond2Op != ICmpInst::ICMP_SGT && Cond2Op != ICmpInst::ICMP_SGE)
249 }
else if (Cond1Op == ICmpInst::ICMP_ULT || Cond1Op == ICmpInst::ICMP_ULE) {
250 if (Cond2Op != ICmpInst::ICMP_UGT && Cond2Op != ICmpInst::ICMP_UGE)
252 }
else if (Cond1Op == ICmpInst::ICMP_UGT || Cond1Op == ICmpInst::ICMP_UGE) {
253 if (Cond2Op != ICmpInst::ICMP_ULT && Cond2Op != ICmpInst::ICMP_ULE)
260 PassThroughs.push_back(Info);
267bool BPFAdjustOptImpl::avoidSpeculation(
Instruction &
I) {
268 if (
auto *LdInst = dyn_cast<LoadInst>(&
I)) {
269 if (
auto *GV = dyn_cast<GlobalVariable>(LdInst->getOperand(0))) {
276 if (!isa<LoadInst>(&
I) && !isa<CallInst>(&
I))
300 for (
User *U :
I.users()) {
307 if (
auto *Icmp1 = dyn_cast<ICmpInst>(Inst)) {
308 Value *Icmp1Op1 = Icmp1->getOperand(1);
309 if (!isa<Constant>(Icmp1Op1))
323 if (isa<CallInst>(&I2))
325 if (isa<LoadInst>(&I2) || isa<StoreInst>(&I2))
333 if (Inst->
getOpcode() == Instruction::ZExt ||
334 Inst->
getOpcode() == Instruction::SExt) {
335 PassThroughInfo
Info(&
I, Inst, 0);
337 }
else if (
auto *GI = dyn_cast<GetElementPtrInst>(Inst)) {
340 for (i = 1, e = GI->getNumOperands(); i != e; ++i) {
341 Value *
V = GI->getOperand(i);
348 PassThroughInfo
Info(&
I, GI, i);
360void 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
Module.h This file contains the declarations for the Module class.
static bool isCandidate(const MachineInstr *MI, Register &DefedReg, Register FrameReg)
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 * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
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.