| Index: src/x64/lithium-codegen-x64.cc
|
| diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
|
| index 413bff03d7f9f485173e59db7ca9c684fe32c1dd..564e413a579408099acf4fd5f916c40d30f863ad 100644
|
| --- a/src/x64/lithium-codegen-x64.cc
|
| +++ b/src/x64/lithium-codegen-x64.cc
|
| @@ -3486,7 +3486,7 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
|
| DeoptimizeIf(equal, instr->environment());
|
| } else {
|
| Label negative_sign, done;
|
| - // Deoptimize on negative inputs.
|
| + // Deoptimize on unordered.
|
| __ xorps(xmm_scratch, xmm_scratch); // Zero the register.
|
| __ ucomisd(input_reg, xmm_scratch);
|
| DeoptimizeIf(parity_even, instr->environment());
|
| @@ -3530,48 +3530,72 @@ void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
|
| const XMMRegister xmm_scratch = xmm0;
|
| Register output_reg = ToRegister(instr->result());
|
| XMMRegister input_reg = ToDoubleRegister(instr->value());
|
| + static int64_t one_half = V8_INT64_C(0x3FE0000000000000); // 0.5
|
| + static int64_t minus_one_half = V8_INT64_C(0xBFE0000000000000); // -0.5
|
|
|
| - Label done;
|
| - // xmm_scratch = 0.5
|
| - __ movq(kScratchRegister, V8_INT64_C(0x3FE0000000000000), RelocInfo::NONE64);
|
| + bool minus_zero_check =
|
| + instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero);
|
| +
|
| + __ movq(kScratchRegister, one_half, RelocInfo::NONE64);
|
| __ movq(xmm_scratch, kScratchRegister);
|
| - Label below_half;
|
| - __ ucomisd(xmm_scratch, input_reg);
|
| - // If input_reg is NaN, this doesn't jump.
|
| - __ j(above, &below_half, Label::kNear);
|
| - // input = input + 0.5
|
| - // This addition might give a result that isn't the correct for
|
| - // rounding, due to loss of precision, but only for a number that's
|
| - // so big that the conversion below will overflow anyway.
|
| - __ addsd(xmm_scratch, input_reg);
|
| - // Compute Math.floor(input).
|
| - // Use truncating instruction (OK because input is positive).
|
| - __ cvttsd2si(output_reg, xmm_scratch);
|
| - // Overflow is signalled with minint.
|
| - __ cmpl(output_reg, Immediate(0x80000000));
|
| - DeoptimizeIf(equal, instr->environment());
|
| - __ jmp(&done);
|
|
|
| - __ bind(&below_half);
|
| - if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
|
| - // Bailout if negative (including -0).
|
| - __ movq(output_reg, input_reg);
|
| - __ testq(output_reg, output_reg);
|
| - DeoptimizeIf(negative, instr->environment());
|
| + if (CpuFeatures::IsSupported(SSE4_1) && !minus_zero_check) {
|
| + CpuFeatures::Scope scope(SSE4_1);
|
| + __ addsd(xmm_scratch, input_reg);
|
| + __ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
|
| + __ cvttsd2si(output_reg, xmm_scratch);
|
| + // Overflow is signalled with minint.
|
| + __ cmpl(output_reg, Immediate(0x80000000));
|
| + __ RecordComment("D2I conversion overflow");
|
| + DeoptimizeIf(equal, instr->environment());
|
| } else {
|
| - // Bailout if below -0.5, otherwise round to (positive) zero, even
|
| - // if negative.
|
| - // xmm_scrach = -0.5
|
| - __ movq(kScratchRegister,
|
| - V8_INT64_C(0xBFE0000000000000),
|
| - RelocInfo::NONE64);
|
| + Label done, round_to_zero, below_one_half, do_not_compensate;
|
| + __ ucomisd(xmm_scratch, input_reg);
|
| + __ j(above, &below_one_half);
|
| +
|
| + // CVTTSD2SI rounds towards zero, since 0.5 <= x, we use floor(0.5 + x).
|
| + __ addsd(xmm_scratch, input_reg);
|
| + __ cvttsd2si(output_reg, xmm_scratch);
|
| + // Overflow is signalled with minint.
|
| + __ cmpl(output_reg, Immediate(0x80000000));
|
| + __ RecordComment("D2I conversion overflow");
|
| + DeoptimizeIf(equal, instr->environment());
|
| + __ jmp(&done);
|
| +
|
| + __ bind(&below_one_half);
|
| + __ movq(kScratchRegister, minus_one_half, RelocInfo::NONE64);
|
| __ movq(xmm_scratch, kScratchRegister);
|
| + __ ucomisd(xmm_scratch, input_reg);
|
| + __ j(below_equal, &round_to_zero);
|
| +
|
| + // CVTTSD2SI rounds towards zero, we use ceil(x - (-0.5)) and then
|
| + // compare and compensate.
|
| + __ subsd(input_reg, xmm_scratch);
|
| + __ cvttsd2si(output_reg, input_reg);
|
| + // Catch minint due to overflow, and to prevent overflow when compensating.
|
| + __ cmpl(output_reg, Immediate(0x80000000));
|
| + __ RecordComment("D2I conversion overflow");
|
| + DeoptimizeIf(equal, instr->environment());
|
| +
|
| + __ cvtlsi2sd(xmm_scratch, output_reg);
|
| __ ucomisd(input_reg, xmm_scratch);
|
| - DeoptimizeIf(below, instr->environment());
|
| - }
|
| - __ xorl(output_reg, output_reg);
|
| + __ j(equal, &done, Label::kNear);
|
| + __ subl(output_reg, Immediate(1));
|
| + // No overflow because we already ruled out minint.
|
| + __ jmp(&done);
|
|
|
| - __ bind(&done);
|
| + __ bind(&round_to_zero);
|
| + // We return 0 for the input range [+0, 0.5[, or [-0.5, 0.5[ if
|
| + // we can ignore the difference between a result of -0 and +0.
|
| + if (minus_zero_check) {
|
| + __ movq(output_reg, input_reg);
|
| + __ testq(output_reg, output_reg);
|
| + __ RecordComment("Minus zero");
|
| + DeoptimizeIf(negative, instr->environment());
|
| + }
|
| + __ Set(output_reg, 0);
|
| + __ bind(&done);
|
| + }
|
| }
|
|
|
|
|
|
|