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