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