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 <cassert>
19 #include <tuple>
20
21 namespace llvm {
22
23 class ElementCount {
24 public:
25 unsigned Min; // Minimum number of vector elements.
26 bool Scalable; // If true, NumElements is a multiple of 'Min' determined
27 // at runtime rather than compile time.
28
ElementCount(unsigned Min,bool Scalable)29 ElementCount(unsigned Min, bool Scalable)
30 : Min(Min), Scalable(Scalable) {}
31
32 ElementCount operator*(unsigned RHS) {
33 return { Min * RHS, Scalable };
34 }
35 ElementCount operator/(unsigned RHS) {
36 return { Min / RHS, Scalable };
37 }
38
39 bool operator==(const ElementCount& RHS) const {
40 return Min == RHS.Min && Scalable == RHS.Scalable;
41 }
42 bool operator!=(const ElementCount& RHS) const {
43 return !(*this == RHS);
44 }
45 };
46
47 // This class is used to represent the size of types. If the type is of fixed
48 // size, it will represent the exact size. If the type is a scalable vector,
49 // it will represent the known minimum size.
50 class TypeSize {
51 uint64_t MinSize; // The known minimum size.
52 bool IsScalable; // If true, then the runtime size is an integer multiple
53 // of MinSize.
54
55 public:
TypeSize(uint64_t MinSize,bool Scalable)56 constexpr TypeSize(uint64_t MinSize, bool Scalable)
57 : MinSize(MinSize), IsScalable(Scalable) {}
58
Fixed(uint64_t Size)59 static constexpr TypeSize Fixed(uint64_t Size) {
60 return TypeSize(Size, /*IsScalable=*/false);
61 }
62
Scalable(uint64_t MinSize)63 static constexpr TypeSize Scalable(uint64_t MinSize) {
64 return TypeSize(MinSize, /*IsScalable=*/true);
65 }
66
67 // Scalable vector types with the same minimum size as a fixed size type are
68 // not guaranteed to be the same size at runtime, so they are never
69 // considered to be equal.
70 friend bool operator==(const TypeSize &LHS, const TypeSize &RHS) {
71 return std::tie(LHS.MinSize, LHS.IsScalable) ==
72 std::tie(RHS.MinSize, RHS.IsScalable);
73 }
74
75 friend bool operator!=(const TypeSize &LHS, const TypeSize &RHS) {
76 return !(LHS == RHS);
77 }
78
79 // For many cases, size ordering between scalable and fixed size types cannot
80 // be determined at compile time, so such comparisons aren't allowed.
81 //
82 // e.g. <vscale x 2 x i16> could be bigger than <4 x i32> with a runtime
83 // vscale >= 5, equal sized with a vscale of 4, and smaller with
84 // a vscale <= 3.
85 //
86 // If the scalable flags match, just perform the requested comparison
87 // between the minimum sizes.
88 friend bool operator<(const TypeSize &LHS, const TypeSize &RHS) {
89 assert(LHS.IsScalable == RHS.IsScalable &&
90 "Ordering comparison of scalable and fixed types");
91
92 return LHS.MinSize < RHS.MinSize;
93 }
94
95 friend bool operator>(const TypeSize &LHS, const TypeSize &RHS) {
96 return RHS < LHS;
97 }
98
99 friend bool operator<=(const TypeSize &LHS, const TypeSize &RHS) {
100 return !(RHS < LHS);
101 }
102
103 friend bool operator>=(const TypeSize &LHS, const TypeSize& RHS) {
104 return !(LHS < RHS);
105 }
106
107 // Convenience operators to obtain relative sizes independently of
108 // the scalable flag.
109 TypeSize operator*(unsigned RHS) const {
110 return { MinSize * RHS, IsScalable };
111 }
112
113 friend TypeSize operator*(const unsigned LHS, const TypeSize &RHS) {
114 return { LHS * RHS.MinSize, RHS.IsScalable };
115 }
116
117 TypeSize operator/(unsigned RHS) const {
118 return { MinSize / RHS, IsScalable };
119 }
120
121 // Return the minimum size with the assumption that the size is exact.
122 // Use in places where a scalable size doesn't make sense (e.g. non-vector
123 // types, or vectors in backends which don't support scalable vectors).
getFixedSize()124 uint64_t getFixedSize() const {
125 assert(!IsScalable && "Request for a fixed size on a scalable object");
126 return MinSize;
127 }
128
129 // Return the known minimum size. Use in places where the scalable property
130 // doesn't matter (e.g. determining alignment) or in conjunction with the
131 // isScalable method below.
getKnownMinSize()132 uint64_t getKnownMinSize() const {
133 return MinSize;
134 }
135
136 // Return whether or not the size is scalable.
isScalable()137 bool isScalable() const {
138 return IsScalable;
139 }
140
141 // Returns true if the number of bits is a multiple of an 8-bit byte.
isByteSized()142 bool isByteSized() const {
143 return (MinSize & 7) == 0;
144 }
145
146 // Casts to a uint64_t if this is a fixed-width size.
147 //
148 // NOTE: This interface is obsolete and will be removed in a future version
149 // of LLVM in favour of calling getFixedSize() directly.
uint64_t()150 operator uint64_t() const {
151 return getFixedSize();
152 }
153
154 // Additional convenience operators needed to avoid ambiguous parses.
155 // TODO: Make uint64_t the default operator?
156 TypeSize operator*(uint64_t RHS) const {
157 return { MinSize * RHS, IsScalable };
158 }
159
160 TypeSize operator*(int RHS) const {
161 return { MinSize * RHS, IsScalable };
162 }
163
164 TypeSize operator*(int64_t RHS) const {
165 return { MinSize * RHS, IsScalable };
166 }
167
168 friend TypeSize operator*(const uint64_t LHS, const TypeSize &RHS) {
169 return { LHS * RHS.MinSize, RHS.IsScalable };
170 }
171
172 friend TypeSize operator*(const int LHS, const TypeSize &RHS) {
173 return { LHS * RHS.MinSize, RHS.IsScalable };
174 }
175
176 friend TypeSize operator*(const int64_t LHS, const TypeSize &RHS) {
177 return { LHS * RHS.MinSize, RHS.IsScalable };
178 }
179
180 TypeSize operator/(uint64_t RHS) const {
181 return { MinSize / RHS, IsScalable };
182 }
183
184 TypeSize operator/(int RHS) const {
185 return { MinSize / RHS, IsScalable };
186 }
187
188 TypeSize operator/(int64_t RHS) const {
189 return { MinSize / RHS, IsScalable };
190 }
191 };
192
193 /// Returns a TypeSize with a known minimum size that is the next integer
194 /// (mod 2**64) that is greater than or equal to \p Value and is a multiple
195 /// of \p Align. \p Align must be non-zero.
196 ///
197 /// Similar to the alignTo functions in MathExtras.h
alignTo(TypeSize Size,uint64_t Align)198 inline TypeSize alignTo(TypeSize Size, uint64_t Align) {
199 assert(Align != 0u && "Align must be non-zero");
200 return {(Size.getKnownMinSize() + Align - 1) / Align * Align,
201 Size.isScalable()};
202 }
203
204 } // end namespace llvm
205
206 #endif // LLVM_SUPPORT_TypeSize_H
207