Revision: 8173
Author:   [email protected]
Date:     Mon Jun  6 01:43:15 2011
Log: MIPS: Fixed FPU rounding checks and related errors in the Simulator.

Removed some unnecessary shifts when reading FCSR error flags.
Fixed some FCSR-related bugs.
Fixed some un-related style issues.

With this commit, mips build is still broken. Two more commits to come.

BUG=
TEST=

Review URL: http://codereview.chromium.org/6993054
Patch from Paul Lind <[email protected]>.
http://code.google.com/p/v8/source/detail?r=8173

Modified:
 /branches/bleeding_edge/src/mips/code-stubs-mips.cc
 /branches/bleeding_edge/src/mips/constants-mips.h
 /branches/bleeding_edge/src/mips/macro-assembler-mips.cc
 /branches/bleeding_edge/src/mips/simulator-mips.cc
 /branches/bleeding_edge/src/mips/stub-cache-mips.cc
 /branches/bleeding_edge/test/cctest/test-assembler-mips.cc

=======================================
--- /branches/bleeding_edge/src/mips/code-stubs-mips.cc Wed Jun 1 02:01:57 2011 +++ /branches/bleeding_edge/src/mips/code-stubs-mips.cc Mon Jun 6 01:43:15 2011
@@ -672,9 +672,8 @@
     // Restore FCSR.
     __ ctc1(scratch1, FCSR);

-    // Check for inexact conversion.
-    __ srl(scratch2, scratch2, kFCSRFlagShift);
-    __ And(scratch2, scratch2, (kFCSRFlagMask | kFCSRInexactFlagBit));
+    // Check for inexact conversion or exception.
+    __ And(scratch2, scratch2, kFCSRFlagMask);

     // Jump to not_int32 if the operation did not succeed.
     __ Branch(not_int32, ne, scratch2, Operand(zero_reg));
@@ -757,9 +756,8 @@
     // Restore FCSR.
     __ ctc1(scratch1, FCSR);

-    // Check for inexact conversion.
-    __ srl(scratch2, scratch2, kFCSRFlagShift);
-    __ And(scratch2, scratch2, (kFCSRFlagMask | kFCSRInexactFlagBit));
+    // Check for inexact conversion or exception.
+    __ And(scratch2, scratch2, kFCSRFlagMask);

     // Jump to not_int32 if the operation did not succeed.
     __ Branch(not_int32, ne, scratch2, Operand(zero_reg));
@@ -1965,6 +1963,7 @@
   __ bind(&slow);
   GenerateTypeTransition(masm);
 }
+

 void UnaryOpStub::GenerateHeapNumberCodeSub(MacroAssembler* masm,
                                             Label* slow) {
@@ -2777,8 +2776,7 @@
           // Restore FCSR.
           __ ctc1(scratch1, FCSR);

-          // Check for inexact conversion.
-          __ srl(scratch2, scratch2, kFCSRFlagShift);
+          // Check for inexact conversion or exception.
           __ And(scratch2, scratch2, kFCSRFlagMask);

           if (result_type_ <= BinaryOpIC::INT32) {
@@ -6373,6 +6371,7 @@
   __ pop(a1);
   __ Jump(a2);
 }
+

 void DirectCEntryStub::Generate(MacroAssembler* masm) {
   // No need to pop or drop anything, LeaveExitFrame will restore the old
@@ -6397,6 +6396,7 @@
   __ li(t9, Operand(function));
   this->GenerateCall(masm, t9);
 }
+

 void DirectCEntryStub::GenerateCall(MacroAssembler* masm,
                                     Register target) {
=======================================
--- /branches/bleeding_edge/src/mips/constants-mips.h Thu May 26 00:46:18 2011 +++ /branches/bleeding_edge/src/mips/constants-mips.h Mon Jun 6 01:43:15 2011
@@ -1,4 +1,4 @@
-// Copyright 2010 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
@@ -93,13 +93,27 @@
 static const uint32_t kFPUInvalidResult = (uint32_t) (1 << 31) - 1;

 // FCSR constants.
-static const uint32_t kFCSRFlagMask = (1 << 6) - 1;
-static const uint32_t kFCSRFlagShift = 2;
-static const uint32_t kFCSRInexactFlagBit = 1 << 0;
-static const uint32_t kFCSRUnderflowFlagBit = 1 << 1;
-static const uint32_t kFCSROverflowFlagBit = 1 << 2;
-static const uint32_t kFCSRDivideByZeroFlagBit = 1 << 3;
-static const uint32_t kFCSRInvalidOpFlagBit = 1 << 4;
+static const uint32_t kFCSRInexactFlagBit = 2;
+static const uint32_t kFCSRUnderflowFlagBit = 3;
+static const uint32_t kFCSROverflowFlagBit = 4;
+static const uint32_t kFCSRDivideByZeroFlagBit = 5;
+static const uint32_t kFCSRInvalidOpFlagBit = 6;
+
+static const uint32_t kFCSRInexactFlagMask = 1 << kFCSRInexactFlagBit;
+static const uint32_t kFCSRUnderflowFlagMask = 1 << kFCSRUnderflowFlagBit;
+static const uint32_t kFCSROverflowFlagMask = 1 << kFCSROverflowFlagBit;
+static const uint32_t kFCSRDivideByZeroFlagMask = 1 << kFCSRDivideByZeroFlagBit;
+static const uint32_t kFCSRInvalidOpFlagMask = 1 << kFCSRInvalidOpFlagBit;
+
+static const uint32_t kFCSRFlagMask =
+    kFCSRInexactFlagMask |
+    kFCSRUnderflowFlagMask |
+    kFCSROverflowFlagMask |
+    kFCSRDivideByZeroFlagMask |
+    kFCSRInvalidOpFlagMask;
+
+static const uint32_t kFCSRExceptionFlagMask =
+    kFCSRFlagMask ^ kFCSRInexactFlagMask;

 // Helper functions for converting between register numbers and names.
 class Registers {
@@ -748,4 +762,3 @@
 } }   // namespace v8::internal

 #endif    // #ifndef V8_MIPS_CONSTANTS_H_
-
=======================================
--- /branches/bleeding_edge/src/mips/macro-assembler-mips.cc Wed Jun 1 02:01:57 2011 +++ /branches/bleeding_edge/src/mips/macro-assembler-mips.cc Mon Jun 6 01:43:15 2011
@@ -192,6 +192,7 @@
   or_(scratch, scratch, at);
   sw(scratch, MemOperand(object, Page::kDirtyFlagOffset));
 }
+

 // Push and pop all registers that can hold pointers.
 void MacroAssembler::PushSafepointRegisters() {
@@ -202,12 +203,14 @@
   Subu(sp, sp, Operand(num_unsaved * kPointerSize));
   MultiPush(kSafepointSavedRegisters);
 }
+

 void MacroAssembler::PopSafepointRegisters() {
const int num_unsaved = kNumSafepointRegisters - kNumSafepointSavedRegisters;
   MultiPop(kSafepointSavedRegisters);
   Addu(sp, sp, Operand(num_unsaved * kPointerSize));
 }
+

 void MacroAssembler::PushSafepointRegistersAndDoubles() {
   PushSafepointRegisters();
@@ -217,6 +220,7 @@
     sdc1(reg, MemOperand(sp, i * kDoubleSize));
   }
 }
+

 void MacroAssembler::PopSafepointRegistersAndDoubles() {
   for (int i = 0; i < FPURegister::kNumAllocatableRegisters; i+=2) {
@@ -226,6 +230,7 @@
Addu(sp, sp, Operand(FPURegister::kNumAllocatableRegisters * kDoubleSize));
   PopSafepointRegisters();
 }
+

 void MacroAssembler::StoreToSafepointRegistersAndDoublesSlot(Register src,
Register dst) {
@@ -3025,13 +3030,13 @@
Call(Handle<Code>(Code::cast(result)), RelocInfo::CODE_TARGET, cond, r1, r2);
   return result;
 }
-


 void MacroAssembler::TailCallStub(CodeStub* stub) {
   ASSERT(allow_stub_calls());  // Stub calls are not allowed in some stubs.
   Jump(stub->GetCode(), RelocInfo::CODE_TARGET);
 }
+

 MaybeObject* MacroAssembler::TryTailCallStub(CodeStub* stub,
                                              Condition cond,
@@ -3352,6 +3357,7 @@
   li(a0, Operand(num_arguments));
   JumpToExternalReference(ext);
 }
+

 MaybeObject* MacroAssembler::TryTailCallExternalReference(
     const ExternalReference& ext, int num_arguments, int result_size) {
@@ -3757,6 +3763,7 @@
   return FLAG_sim_stack_alignment;
 #endif  // defined(V8_HOST_ARCH_MIPS)
 }
+

 void MacroAssembler::AssertStackIsAligned() {
   if (emit_debug_code()) {
=======================================
--- /branches/bleeding_edge/src/mips/simulator-mips.cc Thu May 26 00:46:18 2011 +++ /branches/bleeding_edge/src/mips/simulator-mips.cc Mon Jun 6 01:43:15 2011
@@ -1159,15 +1159,30 @@
// Sets the rounding error codes in FCSR based on the result of the rounding.
 // Returns true if the operation was invalid.
 bool Simulator::set_fcsr_round_error(double original, double rounded) {
-  if (!isfinite(original) ||
-      rounded > LONG_MAX ||
-      rounded < LONG_MIN) {
-    set_fcsr_bit(6, true);  // Invalid operation.
-    return true;
-  } else if (original != static_cast<double>(rounded)) {
-    set_fcsr_bit(2, true);  // Inexact.
-  }
-  return false;
+  bool ret = false;
+
+  if (!isfinite(original) || !isfinite(rounded)) {
+    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
+    ret = true;
+  }
+
+  if (original != rounded) {
+    set_fcsr_bit(kFCSRInexactFlagBit, true);
+  }
+
+  if (rounded < DBL_MIN && rounded > -DBL_MIN && rounded != 0) {
+    set_fcsr_bit(kFCSRUnderflowFlagBit, true);
+    ret = true;
+  }
+
+  if (rounded > INT_MAX || rounded < INT_MIN) {
+    set_fcsr_bit(kFCSROverflowFlagBit, true);
+    // The reference is not really clear but it seems this is required:
+    set_fcsr_bit(kFCSRInvalidOpFlagBit, true);
+    ret = true;
+  }
+
+  return ret;
 }


@@ -2054,9 +2069,10 @@
               break;
             case TRUNC_W_D:  // Truncate double to word (round towards 0).
               {
-                int32_t result = static_cast<int32_t>(fs);
+                double rounded = trunc(fs);
+                int32_t result = static_cast<int32_t>(rounded);
                 set_fpu_register(fd_reg, result);
- if (set_fcsr_round_error(fs, static_cast<double>(result))) {
+                if (set_fcsr_round_error(fs, rounded)) {
                   set_fpu_register(fd_reg, kFPUInvalidResult);
                 }
               }
@@ -2084,16 +2100,20 @@
             case CVT_S_D:  // Convert double to float (single).
               set_fpu_register_float(fd_reg, static_cast<float>(fs));
               break;
- case CVT_L_D: // Mips32r2: Truncate double to 64-bit long-word.
-              i64 = static_cast<int64_t>(fs);
+ case CVT_L_D: { // Mips32r2: Truncate double to 64-bit long-word.
+              double rounded = trunc(fs);
+              i64 = static_cast<int64_t>(rounded);
               set_fpu_register(fd_reg, i64 & 0xffffffff);
               set_fpu_register(fd_reg + 1, i64 >> 32);
               break;
-            case TRUNC_L_D:  // Mips32r2 instruction.
-              i64 = static_cast<int64_t>(fs);
+            }
+            case TRUNC_L_D: {  // Mips32r2 instruction.
+              double rounded = trunc(fs);
+              i64 = static_cast<int64_t>(rounded);
               set_fpu_register(fd_reg, i64 & 0xffffffff);
               set_fpu_register(fd_reg + 1, i64 >> 32);
               break;
+            }
             case ROUND_L_D: {  // Mips32r2 instruction.
               double rounded = fs > 0 ? floor(fs + 0.5) : ceil(fs - 0.5);
               i64 = static_cast<int64_t>(rounded);
=======================================
--- /branches/bleeding_edge/src/mips/stub-cache-mips.cc Wed Jun 1 02:01:57 2011 +++ /branches/bleeding_edge/src/mips/stub-cache-mips.cc Mon Jun 6 01:43:15 2011
@@ -2096,9 +2096,7 @@

   // Retrieve FCSR and check for fpu errors.
   __ cfc1(t5, FCSR);
-  __ srl(t5, t5, kFCSRFlagShift);
-  // Flag 1 marks an inaccurate but still good result so we ignore it.
-  __ And(t5, t5, Operand(kFCSRFlagMask ^ 1));
+  __ And(t5, t5, Operand(kFCSRExceptionFlagMask));
   __ Branch(&no_fpu_error, eq, t5, Operand(zero_reg));

   // Check for NaN, Infinity, and -Infinity.
=======================================
--- /branches/bleeding_edge/test/cctest/test-assembler-mips.cc Mon May 9 07:28:09 2011 +++ /branches/bleeding_edge/test/cctest/test-assembler-mips.cc Mon Jun 6 01:43:15 2011
@@ -1220,8 +1220,6 @@
     // Restore FCSR.
     __ ctc1(a1, FCSR);

-#undef RUN_ROUND_TEST
-
     __ jr(ra);
     __ nop();

@@ -1246,66 +1244,19 @@
     Object* dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);
     USE(dummy);

-#define GET_FPU_ERR(x) (static_cast<int>((x >> kFCSRFlagShift) & kFCSRFlagMask))
-
-    CHECK_EQ(124, t.round_up_out);
-    CHECK_EQ(123, t.round_down_out);
-    CHECK_EQ(-124, t.neg_round_up_out);
-    CHECK_EQ(-123, t.neg_round_down_out);
-
-    // Inexact.
-    CHECK_EQ(kFCSRInexactFlagBit, GET_FPU_ERR(t.round_err1_out));
-    // No error.
-    CHECK_EQ(0, GET_FPU_ERR(t.round_err2_out));
-    // Invalid operation.
-    CHECK_EQ(kFCSRInvalidOpFlagBit, GET_FPU_ERR(t.round_err3_out));
-    CHECK_EQ(kFCSRInvalidOpFlagBit, GET_FPU_ERR(t.round_err4_out));
-    CHECK_EQ(kFPUInvalidResult, t.round_invalid_result);
-
-    CHECK_EQ(123, t.floor_up_out);
-    CHECK_EQ(123, t.floor_down_out);
-    CHECK_EQ(-124, t.neg_floor_up_out);
-    CHECK_EQ(-124, t.neg_floor_down_out);
-
-    // Inexact.
-    CHECK_EQ(kFCSRInexactFlagBit, GET_FPU_ERR(t.floor_err1_out));
-    // No error.
-    CHECK_EQ(0, GET_FPU_ERR(t.floor_err2_out));
-    // Invalid operation.
-    CHECK_EQ(kFCSRInvalidOpFlagBit, GET_FPU_ERR(t.floor_err3_out));
-    CHECK_EQ(kFCSRInvalidOpFlagBit, GET_FPU_ERR(t.floor_err4_out));
-    CHECK_EQ(kFPUInvalidResult, t.floor_invalid_result);
-
-    CHECK_EQ(124, t.ceil_up_out);
-    CHECK_EQ(124, t.ceil_down_out);
-    CHECK_EQ(-123, t.neg_ceil_up_out);
-    CHECK_EQ(-123, t.neg_ceil_down_out);
-
-    // Inexact.
-    CHECK_EQ(kFCSRInexactFlagBit, GET_FPU_ERR(t.ceil_err1_out));
-    // No error.
-    CHECK_EQ(0, GET_FPU_ERR(t.ceil_err2_out));
-    // Invalid operation.
-    CHECK_EQ(kFCSRInvalidOpFlagBit, GET_FPU_ERR(t.ceil_err3_out));
-    CHECK_EQ(kFCSRInvalidOpFlagBit, GET_FPU_ERR(t.ceil_err4_out));
-    CHECK_EQ(kFPUInvalidResult, t.ceil_invalid_result);
-
-    // In rounding mode 0 cvt should behave like round.
-    CHECK_EQ(t.round_up_out, t.cvt_up_out);
-    CHECK_EQ(t.round_down_out, t.cvt_down_out);
-    CHECK_EQ(t.neg_round_up_out, t.neg_cvt_up_out);
-    CHECK_EQ(t.neg_round_down_out, t.neg_cvt_down_out);
-
-    // Inexact.
-    CHECK_EQ(kFCSRInexactFlagBit, GET_FPU_ERR(t.cvt_err1_out));
-    // No error.
-    CHECK_EQ(0, GET_FPU_ERR(t.cvt_err2_out));
-    // Invalid operation.
-    CHECK_EQ(kFCSRInvalidOpFlagBit, GET_FPU_ERR(t.cvt_err3_out));
-    CHECK_EQ(kFCSRInvalidOpFlagBit, GET_FPU_ERR(t.cvt_err4_out));
-    CHECK_EQ(kFPUInvalidResult, t.cvt_invalid_result);
+#define GET_FPU_ERR(x) (static_cast<int>(x & kFCSRFlagMask))
+#define CHECK_ROUND_RESULT(type) \
+  CHECK(GET_FPU_ERR(t.type##_err1_out) & kFCSRInexactFlagMask); \
+  CHECK_EQ(0, GET_FPU_ERR(t.type##_err2_out)); \
+  CHECK(GET_FPU_ERR(t.type##_err3_out) & kFCSRInvalidOpFlagMask); \
+  CHECK(GET_FPU_ERR(t.type##_err4_out) & kFCSRInvalidOpFlagMask); \
+  CHECK_EQ(kFPUInvalidResult, t.type##_invalid_result);
+
+    CHECK_ROUND_RESULT(round);
+    CHECK_ROUND_RESULT(floor);
+    CHECK_ROUND_RESULT(ceil);
+    CHECK_ROUND_RESULT(cvt);
   }
 }
-

 #undef __

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

Reply via email to