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