1*0fca6ea1SDimitry Andric //==--------------- llvm/CodeGen/SDPatternMatch.h ---------------*- C++ -*-===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric /// \file 9*0fca6ea1SDimitry Andric /// Contains matchers for matching SelectionDAG nodes and values. 10*0fca6ea1SDimitry Andric /// 11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 12*0fca6ea1SDimitry Andric 13*0fca6ea1SDimitry Andric #ifndef LLVM_CODEGEN_SDPATTERNMATCH_H 14*0fca6ea1SDimitry Andric #define LLVM_CODEGEN_SDPATTERNMATCH_H 15*0fca6ea1SDimitry Andric 16*0fca6ea1SDimitry Andric #include "llvm/ADT/APInt.h" 17*0fca6ea1SDimitry Andric #include "llvm/ADT/STLExtras.h" 18*0fca6ea1SDimitry Andric #include "llvm/CodeGen/SelectionDAG.h" 19*0fca6ea1SDimitry Andric #include "llvm/CodeGen/SelectionDAGNodes.h" 20*0fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetLowering.h" 21*0fca6ea1SDimitry Andric 22*0fca6ea1SDimitry Andric namespace llvm { 23*0fca6ea1SDimitry Andric namespace SDPatternMatch { 24*0fca6ea1SDimitry Andric 25*0fca6ea1SDimitry Andric /// MatchContext can repurpose existing patterns to behave differently under 26*0fca6ea1SDimitry Andric /// a certain context. For instance, `m_Opc(ISD::ADD)` matches plain ADD nodes 27*0fca6ea1SDimitry Andric /// in normal circumstances, but matches VP_ADD nodes under a custom 28*0fca6ea1SDimitry Andric /// VPMatchContext. This design is meant to facilitate code / pattern reusing. 29*0fca6ea1SDimitry Andric class BasicMatchContext { 30*0fca6ea1SDimitry Andric const SelectionDAG *DAG; 31*0fca6ea1SDimitry Andric const TargetLowering *TLI; 32*0fca6ea1SDimitry Andric 33*0fca6ea1SDimitry Andric public: 34*0fca6ea1SDimitry Andric explicit BasicMatchContext(const SelectionDAG *DAG) 35*0fca6ea1SDimitry Andric : DAG(DAG), TLI(DAG ? &DAG->getTargetLoweringInfo() : nullptr) {} 36*0fca6ea1SDimitry Andric 37*0fca6ea1SDimitry Andric explicit BasicMatchContext(const TargetLowering *TLI) 38*0fca6ea1SDimitry Andric : DAG(nullptr), TLI(TLI) {} 39*0fca6ea1SDimitry Andric 40*0fca6ea1SDimitry Andric // A valid MatchContext has to implement the following functions. 41*0fca6ea1SDimitry Andric 42*0fca6ea1SDimitry Andric const SelectionDAG *getDAG() const { return DAG; } 43*0fca6ea1SDimitry Andric 44*0fca6ea1SDimitry Andric const TargetLowering *getTLI() const { return TLI; } 45*0fca6ea1SDimitry Andric 46*0fca6ea1SDimitry Andric /// Return true if N effectively has opcode Opcode. 47*0fca6ea1SDimitry Andric bool match(SDValue N, unsigned Opcode) const { 48*0fca6ea1SDimitry Andric return N->getOpcode() == Opcode; 49*0fca6ea1SDimitry Andric } 50*0fca6ea1SDimitry Andric }; 51*0fca6ea1SDimitry Andric 52*0fca6ea1SDimitry Andric template <typename Pattern, typename MatchContext> 53*0fca6ea1SDimitry Andric [[nodiscard]] bool sd_context_match(SDValue N, const MatchContext &Ctx, 54*0fca6ea1SDimitry Andric Pattern &&P) { 55*0fca6ea1SDimitry Andric return P.match(Ctx, N); 56*0fca6ea1SDimitry Andric } 57*0fca6ea1SDimitry Andric 58*0fca6ea1SDimitry Andric template <typename Pattern, typename MatchContext> 59*0fca6ea1SDimitry Andric [[nodiscard]] bool sd_context_match(SDNode *N, const MatchContext &Ctx, 60*0fca6ea1SDimitry Andric Pattern &&P) { 61*0fca6ea1SDimitry Andric return sd_context_match(SDValue(N, 0), Ctx, P); 62*0fca6ea1SDimitry Andric } 63*0fca6ea1SDimitry Andric 64*0fca6ea1SDimitry Andric template <typename Pattern> 65*0fca6ea1SDimitry Andric [[nodiscard]] bool sd_match(SDNode *N, const SelectionDAG *DAG, Pattern &&P) { 66*0fca6ea1SDimitry Andric return sd_context_match(N, BasicMatchContext(DAG), P); 67*0fca6ea1SDimitry Andric } 68*0fca6ea1SDimitry Andric 69*0fca6ea1SDimitry Andric template <typename Pattern> 70*0fca6ea1SDimitry Andric [[nodiscard]] bool sd_match(SDValue N, const SelectionDAG *DAG, Pattern &&P) { 71*0fca6ea1SDimitry Andric return sd_context_match(N, BasicMatchContext(DAG), P); 72*0fca6ea1SDimitry Andric } 73*0fca6ea1SDimitry Andric 74*0fca6ea1SDimitry Andric template <typename Pattern> 75*0fca6ea1SDimitry Andric [[nodiscard]] bool sd_match(SDNode *N, Pattern &&P) { 76*0fca6ea1SDimitry Andric return sd_match(N, nullptr, P); 77*0fca6ea1SDimitry Andric } 78*0fca6ea1SDimitry Andric 79*0fca6ea1SDimitry Andric template <typename Pattern> 80*0fca6ea1SDimitry Andric [[nodiscard]] bool sd_match(SDValue N, Pattern &&P) { 81*0fca6ea1SDimitry Andric return sd_match(N, nullptr, P); 82*0fca6ea1SDimitry Andric } 83*0fca6ea1SDimitry Andric 84*0fca6ea1SDimitry Andric // === Utilities === 85*0fca6ea1SDimitry Andric struct Value_match { 86*0fca6ea1SDimitry Andric SDValue MatchVal; 87*0fca6ea1SDimitry Andric 88*0fca6ea1SDimitry Andric Value_match() = default; 89*0fca6ea1SDimitry Andric 90*0fca6ea1SDimitry Andric explicit Value_match(SDValue Match) : MatchVal(Match) {} 91*0fca6ea1SDimitry Andric 92*0fca6ea1SDimitry Andric template <typename MatchContext> bool match(const MatchContext &, SDValue N) { 93*0fca6ea1SDimitry Andric if (MatchVal) 94*0fca6ea1SDimitry Andric return MatchVal == N; 95*0fca6ea1SDimitry Andric return N.getNode(); 96*0fca6ea1SDimitry Andric } 97*0fca6ea1SDimitry Andric }; 98*0fca6ea1SDimitry Andric 99*0fca6ea1SDimitry Andric /// Match any valid SDValue. 100*0fca6ea1SDimitry Andric inline Value_match m_Value() { return Value_match(); } 101*0fca6ea1SDimitry Andric 102*0fca6ea1SDimitry Andric inline Value_match m_Specific(SDValue N) { 103*0fca6ea1SDimitry Andric assert(N); 104*0fca6ea1SDimitry Andric return Value_match(N); 105*0fca6ea1SDimitry Andric } 106*0fca6ea1SDimitry Andric 107*0fca6ea1SDimitry Andric struct DeferredValue_match { 108*0fca6ea1SDimitry Andric SDValue &MatchVal; 109*0fca6ea1SDimitry Andric 110*0fca6ea1SDimitry Andric explicit DeferredValue_match(SDValue &Match) : MatchVal(Match) {} 111*0fca6ea1SDimitry Andric 112*0fca6ea1SDimitry Andric template <typename MatchContext> bool match(const MatchContext &, SDValue N) { 113*0fca6ea1SDimitry Andric return N == MatchVal; 114*0fca6ea1SDimitry Andric } 115*0fca6ea1SDimitry Andric }; 116*0fca6ea1SDimitry Andric 117*0fca6ea1SDimitry Andric /// Similar to m_Specific, but the specific value to match is determined by 118*0fca6ea1SDimitry Andric /// another sub-pattern in the same sd_match() expression. For instance, 119*0fca6ea1SDimitry Andric /// We cannot match `(add V, V)` with `m_Add(m_Value(X), m_Specific(X))` since 120*0fca6ea1SDimitry Andric /// `X` is not initialized at the time it got copied into `m_Specific`. Instead, 121*0fca6ea1SDimitry Andric /// we should use `m_Add(m_Value(X), m_Deferred(X))`. 122*0fca6ea1SDimitry Andric inline DeferredValue_match m_Deferred(SDValue &V) { 123*0fca6ea1SDimitry Andric return DeferredValue_match(V); 124*0fca6ea1SDimitry Andric } 125*0fca6ea1SDimitry Andric 126*0fca6ea1SDimitry Andric struct Opcode_match { 127*0fca6ea1SDimitry Andric unsigned Opcode; 128*0fca6ea1SDimitry Andric 129*0fca6ea1SDimitry Andric explicit Opcode_match(unsigned Opc) : Opcode(Opc) {} 130*0fca6ea1SDimitry Andric 131*0fca6ea1SDimitry Andric template <typename MatchContext> 132*0fca6ea1SDimitry Andric bool match(const MatchContext &Ctx, SDValue N) { 133*0fca6ea1SDimitry Andric return Ctx.match(N, Opcode); 134*0fca6ea1SDimitry Andric } 135*0fca6ea1SDimitry Andric }; 136*0fca6ea1SDimitry Andric 137*0fca6ea1SDimitry Andric inline Opcode_match m_Opc(unsigned Opcode) { return Opcode_match(Opcode); } 138*0fca6ea1SDimitry Andric 139*0fca6ea1SDimitry Andric template <unsigned NumUses, typename Pattern> struct NUses_match { 140*0fca6ea1SDimitry Andric Pattern P; 141*0fca6ea1SDimitry Andric 142*0fca6ea1SDimitry Andric explicit NUses_match(const Pattern &P) : P(P) {} 143*0fca6ea1SDimitry Andric 144*0fca6ea1SDimitry Andric template <typename MatchContext> 145*0fca6ea1SDimitry Andric bool match(const MatchContext &Ctx, SDValue N) { 146*0fca6ea1SDimitry Andric // SDNode::hasNUsesOfValue is pretty expensive when the SDNode produces 147*0fca6ea1SDimitry Andric // multiple results, hence we check the subsequent pattern here before 148*0fca6ea1SDimitry Andric // checking the number of value users. 149*0fca6ea1SDimitry Andric return P.match(Ctx, N) && N->hasNUsesOfValue(NumUses, N.getResNo()); 150*0fca6ea1SDimitry Andric } 151*0fca6ea1SDimitry Andric }; 152*0fca6ea1SDimitry Andric 153*0fca6ea1SDimitry Andric template <typename Pattern> 154*0fca6ea1SDimitry Andric inline NUses_match<1, Pattern> m_OneUse(const Pattern &P) { 155*0fca6ea1SDimitry Andric return NUses_match<1, Pattern>(P); 156*0fca6ea1SDimitry Andric } 157*0fca6ea1SDimitry Andric template <unsigned N, typename Pattern> 158*0fca6ea1SDimitry Andric inline NUses_match<N, Pattern> m_NUses(const Pattern &P) { 159*0fca6ea1SDimitry Andric return NUses_match<N, Pattern>(P); 160*0fca6ea1SDimitry Andric } 161*0fca6ea1SDimitry Andric 162*0fca6ea1SDimitry Andric inline NUses_match<1, Value_match> m_OneUse() { 163*0fca6ea1SDimitry Andric return NUses_match<1, Value_match>(m_Value()); 164*0fca6ea1SDimitry Andric } 165*0fca6ea1SDimitry Andric template <unsigned N> inline NUses_match<N, Value_match> m_NUses() { 166*0fca6ea1SDimitry Andric return NUses_match<N, Value_match>(m_Value()); 167*0fca6ea1SDimitry Andric } 168*0fca6ea1SDimitry Andric 169*0fca6ea1SDimitry Andric struct Value_bind { 170*0fca6ea1SDimitry Andric SDValue &BindVal; 171*0fca6ea1SDimitry Andric 172*0fca6ea1SDimitry Andric explicit Value_bind(SDValue &N) : BindVal(N) {} 173*0fca6ea1SDimitry Andric 174*0fca6ea1SDimitry Andric template <typename MatchContext> bool match(const MatchContext &, SDValue N) { 175*0fca6ea1SDimitry Andric BindVal = N; 176*0fca6ea1SDimitry Andric return true; 177*0fca6ea1SDimitry Andric } 178*0fca6ea1SDimitry Andric }; 179*0fca6ea1SDimitry Andric 180*0fca6ea1SDimitry Andric inline Value_bind m_Value(SDValue &N) { return Value_bind(N); } 181*0fca6ea1SDimitry Andric 182*0fca6ea1SDimitry Andric template <typename Pattern, typename PredFuncT> struct TLI_pred_match { 183*0fca6ea1SDimitry Andric Pattern P; 184*0fca6ea1SDimitry Andric PredFuncT PredFunc; 185*0fca6ea1SDimitry Andric 186*0fca6ea1SDimitry Andric TLI_pred_match(const PredFuncT &Pred, const Pattern &P) 187*0fca6ea1SDimitry Andric : P(P), PredFunc(Pred) {} 188*0fca6ea1SDimitry Andric 189*0fca6ea1SDimitry Andric template <typename MatchContext> 190*0fca6ea1SDimitry Andric bool match(const MatchContext &Ctx, SDValue N) { 191*0fca6ea1SDimitry Andric assert(Ctx.getTLI() && "TargetLowering is required for this pattern."); 192*0fca6ea1SDimitry Andric return PredFunc(*Ctx.getTLI(), N) && P.match(Ctx, N); 193*0fca6ea1SDimitry Andric } 194*0fca6ea1SDimitry Andric }; 195*0fca6ea1SDimitry Andric 196*0fca6ea1SDimitry Andric // Explicit deduction guide. 197*0fca6ea1SDimitry Andric template <typename PredFuncT, typename Pattern> 198*0fca6ea1SDimitry Andric TLI_pred_match(const PredFuncT &Pred, const Pattern &P) 199*0fca6ea1SDimitry Andric -> TLI_pred_match<Pattern, PredFuncT>; 200*0fca6ea1SDimitry Andric 201*0fca6ea1SDimitry Andric /// Match legal SDNodes based on the information provided by TargetLowering. 202*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_LegalOp(const Pattern &P) { 203*0fca6ea1SDimitry Andric return TLI_pred_match{[](const TargetLowering &TLI, SDValue N) { 204*0fca6ea1SDimitry Andric return TLI.isOperationLegal(N->getOpcode(), 205*0fca6ea1SDimitry Andric N.getValueType()); 206*0fca6ea1SDimitry Andric }, 207*0fca6ea1SDimitry Andric P}; 208*0fca6ea1SDimitry Andric } 209*0fca6ea1SDimitry Andric 210*0fca6ea1SDimitry Andric /// Switch to a different MatchContext for subsequent patterns. 211*0fca6ea1SDimitry Andric template <typename NewMatchContext, typename Pattern> struct SwitchContext { 212*0fca6ea1SDimitry Andric const NewMatchContext &Ctx; 213*0fca6ea1SDimitry Andric Pattern P; 214*0fca6ea1SDimitry Andric 215*0fca6ea1SDimitry Andric template <typename OrigMatchContext> 216*0fca6ea1SDimitry Andric bool match(const OrigMatchContext &, SDValue N) { 217*0fca6ea1SDimitry Andric return P.match(Ctx, N); 218*0fca6ea1SDimitry Andric } 219*0fca6ea1SDimitry Andric }; 220*0fca6ea1SDimitry Andric 221*0fca6ea1SDimitry Andric template <typename MatchContext, typename Pattern> 222*0fca6ea1SDimitry Andric inline SwitchContext<MatchContext, Pattern> m_Context(const MatchContext &Ctx, 223*0fca6ea1SDimitry Andric Pattern &&P) { 224*0fca6ea1SDimitry Andric return SwitchContext<MatchContext, Pattern>{Ctx, std::move(P)}; 225*0fca6ea1SDimitry Andric } 226*0fca6ea1SDimitry Andric 227*0fca6ea1SDimitry Andric // === Value type === 228*0fca6ea1SDimitry Andric struct ValueType_bind { 229*0fca6ea1SDimitry Andric EVT &BindVT; 230*0fca6ea1SDimitry Andric 231*0fca6ea1SDimitry Andric explicit ValueType_bind(EVT &Bind) : BindVT(Bind) {} 232*0fca6ea1SDimitry Andric 233*0fca6ea1SDimitry Andric template <typename MatchContext> bool match(const MatchContext &, SDValue N) { 234*0fca6ea1SDimitry Andric BindVT = N.getValueType(); 235*0fca6ea1SDimitry Andric return true; 236*0fca6ea1SDimitry Andric } 237*0fca6ea1SDimitry Andric }; 238*0fca6ea1SDimitry Andric 239*0fca6ea1SDimitry Andric /// Retreive the ValueType of the current SDValue. 240*0fca6ea1SDimitry Andric inline ValueType_bind m_VT(EVT &VT) { return ValueType_bind(VT); } 241*0fca6ea1SDimitry Andric 242*0fca6ea1SDimitry Andric template <typename Pattern, typename PredFuncT> struct ValueType_match { 243*0fca6ea1SDimitry Andric PredFuncT PredFunc; 244*0fca6ea1SDimitry Andric Pattern P; 245*0fca6ea1SDimitry Andric 246*0fca6ea1SDimitry Andric ValueType_match(const PredFuncT &Pred, const Pattern &P) 247*0fca6ea1SDimitry Andric : PredFunc(Pred), P(P) {} 248*0fca6ea1SDimitry Andric 249*0fca6ea1SDimitry Andric template <typename MatchContext> 250*0fca6ea1SDimitry Andric bool match(const MatchContext &Ctx, SDValue N) { 251*0fca6ea1SDimitry Andric return PredFunc(N.getValueType()) && P.match(Ctx, N); 252*0fca6ea1SDimitry Andric } 253*0fca6ea1SDimitry Andric }; 254*0fca6ea1SDimitry Andric 255*0fca6ea1SDimitry Andric // Explicit deduction guide. 256*0fca6ea1SDimitry Andric template <typename PredFuncT, typename Pattern> 257*0fca6ea1SDimitry Andric ValueType_match(const PredFuncT &Pred, const Pattern &P) 258*0fca6ea1SDimitry Andric -> ValueType_match<Pattern, PredFuncT>; 259*0fca6ea1SDimitry Andric 260*0fca6ea1SDimitry Andric /// Match a specific ValueType. 261*0fca6ea1SDimitry Andric template <typename Pattern> 262*0fca6ea1SDimitry Andric inline auto m_SpecificVT(EVT RefVT, const Pattern &P) { 263*0fca6ea1SDimitry Andric return ValueType_match{[=](EVT VT) { return VT == RefVT; }, P}; 264*0fca6ea1SDimitry Andric } 265*0fca6ea1SDimitry Andric inline auto m_SpecificVT(EVT RefVT) { 266*0fca6ea1SDimitry Andric return ValueType_match{[=](EVT VT) { return VT == RefVT; }, m_Value()}; 267*0fca6ea1SDimitry Andric } 268*0fca6ea1SDimitry Andric 269*0fca6ea1SDimitry Andric inline auto m_Glue() { return m_SpecificVT(MVT::Glue); } 270*0fca6ea1SDimitry Andric inline auto m_OtherVT() { return m_SpecificVT(MVT::Other); } 271*0fca6ea1SDimitry Andric 272*0fca6ea1SDimitry Andric /// Match any integer ValueTypes. 273*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_IntegerVT(const Pattern &P) { 274*0fca6ea1SDimitry Andric return ValueType_match{[](EVT VT) { return VT.isInteger(); }, P}; 275*0fca6ea1SDimitry Andric } 276*0fca6ea1SDimitry Andric inline auto m_IntegerVT() { 277*0fca6ea1SDimitry Andric return ValueType_match{[](EVT VT) { return VT.isInteger(); }, m_Value()}; 278*0fca6ea1SDimitry Andric } 279*0fca6ea1SDimitry Andric 280*0fca6ea1SDimitry Andric /// Match any floating point ValueTypes. 281*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_FloatingPointVT(const Pattern &P) { 282*0fca6ea1SDimitry Andric return ValueType_match{[](EVT VT) { return VT.isFloatingPoint(); }, P}; 283*0fca6ea1SDimitry Andric } 284*0fca6ea1SDimitry Andric inline auto m_FloatingPointVT() { 285*0fca6ea1SDimitry Andric return ValueType_match{[](EVT VT) { return VT.isFloatingPoint(); }, 286*0fca6ea1SDimitry Andric m_Value()}; 287*0fca6ea1SDimitry Andric } 288*0fca6ea1SDimitry Andric 289*0fca6ea1SDimitry Andric /// Match any vector ValueTypes. 290*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_VectorVT(const Pattern &P) { 291*0fca6ea1SDimitry Andric return ValueType_match{[](EVT VT) { return VT.isVector(); }, P}; 292*0fca6ea1SDimitry Andric } 293*0fca6ea1SDimitry Andric inline auto m_VectorVT() { 294*0fca6ea1SDimitry Andric return ValueType_match{[](EVT VT) { return VT.isVector(); }, m_Value()}; 295*0fca6ea1SDimitry Andric } 296*0fca6ea1SDimitry Andric 297*0fca6ea1SDimitry Andric /// Match fixed-length vector ValueTypes. 298*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_FixedVectorVT(const Pattern &P) { 299*0fca6ea1SDimitry Andric return ValueType_match{[](EVT VT) { return VT.isFixedLengthVector(); }, P}; 300*0fca6ea1SDimitry Andric } 301*0fca6ea1SDimitry Andric inline auto m_FixedVectorVT() { 302*0fca6ea1SDimitry Andric return ValueType_match{[](EVT VT) { return VT.isFixedLengthVector(); }, 303*0fca6ea1SDimitry Andric m_Value()}; 304*0fca6ea1SDimitry Andric } 305*0fca6ea1SDimitry Andric 306*0fca6ea1SDimitry Andric /// Match scalable vector ValueTypes. 307*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_ScalableVectorVT(const Pattern &P) { 308*0fca6ea1SDimitry Andric return ValueType_match{[](EVT VT) { return VT.isScalableVector(); }, P}; 309*0fca6ea1SDimitry Andric } 310*0fca6ea1SDimitry Andric inline auto m_ScalableVectorVT() { 311*0fca6ea1SDimitry Andric return ValueType_match{[](EVT VT) { return VT.isScalableVector(); }, 312*0fca6ea1SDimitry Andric m_Value()}; 313*0fca6ea1SDimitry Andric } 314*0fca6ea1SDimitry Andric 315*0fca6ea1SDimitry Andric /// Match legal ValueTypes based on the information provided by TargetLowering. 316*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_LegalType(const Pattern &P) { 317*0fca6ea1SDimitry Andric return TLI_pred_match{[](const TargetLowering &TLI, SDValue N) { 318*0fca6ea1SDimitry Andric return TLI.isTypeLegal(N.getValueType()); 319*0fca6ea1SDimitry Andric }, 320*0fca6ea1SDimitry Andric P}; 321*0fca6ea1SDimitry Andric } 322*0fca6ea1SDimitry Andric 323*0fca6ea1SDimitry Andric // === Patterns combinators === 324*0fca6ea1SDimitry Andric template <typename... Preds> struct And { 325*0fca6ea1SDimitry Andric template <typename MatchContext> bool match(const MatchContext &, SDValue N) { 326*0fca6ea1SDimitry Andric return true; 327*0fca6ea1SDimitry Andric } 328*0fca6ea1SDimitry Andric }; 329*0fca6ea1SDimitry Andric 330*0fca6ea1SDimitry Andric template <typename Pred, typename... Preds> 331*0fca6ea1SDimitry Andric struct And<Pred, Preds...> : And<Preds...> { 332*0fca6ea1SDimitry Andric Pred P; 333*0fca6ea1SDimitry Andric And(const Pred &p, const Preds &...preds) : And<Preds...>(preds...), P(p) {} 334*0fca6ea1SDimitry Andric 335*0fca6ea1SDimitry Andric template <typename MatchContext> 336*0fca6ea1SDimitry Andric bool match(const MatchContext &Ctx, SDValue N) { 337*0fca6ea1SDimitry Andric return P.match(Ctx, N) && And<Preds...>::match(Ctx, N); 338*0fca6ea1SDimitry Andric } 339*0fca6ea1SDimitry Andric }; 340*0fca6ea1SDimitry Andric 341*0fca6ea1SDimitry Andric template <typename... Preds> struct Or { 342*0fca6ea1SDimitry Andric template <typename MatchContext> bool match(const MatchContext &, SDValue N) { 343*0fca6ea1SDimitry Andric return false; 344*0fca6ea1SDimitry Andric } 345*0fca6ea1SDimitry Andric }; 346*0fca6ea1SDimitry Andric 347*0fca6ea1SDimitry Andric template <typename Pred, typename... Preds> 348*0fca6ea1SDimitry Andric struct Or<Pred, Preds...> : Or<Preds...> { 349*0fca6ea1SDimitry Andric Pred P; 350*0fca6ea1SDimitry Andric Or(const Pred &p, const Preds &...preds) : Or<Preds...>(preds...), P(p) {} 351*0fca6ea1SDimitry Andric 352*0fca6ea1SDimitry Andric template <typename MatchContext> 353*0fca6ea1SDimitry Andric bool match(const MatchContext &Ctx, SDValue N) { 354*0fca6ea1SDimitry Andric return P.match(Ctx, N) || Or<Preds...>::match(Ctx, N); 355*0fca6ea1SDimitry Andric } 356*0fca6ea1SDimitry Andric }; 357*0fca6ea1SDimitry Andric 358*0fca6ea1SDimitry Andric template <typename Pred> struct Not { 359*0fca6ea1SDimitry Andric Pred P; 360*0fca6ea1SDimitry Andric 361*0fca6ea1SDimitry Andric explicit Not(const Pred &P) : P(P) {} 362*0fca6ea1SDimitry Andric 363*0fca6ea1SDimitry Andric template <typename MatchContext> 364*0fca6ea1SDimitry Andric bool match(const MatchContext &Ctx, SDValue N) { 365*0fca6ea1SDimitry Andric return !P.match(Ctx, N); 366*0fca6ea1SDimitry Andric } 367*0fca6ea1SDimitry Andric }; 368*0fca6ea1SDimitry Andric // Explicit deduction guide. 369*0fca6ea1SDimitry Andric template <typename Pred> Not(const Pred &P) -> Not<Pred>; 370*0fca6ea1SDimitry Andric 371*0fca6ea1SDimitry Andric /// Match if the inner pattern does NOT match. 372*0fca6ea1SDimitry Andric template <typename Pred> inline Not<Pred> m_Unless(const Pred &P) { 373*0fca6ea1SDimitry Andric return Not{P}; 374*0fca6ea1SDimitry Andric } 375*0fca6ea1SDimitry Andric 376*0fca6ea1SDimitry Andric template <typename... Preds> And<Preds...> m_AllOf(const Preds &...preds) { 377*0fca6ea1SDimitry Andric return And<Preds...>(preds...); 378*0fca6ea1SDimitry Andric } 379*0fca6ea1SDimitry Andric 380*0fca6ea1SDimitry Andric template <typename... Preds> Or<Preds...> m_AnyOf(const Preds &...preds) { 381*0fca6ea1SDimitry Andric return Or<Preds...>(preds...); 382*0fca6ea1SDimitry Andric } 383*0fca6ea1SDimitry Andric 384*0fca6ea1SDimitry Andric template <typename... Preds> auto m_NoneOf(const Preds &...preds) { 385*0fca6ea1SDimitry Andric return m_Unless(m_AnyOf(preds...)); 386*0fca6ea1SDimitry Andric } 387*0fca6ea1SDimitry Andric 388*0fca6ea1SDimitry Andric // === Generic node matching === 389*0fca6ea1SDimitry Andric template <unsigned OpIdx, typename... OpndPreds> struct Operands_match { 390*0fca6ea1SDimitry Andric template <typename MatchContext> 391*0fca6ea1SDimitry Andric bool match(const MatchContext &Ctx, SDValue N) { 392*0fca6ea1SDimitry Andric // Returns false if there are more operands than predicates; 393*0fca6ea1SDimitry Andric return N->getNumOperands() == OpIdx; 394*0fca6ea1SDimitry Andric } 395*0fca6ea1SDimitry Andric }; 396*0fca6ea1SDimitry Andric 397*0fca6ea1SDimitry Andric template <unsigned OpIdx, typename OpndPred, typename... OpndPreds> 398*0fca6ea1SDimitry Andric struct Operands_match<OpIdx, OpndPred, OpndPreds...> 399*0fca6ea1SDimitry Andric : Operands_match<OpIdx + 1, OpndPreds...> { 400*0fca6ea1SDimitry Andric OpndPred P; 401*0fca6ea1SDimitry Andric 402*0fca6ea1SDimitry Andric Operands_match(const OpndPred &p, const OpndPreds &...preds) 403*0fca6ea1SDimitry Andric : Operands_match<OpIdx + 1, OpndPreds...>(preds...), P(p) {} 404*0fca6ea1SDimitry Andric 405*0fca6ea1SDimitry Andric template <typename MatchContext> 406*0fca6ea1SDimitry Andric bool match(const MatchContext &Ctx, SDValue N) { 407*0fca6ea1SDimitry Andric if (OpIdx < N->getNumOperands()) 408*0fca6ea1SDimitry Andric return P.match(Ctx, N->getOperand(OpIdx)) && 409*0fca6ea1SDimitry Andric Operands_match<OpIdx + 1, OpndPreds...>::match(Ctx, N); 410*0fca6ea1SDimitry Andric 411*0fca6ea1SDimitry Andric // This is the case where there are more predicates than operands. 412*0fca6ea1SDimitry Andric return false; 413*0fca6ea1SDimitry Andric } 414*0fca6ea1SDimitry Andric }; 415*0fca6ea1SDimitry Andric 416*0fca6ea1SDimitry Andric template <typename... OpndPreds> 417*0fca6ea1SDimitry Andric auto m_Node(unsigned Opcode, const OpndPreds &...preds) { 418*0fca6ea1SDimitry Andric return m_AllOf(m_Opc(Opcode), Operands_match<0, OpndPreds...>(preds...)); 419*0fca6ea1SDimitry Andric } 420*0fca6ea1SDimitry Andric 421*0fca6ea1SDimitry Andric /// Provide number of operands that are not chain or glue, as well as the first 422*0fca6ea1SDimitry Andric /// index of such operand. 423*0fca6ea1SDimitry Andric template <bool ExcludeChain> struct EffectiveOperands { 424*0fca6ea1SDimitry Andric unsigned Size = 0; 425*0fca6ea1SDimitry Andric unsigned FirstIndex = 0; 426*0fca6ea1SDimitry Andric 427*0fca6ea1SDimitry Andric explicit EffectiveOperands(SDValue N) { 428*0fca6ea1SDimitry Andric const unsigned TotalNumOps = N->getNumOperands(); 429*0fca6ea1SDimitry Andric FirstIndex = TotalNumOps; 430*0fca6ea1SDimitry Andric for (unsigned I = 0; I < TotalNumOps; ++I) { 431*0fca6ea1SDimitry Andric // Count the number of non-chain and non-glue nodes (we ignore chain 432*0fca6ea1SDimitry Andric // and glue by default) and retreive the operand index offset. 433*0fca6ea1SDimitry Andric EVT VT = N->getOperand(I).getValueType(); 434*0fca6ea1SDimitry Andric if (VT != MVT::Glue && VT != MVT::Other) { 435*0fca6ea1SDimitry Andric ++Size; 436*0fca6ea1SDimitry Andric if (FirstIndex == TotalNumOps) 437*0fca6ea1SDimitry Andric FirstIndex = I; 438*0fca6ea1SDimitry Andric } 439*0fca6ea1SDimitry Andric } 440*0fca6ea1SDimitry Andric } 441*0fca6ea1SDimitry Andric }; 442*0fca6ea1SDimitry Andric 443*0fca6ea1SDimitry Andric template <> struct EffectiveOperands<false> { 444*0fca6ea1SDimitry Andric unsigned Size = 0; 445*0fca6ea1SDimitry Andric unsigned FirstIndex = 0; 446*0fca6ea1SDimitry Andric 447*0fca6ea1SDimitry Andric explicit EffectiveOperands(SDValue N) : Size(N->getNumOperands()) {} 448*0fca6ea1SDimitry Andric }; 449*0fca6ea1SDimitry Andric 450*0fca6ea1SDimitry Andric // === Ternary operations === 451*0fca6ea1SDimitry Andric template <typename T0_P, typename T1_P, typename T2_P, bool Commutable = false, 452*0fca6ea1SDimitry Andric bool ExcludeChain = false> 453*0fca6ea1SDimitry Andric struct TernaryOpc_match { 454*0fca6ea1SDimitry Andric unsigned Opcode; 455*0fca6ea1SDimitry Andric T0_P Op0; 456*0fca6ea1SDimitry Andric T1_P Op1; 457*0fca6ea1SDimitry Andric T2_P Op2; 458*0fca6ea1SDimitry Andric 459*0fca6ea1SDimitry Andric TernaryOpc_match(unsigned Opc, const T0_P &Op0, const T1_P &Op1, 460*0fca6ea1SDimitry Andric const T2_P &Op2) 461*0fca6ea1SDimitry Andric : Opcode(Opc), Op0(Op0), Op1(Op1), Op2(Op2) {} 462*0fca6ea1SDimitry Andric 463*0fca6ea1SDimitry Andric template <typename MatchContext> 464*0fca6ea1SDimitry Andric bool match(const MatchContext &Ctx, SDValue N) { 465*0fca6ea1SDimitry Andric if (sd_context_match(N, Ctx, m_Opc(Opcode))) { 466*0fca6ea1SDimitry Andric EffectiveOperands<ExcludeChain> EO(N); 467*0fca6ea1SDimitry Andric assert(EO.Size == 3); 468*0fca6ea1SDimitry Andric return ((Op0.match(Ctx, N->getOperand(EO.FirstIndex)) && 469*0fca6ea1SDimitry Andric Op1.match(Ctx, N->getOperand(EO.FirstIndex + 1))) || 470*0fca6ea1SDimitry Andric (Commutable && Op0.match(Ctx, N->getOperand(EO.FirstIndex + 1)) && 471*0fca6ea1SDimitry Andric Op1.match(Ctx, N->getOperand(EO.FirstIndex)))) && 472*0fca6ea1SDimitry Andric Op2.match(Ctx, N->getOperand(EO.FirstIndex + 2)); 473*0fca6ea1SDimitry Andric } 474*0fca6ea1SDimitry Andric 475*0fca6ea1SDimitry Andric return false; 476*0fca6ea1SDimitry Andric } 477*0fca6ea1SDimitry Andric }; 478*0fca6ea1SDimitry Andric 479*0fca6ea1SDimitry Andric template <typename T0_P, typename T1_P, typename T2_P> 480*0fca6ea1SDimitry Andric inline TernaryOpc_match<T0_P, T1_P, T2_P, false, false> 481*0fca6ea1SDimitry Andric m_SetCC(const T0_P &LHS, const T1_P &RHS, const T2_P &CC) { 482*0fca6ea1SDimitry Andric return TernaryOpc_match<T0_P, T1_P, T2_P, false, false>(ISD::SETCC, LHS, RHS, 483*0fca6ea1SDimitry Andric CC); 484*0fca6ea1SDimitry Andric } 485*0fca6ea1SDimitry Andric 486*0fca6ea1SDimitry Andric template <typename T0_P, typename T1_P, typename T2_P> 487*0fca6ea1SDimitry Andric inline TernaryOpc_match<T0_P, T1_P, T2_P, true, false> 488*0fca6ea1SDimitry Andric m_c_SetCC(const T0_P &LHS, const T1_P &RHS, const T2_P &CC) { 489*0fca6ea1SDimitry Andric return TernaryOpc_match<T0_P, T1_P, T2_P, true, false>(ISD::SETCC, LHS, RHS, 490*0fca6ea1SDimitry Andric CC); 491*0fca6ea1SDimitry Andric } 492*0fca6ea1SDimitry Andric 493*0fca6ea1SDimitry Andric // === Binary operations === 494*0fca6ea1SDimitry Andric template <typename LHS_P, typename RHS_P, bool Commutable = false, 495*0fca6ea1SDimitry Andric bool ExcludeChain = false> 496*0fca6ea1SDimitry Andric struct BinaryOpc_match { 497*0fca6ea1SDimitry Andric unsigned Opcode; 498*0fca6ea1SDimitry Andric LHS_P LHS; 499*0fca6ea1SDimitry Andric RHS_P RHS; 500*0fca6ea1SDimitry Andric 501*0fca6ea1SDimitry Andric BinaryOpc_match(unsigned Opc, const LHS_P &L, const RHS_P &R) 502*0fca6ea1SDimitry Andric : Opcode(Opc), LHS(L), RHS(R) {} 503*0fca6ea1SDimitry Andric 504*0fca6ea1SDimitry Andric template <typename MatchContext> 505*0fca6ea1SDimitry Andric bool match(const MatchContext &Ctx, SDValue N) { 506*0fca6ea1SDimitry Andric if (sd_context_match(N, Ctx, m_Opc(Opcode))) { 507*0fca6ea1SDimitry Andric EffectiveOperands<ExcludeChain> EO(N); 508*0fca6ea1SDimitry Andric assert(EO.Size == 2); 509*0fca6ea1SDimitry Andric return (LHS.match(Ctx, N->getOperand(EO.FirstIndex)) && 510*0fca6ea1SDimitry Andric RHS.match(Ctx, N->getOperand(EO.FirstIndex + 1))) || 511*0fca6ea1SDimitry Andric (Commutable && LHS.match(Ctx, N->getOperand(EO.FirstIndex + 1)) && 512*0fca6ea1SDimitry Andric RHS.match(Ctx, N->getOperand(EO.FirstIndex))); 513*0fca6ea1SDimitry Andric } 514*0fca6ea1SDimitry Andric 515*0fca6ea1SDimitry Andric return false; 516*0fca6ea1SDimitry Andric } 517*0fca6ea1SDimitry Andric }; 518*0fca6ea1SDimitry Andric 519*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 520*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_BinOp(unsigned Opc, const LHS &L, 521*0fca6ea1SDimitry Andric const RHS &R) { 522*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, false>(Opc, L, R); 523*0fca6ea1SDimitry Andric } 524*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 525*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_c_BinOp(unsigned Opc, const LHS &L, 526*0fca6ea1SDimitry Andric const RHS &R) { 527*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, true>(Opc, L, R); 528*0fca6ea1SDimitry Andric } 529*0fca6ea1SDimitry Andric 530*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 531*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false, true> 532*0fca6ea1SDimitry Andric m_ChainedBinOp(unsigned Opc, const LHS &L, const RHS &R) { 533*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, false, true>(Opc, L, R); 534*0fca6ea1SDimitry Andric } 535*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 536*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true, true> 537*0fca6ea1SDimitry Andric m_c_ChainedBinOp(unsigned Opc, const LHS &L, const RHS &R) { 538*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, true, true>(Opc, L, R); 539*0fca6ea1SDimitry Andric } 540*0fca6ea1SDimitry Andric 541*0fca6ea1SDimitry Andric // Common binary operations 542*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 543*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_Add(const LHS &L, const RHS &R) { 544*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, true>(ISD::ADD, L, R); 545*0fca6ea1SDimitry Andric } 546*0fca6ea1SDimitry Andric 547*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 548*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_Sub(const LHS &L, const RHS &R) { 549*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, false>(ISD::SUB, L, R); 550*0fca6ea1SDimitry Andric } 551*0fca6ea1SDimitry Andric 552*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 553*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_Mul(const LHS &L, const RHS &R) { 554*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, true>(ISD::MUL, L, R); 555*0fca6ea1SDimitry Andric } 556*0fca6ea1SDimitry Andric 557*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 558*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_And(const LHS &L, const RHS &R) { 559*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, true>(ISD::AND, L, R); 560*0fca6ea1SDimitry Andric } 561*0fca6ea1SDimitry Andric 562*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 563*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_Or(const LHS &L, const RHS &R) { 564*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, true>(ISD::OR, L, R); 565*0fca6ea1SDimitry Andric } 566*0fca6ea1SDimitry Andric 567*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 568*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_Xor(const LHS &L, const RHS &R) { 569*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, true>(ISD::XOR, L, R); 570*0fca6ea1SDimitry Andric } 571*0fca6ea1SDimitry Andric 572*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 573*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_SMin(const LHS &L, const RHS &R) { 574*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, true>(ISD::SMIN, L, R); 575*0fca6ea1SDimitry Andric } 576*0fca6ea1SDimitry Andric 577*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 578*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_SMax(const LHS &L, const RHS &R) { 579*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, true>(ISD::SMAX, L, R); 580*0fca6ea1SDimitry Andric } 581*0fca6ea1SDimitry Andric 582*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 583*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_UMin(const LHS &L, const RHS &R) { 584*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, true>(ISD::UMIN, L, R); 585*0fca6ea1SDimitry Andric } 586*0fca6ea1SDimitry Andric 587*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 588*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_UMax(const LHS &L, const RHS &R) { 589*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, true>(ISD::UMAX, L, R); 590*0fca6ea1SDimitry Andric } 591*0fca6ea1SDimitry Andric 592*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 593*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_UDiv(const LHS &L, const RHS &R) { 594*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, false>(ISD::UDIV, L, R); 595*0fca6ea1SDimitry Andric } 596*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 597*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_SDiv(const LHS &L, const RHS &R) { 598*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, false>(ISD::SDIV, L, R); 599*0fca6ea1SDimitry Andric } 600*0fca6ea1SDimitry Andric 601*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 602*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_URem(const LHS &L, const RHS &R) { 603*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, false>(ISD::UREM, L, R); 604*0fca6ea1SDimitry Andric } 605*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 606*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_SRem(const LHS &L, const RHS &R) { 607*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, false>(ISD::SREM, L, R); 608*0fca6ea1SDimitry Andric } 609*0fca6ea1SDimitry Andric 610*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 611*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_Shl(const LHS &L, const RHS &R) { 612*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, false>(ISD::SHL, L, R); 613*0fca6ea1SDimitry Andric } 614*0fca6ea1SDimitry Andric 615*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 616*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_Sra(const LHS &L, const RHS &R) { 617*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, false>(ISD::SRA, L, R); 618*0fca6ea1SDimitry Andric } 619*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 620*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_Srl(const LHS &L, const RHS &R) { 621*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, false>(ISD::SRL, L, R); 622*0fca6ea1SDimitry Andric } 623*0fca6ea1SDimitry Andric 624*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 625*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_FAdd(const LHS &L, const RHS &R) { 626*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, true>(ISD::FADD, L, R); 627*0fca6ea1SDimitry Andric } 628*0fca6ea1SDimitry Andric 629*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 630*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_FSub(const LHS &L, const RHS &R) { 631*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, false>(ISD::FSUB, L, R); 632*0fca6ea1SDimitry Andric } 633*0fca6ea1SDimitry Andric 634*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 635*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_FMul(const LHS &L, const RHS &R) { 636*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, true>(ISD::FMUL, L, R); 637*0fca6ea1SDimitry Andric } 638*0fca6ea1SDimitry Andric 639*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 640*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_FDiv(const LHS &L, const RHS &R) { 641*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, false>(ISD::FDIV, L, R); 642*0fca6ea1SDimitry Andric } 643*0fca6ea1SDimitry Andric 644*0fca6ea1SDimitry Andric template <typename LHS, typename RHS> 645*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_FRem(const LHS &L, const RHS &R) { 646*0fca6ea1SDimitry Andric return BinaryOpc_match<LHS, RHS, false>(ISD::FREM, L, R); 647*0fca6ea1SDimitry Andric } 648*0fca6ea1SDimitry Andric 649*0fca6ea1SDimitry Andric // === Unary operations === 650*0fca6ea1SDimitry Andric template <typename Opnd_P, bool ExcludeChain = false> struct UnaryOpc_match { 651*0fca6ea1SDimitry Andric unsigned Opcode; 652*0fca6ea1SDimitry Andric Opnd_P Opnd; 653*0fca6ea1SDimitry Andric 654*0fca6ea1SDimitry Andric UnaryOpc_match(unsigned Opc, const Opnd_P &Op) : Opcode(Opc), Opnd(Op) {} 655*0fca6ea1SDimitry Andric 656*0fca6ea1SDimitry Andric template <typename MatchContext> 657*0fca6ea1SDimitry Andric bool match(const MatchContext &Ctx, SDValue N) { 658*0fca6ea1SDimitry Andric if (sd_context_match(N, Ctx, m_Opc(Opcode))) { 659*0fca6ea1SDimitry Andric EffectiveOperands<ExcludeChain> EO(N); 660*0fca6ea1SDimitry Andric assert(EO.Size == 1); 661*0fca6ea1SDimitry Andric return Opnd.match(Ctx, N->getOperand(EO.FirstIndex)); 662*0fca6ea1SDimitry Andric } 663*0fca6ea1SDimitry Andric 664*0fca6ea1SDimitry Andric return false; 665*0fca6ea1SDimitry Andric } 666*0fca6ea1SDimitry Andric }; 667*0fca6ea1SDimitry Andric 668*0fca6ea1SDimitry Andric template <typename Opnd> 669*0fca6ea1SDimitry Andric inline UnaryOpc_match<Opnd> m_UnaryOp(unsigned Opc, const Opnd &Op) { 670*0fca6ea1SDimitry Andric return UnaryOpc_match<Opnd>(Opc, Op); 671*0fca6ea1SDimitry Andric } 672*0fca6ea1SDimitry Andric template <typename Opnd> 673*0fca6ea1SDimitry Andric inline UnaryOpc_match<Opnd, true> m_ChainedUnaryOp(unsigned Opc, 674*0fca6ea1SDimitry Andric const Opnd &Op) { 675*0fca6ea1SDimitry Andric return UnaryOpc_match<Opnd, true>(Opc, Op); 676*0fca6ea1SDimitry Andric } 677*0fca6ea1SDimitry Andric 678*0fca6ea1SDimitry Andric template <typename Opnd> 679*0fca6ea1SDimitry Andric inline UnaryOpc_match<Opnd> m_BitReverse(const Opnd &Op) { 680*0fca6ea1SDimitry Andric return UnaryOpc_match<Opnd>(ISD::BITREVERSE, Op); 681*0fca6ea1SDimitry Andric } 682*0fca6ea1SDimitry Andric 683*0fca6ea1SDimitry Andric template <typename Opnd> inline UnaryOpc_match<Opnd> m_ZExt(const Opnd &Op) { 684*0fca6ea1SDimitry Andric return UnaryOpc_match<Opnd>(ISD::ZERO_EXTEND, Op); 685*0fca6ea1SDimitry Andric } 686*0fca6ea1SDimitry Andric 687*0fca6ea1SDimitry Andric template <typename Opnd> inline auto m_SExt(const Opnd &Op) { 688*0fca6ea1SDimitry Andric return UnaryOpc_match<Opnd>(ISD::SIGN_EXTEND, Op); 689*0fca6ea1SDimitry Andric } 690*0fca6ea1SDimitry Andric 691*0fca6ea1SDimitry Andric template <typename Opnd> inline UnaryOpc_match<Opnd> m_AnyExt(const Opnd &Op) { 692*0fca6ea1SDimitry Andric return UnaryOpc_match<Opnd>(ISD::ANY_EXTEND, Op); 693*0fca6ea1SDimitry Andric } 694*0fca6ea1SDimitry Andric 695*0fca6ea1SDimitry Andric template <typename Opnd> inline UnaryOpc_match<Opnd> m_Trunc(const Opnd &Op) { 696*0fca6ea1SDimitry Andric return UnaryOpc_match<Opnd>(ISD::TRUNCATE, Op); 697*0fca6ea1SDimitry Andric } 698*0fca6ea1SDimitry Andric 699*0fca6ea1SDimitry Andric /// Match a zext or identity 700*0fca6ea1SDimitry Andric /// Allows to peek through optional extensions 701*0fca6ea1SDimitry Andric template <typename Opnd> inline auto m_ZExtOrSelf(const Opnd &Op) { 702*0fca6ea1SDimitry Andric return m_AnyOf(m_ZExt(Op), Op); 703*0fca6ea1SDimitry Andric } 704*0fca6ea1SDimitry Andric 705*0fca6ea1SDimitry Andric /// Match a sext or identity 706*0fca6ea1SDimitry Andric /// Allows to peek through optional extensions 707*0fca6ea1SDimitry Andric template <typename Opnd> inline auto m_SExtOrSelf(const Opnd &Op) { 708*0fca6ea1SDimitry Andric return m_AnyOf(m_SExt(Op), Op); 709*0fca6ea1SDimitry Andric } 710*0fca6ea1SDimitry Andric 711*0fca6ea1SDimitry Andric /// Match a aext or identity 712*0fca6ea1SDimitry Andric /// Allows to peek through optional extensions 713*0fca6ea1SDimitry Andric template <typename Opnd> 714*0fca6ea1SDimitry Andric inline Or<UnaryOpc_match<Opnd>, Opnd> m_AExtOrSelf(const Opnd &Op) { 715*0fca6ea1SDimitry Andric return Or<UnaryOpc_match<Opnd>, Opnd>(m_AnyExt(Op), Op); 716*0fca6ea1SDimitry Andric } 717*0fca6ea1SDimitry Andric 718*0fca6ea1SDimitry Andric /// Match a trunc or identity 719*0fca6ea1SDimitry Andric /// Allows to peek through optional truncations 720*0fca6ea1SDimitry Andric template <typename Opnd> 721*0fca6ea1SDimitry Andric inline Or<UnaryOpc_match<Opnd>, Opnd> m_TruncOrSelf(const Opnd &Op) { 722*0fca6ea1SDimitry Andric return Or<UnaryOpc_match<Opnd>, Opnd>(m_Trunc(Op), Op); 723*0fca6ea1SDimitry Andric } 724*0fca6ea1SDimitry Andric 725*0fca6ea1SDimitry Andric // === Constants === 726*0fca6ea1SDimitry Andric struct ConstantInt_match { 727*0fca6ea1SDimitry Andric APInt *BindVal; 728*0fca6ea1SDimitry Andric 729*0fca6ea1SDimitry Andric explicit ConstantInt_match(APInt *V) : BindVal(V) {} 730*0fca6ea1SDimitry Andric 731*0fca6ea1SDimitry Andric template <typename MatchContext> bool match(const MatchContext &, SDValue N) { 732*0fca6ea1SDimitry Andric // The logics here are similar to that in 733*0fca6ea1SDimitry Andric // SelectionDAG::isConstantIntBuildVectorOrConstantInt, but the latter also 734*0fca6ea1SDimitry Andric // treats GlobalAddressSDNode as a constant, which is difficult to turn into 735*0fca6ea1SDimitry Andric // APInt. 736*0fca6ea1SDimitry Andric if (auto *C = dyn_cast_or_null<ConstantSDNode>(N.getNode())) { 737*0fca6ea1SDimitry Andric if (BindVal) 738*0fca6ea1SDimitry Andric *BindVal = C->getAPIntValue(); 739*0fca6ea1SDimitry Andric return true; 740*0fca6ea1SDimitry Andric } 741*0fca6ea1SDimitry Andric 742*0fca6ea1SDimitry Andric APInt Discard; 743*0fca6ea1SDimitry Andric return ISD::isConstantSplatVector(N.getNode(), 744*0fca6ea1SDimitry Andric BindVal ? *BindVal : Discard); 745*0fca6ea1SDimitry Andric } 746*0fca6ea1SDimitry Andric }; 747*0fca6ea1SDimitry Andric /// Match any interger constants or splat of an integer constant. 748*0fca6ea1SDimitry Andric inline ConstantInt_match m_ConstInt() { return ConstantInt_match(nullptr); } 749*0fca6ea1SDimitry Andric /// Match any interger constants or splat of an integer constant; return the 750*0fca6ea1SDimitry Andric /// specific constant or constant splat value. 751*0fca6ea1SDimitry Andric inline ConstantInt_match m_ConstInt(APInt &V) { return ConstantInt_match(&V); } 752*0fca6ea1SDimitry Andric 753*0fca6ea1SDimitry Andric struct SpecificInt_match { 754*0fca6ea1SDimitry Andric APInt IntVal; 755*0fca6ea1SDimitry Andric 756*0fca6ea1SDimitry Andric explicit SpecificInt_match(APInt APV) : IntVal(std::move(APV)) {} 757*0fca6ea1SDimitry Andric 758*0fca6ea1SDimitry Andric template <typename MatchContext> 759*0fca6ea1SDimitry Andric bool match(const MatchContext &Ctx, SDValue N) { 760*0fca6ea1SDimitry Andric APInt ConstInt; 761*0fca6ea1SDimitry Andric if (sd_context_match(N, Ctx, m_ConstInt(ConstInt))) 762*0fca6ea1SDimitry Andric return APInt::isSameValue(IntVal, ConstInt); 763*0fca6ea1SDimitry Andric return false; 764*0fca6ea1SDimitry Andric } 765*0fca6ea1SDimitry Andric }; 766*0fca6ea1SDimitry Andric 767*0fca6ea1SDimitry Andric /// Match a specific integer constant or constant splat value. 768*0fca6ea1SDimitry Andric inline SpecificInt_match m_SpecificInt(APInt V) { 769*0fca6ea1SDimitry Andric return SpecificInt_match(std::move(V)); 770*0fca6ea1SDimitry Andric } 771*0fca6ea1SDimitry Andric inline SpecificInt_match m_SpecificInt(uint64_t V) { 772*0fca6ea1SDimitry Andric return SpecificInt_match(APInt(64, V)); 773*0fca6ea1SDimitry Andric } 774*0fca6ea1SDimitry Andric 775*0fca6ea1SDimitry Andric inline SpecificInt_match m_Zero() { return m_SpecificInt(0U); } 776*0fca6ea1SDimitry Andric inline SpecificInt_match m_One() { return m_SpecificInt(1U); } 777*0fca6ea1SDimitry Andric 778*0fca6ea1SDimitry Andric struct AllOnes_match { 779*0fca6ea1SDimitry Andric 780*0fca6ea1SDimitry Andric AllOnes_match() = default; 781*0fca6ea1SDimitry Andric 782*0fca6ea1SDimitry Andric template <typename MatchContext> bool match(const MatchContext &, SDValue N) { 783*0fca6ea1SDimitry Andric return isAllOnesOrAllOnesSplat(N); 784*0fca6ea1SDimitry Andric } 785*0fca6ea1SDimitry Andric }; 786*0fca6ea1SDimitry Andric 787*0fca6ea1SDimitry Andric inline AllOnes_match m_AllOnes() { return AllOnes_match(); } 788*0fca6ea1SDimitry Andric 789*0fca6ea1SDimitry Andric /// Match true boolean value based on the information provided by 790*0fca6ea1SDimitry Andric /// TargetLowering. 791*0fca6ea1SDimitry Andric inline auto m_True() { 792*0fca6ea1SDimitry Andric return TLI_pred_match{ 793*0fca6ea1SDimitry Andric [](const TargetLowering &TLI, SDValue N) { 794*0fca6ea1SDimitry Andric APInt ConstVal; 795*0fca6ea1SDimitry Andric if (sd_match(N, m_ConstInt(ConstVal))) 796*0fca6ea1SDimitry Andric switch (TLI.getBooleanContents(N.getValueType())) { 797*0fca6ea1SDimitry Andric case TargetLowering::ZeroOrOneBooleanContent: 798*0fca6ea1SDimitry Andric return ConstVal.isOne(); 799*0fca6ea1SDimitry Andric case TargetLowering::ZeroOrNegativeOneBooleanContent: 800*0fca6ea1SDimitry Andric return ConstVal.isAllOnes(); 801*0fca6ea1SDimitry Andric case TargetLowering::UndefinedBooleanContent: 802*0fca6ea1SDimitry Andric return (ConstVal & 0x01) == 1; 803*0fca6ea1SDimitry Andric } 804*0fca6ea1SDimitry Andric 805*0fca6ea1SDimitry Andric return false; 806*0fca6ea1SDimitry Andric }, 807*0fca6ea1SDimitry Andric m_Value()}; 808*0fca6ea1SDimitry Andric } 809*0fca6ea1SDimitry Andric /// Match false boolean value based on the information provided by 810*0fca6ea1SDimitry Andric /// TargetLowering. 811*0fca6ea1SDimitry Andric inline auto m_False() { 812*0fca6ea1SDimitry Andric return TLI_pred_match{ 813*0fca6ea1SDimitry Andric [](const TargetLowering &TLI, SDValue N) { 814*0fca6ea1SDimitry Andric APInt ConstVal; 815*0fca6ea1SDimitry Andric if (sd_match(N, m_ConstInt(ConstVal))) 816*0fca6ea1SDimitry Andric switch (TLI.getBooleanContents(N.getValueType())) { 817*0fca6ea1SDimitry Andric case TargetLowering::ZeroOrOneBooleanContent: 818*0fca6ea1SDimitry Andric case TargetLowering::ZeroOrNegativeOneBooleanContent: 819*0fca6ea1SDimitry Andric return ConstVal.isZero(); 820*0fca6ea1SDimitry Andric case TargetLowering::UndefinedBooleanContent: 821*0fca6ea1SDimitry Andric return (ConstVal & 0x01) == 0; 822*0fca6ea1SDimitry Andric } 823*0fca6ea1SDimitry Andric 824*0fca6ea1SDimitry Andric return false; 825*0fca6ea1SDimitry Andric }, 826*0fca6ea1SDimitry Andric m_Value()}; 827*0fca6ea1SDimitry Andric } 828*0fca6ea1SDimitry Andric 829*0fca6ea1SDimitry Andric struct CondCode_match { 830*0fca6ea1SDimitry Andric std::optional<ISD::CondCode> CCToMatch; 831*0fca6ea1SDimitry Andric ISD::CondCode *BindCC = nullptr; 832*0fca6ea1SDimitry Andric 833*0fca6ea1SDimitry Andric explicit CondCode_match(ISD::CondCode CC) : CCToMatch(CC) {} 834*0fca6ea1SDimitry Andric 835*0fca6ea1SDimitry Andric explicit CondCode_match(ISD::CondCode *CC) : BindCC(CC) {} 836*0fca6ea1SDimitry Andric 837*0fca6ea1SDimitry Andric template <typename MatchContext> bool match(const MatchContext &, SDValue N) { 838*0fca6ea1SDimitry Andric if (auto *CC = dyn_cast<CondCodeSDNode>(N.getNode())) { 839*0fca6ea1SDimitry Andric if (CCToMatch && *CCToMatch != CC->get()) 840*0fca6ea1SDimitry Andric return false; 841*0fca6ea1SDimitry Andric 842*0fca6ea1SDimitry Andric if (BindCC) 843*0fca6ea1SDimitry Andric *BindCC = CC->get(); 844*0fca6ea1SDimitry Andric return true; 845*0fca6ea1SDimitry Andric } 846*0fca6ea1SDimitry Andric 847*0fca6ea1SDimitry Andric return false; 848*0fca6ea1SDimitry Andric } 849*0fca6ea1SDimitry Andric }; 850*0fca6ea1SDimitry Andric 851*0fca6ea1SDimitry Andric /// Match any conditional code SDNode. 852*0fca6ea1SDimitry Andric inline CondCode_match m_CondCode() { return CondCode_match(nullptr); } 853*0fca6ea1SDimitry Andric /// Match any conditional code SDNode and return its ISD::CondCode value. 854*0fca6ea1SDimitry Andric inline CondCode_match m_CondCode(ISD::CondCode &CC) { 855*0fca6ea1SDimitry Andric return CondCode_match(&CC); 856*0fca6ea1SDimitry Andric } 857*0fca6ea1SDimitry Andric /// Match a conditional code SDNode with a specific ISD::CondCode. 858*0fca6ea1SDimitry Andric inline CondCode_match m_SpecificCondCode(ISD::CondCode CC) { 859*0fca6ea1SDimitry Andric return CondCode_match(CC); 860*0fca6ea1SDimitry Andric } 861*0fca6ea1SDimitry Andric 862*0fca6ea1SDimitry Andric /// Match a negate as a sub(0, v) 863*0fca6ea1SDimitry Andric template <typename ValTy> 864*0fca6ea1SDimitry Andric inline BinaryOpc_match<SpecificInt_match, ValTy> m_Neg(const ValTy &V) { 865*0fca6ea1SDimitry Andric return m_Sub(m_Zero(), V); 866*0fca6ea1SDimitry Andric } 867*0fca6ea1SDimitry Andric 868*0fca6ea1SDimitry Andric /// Match a Not as a xor(v, -1) or xor(-1, v) 869*0fca6ea1SDimitry Andric template <typename ValTy> 870*0fca6ea1SDimitry Andric inline BinaryOpc_match<ValTy, AllOnes_match, true> m_Not(const ValTy &V) { 871*0fca6ea1SDimitry Andric return m_Xor(V, m_AllOnes()); 872*0fca6ea1SDimitry Andric } 873*0fca6ea1SDimitry Andric 874*0fca6ea1SDimitry Andric } // namespace SDPatternMatch 875*0fca6ea1SDimitry Andric } // namespace llvm 876*0fca6ea1SDimitry Andric #endif 877