Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //==------ llvm/CodeGen/GlobalISel/MIPatternMatch.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 SSA Machine Instructions.
0010 ///
0011 //===----------------------------------------------------------------------===//
0012 
0013 #ifndef LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H
0014 #define LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H
0015 
0016 #include "llvm/ADT/APInt.h"
0017 #include "llvm/CodeGen/GlobalISel/Utils.h"
0018 #include "llvm/CodeGen/MachineRegisterInfo.h"
0019 #include "llvm/IR/InstrTypes.h"
0020 
0021 namespace llvm {
0022 namespace MIPatternMatch {
0023 
0024 template <typename Reg, typename Pattern>
0025 [[nodiscard]] bool mi_match(Reg R, const MachineRegisterInfo &MRI,
0026                             Pattern &&P) {
0027   return P.match(MRI, R);
0028 }
0029 
0030 template <typename Pattern>
0031 [[nodiscard]] bool mi_match(MachineInstr &MI, const MachineRegisterInfo &MRI,
0032                             Pattern &&P) {
0033   return P.match(MRI, &MI);
0034 }
0035 
0036 // TODO: Extend for N use.
0037 template <typename SubPatternT> struct OneUse_match {
0038   SubPatternT SubPat;
0039   OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
0040 
0041   bool match(const MachineRegisterInfo &MRI, Register Reg) {
0042     return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
0043   }
0044 };
0045 
0046 template <typename SubPat>
0047 inline OneUse_match<SubPat> m_OneUse(const SubPat &SP) {
0048   return SP;
0049 }
0050 
0051 template <typename SubPatternT> struct OneNonDBGUse_match {
0052   SubPatternT SubPat;
0053   OneNonDBGUse_match(const SubPatternT &SP) : SubPat(SP) {}
0054 
0055   bool match(const MachineRegisterInfo &MRI, Register Reg) {
0056     return MRI.hasOneNonDBGUse(Reg) && SubPat.match(MRI, Reg);
0057   }
0058 };
0059 
0060 template <typename SubPat>
0061 inline OneNonDBGUse_match<SubPat> m_OneNonDBGUse(const SubPat &SP) {
0062   return SP;
0063 }
0064 
0065 template <typename ConstT>
0066 inline std::optional<ConstT> matchConstant(Register,
0067                                            const MachineRegisterInfo &);
0068 
0069 template <>
0070 inline std::optional<APInt> matchConstant(Register Reg,
0071                                           const MachineRegisterInfo &MRI) {
0072   return getIConstantVRegVal(Reg, MRI);
0073 }
0074 
0075 template <>
0076 inline std::optional<int64_t> matchConstant(Register Reg,
0077                                             const MachineRegisterInfo &MRI) {
0078   return getIConstantVRegSExtVal(Reg, MRI);
0079 }
0080 
0081 template <typename ConstT> struct ConstantMatch {
0082   ConstT &CR;
0083   ConstantMatch(ConstT &C) : CR(C) {}
0084   bool match(const MachineRegisterInfo &MRI, Register Reg) {
0085     if (auto MaybeCst = matchConstant<ConstT>(Reg, MRI)) {
0086       CR = *MaybeCst;
0087       return true;
0088     }
0089     return false;
0090   }
0091 };
0092 
0093 inline ConstantMatch<APInt> m_ICst(APInt &Cst) {
0094   return ConstantMatch<APInt>(Cst);
0095 }
0096 inline ConstantMatch<int64_t> m_ICst(int64_t &Cst) {
0097   return ConstantMatch<int64_t>(Cst);
0098 }
0099 
0100 template <typename ConstT>
0101 inline std::optional<ConstT> matchConstantSplat(Register,
0102                                                 const MachineRegisterInfo &);
0103 
0104 template <>
0105 inline std::optional<APInt> matchConstantSplat(Register Reg,
0106                                                const MachineRegisterInfo &MRI) {
0107   return getIConstantSplatVal(Reg, MRI);
0108 }
0109 
0110 template <>
0111 inline std::optional<int64_t>
0112 matchConstantSplat(Register Reg, const MachineRegisterInfo &MRI) {
0113   return getIConstantSplatSExtVal(Reg, MRI);
0114 }
0115 
0116 template <typename ConstT> struct ICstOrSplatMatch {
0117   ConstT &CR;
0118   ICstOrSplatMatch(ConstT &C) : CR(C) {}
0119   bool match(const MachineRegisterInfo &MRI, Register Reg) {
0120     if (auto MaybeCst = matchConstant<ConstT>(Reg, MRI)) {
0121       CR = *MaybeCst;
0122       return true;
0123     }
0124 
0125     if (auto MaybeCstSplat = matchConstantSplat<ConstT>(Reg, MRI)) {
0126       CR = *MaybeCstSplat;
0127       return true;
0128     }
0129 
0130     return false;
0131   };
0132 };
0133 
0134 inline ICstOrSplatMatch<APInt> m_ICstOrSplat(APInt &Cst) {
0135   return ICstOrSplatMatch<APInt>(Cst);
0136 }
0137 
0138 inline ICstOrSplatMatch<int64_t> m_ICstOrSplat(int64_t &Cst) {
0139   return ICstOrSplatMatch<int64_t>(Cst);
0140 }
0141 
0142 struct GCstAndRegMatch {
0143   std::optional<ValueAndVReg> &ValReg;
0144   GCstAndRegMatch(std::optional<ValueAndVReg> &ValReg) : ValReg(ValReg) {}
0145   bool match(const MachineRegisterInfo &MRI, Register Reg) {
0146     ValReg = getIConstantVRegValWithLookThrough(Reg, MRI);
0147     return ValReg ? true : false;
0148   }
0149 };
0150 
0151 inline GCstAndRegMatch m_GCst(std::optional<ValueAndVReg> &ValReg) {
0152   return GCstAndRegMatch(ValReg);
0153 }
0154 
0155 struct GFCstAndRegMatch {
0156   std::optional<FPValueAndVReg> &FPValReg;
0157   GFCstAndRegMatch(std::optional<FPValueAndVReg> &FPValReg)
0158       : FPValReg(FPValReg) {}
0159   bool match(const MachineRegisterInfo &MRI, Register Reg) {
0160     FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI);
0161     return FPValReg ? true : false;
0162   }
0163 };
0164 
0165 inline GFCstAndRegMatch m_GFCst(std::optional<FPValueAndVReg> &FPValReg) {
0166   return GFCstAndRegMatch(FPValReg);
0167 }
0168 
0169 struct GFCstOrSplatGFCstMatch {
0170   std::optional<FPValueAndVReg> &FPValReg;
0171   GFCstOrSplatGFCstMatch(std::optional<FPValueAndVReg> &FPValReg)
0172       : FPValReg(FPValReg) {}
0173   bool match(const MachineRegisterInfo &MRI, Register Reg) {
0174     return (FPValReg = getFConstantSplat(Reg, MRI)) ||
0175            (FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI));
0176   };
0177 };
0178 
0179 inline GFCstOrSplatGFCstMatch
0180 m_GFCstOrSplat(std::optional<FPValueAndVReg> &FPValReg) {
0181   return GFCstOrSplatGFCstMatch(FPValReg);
0182 }
0183 
0184 /// Matcher for a specific constant value.
0185 struct SpecificConstantMatch {
0186   int64_t RequestedVal;
0187   SpecificConstantMatch(int64_t RequestedVal) : RequestedVal(RequestedVal) {}
0188   bool match(const MachineRegisterInfo &MRI, Register Reg) {
0189     int64_t MatchedVal;
0190     return mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal;
0191   }
0192 };
0193 
0194 /// Matches a constant equal to \p RequestedValue.
0195 inline SpecificConstantMatch m_SpecificICst(int64_t RequestedValue) {
0196   return SpecificConstantMatch(RequestedValue);
0197 }
0198 
0199 /// Matcher for a specific constant splat.
0200 struct SpecificConstantSplatMatch {
0201   int64_t RequestedVal;
0202   SpecificConstantSplatMatch(int64_t RequestedVal)
0203       : RequestedVal(RequestedVal) {}
0204   bool match(const MachineRegisterInfo &MRI, Register Reg) {
0205     return isBuildVectorConstantSplat(Reg, MRI, RequestedVal,
0206                                       /* AllowUndef */ false);
0207   }
0208 };
0209 
0210 /// Matches a constant splat of \p RequestedValue.
0211 inline SpecificConstantSplatMatch m_SpecificICstSplat(int64_t RequestedValue) {
0212   return SpecificConstantSplatMatch(RequestedValue);
0213 }
0214 
0215 /// Matcher for a specific constant or constant splat.
0216 struct SpecificConstantOrSplatMatch {
0217   int64_t RequestedVal;
0218   SpecificConstantOrSplatMatch(int64_t RequestedVal)
0219       : RequestedVal(RequestedVal) {}
0220   bool match(const MachineRegisterInfo &MRI, Register Reg) {
0221     int64_t MatchedVal;
0222     if (mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal)
0223       return true;
0224     return isBuildVectorConstantSplat(Reg, MRI, RequestedVal,
0225                                       /* AllowUndef */ false);
0226   }
0227 };
0228 
0229 /// Matches a \p RequestedValue constant or a constant splat of \p
0230 /// RequestedValue.
0231 inline SpecificConstantOrSplatMatch
0232 m_SpecificICstOrSplat(int64_t RequestedValue) {
0233   return SpecificConstantOrSplatMatch(RequestedValue);
0234 }
0235 
0236 ///{
0237 /// Convenience matchers for specific integer values.
0238 inline SpecificConstantMatch m_ZeroInt() { return SpecificConstantMatch(0); }
0239 inline SpecificConstantMatch m_AllOnesInt() {
0240   return SpecificConstantMatch(-1);
0241 }
0242 ///}
0243 
0244 /// Matcher for a specific register.
0245 struct SpecificRegisterMatch {
0246   Register RequestedReg;
0247   SpecificRegisterMatch(Register RequestedReg) : RequestedReg(RequestedReg) {}
0248   bool match(const MachineRegisterInfo &MRI, Register Reg) {
0249     return Reg == RequestedReg;
0250   }
0251 };
0252 
0253 /// Matches a register only if it is equal to \p RequestedReg.
0254 inline SpecificRegisterMatch m_SpecificReg(Register RequestedReg) {
0255   return SpecificRegisterMatch(RequestedReg);
0256 }
0257 
0258 // TODO: Rework this for different kinds of MachineOperand.
0259 // Currently assumes the Src for a match is a register.
0260 // We might want to support taking in some MachineOperands and call getReg on
0261 // that.
0262 
0263 struct operand_type_match {
0264   bool match(const MachineRegisterInfo &MRI, Register Reg) { return true; }
0265   bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) {
0266     return MO->isReg();
0267   }
0268 };
0269 
0270 inline operand_type_match m_Reg() { return operand_type_match(); }
0271 
0272 /// Matching combinators.
0273 template <typename... Preds> struct And {
0274   template <typename MatchSrc>
0275   bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
0276     return true;
0277   }
0278 };
0279 
0280 template <typename Pred, typename... Preds>
0281 struct And<Pred, Preds...> : And<Preds...> {
0282   Pred P;
0283   And(Pred &&p, Preds &&... preds)
0284       : And<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {
0285   }
0286   template <typename MatchSrc>
0287   bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
0288     return P.match(MRI, src) && And<Preds...>::match(MRI, src);
0289   }
0290 };
0291 
0292 template <typename... Preds> struct Or {
0293   template <typename MatchSrc>
0294   bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
0295     return false;
0296   }
0297 };
0298 
0299 template <typename Pred, typename... Preds>
0300 struct Or<Pred, Preds...> : Or<Preds...> {
0301   Pred P;
0302   Or(Pred &&p, Preds &&... preds)
0303       : Or<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {}
0304   template <typename MatchSrc>
0305   bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
0306     return P.match(MRI, src) || Or<Preds...>::match(MRI, src);
0307   }
0308 };
0309 
0310 template <typename... Preds> And<Preds...> m_all_of(Preds &&... preds) {
0311   return And<Preds...>(std::forward<Preds>(preds)...);
0312 }
0313 
0314 template <typename... Preds> Or<Preds...> m_any_of(Preds &&... preds) {
0315   return Or<Preds...>(std::forward<Preds>(preds)...);
0316 }
0317 
0318 template <typename BindTy> struct bind_helper {
0319   static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
0320     VR = V;
0321     return true;
0322   }
0323 };
0324 
0325 template <> struct bind_helper<MachineInstr *> {
0326   static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
0327                    Register Reg) {
0328     MI = MRI.getVRegDef(Reg);
0329     if (MI)
0330       return true;
0331     return false;
0332   }
0333   static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
0334                    MachineInstr *Inst) {
0335     MI = Inst;
0336     return MI;
0337   }
0338 };
0339 
0340 template <> struct bind_helper<LLT> {
0341   static bool bind(const MachineRegisterInfo &MRI, LLT &Ty, Register Reg) {
0342     Ty = MRI.getType(Reg);
0343     if (Ty.isValid())
0344       return true;
0345     return false;
0346   }
0347 };
0348 
0349 template <> struct bind_helper<const ConstantFP *> {
0350   static bool bind(const MachineRegisterInfo &MRI, const ConstantFP *&F,
0351                    Register Reg) {
0352     F = getConstantFPVRegVal(Reg, MRI);
0353     if (F)
0354       return true;
0355     return false;
0356   }
0357 };
0358 
0359 template <typename Class> struct bind_ty {
0360   Class &VR;
0361 
0362   bind_ty(Class &V) : VR(V) {}
0363 
0364   template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) {
0365     return bind_helper<Class>::bind(MRI, VR, V);
0366   }
0367 };
0368 
0369 inline bind_ty<Register> m_Reg(Register &R) { return R; }
0370 inline bind_ty<MachineInstr *> m_MInstr(MachineInstr *&MI) { return MI; }
0371 inline bind_ty<LLT> m_Type(LLT &Ty) { return Ty; }
0372 inline bind_ty<CmpInst::Predicate> m_Pred(CmpInst::Predicate &P) { return P; }
0373 inline operand_type_match m_Pred() { return operand_type_match(); }
0374 
0375 template <typename BindTy> struct deferred_helper {
0376   static bool match(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
0377     return VR == V;
0378   }
0379 };
0380 
0381 template <> struct deferred_helper<LLT> {
0382   static bool match(const MachineRegisterInfo &MRI, LLT VT, Register R) {
0383     return VT == MRI.getType(R);
0384   }
0385 };
0386 
0387 template <typename Class> struct deferred_ty {
0388   Class &VR;
0389 
0390   deferred_ty(Class &V) : VR(V) {}
0391 
0392   template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) {
0393     return deferred_helper<Class>::match(MRI, VR, V);
0394   }
0395 };
0396 
0397 /// Similar to m_SpecificReg/Type, but the specific value to match originated
0398 /// from an earlier sub-pattern in the same mi_match expression. For example,
0399 /// we cannot match `(add X, X)` with `m_GAdd(m_Reg(X), m_SpecificReg(X))`
0400 /// because `X` is not initialized at the time it's passed to `m_SpecificReg`.
0401 /// Instead, we can use `m_GAdd(m_Reg(x), m_DeferredReg(X))`.
0402 inline deferred_ty<Register> m_DeferredReg(Register &R) { return R; }
0403 inline deferred_ty<LLT> m_DeferredType(LLT &Ty) { return Ty; }
0404 
0405 struct ImplicitDefMatch {
0406   bool match(const MachineRegisterInfo &MRI, Register Reg) {
0407     MachineInstr *TmpMI;
0408     if (mi_match(Reg, MRI, m_MInstr(TmpMI)))
0409       return TmpMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF;
0410     return false;
0411   }
0412 };
0413 
0414 inline ImplicitDefMatch m_GImplicitDef() { return ImplicitDefMatch(); }
0415 
0416 // Helper for matching G_FCONSTANT
0417 inline bind_ty<const ConstantFP *> m_GFCst(const ConstantFP *&C) { return C; }
0418 
0419 // General helper for all the binary generic MI such as G_ADD/G_SUB etc
0420 template <typename LHS_P, typename RHS_P, unsigned Opcode,
0421           bool Commutable = false>
0422 struct BinaryOp_match {
0423   LHS_P L;
0424   RHS_P R;
0425 
0426   BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {}
0427   template <typename OpTy>
0428   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
0429     MachineInstr *TmpMI;
0430     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
0431       if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) {
0432         return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
0433                 R.match(MRI, TmpMI->getOperand(2).getReg())) ||
0434                // NOTE: When trying the alternative operand ordering
0435                // with a commutative operation, it is imperative to always run
0436                // the LHS sub-pattern  (i.e. `L`) before the RHS sub-pattern
0437                // (i.e. `R`). Otherwsie, m_DeferredReg/Type will not work as
0438                // expected.
0439                (Commutable && (L.match(MRI, TmpMI->getOperand(2).getReg()) &&
0440                                R.match(MRI, TmpMI->getOperand(1).getReg())));
0441       }
0442     }
0443     return false;
0444   }
0445 };
0446 
0447 // Helper for (commutative) binary generic MI that checks Opcode.
0448 template <typename LHS_P, typename RHS_P, bool Commutable = false>
0449 struct BinaryOpc_match {
0450   unsigned Opc;
0451   LHS_P L;
0452   RHS_P R;
0453 
0454   BinaryOpc_match(unsigned Opcode, const LHS_P &LHS, const RHS_P &RHS)
0455       : Opc(Opcode), L(LHS), R(RHS) {}
0456   template <typename OpTy>
0457   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
0458     MachineInstr *TmpMI;
0459     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
0460       if (TmpMI->getOpcode() == Opc && TmpMI->getNumDefs() == 1 &&
0461           TmpMI->getNumOperands() == 3) {
0462         return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
0463                 R.match(MRI, TmpMI->getOperand(2).getReg())) ||
0464                // NOTE: When trying the alternative operand ordering
0465                // with a commutative operation, it is imperative to always run
0466                // the LHS sub-pattern  (i.e. `L`) before the RHS sub-pattern
0467                // (i.e. `R`). Otherwsie, m_DeferredReg/Type will not work as
0468                // expected.
0469                (Commutable && (L.match(MRI, TmpMI->getOperand(2).getReg()) &&
0470                                R.match(MRI, TmpMI->getOperand(1).getReg())));
0471       }
0472     }
0473     return false;
0474   }
0475 };
0476 
0477 template <typename LHS, typename RHS>
0478 inline BinaryOpc_match<LHS, RHS, false> m_BinOp(unsigned Opcode, const LHS &L,
0479                                                 const RHS &R) {
0480   return BinaryOpc_match<LHS, RHS, false>(Opcode, L, R);
0481 }
0482 
0483 template <typename LHS, typename RHS>
0484 inline BinaryOpc_match<LHS, RHS, true>
0485 m_CommutativeBinOp(unsigned Opcode, const LHS &L, const RHS &R) {
0486   return BinaryOpc_match<LHS, RHS, true>(Opcode, L, R);
0487 }
0488 
0489 template <typename LHS, typename RHS>
0490 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>
0491 m_GAdd(const LHS &L, const RHS &R) {
0492   return BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>(L, R);
0493 }
0494 
0495 template <typename LHS, typename RHS>
0496 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false>
0497 m_GBuildVector(const LHS &L, const RHS &R) {
0498   return BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false>(L, R);
0499 }
0500 
0501 template <typename LHS, typename RHS>
0502 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false>
0503 m_GBuildVectorTrunc(const LHS &L, const RHS &R) {
0504   return BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false>(L,
0505                                                                              R);
0506 }
0507 
0508 template <typename LHS, typename RHS>
0509 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false>
0510 m_GPtrAdd(const LHS &L, const RHS &R) {
0511   return BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false>(L, R);
0512 }
0513 
0514 template <typename LHS, typename RHS>
0515 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB> m_GSub(const LHS &L,
0516                                                             const RHS &R) {
0517   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB>(L, R);
0518 }
0519 
0520 template <typename LHS, typename RHS>
0521 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>
0522 m_GMul(const LHS &L, const RHS &R) {
0523   return BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>(L, R);
0524 }
0525 
0526 template <typename LHS, typename RHS>
0527 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>
0528 m_GFAdd(const LHS &L, const RHS &R) {
0529   return BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>(L, R);
0530 }
0531 
0532 template <typename LHS, typename RHS>
0533 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>
0534 m_GFMul(const LHS &L, const RHS &R) {
0535   return BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>(L, R);
0536 }
0537 
0538 template <typename LHS, typename RHS>
0539 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>
0540 m_GFSub(const LHS &L, const RHS &R) {
0541   return BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>(L, R);
0542 }
0543 
0544 template <typename LHS, typename RHS>
0545 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>
0546 m_GAnd(const LHS &L, const RHS &R) {
0547   return BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>(L, R);
0548 }
0549 
0550 template <typename LHS, typename RHS>
0551 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>
0552 m_GXor(const LHS &L, const RHS &R) {
0553   return BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>(L, R);
0554 }
0555 
0556 template <typename LHS, typename RHS>
0557 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true> m_GOr(const LHS &L,
0558                                                                 const RHS &R) {
0559   return BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true>(L, R);
0560 }
0561 
0562 template <typename LHS, typename RHS>
0563 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>
0564 m_GShl(const LHS &L, const RHS &R) {
0565   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>(L, R);
0566 }
0567 
0568 template <typename LHS, typename RHS>
0569 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>
0570 m_GLShr(const LHS &L, const RHS &R) {
0571   return BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>(L, R);
0572 }
0573 
0574 template <typename LHS, typename RHS>
0575 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>
0576 m_GAShr(const LHS &L, const RHS &R) {
0577   return BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>(L, R);
0578 }
0579 
0580 template <typename LHS, typename RHS>
0581 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, true>
0582 m_GSMax(const LHS &L, const RHS &R) {
0583   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, true>(L, R);
0584 }
0585 
0586 template <typename LHS, typename RHS>
0587 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, true>
0588 m_GSMin(const LHS &L, const RHS &R) {
0589   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, true>(L, R);
0590 }
0591 
0592 template <typename LHS, typename RHS>
0593 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_UMAX, true>
0594 m_GUMax(const LHS &L, const RHS &R) {
0595   return BinaryOp_match<LHS, RHS, TargetOpcode::G_UMAX, true>(L, R);
0596 }
0597 
0598 template <typename LHS, typename RHS>
0599 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_UMIN, true>
0600 m_GUMin(const LHS &L, const RHS &R) {
0601   return BinaryOp_match<LHS, RHS, TargetOpcode::G_UMIN, true>(L, R);
0602 }
0603 
0604 // Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc
0605 template <typename SrcTy, unsigned Opcode> struct UnaryOp_match {
0606   SrcTy L;
0607 
0608   UnaryOp_match(const SrcTy &LHS) : L(LHS) {}
0609   template <typename OpTy>
0610   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
0611     MachineInstr *TmpMI;
0612     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
0613       if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) {
0614         return L.match(MRI, TmpMI->getOperand(1).getReg());
0615       }
0616     }
0617     return false;
0618   }
0619 };
0620 
0621 template <typename SrcTy>
0622 inline UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>
0623 m_GAnyExt(const SrcTy &Src) {
0624   return UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>(Src);
0625 }
0626 
0627 template <typename SrcTy>
0628 inline UnaryOp_match<SrcTy, TargetOpcode::G_SEXT> m_GSExt(const SrcTy &Src) {
0629   return UnaryOp_match<SrcTy, TargetOpcode::G_SEXT>(Src);
0630 }
0631 
0632 template <typename SrcTy>
0633 inline UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT> m_GZExt(const SrcTy &Src) {
0634   return UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT>(Src);
0635 }
0636 
0637 template <typename SrcTy>
0638 inline UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT> m_GFPExt(const SrcTy &Src) {
0639   return UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT>(Src);
0640 }
0641 
0642 template <typename SrcTy>
0643 inline UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC> m_GTrunc(const SrcTy &Src) {
0644   return UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC>(Src);
0645 }
0646 
0647 template <typename SrcTy>
0648 inline UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>
0649 m_GBitcast(const SrcTy &Src) {
0650   return UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>(Src);
0651 }
0652 
0653 template <typename SrcTy>
0654 inline UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>
0655 m_GPtrToInt(const SrcTy &Src) {
0656   return UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>(Src);
0657 }
0658 
0659 template <typename SrcTy>
0660 inline UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>
0661 m_GIntToPtr(const SrcTy &Src) {
0662   return UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>(Src);
0663 }
0664 
0665 template <typename SrcTy>
0666 inline UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>
0667 m_GFPTrunc(const SrcTy &Src) {
0668   return UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>(Src);
0669 }
0670 
0671 template <typename SrcTy>
0672 inline UnaryOp_match<SrcTy, TargetOpcode::G_FABS> m_GFabs(const SrcTy &Src) {
0673   return UnaryOp_match<SrcTy, TargetOpcode::G_FABS>(Src);
0674 }
0675 
0676 template <typename SrcTy>
0677 inline UnaryOp_match<SrcTy, TargetOpcode::G_FNEG> m_GFNeg(const SrcTy &Src) {
0678   return UnaryOp_match<SrcTy, TargetOpcode::G_FNEG>(Src);
0679 }
0680 
0681 template <typename SrcTy>
0682 inline UnaryOp_match<SrcTy, TargetOpcode::COPY> m_Copy(SrcTy &&Src) {
0683   return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src));
0684 }
0685 
0686 template <typename SrcTy>
0687 inline UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT> m_GFSqrt(const SrcTy &Src) {
0688   return UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT>(Src);
0689 }
0690 
0691 // General helper for generic MI compares, i.e. G_ICMP and G_FCMP
0692 // TODO: Allow checking a specific predicate.
0693 template <typename Pred_P, typename LHS_P, typename RHS_P, unsigned Opcode,
0694           bool Commutable = false>
0695 struct CompareOp_match {
0696   Pred_P P;
0697   LHS_P L;
0698   RHS_P R;
0699 
0700   CompareOp_match(const Pred_P &Pred, const LHS_P &LHS, const RHS_P &RHS)
0701       : P(Pred), L(LHS), R(RHS) {}
0702 
0703   template <typename OpTy>
0704   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
0705     MachineInstr *TmpMI;
0706     if (!mi_match(Op, MRI, m_MInstr(TmpMI)) || TmpMI->getOpcode() != Opcode)
0707       return false;
0708 
0709     auto TmpPred =
0710         static_cast<CmpInst::Predicate>(TmpMI->getOperand(1).getPredicate());
0711     if (!P.match(MRI, TmpPred))
0712       return false;
0713     Register LHS = TmpMI->getOperand(2).getReg();
0714     Register RHS = TmpMI->getOperand(3).getReg();
0715     if (L.match(MRI, LHS) && R.match(MRI, RHS))
0716       return true;
0717     // NOTE: When trying the alternative operand ordering
0718     // with a commutative operation, it is imperative to always run
0719     // the LHS sub-pattern  (i.e. `L`) before the RHS sub-pattern
0720     // (i.e. `R`). Otherwsie, m_DeferredReg/Type will not work as expected.
0721     if (Commutable && L.match(MRI, RHS) && R.match(MRI, LHS) &&
0722         P.match(MRI, CmpInst::getSwappedPredicate(TmpPred)))
0723       return true;
0724     return false;
0725   }
0726 };
0727 
0728 template <typename Pred, typename LHS, typename RHS>
0729 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>
0730 m_GICmp(const Pred &P, const LHS &L, const RHS &R) {
0731   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>(P, L, R);
0732 }
0733 
0734 template <typename Pred, typename LHS, typename RHS>
0735 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>
0736 m_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
0737   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>(P, L, R);
0738 }
0739 
0740 /// G_ICMP matcher that also matches commuted compares.
0741 /// E.g.
0742 ///
0743 /// m_c_GICmp(m_Pred(...), m_GAdd(...), m_GSub(...))
0744 ///
0745 /// Could match both of:
0746 ///
0747 /// icmp ugt (add x, y) (sub a, b)
0748 /// icmp ult (sub a, b) (add x, y)
0749 template <typename Pred, typename LHS, typename RHS>
0750 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP, true>
0751 m_c_GICmp(const Pred &P, const LHS &L, const RHS &R) {
0752   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP, true>(P, L, R);
0753 }
0754 
0755 /// G_FCMP matcher that also matches commuted compares.
0756 /// E.g.
0757 ///
0758 /// m_c_GFCmp(m_Pred(...), m_FAdd(...), m_GFMul(...))
0759 ///
0760 /// Could match both of:
0761 ///
0762 /// fcmp ogt (fadd x, y) (fmul a, b)
0763 /// fcmp olt (fmul a, b) (fadd x, y)
0764 template <typename Pred, typename LHS, typename RHS>
0765 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP, true>
0766 m_c_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
0767   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP, true>(P, L, R);
0768 }
0769 
0770 // Helper for checking if a Reg is of specific type.
0771 struct CheckType {
0772   LLT Ty;
0773   CheckType(const LLT Ty) : Ty(Ty) {}
0774 
0775   bool match(const MachineRegisterInfo &MRI, Register Reg) {
0776     return MRI.getType(Reg) == Ty;
0777   }
0778 };
0779 
0780 inline CheckType m_SpecificType(LLT Ty) { return Ty; }
0781 
0782 template <typename Src0Ty, typename Src1Ty, typename Src2Ty, unsigned Opcode>
0783 struct TernaryOp_match {
0784   Src0Ty Src0;
0785   Src1Ty Src1;
0786   Src2Ty Src2;
0787 
0788   TernaryOp_match(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
0789       : Src0(Src0), Src1(Src1), Src2(Src2) {}
0790   template <typename OpTy>
0791   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
0792     MachineInstr *TmpMI;
0793     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
0794       if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 4) {
0795         return (Src0.match(MRI, TmpMI->getOperand(1).getReg()) &&
0796                 Src1.match(MRI, TmpMI->getOperand(2).getReg()) &&
0797                 Src2.match(MRI, TmpMI->getOperand(3).getReg()));
0798       }
0799     }
0800     return false;
0801   }
0802 };
0803 template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
0804 inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
0805                        TargetOpcode::G_INSERT_VECTOR_ELT>
0806 m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
0807   return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
0808                          TargetOpcode::G_INSERT_VECTOR_ELT>(Src0, Src1, Src2);
0809 }
0810 
0811 template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
0812 inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>
0813 m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
0814   return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>(
0815       Src0, Src1, Src2);
0816 }
0817 
0818 /// Matches a register negated by a G_SUB.
0819 /// G_SUB 0, %negated_reg
0820 template <typename SrcTy>
0821 inline BinaryOp_match<SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB>
0822 m_Neg(const SrcTy &&Src) {
0823   return m_GSub(m_ZeroInt(), Src);
0824 }
0825 
0826 /// Matches a register not-ed by a G_XOR.
0827 /// G_XOR %not_reg, -1
0828 template <typename SrcTy>
0829 inline BinaryOp_match<SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true>
0830 m_Not(const SrcTy &&Src) {
0831   return m_GXor(Src, m_AllOnesInt());
0832 }
0833 
0834 } // namespace MIPatternMatch
0835 } // namespace llvm
0836 
0837 #endif