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

source code of llvm/include/llvm/CodeGenTypes/LowLevelType.h