Revision: 5267
Author: [email protected]
Date: Mon Aug 16 00:52:49 2010
Log: 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 <[email protected]>


http://code.google.com/p/v8/source/detail?r=5267

Modified:
 /branches/bleeding_edge/src/arm/assembler-arm.cc
 /branches/bleeding_edge/src/arm/assembler-arm.h
 /branches/bleeding_edge/src/arm/codegen-arm.cc
 /branches/bleeding_edge/src/arm/codegen-arm.h
 /branches/bleeding_edge/src/arm/disasm-arm.cc
 /branches/bleeding_edge/src/arm/simulator-arm.cc
 /branches/bleeding_edge/src/codegen.h
 /branches/bleeding_edge/src/globals.h
 /branches/bleeding_edge/src/ia32/codegen-ia32.h
 /branches/bleeding_edge/src/objects.cc
 /branches/bleeding_edge/src/x64/codegen-x64.h

=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.cc Fri Jul 23 01:47:15 2010 +++ /branches/bleeding_edge/src/arm/assembler-arm.cc Mon Aug 16 00:52:49 2010
@@ -2274,6 +2274,21 @@
   emit(cond | 0xE*B24 |B23 | 0x3*B20 | B18 |
        src1.code()*B12 | 0x5*B9 | B8 | B6 | src2.code());
 }
+
+
+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) {
=======================================
--- /branches/bleeding_edge/src/arm/assembler-arm.h     Thu Jul 22 01:17:40 2010
+++ /branches/bleeding_edge/src/arm/assembler-arm.h     Mon Aug 16 00:52:49 2010
@@ -1029,6 +1029,10 @@
             const Condition cond = al);
   void vcmp(const DwVfpRegister src1,
             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,
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc      Fri Aug 13 05:36:59 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc      Mon Aug 16 00:52:49 2010
@@ -771,12 +771,26 @@
     __ 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;
@@ -7937,6 +7951,77 @@
   // tagged as a small integer.
   __ InvokeBuiltin(native, JUMP_JS);
 }
+
+
+// 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
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h       Thu Aug 12 06:43:08 2010
+++ /branches/bleeding_edge/src/arm/codegen-arm.h       Mon Aug 16 00:52:49 2010
@@ -625,6 +625,19 @@
 };


+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,
=======================================
--- /branches/bleeding_edge/src/arm/disasm-arm.cc       Wed Jul 21 00:42:51 2010
+++ /branches/bleeding_edge/src/arm/disasm-arm.cc       Mon Aug 16 00:52:49 2010
@@ -1188,7 +1188,13 @@
   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.
   }
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Wed Jul 21 00:42:51 2010 +++ /branches/bleeding_edge/src/arm/simulator-arm.cc Mon Aug 16 00:52:49 2010
@@ -2431,11 +2431,17 @@
   }

   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 {
=======================================
--- /branches/bleeding_edge/src/codegen.h       Thu Aug 12 06:43:08 2010
+++ /branches/bleeding_edge/src/codegen.h       Mon Aug 16 00:52:49 2010
@@ -731,18 +731,6 @@
 };


-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,
=======================================
--- /branches/bleeding_edge/src/globals.h       Thu Aug  5 05:34:53 2010
+++ /branches/bleeding_edge/src/globals.h       Mon Aug 16 00:52:49 2010
@@ -507,6 +507,31 @@
 };


+// 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);
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.h     Thu Aug 12 06:43:08 2010
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.h     Mon Aug 16 00:52:49 2010
@@ -813,6 +813,18 @@
 };


+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,
=======================================
--- /branches/bleeding_edge/src/objects.cc      Thu Aug 12 23:55:44 2010
+++ /branches/bleeding_edge/src/objects.cc      Mon Aug 16 00:52:49 2010
@@ -1155,11 +1155,23 @@

 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();
 }


=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.h       Thu Aug 12 06:43:08 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.h       Mon Aug 16 00:52:49 2010
@@ -766,6 +766,18 @@
 };


+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,

--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to