blob: 5622f8952968f671cb13998c96fb56599f8a2738 [file] [log] [blame]
Dave Allison65fcc2c2014-04-28 13:45:27 -07001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Nicolas Geoffray96f89a22014-07-11 10:57:49 +010017#include <dirent.h>
Andreas Gampefd114702015-05-13 17:00:41 -070018#include <errno.h>
Andreas Gampefd114702015-05-13 17:00:41 -070019#include <string.h>
20#include <sys/types.h>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070021#include <fstream>
22#include <map>
Dave Allison65fcc2c2014-04-28 13:45:27 -070023
24#include "gtest/gtest.h"
Artem Serov12e097c2016-08-08 15:13:26 +010025
26#include "jni/quick/calling_convention.h"
27#include "utils/arm/jni_macro_assembler_arm_vixl.h"
28
Dave Allison65fcc2c2014-04-28 13:45:27 -070029#include "base/hex_dump.h"
30#include "common_runtime_test.h"
31
32namespace art {
33namespace arm {
34
35// Include results file (generated manually)
36#include "assembler_thumb_test_expected.cc.inc"
37
Bilyan Borisovbb661c02016-04-04 16:27:32 +010038#ifndef ART_TARGET_ANDROID
Dave Allison45fdb932014-06-25 12:37:10 -070039// This controls whether the results are printed to the
40// screen or compared against the expected output.
41// To generate new expected output, set this to true and
42// copy the output into the .cc.inc file in the form
43// of the other results.
44//
45// When this is false, the results are not printed to the
46// output, but are compared against the expected results
47// in the .cc.inc file.
Dave Allison65fcc2c2014-04-28 13:45:27 -070048static constexpr bool kPrintResults = false;
Dave Allisond20ddb22014-06-05 14:16:30 -070049#endif
Dave Allison65fcc2c2014-04-28 13:45:27 -070050
51void SetAndroidData() {
52 const char* data = getenv("ANDROID_DATA");
53 if (data == nullptr) {
54 setenv("ANDROID_DATA", "/tmp", 1);
55 }
56}
57
Dave Allison45fdb932014-06-25 12:37:10 -070058int CompareIgnoringSpace(const char* s1, const char* s2) {
59 while (*s1 != '\0') {
60 while (isspace(*s1)) ++s1;
61 while (isspace(*s2)) ++s2;
62 if (*s1 == '\0' || *s1 != *s2) {
63 break;
64 }
65 ++s1;
66 ++s2;
67 }
68 return *s1 - *s2;
69}
70
Vladimir Markocf93a5c2015-06-16 11:33:24 +000071void InitResults() {
72 if (test_results.empty()) {
73 setup_results();
74 }
75}
76
77std::string GetToolsDir() {
Bilyan Borisovbb661c02016-04-04 16:27:32 +010078#ifndef ART_TARGET_ANDROID
Vladimir Markocf93a5c2015-06-16 11:33:24 +000079 // This will only work on the host. There is no as, objcopy or objdump on the device.
Dave Allison65fcc2c2014-04-28 13:45:27 -070080 static std::string toolsdir;
81
Vladimir Markocf93a5c2015-06-16 11:33:24 +000082 if (toolsdir.empty()) {
Dave Allison65fcc2c2014-04-28 13:45:27 -070083 setup_results();
David Srbecky3e52aa42015-04-12 07:45:18 +010084 toolsdir = CommonRuntimeTest::GetAndroidTargetToolsDir(kThumb2);
Dave Allison65fcc2c2014-04-28 13:45:27 -070085 SetAndroidData();
Dave Allison65fcc2c2014-04-28 13:45:27 -070086 }
87
Vladimir Markocf93a5c2015-06-16 11:33:24 +000088 return toolsdir;
89#else
90 return std::string();
91#endif
92}
93
94void DumpAndCheck(std::vector<uint8_t>& code, const char* testname, const char* const* results) {
Bilyan Borisovbb661c02016-04-04 16:27:32 +010095#ifndef ART_TARGET_ANDROID
Vladimir Markocf93a5c2015-06-16 11:33:24 +000096 static std::string toolsdir = GetToolsDir();
97
Dave Allison65fcc2c2014-04-28 13:45:27 -070098 ScratchFile file;
99
100 const char* filename = file.GetFilename().c_str();
101
102 std::ofstream out(filename);
103 if (out) {
104 out << ".section \".text\"\n";
105 out << ".syntax unified\n";
106 out << ".arch armv7-a\n";
107 out << ".thumb\n";
108 out << ".thumb_func\n";
109 out << ".type " << testname << ", #function\n";
110 out << ".global " << testname << "\n";
111 out << testname << ":\n";
112 out << ".fnstart\n";
113
114 for (uint32_t i = 0 ; i < code.size(); ++i) {
115 out << ".byte " << (static_cast<int>(code[i]) & 0xff) << "\n";
116 }
117 out << ".fnend\n";
118 out << ".size " << testname << ", .-" << testname << "\n";
119 }
120 out.close();
121
Andreas Gampe4470c1d2014-07-21 18:32:59 -0700122 char cmd[1024];
Dave Allison65fcc2c2014-04-28 13:45:27 -0700123
124 // Assemble the .S
David Srbecky3e52aa42015-04-12 07:45:18 +0100125 snprintf(cmd, sizeof(cmd), "%sas %s -o %s.o", toolsdir.c_str(), filename, filename);
Andreas Gampefd114702015-05-13 17:00:41 -0700126 int cmd_result = system(cmd);
127 ASSERT_EQ(cmd_result, 0) << strerror(errno);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700128
Dave Allison65fcc2c2014-04-28 13:45:27 -0700129 // Disassemble.
Rahul Chaudhry956dac22017-09-27 16:33:40 -0700130 snprintf(cmd, sizeof(cmd), "%sobjdump -D -M force-thumb --section=.text %s.o | grep '^ *[0-9a-f][0-9a-f]*:'",
David Srbecky3e52aa42015-04-12 07:45:18 +0100131 toolsdir.c_str(), filename);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700132 if (kPrintResults) {
133 // Print the results only, don't check. This is used to generate new output for inserting
Vladimir Markof5c09c32015-12-17 12:08:08 +0000134 // into the .inc file, so let's add the appropriate prefix/suffix needed in the C++ code.
135 strcat(cmd, " | sed '-es/^/ \"/' | sed '-es/$/\\\\n\",/'");
Andreas Gampefd114702015-05-13 17:00:41 -0700136 int cmd_result3 = system(cmd);
137 ASSERT_EQ(cmd_result3, 0) << strerror(errno);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700138 } else {
139 // Check the results match the appropriate results in the .inc file.
140 FILE *fp = popen(cmd, "r");
141 ASSERT_TRUE(fp != nullptr);
142
Dave Allison65fcc2c2014-04-28 13:45:27 -0700143 uint32_t lineindex = 0;
144
145 while (!feof(fp)) {
146 char testline[256];
147 char *s = fgets(testline, sizeof(testline), fp);
148 if (s == nullptr) {
149 break;
150 }
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000151 if (CompareIgnoringSpace(results[lineindex], testline) != 0) {
Dave Allison45fdb932014-06-25 12:37:10 -0700152 LOG(FATAL) << "Output is not as expected at line: " << lineindex
Igor Murashkinaf1e2992016-10-12 17:44:50 -0700153 << results[lineindex] << "/" << testline << ", test name: " << testname;
Dave Allison45fdb932014-06-25 12:37:10 -0700154 }
Dave Allison65fcc2c2014-04-28 13:45:27 -0700155 ++lineindex;
156 }
157 // Check that we are at the end.
Vladimir Markocf93a5c2015-06-16 11:33:24 +0000158 ASSERT_TRUE(results[lineindex] == nullptr);
Dave Allison65fcc2c2014-04-28 13:45:27 -0700159 fclose(fp);
160 }
161
162 char buf[FILENAME_MAX];
163 snprintf(buf, sizeof(buf), "%s.o", filename);
164 unlink(buf);
Bilyan Borisovbb661c02016-04-04 16:27:32 +0100165#endif // ART_TARGET_ANDROID
Dave Allison65fcc2c2014-04-28 13:45:27 -0700166}
167
Vladimir Marko0e851e22016-08-25 18:17:56 +0100168class ArmVIXLAssemblerTest : public ::testing::Test {
Artem Serov12e097c2016-08-08 15:13:26 +0100169 public:
Vladimir Marko0e851e22016-08-25 18:17:56 +0100170 ArmVIXLAssemblerTest() : pool(), arena(&pool), assembler(&arena) { }
Artem Serov12e097c2016-08-08 15:13:26 +0100171
172 ArenaPool pool;
173 ArenaAllocator arena;
Roland Levillainc043d002017-07-14 16:39:16 +0100174 ArmVIXLJNIMacroAssembler assembler;
Artem Serov12e097c2016-08-08 15:13:26 +0100175};
176
Artem Serov12e097c2016-08-08 15:13:26 +0100177#define __ assembler->
178
Roland Levillainc043d002017-07-14 16:39:16 +0100179void EmitAndCheck(ArmVIXLJNIMacroAssembler* assembler, const char* testname,
Artem Serov12e097c2016-08-08 15:13:26 +0100180 const char* const* results) {
181 __ FinalizeCode();
182 size_t cs = __ CodeSize();
183 std::vector<uint8_t> managed_code(cs);
184 MemoryRegion code(&managed_code[0], managed_code.size());
185 __ FinalizeInstructions(code);
186
187 DumpAndCheck(managed_code, testname, results);
188}
189
Roland Levillainc043d002017-07-14 16:39:16 +0100190void EmitAndCheck(ArmVIXLJNIMacroAssembler* assembler, const char* testname) {
Artem Serov12e097c2016-08-08 15:13:26 +0100191 InitResults();
192 std::map<std::string, const char* const*>::iterator results = test_results.find(testname);
193 ASSERT_NE(results, test_results.end());
194
195 EmitAndCheck(assembler, testname, results->second);
196}
197
198#undef __
Roland Levillainc043d002017-07-14 16:39:16 +0100199
Artem Serov12e097c2016-08-08 15:13:26 +0100200#define __ assembler.
201
Vladimir Marko0e851e22016-08-25 18:17:56 +0100202TEST_F(ArmVIXLAssemblerTest, VixlJniHelpers) {
Roland Levillain6d729a72017-06-30 18:34:01 +0100203 // Run the test only with Baker read barriers, as the expected
204 // generated code contains a Marking Register refresh instruction.
205 TEST_DISABLED_WITHOUT_BAKER_READ_BARRIERS();
206
Artem Serov12e097c2016-08-08 15:13:26 +0100207 const bool is_static = true;
208 const bool is_synchronized = false;
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700209 const bool is_critical_native = false;
Artem Serov12e097c2016-08-08 15:13:26 +0100210 const char* shorty = "IIFII";
211
212 ArenaPool pool;
213 ArenaAllocator arena(&pool);
214
215 std::unique_ptr<JniCallingConvention> jni_conv(
Igor Murashkin367f3dd2016-09-01 17:00:24 -0700216 JniCallingConvention::Create(&arena,
217 is_static,
218 is_synchronized,
219 is_critical_native,
220 shorty,
221 kThumb2));
Artem Serov12e097c2016-08-08 15:13:26 +0100222 std::unique_ptr<ManagedRuntimeCallingConvention> mr_conv(
223 ManagedRuntimeCallingConvention::Create(&arena, is_static, is_synchronized, shorty, kThumb2));
224 const int frame_size(jni_conv->FrameSize());
225 ArrayRef<const ManagedRegister> callee_save_regs = jni_conv->CalleeSaveRegisters();
226
227 const ManagedRegister method_register = ArmManagedRegister::FromCoreRegister(R0);
228 const ManagedRegister scratch_register = ArmManagedRegister::FromCoreRegister(R12);
229
230 __ BuildFrame(frame_size, mr_conv->MethodRegister(), callee_save_regs, mr_conv->EntrySpills());
231 __ IncreaseFrameSize(32);
232
233 // Loads
234 __ IncreaseFrameSize(4096);
235 __ Load(method_register, FrameOffset(32), 4);
236 __ Load(method_register, FrameOffset(124), 4);
237 __ Load(method_register, FrameOffset(132), 4);
238 __ Load(method_register, FrameOffset(1020), 4);
239 __ Load(method_register, FrameOffset(1024), 4);
240 __ Load(scratch_register, FrameOffset(4092), 4);
241 __ Load(scratch_register, FrameOffset(4096), 4);
242 __ LoadRawPtrFromThread(scratch_register, ThreadOffset32(512));
Vladimir Marko0e851e22016-08-25 18:17:56 +0100243 __ LoadRef(method_register, scratch_register, MemberOffset(128), /* unpoison_reference */ false);
Artem Serov12e097c2016-08-08 15:13:26 +0100244
245 // Stores
246 __ Store(FrameOffset(32), method_register, 4);
247 __ Store(FrameOffset(124), method_register, 4);
248 __ Store(FrameOffset(132), method_register, 4);
249 __ Store(FrameOffset(1020), method_register, 4);
250 __ Store(FrameOffset(1024), method_register, 4);
251 __ Store(FrameOffset(4092), scratch_register, 4);
252 __ Store(FrameOffset(4096), scratch_register, 4);
253 __ StoreImmediateToFrame(FrameOffset(48), 0xFF, scratch_register);
254 __ StoreImmediateToFrame(FrameOffset(48), 0xFFFFFF, scratch_register);
255 __ StoreRawPtr(FrameOffset(48), scratch_register);
256 __ StoreRef(FrameOffset(48), scratch_register);
257 __ StoreSpanning(FrameOffset(48), method_register, FrameOffset(48), scratch_register);
258 __ StoreStackOffsetToThread(ThreadOffset32(512), FrameOffset(4096), scratch_register);
259 __ StoreStackPointerToThread(ThreadOffset32(512));
260
261 // Other
262 __ Call(method_register, FrameOffset(48), scratch_register);
263 __ Copy(FrameOffset(48), FrameOffset(44), scratch_register, 4);
264 __ CopyRawPtrFromThread(FrameOffset(44), ThreadOffset32(512), scratch_register);
265 __ CopyRef(FrameOffset(48), FrameOffset(44), scratch_register);
266 __ GetCurrentThread(method_register);
267 __ GetCurrentThread(FrameOffset(48), scratch_register);
268 __ Move(scratch_register, method_register, 4);
269 __ VerifyObject(scratch_register, false);
270
271 __ CreateHandleScopeEntry(scratch_register, FrameOffset(48), scratch_register, true);
272 __ CreateHandleScopeEntry(scratch_register, FrameOffset(48), scratch_register, false);
273 __ CreateHandleScopeEntry(method_register, FrameOffset(48), scratch_register, true);
274 __ CreateHandleScopeEntry(FrameOffset(48), FrameOffset(64), scratch_register, true);
275 __ CreateHandleScopeEntry(method_register, FrameOffset(0), scratch_register, true);
276 __ CreateHandleScopeEntry(method_register, FrameOffset(1025), scratch_register, true);
277 __ CreateHandleScopeEntry(scratch_register, FrameOffset(1025), scratch_register, true);
278
279 __ ExceptionPoll(scratch_register, 0);
280
Artem Serov8f840f82016-12-15 17:56:27 +0000281 // Push the target out of range of branch emitted by ExceptionPoll.
282 for (int i = 0; i < 64; i++) {
283 __ Store(FrameOffset(2047), scratch_register, 4);
284 }
285
Artem Serov12e097c2016-08-08 15:13:26 +0100286 __ DecreaseFrameSize(4096);
287 __ DecreaseFrameSize(32);
Roland Levillain0d127e12017-07-05 17:01:11 +0100288 __ RemoveFrame(frame_size, callee_save_regs, /* may_suspend */ true);
Artem Serov12e097c2016-08-08 15:13:26 +0100289
290 EmitAndCheck(&assembler, "VixlJniHelpers");
291}
292
Roland Levillainc043d002017-07-14 16:39:16 +0100293#undef __
294
295// TODO: Avoid these macros.
Artem Serov12e097c2016-08-08 15:13:26 +0100296#define R0 vixl::aarch32::r0
297#define R2 vixl::aarch32::r2
298#define R4 vixl::aarch32::r4
299#define R12 vixl::aarch32::r12
Roland Levillainc043d002017-07-14 16:39:16 +0100300
Artem Serov12e097c2016-08-08 15:13:26 +0100301#define __ assembler.asm_.
Artem Serov12e097c2016-08-08 15:13:26 +0100302
Vladimir Marko0e851e22016-08-25 18:17:56 +0100303TEST_F(ArmVIXLAssemblerTest, VixlLoadFromOffset) {
Artem Serov12e097c2016-08-08 15:13:26 +0100304 __ LoadFromOffset(kLoadWord, R2, R4, 12);
305 __ LoadFromOffset(kLoadWord, R2, R4, 0xfff);
306 __ LoadFromOffset(kLoadWord, R2, R4, 0x1000);
307 __ LoadFromOffset(kLoadWord, R2, R4, 0x1000a4);
308 __ LoadFromOffset(kLoadWord, R2, R4, 0x101000);
309 __ LoadFromOffset(kLoadWord, R4, R4, 0x101000);
310 __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 12);
311 __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 0xfff);
312 __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 0x1000);
313 __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 0x1000a4);
314 __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 0x101000);
315 __ LoadFromOffset(kLoadUnsignedHalfword, R4, R4, 0x101000);
316 __ LoadFromOffset(kLoadWordPair, R2, R4, 12);
317 __ LoadFromOffset(kLoadWordPair, R2, R4, 0x3fc);
318 __ LoadFromOffset(kLoadWordPair, R2, R4, 0x400);
319 __ LoadFromOffset(kLoadWordPair, R2, R4, 0x400a4);
320 __ LoadFromOffset(kLoadWordPair, R2, R4, 0x40400);
321 __ LoadFromOffset(kLoadWordPair, R4, R4, 0x40400);
322
Scott Wakelingb77051e2016-11-21 19:46:00 +0000323 vixl::aarch32::UseScratchRegisterScope temps(assembler.asm_.GetVIXLAssembler());
324 temps.Exclude(R12);
Artem Serov12e097c2016-08-08 15:13:26 +0100325 __ LoadFromOffset(kLoadWord, R0, R12, 12); // 32-bit because of R12.
Scott Wakelingb77051e2016-11-21 19:46:00 +0000326 temps.Include(R12);
Artem Serov12e097c2016-08-08 15:13:26 +0100327 __ LoadFromOffset(kLoadWord, R2, R4, 0xa4 - 0x100000);
328
329 __ LoadFromOffset(kLoadSignedByte, R2, R4, 12);
330 __ LoadFromOffset(kLoadUnsignedByte, R2, R4, 12);
331 __ LoadFromOffset(kLoadSignedHalfword, R2, R4, 12);
332
333 EmitAndCheck(&assembler, "VixlLoadFromOffset");
334}
335
Vladimir Marko0e851e22016-08-25 18:17:56 +0100336TEST_F(ArmVIXLAssemblerTest, VixlStoreToOffset) {
Artem Serov12e097c2016-08-08 15:13:26 +0100337 __ StoreToOffset(kStoreWord, R2, R4, 12);
338 __ StoreToOffset(kStoreWord, R2, R4, 0xfff);
339 __ StoreToOffset(kStoreWord, R2, R4, 0x1000);
340 __ StoreToOffset(kStoreWord, R2, R4, 0x1000a4);
341 __ StoreToOffset(kStoreWord, R2, R4, 0x101000);
342 __ StoreToOffset(kStoreWord, R4, R4, 0x101000);
343 __ StoreToOffset(kStoreHalfword, R2, R4, 12);
344 __ StoreToOffset(kStoreHalfword, R2, R4, 0xfff);
345 __ StoreToOffset(kStoreHalfword, R2, R4, 0x1000);
346 __ StoreToOffset(kStoreHalfword, R2, R4, 0x1000a4);
347 __ StoreToOffset(kStoreHalfword, R2, R4, 0x101000);
348 __ StoreToOffset(kStoreHalfword, R4, R4, 0x101000);
349 __ StoreToOffset(kStoreWordPair, R2, R4, 12);
350 __ StoreToOffset(kStoreWordPair, R2, R4, 0x3fc);
351 __ StoreToOffset(kStoreWordPair, R2, R4, 0x400);
352 __ StoreToOffset(kStoreWordPair, R2, R4, 0x400a4);
353 __ StoreToOffset(kStoreWordPair, R2, R4, 0x40400);
354 __ StoreToOffset(kStoreWordPair, R4, R4, 0x40400);
355
Scott Wakelingb77051e2016-11-21 19:46:00 +0000356 vixl::aarch32::UseScratchRegisterScope temps(assembler.asm_.GetVIXLAssembler());
357 temps.Exclude(R12);
Artem Serov12e097c2016-08-08 15:13:26 +0100358 __ StoreToOffset(kStoreWord, R0, R12, 12); // 32-bit because of R12.
Scott Wakelingb77051e2016-11-21 19:46:00 +0000359 temps.Include(R12);
Artem Serov12e097c2016-08-08 15:13:26 +0100360 __ StoreToOffset(kStoreWord, R2, R4, 0xa4 - 0x100000);
361
362 __ StoreToOffset(kStoreByte, R2, R4, 12);
363
364 EmitAndCheck(&assembler, "VixlStoreToOffset");
365}
366
367#undef __
Dave Allison65fcc2c2014-04-28 13:45:27 -0700368} // namespace arm
369} // namespace art