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
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  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.
136static 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.
141static float rawbits_to_fp(uint32_t bits) {
142  return rawbits_to_float(bits);
143}
144
145static 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.
151typedef void (MacroAssembler::*Test1OpFPHelper_t)(const FPRegister& fd,
152                                                  const FPRegister& fn);
153typedef void (MacroAssembler::*Test2OpFPHelper_t)(const FPRegister& fd,
154                                                  const FPRegister& fn,
155                                                  const FPRegister& fm);
156typedef void (MacroAssembler::*Test3OpFPHelper_t)(const FPRegister& fd,
157                                                  const FPRegister& fn,
158                                                  const FPRegister& fm,
159                                                  const FPRegister& fa);
160typedef void (MacroAssembler::*TestFPCmpHelper_t)(const FPRegister& fn,
161                                                  const FPRegister& fm);
162typedef void (MacroAssembler::*TestFPCmpZeroHelper_t)(const FPRegister& fn,
163                                                      double value);
164typedef void (MacroAssembler::*TestFPToIntHelper_t)(const Register& rd,
165                                                    const FPRegister& fn);
166typedef void (MacroAssembler::*TestFixedToFPHelper_t)(const FPRegister& fd,
167                                                      const Register& rn,
168                                                      unsigned fbits);
169
170// Standard test dispatchers.
171
172
173static 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.
220template <typename Tn, typename Td>
221static 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
275static 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.
332template <typename T>
333static 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
392static 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.
459template <typename T>
460static 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
524static 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.
583template <typename T>
584static 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
650static 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.
699template <typename T>
700static 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
763static 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.
812template <typename Tn, typename Td>
813static 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.
881template <typename Tn, typename Td>
882static 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
957DEFINE_TEST_FP(fmadd, 3Op, Basic)
958DEFINE_TEST_FP(fmsub, 3Op, Basic)
959DEFINE_TEST_FP(fnmadd, 3Op, Basic)
960DEFINE_TEST_FP(fnmsub, 3Op, Basic)
961
962DEFINE_TEST_FP(fadd, 2Op, Basic)
963DEFINE_TEST_FP(fdiv, 2Op, Basic)
964DEFINE_TEST_FP(fmax, 2Op, Basic)
965DEFINE_TEST_FP(fmaxnm, 2Op, Basic)
966DEFINE_TEST_FP(fmin, 2Op, Basic)
967DEFINE_TEST_FP(fminnm, 2Op, Basic)
968DEFINE_TEST_FP(fmul, 2Op, Basic)
969DEFINE_TEST_FP(fsub, 2Op, Basic)
970
971DEFINE_TEST_FP(fabs, 1Op, Basic)
972DEFINE_TEST_FP(fmov, 1Op, Basic)
973DEFINE_TEST_FP(fneg, 1Op, Basic)
974DEFINE_TEST_FP(fsqrt, 1Op, Basic)
975DEFINE_TEST_FP(frinta, 1Op, Conversions)
976DEFINE_TEST_FP(frintn, 1Op, Conversions)
977DEFINE_TEST_FP(frintz, 1Op, Conversions)
978
979TEST(fcmp_d) { CALL_TEST_FP_HELPER(fcmp, d, Cmp, kInputDoubleBasic); }
980TEST(fcmp_s) { CALL_TEST_FP_HELPER(fcmp, s, Cmp, kInputFloatBasic); }
981TEST(fcmp_dz) { CALL_TEST_FP_HELPER(fcmp, dz, CmpZero, kInputDoubleBasic); }
982TEST(fcmp_sz) { CALL_TEST_FP_HELPER(fcmp, sz, CmpZero, kInputFloatBasic); }
983
984TEST(fcvt_sd) { CALL_TEST_FP_HELPER(fcvt, sd, 1Op, kInputDoubleConversions); }
985TEST(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
1001DEFINE_TEST_FP_TO_INT(fcvtas, FPToS, Conversions)
1002DEFINE_TEST_FP_TO_INT(fcvtau, FPToU, Conversions)
1003DEFINE_TEST_FP_TO_INT(fcvtms, FPToS, Conversions)
1004DEFINE_TEST_FP_TO_INT(fcvtmu, FPToU, Conversions)
1005DEFINE_TEST_FP_TO_INT(fcvtns, FPToS, Conversions)
1006DEFINE_TEST_FP_TO_INT(fcvtnu, FPToU, Conversions)
1007DEFINE_TEST_FP_TO_INT(fcvtzs, FPToS, Conversions)
1008DEFINE_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