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() {
}
ExternalReference ExternalReference::random_uint32_function() {
return ExternalReference(Redirect(FUNCTION_ADDR(V8::Random)));
}
ExternalReference ExternalReference::transcendental_cache_array_address() {
return ExternalReference(TranscendentalCache::cache_array_address());
}
......
......@@ -399,6 +399,7 @@ class ExternalReference BASE_EMBEDDED {
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.
......
......@@ -6438,7 +6438,7 @@ void CodeGenerator::GenerateRandomHeapNumber(
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 @@ void CodeGenerator::GenerateRandomHeapNumber(
// -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);
......
......@@ -334,6 +334,11 @@ void ExternalReferenceTable::PopulateTable() {
2,
"V8::FillHeapNumberWithRandom");
Add(ExternalReference::random_uint32_function().address(),
RUNTIME_ENTRY,
3,
"V8::Random");
// Miscellaneous
Add(ExternalReference::the_hole_value_location().address(),
UNCLASSIFIED,
......
......@@ -210,11 +210,13 @@ Object* V8::FillHeapNumberWithRandom(Object* heap_number) {
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;
}
......
......@@ -2385,6 +2385,17 @@ void Assembler::emit_farith(int b1, int b2, int i) {
// 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_;
......@@ -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) {
EnsureSpace ensure_space(this);
last_pc_ = pc_;
......
......@@ -1079,9 +1079,11 @@ class Assembler : public Malloced {
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 @@ class Assembler : public Malloced {
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 @@ class Assembler : public Malloced {
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);
......
......@@ -4081,7 +4081,7 @@ void CodeGenerator::GenerateRandomHeapNumber(
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 @@ void CodeGenerator::GenerateRandomHeapNumber(
// -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);
}
......
......@@ -997,18 +997,23 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
// 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();
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) {
// Beginning of instructions with prefix 0xF2.
......@@ -1039,13 +1044,21 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
} 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;
......
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