| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 511 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 522 __ Mov(constants, Operand(ExternalReference::math_exp_constants(0))); | 522 __ Mov(constants, Operand(ExternalReference::math_exp_constants(0))); |
| 523 | 523 |
| 524 // We have to do a four-way split here: | 524 // We have to do a four-way split here: |
| 525 // - If input <= about -708.4, the output always rounds to zero. | 525 // - If input <= about -708.4, the output always rounds to zero. |
| 526 // - If input >= about 709.8, the output always rounds to +infinity. | 526 // - If input >= about 709.8, the output always rounds to +infinity. |
| 527 // - If the input is NaN, the output is NaN. | 527 // - If the input is NaN, the output is NaN. |
| 528 // - Otherwise, the result needs to be calculated. | 528 // - Otherwise, the result needs to be calculated. |
| 529 Label result_is_finite_non_zero; | 529 Label result_is_finite_non_zero; |
| 530 // Assert that we can load offset 0 (the small input threshold) and offset 1 | 530 // Assert that we can load offset 0 (the small input threshold) and offset 1 |
| 531 // (the large input threshold) with a single ldp. | 531 // (the large input threshold) with a single ldp. |
| 532 ASSERT(kDRegSizeInBytes == (ExpConstant(constants, 1).offset() - | 532 ASSERT(kDRegSize == (ExpConstant(constants, 1).offset() - |
| 533 ExpConstant(constants, 0).offset())); | 533 ExpConstant(constants, 0).offset())); |
| 534 __ Ldp(double_temp1, double_temp2, ExpConstant(constants, 0)); | 534 __ Ldp(double_temp1, double_temp2, ExpConstant(constants, 0)); |
| 535 | 535 |
| 536 __ Fcmp(input, double_temp1); | 536 __ Fcmp(input, double_temp1); |
| 537 __ Fccmp(input, double_temp2, NoFlag, hi); | 537 __ Fccmp(input, double_temp2, NoFlag, hi); |
| 538 // At this point, the condition flags can be in one of five states: | 538 // At this point, the condition flags can be in one of five states: |
| 539 // NZCV | 539 // NZCV |
| 540 // 1000 -708.4 < input < 709.8 result = exp(input) | 540 // 1000 -708.4 < input < 709.8 result = exp(input) |
| 541 // 0110 input == 709.8 result = +infinity | 541 // 0110 input == 709.8 result = +infinity |
| 542 // 0010 input > 709.8 result = +infinity | 542 // 0010 input > 709.8 result = +infinity |
| 543 // 0011 input is NaN result = input | 543 // 0011 input is NaN result = input |
| 544 // 0000 input <= -708.4 result = +0.0 | 544 // 0000 input <= -708.4 result = +0.0 |
| 545 | 545 |
| 546 // Continue the common case first. 'mi' tests N == 1. | 546 // Continue the common case first. 'mi' tests N == 1. |
| 547 __ B(&result_is_finite_non_zero, mi); | 547 __ B(&result_is_finite_non_zero, mi); |
| 548 | 548 |
| 549 // TODO(jbramley): Add (and use) a zero D register for A64. | |
| 550 // TODO(jbramley): Consider adding a +infinity register for A64. | 549 // TODO(jbramley): Consider adding a +infinity register for A64. |
| 551 __ Ldr(double_temp2, ExpConstant(constants, 2)); // Synthesize +infinity. | 550 __ Ldr(double_temp2, ExpConstant(constants, 2)); // Synthesize +infinity. |
| 552 __ Fsub(double_temp1, double_temp1, double_temp1); // Synthesize +0.0. | |
| 553 | 551 |
| 554 // Select between +0.0 and +infinity. 'lo' tests C == 0. | 552 // Select between +0.0 and +infinity. 'lo' tests C == 0. |
| 555 __ Fcsel(result, double_temp1, double_temp2, lo); | 553 __ Fcsel(result, fp_zero, double_temp2, lo); |
| 556 // Select between {+0.0 or +infinity} and input. 'vc' tests V == 0. | 554 // Select between {+0.0 or +infinity} and input. 'vc' tests V == 0. |
| 557 __ Fcsel(result, result, input, vc); | 555 __ Fcsel(result, result, input, vc); |
| 558 __ B(&done); | 556 __ B(&done); |
| 559 | 557 |
| 560 // The rest is magic, as described in InitializeMathExpData(). | 558 // The rest is magic, as described in InitializeMathExpData(). |
| 561 __ Bind(&result_is_finite_non_zero); | 559 __ Bind(&result_is_finite_non_zero); |
| 562 | 560 |
| 563 // Assert that we can load offset 3 and offset 4 with a single ldp. | 561 // Assert that we can load offset 3 and offset 4 with a single ldp. |
| 564 ASSERT(kDRegSizeInBytes == (ExpConstant(constants, 4).offset() - | 562 ASSERT(kDRegSize == (ExpConstant(constants, 4).offset() - |
| 565 ExpConstant(constants, 3).offset())); | 563 ExpConstant(constants, 3).offset())); |
| 566 __ Ldp(double_temp1, double_temp3, ExpConstant(constants, 3)); | 564 __ Ldp(double_temp1, double_temp3, ExpConstant(constants, 3)); |
| 567 __ Fmadd(double_temp1, double_temp1, input, double_temp3); | 565 __ Fmadd(double_temp1, double_temp1, input, double_temp3); |
| 568 __ Fmov(temp2.W(), double_temp1.S()); | 566 __ Fmov(temp2.W(), double_temp1.S()); |
| 569 __ Fsub(double_temp1, double_temp1, double_temp3); | 567 __ Fsub(double_temp1, double_temp1, double_temp3); |
| 570 | 568 |
| 571 // Assert that we can load offset 5 and offset 6 with a single ldp. | 569 // Assert that we can load offset 5 and offset 6 with a single ldp. |
| 572 ASSERT(kDRegSizeInBytes == (ExpConstant(constants, 6).offset() - | 570 ASSERT(kDRegSize == (ExpConstant(constants, 6).offset() - |
| 573 ExpConstant(constants, 5).offset())); | 571 ExpConstant(constants, 5).offset())); |
| 574 __ Ldp(double_temp2, double_temp3, ExpConstant(constants, 5)); | 572 __ Ldp(double_temp2, double_temp3, ExpConstant(constants, 5)); |
| 575 // TODO(jbramley): Consider using Fnmsub here. | 573 // TODO(jbramley): Consider using Fnmsub here. |
| 576 __ Fmul(double_temp1, double_temp1, double_temp2); | 574 __ Fmul(double_temp1, double_temp1, double_temp2); |
| 577 __ Fsub(double_temp1, double_temp1, input); | 575 __ Fsub(double_temp1, double_temp1, input); |
| 578 | 576 |
| 579 __ Fmul(double_temp2, double_temp1, double_temp1); | 577 __ Fmul(double_temp2, double_temp1, double_temp1); |
| 580 __ Fsub(double_temp3, double_temp3, double_temp1); | 578 __ Fsub(double_temp3, double_temp3, double_temp1); |
| 581 __ Fmul(double_temp3, double_temp3, double_temp2); | 579 __ Fmul(double_temp3, double_temp3, double_temp2); |
| 582 | 580 |
| 583 __ Mov(temp1.W(), Operand(temp2.W(), LSR, 11)); | 581 __ Mov(temp1.W(), Operand(temp2.W(), LSR, 11)); |
| 584 | 582 |
| 585 __ Ldr(double_temp2, ExpConstant(constants, 7)); | 583 __ Ldr(double_temp2, ExpConstant(constants, 7)); |
| 586 // TODO(jbramley): Consider using Fnmsub here. | 584 // TODO(jbramley): Consider using Fnmsub here. |
| 587 __ Fmul(double_temp3, double_temp3, double_temp2); | 585 __ Fmul(double_temp3, double_temp3, double_temp2); |
| 588 __ Fsub(double_temp3, double_temp3, double_temp1); | 586 __ Fsub(double_temp3, double_temp3, double_temp1); |
| 589 | 587 |
| 590 // The 8th constant is 1.0, so use an immediate move rather than a load. | 588 // The 8th constant is 1.0, so use an immediate move rather than a load. |
| 591 // We can't generate a runtime assertion here as we would need to call Abort | 589 // We can't generate a runtime assertion here as we would need to call Abort |
| 592 // in the runtime and we don't have an Isolate when we generate this code. | 590 // in the runtime and we don't have an Isolate when we generate this code. |
| 593 __ Fmov(double_temp2, 1.0); | 591 __ Fmov(double_temp2, 1.0); |
| 594 __ Fadd(double_temp3, double_temp3, double_temp2); | 592 __ Fadd(double_temp3, double_temp3, double_temp2); |
| 595 | 593 |
| 596 __ And(temp2, temp2, 0x7ff); | 594 __ And(temp2, temp2, 0x7ff); |
| 597 __ Add(temp1, temp1, 0x3ff); | 595 __ Add(temp1, temp1, 0x3ff); |
| 598 | 596 |
| 599 // Do the final table lookup. | 597 // Do the final table lookup. |
| 600 __ Mov(temp3, Operand(ExternalReference::math_exp_log_table())); | 598 __ Mov(temp3, Operand(ExternalReference::math_exp_log_table())); |
| 601 | 599 |
| 602 __ Add(temp3, temp3, Operand(temp2, LSL, kDRegSizeInBytesLog2)); | 600 __ Add(temp3, temp3, Operand(temp2, LSL, kDRegSizeLog2)); |
| 603 __ Ldp(temp2.W(), temp3.W(), MemOperand(temp3)); | 601 __ Ldp(temp2.W(), temp3.W(), MemOperand(temp3)); |
| 604 __ Orr(temp1.W(), temp3.W(), Operand(temp1.W(), LSL, 20)); | 602 __ Orr(temp1.W(), temp3.W(), Operand(temp1.W(), LSL, 20)); |
| 605 __ Bfi(temp2, temp1, 32, 32); | 603 __ Bfi(temp2, temp1, 32, 32); |
| 606 __ Fmov(double_temp1, temp2); | 604 __ Fmov(double_temp1, temp2); |
| 607 | 605 |
| 608 __ Fmul(result, double_temp3, double_temp1); | 606 __ Fmul(result, double_temp3, double_temp1); |
| 609 | 607 |
| 610 __ Bind(&done); | 608 __ Bind(&done); |
| 611 } | 609 } |
| 612 | 610 |
| 613 #undef __ | 611 #undef __ |
| 614 | 612 |
| 615 } } // namespace v8::internal | 613 } } // namespace v8::internal |
| 616 | 614 |
| 617 #endif // V8_TARGET_ARCH_A64 | 615 #endif // V8_TARGET_ARCH_A64 |
| OLD | NEW |