testJitMacroAssembler.cpp (31779B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 3 */ 4 /* This Source Code Form is subject to the terms of the Mozilla Public 5 * License, v. 2.0. If a copy of the MPL was not distributed with this 6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 7 8 #include "mozilla/Sprintf.h" 9 10 #include "jit/IonAnalysis.h" 11 #include "jit/Linker.h" 12 #include "jit/MacroAssembler.h" 13 #include "jit/MIRGenerator.h" 14 #include "jit/MIRGraph.h" 15 #include "jit/ValueNumbering.h" 16 #include "js/Value.h" 17 18 #include "jsapi-tests/tests.h" 19 #include "jsapi-tests/testsJit.h" 20 21 #include "jit/MacroAssembler-inl.h" 22 23 using namespace js; 24 using namespace js::jit; 25 26 using mozilla::NegativeInfinity; 27 using mozilla::PositiveInfinity; 28 29 #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) 30 31 BEGIN_TEST(testJitMacroAssembler_flexibleDivMod) { 32 TempAllocator tempAlloc(&cx->tempLifoAlloc()); 33 JitContext jcx(cx); 34 StackMacroAssembler masm(cx, tempAlloc); 35 AutoCreatedBy acb(masm, __func__); 36 37 PrepareJit(masm); 38 39 // Test case divides 9/2; 40 const uintptr_t dividend = 9; 41 const uintptr_t divisor = 2; 42 const uintptr_t quotient_result = 4; 43 const uintptr_t remainder_result = 1; 44 45 AllocatableGeneralRegisterSet leftHandSides(GeneralRegisterSet::All()); 46 while (!leftHandSides.empty()) { 47 Register lhs = leftHandSides.takeAny(); 48 49 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All()); 50 while (!rightHandSides.empty()) { 51 Register rhs = rightHandSides.takeAny(); 52 53 AllocatableGeneralRegisterSet quotients(GeneralRegisterSet::All()); 54 while (!quotients.empty()) { 55 Register quotientOutput = quotients.takeAny(); 56 57 AllocatableGeneralRegisterSet remainders(GeneralRegisterSet::All()); 58 while (!remainders.empty()) { 59 Register remainderOutput = remainders.takeAny(); 60 61 // lhs and rhs are preserved by |flexibleDivMod32|, so neither can be 62 // an output register. 63 if (lhs == quotientOutput || lhs == remainderOutput) { 64 continue; 65 } 66 if (rhs == quotientOutput || rhs == remainderOutput) { 67 continue; 68 } 69 70 // Output registers must be distinct. 71 if (quotientOutput == remainderOutput) { 72 continue; 73 } 74 75 AllocatableRegisterSet regs(RegisterSet::Volatile()); 76 LiveRegisterSet save(regs.asLiveSet()); 77 78 Label next, fail; 79 masm.mov(ImmWord(dividend), lhs); 80 masm.mov(ImmWord(divisor), rhs); 81 masm.flexibleDivMod32(lhs, rhs, quotientOutput, remainderOutput, 82 false, save); 83 masm.branchPtr(Assembler::NotEqual, quotientOutput, 84 ImmWord(lhs != rhs ? quotient_result : 1), &fail); 85 masm.branchPtr(Assembler::NotEqual, remainderOutput, 86 ImmWord(lhs != rhs ? remainder_result : 0), &fail); 87 // Ensure LHS was not clobbered 88 masm.branchPtr(Assembler::NotEqual, lhs, 89 ImmWord(lhs != rhs ? dividend : divisor), &fail); 90 // Ensure RHS was not clobbered 91 masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(divisor), &fail); 92 masm.jump(&next); 93 masm.bind(&fail); 94 masm.printf("Failed\n"); 95 96 char buffer[128]; 97 SprintfLiteral( 98 buffer, 99 "\tlhs = %s, rhs = %s, quotientOutput = %s, remainderOutput " 100 "= %s\n", 101 lhs.name(), rhs.name(), quotientOutput.name(), 102 remainderOutput.name()); 103 104 masm.printf(buffer); 105 masm.printf("\tlhs = %d\n", lhs); 106 masm.printf("\trhs = %d\n", rhs); 107 masm.printf("\tquotientOutput = %d\n", quotientOutput); 108 masm.printf("\tremainderOutput = %d\n", remainderOutput); 109 110 masm.breakpoint(); 111 112 masm.bind(&next); 113 } 114 } 115 } 116 } 117 118 return ExecuteJit(cx, masm); 119 } 120 END_TEST(testJitMacroAssembler_flexibleDivMod) 121 122 BEGIN_TEST(testJitMacroAssembler_flexibleRemainder) { 123 TempAllocator tempAlloc(&cx->tempLifoAlloc()); 124 JitContext jcx(cx); 125 StackMacroAssembler masm(cx, tempAlloc); 126 AutoCreatedBy acb(masm, __func__); 127 128 PrepareJit(masm); 129 130 // Test case divides 9/2; 131 const uintptr_t dividend = 9; 132 const uintptr_t divisor = 2; 133 const uintptr_t remainder_result = 1; 134 135 AllocatableGeneralRegisterSet leftHandSides(GeneralRegisterSet::All()); 136 while (!leftHandSides.empty()) { 137 Register lhs = leftHandSides.takeAny(); 138 139 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All()); 140 while (!rightHandSides.empty()) { 141 Register rhs = rightHandSides.takeAny(); 142 143 AllocatableGeneralRegisterSet outputs(GeneralRegisterSet::All()); 144 while (!outputs.empty()) { 145 Register output = outputs.takeAny(); 146 147 AllocatableRegisterSet regs(RegisterSet::Volatile()); 148 LiveRegisterSet save(regs.asLiveSet()); 149 150 Label next, fail; 151 masm.mov(ImmWord(dividend), lhs); 152 masm.mov(ImmWord(divisor), rhs); 153 masm.flexibleRemainder32(lhs, rhs, output, false, save); 154 masm.branchPtr(Assembler::NotEqual, output, 155 ImmWord(lhs != rhs ? remainder_result : 0), &fail); 156 // Ensure LHS was not clobbered 157 if (lhs != output) { 158 masm.branchPtr(Assembler::NotEqual, lhs, 159 ImmWord(lhs != rhs ? dividend : divisor), &fail); 160 } 161 // Ensure RHS was not clobbered 162 if (rhs != output) { 163 masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(divisor), &fail); 164 } 165 masm.jump(&next); 166 masm.bind(&fail); 167 masm.printf("Failed\n"); 168 169 char buffer[128]; 170 SprintfLiteral(buffer, "\tlhs = %s, rhs = %s, output = %s\n", 171 lhs.name(), rhs.name(), output.name()); 172 173 masm.printf(buffer); 174 masm.printf("\tlhs = %d\n", lhs); 175 masm.printf("\trhs = %d\n", rhs); 176 masm.printf("\toutput = %d\n", output); 177 178 masm.breakpoint(); 179 180 masm.bind(&next); 181 } 182 } 183 } 184 185 return ExecuteJit(cx, masm); 186 } 187 END_TEST(testJitMacroAssembler_flexibleRemainder) 188 189 BEGIN_TEST(testJitMacroAssembler_flexibleQuotient) { 190 TempAllocator tempAlloc(&cx->tempLifoAlloc()); 191 JitContext jcx(cx); 192 StackMacroAssembler masm(cx, tempAlloc); 193 AutoCreatedBy acb(masm, __func__); 194 195 PrepareJit(masm); 196 197 // Test case divides 9/2; 198 const uintptr_t dividend = 9; 199 const uintptr_t divisor = 2; 200 const uintptr_t quotient_result = 4; 201 202 AllocatableGeneralRegisterSet leftHandSides(GeneralRegisterSet::All()); 203 while (!leftHandSides.empty()) { 204 Register lhs = leftHandSides.takeAny(); 205 206 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All()); 207 while (!rightHandSides.empty()) { 208 Register rhs = rightHandSides.takeAny(); 209 210 AllocatableGeneralRegisterSet outputs(GeneralRegisterSet::All()); 211 while (!outputs.empty()) { 212 Register output = outputs.takeAny(); 213 214 AllocatableRegisterSet regs(RegisterSet::Volatile()); 215 LiveRegisterSet save(regs.asLiveSet()); 216 217 Label next, fail; 218 masm.mov(ImmWord(dividend), lhs); 219 masm.mov(ImmWord(divisor), rhs); 220 masm.flexibleQuotient32(lhs, rhs, output, false, save); 221 masm.branchPtr(Assembler::NotEqual, output, 222 ImmWord(lhs != rhs ? quotient_result : 1), &fail); 223 // Ensure LHS was not clobbered 224 if (lhs != output) { 225 masm.branchPtr(Assembler::NotEqual, lhs, 226 ImmWord(lhs != rhs ? dividend : divisor), &fail); 227 } 228 // Ensure RHS was not clobbered 229 if (rhs != output) { 230 masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(divisor), &fail); 231 } 232 masm.jump(&next); 233 masm.bind(&fail); 234 masm.printf("Failed\n"); 235 236 char buffer[128]; 237 SprintfLiteral(buffer, "\tlhs = %s, rhs = %s, output = %s\n", 238 lhs.name(), rhs.name(), output.name()); 239 240 masm.printf(buffer); 241 masm.printf("\tlhs = %d\n", lhs); 242 masm.printf("\trhs = %d\n", rhs); 243 masm.printf("\toutput = %d\n", output); 244 245 masm.breakpoint(); 246 247 masm.bind(&next); 248 } 249 } 250 } 251 252 return ExecuteJit(cx, masm); 253 } 254 END_TEST(testJitMacroAssembler_flexibleQuotient) 255 256 bool shiftTest(JSContext* cx, const char* name, 257 void (*operation)(StackMacroAssembler& masm, Register, Register), 258 uintptr_t lhsInput, uintptr_t rhsInput, uintptr_t result) { 259 TempAllocator tempAlloc(&cx->tempLifoAlloc()); 260 JitContext jcx(cx); 261 StackMacroAssembler masm(cx, tempAlloc); 262 AutoCreatedBy acb(masm, __func__); 263 264 PrepareJit(masm); 265 266 const uintptr_t guardEcx = 0xfeedbad; 267 268 JS::AutoSuppressGCAnalysis suppress; 269 AllocatableGeneralRegisterSet leftOutputHandSides(GeneralRegisterSet::All()); 270 271 while (!leftOutputHandSides.empty()) { 272 Register lhsOutput = leftOutputHandSides.takeAny(); 273 274 AllocatableGeneralRegisterSet rightHandSides(GeneralRegisterSet::All()); 275 while (!rightHandSides.empty()) { 276 Register rhs = rightHandSides.takeAny(); 277 278 // You can only use shift as the same reg if the values are the same 279 if (lhsOutput == rhs && lhsInput != rhsInput) { 280 continue; 281 } 282 283 Label next, outputFail, clobberRhs, clobberEcx, dump; 284 masm.mov(ImmWord(guardEcx), ecx); 285 masm.mov(ImmWord(lhsInput), lhsOutput); 286 masm.mov(ImmWord(rhsInput), rhs); 287 288 operation(masm, rhs, lhsOutput); 289 290 // Ensure Result is correct 291 masm.branchPtr(Assembler::NotEqual, lhsOutput, ImmWord(result), 292 &outputFail); 293 294 // Ensure RHS was not clobbered, unless it's also the output register. 295 if (lhsOutput != rhs) { 296 masm.branchPtr(Assembler::NotEqual, rhs, ImmWord(rhsInput), 297 &clobberRhs); 298 } 299 300 if (lhsOutput != ecx && rhs != ecx) { 301 // If neither lhsOutput nor rhs is ecx, make sure ecx has been 302 // preserved, otherwise it's expected to be covered by the RHS clobber 303 // check above, or intentionally clobbered as the output. 304 masm.branchPtr(Assembler::NotEqual, ecx, ImmWord(guardEcx), 305 &clobberEcx); 306 } 307 308 masm.jump(&next); 309 310 masm.bind(&outputFail); 311 masm.printf("Incorrect output (got %d) ", lhsOutput); 312 masm.jump(&dump); 313 314 masm.bind(&clobberRhs); 315 masm.printf("rhs clobbered %d", rhs); 316 masm.jump(&dump); 317 318 masm.bind(&clobberEcx); 319 masm.printf("ecx clobbered"); 320 masm.jump(&dump); 321 322 masm.bind(&dump); 323 masm.mov(ImmPtr(lhsOutput.name()), lhsOutput); 324 masm.printf("(lhsOutput/srcDest) %s ", lhsOutput); 325 masm.mov(ImmPtr(name), lhsOutput); 326 masm.printf("%s ", lhsOutput); 327 masm.mov(ImmPtr(rhs.name()), lhsOutput); 328 masm.printf("(shift/rhs) %s \n", lhsOutput); 329 // Breakpoint to force test failure. 330 masm.breakpoint(); 331 masm.bind(&next); 332 } 333 } 334 335 return ExecuteJit(cx, masm); 336 } 337 338 BEGIN_TEST(testJitMacroAssembler_flexibleRshift) { 339 { 340 // Test case 16 >> 2 == 4; 341 const uintptr_t lhsInput = 16; 342 const uintptr_t rhsInput = 2; 343 const uintptr_t result = 4; 344 345 bool res = shiftTest( 346 cx, "flexibleRshift32", 347 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { 348 masm.flexibleRshift32(rhs, lhsOutput); 349 }, 350 lhsInput, rhsInput, result); 351 if (!res) { 352 return false; 353 } 354 } 355 356 { 357 // Test case 16 >> 16 == 0 -- this helps cover the case where the same 358 // register can be passed for source and dest. 359 const uintptr_t lhsInput = 16; 360 const uintptr_t rhsInput = 16; 361 const uintptr_t result = 0; 362 363 bool res = shiftTest( 364 cx, "flexibleRshift32", 365 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { 366 masm.flexibleRshift32(rhs, lhsOutput); 367 }, 368 lhsInput, rhsInput, result); 369 if (!res) { 370 return false; 371 } 372 } 373 374 return true; 375 } 376 END_TEST(testJitMacroAssembler_flexibleRshift) 377 378 BEGIN_TEST(testJitMacroAssembler_flexibleRshiftArithmetic) { 379 { 380 // Test case 4294967295 >> 2 == 4294967295; 381 const uintptr_t lhsInput = 4294967295; 382 const uintptr_t rhsInput = 2; 383 const uintptr_t result = 4294967295; 384 bool res = shiftTest( 385 cx, "flexibleRshift32Arithmetic", 386 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { 387 masm.flexibleRshift32Arithmetic(rhs, lhsOutput); 388 }, 389 lhsInput, rhsInput, result); 390 if (!res) { 391 return false; 392 } 393 } 394 395 { 396 // Test case 16 >> 16 == 0 -- this helps cover the case where the same 397 // register can be passed for source and dest. 398 const uintptr_t lhsInput = 16; 399 const uintptr_t rhsInput = 16; 400 const uintptr_t result = 0; 401 402 bool res = shiftTest( 403 cx, "flexibleRshift32Arithmetic", 404 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { 405 masm.flexibleRshift32Arithmetic(rhs, lhsOutput); 406 }, 407 lhsInput, rhsInput, result); 408 if (!res) { 409 return false; 410 } 411 } 412 413 return true; 414 } 415 END_TEST(testJitMacroAssembler_flexibleRshiftArithmetic) 416 417 BEGIN_TEST(testJitMacroAssembler_flexibleLshift) { 418 { 419 // Test case 16 << 2 == 64; 420 const uintptr_t lhsInput = 16; 421 const uintptr_t rhsInput = 2; 422 const uintptr_t result = 64; 423 424 bool res = shiftTest( 425 cx, "flexibleLshift32", 426 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { 427 masm.flexibleLshift32(rhs, lhsOutput); 428 }, 429 lhsInput, rhsInput, result); 430 if (!res) { 431 return false; 432 } 433 } 434 435 { 436 // Test case 4 << 4 == 64; duplicated input case 437 const uintptr_t lhsInput = 4; 438 const uintptr_t rhsInput = 4; 439 const uintptr_t result = 64; 440 441 bool res = shiftTest( 442 cx, "flexibleLshift32", 443 [](StackMacroAssembler& masm, Register rhs, Register lhsOutput) { 444 masm.flexibleLshift32(rhs, lhsOutput); 445 }, 446 lhsInput, rhsInput, result); 447 if (!res) { 448 return false; 449 } 450 } 451 452 return true; 453 } 454 END_TEST(testJitMacroAssembler_flexibleLshift) 455 456 BEGIN_TEST(testJitMacroAssembler_truncateDoubleToInt64) { 457 TempAllocator tempAlloc(&cx->tempLifoAlloc()); 458 JitContext jcx(cx); 459 StackMacroAssembler masm(cx, tempAlloc); 460 AutoCreatedBy acb(masm, __func__); 461 462 PrepareJit(masm); 463 464 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); 465 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); 466 FloatRegister input = allFloatRegs.takeAny(); 467 # ifdef JS_NUNBOX32 468 Register64 output(allRegs.takeAny(), allRegs.takeAny()); 469 # else 470 Register64 output(allRegs.takeAny()); 471 # endif 472 Register temp = allRegs.takeAny(); 473 474 masm.reserveStack(sizeof(int32_t)); 475 476 # define TEST(INPUT, OUTPUT) \ 477 { \ 478 Label next; \ 479 masm.loadConstantDouble(double(INPUT), input); \ 480 masm.storeDouble(input, Operand(esp, 0)); \ 481 masm.truncateDoubleToInt64(Address(esp, 0), Address(esp, 0), temp); \ 482 masm.branch64(Assembler::Equal, Address(esp, 0), Imm64(OUTPUT), &next); \ 483 masm.printf("truncateDoubleToInt64(" #INPUT ") failed\n"); \ 484 masm.breakpoint(); \ 485 masm.bind(&next); \ 486 } 487 488 TEST(0, 0); 489 TEST(-0, 0); 490 TEST(1, 1); 491 TEST(9223372036854774784.0, 9223372036854774784); 492 TEST(-9223372036854775808.0, 0x8000000000000000); 493 TEST(9223372036854775808.0, 0x8000000000000000); 494 TEST(JS::GenericNaN(), 0x8000000000000000); 495 TEST(PositiveInfinity<double>(), 0x8000000000000000); 496 TEST(NegativeInfinity<double>(), 0x8000000000000000); 497 # undef TEST 498 499 masm.freeStack(sizeof(int32_t)); 500 501 return ExecuteJit(cx, masm); 502 } 503 END_TEST(testJitMacroAssembler_truncateDoubleToInt64) 504 505 BEGIN_TEST(testJitMacroAssembler_truncateDoubleToUInt64) { 506 TempAllocator tempAlloc(&cx->tempLifoAlloc()); 507 JitContext jcx(cx); 508 StackMacroAssembler masm(cx, tempAlloc); 509 AutoCreatedBy acb(masm, __func__); 510 511 PrepareJit(masm); 512 513 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); 514 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); 515 FloatRegister input = allFloatRegs.takeAny(); 516 FloatRegister floatTemp = allFloatRegs.takeAny(); 517 # ifdef JS_NUNBOX32 518 Register64 output(allRegs.takeAny(), allRegs.takeAny()); 519 # else 520 Register64 output(allRegs.takeAny()); 521 # endif 522 Register temp = allRegs.takeAny(); 523 524 masm.reserveStack(sizeof(int32_t)); 525 526 # define TEST(INPUT, OUTPUT) \ 527 { \ 528 Label next; \ 529 masm.loadConstantDouble(double(INPUT), input); \ 530 masm.storeDouble(input, Operand(esp, 0)); \ 531 masm.truncateDoubleToUInt64(Address(esp, 0), Address(esp, 0), temp, \ 532 floatTemp); \ 533 masm.branch64(Assembler::Equal, Address(esp, 0), Imm64(OUTPUT), &next); \ 534 masm.printf("truncateDoubleToUInt64(" #INPUT ") failed\n"); \ 535 masm.breakpoint(); \ 536 masm.bind(&next); \ 537 } 538 539 TEST(0, 0); 540 TEST(1, 1); 541 TEST(9223372036854774784.0, 9223372036854774784); 542 TEST((uint64_t)0x8000000000000000, 0x8000000000000000); 543 TEST((uint64_t)0x8000000000000001, 0x8000000000000000); 544 TEST((uint64_t)0x8006004000000001, 0x8006004000000000); 545 TEST(-0.0, 0); 546 TEST(-0.5, 0); 547 TEST(-0.99, 0); 548 TEST(JS::GenericNaN(), 0x8000000000000000); 549 TEST(PositiveInfinity<double>(), 0x8000000000000000); 550 TEST(NegativeInfinity<double>(), 0x8000000000000000); 551 # undef TEST 552 553 masm.freeStack(sizeof(int32_t)); 554 555 return ExecuteJit(cx, masm); 556 } 557 END_TEST(testJitMacroAssembler_truncateDoubleToUInt64) 558 559 BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range) { 560 TempAllocator tempAlloc(&cx->tempLifoAlloc()); 561 JitContext jcx(cx); 562 StackMacroAssembler masm(cx, tempAlloc); 563 AutoCreatedBy acb(masm, __func__); 564 565 PrepareJit(masm); 566 567 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); 568 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); 569 FloatRegister input = allFloatRegs.takeAny(); 570 # ifdef JS_NUNBOX32 571 Register64 output(allRegs.takeAny(), allRegs.takeAny()); 572 # else 573 Register64 output(allRegs.takeAny()); 574 # endif 575 Register temp = allRegs.takeAny(); 576 577 masm.reserveStack(sizeof(int32_t)); 578 579 # define TEST(INPUT, OUTPUT) \ 580 { \ 581 Label next; \ 582 masm.loadConstantDouble(double(INPUT), input); \ 583 masm.storeDouble(input, Operand(esp, 0)); \ 584 if (OUTPUT) { \ 585 masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &next); \ 586 } else { \ 587 Label fail; \ 588 masm.branchDoubleNotInInt64Range(Address(esp, 0), temp, &fail); \ 589 masm.jump(&next); \ 590 masm.bind(&fail); \ 591 } \ 592 masm.printf("branchDoubleNotInInt64Range(" #INPUT ") failed\n"); \ 593 masm.breakpoint(); \ 594 masm.bind(&next); \ 595 } 596 597 TEST(0, false); 598 TEST(-0, false); 599 TEST(1, false); 600 TEST(9223372036854774784.0, false); 601 TEST(-9223372036854775808.0, true); 602 TEST(9223372036854775808.0, true); 603 TEST(JS::GenericNaN(), true); 604 TEST(PositiveInfinity<double>(), true); 605 TEST(NegativeInfinity<double>(), true); 606 # undef TEST 607 608 masm.freeStack(sizeof(int32_t)); 609 610 return ExecuteJit(cx, masm); 611 } 612 END_TEST(testJitMacroAssembler_branchDoubleNotInInt64Range) 613 614 BEGIN_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range) { 615 TempAllocator tempAlloc(&cx->tempLifoAlloc()); 616 JitContext jcx(cx); 617 StackMacroAssembler masm(cx, tempAlloc); 618 AutoCreatedBy acb(masm, __func__); 619 620 PrepareJit(masm); 621 622 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); 623 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); 624 FloatRegister input = allFloatRegs.takeAny(); 625 # ifdef JS_NUNBOX32 626 Register64 output(allRegs.takeAny(), allRegs.takeAny()); 627 # else 628 Register64 output(allRegs.takeAny()); 629 # endif 630 Register temp = allRegs.takeAny(); 631 632 masm.reserveStack(sizeof(int32_t)); 633 634 # define TEST(INPUT, OUTPUT) \ 635 { \ 636 Label next; \ 637 masm.loadConstantDouble(double(INPUT), input); \ 638 masm.storeDouble(input, Operand(esp, 0)); \ 639 if (OUTPUT) { \ 640 masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &next); \ 641 } else { \ 642 Label fail; \ 643 masm.branchDoubleNotInUInt64Range(Address(esp, 0), temp, &fail); \ 644 masm.jump(&next); \ 645 masm.bind(&fail); \ 646 } \ 647 masm.printf("branchDoubleNotInUInt64Range(" #INPUT ") failed\n"); \ 648 masm.breakpoint(); \ 649 masm.bind(&next); \ 650 } 651 652 TEST(0, false); 653 TEST(1, false); 654 TEST(9223372036854774784.0, false); 655 TEST((uint64_t)0x8000000000000000, false); 656 TEST((uint64_t)0x8000000000000001, false); 657 TEST((uint64_t)0x8006004000000001, false); 658 TEST(-0.0, true); 659 TEST(-0.5, true); 660 TEST(-0.99, true); 661 TEST(JS::GenericNaN(), true); 662 TEST(PositiveInfinity<double>(), true); 663 TEST(NegativeInfinity<double>(), true); 664 # undef TEST 665 666 masm.freeStack(sizeof(int32_t)); 667 668 return ExecuteJit(cx, masm); 669 } 670 END_TEST(testJitMacroAssembler_branchDoubleNotInUInt64Range) 671 672 BEGIN_TEST(testJitMacroAssembler_lshift64) { 673 TempAllocator tempAlloc(&cx->tempLifoAlloc()); 674 JitContext jcx(cx); 675 StackMacroAssembler masm(cx, tempAlloc); 676 AutoCreatedBy acb(masm, __func__); 677 678 PrepareJit(masm); 679 680 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); 681 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); 682 # if defined(JS_CODEGEN_X86) 683 Register shift = ecx; 684 allRegs.take(shift); 685 # elif defined(JS_CODEGEN_X64) 686 Register shift = rcx; 687 allRegs.take(shift); 688 # else 689 Register shift = allRegs.takeAny(); 690 # endif 691 692 # ifdef JS_NUNBOX32 693 Register64 input(allRegs.takeAny(), allRegs.takeAny()); 694 # else 695 Register64 input(allRegs.takeAny()); 696 # endif 697 698 masm.reserveStack(sizeof(int32_t)); 699 700 # define TEST(SHIFT, INPUT, OUTPUT) \ 701 { \ 702 Label next; \ 703 masm.move64(Imm64(INPUT), input); \ 704 masm.move32(Imm32(SHIFT), shift); \ 705 masm.lshift64(shift, input); \ 706 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \ 707 masm.printf("lshift64(" #SHIFT ", " #INPUT ") failed\n"); \ 708 masm.breakpoint(); \ 709 masm.bind(&next); \ 710 } \ 711 { \ 712 Label next; \ 713 masm.move64(Imm64(INPUT), input); \ 714 masm.lshift64(Imm32(SHIFT & 0x3f), input); \ 715 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \ 716 masm.printf("lshift64(Imm32(" #SHIFT "&0x3f), " #INPUT ") failed\n"); \ 717 masm.breakpoint(); \ 718 masm.bind(&next); \ 719 } 720 721 TEST(0, 1, 1); 722 TEST(1, 1, 2); 723 TEST(2, 1, 4); 724 TEST(32, 1, 0x0000000100000000); 725 TEST(33, 1, 0x0000000200000000); 726 TEST(0, -1, 0xffffffffffffffff); 727 TEST(1, -1, 0xfffffffffffffffe); 728 TEST(2, -1, 0xfffffffffffffffc); 729 TEST(32, -1, 0xffffffff00000000); 730 TEST(0xffffffff, 1, 0x8000000000000000); 731 TEST(0xfffffffe, 1, 0x4000000000000000); 732 TEST(0xfffffffd, 1, 0x2000000000000000); 733 TEST(0x80000001, 1, 2); 734 # undef TEST 735 736 masm.freeStack(sizeof(int32_t)); 737 738 return ExecuteJit(cx, masm); 739 } 740 END_TEST(testJitMacroAssembler_lshift64) 741 742 BEGIN_TEST(testJitMacroAssembler_rshift64Arithmetic) { 743 TempAllocator tempAlloc(&cx->tempLifoAlloc()); 744 JitContext jcx(cx); 745 StackMacroAssembler masm(cx, tempAlloc); 746 AutoCreatedBy acb(masm, __func__); 747 748 PrepareJit(masm); 749 750 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); 751 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); 752 # if defined(JS_CODEGEN_X86) 753 Register shift = ecx; 754 allRegs.take(shift); 755 # elif defined(JS_CODEGEN_X64) 756 Register shift = rcx; 757 allRegs.take(shift); 758 # else 759 Register shift = allRegs.takeAny(); 760 # endif 761 762 # ifdef JS_NUNBOX32 763 Register64 input(allRegs.takeAny(), allRegs.takeAny()); 764 # else 765 Register64 input(allRegs.takeAny()); 766 # endif 767 768 masm.reserveStack(sizeof(int32_t)); 769 770 # define TEST(SHIFT, INPUT, OUTPUT) \ 771 { \ 772 Label next; \ 773 masm.move64(Imm64(INPUT), input); \ 774 masm.move32(Imm32(SHIFT), shift); \ 775 masm.rshift64Arithmetic(shift, input); \ 776 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \ 777 masm.printf("rshift64Arithmetic(" #SHIFT ", " #INPUT ") failed\n"); \ 778 masm.breakpoint(); \ 779 masm.bind(&next); \ 780 } \ 781 { \ 782 Label next; \ 783 masm.move64(Imm64(INPUT), input); \ 784 masm.rshift64Arithmetic(Imm32(SHIFT & 0x3f), input); \ 785 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \ 786 masm.printf("rshift64Arithmetic(Imm32(" #SHIFT "&0x3f), " #INPUT \ 787 ") failed\n"); \ 788 masm.breakpoint(); \ 789 masm.bind(&next); \ 790 } 791 792 TEST(0, 0x4000000000000000, 0x4000000000000000); 793 TEST(1, 0x4000000000000000, 0x2000000000000000); 794 TEST(2, 0x4000000000000000, 0x1000000000000000); 795 TEST(32, 0x4000000000000000, 0x0000000040000000); 796 TEST(0, 0x8000000000000000, 0x8000000000000000); 797 TEST(1, 0x8000000000000000, 0xc000000000000000); 798 TEST(2, 0x8000000000000000, 0xe000000000000000); 799 TEST(32, 0x8000000000000000, 0xffffffff80000000); 800 TEST(0xffffffff, 0x8000000000000000, 0xffffffffffffffff); 801 TEST(0xfffffffe, 0x8000000000000000, 0xfffffffffffffffe); 802 TEST(0xfffffffd, 0x8000000000000000, 0xfffffffffffffffc); 803 TEST(0x80000001, 0x8000000000000000, 0xc000000000000000); 804 # undef TEST 805 806 masm.freeStack(sizeof(int32_t)); 807 808 return ExecuteJit(cx, masm); 809 } 810 END_TEST(testJitMacroAssembler_rshift64Arithmetic) 811 812 BEGIN_TEST(testJitMacroAssembler_rshift64) { 813 TempAllocator tempAlloc(&cx->tempLifoAlloc()); 814 JitContext jcx(cx); 815 StackMacroAssembler masm(cx, tempAlloc); 816 AutoCreatedBy acb(masm, __func__); 817 818 PrepareJit(masm); 819 820 AllocatableGeneralRegisterSet allRegs(GeneralRegisterSet::All()); 821 AllocatableFloatRegisterSet allFloatRegs(FloatRegisterSet::All()); 822 # if defined(JS_CODEGEN_X86) 823 Register shift = ecx; 824 allRegs.take(shift); 825 # elif defined(JS_CODEGEN_X64) 826 Register shift = rcx; 827 allRegs.take(shift); 828 # else 829 Register shift = allRegs.takeAny(); 830 # endif 831 832 # ifdef JS_NUNBOX32 833 Register64 input(allRegs.takeAny(), allRegs.takeAny()); 834 # else 835 Register64 input(allRegs.takeAny()); 836 # endif 837 838 masm.reserveStack(sizeof(int32_t)); 839 840 # define TEST(SHIFT, INPUT, OUTPUT) \ 841 { \ 842 Label next; \ 843 masm.move64(Imm64(INPUT), input); \ 844 masm.move32(Imm32(SHIFT), shift); \ 845 masm.rshift64(shift, input); \ 846 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \ 847 masm.printf("rshift64(" #SHIFT ", " #INPUT ") failed\n"); \ 848 masm.breakpoint(); \ 849 masm.bind(&next); \ 850 } \ 851 { \ 852 Label next; \ 853 masm.move64(Imm64(INPUT), input); \ 854 masm.rshift64(Imm32(SHIFT & 0x3f), input); \ 855 masm.branch64(Assembler::Equal, input, Imm64(OUTPUT), &next); \ 856 masm.printf("rshift64(Imm32(" #SHIFT "&0x3f), " #INPUT ") failed\n"); \ 857 masm.breakpoint(); \ 858 masm.bind(&next); \ 859 } 860 861 TEST(0, 0x4000000000000000, 0x4000000000000000); 862 TEST(1, 0x4000000000000000, 0x2000000000000000); 863 TEST(2, 0x4000000000000000, 0x1000000000000000); 864 TEST(32, 0x4000000000000000, 0x0000000040000000); 865 TEST(0, 0x8000000000000000, 0x8000000000000000); 866 TEST(1, 0x8000000000000000, 0x4000000000000000); 867 TEST(2, 0x8000000000000000, 0x2000000000000000); 868 TEST(32, 0x8000000000000000, 0x0000000080000000); 869 TEST(0xffffffff, 0x8000000000000000, 0x0000000000000001); 870 TEST(0xfffffffe, 0x8000000000000000, 0x0000000000000002); 871 TEST(0xfffffffd, 0x8000000000000000, 0x0000000000000004); 872 TEST(0x80000001, 0x8000000000000000, 0x4000000000000000); 873 # undef TEST 874 875 masm.freeStack(sizeof(int32_t)); 876 877 return ExecuteJit(cx, masm); 878 } 879 END_TEST(testJitMacroAssembler_rshift64) 880 881 #endif