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