xref: /llvm-project/llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h (revision a74f825a7acec4962bb4c172da7ed0028f7b4d44)
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 template <typename BindTy> struct deferred_helper {
376   static bool match(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
377     return VR == V;
378   }
379 };
380 
381 template <> struct deferred_helper<LLT> {
382   static bool match(const MachineRegisterInfo &MRI, LLT VT, Register R) {
383     return VT == MRI.getType(R);
384   }
385 };
386 
387 template <typename Class> struct deferred_ty {
388   Class &VR;
389 
390   deferred_ty(Class &V) : VR(V) {}
391 
392   template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) {
393     return deferred_helper<Class>::match(MRI, VR, V);
394   }
395 };
396 
397 /// Similar to m_SpecificReg/Type, but the specific value to match originated
398 /// from an earlier sub-pattern in the same mi_match expression. For example,
399 /// we cannot match `(add X, X)` with `m_GAdd(m_Reg(X), m_SpecificReg(X))`
400 /// because `X` is not initialized at the time it's passed to `m_SpecificReg`.
401 /// Instead, we can use `m_GAdd(m_Reg(x), m_DeferredReg(X))`.
402 inline deferred_ty<Register> m_DeferredReg(Register &R) { return R; }
403 inline deferred_ty<LLT> m_DeferredType(LLT &Ty) { return Ty; }
404 
405 struct ImplicitDefMatch {
406   bool match(const MachineRegisterInfo &MRI, Register Reg) {
407     MachineInstr *TmpMI;
408     if (mi_match(Reg, MRI, m_MInstr(TmpMI)))
409       return TmpMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF;
410     return false;
411   }
412 };
413 
414 inline ImplicitDefMatch m_GImplicitDef() { return ImplicitDefMatch(); }
415 
416 // Helper for matching G_FCONSTANT
417 inline bind_ty<const ConstantFP *> m_GFCst(const ConstantFP *&C) { return C; }
418 
419 // General helper for all the binary generic MI such as G_ADD/G_SUB etc
420 template <typename LHS_P, typename RHS_P, unsigned Opcode,
421           bool Commutable = false>
422 struct BinaryOp_match {
423   LHS_P L;
424   RHS_P R;
425 
426   BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {}
427   template <typename OpTy>
428   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
429     MachineInstr *TmpMI;
430     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
431       if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) {
432         return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
433                 R.match(MRI, TmpMI->getOperand(2).getReg())) ||
434                // NOTE: When trying the alternative operand ordering
435                // with a commutative operation, it is imperative to always run
436                // the LHS sub-pattern  (i.e. `L`) before the RHS sub-pattern
437                // (i.e. `R`). Otherwsie, m_DeferredReg/Type will not work as
438                // expected.
439                (Commutable && (L.match(MRI, TmpMI->getOperand(2).getReg()) &&
440                                R.match(MRI, TmpMI->getOperand(1).getReg())));
441       }
442     }
443     return false;
444   }
445 };
446 
447 // Helper for (commutative) binary generic MI that checks Opcode.
448 template <typename LHS_P, typename RHS_P, bool Commutable = false>
449 struct BinaryOpc_match {
450   unsigned Opc;
451   LHS_P L;
452   RHS_P R;
453 
454   BinaryOpc_match(unsigned Opcode, const LHS_P &LHS, const RHS_P &RHS)
455       : Opc(Opcode), L(LHS), R(RHS) {}
456   template <typename OpTy>
457   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
458     MachineInstr *TmpMI;
459     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
460       if (TmpMI->getOpcode() == Opc && TmpMI->getNumDefs() == 1 &&
461           TmpMI->getNumOperands() == 3) {
462         return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
463                 R.match(MRI, TmpMI->getOperand(2).getReg())) ||
464                // NOTE: When trying the alternative operand ordering
465                // with a commutative operation, it is imperative to always run
466                // the LHS sub-pattern  (i.e. `L`) before the RHS sub-pattern
467                // (i.e. `R`). Otherwsie, m_DeferredReg/Type will not work as
468                // expected.
469                (Commutable && (L.match(MRI, TmpMI->getOperand(2).getReg()) &&
470                                R.match(MRI, TmpMI->getOperand(1).getReg())));
471       }
472     }
473     return false;
474   }
475 };
476 
477 template <typename LHS, typename RHS>
478 inline BinaryOpc_match<LHS, RHS, false> m_BinOp(unsigned Opcode, const LHS &L,
479                                                 const RHS &R) {
480   return BinaryOpc_match<LHS, RHS, false>(Opcode, L, R);
481 }
482 
483 template <typename LHS, typename RHS>
484 inline BinaryOpc_match<LHS, RHS, true>
485 m_CommutativeBinOp(unsigned Opcode, const LHS &L, const RHS &R) {
486   return BinaryOpc_match<LHS, RHS, true>(Opcode, L, R);
487 }
488 
489 template <typename LHS, typename RHS>
490 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>
491 m_GAdd(const LHS &L, const RHS &R) {
492   return BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>(L, R);
493 }
494 
495 template <typename LHS, typename RHS>
496 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false>
497 m_GBuildVector(const LHS &L, const RHS &R) {
498   return BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false>(L, R);
499 }
500 
501 template <typename LHS, typename RHS>
502 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false>
503 m_GBuildVectorTrunc(const LHS &L, const RHS &R) {
504   return BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false>(L,
505                                                                              R);
506 }
507 
508 template <typename LHS, typename RHS>
509 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false>
510 m_GPtrAdd(const LHS &L, const RHS &R) {
511   return BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false>(L, R);
512 }
513 
514 template <typename LHS, typename RHS>
515 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB> m_GSub(const LHS &L,
516                                                             const RHS &R) {
517   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB>(L, R);
518 }
519 
520 template <typename LHS, typename RHS>
521 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>
522 m_GMul(const LHS &L, const RHS &R) {
523   return BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>(L, R);
524 }
525 
526 template <typename LHS, typename RHS>
527 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>
528 m_GFAdd(const LHS &L, const RHS &R) {
529   return BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>(L, R);
530 }
531 
532 template <typename LHS, typename RHS>
533 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>
534 m_GFMul(const LHS &L, const RHS &R) {
535   return BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>(L, R);
536 }
537 
538 template <typename LHS, typename RHS>
539 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>
540 m_GFSub(const LHS &L, const RHS &R) {
541   return BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>(L, R);
542 }
543 
544 template <typename LHS, typename RHS>
545 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>
546 m_GAnd(const LHS &L, const RHS &R) {
547   return BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>(L, R);
548 }
549 
550 template <typename LHS, typename RHS>
551 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>
552 m_GXor(const LHS &L, const RHS &R) {
553   return BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>(L, R);
554 }
555 
556 template <typename LHS, typename RHS>
557 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true> m_GOr(const LHS &L,
558                                                                 const RHS &R) {
559   return BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true>(L, R);
560 }
561 
562 template <typename LHS, typename RHS>
563 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>
564 m_GShl(const LHS &L, const RHS &R) {
565   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>(L, R);
566 }
567 
568 template <typename LHS, typename RHS>
569 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>
570 m_GLShr(const LHS &L, const RHS &R) {
571   return BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>(L, R);
572 }
573 
574 template <typename LHS, typename RHS>
575 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>
576 m_GAShr(const LHS &L, const RHS &R) {
577   return BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>(L, R);
578 }
579 
580 template <typename LHS, typename RHS>
581 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, true>
582 m_GSMax(const LHS &L, const RHS &R) {
583   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, true>(L, R);
584 }
585 
586 template <typename LHS, typename RHS>
587 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, true>
588 m_GSMin(const LHS &L, const RHS &R) {
589   return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, true>(L, R);
590 }
591 
592 template <typename LHS, typename RHS>
593 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_UMAX, true>
594 m_GUMax(const LHS &L, const RHS &R) {
595   return BinaryOp_match<LHS, RHS, TargetOpcode::G_UMAX, true>(L, R);
596 }
597 
598 template <typename LHS, typename RHS>
599 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_UMIN, true>
600 m_GUMin(const LHS &L, const RHS &R) {
601   return BinaryOp_match<LHS, RHS, TargetOpcode::G_UMIN, true>(L, R);
602 }
603 
604 // Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc
605 template <typename SrcTy, unsigned Opcode> struct UnaryOp_match {
606   SrcTy L;
607 
608   UnaryOp_match(const SrcTy &LHS) : L(LHS) {}
609   template <typename OpTy>
610   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
611     MachineInstr *TmpMI;
612     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
613       if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) {
614         return L.match(MRI, TmpMI->getOperand(1).getReg());
615       }
616     }
617     return false;
618   }
619 };
620 
621 template <typename SrcTy>
622 inline UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>
623 m_GAnyExt(const SrcTy &Src) {
624   return UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>(Src);
625 }
626 
627 template <typename SrcTy>
628 inline UnaryOp_match<SrcTy, TargetOpcode::G_SEXT> m_GSExt(const SrcTy &Src) {
629   return UnaryOp_match<SrcTy, TargetOpcode::G_SEXT>(Src);
630 }
631 
632 template <typename SrcTy>
633 inline UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT> m_GZExt(const SrcTy &Src) {
634   return UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT>(Src);
635 }
636 
637 template <typename SrcTy>
638 inline UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT> m_GFPExt(const SrcTy &Src) {
639   return UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT>(Src);
640 }
641 
642 template <typename SrcTy>
643 inline UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC> m_GTrunc(const SrcTy &Src) {
644   return UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC>(Src);
645 }
646 
647 template <typename SrcTy>
648 inline UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>
649 m_GBitcast(const SrcTy &Src) {
650   return UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>(Src);
651 }
652 
653 template <typename SrcTy>
654 inline UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>
655 m_GPtrToInt(const SrcTy &Src) {
656   return UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>(Src);
657 }
658 
659 template <typename SrcTy>
660 inline UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>
661 m_GIntToPtr(const SrcTy &Src) {
662   return UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>(Src);
663 }
664 
665 template <typename SrcTy>
666 inline UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>
667 m_GFPTrunc(const SrcTy &Src) {
668   return UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>(Src);
669 }
670 
671 template <typename SrcTy>
672 inline UnaryOp_match<SrcTy, TargetOpcode::G_FABS> m_GFabs(const SrcTy &Src) {
673   return UnaryOp_match<SrcTy, TargetOpcode::G_FABS>(Src);
674 }
675 
676 template <typename SrcTy>
677 inline UnaryOp_match<SrcTy, TargetOpcode::G_FNEG> m_GFNeg(const SrcTy &Src) {
678   return UnaryOp_match<SrcTy, TargetOpcode::G_FNEG>(Src);
679 }
680 
681 template <typename SrcTy>
682 inline UnaryOp_match<SrcTy, TargetOpcode::COPY> m_Copy(SrcTy &&Src) {
683   return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src));
684 }
685 
686 template <typename SrcTy>
687 inline UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT> m_GFSqrt(const SrcTy &Src) {
688   return UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT>(Src);
689 }
690 
691 // General helper for generic MI compares, i.e. G_ICMP and G_FCMP
692 // TODO: Allow checking a specific predicate.
693 template <typename Pred_P, typename LHS_P, typename RHS_P, unsigned Opcode,
694           bool Commutable = false>
695 struct CompareOp_match {
696   Pred_P P;
697   LHS_P L;
698   RHS_P R;
699 
700   CompareOp_match(const Pred_P &Pred, const LHS_P &LHS, const RHS_P &RHS)
701       : P(Pred), L(LHS), R(RHS) {}
702 
703   template <typename OpTy>
704   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
705     MachineInstr *TmpMI;
706     if (!mi_match(Op, MRI, m_MInstr(TmpMI)) || TmpMI->getOpcode() != Opcode)
707       return false;
708 
709     auto TmpPred =
710         static_cast<CmpInst::Predicate>(TmpMI->getOperand(1).getPredicate());
711     if (!P.match(MRI, TmpPred))
712       return false;
713     Register LHS = TmpMI->getOperand(2).getReg();
714     Register RHS = TmpMI->getOperand(3).getReg();
715     if (L.match(MRI, LHS) && R.match(MRI, RHS))
716       return true;
717     // NOTE: When trying the alternative operand ordering
718     // with a commutative operation, it is imperative to always run
719     // the LHS sub-pattern  (i.e. `L`) before the RHS sub-pattern
720     // (i.e. `R`). Otherwsie, m_DeferredReg/Type will not work as expected.
721     if (Commutable && L.match(MRI, RHS) && R.match(MRI, LHS) &&
722         P.match(MRI, CmpInst::getSwappedPredicate(TmpPred)))
723       return true;
724     return false;
725   }
726 };
727 
728 template <typename Pred, typename LHS, typename RHS>
729 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>
730 m_GICmp(const Pred &P, const LHS &L, const RHS &R) {
731   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>(P, L, R);
732 }
733 
734 template <typename Pred, typename LHS, typename RHS>
735 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>
736 m_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
737   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>(P, L, R);
738 }
739 
740 /// G_ICMP matcher that also matches commuted compares.
741 /// E.g.
742 ///
743 /// m_c_GICmp(m_Pred(...), m_GAdd(...), m_GSub(...))
744 ///
745 /// Could match both of:
746 ///
747 /// icmp ugt (add x, y) (sub a, b)
748 /// icmp ult (sub a, b) (add x, y)
749 template <typename Pred, typename LHS, typename RHS>
750 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP, true>
751 m_c_GICmp(const Pred &P, const LHS &L, const RHS &R) {
752   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP, true>(P, L, R);
753 }
754 
755 /// G_FCMP matcher that also matches commuted compares.
756 /// E.g.
757 ///
758 /// m_c_GFCmp(m_Pred(...), m_FAdd(...), m_GFMul(...))
759 ///
760 /// Could match both of:
761 ///
762 /// fcmp ogt (fadd x, y) (fmul a, b)
763 /// fcmp olt (fmul a, b) (fadd x, y)
764 template <typename Pred, typename LHS, typename RHS>
765 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP, true>
766 m_c_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
767   return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP, true>(P, L, R);
768 }
769 
770 // Helper for checking if a Reg is of specific type.
771 struct CheckType {
772   LLT Ty;
773   CheckType(const LLT Ty) : Ty(Ty) {}
774 
775   bool match(const MachineRegisterInfo &MRI, Register Reg) {
776     return MRI.getType(Reg) == Ty;
777   }
778 };
779 
780 inline CheckType m_SpecificType(LLT Ty) { return Ty; }
781 
782 template <typename Src0Ty, typename Src1Ty, typename Src2Ty, unsigned Opcode>
783 struct TernaryOp_match {
784   Src0Ty Src0;
785   Src1Ty Src1;
786   Src2Ty Src2;
787 
788   TernaryOp_match(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
789       : Src0(Src0), Src1(Src1), Src2(Src2) {}
790   template <typename OpTy>
791   bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
792     MachineInstr *TmpMI;
793     if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
794       if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 4) {
795         return (Src0.match(MRI, TmpMI->getOperand(1).getReg()) &&
796                 Src1.match(MRI, TmpMI->getOperand(2).getReg()) &&
797                 Src2.match(MRI, TmpMI->getOperand(3).getReg()));
798       }
799     }
800     return false;
801   }
802 };
803 template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
804 inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
805                        TargetOpcode::G_INSERT_VECTOR_ELT>
806 m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
807   return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
808                          TargetOpcode::G_INSERT_VECTOR_ELT>(Src0, Src1, Src2);
809 }
810 
811 template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
812 inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>
813 m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
814   return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>(
815       Src0, Src1, Src2);
816 }
817 
818 /// Matches a register negated by a G_SUB.
819 /// G_SUB 0, %negated_reg
820 template <typename SrcTy>
821 inline BinaryOp_match<SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB>
822 m_Neg(const SrcTy &&Src) {
823   return m_GSub(m_ZeroInt(), Src);
824 }
825 
826 /// Matches a register not-ed by a G_XOR.
827 /// G_XOR %not_reg, -1
828 template <typename SrcTy>
829 inline BinaryOp_match<SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true>
830 m_Not(const SrcTy &&Src) {
831   return m_GXor(Src, m_AllOnesInt());
832 }
833 
834 } // namespace MIPatternMatch
835 } // namespace llvm
836 
837 #endif
838