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 20 namespace llvm { 21 namespace MIPatternMatch { 22 23 template <typename Reg, typename Pattern> 24 bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P) { 25 return P.match(MRI, R); 26 } 27 28 // TODO: Extend for N use. 29 template <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 38 template <typename SubPat> 39 inline OneUse_match<SubPat> m_OneUse(const SubPat &SP) { 40 return SP; 41 } 42 43 struct 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 55 inline 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 62 struct 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 69 inline operand_type_match m_Reg() { return operand_type_match(); } 70 71 /// Matching combinators. 72 template <typename... Preds> struct And { 73 template <typename MatchSrc> 74 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) { 75 return true; 76 } 77 }; 78 79 template <typename Pred, typename... Preds> 80 struct 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 91 template <typename... Preds> struct Or { 92 template <typename MatchSrc> 93 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) { 94 return false; 95 } 96 }; 97 98 template <typename Pred, typename... Preds> 99 struct 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 109 template <typename... Preds> And<Preds...> m_all_of(Preds &&... preds) { 110 return And<Preds...>(std::forward<Preds>(preds)...); 111 } 112 113 template <typename... Preds> Or<Preds...> m_any_of(Preds &&... preds) { 114 return Or<Preds...>(std::forward<Preds>(preds)...); 115 } 116 117 template <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 124 template <> 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 134 template <> 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 143 template <> 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 153 template <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 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; } 166 167 // Helper for matching G_FCONSTANT 168 inline 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 171 template <typename LHS_P, typename RHS_P, unsigned Opcode, 172 bool Commutable = false> 173 struct 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 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); 197 } 198 199 template <typename LHS, typename RHS> 200 inline 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 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); 209 } 210 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); 215 } 216 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); 221 } 222 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); 227 } 228 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); 233 } 234 235 template <typename LHS, typename RHS> 236 inline 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 242 template <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 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); 262 } 263 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); 267 } 268 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); 272 } 273 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); 277 } 278 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); 282 } 283 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); 288 } 289 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); 294 } 295 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); 300 } 301 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); 306 } 307 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); 311 } 312 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); 316 } 317 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)); 321 } 322 323 // Helper for checking if a Reg is of specific type. 324 struct 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 333 inline CheckType m_SpecificType(LLT Ty) { return Ty; } 334 335 } // namespace GMIPatternMatch 336 } // namespace llvm 337 338 #endif 339