• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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