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