blob: 13eddd9539fa85432d6e667591f609f0e891e1cb [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
15#include "llvm/ADT/APFloat.h"
16#include "llvm/ADT/APInt.h"
17#include "llvm/CodeGen/GlobalISel/Utils.h"
18#include "llvm/CodeGen/MachineRegisterInfo.h"
19
20namespace llvm {
21namespace MIPatternMatch {
22
23template <typename Reg, typename Pattern>
24bool mi_match(Reg R, MachineRegisterInfo &MRI, Pattern &&P) {
25 return P.match(MRI, R);
26}
27
28// TODO: Extend for N use.
29template <typename SubPatternT> struct OneUse_match {
30 SubPatternT SubPat;
31 OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
32
Andrew Walbran3d2c1972020-04-07 12:24:26 +010033 bool match(MachineRegisterInfo &MRI, unsigned Reg) {
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010034 return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
35 }
36};
37
38template <typename SubPat>
39inline OneUse_match<SubPat> m_OneUse(const SubPat &SP) {
40 return SP;
41}
42
43struct ConstantMatch {
44 int64_t &CR;
45 ConstantMatch(int64_t &C) : CR(C) {}
46 bool match(const MachineRegisterInfo &MRI, unsigned Reg) {
47 if (auto MaybeCst = getConstantVRegVal(Reg, MRI)) {
48 CR = *MaybeCst;
49 return true;
50 }
51 return false;
52 }
53};
54
55inline ConstantMatch m_ICst(int64_t &Cst) { return ConstantMatch(Cst); }
56
57// TODO: Rework this for different kinds of MachineOperand.
58// Currently assumes the Src for a match is a register.
59// We might want to support taking in some MachineOperands and call getReg on
60// that.
61
62struct operand_type_match {
63 bool match(const MachineRegisterInfo &MRI, unsigned Reg) { return true; }
64 bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) {
65 return MO->isReg();
66 }
67};
68
69inline operand_type_match m_Reg() { return operand_type_match(); }
70
71/// Matching combinators.
72template <typename... Preds> struct And {
73 template <typename MatchSrc>
74 bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
75 return true;
76 }
77};
78
79template <typename Pred, typename... Preds>
80struct And<Pred, Preds...> : And<Preds...> {
81 Pred P;
82 And(Pred &&p, Preds &&... preds)
83 : And<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {
84 }
85 template <typename MatchSrc>
86 bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
87 return P.match(MRI, src) && And<Preds...>::match(MRI, src);
88 }
89};
90
91template <typename... Preds> struct Or {
92 template <typename MatchSrc>
93 bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
94 return false;
95 }
96};
97
98template <typename Pred, typename... Preds>
99struct Or<Pred, Preds...> : Or<Preds...> {
100 Pred P;
101 Or(Pred &&p, Preds &&... preds)
102 : Or<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {}
103 template <typename MatchSrc>
104 bool match(MachineRegisterInfo &MRI, MatchSrc &&src) {
105 return P.match(MRI, src) || Or<Preds...>::match(MRI, src);
106 }
107};
108
109template <typename... Preds> And<Preds...> m_all_of(Preds &&... preds) {
110 return And<Preds...>(std::forward<Preds>(preds)...);
111}
112
113template <typename... Preds> Or<Preds...> m_any_of(Preds &&... preds) {
114 return Or<Preds...>(std::forward<Preds>(preds)...);
115}
116
117template <typename BindTy> struct bind_helper {
118 static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
119 VR = V;
120 return true;
121 }
122};
123
124template <> struct bind_helper<MachineInstr *> {
125 static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
126 unsigned Reg) {
127 MI = MRI.getVRegDef(Reg);
128 if (MI)
129 return true;
130 return false;
131 }
132};
133
134template <> struct bind_helper<LLT> {
135 static bool bind(const MachineRegisterInfo &MRI, LLT &Ty, unsigned Reg) {
136 Ty = MRI.getType(Reg);
137 if (Ty.isValid())
138 return true;
139 return false;
140 }
141};
142
143template <> struct bind_helper<const ConstantFP *> {
144 static bool bind(const MachineRegisterInfo &MRI, const ConstantFP *&F,
145 unsigned Reg) {
146 F = getConstantFPVRegVal(Reg, MRI);
147 if (F)
148 return true;
149 return false;
150 }
151};
152
153template <typename Class> struct bind_ty {
154 Class &VR;
155
156 bind_ty(Class &V) : VR(V) {}
157
158 template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) {
159 return bind_helper<Class>::bind(MRI, VR, V);
160 }
161};
162
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100163inline bind_ty<Register> m_Reg(Register &R) { return R; }
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100164inline bind_ty<MachineInstr *> m_MInstr(MachineInstr *&MI) { return MI; }
165inline bind_ty<LLT> m_Type(LLT &Ty) { return Ty; }
166
167// Helper for matching G_FCONSTANT
168inline bind_ty<const ConstantFP *> m_GFCst(const ConstantFP *&C) { return C; }
169
170// General helper for all the binary generic MI such as G_ADD/G_SUB etc
171template <typename LHS_P, typename RHS_P, unsigned Opcode,
172 bool Commutable = false>
173struct BinaryOp_match {
174 LHS_P L;
175 RHS_P R;
176
177 BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {}
178 template <typename OpTy> bool match(MachineRegisterInfo &MRI, OpTy &&Op) {
179 MachineInstr *TmpMI;
180 if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
181 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) {
182 return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
183 R.match(MRI, TmpMI->getOperand(2).getReg())) ||
184 (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) &&
185 L.match(MRI, TmpMI->getOperand(2).getReg())));
186 }
187 }
188 return false;
189 }
190};
191
192template <typename LHS, typename RHS>
193inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>
194m_GAdd(const LHS &L, const RHS &R) {
195 return BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>(L, R);
196}
197
198template <typename LHS, typename RHS>
199inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB> m_GSub(const LHS &L,
200 const RHS &R) {
201 return BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB>(L, R);
202}
203
204template <typename LHS, typename RHS>
205inline BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>
206m_GMul(const LHS &L, const RHS &R) {
207 return BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>(L, R);
208}
209
210template <typename LHS, typename RHS>
211inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>
212m_GFAdd(const LHS &L, const RHS &R) {
213 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>(L, R);
214}
215
216template <typename LHS, typename RHS>
217inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>
218m_GFMul(const LHS &L, const RHS &R) {
219 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>(L, R);
220}
221
222template <typename LHS, typename RHS>
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100223inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>
224m_GFSub(const LHS &L, const RHS &R) {
225 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>(L, R);
226}
227
228template <typename LHS, typename RHS>
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100229inline BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>
230m_GAnd(const LHS &L, const RHS &R) {
231 return BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>(L, R);
232}
233
234template <typename LHS, typename RHS>
235inline BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true> m_GOr(const LHS &L,
236 const RHS &R) {
237 return BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true>(L, R);
238}
239
240// Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc
241template <typename SrcTy, unsigned Opcode> struct UnaryOp_match {
242 SrcTy L;
243
244 UnaryOp_match(const SrcTy &LHS) : L(LHS) {}
245 template <typename OpTy> bool match(MachineRegisterInfo &MRI, OpTy &&Op) {
246 MachineInstr *TmpMI;
247 if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
248 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) {
249 return L.match(MRI, TmpMI->getOperand(1).getReg());
250 }
251 }
252 return false;
253 }
254};
255
256template <typename SrcTy>
257inline UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>
258m_GAnyExt(const SrcTy &Src) {
259 return UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>(Src);
260}
261
262template <typename SrcTy>
263inline UnaryOp_match<SrcTy, TargetOpcode::G_SEXT> m_GSExt(const SrcTy &Src) {
264 return UnaryOp_match<SrcTy, TargetOpcode::G_SEXT>(Src);
265}
266
267template <typename SrcTy>
268inline UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT> m_GZExt(const SrcTy &Src) {
269 return UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT>(Src);
270}
271
272template <typename SrcTy>
273inline UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT> m_GFPExt(const SrcTy &Src) {
274 return UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT>(Src);
275}
276
277template <typename SrcTy>
278inline UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC> m_GTrunc(const SrcTy &Src) {
279 return UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC>(Src);
280}
281
282template <typename SrcTy>
283inline UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>
284m_GBitcast(const SrcTy &Src) {
285 return UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>(Src);
286}
287
288template <typename SrcTy>
289inline UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>
290m_GPtrToInt(const SrcTy &Src) {
291 return UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>(Src);
292}
293
294template <typename SrcTy>
295inline UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>
296m_GIntToPtr(const SrcTy &Src) {
297 return UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>(Src);
298}
299
300template <typename SrcTy>
301inline UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>
302m_GFPTrunc(const SrcTy &Src) {
303 return UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>(Src);
304}
305
306template <typename SrcTy>
307inline UnaryOp_match<SrcTy, TargetOpcode::G_FABS> m_GFabs(const SrcTy &Src) {
308 return UnaryOp_match<SrcTy, TargetOpcode::G_FABS>(Src);
309}
310
311template <typename SrcTy>
Andrew Scullcdfcccc2018-10-05 20:58:37 +0100312inline UnaryOp_match<SrcTy, TargetOpcode::G_FNEG> m_GFNeg(const SrcTy &Src) {
313 return UnaryOp_match<SrcTy, TargetOpcode::G_FNEG>(Src);
314}
315
316template <typename SrcTy>
Andrew Scull5e1ddfa2018-08-14 10:06:54 +0100317inline UnaryOp_match<SrcTy, TargetOpcode::COPY> m_Copy(SrcTy &&Src) {
318 return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src));
319}
320
321// Helper for checking if a Reg is of specific type.
322struct CheckType {
323 LLT Ty;
324 CheckType(const LLT &Ty) : Ty(Ty) {}
325
326 bool match(MachineRegisterInfo &MRI, unsigned Reg) {
327 return MRI.getType(Reg) == Ty;
328 }
329};
330
331inline CheckType m_SpecificType(LLT Ty) { return Ty; }
332
333} // namespace GMIPatternMatch
334} // namespace llvm
335
336#endif