1 // Copyright 2014, ARM Limited
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright notice,
8 // this list of conditions and the following disclaimer.
9 // * Redistributions in binary form must reproduce the above copyright notice,
10 // this list of conditions and the following disclaimer in the documentation
11 // and/or other materials provided with the distribution.
12 // * Neither the name of ARM Limited nor the names of its contributors may be
13 // used to endorse or promote products derived from this software without
14 // specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
17 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 #include <stdio.h>
28 #include <float.h>
29
30 #include "cctest.h"
31 #include "test-utils-a64.h"
32 #include "test-simulator-inputs-a64.h"
33 #include "test-simulator-traces-a64.h"
34 #include "a64/macro-assembler-a64.h"
35 #include "a64/simulator-a64.h"
36
37 namespace vixl {
38
39 // ==== Simulator Tests ====
40 //
41 // These simulator tests check instruction behaviour against a trace taken from
42 // real AArch64 hardware. The same test code is used to generate the trace; the
43 // results are printed to stdout when the test is run with --sim_test_trace.
44 //
45 // The input lists and expected results are stored in
46 // test/test-simulator-traces-a64.h. The expected results can be regenerated
47 // using tools/generate_simulator_traces.py.
48
49 #define __ masm.
50 #define TEST(name) TEST_(SIM_##name)
51
52 #define BUF_SIZE (256)
53
54 #ifdef USE_SIMULATOR
55
56 #define SETUP() \
57 byte* buf = new byte[BUF_SIZE]; \
58 MacroAssembler masm(buf, BUF_SIZE); \
59 Decoder decoder; \
60 Simulator* simulator = NULL; \
61 if (Cctest::run_debugger()) { \
62 simulator = new Debugger(&decoder); \
63 } else { \
64 simulator = new Simulator(&decoder); \
65 simulator->set_disasm_trace(Cctest::trace_sim()); \
66 } \
67 simulator->set_coloured_trace(Cctest::coloured_trace()); \
68 simulator->set_instruction_stats(Cctest::instruction_stats());
69
70 #define START() \
71 masm.Reset(); \
72 simulator->ResetState(); \
73 __ PushCalleeSavedRegisters(); \
74 if (Cctest::run_debugger()) { \
75 if (Cctest::trace_reg()) { \
76 __ Trace(LOG_STATE, TRACE_ENABLE); \
77 } \
78 if (Cctest::trace_sim()) { \
79 __ Trace(LOG_DISASM, TRACE_ENABLE); \
80 } \
81 } \
82 if (Cctest::instruction_stats()) { \
83 __ EnableInstrumentation(); \
84 }
85
86 #define END() \
87 if (Cctest::instruction_stats()) { \
88 __ DisableInstrumentation(); \
89 } \
90 if (Cctest::run_debugger()) { \
91 __ Trace(LOG_ALL, TRACE_DISABLE); \
92 } \
93 __ PopCalleeSavedRegisters(); \
94 __ Ret(); \
95 masm.FinalizeCode()
96
97 #define RUN() \
98 simulator->RunFrom(reinterpret_cast<Instruction*>(buf))
99
100 #define TEARDOWN() \
101 delete simulator; \
102 delete[] buf;
103
104 #else // USE_SIMULATOR
105
106 #define SETUP() \
107 byte* buf = new byte[BUF_SIZE]; \
108 MacroAssembler masm(buf, BUF_SIZE); \
109 CPU::SetUp()
110
111 #define START() \
112 masm.Reset(); \
113 __ PushCalleeSavedRegisters()
114
115 #define END() \
116 __ PopCalleeSavedRegisters(); \
117 __ Ret(); \
118 masm.FinalizeCode()
119
120 #define RUN() \
121 CPU::EnsureIAndDCacheCoherency(buf, BUF_SIZE); \
122 { \
123 void (*test_function)(void); \
124 VIXL_ASSERT(sizeof(buf) == sizeof(test_function)); \
125 memcpy(&test_function, &buf, sizeof(buf)); \
126 test_function(); \
127 }
128
129 #define TEARDOWN() \
130 delete[] buf;
131
132 #endif // USE_SIMULATOR
133
134
135 // The maximum number of errors to report in detail for each test.
136 static const unsigned kErrorReportLimit = 8;
137
138
139 // Overloaded versions of rawbits_to_double and rawbits_to_float for use in the
140 // templated test functions.
rawbits_to_fp(uint32_t bits)141 static float rawbits_to_fp(uint32_t bits) {
142 return rawbits_to_float(bits);
143 }
144
rawbits_to_fp(uint64_t bits)145 static double rawbits_to_fp(uint64_t bits) {
146 return rawbits_to_double(bits);
147 }
148
149
150 // MacroAssembler member function pointers to pass to the test dispatchers.
151 typedef void (MacroAssembler::*Test1OpFPHelper_t)(const FPRegister& fd,
152 const FPRegister& fn);
153 typedef void (MacroAssembler::*Test2OpFPHelper_t)(const FPRegister& fd,
154 const FPRegister& fn,
155 const FPRegister& fm);
156 typedef void (MacroAssembler::*Test3OpFPHelper_t)(const FPRegister& fd,
157 const FPRegister& fn,
158 const FPRegister& fm,
159 const FPRegister& fa);
160 typedef void (MacroAssembler::*TestFPCmpHelper_t)(const FPRegister& fn,
161 const FPRegister& fm);
162 typedef void (MacroAssembler::*TestFPCmpZeroHelper_t)(const FPRegister& fn,
163 double value);
164 typedef void (MacroAssembler::*TestFPToIntHelper_t)(const Register& rd,
165 const FPRegister& fn);
166 typedef void (MacroAssembler::*TestFixedToFPHelper_t)(const FPRegister& fd,
167 const Register& rn,
168 unsigned fbits);
169
170 // Standard test dispatchers.
171
172
Test1Op_Helper(Test1OpFPHelper_t helper,uintptr_t inputs,unsigned inputs_length,uintptr_t results,unsigned d_size,unsigned n_size)173 static void Test1Op_Helper(Test1OpFPHelper_t helper, uintptr_t inputs,
174 unsigned inputs_length, uintptr_t results,
175 unsigned d_size, unsigned n_size) {
176 VIXL_ASSERT((d_size == kDRegSize) || (d_size == kSRegSize));
177 VIXL_ASSERT((n_size == kDRegSize) || (n_size == kSRegSize));
178
179 SETUP();
180 START();
181
182 // Roll up the loop to keep the code size down.
183 Label loop_n;
184
185 Register out = x0;
186 Register inputs_base = x1;
187 Register length = w2;
188 Register index_n = w3;
189
190 const int n_index_shift =
191 (n_size == kDRegSize) ? kDRegSizeInBytesLog2 : kSRegSizeInBytesLog2;
192
193 FPRegister fd = (d_size == kDRegSize) ? d0 : s0;
194 FPRegister fn = (n_size == kDRegSize) ? d1 : s1;
195
196 __ Mov(out, results);
197 __ Mov(inputs_base, inputs);
198 __ Mov(length, inputs_length);
199
200 __ Mov(index_n, 0);
201 __ Bind(&loop_n);
202 __ Ldr(fn, MemOperand(inputs_base, index_n, UXTW, n_index_shift));
203
204 (masm.*helper)(fd, fn);
205 __ Str(fd, MemOperand(out, fd.SizeInBytes(), PostIndex));
206
207 __ Add(index_n, index_n, 1);
208 __ Cmp(index_n, inputs_length);
209 __ B(lo, &loop_n);
210
211 END();
212 RUN();
213 TEARDOWN();
214 }
215
216
217 // Test FP instructions. The inputs[] and expected[] arrays should be arrays of
218 // rawbits representations of doubles or floats. This ensures that exact bit
219 // comparisons can be performed.
220 template <typename Tn, typename Td>
Test1Op(const char * name,Test1OpFPHelper_t helper,const Tn inputs[],unsigned inputs_length,const Td expected[],unsigned expected_length)221 static void Test1Op(const char * name, Test1OpFPHelper_t helper,
222 const Tn inputs[], unsigned inputs_length,
223 const Td expected[], unsigned expected_length) {
224 VIXL_ASSERT(inputs_length > 0);
225
226 const unsigned results_length = inputs_length;
227 Td * results = new Td[results_length];
228
229 const unsigned d_bits = sizeof(Td) * 8;
230 const unsigned n_bits = sizeof(Tn) * 8;
231
232 Test1Op_Helper(helper, reinterpret_cast<uintptr_t>(inputs), inputs_length,
233 reinterpret_cast<uintptr_t>(results), d_bits, n_bits);
234
235 if (Cctest::sim_test_trace()) {
236 // Print the results.
237 printf("const uint%u_t kExpected_%s[] = {\n", d_bits, name);
238 for (unsigned d = 0; d < results_length; d++) {
239 printf(" 0x%0*" PRIx64 ",\n",
240 d_bits / 4, static_cast<uint64_t>(results[d]));
241 }
242 printf("};\n");
243 printf("const unsigned kExpectedCount_%s = %u;\n", name, results_length);
244 } else {
245 // Check the results.
246 VIXL_CHECK(expected_length == results_length);
247 unsigned error_count = 0;
248 unsigned d = 0;
249 for (unsigned n = 0; n < inputs_length; n++, d++) {
250 if (results[d] != expected[d]) {
251 if (++error_count > kErrorReportLimit) continue;
252
253 printf("%s 0x%0*" PRIx64 " (%s %g):\n",
254 name, n_bits / 4, static_cast<uint64_t>(inputs[n]),
255 name, rawbits_to_fp(inputs[n]));
256 printf(" Expected: 0x%0*" PRIx64 " (%g)\n",
257 d_bits / 4, static_cast<uint64_t>(expected[d]),
258 rawbits_to_fp(expected[d]));
259 printf(" Found: 0x%0*" PRIx64 " (%g)\n",
260 d_bits / 4, static_cast<uint64_t>(results[d]),
261 rawbits_to_fp(results[d]));
262 printf("\n");
263 }
264 }
265 VIXL_ASSERT(d == expected_length);
266 if (error_count > kErrorReportLimit) {
267 printf("%u other errors follow.\n", error_count - kErrorReportLimit);
268 }
269 VIXL_CHECK(error_count == 0);
270 }
271 delete[] results;
272 }
273
274
Test2Op_Helper(Test2OpFPHelper_t helper,uintptr_t inputs,unsigned inputs_length,uintptr_t results,unsigned reg_size)275 static void Test2Op_Helper(Test2OpFPHelper_t helper,
276 uintptr_t inputs, unsigned inputs_length,
277 uintptr_t results, unsigned reg_size) {
278 VIXL_ASSERT((reg_size == kDRegSize) || (reg_size == kSRegSize));
279
280 SETUP();
281 START();
282
283 // Roll up the loop to keep the code size down.
284 Label loop_n, loop_m;
285
286 Register out = x0;
287 Register inputs_base = x1;
288 Register length = w2;
289 Register index_n = w3;
290 Register index_m = w4;
291
292 bool double_op = reg_size == kDRegSize;
293 const int index_shift =
294 double_op ? kDRegSizeInBytesLog2 : kSRegSizeInBytesLog2;
295
296 FPRegister fd = double_op ? d0 : s0;
297 FPRegister fn = double_op ? d1 : s1;
298 FPRegister fm = double_op ? d2 : s2;
299
300 __ Mov(out, results);
301 __ Mov(inputs_base, inputs);
302 __ Mov(length, inputs_length);
303
304 __ Mov(index_n, 0);
305 __ Bind(&loop_n);
306 __ Ldr(fn, MemOperand(inputs_base, index_n, UXTW, index_shift));
307
308 __ Mov(index_m, 0);
309 __ Bind(&loop_m);
310 __ Ldr(fm, MemOperand(inputs_base, index_m, UXTW, index_shift));
311
312 (masm.*helper)(fd, fn, fm);
313 __ Str(fd, MemOperand(out, fd.SizeInBytes(), PostIndex));
314
315 __ Add(index_m, index_m, 1);
316 __ Cmp(index_m, inputs_length);
317 __ B(lo, &loop_m);
318
319 __ Add(index_n, index_n, 1);
320 __ Cmp(index_n, inputs_length);
321 __ B(lo, &loop_n);
322
323 END();
324 RUN();
325 TEARDOWN();
326 }
327
328
329 // Test FP instructions. The inputs[] and expected[] arrays should be arrays of
330 // rawbits representations of doubles or floats. This ensures that exact bit
331 // comparisons can be performed.
332 template <typename T>
Test2Op(const char * name,Test2OpFPHelper_t helper,const T inputs[],unsigned inputs_length,const T expected[],unsigned expected_length)333 static void Test2Op(const char * name, Test2OpFPHelper_t helper,
334 const T inputs[], unsigned inputs_length,
335 const T expected[], unsigned expected_length) {
336 VIXL_ASSERT(inputs_length > 0);
337
338 const unsigned results_length = inputs_length * inputs_length;
339 T * results = new T[results_length];
340
341 const unsigned bits = sizeof(T) * 8;
342
343 Test2Op_Helper(helper, reinterpret_cast<uintptr_t>(inputs), inputs_length,
344 reinterpret_cast<uintptr_t>(results), bits);
345
346 if (Cctest::sim_test_trace()) {
347 // Print the results.
348 printf("const uint%u_t kExpected_%s[] = {\n", bits, name);
349 for (unsigned d = 0; d < results_length; d++) {
350 printf(" 0x%0*" PRIx64 ",\n",
351 bits / 4, static_cast<uint64_t>(results[d]));
352 }
353 printf("};\n");
354 printf("const unsigned kExpectedCount_%s = %u;\n", name, results_length);
355 } else {
356 // Check the results.
357 VIXL_CHECK(expected_length == results_length);
358 unsigned error_count = 0;
359 unsigned d = 0;
360 for (unsigned n = 0; n < inputs_length; n++) {
361 for (unsigned m = 0; m < inputs_length; m++, d++) {
362 if (results[d] != expected[d]) {
363 if (++error_count > kErrorReportLimit) continue;
364
365 printf("%s 0x%0*" PRIx64 ", 0x%0*" PRIx64 " (%s %g %g):\n",
366 name,
367 bits / 4, static_cast<uint64_t>(inputs[n]),
368 bits / 4, static_cast<uint64_t>(inputs[m]),
369 name,
370 rawbits_to_fp(inputs[n]),
371 rawbits_to_fp(inputs[m]));
372 printf(" Expected: 0x%0*" PRIx64 " (%g)\n",
373 bits / 4, static_cast<uint64_t>(expected[d]),
374 rawbits_to_fp(expected[d]));
375 printf(" Found: 0x%0*" PRIx64 " (%g)\n",
376 bits / 4, static_cast<uint64_t>(results[d]),
377 rawbits_to_fp(results[d]));
378 printf("\n");
379 }
380 }
381 }
382 VIXL_ASSERT(d == expected_length);
383 if (error_count > kErrorReportLimit) {
384 printf("%u other errors follow.\n", error_count - kErrorReportLimit);
385 }
386 VIXL_CHECK(error_count == 0);
387 }
388 delete[] results;
389 }
390
391
Test3Op_Helper(Test3OpFPHelper_t helper,uintptr_t inputs,unsigned inputs_length,uintptr_t results,unsigned reg_size)392 static void Test3Op_Helper(Test3OpFPHelper_t helper,
393 uintptr_t inputs, unsigned inputs_length,
394 uintptr_t results, unsigned reg_size) {
395 VIXL_ASSERT((reg_size == kDRegSize) || (reg_size == kSRegSize));
396
397 SETUP();
398 START();
399
400 // Roll up the loop to keep the code size down.
401 Label loop_n, loop_m, loop_a;
402
403 Register out = x0;
404 Register inputs_base = x1;
405 Register length = w2;
406 Register index_n = w3;
407 Register index_m = w4;
408 Register index_a = w5;
409
410 bool double_op = reg_size == kDRegSize;
411 const int index_shift =
412 double_op ? kDRegSizeInBytesLog2 : kSRegSizeInBytesLog2;
413
414 FPRegister fd = double_op ? d0 : s0;
415 FPRegister fn = double_op ? d1 : s1;
416 FPRegister fm = double_op ? d2 : s2;
417 FPRegister fa = double_op ? d3 : s3;
418
419 __ Mov(out, results);
420 __ Mov(inputs_base, inputs);
421 __ Mov(length, inputs_length);
422
423 __ Mov(index_n, 0);
424 __ Bind(&loop_n);
425 __ Ldr(fn, MemOperand(inputs_base, index_n, UXTW, index_shift));
426
427 __ Mov(index_m, 0);
428 __ Bind(&loop_m);
429 __ Ldr(fm, MemOperand(inputs_base, index_m, UXTW, index_shift));
430
431 __ Mov(index_a, 0);
432 __ Bind(&loop_a);
433 __ Ldr(fa, MemOperand(inputs_base, index_a, UXTW, index_shift));
434
435 (masm.*helper)(fd, fn, fm, fa);
436 __ Str(fd, MemOperand(out, fd.SizeInBytes(), PostIndex));
437
438 __ Add(index_a, index_a, 1);
439 __ Cmp(index_a, inputs_length);
440 __ B(lo, &loop_a);
441
442 __ Add(index_m, index_m, 1);
443 __ Cmp(index_m, inputs_length);
444 __ B(lo, &loop_m);
445
446 __ Add(index_n, index_n, 1);
447 __ Cmp(index_n, inputs_length);
448 __ B(lo, &loop_n);
449
450 END();
451 RUN();
452 TEARDOWN();
453 }
454
455
456 // Test FP instructions. The inputs[] and expected[] arrays should be arrays of
457 // rawbits representations of doubles or floats. This ensures that exact bit
458 // comparisons can be performed.
459 template <typename T>
Test3Op(const char * name,Test3OpFPHelper_t helper,const T inputs[],unsigned inputs_length,const T expected[],unsigned expected_length)460 static void Test3Op(const char * name, Test3OpFPHelper_t helper,
461 const T inputs[], unsigned inputs_length,
462 const T expected[], unsigned expected_length) {
463 VIXL_ASSERT(inputs_length > 0);
464
465 const unsigned results_length = inputs_length * inputs_length * inputs_length;
466 T * results = new T[results_length];
467
468 const unsigned bits = sizeof(T) * 8;
469
470 Test3Op_Helper(helper, reinterpret_cast<uintptr_t>(inputs), inputs_length,
471 reinterpret_cast<uintptr_t>(results), bits);
472
473 if (Cctest::sim_test_trace()) {
474 // Print the results.
475 printf("const uint%u_t kExpected_%s[] = {\n", bits, name);
476 for (unsigned d = 0; d < results_length; d++) {
477 printf(" 0x%0*" PRIx64 ",\n",
478 bits / 4, static_cast<uint64_t>(results[d]));
479 }
480 printf("};\n");
481 printf("const unsigned kExpectedCount_%s = %u;\n", name, results_length);
482 } else {
483 // Check the results.
484 VIXL_CHECK(expected_length == results_length);
485 unsigned error_count = 0;
486 unsigned d = 0;
487 for (unsigned n = 0; n < inputs_length; n++) {
488 for (unsigned m = 0; m < inputs_length; m++) {
489 for (unsigned a = 0; a < inputs_length; a++, d++) {
490 if (results[d] != expected[d]) {
491 if (++error_count > kErrorReportLimit) continue;
492
493 printf("%s 0x%0*" PRIx64 ", 0x%0*" PRIx64 ", 0x%0*" PRIx64
494 " (%s %g %g %g):\n",
495 name,
496 bits / 4, static_cast<uint64_t>(inputs[n]),
497 bits / 4, static_cast<uint64_t>(inputs[m]),
498 bits / 4, static_cast<uint64_t>(inputs[a]),
499 name,
500 rawbits_to_fp(inputs[n]),
501 rawbits_to_fp(inputs[m]),
502 rawbits_to_fp(inputs[a]));
503 printf(" Expected: 0x%0*" PRIx64 " (%g)\n",
504 bits / 4, static_cast<uint64_t>(expected[d]),
505 rawbits_to_fp(expected[d]));
506 printf(" Found: 0x%0*" PRIx64 " (%g)\n",
507 bits / 4, static_cast<uint64_t>(results[d]),
508 rawbits_to_fp(results[d]));
509 printf("\n");
510 }
511 }
512 }
513 }
514 VIXL_ASSERT(d == expected_length);
515 if (error_count > kErrorReportLimit) {
516 printf("%u other errors follow.\n", error_count - kErrorReportLimit);
517 }
518 VIXL_CHECK(error_count == 0);
519 }
520 delete[] results;
521 }
522
523
TestCmp_Helper(TestFPCmpHelper_t helper,uintptr_t inputs,unsigned inputs_length,uintptr_t results,unsigned reg_size)524 static void TestCmp_Helper(TestFPCmpHelper_t helper,
525 uintptr_t inputs, unsigned inputs_length,
526 uintptr_t results, unsigned reg_size) {
527 VIXL_ASSERT((reg_size == kDRegSize) || (reg_size == kSRegSize));
528
529 SETUP();
530 START();
531
532 // Roll up the loop to keep the code size down.
533 Label loop_n, loop_m;
534
535 Register out = x0;
536 Register inputs_base = x1;
537 Register length = w2;
538 Register index_n = w3;
539 Register index_m = w4;
540 Register flags = x5;
541
542 bool double_op = reg_size == kDRegSize;
543 const int index_shift =
544 double_op ? kDRegSizeInBytesLog2 : kSRegSizeInBytesLog2;
545
546 FPRegister fn = double_op ? d1 : s1;
547 FPRegister fm = double_op ? d2 : s2;
548
549 __ Mov(out, results);
550 __ Mov(inputs_base, inputs);
551 __ Mov(length, inputs_length);
552
553 __ Mov(index_n, 0);
554 __ Bind(&loop_n);
555 __ Ldr(fn, MemOperand(inputs_base, index_n, UXTW, index_shift));
556
557 __ Mov(index_m, 0);
558 __ Bind(&loop_m);
559 __ Ldr(fm, MemOperand(inputs_base, index_m, UXTW, index_shift));
560
561 (masm.*helper)(fn, fm);
562 __ Mrs(flags, NZCV);
563 __ Ubfx(flags, flags, 28, 4);
564 __ Strb(flags, MemOperand(out, 1, PostIndex));
565
566 __ Add(index_m, index_m, 1);
567 __ Cmp(index_m, inputs_length);
568 __ B(lo, &loop_m);
569
570 __ Add(index_n, index_n, 1);
571 __ Cmp(index_n, inputs_length);
572 __ B(lo, &loop_n);
573
574 END();
575 RUN();
576 TEARDOWN();
577 }
578
579
580 // Test FP instructions. The inputs[] and expected[] arrays should be arrays of
581 // rawbits representations of doubles or floats. This ensures that exact bit
582 // comparisons can be performed.
583 template <typename T>
TestCmp(const char * name,TestFPCmpHelper_t helper,const T inputs[],unsigned inputs_length,const uint8_t expected[],unsigned expected_length)584 static void TestCmp(const char * name, TestFPCmpHelper_t helper,
585 const T inputs[], unsigned inputs_length,
586 const uint8_t expected[], unsigned expected_length) {
587 VIXL_ASSERT(inputs_length > 0);
588
589 const unsigned results_length = inputs_length * inputs_length;
590 uint8_t * results = new uint8_t[results_length];
591
592 const unsigned bits = sizeof(T) * 8;
593
594 TestCmp_Helper(helper, reinterpret_cast<uintptr_t>(inputs), inputs_length,
595 reinterpret_cast<uintptr_t>(results), bits);
596
597 if (Cctest::sim_test_trace()) {
598 // Print the results.
599 printf("const uint8_t kExpected_%s[] = {\n", name);
600 for (unsigned d = 0; d < results_length; d++) {
601 // Each NZCV result only requires 4 bits.
602 VIXL_ASSERT((results[d] & 0xf) == results[d]);
603 printf(" 0x%" PRIx8 ",\n", results[d]);
604 }
605 printf("};\n");
606 printf("const unsigned kExpectedCount_%s = %u;\n", name, results_length);
607 } else {
608 // Check the results.
609 VIXL_CHECK(expected_length == results_length);
610 unsigned error_count = 0;
611 unsigned d = 0;
612 for (unsigned n = 0; n < inputs_length; n++) {
613 for (unsigned m = 0; m < inputs_length; m++, d++) {
614 if (results[d] != expected[d]) {
615 if (++error_count > kErrorReportLimit) continue;
616
617 printf("%s 0x%0*" PRIx64 ", 0x%0*" PRIx64 " (%s %g %g):\n",
618 name,
619 bits / 4, static_cast<uint64_t>(inputs[n]),
620 bits / 4, static_cast<uint64_t>(inputs[m]),
621 name,
622 rawbits_to_fp(inputs[n]),
623 rawbits_to_fp(inputs[m]));
624 printf(" Expected: %c%c%c%c (0x%" PRIx8 ")\n",
625 (expected[d] & 0x8) ? 'N' : 'n',
626 (expected[d] & 0x4) ? 'Z' : 'z',
627 (expected[d] & 0x2) ? 'C' : 'c',
628 (expected[d] & 0x1) ? 'V' : 'v',
629 expected[d]);
630 printf(" Found: %c%c%c%c (0x%" PRIx8 ")\n",
631 (results[d] & 0x8) ? 'N' : 'n',
632 (results[d] & 0x4) ? 'Z' : 'z',
633 (results[d] & 0x2) ? 'C' : 'c',
634 (results[d] & 0x1) ? 'V' : 'v',
635 results[d]);
636 printf("\n");
637 }
638 }
639 }
640 VIXL_ASSERT(d == expected_length);
641 if (error_count > kErrorReportLimit) {
642 printf("%u other errors follow.\n", error_count - kErrorReportLimit);
643 }
644 VIXL_CHECK(error_count == 0);
645 }
646 delete[] results;
647 }
648
649
TestCmpZero_Helper(TestFPCmpZeroHelper_t helper,uintptr_t inputs,unsigned inputs_length,uintptr_t results,unsigned reg_size)650 static void TestCmpZero_Helper(TestFPCmpZeroHelper_t helper,
651 uintptr_t inputs, unsigned inputs_length,
652 uintptr_t results, unsigned reg_size) {
653 VIXL_ASSERT((reg_size == kDRegSize) || (reg_size == kSRegSize));
654
655 SETUP();
656 START();
657
658 // Roll up the loop to keep the code size down.
659 Label loop_n, loop_m;
660
661 Register out = x0;
662 Register inputs_base = x1;
663 Register length = w2;
664 Register index_n = w3;
665 Register flags = x4;
666
667 bool double_op = reg_size == kDRegSize;
668 const int index_shift =
669 double_op ? kDRegSizeInBytesLog2 : kSRegSizeInBytesLog2;
670
671 FPRegister fn = double_op ? d1 : s1;
672
673 __ Mov(out, results);
674 __ Mov(inputs_base, inputs);
675 __ Mov(length, inputs_length);
676
677 __ Mov(index_n, 0);
678 __ Bind(&loop_n);
679 __ Ldr(fn, MemOperand(inputs_base, index_n, UXTW, index_shift));
680
681 (masm.*helper)(fn, 0.0);
682 __ Mrs(flags, NZCV);
683 __ Ubfx(flags, flags, 28, 4);
684 __ Strb(flags, MemOperand(out, 1, PostIndex));
685
686 __ Add(index_n, index_n, 1);
687 __ Cmp(index_n, inputs_length);
688 __ B(lo, &loop_n);
689
690 END();
691 RUN();
692 TEARDOWN();
693 }
694
695
696 // Test FP instructions. The inputs[] and expected[] arrays should be arrays of
697 // rawbits representations of doubles or floats. This ensures that exact bit
698 // comparisons can be performed.
699 template <typename T>
TestCmpZero(const char * name,TestFPCmpZeroHelper_t helper,const T inputs[],unsigned inputs_length,const uint8_t expected[],unsigned expected_length)700 static void TestCmpZero(const char * name, TestFPCmpZeroHelper_t helper,
701 const T inputs[], unsigned inputs_length,
702 const uint8_t expected[], unsigned expected_length) {
703 VIXL_ASSERT(inputs_length > 0);
704
705 const unsigned results_length = inputs_length;
706 uint8_t * results = new uint8_t[results_length];
707
708 const unsigned bits = sizeof(T) * 8;
709
710 TestCmpZero_Helper(helper, reinterpret_cast<uintptr_t>(inputs), inputs_length,
711 reinterpret_cast<uintptr_t>(results), bits);
712
713 if (Cctest::sim_test_trace()) {
714 // Print the results.
715 printf("const uint8_t kExpected_%s[] = {\n", name);
716 for (unsigned d = 0; d < results_length; d++) {
717 // Each NZCV result only requires 4 bits.
718 VIXL_ASSERT((results[d] & 0xf) == results[d]);
719 printf(" 0x%" PRIx8 ",\n", results[d]);
720 }
721 printf("};\n");
722 printf("const unsigned kExpectedCount_%s = %u;\n", name, results_length);
723 } else {
724 // Check the results.
725 VIXL_CHECK(expected_length == results_length);
726 unsigned error_count = 0;
727 unsigned d = 0;
728 for (unsigned n = 0; n < inputs_length; n++, d++) {
729 if (results[d] != expected[d]) {
730 if (++error_count > kErrorReportLimit) continue;
731
732 printf("%s 0x%0*" PRIx64 ", 0x%0*u (%s %g #0.0):\n",
733 name,
734 bits / 4, static_cast<uint64_t>(inputs[n]),
735 bits / 4, 0,
736 name,
737 rawbits_to_fp(inputs[n]));
738 printf(" Expected: %c%c%c%c (0x%" PRIx8 ")\n",
739 (expected[d] & 0x8) ? 'N' : 'n',
740 (expected[d] & 0x4) ? 'Z' : 'z',
741 (expected[d] & 0x2) ? 'C' : 'c',
742 (expected[d] & 0x1) ? 'V' : 'v',
743 expected[d]);
744 printf(" Found: %c%c%c%c (0x%" PRIx8 ")\n",
745 (results[d] & 0x8) ? 'N' : 'n',
746 (results[d] & 0x4) ? 'Z' : 'z',
747 (results[d] & 0x2) ? 'C' : 'c',
748 (results[d] & 0x1) ? 'V' : 'v',
749 results[d]);
750 printf("\n");
751 }
752 }
753 VIXL_ASSERT(d == expected_length);
754 if (error_count > kErrorReportLimit) {
755 printf("%u other errors follow.\n", error_count - kErrorReportLimit);
756 }
757 VIXL_CHECK(error_count == 0);
758 }
759 delete[] results;
760 }
761
762
TestFPToInt_Helper(TestFPToIntHelper_t helper,uintptr_t inputs,unsigned inputs_length,uintptr_t results,unsigned d_size,unsigned n_size)763 static void TestFPToInt_Helper(TestFPToIntHelper_t helper, uintptr_t inputs,
764 unsigned inputs_length, uintptr_t results,
765 unsigned d_size, unsigned n_size) {
766 VIXL_ASSERT((d_size == kXRegSize) || (d_size == kWRegSize));
767 VIXL_ASSERT((n_size == kDRegSize) || (n_size == kSRegSize));
768
769 SETUP();
770 START();
771
772 // Roll up the loop to keep the code size down.
773 Label loop_n;
774
775 Register out = x0;
776 Register inputs_base = x1;
777 Register length = w2;
778 Register index_n = w3;
779
780 const int n_index_shift =
781 (n_size == kDRegSize) ? kDRegSizeInBytesLog2 : kSRegSizeInBytesLog2;
782
783 Register rd = (d_size == kXRegSize) ? x10 : w10;
784 FPRegister fn = (n_size == kDRegSize) ? d1 : s1;
785
786 __ Mov(out, results);
787 __ Mov(inputs_base, inputs);
788 __ Mov(length, inputs_length);
789
790 __ Mov(index_n, 0);
791 __ Bind(&loop_n);
792 __ Ldr(fn, MemOperand(inputs_base, index_n, UXTW, n_index_shift));
793
794 (masm.*helper)(rd, fn);
795 __ Str(rd, MemOperand(out, rd.SizeInBytes(), PostIndex));
796
797 __ Add(index_n, index_n, 1);
798 __ Cmp(index_n, inputs_length);
799 __ B(lo, &loop_n);
800
801 END();
802 RUN();
803 TEARDOWN();
804 }
805
806
807 // Test FP instructions.
808 // - The inputs[] array should be an array of rawbits representations of
809 // doubles or floats. This ensures that exact bit comparisons can be
810 // performed.
811 // - The expected[] array should be an array of signed integers.
812 template <typename Tn, typename Td>
TestFPToS(const char * name,TestFPToIntHelper_t helper,const Tn inputs[],unsigned inputs_length,const Td expected[],unsigned expected_length)813 static void TestFPToS(const char * name, TestFPToIntHelper_t helper,
814 const Tn inputs[], unsigned inputs_length,
815 const Td expected[], unsigned expected_length) {
816 VIXL_ASSERT(inputs_length > 0);
817
818 const unsigned results_length = inputs_length;
819 Td * results = new Td[results_length];
820
821 const unsigned d_bits = sizeof(Td) * 8;
822 const unsigned n_bits = sizeof(Tn) * 8;
823
824 TestFPToInt_Helper(helper, reinterpret_cast<uintptr_t>(inputs), inputs_length,
825 reinterpret_cast<uintptr_t>(results), d_bits, n_bits);
826
827 if (Cctest::sim_test_trace()) {
828 // Print the results.
829 printf("const int%u_t kExpected_%s[] = {\n", d_bits, name);
830 // There is no simple C++ literal for INT*_MIN that doesn't produce
831 // warnings, so we use an appropriate constant in that case instead.
832 // Deriving int_d_min in this way (rather than just checking INT64_MIN and
833 // the like) avoids warnings about comparing values with differing ranges.
834 const int64_t int_d_max = (UINT64_C(1) << (d_bits - 1)) - 1;
835 const int64_t int_d_min = -(int_d_max) - 1;
836 for (unsigned d = 0; d < results_length; d++) {
837 if (results[d] == int_d_min) {
838 printf(" -INT%u_C(%" PRId64 ") - 1,\n", d_bits, int_d_max);
839 } else {
840 printf(" %" PRId64 ",\n", static_cast<int64_t>(results[d]));
841 }
842 }
843 printf("};\n");
844 printf("const unsigned kExpectedCount_%s = %u;\n", name, results_length);
845 } else {
846 // Check the results.
847 VIXL_CHECK(expected_length == results_length);
848 unsigned error_count = 0;
849 unsigned d = 0;
850 for (unsigned n = 0; n < inputs_length; n++, d++) {
851 if (results[d] != expected[d]) {
852 if (++error_count > kErrorReportLimit) continue;
853
854 printf("%s 0x%0*" PRIx64 " (%s %g):\n",
855 name, n_bits / 4, static_cast<uint64_t>(inputs[n]),
856 name, rawbits_to_fp(inputs[n]));
857 printf(" Expected: 0x%0*" PRIx64 " (%" PRId64 ")\n",
858 d_bits / 4, static_cast<uint64_t>(expected[d]),
859 static_cast<int64_t>(expected[d]));
860 printf(" Found: 0x%0*" PRIx64 " (%" PRId64 ")\n",
861 d_bits / 4, static_cast<uint64_t>(results[d]),
862 static_cast<int64_t>(results[d]));
863 printf("\n");
864 }
865 }
866 VIXL_ASSERT(d == expected_length);
867 if (error_count > kErrorReportLimit) {
868 printf("%u other errors follow.\n", error_count - kErrorReportLimit);
869 }
870 VIXL_CHECK(error_count == 0);
871 }
872 delete[] results;
873 }
874
875
876 // Test FP instructions.
877 // - The inputs[] array should be an array of rawbits representations of
878 // doubles or floats. This ensures that exact bit comparisons can be
879 // performed.
880 // - The expected[] array should be an array of unsigned integers.
881 template <typename Tn, typename Td>
TestFPToU(const char * name,TestFPToIntHelper_t helper,const Tn inputs[],unsigned inputs_length,const Td expected[],unsigned expected_length)882 static void TestFPToU(const char * name, TestFPToIntHelper_t helper,
883 const Tn inputs[], unsigned inputs_length,
884 const Td expected[], unsigned expected_length) {
885 VIXL_ASSERT(inputs_length > 0);
886
887 const unsigned results_length = inputs_length;
888 Td * results = new Td[results_length];
889
890 const unsigned d_bits = sizeof(Td) * 8;
891 const unsigned n_bits = sizeof(Tn) * 8;
892
893 TestFPToInt_Helper(helper, reinterpret_cast<uintptr_t>(inputs), inputs_length,
894 reinterpret_cast<uintptr_t>(results), d_bits, n_bits);
895
896 if (Cctest::sim_test_trace()) {
897 // Print the results.
898 printf("const uint%u_t kExpected_%s[] = {\n", d_bits, name);
899 for (unsigned d = 0; d < results_length; d++) {
900 printf(" %" PRIu64 "u,\n", static_cast<uint64_t>(results[d]));
901 }
902 printf("};\n");
903 printf("const unsigned kExpectedCount_%s = %u;\n", name, results_length);
904 } else {
905 // Check the results.
906 VIXL_CHECK(expected_length == results_length);
907 unsigned error_count = 0;
908 unsigned d = 0;
909 for (unsigned n = 0; n < inputs_length; n++, d++) {
910 if (results[d] != expected[d]) {
911 if (++error_count > kErrorReportLimit) continue;
912
913 printf("%s 0x%0*" PRIx64 " (%s %g):\n",
914 name, n_bits / 4, static_cast<uint64_t>(inputs[n]),
915 name, rawbits_to_fp(inputs[n]));
916 printf(" Expected: 0x%0*" PRIx64 " (%" PRIu64 ")\n",
917 d_bits / 4, static_cast<uint64_t>(expected[d]),
918 static_cast<uint64_t>(expected[d]));
919 printf(" Found: 0x%0*" PRIx64 " (%" PRIu64 ")\n",
920 d_bits / 4, static_cast<uint64_t>(results[d]),
921 static_cast<uint64_t>(results[d]));
922 printf("\n");
923 }
924 }
925 VIXL_ASSERT(d == expected_length);
926 if (error_count > kErrorReportLimit) {
927 printf("%u other errors follow.\n", error_count - kErrorReportLimit);
928 }
929 VIXL_CHECK(error_count == 0);
930 }
931 delete[] results;
932 }
933
934
935 // Floating-point tests.
936
937
938 // Standard floating-point test expansion for both double- and single-precision
939 // operations.
940 #define STRINGIFY(s) #s
941
942 #define CALL_TEST_FP_HELPER(mnemonic, variant, type, input) \
943 Test##type(STRINGIFY(mnemonic) "_" STRINGIFY(variant), \
944 &MacroAssembler::mnemonic, \
945 input, sizeof(input) / sizeof(input[0]), \
946 kExpected_##mnemonic##_##variant, \
947 kExpectedCount_##mnemonic##_##variant)
948
949 #define DEFINE_TEST_FP(mnemonic, type, input) \
950 TEST(mnemonic##_d) { \
951 CALL_TEST_FP_HELPER(mnemonic, d, type, kInputDouble##input); \
952 } \
953 TEST(mnemonic##_s) { \
954 CALL_TEST_FP_HELPER(mnemonic, s, type, kInputFloat##input); \
955 }
956
957 DEFINE_TEST_FP(fmadd, 3Op, Basic)
958 DEFINE_TEST_FP(fmsub, 3Op, Basic)
959 DEFINE_TEST_FP(fnmadd, 3Op, Basic)
960 DEFINE_TEST_FP(fnmsub, 3Op, Basic)
961
962 DEFINE_TEST_FP(fadd, 2Op, Basic)
963 DEFINE_TEST_FP(fdiv, 2Op, Basic)
964 DEFINE_TEST_FP(fmax, 2Op, Basic)
965 DEFINE_TEST_FP(fmaxnm, 2Op, Basic)
966 DEFINE_TEST_FP(fmin, 2Op, Basic)
967 DEFINE_TEST_FP(fminnm, 2Op, Basic)
968 DEFINE_TEST_FP(fmul, 2Op, Basic)
969 DEFINE_TEST_FP(fsub, 2Op, Basic)
970
971 DEFINE_TEST_FP(fabs, 1Op, Basic)
972 DEFINE_TEST_FP(fmov, 1Op, Basic)
973 DEFINE_TEST_FP(fneg, 1Op, Basic)
974 DEFINE_TEST_FP(fsqrt, 1Op, Basic)
975 DEFINE_TEST_FP(frinta, 1Op, Conversions)
976 DEFINE_TEST_FP(frintn, 1Op, Conversions)
977 DEFINE_TEST_FP(frintz, 1Op, Conversions)
978
TEST(fcmp_d)979 TEST(fcmp_d) { CALL_TEST_FP_HELPER(fcmp, d, Cmp, kInputDoubleBasic); }
TEST(fcmp_s)980 TEST(fcmp_s) { CALL_TEST_FP_HELPER(fcmp, s, Cmp, kInputFloatBasic); }
TEST(fcmp_dz)981 TEST(fcmp_dz) { CALL_TEST_FP_HELPER(fcmp, dz, CmpZero, kInputDoubleBasic); }
TEST(fcmp_sz)982 TEST(fcmp_sz) { CALL_TEST_FP_HELPER(fcmp, sz, CmpZero, kInputFloatBasic); }
983
TEST(fcvt_sd)984 TEST(fcvt_sd) { CALL_TEST_FP_HELPER(fcvt, sd, 1Op, kInputDoubleConversions); }
TEST(fcvt_ds)985 TEST(fcvt_ds) { CALL_TEST_FP_HELPER(fcvt, ds, 1Op, kInputFloatConversions); }
986
987 #define DEFINE_TEST_FP_TO_INT(mnemonic, type, input) \
988 TEST(mnemonic##_xd) { \
989 CALL_TEST_FP_HELPER(mnemonic, xd, type, kInputDouble##input); \
990 } \
991 TEST(mnemonic##_xs) { \
992 CALL_TEST_FP_HELPER(mnemonic, xs, type, kInputFloat##input); \
993 } \
994 TEST(mnemonic##_wd) { \
995 CALL_TEST_FP_HELPER(mnemonic, wd, type, kInputDouble##input); \
996 } \
997 TEST(mnemonic##_ws) { \
998 CALL_TEST_FP_HELPER(mnemonic, ws, type, kInputFloat##input); \
999 }
1000
1001 DEFINE_TEST_FP_TO_INT(fcvtas, FPToS, Conversions)
1002 DEFINE_TEST_FP_TO_INT(fcvtau, FPToU, Conversions)
1003 DEFINE_TEST_FP_TO_INT(fcvtms, FPToS, Conversions)
1004 DEFINE_TEST_FP_TO_INT(fcvtmu, FPToU, Conversions)
1005 DEFINE_TEST_FP_TO_INT(fcvtns, FPToS, Conversions)
1006 DEFINE_TEST_FP_TO_INT(fcvtnu, FPToU, Conversions)
1007 DEFINE_TEST_FP_TO_INT(fcvtzs, FPToS, Conversions)
1008 DEFINE_TEST_FP_TO_INT(fcvtzu, FPToU, Conversions)
1009
1010 // TODO(jbramley): Scvtf-fixed-point
1011 // TODO(jbramley): Scvtf-integer
1012 // TODO(jbramley): Ucvtf-fixed-point
1013 // TODO(jbramley): Ucvtf-integer
1014
1015 // TODO(jbramley): Fccmp
1016 // TODO(jbramley): Fcsel
1017
1018 } // namespace vixl
1019