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
96 // CC-OFFNXT(G.FUD.06) switch-case, ODR
GetCommonType(Type type)97 constexpr inline Type GetCommonType(Type type)
98 {
99 switch (type) {
100 case Type::BOOL:
101 case Type::UINT8:
102 case Type::INT8:
103 case Type::UINT16:
104 case Type::INT16:
105 case Type::UINT32:
106 case Type::INT32:
107 case Type::UINT64:
108 case Type::INT64:
109 return Type::INT64;
110 case Type::REFERENCE:
111 case Type::POINTER:
112 return Type::POINTER;
113 default:
114 return type;
115 };
116 }
117
118 // CC-OFFNXT(G.FUD.06) switch-case, ODR
IsInt32Bit(Type type)119 inline bool IsInt32Bit(Type type)
120 {
121 switch (type) {
122 case Type::BOOL:
123 case Type::UINT8:
124 case Type::INT8:
125 case Type::UINT16:
126 case Type::INT16:
127 case Type::UINT32:
128 case Type::INT32:
129 return true;
130 default:
131 return false;
132 };
133 }
134
135 // CC-OFFNXT(G.FUD.06) switch-case, ODR
IsTypeNumeric(Type type)136 inline bool IsTypeNumeric(Type type)
137 {
138 switch (type) {
139 case BOOL:
140 case UINT8:
141 case INT8:
142 case UINT16:
143 case INT16:
144 case UINT32:
145 case INT32:
146 case UINT64:
147 case INT64:
148 case FLOAT32:
149 case FLOAT64:
150 case POINTER:
151 return true;
152 default:
153 return false;
154 }
155 }
156
IsLessInt32(Type type)157 inline bool IsLessInt32(Type type)
158 {
159 switch (type) {
160 case BOOL:
161 case UINT8:
162 case INT8:
163 case UINT16:
164 case INT16:
165 return true;
166 default:
167 return false;
168 }
169 }
170
171 // CC-OFFNXT(G.FUD.06) switch-case, ODR
GetIntTypeForReference(Arch arch)172 inline Type GetIntTypeForReference([[maybe_unused]] Arch arch)
173 {
174 // This is necessary for arm32 cross compilation
175 if (arch == Arch::AARCH32) {
176 return UINT32;
177 }
178
179 if constexpr (ark::OBJECT_POINTER_SIZE == sizeof(uint64_t)) {
180 return UINT64;
181 } else if constexpr (ark::OBJECT_POINTER_SIZE == sizeof(uint32_t)) {
182 return UINT32;
183 } else if constexpr (ark::OBJECT_POINTER_SIZE == sizeof(uint16_t)) {
184 UNREACHABLE_CONSTEXPR();
185 return UINT16;
186 } else {
187 UNREACHABLE_CONSTEXPR();
188 return UINT8;
189 }
190 }
191
192 // CC-OFFNXT(G.FUD.06) switch-case, ODR
193 constexpr inline Type GetIntTypeBySize(size_t sizeInBytes, bool isSigned = false)
194 {
195 if (sizeInBytes <= sizeof(uint8_t)) {
196 return isSigned ? INT8 : UINT8;
197 }
198 if (sizeInBytes <= sizeof(uint16_t)) {
199 return isSigned ? INT16 : UINT16;
200 }
201 if (sizeInBytes <= sizeof(uint32_t)) {
202 return isSigned ? INT32 : UINT32;
203 }
204 if (sizeInBytes <= sizeof(uint64_t)) {
205 return isSigned ? INT64 : UINT64;
206 }
207 UNREACHABLE_CONSTEXPR();
208 return NO_TYPE;
209 }
210
211 // CC-OFFNXT(G.FUD.06) switch-case, ODR
Is32Bits(Type type,Arch arch)212 inline bool Is32Bits(Type type, Arch arch)
213 {
214 switch (type) {
215 case BOOL:
216 case UINT8:
217 case INT8:
218 case UINT16:
219 case INT16:
220 case UINT32:
221 case INT32:
222 case FLOAT32:
223 return true;
224 case POINTER:
225 return !Is64BitsArch(arch);
226 case REFERENCE:
227 return Is32Bits(GetIntTypeForReference(arch), arch);
228 default:
229 return false;
230 }
231 }
232
Is64Bits(Type type,Arch arch)233 inline bool Is64Bits(Type type, Arch arch)
234 {
235 return !Is32Bits(type, arch);
236 }
237
IsFloatType(Type type)238 inline bool IsFloatType(Type type)
239 {
240 switch (type) {
241 case FLOAT32:
242 case FLOAT64:
243 return true;
244 default:
245 return false;
246 }
247 }
248
249 // CC-OFFNXT(G.FUD.06) switch-case, ODR
IsTypeSigned(Type type)250 inline bool IsTypeSigned(Type type)
251 {
252 switch (type) {
253 case INT8:
254 case INT16:
255 case INT32:
256 case INT64:
257 case FLOAT32:
258 case FLOAT64:
259 return true;
260 default:
261 return false;
262 }
263 }
264
IsReference(Type type)265 inline bool IsReference(Type type)
266 {
267 return type == REFERENCE;
268 }
269
270 // CC-OFFNXT(G.FUD.06) switch-case, ODR
ShiftByType(Type type,Arch arch)271 inline uint8_t ShiftByType(Type type, Arch arch)
272 {
273 switch (type) {
274 case VOID:
275 case BOOL:
276 case UINT8:
277 case INT8:
278 return 0;
279 case UINT16:
280 case INT16:
281 return 1;
282 case UINT32:
283 case INT32:
284 case FLOAT32:
285 return 2U;
286 case UINT64:
287 case INT64:
288 case FLOAT64:
289 case ANY:
290 return 3U;
291 case REFERENCE:
292 return ShiftByType(GetIntTypeForReference(arch), arch);
293 case POINTER:
294 return Is64BitsArch(arch) ? 3U : 2U;
295 default:
296 UNREACHABLE();
297 return 0;
298 }
299 }
300
GetTypeSize(Type type,Arch arch)301 inline uint8_t GetTypeSize(Type type, Arch arch)
302 {
303 // NOLINTNEXTLINE(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers)
304 return 8U << ShiftByType(type, arch);
305 }
306
GetTypeByteSize(Type type,Arch arch)307 inline uint8_t GetTypeByteSize(Type type, Arch arch)
308 {
309 // NOLINTNEXTLINE(readability-magic-numbers, cppcoreguidelines-avoid-magic-numbers)
310 return 1U << ShiftByType(type, arch);
311 }
312
NeedCastIntTypes(Arch arch,DataType::Type typeBefore,DataType::Type typeAfter)313 inline bool NeedCastIntTypes(Arch arch, DataType::Type typeBefore, DataType::Type typeAfter)
314 {
315 auto sizeBefore = DataType::GetTypeSize(typeBefore, arch);
316 auto sizeAfter = DataType::GetTypeSize(typeAfter, arch);
317
318 // In our ISA minimal type is 32-bit, so type less then 32-bit we should extend to 32-bit.
319 // Thereby we may to avoid some casts.
320 constexpr auto NUM_BITS_INT32 = 32U;
321 bool extendNotNeed = sizeBefore < sizeAfter && sizeAfter <= NUM_BITS_INT32;
322 return !extendNotNeed || DataType::IsTypeSigned(typeBefore) != DataType::IsTypeSigned(typeAfter);
323 }
324
NeedCastForTypes(Arch arch,DataType::Type typeBefore,DataType::Type typeAfter)325 inline bool NeedCastForTypes(Arch arch, DataType::Type typeBefore, DataType::Type typeAfter)
326 {
327 // If types is equal, we avoid cast
328 if (typeBefore == typeAfter) {
329 return false;
330 }
331
332 // There are types left here: int and float
333 ASSERT(DataType::IsTypeNumeric(typeBefore) && DataType::IsTypeNumeric(typeAfter));
334 if (DataType::IsFloatType(typeBefore) || DataType::IsFloatType(typeAfter)) {
335 return true;
336 }
337
338 // There are types left here: int
339 return NeedCastIntTypes(arch, typeBefore, typeAfter);
340 }
341
342 } // namespace DataType
343 } // namespace ark::compiler
344
345 #endif // COMPILER_OPTIMIZER_IR_DATATYPE_H
346