Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

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