Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  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/ADT/APInt.h"
  17. #include "llvm/CodeGen/GlobalISel/Utils.h"
  18. #include "llvm/CodeGen/MachineRegisterInfo.h"
  19. #include "llvm/IR/InstrTypes.h"
  20.  
  21. namespace llvm {
  22. namespace MIPatternMatch {
  23.  
  24. template <typename Reg, typename Pattern>
  25. [[nodiscard]] bool mi_match(Reg R, const MachineRegisterInfo &MRI,
  26.                             Pattern &&P) {
  27.   return P.match(MRI, R);
  28. }
  29.  
  30. template <typename Pattern>
  31. [[nodiscard]] bool mi_match(MachineInstr &MI, const MachineRegisterInfo &MRI,
  32.                             Pattern &&P) {
  33.   return P.match(MRI, &MI);
  34. }
  35.  
  36. // TODO: Extend for N use.
  37. template <typename SubPatternT> struct OneUse_match {
  38.   SubPatternT SubPat;
  39.   OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
  40.  
  41.   bool match(const MachineRegisterInfo &MRI, Register Reg) {
  42.     return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
  43.   }
  44. };
  45.  
  46. template <typename SubPat>
  47. inline OneUse_match<SubPat> m_OneUse(const SubPat &SP) {
  48.   return SP;
  49. }
  50.  
  51. template <typename SubPatternT> struct OneNonDBGUse_match {
  52.   SubPatternT SubPat;
  53.   OneNonDBGUse_match(const SubPatternT &SP) : SubPat(SP) {}
  54.  
  55.   bool match(const MachineRegisterInfo &MRI, Register Reg) {
  56.     return MRI.hasOneNonDBGUse(Reg) && SubPat.match(MRI, Reg);
  57.   }
  58. };
  59.  
  60. template <typename SubPat>
  61. inline OneNonDBGUse_match<SubPat> m_OneNonDBGUse(const SubPat &SP) {
  62.   return SP;
  63. }
  64.  
  65. template <typename ConstT>
  66. inline std::optional<ConstT> matchConstant(Register,
  67.                                            const MachineRegisterInfo &);
  68.  
  69. template <>
  70. inline std::optional<APInt> matchConstant(Register Reg,
  71.                                           const MachineRegisterInfo &MRI) {
  72.   return getIConstantVRegVal(Reg, MRI);
  73. }
  74.  
  75. template <>
  76. inline std::optional<int64_t> matchConstant(Register Reg,
  77.                                             const MachineRegisterInfo &MRI) {
  78.   return getIConstantVRegSExtVal(Reg, MRI);
  79. }
  80.  
  81. template <typename ConstT> struct ConstantMatch {
  82.   ConstT &CR;
  83.   ConstantMatch(ConstT &C) : CR(C) {}
  84.   bool match(const MachineRegisterInfo &MRI, Register Reg) {
  85.     if (auto MaybeCst = matchConstant<ConstT>(Reg, MRI)) {
  86.       CR = *MaybeCst;
  87.       return true;
  88.     }
  89.     return false;
  90.   }
  91. };
  92.  
  93. inline ConstantMatch<APInt> m_ICst(APInt &Cst) {
  94.   return ConstantMatch<APInt>(Cst);
  95. }
  96. inline ConstantMatch<int64_t> m_ICst(int64_t &Cst) {
  97.   return ConstantMatch<int64_t>(Cst);
  98. }
  99.  
  100. template <typename ConstT>
  101. inline std::optional<ConstT> matchConstantSplat(Register,
  102.                                                 const MachineRegisterInfo &);
  103.  
  104. template <>
  105. inline std::optional<APInt> matchConstantSplat(Register Reg,
  106.                                                const MachineRegisterInfo &MRI) {
  107.   return getIConstantSplatVal(Reg, MRI);
  108. }
  109.  
  110. template <>
  111. inline std::optional<int64_t>
  112. matchConstantSplat(Register Reg, const MachineRegisterInfo &MRI) {
  113.   return getIConstantSplatSExtVal(Reg, MRI);
  114. }
  115.  
  116. template <typename ConstT> struct ICstOrSplatMatch {
  117.   ConstT &CR;
  118.   ICstOrSplatMatch(ConstT &C) : CR(C) {}
  119.   bool match(const MachineRegisterInfo &MRI, Register Reg) {
  120.     if (auto MaybeCst = matchConstant<ConstT>(Reg, MRI)) {
  121.       CR = *MaybeCst;
  122.       return true;
  123.     }
  124.  
  125.     if (auto MaybeCstSplat = matchConstantSplat<ConstT>(Reg, MRI)) {
  126.       CR = *MaybeCstSplat;
  127.       return true;
  128.     }
  129.  
  130.     return false;
  131.   };
  132. };
  133.  
  134. inline ICstOrSplatMatch<APInt> m_ICstOrSplat(APInt &Cst) {
  135.   return ICstOrSplatMatch<APInt>(Cst);
  136. }
  137.  
  138. inline ICstOrSplatMatch<int64_t> m_ICstOrSplat(int64_t &Cst) {
  139.   return ICstOrSplatMatch<int64_t>(Cst);
  140. }
  141.  
  142. struct GCstAndRegMatch {
  143.   std::optional<ValueAndVReg> &ValReg;
  144.   GCstAndRegMatch(std::optional<ValueAndVReg> &ValReg) : ValReg(ValReg) {}
  145.   bool match(const MachineRegisterInfo &MRI, Register Reg) {
  146.     ValReg = getIConstantVRegValWithLookThrough(Reg, MRI);
  147.     return ValReg ? true : false;
  148.   }
  149. };
  150.  
  151. inline GCstAndRegMatch m_GCst(std::optional<ValueAndVReg> &ValReg) {
  152.   return GCstAndRegMatch(ValReg);
  153. }
  154.  
  155. struct GFCstAndRegMatch {
  156.   std::optional<FPValueAndVReg> &FPValReg;
  157.   GFCstAndRegMatch(std::optional<FPValueAndVReg> &FPValReg)
  158.       : FPValReg(FPValReg) {}
  159.   bool match(const MachineRegisterInfo &MRI, Register Reg) {
  160.     FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI);
  161.     return FPValReg ? true : false;
  162.   }
  163. };
  164.  
  165. inline GFCstAndRegMatch m_GFCst(std::optional<FPValueAndVReg> &FPValReg) {
  166.   return GFCstAndRegMatch(FPValReg);
  167. }
  168.  
  169. struct GFCstOrSplatGFCstMatch {
  170.   std::optional<FPValueAndVReg> &FPValReg;
  171.   GFCstOrSplatGFCstMatch(std::optional<FPValueAndVReg> &FPValReg)
  172.       : FPValReg(FPValReg) {}
  173.   bool match(const MachineRegisterInfo &MRI, Register Reg) {
  174.     return (FPValReg = getFConstantSplat(Reg, MRI)) ||
  175.            (FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI));
  176.   };
  177. };
  178.  
  179. inline GFCstOrSplatGFCstMatch
  180. m_GFCstOrSplat(std::optional<FPValueAndVReg> &FPValReg) {
  181.   return GFCstOrSplatGFCstMatch(FPValReg);
  182. }
  183.  
  184. /// Matcher for a specific constant value.
  185. struct SpecificConstantMatch {
  186.   int64_t RequestedVal;
  187.   SpecificConstantMatch(int64_t RequestedVal) : RequestedVal(RequestedVal) {}
  188.   bool match(const MachineRegisterInfo &MRI, Register Reg) {
  189.     int64_t MatchedVal;
  190.     return mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal;
  191.   }
  192. };
  193.  
  194. /// Matches a constant equal to \p RequestedValue.
  195. inline SpecificConstantMatch m_SpecificICst(int64_t RequestedValue) {
  196.   return SpecificConstantMatch(RequestedValue);
  197. }
  198.  
  199. /// Matcher for a specific constant splat.
  200. struct SpecificConstantSplatMatch {
  201.   int64_t RequestedVal;
  202.   SpecificConstantSplatMatch(int64_t RequestedVal)
  203.       : RequestedVal(RequestedVal) {}
  204.   bool match(const MachineRegisterInfo &MRI, Register Reg) {
  205.     return isBuildVectorConstantSplat(Reg, MRI, RequestedVal,
  206.                                       /* AllowUndef */ false);
  207.   }
  208. };
  209.  
  210. /// Matches a constant splat of \p RequestedValue.
  211. inline SpecificConstantSplatMatch m_SpecificICstSplat(int64_t RequestedValue) {
  212.   return SpecificConstantSplatMatch(RequestedValue);
  213. }
  214.  
  215. /// Matcher for a specific constant or constant splat.
  216. struct SpecificConstantOrSplatMatch {
  217.   int64_t RequestedVal;
  218.   SpecificConstantOrSplatMatch(int64_t RequestedVal)
  219.       : RequestedVal(RequestedVal) {}
  220.   bool match(const MachineRegisterInfo &MRI, Register Reg) {
  221.     int64_t MatchedVal;
  222.     if (mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal)
  223.       return true;
  224.     return isBuildVectorConstantSplat(Reg, MRI, RequestedVal,
  225.                                       /* AllowUndef */ false);
  226.   }
  227. };
  228.  
  229. /// Matches a \p RequestedValue constant or a constant splat of \p
  230. /// RequestedValue.
  231. inline SpecificConstantOrSplatMatch
  232. m_SpecificICstOrSplat(int64_t RequestedValue) {
  233.   return SpecificConstantOrSplatMatch(RequestedValue);
  234. }
  235.  
  236. ///{
  237. /// Convenience matchers for specific integer values.
  238. inline SpecificConstantMatch m_ZeroInt() { return SpecificConstantMatch(0); }
  239. inline SpecificConstantMatch m_AllOnesInt() {
  240.   return SpecificConstantMatch(-1);
  241. }
  242. ///}
  243.  
  244. /// Matcher for a specific register.
  245. struct SpecificRegisterMatch {
  246.   Register RequestedReg;
  247.   SpecificRegisterMatch(Register RequestedReg) : RequestedReg(RequestedReg) {}
  248.   bool match(const MachineRegisterInfo &MRI, Register Reg) {
  249.     return Reg == RequestedReg;
  250.   }
  251. };
  252.  
  253. /// Matches a register only if it is equal to \p RequestedReg.
  254. inline SpecificRegisterMatch m_SpecificReg(Register RequestedReg) {
  255.   return SpecificRegisterMatch(RequestedReg);
  256. }
  257.  
  258. // TODO: Rework this for different kinds of MachineOperand.
  259. // Currently assumes the Src for a match is a register.
  260. // We might want to support taking in some MachineOperands and call getReg on
  261. // that.
  262.  
  263. struct operand_type_match {
  264.   bool match(const MachineRegisterInfo &MRI, Register Reg) { return true; }
  265.   bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) {
  266.     return MO->isReg();
  267.   }
  268. };
  269.  
  270. inline operand_type_match m_Reg() { return operand_type_match(); }
  271.  
  272. /// Matching combinators.
  273. template <typename... Preds> struct And {
  274.   template <typename MatchSrc>
  275.   bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
  276.     return true;
  277.   }
  278. };
  279.  
  280. template <typename Pred, typename... Preds>
  281. struct And<Pred, Preds...> : And<Preds...> {
  282.   Pred P;
  283.   And(Pred &&p, Preds &&... preds)
  284.       : And<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {
  285.   }
  286.   template <typename MatchSrc>
  287.   bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
  288.     return P.match(MRI, src) && And<Preds...>::match(MRI, src);
  289.   }
  290. };
  291.  
  292. template <typename... Preds> struct Or {
  293.   template <typename MatchSrc>
  294.   bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
  295.     return false;
  296.   }
  297. };
  298.  
  299. template <typename Pred, typename... Preds>
  300. struct Or<Pred, Preds...> : Or<Preds...> {
  301.   Pred P;
  302.   Or(Pred &&p, Preds &&... preds)
  303.       : Or<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {}
  304.   template <typename MatchSrc>
  305.   bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
  306.     return P.match(MRI, src) || Or<Preds...>::match(MRI, src);
  307.   }
  308. };
  309.  
  310. template <typename... Preds> And<Preds...> m_all_of(Preds &&... preds) {
  311.   return And<Preds...>(std::forward<Preds>(preds)...);
  312. }
  313.  
  314. template <typename... Preds> Or<Preds...> m_any_of(Preds &&... preds) {
  315.   return Or<Preds...>(std::forward<Preds>(preds)...);
  316. }
  317.  
  318. template <typename BindTy> struct bind_helper {
  319.   static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
  320.     VR = V;
  321.     return true;
  322.   }
  323. };
  324.  
  325. template <> struct bind_helper<MachineInstr *> {
  326.   static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
  327.                    Register Reg) {
  328.     MI = MRI.getVRegDef(Reg);
  329.     if (MI)
  330.       return true;
  331.     return false;
  332.   }
  333.   static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
  334.                    MachineInstr *Inst) {
  335.     MI = Inst;
  336.     return MI;
  337.   }
  338. };
  339.  
  340. template <> struct bind_helper<LLT> {
  341.   static bool bind(const MachineRegisterInfo &MRI, LLT Ty, Register Reg) {
  342.     Ty = MRI.getType(Reg);
  343.     if (Ty.isValid())
  344.       return true;
  345.     return false;
  346.   }
  347. };
  348.  
  349. template <> struct bind_helper<const ConstantFP *> {
  350.   static bool bind(const MachineRegisterInfo &MRI, const ConstantFP *&F,
  351.                    Register Reg) {
  352.     F = getConstantFPVRegVal(Reg, MRI);
  353.     if (F)
  354.       return true;
  355.     return false;
  356.   }
  357. };
  358.  
  359. template <typename Class> struct bind_ty {
  360.   Class &VR;
  361.  
  362.   bind_ty(Class &V) : VR(V) {}
  363.  
  364.   template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) {
  365.     return bind_helper<Class>::bind(MRI, VR, V);
  366.   }
  367. };
  368.  
  369. inline bind_ty<Register> m_Reg(Register &R) { return R; }
  370. inline bind_ty<MachineInstr *> m_MInstr(MachineInstr *&MI) { return MI; }
  371. inline bind_ty<LLT> m_Type(LLT Ty) { return Ty; }
  372. inline bind_ty<CmpInst::Predicate> m_Pred(CmpInst::Predicate &P) { return P; }
  373. inline operand_type_match m_Pred() { return operand_type_match(); }
  374.  
  375. struct ImplicitDefMatch {
  376.   bool match(const MachineRegisterInfo &MRI, Register Reg) {
  377.     MachineInstr *TmpMI;
  378.     if (mi_match(Reg, MRI, m_MInstr(TmpMI)))
  379.       return TmpMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF;
  380.     return false;
  381.   }
  382. };
  383.  
  384. inline ImplicitDefMatch m_GImplicitDef() { return ImplicitDefMatch(); }
  385.  
  386. // Helper for matching G_FCONSTANT
  387. inline bind_ty<const ConstantFP *> m_GFCst(const ConstantFP *&C) { return C; }
  388.  
  389. // General helper for all the binary generic MI such as G_ADD/G_SUB etc
  390. template <typename LHS_P, typename RHS_P, unsigned Opcode,
  391.           bool Commutable = false>
  392. struct BinaryOp_match {
  393.   LHS_P L;
  394.   RHS_P R;
  395.  
  396.   BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {}
  397.   template <typename OpTy>
  398.   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
  399.     MachineInstr *TmpMI;
  400.     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
  401.       if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) {
  402.         return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
  403.                 R.match(MRI, TmpMI->getOperand(2).getReg())) ||
  404.                (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) &&
  405.                                L.match(MRI, TmpMI->getOperand(2).getReg())));
  406.       }
  407.     }
  408.     return false;
  409.   }
  410. };
  411.  
  412. // Helper for (commutative) binary generic MI that checks Opcode.
  413. template <typename LHS_P, typename RHS_P, bool Commutable = false>
  414. struct BinaryOpc_match {
  415.   unsigned Opc;
  416.   LHS_P L;
  417.   RHS_P R;
  418.  
  419.   BinaryOpc_match(unsigned Opcode, const LHS_P &LHS, const RHS_P &RHS)
  420.       : Opc(Opcode), L(LHS), R(RHS) {}
  421.   template <typename OpTy>
  422.   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
  423.     MachineInstr *TmpMI;
  424.     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
  425.       if (TmpMI->getOpcode() == Opc && TmpMI->getNumDefs() == 1 &&
  426.           TmpMI->getNumOperands() == 3) {
  427.         return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
  428.                 R.match(MRI, TmpMI->getOperand(2).getReg())) ||
  429.                (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) &&
  430.                                L.match(MRI, TmpMI->getOperand(2).getReg())));
  431.       }
  432.     }
  433.     return false;
  434.   }
  435. };
  436.  
  437. template <typename LHS, typename RHS>
  438. inline BinaryOpc_match<LHS, RHS, false> m_BinOp(unsigned Opcode, const LHS &L,
  439.                                                 const RHS &R) {
  440.   return BinaryOpc_match<LHS, RHS, false>(Opcode, L, R);
  441. }
  442.  
  443. template <typename LHS, typename RHS>
  444. inline BinaryOpc_match<LHS, RHS, true>
  445. m_CommutativeBinOp(unsigned Opcode, const LHS &L, const RHS &R) {
  446.   return BinaryOpc_match<LHS, RHS, true>(Opcode, L, R);
  447. }
  448.  
  449. template <typename LHS, typename RHS>
  450. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>
  451. m_GAdd(const LHS &L, const RHS &R) {
  452.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>(L, R);
  453. }
  454.  
  455. template <typename LHS, typename RHS>
  456. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false>
  457. m_GBuildVector(const LHS &L, const RHS &R) {
  458.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false>(L, R);
  459. }
  460.  
  461. template <typename LHS, typename RHS>
  462. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false>
  463. m_GBuildVectorTrunc(const LHS &L, const RHS &R) {
  464.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false>(L,
  465.                                                                              R);
  466. }
  467.  
  468. template <typename LHS, typename RHS>
  469. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false>
  470. m_GPtrAdd(const LHS &L, const RHS &R) {
  471.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false>(L, R);
  472. }
  473.  
  474. template <typename LHS, typename RHS>
  475. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB> m_GSub(const LHS &L,
  476.                                                             const RHS &R) {
  477.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB>(L, R);
  478. }
  479.  
  480. template <typename LHS, typename RHS>
  481. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>
  482. m_GMul(const LHS &L, const RHS &R) {
  483.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>(L, R);
  484. }
  485.  
  486. template <typename LHS, typename RHS>
  487. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>
  488. m_GFAdd(const LHS &L, const RHS &R) {
  489.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>(L, R);
  490. }
  491.  
  492. template <typename LHS, typename RHS>
  493. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>
  494. m_GFMul(const LHS &L, const RHS &R) {
  495.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>(L, R);
  496. }
  497.  
  498. template <typename LHS, typename RHS>
  499. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>
  500. m_GFSub(const LHS &L, const RHS &R) {
  501.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>(L, R);
  502. }
  503.  
  504. template <typename LHS, typename RHS>
  505. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>
  506. m_GAnd(const LHS &L, const RHS &R) {
  507.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>(L, R);
  508. }
  509.  
  510. template <typename LHS, typename RHS>
  511. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>
  512. m_GXor(const LHS &L, const RHS &R) {
  513.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>(L, R);
  514. }
  515.  
  516. template <typename LHS, typename RHS>
  517. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true> m_GOr(const LHS &L,
  518.                                                                 const RHS &R) {
  519.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true>(L, R);
  520. }
  521.  
  522. template <typename LHS, typename RHS>
  523. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>
  524. m_GShl(const LHS &L, const RHS &R) {
  525.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>(L, R);
  526. }
  527.  
  528. template <typename LHS, typename RHS>
  529. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>
  530. m_GLShr(const LHS &L, const RHS &R) {
  531.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>(L, R);
  532. }
  533.  
  534. template <typename LHS, typename RHS>
  535. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>
  536. m_GAShr(const LHS &L, const RHS &R) {
  537.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>(L, R);
  538. }
  539.  
  540. template <typename LHS, typename RHS>
  541. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, false>
  542. m_GSMax(const LHS &L, const RHS &R) {
  543.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, false>(L, R);
  544. }
  545.  
  546. template <typename LHS, typename RHS>
  547. inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, false>
  548. m_GSMin(const LHS &L, const RHS &R) {
  549.   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, false>(L, R);
  550. }
  551.  
  552. // Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc
  553. template <typename SrcTy, unsigned Opcode> struct UnaryOp_match {
  554.   SrcTy L;
  555.  
  556.   UnaryOp_match(const SrcTy &LHS) : L(LHS) {}
  557.   template <typename OpTy>
  558.   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
  559.     MachineInstr *TmpMI;
  560.     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
  561.       if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) {
  562.         return L.match(MRI, TmpMI->getOperand(1).getReg());
  563.       }
  564.     }
  565.     return false;
  566.   }
  567. };
  568.  
  569. template <typename SrcTy>
  570. inline UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>
  571. m_GAnyExt(const SrcTy &Src) {
  572.   return UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>(Src);
  573. }
  574.  
  575. template <typename SrcTy>
  576. inline UnaryOp_match<SrcTy, TargetOpcode::G_SEXT> m_GSExt(const SrcTy &Src) {
  577.   return UnaryOp_match<SrcTy, TargetOpcode::G_SEXT>(Src);
  578. }
  579.  
  580. template <typename SrcTy>
  581. inline UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT> m_GZExt(const SrcTy &Src) {
  582.   return UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT>(Src);
  583. }
  584.  
  585. template <typename SrcTy>
  586. inline UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT> m_GFPExt(const SrcTy &Src) {
  587.   return UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT>(Src);
  588. }
  589.  
  590. template <typename SrcTy>
  591. inline UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC> m_GTrunc(const SrcTy &Src) {
  592.   return UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC>(Src);
  593. }
  594.  
  595. template <typename SrcTy>
  596. inline UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>
  597. m_GBitcast(const SrcTy &Src) {
  598.   return UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>(Src);
  599. }
  600.  
  601. template <typename SrcTy>
  602. inline UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>
  603. m_GPtrToInt(const SrcTy &Src) {
  604.   return UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>(Src);
  605. }
  606.  
  607. template <typename SrcTy>
  608. inline UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>
  609. m_GIntToPtr(const SrcTy &Src) {
  610.   return UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>(Src);
  611. }
  612.  
  613. template <typename SrcTy>
  614. inline UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>
  615. m_GFPTrunc(const SrcTy &Src) {
  616.   return UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>(Src);
  617. }
  618.  
  619. template <typename SrcTy>
  620. inline UnaryOp_match<SrcTy, TargetOpcode::G_FABS> m_GFabs(const SrcTy &Src) {
  621.   return UnaryOp_match<SrcTy, TargetOpcode::G_FABS>(Src);
  622. }
  623.  
  624. template <typename SrcTy>
  625. inline UnaryOp_match<SrcTy, TargetOpcode::G_FNEG> m_GFNeg(const SrcTy &Src) {
  626.   return UnaryOp_match<SrcTy, TargetOpcode::G_FNEG>(Src);
  627. }
  628.  
  629. template <typename SrcTy>
  630. inline UnaryOp_match<SrcTy, TargetOpcode::COPY> m_Copy(SrcTy &&Src) {
  631.   return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src));
  632. }
  633.  
  634. template <typename SrcTy>
  635. inline UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT> m_GFSqrt(const SrcTy &Src) {
  636.   return UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT>(Src);
  637. }
  638.  
  639. // General helper for generic MI compares, i.e. G_ICMP and G_FCMP
  640. // TODO: Allow checking a specific predicate.
  641. template <typename Pred_P, typename LHS_P, typename RHS_P, unsigned Opcode,
  642.           bool Commutable = false>
  643. struct CompareOp_match {
  644.   Pred_P P;
  645.   LHS_P L;
  646.   RHS_P R;
  647.  
  648.   CompareOp_match(const Pred_P &Pred, const LHS_P &LHS, const RHS_P &RHS)
  649.       : P(Pred), L(LHS), R(RHS) {}
  650.  
  651.   template <typename OpTy>
  652.   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
  653.     MachineInstr *TmpMI;
  654.     if (!mi_match(Op, MRI, m_MInstr(TmpMI)) || TmpMI->getOpcode() != Opcode)
  655.       return false;
  656.  
  657.     auto TmpPred =
  658.         static_cast<CmpInst::Predicate>(TmpMI->getOperand(1).getPredicate());
  659.     if (!P.match(MRI, TmpPred))
  660.       return false;
  661.     Register LHS = TmpMI->getOperand(2).getReg();
  662.     Register RHS = TmpMI->getOperand(3).getReg();
  663.     if (L.match(MRI, LHS) && R.match(MRI, RHS))
  664.       return true;
  665.     if (Commutable && L.match(MRI, RHS) && R.match(MRI, LHS) &&
  666.         P.match(MRI, CmpInst::getSwappedPredicate(TmpPred)))
  667.       return true;
  668.     return false;
  669.   }
  670. };
  671.  
  672. template <typename Pred, typename LHS, typename RHS>
  673. inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>
  674. m_GICmp(const Pred &P, const LHS &L, const RHS &R) {
  675.   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>(P, L, R);
  676. }
  677.  
  678. template <typename Pred, typename LHS, typename RHS>
  679. inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>
  680. m_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
  681.   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>(P, L, R);
  682. }
  683.  
  684. /// G_ICMP matcher that also matches commuted compares.
  685. /// E.g.
  686. ///
  687. /// m_c_GICmp(m_Pred(...), m_GAdd(...), m_GSub(...))
  688. ///
  689. /// Could match both of:
  690. ///
  691. /// icmp ugt (add x, y) (sub a, b)
  692. /// icmp ult (sub a, b) (add x, y)
  693. template <typename Pred, typename LHS, typename RHS>
  694. inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP, true>
  695. m_c_GICmp(const Pred &P, const LHS &L, const RHS &R) {
  696.   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP, true>(P, L, R);
  697. }
  698.  
  699. /// G_FCMP matcher that also matches commuted compares.
  700. /// E.g.
  701. ///
  702. /// m_c_GFCmp(m_Pred(...), m_FAdd(...), m_GFMul(...))
  703. ///
  704. /// Could match both of:
  705. ///
  706. /// fcmp ogt (fadd x, y) (fmul a, b)
  707. /// fcmp olt (fmul a, b) (fadd x, y)
  708. template <typename Pred, typename LHS, typename RHS>
  709. inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP, true>
  710. m_c_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
  711.   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP, true>(P, L, R);
  712. }
  713.  
  714. // Helper for checking if a Reg is of specific type.
  715. struct CheckType {
  716.   LLT Ty;
  717.   CheckType(const LLT Ty) : Ty(Ty) {}
  718.  
  719.   bool match(const MachineRegisterInfo &MRI, Register Reg) {
  720.     return MRI.getType(Reg) == Ty;
  721.   }
  722. };
  723.  
  724. inline CheckType m_SpecificType(LLT Ty) { return Ty; }
  725.  
  726. template <typename Src0Ty, typename Src1Ty, typename Src2Ty, unsigned Opcode>
  727. struct TernaryOp_match {
  728.   Src0Ty Src0;
  729.   Src1Ty Src1;
  730.   Src2Ty Src2;
  731.  
  732.   TernaryOp_match(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
  733.       : Src0(Src0), Src1(Src1), Src2(Src2) {}
  734.   template <typename OpTy>
  735.   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
  736.     MachineInstr *TmpMI;
  737.     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
  738.       if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 4) {
  739.         return (Src0.match(MRI, TmpMI->getOperand(1).getReg()) &&
  740.                 Src1.match(MRI, TmpMI->getOperand(2).getReg()) &&
  741.                 Src2.match(MRI, TmpMI->getOperand(3).getReg()));
  742.       }
  743.     }
  744.     return false;
  745.   }
  746. };
  747. template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
  748. inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
  749.                        TargetOpcode::G_INSERT_VECTOR_ELT>
  750. m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
  751.   return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
  752.                          TargetOpcode::G_INSERT_VECTOR_ELT>(Src0, Src1, Src2);
  753. }
  754.  
  755. template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
  756. inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>
  757. m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
  758.   return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>(
  759.       Src0, Src1, Src2);
  760. }
  761.  
  762. /// Matches a register negated by a G_SUB.
  763. /// G_SUB 0, %negated_reg
  764. template <typename SrcTy>
  765. inline BinaryOp_match<SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB>
  766. m_Neg(const SrcTy &&Src) {
  767.   return m_GSub(m_ZeroInt(), Src);
  768. }
  769.  
  770. /// Matches a register not-ed by a G_XOR.
  771. /// G_XOR %not_reg, -1
  772. template <typename SrcTy>
  773. inline BinaryOp_match<SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true>
  774. m_Not(const SrcTy &&Src) {
  775.   return m_GXor(Src, m_AllOnesInt());
  776. }
  777.  
  778. } // namespace MIPatternMatch
  779. } // namespace llvm
  780.  
  781. #endif
  782.