Index: src/ia32/lithium-codegen-ia32.cc |
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc |
index 9569ac8b8099f628e410c09e0e00e2741e5feaa3..7eba99e8e0a4410dc778d9956c629d5537ed8641 100644 |
--- a/src/ia32/lithium-codegen-ia32.cc |
+++ b/src/ia32/lithium-codegen-ia32.cc |
@@ -2885,9 +2885,62 @@ void LCodeGen::DoDoubleToI(LDoubleToI* instr) { |
__ add(Operand(esp), Immediate(kDoubleSize)); |
__ bind(&done); |
} else { |
- // This will bail out if the input was not in the int32 range (or, |
- // unfortunately, if the input was 0x80000000). |
- DeoptimizeIf(equal, instr->environment()); |
+ NearLabel done; |
+ Register temp_reg = ToRegister(instr->temporary()); |
+ XMMRegister xmm_scratch = xmm0; |
+ |
+ // If cvttsd2si succeeded, we're done. Otherwise, we attempt |
+ // manual conversion. |
+ __ j(not_equal, &done); |
+ |
+ // Get high 32 bits of the input in temp_reg. |
+ __ pshufd(xmm_scratch, input_reg, 1); |
+ __ movd(Operand(temp_reg), xmm_scratch); |
+ |
+ // Zero out the sign and the exponent in the input (by shifting |
+ // it to the left) and restore the implicit mantissa bit, |
+ // i.e. convert the input to unsigned int64 shifted left by |
+ // kExponentBits. |
+ ExternalReference minus_zero = ExternalReference::address_of_minus_zero(); |
+ // Minus zero has the most significant bit set and the other |
+ // bits cleared. |
+ __ movdbl(xmm_scratch, Operand::StaticVariable(minus_zero)); |
+ __ psllq(input_reg, HeapNumber::kExponentBits); |
+ __ por(input_reg, xmm_scratch); |
+ |
+ // Save high 32 bits of the input in result_reg. |
+ __ mov(result_reg, temp_reg); |
+ |
+ // Prepare negation mask in temp_reg. |
+ __ sar(temp_reg, kBitsPerInt - 1); |
+ |
+ // Extract the exponent from result_reg and subtract adjusted |
+ // bias from it. The adjustment is selected in a way such that |
+ // when the difference is zero, the answer is in the low 32 bits |
+ // of the input, otherwise a shift has to be performed. |
+ __ shr(result_reg, HeapNumber::kExponentShift); |
+ __ and_(result_reg, |
+ HeapNumber::kExponentMask >> HeapNumber::kExponentShift); |
+ __ sub(Operand(result_reg), |
+ Immediate(HeapNumber::kExponentBias + |
+ HeapNumber::kExponentBits + |
+ HeapNumber::kMantissaBits)); |
+ // Don't handle big (> kMantissaBits + kExponentBits == 63) or |
+ // special exponents. |
+ DeoptimizeIf(greater, instr->environment()); |
+ |
+ // Get the amount to shift the input right in xmm_scratch. |
+ __ neg(result_reg); |
+ __ movd(xmm_scratch, Operand(result_reg)); |
+ |
+ // Shift the input right and extract low 32 bits. |
+ __ psrlq(input_reg, xmm_scratch); |
+ __ movd(Operand(result_reg), input_reg); |
+ |
+ // Use the prepared mask in temp_reg to negate the result if necessary. |
+ __ xor_(result_reg, Operand(temp_reg)); |
+ __ sub(result_reg, Operand(temp_reg)); |
+ __ bind(&done); |
} |
} else { |
NearLabel done; |