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>
mi_match(Reg R,const MachineRegisterInfo & MRI,Pattern && P)25 bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P) {
26 return P.match(MRI, R);
27 }
28
29 template <typename Pattern>
mi_match(MachineInstr & MI,const MachineRegisterInfo & MRI,Pattern && P)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;
OneUse_matchOneUse_match37 OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
38
matchOneUse_match39 bool match(const MachineRegisterInfo &MRI, Register Reg) {
40 return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
41 }
42 };
43
44 template <typename SubPat>
m_OneUse(const SubPat & SP)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;
OneNonDBGUse_matchOneNonDBGUse_match51 OneNonDBGUse_match(const SubPatternT &SP) : SubPat(SP) {}
52
matchOneNonDBGUse_match53 bool match(const MachineRegisterInfo &MRI, Register Reg) {
54 return MRI.hasOneNonDBGUse(Reg) && SubPat.match(MRI, Reg);
55 }
56 };
57
58 template <typename SubPat>
m_OneNonDBGUse(const SubPat & SP)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 <>
matchConstant(Register Reg,const MachineRegisterInfo & MRI)67 inline Optional<APInt> matchConstant(Register Reg,
68 const MachineRegisterInfo &MRI) {
69 return getIConstantVRegVal(Reg, MRI);
70 }
71
72 template <>
matchConstant(Register Reg,const MachineRegisterInfo & MRI)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;
ConstantMatchConstantMatch80 ConstantMatch(ConstT &C) : CR(C) {}
matchConstantMatch81 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
m_ICst(APInt & Cst)90 inline ConstantMatch<APInt> m_ICst(APInt &Cst) {
91 return ConstantMatch<APInt>(Cst);
92 }
m_ICst(int64_t & Cst)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 <>
matchConstantSplat(Register Reg,const MachineRegisterInfo & MRI)102 inline Optional<APInt> matchConstantSplat(Register Reg,
103 const MachineRegisterInfo &MRI) {
104 return getIConstantSplatVal(Reg, MRI);
105 }
106
107 template <>
matchConstantSplat(Register Reg,const MachineRegisterInfo & MRI)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;
ICstOrSplatMatchICstOrSplatMatch115 ICstOrSplatMatch(ConstT &C) : CR(C) {}
matchICstOrSplatMatch116 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
m_ICstOrSplat(APInt & Cst)131 inline ICstOrSplatMatch<APInt> m_ICstOrSplat(APInt &Cst) {
132 return ICstOrSplatMatch<APInt>(Cst);
133 }
134
m_ICstOrSplat(int64_t & Cst)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;
GCstAndRegMatchGCstAndRegMatch141 GCstAndRegMatch(Optional<ValueAndVReg> &ValReg) : ValReg(ValReg) {}
matchGCstAndRegMatch142 bool match(const MachineRegisterInfo &MRI, Register Reg) {
143 ValReg = getIConstantVRegValWithLookThrough(Reg, MRI);
144 return ValReg ? true : false;
145 }
146 };
147
m_GCst(Optional<ValueAndVReg> & ValReg)148 inline GCstAndRegMatch m_GCst(Optional<ValueAndVReg> &ValReg) {
149 return GCstAndRegMatch(ValReg);
150 }
151
152 struct GFCstAndRegMatch {
153 Optional<FPValueAndVReg> &FPValReg;
GFCstAndRegMatchGFCstAndRegMatch154 GFCstAndRegMatch(Optional<FPValueAndVReg> &FPValReg) : FPValReg(FPValReg) {}
matchGFCstAndRegMatch155 bool match(const MachineRegisterInfo &MRI, Register Reg) {
156 FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI);
157 return FPValReg ? true : false;
158 }
159 };
160
m_GFCst(Optional<FPValueAndVReg> & FPValReg)161 inline GFCstAndRegMatch m_GFCst(Optional<FPValueAndVReg> &FPValReg) {
162 return GFCstAndRegMatch(FPValReg);
163 }
164
165 struct GFCstOrSplatGFCstMatch {
166 Optional<FPValueAndVReg> &FPValReg;
GFCstOrSplatGFCstMatchGFCstOrSplatGFCstMatch167 GFCstOrSplatGFCstMatch(Optional<FPValueAndVReg> &FPValReg)
168 : FPValReg(FPValReg) {}
matchGFCstOrSplatGFCstMatch169 bool match(const MachineRegisterInfo &MRI, Register Reg) {
170 return (FPValReg = getFConstantSplat(Reg, MRI)) ||
171 (FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI));
172 };
173 };
174
175 inline GFCstOrSplatGFCstMatch
m_GFCstOrSplat(Optional<FPValueAndVReg> & FPValReg)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;
SpecificConstantMatchSpecificConstantMatch183 SpecificConstantMatch(int64_t RequestedVal) : RequestedVal(RequestedVal) {}
matchSpecificConstantMatch184 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.
m_SpecificICst(int64_t 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;
SpecificConstantSplatMatchSpecificConstantSplatMatch198 SpecificConstantSplatMatch(int64_t RequestedVal)
199 : RequestedVal(RequestedVal) {}
matchSpecificConstantSplatMatch200 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.
m_SpecificICstSplat(int64_t 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;
SpecificConstantOrSplatMatchSpecificConstantOrSplatMatch214 SpecificConstantOrSplatMatch(int64_t RequestedVal)
215 : RequestedVal(RequestedVal) {}
matchSpecificConstantOrSplatMatch216 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
m_SpecificICstOrSplat(int64_t RequestedValue)228 m_SpecificICstOrSplat(int64_t RequestedValue) {
229 return SpecificConstantOrSplatMatch(RequestedValue);
230 }
231
232 ///{
233 /// Convenience matchers for specific integer values.
m_ZeroInt()234 inline SpecificConstantMatch m_ZeroInt() { return SpecificConstantMatch(0); }
m_AllOnesInt()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 {
matchoperand_type_match246 bool match(const MachineRegisterInfo &MRI, Register Reg) { return true; }
matchoperand_type_match247 bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) {
248 return MO->isReg();
249 }
250 };
251
m_Reg()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>
matchAnd257 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