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