Commit 3bbcab1c authored by lrn@chromium.org's avatar lrn@chromium.org

X64: Use roundsd for DoMathFloor.

TEST=mjsunit/math-floor

Review URL: http://codereview.chromium.org/6835021

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@7613 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 68a8cf36
...@@ -2863,6 +2863,21 @@ void Assembler::ucomisd(XMMRegister dst, const Operand& src) { ...@@ -2863,6 +2863,21 @@ void Assembler::ucomisd(XMMRegister dst, const Operand& src) {
} }
void Assembler::roundsd(XMMRegister dst, XMMRegister src,
Assembler::RoundingMode mode) {
ASSERT(CpuFeatures::IsEnabled(SSE4_1));
EnsureSpace ensure_space(this);
emit(0x66);
emit_optional_rex_32(dst, src);
emit(0x0f);
emit(0x3a);
emit(0x0b);
emit_sse_operand(dst, src);
// Mask precision exeption.
emit(static_cast<byte>(mode) | 0x8);
}
void Assembler::movmskpd(Register dst, XMMRegister src) { void Assembler::movmskpd(Register dst, XMMRegister src) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
emit(0x66); emit(0x66);
......
...@@ -1336,6 +1336,15 @@ class Assembler : public AssemblerBase { ...@@ -1336,6 +1336,15 @@ class Assembler : public AssemblerBase {
void ucomisd(XMMRegister dst, XMMRegister src); void ucomisd(XMMRegister dst, XMMRegister src);
void ucomisd(XMMRegister dst, const Operand& src); void ucomisd(XMMRegister dst, const Operand& src);
enum RoundingMode {
kRoundToNearest = 0x0,
kRoundDown = 0x1,
kRoundUp = 0x2,
kRoundToZero = 0x3
};
void roundsd(XMMRegister dst, XMMRegister src, RoundingMode mode);
void movmskpd(Register dst, XMMRegister src); void movmskpd(Register dst, XMMRegister src);
// The first argument is the reg field, the second argument is the r/m field. // The first argument is the reg field, the second argument is the r/m field.
......
...@@ -1021,6 +1021,13 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { ...@@ -1021,6 +1021,13 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
current += PrintRightOperand(current); current += PrintRightOperand(current);
AppendToBuffer(", %s, %d", NameOfCPURegister(regop), (*current) & 3); AppendToBuffer(", %s, %d", NameOfCPURegister(regop), (*current) & 3);
current += 1; current += 1;
} else if (third_byte == 0x0b) {
get_modrm(*current, &mod, &regop, &rm);
// roundsd xmm, xmm/m64, imm8
AppendToBuffer("roundsd %s, ", NameOfCPURegister(regop));
current += PrintRightOperand(current);
AppendToBuffer(", %d", (*current) & 3);
current += 1;
} else { } else {
UnimplementedInstruction(); UnimplementedInstruction();
} }
......
...@@ -2698,21 +2698,36 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { ...@@ -2698,21 +2698,36 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
XMMRegister xmm_scratch = xmm0; XMMRegister xmm_scratch = xmm0;
Register output_reg = ToRegister(instr->result()); Register output_reg = ToRegister(instr->result());
XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0)); XMMRegister input_reg = ToDoubleRegister(instr->InputAt(0));
__ xorpd(xmm_scratch, xmm_scratch); // Zero the register.
__ ucomisd(input_reg, xmm_scratch);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { if (CpuFeatures::IsSupported(SSE4_1)) {
DeoptimizeIf(below_equal, instr->environment()); CpuFeatures::Scope scope(SSE4_1);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Deoptimize if minus zero.
__ movq(output_reg, input_reg);
__ subq(output_reg, Immediate(1));
DeoptimizeIf(overflow, instr->environment());
}
__ roundsd(xmm_scratch, input_reg, Assembler::kRoundDown);
__ cvttsd2si(output_reg, xmm_scratch);
__ cmpl(output_reg, Immediate(0x80000000));
DeoptimizeIf(equal, instr->environment());
} else { } else {
DeoptimizeIf(below, instr->environment()); __ xorpd(xmm_scratch, xmm_scratch); // Zero the register.
} __ ucomisd(input_reg, xmm_scratch);
// Use truncating instruction (OK because input is positive). if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ cvttsd2si(output_reg, input_reg); DeoptimizeIf(below_equal, instr->environment());
} else {
DeoptimizeIf(below, instr->environment());
}
// Overflow is signalled with minint. // Use truncating instruction (OK because input is positive).
__ cmpl(output_reg, Immediate(0x80000000)); __ cvttsd2si(output_reg, input_reg);
DeoptimizeIf(equal, instr->environment());
// Overflow is signalled with minint.
__ cmpl(output_reg, Immediate(0x80000000));
DeoptimizeIf(equal, instr->environment());
}
} }
......
// Copyright 2010 the V8 project authors. All rights reserved. // Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are // modification, are permitted provided that the following conditions are
// met: // met:
...@@ -25,7 +25,18 @@ ...@@ -25,7 +25,18 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --max-new-space-size=256 // Flags: --max-new-space-size=256 --allow-natives-syntax
function testFloor(expect, input) {
function test(n) {
return Math.floor(n);
}
assertEquals(expect, test(input));
assertEquals(expect, test(input));
assertEquals(expect, test(input));
%OptimizeFunctionOnNextCall(test);
assertEquals(expect, test(input));
}
function zero() { function zero() {
var x = 0.5; var x = 0.5;
...@@ -33,82 +44,84 @@ function zero() { ...@@ -33,82 +44,84 @@ function zero() {
} }
function test() { function test() {
assertEquals(0, Math.floor(0)); testFloor(0, 0);
assertEquals(0, Math.floor(zero())); testFloor(0, zero());
assertEquals(1/-0, 1/Math.floor(-0)); // 0 == -0, so we use reciprocals. testFloor(-0, -0);
assertEquals(Infinity, Math.floor(Infinity)); testFloor(Infinity, Infinity);
assertEquals(-Infinity, Math.floor(-Infinity)); testFloor(-Infinity, -Infinity);
assertNaN(Math.floor(NaN)); testFloor(NaN, NaN);
assertEquals(0, Math.floor(0.1)); testFloor(0, 0.1);
assertEquals(0, Math.floor(0.5)); testFloor(0, 0.49999999999999994);
assertEquals(0, Math.floor(0.7)); testFloor(0, 0.5);
assertEquals(-1, Math.floor(-0.1)); testFloor(0, 0.7);
assertEquals(-1, Math.floor(-0.5)); testFloor(-1, -0.1);
assertEquals(-1, Math.floor(-0.7)); testFloor(-1, -0.49999999999999994);
assertEquals(1, Math.floor(1)); testFloor(-1, -0.5);
assertEquals(1, Math.floor(1.1)); testFloor(-1, -0.7);
assertEquals(1, Math.floor(1.5)); testFloor(1, 1);
assertEquals(1, Math.floor(1.7)); testFloor(1, 1.1);
assertEquals(-1, Math.floor(-1)); testFloor(1, 1.5);
assertEquals(-2, Math.floor(-1.1)); testFloor(1, 1.7);
assertEquals(-2, Math.floor(-1.5)); testFloor(-1, -1);
assertEquals(-2, Math.floor(-1.7)); testFloor(-2, -1.1);
testFloor(-2, -1.5);
assertEquals(0, Math.floor(Number.MIN_VALUE)); testFloor(-2, -1.7);
assertEquals(-1, Math.floor(-Number.MIN_VALUE));
assertEquals(Number.MAX_VALUE, Math.floor(Number.MAX_VALUE)); testFloor(0, Number.MIN_VALUE);
assertEquals(-Number.MAX_VALUE, Math.floor(-Number.MAX_VALUE)); testFloor(-1, -Number.MIN_VALUE);
assertEquals(Infinity, Math.floor(Infinity)); testFloor(Number.MAX_VALUE, Number.MAX_VALUE);
assertEquals(-Infinity, Math.floor(-Infinity)); testFloor(-Number.MAX_VALUE, -Number.MAX_VALUE);
testFloor(Infinity, Infinity);
testFloor(-Infinity, -Infinity);
// 2^30 is a smi boundary. // 2^30 is a smi boundary.
var two_30 = 1 << 30; var two_30 = 1 << 30;
assertEquals(two_30, Math.floor(two_30)); testFloor(two_30, two_30);
assertEquals(two_30, Math.floor(two_30 + 0.1)); testFloor(two_30, two_30 + 0.1);
assertEquals(two_30, Math.floor(two_30 + 0.5)); testFloor(two_30, two_30 + 0.5);
assertEquals(two_30, Math.floor(two_30 + 0.7)); testFloor(two_30, two_30 + 0.7);
assertEquals(two_30 - 1, Math.floor(two_30 - 1)); testFloor(two_30 - 1, two_30 - 1);
assertEquals(two_30 - 1, Math.floor(two_30 - 1 + 0.1)); testFloor(two_30 - 1, two_30 - 1 + 0.1);
assertEquals(two_30 - 1, Math.floor(two_30 - 1 + 0.5)); testFloor(two_30 - 1, two_30 - 1 + 0.5);
assertEquals(two_30 - 1, Math.floor(two_30 - 1 + 0.7)); testFloor(two_30 - 1, two_30 - 1 + 0.7);
assertEquals(-two_30, Math.floor(-two_30)); testFloor(-two_30, -two_30);
assertEquals(-two_30, Math.floor(-two_30 + 0.1)); testFloor(-two_30, -two_30 + 0.1);
assertEquals(-two_30, Math.floor(-two_30 + 0.5)); testFloor(-two_30, -two_30 + 0.5);
assertEquals(-two_30, Math.floor(-two_30 + 0.7)); testFloor(-two_30, -two_30 + 0.7);
assertEquals(-two_30 + 1, Math.floor(-two_30 + 1)); testFloor(-two_30 + 1, -two_30 + 1);
assertEquals(-two_30 + 1, Math.floor(-two_30 + 1 + 0.1)); testFloor(-two_30 + 1, -two_30 + 1 + 0.1);
assertEquals(-two_30 + 1, Math.floor(-two_30 + 1 + 0.5)); testFloor(-two_30 + 1, -two_30 + 1 + 0.5);
assertEquals(-two_30 + 1, Math.floor(-two_30 + 1 + 0.7)); testFloor(-two_30 + 1, -two_30 + 1 + 0.7);
// 2^52 is a precision boundary. // 2^52 is a precision boundary.
var two_52 = (1 << 30) * (1 << 22); var two_52 = (1 << 30) * (1 << 22);
assertEquals(two_52, Math.floor(two_52)); testFloor(two_52, two_52);
assertEquals(two_52, Math.floor(two_52 + 0.1)); testFloor(two_52, two_52 + 0.1);
assertEquals(two_52, two_52 + 0.5); assertEquals(two_52, two_52 + 0.5);
assertEquals(two_52, Math.floor(two_52 + 0.5)); testFloor(two_52, two_52 + 0.5);
assertEquals(two_52 + 1, two_52 + 0.7); assertEquals(two_52 + 1, two_52 + 0.7);
assertEquals(two_52 + 1, Math.floor(two_52 + 0.7)); testFloor(two_52 + 1, two_52 + 0.7);
assertEquals(two_52 - 1, Math.floor(two_52 - 1)); testFloor(two_52 - 1, two_52 - 1);
assertEquals(two_52 - 1, Math.floor(two_52 - 1 + 0.1)); testFloor(two_52 - 1, two_52 - 1 + 0.1);
assertEquals(two_52 - 1, Math.floor(two_52 - 1 + 0.5)); testFloor(two_52 - 1, two_52 - 1 + 0.5);
assertEquals(two_52 - 1, Math.floor(two_52 - 1 + 0.7)); testFloor(two_52 - 1, two_52 - 1 + 0.7);
assertEquals(-two_52, Math.floor(-two_52)); testFloor(-two_52, -two_52);
assertEquals(-two_52, Math.floor(-two_52 + 0.1)); testFloor(-two_52, -two_52 + 0.1);
assertEquals(-two_52, Math.floor(-two_52 + 0.5)); testFloor(-two_52, -two_52 + 0.5);
assertEquals(-two_52, Math.floor(-two_52 + 0.7)); testFloor(-two_52, -two_52 + 0.7);
assertEquals(-two_52 + 1, Math.floor(-two_52 + 1)); testFloor(-two_52 + 1, -two_52 + 1);
assertEquals(-two_52 + 1, Math.floor(-two_52 + 1 + 0.1)); testFloor(-two_52 + 1, -two_52 + 1 + 0.1);
assertEquals(-two_52 + 1, Math.floor(-two_52 + 1 + 0.5)); testFloor(-two_52 + 1, -two_52 + 1 + 0.5);
assertEquals(-two_52 + 1, Math.floor(-two_52 + 1 + 0.7)); testFloor(-two_52 + 1, -two_52 + 1 + 0.7);
} }
......
...@@ -32,6 +32,8 @@ function testRound(expect, input) { ...@@ -32,6 +32,8 @@ function testRound(expect, input) {
return Math.round(input); return Math.round(input);
} }
assertEquals(expect, doRound(input)); assertEquals(expect, doRound(input));
assertEquals(expect, doRound(input));
assertEquals(expect, doRound(input));
%OptimizeFunctionOnNextCall(doRound); %OptimizeFunctionOnNextCall(doRound);
assertEquals(expect, doRound(input)); assertEquals(expect, doRound(input));
} }
......
...@@ -31,37 +31,45 @@ function MjsUnitAssertionError(message) { ...@@ -31,37 +31,45 @@ function MjsUnitAssertionError(message) {
this.stack = new Error("").stack; this.stack = new Error("").stack;
} }
MjsUnitAssertionError.prototype.toString = function () {
return this.message;
}
/* /*
* This file is included in all mini jsunit test cases. The test * This file is included in all mini jsunit test cases. The test
* framework expects lines that signal failed tests to start with * framework expects lines that signal failed tests to start with
* the f-word and ignore all other lines. * the f-word and ignore all other lines.
*/ */
MjsUnitAssertionError.prototype.toString = function () {
return this.message;
};
function classOf(object) {
var string = Object.prototype.toString.call(object);
// String has format [object <ClassName>].
return string.substring(8, string.length - 1);
}
function MjsUnitToString(value) { function MjsUnitToString(value) {
switch (typeof value) { switch (typeof value) {
case "string": case "string":
return JSON.stringify(value); return JSON.stringify(value);
case "number": case "number":
if (value === 0 && (1 / value) < 0) return "-0"; if (value === 0 && (1 / value) < 0) return "-0";
// FALLTHROUGH.
case "boolean": case "boolean":
case "null":
case "undefined": case "undefined":
case "function": case "function":
return String(value); return String(value);
case "object": case "object":
if (value === null) return "null"; if (value === null) return "null";
var clazz = Object.prototype.toString.call(value); var objectClass = classOf(value);
clazz = clazz.substring(8, clazz.length - 1); switch (objectClass) {
switch (clazz) {
case "Number": case "Number":
case "String": case "String":
case "Boolean": case "Boolean":
case "Date": case "Date":
return clazz + "(" + MjsUnitToString(value.valueOf()) + ")"; return objectClass + "(" + MjsUnitToString(value.valueOf()) + ")";
case "RegExp": case "RegExp":
return value.toString(); return value.toString();
case "Array": case "Array":
...@@ -69,7 +77,7 @@ function MjsUnitToString(value) { ...@@ -69,7 +77,7 @@ function MjsUnitToString(value) {
case "Object": case "Object":
break; break;
default: default:
return clazz + "()"; return objectClass + "()";
} }
// [[Class]] is "Object". // [[Class]] is "Object".
var constructor = value.constructor.name; var constructor = value.constructor.name;
...@@ -102,11 +110,13 @@ function fail(expected, found, name_opt) { ...@@ -102,11 +110,13 @@ function fail(expected, found, name_opt) {
function deepObjectEquals(a, b) { function deepObjectEquals(a, b) {
var aProps = []; var aProps = [];
for (var key in a) for (var key in a) {
aProps.push(key); aProps.push(key);
}
var bProps = []; var bProps = [];
for (var key in b) for (key in b) {
bProps.push(key); bProps.push(key);
}
aProps.sort(); aProps.sort();
bProps.sort(); bProps.sort();
if (!deepEquals(aProps, bProps)) if (!deepEquals(aProps, bProps))
...@@ -129,14 +139,16 @@ function deepEquals(a, b) { ...@@ -129,14 +139,16 @@ function deepEquals(a, b) {
return true; return true;
} }
if (a == null || b == null) return false; if (a == null || b == null) return false;
if (a.constructor === RegExp || b.constructor === RegExp) { var aClass = classOf(a);
return (a.constructor === b.constructor) && (a.toString() === b.toString()); var bClass = classOf(b);
if (aClass === "RegExp" || bClass === "RegExp") {
return (aClass === bClass) && (a.toString() === b.toString());
} }
if ((typeof a) !== 'object' || (typeof b) !== 'object' || if ((typeof a) !== 'object' || (typeof b) !== 'object' ||
(a === null) || (b === null)) (a === null) || (b === null))
return false; return false;
if (a.constructor === Array) { if (aClass === "Array") {
if (b.constructor !== Array) if (bClass !== "Array")
return false; return false;
if (a.length != b.length) if (a.length != b.length)
return false; return false;
...@@ -149,6 +161,8 @@ function deepEquals(a, b) { ...@@ -149,6 +161,8 @@ function deepEquals(a, b) {
} }
} }
return true; return true;
} else if (bClass == "Array") {
return false;
} else { } else {
return deepObjectEquals(a, b); return deepObjectEquals(a, b);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment