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