xref: /freebsd/contrib/llvm-project/llvm/include/llvm/IR/PatternMatch.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===- PatternMatch.h - Match on the LLVM IR --------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file provides a simple and efficient mechanism for performing general
100b57cec5SDimitry Andric // tree-based pattern matches on the LLVM IR. The power of these routines is
110b57cec5SDimitry Andric // that it allows you to write concise patterns that are expressive and easy to
120b57cec5SDimitry Andric // understand. The other major advantage of this is that it allows you to
130b57cec5SDimitry Andric // trivially capture/bind elements in the pattern to variables. For example,
140b57cec5SDimitry Andric // you can do something like this:
150b57cec5SDimitry Andric //
160b57cec5SDimitry Andric //  Value *Exp = ...
170b57cec5SDimitry Andric //  Value *X, *Y;  ConstantInt *C1, *C2;      // (X & C1) | (Y & C2)
180b57cec5SDimitry Andric //  if (match(Exp, m_Or(m_And(m_Value(X), m_ConstantInt(C1)),
190b57cec5SDimitry Andric //                      m_And(m_Value(Y), m_ConstantInt(C2))))) {
200b57cec5SDimitry Andric //    ... Pattern is matched and variables are bound ...
210b57cec5SDimitry Andric //  }
220b57cec5SDimitry Andric //
230b57cec5SDimitry Andric // This is primarily useful to things like the instruction combiner, but can
240b57cec5SDimitry Andric // also be useful for static analysis tools or code generators.
250b57cec5SDimitry Andric //
260b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #ifndef LLVM_IR_PATTERNMATCH_H
290b57cec5SDimitry Andric #define LLVM_IR_PATTERNMATCH_H
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric #include "llvm/ADT/APFloat.h"
320b57cec5SDimitry Andric #include "llvm/ADT/APInt.h"
330b57cec5SDimitry Andric #include "llvm/IR/Constant.h"
340b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
355ffd83dbSDimitry Andric #include "llvm/IR/DataLayout.h"
360b57cec5SDimitry Andric #include "llvm/IR/InstrTypes.h"
370b57cec5SDimitry Andric #include "llvm/IR/Instruction.h"
380b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
39480093f4SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
400b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h"
410b57cec5SDimitry Andric #include "llvm/IR/Operator.h"
420b57cec5SDimitry Andric #include "llvm/IR/Value.h"
430b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
440b57cec5SDimitry Andric #include <cstdint>
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric namespace llvm {
470b57cec5SDimitry Andric namespace PatternMatch {
480b57cec5SDimitry Andric 
match(Val * V,const Pattern & P)490b57cec5SDimitry Andric template <typename Val, typename Pattern> bool match(Val *V, const Pattern &P) {
500b57cec5SDimitry Andric   return const_cast<Pattern &>(P).match(V);
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric 
match(ArrayRef<int> Mask,const Pattern & P)535ffd83dbSDimitry Andric template <typename Pattern> bool match(ArrayRef<int> Mask, const Pattern &P) {
545ffd83dbSDimitry Andric   return const_cast<Pattern &>(P).match(Mask);
555ffd83dbSDimitry Andric }
565ffd83dbSDimitry Andric 
570b57cec5SDimitry Andric template <typename SubPattern_t> struct OneUse_match {
580b57cec5SDimitry Andric   SubPattern_t SubPattern;
590b57cec5SDimitry Andric 
OneUse_matchOneUse_match600b57cec5SDimitry Andric   OneUse_match(const SubPattern_t &SP) : SubPattern(SP) {}
610b57cec5SDimitry Andric 
matchOneUse_match620b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
630b57cec5SDimitry Andric     return V->hasOneUse() && SubPattern.match(V);
640b57cec5SDimitry Andric   }
650b57cec5SDimitry Andric };
660b57cec5SDimitry Andric 
m_OneUse(const T & SubPattern)670b57cec5SDimitry Andric template <typename T> inline OneUse_match<T> m_OneUse(const T &SubPattern) {
680b57cec5SDimitry Andric   return SubPattern;
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric 
71*0fca6ea1SDimitry Andric template <typename SubPattern_t> struct AllowReassoc_match {
72*0fca6ea1SDimitry Andric   SubPattern_t SubPattern;
73*0fca6ea1SDimitry Andric 
AllowReassoc_matchAllowReassoc_match74*0fca6ea1SDimitry Andric   AllowReassoc_match(const SubPattern_t &SP) : SubPattern(SP) {}
75*0fca6ea1SDimitry Andric 
matchAllowReassoc_match76*0fca6ea1SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
77*0fca6ea1SDimitry Andric     auto *I = dyn_cast<FPMathOperator>(V);
78*0fca6ea1SDimitry Andric     return I && I->hasAllowReassoc() && SubPattern.match(I);
79*0fca6ea1SDimitry Andric   }
80*0fca6ea1SDimitry Andric };
81*0fca6ea1SDimitry Andric 
82*0fca6ea1SDimitry Andric template <typename T>
m_AllowReassoc(const T & SubPattern)83*0fca6ea1SDimitry Andric inline AllowReassoc_match<T> m_AllowReassoc(const T &SubPattern) {
84*0fca6ea1SDimitry Andric   return SubPattern;
85*0fca6ea1SDimitry Andric }
86*0fca6ea1SDimitry Andric 
870b57cec5SDimitry Andric template <typename Class> struct class_match {
matchclass_match880b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *V) { return isa<Class>(V); }
890b57cec5SDimitry Andric };
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric /// Match an arbitrary value and ignore it.
m_Value()920b57cec5SDimitry Andric inline class_match<Value> m_Value() { return class_match<Value>(); }
930b57cec5SDimitry Andric 
945ffd83dbSDimitry Andric /// Match an arbitrary unary operation and ignore it.
m_UnOp()955ffd83dbSDimitry Andric inline class_match<UnaryOperator> m_UnOp() {
965ffd83dbSDimitry Andric   return class_match<UnaryOperator>();
975ffd83dbSDimitry Andric }
985ffd83dbSDimitry Andric 
990b57cec5SDimitry Andric /// Match an arbitrary binary operation and ignore it.
m_BinOp()1000b57cec5SDimitry Andric inline class_match<BinaryOperator> m_BinOp() {
1010b57cec5SDimitry Andric   return class_match<BinaryOperator>();
1020b57cec5SDimitry Andric }
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric /// Matches any compare instruction and ignore it.
m_Cmp()1050b57cec5SDimitry Andric inline class_match<CmpInst> m_Cmp() { return class_match<CmpInst>(); }
1060b57cec5SDimitry Andric 
107fe6060f1SDimitry Andric struct undef_match {
checkundef_match108fe6060f1SDimitry Andric   static bool check(const Value *V) {
109fe6060f1SDimitry Andric     if (isa<UndefValue>(V))
110fe6060f1SDimitry Andric       return true;
111fe6060f1SDimitry Andric 
112fe6060f1SDimitry Andric     const auto *CA = dyn_cast<ConstantAggregate>(V);
113fe6060f1SDimitry Andric     if (!CA)
114fe6060f1SDimitry Andric       return false;
115fe6060f1SDimitry Andric 
116fe6060f1SDimitry Andric     SmallPtrSet<const ConstantAggregate *, 8> Seen;
117fe6060f1SDimitry Andric     SmallVector<const ConstantAggregate *, 8> Worklist;
118fe6060f1SDimitry Andric 
119fe6060f1SDimitry Andric     // Either UndefValue, PoisonValue, or an aggregate that only contains
120fe6060f1SDimitry Andric     // these is accepted by matcher.
121fe6060f1SDimitry Andric     // CheckValue returns false if CA cannot satisfy this constraint.
122fe6060f1SDimitry Andric     auto CheckValue = [&](const ConstantAggregate *CA) {
123fe6060f1SDimitry Andric       for (const Value *Op : CA->operand_values()) {
124fe6060f1SDimitry Andric         if (isa<UndefValue>(Op))
125fe6060f1SDimitry Andric           continue;
126fe6060f1SDimitry Andric 
127fe6060f1SDimitry Andric         const auto *CA = dyn_cast<ConstantAggregate>(Op);
128fe6060f1SDimitry Andric         if (!CA)
129fe6060f1SDimitry Andric           return false;
130fe6060f1SDimitry Andric         if (Seen.insert(CA).second)
131fe6060f1SDimitry Andric           Worklist.emplace_back(CA);
132fe6060f1SDimitry Andric       }
133fe6060f1SDimitry Andric 
134fe6060f1SDimitry Andric       return true;
135fe6060f1SDimitry Andric     };
136fe6060f1SDimitry Andric 
137fe6060f1SDimitry Andric     if (!CheckValue(CA))
138fe6060f1SDimitry Andric       return false;
139fe6060f1SDimitry Andric 
140fe6060f1SDimitry Andric     while (!Worklist.empty()) {
141fe6060f1SDimitry Andric       if (!CheckValue(Worklist.pop_back_val()))
142fe6060f1SDimitry Andric         return false;
143fe6060f1SDimitry Andric     }
144fe6060f1SDimitry Andric     return true;
145fe6060f1SDimitry Andric   }
matchundef_match146fe6060f1SDimitry Andric   template <typename ITy> bool match(ITy *V) { return check(V); }
147fe6060f1SDimitry Andric };
148fe6060f1SDimitry Andric 
149fe6060f1SDimitry Andric /// Match an arbitrary undef constant. This matches poison as well.
150fe6060f1SDimitry Andric /// If this is an aggregate and contains a non-aggregate element that is
151fe6060f1SDimitry Andric /// neither undef nor poison, the aggregate is not matched.
m_Undef()152fe6060f1SDimitry Andric inline auto m_Undef() { return undef_match(); }
153e8d8bef9SDimitry Andric 
154*0fca6ea1SDimitry Andric /// Match an arbitrary UndefValue constant.
m_UndefValue()155*0fca6ea1SDimitry Andric inline class_match<UndefValue> m_UndefValue() {
156*0fca6ea1SDimitry Andric   return class_match<UndefValue>();
157*0fca6ea1SDimitry Andric }
158*0fca6ea1SDimitry Andric 
159e8d8bef9SDimitry Andric /// Match an arbitrary poison constant.
m_Poison()16081ad6265SDimitry Andric inline class_match<PoisonValue> m_Poison() {
16181ad6265SDimitry Andric   return class_match<PoisonValue>();
16281ad6265SDimitry Andric }
163e8d8bef9SDimitry Andric 
164e8d8bef9SDimitry Andric /// Match an arbitrary Constant and ignore it.
m_Constant()165e8d8bef9SDimitry Andric inline class_match<Constant> m_Constant() { return class_match<Constant>(); }
166e8d8bef9SDimitry Andric 
1670b57cec5SDimitry Andric /// Match an arbitrary ConstantInt and ignore it.
m_ConstantInt()1680b57cec5SDimitry Andric inline class_match<ConstantInt> m_ConstantInt() {
1690b57cec5SDimitry Andric   return class_match<ConstantInt>();
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric 
172e8d8bef9SDimitry Andric /// Match an arbitrary ConstantFP and ignore it.
m_ConstantFP()173e8d8bef9SDimitry Andric inline class_match<ConstantFP> m_ConstantFP() {
174e8d8bef9SDimitry Andric   return class_match<ConstantFP>();
175e8d8bef9SDimitry Andric }
1760b57cec5SDimitry Andric 
177fcaf7f86SDimitry Andric struct constantexpr_match {
matchconstantexpr_match178fcaf7f86SDimitry Andric   template <typename ITy> bool match(ITy *V) {
179fcaf7f86SDimitry Andric     auto *C = dyn_cast<Constant>(V);
180fcaf7f86SDimitry Andric     return C && (isa<ConstantExpr>(C) || C->containsConstantExpression());
181e8d8bef9SDimitry Andric   }
182fcaf7f86SDimitry Andric };
183fcaf7f86SDimitry Andric 
184fcaf7f86SDimitry Andric /// Match a constant expression or a constant that contains a constant
185fcaf7f86SDimitry Andric /// expression.
m_ConstantExpr()186fcaf7f86SDimitry Andric inline constantexpr_match m_ConstantExpr() { return constantexpr_match(); }
1870b57cec5SDimitry Andric 
1888bcb0991SDimitry Andric /// Match an arbitrary basic block value and ignore it.
m_BasicBlock()1898bcb0991SDimitry Andric inline class_match<BasicBlock> m_BasicBlock() {
1908bcb0991SDimitry Andric   return class_match<BasicBlock>();
1918bcb0991SDimitry Andric }
1928bcb0991SDimitry Andric 
1938bcb0991SDimitry Andric /// Inverting matcher
1948bcb0991SDimitry Andric template <typename Ty> struct match_unless {
1958bcb0991SDimitry Andric   Ty M;
1968bcb0991SDimitry Andric 
match_unlessmatch_unless1978bcb0991SDimitry Andric   match_unless(const Ty &Matcher) : M(Matcher) {}
1988bcb0991SDimitry Andric 
matchmatch_unless1998bcb0991SDimitry Andric   template <typename ITy> bool match(ITy *V) { return !M.match(V); }
2008bcb0991SDimitry Andric };
2018bcb0991SDimitry Andric 
2028bcb0991SDimitry Andric /// Match if the inner matcher does *NOT* match.
m_Unless(const Ty & M)2038bcb0991SDimitry Andric template <typename Ty> inline match_unless<Ty> m_Unless(const Ty &M) {
2048bcb0991SDimitry Andric   return match_unless<Ty>(M);
2058bcb0991SDimitry Andric }
2068bcb0991SDimitry Andric 
2070b57cec5SDimitry Andric /// Matching combinators
2080b57cec5SDimitry Andric template <typename LTy, typename RTy> struct match_combine_or {
2090b57cec5SDimitry Andric   LTy L;
2100b57cec5SDimitry Andric   RTy R;
2110b57cec5SDimitry Andric 
match_combine_ormatch_combine_or2120b57cec5SDimitry Andric   match_combine_or(const LTy &Left, const RTy &Right) : L(Left), R(Right) {}
2130b57cec5SDimitry Andric 
matchmatch_combine_or2140b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *V) {
2150b57cec5SDimitry Andric     if (L.match(V))
2160b57cec5SDimitry Andric       return true;
2170b57cec5SDimitry Andric     if (R.match(V))
2180b57cec5SDimitry Andric       return true;
2190b57cec5SDimitry Andric     return false;
2200b57cec5SDimitry Andric   }
2210b57cec5SDimitry Andric };
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric template <typename LTy, typename RTy> struct match_combine_and {
2240b57cec5SDimitry Andric   LTy L;
2250b57cec5SDimitry Andric   RTy R;
2260b57cec5SDimitry Andric 
match_combine_andmatch_combine_and2270b57cec5SDimitry Andric   match_combine_and(const LTy &Left, const RTy &Right) : L(Left), R(Right) {}
2280b57cec5SDimitry Andric 
matchmatch_combine_and2290b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *V) {
2300b57cec5SDimitry Andric     if (L.match(V))
2310b57cec5SDimitry Andric       if (R.match(V))
2320b57cec5SDimitry Andric         return true;
2330b57cec5SDimitry Andric     return false;
2340b57cec5SDimitry Andric   }
2350b57cec5SDimitry Andric };
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric /// Combine two pattern matchers matching L || R
2380b57cec5SDimitry Andric template <typename LTy, typename RTy>
m_CombineOr(const LTy & L,const RTy & R)2390b57cec5SDimitry Andric inline match_combine_or<LTy, RTy> m_CombineOr(const LTy &L, const RTy &R) {
2400b57cec5SDimitry Andric   return match_combine_or<LTy, RTy>(L, R);
2410b57cec5SDimitry Andric }
2420b57cec5SDimitry Andric 
2430b57cec5SDimitry Andric /// Combine two pattern matchers matching L && R
2440b57cec5SDimitry Andric template <typename LTy, typename RTy>
m_CombineAnd(const LTy & L,const RTy & R)2450b57cec5SDimitry Andric inline match_combine_and<LTy, RTy> m_CombineAnd(const LTy &L, const RTy &R) {
2460b57cec5SDimitry Andric   return match_combine_and<LTy, RTy>(L, R);
2470b57cec5SDimitry Andric }
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric struct apint_match {
2500b57cec5SDimitry Andric   const APInt *&Res;
251*0fca6ea1SDimitry Andric   bool AllowPoison;
2520b57cec5SDimitry Andric 
apint_matchapint_match253*0fca6ea1SDimitry Andric   apint_match(const APInt *&Res, bool AllowPoison)
254*0fca6ea1SDimitry Andric       : Res(Res), AllowPoison(AllowPoison) {}
2550b57cec5SDimitry Andric 
matchapint_match2560b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *V) {
2570b57cec5SDimitry Andric     if (auto *CI = dyn_cast<ConstantInt>(V)) {
2580b57cec5SDimitry Andric       Res = &CI->getValue();
2590b57cec5SDimitry Andric       return true;
2600b57cec5SDimitry Andric     }
2610b57cec5SDimitry Andric     if (V->getType()->isVectorTy())
2620b57cec5SDimitry Andric       if (const auto *C = dyn_cast<Constant>(V))
26381ad6265SDimitry Andric         if (auto *CI =
264*0fca6ea1SDimitry Andric                 dyn_cast_or_null<ConstantInt>(C->getSplatValue(AllowPoison))) {
2650b57cec5SDimitry Andric           Res = &CI->getValue();
2660b57cec5SDimitry Andric           return true;
2670b57cec5SDimitry Andric         }
2680b57cec5SDimitry Andric     return false;
2690b57cec5SDimitry Andric   }
2700b57cec5SDimitry Andric };
2710b57cec5SDimitry Andric // Either constexpr if or renaming ConstantFP::getValueAPF to
2720b57cec5SDimitry Andric // ConstantFP::getValue is needed to do it via single template
2730b57cec5SDimitry Andric // function for both apint/apfloat.
2740b57cec5SDimitry Andric struct apfloat_match {
2750b57cec5SDimitry Andric   const APFloat *&Res;
276*0fca6ea1SDimitry Andric   bool AllowPoison;
2775ffd83dbSDimitry Andric 
apfloat_matchapfloat_match278*0fca6ea1SDimitry Andric   apfloat_match(const APFloat *&Res, bool AllowPoison)
279*0fca6ea1SDimitry Andric       : Res(Res), AllowPoison(AllowPoison) {}
2805ffd83dbSDimitry Andric 
matchapfloat_match2810b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *V) {
2820b57cec5SDimitry Andric     if (auto *CI = dyn_cast<ConstantFP>(V)) {
2830b57cec5SDimitry Andric       Res = &CI->getValueAPF();
2840b57cec5SDimitry Andric       return true;
2850b57cec5SDimitry Andric     }
2860b57cec5SDimitry Andric     if (V->getType()->isVectorTy())
2870b57cec5SDimitry Andric       if (const auto *C = dyn_cast<Constant>(V))
28881ad6265SDimitry Andric         if (auto *CI =
289*0fca6ea1SDimitry Andric                 dyn_cast_or_null<ConstantFP>(C->getSplatValue(AllowPoison))) {
2900b57cec5SDimitry Andric           Res = &CI->getValueAPF();
2910b57cec5SDimitry Andric           return true;
2920b57cec5SDimitry Andric         }
2930b57cec5SDimitry Andric     return false;
2940b57cec5SDimitry Andric   }
2950b57cec5SDimitry Andric };
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric /// Match a ConstantInt or splatted ConstantVector, binding the
2980b57cec5SDimitry Andric /// specified pointer to the contained APInt.
m_APInt(const APInt * & Res)2995ffd83dbSDimitry Andric inline apint_match m_APInt(const APInt *&Res) {
300*0fca6ea1SDimitry Andric   // Forbid poison by default to maintain previous behavior.
301*0fca6ea1SDimitry Andric   return apint_match(Res, /* AllowPoison */ false);
3025ffd83dbSDimitry Andric }
3035ffd83dbSDimitry Andric 
304*0fca6ea1SDimitry Andric /// Match APInt while allowing poison in splat vector constants.
m_APIntAllowPoison(const APInt * & Res)305*0fca6ea1SDimitry Andric inline apint_match m_APIntAllowPoison(const APInt *&Res) {
306*0fca6ea1SDimitry Andric   return apint_match(Res, /* AllowPoison */ true);
3075ffd83dbSDimitry Andric }
3085ffd83dbSDimitry Andric 
309*0fca6ea1SDimitry Andric /// Match APInt while forbidding poison in splat vector constants.
m_APIntForbidPoison(const APInt * & Res)310*0fca6ea1SDimitry Andric inline apint_match m_APIntForbidPoison(const APInt *&Res) {
311*0fca6ea1SDimitry Andric   return apint_match(Res, /* AllowPoison */ false);
3125ffd83dbSDimitry Andric }
3130b57cec5SDimitry Andric 
3140b57cec5SDimitry Andric /// Match a ConstantFP or splatted ConstantVector, binding the
3150b57cec5SDimitry Andric /// specified pointer to the contained APFloat.
m_APFloat(const APFloat * & Res)3165ffd83dbSDimitry Andric inline apfloat_match m_APFloat(const APFloat *&Res) {
3175ffd83dbSDimitry Andric   // Forbid undefs by default to maintain previous behavior.
318*0fca6ea1SDimitry Andric   return apfloat_match(Res, /* AllowPoison */ false);
3195ffd83dbSDimitry Andric }
3205ffd83dbSDimitry Andric 
321*0fca6ea1SDimitry Andric /// Match APFloat while allowing poison in splat vector constants.
m_APFloatAllowPoison(const APFloat * & Res)322*0fca6ea1SDimitry Andric inline apfloat_match m_APFloatAllowPoison(const APFloat *&Res) {
323*0fca6ea1SDimitry Andric   return apfloat_match(Res, /* AllowPoison */ true);
3245ffd83dbSDimitry Andric }
3255ffd83dbSDimitry Andric 
326*0fca6ea1SDimitry Andric /// Match APFloat while forbidding poison in splat vector constants.
m_APFloatForbidPoison(const APFloat * & Res)327*0fca6ea1SDimitry Andric inline apfloat_match m_APFloatForbidPoison(const APFloat *&Res) {
328*0fca6ea1SDimitry Andric   return apfloat_match(Res, /* AllowPoison */ false);
3295ffd83dbSDimitry Andric }
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric template <int64_t Val> struct constantint_match {
matchconstantint_match3320b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *V) {
3330b57cec5SDimitry Andric     if (const auto *CI = dyn_cast<ConstantInt>(V)) {
3340b57cec5SDimitry Andric       const APInt &CIV = CI->getValue();
3350b57cec5SDimitry Andric       if (Val >= 0)
3360b57cec5SDimitry Andric         return CIV == static_cast<uint64_t>(Val);
3370b57cec5SDimitry Andric       // If Val is negative, and CI is shorter than it, truncate to the right
3380b57cec5SDimitry Andric       // number of bits.  If it is larger, then we have to sign extend.  Just
3390b57cec5SDimitry Andric       // compare their negated values.
3400b57cec5SDimitry Andric       return -CIV == -Val;
3410b57cec5SDimitry Andric     }
3420b57cec5SDimitry Andric     return false;
3430b57cec5SDimitry Andric   }
3440b57cec5SDimitry Andric };
3450b57cec5SDimitry Andric 
3460b57cec5SDimitry Andric /// Match a ConstantInt with a specific value.
m_ConstantInt()3470b57cec5SDimitry Andric template <int64_t Val> inline constantint_match<Val> m_ConstantInt() {
3480b57cec5SDimitry Andric   return constantint_match<Val>();
3490b57cec5SDimitry Andric }
3500b57cec5SDimitry Andric 
3515ffd83dbSDimitry Andric /// This helper class is used to match constant scalars, vector splats,
3525ffd83dbSDimitry Andric /// and fixed width vectors that satisfy a specified predicate.
353*0fca6ea1SDimitry Andric /// For fixed width vector constants, poison elements are ignored if AllowPoison
354*0fca6ea1SDimitry Andric /// is true.
355*0fca6ea1SDimitry Andric template <typename Predicate, typename ConstantVal, bool AllowPoison>
3565ffd83dbSDimitry Andric struct cstval_pred_ty : public Predicate {
357*0fca6ea1SDimitry Andric   const Constant **Res = nullptr;
match_implcstval_pred_ty358*0fca6ea1SDimitry Andric   template <typename ITy> bool match_impl(ITy *V) {
3595ffd83dbSDimitry Andric     if (const auto *CV = dyn_cast<ConstantVal>(V))
3605ffd83dbSDimitry Andric       return this->isValue(CV->getValue());
3615ffd83dbSDimitry Andric     if (const auto *VTy = dyn_cast<VectorType>(V->getType())) {
3620b57cec5SDimitry Andric       if (const auto *C = dyn_cast<Constant>(V)) {
3635ffd83dbSDimitry Andric         if (const auto *CV = dyn_cast_or_null<ConstantVal>(C->getSplatValue()))
3645ffd83dbSDimitry Andric           return this->isValue(CV->getValue());
3655ffd83dbSDimitry Andric 
3665ffd83dbSDimitry Andric         // Number of elements of a scalable vector unknown at compile time
3675ffd83dbSDimitry Andric         auto *FVTy = dyn_cast<FixedVectorType>(VTy);
3685ffd83dbSDimitry Andric         if (!FVTy)
3695ffd83dbSDimitry Andric           return false;
3700b57cec5SDimitry Andric 
3710b57cec5SDimitry Andric         // Non-splat vector constant: check each element for a match.
3725ffd83dbSDimitry Andric         unsigned NumElts = FVTy->getNumElements();
3730b57cec5SDimitry Andric         assert(NumElts != 0 && "Constant vector with no elements?");
374*0fca6ea1SDimitry Andric         bool HasNonPoisonElements = false;
3750b57cec5SDimitry Andric         for (unsigned i = 0; i != NumElts; ++i) {
3760b57cec5SDimitry Andric           Constant *Elt = C->getAggregateElement(i);
3770b57cec5SDimitry Andric           if (!Elt)
3780b57cec5SDimitry Andric             return false;
379*0fca6ea1SDimitry Andric           if (AllowPoison && isa<PoisonValue>(Elt))
3800b57cec5SDimitry Andric             continue;
3815ffd83dbSDimitry Andric           auto *CV = dyn_cast<ConstantVal>(Elt);
3825ffd83dbSDimitry Andric           if (!CV || !this->isValue(CV->getValue()))
3830b57cec5SDimitry Andric             return false;
384*0fca6ea1SDimitry Andric           HasNonPoisonElements = true;
3850b57cec5SDimitry Andric         }
386*0fca6ea1SDimitry Andric         return HasNonPoisonElements;
3870b57cec5SDimitry Andric       }
3880b57cec5SDimitry Andric     }
3890b57cec5SDimitry Andric     return false;
3900b57cec5SDimitry Andric   }
391*0fca6ea1SDimitry Andric 
matchcstval_pred_ty392*0fca6ea1SDimitry Andric   template <typename ITy> bool match(ITy *V) {
393*0fca6ea1SDimitry Andric     if (this->match_impl(V)) {
394*0fca6ea1SDimitry Andric       if (Res)
395*0fca6ea1SDimitry Andric         *Res = cast<Constant>(V);
396*0fca6ea1SDimitry Andric       return true;
397*0fca6ea1SDimitry Andric     }
398*0fca6ea1SDimitry Andric     return false;
399*0fca6ea1SDimitry Andric   }
4000b57cec5SDimitry Andric };
4010b57cec5SDimitry Andric 
4025ffd83dbSDimitry Andric /// specialization of cstval_pred_ty for ConstantInt
403*0fca6ea1SDimitry Andric template <typename Predicate, bool AllowPoison = true>
404*0fca6ea1SDimitry Andric using cst_pred_ty = cstval_pred_ty<Predicate, ConstantInt, AllowPoison>;
4055ffd83dbSDimitry Andric 
4065ffd83dbSDimitry Andric /// specialization of cstval_pred_ty for ConstantFP
4075ffd83dbSDimitry Andric template <typename Predicate>
408*0fca6ea1SDimitry Andric using cstfp_pred_ty = cstval_pred_ty<Predicate, ConstantFP,
409*0fca6ea1SDimitry Andric                                      /*AllowPoison=*/true>;
4105ffd83dbSDimitry Andric 
4110b57cec5SDimitry Andric /// This helper class is used to match scalar and vector constants that
4120b57cec5SDimitry Andric /// satisfy a specified predicate, and bind them to an APInt.
4130b57cec5SDimitry Andric template <typename Predicate> struct api_pred_ty : public Predicate {
4140b57cec5SDimitry Andric   const APInt *&Res;
4150b57cec5SDimitry Andric 
api_pred_tyapi_pred_ty4160b57cec5SDimitry Andric   api_pred_ty(const APInt *&R) : Res(R) {}
4170b57cec5SDimitry Andric 
matchapi_pred_ty4180b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *V) {
4190b57cec5SDimitry Andric     if (const auto *CI = dyn_cast<ConstantInt>(V))
4200b57cec5SDimitry Andric       if (this->isValue(CI->getValue())) {
4210b57cec5SDimitry Andric         Res = &CI->getValue();
4220b57cec5SDimitry Andric         return true;
4230b57cec5SDimitry Andric       }
4240b57cec5SDimitry Andric     if (V->getType()->isVectorTy())
4250b57cec5SDimitry Andric       if (const auto *C = dyn_cast<Constant>(V))
426*0fca6ea1SDimitry Andric         if (auto *CI = dyn_cast_or_null<ConstantInt>(
427*0fca6ea1SDimitry Andric                 C->getSplatValue(/*AllowPoison=*/true)))
4280b57cec5SDimitry Andric           if (this->isValue(CI->getValue())) {
4290b57cec5SDimitry Andric             Res = &CI->getValue();
4300b57cec5SDimitry Andric             return true;
4310b57cec5SDimitry Andric           }
4320b57cec5SDimitry Andric 
4330b57cec5SDimitry Andric     return false;
4340b57cec5SDimitry Andric   }
4350b57cec5SDimitry Andric };
4360b57cec5SDimitry Andric 
437e8d8bef9SDimitry Andric /// This helper class is used to match scalar and vector constants that
438e8d8bef9SDimitry Andric /// satisfy a specified predicate, and bind them to an APFloat.
439*0fca6ea1SDimitry Andric /// Poison is allowed in splat vector constants.
440e8d8bef9SDimitry Andric template <typename Predicate> struct apf_pred_ty : public Predicate {
441e8d8bef9SDimitry Andric   const APFloat *&Res;
442e8d8bef9SDimitry Andric 
apf_pred_tyapf_pred_ty443e8d8bef9SDimitry Andric   apf_pred_ty(const APFloat *&R) : Res(R) {}
444e8d8bef9SDimitry Andric 
matchapf_pred_ty445e8d8bef9SDimitry Andric   template <typename ITy> bool match(ITy *V) {
446e8d8bef9SDimitry Andric     if (const auto *CI = dyn_cast<ConstantFP>(V))
447e8d8bef9SDimitry Andric       if (this->isValue(CI->getValue())) {
448e8d8bef9SDimitry Andric         Res = &CI->getValue();
449e8d8bef9SDimitry Andric         return true;
450e8d8bef9SDimitry Andric       }
451e8d8bef9SDimitry Andric     if (V->getType()->isVectorTy())
452e8d8bef9SDimitry Andric       if (const auto *C = dyn_cast<Constant>(V))
453e8d8bef9SDimitry Andric         if (auto *CI = dyn_cast_or_null<ConstantFP>(
454*0fca6ea1SDimitry Andric                 C->getSplatValue(/* AllowPoison */ true)))
455e8d8bef9SDimitry Andric           if (this->isValue(CI->getValue())) {
456e8d8bef9SDimitry Andric             Res = &CI->getValue();
457e8d8bef9SDimitry Andric             return true;
458e8d8bef9SDimitry Andric           }
459e8d8bef9SDimitry Andric 
460e8d8bef9SDimitry Andric     return false;
461e8d8bef9SDimitry Andric   }
462e8d8bef9SDimitry Andric };
463e8d8bef9SDimitry Andric 
4640b57cec5SDimitry Andric ///////////////////////////////////////////////////////////////////////////////
4650b57cec5SDimitry Andric //
4660b57cec5SDimitry Andric // Encapsulate constant value queries for use in templated predicate matchers.
4670b57cec5SDimitry Andric // This allows checking if constants match using compound predicates and works
4680b57cec5SDimitry Andric // with vector constants, possibly with relaxed constraints. For example, ignore
4690b57cec5SDimitry Andric // undef values.
4700b57cec5SDimitry Andric //
4710b57cec5SDimitry Andric ///////////////////////////////////////////////////////////////////////////////
4720b57cec5SDimitry Andric 
473*0fca6ea1SDimitry Andric template <typename APTy> struct custom_checkfn {
474*0fca6ea1SDimitry Andric   function_ref<bool(const APTy &)> CheckFn;
isValuecustom_checkfn475*0fca6ea1SDimitry Andric   bool isValue(const APTy &C) { return CheckFn(C); }
476*0fca6ea1SDimitry Andric };
477*0fca6ea1SDimitry Andric 
478*0fca6ea1SDimitry Andric /// Match an integer or vector where CheckFn(ele) for each element is true.
479*0fca6ea1SDimitry Andric /// For vectors, poison elements are assumed to match.
480*0fca6ea1SDimitry Andric inline cst_pred_ty<custom_checkfn<APInt>>
m_CheckedInt(function_ref<bool (const APInt &)> CheckFn)481*0fca6ea1SDimitry Andric m_CheckedInt(function_ref<bool(const APInt &)> CheckFn) {
482*0fca6ea1SDimitry Andric   return cst_pred_ty<custom_checkfn<APInt>>{{CheckFn}};
483*0fca6ea1SDimitry Andric }
484*0fca6ea1SDimitry Andric 
485*0fca6ea1SDimitry Andric inline cst_pred_ty<custom_checkfn<APInt>>
m_CheckedInt(const Constant * & V,function_ref<bool (const APInt &)> CheckFn)486*0fca6ea1SDimitry Andric m_CheckedInt(const Constant *&V, function_ref<bool(const APInt &)> CheckFn) {
487*0fca6ea1SDimitry Andric   return cst_pred_ty<custom_checkfn<APInt>>{{CheckFn}, &V};
488*0fca6ea1SDimitry Andric }
489*0fca6ea1SDimitry Andric 
490*0fca6ea1SDimitry Andric /// Match a float or vector where CheckFn(ele) for each element is true.
491*0fca6ea1SDimitry Andric /// For vectors, poison elements are assumed to match.
492*0fca6ea1SDimitry Andric inline cstfp_pred_ty<custom_checkfn<APFloat>>
m_CheckedFp(function_ref<bool (const APFloat &)> CheckFn)493*0fca6ea1SDimitry Andric m_CheckedFp(function_ref<bool(const APFloat &)> CheckFn) {
494*0fca6ea1SDimitry Andric   return cstfp_pred_ty<custom_checkfn<APFloat>>{{CheckFn}};
495*0fca6ea1SDimitry Andric }
496*0fca6ea1SDimitry Andric 
497*0fca6ea1SDimitry Andric inline cstfp_pred_ty<custom_checkfn<APFloat>>
m_CheckedFp(const Constant * & V,function_ref<bool (const APFloat &)> CheckFn)498*0fca6ea1SDimitry Andric m_CheckedFp(const Constant *&V, function_ref<bool(const APFloat &)> CheckFn) {
499*0fca6ea1SDimitry Andric   return cstfp_pred_ty<custom_checkfn<APFloat>>{{CheckFn}, &V};
500*0fca6ea1SDimitry Andric }
501*0fca6ea1SDimitry Andric 
5028bcb0991SDimitry Andric struct is_any_apint {
isValueis_any_apint5038bcb0991SDimitry Andric   bool isValue(const APInt &C) { return true; }
5048bcb0991SDimitry Andric };
5058bcb0991SDimitry Andric /// Match an integer or vector with any integral constant.
5068bcb0991SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_AnyIntegralConstant()5078bcb0991SDimitry Andric inline cst_pred_ty<is_any_apint> m_AnyIntegralConstant() {
5088bcb0991SDimitry Andric   return cst_pred_ty<is_any_apint>();
5098bcb0991SDimitry Andric }
5108bcb0991SDimitry Andric 
51106c3fb27SDimitry Andric struct is_shifted_mask {
isValueis_shifted_mask51206c3fb27SDimitry Andric   bool isValue(const APInt &C) { return C.isShiftedMask(); }
51306c3fb27SDimitry Andric };
51406c3fb27SDimitry Andric 
m_ShiftedMask()51506c3fb27SDimitry Andric inline cst_pred_ty<is_shifted_mask> m_ShiftedMask() {
51606c3fb27SDimitry Andric   return cst_pred_ty<is_shifted_mask>();
51706c3fb27SDimitry Andric }
51806c3fb27SDimitry Andric 
5190b57cec5SDimitry Andric struct is_all_ones {
isValueis_all_ones520349cc55cSDimitry Andric   bool isValue(const APInt &C) { return C.isAllOnes(); }
5210b57cec5SDimitry Andric };
5220b57cec5SDimitry Andric /// Match an integer or vector with all bits set.
5230b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_AllOnes()5240b57cec5SDimitry Andric inline cst_pred_ty<is_all_ones> m_AllOnes() {
5250b57cec5SDimitry Andric   return cst_pred_ty<is_all_ones>();
5260b57cec5SDimitry Andric }
5270b57cec5SDimitry Andric 
m_AllOnesForbidPoison()528*0fca6ea1SDimitry Andric inline cst_pred_ty<is_all_ones, false> m_AllOnesForbidPoison() {
529*0fca6ea1SDimitry Andric   return cst_pred_ty<is_all_ones, false>();
530*0fca6ea1SDimitry Andric }
531*0fca6ea1SDimitry Andric 
5320b57cec5SDimitry Andric struct is_maxsignedvalue {
isValueis_maxsignedvalue5330b57cec5SDimitry Andric   bool isValue(const APInt &C) { return C.isMaxSignedValue(); }
5340b57cec5SDimitry Andric };
5350b57cec5SDimitry Andric /// Match an integer or vector with values having all bits except for the high
5360b57cec5SDimitry Andric /// bit set (0x7f...).
5370b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_MaxSignedValue()5380b57cec5SDimitry Andric inline cst_pred_ty<is_maxsignedvalue> m_MaxSignedValue() {
5390b57cec5SDimitry Andric   return cst_pred_ty<is_maxsignedvalue>();
5400b57cec5SDimitry Andric }
m_MaxSignedValue(const APInt * & V)5410b57cec5SDimitry Andric inline api_pred_ty<is_maxsignedvalue> m_MaxSignedValue(const APInt *&V) {
5420b57cec5SDimitry Andric   return V;
5430b57cec5SDimitry Andric }
5440b57cec5SDimitry Andric 
5450b57cec5SDimitry Andric struct is_negative {
isValueis_negative5460b57cec5SDimitry Andric   bool isValue(const APInt &C) { return C.isNegative(); }
5470b57cec5SDimitry Andric };
5480b57cec5SDimitry Andric /// Match an integer or vector of negative values.
5490b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_Negative()5500b57cec5SDimitry Andric inline cst_pred_ty<is_negative> m_Negative() {
5510b57cec5SDimitry Andric   return cst_pred_ty<is_negative>();
5520b57cec5SDimitry Andric }
m_Negative(const APInt * & V)55381ad6265SDimitry Andric inline api_pred_ty<is_negative> m_Negative(const APInt *&V) { return V; }
5540b57cec5SDimitry Andric 
5550b57cec5SDimitry Andric struct is_nonnegative {
isValueis_nonnegative5560b57cec5SDimitry Andric   bool isValue(const APInt &C) { return C.isNonNegative(); }
5570b57cec5SDimitry Andric };
558480093f4SDimitry Andric /// Match an integer or vector of non-negative values.
5590b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_NonNegative()5600b57cec5SDimitry Andric inline cst_pred_ty<is_nonnegative> m_NonNegative() {
5610b57cec5SDimitry Andric   return cst_pred_ty<is_nonnegative>();
5620b57cec5SDimitry Andric }
m_NonNegative(const APInt * & V)56381ad6265SDimitry Andric inline api_pred_ty<is_nonnegative> m_NonNegative(const APInt *&V) { return V; }
5640b57cec5SDimitry Andric 
565480093f4SDimitry Andric struct is_strictlypositive {
isValueis_strictlypositive566480093f4SDimitry Andric   bool isValue(const APInt &C) { return C.isStrictlyPositive(); }
567480093f4SDimitry Andric };
568480093f4SDimitry Andric /// Match an integer or vector of strictly positive values.
569480093f4SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_StrictlyPositive()570480093f4SDimitry Andric inline cst_pred_ty<is_strictlypositive> m_StrictlyPositive() {
571480093f4SDimitry Andric   return cst_pred_ty<is_strictlypositive>();
572480093f4SDimitry Andric }
m_StrictlyPositive(const APInt * & V)573480093f4SDimitry Andric inline api_pred_ty<is_strictlypositive> m_StrictlyPositive(const APInt *&V) {
574480093f4SDimitry Andric   return V;
575480093f4SDimitry Andric }
576480093f4SDimitry Andric 
577480093f4SDimitry Andric struct is_nonpositive {
isValueis_nonpositive578480093f4SDimitry Andric   bool isValue(const APInt &C) { return C.isNonPositive(); }
579480093f4SDimitry Andric };
580480093f4SDimitry Andric /// Match an integer or vector of non-positive values.
581480093f4SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_NonPositive()582480093f4SDimitry Andric inline cst_pred_ty<is_nonpositive> m_NonPositive() {
583480093f4SDimitry Andric   return cst_pred_ty<is_nonpositive>();
584480093f4SDimitry Andric }
m_NonPositive(const APInt * & V)585480093f4SDimitry Andric inline api_pred_ty<is_nonpositive> m_NonPositive(const APInt *&V) { return V; }
586480093f4SDimitry Andric 
5870b57cec5SDimitry Andric struct is_one {
isValueis_one588349cc55cSDimitry Andric   bool isValue(const APInt &C) { return C.isOne(); }
5890b57cec5SDimitry Andric };
5900b57cec5SDimitry Andric /// Match an integer 1 or a vector with all elements equal to 1.
5910b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_One()59281ad6265SDimitry Andric inline cst_pred_ty<is_one> m_One() { return cst_pred_ty<is_one>(); }
5930b57cec5SDimitry Andric 
5940b57cec5SDimitry Andric struct is_zero_int {
isValueis_zero_int595349cc55cSDimitry Andric   bool isValue(const APInt &C) { return C.isZero(); }
5960b57cec5SDimitry Andric };
5970b57cec5SDimitry Andric /// Match an integer 0 or a vector with all elements equal to 0.
5980b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_ZeroInt()5990b57cec5SDimitry Andric inline cst_pred_ty<is_zero_int> m_ZeroInt() {
6000b57cec5SDimitry Andric   return cst_pred_ty<is_zero_int>();
6010b57cec5SDimitry Andric }
6020b57cec5SDimitry Andric 
6030b57cec5SDimitry Andric struct is_zero {
matchis_zero6040b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *V) {
6050b57cec5SDimitry Andric     auto *C = dyn_cast<Constant>(V);
6065ffd83dbSDimitry Andric     // FIXME: this should be able to do something for scalable vectors
6070b57cec5SDimitry Andric     return C && (C->isNullValue() || cst_pred_ty<is_zero_int>().match(C));
6080b57cec5SDimitry Andric   }
6090b57cec5SDimitry Andric };
6100b57cec5SDimitry Andric /// Match any null constant or a vector with all elements equal to 0.
6110b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_Zero()61281ad6265SDimitry Andric inline is_zero m_Zero() { return is_zero(); }
6130b57cec5SDimitry Andric 
6140b57cec5SDimitry Andric struct is_power2 {
isValueis_power26150b57cec5SDimitry Andric   bool isValue(const APInt &C) { return C.isPowerOf2(); }
6160b57cec5SDimitry Andric };
6170b57cec5SDimitry Andric /// Match an integer or vector power-of-2.
6180b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_Power2()61981ad6265SDimitry Andric inline cst_pred_ty<is_power2> m_Power2() { return cst_pred_ty<is_power2>(); }
m_Power2(const APInt * & V)62081ad6265SDimitry Andric inline api_pred_ty<is_power2> m_Power2(const APInt *&V) { return V; }
6210b57cec5SDimitry Andric 
6228bcb0991SDimitry Andric struct is_negated_power2 {
isValueis_negated_power2623349cc55cSDimitry Andric   bool isValue(const APInt &C) { return C.isNegatedPowerOf2(); }
6248bcb0991SDimitry Andric };
6258bcb0991SDimitry Andric /// Match a integer or vector negated power-of-2.
6268bcb0991SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_NegatedPower2()6278bcb0991SDimitry Andric inline cst_pred_ty<is_negated_power2> m_NegatedPower2() {
6288bcb0991SDimitry Andric   return cst_pred_ty<is_negated_power2>();
6298bcb0991SDimitry Andric }
m_NegatedPower2(const APInt * & V)6308bcb0991SDimitry Andric inline api_pred_ty<is_negated_power2> m_NegatedPower2(const APInt *&V) {
6318bcb0991SDimitry Andric   return V;
6328bcb0991SDimitry Andric }
6338bcb0991SDimitry Andric 
634*0fca6ea1SDimitry Andric struct is_negated_power2_or_zero {
isValueis_negated_power2_or_zero635*0fca6ea1SDimitry Andric   bool isValue(const APInt &C) { return !C || C.isNegatedPowerOf2(); }
636*0fca6ea1SDimitry Andric };
637*0fca6ea1SDimitry Andric /// Match a integer or vector negated power-of-2.
638*0fca6ea1SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_NegatedPower2OrZero()639*0fca6ea1SDimitry Andric inline cst_pred_ty<is_negated_power2_or_zero> m_NegatedPower2OrZero() {
640*0fca6ea1SDimitry Andric   return cst_pred_ty<is_negated_power2_or_zero>();
641*0fca6ea1SDimitry Andric }
642*0fca6ea1SDimitry Andric inline api_pred_ty<is_negated_power2_or_zero>
m_NegatedPower2OrZero(const APInt * & V)643*0fca6ea1SDimitry Andric m_NegatedPower2OrZero(const APInt *&V) {
644*0fca6ea1SDimitry Andric   return V;
645*0fca6ea1SDimitry Andric }
646*0fca6ea1SDimitry Andric 
6470b57cec5SDimitry Andric struct is_power2_or_zero {
isValueis_power2_or_zero6480b57cec5SDimitry Andric   bool isValue(const APInt &C) { return !C || C.isPowerOf2(); }
6490b57cec5SDimitry Andric };
6500b57cec5SDimitry Andric /// Match an integer or vector of 0 or power-of-2 values.
6510b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_Power2OrZero()6520b57cec5SDimitry Andric inline cst_pred_ty<is_power2_or_zero> m_Power2OrZero() {
6530b57cec5SDimitry Andric   return cst_pred_ty<is_power2_or_zero>();
6540b57cec5SDimitry Andric }
m_Power2OrZero(const APInt * & V)6550b57cec5SDimitry Andric inline api_pred_ty<is_power2_or_zero> m_Power2OrZero(const APInt *&V) {
6560b57cec5SDimitry Andric   return V;
6570b57cec5SDimitry Andric }
6580b57cec5SDimitry Andric 
6590b57cec5SDimitry Andric struct is_sign_mask {
isValueis_sign_mask6600b57cec5SDimitry Andric   bool isValue(const APInt &C) { return C.isSignMask(); }
6610b57cec5SDimitry Andric };
6620b57cec5SDimitry Andric /// Match an integer or vector with only the sign bit(s) set.
6630b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_SignMask()6640b57cec5SDimitry Andric inline cst_pred_ty<is_sign_mask> m_SignMask() {
6650b57cec5SDimitry Andric   return cst_pred_ty<is_sign_mask>();
6660b57cec5SDimitry Andric }
6670b57cec5SDimitry Andric 
6680b57cec5SDimitry Andric struct is_lowbit_mask {
isValueis_lowbit_mask6690b57cec5SDimitry Andric   bool isValue(const APInt &C) { return C.isMask(); }
6700b57cec5SDimitry Andric };
6710b57cec5SDimitry Andric /// Match an integer or vector with only the low bit(s) set.
6720b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_LowBitMask()6730b57cec5SDimitry Andric inline cst_pred_ty<is_lowbit_mask> m_LowBitMask() {
6740b57cec5SDimitry Andric   return cst_pred_ty<is_lowbit_mask>();
6750b57cec5SDimitry Andric }
m_LowBitMask(const APInt * & V)67681ad6265SDimitry Andric inline api_pred_ty<is_lowbit_mask> m_LowBitMask(const APInt *&V) { return V; }
6770b57cec5SDimitry Andric 
678*0fca6ea1SDimitry Andric struct is_lowbit_mask_or_zero {
isValueis_lowbit_mask_or_zero679*0fca6ea1SDimitry Andric   bool isValue(const APInt &C) { return !C || C.isMask(); }
680*0fca6ea1SDimitry Andric };
681*0fca6ea1SDimitry Andric /// Match an integer or vector with only the low bit(s) set.
682*0fca6ea1SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_LowBitMaskOrZero()683*0fca6ea1SDimitry Andric inline cst_pred_ty<is_lowbit_mask_or_zero> m_LowBitMaskOrZero() {
684*0fca6ea1SDimitry Andric   return cst_pred_ty<is_lowbit_mask_or_zero>();
685*0fca6ea1SDimitry Andric }
m_LowBitMaskOrZero(const APInt * & V)686*0fca6ea1SDimitry Andric inline api_pred_ty<is_lowbit_mask_or_zero> m_LowBitMaskOrZero(const APInt *&V) {
687*0fca6ea1SDimitry Andric   return V;
688*0fca6ea1SDimitry Andric }
689*0fca6ea1SDimitry Andric 
6900b57cec5SDimitry Andric struct icmp_pred_with_threshold {
6910b57cec5SDimitry Andric   ICmpInst::Predicate Pred;
6920b57cec5SDimitry Andric   const APInt *Thr;
isValueicmp_pred_with_threshold693349cc55cSDimitry Andric   bool isValue(const APInt &C) { return ICmpInst::compare(C, *Thr, Pred); }
6940b57cec5SDimitry Andric };
6950b57cec5SDimitry Andric /// Match an integer or vector with every element comparing 'pred' (eg/ne/...)
6960b57cec5SDimitry Andric /// to Threshold. For vectors, this includes constants with undefined elements.
6970b57cec5SDimitry Andric inline cst_pred_ty<icmp_pred_with_threshold>
m_SpecificInt_ICMP(ICmpInst::Predicate Predicate,const APInt & Threshold)6980b57cec5SDimitry Andric m_SpecificInt_ICMP(ICmpInst::Predicate Predicate, const APInt &Threshold) {
6990b57cec5SDimitry Andric   cst_pred_ty<icmp_pred_with_threshold> P;
7000b57cec5SDimitry Andric   P.Pred = Predicate;
7010b57cec5SDimitry Andric   P.Thr = &Threshold;
7020b57cec5SDimitry Andric   return P;
7030b57cec5SDimitry Andric }
7040b57cec5SDimitry Andric 
7050b57cec5SDimitry Andric struct is_nan {
isValueis_nan7060b57cec5SDimitry Andric   bool isValue(const APFloat &C) { return C.isNaN(); }
7070b57cec5SDimitry Andric };
7080b57cec5SDimitry Andric /// Match an arbitrary NaN constant. This includes quiet and signalling nans.
7090b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_NaN()71081ad6265SDimitry Andric inline cstfp_pred_ty<is_nan> m_NaN() { return cstfp_pred_ty<is_nan>(); }
7110b57cec5SDimitry Andric 
712e8d8bef9SDimitry Andric struct is_nonnan {
isValueis_nonnan713e8d8bef9SDimitry Andric   bool isValue(const APFloat &C) { return !C.isNaN(); }
714e8d8bef9SDimitry Andric };
715e8d8bef9SDimitry Andric /// Match a non-NaN FP constant.
716e8d8bef9SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_NonNaN()717e8d8bef9SDimitry Andric inline cstfp_pred_ty<is_nonnan> m_NonNaN() {
718e8d8bef9SDimitry Andric   return cstfp_pred_ty<is_nonnan>();
719e8d8bef9SDimitry Andric }
720e8d8bef9SDimitry Andric 
7215ffd83dbSDimitry Andric struct is_inf {
isValueis_inf7225ffd83dbSDimitry Andric   bool isValue(const APFloat &C) { return C.isInfinity(); }
7235ffd83dbSDimitry Andric };
7245ffd83dbSDimitry Andric /// Match a positive or negative infinity FP constant.
7255ffd83dbSDimitry Andric /// For vectors, this includes constants with undefined elements.
m_Inf()72681ad6265SDimitry Andric inline cstfp_pred_ty<is_inf> m_Inf() { return cstfp_pred_ty<is_inf>(); }
7275ffd83dbSDimitry Andric 
728e8d8bef9SDimitry Andric struct is_noninf {
isValueis_noninf729e8d8bef9SDimitry Andric   bool isValue(const APFloat &C) { return !C.isInfinity(); }
730e8d8bef9SDimitry Andric };
731e8d8bef9SDimitry Andric /// Match a non-infinity FP constant, i.e. finite or NaN.
732e8d8bef9SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_NonInf()733e8d8bef9SDimitry Andric inline cstfp_pred_ty<is_noninf> m_NonInf() {
734e8d8bef9SDimitry Andric   return cstfp_pred_ty<is_noninf>();
735e8d8bef9SDimitry Andric }
736e8d8bef9SDimitry Andric 
737e8d8bef9SDimitry Andric struct is_finite {
isValueis_finite738e8d8bef9SDimitry Andric   bool isValue(const APFloat &C) { return C.isFinite(); }
739e8d8bef9SDimitry Andric };
740e8d8bef9SDimitry Andric /// Match a finite FP constant, i.e. not infinity or NaN.
741e8d8bef9SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_Finite()742e8d8bef9SDimitry Andric inline cstfp_pred_ty<is_finite> m_Finite() {
743e8d8bef9SDimitry Andric   return cstfp_pred_ty<is_finite>();
744e8d8bef9SDimitry Andric }
m_Finite(const APFloat * & V)745e8d8bef9SDimitry Andric inline apf_pred_ty<is_finite> m_Finite(const APFloat *&V) { return V; }
746e8d8bef9SDimitry Andric 
747e8d8bef9SDimitry Andric struct is_finitenonzero {
isValueis_finitenonzero748e8d8bef9SDimitry Andric   bool isValue(const APFloat &C) { return C.isFiniteNonZero(); }
749e8d8bef9SDimitry Andric };
750e8d8bef9SDimitry Andric /// Match a finite non-zero FP constant.
751e8d8bef9SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_FiniteNonZero()752e8d8bef9SDimitry Andric inline cstfp_pred_ty<is_finitenonzero> m_FiniteNonZero() {
753e8d8bef9SDimitry Andric   return cstfp_pred_ty<is_finitenonzero>();
754e8d8bef9SDimitry Andric }
m_FiniteNonZero(const APFloat * & V)755e8d8bef9SDimitry Andric inline apf_pred_ty<is_finitenonzero> m_FiniteNonZero(const APFloat *&V) {
756e8d8bef9SDimitry Andric   return V;
757e8d8bef9SDimitry Andric }
758e8d8bef9SDimitry Andric 
7590b57cec5SDimitry Andric struct is_any_zero_fp {
isValueis_any_zero_fp7600b57cec5SDimitry Andric   bool isValue(const APFloat &C) { return C.isZero(); }
7610b57cec5SDimitry Andric };
7620b57cec5SDimitry Andric /// Match a floating-point negative zero or positive zero.
7630b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_AnyZeroFP()7640b57cec5SDimitry Andric inline cstfp_pred_ty<is_any_zero_fp> m_AnyZeroFP() {
7650b57cec5SDimitry Andric   return cstfp_pred_ty<is_any_zero_fp>();
7660b57cec5SDimitry Andric }
7670b57cec5SDimitry Andric 
7680b57cec5SDimitry Andric struct is_pos_zero_fp {
isValueis_pos_zero_fp7690b57cec5SDimitry Andric   bool isValue(const APFloat &C) { return C.isPosZero(); }
7700b57cec5SDimitry Andric };
7710b57cec5SDimitry Andric /// Match a floating-point positive zero.
7720b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_PosZeroFP()7730b57cec5SDimitry Andric inline cstfp_pred_ty<is_pos_zero_fp> m_PosZeroFP() {
7740b57cec5SDimitry Andric   return cstfp_pred_ty<is_pos_zero_fp>();
7750b57cec5SDimitry Andric }
7760b57cec5SDimitry Andric 
7770b57cec5SDimitry Andric struct is_neg_zero_fp {
isValueis_neg_zero_fp7780b57cec5SDimitry Andric   bool isValue(const APFloat &C) { return C.isNegZero(); }
7790b57cec5SDimitry Andric };
7800b57cec5SDimitry Andric /// Match a floating-point negative zero.
7810b57cec5SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_NegZeroFP()7820b57cec5SDimitry Andric inline cstfp_pred_ty<is_neg_zero_fp> m_NegZeroFP() {
7830b57cec5SDimitry Andric   return cstfp_pred_ty<is_neg_zero_fp>();
7840b57cec5SDimitry Andric }
7850b57cec5SDimitry Andric 
786e8d8bef9SDimitry Andric struct is_non_zero_fp {
isValueis_non_zero_fp787e8d8bef9SDimitry Andric   bool isValue(const APFloat &C) { return C.isNonZero(); }
788e8d8bef9SDimitry Andric };
789e8d8bef9SDimitry Andric /// Match a floating-point non-zero.
790e8d8bef9SDimitry Andric /// For vectors, this includes constants with undefined elements.
m_NonZeroFP()791e8d8bef9SDimitry Andric inline cstfp_pred_ty<is_non_zero_fp> m_NonZeroFP() {
792e8d8bef9SDimitry Andric   return cstfp_pred_ty<is_non_zero_fp>();
793e8d8bef9SDimitry Andric }
794e8d8bef9SDimitry Andric 
7950b57cec5SDimitry Andric ///////////////////////////////////////////////////////////////////////////////
7960b57cec5SDimitry Andric 
7970b57cec5SDimitry Andric template <typename Class> struct bind_ty {
7980b57cec5SDimitry Andric   Class *&VR;
7990b57cec5SDimitry Andric 
bind_tybind_ty8000b57cec5SDimitry Andric   bind_ty(Class *&V) : VR(V) {}
8010b57cec5SDimitry Andric 
matchbind_ty8020b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *V) {
8030b57cec5SDimitry Andric     if (auto *CV = dyn_cast<Class>(V)) {
8040b57cec5SDimitry Andric       VR = CV;
8050b57cec5SDimitry Andric       return true;
8060b57cec5SDimitry Andric     }
8070b57cec5SDimitry Andric     return false;
8080b57cec5SDimitry Andric   }
8090b57cec5SDimitry Andric };
8100b57cec5SDimitry Andric 
8110b57cec5SDimitry Andric /// Match a value, capturing it if we match.
m_Value(Value * & V)8120b57cec5SDimitry Andric inline bind_ty<Value> m_Value(Value *&V) { return V; }
m_Value(const Value * & V)8130b57cec5SDimitry Andric inline bind_ty<const Value> m_Value(const Value *&V) { return V; }
8140b57cec5SDimitry Andric 
8150b57cec5SDimitry Andric /// Match an instruction, capturing it if we match.
m_Instruction(Instruction * & I)8160b57cec5SDimitry Andric inline bind_ty<Instruction> m_Instruction(Instruction *&I) { return I; }
8175ffd83dbSDimitry Andric /// Match a unary operator, capturing it if we match.
m_UnOp(UnaryOperator * & I)8185ffd83dbSDimitry Andric inline bind_ty<UnaryOperator> m_UnOp(UnaryOperator *&I) { return I; }
8190b57cec5SDimitry Andric /// Match a binary operator, capturing it if we match.
m_BinOp(BinaryOperator * & I)8200b57cec5SDimitry Andric inline bind_ty<BinaryOperator> m_BinOp(BinaryOperator *&I) { return I; }
821480093f4SDimitry Andric /// Match a with overflow intrinsic, capturing it if we match.
m_WithOverflowInst(WithOverflowInst * & I)82281ad6265SDimitry Andric inline bind_ty<WithOverflowInst> m_WithOverflowInst(WithOverflowInst *&I) {
82381ad6265SDimitry Andric   return I;
82481ad6265SDimitry Andric }
825fe6060f1SDimitry Andric inline bind_ty<const WithOverflowInst>
m_WithOverflowInst(const WithOverflowInst * & I)826fe6060f1SDimitry Andric m_WithOverflowInst(const WithOverflowInst *&I) {
827fe6060f1SDimitry Andric   return I;
828fe6060f1SDimitry Andric }
8290b57cec5SDimitry Andric 
830*0fca6ea1SDimitry Andric /// Match an UndefValue, capturing the value if we match.
m_UndefValue(UndefValue * & U)831*0fca6ea1SDimitry Andric inline bind_ty<UndefValue> m_UndefValue(UndefValue *&U) { return U; }
832*0fca6ea1SDimitry Andric 
8330b57cec5SDimitry Andric /// Match a Constant, capturing the value if we match.
m_Constant(Constant * & C)8340b57cec5SDimitry Andric inline bind_ty<Constant> m_Constant(Constant *&C) { return C; }
8350b57cec5SDimitry Andric 
836e8d8bef9SDimitry Andric /// Match a ConstantInt, capturing the value if we match.
m_ConstantInt(ConstantInt * & CI)837e8d8bef9SDimitry Andric inline bind_ty<ConstantInt> m_ConstantInt(ConstantInt *&CI) { return CI; }
838e8d8bef9SDimitry Andric 
8390b57cec5SDimitry Andric /// Match a ConstantFP, capturing the value if we match.
m_ConstantFP(ConstantFP * & C)8400b57cec5SDimitry Andric inline bind_ty<ConstantFP> m_ConstantFP(ConstantFP *&C) { return C; }
8410b57cec5SDimitry Andric 
842e8d8bef9SDimitry Andric /// Match a ConstantExpr, capturing the value if we match.
m_ConstantExpr(ConstantExpr * & C)843e8d8bef9SDimitry Andric inline bind_ty<ConstantExpr> m_ConstantExpr(ConstantExpr *&C) { return C; }
844e8d8bef9SDimitry Andric 
8458bcb0991SDimitry Andric /// Match a basic block value, capturing it if we match.
m_BasicBlock(BasicBlock * & V)8468bcb0991SDimitry Andric inline bind_ty<BasicBlock> m_BasicBlock(BasicBlock *&V) { return V; }
m_BasicBlock(const BasicBlock * & V)8478bcb0991SDimitry Andric inline bind_ty<const BasicBlock> m_BasicBlock(const BasicBlock *&V) {
8488bcb0991SDimitry Andric   return V;
8498bcb0991SDimitry Andric }
8508bcb0991SDimitry Andric 
851e8d8bef9SDimitry Andric /// Match an arbitrary immediate Constant and ignore it.
852e8d8bef9SDimitry Andric inline match_combine_and<class_match<Constant>,
853fcaf7f86SDimitry Andric                          match_unless<constantexpr_match>>
m_ImmConstant()854e8d8bef9SDimitry Andric m_ImmConstant() {
855e8d8bef9SDimitry Andric   return m_CombineAnd(m_Constant(), m_Unless(m_ConstantExpr()));
856e8d8bef9SDimitry Andric }
857e8d8bef9SDimitry Andric 
858e8d8bef9SDimitry Andric /// Match an immediate Constant, capturing the value if we match.
859e8d8bef9SDimitry Andric inline match_combine_and<bind_ty<Constant>,
860fcaf7f86SDimitry Andric                          match_unless<constantexpr_match>>
m_ImmConstant(Constant * & C)861e8d8bef9SDimitry Andric m_ImmConstant(Constant *&C) {
862e8d8bef9SDimitry Andric   return m_CombineAnd(m_Constant(C), m_Unless(m_ConstantExpr()));
863e8d8bef9SDimitry Andric }
864e8d8bef9SDimitry Andric 
8650b57cec5SDimitry Andric /// Match a specified Value*.
8660b57cec5SDimitry Andric struct specificval_ty {
8670b57cec5SDimitry Andric   const Value *Val;
8680b57cec5SDimitry Andric 
specificval_tyspecificval_ty8690b57cec5SDimitry Andric   specificval_ty(const Value *V) : Val(V) {}
8700b57cec5SDimitry Andric 
matchspecificval_ty8710b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *V) { return V == Val; }
8720b57cec5SDimitry Andric };
8730b57cec5SDimitry Andric 
8740b57cec5SDimitry Andric /// Match if we have a specific specified value.
m_Specific(const Value * V)8750b57cec5SDimitry Andric inline specificval_ty m_Specific(const Value *V) { return V; }
8760b57cec5SDimitry Andric 
8770b57cec5SDimitry Andric /// Stores a reference to the Value *, not the Value * itself,
8780b57cec5SDimitry Andric /// thus can be used in commutative matchers.
8790b57cec5SDimitry Andric template <typename Class> struct deferredval_ty {
8800b57cec5SDimitry Andric   Class *const &Val;
8810b57cec5SDimitry Andric 
deferredval_tydeferredval_ty8820b57cec5SDimitry Andric   deferredval_ty(Class *const &V) : Val(V) {}
8830b57cec5SDimitry Andric 
matchdeferredval_ty8840b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *const V) { return V == Val; }
8850b57cec5SDimitry Andric };
8860b57cec5SDimitry Andric 
887fe6060f1SDimitry Andric /// Like m_Specific(), but works if the specific value to match is determined
888fe6060f1SDimitry Andric /// as part of the same match() expression. For example:
889fe6060f1SDimitry Andric /// m_Add(m_Value(X), m_Specific(X)) is incorrect, because m_Specific() will
890fe6060f1SDimitry Andric /// bind X before the pattern match starts.
891fe6060f1SDimitry Andric /// m_Add(m_Value(X), m_Deferred(X)) is correct, and will check against
892fe6060f1SDimitry Andric /// whichever value m_Value(X) populated.
m_Deferred(Value * const & V)8930b57cec5SDimitry Andric inline deferredval_ty<Value> m_Deferred(Value *const &V) { return V; }
m_Deferred(const Value * const & V)8940b57cec5SDimitry Andric inline deferredval_ty<const Value> m_Deferred(const Value *const &V) {
8950b57cec5SDimitry Andric   return V;
8960b57cec5SDimitry Andric }
8970b57cec5SDimitry Andric 
8980b57cec5SDimitry Andric /// Match a specified floating point value or vector of all elements of
8990b57cec5SDimitry Andric /// that value.
9000b57cec5SDimitry Andric struct specific_fpval {
9010b57cec5SDimitry Andric   double Val;
9020b57cec5SDimitry Andric 
specific_fpvalspecific_fpval9030b57cec5SDimitry Andric   specific_fpval(double V) : Val(V) {}
9040b57cec5SDimitry Andric 
matchspecific_fpval9050b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *V) {
9060b57cec5SDimitry Andric     if (const auto *CFP = dyn_cast<ConstantFP>(V))
9070b57cec5SDimitry Andric       return CFP->isExactlyValue(Val);
9080b57cec5SDimitry Andric     if (V->getType()->isVectorTy())
9090b57cec5SDimitry Andric       if (const auto *C = dyn_cast<Constant>(V))
9100b57cec5SDimitry Andric         if (auto *CFP = dyn_cast_or_null<ConstantFP>(C->getSplatValue()))
9110b57cec5SDimitry Andric           return CFP->isExactlyValue(Val);
9120b57cec5SDimitry Andric     return false;
9130b57cec5SDimitry Andric   }
9140b57cec5SDimitry Andric };
9150b57cec5SDimitry Andric 
9160b57cec5SDimitry Andric /// Match a specific floating point value or vector with all elements
9170b57cec5SDimitry Andric /// equal to the value.
m_SpecificFP(double V)9180b57cec5SDimitry Andric inline specific_fpval m_SpecificFP(double V) { return specific_fpval(V); }
9190b57cec5SDimitry Andric 
9200b57cec5SDimitry Andric /// Match a float 1.0 or vector with all elements equal to 1.0.
m_FPOne()9210b57cec5SDimitry Andric inline specific_fpval m_FPOne() { return m_SpecificFP(1.0); }
9220b57cec5SDimitry Andric 
9230b57cec5SDimitry Andric struct bind_const_intval_ty {
9240b57cec5SDimitry Andric   uint64_t &VR;
9250b57cec5SDimitry Andric 
bind_const_intval_tybind_const_intval_ty9260b57cec5SDimitry Andric   bind_const_intval_ty(uint64_t &V) : VR(V) {}
9270b57cec5SDimitry Andric 
matchbind_const_intval_ty9280b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *V) {
9290b57cec5SDimitry Andric     if (const auto *CV = dyn_cast<ConstantInt>(V))
9300b57cec5SDimitry Andric       if (CV->getValue().ule(UINT64_MAX)) {
9310b57cec5SDimitry Andric         VR = CV->getZExtValue();
9320b57cec5SDimitry Andric         return true;
9330b57cec5SDimitry Andric       }
9340b57cec5SDimitry Andric     return false;
9350b57cec5SDimitry Andric   }
9360b57cec5SDimitry Andric };
9370b57cec5SDimitry Andric 
9380b57cec5SDimitry Andric /// Match a specified integer value or vector of all elements of that
9398bcb0991SDimitry Andric /// value.
940*0fca6ea1SDimitry Andric template <bool AllowPoison> struct specific_intval {
941*0fca6ea1SDimitry Andric   const APInt &Val;
9420b57cec5SDimitry Andric 
specific_intvalspecific_intval943*0fca6ea1SDimitry Andric   specific_intval(const APInt &V) : Val(V) {}
9440b57cec5SDimitry Andric 
matchspecific_intval9450b57cec5SDimitry Andric   template <typename ITy> bool match(ITy *V) {
9460b57cec5SDimitry Andric     const auto *CI = dyn_cast<ConstantInt>(V);
9470b57cec5SDimitry Andric     if (!CI && V->getType()->isVectorTy())
9480b57cec5SDimitry Andric       if (const auto *C = dyn_cast<Constant>(V))
949*0fca6ea1SDimitry Andric         CI = dyn_cast_or_null<ConstantInt>(C->getSplatValue(AllowPoison));
9500b57cec5SDimitry Andric 
9518bcb0991SDimitry Andric     return CI && APInt::isSameValue(CI->getValue(), Val);
9520b57cec5SDimitry Andric   }
9530b57cec5SDimitry Andric };
9540b57cec5SDimitry Andric 
955*0fca6ea1SDimitry Andric template <bool AllowPoison> struct specific_intval64 {
956*0fca6ea1SDimitry Andric   uint64_t Val;
957*0fca6ea1SDimitry Andric 
specific_intval64specific_intval64958*0fca6ea1SDimitry Andric   specific_intval64(uint64_t V) : Val(V) {}
959*0fca6ea1SDimitry Andric 
matchspecific_intval64960*0fca6ea1SDimitry Andric   template <typename ITy> bool match(ITy *V) {
961*0fca6ea1SDimitry Andric     const auto *CI = dyn_cast<ConstantInt>(V);
962*0fca6ea1SDimitry Andric     if (!CI && V->getType()->isVectorTy())
963*0fca6ea1SDimitry Andric       if (const auto *C = dyn_cast<Constant>(V))
964*0fca6ea1SDimitry Andric         CI = dyn_cast_or_null<ConstantInt>(C->getSplatValue(AllowPoison));
965*0fca6ea1SDimitry Andric 
966*0fca6ea1SDimitry Andric     return CI && CI->getValue() == Val;
967*0fca6ea1SDimitry Andric   }
968*0fca6ea1SDimitry Andric };
969*0fca6ea1SDimitry Andric 
9700b57cec5SDimitry Andric /// Match a specific integer value or vector with all elements equal to
9710b57cec5SDimitry Andric /// the value.
m_SpecificInt(const APInt & V)972*0fca6ea1SDimitry Andric inline specific_intval<false> m_SpecificInt(const APInt &V) {
973*0fca6ea1SDimitry Andric   return specific_intval<false>(V);
9748bcb0991SDimitry Andric }
9758bcb0991SDimitry Andric 
m_SpecificInt(uint64_t V)976*0fca6ea1SDimitry Andric inline specific_intval64<false> m_SpecificInt(uint64_t V) {
977*0fca6ea1SDimitry Andric   return specific_intval64<false>(V);
9788bcb0991SDimitry Andric }
9790b57cec5SDimitry Andric 
m_SpecificIntAllowPoison(const APInt & V)980*0fca6ea1SDimitry Andric inline specific_intval<true> m_SpecificIntAllowPoison(const APInt &V) {
981*0fca6ea1SDimitry Andric   return specific_intval<true>(V);
982e8d8bef9SDimitry Andric }
983e8d8bef9SDimitry Andric 
m_SpecificIntAllowPoison(uint64_t V)984*0fca6ea1SDimitry Andric inline specific_intval64<true> m_SpecificIntAllowPoison(uint64_t V) {
985*0fca6ea1SDimitry Andric   return specific_intval64<true>(V);
986e8d8bef9SDimitry Andric }
987e8d8bef9SDimitry Andric 
9880b57cec5SDimitry Andric /// Match a ConstantInt and bind to its value.  This does not match
9890b57cec5SDimitry Andric /// ConstantInts wider than 64-bits.
m_ConstantInt(uint64_t & V)9900b57cec5SDimitry Andric inline bind_const_intval_ty m_ConstantInt(uint64_t &V) { return V; }
9910b57cec5SDimitry Andric 
9928bcb0991SDimitry Andric /// Match a specified basic block value.
9938bcb0991SDimitry Andric struct specific_bbval {
9948bcb0991SDimitry Andric   BasicBlock *Val;
9958bcb0991SDimitry Andric 
specific_bbvalspecific_bbval9968bcb0991SDimitry Andric   specific_bbval(BasicBlock *Val) : Val(Val) {}
9978bcb0991SDimitry Andric 
matchspecific_bbval9988bcb0991SDimitry Andric   template <typename ITy> bool match(ITy *V) {
9998bcb0991SDimitry Andric     const auto *BB = dyn_cast<BasicBlock>(V);
10008bcb0991SDimitry Andric     return BB && BB == Val;
10018bcb0991SDimitry Andric   }
10028bcb0991SDimitry Andric };
10038bcb0991SDimitry Andric 
10048bcb0991SDimitry Andric /// Match a specific basic block value.
m_SpecificBB(BasicBlock * BB)10058bcb0991SDimitry Andric inline specific_bbval m_SpecificBB(BasicBlock *BB) {
10068bcb0991SDimitry Andric   return specific_bbval(BB);
10078bcb0991SDimitry Andric }
10088bcb0991SDimitry Andric 
10098bcb0991SDimitry Andric /// A commutative-friendly version of m_Specific().
m_Deferred(BasicBlock * const & BB)10108bcb0991SDimitry Andric inline deferredval_ty<BasicBlock> m_Deferred(BasicBlock *const &BB) {
10118bcb0991SDimitry Andric   return BB;
10128bcb0991SDimitry Andric }
10138bcb0991SDimitry Andric inline deferredval_ty<const BasicBlock>
m_Deferred(const BasicBlock * const & BB)10148bcb0991SDimitry Andric m_Deferred(const BasicBlock *const &BB) {
10158bcb0991SDimitry Andric   return BB;
10168bcb0991SDimitry Andric }
10178bcb0991SDimitry Andric 
10180b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
10190b57cec5SDimitry Andric // Matcher for any binary operator.
10200b57cec5SDimitry Andric //
10210b57cec5SDimitry Andric template <typename LHS_t, typename RHS_t, bool Commutable = false>
10220b57cec5SDimitry Andric struct AnyBinaryOp_match {
10230b57cec5SDimitry Andric   LHS_t L;
10240b57cec5SDimitry Andric   RHS_t R;
10250b57cec5SDimitry Andric 
10260b57cec5SDimitry Andric   // The evaluation order is always stable, regardless of Commutability.
10270b57cec5SDimitry Andric   // The LHS is always matched first.
AnyBinaryOp_matchAnyBinaryOp_match10280b57cec5SDimitry Andric   AnyBinaryOp_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {}
10290b57cec5SDimitry Andric 
matchAnyBinaryOp_match10300b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
10310b57cec5SDimitry Andric     if (auto *I = dyn_cast<BinaryOperator>(V))
10320b57cec5SDimitry Andric       return (L.match(I->getOperand(0)) && R.match(I->getOperand(1))) ||
10330b57cec5SDimitry Andric              (Commutable && L.match(I->getOperand(1)) &&
10340b57cec5SDimitry Andric               R.match(I->getOperand(0)));
10350b57cec5SDimitry Andric     return false;
10360b57cec5SDimitry Andric   }
10370b57cec5SDimitry Andric };
10380b57cec5SDimitry Andric 
10390b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_BinOp(const LHS & L,const RHS & R)10400b57cec5SDimitry Andric inline AnyBinaryOp_match<LHS, RHS> m_BinOp(const LHS &L, const RHS &R) {
10410b57cec5SDimitry Andric   return AnyBinaryOp_match<LHS, RHS>(L, R);
10420b57cec5SDimitry Andric }
10430b57cec5SDimitry Andric 
10440b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
10455ffd83dbSDimitry Andric // Matcher for any unary operator.
10465ffd83dbSDimitry Andric // TODO fuse unary, binary matcher into n-ary matcher
10475ffd83dbSDimitry Andric //
10485ffd83dbSDimitry Andric template <typename OP_t> struct AnyUnaryOp_match {
10495ffd83dbSDimitry Andric   OP_t X;
10505ffd83dbSDimitry Andric 
AnyUnaryOp_matchAnyUnaryOp_match10515ffd83dbSDimitry Andric   AnyUnaryOp_match(const OP_t &X) : X(X) {}
10525ffd83dbSDimitry Andric 
matchAnyUnaryOp_match10535ffd83dbSDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
10545ffd83dbSDimitry Andric     if (auto *I = dyn_cast<UnaryOperator>(V))
10555ffd83dbSDimitry Andric       return X.match(I->getOperand(0));
10565ffd83dbSDimitry Andric     return false;
10575ffd83dbSDimitry Andric   }
10585ffd83dbSDimitry Andric };
10595ffd83dbSDimitry Andric 
m_UnOp(const OP_t & X)10605ffd83dbSDimitry Andric template <typename OP_t> inline AnyUnaryOp_match<OP_t> m_UnOp(const OP_t &X) {
10615ffd83dbSDimitry Andric   return AnyUnaryOp_match<OP_t>(X);
10625ffd83dbSDimitry Andric }
10635ffd83dbSDimitry Andric 
10645ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
10650b57cec5SDimitry Andric // Matchers for specific binary operators.
10660b57cec5SDimitry Andric //
10670b57cec5SDimitry Andric 
10680b57cec5SDimitry Andric template <typename LHS_t, typename RHS_t, unsigned Opcode,
10690b57cec5SDimitry Andric           bool Commutable = false>
10700b57cec5SDimitry Andric struct BinaryOp_match {
10710b57cec5SDimitry Andric   LHS_t L;
10720b57cec5SDimitry Andric   RHS_t R;
10730b57cec5SDimitry Andric 
10740b57cec5SDimitry Andric   // The evaluation order is always stable, regardless of Commutability.
10750b57cec5SDimitry Andric   // The LHS is always matched first.
BinaryOp_matchBinaryOp_match10760b57cec5SDimitry Andric   BinaryOp_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {}
10770b57cec5SDimitry Andric 
matchBinaryOp_match1078349cc55cSDimitry Andric   template <typename OpTy> inline bool match(unsigned Opc, OpTy *V) {
1079349cc55cSDimitry Andric     if (V->getValueID() == Value::InstructionVal + Opc) {
10800b57cec5SDimitry Andric       auto *I = cast<BinaryOperator>(V);
10810b57cec5SDimitry Andric       return (L.match(I->getOperand(0)) && R.match(I->getOperand(1))) ||
10820b57cec5SDimitry Andric              (Commutable && L.match(I->getOperand(1)) &&
10830b57cec5SDimitry Andric               R.match(I->getOperand(0)));
10840b57cec5SDimitry Andric     }
10850b57cec5SDimitry Andric     return false;
10860b57cec5SDimitry Andric   }
1087349cc55cSDimitry Andric 
matchBinaryOp_match1088349cc55cSDimitry Andric   template <typename OpTy> bool match(OpTy *V) { return match(Opcode, V); }
10890b57cec5SDimitry Andric };
10900b57cec5SDimitry Andric 
10910b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_Add(const LHS & L,const RHS & R)10920b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::Add> m_Add(const LHS &L,
10930b57cec5SDimitry Andric                                                         const RHS &R) {
10940b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::Add>(L, R);
10950b57cec5SDimitry Andric }
10960b57cec5SDimitry Andric 
10970b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_FAdd(const LHS & L,const RHS & R)10980b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::FAdd> m_FAdd(const LHS &L,
10990b57cec5SDimitry Andric                                                           const RHS &R) {
11000b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::FAdd>(L, R);
11010b57cec5SDimitry Andric }
11020b57cec5SDimitry Andric 
11030b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_Sub(const LHS & L,const RHS & R)11040b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::Sub> m_Sub(const LHS &L,
11050b57cec5SDimitry Andric                                                         const RHS &R) {
11060b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::Sub>(L, R);
11070b57cec5SDimitry Andric }
11080b57cec5SDimitry Andric 
11090b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_FSub(const LHS & L,const RHS & R)11100b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::FSub> m_FSub(const LHS &L,
11110b57cec5SDimitry Andric                                                           const RHS &R) {
11120b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::FSub>(L, R);
11130b57cec5SDimitry Andric }
11140b57cec5SDimitry Andric 
11150b57cec5SDimitry Andric template <typename Op_t> struct FNeg_match {
11160b57cec5SDimitry Andric   Op_t X;
11170b57cec5SDimitry Andric 
FNeg_matchFNeg_match11180b57cec5SDimitry Andric   FNeg_match(const Op_t &Op) : X(Op) {}
matchFNeg_match11190b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
11200b57cec5SDimitry Andric     auto *FPMO = dyn_cast<FPMathOperator>(V);
112181ad6265SDimitry Andric     if (!FPMO)
112281ad6265SDimitry Andric       return false;
11230b57cec5SDimitry Andric 
11240b57cec5SDimitry Andric     if (FPMO->getOpcode() == Instruction::FNeg)
11250b57cec5SDimitry Andric       return X.match(FPMO->getOperand(0));
11260b57cec5SDimitry Andric 
11270b57cec5SDimitry Andric     if (FPMO->getOpcode() == Instruction::FSub) {
11280b57cec5SDimitry Andric       if (FPMO->hasNoSignedZeros()) {
11290b57cec5SDimitry Andric         // With 'nsz', any zero goes.
11300b57cec5SDimitry Andric         if (!cstfp_pred_ty<is_any_zero_fp>().match(FPMO->getOperand(0)))
11310b57cec5SDimitry Andric           return false;
11320b57cec5SDimitry Andric       } else {
11330b57cec5SDimitry Andric         // Without 'nsz', we need fsub -0.0, X exactly.
11340b57cec5SDimitry Andric         if (!cstfp_pred_ty<is_neg_zero_fp>().match(FPMO->getOperand(0)))
11350b57cec5SDimitry Andric           return false;
11360b57cec5SDimitry Andric       }
11370b57cec5SDimitry Andric 
11380b57cec5SDimitry Andric       return X.match(FPMO->getOperand(1));
11390b57cec5SDimitry Andric     }
11400b57cec5SDimitry Andric 
11410b57cec5SDimitry Andric     return false;
11420b57cec5SDimitry Andric   }
11430b57cec5SDimitry Andric };
11440b57cec5SDimitry Andric 
11450b57cec5SDimitry Andric /// Match 'fneg X' as 'fsub -0.0, X'.
m_FNeg(const OpTy & X)114681ad6265SDimitry Andric template <typename OpTy> inline FNeg_match<OpTy> m_FNeg(const OpTy &X) {
11470b57cec5SDimitry Andric   return FNeg_match<OpTy>(X);
11480b57cec5SDimitry Andric }
11490b57cec5SDimitry Andric 
11500b57cec5SDimitry Andric /// Match 'fneg X' as 'fsub +-0.0, X'.
11510b57cec5SDimitry Andric template <typename RHS>
11520b57cec5SDimitry Andric inline BinaryOp_match<cstfp_pred_ty<is_any_zero_fp>, RHS, Instruction::FSub>
m_FNegNSZ(const RHS & X)11530b57cec5SDimitry Andric m_FNegNSZ(const RHS &X) {
11540b57cec5SDimitry Andric   return m_FSub(m_AnyZeroFP(), X);
11550b57cec5SDimitry Andric }
11560b57cec5SDimitry Andric 
11570b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_Mul(const LHS & L,const RHS & R)11580b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::Mul> m_Mul(const LHS &L,
11590b57cec5SDimitry Andric                                                         const RHS &R) {
11600b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::Mul>(L, R);
11610b57cec5SDimitry Andric }
11620b57cec5SDimitry Andric 
11630b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_FMul(const LHS & L,const RHS & R)11640b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::FMul> m_FMul(const LHS &L,
11650b57cec5SDimitry Andric                                                           const RHS &R) {
11660b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::FMul>(L, R);
11670b57cec5SDimitry Andric }
11680b57cec5SDimitry Andric 
11690b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_UDiv(const LHS & L,const RHS & R)11700b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::UDiv> m_UDiv(const LHS &L,
11710b57cec5SDimitry Andric                                                           const RHS &R) {
11720b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::UDiv>(L, R);
11730b57cec5SDimitry Andric }
11740b57cec5SDimitry Andric 
11750b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_SDiv(const LHS & L,const RHS & R)11760b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::SDiv> m_SDiv(const LHS &L,
11770b57cec5SDimitry Andric                                                           const RHS &R) {
11780b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::SDiv>(L, R);
11790b57cec5SDimitry Andric }
11800b57cec5SDimitry Andric 
11810b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_FDiv(const LHS & L,const RHS & R)11820b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::FDiv> m_FDiv(const LHS &L,
11830b57cec5SDimitry Andric                                                           const RHS &R) {
11840b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::FDiv>(L, R);
11850b57cec5SDimitry Andric }
11860b57cec5SDimitry Andric 
11870b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_URem(const LHS & L,const RHS & R)11880b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::URem> m_URem(const LHS &L,
11890b57cec5SDimitry Andric                                                           const RHS &R) {
11900b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::URem>(L, R);
11910b57cec5SDimitry Andric }
11920b57cec5SDimitry Andric 
11930b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_SRem(const LHS & L,const RHS & R)11940b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::SRem> m_SRem(const LHS &L,
11950b57cec5SDimitry Andric                                                           const RHS &R) {
11960b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::SRem>(L, R);
11970b57cec5SDimitry Andric }
11980b57cec5SDimitry Andric 
11990b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_FRem(const LHS & L,const RHS & R)12000b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::FRem> m_FRem(const LHS &L,
12010b57cec5SDimitry Andric                                                           const RHS &R) {
12020b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::FRem>(L, R);
12030b57cec5SDimitry Andric }
12040b57cec5SDimitry Andric 
12050b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_And(const LHS & L,const RHS & R)12060b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::And> m_And(const LHS &L,
12070b57cec5SDimitry Andric                                                         const RHS &R) {
12080b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::And>(L, R);
12090b57cec5SDimitry Andric }
12100b57cec5SDimitry Andric 
12110b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_Or(const LHS & L,const RHS & R)12120b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::Or> m_Or(const LHS &L,
12130b57cec5SDimitry Andric                                                       const RHS &R) {
12140b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::Or>(L, R);
12150b57cec5SDimitry Andric }
12160b57cec5SDimitry Andric 
12170b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_Xor(const LHS & L,const RHS & R)12180b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::Xor> m_Xor(const LHS &L,
12190b57cec5SDimitry Andric                                                         const RHS &R) {
12200b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::Xor>(L, R);
12210b57cec5SDimitry Andric }
12220b57cec5SDimitry Andric 
12230b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_Shl(const LHS & L,const RHS & R)12240b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::Shl> m_Shl(const LHS &L,
12250b57cec5SDimitry Andric                                                         const RHS &R) {
12260b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::Shl>(L, R);
12270b57cec5SDimitry Andric }
12280b57cec5SDimitry Andric 
12290b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_LShr(const LHS & L,const RHS & R)12300b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::LShr> m_LShr(const LHS &L,
12310b57cec5SDimitry Andric                                                           const RHS &R) {
12320b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::LShr>(L, R);
12330b57cec5SDimitry Andric }
12340b57cec5SDimitry Andric 
12350b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_AShr(const LHS & L,const RHS & R)12360b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::AShr> m_AShr(const LHS &L,
12370b57cec5SDimitry Andric                                                           const RHS &R) {
12380b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::AShr>(L, R);
12390b57cec5SDimitry Andric }
12400b57cec5SDimitry Andric 
12410b57cec5SDimitry Andric template <typename LHS_t, typename RHS_t, unsigned Opcode,
1242*0fca6ea1SDimitry Andric           unsigned WrapFlags = 0, bool Commutable = false>
12430b57cec5SDimitry Andric struct OverflowingBinaryOp_match {
12440b57cec5SDimitry Andric   LHS_t L;
12450b57cec5SDimitry Andric   RHS_t R;
12460b57cec5SDimitry Andric 
OverflowingBinaryOp_matchOverflowingBinaryOp_match12470b57cec5SDimitry Andric   OverflowingBinaryOp_match(const LHS_t &LHS, const RHS_t &RHS)
12480b57cec5SDimitry Andric       : L(LHS), R(RHS) {}
12490b57cec5SDimitry Andric 
matchOverflowingBinaryOp_match12500b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
12510b57cec5SDimitry Andric     if (auto *Op = dyn_cast<OverflowingBinaryOperator>(V)) {
12520b57cec5SDimitry Andric       if (Op->getOpcode() != Opcode)
12530b57cec5SDimitry Andric         return false;
1254fe6060f1SDimitry Andric       if ((WrapFlags & OverflowingBinaryOperator::NoUnsignedWrap) &&
12550b57cec5SDimitry Andric           !Op->hasNoUnsignedWrap())
12560b57cec5SDimitry Andric         return false;
1257fe6060f1SDimitry Andric       if ((WrapFlags & OverflowingBinaryOperator::NoSignedWrap) &&
12580b57cec5SDimitry Andric           !Op->hasNoSignedWrap())
12590b57cec5SDimitry Andric         return false;
1260*0fca6ea1SDimitry Andric       return (L.match(Op->getOperand(0)) && R.match(Op->getOperand(1))) ||
1261*0fca6ea1SDimitry Andric              (Commutable && L.match(Op->getOperand(1)) &&
1262*0fca6ea1SDimitry Andric               R.match(Op->getOperand(0)));
12630b57cec5SDimitry Andric     }
12640b57cec5SDimitry Andric     return false;
12650b57cec5SDimitry Andric   }
12660b57cec5SDimitry Andric };
12670b57cec5SDimitry Andric 
12680b57cec5SDimitry Andric template <typename LHS, typename RHS>
12690b57cec5SDimitry Andric inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
12700b57cec5SDimitry Andric                                  OverflowingBinaryOperator::NoSignedWrap>
m_NSWAdd(const LHS & L,const RHS & R)12710b57cec5SDimitry Andric m_NSWAdd(const LHS &L, const RHS &R) {
12720b57cec5SDimitry Andric   return OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
127381ad6265SDimitry Andric                                    OverflowingBinaryOperator::NoSignedWrap>(L,
127481ad6265SDimitry Andric                                                                             R);
12750b57cec5SDimitry Andric }
12760b57cec5SDimitry Andric template <typename LHS, typename RHS>
12770b57cec5SDimitry Andric inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Sub,
12780b57cec5SDimitry Andric                                  OverflowingBinaryOperator::NoSignedWrap>
m_NSWSub(const LHS & L,const RHS & R)12790b57cec5SDimitry Andric m_NSWSub(const LHS &L, const RHS &R) {
12800b57cec5SDimitry Andric   return OverflowingBinaryOp_match<LHS, RHS, Instruction::Sub,
128181ad6265SDimitry Andric                                    OverflowingBinaryOperator::NoSignedWrap>(L,
128281ad6265SDimitry Andric                                                                             R);
12830b57cec5SDimitry Andric }
12840b57cec5SDimitry Andric template <typename LHS, typename RHS>
12850b57cec5SDimitry Andric inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Mul,
12860b57cec5SDimitry Andric                                  OverflowingBinaryOperator::NoSignedWrap>
m_NSWMul(const LHS & L,const RHS & R)12870b57cec5SDimitry Andric m_NSWMul(const LHS &L, const RHS &R) {
12880b57cec5SDimitry Andric   return OverflowingBinaryOp_match<LHS, RHS, Instruction::Mul,
128981ad6265SDimitry Andric                                    OverflowingBinaryOperator::NoSignedWrap>(L,
129081ad6265SDimitry Andric                                                                             R);
12910b57cec5SDimitry Andric }
12920b57cec5SDimitry Andric template <typename LHS, typename RHS>
12930b57cec5SDimitry Andric inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Shl,
12940b57cec5SDimitry Andric                                  OverflowingBinaryOperator::NoSignedWrap>
m_NSWShl(const LHS & L,const RHS & R)12950b57cec5SDimitry Andric m_NSWShl(const LHS &L, const RHS &R) {
12960b57cec5SDimitry Andric   return OverflowingBinaryOp_match<LHS, RHS, Instruction::Shl,
129781ad6265SDimitry Andric                                    OverflowingBinaryOperator::NoSignedWrap>(L,
129881ad6265SDimitry Andric                                                                             R);
12990b57cec5SDimitry Andric }
13000b57cec5SDimitry Andric 
13010b57cec5SDimitry Andric template <typename LHS, typename RHS>
13020b57cec5SDimitry Andric inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
13030b57cec5SDimitry Andric                                  OverflowingBinaryOperator::NoUnsignedWrap>
m_NUWAdd(const LHS & L,const RHS & R)13040b57cec5SDimitry Andric m_NUWAdd(const LHS &L, const RHS &R) {
13050b57cec5SDimitry Andric   return OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
13060b57cec5SDimitry Andric                                    OverflowingBinaryOperator::NoUnsignedWrap>(
13070b57cec5SDimitry Andric       L, R);
13080b57cec5SDimitry Andric }
1309*0fca6ea1SDimitry Andric 
1310*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
1311*0fca6ea1SDimitry Andric inline OverflowingBinaryOp_match<
1312*0fca6ea1SDimitry Andric     LHS, RHS, Instruction::Add, OverflowingBinaryOperator::NoUnsignedWrap, true>
m_c_NUWAdd(const LHS & L,const RHS & R)1313*0fca6ea1SDimitry Andric m_c_NUWAdd(const LHS &L, const RHS &R) {
1314*0fca6ea1SDimitry Andric   return OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
1315*0fca6ea1SDimitry Andric                                    OverflowingBinaryOperator::NoUnsignedWrap,
1316*0fca6ea1SDimitry Andric                                    true>(L, R);
1317*0fca6ea1SDimitry Andric }
1318*0fca6ea1SDimitry Andric 
13190b57cec5SDimitry Andric template <typename LHS, typename RHS>
13200b57cec5SDimitry Andric inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Sub,
13210b57cec5SDimitry Andric                                  OverflowingBinaryOperator::NoUnsignedWrap>
m_NUWSub(const LHS & L,const RHS & R)13220b57cec5SDimitry Andric m_NUWSub(const LHS &L, const RHS &R) {
13230b57cec5SDimitry Andric   return OverflowingBinaryOp_match<LHS, RHS, Instruction::Sub,
13240b57cec5SDimitry Andric                                    OverflowingBinaryOperator::NoUnsignedWrap>(
13250b57cec5SDimitry Andric       L, R);
13260b57cec5SDimitry Andric }
13270b57cec5SDimitry Andric template <typename LHS, typename RHS>
13280b57cec5SDimitry Andric inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Mul,
13290b57cec5SDimitry Andric                                  OverflowingBinaryOperator::NoUnsignedWrap>
m_NUWMul(const LHS & L,const RHS & R)13300b57cec5SDimitry Andric m_NUWMul(const LHS &L, const RHS &R) {
13310b57cec5SDimitry Andric   return OverflowingBinaryOp_match<LHS, RHS, Instruction::Mul,
13320b57cec5SDimitry Andric                                    OverflowingBinaryOperator::NoUnsignedWrap>(
13330b57cec5SDimitry Andric       L, R);
13340b57cec5SDimitry Andric }
13350b57cec5SDimitry Andric template <typename LHS, typename RHS>
13360b57cec5SDimitry Andric inline OverflowingBinaryOp_match<LHS, RHS, Instruction::Shl,
13370b57cec5SDimitry Andric                                  OverflowingBinaryOperator::NoUnsignedWrap>
m_NUWShl(const LHS & L,const RHS & R)13380b57cec5SDimitry Andric m_NUWShl(const LHS &L, const RHS &R) {
13390b57cec5SDimitry Andric   return OverflowingBinaryOp_match<LHS, RHS, Instruction::Shl,
13400b57cec5SDimitry Andric                                    OverflowingBinaryOperator::NoUnsignedWrap>(
13410b57cec5SDimitry Andric       L, R);
13420b57cec5SDimitry Andric }
13430b57cec5SDimitry Andric 
1344349cc55cSDimitry Andric template <typename LHS_t, typename RHS_t, bool Commutable = false>
1345349cc55cSDimitry Andric struct SpecificBinaryOp_match
1346349cc55cSDimitry Andric     : public BinaryOp_match<LHS_t, RHS_t, 0, Commutable> {
1347349cc55cSDimitry Andric   unsigned Opcode;
1348349cc55cSDimitry Andric 
SpecificBinaryOp_matchSpecificBinaryOp_match1349349cc55cSDimitry Andric   SpecificBinaryOp_match(unsigned Opcode, const LHS_t &LHS, const RHS_t &RHS)
1350349cc55cSDimitry Andric       : BinaryOp_match<LHS_t, RHS_t, 0, Commutable>(LHS, RHS), Opcode(Opcode) {}
1351349cc55cSDimitry Andric 
matchSpecificBinaryOp_match1352349cc55cSDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
1353349cc55cSDimitry Andric     return BinaryOp_match<LHS_t, RHS_t, 0, Commutable>::match(Opcode, V);
1354349cc55cSDimitry Andric   }
1355349cc55cSDimitry Andric };
1356349cc55cSDimitry Andric 
1357349cc55cSDimitry Andric /// Matches a specific opcode.
1358349cc55cSDimitry Andric template <typename LHS, typename RHS>
m_BinOp(unsigned Opcode,const LHS & L,const RHS & R)1359349cc55cSDimitry Andric inline SpecificBinaryOp_match<LHS, RHS> m_BinOp(unsigned Opcode, const LHS &L,
1360349cc55cSDimitry Andric                                                 const RHS &R) {
1361349cc55cSDimitry Andric   return SpecificBinaryOp_match<LHS, RHS>(Opcode, L, R);
1362349cc55cSDimitry Andric }
1363349cc55cSDimitry Andric 
13645f757f3fSDimitry Andric template <typename LHS, typename RHS, bool Commutable = false>
13655f757f3fSDimitry Andric struct DisjointOr_match {
13665f757f3fSDimitry Andric   LHS L;
13675f757f3fSDimitry Andric   RHS R;
13685f757f3fSDimitry Andric 
DisjointOr_matchDisjointOr_match13695f757f3fSDimitry Andric   DisjointOr_match(const LHS &L, const RHS &R) : L(L), R(R) {}
13705f757f3fSDimitry Andric 
matchDisjointOr_match13715f757f3fSDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
13725f757f3fSDimitry Andric     if (auto *PDI = dyn_cast<PossiblyDisjointInst>(V)) {
13735f757f3fSDimitry Andric       assert(PDI->getOpcode() == Instruction::Or && "Only or can be disjoint");
13745f757f3fSDimitry Andric       if (!PDI->isDisjoint())
13755f757f3fSDimitry Andric         return false;
13765f757f3fSDimitry Andric       return (L.match(PDI->getOperand(0)) && R.match(PDI->getOperand(1))) ||
13775f757f3fSDimitry Andric              (Commutable && L.match(PDI->getOperand(1)) &&
13785f757f3fSDimitry Andric               R.match(PDI->getOperand(0)));
13795f757f3fSDimitry Andric     }
13805f757f3fSDimitry Andric     return false;
13815f757f3fSDimitry Andric   }
13825f757f3fSDimitry Andric };
13835f757f3fSDimitry Andric 
13845f757f3fSDimitry Andric template <typename LHS, typename RHS>
m_DisjointOr(const LHS & L,const RHS & R)13855f757f3fSDimitry Andric inline DisjointOr_match<LHS, RHS> m_DisjointOr(const LHS &L, const RHS &R) {
13865f757f3fSDimitry Andric   return DisjointOr_match<LHS, RHS>(L, R);
13875f757f3fSDimitry Andric }
13885f757f3fSDimitry Andric 
13895f757f3fSDimitry Andric template <typename LHS, typename RHS>
m_c_DisjointOr(const LHS & L,const RHS & R)13905f757f3fSDimitry Andric inline DisjointOr_match<LHS, RHS, true> m_c_DisjointOr(const LHS &L,
13915f757f3fSDimitry Andric                                                        const RHS &R) {
13925f757f3fSDimitry Andric   return DisjointOr_match<LHS, RHS, true>(L, R);
13935f757f3fSDimitry Andric }
13945f757f3fSDimitry Andric 
13951db9f3b2SDimitry Andric /// Match either "add" or "or disjoint".
13965f757f3fSDimitry Andric template <typename LHS, typename RHS>
13975f757f3fSDimitry Andric inline match_combine_or<BinaryOp_match<LHS, RHS, Instruction::Add>,
13985f757f3fSDimitry Andric                         DisjointOr_match<LHS, RHS>>
m_AddLike(const LHS & L,const RHS & R)13995f757f3fSDimitry Andric m_AddLike(const LHS &L, const RHS &R) {
14005f757f3fSDimitry Andric   return m_CombineOr(m_Add(L, R), m_DisjointOr(L, R));
14015f757f3fSDimitry Andric }
14025f757f3fSDimitry Andric 
1403*0fca6ea1SDimitry Andric /// Match either "add nsw" or "or disjoint"
1404*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
1405*0fca6ea1SDimitry Andric inline match_combine_or<
1406*0fca6ea1SDimitry Andric     OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
1407*0fca6ea1SDimitry Andric                               OverflowingBinaryOperator::NoSignedWrap>,
1408*0fca6ea1SDimitry Andric     DisjointOr_match<LHS, RHS>>
m_NSWAddLike(const LHS & L,const RHS & R)1409*0fca6ea1SDimitry Andric m_NSWAddLike(const LHS &L, const RHS &R) {
1410*0fca6ea1SDimitry Andric   return m_CombineOr(m_NSWAdd(L, R), m_DisjointOr(L, R));
1411*0fca6ea1SDimitry Andric }
1412*0fca6ea1SDimitry Andric 
1413*0fca6ea1SDimitry Andric /// Match either "add nuw" or "or disjoint"
1414*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
1415*0fca6ea1SDimitry Andric inline match_combine_or<
1416*0fca6ea1SDimitry Andric     OverflowingBinaryOp_match<LHS, RHS, Instruction::Add,
1417*0fca6ea1SDimitry Andric                               OverflowingBinaryOperator::NoUnsignedWrap>,
1418*0fca6ea1SDimitry Andric     DisjointOr_match<LHS, RHS>>
m_NUWAddLike(const LHS & L,const RHS & R)1419*0fca6ea1SDimitry Andric m_NUWAddLike(const LHS &L, const RHS &R) {
1420*0fca6ea1SDimitry Andric   return m_CombineOr(m_NUWAdd(L, R), m_DisjointOr(L, R));
1421*0fca6ea1SDimitry Andric }
1422*0fca6ea1SDimitry Andric 
14230b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
14240b57cec5SDimitry Andric // Class that matches a group of binary opcodes.
14250b57cec5SDimitry Andric //
1426*0fca6ea1SDimitry Andric template <typename LHS_t, typename RHS_t, typename Predicate,
1427*0fca6ea1SDimitry Andric           bool Commutable = false>
14280b57cec5SDimitry Andric struct BinOpPred_match : Predicate {
14290b57cec5SDimitry Andric   LHS_t L;
14300b57cec5SDimitry Andric   RHS_t R;
14310b57cec5SDimitry Andric 
BinOpPred_matchBinOpPred_match14320b57cec5SDimitry Andric   BinOpPred_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {}
14330b57cec5SDimitry Andric 
matchBinOpPred_match14340b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
14350b57cec5SDimitry Andric     if (auto *I = dyn_cast<Instruction>(V))
1436*0fca6ea1SDimitry Andric       return this->isOpType(I->getOpcode()) &&
1437*0fca6ea1SDimitry Andric              ((L.match(I->getOperand(0)) && R.match(I->getOperand(1))) ||
1438*0fca6ea1SDimitry Andric               (Commutable && L.match(I->getOperand(1)) &&
1439*0fca6ea1SDimitry Andric                R.match(I->getOperand(0))));
14400b57cec5SDimitry Andric     return false;
14410b57cec5SDimitry Andric   }
14420b57cec5SDimitry Andric };
14430b57cec5SDimitry Andric 
14440b57cec5SDimitry Andric struct is_shift_op {
isOpTypeis_shift_op14450b57cec5SDimitry Andric   bool isOpType(unsigned Opcode) { return Instruction::isShift(Opcode); }
14460b57cec5SDimitry Andric };
14470b57cec5SDimitry Andric 
14480b57cec5SDimitry Andric struct is_right_shift_op {
isOpTypeis_right_shift_op14490b57cec5SDimitry Andric   bool isOpType(unsigned Opcode) {
14500b57cec5SDimitry Andric     return Opcode == Instruction::LShr || Opcode == Instruction::AShr;
14510b57cec5SDimitry Andric   }
14520b57cec5SDimitry Andric };
14530b57cec5SDimitry Andric 
14540b57cec5SDimitry Andric struct is_logical_shift_op {
isOpTypeis_logical_shift_op14550b57cec5SDimitry Andric   bool isOpType(unsigned Opcode) {
14560b57cec5SDimitry Andric     return Opcode == Instruction::LShr || Opcode == Instruction::Shl;
14570b57cec5SDimitry Andric   }
14580b57cec5SDimitry Andric };
14590b57cec5SDimitry Andric 
14600b57cec5SDimitry Andric struct is_bitwiselogic_op {
isOpTypeis_bitwiselogic_op14610b57cec5SDimitry Andric   bool isOpType(unsigned Opcode) {
14620b57cec5SDimitry Andric     return Instruction::isBitwiseLogicOp(Opcode);
14630b57cec5SDimitry Andric   }
14640b57cec5SDimitry Andric };
14650b57cec5SDimitry Andric 
14660b57cec5SDimitry Andric struct is_idiv_op {
isOpTypeis_idiv_op14670b57cec5SDimitry Andric   bool isOpType(unsigned Opcode) {
14680b57cec5SDimitry Andric     return Opcode == Instruction::SDiv || Opcode == Instruction::UDiv;
14690b57cec5SDimitry Andric   }
14700b57cec5SDimitry Andric };
14710b57cec5SDimitry Andric 
14728bcb0991SDimitry Andric struct is_irem_op {
isOpTypeis_irem_op14738bcb0991SDimitry Andric   bool isOpType(unsigned Opcode) {
14748bcb0991SDimitry Andric     return Opcode == Instruction::SRem || Opcode == Instruction::URem;
14758bcb0991SDimitry Andric   }
14768bcb0991SDimitry Andric };
14778bcb0991SDimitry Andric 
14780b57cec5SDimitry Andric /// Matches shift operations.
14790b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_Shift(const LHS & L,const RHS & R)14800b57cec5SDimitry Andric inline BinOpPred_match<LHS, RHS, is_shift_op> m_Shift(const LHS &L,
14810b57cec5SDimitry Andric                                                       const RHS &R) {
14820b57cec5SDimitry Andric   return BinOpPred_match<LHS, RHS, is_shift_op>(L, R);
14830b57cec5SDimitry Andric }
14840b57cec5SDimitry Andric 
14850b57cec5SDimitry Andric /// Matches logical shift operations.
14860b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_Shr(const LHS & L,const RHS & R)14870b57cec5SDimitry Andric inline BinOpPred_match<LHS, RHS, is_right_shift_op> m_Shr(const LHS &L,
14880b57cec5SDimitry Andric                                                           const RHS &R) {
14890b57cec5SDimitry Andric   return BinOpPred_match<LHS, RHS, is_right_shift_op>(L, R);
14900b57cec5SDimitry Andric }
14910b57cec5SDimitry Andric 
14920b57cec5SDimitry Andric /// Matches logical shift operations.
14930b57cec5SDimitry Andric template <typename LHS, typename RHS>
14940b57cec5SDimitry Andric inline BinOpPred_match<LHS, RHS, is_logical_shift_op>
m_LogicalShift(const LHS & L,const RHS & R)14950b57cec5SDimitry Andric m_LogicalShift(const LHS &L, const RHS &R) {
14960b57cec5SDimitry Andric   return BinOpPred_match<LHS, RHS, is_logical_shift_op>(L, R);
14970b57cec5SDimitry Andric }
14980b57cec5SDimitry Andric 
14990b57cec5SDimitry Andric /// Matches bitwise logic operations.
15000b57cec5SDimitry Andric template <typename LHS, typename RHS>
15010b57cec5SDimitry Andric inline BinOpPred_match<LHS, RHS, is_bitwiselogic_op>
m_BitwiseLogic(const LHS & L,const RHS & R)15020b57cec5SDimitry Andric m_BitwiseLogic(const LHS &L, const RHS &R) {
15030b57cec5SDimitry Andric   return BinOpPred_match<LHS, RHS, is_bitwiselogic_op>(L, R);
15040b57cec5SDimitry Andric }
15050b57cec5SDimitry Andric 
1506*0fca6ea1SDimitry Andric /// Matches bitwise logic operations in either order.
1507*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
1508*0fca6ea1SDimitry Andric inline BinOpPred_match<LHS, RHS, is_bitwiselogic_op, true>
m_c_BitwiseLogic(const LHS & L,const RHS & R)1509*0fca6ea1SDimitry Andric m_c_BitwiseLogic(const LHS &L, const RHS &R) {
1510*0fca6ea1SDimitry Andric   return BinOpPred_match<LHS, RHS, is_bitwiselogic_op, true>(L, R);
1511*0fca6ea1SDimitry Andric }
1512*0fca6ea1SDimitry Andric 
15130b57cec5SDimitry Andric /// Matches integer division operations.
15140b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_IDiv(const LHS & L,const RHS & R)15150b57cec5SDimitry Andric inline BinOpPred_match<LHS, RHS, is_idiv_op> m_IDiv(const LHS &L,
15160b57cec5SDimitry Andric                                                     const RHS &R) {
15170b57cec5SDimitry Andric   return BinOpPred_match<LHS, RHS, is_idiv_op>(L, R);
15180b57cec5SDimitry Andric }
15190b57cec5SDimitry Andric 
15208bcb0991SDimitry Andric /// Matches integer remainder operations.
15218bcb0991SDimitry Andric template <typename LHS, typename RHS>
m_IRem(const LHS & L,const RHS & R)15228bcb0991SDimitry Andric inline BinOpPred_match<LHS, RHS, is_irem_op> m_IRem(const LHS &L,
15238bcb0991SDimitry Andric                                                     const RHS &R) {
15248bcb0991SDimitry Andric   return BinOpPred_match<LHS, RHS, is_irem_op>(L, R);
15258bcb0991SDimitry Andric }
15268bcb0991SDimitry Andric 
15270b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
15280b57cec5SDimitry Andric // Class that matches exact binary ops.
15290b57cec5SDimitry Andric //
15300b57cec5SDimitry Andric template <typename SubPattern_t> struct Exact_match {
15310b57cec5SDimitry Andric   SubPattern_t SubPattern;
15320b57cec5SDimitry Andric 
Exact_matchExact_match15330b57cec5SDimitry Andric   Exact_match(const SubPattern_t &SP) : SubPattern(SP) {}
15340b57cec5SDimitry Andric 
matchExact_match15350b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
15360b57cec5SDimitry Andric     if (auto *PEO = dyn_cast<PossiblyExactOperator>(V))
15370b57cec5SDimitry Andric       return PEO->isExact() && SubPattern.match(V);
15380b57cec5SDimitry Andric     return false;
15390b57cec5SDimitry Andric   }
15400b57cec5SDimitry Andric };
15410b57cec5SDimitry Andric 
m_Exact(const T & SubPattern)15420b57cec5SDimitry Andric template <typename T> inline Exact_match<T> m_Exact(const T &SubPattern) {
15430b57cec5SDimitry Andric   return SubPattern;
15440b57cec5SDimitry Andric }
15450b57cec5SDimitry Andric 
15460b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
15470b57cec5SDimitry Andric // Matchers for CmpInst classes
15480b57cec5SDimitry Andric //
15490b57cec5SDimitry Andric 
15500b57cec5SDimitry Andric template <typename LHS_t, typename RHS_t, typename Class, typename PredicateTy,
15510b57cec5SDimitry Andric           bool Commutable = false>
15520b57cec5SDimitry Andric struct CmpClass_match {
1553*0fca6ea1SDimitry Andric   PredicateTy *Predicate;
15540b57cec5SDimitry Andric   LHS_t L;
15550b57cec5SDimitry Andric   RHS_t R;
15560b57cec5SDimitry Andric 
15570b57cec5SDimitry Andric   // The evaluation order is always stable, regardless of Commutability.
15580b57cec5SDimitry Andric   // The LHS is always matched first.
CmpClass_matchCmpClass_match15590b57cec5SDimitry Andric   CmpClass_match(PredicateTy &Pred, const LHS_t &LHS, const RHS_t &RHS)
1560*0fca6ea1SDimitry Andric       : Predicate(&Pred), L(LHS), R(RHS) {}
CmpClass_matchCmpClass_match1561*0fca6ea1SDimitry Andric   CmpClass_match(const LHS_t &LHS, const RHS_t &RHS)
1562*0fca6ea1SDimitry Andric       : Predicate(nullptr), L(LHS), R(RHS) {}
15630b57cec5SDimitry Andric 
matchCmpClass_match15640b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
15655ffd83dbSDimitry Andric     if (auto *I = dyn_cast<Class>(V)) {
15665ffd83dbSDimitry Andric       if (L.match(I->getOperand(0)) && R.match(I->getOperand(1))) {
1567*0fca6ea1SDimitry Andric         if (Predicate)
1568*0fca6ea1SDimitry Andric           *Predicate = I->getPredicate();
15690b57cec5SDimitry Andric         return true;
15705ffd83dbSDimitry Andric       } else if (Commutable && L.match(I->getOperand(1)) &&
15715ffd83dbSDimitry Andric                  R.match(I->getOperand(0))) {
1572*0fca6ea1SDimitry Andric         if (Predicate)
1573*0fca6ea1SDimitry Andric           *Predicate = I->getSwappedPredicate();
15745ffd83dbSDimitry Andric         return true;
15755ffd83dbSDimitry Andric       }
15760b57cec5SDimitry Andric     }
15770b57cec5SDimitry Andric     return false;
15780b57cec5SDimitry Andric   }
15790b57cec5SDimitry Andric };
15800b57cec5SDimitry Andric 
15810b57cec5SDimitry Andric template <typename LHS, typename RHS>
15820b57cec5SDimitry Andric inline CmpClass_match<LHS, RHS, CmpInst, CmpInst::Predicate>
m_Cmp(CmpInst::Predicate & Pred,const LHS & L,const RHS & R)15830b57cec5SDimitry Andric m_Cmp(CmpInst::Predicate &Pred, const LHS &L, const RHS &R) {
15840b57cec5SDimitry Andric   return CmpClass_match<LHS, RHS, CmpInst, CmpInst::Predicate>(Pred, L, R);
15850b57cec5SDimitry Andric }
15860b57cec5SDimitry Andric 
15870b57cec5SDimitry Andric template <typename LHS, typename RHS>
15880b57cec5SDimitry Andric inline CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate>
m_ICmp(ICmpInst::Predicate & Pred,const LHS & L,const RHS & R)15890b57cec5SDimitry Andric m_ICmp(ICmpInst::Predicate &Pred, const LHS &L, const RHS &R) {
15900b57cec5SDimitry Andric   return CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate>(Pred, L, R);
15910b57cec5SDimitry Andric }
15920b57cec5SDimitry Andric 
15930b57cec5SDimitry Andric template <typename LHS, typename RHS>
15940b57cec5SDimitry Andric inline CmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate>
m_FCmp(FCmpInst::Predicate & Pred,const LHS & L,const RHS & R)15950b57cec5SDimitry Andric m_FCmp(FCmpInst::Predicate &Pred, const LHS &L, const RHS &R) {
15960b57cec5SDimitry Andric   return CmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate>(Pred, L, R);
15970b57cec5SDimitry Andric }
15980b57cec5SDimitry Andric 
1599*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
1600*0fca6ea1SDimitry Andric inline CmpClass_match<LHS, RHS, CmpInst, CmpInst::Predicate>
m_Cmp(const LHS & L,const RHS & R)1601*0fca6ea1SDimitry Andric m_Cmp(const LHS &L, const RHS &R) {
1602*0fca6ea1SDimitry Andric   return CmpClass_match<LHS, RHS, CmpInst, CmpInst::Predicate>(L, R);
1603*0fca6ea1SDimitry Andric }
1604*0fca6ea1SDimitry Andric 
1605*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
1606*0fca6ea1SDimitry Andric inline CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate>
m_ICmp(const LHS & L,const RHS & R)1607*0fca6ea1SDimitry Andric m_ICmp(const LHS &L, const RHS &R) {
1608*0fca6ea1SDimitry Andric   return CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate>(L, R);
1609*0fca6ea1SDimitry Andric }
1610*0fca6ea1SDimitry Andric 
1611*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
1612*0fca6ea1SDimitry Andric inline CmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate>
m_FCmp(const LHS & L,const RHS & R)1613*0fca6ea1SDimitry Andric m_FCmp(const LHS &L, const RHS &R) {
1614*0fca6ea1SDimitry Andric   return CmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate>(L, R);
1615*0fca6ea1SDimitry Andric }
1616*0fca6ea1SDimitry Andric 
1617*0fca6ea1SDimitry Andric // Same as CmpClass, but instead of saving Pred as out output variable, match a
1618*0fca6ea1SDimitry Andric // specific input pred for equality.
1619*0fca6ea1SDimitry Andric template <typename LHS_t, typename RHS_t, typename Class, typename PredicateTy>
1620*0fca6ea1SDimitry Andric struct SpecificCmpClass_match {
1621*0fca6ea1SDimitry Andric   const PredicateTy Predicate;
1622*0fca6ea1SDimitry Andric   LHS_t L;
1623*0fca6ea1SDimitry Andric   RHS_t R;
1624*0fca6ea1SDimitry Andric 
SpecificCmpClass_matchSpecificCmpClass_match1625*0fca6ea1SDimitry Andric   SpecificCmpClass_match(PredicateTy Pred, const LHS_t &LHS, const RHS_t &RHS)
1626*0fca6ea1SDimitry Andric       : Predicate(Pred), L(LHS), R(RHS) {}
1627*0fca6ea1SDimitry Andric 
matchSpecificCmpClass_match1628*0fca6ea1SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
1629*0fca6ea1SDimitry Andric     if (auto *I = dyn_cast<Class>(V))
1630*0fca6ea1SDimitry Andric       return I->getPredicate() == Predicate && L.match(I->getOperand(0)) &&
1631*0fca6ea1SDimitry Andric              R.match(I->getOperand(1));
1632*0fca6ea1SDimitry Andric     return false;
1633*0fca6ea1SDimitry Andric   }
1634*0fca6ea1SDimitry Andric };
1635*0fca6ea1SDimitry Andric 
1636*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
1637*0fca6ea1SDimitry Andric inline SpecificCmpClass_match<LHS, RHS, CmpInst, CmpInst::Predicate>
m_SpecificCmp(CmpInst::Predicate MatchPred,const LHS & L,const RHS & R)1638*0fca6ea1SDimitry Andric m_SpecificCmp(CmpInst::Predicate MatchPred, const LHS &L, const RHS &R) {
1639*0fca6ea1SDimitry Andric   return SpecificCmpClass_match<LHS, RHS, CmpInst, CmpInst::Predicate>(
1640*0fca6ea1SDimitry Andric       MatchPred, L, R);
1641*0fca6ea1SDimitry Andric }
1642*0fca6ea1SDimitry Andric 
1643*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
1644*0fca6ea1SDimitry Andric inline SpecificCmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate>
m_SpecificICmp(ICmpInst::Predicate MatchPred,const LHS & L,const RHS & R)1645*0fca6ea1SDimitry Andric m_SpecificICmp(ICmpInst::Predicate MatchPred, const LHS &L, const RHS &R) {
1646*0fca6ea1SDimitry Andric   return SpecificCmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate>(
1647*0fca6ea1SDimitry Andric       MatchPred, L, R);
1648*0fca6ea1SDimitry Andric }
1649*0fca6ea1SDimitry Andric 
1650*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
1651*0fca6ea1SDimitry Andric inline SpecificCmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate>
m_SpecificFCmp(FCmpInst::Predicate MatchPred,const LHS & L,const RHS & R)1652*0fca6ea1SDimitry Andric m_SpecificFCmp(FCmpInst::Predicate MatchPred, const LHS &L, const RHS &R) {
1653*0fca6ea1SDimitry Andric   return SpecificCmpClass_match<LHS, RHS, FCmpInst, FCmpInst::Predicate>(
1654*0fca6ea1SDimitry Andric       MatchPred, L, R);
1655*0fca6ea1SDimitry Andric }
1656*0fca6ea1SDimitry Andric 
16570b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
16580b57cec5SDimitry Andric // Matchers for instructions with a given opcode and number of operands.
16590b57cec5SDimitry Andric //
16600b57cec5SDimitry Andric 
16610b57cec5SDimitry Andric /// Matches instructions with Opcode and three operands.
16620b57cec5SDimitry Andric template <typename T0, unsigned Opcode> struct OneOps_match {
16630b57cec5SDimitry Andric   T0 Op1;
16640b57cec5SDimitry Andric 
OneOps_matchOneOps_match16650b57cec5SDimitry Andric   OneOps_match(const T0 &Op1) : Op1(Op1) {}
16660b57cec5SDimitry Andric 
matchOneOps_match16670b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
16680b57cec5SDimitry Andric     if (V->getValueID() == Value::InstructionVal + Opcode) {
16690b57cec5SDimitry Andric       auto *I = cast<Instruction>(V);
16700b57cec5SDimitry Andric       return Op1.match(I->getOperand(0));
16710b57cec5SDimitry Andric     }
16720b57cec5SDimitry Andric     return false;
16730b57cec5SDimitry Andric   }
16740b57cec5SDimitry Andric };
16750b57cec5SDimitry Andric 
16760b57cec5SDimitry Andric /// Matches instructions with Opcode and three operands.
16770b57cec5SDimitry Andric template <typename T0, typename T1, unsigned Opcode> struct TwoOps_match {
16780b57cec5SDimitry Andric   T0 Op1;
16790b57cec5SDimitry Andric   T1 Op2;
16800b57cec5SDimitry Andric 
TwoOps_matchTwoOps_match16810b57cec5SDimitry Andric   TwoOps_match(const T0 &Op1, const T1 &Op2) : Op1(Op1), Op2(Op2) {}
16820b57cec5SDimitry Andric 
matchTwoOps_match16830b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
16840b57cec5SDimitry Andric     if (V->getValueID() == Value::InstructionVal + Opcode) {
16850b57cec5SDimitry Andric       auto *I = cast<Instruction>(V);
16860b57cec5SDimitry Andric       return Op1.match(I->getOperand(0)) && Op2.match(I->getOperand(1));
16870b57cec5SDimitry Andric     }
16880b57cec5SDimitry Andric     return false;
16890b57cec5SDimitry Andric   }
16900b57cec5SDimitry Andric };
16910b57cec5SDimitry Andric 
16920b57cec5SDimitry Andric /// Matches instructions with Opcode and three operands.
16930b57cec5SDimitry Andric template <typename T0, typename T1, typename T2, unsigned Opcode>
16940b57cec5SDimitry Andric struct ThreeOps_match {
16950b57cec5SDimitry Andric   T0 Op1;
16960b57cec5SDimitry Andric   T1 Op2;
16970b57cec5SDimitry Andric   T2 Op3;
16980b57cec5SDimitry Andric 
ThreeOps_matchThreeOps_match16990b57cec5SDimitry Andric   ThreeOps_match(const T0 &Op1, const T1 &Op2, const T2 &Op3)
17000b57cec5SDimitry Andric       : Op1(Op1), Op2(Op2), Op3(Op3) {}
17010b57cec5SDimitry Andric 
matchThreeOps_match17020b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
17030b57cec5SDimitry Andric     if (V->getValueID() == Value::InstructionVal + Opcode) {
17040b57cec5SDimitry Andric       auto *I = cast<Instruction>(V);
17050b57cec5SDimitry Andric       return Op1.match(I->getOperand(0)) && Op2.match(I->getOperand(1)) &&
17060b57cec5SDimitry Andric              Op3.match(I->getOperand(2));
17070b57cec5SDimitry Andric     }
17080b57cec5SDimitry Andric     return false;
17090b57cec5SDimitry Andric   }
17100b57cec5SDimitry Andric };
17110b57cec5SDimitry Andric 
1712297eecfbSDimitry Andric /// Matches instructions with Opcode and any number of operands
1713297eecfbSDimitry Andric template <unsigned Opcode, typename... OperandTypes> struct AnyOps_match {
1714297eecfbSDimitry Andric   std::tuple<OperandTypes...> Operands;
1715297eecfbSDimitry Andric 
AnyOps_matchAnyOps_match1716297eecfbSDimitry Andric   AnyOps_match(const OperandTypes &...Ops) : Operands(Ops...) {}
1717297eecfbSDimitry Andric 
1718297eecfbSDimitry Andric   // Operand matching works by recursively calling match_operands, matching the
1719297eecfbSDimitry Andric   // operands left to right. The first version is called for each operand but
1720297eecfbSDimitry Andric   // the last, for which the second version is called. The second version of
1721297eecfbSDimitry Andric   // match_operands is also used to match each individual operand.
1722297eecfbSDimitry Andric   template <int Idx, int Last>
match_operandsAnyOps_match1723297eecfbSDimitry Andric   std::enable_if_t<Idx != Last, bool> match_operands(const Instruction *I) {
1724297eecfbSDimitry Andric     return match_operands<Idx, Idx>(I) && match_operands<Idx + 1, Last>(I);
1725297eecfbSDimitry Andric   }
1726297eecfbSDimitry Andric 
1727297eecfbSDimitry Andric   template <int Idx, int Last>
match_operandsAnyOps_match1728297eecfbSDimitry Andric   std::enable_if_t<Idx == Last, bool> match_operands(const Instruction *I) {
1729297eecfbSDimitry Andric     return std::get<Idx>(Operands).match(I->getOperand(Idx));
1730297eecfbSDimitry Andric   }
1731297eecfbSDimitry Andric 
matchAnyOps_match1732297eecfbSDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
1733297eecfbSDimitry Andric     if (V->getValueID() == Value::InstructionVal + Opcode) {
1734297eecfbSDimitry Andric       auto *I = cast<Instruction>(V);
1735297eecfbSDimitry Andric       return I->getNumOperands() == sizeof...(OperandTypes) &&
1736297eecfbSDimitry Andric              match_operands<0, sizeof...(OperandTypes) - 1>(I);
1737297eecfbSDimitry Andric     }
1738297eecfbSDimitry Andric     return false;
1739297eecfbSDimitry Andric   }
1740297eecfbSDimitry Andric };
1741297eecfbSDimitry Andric 
17420b57cec5SDimitry Andric /// Matches SelectInst.
17430b57cec5SDimitry Andric template <typename Cond, typename LHS, typename RHS>
17440b57cec5SDimitry Andric inline ThreeOps_match<Cond, LHS, RHS, Instruction::Select>
m_Select(const Cond & C,const LHS & L,const RHS & R)17450b57cec5SDimitry Andric m_Select(const Cond &C, const LHS &L, const RHS &R) {
17460b57cec5SDimitry Andric   return ThreeOps_match<Cond, LHS, RHS, Instruction::Select>(C, L, R);
17470b57cec5SDimitry Andric }
17480b57cec5SDimitry Andric 
17490b57cec5SDimitry Andric /// This matches a select of two constants, e.g.:
17500b57cec5SDimitry Andric /// m_SelectCst<-1, 0>(m_Value(V))
17510b57cec5SDimitry Andric template <int64_t L, int64_t R, typename Cond>
17520b57cec5SDimitry Andric inline ThreeOps_match<Cond, constantint_match<L>, constantint_match<R>,
17530b57cec5SDimitry Andric                       Instruction::Select>
m_SelectCst(const Cond & C)17540b57cec5SDimitry Andric m_SelectCst(const Cond &C) {
17550b57cec5SDimitry Andric   return m_Select(C, m_ConstantInt<L>(), m_ConstantInt<R>());
17560b57cec5SDimitry Andric }
17570b57cec5SDimitry Andric 
1758480093f4SDimitry Andric /// Matches FreezeInst.
1759480093f4SDimitry Andric template <typename OpTy>
m_Freeze(const OpTy & Op)1760480093f4SDimitry Andric inline OneOps_match<OpTy, Instruction::Freeze> m_Freeze(const OpTy &Op) {
1761480093f4SDimitry Andric   return OneOps_match<OpTy, Instruction::Freeze>(Op);
1762480093f4SDimitry Andric }
1763480093f4SDimitry Andric 
17640b57cec5SDimitry Andric /// Matches InsertElementInst.
17650b57cec5SDimitry Andric template <typename Val_t, typename Elt_t, typename Idx_t>
17660b57cec5SDimitry Andric inline ThreeOps_match<Val_t, Elt_t, Idx_t, Instruction::InsertElement>
m_InsertElt(const Val_t & Val,const Elt_t & Elt,const Idx_t & Idx)17675ffd83dbSDimitry Andric m_InsertElt(const Val_t &Val, const Elt_t &Elt, const Idx_t &Idx) {
17680b57cec5SDimitry Andric   return ThreeOps_match<Val_t, Elt_t, Idx_t, Instruction::InsertElement>(
17690b57cec5SDimitry Andric       Val, Elt, Idx);
17700b57cec5SDimitry Andric }
17710b57cec5SDimitry Andric 
17720b57cec5SDimitry Andric /// Matches ExtractElementInst.
17730b57cec5SDimitry Andric template <typename Val_t, typename Idx_t>
17740b57cec5SDimitry Andric inline TwoOps_match<Val_t, Idx_t, Instruction::ExtractElement>
m_ExtractElt(const Val_t & Val,const Idx_t & Idx)17755ffd83dbSDimitry Andric m_ExtractElt(const Val_t &Val, const Idx_t &Idx) {
17760b57cec5SDimitry Andric   return TwoOps_match<Val_t, Idx_t, Instruction::ExtractElement>(Val, Idx);
17770b57cec5SDimitry Andric }
17780b57cec5SDimitry Andric 
17795ffd83dbSDimitry Andric /// Matches shuffle.
17805ffd83dbSDimitry Andric template <typename T0, typename T1, typename T2> struct Shuffle_match {
17815ffd83dbSDimitry Andric   T0 Op1;
17825ffd83dbSDimitry Andric   T1 Op2;
17835ffd83dbSDimitry Andric   T2 Mask;
17845ffd83dbSDimitry Andric 
Shuffle_matchShuffle_match17855ffd83dbSDimitry Andric   Shuffle_match(const T0 &Op1, const T1 &Op2, const T2 &Mask)
17865ffd83dbSDimitry Andric       : Op1(Op1), Op2(Op2), Mask(Mask) {}
17875ffd83dbSDimitry Andric 
matchShuffle_match17885ffd83dbSDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
17895ffd83dbSDimitry Andric     if (auto *I = dyn_cast<ShuffleVectorInst>(V)) {
17905ffd83dbSDimitry Andric       return Op1.match(I->getOperand(0)) && Op2.match(I->getOperand(1)) &&
17915ffd83dbSDimitry Andric              Mask.match(I->getShuffleMask());
17925ffd83dbSDimitry Andric     }
17935ffd83dbSDimitry Andric     return false;
17945ffd83dbSDimitry Andric   }
17955ffd83dbSDimitry Andric };
17965ffd83dbSDimitry Andric 
17975ffd83dbSDimitry Andric struct m_Mask {
17985ffd83dbSDimitry Andric   ArrayRef<int> &MaskRef;
m_Maskm_Mask17995ffd83dbSDimitry Andric   m_Mask(ArrayRef<int> &MaskRef) : MaskRef(MaskRef) {}
matchm_Mask18005ffd83dbSDimitry Andric   bool match(ArrayRef<int> Mask) {
18015ffd83dbSDimitry Andric     MaskRef = Mask;
18025ffd83dbSDimitry Andric     return true;
18035ffd83dbSDimitry Andric   }
18045ffd83dbSDimitry Andric };
18055ffd83dbSDimitry Andric 
18065ffd83dbSDimitry Andric struct m_ZeroMask {
matchm_ZeroMask18075ffd83dbSDimitry Andric   bool match(ArrayRef<int> Mask) {
18085ffd83dbSDimitry Andric     return all_of(Mask, [](int Elem) { return Elem == 0 || Elem == -1; });
18095ffd83dbSDimitry Andric   }
18105ffd83dbSDimitry Andric };
18115ffd83dbSDimitry Andric 
18125ffd83dbSDimitry Andric struct m_SpecificMask {
18135ffd83dbSDimitry Andric   ArrayRef<int> &MaskRef;
m_SpecificMaskm_SpecificMask18145ffd83dbSDimitry Andric   m_SpecificMask(ArrayRef<int> &MaskRef) : MaskRef(MaskRef) {}
matchm_SpecificMask18155ffd83dbSDimitry Andric   bool match(ArrayRef<int> Mask) { return MaskRef == Mask; }
18165ffd83dbSDimitry Andric };
18175ffd83dbSDimitry Andric 
1818*0fca6ea1SDimitry Andric struct m_SplatOrPoisonMask {
18195ffd83dbSDimitry Andric   int &SplatIndex;
m_SplatOrPoisonMaskm_SplatOrPoisonMask1820*0fca6ea1SDimitry Andric   m_SplatOrPoisonMask(int &SplatIndex) : SplatIndex(SplatIndex) {}
matchm_SplatOrPoisonMask18215ffd83dbSDimitry Andric   bool match(ArrayRef<int> Mask) {
182206c3fb27SDimitry Andric     const auto *First = find_if(Mask, [](int Elem) { return Elem != -1; });
18235ffd83dbSDimitry Andric     if (First == Mask.end())
18245ffd83dbSDimitry Andric       return false;
18255ffd83dbSDimitry Andric     SplatIndex = *First;
18265ffd83dbSDimitry Andric     return all_of(Mask,
18275ffd83dbSDimitry Andric                   [First](int Elem) { return Elem == *First || Elem == -1; });
18285ffd83dbSDimitry Andric   }
18295ffd83dbSDimitry Andric };
18305ffd83dbSDimitry Andric 
1831*0fca6ea1SDimitry Andric template <typename PointerOpTy, typename OffsetOpTy> struct PtrAdd_match {
1832*0fca6ea1SDimitry Andric   PointerOpTy PointerOp;
1833*0fca6ea1SDimitry Andric   OffsetOpTy OffsetOp;
1834*0fca6ea1SDimitry Andric 
PtrAdd_matchPtrAdd_match1835*0fca6ea1SDimitry Andric   PtrAdd_match(const PointerOpTy &PointerOp, const OffsetOpTy &OffsetOp)
1836*0fca6ea1SDimitry Andric       : PointerOp(PointerOp), OffsetOp(OffsetOp) {}
1837*0fca6ea1SDimitry Andric 
matchPtrAdd_match1838*0fca6ea1SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
1839*0fca6ea1SDimitry Andric     auto *GEP = dyn_cast<GEPOperator>(V);
1840*0fca6ea1SDimitry Andric     return GEP && GEP->getSourceElementType()->isIntegerTy(8) &&
1841*0fca6ea1SDimitry Andric            PointerOp.match(GEP->getPointerOperand()) &&
1842*0fca6ea1SDimitry Andric            OffsetOp.match(GEP->idx_begin()->get());
1843*0fca6ea1SDimitry Andric   }
1844*0fca6ea1SDimitry Andric };
1845*0fca6ea1SDimitry Andric 
18465ffd83dbSDimitry Andric /// Matches ShuffleVectorInst independently of mask value.
18475ffd83dbSDimitry Andric template <typename V1_t, typename V2_t>
18485ffd83dbSDimitry Andric inline TwoOps_match<V1_t, V2_t, Instruction::ShuffleVector>
m_Shuffle(const V1_t & v1,const V2_t & v2)18495ffd83dbSDimitry Andric m_Shuffle(const V1_t &v1, const V2_t &v2) {
18505ffd83dbSDimitry Andric   return TwoOps_match<V1_t, V2_t, Instruction::ShuffleVector>(v1, v2);
18515ffd83dbSDimitry Andric }
18525ffd83dbSDimitry Andric 
18530b57cec5SDimitry Andric template <typename V1_t, typename V2_t, typename Mask_t>
18545ffd83dbSDimitry Andric inline Shuffle_match<V1_t, V2_t, Mask_t>
m_Shuffle(const V1_t & v1,const V2_t & v2,const Mask_t & mask)18555ffd83dbSDimitry Andric m_Shuffle(const V1_t &v1, const V2_t &v2, const Mask_t &mask) {
18565ffd83dbSDimitry Andric   return Shuffle_match<V1_t, V2_t, Mask_t>(v1, v2, mask);
18570b57cec5SDimitry Andric }
18580b57cec5SDimitry Andric 
18590b57cec5SDimitry Andric /// Matches LoadInst.
18600b57cec5SDimitry Andric template <typename OpTy>
m_Load(const OpTy & Op)18610b57cec5SDimitry Andric inline OneOps_match<OpTy, Instruction::Load> m_Load(const OpTy &Op) {
18620b57cec5SDimitry Andric   return OneOps_match<OpTy, Instruction::Load>(Op);
18630b57cec5SDimitry Andric }
18640b57cec5SDimitry Andric 
18650b57cec5SDimitry Andric /// Matches StoreInst.
18660b57cec5SDimitry Andric template <typename ValueOpTy, typename PointerOpTy>
18670b57cec5SDimitry Andric inline TwoOps_match<ValueOpTy, PointerOpTy, Instruction::Store>
m_Store(const ValueOpTy & ValueOp,const PointerOpTy & PointerOp)18680b57cec5SDimitry Andric m_Store(const ValueOpTy &ValueOp, const PointerOpTy &PointerOp) {
18690b57cec5SDimitry Andric   return TwoOps_match<ValueOpTy, PointerOpTy, Instruction::Store>(ValueOp,
18700b57cec5SDimitry Andric                                                                   PointerOp);
18710b57cec5SDimitry Andric }
18720b57cec5SDimitry Andric 
1873297eecfbSDimitry Andric /// Matches GetElementPtrInst.
1874297eecfbSDimitry Andric template <typename... OperandTypes>
m_GEP(const OperandTypes &...Ops)1875297eecfbSDimitry Andric inline auto m_GEP(const OperandTypes &...Ops) {
1876297eecfbSDimitry Andric   return AnyOps_match<Instruction::GetElementPtr, OperandTypes...>(Ops...);
1877297eecfbSDimitry Andric }
1878297eecfbSDimitry Andric 
1879*0fca6ea1SDimitry Andric /// Matches GEP with i8 source element type
1880*0fca6ea1SDimitry Andric template <typename PointerOpTy, typename OffsetOpTy>
1881*0fca6ea1SDimitry Andric inline PtrAdd_match<PointerOpTy, OffsetOpTy>
m_PtrAdd(const PointerOpTy & PointerOp,const OffsetOpTy & OffsetOp)1882*0fca6ea1SDimitry Andric m_PtrAdd(const PointerOpTy &PointerOp, const OffsetOpTy &OffsetOp) {
1883*0fca6ea1SDimitry Andric   return PtrAdd_match<PointerOpTy, OffsetOpTy>(PointerOp, OffsetOp);
1884*0fca6ea1SDimitry Andric }
1885*0fca6ea1SDimitry Andric 
18860b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
18870b57cec5SDimitry Andric // Matchers for CastInst classes
18880b57cec5SDimitry Andric //
18890b57cec5SDimitry Andric 
18905f757f3fSDimitry Andric template <typename Op_t, unsigned Opcode> struct CastOperator_match {
18910b57cec5SDimitry Andric   Op_t Op;
18920b57cec5SDimitry Andric 
CastOperator_matchCastOperator_match18935f757f3fSDimitry Andric   CastOperator_match(const Op_t &OpMatch) : Op(OpMatch) {}
18940b57cec5SDimitry Andric 
matchCastOperator_match18950b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
18960b57cec5SDimitry Andric     if (auto *O = dyn_cast<Operator>(V))
18970b57cec5SDimitry Andric       return O->getOpcode() == Opcode && Op.match(O->getOperand(0));
18980b57cec5SDimitry Andric     return false;
18990b57cec5SDimitry Andric   }
19000b57cec5SDimitry Andric };
19010b57cec5SDimitry Andric 
1902*0fca6ea1SDimitry Andric template <typename Op_t, typename Class> struct CastInst_match {
19035f757f3fSDimitry Andric   Op_t Op;
19045f757f3fSDimitry Andric 
CastInst_matchCastInst_match19055f757f3fSDimitry Andric   CastInst_match(const Op_t &OpMatch) : Op(OpMatch) {}
19065f757f3fSDimitry Andric 
matchCastInst_match19075f757f3fSDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
1908*0fca6ea1SDimitry Andric     if (auto *I = dyn_cast<Class>(V))
1909*0fca6ea1SDimitry Andric       return Op.match(I->getOperand(0));
19105f757f3fSDimitry Andric     return false;
19115f757f3fSDimitry Andric   }
19125f757f3fSDimitry Andric };
19135f757f3fSDimitry Andric 
191406c3fb27SDimitry Andric template <typename Op_t> struct PtrToIntSameSize_match {
191506c3fb27SDimitry Andric   const DataLayout &DL;
191606c3fb27SDimitry Andric   Op_t Op;
191706c3fb27SDimitry Andric 
PtrToIntSameSize_matchPtrToIntSameSize_match191806c3fb27SDimitry Andric   PtrToIntSameSize_match(const DataLayout &DL, const Op_t &OpMatch)
191906c3fb27SDimitry Andric       : DL(DL), Op(OpMatch) {}
192006c3fb27SDimitry Andric 
matchPtrToIntSameSize_match192106c3fb27SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
192206c3fb27SDimitry Andric     if (auto *O = dyn_cast<Operator>(V))
192306c3fb27SDimitry Andric       return O->getOpcode() == Instruction::PtrToInt &&
192406c3fb27SDimitry Andric              DL.getTypeSizeInBits(O->getType()) ==
192506c3fb27SDimitry Andric                  DL.getTypeSizeInBits(O->getOperand(0)->getType()) &&
192606c3fb27SDimitry Andric              Op.match(O->getOperand(0));
192706c3fb27SDimitry Andric     return false;
192806c3fb27SDimitry Andric   }
192906c3fb27SDimitry Andric };
193006c3fb27SDimitry Andric 
1931cb14a3feSDimitry Andric template <typename Op_t> struct NNegZExt_match {
1932cb14a3feSDimitry Andric   Op_t Op;
1933cb14a3feSDimitry Andric 
NNegZExt_matchNNegZExt_match1934cb14a3feSDimitry Andric   NNegZExt_match(const Op_t &OpMatch) : Op(OpMatch) {}
1935cb14a3feSDimitry Andric 
matchNNegZExt_match1936cb14a3feSDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
1937*0fca6ea1SDimitry Andric     if (auto *I = dyn_cast<ZExtInst>(V))
1938*0fca6ea1SDimitry Andric       return I->hasNonNeg() && Op.match(I->getOperand(0));
1939*0fca6ea1SDimitry Andric     return false;
1940*0fca6ea1SDimitry Andric   }
1941*0fca6ea1SDimitry Andric };
1942*0fca6ea1SDimitry Andric 
1943*0fca6ea1SDimitry Andric template <typename Op_t, unsigned WrapFlags = 0> struct NoWrapTrunc_match {
1944*0fca6ea1SDimitry Andric   Op_t Op;
1945*0fca6ea1SDimitry Andric 
NoWrapTrunc_matchNoWrapTrunc_match1946*0fca6ea1SDimitry Andric   NoWrapTrunc_match(const Op_t &OpMatch) : Op(OpMatch) {}
1947*0fca6ea1SDimitry Andric 
matchNoWrapTrunc_match1948*0fca6ea1SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
1949*0fca6ea1SDimitry Andric     if (auto *I = dyn_cast<TruncInst>(V))
1950*0fca6ea1SDimitry Andric       return (I->getNoWrapKind() & WrapFlags) == WrapFlags &&
1951cb14a3feSDimitry Andric              Op.match(I->getOperand(0));
1952cb14a3feSDimitry Andric     return false;
1953cb14a3feSDimitry Andric   }
1954cb14a3feSDimitry Andric };
1955cb14a3feSDimitry Andric 
19560b57cec5SDimitry Andric /// Matches BitCast.
19570b57cec5SDimitry Andric template <typename OpTy>
19585f757f3fSDimitry Andric inline CastOperator_match<OpTy, Instruction::BitCast>
m_BitCast(const OpTy & Op)19595f757f3fSDimitry Andric m_BitCast(const OpTy &Op) {
19605f757f3fSDimitry Andric   return CastOperator_match<OpTy, Instruction::BitCast>(Op);
19610b57cec5SDimitry Andric }
19620b57cec5SDimitry Andric 
1963*0fca6ea1SDimitry Andric template <typename Op_t> struct ElementWiseBitCast_match {
1964*0fca6ea1SDimitry Andric   Op_t Op;
1965*0fca6ea1SDimitry Andric 
ElementWiseBitCast_matchElementWiseBitCast_match1966*0fca6ea1SDimitry Andric   ElementWiseBitCast_match(const Op_t &OpMatch) : Op(OpMatch) {}
1967*0fca6ea1SDimitry Andric 
matchElementWiseBitCast_match1968*0fca6ea1SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
1969*0fca6ea1SDimitry Andric     auto *I = dyn_cast<BitCastInst>(V);
1970*0fca6ea1SDimitry Andric     if (!I)
1971*0fca6ea1SDimitry Andric       return false;
1972*0fca6ea1SDimitry Andric     Type *SrcType = I->getSrcTy();
1973*0fca6ea1SDimitry Andric     Type *DstType = I->getType();
1974*0fca6ea1SDimitry Andric     // Make sure the bitcast doesn't change between scalar and vector and
1975*0fca6ea1SDimitry Andric     // doesn't change the number of vector elements.
1976*0fca6ea1SDimitry Andric     if (SrcType->isVectorTy() != DstType->isVectorTy())
1977*0fca6ea1SDimitry Andric       return false;
1978*0fca6ea1SDimitry Andric     if (VectorType *SrcVecTy = dyn_cast<VectorType>(SrcType);
1979*0fca6ea1SDimitry Andric         SrcVecTy && SrcVecTy->getElementCount() !=
1980*0fca6ea1SDimitry Andric                         cast<VectorType>(DstType)->getElementCount())
1981*0fca6ea1SDimitry Andric       return false;
1982*0fca6ea1SDimitry Andric     return Op.match(I->getOperand(0));
1983*0fca6ea1SDimitry Andric   }
1984*0fca6ea1SDimitry Andric };
1985*0fca6ea1SDimitry Andric 
1986*0fca6ea1SDimitry Andric template <typename OpTy>
m_ElementWiseBitCast(const OpTy & Op)1987*0fca6ea1SDimitry Andric inline ElementWiseBitCast_match<OpTy> m_ElementWiseBitCast(const OpTy &Op) {
1988*0fca6ea1SDimitry Andric   return ElementWiseBitCast_match<OpTy>(Op);
1989*0fca6ea1SDimitry Andric }
1990*0fca6ea1SDimitry Andric 
19910b57cec5SDimitry Andric /// Matches PtrToInt.
19920b57cec5SDimitry Andric template <typename OpTy>
19935f757f3fSDimitry Andric inline CastOperator_match<OpTy, Instruction::PtrToInt>
m_PtrToInt(const OpTy & Op)19945f757f3fSDimitry Andric m_PtrToInt(const OpTy &Op) {
19955f757f3fSDimitry Andric   return CastOperator_match<OpTy, Instruction::PtrToInt>(Op);
19960b57cec5SDimitry Andric }
19970b57cec5SDimitry Andric 
199806c3fb27SDimitry Andric template <typename OpTy>
m_PtrToIntSameSize(const DataLayout & DL,const OpTy & Op)199906c3fb27SDimitry Andric inline PtrToIntSameSize_match<OpTy> m_PtrToIntSameSize(const DataLayout &DL,
200006c3fb27SDimitry Andric                                                        const OpTy &Op) {
200106c3fb27SDimitry Andric   return PtrToIntSameSize_match<OpTy>(DL, Op);
200206c3fb27SDimitry Andric }
200306c3fb27SDimitry Andric 
2004e8d8bef9SDimitry Andric /// Matches IntToPtr.
2005e8d8bef9SDimitry Andric template <typename OpTy>
20065f757f3fSDimitry Andric inline CastOperator_match<OpTy, Instruction::IntToPtr>
m_IntToPtr(const OpTy & Op)20075f757f3fSDimitry Andric m_IntToPtr(const OpTy &Op) {
20085f757f3fSDimitry Andric   return CastOperator_match<OpTy, Instruction::IntToPtr>(Op);
2009e8d8bef9SDimitry Andric }
2010e8d8bef9SDimitry Andric 
20110b57cec5SDimitry Andric /// Matches Trunc.
20120b57cec5SDimitry Andric template <typename OpTy>
m_Trunc(const OpTy & Op)2013*0fca6ea1SDimitry Andric inline CastInst_match<OpTy, TruncInst> m_Trunc(const OpTy &Op) {
2014*0fca6ea1SDimitry Andric   return CastInst_match<OpTy, TruncInst>(Op);
2015*0fca6ea1SDimitry Andric }
2016*0fca6ea1SDimitry Andric 
2017*0fca6ea1SDimitry Andric /// Matches trunc nuw.
2018*0fca6ea1SDimitry Andric template <typename OpTy>
2019*0fca6ea1SDimitry Andric inline NoWrapTrunc_match<OpTy, TruncInst::NoUnsignedWrap>
m_NUWTrunc(const OpTy & Op)2020*0fca6ea1SDimitry Andric m_NUWTrunc(const OpTy &Op) {
2021*0fca6ea1SDimitry Andric   return NoWrapTrunc_match<OpTy, TruncInst::NoUnsignedWrap>(Op);
2022*0fca6ea1SDimitry Andric }
2023*0fca6ea1SDimitry Andric 
2024*0fca6ea1SDimitry Andric /// Matches trunc nsw.
2025*0fca6ea1SDimitry Andric template <typename OpTy>
2026*0fca6ea1SDimitry Andric inline NoWrapTrunc_match<OpTy, TruncInst::NoSignedWrap>
m_NSWTrunc(const OpTy & Op)2027*0fca6ea1SDimitry Andric m_NSWTrunc(const OpTy &Op) {
2028*0fca6ea1SDimitry Andric   return NoWrapTrunc_match<OpTy, TruncInst::NoSignedWrap>(Op);
20290b57cec5SDimitry Andric }
20300b57cec5SDimitry Andric 
20318bcb0991SDimitry Andric template <typename OpTy>
2032*0fca6ea1SDimitry Andric inline match_combine_or<CastInst_match<OpTy, TruncInst>, OpTy>
m_TruncOrSelf(const OpTy & Op)20338bcb0991SDimitry Andric m_TruncOrSelf(const OpTy &Op) {
20348bcb0991SDimitry Andric   return m_CombineOr(m_Trunc(Op), Op);
20358bcb0991SDimitry Andric }
20368bcb0991SDimitry Andric 
20370b57cec5SDimitry Andric /// Matches SExt.
20380b57cec5SDimitry Andric template <typename OpTy>
m_SExt(const OpTy & Op)2039*0fca6ea1SDimitry Andric inline CastInst_match<OpTy, SExtInst> m_SExt(const OpTy &Op) {
2040*0fca6ea1SDimitry Andric   return CastInst_match<OpTy, SExtInst>(Op);
20410b57cec5SDimitry Andric }
20420b57cec5SDimitry Andric 
20430b57cec5SDimitry Andric /// Matches ZExt.
20440b57cec5SDimitry Andric template <typename OpTy>
m_ZExt(const OpTy & Op)2045*0fca6ea1SDimitry Andric inline CastInst_match<OpTy, ZExtInst> m_ZExt(const OpTy &Op) {
2046*0fca6ea1SDimitry Andric   return CastInst_match<OpTy, ZExtInst>(Op);
20470b57cec5SDimitry Andric }
20480b57cec5SDimitry Andric 
20490b57cec5SDimitry Andric template <typename OpTy>
m_NNegZExt(const OpTy & Op)2050cb14a3feSDimitry Andric inline NNegZExt_match<OpTy> m_NNegZExt(const OpTy &Op) {
2051cb14a3feSDimitry Andric   return NNegZExt_match<OpTy>(Op);
2052cb14a3feSDimitry Andric }
2053cb14a3feSDimitry Andric 
2054cb14a3feSDimitry Andric template <typename OpTy>
2055*0fca6ea1SDimitry Andric inline match_combine_or<CastInst_match<OpTy, ZExtInst>, OpTy>
m_ZExtOrSelf(const OpTy & Op)20568bcb0991SDimitry Andric m_ZExtOrSelf(const OpTy &Op) {
20578bcb0991SDimitry Andric   return m_CombineOr(m_ZExt(Op), Op);
20588bcb0991SDimitry Andric }
20598bcb0991SDimitry Andric 
20608bcb0991SDimitry Andric template <typename OpTy>
2061*0fca6ea1SDimitry Andric inline match_combine_or<CastInst_match<OpTy, SExtInst>, OpTy>
m_SExtOrSelf(const OpTy & Op)20628bcb0991SDimitry Andric m_SExtOrSelf(const OpTy &Op) {
20638bcb0991SDimitry Andric   return m_CombineOr(m_SExt(Op), Op);
20648bcb0991SDimitry Andric }
20658bcb0991SDimitry Andric 
2066cb14a3feSDimitry Andric /// Match either "sext" or "zext nneg".
2067cb14a3feSDimitry Andric template <typename OpTy>
2068*0fca6ea1SDimitry Andric inline match_combine_or<CastInst_match<OpTy, SExtInst>, NNegZExt_match<OpTy>>
m_SExtLike(const OpTy & Op)2069cb14a3feSDimitry Andric m_SExtLike(const OpTy &Op) {
2070cb14a3feSDimitry Andric   return m_CombineOr(m_SExt(Op), m_NNegZExt(Op));
2071cb14a3feSDimitry Andric }
2072cb14a3feSDimitry Andric 
20738bcb0991SDimitry Andric template <typename OpTy>
2074*0fca6ea1SDimitry Andric inline match_combine_or<CastInst_match<OpTy, ZExtInst>,
2075*0fca6ea1SDimitry Andric                         CastInst_match<OpTy, SExtInst>>
m_ZExtOrSExt(const OpTy & Op)20760b57cec5SDimitry Andric m_ZExtOrSExt(const OpTy &Op) {
20770b57cec5SDimitry Andric   return m_CombineOr(m_ZExt(Op), m_SExt(Op));
20780b57cec5SDimitry Andric }
20790b57cec5SDimitry Andric 
20808bcb0991SDimitry Andric template <typename OpTy>
2081*0fca6ea1SDimitry Andric inline match_combine_or<match_combine_or<CastInst_match<OpTy, ZExtInst>,
2082*0fca6ea1SDimitry Andric                                          CastInst_match<OpTy, SExtInst>>,
20838bcb0991SDimitry Andric                         OpTy>
m_ZExtOrSExtOrSelf(const OpTy & Op)20848bcb0991SDimitry Andric m_ZExtOrSExtOrSelf(const OpTy &Op) {
20858bcb0991SDimitry Andric   return m_CombineOr(m_ZExtOrSExt(Op), Op);
20868bcb0991SDimitry Andric }
20878bcb0991SDimitry Andric 
20880b57cec5SDimitry Andric template <typename OpTy>
m_UIToFP(const OpTy & Op)2089*0fca6ea1SDimitry Andric inline CastInst_match<OpTy, UIToFPInst> m_UIToFP(const OpTy &Op) {
2090*0fca6ea1SDimitry Andric   return CastInst_match<OpTy, UIToFPInst>(Op);
20910b57cec5SDimitry Andric }
20920b57cec5SDimitry Andric 
20930b57cec5SDimitry Andric template <typename OpTy>
m_SIToFP(const OpTy & Op)2094*0fca6ea1SDimitry Andric inline CastInst_match<OpTy, SIToFPInst> m_SIToFP(const OpTy &Op) {
2095*0fca6ea1SDimitry Andric   return CastInst_match<OpTy, SIToFPInst>(Op);
20960b57cec5SDimitry Andric }
20970b57cec5SDimitry Andric 
20985ffd83dbSDimitry Andric template <typename OpTy>
m_FPToUI(const OpTy & Op)2099*0fca6ea1SDimitry Andric inline CastInst_match<OpTy, FPToUIInst> m_FPToUI(const OpTy &Op) {
2100*0fca6ea1SDimitry Andric   return CastInst_match<OpTy, FPToUIInst>(Op);
21015ffd83dbSDimitry Andric }
21025ffd83dbSDimitry Andric 
21035ffd83dbSDimitry Andric template <typename OpTy>
m_FPToSI(const OpTy & Op)2104*0fca6ea1SDimitry Andric inline CastInst_match<OpTy, FPToSIInst> m_FPToSI(const OpTy &Op) {
2105*0fca6ea1SDimitry Andric   return CastInst_match<OpTy, FPToSIInst>(Op);
21065ffd83dbSDimitry Andric }
21075ffd83dbSDimitry Andric 
21080b57cec5SDimitry Andric template <typename OpTy>
m_FPTrunc(const OpTy & Op)2109*0fca6ea1SDimitry Andric inline CastInst_match<OpTy, FPTruncInst> m_FPTrunc(const OpTy &Op) {
2110*0fca6ea1SDimitry Andric   return CastInst_match<OpTy, FPTruncInst>(Op);
21110b57cec5SDimitry Andric }
21120b57cec5SDimitry Andric 
21130b57cec5SDimitry Andric template <typename OpTy>
m_FPExt(const OpTy & Op)2114*0fca6ea1SDimitry Andric inline CastInst_match<OpTy, FPExtInst> m_FPExt(const OpTy &Op) {
2115*0fca6ea1SDimitry Andric   return CastInst_match<OpTy, FPExtInst>(Op);
21160b57cec5SDimitry Andric }
21170b57cec5SDimitry Andric 
21180b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
21190b57cec5SDimitry Andric // Matchers for control flow.
21200b57cec5SDimitry Andric //
21210b57cec5SDimitry Andric 
21220b57cec5SDimitry Andric struct br_match {
21230b57cec5SDimitry Andric   BasicBlock *&Succ;
21240b57cec5SDimitry Andric 
br_matchbr_match21250b57cec5SDimitry Andric   br_match(BasicBlock *&Succ) : Succ(Succ) {}
21260b57cec5SDimitry Andric 
matchbr_match21270b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
21280b57cec5SDimitry Andric     if (auto *BI = dyn_cast<BranchInst>(V))
21290b57cec5SDimitry Andric       if (BI->isUnconditional()) {
21300b57cec5SDimitry Andric         Succ = BI->getSuccessor(0);
21310b57cec5SDimitry Andric         return true;
21320b57cec5SDimitry Andric       }
21330b57cec5SDimitry Andric     return false;
21340b57cec5SDimitry Andric   }
21350b57cec5SDimitry Andric };
21360b57cec5SDimitry Andric 
m_UnconditionalBr(BasicBlock * & Succ)21370b57cec5SDimitry Andric inline br_match m_UnconditionalBr(BasicBlock *&Succ) { return br_match(Succ); }
21380b57cec5SDimitry Andric 
21398bcb0991SDimitry Andric template <typename Cond_t, typename TrueBlock_t, typename FalseBlock_t>
21408bcb0991SDimitry Andric struct brc_match {
21410b57cec5SDimitry Andric   Cond_t Cond;
21428bcb0991SDimitry Andric   TrueBlock_t T;
21438bcb0991SDimitry Andric   FalseBlock_t F;
21440b57cec5SDimitry Andric 
brc_matchbrc_match21458bcb0991SDimitry Andric   brc_match(const Cond_t &C, const TrueBlock_t &t, const FalseBlock_t &f)
21460b57cec5SDimitry Andric       : Cond(C), T(t), F(f) {}
21470b57cec5SDimitry Andric 
matchbrc_match21480b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
21490b57cec5SDimitry Andric     if (auto *BI = dyn_cast<BranchInst>(V))
21508bcb0991SDimitry Andric       if (BI->isConditional() && Cond.match(BI->getCondition()))
21518bcb0991SDimitry Andric         return T.match(BI->getSuccessor(0)) && F.match(BI->getSuccessor(1));
21520b57cec5SDimitry Andric     return false;
21530b57cec5SDimitry Andric   }
21540b57cec5SDimitry Andric };
21550b57cec5SDimitry Andric 
21560b57cec5SDimitry Andric template <typename Cond_t>
21578bcb0991SDimitry Andric inline brc_match<Cond_t, bind_ty<BasicBlock>, bind_ty<BasicBlock>>
m_Br(const Cond_t & C,BasicBlock * & T,BasicBlock * & F)21588bcb0991SDimitry Andric m_Br(const Cond_t &C, BasicBlock *&T, BasicBlock *&F) {
21598bcb0991SDimitry Andric   return brc_match<Cond_t, bind_ty<BasicBlock>, bind_ty<BasicBlock>>(
21608bcb0991SDimitry Andric       C, m_BasicBlock(T), m_BasicBlock(F));
21618bcb0991SDimitry Andric }
21628bcb0991SDimitry Andric 
21638bcb0991SDimitry Andric template <typename Cond_t, typename TrueBlock_t, typename FalseBlock_t>
21648bcb0991SDimitry Andric inline brc_match<Cond_t, TrueBlock_t, FalseBlock_t>
m_Br(const Cond_t & C,const TrueBlock_t & T,const FalseBlock_t & F)21658bcb0991SDimitry Andric m_Br(const Cond_t &C, const TrueBlock_t &T, const FalseBlock_t &F) {
21668bcb0991SDimitry Andric   return brc_match<Cond_t, TrueBlock_t, FalseBlock_t>(C, T, F);
21670b57cec5SDimitry Andric }
21680b57cec5SDimitry Andric 
21690b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
21700b57cec5SDimitry Andric // Matchers for max/min idioms, eg: "select (sgt x, y), x, y" -> smax(x,y).
21710b57cec5SDimitry Andric //
21720b57cec5SDimitry Andric 
21730b57cec5SDimitry Andric template <typename CmpInst_t, typename LHS_t, typename RHS_t, typename Pred_t,
21740b57cec5SDimitry Andric           bool Commutable = false>
21750b57cec5SDimitry Andric struct MaxMin_match {
2176fe6060f1SDimitry Andric   using PredType = Pred_t;
21770b57cec5SDimitry Andric   LHS_t L;
21780b57cec5SDimitry Andric   RHS_t R;
21790b57cec5SDimitry Andric 
21800b57cec5SDimitry Andric   // The evaluation order is always stable, regardless of Commutability.
21810b57cec5SDimitry Andric   // The LHS is always matched first.
MaxMin_matchMaxMin_match21820b57cec5SDimitry Andric   MaxMin_match(const LHS_t &LHS, const RHS_t &RHS) : L(LHS), R(RHS) {}
21830b57cec5SDimitry Andric 
matchMaxMin_match21840b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
2185e8d8bef9SDimitry Andric     if (auto *II = dyn_cast<IntrinsicInst>(V)) {
2186e8d8bef9SDimitry Andric       Intrinsic::ID IID = II->getIntrinsicID();
2187e8d8bef9SDimitry Andric       if ((IID == Intrinsic::smax && Pred_t::match(ICmpInst::ICMP_SGT)) ||
2188e8d8bef9SDimitry Andric           (IID == Intrinsic::smin && Pred_t::match(ICmpInst::ICMP_SLT)) ||
2189e8d8bef9SDimitry Andric           (IID == Intrinsic::umax && Pred_t::match(ICmpInst::ICMP_UGT)) ||
2190e8d8bef9SDimitry Andric           (IID == Intrinsic::umin && Pred_t::match(ICmpInst::ICMP_ULT))) {
2191e8d8bef9SDimitry Andric         Value *LHS = II->getOperand(0), *RHS = II->getOperand(1);
2192e8d8bef9SDimitry Andric         return (L.match(LHS) && R.match(RHS)) ||
2193e8d8bef9SDimitry Andric                (Commutable && L.match(RHS) && R.match(LHS));
2194e8d8bef9SDimitry Andric       }
2195e8d8bef9SDimitry Andric     }
21960b57cec5SDimitry Andric     // Look for "(x pred y) ? x : y" or "(x pred y) ? y : x".
21970b57cec5SDimitry Andric     auto *SI = dyn_cast<SelectInst>(V);
21980b57cec5SDimitry Andric     if (!SI)
21990b57cec5SDimitry Andric       return false;
22000b57cec5SDimitry Andric     auto *Cmp = dyn_cast<CmpInst_t>(SI->getCondition());
22010b57cec5SDimitry Andric     if (!Cmp)
22020b57cec5SDimitry Andric       return false;
22030b57cec5SDimitry Andric     // At this point we have a select conditioned on a comparison.  Check that
22040b57cec5SDimitry Andric     // it is the values returned by the select that are being compared.
2205fe6060f1SDimitry Andric     auto *TrueVal = SI->getTrueValue();
2206fe6060f1SDimitry Andric     auto *FalseVal = SI->getFalseValue();
2207fe6060f1SDimitry Andric     auto *LHS = Cmp->getOperand(0);
2208fe6060f1SDimitry Andric     auto *RHS = Cmp->getOperand(1);
22090b57cec5SDimitry Andric     if ((TrueVal != LHS || FalseVal != RHS) &&
22100b57cec5SDimitry Andric         (TrueVal != RHS || FalseVal != LHS))
22110b57cec5SDimitry Andric       return false;
22120b57cec5SDimitry Andric     typename CmpInst_t::Predicate Pred =
22130b57cec5SDimitry Andric         LHS == TrueVal ? Cmp->getPredicate() : Cmp->getInversePredicate();
22140b57cec5SDimitry Andric     // Does "(x pred y) ? x : y" represent the desired max/min operation?
22150b57cec5SDimitry Andric     if (!Pred_t::match(Pred))
22160b57cec5SDimitry Andric       return false;
22170b57cec5SDimitry Andric     // It does!  Bind the operands.
22180b57cec5SDimitry Andric     return (L.match(LHS) && R.match(RHS)) ||
22190b57cec5SDimitry Andric            (Commutable && L.match(RHS) && R.match(LHS));
22200b57cec5SDimitry Andric   }
22210b57cec5SDimitry Andric };
22220b57cec5SDimitry Andric 
22230b57cec5SDimitry Andric /// Helper class for identifying signed max predicates.
22240b57cec5SDimitry Andric struct smax_pred_ty {
matchsmax_pred_ty22250b57cec5SDimitry Andric   static bool match(ICmpInst::Predicate Pred) {
22260b57cec5SDimitry Andric     return Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SGE;
22270b57cec5SDimitry Andric   }
22280b57cec5SDimitry Andric };
22290b57cec5SDimitry Andric 
22300b57cec5SDimitry Andric /// Helper class for identifying signed min predicates.
22310b57cec5SDimitry Andric struct smin_pred_ty {
matchsmin_pred_ty22320b57cec5SDimitry Andric   static bool match(ICmpInst::Predicate Pred) {
22330b57cec5SDimitry Andric     return Pred == CmpInst::ICMP_SLT || Pred == CmpInst::ICMP_SLE;
22340b57cec5SDimitry Andric   }
22350b57cec5SDimitry Andric };
22360b57cec5SDimitry Andric 
22370b57cec5SDimitry Andric /// Helper class for identifying unsigned max predicates.
22380b57cec5SDimitry Andric struct umax_pred_ty {
matchumax_pred_ty22390b57cec5SDimitry Andric   static bool match(ICmpInst::Predicate Pred) {
22400b57cec5SDimitry Andric     return Pred == CmpInst::ICMP_UGT || Pred == CmpInst::ICMP_UGE;
22410b57cec5SDimitry Andric   }
22420b57cec5SDimitry Andric };
22430b57cec5SDimitry Andric 
22440b57cec5SDimitry Andric /// Helper class for identifying unsigned min predicates.
22450b57cec5SDimitry Andric struct umin_pred_ty {
matchumin_pred_ty22460b57cec5SDimitry Andric   static bool match(ICmpInst::Predicate Pred) {
22470b57cec5SDimitry Andric     return Pred == CmpInst::ICMP_ULT || Pred == CmpInst::ICMP_ULE;
22480b57cec5SDimitry Andric   }
22490b57cec5SDimitry Andric };
22500b57cec5SDimitry Andric 
22510b57cec5SDimitry Andric /// Helper class for identifying ordered max predicates.
22520b57cec5SDimitry Andric struct ofmax_pred_ty {
matchofmax_pred_ty22530b57cec5SDimitry Andric   static bool match(FCmpInst::Predicate Pred) {
22540b57cec5SDimitry Andric     return Pred == CmpInst::FCMP_OGT || Pred == CmpInst::FCMP_OGE;
22550b57cec5SDimitry Andric   }
22560b57cec5SDimitry Andric };
22570b57cec5SDimitry Andric 
22580b57cec5SDimitry Andric /// Helper class for identifying ordered min predicates.
22590b57cec5SDimitry Andric struct ofmin_pred_ty {
matchofmin_pred_ty22600b57cec5SDimitry Andric   static bool match(FCmpInst::Predicate Pred) {
22610b57cec5SDimitry Andric     return Pred == CmpInst::FCMP_OLT || Pred == CmpInst::FCMP_OLE;
22620b57cec5SDimitry Andric   }
22630b57cec5SDimitry Andric };
22640b57cec5SDimitry Andric 
22650b57cec5SDimitry Andric /// Helper class for identifying unordered max predicates.
22660b57cec5SDimitry Andric struct ufmax_pred_ty {
matchufmax_pred_ty22670b57cec5SDimitry Andric   static bool match(FCmpInst::Predicate Pred) {
22680b57cec5SDimitry Andric     return Pred == CmpInst::FCMP_UGT || Pred == CmpInst::FCMP_UGE;
22690b57cec5SDimitry Andric   }
22700b57cec5SDimitry Andric };
22710b57cec5SDimitry Andric 
22720b57cec5SDimitry Andric /// Helper class for identifying unordered min predicates.
22730b57cec5SDimitry Andric struct ufmin_pred_ty {
matchufmin_pred_ty22740b57cec5SDimitry Andric   static bool match(FCmpInst::Predicate Pred) {
22750b57cec5SDimitry Andric     return Pred == CmpInst::FCMP_ULT || Pred == CmpInst::FCMP_ULE;
22760b57cec5SDimitry Andric   }
22770b57cec5SDimitry Andric };
22780b57cec5SDimitry Andric 
22790b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_SMax(const LHS & L,const RHS & R)22800b57cec5SDimitry Andric inline MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty> m_SMax(const LHS &L,
22810b57cec5SDimitry Andric                                                              const RHS &R) {
22820b57cec5SDimitry Andric   return MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty>(L, R);
22830b57cec5SDimitry Andric }
22840b57cec5SDimitry Andric 
22850b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_SMin(const LHS & L,const RHS & R)22860b57cec5SDimitry Andric inline MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty> m_SMin(const LHS &L,
22870b57cec5SDimitry Andric                                                              const RHS &R) {
22880b57cec5SDimitry Andric   return MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty>(L, R);
22890b57cec5SDimitry Andric }
22900b57cec5SDimitry Andric 
22910b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_UMax(const LHS & L,const RHS & R)22920b57cec5SDimitry Andric inline MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty> m_UMax(const LHS &L,
22930b57cec5SDimitry Andric                                                              const RHS &R) {
22940b57cec5SDimitry Andric   return MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty>(L, R);
22950b57cec5SDimitry Andric }
22960b57cec5SDimitry Andric 
22970b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_UMin(const LHS & L,const RHS & R)22980b57cec5SDimitry Andric inline MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty> m_UMin(const LHS &L,
22990b57cec5SDimitry Andric                                                              const RHS &R) {
23000b57cec5SDimitry Andric   return MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty>(L, R);
23010b57cec5SDimitry Andric }
23020b57cec5SDimitry Andric 
2303e8d8bef9SDimitry Andric template <typename LHS, typename RHS>
2304e8d8bef9SDimitry Andric inline match_combine_or<
2305e8d8bef9SDimitry Andric     match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty>,
2306e8d8bef9SDimitry Andric                      MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty>>,
2307e8d8bef9SDimitry Andric     match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty>,
2308e8d8bef9SDimitry Andric                      MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty>>>
m_MaxOrMin(const LHS & L,const RHS & R)2309e8d8bef9SDimitry Andric m_MaxOrMin(const LHS &L, const RHS &R) {
2310e8d8bef9SDimitry Andric   return m_CombineOr(m_CombineOr(m_SMax(L, R), m_SMin(L, R)),
2311e8d8bef9SDimitry Andric                      m_CombineOr(m_UMax(L, R), m_UMin(L, R)));
2312e8d8bef9SDimitry Andric }
2313e8d8bef9SDimitry Andric 
23140b57cec5SDimitry Andric /// Match an 'ordered' floating point maximum function.
23150b57cec5SDimitry Andric /// Floating point has one special value 'NaN'. Therefore, there is no total
23160b57cec5SDimitry Andric /// order. However, if we can ignore the 'NaN' value (for example, because of a
23170b57cec5SDimitry Andric /// 'no-nans-float-math' flag) a combination of a fcmp and select has 'maximum'
23180b57cec5SDimitry Andric /// semantics. In the presence of 'NaN' we have to preserve the original
23190b57cec5SDimitry Andric /// select(fcmp(ogt/ge, L, R), L, R) semantics matched by this predicate.
23200b57cec5SDimitry Andric ///
23210b57cec5SDimitry Andric ///                         max(L, R)  iff L and R are not NaN
23220b57cec5SDimitry Andric ///  m_OrdFMax(L, R) =      R          iff L or R are NaN
23230b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_OrdFMax(const LHS & L,const RHS & R)23240b57cec5SDimitry Andric inline MaxMin_match<FCmpInst, LHS, RHS, ofmax_pred_ty> m_OrdFMax(const LHS &L,
23250b57cec5SDimitry Andric                                                                  const RHS &R) {
23260b57cec5SDimitry Andric   return MaxMin_match<FCmpInst, LHS, RHS, ofmax_pred_ty>(L, R);
23270b57cec5SDimitry Andric }
23280b57cec5SDimitry Andric 
23290b57cec5SDimitry Andric /// Match an 'ordered' floating point minimum function.
23300b57cec5SDimitry Andric /// Floating point has one special value 'NaN'. Therefore, there is no total
23310b57cec5SDimitry Andric /// order. However, if we can ignore the 'NaN' value (for example, because of a
23320b57cec5SDimitry Andric /// 'no-nans-float-math' flag) a combination of a fcmp and select has 'minimum'
23330b57cec5SDimitry Andric /// semantics. In the presence of 'NaN' we have to preserve the original
23340b57cec5SDimitry Andric /// select(fcmp(olt/le, L, R), L, R) semantics matched by this predicate.
23350b57cec5SDimitry Andric ///
23360b57cec5SDimitry Andric ///                         min(L, R)  iff L and R are not NaN
23370b57cec5SDimitry Andric ///  m_OrdFMin(L, R) =      R          iff L or R are NaN
23380b57cec5SDimitry Andric template <typename LHS, typename RHS>
m_OrdFMin(const LHS & L,const RHS & R)23390b57cec5SDimitry Andric inline MaxMin_match<FCmpInst, LHS, RHS, ofmin_pred_ty> m_OrdFMin(const LHS &L,
23400b57cec5SDimitry Andric                                                                  const RHS &R) {
23410b57cec5SDimitry Andric   return MaxMin_match<FCmpInst, LHS, RHS, ofmin_pred_ty>(L, R);
23420b57cec5SDimitry Andric }
23430b57cec5SDimitry Andric 
23440b57cec5SDimitry Andric /// Match an 'unordered' floating point maximum function.
23450b57cec5SDimitry Andric /// Floating point has one special value 'NaN'. Therefore, there is no total
23460b57cec5SDimitry Andric /// order. However, if we can ignore the 'NaN' value (for example, because of a
23470b57cec5SDimitry Andric /// 'no-nans-float-math' flag) a combination of a fcmp and select has 'maximum'
23480b57cec5SDimitry Andric /// semantics. In the presence of 'NaN' we have to preserve the original
23490b57cec5SDimitry Andric /// select(fcmp(ugt/ge, L, R), L, R) semantics matched by this predicate.
23500b57cec5SDimitry Andric ///
23510b57cec5SDimitry Andric ///                         max(L, R)  iff L and R are not NaN
23520b57cec5SDimitry Andric ///  m_UnordFMax(L, R) =    L          iff L or R are NaN
23530b57cec5SDimitry Andric template <typename LHS, typename RHS>
23540b57cec5SDimitry Andric inline MaxMin_match<FCmpInst, LHS, RHS, ufmax_pred_ty>
m_UnordFMax(const LHS & L,const RHS & R)23550b57cec5SDimitry Andric m_UnordFMax(const LHS &L, const RHS &R) {
23560b57cec5SDimitry Andric   return MaxMin_match<FCmpInst, LHS, RHS, ufmax_pred_ty>(L, R);
23570b57cec5SDimitry Andric }
23580b57cec5SDimitry Andric 
23590b57cec5SDimitry Andric /// Match an 'unordered' floating point minimum function.
23600b57cec5SDimitry Andric /// Floating point has one special value 'NaN'. Therefore, there is no total
23610b57cec5SDimitry Andric /// order. However, if we can ignore the 'NaN' value (for example, because of a
23620b57cec5SDimitry Andric /// 'no-nans-float-math' flag) a combination of a fcmp and select has 'minimum'
23630b57cec5SDimitry Andric /// semantics. In the presence of 'NaN' we have to preserve the original
23640b57cec5SDimitry Andric /// select(fcmp(ult/le, L, R), L, R) semantics matched by this predicate.
23650b57cec5SDimitry Andric ///
23660b57cec5SDimitry Andric ///                          min(L, R)  iff L and R are not NaN
23670b57cec5SDimitry Andric ///  m_UnordFMin(L, R) =     L          iff L or R are NaN
23680b57cec5SDimitry Andric template <typename LHS, typename RHS>
23690b57cec5SDimitry Andric inline MaxMin_match<FCmpInst, LHS, RHS, ufmin_pred_ty>
m_UnordFMin(const LHS & L,const RHS & R)23700b57cec5SDimitry Andric m_UnordFMin(const LHS &L, const RHS &R) {
23710b57cec5SDimitry Andric   return MaxMin_match<FCmpInst, LHS, RHS, ufmin_pred_ty>(L, R);
23720b57cec5SDimitry Andric }
23730b57cec5SDimitry Andric 
2374*0fca6ea1SDimitry Andric /// Matches a 'Not' as 'xor V, -1' or 'xor -1, V'.
2375*0fca6ea1SDimitry Andric /// NOTE: we first match the 'Not' (by matching '-1'),
2376*0fca6ea1SDimitry Andric /// and only then match the inner matcher!
2377*0fca6ea1SDimitry Andric template <typename ValTy>
2378*0fca6ea1SDimitry Andric inline BinaryOp_match<cst_pred_ty<is_all_ones>, ValTy, Instruction::Xor, true>
m_Not(const ValTy & V)2379*0fca6ea1SDimitry Andric m_Not(const ValTy &V) {
2380*0fca6ea1SDimitry Andric   return m_c_Xor(m_AllOnes(), V);
2381*0fca6ea1SDimitry Andric }
2382*0fca6ea1SDimitry Andric 
2383*0fca6ea1SDimitry Andric template <typename ValTy>
2384*0fca6ea1SDimitry Andric inline BinaryOp_match<cst_pred_ty<is_all_ones, false>, ValTy, Instruction::Xor,
2385*0fca6ea1SDimitry Andric                       true>
m_NotForbidPoison(const ValTy & V)2386*0fca6ea1SDimitry Andric m_NotForbidPoison(const ValTy &V) {
2387*0fca6ea1SDimitry Andric   return m_c_Xor(m_AllOnesForbidPoison(), V);
2388*0fca6ea1SDimitry Andric }
2389*0fca6ea1SDimitry Andric 
23900b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
23915ffd83dbSDimitry Andric // Matchers for overflow check patterns: e.g. (a + b) u< a, (a ^ -1) <u b
23925ffd83dbSDimitry Andric // Note that S might be matched to other instructions than AddInst.
23930b57cec5SDimitry Andric //
23940b57cec5SDimitry Andric 
23950b57cec5SDimitry Andric template <typename LHS_t, typename RHS_t, typename Sum_t>
23960b57cec5SDimitry Andric struct UAddWithOverflow_match {
23970b57cec5SDimitry Andric   LHS_t L;
23980b57cec5SDimitry Andric   RHS_t R;
23990b57cec5SDimitry Andric   Sum_t S;
24000b57cec5SDimitry Andric 
UAddWithOverflow_matchUAddWithOverflow_match24010b57cec5SDimitry Andric   UAddWithOverflow_match(const LHS_t &L, const RHS_t &R, const Sum_t &S)
24020b57cec5SDimitry Andric       : L(L), R(R), S(S) {}
24030b57cec5SDimitry Andric 
matchUAddWithOverflow_match24040b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
24050b57cec5SDimitry Andric     Value *ICmpLHS, *ICmpRHS;
24060b57cec5SDimitry Andric     ICmpInst::Predicate Pred;
24070b57cec5SDimitry Andric     if (!m_ICmp(Pred, m_Value(ICmpLHS), m_Value(ICmpRHS)).match(V))
24080b57cec5SDimitry Andric       return false;
24090b57cec5SDimitry Andric 
24100b57cec5SDimitry Andric     Value *AddLHS, *AddRHS;
24110b57cec5SDimitry Andric     auto AddExpr = m_Add(m_Value(AddLHS), m_Value(AddRHS));
24120b57cec5SDimitry Andric 
24130b57cec5SDimitry Andric     // (a + b) u< a, (a + b) u< b
24140b57cec5SDimitry Andric     if (Pred == ICmpInst::ICMP_ULT)
24150b57cec5SDimitry Andric       if (AddExpr.match(ICmpLHS) && (ICmpRHS == AddLHS || ICmpRHS == AddRHS))
24160b57cec5SDimitry Andric         return L.match(AddLHS) && R.match(AddRHS) && S.match(ICmpLHS);
24170b57cec5SDimitry Andric 
24180b57cec5SDimitry Andric     // a >u (a + b), b >u (a + b)
24190b57cec5SDimitry Andric     if (Pred == ICmpInst::ICMP_UGT)
24200b57cec5SDimitry Andric       if (AddExpr.match(ICmpRHS) && (ICmpLHS == AddLHS || ICmpLHS == AddRHS))
24210b57cec5SDimitry Andric         return L.match(AddLHS) && R.match(AddRHS) && S.match(ICmpRHS);
24220b57cec5SDimitry Andric 
24235ffd83dbSDimitry Andric     Value *Op1;
2424*0fca6ea1SDimitry Andric     auto XorExpr = m_OneUse(m_Not(m_Value(Op1)));
2425*0fca6ea1SDimitry Andric     // (~a) <u b
24265ffd83dbSDimitry Andric     if (Pred == ICmpInst::ICMP_ULT) {
24275ffd83dbSDimitry Andric       if (XorExpr.match(ICmpLHS))
24285ffd83dbSDimitry Andric         return L.match(Op1) && R.match(ICmpRHS) && S.match(ICmpLHS);
24295ffd83dbSDimitry Andric     }
2430*0fca6ea1SDimitry Andric     //  b > u (~a)
24315ffd83dbSDimitry Andric     if (Pred == ICmpInst::ICMP_UGT) {
24325ffd83dbSDimitry Andric       if (XorExpr.match(ICmpRHS))
24335ffd83dbSDimitry Andric         return L.match(Op1) && R.match(ICmpLHS) && S.match(ICmpRHS);
24345ffd83dbSDimitry Andric     }
24355ffd83dbSDimitry Andric 
24360b57cec5SDimitry Andric     // Match special-case for increment-by-1.
24370b57cec5SDimitry Andric     if (Pred == ICmpInst::ICMP_EQ) {
24380b57cec5SDimitry Andric       // (a + 1) == 0
24390b57cec5SDimitry Andric       // (1 + a) == 0
24400b57cec5SDimitry Andric       if (AddExpr.match(ICmpLHS) && m_ZeroInt().match(ICmpRHS) &&
24410b57cec5SDimitry Andric           (m_One().match(AddLHS) || m_One().match(AddRHS)))
24420b57cec5SDimitry Andric         return L.match(AddLHS) && R.match(AddRHS) && S.match(ICmpLHS);
24430b57cec5SDimitry Andric       // 0 == (a + 1)
24440b57cec5SDimitry Andric       // 0 == (1 + a)
24450b57cec5SDimitry Andric       if (m_ZeroInt().match(ICmpLHS) && AddExpr.match(ICmpRHS) &&
24460b57cec5SDimitry Andric           (m_One().match(AddLHS) || m_One().match(AddRHS)))
24470b57cec5SDimitry Andric         return L.match(AddLHS) && R.match(AddRHS) && S.match(ICmpRHS);
24480b57cec5SDimitry Andric     }
24490b57cec5SDimitry Andric 
24500b57cec5SDimitry Andric     return false;
24510b57cec5SDimitry Andric   }
24520b57cec5SDimitry Andric };
24530b57cec5SDimitry Andric 
24540b57cec5SDimitry Andric /// Match an icmp instruction checking for unsigned overflow on addition.
24550b57cec5SDimitry Andric ///
24560b57cec5SDimitry Andric /// S is matched to the addition whose result is being checked for overflow, and
24570b57cec5SDimitry Andric /// L and R are matched to the LHS and RHS of S.
24580b57cec5SDimitry Andric template <typename LHS_t, typename RHS_t, typename Sum_t>
24590b57cec5SDimitry Andric UAddWithOverflow_match<LHS_t, RHS_t, Sum_t>
m_UAddWithOverflow(const LHS_t & L,const RHS_t & R,const Sum_t & S)24600b57cec5SDimitry Andric m_UAddWithOverflow(const LHS_t &L, const RHS_t &R, const Sum_t &S) {
24610b57cec5SDimitry Andric   return UAddWithOverflow_match<LHS_t, RHS_t, Sum_t>(L, R, S);
24620b57cec5SDimitry Andric }
24630b57cec5SDimitry Andric 
24640b57cec5SDimitry Andric template <typename Opnd_t> struct Argument_match {
24650b57cec5SDimitry Andric   unsigned OpI;
24660b57cec5SDimitry Andric   Opnd_t Val;
24670b57cec5SDimitry Andric 
Argument_matchArgument_match24680b57cec5SDimitry Andric   Argument_match(unsigned OpIdx, const Opnd_t &V) : OpI(OpIdx), Val(V) {}
24690b57cec5SDimitry Andric 
matchArgument_match24700b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
24710b57cec5SDimitry Andric     // FIXME: Should likely be switched to use `CallBase`.
24720b57cec5SDimitry Andric     if (const auto *CI = dyn_cast<CallInst>(V))
24730b57cec5SDimitry Andric       return Val.match(CI->getArgOperand(OpI));
24740b57cec5SDimitry Andric     return false;
24750b57cec5SDimitry Andric   }
24760b57cec5SDimitry Andric };
24770b57cec5SDimitry Andric 
24780b57cec5SDimitry Andric /// Match an argument.
24790b57cec5SDimitry Andric template <unsigned OpI, typename Opnd_t>
m_Argument(const Opnd_t & Op)24800b57cec5SDimitry Andric inline Argument_match<Opnd_t> m_Argument(const Opnd_t &Op) {
24810b57cec5SDimitry Andric   return Argument_match<Opnd_t>(OpI, Op);
24820b57cec5SDimitry Andric }
24830b57cec5SDimitry Andric 
24840b57cec5SDimitry Andric /// Intrinsic matchers.
24850b57cec5SDimitry Andric struct IntrinsicID_match {
24860b57cec5SDimitry Andric   unsigned ID;
24870b57cec5SDimitry Andric 
IntrinsicID_matchIntrinsicID_match24880b57cec5SDimitry Andric   IntrinsicID_match(Intrinsic::ID IntrID) : ID(IntrID) {}
24890b57cec5SDimitry Andric 
matchIntrinsicID_match24900b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
24910b57cec5SDimitry Andric     if (const auto *CI = dyn_cast<CallInst>(V))
24920b57cec5SDimitry Andric       if (const auto *F = CI->getCalledFunction())
24930b57cec5SDimitry Andric         return F->getIntrinsicID() == ID;
24940b57cec5SDimitry Andric     return false;
24950b57cec5SDimitry Andric   }
24960b57cec5SDimitry Andric };
24970b57cec5SDimitry Andric 
24980b57cec5SDimitry Andric /// Intrinsic matches are combinations of ID matchers, and argument
24990b57cec5SDimitry Andric /// matchers. Higher arity matcher are defined recursively in terms of and-ing
25000b57cec5SDimitry Andric /// them with lower arity matchers. Here's some convenient typedefs for up to
25010b57cec5SDimitry Andric /// several arguments, and more can be added as needed
25020b57cec5SDimitry Andric template <typename T0 = void, typename T1 = void, typename T2 = void,
25030b57cec5SDimitry Andric           typename T3 = void, typename T4 = void, typename T5 = void,
25040b57cec5SDimitry Andric           typename T6 = void, typename T7 = void, typename T8 = void,
25050b57cec5SDimitry Andric           typename T9 = void, typename T10 = void>
25060b57cec5SDimitry Andric struct m_Intrinsic_Ty;
25070b57cec5SDimitry Andric template <typename T0> struct m_Intrinsic_Ty<T0> {
25080b57cec5SDimitry Andric   using Ty = match_combine_and<IntrinsicID_match, Argument_match<T0>>;
25090b57cec5SDimitry Andric };
25100b57cec5SDimitry Andric template <typename T0, typename T1> struct m_Intrinsic_Ty<T0, T1> {
25110b57cec5SDimitry Andric   using Ty =
25120b57cec5SDimitry Andric       match_combine_and<typename m_Intrinsic_Ty<T0>::Ty, Argument_match<T1>>;
25130b57cec5SDimitry Andric };
25140b57cec5SDimitry Andric template <typename T0, typename T1, typename T2>
25150b57cec5SDimitry Andric struct m_Intrinsic_Ty<T0, T1, T2> {
251681ad6265SDimitry Andric   using Ty = match_combine_and<typename m_Intrinsic_Ty<T0, T1>::Ty,
25170b57cec5SDimitry Andric                                Argument_match<T2>>;
25180b57cec5SDimitry Andric };
25190b57cec5SDimitry Andric template <typename T0, typename T1, typename T2, typename T3>
25200b57cec5SDimitry Andric struct m_Intrinsic_Ty<T0, T1, T2, T3> {
252181ad6265SDimitry Andric   using Ty = match_combine_and<typename m_Intrinsic_Ty<T0, T1, T2>::Ty,
25220b57cec5SDimitry Andric                                Argument_match<T3>>;
25230b57cec5SDimitry Andric };
25240b57cec5SDimitry Andric 
2525480093f4SDimitry Andric template <typename T0, typename T1, typename T2, typename T3, typename T4>
2526480093f4SDimitry Andric struct m_Intrinsic_Ty<T0, T1, T2, T3, T4> {
2527480093f4SDimitry Andric   using Ty = match_combine_and<typename m_Intrinsic_Ty<T0, T1, T2, T3>::Ty,
2528480093f4SDimitry Andric                                Argument_match<T4>>;
2529480093f4SDimitry Andric };
2530480093f4SDimitry Andric 
253181ad6265SDimitry Andric template <typename T0, typename T1, typename T2, typename T3, typename T4,
253281ad6265SDimitry Andric           typename T5>
25335ffd83dbSDimitry Andric struct m_Intrinsic_Ty<T0, T1, T2, T3, T4, T5> {
25345ffd83dbSDimitry Andric   using Ty = match_combine_and<typename m_Intrinsic_Ty<T0, T1, T2, T3, T4>::Ty,
25355ffd83dbSDimitry Andric                                Argument_match<T5>>;
25365ffd83dbSDimitry Andric };
25375ffd83dbSDimitry Andric 
25380b57cec5SDimitry Andric /// Match intrinsic calls like this:
25390b57cec5SDimitry Andric /// m_Intrinsic<Intrinsic::fabs>(m_Value(X))
25400b57cec5SDimitry Andric template <Intrinsic::ID IntrID> inline IntrinsicID_match m_Intrinsic() {
25410b57cec5SDimitry Andric   return IntrinsicID_match(IntrID);
25420b57cec5SDimitry Andric }
25430b57cec5SDimitry Andric 
2544fe6060f1SDimitry Andric /// Matches MaskedLoad Intrinsic.
2545fe6060f1SDimitry Andric template <typename Opnd0, typename Opnd1, typename Opnd2, typename Opnd3>
2546fe6060f1SDimitry Andric inline typename m_Intrinsic_Ty<Opnd0, Opnd1, Opnd2, Opnd3>::Ty
2547fe6060f1SDimitry Andric m_MaskedLoad(const Opnd0 &Op0, const Opnd1 &Op1, const Opnd2 &Op2,
2548fe6060f1SDimitry Andric              const Opnd3 &Op3) {
2549fe6060f1SDimitry Andric   return m_Intrinsic<Intrinsic::masked_load>(Op0, Op1, Op2, Op3);
2550fe6060f1SDimitry Andric }
2551fe6060f1SDimitry Andric 
255281ad6265SDimitry Andric /// Matches MaskedGather Intrinsic.
255381ad6265SDimitry Andric template <typename Opnd0, typename Opnd1, typename Opnd2, typename Opnd3>
255481ad6265SDimitry Andric inline typename m_Intrinsic_Ty<Opnd0, Opnd1, Opnd2, Opnd3>::Ty
255581ad6265SDimitry Andric m_MaskedGather(const Opnd0 &Op0, const Opnd1 &Op1, const Opnd2 &Op2,
255681ad6265SDimitry Andric                const Opnd3 &Op3) {
255781ad6265SDimitry Andric   return m_Intrinsic<Intrinsic::masked_gather>(Op0, Op1, Op2, Op3);
255881ad6265SDimitry Andric }
255981ad6265SDimitry Andric 
25600b57cec5SDimitry Andric template <Intrinsic::ID IntrID, typename T0>
25610b57cec5SDimitry Andric inline typename m_Intrinsic_Ty<T0>::Ty m_Intrinsic(const T0 &Op0) {
25620b57cec5SDimitry Andric   return m_CombineAnd(m_Intrinsic<IntrID>(), m_Argument<0>(Op0));
25630b57cec5SDimitry Andric }
25640b57cec5SDimitry Andric 
25650b57cec5SDimitry Andric template <Intrinsic::ID IntrID, typename T0, typename T1>
25660b57cec5SDimitry Andric inline typename m_Intrinsic_Ty<T0, T1>::Ty m_Intrinsic(const T0 &Op0,
25670b57cec5SDimitry Andric                                                        const T1 &Op1) {
25680b57cec5SDimitry Andric   return m_CombineAnd(m_Intrinsic<IntrID>(Op0), m_Argument<1>(Op1));
25690b57cec5SDimitry Andric }
25700b57cec5SDimitry Andric 
25710b57cec5SDimitry Andric template <Intrinsic::ID IntrID, typename T0, typename T1, typename T2>
25720b57cec5SDimitry Andric inline typename m_Intrinsic_Ty<T0, T1, T2>::Ty
25730b57cec5SDimitry Andric m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2) {
25740b57cec5SDimitry Andric   return m_CombineAnd(m_Intrinsic<IntrID>(Op0, Op1), m_Argument<2>(Op2));
25750b57cec5SDimitry Andric }
25760b57cec5SDimitry Andric 
25770b57cec5SDimitry Andric template <Intrinsic::ID IntrID, typename T0, typename T1, typename T2,
25780b57cec5SDimitry Andric           typename T3>
25790b57cec5SDimitry Andric inline typename m_Intrinsic_Ty<T0, T1, T2, T3>::Ty
25800b57cec5SDimitry Andric m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2, const T3 &Op3) {
25810b57cec5SDimitry Andric   return m_CombineAnd(m_Intrinsic<IntrID>(Op0, Op1, Op2), m_Argument<3>(Op3));
25820b57cec5SDimitry Andric }
25830b57cec5SDimitry Andric 
2584480093f4SDimitry Andric template <Intrinsic::ID IntrID, typename T0, typename T1, typename T2,
2585480093f4SDimitry Andric           typename T3, typename T4>
2586480093f4SDimitry Andric inline typename m_Intrinsic_Ty<T0, T1, T2, T3, T4>::Ty
2587480093f4SDimitry Andric m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2, const T3 &Op3,
2588480093f4SDimitry Andric             const T4 &Op4) {
2589480093f4SDimitry Andric   return m_CombineAnd(m_Intrinsic<IntrID>(Op0, Op1, Op2, Op3),
2590480093f4SDimitry Andric                       m_Argument<4>(Op4));
2591480093f4SDimitry Andric }
2592480093f4SDimitry Andric 
25935ffd83dbSDimitry Andric template <Intrinsic::ID IntrID, typename T0, typename T1, typename T2,
25945ffd83dbSDimitry Andric           typename T3, typename T4, typename T5>
25955ffd83dbSDimitry Andric inline typename m_Intrinsic_Ty<T0, T1, T2, T3, T4, T5>::Ty
25965ffd83dbSDimitry Andric m_Intrinsic(const T0 &Op0, const T1 &Op1, const T2 &Op2, const T3 &Op3,
25975ffd83dbSDimitry Andric             const T4 &Op4, const T5 &Op5) {
25985ffd83dbSDimitry Andric   return m_CombineAnd(m_Intrinsic<IntrID>(Op0, Op1, Op2, Op3, Op4),
25995ffd83dbSDimitry Andric                       m_Argument<5>(Op5));
26005ffd83dbSDimitry Andric }
26015ffd83dbSDimitry Andric 
26020b57cec5SDimitry Andric // Helper intrinsic matching specializations.
26030b57cec5SDimitry Andric template <typename Opnd0>
26040b57cec5SDimitry Andric inline typename m_Intrinsic_Ty<Opnd0>::Ty m_BitReverse(const Opnd0 &Op0) {
26050b57cec5SDimitry Andric   return m_Intrinsic<Intrinsic::bitreverse>(Op0);
26060b57cec5SDimitry Andric }
26070b57cec5SDimitry Andric 
26080b57cec5SDimitry Andric template <typename Opnd0>
26090b57cec5SDimitry Andric inline typename m_Intrinsic_Ty<Opnd0>::Ty m_BSwap(const Opnd0 &Op0) {
26100b57cec5SDimitry Andric   return m_Intrinsic<Intrinsic::bswap>(Op0);
26110b57cec5SDimitry Andric }
26120b57cec5SDimitry Andric 
26130b57cec5SDimitry Andric template <typename Opnd0>
26140b57cec5SDimitry Andric inline typename m_Intrinsic_Ty<Opnd0>::Ty m_FAbs(const Opnd0 &Op0) {
26150b57cec5SDimitry Andric   return m_Intrinsic<Intrinsic::fabs>(Op0);
26160b57cec5SDimitry Andric }
26170b57cec5SDimitry Andric 
26180b57cec5SDimitry Andric template <typename Opnd0>
26190b57cec5SDimitry Andric inline typename m_Intrinsic_Ty<Opnd0>::Ty m_FCanonicalize(const Opnd0 &Op0) {
26200b57cec5SDimitry Andric   return m_Intrinsic<Intrinsic::canonicalize>(Op0);
26210b57cec5SDimitry Andric }
26220b57cec5SDimitry Andric 
26230b57cec5SDimitry Andric template <typename Opnd0, typename Opnd1>
26240b57cec5SDimitry Andric inline typename m_Intrinsic_Ty<Opnd0, Opnd1>::Ty m_FMin(const Opnd0 &Op0,
26250b57cec5SDimitry Andric                                                         const Opnd1 &Op1) {
26260b57cec5SDimitry Andric   return m_Intrinsic<Intrinsic::minnum>(Op0, Op1);
26270b57cec5SDimitry Andric }
26280b57cec5SDimitry Andric 
26290b57cec5SDimitry Andric template <typename Opnd0, typename Opnd1>
26300b57cec5SDimitry Andric inline typename m_Intrinsic_Ty<Opnd0, Opnd1>::Ty m_FMax(const Opnd0 &Op0,
26310b57cec5SDimitry Andric                                                         const Opnd1 &Op1) {
26320b57cec5SDimitry Andric   return m_Intrinsic<Intrinsic::maxnum>(Op0, Op1);
26330b57cec5SDimitry Andric }
26340b57cec5SDimitry Andric 
2635e8d8bef9SDimitry Andric template <typename Opnd0, typename Opnd1, typename Opnd2>
2636e8d8bef9SDimitry Andric inline typename m_Intrinsic_Ty<Opnd0, Opnd1, Opnd2>::Ty
2637e8d8bef9SDimitry Andric m_FShl(const Opnd0 &Op0, const Opnd1 &Op1, const Opnd2 &Op2) {
2638e8d8bef9SDimitry Andric   return m_Intrinsic<Intrinsic::fshl>(Op0, Op1, Op2);
2639e8d8bef9SDimitry Andric }
2640e8d8bef9SDimitry Andric 
2641e8d8bef9SDimitry Andric template <typename Opnd0, typename Opnd1, typename Opnd2>
2642e8d8bef9SDimitry Andric inline typename m_Intrinsic_Ty<Opnd0, Opnd1, Opnd2>::Ty
2643e8d8bef9SDimitry Andric m_FShr(const Opnd0 &Op0, const Opnd1 &Op1, const Opnd2 &Op2) {
2644e8d8bef9SDimitry Andric   return m_Intrinsic<Intrinsic::fshr>(Op0, Op1, Op2);
2645e8d8bef9SDimitry Andric }
2646e8d8bef9SDimitry Andric 
264781ad6265SDimitry Andric template <typename Opnd0>
264881ad6265SDimitry Andric inline typename m_Intrinsic_Ty<Opnd0>::Ty m_Sqrt(const Opnd0 &Op0) {
264981ad6265SDimitry Andric   return m_Intrinsic<Intrinsic::sqrt>(Op0);
265081ad6265SDimitry Andric }
265181ad6265SDimitry Andric 
2652bdd1243dSDimitry Andric template <typename Opnd0, typename Opnd1>
2653bdd1243dSDimitry Andric inline typename m_Intrinsic_Ty<Opnd0, Opnd1>::Ty m_CopySign(const Opnd0 &Op0,
2654bdd1243dSDimitry Andric                                                             const Opnd1 &Op1) {
2655bdd1243dSDimitry Andric   return m_Intrinsic<Intrinsic::copysign>(Op0, Op1);
2656bdd1243dSDimitry Andric }
2657bdd1243dSDimitry Andric 
2658bdd1243dSDimitry Andric template <typename Opnd0>
2659bdd1243dSDimitry Andric inline typename m_Intrinsic_Ty<Opnd0>::Ty m_VecReverse(const Opnd0 &Op0) {
2660*0fca6ea1SDimitry Andric   return m_Intrinsic<Intrinsic::vector_reverse>(Op0);
2661bdd1243dSDimitry Andric }
2662bdd1243dSDimitry Andric 
26630b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
26640b57cec5SDimitry Andric // Matchers for two-operands operators with the operators in either order
26650b57cec5SDimitry Andric //
26660b57cec5SDimitry Andric 
26670b57cec5SDimitry Andric /// Matches a BinaryOperator with LHS and RHS in either order.
26680b57cec5SDimitry Andric template <typename LHS, typename RHS>
26690b57cec5SDimitry Andric inline AnyBinaryOp_match<LHS, RHS, true> m_c_BinOp(const LHS &L, const RHS &R) {
26700b57cec5SDimitry Andric   return AnyBinaryOp_match<LHS, RHS, true>(L, R);
26710b57cec5SDimitry Andric }
26720b57cec5SDimitry Andric 
26730b57cec5SDimitry Andric /// Matches an ICmp with a predicate over LHS and RHS in either order.
26745ffd83dbSDimitry Andric /// Swaps the predicate if operands are commuted.
26750b57cec5SDimitry Andric template <typename LHS, typename RHS>
26760b57cec5SDimitry Andric inline CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate, true>
26770b57cec5SDimitry Andric m_c_ICmp(ICmpInst::Predicate &Pred, const LHS &L, const RHS &R) {
26780b57cec5SDimitry Andric   return CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate, true>(Pred, L,
26790b57cec5SDimitry Andric                                                                        R);
26800b57cec5SDimitry Andric }
26810b57cec5SDimitry Andric 
2682*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
2683*0fca6ea1SDimitry Andric inline CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate, true>
2684*0fca6ea1SDimitry Andric m_c_ICmp(const LHS &L, const RHS &R) {
2685*0fca6ea1SDimitry Andric   return CmpClass_match<LHS, RHS, ICmpInst, ICmpInst::Predicate, true>(L, R);
2686*0fca6ea1SDimitry Andric }
2687*0fca6ea1SDimitry Andric 
2688349cc55cSDimitry Andric /// Matches a specific opcode with LHS and RHS in either order.
2689349cc55cSDimitry Andric template <typename LHS, typename RHS>
2690349cc55cSDimitry Andric inline SpecificBinaryOp_match<LHS, RHS, true>
2691349cc55cSDimitry Andric m_c_BinOp(unsigned Opcode, const LHS &L, const RHS &R) {
2692349cc55cSDimitry Andric   return SpecificBinaryOp_match<LHS, RHS, true>(Opcode, L, R);
2693349cc55cSDimitry Andric }
2694349cc55cSDimitry Andric 
26950b57cec5SDimitry Andric /// Matches a Add with LHS and RHS in either order.
26960b57cec5SDimitry Andric template <typename LHS, typename RHS>
26970b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::Add, true> m_c_Add(const LHS &L,
26980b57cec5SDimitry Andric                                                                 const RHS &R) {
26990b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::Add, true>(L, R);
27000b57cec5SDimitry Andric }
27010b57cec5SDimitry Andric 
27020b57cec5SDimitry Andric /// Matches a Mul with LHS and RHS in either order.
27030b57cec5SDimitry Andric template <typename LHS, typename RHS>
27040b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::Mul, true> m_c_Mul(const LHS &L,
27050b57cec5SDimitry Andric                                                                 const RHS &R) {
27060b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::Mul, true>(L, R);
27070b57cec5SDimitry Andric }
27080b57cec5SDimitry Andric 
27090b57cec5SDimitry Andric /// Matches an And with LHS and RHS in either order.
27100b57cec5SDimitry Andric template <typename LHS, typename RHS>
27110b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::And, true> m_c_And(const LHS &L,
27120b57cec5SDimitry Andric                                                                 const RHS &R) {
27130b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::And, true>(L, R);
27140b57cec5SDimitry Andric }
27150b57cec5SDimitry Andric 
27160b57cec5SDimitry Andric /// Matches an Or with LHS and RHS in either order.
27170b57cec5SDimitry Andric template <typename LHS, typename RHS>
27180b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::Or, true> m_c_Or(const LHS &L,
27190b57cec5SDimitry Andric                                                               const RHS &R) {
27200b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::Or, true>(L, R);
27210b57cec5SDimitry Andric }
27220b57cec5SDimitry Andric 
27230b57cec5SDimitry Andric /// Matches an Xor with LHS and RHS in either order.
27240b57cec5SDimitry Andric template <typename LHS, typename RHS>
27250b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::Xor, true> m_c_Xor(const LHS &L,
27260b57cec5SDimitry Andric                                                                 const RHS &R) {
27270b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::Xor, true>(L, R);
27280b57cec5SDimitry Andric }
27290b57cec5SDimitry Andric 
27300b57cec5SDimitry Andric /// Matches a 'Neg' as 'sub 0, V'.
27310b57cec5SDimitry Andric template <typename ValTy>
27320b57cec5SDimitry Andric inline BinaryOp_match<cst_pred_ty<is_zero_int>, ValTy, Instruction::Sub>
27330b57cec5SDimitry Andric m_Neg(const ValTy &V) {
27340b57cec5SDimitry Andric   return m_Sub(m_ZeroInt(), V);
27350b57cec5SDimitry Andric }
27360b57cec5SDimitry Andric 
2737e8d8bef9SDimitry Andric /// Matches a 'Neg' as 'sub nsw 0, V'.
2738e8d8bef9SDimitry Andric template <typename ValTy>
2739e8d8bef9SDimitry Andric inline OverflowingBinaryOp_match<cst_pred_ty<is_zero_int>, ValTy,
2740e8d8bef9SDimitry Andric                                  Instruction::Sub,
2741e8d8bef9SDimitry Andric                                  OverflowingBinaryOperator::NoSignedWrap>
2742e8d8bef9SDimitry Andric m_NSWNeg(const ValTy &V) {
2743e8d8bef9SDimitry Andric   return m_NSWSub(m_ZeroInt(), V);
2744e8d8bef9SDimitry Andric }
2745e8d8bef9SDimitry Andric 
27460b57cec5SDimitry Andric /// Matches an SMin with LHS and RHS in either order.
27470b57cec5SDimitry Andric template <typename LHS, typename RHS>
27480b57cec5SDimitry Andric inline MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty, true>
27490b57cec5SDimitry Andric m_c_SMin(const LHS &L, const RHS &R) {
27500b57cec5SDimitry Andric   return MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty, true>(L, R);
27510b57cec5SDimitry Andric }
27520b57cec5SDimitry Andric /// Matches an SMax with LHS and RHS in either order.
27530b57cec5SDimitry Andric template <typename LHS, typename RHS>
27540b57cec5SDimitry Andric inline MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty, true>
27550b57cec5SDimitry Andric m_c_SMax(const LHS &L, const RHS &R) {
27560b57cec5SDimitry Andric   return MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty, true>(L, R);
27570b57cec5SDimitry Andric }
27580b57cec5SDimitry Andric /// Matches a UMin with LHS and RHS in either order.
27590b57cec5SDimitry Andric template <typename LHS, typename RHS>
27600b57cec5SDimitry Andric inline MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty, true>
27610b57cec5SDimitry Andric m_c_UMin(const LHS &L, const RHS &R) {
27620b57cec5SDimitry Andric   return MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty, true>(L, R);
27630b57cec5SDimitry Andric }
27640b57cec5SDimitry Andric /// Matches a UMax with LHS and RHS in either order.
27650b57cec5SDimitry Andric template <typename LHS, typename RHS>
27660b57cec5SDimitry Andric inline MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty, true>
27670b57cec5SDimitry Andric m_c_UMax(const LHS &L, const RHS &R) {
27680b57cec5SDimitry Andric   return MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty, true>(L, R);
27690b57cec5SDimitry Andric }
27700b57cec5SDimitry Andric 
2771e8d8bef9SDimitry Andric template <typename LHS, typename RHS>
2772e8d8bef9SDimitry Andric inline match_combine_or<
2773e8d8bef9SDimitry Andric     match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, smax_pred_ty, true>,
2774e8d8bef9SDimitry Andric                      MaxMin_match<ICmpInst, LHS, RHS, smin_pred_ty, true>>,
2775e8d8bef9SDimitry Andric     match_combine_or<MaxMin_match<ICmpInst, LHS, RHS, umax_pred_ty, true>,
2776e8d8bef9SDimitry Andric                      MaxMin_match<ICmpInst, LHS, RHS, umin_pred_ty, true>>>
2777e8d8bef9SDimitry Andric m_c_MaxOrMin(const LHS &L, const RHS &R) {
2778e8d8bef9SDimitry Andric   return m_CombineOr(m_CombineOr(m_c_SMax(L, R), m_c_SMin(L, R)),
2779e8d8bef9SDimitry Andric                      m_CombineOr(m_c_UMax(L, R), m_c_UMin(L, R)));
2780e8d8bef9SDimitry Andric }
2781e8d8bef9SDimitry Andric 
278206c3fb27SDimitry Andric template <Intrinsic::ID IntrID, typename T0, typename T1>
278306c3fb27SDimitry Andric inline match_combine_or<typename m_Intrinsic_Ty<T0, T1>::Ty,
278406c3fb27SDimitry Andric                         typename m_Intrinsic_Ty<T1, T0>::Ty>
278506c3fb27SDimitry Andric m_c_Intrinsic(const T0 &Op0, const T1 &Op1) {
278606c3fb27SDimitry Andric   return m_CombineOr(m_Intrinsic<IntrID>(Op0, Op1),
278706c3fb27SDimitry Andric                      m_Intrinsic<IntrID>(Op1, Op0));
278806c3fb27SDimitry Andric }
278906c3fb27SDimitry Andric 
27900b57cec5SDimitry Andric /// Matches FAdd with LHS and RHS in either order.
27910b57cec5SDimitry Andric template <typename LHS, typename RHS>
27920b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::FAdd, true>
27930b57cec5SDimitry Andric m_c_FAdd(const LHS &L, const RHS &R) {
27940b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::FAdd, true>(L, R);
27950b57cec5SDimitry Andric }
27960b57cec5SDimitry Andric 
27970b57cec5SDimitry Andric /// Matches FMul with LHS and RHS in either order.
27980b57cec5SDimitry Andric template <typename LHS, typename RHS>
27990b57cec5SDimitry Andric inline BinaryOp_match<LHS, RHS, Instruction::FMul, true>
28000b57cec5SDimitry Andric m_c_FMul(const LHS &L, const RHS &R) {
28010b57cec5SDimitry Andric   return BinaryOp_match<LHS, RHS, Instruction::FMul, true>(L, R);
28020b57cec5SDimitry Andric }
28030b57cec5SDimitry Andric 
28040b57cec5SDimitry Andric template <typename Opnd_t> struct Signum_match {
28050b57cec5SDimitry Andric   Opnd_t Val;
28060b57cec5SDimitry Andric   Signum_match(const Opnd_t &V) : Val(V) {}
28070b57cec5SDimitry Andric 
28080b57cec5SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
28090b57cec5SDimitry Andric     unsigned TypeSize = V->getType()->getScalarSizeInBits();
28100b57cec5SDimitry Andric     if (TypeSize == 0)
28110b57cec5SDimitry Andric       return false;
28120b57cec5SDimitry Andric 
28130b57cec5SDimitry Andric     unsigned ShiftWidth = TypeSize - 1;
28140b57cec5SDimitry Andric     Value *OpL = nullptr, *OpR = nullptr;
28150b57cec5SDimitry Andric 
28160b57cec5SDimitry Andric     // This is the representation of signum we match:
28170b57cec5SDimitry Andric     //
28180b57cec5SDimitry Andric     //  signum(x) == (x >> 63) | (-x >>u 63)
28190b57cec5SDimitry Andric     //
28200b57cec5SDimitry Andric     // An i1 value is its own signum, so it's correct to match
28210b57cec5SDimitry Andric     //
28220b57cec5SDimitry Andric     //  signum(x) == (x >> 0)  | (-x >>u 0)
28230b57cec5SDimitry Andric     //
28240b57cec5SDimitry Andric     // for i1 values.
28250b57cec5SDimitry Andric 
28260b57cec5SDimitry Andric     auto LHS = m_AShr(m_Value(OpL), m_SpecificInt(ShiftWidth));
28270b57cec5SDimitry Andric     auto RHS = m_LShr(m_Neg(m_Value(OpR)), m_SpecificInt(ShiftWidth));
28280b57cec5SDimitry Andric     auto Signum = m_Or(LHS, RHS);
28290b57cec5SDimitry Andric 
28300b57cec5SDimitry Andric     return Signum.match(V) && OpL == OpR && Val.match(OpL);
28310b57cec5SDimitry Andric   }
28320b57cec5SDimitry Andric };
28330b57cec5SDimitry Andric 
28340b57cec5SDimitry Andric /// Matches a signum pattern.
28350b57cec5SDimitry Andric ///
28360b57cec5SDimitry Andric /// signum(x) =
28370b57cec5SDimitry Andric ///      x >  0  ->  1
28380b57cec5SDimitry Andric ///      x == 0  ->  0
28390b57cec5SDimitry Andric ///      x <  0  -> -1
28400b57cec5SDimitry Andric template <typename Val_t> inline Signum_match<Val_t> m_Signum(const Val_t &V) {
28410b57cec5SDimitry Andric   return Signum_match<Val_t>(V);
28420b57cec5SDimitry Andric }
28430b57cec5SDimitry Andric 
2844480093f4SDimitry Andric template <int Ind, typename Opnd_t> struct ExtractValue_match {
2845480093f4SDimitry Andric   Opnd_t Val;
2846480093f4SDimitry Andric   ExtractValue_match(const Opnd_t &V) : Val(V) {}
2847480093f4SDimitry Andric 
2848480093f4SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
2849fe6060f1SDimitry Andric     if (auto *I = dyn_cast<ExtractValueInst>(V)) {
2850fe6060f1SDimitry Andric       // If Ind is -1, don't inspect indices
2851fe6060f1SDimitry Andric       if (Ind != -1 &&
2852fe6060f1SDimitry Andric           !(I->getNumIndices() == 1 && I->getIndices()[0] == (unsigned)Ind))
2853fe6060f1SDimitry Andric         return false;
2854fe6060f1SDimitry Andric       return Val.match(I->getAggregateOperand());
2855fe6060f1SDimitry Andric     }
2856480093f4SDimitry Andric     return false;
2857480093f4SDimitry Andric   }
2858480093f4SDimitry Andric };
2859480093f4SDimitry Andric 
2860480093f4SDimitry Andric /// Match a single index ExtractValue instruction.
2861480093f4SDimitry Andric /// For example m_ExtractValue<1>(...)
2862480093f4SDimitry Andric template <int Ind, typename Val_t>
2863480093f4SDimitry Andric inline ExtractValue_match<Ind, Val_t> m_ExtractValue(const Val_t &V) {
2864480093f4SDimitry Andric   return ExtractValue_match<Ind, Val_t>(V);
2865480093f4SDimitry Andric }
2866480093f4SDimitry Andric 
2867fe6060f1SDimitry Andric /// Match an ExtractValue instruction with any index.
2868fe6060f1SDimitry Andric /// For example m_ExtractValue(...)
2869fe6060f1SDimitry Andric template <typename Val_t>
2870fe6060f1SDimitry Andric inline ExtractValue_match<-1, Val_t> m_ExtractValue(const Val_t &V) {
2871fe6060f1SDimitry Andric   return ExtractValue_match<-1, Val_t>(V);
2872fe6060f1SDimitry Andric }
2873fe6060f1SDimitry Andric 
2874e8d8bef9SDimitry Andric /// Matcher for a single index InsertValue instruction.
2875e8d8bef9SDimitry Andric template <int Ind, typename T0, typename T1> struct InsertValue_match {
2876e8d8bef9SDimitry Andric   T0 Op0;
2877e8d8bef9SDimitry Andric   T1 Op1;
2878e8d8bef9SDimitry Andric 
2879e8d8bef9SDimitry Andric   InsertValue_match(const T0 &Op0, const T1 &Op1) : Op0(Op0), Op1(Op1) {}
2880e8d8bef9SDimitry Andric 
2881e8d8bef9SDimitry Andric   template <typename OpTy> bool match(OpTy *V) {
2882e8d8bef9SDimitry Andric     if (auto *I = dyn_cast<InsertValueInst>(V)) {
2883e8d8bef9SDimitry Andric       return Op0.match(I->getOperand(0)) && Op1.match(I->getOperand(1)) &&
2884e8d8bef9SDimitry Andric              I->getNumIndices() == 1 && Ind == I->getIndices()[0];
2885e8d8bef9SDimitry Andric     }
2886e8d8bef9SDimitry Andric     return false;
2887e8d8bef9SDimitry Andric   }
2888e8d8bef9SDimitry Andric };
2889e8d8bef9SDimitry Andric 
2890e8d8bef9SDimitry Andric /// Matches a single index InsertValue instruction.
2891e8d8bef9SDimitry Andric template <int Ind, typename Val_t, typename Elt_t>
2892e8d8bef9SDimitry Andric inline InsertValue_match<Ind, Val_t, Elt_t> m_InsertValue(const Val_t &Val,
2893e8d8bef9SDimitry Andric                                                           const Elt_t &Elt) {
2894e8d8bef9SDimitry Andric   return InsertValue_match<Ind, Val_t, Elt_t>(Val, Elt);
2895e8d8bef9SDimitry Andric }
2896e8d8bef9SDimitry Andric 
28975ffd83dbSDimitry Andric /// Matches patterns for `vscale`. This can either be a call to `llvm.vscale` or
28985ffd83dbSDimitry Andric /// the constant expression
28995ffd83dbSDimitry Andric ///  `ptrtoint(gep <vscale x 1 x i8>, <vscale x 1 x i8>* null, i32 1>`
29005ffd83dbSDimitry Andric /// under the right conditions determined by DataLayout.
29015ffd83dbSDimitry Andric struct VScaleVal_match {
29025ffd83dbSDimitry Andric   template <typename ITy> bool match(ITy *V) {
29035ffd83dbSDimitry Andric     if (m_Intrinsic<Intrinsic::vscale>().match(V))
29045ffd83dbSDimitry Andric       return true;
29055ffd83dbSDimitry Andric 
2906fe6060f1SDimitry Andric     Value *Ptr;
2907fe6060f1SDimitry Andric     if (m_PtrToInt(m_Value(Ptr)).match(V)) {
2908fe6060f1SDimitry Andric       if (auto *GEP = dyn_cast<GEPOperator>(Ptr)) {
290906c3fb27SDimitry Andric         auto *DerefTy =
291006c3fb27SDimitry Andric             dyn_cast<ScalableVectorType>(GEP->getSourceElementType());
291106c3fb27SDimitry Andric         if (GEP->getNumIndices() == 1 && DerefTy &&
291206c3fb27SDimitry Andric             DerefTy->getElementType()->isIntegerTy(8) &&
2913fe6060f1SDimitry Andric             m_Zero().match(GEP->getPointerOperand()) &&
291406c3fb27SDimitry Andric             m_SpecificInt(1).match(GEP->idx_begin()->get()))
29155ffd83dbSDimitry Andric           return true;
29165ffd83dbSDimitry Andric       }
2917fe6060f1SDimitry Andric     }
29185ffd83dbSDimitry Andric 
29195ffd83dbSDimitry Andric     return false;
29205ffd83dbSDimitry Andric   }
29215ffd83dbSDimitry Andric };
29225ffd83dbSDimitry Andric 
292306c3fb27SDimitry Andric inline VScaleVal_match m_VScale() {
292406c3fb27SDimitry Andric   return VScaleVal_match();
29255ffd83dbSDimitry Andric }
29265ffd83dbSDimitry Andric 
2927349cc55cSDimitry Andric template <typename LHS, typename RHS, unsigned Opcode, bool Commutable = false>
2928e8d8bef9SDimitry Andric struct LogicalOp_match {
2929e8d8bef9SDimitry Andric   LHS L;
2930e8d8bef9SDimitry Andric   RHS R;
2931e8d8bef9SDimitry Andric 
2932e8d8bef9SDimitry Andric   LogicalOp_match(const LHS &L, const RHS &R) : L(L), R(R) {}
2933e8d8bef9SDimitry Andric 
2934e8d8bef9SDimitry Andric   template <typename T> bool match(T *V) {
2935349cc55cSDimitry Andric     auto *I = dyn_cast<Instruction>(V);
2936349cc55cSDimitry Andric     if (!I || !I->getType()->isIntOrIntVectorTy(1))
2937e8d8bef9SDimitry Andric       return false;
2938e8d8bef9SDimitry Andric 
2939349cc55cSDimitry Andric     if (I->getOpcode() == Opcode) {
2940349cc55cSDimitry Andric       auto *Op0 = I->getOperand(0);
2941349cc55cSDimitry Andric       auto *Op1 = I->getOperand(1);
2942349cc55cSDimitry Andric       return (L.match(Op0) && R.match(Op1)) ||
2943349cc55cSDimitry Andric              (Commutable && L.match(Op1) && R.match(Op0));
2944349cc55cSDimitry Andric     }
2945e8d8bef9SDimitry Andric 
2946349cc55cSDimitry Andric     if (auto *Select = dyn_cast<SelectInst>(I)) {
2947349cc55cSDimitry Andric       auto *Cond = Select->getCondition();
2948349cc55cSDimitry Andric       auto *TVal = Select->getTrueValue();
2949349cc55cSDimitry Andric       auto *FVal = Select->getFalseValue();
2950bdd1243dSDimitry Andric 
2951bdd1243dSDimitry Andric       // Don't match a scalar select of bool vectors.
2952bdd1243dSDimitry Andric       // Transforms expect a single type for operands if this matches.
2953bdd1243dSDimitry Andric       if (Cond->getType() != Select->getType())
2954bdd1243dSDimitry Andric         return false;
2955bdd1243dSDimitry Andric 
2956e8d8bef9SDimitry Andric       if (Opcode == Instruction::And) {
2957349cc55cSDimitry Andric         auto *C = dyn_cast<Constant>(FVal);
2958349cc55cSDimitry Andric         if (C && C->isNullValue())
2959349cc55cSDimitry Andric           return (L.match(Cond) && R.match(TVal)) ||
2960349cc55cSDimitry Andric                  (Commutable && L.match(TVal) && R.match(Cond));
2961e8d8bef9SDimitry Andric       } else {
2962e8d8bef9SDimitry Andric         assert(Opcode == Instruction::Or);
2963349cc55cSDimitry Andric         auto *C = dyn_cast<Constant>(TVal);
2964349cc55cSDimitry Andric         if (C && C->isOneValue())
2965349cc55cSDimitry Andric           return (L.match(Cond) && R.match(FVal)) ||
2966349cc55cSDimitry Andric                  (Commutable && L.match(FVal) && R.match(Cond));
2967e8d8bef9SDimitry Andric       }
2968e8d8bef9SDimitry Andric     }
2969e8d8bef9SDimitry Andric 
2970e8d8bef9SDimitry Andric     return false;
2971e8d8bef9SDimitry Andric   }
2972e8d8bef9SDimitry Andric };
2973e8d8bef9SDimitry Andric 
2974e8d8bef9SDimitry Andric /// Matches L && R either in the form of L & R or L ? R : false.
2975e8d8bef9SDimitry Andric /// Note that the latter form is poison-blocking.
2976e8d8bef9SDimitry Andric template <typename LHS, typename RHS>
297781ad6265SDimitry Andric inline LogicalOp_match<LHS, RHS, Instruction::And> m_LogicalAnd(const LHS &L,
297881ad6265SDimitry Andric                                                                 const RHS &R) {
2979e8d8bef9SDimitry Andric   return LogicalOp_match<LHS, RHS, Instruction::And>(L, R);
2980e8d8bef9SDimitry Andric }
2981e8d8bef9SDimitry Andric 
2982fe6060f1SDimitry Andric /// Matches L && R where L and R are arbitrary values.
2983fe6060f1SDimitry Andric inline auto m_LogicalAnd() { return m_LogicalAnd(m_Value(), m_Value()); }
2984fe6060f1SDimitry Andric 
2985349cc55cSDimitry Andric /// Matches L && R with LHS and RHS in either order.
2986349cc55cSDimitry Andric template <typename LHS, typename RHS>
2987349cc55cSDimitry Andric inline LogicalOp_match<LHS, RHS, Instruction::And, true>
2988349cc55cSDimitry Andric m_c_LogicalAnd(const LHS &L, const RHS &R) {
2989349cc55cSDimitry Andric   return LogicalOp_match<LHS, RHS, Instruction::And, true>(L, R);
2990349cc55cSDimitry Andric }
2991349cc55cSDimitry Andric 
2992e8d8bef9SDimitry Andric /// Matches L || R either in the form of L | R or L ? true : R.
2993e8d8bef9SDimitry Andric /// Note that the latter form is poison-blocking.
2994e8d8bef9SDimitry Andric template <typename LHS, typename RHS>
299581ad6265SDimitry Andric inline LogicalOp_match<LHS, RHS, Instruction::Or> m_LogicalOr(const LHS &L,
299681ad6265SDimitry Andric                                                               const RHS &R) {
2997e8d8bef9SDimitry Andric   return LogicalOp_match<LHS, RHS, Instruction::Or>(L, R);
2998e8d8bef9SDimitry Andric }
2999e8d8bef9SDimitry Andric 
3000fe6060f1SDimitry Andric /// Matches L || R where L and R are arbitrary values.
3001349cc55cSDimitry Andric inline auto m_LogicalOr() { return m_LogicalOr(m_Value(), m_Value()); }
3002349cc55cSDimitry Andric 
3003349cc55cSDimitry Andric /// Matches L || R with LHS and RHS in either order.
3004349cc55cSDimitry Andric template <typename LHS, typename RHS>
3005349cc55cSDimitry Andric inline LogicalOp_match<LHS, RHS, Instruction::Or, true>
3006349cc55cSDimitry Andric m_c_LogicalOr(const LHS &L, const RHS &R) {
3007349cc55cSDimitry Andric   return LogicalOp_match<LHS, RHS, Instruction::Or, true>(L, R);
3008fe6060f1SDimitry Andric }
3009fe6060f1SDimitry Andric 
3010bdd1243dSDimitry Andric /// Matches either L && R or L || R,
3011bdd1243dSDimitry Andric /// either one being in the either binary or logical form.
3012bdd1243dSDimitry Andric /// Note that the latter form is poison-blocking.
3013bdd1243dSDimitry Andric template <typename LHS, typename RHS, bool Commutable = false>
3014bdd1243dSDimitry Andric inline auto m_LogicalOp(const LHS &L, const RHS &R) {
3015bdd1243dSDimitry Andric   return m_CombineOr(
3016bdd1243dSDimitry Andric       LogicalOp_match<LHS, RHS, Instruction::And, Commutable>(L, R),
3017bdd1243dSDimitry Andric       LogicalOp_match<LHS, RHS, Instruction::Or, Commutable>(L, R));
3018bdd1243dSDimitry Andric }
3019bdd1243dSDimitry Andric 
3020bdd1243dSDimitry Andric /// Matches either L && R or L || R where L and R are arbitrary values.
3021bdd1243dSDimitry Andric inline auto m_LogicalOp() { return m_LogicalOp(m_Value(), m_Value()); }
3022bdd1243dSDimitry Andric 
3023bdd1243dSDimitry Andric /// Matches either L && R or L || R with LHS and RHS in either order.
3024bdd1243dSDimitry Andric template <typename LHS, typename RHS>
3025bdd1243dSDimitry Andric inline auto m_c_LogicalOp(const LHS &L, const RHS &R) {
3026bdd1243dSDimitry Andric   return m_LogicalOp<LHS, RHS, /*Commutable=*/true>(L, R);
3027bdd1243dSDimitry Andric }
3028bdd1243dSDimitry Andric 
30290b57cec5SDimitry Andric } // end namespace PatternMatch
30300b57cec5SDimitry Andric } // end namespace llvm
30310b57cec5SDimitry Andric 
30320b57cec5SDimitry Andric #endif // LLVM_IR_PATTERNMATCH_H
3033