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

source code of llvm/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h