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; 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 /// Returns the size in bytes of the memory access. getMemSize()70 LocationSize getMemSize() const { return getMMO().getSize(); } 71 /// Returns the size in bits of the memory access. getMemSizeInBits()72 LocationSize getMemSizeInBits() const { return getMMO().getSizeInBits(); } 73 classof(const MachineInstr * MI)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. getPointerReg()84 Register getPointerReg() const { return getOperand(1).getReg(); } 85 classof(const MachineInstr * MI)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. getDstReg()105 Register getDstReg() const { return getOperand(0).getReg(); } 106 /// Get the def register of the writeback value. getWritebackReg()107 Register getWritebackReg() const { return getOperand(1).getReg(); } 108 /// Get the base register of the pointer value. getBaseReg()109 Register getBaseReg() const { return getOperand(2).getReg(); } 110 /// Get the offset register of the pointer value. getOffsetReg()111 Register getOffsetReg() const { return getOperand(3).getReg(); } 112 isPre()113 bool isPre() const { return getOperand(4).getImm() == 1; } isPost()114 bool isPost() const { return !isPre(); } 115 classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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. getWritebackReg()165 Register getWritebackReg() const { return getOperand(0).getReg(); } 166 /// Get the stored value register. getValueReg()167 Register getValueReg() const { return getOperand(1).getReg(); } 168 /// Get the base register of the pointer value. getBaseReg()169 Register getBaseReg() const { return getOperand(2).getReg(); } 170 /// Get the offset register of the pointer value. getOffsetReg()171 Register getOffsetReg() const { return getOperand(3).getReg(); } 172 isPre()173 bool isPre() const { return getOperand(4).getImm() == 1; } isPost()174 bool isPost() const { return !isPre(); } 175 classof(const MachineInstr * MI)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. getDstReg()185 Register getDstReg() const { return getOperand(0).getReg(); } 186 187 /// Returns the Ranges that describes the dereference. getRanges()188 const MDNode *getRanges() const { 189 return getMMO().getRanges(); 190 } 191 classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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. getValueReg()241 Register getValueReg() const { return getOperand(0).getReg(); } 242 classof(const MachineInstr * MI)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. getNumDefs()252 unsigned getNumDefs() const { return getNumOperands() - 1; } 253 /// Get the unmerge source register. getSourceReg()254 Register getSourceReg() const { return getOperand(getNumDefs()).getReg(); } 255 classof(const MachineInstr * MI)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. getNumSources()267 unsigned getNumSources() const { return getNumOperands() - 1; } 268 /// Returns the I'th source register. getSourceReg(unsigned I)269 Register getSourceReg(unsigned I) const { return getReg(I + 1); } 270 classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: getSrc1Reg()318 Register getSrc1Reg() const { return getOperand(1).getReg(); } getSrc2Reg()319 Register getSrc2Reg() const { return getOperand(2).getReg(); } getMask()320 ArrayRef<int> getMask() const { return getOperand(3).getShuffleMask(); } 321 classof(const MachineInstr * MI)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: getBaseReg()330 Register getBaseReg() const { return getReg(1); } getOffsetReg()331 Register getOffsetReg() const { return getReg(2); } 332 classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: getCondReg()349 Register getCondReg() const { return getReg(1); } getTrueReg()350 Register getTrueReg() const { return getReg(2); } getFalseReg()351 Register getFalseReg() const { return getReg(3); } 352 classof(const MachineInstr * MI)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: getCond()361 CmpInst::Predicate getCond() const { 362 return static_cast<CmpInst::Predicate>(getOperand(1).getPredicate()); 363 } getLHSReg()364 Register getLHSReg() const { return getReg(2); } getRHSReg()365 Register getRHSReg() const { return getReg(3); } 366 classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: getDstReg()396 Register getDstReg() const { return getReg(0); } getCarryOutReg()397 Register getCarryOutReg() const { return getReg(1); } getLHS()398 MachineOperand &getLHS() { return getOperand(2); } getRHS()399 MachineOperand &getRHS() { return getOperand(3); } getLHSReg()400 Register getLHSReg() const { return getOperand(2).getReg(); } getRHSReg()401 Register getRHSReg() const { return getOperand(3).getReg(); } 402 classof(const MachineInstr * MI)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: isAdd()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 } isSub()440 bool isSub() const { return !isAdd(); } 441 isSigned()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 } isUnsigned()453 bool isUnsigned() const { return !isSigned(); } 454 classof(const MachineInstr * MI)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: isSigned()476 bool isSigned() const { return getOpcode() == TargetOpcode::G_SADDO; } 477 classof(const MachineInstr * MI)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 add/sub operations that also consume a carry-in. 490 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE 491 class GAddSubCarryInOut : public GAddSubCarryOut { 492 public: getCarryInReg()493 Register getCarryInReg() const { return getReg(4); } 494 classof(const MachineInstr * MI)495 static bool classof(const MachineInstr *MI) { 496 switch (MI->getOpcode()) { 497 case TargetOpcode::G_UADDE: 498 case TargetOpcode::G_SADDE: 499 case TargetOpcode::G_USUBE: 500 case TargetOpcode::G_SSUBE: 501 return true; 502 default: 503 return false; 504 } 505 } 506 }; 507 508 /// Represents a call to an intrinsic. 509 class GIntrinsic final : public GenericMachineInstr { 510 public: getIntrinsicID()511 Intrinsic::ID getIntrinsicID() const { 512 return getOperand(getNumExplicitDefs()).getIntrinsicID(); 513 } 514 is(Intrinsic::ID ID)515 bool is(Intrinsic::ID ID) const { return getIntrinsicID() == ID; } 516 hasSideEffects()517 bool hasSideEffects() const { 518 switch (getOpcode()) { 519 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: 520 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS: 521 return true; 522 default: 523 return false; 524 } 525 } 526 isConvergent()527 bool isConvergent() const { 528 switch (getOpcode()) { 529 case TargetOpcode::G_INTRINSIC_CONVERGENT: 530 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS: 531 return true; 532 default: 533 return false; 534 } 535 } 536 classof(const MachineInstr * MI)537 static bool classof(const MachineInstr *MI) { 538 switch (MI->getOpcode()) { 539 case TargetOpcode::G_INTRINSIC: 540 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: 541 case TargetOpcode::G_INTRINSIC_CONVERGENT: 542 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS: 543 return true; 544 default: 545 return false; 546 } 547 } 548 }; 549 550 // Represents a (non-sequential) vector reduction operation. 551 class GVecReduce : public GenericMachineInstr { 552 public: classof(const MachineInstr * MI)553 static bool classof(const MachineInstr *MI) { 554 switch (MI->getOpcode()) { 555 case TargetOpcode::G_VECREDUCE_FADD: 556 case TargetOpcode::G_VECREDUCE_FMUL: 557 case TargetOpcode::G_VECREDUCE_FMAX: 558 case TargetOpcode::G_VECREDUCE_FMIN: 559 case TargetOpcode::G_VECREDUCE_FMAXIMUM: 560 case TargetOpcode::G_VECREDUCE_FMINIMUM: 561 case TargetOpcode::G_VECREDUCE_ADD: 562 case TargetOpcode::G_VECREDUCE_MUL: 563 case TargetOpcode::G_VECREDUCE_AND: 564 case TargetOpcode::G_VECREDUCE_OR: 565 case TargetOpcode::G_VECREDUCE_XOR: 566 case TargetOpcode::G_VECREDUCE_SMAX: 567 case TargetOpcode::G_VECREDUCE_SMIN: 568 case TargetOpcode::G_VECREDUCE_UMAX: 569 case TargetOpcode::G_VECREDUCE_UMIN: 570 return true; 571 default: 572 return false; 573 } 574 } 575 576 /// Get the opcode for the equivalent scalar operation for this reduction. 577 /// E.g. for G_VECREDUCE_FADD, this returns G_FADD. getScalarOpcForReduction()578 unsigned getScalarOpcForReduction() { 579 unsigned ScalarOpc; 580 switch (getOpcode()) { 581 case TargetOpcode::G_VECREDUCE_FADD: 582 ScalarOpc = TargetOpcode::G_FADD; 583 break; 584 case TargetOpcode::G_VECREDUCE_FMUL: 585 ScalarOpc = TargetOpcode::G_FMUL; 586 break; 587 case TargetOpcode::G_VECREDUCE_FMAX: 588 ScalarOpc = TargetOpcode::G_FMAXNUM; 589 break; 590 case TargetOpcode::G_VECREDUCE_FMIN: 591 ScalarOpc = TargetOpcode::G_FMINNUM; 592 break; 593 case TargetOpcode::G_VECREDUCE_FMAXIMUM: 594 ScalarOpc = TargetOpcode::G_FMAXIMUM; 595 break; 596 case TargetOpcode::G_VECREDUCE_FMINIMUM: 597 ScalarOpc = TargetOpcode::G_FMINIMUM; 598 break; 599 case TargetOpcode::G_VECREDUCE_ADD: 600 ScalarOpc = TargetOpcode::G_ADD; 601 break; 602 case TargetOpcode::G_VECREDUCE_MUL: 603 ScalarOpc = TargetOpcode::G_MUL; 604 break; 605 case TargetOpcode::G_VECREDUCE_AND: 606 ScalarOpc = TargetOpcode::G_AND; 607 break; 608 case TargetOpcode::G_VECREDUCE_OR: 609 ScalarOpc = TargetOpcode::G_OR; 610 break; 611 case TargetOpcode::G_VECREDUCE_XOR: 612 ScalarOpc = TargetOpcode::G_XOR; 613 break; 614 case TargetOpcode::G_VECREDUCE_SMAX: 615 ScalarOpc = TargetOpcode::G_SMAX; 616 break; 617 case TargetOpcode::G_VECREDUCE_SMIN: 618 ScalarOpc = TargetOpcode::G_SMIN; 619 break; 620 case TargetOpcode::G_VECREDUCE_UMAX: 621 ScalarOpc = TargetOpcode::G_UMAX; 622 break; 623 case TargetOpcode::G_VECREDUCE_UMIN: 624 ScalarOpc = TargetOpcode::G_UMIN; 625 break; 626 default: 627 llvm_unreachable("Unhandled reduction"); 628 } 629 return ScalarOpc; 630 } 631 }; 632 633 /// Represents a G_PHI. 634 class GPhi : public GenericMachineInstr { 635 public: 636 /// Returns the number of incoming values. getNumIncomingValues()637 unsigned getNumIncomingValues() const { return (getNumOperands() - 1) / 2; } 638 /// Returns the I'th incoming vreg. getIncomingValue(unsigned I)639 Register getIncomingValue(unsigned I) const { 640 return getOperand(I * 2 + 1).getReg(); 641 } 642 /// Returns the I'th incoming basic block. getIncomingBlock(unsigned I)643 MachineBasicBlock *getIncomingBlock(unsigned I) const { 644 return getOperand(I * 2 + 2).getMBB(); 645 } 646 classof(const MachineInstr * MI)647 static bool classof(const MachineInstr *MI) { 648 return MI->getOpcode() == TargetOpcode::G_PHI; 649 } 650 }; 651 652 /// Represents a binary operation, i.e, x = y op z. 653 class GBinOp : public GenericMachineInstr { 654 public: getLHSReg()655 Register getLHSReg() const { return getReg(1); } getRHSReg()656 Register getRHSReg() const { return getReg(2); } 657 classof(const MachineInstr * MI)658 static bool classof(const MachineInstr *MI) { 659 switch (MI->getOpcode()) { 660 // Integer. 661 case TargetOpcode::G_ADD: 662 case TargetOpcode::G_SUB: 663 case TargetOpcode::G_MUL: 664 case TargetOpcode::G_SDIV: 665 case TargetOpcode::G_UDIV: 666 case TargetOpcode::G_SREM: 667 case TargetOpcode::G_UREM: 668 case TargetOpcode::G_SMIN: 669 case TargetOpcode::G_SMAX: 670 case TargetOpcode::G_UMIN: 671 case TargetOpcode::G_UMAX: 672 // Floating point. 673 case TargetOpcode::G_FMINNUM: 674 case TargetOpcode::G_FMAXNUM: 675 case TargetOpcode::G_FMINNUM_IEEE: 676 case TargetOpcode::G_FMAXNUM_IEEE: 677 case TargetOpcode::G_FMINIMUM: 678 case TargetOpcode::G_FMAXIMUM: 679 case TargetOpcode::G_FADD: 680 case TargetOpcode::G_FSUB: 681 case TargetOpcode::G_FMUL: 682 case TargetOpcode::G_FDIV: 683 case TargetOpcode::G_FPOW: 684 // Logical. 685 case TargetOpcode::G_AND: 686 case TargetOpcode::G_OR: 687 case TargetOpcode::G_XOR: 688 return true; 689 default: 690 return false; 691 } 692 }; 693 }; 694 695 /// Represents an integer binary operation. 696 class GIntBinOp : public GBinOp { 697 public: classof(const MachineInstr * MI)698 static bool classof(const MachineInstr *MI) { 699 switch (MI->getOpcode()) { 700 case TargetOpcode::G_ADD: 701 case TargetOpcode::G_SUB: 702 case TargetOpcode::G_MUL: 703 case TargetOpcode::G_SDIV: 704 case TargetOpcode::G_UDIV: 705 case TargetOpcode::G_SREM: 706 case TargetOpcode::G_UREM: 707 case TargetOpcode::G_SMIN: 708 case TargetOpcode::G_SMAX: 709 case TargetOpcode::G_UMIN: 710 case TargetOpcode::G_UMAX: 711 return true; 712 default: 713 return false; 714 } 715 }; 716 }; 717 718 /// Represents a floating point binary operation. 719 class GFBinOp : public GBinOp { 720 public: classof(const MachineInstr * MI)721 static bool classof(const MachineInstr *MI) { 722 switch (MI->getOpcode()) { 723 case TargetOpcode::G_FMINNUM: 724 case TargetOpcode::G_FMAXNUM: 725 case TargetOpcode::G_FMINNUM_IEEE: 726 case TargetOpcode::G_FMAXNUM_IEEE: 727 case TargetOpcode::G_FMINIMUM: 728 case TargetOpcode::G_FMAXIMUM: 729 case TargetOpcode::G_FADD: 730 case TargetOpcode::G_FSUB: 731 case TargetOpcode::G_FMUL: 732 case TargetOpcode::G_FDIV: 733 case TargetOpcode::G_FPOW: 734 return true; 735 default: 736 return false; 737 } 738 }; 739 }; 740 741 /// Represents a logical binary operation. 742 class GLogicalBinOp : public GBinOp { 743 public: classof(const MachineInstr * MI)744 static bool classof(const MachineInstr *MI) { 745 switch (MI->getOpcode()) { 746 case TargetOpcode::G_AND: 747 case TargetOpcode::G_OR: 748 case TargetOpcode::G_XOR: 749 return true; 750 default: 751 return false; 752 } 753 }; 754 }; 755 756 /// Represents an integer addition. 757 class GAdd : public GIntBinOp { 758 public: classof(const MachineInstr * MI)759 static bool classof(const MachineInstr *MI) { 760 return MI->getOpcode() == TargetOpcode::G_ADD; 761 }; 762 }; 763 764 /// Represents a logical and. 765 class GAnd : public GLogicalBinOp { 766 public: classof(const MachineInstr * MI)767 static bool classof(const MachineInstr *MI) { 768 return MI->getOpcode() == TargetOpcode::G_AND; 769 }; 770 }; 771 772 /// Represents a logical or. 773 class GOr : public GLogicalBinOp { 774 public: classof(const MachineInstr * MI)775 static bool classof(const MachineInstr *MI) { 776 return MI->getOpcode() == TargetOpcode::G_OR; 777 }; 778 }; 779 780 /// Represents an extract vector element. 781 class GExtractVectorElement : public GenericMachineInstr { 782 public: getVectorReg()783 Register getVectorReg() const { return getOperand(1).getReg(); } getIndexReg()784 Register getIndexReg() const { return getOperand(2).getReg(); } 785 classof(const MachineInstr * MI)786 static bool classof(const MachineInstr *MI) { 787 return MI->getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT; 788 } 789 }; 790 791 /// Represents an insert vector element. 792 class GInsertVectorElement : public GenericMachineInstr { 793 public: getVectorReg()794 Register getVectorReg() const { return getOperand(1).getReg(); } getElementReg()795 Register getElementReg() const { return getOperand(2).getReg(); } getIndexReg()796 Register getIndexReg() const { return getOperand(3).getReg(); } 797 classof(const MachineInstr * MI)798 static bool classof(const MachineInstr *MI) { 799 return MI->getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT; 800 } 801 }; 802 803 /// Represents a freeze. 804 class GFreeze : public GenericMachineInstr { 805 public: getSourceReg()806 Register getSourceReg() const { return getOperand(1).getReg(); } 807 classof(const MachineInstr * MI)808 static bool classof(const MachineInstr *MI) { 809 return MI->getOpcode() == TargetOpcode::G_FREEZE; 810 } 811 }; 812 813 /// Represents a cast operation. 814 /// It models the llvm::CastInst concept. 815 /// The exception is bitcast. 816 class GCastOp : public GenericMachineInstr { 817 public: getSrcReg()818 Register getSrcReg() const { return getOperand(1).getReg(); } 819 classof(const MachineInstr * MI)820 static bool classof(const MachineInstr *MI) { 821 switch (MI->getOpcode()) { 822 case TargetOpcode::G_ADDRSPACE_CAST: 823 case TargetOpcode::G_FPEXT: 824 case TargetOpcode::G_FPTOSI: 825 case TargetOpcode::G_FPTOUI: 826 case TargetOpcode::G_FPTRUNC: 827 case TargetOpcode::G_INTTOPTR: 828 case TargetOpcode::G_PTRTOINT: 829 case TargetOpcode::G_SEXT: 830 case TargetOpcode::G_SITOFP: 831 case TargetOpcode::G_TRUNC: 832 case TargetOpcode::G_UITOFP: 833 case TargetOpcode::G_ZEXT: 834 case TargetOpcode::G_ANYEXT: 835 return true; 836 default: 837 return false; 838 } 839 }; 840 }; 841 842 /// Represents a sext. 843 class GSext : public GCastOp { 844 public: classof(const MachineInstr * MI)845 static bool classof(const MachineInstr *MI) { 846 return MI->getOpcode() == TargetOpcode::G_SEXT; 847 }; 848 }; 849 850 /// Represents a zext. 851 class GZext : public GCastOp { 852 public: classof(const MachineInstr * MI)853 static bool classof(const MachineInstr *MI) { 854 return MI->getOpcode() == TargetOpcode::G_ZEXT; 855 }; 856 }; 857 858 /// Represents a trunc. 859 class GTrunc : public GCastOp { 860 public: classof(const MachineInstr * MI)861 static bool classof(const MachineInstr *MI) { 862 return MI->getOpcode() == TargetOpcode::G_TRUNC; 863 }; 864 }; 865 866 /// Represents a vscale. 867 class GVScale : public GenericMachineInstr { 868 public: getSrc()869 APInt getSrc() const { return getOperand(1).getCImm()->getValue(); } 870 classof(const MachineInstr * MI)871 static bool classof(const MachineInstr *MI) { 872 return MI->getOpcode() == TargetOpcode::G_VSCALE; 873 }; 874 }; 875 876 /// Represents an integer subtraction. 877 class GSub : public GIntBinOp { 878 public: classof(const MachineInstr * MI)879 static bool classof(const MachineInstr *MI) { 880 return MI->getOpcode() == TargetOpcode::G_SUB; 881 }; 882 }; 883 884 /// Represents an integer multiplication. 885 class GMul : public GIntBinOp { 886 public: classof(const MachineInstr * MI)887 static bool classof(const MachineInstr *MI) { 888 return MI->getOpcode() == TargetOpcode::G_MUL; 889 }; 890 }; 891 892 /// Represents a shift left. 893 class GShl : public GenericMachineInstr { 894 public: getSrcReg()895 Register getSrcReg() const { return getOperand(1).getReg(); } getShiftReg()896 Register getShiftReg() const { return getOperand(2).getReg(); } 897 classof(const MachineInstr * MI)898 static bool classof(const MachineInstr *MI) { 899 return MI->getOpcode() == TargetOpcode::G_SHL; 900 }; 901 }; 902 903 /// Represents a threeway compare. 904 class GSUCmp : public GenericMachineInstr { 905 public: getLHSReg()906 Register getLHSReg() const { return getOperand(1).getReg(); } getRHSReg()907 Register getRHSReg() const { return getOperand(2).getReg(); } 908 isSigned()909 bool isSigned() const { return getOpcode() == TargetOpcode::G_SCMP; } 910 classof(const MachineInstr * MI)911 static bool classof(const MachineInstr *MI) { 912 switch (MI->getOpcode()) { 913 case TargetOpcode::G_SCMP: 914 case TargetOpcode::G_UCMP: 915 return true; 916 default: 917 return false; 918 } 919 }; 920 }; 921 922 } // namespace llvm 923 924 #endif // LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H 925