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