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 [[nodiscard]] bool mi_match(Reg R, const MachineRegisterInfo &MRI, 26 Pattern &&P) { 27 return P.match(MRI, R); 28 } 29 30 template <typename Pattern> 31 [[nodiscard]] bool mi_match(MachineInstr &MI, const MachineRegisterInfo &MRI, 32 Pattern &&P) { 33 return P.match(MRI, &MI); 34 } 35 36 // TODO: Extend for N use. 37 template <typename SubPatternT> struct OneUse_match { 38 SubPatternT SubPat; 39 OneUse_match(const SubPatternT &SP) : SubPat(SP) {} 40 41 bool match(const MachineRegisterInfo &MRI, Register Reg) { 42 return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg); 43 } 44 }; 45 46 template <typename SubPat> 47 inline OneUse_match<SubPat> m_OneUse(const SubPat &SP) { 48 return SP; 49 } 50 51 template <typename SubPatternT> struct OneNonDBGUse_match { 52 SubPatternT SubPat; 53 OneNonDBGUse_match(const SubPatternT &SP) : SubPat(SP) {} 54 55 bool match(const MachineRegisterInfo &MRI, Register Reg) { 56 return MRI.hasOneNonDBGUse(Reg) && SubPat.match(MRI, Reg); 57 } 58 }; 59 60 template <typename SubPat> 61 inline OneNonDBGUse_match<SubPat> m_OneNonDBGUse(const SubPat &SP) { 62 return SP; 63 } 64 65 template <typename ConstT> 66 inline std::optional<ConstT> matchConstant(Register, 67 const MachineRegisterInfo &); 68 69 template <> 70 inline std::optional<APInt> matchConstant(Register Reg, 71 const MachineRegisterInfo &MRI) { 72 return getIConstantVRegVal(Reg, MRI); 73 } 74 75 template <> 76 inline std::optional<int64_t> matchConstant(Register Reg, 77 const MachineRegisterInfo &MRI) { 78 return getIConstantVRegSExtVal(Reg, MRI); 79 } 80 81 template <typename ConstT> struct ConstantMatch { 82 ConstT &CR; 83 ConstantMatch(ConstT &C) : CR(C) {} 84 bool match(const MachineRegisterInfo &MRI, Register Reg) { 85 if (auto MaybeCst = matchConstant<ConstT>(Reg, MRI)) { 86 CR = *MaybeCst; 87 return true; 88 } 89 return false; 90 } 91 }; 92 93 inline ConstantMatch<APInt> m_ICst(APInt &Cst) { 94 return ConstantMatch<APInt>(Cst); 95 } 96 inline ConstantMatch<int64_t> m_ICst(int64_t &Cst) { 97 return ConstantMatch<int64_t>(Cst); 98 } 99 100 template <typename ConstT> 101 inline std::optional<ConstT> matchConstantSplat(Register, 102 const MachineRegisterInfo &); 103 104 template <> 105 inline std::optional<APInt> matchConstantSplat(Register Reg, 106 const MachineRegisterInfo &MRI) { 107 return getIConstantSplatVal(Reg, MRI); 108 } 109 110 template <> 111 inline std::optional<int64_t> 112 matchConstantSplat(Register Reg, const MachineRegisterInfo &MRI) { 113 return getIConstantSplatSExtVal(Reg, MRI); 114 } 115 116 template <typename ConstT> struct ICstOrSplatMatch { 117 ConstT &CR; 118 ICstOrSplatMatch(ConstT &C) : CR(C) {} 119 bool match(const MachineRegisterInfo &MRI, Register Reg) { 120 if (auto MaybeCst = matchConstant<ConstT>(Reg, MRI)) { 121 CR = *MaybeCst; 122 return true; 123 } 124 125 if (auto MaybeCstSplat = matchConstantSplat<ConstT>(Reg, MRI)) { 126 CR = *MaybeCstSplat; 127 return true; 128 } 129 130 return false; 131 }; 132 }; 133 134 inline ICstOrSplatMatch<APInt> m_ICstOrSplat(APInt &Cst) { 135 return ICstOrSplatMatch<APInt>(Cst); 136 } 137 138 inline ICstOrSplatMatch<int64_t> m_ICstOrSplat(int64_t &Cst) { 139 return ICstOrSplatMatch<int64_t>(Cst); 140 } 141 142 struct GCstAndRegMatch { 143 std::optional<ValueAndVReg> &ValReg; 144 GCstAndRegMatch(std::optional<ValueAndVReg> &ValReg) : ValReg(ValReg) {} 145 bool match(const MachineRegisterInfo &MRI, Register Reg) { 146 ValReg = getIConstantVRegValWithLookThrough(Reg, MRI); 147 return ValReg ? true : false; 148 } 149 }; 150 151 inline GCstAndRegMatch m_GCst(std::optional<ValueAndVReg> &ValReg) { 152 return GCstAndRegMatch(ValReg); 153 } 154 155 struct GFCstAndRegMatch { 156 std::optional<FPValueAndVReg> &FPValReg; 157 GFCstAndRegMatch(std::optional<FPValueAndVReg> &FPValReg) 158 : FPValReg(FPValReg) {} 159 bool match(const MachineRegisterInfo &MRI, Register Reg) { 160 FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI); 161 return FPValReg ? true : false; 162 } 163 }; 164 165 inline GFCstAndRegMatch m_GFCst(std::optional<FPValueAndVReg> &FPValReg) { 166 return GFCstAndRegMatch(FPValReg); 167 } 168 169 struct GFCstOrSplatGFCstMatch { 170 std::optional<FPValueAndVReg> &FPValReg; 171 GFCstOrSplatGFCstMatch(std::optional<FPValueAndVReg> &FPValReg) 172 : FPValReg(FPValReg) {} 173 bool match(const MachineRegisterInfo &MRI, Register Reg) { 174 return (FPValReg = getFConstantSplat(Reg, MRI)) || 175 (FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI)); 176 }; 177 }; 178 179 inline GFCstOrSplatGFCstMatch 180 m_GFCstOrSplat(std::optional<FPValueAndVReg> &FPValReg) { 181 return GFCstOrSplatGFCstMatch(FPValReg); 182 } 183 184 /// Matcher for a specific constant value. 185 struct SpecificConstantMatch { 186 int64_t RequestedVal; 187 SpecificConstantMatch(int64_t RequestedVal) : RequestedVal(RequestedVal) {} 188 bool match(const MachineRegisterInfo &MRI, Register Reg) { 189 int64_t MatchedVal; 190 return mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal; 191 } 192 }; 193 194 /// Matches a constant equal to \p RequestedValue. 195 inline SpecificConstantMatch m_SpecificICst(int64_t RequestedValue) { 196 return SpecificConstantMatch(RequestedValue); 197 } 198 199 /// Matcher for a specific constant splat. 200 struct SpecificConstantSplatMatch { 201 int64_t RequestedVal; 202 SpecificConstantSplatMatch(int64_t RequestedVal) 203 : RequestedVal(RequestedVal) {} 204 bool match(const MachineRegisterInfo &MRI, Register Reg) { 205 return isBuildVectorConstantSplat(Reg, MRI, RequestedVal, 206 /* AllowUndef */ false); 207 } 208 }; 209 210 /// Matches a constant splat of \p RequestedValue. 211 inline SpecificConstantSplatMatch m_SpecificICstSplat(int64_t RequestedValue) { 212 return SpecificConstantSplatMatch(RequestedValue); 213 } 214 215 /// Matcher for a specific constant or constant splat. 216 struct SpecificConstantOrSplatMatch { 217 int64_t RequestedVal; 218 SpecificConstantOrSplatMatch(int64_t RequestedVal) 219 : RequestedVal(RequestedVal) {} 220 bool match(const MachineRegisterInfo &MRI, Register Reg) { 221 int64_t MatchedVal; 222 if (mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal) 223 return true; 224 return isBuildVectorConstantSplat(Reg, MRI, RequestedVal, 225 /* AllowUndef */ false); 226 } 227 }; 228 229 /// Matches a \p RequestedValue constant or a constant splat of \p 230 /// RequestedValue. 231 inline SpecificConstantOrSplatMatch 232 m_SpecificICstOrSplat(int64_t RequestedValue) { 233 return SpecificConstantOrSplatMatch(RequestedValue); 234 } 235 236 ///{ 237 /// Convenience matchers for specific integer values. 238 inline SpecificConstantMatch m_ZeroInt() { return SpecificConstantMatch(0); } 239 inline SpecificConstantMatch m_AllOnesInt() { 240 return SpecificConstantMatch(-1); 241 } 242 ///} 243 244 /// Matcher for a specific register. 245 struct SpecificRegisterMatch { 246 Register RequestedReg; 247 SpecificRegisterMatch(Register RequestedReg) : RequestedReg(RequestedReg) {} 248 bool match(const MachineRegisterInfo &MRI, Register Reg) { 249 return Reg == RequestedReg; 250 } 251 }; 252 253 /// Matches a register only if it is equal to \p RequestedReg. 254 inline SpecificRegisterMatch m_SpecificReg(Register RequestedReg) { 255 return SpecificRegisterMatch(RequestedReg); 256 } 257 258 // TODO: Rework this for different kinds of MachineOperand. 259 // Currently assumes the Src for a match is a register. 260 // We might want to support taking in some MachineOperands and call getReg on 261 // that. 262 263 struct operand_type_match { 264 bool match(const MachineRegisterInfo &MRI, Register Reg) { return true; } 265 bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) { 266 return MO->isReg(); 267 } 268 }; 269 270 inline operand_type_match m_Reg() { return operand_type_match(); } 271 272 /// Matching combinators. 273 template <typename... Preds> struct And { 274 template <typename MatchSrc> 275 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) { 276 return true; 277 } 278 }; 279 280 template <typename Pred, typename... Preds> 281 struct And<Pred, Preds...> : And<Preds...> { 282 Pred P; 283 And(Pred &&p, Preds &&... preds) 284 : And<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) { 285 } 286 template <typename MatchSrc> 287 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) { 288 return P.match(MRI, src) && And<Preds...>::match(MRI, src); 289 } 290 }; 291 292 template <typename... Preds> struct Or { 293 template <typename MatchSrc> 294 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) { 295 return false; 296 } 297 }; 298 299 template <typename Pred, typename... Preds> 300 struct Or<Pred, Preds...> : Or<Preds...> { 301 Pred P; 302 Or(Pred &&p, Preds &&... preds) 303 : Or<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {} 304 template <typename MatchSrc> 305 bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) { 306 return P.match(MRI, src) || Or<Preds...>::match(MRI, src); 307 } 308 }; 309 310 template <typename... Preds> And<Preds...> m_all_of(Preds &&... preds) { 311 return And<Preds...>(std::forward<Preds>(preds)...); 312 } 313 314 template <typename... Preds> Or<Preds...> m_any_of(Preds &&... preds) { 315 return Or<Preds...>(std::forward<Preds>(preds)...); 316 } 317 318 template <typename BindTy> struct bind_helper { 319 static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) { 320 VR = V; 321 return true; 322 } 323 }; 324 325 template <> struct bind_helper<MachineInstr *> { 326 static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI, 327 Register Reg) { 328 MI = MRI.getVRegDef(Reg); 329 if (MI) 330 return true; 331 return false; 332 } 333 static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI, 334 MachineInstr *Inst) { 335 MI = Inst; 336 return MI; 337 } 338 }; 339 340 template <> struct bind_helper<LLT> { 341 static bool bind(const MachineRegisterInfo &MRI, LLT &Ty, Register Reg) { 342 Ty = MRI.getType(Reg); 343 if (Ty.isValid()) 344 return true; 345 return false; 346 } 347 }; 348 349 template <> struct bind_helper<const ConstantFP *> { 350 static bool bind(const MachineRegisterInfo &MRI, const ConstantFP *&F, 351 Register Reg) { 352 F = getConstantFPVRegVal(Reg, MRI); 353 if (F) 354 return true; 355 return false; 356 } 357 }; 358 359 template <typename Class> struct bind_ty { 360 Class &VR; 361 362 bind_ty(Class &V) : VR(V) {} 363 364 template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) { 365 return bind_helper<Class>::bind(MRI, VR, V); 366 } 367 }; 368 369 inline bind_ty<Register> m_Reg(Register &R) { return R; } 370 inline bind_ty<MachineInstr *> m_MInstr(MachineInstr *&MI) { return MI; } 371 inline bind_ty<LLT> m_Type(LLT &Ty) { return Ty; } 372 inline bind_ty<CmpInst::Predicate> m_Pred(CmpInst::Predicate &P) { return P; } 373 inline operand_type_match m_Pred() { return operand_type_match(); } 374 375 template <typename BindTy> struct deferred_helper { 376 static bool match(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) { 377 return VR == V; 378 } 379 }; 380 381 template <> struct deferred_helper<LLT> { 382 static bool match(const MachineRegisterInfo &MRI, LLT VT, Register R) { 383 return VT == MRI.getType(R); 384 } 385 }; 386 387 template <typename Class> struct deferred_ty { 388 Class &VR; 389 390 deferred_ty(Class &V) : VR(V) {} 391 392 template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) { 393 return deferred_helper<Class>::match(MRI, VR, V); 394 } 395 }; 396 397 /// Similar to m_SpecificReg/Type, but the specific value to match originated 398 /// from an earlier sub-pattern in the same mi_match expression. For example, 399 /// we cannot match `(add X, X)` with `m_GAdd(m_Reg(X), m_SpecificReg(X))` 400 /// because `X` is not initialized at the time it's passed to `m_SpecificReg`. 401 /// Instead, we can use `m_GAdd(m_Reg(x), m_DeferredReg(X))`. 402 inline deferred_ty<Register> m_DeferredReg(Register &R) { return R; } 403 inline deferred_ty<LLT> m_DeferredType(LLT &Ty) { return Ty; } 404 405 struct ImplicitDefMatch { 406 bool match(const MachineRegisterInfo &MRI, Register Reg) { 407 MachineInstr *TmpMI; 408 if (mi_match(Reg, MRI, m_MInstr(TmpMI))) 409 return TmpMI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF; 410 return false; 411 } 412 }; 413 414 inline ImplicitDefMatch m_GImplicitDef() { return ImplicitDefMatch(); } 415 416 // Helper for matching G_FCONSTANT 417 inline bind_ty<const ConstantFP *> m_GFCst(const ConstantFP *&C) { return C; } 418 419 // General helper for all the binary generic MI such as G_ADD/G_SUB etc 420 template <typename LHS_P, typename RHS_P, unsigned Opcode, 421 bool Commutable = false> 422 struct BinaryOp_match { 423 LHS_P L; 424 RHS_P R; 425 426 BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {} 427 template <typename OpTy> 428 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) { 429 MachineInstr *TmpMI; 430 if (mi_match(Op, MRI, m_MInstr(TmpMI))) { 431 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) { 432 return (L.match(MRI, TmpMI->getOperand(1).getReg()) && 433 R.match(MRI, TmpMI->getOperand(2).getReg())) || 434 // NOTE: When trying the alternative operand ordering 435 // with a commutative operation, it is imperative to always run 436 // the LHS sub-pattern (i.e. `L`) before the RHS sub-pattern 437 // (i.e. `R`). Otherwsie, m_DeferredReg/Type will not work as 438 // expected. 439 (Commutable && (L.match(MRI, TmpMI->getOperand(2).getReg()) && 440 R.match(MRI, TmpMI->getOperand(1).getReg()))); 441 } 442 } 443 return false; 444 } 445 }; 446 447 // Helper for (commutative) binary generic MI that checks Opcode. 448 template <typename LHS_P, typename RHS_P, bool Commutable = false> 449 struct BinaryOpc_match { 450 unsigned Opc; 451 LHS_P L; 452 RHS_P R; 453 454 BinaryOpc_match(unsigned Opcode, const LHS_P &LHS, const RHS_P &RHS) 455 : Opc(Opcode), L(LHS), R(RHS) {} 456 template <typename OpTy> 457 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) { 458 MachineInstr *TmpMI; 459 if (mi_match(Op, MRI, m_MInstr(TmpMI))) { 460 if (TmpMI->getOpcode() == Opc && TmpMI->getNumDefs() == 1 && 461 TmpMI->getNumOperands() == 3) { 462 return (L.match(MRI, TmpMI->getOperand(1).getReg()) && 463 R.match(MRI, TmpMI->getOperand(2).getReg())) || 464 // NOTE: When trying the alternative operand ordering 465 // with a commutative operation, it is imperative to always run 466 // the LHS sub-pattern (i.e. `L`) before the RHS sub-pattern 467 // (i.e. `R`). Otherwsie, m_DeferredReg/Type will not work as 468 // expected. 469 (Commutable && (L.match(MRI, TmpMI->getOperand(2).getReg()) && 470 R.match(MRI, TmpMI->getOperand(1).getReg()))); 471 } 472 } 473 return false; 474 } 475 }; 476 477 template <typename LHS, typename RHS> 478 inline BinaryOpc_match<LHS, RHS, false> m_BinOp(unsigned Opcode, const LHS &L, 479 const RHS &R) { 480 return BinaryOpc_match<LHS, RHS, false>(Opcode, L, R); 481 } 482 483 template <typename LHS, typename RHS> 484 inline BinaryOpc_match<LHS, RHS, true> 485 m_CommutativeBinOp(unsigned Opcode, const LHS &L, const RHS &R) { 486 return BinaryOpc_match<LHS, RHS, true>(Opcode, L, R); 487 } 488 489 template <typename LHS, typename RHS> 490 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true> 491 m_GAdd(const LHS &L, const RHS &R) { 492 return BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>(L, R); 493 } 494 495 template <typename LHS, typename RHS> 496 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false> 497 m_GBuildVector(const LHS &L, const RHS &R) { 498 return BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR, false>(L, R); 499 } 500 501 template <typename LHS, typename RHS> 502 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false> 503 m_GBuildVectorTrunc(const LHS &L, const RHS &R) { 504 return BinaryOp_match<LHS, RHS, TargetOpcode::G_BUILD_VECTOR_TRUNC, false>(L, 505 R); 506 } 507 508 template <typename LHS, typename RHS> 509 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false> 510 m_GPtrAdd(const LHS &L, const RHS &R) { 511 return BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false>(L, R); 512 } 513 514 template <typename LHS, typename RHS> 515 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB> m_GSub(const LHS &L, 516 const RHS &R) { 517 return BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB>(L, R); 518 } 519 520 template <typename LHS, typename RHS> 521 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true> 522 m_GMul(const LHS &L, const RHS &R) { 523 return BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>(L, R); 524 } 525 526 template <typename LHS, typename RHS> 527 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true> 528 m_GFAdd(const LHS &L, const RHS &R) { 529 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>(L, R); 530 } 531 532 template <typename LHS, typename RHS> 533 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true> 534 m_GFMul(const LHS &L, const RHS &R) { 535 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>(L, R); 536 } 537 538 template <typename LHS, typename RHS> 539 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false> 540 m_GFSub(const LHS &L, const RHS &R) { 541 return BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>(L, R); 542 } 543 544 template <typename LHS, typename RHS> 545 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true> 546 m_GAnd(const LHS &L, const RHS &R) { 547 return BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>(L, R); 548 } 549 550 template <typename LHS, typename RHS> 551 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true> 552 m_GXor(const LHS &L, const RHS &R) { 553 return BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>(L, R); 554 } 555 556 template <typename LHS, typename RHS> 557 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true> m_GOr(const LHS &L, 558 const RHS &R) { 559 return BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true>(L, R); 560 } 561 562 template <typename LHS, typename RHS> 563 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false> 564 m_GShl(const LHS &L, const RHS &R) { 565 return BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>(L, R); 566 } 567 568 template <typename LHS, typename RHS> 569 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false> 570 m_GLShr(const LHS &L, const RHS &R) { 571 return BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>(L, R); 572 } 573 574 template <typename LHS, typename RHS> 575 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false> 576 m_GAShr(const LHS &L, const RHS &R) { 577 return BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>(L, R); 578 } 579 580 template <typename LHS, typename RHS> 581 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, true> 582 m_GSMax(const LHS &L, const RHS &R) { 583 return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, true>(L, R); 584 } 585 586 template <typename LHS, typename RHS> 587 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, true> 588 m_GSMin(const LHS &L, const RHS &R) { 589 return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, true>(L, R); 590 } 591 592 template <typename LHS, typename RHS> 593 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_UMAX, true> 594 m_GUMax(const LHS &L, const RHS &R) { 595 return BinaryOp_match<LHS, RHS, TargetOpcode::G_UMAX, true>(L, R); 596 } 597 598 template <typename LHS, typename RHS> 599 inline BinaryOp_match<LHS, RHS, TargetOpcode::G_UMIN, true> 600 m_GUMin(const LHS &L, const RHS &R) { 601 return BinaryOp_match<LHS, RHS, TargetOpcode::G_UMIN, true>(L, R); 602 } 603 604 // Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc 605 template <typename SrcTy, unsigned Opcode> struct UnaryOp_match { 606 SrcTy L; 607 608 UnaryOp_match(const SrcTy &LHS) : L(LHS) {} 609 template <typename OpTy> 610 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) { 611 MachineInstr *TmpMI; 612 if (mi_match(Op, MRI, m_MInstr(TmpMI))) { 613 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) { 614 return L.match(MRI, TmpMI->getOperand(1).getReg()); 615 } 616 } 617 return false; 618 } 619 }; 620 621 template <typename SrcTy> 622 inline UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT> 623 m_GAnyExt(const SrcTy &Src) { 624 return UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>(Src); 625 } 626 627 template <typename SrcTy> 628 inline UnaryOp_match<SrcTy, TargetOpcode::G_SEXT> m_GSExt(const SrcTy &Src) { 629 return UnaryOp_match<SrcTy, TargetOpcode::G_SEXT>(Src); 630 } 631 632 template <typename SrcTy> 633 inline UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT> m_GZExt(const SrcTy &Src) { 634 return UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT>(Src); 635 } 636 637 template <typename SrcTy> 638 inline UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT> m_GFPExt(const SrcTy &Src) { 639 return UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT>(Src); 640 } 641 642 template <typename SrcTy> 643 inline UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC> m_GTrunc(const SrcTy &Src) { 644 return UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC>(Src); 645 } 646 647 template <typename SrcTy> 648 inline UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST> 649 m_GBitcast(const SrcTy &Src) { 650 return UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>(Src); 651 } 652 653 template <typename SrcTy> 654 inline UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT> 655 m_GPtrToInt(const SrcTy &Src) { 656 return UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>(Src); 657 } 658 659 template <typename SrcTy> 660 inline UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR> 661 m_GIntToPtr(const SrcTy &Src) { 662 return UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>(Src); 663 } 664 665 template <typename SrcTy> 666 inline UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC> 667 m_GFPTrunc(const SrcTy &Src) { 668 return UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>(Src); 669 } 670 671 template <typename SrcTy> 672 inline UnaryOp_match<SrcTy, TargetOpcode::G_FABS> m_GFabs(const SrcTy &Src) { 673 return UnaryOp_match<SrcTy, TargetOpcode::G_FABS>(Src); 674 } 675 676 template <typename SrcTy> 677 inline UnaryOp_match<SrcTy, TargetOpcode::G_FNEG> m_GFNeg(const SrcTy &Src) { 678 return UnaryOp_match<SrcTy, TargetOpcode::G_FNEG>(Src); 679 } 680 681 template <typename SrcTy> 682 inline UnaryOp_match<SrcTy, TargetOpcode::COPY> m_Copy(SrcTy &&Src) { 683 return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src)); 684 } 685 686 template <typename SrcTy> 687 inline UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT> m_GFSqrt(const SrcTy &Src) { 688 return UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT>(Src); 689 } 690 691 // General helper for generic MI compares, i.e. G_ICMP and G_FCMP 692 // TODO: Allow checking a specific predicate. 693 template <typename Pred_P, typename LHS_P, typename RHS_P, unsigned Opcode, 694 bool Commutable = false> 695 struct CompareOp_match { 696 Pred_P P; 697 LHS_P L; 698 RHS_P R; 699 700 CompareOp_match(const Pred_P &Pred, const LHS_P &LHS, const RHS_P &RHS) 701 : P(Pred), L(LHS), R(RHS) {} 702 703 template <typename OpTy> 704 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) { 705 MachineInstr *TmpMI; 706 if (!mi_match(Op, MRI, m_MInstr(TmpMI)) || TmpMI->getOpcode() != Opcode) 707 return false; 708 709 auto TmpPred = 710 static_cast<CmpInst::Predicate>(TmpMI->getOperand(1).getPredicate()); 711 if (!P.match(MRI, TmpPred)) 712 return false; 713 Register LHS = TmpMI->getOperand(2).getReg(); 714 Register RHS = TmpMI->getOperand(3).getReg(); 715 if (L.match(MRI, LHS) && R.match(MRI, RHS)) 716 return true; 717 // NOTE: When trying the alternative operand ordering 718 // with a commutative operation, it is imperative to always run 719 // the LHS sub-pattern (i.e. `L`) before the RHS sub-pattern 720 // (i.e. `R`). Otherwsie, m_DeferredReg/Type will not work as expected. 721 if (Commutable && L.match(MRI, RHS) && R.match(MRI, LHS) && 722 P.match(MRI, CmpInst::getSwappedPredicate(TmpPred))) 723 return true; 724 return false; 725 } 726 }; 727 728 template <typename Pred, typename LHS, typename RHS> 729 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP> 730 m_GICmp(const Pred &P, const LHS &L, const RHS &R) { 731 return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>(P, L, R); 732 } 733 734 template <typename Pred, typename LHS, typename RHS> 735 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP> 736 m_GFCmp(const Pred &P, const LHS &L, const RHS &R) { 737 return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>(P, L, R); 738 } 739 740 /// G_ICMP matcher that also matches commuted compares. 741 /// E.g. 742 /// 743 /// m_c_GICmp(m_Pred(...), m_GAdd(...), m_GSub(...)) 744 /// 745 /// Could match both of: 746 /// 747 /// icmp ugt (add x, y) (sub a, b) 748 /// icmp ult (sub a, b) (add x, y) 749 template <typename Pred, typename LHS, typename RHS> 750 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP, true> 751 m_c_GICmp(const Pred &P, const LHS &L, const RHS &R) { 752 return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP, true>(P, L, R); 753 } 754 755 /// G_FCMP matcher that also matches commuted compares. 756 /// E.g. 757 /// 758 /// m_c_GFCmp(m_Pred(...), m_FAdd(...), m_GFMul(...)) 759 /// 760 /// Could match both of: 761 /// 762 /// fcmp ogt (fadd x, y) (fmul a, b) 763 /// fcmp olt (fmul a, b) (fadd x, y) 764 template <typename Pred, typename LHS, typename RHS> 765 inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP, true> 766 m_c_GFCmp(const Pred &P, const LHS &L, const RHS &R) { 767 return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP, true>(P, L, R); 768 } 769 770 // Helper for checking if a Reg is of specific type. 771 struct CheckType { 772 LLT Ty; 773 CheckType(const LLT Ty) : Ty(Ty) {} 774 775 bool match(const MachineRegisterInfo &MRI, Register Reg) { 776 return MRI.getType(Reg) == Ty; 777 } 778 }; 779 780 inline CheckType m_SpecificType(LLT Ty) { return Ty; } 781 782 template <typename Src0Ty, typename Src1Ty, typename Src2Ty, unsigned Opcode> 783 struct TernaryOp_match { 784 Src0Ty Src0; 785 Src1Ty Src1; 786 Src2Ty Src2; 787 788 TernaryOp_match(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) 789 : Src0(Src0), Src1(Src1), Src2(Src2) {} 790 template <typename OpTy> 791 bool match(const MachineRegisterInfo &MRI, OpTy &&Op) { 792 MachineInstr *TmpMI; 793 if (mi_match(Op, MRI, m_MInstr(TmpMI))) { 794 if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 4) { 795 return (Src0.match(MRI, TmpMI->getOperand(1).getReg()) && 796 Src1.match(MRI, TmpMI->getOperand(2).getReg()) && 797 Src2.match(MRI, TmpMI->getOperand(3).getReg())); 798 } 799 } 800 return false; 801 } 802 }; 803 template <typename Src0Ty, typename Src1Ty, typename Src2Ty> 804 inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, 805 TargetOpcode::G_INSERT_VECTOR_ELT> 806 m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) { 807 return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, 808 TargetOpcode::G_INSERT_VECTOR_ELT>(Src0, Src1, Src2); 809 } 810 811 template <typename Src0Ty, typename Src1Ty, typename Src2Ty> 812 inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT> 813 m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) { 814 return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>( 815 Src0, Src1, Src2); 816 } 817 818 /// Matches a register negated by a G_SUB. 819 /// G_SUB 0, %negated_reg 820 template <typename SrcTy> 821 inline BinaryOp_match<SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB> 822 m_Neg(const SrcTy &&Src) { 823 return m_GSub(m_ZeroInt(), Src); 824 } 825 826 /// Matches a register not-ed by a G_XOR. 827 /// G_XOR %not_reg, -1 828 template <typename SrcTy> 829 inline BinaryOp_match<SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true> 830 m_Not(const SrcTy &&Src) { 831 return m_GXor(Src, m_AllOnesInt()); 832 } 833 834 } // namespace MIPatternMatch 835 } // namespace llvm 836 837 #endif 838