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:
parent
6dd671d6c2
commit
5e3381c9c7
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user