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