• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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