Bug 870356 - Fix IonMonkey Math.round bug on x86/x64 hardware without SSE 4.1. r=sstangl

This commit is contained in:
Jan de Mooij 2013-07-16 17:55:29 +02:00
parent ed960be5bf
commit 4dec24de90
3 changed files with 47 additions and 8 deletions

View File

@ -326,6 +326,13 @@ CodeGeneratorX86Shared::bailoutIf(Assembler::Condition condition, LSnapshot *sna
return bailout(BailoutJump(condition), snapshot); return bailout(BailoutJump(condition), snapshot);
} }
bool
CodeGeneratorX86Shared::bailoutIf(Assembler::DoubleCondition condition, LSnapshot *snapshot)
{
JS_ASSERT(Assembler::NaNCondFromDoubleCondition(condition) == Assembler::NaN_HandledByCond);
return bailoutIf(Assembler::ConditionFromDoubleCondition(condition), snapshot);
}
bool bool
CodeGeneratorX86Shared::bailoutFrom(Label *label, LSnapshot *snapshot) CodeGeneratorX86Shared::bailoutFrom(Label *label, LSnapshot *snapshot)
{ {
@ -1289,8 +1296,12 @@ CodeGeneratorX86Shared::visitRound(LRound *lir)
masm.addsd(input, temp); masm.addsd(input, temp);
// Round toward -Infinity without the benefit of ROUNDSD. // Round toward -Infinity without the benefit of ROUNDSD.
Label testZero;
{ {
// If input + 0.5 >= 0, input is a negative number >= -0.5 and the result is -0.
masm.compareDouble(Assembler::DoubleGreaterThanOrEqual, temp, scratch);
if (!bailoutIf(Assembler::DoubleGreaterThanOrEqual, lir->snapshot()))
return false;
// Truncate and round toward zero. // Truncate and round toward zero.
// This is off-by-one for everything but integer-valued inputs. // This is off-by-one for everything but integer-valued inputs.
masm.cvttsd2si(temp, output); masm.cvttsd2si(temp, output);
@ -1300,19 +1311,13 @@ CodeGeneratorX86Shared::visitRound(LRound *lir)
// Test whether the truncated double was integer-valued. // Test whether the truncated double was integer-valued.
masm.cvtsi2sd(output, scratch); masm.cvtsi2sd(output, scratch);
masm.branchDouble(Assembler::DoubleEqualOrUnordered, temp, scratch, &testZero); masm.branchDouble(Assembler::DoubleEqualOrUnordered, temp, scratch, &end);
// Input is not integer-valued, so we rounded off-by-one in the // Input is not integer-valued, so we rounded off-by-one in the
// wrong direction. Correct by subtraction. // wrong direction. Correct by subtraction.
masm.subl(Imm32(1), output); masm.subl(Imm32(1), output);
// Cannot overflow: output was already checked against INT_MIN. // Cannot overflow: output was already checked against INT_MIN.
// Fall through to testZero.
} }
masm.bind(&testZero);
if (!bailoutIf(Assembler::Zero, lir->snapshot()))
return false;
} }
masm.bind(&end); masm.bind(&end);

View File

@ -50,6 +50,7 @@ class CodeGeneratorX86Shared : public CodeGeneratorShared
MoveResolver::MoveOperand toMoveOperand(const LAllocation *a) const; MoveResolver::MoveOperand toMoveOperand(const LAllocation *a) const;
bool bailoutIf(Assembler::Condition condition, LSnapshot *snapshot); bool bailoutIf(Assembler::Condition condition, LSnapshot *snapshot);
bool bailoutIf(Assembler::DoubleCondition condition, LSnapshot *snapshot);
bool bailoutFrom(Label *label, LSnapshot *snapshot); bool bailoutFrom(Label *label, LSnapshot *snapshot);
bool bailout(LSnapshot *snapshot); bool bailout(LSnapshot *snapshot);

View File

@ -0,0 +1,33 @@
function f1(x) {
return Math.round(x);
}
assertEq(f1(3.3), 3);
assertEq(f1(-2.842170943040401e-14), -0);
function f2(x) {
return Math.round(x);
}
assertEq(f2(3.3), 3);
assertEq(f2(-1.3), -1);
assertEq(f2(-1.8), -2);
assertEq(f2(-0.9), -1);
assertEq(f2(-0.6), -1);
assertEq(f2(-0.4), -0);
function f3(x) {
return Math.round(x);
}
assertEq(f3(0.1), 0);
assertEq(f3(-0.5), -0);
function f4(x) {
return Math.round(x);
}
assertEq(f4(0.1), 0);
assertEq(f4(-0), -0);
function f5(x) {
return Math.round(x);
}
assertEq(f5(2.9), 3);
assertEq(f5(NaN), NaN);