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,
}
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) |
......
......@@ -1031,6 +1031,10 @@ class Assembler : public Malloced {
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,
......
......@@ -771,12 +771,26 @@ void CodeGenerator::ToBoolean(JumpTarget* true_target,
__ 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;
......@@ -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
// 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
......
......@@ -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 {
public:
GenericBinaryOpStub(Token::Value op,
......
......@@ -1188,7 +1188,13 @@ void Decoder::DecodeVCMP(Instr* instr) {
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.
}
......
......@@ -2431,11 +2431,17 @@ void Simulator::DecodeVCMP(Instr* instr) {
}
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 {
......
......@@ -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 {
// Accepts smis or heap numbers.
STRING_INDEX_IS_NUMBER,
......
......@@ -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
struct AccessorDescriptor {
Object* (*getter)(Object* object, void* data);
......
......@@ -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.
enum GenericBinaryFlags {
NO_GENERIC_BINARY_FLAGS = 0,
......
......@@ -1155,11 +1155,23 @@ void HeapObject::IterateStructBody(int object_size, ObjectVisitor* v) {
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();
}
......
......@@ -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.
enum GenericBinaryFlags {
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