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// 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, const 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 bool match(const MachineRegisterInfo &MRI, unsigned Reg) { 34 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(const 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(const 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(const 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(const 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 163inline bind_ty<Register> m_Reg(Register &R) { return R; } 164inline 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> 179 bool match(const 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> 224inline 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> 230inline 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> 247 bool match(const 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> 314inline 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> 319inline 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(const 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 339