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