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 /// \file 9 /// Contains matchers for matching SSA Machine Instructions. 10 /// 11 //===----------------------------------------------------------------------===// 12 13 #ifndef LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H 14 #define LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H 15 16 #include "llvm/ADT/APInt.h" 17 #include "llvm/CodeGen/GlobalISel/Utils.h" 18 #include "llvm/CodeGen/MachineRegisterInfo.h" 19 #include "llvm/IR/InstrTypes.h" 20 21 namespace llvm { 22 namespace MIPatternMatch { 23 24 template <typename Reg, typename Pattern> 25 bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P) { 26 return P.match(MRI, R); 27 } 28 29 template <typename Pattern> 30 bool mi_match(MachineInstr &MI, const MachineRegisterInfo &MRI, Pattern &&P) { 31 return P.match(MRI, &MI); 32 } 33 34 // TODO: Extend for N use. 35 template <typename SubPatternT> struct OneUse_match { 36 SubPatternT SubPat; 37 OneUse_match(const SubPatternT &SP) : SubPat(SP) {} 38 39 bool match(const MachineRegisterInfo &MRI, Register Reg) { 40 return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg); 41 } 42 }; 43 44 template <typename SubPat> 45 inline OneUse_match<SubPat> m_OneUse(const SubPat &SP) { 46 return SP; 47 } 48 49 template <typename SubPatternT> struct OneNonDBGUse_match { 50 SubPatternT SubPat; 51 OneNonDBGUse_match(const SubPatternT &SP) : SubPat(SP) {} 52 53 bool match(const MachineRegisterInfo &MRI, Register Reg) { 54 return MRI.hasOneNonDBGUse(Reg) && SubPat.match(MRI, Reg); 55 } 56 }; 57 58 template <typename SubPat> 59 inline OneNonDBGUse_match<SubPat> m_OneNonDBGUse(const SubPat &SP) { 60 return SP; 61 } 62 63 template <typename ConstT> 64 inline Optional<ConstT> matchConstant(Register, const MachineRegisterInfo &); 65 66 template <> 67 inline Optional<APInt> matchConstant(Register Reg, 68 const MachineRegisterInfo &MRI) { 69 return getIConstantVRegVal(Reg, MRI); 70 } 71 72 template <> 73 inline Optional<int64_t> matchConstant(Register Reg, 74 const MachineRegisterInfo &MRI) { 75 return getIConstantVRegSExtVal(Reg, MRI); 76 } 77 78 template <typename ConstT> struct ConstantMatch { 79 ConstT &CR; 80 ConstantMatch(ConstT &C) : CR(C) {} 81 bool match(const MachineRegisterInfo &MRI, Register Reg) { 82 if (auto MaybeCst = matchConstant<ConstT>(Reg, MRI)) { 83 CR = *MaybeCst; 84 return true; 85 } 86 return false; 87 } 88 }; 89 90 inline ConstantMatch<APInt> m_ICst(APInt &Cst) { 91 return ConstantMatch<APInt>(Cst); 92 } 93 inline ConstantMatch<int64_t> m_ICst(int64_t &Cst) { 94 return ConstantMatch<int64_t>(Cst); 95 } 96 97 struct GCstAndRegMatch { 98 Optional<ValueAndVReg> &ValReg; 99 GCstAndRegMatch(Optional<ValueAndVReg> &ValReg) : ValReg(ValReg) {} 100 bool match(const MachineRegisterInfo &MRI, Register Reg) { 101 ValReg = getIConstantVRegValWithLookThrough(Reg, MRI); 102 return ValReg ? true : false; 103 } 104 }; 105 106 inline GCstAndRegMatch m_GCst(Optional<ValueAndVReg> &ValReg) { 107 return GCstAndRegMatch(ValReg); 108 } 109 110 struct GFCstAndRegMatch { 111 Optional<FPValueAndVReg> &FPValReg; 112 GFCstAndRegMatch(Optional<FPValueAndVReg> &FPValReg) : FPValReg(FPValReg) {} 113 bool match(const MachineRegisterInfo &MRI, Register Reg) { 114 FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI); 115 return FPValReg ? true : false; 116 } 117 }; 118 119 inline GFCstAndRegMatch m_GFCst(Optional<FPValueAndVReg> &FPValReg) { 120 return GFCstAndRegMatch(FPValReg); 121 } 122 123 struct GFCstOrSplatGFCstMatch { 124 Optional<FPValueAndVReg> &FPValReg; 125 GFCstOrSplatGFCstMatch(Optional<FPValueAndVReg> &FPValReg) 126 : FPValReg(FPValReg) {} 127 bool match(const MachineRegisterInfo &MRI, Register Reg) { 128 return (FPValReg = getFConstantSplat(Reg, MRI)) || 129 (FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI)); 130 }; 131 }; 132 133 inline GFCstOrSplatGFCstMatch 134 m_GFCstOrSplat(Optional<FPValueAndVReg> &FPValReg) { 135 return GFCstOrSplatGFCstMatch(FPValReg); 136 } 137 138 /// Matcher for a specific constant value. 139 struct SpecificConstantMatch { 140 int64_t RequestedVal; 141 SpecificConstantMatch(int64_t RequestedVal) : RequestedVal(RequestedVal) {} 142 bool match(const MachineRegisterInfo &MRI, Register Reg) { 143 int64_t MatchedVal; 144 return mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal; 145 } 146 }; 147 148 /// Matches a constant equal to \p RequestedValue. 149 inline SpecificConstantMatch m_SpecificICst(int64_t RequestedValue) { 150 return SpecificConstantMatch(RequestedValue); 151 } 152 153 /// Matcher for a specific constant splat. 154 struct SpecificConstantSplatMatch { 155 int64_t RequestedVal; 156 SpecificConstantSplatMatch(int64_t RequestedVal) 157 : RequestedVal(RequestedVal) {} 158 bool match(const MachineRegisterInfo &MRI, Register Reg) { 159 return isBuildVectorConstantSplat(Reg, MRI, RequestedVal, 160 /* AllowUndef */ false); 161 } 162 }; 163 164 /// Matches a constant splat of \p RequestedValue. 165 inline SpecificConstantSplatMatch m_SpecificICstSplat(int64_t RequestedValue) { 166 return SpecificConstantSplatMatch(RequestedValue); 167 } 168 169 /// Matcher for a specific constant or constant splat. 170 struct SpecificConstantOrSplatMatch { 171 int64_t RequestedVal; 172 SpecificConstantOrSplatMatch(int64_t RequestedVal) 173 : RequestedVal(RequestedVal) {} 174 bool match(const MachineRegisterInfo &MRI, Register Reg) { 175 int64_t MatchedVal; 176 if (mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal) 177 return true; 178 return isBuildVectorConstantSplat(Reg, MRI, RequestedVal, 179 /* AllowUndef */ false); 180 } 181 }; 182 183 /// Matches a \p RequestedValue constant or a constant splat of \p 184 /// RequestedValue. 185 inline SpecificConstantOrSplatMatch 186 m_SpecificICstOrSplat(int64_t RequestedValue) { 187 return SpecificConstantOrSplatMatch(RequestedValue); 188 } 189 190 ///{ 191 /// Convenience matchers for specific integer values. 192 inline SpecificConstantMatch m_ZeroInt() { return SpecificConstantMatch(0); } 193 inline SpecificConstantMatch m_AllOnesInt() { 194 return SpecificConstantMatch(-1); 195 } 196 ///} 197 198 // TODO: Rework this for different kinds of MachineOperand. 199 // Currently assumes the Src for a match is a register. 200 // We might want to support taking in some MachineOperands and call getReg on 201 // that. 202 203 struct operand_type_match { 204 bool match(const MachineRegisterInfo &MRI, Register Reg) { return true; } 205 bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) { 206 return MO->isReg(); 207 } 208 }; 209 210 inline operand_type_match m_Reg() { return operand_type_match(); } 211 212 /// Matching combinators. 213 template <typename... Preds> struct And { 214 template <typename MatchSrc> 215 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) { 216 return true; 217 } 218 }; 219 220 template <typename Pred, typename... Preds> 221 struct And<Pred, Preds...> : And<Preds...> { 222 Pred P; 223 And(Pred &&p, Preds &&... preds) 224 : And<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) { 225 } 226 template <typename MatchSrc> 227 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) { 228 return P.match(MRI, src) && And<Preds...>::match(MRI, src); 229 } 230 }; 231 232 template <typename... Preds> struct Or { 233 template <typename MatchSrc> 234 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) { 235 return false; 236 } 237 }; 238 239 template <typename Pred, typename... Preds> 240 struct Or<Pred, Preds...> : Or<Preds...> { 241 Pred P; 242 Or(Pred &&p, Preds &&... preds) 243 : Or<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {} 244 template <typename MatchSrc> 245 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) { 246 return P.match(MRI, src) || Or<Preds...>::match(MRI, src); 247 } 248 }; 249 250 template <typename... Preds> And<Preds...> m_all_of(Preds &&... preds) { 251 return And<Preds...>(std::forward<Preds>(preds)...); 252 } 253 254 template <typename... Preds> Or<Preds...> m_any_of(Preds &&... preds) { 255 return Or<Preds...>(std::forward<Preds>(preds)...); 256 } 257 258 template <typename BindTy> struct bind_helper { 259 static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) { 260 VR = V; 261 return true; 262 } 263 }; 264 265 template <> struct bind_helper<MachineInstr *> { 266 static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI, 267 Register Reg) { 268 MI = MRI.getVRegDef(Reg); 269 if (MI) 270 return true; 271 return false; 272 } 273 static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI, 274 MachineInstr *Inst) { 275 MI = Inst; 276 return MI; 277 } 278 }; 279 280 template <> struct bind_helper<LLT> { 281 static bool bind(const MachineRegisterInfo &MRI, LLT Ty, Register Reg) { 282 Ty = MRI.getType(Reg); 283 if (Ty.isValid()) 284 return true; 285 return false; 286 } 287 }; 288 289 template <> struct bind_helper<const ConstantFP *> { 290 static bool bind(const MachineRegisterInfo &MRI, const ConstantFP *&F, 291 Register Reg) { 292 F = getConstantFPVRegVal(Reg, MRI); 293 if (F) 294 return true; 295 return false; 296 } 297 }; 298 299 template <typename Class> struct bind_ty { 300 Class &VR; 301 302 bind_ty(Class &V) : VR(V) {} 303 304 template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) { 305 return bind_helper<Class>::bind(MRI, VR, V); 306 } 307 }; 308 309 inline bind_ty<Register> m_Reg(Register &R) { return R; } 310 inline bind_ty<MachineInstr *> m_MInstr(MachineInstr *&MI) { return MI; } 311 inline bind_ty<LLT> m_Type(LLT Ty) { return Ty; } 312 inline bind_ty<CmpInst::Predicate> m_Pred(CmpInst::Predicate &P) { return P; } 313 inline operand_type_match m_Pred() { return operand_type_match(); } 314 315 // Helper for matching G_FCONSTANT 316 inline bind_ty<const ConstantFP *> m_GFCst(const ConstantFP *&C) { return C; } 317 318 // General helper for all the binary generic MI such as G_ADD/G_SUB etc 319 template <typename LHS_P, typename RHS_P, unsigned Opcode, 320 bool Commutable = false> 321 struct BinaryOp_match { 322 LHS_P L; 323 RHS_P R; 324 325 BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {} 326 template <typename OpTy> 327 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) { 328 MachineInstr *TmpMI; 329 if (mi_match(Op, MRI, m_MInstr(TmpMI))) { 330 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) { 331 return (L.match(MRI, TmpMI->getOperand(1).getReg()) && 332 R.match(MRI, TmpMI->getOperand(2).getReg())) || 333 (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) && 334 L.match(MRI, TmpMI->getOperand(2).getReg()))); 335 } 336 } 337 return false; 338 } 339 }; 340 341 // Helper for (commutative) binary generic MI that checks Opcode. 342 template <typename LHS_P, typename RHS_P, bool Commutable = false> 343 struct BinaryOpc_match { 344 unsigned Opc; 345 LHS_P L; 346 RHS_P R; 347 348 BinaryOpc_match(unsigned Opcode, const LHS_P &LHS, const RHS_P &RHS) 349 : Opc(Opcode), L(LHS), R(RHS) {} 350 template <typename OpTy> 351 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) { 352 MachineInstr *TmpMI; 353 if (mi_match(Op, MRI, m_MInstr(TmpMI))) { 354 if (TmpMI->getOpcode() == Opc && TmpMI->getNumDefs() == 1 && 355 TmpMI->getNumOperands() == 3) { 356 return (L.match(MRI, TmpMI->getOperand(1).getReg()) && 357 R.match(MRI, TmpMI->getOperand(2).getReg())) || 358 (Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) && 359 L.match(MRI, TmpMI->getOperand(2).getReg()))); 360 } 361 } 362 return false; 363 } 364 }; 365 366 template <typename LHS, typename RHS> 367 inline BinaryOpc_match<LHS, RHS, false> m_BinOp(unsigned Opcode, const LHS &L, 368 const RHS &R) { 369 return BinaryOpc_match<LHS, RHS, false>(Opcode, L, R); 370 } 371 372 template <typename LHS, typename RHS> 373 inline BinaryOpc_match<LHS, RHS, true> 374 m_CommutativeBinOp(unsigned Opcode, const LHS &L, const RHS &R) { 375 return BinaryOpc_match<LHS, RHS, true>(Opcode, L, R); 376 } 377 378 template <typename LHS, typename RHS> 379 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true> 380 m_GAdd(const LHS &L, const RHS &R) { 381 return BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>(L, R); 382 } 383 384 template <typename LHS, typename RHS> 385 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false> 386 m_GPtrAdd(const LHS &L, const RHS &R) { 387 return BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false>(L, R); 388 } 389 390 template <typename LHS, typename RHS> 391 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB> m_GSub(const LHS &L, 392 const RHS &R) { 393 return BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB>(L, R); 394 } 395 396 template <typename LHS, typename RHS> 397 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true> 398 m_GMul(const LHS &L, const RHS &R) { 399 return BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>(L, R); 400 } 401 402 template <typename LHS, typename RHS> 403 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true> 404 m_GFAdd(const LHS &L, const RHS &R) { 405 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>(L, R); 406 } 407 408 template <typename LHS, typename RHS> 409 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true> 410 m_GFMul(const LHS &L, const RHS &R) { 411 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>(L, R); 412 } 413 414 template <typename LHS, typename RHS> 415 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false> 416 m_GFSub(const LHS &L, const RHS &R) { 417 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>(L, R); 418 } 419 420 template <typename LHS, typename RHS> 421 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true> 422 m_GAnd(const LHS &L, const RHS &R) { 423 return BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>(L, R); 424 } 425 426 template <typename LHS, typename RHS> 427 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true> 428 m_GXor(const LHS &L, const RHS &R) { 429 return BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>(L, R); 430 } 431 432 template <typename LHS, typename RHS> 433 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true> m_GOr(const LHS &L, 434 const RHS &R) { 435 return BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true>(L, R); 436 } 437 438 template <typename LHS, typename RHS> 439 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false> 440 m_GShl(const LHS &L, const RHS &R) { 441 return BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>(L, R); 442 } 443 444 template <typename LHS, typename RHS> 445 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false> 446 m_GLShr(const LHS &L, const RHS &R) { 447 return BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>(L, R); 448 } 449 450 template <typename LHS, typename RHS> 451 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false> 452 m_GAShr(const LHS &L, const RHS &R) { 453 return BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>(L, R); 454 } 455 456 template <typename LHS, typename RHS> 457 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, false> 458 m_GSMax(const LHS &L, const RHS &R) { 459 return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, false>(L, R); 460 } 461 462 template <typename LHS, typename RHS> 463 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, false> 464 m_GSMin(const LHS &L, const RHS &R) { 465 return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, false>(L, R); 466 } 467 468 // Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc 469 template <typename SrcTy, unsigned Opcode> struct UnaryOp_match { 470 SrcTy L; 471 472 UnaryOp_match(const SrcTy &LHS) : L(LHS) {} 473 template <typename OpTy> 474 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) { 475 MachineInstr *TmpMI; 476 if (mi_match(Op, MRI, m_MInstr(TmpMI))) { 477 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) { 478 return L.match(MRI, TmpMI->getOperand(1).getReg()); 479 } 480 } 481 return false; 482 } 483 }; 484 485 template <typename SrcTy> 486 inline UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT> 487 m_GAnyExt(const SrcTy &Src) { 488 return UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>(Src); 489 } 490 491 template <typename SrcTy> 492 inline UnaryOp_match<SrcTy, TargetOpcode::G_SEXT> m_GSExt(const SrcTy &Src) { 493 return UnaryOp_match<SrcTy, TargetOpcode::G_SEXT>(Src); 494 } 495 496 template <typename SrcTy> 497 inline UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT> m_GZExt(const SrcTy &Src) { 498 return UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT>(Src); 499 } 500 501 template <typename SrcTy> 502 inline UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT> m_GFPExt(const SrcTy &Src) { 503 return UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT>(Src); 504 } 505 506 template <typename SrcTy> 507 inline UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC> m_GTrunc(const SrcTy &Src) { 508 return UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC>(Src); 509 } 510 511 template <typename SrcTy> 512 inline UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST> 513 m_GBitcast(const SrcTy &Src) { 514 return UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>(Src); 515 } 516 517 template <typename SrcTy> 518 inline UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT> 519 m_GPtrToInt(const SrcTy &Src) { 520 return UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>(Src); 521 } 522 523 template <typename SrcTy> 524 inline UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR> 525 m_GIntToPtr(const SrcTy &Src) { 526 return UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>(Src); 527 } 528 529 template <typename SrcTy> 530 inline UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC> 531 m_GFPTrunc(const SrcTy &Src) { 532 return UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>(Src); 533 } 534 535 template <typename SrcTy> 536 inline UnaryOp_match<SrcTy, TargetOpcode::G_FABS> m_GFabs(const SrcTy &Src) { 537 return UnaryOp_match<SrcTy, TargetOpcode::G_FABS>(Src); 538 } 539 540 template <typename SrcTy> 541 inline UnaryOp_match<SrcTy, TargetOpcode::G_FNEG> m_GFNeg(const SrcTy &Src) { 542 return UnaryOp_match<SrcTy, TargetOpcode::G_FNEG>(Src); 543 } 544 545 template <typename SrcTy> 546 inline UnaryOp_match<SrcTy, TargetOpcode::COPY> m_Copy(SrcTy &&Src) { 547 return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src)); 548 } 549 550 template <typename SrcTy> 551 inline UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT> m_GFSqrt(const SrcTy &Src) { 552 return UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT>(Src); 553 } 554 555 // General helper for generic MI compares, i.e. G_ICMP and G_FCMP 556 // TODO: Allow checking a specific predicate. 557 template <typename Pred_P, typename LHS_P, typename RHS_P, unsigned Opcode> 558 struct CompareOp_match { 559 Pred_P P; 560 LHS_P L; 561 RHS_P R; 562 563 CompareOp_match(const Pred_P &Pred, const LHS_P &LHS, const RHS_P &RHS) 564 : P(Pred), L(LHS), R(RHS) {} 565 566 template <typename OpTy> 567 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) { 568 MachineInstr *TmpMI; 569 if (!mi_match(Op, MRI, m_MInstr(TmpMI)) || TmpMI->getOpcode() != Opcode) 570 return false; 571 572 auto TmpPred = 573 static_cast<CmpInst::Predicate>(TmpMI->getOperand(1).getPredicate()); 574 if (!P.match(MRI, TmpPred)) 575 return false; 576 577 return L.match(MRI, TmpMI->getOperand(2).getReg()) && 578 R.match(MRI, TmpMI->getOperand(3).getReg()); 579 } 580 }; 581 582 template <typename Pred, typename LHS, typename RHS> 583 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP> 584 m_GICmp(const Pred &P, const LHS &L, const RHS &R) { 585 return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>(P, L, R); 586 } 587 588 template <typename Pred, typename LHS, typename RHS> 589 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP> 590 m_GFCmp(const Pred &P, const LHS &L, const RHS &R) { 591 return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>(P, L, R); 592 } 593 594 // Helper for checking if a Reg is of specific type. 595 struct CheckType { 596 LLT Ty; 597 CheckType(const LLT Ty) : Ty(Ty) {} 598 599 bool match(const MachineRegisterInfo &MRI, Register Reg) { 600 return MRI.getType(Reg) == Ty; 601 } 602 }; 603 604 inline CheckType m_SpecificType(LLT Ty) { return Ty; } 605 606 template <typename Src0Ty, typename Src1Ty, typename Src2Ty, unsigned Opcode> 607 struct TernaryOp_match { 608 Src0Ty Src0; 609 Src1Ty Src1; 610 Src2Ty Src2; 611 612 TernaryOp_match(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) 613 : Src0(Src0), Src1(Src1), Src2(Src2) {} 614 template <typename OpTy> 615 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) { 616 MachineInstr *TmpMI; 617 if (mi_match(Op, MRI, m_MInstr(TmpMI))) { 618 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 4) { 619 return (Src0.match(MRI, TmpMI->getOperand(1).getReg()) && 620 Src1.match(MRI, TmpMI->getOperand(2).getReg()) && 621 Src2.match(MRI, TmpMI->getOperand(3).getReg())); 622 } 623 } 624 return false; 625 } 626 }; 627 template <typename Src0Ty, typename Src1Ty, typename Src2Ty> 628 inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, 629 TargetOpcode::G_INSERT_VECTOR_ELT> 630 m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) { 631 return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, 632 TargetOpcode::G_INSERT_VECTOR_ELT>(Src0, Src1, Src2); 633 } 634 635 template <typename Src0Ty, typename Src1Ty, typename Src2Ty> 636 inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT> 637 m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) { 638 return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>( 639 Src0, Src1, Src2); 640 } 641 642 /// Matches a register negated by a G_SUB. 643 /// G_SUB 0, %negated_reg 644 template <typename SrcTy> 645 inline BinaryOp_match<SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB> 646 m_Neg(const SrcTy &&Src) { 647 return m_GSub(m_ZeroInt(), Src); 648 } 649 650 /// Matches a register not-ed by a G_XOR. 651 /// G_XOR %not_reg, -1 652 template <typename SrcTy> 653 inline BinaryOp_match<SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true> 654 m_Not(const SrcTy &&Src) { 655 return m_GXor(Src, m_AllOnesInt()); 656 } 657 658 } // namespace MIPatternMatch 659 } // namespace llvm 660 661 #endif 662