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