Revision: 7613
Author:   [email protected]
Date:     Thu Apr 14 02:05:43 2011
Log:      X64: Use roundsd for DoMathFloor.

TEST=mjsunit/math-floor

Review URL: http://codereview.chromium.org/6835021
http://code.google.com/p/v8/source/detail?r=7613

Modified:
 /branches/bleeding_edge/src/x64/assembler-x64.cc
 /branches/bleeding_edge/src/x64/assembler-x64.h
 /branches/bleeding_edge/src/x64/disasm-x64.cc
 /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
 /branches/bleeding_edge/test/mjsunit/math-floor.js
 /branches/bleeding_edge/test/mjsunit/math-round.js
 /branches/bleeding_edge/test/mjsunit/mjsunit.js

=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.cc Tue Apr 12 06:20:51 2011 +++ /branches/bleeding_edge/src/x64/assembler-x64.cc Thu Apr 14 02:05:43 2011
@@ -2861,6 +2861,21 @@
   emit(0x2e);
   emit_sse_operand(dst, 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) {
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.h     Wed Apr  6 01:41:28 2011
+++ /branches/bleeding_edge/src/x64/assembler-x64.h     Thu Apr 14 02:05:43 2011
@@ -1336,6 +1336,15 @@
   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.
=======================================
--- /branches/bleeding_edge/src/x64/disasm-x64.cc       Tue Apr 12 06:20:51 2011
+++ /branches/bleeding_edge/src/x64/disasm-x64.cc       Thu Apr 14 02:05:43 2011
@@ -1021,6 +1021,13 @@
         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();
       }
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Wed Apr 13 02:35:56 2011 +++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Thu Apr 14 02:05:43 2011
@@ -2698,21 +2698,36 @@
   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());
-  }
-
-  // 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());
+    __ xorpd(xmm_scratch, xmm_scratch);  // Zero the register.
+    __ ucomisd(input_reg, xmm_scratch);
+
+    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
+      DeoptimizeIf(below_equal, instr->environment());
+    } else {
+      DeoptimizeIf(below, 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());
+  }
 }


=======================================
--- /branches/bleeding_edge/test/mjsunit/math-floor.js Tue Dec 7 03:01:02 2010 +++ /branches/bleeding_edge/test/mjsunit/math-floor.js Thu Apr 14 02:05:43 2011
@@ -1,4 +1,4 @@
-// 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 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));
-
-  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));
-
-  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));
-
-  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, two_30);
+  testFloor(two_30, two_30 + 0.1);
+  testFloor(two_30, two_30 + 0.5);
+  testFloor(two_30, two_30 + 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);
+
+  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);
+
+  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);
 }


=======================================
--- /branches/bleeding_edge/test/mjsunit/math-round.js Wed Apr 13 02:35:56 2011 +++ /branches/bleeding_edge/test/mjsunit/math-round.js Thu Apr 14 02:05:43 2011
@@ -31,6 +31,8 @@
   function doRound(input) {
     return Math.round(input);
   }
+  assertEquals(expect, doRound(input));
+  assertEquals(expect, doRound(input));
   assertEquals(expect, doRound(input));
   %OptimizeFunctionOnNextCall(doRound);
   assertEquals(expect, doRound(input));
=======================================
--- /branches/bleeding_edge/test/mjsunit/mjsunit.js     Fri Mar 25 06:24:20 2011
+++ /branches/bleeding_edge/test/mjsunit/mjsunit.js     Thu Apr 14 02:05:43 2011
@@ -30,10 +30,6 @@
   // This allows fetching the stack trace using TryCatch::StackTrace.
   this.stack = new Error("").stack;
 }
-
-MjsUnitAssertionError.prototype.toString = function () {
-  return this.message;
-}

 /*
  * This file is included in all mini jsunit test cases.  The test
@@ -41,27 +37,39 @@
  * 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 @@
         case "Object":
           break;
         default:
-          return clazz + "()";
+          return objectClass + "()";
       }
       // [[Class]] is "Object".
       var constructor = value.constructor.name;
@@ -102,11 +110,13 @@

 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 @@
     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 @@
       }
     }
     return true;
+  } else if (bClass == "Array") {
+    return false;
   } else {
     return deepObjectEquals(a, b);
   }

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to