• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- llvm/CodeGen/GlobalISel/GenericMachineInstrs.h -----------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 /// \file
9 /// Declares convenience wrapper classes for interpreting MachineInstr instances
10 /// as specific generic operations.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H
15 #define LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H
16 
17 #include "llvm/IR/Instructions.h"
18 #include "llvm/CodeGen/MachineInstr.h"
19 #include "llvm/CodeGen/MachineMemOperand.h"
20 #include "llvm/CodeGen/TargetOpcodes.h"
21 #include "llvm/Support/Casting.h"
22 
23 namespace llvm {
24 
25 /// A base class for all GenericMachineInstrs.
26 class GenericMachineInstr : public MachineInstr {
27 public:
28   GenericMachineInstr() = delete;
29 
30   /// Access the Idx'th operand as a register and return it.
31   /// This assumes that the Idx'th operand is a Register type.
getReg(unsigned Idx)32   Register getReg(unsigned Idx) const { return getOperand(Idx).getReg(); }
33 
classof(const MachineInstr * MI)34   static bool classof(const MachineInstr *MI) {
35     return isPreISelGenericOpcode(MI->getOpcode());
36   }
37 };
38 
39 /// Provides common memory operand functionality.
40 class GMemOperation : public GenericMachineInstr {
41 public:
42   /// Get the MachineMemOperand on this instruction.
getMMO()43   MachineMemOperand &getMMO() const { return **memoperands_begin(); }
44 
45   /// Returns true if the attached MachineMemOperand  has the atomic flag set.
isAtomic()46   bool isAtomic() const { return getMMO().isAtomic(); }
47   /// Returns true if the attached MachineMemOpeand as the volatile flag set.
isVolatile()48   bool isVolatile() const { return getMMO().isVolatile(); }
49   /// Returns true if the memory operation is neither atomic or volatile.
isSimple()50   bool isSimple() const { return !isAtomic() && !isVolatile(); }
51   /// Returns true if this memory operation doesn't have any ordering
52   /// constraints other than normal aliasing. Volatile and (ordered) atomic
53   /// memory operations can't be reordered.
isUnordered()54   bool isUnordered() const { return getMMO().isUnordered(); }
55 
56   /// Returns the size in bytes of the memory access.
getMemSize()57   uint64_t getMemSize() const { return getMMO().getSize(); }
58   /// Returns the size in bits of the memory access.
getMemSizeInBits()59   uint64_t getMemSizeInBits() const { return getMMO().getSizeInBits(); }
60 
classof(const MachineInstr * MI)61   static bool classof(const MachineInstr *MI) {
62     return GenericMachineInstr::classof(MI) && MI->hasOneMemOperand();
63   }
64 };
65 
66 /// Represents any type of generic load or store.
67 /// G_LOAD, G_STORE, G_ZEXTLOAD, G_SEXTLOAD.
68 class GLoadStore : public GMemOperation {
69 public:
70   /// Get the source register of the pointer value.
getPointerReg()71   Register getPointerReg() const { return getOperand(1).getReg(); }
72 
classof(const MachineInstr * MI)73   static bool classof(const MachineInstr *MI) {
74     switch (MI->getOpcode()) {
75     case TargetOpcode::G_LOAD:
76     case TargetOpcode::G_STORE:
77     case TargetOpcode::G_ZEXTLOAD:
78     case TargetOpcode::G_SEXTLOAD:
79       return true;
80     default:
81       return false;
82     }
83   }
84 };
85 
86 /// Represents indexed loads. These are different enough from regular loads
87 /// that they get their own class. Including them in GAnyLoad would probably
88 /// make a footgun for someone.
89 class GIndexedLoad : public GMemOperation {
90 public:
91   /// Get the definition register of the loaded value.
getDstReg()92   Register getDstReg() const { return getOperand(0).getReg(); }
93   /// Get the def register of the writeback value.
getWritebackReg()94   Register getWritebackReg() const { return getOperand(1).getReg(); }
95   /// Get the base register of the pointer value.
getBaseReg()96   Register getBaseReg() const { return getOperand(2).getReg(); }
97   /// Get the offset register of the pointer value.
getOffsetReg()98   Register getOffsetReg() const { return getOperand(3).getReg(); }
99 
isPre()100   bool isPre() const { return getOperand(4).getImm() == 1; }
isPost()101   bool isPost() const { return !isPre(); }
102 
classof(const MachineInstr * MI)103   static bool classof(const MachineInstr *MI) {
104     return MI->getOpcode() == TargetOpcode::G_INDEXED_LOAD;
105   }
106 };
107 
108 /// Represents a G_INDEX_ZEXTLOAD/G_INDEXED_SEXTLOAD.
109 class GIndexedExtLoad : public GIndexedLoad {
110 public:
classof(const MachineInstr * MI)111   static bool classof(const MachineInstr *MI) {
112     return MI->getOpcode() == TargetOpcode::G_INDEXED_SEXTLOAD ||
113            MI->getOpcode() == TargetOpcode::G_INDEXED_ZEXTLOAD;
114   }
115 };
116 
117 /// Represents a G_ZEXTLOAD.
118 class GIndexedZExtLoad : GIndexedExtLoad {
119 public:
classof(const MachineInstr * MI)120   static bool classof(const MachineInstr *MI) {
121     return MI->getOpcode() == TargetOpcode::G_INDEXED_ZEXTLOAD;
122   }
123 };
124 
125 /// Represents a G_SEXTLOAD.
126 class GIndexedSExtLoad : GIndexedExtLoad {
127 public:
classof(const MachineInstr * MI)128   static bool classof(const MachineInstr *MI) {
129     return MI->getOpcode() == TargetOpcode::G_INDEXED_SEXTLOAD;
130   }
131 };
132 
133 /// Represents indexed stores.
134 class GIndexedStore : public GMemOperation {
135 public:
136   /// Get the def register of the writeback value.
getWritebackReg()137   Register getWritebackReg() const { return getOperand(0).getReg(); }
138   /// Get the stored value register.
getValueReg()139   Register getValueReg() const { return getOperand(1).getReg(); }
140   /// Get the base register of the pointer value.
getBaseReg()141   Register getBaseReg() const { return getOperand(2).getReg(); }
142   /// Get the offset register of the pointer value.
getOffsetReg()143   Register getOffsetReg() const { return getOperand(3).getReg(); }
144 
isPre()145   bool isPre() const { return getOperand(4).getImm() == 1; }
isPost()146   bool isPost() const { return !isPre(); }
147 
classof(const MachineInstr * MI)148   static bool classof(const MachineInstr *MI) {
149     return MI->getOpcode() == TargetOpcode::G_INDEXED_STORE;
150   }
151 };
152 
153 /// Represents any generic load, including sign/zero extending variants.
154 class GAnyLoad : public GLoadStore {
155 public:
156   /// Get the definition register of the loaded value.
getDstReg()157   Register getDstReg() const { return getOperand(0).getReg(); }
158 
classof(const MachineInstr * MI)159   static bool classof(const MachineInstr *MI) {
160     switch (MI->getOpcode()) {
161     case TargetOpcode::G_LOAD:
162     case TargetOpcode::G_ZEXTLOAD:
163     case TargetOpcode::G_SEXTLOAD:
164       return true;
165     default:
166       return false;
167     }
168   }
169 };
170 
171 /// Represents a G_LOAD.
172 class GLoad : public GAnyLoad {
173 public:
classof(const MachineInstr * MI)174   static bool classof(const MachineInstr *MI) {
175     return MI->getOpcode() == TargetOpcode::G_LOAD;
176   }
177 };
178 
179 /// Represents either a G_SEXTLOAD or G_ZEXTLOAD.
180 class GExtLoad : public GAnyLoad {
181 public:
classof(const MachineInstr * MI)182   static bool classof(const MachineInstr *MI) {
183     return MI->getOpcode() == TargetOpcode::G_SEXTLOAD ||
184            MI->getOpcode() == TargetOpcode::G_ZEXTLOAD;
185   }
186 };
187 
188 /// Represents a G_SEXTLOAD.
189 class GSExtLoad : public GExtLoad {
190 public:
classof(const MachineInstr * MI)191   static bool classof(const MachineInstr *MI) {
192     return MI->getOpcode() == TargetOpcode::G_SEXTLOAD;
193   }
194 };
195 
196 /// Represents a G_ZEXTLOAD.
197 class GZExtLoad : public GExtLoad {
198 public:
classof(const MachineInstr * MI)199   static bool classof(const MachineInstr *MI) {
200     return MI->getOpcode() == TargetOpcode::G_ZEXTLOAD;
201   }
202 };
203 
204 /// Represents a G_STORE.
205 class GStore : public GLoadStore {
206 public:
207   /// Get the stored value register.
getValueReg()208   Register getValueReg() const { return getOperand(0).getReg(); }
209 
classof(const MachineInstr * MI)210   static bool classof(const MachineInstr *MI) {
211     return MI->getOpcode() == TargetOpcode::G_STORE;
212   }
213 };
214 
215 /// Represents a G_UNMERGE_VALUES.
216 class GUnmerge : public GenericMachineInstr {
217 public:
218   /// Returns the number of def registers.
getNumDefs()219   unsigned getNumDefs() const { return getNumOperands() - 1; }
220   /// Get the unmerge source register.
getSourceReg()221   Register getSourceReg() const { return getOperand(getNumDefs()).getReg(); }
222 
classof(const MachineInstr * MI)223   static bool classof(const MachineInstr *MI) {
224     return MI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES;
225   }
226 };
227 
228 /// Represents G_BUILD_VECTOR, G_CONCAT_VECTORS or G_MERGE_VALUES.
229 /// All these have the common property of generating a single value from
230 /// multiple sources.
231 class GMergeLikeInstr : public GenericMachineInstr {
232 public:
233   /// Returns the number of source registers.
getNumSources()234   unsigned getNumSources() const { return getNumOperands() - 1; }
235   /// Returns the I'th source register.
getSourceReg(unsigned I)236   Register getSourceReg(unsigned I) const { return getReg(I + 1); }
237 
classof(const MachineInstr * MI)238   static bool classof(const MachineInstr *MI) {
239     switch (MI->getOpcode()) {
240     case TargetOpcode::G_MERGE_VALUES:
241     case TargetOpcode::G_CONCAT_VECTORS:
242     case TargetOpcode::G_BUILD_VECTOR:
243       return true;
244     default:
245       return false;
246     }
247   }
248 };
249 
250 /// Represents a G_MERGE_VALUES.
251 class GMerge : public GMergeLikeInstr {
252 public:
classof(const MachineInstr * MI)253   static bool classof(const MachineInstr *MI) {
254     return MI->getOpcode() == TargetOpcode::G_MERGE_VALUES;
255   }
256 };
257 
258 /// Represents a G_CONCAT_VECTORS.
259 class GConcatVectors : public GMergeLikeInstr {
260 public:
classof(const MachineInstr * MI)261   static bool classof(const MachineInstr *MI) {
262     return MI->getOpcode() == TargetOpcode::G_CONCAT_VECTORS;
263   }
264 };
265 
266 /// Represents a G_BUILD_VECTOR.
267 class GBuildVector : public GMergeLikeInstr {
268 public:
classof(const MachineInstr * MI)269   static bool classof(const MachineInstr *MI) {
270     return MI->getOpcode() == TargetOpcode::G_BUILD_VECTOR;
271   }
272 };
273 
274 /// Represents a G_PTR_ADD.
275 class GPtrAdd : public GenericMachineInstr {
276 public:
getBaseReg()277   Register getBaseReg() const { return getReg(1); }
getOffsetReg()278   Register getOffsetReg() const { return getReg(2); }
279 
classof(const MachineInstr * MI)280   static bool classof(const MachineInstr *MI) {
281     return MI->getOpcode() == TargetOpcode::G_PTR_ADD;
282   }
283 };
284 
285 /// Represents a G_IMPLICIT_DEF.
286 class GImplicitDef : public GenericMachineInstr {
287 public:
classof(const MachineInstr * MI)288   static bool classof(const MachineInstr *MI) {
289     return MI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF;
290   }
291 };
292 
293 /// Represents a G_SELECT.
294 class GSelect : public GenericMachineInstr {
295 public:
getCondReg()296   Register getCondReg() const { return getReg(1); }
getTrueReg()297   Register getTrueReg() const { return getReg(2); }
getFalseReg()298   Register getFalseReg() const { return getReg(3); }
299 
classof(const MachineInstr * MI)300   static bool classof(const MachineInstr *MI) {
301     return MI->getOpcode() == TargetOpcode::G_SELECT;
302   }
303 };
304 
305 /// Represent a G_ICMP or G_FCMP.
306 class GAnyCmp : public GenericMachineInstr {
307 public:
getCond()308   CmpInst::Predicate getCond() const {
309     return static_cast<CmpInst::Predicate>(getOperand(1).getPredicate());
310   }
getLHSReg()311   Register getLHSReg() const { return getReg(2); }
getRHSReg()312   Register getRHSReg() const { return getReg(3); }
313 
classof(const MachineInstr * MI)314   static bool classof(const MachineInstr *MI) {
315     return MI->getOpcode() == TargetOpcode::G_ICMP ||
316            MI->getOpcode() == TargetOpcode::G_FCMP;
317   }
318 };
319 
320 /// Represent a G_ICMP.
321 class GICmp : public GAnyCmp {
322 public:
classof(const MachineInstr * MI)323   static bool classof(const MachineInstr *MI) {
324     return MI->getOpcode() == TargetOpcode::G_ICMP;
325   }
326 };
327 
328 /// Represent a G_FCMP.
329 class GFCmp : public GAnyCmp {
330 public:
classof(const MachineInstr * MI)331   static bool classof(const MachineInstr *MI) {
332     return MI->getOpcode() == TargetOpcode::G_FCMP;
333   }
334 };
335 
336 /// Represents overflowing binary operations.
337 /// Only carry-out:
338 /// G_UADDO, G_SADDO, G_USUBO, G_SSUBO, G_UMULO, G_SMULO
339 /// Carry-in and carry-out:
340 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE
341 class GBinOpCarryOut : public GenericMachineInstr {
342 public:
getDstReg()343   Register getDstReg() const { return getReg(0); }
getCarryOutReg()344   Register getCarryOutReg() const { return getReg(1); }
getLHS()345   MachineOperand &getLHS() { return getOperand(2); }
getRHS()346   MachineOperand &getRHS() { return getOperand(3); }
347 
classof(const MachineInstr * MI)348   static bool classof(const MachineInstr *MI) {
349     switch (MI->getOpcode()) {
350     case TargetOpcode::G_UADDO:
351     case TargetOpcode::G_SADDO:
352     case TargetOpcode::G_USUBO:
353     case TargetOpcode::G_SSUBO:
354     case TargetOpcode::G_UADDE:
355     case TargetOpcode::G_SADDE:
356     case TargetOpcode::G_USUBE:
357     case TargetOpcode::G_SSUBE:
358     case TargetOpcode::G_UMULO:
359     case TargetOpcode::G_SMULO:
360       return true;
361     default:
362       return false;
363     }
364   }
365 };
366 
367 /// Represents overflowing add/sub operations.
368 /// Only carry-out:
369 /// G_UADDO, G_SADDO, G_USUBO, G_SSUBO
370 /// Carry-in and carry-out:
371 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE
372 class GAddSubCarryOut : public GBinOpCarryOut {
373 public:
isAdd()374   bool isAdd() const {
375     switch (getOpcode()) {
376     case TargetOpcode::G_UADDO:
377     case TargetOpcode::G_SADDO:
378     case TargetOpcode::G_UADDE:
379     case TargetOpcode::G_SADDE:
380       return true;
381     default:
382       return false;
383     }
384   }
isSub()385   bool isSub() const { return !isAdd(); }
386 
isSigned()387   bool isSigned() const {
388     switch (getOpcode()) {
389     case TargetOpcode::G_SADDO:
390     case TargetOpcode::G_SSUBO:
391     case TargetOpcode::G_SADDE:
392     case TargetOpcode::G_SSUBE:
393       return true;
394     default:
395       return false;
396     }
397   }
isUnsigned()398   bool isUnsigned() const { return !isSigned(); }
399 
classof(const MachineInstr * MI)400   static bool classof(const MachineInstr *MI) {
401     switch (MI->getOpcode()) {
402     case TargetOpcode::G_UADDO:
403     case TargetOpcode::G_SADDO:
404     case TargetOpcode::G_USUBO:
405     case TargetOpcode::G_SSUBO:
406     case TargetOpcode::G_UADDE:
407     case TargetOpcode::G_SADDE:
408     case TargetOpcode::G_USUBE:
409     case TargetOpcode::G_SSUBE:
410       return true;
411     default:
412       return false;
413     }
414   }
415 };
416 
417 /// Represents overflowing add/sub operations that also consume a carry-in.
418 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE
419 class GAddSubCarryInOut : public GAddSubCarryOut {
420 public:
getCarryInReg()421   Register getCarryInReg() const { return getReg(4); }
422 
classof(const MachineInstr * MI)423   static bool classof(const MachineInstr *MI) {
424     switch (MI->getOpcode()) {
425     case TargetOpcode::G_UADDE:
426     case TargetOpcode::G_SADDE:
427     case TargetOpcode::G_USUBE:
428     case TargetOpcode::G_SSUBE:
429       return true;
430     default:
431       return false;
432     }
433   }
434 };
435 
436 /// Represents a call to an intrinsic.
437 class GIntrinsic final : public GenericMachineInstr {
438 public:
getIntrinsicID()439   Intrinsic::ID getIntrinsicID() const {
440     return getOperand(getNumExplicitDefs()).getIntrinsicID();
441   }
442 
is(Intrinsic::ID ID)443   bool is(Intrinsic::ID ID) const { return getIntrinsicID() == ID; }
444 
hasSideEffects()445   bool hasSideEffects() const {
446     switch (getOpcode()) {
447     case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
448     case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
449       return true;
450     default:
451       return false;
452     }
453   }
454 
isConvergent()455   bool isConvergent() const {
456     switch (getOpcode()) {
457     case TargetOpcode::G_INTRINSIC_CONVERGENT:
458     case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
459       return true;
460     default:
461       return false;
462     }
463   }
464 
classof(const MachineInstr * MI)465   static bool classof(const MachineInstr *MI) {
466     switch (MI->getOpcode()) {
467     case TargetOpcode::G_INTRINSIC:
468     case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
469     case TargetOpcode::G_INTRINSIC_CONVERGENT:
470     case TargetOpcode::G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS:
471       return true;
472     default:
473       return false;
474     }
475   }
476 };
477 
478 // Represents a (non-sequential) vector reduction operation.
479 class GVecReduce : public GenericMachineInstr {
480 public:
classof(const MachineInstr * MI)481   static bool classof(const MachineInstr *MI) {
482     switch (MI->getOpcode()) {
483     case TargetOpcode::G_VECREDUCE_FADD:
484     case TargetOpcode::G_VECREDUCE_FMUL:
485     case TargetOpcode::G_VECREDUCE_FMAX:
486     case TargetOpcode::G_VECREDUCE_FMIN:
487     case TargetOpcode::G_VECREDUCE_FMAXIMUM:
488     case TargetOpcode::G_VECREDUCE_FMINIMUM:
489     case TargetOpcode::G_VECREDUCE_ADD:
490     case TargetOpcode::G_VECREDUCE_MUL:
491     case TargetOpcode::G_VECREDUCE_AND:
492     case TargetOpcode::G_VECREDUCE_OR:
493     case TargetOpcode::G_VECREDUCE_XOR:
494     case TargetOpcode::G_VECREDUCE_SMAX:
495     case TargetOpcode::G_VECREDUCE_SMIN:
496     case TargetOpcode::G_VECREDUCE_UMAX:
497     case TargetOpcode::G_VECREDUCE_UMIN:
498       return true;
499     default:
500       return false;
501     }
502   }
503 
504   /// Get the opcode for the equivalent scalar operation for this reduction.
505   /// E.g. for G_VECREDUCE_FADD, this returns G_FADD.
getScalarOpcForReduction()506   unsigned getScalarOpcForReduction() {
507     unsigned ScalarOpc;
508     switch (getOpcode()) {
509     case TargetOpcode::G_VECREDUCE_FADD:
510       ScalarOpc = TargetOpcode::G_FADD;
511       break;
512     case TargetOpcode::G_VECREDUCE_FMUL:
513       ScalarOpc = TargetOpcode::G_FMUL;
514       break;
515     case TargetOpcode::G_VECREDUCE_FMAX:
516       ScalarOpc = TargetOpcode::G_FMAXNUM;
517       break;
518     case TargetOpcode::G_VECREDUCE_FMIN:
519       ScalarOpc = TargetOpcode::G_FMINNUM;
520       break;
521     case TargetOpcode::G_VECREDUCE_FMAXIMUM:
522       ScalarOpc = TargetOpcode::G_FMAXIMUM;
523       break;
524     case TargetOpcode::G_VECREDUCE_FMINIMUM:
525       ScalarOpc = TargetOpcode::G_FMINIMUM;
526       break;
527     case TargetOpcode::G_VECREDUCE_ADD:
528       ScalarOpc = TargetOpcode::G_ADD;
529       break;
530     case TargetOpcode::G_VECREDUCE_MUL:
531       ScalarOpc = TargetOpcode::G_MUL;
532       break;
533     case TargetOpcode::G_VECREDUCE_AND:
534       ScalarOpc = TargetOpcode::G_AND;
535       break;
536     case TargetOpcode::G_VECREDUCE_OR:
537       ScalarOpc = TargetOpcode::G_OR;
538       break;
539     case TargetOpcode::G_VECREDUCE_XOR:
540       ScalarOpc = TargetOpcode::G_XOR;
541       break;
542     case TargetOpcode::G_VECREDUCE_SMAX:
543       ScalarOpc = TargetOpcode::G_SMAX;
544       break;
545     case TargetOpcode::G_VECREDUCE_SMIN:
546       ScalarOpc = TargetOpcode::G_SMIN;
547       break;
548     case TargetOpcode::G_VECREDUCE_UMAX:
549       ScalarOpc = TargetOpcode::G_UMAX;
550       break;
551     case TargetOpcode::G_VECREDUCE_UMIN:
552       ScalarOpc = TargetOpcode::G_UMIN;
553       break;
554     default:
555       llvm_unreachable("Unhandled reduction");
556     }
557     return ScalarOpc;
558   }
559 };
560 
561 
562 } // namespace llvm
563 
564 #endif // LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H
565