Update prebuilt Clang to r416183b from Android.
https://android.googlesource.com/platform/prebuilts/clang/host/
linux-x86/+/06a71ddac05c22edb2d10b590e1769b3f8619bef
clang 12.0.5 (based on r416183b) from build 7284624.
Change-Id: I277a316abcf47307562d8b748b84870f31a72866
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/linux-x64/clang/include/llvm/IR/PatternMatch.h b/linux-x64/clang/include/llvm/IR/PatternMatch.h
index 1a11af2..166ad23 100644
--- a/linux-x64/clang/include/llvm/IR/PatternMatch.h
+++ b/linux-x64/clang/include/llvm/IR/PatternMatch.h
@@ -32,9 +32,11 @@
#include "llvm/ADT/APInt.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
+#include "llvm/IR/DataLayout.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Value.h"
@@ -48,6 +50,10 @@
return const_cast<Pattern &>(P).match(V);
}
+template <typename Pattern> bool match(ArrayRef<int> Mask, const Pattern &P) {
+ return const_cast<Pattern &>(P).match(Mask);
+}
+
template <typename SubPattern_t> struct OneUse_match {
SubPattern_t SubPattern;
@@ -69,6 +75,11 @@
/// Match an arbitrary value and ignore it.
inline class_match<Value> m_Value() { return class_match<Value>(); }
+/// Match an arbitrary unary operation and ignore it.
+inline class_match<UnaryOperator> m_UnOp() {
+ return class_match<UnaryOperator>();
+}
+
/// Match an arbitrary binary operation and ignore it.
inline class_match<BinaryOperator> m_BinOp() {
return class_match<BinaryOperator>();
@@ -77,16 +88,48 @@
/// Matches any compare instruction and ignore it.
inline class_match<CmpInst> m_Cmp() { return class_match<CmpInst>(); }
+/// Match an arbitrary undef constant.
+inline class_match<UndefValue> m_Undef() { return class_match<UndefValue>(); }
+
+/// Match an arbitrary poison constant.
+inline class_match<PoisonValue> m_Poison() { return class_match<PoisonValue>(); }
+
+/// Match an arbitrary Constant and ignore it.
+inline class_match<Constant> m_Constant() { return class_match<Constant>(); }
+
/// Match an arbitrary ConstantInt and ignore it.
inline class_match<ConstantInt> m_ConstantInt() {
return class_match<ConstantInt>();
}
-/// Match an arbitrary undef constant.
-inline class_match<UndefValue> m_Undef() { return class_match<UndefValue>(); }
+/// Match an arbitrary ConstantFP and ignore it.
+inline class_match<ConstantFP> m_ConstantFP() {
+ return class_match<ConstantFP>();
+}
-/// Match an arbitrary Constant and ignore it.
-inline class_match<Constant> m_Constant() { return class_match<Constant>(); }
+/// Match an arbitrary ConstantExpr and ignore it.
+inline class_match<ConstantExpr> m_ConstantExpr() {
+ return class_match<ConstantExpr>();
+}
+
+/// Match an arbitrary basic block value and ignore it.
+inline class_match<BasicBlock> m_BasicBlock() {
+ return class_match<BasicBlock>();
+}
+
+/// Inverting matcher
+template <typename Ty> struct match_unless {
+ Ty M;
+
+ match_unless(const Ty &Matcher) : M(Matcher) {}
+
+ template <typename ITy> bool match(ITy *V) { return !M.match(V); }
+};
+
+/// Match if the inner matcher does *NOT* match.
+template <typename Ty> inline match_unless<Ty> m_Unless(const Ty &M) {
+ return match_unless<Ty>(M);
+}
/// Matching combinators
template <typename LTy, typename RTy> struct match_combine_or {
@@ -132,8 +175,10 @@
struct apint_match {
const APInt *&Res;
+ bool AllowUndef;
- apint_match(const APInt *&R) : Res(R) {}
+ apint_match(const APInt *&Res, bool AllowUndef)
+ : Res(Res), AllowUndef(AllowUndef) {}
template <typename ITy> bool match(ITy *V) {
if (auto *CI = dyn_cast<ConstantInt>(V)) {
@@ -142,7 +187,8 @@
}
if (V->getType()->isVectorTy())
if (const auto *C = dyn_cast<Constant>(V))
- if (auto *CI = dyn_cast_or_null<ConstantInt>(C->getSplatValue())) {
+ if (auto *CI = dyn_cast_or_null<ConstantInt>(
+ C->getSplatValue(AllowUndef))) {
Res = &CI->getValue();
return true;
}
@@ -154,7 +200,11 @@
// function for both apint/apfloat.
struct apfloat_match {
const APFloat *&Res;
- apfloat_match(const APFloat *&R) : Res(R) {}
+ bool AllowUndef;
+
+ apfloat_match(const APFloat *&Res, bool AllowUndef)
+ : Res(Res), AllowUndef(AllowUndef) {}
+
template <typename ITy> bool match(ITy *V) {
if (auto *CI = dyn_cast<ConstantFP>(V)) {
Res = &CI->getValueAPF();
@@ -162,7 +212,8 @@
}
if (V->getType()->isVectorTy())
if (const auto *C = dyn_cast<Constant>(V))
- if (auto *CI = dyn_cast_or_null<ConstantFP>(C->getSplatValue())) {
+ if (auto *CI = dyn_cast_or_null<ConstantFP>(
+ C->getSplatValue(AllowUndef))) {
Res = &CI->getValueAPF();
return true;
}
@@ -172,11 +223,37 @@
/// Match a ConstantInt or splatted ConstantVector, binding the
/// specified pointer to the contained APInt.
-inline apint_match m_APInt(const APInt *&Res) { return Res; }
+inline apint_match m_APInt(const APInt *&Res) {
+ // Forbid undefs by default to maintain previous behavior.
+ return apint_match(Res, /* AllowUndef */ false);
+}
+
+/// Match APInt while allowing undefs in splat vector constants.
+inline apint_match m_APIntAllowUndef(const APInt *&Res) {
+ return apint_match(Res, /* AllowUndef */ true);
+}
+
+/// Match APInt while forbidding undefs in splat vector constants.
+inline apint_match m_APIntForbidUndef(const APInt *&Res) {
+ return apint_match(Res, /* AllowUndef */ false);
+}
/// Match a ConstantFP or splatted ConstantVector, binding the
/// specified pointer to the contained APFloat.
-inline apfloat_match m_APFloat(const APFloat *&Res) { return Res; }
+inline apfloat_match m_APFloat(const APFloat *&Res) {
+ // Forbid undefs by default to maintain previous behavior.
+ return apfloat_match(Res, /* AllowUndef */ false);
+}
+
+/// Match APFloat while allowing undefs in splat vector constants.
+inline apfloat_match m_APFloatAllowUndef(const APFloat *&Res) {
+ return apfloat_match(Res, /* AllowUndef */ true);
+}
+
+/// Match APFloat while forbidding undefs in splat vector constants.
+inline apfloat_match m_APFloatForbidUndef(const APFloat *&Res) {
+ return apfloat_match(Res, /* AllowUndef */ false);
+}
template <int64_t Val> struct constantint_match {
template <typename ITy> bool match(ITy *V) {
@@ -198,20 +275,26 @@
return constantint_match<Val>();
}
-/// 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 <typename Predicate> struct cst_pred_ty : public Predicate {
+/// This helper class is used to match constant scalars, vector splats,
+/// and fixed width vectors that satisfy a specified predicate.
+/// For fixed width vector constants, undefined elements are ignored.
+template <typename Predicate, typename ConstantVal>
+struct cstval_pred_ty : public Predicate {
template <typename ITy> bool match(ITy *V) {
- if (const auto *CI = dyn_cast<ConstantInt>(V))
- return this->isValue(CI->getValue());
- if (V->getType()->isVectorTy()) {
+ if (const auto *CV = dyn_cast<ConstantVal>(V))
+ return this->isValue(CV->getValue());
+ if (const auto *VTy = dyn_cast<VectorType>(V->getType())) {
if (const auto *C = dyn_cast<Constant>(V)) {
- if (const auto *CI = dyn_cast_or_null<ConstantInt>(C->getSplatValue()))
- return this->isValue(CI->getValue());
+ if (const auto *CV = dyn_cast_or_null<ConstantVal>(C->getSplatValue()))
+ return this->isValue(CV->getValue());
+
+ // Number of elements of a scalable vector unknown at compile time
+ auto *FVTy = dyn_cast<FixedVectorType>(VTy);
+ if (!FVTy)
+ return false;
// Non-splat vector constant: check each element for a match.
- unsigned NumElts = V->getType()->getVectorNumElements();
+ unsigned NumElts = FVTy->getNumElements();
assert(NumElts != 0 && "Constant vector with no elements?");
bool HasNonUndefElements = false;
for (unsigned i = 0; i != NumElts; ++i) {
@@ -220,8 +303,8 @@
return false;
if (isa<UndefValue>(Elt))
continue;
- auto *CI = dyn_cast<ConstantInt>(Elt);
- if (!CI || !this->isValue(CI->getValue()))
+ auto *CV = dyn_cast<ConstantVal>(Elt);
+ if (!CV || !this->isValue(CV->getValue()))
return false;
HasNonUndefElements = true;
}
@@ -232,6 +315,14 @@
}
};
+/// specialization of cstval_pred_ty for ConstantInt
+template <typename Predicate>
+using cst_pred_ty = cstval_pred_ty<Predicate, ConstantInt>;
+
+/// specialization of cstval_pred_ty for ConstantFP
+template <typename Predicate>
+using cstfp_pred_ty = cstval_pred_ty<Predicate, ConstantFP>;
+
/// This helper class is used to match scalar and vector constants that
/// satisfy a specified predicate, and bind them to an APInt.
template <typename Predicate> struct api_pred_ty : public Predicate {
@@ -257,36 +348,29 @@
}
};
-/// 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 <typename Predicate> struct cstfp_pred_ty : public Predicate {
- template <typename ITy> bool match(ITy *V) {
- if (const auto *CF = dyn_cast<ConstantFP>(V))
- return this->isValue(CF->getValueAPF());
- if (V->getType()->isVectorTy()) {
- if (const auto *C = dyn_cast<Constant>(V)) {
- if (const auto *CF = dyn_cast_or_null<ConstantFP>(C->getSplatValue()))
- return this->isValue(CF->getValueAPF());
+/// This helper class is used to match scalar and vector constants that
+/// satisfy a specified predicate, and bind them to an APFloat.
+/// Undefs are allowed in splat vector constants.
+template <typename Predicate> struct apf_pred_ty : public Predicate {
+ const APFloat *&Res;
- // Non-splat vector constant: check each element for a match.
- unsigned NumElts = V->getType()->getVectorNumElements();
- assert(NumElts != 0 && "Constant vector with no elements?");
- bool HasNonUndefElements = false;
- for (unsigned i = 0; i != NumElts; ++i) {
- Constant *Elt = C->getAggregateElement(i);
- if (!Elt)
- return false;
- if (isa<UndefValue>(Elt))
- continue;
- auto *CF = dyn_cast<ConstantFP>(Elt);
- if (!CF || !this->isValue(CF->getValueAPF()))
- return false;
- HasNonUndefElements = true;
- }
- return HasNonUndefElements;
+ apf_pred_ty(const APFloat *&R) : Res(R) {}
+
+ template <typename ITy> bool match(ITy *V) {
+ if (const auto *CI = dyn_cast<ConstantFP>(V))
+ if (this->isValue(CI->getValue())) {
+ Res = &CI->getValue();
+ return true;
}
- }
+ if (V->getType()->isVectorTy())
+ if (const auto *C = dyn_cast<Constant>(V))
+ if (auto *CI = dyn_cast_or_null<ConstantFP>(
+ C->getSplatValue(/* AllowUndef */ true)))
+ if (this->isValue(CI->getValue())) {
+ Res = &CI->getValue();
+ return true;
+ }
+
return false;
}
};
@@ -300,6 +384,15 @@
//
///////////////////////////////////////////////////////////////////////////////
+struct is_any_apint {
+ bool isValue(const APInt &C) { return true; }
+};
+/// Match an integer or vector with any integral constant.
+/// For vectors, this includes constants with undefined elements.
+inline cst_pred_ty<is_any_apint> m_AnyIntegralConstant() {
+ return cst_pred_ty<is_any_apint>();
+}
+
struct is_all_ones {
bool isValue(const APInt &C) { return C.isAllOnesValue(); }
};
@@ -337,7 +430,7 @@
struct is_nonnegative {
bool isValue(const APInt &C) { return C.isNonNegative(); }
};
-/// Match an integer or vector of nonnegative values.
+/// Match an integer or vector of non-negative values.
/// For vectors, this includes constants with undefined elements.
inline cst_pred_ty<is_nonnegative> m_NonNegative() {
return cst_pred_ty<is_nonnegative>();
@@ -346,6 +439,28 @@
return V;
}
+struct is_strictlypositive {
+ bool isValue(const APInt &C) { return C.isStrictlyPositive(); }
+};
+/// Match an integer or vector of strictly positive values.
+/// For vectors, this includes constants with undefined elements.
+inline cst_pred_ty<is_strictlypositive> m_StrictlyPositive() {
+ return cst_pred_ty<is_strictlypositive>();
+}
+inline api_pred_ty<is_strictlypositive> m_StrictlyPositive(const APInt *&V) {
+ return V;
+}
+
+struct is_nonpositive {
+ bool isValue(const APInt &C) { return C.isNonPositive(); }
+};
+/// Match an integer or vector of non-positive values.
+/// For vectors, this includes constants with undefined elements.
+inline cst_pred_ty<is_nonpositive> m_NonPositive() {
+ return cst_pred_ty<is_nonpositive>();
+}
+inline api_pred_ty<is_nonpositive> m_NonPositive(const APInt *&V) { return V; }
+
struct is_one {
bool isValue(const APInt &C) { return C.isOneValue(); }
};
@@ -367,6 +482,7 @@
struct is_zero {
template <typename ITy> bool match(ITy *V) {
auto *C = dyn_cast<Constant>(V);
+ // FIXME: this should be able to do something for scalable vectors
return C && (C->isNullValue() || cst_pred_ty<is_zero_int>().match(C));
}
};
@@ -388,6 +504,18 @@
return V;
}
+struct is_negated_power2 {
+ bool isValue(const APInt &C) { return (-C).isPowerOf2(); }
+};
+/// Match a integer or vector negated power-of-2.
+/// For vectors, this includes constants with undefined elements.
+inline cst_pred_ty<is_negated_power2> m_NegatedPower2() {
+ return cst_pred_ty<is_negated_power2>();
+}
+inline api_pred_ty<is_negated_power2> m_NegatedPower2(const APInt *&V) {
+ return V;
+}
+
struct is_power2_or_zero {
bool isValue(const APInt &C) { return !C || C.isPowerOf2(); }
};
@@ -418,16 +546,42 @@
return cst_pred_ty<is_lowbit_mask>();
}
-struct is_unsigned_less_than {
+struct icmp_pred_with_threshold {
+ ICmpInst::Predicate Pred;
const APInt *Thr;
- bool isValue(const APInt &C) { return C.ult(*Thr); }
+ bool isValue(const APInt &C) {
+ switch (Pred) {
+ case ICmpInst::Predicate::ICMP_EQ:
+ return C.eq(*Thr);
+ case ICmpInst::Predicate::ICMP_NE:
+ return C.ne(*Thr);
+ case ICmpInst::Predicate::ICMP_UGT:
+ return C.ugt(*Thr);
+ case ICmpInst::Predicate::ICMP_UGE:
+ return C.uge(*Thr);
+ case ICmpInst::Predicate::ICMP_ULT:
+ return C.ult(*Thr);
+ case ICmpInst::Predicate::ICMP_ULE:
+ return C.ule(*Thr);
+ case ICmpInst::Predicate::ICMP_SGT:
+ return C.sgt(*Thr);
+ case ICmpInst::Predicate::ICMP_SGE:
+ return C.sge(*Thr);
+ case ICmpInst::Predicate::ICMP_SLT:
+ return C.slt(*Thr);
+ case ICmpInst::Predicate::ICMP_SLE:
+ return C.sle(*Thr);
+ default:
+ llvm_unreachable("Unhandled ICmp predicate");
+ }
+ }
};
-/// Match an integer or vector with every element unsigned less than the
-/// Threshold. For vectors, this includes constants with undefined elements.
-/// FIXME: is it worth generalizing this to simply take ICmpInst::Predicate?
-inline cst_pred_ty<is_unsigned_less_than>
-m_SpecificInt_ULT(const APInt &Threshold) {
- cst_pred_ty<is_unsigned_less_than> P;
+/// Match an integer or vector with every element comparing 'pred' (eg/ne/...)
+/// to Threshold. For vectors, this includes constants with undefined elements.
+inline cst_pred_ty<icmp_pred_with_threshold>
+m_SpecificInt_ICMP(ICmpInst::Predicate Predicate, const APInt &Threshold) {
+ cst_pred_ty<icmp_pred_with_threshold> P;
+ P.Pred = Predicate;
P.Thr = &Threshold;
return P;
}
@@ -441,6 +595,55 @@
return cstfp_pred_ty<is_nan>();
}
+struct is_nonnan {
+ bool isValue(const APFloat &C) { return !C.isNaN(); }
+};
+/// Match a non-NaN FP constant.
+/// For vectors, this includes constants with undefined elements.
+inline cstfp_pred_ty<is_nonnan> m_NonNaN() {
+ return cstfp_pred_ty<is_nonnan>();
+}
+
+struct is_inf {
+ bool isValue(const APFloat &C) { return C.isInfinity(); }
+};
+/// Match a positive or negative infinity FP constant.
+/// For vectors, this includes constants with undefined elements.
+inline cstfp_pred_ty<is_inf> m_Inf() {
+ return cstfp_pred_ty<is_inf>();
+}
+
+struct is_noninf {
+ bool isValue(const APFloat &C) { return !C.isInfinity(); }
+};
+/// Match a non-infinity FP constant, i.e. finite or NaN.
+/// For vectors, this includes constants with undefined elements.
+inline cstfp_pred_ty<is_noninf> m_NonInf() {
+ return cstfp_pred_ty<is_noninf>();
+}
+
+struct is_finite {
+ bool isValue(const APFloat &C) { return C.isFinite(); }
+};
+/// Match a finite FP constant, i.e. not infinity or NaN.
+/// For vectors, this includes constants with undefined elements.
+inline cstfp_pred_ty<is_finite> m_Finite() {
+ return cstfp_pred_ty<is_finite>();
+}
+inline apf_pred_ty<is_finite> m_Finite(const APFloat *&V) { return V; }
+
+struct is_finitenonzero {
+ bool isValue(const APFloat &C) { return C.isFiniteNonZero(); }
+};
+/// Match a finite non-zero FP constant.
+/// For vectors, this includes constants with undefined elements.
+inline cstfp_pred_ty<is_finitenonzero> m_FiniteNonZero() {
+ return cstfp_pred_ty<is_finitenonzero>();
+}
+inline apf_pred_ty<is_finitenonzero> m_FiniteNonZero(const APFloat *&V) {
+ return V;
+}
+
struct is_any_zero_fp {
bool isValue(const APFloat &C) { return C.isZero(); }
};
@@ -468,6 +671,15 @@
return cstfp_pred_ty<is_neg_zero_fp>();
}
+struct is_non_zero_fp {
+ bool isValue(const APFloat &C) { return C.isNonZero(); }
+};
+/// Match a floating-point non-zero.
+/// For vectors, this includes constants with undefined elements.
+inline cstfp_pred_ty<is_non_zero_fp> m_NonZeroFP() {
+ return cstfp_pred_ty<is_non_zero_fp>();
+}
+
///////////////////////////////////////////////////////////////////////////////
template <typename Class> struct bind_ty {
@@ -490,18 +702,45 @@
/// Match an instruction, capturing it if we match.
inline bind_ty<Instruction> m_Instruction(Instruction *&I) { return I; }
+/// Match a unary operator, capturing it if we match.
+inline bind_ty<UnaryOperator> m_UnOp(UnaryOperator *&I) { return I; }
/// Match a binary operator, capturing it if we match.
inline bind_ty<BinaryOperator> m_BinOp(BinaryOperator *&I) { return I; }
-
-/// Match a ConstantInt, capturing the value if we match.
-inline bind_ty<ConstantInt> m_ConstantInt(ConstantInt *&CI) { return CI; }
+/// Match a with overflow intrinsic, capturing it if we match.
+inline bind_ty<WithOverflowInst> m_WithOverflowInst(WithOverflowInst *&I) { return I; }
/// Match a Constant, capturing the value if we match.
inline bind_ty<Constant> m_Constant(Constant *&C) { return C; }
+/// Match a ConstantInt, capturing the value if we match.
+inline bind_ty<ConstantInt> m_ConstantInt(ConstantInt *&CI) { return CI; }
+
/// Match a ConstantFP, capturing the value if we match.
inline bind_ty<ConstantFP> m_ConstantFP(ConstantFP *&C) { return C; }
+/// Match a ConstantExpr, capturing the value if we match.
+inline bind_ty<ConstantExpr> m_ConstantExpr(ConstantExpr *&C) { return C; }
+
+/// Match a basic block value, capturing it if we match.
+inline bind_ty<BasicBlock> m_BasicBlock(BasicBlock *&V) { return V; }
+inline bind_ty<const BasicBlock> m_BasicBlock(const BasicBlock *&V) {
+ return V;
+}
+
+/// Match an arbitrary immediate Constant and ignore it.
+inline match_combine_and<class_match<Constant>,
+ match_unless<class_match<ConstantExpr>>>
+m_ImmConstant() {
+ return m_CombineAnd(m_Constant(), m_Unless(m_ConstantExpr()));
+}
+
+/// Match an immediate Constant, capturing the value if we match.
+inline match_combine_and<bind_ty<Constant>,
+ match_unless<class_match<ConstantExpr>>>
+m_ImmConstant(Constant *&C) {
+ return m_CombineAnd(m_Constant(C), m_Unless(m_ConstantExpr()));
+}
+
/// Match a specified Value*.
struct specificval_ty {
const Value *Val;
@@ -571,30 +810,71 @@
};
/// Match a specified integer value or vector of all elements of that
-// value.
+/// value.
+template <bool AllowUndefs>
struct specific_intval {
- uint64_t Val;
+ APInt Val;
- specific_intval(uint64_t V) : Val(V) {}
+ specific_intval(APInt V) : Val(std::move(V)) {}
template <typename ITy> bool match(ITy *V) {
const auto *CI = dyn_cast<ConstantInt>(V);
if (!CI && V->getType()->isVectorTy())
if (const auto *C = dyn_cast<Constant>(V))
- CI = dyn_cast_or_null<ConstantInt>(C->getSplatValue());
+ CI = dyn_cast_or_null<ConstantInt>(C->getSplatValue(AllowUndefs));
- return CI && CI->getValue() == Val;
+ return CI && APInt::isSameValue(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); }
+inline specific_intval<false> m_SpecificInt(APInt V) {
+ return specific_intval<false>(std::move(V));
+}
+
+inline specific_intval<false> m_SpecificInt(uint64_t V) {
+ return m_SpecificInt(APInt(64, V));
+}
+
+inline specific_intval<true> m_SpecificIntAllowUndef(APInt V) {
+ return specific_intval<true>(std::move(V));
+}
+
+inline specific_intval<true> m_SpecificIntAllowUndef(uint64_t V) {
+ return m_SpecificIntAllowUndef(APInt(64, 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; }
+/// Match a specified basic block value.
+struct specific_bbval {
+ BasicBlock *Val;
+
+ specific_bbval(BasicBlock *Val) : Val(Val) {}
+
+ template <typename ITy> bool match(ITy *V) {
+ const auto *BB = dyn_cast<BasicBlock>(V);
+ return BB && BB == Val;
+ }
+};
+
+/// Match a specific basic block value.
+inline specific_bbval m_SpecificBB(BasicBlock *BB) {
+ return specific_bbval(BB);
+}
+
+/// A commutative-friendly version of m_Specific().
+inline deferredval_ty<BasicBlock> m_Deferred(BasicBlock *const &BB) {
+ return BB;
+}
+inline deferredval_ty<const BasicBlock>
+m_Deferred(const BasicBlock *const &BB) {
+ return BB;
+}
+
//===----------------------------------------------------------------------===//
// Matcher for any binary operator.
//
@@ -622,6 +902,26 @@
}
//===----------------------------------------------------------------------===//
+// Matcher for any unary operator.
+// TODO fuse unary, binary matcher into n-ary matcher
+//
+template <typename OP_t> struct AnyUnaryOp_match {
+ OP_t X;
+
+ AnyUnaryOp_match(const OP_t &X) : X(X) {}
+
+ template <typename OpTy> bool match(OpTy *V) {
+ if (auto *I = dyn_cast<UnaryOperator>(V))
+ return X.match(I->getOperand(0));
+ return false;
+ }
+};
+
+template <typename OP_t> inline AnyUnaryOp_match<OP_t> m_UnOp(const OP_t &X) {
+ return AnyUnaryOp_match<OP_t>(X);
+}
+
+//===----------------------------------------------------------------------===//
// Matchers for specific binary operators.
//
@@ -942,6 +1242,12 @@
}
};
+struct is_irem_op {
+ bool isOpType(unsigned Opcode) {
+ return Opcode == Instruction::SRem || Opcode == Instruction::URem;
+ }
+};
+
/// Matches shift operations.
template <typename LHS, typename RHS>
inline BinOpPred_match<LHS, RHS, is_shift_op> m_Shift(const LHS &L,
@@ -977,6 +1283,13 @@
return BinOpPred_match<LHS, RHS, is_idiv_op>(L, R);
}
+/// Matches integer remainder operations.
+template <typename LHS, typename RHS>
+inline BinOpPred_match<LHS, RHS, is_irem_op> m_IRem(const LHS &L,
+ const RHS &R) {
+ return BinOpPred_match<LHS, RHS, is_irem_op>(L, R);
+}
+
//===----------------------------------------------------------------------===//
// Class that matches exact binary ops.
//
@@ -1013,13 +1326,16 @@
: Predicate(Pred), L(LHS), R(RHS) {}
template <typename OpTy> bool match(OpTy *V) {
- if (auto *I = dyn_cast<Class>(V))
- if ((L.match(I->getOperand(0)) && R.match(I->getOperand(1))) ||
- (Commutable && L.match(I->getOperand(1)) &&
- R.match(I->getOperand(0)))) {
+ if (auto *I = dyn_cast<Class>(V)) {
+ if (L.match(I->getOperand(0)) && R.match(I->getOperand(1))) {
Predicate = I->getPredicate();
return true;
+ } else if (Commutable && L.match(I->getOperand(1)) &&
+ R.match(I->getOperand(0))) {
+ Predicate = I->getSwappedPredicate();
+ return true;
}
+ }
return false;
}
};
@@ -1113,10 +1429,16 @@
return m_Select(C, m_ConstantInt<L>(), m_ConstantInt<R>());
}
+/// Matches FreezeInst.
+template <typename OpTy>
+inline OneOps_match<OpTy, Instruction::Freeze> m_Freeze(const OpTy &Op) {
+ return OneOps_match<OpTy, Instruction::Freeze>(Op);
+}
+
/// Matches InsertElementInst.
template <typename Val_t, typename Elt_t, typename Idx_t>
inline ThreeOps_match<Val_t, Elt_t, Idx_t, Instruction::InsertElement>
-m_InsertElement(const Val_t &Val, const Elt_t &Elt, const Idx_t &Idx) {
+m_InsertElt(const Val_t &Val, const Elt_t &Elt, const Idx_t &Idx) {
return ThreeOps_match<Val_t, Elt_t, Idx_t, Instruction::InsertElement>(
Val, Elt, Idx);
}
@@ -1124,16 +1446,73 @@
/// Matches ExtractElementInst.
template <typename Val_t, typename Idx_t>
inline TwoOps_match<Val_t, Idx_t, Instruction::ExtractElement>
-m_ExtractElement(const Val_t &Val, const Idx_t &Idx) {
+m_ExtractElt(const Val_t &Val, const Idx_t &Idx) {
return TwoOps_match<Val_t, Idx_t, Instruction::ExtractElement>(Val, Idx);
}
-/// Matches ShuffleVectorInst.
+/// Matches shuffle.
+template <typename T0, typename T1, typename T2> struct Shuffle_match {
+ T0 Op1;
+ T1 Op2;
+ T2 Mask;
+
+ Shuffle_match(const T0 &Op1, const T1 &Op2, const T2 &Mask)
+ : Op1(Op1), Op2(Op2), Mask(Mask) {}
+
+ template <typename OpTy> bool match(OpTy *V) {
+ if (auto *I = dyn_cast<ShuffleVectorInst>(V)) {
+ return Op1.match(I->getOperand(0)) && Op2.match(I->getOperand(1)) &&
+ Mask.match(I->getShuffleMask());
+ }
+ return false;
+ }
+};
+
+struct m_Mask {
+ ArrayRef<int> &MaskRef;
+ m_Mask(ArrayRef<int> &MaskRef) : MaskRef(MaskRef) {}
+ bool match(ArrayRef<int> Mask) {
+ MaskRef = Mask;
+ return true;
+ }
+};
+
+struct m_ZeroMask {
+ bool match(ArrayRef<int> Mask) {
+ return all_of(Mask, [](int Elem) { return Elem == 0 || Elem == -1; });
+ }
+};
+
+struct m_SpecificMask {
+ ArrayRef<int> &MaskRef;
+ m_SpecificMask(ArrayRef<int> &MaskRef) : MaskRef(MaskRef) {}
+ bool match(ArrayRef<int> Mask) { return MaskRef == Mask; }
+};
+
+struct m_SplatOrUndefMask {
+ int &SplatIndex;
+ m_SplatOrUndefMask(int &SplatIndex) : SplatIndex(SplatIndex) {}
+ bool match(ArrayRef<int> Mask) {
+ auto First = find_if(Mask, [](int Elem) { return Elem != -1; });
+ if (First == Mask.end())
+ return false;
+ SplatIndex = *First;
+ return all_of(Mask,
+ [First](int Elem) { return Elem == *First || Elem == -1; });
+ }
+};
+
+/// Matches ShuffleVectorInst independently of mask value.
+template <typename V1_t, typename V2_t>
+inline TwoOps_match<V1_t, V2_t, Instruction::ShuffleVector>
+m_Shuffle(const V1_t &v1, const V2_t &v2) {
+ return TwoOps_match<V1_t, V2_t, Instruction::ShuffleVector>(v1, v2);
+}
+
template <typename V1_t, typename V2_t, typename Mask_t>
-inline ThreeOps_match<V1_t, V2_t, Mask_t, Instruction::ShuffleVector>
-m_ShuffleVector(const V1_t &v1, const V2_t &v2, const Mask_t &m) {
- return ThreeOps_match<V1_t, V2_t, Mask_t, Instruction::ShuffleVector>(v1, v2,
- m);
+inline Shuffle_match<V1_t, V2_t, Mask_t>
+m_Shuffle(const V1_t &v1, const V2_t &v2, const Mask_t &mask) {
+ return Shuffle_match<V1_t, V2_t, Mask_t>(v1, v2, mask);
}
/// Matches LoadInst.
@@ -1178,12 +1557,24 @@
return CastClass_match<OpTy, Instruction::PtrToInt>(Op);
}
+/// Matches IntToPtr.
+template <typename OpTy>
+inline CastClass_match<OpTy, Instruction::IntToPtr> m_IntToPtr(const OpTy &Op) {
+ return CastClass_match<OpTy, Instruction::IntToPtr>(Op);
+}
+
/// Matches Trunc.
template <typename OpTy>
inline CastClass_match<OpTy, Instruction::Trunc> m_Trunc(const OpTy &Op) {
return CastClass_match<OpTy, Instruction::Trunc>(Op);
}
+template <typename OpTy>
+inline match_combine_or<CastClass_match<OpTy, Instruction::Trunc>, OpTy>
+m_TruncOrSelf(const OpTy &Op) {
+ return m_CombineOr(m_Trunc(Op), Op);
+}
+
/// Matches SExt.
template <typename OpTy>
inline CastClass_match<OpTy, Instruction::SExt> m_SExt(const OpTy &Op) {
@@ -1197,31 +1588,58 @@
}
template <typename OpTy>
+inline match_combine_or<CastClass_match<OpTy, Instruction::ZExt>, OpTy>
+m_ZExtOrSelf(const OpTy &Op) {
+ return m_CombineOr(m_ZExt(Op), Op);
+}
+
+template <typename OpTy>
+inline match_combine_or<CastClass_match<OpTy, Instruction::SExt>, OpTy>
+m_SExtOrSelf(const OpTy &Op) {
+ return m_CombineOr(m_SExt(Op), Op);
+}
+
+template <typename OpTy>
inline match_combine_or<CastClass_match<OpTy, Instruction::ZExt>,
CastClass_match<OpTy, Instruction::SExt>>
m_ZExtOrSExt(const OpTy &Op) {
return m_CombineOr(m_ZExt(Op), m_SExt(Op));
}
-/// Matches UIToFP.
+template <typename OpTy>
+inline match_combine_or<
+ match_combine_or<CastClass_match<OpTy, Instruction::ZExt>,
+ CastClass_match<OpTy, Instruction::SExt>>,
+ OpTy>
+m_ZExtOrSExtOrSelf(const OpTy &Op) {
+ return m_CombineOr(m_ZExtOrSExt(Op), Op);
+}
+
template <typename OpTy>
inline CastClass_match<OpTy, Instruction::UIToFP> m_UIToFP(const OpTy &Op) {
return CastClass_match<OpTy, Instruction::UIToFP>(Op);
}
-/// Matches SIToFP.
template <typename OpTy>
inline CastClass_match<OpTy, Instruction::SIToFP> m_SIToFP(const OpTy &Op) {
return CastClass_match<OpTy, Instruction::SIToFP>(Op);
}
-/// Matches FPTrunc
+template <typename OpTy>
+inline CastClass_match<OpTy, Instruction::FPToUI> m_FPToUI(const OpTy &Op) {
+ return CastClass_match<OpTy, Instruction::FPToUI>(Op);
+}
+
+template <typename OpTy>
+inline CastClass_match<OpTy, Instruction::FPToSI> m_FPToSI(const OpTy &Op) {
+ return CastClass_match<OpTy, Instruction::FPToSI>(Op);
+}
+
template <typename OpTy>
inline CastClass_match<OpTy, Instruction::FPTrunc> m_FPTrunc(const OpTy &Op) {
return CastClass_match<OpTy, Instruction::FPTrunc>(Op);
}
-/// Matches FPExt
template <typename OpTy>
inline CastClass_match<OpTy, Instruction::FPExt> m_FPExt(const OpTy &Op) {
return CastClass_match<OpTy, Instruction::FPExt>(Op);
@@ -1248,27 +1666,34 @@
inline br_match m_UnconditionalBr(BasicBlock *&Succ) { return br_match(Succ); }
-template <typename Cond_t> struct brc_match {
+template <typename Cond_t, typename TrueBlock_t, typename FalseBlock_t>
+struct brc_match {
Cond_t Cond;
- BasicBlock *&T, *&F;
+ TrueBlock_t T;
+ FalseBlock_t F;
- brc_match(const Cond_t &C, BasicBlock *&t, BasicBlock *&f)
+ brc_match(const Cond_t &C, const TrueBlock_t &t, const FalseBlock_t &f)
: Cond(C), T(t), F(f) {}
template <typename OpTy> bool match(OpTy *V) {
if (auto *BI = dyn_cast<BranchInst>(V))
- if (BI->isConditional() && Cond.match(BI->getCondition())) {
- T = BI->getSuccessor(0);
- F = BI->getSuccessor(1);
- return true;
- }
+ if (BI->isConditional() && Cond.match(BI->getCondition()))
+ return T.match(BI->getSuccessor(0)) && F.match(BI->getSuccessor(1));
return false;
}
};
template <typename Cond_t>
-inline brc_match<Cond_t> m_Br(const Cond_t &C, BasicBlock *&T, BasicBlock *&F) {
- return brc_match<Cond_t>(C, T, F);
+inline brc_match<Cond_t, bind_ty<BasicBlock>, bind_ty<BasicBlock>>
+m_Br(const Cond_t &C, BasicBlock *&T, BasicBlock *&F) {
+ return brc_match<Cond_t, bind_ty<BasicBlock>, bind_ty<BasicBlock>>(
+ C, m_BasicBlock(T), m_BasicBlock(F));
+}
+
+template <typename Cond_t, typename TrueBlock_t, typename FalseBlock_t>
+inline brc_match<Cond_t, TrueBlock_t, FalseBlock_t>
+m_Br(const Cond_t &C, const TrueBlock_t &T, const FalseBlock_t &F) {
+ return brc_match<Cond_t, TrueBlock_t, FalseBlock_t>(C, T, F);
}
//===----------------------------------------------------------------------===//
@@ -1286,6 +1711,17 @@
MaxMin_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {}
template <typename OpTy> bool match(OpTy *V) {
+ if (auto *II = dyn_cast<IntrinsicInst>(V)) {
+ Intrinsic::ID IID = II->getIntrinsicID();
+ if ((IID == Intrinsic::smax && Pred_t::match(ICmpInst::ICMP_SGT)) ||
+ (IID == Intrinsic::smin && Pred_t::match(ICmpInst::ICMP_SLT)) ||
+ (IID == Intrinsic::umax && Pred_t::match(ICmpInst::ICMP_UGT)) ||
+ (IID == Intrinsic::umin && Pred_t::match(ICmpInst::ICMP_ULT))) {
+ Value *LHS = II->getOperand(0), *RHS = II->getOperand(1);
+ return (L.match(LHS) && R.match(RHS)) ||
+ (Commutable && L.match(RHS) && R.match(LHS));
+ }
+ }
// Look for "(x pred y) ? x : y" or "(x pred y) ? y : x".
auto *SI = dyn_cast<SelectInst>(V);
if (!SI)
@@ -1393,6 +1829,17 @@
return MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty>(L, R);
}
+template <typename LHS, typename RHS>
+inline match_combine_or<
+ match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty>,
+ MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty>>,
+ match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty>,
+ MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty>>>
+m_MaxOrMin(const LHS &L, const RHS &R) {
+ return m_CombineOr(m_CombineOr(m_SMax(L, R), m_SMin(L, R)),
+ m_CombineOr(m_UMax(L, R), m_UMin(L, R)));
+}
+
/// Match an 'ordered' floating point maximum function.
/// Floating point has one special value 'NaN'. Therefore, there is no total
/// order. However, if we can ignore the 'NaN' value (for example, because of a
@@ -1454,7 +1901,8 @@
}
//===----------------------------------------------------------------------===//
-// Matchers for overflow check patterns: e.g. (a + b) u< a
+// Matchers for overflow check patterns: e.g. (a + b) u< a, (a ^ -1) <u b
+// Note that S might be matched to other instructions than AddInst.
//
template <typename LHS_t, typename RHS_t, typename Sum_t>
@@ -1485,6 +1933,19 @@
if (AddExpr.match(ICmpRHS) && (ICmpLHS == AddLHS || ICmpLHS == AddRHS))
return L.match(AddLHS) && R.match(AddRHS) && S.match(ICmpRHS);
+ Value *Op1;
+ auto XorExpr = m_OneUse(m_Xor(m_Value(Op1), m_AllOnes()));
+ // (a ^ -1) <u b
+ if (Pred == ICmpInst::ICMP_ULT) {
+ if (XorExpr.match(ICmpLHS))
+ return L.match(Op1) && R.match(ICmpRHS) && S.match(ICmpLHS);
+ }
+ // b > u (a ^ -1)
+ if (Pred == ICmpInst::ICMP_UGT) {
+ if (XorExpr.match(ICmpRHS))
+ return L.match(Op1) && R.match(ICmpLHS) && S.match(ICmpRHS);
+ }
+
// Match special-case for increment-by-1.
if (Pred == ICmpInst::ICMP_EQ) {
// (a + 1) == 0
@@ -1576,6 +2037,18 @@
Argument_match<T3>>;
};
+template <typename T0, typename T1, typename T2, typename T3, typename T4>
+struct m_Intrinsic_Ty<T0, T1, T2, T3, T4> {
+ using Ty = match_combine_and<typename m_Intrinsic_Ty<T0, T1, T2, T3>::Ty,
+ Argument_match<T4>>;
+};
+
+template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
+struct m_Intrinsic_Ty<T0, T1, T2, T3, T4, T5> {
+ using Ty = match_combine_and<typename m_Intrinsic_Ty<T0, T1, T2, T3, T4>::Ty,
+ Argument_match<T5>>;
+};
+
/// Match intrinsic calls like this:
/// m_Intrinsic<Intrinsic::fabs>(m_Value(X))
template <Intrinsic::ID IntrID> inline IntrinsicID_match m_Intrinsic() {
@@ -1606,6 +2079,24 @@
return m_CombineAnd(m_Intrinsic<IntrID>(Op0, Op1, Op2), m_Argument<3>(Op3));
}
+template <Intrinsic::ID IntrID, typename T0, typename T1, typename T2,
+ typename T3, typename T4>
+inline typename m_Intrinsic_Ty<T0, T1, T2, T3, T4>::Ty
+m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2, const T3 &Op3,
+ const T4 &Op4) {
+ return m_CombineAnd(m_Intrinsic<IntrID>(Op0, Op1, Op2, Op3),
+ m_Argument<4>(Op4));
+}
+
+template <Intrinsic::ID IntrID, typename T0, typename T1, typename T2,
+ typename T3, typename T4, typename T5>
+inline typename m_Intrinsic_Ty<T0, T1, T2, T3, T4, T5>::Ty
+m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2, const T3 &Op3,
+ const T4 &Op4, const T5 &Op5) {
+ return m_CombineAnd(m_Intrinsic<IntrID>(Op0, Op1, Op2, Op3, Op4),
+ m_Argument<5>(Op5));
+}
+
// Helper intrinsic matching specializations.
template <typename Opnd0>
inline typename m_Intrinsic_Ty<Opnd0>::Ty m_BitReverse(const Opnd0 &Op0) {
@@ -1639,6 +2130,18 @@
return m_Intrinsic<Intrinsic::maxnum>(Op0, Op1);
}
+template <typename Opnd0, typename Opnd1, typename Opnd2>
+inline typename m_Intrinsic_Ty<Opnd0, Opnd1, Opnd2>::Ty
+m_FShl(const Opnd0 &Op0, const Opnd1 &Op1, const Opnd2 &Op2) {
+ return m_Intrinsic<Intrinsic::fshl>(Op0, Op1, Op2);
+}
+
+template <typename Opnd0, typename Opnd1, typename Opnd2>
+inline typename m_Intrinsic_Ty<Opnd0, Opnd1, Opnd2>::Ty
+m_FShr(const Opnd0 &Op0, const Opnd1 &Op1, const Opnd2 &Op2) {
+ return m_Intrinsic<Intrinsic::fshr>(Op0, Op1, Op2);
+}
+
//===----------------------------------------------------------------------===//
// Matchers for two-operands operators with the operators in either order
//
@@ -1650,7 +2153,7 @@
}
/// Matches an ICmp with a predicate over LHS and RHS in either order.
-/// Does not swap the predicate.
+/// Swaps the predicate if operands are commuted.
template <typename LHS, typename RHS>
inline CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate, true>
m_c_ICmp(ICmpInst::Predicate &Pred, const LHS &L, const RHS &R) {
@@ -1700,6 +2203,15 @@
return m_Sub(m_ZeroInt(), V);
}
+/// Matches a 'Neg' as 'sub nsw 0, V'.
+template <typename ValTy>
+inline OverflowingBinaryOp_match<cst_pred_ty<is_zero_int>, ValTy,
+ Instruction::Sub,
+ OverflowingBinaryOperator::NoSignedWrap>
+m_NSWNeg(const ValTy &V) {
+ return m_NSWSub(m_ZeroInt(), V);
+}
+
/// Matches a 'Not' as 'xor V, -1' or 'xor -1, V'.
template <typename ValTy>
inline BinaryOp_match<ValTy, cst_pred_ty<is_all_ones>, Instruction::Xor, true>
@@ -1732,6 +2244,17 @@
return MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty, true>(L, R);
}
+template <typename LHS, typename RHS>
+inline match_combine_or<
+ match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty, true>,
+ MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty, true>>,
+ match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty, true>,
+ MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty, true>>>
+m_c_MaxOrMin(const LHS &L, const RHS &R) {
+ return m_CombineOr(m_CombineOr(m_c_SMax(L, R), m_c_SMin(L, R)),
+ m_CombineOr(m_c_UMax(L, R), m_c_UMin(L, R)));
+}
+
/// Matches FAdd with LHS and RHS in either order.
template <typename LHS, typename RHS>
inline BinaryOp_match<LHS, RHS, Instruction::FAdd, true>
@@ -1786,6 +2309,136 @@
return Signum_match<Val_t>(V);
}
+template <int Ind, typename Opnd_t> struct ExtractValue_match {
+ Opnd_t Val;
+ ExtractValue_match(const Opnd_t &V) : Val(V) {}
+
+ template <typename OpTy> bool match(OpTy *V) {
+ if (auto *I = dyn_cast<ExtractValueInst>(V))
+ return I->getNumIndices() == 1 && I->getIndices()[0] == Ind &&
+ Val.match(I->getAggregateOperand());
+ return false;
+ }
+};
+
+/// Match a single index ExtractValue instruction.
+/// For example m_ExtractValue<1>(...)
+template <int Ind, typename Val_t>
+inline ExtractValue_match<Ind, Val_t> m_ExtractValue(const Val_t &V) {
+ return ExtractValue_match<Ind, Val_t>(V);
+}
+
+/// Matcher for a single index InsertValue instruction.
+template <int Ind, typename T0, typename T1> struct InsertValue_match {
+ T0 Op0;
+ T1 Op1;
+
+ InsertValue_match(const T0 &Op0, const T1 &Op1) : Op0(Op0), Op1(Op1) {}
+
+ template <typename OpTy> bool match(OpTy *V) {
+ if (auto *I = dyn_cast<InsertValueInst>(V)) {
+ return Op0.match(I->getOperand(0)) && Op1.match(I->getOperand(1)) &&
+ I->getNumIndices() == 1 && Ind == I->getIndices()[0];
+ }
+ return false;
+ }
+};
+
+/// Matches a single index InsertValue instruction.
+template <int Ind, typename Val_t, typename Elt_t>
+inline InsertValue_match<Ind, Val_t, Elt_t> m_InsertValue(const Val_t &Val,
+ const Elt_t &Elt) {
+ return InsertValue_match<Ind, Val_t, Elt_t>(Val, Elt);
+}
+
+/// Matches patterns for `vscale`. This can either be a call to `llvm.vscale` or
+/// the constant expression
+/// `ptrtoint(gep <vscale x 1 x i8>, <vscale x 1 x i8>* null, i32 1>`
+/// under the right conditions determined by DataLayout.
+struct VScaleVal_match {
+private:
+ template <typename Base, typename Offset>
+ inline BinaryOp_match<Base, Offset, Instruction::GetElementPtr>
+ m_OffsetGep(const Base &B, const Offset &O) {
+ return BinaryOp_match<Base, Offset, Instruction::GetElementPtr>(B, O);
+ }
+
+public:
+ const DataLayout &DL;
+ VScaleVal_match(const DataLayout &DL) : DL(DL) {}
+
+ template <typename ITy> bool match(ITy *V) {
+ if (m_Intrinsic<Intrinsic::vscale>().match(V))
+ return true;
+
+ if (m_PtrToInt(m_OffsetGep(m_Zero(), m_SpecificInt(1))).match(V)) {
+ Type *PtrTy = cast<Operator>(V)->getOperand(0)->getType();
+ auto *DerefTy = PtrTy->getPointerElementType();
+ if (isa<ScalableVectorType>(DerefTy) &&
+ DL.getTypeAllocSizeInBits(DerefTy).getKnownMinSize() == 8)
+ return true;
+ }
+
+ return false;
+ }
+};
+
+inline VScaleVal_match m_VScale(const DataLayout &DL) {
+ return VScaleVal_match(DL);
+}
+
+template <typename LHS, typename RHS, unsigned Opcode>
+struct LogicalOp_match {
+ LHS L;
+ RHS R;
+
+ LogicalOp_match(const LHS &L, const RHS &R) : L(L), R(R) {}
+
+ template <typename T> bool match(T *V) {
+ if (auto *I = dyn_cast<Instruction>(V)) {
+ if (!I->getType()->isIntOrIntVectorTy(1))
+ return false;
+
+ if (I->getOpcode() == Opcode && L.match(I->getOperand(0)) &&
+ R.match(I->getOperand(1)))
+ return true;
+
+ if (auto *SI = dyn_cast<SelectInst>(I)) {
+ if (Opcode == Instruction::And) {
+ if (const auto *C = dyn_cast<Constant>(SI->getFalseValue()))
+ if (C->isNullValue() && L.match(SI->getCondition()) &&
+ R.match(SI->getTrueValue()))
+ return true;
+ } else {
+ assert(Opcode == Instruction::Or);
+ if (const auto *C = dyn_cast<Constant>(SI->getTrueValue()))
+ if (C->isOneValue() && L.match(SI->getCondition()) &&
+ R.match(SI->getFalseValue()))
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+};
+
+/// Matches L && R either in the form of L & R or L ? R : false.
+/// Note that the latter form is poison-blocking.
+template <typename LHS, typename RHS>
+inline LogicalOp_match<LHS, RHS, Instruction::And>
+m_LogicalAnd(const LHS &L, const RHS &R) {
+ return LogicalOp_match<LHS, RHS, Instruction::And>(L, R);
+}
+
+/// Matches L || R either in the form of L | R or L ? true : R.
+/// Note that the latter form is poison-blocking.
+template <typename LHS, typename RHS>
+inline LogicalOp_match<LHS, RHS, Instruction::Or>
+m_LogicalOr(const LHS &L, const RHS &R) {
+ return LogicalOp_match<LHS, RHS, Instruction::Or>(L, R);
+}
+
} // end namespace PatternMatch
} // end namespace llvm