1 /**
2 * Copyright (c) 2021-2022 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 #include "mem/code_allocator.h"
20 #include "mem/pool_manager.h"
21 #include "target/aarch32/target.h"
22 #include "mem/base_mem_stats.h"
23
24 const uint64_t SEED = 0x1234;
25 #ifndef PANDA_NIGHTLY_TEST_ON
26 const uint64_t ITERATION = 40;
27 #else
28 const uint64_t ITERATION = 0xffffff;
29 #endif
30 static inline auto random_gen = std::mt19937_64(SEED);
31
32 namespace panda::compiler {
33 class Callconv32Test : public ::testing::Test {
34 public:
Callconv32Test()35 Callconv32Test()
36 {
37 panda::mem::MemConfig::Initialize(64_MB, 64_MB, 64_MB, 32_MB);
38 PoolManager::Initialize();
39 allocator_ = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER);
40 encoder_ = Encoder::Create(allocator_, Arch::AARCH32, false);
41 encoder_->InitMasm();
42 regfile_ = RegistersDescription::Create(allocator_, Arch::AARCH32);
43 callconv_ = CallingConvention::Create(allocator_, encoder_, regfile_, Arch::AARCH32);
44 mem_stats_ = new BaseMemStats();
45 code_alloc_ = new (std::nothrow) CodeAllocator(mem_stats_);
46 }
~Callconv32Test()47 ~Callconv32Test()
48 {
49 Logger::Destroy();
50 encoder_->~Encoder();
51 delete allocator_;
52 delete code_alloc_;
53 delete mem_stats_;
54 PoolManager::Finalize();
55 panda::mem::MemConfig::Finalize();
56 }
57
GetAllocator()58 ArenaAllocator *GetAllocator()
59 {
60 return allocator_;
61 }
62
GetEncoder()63 Encoder *GetEncoder()
64 {
65 return encoder_;
66 }
67
GetRegfile()68 RegistersDescription *GetRegfile()
69 {
70 return regfile_;
71 }
72
GetCallconv()73 CallingConvention *GetCallconv()
74 {
75 return callconv_;
76 }
77
78 private:
79 ArenaAllocator *allocator_ {nullptr};
80 Encoder *encoder_ {nullptr};
81 RegistersDescription *regfile_ {nullptr};
82 CallingConvention *callconv_ {nullptr};
83 CodeAllocator *code_alloc_ {nullptr};
84 BaseMemStats *mem_stats_ {nullptr};
85 };
86
87 #if (PANDA_TARGET_ARM32_ABI_HARD)
88 #define FLOAT_PARAM_TYPE FLOAT32_TYPE
89 #define DOUBLE_PARAM_TYPE FLOAT64_TYPE
90 #else
91 #define FLOAT_PARAM_TYPE INT32_TYPE
92 #define DOUBLE_PARAM_TYPE INT64_TYPE
93 #endif
94
TEST_F(Callconv32Test,NativeParams)95 TEST_F(Callconv32Test, NativeParams)
96 {
97 // Test for
98 // std::variant<Reg, uint8_t> GetNativeParam(const TypeInfo& type)
99
100 // 4 uint8_t params - in registers
101 {
102 ArenaVector<TypeInfo> tmp(GetAllocator()->Adapter());
103 auto param_info = GetCallconv()->GetParameterInfo(0);
104 auto ret = param_info->GetNativeParam(INT8_TYPE);
105 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
106 EXPECT_EQ(std::get<Reg>(ret).GetId(), 0);
107 EXPECT_EQ(std::get<Reg>(ret), Reg(0, INT8_TYPE));
108
109 for (uint32_t i = 1; i <= 3; ++i) {
110 ret = param_info->GetNativeParam(INT8_TYPE);
111 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
112 EXPECT_EQ(std::get<Reg>(ret).GetId(), i);
113 EXPECT_EQ(std::get<Reg>(ret), Reg(i, INT8_TYPE));
114 }
115 }
116
117 // 4 uint32_t params - in registers
118 {
119 auto param_info = GetCallconv()->GetParameterInfo(0);
120 auto ret = param_info->GetNativeParam(INT32_TYPE);
121 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
122 EXPECT_EQ(std::get<Reg>(ret).GetId(), 0);
123 EXPECT_EQ(std::get<Reg>(ret), Reg(0, INT32_TYPE));
124
125 for (uint32_t i = 1; i <= 3; ++i) {
126 ret = param_info->GetNativeParam(INT32_TYPE);
127 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
128 EXPECT_EQ(std::get<Reg>(ret).GetId(), i);
129 EXPECT_EQ(std::get<Reg>(ret), Reg(i, INT32_TYPE));
130 }
131 }
132
133 // 2 uint64_t params - in registers
134 {
135 auto param_info = GetCallconv()->GetParameterInfo(0);
136 auto ret = param_info->GetNativeParam(INT64_TYPE);
137 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
138 EXPECT_EQ(std::get<Reg>(ret).GetId(), 0);
139 EXPECT_EQ(std::get<Reg>(ret), Reg(0, INT64_TYPE));
140
141 ret = param_info->GetNativeParam(INT64_TYPE);
142 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
143 EXPECT_EQ(std::get<Reg>(ret).GetId(), 2);
144 EXPECT_EQ(std::get<Reg>(ret), Reg(2, INT64_TYPE));
145 }
146
147 // 4 float params - in registers
148 {
149 auto param_info = GetCallconv()->GetParameterInfo(0);
150 auto ret = param_info->GetNativeParam(FLOAT32_TYPE);
151 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
152 EXPECT_EQ(std::get<Reg>(ret).GetId(), 0);
153 EXPECT_EQ(std::get<Reg>(ret), Reg(0, FLOAT_PARAM_TYPE));
154
155 for (uint32_t i = 1; i <= 3; ++i) {
156 ret = param_info->GetNativeParam(FLOAT32_TYPE);
157 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
158 EXPECT_EQ(std::get<Reg>(ret).GetId(), i);
159 EXPECT_EQ(std::get<Reg>(ret), Reg(i, FLOAT_PARAM_TYPE));
160 }
161 }
162
163 // 2 double params - in registers
164 {
165 auto param_info = GetCallconv()->GetParameterInfo(0);
166 auto ret = param_info->GetNativeParam(FLOAT64_TYPE);
167 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
168 EXPECT_EQ(std::get<Reg>(ret).GetId(), 0);
169 EXPECT_EQ(std::get<Reg>(ret), Reg(0, DOUBLE_PARAM_TYPE));
170
171 ret = param_info->GetNativeParam(FLOAT64_TYPE);
172 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
173 EXPECT_EQ(std::get<Reg>(ret).GetId(), 2);
174 EXPECT_EQ(std::get<Reg>(ret), Reg(2, DOUBLE_PARAM_TYPE));
175 }
176
177 // int8_t uin64_t int8_t int64_t int8_t int8_t in32_t int64_t
178 // r0 r2+r3 stack0 stack2(align) stack4 stack5 stack6 stack8(align)
179 // r1 stack1 stack7 - missed by align
180 {
181 auto param_info = GetCallconv()->GetParameterInfo(0);
182 auto ret = param_info->GetNativeParam(INT8_TYPE);
183 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
184 EXPECT_EQ(std::get<Reg>(ret).GetId(), 0);
185 EXPECT_EQ(std::get<Reg>(ret), Reg(0, INT8_TYPE));
186
187 ret = param_info->GetNativeParam(INT64_TYPE);
188 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
189 EXPECT_EQ(std::get<Reg>(ret).GetId(), 2);
190 EXPECT_EQ(std::get<Reg>(ret), Reg(2, INT64_TYPE));
191
192 ret = param_info->GetNativeParam(INT8_TYPE);
193 EXPECT_TRUE(std::holds_alternative<uint8_t>(ret));
194 EXPECT_EQ(std::get<uint8_t>(ret), 0);
195
196 ret = param_info->GetNativeParam(INT64_TYPE);
197 EXPECT_TRUE(std::holds_alternative<uint8_t>(ret));
198 EXPECT_EQ(std::get<uint8_t>(ret), 2);
199
200 ret = param_info->GetNativeParam(INT8_TYPE);
201 EXPECT_TRUE(std::holds_alternative<uint8_t>(ret));
202 EXPECT_EQ(std::get<uint8_t>(ret), 4);
203
204 ret = param_info->GetNativeParam(INT8_TYPE);
205 EXPECT_TRUE(std::holds_alternative<uint8_t>(ret));
206 EXPECT_EQ(std::get<uint8_t>(ret), 5);
207
208 ret = param_info->GetNativeParam(INT32_TYPE);
209 EXPECT_TRUE(std::holds_alternative<uint8_t>(ret));
210 EXPECT_EQ(std::get<uint8_t>(ret), 6);
211
212 ret = param_info->GetNativeParam(INT64_TYPE);
213 EXPECT_TRUE(std::holds_alternative<uint8_t>(ret));
214 EXPECT_EQ(std::get<uint8_t>(ret), 8);
215 }
216
217 // int32_t float int64_t double float
218 // hfloat r0 s0! r2+r3 d1(s2+s3)! s4!
219 // sfloat r0 r1! r2+r3 stack0+1 ! stack2!
220 {
221 auto param_info = GetCallconv()->GetParameterInfo(0);
222 auto ret = param_info->GetNativeParam(INT32_TYPE);
223 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
224 EXPECT_EQ(std::get<Reg>(ret).GetId(), 0);
225 EXPECT_EQ(std::get<Reg>(ret), Reg(0, INT32_TYPE));
226
227 ret = param_info->GetNativeParam(FLOAT32_TYPE);
228 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
229 #if (PANDA_TARGET_ARM32_ABI_HARD)
230 EXPECT_EQ(std::get<Reg>(ret).GetId(), 0);
231 EXPECT_EQ(std::get<Reg>(ret), Reg(0, FLOAT32_TYPE));
232 #else
233 EXPECT_EQ(std::get<Reg>(ret).GetId(), 1);
234 EXPECT_EQ(std::get<Reg>(ret), Reg(1, INT32_TYPE));
235 #endif
236
237 ret = param_info->GetNativeParam(INT64_TYPE);
238 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
239 EXPECT_EQ(std::get<Reg>(ret).GetId(), 2);
240 EXPECT_EQ(std::get<Reg>(ret), Reg(2, INT64_TYPE));
241
242 ret = param_info->GetNativeParam(FLOAT64_TYPE);
243 #if (PANDA_TARGET_ARM32_ABI_HARD)
244 EXPECT_EQ(std::get<Reg>(ret).GetId(), 2);
245 EXPECT_EQ(std::get<Reg>(ret), Reg(2, FLOAT64_TYPE));
246 #else
247 EXPECT_TRUE(std::holds_alternative<uint8_t>(ret));
248 EXPECT_EQ(std::get<uint8_t>(ret), 0);
249 #endif
250
251 ret = param_info->GetNativeParam(FLOAT32_TYPE);
252 #if (PANDA_TARGET_ARM32_ABI_HARD)
253 EXPECT_EQ(std::get<Reg>(ret).GetId(), 4);
254 EXPECT_EQ(std::get<Reg>(ret), Reg(4, FLOAT32_TYPE));
255 #else
256 EXPECT_TRUE(std::holds_alternative<uint8_t>(ret));
257 EXPECT_EQ(std::get<uint8_t>(ret), 2);
258 #endif
259 }
260
261 // float int64_t float int32_t float double int8_t
262 // hfloat s0 r0+r1 s1 r2 s2 s4(d2) r3
263 // sfloat r0 r2+r3 slot0 slot1 slot2 slot4+5 slot6
264 {
265 auto param_info = GetCallconv()->GetParameterInfo(0);
266 auto ret = param_info->GetNativeParam(FLOAT32_TYPE);
267 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
268 EXPECT_EQ(std::get<Reg>(ret).GetId(), 0);
269 EXPECT_EQ(std::get<Reg>(ret), Reg(0, FLOAT_PARAM_TYPE));
270
271 ret = param_info->GetNativeParam(INT64_TYPE);
272 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
273 #if (PANDA_TARGET_ARM32_ABI_HARD)
274 EXPECT_EQ(std::get<Reg>(ret).GetId(), 0);
275 EXPECT_EQ(std::get<Reg>(ret), Reg(0, INT64_TYPE));
276 #else
277 EXPECT_EQ(std::get<Reg>(ret).GetId(), 2);
278 EXPECT_EQ(std::get<Reg>(ret), Reg(2, INT64_TYPE));
279 #endif
280
281 ret = param_info->GetNativeParam(FLOAT32_TYPE);
282 #if (PANDA_TARGET_ARM32_ABI_HARD)
283 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
284 EXPECT_EQ(std::get<Reg>(ret).GetId(), 1);
285 EXPECT_EQ(std::get<Reg>(ret), Reg(1, FLOAT32_TYPE));
286 #else
287 EXPECT_TRUE(std::holds_alternative<uint8_t>(ret));
288 EXPECT_EQ(std::get<uint8_t>(ret), 0);
289 #endif
290
291 ret = param_info->GetNativeParam(INT32_TYPE);
292 #if (PANDA_TARGET_ARM32_ABI_HARD)
293 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
294 EXPECT_EQ(std::get<Reg>(ret).GetId(), 2);
295 EXPECT_EQ(std::get<Reg>(ret), Reg(2, INT32_TYPE));
296 #else
297 EXPECT_TRUE(std::holds_alternative<uint8_t>(ret));
298 EXPECT_EQ(std::get<uint8_t>(ret), 1);
299 #endif
300
301 ret = param_info->GetNativeParam(FLOAT32_TYPE);
302 #if (PANDA_TARGET_ARM32_ABI_HARD)
303 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
304 EXPECT_EQ(std::get<Reg>(ret).GetId(), 2);
305 EXPECT_EQ(std::get<Reg>(ret), Reg(2, FLOAT32_TYPE));
306 #else
307 EXPECT_TRUE(std::holds_alternative<uint8_t>(ret));
308 EXPECT_EQ(std::get<uint8_t>(ret), 2);
309 #endif
310
311 ret = param_info->GetNativeParam(FLOAT64_TYPE);
312 #if (PANDA_TARGET_ARM32_ABI_HARD)
313 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
314 EXPECT_EQ(std::get<Reg>(ret).GetId(), 4);
315 EXPECT_EQ(std::get<Reg>(ret), Reg(4, FLOAT64_TYPE));
316 #else
317 EXPECT_TRUE(std::holds_alternative<uint8_t>(ret));
318 EXPECT_EQ(std::get<uint8_t>(ret), 4);
319 #endif
320
321 ret = param_info->GetNativeParam(INT8_TYPE);
322 #if (PANDA_TARGET_ARM32_ABI_HARD)
323 EXPECT_TRUE(std::holds_alternative<Reg>(ret));
324 EXPECT_EQ(std::get<Reg>(ret).GetId(), 3);
325 EXPECT_EQ(std::get<Reg>(ret), Reg(3, INT8_TYPE));
326 #else
327 EXPECT_TRUE(std::holds_alternative<uint8_t>(ret));
328 EXPECT_EQ(std::get<uint8_t>(ret), 6);
329 #endif
330 }
331 }
332 } // namespace panda::compiler
333