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