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