blob: 55d6d365fbb43d382ae44cb83f25b1ec5fbcb4a4 [file] [log] [blame]
Andrew Walbran3d2c1972020-04-07 12:24:26 +01001//==------ llvm/CodeGen/GlobalISel/MIPatternMatch.h -------------*- C++ -*-===//
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01002//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// 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
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
7//===----------------------------------------------------------------------===//
8//
9/// Contains matchers for matching SSA Machine Instructions.
10//
11//===----------------------------------------------------------------------===//
12#ifndef LLVM_GMIR_PATTERNMATCH_H
13#define LLVM_GMIR_PATTERNMATCH_H
14
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010015#include "llvm/CodeGen/GlobalISel/Utils.h"
16#include "llvm/CodeGen/MachineRegisterInfo.h"
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020017#include "llvm/IR/InstrTypes.h"
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010018
19namespace llvm {
20namespace MIPatternMatch {
21
22template <typename Reg, typename Pattern>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020023bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010024 return P.match(MRI, R);
25}
26
27// TODO: Extend for N use.
28template <typename SubPatternT> struct OneUse_match {
29 SubPatternT SubPat;
30 OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
31
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020032 bool match(const MachineRegisterInfo &MRI, Register Reg) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010033 return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
34 }
35};
36
37template <typename SubPat>
38inline OneUse_match<SubPat> m_OneUse(const SubPat &SP) {
39 return SP;
40}
41
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020042template <typename SubPatternT> struct OneNonDBGUse_match {
43 SubPatternT SubPat;
44 OneNonDBGUse_match(const SubPatternT &SP) : SubPat(SP) {}
45
46 bool match(const MachineRegisterInfo &MRI, Register Reg) {
47 return MRI.hasOneNonDBGUse(Reg) && SubPat.match(MRI, Reg);
48 }
49};
50
51template <typename SubPat>
52inline OneNonDBGUse_match<SubPat> m_OneNonDBGUse(const SubPat &SP) {
53 return SP;
54}
55
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010056struct ConstantMatch {
57 int64_t &CR;
58 ConstantMatch(int64_t &C) : CR(C) {}
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020059 bool match(const MachineRegisterInfo &MRI, Register Reg) {
60 if (auto MaybeCst = getConstantVRegSExtVal(Reg, MRI)) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010061 CR = *MaybeCst;
62 return true;
63 }
64 return false;
65 }
66};
67
68inline ConstantMatch m_ICst(int64_t &Cst) { return ConstantMatch(Cst); }
69
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020070/// Matcher for a specific constant value.
71struct SpecificConstantMatch {
72 int64_t RequestedVal;
73 SpecificConstantMatch(int64_t RequestedVal) : RequestedVal(RequestedVal) {}
74 bool match(const MachineRegisterInfo &MRI, Register Reg) {
75 int64_t MatchedVal;
76 return mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal;
77 }
78};
79
80/// Matches a constant equal to \p RequestedValue.
81inline SpecificConstantMatch m_SpecificICst(int64_t RequestedValue) {
82 return SpecificConstantMatch(RequestedValue);
83}
84
85///{
86/// Convenience matchers for specific integer values.
87inline SpecificConstantMatch m_ZeroInt() { return SpecificConstantMatch(0); }
88inline SpecificConstantMatch m_AllOnesInt() {
89 return SpecificConstantMatch(-1);
90}
91///}
92
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010093// TODO: Rework this for different kinds of MachineOperand.
94// Currently assumes the Src for a match is a register.
95// We might want to support taking in some MachineOperands and call getReg on
96// that.
97
98struct operand_type_match {
Olivier Deprezf4ef2d02021-04-20 13:36:24 +020099 bool match(const MachineRegisterInfo &MRI, Register Reg) { return true; }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100100 bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) {
101 return MO->isReg();
102 }
103};
104
105inline operand_type_match m_Reg() { return operand_type_match(); }
106
107/// Matching combinators.
108template <typename... Preds> struct And {
109 template <typename MatchSrc>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200110 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100111 return true;
112 }
113};
114
115template <typename Pred, typename... Preds>
116struct And<Pred, Preds...> : And<Preds...> {
117 Pred P;
118 And(Pred &&p, Preds &&... preds)
119 : And<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {
120 }
121 template <typename MatchSrc>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200122 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100123 return P.match(MRI, src) && And<Preds...>::match(MRI, src);
124 }
125};
126
127template <typename... Preds> struct Or {
128 template <typename MatchSrc>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200129 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100130 return false;
131 }
132};
133
134template <typename Pred, typename... Preds>
135struct Or<Pred, Preds...> : Or<Preds...> {
136 Pred P;
137 Or(Pred &&p, Preds &&... preds)
138 : Or<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {}
139 template <typename MatchSrc>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200140 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100141 return P.match(MRI, src) || Or<Preds...>::match(MRI, src);
142 }
143};
144
145template <typename... Preds> And<Preds...> m_all_of(Preds &&... preds) {
146 return And<Preds...>(std::forward<Preds>(preds)...);
147}
148
149template <typename... Preds> Or<Preds...> m_any_of(Preds &&... preds) {
150 return Or<Preds...>(std::forward<Preds>(preds)...);
151}
152
153template <typename BindTy> struct bind_helper {
154 static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
155 VR = V;
156 return true;
157 }
158};
159
160template <> struct bind_helper<MachineInstr *> {
161 static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200162 Register Reg) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100163 MI = MRI.getVRegDef(Reg);
164 if (MI)
165 return true;
166 return false;
167 }
168};
169
170template <> struct bind_helper<LLT> {
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200171 static bool bind(const MachineRegisterInfo &MRI, LLT Ty, Register Reg) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100172 Ty = MRI.getType(Reg);
173 if (Ty.isValid())
174 return true;
175 return false;
176 }
177};
178
179template <> struct bind_helper<const ConstantFP *> {
180 static bool bind(const MachineRegisterInfo &MRI, const ConstantFP *&F,
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200181 Register Reg) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100182 F = getConstantFPVRegVal(Reg, MRI);
183 if (F)
184 return true;
185 return false;
186 }
187};
188
189template <typename Class> struct bind_ty {
190 Class &VR;
191
192 bind_ty(Class &V) : VR(V) {}
193
194 template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) {
195 return bind_helper<Class>::bind(MRI, VR, V);
196 }
197};
198
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100199inline bind_ty<Register> m_Reg(Register &R) { return R; }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100200inline bind_ty<MachineInstr *> m_MInstr(MachineInstr *&MI) { return MI; }
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200201inline bind_ty<LLT> m_Type(LLT Ty) { return Ty; }
202inline bind_ty<CmpInst::Predicate> m_Pred(CmpInst::Predicate &P) { return P; }
203inline operand_type_match m_Pred() { return operand_type_match(); }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100204
205// Helper for matching G_FCONSTANT
206inline bind_ty<const ConstantFP *> m_GFCst(const ConstantFP *&C) { return C; }
207
208// General helper for all the binary generic MI such as G_ADD/G_SUB etc
209template <typename LHS_P, typename RHS_P, unsigned Opcode,
210 bool Commutable = false>
211struct BinaryOp_match {
212 LHS_P L;
213 RHS_P R;
214
215 BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {}
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200216 template <typename OpTy>
217 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100218 MachineInstr *TmpMI;
219 if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
220 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) {
221 return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
222 R.match(MRI, TmpMI->getOperand(2).getReg())) ||
223 (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) &&
224 L.match(MRI, TmpMI->getOperand(2).getReg())));
225 }
226 }
227 return false;
228 }
229};
230
231template <typename LHS, typename RHS>
232inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>
233m_GAdd(const LHS &L, const RHS &R) {
234 return BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>(L, R);
235}
236
237template <typename LHS, typename RHS>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200238inline BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, true>
239m_GPtrAdd(const LHS &L, const RHS &R) {
240 return BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, true>(L, R);
241}
242
243template <typename LHS, typename RHS>
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100244inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB> m_GSub(const LHS &L,
245 const RHS &R) {
246 return BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB>(L, R);
247}
248
249template <typename LHS, typename RHS>
250inline BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>
251m_GMul(const LHS &L, const RHS &R) {
252 return BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>(L, R);
253}
254
255template <typename LHS, typename RHS>
256inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>
257m_GFAdd(const LHS &L, const RHS &R) {
258 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>(L, R);
259}
260
261template <typename LHS, typename RHS>
262inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>
263m_GFMul(const LHS &L, const RHS &R) {
264 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>(L, R);
265}
266
267template <typename LHS, typename RHS>
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100268inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>
269m_GFSub(const LHS &L, const RHS &R) {
270 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>(L, R);
271}
272
273template <typename LHS, typename RHS>
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100274inline BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>
275m_GAnd(const LHS &L, const RHS &R) {
276 return BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>(L, R);
277}
278
279template <typename LHS, typename RHS>
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200280inline BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>
281m_GXor(const LHS &L, const RHS &R) {
282 return BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>(L, R);
283}
284
285template <typename LHS, typename RHS>
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100286inline BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true> m_GOr(const LHS &L,
287 const RHS &R) {
288 return BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true>(L, R);
289}
290
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200291template <typename LHS, typename RHS>
292inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>
293m_GShl(const LHS &L, const RHS &R) {
294 return BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>(L, R);
295}
296
297template <typename LHS, typename RHS>
298inline BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>
299m_GLShr(const LHS &L, const RHS &R) {
300 return BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>(L, R);
301}
302
303template <typename LHS, typename RHS>
304inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>
305m_GAShr(const LHS &L, const RHS &R) {
306 return BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>(L, R);
307}
308
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100309// Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc
310template <typename SrcTy, unsigned Opcode> struct UnaryOp_match {
311 SrcTy L;
312
313 UnaryOp_match(const SrcTy &LHS) : L(LHS) {}
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200314 template <typename OpTy>
315 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100316 MachineInstr *TmpMI;
317 if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
318 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) {
319 return L.match(MRI, TmpMI->getOperand(1).getReg());
320 }
321 }
322 return false;
323 }
324};
325
326template <typename SrcTy>
327inline UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>
328m_GAnyExt(const SrcTy &Src) {
329 return UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>(Src);
330}
331
332template <typename SrcTy>
333inline UnaryOp_match<SrcTy, TargetOpcode::G_SEXT> m_GSExt(const SrcTy &Src) {
334 return UnaryOp_match<SrcTy, TargetOpcode::G_SEXT>(Src);
335}
336
337template <typename SrcTy>
338inline UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT> m_GZExt(const SrcTy &Src) {
339 return UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT>(Src);
340}
341
342template <typename SrcTy>
343inline UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT> m_GFPExt(const SrcTy &Src) {
344 return UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT>(Src);
345}
346
347template <typename SrcTy>
348inline UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC> m_GTrunc(const SrcTy &Src) {
349 return UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC>(Src);
350}
351
352template <typename SrcTy>
353inline UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>
354m_GBitcast(const SrcTy &Src) {
355 return UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>(Src);
356}
357
358template <typename SrcTy>
359inline UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>
360m_GPtrToInt(const SrcTy &Src) {
361 return UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>(Src);
362}
363
364template <typename SrcTy>
365inline UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>
366m_GIntToPtr(const SrcTy &Src) {
367 return UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>(Src);
368}
369
370template <typename SrcTy>
371inline UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>
372m_GFPTrunc(const SrcTy &Src) {
373 return UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>(Src);
374}
375
376template <typename SrcTy>
377inline UnaryOp_match<SrcTy, TargetOpcode::G_FABS> m_GFabs(const SrcTy &Src) {
378 return UnaryOp_match<SrcTy, TargetOpcode::G_FABS>(Src);
379}
380
381template <typename SrcTy>
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100382inline UnaryOp_match<SrcTy, TargetOpcode::G_FNEG> m_GFNeg(const SrcTy &Src) {
383 return UnaryOp_match<SrcTy, TargetOpcode::G_FNEG>(Src);
384}
385
386template <typename SrcTy>
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100387inline UnaryOp_match<SrcTy, TargetOpcode::COPY> m_Copy(SrcTy &&Src) {
388 return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src));
389}
390
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200391// General helper for generic MI compares, i.e. G_ICMP and G_FCMP
392// TODO: Allow checking a specific predicate.
393template <typename Pred_P, typename LHS_P, typename RHS_P, unsigned Opcode>
394struct CompareOp_match {
395 Pred_P P;
396 LHS_P L;
397 RHS_P R;
398
399 CompareOp_match(const Pred_P &Pred, const LHS_P &LHS, const RHS_P &RHS)
400 : P(Pred), L(LHS), R(RHS) {}
401
402 template <typename OpTy>
403 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
404 MachineInstr *TmpMI;
405 if (!mi_match(Op, MRI, m_MInstr(TmpMI)) || TmpMI->getOpcode() != Opcode)
406 return false;
407
408 auto TmpPred =
409 static_cast<CmpInst::Predicate>(TmpMI->getOperand(1).getPredicate());
410 if (!P.match(MRI, TmpPred))
411 return false;
412
413 return L.match(MRI, TmpMI->getOperand(2).getReg()) &&
414 R.match(MRI, TmpMI->getOperand(3).getReg());
415 }
416};
417
418template <typename Pred, typename LHS, typename RHS>
419inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>
420m_GICmp(const Pred &P, const LHS &L, const RHS &R) {
421 return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>(P, L, R);
422}
423
424template <typename Pred, typename LHS, typename RHS>
425inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>
426m_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
427 return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>(P, L, R);
428}
429
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100430// Helper for checking if a Reg is of specific type.
431struct CheckType {
432 LLT Ty;
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200433 CheckType(const LLT Ty) : Ty(Ty) {}
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100434
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200435 bool match(const MachineRegisterInfo &MRI, Register Reg) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100436 return MRI.getType(Reg) == Ty;
437 }
438};
439
440inline CheckType m_SpecificType(LLT Ty) { return Ty; }
441
Olivier Deprezf4ef2d02021-04-20 13:36:24 +0200442template <typename Src0Ty, typename Src1Ty, typename Src2Ty, unsigned Opcode>
443struct TernaryOp_match {
444 Src0Ty Src0;
445 Src1Ty Src1;
446 Src2Ty Src2;
447
448 TernaryOp_match(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
449 : Src0(Src0), Src1(Src1), Src2(Src2) {}
450 template <typename OpTy>
451 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
452 MachineInstr *TmpMI;
453 if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
454 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 4) {
455 return (Src0.match(MRI, TmpMI->getOperand(1).getReg()) &&
456 Src1.match(MRI, TmpMI->getOperand(2).getReg()) &&
457 Src2.match(MRI, TmpMI->getOperand(3).getReg()));
458 }
459 }
460 return false;
461 }
462};
463template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
464inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
465 TargetOpcode::G_INSERT_VECTOR_ELT>
466m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
467 return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
468 TargetOpcode::G_INSERT_VECTOR_ELT>(Src0, Src1, Src2);
469}
470
471/// Matches a register negated by a G_SUB.
472/// G_SUB 0, %negated_reg
473template <typename SrcTy>
474inline BinaryOp_match<SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB>
475m_Neg(const SrcTy &&Src) {
476 return m_GSub(m_ZeroInt(), Src);
477}
478
479/// Matches a register not-ed by a G_XOR.
480/// G_XOR %not_reg, -1
481template <typename SrcTy>
482inline BinaryOp_match<SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true>
483m_Not(const SrcTy &&Src) {
484 return m_GXor(Src, m_AllOnesInt());
485}
486
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100487} // namespace GMIPatternMatch
488} // namespace llvm
489
490#endif