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, 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(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(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(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(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(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> bool match(MachineRegisterInfo &MRI, OpTy &&Op) { 179 MachineInstr *TmpMI; 180 if (mi_match(Op, MRI, m_MInstr(TmpMI))) { 181 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) { 182 return (L.match(MRI, TmpMI->getOperand(1).getReg()) && 183 R.match(MRI, TmpMI->getOperand(2).getReg())) || 184 (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) && 185 L.match(MRI, TmpMI->getOperand(2).getReg()))); 186 } 187 } 188 return false; 189 } 190 }; 191 192 template <typename LHS, typename RHS> 193 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true> 194 m_GAdd(const LHS &L, const RHS &R) { 195 return BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>(L, R); 196 } 197 198 template <typename LHS, typename RHS> 199 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB> m_GSub(const LHS &L, 200 const RHS &R) { 201 return BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB>(L, R); 202 } 203 204 template <typename LHS, typename RHS> 205 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true> 206 m_GMul(const LHS &L, const RHS &R) { 207 return BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>(L, R); 208 } 209 210 template <typename LHS, typename RHS> 211 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true> 212 m_GFAdd(const LHS &L, const RHS &R) { 213 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>(L, R); 214 } 215 216 template <typename LHS, typename RHS> 217 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true> 218 m_GFMul(const LHS &L, const RHS &R) { 219 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>(L, R); 220 } 221 222 template <typename LHS, typename RHS> 223 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false> 224 m_GFSub(const LHS &L, const RHS &R) { 225 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>(L, R); 226 } 227 228 template <typename LHS, typename RHS> 229 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true> 230 m_GAnd(const LHS &L, const RHS &R) { 231 return BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>(L, R); 232 } 233 234 template <typename LHS, typename RHS> 235 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true> m_GOr(const LHS &L, 236 const RHS &R) { 237 return BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true>(L, R); 238 } 239 240 // Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc 241 template <typename SrcTy, unsigned Opcode> struct UnaryOp_match { 242 SrcTy L; 243 244 UnaryOp_match(const SrcTy &LHS) : L(LHS) {} 245 template <typename OpTy> bool match(MachineRegisterInfo &MRI, OpTy &&Op) { 246 MachineInstr *TmpMI; 247 if (mi_match(Op, MRI, m_MInstr(TmpMI))) { 248 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) { 249 return L.match(MRI, TmpMI->getOperand(1).getReg()); 250 } 251 } 252 return false; 253 } 254 }; 255 256 template <typename SrcTy> 257 inline UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT> 258 m_GAnyExt(const SrcTy &Src) { 259 return UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>(Src); 260 } 261 262 template <typename SrcTy> 263 inline UnaryOp_match<SrcTy, TargetOpcode::G_SEXT> m_GSExt(const SrcTy &Src) { 264 return UnaryOp_match<SrcTy, TargetOpcode::G_SEXT>(Src); 265 } 266 267 template <typename SrcTy> 268 inline UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT> m_GZExt(const SrcTy &Src) { 269 return UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT>(Src); 270 } 271 272 template <typename SrcTy> 273 inline UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT> m_GFPExt(const SrcTy &Src) { 274 return UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT>(Src); 275 } 276 277 template <typename SrcTy> 278 inline UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC> m_GTrunc(const SrcTy &Src) { 279 return UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC>(Src); 280 } 281 282 template <typename SrcTy> 283 inline UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST> 284 m_GBitcast(const SrcTy &Src) { 285 return UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>(Src); 286 } 287 288 template <typename SrcTy> 289 inline UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT> 290 m_GPtrToInt(const SrcTy &Src) { 291 return UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>(Src); 292 } 293 294 template <typename SrcTy> 295 inline UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR> 296 m_GIntToPtr(const SrcTy &Src) { 297 return UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>(Src); 298 } 299 300 template <typename SrcTy> 301 inline UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC> 302 m_GFPTrunc(const SrcTy &Src) { 303 return UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>(Src); 304 } 305 306 template <typename SrcTy> 307 inline UnaryOp_match<SrcTy, TargetOpcode::G_FABS> m_GFabs(const SrcTy &Src) { 308 return UnaryOp_match<SrcTy, TargetOpcode::G_FABS>(Src); 309 } 310 311 template <typename SrcTy> 312 inline UnaryOp_match<SrcTy, TargetOpcode::G_FNEG> m_GFNeg(const SrcTy &Src) { 313 return UnaryOp_match<SrcTy, TargetOpcode::G_FNEG>(Src); 314 } 315 316 template <typename SrcTy> 317 inline UnaryOp_match<SrcTy, TargetOpcode::COPY> m_Copy(SrcTy &&Src) { 318 return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src)); 319 } 320 321 // Helper for checking if a Reg is of specific type. 322 struct CheckType { 323 LLT Ty; 324 CheckType(const LLT &Ty) : Ty(Ty) {} 325 326 bool match(MachineRegisterInfo &MRI, unsigned Reg) { 327 return MRI.getType(Reg) == Ty; 328 } 329 }; 330 331 inline CheckType m_SpecificType(LLT Ty) { return Ty; } 332 333 } // namespace GMIPatternMatch 334 } // namespace llvm 335 336 #endif 337