Chromium Code Reviews| Index: src/ia32/macro-assembler-ia32.cc |
| diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc |
| index f86820cba6469876d73c63c397cb72c1ea0ed448..3bd95f916ed344e109a38e80385940b92fcb7eb8 100644 |
| --- a/src/ia32/macro-assembler-ia32.cc |
| +++ b/src/ia32/macro-assembler-ia32.cc |
| @@ -215,6 +215,224 @@ void MacroAssembler::ClampUint8(Register reg) { |
| } |
| +void MacroAssembler::SlowTruncateToI(Register input_reg, Register result_reg, |
| + int index) { |
| + DoubleToIStub stub(input_reg, result_reg, index, true); |
| + call(stub.GetCode(isolate()), RelocInfo::CODE_TARGET); |
| +} |
| + |
| + |
| +void MacroAssembler::TruncateDoubleToI( |
| + XMMRegister input_reg, Register result_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(esp, result_reg, 0); |
| + add(esp, Immediate(kDoubleSize)); |
| + bind(&done); |
| +} |
| + |
| + |
| +void MacroAssembler::TruncateX87TOSToI(Register result_reg) { |
| + sub(esp, Immediate(kDoubleSize)); |
| + fst_d(MemOperand(esp, 0)); |
| + SlowTruncateToI(esp, result_reg, 0); |
| + add(esp, Immediate(kDoubleSize)); |
| +} |
| + |
| + |
| +void MacroAssembler::X87TOSToI(Register result_reg, |
| + bool treat_minus_zero_as_zero, |
| + 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 (!treat_minus_zero_as_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(XMMRegister input_reg, Register result_reg, |
| + XMMRegister scratch, bool treat_minus_zero_as_zero, |
| + 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 (!treat_minus_zero_as_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 input_reg, |
| + Register result_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(esp, result_reg, 0); |
| + add(esp, Immediate(kDoubleSize)); |
| + } else { |
| + fstp(0); |
| + SlowTruncateToI(input_reg, result_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(esp, result_reg, 0); |
| + add(esp, Immediate(kDoubleSize)); |
| + } else { |
| + SlowTruncateToI(input_reg, result_reg); |
| + } |
| + } else { |
| + SlowTruncateToI(input_reg, result_reg); |
| + } |
| + bind(&done); |
| +} |
| + |
| + |
| +void MacroAssembler::TaggedToI(Register input_reg, Register result_reg, |
| + XMMRegister temp, bool treat_minus_zero_as_zero, 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 (!treat_minus_zero_as_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; |
| + sub(esp, Immediate(kPointerSize)); |
| + fld_d(FieldOperand(input_reg, HeapNumber::kValueOffset)); |
| + if (!treat_minus_zero_as_zero) fld(0); |
| + fist_s(MemOperand(esp, 0)); |
| + fild_s(MemOperand(esp, 0)); |
| + FCmp(); |
| + pop(result_reg); |
| + j(not_equal, !treat_minus_zero_as_zero |
|
danno
2013/08/20 16:14:28
nit: Factor this label decision out into a variabl
oliv
2013/08/20 16:56:23
Done.
|
| + ? &lost_precision_pop : lost_precision, Label::kNear); |
| + j(parity_even, !treat_minus_zero_as_zero |
| + ? &lost_precision_pop : lost_precision, Label::kNear); // NaN. |
| + if (!treat_minus_zero_as_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; |