Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:34

0001 //==--------------- llvm/CodeGen/SDPatternMatch.h ---------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 /// \file
0009 /// Contains matchers for matching SelectionDAG nodes and values.
0010 ///
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_CODEGEN_SDPATTERNMATCH_H
0014 #define LLVM_CODEGEN_SDPATTERNMATCH_H
0015 
0016 #include "llvm/ADT/APInt.h"
0017 #include "llvm/ADT/STLExtras.h"
0018 #include "llvm/CodeGen/SelectionDAG.h"
0019 #include "llvm/CodeGen/SelectionDAGNodes.h"
0020 #include "llvm/CodeGen/TargetLowering.h"
0021 
0022 namespace llvm {
0023 namespace SDPatternMatch {
0024 
0025 /// MatchContext can repurpose existing patterns to behave differently under
0026 /// a certain context. For instance, `m_Opc(ISD::ADD)` matches plain ADD nodes
0027 /// in normal circumstances, but matches VP_ADD nodes under a custom
0028 /// VPMatchContext. This design is meant to facilitate code / pattern reusing.
0029 class BasicMatchContext {
0030   const SelectionDAG *DAG;
0031   const TargetLowering *TLI;
0032 
0033 public:
0034   explicit BasicMatchContext(const SelectionDAG *DAG)
0035       : DAG(DAG), TLI(DAG ? &DAG->getTargetLoweringInfo() : nullptr) {}
0036 
0037   explicit BasicMatchContext(const TargetLowering *TLI)
0038       : DAG(nullptr), TLI(TLI) {}
0039 
0040   // A valid MatchContext has to implement the following functions.
0041 
0042   const SelectionDAG *getDAG() const { return DAG; }
0043 
0044   const TargetLowering *getTLI() const { return TLI; }
0045 
0046   /// Return true if N effectively has opcode Opcode.
0047   bool match(SDValue N, unsigned Opcode) const {
0048     return N->getOpcode() == Opcode;
0049   }
0050 
0051   unsigned getNumOperands(SDValue N) const { return N->getNumOperands(); }
0052 };
0053 
0054 template <typename Pattern, typename MatchContext>
0055 [[nodiscard]] bool sd_context_match(SDValue N, const MatchContext &Ctx,
0056                                     Pattern &&P) {
0057   return P.match(Ctx, N);
0058 }
0059 
0060 template <typename Pattern, typename MatchContext>
0061 [[nodiscard]] bool sd_context_match(SDNode *N, const MatchContext &Ctx,
0062                                     Pattern &&P) {
0063   return sd_context_match(SDValue(N, 0), Ctx, P);
0064 }
0065 
0066 template <typename Pattern>
0067 [[nodiscard]] bool sd_match(SDNode *N, const SelectionDAG *DAG, Pattern &&P) {
0068   return sd_context_match(N, BasicMatchContext(DAG), P);
0069 }
0070 
0071 template <typename Pattern>
0072 [[nodiscard]] bool sd_match(SDValue N, const SelectionDAG *DAG, Pattern &&P) {
0073   return sd_context_match(N, BasicMatchContext(DAG), P);
0074 }
0075 
0076 template <typename Pattern>
0077 [[nodiscard]] bool sd_match(SDNode *N, Pattern &&P) {
0078   return sd_match(N, nullptr, P);
0079 }
0080 
0081 template <typename Pattern>
0082 [[nodiscard]] bool sd_match(SDValue N, Pattern &&P) {
0083   return sd_match(N, nullptr, P);
0084 }
0085 
0086 // === Utilities ===
0087 struct Value_match {
0088   SDValue MatchVal;
0089 
0090   Value_match() = default;
0091 
0092   explicit Value_match(SDValue Match) : MatchVal(Match) {}
0093 
0094   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
0095     if (MatchVal)
0096       return MatchVal == N;
0097     return N.getNode();
0098   }
0099 };
0100 
0101 /// Match any valid SDValue.
0102 inline Value_match m_Value() { return Value_match(); }
0103 
0104 inline Value_match m_Specific(SDValue N) {
0105   assert(N);
0106   return Value_match(N);
0107 }
0108 
0109 struct DeferredValue_match {
0110   SDValue &MatchVal;
0111 
0112   explicit DeferredValue_match(SDValue &Match) : MatchVal(Match) {}
0113 
0114   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
0115     return N == MatchVal;
0116   }
0117 };
0118 
0119 /// Similar to m_Specific, but the specific value to match is determined by
0120 /// another sub-pattern in the same sd_match() expression. For instance,
0121 /// We cannot match `(add V, V)` with `m_Add(m_Value(X), m_Specific(X))` since
0122 /// `X` is not initialized at the time it got copied into `m_Specific`. Instead,
0123 /// we should use `m_Add(m_Value(X), m_Deferred(X))`.
0124 inline DeferredValue_match m_Deferred(SDValue &V) {
0125   return DeferredValue_match(V);
0126 }
0127 
0128 struct Opcode_match {
0129   unsigned Opcode;
0130 
0131   explicit Opcode_match(unsigned Opc) : Opcode(Opc) {}
0132 
0133   template <typename MatchContext>
0134   bool match(const MatchContext &Ctx, SDValue N) {
0135     return Ctx.match(N, Opcode);
0136   }
0137 };
0138 
0139 inline Opcode_match m_Opc(unsigned Opcode) { return Opcode_match(Opcode); }
0140 
0141 inline Opcode_match m_Undef() { return Opcode_match(ISD::UNDEF); }
0142 
0143 template <unsigned NumUses, typename Pattern> struct NUses_match {
0144   Pattern P;
0145 
0146   explicit NUses_match(const Pattern &P) : P(P) {}
0147 
0148   template <typename MatchContext>
0149   bool match(const MatchContext &Ctx, SDValue N) {
0150     // SDNode::hasNUsesOfValue is pretty expensive when the SDNode produces
0151     // multiple results, hence we check the subsequent pattern here before
0152     // checking the number of value users.
0153     return P.match(Ctx, N) && N->hasNUsesOfValue(NumUses, N.getResNo());
0154   }
0155 };
0156 
0157 template <typename Pattern>
0158 inline NUses_match<1, Pattern> m_OneUse(const Pattern &P) {
0159   return NUses_match<1, Pattern>(P);
0160 }
0161 template <unsigned N, typename Pattern>
0162 inline NUses_match<N, Pattern> m_NUses(const Pattern &P) {
0163   return NUses_match<N, Pattern>(P);
0164 }
0165 
0166 inline NUses_match<1, Value_match> m_OneUse() {
0167   return NUses_match<1, Value_match>(m_Value());
0168 }
0169 template <unsigned N> inline NUses_match<N, Value_match> m_NUses() {
0170   return NUses_match<N, Value_match>(m_Value());
0171 }
0172 
0173 struct Value_bind {
0174   SDValue &BindVal;
0175 
0176   explicit Value_bind(SDValue &N) : BindVal(N) {}
0177 
0178   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
0179     BindVal = N;
0180     return true;
0181   }
0182 };
0183 
0184 inline Value_bind m_Value(SDValue &N) { return Value_bind(N); }
0185 
0186 template <typename Pattern, typename PredFuncT> struct TLI_pred_match {
0187   Pattern P;
0188   PredFuncT PredFunc;
0189 
0190   TLI_pred_match(const PredFuncT &Pred, const Pattern &P)
0191       : P(P), PredFunc(Pred) {}
0192 
0193   template <typename MatchContext>
0194   bool match(const MatchContext &Ctx, SDValue N) {
0195     assert(Ctx.getTLI() && "TargetLowering is required for this pattern.");
0196     return PredFunc(*Ctx.getTLI(), N) && P.match(Ctx, N);
0197   }
0198 };
0199 
0200 // Explicit deduction guide.
0201 template <typename PredFuncT, typename Pattern>
0202 TLI_pred_match(const PredFuncT &Pred, const Pattern &P)
0203     -> TLI_pred_match<Pattern, PredFuncT>;
0204 
0205 /// Match legal SDNodes based on the information provided by TargetLowering.
0206 template <typename Pattern> inline auto m_LegalOp(const Pattern &P) {
0207   return TLI_pred_match{[](const TargetLowering &TLI, SDValue N) {
0208                           return TLI.isOperationLegal(N->getOpcode(),
0209                                                       N.getValueType());
0210                         },
0211                         P};
0212 }
0213 
0214 /// Switch to a different MatchContext for subsequent patterns.
0215 template <typename NewMatchContext, typename Pattern> struct SwitchContext {
0216   const NewMatchContext &Ctx;
0217   Pattern P;
0218 
0219   template <typename OrigMatchContext>
0220   bool match(const OrigMatchContext &, SDValue N) {
0221     return P.match(Ctx, N);
0222   }
0223 };
0224 
0225 template <typename MatchContext, typename Pattern>
0226 inline SwitchContext<MatchContext, Pattern> m_Context(const MatchContext &Ctx,
0227                                                       Pattern &&P) {
0228   return SwitchContext<MatchContext, Pattern>{Ctx, std::move(P)};
0229 }
0230 
0231 // === Value type ===
0232 struct ValueType_bind {
0233   EVT &BindVT;
0234 
0235   explicit ValueType_bind(EVT &Bind) : BindVT(Bind) {}
0236 
0237   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
0238     BindVT = N.getValueType();
0239     return true;
0240   }
0241 };
0242 
0243 /// Retreive the ValueType of the current SDValue.
0244 inline ValueType_bind m_VT(EVT &VT) { return ValueType_bind(VT); }
0245 
0246 template <typename Pattern, typename PredFuncT> struct ValueType_match {
0247   PredFuncT PredFunc;
0248   Pattern P;
0249 
0250   ValueType_match(const PredFuncT &Pred, const Pattern &P)
0251       : PredFunc(Pred), P(P) {}
0252 
0253   template <typename MatchContext>
0254   bool match(const MatchContext &Ctx, SDValue N) {
0255     return PredFunc(N.getValueType()) && P.match(Ctx, N);
0256   }
0257 };
0258 
0259 // Explicit deduction guide.
0260 template <typename PredFuncT, typename Pattern>
0261 ValueType_match(const PredFuncT &Pred, const Pattern &P)
0262     -> ValueType_match<Pattern, PredFuncT>;
0263 
0264 /// Match a specific ValueType.
0265 template <typename Pattern>
0266 inline auto m_SpecificVT(EVT RefVT, const Pattern &P) {
0267   return ValueType_match{[=](EVT VT) { return VT == RefVT; }, P};
0268 }
0269 inline auto m_SpecificVT(EVT RefVT) {
0270   return ValueType_match{[=](EVT VT) { return VT == RefVT; }, m_Value()};
0271 }
0272 
0273 inline auto m_Glue() { return m_SpecificVT(MVT::Glue); }
0274 inline auto m_OtherVT() { return m_SpecificVT(MVT::Other); }
0275 
0276 /// Match any integer ValueTypes.
0277 template <typename Pattern> inline auto m_IntegerVT(const Pattern &P) {
0278   return ValueType_match{[](EVT VT) { return VT.isInteger(); }, P};
0279 }
0280 inline auto m_IntegerVT() {
0281   return ValueType_match{[](EVT VT) { return VT.isInteger(); }, m_Value()};
0282 }
0283 
0284 /// Match any floating point ValueTypes.
0285 template <typename Pattern> inline auto m_FloatingPointVT(const Pattern &P) {
0286   return ValueType_match{[](EVT VT) { return VT.isFloatingPoint(); }, P};
0287 }
0288 inline auto m_FloatingPointVT() {
0289   return ValueType_match{[](EVT VT) { return VT.isFloatingPoint(); },
0290                          m_Value()};
0291 }
0292 
0293 /// Match any vector ValueTypes.
0294 template <typename Pattern> inline auto m_VectorVT(const Pattern &P) {
0295   return ValueType_match{[](EVT VT) { return VT.isVector(); }, P};
0296 }
0297 inline auto m_VectorVT() {
0298   return ValueType_match{[](EVT VT) { return VT.isVector(); }, m_Value()};
0299 }
0300 
0301 /// Match fixed-length vector ValueTypes.
0302 template <typename Pattern> inline auto m_FixedVectorVT(const Pattern &P) {
0303   return ValueType_match{[](EVT VT) { return VT.isFixedLengthVector(); }, P};
0304 }
0305 inline auto m_FixedVectorVT() {
0306   return ValueType_match{[](EVT VT) { return VT.isFixedLengthVector(); },
0307                          m_Value()};
0308 }
0309 
0310 /// Match scalable vector ValueTypes.
0311 template <typename Pattern> inline auto m_ScalableVectorVT(const Pattern &P) {
0312   return ValueType_match{[](EVT VT) { return VT.isScalableVector(); }, P};
0313 }
0314 inline auto m_ScalableVectorVT() {
0315   return ValueType_match{[](EVT VT) { return VT.isScalableVector(); },
0316                          m_Value()};
0317 }
0318 
0319 /// Match legal ValueTypes based on the information provided by TargetLowering.
0320 template <typename Pattern> inline auto m_LegalType(const Pattern &P) {
0321   return TLI_pred_match{[](const TargetLowering &TLI, SDValue N) {
0322                           return TLI.isTypeLegal(N.getValueType());
0323                         },
0324                         P};
0325 }
0326 
0327 // === Patterns combinators ===
0328 template <typename... Preds> struct And {
0329   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
0330     return true;
0331   }
0332 };
0333 
0334 template <typename Pred, typename... Preds>
0335 struct And<Pred, Preds...> : And<Preds...> {
0336   Pred P;
0337   And(const Pred &p, const Preds &...preds) : And<Preds...>(preds...), P(p) {}
0338 
0339   template <typename MatchContext>
0340   bool match(const MatchContext &Ctx, SDValue N) {
0341     return P.match(Ctx, N) && And<Preds...>::match(Ctx, N);
0342   }
0343 };
0344 
0345 template <typename... Preds> struct Or {
0346   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
0347     return false;
0348   }
0349 };
0350 
0351 template <typename Pred, typename... Preds>
0352 struct Or<Pred, Preds...> : Or<Preds...> {
0353   Pred P;
0354   Or(const Pred &p, const Preds &...preds) : Or<Preds...>(preds...), P(p) {}
0355 
0356   template <typename MatchContext>
0357   bool match(const MatchContext &Ctx, SDValue N) {
0358     return P.match(Ctx, N) || Or<Preds...>::match(Ctx, N);
0359   }
0360 };
0361 
0362 template <typename Pred> struct Not {
0363   Pred P;
0364 
0365   explicit Not(const Pred &P) : P(P) {}
0366 
0367   template <typename MatchContext>
0368   bool match(const MatchContext &Ctx, SDValue N) {
0369     return !P.match(Ctx, N);
0370   }
0371 };
0372 // Explicit deduction guide.
0373 template <typename Pred> Not(const Pred &P) -> Not<Pred>;
0374 
0375 /// Match if the inner pattern does NOT match.
0376 template <typename Pred> inline Not<Pred> m_Unless(const Pred &P) {
0377   return Not{P};
0378 }
0379 
0380 template <typename... Preds> And<Preds...> m_AllOf(const Preds &...preds) {
0381   return And<Preds...>(preds...);
0382 }
0383 
0384 template <typename... Preds> Or<Preds...> m_AnyOf(const Preds &...preds) {
0385   return Or<Preds...>(preds...);
0386 }
0387 
0388 template <typename... Preds> auto m_NoneOf(const Preds &...preds) {
0389   return m_Unless(m_AnyOf(preds...));
0390 }
0391 
0392 // === Generic node matching ===
0393 template <unsigned OpIdx, typename... OpndPreds> struct Operands_match {
0394   template <typename MatchContext>
0395   bool match(const MatchContext &Ctx, SDValue N) {
0396     // Returns false if there are more operands than predicates;
0397     // Ignores the last two operands if both the Context and the Node are VP
0398     return Ctx.getNumOperands(N) == OpIdx;
0399   }
0400 };
0401 
0402 template <unsigned OpIdx, typename OpndPred, typename... OpndPreds>
0403 struct Operands_match<OpIdx, OpndPred, OpndPreds...>
0404     : Operands_match<OpIdx + 1, OpndPreds...> {
0405   OpndPred P;
0406 
0407   Operands_match(const OpndPred &p, const OpndPreds &...preds)
0408       : Operands_match<OpIdx + 1, OpndPreds...>(preds...), P(p) {}
0409 
0410   template <typename MatchContext>
0411   bool match(const MatchContext &Ctx, SDValue N) {
0412     if (OpIdx < N->getNumOperands())
0413       return P.match(Ctx, N->getOperand(OpIdx)) &&
0414              Operands_match<OpIdx + 1, OpndPreds...>::match(Ctx, N);
0415 
0416     // This is the case where there are more predicates than operands.
0417     return false;
0418   }
0419 };
0420 
0421 template <typename... OpndPreds>
0422 auto m_Node(unsigned Opcode, const OpndPreds &...preds) {
0423   return m_AllOf(m_Opc(Opcode), Operands_match<0, OpndPreds...>(preds...));
0424 }
0425 
0426 /// Provide number of operands that are not chain or glue, as well as the first
0427 /// index of such operand.
0428 template <bool ExcludeChain> struct EffectiveOperands {
0429   unsigned Size = 0;
0430   unsigned FirstIndex = 0;
0431 
0432   template <typename MatchContext>
0433   explicit EffectiveOperands(SDValue N, const MatchContext &Ctx) {
0434     const unsigned TotalNumOps = Ctx.getNumOperands(N);
0435     FirstIndex = TotalNumOps;
0436     for (unsigned I = 0; I < TotalNumOps; ++I) {
0437       // Count the number of non-chain and non-glue nodes (we ignore chain
0438       // and glue by default) and retreive the operand index offset.
0439       EVT VT = N->getOperand(I).getValueType();
0440       if (VT != MVT::Glue && VT != MVT::Other) {
0441         ++Size;
0442         if (FirstIndex == TotalNumOps)
0443           FirstIndex = I;
0444       }
0445     }
0446   }
0447 };
0448 
0449 template <> struct EffectiveOperands<false> {
0450   unsigned Size = 0;
0451   unsigned FirstIndex = 0;
0452 
0453   template <typename MatchContext>
0454   explicit EffectiveOperands(SDValue N, const MatchContext &Ctx)
0455       : Size(Ctx.getNumOperands(N)) {}
0456 };
0457 
0458 // === Ternary operations ===
0459 template <typename T0_P, typename T1_P, typename T2_P, bool Commutable = false,
0460           bool ExcludeChain = false>
0461 struct TernaryOpc_match {
0462   unsigned Opcode;
0463   T0_P Op0;
0464   T1_P Op1;
0465   T2_P Op2;
0466 
0467   TernaryOpc_match(unsigned Opc, const T0_P &Op0, const T1_P &Op1,
0468                    const T2_P &Op2)
0469       : Opcode(Opc), Op0(Op0), Op1(Op1), Op2(Op2) {}
0470 
0471   template <typename MatchContext>
0472   bool match(const MatchContext &Ctx, SDValue N) {
0473     if (sd_context_match(N, Ctx, m_Opc(Opcode))) {
0474       EffectiveOperands<ExcludeChain> EO(N, Ctx);
0475       assert(EO.Size == 3);
0476       return ((Op0.match(Ctx, N->getOperand(EO.FirstIndex)) &&
0477                Op1.match(Ctx, N->getOperand(EO.FirstIndex + 1))) ||
0478               (Commutable && Op0.match(Ctx, N->getOperand(EO.FirstIndex + 1)) &&
0479                Op1.match(Ctx, N->getOperand(EO.FirstIndex)))) &&
0480              Op2.match(Ctx, N->getOperand(EO.FirstIndex + 2));
0481     }
0482 
0483     return false;
0484   }
0485 };
0486 
0487 template <typename T0_P, typename T1_P, typename T2_P>
0488 inline TernaryOpc_match<T0_P, T1_P, T2_P>
0489 m_SetCC(const T0_P &LHS, const T1_P &RHS, const T2_P &CC) {
0490   return TernaryOpc_match<T0_P, T1_P, T2_P>(ISD::SETCC, LHS, RHS, CC);
0491 }
0492 
0493 template <typename T0_P, typename T1_P, typename T2_P>
0494 inline TernaryOpc_match<T0_P, T1_P, T2_P, true, false>
0495 m_c_SetCC(const T0_P &LHS, const T1_P &RHS, const T2_P &CC) {
0496   return TernaryOpc_match<T0_P, T1_P, T2_P, true, false>(ISD::SETCC, LHS, RHS,
0497                                                          CC);
0498 }
0499 
0500 template <typename T0_P, typename T1_P, typename T2_P>
0501 inline TernaryOpc_match<T0_P, T1_P, T2_P>
0502 m_Select(const T0_P &Cond, const T1_P &T, const T2_P &F) {
0503   return TernaryOpc_match<T0_P, T1_P, T2_P>(ISD::SELECT, Cond, T, F);
0504 }
0505 
0506 template <typename T0_P, typename T1_P, typename T2_P>
0507 inline TernaryOpc_match<T0_P, T1_P, T2_P>
0508 m_VSelect(const T0_P &Cond, const T1_P &T, const T2_P &F) {
0509   return TernaryOpc_match<T0_P, T1_P, T2_P>(ISD::VSELECT, Cond, T, F);
0510 }
0511 
0512 template <typename T0_P, typename T1_P, typename T2_P>
0513 inline TernaryOpc_match<T0_P, T1_P, T2_P>
0514 m_InsertElt(const T0_P &Vec, const T1_P &Val, const T2_P &Idx) {
0515   return TernaryOpc_match<T0_P, T1_P, T2_P>(ISD::INSERT_VECTOR_ELT, Vec, Val,
0516                                             Idx);
0517 }
0518 
0519 template <typename LHS, typename RHS, typename IDX>
0520 inline TernaryOpc_match<LHS, RHS, IDX>
0521 m_InsertSubvector(const LHS &Base, const RHS &Sub, const IDX &Idx) {
0522   return TernaryOpc_match<LHS, RHS, IDX>(ISD::INSERT_SUBVECTOR, Base, Sub, Idx);
0523 }
0524 
0525 // === Binary operations ===
0526 template <typename LHS_P, typename RHS_P, bool Commutable = false,
0527           bool ExcludeChain = false>
0528 struct BinaryOpc_match {
0529   unsigned Opcode;
0530   LHS_P LHS;
0531   RHS_P RHS;
0532   std::optional<SDNodeFlags> Flags;
0533   BinaryOpc_match(unsigned Opc, const LHS_P &L, const RHS_P &R,
0534                   std::optional<SDNodeFlags> Flgs = std::nullopt)
0535       : Opcode(Opc), LHS(L), RHS(R), Flags(Flgs) {}
0536 
0537   template <typename MatchContext>
0538   bool match(const MatchContext &Ctx, SDValue N) {
0539     if (sd_context_match(N, Ctx, m_Opc(Opcode))) {
0540       EffectiveOperands<ExcludeChain> EO(N, Ctx);
0541       assert(EO.Size == 2);
0542       if (!((LHS.match(Ctx, N->getOperand(EO.FirstIndex)) &&
0543              RHS.match(Ctx, N->getOperand(EO.FirstIndex + 1))) ||
0544             (Commutable && LHS.match(Ctx, N->getOperand(EO.FirstIndex + 1)) &&
0545              RHS.match(Ctx, N->getOperand(EO.FirstIndex)))))
0546         return false;
0547 
0548       if (!Flags.has_value())
0549         return true;
0550 
0551       return (*Flags & N->getFlags()) == *Flags;
0552     }
0553 
0554     return false;
0555   }
0556 };
0557 
0558 /// Matching while capturing mask
0559 template <typename T0, typename T1, typename T2> struct SDShuffle_match {
0560   T0 Op1;
0561   T1 Op2;
0562   T2 Mask;
0563 
0564   SDShuffle_match(const T0 &Op1, const T1 &Op2, const T2 &Mask)
0565       : Op1(Op1), Op2(Op2), Mask(Mask) {}
0566 
0567   template <typename MatchContext>
0568   bool match(const MatchContext &Ctx, SDValue N) {
0569     if (auto *I = dyn_cast<ShuffleVectorSDNode>(N)) {
0570       return Op1.match(Ctx, I->getOperand(0)) &&
0571              Op2.match(Ctx, I->getOperand(1)) && Mask.match(I->getMask());
0572     }
0573     return false;
0574   }
0575 };
0576 struct m_Mask {
0577   ArrayRef<int> &MaskRef;
0578   m_Mask(ArrayRef<int> &MaskRef) : MaskRef(MaskRef) {}
0579   bool match(ArrayRef<int> Mask) {
0580     MaskRef = Mask;
0581     return true;
0582   }
0583 };
0584 
0585 struct m_SpecificMask {
0586   ArrayRef<int> MaskRef;
0587   m_SpecificMask(ArrayRef<int> MaskRef) : MaskRef(MaskRef) {}
0588   bool match(ArrayRef<int> Mask) { return MaskRef == Mask; }
0589 };
0590 
0591 template <typename LHS_P, typename RHS_P, typename Pred_t,
0592           bool Commutable = false, bool ExcludeChain = false>
0593 struct MaxMin_match {
0594   using PredType = Pred_t;
0595   LHS_P LHS;
0596   RHS_P RHS;
0597 
0598   MaxMin_match(const LHS_P &L, const RHS_P &R) : LHS(L), RHS(R) {}
0599 
0600   template <typename MatchContext>
0601   bool match(const MatchContext &Ctx, SDValue N) {
0602     if (sd_context_match(N, Ctx, m_Opc(ISD::SELECT)) ||
0603         sd_context_match(N, Ctx, m_Opc(ISD::VSELECT))) {
0604       EffectiveOperands<ExcludeChain> EO_SELECT(N, Ctx);
0605       assert(EO_SELECT.Size == 3);
0606       SDValue Cond = N->getOperand(EO_SELECT.FirstIndex);
0607       SDValue TrueValue = N->getOperand(EO_SELECT.FirstIndex + 1);
0608       SDValue FalseValue = N->getOperand(EO_SELECT.FirstIndex + 2);
0609 
0610       if (sd_context_match(Cond, Ctx, m_Opc(ISD::SETCC))) {
0611         EffectiveOperands<ExcludeChain> EO_SETCC(Cond, Ctx);
0612         assert(EO_SETCC.Size == 3);
0613         SDValue L = Cond->getOperand(EO_SETCC.FirstIndex);
0614         SDValue R = Cond->getOperand(EO_SETCC.FirstIndex + 1);
0615         auto *CondNode =
0616             cast<CondCodeSDNode>(Cond->getOperand(EO_SETCC.FirstIndex + 2));
0617 
0618         if ((TrueValue != L || FalseValue != R) &&
0619             (TrueValue != R || FalseValue != L)) {
0620           return false;
0621         }
0622 
0623         ISD::CondCode Cond =
0624             TrueValue == L ? CondNode->get()
0625                            : getSetCCInverse(CondNode->get(), L.getValueType());
0626         if (!Pred_t::match(Cond)) {
0627           return false;
0628         }
0629         return (LHS.match(Ctx, L) && RHS.match(Ctx, R)) ||
0630                (Commutable && LHS.match(Ctx, R) && RHS.match(Ctx, L));
0631       }
0632     }
0633 
0634     return false;
0635   }
0636 };
0637 
0638 // Helper class for identifying signed max predicates.
0639 struct smax_pred_ty {
0640   static bool match(ISD::CondCode Cond) {
0641     return Cond == ISD::CondCode::SETGT || Cond == ISD::CondCode::SETGE;
0642   }
0643 };
0644 
0645 // Helper class for identifying unsigned max predicates.
0646 struct umax_pred_ty {
0647   static bool match(ISD::CondCode Cond) {
0648     return Cond == ISD::CondCode::SETUGT || Cond == ISD::CondCode::SETUGE;
0649   }
0650 };
0651 
0652 // Helper class for identifying signed min predicates.
0653 struct smin_pred_ty {
0654   static bool match(ISD::CondCode Cond) {
0655     return Cond == ISD::CondCode::SETLT || Cond == ISD::CondCode::SETLE;
0656   }
0657 };
0658 
0659 // Helper class for identifying unsigned min predicates.
0660 struct umin_pred_ty {
0661   static bool match(ISD::CondCode Cond) {
0662     return Cond == ISD::CondCode::SETULT || Cond == ISD::CondCode::SETULE;
0663   }
0664 };
0665 
0666 template <typename LHS, typename RHS>
0667 inline BinaryOpc_match<LHS, RHS> m_BinOp(unsigned Opc, const LHS &L,
0668                                          const RHS &R) {
0669   return BinaryOpc_match<LHS, RHS>(Opc, L, R);
0670 }
0671 template <typename LHS, typename RHS>
0672 inline BinaryOpc_match<LHS, RHS, true> m_c_BinOp(unsigned Opc, const LHS &L,
0673                                                  const RHS &R) {
0674   return BinaryOpc_match<LHS, RHS, true>(Opc, L, R);
0675 }
0676 
0677 template <typename LHS, typename RHS>
0678 inline BinaryOpc_match<LHS, RHS, false, true>
0679 m_ChainedBinOp(unsigned Opc, const LHS &L, const RHS &R) {
0680   return BinaryOpc_match<LHS, RHS, false, true>(Opc, L, R);
0681 }
0682 template <typename LHS, typename RHS>
0683 inline BinaryOpc_match<LHS, RHS, true, true>
0684 m_c_ChainedBinOp(unsigned Opc, const LHS &L, const RHS &R) {
0685   return BinaryOpc_match<LHS, RHS, true, true>(Opc, L, R);
0686 }
0687 
0688 // Common binary operations
0689 template <typename LHS, typename RHS>
0690 inline BinaryOpc_match<LHS, RHS, true> m_Add(const LHS &L, const RHS &R) {
0691   return BinaryOpc_match<LHS, RHS, true>(ISD::ADD, L, R);
0692 }
0693 
0694 template <typename LHS, typename RHS>
0695 inline BinaryOpc_match<LHS, RHS> m_Sub(const LHS &L, const RHS &R) {
0696   return BinaryOpc_match<LHS, RHS>(ISD::SUB, L, R);
0697 }
0698 
0699 template <typename LHS, typename RHS>
0700 inline BinaryOpc_match<LHS, RHS, true> m_Mul(const LHS &L, const RHS &R) {
0701   return BinaryOpc_match<LHS, RHS, true>(ISD::MUL, L, R);
0702 }
0703 
0704 template <typename LHS, typename RHS>
0705 inline BinaryOpc_match<LHS, RHS, true> m_And(const LHS &L, const RHS &R) {
0706   return BinaryOpc_match<LHS, RHS, true>(ISD::AND, L, R);
0707 }
0708 
0709 template <typename LHS, typename RHS>
0710 inline BinaryOpc_match<LHS, RHS, true> m_Or(const LHS &L, const RHS &R) {
0711   return BinaryOpc_match<LHS, RHS, true>(ISD::OR, L, R);
0712 }
0713 
0714 template <typename LHS, typename RHS>
0715 inline BinaryOpc_match<LHS, RHS, true> m_DisjointOr(const LHS &L,
0716                                                     const RHS &R) {
0717   return BinaryOpc_match<LHS, RHS, true>(ISD::OR, L, R, SDNodeFlags::Disjoint);
0718 }
0719 
0720 template <typename LHS, typename RHS>
0721 inline auto m_AddLike(const LHS &L, const RHS &R) {
0722   return m_AnyOf(m_Add(L, R), m_DisjointOr(L, R));
0723 }
0724 
0725 template <typename LHS, typename RHS>
0726 inline BinaryOpc_match<LHS, RHS, true> m_Xor(const LHS &L, const RHS &R) {
0727   return BinaryOpc_match<LHS, RHS, true>(ISD::XOR, L, R);
0728 }
0729 
0730 template <typename LHS, typename RHS>
0731 inline BinaryOpc_match<LHS, RHS, true> m_SMin(const LHS &L, const RHS &R) {
0732   return BinaryOpc_match<LHS, RHS, true>(ISD::SMIN, L, R);
0733 }
0734 
0735 template <typename LHS, typename RHS>
0736 inline auto m_SMinLike(const LHS &L, const RHS &R) {
0737   return m_AnyOf(BinaryOpc_match<LHS, RHS, true>(ISD::SMIN, L, R),
0738                  MaxMin_match<LHS, RHS, smin_pred_ty, true>(L, R));
0739 }
0740 
0741 template <typename LHS, typename RHS>
0742 inline BinaryOpc_match<LHS, RHS, true> m_SMax(const LHS &L, const RHS &R) {
0743   return BinaryOpc_match<LHS, RHS, true>(ISD::SMAX, L, R);
0744 }
0745 
0746 template <typename LHS, typename RHS>
0747 inline auto m_SMaxLike(const LHS &L, const RHS &R) {
0748   return m_AnyOf(BinaryOpc_match<LHS, RHS, true>(ISD::SMAX, L, R),
0749                  MaxMin_match<LHS, RHS, smax_pred_ty, true>(L, R));
0750 }
0751 
0752 template <typename LHS, typename RHS>
0753 inline BinaryOpc_match<LHS, RHS, true> m_UMin(const LHS &L, const RHS &R) {
0754   return BinaryOpc_match<LHS, RHS, true>(ISD::UMIN, L, R);
0755 }
0756 
0757 template <typename LHS, typename RHS>
0758 inline auto m_UMinLike(const LHS &L, const RHS &R) {
0759   return m_AnyOf(BinaryOpc_match<LHS, RHS, true>(ISD::UMIN, L, R),
0760                  MaxMin_match<LHS, RHS, umin_pred_ty, true>(L, R));
0761 }
0762 
0763 template <typename LHS, typename RHS>
0764 inline BinaryOpc_match<LHS, RHS, true> m_UMax(const LHS &L, const RHS &R) {
0765   return BinaryOpc_match<LHS, RHS, true>(ISD::UMAX, L, R);
0766 }
0767 
0768 template <typename LHS, typename RHS>
0769 inline auto m_UMaxLike(const LHS &L, const RHS &R) {
0770   return m_AnyOf(BinaryOpc_match<LHS, RHS, true>(ISD::UMAX, L, R),
0771                  MaxMin_match<LHS, RHS, umax_pred_ty, true>(L, R));
0772 }
0773 
0774 template <typename LHS, typename RHS>
0775 inline BinaryOpc_match<LHS, RHS> m_UDiv(const LHS &L, const RHS &R) {
0776   return BinaryOpc_match<LHS, RHS>(ISD::UDIV, L, R);
0777 }
0778 template <typename LHS, typename RHS>
0779 inline BinaryOpc_match<LHS, RHS> m_SDiv(const LHS &L, const RHS &R) {
0780   return BinaryOpc_match<LHS, RHS>(ISD::SDIV, L, R);
0781 }
0782 
0783 template <typename LHS, typename RHS>
0784 inline BinaryOpc_match<LHS, RHS> m_URem(const LHS &L, const RHS &R) {
0785   return BinaryOpc_match<LHS, RHS>(ISD::UREM, L, R);
0786 }
0787 template <typename LHS, typename RHS>
0788 inline BinaryOpc_match<LHS, RHS> m_SRem(const LHS &L, const RHS &R) {
0789   return BinaryOpc_match<LHS, RHS>(ISD::SREM, L, R);
0790 }
0791 
0792 template <typename LHS, typename RHS>
0793 inline BinaryOpc_match<LHS, RHS> m_Shl(const LHS &L, const RHS &R) {
0794   return BinaryOpc_match<LHS, RHS>(ISD::SHL, L, R);
0795 }
0796 
0797 template <typename LHS, typename RHS>
0798 inline BinaryOpc_match<LHS, RHS> m_Sra(const LHS &L, const RHS &R) {
0799   return BinaryOpc_match<LHS, RHS>(ISD::SRA, L, R);
0800 }
0801 template <typename LHS, typename RHS>
0802 inline BinaryOpc_match<LHS, RHS> m_Srl(const LHS &L, const RHS &R) {
0803   return BinaryOpc_match<LHS, RHS>(ISD::SRL, L, R);
0804 }
0805 
0806 template <typename LHS, typename RHS>
0807 inline BinaryOpc_match<LHS, RHS> m_Rotl(const LHS &L, const RHS &R) {
0808   return BinaryOpc_match<LHS, RHS>(ISD::ROTL, L, R);
0809 }
0810 
0811 template <typename LHS, typename RHS>
0812 inline BinaryOpc_match<LHS, RHS> m_Rotr(const LHS &L, const RHS &R) {
0813   return BinaryOpc_match<LHS, RHS>(ISD::ROTR, L, R);
0814 }
0815 
0816 template <typename LHS, typename RHS>
0817 inline BinaryOpc_match<LHS, RHS, true> m_FAdd(const LHS &L, const RHS &R) {
0818   return BinaryOpc_match<LHS, RHS, true>(ISD::FADD, L, R);
0819 }
0820 
0821 template <typename LHS, typename RHS>
0822 inline BinaryOpc_match<LHS, RHS> m_FSub(const LHS &L, const RHS &R) {
0823   return BinaryOpc_match<LHS, RHS>(ISD::FSUB, L, R);
0824 }
0825 
0826 template <typename LHS, typename RHS>
0827 inline BinaryOpc_match<LHS, RHS, true> m_FMul(const LHS &L, const RHS &R) {
0828   return BinaryOpc_match<LHS, RHS, true>(ISD::FMUL, L, R);
0829 }
0830 
0831 template <typename LHS, typename RHS>
0832 inline BinaryOpc_match<LHS, RHS> m_FDiv(const LHS &L, const RHS &R) {
0833   return BinaryOpc_match<LHS, RHS>(ISD::FDIV, L, R);
0834 }
0835 
0836 template <typename LHS, typename RHS>
0837 inline BinaryOpc_match<LHS, RHS> m_FRem(const LHS &L, const RHS &R) {
0838   return BinaryOpc_match<LHS, RHS>(ISD::FREM, L, R);
0839 }
0840 
0841 template <typename V1_t, typename V2_t>
0842 inline BinaryOpc_match<V1_t, V2_t> m_Shuffle(const V1_t &v1, const V2_t &v2) {
0843   return BinaryOpc_match<V1_t, V2_t>(ISD::VECTOR_SHUFFLE, v1, v2);
0844 }
0845 
0846 template <typename V1_t, typename V2_t, typename Mask_t>
0847 inline SDShuffle_match<V1_t, V2_t, Mask_t>
0848 m_Shuffle(const V1_t &v1, const V2_t &v2, const Mask_t &mask) {
0849   return SDShuffle_match<V1_t, V2_t, Mask_t>(v1, v2, mask);
0850 }
0851 
0852 template <typename LHS, typename RHS>
0853 inline BinaryOpc_match<LHS, RHS> m_ExtractElt(const LHS &Vec, const RHS &Idx) {
0854   return BinaryOpc_match<LHS, RHS>(ISD::EXTRACT_VECTOR_ELT, Vec, Idx);
0855 }
0856 
0857 template <typename LHS, typename RHS>
0858 inline BinaryOpc_match<LHS, RHS> m_ExtractSubvector(const LHS &Vec,
0859                                                     const RHS &Idx) {
0860   return BinaryOpc_match<LHS, RHS>(ISD::EXTRACT_SUBVECTOR, Vec, Idx);
0861 }
0862 
0863 // === Unary operations ===
0864 template <typename Opnd_P, bool ExcludeChain = false> struct UnaryOpc_match {
0865   unsigned Opcode;
0866   Opnd_P Opnd;
0867   std::optional<SDNodeFlags> Flags;
0868   UnaryOpc_match(unsigned Opc, const Opnd_P &Op,
0869                  std::optional<SDNodeFlags> Flgs = std::nullopt)
0870       : Opcode(Opc), Opnd(Op), Flags(Flgs) {}
0871 
0872   template <typename MatchContext>
0873   bool match(const MatchContext &Ctx, SDValue N) {
0874     if (sd_context_match(N, Ctx, m_Opc(Opcode))) {
0875       EffectiveOperands<ExcludeChain> EO(N, Ctx);
0876       assert(EO.Size == 1);
0877       if (!Opnd.match(Ctx, N->getOperand(EO.FirstIndex)))
0878         return false;
0879       if (!Flags.has_value())
0880         return true;
0881 
0882       return (*Flags & N->getFlags()) == *Flags;
0883     }
0884 
0885     return false;
0886   }
0887 };
0888 
0889 template <typename Opnd>
0890 inline UnaryOpc_match<Opnd> m_UnaryOp(unsigned Opc, const Opnd &Op) {
0891   return UnaryOpc_match<Opnd>(Opc, Op);
0892 }
0893 template <typename Opnd>
0894 inline UnaryOpc_match<Opnd, true> m_ChainedUnaryOp(unsigned Opc,
0895                                                    const Opnd &Op) {
0896   return UnaryOpc_match<Opnd, true>(Opc, Op);
0897 }
0898 
0899 template <typename Opnd> inline UnaryOpc_match<Opnd> m_BitCast(const Opnd &Op) {
0900   return UnaryOpc_match<Opnd>(ISD::BITCAST, Op);
0901 }
0902 
0903 template <typename Opnd>
0904 inline UnaryOpc_match<Opnd> m_BSwap(const Opnd &Op) {
0905   return UnaryOpc_match<Opnd>(ISD::BSWAP, Op);
0906 }
0907 
0908 template <typename Opnd>
0909 inline UnaryOpc_match<Opnd> m_BitReverse(const Opnd &Op) {
0910   return UnaryOpc_match<Opnd>(ISD::BITREVERSE, Op);
0911 }
0912 
0913 template <typename Opnd> inline UnaryOpc_match<Opnd> m_ZExt(const Opnd &Op) {
0914   return UnaryOpc_match<Opnd>(ISD::ZERO_EXTEND, Op);
0915 }
0916 
0917 template <typename Opnd>
0918 inline UnaryOpc_match<Opnd> m_NNegZExt(const Opnd &Op) {
0919   return UnaryOpc_match<Opnd>(ISD::ZERO_EXTEND, Op, SDNodeFlags::NonNeg);
0920 }
0921 
0922 template <typename Opnd> inline auto m_SExt(const Opnd &Op) {
0923   return UnaryOpc_match<Opnd>(ISD::SIGN_EXTEND, Op);
0924 }
0925 
0926 template <typename Opnd> inline UnaryOpc_match<Opnd> m_AnyExt(const Opnd &Op) {
0927   return UnaryOpc_match<Opnd>(ISD::ANY_EXTEND, Op);
0928 }
0929 
0930 template <typename Opnd> inline UnaryOpc_match<Opnd> m_Trunc(const Opnd &Op) {
0931   return UnaryOpc_match<Opnd>(ISD::TRUNCATE, Op);
0932 }
0933 
0934 /// Match a zext or identity
0935 /// Allows to peek through optional extensions
0936 template <typename Opnd> inline auto m_ZExtOrSelf(const Opnd &Op) {
0937   return m_AnyOf(m_ZExt(Op), Op);
0938 }
0939 
0940 /// Match a sext or identity
0941 /// Allows to peek through optional extensions
0942 template <typename Opnd> inline auto m_SExtOrSelf(const Opnd &Op) {
0943   return m_AnyOf(m_SExt(Op), Op);
0944 }
0945 
0946 template <typename Opnd> inline auto m_SExtLike(const Opnd &Op) {
0947   return m_AnyOf(m_SExt(Op), m_NNegZExt(Op));
0948 }
0949 
0950 /// Match a aext or identity
0951 /// Allows to peek through optional extensions
0952 template <typename Opnd>
0953 inline Or<UnaryOpc_match<Opnd>, Opnd> m_AExtOrSelf(const Opnd &Op) {
0954   return Or<UnaryOpc_match<Opnd>, Opnd>(m_AnyExt(Op), Op);
0955 }
0956 
0957 /// Match a trunc or identity
0958 /// Allows to peek through optional truncations
0959 template <typename Opnd>
0960 inline Or<UnaryOpc_match<Opnd>, Opnd> m_TruncOrSelf(const Opnd &Op) {
0961   return Or<UnaryOpc_match<Opnd>, Opnd>(m_Trunc(Op), Op);
0962 }
0963 
0964 template <typename Opnd> inline UnaryOpc_match<Opnd> m_VScale(const Opnd &Op) {
0965   return UnaryOpc_match<Opnd>(ISD::VSCALE, Op);
0966 }
0967 
0968 template <typename Opnd> inline UnaryOpc_match<Opnd> m_FPToUI(const Opnd &Op) {
0969   return UnaryOpc_match<Opnd>(ISD::FP_TO_UINT, Op);
0970 }
0971 
0972 template <typename Opnd> inline UnaryOpc_match<Opnd> m_FPToSI(const Opnd &Op) {
0973   return UnaryOpc_match<Opnd>(ISD::FP_TO_SINT, Op);
0974 }
0975 
0976 template <typename Opnd> inline UnaryOpc_match<Opnd> m_Ctpop(const Opnd &Op) {
0977   return UnaryOpc_match<Opnd>(ISD::CTPOP, Op);
0978 }
0979 
0980 template <typename Opnd> inline UnaryOpc_match<Opnd> m_Ctlz(const Opnd &Op) {
0981   return UnaryOpc_match<Opnd>(ISD::CTLZ, Op);
0982 }
0983 
0984 template <typename Opnd> inline UnaryOpc_match<Opnd> m_Cttz(const Opnd &Op) {
0985   return UnaryOpc_match<Opnd>(ISD::CTTZ, Op);
0986 }
0987 
0988 // === Constants ===
0989 struct ConstantInt_match {
0990   APInt *BindVal;
0991 
0992   explicit ConstantInt_match(APInt *V) : BindVal(V) {}
0993 
0994   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
0995     // The logics here are similar to that in
0996     // SelectionDAG::isConstantIntBuildVectorOrConstantInt, but the latter also
0997     // treats GlobalAddressSDNode as a constant, which is difficult to turn into
0998     // APInt.
0999     if (auto *C = dyn_cast_or_null<ConstantSDNode>(N.getNode())) {
1000       if (BindVal)
1001         *BindVal = C->getAPIntValue();
1002       return true;
1003     }
1004 
1005     APInt Discard;
1006     return ISD::isConstantSplatVector(N.getNode(),
1007                                       BindVal ? *BindVal : Discard);
1008   }
1009 };
1010 /// Match any interger constants or splat of an integer constant.
1011 inline ConstantInt_match m_ConstInt() { return ConstantInt_match(nullptr); }
1012 /// Match any interger constants or splat of an integer constant; return the
1013 /// specific constant or constant splat value.
1014 inline ConstantInt_match m_ConstInt(APInt &V) { return ConstantInt_match(&V); }
1015 
1016 struct SpecificInt_match {
1017   APInt IntVal;
1018 
1019   explicit SpecificInt_match(APInt APV) : IntVal(std::move(APV)) {}
1020 
1021   template <typename MatchContext>
1022   bool match(const MatchContext &Ctx, SDValue N) {
1023     APInt ConstInt;
1024     if (sd_context_match(N, Ctx, m_ConstInt(ConstInt)))
1025       return APInt::isSameValue(IntVal, ConstInt);
1026     return false;
1027   }
1028 };
1029 
1030 /// Match a specific integer constant or constant splat value.
1031 inline SpecificInt_match m_SpecificInt(APInt V) {
1032   return SpecificInt_match(std::move(V));
1033 }
1034 inline SpecificInt_match m_SpecificInt(uint64_t V) {
1035   return SpecificInt_match(APInt(64, V));
1036 }
1037 
1038 inline SpecificInt_match m_Zero() { return m_SpecificInt(0U); }
1039 inline SpecificInt_match m_One() { return m_SpecificInt(1U); }
1040 
1041 struct AllOnes_match {
1042 
1043   AllOnes_match() = default;
1044 
1045   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
1046     return isAllOnesOrAllOnesSplat(N);
1047   }
1048 };
1049 
1050 inline AllOnes_match m_AllOnes() { return AllOnes_match(); }
1051 
1052 /// Match true boolean value based on the information provided by
1053 /// TargetLowering.
1054 inline auto m_True() {
1055   return TLI_pred_match{
1056       [](const TargetLowering &TLI, SDValue N) {
1057         APInt ConstVal;
1058         if (sd_match(N, m_ConstInt(ConstVal)))
1059           switch (TLI.getBooleanContents(N.getValueType())) {
1060           case TargetLowering::ZeroOrOneBooleanContent:
1061             return ConstVal.isOne();
1062           case TargetLowering::ZeroOrNegativeOneBooleanContent:
1063             return ConstVal.isAllOnes();
1064           case TargetLowering::UndefinedBooleanContent:
1065             return (ConstVal & 0x01) == 1;
1066           }
1067 
1068         return false;
1069       },
1070       m_Value()};
1071 }
1072 /// Match false boolean value based on the information provided by
1073 /// TargetLowering.
1074 inline auto m_False() {
1075   return TLI_pred_match{
1076       [](const TargetLowering &TLI, SDValue N) {
1077         APInt ConstVal;
1078         if (sd_match(N, m_ConstInt(ConstVal)))
1079           switch (TLI.getBooleanContents(N.getValueType())) {
1080           case TargetLowering::ZeroOrOneBooleanContent:
1081           case TargetLowering::ZeroOrNegativeOneBooleanContent:
1082             return ConstVal.isZero();
1083           case TargetLowering::UndefinedBooleanContent:
1084             return (ConstVal & 0x01) == 0;
1085           }
1086 
1087         return false;
1088       },
1089       m_Value()};
1090 }
1091 
1092 struct CondCode_match {
1093   std::optional<ISD::CondCode> CCToMatch;
1094   ISD::CondCode *BindCC = nullptr;
1095 
1096   explicit CondCode_match(ISD::CondCode CC) : CCToMatch(CC) {}
1097 
1098   explicit CondCode_match(ISD::CondCode *CC) : BindCC(CC) {}
1099 
1100   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
1101     if (auto *CC = dyn_cast<CondCodeSDNode>(N.getNode())) {
1102       if (CCToMatch && *CCToMatch != CC->get())
1103         return false;
1104 
1105       if (BindCC)
1106         *BindCC = CC->get();
1107       return true;
1108     }
1109 
1110     return false;
1111   }
1112 };
1113 
1114 /// Match any conditional code SDNode.
1115 inline CondCode_match m_CondCode() { return CondCode_match(nullptr); }
1116 /// Match any conditional code SDNode and return its ISD::CondCode value.
1117 inline CondCode_match m_CondCode(ISD::CondCode &CC) {
1118   return CondCode_match(&CC);
1119 }
1120 /// Match a conditional code SDNode with a specific ISD::CondCode.
1121 inline CondCode_match m_SpecificCondCode(ISD::CondCode CC) {
1122   return CondCode_match(CC);
1123 }
1124 
1125 /// Match a negate as a sub(0, v)
1126 template <typename ValTy>
1127 inline BinaryOpc_match<SpecificInt_match, ValTy> m_Neg(const ValTy &V) {
1128   return m_Sub(m_Zero(), V);
1129 }
1130 
1131 /// Match a Not as a xor(v, -1) or xor(-1, v)
1132 template <typename ValTy>
1133 inline BinaryOpc_match<ValTy, AllOnes_match, true> m_Not(const ValTy &V) {
1134   return m_Xor(V, m_AllOnes());
1135 }
1136 
1137 } // namespace SDPatternMatch
1138 } // namespace llvm
1139 #endif