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