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. 32 Register getReg(unsigned Idx) const { return getOperand(Idx).getReg(); } 33 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. 43 MachineMemOperand &getMMO() const { return **memoperands_begin(); } 44 45 /// Returns true if the attached MachineMemOperand has the atomic flag set. 46 bool isAtomic() const { return getMMO().isAtomic(); } 47 /// Returns true if the attached MachineMemOpeand as the volatile flag set. 48 bool isVolatile() const { return getMMO().isVolatile(); } 49 /// Returns true if the memory operation is neither atomic or volatile. 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. 54 bool isUnordered() const { return getMMO().isUnordered(); } 55 56 /// Returns the size in bytes of the memory access. 57 uint64_t getMemSize() const { return getMMO().getSize(); } 58 /// Returns the size in bits of the memory access. 59 uint64_t getMemSizeInBits() const { return getMMO().getSizeInBits(); } 60 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. 71 Register getPointerReg() const { return getOperand(1).getReg(); } 72 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. 92 Register getDstReg() const { return getOperand(0).getReg(); } 93 /// Get the def register of the writeback value. 94 Register getWritebackReg() const { return getOperand(1).getReg(); } 95 /// Get the base register of the pointer value. 96 Register getBaseReg() const { return getOperand(2).getReg(); } 97 /// Get the offset register of the pointer value. 98 Register getOffsetReg() const { return getOperand(3).getReg(); } 99 100 bool isPre() const { return getOperand(4).getImm() == 1; } 101 bool isPost() const { return !isPre(); } 102 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: 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: 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: 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: 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. 152 Register getWritebackReg() const { return getOperand(0).getReg(); } 153 /// Get the stored value register. 154 Register getValueReg() const { return getOperand(1).getReg(); } 155 /// Get the base register of the pointer value. 156 Register getBaseReg() const { return getOperand(2).getReg(); } 157 /// Get the offset register of the pointer value. 158 Register getOffsetReg() const { return getOperand(3).getReg(); } 159 160 bool isPre() const { return getOperand(4).getImm() == 1; } 161 bool isPost() const { return !isPre(); } 162 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. 172 Register getDstReg() const { return getOperand(0).getReg(); } 173 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: 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: 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: 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: 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. 223 Register getValueReg() const { return getOperand(0).getReg(); } 224 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. 234 unsigned getNumDefs() const { return getNumOperands() - 1; } 235 /// Get the unmerge source register. 236 Register getSourceReg() const { return getOperand(getNumDefs()).getReg(); } 237 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. 249 unsigned getNumSources() const { return getNumOperands() - 1; } 250 /// Returns the I'th source register. 251 Register getSourceReg(unsigned I) const { return getReg(I + 1); } 252 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: 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: 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: 284 static bool classof(const MachineInstr *MI) { 285 return MI->getOpcode() == TargetOpcode::G_BUILD_VECTOR; 286 } 287 }; 288 289 /// Represents a G_PTR_ADD. 290 class GPtrAdd : public GenericMachineInstr { 291 public: 292 Register getBaseReg() const { return getReg(1); } 293 Register getOffsetReg() const { return getReg(2); } 294 295 static bool classof(const MachineInstr *MI) { 296 return MI->getOpcode() == TargetOpcode::G_PTR_ADD; 297 } 298 }; 299 300 /// Represents a G_IMPLICIT_DEF. 301 class GImplicitDef : public GenericMachineInstr { 302 public: 303 static bool classof(const MachineInstr *MI) { 304 return MI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF; 305 } 306 }; 307 308 /// Represents a G_SELECT. 309 class GSelect : public GenericMachineInstr { 310 public: 311 Register getCondReg() const { return getReg(1); } 312 Register getTrueReg() const { return getReg(2); } 313 Register getFalseReg() const { return getReg(3); } 314 315 static bool classof(const MachineInstr *MI) { 316 return MI->getOpcode() == TargetOpcode::G_SELECT; 317 } 318 }; 319 320 /// Represent a G_ICMP or G_FCMP. 321 class GAnyCmp : public GenericMachineInstr { 322 public: 323 CmpInst::Predicate getCond() const { 324 return static_cast<CmpInst::Predicate>(getOperand(1).getPredicate()); 325 } 326 Register getLHSReg() const { return getReg(2); } 327 Register getRHSReg() const { return getReg(3); } 328 329 static bool classof(const MachineInstr *MI) { 330 return MI->getOpcode() == TargetOpcode::G_ICMP || 331 MI->getOpcode() == TargetOpcode::G_FCMP; 332 } 333 }; 334 335 /// Represent a G_ICMP. 336 class GICmp : public GAnyCmp { 337 public: 338 static bool classof(const MachineInstr *MI) { 339 return MI->getOpcode() == TargetOpcode::G_ICMP; 340 } 341 }; 342 343 /// Represent a G_FCMP. 344 class GFCmp : public GAnyCmp { 345 public: 346 static bool classof(const MachineInstr *MI) { 347 return MI->getOpcode() == TargetOpcode::G_FCMP; 348 } 349 }; 350 351 /// Represents overflowing binary operations. 352 /// Only carry-out: 353 /// G_UADDO, G_SADDO, G_USUBO, G_SSUBO, G_UMULO, G_SMULO 354 /// Carry-in and carry-out: 355 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE 356 class GBinOpCarryOut : public GenericMachineInstr { 357 public: 358 Register getDstReg() const { return getReg(0); } 359 Register getCarryOutReg() const { return getReg(1); } 360 MachineOperand &getLHS() { return getOperand(2); } 361 MachineOperand &getRHS() { return getOperand(3); } 362 363 static bool classof(const MachineInstr *MI) { 364 switch (MI->getOpcode()) { 365 case TargetOpcode::G_UADDO: 366 case TargetOpcode::G_SADDO: 367 case TargetOpcode::G_USUBO: 368 case TargetOpcode::G_SSUBO: 369 case TargetOpcode::G_UADDE: 370 case TargetOpcode::G_SADDE: 371 case TargetOpcode::G_USUBE: 372 case TargetOpcode::G_SSUBE: 373 case TargetOpcode::G_UMULO: 374 case TargetOpcode::G_SMULO: 375 return true; 376 default: 377 return false; 378 } 379 } 380 }; 381 382 /// Represents overflowing add/sub operations. 383 /// Only carry-out: 384 /// G_UADDO, G_SADDO, G_USUBO, G_SSUBO 385 /// Carry-in and carry-out: 386 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE 387 class GAddSubCarryOut : public GBinOpCarryOut { 388 public: 389 bool isAdd() const { 390 switch (getOpcode()) { 391 case TargetOpcode::G_UADDO: 392 case TargetOpcode::G_SADDO: 393 case TargetOpcode::G_UADDE: 394 case TargetOpcode::G_SADDE: 395 return true; 396 default: 397 return false; 398 } 399 } 400 bool isSub() const { return !isAdd(); } 401 402 bool isSigned() const { 403 switch (getOpcode()) { 404 case TargetOpcode::G_SADDO: 405 case TargetOpcode::G_SSUBO: 406 case TargetOpcode::G_SADDE: 407 case TargetOpcode::G_SSUBE: 408 return true; 409 default: 410 return false; 411 } 412 } 413 bool isUnsigned() const { return !isSigned(); } 414 415 static bool classof(const MachineInstr *MI) { 416 switch (MI->getOpcode()) { 417 case TargetOpcode::G_UADDO: 418 case TargetOpcode::G_SADDO: 419 case TargetOpcode::G_USUBO: 420 case TargetOpcode::G_SSUBO: 421 case TargetOpcode::G_UADDE: 422 case TargetOpcode::G_SADDE: 423 case TargetOpcode::G_USUBE: 424 case TargetOpcode::G_SSUBE: 425 return true; 426 default: 427 return false; 428 } 429 } 430 }; 431 432 /// Represents overflowing add/sub operations that also consume a carry-in. 433 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE 434 class GAddSubCarryInOut : public GAddSubCarryOut { 435 public: 436 Register getCarryInReg() const { return getReg(4); } 437 438 static bool classof(const MachineInstr *MI) { 439 switch (MI->getOpcode()) { 440 case TargetOpcode::G_UADDE: 441 case TargetOpcode::G_SADDE: 442 case TargetOpcode::G_USUBE: 443 case TargetOpcode::G_SSUBE: 444 return true; 445 default: 446 return false; 447 } 448 } 449 }; 450 451 /// Represents a call to an intrinsic. 452 class GIntrinsic final : public GenericMachineInstr { 453 public: 454 Intrinsic::ID getIntrinsicID() const { 455 return getOperand(getNumExplicitDefs()).getIntrinsicID(); 456 } 457 458 bool is(Intrinsic::ID ID) const { return getIntrinsicID() == ID; } 459 460 bool hasSideEffects() const { 461 switch (getOpcode()) { 462 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: 463 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS: 464 return true; 465 default: 466 return false; 467 } 468 } 469 470 bool isConvergent() const { 471 switch (getOpcode()) { 472 case TargetOpcode::G_INTRINSIC_CONVERGENT: 473 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS: 474 return true; 475 default: 476 return false; 477 } 478 } 479 480 static bool classof(const MachineInstr *MI) { 481 switch (MI->getOpcode()) { 482 case TargetOpcode::G_INTRINSIC: 483 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS: 484 case TargetOpcode::G_INTRINSIC_CONVERGENT: 485 case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS: 486 return true; 487 default: 488 return false; 489 } 490 } 491 }; 492 493 // Represents a (non-sequential) vector reduction operation. 494 class GVecReduce : public GenericMachineInstr { 495 public: 496 static bool classof(const MachineInstr *MI) { 497 switch (MI->getOpcode()) { 498 case TargetOpcode::G_VECREDUCE_FADD: 499 case TargetOpcode::G_VECREDUCE_FMUL: 500 case TargetOpcode::G_VECREDUCE_FMAX: 501 case TargetOpcode::G_VECREDUCE_FMIN: 502 case TargetOpcode::G_VECREDUCE_FMAXIMUM: 503 case TargetOpcode::G_VECREDUCE_FMINIMUM: 504 case TargetOpcode::G_VECREDUCE_ADD: 505 case TargetOpcode::G_VECREDUCE_MUL: 506 case TargetOpcode::G_VECREDUCE_AND: 507 case TargetOpcode::G_VECREDUCE_OR: 508 case TargetOpcode::G_VECREDUCE_XOR: 509 case TargetOpcode::G_VECREDUCE_SMAX: 510 case TargetOpcode::G_VECREDUCE_SMIN: 511 case TargetOpcode::G_VECREDUCE_UMAX: 512 case TargetOpcode::G_VECREDUCE_UMIN: 513 return true; 514 default: 515 return false; 516 } 517 } 518 519 /// Get the opcode for the equivalent scalar operation for this reduction. 520 /// E.g. for G_VECREDUCE_FADD, this returns G_FADD. 521 unsigned getScalarOpcForReduction() { 522 unsigned ScalarOpc; 523 switch (getOpcode()) { 524 case TargetOpcode::G_VECREDUCE_FADD: 525 ScalarOpc = TargetOpcode::G_FADD; 526 break; 527 case TargetOpcode::G_VECREDUCE_FMUL: 528 ScalarOpc = TargetOpcode::G_FMUL; 529 break; 530 case TargetOpcode::G_VECREDUCE_FMAX: 531 ScalarOpc = TargetOpcode::G_FMAXNUM; 532 break; 533 case TargetOpcode::G_VECREDUCE_FMIN: 534 ScalarOpc = TargetOpcode::G_FMINNUM; 535 break; 536 case TargetOpcode::G_VECREDUCE_FMAXIMUM: 537 ScalarOpc = TargetOpcode::G_FMAXIMUM; 538 break; 539 case TargetOpcode::G_VECREDUCE_FMINIMUM: 540 ScalarOpc = TargetOpcode::G_FMINIMUM; 541 break; 542 case TargetOpcode::G_VECREDUCE_ADD: 543 ScalarOpc = TargetOpcode::G_ADD; 544 break; 545 case TargetOpcode::G_VECREDUCE_MUL: 546 ScalarOpc = TargetOpcode::G_MUL; 547 break; 548 case TargetOpcode::G_VECREDUCE_AND: 549 ScalarOpc = TargetOpcode::G_AND; 550 break; 551 case TargetOpcode::G_VECREDUCE_OR: 552 ScalarOpc = TargetOpcode::G_OR; 553 break; 554 case TargetOpcode::G_VECREDUCE_XOR: 555 ScalarOpc = TargetOpcode::G_XOR; 556 break; 557 case TargetOpcode::G_VECREDUCE_SMAX: 558 ScalarOpc = TargetOpcode::G_SMAX; 559 break; 560 case TargetOpcode::G_VECREDUCE_SMIN: 561 ScalarOpc = TargetOpcode::G_SMIN; 562 break; 563 case TargetOpcode::G_VECREDUCE_UMAX: 564 ScalarOpc = TargetOpcode::G_UMAX; 565 break; 566 case TargetOpcode::G_VECREDUCE_UMIN: 567 ScalarOpc = TargetOpcode::G_UMIN; 568 break; 569 default: 570 llvm_unreachable("Unhandled reduction"); 571 } 572 return ScalarOpc; 573 } 574 }; 575 576 /// Represents a G_PHI. 577 class GPhi : public GenericMachineInstr { 578 public: 579 /// Returns the number of incoming values. 580 unsigned getNumIncomingValues() const { return (getNumOperands() - 1) / 2; } 581 /// Returns the I'th incoming vreg. 582 Register getIncomingValue(unsigned I) const { 583 return getOperand(I * 2 + 1).getReg(); 584 } 585 /// Returns the I'th incoming basic block. 586 MachineBasicBlock *getIncomingBlock(unsigned I) const { 587 return getOperand(I * 2 + 2).getMBB(); 588 } 589 590 static bool classof(const MachineInstr *MI) { 591 return MI->getOpcode() == TargetOpcode::G_PHI; 592 } 593 }; 594 595 } // namespace llvm 596 597 #endif // LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H 598