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