xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/CodeGen/SDPatternMatch.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //==--------------- llvm/CodeGen/SDPatternMatch.h ---------------*- C++ -*-===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric /// \file
9*0fca6ea1SDimitry Andric /// Contains matchers for matching SelectionDAG nodes and values.
10*0fca6ea1SDimitry Andric ///
11*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
12*0fca6ea1SDimitry Andric 
13*0fca6ea1SDimitry Andric #ifndef LLVM_CODEGEN_SDPATTERNMATCH_H
14*0fca6ea1SDimitry Andric #define LLVM_CODEGEN_SDPATTERNMATCH_H
15*0fca6ea1SDimitry Andric 
16*0fca6ea1SDimitry Andric #include "llvm/ADT/APInt.h"
17*0fca6ea1SDimitry Andric #include "llvm/ADT/STLExtras.h"
18*0fca6ea1SDimitry Andric #include "llvm/CodeGen/SelectionDAG.h"
19*0fca6ea1SDimitry Andric #include "llvm/CodeGen/SelectionDAGNodes.h"
20*0fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
21*0fca6ea1SDimitry Andric 
22*0fca6ea1SDimitry Andric namespace llvm {
23*0fca6ea1SDimitry Andric namespace SDPatternMatch {
24*0fca6ea1SDimitry Andric 
25*0fca6ea1SDimitry Andric /// MatchContext can repurpose existing patterns to behave differently under
26*0fca6ea1SDimitry Andric /// a certain context. For instance, `m_Opc(ISD::ADD)` matches plain ADD nodes
27*0fca6ea1SDimitry Andric /// in normal circumstances, but matches VP_ADD nodes under a custom
28*0fca6ea1SDimitry Andric /// VPMatchContext. This design is meant to facilitate code / pattern reusing.
29*0fca6ea1SDimitry Andric class BasicMatchContext {
30*0fca6ea1SDimitry Andric   const SelectionDAG *DAG;
31*0fca6ea1SDimitry Andric   const TargetLowering *TLI;
32*0fca6ea1SDimitry Andric 
33*0fca6ea1SDimitry Andric public:
34*0fca6ea1SDimitry Andric   explicit BasicMatchContext(const SelectionDAG *DAG)
35*0fca6ea1SDimitry Andric       : DAG(DAG), TLI(DAG ? &DAG->getTargetLoweringInfo() : nullptr) {}
36*0fca6ea1SDimitry Andric 
37*0fca6ea1SDimitry Andric   explicit BasicMatchContext(const TargetLowering *TLI)
38*0fca6ea1SDimitry Andric       : DAG(nullptr), TLI(TLI) {}
39*0fca6ea1SDimitry Andric 
40*0fca6ea1SDimitry Andric   // A valid MatchContext has to implement the following functions.
41*0fca6ea1SDimitry Andric 
42*0fca6ea1SDimitry Andric   const SelectionDAG *getDAG() const { return DAG; }
43*0fca6ea1SDimitry Andric 
44*0fca6ea1SDimitry Andric   const TargetLowering *getTLI() const { return TLI; }
45*0fca6ea1SDimitry Andric 
46*0fca6ea1SDimitry Andric   /// Return true if N effectively has opcode Opcode.
47*0fca6ea1SDimitry Andric   bool match(SDValue N, unsigned Opcode) const {
48*0fca6ea1SDimitry Andric     return N->getOpcode() == Opcode;
49*0fca6ea1SDimitry Andric   }
50*0fca6ea1SDimitry Andric };
51*0fca6ea1SDimitry Andric 
52*0fca6ea1SDimitry Andric template <typename Pattern, typename MatchContext>
53*0fca6ea1SDimitry Andric [[nodiscard]] bool sd_context_match(SDValue N, const MatchContext &Ctx,
54*0fca6ea1SDimitry Andric                                     Pattern &&P) {
55*0fca6ea1SDimitry Andric   return P.match(Ctx, N);
56*0fca6ea1SDimitry Andric }
57*0fca6ea1SDimitry Andric 
58*0fca6ea1SDimitry Andric template <typename Pattern, typename MatchContext>
59*0fca6ea1SDimitry Andric [[nodiscard]] bool sd_context_match(SDNode *N, const MatchContext &Ctx,
60*0fca6ea1SDimitry Andric                                     Pattern &&P) {
61*0fca6ea1SDimitry Andric   return sd_context_match(SDValue(N, 0), Ctx, P);
62*0fca6ea1SDimitry Andric }
63*0fca6ea1SDimitry Andric 
64*0fca6ea1SDimitry Andric template <typename Pattern>
65*0fca6ea1SDimitry Andric [[nodiscard]] bool sd_match(SDNode *N, const SelectionDAG *DAG, Pattern &&P) {
66*0fca6ea1SDimitry Andric   return sd_context_match(N, BasicMatchContext(DAG), P);
67*0fca6ea1SDimitry Andric }
68*0fca6ea1SDimitry Andric 
69*0fca6ea1SDimitry Andric template <typename Pattern>
70*0fca6ea1SDimitry Andric [[nodiscard]] bool sd_match(SDValue N, const SelectionDAG *DAG, Pattern &&P) {
71*0fca6ea1SDimitry Andric   return sd_context_match(N, BasicMatchContext(DAG), P);
72*0fca6ea1SDimitry Andric }
73*0fca6ea1SDimitry Andric 
74*0fca6ea1SDimitry Andric template <typename Pattern>
75*0fca6ea1SDimitry Andric [[nodiscard]] bool sd_match(SDNode *N, Pattern &&P) {
76*0fca6ea1SDimitry Andric   return sd_match(N, nullptr, P);
77*0fca6ea1SDimitry Andric }
78*0fca6ea1SDimitry Andric 
79*0fca6ea1SDimitry Andric template <typename Pattern>
80*0fca6ea1SDimitry Andric [[nodiscard]] bool sd_match(SDValue N, Pattern &&P) {
81*0fca6ea1SDimitry Andric   return sd_match(N, nullptr, P);
82*0fca6ea1SDimitry Andric }
83*0fca6ea1SDimitry Andric 
84*0fca6ea1SDimitry Andric // === Utilities ===
85*0fca6ea1SDimitry Andric struct Value_match {
86*0fca6ea1SDimitry Andric   SDValue MatchVal;
87*0fca6ea1SDimitry Andric 
88*0fca6ea1SDimitry Andric   Value_match() = default;
89*0fca6ea1SDimitry Andric 
90*0fca6ea1SDimitry Andric   explicit Value_match(SDValue Match) : MatchVal(Match) {}
91*0fca6ea1SDimitry Andric 
92*0fca6ea1SDimitry Andric   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
93*0fca6ea1SDimitry Andric     if (MatchVal)
94*0fca6ea1SDimitry Andric       return MatchVal == N;
95*0fca6ea1SDimitry Andric     return N.getNode();
96*0fca6ea1SDimitry Andric   }
97*0fca6ea1SDimitry Andric };
98*0fca6ea1SDimitry Andric 
99*0fca6ea1SDimitry Andric /// Match any valid SDValue.
100*0fca6ea1SDimitry Andric inline Value_match m_Value() { return Value_match(); }
101*0fca6ea1SDimitry Andric 
102*0fca6ea1SDimitry Andric inline Value_match m_Specific(SDValue N) {
103*0fca6ea1SDimitry Andric   assert(N);
104*0fca6ea1SDimitry Andric   return Value_match(N);
105*0fca6ea1SDimitry Andric }
106*0fca6ea1SDimitry Andric 
107*0fca6ea1SDimitry Andric struct DeferredValue_match {
108*0fca6ea1SDimitry Andric   SDValue &MatchVal;
109*0fca6ea1SDimitry Andric 
110*0fca6ea1SDimitry Andric   explicit DeferredValue_match(SDValue &Match) : MatchVal(Match) {}
111*0fca6ea1SDimitry Andric 
112*0fca6ea1SDimitry Andric   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
113*0fca6ea1SDimitry Andric     return N == MatchVal;
114*0fca6ea1SDimitry Andric   }
115*0fca6ea1SDimitry Andric };
116*0fca6ea1SDimitry Andric 
117*0fca6ea1SDimitry Andric /// Similar to m_Specific, but the specific value to match is determined by
118*0fca6ea1SDimitry Andric /// another sub-pattern in the same sd_match() expression. For instance,
119*0fca6ea1SDimitry Andric /// We cannot match `(add V, V)` with `m_Add(m_Value(X), m_Specific(X))` since
120*0fca6ea1SDimitry Andric /// `X` is not initialized at the time it got copied into `m_Specific`. Instead,
121*0fca6ea1SDimitry Andric /// we should use `m_Add(m_Value(X), m_Deferred(X))`.
122*0fca6ea1SDimitry Andric inline DeferredValue_match m_Deferred(SDValue &V) {
123*0fca6ea1SDimitry Andric   return DeferredValue_match(V);
124*0fca6ea1SDimitry Andric }
125*0fca6ea1SDimitry Andric 
126*0fca6ea1SDimitry Andric struct Opcode_match {
127*0fca6ea1SDimitry Andric   unsigned Opcode;
128*0fca6ea1SDimitry Andric 
129*0fca6ea1SDimitry Andric   explicit Opcode_match(unsigned Opc) : Opcode(Opc) {}
130*0fca6ea1SDimitry Andric 
131*0fca6ea1SDimitry Andric   template <typename MatchContext>
132*0fca6ea1SDimitry Andric   bool match(const MatchContext &Ctx, SDValue N) {
133*0fca6ea1SDimitry Andric     return Ctx.match(N, Opcode);
134*0fca6ea1SDimitry Andric   }
135*0fca6ea1SDimitry Andric };
136*0fca6ea1SDimitry Andric 
137*0fca6ea1SDimitry Andric inline Opcode_match m_Opc(unsigned Opcode) { return Opcode_match(Opcode); }
138*0fca6ea1SDimitry Andric 
139*0fca6ea1SDimitry Andric template <unsigned NumUses, typename Pattern> struct NUses_match {
140*0fca6ea1SDimitry Andric   Pattern P;
141*0fca6ea1SDimitry Andric 
142*0fca6ea1SDimitry Andric   explicit NUses_match(const Pattern &P) : P(P) {}
143*0fca6ea1SDimitry Andric 
144*0fca6ea1SDimitry Andric   template <typename MatchContext>
145*0fca6ea1SDimitry Andric   bool match(const MatchContext &Ctx, SDValue N) {
146*0fca6ea1SDimitry Andric     // SDNode::hasNUsesOfValue is pretty expensive when the SDNode produces
147*0fca6ea1SDimitry Andric     // multiple results, hence we check the subsequent pattern here before
148*0fca6ea1SDimitry Andric     // checking the number of value users.
149*0fca6ea1SDimitry Andric     return P.match(Ctx, N) && N->hasNUsesOfValue(NumUses, N.getResNo());
150*0fca6ea1SDimitry Andric   }
151*0fca6ea1SDimitry Andric };
152*0fca6ea1SDimitry Andric 
153*0fca6ea1SDimitry Andric template <typename Pattern>
154*0fca6ea1SDimitry Andric inline NUses_match<1, Pattern> m_OneUse(const Pattern &P) {
155*0fca6ea1SDimitry Andric   return NUses_match<1, Pattern>(P);
156*0fca6ea1SDimitry Andric }
157*0fca6ea1SDimitry Andric template <unsigned N, typename Pattern>
158*0fca6ea1SDimitry Andric inline NUses_match<N, Pattern> m_NUses(const Pattern &P) {
159*0fca6ea1SDimitry Andric   return NUses_match<N, Pattern>(P);
160*0fca6ea1SDimitry Andric }
161*0fca6ea1SDimitry Andric 
162*0fca6ea1SDimitry Andric inline NUses_match<1, Value_match> m_OneUse() {
163*0fca6ea1SDimitry Andric   return NUses_match<1, Value_match>(m_Value());
164*0fca6ea1SDimitry Andric }
165*0fca6ea1SDimitry Andric template <unsigned N> inline NUses_match<N, Value_match> m_NUses() {
166*0fca6ea1SDimitry Andric   return NUses_match<N, Value_match>(m_Value());
167*0fca6ea1SDimitry Andric }
168*0fca6ea1SDimitry Andric 
169*0fca6ea1SDimitry Andric struct Value_bind {
170*0fca6ea1SDimitry Andric   SDValue &BindVal;
171*0fca6ea1SDimitry Andric 
172*0fca6ea1SDimitry Andric   explicit Value_bind(SDValue &N) : BindVal(N) {}
173*0fca6ea1SDimitry Andric 
174*0fca6ea1SDimitry Andric   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
175*0fca6ea1SDimitry Andric     BindVal = N;
176*0fca6ea1SDimitry Andric     return true;
177*0fca6ea1SDimitry Andric   }
178*0fca6ea1SDimitry Andric };
179*0fca6ea1SDimitry Andric 
180*0fca6ea1SDimitry Andric inline Value_bind m_Value(SDValue &N) { return Value_bind(N); }
181*0fca6ea1SDimitry Andric 
182*0fca6ea1SDimitry Andric template <typename Pattern, typename PredFuncT> struct TLI_pred_match {
183*0fca6ea1SDimitry Andric   Pattern P;
184*0fca6ea1SDimitry Andric   PredFuncT PredFunc;
185*0fca6ea1SDimitry Andric 
186*0fca6ea1SDimitry Andric   TLI_pred_match(const PredFuncT &Pred, const Pattern &P)
187*0fca6ea1SDimitry Andric       : P(P), PredFunc(Pred) {}
188*0fca6ea1SDimitry Andric 
189*0fca6ea1SDimitry Andric   template <typename MatchContext>
190*0fca6ea1SDimitry Andric   bool match(const MatchContext &Ctx, SDValue N) {
191*0fca6ea1SDimitry Andric     assert(Ctx.getTLI() && "TargetLowering is required for this pattern.");
192*0fca6ea1SDimitry Andric     return PredFunc(*Ctx.getTLI(), N) && P.match(Ctx, N);
193*0fca6ea1SDimitry Andric   }
194*0fca6ea1SDimitry Andric };
195*0fca6ea1SDimitry Andric 
196*0fca6ea1SDimitry Andric // Explicit deduction guide.
197*0fca6ea1SDimitry Andric template <typename PredFuncT, typename Pattern>
198*0fca6ea1SDimitry Andric TLI_pred_match(const PredFuncT &Pred, const Pattern &P)
199*0fca6ea1SDimitry Andric     -> TLI_pred_match<Pattern, PredFuncT>;
200*0fca6ea1SDimitry Andric 
201*0fca6ea1SDimitry Andric /// Match legal SDNodes based on the information provided by TargetLowering.
202*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_LegalOp(const Pattern &P) {
203*0fca6ea1SDimitry Andric   return TLI_pred_match{[](const TargetLowering &TLI, SDValue N) {
204*0fca6ea1SDimitry Andric                           return TLI.isOperationLegal(N->getOpcode(),
205*0fca6ea1SDimitry Andric                                                       N.getValueType());
206*0fca6ea1SDimitry Andric                         },
207*0fca6ea1SDimitry Andric                         P};
208*0fca6ea1SDimitry Andric }
209*0fca6ea1SDimitry Andric 
210*0fca6ea1SDimitry Andric /// Switch to a different MatchContext for subsequent patterns.
211*0fca6ea1SDimitry Andric template <typename NewMatchContext, typename Pattern> struct SwitchContext {
212*0fca6ea1SDimitry Andric   const NewMatchContext &Ctx;
213*0fca6ea1SDimitry Andric   Pattern P;
214*0fca6ea1SDimitry Andric 
215*0fca6ea1SDimitry Andric   template <typename OrigMatchContext>
216*0fca6ea1SDimitry Andric   bool match(const OrigMatchContext &, SDValue N) {
217*0fca6ea1SDimitry Andric     return P.match(Ctx, N);
218*0fca6ea1SDimitry Andric   }
219*0fca6ea1SDimitry Andric };
220*0fca6ea1SDimitry Andric 
221*0fca6ea1SDimitry Andric template <typename MatchContext, typename Pattern>
222*0fca6ea1SDimitry Andric inline SwitchContext<MatchContext, Pattern> m_Context(const MatchContext &Ctx,
223*0fca6ea1SDimitry Andric                                                       Pattern &&P) {
224*0fca6ea1SDimitry Andric   return SwitchContext<MatchContext, Pattern>{Ctx, std::move(P)};
225*0fca6ea1SDimitry Andric }
226*0fca6ea1SDimitry Andric 
227*0fca6ea1SDimitry Andric // === Value type ===
228*0fca6ea1SDimitry Andric struct ValueType_bind {
229*0fca6ea1SDimitry Andric   EVT &BindVT;
230*0fca6ea1SDimitry Andric 
231*0fca6ea1SDimitry Andric   explicit ValueType_bind(EVT &Bind) : BindVT(Bind) {}
232*0fca6ea1SDimitry Andric 
233*0fca6ea1SDimitry Andric   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
234*0fca6ea1SDimitry Andric     BindVT = N.getValueType();
235*0fca6ea1SDimitry Andric     return true;
236*0fca6ea1SDimitry Andric   }
237*0fca6ea1SDimitry Andric };
238*0fca6ea1SDimitry Andric 
239*0fca6ea1SDimitry Andric /// Retreive the ValueType of the current SDValue.
240*0fca6ea1SDimitry Andric inline ValueType_bind m_VT(EVT &VT) { return ValueType_bind(VT); }
241*0fca6ea1SDimitry Andric 
242*0fca6ea1SDimitry Andric template <typename Pattern, typename PredFuncT> struct ValueType_match {
243*0fca6ea1SDimitry Andric   PredFuncT PredFunc;
244*0fca6ea1SDimitry Andric   Pattern P;
245*0fca6ea1SDimitry Andric 
246*0fca6ea1SDimitry Andric   ValueType_match(const PredFuncT &Pred, const Pattern &P)
247*0fca6ea1SDimitry Andric       : PredFunc(Pred), P(P) {}
248*0fca6ea1SDimitry Andric 
249*0fca6ea1SDimitry Andric   template <typename MatchContext>
250*0fca6ea1SDimitry Andric   bool match(const MatchContext &Ctx, SDValue N) {
251*0fca6ea1SDimitry Andric     return PredFunc(N.getValueType()) && P.match(Ctx, N);
252*0fca6ea1SDimitry Andric   }
253*0fca6ea1SDimitry Andric };
254*0fca6ea1SDimitry Andric 
255*0fca6ea1SDimitry Andric // Explicit deduction guide.
256*0fca6ea1SDimitry Andric template <typename PredFuncT, typename Pattern>
257*0fca6ea1SDimitry Andric ValueType_match(const PredFuncT &Pred, const Pattern &P)
258*0fca6ea1SDimitry Andric     -> ValueType_match<Pattern, PredFuncT>;
259*0fca6ea1SDimitry Andric 
260*0fca6ea1SDimitry Andric /// Match a specific ValueType.
261*0fca6ea1SDimitry Andric template <typename Pattern>
262*0fca6ea1SDimitry Andric inline auto m_SpecificVT(EVT RefVT, const Pattern &P) {
263*0fca6ea1SDimitry Andric   return ValueType_match{[=](EVT VT) { return VT == RefVT; }, P};
264*0fca6ea1SDimitry Andric }
265*0fca6ea1SDimitry Andric inline auto m_SpecificVT(EVT RefVT) {
266*0fca6ea1SDimitry Andric   return ValueType_match{[=](EVT VT) { return VT == RefVT; }, m_Value()};
267*0fca6ea1SDimitry Andric }
268*0fca6ea1SDimitry Andric 
269*0fca6ea1SDimitry Andric inline auto m_Glue() { return m_SpecificVT(MVT::Glue); }
270*0fca6ea1SDimitry Andric inline auto m_OtherVT() { return m_SpecificVT(MVT::Other); }
271*0fca6ea1SDimitry Andric 
272*0fca6ea1SDimitry Andric /// Match any integer ValueTypes.
273*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_IntegerVT(const Pattern &P) {
274*0fca6ea1SDimitry Andric   return ValueType_match{[](EVT VT) { return VT.isInteger(); }, P};
275*0fca6ea1SDimitry Andric }
276*0fca6ea1SDimitry Andric inline auto m_IntegerVT() {
277*0fca6ea1SDimitry Andric   return ValueType_match{[](EVT VT) { return VT.isInteger(); }, m_Value()};
278*0fca6ea1SDimitry Andric }
279*0fca6ea1SDimitry Andric 
280*0fca6ea1SDimitry Andric /// Match any floating point ValueTypes.
281*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_FloatingPointVT(const Pattern &P) {
282*0fca6ea1SDimitry Andric   return ValueType_match{[](EVT VT) { return VT.isFloatingPoint(); }, P};
283*0fca6ea1SDimitry Andric }
284*0fca6ea1SDimitry Andric inline auto m_FloatingPointVT() {
285*0fca6ea1SDimitry Andric   return ValueType_match{[](EVT VT) { return VT.isFloatingPoint(); },
286*0fca6ea1SDimitry Andric                          m_Value()};
287*0fca6ea1SDimitry Andric }
288*0fca6ea1SDimitry Andric 
289*0fca6ea1SDimitry Andric /// Match any vector ValueTypes.
290*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_VectorVT(const Pattern &P) {
291*0fca6ea1SDimitry Andric   return ValueType_match{[](EVT VT) { return VT.isVector(); }, P};
292*0fca6ea1SDimitry Andric }
293*0fca6ea1SDimitry Andric inline auto m_VectorVT() {
294*0fca6ea1SDimitry Andric   return ValueType_match{[](EVT VT) { return VT.isVector(); }, m_Value()};
295*0fca6ea1SDimitry Andric }
296*0fca6ea1SDimitry Andric 
297*0fca6ea1SDimitry Andric /// Match fixed-length vector ValueTypes.
298*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_FixedVectorVT(const Pattern &P) {
299*0fca6ea1SDimitry Andric   return ValueType_match{[](EVT VT) { return VT.isFixedLengthVector(); }, P};
300*0fca6ea1SDimitry Andric }
301*0fca6ea1SDimitry Andric inline auto m_FixedVectorVT() {
302*0fca6ea1SDimitry Andric   return ValueType_match{[](EVT VT) { return VT.isFixedLengthVector(); },
303*0fca6ea1SDimitry Andric                          m_Value()};
304*0fca6ea1SDimitry Andric }
305*0fca6ea1SDimitry Andric 
306*0fca6ea1SDimitry Andric /// Match scalable vector ValueTypes.
307*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_ScalableVectorVT(const Pattern &P) {
308*0fca6ea1SDimitry Andric   return ValueType_match{[](EVT VT) { return VT.isScalableVector(); }, P};
309*0fca6ea1SDimitry Andric }
310*0fca6ea1SDimitry Andric inline auto m_ScalableVectorVT() {
311*0fca6ea1SDimitry Andric   return ValueType_match{[](EVT VT) { return VT.isScalableVector(); },
312*0fca6ea1SDimitry Andric                          m_Value()};
313*0fca6ea1SDimitry Andric }
314*0fca6ea1SDimitry Andric 
315*0fca6ea1SDimitry Andric /// Match legal ValueTypes based on the information provided by TargetLowering.
316*0fca6ea1SDimitry Andric template <typename Pattern> inline auto m_LegalType(const Pattern &P) {
317*0fca6ea1SDimitry Andric   return TLI_pred_match{[](const TargetLowering &TLI, SDValue N) {
318*0fca6ea1SDimitry Andric                           return TLI.isTypeLegal(N.getValueType());
319*0fca6ea1SDimitry Andric                         },
320*0fca6ea1SDimitry Andric                         P};
321*0fca6ea1SDimitry Andric }
322*0fca6ea1SDimitry Andric 
323*0fca6ea1SDimitry Andric // === Patterns combinators ===
324*0fca6ea1SDimitry Andric template <typename... Preds> struct And {
325*0fca6ea1SDimitry Andric   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
326*0fca6ea1SDimitry Andric     return true;
327*0fca6ea1SDimitry Andric   }
328*0fca6ea1SDimitry Andric };
329*0fca6ea1SDimitry Andric 
330*0fca6ea1SDimitry Andric template <typename Pred, typename... Preds>
331*0fca6ea1SDimitry Andric struct And<Pred, Preds...> : And<Preds...> {
332*0fca6ea1SDimitry Andric   Pred P;
333*0fca6ea1SDimitry Andric   And(const Pred &p, const Preds &...preds) : And<Preds...>(preds...), P(p) {}
334*0fca6ea1SDimitry Andric 
335*0fca6ea1SDimitry Andric   template <typename MatchContext>
336*0fca6ea1SDimitry Andric   bool match(const MatchContext &Ctx, SDValue N) {
337*0fca6ea1SDimitry Andric     return P.match(Ctx, N) && And<Preds...>::match(Ctx, N);
338*0fca6ea1SDimitry Andric   }
339*0fca6ea1SDimitry Andric };
340*0fca6ea1SDimitry Andric 
341*0fca6ea1SDimitry Andric template <typename... Preds> struct Or {
342*0fca6ea1SDimitry Andric   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
343*0fca6ea1SDimitry Andric     return false;
344*0fca6ea1SDimitry Andric   }
345*0fca6ea1SDimitry Andric };
346*0fca6ea1SDimitry Andric 
347*0fca6ea1SDimitry Andric template <typename Pred, typename... Preds>
348*0fca6ea1SDimitry Andric struct Or<Pred, Preds...> : Or<Preds...> {
349*0fca6ea1SDimitry Andric   Pred P;
350*0fca6ea1SDimitry Andric   Or(const Pred &p, const Preds &...preds) : Or<Preds...>(preds...), P(p) {}
351*0fca6ea1SDimitry Andric 
352*0fca6ea1SDimitry Andric   template <typename MatchContext>
353*0fca6ea1SDimitry Andric   bool match(const MatchContext &Ctx, SDValue N) {
354*0fca6ea1SDimitry Andric     return P.match(Ctx, N) || Or<Preds...>::match(Ctx, N);
355*0fca6ea1SDimitry Andric   }
356*0fca6ea1SDimitry Andric };
357*0fca6ea1SDimitry Andric 
358*0fca6ea1SDimitry Andric template <typename Pred> struct Not {
359*0fca6ea1SDimitry Andric   Pred P;
360*0fca6ea1SDimitry Andric 
361*0fca6ea1SDimitry Andric   explicit Not(const Pred &P) : P(P) {}
362*0fca6ea1SDimitry Andric 
363*0fca6ea1SDimitry Andric   template <typename MatchContext>
364*0fca6ea1SDimitry Andric   bool match(const MatchContext &Ctx, SDValue N) {
365*0fca6ea1SDimitry Andric     return !P.match(Ctx, N);
366*0fca6ea1SDimitry Andric   }
367*0fca6ea1SDimitry Andric };
368*0fca6ea1SDimitry Andric // Explicit deduction guide.
369*0fca6ea1SDimitry Andric template <typename Pred> Not(const Pred &P) -> Not<Pred>;
370*0fca6ea1SDimitry Andric 
371*0fca6ea1SDimitry Andric /// Match if the inner pattern does NOT match.
372*0fca6ea1SDimitry Andric template <typename Pred> inline Not<Pred> m_Unless(const Pred &P) {
373*0fca6ea1SDimitry Andric   return Not{P};
374*0fca6ea1SDimitry Andric }
375*0fca6ea1SDimitry Andric 
376*0fca6ea1SDimitry Andric template <typename... Preds> And<Preds...> m_AllOf(const Preds &...preds) {
377*0fca6ea1SDimitry Andric   return And<Preds...>(preds...);
378*0fca6ea1SDimitry Andric }
379*0fca6ea1SDimitry Andric 
380*0fca6ea1SDimitry Andric template <typename... Preds> Or<Preds...> m_AnyOf(const Preds &...preds) {
381*0fca6ea1SDimitry Andric   return Or<Preds...>(preds...);
382*0fca6ea1SDimitry Andric }
383*0fca6ea1SDimitry Andric 
384*0fca6ea1SDimitry Andric template <typename... Preds> auto m_NoneOf(const Preds &...preds) {
385*0fca6ea1SDimitry Andric   return m_Unless(m_AnyOf(preds...));
386*0fca6ea1SDimitry Andric }
387*0fca6ea1SDimitry Andric 
388*0fca6ea1SDimitry Andric // === Generic node matching ===
389*0fca6ea1SDimitry Andric template <unsigned OpIdx, typename... OpndPreds> struct Operands_match {
390*0fca6ea1SDimitry Andric   template <typename MatchContext>
391*0fca6ea1SDimitry Andric   bool match(const MatchContext &Ctx, SDValue N) {
392*0fca6ea1SDimitry Andric     // Returns false if there are more operands than predicates;
393*0fca6ea1SDimitry Andric     return N->getNumOperands() == OpIdx;
394*0fca6ea1SDimitry Andric   }
395*0fca6ea1SDimitry Andric };
396*0fca6ea1SDimitry Andric 
397*0fca6ea1SDimitry Andric template <unsigned OpIdx, typename OpndPred, typename... OpndPreds>
398*0fca6ea1SDimitry Andric struct Operands_match<OpIdx, OpndPred, OpndPreds...>
399*0fca6ea1SDimitry Andric     : Operands_match<OpIdx + 1, OpndPreds...> {
400*0fca6ea1SDimitry Andric   OpndPred P;
401*0fca6ea1SDimitry Andric 
402*0fca6ea1SDimitry Andric   Operands_match(const OpndPred &p, const OpndPreds &...preds)
403*0fca6ea1SDimitry Andric       : Operands_match<OpIdx + 1, OpndPreds...>(preds...), P(p) {}
404*0fca6ea1SDimitry Andric 
405*0fca6ea1SDimitry Andric   template <typename MatchContext>
406*0fca6ea1SDimitry Andric   bool match(const MatchContext &Ctx, SDValue N) {
407*0fca6ea1SDimitry Andric     if (OpIdx < N->getNumOperands())
408*0fca6ea1SDimitry Andric       return P.match(Ctx, N->getOperand(OpIdx)) &&
409*0fca6ea1SDimitry Andric              Operands_match<OpIdx + 1, OpndPreds...>::match(Ctx, N);
410*0fca6ea1SDimitry Andric 
411*0fca6ea1SDimitry Andric     // This is the case where there are more predicates than operands.
412*0fca6ea1SDimitry Andric     return false;
413*0fca6ea1SDimitry Andric   }
414*0fca6ea1SDimitry Andric };
415*0fca6ea1SDimitry Andric 
416*0fca6ea1SDimitry Andric template <typename... OpndPreds>
417*0fca6ea1SDimitry Andric auto m_Node(unsigned Opcode, const OpndPreds &...preds) {
418*0fca6ea1SDimitry Andric   return m_AllOf(m_Opc(Opcode), Operands_match<0, OpndPreds...>(preds...));
419*0fca6ea1SDimitry Andric }
420*0fca6ea1SDimitry Andric 
421*0fca6ea1SDimitry Andric /// Provide number of operands that are not chain or glue, as well as the first
422*0fca6ea1SDimitry Andric /// index of such operand.
423*0fca6ea1SDimitry Andric template <bool ExcludeChain> struct EffectiveOperands {
424*0fca6ea1SDimitry Andric   unsigned Size = 0;
425*0fca6ea1SDimitry Andric   unsigned FirstIndex = 0;
426*0fca6ea1SDimitry Andric 
427*0fca6ea1SDimitry Andric   explicit EffectiveOperands(SDValue N) {
428*0fca6ea1SDimitry Andric     const unsigned TotalNumOps = N->getNumOperands();
429*0fca6ea1SDimitry Andric     FirstIndex = TotalNumOps;
430*0fca6ea1SDimitry Andric     for (unsigned I = 0; I < TotalNumOps; ++I) {
431*0fca6ea1SDimitry Andric       // Count the number of non-chain and non-glue nodes (we ignore chain
432*0fca6ea1SDimitry Andric       // and glue by default) and retreive the operand index offset.
433*0fca6ea1SDimitry Andric       EVT VT = N->getOperand(I).getValueType();
434*0fca6ea1SDimitry Andric       if (VT != MVT::Glue && VT != MVT::Other) {
435*0fca6ea1SDimitry Andric         ++Size;
436*0fca6ea1SDimitry Andric         if (FirstIndex == TotalNumOps)
437*0fca6ea1SDimitry Andric           FirstIndex = I;
438*0fca6ea1SDimitry Andric       }
439*0fca6ea1SDimitry Andric     }
440*0fca6ea1SDimitry Andric   }
441*0fca6ea1SDimitry Andric };
442*0fca6ea1SDimitry Andric 
443*0fca6ea1SDimitry Andric template <> struct EffectiveOperands<false> {
444*0fca6ea1SDimitry Andric   unsigned Size = 0;
445*0fca6ea1SDimitry Andric   unsigned FirstIndex = 0;
446*0fca6ea1SDimitry Andric 
447*0fca6ea1SDimitry Andric   explicit EffectiveOperands(SDValue N) : Size(N->getNumOperands()) {}
448*0fca6ea1SDimitry Andric };
449*0fca6ea1SDimitry Andric 
450*0fca6ea1SDimitry Andric // === Ternary operations ===
451*0fca6ea1SDimitry Andric template <typename T0_P, typename T1_P, typename T2_P, bool Commutable = false,
452*0fca6ea1SDimitry Andric           bool ExcludeChain = false>
453*0fca6ea1SDimitry Andric struct TernaryOpc_match {
454*0fca6ea1SDimitry Andric   unsigned Opcode;
455*0fca6ea1SDimitry Andric   T0_P Op0;
456*0fca6ea1SDimitry Andric   T1_P Op1;
457*0fca6ea1SDimitry Andric   T2_P Op2;
458*0fca6ea1SDimitry Andric 
459*0fca6ea1SDimitry Andric   TernaryOpc_match(unsigned Opc, const T0_P &Op0, const T1_P &Op1,
460*0fca6ea1SDimitry Andric                    const T2_P &Op2)
461*0fca6ea1SDimitry Andric       : Opcode(Opc), Op0(Op0), Op1(Op1), Op2(Op2) {}
462*0fca6ea1SDimitry Andric 
463*0fca6ea1SDimitry Andric   template <typename MatchContext>
464*0fca6ea1SDimitry Andric   bool match(const MatchContext &Ctx, SDValue N) {
465*0fca6ea1SDimitry Andric     if (sd_context_match(N, Ctx, m_Opc(Opcode))) {
466*0fca6ea1SDimitry Andric       EffectiveOperands<ExcludeChain> EO(N);
467*0fca6ea1SDimitry Andric       assert(EO.Size == 3);
468*0fca6ea1SDimitry Andric       return ((Op0.match(Ctx, N->getOperand(EO.FirstIndex)) &&
469*0fca6ea1SDimitry Andric                Op1.match(Ctx, N->getOperand(EO.FirstIndex + 1))) ||
470*0fca6ea1SDimitry Andric               (Commutable && Op0.match(Ctx, N->getOperand(EO.FirstIndex + 1)) &&
471*0fca6ea1SDimitry Andric                Op1.match(Ctx, N->getOperand(EO.FirstIndex)))) &&
472*0fca6ea1SDimitry Andric              Op2.match(Ctx, N->getOperand(EO.FirstIndex + 2));
473*0fca6ea1SDimitry Andric     }
474*0fca6ea1SDimitry Andric 
475*0fca6ea1SDimitry Andric     return false;
476*0fca6ea1SDimitry Andric   }
477*0fca6ea1SDimitry Andric };
478*0fca6ea1SDimitry Andric 
479*0fca6ea1SDimitry Andric template <typename T0_P, typename T1_P, typename T2_P>
480*0fca6ea1SDimitry Andric inline TernaryOpc_match<T0_P, T1_P, T2_P, false, false>
481*0fca6ea1SDimitry Andric m_SetCC(const T0_P &LHS, const T1_P &RHS, const T2_P &CC) {
482*0fca6ea1SDimitry Andric   return TernaryOpc_match<T0_P, T1_P, T2_P, false, false>(ISD::SETCC, LHS, RHS,
483*0fca6ea1SDimitry Andric                                                           CC);
484*0fca6ea1SDimitry Andric }
485*0fca6ea1SDimitry Andric 
486*0fca6ea1SDimitry Andric template <typename T0_P, typename T1_P, typename T2_P>
487*0fca6ea1SDimitry Andric inline TernaryOpc_match<T0_P, T1_P, T2_P, true, false>
488*0fca6ea1SDimitry Andric m_c_SetCC(const T0_P &LHS, const T1_P &RHS, const T2_P &CC) {
489*0fca6ea1SDimitry Andric   return TernaryOpc_match<T0_P, T1_P, T2_P, true, false>(ISD::SETCC, LHS, RHS,
490*0fca6ea1SDimitry Andric                                                          CC);
491*0fca6ea1SDimitry Andric }
492*0fca6ea1SDimitry Andric 
493*0fca6ea1SDimitry Andric // === Binary operations ===
494*0fca6ea1SDimitry Andric template <typename LHS_P, typename RHS_P, bool Commutable = false,
495*0fca6ea1SDimitry Andric           bool ExcludeChain = false>
496*0fca6ea1SDimitry Andric struct BinaryOpc_match {
497*0fca6ea1SDimitry Andric   unsigned Opcode;
498*0fca6ea1SDimitry Andric   LHS_P LHS;
499*0fca6ea1SDimitry Andric   RHS_P RHS;
500*0fca6ea1SDimitry Andric 
501*0fca6ea1SDimitry Andric   BinaryOpc_match(unsigned Opc, const LHS_P &L, const RHS_P &R)
502*0fca6ea1SDimitry Andric       : Opcode(Opc), LHS(L), RHS(R) {}
503*0fca6ea1SDimitry Andric 
504*0fca6ea1SDimitry Andric   template <typename MatchContext>
505*0fca6ea1SDimitry Andric   bool match(const MatchContext &Ctx, SDValue N) {
506*0fca6ea1SDimitry Andric     if (sd_context_match(N, Ctx, m_Opc(Opcode))) {
507*0fca6ea1SDimitry Andric       EffectiveOperands<ExcludeChain> EO(N);
508*0fca6ea1SDimitry Andric       assert(EO.Size == 2);
509*0fca6ea1SDimitry Andric       return (LHS.match(Ctx, N->getOperand(EO.FirstIndex)) &&
510*0fca6ea1SDimitry Andric               RHS.match(Ctx, N->getOperand(EO.FirstIndex + 1))) ||
511*0fca6ea1SDimitry Andric              (Commutable && LHS.match(Ctx, N->getOperand(EO.FirstIndex + 1)) &&
512*0fca6ea1SDimitry Andric               RHS.match(Ctx, N->getOperand(EO.FirstIndex)));
513*0fca6ea1SDimitry Andric     }
514*0fca6ea1SDimitry Andric 
515*0fca6ea1SDimitry Andric     return false;
516*0fca6ea1SDimitry Andric   }
517*0fca6ea1SDimitry Andric };
518*0fca6ea1SDimitry Andric 
519*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
520*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_BinOp(unsigned Opc, const LHS &L,
521*0fca6ea1SDimitry Andric                                                 const RHS &R) {
522*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, false>(Opc, L, R);
523*0fca6ea1SDimitry Andric }
524*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
525*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_c_BinOp(unsigned Opc, const LHS &L,
526*0fca6ea1SDimitry Andric                                                  const RHS &R) {
527*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, true>(Opc, L, R);
528*0fca6ea1SDimitry Andric }
529*0fca6ea1SDimitry Andric 
530*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
531*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false, true>
532*0fca6ea1SDimitry Andric m_ChainedBinOp(unsigned Opc, const LHS &L, const RHS &R) {
533*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, false, true>(Opc, L, R);
534*0fca6ea1SDimitry Andric }
535*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
536*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true, true>
537*0fca6ea1SDimitry Andric m_c_ChainedBinOp(unsigned Opc, const LHS &L, const RHS &R) {
538*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, true, true>(Opc, L, R);
539*0fca6ea1SDimitry Andric }
540*0fca6ea1SDimitry Andric 
541*0fca6ea1SDimitry Andric // Common binary operations
542*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
543*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_Add(const LHS &L, const RHS &R) {
544*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, true>(ISD::ADD, L, R);
545*0fca6ea1SDimitry Andric }
546*0fca6ea1SDimitry Andric 
547*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
548*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_Sub(const LHS &L, const RHS &R) {
549*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, false>(ISD::SUB, L, R);
550*0fca6ea1SDimitry Andric }
551*0fca6ea1SDimitry Andric 
552*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
553*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_Mul(const LHS &L, const RHS &R) {
554*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, true>(ISD::MUL, L, R);
555*0fca6ea1SDimitry Andric }
556*0fca6ea1SDimitry Andric 
557*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
558*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_And(const LHS &L, const RHS &R) {
559*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, true>(ISD::AND, L, R);
560*0fca6ea1SDimitry Andric }
561*0fca6ea1SDimitry Andric 
562*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
563*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_Or(const LHS &L, const RHS &R) {
564*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, true>(ISD::OR, L, R);
565*0fca6ea1SDimitry Andric }
566*0fca6ea1SDimitry Andric 
567*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
568*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_Xor(const LHS &L, const RHS &R) {
569*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, true>(ISD::XOR, L, R);
570*0fca6ea1SDimitry Andric }
571*0fca6ea1SDimitry Andric 
572*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
573*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_SMin(const LHS &L, const RHS &R) {
574*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, true>(ISD::SMIN, L, R);
575*0fca6ea1SDimitry Andric }
576*0fca6ea1SDimitry Andric 
577*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
578*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_SMax(const LHS &L, const RHS &R) {
579*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, true>(ISD::SMAX, L, R);
580*0fca6ea1SDimitry Andric }
581*0fca6ea1SDimitry Andric 
582*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
583*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_UMin(const LHS &L, const RHS &R) {
584*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, true>(ISD::UMIN, L, R);
585*0fca6ea1SDimitry Andric }
586*0fca6ea1SDimitry Andric 
587*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
588*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_UMax(const LHS &L, const RHS &R) {
589*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, true>(ISD::UMAX, L, R);
590*0fca6ea1SDimitry Andric }
591*0fca6ea1SDimitry Andric 
592*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
593*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_UDiv(const LHS &L, const RHS &R) {
594*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, false>(ISD::UDIV, L, R);
595*0fca6ea1SDimitry Andric }
596*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
597*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_SDiv(const LHS &L, const RHS &R) {
598*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, false>(ISD::SDIV, L, R);
599*0fca6ea1SDimitry Andric }
600*0fca6ea1SDimitry Andric 
601*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
602*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_URem(const LHS &L, const RHS &R) {
603*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, false>(ISD::UREM, L, R);
604*0fca6ea1SDimitry Andric }
605*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
606*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_SRem(const LHS &L, const RHS &R) {
607*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, false>(ISD::SREM, L, R);
608*0fca6ea1SDimitry Andric }
609*0fca6ea1SDimitry Andric 
610*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
611*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_Shl(const LHS &L, const RHS &R) {
612*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, false>(ISD::SHL, L, R);
613*0fca6ea1SDimitry Andric }
614*0fca6ea1SDimitry Andric 
615*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
616*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_Sra(const LHS &L, const RHS &R) {
617*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, false>(ISD::SRA, L, R);
618*0fca6ea1SDimitry Andric }
619*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
620*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_Srl(const LHS &L, const RHS &R) {
621*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, false>(ISD::SRL, L, R);
622*0fca6ea1SDimitry Andric }
623*0fca6ea1SDimitry Andric 
624*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
625*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_FAdd(const LHS &L, const RHS &R) {
626*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, true>(ISD::FADD, L, R);
627*0fca6ea1SDimitry Andric }
628*0fca6ea1SDimitry Andric 
629*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
630*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_FSub(const LHS &L, const RHS &R) {
631*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, false>(ISD::FSUB, L, R);
632*0fca6ea1SDimitry Andric }
633*0fca6ea1SDimitry Andric 
634*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
635*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, true> m_FMul(const LHS &L, const RHS &R) {
636*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, true>(ISD::FMUL, L, R);
637*0fca6ea1SDimitry Andric }
638*0fca6ea1SDimitry Andric 
639*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
640*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_FDiv(const LHS &L, const RHS &R) {
641*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, false>(ISD::FDIV, L, R);
642*0fca6ea1SDimitry Andric }
643*0fca6ea1SDimitry Andric 
644*0fca6ea1SDimitry Andric template <typename LHS, typename RHS>
645*0fca6ea1SDimitry Andric inline BinaryOpc_match<LHS, RHS, false> m_FRem(const LHS &L, const RHS &R) {
646*0fca6ea1SDimitry Andric   return BinaryOpc_match<LHS, RHS, false>(ISD::FREM, L, R);
647*0fca6ea1SDimitry Andric }
648*0fca6ea1SDimitry Andric 
649*0fca6ea1SDimitry Andric // === Unary operations ===
650*0fca6ea1SDimitry Andric template <typename Opnd_P, bool ExcludeChain = false> struct UnaryOpc_match {
651*0fca6ea1SDimitry Andric   unsigned Opcode;
652*0fca6ea1SDimitry Andric   Opnd_P Opnd;
653*0fca6ea1SDimitry Andric 
654*0fca6ea1SDimitry Andric   UnaryOpc_match(unsigned Opc, const Opnd_P &Op) : Opcode(Opc), Opnd(Op) {}
655*0fca6ea1SDimitry Andric 
656*0fca6ea1SDimitry Andric   template <typename MatchContext>
657*0fca6ea1SDimitry Andric   bool match(const MatchContext &Ctx, SDValue N) {
658*0fca6ea1SDimitry Andric     if (sd_context_match(N, Ctx, m_Opc(Opcode))) {
659*0fca6ea1SDimitry Andric       EffectiveOperands<ExcludeChain> EO(N);
660*0fca6ea1SDimitry Andric       assert(EO.Size == 1);
661*0fca6ea1SDimitry Andric       return Opnd.match(Ctx, N->getOperand(EO.FirstIndex));
662*0fca6ea1SDimitry Andric     }
663*0fca6ea1SDimitry Andric 
664*0fca6ea1SDimitry Andric     return false;
665*0fca6ea1SDimitry Andric   }
666*0fca6ea1SDimitry Andric };
667*0fca6ea1SDimitry Andric 
668*0fca6ea1SDimitry Andric template <typename Opnd>
669*0fca6ea1SDimitry Andric inline UnaryOpc_match<Opnd> m_UnaryOp(unsigned Opc, const Opnd &Op) {
670*0fca6ea1SDimitry Andric   return UnaryOpc_match<Opnd>(Opc, Op);
671*0fca6ea1SDimitry Andric }
672*0fca6ea1SDimitry Andric template <typename Opnd>
673*0fca6ea1SDimitry Andric inline UnaryOpc_match<Opnd, true> m_ChainedUnaryOp(unsigned Opc,
674*0fca6ea1SDimitry Andric                                                    const Opnd &Op) {
675*0fca6ea1SDimitry Andric   return UnaryOpc_match<Opnd, true>(Opc, Op);
676*0fca6ea1SDimitry Andric }
677*0fca6ea1SDimitry Andric 
678*0fca6ea1SDimitry Andric template <typename Opnd>
679*0fca6ea1SDimitry Andric inline UnaryOpc_match<Opnd> m_BitReverse(const Opnd &Op) {
680*0fca6ea1SDimitry Andric   return UnaryOpc_match<Opnd>(ISD::BITREVERSE, Op);
681*0fca6ea1SDimitry Andric }
682*0fca6ea1SDimitry Andric 
683*0fca6ea1SDimitry Andric template <typename Opnd> inline UnaryOpc_match<Opnd> m_ZExt(const Opnd &Op) {
684*0fca6ea1SDimitry Andric   return UnaryOpc_match<Opnd>(ISD::ZERO_EXTEND, Op);
685*0fca6ea1SDimitry Andric }
686*0fca6ea1SDimitry Andric 
687*0fca6ea1SDimitry Andric template <typename Opnd> inline auto m_SExt(const Opnd &Op) {
688*0fca6ea1SDimitry Andric   return UnaryOpc_match<Opnd>(ISD::SIGN_EXTEND, Op);
689*0fca6ea1SDimitry Andric }
690*0fca6ea1SDimitry Andric 
691*0fca6ea1SDimitry Andric template <typename Opnd> inline UnaryOpc_match<Opnd> m_AnyExt(const Opnd &Op) {
692*0fca6ea1SDimitry Andric   return UnaryOpc_match<Opnd>(ISD::ANY_EXTEND, Op);
693*0fca6ea1SDimitry Andric }
694*0fca6ea1SDimitry Andric 
695*0fca6ea1SDimitry Andric template <typename Opnd> inline UnaryOpc_match<Opnd> m_Trunc(const Opnd &Op) {
696*0fca6ea1SDimitry Andric   return UnaryOpc_match<Opnd>(ISD::TRUNCATE, Op);
697*0fca6ea1SDimitry Andric }
698*0fca6ea1SDimitry Andric 
699*0fca6ea1SDimitry Andric /// Match a zext or identity
700*0fca6ea1SDimitry Andric /// Allows to peek through optional extensions
701*0fca6ea1SDimitry Andric template <typename Opnd> inline auto m_ZExtOrSelf(const Opnd &Op) {
702*0fca6ea1SDimitry Andric   return m_AnyOf(m_ZExt(Op), Op);
703*0fca6ea1SDimitry Andric }
704*0fca6ea1SDimitry Andric 
705*0fca6ea1SDimitry Andric /// Match a sext or identity
706*0fca6ea1SDimitry Andric /// Allows to peek through optional extensions
707*0fca6ea1SDimitry Andric template <typename Opnd> inline auto m_SExtOrSelf(const Opnd &Op) {
708*0fca6ea1SDimitry Andric   return m_AnyOf(m_SExt(Op), Op);
709*0fca6ea1SDimitry Andric }
710*0fca6ea1SDimitry Andric 
711*0fca6ea1SDimitry Andric /// Match a aext or identity
712*0fca6ea1SDimitry Andric /// Allows to peek through optional extensions
713*0fca6ea1SDimitry Andric template <typename Opnd>
714*0fca6ea1SDimitry Andric inline Or<UnaryOpc_match<Opnd>, Opnd> m_AExtOrSelf(const Opnd &Op) {
715*0fca6ea1SDimitry Andric   return Or<UnaryOpc_match<Opnd>, Opnd>(m_AnyExt(Op), Op);
716*0fca6ea1SDimitry Andric }
717*0fca6ea1SDimitry Andric 
718*0fca6ea1SDimitry Andric /// Match a trunc or identity
719*0fca6ea1SDimitry Andric /// Allows to peek through optional truncations
720*0fca6ea1SDimitry Andric template <typename Opnd>
721*0fca6ea1SDimitry Andric inline Or<UnaryOpc_match<Opnd>, Opnd> m_TruncOrSelf(const Opnd &Op) {
722*0fca6ea1SDimitry Andric   return Or<UnaryOpc_match<Opnd>, Opnd>(m_Trunc(Op), Op);
723*0fca6ea1SDimitry Andric }
724*0fca6ea1SDimitry Andric 
725*0fca6ea1SDimitry Andric // === Constants ===
726*0fca6ea1SDimitry Andric struct ConstantInt_match {
727*0fca6ea1SDimitry Andric   APInt *BindVal;
728*0fca6ea1SDimitry Andric 
729*0fca6ea1SDimitry Andric   explicit ConstantInt_match(APInt *V) : BindVal(V) {}
730*0fca6ea1SDimitry Andric 
731*0fca6ea1SDimitry Andric   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
732*0fca6ea1SDimitry Andric     // The logics here are similar to that in
733*0fca6ea1SDimitry Andric     // SelectionDAG::isConstantIntBuildVectorOrConstantInt, but the latter also
734*0fca6ea1SDimitry Andric     // treats GlobalAddressSDNode as a constant, which is difficult to turn into
735*0fca6ea1SDimitry Andric     // APInt.
736*0fca6ea1SDimitry Andric     if (auto *C = dyn_cast_or_null<ConstantSDNode>(N.getNode())) {
737*0fca6ea1SDimitry Andric       if (BindVal)
738*0fca6ea1SDimitry Andric         *BindVal = C->getAPIntValue();
739*0fca6ea1SDimitry Andric       return true;
740*0fca6ea1SDimitry Andric     }
741*0fca6ea1SDimitry Andric 
742*0fca6ea1SDimitry Andric     APInt Discard;
743*0fca6ea1SDimitry Andric     return ISD::isConstantSplatVector(N.getNode(),
744*0fca6ea1SDimitry Andric                                       BindVal ? *BindVal : Discard);
745*0fca6ea1SDimitry Andric   }
746*0fca6ea1SDimitry Andric };
747*0fca6ea1SDimitry Andric /// Match any interger constants or splat of an integer constant.
748*0fca6ea1SDimitry Andric inline ConstantInt_match m_ConstInt() { return ConstantInt_match(nullptr); }
749*0fca6ea1SDimitry Andric /// Match any interger constants or splat of an integer constant; return the
750*0fca6ea1SDimitry Andric /// specific constant or constant splat value.
751*0fca6ea1SDimitry Andric inline ConstantInt_match m_ConstInt(APInt &V) { return ConstantInt_match(&V); }
752*0fca6ea1SDimitry Andric 
753*0fca6ea1SDimitry Andric struct SpecificInt_match {
754*0fca6ea1SDimitry Andric   APInt IntVal;
755*0fca6ea1SDimitry Andric 
756*0fca6ea1SDimitry Andric   explicit SpecificInt_match(APInt APV) : IntVal(std::move(APV)) {}
757*0fca6ea1SDimitry Andric 
758*0fca6ea1SDimitry Andric   template <typename MatchContext>
759*0fca6ea1SDimitry Andric   bool match(const MatchContext &Ctx, SDValue N) {
760*0fca6ea1SDimitry Andric     APInt ConstInt;
761*0fca6ea1SDimitry Andric     if (sd_context_match(N, Ctx, m_ConstInt(ConstInt)))
762*0fca6ea1SDimitry Andric       return APInt::isSameValue(IntVal, ConstInt);
763*0fca6ea1SDimitry Andric     return false;
764*0fca6ea1SDimitry Andric   }
765*0fca6ea1SDimitry Andric };
766*0fca6ea1SDimitry Andric 
767*0fca6ea1SDimitry Andric /// Match a specific integer constant or constant splat value.
768*0fca6ea1SDimitry Andric inline SpecificInt_match m_SpecificInt(APInt V) {
769*0fca6ea1SDimitry Andric   return SpecificInt_match(std::move(V));
770*0fca6ea1SDimitry Andric }
771*0fca6ea1SDimitry Andric inline SpecificInt_match m_SpecificInt(uint64_t V) {
772*0fca6ea1SDimitry Andric   return SpecificInt_match(APInt(64, V));
773*0fca6ea1SDimitry Andric }
774*0fca6ea1SDimitry Andric 
775*0fca6ea1SDimitry Andric inline SpecificInt_match m_Zero() { return m_SpecificInt(0U); }
776*0fca6ea1SDimitry Andric inline SpecificInt_match m_One() { return m_SpecificInt(1U); }
777*0fca6ea1SDimitry Andric 
778*0fca6ea1SDimitry Andric struct AllOnes_match {
779*0fca6ea1SDimitry Andric 
780*0fca6ea1SDimitry Andric   AllOnes_match() = default;
781*0fca6ea1SDimitry Andric 
782*0fca6ea1SDimitry Andric   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
783*0fca6ea1SDimitry Andric     return isAllOnesOrAllOnesSplat(N);
784*0fca6ea1SDimitry Andric   }
785*0fca6ea1SDimitry Andric };
786*0fca6ea1SDimitry Andric 
787*0fca6ea1SDimitry Andric inline AllOnes_match m_AllOnes() { return AllOnes_match(); }
788*0fca6ea1SDimitry Andric 
789*0fca6ea1SDimitry Andric /// Match true boolean value based on the information provided by
790*0fca6ea1SDimitry Andric /// TargetLowering.
791*0fca6ea1SDimitry Andric inline auto m_True() {
792*0fca6ea1SDimitry Andric   return TLI_pred_match{
793*0fca6ea1SDimitry Andric       [](const TargetLowering &TLI, SDValue N) {
794*0fca6ea1SDimitry Andric         APInt ConstVal;
795*0fca6ea1SDimitry Andric         if (sd_match(N, m_ConstInt(ConstVal)))
796*0fca6ea1SDimitry Andric           switch (TLI.getBooleanContents(N.getValueType())) {
797*0fca6ea1SDimitry Andric           case TargetLowering::ZeroOrOneBooleanContent:
798*0fca6ea1SDimitry Andric             return ConstVal.isOne();
799*0fca6ea1SDimitry Andric           case TargetLowering::ZeroOrNegativeOneBooleanContent:
800*0fca6ea1SDimitry Andric             return ConstVal.isAllOnes();
801*0fca6ea1SDimitry Andric           case TargetLowering::UndefinedBooleanContent:
802*0fca6ea1SDimitry Andric             return (ConstVal & 0x01) == 1;
803*0fca6ea1SDimitry Andric           }
804*0fca6ea1SDimitry Andric 
805*0fca6ea1SDimitry Andric         return false;
806*0fca6ea1SDimitry Andric       },
807*0fca6ea1SDimitry Andric       m_Value()};
808*0fca6ea1SDimitry Andric }
809*0fca6ea1SDimitry Andric /// Match false boolean value based on the information provided by
810*0fca6ea1SDimitry Andric /// TargetLowering.
811*0fca6ea1SDimitry Andric inline auto m_False() {
812*0fca6ea1SDimitry Andric   return TLI_pred_match{
813*0fca6ea1SDimitry Andric       [](const TargetLowering &TLI, SDValue N) {
814*0fca6ea1SDimitry Andric         APInt ConstVal;
815*0fca6ea1SDimitry Andric         if (sd_match(N, m_ConstInt(ConstVal)))
816*0fca6ea1SDimitry Andric           switch (TLI.getBooleanContents(N.getValueType())) {
817*0fca6ea1SDimitry Andric           case TargetLowering::ZeroOrOneBooleanContent:
818*0fca6ea1SDimitry Andric           case TargetLowering::ZeroOrNegativeOneBooleanContent:
819*0fca6ea1SDimitry Andric             return ConstVal.isZero();
820*0fca6ea1SDimitry Andric           case TargetLowering::UndefinedBooleanContent:
821*0fca6ea1SDimitry Andric             return (ConstVal & 0x01) == 0;
822*0fca6ea1SDimitry Andric           }
823*0fca6ea1SDimitry Andric 
824*0fca6ea1SDimitry Andric         return false;
825*0fca6ea1SDimitry Andric       },
826*0fca6ea1SDimitry Andric       m_Value()};
827*0fca6ea1SDimitry Andric }
828*0fca6ea1SDimitry Andric 
829*0fca6ea1SDimitry Andric struct CondCode_match {
830*0fca6ea1SDimitry Andric   std::optional<ISD::CondCode> CCToMatch;
831*0fca6ea1SDimitry Andric   ISD::CondCode *BindCC = nullptr;
832*0fca6ea1SDimitry Andric 
833*0fca6ea1SDimitry Andric   explicit CondCode_match(ISD::CondCode CC) : CCToMatch(CC) {}
834*0fca6ea1SDimitry Andric 
835*0fca6ea1SDimitry Andric   explicit CondCode_match(ISD::CondCode *CC) : BindCC(CC) {}
836*0fca6ea1SDimitry Andric 
837*0fca6ea1SDimitry Andric   template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
838*0fca6ea1SDimitry Andric     if (auto *CC = dyn_cast<CondCodeSDNode>(N.getNode())) {
839*0fca6ea1SDimitry Andric       if (CCToMatch && *CCToMatch != CC->get())
840*0fca6ea1SDimitry Andric         return false;
841*0fca6ea1SDimitry Andric 
842*0fca6ea1SDimitry Andric       if (BindCC)
843*0fca6ea1SDimitry Andric         *BindCC = CC->get();
844*0fca6ea1SDimitry Andric       return true;
845*0fca6ea1SDimitry Andric     }
846*0fca6ea1SDimitry Andric 
847*0fca6ea1SDimitry Andric     return false;
848*0fca6ea1SDimitry Andric   }
849*0fca6ea1SDimitry Andric };
850*0fca6ea1SDimitry Andric 
851*0fca6ea1SDimitry Andric /// Match any conditional code SDNode.
852*0fca6ea1SDimitry Andric inline CondCode_match m_CondCode() { return CondCode_match(nullptr); }
853*0fca6ea1SDimitry Andric /// Match any conditional code SDNode and return its ISD::CondCode value.
854*0fca6ea1SDimitry Andric inline CondCode_match m_CondCode(ISD::CondCode &CC) {
855*0fca6ea1SDimitry Andric   return CondCode_match(&CC);
856*0fca6ea1SDimitry Andric }
857*0fca6ea1SDimitry Andric /// Match a conditional code SDNode with a specific ISD::CondCode.
858*0fca6ea1SDimitry Andric inline CondCode_match m_SpecificCondCode(ISD::CondCode CC) {
859*0fca6ea1SDimitry Andric   return CondCode_match(CC);
860*0fca6ea1SDimitry Andric }
861*0fca6ea1SDimitry Andric 
862*0fca6ea1SDimitry Andric /// Match a negate as a sub(0, v)
863*0fca6ea1SDimitry Andric template <typename ValTy>
864*0fca6ea1SDimitry Andric inline BinaryOpc_match<SpecificInt_match, ValTy> m_Neg(const ValTy &V) {
865*0fca6ea1SDimitry Andric   return m_Sub(m_Zero(), V);
866*0fca6ea1SDimitry Andric }
867*0fca6ea1SDimitry Andric 
868*0fca6ea1SDimitry Andric /// Match a Not as a xor(v, -1) or xor(-1, v)
869*0fca6ea1SDimitry Andric template <typename ValTy>
870*0fca6ea1SDimitry Andric inline BinaryOpc_match<ValTy, AllOnes_match, true> m_Not(const ValTy &V) {
871*0fca6ea1SDimitry Andric   return m_Xor(V, m_AllOnes());
872*0fca6ea1SDimitry Andric }
873*0fca6ea1SDimitry Andric 
874*0fca6ea1SDimitry Andric } // namespace SDPatternMatch
875*0fca6ea1SDimitry Andric } // namespace llvm
876*0fca6ea1SDimitry Andric #endif
877