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