Commit a8e81716 authored by whesse@chromium.org's avatar whesse@chromium.org

Optimize the assembly code generated for Math.random()

Review URL: http://codereview.chromium.org/1631008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4384 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent d4e436d0
...@@ -580,6 +580,11 @@ ExternalReference ExternalReference::fill_heap_number_with_random_function() { ...@@ -580,6 +580,11 @@ ExternalReference ExternalReference::fill_heap_number_with_random_function() {
} }
ExternalReference ExternalReference::random_uint32_function() {
return ExternalReference(Redirect(FUNCTION_ADDR(V8::Random)));
}
ExternalReference ExternalReference::transcendental_cache_array_address() { ExternalReference ExternalReference::transcendental_cache_array_address() {
return ExternalReference(TranscendentalCache::cache_array_address()); return ExternalReference(TranscendentalCache::cache_array_address());
} }
......
...@@ -399,6 +399,7 @@ class ExternalReference BASE_EMBEDDED { ...@@ -399,6 +399,7 @@ class ExternalReference BASE_EMBEDDED {
static ExternalReference perform_gc_function(); static ExternalReference perform_gc_function();
static ExternalReference fill_heap_number_with_random_function(); static ExternalReference fill_heap_number_with_random_function();
static ExternalReference random_uint32_function();
static ExternalReference transcendental_cache_array_address(); static ExternalReference transcendental_cache_array_address();
// Static data in the keyed lookup cache. // Static data in the keyed lookup cache.
......
...@@ -6438,7 +6438,7 @@ void CodeGenerator::GenerateRandomHeapNumber( ...@@ -6438,7 +6438,7 @@ void CodeGenerator::GenerateRandomHeapNumber(
Label slow_allocate_heapnumber; Label slow_allocate_heapnumber;
Label heapnumber_allocated; Label heapnumber_allocated;
__ AllocateHeapNumber(eax, ebx, ecx, &slow_allocate_heapnumber); __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
__ jmp(&heapnumber_allocated); __ jmp(&heapnumber_allocated);
__ bind(&slow_allocate_heapnumber); __ bind(&slow_allocate_heapnumber);
...@@ -6447,13 +6447,38 @@ void CodeGenerator::GenerateRandomHeapNumber( ...@@ -6447,13 +6447,38 @@ void CodeGenerator::GenerateRandomHeapNumber(
// -0.0. A new, distinct heap number is returned each time. // -0.0. A new, distinct heap number is returned each time.
__ push(Immediate(Smi::FromInt(0))); __ push(Immediate(Smi::FromInt(0)));
__ CallRuntime(Runtime::kNumberUnaryMinus, 1); __ CallRuntime(Runtime::kNumberUnaryMinus, 1);
__ mov(edi, eax);
__ bind(&heapnumber_allocated); __ bind(&heapnumber_allocated);
__ PrepareCallCFunction(1, ebx); __ PrepareCallCFunction(0, ebx);
__ mov(Operand(esp, 0), eax); __ CallCFunction(ExternalReference::random_uint32_function(), 0);
__ CallCFunction(ExternalReference::fill_heap_number_with_random_function(),
1); // 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); Result result = allocator_->Allocate(eax);
frame_->Push(&result); frame_->Push(&result);
......
...@@ -334,6 +334,11 @@ void ExternalReferenceTable::PopulateTable() { ...@@ -334,6 +334,11 @@ void ExternalReferenceTable::PopulateTable() {
2, 2,
"V8::FillHeapNumberWithRandom"); "V8::FillHeapNumberWithRandom");
Add(ExternalReference::random_uint32_function().address(),
RUNTIME_ENTRY,
3,
"V8::Random");
// Miscellaneous // Miscellaneous
Add(ExternalReference::the_hole_value_location().address(), Add(ExternalReference::the_hole_value_location().address(),
UNCLASSIFIED, UNCLASSIFIED,
......
...@@ -210,11 +210,13 @@ Object* V8::FillHeapNumberWithRandom(Object* heap_number) { ...@@ -210,11 +210,13 @@ Object* V8::FillHeapNumberWithRandom(Object* heap_number) {
double_int_union* r = reinterpret_cast<double_int_union*>( double_int_union* r = reinterpret_cast<double_int_union*>(
reinterpret_cast<char*>(heap_number) + reinterpret_cast<char*>(heap_number) +
HeapNumber::kValueOffset - kHeapObjectTag); HeapNumber::kValueOffset - kHeapObjectTag);
// Create a random number between 0.0 and 1.0 by putting random bits into // Convert 32 random bits to 0.(32 random bits) in a double
// the mantissa of 1.0 and subtracting 1.0. // by computing:
r->double_value = 1.0; // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
r->uint64_t_value |= (random_bits << 20); const double binary_million = 1048576.0;
r->double_value -= 1.0; // Force into the range [0.0, 1.0). r->double_value = binary_million;
r->uint64_t_value |= random_bits;
r->double_value -= binary_million;
return heap_number; return heap_number;
} }
......
...@@ -2385,6 +2385,17 @@ void Assembler::emit_farith(int b1, int b2, int i) { ...@@ -2385,6 +2385,17 @@ void Assembler::emit_farith(int b1, int b2, int i) {
// SSE 2 operations. // 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) { void Assembler::movsd(const Operand& dst, XMMRegister src) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
last_pc_ = pc_; last_pc_ = pc_;
...@@ -2473,6 +2484,17 @@ void Assembler::cvtqsi2sd(XMMRegister dst, Register src) { ...@@ -2473,6 +2484,17 @@ void Assembler::cvtqsi2sd(XMMRegister dst, Register 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) { void Assembler::addsd(XMMRegister dst, XMMRegister src) {
EnsureSpace ensure_space(this); EnsureSpace ensure_space(this);
last_pc_ = pc_; last_pc_ = pc_;
......
...@@ -1079,9 +1079,11 @@ class Assembler : public Malloced { ...@@ -1079,9 +1079,11 @@ class Assembler : public Malloced {
void sahf(); void sahf();
// SSE2 instructions // SSE2 instructions
void movd(XMMRegister dst, Register src);
void movsd(const Operand& dst, XMMRegister src); void movsd(const Operand& dst, XMMRegister src);
void movsd(XMMRegister src, XMMRegister dst); void movsd(XMMRegister dst, XMMRegister src);
void movsd(XMMRegister src, const Operand& dst); void movsd(XMMRegister dst, const Operand& src);
void cvttss2si(Register dst, const Operand& src); void cvttss2si(Register dst, const Operand& src);
void cvttsd2si(Register dst, const Operand& src); void cvttsd2si(Register dst, const Operand& src);
...@@ -1091,6 +1093,8 @@ class Assembler : public Malloced { ...@@ -1091,6 +1093,8 @@ class Assembler : public Malloced {
void cvtqsi2sd(XMMRegister dst, const Operand& src); void cvtqsi2sd(XMMRegister dst, const Operand& src);
void cvtqsi2sd(XMMRegister dst, Register src); void cvtqsi2sd(XMMRegister dst, Register src);
void cvtss2sd(XMMRegister dst, XMMRegister src);
void addsd(XMMRegister dst, XMMRegister src); void addsd(XMMRegister dst, XMMRegister src);
void subsd(XMMRegister dst, XMMRegister src); void subsd(XMMRegister dst, XMMRegister src);
void mulsd(XMMRegister dst, XMMRegister src); void mulsd(XMMRegister dst, XMMRegister src);
...@@ -1101,6 +1105,7 @@ class Assembler : public Malloced { ...@@ -1101,6 +1105,7 @@ class Assembler : public Malloced {
void comisd(XMMRegister dst, XMMRegister src); void comisd(XMMRegister dst, XMMRegister src);
void ucomisd(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 dst, XMMRegister src);
void emit_sse_operand(XMMRegister reg, const Operand& adr); void emit_sse_operand(XMMRegister reg, const Operand& adr);
void emit_sse_operand(XMMRegister dst, Register src); void emit_sse_operand(XMMRegister dst, Register src);
......
...@@ -4081,7 +4081,7 @@ void CodeGenerator::GenerateRandomHeapNumber( ...@@ -4081,7 +4081,7 @@ void CodeGenerator::GenerateRandomHeapNumber(
Label slow_allocate_heapnumber; Label slow_allocate_heapnumber;
Label heapnumber_allocated; Label heapnumber_allocated;
__ AllocateHeapNumber(rdi, rbx, &slow_allocate_heapnumber); __ AllocateHeapNumber(rbx, rcx, &slow_allocate_heapnumber);
__ jmp(&heapnumber_allocated); __ jmp(&heapnumber_allocated);
__ bind(&slow_allocate_heapnumber); __ bind(&slow_allocate_heapnumber);
...@@ -4090,25 +4090,27 @@ void CodeGenerator::GenerateRandomHeapNumber( ...@@ -4090,25 +4090,27 @@ void CodeGenerator::GenerateRandomHeapNumber(
// -0.0. A new, distinct heap number is returned each time. // -0.0. A new, distinct heap number is returned each time.
__ Push(Smi::FromInt(0)); __ Push(Smi::FromInt(0));
__ CallRuntime(Runtime::kNumberUnaryMinus, 1); __ CallRuntime(Runtime::kNumberUnaryMinus, 1);
__ movq(rdi, rax); __ movq(rbx, rax);
__ bind(&heapnumber_allocated); __ bind(&heapnumber_allocated);
// Put a random number into the heap number rdi using a C++ function. // Return a random uint32 number in rax.
// Return the heap number in rax. // The fresh HeapNumber is in rbx, which is callee-save on both x64 ABIs.
#ifdef _WIN64 __ PrepareCallCFunction(0);
__ movq(rcx, rdi); __ CallCFunction(ExternalReference::random_uint32_function(), 0);
#else
// Callee-save in Microsoft 64-bit ABI, but not in AMD64 ABI. // Convert 32 random bits in eax to 0.(32 random bits) in a double
__ push(rsi); // by computing:
#endif // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
__ PrepareCallCFunction(1); __ movl(rcx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
__ CallCFunction(ExternalReference::fill_heap_number_with_random_function(), __ movd(xmm1, rcx);
1); __ movd(xmm0, rax);
#ifndef _WIN64 __ cvtss2sd(xmm1, xmm1);
// Callee-save in Microsoft 64-bit ABI, but not in AMD64 ABI. __ xorpd(xmm0, xmm1);
__ pop(rsi); __ subsd(xmm0, xmm1);
#endif __ movsd(FieldOperand(rbx, HeapNumber::kValueOffset), xmm0);
__ movq(rax, rbx);
Result result = allocator_->Allocate(rax); Result result = allocator_->Allocate(rax);
frame_->Push(&result); frame_->Push(&result);
} }
......
...@@ -997,18 +997,23 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { ...@@ -997,18 +997,23 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
// 0x66 0x0F prefix. // 0x66 0x0F prefix.
int mod, regop, rm; int mod, regop, rm;
get_modrm(*current, &mod, &regop, &rm); get_modrm(*current, &mod, &regop, &rm);
const char* mnemonic = "?"; if (opcode == 0x6E) {
if (opcode == 0x57) { AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
mnemonic = "xorpd"; current += PrintRightOperand(current);
} else if (opcode == 0x2E) {
mnemonic = "comisd";
} else if (opcode == 0x2F) {
mnemonic = "ucomisd";
} else { } else {
UnimplementedInstruction(); 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);
} }
AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
} else if (group_1_prefix_ == 0xF2) { } else if (group_1_prefix_ == 0xF2) {
// Beginning of instructions with prefix 0xF2. // Beginning of instructions with prefix 0xF2.
...@@ -1039,13 +1044,21 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { ...@@ -1039,13 +1044,21 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
} else { } else {
UnimplementedInstruction(); UnimplementedInstruction();
} }
} else if (opcode == 0x2C && group_1_prefix_ == 0xF3) { } else if (group_1_prefix_ == 0xF3) {
// Instruction with prefix 0xF3. // Instructions with prefix 0xF3.
if (opcode == 0x2C) {
// CVTTSS2SI: Convert scalar single-precision FP to dword integer. // CVTTSS2SI: Convert scalar single-precision FP to dword integer.
// Assert that mod is not 3, so source is memory, not an XMM register. // Assert that mod is not 3, so source is memory, not an XMM register.
ASSERT_NE(0xC0, *current & 0xC0); ASSERT_NE(0xC0, *current & 0xC0);
current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current); 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) { } else if (opcode == 0x1F) {
// NOP // NOP
int mod, regop, rm; int mod, regop, rm;
......
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