xref: /freebsd/contrib/llvm-project/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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>
mi_match(Reg R,const MachineRegisterInfo & MRI,Pattern && P)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>
mi_match(MachineInstr & MI,const MachineRegisterInfo & MRI,Pattern && P)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;
OneUse_matchOneUse_match39   OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
40 
matchOneUse_match41   bool match(const MachineRegisterInfo &MRI, Register Reg) {
42     return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
43   }
44 };
45 
46 template <typename SubPat>
m_OneUse(const SubPat & SP)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;
OneNonDBGUse_matchOneNonDBGUse_match53   OneNonDBGUse_match(const SubPatternT &SP) : SubPat(SP) {}
54 
matchOneNonDBGUse_match55   bool match(const MachineRegisterInfo &MRI, Register Reg) {
56     return MRI.hasOneNonDBGUse(Reg) && SubPat.match(MRI, Reg);
57   }
58 };
59 
60 template <typename SubPat>
m_OneNonDBGUse(const SubPat & SP)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 <>
matchConstant(Register Reg,const MachineRegisterInfo & MRI)70 inline std::optional<APInt> matchConstant(Register Reg,
71                                           const MachineRegisterInfo &MRI) {
72   return getIConstantVRegVal(Reg, MRI);
73 }
74 
75 template <>
matchConstant(Register Reg,const MachineRegisterInfo & MRI)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;
ConstantMatchConstantMatch83   ConstantMatch(ConstT &C) : CR(C) {}
matchConstantMatch84   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 
m_ICst(APInt & Cst)93 inline ConstantMatch<APInt> m_ICst(APInt &Cst) {
94   return ConstantMatch<APInt>(Cst);
95 }
m_ICst(int64_t & Cst)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 <>
matchConstantSplat(Register Reg,const MachineRegisterInfo & MRI)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>
matchConstantSplat(Register Reg,const MachineRegisterInfo & MRI)112 matchConstantSplat(Register Reg, const MachineRegisterInfo &MRI) {
113   return getIConstantSplatSExtVal(Reg, MRI);
114 }
115 
116 template <typename ConstT> struct ICstOrSplatMatch {
117   ConstT &CR;
ICstOrSplatMatchICstOrSplatMatch118   ICstOrSplatMatch(ConstT &C) : CR(C) {}
matchICstOrSplatMatch119   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 
m_ICstOrSplat(APInt & Cst)134 inline ICstOrSplatMatch<APInt> m_ICstOrSplat(APInt &Cst) {
135   return ICstOrSplatMatch<APInt>(Cst);
136 }
137 
m_ICstOrSplat(int64_t & Cst)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;
GCstAndRegMatchGCstAndRegMatch144   GCstAndRegMatch(std::optional<ValueAndVReg> &ValReg) : ValReg(ValReg) {}
matchGCstAndRegMatch145   bool match(const MachineRegisterInfo &MRI, Register Reg) {
146     ValReg = getIConstantVRegValWithLookThrough(Reg, MRI);
147     return ValReg ? true : false;
148   }
149 };
150 
m_GCst(std::optional<ValueAndVReg> & ValReg)151 inline GCstAndRegMatch m_GCst(std::optional<ValueAndVReg> &ValReg) {
152   return GCstAndRegMatch(ValReg);
153 }
154 
155 struct GFCstAndRegMatch {
156   std::optional<FPValueAndVReg> &FPValReg;
GFCstAndRegMatchGFCstAndRegMatch157   GFCstAndRegMatch(std::optional<FPValueAndVReg> &FPValReg)
158       : FPValReg(FPValReg) {}
matchGFCstAndRegMatch159   bool match(const MachineRegisterInfo &MRI, Register Reg) {
160     FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI);
161     return FPValReg ? true : false;
162   }
163 };
164 
m_GFCst(std::optional<FPValueAndVReg> & FPValReg)165 inline GFCstAndRegMatch m_GFCst(std::optional<FPValueAndVReg> &FPValReg) {
166   return GFCstAndRegMatch(FPValReg);
167 }
168 
169 struct GFCstOrSplatGFCstMatch {
170   std::optional<FPValueAndVReg> &FPValReg;
GFCstOrSplatGFCstMatchGFCstOrSplatGFCstMatch171   GFCstOrSplatGFCstMatch(std::optional<FPValueAndVReg> &FPValReg)
172       : FPValReg(FPValReg) {}
matchGFCstOrSplatGFCstMatch173   bool match(const MachineRegisterInfo &MRI, Register Reg) {
174     return (FPValReg = getFConstantSplat(Reg, MRI)) ||
175            (FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI));
176   };
177 };
178 
179 inline GFCstOrSplatGFCstMatch
m_GFCstOrSplat(std::optional<FPValueAndVReg> & FPValReg)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;
SpecificConstantMatchSpecificConstantMatch187   SpecificConstantMatch(int64_t RequestedVal) : RequestedVal(RequestedVal) {}
matchSpecificConstantMatch188   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.
m_SpecificICst(int64_t 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;
SpecificConstantSplatMatchSpecificConstantSplatMatch202   SpecificConstantSplatMatch(int64_t RequestedVal)
203       : RequestedVal(RequestedVal) {}
matchSpecificConstantSplatMatch204   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.
m_SpecificICstSplat(int64_t 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;
SpecificConstantOrSplatMatchSpecificConstantOrSplatMatch218   SpecificConstantOrSplatMatch(int64_t RequestedVal)
219       : RequestedVal(RequestedVal) {}
matchSpecificConstantOrSplatMatch220   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
m_SpecificICstOrSplat(int64_t RequestedValue)232 m_SpecificICstOrSplat(int64_t RequestedValue) {
233   return SpecificConstantOrSplatMatch(RequestedValue);
234 }
235 
236 ///{
237 /// Convenience matchers for specific integer values.
m_ZeroInt()238 inline SpecificConstantMatch m_ZeroInt() { return SpecificConstantMatch(0); }
m_AllOnesInt()239 inline SpecificConstantMatch m_AllOnesInt() {
240   return SpecificConstantMatch(-1);
241 }
242 ///}
243 
244 /// Matcher for a specific register.
245 struct SpecificRegisterMatch {
246   Register RequestedReg;
SpecificRegisterMatchSpecificRegisterMatch247   SpecificRegisterMatch(Register RequestedReg) : RequestedReg(RequestedReg) {}
matchSpecificRegisterMatch248   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.
m_SpecificReg(Register 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 {
matchoperand_type_match264   bool match(const MachineRegisterInfo &MRI, Register Reg) { return true; }
matchoperand_type_match265   bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) {
266     return MO->isReg();
267   }
268 };
269 
m_Reg()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>
matchAnd275   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