Revision: 3504
Author: [email protected]
Date: Mon Dec 21 00:32:20 2009
Log: Bring back the fisttp instruction on machines with SSE3, but check the
input so we don't have to check the exception flags afterwards.
Review URL: http://codereview.chromium.org/509001
http://code.google.com/p/v8/source/detail?r=3504

Modified:
  /branches/bleeding_edge/src/ia32/assembler-ia32.cc
  /branches/bleeding_edge/src/ia32/assembler-ia32.h
  /branches/bleeding_edge/src/ia32/codegen-ia32.cc
  /branches/bleeding_edge/test/mjsunit/smi-ops.js

=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.cc  Thu Dec 17 22:38:12  
2009
+++ /branches/bleeding_edge/src/ia32/assembler-ia32.cc  Mon Dec 21 00:32:20  
2009
@@ -1673,6 +1673,15 @@
    EMIT(0xDB);
    emit_operand(ecx, adr);
  }
+
+
+void Assembler::fisttp_d(const Operand& adr) {
+  ASSERT(CpuFeatures::IsEnabled(SSE3));
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  EMIT(0xDD);
+  emit_operand(ecx, adr);
+}


  void Assembler::fist_s(const Operand& adr) {
=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.h   Thu Dec 17 22:38:12  
2009
+++ /branches/bleeding_edge/src/ia32/assembler-ia32.h   Mon Dec 21 00:32:20  
2009
@@ -693,6 +693,7 @@
    void fistp_d(const Operand& adr);

    void fisttp_s(const Operand& adr);
+  void fisttp_d(const Operand& adr);

    void fabs();
    void fchs();
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc    Fri Dec 18 05:47:58  
2009
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc    Mon Dec 21 00:32:20  
2009
@@ -764,6 +764,7 @@
    // Takes the operands in edx and eax and loads them as integers in eax
    // and ecx.
    static void LoadAsIntegers(MacroAssembler* masm,
+                             bool use_sse3,
                               Label* operand_conversion_failure);
    // Test if operands are numbers (smi or HeapNumber objects), and load
    // them into xmm0 and xmm1 if they are.  Jump to label not_numbers if
@@ -7268,6 +7269,7 @@
        Label operand_conversion_failure;
        FloatingPointHelper::LoadAsIntegers(
          masm,
+        use_sse3_,
          &operand_conversion_failure);
        switch (op_) {
          case Token::BIT_OR:  __ or_(eax, Operand(ecx)); break;
@@ -7450,6 +7452,7 @@
  // trashed registers.
  void IntegerConvert(MacroAssembler* masm,
                      Register source,
+                    bool use_sse3,
                      Label* conversion_failure) {
    Label done, right_exponent, normal_exponent;
    Register scratch = ebx;
@@ -7459,109 +7462,128 @@
    // Get exponent alone in scratch2.
    __ mov(scratch2, scratch);
    __ and_(scratch2, HeapNumber::kExponentMask);
-  // Load ecx with zero.  We use this either for the final shift or
-  // for the answer.
-  __ xor_(ecx, Operand(ecx));
-  // Check whether the exponent matches a 32 bit signed int that cannot be
-  // represented by a Smi.  A non-smi 32 bit integer is 1.xxx * 2^30 so the
-  // exponent is 30 (biased).  This is the exponent that we are fastest at  
and
-  // also the highest exponent we can handle here.
-  const uint32_t non_smi_exponent =
-      (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
-  __ cmp(Operand(scratch2), Immediate(non_smi_exponent));
-  // If we have a match of the int32-but-not-Smi exponent then skip some  
logic.
-  __ j(equal, &right_exponent);
-  // If the exponent is higher than that then go to slow case.  This  
catches
-  // numbers that don't fit in a signed int32, infinities and NaNs.
-  __ j(less, &normal_exponent);
-
-  {
-    // Handle a big exponent.  The only reason we have this code is that  
the >>>
-    // operator has a tendency to generate numbers with an exponent of 31.
-    const uint32_t big_non_smi_exponent =
-        (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift;
-    __ cmp(Operand(scratch2), Immediate(big_non_smi_exponent));
-    __ j(not_equal, conversion_failure);
-    // We have the big exponent, typically from >>>.  This means the  
number is
-    // in the range 2^31 to 2^32 - 1.  Get the top bits of the mantissa.
-    __ mov(scratch2, scratch);
-    __ and_(scratch2, HeapNumber::kMantissaMask);
+  if (use_sse3) {
+    CpuFeatures::Scope scope(SSE3);
+    // Check whether the exponent is too big for a 64 bit signed integer.
+    const uint32_t too_big_exponent =
+        (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
+    __ cmp(Operand(scratch2), Immediate(too_big_exponent));
+    __ j(greater_equal, conversion_failure);
+    // Load x87 register with heap number.
+    __ fld_d(FieldOperand(source, HeapNumber::kValueOffset));
+    // Reserve space for 64 bit answer.
+    __ sub(Operand(esp), Immediate(sizeof(uint64_t)));  // Nolint.
+    // Do conversion, which cannot fail because we checked the exponent.
+    __ fisttp_d(Operand(esp, 0));
+    __ mov(ecx, Operand(esp, 0));  // Load low word of answer into ecx.
+    __ add(Operand(esp), Immediate(sizeof(uint64_t)));  // Nolint.
+  } else {
+    // Load ecx with zero.  We use this either for the final shift or
+    // for the answer.
+    __ xor_(ecx, Operand(ecx));
+    // Check whether the exponent matches a 32 bit signed int that cannot  
be
+    // represented by a Smi.  A non-smi 32 bit integer is 1.xxx * 2^30 so  
the
+    // exponent is 30 (biased).  This is the exponent that we are fastest  
at and
+    // also the highest exponent we can handle here.
+    const uint32_t non_smi_exponent =
+        (HeapNumber::kExponentBias + 30) << HeapNumber::kExponentShift;
+    __ cmp(Operand(scratch2), Immediate(non_smi_exponent));
+    // If we have a match of the int32-but-not-Smi exponent then skip some
+    // logic.
+    __ j(equal, &right_exponent);
+    // If the exponent is higher than that then go to slow case.  This  
catches
+    // numbers that don't fit in a signed int32, infinities and NaNs.
+    __ j(less, &normal_exponent);
+
+    {
+      // Handle a big exponent.  The only reason we have this code is that  
the
+      // >>> operator has a tendency to generate numbers with an exponent  
of 31.
+      const uint32_t big_non_smi_exponent =
+          (HeapNumber::kExponentBias + 31) << HeapNumber::kExponentShift;
+      __ cmp(Operand(scratch2), Immediate(big_non_smi_exponent));
+      __ j(not_equal, conversion_failure);
+      // We have the big exponent, typically from >>>.  This means the  
number is
+      // in the range 2^31 to 2^32 - 1.  Get the top bits of the mantissa.
+      __ mov(scratch2, scratch);
+      __ and_(scratch2, HeapNumber::kMantissaMask);
+      // Put back the implicit 1.
+      __ or_(scratch2, 1 << HeapNumber::kExponentShift);
+      // Shift up the mantissa bits to take up the space the exponent used  
to
+      // take. We just orred in the implicit bit so that took care of one  
and
+      // we want to use the full unsigned range so we subtract 1 bit from  
the
+      // shift distance.
+      const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord  
- 1;
+      __ shl(scratch2, big_shift_distance);
+      // Get the second half of the double.
+      __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset));
+      // Shift down 21 bits to get the most significant 11 bits or the low
+      // mantissa word.
+      __ shr(ecx, 32 - big_shift_distance);
+      __ or_(ecx, Operand(scratch2));
+      // We have the answer in ecx, but we may need to negate it.
+      __ test(scratch, Operand(scratch));
+      __ j(positive, &done);
+      __ neg(ecx);
+      __ jmp(&done);
+    }
+
+    __ bind(&normal_exponent);
+    // Exponent word in scratch, exponent part of exponent word in  
scratch2.
+    // Zero in ecx.
+    // We know the exponent is smaller than 30 (biased).  If it is less  
than
+    // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0,  
ie
+    // it rounds to zero.
+    const uint32_t zero_exponent =
+        (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift;
+    __ sub(Operand(scratch2), Immediate(zero_exponent));
+    // ecx already has a Smi zero.
+    __ j(less, &done);
+
+    // We have a shifted exponent between 0 and 30 in scratch2.
+    __ shr(scratch2, HeapNumber::kExponentShift);
+    __ mov(ecx, Immediate(30));
+    __ sub(ecx, Operand(scratch2));
+
+    __ bind(&right_exponent);
+    // Here ecx is the shift, scratch is the exponent word.
+    // Get the top bits of the mantissa.
+    __ and_(scratch, HeapNumber::kMantissaMask);
      // Put back the implicit 1.
-    __ or_(scratch2, 1 << HeapNumber::kExponentShift);
+    __ or_(scratch, 1 << HeapNumber::kExponentShift);
      // Shift up the mantissa bits to take up the space the exponent used to
-    // take. We just orred in the implicit bit so that took care of one and
-    // we want to use the full unsigned range so we subtract 1 bit from the
-    // shift distance.
-    const int big_shift_distance = HeapNumber::kNonMantissaBitsInTopWord -  
1;
-    __ shl(scratch2, big_shift_distance);
-    // Get the second half of the double.
-    __ mov(ecx, FieldOperand(source, HeapNumber::kMantissaOffset));
-    // Shift down 21 bits to get the most significant 11 bits or the low
+    // take. We have kExponentShift + 1 significant bits int he low end of  
the
+    // word.  Shift them to the top bits.
+    const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
+    __ shl(scratch, shift_distance);
+    // Get the second half of the double. For some exponents we don't
+    // actually need this because the bits get shifted out again, but
+    // it's probably slower to test than just to do it.
+    __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset));
+    // Shift down 22 bits to get the most significant 10 bits or the low
      // mantissa word.
-    __ shr(ecx, 32 - big_shift_distance);
-    __ or_(ecx, Operand(scratch2));
-    // We have the answer in ecx, but we may need to negate it.
-    __ test(scratch, Operand(scratch));
-    __ j(positive, &done);
-    __ neg(ecx);
+    __ shr(scratch2, 32 - shift_distance);
+    __ or_(scratch2, Operand(scratch));
+    // Move down according to the exponent.
+    __ shr_cl(scratch2);
+    // Now the unsigned answer is in scratch2.  We need to move it to ecx  
and
+    // we may need to fix the sign.
+    Label negative;
+    __ xor_(ecx, Operand(ecx));
+    __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset));
+    __ j(greater, &negative);
+    __ mov(ecx, scratch2);
      __ jmp(&done);
-  }
-
-  __ bind(&normal_exponent);
-  // Exponent word in scratch, exponent part of exponent word in scratch2.
-  // Zero in ecx.
-  // We know the exponent is smaller than 30 (biased).  If it is less than
-  // 0 (biased) then the number is smaller in magnitude than 1.0 * 2^0, ie
-  // it rounds to zero.
-  const uint32_t zero_exponent =
-      (HeapNumber::kExponentBias + 0) << HeapNumber::kExponentShift;
-  __ sub(Operand(scratch2), Immediate(zero_exponent));
-  // ecx already has a Smi zero.
-  __ j(less, &done);
-
-  // We have a shifted exponent between 0 and 30 in scratch2.
-  __ shr(scratch2, HeapNumber::kExponentShift);
-  __ mov(ecx, Immediate(30));
-  __ sub(ecx, Operand(scratch2));
-
-  __ bind(&right_exponent);
-  // Here ecx is the shift, scratch is the exponent word.
-  // Get the top bits of the mantissa.
-  __ and_(scratch, HeapNumber::kMantissaMask);
-  // Put back the implicit 1.
-  __ or_(scratch, 1 << HeapNumber::kExponentShift);
-  // Shift up the mantissa bits to take up the space the exponent used to
-  // take. We have kExponentShift + 1 significant bits int he low end of  
the
-  // word.  Shift them to the top bits.
-  const int shift_distance = HeapNumber::kNonMantissaBitsInTopWord - 2;
-  __ shl(scratch, shift_distance);
-  // Get the second half of the double. For some exponents we don't
-  // actually need this because the bits get shifted out again, but
-  // it's probably slower to test than just to do it.
-  __ mov(scratch2, FieldOperand(source, HeapNumber::kMantissaOffset));
-  // Shift down 22 bits to get the most significant 10 bits or the low  
mantissa
-  // word.
-  __ shr(scratch2, 32 - shift_distance);
-  __ or_(scratch2, Operand(scratch));
-  // Move down according to the exponent.
-  __ shr_cl(scratch2);
-  // Now the unsigned answer is in scratch2.  We need to move it to ecx and
-  // we may need to fix the sign.
-  Label negative;
-  __ xor_(ecx, Operand(ecx));
-  __ cmp(ecx, FieldOperand(source, HeapNumber::kExponentOffset));
-  __ j(greater, &negative);
-  __ mov(ecx, scratch2);
-  __ jmp(&done);
-  __ bind(&negative);
-  __ sub(ecx, Operand(scratch2));
-  __ bind(&done);
+    __ bind(&negative);
+    __ sub(ecx, Operand(scratch2));
+    __ bind(&done);
+  }
  }


  // Input: edx, eax are the left and right objects of a bit op.
  // Output: eax, ecx are left and right integers for a bit op.
  void FloatingPointHelper::LoadAsIntegers(MacroAssembler* masm,
+                                         bool use_sse3,
                                           Label* conversion_failure) {
    // Check float operands.
    Label arg1_is_object, arg2_is_object, load_arg2;
@@ -7577,7 +7599,7 @@
    __ cmp(ebx, Factory::heap_number_map());
    __ j(not_equal, conversion_failure);
    // Get the untagged integer version of the edx heap number in ecx.
-  IntegerConvert(masm, edx, conversion_failure);
+  IntegerConvert(masm, edx, use_sse3, conversion_failure);
    __ mov(edx, ecx);

    // Here edx has the untagged integer, eax has a Smi or a heap number.
@@ -7594,7 +7616,7 @@
    __ cmp(ebx, Factory::heap_number_map());
    __ j(not_equal, conversion_failure);
    // Get the untagged integer version of the eax heap number in ecx.
-  IntegerConvert(masm, eax, conversion_failure);
+  IntegerConvert(masm, eax, use_sse3, conversion_failure);
    __ bind(&done);
    __ mov(eax, edx);
  }
=======================================
--- /branches/bleeding_edge/test/mjsunit/smi-ops.js     Thu Jul  9 04:46:30 2009
+++ /branches/bleeding_edge/test/mjsunit/smi-ops.js     Mon Dec 21 00:32:20 2009
@@ -537,7 +537,7 @@
    one = four - three;
    zero = one - one;

- // Begin block A repeat 3
+  // Begin block A repeat 3
    assertEquals(pos_non_smi, (pos_non_smi) >> zero);
    assertEquals(pos_non_smi, (pos_non_smi) >>> zero);
    assertEquals(pos_non_smi, (pos_non_smi) << zero);
@@ -638,6 +638,31 @@

  testShiftNonSmis();

+function intConversion() {
+  function foo(x) {
+    assertEquals(x, (x * 1.0000000001) | 0, "foo more " + x);
+    assertEquals(x, x | 0, "foo " + x);
+    if (x > 0) {
+      assertEquals(x - 1, (x * 0.9999999999) | 0, "foo less " + x);
+    } else {
+      assertEquals(x + 1, (x * 0.9999999999) | 0, "foo less " + x);
+    }
+  }
+  for (var i = 1; i < 0x80000000; i *= 2) {
+    foo(i);
+    foo(-i);
+  }
+  for (var i = 1; i < 1/0; i *= 2) {
+    assertEquals(i | 0, (i * 1.0000000000000001) | 0, "b" + i);
+    assertEquals(-i | 0, (i * -1.0000000000000001) | 0, "c" + i);
+  }
+  for (var i = 0.5; i > 0; i /= 2) {
+    assertEquals(0, i | 0, "d" + i);
+    assertEquals(0, -i | 0, "e" + i);
+  }
+}
+
+intConversion();

  // Verify that we handle the (optimized) corner case of shifting by
  // zero even for non-smis.

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

Reply via email to