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.
32   Register getReg(unsigned Idx) const { return getOperand(Idx).getReg(); }
33 
34   static bool classof(const MachineInstr *MI) {
35     return isPreISelGenericOpcode(MI->getOpcode());
36   }
37 };
38 
39 /// Represents any type of generic load or store.
40 /// G_LOAD, G_STORE, G_ZEXTLOAD, G_SEXTLOAD.
41 class GLoadStore : public GenericMachineInstr {
42 public:
43   /// Get the source register of the pointer value.
44   Register getPointerReg() const { return getOperand(1).getReg(); }
45 
46   /// Get the MachineMemOperand on this instruction.
47   MachineMemOperand &getMMO() const { return **memoperands_begin(); }
48 
49   /// Returns true if the attached MachineMemOperand  has the atomic flag set.
50   bool isAtomic() const { return getMMO().isAtomic(); }
51   /// Returns true if the attached MachineMemOpeand as the volatile flag set.
52   bool isVolatile() const { return getMMO().isVolatile(); }
53   /// Returns true if the memory operation is neither atomic or volatile.
54   bool isSimple() const { return !isAtomic() && !isVolatile(); }
55   /// Returns true if this memory operation doesn't have any ordering
56   /// constraints other than normal aliasing. Volatile and (ordered) atomic
57   /// memory operations can't be reordered.
58   bool isUnordered() const { return getMMO().isUnordered(); }
59 
60   /// Returns the size in bytes of the memory access.
61   uint64_t getMemSize() const { return getMMO().getSize();
62   } /// Returns the size in bits of the memory access.
63   uint64_t getMemSizeInBits() const { return getMMO().getSizeInBits(); }
64 
65   static bool classof(const MachineInstr *MI) {
66     switch (MI->getOpcode()) {
67     case TargetOpcode::G_LOAD:
68     case TargetOpcode::G_STORE:
69     case TargetOpcode::G_ZEXTLOAD:
70     case TargetOpcode::G_SEXTLOAD:
71       return true;
72     default:
73       return false;
74     }
75   }
76 };
77 
78 /// Represents any generic load, including sign/zero extending variants.
79 class GAnyLoad : public GLoadStore {
80 public:
81   /// Get the definition register of the loaded value.
82   Register getDstReg() const { return getOperand(0).getReg(); }
83 
84   static bool classof(const MachineInstr *MI) {
85     switch (MI->getOpcode()) {
86     case TargetOpcode::G_LOAD:
87     case TargetOpcode::G_ZEXTLOAD:
88     case TargetOpcode::G_SEXTLOAD:
89       return true;
90     default:
91       return false;
92     }
93   }
94 };
95 
96 /// Represents a G_LOAD.
97 class GLoad : public GAnyLoad {
98 public:
99   static bool classof(const MachineInstr *MI) {
100     return MI->getOpcode() == TargetOpcode::G_LOAD;
101   }
102 };
103 
104 /// Represents either a G_SEXTLOAD or G_ZEXTLOAD.
105 class GExtLoad : public GAnyLoad {
106 public:
107   static bool classof(const MachineInstr *MI) {
108     return MI->getOpcode() == TargetOpcode::G_SEXTLOAD ||
109            MI->getOpcode() == TargetOpcode::G_ZEXTLOAD;
110   }
111 };
112 
113 /// Represents a G_SEXTLOAD.
114 class GSExtLoad : public GExtLoad {
115 public:
116   static bool classof(const MachineInstr *MI) {
117     return MI->getOpcode() == TargetOpcode::G_SEXTLOAD;
118   }
119 };
120 
121 /// Represents a G_ZEXTLOAD.
122 class GZExtLoad : public GExtLoad {
123 public:
124   static bool classof(const MachineInstr *MI) {
125     return MI->getOpcode() == TargetOpcode::G_ZEXTLOAD;
126   }
127 };
128 
129 /// Represents a G_STORE.
130 class GStore : public GLoadStore {
131 public:
132   /// Get the stored value register.
133   Register getValueReg() const { return getOperand(0).getReg(); }
134 
135   static bool classof(const MachineInstr *MI) {
136     return MI->getOpcode() == TargetOpcode::G_STORE;
137   }
138 };
139 
140 /// Represents a G_UNMERGE_VALUES.
141 class GUnmerge : public GenericMachineInstr {
142 public:
143   /// Returns the number of def registers.
144   unsigned getNumDefs() const { return getNumOperands() - 1; }
145   /// Get the unmerge source register.
146   Register getSourceReg() const { return getOperand(getNumDefs()).getReg(); }
147 
148   static bool classof(const MachineInstr *MI) {
149     return MI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES;
150   }
151 };
152 
153 /// Represents G_BUILD_VECTOR, G_CONCAT_VECTORS or G_MERGE_VALUES.
154 /// All these have the common property of generating a single value from
155 /// multiple sources.
156 class GMergeLikeInstr : public GenericMachineInstr {
157 public:
158   /// Returns the number of source registers.
159   unsigned getNumSources() const { return getNumOperands() - 1; }
160   /// Returns the I'th source register.
161   Register getSourceReg(unsigned I) const { return getReg(I + 1); }
162 
163   static bool classof(const MachineInstr *MI) {
164     switch (MI->getOpcode()) {
165     case TargetOpcode::G_MERGE_VALUES:
166     case TargetOpcode::G_CONCAT_VECTORS:
167     case TargetOpcode::G_BUILD_VECTOR:
168       return true;
169     default:
170       return false;
171     }
172   }
173 };
174 
175 /// Represents a G_MERGE_VALUES.
176 class GMerge : public GMergeLikeInstr {
177 public:
178   static bool classof(const MachineInstr *MI) {
179     return MI->getOpcode() == TargetOpcode::G_MERGE_VALUES;
180   }
181 };
182 
183 /// Represents a G_CONCAT_VECTORS.
184 class GConcatVectors : public GMergeLikeInstr {
185 public:
186   static bool classof(const MachineInstr *MI) {
187     return MI->getOpcode() == TargetOpcode::G_CONCAT_VECTORS;
188   }
189 };
190 
191 /// Represents a G_BUILD_VECTOR.
192 class GBuildVector : public GMergeLikeInstr {
193 public:
194   static bool classof(const MachineInstr *MI) {
195     return MI->getOpcode() == TargetOpcode::G_BUILD_VECTOR;
196   }
197 };
198 
199 /// Represents a G_PTR_ADD.
200 class GPtrAdd : public GenericMachineInstr {
201 public:
202   Register getBaseReg() const { return getReg(1); }
203   Register getOffsetReg() const { return getReg(2); }
204 
205   static bool classof(const MachineInstr *MI) {
206     return MI->getOpcode() == TargetOpcode::G_PTR_ADD;
207   }
208 };
209 
210 /// Represents a G_IMPLICIT_DEF.
211 class GImplicitDef : public GenericMachineInstr {
212 public:
213   static bool classof(const MachineInstr *MI) {
214     return MI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF;
215   }
216 };
217 
218 /// Represents a G_SELECT.
219 class GSelect : public GenericMachineInstr {
220 public:
221   Register getCondReg() const { return getReg(1); }
222   Register getTrueReg() const { return getReg(2); }
223   Register getFalseReg() const { return getReg(3); }
224 
225   static bool classof(const MachineInstr *MI) {
226     return MI->getOpcode() == TargetOpcode::G_SELECT;
227   }
228 };
229 
230 /// Represent a G_ICMP or G_FCMP.
231 class GAnyCmp : public GenericMachineInstr {
232 public:
233   CmpInst::Predicate getCond() const {
234     return static_cast<CmpInst::Predicate>(getOperand(1).getPredicate());
235   }
236   Register getLHSReg() const { return getReg(2); }
237   Register getRHSReg() const { return getReg(3); }
238 
239   static bool classof(const MachineInstr *MI) {
240     return MI->getOpcode() == TargetOpcode::G_ICMP ||
241            MI->getOpcode() == TargetOpcode::G_FCMP;
242   }
243 };
244 
245 /// Represent a G_ICMP.
246 class GICmp : public GAnyCmp {
247 public:
248   static bool classof(const MachineInstr *MI) {
249     return MI->getOpcode() == TargetOpcode::G_ICMP;
250   }
251 };
252 
253 /// Represent a G_FCMP.
254 class GFCmp : public GAnyCmp {
255 public:
256   static bool classof(const MachineInstr *MI) {
257     return MI->getOpcode() == TargetOpcode::G_FCMP;
258   }
259 };
260 
261 /// Represents overflowing binary operations.
262 /// Only carry-out:
263 /// G_UADDO, G_SADDO, G_USUBO, G_SSUBO, G_UMULO, G_SMULO
264 /// Carry-in and carry-out:
265 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE
266 class GBinOpCarryOut : public GenericMachineInstr {
267 public:
268   Register getDstReg() const { return getReg(0); }
269   Register getCarryOutReg() const { return getReg(1); }
270   MachineOperand &getLHS() { return getOperand(2); }
271   MachineOperand &getRHS() { return getOperand(3); }
272 
273   static bool classof(const MachineInstr *MI) {
274     switch (MI->getOpcode()) {
275     case TargetOpcode::G_UADDO:
276     case TargetOpcode::G_SADDO:
277     case TargetOpcode::G_USUBO:
278     case TargetOpcode::G_SSUBO:
279     case TargetOpcode::G_UADDE:
280     case TargetOpcode::G_SADDE:
281     case TargetOpcode::G_USUBE:
282     case TargetOpcode::G_SSUBE:
283     case TargetOpcode::G_UMULO:
284     case TargetOpcode::G_SMULO:
285       return true;
286     default:
287       return false;
288     }
289   }
290 };
291 
292 /// Represents overflowing add/sub operations.
293 /// Only carry-out:
294 /// G_UADDO, G_SADDO, G_USUBO, G_SSUBO
295 /// Carry-in and carry-out:
296 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE
297 class GAddSubCarryOut : public GBinOpCarryOut {
298 public:
299   bool isAdd() const {
300     switch (getOpcode()) {
301     case TargetOpcode::G_UADDO:
302     case TargetOpcode::G_SADDO:
303     case TargetOpcode::G_UADDE:
304     case TargetOpcode::G_SADDE:
305       return true;
306     default:
307       return false;
308     }
309   }
310   bool isSub() const { return !isAdd(); }
311 
312   bool isSigned() const {
313     switch (getOpcode()) {
314     case TargetOpcode::G_SADDO:
315     case TargetOpcode::G_SSUBO:
316     case TargetOpcode::G_SADDE:
317     case TargetOpcode::G_SSUBE:
318       return true;
319     default:
320       return false;
321     }
322   }
323   bool isUnsigned() const { return !isSigned(); }
324 
325   static bool classof(const MachineInstr *MI) {
326     switch (MI->getOpcode()) {
327     case TargetOpcode::G_UADDO:
328     case TargetOpcode::G_SADDO:
329     case TargetOpcode::G_USUBO:
330     case TargetOpcode::G_SSUBO:
331     case TargetOpcode::G_UADDE:
332     case TargetOpcode::G_SADDE:
333     case TargetOpcode::G_USUBE:
334     case TargetOpcode::G_SSUBE:
335       return true;
336     default:
337       return false;
338     }
339   }
340 };
341 
342 /// Represents overflowing add/sub operations that also consume a carry-in.
343 /// G_UADDE, G_SADDE, G_USUBE, G_SSUBE
344 class GAddSubCarryInOut : public GAddSubCarryOut {
345 public:
346   Register getCarryInReg() const { return getReg(4); }
347 
348   static bool classof(const MachineInstr *MI) {
349     switch (MI->getOpcode()) {
350     case TargetOpcode::G_UADDE:
351     case TargetOpcode::G_SADDE:
352     case TargetOpcode::G_USUBE:
353     case TargetOpcode::G_SSUBE:
354       return true;
355     default:
356       return false;
357     }
358   }
359 };
360 
361 } // namespace llvm
362 
363 #endif // LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H
364