}
+void Assembler::vcmp(const DwVfpRegister src1,
+ const double src2,
+ const SBit s,
+ const Condition cond) {
+ // vcmp(Dd, Dm) double precision floating point comparison.
+ // Instruction details available in ARM DDI 0406A, A8-570.
+ // 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)
+ ASSERT(CpuFeatures::IsEnabled(VFP3));
+ ASSERT(src2 == 0.0);
+ emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 | B16 |
+ src1.code()*B12 | 0x5*B9 | B8 | B6);
+}
+
+
void Assembler::vmrs(Register dst, Condition cond) {
// Instruction details available in ARM DDI 0406A, A8-652.
// cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
const DwVfpRegister src2,
const SBit s = LeaveCC,
const Condition cond = al);
+ void vcmp(const DwVfpRegister src1,
+ const double src2,
+ const SBit s = LeaveCC,
+ const Condition cond = al);
void vmrs(const Register dst,
const Condition cond = al);
void vsqrt(const DwVfpRegister dst,
__ tst(tos, Operand(kSmiTagMask));
true_target->Branch(eq);
- // Slow case: call the runtime.
- frame_->EmitPush(tos);
- frame_->CallRuntime(Runtime::kToBool, 1);
- // Convert the result (r0) to a condition code.
- __ LoadRoot(ip, Heap::kFalseValueRootIndex);
- __ cmp(r0, ip);
+ // Slow case.
+ if (CpuFeatures::IsSupported(VFP3)) {
+ CpuFeatures::Scope scope(VFP3);
+ // Implements the slow case by using ToBooleanStub.
+ // The ToBooleanStub takes a single argument, and
+ // returns a non-zero value for true, or zero for false.
+ // Both the argument value and the return value use the
+ // register assigned to tos_
+ ToBooleanStub stub(tos);
+ frame_->CallStub(&stub, 0);
+ // Convert the result in "tos" to a condition code.
+ __ cmp(tos, Operand(0));
+ } else {
+ // Implements slow case by calling the runtime.
+ frame_->EmitPush(tos);
+ frame_->CallRuntime(Runtime::kToBool, 1);
+ // Convert the result (r0) to a condition code.
+ __ LoadRoot(ip, Heap::kFalseValueRootIndex);
+ __ cmp(r0, ip);
+ }
}
cc_reg_ = ne;
}
+// This stub does not handle the inlined cases (Smis, Booleans, undefined).
+// The stub returns zero for false, and a non-zero value for true.
+void ToBooleanStub::Generate(MacroAssembler* masm) {
+ Label false_result;
+ Label not_heap_number;
+ Register scratch0 = VirtualFrame::scratch0();
+
+ // HeapNumber => false iff +0, -0, or NaN.
+ __ ldr(scratch0, FieldMemOperand(tos_, HeapObject::kMapOffset));
+ __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
+ __ cmp(scratch0, ip);
+ __ b(¬_heap_number, ne);
+
+ __ sub(ip, tos_, Operand(kHeapObjectTag));
+ __ vldr(d1, ip, HeapNumber::kValueOffset);
+ __ vcmp(d1, 0.0);
+ __ vmrs(pc);
+ // "tos_" is a register, and contains a non zero value by default.
+ // Hence we only need to overwrite "tos_" with zero to return false for
+ // FP_ZERO or FP_NAN cases. Otherwise, by default it returns true.
+ __ mov(tos_, Operand(0), LeaveCC, eq); // for FP_ZERO
+ __ mov(tos_, Operand(0), LeaveCC, vs); // for FP_NAN
+ __ Ret();
+
+ __ bind(¬_heap_number);
+
+ // Check if the value is 'null'.
+ // 'null' => false.
+ __ LoadRoot(ip, Heap::kNullValueRootIndex);
+ __ cmp(tos_, ip);
+ __ b(&false_result, eq);
+
+ // It can be an undetectable object.
+ // Undetectable => false.
+ __ ldr(ip, FieldMemOperand(tos_, HeapObject::kMapOffset));
+ __ ldrb(scratch0, FieldMemOperand(ip, Map::kBitFieldOffset));
+ __ and_(scratch0, scratch0, Operand(1 << Map::kIsUndetectable));
+ __ cmp(scratch0, Operand(1 << Map::kIsUndetectable));
+ __ b(&false_result, eq);
+
+ // JavaScript object => true.
+ __ ldr(scratch0, FieldMemOperand(tos_, HeapObject::kMapOffset));
+ __ ldrb(scratch0, FieldMemOperand(scratch0, Map::kInstanceTypeOffset));
+ __ cmp(scratch0, Operand(FIRST_JS_OBJECT_TYPE));
+ // "tos_" is a register and contains a non-zero value.
+ // Hence we implicitly return true if the greater than
+ // condition is satisfied.
+ __ Ret(gt);
+
+ // Check for string
+ __ ldr(scratch0, FieldMemOperand(tos_, HeapObject::kMapOffset));
+ __ ldrb(scratch0, FieldMemOperand(scratch0, Map::kInstanceTypeOffset));
+ __ cmp(scratch0, Operand(FIRST_NONSTRING_TYPE));
+ // "tos_" is a register and contains a non-zero value.
+ // Hence we implicitly return true if the greater than
+ // condition is satisfied.
+ __ Ret(gt);
+
+ // String value => false iff empty, i.e., length is zero
+ __ ldr(tos_, FieldMemOperand(tos_, String::kLengthOffset));
+ // If length is zero, "tos_" contains zero ==> false.
+ // If length is not zero, "tos_" contains a non-zero value ==> true.
+ __ Ret();
+
+ // Return 0 in "tos_" for false .
+ __ bind(&false_result);
+ __ mov(tos_, Operand(0));
+ __ Ret();
+}
+
+
// We fall into this code if the operands were Smis, but the result was
// not (eg. overflow). We branch into this code (to the not_smi label) if
// the operands were not both Smi. The operands are in r0 and r1. In order
};
+class ToBooleanStub: public CodeStub {
+ public:
+ explicit ToBooleanStub(Register tos) : tos_(tos) { }
+
+ void Generate(MacroAssembler* masm);
+
+ private:
+ Register tos_;
+ Major MajorKey() { return ToBoolean; }
+ int MinorKey() { return tos_.code(); }
+};
+
+
class GenericBinaryOpStub : public CodeStub {
public:
GenericBinaryOpStub(Token::Value op,
bool raise_exception_for_qnan = (instr->Bit(7) == 0x1);
if (dp_operation && !raise_exception_for_qnan) {
- Format(instr, "vcmp.f64'cond 'Dd, 'Dm");
+ if (instr->Opc2Field() == 0x4) {
+ Format(instr, "vcmp.f64'cond 'Dd, 'Dm");
+ } else if (instr->Opc2Field() == 0x5) {
+ Format(instr, "vcmp.f64'cond 'Dd, #0.0");
+ } else {
+ Unknown(instr); // invalid
+ }
} else {
Unknown(instr); // Not used by V8.
}
}
int d = GlueRegCode(!dp_operation, instr->VdField(), instr->DField());
- int m = GlueRegCode(!dp_operation, instr->VmField(), instr->MField());
+ int m = 0;
+ if (instr->Opc2Field() == 0x4) {
+ m = GlueRegCode(!dp_operation, instr->VmField(), instr->MField());
+ }
if (dp_operation) {
double dd_value = get_double_from_d_register(d);
- double dm_value = get_double_from_d_register(m);
+ double dm_value = 0.0;
+ if (instr->Opc2Field() == 0x4) {
+ dm_value = get_double_from_d_register(m);
+ }
Compute_FPSCR_Flags(dd_value, dm_value);
} else {
};
-class ToBooleanStub: public CodeStub {
- public:
- ToBooleanStub() { }
-
- void Generate(MacroAssembler* masm);
-
- private:
- Major MajorKey() { return ToBoolean; }
- int MinorKey() { return 0; }
-};
-
-
enum StringIndexFlags {
// Accepts smis or heap numbers.
STRING_INDEX_IS_NUMBER,
};
+// Union used for customized checking of the IEEE double types
+// inlined within v8 runtime, rather than going to the underlying
+// platform headers and libraries
+union IeeeDoubleLittleEndianArchType {
+ double d;
+ struct {
+ unsigned int man_low :32;
+ unsigned int man_high :20;
+ unsigned int exp :11;
+ unsigned int sign :1;
+ } bits;
+};
+
+
+union IeeeDoubleBigEndianArchType {
+ double d;
+ struct {
+ unsigned int sign :1;
+ unsigned int exp :11;
+ unsigned int man_high :20;
+ unsigned int man_low :32;
+ } bits;
+};
+
+
// AccessorCallback
struct AccessorDescriptor {
Object* (*getter)(Object* object, void* data);
};
+class ToBooleanStub: public CodeStub {
+ public:
+ ToBooleanStub() { }
+
+ void Generate(MacroAssembler* masm);
+
+ private:
+ Major MajorKey() { return ToBoolean; }
+ int MinorKey() { return 0; }
+};
+
+
// Flag that indicates how to generate code for the stub GenericBinaryOpStub.
enum GenericBinaryFlags {
NO_GENERIC_BINARY_FLAGS = 0,
Object* HeapNumber::HeapNumberToBoolean() {
// NaN, +0, and -0 should return the false object
- switch (fpclassify(value())) {
- case FP_NAN: // fall through
- case FP_ZERO: return Heap::false_value();
- default: return Heap::true_value();
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+ union IeeeDoubleLittleEndianArchType u;
+#elif __BYTE_ORDER == __BIG_ENDIAN
+ union IeeeDoubleBigEndianArchType u;
+#endif
+ u.d = value();
+ if (u.bits.exp == 2047) {
+ // Detect NaN for IEEE double precision floating point.
+ if ((u.bits.man_low | u.bits.man_high) != 0)
+ return Heap::false_value();
}
+ if (u.bits.exp == 0) {
+ // Detect +0, and -0 for IEEE double precision floating point.
+ if ((u.bits.man_low | u.bits.man_high) == 0)
+ return Heap::false_value();
+ }
+ return Heap::true_value();
}
};
+class ToBooleanStub: public CodeStub {
+ public:
+ ToBooleanStub() { }
+
+ void Generate(MacroAssembler* masm);
+
+ private:
+ Major MajorKey() { return ToBoolean; }
+ int MinorKey() { return 0; }
+};
+
+
// Flag that indicates how to generate code for the stub GenericBinaryOpStub.
enum GenericBinaryFlags {
NO_GENERIC_BINARY_FLAGS = 0,