1 //==------ llvm/CodeGen/GlobalISel/MIPatternMatch.h -------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 /// Contains matchers for matching SSA Machine Instructions.
11 //===----------------------------------------------------------------------===//
12 #ifndef LLVM_GMIR_PATTERNMATCH_H
13 #define LLVM_GMIR_PATTERNMATCH_H
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"
21 namespace MIPatternMatch
{
23 template <typename Reg
, typename Pattern
>
24 bool mi_match(Reg R
, const MachineRegisterInfo
&MRI
, Pattern
&&P
) {
25 return P
.match(MRI
, R
);
28 // TODO: Extend for N use.
29 template <typename SubPatternT
> struct OneUse_match
{
31 OneUse_match(const SubPatternT
&SP
) : SubPat(SP
) {}
33 bool match(const MachineRegisterInfo
&MRI
, unsigned Reg
) {
34 return MRI
.hasOneUse(Reg
) && SubPat
.match(MRI
, Reg
);
38 template <typename SubPat
>
39 inline OneUse_match
<SubPat
> m_OneUse(const SubPat
&SP
) {
43 struct ConstantMatch
{
45 ConstantMatch(int64_t &C
) : CR(C
) {}
46 bool match(const MachineRegisterInfo
&MRI
, unsigned Reg
) {
47 if (auto MaybeCst
= getConstantVRegVal(Reg
, MRI
)) {
55 inline ConstantMatch
m_ICst(int64_t &Cst
) { return ConstantMatch(Cst
); }
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
62 struct operand_type_match
{
63 bool match(const MachineRegisterInfo
&MRI
, unsigned Reg
) { return true; }
64 bool match(const MachineRegisterInfo
&MRI
, MachineOperand
*MO
) {
69 inline operand_type_match
m_Reg() { return operand_type_match(); }
71 /// Matching combinators.
72 template <typename
... Preds
> struct And
{
73 template <typename MatchSrc
>
74 bool match(const MachineRegisterInfo
&MRI
, MatchSrc
&&src
) {
79 template <typename Pred
, typename
... Preds
>
80 struct And
<Pred
, Preds
...> : And
<Preds
...> {
82 And(Pred
&&p
, Preds
&&... preds
)
83 : And
<Preds
...>(std::forward
<Preds
>(preds
)...), P(std::forward
<Pred
>(p
)) {
85 template <typename MatchSrc
>
86 bool match(const MachineRegisterInfo
&MRI
, MatchSrc
&&src
) {
87 return P
.match(MRI
, src
) && And
<Preds
...>::match(MRI
, src
);
91 template <typename
... Preds
> struct Or
{
92 template <typename MatchSrc
>
93 bool match(const MachineRegisterInfo
&MRI
, MatchSrc
&&src
) {
98 template <typename Pred
, typename
... Preds
>
99 struct Or
<Pred
, Preds
...> : Or
<Preds
...> {
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(const MachineRegisterInfo
&MRI
, MatchSrc
&&src
) {
105 return P
.match(MRI
, src
) || Or
<Preds
...>::match(MRI
, src
);
109 template <typename
... Preds
> And
<Preds
...> m_all_of(Preds
&&... preds
) {
110 return And
<Preds
...>(std::forward
<Preds
>(preds
)...);
113 template <typename
... Preds
> Or
<Preds
...> m_any_of(Preds
&&... preds
) {
114 return Or
<Preds
...>(std::forward
<Preds
>(preds
)...);
117 template <typename BindTy
> struct bind_helper
{
118 static bool bind(const MachineRegisterInfo
&MRI
, BindTy
&VR
, BindTy
&V
) {
124 template <> struct bind_helper
<MachineInstr
*> {
125 static bool bind(const MachineRegisterInfo
&MRI
, MachineInstr
*&MI
,
127 MI
= MRI
.getVRegDef(Reg
);
134 template <> struct bind_helper
<LLT
> {
135 static bool bind(const MachineRegisterInfo
&MRI
, LLT
&Ty
, unsigned Reg
) {
136 Ty
= MRI
.getType(Reg
);
143 template <> struct bind_helper
<const ConstantFP
*> {
144 static bool bind(const MachineRegisterInfo
&MRI
, const ConstantFP
*&F
,
146 F
= getConstantFPVRegVal(Reg
, MRI
);
153 template <typename Class
> struct bind_ty
{
156 bind_ty(Class
&V
) : VR(V
) {}
158 template <typename ITy
> bool match(const MachineRegisterInfo
&MRI
, ITy
&&V
) {
159 return bind_helper
<Class
>::bind(MRI
, VR
, V
);
163 inline bind_ty
<Register
> m_Reg(Register
&R
) { return R
; }
164 inline bind_ty
<MachineInstr
*> m_MInstr(MachineInstr
*&MI
) { return MI
; }
165 inline bind_ty
<LLT
> m_Type(LLT
&Ty
) { return Ty
; }
167 // Helper for matching G_FCONSTANT
168 inline bind_ty
<const ConstantFP
*> m_GFCst(const ConstantFP
*&C
) { return C
; }
170 // General helper for all the binary generic MI such as G_ADD/G_SUB etc
171 template <typename LHS_P
, typename RHS_P
, unsigned Opcode
,
172 bool Commutable
= false>
173 struct BinaryOp_match
{
177 BinaryOp_match(const LHS_P
&LHS
, const RHS_P
&RHS
) : L(LHS
), R(RHS
) {}
178 template <typename OpTy
>
179 bool match(const MachineRegisterInfo
&MRI
, OpTy
&&Op
) {
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())));
193 template <typename LHS
, typename RHS
>
194 inline BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_ADD
, true>
195 m_GAdd(const LHS
&L
, const RHS
&R
) {
196 return BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_ADD
, true>(L
, R
);
199 template <typename LHS
, typename RHS
>
200 inline BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_SUB
> m_GSub(const LHS
&L
,
202 return BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_SUB
>(L
, R
);
205 template <typename LHS
, typename RHS
>
206 inline BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_MUL
, true>
207 m_GMul(const LHS
&L
, const RHS
&R
) {
208 return BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_MUL
, true>(L
, R
);
211 template <typename LHS
, typename RHS
>
212 inline BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_FADD
, true>
213 m_GFAdd(const LHS
&L
, const RHS
&R
) {
214 return BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_FADD
, true>(L
, R
);
217 template <typename LHS
, typename RHS
>
218 inline BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_FMUL
, true>
219 m_GFMul(const LHS
&L
, const RHS
&R
) {
220 return BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_FMUL
, true>(L
, R
);
223 template <typename LHS
, typename RHS
>
224 inline BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_FSUB
, false>
225 m_GFSub(const LHS
&L
, const RHS
&R
) {
226 return BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_FSUB
, false>(L
, R
);
229 template <typename LHS
, typename RHS
>
230 inline BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_AND
, true>
231 m_GAnd(const LHS
&L
, const RHS
&R
) {
232 return BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_AND
, true>(L
, R
);
235 template <typename LHS
, typename RHS
>
236 inline BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_OR
, true> m_GOr(const LHS
&L
,
238 return BinaryOp_match
<LHS
, RHS
, TargetOpcode::G_OR
, true>(L
, R
);
241 // Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc
242 template <typename SrcTy
, unsigned Opcode
> struct UnaryOp_match
{
245 UnaryOp_match(const SrcTy
&LHS
) : L(LHS
) {}
246 template <typename OpTy
>
247 bool match(const MachineRegisterInfo
&MRI
, OpTy
&&Op
) {
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());
258 template <typename SrcTy
>
259 inline UnaryOp_match
<SrcTy
, TargetOpcode::G_ANYEXT
>
260 m_GAnyExt(const SrcTy
&Src
) {
261 return UnaryOp_match
<SrcTy
, TargetOpcode::G_ANYEXT
>(Src
);
264 template <typename SrcTy
>
265 inline UnaryOp_match
<SrcTy
, TargetOpcode::G_SEXT
> m_GSExt(const SrcTy
&Src
) {
266 return UnaryOp_match
<SrcTy
, TargetOpcode::G_SEXT
>(Src
);
269 template <typename SrcTy
>
270 inline UnaryOp_match
<SrcTy
, TargetOpcode::G_ZEXT
> m_GZExt(const SrcTy
&Src
) {
271 return UnaryOp_match
<SrcTy
, TargetOpcode::G_ZEXT
>(Src
);
274 template <typename SrcTy
>
275 inline UnaryOp_match
<SrcTy
, TargetOpcode::G_FPEXT
> m_GFPExt(const SrcTy
&Src
) {
276 return UnaryOp_match
<SrcTy
, TargetOpcode::G_FPEXT
>(Src
);
279 template <typename SrcTy
>
280 inline UnaryOp_match
<SrcTy
, TargetOpcode::G_TRUNC
> m_GTrunc(const SrcTy
&Src
) {
281 return UnaryOp_match
<SrcTy
, TargetOpcode::G_TRUNC
>(Src
);
284 template <typename SrcTy
>
285 inline UnaryOp_match
<SrcTy
, TargetOpcode::G_BITCAST
>
286 m_GBitcast(const SrcTy
&Src
) {
287 return UnaryOp_match
<SrcTy
, TargetOpcode::G_BITCAST
>(Src
);
290 template <typename SrcTy
>
291 inline UnaryOp_match
<SrcTy
, TargetOpcode::G_PTRTOINT
>
292 m_GPtrToInt(const SrcTy
&Src
) {
293 return UnaryOp_match
<SrcTy
, TargetOpcode::G_PTRTOINT
>(Src
);
296 template <typename SrcTy
>
297 inline UnaryOp_match
<SrcTy
, TargetOpcode::G_INTTOPTR
>
298 m_GIntToPtr(const SrcTy
&Src
) {
299 return UnaryOp_match
<SrcTy
, TargetOpcode::G_INTTOPTR
>(Src
);
302 template <typename SrcTy
>
303 inline UnaryOp_match
<SrcTy
, TargetOpcode::G_FPTRUNC
>
304 m_GFPTrunc(const SrcTy
&Src
) {
305 return UnaryOp_match
<SrcTy
, TargetOpcode::G_FPTRUNC
>(Src
);
308 template <typename SrcTy
>
309 inline UnaryOp_match
<SrcTy
, TargetOpcode::G_FABS
> m_GFabs(const SrcTy
&Src
) {
310 return UnaryOp_match
<SrcTy
, TargetOpcode::G_FABS
>(Src
);
313 template <typename SrcTy
>
314 inline UnaryOp_match
<SrcTy
, TargetOpcode::G_FNEG
> m_GFNeg(const SrcTy
&Src
) {
315 return UnaryOp_match
<SrcTy
, TargetOpcode::G_FNEG
>(Src
);
318 template <typename SrcTy
>
319 inline UnaryOp_match
<SrcTy
, TargetOpcode::COPY
> m_Copy(SrcTy
&&Src
) {
320 return UnaryOp_match
<SrcTy
, TargetOpcode::COPY
>(std::forward
<SrcTy
>(Src
));
323 // Helper for checking if a Reg is of specific type.
326 CheckType(const LLT
&Ty
) : Ty(Ty
) {}
328 bool match(const MachineRegisterInfo
&MRI
, unsigned Reg
) {
329 return MRI
.getType(Reg
) == Ty
;
333 inline CheckType
m_SpecificType(LLT Ty
) { return Ty
; }
335 } // namespace GMIPatternMatch