1 //===- llvm/CodeGen/GlobalISel/GenericMachineInstrs.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 /// Declares convenience wrapper classes for interpreting MachineInstr instances 10 /// as specific generic operations. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H 15 #define LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H 16 17 #include "llvm/ADT/APInt.h" 18 #include "llvm/CodeGen/MachineInstr.h" 19 #include "llvm/CodeGen/MachineMemOperand.h" 20 #include "llvm/CodeGen/TargetOpcodes.h" 21 #include "llvm/IR/Constants.h" 22 #include "llvm/IR/Instructions.h" 23 #include "llvm/Support/Casting.h" 24 25 namespace llvm { 26 27 /// A base class for all GenericMachineInstrs. 28 class GenericMachineInstr : public MachineInstr { 29 constexpr static unsigned PoisonFlags = NoUWrap | NoSWrap | NoUSWrap | 30 IsExact | Disjoint | NonNeg | 31 FmNoNans | FmNoInfs | SameSign; 32 33 public: 34 GenericMachineInstr() = delete; 35 36 /// Access the Idx'th operand as a register and return it. 37 /// This assumes that the Idx'th operand is a Register type. 38 Register getReg(unsigned Idx) const { return getOperand(Idx).getReg(); } 39 40 static bool classof(const MachineInstr *MI) { 41 return isPreISelGenericOpcode(MI->getOpcode()); 42 } 43 44 bool hasPoisonGeneratingFlags() const { return getFlags() & PoisonFlags; } 45 46 void dropPoisonGeneratingFlags() { 47 clearFlags(PoisonFlags); 48 assert(!hasPoisonGeneratingFlags()); 49 } 50 }; 51 52 /// Provides common memory operand functionality. 53 class GMemOperation : public GenericMachineInstr { 54 public: 55 /// Get the MachineMemOperand on this instruction. 56 MachineMemOperand &getMMO() const { return **memoperands_begin(); } 57 58 /// Returns true if the attached MachineMemOperand has the atomic flag set. 59 bool isAtomic() const { return getMMO().isAtomic(); } 60 /// Returns true if the attached MachineMemOpeand as the volatile flag set. 61 bool isVolatile() const { return getMMO().isVolatile(); } 62 /// Returns true if the memory operation is neither atomic or volatile. 63 bool isSimple() const { return !isAtomic() && !isVolatile(); } 64 /// Returns true if this memory operation doesn't have any ordering 65 /// constraints other than normal aliasing. Volatile and (ordered) atomic 66 /// memory operations can't be reordered. 67 bool isUnordered() const { return getMMO().isUnordered(); } 68 69 /// Returns the size in bytes of the memory access. 70 LocationSize getMemSize() const { return getMMO().getSize(); } 71 /// Returns the size in bits of the memory access. 72 LocationSize getMemSizeInBits() const { return getMMO().getSizeInBits(); } 73 74 static bool classof(const MachineInstr *MI) { 75 return GenericMachineInstr::classof(MI) && MI->hasOneMemOperand(); 76 } 77 }; 78 79 /// Represents any type of generic load or store. 80 /// G_LOAD, G_STORE, G_ZEXTLOAD, G_SEXTLOAD. 81 class GLoadStore : public GMemOperation { 82 public: 83 /// Get the source register of the pointer value. 84 Register getPointerReg() const { return getOperand(1).getReg(); } 85 86 static bool classof(const MachineInstr *MI) { 87 switch (MI->getOpcode()) { 88 case TargetOpcode::G_LOAD: 89 case TargetOpcode::G_STORE: 90 case TargetOpcode::G_ZEXTLOAD: 91 case TargetOpcode::G_SEXTLOAD: 92 return true; 93 default: 94 return false; 95 } 96 } 97 }; 98 99 /// Represents indexed loads. These are different enough from regular loads 100 /// that they get their own class. Including them in GAnyLoad would probably 101 /// make a footgun for someone. 102 class GIndexedLoad : public GMemOperation { 103 public: 104 /// Get the definition register of the loaded value. 105 Register getDstReg() const { return getOperand(0).getReg(); } 106 /// Get the def register of the writeback value. 107 Register getWritebackReg() const { return getOperand(1).getReg(); } 108 /// Get the base register of the pointer value. 109 Register getBaseReg() const { return getOperand(2).getReg(); } 110 /// Get the offset register of the pointer value. 111 Register getOffsetReg() const { return getOperand(3).getReg(); } 112 113 bool isPre() const { return getOperand(4).getImm() == 1; } 114 bool isPost() const { return !isPre(); } 115 116 static bool classof(const MachineInstr *MI) { 117 return MI->getOpcode() == TargetOpcode::G_INDEXED_LOAD; 118 } 119 }; 120 121 /// Represents a G_INDEX_ZEXTLOAD/G_INDEXED_SEXTLOAD. 122 class GIndexedExtLoad : public GIndexedLoad { 123 public: 124 static bool classof(const MachineInstr *MI) { 125 return MI->getOpcode() == TargetOpcode::G_INDEXED_SEXTLOAD || 126 MI->getOpcode() == TargetOpcode::G_INDEXED_ZEXTLOAD; 127 } 128 }; 129 130 /// Represents either G_INDEXED_LOAD, G_INDEXED_ZEXTLOAD or G_INDEXED_SEXTLOAD. 131 class GIndexedAnyExtLoad : public GIndexedLoad { 132 public: 133 static bool classof(const MachineInstr *MI) { 134 switch (MI->getOpcode()) { 135 case TargetOpcode::G_INDEXED_LOAD: 136 case TargetOpcode::G_INDEXED_ZEXTLOAD: 137 case TargetOpcode::G_INDEXED_SEXTLOAD: 138 return true; 139 default: 140 return false; 141 } 142 } 143 }; 144 145 /// Represents a G_ZEXTLOAD. 146 class GIndexedZExtLoad : GIndexedExtLoad { 147 public: 148 static bool classof(const MachineInstr *MI) { 149 return MI->getOpcode() == TargetOpcode::G_INDEXED_ZEXTLOAD; 150 } 151 }; 152 153 /// Represents a G_SEXTLOAD. 154 class GIndexedSExtLoad : GIndexedExtLoad { 155 public: 156 static bool classof(const MachineInstr *MI) { 157 return MI->getOpcode() == TargetOpcode::G_INDEXED_SEXTLOAD; 158 } 159 }; 160 161 /// Represents indexed stores. 162 class GIndexedStore : public GMemOperation { 163 public: 164 /// Get the def register of the writeback value. 165 Register getWritebackReg() const { return getOperand(0).getReg(); } 166 /// Get the stored value register. 167 Register getValueReg() const { return getOperand(1).getReg(); } 168 /// Get the base register of the pointer value. 169 Register getBaseReg() const { return getOperand(2).getReg(); } 170 /// Get the offset register of the pointer value. 171 Register getOffsetReg() const { return getOperand(3).getReg(); } 172 173 bool isPre() const { return getOperand(4).getImm() == 1; } 174 bool isPost() const { return !isPre(); } 175 176 static bool classof(const MachineInstr *MI) { 177 return MI->getOpcode() == TargetOpcode::G_INDEXED_STORE; 178 } 179 }; 180 181 /// Represents any generic load, including sign/zero extending variants. 182 class GAnyLoad : public GLoadStore { 183 public: 184 /// Get the definition register of the loaded value. 185 Register getDstReg() const { return getOperand(0).getReg(); } 186 187 /// Returns the Ranges that describes the dereference. 188 const MDNode *getRanges() const { 189 return getMMO().getRanges(); 190 } 191 192 static bool classof(const MachineInstr *MI) { 193 switch (MI->getOpcode()) { 194 case TargetOpcode::G_LOAD: 195 case TargetOpcode::G_ZEXTLOAD: 196 case TargetOpcode::G_SEXTLOAD: 197 return true; 198 default: 199 return false; 200 } 201 } 202 }; 203 204 /// Represents a G_LOAD. 205 class GLoad : public GAnyLoad { 206 public: 207 static bool classof(const MachineInstr *MI) { 208 return MI->getOpcode() == TargetOpcode::G_LOAD; 209 } 210 }; 211 212 /// Represents either a G_SEXTLOAD or G_ZEXTLOAD. 213 class GExtLoad : public GAnyLoad { 214 public: 215 static bool classof(const MachineInstr *MI) { 216 return MI->getOpcode() == TargetOpcode::G_SEXTLOAD || 217 MI->getOpcode() == TargetOpcode::G_ZEXTLOAD; 218 } 219 }; 220 221 /// Represents a G_SEXTLOAD. 222 class GSExtLoad : public GExtLoad { 223 public: 224 static bool classof(const MachineInstr *MI) { 225 return MI->getOpcode() == TargetOpcode::G_SEXTLOAD; 226 } 227 }; 228 229 /// Represents a G_ZEXTLOAD. 230 class GZExtLoad : public GExtLoad { 231 public: 232 static bool classof(const MachineInstr *MI) { 233 return MI->getOpcode() == TargetOpcode::G_ZEXTLOAD; 234 } 235 }; 236 237 /// Represents a G_STORE. 238 class GStore : public GLoadStore { 239 public: 240 /// Get the stored value register. 241 Register getValueReg() const { return getOperand(0).getReg(); } 242 243 static bool classof(const MachineInstr *MI) { 244 return MI->getOpcode() == TargetOpcode::G_STORE; 245 } 246 }; 247 248 /// Represents a G_UNMERGE_VALUES. 249 class GUnmerge : public GenericMachineInstr { 250 public: 251 /// Returns the number of def registers. 252 unsigned getNumDefs() const { return getNumOperands() - 1; } 253 /// Get the unmerge source register. 254 Register getSourceReg() const { return getOperand(getNumDefs()).getReg(); } 255 256 static bool classof(const MachineInstr *MI) { 257 return MI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES; 258 } 259 }; 260 261 /// Represents G_BUILD_VECTOR, G_CONCAT_VECTORS or G_MERGE_VALUES. 262 /// All these have the common property of generating a single value from 263 /// multiple sources. 264 class GMergeLikeInstr : public GenericMachineInstr { 265 public: 266 /// Returns the number of source registers. 267 unsigned getNumSources() const { return getNumOperands() - 1; } 268 /// Returns the I'th source register. 269 Register getSourceReg(unsigned I) const { return getReg(I + 1); } 270 271 static bool classof(const MachineInstr *MI) { 272 switch (MI->getOpcode()) { 273 case TargetOpcode::G_MERGE_VALUES: 274 case TargetOpcode::G_CONCAT_VECTORS: 275 case TargetOpcode::G_BUILD_VECTOR: 276 return true; 277 default: 278 return false; 279 } 280 } 281 }; 282 283 /// Represents a G_MERGE_VALUES. 284 class GMerge : public GMergeLikeInstr { 285 public: 286 static bool classof(const MachineInstr *MI) { 287 return MI->getOpcode() == TargetOpcode::G_MERGE_VALUES; 288 } 289 }; 290 291 /// Represents a G_CONCAT_VECTORS. 292 class GConcatVectors : public GMergeLikeInstr { 293 public: 294 static bool classof(const MachineInstr *MI) { 295 return MI->getOpcode() == TargetOpcode::G_CONCAT_VECTORS; 296 } 297 }; 298 299 /// Represents a G_BUILD_VECTOR. 300 class GBuildVector : public GMergeLikeInstr { 301 public: 302 static bool classof(const MachineInstr *MI) { 303 return MI->getOpcode() == TargetOpcode::G_BUILD_VECTOR; 304 } 305 }; 306 307 /// Represents a G_BUILD_VECTOR_TRUNC. 308 class GBuildVectorTrunc : public GMergeLikeInstr { 309 public: 310 static bool classof(const MachineInstr *MI) { 311 return MI->getOpcode() == TargetOpcode::G_BUILD_VECTOR_TRUNC; 312 } 313 }; 314 315 /// Represents a G_SHUFFLE_VECTOR. 316 class GShuffleVector : public GenericMachineInstr { 317 public: 318 Register getSrc1Reg() const { return getOperand(1).getReg(); } 319 Register getSrc2Reg() const { return getOperand(2).getReg(); } 320 ArrayRef<int> getMask() const { return getOperand(3).getShuffleMask(); } 321 322 static bool classof(const MachineInstr *MI) { 323 return MI->getOpcode() == TargetOpcode::G_SHUFFLE_VECTOR; 324 } 325 }; 326 327 /// Represents a G_PTR_ADD. 328 class GPtrAdd : public GenericMachineInstr { 329 public: 330 Register getBaseReg() const { return getReg(1); } 331 Register getOffsetReg() const { return getReg(2); } 332 333 static bool classof(const MachineInstr *MI) { 334 return MI->getOpcode() == TargetOpcode::G_PTR_ADD; 335 } 336 }; 337 338 /// Represents a G_IMPLICIT_DEF. 339 class GImplicitDef : public GenericMachineInstr { 340 public: 341 static bool classof(const MachineInstr *MI) { 342 return MI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF; 343 } 344 }; 345 346 /// Represents a G_SELECT. 347 class GSelect : public GenericMachineInstr { 348 public: 349 Register getCondReg() const { return getReg(1); } 350 Register getTrueReg() const { return getReg(2); } 351 Register getFalseReg() const { return getReg(3); } 352 353 static bool classof(const MachineInstr *MI) { 354 return MI->getOpcode() == TargetOpcode::G_SELECT; 355 } 356 }; 357 358 /// Represent a G_ICMP or G_FCMP. 359 class GAnyCmp : public GenericMachineInstr { 360 public: 361 CmpInst::Predicate getCond() const { 362 return static_cast<CmpInst::Predicate>(getOperand(1).getPredicate()); 363 } 364 Register getLHSReg() const { return getReg(2); } 365 Register getRHSReg() const { return getReg(3); } 366 367 static bool classof(const MachineInstr *MI) { 368 return MI->getOpcode() == TargetOpcode::G_ICMP || 369 MI->getOpcode() == TargetOpcode::G_FCMP; 370 } 371 }; 372 373 /// Represent a G_ICMP. 374 class GICmp : public GAnyCmp { 375 public: 376 static bool classof(const MachineInstr *MI) { 377 return MI->getOpcode() == TargetOpcode::G_ICMP; 378 } 379 }; 380 381 /// Represent a G_FCMP. 382 class GFCmp : public GAnyCmp { 383 public: 384 static bool classof(const MachineInstr *MI) { 385 return MI->getOpcode() == TargetOpcode::G_FCMP; 386 } 387 }; 388 389 /// Represents overflowing binary operations. 390 /// Only carry-out: 391 /// G_UADDO, G_SADDO, G_USUBO, G_SSUBO, G_UMULO, G_SMULO 392 /// Carry-in and carry-out: 393 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE 394 class GBinOpCarryOut : public GenericMachineInstr { 395 public: 396 Register getDstReg() const { return getReg(0); } 397 Register getCarryOutReg() const { return getReg(1); } 398 MachineOperand &getLHS() { return getOperand(2); } 399 MachineOperand &getRHS() { return getOperand(3); } 400 Register getLHSReg() const { return getOperand(2).getReg(); } 401 Register getRHSReg() const { return getOperand(3).getReg(); } 402 403 static bool classof(const MachineInstr *MI) { 404 switch (MI->getOpcode()) { 405 case TargetOpcode::G_UADDO: 406 case TargetOpcode::G_SADDO: 407 case TargetOpcode::G_USUBO: 408 case TargetOpcode::G_SSUBO: 409 case TargetOpcode::G_UADDE: 410 case TargetOpcode::G_SADDE: 411 case TargetOpcode::G_USUBE: 412 case TargetOpcode::G_SSUBE: 413 case TargetOpcode::G_UMULO: 414 case TargetOpcode::G_SMULO: 415 return true; 416 default: 417 return false; 418 } 419 } 420 }; 421 422 /// Represents overflowing add/sub operations. 423 /// Only carry-out: 424 /// G_UADDO, G_SADDO, G_USUBO, G_SSUBO 425 /// Carry-in and carry-out: 426 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE 427 class GAddSubCarryOut : public GBinOpCarryOut { 428 public: 429 bool isAdd() const { 430 switch (getOpcode()) { 431 case TargetOpcode::G_UADDO: 432 case TargetOpcode::G_SADDO: 433 case TargetOpcode::G_UADDE: 434 case TargetOpcode::G_SADDE: 435 return true; 436 default: 437 return false; 438 } 439 } 440 bool isSub() const { return !isAdd(); } 441 442 bool isSigned() const { 443 switch (getOpcode()) { 444 case TargetOpcode::G_SADDO: 445 case TargetOpcode::G_SSUBO: 446 case TargetOpcode::G_SADDE: 447 case TargetOpcode::G_SSUBE: 448 return true; 449 default: 450 return false; 451 } 452 } 453 bool isUnsigned() const { return !isSigned(); } 454 455 static bool classof(const MachineInstr *MI) { 456 switch (MI->getOpcode()) { 457 case TargetOpcode::G_UADDO: 458 case TargetOpcode::G_SADDO: 459 case TargetOpcode::G_USUBO: 460 case TargetOpcode::G_SSUBO: 461 case TargetOpcode::G_UADDE: 462 case TargetOpcode::G_SADDE: 463 case TargetOpcode::G_USUBE: 464 case TargetOpcode::G_SSUBE: 465 return true; 466 default: 467 return false; 468 } 469 } 470 }; 471 472 /// Represents overflowing add operations. 473 /// G_UADDO, G_SADDO 474 class GAddCarryOut : public GBinOpCarryOut { 475 public: 476 bool isSigned() const { return getOpcode() == TargetOpcode::G_SADDO; } 477 478 static bool classof(const MachineInstr *MI) { 479 switch (MI->getOpcode()) { 480 case TargetOpcode::G_UADDO: 481 case TargetOpcode::G_SADDO: 482 return true; 483 default: 484 return false; 485 } 486 } 487 }; 488 489 /// Represents overflowing sub operations. 490 /// G_USUBO, G_SSUBO 491 class GSubCarryOut : public GBinOpCarryOut { 492 public: 493 bool isSigned() const { return getOpcode() == TargetOpcode::G_SSUBO; } 494 495 static bool classof(const MachineInstr *MI) { 496 switch (MI->getOpcode()) { 497 case TargetOpcode::G_USUBO: 498 case TargetOpcode::G_SSUBO: 499 return true; 500 default: 501 return false; 502 } 503 } 504 }; 505 506 /// Represents overflowing add/sub operations that also consume a carry-in. 507 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE 508 class GAddSubCarryInOut : public GAddSubCarryOut { 509 public: 510 Register getCarryInReg() const { return getReg(4); } 511 512 static bool classof(const MachineInstr *MI) { 513 switch (MI->getOpcode()) { 514 case TargetOpcode::G_UADDE: 515 case TargetOpcode::G_SADDE: 516 case TargetOpcode::G_USUBE: 517 case TargetOpcode::G_SSUBE: 518 return true; 519 default: 520 return false; 521 } 522 } 523 }; 524 525 /// Represents a call to an intrinsic. 526 class GIntrinsic final : public GenericMachineInstr { 527 public: 528 Intrinsic::ID getIntrinsicID() const { 529 return getOperand(getNumExplicitDefs()).getIntrinsicID(); 530 } 531 532 bool is(Intrinsic::ID ID) const { return getIntrinsicID() == ID; } 533 534 bool hasSideEffects() const { 535 switch (getOpcode()) { 536 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: 537 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS: 538 return true; 539 default: 540 return false; 541 } 542 } 543 544 bool isConvergent() const { 545 switch (getOpcode()) { 546 case TargetOpcode::G_INTRINSIC_CONVERGENT: 547 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS: 548 return true; 549 default: 550 return false; 551 } 552 } 553 554 static bool classof(const MachineInstr *MI) { 555 switch (MI->getOpcode()) { 556 case TargetOpcode::G_INTRINSIC: 557 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: 558 case TargetOpcode::G_INTRINSIC_CONVERGENT: 559 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS: 560 return true; 561 default: 562 return false; 563 } 564 } 565 }; 566 567 // Represents a (non-sequential) vector reduction operation. 568 class GVecReduce : public GenericMachineInstr { 569 public: 570 static bool classof(const MachineInstr *MI) { 571 switch (MI->getOpcode()) { 572 case TargetOpcode::G_VECREDUCE_FADD: 573 case TargetOpcode::G_VECREDUCE_FMUL: 574 case TargetOpcode::G_VECREDUCE_FMAX: 575 case TargetOpcode::G_VECREDUCE_FMIN: 576 case TargetOpcode::G_VECREDUCE_FMAXIMUM: 577 case TargetOpcode::G_VECREDUCE_FMINIMUM: 578 case TargetOpcode::G_VECREDUCE_ADD: 579 case TargetOpcode::G_VECREDUCE_MUL: 580 case TargetOpcode::G_VECREDUCE_AND: 581 case TargetOpcode::G_VECREDUCE_OR: 582 case TargetOpcode::G_VECREDUCE_XOR: 583 case TargetOpcode::G_VECREDUCE_SMAX: 584 case TargetOpcode::G_VECREDUCE_SMIN: 585 case TargetOpcode::G_VECREDUCE_UMAX: 586 case TargetOpcode::G_VECREDUCE_UMIN: 587 return true; 588 default: 589 return false; 590 } 591 } 592 593 /// Get the opcode for the equivalent scalar operation for this reduction. 594 /// E.g. for G_VECREDUCE_FADD, this returns G_FADD. 595 unsigned getScalarOpcForReduction() { 596 unsigned ScalarOpc; 597 switch (getOpcode()) { 598 case TargetOpcode::G_VECREDUCE_FADD: 599 ScalarOpc = TargetOpcode::G_FADD; 600 break; 601 case TargetOpcode::G_VECREDUCE_FMUL: 602 ScalarOpc = TargetOpcode::G_FMUL; 603 break; 604 case TargetOpcode::G_VECREDUCE_FMAX: 605 ScalarOpc = TargetOpcode::G_FMAXNUM; 606 break; 607 case TargetOpcode::G_VECREDUCE_FMIN: 608 ScalarOpc = TargetOpcode::G_FMINNUM; 609 break; 610 case TargetOpcode::G_VECREDUCE_FMAXIMUM: 611 ScalarOpc = TargetOpcode::G_FMAXIMUM; 612 break; 613 case TargetOpcode::G_VECREDUCE_FMINIMUM: 614 ScalarOpc = TargetOpcode::G_FMINIMUM; 615 break; 616 case TargetOpcode::G_VECREDUCE_ADD: 617 ScalarOpc = TargetOpcode::G_ADD; 618 break; 619 case TargetOpcode::G_VECREDUCE_MUL: 620 ScalarOpc = TargetOpcode::G_MUL; 621 break; 622 case TargetOpcode::G_VECREDUCE_AND: 623 ScalarOpc = TargetOpcode::G_AND; 624 break; 625 case TargetOpcode::G_VECREDUCE_OR: 626 ScalarOpc = TargetOpcode::G_OR; 627 break; 628 case TargetOpcode::G_VECREDUCE_XOR: 629 ScalarOpc = TargetOpcode::G_XOR; 630 break; 631 case TargetOpcode::G_VECREDUCE_SMAX: 632 ScalarOpc = TargetOpcode::G_SMAX; 633 break; 634 case TargetOpcode::G_VECREDUCE_SMIN: 635 ScalarOpc = TargetOpcode::G_SMIN; 636 break; 637 case TargetOpcode::G_VECREDUCE_UMAX: 638 ScalarOpc = TargetOpcode::G_UMAX; 639 break; 640 case TargetOpcode::G_VECREDUCE_UMIN: 641 ScalarOpc = TargetOpcode::G_UMIN; 642 break; 643 default: 644 llvm_unreachable("Unhandled reduction"); 645 } 646 return ScalarOpc; 647 } 648 }; 649 650 /// Represents a G_PHI. 651 class GPhi : public GenericMachineInstr { 652 public: 653 /// Returns the number of incoming values. 654 unsigned getNumIncomingValues() const { return (getNumOperands() - 1) / 2; } 655 /// Returns the I'th incoming vreg. 656 Register getIncomingValue(unsigned I) const { 657 return getOperand(I * 2 + 1).getReg(); 658 } 659 /// Returns the I'th incoming basic block. 660 MachineBasicBlock *getIncomingBlock(unsigned I) const { 661 return getOperand(I * 2 + 2).getMBB(); 662 } 663 664 static bool classof(const MachineInstr *MI) { 665 return MI->getOpcode() == TargetOpcode::G_PHI; 666 } 667 }; 668 669 /// Represents a binary operation, i.e, x = y op z. 670 class GBinOp : public GenericMachineInstr { 671 public: 672 Register getLHSReg() const { return getReg(1); } 673 Register getRHSReg() const { return getReg(2); } 674 675 static bool classof(const MachineInstr *MI) { 676 switch (MI->getOpcode()) { 677 // Integer. 678 case TargetOpcode::G_ADD: 679 case TargetOpcode::G_SUB: 680 case TargetOpcode::G_MUL: 681 case TargetOpcode::G_SDIV: 682 case TargetOpcode::G_UDIV: 683 case TargetOpcode::G_SREM: 684 case TargetOpcode::G_UREM: 685 case TargetOpcode::G_SMIN: 686 case TargetOpcode::G_SMAX: 687 case TargetOpcode::G_UMIN: 688 case TargetOpcode::G_UMAX: 689 // Floating point. 690 case TargetOpcode::G_FMINNUM: 691 case TargetOpcode::G_FMAXNUM: 692 case TargetOpcode::G_FMINNUM_IEEE: 693 case TargetOpcode::G_FMAXNUM_IEEE: 694 case TargetOpcode::G_FMINIMUM: 695 case TargetOpcode::G_FMAXIMUM: 696 case TargetOpcode::G_FADD: 697 case TargetOpcode::G_FSUB: 698 case TargetOpcode::G_FMUL: 699 case TargetOpcode::G_FDIV: 700 case TargetOpcode::G_FPOW: 701 // Logical. 702 case TargetOpcode::G_AND: 703 case TargetOpcode::G_OR: 704 case TargetOpcode::G_XOR: 705 return true; 706 default: 707 return false; 708 } 709 }; 710 }; 711 712 /// Represents an integer binary operation. 713 class GIntBinOp : public GBinOp { 714 public: 715 static bool classof(const MachineInstr *MI) { 716 switch (MI->getOpcode()) { 717 case TargetOpcode::G_ADD: 718 case TargetOpcode::G_SUB: 719 case TargetOpcode::G_MUL: 720 case TargetOpcode::G_SDIV: 721 case TargetOpcode::G_UDIV: 722 case TargetOpcode::G_SREM: 723 case TargetOpcode::G_UREM: 724 case TargetOpcode::G_SMIN: 725 case TargetOpcode::G_SMAX: 726 case TargetOpcode::G_UMIN: 727 case TargetOpcode::G_UMAX: 728 return true; 729 default: 730 return false; 731 } 732 }; 733 }; 734 735 /// Represents a floating point binary operation. 736 class GFBinOp : public GBinOp { 737 public: 738 static bool classof(const MachineInstr *MI) { 739 switch (MI->getOpcode()) { 740 case TargetOpcode::G_FMINNUM: 741 case TargetOpcode::G_FMAXNUM: 742 case TargetOpcode::G_FMINNUM_IEEE: 743 case TargetOpcode::G_FMAXNUM_IEEE: 744 case TargetOpcode::G_FMINIMUM: 745 case TargetOpcode::G_FMAXIMUM: 746 case TargetOpcode::G_FADD: 747 case TargetOpcode::G_FSUB: 748 case TargetOpcode::G_FMUL: 749 case TargetOpcode::G_FDIV: 750 case TargetOpcode::G_FPOW: 751 return true; 752 default: 753 return false; 754 } 755 }; 756 }; 757 758 /// Represents a logical binary operation. 759 class GLogicalBinOp : public GBinOp { 760 public: 761 static bool classof(const MachineInstr *MI) { 762 switch (MI->getOpcode()) { 763 case TargetOpcode::G_AND: 764 case TargetOpcode::G_OR: 765 case TargetOpcode::G_XOR: 766 return true; 767 default: 768 return false; 769 } 770 }; 771 }; 772 773 /// Represents an integer addition. 774 class GAdd : public GIntBinOp { 775 public: 776 static bool classof(const MachineInstr *MI) { 777 return MI->getOpcode() == TargetOpcode::G_ADD; 778 }; 779 }; 780 781 /// Represents a logical and. 782 class GAnd : public GLogicalBinOp { 783 public: 784 static bool classof(const MachineInstr *MI) { 785 return MI->getOpcode() == TargetOpcode::G_AND; 786 }; 787 }; 788 789 /// Represents a logical or. 790 class GOr : public GLogicalBinOp { 791 public: 792 static bool classof(const MachineInstr *MI) { 793 return MI->getOpcode() == TargetOpcode::G_OR; 794 }; 795 }; 796 797 /// Represents an extract vector element. 798 class GExtractVectorElement : public GenericMachineInstr { 799 public: 800 Register getVectorReg() const { return getOperand(1).getReg(); } 801 Register getIndexReg() const { return getOperand(2).getReg(); } 802 803 static bool classof(const MachineInstr *MI) { 804 return MI->getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT; 805 } 806 }; 807 808 /// Represents an insert vector element. 809 class GInsertVectorElement : public GenericMachineInstr { 810 public: 811 Register getVectorReg() const { return getOperand(1).getReg(); } 812 Register getElementReg() const { return getOperand(2).getReg(); } 813 Register getIndexReg() const { return getOperand(3).getReg(); } 814 815 static bool classof(const MachineInstr *MI) { 816 return MI->getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT; 817 } 818 }; 819 820 /// Represents an extract subvector. 821 class GExtractSubvector : public GenericMachineInstr { 822 public: 823 Register getSrcVec() const { return getOperand(1).getReg(); } 824 uint64_t getIndexImm() const { return getOperand(2).getImm(); } 825 826 static bool classof(const MachineInstr *MI) { 827 return MI->getOpcode() == TargetOpcode::G_EXTRACT_SUBVECTOR; 828 } 829 }; 830 831 /// Represents a insert subvector. 832 class GInsertSubvector : public GenericMachineInstr { 833 public: 834 Register getBigVec() const { return getOperand(1).getReg(); } 835 Register getSubVec() const { return getOperand(2).getReg(); } 836 uint64_t getIndexImm() const { return getOperand(3).getImm(); } 837 838 static bool classof(const MachineInstr *MI) { 839 return MI->getOpcode() == TargetOpcode::G_INSERT_SUBVECTOR; 840 } 841 }; 842 843 /// Represents a freeze. 844 class GFreeze : public GenericMachineInstr { 845 public: 846 Register getSourceReg() const { return getOperand(1).getReg(); } 847 848 static bool classof(const MachineInstr *MI) { 849 return MI->getOpcode() == TargetOpcode::G_FREEZE; 850 } 851 }; 852 853 /// Represents a cast operation. 854 /// It models the llvm::CastInst concept. 855 /// The exception is bitcast. 856 class GCastOp : public GenericMachineInstr { 857 public: 858 Register getSrcReg() const { return getOperand(1).getReg(); } 859 860 static bool classof(const MachineInstr *MI) { 861 switch (MI->getOpcode()) { 862 case TargetOpcode::G_ADDRSPACE_CAST: 863 case TargetOpcode::G_FPEXT: 864 case TargetOpcode::G_FPTOSI: 865 case TargetOpcode::G_FPTOUI: 866 case TargetOpcode::G_FPTOSI_SAT: 867 case TargetOpcode::G_FPTOUI_SAT: 868 case TargetOpcode::G_FPTRUNC: 869 case TargetOpcode::G_INTTOPTR: 870 case TargetOpcode::G_PTRTOINT: 871 case TargetOpcode::G_SEXT: 872 case TargetOpcode::G_SITOFP: 873 case TargetOpcode::G_TRUNC: 874 case TargetOpcode::G_UITOFP: 875 case TargetOpcode::G_ZEXT: 876 case TargetOpcode::G_ANYEXT: 877 return true; 878 default: 879 return false; 880 } 881 }; 882 }; 883 884 /// Represents a sext. 885 class GSext : public GCastOp { 886 public: 887 static bool classof(const MachineInstr *MI) { 888 return MI->getOpcode() == TargetOpcode::G_SEXT; 889 }; 890 }; 891 892 /// Represents a zext. 893 class GZext : public GCastOp { 894 public: 895 static bool classof(const MachineInstr *MI) { 896 return MI->getOpcode() == TargetOpcode::G_ZEXT; 897 }; 898 }; 899 900 /// Represents an any ext. 901 class GAnyExt : public GCastOp { 902 public: 903 static bool classof(const MachineInstr *MI) { 904 return MI->getOpcode() == TargetOpcode::G_ANYEXT; 905 }; 906 }; 907 908 /// Represents a trunc. 909 class GTrunc : public GCastOp { 910 public: 911 static bool classof(const MachineInstr *MI) { 912 return MI->getOpcode() == TargetOpcode::G_TRUNC; 913 }; 914 }; 915 916 /// Represents a vscale. 917 class GVScale : public GenericMachineInstr { 918 public: 919 APInt getSrc() const { return getOperand(1).getCImm()->getValue(); } 920 921 static bool classof(const MachineInstr *MI) { 922 return MI->getOpcode() == TargetOpcode::G_VSCALE; 923 }; 924 }; 925 926 /// Represents a step vector. 927 class GStepVector : public GenericMachineInstr { 928 public: 929 uint64_t getStep() const { 930 return getOperand(1).getCImm()->getValue().getZExtValue(); 931 } 932 933 static bool classof(const MachineInstr *MI) { 934 return MI->getOpcode() == TargetOpcode::G_STEP_VECTOR; 935 }; 936 }; 937 938 /// Represents an integer subtraction. 939 class GSub : public GIntBinOp { 940 public: 941 static bool classof(const MachineInstr *MI) { 942 return MI->getOpcode() == TargetOpcode::G_SUB; 943 }; 944 }; 945 946 /// Represents an integer multiplication. 947 class GMul : public GIntBinOp { 948 public: 949 static bool classof(const MachineInstr *MI) { 950 return MI->getOpcode() == TargetOpcode::G_MUL; 951 }; 952 }; 953 954 /// Represents a shift left. 955 class GShl : public GenericMachineInstr { 956 public: 957 Register getSrcReg() const { return getOperand(1).getReg(); } 958 Register getShiftReg() const { return getOperand(2).getReg(); } 959 960 static bool classof(const MachineInstr *MI) { 961 return MI->getOpcode() == TargetOpcode::G_SHL; 962 }; 963 }; 964 965 /// Represents a threeway compare. 966 class GSUCmp : public GenericMachineInstr { 967 public: 968 Register getLHSReg() const { return getOperand(1).getReg(); } 969 Register getRHSReg() const { return getOperand(2).getReg(); } 970 971 bool isSigned() const { return getOpcode() == TargetOpcode::G_SCMP; } 972 973 static bool classof(const MachineInstr *MI) { 974 switch (MI->getOpcode()) { 975 case TargetOpcode::G_SCMP: 976 case TargetOpcode::G_UCMP: 977 return true; 978 default: 979 return false; 980 } 981 }; 982 }; 983 984 /// Represents an integer-like extending operation. 985 class GExtOp : public GCastOp { 986 public: 987 static bool classof(const MachineInstr *MI) { 988 switch (MI->getOpcode()) { 989 case TargetOpcode::G_SEXT: 990 case TargetOpcode::G_ZEXT: 991 case TargetOpcode::G_ANYEXT: 992 return true; 993 default: 994 return false; 995 } 996 }; 997 }; 998 999 /// Represents an integer-like extending or truncating operation. 1000 class GExtOrTruncOp : public GCastOp { 1001 public: 1002 static bool classof(const MachineInstr *MI) { 1003 switch (MI->getOpcode()) { 1004 case TargetOpcode::G_SEXT: 1005 case TargetOpcode::G_ZEXT: 1006 case TargetOpcode::G_ANYEXT: 1007 case TargetOpcode::G_TRUNC: 1008 return true; 1009 default: 1010 return false; 1011 } 1012 }; 1013 }; 1014 1015 /// Represents a splat vector. 1016 class GSplatVector : public GenericMachineInstr { 1017 public: 1018 Register getScalarReg() const { return getOperand(1).getReg(); } 1019 1020 static bool classof(const MachineInstr *MI) { 1021 return MI->getOpcode() == TargetOpcode::G_SPLAT_VECTOR; 1022 }; 1023 }; 1024 1025 } // namespace llvm 1026 1027 #endif // LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H 1028