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 #include <random>
17 #include <gtest/gtest.h>
18
19 const uint64_t SEED = 0x1234;
20 #ifndef PANDA_NIGHTLY_TEST_ON
21 const uint64_t ITERATION = 20;
22 #else
23 const uint64_t ITERATION = 4000;
24 #endif
25 // NOLINTNEXTLINE(fuchsia-statically-constructed-objects,cert-msc51-cpp)
26 static auto g_randomGen = std::mt19937_64(SEED);
27
28 // Encoder header
29 #include "optimizer/code_generator/operands.h"
30
31 // NOLINTBEGIN(readability-isolate-declaration)
32 namespace ark::compiler {
33
34 class TypeInfoTest : public ::testing::Test {
35 public:
CheckValid()36 void CheckValid()
37 {
38 for (uint64_t i = 0; i < sizeof(arr_) / sizeof(TypeInfo); ++i) {
39 if (i >= 16U) { // NOLINT(readability-magic-numbers)
40 ASSERT_FALSE(arr_[i].IsValid());
41 } else {
42 ASSERT_TRUE(arr_[i].IsValid());
43 }
44 }
45 }
46
CheckSizes()47 void CheckSizes()
48 {
49 ASSERT_EQ(BYTE_SIZE, HALF_SIZE / 2U);
50 ASSERT_EQ(HALF_SIZE, WORD_SIZE / 2U);
51 ASSERT_EQ(WORD_SIZE, DOUBLE_WORD_SIZE / 2U);
52
53 ASSERT_EQ(arr_[0U].GetSize(), BYTE_SIZE);
54 ASSERT_EQ(arr_[1U].GetSize(), HALF_SIZE);
55 ASSERT_EQ(arr_[2U].GetSize(), WORD_SIZE);
56 ASSERT_EQ(arr_[3U].GetSize(), DOUBLE_WORD_SIZE);
57
58 ASSERT_EQ(sizeof(TypeInfo), sizeof(uint8_t));
59
60 ASSERT_EQ(TypeInfo(u8_), INT8_TYPE);
61 ASSERT_EQ(TypeInfo(u16_), INT16_TYPE);
62 ASSERT_EQ(TypeInfo(u32_), INT32_TYPE);
63 ASSERT_EQ(TypeInfo(u64_), INT64_TYPE);
64
65 ASSERT_EQ(TypeInfo(f32_), FLOAT32_TYPE);
66 ASSERT_EQ(TypeInfo(f64_), FLOAT64_TYPE);
67 // Float
68 ASSERT_EQ(arr_[2U].GetSize(), arr_[12U].GetSize());
69 ASSERT_EQ(arr_[2U].GetSize(), arr_[14U].GetSize());
70 // Double
71 ASSERT_EQ(arr_[3U].GetSize(), arr_[13U].GetSize());
72 ASSERT_EQ(arr_[3U].GetSize(), arr_[15U].GetSize());
73 }
74
CompareSizes()75 void CompareSizes()
76 {
77 for (size_t i = 0; i < 4U; ++i) {
78 ASSERT_EQ(arr_[i], arr_[4U + i]);
79 ASSERT_EQ(arr_[i], arr_[8U + i]);
80 ASSERT_EQ(arr_[4U + i], arr_[8U + i]);
81
82 ASSERT_EQ(arr_[i].GetSize(), arr_[4U + i].GetSize());
83 ASSERT_EQ(arr_[i].GetSize(), arr_[8U + i].GetSize());
84 ASSERT_EQ(arr_[4U + i].GetSize(), arr_[8U + i].GetSize());
85
86 ASSERT_TRUE(arr_[i].IsScalar());
87 ASSERT_TRUE(arr_[4U + i].IsScalar());
88 ASSERT_TRUE(arr_[8U + i].IsScalar());
89
90 ASSERT_FALSE(arr_[i].IsFloat());
91 ASSERT_FALSE(arr_[4U + i].IsFloat());
92 ASSERT_FALSE(arr_[8U + i].IsFloat());
93
94 ASSERT_NE(arr_[i], arr_[12U]);
95 ASSERT_NE(arr_[i], arr_[13U]);
96 ASSERT_NE(arr_[4U + i], arr_[12U]);
97 ASSERT_NE(arr_[4U + i], arr_[13U]);
98 ASSERT_NE(arr_[8U + i], arr_[12U]);
99 ASSERT_NE(arr_[8U + i], arr_[13U]);
100
101 ASSERT_NE(arr_[i], arr_[14U]);
102 ASSERT_NE(arr_[i], arr_[15U]);
103 ASSERT_NE(arr_[4U + i], arr_[14U]);
104 ASSERT_NE(arr_[4U + i], arr_[15U]);
105 ASSERT_NE(arr_[8U + i], arr_[14U]);
106 ASSERT_NE(arr_[8U + i], arr_[15U]);
107 ASSERT_NE(arr_[i], arr_[16U]);
108 ASSERT_NE(arr_[i], arr_[17U]);
109 ASSERT_NE(arr_[4U + i], arr_[16U]);
110 ASSERT_NE(arr_[4U + i], arr_[17U]);
111 ASSERT_NE(arr_[8U + i], arr_[16U]);
112 ASSERT_NE(arr_[8U + i], arr_[17U]);
113 }
114 }
115
CheckFloats()116 void CheckFloats()
117 {
118 // Float
119 ASSERT_TRUE(arr_[12U].IsValid());
120 ASSERT_TRUE(arr_[14U].IsValid());
121 ASSERT_TRUE(arr_[12U].IsFloat());
122 ASSERT_TRUE(arr_[14U].IsFloat());
123 }
124
125 private:
126 uint8_t u8_ = 0;
127 int8_t i8_ = 0;
128 uint16_t u16_ = 0;
129 int16_t i16_ = 0;
130 uint32_t u32_ = 0;
131 int32_t i32_ = 0;
132 uint64_t u64_ = 0;
133 int64_t i64_ = 0;
134
135 float f32_ = 0.0;
136 double f64_ = 0.0;
137
138 // NOLINTNEXTLINE(readability-magic-numbers)
139 std::array<TypeInfo, 18U> arr_ {
140 TypeInfo(u8_), // 0
141 TypeInfo(u16_),
142 TypeInfo(u32_),
143 TypeInfo(u64_),
144 TypeInfo(i8_), // 4
145 TypeInfo(i16_),
146 TypeInfo(i32_),
147 TypeInfo(i64_),
148 TypeInfo(INT8_TYPE), // 8
149 TypeInfo(INT16_TYPE),
150 TypeInfo(INT32_TYPE),
151 TypeInfo(INT64_TYPE),
152 TypeInfo(f32_), // 12
153 TypeInfo(f64_),
154 TypeInfo(FLOAT32_TYPE), // 14
155 TypeInfo(FLOAT64_TYPE),
156 TypeInfo(), // 16
157 INVALID_TYPE,
158 };
159 };
160
TEST_F(TypeInfoTest,Valid)161 TEST_F(TypeInfoTest, Valid)
162 {
163 CheckValid();
164 CheckFloats();
165 }
166
TEST_F(TypeInfoTest,Sizes)167 TEST_F(TypeInfoTest, Sizes)
168 {
169 CheckSizes();
170 CompareSizes();
171 }
172
TEST(Operands,Reg)173 TEST(Operands, Reg)
174 {
175 // Size of structure
176 ASSERT_LE(sizeof(Reg), sizeof(size_t));
177
178 ASSERT_EQ(INVALID_REGISTER.GetId(), INVALID_REG_ID);
179
180 // Check, what it is possible to create all 32 registers
181 // for each type
182
183 // Check what special registers are possible to compare with others
184
185 // Check equality between registers
186
187 // Check invalid registers
188 }
189
TEST(Operands,ImmUnsignedSmall)190 TEST(Operands, ImmUnsignedSmall)
191 {
192 // Check all possible types:
193 // Imm holds same data (static cast for un-signed)
194
195 for (uint64_t i = 0; i < ITERATION; ++i) {
196 uint8_t u8 = g_randomGen(), u8Z = 0U, u8Min = std::numeric_limits<uint8_t>::min(),
197 u8Max = std::numeric_limits<uint8_t>::max();
198 uint16_t u16 = g_randomGen(), u16Z = 0U, u16Min = std::numeric_limits<uint16_t>::min(),
199 u16Max = std::numeric_limits<uint16_t>::max();
200 // Unsigned part - check across static_cast
201
202 Imm immU8(u8), immU8Z(u8Z), immU8Min(u8Min), immU8Max(u8Max);
203 ASSERT_EQ(immU8.GetAsInt(), u8);
204 ASSERT_EQ(immU8Min.GetAsInt(), u8Min);
205 ASSERT_EQ(immU8Max.GetAsInt(), u8Max);
206 ASSERT_EQ(immU8Z.GetAsInt(), u8Z);
207
208 TypedImm typedImmU8(u8), typedImmU8Z(u8Z);
209 ASSERT_EQ(typedImmU8Z.GetType(), INT8_TYPE);
210 ASSERT_EQ(typedImmU8.GetType(), INT8_TYPE);
211 ASSERT_EQ(typedImmU8Z.GetImm().GetAsInt(), u8Z);
212 ASSERT_EQ(typedImmU8.GetImm().GetAsInt(), u8);
213
214 Imm immU16(u16), immU16Z(u16Z), immU16Min(u16Min), immU16Max(u16Max);
215 ASSERT_EQ(immU16.GetAsInt(), u16);
216 ASSERT_EQ(immU16Min.GetAsInt(), u16Min);
217 ASSERT_EQ(immU16Max.GetAsInt(), u16Max);
218 ASSERT_EQ(immU16Z.GetAsInt(), u16Z);
219
220 TypedImm typedImmU16(u16), typedImmU16Z(u16Z);
221 ASSERT_EQ(typedImmU16Z.GetType(), INT16_TYPE);
222 ASSERT_EQ(typedImmU16.GetType(), INT16_TYPE);
223 ASSERT_EQ(typedImmU16Z.GetImm().GetAsInt(), u16Z);
224 ASSERT_EQ(typedImmU16.GetImm().GetAsInt(), u16);
225 }
226
227 #ifndef NDEBUG
228 // Imm holds std::variant:
229 ASSERT_EQ(sizeof(Imm), sizeof(uint64_t) * 2U);
230 #else
231 // Imm holds 64-bit storage only:
232 ASSERT_EQ(sizeof(Imm), sizeof(uint64_t));
233 #endif // NDEBUG
234 }
235
TEST(Operands,ImmUnsignedLarge)236 TEST(Operands, ImmUnsignedLarge)
237 {
238 for (uint64_t i = 0; i < ITERATION; ++i) {
239 uint32_t u32 = g_randomGen(), u32Z = 0U, u32Min = std::numeric_limits<uint32_t>::min(),
240 u32Max = std::numeric_limits<uint32_t>::max();
241 uint64_t u64 = g_randomGen(), u64Z = 0U, u64Min = std::numeric_limits<uint64_t>::min(),
242 u64Max = std::numeric_limits<uint64_t>::max();
243
244 Imm immU32(u32), immU32Z(u32Z), immU32Min(u32Min), immU32Max(u32Max);
245 ASSERT_EQ(immU32.GetAsInt(), u32);
246 ASSERT_EQ(immU32Min.GetAsInt(), u32Min);
247 ASSERT_EQ(immU32Max.GetAsInt(), u32Max);
248 ASSERT_EQ(immU32Z.GetAsInt(), u32Z);
249
250 TypedImm typedImmU32(u32), typedImmU32Z(u32Z);
251 ASSERT_EQ(typedImmU32Z.GetType(), INT32_TYPE);
252 ASSERT_EQ(typedImmU32.GetType(), INT32_TYPE);
253 ASSERT_EQ(typedImmU32Z.GetImm().GetAsInt(), u32Z);
254 ASSERT_EQ(typedImmU32.GetImm().GetAsInt(), u32);
255
256 Imm immU64(u64), immU64Z(u64Z), immU64Min(u64Min), immU64Max(u64Max);
257 ASSERT_EQ(immU64.GetAsInt(), u64);
258 ASSERT_EQ(immU64Min.GetAsInt(), u64Min);
259 ASSERT_EQ(immU64Max.GetAsInt(), u64Max);
260 ASSERT_EQ(immU64Z.GetAsInt(), u64Z);
261
262 TypedImm typedImmU64(u64), typedImmU64Z(u64Z);
263 ASSERT_EQ(typedImmU64Z.GetType(), INT64_TYPE);
264 ASSERT_EQ(typedImmU64.GetType(), INT64_TYPE);
265 ASSERT_EQ(typedImmU64Z.GetImm().GetAsInt(), u64Z);
266 ASSERT_EQ(typedImmU64.GetImm().GetAsInt(), u64);
267 }
268 }
269
TEST(Operands,ImmSignedSmall)270 TEST(Operands, ImmSignedSmall)
271 {
272 for (uint64_t i = 0; i < ITERATION; ++i) {
273 // Signed part
274
275 int8_t i8 = g_randomGen(), i8Z = 0U, i8Min = std::numeric_limits<int8_t>::min(),
276 i8Max = std::numeric_limits<int8_t>::max();
277 int16_t i16 = g_randomGen(), i16Z = 0U, i16Min = std::numeric_limits<int16_t>::min(),
278 i16Max = std::numeric_limits<int16_t>::max();
279
280 Imm immI8(i8), immI8Z(i8Z), immI8Min(i8Min), immI8Max(i8Max);
281 ASSERT_EQ(immI8.GetAsInt(), i8);
282 ASSERT_EQ(immI8Min.GetAsInt(), i8Min);
283 ASSERT_EQ(immI8Max.GetAsInt(), i8Max);
284 ASSERT_EQ(immI8Z.GetAsInt(), i8Z);
285
286 TypedImm typedImmI8(i8), typedImmI8Z(i8Z);
287 ASSERT_EQ(typedImmI8Z.GetType(), INT8_TYPE);
288 ASSERT_EQ(typedImmI8.GetType(), INT8_TYPE);
289 ASSERT_EQ(typedImmI8Z.GetImm().GetAsInt(), i8Z);
290 ASSERT_EQ(typedImmI8.GetImm().GetAsInt(), i8);
291
292 Imm immI16(i16), immI16Z(i16Z), immI16Min(i16Min), immI16Max(i16Max);
293 ASSERT_EQ(immI16.GetAsInt(), i16);
294 ASSERT_EQ(immI16Min.GetAsInt(), i16Min);
295 ASSERT_EQ(immI16Max.GetAsInt(), i16Max);
296 ASSERT_EQ(immI16Z.GetAsInt(), i16Z);
297
298 TypedImm typedImmI16(i16), typedImmI16Z(i16Z);
299 ASSERT_EQ(typedImmI16Z.GetType(), INT16_TYPE);
300 ASSERT_EQ(typedImmI16.GetType(), INT16_TYPE);
301 ASSERT_EQ(typedImmI16Z.GetImm().GetAsInt(), i16Z);
302 ASSERT_EQ(typedImmI16.GetImm().GetAsInt(), i16);
303 }
304 }
305
TEST(Operands,ImmSignedLarge)306 TEST(Operands, ImmSignedLarge)
307 {
308 for (uint64_t i = 0; i < ITERATION; ++i) {
309 int32_t i32 = g_randomGen(), i32Z = 0U, i32Min = std::numeric_limits<int32_t>::min(),
310 i32Max = std::numeric_limits<int32_t>::max();
311 int64_t i64 = g_randomGen(), i64Z = 0U, i64Min = std::numeric_limits<int64_t>::min(),
312 i64Max = std::numeric_limits<int64_t>::max();
313
314 Imm immI32(i32), immI32Z(i32Z), immI32Min(i32Min), immI32Max(i32Max);
315 ASSERT_EQ(immI32.GetAsInt(), i32);
316 ASSERT_EQ(immI32Min.GetAsInt(), i32Min);
317 ASSERT_EQ(immI32Max.GetAsInt(), i32Max);
318 ASSERT_EQ(immI32Z.GetAsInt(), i32Z);
319
320 TypedImm typedImmI32(i32), typedImmI32Z(i32Z);
321 ASSERT_EQ(typedImmI32Z.GetType(), INT32_TYPE);
322 ASSERT_EQ(typedImmI32.GetType(), INT32_TYPE);
323 ASSERT_EQ(typedImmI32Z.GetImm().GetAsInt(), i32Z);
324 ASSERT_EQ(typedImmI32.GetImm().GetAsInt(), i32);
325
326 Imm immI64(i64), immI64Z(i64Z), immI64Min(i64Min), immI64Max(i64Max);
327 ASSERT_EQ(immI64.GetAsInt(), i64);
328 ASSERT_EQ(immI64Min.GetAsInt(), i64Min);
329 ASSERT_EQ(immI64Max.GetAsInt(), i64Max);
330 ASSERT_EQ(immI64Z.GetAsInt(), i64Z);
331
332 TypedImm typedImmI64(i64), typedImmI64Z(i64Z);
333 ASSERT_EQ(typedImmI64Z.GetType(), INT64_TYPE);
334 ASSERT_EQ(typedImmI64.GetType(), INT64_TYPE);
335 ASSERT_EQ(typedImmI64Z.GetImm().GetAsInt(), i64Z);
336 ASSERT_EQ(typedImmI64.GetImm().GetAsInt(), i64);
337 }
338 }
339
TEST(Operands,ImmFloat)340 TEST(Operands, ImmFloat)
341 {
342 for (uint64_t i = 0; i < ITERATION; ++i) {
343 float f32 = g_randomGen(), f32Z = 0.0, f32Min = std::numeric_limits<float>::min(),
344 f32Max = std::numeric_limits<float>::max();
345 double f64 = g_randomGen(), f64Z = 0.0, f64Min = std::numeric_limits<double>::min(),
346 f64Max = std::numeric_limits<double>::max();
347
348 // Float test:
349 Imm immF32(f32), immF32Z(f32Z), immF32Min(f32Min), immF32Max(f32Max);
350 ASSERT_EQ(immF32.GetAsFloat(), f32);
351 ASSERT_EQ(immF32Min.GetAsFloat(), f32Min);
352 ASSERT_EQ(immF32Max.GetAsFloat(), f32Max);
353 ASSERT_EQ(immF32Z.GetAsFloat(), f32Z);
354 ASSERT_EQ(bit_cast<float>(static_cast<int32_t>(immF32.GetRawValue())), f32);
355 ASSERT_EQ(bit_cast<float>(static_cast<int32_t>(immF32Min.GetRawValue())), f32Min);
356 ASSERT_EQ(bit_cast<float>(static_cast<int32_t>(immF32Max.GetRawValue())), f32Max);
357 ASSERT_EQ(bit_cast<float>(static_cast<int32_t>(immF32Z.GetRawValue())), f32Z);
358
359 TypedImm typedImmF32(f32), typedImmF32Z(f32Z);
360 ASSERT_EQ(typedImmF32Z.GetType(), FLOAT32_TYPE);
361 ASSERT_EQ(typedImmF32.GetType(), FLOAT32_TYPE);
362 ASSERT_EQ(typedImmF32Z.GetImm().GetAsFloat(), f32Z);
363 ASSERT_EQ(typedImmF32.GetImm().GetAsFloat(), f32);
364
365 Imm immF64(f64), immF64Z(f64Z), immF64Min(f64Min), immF64Max(f64Max);
366 ASSERT_EQ(immF64.GetAsDouble(), f64);
367 ASSERT_EQ(immF64Min.GetAsDouble(), f64Min);
368 ASSERT_EQ(immF64Max.GetAsDouble(), f64Max);
369 ASSERT_EQ(immF64Z.GetAsDouble(), f64Z);
370 ASSERT_EQ(bit_cast<double>(immF64.GetRawValue()), f64);
371 ASSERT_EQ(bit_cast<double>(immF64Min.GetRawValue()), f64Min);
372 ASSERT_EQ(bit_cast<double>(immF64Max.GetRawValue()), f64Max);
373 ASSERT_EQ(bit_cast<double>(immF64Z.GetRawValue()), f64Z);
374
375 TypedImm typedImmF64(f64), typedImmF64Z(f64Z);
376 ASSERT_EQ(typedImmF64Z.GetType(), FLOAT64_TYPE);
377 ASSERT_EQ(typedImmF64.GetType(), FLOAT64_TYPE);
378 ASSERT_EQ(typedImmF64Z.GetImm().GetAsDouble(), f64Z);
379 ASSERT_EQ(typedImmF64.GetImm().GetAsDouble(), f64);
380 }
381 }
382
TEST(Operands,MemRef)383 TEST(Operands, MemRef)
384 {
385 Reg r1(1U, INT64_TYPE), r2(2U, INT64_TYPE), rI(INVALID_REG_ID, INVALID_TYPE);
386 ssize_t i1(0x0U), i2(0x2U);
387
388 // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
389 std::array<MemRef, 3U> arr {MemRef(r1), MemRef(r1, i1), MemRef(r1)};
390 // 1. Check constructors
391 // for getters
392 // for validness
393 // for operator ==
394 // 2. Create mem with invalid_reg / invalid imm
395 }
396 // NOLINTEND(readability-isolate-declaration)
397
398 } // namespace ark::compiler
399