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 23namespace llvm { 24 25/// A base class for all GenericMachineInstrs. 26class GenericMachineInstr : public MachineInstr { 27public: 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. 40class GMemOperation : public GenericMachineInstr { 41public: 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. 68class GLoadStore : public GMemOperation { 69public: 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. 89class GIndexedLoad : public GMemOperation { 90public: 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. 109class GIndexedExtLoad : public GIndexedLoad { 110public: 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. 118class GIndexedAnyExtLoad : public GIndexedLoad { 119public: 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. 133class GIndexedZExtLoad : GIndexedExtLoad { 134public: 135 static bool classof(const MachineInstr *MI) { 136 return MI->getOpcode() == TargetOpcode::G_INDEXED_ZEXTLOAD; 137 } 138}; 139 140/// Represents a G_SEXTLOAD. 141class GIndexedSExtLoad : GIndexedExtLoad { 142public: 143 static bool classof(const MachineInstr *MI) { 144 return MI->getOpcode() == TargetOpcode::G_INDEXED_SEXTLOAD; 145 } 146}; 147 148/// Represents indexed stores. 149class GIndexedStore : public GMemOperation { 150public: 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. 169class GAnyLoad : public GLoadStore { 170public: 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. 187class GLoad : public GAnyLoad { 188public: 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. 195class GExtLoad : public GAnyLoad { 196public: 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. 204class GSExtLoad : public GExtLoad { 205public: 206 static bool classof(const MachineInstr *MI) { 207 return MI->getOpcode() == TargetOpcode::G_SEXTLOAD; 208 } 209}; 210 211/// Represents a G_ZEXTLOAD. 212class GZExtLoad : public GExtLoad { 213public: 214 static bool classof(const MachineInstr *MI) { 215 return MI->getOpcode() == TargetOpcode::G_ZEXTLOAD; 216 } 217}; 218 219/// Represents a G_STORE. 220class GStore : public GLoadStore { 221public: 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. 231class GUnmerge : public GenericMachineInstr { 232public: 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. 246class GMergeLikeInstr : public GenericMachineInstr { 247public: 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. 266class GMerge : public GMergeLikeInstr { 267public: 268 static bool classof(const MachineInstr *MI) { 269 return MI->getOpcode() == TargetOpcode::G_MERGE_VALUES; 270 } 271}; 272 273/// Represents a G_CONCAT_VECTORS. 274class GConcatVectors : public GMergeLikeInstr { 275public: 276 static bool classof(const MachineInstr *MI) { 277 return MI->getOpcode() == TargetOpcode::G_CONCAT_VECTORS; 278 } 279}; 280 281/// Represents a G_BUILD_VECTOR. 282class GBuildVector : public GMergeLikeInstr { 283public: 284 static bool classof(const MachineInstr *MI) { 285 return MI->getOpcode() == TargetOpcode::G_BUILD_VECTOR; 286 } 287}; 288 289/// Represents a G_PTR_ADD. 290class GPtrAdd : public GenericMachineInstr { 291public: 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. 301class GImplicitDef : public GenericMachineInstr { 302public: 303 static bool classof(const MachineInstr *MI) { 304 return MI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF; 305 } 306}; 307 308/// Represents a G_SELECT. 309class GSelect : public GenericMachineInstr { 310public: 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. 321class GAnyCmp : public GenericMachineInstr { 322public: 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. 336class GICmp : public GAnyCmp { 337public: 338 static bool classof(const MachineInstr *MI) { 339 return MI->getOpcode() == TargetOpcode::G_ICMP; 340 } 341}; 342 343/// Represent a G_FCMP. 344class GFCmp : public GAnyCmp { 345public: 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 356class GBinOpCarryOut : public GenericMachineInstr { 357public: 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 387class GAddSubCarryOut : public GBinOpCarryOut { 388public: 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 434class GAddSubCarryInOut : public GAddSubCarryOut { 435public: 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. 452class GIntrinsic final : public GenericMachineInstr { 453public: 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. 494class GVecReduce : public GenericMachineInstr { 495public: 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. 577class GPhi : public GenericMachineInstr { 578public: 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