xref: /freebsd/contrib/llvm-project/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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;
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.
getReg(unsigned Idx)38   Register getReg(unsigned Idx) const { return getOperand(Idx).getReg(); }
39 
classof(const MachineInstr * MI)40   static bool classof(const MachineInstr *MI) {
41     return isPreISelGenericOpcode(MI->getOpcode());
42   }
43 
hasPoisonGeneratingFlags()44   bool hasPoisonGeneratingFlags() const { return getFlags() & PoisonFlags; }
45 
dropPoisonGeneratingFlags()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.
getMMO()56   MachineMemOperand &getMMO() const { return **memoperands_begin(); }
57 
58   /// Returns true if the attached MachineMemOperand  has the atomic flag set.
isAtomic()59   bool isAtomic() const { return getMMO().isAtomic(); }
60   /// Returns true if the attached MachineMemOpeand as the volatile flag set.
isVolatile()61   bool isVolatile() const { return getMMO().isVolatile(); }
62   /// Returns true if the memory operation is neither atomic or volatile.
isSimple()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.
isUnordered()67   bool isUnordered() const { return getMMO().isUnordered(); }
68 
69   /// Returns the size in bytes of the memory access.
getMemSize()70   LocationSize getMemSize() const { return getMMO().getSize(); }
71   /// Returns the size in bits of the memory access.
getMemSizeInBits()72   LocationSize getMemSizeInBits() const { return getMMO().getSizeInBits(); }
73 
classof(const MachineInstr * MI)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.
getPointerReg()84   Register getPointerReg() const { return getOperand(1).getReg(); }
85 
classof(const MachineInstr * MI)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.
getDstReg()105   Register getDstReg() const { return getOperand(0).getReg(); }
106   /// Get the def register of the writeback value.
getWritebackReg()107   Register getWritebackReg() const { return getOperand(1).getReg(); }
108   /// Get the base register of the pointer value.
getBaseReg()109   Register getBaseReg() const { return getOperand(2).getReg(); }
110   /// Get the offset register of the pointer value.
getOffsetReg()111   Register getOffsetReg() const { return getOperand(3).getReg(); }
112 
isPre()113   bool isPre() const { return getOperand(4).getImm() == 1; }
isPost()114   bool isPost() const { return !isPre(); }
115 
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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.
getWritebackReg()165   Register getWritebackReg() const { return getOperand(0).getReg(); }
166   /// Get the stored value register.
getValueReg()167   Register getValueReg() const { return getOperand(1).getReg(); }
168   /// Get the base register of the pointer value.
getBaseReg()169   Register getBaseReg() const { return getOperand(2).getReg(); }
170   /// Get the offset register of the pointer value.
getOffsetReg()171   Register getOffsetReg() const { return getOperand(3).getReg(); }
172 
isPre()173   bool isPre() const { return getOperand(4).getImm() == 1; }
isPost()174   bool isPost() const { return !isPre(); }
175 
classof(const MachineInstr * MI)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.
getDstReg()185   Register getDstReg() const { return getOperand(0).getReg(); }
186 
187   /// Returns the Ranges that describes the dereference.
getRanges()188   const MDNode *getRanges() const {
189     return getMMO().getRanges();
190   }
191 
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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.
getValueReg()241   Register getValueReg() const { return getOperand(0).getReg(); }
242 
classof(const MachineInstr * MI)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.
getNumDefs()252   unsigned getNumDefs() const { return getNumOperands() - 1; }
253   /// Get the unmerge source register.
getSourceReg()254   Register getSourceReg() const { return getOperand(getNumDefs()).getReg(); }
255 
classof(const MachineInstr * MI)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.
getNumSources()267   unsigned getNumSources() const { return getNumOperands() - 1; }
268   /// Returns the I'th source register.
getSourceReg(unsigned I)269   Register getSourceReg(unsigned I) const { return getReg(I + 1); }
270 
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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:
getSrc1Reg()318   Register getSrc1Reg() const { return getOperand(1).getReg(); }
getSrc2Reg()319   Register getSrc2Reg() const { return getOperand(2).getReg(); }
getMask()320   ArrayRef<int> getMask() const { return getOperand(3).getShuffleMask(); }
321 
classof(const MachineInstr * MI)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:
getBaseReg()330   Register getBaseReg() const { return getReg(1); }
getOffsetReg()331   Register getOffsetReg() const { return getReg(2); }
332 
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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:
getCondReg()349   Register getCondReg() const { return getReg(1); }
getTrueReg()350   Register getTrueReg() const { return getReg(2); }
getFalseReg()351   Register getFalseReg() const { return getReg(3); }
352 
classof(const MachineInstr * MI)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:
getCond()361   CmpInst::Predicate getCond() const {
362     return static_cast<CmpInst::Predicate>(getOperand(1).getPredicate());
363   }
getLHSReg()364   Register getLHSReg() const { return getReg(2); }
getRHSReg()365   Register getRHSReg() const { return getReg(3); }
366 
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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:
classof(const MachineInstr * MI)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:
getDstReg()396   Register getDstReg() const { return getReg(0); }
getCarryOutReg()397   Register getCarryOutReg() const { return getReg(1); }
getLHS()398   MachineOperand &getLHS() { return getOperand(2); }
getRHS()399   MachineOperand &getRHS() { return getOperand(3); }
getLHSReg()400   Register getLHSReg() const { return getOperand(2).getReg(); }
getRHSReg()401   Register getRHSReg() const { return getOperand(3).getReg(); }
402 
classof(const MachineInstr * MI)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:
isAdd()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   }
isSub()440   bool isSub() const { return !isAdd(); }
441 
isSigned()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   }
isUnsigned()453   bool isUnsigned() const { return !isSigned(); }
454 
classof(const MachineInstr * MI)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:
isSigned()476   bool isSigned() const { return getOpcode() == TargetOpcode::G_SADDO; }
477 
classof(const MachineInstr * MI)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 add/sub operations that also consume a carry-in.
490 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE
491 class GAddSubCarryInOut : public GAddSubCarryOut {
492 public:
getCarryInReg()493   Register getCarryInReg() const { return getReg(4); }
494 
classof(const MachineInstr * MI)495   static bool classof(const MachineInstr *MI) {
496     switch (MI->getOpcode()) {
497     case TargetOpcode::G_UADDE:
498     case TargetOpcode::G_SADDE:
499     case TargetOpcode::G_USUBE:
500     case TargetOpcode::G_SSUBE:
501       return true;
502     default:
503       return false;
504     }
505   }
506 };
507 
508 /// Represents a call to an intrinsic.
509 class GIntrinsic final : public GenericMachineInstr {
510 public:
getIntrinsicID()511   Intrinsic::ID getIntrinsicID() const {
512     return getOperand(getNumExplicitDefs()).getIntrinsicID();
513   }
514 
is(Intrinsic::ID ID)515   bool is(Intrinsic::ID ID) const { return getIntrinsicID() == ID; }
516 
hasSideEffects()517   bool hasSideEffects() const {
518     switch (getOpcode()) {
519     case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
520     case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
521       return true;
522     default:
523       return false;
524     }
525   }
526 
isConvergent()527   bool isConvergent() const {
528     switch (getOpcode()) {
529     case TargetOpcode::G_INTRINSIC_CONVERGENT:
530     case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
531       return true;
532     default:
533       return false;
534     }
535   }
536 
classof(const MachineInstr * MI)537   static bool classof(const MachineInstr *MI) {
538     switch (MI->getOpcode()) {
539     case TargetOpcode::G_INTRINSIC:
540     case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
541     case TargetOpcode::G_INTRINSIC_CONVERGENT:
542     case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
543       return true;
544     default:
545       return false;
546     }
547   }
548 };
549 
550 // Represents a (non-sequential) vector reduction operation.
551 class GVecReduce : public GenericMachineInstr {
552 public:
classof(const MachineInstr * MI)553   static bool classof(const MachineInstr *MI) {
554     switch (MI->getOpcode()) {
555     case TargetOpcode::G_VECREDUCE_FADD:
556     case TargetOpcode::G_VECREDUCE_FMUL:
557     case TargetOpcode::G_VECREDUCE_FMAX:
558     case TargetOpcode::G_VECREDUCE_FMIN:
559     case TargetOpcode::G_VECREDUCE_FMAXIMUM:
560     case TargetOpcode::G_VECREDUCE_FMINIMUM:
561     case TargetOpcode::G_VECREDUCE_ADD:
562     case TargetOpcode::G_VECREDUCE_MUL:
563     case TargetOpcode::G_VECREDUCE_AND:
564     case TargetOpcode::G_VECREDUCE_OR:
565     case TargetOpcode::G_VECREDUCE_XOR:
566     case TargetOpcode::G_VECREDUCE_SMAX:
567     case TargetOpcode::G_VECREDUCE_SMIN:
568     case TargetOpcode::G_VECREDUCE_UMAX:
569     case TargetOpcode::G_VECREDUCE_UMIN:
570       return true;
571     default:
572       return false;
573     }
574   }
575 
576   /// Get the opcode for the equivalent scalar operation for this reduction.
577   /// E.g. for G_VECREDUCE_FADD, this returns G_FADD.
getScalarOpcForReduction()578   unsigned getScalarOpcForReduction() {
579     unsigned ScalarOpc;
580     switch (getOpcode()) {
581     case TargetOpcode::G_VECREDUCE_FADD:
582       ScalarOpc = TargetOpcode::G_FADD;
583       break;
584     case TargetOpcode::G_VECREDUCE_FMUL:
585       ScalarOpc = TargetOpcode::G_FMUL;
586       break;
587     case TargetOpcode::G_VECREDUCE_FMAX:
588       ScalarOpc = TargetOpcode::G_FMAXNUM;
589       break;
590     case TargetOpcode::G_VECREDUCE_FMIN:
591       ScalarOpc = TargetOpcode::G_FMINNUM;
592       break;
593     case TargetOpcode::G_VECREDUCE_FMAXIMUM:
594       ScalarOpc = TargetOpcode::G_FMAXIMUM;
595       break;
596     case TargetOpcode::G_VECREDUCE_FMINIMUM:
597       ScalarOpc = TargetOpcode::G_FMINIMUM;
598       break;
599     case TargetOpcode::G_VECREDUCE_ADD:
600       ScalarOpc = TargetOpcode::G_ADD;
601       break;
602     case TargetOpcode::G_VECREDUCE_MUL:
603       ScalarOpc = TargetOpcode::G_MUL;
604       break;
605     case TargetOpcode::G_VECREDUCE_AND:
606       ScalarOpc = TargetOpcode::G_AND;
607       break;
608     case TargetOpcode::G_VECREDUCE_OR:
609       ScalarOpc = TargetOpcode::G_OR;
610       break;
611     case TargetOpcode::G_VECREDUCE_XOR:
612       ScalarOpc = TargetOpcode::G_XOR;
613       break;
614     case TargetOpcode::G_VECREDUCE_SMAX:
615       ScalarOpc = TargetOpcode::G_SMAX;
616       break;
617     case TargetOpcode::G_VECREDUCE_SMIN:
618       ScalarOpc = TargetOpcode::G_SMIN;
619       break;
620     case TargetOpcode::G_VECREDUCE_UMAX:
621       ScalarOpc = TargetOpcode::G_UMAX;
622       break;
623     case TargetOpcode::G_VECREDUCE_UMIN:
624       ScalarOpc = TargetOpcode::G_UMIN;
625       break;
626     default:
627       llvm_unreachable("Unhandled reduction");
628     }
629     return ScalarOpc;
630   }
631 };
632 
633 /// Represents a G_PHI.
634 class GPhi : public GenericMachineInstr {
635 public:
636   /// Returns the number of incoming values.
getNumIncomingValues()637   unsigned getNumIncomingValues() const { return (getNumOperands() - 1) / 2; }
638   /// Returns the I'th incoming vreg.
getIncomingValue(unsigned I)639   Register getIncomingValue(unsigned I) const {
640     return getOperand(I * 2 + 1).getReg();
641   }
642   /// Returns the I'th incoming basic block.
getIncomingBlock(unsigned I)643   MachineBasicBlock *getIncomingBlock(unsigned I) const {
644     return getOperand(I * 2 + 2).getMBB();
645   }
646 
classof(const MachineInstr * MI)647   static bool classof(const MachineInstr *MI) {
648     return MI->getOpcode() == TargetOpcode::G_PHI;
649   }
650 };
651 
652 /// Represents a binary operation, i.e, x = y op z.
653 class GBinOp : public GenericMachineInstr {
654 public:
getLHSReg()655   Register getLHSReg() const { return getReg(1); }
getRHSReg()656   Register getRHSReg() const { return getReg(2); }
657 
classof(const MachineInstr * MI)658   static bool classof(const MachineInstr *MI) {
659     switch (MI->getOpcode()) {
660     // Integer.
661     case TargetOpcode::G_ADD:
662     case TargetOpcode::G_SUB:
663     case TargetOpcode::G_MUL:
664     case TargetOpcode::G_SDIV:
665     case TargetOpcode::G_UDIV:
666     case TargetOpcode::G_SREM:
667     case TargetOpcode::G_UREM:
668     case TargetOpcode::G_SMIN:
669     case TargetOpcode::G_SMAX:
670     case TargetOpcode::G_UMIN:
671     case TargetOpcode::G_UMAX:
672     // Floating point.
673     case TargetOpcode::G_FMINNUM:
674     case TargetOpcode::G_FMAXNUM:
675     case TargetOpcode::G_FMINNUM_IEEE:
676     case TargetOpcode::G_FMAXNUM_IEEE:
677     case TargetOpcode::G_FMINIMUM:
678     case TargetOpcode::G_FMAXIMUM:
679     case TargetOpcode::G_FADD:
680     case TargetOpcode::G_FSUB:
681     case TargetOpcode::G_FMUL:
682     case TargetOpcode::G_FDIV:
683     case TargetOpcode::G_FPOW:
684     // Logical.
685     case TargetOpcode::G_AND:
686     case TargetOpcode::G_OR:
687     case TargetOpcode::G_XOR:
688       return true;
689     default:
690       return false;
691     }
692   };
693 };
694 
695 /// Represents an integer binary operation.
696 class GIntBinOp : public GBinOp {
697 public:
classof(const MachineInstr * MI)698   static bool classof(const MachineInstr *MI) {
699     switch (MI->getOpcode()) {
700     case TargetOpcode::G_ADD:
701     case TargetOpcode::G_SUB:
702     case TargetOpcode::G_MUL:
703     case TargetOpcode::G_SDIV:
704     case TargetOpcode::G_UDIV:
705     case TargetOpcode::G_SREM:
706     case TargetOpcode::G_UREM:
707     case TargetOpcode::G_SMIN:
708     case TargetOpcode::G_SMAX:
709     case TargetOpcode::G_UMIN:
710     case TargetOpcode::G_UMAX:
711       return true;
712     default:
713       return false;
714     }
715   };
716 };
717 
718 /// Represents a floating point binary operation.
719 class GFBinOp : public GBinOp {
720 public:
classof(const MachineInstr * MI)721   static bool classof(const MachineInstr *MI) {
722     switch (MI->getOpcode()) {
723     case TargetOpcode::G_FMINNUM:
724     case TargetOpcode::G_FMAXNUM:
725     case TargetOpcode::G_FMINNUM_IEEE:
726     case TargetOpcode::G_FMAXNUM_IEEE:
727     case TargetOpcode::G_FMINIMUM:
728     case TargetOpcode::G_FMAXIMUM:
729     case TargetOpcode::G_FADD:
730     case TargetOpcode::G_FSUB:
731     case TargetOpcode::G_FMUL:
732     case TargetOpcode::G_FDIV:
733     case TargetOpcode::G_FPOW:
734       return true;
735     default:
736       return false;
737     }
738   };
739 };
740 
741 /// Represents a logical binary operation.
742 class GLogicalBinOp : public GBinOp {
743 public:
classof(const MachineInstr * MI)744   static bool classof(const MachineInstr *MI) {
745     switch (MI->getOpcode()) {
746     case TargetOpcode::G_AND:
747     case TargetOpcode::G_OR:
748     case TargetOpcode::G_XOR:
749       return true;
750     default:
751       return false;
752     }
753   };
754 };
755 
756 /// Represents an integer addition.
757 class GAdd : public GIntBinOp {
758 public:
classof(const MachineInstr * MI)759   static bool classof(const MachineInstr *MI) {
760     return MI->getOpcode() == TargetOpcode::G_ADD;
761   };
762 };
763 
764 /// Represents a logical and.
765 class GAnd : public GLogicalBinOp {
766 public:
classof(const MachineInstr * MI)767   static bool classof(const MachineInstr *MI) {
768     return MI->getOpcode() == TargetOpcode::G_AND;
769   };
770 };
771 
772 /// Represents a logical or.
773 class GOr : public GLogicalBinOp {
774 public:
classof(const MachineInstr * MI)775   static bool classof(const MachineInstr *MI) {
776     return MI->getOpcode() == TargetOpcode::G_OR;
777   };
778 };
779 
780 /// Represents an extract vector element.
781 class GExtractVectorElement : public GenericMachineInstr {
782 public:
getVectorReg()783   Register getVectorReg() const { return getOperand(1).getReg(); }
getIndexReg()784   Register getIndexReg() const { return getOperand(2).getReg(); }
785 
classof(const MachineInstr * MI)786   static bool classof(const MachineInstr *MI) {
787     return MI->getOpcode() == TargetOpcode::G_EXTRACT_VECTOR_ELT;
788   }
789 };
790 
791 /// Represents an insert vector element.
792 class GInsertVectorElement : public GenericMachineInstr {
793 public:
getVectorReg()794   Register getVectorReg() const { return getOperand(1).getReg(); }
getElementReg()795   Register getElementReg() const { return getOperand(2).getReg(); }
getIndexReg()796   Register getIndexReg() const { return getOperand(3).getReg(); }
797 
classof(const MachineInstr * MI)798   static bool classof(const MachineInstr *MI) {
799     return MI->getOpcode() == TargetOpcode::G_INSERT_VECTOR_ELT;
800   }
801 };
802 
803 /// Represents a freeze.
804 class GFreeze : public GenericMachineInstr {
805 public:
getSourceReg()806   Register getSourceReg() const { return getOperand(1).getReg(); }
807 
classof(const MachineInstr * MI)808   static bool classof(const MachineInstr *MI) {
809     return MI->getOpcode() == TargetOpcode::G_FREEZE;
810   }
811 };
812 
813 /// Represents a cast operation.
814 /// It models the llvm::CastInst concept.
815 /// The exception is bitcast.
816 class GCastOp : public GenericMachineInstr {
817 public:
getSrcReg()818   Register getSrcReg() const { return getOperand(1).getReg(); }
819 
classof(const MachineInstr * MI)820   static bool classof(const MachineInstr *MI) {
821     switch (MI->getOpcode()) {
822     case TargetOpcode::G_ADDRSPACE_CAST:
823     case TargetOpcode::G_FPEXT:
824     case TargetOpcode::G_FPTOSI:
825     case TargetOpcode::G_FPTOUI:
826     case TargetOpcode::G_FPTRUNC:
827     case TargetOpcode::G_INTTOPTR:
828     case TargetOpcode::G_PTRTOINT:
829     case TargetOpcode::G_SEXT:
830     case TargetOpcode::G_SITOFP:
831     case TargetOpcode::G_TRUNC:
832     case TargetOpcode::G_UITOFP:
833     case TargetOpcode::G_ZEXT:
834     case TargetOpcode::G_ANYEXT:
835       return true;
836     default:
837       return false;
838     }
839   };
840 };
841 
842 /// Represents a sext.
843 class GSext : public GCastOp {
844 public:
classof(const MachineInstr * MI)845   static bool classof(const MachineInstr *MI) {
846     return MI->getOpcode() == TargetOpcode::G_SEXT;
847   };
848 };
849 
850 /// Represents a zext.
851 class GZext : public GCastOp {
852 public:
classof(const MachineInstr * MI)853   static bool classof(const MachineInstr *MI) {
854     return MI->getOpcode() == TargetOpcode::G_ZEXT;
855   };
856 };
857 
858 /// Represents a trunc.
859 class GTrunc : public GCastOp {
860 public:
classof(const MachineInstr * MI)861   static bool classof(const MachineInstr *MI) {
862     return MI->getOpcode() == TargetOpcode::G_TRUNC;
863   };
864 };
865 
866 /// Represents a vscale.
867 class GVScale : public GenericMachineInstr {
868 public:
getSrc()869   APInt getSrc() const { return getOperand(1).getCImm()->getValue(); }
870 
classof(const MachineInstr * MI)871   static bool classof(const MachineInstr *MI) {
872     return MI->getOpcode() == TargetOpcode::G_VSCALE;
873   };
874 };
875 
876 /// Represents an integer subtraction.
877 class GSub : public GIntBinOp {
878 public:
classof(const MachineInstr * MI)879   static bool classof(const MachineInstr *MI) {
880     return MI->getOpcode() == TargetOpcode::G_SUB;
881   };
882 };
883 
884 /// Represents an integer multiplication.
885 class GMul : public GIntBinOp {
886 public:
classof(const MachineInstr * MI)887   static bool classof(const MachineInstr *MI) {
888     return MI->getOpcode() == TargetOpcode::G_MUL;
889   };
890 };
891 
892 /// Represents a shift left.
893 class GShl : public GenericMachineInstr {
894 public:
getSrcReg()895   Register getSrcReg() const { return getOperand(1).getReg(); }
getShiftReg()896   Register getShiftReg() const { return getOperand(2).getReg(); }
897 
classof(const MachineInstr * MI)898   static bool classof(const MachineInstr *MI) {
899     return MI->getOpcode() == TargetOpcode::G_SHL;
900   };
901 };
902 
903 /// Represents a threeway compare.
904 class GSUCmp : public GenericMachineInstr {
905 public:
getLHSReg()906   Register getLHSReg() const { return getOperand(1).getReg(); }
getRHSReg()907   Register getRHSReg() const { return getOperand(2).getReg(); }
908 
isSigned()909   bool isSigned() const { return getOpcode() == TargetOpcode::G_SCMP; }
910 
classof(const MachineInstr * MI)911   static bool classof(const MachineInstr *MI) {
912     switch (MI->getOpcode()) {
913     case TargetOpcode::G_SCMP:
914     case TargetOpcode::G_UCMP:
915       return true;
916     default:
917       return false;
918     }
919   };
920 };
921 
922 } // namespace llvm
923 
924 #endif // LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H
925