1//==--------------- llvm/CodeGen/SDPatternMatch.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 SelectionDAG nodes and values.
10///
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_CODEGEN_SDPATTERNMATCH_H
14#define LLVM_CODEGEN_SDPATTERNMATCH_H
15
16#include "llvm/ADT/APInt.h"
17#include "llvm/ADT/ArrayRef.h"
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/SmallBitVector.h"
20#include "llvm/ADT/bit.h"
21#include "llvm/CodeGen/SelectionDAG.h"
22#include "llvm/CodeGen/SelectionDAGNodes.h"
23#include "llvm/CodeGen/TargetLowering.h"
24#include "llvm/Support/KnownBits.h"
25
26#include <type_traits>
27
28namespace llvm {
29namespace SDPatternMatch {
30
31/// MatchContext can repurpose existing patterns to behave differently under
32/// a certain context. For instance, `m_SpecificOpc(ISD::ADD)` matches plain ADD
33/// nodes in normal circumstances, but matches VP_ADD nodes under a custom
34/// VPMatchContext. This design is meant to facilitate code / pattern reusing.
35/// TODO: Remove now that we don't need to match over VP nodes.
36
37class BasicMatchContext {
38 const SelectionDAG *DAG;
39 const TargetLowering *TLI;
40
41public:
42 explicit BasicMatchContext(const SelectionDAG *DAG)
43 : DAG(DAG), TLI(DAG ? &DAG->getTargetLoweringInfo() : nullptr) {}
44
45 explicit BasicMatchContext(const TargetLowering *TLI)
46 : DAG(nullptr), TLI(TLI) {}
47
48 // A valid MatchContext has to implement the following functions.
49
50 const SelectionDAG *getDAG() const { return DAG; }
51
52 const TargetLowering *getTLI() const { return TLI; }
53
54 /// Return true if N effectively has opcode Opcode.
55 bool match(SDValue N, unsigned Opcode) const {
56 return N->getOpcode() == Opcode;
57 }
58
59 unsigned getNumOperands(SDValue N) const { return N->getNumOperands(); }
60};
61
62template <typename Pattern, typename MatchContext>
63[[nodiscard]] bool sd_context_match(SDValue N, const MatchContext &Ctx,
64 Pattern &&P) {
65 return P.match(Ctx, N);
66}
67
68template <typename Pattern, typename MatchContext>
69[[nodiscard]] bool sd_context_match(SDNode *N, const MatchContext &Ctx,
70 Pattern &&P) {
71 return sd_context_match(SDValue(N, 0), Ctx, P);
72}
73
74template <typename Pattern>
75[[nodiscard]] bool sd_match(SDNode *N, const SelectionDAG *DAG, Pattern &&P) {
76 return sd_context_match(N, BasicMatchContext(DAG), P);
77}
78
79template <typename Pattern>
80[[nodiscard]] bool sd_match(SDValue N, const SelectionDAG *DAG, Pattern &&P) {
81 return sd_context_match(N, BasicMatchContext(DAG), P);
82}
83
84template <typename Pattern>
85[[nodiscard]] bool sd_match(SDNode *N, Pattern &&P) {
86 return sd_match(N, nullptr, P);
87}
88
89template <typename Pattern>
90[[nodiscard]] bool sd_match(SDValue N, Pattern &&P) {
91 return sd_match(N, nullptr, P);
92}
93
94// === Utilities ===
95struct Value_match {
96 SDValue MatchVal;
97
98 Value_match() = default;
99
100 explicit Value_match(SDValue Match) : MatchVal(Match) {}
101
102 template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
103 if (MatchVal)
104 return MatchVal == N;
105 return N.getNode();
106 }
107};
108
109/// Match any valid SDValue.
110inline Value_match m_Value() { return Value_match(); }
111
112inline Value_match m_Specific(SDValue N) {
113 assert(N);
114 return Value_match(N);
115}
116
117template <unsigned ResNo, typename Pattern> struct Result_match {
118 Pattern P;
119
120 explicit Result_match(const Pattern &P) : P(P) {}
121
122 template <typename MatchContext>
123 bool match(const MatchContext &Ctx, SDValue N) {
124 return N.getResNo() == ResNo && P.match(Ctx, N);
125 }
126};
127
128/// Match only if the SDValue is a certain result at ResNo.
129template <unsigned ResNo, typename Pattern>
130inline Result_match<ResNo, Pattern> m_Result(const Pattern &P) {
131 return Result_match<ResNo, Pattern>(P);
132}
133
134struct DeferredValue_match {
135 SDValue &MatchVal;
136
137 explicit DeferredValue_match(SDValue &Match) : MatchVal(Match) {}
138
139 template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
140 return N == MatchVal;
141 }
142};
143
144/// Similar to m_Specific, but the specific value to match is determined by
145/// another sub-pattern in the same sd_match() expression. For instance,
146/// We cannot match `(add V, V)` with `m_Add(m_Value(X), m_Specific(X))` since
147/// `X` is not initialized at the time it got copied into `m_Specific`. Instead,
148/// we should use `m_Add(m_Value(X), m_Deferred(X))`.
149inline DeferredValue_match m_Deferred(SDValue &V) {
150 return DeferredValue_match(V);
151}
152
153struct Opcode_match {
154 unsigned Opcode;
155
156 explicit Opcode_match(unsigned Opc) : Opcode(Opc) {}
157
158 template <typename MatchContext>
159 bool match(const MatchContext &Ctx, SDValue N) {
160 return Ctx.match(N, Opcode);
161 }
162};
163
164// === Patterns combinators ===
165template <typename... Preds> struct And {
166 template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
167 return true;
168 }
169};
170
171template <typename Pred, typename... Preds>
172struct And<Pred, Preds...> : And<Preds...> {
173 Pred P;
174 And(const Pred &p, const Preds &...preds) : And<Preds...>(preds...), P(p) {}
175
176 template <typename MatchContext>
177 bool match(const MatchContext &Ctx, SDValue N) {
178 return P.match(Ctx, N) && And<Preds...>::match(Ctx, N);
179 }
180};
181
182template <typename... Preds> struct Or {
183 template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
184 return false;
185 }
186};
187
188template <typename Pred, typename... Preds>
189struct Or<Pred, Preds...> : Or<Preds...> {
190 Pred P;
191 Or(const Pred &p, const Preds &...preds) : Or<Preds...>(preds...), P(p) {}
192
193 template <typename MatchContext>
194 bool match(const MatchContext &Ctx, SDValue N) {
195 return P.match(Ctx, N) || Or<Preds...>::match(Ctx, N);
196 }
197};
198
199template <typename Pred> struct Not {
200 Pred P;
201
202 explicit Not(const Pred &P) : P(P) {}
203
204 template <typename MatchContext>
205 bool match(const MatchContext &Ctx, SDValue N) {
206 return !P.match(Ctx, N);
207 }
208};
209// Explicit deduction guide.
210template <typename Pred> Not(const Pred &P) -> Not<Pred>;
211
212/// Match if the inner pattern does NOT match.
213template <typename Pred> inline Not<Pred> m_Unless(const Pred &P) {
214 return Not{P};
215}
216
217template <typename... Preds> And<Preds...> m_AllOf(const Preds &...preds) {
218 return And<Preds...>(preds...);
219}
220
221template <typename... Preds> Or<Preds...> m_AnyOf(const Preds &...preds) {
222 return Or<Preds...>(preds...);
223}
224
225template <typename... Preds> auto m_NoneOf(const Preds &...preds) {
226 return m_Unless(m_AnyOf(preds...));
227}
228
229inline Opcode_match m_SpecificOpc(unsigned Opcode) {
230 return Opcode_match(Opcode);
231}
232
233inline auto m_Undef() {
234 return m_AnyOf(preds: Opcode_match(ISD::UNDEF), preds: Opcode_match(ISD::POISON));
235}
236
237inline Opcode_match m_Poison() { return Opcode_match(ISD::POISON); }
238
239template <unsigned NumUses, typename Pattern> struct NUses_match {
240 Pattern P;
241
242 explicit NUses_match(const Pattern &P) : P(P) {}
243
244 template <typename MatchContext>
245 bool match(const MatchContext &Ctx, SDValue N) {
246 // SDNode::hasNUsesOfValue is pretty expensive when the SDNode produces
247 // multiple results, hence we check the subsequent pattern here before
248 // checking the number of value users.
249 return P.match(Ctx, N) && N->hasNUsesOfValue(NUses: NumUses, Value: N.getResNo());
250 }
251};
252
253template <typename Pattern>
254inline NUses_match<1, Pattern> m_OneUse(const Pattern &P) {
255 return NUses_match<1, Pattern>(P);
256}
257template <unsigned N, typename Pattern>
258inline NUses_match<N, Pattern> m_NUses(const Pattern &P) {
259 return NUses_match<N, Pattern>(P);
260}
261
262inline NUses_match<1, Value_match> m_OneUse() {
263 return NUses_match<1, Value_match>(m_Value());
264}
265template <unsigned N> inline NUses_match<N, Value_match> m_NUses() {
266 return NUses_match<N, Value_match>(m_Value());
267}
268
269template <typename PredPattern> struct Value_bind {
270 SDValue &BindVal;
271 PredPattern Pred;
272
273 Value_bind(SDValue &N, const PredPattern &P) : BindVal(N), Pred(P) {}
274
275 template <typename MatchContext>
276 bool match(const MatchContext &Ctx, SDValue N) {
277 if (!Pred.match(Ctx, N))
278 return false;
279
280 BindVal = N;
281 return true;
282 }
283};
284
285inline auto m_Value(SDValue &N) {
286 return Value_bind<Value_match>(N, m_Value());
287}
288/// Conditionally bind an SDValue based on the predicate.
289template <typename PredPattern>
290inline auto m_Value(SDValue &N, const PredPattern &P) {
291 return Value_bind<PredPattern>(N, P);
292}
293
294template <typename Pattern, typename PredFuncT> struct TLI_pred_match {
295 Pattern P;
296 PredFuncT PredFunc;
297
298 TLI_pred_match(const PredFuncT &Pred, const Pattern &P)
299 : P(P), PredFunc(Pred) {}
300
301 template <typename MatchContext>
302 bool match(const MatchContext &Ctx, SDValue N) {
303 assert(Ctx.getTLI() && "TargetLowering is required for this pattern.");
304 return PredFunc(*Ctx.getTLI(), N) && P.match(Ctx, N);
305 }
306};
307
308// Explicit deduction guide.
309template <typename PredFuncT, typename Pattern>
310TLI_pred_match(const PredFuncT &Pred, const Pattern &P)
311 -> TLI_pred_match<Pattern, PredFuncT>;
312
313/// Match legal SDNodes based on the information provided by TargetLowering.
314template <typename Pattern> inline auto m_LegalOp(const Pattern &P) {
315 return TLI_pred_match{[](const TargetLowering &TLI, SDValue N) {
316 return TLI.isOperationLegal(Op: N->getOpcode(),
317 VT: N.getValueType());
318 },
319 P};
320}
321
322/// Switch to a different MatchContext for subsequent patterns.
323template <typename NewMatchContext, typename Pattern> struct SwitchContext {
324 const NewMatchContext &Ctx;
325 Pattern P;
326
327 template <typename OrigMatchContext>
328 bool match(const OrigMatchContext &, SDValue N) {
329 return P.match(Ctx, N);
330 }
331};
332
333template <typename MatchContext, typename Pattern>
334inline SwitchContext<MatchContext, Pattern> m_Context(const MatchContext &Ctx,
335 Pattern &&P) {
336 return SwitchContext<MatchContext, Pattern>{Ctx, std::move(P)};
337}
338
339// === Value type ===
340
341template <typename Pattern> struct ValueType_bind {
342 EVT &BindVT;
343 Pattern P;
344
345 explicit ValueType_bind(EVT &Bind, const Pattern &P) : BindVT(Bind), P(P) {}
346
347 template <typename MatchContext>
348 bool match(const MatchContext &Ctx, SDValue N) {
349 BindVT = N.getValueType();
350 return P.match(Ctx, N);
351 }
352};
353
354template <typename Pattern>
355ValueType_bind(const Pattern &P) -> ValueType_bind<Pattern>;
356
357/// Retreive the ValueType of the current SDValue.
358inline auto m_VT(EVT &VT) { return ValueType_bind(VT, m_Value()); }
359
360template <typename Pattern> inline auto m_VT(EVT &VT, const Pattern &P) {
361 return ValueType_bind(VT, P);
362}
363
364template <typename Pattern, typename PredFuncT> struct ValueType_match {
365 PredFuncT PredFunc;
366 Pattern P;
367
368 ValueType_match(const PredFuncT &Pred, const Pattern &P)
369 : PredFunc(Pred), P(P) {}
370
371 template <typename MatchContext>
372 bool match(const MatchContext &Ctx, SDValue N) {
373 return PredFunc(N.getValueType()) && P.match(Ctx, N);
374 }
375};
376
377// Explicit deduction guide.
378template <typename PredFuncT, typename Pattern>
379ValueType_match(const PredFuncT &Pred, const Pattern &P)
380 -> ValueType_match<Pattern, PredFuncT>;
381
382/// Match a specific ValueType.
383template <typename Pattern>
384inline auto m_SpecificVT(EVT RefVT, const Pattern &P) {
385 return ValueType_match{[=](EVT VT) { return VT == RefVT; }, P};
386}
387inline auto m_SpecificVT(EVT RefVT) {
388 return ValueType_match{[=](EVT VT) { return VT == RefVT; }, m_Value()};
389}
390
391inline auto m_Glue() { return m_SpecificVT(RefVT: MVT::Glue); }
392inline auto m_OtherVT() { return m_SpecificVT(RefVT: MVT::Other); }
393
394/// Match a scalar ValueType.
395template <typename Pattern>
396inline auto m_SpecificScalarVT(EVT RefVT, const Pattern &P) {
397 return ValueType_match{[=](EVT VT) { return VT.getScalarType() == RefVT; },
398 P};
399}
400inline auto m_SpecificScalarVT(EVT RefVT) {
401 return ValueType_match{[=](EVT VT) { return VT.getScalarType() == RefVT; },
402 m_Value()};
403}
404
405/// Match a vector ValueType.
406template <typename Pattern>
407inline auto m_SpecificVectorElementVT(EVT RefVT, const Pattern &P) {
408 return ValueType_match{[=](EVT VT) {
409 return VT.isVector() &&
410 VT.getVectorElementType() == RefVT;
411 },
412 P};
413}
414inline auto m_SpecificVectorElementVT(EVT RefVT) {
415 return ValueType_match{[=](EVT VT) {
416 return VT.isVector() &&
417 VT.getVectorElementType() == RefVT;
418 },
419 m_Value()};
420}
421
422/// Match any integer ValueTypes.
423template <typename Pattern> inline auto m_IntegerVT(const Pattern &P) {
424 return ValueType_match{[](EVT VT) { return VT.isInteger(); }, P};
425}
426inline auto m_IntegerVT() {
427 return ValueType_match{[](EVT VT) { return VT.isInteger(); }, m_Value()};
428}
429
430/// Match any floating point ValueTypes.
431template <typename Pattern> inline auto m_FloatingPointVT(const Pattern &P) {
432 return ValueType_match{[](EVT VT) { return VT.isFloatingPoint(); }, P};
433}
434inline auto m_FloatingPointVT() {
435 return ValueType_match{[](EVT VT) { return VT.isFloatingPoint(); },
436 m_Value()};
437}
438
439/// Match any vector ValueTypes.
440template <typename Pattern> inline auto m_VectorVT(const Pattern &P) {
441 return ValueType_match{[](EVT VT) { return VT.isVector(); }, P};
442}
443inline auto m_VectorVT() {
444 return ValueType_match{[](EVT VT) { return VT.isVector(); }, m_Value()};
445}
446
447/// Match fixed-length vector ValueTypes.
448template <typename Pattern> inline auto m_FixedVectorVT(const Pattern &P) {
449 return ValueType_match{[](EVT VT) { return VT.isFixedLengthVector(); }, P};
450}
451inline auto m_FixedVectorVT() {
452 return ValueType_match{[](EVT VT) { return VT.isFixedLengthVector(); },
453 m_Value()};
454}
455
456/// Match scalable vector ValueTypes.
457template <typename Pattern> inline auto m_ScalableVectorVT(const Pattern &P) {
458 return ValueType_match{[](EVT VT) { return VT.isScalableVector(); }, P};
459}
460inline auto m_ScalableVectorVT() {
461 return ValueType_match{[](EVT VT) { return VT.isScalableVector(); },
462 m_Value()};
463}
464
465/// Match legal ValueTypes based on the information provided by TargetLowering.
466template <typename Pattern> inline auto m_LegalType(const Pattern &P) {
467 return TLI_pred_match{[](const TargetLowering &TLI, SDValue N) {
468 return TLI.isTypeLegal(VT: N.getValueType());
469 },
470 P};
471}
472
473// === Generic node matching ===
474template <unsigned OpIdx, typename... OpndPreds> struct Operands_match {
475 template <typename MatchContext>
476 bool match(const MatchContext &Ctx, SDValue N) {
477 // Returns false if there are more operands than predicates;
478 // Ignores the last two operands if both the Context and the Node are VP
479 return Ctx.getNumOperands(N) == OpIdx;
480 }
481};
482
483template <unsigned OpIdx, typename OpndPred, typename... OpndPreds>
484struct Operands_match<OpIdx, OpndPred, OpndPreds...>
485 : Operands_match<OpIdx + 1, OpndPreds...> {
486 OpndPred P;
487
488 Operands_match(const OpndPred &p, const OpndPreds &...preds)
489 : Operands_match<OpIdx + 1, OpndPreds...>(preds...), P(p) {}
490
491 template <typename MatchContext>
492 bool match(const MatchContext &Ctx, SDValue N) {
493 if (OpIdx < N->getNumOperands())
494 return P.match(Ctx, N->getOperand(Num: OpIdx)) &&
495 Operands_match<OpIdx + 1, OpndPreds...>::match(Ctx, N);
496
497 // This is the case where there are more predicates than operands.
498 return false;
499 }
500};
501
502template <typename... OpndPreds>
503auto m_Node(unsigned Opcode, const OpndPreds &...preds) {
504 return m_AllOf(m_SpecificOpc(Opcode),
505 Operands_match<0, OpndPreds...>(preds...));
506}
507
508/// Provide number of operands that are not chain or glue, as well as the first
509/// index of such operand.
510template <bool ExcludeChain> struct EffectiveOperands {
511 unsigned Size = 0;
512 unsigned FirstIndex = 0;
513
514 template <typename MatchContext>
515 explicit EffectiveOperands(SDValue N, const MatchContext &Ctx) {
516 const unsigned TotalNumOps = Ctx.getNumOperands(N);
517 FirstIndex = TotalNumOps;
518 for (unsigned I = 0; I < TotalNumOps; ++I) {
519 // Count the number of non-chain and non-glue nodes (we ignore chain
520 // and glue by default) and retreive the operand index offset.
521 EVT VT = N->getOperand(Num: I).getValueType();
522 if (VT != MVT::Glue && VT != MVT::Other) {
523 ++Size;
524 if (FirstIndex == TotalNumOps)
525 FirstIndex = I;
526 }
527 }
528 }
529};
530
531template <> struct EffectiveOperands<false> {
532 unsigned Size = 0;
533 unsigned FirstIndex = 0;
534
535 template <typename MatchContext>
536 explicit EffectiveOperands(SDValue N, const MatchContext &Ctx)
537 : Size(Ctx.getNumOperands(N)) {}
538};
539
540// === Ternary operations ===
541template <typename T0_P, typename T1_P, typename T2_P, bool Commutable = false,
542 bool ExcludeChain = false>
543struct TernaryOpc_match {
544 unsigned Opcode;
545 T0_P Op0;
546 T1_P Op1;
547 T2_P Op2;
548
549 TernaryOpc_match(unsigned Opc, const T0_P &Op0, const T1_P &Op1,
550 const T2_P &Op2)
551 : Opcode(Opc), Op0(Op0), Op1(Op1), Op2(Op2) {}
552
553 template <typename MatchContext>
554 bool match(const MatchContext &Ctx, SDValue N) {
555 if (sd_context_match(N, Ctx, m_SpecificOpc(Opcode))) {
556 EffectiveOperands<ExcludeChain> EO(N, Ctx);
557 assert(EO.Size == 3);
558 return ((Op0.match(Ctx, N->getOperand(Num: EO.FirstIndex)) &&
559 Op1.match(Ctx, N->getOperand(Num: EO.FirstIndex + 1))) ||
560 (Commutable && Op0.match(Ctx, N->getOperand(Num: EO.FirstIndex + 1)) &&
561 Op1.match(Ctx, N->getOperand(Num: EO.FirstIndex)))) &&
562 Op2.match(Ctx, N->getOperand(Num: EO.FirstIndex + 2));
563 }
564
565 return false;
566 }
567};
568
569template <typename T0_P, typename T1_P, typename T2_P>
570inline TernaryOpc_match<T0_P, T1_P, T2_P>
571m_SetCC(const T0_P &LHS, const T1_P &RHS, const T2_P &CC) {
572 return TernaryOpc_match<T0_P, T1_P, T2_P>(ISD::SETCC, LHS, RHS, CC);
573}
574
575template <typename T0_P, typename T1_P, typename T2_P>
576inline TernaryOpc_match<T0_P, T1_P, T2_P, true, false>
577m_c_SetCC(const T0_P &LHS, const T1_P &RHS, const T2_P &CC) {
578 return TernaryOpc_match<T0_P, T1_P, T2_P, true, false>(ISD::SETCC, LHS, RHS,
579 CC);
580}
581
582template <typename T0_P, typename T1_P, typename T2_P>
583inline TernaryOpc_match<T0_P, T1_P, T2_P>
584m_Select(const T0_P &Cond, const T1_P &T, const T2_P &F) {
585 return TernaryOpc_match<T0_P, T1_P, T2_P>(ISD::SELECT, Cond, T, F);
586}
587
588template <typename T0_P, typename T1_P, typename T2_P>
589inline TernaryOpc_match<T0_P, T1_P, T2_P>
590m_VSelect(const T0_P &Cond, const T1_P &T, const T2_P &F) {
591 return TernaryOpc_match<T0_P, T1_P, T2_P>(ISD::VSELECT, Cond, T, F);
592}
593
594template <typename T0_P, typename T1_P, typename T2_P>
595inline auto m_SelectLike(const T0_P &Cond, const T1_P &T, const T2_P &F) {
596 return m_AnyOf(m_Select(Cond, T, F), m_VSelect(Cond, T, F));
597}
598
599template <typename T0_P, typename T1_P, typename T2_P>
600inline Result_match<0, TernaryOpc_match<T0_P, T1_P, T2_P>>
601m_Load(const T0_P &Ch, const T1_P &Ptr, const T2_P &Offset) {
602 return m_Result<0>(
603 TernaryOpc_match<T0_P, T1_P, T2_P>(ISD::LOAD, Ch, Ptr, Offset));
604}
605
606template <typename T0_P, typename T1_P, typename T2_P>
607inline TernaryOpc_match<T0_P, T1_P, T2_P>
608m_InsertElt(const T0_P &Vec, const T1_P &Val, const T2_P &Idx) {
609 return TernaryOpc_match<T0_P, T1_P, T2_P>(ISD::INSERT_VECTOR_ELT, Vec, Val,
610 Idx);
611}
612
613template <typename LHS, typename RHS, typename IDX>
614inline TernaryOpc_match<LHS, RHS, IDX>
615m_InsertSubvector(const LHS &Base, const RHS &Sub, const IDX &Idx) {
616 return TernaryOpc_match<LHS, RHS, IDX>(ISD::INSERT_SUBVECTOR, Base, Sub, Idx);
617}
618
619template <typename T0_P, typename T1_P, typename T2_P>
620inline TernaryOpc_match<T0_P, T1_P, T2_P>
621m_SpliceRight(const T0_P &V1, const T1_P &V2, const T2_P &Offset) {
622 return TernaryOpc_match<T0_P, T1_P, T2_P>(ISD::VECTOR_SPLICE_RIGHT, V1, V2,
623 Offset);
624}
625
626template <typename T0_P, typename T1_P, typename T2_P>
627inline TernaryOpc_match<T0_P, T1_P, T2_P>
628m_TernaryOp(unsigned Opc, const T0_P &Op0, const T1_P &Op1, const T2_P &Op2) {
629 return TernaryOpc_match<T0_P, T1_P, T2_P>(Opc, Op0, Op1, Op2);
630}
631
632template <typename T0_P, typename T1_P, typename T2_P>
633inline TernaryOpc_match<T0_P, T1_P, T2_P, true>
634m_c_TernaryOp(unsigned Opc, const T0_P &Op0, const T1_P &Op1, const T2_P &Op2) {
635 return TernaryOpc_match<T0_P, T1_P, T2_P, true>(Opc, Op0, Op1, Op2);
636}
637
638template <typename LTy, typename RTy, typename TTy, typename FTy, typename CCTy>
639inline auto m_SelectCC(const LTy &L, const RTy &R, const TTy &T, const FTy &F,
640 const CCTy &CC) {
641 return m_Node(ISD::SELECT_CC, L, R, T, F, CC);
642}
643
644template <typename LTy, typename RTy, typename TTy, typename FTy, typename CCTy>
645inline auto m_SelectCCLike(const LTy &L, const RTy &R, const TTy &T,
646 const FTy &F, const CCTy &CC) {
647 return m_AnyOf(m_Select(m_SetCC(L, R, CC), T, F), m_SelectCC(L, R, T, F, CC));
648}
649
650// === Binary operations ===
651template <typename LHS_P, typename RHS_P, bool Commutable = false,
652 bool ExcludeChain = false>
653struct BinaryOpc_match {
654 unsigned Opcode;
655 LHS_P LHS;
656 RHS_P RHS;
657 SDNodeFlags Flags;
658 BinaryOpc_match(unsigned Opc, const LHS_P &L, const RHS_P &R,
659 SDNodeFlags Flgs = SDNodeFlags())
660 : Opcode(Opc), LHS(L), RHS(R), Flags(Flgs) {}
661
662 template <typename MatchContext>
663 bool match(const MatchContext &Ctx, SDValue N) {
664 if (sd_context_match(N, Ctx, m_SpecificOpc(Opcode))) {
665 EffectiveOperands<ExcludeChain> EO(N, Ctx);
666 assert(EO.Size == 2);
667 if (!((LHS.match(Ctx, N->getOperand(Num: EO.FirstIndex)) &&
668 RHS.match(Ctx, N->getOperand(Num: EO.FirstIndex + 1))) ||
669 (Commutable && LHS.match(Ctx, N->getOperand(Num: EO.FirstIndex + 1)) &&
670 RHS.match(Ctx, N->getOperand(Num: EO.FirstIndex)))))
671 return false;
672
673 return (Flags & N->getFlags()) == Flags;
674 }
675
676 return false;
677 }
678};
679
680/// Matching while capturing mask
681template <typename T0, typename T1, typename T2> struct SDShuffle_match {
682 T0 Op1;
683 T1 Op2;
684 T2 Mask;
685
686 SDShuffle_match(const T0 &Op1, const T1 &Op2, const T2 &Mask)
687 : Op1(Op1), Op2(Op2), Mask(Mask) {}
688
689 template <typename MatchContext>
690 bool match(const MatchContext &Ctx, SDValue N) {
691 if (auto *I = dyn_cast<ShuffleVectorSDNode>(Val&: N)) {
692 return Op1.match(Ctx, I->getOperand(Num: 0)) &&
693 Op2.match(Ctx, I->getOperand(Num: 1)) && Mask.match(I->getMask());
694 }
695 return false;
696 }
697};
698struct m_Mask {
699 ArrayRef<int> &MaskRef;
700 m_Mask(ArrayRef<int> &MaskRef) : MaskRef(MaskRef) {}
701 bool match(ArrayRef<int> Mask) {
702 MaskRef = Mask;
703 return true;
704 }
705};
706
707struct m_SpecificMask {
708 ArrayRef<int> MaskRef;
709 m_SpecificMask(ArrayRef<int> MaskRef) : MaskRef(MaskRef) {}
710 bool match(ArrayRef<int> Mask) { return MaskRef == Mask; }
711};
712
713template <typename LHS_P, typename RHS_P, typename Pred_t,
714 bool Commutable = false, bool ExcludeChain = false>
715struct MaxMin_match {
716 using PredType = Pred_t;
717 LHS_P LHS;
718 RHS_P RHS;
719
720 MaxMin_match(const LHS_P &L, const RHS_P &R) : LHS(L), RHS(R) {}
721
722 template <typename MatchContext>
723 bool match(const MatchContext &Ctx, SDValue N) {
724 auto MatchMinMax = [&](SDValue L, SDValue R, SDValue TrueValue,
725 SDValue FalseValue, ISD::CondCode CC) {
726 if ((TrueValue != L || FalseValue != R) &&
727 (TrueValue != R || FalseValue != L))
728 return false;
729
730 ISD::CondCode Cond =
731 TrueValue == L ? CC : getSetCCInverse(Operation: CC, Type: L.getValueType());
732 if (!Pred_t::match(Cond))
733 return false;
734
735 return (LHS.match(Ctx, L) && RHS.match(Ctx, R)) ||
736 (Commutable && LHS.match(Ctx, R) && RHS.match(Ctx, L));
737 };
738
739 if (sd_context_match(N, Ctx, m_SpecificOpc(Opcode: ISD::SELECT)) ||
740 sd_context_match(N, Ctx, m_SpecificOpc(Opcode: ISD::VSELECT))) {
741 EffectiveOperands<ExcludeChain> EO_SELECT(N, Ctx);
742 assert(EO_SELECT.Size == 3);
743 SDValue Cond = N->getOperand(Num: EO_SELECT.FirstIndex);
744 SDValue TrueValue = N->getOperand(Num: EO_SELECT.FirstIndex + 1);
745 SDValue FalseValue = N->getOperand(Num: EO_SELECT.FirstIndex + 2);
746
747 if (sd_context_match(Cond, Ctx, m_SpecificOpc(Opcode: ISD::SETCC))) {
748 EffectiveOperands<ExcludeChain> EO_SETCC(Cond, Ctx);
749 assert(EO_SETCC.Size == 3);
750 SDValue L = Cond->getOperand(Num: EO_SETCC.FirstIndex);
751 SDValue R = Cond->getOperand(Num: EO_SETCC.FirstIndex + 1);
752 auto *CondNode =
753 cast<CondCodeSDNode>(Cond->getOperand(Num: EO_SETCC.FirstIndex + 2));
754 return MatchMinMax(L, R, TrueValue, FalseValue, CondNode->get());
755 }
756 }
757
758 if (sd_context_match(N, Ctx, m_SpecificOpc(Opcode: ISD::SELECT_CC))) {
759 EffectiveOperands<ExcludeChain> EO_SELECT(N, Ctx);
760 assert(EO_SELECT.Size == 5);
761 SDValue L = N->getOperand(Num: EO_SELECT.FirstIndex);
762 SDValue R = N->getOperand(Num: EO_SELECT.FirstIndex + 1);
763 SDValue TrueValue = N->getOperand(Num: EO_SELECT.FirstIndex + 2);
764 SDValue FalseValue = N->getOperand(Num: EO_SELECT.FirstIndex + 3);
765 auto *CondNode =
766 cast<CondCodeSDNode>(N->getOperand(Num: EO_SELECT.FirstIndex + 4));
767 return MatchMinMax(L, R, TrueValue, FalseValue, CondNode->get());
768 }
769
770 return false;
771 }
772};
773
774// Helper class for identifying signed max predicates.
775struct smax_pred_ty {
776 static bool match(ISD::CondCode Cond) {
777 return Cond == ISD::CondCode::SETGT || Cond == ISD::CondCode::SETGE;
778 }
779};
780
781// Helper class for identifying unsigned max predicates.
782struct umax_pred_ty {
783 static bool match(ISD::CondCode Cond) {
784 return Cond == ISD::CondCode::SETUGT || Cond == ISD::CondCode::SETUGE;
785 }
786};
787
788// Helper class for identifying signed min predicates.
789struct smin_pred_ty {
790 static bool match(ISD::CondCode Cond) {
791 return Cond == ISD::CondCode::SETLT || Cond == ISD::CondCode::SETLE;
792 }
793};
794
795// Helper class for identifying unsigned min predicates.
796struct umin_pred_ty {
797 static bool match(ISD::CondCode Cond) {
798 return Cond == ISD::CondCode::SETULT || Cond == ISD::CondCode::SETULE;
799 }
800};
801
802template <typename LHS, typename RHS>
803inline BinaryOpc_match<LHS, RHS> m_BinOp(unsigned Opc, const LHS &L,
804 const RHS &R,
805 SDNodeFlags Flgs = SDNodeFlags()) {
806 return BinaryOpc_match<LHS, RHS>(Opc, L, R, Flgs);
807}
808template <typename LHS, typename RHS>
809inline BinaryOpc_match<LHS, RHS, true>
810m_c_BinOp(unsigned Opc, const LHS &L, const RHS &R,
811 SDNodeFlags Flgs = SDNodeFlags()) {
812 return BinaryOpc_match<LHS, RHS, true>(Opc, L, R, Flgs);
813}
814
815template <typename LHS, typename RHS>
816inline BinaryOpc_match<LHS, RHS, false, true>
817m_ChainedBinOp(unsigned Opc, const LHS &L, const RHS &R) {
818 return BinaryOpc_match<LHS, RHS, false, true>(Opc, L, R);
819}
820template <typename LHS, typename RHS>
821inline BinaryOpc_match<LHS, RHS, true, true>
822m_c_ChainedBinOp(unsigned Opc, const LHS &L, const RHS &R) {
823 return BinaryOpc_match<LHS, RHS, true, true>(Opc, L, R);
824}
825
826// Common binary operations
827template <typename LHS, typename RHS>
828inline BinaryOpc_match<LHS, RHS, true> m_Add(const LHS &L, const RHS &R) {
829 return BinaryOpc_match<LHS, RHS, true>(ISD::ADD, L, R);
830}
831
832template <typename LHS, typename RHS>
833inline auto m_NUWAdd(const LHS &L, const RHS &R) {
834 return BinaryOpc_match<LHS, RHS, true>(ISD::ADD, L, R,
835 SDNodeFlags::NoUnsignedWrap);
836}
837
838template <typename LHS, typename RHS>
839inline auto m_NSWAdd(const LHS &L, const RHS &R) {
840 return BinaryOpc_match<LHS, RHS, true>(ISD::ADD, L, R,
841 SDNodeFlags::NoSignedWrap);
842}
843
844template <typename LHS, typename RHS>
845inline BinaryOpc_match<LHS, RHS> m_Sub(const LHS &L, const RHS &R) {
846 return BinaryOpc_match<LHS, RHS>(ISD::SUB, L, R);
847}
848
849template <typename LHS, typename RHS>
850inline BinaryOpc_match<LHS, RHS, true> m_Mul(const LHS &L, const RHS &R) {
851 return BinaryOpc_match<LHS, RHS, true>(ISD::MUL, L, R);
852}
853
854template <typename LHS, typename RHS>
855inline BinaryOpc_match<LHS, RHS, true> m_And(const LHS &L, const RHS &R) {
856 return BinaryOpc_match<LHS, RHS, true>(ISD::AND, L, R);
857}
858
859template <typename LHS, typename RHS>
860inline BinaryOpc_match<LHS, RHS, true> m_Or(const LHS &L, const RHS &R) {
861 return BinaryOpc_match<LHS, RHS, true>(ISD::OR, L, R);
862}
863
864template <typename LHS, typename RHS>
865inline BinaryOpc_match<LHS, RHS, true> m_DisjointOr(const LHS &L,
866 const RHS &R) {
867 return BinaryOpc_match<LHS, RHS, true>(ISD::OR, L, R, SDNodeFlags::Disjoint);
868}
869
870template <typename LHS, typename RHS>
871inline auto m_AddLike(const LHS &L, const RHS &R) {
872 return m_AnyOf(m_Add(L, R), m_DisjointOr(L, R));
873}
874
875template <typename LHS, typename RHS>
876inline auto m_NSWAddLike(const LHS &L, const RHS &R) {
877 return m_AnyOf(m_NSWAdd(L, R), m_DisjointOr(L, R));
878}
879
880template <typename LHS, typename RHS>
881inline auto m_NUWAddLike(const LHS &L, const RHS &R) {
882 return m_AnyOf(m_NUWAdd(L, R), m_DisjointOr(L, R));
883}
884
885template <typename LHS, typename RHS>
886inline BinaryOpc_match<LHS, RHS, true> m_Xor(const LHS &L, const RHS &R) {
887 return BinaryOpc_match<LHS, RHS, true>(ISD::XOR, L, R);
888}
889
890template <typename LHS, typename RHS>
891inline auto m_BitwiseLogic(const LHS &L, const RHS &R) {
892 return m_AnyOf(m_And(L, R), m_Or(L, R), m_Xor(L, R));
893}
894
895template <unsigned Opc, typename Pred, typename LHS, typename RHS>
896inline auto m_MaxMinLike(const LHS &L, const RHS &R) {
897 return m_AnyOf(BinaryOpc_match<LHS, RHS, true>(Opc, L, R),
898 MaxMin_match<LHS, RHS, Pred, true>(L, R));
899}
900
901template <typename LHS, typename RHS>
902inline BinaryOpc_match<LHS, RHS, true> m_SMin(const LHS &L, const RHS &R) {
903 return BinaryOpc_match<LHS, RHS, true>(ISD::SMIN, L, R);
904}
905
906template <typename LHS, typename RHS>
907inline auto m_SMinLike(const LHS &L, const RHS &R) {
908 return m_AnyOf(
909 m_MaxMinLike<ISD::SMIN, smin_pred_ty>(L, R),
910 m_MaxMinLike<ISD::UMIN, umin_pred_ty>(m_NonNegative(L), m_NonNegative(R)),
911 m_MaxMinLike<ISD::UMIN, umin_pred_ty>(m_Negative(L), m_Negative(R)));
912}
913
914template <typename LHS, typename RHS>
915inline BinaryOpc_match<LHS, RHS, true> m_SMax(const LHS &L, const RHS &R) {
916 return BinaryOpc_match<LHS, RHS, true>(ISD::SMAX, L, R);
917}
918
919template <typename LHS, typename RHS>
920inline auto m_SMaxLike(const LHS &L, const RHS &R) {
921 return m_AnyOf(
922 m_MaxMinLike<ISD::SMAX, smax_pred_ty>(L, R),
923 m_MaxMinLike<ISD::UMAX, umax_pred_ty>(m_NonNegative(L), m_NonNegative(R)),
924 m_MaxMinLike<ISD::UMAX, umax_pred_ty>(m_Negative(L), m_Negative(R)));
925}
926
927template <typename LHS, typename RHS>
928inline BinaryOpc_match<LHS, RHS, true> m_UMin(const LHS &L, const RHS &R) {
929 return BinaryOpc_match<LHS, RHS, true>(ISD::UMIN, L, R);
930}
931
932template <typename LHS, typename RHS>
933inline auto m_UMinLike(const LHS &L, const RHS &R) {
934 return m_AnyOf(
935 m_MaxMinLike<ISD::UMIN, umin_pred_ty>(L, R),
936 m_MaxMinLike<ISD::SMIN, smin_pred_ty>(m_NonNegative(L), m_NonNegative(R)),
937 m_MaxMinLike<ISD::SMIN, smin_pred_ty>(m_Negative(L), m_Negative(R)));
938}
939
940template <typename LHS, typename RHS>
941inline BinaryOpc_match<LHS, RHS, true> m_UMax(const LHS &L, const RHS &R) {
942 return BinaryOpc_match<LHS, RHS, true>(ISD::UMAX, L, R);
943}
944
945template <typename LHS, typename RHS>
946inline auto m_UMaxLike(const LHS &L, const RHS &R) {
947 return m_AnyOf(
948 m_MaxMinLike<ISD::UMAX, umax_pred_ty>(L, R),
949 m_MaxMinLike<ISD::SMAX, smax_pred_ty>(m_NonNegative(L), m_NonNegative(R)),
950 m_MaxMinLike<ISD::SMAX, smax_pred_ty>(m_Negative(L), m_Negative(R)));
951}
952
953template <typename LHS, typename RHS>
954inline BinaryOpc_match<LHS, RHS> m_UDiv(const LHS &L, const RHS &R) {
955 return BinaryOpc_match<LHS, RHS>(ISD::UDIV, L, R);
956}
957template <typename LHS, typename RHS>
958inline BinaryOpc_match<LHS, RHS> m_SDiv(const LHS &L, const RHS &R) {
959 return BinaryOpc_match<LHS, RHS>(ISD::SDIV, L, R);
960}
961
962template <typename LHS, typename RHS>
963inline BinaryOpc_match<LHS, RHS> m_URem(const LHS &L, const RHS &R) {
964 return BinaryOpc_match<LHS, RHS>(ISD::UREM, L, R);
965}
966template <typename LHS, typename RHS>
967inline BinaryOpc_match<LHS, RHS> m_SRem(const LHS &L, const RHS &R) {
968 return BinaryOpc_match<LHS, RHS>(ISD::SREM, L, R);
969}
970
971template <typename LHS, typename RHS>
972inline BinaryOpc_match<LHS, RHS> m_Shl(const LHS &L, const RHS &R) {
973 return BinaryOpc_match<LHS, RHS>(ISD::SHL, L, R);
974}
975
976template <typename LHS, typename RHS>
977inline BinaryOpc_match<LHS, RHS> m_Sra(const LHS &L, const RHS &R) {
978 return BinaryOpc_match<LHS, RHS>(ISD::SRA, L, R);
979}
980template <typename LHS, typename RHS>
981inline BinaryOpc_match<LHS, RHS> m_Srl(const LHS &L, const RHS &R) {
982 return BinaryOpc_match<LHS, RHS>(ISD::SRL, L, R);
983}
984template <typename LHS, typename RHS>
985inline auto m_ExactSr(const LHS &L, const RHS &R) {
986 return m_AnyOf(BinaryOpc_match<LHS, RHS>(ISD::SRA, L, R, SDNodeFlags::Exact),
987 BinaryOpc_match<LHS, RHS>(ISD::SRL, L, R, SDNodeFlags::Exact));
988}
989
990template <typename LHS, typename RHS>
991inline BinaryOpc_match<LHS, RHS> m_Rotl(const LHS &L, const RHS &R) {
992 return BinaryOpc_match<LHS, RHS>(ISD::ROTL, L, R);
993}
994
995template <typename LHS, typename RHS>
996inline BinaryOpc_match<LHS, RHS> m_Rotr(const LHS &L, const RHS &R) {
997 return BinaryOpc_match<LHS, RHS>(ISD::ROTR, L, R);
998}
999
1000template <typename T0_P, typename T1_P, typename T2_P>
1001inline TernaryOpc_match<T0_P, T1_P, T2_P>
1002m_FShL(const T0_P &Op0, const T1_P &Op1, const T2_P &Op2) {
1003 return m_TernaryOp(ISD::FSHL, Op0, Op1, Op2);
1004}
1005
1006template <typename T0_P, typename T1_P, typename T2_P>
1007inline TernaryOpc_match<T0_P, T1_P, T2_P>
1008m_FShR(const T0_P &Op0, const T1_P &Op1, const T2_P &Op2) {
1009 return m_TernaryOp(ISD::FSHR, Op0, Op1, Op2);
1010}
1011
1012template <typename T0_P, typename T1_P, typename T2_P, bool Left>
1013struct FunnelShiftLike_match {
1014 T0_P Op0;
1015 T1_P Op1;
1016 T2_P Op2;
1017
1018 FunnelShiftLike_match(const T0_P &Op0, const T1_P &Op1, const T2_P &Op2)
1019 : Op0(Op0), Op1(Op1), Op2(Op2) {}
1020
1021 static bool hasComplementaryConstantShifts(const APInt &ShlV,
1022 const APInt &SrlV,
1023 unsigned BitWidth) {
1024 unsigned SumWidth = std::max(a: ShlV.getBitWidth(), b: SrlV.getBitWidth()) + 1;
1025 unsigned BitWidthBits = llvm::bit_width(Value: BitWidth);
1026 if (BitWidthBits > SumWidth)
1027 return false;
1028
1029 return ShlV.zext(width: SumWidth) + SrlV.zext(width: SumWidth) ==
1030 APInt(SumWidth, BitWidth);
1031 }
1032
1033 template <typename MatchContext>
1034 bool matchOperands(const MatchContext &Ctx, SDValue X, SDValue Y, SDValue Z) {
1035 return Op0.match(Ctx, X) && Op1.match(Ctx, Y) && Op2.match(Ctx, Z);
1036 }
1037
1038 template <typename MatchContext>
1039 bool matchShiftOr(const MatchContext &Ctx, SDValue N, unsigned BitWidth);
1040
1041 template <typename MatchContext>
1042 bool match(const MatchContext &Ctx, SDValue N) {
1043 if (sd_context_match(N, Ctx,
1044 Left ? m_FShL(Op0, Op1, Op2) : m_FShR(Op0, Op1, Op2)))
1045 return true;
1046
1047 SDValue X, Z;
1048 if (sd_context_match(N, Ctx,
1049 Left ? m_Rotl(L: m_Value(N&: X), R: m_Value(N&: Z))
1050 : m_Rotr(L: m_Value(N&: X), R: m_Value(N&: Z))))
1051 return matchOperands(Ctx, X, X, Z);
1052
1053 return matchShiftOr(Ctx, N, N.getValueType().getScalarSizeInBits());
1054 }
1055};
1056
1057template <typename T0_P, typename T1_P, typename T2_P>
1058inline FunnelShiftLike_match<T0_P, T1_P, T2_P, true>
1059m_FShLLike(const T0_P &Op0, const T1_P &Op1, const T2_P &Op2) {
1060 return FunnelShiftLike_match<T0_P, T1_P, T2_P, true>(Op0, Op1, Op2);
1061}
1062
1063template <typename T0_P, typename T1_P, typename T2_P>
1064inline FunnelShiftLike_match<T0_P, T1_P, T2_P, false>
1065m_FShRLike(const T0_P &Op0, const T1_P &Op1, const T2_P &Op2) {
1066 return FunnelShiftLike_match<T0_P, T1_P, T2_P, false>(Op0, Op1, Op2);
1067}
1068
1069template <typename LHS, typename RHS>
1070inline BinaryOpc_match<LHS, RHS, true> m_Clmul(const LHS &L, const RHS &R) {
1071 return BinaryOpc_match<LHS, RHS, true>(ISD::CLMUL, L, R);
1072}
1073
1074template <typename LHS, typename RHS>
1075inline BinaryOpc_match<LHS, RHS, true> m_FAdd(const LHS &L, const RHS &R) {
1076 return BinaryOpc_match<LHS, RHS, true>(ISD::FADD, L, R);
1077}
1078
1079template <typename LHS, typename RHS>
1080inline BinaryOpc_match<LHS, RHS> m_FSub(const LHS &L, const RHS &R) {
1081 return BinaryOpc_match<LHS, RHS>(ISD::FSUB, L, R);
1082}
1083
1084template <typename LHS, typename RHS>
1085inline BinaryOpc_match<LHS, RHS, true> m_FMul(const LHS &L, const RHS &R) {
1086 return BinaryOpc_match<LHS, RHS, true>(ISD::FMUL, L, R);
1087}
1088
1089template <typename LHS, typename RHS>
1090inline BinaryOpc_match<LHS, RHS> m_FDiv(const LHS &L, const RHS &R) {
1091 return BinaryOpc_match<LHS, RHS>(ISD::FDIV, L, R);
1092}
1093
1094template <typename LHS, typename RHS>
1095inline BinaryOpc_match<LHS, RHS> m_FRem(const LHS &L, const RHS &R) {
1096 return BinaryOpc_match<LHS, RHS>(ISD::FREM, L, R);
1097}
1098
1099template <typename V1_t, typename V2_t>
1100inline BinaryOpc_match<V1_t, V2_t> m_Shuffle(const V1_t &v1, const V2_t &v2) {
1101 return BinaryOpc_match<V1_t, V2_t>(ISD::VECTOR_SHUFFLE, v1, v2);
1102}
1103
1104template <typename V1_t, typename V2_t, typename Mask_t>
1105inline SDShuffle_match<V1_t, V2_t, Mask_t>
1106m_Shuffle(const V1_t &v1, const V2_t &v2, const Mask_t &mask) {
1107 return SDShuffle_match<V1_t, V2_t, Mask_t>(v1, v2, mask);
1108}
1109
1110template <typename LHS, typename RHS>
1111inline BinaryOpc_match<LHS, RHS> m_ExtractElt(const LHS &Vec, const RHS &Idx) {
1112 return BinaryOpc_match<LHS, RHS>(ISD::EXTRACT_VECTOR_ELT, Vec, Idx);
1113}
1114
1115template <typename LHS, typename RHS>
1116inline BinaryOpc_match<LHS, RHS> m_ExtractSubvector(const LHS &Vec,
1117 const RHS &Idx) {
1118 return BinaryOpc_match<LHS, RHS>(ISD::EXTRACT_SUBVECTOR, Vec, Idx);
1119}
1120
1121// === Unary operations ===
1122template <typename Opnd_P, bool ExcludeChain = false> struct UnaryOpc_match {
1123 unsigned Opcode;
1124 Opnd_P Opnd;
1125 SDNodeFlags Flags;
1126 UnaryOpc_match(unsigned Opc, const Opnd_P &Op,
1127 SDNodeFlags Flgs = SDNodeFlags())
1128 : Opcode(Opc), Opnd(Op), Flags(Flgs) {}
1129
1130 template <typename MatchContext>
1131 bool match(const MatchContext &Ctx, SDValue N) {
1132 if (sd_context_match(N, Ctx, m_SpecificOpc(Opcode))) {
1133 EffectiveOperands<ExcludeChain> EO(N, Ctx);
1134 assert(EO.Size == 1);
1135 if (!Opnd.match(Ctx, N->getOperand(Num: EO.FirstIndex)))
1136 return false;
1137
1138 return (Flags & N->getFlags()) == Flags;
1139 }
1140
1141 return false;
1142 }
1143};
1144
1145template <typename Opnd>
1146inline UnaryOpc_match<Opnd> m_UnaryOp(unsigned Opc, const Opnd &Op) {
1147 return UnaryOpc_match<Opnd>(Opc, Op);
1148}
1149template <typename Opnd>
1150inline UnaryOpc_match<Opnd, true> m_ChainedUnaryOp(unsigned Opc,
1151 const Opnd &Op) {
1152 return UnaryOpc_match<Opnd, true>(Opc, Op);
1153}
1154
1155template <typename Opnd> inline UnaryOpc_match<Opnd> m_BitCast(const Opnd &Op) {
1156 return UnaryOpc_match<Opnd>(ISD::BITCAST, Op);
1157}
1158
1159template <typename Opnd>
1160inline UnaryOpc_match<Opnd> m_BSwap(const Opnd &Op) {
1161 return UnaryOpc_match<Opnd>(ISD::BSWAP, Op);
1162}
1163
1164template <typename Opnd>
1165inline UnaryOpc_match<Opnd> m_BitReverse(const Opnd &Op) {
1166 return UnaryOpc_match<Opnd>(ISD::BITREVERSE, Op);
1167}
1168
1169template <typename Opnd> inline UnaryOpc_match<Opnd> m_ZExt(const Opnd &Op) {
1170 return UnaryOpc_match<Opnd>(ISD::ZERO_EXTEND, Op);
1171}
1172
1173template <typename Opnd>
1174inline UnaryOpc_match<Opnd> m_NNegZExt(const Opnd &Op) {
1175 return UnaryOpc_match<Opnd>(ISD::ZERO_EXTEND, Op, SDNodeFlags::NonNeg);
1176}
1177
1178template <typename Opnd> inline auto m_SExt(const Opnd &Op) {
1179 return UnaryOpc_match<Opnd>(ISD::SIGN_EXTEND, Op);
1180}
1181
1182template <typename Opnd> inline UnaryOpc_match<Opnd> m_AnyExt(const Opnd &Op) {
1183 return UnaryOpc_match<Opnd>(ISD::ANY_EXTEND, Op);
1184}
1185
1186template <typename Opnd> inline UnaryOpc_match<Opnd> m_Trunc(const Opnd &Op) {
1187 return UnaryOpc_match<Opnd>(ISD::TRUNCATE, Op);
1188}
1189
1190template <typename Opnd> inline auto m_Abs(const Opnd &Op) {
1191 return m_AnyOf(UnaryOpc_match<Opnd>(ISD::ABS, Op),
1192 UnaryOpc_match<Opnd>(ISD::ABS_MIN_POISON, Op));
1193}
1194
1195template <typename Opnd> inline UnaryOpc_match<Opnd> m_FAbs(const Opnd &Op) {
1196 return UnaryOpc_match<Opnd>(ISD::FABS, Op);
1197}
1198
1199/// Match a zext or identity
1200/// Allows to peek through optional extensions
1201template <typename Opnd> inline auto m_ZExtOrSelf(const Opnd &Op) {
1202 return m_AnyOf(m_ZExt(Op), Op);
1203}
1204
1205/// Match a sext or identity
1206/// Allows to peek through optional extensions
1207template <typename Opnd> inline auto m_SExtOrSelf(const Opnd &Op) {
1208 return m_AnyOf(m_SExt(Op), Op);
1209}
1210
1211template <typename Opnd> inline auto m_SExtLike(const Opnd &Op) {
1212 return m_AnyOf(m_SExt(Op), m_NNegZExt(Op));
1213}
1214
1215/// Match a aext or identity
1216/// Allows to peek through optional extensions
1217template <typename Opnd>
1218inline Or<UnaryOpc_match<Opnd>, Opnd> m_AExtOrSelf(const Opnd &Op) {
1219 return Or<UnaryOpc_match<Opnd>, Opnd>(m_AnyExt(Op), Op);
1220}
1221
1222/// Match a trunc or identity
1223/// Allows to peek through optional truncations
1224template <typename Opnd>
1225inline Or<UnaryOpc_match<Opnd>, Opnd> m_TruncOrSelf(const Opnd &Op) {
1226 return Or<UnaryOpc_match<Opnd>, Opnd>(m_Trunc(Op), Op);
1227}
1228
1229template <typename Opnd> inline UnaryOpc_match<Opnd> m_VScale(const Opnd &Op) {
1230 return UnaryOpc_match<Opnd>(ISD::VSCALE, Op);
1231}
1232
1233template <typename Opnd> inline UnaryOpc_match<Opnd> m_FPToUI(const Opnd &Op) {
1234 return UnaryOpc_match<Opnd>(ISD::FP_TO_UINT, Op);
1235}
1236
1237template <typename Opnd> inline UnaryOpc_match<Opnd> m_FPToSI(const Opnd &Op) {
1238 return UnaryOpc_match<Opnd>(ISD::FP_TO_SINT, Op);
1239}
1240
1241template <typename Opnd> inline UnaryOpc_match<Opnd> m_Ctpop(const Opnd &Op) {
1242 return UnaryOpc_match<Opnd>(ISD::CTPOP, Op);
1243}
1244
1245template <typename Opnd> inline UnaryOpc_match<Opnd> m_Ctlz(const Opnd &Op) {
1246 return UnaryOpc_match<Opnd>(ISD::CTLZ, Op);
1247}
1248
1249template <typename Opnd> inline UnaryOpc_match<Opnd> m_Cttz(const Opnd &Op) {
1250 return UnaryOpc_match<Opnd>(ISD::CTTZ, Op);
1251}
1252
1253template <typename Opnd> inline UnaryOpc_match<Opnd> m_FNeg(const Opnd &Op) {
1254 return UnaryOpc_match<Opnd>(ISD::FNEG, Op);
1255}
1256
1257template <typename Opnd>
1258inline UnaryOpc_match<Opnd> m_VectorReverse(const Opnd &Op) {
1259 return UnaryOpc_match<Opnd>(ISD::VECTOR_REVERSE, Op);
1260}
1261
1262// === Constants ===
1263struct ConstantInt_match {
1264 APInt *BindVal;
1265
1266 explicit ConstantInt_match(APInt *V) : BindVal(V) {}
1267
1268 template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
1269 // The logics here are similar to that in
1270 // SelectionDAG::isConstantIntBuildVectorOrConstantInt, but the latter also
1271 // treats GlobalAddressSDNode as a constant, which is difficult to turn into
1272 // APInt.
1273 if (auto *C = dyn_cast_or_null<ConstantSDNode>(Val: N.getNode())) {
1274 if (BindVal)
1275 *BindVal = C->getAPIntValue();
1276 return true;
1277 }
1278
1279 APInt Discard;
1280 return ISD::isConstantSplatVector(N: N.getNode(),
1281 SplatValue&: BindVal ? *BindVal : Discard);
1282 }
1283};
1284
1285template <typename T> struct Constant64_match {
1286 static_assert(sizeof(T) == 8, "T must be 64 bits wide");
1287
1288 T &BindVal;
1289
1290 explicit Constant64_match(T &V) : BindVal(V) {}
1291
1292 template <typename MatchContext>
1293 bool match(const MatchContext &Ctx, SDValue N) {
1294 APInt V;
1295 if (!ConstantInt_match(&V).match(Ctx, N))
1296 return false;
1297
1298 if constexpr (std::is_signed_v<T>) {
1299 if (std::optional<int64_t> TrySExt = V.trySExtValue()) {
1300 BindVal = *TrySExt;
1301 return true;
1302 }
1303 }
1304
1305 if constexpr (std::is_unsigned_v<T>) {
1306 if (std::optional<uint64_t> TryZExt = V.tryZExtValue()) {
1307 BindVal = *TryZExt;
1308 return true;
1309 }
1310 }
1311
1312 return false;
1313 }
1314};
1315
1316/// Match any integer constants or splat of an integer constant.
1317inline ConstantInt_match m_ConstInt() { return ConstantInt_match(nullptr); }
1318/// Match any integer constants or splat of an integer constant; return the
1319/// specific constant or constant splat value.
1320inline ConstantInt_match m_ConstInt(APInt &V) { return ConstantInt_match(&V); }
1321/// Match any integer constants or splat of an integer constant that can fit in
1322/// 64 bits; return the specific constant or constant splat value, zero-extended
1323/// to 64 bits.
1324inline Constant64_match<uint64_t> m_ConstInt(uint64_t &V) {
1325 return Constant64_match<uint64_t>(V);
1326}
1327/// Match any integer constants or splat of an integer constant that can fit in
1328/// 64 bits; return the specific constant or constant splat value, sign-extended
1329/// to 64 bits.
1330inline Constant64_match<int64_t> m_ConstInt(int64_t &V) {
1331 return Constant64_match<int64_t>(V);
1332}
1333
1334template <typename T0_P, typename T1_P, typename T2_P, bool Left>
1335template <typename MatchContext>
1336bool FunnelShiftLike_match<T0_P, T1_P, T2_P, Left>::matchShiftOr(
1337 const MatchContext &Ctx, SDValue N, unsigned BitWidth) {
1338 SDValue X, Y, ShlAmt, SrlAmt;
1339 APInt ShlConst, SrlConst;
1340 if (!sd_context_match(
1341 N, Ctx,
1342 m_Or(L: m_Shl(L: m_Value(N&: X), R: m_Value(N&: ShlAmt, P: m_ConstInt(V&: ShlConst))),
1343 R: m_Srl(L: m_Value(N&: Y), R: m_Value(N&: SrlAmt, P: m_ConstInt(V&: SrlConst))))) ||
1344 !hasComplementaryConstantShifts(ShlV: ShlConst, SrlV: SrlConst, BitWidth))
1345 return false;
1346
1347 return matchOperands(Ctx, X, Y, Left ? ShlAmt : SrlAmt);
1348}
1349
1350struct SpecificInt_match {
1351 APInt IntVal;
1352
1353 explicit SpecificInt_match(APInt APV) : IntVal(std::move(APV)) {}
1354
1355 template <typename MatchContext>
1356 bool match(const MatchContext &Ctx, SDValue N) {
1357 APInt ConstInt;
1358 if (sd_context_match(N, Ctx, m_ConstInt(V&: ConstInt)))
1359 return APInt::isSameValue(I1: IntVal, I2: ConstInt);
1360 return false;
1361 }
1362};
1363
1364/// Match a specific integer constant or constant splat value.
1365inline SpecificInt_match m_SpecificInt(APInt V) {
1366 return SpecificInt_match(std::move(V));
1367}
1368inline SpecificInt_match m_SpecificInt(uint64_t V) {
1369 return SpecificInt_match(APInt(64, V));
1370}
1371
1372struct SpecificFP_match {
1373 APFloat Val;
1374
1375 explicit SpecificFP_match(APFloat V) : Val(V) {}
1376
1377 template <typename MatchContext>
1378 bool match(const MatchContext &Ctx, SDValue V) {
1379 if (const auto *CFP = dyn_cast<ConstantFPSDNode>(Val: V.getNode()))
1380 return CFP->isExactlyValue(V: Val);
1381 if (ConstantFPSDNode *C = isConstOrConstSplatFP(N: V, /*AllowUndefs=*/AllowUndefs: true))
1382 return C->getValueAPF().compare(RHS: Val) == APFloat::cmpEqual;
1383 return false;
1384 }
1385};
1386
1387/// Match a specific float constant.
1388inline SpecificFP_match m_SpecificFP(APFloat V) { return SpecificFP_match(V); }
1389
1390inline SpecificFP_match m_SpecificFP(double V) {
1391 return SpecificFP_match(APFloat(V));
1392}
1393
1394struct AnyZeroFP_match {
1395 template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
1396 if (ConstantFPSDNode *C = isConstOrConstSplatFP(N))
1397 return C->isZero();
1398 return false;
1399 }
1400};
1401
1402/// Match a floating-point +0.0 or -0.0 constant or splat.
1403inline AnyZeroFP_match m_AnyZeroFP() { return AnyZeroFP_match(); }
1404
1405struct Negative_match {
1406 template <typename MatchContext>
1407 bool match(const MatchContext &Ctx, SDValue N) {
1408 const SelectionDAG *DAG = Ctx.getDAG();
1409 return DAG && DAG->computeKnownBits(Op: N).isNegative();
1410 }
1411};
1412
1413struct NonNegative_match {
1414 template <typename MatchContext>
1415 bool match(const MatchContext &Ctx, SDValue N) {
1416 const SelectionDAG *DAG = Ctx.getDAG();
1417 return DAG && DAG->computeKnownBits(Op: N).isNonNegative();
1418 }
1419};
1420
1421struct StrictlyPositive_match {
1422 template <typename MatchContext>
1423 bool match(const MatchContext &Ctx, SDValue N) {
1424 const SelectionDAG *DAG = Ctx.getDAG();
1425 return DAG && DAG->computeKnownBits(Op: N).isStrictlyPositive();
1426 }
1427};
1428
1429struct NonPositive_match {
1430 template <typename MatchContext>
1431 bool match(const MatchContext &Ctx, SDValue N) {
1432 const SelectionDAG *DAG = Ctx.getDAG();
1433 return DAG && DAG->computeKnownBits(Op: N).isNonPositive();
1434 }
1435};
1436
1437struct NonZero_match {
1438 template <typename MatchContext>
1439 bool match(const MatchContext &Ctx, SDValue N) {
1440 const SelectionDAG *DAG = Ctx.getDAG();
1441 return DAG && DAG->computeKnownBits(Op: N).isNonZero();
1442 }
1443};
1444
1445struct Zero_match {
1446 bool AllowUndefs;
1447
1448 explicit Zero_match(bool AllowUndefs) : AllowUndefs(AllowUndefs) {}
1449
1450 template <typename MatchContext>
1451 bool match(const MatchContext &, SDValue N) const {
1452 return isZeroOrZeroSplat(N, AllowUndefs);
1453 }
1454};
1455
1456struct Ones_match {
1457 bool AllowUndefs;
1458
1459 Ones_match(bool AllowUndefs) : AllowUndefs(AllowUndefs) {}
1460
1461 template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
1462 return isOnesOrOnesSplat(N, AllowUndefs);
1463 }
1464};
1465
1466struct AllOnes_match {
1467 bool AllowUndefs;
1468
1469 AllOnes_match(bool AllowUndefs) : AllowUndefs(AllowUndefs) {}
1470
1471 template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
1472 return isAllOnesOrAllOnesSplat(V: N, AllowUndefs);
1473 }
1474};
1475
1476inline Negative_match m_Negative() { return Negative_match(); }
1477template <typename Pattern> inline auto m_Negative(const Pattern &P) {
1478 return m_AllOf(m_Negative(), P);
1479}
1480inline NonNegative_match m_NonNegative() { return NonNegative_match(); }
1481template <typename Pattern> inline auto m_NonNegative(const Pattern &P) {
1482 return m_AllOf(m_NonNegative(), P);
1483}
1484inline StrictlyPositive_match m_StrictlyPositive() {
1485 return StrictlyPositive_match();
1486}
1487template <typename Pattern> inline auto m_StrictlyPositive(const Pattern &P) {
1488 return m_AllOf(m_StrictlyPositive(), P);
1489}
1490inline NonPositive_match m_NonPositive() { return NonPositive_match(); }
1491template <typename Pattern> inline auto m_NonPositive(const Pattern &P) {
1492 return m_AllOf(m_NonPositive(), P);
1493}
1494inline NonZero_match m_NonZero() { return NonZero_match(); }
1495template <typename Pattern> inline auto m_NonZero(const Pattern &P) {
1496 return m_AllOf(m_NonZero(), P);
1497}
1498inline Ones_match m_One(bool AllowUndefs = false) {
1499 return Ones_match(AllowUndefs);
1500}
1501inline Zero_match m_Zero(bool AllowUndefs = false) {
1502 return Zero_match(AllowUndefs);
1503}
1504inline AllOnes_match m_AllOnes(bool AllowUndefs = false) {
1505 return AllOnes_match(AllowUndefs);
1506}
1507
1508/// Match true boolean value based on the information provided by
1509/// TargetLowering.
1510inline auto m_True() {
1511 return TLI_pred_match{
1512 [](const TargetLowering &TLI, SDValue N) {
1513 APInt ConstVal;
1514 if (sd_match(N, P: m_ConstInt(V&: ConstVal)))
1515 switch (TLI.getBooleanContents(Type: N.getValueType())) {
1516 case TargetLowering::ZeroOrOneBooleanContent:
1517 return ConstVal.isOne();
1518 case TargetLowering::ZeroOrNegativeOneBooleanContent:
1519 return ConstVal.isAllOnes();
1520 case TargetLowering::UndefinedBooleanContent:
1521 return (ConstVal & 0x01) == 1;
1522 }
1523
1524 return false;
1525 },
1526 m_Value()};
1527}
1528/// Match false boolean value based on the information provided by
1529/// TargetLowering.
1530inline auto m_False() {
1531 return TLI_pred_match{
1532 [](const TargetLowering &TLI, SDValue N) {
1533 APInt ConstVal;
1534 if (sd_match(N, P: m_ConstInt(V&: ConstVal)))
1535 switch (TLI.getBooleanContents(Type: N.getValueType())) {
1536 case TargetLowering::ZeroOrOneBooleanContent:
1537 case TargetLowering::ZeroOrNegativeOneBooleanContent:
1538 return ConstVal.isZero();
1539 case TargetLowering::UndefinedBooleanContent:
1540 return (ConstVal & 0x01) == 0;
1541 }
1542
1543 return false;
1544 },
1545 m_Value()};
1546}
1547
1548struct CondCode_match {
1549 std::optional<ISD::CondCode> CCToMatch;
1550 ISD::CondCode *BindCC = nullptr;
1551
1552 explicit CondCode_match(ISD::CondCode CC) : CCToMatch(CC) {}
1553
1554 explicit CondCode_match(ISD::CondCode *CC) : BindCC(CC) {}
1555
1556 template <typename MatchContext> bool match(const MatchContext &, SDValue N) {
1557 if (auto *CC = dyn_cast<CondCodeSDNode>(Val: N.getNode())) {
1558 if (CCToMatch && *CCToMatch != CC->get())
1559 return false;
1560
1561 if (BindCC)
1562 *BindCC = CC->get();
1563 return true;
1564 }
1565
1566 return false;
1567 }
1568};
1569
1570/// Match any conditional code SDNode.
1571inline CondCode_match m_CondCode() { return CondCode_match(nullptr); }
1572/// Match any conditional code SDNode and return its ISD::CondCode value.
1573inline CondCode_match m_CondCode(ISD::CondCode &CC) {
1574 return CondCode_match(&CC);
1575}
1576/// Match a conditional code SDNode with a specific ISD::CondCode.
1577inline CondCode_match m_SpecificCondCode(ISD::CondCode CC) {
1578 return CondCode_match(CC);
1579}
1580
1581/// Match a negate as a sub(0, v)
1582template <typename ValTy>
1583inline BinaryOpc_match<Zero_match, ValTy, false> m_Neg(const ValTy &V) {
1584 return m_Sub(m_Zero(), V);
1585}
1586
1587/// Match a Not as a xor(v, -1) or xor(-1, v)
1588template <typename ValTy>
1589inline BinaryOpc_match<ValTy, AllOnes_match, true> m_Not(const ValTy &V) {
1590 return m_Xor(V, m_AllOnes());
1591}
1592
1593template <unsigned IntrinsicId, typename... OpndPreds>
1594inline auto m_IntrinsicWOChain(const OpndPreds &...Opnds) {
1595 return m_Node(ISD::INTRINSIC_WO_CHAIN, m_SpecificInt(V: IntrinsicId), Opnds...);
1596}
1597
1598struct SpecificNeg_match {
1599 SDValue V;
1600
1601 explicit SpecificNeg_match(SDValue V) : V(V) {}
1602
1603 template <typename MatchContext>
1604 bool match(const MatchContext &Ctx, SDValue N) {
1605 if (sd_context_match(N, Ctx, m_Neg(V: m_Specific(N: V))))
1606 return true;
1607
1608 return ISD::matchBinaryPredicate(
1609 V, N, [](ConstantSDNode *LHS, ConstantSDNode *RHS) {
1610 return LHS->getAPIntValue() == -RHS->getAPIntValue();
1611 });
1612 }
1613};
1614
1615/// Match a negation of a specific value V, either as sub(0, V) or as
1616/// constant(s) that are the negation of V's constant(s).
1617inline SpecificNeg_match m_SpecificNeg(SDValue V) {
1618 return SpecificNeg_match(V);
1619}
1620
1621template <typename... PatternTs> struct ReassociatableOpc_match {
1622 unsigned Opcode;
1623 std::tuple<PatternTs...> Patterns;
1624 constexpr static size_t NumPatterns =
1625 std::tuple_size_v<std::tuple<PatternTs...>>;
1626
1627 SDNodeFlags Flags;
1628
1629 ReassociatableOpc_match(unsigned Opcode, const PatternTs &...Patterns)
1630 : Opcode(Opcode), Patterns(Patterns...) {}
1631
1632 ReassociatableOpc_match(unsigned Opcode, SDNodeFlags Flags,
1633 const PatternTs &...Patterns)
1634 : Opcode(Opcode), Patterns(Patterns...), Flags(Flags) {}
1635
1636 template <typename MatchContext>
1637 bool match(const MatchContext &Ctx, SDValue N) {
1638 std::array<SDValue, NumPatterns> Leaves;
1639 size_t LeavesIdx = 0;
1640 if (!(collectLeaves(V: N, Leaves, LeafIdx&: LeavesIdx) && (LeavesIdx == NumPatterns)))
1641 return false;
1642
1643 Bitset<NumPatterns> Used;
1644 return std::apply(
1645 [&](auto &...P) -> bool {
1646 return reassociatableMatchHelper(Ctx, Leaves, Used, P...);
1647 },
1648 Patterns);
1649 }
1650
1651 bool collectLeaves(SDValue V, std::array<SDValue, NumPatterns> &Leaves,
1652 std::size_t &LeafIdx) {
1653 if (V->getOpcode() == Opcode && (Flags & V->getFlags()) == Flags) {
1654 for (size_t I = 0, N = V->getNumOperands(); I < N; I++)
1655 if ((LeafIdx == NumPatterns) ||
1656 !collectLeaves(V: V->getOperand(Num: I), Leaves, LeafIdx))
1657 return false;
1658 } else {
1659 Leaves[LeafIdx] = V;
1660 LeafIdx++;
1661 }
1662 return true;
1663 }
1664
1665 // Searchs for a matching leaf for every sub-pattern.
1666 template <typename MatchContext, typename PatternHd, typename... PatternTl>
1667 [[nodiscard]] inline bool
1668 reassociatableMatchHelper(const MatchContext &Ctx, ArrayRef<SDValue> Leaves,
1669 Bitset<NumPatterns> &Used, PatternHd &HeadPattern,
1670 PatternTl &...TailPatterns) {
1671 for (size_t Match = 0, N = Used.size(); Match < N; Match++) {
1672 if (Used[Match] || !(sd_context_match(Leaves[Match], Ctx, HeadPattern)))
1673 continue;
1674 Used.set(Match);
1675 if (reassociatableMatchHelper(Ctx, Leaves, Used, TailPatterns...))
1676 return true;
1677 Used.reset(Match);
1678 }
1679 return false;
1680 }
1681
1682 template <typename MatchContext>
1683 [[nodiscard]] inline bool
1684 reassociatableMatchHelper(const MatchContext &Ctx, ArrayRef<SDValue> Leaves,
1685 Bitset<NumPatterns> &Used) {
1686 return true;
1687 }
1688};
1689
1690template <typename... PatternTs>
1691inline ReassociatableOpc_match<PatternTs...>
1692m_ReassociatableAdd(const PatternTs &...Patterns) {
1693 return ReassociatableOpc_match<PatternTs...>(ISD::ADD, Patterns...);
1694}
1695
1696template <typename... PatternTs>
1697inline ReassociatableOpc_match<PatternTs...>
1698m_ReassociatableOr(const PatternTs &...Patterns) {
1699 return ReassociatableOpc_match<PatternTs...>(ISD::OR, Patterns...);
1700}
1701
1702template <typename... PatternTs>
1703inline ReassociatableOpc_match<PatternTs...>
1704m_ReassociatableAnd(const PatternTs &...Patterns) {
1705 return ReassociatableOpc_match<PatternTs...>(ISD::AND, Patterns...);
1706}
1707
1708template <typename... PatternTs>
1709inline ReassociatableOpc_match<PatternTs...>
1710m_ReassociatableMul(const PatternTs &...Patterns) {
1711 return ReassociatableOpc_match<PatternTs...>(ISD::MUL, Patterns...);
1712}
1713
1714template <typename... PatternTs>
1715inline ReassociatableOpc_match<PatternTs...>
1716m_ReassociatableNSWAdd(const PatternTs &...Patterns) {
1717 return ReassociatableOpc_match<PatternTs...>(
1718 ISD::ADD, SDNodeFlags::NoSignedWrap, Patterns...);
1719}
1720
1721template <typename... PatternTs>
1722inline ReassociatableOpc_match<PatternTs...>
1723m_ReassociatableNUWAdd(const PatternTs &...Patterns) {
1724 return ReassociatableOpc_match<PatternTs...>(
1725 ISD::ADD, SDNodeFlags::NoUnsignedWrap, Patterns...);
1726}
1727
1728} // namespace SDPatternMatch
1729} // namespace llvm
1730#endif
1731