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) {
}
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) {
EnsureSpace ensure_space(this);
emit(0x66);
......
......@@ -1336,6 +1336,15 @@ class Assembler : public AssemblerBase {
void ucomisd(XMMRegister dst, XMMRegister 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);
// The first argument is the reg field, the second argument is the r/m field.
......
......@@ -1021,6 +1021,13 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
current += PrintRightOperand(current);
AppendToBuffer(", %s, %d", NameOfCPURegister(regop), (*current) & 3);
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 {
UnimplementedInstruction();
}
......
......@@ -2698,21 +2698,36 @@ void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
XMMRegister xmm_scratch = xmm0;
Register output_reg = ToRegister(instr->result());
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)) {
DeoptimizeIf(below_equal, instr->environment());
if (CpuFeatures::IsSupported(SSE4_1)) {
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 {
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).
__ cvttsd2si(output_reg, input_reg);
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
DeoptimizeIf(below_equal, instr->environment());
} else {
DeoptimizeIf(below, instr->environment());
}
// Overflow is signalled with minint.
__ cmpl(output_reg, Immediate(0x80000000));
DeoptimizeIf(equal, instr->environment());
// Use truncating instruction (OK because input is positive).
__ cvttsd2si(output_reg, input_reg);
// 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
// modification, are permitted provided that the following conditions are
// met:
......@@ -25,7 +25,18 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// 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() {
var x = 0.5;
......@@ -33,82 +44,84 @@ function zero() {
}
function test() {
assertEquals(0, Math.floor(0));
assertEquals(0, Math.floor(zero()));
assertEquals(1/-0, 1/Math.floor(-0)); // 0 == -0, so we use reciprocals.
assertEquals(Infinity, Math.floor(Infinity));
assertEquals(-Infinity, Math.floor(-Infinity));
assertNaN(Math.floor(NaN));
assertEquals(0, Math.floor(0.1));
assertEquals(0, Math.floor(0.5));
assertEquals(0, Math.floor(0.7));
assertEquals(-1, Math.floor(-0.1));
assertEquals(-1, Math.floor(-0.5));
assertEquals(-1, Math.floor(-0.7));
assertEquals(1, Math.floor(1));
assertEquals(1, Math.floor(1.1));
assertEquals(1, Math.floor(1.5));
assertEquals(1, Math.floor(1.7));
assertEquals(-1, Math.floor(-1));
assertEquals(-2, Math.floor(-1.1));
assertEquals(-2, Math.floor(-1.5));
assertEquals(-2, Math.floor(-1.7));
assertEquals(0, Math.floor(Number.MIN_VALUE));
assertEquals(-1, Math.floor(-Number.MIN_VALUE));
assertEquals(Number.MAX_VALUE, Math.floor(Number.MAX_VALUE));
assertEquals(-Number.MAX_VALUE, Math.floor(-Number.MAX_VALUE));
assertEquals(Infinity, Math.floor(Infinity));
assertEquals(-Infinity, Math.floor(-Infinity));
testFloor(0, 0);
testFloor(0, zero());
testFloor(-0, -0);
testFloor(Infinity, Infinity);
testFloor(-Infinity, -Infinity);
testFloor(NaN, NaN);
testFloor(0, 0.1);
testFloor(0, 0.49999999999999994);
testFloor(0, 0.5);
testFloor(0, 0.7);
testFloor(-1, -0.1);
testFloor(-1, -0.49999999999999994);
testFloor(-1, -0.5);
testFloor(-1, -0.7);
testFloor(1, 1);
testFloor(1, 1.1);
testFloor(1, 1.5);
testFloor(1, 1.7);
testFloor(-1, -1);
testFloor(-2, -1.1);
testFloor(-2, -1.5);
testFloor(-2, -1.7);
testFloor(0, Number.MIN_VALUE);
testFloor(-1, -Number.MIN_VALUE);
testFloor(Number.MAX_VALUE, Number.MAX_VALUE);
testFloor(-Number.MAX_VALUE, -Number.MAX_VALUE);
testFloor(Infinity, Infinity);
testFloor(-Infinity, -Infinity);
// 2^30 is a smi boundary.
var two_30 = 1 << 30;
assertEquals(two_30, Math.floor(two_30));
assertEquals(two_30, Math.floor(two_30 + 0.1));
assertEquals(two_30, Math.floor(two_30 + 0.5));
assertEquals(two_30, Math.floor(two_30 + 0.7));
testFloor(two_30, two_30);
testFloor(two_30, two_30 + 0.1);
testFloor(two_30, two_30 + 0.5);
testFloor(two_30, two_30 + 0.7);
assertEquals(two_30 - 1, Math.floor(two_30 - 1));
assertEquals(two_30 - 1, Math.floor(two_30 - 1 + 0.1));
assertEquals(two_30 - 1, Math.floor(two_30 - 1 + 0.5));
assertEquals(two_30 - 1, Math.floor(two_30 - 1 + 0.7));
testFloor(two_30 - 1, two_30 - 1);
testFloor(two_30 - 1, two_30 - 1 + 0.1);
testFloor(two_30 - 1, two_30 - 1 + 0.5);
testFloor(two_30 - 1, two_30 - 1 + 0.7);
assertEquals(-two_30, Math.floor(-two_30));
assertEquals(-two_30, Math.floor(-two_30 + 0.1));
assertEquals(-two_30, Math.floor(-two_30 + 0.5));
assertEquals(-two_30, Math.floor(-two_30 + 0.7));
testFloor(-two_30, -two_30);
testFloor(-two_30, -two_30 + 0.1);
testFloor(-two_30, -two_30 + 0.5);
testFloor(-two_30, -two_30 + 0.7);
assertEquals(-two_30 + 1, Math.floor(-two_30 + 1));
assertEquals(-two_30 + 1, Math.floor(-two_30 + 1 + 0.1));
assertEquals(-two_30 + 1, Math.floor(-two_30 + 1 + 0.5));
assertEquals(-two_30 + 1, Math.floor(-two_30 + 1 + 0.7));
testFloor(-two_30 + 1, -two_30 + 1);
testFloor(-two_30 + 1, -two_30 + 1 + 0.1);
testFloor(-two_30 + 1, -two_30 + 1 + 0.5);
testFloor(-two_30 + 1, -two_30 + 1 + 0.7);
// 2^52 is a precision boundary.
var two_52 = (1 << 30) * (1 << 22);
assertEquals(two_52, Math.floor(two_52));
assertEquals(two_52, Math.floor(two_52 + 0.1));
testFloor(two_52, two_52);
testFloor(two_52, two_52 + 0.1);
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, Math.floor(two_52 + 0.7));
assertEquals(two_52 - 1, Math.floor(two_52 - 1));
assertEquals(two_52 - 1, Math.floor(two_52 - 1 + 0.1));
assertEquals(two_52 - 1, Math.floor(two_52 - 1 + 0.5));
assertEquals(two_52 - 1, Math.floor(two_52 - 1 + 0.7));
assertEquals(-two_52, Math.floor(-two_52));
assertEquals(-two_52, Math.floor(-two_52 + 0.1));
assertEquals(-two_52, Math.floor(-two_52 + 0.5));
assertEquals(-two_52, Math.floor(-two_52 + 0.7));
assertEquals(-two_52 + 1, Math.floor(-two_52 + 1));
assertEquals(-two_52 + 1, Math.floor(-two_52 + 1 + 0.1));
assertEquals(-two_52 + 1, Math.floor(-two_52 + 1 + 0.5));
assertEquals(-two_52 + 1, Math.floor(-two_52 + 1 + 0.7));
testFloor(two_52 + 1, two_52 + 0.7);
testFloor(two_52 - 1, two_52 - 1);
testFloor(two_52 - 1, two_52 - 1 + 0.1);
testFloor(two_52 - 1, two_52 - 1 + 0.5);
testFloor(two_52 - 1, two_52 - 1 + 0.7);
testFloor(-two_52, -two_52);
testFloor(-two_52, -two_52 + 0.1);
testFloor(-two_52, -two_52 + 0.5);
testFloor(-two_52, -two_52 + 0.7);
testFloor(-two_52 + 1, -two_52 + 1);
testFloor(-two_52 + 1, -two_52 + 1 + 0.1);
testFloor(-two_52 + 1, -two_52 + 1 + 0.5);
testFloor(-two_52 + 1, -two_52 + 1 + 0.7);
}
......
......@@ -32,6 +32,8 @@ function testRound(expect, input) {
return Math.round(input);
}
assertEquals(expect, doRound(input));
assertEquals(expect, doRound(input));
assertEquals(expect, doRound(input));
%OptimizeFunctionOnNextCall(doRound);
assertEquals(expect, doRound(input));
}
......
......@@ -31,37 +31,45 @@ function MjsUnitAssertionError(message) {
this.stack = new Error("").stack;
}
MjsUnitAssertionError.prototype.toString = function () {
return this.message;
}
/*
* This file is included in all mini jsunit test cases. The test
* framework expects lines that signal failed tests to start with
* 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) {
switch (typeof value) {
case "string":
return JSON.stringify(value);
case "number":
if (value === 0 && (1 / value) < 0) return "-0";
// FALLTHROUGH.
case "boolean":
case "null":
case "undefined":
case "function":
return String(value);
case "object":
if (value === null) return "null";
var clazz = Object.prototype.toString.call(value);
clazz = clazz.substring(8, clazz.length - 1);
switch (clazz) {
var objectClass = classOf(value);
switch (objectClass) {
case "Number":
case "String":
case "Boolean":
case "Date":
return clazz + "(" + MjsUnitToString(value.valueOf()) + ")";
return objectClass + "(" + MjsUnitToString(value.valueOf()) + ")";
case "RegExp":
return value.toString();
case "Array":
......@@ -69,7 +77,7 @@ function MjsUnitToString(value) {
case "Object":
break;
default:
return clazz + "()";
return objectClass + "()";
}
// [[Class]] is "Object".
var constructor = value.constructor.name;
......@@ -102,11 +110,13 @@ function fail(expected, found, name_opt) {
function deepObjectEquals(a, b) {
var aProps = [];
for (var key in a)
for (var key in a) {
aProps.push(key);
}
var bProps = [];
for (var key in b)
for (key in b) {
bProps.push(key);
}
aProps.sort();
bProps.sort();
if (!deepEquals(aProps, bProps))
......@@ -129,14 +139,16 @@ function deepEquals(a, b) {
return true;
}
if (a == null || b == null) return false;
if (a.constructor === RegExp || b.constructor === RegExp) {
return (a.constructor === b.constructor) && (a.toString() === b.toString());
var aClass = classOf(a);
var bClass = classOf(b);
if (aClass === "RegExp" || bClass === "RegExp") {
return (aClass === bClass) && (a.toString() === b.toString());
}
if ((typeof a) !== 'object' || (typeof b) !== 'object' ||
(a === null) || (b === null))
return false;
if (a.constructor === Array) {
if (b.constructor !== Array)
if (aClass === "Array") {
if (bClass !== "Array")
return false;
if (a.length != b.length)
return false;
......@@ -149,6 +161,8 @@ function deepEquals(a, b) {
}
}
return true;
} else if (bClass == "Array") {
return false;
} else {
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