Revision: 4384
Author: [email protected]
Date: Mon Apr 12 03:07:50 2010
Log: Optimize the assembly code generated for Math.random()
Review URL: http://codereview.chromium.org/1631008
http://code.google.com/p/v8/source/detail?r=4384

Modified:
 /branches/bleeding_edge/src/assembler.cc
 /branches/bleeding_edge/src/assembler.h
 /branches/bleeding_edge/src/ia32/codegen-ia32.cc
 /branches/bleeding_edge/src/serialize.cc
 /branches/bleeding_edge/src/v8.cc
 /branches/bleeding_edge/src/x64/assembler-x64.cc
 /branches/bleeding_edge/src/x64/assembler-x64.h
 /branches/bleeding_edge/src/x64/codegen-x64.cc
 /branches/bleeding_edge/src/x64/disasm-x64.cc

=======================================
--- /branches/bleeding_edge/src/assembler.cc    Wed Apr  7 01:18:51 2010
+++ /branches/bleeding_edge/src/assembler.cc    Mon Apr 12 03:07:50 2010
@@ -578,6 +578,11 @@
   return
ExternalReference(Redirect(FUNCTION_ADDR(V8::FillHeapNumberWithRandom)));
 }
+
+
+ExternalReference ExternalReference::random_uint32_function() {
+  return ExternalReference(Redirect(FUNCTION_ADDR(V8::Random)));
+}


 ExternalReference ExternalReference::transcendental_cache_array_address() {
=======================================
--- /branches/bleeding_edge/src/assembler.h     Wed Apr  7 01:18:51 2010
+++ /branches/bleeding_edge/src/assembler.h     Mon Apr 12 03:07:50 2010
@@ -399,6 +399,7 @@

   static ExternalReference perform_gc_function();
   static ExternalReference fill_heap_number_with_random_function();
+  static ExternalReference random_uint32_function();
   static ExternalReference transcendental_cache_array_address();

   // Static data in the keyed lookup cache.
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Mon Apr 12 00:05:24 2010 +++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Mon Apr 12 03:07:50 2010
@@ -6438,7 +6438,7 @@
   Label slow_allocate_heapnumber;
   Label heapnumber_allocated;

-  __ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber);
+  __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
   __ jmp(&heapnumber_allocated);

   __ bind(&slow_allocate_heapnumber);
@@ -6447,13 +6447,38 @@
   // -0.0.  A new, distinct heap number is returned each time.
   __ push(Immediate(Smi::FromInt(0)));
   __ CallRuntime(Runtime::kNumberUnaryMinus, 1);
+  __ mov(edi, eax);

   __ bind(&heapnumber_allocated);

-  __ PrepareCallCFunction(1, ebx);
-  __ mov(Operand(esp, 0), eax);
- __ CallCFunction(ExternalReference::fill_heap_number_with_random_function(),
-                   1);
+  __ PrepareCallCFunction(0, ebx);
+  __ CallCFunction(ExternalReference::random_uint32_function(), 0);
+
+  // Convert 32 random bits in eax to 0.(32 random bits) in a double
+  // by computing:
+  // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
+  // This is implemented on both SSE2 and FPU.
+  if (CpuFeatures::IsSupported(SSE2)) {
+    CpuFeatures::Scope fscope(SSE2);
+    __ mov(ebx, Immediate(0x49800000));  // 1.0 x 2^20 as single.
+    __ movd(xmm1, Operand(ebx));
+    __ movd(xmm0, Operand(eax));
+    __ cvtss2sd(xmm1, xmm1);
+    __ pxor(xmm0, xmm1);
+    __ subsd(xmm0, xmm1);
+    __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
+  } else {
+    // 0x4130000000000000 is 1.0 x 2^20 as a double.
+    __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
+           Immediate(0x41300000));
+    __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
+    __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
+    __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
+    __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
+    __ fsubp(1);
+    __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
+  }
+  __ mov(eax, edi);

   Result result = allocator_->Allocate(eax);
   frame_->Push(&result);
=======================================
--- /branches/bleeding_edge/src/serialize.cc    Wed Apr  7 01:18:51 2010
+++ /branches/bleeding_edge/src/serialize.cc    Mon Apr 12 03:07:50 2010
@@ -334,6 +334,11 @@
       2,
       "V8::FillHeapNumberWithRandom");

+  Add(ExternalReference::random_uint32_function().address(),
+      RUNTIME_ENTRY,
+      3,
+      "V8::Random");
+
   // Miscellaneous
   Add(ExternalReference::the_hole_value_location().address(),
       UNCLASSIFIED,
=======================================
--- /branches/bleeding_edge/src/v8.cc   Mon Apr 12 00:23:43 2010
+++ /branches/bleeding_edge/src/v8.cc   Mon Apr 12 03:07:50 2010
@@ -210,11 +210,13 @@
   double_int_union* r = reinterpret_cast<double_int_union*>(
       reinterpret_cast<char*>(heap_number) +
       HeapNumber::kValueOffset - kHeapObjectTag);
-  // Create a random number between 0.0 and 1.0 by putting random bits into
-  // the mantissa of 1.0 and subtracting 1.0.
-  r->double_value = 1.0;
-  r->uint64_t_value |= (random_bits << 20);
-  r->double_value -= 1.0;  // Force into the range [0.0, 1.0).
+  // Convert 32 random bits to 0.(32 random bits) in a double
+  // by computing:
+  // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
+  const double binary_million = 1048576.0;
+  r->double_value = binary_million;
+  r->uint64_t_value |=  random_bits;
+  r->double_value -= binary_million;

   return heap_number;
 }
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.cc Tue Apr 6 03:36:38 2010 +++ /branches/bleeding_edge/src/x64/assembler-x64.cc Mon Apr 12 03:07:50 2010
@@ -2385,6 +2385,17 @@

 // SSE 2 operations.

+void Assembler::movd(XMMRegister dst, Register src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit(0x66);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x6E);
+  emit_sse_operand(dst, src);
+}
+
+
 void Assembler::movsd(const Operand& dst, XMMRegister src) {
   EnsureSpace ensure_space(this);
   last_pc_ = pc_;
@@ -2471,6 +2482,17 @@
   emit(0x2A);
   emit_sse_operand(dst, src);
 }
+
+
+void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) {
+  EnsureSpace ensure_space(this);
+  last_pc_ = pc_;
+  emit(0xF3);
+  emit_optional_rex_32(dst, src);
+  emit(0x0F);
+  emit(0x5A);
+  emit_sse_operand(dst, src);
+}


 void Assembler::addsd(XMMRegister dst, XMMRegister src) {
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.h     Fri Mar 19 05:53:55 2010
+++ /branches/bleeding_edge/src/x64/assembler-x64.h     Mon Apr 12 03:07:50 2010
@@ -1079,9 +1079,11 @@
   void sahf();

   // SSE2 instructions
+  void movd(XMMRegister dst, Register src);
+
   void movsd(const Operand& dst, XMMRegister src);
-  void movsd(XMMRegister src, XMMRegister dst);
-  void movsd(XMMRegister src, const Operand& dst);
+  void movsd(XMMRegister dst, XMMRegister src);
+  void movsd(XMMRegister dst, const Operand& src);

   void cvttss2si(Register dst, const Operand& src);
   void cvttsd2si(Register dst, const Operand& src);
@@ -1091,6 +1093,8 @@
   void cvtqsi2sd(XMMRegister dst, const Operand& src);
   void cvtqsi2sd(XMMRegister dst, Register src);

+  void cvtss2sd(XMMRegister dst, XMMRegister src);
+
   void addsd(XMMRegister dst, XMMRegister src);
   void subsd(XMMRegister dst, XMMRegister src);
   void mulsd(XMMRegister dst, XMMRegister src);
@@ -1101,6 +1105,7 @@
   void comisd(XMMRegister dst, XMMRegister src);
   void ucomisd(XMMRegister dst, XMMRegister src);

+ // The first argument is the reg field, the second argument is the r/m field.
   void emit_sse_operand(XMMRegister dst, XMMRegister src);
   void emit_sse_operand(XMMRegister reg, const Operand& adr);
   void emit_sse_operand(XMMRegister dst, Register src);
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc      Mon Apr 12 00:05:24 2010
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc      Mon Apr 12 03:07:50 2010
@@ -4081,7 +4081,7 @@

   Label slow_allocate_heapnumber;
   Label heapnumber_allocated;
-  __ AllocateHeapNumber(rdi, rbx, &slow_allocate_heapnumber);
+  __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber);
   __ jmp(&heapnumber_allocated);

   __ bind(&slow_allocate_heapnumber);
@@ -4090,25 +4090,27 @@
   // -0.0.  A new, distinct heap number is returned each time.
   __ Push(Smi::FromInt(0));
   __ CallRuntime(Runtime::kNumberUnaryMinus, 1);
-  __ movq(rdi, rax);
+  __ movq(rbx, rax);

   __ bind(&heapnumber_allocated);

-  // Put a random number into the heap number rdi using a C++ function.
-  // Return the heap number in rax.
-#ifdef _WIN64
-  __ movq(rcx, rdi);
-#else
-  // Callee-save in Microsoft 64-bit ABI, but not in AMD64 ABI.
-  __ push(rsi);
-#endif
-  __ PrepareCallCFunction(1);
- __ CallCFunction(ExternalReference::fill_heap_number_with_random_function(),
-                   1);
-#ifndef _WIN64
-  // Callee-save in Microsoft 64-bit ABI, but not in AMD64 ABI.
-  __ pop(rsi);
-#endif
+  // Return a random uint32 number in rax.
+  // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
+  __ PrepareCallCFunction(0);
+  __ CallCFunction(ExternalReference::random_uint32_function(), 0);
+
+  // Convert 32 random bits in eax to 0.(32 random bits) in a double
+  // by computing:
+  // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
+  __ movl(rcx, Immediate(0x49800000));  // 1.0 x 2^20 as single.
+  __ movd(xmm1, rcx);
+  __ movd(xmm0, rax);
+  __ cvtss2sd(xmm1, xmm1);
+  __ xorpd(xmm0, xmm1);
+  __ subsd(xmm0, xmm1);
+  __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
+
+  __ movq(rax, rbx);
   Result result = allocator_->Allocate(rax);
   frame_->Push(&result);
 }
=======================================
--- /branches/bleeding_edge/src/x64/disasm-x64.cc       Fri Mar 19 05:26:45 2010
+++ /branches/bleeding_edge/src/x64/disasm-x64.cc       Mon Apr 12 03:07:50 2010
@@ -997,18 +997,23 @@
     // 0x66 0x0F prefix.
     int mod, regop, rm;
     get_modrm(*current, &mod, &regop, &rm);
-    const char* mnemonic = "?";
-    if (opcode == 0x57) {
-      mnemonic = "xorpd";
-    } else if (opcode == 0x2E) {
-      mnemonic = "comisd";
-    } else if (opcode == 0x2F) {
-      mnemonic = "ucomisd";
+    if (opcode == 0x6E) {
+      AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
+      current += PrintRightOperand(current);
     } else {
-      UnimplementedInstruction();
-    }
-    AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
-    current += PrintRightXMMOperand(current);
+      const char* mnemonic = "?";
+      if (opcode == 0x57) {
+        mnemonic = "xorpd";
+      } else if (opcode == 0x2E) {
+        mnemonic = "comisd";
+      } else if (opcode == 0x2F) {
+        mnemonic = "ucomisd";
+      } else {
+        UnimplementedInstruction();
+      }
+      AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
+      current += PrintRightXMMOperand(current);
+    }
   } else if (group_1_prefix_ == 0xF2) {
     // Beginning of instructions with prefix 0xF2.

@@ -1039,13 +1044,21 @@
     } else {
       UnimplementedInstruction();
     }
-  } else if (opcode == 0x2C && group_1_prefix_ == 0xF3) {
-    // Instruction with prefix 0xF3.
-
-    // CVTTSS2SI: Convert scalar single-precision FP to dword integer.
-    // Assert that mod is not 3, so source is memory, not an XMM register.
-    ASSERT_NE(0xC0, *current & 0xC0);
-    current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current);
+  } else if (group_1_prefix_ == 0xF3) {
+    // Instructions with prefix 0xF3.
+    if (opcode == 0x2C) {
+      // CVTTSS2SI: Convert scalar single-precision FP to dword integer.
+ // Assert that mod is not 3, so source is memory, not an XMM register.
+      ASSERT_NE(0xC0, *current & 0xC0);
+      current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current);
+    } else if (opcode == 0x5A) {
+      int mod, regop, rm;
+      get_modrm(*current, &mod, &regop, &rm);
+      AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
+      current += PrintRightXMMOperand(current);
+    } else {
+      UnimplementedInstruction();
+    }
   } else if (opcode == 0x1F) {
     // NOP
     int mod, regop, rm;

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

To unsubscribe, reply using "remove me" as the subject.

Reply via email to