Landing for Martyn Capewell.

ARM: Fix comparison of NaN values.

Enables the cumulative exception flag when comparing values, and uses it to
detect NaN results.

BUG=1023
TEST=none

Code review URL: http://codereview.chromium.org/6142004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@6236 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
ager@chromium.org 2011-01-10 08:04:30 +00:00
parent 6dd671d6c2
commit 5e3381c9c7
6 changed files with 44 additions and 13 deletions

View File

@ -2340,12 +2340,14 @@ void Assembler::vcmp(const DwVfpRegister src1,
const SBit s,
const Condition cond) {
// vcmp(Dd, Dm) double precision floating point comparison.
// We set bit E, as we want any NaN to set the cumulative exception flag
// in the FPSCR.
// Instruction details available in ARM DDI 0406A, A8-570.
// cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0100 (19-16) |
// Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=? | 1(6) | M(5)=? | 0(4) | Vm(3-0)
// Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=1 | 1(6) | M(5)=? | 0(4) | Vm(3-0)
ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 |
src1.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
src1.code()*B12 | 0x5*B9 | B8 | B7 | B6 | src2.code());
}
@ -2355,12 +2357,14 @@ void Assembler::vcmp(const DwVfpRegister src1,
const Condition cond) {
// vcmp(Dd, Dm) double precision floating point comparison.
// Instruction details available in ARM DDI 0406A, A8-570.
// We set bit E, as we want any NaN to set the cumulative exception flag
// in the FPSCR.
// cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0101 (19-16) |
// Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=? | 1(6) | M(5)=? | 0(4) | 0000(3-0)
// Vd(15-12) | 101(11-9) | sz(8)=1 | E(7)=1 | 1(6) | M(5)=? | 0(4) | 0000(3-0)
ASSERT(CpuFeatures::IsEnabled(VFP3));
ASSERT(src2 == 0.0);
emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | B16 |
src1.code()*B12 | 0x5*B9 | B8 | B6);
src1.code()*B12 | 0x5*B9 | B8 | B7 | B6);
}

View File

@ -302,6 +302,8 @@ static const uint32_t kVFPExceptionMask = 0xf;
static const uint32_t kVFPRoundingModeMask = 3 << 22;
static const uint32_t kVFPFlushToZeroMask = 1 << 24;
static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22;
static const uint32_t kVFPZConditionFlagBit = 1 << 30;
static const uint32_t kVFPInvalidExceptionBit = 1;
// Coprocessor register
struct CRegister {

View File

@ -1076,8 +1076,16 @@ void LCodeGen::DoBranch(LBranch* instr) {
EmitBranch(true_block, false_block, nz);
} else if (r.IsDouble()) {
DoubleRegister reg = ToDoubleRegister(instr->input());
Register scratch = scratch0();
// Test for the double value. Zero and NaN are false.
// Clear the Invalid cumulative exception flags.
__ ClearFPSCRBits(kVFPInvalidExceptionBit, scratch);
__ vcmp(reg, 0.0);
__ vmrs(pc); // Move vector status bits to normal status bits.
// Retrieve the exception and status flags and
// check for zero or an invalid exception.
__ vmrs(scratch);
__ tst(scratch, Operand(kVFPZConditionFlagBit | kVFPInvalidExceptionBit));
EmitBranch(true_block, false_block, ne);
} else {
ASSERT(r.IsTagged());
@ -1104,7 +1112,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ tst(reg, Operand(kSmiTagMask));
__ b(eq, true_label);
// Test for double values. Zero is false.
// Test for double values. Zero and NaN are false.
Label call_stub;
DoubleRegister dbl_scratch = d0;
Register scratch = scratch0();
@ -1114,9 +1122,14 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ b(ne, &call_stub);
__ sub(ip, reg, Operand(kHeapObjectTag));
__ vldr(dbl_scratch, ip, HeapNumber::kValueOffset);
// Clear the Invalid cumulative exception flags.
__ ClearFPSCRBits(kVFPInvalidExceptionBit, scratch);
__ vcmp(dbl_scratch, 0.0);
__ vmrs(pc); // Move vector status bits to normal status bits.
__ b(eq, false_label);
// Retrieve the exception and status flags and
// check for zero or an invalid exception.
__ vmrs(scratch);
__ tst(scratch, Operand(kVFPZConditionFlagBit | kVFPInvalidExceptionBit));
__ b(ne, false_label);
__ b(true_label);
// The conversion stub doesn't cause garbage collections so it's

View File

@ -519,6 +519,13 @@ void MacroAssembler::Strd(Register src1, Register src2,
}
void MacroAssembler::ClearFPSCRBits(uint32_t bits_to_clear, Register scratch) {
vmrs(scratch);
bic(scratch, scratch, Operand(bits_to_clear));
vmsr(scratch);
}
void MacroAssembler::EnterFrame(StackFrame::Type type) {
// r0-r3: preserved
stm(db_w, sp, cp.bit() | fp.bit() | lr.bit());

View File

@ -243,6 +243,9 @@ class MacroAssembler: public Assembler {
const MemOperand& dst,
Condition cond = al);
// Clear FPSCR bits.
void ClearFPSCRBits(uint32_t bits_to_clear, Register scratch);
// ---------------------------------------------------------------------------
// Activation frames

View File

@ -2600,11 +2600,6 @@ void Simulator::DecodeVCMP(Instr* instr) {
precision = kDoublePrecision;
}
if (instr->Bit(7) != 0) {
// Raising exceptions for quiet NaNs are not supported.
UNIMPLEMENTED(); // Not used by V8.
}
int d = instr->VFPDRegCode(precision);
int m = 0;
if (instr->Opc2Field() == 0x4) {
@ -2618,6 +2613,13 @@ void Simulator::DecodeVCMP(Instr* instr) {
dm_value = get_double_from_d_register(m);
}
// Raise exceptions for quiet NaNs if necessary.
if (instr->Bit(7) == 1) {
if (isnan(dd_value)) {
inv_op_vfp_flag_ = true;
}
}
Compute_FPSCR_Flags(dd_value, dm_value);
} else {
UNIMPLEMENTED(); // Not used by V8.