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 uint64_t getMemSize() const { return getMMO().getSize(); } 58 /// Returns the size in bits of the memory access. getMemSizeInBits()59 uint64_t 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_PTR_ADD. 290 class GPtrAdd : public GenericMachineInstr { 291 public: getBaseReg()292 Register getBaseReg() const { return getReg(1); } getOffsetReg()293 Register getOffsetReg() const { return getReg(2); } 294 classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: getCondReg()311 Register getCondReg() const { return getReg(1); } getTrueReg()312 Register getTrueReg() const { return getReg(2); } getFalseReg()313 Register getFalseReg() const { return getReg(3); } 314 classof(const MachineInstr * MI)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: getCond()323 CmpInst::Predicate getCond() const { 324 return static_cast<CmpInst::Predicate>(getOperand(1).getPredicate()); 325 } getLHSReg()326 Register getLHSReg() const { return getReg(2); } getRHSReg()327 Register getRHSReg() const { return getReg(3); } 328 classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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: getDstReg()358 Register getDstReg() const { return getReg(0); } getCarryOutReg()359 Register getCarryOutReg() const { return getReg(1); } getLHS()360 MachineOperand &getLHS() { return getOperand(2); } getRHS()361 MachineOperand &getRHS() { return getOperand(3); } 362 classof(const MachineInstr * MI)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: isAdd()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 } isSub()400 bool isSub() const { return !isAdd(); } 401 isSigned()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 } isUnsigned()413 bool isUnsigned() const { return !isSigned(); } 414 classof(const MachineInstr * MI)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: getCarryInReg()436 Register getCarryInReg() const { return getReg(4); } 437 classof(const MachineInstr * MI)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: getIntrinsicID()454 Intrinsic::ID getIntrinsicID() const { 455 return getOperand(getNumExplicitDefs()).getIntrinsicID(); 456 } 457 is(Intrinsic::ID ID)458 bool is(Intrinsic::ID ID) const { return getIntrinsicID() == ID; } 459 hasSideEffects()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 isConvergent()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 classof(const MachineInstr * MI)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: classof(const MachineInstr * MI)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. getScalarOpcForReduction()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. getNumIncomingValues()580 unsigned getNumIncomingValues() const { return (getNumOperands() - 1) / 2; } 581 /// Returns the I'th incoming vreg. getIncomingValue(unsigned I)582 Register getIncomingValue(unsigned I) const { 583 return getOperand(I * 2 + 1).getReg(); 584 } 585 /// Returns the I'th incoming basic block. getIncomingBlock(unsigned I)586 MachineBasicBlock *getIncomingBlock(unsigned I) const { 587 return getOperand(I * 2 + 2).getMBB(); 588 } 589 classof(const MachineInstr * MI)590 static bool classof(const MachineInstr *MI) { 591 return MI->getOpcode() == TargetOpcode::G_PHI; 592 } 593 }; 594 595 /// Represents a binary operation, i.e, x = y op z. 596 class GBinOp : public GenericMachineInstr { 597 public: getLHSReg()598 Register getLHSReg() const { return getReg(1); } getRHSReg()599 Register getRHSReg() const { return getReg(2); } 600 classof(const MachineInstr * MI)601 static bool classof(const MachineInstr *MI) { 602 switch (MI->getOpcode()) { 603 // Integer. 604 case TargetOpcode::G_ADD: 605 case TargetOpcode::G_SUB: 606 case TargetOpcode::G_MUL: 607 case TargetOpcode::G_SDIV: 608 case TargetOpcode::G_UDIV: 609 case TargetOpcode::G_SREM: 610 case TargetOpcode::G_UREM: 611 case TargetOpcode::G_SMIN: 612 case TargetOpcode::G_SMAX: 613 case TargetOpcode::G_UMIN: 614 case TargetOpcode::G_UMAX: 615 // Floating point. 616 case TargetOpcode::G_FMINNUM: 617 case TargetOpcode::G_FMAXNUM: 618 case TargetOpcode::G_FMINNUM_IEEE: 619 case TargetOpcode::G_FMAXNUM_IEEE: 620 case TargetOpcode::G_FMINIMUM: 621 case TargetOpcode::G_FMAXIMUM: 622 case TargetOpcode::G_FADD: 623 case TargetOpcode::G_FSUB: 624 case TargetOpcode::G_FMUL: 625 case TargetOpcode::G_FDIV: 626 case TargetOpcode::G_FPOW: 627 // Logical. 628 case TargetOpcode::G_AND: 629 case TargetOpcode::G_OR: 630 case TargetOpcode::G_XOR: 631 return true; 632 default: 633 return false; 634 } 635 }; 636 }; 637 638 /// Represents an integer binary operation. 639 class GIntBinOp : public GBinOp { 640 public: classof(const MachineInstr * MI)641 static bool classof(const MachineInstr *MI) { 642 switch (MI->getOpcode()) { 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 return true; 655 default: 656 return false; 657 } 658 }; 659 }; 660 661 /// Represents a floating point binary operation. 662 class GFBinOp : public GBinOp { 663 public: classof(const MachineInstr * MI)664 static bool classof(const MachineInstr *MI) { 665 switch (MI->getOpcode()) { 666 case TargetOpcode::G_FMINNUM: 667 case TargetOpcode::G_FMAXNUM: 668 case TargetOpcode::G_FMINNUM_IEEE: 669 case TargetOpcode::G_FMAXNUM_IEEE: 670 case TargetOpcode::G_FMINIMUM: 671 case TargetOpcode::G_FMAXIMUM: 672 case TargetOpcode::G_FADD: 673 case TargetOpcode::G_FSUB: 674 case TargetOpcode::G_FMUL: 675 case TargetOpcode::G_FDIV: 676 case TargetOpcode::G_FPOW: 677 return true; 678 default: 679 return false; 680 } 681 }; 682 }; 683 684 /// Represents a logical binary operation. 685 class GLogicalBinOp : public GBinOp { 686 public: classof(const MachineInstr * MI)687 static bool classof(const MachineInstr *MI) { 688 switch (MI->getOpcode()) { 689 case TargetOpcode::G_AND: 690 case TargetOpcode::G_OR: 691 case TargetOpcode::G_XOR: 692 return true; 693 default: 694 return false; 695 } 696 }; 697 }; 698 699 /// Represents an integer addition. 700 class GAdd : public GIntBinOp { 701 public: classof(const MachineInstr * MI)702 static bool classof(const MachineInstr *MI) { 703 return MI->getOpcode() == TargetOpcode::G_ADD; 704 }; 705 }; 706 707 /// Represents a logical and. 708 class GAnd : public GLogicalBinOp { 709 public: classof(const MachineInstr * MI)710 static bool classof(const MachineInstr *MI) { 711 return MI->getOpcode() == TargetOpcode::G_AND; 712 }; 713 }; 714 715 /// Represents a logical or. 716 class GOr : public GLogicalBinOp { 717 public: classof(const MachineInstr * MI)718 static bool classof(const MachineInstr *MI) { 719 return MI->getOpcode() == TargetOpcode::G_OR; 720 }; 721 }; 722 723 } // namespace llvm 724 725 #endif // LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H 726