Move ToI conversions to the MacroAssembler
authorolivf@chromium.org <olivf@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Sep 2013 09:30:54 +0000 (09:30 +0000)
committerolivf@chromium.org <olivf@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 2 Sep 2013 09:30:54 +0000 (09:30 +0000)
+ Replace DeferredTaggedToINoSSE2 by DoubleToIStub and a fpu version.

+ Prevent truncating TaggedToI from bailing out.

BUG=
R=verwaest@chromium.org

Review URL: https://codereview.chromium.org/22290005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16464 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

12 files changed:
src/hydrogen-instructions.h
src/ia32/assembler-ia32.h
src/ia32/code-stubs-ia32.cc
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.h
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/ia32/macro-assembler-ia32.cc
src/ia32/macro-assembler-ia32.h
src/v8globals.h
test/mjsunit/external-array-no-sse2.js
test/mjsunit/external-array.js

index dd42190..0357805 100644 (file)
@@ -947,6 +947,11 @@ class HValue : public ZoneObject {
     return type().ToStringOrToNumberCanBeObserved(representation());
   }
 
+  MinusZeroMode GetMinusZeroMode() {
+    return CheckFlag(kBailoutOnMinusZero)
+        ? FAIL_ON_MINUS_ZERO : TREAT_MINUS_ZERO_AS_ZERO;
+  }
+
  protected:
   // This function must be overridden for instructions with flag kUseGVN, to
   // compare the non-Operand parts of the instruction.
index d6b6dab..551d031 100644 (file)
@@ -183,6 +183,7 @@ const IntelDoubleRegister double_register_4 = { 4 };
 const IntelDoubleRegister double_register_5 = { 5 };
 const IntelDoubleRegister double_register_6 = { 6 };
 const IntelDoubleRegister double_register_7 = { 7 };
+const IntelDoubleRegister no_double_reg = { -1 };
 
 
 struct XMMRegister : IntelDoubleRegister {
@@ -227,6 +228,7 @@ struct XMMRegister : IntelDoubleRegister {
 #define xmm5 (static_cast<const XMMRegister&>(double_register_5))
 #define xmm6 (static_cast<const XMMRegister&>(double_register_6))
 #define xmm7 (static_cast<const XMMRegister&>(double_register_7))
+#define no_xmm_reg (static_cast<const XMMRegister&>(no_double_reg))
 
 
 struct X87Register : IntelDoubleRegister {
index 42b1296..7891dc6 100644 (file)
@@ -658,18 +658,6 @@ void DoubleToIStub::Generate(MacroAssembler* masm) {
 }
 
 
-// Uses SSE2 to convert the heap number in |source| to an integer. Jumps to
-// |conversion_failure| if the heap number did not contain an int32 value.
-// Result is in ecx. Trashes ebx, xmm0, and xmm1.
-static void ConvertHeapNumberToInt32(MacroAssembler* masm,
-                                     Register source,
-                                     Label* conversion_failure) {
-  __ movdbl(xmm0, FieldOperand(source, HeapNumber::kValueOffset));
-  FloatingPointHelper::CheckSSE2OperandIsInt32(
-      masm, conversion_failure, xmm0, ecx, ebx, xmm1);
-}
-
-
 void BinaryOpStub::Initialize() {
   platform_specific_bit_ = CpuFeatures::IsSupported(SSE3);
 }
@@ -2270,16 +2258,7 @@ void FloatingPointHelper::LoadUnknownsAsIntegers(
   __ cmp(ebx, factory->heap_number_map());
   __ j(not_equal, &check_undefined_arg1);
 
-  // Get the untagged integer version of the edx heap number in ecx.
-  if (left_type == BinaryOpIC::INT32 && CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatureScope use_sse2(masm, SSE2);
-    ConvertHeapNumberToInt32(masm, edx, conversion_failure);
-  } else {
-    DoubleToIStub stub(edx, ecx, HeapNumber::kValueOffset - kHeapObjectTag,
-                       true);
-    __ call(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
-  }
-  __ mov(edx, ecx);
+  __ TruncateHeapNumberToI(edx, edx);
 
   // Here edx has the untagged integer, eax has a Smi or a heap number.
   __ bind(&load_arg2);
@@ -2308,14 +2287,7 @@ void FloatingPointHelper::LoadUnknownsAsIntegers(
   __ j(not_equal, &check_undefined_arg2);
   // Get the untagged integer version of the eax heap number in ecx.
 
-  if (right_type == BinaryOpIC::INT32 && CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatureScope use_sse2(masm, SSE2);
-    ConvertHeapNumberToInt32(masm, eax, conversion_failure);
-  } else {
-    DoubleToIStub stub(eax, ecx, HeapNumber::kValueOffset - kHeapObjectTag,
-                       true);
-    __ call(stub.GetCode(masm->isolate()), RelocInfo::CODE_TARGET);
-  }
+  __ TruncateHeapNumberToI(ecx, eax);
 
   __ bind(&done);
   __ mov(eax, edx);
@@ -2542,16 +2514,16 @@ void MathPowStub::Generate(MacroAssembler* masm) {
   }
 
   if (exponent_type_ != INTEGER) {
-    Label fast_power;
-    // Detect integer exponents stored as double.
-    __ cvttsd2si(exponent, Operand(double_exponent));
+    Label fast_power, try_arithmetic_simplification;
+    __ DoubleToI(exponent, double_exponent, double_scratch,
+                 TREAT_MINUS_ZERO_AS_ZERO, &try_arithmetic_simplification);
+    __ jmp(&int_exponent);
+
+    __ bind(&try_arithmetic_simplification);
     // Skip to runtime if possibly NaN (indicated by the indefinite integer).
+    __ cvttsd2si(exponent, Operand(double_exponent));
     __ cmp(exponent, Immediate(0x80000000u));
     __ j(equal, &call_runtime);
-    __ cvtsi2sd(double_scratch, exponent);
-    // Already ruled out NaNs for exponent.
-    __ ucomisd(double_exponent, double_scratch);
-    __ j(equal, &int_exponent);
 
     if (exponent_type_ == ON_STACK) {
       // Detect square root case.  Crankshaft detects constant +/-0.5 at
index b2c66b3..75525ed 100644 (file)
@@ -448,6 +448,7 @@ bool LCodeGen::GenerateDeferredCode() {
         Comment(";;; Deferred code");
       }
       code->Generate();
+      __ bind(code->done());
       if (NeedsDeferredFrame()) {
         Comment(";;; Destroy frame");
         ASSERT(frame_is_built_);
@@ -5306,94 +5307,39 @@ void LCodeGen::EmitNumberUntagD(Register input_reg,
 }
 
 
-void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr) {
-  Label done, heap_number;
+void LCodeGen::DoDeferredTaggedToI(LTaggedToI* instr, Label* done) {
   Register input_reg = ToRegister(instr->value());
 
-  // Heap number map check.
-  __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
-         factory()->heap_number_map());
 
   if (instr->truncating()) {
+    Label heap_number, slow_case;
+
+    // Heap number map check.
+    __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
+           factory()->heap_number_map());
     __ j(equal, &heap_number, Label::kNear);
+
     // Check for undefined. Undefined is converted to zero for truncating
     // conversions.
     __ cmp(input_reg, factory()->undefined_value());
     __ RecordComment("Deferred TaggedToI: cannot truncate");
     DeoptimizeIf(not_equal, instr->environment());
     __ mov(input_reg, 0);
-    __ jmp(&done, Label::kNear);
+    __ jmp(done);
 
     __ bind(&heap_number);
-    if (CpuFeatures::IsSupported(SSE3)) {
-      CpuFeatureScope scope(masm(), SSE3);
-      Label convert;
-      // Use more powerful conversion when sse3 is available.
-      // Load x87 register with heap number.
-      __ fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
-      // Get exponent alone and check for too-big exponent.
-      __ mov(input_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
-      __ and_(input_reg, HeapNumber::kExponentMask);
-      const uint32_t kTooBigExponent =
-          (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
-      __ cmp(Operand(input_reg), Immediate(kTooBigExponent));
-      __ j(less, &convert, Label::kNear);
-      // Pop FPU stack before deoptimizing.
-      __ fstp(0);
-      __ RecordComment("Deferred TaggedToI: exponent too big");
-      DeoptimizeIf(no_condition, instr->environment());
-
-      // Reserve space for 64 bit answer.
-      __ bind(&convert);
-      __ sub(Operand(esp), Immediate(kDoubleSize));
-      // Do conversion, which cannot fail because we checked the exponent.
-      __ fisttp_d(Operand(esp, 0));
-      __ mov(input_reg, Operand(esp, 0));  // Low word of answer is the result.
-      __ add(Operand(esp), Immediate(kDoubleSize));
-    } else if (CpuFeatures::IsSupported(SSE2)) {
-      CpuFeatureScope scope(masm(), SSE2);
-      XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
-      __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
-      __ cvttsd2si(input_reg, Operand(xmm0));
-      __ cmp(input_reg, 0x80000000u);
-      __ j(not_equal, &done);
-      // Check if the input was 0x8000000 (kMinInt).
-      // If no, then we got an overflow and we deoptimize.
-      ExternalReference min_int = ExternalReference::address_of_min_int();
-      __ movdbl(xmm_temp, Operand::StaticVariable(min_int));
-      __ ucomisd(xmm_temp, xmm0);
-      DeoptimizeIf(not_equal, instr->environment());
-      DeoptimizeIf(parity_even, instr->environment());  // NaN.
-    } else {
-      UNREACHABLE();
-    }
-  } else if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatureScope scope(masm(), SSE2);
-    // Deoptimize if we don't have a heap number.
-    __ RecordComment("Deferred TaggedToI: not a heap number");
-    DeoptimizeIf(not_equal, instr->environment());
-
-    XMMRegister xmm_temp = ToDoubleRegister(instr->temp());
-    __ movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
-    __ cvttsd2si(input_reg, Operand(xmm0));
-    __ cvtsi2sd(xmm_temp, Operand(input_reg));
-    __ ucomisd(xmm0, xmm_temp);
-    __ RecordComment("Deferred TaggedToI: lost precision");
-    DeoptimizeIf(not_equal, instr->environment());
-    __ RecordComment("Deferred TaggedToI: NaN");
-    DeoptimizeIf(parity_even, instr->environment());  // NaN.
-    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-      __ test(input_reg, Operand(input_reg));
-      __ j(not_zero, &done);
-      __ movmskpd(input_reg, xmm0);
-      __ and_(input_reg, 1);
-      __ RecordComment("Deferred TaggedToI: minus zero");
-      DeoptimizeIf(not_zero, instr->environment());
-    }
+    __ TruncateHeapNumberToI(input_reg, input_reg);
   } else {
-    UNREACHABLE();
+    Label bailout;
+    XMMRegister scratch = (instr->temp() != NULL)
+        ? ToDoubleRegister(instr->temp())
+        : no_xmm_reg;
+    __ TaggedToI(input_reg, input_reg, scratch,
+                 instr->hydrogen()->GetMinusZeroMode(), &bailout);
+    __ jmp(done);
+    __ bind(&bailout);
+    DeoptimizeIf(no_condition, instr->environment());
   }
-  __ bind(&done);
 }
 
 
@@ -5405,7 +5351,7 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
                       const X87Stack& x87_stack)
         : LDeferredCode(codegen, x87_stack), instr_(instr) { }
     virtual void Generate() V8_OVERRIDE {
-      codegen()->DoDeferredTaggedToI(instr_);
+      codegen()->DoDeferredTaggedToI(instr_, done());
     }
     virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
    private:
@@ -5426,171 +5372,6 @@ void LCodeGen::DoTaggedToI(LTaggedToI* instr) {
 }
 
 
-void LCodeGen::DoDeferredTaggedToINoSSE2(LTaggedToINoSSE2* instr) {
-  Label done, heap_number;
-  Register result_reg = ToRegister(instr->result());
-  Register input_reg = ToRegister(instr->value());
-
-  // Heap number map check.
-  __ cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
-         factory()->heap_number_map());
-  if (instr->truncating()) {
-    __ j(equal, &heap_number, Label::kNear);
-    // Check for undefined. Undefined is converted to zero for truncating
-    // conversions.
-    __ cmp(input_reg, factory()->undefined_value());
-    __ RecordComment("Deferred TaggedToI: cannot truncate");
-    DeoptimizeIf(not_equal, instr->environment());
-    __ xor_(result_reg, result_reg);
-    __ jmp(&done, Label::kFar);
-    __ bind(&heap_number);
-  } else {
-    // Deoptimize if we don't have a heap number.
-    DeoptimizeIf(not_equal, instr->environment());
-  }
-
-  // Surprisingly, all of this crazy bit manipulation is considerably
-  // faster than using the built-in x86 CPU conversion functions (about 6x).
-  Label right_exponent, adjust_bias, zero_result;
-  Register scratch = ToRegister(instr->scratch());
-  Register scratch2 = ToRegister(instr->scratch2());
-  // Get exponent word.
-  __ mov(scratch, FieldOperand(input_reg, HeapNumber::kExponentOffset));
-  // Get exponent alone in scratch2.
-  __ mov(scratch2, scratch);
-  __ and_(scratch2, HeapNumber::kExponentMask);
-  __ shr(scratch2, HeapNumber::kExponentShift);
-  if (instr->truncating()) {
-    __ j(zero, &zero_result);
-  } else {
-    __ j(not_zero, &adjust_bias);
-    __ test(scratch, Immediate(HeapNumber::kMantissaMask));
-    DeoptimizeIf(not_zero, instr->environment());
-    __ cmp(FieldOperand(input_reg, HeapNumber::kMantissaOffset), Immediate(0));
-    DeoptimizeIf(not_equal, instr->environment());
-    __ bind(&adjust_bias);
-  }
-  __ sub(scratch2, Immediate(HeapNumber::kExponentBias));
-  if (!instr->truncating()) {
-    DeoptimizeIf(negative, instr->environment());
-  } else {
-    __ j(negative, &zero_result);
-  }
-
-  // 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.
-  Register scratch3 = ToRegister(instr->scratch3());
-  __ mov(scratch3, FieldOperand(input_reg, HeapNumber::kMantissaOffset));
-  __ xor_(result_reg, result_reg);
-
-  const uint32_t non_int32_exponent = 31;
-  __ cmp(scratch2, Immediate(non_int32_exponent));
-  // If we have a match of the int32 exponent then skip some logic.
-  __ j(equal, &right_exponent, Label::kNear);
-  // If the number doesn't find in an int32, deopt.
-  DeoptimizeIf(greater, instr->environment());
-
-  // Exponent word in scratch, exponent in scratch2.  We know that 0 <= exponent
-  // < 31.
-  __ mov(result_reg, Immediate(31));
-  __ sub(result_reg, scratch2);
-
-  __ bind(&right_exponent);
-
-  // Save off exponent for negative check later.
-  __ mov(scratch2, scratch);
-
-  // Here result_reg 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 - 1;
-  __ shl(scratch, shift_distance);
-  if (!instr->truncating()) {
-    // If not truncating, a non-zero value in the bottom 22 bits means a
-    // non-integral value --> trigger a deopt.
-    __ test(scratch3, Immediate((1 << (32 - shift_distance)) - 1));
-    DeoptimizeIf(not_equal, instr->environment());
-  }
-  // Shift down 22 bits to get the most significant 10 bits or the low
-  // mantissa word.
-  __ shr(scratch3, 32 - shift_distance);
-  __ or_(scratch3, scratch);
-  if (!instr->truncating()) {
-    // If truncating, a non-zero value in the bits that will be shifted away
-    // when adjusting the exponent means rounding --> deopt.
-    __ mov(scratch, 0x1);
-    ASSERT(result_reg.is(ecx));
-    __ shl_cl(scratch);
-    __ dec(scratch);
-    __ test(scratch3, scratch);
-    DeoptimizeIf(not_equal, instr->environment());
-  }
-  // Move down according to the exponent.
-  ASSERT(result_reg.is(ecx));
-  __ shr_cl(scratch3);
-  // Now the unsigned 32-bit answer is in scratch3.  We need to move it to
-  // result_reg and we may need to fix the sign.
-  Label negative_result;
-  __ xor_(result_reg, result_reg);
-  __ cmp(scratch2, result_reg);
-  __ j(less, &negative_result, Label::kNear);
-  __ cmp(scratch3, result_reg);
-  __ mov(result_reg, scratch3);
-  // If the result is > MAX_INT, result doesn't fit in signed 32-bit --> deopt.
-  DeoptimizeIf(less, instr->environment());
-  __ jmp(&done, Label::kNear);
-  __ bind(&zero_result);
-  __ xor_(result_reg, result_reg);
-  __ jmp(&done, Label::kNear);
-  __ bind(&negative_result);
-  __ sub(result_reg, scratch3);
-  if (!instr->truncating()) {
-    // -0.0 triggers a deopt.
-    DeoptimizeIf(zero, instr->environment());
-  }
-  // If the negative subtraction overflows into a positive number, there was an
-  // overflow --> deopt.
-  DeoptimizeIf(positive, instr->environment());
-  __ bind(&done);
-}
-
-
-void LCodeGen::DoTaggedToINoSSE2(LTaggedToINoSSE2* instr) {
-  class DeferredTaggedToINoSSE2 V8_FINAL : public LDeferredCode {
-   public:
-    DeferredTaggedToINoSSE2(LCodeGen* codegen,
-                            LTaggedToINoSSE2* instr,
-                            const X87Stack& x87_stack)
-        : LDeferredCode(codegen, x87_stack), instr_(instr) { }
-    virtual void Generate() V8_OVERRIDE {
-      codegen()->DoDeferredTaggedToINoSSE2(instr_);
-    }
-    virtual LInstruction* instr() V8_OVERRIDE { return instr_; }
-   private:
-    LTaggedToINoSSE2* instr_;
-  };
-
-  LOperand* input = instr->value();
-  ASSERT(input->IsRegister());
-  Register input_reg = ToRegister(input);
-  ASSERT(input_reg.is(ToRegister(instr->result())));
-
-  DeferredTaggedToINoSSE2* deferred =
-      new(zone()) DeferredTaggedToINoSSE2(this, instr, x87_stack_);
-
-  // Smi check.
-  __ JumpIfNotSmi(input_reg, deferred->entry());
-  __ SmiUntag(input_reg);  // Untag smi.
-  __ bind(deferred->exit());
-}
-
-
 void LCodeGen::DoNumberUntagD(LNumberUntagD* instr) {
   LOperand* input = instr->value();
   ASSERT(input->IsRegister());
@@ -5637,73 +5418,33 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) {
   ASSERT(result->IsRegister());
   Register result_reg = ToRegister(result);
 
-  Label done;
-  if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
-    CpuFeatureScope scope(masm(), SSE2);
-
-    XMMRegister input_reg = ToDoubleRegister(input);
-
-    __ cvttsd2si(result_reg, Operand(input_reg));
-
-    if (instr->truncating()) {
-      // Performs a truncating conversion of a floating point number as used by
-      // the JS bitwise operations.
-      Label fast_case_succeeded;
-      __ cmp(result_reg, 0x80000000u);
-      __ j(not_equal, &fast_case_succeeded);
-      __ sub(esp, Immediate(kDoubleSize));
-      __ movdbl(MemOperand(esp, 0), input_reg);
-      DoubleToIStub stub(esp, result_reg, 0, true);
-      __ call(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
-      __ add(esp, Immediate(kDoubleSize));
-      __ bind(&fast_case_succeeded);
+  if (instr->truncating()) {
+    if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+      CpuFeatureScope scope(masm(), SSE2);
+      XMMRegister input_reg = ToDoubleRegister(input);
+      __ TruncateDoubleToI(result_reg, input_reg);
     } else {
-      __ cvtsi2sd(xmm0, Operand(result_reg));
-      __ ucomisd(xmm0, input_reg);
-      DeoptimizeIf(not_equal, instr->environment());
-      DeoptimizeIf(parity_even, instr->environment());  // NaN.
-      if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-        // The integer converted back is equal to the original. We
-        // only have to test if we got -0 as an input.
-        __ test(result_reg, Operand(result_reg));
-        __ j(not_zero, &done, Label::kNear);
-        __ movmskpd(result_reg, input_reg);
-        // Bit 0 contains the sign of the double in input_reg.
-        // If input was positive, we are ok and return 0, otherwise
-        // deoptimize.
-        __ and_(result_reg, 1);
-        DeoptimizeIf(not_zero, instr->environment());
-      }
-      __ bind(&done);
+      X87Register input_reg = ToX87Register(input);
+      X87Fxch(input_reg);
+      __ TruncateX87TOSToI(result_reg);
     }
   } else {
-    X87Register input_reg = ToX87Register(input);
-    __ push(result_reg);
-    X87Mov(Operand(esp, 0), input_reg, kX87IntOperand);
-    if (instr->truncating()) {
-      __ pop(result_reg);
+    Label bailout, done;
+    if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+      CpuFeatureScope scope(masm(), SSE2);
+      XMMRegister input_reg = ToDoubleRegister(input);
+       __ DoubleToI(result_reg, input_reg, xmm0,
+           instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
     } else {
+      X87Register input_reg = ToX87Register(input);
       X87Fxch(input_reg);
-      __ fld(0);
-      __ fild_s(Operand(esp, 0));
-      __ pop(result_reg);
-      __ FCmp();
-      DeoptimizeIf(not_equal, instr->environment());
-      DeoptimizeIf(parity_even, instr->environment());  // NaN.
-    }
-    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-      __ test(result_reg, Operand(result_reg));
-      __ j(not_zero, &done, Label::kNear);
-      // To check for minus zero, we load the value again as float, and check
-      // if that is still 0.
-      X87Fxch(input_reg);
-      __ push(result_reg);
-      __ fst_s(Operand(esp, 0));
-      __ pop(result_reg);
-      __ test(result_reg, Operand(result_reg));
-      DeoptimizeIf(not_zero, instr->environment());
-      __ bind(&done);
+      __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(),
+                   &bailout, Label::kNear);
     }
+    __ jmp(&done, Label::kNear);
+    __ bind(&bailout);
+    DeoptimizeIf(no_condition, instr->environment());
+    __ bind(&done);
   }
 }
 
@@ -5715,55 +5456,23 @@ void LCodeGen::DoDoubleToSmi(LDoubleToSmi* instr) {
   ASSERT(result->IsRegister());
   Register result_reg = ToRegister(result);
 
-  Label done;
+  Label bailout, done;
   if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
     CpuFeatureScope scope(masm(), SSE2);
-
     XMMRegister input_reg = ToDoubleRegister(input);
-
-    __ cvttsd2si(result_reg, Operand(input_reg));
-    __ cvtsi2sd(xmm0, Operand(result_reg));
-    __ ucomisd(xmm0, input_reg);
-    DeoptimizeIf(not_equal, instr->environment());
-    DeoptimizeIf(parity_even, instr->environment());  // NaN.
-    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-      // The integer converted back is equal to the original. We
-      // only have to test if we got -0 as an input.
-      __ test(result_reg, Operand(result_reg));
-      __ j(not_zero, &done, Label::kNear);
-      __ movmskpd(result_reg, input_reg);
-      // Bit 0 contains the sign of the double in input_reg.
-      // If input was positive, we are ok and return 0, otherwise
-      // deoptimize.
-      __ and_(result_reg, 1);
-      DeoptimizeIf(not_zero, instr->environment());
-      __ bind(&done);
-    }
+    __ DoubleToI(result_reg, input_reg, xmm0,
+        instr->hydrogen()->GetMinusZeroMode(), &bailout, Label::kNear);
   } else {
     X87Register input_reg = ToX87Register(input);
     X87Fxch(input_reg);
-    __ push(result_reg);
-    X87Mov(Operand(esp, 0), input_reg, kX87IntOperand);
-    __ fld(0);
-    __ fild_s(Operand(esp, 0));
-    __ pop(result_reg);
-    __ FCmp();
-    DeoptimizeIf(not_equal, instr->environment());
-    DeoptimizeIf(parity_even, instr->environment());  // NaN.
-
-    if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
-      __ test(result_reg, Operand(result_reg));
-      __ j(not_zero, &done, Label::kNear);
-      // To check for minus zero, we load the value again as float, and check
-      // if that is still 0.
-      __ push(result_reg);
-      __ fst_s(Operand(esp, 0));
-      __ pop(result_reg);
-      __ test(result_reg, Operand(result_reg));
-      DeoptimizeIf(not_zero, instr->environment());
-      __ bind(&done);
-    }
+    __ X87TOSToI(result_reg, instr->hydrogen()->GetMinusZeroMode(),
+        &bailout, Label::kNear);
   }
+  __ jmp(&done, Label::kNear);
+  __ bind(&bailout);
+  DeoptimizeIf(no_condition, instr->environment());
+  __ bind(&done);
+
   __ SmiTag(result_reg);
   DeoptimizeIf(overflow, instr->environment());
 }
index 37a7ea9..23b2e48 100644 (file)
@@ -163,8 +163,7 @@ class LCodeGen V8_FINAL BASE_EMBEDDED {
                             LOperand* value,
                             IntegerSignedness signedness);
 
-  void DoDeferredTaggedToI(LTaggedToI* instr);
-  void DoDeferredTaggedToINoSSE2(LTaggedToINoSSE2* instr);
+  void DoDeferredTaggedToI(LTaggedToI* instr, Label* done);
   void DoDeferredMathAbsTaggedHeapNumber(LMathAbs* instr);
   void DoDeferredStackCheck(LStackCheck* instr);
   void DoDeferredRandom(LRandom* instr);
@@ -549,6 +548,7 @@ class LDeferredCode : public ZoneObject {
   void SetExit(Label* exit) { external_exit_ = exit; }
   Label* entry() { return &entry_; }
   Label* exit() { return external_exit_ != NULL ? external_exit_ : &exit_; }
+  Label* done() { return &done_; }
   int instruction_index() const { return instruction_index_; }
   const LCodeGen::X87Stack& x87_stack() const { return x87_stack_; }
 
@@ -561,6 +561,7 @@ class LDeferredCode : public ZoneObject {
   Label entry_;
   Label exit_;
   Label* external_exit_;
+  Label done_;
   int instruction_index_;
   LCodeGen::X87Stack x87_stack_;
 };
index e6cc719..8d66085 100644 (file)
@@ -1944,21 +1944,11 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
         return DefineSameAsFirst(new(zone()) LSmiUntag(value, false));
       } else {
         bool truncating = instr->CanTruncateToInt32();
-        if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
-          LOperand* value = UseRegister(val);
-          LOperand* xmm_temp =
-              (truncating && CpuFeatures::IsSupported(SSE3))
-              ? NULL
-              : FixedTemp(xmm1);
-          LTaggedToI* res = new(zone()) LTaggedToI(value, xmm_temp);
-          return AssignEnvironment(DefineSameAsFirst(res));
-        } else {
-          LOperand* value = UseFixed(val, ecx);
-          LTaggedToINoSSE2* res =
-              new(zone()) LTaggedToINoSSE2(value, TempRegister(),
-                                           TempRegister(), TempRegister());
-          return AssignEnvironment(DefineFixed(res, ecx));
-        }
+        LOperand* xmm_temp =
+            (CpuFeatures::IsSafeForSnapshot(SSE2) && !truncating)
+                ? FixedTemp(xmm1) : NULL;
+        LTaggedToI* res = new(zone()) LTaggedToI(UseRegister(val), xmm_temp);
+        return AssignEnvironment(DefineSameAsFirst(res));
       }
     }
   } else if (from.IsDouble()) {
@@ -1978,7 +1968,7 @@ LInstruction* LChunkBuilder::DoChange(HChange* instr) {
     } else {
       ASSERT(to.IsInteger32());
       bool truncating = instr->CanTruncateToInt32();
-      bool needs_temp = truncating && !CpuFeatures::IsSupported(SSE3);
+      bool needs_temp = CpuFeatures::IsSafeForSnapshot(SSE2) && !truncating;
       LOperand* value = needs_temp ?
           UseTempRegister(instr->value()) : UseRegister(instr->value());
       LOperand* temp = needs_temp ? TempRegister() : NULL;
index e795926..8b311b7 100644 (file)
@@ -175,7 +175,6 @@ class LCodeGen;
   V(StringCompareAndBranch)                     \
   V(SubI)                                       \
   V(TaggedToI)                                  \
-  V(TaggedToINoSSE2)                            \
   V(ThisFunction)                               \
   V(Throw)                                      \
   V(ToFastProperties)                           \
@@ -2171,31 +2170,6 @@ class LTaggedToI V8_FINAL : public LTemplateInstruction<1, 1, 1> {
 };
 
 
-// Truncating conversion from a tagged value to an int32.
-class LTaggedToINoSSE2 V8_FINAL : public LTemplateInstruction<1, 1, 3> {
- public:
-  LTaggedToINoSSE2(LOperand* value,
-                   LOperand* temp1,
-                   LOperand* temp2,
-                   LOperand* temp3) {
-    inputs_[0] = value;
-    temps_[0] = temp1;
-    temps_[1] = temp2;
-    temps_[2] = temp3;
-  }
-
-  LOperand* value() { return inputs_[0]; }
-  LOperand* scratch() { return temps_[0]; }
-  LOperand* scratch2() { return temps_[1]; }
-  LOperand* scratch3() { return temps_[2]; }
-
-  DECLARE_CONCRETE_INSTRUCTION(TaggedToINoSSE2, "tagged-to-i-nosse2")
-  DECLARE_HYDROGEN_ACCESSOR(UnaryOperation)
-
-  bool truncating() { return hydrogen()->CanTruncateToInt32(); }
-};
-
-
 class LSmiTag V8_FINAL : public LTemplateInstruction<1, 1, 0> {
  public:
   explicit LSmiTag(LOperand* value) {
index aaacbd9..bd058f8 100644 (file)
@@ -215,6 +215,231 @@ void MacroAssembler::ClampUint8(Register reg) {
 }
 
 
+void MacroAssembler::SlowTruncateToI(Register result_reg,
+                                     Register input_reg,
+                                     int offset) {
+  DoubleToIStub stub(input_reg, result_reg, offset, true);
+  call(stub.GetCode(isolate()), RelocInfo::CODE_TARGET);
+}
+
+
+void MacroAssembler::TruncateDoubleToI(Register result_reg,
+                                       XMMRegister input_reg) {
+  Label done;
+  cvttsd2si(result_reg, Operand(input_reg));
+  cmp(result_reg, 0x80000000u);
+  j(not_equal, &done, Label::kNear);
+
+  sub(esp, Immediate(kDoubleSize));
+  movdbl(MemOperand(esp, 0), input_reg);
+  SlowTruncateToI(result_reg, esp, 0);
+  add(esp, Immediate(kDoubleSize));
+  bind(&done);
+}
+
+
+void MacroAssembler::TruncateX87TOSToI(Register result_reg) {
+  sub(esp, Immediate(kDoubleSize));
+  fst_d(MemOperand(esp, 0));
+  SlowTruncateToI(result_reg, esp, 0);
+  add(esp, Immediate(kDoubleSize));
+}
+
+
+void MacroAssembler::X87TOSToI(Register result_reg,
+                               MinusZeroMode minus_zero_mode,
+                               Label* conversion_failed,
+                               Label::Distance dst) {
+  Label done;
+  sub(esp, Immediate(kPointerSize));
+  fist_s(MemOperand(esp, 0));
+  fld(0);
+  fild_s(MemOperand(esp, 0));
+  pop(result_reg);
+  FCmp();
+  j(not_equal, conversion_failed, dst);
+  j(parity_even, conversion_failed, dst);
+  if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
+    test(result_reg, Operand(result_reg));
+    j(not_zero, &done, Label::kNear);
+    // To check for minus zero, we load the value again as float, and check
+    // if that is still 0.
+    sub(esp, Immediate(kPointerSize));
+    fst_s(MemOperand(esp, 0));
+    pop(result_reg);
+    test(result_reg, Operand(result_reg));
+    j(not_zero, conversion_failed, dst);
+  }
+  bind(&done);
+}
+
+
+void MacroAssembler::DoubleToI(Register result_reg,
+                               XMMRegister input_reg,
+                               XMMRegister scratch,
+                               MinusZeroMode minus_zero_mode,
+                               Label* conversion_failed,
+                               Label::Distance dst) {
+  ASSERT(!input_reg.is(scratch));
+  Label done;
+  cvttsd2si(result_reg, Operand(input_reg));
+  cvtsi2sd(scratch, Operand(result_reg));
+  ucomisd(scratch, input_reg);
+  j(not_equal, conversion_failed, dst);
+  j(parity_even, conversion_failed, dst);  // NaN.
+  if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
+    test(result_reg, Operand(result_reg));
+    j(not_zero, &done, Label::kNear);
+    movmskpd(result_reg, input_reg);
+    and_(result_reg, 1);
+    j(not_zero, conversion_failed, dst);
+  }
+  bind(&done);
+}
+
+
+void MacroAssembler::TruncateHeapNumberToI(Register result_reg,
+                                           Register input_reg) {
+  Label done, slow_case;
+
+  if (CpuFeatures::IsSupported(SSE3)) {
+    CpuFeatureScope scope(this, SSE3);
+    Label convert;
+    // Use more powerful conversion when sse3 is available.
+    // Load x87 register with heap number.
+    fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
+    // Get exponent alone and check for too-big exponent.
+    mov(result_reg, FieldOperand(input_reg, HeapNumber::kExponentOffset));
+    and_(result_reg, HeapNumber::kExponentMask);
+    const uint32_t kTooBigExponent =
+        (HeapNumber::kExponentBias + 63) << HeapNumber::kExponentShift;
+    cmp(Operand(result_reg), Immediate(kTooBigExponent));
+    j(greater_equal, &slow_case, Label::kNear);
+
+    // Reserve space for 64 bit answer.
+    sub(Operand(esp), Immediate(kDoubleSize));
+    // Do conversion, which cannot fail because we checked the exponent.
+    fisttp_d(Operand(esp, 0));
+    mov(result_reg, Operand(esp, 0));  // Low word of answer is the result.
+    add(Operand(esp), Immediate(kDoubleSize));
+    jmp(&done, Label::kNear);
+
+    // Slow case.
+    bind(&slow_case);
+    if (input_reg.is(result_reg)) {
+      // Input is clobbered. Restore number from fpu stack
+      sub(Operand(esp), Immediate(kDoubleSize));
+      fstp_d(Operand(esp, 0));
+      SlowTruncateToI(result_reg, esp, 0);
+      add(esp, Immediate(kDoubleSize));
+    } else {
+      fstp(0);
+      SlowTruncateToI(result_reg, input_reg);
+    }
+  } else if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatureScope scope(this, SSE2);
+    movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
+    cvttsd2si(result_reg, Operand(xmm0));
+    cmp(result_reg, 0x80000000u);
+    j(not_equal, &done, Label::kNear);
+    // Check if the input was 0x8000000 (kMinInt).
+    // If no, then we got an overflow and we deoptimize.
+    ExternalReference min_int = ExternalReference::address_of_min_int();
+    ucomisd(xmm0, Operand::StaticVariable(min_int));
+    j(not_equal, &slow_case, Label::kNear);
+    j(parity_even, &slow_case, Label::kNear);  // NaN.
+    jmp(&done, Label::kNear);
+
+    // Slow case.
+    bind(&slow_case);
+    if (input_reg.is(result_reg)) {
+      // Input is clobbered. Restore number from double scratch.
+      sub(esp, Immediate(kDoubleSize));
+      movdbl(MemOperand(esp, 0), xmm0);
+      SlowTruncateToI(result_reg, esp, 0);
+      add(esp, Immediate(kDoubleSize));
+    } else {
+      SlowTruncateToI(result_reg, input_reg);
+    }
+  } else {
+    SlowTruncateToI(result_reg, input_reg);
+  }
+  bind(&done);
+}
+
+
+void MacroAssembler::TaggedToI(Register result_reg,
+                               Register input_reg,
+                               XMMRegister temp,
+                               MinusZeroMode minus_zero_mode,
+                               Label* lost_precision) {
+  Label done;
+  ASSERT(!temp.is(xmm0));
+
+  cmp(FieldOperand(input_reg, HeapObject::kMapOffset),
+      isolate()->factory()->heap_number_map());
+  j(not_equal, lost_precision, Label::kNear);
+
+  if (CpuFeatures::IsSafeForSnapshot(SSE2)) {
+    ASSERT(!temp.is(no_xmm_reg));
+    CpuFeatureScope scope(this, SSE2);
+
+    movdbl(xmm0, FieldOperand(input_reg, HeapNumber::kValueOffset));
+    cvttsd2si(result_reg, Operand(xmm0));
+    cvtsi2sd(temp, Operand(result_reg));
+    ucomisd(xmm0, temp);
+    RecordComment("Deferred TaggedToI: lost precision");
+    j(not_equal, lost_precision, Label::kNear);
+    RecordComment("Deferred TaggedToI: NaN");
+    j(parity_even, lost_precision, Label::kNear);
+    if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
+      test(result_reg, Operand(result_reg));
+      j(not_zero, &done, Label::kNear);
+      movmskpd(result_reg, xmm0);
+      and_(result_reg, 1);
+      RecordComment("Deferred TaggedToI: minus zero");
+      j(not_zero, lost_precision, Label::kNear);
+    }
+  } else {
+    // TODO(olivf) Converting a number on the fpu is actually quite slow. We
+    // should first try a fast conversion and then bailout to this slow case.
+    Label lost_precision_pop, zero_check;
+    Label* lost_precision_int = (minus_zero_mode == FAIL_ON_MINUS_ZERO)
+        ? &lost_precision_pop : lost_precision;
+    sub(esp, Immediate(kPointerSize));
+    fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset));
+    if (minus_zero_mode == FAIL_ON_MINUS_ZERO) fld(0);
+    fist_s(MemOperand(esp, 0));
+    fild_s(MemOperand(esp, 0));
+    FCmp();
+    pop(result_reg);
+    j(not_equal, lost_precision_int, Label::kNear);
+    j(parity_even, lost_precision_int, Label::kNear);  // NaN.
+    if (minus_zero_mode == FAIL_ON_MINUS_ZERO) {
+      test(result_reg, Operand(result_reg));
+      j(zero, &zero_check, Label::kNear);
+      fstp(0);
+      jmp(&done, Label::kNear);
+      bind(&zero_check);
+      // To check for minus zero, we load the value again as float, and check
+      // if that is still 0.
+      sub(esp, Immediate(kPointerSize));
+      fstp_s(Operand(esp, 0));
+      pop(result_reg);
+      test(result_reg, Operand(result_reg));
+      j(zero, &done, Label::kNear);
+      jmp(lost_precision, Label::kNear);
+
+      bind(&lost_precision_pop);
+      fstp(0);
+      jmp(lost_precision, Label::kNear);
+    }
+  }
+  bind(&done);
+}
+
+
+
 static double kUint32Bias =
     static_cast<double>(static_cast<uint32_t>(0xFFFFFFFF)) + 1;
 
index 4d9ebad..e4e4533 100644 (file)
@@ -474,6 +474,21 @@ class MacroAssembler: public Assembler {
                           XMMRegister scratch_reg,
                           Register result_reg);
 
+  void SlowTruncateToI(Register result_reg, Register input_reg,
+      int offset = HeapNumber::kValueOffset - kHeapObjectTag);
+
+  void TruncateHeapNumberToI(Register result_reg, Register input_reg);
+  void TruncateDoubleToI(Register result_reg, XMMRegister input_reg);
+  void TruncateX87TOSToI(Register result_reg);
+
+  void DoubleToI(Register result_reg, XMMRegister input_reg,
+      XMMRegister scratch, MinusZeroMode minus_zero_mode,
+      Label* conversion_failed, Label::Distance dst = Label::kFar);
+  void X87TOSToI(Register result_reg, MinusZeroMode minus_zero_mode,
+      Label* conversion_failed, Label::Distance dst = Label::kFar);
+
+  void TaggedToI(Register result_reg, Register input_reg, XMMRegister temp,
+      MinusZeroMode minus_zero_mode, Label* lost_precision);
 
   // Smi tagging support.
   void SmiTag(Register reg) {
index 745fccb..7fa2fd6 100644 (file)
@@ -565,6 +565,11 @@ enum ClearExceptionFlag {
 };
 
 
+enum MinusZeroMode {
+  TREAT_MINUS_ZERO_AS_ZERO,
+  FAIL_ON_MINUS_ZERO
+};
+
 } }  // namespace v8::internal
 
 #endif  // V8_V8GLOBALS_H_
index 11e61ba..575a8b5 100644 (file)
@@ -679,3 +679,37 @@ boo(built_in_array, 0, 2.5);
 assertEquals(2.5, goo(built_in_array, 0));
 %ClearFunctionTypeFeedback(goo);
 %ClearFunctionTypeFeedback(boo);
+
+// Check all int range edge cases
+function checkRange() {
+  var e32 = Math.pow(2,32); var e31 = Math.pow(2,31);
+  var e16 = Math.pow(2,16); var e15 = Math.pow(2,15);
+  var e8 = Math.pow(2,8);   var e7 = Math.pow(2,7);
+  var a7 = new Uint32Array(2);  var a71 = new Int32Array(2);
+  var a72 = new Uint16Array(2); var a73 = new Int16Array(2);
+  var a74 = new Uint8Array(2);  var a75 = new Int8Array(2);
+  for (i = 1; i <= Math.pow(2,33); i *= 2) {
+    var j = i-1;
+    a7[0] = i; a71[0] = i; a72[0] = i; a73[0] = i; a74[0] = i; a75[0] = i;
+    a7[1] = j; a71[1] = j; a72[1] = j; a73[1] = j; a74[1] = j; a75[1] = j;
+
+    if (i < e32) { assertEquals(a7[0], i); } else { assertEquals(a7[0], 0); }
+    if (j < e32) { assertEquals(a7[1], j); } else { assertEquals(a7[1],e32-1); }
+    if (i < e31) { assertEquals(a71[0], i); } else {
+      assertEquals(a71[0], (i < e32) ? -e31 : 0 ); }
+    if (j < e31) { assertEquals(a71[1], j); } else { assertEquals(a71[1], -1); }
+
+    if (i < e16) { assertEquals(a72[0], i); } else { assertEquals(a72[0], 0); }
+    if (j < e16) { assertEquals(a72[1], j); } else { assertEquals(a72[1], e16-1); }
+    if (i < e15) { assertEquals(a73[0], i); } else {
+      assertEquals(a73[0], (i < e16) ? -e15 : 0 ); }
+    if (j < e15) { assertEquals(a73[1], j); } else { assertEquals(a73[1], -1); }
+
+    if (i < e8) { assertEquals(a74[0], i); } else { assertEquals(a74[0], 0); }
+    if (j < e8) { assertEquals(a74[1], j); } else { assertEquals(a74[1], e8-1); }
+    if (i < e7) { assertEquals(a75[0], i); } else {
+      assertEquals(a75[0], (i < e8) ? -e7 : 0); }
+    if (j < e7) { assertEquals(a75[1], j); } else { assertEquals(a75[1], -1); }
+  }
+}
+checkRange();
index 3fcd544..ab5435e 100644 (file)
@@ -678,3 +678,37 @@ boo(built_in_array, 0, 2.5);
 assertEquals(2.5, goo(built_in_array, 0));
 %ClearFunctionTypeFeedback(goo);
 %ClearFunctionTypeFeedback(boo);
+
+// Check all int range edge cases
+function checkRange() {
+  var e32 = Math.pow(2,32); var e31 = Math.pow(2,31);
+  var e16 = Math.pow(2,16); var e15 = Math.pow(2,15);
+  var e8 = Math.pow(2,8);   var e7 = Math.pow(2,7);
+  var a7 = new Uint32Array(2);  var a71 = new Int32Array(2);
+  var a72 = new Uint16Array(2); var a73 = new Int16Array(2);
+  var a74 = new Uint8Array(2);  var a75 = new Int8Array(2);
+  for (i = 1; i <= Math.pow(2,33); i *= 2) {
+    var j = i-1;
+    a7[0] = i; a71[0] = i; a72[0] = i; a73[0] = i; a74[0] = i; a75[0] = i;
+    a7[1] = j; a71[1] = j; a72[1] = j; a73[1] = j; a74[1] = j; a75[1] = j;
+
+    if (i < e32) { assertEquals(a7[0], i); } else { assertEquals(a7[0], 0); }
+    if (j < e32) { assertEquals(a7[1], j); } else { assertEquals(a7[1],e32-1); }
+    if (i < e31) { assertEquals(a71[0], i); } else {
+      assertEquals(a71[0], (i < e32) ? -e31 : 0 ); }
+    if (j < e31) { assertEquals(a71[1], j); } else { assertEquals(a71[1], -1); }
+
+    if (i < e16) { assertEquals(a72[0], i); } else { assertEquals(a72[0], 0); }
+    if (j < e16) { assertEquals(a72[1], j); } else { assertEquals(a72[1], e16-1); }
+    if (i < e15) { assertEquals(a73[0], i); } else {
+      assertEquals(a73[0], (i < e16) ? -e15 : 0 ); }
+    if (j < e15) { assertEquals(a73[1], j); } else { assertEquals(a73[1], -1); }
+
+    if (i < e8) { assertEquals(a74[0], i); } else { assertEquals(a74[0], 0); }
+    if (j < e8) { assertEquals(a74[1], j); } else { assertEquals(a74[1], e8-1); }
+    if (i < e7) { assertEquals(a75[0], i); } else {
+      assertEquals(a75[0], (i < e8) ? -e7 : 0); }
+    if (j < e7) { assertEquals(a75[1], j); } else { assertEquals(a75[1], -1); }
+  }
+}
+checkRange();