HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Android 10
|
10.0.0_r6
下载
查看原文件
收藏
根目录
prebuilts
clang
host
darwin-x86
clang-r346389c
include
llvm
IR
PatternMatch.h
//===- PatternMatch.h - Match on the LLVM IR --------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file provides a simple and efficient mechanism for performing general // tree-based pattern matches on the LLVM IR. The power of these routines is // that it allows you to write concise patterns that are expressive and easy to // understand. The other major advantage of this is that it allows you to // trivially capture/bind elements in the pattern to variables. For example, // you can do something like this: // // Value *Exp = ... // Value *X, *Y; ConstantInt *C1, *C2; // (X & C1) | (Y & C2) // if (match(Exp, m_Or(m_And(m_Value(X), m_ConstantInt(C1)), // m_And(m_Value(Y), m_ConstantInt(C2))))) { // ... Pattern is matched and variables are bound ... // } // // This is primarily useful to things like the instruction combiner, but can // also be useful for static analysis tools or code generators. // //===----------------------------------------------------------------------===// #ifndef LLVM_IR_PATTERNMATCH_H #define LLVM_IR_PATTERNMATCH_H #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/IR/CallSite.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Operator.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" #include
namespace llvm { namespace PatternMatch { template
bool match(Val *V, const Pattern &P) { return const_cast
(P).match(V); } template
struct OneUse_match { SubPattern_t SubPattern; OneUse_match(const SubPattern_t &SP) : SubPattern(SP) {} template
bool match(OpTy *V) { return V->hasOneUse() && SubPattern.match(V); } }; template
inline OneUse_match
m_OneUse(const T &SubPattern) { return SubPattern; } template
struct class_match { template
bool match(ITy *V) { return isa
(V); } }; /// Match an arbitrary value and ignore it. inline class_match
m_Value() { return class_match
(); } /// Match an arbitrary binary operation and ignore it. inline class_match
m_BinOp() { return class_match
(); } /// Matches any compare instruction and ignore it. inline class_match
m_Cmp() { return class_match
(); } /// Match an arbitrary ConstantInt and ignore it. inline class_match
m_ConstantInt() { return class_match
(); } /// Match an arbitrary undef constant. inline class_match
m_Undef() { return class_match
(); } /// Match an arbitrary Constant and ignore it. inline class_match
m_Constant() { return class_match
(); } /// Matching combinators template
struct match_combine_or { LTy L; RTy R; match_combine_or(const LTy &Left, const RTy &Right) : L(Left), R(Right) {} template
bool match(ITy *V) { if (L.match(V)) return true; if (R.match(V)) return true; return false; } }; template
struct match_combine_and { LTy L; RTy R; match_combine_and(const LTy &Left, const RTy &Right) : L(Left), R(Right) {} template
bool match(ITy *V) { if (L.match(V)) if (R.match(V)) return true; return false; } }; /// Combine two pattern matchers matching L || R template
inline match_combine_or
m_CombineOr(const LTy &L, const RTy &R) { return match_combine_or
(L, R); } /// Combine two pattern matchers matching L && R template
inline match_combine_and
m_CombineAnd(const LTy &L, const RTy &R) { return match_combine_and
(L, R); } struct apint_match { const APInt *&Res; apint_match(const APInt *&R) : Res(R) {} template
bool match(ITy *V) { if (auto *CI = dyn_cast
(V)) { Res = &CI->getValue(); return true; } if (V->getType()->isVectorTy()) if (const auto *C = dyn_cast
(V)) if (auto *CI = dyn_cast_or_null
(C->getSplatValue())) { Res = &CI->getValue(); return true; } return false; } }; // Either constexpr if or renaming ConstantFP::getValueAPF to // ConstantFP::getValue is needed to do it via single template // function for both apint/apfloat. struct apfloat_match { const APFloat *&Res; apfloat_match(const APFloat *&R) : Res(R) {} template
bool match(ITy *V) { if (auto *CI = dyn_cast
(V)) { Res = &CI->getValueAPF(); return true; } if (V->getType()->isVectorTy()) if (const auto *C = dyn_cast
(V)) if (auto *CI = dyn_cast_or_null
(C->getSplatValue())) { Res = &CI->getValueAPF(); return true; } return false; } }; /// Match a ConstantInt or splatted ConstantVector, binding the /// specified pointer to the contained APInt. inline apint_match m_APInt(const APInt *&Res) { return Res; } /// Match a ConstantFP or splatted ConstantVector, binding the /// specified pointer to the contained APFloat. inline apfloat_match m_APFloat(const APFloat *&Res) { return Res; } template
struct constantint_match { template
bool match(ITy *V) { if (const auto *CI = dyn_cast
(V)) { const APInt &CIV = CI->getValue(); if (Val >= 0) return CIV == static_cast
(Val); // If Val is negative, and CI is shorter than it, truncate to the right // number of bits. If it is larger, then we have to sign extend. Just // compare their negated values. return -CIV == -Val; } return false; } }; /// Match a ConstantInt with a specific value. template
inline constantint_match
m_ConstantInt() { return constantint_match
(); } /// This helper class is used to match scalar and vector integer constants that /// satisfy a specified predicate. /// For vector constants, undefined elements are ignored. template
struct cst_pred_ty : public Predicate { template
bool match(ITy *V) { if (const auto *CI = dyn_cast
(V)) return this->isValue(CI->getValue()); if (V->getType()->isVectorTy()) { if (const auto *C = dyn_cast
(V)) { if (const auto *CI = dyn_cast_or_null
(C->getSplatValue())) return this->isValue(CI->getValue()); // Non-splat vector constant: check each element for a match. unsigned NumElts = V->getType()->getVectorNumElements(); assert(NumElts != 0 && "Constant vector with no elements?"); for (unsigned i = 0; i != NumElts; ++i) { Constant *Elt = C->getAggregateElement(i); if (!Elt) return false; if (isa
(Elt)) continue; auto *CI = dyn_cast
(Elt); if (!CI || !this->isValue(CI->getValue())) return false; } return true; } } return false; } }; /// This helper class is used to match scalar and vector constants that /// satisfy a specified predicate, and bind them to an APInt. template
struct api_pred_ty : public Predicate { const APInt *&Res; api_pred_ty(const APInt *&R) : Res(R) {} template
bool match(ITy *V) { if (const auto *CI = dyn_cast
(V)) if (this->isValue(CI->getValue())) { Res = &CI->getValue(); return true; } if (V->getType()->isVectorTy()) if (const auto *C = dyn_cast
(V)) if (auto *CI = dyn_cast_or_null
(C->getSplatValue())) if (this->isValue(CI->getValue())) { Res = &CI->getValue(); return true; } return false; } }; /// This helper class is used to match scalar and vector floating-point /// constants that satisfy a specified predicate. /// For vector constants, undefined elements are ignored. template
struct cstfp_pred_ty : public Predicate { template
bool match(ITy *V) { if (const auto *CF = dyn_cast
(V)) return this->isValue(CF->getValueAPF()); if (V->getType()->isVectorTy()) { if (const auto *C = dyn_cast
(V)) { if (const auto *CF = dyn_cast_or_null
(C->getSplatValue())) return this->isValue(CF->getValueAPF()); // Non-splat vector constant: check each element for a match. unsigned NumElts = V->getType()->getVectorNumElements(); assert(NumElts != 0 && "Constant vector with no elements?"); for (unsigned i = 0; i != NumElts; ++i) { Constant *Elt = C->getAggregateElement(i); if (!Elt) return false; if (isa
(Elt)) continue; auto *CF = dyn_cast
(Elt); if (!CF || !this->isValue(CF->getValueAPF())) return false; } return true; } } return false; } }; /////////////////////////////////////////////////////////////////////////////// // // Encapsulate constant value queries for use in templated predicate matchers. // This allows checking if constants match using compound predicates and works // with vector constants, possibly with relaxed constraints. For example, ignore // undef values. // /////////////////////////////////////////////////////////////////////////////// struct is_all_ones { bool isValue(const APInt &C) { return C.isAllOnesValue(); } }; /// Match an integer or vector with all bits set. /// For vectors, this includes constants with undefined elements. inline cst_pred_ty
m_AllOnes() { return cst_pred_ty
(); } struct is_maxsignedvalue { bool isValue(const APInt &C) { return C.isMaxSignedValue(); } }; /// Match an integer or vector with values having all bits except for the high /// bit set (0x7f...). /// For vectors, this includes constants with undefined elements. inline cst_pred_ty
m_MaxSignedValue() { return cst_pred_ty
(); } inline api_pred_ty
m_MaxSignedValue(const APInt *&V) { return V; } struct is_negative { bool isValue(const APInt &C) { return C.isNegative(); } }; /// Match an integer or vector of negative values. /// For vectors, this includes constants with undefined elements. inline cst_pred_ty
m_Negative() { return cst_pred_ty
(); } inline api_pred_ty
m_Negative(const APInt *&V) { return V; } struct is_nonnegative { bool isValue(const APInt &C) { return C.isNonNegative(); } }; /// Match an integer or vector of nonnegative values. /// For vectors, this includes constants with undefined elements. inline cst_pred_ty
m_NonNegative() { return cst_pred_ty
(); } inline api_pred_ty
m_NonNegative(const APInt *&V) { return V; } struct is_one { bool isValue(const APInt &C) { return C.isOneValue(); } }; /// Match an integer 1 or a vector with all elements equal to 1. /// For vectors, this includes constants with undefined elements. inline cst_pred_ty
m_One() { return cst_pred_ty
(); } struct is_zero_int { bool isValue(const APInt &C) { return C.isNullValue(); } }; /// Match an integer 0 or a vector with all elements equal to 0. /// For vectors, this includes constants with undefined elements. inline cst_pred_ty
m_ZeroInt() { return cst_pred_ty
(); } struct is_zero { template
bool match(ITy *V) { auto *C = dyn_cast
(V); return C && (C->isNullValue() || cst_pred_ty
().match(C)); } }; /// Match any null constant or a vector with all elements equal to 0. /// For vectors, this includes constants with undefined elements. inline is_zero m_Zero() { return is_zero(); } struct is_power2 { bool isValue(const APInt &C) { return C.isPowerOf2(); } }; /// Match an integer or vector power-of-2. /// For vectors, this includes constants with undefined elements. inline cst_pred_ty
m_Power2() { return cst_pred_ty
(); } inline api_pred_ty
m_Power2(const APInt *&V) { return V; } struct is_power2_or_zero { bool isValue(const APInt &C) { return !C || C.isPowerOf2(); } }; /// Match an integer or vector of 0 or power-of-2 values. /// For vectors, this includes constants with undefined elements. inline cst_pred_ty
m_Power2OrZero() { return cst_pred_ty
(); } inline api_pred_ty
m_Power2OrZero(const APInt *&V) { return V; } struct is_sign_mask { bool isValue(const APInt &C) { return C.isSignMask(); } }; /// Match an integer or vector with only the sign bit(s) set. /// For vectors, this includes constants with undefined elements. inline cst_pred_ty
m_SignMask() { return cst_pred_ty
(); } struct is_lowbit_mask { bool isValue(const APInt &C) { return C.isMask(); } }; /// Match an integer or vector with only the low bit(s) set. /// For vectors, this includes constants with undefined elements. inline cst_pred_ty
m_LowBitMask() { return cst_pred_ty
(); } struct is_nan { bool isValue(const APFloat &C) { return C.isNaN(); } }; /// Match an arbitrary NaN constant. This includes quiet and signalling nans. /// For vectors, this includes constants with undefined elements. inline cstfp_pred_ty
m_NaN() { return cstfp_pred_ty
(); } struct is_any_zero_fp { bool isValue(const APFloat &C) { return C.isZero(); } }; /// Match a floating-point negative zero or positive zero. /// For vectors, this includes constants with undefined elements. inline cstfp_pred_ty
m_AnyZeroFP() { return cstfp_pred_ty
(); } struct is_pos_zero_fp { bool isValue(const APFloat &C) { return C.isPosZero(); } }; /// Match a floating-point positive zero. /// For vectors, this includes constants with undefined elements. inline cstfp_pred_ty
m_PosZeroFP() { return cstfp_pred_ty
(); } struct is_neg_zero_fp { bool isValue(const APFloat &C) { return C.isNegZero(); } }; /// Match a floating-point negative zero. /// For vectors, this includes constants with undefined elements. inline cstfp_pred_ty
m_NegZeroFP() { return cstfp_pred_ty
(); } /////////////////////////////////////////////////////////////////////////////// template
struct bind_ty { Class *&VR; bind_ty(Class *&V) : VR(V) {} template
bool match(ITy *V) { if (auto *CV = dyn_cast
(V)) { VR = CV; return true; } return false; } }; /// Match a value, capturing it if we match. inline bind_ty
m_Value(Value *&V) { return V; } inline bind_ty
m_Value(const Value *&V) { return V; } /// Match an instruction, capturing it if we match. inline bind_ty
m_Instruction(Instruction *&I) { return I; } /// Match a binary operator, capturing it if we match. inline bind_ty
m_BinOp(BinaryOperator *&I) { return I; } /// Match a ConstantInt, capturing the value if we match. inline bind_ty
m_ConstantInt(ConstantInt *&CI) { return CI; } /// Match a Constant, capturing the value if we match. inline bind_ty
m_Constant(Constant *&C) { return C; } /// Match a ConstantFP, capturing the value if we match. inline bind_ty
m_ConstantFP(ConstantFP *&C) { return C; } /// Match a specified Value*. struct specificval_ty { const Value *Val; specificval_ty(const Value *V) : Val(V) {} template
bool match(ITy *V) { return V == Val; } }; /// Match if we have a specific specified value. inline specificval_ty m_Specific(const Value *V) { return V; } /// Stores a reference to the Value *, not the Value * itself, /// thus can be used in commutative matchers. template
struct deferredval_ty { Class *const &Val; deferredval_ty(Class *const &V) : Val(V) {} template
bool match(ITy *const V) { return V == Val; } }; /// A commutative-friendly version of m_Specific(). inline deferredval_ty
m_Deferred(Value *const &V) { return V; } inline deferredval_ty
m_Deferred(const Value *const &V) { return V; } /// Match a specified floating point value or vector of all elements of /// that value. struct specific_fpval { double Val; specific_fpval(double V) : Val(V) {} template
bool match(ITy *V) { if (const auto *CFP = dyn_cast
(V)) return CFP->isExactlyValue(Val); if (V->getType()->isVectorTy()) if (const auto *C = dyn_cast
(V)) if (auto *CFP = dyn_cast_or_null
(C->getSplatValue())) return CFP->isExactlyValue(Val); return false; } }; /// Match a specific floating point value or vector with all elements /// equal to the value. inline specific_fpval m_SpecificFP(double V) { return specific_fpval(V); } /// Match a float 1.0 or vector with all elements equal to 1.0. inline specific_fpval m_FPOne() { return m_SpecificFP(1.0); } struct bind_const_intval_ty { uint64_t &VR; bind_const_intval_ty(uint64_t &V) : VR(V) {} template
bool match(ITy *V) { if (const auto *CV = dyn_cast
(V)) if (CV->getValue().ule(UINT64_MAX)) { VR = CV->getZExtValue(); return true; } return false; } }; /// Match a specified integer value or vector of all elements of that // value. struct specific_intval { uint64_t Val; specific_intval(uint64_t V) : Val(V) {} template
bool match(ITy *V) { const auto *CI = dyn_cast
(V); if (!CI && V->getType()->isVectorTy()) if (const auto *C = dyn_cast
(V)) CI = dyn_cast_or_null
(C->getSplatValue()); return CI && CI->getValue() == Val; } }; /// Match a specific integer value or vector with all elements equal to /// the value. inline specific_intval m_SpecificInt(uint64_t V) { return specific_intval(V); } /// Match a ConstantInt and bind to its value. This does not match /// ConstantInts wider than 64-bits. inline bind_const_intval_ty m_ConstantInt(uint64_t &V) { return V; } //===----------------------------------------------------------------------===// // Matcher for any binary operator. // template
struct AnyBinaryOp_match { LHS_t L; RHS_t R; // The evaluation order is always stable, regardless of Commutability. // The LHS is always matched first. AnyBinaryOp_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {} template
bool match(OpTy *V) { if (auto *I = dyn_cast
(V)) return (L.match(I->getOperand(0)) && R.match(I->getOperand(1))) || (Commutable && L.match(I->getOperand(1)) && R.match(I->getOperand(0))); return false; } }; template
inline AnyBinaryOp_match
m_BinOp(const LHS &L, const RHS &R) { return AnyBinaryOp_match
(L, R); } //===----------------------------------------------------------------------===// // Matchers for specific binary operators. // template
struct BinaryOp_match { LHS_t L; RHS_t R; // The evaluation order is always stable, regardless of Commutability. // The LHS is always matched first. BinaryOp_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {} template
bool match(OpTy *V) { if (V->getValueID() == Value::InstructionVal + Opcode) { auto *I = cast
(V); return (L.match(I->getOperand(0)) && R.match(I->getOperand(1))) || (Commutable && L.match(I->getOperand(1)) && R.match(I->getOperand(0))); } if (auto *CE = dyn_cast
(V)) return CE->getOpcode() == Opcode && ((L.match(CE->getOperand(0)) && R.match(CE->getOperand(1))) || (Commutable && L.match(CE->getOperand(1)) && R.match(CE->getOperand(0)))); return false; } }; template
inline BinaryOp_match
m_Add(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_FAdd(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_Sub(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_FSub(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
struct FNeg_match { Op_t X; FNeg_match(const Op_t &Op) : X(Op) {} template
bool match(OpTy *V) { auto *FPMO = dyn_cast
(V); if (!FPMO || FPMO->getOpcode() != Instruction::FSub) return false; if (FPMO->hasNoSignedZeros()) { // With 'nsz', any zero goes. if (!cstfp_pred_ty
().match(FPMO->getOperand(0))) return false; } else { // Without 'nsz', we need fsub -0.0, X exactly. if (!cstfp_pred_ty
().match(FPMO->getOperand(0))) return false; } return X.match(FPMO->getOperand(1)); } }; /// Match 'fneg X' as 'fsub -0.0, X'. template
inline FNeg_match
m_FNeg(const OpTy &X) { return FNeg_match
(X); } /// Match 'fneg X' as 'fsub +-0.0, X'. template
inline BinaryOp_match
, RHS, Instruction::FSub> m_FNegNSZ(const RHS &X) { return m_FSub(m_AnyZeroFP(), X); } template
inline BinaryOp_match
m_Mul(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_FMul(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_UDiv(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_SDiv(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_FDiv(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_URem(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_SRem(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_FRem(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_And(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_Or(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_Xor(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_Shl(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_LShr(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
inline BinaryOp_match
m_AShr(const LHS &L, const RHS &R) { return BinaryOp_match
(L, R); } template
struct OverflowingBinaryOp_match { LHS_t L; RHS_t R; OverflowingBinaryOp_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {} template
bool match(OpTy *V) { if (auto *Op = dyn_cast
(V)) { if (Op->getOpcode() != Opcode) return false; if (WrapFlags & OverflowingBinaryOperator::NoUnsignedWrap && !Op->hasNoUnsignedWrap()) return false; if (WrapFlags & OverflowingBinaryOperator::NoSignedWrap && !Op->hasNoSignedWrap()) return false; return L.match(Op->getOperand(0)) && R.match(Op->getOperand(1)); } return false; } }; template
inline OverflowingBinaryOp_match
m_NSWAdd(const LHS &L, const RHS &R) { return OverflowingBinaryOp_match
( L, R); } template
inline OverflowingBinaryOp_match
m_NSWSub(const LHS &L, const RHS &R) { return OverflowingBinaryOp_match
( L, R); } template
inline OverflowingBinaryOp_match
m_NSWMul(const LHS &L, const RHS &R) { return OverflowingBinaryOp_match
( L, R); } template
inline OverflowingBinaryOp_match
m_NSWShl(const LHS &L, const RHS &R) { return OverflowingBinaryOp_match
( L, R); } template
inline OverflowingBinaryOp_match
m_NUWAdd(const LHS &L, const RHS &R) { return OverflowingBinaryOp_match
( L, R); } template
inline OverflowingBinaryOp_match
m_NUWSub(const LHS &L, const RHS &R) { return OverflowingBinaryOp_match
( L, R); } template
inline OverflowingBinaryOp_match
m_NUWMul(const LHS &L, const RHS &R) { return OverflowingBinaryOp_match
( L, R); } template
inline OverflowingBinaryOp_match
m_NUWShl(const LHS &L, const RHS &R) { return OverflowingBinaryOp_match
( L, R); } //===----------------------------------------------------------------------===// // Class that matches a group of binary opcodes. // template
struct BinOpPred_match : Predicate { LHS_t L; RHS_t R; BinOpPred_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {} template
bool match(OpTy *V) { if (auto *I = dyn_cast
(V)) return this->isOpType(I->getOpcode()) && L.match(I->getOperand(0)) && R.match(I->getOperand(1)); if (auto *CE = dyn_cast
(V)) return this->isOpType(CE->getOpcode()) && L.match(CE->getOperand(0)) && R.match(CE->getOperand(1)); return false; } }; struct is_shift_op { bool isOpType(unsigned Opcode) { return Instruction::isShift(Opcode); } }; struct is_right_shift_op { bool isOpType(unsigned Opcode) { return Opcode == Instruction::LShr || Opcode == Instruction::AShr; } }; struct is_logical_shift_op { bool isOpType(unsigned Opcode) { return Opcode == Instruction::LShr || Opcode == Instruction::Shl; } }; struct is_bitwiselogic_op { bool isOpType(unsigned Opcode) { return Instruction::isBitwiseLogicOp(Opcode); } }; struct is_idiv_op { bool isOpType(unsigned Opcode) { return Opcode == Instruction::SDiv || Opcode == Instruction::UDiv; } }; /// Matches shift operations. template
inline BinOpPred_match
m_Shift(const LHS &L, const RHS &R) { return BinOpPred_match
(L, R); } /// Matches logical shift operations. template
inline BinOpPred_match
m_Shr(const LHS &L, const RHS &R) { return BinOpPred_match
(L, R); } /// Matches logical shift operations. template
inline BinOpPred_match
m_LogicalShift(const LHS &L, const RHS &R) { return BinOpPred_match
(L, R); } /// Matches bitwise logic operations. template
inline BinOpPred_match
m_BitwiseLogic(const LHS &L, const RHS &R) { return BinOpPred_match
(L, R); } /// Matches integer division operations. template
inline BinOpPred_match
m_IDiv(const LHS &L, const RHS &R) { return BinOpPred_match
(L, R); } //===----------------------------------------------------------------------===// // Class that matches exact binary ops. // template
struct Exact_match { SubPattern_t SubPattern; Exact_match(const SubPattern_t &SP) : SubPattern(SP) {} template
bool match(OpTy *V) { if (auto *PEO = dyn_cast
(V)) return PEO->isExact() && SubPattern.match(V); return false; } }; template
inline Exact_match
m_Exact(const T &SubPattern) { return SubPattern; } //===----------------------------------------------------------------------===// // Matchers for CmpInst classes // template
struct CmpClass_match { PredicateTy &Predicate; LHS_t L; RHS_t R; // The evaluation order is always stable, regardless of Commutability. // The LHS is always matched first. CmpClass_match(PredicateTy &Pred, const LHS_t &LHS, const RHS_t &RHS) : Predicate(Pred), L(LHS), R(RHS) {} template