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