LLVM 24.0.0git
MIPatternMatch.h
Go to the documentation of this file.
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"
22#include "llvm/IR/InstrTypes.h"
23
24namespace llvm {
25namespace MIPatternMatch {
26
27template <typename Reg, typename Pattern>
28[[nodiscard]] bool mi_match(Reg R, const MachineRegisterInfo &MRI,
29 Pattern &&P) {
30 return P.match(MRI, R);
31}
32
33template <typename Pattern>
34[[nodiscard]] bool mi_match(MachineInstr &MI, const MachineRegisterInfo &MRI,
35 Pattern &&P) {
36 return P.match(MRI, &MI);
37}
38
39template <typename Pattern>
40[[nodiscard]] bool mi_match(const MachineInstr &MI,
41 const MachineRegisterInfo &MRI, Pattern &&P) {
42 return P.match(MRI, &MI);
43}
44
45// TODO: Extend for N use.
46template <typename SubPatternT> struct OneUse_match {
47 SubPatternT SubPat;
48 OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
49
51 return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
52 }
53};
54
55template <typename SubPat>
56inline OneUse_match<SubPat> m_OneUse(const SubPat &SP) {
57 return SP;
58}
59
60template <typename SubPatternT> struct OneNonDBGUse_match {
61 SubPatternT SubPat;
62 OneNonDBGUse_match(const SubPatternT &SP) : SubPat(SP) {}
63
65 return MRI.hasOneNonDBGUse(Reg) && SubPat.match(MRI, Reg);
66 }
67};
68
69template <typename SubPat>
71 return SP;
72}
73
74template <typename ConstT>
75inline std::optional<ConstT> matchConstant(Register,
76 const MachineRegisterInfo &);
77
78template <>
79inline std::optional<APInt> matchConstant(Register Reg,
80 const MachineRegisterInfo &MRI) {
81 return getIConstantVRegVal(Reg, MRI);
82}
83
84template <>
85inline std::optional<int64_t> matchConstant(Register Reg,
86 const MachineRegisterInfo &MRI) {
87 return getIConstantVRegSExtVal(Reg, MRI);
88}
89
90template <typename ConstT> struct ConstantMatch {
91 ConstT &CR;
92 ConstantMatch(ConstT &C) : CR(C) {}
94 if (auto MaybeCst = matchConstant<ConstT>(Reg, MRI)) {
95 CR = *MaybeCst;
96 return true;
97 }
98 return false;
99 }
100};
101
103 return ConstantMatch<APInt>(Cst);
104}
105inline ConstantMatch<int64_t> m_ICst(int64_t &Cst) {
106 return ConstantMatch<int64_t>(Cst);
107}
108
109template <typename ConstT>
110inline std::optional<ConstT> matchConstantSplat(Register,
111 const MachineRegisterInfo &);
112
113template <>
114inline std::optional<APInt> matchConstantSplat(Register Reg,
115 const MachineRegisterInfo &MRI) {
116 return getIConstantSplatVal(Reg, MRI);
117}
118
119template <>
120inline std::optional<int64_t>
124
125template <typename ConstT> struct ICstOrSplatMatch {
126 ConstT &CR;
127 ICstOrSplatMatch(ConstT &C) : CR(C) {}
129 if (auto MaybeCst = matchConstant<ConstT>(Reg, MRI)) {
130 CR = *MaybeCst;
131 return true;
132 }
133
134 if (auto MaybeCstSplat = matchConstantSplat<ConstT>(Reg, MRI)) {
135 CR = *MaybeCstSplat;
136 return true;
137 }
138
139 return false;
140 };
141};
142
146
148 return ICstOrSplatMatch<int64_t>(Cst);
149}
150
152 std::optional<ValueAndVReg> &ValReg;
153 GCstAndRegMatch(std::optional<ValueAndVReg> &ValReg) : ValReg(ValReg) {}
156 return ValReg ? true : false;
157 }
158};
159
160inline GCstAndRegMatch m_GCst(std::optional<ValueAndVReg> &ValReg) {
161 return GCstAndRegMatch(ValReg);
162}
163
165 std::optional<FPValueAndVReg> &FPValReg;
166 GFCstAndRegMatch(std::optional<FPValueAndVReg> &FPValReg)
167 : FPValReg(FPValReg) {}
170 return FPValReg ? true : false;
171 }
172};
173
174inline GFCstAndRegMatch m_GFCst(std::optional<FPValueAndVReg> &FPValReg) {
175 return GFCstAndRegMatch(FPValReg);
176}
177
179 std::optional<FPValueAndVReg> &FPValReg;
180 GFCstOrSplatGFCstMatch(std::optional<FPValueAndVReg> &FPValReg)
181 : FPValReg(FPValReg) {}
183 return (FPValReg = getFConstantSplat(Reg, MRI)) ||
185 };
186};
187
189m_GFCstOrSplat(std::optional<FPValueAndVReg> &FPValReg) {
190 return GFCstOrSplatGFCstMatch(FPValReg);
191}
192
193/// Matcher for a specific constant value.
199 APInt MatchedVal;
200 if (mi_match(Reg, MRI, m_ICst(MatchedVal))) {
201 if (MatchedVal.getBitWidth() > RequestedVal.getBitWidth())
202 RequestedVal = RequestedVal.sext(MatchedVal.getBitWidth());
203 else
204 MatchedVal = MatchedVal.sext(RequestedVal.getBitWidth());
205
206 return APInt::isSameValue(MatchedVal, RequestedVal);
207 }
208 return false;
209 }
210};
211
212/// Matches a constant equal to \p RequestedValue.
213inline SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue) {
214 return SpecificConstantMatch(RequestedValue);
215}
216
217inline SpecificConstantMatch m_SpecificICst(int64_t RequestedValue) {
218 return SpecificConstantMatch(APInt(64, RequestedValue, /* isSigned */ true));
219}
220
221/// Matcher for a specific constant splat.
231
232/// Matches a constant splat of \p RequestedValue.
234m_SpecificICstSplat(const APInt &RequestedValue) {
235 return SpecificConstantSplatMatch(RequestedValue);
236}
237
238inline SpecificConstantSplatMatch m_SpecificICstSplat(int64_t RequestedValue) {
240 APInt(64, RequestedValue, /* isSigned */ true));
241}
242
243/// Matcher for a specific constant or constant splat.
249 APInt MatchedVal;
250 if (mi_match(Reg, MRI, m_ICst(MatchedVal))) {
251 if (MatchedVal.getBitWidth() > RequestedVal.getBitWidth())
252 RequestedVal = RequestedVal.sext(MatchedVal.getBitWidth());
253 else
254 MatchedVal = MatchedVal.sext(RequestedVal.getBitWidth());
255
256 if (APInt::isSameValue(MatchedVal, RequestedVal))
257 return true;
258 }
260 /* AllowUndef */ false);
261 }
262};
263
264/// Matches a \p RequestedValue constant or a constant splat of \p
265/// RequestedValue.
267m_SpecificICstOrSplat(const APInt &RequestedValue) {
268 return SpecificConstantOrSplatMatch(RequestedValue);
269}
270
272m_SpecificICstOrSplat(int64_t RequestedValue) {
274 APInt(64, RequestedValue, /* isSigned */ true));
275}
276
277/// Convenience matchers for specific integer values.
284
285/// Matcher for a specific register.
293
294/// Matches a register only if it is equal to \p RequestedReg.
296 return SpecificRegisterMatch(RequestedReg);
297}
298
299// TODO: Rework this for different kinds of MachineOperand.
300// Currently assumes the Src for a match is a register.
301// We might want to support taking in some MachineOperands and call getReg on
302// that.
303
305 bool match(const MachineRegisterInfo &MRI, Register Reg) { return true; }
307 return MO->isReg();
308 }
309};
310
312
313/// Matching combinators.
314template <typename... Preds> struct And {
315 template <typename MatchSrc>
316 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
317 return true;
318 }
319};
320
321template <typename Pred, typename... Preds>
322struct And<Pred, Preds...> : And<Preds...> {
323 Pred P;
324 And(Pred &&p, Preds &&... preds)
325 : And<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {
326 }
327 template <typename MatchSrc>
328 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
329 return P.match(MRI, src) && And<Preds...>::match(MRI, src);
330 }
331};
332
333template <typename... Preds> struct Or {
334 template <typename MatchSrc>
335 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
336 return false;
337 }
338};
339
340template <typename Pred, typename... Preds>
341struct Or<Pred, Preds...> : Or<Preds...> {
342 Pred P;
343 Or(Pred &&p, Preds &&... preds)
344 : Or<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {}
345 template <typename MatchSrc>
346 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
347 return P.match(MRI, src) || Or<Preds...>::match(MRI, src);
348 }
349};
350
351template <typename... Preds> And<Preds...> m_all_of(Preds &&... preds) {
352 return And<Preds...>(std::forward<Preds>(preds)...);
353}
354
355template <typename... Preds> Or<Preds...> m_any_of(Preds &&... preds) {
356 return Or<Preds...>(std::forward<Preds>(preds)...);
357}
358
359template <typename BindTy> struct bind_helper {
360 static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
361 VR = V;
362 return true;
363 }
364};
365
366template <> struct bind_helper<MachineInstr *> {
367 static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
368 Register Reg) {
369 MI = MRI.getVRegDef(Reg);
370 if (MI)
371 return true;
372 return false;
373 }
374 static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
375 MachineInstr *Inst) {
376 MI = Inst;
377 return MI;
378 }
379};
380
381template <> struct bind_helper<const MachineInstr *> {
382 static bool bind(const MachineRegisterInfo &MRI, const MachineInstr *&MI,
383 Register Reg) {
384 MI = MRI.getVRegDef(Reg);
385 return MI;
386 }
387 static bool bind(const MachineRegisterInfo &MRI, const MachineInstr *&MI,
388 const MachineInstr *Inst) {
389 MI = Inst;
390 return MI;
391 }
392};
393
394template <> struct bind_helper<LLT> {
395 static bool bind(const MachineRegisterInfo &MRI, LLT &Ty, Register Reg) {
396 Ty = MRI.getType(Reg);
397 if (Ty.isValid())
398 return true;
399 return false;
400 }
401};
402
403template <> struct bind_helper<const ConstantFP *> {
404 static bool bind(const MachineRegisterInfo &MRI, const ConstantFP *&F,
405 Register Reg) {
406 F = getConstantFPVRegVal(Reg, MRI);
407 if (F)
408 return true;
409 return false;
410 }
411};
412
413template <typename Class> struct bind_ty {
414 Class &VR;
415
416 bind_ty(Class &V) : VR(V) {}
417
418 template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) {
419 return bind_helper<Class>::bind(MRI, VR, V);
420 }
421};
422
423inline bind_ty<Register> m_Reg(Register &R) { return R; }
426 return MI;
427}
428inline bind_ty<LLT> m_Type(LLT &Ty) { return Ty; }
432
433/// Wraps a MIFlags output for use as an optional trailing operand of an
434/// instruction matcher (e.g. m_GPtrAdd(L, R, m_MIFlags(Flags))). On a
435/// successful match the matched instruction's flags are written to \p Flags.
439
440inline MIFlagsRef m_MIFlags(uint32_t &Flags) { return {Flags}; }
441
442template <typename BindTy> struct deferred_helper {
443 static bool match(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
444 return VR == V;
445 }
446};
447
448template <> struct deferred_helper<LLT> {
449 static bool match(const MachineRegisterInfo &MRI, LLT VT, Register R) {
450 return VT == MRI.getType(R);
451 }
452};
453
454template <typename Class> struct deferred_ty {
455 Class &VR;
456
457 deferred_ty(Class &V) : VR(V) {}
458
459 template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) {
460 return deferred_helper<Class>::match(MRI, VR, V);
461 }
462};
463
464/// Similar to m_SpecificReg/Type, but the specific value to match originated
465/// from an earlier sub-pattern in the same mi_match expression. For example,
466/// we cannot match `(add X, X)` with `m_GAdd(m_Reg(X), m_SpecificReg(X))`
467/// because `X` is not initialized at the time it's passed to `m_SpecificReg`.
468/// Instead, we can use `m_GAdd(m_Reg(x), m_DeferredReg(X))`.
470inline deferred_ty<LLT> m_DeferredType(LLT &Ty) { return Ty; }
471
474 MachineInstr *TmpMI;
475 if (mi_match(Reg, MRI, m_MInstr(TmpMI)))
476 return TmpMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF;
477 return false;
478 }
479};
480
482
483/// Matches a G_CONSTANT and binds the defining instruction. Unlike m_ICst, this
484/// returns the instruction (not the value) and does not look through vector
485/// splats.
486template <typename Class> struct GConstantMatch {
487 Class *&Inst;
488
491 MachineInstr *TmpMI;
492 if (mi_match(Reg, MRI, m_MInstr(TmpMI))) {
493 if (auto *Cst = dyn_cast<Class>(TmpMI)) {
494 Inst = Cst;
495 return true;
496 }
497 }
498 return false;
499 }
500};
501
502inline GConstantMatch<GConstant> m_GConstant(GConstant *&Inst) { return Inst; }
504 return Inst;
505}
506
507// Helper for matching G_FCONSTANT
509
510// General helper for all the binary generic MI such as G_ADD/G_SUB etc
511template <typename LHS_P, typename RHS_P, unsigned Opcode,
512 bool Commutable = false, unsigned Flags = MachineInstr::NoFlags>
514 LHS_P L;
515 RHS_P R;
516 // Optional output: when set, receives the matched instruction's flags.
517 uint32_t *FlagsOut = nullptr;
518
519 BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {}
520 BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS, MIFlagsRef FlagsOut)
521 : L(LHS), R(RHS), FlagsOut(&FlagsOut.Flags) {}
522 template <typename OpTy>
523 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
524 const MachineInstr *TmpMI;
525 if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
526 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) {
527 if ((!L.match(MRI, TmpMI->getOperand(1).getReg()) ||
528 !R.match(MRI, TmpMI->getOperand(2).getReg())) &&
529 // NOTE: When trying the alternative operand ordering
530 // with a commutative operation, it is imperative to always run
531 // the LHS sub-pattern (i.e. `L`) before the RHS sub-pattern
532 // (i.e. `R`). Otherwise, m_DeferredReg/Type will not work as
533 // expected.
534 (!Commutable || !L.match(MRI, TmpMI->getOperand(2).getReg()) ||
535 !R.match(MRI, TmpMI->getOperand(1).getReg())))
536 return false;
537 if ((TmpMI->getFlags() & Flags) != Flags)
538 return false;
539 if (FlagsOut)
540 *FlagsOut = TmpMI->getFlags();
541 return true;
542 }
543 }
544 return false;
545 }
546};
547
548// Helper for (commutative) binary generic MI that checks Opcode.
549template <typename LHS_P, typename RHS_P, bool Commutable = false>
551 unsigned Opc;
552 LHS_P L;
553 RHS_P R;
554
555 BinaryOpc_match(unsigned Opcode, const LHS_P &LHS, const RHS_P &RHS)
556 : Opc(Opcode), L(LHS), R(RHS) {}
557 template <typename OpTy>
558 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
559 MachineInstr *TmpMI;
560 if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
561 if (TmpMI->getOpcode() == Opc && TmpMI->getNumDefs() == 1 &&
562 TmpMI->getNumOperands() == 3) {
563 return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
564 R.match(MRI, TmpMI->getOperand(2).getReg())) ||
565 // NOTE: When trying the alternative operand ordering
566 // with a commutative operation, it is imperative to always run
567 // the LHS sub-pattern (i.e. `L`) before the RHS sub-pattern
568 // (i.e. `R`). Otherwise, m_DeferredReg/Type will not work as
569 // expected.
570 (Commutable && (L.match(MRI, TmpMI->getOperand(2).getReg()) &&
571 R.match(MRI, TmpMI->getOperand(1).getReg())));
572 }
573 }
574 return false;
575 }
576};
577
578template <typename LHS, typename RHS>
579inline BinaryOpc_match<LHS, RHS, false> m_BinOp(unsigned Opcode, const LHS &L,
580 const RHS &R) {
581 return BinaryOpc_match<LHS, RHS, false>(Opcode, L, R);
582}
583
584template <typename LHS, typename RHS>
586m_CommutativeBinOp(unsigned Opcode, const LHS &L, const RHS &R) {
587 return BinaryOpc_match<LHS, RHS, true>(Opcode, L, R);
588}
589
590template <typename LHS, typename RHS>
592m_GAdd(const LHS &L, const RHS &R) {
594}
595
596template <typename LHS, typename RHS>
601
602template <typename LHS, typename RHS>
608
609template <typename LHS, typename RHS>
614
615template <typename LHS, typename RHS>
617m_GPtrAdd(const LHS &L, const RHS &R, MIFlagsRef Flags) {
619}
620
621template <typename LHS, typename RHS>
626
627template <typename LHS, typename RHS>
629m_GMul(const LHS &L, const RHS &R) {
631}
632
633template <typename LHS, typename RHS>
635m_GFAdd(const LHS &L, const RHS &R) {
637}
638
639template <typename LHS, typename RHS>
641m_GFMul(const LHS &L, const RHS &R) {
643}
644
645template <typename LHS, typename RHS>
647m_GFSub(const LHS &L, const RHS &R) {
649}
650
651template <typename LHS, typename RHS>
653m_GAnd(const LHS &L, const RHS &R) {
655}
656
657template <typename LHS, typename RHS>
659m_GXor(const LHS &L, const RHS &R) {
661}
662
663template <typename LHS, typename RHS>
668
669template <typename LHS, typename RHS>
670inline BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true,
672m_GDisjointOr(const LHS &L, const RHS &R) {
673 return BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true,
675}
676
677template <typename LHS, typename RHS>
678inline auto m_GAddLike(const LHS &L, const RHS &R) {
679 return m_any_of(m_GAdd(L, R), m_GDisjointOr(L, R));
680}
681
682template <typename LHS, typename RHS>
684m_GShl(const LHS &L, const RHS &R) {
686}
687
688template <typename LHS, typename RHS>
690m_GLShr(const LHS &L, const RHS &R) {
692}
693
694template <typename LHS, typename RHS>
696m_GAShr(const LHS &L, const RHS &R) {
698}
699
700template <typename LHS, typename RHS>
702m_GSMax(const LHS &L, const RHS &R) {
704}
705
706template <typename LHS, typename RHS>
708m_GSMin(const LHS &L, const RHS &R) {
710}
711
712template <typename LHS, typename RHS>
714m_GUMax(const LHS &L, const RHS &R) {
716}
717
718template <typename LHS, typename RHS>
720m_GUMin(const LHS &L, const RHS &R) {
722}
723
724// Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc
725template <typename SrcTy, unsigned Opcode> struct UnaryOp_match {
726 SrcTy L;
727
728 UnaryOp_match(const SrcTy &LHS) : L(LHS) {}
729 template <typename OpTy>
730 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
731 MachineInstr *TmpMI;
732 if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
733 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) {
734 return L.match(MRI, TmpMI->getOperand(1).getReg());
735 }
736 }
737 return false;
738 }
739};
740
741template <typename SrcTy>
743m_GAnyExt(const SrcTy &Src) {
745}
746
747template <typename SrcTy>
751
752template <typename SrcTy>
756
757template <typename SrcTy>
761
762template <typename SrcTy>
766
767template <typename SrcTy>
769m_GBitcast(const SrcTy &Src) {
771}
772
773template <typename SrcTy>
775m_GPtrToInt(const SrcTy &Src) {
777}
778
779template <typename SrcTy>
781m_GIntToPtr(const SrcTy &Src) {
783}
784
785template <typename SrcTy>
787m_GFPTrunc(const SrcTy &Src) {
789}
790
791/// Matches a G_SEXT_INREG, binding its source operand. G_SEXT_INREG has an
792/// extra immediate operand, so it does not fit the plain UnaryOp_match shape.
793template <typename SrcTy> struct SExtInRegMatch {
794 SrcTy L;
795
796 SExtInRegMatch(const SrcTy &LHS) : L(LHS) {}
797 template <typename OpTy>
798 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
799 MachineInstr *TmpMI;
800 if (mi_match(Op, MRI, m_MInstr(TmpMI)) &&
801 TmpMI->getOpcode() == TargetOpcode::G_SEXT_INREG)
802 return L.match(MRI, TmpMI->getOperand(1).getReg());
803 return false;
804 }
805};
806
807template <typename SrcTy>
808inline SExtInRegMatch<SrcTy> m_GSExtInReg(const SrcTy &Src) {
809 return SExtInRegMatch<SrcTy>(Src);
810}
811
812template <typename SrcTy>
816
817template <typename SrcTy>
821
822template <typename SrcTy>
824 return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src));
825}
826
827template <typename SrcTy>
831
832template <typename SrcTy>
834m_GFFloor(const SrcTy &Src) {
836}
837
838// General helper for generic MI compares, i.e. G_ICMP and G_FCMP
839// TODO: Allow checking a specific predicate.
840template <typename Pred_P, typename LHS_P, typename RHS_P, unsigned Opcode,
841 bool Commutable = false>
843 Pred_P P;
844 LHS_P L;
845 RHS_P R;
846
847 CompareOp_match(const Pred_P &Pred, const LHS_P &LHS, const RHS_P &RHS)
848 : P(Pred), L(LHS), R(RHS) {}
849
850 template <typename OpTy>
851 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
852 MachineInstr *TmpMI;
853 if (!mi_match(Op, MRI, m_MInstr(TmpMI)) || TmpMI->getOpcode() != Opcode)
854 return false;
855
856 auto TmpPred =
857 static_cast<CmpInst::Predicate>(TmpMI->getOperand(1).getPredicate());
858 if (!P.match(MRI, TmpPred))
859 return false;
860 Register LHS = TmpMI->getOperand(2).getReg();
861 Register RHS = TmpMI->getOperand(3).getReg();
862 if (L.match(MRI, LHS) && R.match(MRI, RHS))
863 return true;
864 // NOTE: When trying the alternative operand ordering
865 // with a commutative operation, it is imperative to always run
866 // the LHS sub-pattern (i.e. `L`) before the RHS sub-pattern
867 // (i.e. `R`). Otherwise, m_DeferredReg/Type will not work as expected.
868 if (Commutable && L.match(MRI, RHS) && R.match(MRI, LHS) &&
869 P.match(MRI, CmpInst::getSwappedPredicate(TmpPred)))
870 return true;
871 return false;
872 }
873};
874
875template <typename LHS_P, typename Test_P, unsigned Opcode>
877 LHS_P L;
878 Test_P T;
879
880 ClassifyOp_match(const LHS_P &LHS, const Test_P &Tst) : L(LHS), T(Tst) {}
881
882 template <typename OpTy>
883 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
884 MachineInstr *TmpMI;
885 if (!mi_match(Op, MRI, m_MInstr(TmpMI)) || TmpMI->getOpcode() != Opcode)
886 return false;
887
888 Register LHS = TmpMI->getOperand(1).getReg();
889 if (!L.match(MRI, LHS))
890 return false;
891
892 FPClassTest TmpClass =
893 static_cast<FPClassTest>(TmpMI->getOperand(2).getImm());
894 if (T.match(MRI, TmpClass))
895 return true;
896
897 return false;
898 }
899};
900
901template <typename Pred, typename LHS, typename RHS>
903m_GICmp(const Pred &P, const LHS &L, const RHS &R) {
905}
906
907template <typename Pred, typename LHS, typename RHS>
909m_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
911}
912
913/// G_ICMP matcher that also matches commuted compares.
914/// E.g.
915///
916/// m_c_GICmp(m_Pred(...), m_GAdd(...), m_GSub(...))
917///
918/// Could match both of:
919///
920/// icmp ugt (add x, y) (sub a, b)
921/// icmp ult (sub a, b) (add x, y)
922template <typename Pred, typename LHS, typename RHS>
924m_c_GICmp(const Pred &P, const LHS &L, const RHS &R) {
926}
927
928/// G_FCMP matcher that also matches commuted compares.
929/// E.g.
930///
931/// m_c_GFCmp(m_Pred(...), m_FAdd(...), m_GFMul(...))
932///
933/// Could match both of:
934///
935/// fcmp ogt (fadd x, y) (fmul a, b)
936/// fcmp olt (fmul a, b) (fadd x, y)
937template <typename Pred, typename LHS, typename RHS>
939m_c_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
941}
942
943/// Matches the register and immediate used in a fpclass test
944/// G_IS_FPCLASS %val, 96
945template <typename LHS, typename Test>
950
951// Helper for checking if a Reg is of specific type.
952struct CheckType {
954 CheckType(const LLT Ty) : Ty(Ty) {}
955
957 return MRI.getType(Reg) == Ty;
958 }
959};
960
961inline CheckType m_SpecificType(LLT Ty) { return Ty; }
962
963template <typename Src0Ty, typename Src1Ty, typename Src2Ty, unsigned Opcode>
965 Src0Ty Src0;
966 Src1Ty Src1;
967 Src2Ty Src2;
968
969 TernaryOp_match(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
970 : Src0(Src0), Src1(Src1), Src2(Src2) {}
971 template <typename OpTy>
972 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
973 MachineInstr *TmpMI;
974 if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
975 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 4) {
976 return (Src0.match(MRI, TmpMI->getOperand(1).getReg()) &&
977 Src1.match(MRI, TmpMI->getOperand(2).getReg()) &&
978 Src2.match(MRI, TmpMI->getOperand(3).getReg()));
979 }
980 }
981 return false;
982 }
983};
984template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
985inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
986 TargetOpcode::G_INSERT_VECTOR_ELT>
987m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
988 return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
989 TargetOpcode::G_INSERT_VECTOR_ELT>(Src0, Src1, Src2);
990}
991
992template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
994m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
996 Src0, Src1, Src2);
997}
998
999/// Matches a register negated by a G_SUB.
1000/// G_SUB 0, %negated_reg
1001template <typename SrcTy>
1003m_Neg(const SrcTy &&Src) {
1004 return m_GSub(m_ZeroInt(), Src);
1005}
1006
1007/// Matches a register not-ed by a G_XOR.
1008/// G_XOR %not_reg, -1
1009template <typename SrcTy>
1011m_Not(const SrcTy &&Src) {
1012 return m_GXor(Src, m_AllOnesInt());
1013}
1014
1015} // namespace MIPatternMatch
1016} // namespace llvm
1017
1018#endif
aarch64 promote const
This file implements a class to represent arbitrary precision integral constant values and operations...
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
Utilities for dealing with flags related to floating point properties and mode controls.
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
Register Reg
#define T
#define P(N)
Value * RHS
Value * LHS
Class for arbitrary precision integers.
Definition APInt.h:78
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:231
unsigned getBitWidth() const
Return the number of bits in the APInt.
Definition APInt.h:1509
static bool isSameValue(const APInt &I1, const APInt &I2, bool SignedCompare=false)
Determine if two APInts have the same value, after zero-extending or sign-extending (if SignedCompare...
Definition APInt.h:551
LLVM_ABI APInt sext(unsigned width) const
Sign extend to a new width.
Definition APInt.cpp:1023
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:197
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
Predicate getSwappedPredicate() const
For example, EQ->EQ, SLE->SGE, ULT->UGT, OEQ->OEQ, ULE->UGE, OLT->OGT, etc.
Definition InstrTypes.h:890
ConstantFP - Floating Point Values [float, double].
Definition Constants.h:420
Represents a G_CONSTANT.
Representation of each machine instruction.
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
unsigned getNumOperands() const
Retuns the total number of operands.
const MachineOperand & getOperand(unsigned i) const
uint32_t getFlags() const
Return the MI flags bitvector.
unsigned getNumDefs() const
Returns the total number of definitions.
MachineOperand class - Representation of each machine instruction operand.
bool isReg() const
isReg - Tests if this is a MO_Register operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLVM_ABI bool hasOneNonDBGUse(Register RegNo) const
hasOneNonDBGUse - Return true if there is exactly one non-Debug use of the specified register.
LLVM_ABI LLVM_READONLY MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
bool hasOneUse(Register RegNo) const
hasOneUse - Return true if there is exactly one instruction using the specified register.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
operand_type_match m_Reg()
SpecificConstantMatch m_SpecificICst(const APInt &RequestedValue)
Matches a constant equal to RequestedValue.
std::optional< ConstT > matchConstantSplat(Register, const MachineRegisterInfo &)
auto m_GAddLike(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false > m_GBuildVector(const LHS &L, const RHS &R)
SpecificConstantSplatMatch m_SpecificICstSplat(const APInt &RequestedValue)
Matches a constant splat of RequestedValue.
GCstAndRegMatch m_GCst(std::optional< ValueAndVReg > &ValReg)
UnaryOp_match< SrcTy, TargetOpcode::G_FFLOOR > m_GFFloor(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::COPY > m_Copy(SrcTy &&Src)
MIFlagsRef m_MIFlags(uint32_t &Flags)
operand_type_match m_Pred()
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMIN, true > m_GUMin(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ZEXT > m_GZExt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_XOR, true > m_GXor(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_SEXT > m_GSExt(const SrcTy &Src)
deferred_ty< LLT > m_DeferredType(LLT &Ty)
UnaryOp_match< SrcTy, TargetOpcode::G_FPEXT > m_GFPExt(const SrcTy &Src)
SpecificConstantMatch m_ZeroInt()
Convenience matchers for specific integer values.
ConstantMatch< APInt > m_ICst(APInt &Cst)
UnaryOp_match< SrcTy, TargetOpcode::G_FSQRT > m_GFSqrt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_INTTOPTR > m_GIntToPtr(const SrcTy &Src)
SpecificConstantMatch m_AllOnesInt()
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true, MachineInstr::Disjoint > m_GDisjointOr(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ADD, true > m_GAdd(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_OR, true > m_GOr(const LHS &L, const RHS &R)
BinaryOp_match< SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB > m_Neg(const SrcTy &&Src)
Matches a register negated by a G_SUB.
ICstOrSplatMatch< APInt > m_ICstOrSplat(APInt &Cst)
bind_ty< FPClassTest > m_FPClassTest(FPClassTest &T)
ImplicitDefMatch m_GImplicitDef()
OneNonDBGUse_match< SubPat > m_OneNonDBGUse(const SubPat &SP)
CheckType m_SpecificType(LLT Ty)
deferred_ty< Register > m_DeferredReg(Register &R)
Similar to m_SpecificReg/Type, but the specific value to match originated from an earlier sub-pattern...
BinaryOp_match< LHS, RHS, TargetOpcode::G_UMAX, true > m_GUMax(const LHS &L, const RHS &R)
BinaryOp_match< SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true > m_Not(const SrcTy &&Src)
Matches a register not-ed by a G_XOR.
BinaryOpc_match< LHS, RHS, true > m_CommutativeBinOp(unsigned Opcode, const LHS &L, const RHS &R)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_ICMP > m_GICmp(const Pred &P, const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FADD, true > m_GFAdd(const LHS &L, const RHS &R)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_FCMP, true > m_c_GFCmp(const Pred &P, const LHS &L, const RHS &R)
G_FCMP matcher that also matches commuted compares.
UnaryOp_match< SrcTy, TargetOpcode::G_PTRTOINT > m_GPtrToInt(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FSUB, false > m_GFSub(const LHS &L, const RHS &R)
GConstantMatch< GConstant > m_GConstant(GConstant *&Inst)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SUB > m_GSub(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_ASHR, false > m_GAShr(const LHS &L, const RHS &R)
TernaryOp_match< Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT > m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P)
BinaryOp_match< LHS, RHS, TargetOpcode::G_PTR_ADD, false > m_GPtrAdd(const LHS &L, const RHS &R)
SpecificRegisterMatch m_SpecificReg(Register RequestedReg)
Matches a register only if it is equal to RequestedReg.
BinaryOp_match< LHS, RHS, TargetOpcode::G_SHL, false > m_GShl(const LHS &L, const RHS &R)
Or< Preds... > m_any_of(Preds &&... preds)
SpecificConstantOrSplatMatch m_SpecificICstOrSplat(const APInt &RequestedValue)
Matches a RequestedValue constant or a constant splat of RequestedValue.
BinaryOp_match< LHS, RHS, TargetOpcode::G_AND, true > m_GAnd(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_BITCAST > m_GBitcast(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false > m_GBuildVectorTrunc(const LHS &L, const RHS &R)
bind_ty< MachineInstr * > m_MInstr(MachineInstr *&MI)
UnaryOp_match< SrcTy, TargetOpcode::G_FNEG > m_GFNeg(const SrcTy &Src)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_ICMP, true > m_c_GICmp(const Pred &P, const LHS &L, const RHS &R)
G_ICMP matcher that also matches commuted compares.
GFCstAndRegMatch m_GFCst(std::optional< FPValueAndVReg > &FPValReg)
ClassifyOp_match< LHS, Test, TargetOpcode::G_IS_FPCLASS > m_GIsFPClass(const LHS &L, const Test &T)
Matches the register and immediate used in a fpclass test G_IS_FPCLASS val, 96.
TernaryOp_match< Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_INSERT_VECTOR_ELT > m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
GFCstOrSplatGFCstMatch m_GFCstOrSplat(std::optional< FPValueAndVReg > &FPValReg)
And< Preds... > m_all_of(Preds &&... preds)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMIN, true > m_GSMin(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_FABS > m_GFabs(const SrcTy &Src)
BinaryOp_match< LHS, RHS, TargetOpcode::G_LSHR, false > m_GLShr(const LHS &L, const RHS &R)
UnaryOp_match< SrcTy, TargetOpcode::G_ANYEXT > m_GAnyExt(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_FPTRUNC > m_GFPTrunc(const SrcTy &Src)
std::optional< ConstT > matchConstant(Register, const MachineRegisterInfo &)
OneUse_match< SubPat > m_OneUse(const SubPat &SP)
BinaryOp_match< LHS, RHS, TargetOpcode::G_FMUL, true > m_GFMul(const LHS &L, const RHS &R)
BinaryOp_match< LHS, RHS, TargetOpcode::G_MUL, true > m_GMul(const LHS &L, const RHS &R)
SExtInRegMatch< SrcTy > m_GSExtInReg(const SrcTy &Src)
UnaryOp_match< SrcTy, TargetOpcode::G_TRUNC > m_GTrunc(const SrcTy &Src)
bind_ty< LLT > m_Type(LLT &Ty)
BinaryOp_match< LHS, RHS, TargetOpcode::G_SMAX, true > m_GSMax(const LHS &L, const RHS &R)
CompareOp_match< Pred, LHS, RHS, TargetOpcode::G_FCMP > m_GFCmp(const Pred &P, const LHS &L, const RHS &R)
auto m_BinOp()
Match an arbitrary binary operation and ignore it.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI const ConstantFP * getConstantFPVRegVal(Register VReg, const MachineRegisterInfo &MRI)
Definition Utils.cpp:464
LLVM_ABI std::optional< APInt > getIConstantVRegVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT, return the corresponding value.
Definition Utils.cpp:297
LLVM_ABI std::optional< APInt > getIConstantSplatVal(const Register Reg, const MachineRegisterInfo &MRI)
Definition Utils.cpp:1394
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI std::optional< int64_t > getIConstantVRegSExtVal(Register VReg, const MachineRegisterInfo &MRI)
If VReg is defined by a G_CONSTANT fits in int64_t returns it.
Definition Utils.cpp:317
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
FPClassTest
Floating-point class tests, supported by 'is_fpclass' intrinsic.
LLVM_ABI std::optional< FPValueAndVReg > getFConstantSplat(Register VReg, const MachineRegisterInfo &MRI, bool AllowUndef=true)
Returns a floating point scalar constant of a build vector splat if it exists.
Definition Utils.cpp:1427
DWARFExpression::Operation Op
LLVM_ABI std::optional< FPValueAndVReg > getFConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_FCONSTANT returns it...
Definition Utils.cpp:450
LLVM_ABI bool isBuildVectorConstantSplat(const Register Reg, const MachineRegisterInfo &MRI, int64_t SplatValue, bool AllowUndef)
Return true if the specified register is defined by G_BUILD_VECTOR or G_BUILD_VECTOR_TRUNC where all ...
Definition Utils.cpp:1353
LLVM_ABI std::optional< ValueAndVReg > getIConstantVRegValWithLookThrough(Register VReg, const MachineRegisterInfo &MRI, bool LookThroughInstrs=true)
If VReg is defined by a statically evaluable chain of instructions rooted on a G_CONSTANT returns its...
Definition Utils.cpp:436
LLVM_ABI std::optional< int64_t > getIConstantSplatSExtVal(const Register Reg, const MachineRegisterInfo &MRI)
Definition Utils.cpp:1412
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:878
bool match(const MachineRegisterInfo &MRI, MatchSrc &&src)
Matching combinators.
bool match(const MachineRegisterInfo &MRI, MatchSrc &&src)
BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS)
BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS, MIFlagsRef FlagsOut)
bool match(const MachineRegisterInfo &MRI, OpTy &&Op)
bool match(const MachineRegisterInfo &MRI, OpTy &&Op)
BinaryOpc_match(unsigned Opcode, const LHS_P &LHS, const RHS_P &RHS)
bool match(const MachineRegisterInfo &MRI, Register Reg)
ClassifyOp_match(const LHS_P &LHS, const Test_P &Tst)
bool match(const MachineRegisterInfo &MRI, OpTy &&Op)
CompareOp_match(const Pred_P &Pred, const LHS_P &LHS, const RHS_P &RHS)
bool match(const MachineRegisterInfo &MRI, OpTy &&Op)
bool match(const MachineRegisterInfo &MRI, Register Reg)
Matches a G_CONSTANT and binds the defining instruction.
bool match(const MachineRegisterInfo &MRI, Register Reg)
bool match(const MachineRegisterInfo &MRI, Register Reg)
GCstAndRegMatch(std::optional< ValueAndVReg > &ValReg)
std::optional< ValueAndVReg > & ValReg
GFCstAndRegMatch(std::optional< FPValueAndVReg > &FPValReg)
std::optional< FPValueAndVReg > & FPValReg
bool match(const MachineRegisterInfo &MRI, Register Reg)
GFCstOrSplatGFCstMatch(std::optional< FPValueAndVReg > &FPValReg)
bool match(const MachineRegisterInfo &MRI, Register Reg)
std::optional< FPValueAndVReg > & FPValReg
bool match(const MachineRegisterInfo &MRI, Register Reg)
bool match(const MachineRegisterInfo &MRI, Register Reg)
Wraps a MIFlags output for use as an optional trailing operand of an instruction matcher (e....
bool match(const MachineRegisterInfo &MRI, Register Reg)
OneUse_match(const SubPatternT &SP)
bool match(const MachineRegisterInfo &MRI, Register Reg)
bool match(const MachineRegisterInfo &MRI, MatchSrc &&src)
bool match(const MachineRegisterInfo &MRI, MatchSrc &&src)
Matches a G_SEXT_INREG, binding its source operand.
bool match(const MachineRegisterInfo &MRI, OpTy &&Op)
Matcher for a specific constant value.
SpecificConstantMatch(const APInt &RequestedVal)
bool match(const MachineRegisterInfo &MRI, Register Reg)
Matcher for a specific constant or constant splat.
bool match(const MachineRegisterInfo &MRI, Register Reg)
Matcher for a specific constant splat.
SpecificConstantSplatMatch(const APInt &RequestedVal)
bool match(const MachineRegisterInfo &MRI, Register Reg)
Matcher for a specific register.
bool match(const MachineRegisterInfo &MRI, Register Reg)
bool match(const MachineRegisterInfo &MRI, OpTy &&Op)
TernaryOp_match(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
bool match(const MachineRegisterInfo &MRI, OpTy &&Op)
static bool bind(const MachineRegisterInfo &MRI, LLT &Ty, Register Reg)
static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI, Register Reg)
static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI, MachineInstr *Inst)
static bool bind(const MachineRegisterInfo &MRI, const ConstantFP *&F, Register Reg)
static bool bind(const MachineRegisterInfo &MRI, const MachineInstr *&MI, Register Reg)
static bool bind(const MachineRegisterInfo &MRI, const MachineInstr *&MI, const MachineInstr *Inst)
static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V)
bool match(const MachineRegisterInfo &MRI, ITy &&V)
static bool match(const MachineRegisterInfo &MRI, LLT VT, Register R)
static bool match(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V)
bool match(const MachineRegisterInfo &MRI, ITy &&V)
bool match(const MachineRegisterInfo &MRI, MachineOperand *MO)
bool match(const MachineRegisterInfo &MRI, Register Reg)