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 <fstream>
17 #include "unit_test.h"
18 #include "code_info/code_info_builder.h"
19 #include "codegen.h"
20 #include "panda_runner.h"
21 #include "events/events.h"
22
23 using panda::panda_file::File;
24
25 namespace panda::test {
26 class CodegenRunnerTest : public testing::Test {
27 public:
CodegenRunnerTest()28 CodegenRunnerTest()
29 : default_compiler_non_optimizing_(compiler::options.IsCompilerNonOptimizing()),
30 default_compiler_inlining_(compiler::options.IsCompilerInlining()),
31 default_compiler_regalloc_mask_(compiler::options.GetCompilerRegallocRegMask())
32 {
33 }
34
~CodegenRunnerTest()35 ~CodegenRunnerTest()
36 {
37 compiler::options.SetCompilerNonOptimizing(default_compiler_non_optimizing_);
38 compiler::options.SetCompilerInlining(default_compiler_inlining_);
39 compiler::options.SetCompilerRegallocRegMask(default_compiler_regalloc_mask_);
40 }
SetUp()41 void SetUp()
42 {
43 #ifdef USE_ADDRESS_SANITIZER
44 GTEST_SKIP();
45 #endif
46 if constexpr (RUNTIME_ARCH == Arch::AARCH32) {
47 GTEST_SKIP();
48 }
49 }
50
51 private:
52 bool default_compiler_non_optimizing_;
53 bool default_compiler_inlining_;
54 uint64_t default_compiler_regalloc_mask_;
55 };
56
57 static constexpr auto CODEGEN_OBJECT_PARAMS_SOURCE = R"(
58 .record Value{
59 i32 a
60 i64 b
61 i16 c
62 }
63
64 .function i32 hook() {
65 ldai 1
66 return
67 }
68
69 .function i32 get_Value_a(Value a0) {
70 ldobj a0, Value.a
71 return
72 }
73
74 .function i64 get_Value_b(Value a0) {
75 ldobj a0, Value.b
76 return.64
77 }
78
79 .function i32 get_Value_c(Value a0) {
80 ldobj a0, Value.c
81 return
82 }
83
84 #16:
85 # +0x800
86 # +0x200
87 # +0x80
88 # +0x20
89 # +0x8
90 # +0x2
91 # Result 0xAAA
92 #32:
93 # +0x8000000
94 # +0x2000000
95 # +0x800000
96 # +0x200000
97 # +0x80000
98 # +0x20000
99 # Result 0xAAA0000
100 #64:
101 # +0x800000000000000
102 # +0x200000000000000
103 # +0x80000000000000
104 # +0x20000000000000
105 # +0x8000000000000
106 # +0x2000000000000
107 # Result 0xAAA000000000000
108 # Result 0xAAA00000AAA0AAA
109
110 .function i64 foo(Value a0, Value a1, Value a2, Value a3, Value a4, Value a5) {
111 ldai.64 0
112 sta.64 v17
113
114 # Some math for spill parameters to stack
115 ldai.64 0x1234567890123456
116 sta.64 v8
117
118 ldai.64 0x1000000000000000
119 sta.64 v9
120 ldai.64 0x0200000000000000
121 sta.64 v10
122 ldai.64 0x0030000000000000
123 sta.64 v11
124 ldai.64 0x0004000000000000
125 sta.64 v12
126 ldai.64 0x0000500000000000
127 sta.64 v13
128 ldai.64 0x0000060000000000
129 sta.64 v14
130 ldai.64 0x0000007000000000
131 sta.64 v15
132 ldai.64 0x0000000800000000
133 sta.64 v16
134 ldai.64 0x0000000090000000
135 sta.64 v18
136 ldai.64 0x0000000000100000
137 sta.64 v19
138 ldai.64 0x0000000000020000
139 sta.64 v20
140 ldai.64 0x0000000000003000
141 sta.64 v21
142 ldai.64 0x0000000000000400
143 sta.64 v22
144 ldai.64 0x0000000000000050
145 sta.64 v23
146 ldai.64 0x0000000000000006
147 sta.64 v24
148
149 lda.64 v8
150 sub2.64 v9
151 sub2.64 v10
152 sub2.64 v11
153 sub2.64 v12
154 sub2.64 v13
155 sub2.64 v14
156 sub2.64 v15
157 sub2.64 v16
158 sub2.64 v18
159 sub2.64 v19
160 sub2.64 v20
161 sub2.64 v21
162 sub2.64 v22
163 sub2.64 v23
164 sub2.64 v24
165
166 jeq v17, success_label
167 add2.64 v8
168 add2.64 v9
169 add2.64 v10
170 add2.64 v11
171 add2.64 v12
172 add2.64 v13
173 add2.64 v14
174 add2.64 v15
175 add2.64 v16
176
177 return.64
178
179 success_label:
180
181 ## here params lay on stack - need check somehow (emit in cg)
182 ldai 0
183 sta v0
184 call.range get_Value_c, a2
185 # 0x800
186 add2 v0
187 sta v0
188 call.range get_Value_a, a5
189 # 0x200000
190 add2 v0
191 sta v0
192 call.range get_Value_c, a4
193 # 0x800000
194 add2 v0
195 sta v0
196 call.range get_Value_a, a1
197 # 0x20000000
198 add2 v0
199 sta v0
200 call.range get_Value_c, a0
201 # 0x8000
202 add2 v0
203 sta v0
204 call.range get_Value_a, a3
205 # 0x2000000
206 add2 v0
207 sta v0
208 call.range get_Value_c, a5
209 # 0x20
210 add2 v0
211 sta v0
212 call.range get_Value_a, a2
213 # 0x8000000
214 add2 v0
215 sta v0
216 call.range get_Value_c, a1
217 # 0x2000
218 add2 v0
219 sta v0
220 call.range get_Value_a, a4
221 # 0x80
222 add2 v0
223 sta v0
224 call.range get_Value_c, a3
225 # 0x200
226 add2 v0
227 sta v0
228 call.range get_Value_a, a0
229 # 0x80000000
230 add2 v0
231 i32toi64
232 sta.64 v1
233
234 call.range get_Value_b, a5
235 add2.64 v1
236 sta.64 v1
237 call.range get_Value_b, a0
238 add2.64 v1
239 sta.64 v1
240 call.range get_Value_b, a4
241 add2.64 v1
242 sta.64 v1
243 call.range get_Value_b, a1
244 add2.64 v1
245 sta.64 v1
246 call.range get_Value_b, a3
247 add2.64 v1
248 sta.64 v1
249 call.range get_Value_b, a2
250 add2.64 v1
251
252 return.64
253 }
254
255 .function i64 main() {
256 newobj v0, Value
257 newobj v1, Value
258 newobj v2, Value
259 newobj v3, Value
260 newobj v4, Value
261 newobj v5, Value
262 ## c - i16
263 ldai 0x800
264 stobj v0, Value.c
265 ldai 0x200
266 stobj v1, Value.c
267 ldai 0x80
268 stobj v2, Value.c
269 ldai 0x20
270 stobj v3, Value.c
271 ldai 0x8
272 stobj v4, Value.c
273 ldai 0x2
274 stobj v5, Value.c
275 ## a - i32
276 ldai 0x8000000
277 stobj v0, Value.a
278 ldai 0x2000000
279 stobj v1, Value.a
280 ldai 0x800000
281 stobj v2, Value.a
282 ldai 0x200000
283 stobj v3, Value.a
284 ldai 0x80000
285 stobj v4, Value.a
286 ldai 0x20000
287 stobj v5, Value.a
288 ## b - i64
289 ldai.64 0x800000000000000
290 stobj v0, Value.b
291 ldai.64 0x200000000000000
292 stobj v1, Value.b
293 ldai.64 0x80000000000000
294 stobj v2, Value.b
295 ldai.64 0x20000000000000
296 stobj v3, Value.b
297 ldai.64 0x8000000000000
298 stobj v4, Value.b
299 ldai.64 0x2000000000000
300 stobj v5, Value.b
301
302 ldai.64 0xaaa00000aaa0aaa
303 sta.64 v7
304 # Corrupt stack for call.foo
305 call.short hook
306
307 call.range foo, v0
308
309 jeq v7, success_label
310 return.64
311
312 success_label:
313 ldai 123
314 return.64
315 }
316 )";
317
318 constexpr uint64_t CORUPT_SIZE = 0xFFF;
319 // Allocated on stack check
320 [[maybe_unused]] constexpr uint64_t HOOK_OFFSET = 0x10000;
321 constexpr uint64_t CORUPT_DATA = 0xABCDEF0123456789;
322
Callback(uintptr_t lr,uintptr_t fp)323 NO_OPTIMIZE int Callback([[maybe_unused]] uintptr_t lr, [[maybe_unused]] uintptr_t fp)
324 {
325 uint64_t tmp[CORUPT_SIZE];
326 [[maybe_unused]] auto delta = bit_cast<uintptr_t>(fp) - bit_cast<uintptr_t>(&tmp);
327 ASSERT(delta < HOOK_OFFSET);
328 delta = bit_cast<uintptr_t>(&tmp[CORUPT_SIZE]) - bit_cast<uintptr_t>(&tmp);
329 ASSERT(delta == CORUPT_SIZE * sizeof(uint64_t));
330 for (uintptr_t i = 0; i < CORUPT_SIZE; ++i) {
331 tmp[i] = CORUPT_DATA;
332 }
333 return 0;
334 }
335
TEST_F(CodegenRunnerTest,ObjectParams)336 TEST_F(CodegenRunnerTest, ObjectParams)
337 {
338 // In Release and FastVerify modes compiler can omit frame pointer, thus, PandaRunner can't work properly in these
339 // modes.
340 #if defined(NDEBUG) || defined(PANDA_FAST_VERIFY)
341 GTEST_SKIP();
342 #endif
343 // hi-part is 1 - to do not rewrite fp, lr in arm64
344 uint64_t reg_masks[] = {
345 0, 0xFFFFFFFFFFFFFFF0, 0xFFFFFFFFF0FFF000, 0xFFFFFFFFFFFFDFD6,
346 // TODO (igorban): enable next variants:
347 // 0xFFFFFFFFFF000FFF,
348 // 0xFFFFFFFFF000000F,
349 // 0xFFFFFFFFF000202A,
350 // 0xFFFFFFFFFFFFF00F,
351 };
352
353 for (auto &hook_on : {false, true}) {
354 for (auto &mask : reg_masks) {
355 panda::test::PandaRunner runner;
356 runner.GetCompilerOptions().SetCompilerNonOptimizing(true);
357 runner.GetCompilerOptions().SetCompilerInlining(false);
358 runner.GetRuntimeOptions().SetCompilerHotnessThreshold(0);
359 runner.GetRuntimeOptions().SetShouldLoadBootPandaFiles(true);
360 runner.GetRuntimeOptions().SetShouldInitializeIntrinsics(false);
361 runner.GetCompilerOptions().SetCompilerRegallocRegMask(mask);
362
363 if (hook_on) {
364 runner.SetHook(Callback);
365 }
366
367 runner.Run(CODEGEN_OBJECT_PARAMS_SOURCE, 123);
368 }
369 }
370 }
371
372 } // namespace panda::test
373