Home | History | Annotate | Line # | Download | only in GlobalISel
      1 //==------ llvm/CodeGen/GlobalISel/MIPatternMatch.h -------------*- C++ -*-===//
      2 //
      3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4 // See https://llvm.org/LICENSE.txt for license information.
      5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6 //
      7 //===----------------------------------------------------------------------===//
      8 /// \file
      9 /// Contains matchers for matching SSA Machine Instructions.
     10 ///
     11 //===----------------------------------------------------------------------===//
     12 
     13 #ifndef LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H
     14 #define LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H
     15 
     16 #include "llvm/CodeGen/GlobalISel/Utils.h"
     17 #include "llvm/CodeGen/MachineRegisterInfo.h"
     18 #include "llvm/IR/InstrTypes.h"
     19 
     20 namespace llvm {
     21 namespace MIPatternMatch {
     22 
     23 template <typename Reg, typename Pattern>
     24 bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P) {
     25   return P.match(MRI, R);
     26 }
     27 
     28 template <typename Pattern>
     29 bool mi_match(MachineInstr &MI, const MachineRegisterInfo &MRI, Pattern &&P) {
     30   return P.match(MRI, &MI);
     31 }
     32 
     33 // TODO: Extend for N use.
     34 template <typename SubPatternT> struct OneUse_match {
     35   SubPatternT SubPat;
     36   OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
     37 
     38   bool match(const MachineRegisterInfo &MRI, Register Reg) {
     39     return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
     40   }
     41 };
     42 
     43 template <typename SubPat>
     44 inline OneUse_match<SubPat> m_OneUse(const SubPat &SP) {
     45   return SP;
     46 }
     47 
     48 template <typename SubPatternT> struct OneNonDBGUse_match {
     49   SubPatternT SubPat;
     50   OneNonDBGUse_match(const SubPatternT &SP) : SubPat(SP) {}
     51 
     52   bool match(const MachineRegisterInfo &MRI, Register Reg) {
     53     return MRI.hasOneNonDBGUse(Reg) && SubPat.match(MRI, Reg);
     54   }
     55 };
     56 
     57 template <typename SubPat>
     58 inline OneNonDBGUse_match<SubPat> m_OneNonDBGUse(const SubPat &SP) {
     59   return SP;
     60 }
     61 
     62 struct ConstantMatch {
     63   int64_t &CR;
     64   ConstantMatch(int64_t &C) : CR(C) {}
     65   bool match(const MachineRegisterInfo &MRI, Register Reg) {
     66     if (auto MaybeCst = getConstantVRegSExtVal(Reg, MRI)) {
     67       CR = *MaybeCst;
     68       return true;
     69     }
     70     return false;
     71   }
     72 };
     73 
     74 inline ConstantMatch m_ICst(int64_t &Cst) { return ConstantMatch(Cst); }
     75 
     76 struct ICstRegMatch {
     77   Register &CR;
     78   ICstRegMatch(Register &C) : CR(C) {}
     79   bool match(const MachineRegisterInfo &MRI, Register Reg) {
     80     if (auto MaybeCst = getConstantVRegValWithLookThrough(
     81             Reg, MRI, /*LookThroughInstrs*/ true,
     82             /*HandleFConstants*/ false)) {
     83       CR = MaybeCst->VReg;
     84       return true;
     85     }
     86     return false;
     87   }
     88 };
     89 
     90 inline ICstRegMatch m_ICst(Register &Reg) { return ICstRegMatch(Reg); }
     91 
     92 /// Matcher for a specific constant value.
     93 struct SpecificConstantMatch {
     94   int64_t RequestedVal;
     95   SpecificConstantMatch(int64_t RequestedVal) : RequestedVal(RequestedVal) {}
     96   bool match(const MachineRegisterInfo &MRI, Register Reg) {
     97     int64_t MatchedVal;
     98     return mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal;
     99   }
    100 };
    101 
    102 /// Matches a constant equal to \p RequestedValue.
    103 inline SpecificConstantMatch m_SpecificICst(int64_t RequestedValue) {
    104   return SpecificConstantMatch(RequestedValue);
    105 }
    106 
    107 ///{
    108 /// Convenience matchers for specific integer values.
    109 inline SpecificConstantMatch m_ZeroInt() { return SpecificConstantMatch(0); }
    110 inline SpecificConstantMatch m_AllOnesInt() {
    111   return SpecificConstantMatch(-1);
    112 }
    113 ///}
    114 
    115 // TODO: Rework this for different kinds of MachineOperand.
    116 // Currently assumes the Src for a match is a register.
    117 // We might want to support taking in some MachineOperands and call getReg on
    118 // that.
    119 
    120 struct operand_type_match {
    121   bool match(const MachineRegisterInfo &MRI, Register Reg) { return true; }
    122   bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) {
    123     return MO->isReg();
    124   }
    125 };
    126 
    127 inline operand_type_match m_Reg() { return operand_type_match(); }
    128 
    129 /// Matching combinators.
    130 template <typename... Preds> struct And {
    131   template <typename MatchSrc>
    132   bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
    133     return true;
    134   }
    135 };
    136 
    137 template <typename Pred, typename... Preds>
    138 struct And<Pred, Preds...> : And<Preds...> {
    139   Pred P;
    140   And(Pred &&p, Preds &&... preds)
    141       : And<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {
    142   }
    143   template <typename MatchSrc>
    144   bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
    145     return P.match(MRI, src) && And<Preds...>::match(MRI, src);
    146   }
    147 };
    148 
    149 template <typename... Preds> struct Or {
    150   template <typename MatchSrc>
    151   bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
    152     return false;
    153   }
    154 };
    155 
    156 template <typename Pred, typename... Preds>
    157 struct Or<Pred, Preds...> : Or<Preds...> {
    158   Pred P;
    159   Or(Pred &&p, Preds &&... preds)
    160       : Or<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {}
    161   template <typename MatchSrc>
    162   bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
    163     return P.match(MRI, src) || Or<Preds...>::match(MRI, src);
    164   }
    165 };
    166 
    167 template <typename... Preds> And<Preds...> m_all_of(Preds &&... preds) {
    168   return And<Preds...>(std::forward<Preds>(preds)...);
    169 }
    170 
    171 template <typename... Preds> Or<Preds...> m_any_of(Preds &&... preds) {
    172   return Or<Preds...>(std::forward<Preds>(preds)...);
    173 }
    174 
    175 template <typename BindTy> struct bind_helper {
    176   static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
    177     VR = V;
    178     return true;
    179   }
    180 };
    181 
    182 template <> struct bind_helper<MachineInstr *> {
    183   static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
    184                    Register Reg) {
    185     MI = MRI.getVRegDef(Reg);
    186     if (MI)
    187       return true;
    188     return false;
    189   }
    190   static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
    191                    MachineInstr *Inst) {
    192     MI = Inst;
    193     return MI;
    194   }
    195 };
    196 
    197 template <> struct bind_helper<LLT> {
    198   static bool bind(const MachineRegisterInfo &MRI, LLT Ty, Register Reg) {
    199     Ty = MRI.getType(Reg);
    200     if (Ty.isValid())
    201       return true;
    202     return false;
    203   }
    204 };
    205 
    206 template <> struct bind_helper<const ConstantFP *> {
    207   static bool bind(const MachineRegisterInfo &MRI, const ConstantFP *&F,
    208                    Register Reg) {
    209     F = getConstantFPVRegVal(Reg, MRI);
    210     if (F)
    211       return true;
    212     return false;
    213   }
    214 };
    215 
    216 template <typename Class> struct bind_ty {
    217   Class &VR;
    218 
    219   bind_ty(Class &V) : VR(V) {}
    220 
    221   template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) {
    222     return bind_helper<Class>::bind(MRI, VR, V);
    223   }
    224 };
    225 
    226 inline bind_ty<Register> m_Reg(Register &R) { return R; }
    227 inline bind_ty<MachineInstr *> m_MInstr(MachineInstr *&MI) { return MI; }
    228 inline bind_ty<LLT> m_Type(LLT Ty) { return Ty; }
    229 inline bind_ty<CmpInst::Predicate> m_Pred(CmpInst::Predicate &P) { return P; }
    230 inline operand_type_match m_Pred() { return operand_type_match(); }
    231 
    232 // Helper for matching G_FCONSTANT
    233 inline bind_ty<const ConstantFP *> m_GFCst(const ConstantFP *&C) { return C; }
    234 
    235 // General helper for all the binary generic MI such as G_ADD/G_SUB etc
    236 template <typename LHS_P, typename RHS_P, unsigned Opcode,
    237           bool Commutable = false>
    238 struct BinaryOp_match {
    239   LHS_P L;
    240   RHS_P R;
    241 
    242   BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {}
    243   template <typename OpTy>
    244   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
    245     MachineInstr *TmpMI;
    246     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
    247       if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) {
    248         return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
    249                 R.match(MRI, TmpMI->getOperand(2).getReg())) ||
    250                (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) &&
    251                                L.match(MRI, TmpMI->getOperand(2).getReg())));
    252       }
    253     }
    254     return false;
    255   }
    256 };
    257 
    258 // Helper for (commutative) binary generic MI that checks Opcode.
    259 template <typename LHS_P, typename RHS_P, bool Commutable = false>
    260 struct BinaryOpc_match {
    261   unsigned Opc;
    262   LHS_P L;
    263   RHS_P R;
    264 
    265   BinaryOpc_match(unsigned Opcode, const LHS_P &LHS, const RHS_P &RHS)
    266       : Opc(Opcode), L(LHS), R(RHS) {}
    267   template <typename OpTy>
    268   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
    269     MachineInstr *TmpMI;
    270     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
    271       if (TmpMI->getOpcode() == Opc && TmpMI->getNumDefs() == 1 &&
    272           TmpMI->getNumOperands() == 3) {
    273         return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
    274                 R.match(MRI, TmpMI->getOperand(2).getReg())) ||
    275                (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) &&
    276                                L.match(MRI, TmpMI->getOperand(2).getReg())));
    277       }
    278     }
    279     return false;
    280   }
    281 };
    282 
    283 template <typename LHS, typename RHS>
    284 inline BinaryOpc_match<LHS, RHS, false> m_BinOp(unsigned Opcode, const LHS &L,
    285                                                 const RHS &R) {
    286   return BinaryOpc_match<LHS, RHS, false>(Opcode, L, R);
    287 }
    288 
    289 template <typename LHS, typename RHS>
    290 inline BinaryOpc_match<LHS, RHS, true>
    291 m_CommutativeBinOp(unsigned Opcode, const LHS &L, const RHS &R) {
    292   return BinaryOpc_match<LHS, RHS, true>(Opcode, L, R);
    293 }
    294 
    295 template <typename LHS, typename RHS>
    296 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>
    297 m_GAdd(const LHS &L, const RHS &R) {
    298   return BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>(L, R);
    299 }
    300 
    301 template <typename LHS, typename RHS>
    302 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, true>
    303 m_GPtrAdd(const LHS &L, const RHS &R) {
    304   return BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, true>(L, R);
    305 }
    306 
    307 template <typename LHS, typename RHS>
    308 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB> m_GSub(const LHS &L,
    309                                                             const RHS &R) {
    310   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB>(L, R);
    311 }
    312 
    313 template <typename LHS, typename RHS>
    314 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>
    315 m_GMul(const LHS &L, const RHS &R) {
    316   return BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>(L, R);
    317 }
    318 
    319 template <typename LHS, typename RHS>
    320 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>
    321 m_GFAdd(const LHS &L, const RHS &R) {
    322   return BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>(L, R);
    323 }
    324 
    325 template <typename LHS, typename RHS>
    326 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>
    327 m_GFMul(const LHS &L, const RHS &R) {
    328   return BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>(L, R);
    329 }
    330 
    331 template <typename LHS, typename RHS>
    332 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>
    333 m_GFSub(const LHS &L, const RHS &R) {
    334   return BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>(L, R);
    335 }
    336 
    337 template <typename LHS, typename RHS>
    338 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>
    339 m_GAnd(const LHS &L, const RHS &R) {
    340   return BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>(L, R);
    341 }
    342 
    343 template <typename LHS, typename RHS>
    344 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>
    345 m_GXor(const LHS &L, const RHS &R) {
    346   return BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>(L, R);
    347 }
    348 
    349 template <typename LHS, typename RHS>
    350 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true> m_GOr(const LHS &L,
    351                                                                 const RHS &R) {
    352   return BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true>(L, R);
    353 }
    354 
    355 template <typename LHS, typename RHS>
    356 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>
    357 m_GShl(const LHS &L, const RHS &R) {
    358   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>(L, R);
    359 }
    360 
    361 template <typename LHS, typename RHS>
    362 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>
    363 m_GLShr(const LHS &L, const RHS &R) {
    364   return BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>(L, R);
    365 }
    366 
    367 template <typename LHS, typename RHS>
    368 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>
    369 m_GAShr(const LHS &L, const RHS &R) {
    370   return BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>(L, R);
    371 }
    372 
    373 template <typename LHS, typename RHS>
    374 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, false>
    375 m_GSMax(const LHS &L, const RHS &R) {
    376   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, false>(L, R);
    377 }
    378 
    379 template <typename LHS, typename RHS>
    380 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, false>
    381 m_GSMin(const LHS &L, const RHS &R) {
    382   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, false>(L, R);
    383 }
    384 
    385 // Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc
    386 template <typename SrcTy, unsigned Opcode> struct UnaryOp_match {
    387   SrcTy L;
    388 
    389   UnaryOp_match(const SrcTy &LHS) : L(LHS) {}
    390   template <typename OpTy>
    391   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
    392     MachineInstr *TmpMI;
    393     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
    394       if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) {
    395         return L.match(MRI, TmpMI->getOperand(1).getReg());
    396       }
    397     }
    398     return false;
    399   }
    400 };
    401 
    402 template <typename SrcTy>
    403 inline UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>
    404 m_GAnyExt(const SrcTy &Src) {
    405   return UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>(Src);
    406 }
    407 
    408 template <typename SrcTy>
    409 inline UnaryOp_match<SrcTy, TargetOpcode::G_SEXT> m_GSExt(const SrcTy &Src) {
    410   return UnaryOp_match<SrcTy, TargetOpcode::G_SEXT>(Src);
    411 }
    412 
    413 template <typename SrcTy>
    414 inline UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT> m_GZExt(const SrcTy &Src) {
    415   return UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT>(Src);
    416 }
    417 
    418 template <typename SrcTy>
    419 inline UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT> m_GFPExt(const SrcTy &Src) {
    420   return UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT>(Src);
    421 }
    422 
    423 template <typename SrcTy>
    424 inline UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC> m_GTrunc(const SrcTy &Src) {
    425   return UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC>(Src);
    426 }
    427 
    428 template <typename SrcTy>
    429 inline UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>
    430 m_GBitcast(const SrcTy &Src) {
    431   return UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>(Src);
    432 }
    433 
    434 template <typename SrcTy>
    435 inline UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>
    436 m_GPtrToInt(const SrcTy &Src) {
    437   return UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>(Src);
    438 }
    439 
    440 template <typename SrcTy>
    441 inline UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>
    442 m_GIntToPtr(const SrcTy &Src) {
    443   return UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>(Src);
    444 }
    445 
    446 template <typename SrcTy>
    447 inline UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>
    448 m_GFPTrunc(const SrcTy &Src) {
    449   return UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>(Src);
    450 }
    451 
    452 template <typename SrcTy>
    453 inline UnaryOp_match<SrcTy, TargetOpcode::G_FABS> m_GFabs(const SrcTy &Src) {
    454   return UnaryOp_match<SrcTy, TargetOpcode::G_FABS>(Src);
    455 }
    456 
    457 template <typename SrcTy>
    458 inline UnaryOp_match<SrcTy, TargetOpcode::G_FNEG> m_GFNeg(const SrcTy &Src) {
    459   return UnaryOp_match<SrcTy, TargetOpcode::G_FNEG>(Src);
    460 }
    461 
    462 template <typename SrcTy>
    463 inline UnaryOp_match<SrcTy, TargetOpcode::COPY> m_Copy(SrcTy &&Src) {
    464   return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src));
    465 }
    466 
    467 // General helper for generic MI compares, i.e. G_ICMP and G_FCMP
    468 // TODO: Allow checking a specific predicate.
    469 template <typename Pred_P, typename LHS_P, typename RHS_P, unsigned Opcode>
    470 struct CompareOp_match {
    471   Pred_P P;
    472   LHS_P L;
    473   RHS_P R;
    474 
    475   CompareOp_match(const Pred_P &Pred, const LHS_P &LHS, const RHS_P &RHS)
    476       : P(Pred), L(LHS), R(RHS) {}
    477 
    478   template <typename OpTy>
    479   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
    480     MachineInstr *TmpMI;
    481     if (!mi_match(Op, MRI, m_MInstr(TmpMI)) || TmpMI->getOpcode() != Opcode)
    482       return false;
    483 
    484     auto TmpPred =
    485         static_cast<CmpInst::Predicate>(TmpMI->getOperand(1).getPredicate());
    486     if (!P.match(MRI, TmpPred))
    487       return false;
    488 
    489     return L.match(MRI, TmpMI->getOperand(2).getReg()) &&
    490            R.match(MRI, TmpMI->getOperand(3).getReg());
    491   }
    492 };
    493 
    494 template <typename Pred, typename LHS, typename RHS>
    495 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>
    496 m_GICmp(const Pred &P, const LHS &L, const RHS &R) {
    497   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>(P, L, R);
    498 }
    499 
    500 template <typename Pred, typename LHS, typename RHS>
    501 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>
    502 m_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
    503   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>(P, L, R);
    504 }
    505 
    506 // Helper for checking if a Reg is of specific type.
    507 struct CheckType {
    508   LLT Ty;
    509   CheckType(const LLT Ty) : Ty(Ty) {}
    510 
    511   bool match(const MachineRegisterInfo &MRI, Register Reg) {
    512     return MRI.getType(Reg) == Ty;
    513   }
    514 };
    515 
    516 inline CheckType m_SpecificType(LLT Ty) { return Ty; }
    517 
    518 template <typename Src0Ty, typename Src1Ty, typename Src2Ty, unsigned Opcode>
    519 struct TernaryOp_match {
    520   Src0Ty Src0;
    521   Src1Ty Src1;
    522   Src2Ty Src2;
    523 
    524   TernaryOp_match(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
    525       : Src0(Src0), Src1(Src1), Src2(Src2) {}
    526   template <typename OpTy>
    527   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
    528     MachineInstr *TmpMI;
    529     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
    530       if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 4) {
    531         return (Src0.match(MRI, TmpMI->getOperand(1).getReg()) &&
    532                 Src1.match(MRI, TmpMI->getOperand(2).getReg()) &&
    533                 Src2.match(MRI, TmpMI->getOperand(3).getReg()));
    534       }
    535     }
    536     return false;
    537   }
    538 };
    539 template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
    540 inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
    541                        TargetOpcode::G_INSERT_VECTOR_ELT>
    542 m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
    543   return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
    544                          TargetOpcode::G_INSERT_VECTOR_ELT>(Src0, Src1, Src2);
    545 }
    546 
    547 template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
    548 inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>
    549 m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
    550   return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>(
    551       Src0, Src1, Src2);
    552 }
    553 
    554 /// Matches a register negated by a G_SUB.
    555 /// G_SUB 0, %negated_reg
    556 template <typename SrcTy>
    557 inline BinaryOp_match<SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB>
    558 m_Neg(const SrcTy &&Src) {
    559   return m_GSub(m_ZeroInt(), Src);
    560 }
    561 
    562 /// Matches a register not-ed by a G_XOR.
    563 /// G_XOR %not_reg, -1
    564 template <typename SrcTy>
    565 inline BinaryOp_match<SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true>
    566 m_Not(const SrcTy &&Src) {
    567   return m_GXor(Src, m_AllOnesInt());
    568 }
    569 
    570 } // namespace MIPatternMatch
    571 } // namespace llvm
    572 
    573 #endif
    574