xref: /freebsd/contrib/llvm-project/llvm/include/llvm/CodeGenTypes/LowLevelType.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //== llvm/CodeGenTypes/LowLevelType.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 /// Implement a low-level type suitable for MachineInstr level instruction
10 /// selection.
11 ///
12 /// For a type attached to a MachineInstr, we only care about 2 details: total
13 /// size and the number of vector lanes (if any). Accordingly, there are 4
14 /// possible valid type-kinds:
15 ///
16 ///    * `sN` for scalars and aggregates
17 ///    * `<N x sM>` for vectors, which must have at least 2 elements.
18 ///    * `pN` for pointers
19 ///
20 /// Other information required for correct selection is expected to be carried
21 /// by the opcode, or non-type flags. For example the distinction between G_ADD
22 /// and G_FADD for int/float or fast-math flags.
23 ///
24 //===----------------------------------------------------------------------===//
25 
26 #ifndef LLVM_CODEGEN_LOWLEVELTYPE_H
27 #define LLVM_CODEGEN_LOWLEVELTYPE_H
28 
29 #include "llvm/ADT/DenseMapInfo.h"
30 #include "llvm/CodeGenTypes/MachineValueType.h"
31 #include "llvm/Support/Compiler.h"
32 #include "llvm/Support/Debug.h"
33 #include <cassert>
34 
35 namespace llvm {
36 
37 class Type;
38 class raw_ostream;
39 
40 class LLT {
41 public:
42   /// Get a low-level scalar or aggregate "bag of bits".
scalar(unsigned SizeInBits)43   static constexpr LLT scalar(unsigned SizeInBits) {
44     return LLT{/*isPointer=*/false, /*isVector=*/false, /*isScalar=*/true,
45                ElementCount::getFixed(0), SizeInBits,
46                /*AddressSpace=*/0};
47   }
48 
49   /// Get a low-level token; just a scalar with zero bits (or no size).
token()50   static constexpr LLT token() {
51     return LLT{/*isPointer=*/false, /*isVector=*/false,
52                /*isScalar=*/true,   ElementCount::getFixed(0),
53                /*SizeInBits=*/0,
54                /*AddressSpace=*/0};
55   }
56 
57   /// Get a low-level pointer in the given address space.
pointer(unsigned AddressSpace,unsigned SizeInBits)58   static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits) {
59     assert(SizeInBits > 0 && "invalid pointer size");
60     return LLT{/*isPointer=*/true, /*isVector=*/false, /*isScalar=*/false,
61                ElementCount::getFixed(0), SizeInBits, AddressSpace};
62   }
63 
64   /// Get a low-level vector of some number of elements and element width.
vector(ElementCount EC,unsigned ScalarSizeInBits)65   static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits) {
66     assert(!EC.isScalar() && "invalid number of vector elements");
67     return LLT{/*isPointer=*/false, /*isVector=*/true, /*isScalar=*/false,
68                EC, ScalarSizeInBits, /*AddressSpace=*/0};
69   }
70 
71   /// Get a low-level vector of some number of elements and element type.
vector(ElementCount EC,LLT ScalarTy)72   static constexpr LLT vector(ElementCount EC, LLT ScalarTy) {
73     assert(!EC.isScalar() && "invalid number of vector elements");
74     assert(!ScalarTy.isVector() && "invalid vector element type");
75     return LLT{ScalarTy.isPointer(),
76                /*isVector=*/true,
77                /*isScalar=*/false,
78                EC,
79                ScalarTy.getSizeInBits().getFixedValue(),
80                ScalarTy.isPointer() ? ScalarTy.getAddressSpace() : 0};
81   }
82 
83   /// Get a 16-bit IEEE half value.
84   /// TODO: Add IEEE semantics to type - This currently returns a simple `scalar(16)`.
float16()85   static constexpr LLT float16() {
86     return scalar(16);
87   }
88 
89   /// Get a 32-bit IEEE float value.
float32()90   static constexpr LLT float32() {
91     return scalar(32);
92   }
93 
94   /// Get a 64-bit IEEE double value.
float64()95   static constexpr LLT float64() {
96     return scalar(64);
97   }
98 
99   /// Get a low-level fixed-width vector of some number of elements and element
100   /// width.
fixed_vector(unsigned NumElements,unsigned ScalarSizeInBits)101   static constexpr LLT fixed_vector(unsigned NumElements,
102                                     unsigned ScalarSizeInBits) {
103     return vector(ElementCount::getFixed(NumElements), ScalarSizeInBits);
104   }
105 
106   /// Get a low-level fixed-width vector of some number of elements and element
107   /// type.
fixed_vector(unsigned NumElements,LLT ScalarTy)108   static constexpr LLT fixed_vector(unsigned NumElements, LLT ScalarTy) {
109     return vector(ElementCount::getFixed(NumElements), ScalarTy);
110   }
111 
112   /// Get a low-level scalable vector of some number of elements and element
113   /// width.
scalable_vector(unsigned MinNumElements,unsigned ScalarSizeInBits)114   static constexpr LLT scalable_vector(unsigned MinNumElements,
115                                        unsigned ScalarSizeInBits) {
116     return vector(ElementCount::getScalable(MinNumElements), ScalarSizeInBits);
117   }
118 
119   /// Get a low-level scalable vector of some number of elements and element
120   /// type.
scalable_vector(unsigned MinNumElements,LLT ScalarTy)121   static constexpr LLT scalable_vector(unsigned MinNumElements, LLT ScalarTy) {
122     return vector(ElementCount::getScalable(MinNumElements), ScalarTy);
123   }
124 
scalarOrVector(ElementCount EC,LLT ScalarTy)125   static constexpr LLT scalarOrVector(ElementCount EC, LLT ScalarTy) {
126     return EC.isScalar() ? ScalarTy : LLT::vector(EC, ScalarTy);
127   }
128 
scalarOrVector(ElementCount EC,uint64_t ScalarSize)129   static constexpr LLT scalarOrVector(ElementCount EC, uint64_t ScalarSize) {
130     assert(ScalarSize <= std::numeric_limits<unsigned>::max() &&
131            "Not enough bits in LLT to represent size");
132     return scalarOrVector(EC, LLT::scalar(static_cast<unsigned>(ScalarSize)));
133   }
134 
LLT(bool isPointer,bool isVector,bool isScalar,ElementCount EC,uint64_t SizeInBits,unsigned AddressSpace)135   explicit constexpr LLT(bool isPointer, bool isVector, bool isScalar,
136                          ElementCount EC, uint64_t SizeInBits,
137                          unsigned AddressSpace)
138       : LLT() {
139     init(isPointer, isVector, isScalar, EC, SizeInBits, AddressSpace);
140   }
LLT()141   explicit constexpr LLT()
142       : IsScalar(false), IsPointer(false), IsVector(false), RawData(0) {}
143 
144   LLVM_ABI explicit LLT(MVT VT);
145 
isValid()146   constexpr bool isValid() const { return IsScalar || RawData != 0; }
isScalar()147   constexpr bool isScalar() const { return IsScalar; }
isToken()148   constexpr bool isToken() const { return IsScalar && RawData == 0; };
isVector()149   constexpr bool isVector() const { return isValid() && IsVector; }
isPointer()150   constexpr bool isPointer() const {
151     return isValid() && IsPointer && !IsVector;
152   }
isPointerVector()153   constexpr bool isPointerVector() const { return IsPointer && isVector(); }
isPointerOrPointerVector()154   constexpr bool isPointerOrPointerVector() const {
155     return IsPointer && isValid();
156   }
157 
158   /// Returns the number of elements in a vector LLT. Must only be called on
159   /// vector types.
getNumElements()160   constexpr uint16_t getNumElements() const {
161     if (isScalable())
162       llvm::reportInvalidSizeRequest(
163           "Possible incorrect use of LLT::getNumElements() for "
164           "scalable vector. Scalable flag may be dropped, use "
165           "LLT::getElementCount() instead");
166     return getElementCount().getKnownMinValue();
167   }
168 
169   /// Returns true if the LLT is a scalable vector. Must only be called on
170   /// vector types.
isScalable()171   constexpr bool isScalable() const {
172     assert(isVector() && "Expected a vector type");
173     return getFieldValue(VectorScalableFieldInfo);
174   }
175 
176   /// Returns true if the LLT is a fixed vector. Returns false otherwise, even
177   /// if the LLT is not a vector type.
isFixedVector()178   constexpr bool isFixedVector() const { return isVector() && !isScalable(); }
179 
180   /// Returns true if the LLT is a scalable vector. Returns false otherwise,
181   /// even if the LLT is not a vector type.
isScalableVector()182   constexpr bool isScalableVector() const { return isVector() && isScalable(); }
183 
getElementCount()184   constexpr ElementCount getElementCount() const {
185     assert(IsVector && "cannot get number of elements on scalar/aggregate");
186     return ElementCount::get(getFieldValue(VectorElementsFieldInfo),
187                              isScalable());
188   }
189 
190   /// Returns the total size of the type. Must only be called on sized types.
getSizeInBits()191   constexpr TypeSize getSizeInBits() const {
192     if (isPointer() || isScalar())
193       return TypeSize::getFixed(getScalarSizeInBits());
194     auto EC = getElementCount();
195     return TypeSize(getScalarSizeInBits() * EC.getKnownMinValue(),
196                     EC.isScalable());
197   }
198 
199   /// Returns the total size of the type in bytes, i.e. number of whole bytes
200   /// needed to represent the size in bits. Must only be called on sized types.
getSizeInBytes()201   constexpr TypeSize getSizeInBytes() const {
202     TypeSize BaseSize = getSizeInBits();
203     return {(BaseSize.getKnownMinValue() + 7) / 8, BaseSize.isScalable()};
204   }
205 
getScalarType()206   constexpr LLT getScalarType() const {
207     return isVector() ? getElementType() : *this;
208   }
209 
210   /// If this type is a vector, return a vector with the same number of elements
211   /// but the new element type. Otherwise, return the new element type.
changeElementType(LLT NewEltTy)212   constexpr LLT changeElementType(LLT NewEltTy) const {
213     return isVector() ? LLT::vector(getElementCount(), NewEltTy) : NewEltTy;
214   }
215 
216   /// If this type is a vector, return a vector with the same number of elements
217   /// but the new element size. Otherwise, return the new element type. Invalid
218   /// for pointer types. For pointer types, use changeElementType.
changeElementSize(unsigned NewEltSize)219   constexpr LLT changeElementSize(unsigned NewEltSize) const {
220     assert(!isPointerOrPointerVector() &&
221            "invalid to directly change element size for pointers");
222     return isVector() ? LLT::vector(getElementCount(), NewEltSize)
223                       : LLT::scalar(NewEltSize);
224   }
225 
226   /// Return a vector or scalar with the same element type and the new element
227   /// count.
changeElementCount(ElementCount EC)228   constexpr LLT changeElementCount(ElementCount EC) const {
229     return LLT::scalarOrVector(EC, getScalarType());
230   }
231 
232   /// Return a type that is \p Factor times smaller. Reduces the number of
233   /// elements if this is a vector, or the bitwidth for scalar/pointers. Does
234   /// not attempt to handle cases that aren't evenly divisible.
divide(int Factor)235   constexpr LLT divide(int Factor) const {
236     assert(Factor != 1);
237     assert((!isScalar() || getScalarSizeInBits() != 0) &&
238            "cannot divide scalar of size zero");
239     if (isVector()) {
240       assert(getElementCount().isKnownMultipleOf(Factor));
241       return scalarOrVector(getElementCount().divideCoefficientBy(Factor),
242                             getElementType());
243     }
244 
245     assert(getScalarSizeInBits() % Factor == 0);
246     return scalar(getScalarSizeInBits() / Factor);
247   }
248 
249   /// Produce a vector type that is \p Factor times bigger, preserving the
250   /// element type. For a scalar or pointer, this will produce a new vector with
251   /// \p Factor elements.
multiplyElements(int Factor)252   constexpr LLT multiplyElements(int Factor) const {
253     if (isVector()) {
254       return scalarOrVector(getElementCount().multiplyCoefficientBy(Factor),
255                             getElementType());
256     }
257 
258     return fixed_vector(Factor, *this);
259   }
260 
isByteSized()261   constexpr bool isByteSized() const {
262     return getSizeInBits().isKnownMultipleOf(8);
263   }
264 
getScalarSizeInBits()265   constexpr unsigned getScalarSizeInBits() const {
266     if (isPointerOrPointerVector())
267       return getFieldValue(PointerSizeFieldInfo);
268     return getFieldValue(ScalarSizeFieldInfo);
269   }
270 
getAddressSpace()271   constexpr unsigned getAddressSpace() const {
272     assert(isPointerOrPointerVector() &&
273            "cannot get address space of non-pointer type");
274     return getFieldValue(PointerAddressSpaceFieldInfo);
275   }
276 
277   /// Returns the vector's element type. Only valid for vector types.
getElementType()278   constexpr LLT getElementType() const {
279     assert(isVector() && "cannot get element type of scalar/aggregate");
280     if (IsPointer)
281       return pointer(getAddressSpace(), getScalarSizeInBits());
282     else
283       return scalar(getScalarSizeInBits());
284   }
285 
286   LLVM_ABI void print(raw_ostream &OS) const;
287 
288 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
289   LLVM_DUMP_METHOD void dump() const;
290 #endif
291 
292   constexpr bool operator==(const LLT &RHS) const {
293     return IsPointer == RHS.IsPointer && IsVector == RHS.IsVector &&
294            IsScalar == RHS.IsScalar && RHS.RawData == RawData;
295   }
296 
297   constexpr bool operator!=(const LLT &RHS) const { return !(*this == RHS); }
298 
299   friend struct DenseMapInfo<LLT>;
300   friend class GISelInstProfileBuilder;
301 
302 private:
303   /// LLT is packed into 64 bits as follows:
304   /// isScalar : 1
305   /// isPointer : 1
306   /// isVector  : 1
307   /// with 61 bits remaining for Kind-specific data, packed in bitfields
308   /// as described below. As there isn't a simple portable way to pack bits
309   /// into bitfields, here the different fields in the packed structure is
310   /// described in static const *Field variables. Each of these variables
311   /// is a 2-element array, with the first element describing the bitfield size
312   /// and the second element describing the bitfield offset.
313   ///
314   /// +--------+---------+--------+----------+----------------------+
315   /// |isScalar|isPointer|isVector| RawData  |Notes                 |
316   /// +--------+---------+--------+----------+----------------------+
317   /// |   0    |    0    |   0    |    0     |Invalid               |
318   /// +--------+---------+--------+----------+----------------------+
319   /// |   0    |    0    |   1    |    0     |Tombstone Key         |
320   /// +--------+---------+--------+----------+----------------------+
321   /// |   0    |    1    |   0    |    0     |Empty Key             |
322   /// +--------+---------+--------+----------+----------------------+
323   /// |   1    |    0    |   0    |    0     |Token                 |
324   /// +--------+---------+--------+----------+----------------------+
325   /// |   1    |    0    |   0    | non-zero |Scalar                |
326   /// +--------+---------+--------+----------+----------------------+
327   /// |   0    |    1    |   0    | non-zero |Pointer               |
328   /// +--------+---------+--------+----------+----------------------+
329   /// |   0    |    0    |   1    | non-zero |Vector of non-pointer |
330   /// +--------+---------+--------+----------+----------------------+
331   /// |   0    |    1    |   1    | non-zero |Vector of pointer     |
332   /// +--------+---------+--------+----------+----------------------+
333   ///
334   /// Everything else is reserved.
335   typedef int BitFieldInfo[2];
336   ///
337   /// This is how the bitfields are packed per Kind:
338   /// * Invalid:
339   ///   gets encoded as RawData == 0, as that is an invalid encoding, since for
340   ///   valid encodings, SizeInBits/SizeOfElement must be larger than 0.
341   /// * Non-pointer scalar (isPointer == 0 && isVector == 0):
342   ///   SizeInBits: 32;
343   static const constexpr BitFieldInfo ScalarSizeFieldInfo{32, 29};
344   /// * Pointer (isPointer == 1 && isVector == 0):
345   ///   SizeInBits: 16;
346   ///   AddressSpace: 24;
347   static const constexpr BitFieldInfo PointerSizeFieldInfo{16, 45};
348   static const constexpr BitFieldInfo PointerAddressSpaceFieldInfo{24, 21};
349   /// * Vector-of-non-pointer (isPointer == 0 && isVector == 1):
350   ///   NumElements: 16;
351   ///   SizeOfElement: 32;
352   ///   Scalable: 1;
353   static const constexpr BitFieldInfo VectorElementsFieldInfo{16, 5};
354   static const constexpr BitFieldInfo VectorScalableFieldInfo{1, 0};
355   /// * Vector-of-pointer (isPointer == 1 && isVector == 1):
356   ///   NumElements: 16;
357   ///   SizeOfElement: 16;
358   ///   AddressSpace: 24;
359   ///   Scalable: 1;
360 
361   uint64_t IsScalar : 1;
362   uint64_t IsPointer : 1;
363   uint64_t IsVector : 1;
364   uint64_t RawData : 61;
365 
366   static constexpr uint64_t getMask(const BitFieldInfo FieldInfo) {
367     const int FieldSizeInBits = FieldInfo[0];
368     return (((uint64_t)1) << FieldSizeInBits) - 1;
369   }
370   static constexpr uint64_t maskAndShift(uint64_t Val, uint64_t Mask,
371                                          uint8_t Shift) {
372     assert(Val <= Mask && "Value too large for field");
373     return (Val & Mask) << Shift;
374   }
375   static constexpr uint64_t maskAndShift(uint64_t Val,
376                                          const BitFieldInfo FieldInfo) {
377     return maskAndShift(Val, getMask(FieldInfo), FieldInfo[1]);
378   }
379 
380   constexpr uint64_t getFieldValue(const BitFieldInfo FieldInfo) const {
381     return getMask(FieldInfo) & (RawData >> FieldInfo[1]);
382   }
383 
384   constexpr void init(bool IsPointer, bool IsVector, bool IsScalar,
385                       ElementCount EC, uint64_t SizeInBits,
386                       unsigned AddressSpace) {
387     assert(SizeInBits <= std::numeric_limits<unsigned>::max() &&
388            "Not enough bits in LLT to represent size");
389     this->IsPointer = IsPointer;
390     this->IsVector = IsVector;
391     this->IsScalar = IsScalar;
392     if (IsPointer) {
393       RawData = maskAndShift(SizeInBits, PointerSizeFieldInfo) |
394                 maskAndShift(AddressSpace, PointerAddressSpaceFieldInfo);
395     } else {
396       RawData = maskAndShift(SizeInBits, ScalarSizeFieldInfo);
397     }
398     if (IsVector) {
399       RawData |= maskAndShift(EC.getKnownMinValue(), VectorElementsFieldInfo) |
400                  maskAndShift(EC.isScalable() ? 1 : 0, VectorScalableFieldInfo);
401     }
402   }
403 
404 public:
405   constexpr uint64_t getUniqueRAWLLTData() const {
406     return ((uint64_t)RawData) << 3 | ((uint64_t)IsScalar) << 2 |
407            ((uint64_t)IsPointer) << 1 | ((uint64_t)IsVector);
408   }
409 };
410 
411 inline raw_ostream& operator<<(raw_ostream &OS, const LLT &Ty) {
412   Ty.print(OS);
413   return OS;
414 }
415 
416 template<> struct DenseMapInfo<LLT> {
417   static inline LLT getEmptyKey() {
418     LLT Invalid;
419     Invalid.IsPointer = true;
420     return Invalid;
421   }
422   static inline LLT getTombstoneKey() {
423     LLT Invalid;
424     Invalid.IsVector = true;
425     return Invalid;
426   }
427   static inline unsigned getHashValue(const LLT &Ty) {
428     uint64_t Val = Ty.getUniqueRAWLLTData();
429     return DenseMapInfo<uint64_t>::getHashValue(Val);
430   }
431   static bool isEqual(const LLT &LHS, const LLT &RHS) {
432     return LHS == RHS;
433   }
434 };
435 
436 }
437 
438 #endif // LLVM_CODEGEN_LOWLEVELTYPE_H
439