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