LLVM 18.0.0git
TypeSize.h
Go to the documentation of this file.
1//===- TypeSize.h - Wrapper around type sizes -------------------*- 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//
9// This file provides a struct that can be used to query the size of IR types
10// which may be scalable vectors. It provides convenience operators so that
11// it can be used in much the same way as a single scalar value.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_SUPPORT_TYPESIZE_H
16#define LLVM_SUPPORT_TYPESIZE_H
17
18#include "llvm/ADT/ArrayRef.h"
21
22#include <algorithm>
23#include <cassert>
24#include <cstdint>
25#include <type_traits>
26
27namespace llvm {
28
29/// Reports a diagnostic message to indicate an invalid size request has been
30/// done on a scalable vector. This function may not return.
31void reportInvalidSizeRequest(const char *Msg);
32
33/// StackOffset holds a fixed and a scalable offset in bytes.
35 int64_t Fixed = 0;
36 int64_t Scalable = 0;
37
38 StackOffset(int64_t Fixed, int64_t Scalable)
39 : Fixed(Fixed), Scalable(Scalable) {}
40
41public:
42 StackOffset() = default;
43 static StackOffset getFixed(int64_t Fixed) { return {Fixed, 0}; }
44 static StackOffset getScalable(int64_t Scalable) { return {0, Scalable}; }
45 static StackOffset get(int64_t Fixed, int64_t Scalable) {
46 return {Fixed, Scalable};
47 }
48
49 /// Returns the fixed component of the stack.
50 int64_t getFixed() const { return Fixed; }
51
52 /// Returns the scalable component of the stack.
53 int64_t getScalable() const { return Scalable; }
54
55 // Arithmetic operations.
57 return {Fixed + RHS.Fixed, Scalable + RHS.Scalable};
58 }
60 return {Fixed - RHS.Fixed, Scalable - RHS.Scalable};
61 }
63 Fixed += RHS.Fixed;
64 Scalable += RHS.Scalable;
65 return *this;
66 }
68 Fixed -= RHS.Fixed;
69 Scalable -= RHS.Scalable;
70 return *this;
71 }
72 StackOffset operator-() const { return {-Fixed, -Scalable}; }
73
74 // Equality comparisons.
75 bool operator==(const StackOffset &RHS) const {
76 return Fixed == RHS.Fixed && Scalable == RHS.Scalable;
77 }
78 bool operator!=(const StackOffset &RHS) const {
79 return Fixed != RHS.Fixed || Scalable != RHS.Scalable;
80 }
81
82 // The bool operator returns true iff any of the components is non zero.
83 explicit operator bool() const { return Fixed != 0 || Scalable != 0; }
84};
85
86namespace details {
87
88// Base class for ElementCount and TypeSize below.
89template <typename LeafTy, typename ValueTy> class FixedOrScalableQuantity {
90public:
91 using ScalarTy = ValueTy;
92
93protected:
95 bool Scalable = false;
96
97 constexpr FixedOrScalableQuantity() = default;
100
101 friend constexpr LeafTy &operator+=(LeafTy &LHS, const LeafTy &RHS) {
102 assert((LHS.Quantity == 0 || RHS.Quantity == 0 ||
103 LHS.Scalable == RHS.Scalable) &&
104 "Incompatible types");
105 LHS.Quantity += RHS.Quantity;
106 if (!RHS.isZero())
107 LHS.Scalable = RHS.Scalable;
108 return LHS;
109 }
110
111 friend constexpr LeafTy &operator-=(LeafTy &LHS, const LeafTy &RHS) {
112 assert((LHS.Quantity == 0 || RHS.Quantity == 0 ||
113 LHS.Scalable == RHS.Scalable) &&
114 "Incompatible types");
115 LHS.Quantity -= RHS.Quantity;
116 if (!RHS.isZero())
117 LHS.Scalable = RHS.Scalable;
118 return LHS;
119 }
120
121 friend constexpr LeafTy &operator*=(LeafTy &LHS, ScalarTy RHS) {
122 LHS.Quantity *= RHS;
123 return LHS;
124 }
125
126 friend constexpr LeafTy operator+(const LeafTy &LHS, const LeafTy &RHS) {
127 LeafTy Copy = LHS;
128 return Copy += RHS;
129 }
130
131 friend constexpr LeafTy operator-(const LeafTy &LHS, const LeafTy &RHS) {
132 LeafTy Copy = LHS;
133 return Copy -= RHS;
134 }
135
136 friend constexpr LeafTy operator*(const LeafTy &LHS, ScalarTy RHS) {
137 LeafTy Copy = LHS;
138 return Copy *= RHS;
139 }
140
141 template <typename U = ScalarTy>
142 friend constexpr std::enable_if_t<std::is_signed_v<U>, LeafTy>
143 operator-(const LeafTy &LHS) {
144 LeafTy Copy = LHS;
145 return Copy *= -1;
146 }
147
148public:
149 constexpr bool operator==(const FixedOrScalableQuantity &RHS) const {
150 return Quantity == RHS.Quantity && Scalable == RHS.Scalable;
151 }
152
153 constexpr bool operator!=(const FixedOrScalableQuantity &RHS) const {
154 return Quantity != RHS.Quantity || Scalable != RHS.Scalable;
155 }
156
157 constexpr bool isZero() const { return Quantity == 0; }
158
159 constexpr bool isNonZero() const { return Quantity != 0; }
160
161 explicit operator bool() const { return isNonZero(); }
162
163 /// Add \p RHS to the underlying quantity.
164 constexpr LeafTy getWithIncrement(ScalarTy RHS) const {
165 return LeafTy::get(Quantity + RHS, Scalable);
166 }
167
168 /// Returns the minimum value this quantity can represent.
169 constexpr ScalarTy getKnownMinValue() const { return Quantity; }
170
171 /// Returns whether the quantity is scaled by a runtime quantity (vscale).
172 constexpr bool isScalable() const { return Scalable; }
173
174 /// A return value of true indicates we know at compile time that the number
175 /// of elements (vscale * Min) is definitely even. However, returning false
176 /// does not guarantee that the total number of elements is odd.
177 constexpr bool isKnownEven() const { return (getKnownMinValue() & 0x1) == 0; }
178
179 /// This function tells the caller whether the element count is known at
180 /// compile time to be a multiple of the scalar value RHS.
181 constexpr bool isKnownMultipleOf(ScalarTy RHS) const {
182 return getKnownMinValue() % RHS == 0;
183 }
184
185 // Return the minimum value with the assumption that the count is exact.
186 // Use in places where a scalable count doesn't make sense (e.g. non-vector
187 // types, or vectors in backends which don't support scalable vectors).
188 constexpr ScalarTy getFixedValue() const {
189 assert((!isScalable() || isZero()) &&
190 "Request for a fixed element count on a scalable object");
191 return getKnownMinValue();
192 }
193
194 // For some cases, quantity ordering between scalable and fixed quantity types
195 // cannot be determined at compile time, so such comparisons aren't allowed.
196 //
197 // e.g. <vscale x 2 x i16> could be bigger than <4 x i32> with a runtime
198 // vscale >= 5, equal sized with a vscale of 4, and smaller with
199 // a vscale <= 3.
200 //
201 // All the functions below make use of the fact vscale is always >= 1, which
202 // means that <vscale x 4 x i32> is guaranteed to be >= <4 x i32>, etc.
203
204 static constexpr bool isKnownLT(const FixedOrScalableQuantity &LHS,
206 if (!LHS.isScalable() || RHS.isScalable())
207 return LHS.getKnownMinValue() < RHS.getKnownMinValue();
208 return false;
209 }
210
211 static constexpr bool isKnownGT(const FixedOrScalableQuantity &LHS,
213 if (LHS.isScalable() || !RHS.isScalable())
214 return LHS.getKnownMinValue() > RHS.getKnownMinValue();
215 return false;
216 }
217
218 static constexpr bool isKnownLE(const FixedOrScalableQuantity &LHS,
220 if (!LHS.isScalable() || RHS.isScalable())
221 return LHS.getKnownMinValue() <= RHS.getKnownMinValue();
222 return false;
223 }
224
225 static constexpr bool isKnownGE(const FixedOrScalableQuantity &LHS,
227 if (LHS.isScalable() || !RHS.isScalable())
228 return LHS.getKnownMinValue() >= RHS.getKnownMinValue();
229 return false;
230 }
231
232 /// We do not provide the '/' operator here because division for polynomial
233 /// types does not work in the same way as for normal integer types. We can
234 /// only divide the minimum value (or coefficient) by RHS, which is not the
235 /// same as
236 /// (Min * Vscale) / RHS
237 /// The caller is recommended to use this function in combination with
238 /// isKnownMultipleOf(RHS), which lets the caller know if it's possible to
239 /// perform a lossless divide by RHS.
240 constexpr LeafTy divideCoefficientBy(ScalarTy RHS) const {
241 return LeafTy::get(getKnownMinValue() / RHS, isScalable());
242 }
243
244 constexpr LeafTy multiplyCoefficientBy(ScalarTy RHS) const {
245 return LeafTy::get(getKnownMinValue() * RHS, isScalable());
246 }
247
248 constexpr LeafTy coefficientNextPowerOf2() const {
249 return LeafTy::get(
251 isScalable());
252 }
253
254 /// Returns true if there exists a value X where RHS.multiplyCoefficientBy(X)
255 /// will result in a value whose quantity matches our own.
256 constexpr bool
258 return isScalable() == RHS.isScalable() &&
259 getKnownMinValue() % RHS.getKnownMinValue() == 0;
260 }
261
262 /// Returns a value X where RHS.multiplyCoefficientBy(X) will result in a
263 /// value whose quantity matches our own.
264 constexpr ScalarTy
266 assert(hasKnownScalarFactor(RHS) && "Expected RHS to be a known factor!");
267 return getKnownMinValue() / RHS.getKnownMinValue();
268 }
269
270 /// Printing function.
271 void print(raw_ostream &OS) const {
272 if (isScalable())
273 OS << "vscale x ";
274 OS << getKnownMinValue();
275 }
276};
277
278} // namespace details
279
280// Stores the number of elements for a type and whether this type is fixed
281// (N-Elements) or scalable (e.g., SVE).
282// - ElementCount::getFixed(1) : A scalar value.
283// - ElementCount::getFixed(2) : A vector type holding 2 values.
284// - ElementCount::getScalable(4) : A scalable vector type holding 4 values.
286 : public details::FixedOrScalableQuantity<ElementCount, unsigned> {
287 constexpr ElementCount(ScalarTy MinVal, bool Scalable)
289
290 constexpr ElementCount(
291 const FixedOrScalableQuantity<ElementCount, unsigned> &V)
293
294public:
296
297 static constexpr ElementCount getFixed(ScalarTy MinVal) {
298 return ElementCount(MinVal, false);
299 }
300 static constexpr ElementCount getScalable(ScalarTy MinVal) {
301 return ElementCount(MinVal, true);
302 }
303 static constexpr ElementCount get(ScalarTy MinVal, bool Scalable) {
304 return ElementCount(MinVal, Scalable);
305 }
306
307 /// Exactly one element.
308 constexpr bool isScalar() const {
309 return !isScalable() && getKnownMinValue() == 1;
310 }
311 /// One or more elements.
312 constexpr bool isVector() const {
313 return (isScalable() && getKnownMinValue() != 0) || getKnownMinValue() > 1;
314 }
315};
316
317// Stores the size of a type. If the type is of fixed size, it will represent
318// the exact size. If the type is a scalable vector, it will represent the known
319// minimum size.
320class TypeSize : public details::FixedOrScalableQuantity<TypeSize, uint64_t> {
321 TypeSize(const FixedOrScalableQuantity<TypeSize, uint64_t> &V)
323
324public:
326
329
330 static constexpr TypeSize get(ScalarTy Quantity, bool Scalable) {
331 return TypeSize(Quantity, Scalable);
332 }
333 static constexpr TypeSize getFixed(ScalarTy ExactSize) {
334 return TypeSize(ExactSize, false);
335 }
336 static constexpr TypeSize getScalable(ScalarTy MinimumSize) {
337 return TypeSize(MinimumSize, true);
338 }
339
340 // All code for this class below this point is needed because of the
341 // temporary implicit conversion to uint64_t. The operator overloads are
342 // needed because otherwise the conversion of the parent class
343 // UnivariateLinearPolyBase -> TypeSize is ambiguous.
344 // TODO: Remove the implicit conversion.
345
346 // Casts to a uint64_t if this is a fixed-width size.
347 //
348 // This interface is deprecated and will be removed in a future version
349 // of LLVM in favour of upgrading uses that rely on this implicit conversion
350 // to uint64_t. Calls to functions that return a TypeSize should use the
351 // proper interfaces to TypeSize.
352 // In practice this is mostly calls to MVT/EVT::getSizeInBits().
353 //
354 // To determine how to upgrade the code:
355 //
356 // if (<algorithm works for both scalable and fixed-width vectors>)
357 // use getKnownMinValue()
358 // else if (<algorithm works only for fixed-width vectors>) {
359 // if <algorithm can be adapted for both scalable and fixed-width vectors>
360 // update the algorithm and use getKnownMinValue()
361 // else
362 // bail out early for scalable vectors and use getFixedValue()
363 // }
364 operator ScalarTy() const;
365
366 // Additional operators needed to avoid ambiguous parses
367 // because of the implicit conversion hack.
368 friend constexpr TypeSize operator*(const TypeSize &LHS, const int RHS) {
369 return LHS * (ScalarTy)RHS;
370 }
371 friend constexpr TypeSize operator*(const TypeSize &LHS, const unsigned RHS) {
372 return LHS * (ScalarTy)RHS;
373 }
374 friend constexpr TypeSize operator*(const TypeSize &LHS, const int64_t RHS) {
375 return LHS * (ScalarTy)RHS;
376 }
377 friend constexpr TypeSize operator*(const int LHS, const TypeSize &RHS) {
378 return RHS * LHS;
379 }
380 friend constexpr TypeSize operator*(const unsigned LHS, const TypeSize &RHS) {
381 return RHS * LHS;
382 }
383 friend constexpr TypeSize operator*(const int64_t LHS, const TypeSize &RHS) {
384 return RHS * LHS;
385 }
386 friend constexpr TypeSize operator*(const uint64_t LHS, const TypeSize &RHS) {
387 return RHS * LHS;
388 }
389};
390
391//===----------------------------------------------------------------------===//
392// Utilities
393//===----------------------------------------------------------------------===//
394
395/// Returns a TypeSize with a known minimum size that is the next integer
396/// (mod 2**64) that is greater than or equal to \p Quantity and is a multiple
397/// of \p Align. \p Align must be non-zero.
398///
399/// Similar to the alignTo functions in MathExtras.h
401 assert(Align != 0u && "Align must be non-zero");
402 return {(Size.getKnownMinValue() + Align - 1) / Align * Align,
403 Size.isScalable()};
404}
405
406/// Stream operator function for `FixedOrScalableQuantity`.
407template <typename LeafTy, typename ScalarTy>
411 PS.print(OS);
412 return OS;
413}
414
415template <> struct DenseMapInfo<ElementCount, void> {
416 static inline ElementCount getEmptyKey() {
417 return ElementCount::getScalable(~0U);
418 }
420 return ElementCount::getFixed(~0U - 1);
421 }
422 static unsigned getHashValue(const ElementCount &EltCnt) {
423 unsigned HashVal = EltCnt.getKnownMinValue() * 37U;
424 if (EltCnt.isScalable())
425 return (HashVal - 1U);
426
427 return HashVal;
428 }
429 static bool isEqual(const ElementCount &LHS, const ElementCount &RHS) {
430 return LHS == RHS;
431 }
432};
433
434} // end namespace llvm
435
436#endif // LLVM_SUPPORT_TYPESIZE_H
uint64_t Size
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
Value * RHS
Value * LHS
constexpr bool isVector() const
One or more elements.
Definition: TypeSize.h:312
constexpr ElementCount()
Definition: TypeSize.h:295
static constexpr ElementCount getScalable(ScalarTy MinVal)
Definition: TypeSize.h:300
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition: TypeSize.h:297
static constexpr ElementCount get(ScalarTy MinVal, bool Scalable)
Definition: TypeSize.h:303
constexpr bool isScalar() const
Exactly one element.
Definition: TypeSize.h:308
StackOffset holds a fixed and a scalable offset in bytes.
Definition: TypeSize.h:34
int64_t getFixed() const
Returns the fixed component of the stack.
Definition: TypeSize.h:50
StackOffset operator+(const StackOffset &RHS) const
Definition: TypeSize.h:56
int64_t getScalable() const
Returns the scalable component of the stack.
Definition: TypeSize.h:53
StackOffset operator-() const
Definition: TypeSize.h:72
bool operator!=(const StackOffset &RHS) const
Definition: TypeSize.h:78
StackOffset operator-(const StackOffset &RHS) const
Definition: TypeSize.h:59
bool operator==(const StackOffset &RHS) const
Definition: TypeSize.h:75
StackOffset & operator-=(const StackOffset &RHS)
Definition: TypeSize.h:67
static StackOffset get(int64_t Fixed, int64_t Scalable)
Definition: TypeSize.h:45
StackOffset()=default
static StackOffset getScalable(int64_t Scalable)
Definition: TypeSize.h:44
static StackOffset getFixed(int64_t Fixed)
Definition: TypeSize.h:43
StackOffset & operator+=(const StackOffset &RHS)
Definition: TypeSize.h:62
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition: TypeSize.h:333
constexpr TypeSize(ScalarTy Quantity, bool Scalable)
Definition: TypeSize.h:327
constexpr TypeSize()
Definition: TypeSize.h:325
friend constexpr TypeSize operator*(const TypeSize &LHS, const unsigned RHS)
Definition: TypeSize.h:371
friend constexpr TypeSize operator*(const TypeSize &LHS, const int64_t RHS)
Definition: TypeSize.h:374
friend constexpr TypeSize operator*(const uint64_t LHS, const TypeSize &RHS)
Definition: TypeSize.h:386
static constexpr TypeSize getScalable(ScalarTy MinimumSize)
Definition: TypeSize.h:336
static constexpr TypeSize get(ScalarTy Quantity, bool Scalable)
Definition: TypeSize.h:330
friend constexpr TypeSize operator*(const TypeSize &LHS, const int RHS)
Definition: TypeSize.h:368
friend constexpr TypeSize operator*(const int64_t LHS, const TypeSize &RHS)
Definition: TypeSize.h:383
friend constexpr TypeSize operator*(const unsigned LHS, const TypeSize &RHS)
Definition: TypeSize.h:380
friend constexpr TypeSize operator*(const int LHS, const TypeSize &RHS)
Definition: TypeSize.h:377
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
Definition: TypeSize.h:181
constexpr bool hasKnownScalarFactor(const FixedOrScalableQuantity &RHS) const
Returns true if there exists a value X where RHS.multiplyCoefficientBy(X) will result in a value whos...
Definition: TypeSize.h:257
friend constexpr LeafTy & operator*=(LeafTy &LHS, ScalarTy RHS)
Definition: TypeSize.h:121
friend constexpr LeafTy operator+(const LeafTy &LHS, const LeafTy &RHS)
Definition: TypeSize.h:126
constexpr bool operator!=(const FixedOrScalableQuantity &RHS) const
Definition: TypeSize.h:153
friend constexpr LeafTy & operator-=(LeafTy &LHS, const LeafTy &RHS)
Definition: TypeSize.h:111
constexpr ScalarTy getFixedValue() const
Definition: TypeSize.h:188
static constexpr bool isKnownLE(const FixedOrScalableQuantity &LHS, const FixedOrScalableQuantity &RHS)
Definition: TypeSize.h:218
constexpr FixedOrScalableQuantity()=default
friend constexpr LeafTy & operator+=(LeafTy &LHS, const LeafTy &RHS)
Definition: TypeSize.h:101
constexpr bool isNonZero() const
Definition: TypeSize.h:159
friend constexpr std::enable_if_t< std::is_signed_v< U >, LeafTy > operator-(const LeafTy &LHS)
Definition: TypeSize.h:143
void print(raw_ostream &OS) const
Printing function.
Definition: TypeSize.h:271
constexpr LeafTy coefficientNextPowerOf2() const
Definition: TypeSize.h:248
constexpr LeafTy getWithIncrement(ScalarTy RHS) const
Add RHS to the underlying quantity.
Definition: TypeSize.h:164
constexpr ScalarTy getKnownScalarFactor(const FixedOrScalableQuantity &RHS) const
Returns a value X where RHS.multiplyCoefficientBy(X) will result in a value whose quantity matches ou...
Definition: TypeSize.h:265
constexpr FixedOrScalableQuantity(ScalarTy Quantity, bool Scalable)
Definition: TypeSize.h:98
static constexpr bool isKnownLT(const FixedOrScalableQuantity &LHS, const FixedOrScalableQuantity &RHS)
Definition: TypeSize.h:204
friend constexpr LeafTy operator-(const LeafTy &LHS, const LeafTy &RHS)
Definition: TypeSize.h:131
constexpr bool isScalable() const
Returns whether the quantity is scaled by a runtime quantity (vscale).
Definition: TypeSize.h:172
constexpr LeafTy multiplyCoefficientBy(ScalarTy RHS) const
Definition: TypeSize.h:244
constexpr bool isKnownEven() const
A return value of true indicates we know at compile time that the number of elements (vscale * Min) i...
Definition: TypeSize.h:177
friend constexpr LeafTy operator*(const LeafTy &LHS, ScalarTy RHS)
Definition: TypeSize.h:136
constexpr bool operator==(const FixedOrScalableQuantity &RHS) const
Definition: TypeSize.h:149
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition: TypeSize.h:169
constexpr bool isZero() const
Definition: TypeSize.h:157
static constexpr bool isKnownGT(const FixedOrScalableQuantity &LHS, const FixedOrScalableQuantity &RHS)
Definition: TypeSize.h:211
constexpr LeafTy divideCoefficientBy(ScalarTy RHS) const
We do not provide the '/' operator here because division for polynomial types does not work in the sa...
Definition: TypeSize.h:240
static constexpr bool isKnownGE(const FixedOrScalableQuantity &LHS, const FixedOrScalableQuantity &RHS)
Definition: TypeSize.h:225
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
void reportInvalidSizeRequest(const char *Msg)
Reports a diagnostic message to indicate an invalid size request has been done on a scalable vector.
Definition: TypeSize.cpp:38
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:155
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
Definition: APFixedPoint.h:292
constexpr uint64_t NextPowerOf2(uint64_t A)
Returns the next power of two (in 64-bits) that is strictly greater than A.
Definition: MathExtras.h:349
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition: Alignment.h:39
static ElementCount getEmptyKey()
Definition: TypeSize.h:416
static unsigned getHashValue(const ElementCount &EltCnt)
Definition: TypeSize.h:422
static bool isEqual(const ElementCount &LHS, const ElementCount &RHS)
Definition: TypeSize.h:429
static ElementCount getTombstoneKey()
Definition: TypeSize.h:419
An information struct used to provide DenseMap with the various necessary components for a given valu...
Definition: DenseMapInfo.h:50