Commit 5e3381c9 authored by ager@chromium.org's avatar ager@chromium.org

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
parent 6dd671d6
...@@ -2340,12 +2340,14 @@ void Assembler::vcmp(const DwVfpRegister src1, ...@@ -2340,12 +2340,14 @@ void Assembler::vcmp(const DwVfpRegister src1,
const SBit s, const SBit s,
const Condition cond) { const Condition cond) {
// vcmp(Dd, Dm) double precision floating point comparison. // 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. // Instruction details available in ARM DDI 0406A, A8-570.
// cond(31-28) | 11101 (27-23)| D=?(22) | 11 (21-20) | 0100 (19-16) | // 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)); ASSERT(CpuFeatures::IsEnabled(VFP3));
emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | 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, ...@@ -2355,12 +2357,14 @@ void Assembler::vcmp(const DwVfpRegister src1,
const Condition cond) { const Condition cond) {
// vcmp(Dd, Dm) double precision floating point comparison. // vcmp(Dd, Dm) double precision floating point comparison.
// Instruction details available in ARM DDI 0406A, A8-570. // 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) | // 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(CpuFeatures::IsEnabled(VFP3));
ASSERT(src2 == 0.0); ASSERT(src2 == 0.0);
emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | B16 | emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | B16 |
src1.code()*B12 | 0x5*B9 | B8 | B6); src1.code()*B12 | 0x5*B9 | B8 | B7 | B6);
} }
......
...@@ -302,6 +302,8 @@ static const uint32_t kVFPExceptionMask = 0xf; ...@@ -302,6 +302,8 @@ static const uint32_t kVFPExceptionMask = 0xf;
static const uint32_t kVFPRoundingModeMask = 3 << 22; static const uint32_t kVFPRoundingModeMask = 3 << 22;
static const uint32_t kVFPFlushToZeroMask = 1 << 24; static const uint32_t kVFPFlushToZeroMask = 1 << 24;
static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22; static const uint32_t kVFPRoundToMinusInfinityBits = 2 << 22;
static const uint32_t kVFPZConditionFlagBit = 1 << 30;
static const uint32_t kVFPInvalidExceptionBit = 1;
// Coprocessor register // Coprocessor register
struct CRegister { struct CRegister {
......
...@@ -1076,8 +1076,16 @@ void LCodeGen::DoBranch(LBranch* instr) { ...@@ -1076,8 +1076,16 @@ void LCodeGen::DoBranch(LBranch* instr) {
EmitBranch(true_block, false_block, nz); EmitBranch(true_block, false_block, nz);
} else if (r.IsDouble()) { } else if (r.IsDouble()) {
DoubleRegister reg = ToDoubleRegister(instr->input()); 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); __ 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); EmitBranch(true_block, false_block, ne);
} else { } else {
ASSERT(r.IsTagged()); ASSERT(r.IsTagged());
...@@ -1104,7 +1112,7 @@ void LCodeGen::DoBranch(LBranch* instr) { ...@@ -1104,7 +1112,7 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ tst(reg, Operand(kSmiTagMask)); __ tst(reg, Operand(kSmiTagMask));
__ b(eq, true_label); __ b(eq, true_label);
// Test for double values. Zero is false. // Test for double values. Zero and NaN are false.
Label call_stub; Label call_stub;
DoubleRegister dbl_scratch = d0; DoubleRegister dbl_scratch = d0;
Register scratch = scratch0(); Register scratch = scratch0();
...@@ -1114,9 +1122,14 @@ void LCodeGen::DoBranch(LBranch* instr) { ...@@ -1114,9 +1122,14 @@ void LCodeGen::DoBranch(LBranch* instr) {
__ b(ne, &call_stub); __ b(ne, &call_stub);
__ sub(ip, reg, Operand(kHeapObjectTag)); __ sub(ip, reg, Operand(kHeapObjectTag));
__ vldr(dbl_scratch, ip, HeapNumber::kValueOffset); __ vldr(dbl_scratch, ip, HeapNumber::kValueOffset);
// Clear the Invalid cumulative exception flags.
__ ClearFPSCRBits(kVFPInvalidExceptionBit, scratch);
__ vcmp(dbl_scratch, 0.0); __ vcmp(dbl_scratch, 0.0);
__ vmrs(pc); // Move vector status bits to normal status bits. // Retrieve the exception and status flags and
__ b(eq, false_label); // check for zero or an invalid exception.
__ vmrs(scratch);
__ tst(scratch, Operand(kVFPZConditionFlagBit | kVFPInvalidExceptionBit));
__ b(ne, false_label);
__ b(true_label); __ b(true_label);
// The conversion stub doesn't cause garbage collections so it's // The conversion stub doesn't cause garbage collections so it's
......
...@@ -519,6 +519,13 @@ void MacroAssembler::Strd(Register src1, Register src2, ...@@ -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) { void MacroAssembler::EnterFrame(StackFrame::Type type) {
// r0-r3: preserved // r0-r3: preserved
stm(db_w, sp, cp.bit() | fp.bit() | lr.bit()); stm(db_w, sp, cp.bit() | fp.bit() | lr.bit());
......
...@@ -243,6 +243,9 @@ class MacroAssembler: public Assembler { ...@@ -243,6 +243,9 @@ class MacroAssembler: public Assembler {
const MemOperand& dst, const MemOperand& dst,
Condition cond = al); Condition cond = al);
// Clear FPSCR bits.
void ClearFPSCRBits(uint32_t bits_to_clear, Register scratch);
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Activation frames // Activation frames
......
...@@ -2600,11 +2600,6 @@ void Simulator::DecodeVCMP(Instr* instr) { ...@@ -2600,11 +2600,6 @@ void Simulator::DecodeVCMP(Instr* instr) {
precision = kDoublePrecision; 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 d = instr->VFPDRegCode(precision);
int m = 0; int m = 0;
if (instr->Opc2Field() == 0x4) { if (instr->Opc2Field() == 0x4) {
...@@ -2618,6 +2613,13 @@ void Simulator::DecodeVCMP(Instr* instr) { ...@@ -2618,6 +2613,13 @@ void Simulator::DecodeVCMP(Instr* instr) {
dm_value = get_double_from_d_register(m); 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); Compute_FPSCR_Flags(dd_value, dm_value);
} else { } else {
UNIMPLEMENTED(); // Not used by V8. UNIMPLEMENTED(); // Not used by V8.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment