Index: src/arm/lithium-codegen-arm.cc |
=================================================================== |
--- src/arm/lithium-codegen-arm.cc (revision 6620) |
+++ src/arm/lithium-codegen-arm.cc (working copy) |
@@ -2666,34 +2666,53 @@ |
} |
-void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { |
- DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); |
- Register result = ToRegister(instr->result()); |
- Register prev_fpscr = ToRegister(instr->TempAt(0)); |
- SwVfpRegister single_scratch = double_scratch0().low(); |
- Register scratch = scratch0(); |
+// Truncates a double using a specific rounding mode. |
+// Clears the z flag (ne condition) if an overflow occurs. |
+void LCodeGen::EmitVFPTruncate(VFPRoundingMode rounding_mode, |
+ SwVfpRegister result, |
+ DwVfpRegister double_input, |
+ Register scratch1, |
+ Register scratch2) { |
+ Register prev_fpscr = scratch1; |
+ Register scratch = scratch2; |
// Set custom FPCSR: |
- // - Set rounding mode to "Round towards Minus Infinity". |
+ // - Set rounding mode. |
// - Clear vfp cumulative exception flags. |
// - Make sure Flush-to-zero mode control bit is unset. |
__ vmrs(prev_fpscr); |
- __ bic(scratch, prev_fpscr, |
- Operand(kVFPExceptionMask | kVFPRoundingModeMask | kVFPFlushToZeroMask)); |
- __ orr(scratch, scratch, Operand(kVFPRoundToMinusInfinityBits)); |
+ __ bic(scratch, prev_fpscr, Operand(kVFPExceptionMask | |
+ kVFPRoundingModeMask | |
+ kVFPFlushToZeroMask)); |
+ __ orr(scratch, scratch, Operand(rounding_mode)); |
__ vmsr(scratch); |
// Convert the argument to an integer. |
- __ vcvt_s32_f64(single_scratch, |
- input, |
- Assembler::FPSCRRounding, |
- al); |
+ __ vcvt_s32_f64(result, |
+ double_input, |
+ kFPSCRRounding); |
- // Retrieve FPSCR and check for vfp exceptions. |
+ // Retrieve FPSCR. |
__ vmrs(scratch); |
- // Restore FPSCR |
+ // Restore FPSCR. |
__ vmsr(prev_fpscr); |
+ // Check for vfp exceptions. |
__ tst(scratch, Operand(kVFPExceptionMask)); |
+} |
+ |
+ |
+void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) { |
+ DoubleRegister input = ToDoubleRegister(instr->InputAt(0)); |
+ Register result = ToRegister(instr->result()); |
+ SwVfpRegister single_scratch = double_scratch0().low(); |
+ Register scratch1 = scratch0(); |
+ Register scratch2 = ToRegister(instr->TempAt(0)); |
+ |
+ EmitVFPTruncate(kRoundToMinusInf, |
+ single_scratch, |
+ input, |
+ scratch1, |
+ scratch2); |
DeoptimizeIf(ne, instr->environment()); |
// Move the result back to general purpose register r0. |
@@ -2703,8 +2722,8 @@ |
Label done; |
__ cmp(result, Operand(0)); |
__ b(ne, &done); |
- __ vmov(scratch, input.high()); |
- __ tst(scratch, Operand(HeapNumber::kSignMask)); |
+ __ vmov(scratch1, input.high()); |
+ __ tst(scratch1, Operand(HeapNumber::kSignMask)); |
DeoptimizeIf(ne, instr->environment()); |
__ bind(&done); |
} |
@@ -3338,7 +3357,43 @@ |
void LCodeGen::DoDoubleToI(LDoubleToI* instr) { |
- Abort("DoDoubleToI unimplemented."); |
+ LOperand* input = instr->InputAt(0); |
+ ASSERT(input->IsDoubleRegister()); |
+ LOperand* result = instr->result(); |
+ ASSERT(result->IsRegister()); |
+ |
+ DoubleRegister double_input = ToDoubleRegister(input); |
+ Register result_reg = ToRegister(result); |
+ SwVfpRegister single_scratch = double_scratch0().low(); |
+ Register scratch1 = scratch0(); |
+ Register scratch2 = ToRegister(instr->TempAt(0)); |
+ |
+ VFPRoundingMode rounding_mode = instr->truncating() ? kRoundToMinusInf |
+ : kRoundToNearest; |
+ |
+ |
+ EmitVFPTruncate(rounding_mode, |
+ single_scratch, |
+ double_input, |
+ scratch1, |
+ scratch2); |
+ // Deoptimize if we had a vfp invalid exception. |
+ DeoptimizeIf(ne, instr->environment()); |
+ // Retrieve the result. |
+ __ vmov(result_reg, single_scratch); |
+ |
+ if (instr->truncating() && |
+ instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) { |
+ Label done; |
+ __ cmp(result_reg, Operand(0)); |
+ __ b(ne, &done); |
+ // Check for -0. |
+ __ vmov(scratch1, double_input.high()); |
+ __ tst(scratch1, Operand(HeapNumber::kSignMask)); |
+ DeoptimizeIf(ne, instr->environment()); |
+ |
+ __ bind(&done); |
+ } |
} |