Commit e61bd7bd authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

ARM: backend opt for ToBoolean: JIT code generation for ToBool

Upgraded the CodeGenerator::ToBoolean() function in the ARM backend to use complete JIT code generation and not make runtime calls to ToBool (when VFP is enabled). 

This change also includes the vcmp VFP instruction that supports a constant 0.0 as the second operand. 

Patch by Subrato K De <subratokde@codeaurora.org>



git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5267 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6fa44eb9
...@@ -2276,6 +2276,21 @@ void Assembler::vcmp(const DwVfpRegister src1, ...@@ -2276,6 +2276,21 @@ void Assembler::vcmp(const DwVfpRegister src1,
} }
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) { void Assembler::vmrs(Register dst, Condition cond) {
// Instruction details available in ARM DDI 0406A, A8-652. // Instruction details available in ARM DDI 0406A, A8-652.
// cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) | // cond(31-28) | 1110 (27-24) | 1111(23-20)| 0001 (19-16) |
......
...@@ -1031,6 +1031,10 @@ class Assembler : public Malloced { ...@@ -1031,6 +1031,10 @@ class Assembler : public Malloced {
const DwVfpRegister src2, const DwVfpRegister src2,
const SBit s = LeaveCC, const SBit s = LeaveCC,
const Condition cond = al); 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, void vmrs(const Register dst,
const Condition cond = al); const Condition cond = al);
void vsqrt(const DwVfpRegister dst, void vsqrt(const DwVfpRegister dst,
......
...@@ -771,12 +771,26 @@ void CodeGenerator::ToBoolean(JumpTarget* true_target, ...@@ -771,12 +771,26 @@ void CodeGenerator::ToBoolean(JumpTarget* true_target,
__ tst(tos, Operand(kSmiTagMask)); __ tst(tos, Operand(kSmiTagMask));
true_target->Branch(eq); true_target->Branch(eq);
// Slow case: call the runtime. // Slow case.
frame_->EmitPush(tos); if (CpuFeatures::IsSupported(VFP3)) {
frame_->CallRuntime(Runtime::kToBool, 1); CpuFeatures::Scope scope(VFP3);
// Convert the result (r0) to a condition code. // Implements the slow case by using ToBooleanStub.
__ LoadRoot(ip, Heap::kFalseValueRootIndex); // The ToBooleanStub takes a single argument, and
__ cmp(r0, ip); // 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; cc_reg_ = ne;
...@@ -7939,6 +7953,77 @@ void CompareStub::Generate(MacroAssembler* masm) { ...@@ -7939,6 +7953,77 @@ void CompareStub::Generate(MacroAssembler* masm) {
} }
// 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(&not_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(&not_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 // 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 // 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 // the operands were not both Smi. The operands are in r0 and r1. In order
......
...@@ -625,6 +625,19 @@ class TranscendentalCacheStub: public CodeStub { ...@@ -625,6 +625,19 @@ class TranscendentalCacheStub: public CodeStub {
}; };
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 { class GenericBinaryOpStub : public CodeStub {
public: public:
GenericBinaryOpStub(Token::Value op, GenericBinaryOpStub(Token::Value op,
......
...@@ -1188,7 +1188,13 @@ void Decoder::DecodeVCMP(Instr* instr) { ...@@ -1188,7 +1188,13 @@ void Decoder::DecodeVCMP(Instr* instr) {
bool raise_exception_for_qnan = (instr->Bit(7) == 0x1); bool raise_exception_for_qnan = (instr->Bit(7) == 0x1);
if (dp_operation && !raise_exception_for_qnan) { 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 { } else {
Unknown(instr); // Not used by V8. Unknown(instr); // Not used by V8.
} }
......
...@@ -2431,11 +2431,17 @@ void Simulator::DecodeVCMP(Instr* instr) { ...@@ -2431,11 +2431,17 @@ void Simulator::DecodeVCMP(Instr* instr) {
} }
int d = GlueRegCode(!dp_operation, instr->VdField(), instr->DField()); 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) { if (dp_operation) {
double dd_value = get_double_from_d_register(d); 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); Compute_FPSCR_Flags(dd_value, dm_value);
} else { } else {
......
...@@ -731,18 +731,6 @@ class CallFunctionStub: public CodeStub { ...@@ -731,18 +731,6 @@ class CallFunctionStub: public CodeStub {
}; };
class ToBooleanStub: public CodeStub {
public:
ToBooleanStub() { }
void Generate(MacroAssembler* masm);
private:
Major MajorKey() { return ToBoolean; }
int MinorKey() { return 0; }
};
enum StringIndexFlags { enum StringIndexFlags {
// Accepts smis or heap numbers. // Accepts smis or heap numbers.
STRING_INDEX_IS_NUMBER, STRING_INDEX_IS_NUMBER,
......
...@@ -507,6 +507,31 @@ union DoubleRepresentation { ...@@ -507,6 +507,31 @@ union DoubleRepresentation {
}; };
// 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 // AccessorCallback
struct AccessorDescriptor { struct AccessorDescriptor {
Object* (*getter)(Object* object, void* data); Object* (*getter)(Object* object, void* data);
......
...@@ -813,6 +813,18 @@ class TranscendentalCacheStub: public CodeStub { ...@@ -813,6 +813,18 @@ class TranscendentalCacheStub: public CodeStub {
}; };
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. // Flag that indicates how to generate code for the stub GenericBinaryOpStub.
enum GenericBinaryFlags { enum GenericBinaryFlags {
NO_GENERIC_BINARY_FLAGS = 0, NO_GENERIC_BINARY_FLAGS = 0,
......
...@@ -1155,11 +1155,23 @@ void HeapObject::IterateStructBody(int object_size, ObjectVisitor* v) { ...@@ -1155,11 +1155,23 @@ void HeapObject::IterateStructBody(int object_size, ObjectVisitor* v) {
Object* HeapNumber::HeapNumberToBoolean() { Object* HeapNumber::HeapNumberToBoolean() {
// NaN, +0, and -0 should return the false object // NaN, +0, and -0 should return the false object
switch (fpclassify(value())) { #if __BYTE_ORDER == __LITTLE_ENDIAN
case FP_NAN: // fall through union IeeeDoubleLittleEndianArchType u;
case FP_ZERO: return Heap::false_value(); #elif __BYTE_ORDER == __BIG_ENDIAN
default: return Heap::true_value(); 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();
} }
......
...@@ -766,6 +766,18 @@ class TranscendentalCacheStub: public CodeStub { ...@@ -766,6 +766,18 @@ class TranscendentalCacheStub: public CodeStub {
}; };
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. // Flag that indicates how to generate code for the stub GenericBinaryOpStub.
enum GenericBinaryFlags { enum GenericBinaryFlags {
NO_GENERIC_BINARY_FLAGS = 0, NO_GENERIC_BINARY_FLAGS = 0,
......
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