1 /*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef COMPILER_OPTIMIZER_IR_DATATYPE_H
17 #define COMPILER_OPTIMIZER_IR_DATATYPE_H
18
19 #include "macros.h"
20 #include "utils/arch.h"
21 #include "mem/mem.h"
22
23 // NOLINTNEXTLINE(modernize-concat-nested-namespaces)
24 namespace ark::compiler {
25 /*
26 * Type of the param/instruction
27 */
28 // NOLINTNEXTLINE(readability-identifier-naming)
29 namespace DataType {
30 enum Type : uint8_t {
31 NO_TYPE = 0,
32 REFERENCE,
33 BOOL,
34 UINT8,
35 INT8,
36 UINT16,
37 INT16,
38 UINT32,
39 INT32,
40 UINT64,
41 INT64,
42 FLOAT32,
43 FLOAT64,
44 ANY,
45 VOID,
46 POINTER,
47 LAST = POINTER
48 };
49
50 class Any {
51 public:
Any(uint64_t value)52 explicit Any(uint64_t value) : value_(value) {}
53
Raw()54 uint64_t Raw() const
55 {
56 return value_;
57 }
58
59 private:
60 uint64_t value_ {0};
61 };
62
63 namespace internal {
64 inline constexpr std::array<const char *, Type::LAST + 1> TYPE_NAMES = {
65 "", // NO_TYPE
66 "ref", // REFERENCE
67 "b", // BOOL
68 "u8", // UINT8
69 "i8", // INT8
70 "u16", // UINT16
71 "i16", // INT16
72 "u32", // UINT32
73 "i32", // INT32
74 "u64", // UINT64
75 "i64", // INT64
76 "f32", // FLOAT32
77 "f64", // FLOAT64
78 "any", // ANY
79 "void", // VOID
80 "ptr" // POINTER
81 };
82 } // namespace internal
83
ToString(Type type)84 inline const char *ToString(Type type)
85 {
86 ASSERT(type <= Type::LAST);
87 return internal::TYPE_NAMES[type];
88 }
89
90 inline std::ostream &operator<<(std::ostream &os, const DataType::Type &type)
91 {
92 os << ToString(type);
93 return os;
94 }
95
GetCommonType(Type type)96 constexpr inline Type GetCommonType(Type type)
97 {
98 switch (type) {
99 case Type::BOOL:
100 case Type::UINT8:
101 case Type::INT8:
102 case Type::UINT16:
103 case Type::INT16:
104 case Type::UINT32:
105 case Type::INT32:
106 case Type::UINT64:
107 case Type::INT64:
108 return Type::INT64;
109 case Type::REFERENCE:
110 case Type::POINTER:
111 return Type::POINTER;
112 default:
113 return type;
114 };
115 }
116
IsInt32Bit(Type type)117 inline bool IsInt32Bit(Type type)
118 {
119 switch (type) {
120 case Type::BOOL:
121 case Type::UINT8:
122 case Type::INT8:
123 case Type::UINT16:
124 case Type::INT16:
125 case Type::UINT32:
126 case Type::INT32:
127 return true;
128 default:
129 return false;
130 };
131 }
132
IsTypeNumeric(Type type)133 inline bool IsTypeNumeric(Type type)
134 {
135 switch (type) {
136 case BOOL:
137 case UINT8:
138 case INT8:
139 case UINT16:
140 case INT16:
141 case UINT32:
142 case INT32:
143 case UINT64:
144 case INT64:
145 case FLOAT32:
146 case FLOAT64:
147 case POINTER:
148 return true;
149 default:
150 return false;
151 }
152 }
153
IsLessInt32(Type type)154 inline bool IsLessInt32(Type type)
155 {
156 switch (type) {
157 case BOOL:
158 case UINT8:
159 case INT8:
160 case UINT16:
161 case INT16:
162 return true;
163 default:
164 return false;
165 }
166 }
167
GetIntTypeForReference(Arch arch)168 inline Type GetIntTypeForReference([[maybe_unused]] Arch arch)
169 {
170 // This is necessary for arm32 cross compilation
171 if (arch == Arch::AARCH32) {
172 return UINT32;
173 }
174
175 if constexpr (ark::OBJECT_POINTER_SIZE == sizeof(uint64_t)) {
176 return UINT64;
177 } else if constexpr (ark::OBJECT_POINTER_SIZE == sizeof(uint32_t)) {
178 return UINT32;
179 } else if constexpr (ark::OBJECT_POINTER_SIZE == sizeof(uint16_t)) {
180 UNREACHABLE_CONSTEXPR();
181 return UINT16;
182 } else {
183 UNREACHABLE_CONSTEXPR();
184 return UINT8;
185 }
186 }
187
188 constexpr inline Type GetIntTypeBySize(size_t sizeInBytes, bool isSigned = false)
189 {
190 if (sizeInBytes <= sizeof(uint8_t)) {
191 return isSigned ? INT8 : UINT8;
192 }
193 if (sizeInBytes <= sizeof(uint16_t)) {
194 return isSigned ? INT16 : UINT16;
195 }
196 if (sizeInBytes <= sizeof(uint32_t)) {
197 return isSigned ? INT32 : UINT32;
198 }
199 if (sizeInBytes <= sizeof(uint64_t)) {
200 return isSigned ? INT64 : UINT64;
201 }
202 UNREACHABLE_CONSTEXPR();
203 return NO_TYPE;
204 }
205
Is32Bits(Type type,Arch arch)206 inline bool Is32Bits(Type type, Arch arch)
207 {
208 switch (type) {
209 case BOOL:
210 case UINT8:
211 case INT8:
212 case UINT16:
213 case INT16:
214 case UINT32:
215 case INT32:
216 case FLOAT32:
217 return true;
218 case POINTER:
219 return !Is64BitsArch(arch);
220 case REFERENCE:
221 return Is32Bits(GetIntTypeForReference(arch), arch);
222 default:
223 return false;
224 }
225 }
226
Is64Bits(Type type,Arch arch)227 inline bool Is64Bits(Type type, Arch arch)
228 {
229 return !Is32Bits(type, arch);
230 }
231
IsFloatType(Type type)232 inline bool IsFloatType(Type type)
233 {
234 switch (type) {
235 case FLOAT32:
236 case FLOAT64:
237 return true;
238 default:
239 return false;
240 }
241 }
242
IsTypeSigned(Type type)243 inline bool IsTypeSigned(Type type)
244 {
245 switch (type) {
246 case INT8:
247 case INT16:
248 case INT32:
249 case INT64:
250 case FLOAT32:
251 case FLOAT64:
252 return true;
253 default:
254 return false;
255 }
256 }
257
IsReference(Type type)258 inline bool IsReference(Type type)
259 {
260 return type == REFERENCE;
261 }
262
ShiftByType(Type type,Arch arch)263 inline uint8_t ShiftByType(Type type, Arch arch)
264 {
265 switch (type) {
266 case VOID:
267 case BOOL:
268 case UINT8:
269 case INT8:
270 return 0;
271 case UINT16:
272 case INT16:
273 return 1;
274 case UINT32:
275 case INT32:
276 case FLOAT32:
277 return 2U;
278 case UINT64:
279 case INT64:
280 case FLOAT64:
281 case ANY:
282 return 3U;
283 case REFERENCE:
284 return ShiftByType(GetIntTypeForReference(arch), arch);
285 case POINTER:
286 return Is64BitsArch(arch) ? 3U : 2U;
287 default:
288 UNREACHABLE();
289 return 0;
290 }
291 }
292
GetTypeSize(Type type,Arch arch)293 inline uint8_t GetTypeSize(Type type, Arch arch)
294 {
295 // NOLINTNEXTLINE(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers)
296 return 8U << ShiftByType(type, arch);
297 }
298
GetTypeByteSize(Type type,Arch arch)299 inline uint8_t GetTypeByteSize(Type type, Arch arch)
300 {
301 // NOLINTNEXTLINE(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers)
302 return 1U << ShiftByType(type, arch);
303 }
304
NeedCastIntTypes(Arch arch,DataType::Type typeBefore,DataType::Type typeAfter)305 inline bool NeedCastIntTypes(Arch arch, DataType::Type typeBefore, DataType::Type typeAfter)
306 {
307 auto sizeBefore = DataType::GetTypeSize(typeBefore, arch);
308 auto sizeAfter = DataType::GetTypeSize(typeAfter, arch);
309
310 // In our ISA minimal type is 32-bit, so type less then 32-bit we should extend to 32-bit.
311 // Thereby we may to avoid some casts.
312 constexpr auto NUM_BITS_INT32 = 32U;
313 bool extendNotNeed = sizeBefore < sizeAfter && sizeAfter <= NUM_BITS_INT32;
314 return !extendNotNeed || DataType::IsTypeSigned(typeBefore) != DataType::IsTypeSigned(typeAfter);
315 }
316
NeedCastForTypes(Arch arch,DataType::Type typeBefore,DataType::Type typeAfter)317 inline bool NeedCastForTypes(Arch arch, DataType::Type typeBefore, DataType::Type typeAfter)
318 {
319 // If types is equal, we avoid cast
320 if (typeBefore == typeAfter) {
321 return false;
322 }
323
324 // There are types left here: int and float
325 ASSERT(DataType::IsTypeNumeric(typeBefore) && DataType::IsTypeNumeric(typeAfter));
326 if (DataType::IsFloatType(typeBefore) || DataType::IsFloatType(typeAfter)) {
327 return true;
328 }
329
330 // There are types left here: int
331 return NeedCastIntTypes(arch, typeBefore, typeAfter);
332 }
333
334 } // namespace DataType
335 } // namespace ark::compiler
336
337 #endif // COMPILER_OPTIMIZER_IR_DATATYPE_H
338