• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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_CODEGEN_TYPE_INFO_H
17 #define COMPILER_OPTIMIZER_CODEGEN_TYPE_INFO_H
18 
19 /*
20 Arch-feature definitions
21 */
22 #include <bitset>
23 #include <cstdint>
24 #include <type_traits>
25 
26 #include "utils/arch.h"
27 #include "utils/arena_containers.h"
28 #include "utils/bit_field.h"
29 #include "utils/bit_utils.h"
30 #include "utils/regmask.h"
31 #include "compiler/optimizer/ir/constants.h"
32 #include "compiler/optimizer/ir/datatype.h"
33 #include "utils/type_helpers.h"
34 
35 namespace ark::compiler {
36 constexpr uint8_t BYTE_SIZE = 8;
37 constexpr uint8_t HALF_SIZE = 16;
38 constexpr uint8_t WORD_SIZE = 32;
39 constexpr uint8_t DOUBLE_WORD_SIZE = 64;
40 constexpr uint8_t HALF_WORD_SIZE_BYTES = 2;
41 constexpr uint8_t WORD_SIZE_BYTES = 4;
42 constexpr uint8_t DOUBLE_WORD_SIZE_BYTES = 8;
43 constexpr uint8_t QUAD_WORD_SIZE_BYTES = 16;
44 /// Maximum possible registers count (for scalar and for vector):
45 constexpr uint8_t MAX_NUM_REGS = 32;
46 constexpr uint8_t MAX_NUM_VREGS = 32;
47 
48 constexpr uint64_t NAN_DOUBLE = uint64_t(0x7ff8000000000000);
49 constexpr uint32_t NAN_FLOAT = uint32_t(0x7fc00000);
50 constexpr uint32_t NAN_FLOAT_BITS = NAN_FLOAT >> 16U;
51 
52 // Constants for cast from float to int64:
53 // The number of the bit from which exponential part starts in float
54 constexpr uint8_t START_EXP_FLOAT = 23;
55 // Size exponential part in float
56 constexpr uint8_t SIZE_EXP_FLOAT = 8;
57 // The maximum exponential part of float that can be loaded in int64
58 constexpr uint32_t POSSIBLE_EXP_FLOAT = 0xbe;
59 // Mask say that float number is NaN by IEEE 754
60 constexpr uint32_t UP_BITS_NAN_FLOAT = 0xff;
61 
62 // Constants for cast from double to int64:
63 // The number of the bit from which exponential part starts in double
64 constexpr uint8_t START_EXP_DOUBLE = 20;
65 // Size exponential part in double
66 constexpr uint8_t SIZE_EXP_DOUBLE = 11;
67 // The maximum exponential part of double that can be loaded in int64
68 constexpr uint32_t POSSIBLE_EXP_DOUBLE = 0x43e;
69 // Mask say that double number is NaN by IEEE 754
70 constexpr uint32_t UP_BITS_NAN_DOUBLE = 0x7ff;
71 
72 constexpr uint32_t SHIFT_BITS_DOUBLE = 12;
73 constexpr uint32_t SHIFT_BITS_FLOAT = 9;
74 
75 // Return true, if architecture can be encoded.
76 #ifdef PANDA_WITH_CODEGEN
77 bool BackendSupport(Arch arch);
78 #else
BackendSupport(Arch arch)79 inline bool BackendSupport([[maybe_unused]] Arch arch)
80 {
81     return false;
82 }
83 #endif
84 
85 //  Arch-independent access types
86 
87 /**
88  * Template class for identify types compile-time (nortti - can't use typeid).
89  * Used in register class. Immediate class support conversion to it.
90  */
91 class TypeInfo final {
92 public:
93     enum TypeId : uint8_t { INT8 = 0, INT16 = 1, INT32 = 2, INT64 = 3, FLOAT32 = 4, FLOAT64 = 5, INVALID = 6 };
94 
95     /// Template constructor - use template parameter for create object.
96     template <class T>
TypeInfo(T)97     constexpr explicit TypeInfo(T /* unused */)
98     {
99 #ifndef __clang_analyzer__
100         static_assert(std::is_arithmetic_v<T>);
101         if constexpr (std::is_same<T, uint8_t>()) {
102             typeId_ = INT8;
103         } else if constexpr (std::is_same<T, int8_t>()) {
104             typeId_ = INT8;
105         } else if constexpr (std::is_same<T, uint16_t>()) {
106             typeId_ = INT16;
107         } else if constexpr (std::is_same<T, int16_t>()) {
108             typeId_ = INT16;
109         } else if constexpr (std::is_same<T, uint32_t>()) {
110             typeId_ = INT32;
111         } else if constexpr (std::is_same<T, int32_t>()) {
112             typeId_ = INT32;
113         } else if constexpr (std::is_same<T, uint64_t>()) {
114             typeId_ = INT64;
115         } else if constexpr (std::is_same<T, int64_t>()) {
116             typeId_ = INT64;
117         } else if constexpr (std::is_same<T, float>()) {
118             typeId_ = FLOAT32;
119         } else if constexpr (std::is_same<T, double>()) {
120             typeId_ = FLOAT64;
121         } else {
122             typeId_ = INVALID;
123         }
124 #endif
125     }
126 
TypeInfo(TypeId type)127     constexpr explicit TypeInfo(TypeId type) : typeId_(type) {}
128 
129     DEFAULT_MOVE_SEMANTIC(TypeInfo);
130     DEFAULT_COPY_SEMANTIC(TypeInfo);
131     ~TypeInfo() = default;
132 
133     /// Constructor for create invalid TypeInfo
134     constexpr TypeInfo() = default;
135 
136     /// Validation check
IsValid()137     constexpr bool IsValid() const
138     {
139         return typeId_ != INVALID;
140     }
141 
142     /// Type expected size
GetSize()143     constexpr size_t GetSize() const
144     {
145         ASSERT(IsValid());
146         switch (typeId_) {
147             case INT8:
148                 return BYTE_SIZE;
149             case INT16:
150                 return HALF_SIZE;
151             case INT32:
152             case FLOAT32:
153                 return WORD_SIZE;
154             case INT64:
155             case FLOAT64:
156                 return DOUBLE_WORD_SIZE;
157             default:
158                 return 0;
159         }
160         return 0;
161     }
162 
IsFloat()163     constexpr bool IsFloat() const
164     {
165         ASSERT(IsValid());
166         return typeId_ == FLOAT32 || typeId_ == FLOAT64;
167     }
168 
IsScalar()169     constexpr bool IsScalar() const
170     {
171         // VOID - is scalar type here
172         return !IsFloat();
173     }
174 
175     constexpr bool operator==(const TypeInfo &other) const
176     {
177         return (typeId_ == other.typeId_);
178     }
179 
180     constexpr bool operator!=(const TypeInfo &other) const
181     {
182         return !operator==(other);
183     }
184 
FromDataType(DataType::Type type,Arch arch)185     static TypeInfo FromDataType(DataType::Type type, Arch arch)
186     {
187         switch (type) {
188             case DataType::BOOL:
189             case DataType::UINT8:
190             case DataType::INT8: {
191                 return TypeInfo(INT8);
192             }
193             case DataType::UINT16:
194             case DataType::INT16: {
195                 return TypeInfo(INT16);
196             }
197             case DataType::UINT32:
198             case DataType::INT32: {
199                 return TypeInfo(INT32);
200             }
201             case DataType::UINT64:
202             case DataType::INT64:
203             case DataType::ANY: {
204                 return TypeInfo(INT64);
205             }
206             case DataType::FLOAT32: {
207                 return TypeInfo(FLOAT32);
208             }
209             case DataType::FLOAT64: {
210                 return TypeInfo(FLOAT64);
211             }
212             case DataType::REFERENCE: {
213                 return FromDataType(DataType::GetIntTypeForReference(arch), arch);
214             }
215             case DataType::POINTER: {
216                 return Is64BitsArch(arch) ? TypeInfo(INT64) : TypeInfo(INT32);
217             }
218             default:
219                 UNREACHABLE();
220         }
221     }
222 
ToDataType()223     DataType::Type ToDataType() const
224     {
225         switch (typeId_) {
226             case INT8:
227                 return DataType::INT8;
228             case INT16:
229                 return DataType::INT16;
230             case INT32:
231                 return DataType::INT32;
232             case INT64:
233                 return DataType::INT64;
234             case FLOAT32:
235                 return DataType::FLOAT32;
236             case FLOAT64:
237                 return DataType::FLOAT64;
238             default:
239                 UNREACHABLE();
240         }
241     }
242 
243     static constexpr TypeInfo GetScalarTypeBySize(size_t sizeBits);
244 
Dump()245     void Dump()
246     {
247         std::cerr << "TypeInfo:";
248         switch (typeId_) {
249             case INT8:
250                 std::cerr << "INT8";
251                 break;
252             case INT16:
253                 std::cerr << "INT16";
254                 break;
255             case INT32:
256                 std::cerr << "INT32";
257                 break;
258             case FLOAT32:
259                 std::cerr << "FLOAT32";
260                 break;
261             case INT64:
262                 std::cerr << "INT64";
263                 break;
264             case FLOAT64:
265                 std::cerr << "FLOAT64";
266                 break;
267             default:
268                 std::cerr << "INVALID";
269                 break;
270         }
271         std::cerr << ", size = " << GetSize();
272     }
273 
274 private:
275     TypeId typeId_ {INVALID};
276 };
277 
278 constexpr TypeInfo INT8_TYPE {TypeInfo::INT8};
279 constexpr TypeInfo INT16_TYPE {TypeInfo::INT16};
280 constexpr TypeInfo INT32_TYPE {TypeInfo::INT32};
281 constexpr TypeInfo INT64_TYPE {TypeInfo::INT64};
282 constexpr TypeInfo FLOAT32_TYPE {TypeInfo::FLOAT32};
283 constexpr TypeInfo FLOAT64_TYPE {TypeInfo::FLOAT64};
284 constexpr TypeInfo INVALID_TYPE;
285 
GetScalarTypeBySize(size_t sizeBits)286 constexpr TypeInfo TypeInfo::GetScalarTypeBySize(size_t sizeBits)
287 {
288     auto type = INT64_TYPE;
289     if (sizeBits == BYTE_SIZE) {
290         type = INT8_TYPE;
291     } else if (sizeBits == HALF_SIZE) {
292         type = INT16_TYPE;
293     } else if (sizeBits == WORD_SIZE) {
294         type = INT32_TYPE;
295     }
296     return type;
297 }
298 
299 // Condition also used for tell comparison registers type
300 enum Condition {
301     EQ,  // equal to 0
302     NE,  // not equal to 0
303     // signed
304     LT,  // less
305     LE,  // less than or equal
306     GT,  // greater
307     GE,  // greater than or equal
308     // unsigned - checked from registers
309     LO,  // less
310     LS,  // less than or equal
311     HI,  // greater
312     HS,  // greater than or equal
313     // Special arch-dependecy NOTE (igorban) Fix them
314     MI,  // N set            Negative
315     PL,  // N clear          Positive or zero
316     VS,  // V set            Overflow.
317     VC,  // V clear          No overflow.
318     AL,  //                  Always.
319     NV,  // Behaves as always/al.
320 
321     TST_EQ,
322     TST_NE,
323 
324     INVALID_COND
325 };
326 
IsTestCc(Condition cond)327 inline bool IsTestCc(Condition cond)
328 {
329     return cond == TST_EQ || cond == TST_NE;
330 }
331 
332 }  // namespace ark::compiler
333 #endif  // COMPILER_OPTIMIZER_CODEGEN_TYPE_INFO_H
334