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, ®op, &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, ®op, &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.