Revision: 13054
Author: [email protected]
Date: Mon Nov 26 05:12:35 2012
Log: Faster implementation of Math.exp()
Review URL: https://codereview.chromium.org/11418149
http://code.google.com/p/v8/source/detail?r=13054
Added:
/branches/bleeding_edge/test/mjsunit/math-exp-precision.js
Modified:
/branches/bleeding_edge/src/arm/codegen-arm.cc
/branches/bleeding_edge/src/arm/codegen-arm.h
/branches/bleeding_edge/src/arm/lithium-arm.cc
/branches/bleeding_edge/src/arm/lithium-arm.h
/branches/bleeding_edge/src/arm/lithium-codegen-arm.cc
/branches/bleeding_edge/src/arm/simulator-arm.cc
/branches/bleeding_edge/src/arm/simulator-arm.h
/branches/bleeding_edge/src/assembler.cc
/branches/bleeding_edge/src/assembler.h
/branches/bleeding_edge/src/codegen.h
/branches/bleeding_edge/src/flag-definitions.h
/branches/bleeding_edge/src/hydrogen-instructions.h
/branches/bleeding_edge/src/hydrogen.cc
/branches/bleeding_edge/src/ia32/assembler-ia32.cc
/branches/bleeding_edge/src/ia32/assembler-ia32.h
/branches/bleeding_edge/src/ia32/code-stubs-ia32.cc
/branches/bleeding_edge/src/ia32/codegen-ia32.cc
/branches/bleeding_edge/src/ia32/codegen-ia32.h
/branches/bleeding_edge/src/ia32/disasm-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.cc
/branches/bleeding_edge/src/ia32/lithium-ia32.h
/branches/bleeding_edge/src/platform-posix.cc
/branches/bleeding_edge/src/platform-win32.cc
/branches/bleeding_edge/src/platform.h
/branches/bleeding_edge/src/runtime.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/code-stubs-x64.cc
/branches/bleeding_edge/src/x64/codegen-x64.cc
/branches/bleeding_edge/src/x64/codegen-x64.h
/branches/bleeding_edge/src/x64/lithium-codegen-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.cc
/branches/bleeding_edge/src/x64/lithium-x64.h
=======================================
--- /dev/null
+++ /branches/bleeding_edge/test/mjsunit/math-exp-precision.js Mon Nov 26
05:12:35 2012
@@ -0,0 +1,64 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Tests that the --fast-math implementation of Math.exp() has
+// reasonable precision.
+
+function exp(x) {
+ return Math.exp(x);
+}
+
+var first_call_result = exp(Math.PI);
+var second_call_result = exp(Math.PI);
+
+function assertAlmostEquals(expected, actual, x) {
+ if (expected == 0 && actual == 0) return; // OK
+ if (expected == Number.POSITIVE_INFINITY &&
+ actual == Number.POSITIVE_INFINITY) {
+ return; // OK
+ }
+ relative_diff = Math.abs(expected/actual - 1);
+ assertTrue(relative_diff < 1e-12, "relative difference of " +
relative_diff +
+ " for input " + x);
+}
+
+var increment = Math.PI / 35; // Roughly 0.1, but we want to try many
+ // different mantissae.
+for (var x = -708; x < 710; x += increment) {
+ var ex = exp(x);
+ var reference = Math.pow(Math.E, x);
+ assertAlmostEquals(reference, ex, x);
+ if (ex > 0 && isFinite(ex)) {
+ var back = Math.log(ex);
+ assertAlmostEquals(x, back, x + " (backwards)");
+ }
+}
+
+// Make sure optimizing the function does not alter the result.
+var last_call_result = exp(Math.PI);
+assertEquals(first_call_result, second_call_result);
+assertEquals(first_call_result, last_call_result);
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.cc Thu Nov 15 05:31:27 2012
+++ /branches/bleeding_edge/src/arm/codegen-arm.cc Mon Nov 26 05:12:35 2012
@@ -31,11 +31,11 @@
#include "codegen.h"
#include "macro-assembler.h"
+#include "simulator-arm.h"
namespace v8 {
namespace internal {
-#define __ ACCESS_MASM(masm)
UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type
type) {
switch (type) {
@@ -47,6 +47,74 @@
}
return NULL;
}
+
+
+#define __ masm.
+
+
+#if defined(USE_SIMULATOR)
+byte* fast_exp_arm_machine_code = NULL;
+double fast_exp_simulator(double x) {
+ return Simulator::current(Isolate::Current())->CallFP(
+ fast_exp_arm_machine_code, x, 0);
+}
+#endif
+
+
+UnaryMathFunction CreateExpFunction() {
+ if (!CpuFeatures::IsSupported(VFP2)) return &exp;
+ if (!FLAG_fast_math) return &exp;
+ size_t actual_size;
+ byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size,
true));
+ if (buffer == NULL) return &exp;
+ ExternalReference::InitializeMathExpData();
+
+ MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
+
+ {
+ CpuFeatures::Scope use_vfp(VFP2);
+ DoubleRegister input = d0;
+ DoubleRegister result = d1;
+ DoubleRegister double_scratch1 = d2;
+ DoubleRegister double_scratch2 = d3;
+ Register temp1 = r4;
+ Register temp2 = r5;
+ Register temp3 = r6;
+
+ if (masm.use_eabi_hardfloat()) {
+ // Input value is in d0 anyway, nothing to do.
+ } else {
+ __ vmov(input, r0, r1);
+ }
+ __ Push(temp3, temp2, temp1);
+ MathExpGenerator::EmitMathExp(
+ &masm, input, result, double_scratch1, double_scratch2,
+ temp1, temp2, temp3);
+ __ Pop(temp3, temp2, temp1);
+ if (masm.use_eabi_hardfloat()) {
+ __ vmov(d0, result);
+ } else {
+ __ vmov(r0, r1, result);
+ }
+ __ Ret();
+ }
+
+ CodeDesc desc;
+ masm.GetCode(&desc);
+
+ CPU::FlushICache(buffer, actual_size);
+ OS::ProtectCode(buffer, actual_size);
+
+#if !defined(USE_SIMULATOR)
+ return FUNCTION_CAST<UnaryMathFunction>(buffer);
+#else
+ fast_exp_arm_machine_code = buffer;
+ return &fast_exp_simulator;
+#endif
+}
+
+
+#undef __
UnaryMathFunction CreateSqrtFunction() {
@@ -73,6 +141,8 @@
//
-------------------------------------------------------------------------
// Code generators
+#define __ ACCESS_MASM(masm)
+
void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
MacroAssembler* masm) {
// ----------- S t a t e -------------
@@ -449,6 +519,78 @@
__ ldrb(result, MemOperand(string, index));
__ bind(&done);
}
+
+
+static MemOperand ExpConstant(int index, Register base) {
+ return MemOperand(base, index * kDoubleSize);
+}
+
+
+void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
+ DoubleRegister input,
+ DoubleRegister result,
+ DoubleRegister double_scratch1,
+ DoubleRegister double_scratch2,
+ Register temp1,
+ Register temp2,
+ Register temp3) {
+ ASSERT(!input.is(result));
+ ASSERT(!input.is(double_scratch1));
+ ASSERT(!input.is(double_scratch2));
+ ASSERT(!result.is(double_scratch1));
+ ASSERT(!result.is(double_scratch2));
+ ASSERT(!double_scratch1.is(double_scratch2));
+ ASSERT(!temp1.is(temp2));
+ ASSERT(!temp1.is(temp3));
+ ASSERT(!temp2.is(temp3));
+ ASSERT(ExternalReference::math_exp_constants(0).address() != NULL);
+
+ Label done;
+
+ __ mov(temp3, Operand(ExternalReference::math_exp_constants(0)));
+
+ __ vldr(double_scratch1, ExpConstant(0, temp3));
+ __ vmov(result, kDoubleRegZero);
+ __ VFPCompareAndSetFlags(double_scratch1, input);
+ __ b(ge, &done);
+ __ vldr(double_scratch2, ExpConstant(1, temp3));
+ __ VFPCompareAndSetFlags(input, double_scratch2);
+ __ vldr(result, ExpConstant(2, temp3));
+ __ b(ge, &done);
+ __ vldr(double_scratch1, ExpConstant(3, temp3));
+ __ vldr(result, ExpConstant(4, temp3));
+ __ vmul(double_scratch1, double_scratch1, input);
+ __ vadd(double_scratch1, double_scratch1, result);
+ __ vmov(temp2, temp1, double_scratch1);
+ __ vsub(double_scratch1, double_scratch1, result);
+ __ vldr(result, ExpConstant(6, temp3));
+ __ vldr(double_scratch2, ExpConstant(5, temp3));
+ __ vmul(double_scratch1, double_scratch1, double_scratch2);
+ __ vsub(double_scratch1, double_scratch1, input);
+ __ vsub(result, result, double_scratch1);
+ __ vmul(input, double_scratch1, double_scratch1);
+ __ vmul(result, result, input);
+ __ mov(temp1, Operand(temp2, LSR, 11));
+ __ vldr(double_scratch2, ExpConstant(7, temp3));
+ __ vmul(result, result, double_scratch2);
+ __ vsub(result, result, double_scratch1);
+ __ vldr(double_scratch2, ExpConstant(8, temp3));
+ __ vadd(result, result, double_scratch2);
+ __ movw(ip, 0x7ff);
+ __ and_(temp2, temp2, Operand(ip));
+ __ add(temp1, temp1, Operand(0x3ff));
+ __ mov(temp1, Operand(temp1, LSL, 20));
+
+ // Must not call ExpConstant() after overwriting temp3!
+ __ mov(temp3, Operand(ExternalReference::math_exp_log_table()));
+ __ ldr(ip, MemOperand(temp3, temp2, LSL, 3));
+ __ add(temp3, temp3, Operand(kPointerSize));
+ __ ldr(temp2, MemOperand(temp3, temp2, LSL, 3));
+ __ orr(temp1, temp1, temp2);
+ __ vmov(input, ip, temp1);
+ __ vmul(result, result, input);
+ __ bind(&done);
+}
#undef __
=======================================
--- /branches/bleeding_edge/src/arm/codegen-arm.h Thu Nov 8 04:18:11 2012
+++ /branches/bleeding_edge/src/arm/codegen-arm.h Mon Nov 26 05:12:35 2012
@@ -91,6 +91,22 @@
DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator);
};
+
+class MathExpGenerator : public AllStatic {
+ public:
+ static void EmitMathExp(MacroAssembler* masm,
+ DoubleRegister input,
+ DoubleRegister result,
+ DoubleRegister double_scratch1,
+ DoubleRegister double_scratch2,
+ Register temp1,
+ Register temp2,
+ Register temp3);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
+};
+
} } // namespace v8::internal
#endif // V8_ARM_CODEGEN_ARM_H_
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.cc Thu Nov 22 02:19:05 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.cc Mon Nov 26 05:12:35 2012
@@ -295,6 +295,11 @@
stream->Add("/%s ", hydrogen()->OpName());
value()->PrintTo(stream);
}
+
+
+void LMathExp::PrintDataTo(StringStream* stream) {
+ value()->PrintTo(stream);
+}
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
@@ -1041,6 +1046,15 @@
LOperand* input = UseFixedDouble(instr->value(), d2);
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input,
NULL);
return MarkAsCall(DefineFixedDouble(result, d2), instr);
+ } else if (op == kMathExp) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->value()->representation().IsDouble());
+ LOperand* input = UseTempRegister(instr->value());
+ LOperand* temp1 = TempRegister();
+ LOperand* temp2 = TempRegister();
+ LOperand* double_temp = FixedTemp(d3); // Chosen by fair dice roll.
+ LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1,
temp2);
+ return DefineAsRegister(result);
} else if (op == kMathPowHalf) {
LOperand* input = UseFixedDouble(instr->value(), d2);
LOperand* temp = FixedTemp(d3);
=======================================
--- /branches/bleeding_edge/src/arm/lithium-arm.h Thu Nov 22 02:19:05 2012
+++ /branches/bleeding_edge/src/arm/lithium-arm.h Mon Nov 26 05:12:35 2012
@@ -131,6 +131,7 @@
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(MapEnumLength) \
+ V(MathExp) \
V(MathFloorOfDiv) \
V(MathMinMax) \
V(ModI) \
@@ -681,6 +682,30 @@
};
+class LMathExp: public LTemplateInstruction<1, 1, 3> {
+ public:
+ LMathExp(LOperand* value,
+ LOperand* double_temp,
+ LOperand* temp1,
+ LOperand* temp2) {
+ inputs_[0] = value;
+ temps_[0] = temp1;
+ temps_[1] = temp2;
+ temps_[2] = double_temp;
+ ExternalReference::InitializeMathExpData();
+ }
+
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp1() { return temps_[0]; }
+ LOperand* temp2() { return temps_[1]; }
+ LOperand* double_temp() { return temps_[2]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+
+ virtual void PrintDataTo(StringStream* stream);
+};
+
+
class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> {
public:
LCmpObjectEqAndBranch(LOperand* left, LOperand* right) {
=======================================
--- /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Fri Nov 23
02:53:03 2012
+++ /branches/bleeding_edge/src/arm/lithium-codegen-arm.cc Mon Nov 26
05:12:35 2012
@@ -3805,6 +3805,20 @@
__ CallCFunction(ExternalReference::random_uint32_function(isolate()),
1);
// Return value is in r0.
}
+
+
+void LCodeGen::DoMathExp(LMathExp* instr) {
+ DoubleRegister input = ToDoubleRegister(instr->value());
+ DoubleRegister result = ToDoubleRegister(instr->result());
+ DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
+ DoubleRegister double_scratch2 = double_scratch0();
+ Register temp1 = ToRegister(instr->temp1());
+ Register temp2 = ToRegister(instr->temp2());
+
+ MathExpGenerator::EmitMathExp(
+ masm(), input, result, double_scratch1, double_scratch2,
+ temp1, temp2, scratch0());
+}
void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.cc Wed Nov 14 03:01:18
2012
+++ /branches/bleeding_edge/src/arm/simulator-arm.cc Mon Nov 26 05:12:35
2012
@@ -3301,33 +3301,7 @@
}
-int32_t Simulator::Call(byte* entry, int argument_count, ...) {
- va_list parameters;
- va_start(parameters, argument_count);
- // Set up arguments
-
- // First four arguments passed in registers.
- ASSERT(argument_count >= 4);
- set_register(r0, va_arg(parameters, int32_t));
- set_register(r1, va_arg(parameters, int32_t));
- set_register(r2, va_arg(parameters, int32_t));
- set_register(r3, va_arg(parameters, int32_t));
-
- // Remaining arguments passed on stack.
- int original_stack = get_register(sp);
- // Compute position of stack on entry to generated code.
- int entry_stack = (original_stack - (argument_count - 4) *
sizeof(int32_t));
- if (OS::ActivationFrameAlignment() != 0) {
- entry_stack &= -OS::ActivationFrameAlignment();
- }
- // Store remaining arguments on stack, from low to high memory.
- intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
- for (int i = 4; i < argument_count; i++) {
- stack_argument[i - 4] = va_arg(parameters, int32_t);
- }
- va_end(parameters);
- set_register(sp, entry_stack);
-
+void Simulator::CallInternal(byte* entry) {
// Prepare to execute the code at entry
set_register(pc, reinterpret_cast<int32_t>(entry));
// Put down marker for end of simulation. The simulator will stop
simulation
@@ -3381,6 +3355,37 @@
set_register(r9, r9_val);
set_register(r10, r10_val);
set_register(r11, r11_val);
+}
+
+
+int32_t Simulator::Call(byte* entry, int argument_count, ...) {
+ va_list parameters;
+ va_start(parameters, argument_count);
+ // Set up arguments
+
+ // First four arguments passed in registers.
+ ASSERT(argument_count >= 4);
+ set_register(r0, va_arg(parameters, int32_t));
+ set_register(r1, va_arg(parameters, int32_t));
+ set_register(r2, va_arg(parameters, int32_t));
+ set_register(r3, va_arg(parameters, int32_t));
+
+ // Remaining arguments passed on stack.
+ int original_stack = get_register(sp);
+ // Compute position of stack on entry to generated code.
+ int entry_stack = (original_stack - (argument_count - 4) *
sizeof(int32_t));
+ if (OS::ActivationFrameAlignment() != 0) {
+ entry_stack &= -OS::ActivationFrameAlignment();
+ }
+ // Store remaining arguments on stack, from low to high memory.
+ intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
+ for (int i = 4; i < argument_count; i++) {
+ stack_argument[i - 4] = va_arg(parameters, int32_t);
+ }
+ va_end(parameters);
+ set_register(sp, entry_stack);
+
+ CallInternal(entry);
// Pop stack passed arguments.
CHECK_EQ(entry_stack, get_register(sp));
@@ -3389,6 +3394,27 @@
int32_t result = get_register(r0);
return result;
}
+
+
+double Simulator::CallFP(byte* entry, double d0, double d1) {
+ if (use_eabi_hardfloat()) {
+ set_d_register_from_double(0, d0);
+ set_d_register_from_double(1, d1);
+ } else {
+ int buffer[2];
+ ASSERT(sizeof(buffer[0]) * 2 == sizeof(d0));
+ memcpy(buffer, &d0, sizeof(d0));
+ set_dw_register(0, buffer);
+ memcpy(buffer, &d1, sizeof(d1));
+ set_dw_register(2, buffer);
+ }
+ CallInternal(entry);
+ if (use_eabi_hardfloat()) {
+ return get_double_from_d_register(0);
+ } else {
+ return get_double_from_register_pair(0);
+ }
+}
uintptr_t Simulator::PushAddress(uintptr_t address) {
=======================================
--- /branches/bleeding_edge/src/arm/simulator-arm.h Mon Aug 6 07:28:27 2012
+++ /branches/bleeding_edge/src/arm/simulator-arm.h Mon Nov 26 05:12:35 2012
@@ -205,6 +205,8 @@
// generated RegExp code with 7 parameters. This is a convenience
function,
// which sets up the simulator state and grabs the result on return.
int32_t Call(byte* entry, int argument_count, ...);
+ // Alternative: call a 2-argument double function.
+ double CallFP(byte* entry, double d0, double d1);
// Push an address onto the JS stack.
uintptr_t PushAddress(uintptr_t address);
@@ -356,6 +358,8 @@
template<class InputType, int register_size>
void SetVFPRegister(int reg_index, const InputType& value);
+ void CallInternal(byte* entry);
+
// Architecture state.
// Saturating instructions require a Q flag to indicate saturation.
// There is currently no way to read the CPSR directly, and thus read
the Q
=======================================
--- /branches/bleeding_edge/src/assembler.cc Thu Nov 22 06:59:52 2012
+++ /branches/bleeding_edge/src/assembler.cc Mon Nov 26 05:12:35 2012
@@ -103,6 +103,11 @@
const char* const RelocInfo::kFillerCommentString = "DEOPTIMIZATION
PADDING";
+static bool math_exp_data_initialized = false;
+static Mutex* math_exp_data_mutex = NULL;
+static double* math_exp_constants_array = NULL;
+static double* math_exp_log_table_array = NULL;
+
//
-----------------------------------------------------------------------------
// Implementation of AssemblerBase
@@ -836,9 +841,73 @@
double_constants.canonical_non_hole_nan = OS::nan_value();
double_constants.the_hole_nan = BitCast<double>(kHoleNanInt64);
double_constants.negative_infinity = -V8_INFINITY;
+
+ math_exp_data_mutex = OS::CreateMutex();
}
+void ExternalReference::InitializeMathExpData() {
+ // Early return?
+ if (math_exp_data_initialized) return;
+
+ math_exp_data_mutex->Lock();
+ if (!math_exp_data_initialized) {
+ // If this is changed, generated code must be adapted too.
+ const int kTableSizeBits = 11;
+ const int kTableSize = 1 << kTableSizeBits;
+ const double kTableSizeDouble = static_cast<double>(kTableSize);
+
+ math_exp_constants_array = new double[9];
+ // Input values smaller than this always return 0.
+ math_exp_constants_array[0] = -708.39641853226408;
+ // Input values larger than this always return +Infinity.
+ math_exp_constants_array[1] = 709.78271289338397;
+ math_exp_constants_array[2] = V8_INFINITY;
+ // The rest is black magic. Do not attempt to understand it. It is
+ // loosely based on the "expd" function published at:
+ //
http://herumi.blogspot.com/2011/08/fast-double-precision-exponential.html
+ const double constant3 = (1 << kTableSizeBits) / log(2.0);
+ math_exp_constants_array[3] = constant3;
+ math_exp_constants_array[4] =
+ static_cast<double>(static_cast<int64_t>(3) << 51);
+ math_exp_constants_array[5] = 1 / constant3;
+ math_exp_constants_array[6] = 3.0000000027955394;
+ math_exp_constants_array[7] = 0.16666666685227835;
+ math_exp_constants_array[8] = 1;
+
+ math_exp_log_table_array = new double[kTableSize];
+ for (int i = 0; i < kTableSize; i++) {
+ double value = pow(2, i / kTableSizeDouble);
+
+ uint64_t bits = BitCast<uint64_t, double>(value);
+ bits &= (static_cast<uint64_t>(1) << 52) - 1;
+ double mantissa = BitCast<double, uint64_t>(bits);
+
+ // <just testing>
+ uint64_t doublebits;
+ memcpy(&doublebits, &value, sizeof doublebits);
+ doublebits &= (static_cast<uint64_t>(1) << 52) - 1;
+ double mantissa2;
+ memcpy(&mantissa2, &doublebits, sizeof mantissa2);
+ CHECK_EQ(mantissa, mantissa2);
+ // </just testing>
+
+ math_exp_log_table_array[i] = mantissa;
+ }
+
+ math_exp_data_initialized = true;
+ }
+ math_exp_data_mutex->Unlock();
+}
+
+
+void ExternalReference::TearDownMathExpData() {
+ delete[] math_exp_constants_array;
+ delete[] math_exp_log_table_array;
+ delete math_exp_data_mutex;
+}
+
+
ExternalReference::ExternalReference(Builtins::CFunctionId id, Isolate*
isolate)
: address_(Redirect(isolate, Builtins::c_function_address(id))) {}
@@ -1271,6 +1340,19 @@
FUNCTION_ADDR(math_log_double),
BUILTIN_FP_CALL));
}
+
+
+ExternalReference ExternalReference::math_exp_constants(int
constant_index) {
+ ASSERT(math_exp_data_initialized);
+ return ExternalReference(
+ reinterpret_cast<void*>(math_exp_constants_array + constant_index));
+}
+
+
+ExternalReference ExternalReference::math_exp_log_table() {
+ ASSERT(math_exp_data_initialized);
+ return
ExternalReference(reinterpret_cast<void*>(math_exp_log_table_array));
+}
ExternalReference ExternalReference::page_flags(Page* page) {
=======================================
--- /branches/bleeding_edge/src/assembler.h Thu Nov 22 06:59:52 2012
+++ /branches/bleeding_edge/src/assembler.h Mon Nov 26 05:12:35 2012
@@ -604,6 +604,8 @@
};
static void SetUp();
+ static void InitializeMathExpData();
+ static void TearDownMathExpData();
typedef void* ExternalReferenceRedirector(void* original, Type type);
@@ -725,6 +727,9 @@
static ExternalReference math_tan_double_function(Isolate* isolate);
static ExternalReference math_log_double_function(Isolate* isolate);
+ static ExternalReference math_exp_constants(int constant_index);
+ static ExternalReference math_exp_log_table();
+
static ExternalReference page_flags(Page* page);
Address address() const {return reinterpret_cast<Address>(address_);}
=======================================
--- /branches/bleeding_edge/src/codegen.h Wed May 23 07:24:29 2012
+++ /branches/bleeding_edge/src/codegen.h Mon Nov 26 05:12:35 2012
@@ -90,6 +90,7 @@
typedef double (*UnaryMathFunction)(double x);
UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type
type);
+UnaryMathFunction CreateExpFunction();
UnaryMathFunction CreateSqrtFunction();
=======================================
--- /branches/bleeding_edge/src/flag-definitions.h Thu Nov 22 05:04:11 2012
+++ /branches/bleeding_edge/src/flag-definitions.h Mon Nov 26 05:12:35 2012
@@ -181,6 +181,7 @@
DEFINE_int(max_inlined_nodes_cumulative, 196,
"maximum cumulative number of AST nodes considered for
inlining")
DEFINE_bool(loop_invariant_code_motion, true, "loop invariant code motion")
+DEFINE_bool(fast_math, true, "faster (but maybe less accurate) math
functions")
DEFINE_bool(collect_megamorphic_maps_from_stub_cache,
true,
"crankshaft harvests type feedback from stub cache")
=======================================
--- /branches/bleeding_edge/src/hydrogen-instructions.h Fri Nov 23 02:53:03
2012
+++ /branches/bleeding_edge/src/hydrogen-instructions.h Mon Nov 26 05:12:35
2012
@@ -2084,6 +2084,9 @@
set_representation(Representation::Double());
SetGVNFlag(kChangesNewSpacePromotion);
break;
+ case kMathExp:
+ set_representation(Representation::Double());
+ break;
default:
UNREACHABLE();
}
@@ -2110,6 +2113,7 @@
case kMathSqrt:
case kMathPowHalf:
case kMathLog:
+ case kMathExp:
case kMathSin:
case kMathCos:
case kMathTan:
=======================================
--- /branches/bleeding_edge/src/hydrogen.cc Fri Nov 23 02:53:03 2012
+++ /branches/bleeding_edge/src/hydrogen.cc Mon Nov 26 05:12:35 2012
@@ -7253,6 +7253,9 @@
if (!expr->target()->shared()->HasBuiltinFunctionId()) return false;
BuiltinFunctionId id = expr->target()->shared()->builtin_function_id();
switch (id) {
+ case kMathExp:
+ if (!FLAG_fast_math) break;
+ // Fall through if FLAG_fast_math.
case kMathRound:
case kMathAbs:
case kMathSqrt:
@@ -7313,6 +7316,9 @@
return true;
}
break;
+ case kMathExp:
+ if (!FLAG_fast_math) break;
+ // Fall through if FLAG_fast_math.
case kMathRound:
case kMathFloor:
case kMathAbs:
=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.cc Thu Nov 22 02:28:29
2012
+++ /branches/bleeding_edge/src/ia32/assembler-ia32.cc Mon Nov 26 05:12:35
2012
@@ -1964,6 +1964,16 @@
EMIT(0x58);
emit_sse_operand(dst, src);
}
+
+
+void Assembler::addsd(XMMRegister dst, const Operand& src) {
+ ASSERT(CpuFeatures::IsEnabled(SSE2));
+ EnsureSpace ensure_space(this);
+ EMIT(0xF2);
+ EMIT(0x0F);
+ EMIT(0x58);
+ emit_sse_operand(dst, src);
+}
void Assembler::mulsd(XMMRegister dst, XMMRegister src) {
@@ -1974,6 +1984,16 @@
EMIT(0x59);
emit_sse_operand(dst, src);
}
+
+
+void Assembler::mulsd(XMMRegister dst, const Operand& src) {
+ ASSERT(CpuFeatures::IsEnabled(SSE2));
+ EnsureSpace ensure_space(this);
+ EMIT(0xF2);
+ EMIT(0x0F);
+ EMIT(0x59);
+ emit_sse_operand(dst, src);
+}
void Assembler::subsd(XMMRegister dst, XMMRegister src) {
@@ -2372,7 +2392,7 @@
}
-void Assembler::pshufd(XMMRegister dst, XMMRegister src, int8_t shuffle) {
+void Assembler::pshufd(XMMRegister dst, XMMRegister src, uint8_t shuffle) {
ASSERT(CpuFeatures::IsEnabled(SSE2));
EnsureSpace ensure_space(this);
EMIT(0x66);
=======================================
--- /branches/bleeding_edge/src/ia32/assembler-ia32.h Thu Nov 22 02:28:29
2012
+++ /branches/bleeding_edge/src/ia32/assembler-ia32.h Mon Nov 26 05:12:35
2012
@@ -990,8 +990,10 @@
void cvtsd2ss(XMMRegister dst, XMMRegister src);
void addsd(XMMRegister dst, XMMRegister src);
+ void addsd(XMMRegister dst, const Operand& src);
void subsd(XMMRegister dst, XMMRegister src);
void mulsd(XMMRegister dst, XMMRegister src);
+ void mulsd(XMMRegister dst, const Operand& src);
void divsd(XMMRegister dst, XMMRegister src);
void xorpd(XMMRegister dst, XMMRegister src);
void xorps(XMMRegister dst, XMMRegister src);
@@ -1048,7 +1050,7 @@
void psllq(XMMRegister dst, XMMRegister src);
void psrlq(XMMRegister reg, int8_t shift);
void psrlq(XMMRegister dst, XMMRegister src);
- void pshufd(XMMRegister dst, XMMRegister src, int8_t shuffle);
+ void pshufd(XMMRegister dst, XMMRegister src, uint8_t shuffle);
void pextrd(Register dst, XMMRegister src, int8_t offset) {
pextrd(Operand(dst), src, offset);
}
=======================================
--- /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Wed Nov 21 23:05:20
2012
+++ /branches/bleeding_edge/src/ia32/code-stubs-ia32.cc Mon Nov 26 05:12:35
2012
@@ -3115,10 +3115,10 @@
// F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1
__ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X)
__ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X)
- __ faddp(1); // 1, 2^(X-rnd(X)), rnd(X)
+ __ faddp(1); // 2^(X-rnd(X)), rnd(X)
// FSCALE calculates st(0) * 2^st(1)
__ fscale(); // 2^X, rnd(X)
- __ fstp(1);
+ __ fstp(1); // 2^X
// Bail out to runtime in case of exceptions in the status word.
__ fnstsw_ax();
__ test_b(eax, 0x5F); // We check for all but precision exception.
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.cc Thu Nov 15 05:31:27
2012
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.cc Mon Nov 26 05:12:35
2012
@@ -100,6 +100,43 @@
OS::ProtectCode(buffer, actual_size);
return FUNCTION_CAST<UnaryMathFunction>(buffer);
}
+
+
+UnaryMathFunction CreateExpFunction() {
+ if (!CpuFeatures::IsSupported(SSE2)) return &exp;
+ if (!FLAG_fast_math) return &exp;
+ size_t actual_size;
+ byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size,
true));
+ if (buffer == NULL) return &exp;
+ ExternalReference::InitializeMathExpData();
+
+ MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
+ // esp[1 * kPointerSize]: raw double input
+ // esp[0 * kPointerSize]: return address
+ {
+ CpuFeatures::Scope use_sse2(SSE2);
+ XMMRegister input = xmm1;
+ XMMRegister result = xmm2;
+ __ movdbl(input, Operand(esp, 1 * kPointerSize));
+ __ push(eax);
+ __ push(ebx);
+
+ MathExpGenerator::EmitMathExp(&masm, input, result, xmm0, eax, ebx);
+
+ __ pop(ebx);
+ __ pop(eax);
+ __ movdbl(Operand(esp, 1 * kPointerSize), result);
+ __ fld_d(Operand(esp, 1 * kPointerSize));
+ __ Ret();
+ }
+
+ CodeDesc desc;
+ masm.GetCode(&desc);
+
+ CPU::FlushICache(buffer, actual_size);
+ OS::ProtectCode(buffer, actual_size);
+ return FUNCTION_CAST<UnaryMathFunction>(buffer);
+}
UnaryMathFunction CreateSqrtFunction() {
@@ -754,6 +791,63 @@
SeqOneByteString::kHeaderSize));
__ bind(&done);
}
+
+
+static Operand ExpConstant(int index) {
+ return
Operand::StaticVariable(ExternalReference::math_exp_constants(index));
+}
+
+
+void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
+ XMMRegister input,
+ XMMRegister result,
+ XMMRegister double_scratch,
+ Register temp1,
+ Register temp2) {
+ ASSERT(!input.is(double_scratch));
+ ASSERT(!input.is(result));
+ ASSERT(!result.is(double_scratch));
+ ASSERT(!temp1.is(temp2));
+ ASSERT(ExternalReference::math_exp_constants(0).address() != NULL);
+
+ Label done;
+
+ __ movdbl(double_scratch, ExpConstant(0));
+ __ xorpd(result, result);
+ __ ucomisd(double_scratch, input);
+ __ j(above_equal, &done);
+ __ ucomisd(input, ExpConstant(1));
+ __ movdbl(result, ExpConstant(2));
+ __ j(above_equal, &done);
+ __ movdbl(double_scratch, ExpConstant(3));
+ __ movdbl(result, ExpConstant(4));
+ __ mulsd(double_scratch, input);
+ __ addsd(double_scratch, result);
+ __ movd(temp2, double_scratch);
+ __ subsd(double_scratch, result);
+ __ movdbl(result, ExpConstant(6));
+ __ mulsd(double_scratch, ExpConstant(5));
+ __ subsd(double_scratch, input);
+ __ subsd(result, double_scratch);
+ __ movsd(input, double_scratch);
+ __ mulsd(input, double_scratch);
+ __ mulsd(result, input);
+ __ mov(temp1, temp2);
+ __ mulsd(result, ExpConstant(7));
+ __ subsd(result, double_scratch);
+ __ add(temp1, Immediate(0x1ff800));
+ __ addsd(result, ExpConstant(8));
+ __ and_(temp2, Immediate(0x7ff));
+ __ shr(temp1, 11);
+ __ shl(temp1, 20);
+ __ movd(input, temp1);
+ __ pshufd(input, input, static_cast<uint8_t>(0xe1)); // Order: 11 10 00
01
+ __ movdbl(double_scratch, Operand::StaticArray(
+ temp2, times_8, ExternalReference::math_exp_log_table()));
+ __ por(input, double_scratch);
+ __ mulsd(result, input);
+ __ bind(&done);
+}
#undef __
=======================================
--- /branches/bleeding_edge/src/ia32/codegen-ia32.h Thu Nov 8 04:18:11 2012
+++ /branches/bleeding_edge/src/ia32/codegen-ia32.h Mon Nov 26 05:12:35 2012
@@ -92,6 +92,20 @@
DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator);
};
+
+class MathExpGenerator : public AllStatic {
+ public:
+ static void EmitMathExp(MacroAssembler* masm,
+ XMMRegister input,
+ XMMRegister result,
+ XMMRegister double_scratch,
+ Register temp1,
+ Register temp2);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
+};
+
} } // namespace v8::internal
#endif // V8_IA32_CODEGEN_IA32_H_
=======================================
--- /branches/bleeding_edge/src/ia32/disasm-ia32.cc Wed Sep 19 05:48:49 2012
+++ /branches/bleeding_edge/src/ia32/disasm-ia32.cc Mon Nov 26 05:12:35 2012
@@ -869,6 +869,7 @@
case 0xAF: return "imul";
case 0xA5: return "shld";
case 0xAD: return "shrd";
+ case 0xAC: return "shrd"; // 3-operand version.
case 0xAB: return "bts";
default: return NULL;
}
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Fri Nov 23
02:53:03 2012
+++ /branches/bleeding_edge/src/ia32/lithium-codegen-ia32.cc Mon Nov 26
05:12:35 2012
@@ -3607,6 +3607,16 @@
__ add(Operand(esp), Immediate(kDoubleSize));
__ bind(&done);
}
+
+
+void LCodeGen::DoMathExp(LMathExp* instr) {
+ XMMRegister input = ToDoubleRegister(instr->value());
+ XMMRegister result = ToDoubleRegister(instr->result());
+ Register temp1 = ToRegister(instr->temp1());
+ Register temp2 = ToRegister(instr->temp2());
+
+ MathExpGenerator::EmitMathExp(masm(), input, result, xmm0, temp1, temp2);
+}
void LCodeGen::DoMathTan(LUnaryMathOperation* instr) {
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.cc Thu Nov 22 02:19:05
2012
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.cc Mon Nov 26 05:12:35
2012
@@ -297,6 +297,11 @@
stream->Add("/%s ", hydrogen()->OpName());
value()->PrintTo(stream);
}
+
+
+void LMathExp::PrintDataTo(StringStream* stream) {
+ value()->PrintTo(stream);
+}
void LMathPowHalf::PrintDataTo(StringStream* stream) {
@@ -1087,6 +1092,14 @@
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(context,
input);
return DefineSameAsFirst(result);
+ } else if (op == kMathExp) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->value()->representation().IsDouble());
+ LOperand* value = UseTempRegister(instr->value());
+ LOperand* temp1 = TempRegister();
+ LOperand* temp2 = TempRegister();
+ LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
+ return DefineAsRegister(result);
} else if (op == kMathSin || op == kMathCos || op == kMathTan) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* input = UseFixedDouble(instr->value(), xmm1);
=======================================
--- /branches/bleeding_edge/src/ia32/lithium-ia32.h Thu Nov 22 02:19:05 2012
+++ /branches/bleeding_edge/src/ia32/lithium-ia32.h Mon Nov 26 05:12:35 2012
@@ -125,6 +125,7 @@
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(MapEnumLength) \
+ V(MathExp) \
V(MathFloorOfDiv) \
V(MathMinMax) \
V(MathPowHalf) \
@@ -639,6 +640,27 @@
};
+class LMathExp: public LTemplateInstruction<1, 1, 2> {
+ public:
+ LMathExp(LOperand* value,
+ LOperand* temp1,
+ LOperand* temp2) {
+ inputs_[0] = value;
+ temps_[0] = temp1;
+ temps_[1] = temp2;
+ ExternalReference::InitializeMathExpData();
+ }
+
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp1() { return temps_[0]; }
+ LOperand* temp2() { return temps_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+
+ virtual void PrintDataTo(StringStream* stream);
+};
+
+
class LMathPowHalf: public LTemplateInstruction<1, 2, 1> {
public:
LMathPowHalf(LOperand* context, LOperand* value, LOperand* temp) {
=======================================
--- /branches/bleeding_edge/src/platform-posix.cc Tue Jul 10 05:52:36 2012
+++ /branches/bleeding_edge/src/platform-posix.cc Mon Nov 26 05:12:35 2012
@@ -142,11 +142,19 @@
UNARY_MATH_FUNCTION(cos,
CreateTranscendentalFunction(TranscendentalCache::COS))
UNARY_MATH_FUNCTION(tan,
CreateTranscendentalFunction(TranscendentalCache::TAN))
UNARY_MATH_FUNCTION(log,
CreateTranscendentalFunction(TranscendentalCache::LOG))
+UNARY_MATH_FUNCTION(exp, CreateExpFunction())
UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction())
#undef MATH_FUNCTION
+void lazily_initialize_fast_exp() {
+ if (fast_exp_function == NULL) {
+ init_fast_exp_function();
+ }
+}
+
+
double OS::nan_value() {
// NAN from math.h is defined in C99 and not in POSIX.
return NAN;
@@ -332,6 +340,7 @@
init_fast_cos_function();
init_fast_tan_function();
init_fast_log_function();
+ // fast_exp is initialized lazily.
init_fast_sqrt_function();
}
=======================================
--- /branches/bleeding_edge/src/platform-win32.cc Fri Nov 16 02:38:10 2012
+++ /branches/bleeding_edge/src/platform-win32.cc Mon Nov 26 05:12:35 2012
@@ -199,11 +199,19 @@
UNARY_MATH_FUNCTION(cos,
CreateTranscendentalFunction(TranscendentalCache::COS))
UNARY_MATH_FUNCTION(tan,
CreateTranscendentalFunction(TranscendentalCache::TAN))
UNARY_MATH_FUNCTION(log,
CreateTranscendentalFunction(TranscendentalCache::LOG))
+UNARY_MATH_FUNCTION(exp, CreateExpFunction())
UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction())
#undef MATH_FUNCTION
+void lazily_initialize_fast_exp() {
+ if (fast_exp_function == NULL) {
+ init_fast_exp_function();
+ }
+}
+
+
void MathSetup() {
#ifdef _WIN64
init_modulo_function();
@@ -212,6 +220,7 @@
init_fast_cos_function();
init_fast_tan_function();
init_fast_log_function();
+ // fast_exp is initialized lazily.
init_fast_sqrt_function();
}
=======================================
--- /branches/bleeding_edge/src/platform.h Fri Nov 16 02:38:10 2012
+++ /branches/bleeding_edge/src/platform.h Mon Nov 26 05:12:35 2012
@@ -119,12 +119,16 @@
double ceiling(double x);
double modulo(double x, double y);
-// Custom implementation of sin, cos, tan and log.
+// Custom implementation of math functions.
double fast_sin(double input);
double fast_cos(double input);
double fast_tan(double input);
double fast_log(double input);
+double fast_exp(double input);
double fast_sqrt(double input);
+// The custom exp implementation needs 16KB of lookup data; initialize it
+// on demand.
+void lazily_initialize_fast_exp();
// Forward declarations.
class Socket;
=======================================
--- /branches/bleeding_edge/src/runtime.cc Thu Nov 22 02:25:22 2012
+++ /branches/bleeding_edge/src/runtime.cc Mon Nov 26 05:12:35 2012
@@ -7153,7 +7153,8 @@
isolate->counters()->math_exp()->Increment();
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
- return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
+ lazily_initialize_fast_exp();
+ return isolate->heap()->NumberFromDouble(fast_exp(x));
}
=======================================
--- /branches/bleeding_edge/src/v8.cc Thu Nov 8 05:44:59 2012
+++ /branches/bleeding_edge/src/v8.cc Mon Nov 26 05:12:35 2012
@@ -115,6 +115,7 @@
ElementsAccessor::TearDown();
LOperand::TearDownCaches();
+ ExternalReference::TearDownMathExpData();
RegisteredExtension::UnregisterAll();
is_running_ = false;
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.cc Thu Nov 22 02:28:29
2012
+++ /branches/bleeding_edge/src/x64/assembler-x64.cc Mon Nov 26 05:12:35
2012
@@ -2805,6 +2805,16 @@
emit(0x58);
emit_sse_operand(dst, src);
}
+
+
+void Assembler::addsd(XMMRegister dst, const Operand& src) {
+ EnsureSpace ensure_space(this);
+ emit(0xF2);
+ emit_optional_rex_32(dst, src);
+ emit(0x0F);
+ emit(0x58);
+ emit_sse_operand(dst, src);
+}
void Assembler::mulsd(XMMRegister dst, XMMRegister src) {
@@ -2815,6 +2825,16 @@
emit(0x59);
emit_sse_operand(dst, src);
}
+
+
+void Assembler::mulsd(XMMRegister dst, const Operand& src) {
+ EnsureSpace ensure_space(this);
+ emit(0xF2);
+ emit_optional_rex_32(dst, src);
+ emit(0x0F);
+ emit(0x59);
+ emit_sse_operand(dst, src);
+}
void Assembler::subsd(XMMRegister dst, XMMRegister src) {
=======================================
--- /branches/bleeding_edge/src/x64/assembler-x64.h Thu Nov 22 02:28:29 2012
+++ /branches/bleeding_edge/src/x64/assembler-x64.h Mon Nov 26 05:12:35 2012
@@ -1363,8 +1363,10 @@
void cvtsd2siq(Register dst, XMMRegister src);
void addsd(XMMRegister dst, XMMRegister src);
+ void addsd(XMMRegister dst, const Operand& src);
void subsd(XMMRegister dst, XMMRegister src);
void mulsd(XMMRegister dst, XMMRegister src);
+ void mulsd(XMMRegister dst, const Operand& src);
void divsd(XMMRegister dst, XMMRegister src);
void andpd(XMMRegister dst, XMMRegister src);
=======================================
--- /branches/bleeding_edge/src/x64/code-stubs-x64.cc Wed Nov 21 23:05:20
2012
+++ /branches/bleeding_edge/src/x64/code-stubs-x64.cc Mon Nov 26 05:12:35
2012
@@ -2221,7 +2221,7 @@
// F2XM1 calculates 2^st(0) - 1 for -1 < st(0) < 1
__ f2xm1(); // 2^(X-rnd(X)) - 1, rnd(X)
__ fld1(); // 1, 2^(X-rnd(X)) - 1, rnd(X)
- __ faddp(1); // 1, 2^(X-rnd(X)), rnd(X)
+ __ faddp(1); // 2^(X-rnd(X)), rnd(X)
// FSCALE calculates st(0) * 2^st(1)
__ fscale(); // 2^X, rnd(X)
__ fstp(1);
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.cc Thu Nov 15 05:31:27 2012
+++ /branches/bleeding_edge/src/x64/codegen-x64.cc Mon Nov 26 05:12:35 2012
@@ -97,6 +97,36 @@
OS::ProtectCode(buffer, actual_size);
return FUNCTION_CAST<UnaryMathFunction>(buffer);
}
+
+
+UnaryMathFunction CreateExpFunction() {
+ if (!FLAG_fast_math) return &exp;
+ size_t actual_size;
+ byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size,
true));
+ if (buffer == NULL) return &exp;
+ ExternalReference::InitializeMathExpData();
+
+ MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
+ // xmm0: raw double input.
+ XMMRegister input = xmm0;
+ XMMRegister result = xmm1;
+ __ push(rax);
+ __ push(rbx);
+
+ MathExpGenerator::EmitMathExp(&masm, input, result, xmm2, rax, rbx);
+
+ __ pop(rbx);
+ __ pop(rax);
+ __ movsd(xmm0, result);
+ __ Ret();
+
+ CodeDesc desc;
+ masm.GetCode(&desc);
+
+ CPU::FlushICache(buffer, actual_size);
+ OS::ProtectCode(buffer, actual_size);
+ return FUNCTION_CAST<UnaryMathFunction>(buffer);
+}
UnaryMathFunction CreateSqrtFunction() {
@@ -574,6 +604,58 @@
SeqOneByteString::kHeaderSize));
__ bind(&done);
}
+
+
+void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
+ XMMRegister input,
+ XMMRegister result,
+ XMMRegister double_scratch,
+ Register temp1,
+ Register temp2) {
+ ASSERT(!input.is(result));
+ ASSERT(!input.is(double_scratch));
+ ASSERT(!result.is(double_scratch));
+ ASSERT(!temp1.is(temp2));
+ ASSERT(ExternalReference::math_exp_constants(0).address() != NULL);
+
+ Label done;
+
+ __ movq(kScratchRegister, ExternalReference::math_exp_constants(0));
+ __ movsd(double_scratch, Operand(kScratchRegister, 0 * kDoubleSize));
+ __ xorpd(result, result);
+ __ ucomisd(double_scratch, input);
+ __ j(above_equal, &done);
+ __ ucomisd(input, Operand(kScratchRegister, 1 * kDoubleSize));
+ __ movsd(result, Operand(kScratchRegister, 2 * kDoubleSize));
+ __ j(above_equal, &done);
+ __ movsd(double_scratch, Operand(kScratchRegister, 3 * kDoubleSize));
+ __ movsd(result, Operand(kScratchRegister, 4 * kDoubleSize));
+ __ mulsd(double_scratch, input);
+ __ addsd(double_scratch, result);
+ __ movq(temp2, double_scratch);
+ __ subsd(double_scratch, result);
+ __ movsd(result, Operand(kScratchRegister, 6 * kDoubleSize));
+ __ lea(temp1, Operand(temp2, 0x1ff800));
+ __ and_(temp2, Immediate(0x7ff));
+ __ shr(temp1, Immediate(11));
+ __ mulsd(double_scratch, Operand(kScratchRegister, 5 * kDoubleSize));
+ __ movq(kScratchRegister, ExternalReference::math_exp_log_table());
+ __ shl(temp1, Immediate(52));
+ __ or_(temp1, Operand(kScratchRegister, temp2, times_8, 0));
+ __ movq(kScratchRegister, ExternalReference::math_exp_constants(0));
+ __ subsd(double_scratch, input);
+ __ movsd(input, double_scratch);
+ __ subsd(result, double_scratch);
+ __ mulsd(input, double_scratch);
+ __ mulsd(result, input);
+ __ movq(input, temp1);
+ __ mulsd(result, Operand(kScratchRegister, 7 * kDoubleSize));
+ __ subsd(result, double_scratch);
+ __ addsd(result, Operand(kScratchRegister, 8 * kDoubleSize));
+ __ mulsd(result, input);
+
+ __ bind(&done);
+}
#undef __
=======================================
--- /branches/bleeding_edge/src/x64/codegen-x64.h Thu Nov 8 04:18:11 2012
+++ /branches/bleeding_edge/src/x64/codegen-x64.h Mon Nov 26 05:12:35 2012
@@ -86,6 +86,20 @@
DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator);
};
+
+class MathExpGenerator : public AllStatic {
+ public:
+ static void EmitMathExp(MacroAssembler* masm,
+ XMMRegister input,
+ XMMRegister result,
+ XMMRegister double_scratch,
+ Register temp1,
+ Register temp2);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
+};
+
} } // namespace v8::internal
#endif // V8_X64_CODEGEN_X64_H_
=======================================
--- /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Fri Nov 23
02:53:03 2012
+++ /branches/bleeding_edge/src/x64/lithium-codegen-x64.cc Mon Nov 26
05:12:35 2012
@@ -3475,6 +3475,16 @@
__ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset));
// Return value is in rax.
}
+
+
+void LCodeGen::DoMathExp(LMathExp* instr) {
+ XMMRegister input = ToDoubleRegister(instr->value());
+ XMMRegister result = ToDoubleRegister(instr->result());
+ Register temp1 = ToRegister(instr->temp1());
+ Register temp2 = ToRegister(instr->temp2());
+
+ MathExpGenerator::EmitMathExp(masm(), input, result, xmm0, temp1, temp2);
+}
void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.cc Thu Nov 22 02:19:05 2012
+++ /branches/bleeding_edge/src/x64/lithium-x64.cc Mon Nov 26 05:12:35 2012
@@ -297,6 +297,11 @@
stream->Add("/%s ", hydrogen()->OpName());
value()->PrintTo(stream);
}
+
+
+void LMathExp::PrintDataTo(StringStream* stream) {
+ value()->PrintTo(stream);
+}
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
@@ -1046,6 +1051,14 @@
LOperand* input = UseFixedDouble(instr->value(), xmm1);
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input);
return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
+ } else if (op == kMathExp) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->value()->representation().IsDouble());
+ LOperand* value = UseTempRegister(instr->value());
+ LOperand* temp1 = TempRegister();
+ LOperand* temp2 = TempRegister();
+ LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
+ return DefineAsRegister(result);
} else {
LOperand* input = UseRegisterAtStart(instr->value());
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input);
=======================================
--- /branches/bleeding_edge/src/x64/lithium-x64.h Thu Nov 22 02:19:05 2012
+++ /branches/bleeding_edge/src/x64/lithium-x64.h Mon Nov 26 05:12:35 2012
@@ -131,6 +131,7 @@
V(LoadNamedField) \
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
+ V(MathExp) \
V(MathFloorOfDiv) \
V(MathMinMax) \
V(ModI) \
@@ -643,6 +644,25 @@
};
+class LMathExp: public LTemplateInstruction<1, 1, 2> {
+ public:
+ LMathExp(LOperand* value, LOperand* temp1, LOperand* temp2) {
+ inputs_[0] = value;
+ temps_[0] = temp1;
+ temps_[1] = temp2;
+ ExternalReference::InitializeMathExpData();
+ }
+
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp1() { return temps_[0]; }
+ LOperand* temp2() { return temps_[1]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+
+ virtual void PrintDataTo(StringStream* stream);
+};
+
+
class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> {
public:
LCmpObjectEqAndBranch(LOperand* left, LOperand* right) {
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev