[builtins] Introduce proper Float64Exp operator.
Import base::ieee754::exp() from FreeBSD msun and introduce a Float64Exp TurboFan operator based on that, similar to what we do for Float64Log. Rewrite Math.exp() as TurboFan builtin and use that operator to also inline Math.exp() into optimized TurboFan functions. BUG=v8:3266,v8:3468,v8:3493,v8:5086,v8:5108 R=mvstanton@chromium.org Review-Url: https://codereview.chromium.org/2077533002 Cr-Commit-Position: refs/heads/master@{#37037}
This commit is contained in:
parent
b16d51efa9
commit
93e26314af
@ -16,68 +16,6 @@ namespace internal {
|
||||
|
||||
#define __ masm.
|
||||
|
||||
|
||||
#if defined(USE_SIMULATOR)
|
||||
byte* fast_exp_arm_machine_code = nullptr;
|
||||
double fast_exp_simulator(double x, Isolate* isolate) {
|
||||
return Simulator::current(isolate)
|
||||
->CallFPReturnsDouble(fast_exp_arm_machine_code, x, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
|
||||
size_t actual_size;
|
||||
byte* buffer =
|
||||
static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
|
||||
if (buffer == nullptr) return nullptr;
|
||||
ExternalReference::InitializeMathExpData();
|
||||
|
||||
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
|
||||
CodeObjectRequired::kNo);
|
||||
|
||||
{
|
||||
DwVfpRegister input = d0;
|
||||
DwVfpRegister result = d1;
|
||||
DwVfpRegister double_scratch1 = d2;
|
||||
DwVfpRegister 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);
|
||||
DCHECK(!RelocInfo::RequiresRelocation(desc));
|
||||
|
||||
Assembler::FlushICache(isolate, buffer, actual_size);
|
||||
base::OS::ProtectCode(buffer, actual_size);
|
||||
|
||||
#if !defined(USE_SIMULATOR)
|
||||
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
|
||||
#else
|
||||
fast_exp_arm_machine_code = buffer;
|
||||
return &fast_exp_simulator;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(V8_HOST_ARCH_ARM)
|
||||
MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
|
||||
MemCopyUint8Function stub) {
|
||||
@ -794,94 +732,6 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm,
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
static MemOperand ExpConstant(int index, Register base) {
|
||||
return MemOperand(base, index * kDoubleSize);
|
||||
}
|
||||
|
||||
|
||||
void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
|
||||
DwVfpRegister input,
|
||||
DwVfpRegister result,
|
||||
DwVfpRegister double_scratch1,
|
||||
DwVfpRegister double_scratch2,
|
||||
Register temp1,
|
||||
Register temp2,
|
||||
Register temp3) {
|
||||
DCHECK(!input.is(result));
|
||||
DCHECK(!input.is(double_scratch1));
|
||||
DCHECK(!input.is(double_scratch2));
|
||||
DCHECK(!result.is(double_scratch1));
|
||||
DCHECK(!result.is(double_scratch2));
|
||||
DCHECK(!double_scratch1.is(double_scratch2));
|
||||
DCHECK(!temp1.is(temp2));
|
||||
DCHECK(!temp1.is(temp3));
|
||||
DCHECK(!temp2.is(temp3));
|
||||
DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
|
||||
DCHECK(!masm->serializer_enabled()); // External references not serializable.
|
||||
|
||||
Label zero, infinity, done;
|
||||
|
||||
__ mov(temp3, Operand(ExternalReference::math_exp_constants(0)));
|
||||
|
||||
__ vldr(double_scratch1, ExpConstant(0, temp3));
|
||||
__ VFPCompareAndSetFlags(double_scratch1, input);
|
||||
__ b(ge, &zero);
|
||||
|
||||
__ vldr(double_scratch2, ExpConstant(1, temp3));
|
||||
__ VFPCompareAndSetFlags(input, double_scratch2);
|
||||
__ b(ge, &infinity);
|
||||
|
||||
__ vldr(double_scratch1, ExpConstant(3, temp3));
|
||||
__ vldr(result, ExpConstant(4, temp3));
|
||||
__ vmul(double_scratch1, double_scratch1, input);
|
||||
__ vadd(double_scratch1, double_scratch1, result);
|
||||
__ VmovLow(temp2, 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(double_scratch2, double_scratch1, double_scratch1);
|
||||
__ vmul(result, result, double_scratch2);
|
||||
__ vldr(double_scratch2, ExpConstant(7, temp3));
|
||||
__ vmul(result, result, double_scratch2);
|
||||
__ vsub(result, result, double_scratch1);
|
||||
// Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
|
||||
DCHECK(*reinterpret_cast<double*>
|
||||
(ExternalReference::math_exp_constants(8).address()) == 1);
|
||||
__ vmov(double_scratch2, 1);
|
||||
__ vadd(result, result, double_scratch2);
|
||||
__ mov(temp1, Operand(temp2, LSR, 11));
|
||||
__ Ubfx(temp2, temp2, 0, 11);
|
||||
__ add(temp1, temp1, Operand(0x3ff));
|
||||
|
||||
// Must not call ExpConstant() after overwriting temp3!
|
||||
__ mov(temp3, Operand(ExternalReference::math_exp_log_table()));
|
||||
__ add(temp3, temp3, Operand(temp2, LSL, 3));
|
||||
__ ldm(ia, temp3, temp2.bit() | temp3.bit());
|
||||
// The first word is loaded is the lower number register.
|
||||
if (temp2.code() < temp3.code()) {
|
||||
__ orr(temp1, temp3, Operand(temp1, LSL, 20));
|
||||
__ vmov(double_scratch1, temp2, temp1);
|
||||
} else {
|
||||
__ orr(temp1, temp2, Operand(temp1, LSL, 20));
|
||||
__ vmov(double_scratch1, temp3, temp1);
|
||||
}
|
||||
__ vmul(result, result, double_scratch1);
|
||||
__ b(&done);
|
||||
|
||||
__ bind(&zero);
|
||||
__ vmov(result, kDoubleRegZero);
|
||||
__ b(&done);
|
||||
|
||||
__ bind(&infinity);
|
||||
__ vldr(result, ExpConstant(2, temp3));
|
||||
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -28,22 +28,6 @@ class StringCharLoadGenerator : public AllStatic {
|
||||
};
|
||||
|
||||
|
||||
class MathExpGenerator : public AllStatic {
|
||||
public:
|
||||
// Register input isn't modified. All other registers are clobbered.
|
||||
static void EmitMathExp(MacroAssembler* masm,
|
||||
DwVfpRegister input,
|
||||
DwVfpRegister result,
|
||||
DwVfpRegister double_scratch1,
|
||||
DwVfpRegister double_scratch2,
|
||||
Register temp1,
|
||||
Register temp2,
|
||||
Register temp3);
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -15,66 +15,6 @@ namespace internal {
|
||||
|
||||
#define __ ACCESS_MASM(masm)
|
||||
|
||||
#if defined(USE_SIMULATOR)
|
||||
byte* fast_exp_arm64_machine_code = nullptr;
|
||||
double fast_exp_simulator(double x, Isolate* isolate) {
|
||||
Simulator * simulator = Simulator::current(isolate);
|
||||
Simulator::CallArgument args[] = {
|
||||
Simulator::CallArgument(x),
|
||||
Simulator::CallArgument::End()
|
||||
};
|
||||
return simulator->CallDouble(fast_exp_arm64_machine_code, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
|
||||
// Use the Math.exp implemetation in MathExpGenerator::EmitMathExp() to create
|
||||
// an AAPCS64-compliant exp() function. This will be faster than the C
|
||||
// library's exp() function, but probably less accurate.
|
||||
size_t actual_size;
|
||||
byte* buffer =
|
||||
static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
|
||||
if (buffer == nullptr) return nullptr;
|
||||
|
||||
ExternalReference::InitializeMathExpData();
|
||||
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
|
||||
CodeObjectRequired::kNo);
|
||||
masm.SetStackPointer(csp);
|
||||
|
||||
// The argument will be in d0 on entry.
|
||||
DoubleRegister input = d0;
|
||||
// Use other caller-saved registers for all other values.
|
||||
DoubleRegister result = d1;
|
||||
DoubleRegister double_temp1 = d2;
|
||||
DoubleRegister double_temp2 = d3;
|
||||
Register temp1 = x10;
|
||||
Register temp2 = x11;
|
||||
Register temp3 = x12;
|
||||
|
||||
MathExpGenerator::EmitMathExp(&masm, input, result,
|
||||
double_temp1, double_temp2,
|
||||
temp1, temp2, temp3);
|
||||
// Move the result to the return register.
|
||||
masm.Fmov(d0, result);
|
||||
masm.Ret();
|
||||
|
||||
CodeDesc desc;
|
||||
masm.GetCode(&desc);
|
||||
DCHECK(!RelocInfo::RequiresRelocation(desc));
|
||||
|
||||
Assembler::FlushICache(isolate, buffer, actual_size);
|
||||
base::OS::ProtectCode(buffer, actual_size);
|
||||
|
||||
#if !defined(USE_SIMULATOR)
|
||||
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
|
||||
#else
|
||||
fast_exp_arm64_machine_code = buffer;
|
||||
return &fast_exp_simulator;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -510,127 +450,6 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm,
|
||||
__ Bind(&done);
|
||||
}
|
||||
|
||||
|
||||
static MemOperand ExpConstant(Register base, int index) {
|
||||
return MemOperand(base, index * kDoubleSize);
|
||||
}
|
||||
|
||||
|
||||
void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
|
||||
DoubleRegister input,
|
||||
DoubleRegister result,
|
||||
DoubleRegister double_temp1,
|
||||
DoubleRegister double_temp2,
|
||||
Register temp1,
|
||||
Register temp2,
|
||||
Register temp3) {
|
||||
// TODO(jbramley): There are several instances where fnmsub could be used
|
||||
// instead of fmul and fsub. Doing this changes the result, but since this is
|
||||
// an estimation anyway, does it matter?
|
||||
|
||||
DCHECK(!AreAliased(input, result,
|
||||
double_temp1, double_temp2,
|
||||
temp1, temp2, temp3));
|
||||
DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
|
||||
DCHECK(!masm->serializer_enabled()); // External references not serializable.
|
||||
|
||||
Label done;
|
||||
DoubleRegister double_temp3 = result;
|
||||
Register constants = temp3;
|
||||
|
||||
// The algorithm used relies on some magic constants which are initialized in
|
||||
// ExternalReference::InitializeMathExpData().
|
||||
|
||||
// Load the address of the start of the array.
|
||||
__ Mov(constants, ExternalReference::math_exp_constants(0));
|
||||
|
||||
// We have to do a four-way split here:
|
||||
// - If input <= about -708.4, the output always rounds to zero.
|
||||
// - If input >= about 709.8, the output always rounds to +infinity.
|
||||
// - If the input is NaN, the output is NaN.
|
||||
// - Otherwise, the result needs to be calculated.
|
||||
Label result_is_finite_non_zero;
|
||||
// Assert that we can load offset 0 (the small input threshold) and offset 1
|
||||
// (the large input threshold) with a single ldp.
|
||||
DCHECK(kDRegSize == (ExpConstant(constants, 1).offset() -
|
||||
ExpConstant(constants, 0).offset()));
|
||||
__ Ldp(double_temp1, double_temp2, ExpConstant(constants, 0));
|
||||
|
||||
__ Fcmp(input, double_temp1);
|
||||
__ Fccmp(input, double_temp2, NoFlag, hi);
|
||||
// At this point, the condition flags can be in one of five states:
|
||||
// NZCV
|
||||
// 1000 -708.4 < input < 709.8 result = exp(input)
|
||||
// 0110 input == 709.8 result = +infinity
|
||||
// 0010 input > 709.8 result = +infinity
|
||||
// 0011 input is NaN result = input
|
||||
// 0000 input <= -708.4 result = +0.0
|
||||
|
||||
// Continue the common case first. 'mi' tests N == 1.
|
||||
__ B(&result_is_finite_non_zero, mi);
|
||||
|
||||
// TODO(jbramley): Consider adding a +infinity register for ARM64.
|
||||
__ Ldr(double_temp2, ExpConstant(constants, 2)); // Synthesize +infinity.
|
||||
|
||||
// Select between +0.0 and +infinity. 'lo' tests C == 0.
|
||||
__ Fcsel(result, fp_zero, double_temp2, lo);
|
||||
// Select between {+0.0 or +infinity} and input. 'vc' tests V == 0.
|
||||
__ Fcsel(result, result, input, vc);
|
||||
__ B(&done);
|
||||
|
||||
// The rest is magic, as described in InitializeMathExpData().
|
||||
__ Bind(&result_is_finite_non_zero);
|
||||
|
||||
// Assert that we can load offset 3 and offset 4 with a single ldp.
|
||||
DCHECK(kDRegSize == (ExpConstant(constants, 4).offset() -
|
||||
ExpConstant(constants, 3).offset()));
|
||||
__ Ldp(double_temp1, double_temp3, ExpConstant(constants, 3));
|
||||
__ Fmadd(double_temp1, double_temp1, input, double_temp3);
|
||||
__ Fmov(temp2.W(), double_temp1.S());
|
||||
__ Fsub(double_temp1, double_temp1, double_temp3);
|
||||
|
||||
// Assert that we can load offset 5 and offset 6 with a single ldp.
|
||||
DCHECK(kDRegSize == (ExpConstant(constants, 6).offset() -
|
||||
ExpConstant(constants, 5).offset()));
|
||||
__ Ldp(double_temp2, double_temp3, ExpConstant(constants, 5));
|
||||
// TODO(jbramley): Consider using Fnmsub here.
|
||||
__ Fmul(double_temp1, double_temp1, double_temp2);
|
||||
__ Fsub(double_temp1, double_temp1, input);
|
||||
|
||||
__ Fmul(double_temp2, double_temp1, double_temp1);
|
||||
__ Fsub(double_temp3, double_temp3, double_temp1);
|
||||
__ Fmul(double_temp3, double_temp3, double_temp2);
|
||||
|
||||
__ Mov(temp1.W(), Operand(temp2.W(), LSR, 11));
|
||||
|
||||
__ Ldr(double_temp2, ExpConstant(constants, 7));
|
||||
// TODO(jbramley): Consider using Fnmsub here.
|
||||
__ Fmul(double_temp3, double_temp3, double_temp2);
|
||||
__ Fsub(double_temp3, double_temp3, double_temp1);
|
||||
|
||||
// The 8th constant is 1.0, so use an immediate move rather than a load.
|
||||
// We can't generate a runtime assertion here as we would need to call Abort
|
||||
// in the runtime and we don't have an Isolate when we generate this code.
|
||||
__ Fmov(double_temp2, 1.0);
|
||||
__ Fadd(double_temp3, double_temp3, double_temp2);
|
||||
|
||||
__ And(temp2, temp2, 0x7ff);
|
||||
__ Add(temp1, temp1, 0x3ff);
|
||||
|
||||
// Do the final table lookup.
|
||||
__ Mov(temp3, ExternalReference::math_exp_log_table());
|
||||
|
||||
__ Add(temp3, temp3, Operand(temp2, LSL, kDRegSizeLog2));
|
||||
__ Ldp(temp2.W(), temp3.W(), MemOperand(temp3));
|
||||
__ Orr(temp1.W(), temp3.W(), Operand(temp1.W(), LSL, 20));
|
||||
__ Bfi(temp2, temp1, 32, 32);
|
||||
__ Fmov(double_temp1, temp2);
|
||||
|
||||
__ Fmul(result, double_temp3, double_temp1);
|
||||
|
||||
__ Bind(&done);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
} // namespace internal
|
||||
|
@ -27,22 +27,6 @@ class StringCharLoadGenerator : public AllStatic {
|
||||
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 internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -178,11 +178,6 @@ static DoubleConstant double_constants;
|
||||
|
||||
const char* const RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING";
|
||||
|
||||
static bool math_exp_data_initialized = false;
|
||||
static base::Mutex* math_exp_data_mutex = NULL;
|
||||
static double* math_exp_constants_array = NULL;
|
||||
static double* math_exp_log_table_array = NULL;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Implementation of AssemblerBase
|
||||
|
||||
@ -1006,61 +1001,6 @@ void ExternalReference::SetUp() {
|
||||
double_constants.negative_infinity = -V8_INFINITY;
|
||||
double_constants.uint32_bias =
|
||||
static_cast<double>(static_cast<uint32_t>(0xFFFFFFFF)) + 1;
|
||||
|
||||
math_exp_data_mutex = new base::Mutex();
|
||||
}
|
||||
|
||||
|
||||
void ExternalReference::InitializeMathExpData() {
|
||||
// Early return?
|
||||
if (math_exp_data_initialized) return;
|
||||
|
||||
base::LockGuard<base::Mutex> lock_guard(math_exp_data_mutex);
|
||||
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) / base::ieee754::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 = std::pow(2, i / kTableSizeDouble);
|
||||
uint64_t bits = bit_cast<uint64_t, double>(value);
|
||||
bits &= (static_cast<uint64_t>(1) << 52) - 1;
|
||||
double mantissa = bit_cast<double, uint64_t>(bits);
|
||||
math_exp_log_table_array[i] = mantissa;
|
||||
}
|
||||
|
||||
math_exp_data_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ExternalReference::TearDownMathExpData() {
|
||||
delete[] math_exp_constants_array;
|
||||
math_exp_constants_array = NULL;
|
||||
delete[] math_exp_log_table_array;
|
||||
math_exp_log_table_array = NULL;
|
||||
delete math_exp_data_mutex;
|
||||
math_exp_data_mutex = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -1353,7 +1293,7 @@ ExternalReference ExternalReference::f64_tan_wrapper_function(
|
||||
}
|
||||
|
||||
static void f64_exp_wrapper(double* param) {
|
||||
WriteDoubleValue(param, std::exp(ReadDoubleValue(param)));
|
||||
WriteDoubleValue(param, base::ieee754::exp(ReadDoubleValue(param)));
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::f64_exp_wrapper_function(
|
||||
@ -1628,6 +1568,11 @@ ExternalReference ExternalReference::ieee754_atan2_function(Isolate* isolate) {
|
||||
isolate, FUNCTION_ADDR(base::ieee754::atan2), BUILTIN_FP_FP_CALL));
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::ieee754_exp_function(Isolate* isolate) {
|
||||
return ExternalReference(
|
||||
Redirect(isolate, FUNCTION_ADDR(base::ieee754::exp), BUILTIN_FP_CALL));
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::ieee754_log_function(Isolate* isolate) {
|
||||
return ExternalReference(
|
||||
Redirect(isolate, FUNCTION_ADDR(base::ieee754::log), BUILTIN_FP_CALL));
|
||||
@ -1648,19 +1593,6 @@ ExternalReference ExternalReference::ieee754_log10_function(Isolate* isolate) {
|
||||
Redirect(isolate, FUNCTION_ADDR(base::ieee754::log10), BUILTIN_FP_CALL));
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::math_exp_constants(int constant_index) {
|
||||
DCHECK(math_exp_data_initialized);
|
||||
return ExternalReference(
|
||||
reinterpret_cast<void*>(math_exp_constants_array + constant_index));
|
||||
}
|
||||
|
||||
|
||||
ExternalReference ExternalReference::math_exp_log_table() {
|
||||
DCHECK(math_exp_data_initialized);
|
||||
return ExternalReference(reinterpret_cast<void*>(math_exp_log_table_array));
|
||||
}
|
||||
|
||||
|
||||
ExternalReference ExternalReference::page_flags(Page* page) {
|
||||
return ExternalReference(reinterpret_cast<Address>(page) +
|
||||
MemoryChunk::kFlagsOffset);
|
||||
|
@ -897,8 +897,6 @@ class ExternalReference BASE_EMBEDDED {
|
||||
};
|
||||
|
||||
static void SetUp();
|
||||
static void InitializeMathExpData();
|
||||
static void TearDownMathExpData();
|
||||
|
||||
typedef void* ExternalReferenceRedirector(Isolate* isolate, void* original,
|
||||
Type type);
|
||||
@ -1044,14 +1042,12 @@ class ExternalReference BASE_EMBEDDED {
|
||||
// IEEE 754 functions.
|
||||
static ExternalReference ieee754_atan_function(Isolate* isolate);
|
||||
static ExternalReference ieee754_atan2_function(Isolate* isolate);
|
||||
static ExternalReference ieee754_exp_function(Isolate* isolate);
|
||||
static ExternalReference ieee754_log_function(Isolate* isolate);
|
||||
static ExternalReference ieee754_log1p_function(Isolate* isolate);
|
||||
static ExternalReference ieee754_log2_function(Isolate* isolate);
|
||||
static ExternalReference ieee754_log10_function(Isolate* isolate);
|
||||
|
||||
static ExternalReference math_exp_constants(int constant_index);
|
||||
static ExternalReference math_exp_log_table();
|
||||
|
||||
static ExternalReference page_flags(Page* page);
|
||||
|
||||
static ExternalReference ForDeoptEntry(Address entry);
|
||||
|
@ -392,6 +392,152 @@ double atan2(double y, double x) {
|
||||
}
|
||||
}
|
||||
|
||||
/* exp(x)
|
||||
* Returns the exponential of x.
|
||||
*
|
||||
* Method
|
||||
* 1. Argument reduction:
|
||||
* Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
|
||||
* Given x, find r and integer k such that
|
||||
*
|
||||
* x = k*ln2 + r, |r| <= 0.5*ln2.
|
||||
*
|
||||
* Here r will be represented as r = hi-lo for better
|
||||
* accuracy.
|
||||
*
|
||||
* 2. Approximation of exp(r) by a special rational function on
|
||||
* the interval [0,0.34658]:
|
||||
* Write
|
||||
* R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
|
||||
* We use a special Remes algorithm on [0,0.34658] to generate
|
||||
* a polynomial of degree 5 to approximate R. The maximum error
|
||||
* of this polynomial approximation is bounded by 2**-59. In
|
||||
* other words,
|
||||
* R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
|
||||
* (where z=r*r, and the values of P1 to P5 are listed below)
|
||||
* and
|
||||
* | 5 | -59
|
||||
* | 2.0+P1*z+...+P5*z - R(z) | <= 2
|
||||
* | |
|
||||
* The computation of exp(r) thus becomes
|
||||
* 2*r
|
||||
* exp(r) = 1 + -------
|
||||
* R - r
|
||||
* r*R1(r)
|
||||
* = 1 + r + ----------- (for better accuracy)
|
||||
* 2 - R1(r)
|
||||
* where
|
||||
* 2 4 10
|
||||
* R1(r) = r - (P1*r + P2*r + ... + P5*r ).
|
||||
*
|
||||
* 3. Scale back to obtain exp(x):
|
||||
* From step 1, we have
|
||||
* exp(x) = 2^k * exp(r)
|
||||
*
|
||||
* Special cases:
|
||||
* exp(INF) is INF, exp(NaN) is NaN;
|
||||
* exp(-INF) is 0, and
|
||||
* for finite argument, only exp(0)=1 is exact.
|
||||
*
|
||||
* Accuracy:
|
||||
* according to an error analysis, the error is always less than
|
||||
* 1 ulp (unit in the last place).
|
||||
*
|
||||
* Misc. info.
|
||||
* For IEEE double
|
||||
* if x > 7.09782712893383973096e+02 then exp(x) overflow
|
||||
* if x < -7.45133219101941108420e+02 then exp(x) underflow
|
||||
*
|
||||
* Constants:
|
||||
* The hexadecimal values are the intended ones for the following
|
||||
* constants. The decimal values may be used, provided that the
|
||||
* compiler will convert from decimal to binary accurately enough
|
||||
* to produce the hexadecimal values shown.
|
||||
*/
|
||||
double exp(double x) {
|
||||
static const double
|
||||
one = 1.0,
|
||||
halF[2] = {0.5, -0.5},
|
||||
o_threshold = 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
|
||||
u_threshold = -7.45133219101941108420e+02, /* 0xc0874910, 0xD52D3051 */
|
||||
ln2HI[2] = {6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */
|
||||
-6.93147180369123816490e-01}, /* 0xbfe62e42, 0xfee00000 */
|
||||
ln2LO[2] = {1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */
|
||||
-1.90821492927058770002e-10}, /* 0xbdea39ef, 0x35793c76 */
|
||||
invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
|
||||
P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
|
||||
P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
|
||||
P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
|
||||
P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
|
||||
P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
|
||||
|
||||
static volatile double
|
||||
huge = 1.0e+300,
|
||||
twom1000 = 9.33263618503218878990e-302, /* 2**-1000=0x01700000,0*/
|
||||
two1023 = 8.988465674311579539e307; /* 0x1p1023 */
|
||||
|
||||
double y, hi = 0.0, lo = 0.0, c, t, twopk;
|
||||
int32_t k = 0, xsb;
|
||||
u_int32_t hx;
|
||||
|
||||
GET_HIGH_WORD(hx, x);
|
||||
xsb = (hx >> 31) & 1; /* sign bit of x */
|
||||
hx &= 0x7fffffff; /* high word of |x| */
|
||||
|
||||
/* filter out non-finite argument */
|
||||
if (hx >= 0x40862E42) { /* if |x|>=709.78... */
|
||||
if (hx >= 0x7ff00000) {
|
||||
u_int32_t lx;
|
||||
GET_LOW_WORD(lx, x);
|
||||
if (((hx & 0xfffff) | lx) != 0)
|
||||
return x + x; /* NaN */
|
||||
else
|
||||
return (xsb == 0) ? x : 0.0; /* exp(+-inf)={inf,0} */
|
||||
}
|
||||
if (x > o_threshold) return huge * huge; /* overflow */
|
||||
if (x < u_threshold) return twom1000 * twom1000; /* underflow */
|
||||
}
|
||||
|
||||
/* argument reduction */
|
||||
if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
|
||||
if (hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
|
||||
hi = x - ln2HI[xsb];
|
||||
lo = ln2LO[xsb];
|
||||
k = 1 - xsb - xsb;
|
||||
} else {
|
||||
k = static_cast<int>(invln2 * x + halF[xsb]);
|
||||
t = k;
|
||||
hi = x - t * ln2HI[0]; /* t*ln2HI is exact here */
|
||||
lo = t * ln2LO[0];
|
||||
}
|
||||
STRICT_ASSIGN(double, x, hi - lo);
|
||||
} else if (hx < 0x3e300000) { /* when |x|<2**-28 */
|
||||
if (huge + x > one) return one + x; /* trigger inexact */
|
||||
} else {
|
||||
k = 0;
|
||||
}
|
||||
|
||||
/* x is now in primary range */
|
||||
t = x * x;
|
||||
if (k >= -1021) {
|
||||
INSERT_WORDS(twopk, 0x3ff00000 + (k << 20), 0);
|
||||
} else {
|
||||
INSERT_WORDS(twopk, 0x3ff00000 + ((k + 1000) << 20), 0);
|
||||
}
|
||||
c = x - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5))));
|
||||
if (k == 0) {
|
||||
return one - ((x * c) / (c - 2.0) - x);
|
||||
} else {
|
||||
y = one - ((lo - (x * c) / (2.0 - c)) - hi);
|
||||
}
|
||||
if (k >= -1021) {
|
||||
if (k == 1024) return y * 2.0 * two1023;
|
||||
return y * twopk;
|
||||
} else {
|
||||
return y * twopk * twom1000;
|
||||
}
|
||||
}
|
||||
|
||||
/* log(x)
|
||||
* Return the logrithm of x
|
||||
*
|
||||
|
@ -17,6 +17,9 @@ double atan(double x);
|
||||
// the two arguments to determine the quadrant of the result.
|
||||
double atan2(double y, double x);
|
||||
|
||||
// Returns the base-e exponential of |x|.
|
||||
double exp(double x);
|
||||
|
||||
// Returns the natural logarithm of |x|.
|
||||
double log(double x);
|
||||
|
||||
|
@ -1676,6 +1676,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
SimpleInstallFunction(math, "atan2", Builtins::kMathAtan2, 2, true);
|
||||
SimpleInstallFunction(math, "ceil", Builtins::kMathCeil, 1, true);
|
||||
SimpleInstallFunction(math, "clz32", Builtins::kMathClz32, 1, true);
|
||||
Handle<JSFunction> math_exp =
|
||||
SimpleInstallFunction(math, "exp", Builtins::kMathExp, 1, true);
|
||||
native_context()->set_math_exp(*math_exp);
|
||||
Handle<JSFunction> math_floor =
|
||||
SimpleInstallFunction(math, "floor", Builtins::kMathFloor, 1, true);
|
||||
native_context()->set_math_floor(*math_floor);
|
||||
|
@ -2452,6 +2452,18 @@ void Builtins::Generate_MathClz32(CodeStubAssembler* assembler) {
|
||||
}
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.14 Math.exp ( x )
|
||||
void Builtins::Generate_MathExp(CodeStubAssembler* assembler) {
|
||||
using compiler::Node;
|
||||
|
||||
Node* x = assembler->Parameter(1);
|
||||
Node* context = assembler->Parameter(4);
|
||||
Node* x_value = assembler->TruncateTaggedToFloat64(context, x);
|
||||
Node* value = assembler->Float64Exp(x_value);
|
||||
Node* result = assembler->ChangeFloat64ToTagged(value);
|
||||
assembler->Return(result);
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.16 Math.floor ( x )
|
||||
void Builtins::Generate_MathFloor(CodeStubAssembler* assembler) {
|
||||
Generate_MathRoundingOperation(assembler, &CodeStubAssembler::Float64Floor);
|
||||
|
@ -320,6 +320,7 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
|
||||
V(MathAtan2, 3) \
|
||||
V(MathCeil, 2) \
|
||||
V(MathClz32, 2) \
|
||||
V(MathExp, 2) \
|
||||
V(MathFloor, 2) \
|
||||
V(MathLog, 2) \
|
||||
V(MathLog1p, 2) \
|
||||
@ -634,6 +635,8 @@ class Builtins {
|
||||
static void Generate_MathCeil(CodeStubAssembler* assembler);
|
||||
// ES6 section 20.2.2.11 Math.clz32 ( x )
|
||||
static void Generate_MathClz32(CodeStubAssembler* assembler);
|
||||
// ES6 section 20.2.2.14 Math.exp ( x )
|
||||
static void Generate_MathExp(CodeStubAssembler* assembler);
|
||||
// ES6 section 20.2.2.16 Math.floor ( x )
|
||||
static void Generate_MathFloor(CodeStubAssembler* assembler);
|
||||
// ES6 section 20.2.2.20 Math.log ( x )
|
||||
|
@ -60,7 +60,6 @@ double modulo(double x, double y) {
|
||||
}
|
||||
|
||||
UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction)
|
||||
UNARY_MATH_FUNCTION(exp, CreateExpFunction)
|
||||
|
||||
#undef UNARY_MATH_FUNCTION
|
||||
|
||||
|
@ -93,16 +93,13 @@ class CodeGenerator {
|
||||
// generated code both in runtime and compiled code.
|
||||
typedef double (*UnaryMathFunctionWithIsolate)(double x, Isolate* isolate);
|
||||
|
||||
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate);
|
||||
UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate);
|
||||
|
||||
|
||||
double modulo(double x, double y);
|
||||
|
||||
// Custom implementation of math functions.
|
||||
double fast_exp(double input, Isolate* isolate);
|
||||
double fast_sqrt(double input, Isolate* isolate);
|
||||
void lazily_initialize_fast_exp(Isolate* isolate);
|
||||
void lazily_initialize_fast_sqrt(Isolate* isolate);
|
||||
|
||||
|
||||
|
@ -709,6 +709,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kIeee754Float64Atan2:
|
||||
ASSEMBLE_IEEE754_BINOP(atan2);
|
||||
break;
|
||||
case kIeee754Float64Exp:
|
||||
ASSEMBLE_IEEE754_UNOP(exp);
|
||||
break;
|
||||
case kIeee754Float64Log:
|
||||
ASSEMBLE_IEEE754_UNOP(log);
|
||||
break;
|
||||
|
@ -813,6 +813,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kIeee754Float64Atan2:
|
||||
ASSEMBLE_IEEE754_BINOP(atan2);
|
||||
break;
|
||||
case kIeee754Float64Exp:
|
||||
ASSEMBLE_IEEE754_UNOP(exp);
|
||||
break;
|
||||
case kIeee754Float64Log:
|
||||
ASSEMBLE_IEEE754_UNOP(log);
|
||||
break;
|
||||
|
@ -108,6 +108,7 @@ class Schedule;
|
||||
|
||||
#define CODE_ASSEMBLER_UNARY_OP_LIST(V) \
|
||||
V(Float64Atan) \
|
||||
V(Float64Exp) \
|
||||
V(Float64Log) \
|
||||
V(Float64Log1p) \
|
||||
V(Float64Log2) \
|
||||
|
@ -655,6 +655,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kIeee754Float64Atan2:
|
||||
ASSEMBLE_IEEE754_BINOP(atan2);
|
||||
break;
|
||||
case kIeee754Float64Exp:
|
||||
ASSEMBLE_IEEE754_UNOP(exp);
|
||||
break;
|
||||
case kIeee754Float64Log:
|
||||
ASSEMBLE_IEEE754_UNOP(log);
|
||||
break;
|
||||
|
@ -91,6 +91,7 @@ enum class RecordWriteMode { kValueIsMap, kValueIsPointer, kValueIsAny };
|
||||
V(AtomicStoreWord32) \
|
||||
V(Ieee754Float64Atan) \
|
||||
V(Ieee754Float64Atan2) \
|
||||
V(Ieee754Float64Exp) \
|
||||
V(Ieee754Float64Log) \
|
||||
V(Ieee754Float64Log1p) \
|
||||
V(Ieee754Float64Log2) \
|
||||
|
@ -226,6 +226,7 @@ int InstructionScheduler::GetInstructionFlags(const Instruction* instr) const {
|
||||
case kArchComment:
|
||||
case kIeee754Float64Atan:
|
||||
case kIeee754Float64Atan2:
|
||||
case kIeee754Float64Exp:
|
||||
case kIeee754Float64Log:
|
||||
case kIeee754Float64Log1p:
|
||||
case kIeee754Float64Log2:
|
||||
|
@ -1138,6 +1138,8 @@ void InstructionSelector::VisitNode(Node* node) {
|
||||
return MarkAsFloat64(node), VisitFloat64Atan(node);
|
||||
case IrOpcode::kFloat64Atan2:
|
||||
return MarkAsFloat64(node), VisitFloat64Atan2(node);
|
||||
case IrOpcode::kFloat64Exp:
|
||||
return MarkAsFloat64(node), VisitFloat64Exp(node);
|
||||
case IrOpcode::kFloat64Log:
|
||||
return MarkAsFloat64(node), VisitFloat64Log(node);
|
||||
case IrOpcode::kFloat64Log1p:
|
||||
@ -1259,6 +1261,10 @@ void InstructionSelector::VisitFloat64Atan2(Node* node) {
|
||||
VisitFloat64Ieee754Binop(node, kIeee754Float64Atan2);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Exp(Node* node) {
|
||||
VisitFloat64Ieee754Unop(node, kIeee754Float64Exp);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Log(Node* node) {
|
||||
VisitFloat64Ieee754Unop(node, kIeee754Float64Log);
|
||||
}
|
||||
|
@ -142,6 +142,18 @@ Reduction JSBuiltinReducer::ReduceMathClz32(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.14 Math.exp ( x )
|
||||
Reduction JSBuiltinReducer::ReduceMathExp(Node* node) {
|
||||
JSCallReduction r(node);
|
||||
if (r.InputsMatchOne(Type::PlainPrimitive())) {
|
||||
// Math.exp(a:plain-primitive) -> NumberExp(ToNumber(a))
|
||||
Node* input = ToNumber(r.GetJSCallInput(0));
|
||||
Node* value = graph()->NewNode(simplified()->NumberExp(), input);
|
||||
return Replace(value);
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.16 Math.floor ( x )
|
||||
Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) {
|
||||
JSCallReduction r(node);
|
||||
@ -348,6 +360,9 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
|
||||
case kMathCeil:
|
||||
reduction = ReduceMathCeil(node);
|
||||
break;
|
||||
case kMathExp:
|
||||
reduction = ReduceMathExp(node);
|
||||
break;
|
||||
case kMathFloor:
|
||||
reduction = ReduceMathFloor(node);
|
||||
break;
|
||||
|
@ -33,6 +33,7 @@ class JSBuiltinReducer final : public AdvancedReducer {
|
||||
Reduction ReduceMathAtan2(Node* node);
|
||||
Reduction ReduceMathCeil(Node* node);
|
||||
Reduction ReduceMathClz32(Node* node);
|
||||
Reduction ReduceMathExp(Node* node);
|
||||
Reduction ReduceMathFloor(Node* node);
|
||||
Reduction ReduceMathFround(Node* node);
|
||||
Reduction ReduceMathImul(Node* node);
|
||||
|
@ -402,6 +402,11 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kFloat64Exp: {
|
||||
Float64Matcher m(node->InputAt(0));
|
||||
if (m.HasValue()) return ReplaceFloat64(base::ieee754::exp(m.Value()));
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kFloat64Log: {
|
||||
Float64Matcher m(node->InputAt(0));
|
||||
if (m.HasValue()) return ReplaceFloat64(base::ieee754::log(m.Value()));
|
||||
|
@ -157,6 +157,7 @@ MachineRepresentation AtomicStoreRepresentationOf(Operator const* op) {
|
||||
V(Float64Abs, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float64Atan, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float64Atan2, Operator::kNoProperties, 2, 0, 1) \
|
||||
V(Float64Exp, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float64Log, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float64Log1p, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float64Log2, Operator::kNoProperties, 1, 0, 1) \
|
||||
|
@ -372,6 +372,9 @@ class MachineOperatorBuilder final : public ZoneObject {
|
||||
const Operator* Float64Atan();
|
||||
const Operator* Float64Atan2();
|
||||
|
||||
// Floating point exponential functions.
|
||||
const Operator* Float64Exp();
|
||||
|
||||
// Floating point logarithm (double-precision).
|
||||
const Operator* Float64Log();
|
||||
const Operator* Float64Log1p();
|
||||
|
@ -747,6 +747,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kIeee754Float64Atan2:
|
||||
ASSEMBLE_IEEE754_BINOP(atan2);
|
||||
break;
|
||||
case kIeee754Float64Exp:
|
||||
ASSEMBLE_IEEE754_UNOP(exp);
|
||||
break;
|
||||
case kIeee754Float64Log:
|
||||
ASSEMBLE_IEEE754_UNOP(log);
|
||||
break;
|
||||
|
@ -756,6 +756,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kIeee754Float64Atan2:
|
||||
ASSEMBLE_IEEE754_BINOP(atan2);
|
||||
break;
|
||||
case kIeee754Float64Exp:
|
||||
ASSEMBLE_IEEE754_UNOP(exp);
|
||||
break;
|
||||
case kIeee754Float64Log:
|
||||
ASSEMBLE_IEEE754_UNOP(log);
|
||||
break;
|
||||
|
@ -203,6 +203,7 @@
|
||||
V(NumberFround) \
|
||||
V(NumberAtan) \
|
||||
V(NumberAtan2) \
|
||||
V(NumberExp) \
|
||||
V(NumberLog) \
|
||||
V(NumberLog1p) \
|
||||
V(NumberLog2) \
|
||||
@ -371,6 +372,7 @@
|
||||
V(Float64Abs) \
|
||||
V(Float64Atan) \
|
||||
V(Float64Atan2) \
|
||||
V(Float64Exp) \
|
||||
V(Float64Log) \
|
||||
V(Float64Log1p) \
|
||||
V(Float64Log2) \
|
||||
|
@ -464,6 +464,7 @@ class RawMachineAssembler {
|
||||
Node* Float64Atan2(Node* a, Node* b) {
|
||||
return AddNode(machine()->Float64Atan2(), a, b);
|
||||
}
|
||||
Node* Float64Exp(Node* a) { return AddNode(machine()->Float64Exp(), a); }
|
||||
Node* Float64Log(Node* a) { return AddNode(machine()->Float64Log(), a); }
|
||||
Node* Float64Log1p(Node* a) { return AddNode(machine()->Float64Log1p(), a); }
|
||||
Node* Float64Log2(Node* a) { return AddNode(machine()->Float64Log2(), a); }
|
||||
|
@ -671,6 +671,8 @@ const Operator* RepresentationChanger::Float64OperatorFor(
|
||||
return machine()->Float64Atan();
|
||||
case IrOpcode::kNumberAtan2:
|
||||
return machine()->Float64Atan2();
|
||||
case IrOpcode::kNumberExp:
|
||||
return machine()->Float64Exp();
|
||||
case IrOpcode::kNumberFround:
|
||||
return machine()->TruncateFloat64ToFloat32();
|
||||
case IrOpcode::kNumberLog:
|
||||
|
@ -1442,6 +1442,7 @@ class RepresentationSelector {
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kNumberAtan:
|
||||
case IrOpcode::kNumberExp:
|
||||
case IrOpcode::kNumberLog:
|
||||
case IrOpcode::kNumberLog1p:
|
||||
case IrOpcode::kNumberLog2:
|
||||
|
@ -254,6 +254,7 @@ CompareOperationHints::Hint CompareOperationHintOf(const Operator* op) {
|
||||
V(NumberFround, Operator::kNoProperties, 1) \
|
||||
V(NumberAtan, Operator::kNoProperties, 1) \
|
||||
V(NumberAtan2, Operator::kNoProperties, 2) \
|
||||
V(NumberExp, Operator::kNoProperties, 1) \
|
||||
V(NumberLog, Operator::kNoProperties, 1) \
|
||||
V(NumberLog1p, Operator::kNoProperties, 1) \
|
||||
V(NumberLog2, Operator::kNoProperties, 1) \
|
||||
|
@ -181,6 +181,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
|
||||
const Operator* NumberFround();
|
||||
const Operator* NumberAtan();
|
||||
const Operator* NumberAtan2();
|
||||
const Operator* NumberExp();
|
||||
const Operator* NumberLog();
|
||||
const Operator* NumberLog1p();
|
||||
const Operator* NumberLog2();
|
||||
|
@ -1543,9 +1543,10 @@ Type* Typer::Visitor::JSCallFunctionTyper(Type* fun, Typer* t) {
|
||||
case kMathTrunc:
|
||||
return t->cache_.kIntegerOrMinusZeroOrNaN;
|
||||
// Unary math functions.
|
||||
case kMathExp:
|
||||
return Type::Union(Type::PlainNumber(), Type::NaN(), t->zone());
|
||||
case kMathAbs:
|
||||
case kMathLog:
|
||||
case kMathExp:
|
||||
case kMathSqrt:
|
||||
case kMathCos:
|
||||
case kMathSin:
|
||||
@ -1800,6 +1801,10 @@ Type* Typer::Visitor::TypeNumberAtan(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeNumberAtan2(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeNumberExp(Node* node) {
|
||||
return Type::Union(Type::PlainNumber(), Type::NaN(), zone());
|
||||
}
|
||||
|
||||
Type* Typer::Visitor::TypeNumberLog(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeNumberLog1p(Node* node) { return Type::Number(); }
|
||||
@ -2559,6 +2564,8 @@ Type* Typer::Visitor::TypeFloat64Atan(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeFloat64Atan2(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeFloat64Exp(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeFloat64Log(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeFloat64Log1p(Node* node) { return Type::Number(); }
|
||||
|
@ -753,6 +753,7 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
case IrOpcode::kNumberFloor:
|
||||
case IrOpcode::kNumberFround:
|
||||
case IrOpcode::kNumberAtan:
|
||||
case IrOpcode::kNumberExp:
|
||||
case IrOpcode::kNumberLog:
|
||||
case IrOpcode::kNumberLog1p:
|
||||
case IrOpcode::kNumberLog2:
|
||||
@ -1070,6 +1071,7 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
case IrOpcode::kFloat64Abs:
|
||||
case IrOpcode::kFloat64Atan:
|
||||
case IrOpcode::kFloat64Atan2:
|
||||
case IrOpcode::kFloat64Exp:
|
||||
case IrOpcode::kFloat64Log:
|
||||
case IrOpcode::kFloat64Log1p:
|
||||
case IrOpcode::kFloat64Log2:
|
||||
|
@ -873,6 +873,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
case kIeee754Float64Atan2:
|
||||
ASSEMBLE_IEEE754_BINOP(atan2);
|
||||
break;
|
||||
case kIeee754Float64Exp:
|
||||
ASSEMBLE_IEEE754_UNOP(exp);
|
||||
break;
|
||||
case kIeee754Float64Log:
|
||||
ASSEMBLE_IEEE754_UNOP(log);
|
||||
break;
|
||||
|
@ -86,9 +86,10 @@ enum BindingFlags {
|
||||
V(REFLECT_DELETE_PROPERTY_INDEX, JSFunction, reflect_delete_property) \
|
||||
V(SPREAD_ARGUMENTS_INDEX, JSFunction, spread_arguments) \
|
||||
V(SPREAD_ITERABLE_INDEX, JSFunction, spread_iterable) \
|
||||
V(MATH_FLOOR, JSFunction, math_floor) \
|
||||
V(MATH_LOG, JSFunction, math_log) \
|
||||
V(MATH_SQRT, JSFunction, math_sqrt)
|
||||
V(MATH_EXP_INDEX, JSFunction, math_exp) \
|
||||
V(MATH_FLOOR_INDEX, JSFunction, math_floor) \
|
||||
V(MATH_LOG_INDEX, JSFunction, math_log) \
|
||||
V(MATH_SQRT_INDEX, JSFunction, math_sqrt)
|
||||
|
||||
#define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \
|
||||
V(ARRAY_CONCAT_INDEX, JSFunction, array_concat) \
|
||||
|
@ -1138,12 +1138,8 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
|
||||
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
|
||||
DCHECK(instr->representation().IsDouble());
|
||||
DCHECK(instr->value()->representation().IsDouble());
|
||||
LOperand* input = UseRegister(instr->value());
|
||||
LOperand* temp1 = TempRegister();
|
||||
LOperand* temp2 = TempRegister();
|
||||
LOperand* double_temp = TempDoubleRegister();
|
||||
LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
|
||||
return DefineAsRegister(result);
|
||||
LOperand* input = UseFixedDouble(instr->value(), d0);
|
||||
return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), d0), instr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -905,24 +905,11 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
|
||||
};
|
||||
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 3> {
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
|
||||
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();
|
||||
}
|
||||
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
|
||||
|
||||
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")
|
||||
};
|
||||
|
@ -3540,16 +3540,10 @@ void LCodeGen::DoPower(LPower* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoMathExp(LMathExp* instr) {
|
||||
DwVfpRegister input = ToDoubleRegister(instr->value());
|
||||
DwVfpRegister result = ToDoubleRegister(instr->result());
|
||||
DwVfpRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
|
||||
DwVfpRegister 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());
|
||||
__ PrepareCallCFunction(0, 1, scratch0());
|
||||
__ MovToFloatParameter(ToDoubleRegister(instr->value()));
|
||||
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 0, 1);
|
||||
__ MovFromFloatResult(ToDoubleRegister(instr->result()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -2462,14 +2462,9 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
|
||||
case kMathExp: {
|
||||
DCHECK(instr->representation().IsDouble());
|
||||
DCHECK(instr->value()->representation().IsDouble());
|
||||
LOperand* input = UseRegister(instr->value());
|
||||
LOperand* double_temp1 = TempDoubleRegister();
|
||||
LOperand* temp1 = TempRegister();
|
||||
LOperand* temp2 = TempRegister();
|
||||
LOperand* temp3 = TempRegister();
|
||||
LMathExp* result = new(zone()) LMathExp(input, double_temp1,
|
||||
temp1, temp2, temp3);
|
||||
return DefineAsRegister(result);
|
||||
LOperand* input = UseFixedDouble(instr->value(), d0);
|
||||
LMathExp* result = new (zone()) LMathExp(input);
|
||||
return MarkAsCall(DefineFixedDouble(result, d0), instr);
|
||||
}
|
||||
case kMathFloor: {
|
||||
DCHECK(instr->value()->representation().IsDouble());
|
||||
|
@ -1763,26 +1763,9 @@ class LMathAbsTagged: public LTemplateInstruction<1, 2, 3> {
|
||||
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
|
||||
};
|
||||
|
||||
|
||||
class LMathExp final : public LUnaryMathOperation<4> {
|
||||
class LMathExp final : public LUnaryMathOperation<0> {
|
||||
public:
|
||||
LMathExp(LOperand* value,
|
||||
LOperand* double_temp1,
|
||||
LOperand* temp1,
|
||||
LOperand* temp2,
|
||||
LOperand* temp3)
|
||||
: LUnaryMathOperation<4>(value) {
|
||||
temps_[0] = double_temp1;
|
||||
temps_[1] = temp1;
|
||||
temps_[2] = temp2;
|
||||
temps_[3] = temp3;
|
||||
ExternalReference::InitializeMathExpData();
|
||||
}
|
||||
|
||||
LOperand* double_temp1() { return temps_[0]; }
|
||||
LOperand* temp1() { return temps_[1]; }
|
||||
LOperand* temp2() { return temps_[2]; }
|
||||
LOperand* temp3() { return temps_[3]; }
|
||||
explicit LMathExp(LOperand* value) : LUnaryMathOperation<0>(value) {}
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
|
||||
};
|
||||
|
@ -3548,17 +3548,10 @@ void LCodeGen::DoMathAbsTagged(LMathAbsTagged* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoMathExp(LMathExp* instr) {
|
||||
DoubleRegister input = ToDoubleRegister(instr->value());
|
||||
DoubleRegister result = ToDoubleRegister(instr->result());
|
||||
DoubleRegister double_temp1 = ToDoubleRegister(instr->double_temp1());
|
||||
DoubleRegister double_temp2 = double_scratch();
|
||||
Register temp1 = ToRegister(instr->temp1());
|
||||
Register temp2 = ToRegister(instr->temp2());
|
||||
Register temp3 = ToRegister(instr->temp3());
|
||||
|
||||
MathExpGenerator::EmitMathExp(masm(), input, result,
|
||||
double_temp1, double_temp2,
|
||||
temp1, temp2, temp3);
|
||||
DCHECK(instr->IsMarkedAsCall());
|
||||
DCHECK(ToDoubleRegister(instr->value()).is(d0));
|
||||
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 0, 1);
|
||||
DCHECK(ToDoubleRegister(instr->result()).Is(d0));
|
||||
}
|
||||
|
||||
|
||||
|
@ -3423,8 +3423,7 @@ HInstruction* HUnaryMathOperation::New(Isolate* isolate, Zone* zone,
|
||||
}
|
||||
switch (op) {
|
||||
case kMathExp:
|
||||
lazily_initialize_fast_exp(isolate);
|
||||
return H_CONSTANT_DOUBLE(fast_exp(d, isolate));
|
||||
return H_CONSTANT_DOUBLE(base::ieee754::exp(d));
|
||||
case kMathLog:
|
||||
return H_CONSTANT_DOUBLE(base::ieee754::log(d));
|
||||
case kMathSqrt:
|
||||
|
@ -8856,8 +8856,6 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) {
|
||||
// we inline here do not observe if they were tail called or not.
|
||||
switch (id) {
|
||||
case kMathExp:
|
||||
if (!FLAG_fast_math) break;
|
||||
// Fall through if FLAG_fast_math.
|
||||
case kMathRound:
|
||||
case kMathFround:
|
||||
case kMathFloor:
|
||||
|
@ -3425,11 +3425,16 @@ void LCodeGen::DoMathClz32(LMathClz32* instr) {
|
||||
void LCodeGen::DoMathExp(LMathExp* instr) {
|
||||
XMMRegister input = ToDoubleRegister(instr->value());
|
||||
XMMRegister result = ToDoubleRegister(instr->result());
|
||||
XMMRegister temp0 = double_scratch0();
|
||||
Register temp1 = ToRegister(instr->temp1());
|
||||
Register temp2 = ToRegister(instr->temp2());
|
||||
|
||||
MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2);
|
||||
// Pass one double as argument on the stack.
|
||||
__ PrepareCallCFunction(2, eax);
|
||||
__ movsd(Operand(esp, 0 * kDoubleSize), input);
|
||||
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 2);
|
||||
// Return value is in st(0) on ia32.
|
||||
// Store it into the result register.
|
||||
__ sub(esp, Immediate(kDoubleSize));
|
||||
__ fstp_d(Operand(esp, 0));
|
||||
__ movsd(result, Operand(esp, 0));
|
||||
__ add(esp, Immediate(kDoubleSize));
|
||||
}
|
||||
|
||||
void LCodeGen::PrepareForTailCall(const ParameterCount& actual,
|
||||
|
@ -1181,11 +1181,8 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
|
||||
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
|
||||
DCHECK(instr->representation().IsDouble());
|
||||
DCHECK(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);
|
||||
LOperand* input = UseRegisterAtStart(instr->value());
|
||||
return MarkAsCall(DefineSameAsFirst(new (zone()) LMathExp(input)), instr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -912,21 +912,11 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
|
||||
};
|
||||
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 2> {
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
LMathExp(LOperand* value,
|
||||
LOperand* temp1,
|
||||
LOperand* temp2) {
|
||||
inputs_[0] = value;
|
||||
temps_[0] = temp1;
|
||||
temps_[1] = temp2;
|
||||
ExternalReference::InitializeMathExpData();
|
||||
}
|
||||
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
LOperand* temp1() { return temps_[0]; }
|
||||
LOperand* temp2() { return temps_[1]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
|
||||
};
|
||||
|
@ -3492,16 +3492,10 @@ void LCodeGen::DoPower(LPower* instr) {
|
||||
|
||||
|
||||
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());
|
||||
__ PrepareCallCFunction(0, 1, scratch0());
|
||||
__ MovToFloatParameter(ToDoubleRegister(instr->value()));
|
||||
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 0, 1);
|
||||
__ MovFromFloatResult(ToDoubleRegister(instr->result()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1107,12 +1107,8 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
|
||||
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
|
||||
DCHECK(instr->representation().IsDouble());
|
||||
DCHECK(instr->value()->representation().IsDouble());
|
||||
LOperand* input = UseRegister(instr->value());
|
||||
LOperand* temp1 = TempRegister();
|
||||
LOperand* temp2 = TempRegister();
|
||||
LOperand* double_temp = TempDoubleRegister();
|
||||
LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
|
||||
return DefineAsRegister(result);
|
||||
LOperand* input = UseFixedDouble(instr->value(), f4);
|
||||
return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), f4), instr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -882,24 +882,11 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
|
||||
};
|
||||
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 3> {
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
|
||||
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();
|
||||
}
|
||||
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
|
||||
|
||||
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")
|
||||
};
|
||||
|
@ -3695,16 +3695,10 @@ void LCodeGen::DoPower(LPower* instr) {
|
||||
|
||||
|
||||
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());
|
||||
__ PrepareCallCFunction(0, 1, scratch0());
|
||||
__ MovToFloatParameter(ToDoubleRegister(instr->value()));
|
||||
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 0, 1);
|
||||
__ MovFromFloatResult(ToDoubleRegister(instr->result()));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1107,12 +1107,8 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
|
||||
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
|
||||
DCHECK(instr->representation().IsDouble());
|
||||
DCHECK(instr->value()->representation().IsDouble());
|
||||
LOperand* input = UseRegister(instr->value());
|
||||
LOperand* temp1 = TempRegister();
|
||||
LOperand* temp2 = TempRegister();
|
||||
LOperand* double_temp = TempDoubleRegister();
|
||||
LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
|
||||
return DefineAsRegister(result);
|
||||
LOperand* input = UseFixedDouble(instr->value(), f4);
|
||||
return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), f4), instr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -900,24 +900,11 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
|
||||
};
|
||||
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 3> {
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
|
||||
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();
|
||||
}
|
||||
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
|
||||
|
||||
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")
|
||||
};
|
||||
|
@ -3600,13 +3600,10 @@ void LCodeGen::DoPower(LPower* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoMathExp(LMathExp* instr) {
|
||||
XMMRegister input = ToDoubleRegister(instr->value());
|
||||
XMMRegister result = ToDoubleRegister(instr->result());
|
||||
XMMRegister temp0 = double_scratch0();
|
||||
Register temp1 = ToRegister(instr->temp1());
|
||||
Register temp2 = ToRegister(instr->temp2());
|
||||
|
||||
MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2);
|
||||
DCHECK(ToDoubleRegister(instr->value()).is(xmm0));
|
||||
DCHECK(ToDoubleRegister(instr->result()).is(xmm0));
|
||||
__ PrepareCallCFunction(1);
|
||||
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1171,11 +1171,9 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
|
||||
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
|
||||
DCHECK(instr->representation().IsDouble());
|
||||
DCHECK(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);
|
||||
LOperand* input = UseFixedDouble(instr->value(), xmm0);
|
||||
return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), xmm0),
|
||||
instr);
|
||||
}
|
||||
|
||||
|
||||
|
@ -909,19 +909,11 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
|
||||
};
|
||||
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 2> {
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
|
||||
public:
|
||||
LMathExp(LOperand* value, LOperand* temp1, LOperand* temp2) {
|
||||
inputs_[0] = value;
|
||||
temps_[0] = temp1;
|
||||
temps_[1] = temp2;
|
||||
ExternalReference::InitializeMathExpData();
|
||||
}
|
||||
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
|
||||
|
||||
LOperand* value() { return inputs_[0]; }
|
||||
LOperand* temp1() { return temps_[0]; }
|
||||
LOperand* temp2() { return temps_[1]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
|
||||
};
|
||||
|
@ -71,6 +71,8 @@ ExternalReferenceTable::ExternalReferenceTable(Isolate* isolate) {
|
||||
"base::ieee754::atan");
|
||||
Add(ExternalReference::ieee754_atan2_function(isolate).address(),
|
||||
"base::ieee754::atan2");
|
||||
Add(ExternalReference::ieee754_exp_function(isolate).address(),
|
||||
"base::ieee754::exp");
|
||||
Add(ExternalReference::ieee754_log_function(isolate).address(),
|
||||
"base::ieee754::log");
|
||||
Add(ExternalReference::ieee754_log1p_function(isolate).address(),
|
||||
|
@ -34,43 +34,6 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
|
||||
#define __ masm.
|
||||
|
||||
|
||||
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
|
||||
size_t actual_size;
|
||||
byte* buffer =
|
||||
static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
|
||||
if (buffer == nullptr) return nullptr;
|
||||
ExternalReference::InitializeMathExpData();
|
||||
|
||||
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
|
||||
CodeObjectRequired::kNo);
|
||||
// esp[1 * kPointerSize]: raw double input
|
||||
// esp[0 * kPointerSize]: return address
|
||||
{
|
||||
XMMRegister input = xmm1;
|
||||
XMMRegister result = xmm2;
|
||||
__ movsd(input, Operand(esp, 1 * kPointerSize));
|
||||
__ push(eax);
|
||||
__ push(ebx);
|
||||
|
||||
MathExpGenerator::EmitMathExp(&masm, input, result, xmm0, eax, ebx);
|
||||
|
||||
__ pop(ebx);
|
||||
__ pop(eax);
|
||||
__ movsd(Operand(esp, 1 * kPointerSize), result);
|
||||
__ fld_d(Operand(esp, 1 * kPointerSize));
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
CodeDesc desc;
|
||||
masm.GetCode(&desc);
|
||||
DCHECK(!RelocInfo::RequiresRelocation(desc));
|
||||
|
||||
Assembler::FlushICache(isolate, buffer, actual_size);
|
||||
base::OS::ProtectCode(buffer, actual_size);
|
||||
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
|
||||
}
|
||||
|
||||
|
||||
UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
|
||||
size_t actual_size;
|
||||
// Allocate buffer in executable space.
|
||||
@ -928,64 +891,6 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm,
|
||||
__ 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) {
|
||||
DCHECK(!input.is(double_scratch));
|
||||
DCHECK(!input.is(result));
|
||||
DCHECK(!result.is(double_scratch));
|
||||
DCHECK(!temp1.is(temp2));
|
||||
DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
|
||||
DCHECK(!masm->serializer_enabled()); // External references not serializable.
|
||||
|
||||
Label done;
|
||||
|
||||
__ movsd(double_scratch, ExpConstant(0));
|
||||
__ xorpd(result, result);
|
||||
__ ucomisd(double_scratch, input);
|
||||
__ j(above_equal, &done);
|
||||
__ ucomisd(input, ExpConstant(1));
|
||||
__ movsd(result, ExpConstant(2));
|
||||
__ j(above_equal, &done);
|
||||
__ movsd(double_scratch, ExpConstant(3));
|
||||
__ movsd(result, ExpConstant(4));
|
||||
__ mulsd(double_scratch, input);
|
||||
__ addsd(double_scratch, result);
|
||||
__ movd(temp2, double_scratch);
|
||||
__ subsd(double_scratch, result);
|
||||
__ movsd(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
|
||||
__ movsd(double_scratch, Operand::StaticArray(
|
||||
temp2, times_8, ExternalReference::math_exp_log_table()));
|
||||
__ orps(input, double_scratch);
|
||||
__ mulsd(result, input);
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
#undef __
|
||||
|
||||
|
||||
|
@ -29,19 +29,6 @@ class StringCharLoadGenerator : public AllStatic {
|
||||
};
|
||||
|
||||
|
||||
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 internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -29,11 +29,6 @@ function MathAbs(x) {
|
||||
return (x > 0) ? x : 0 - x;
|
||||
}
|
||||
|
||||
// ECMA 262 - 15.8.2.8
|
||||
function MathExp(x) {
|
||||
return %MathExpRT(TO_NUMBER(x));
|
||||
}
|
||||
|
||||
// ECMA 262 - 15.8.2.13
|
||||
function MathPowJS(x, y) {
|
||||
return %_MathPow(TO_NUMBER(x), TO_NUMBER(y));
|
||||
@ -184,7 +179,6 @@ utils.InstallConstants(GlobalMath, [
|
||||
utils.InstallFunctions(GlobalMath, DONT_ENUM, [
|
||||
"random", MathRandom,
|
||||
"abs", MathAbs,
|
||||
"exp", MathExp,
|
||||
"pow", MathPowJS,
|
||||
"sign", MathSign,
|
||||
"asinh", MathAsinh,
|
||||
@ -203,7 +197,6 @@ utils.InstallFunctions(GlobalMath, DONT_ENUM, [
|
||||
|
||||
utils.Export(function(to) {
|
||||
to.MathAbs = MathAbs;
|
||||
to.MathExp = MathExp;
|
||||
to.IntRandom = MathRandomRaw;
|
||||
});
|
||||
|
||||
|
@ -16,60 +16,6 @@ namespace internal {
|
||||
|
||||
#define __ masm.
|
||||
|
||||
|
||||
#if defined(USE_SIMULATOR)
|
||||
byte* fast_exp_mips_machine_code = nullptr;
|
||||
double fast_exp_simulator(double x, Isolate* isolate) {
|
||||
return Simulator::current(isolate)->CallFP(fast_exp_mips_machine_code, x, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
|
||||
size_t actual_size;
|
||||
byte* buffer =
|
||||
static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
|
||||
if (buffer == nullptr) return nullptr;
|
||||
ExternalReference::InitializeMathExpData();
|
||||
|
||||
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
|
||||
CodeObjectRequired::kNo);
|
||||
|
||||
{
|
||||
DoubleRegister input = f12;
|
||||
DoubleRegister result = f0;
|
||||
DoubleRegister double_scratch1 = f4;
|
||||
DoubleRegister double_scratch2 = f6;
|
||||
Register temp1 = t0;
|
||||
Register temp2 = t1;
|
||||
Register temp3 = t2;
|
||||
|
||||
__ MovFromFloatParameter(input);
|
||||
__ Push(temp3, temp2, temp1);
|
||||
MathExpGenerator::EmitMathExp(
|
||||
&masm, input, result, double_scratch1, double_scratch2,
|
||||
temp1, temp2, temp3);
|
||||
__ Pop(temp3, temp2, temp1);
|
||||
__ MovToFloatResult(result);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
CodeDesc desc;
|
||||
masm.GetCode(&desc);
|
||||
DCHECK(!RelocInfo::RequiresRelocation(desc));
|
||||
|
||||
Assembler::FlushICache(isolate, buffer, actual_size);
|
||||
base::OS::ProtectCode(buffer, actual_size);
|
||||
|
||||
#if !defined(USE_SIMULATOR)
|
||||
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
|
||||
#else
|
||||
fast_exp_mips_machine_code = buffer;
|
||||
return &fast_exp_simulator;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(V8_HOST_ARCH_MIPS)
|
||||
MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
|
||||
MemCopyUint8Function stub) {
|
||||
@ -1092,95 +1038,6 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm,
|
||||
__ 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) {
|
||||
DCHECK(!input.is(result));
|
||||
DCHECK(!input.is(double_scratch1));
|
||||
DCHECK(!input.is(double_scratch2));
|
||||
DCHECK(!result.is(double_scratch1));
|
||||
DCHECK(!result.is(double_scratch2));
|
||||
DCHECK(!double_scratch1.is(double_scratch2));
|
||||
DCHECK(!temp1.is(temp2));
|
||||
DCHECK(!temp1.is(temp3));
|
||||
DCHECK(!temp2.is(temp3));
|
||||
DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
|
||||
DCHECK(!masm->serializer_enabled()); // External references not serializable.
|
||||
|
||||
Label zero, infinity, done;
|
||||
|
||||
__ li(temp3, Operand(ExternalReference::math_exp_constants(0)));
|
||||
|
||||
__ ldc1(double_scratch1, ExpConstant(0, temp3));
|
||||
__ BranchF(&zero, NULL, ge, double_scratch1, input);
|
||||
|
||||
__ ldc1(double_scratch2, ExpConstant(1, temp3));
|
||||
__ BranchF(&infinity, NULL, ge, input, double_scratch2);
|
||||
|
||||
__ ldc1(double_scratch1, ExpConstant(3, temp3));
|
||||
__ ldc1(result, ExpConstant(4, temp3));
|
||||
__ mul_d(double_scratch1, double_scratch1, input);
|
||||
__ add_d(double_scratch1, double_scratch1, result);
|
||||
__ FmoveLow(temp2, double_scratch1);
|
||||
__ sub_d(double_scratch1, double_scratch1, result);
|
||||
__ ldc1(result, ExpConstant(6, temp3));
|
||||
__ ldc1(double_scratch2, ExpConstant(5, temp3));
|
||||
__ mul_d(double_scratch1, double_scratch1, double_scratch2);
|
||||
__ sub_d(double_scratch1, double_scratch1, input);
|
||||
__ sub_d(result, result, double_scratch1);
|
||||
__ mul_d(double_scratch2, double_scratch1, double_scratch1);
|
||||
__ mul_d(result, result, double_scratch2);
|
||||
__ ldc1(double_scratch2, ExpConstant(7, temp3));
|
||||
__ mul_d(result, result, double_scratch2);
|
||||
__ sub_d(result, result, double_scratch1);
|
||||
// Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
|
||||
DCHECK(*reinterpret_cast<double*>
|
||||
(ExternalReference::math_exp_constants(8).address()) == 1);
|
||||
__ Move(double_scratch2, 1.);
|
||||
__ add_d(result, result, double_scratch2);
|
||||
__ srl(temp1, temp2, 11);
|
||||
__ Ext(temp2, temp2, 0, 11);
|
||||
__ Addu(temp1, temp1, Operand(0x3ff));
|
||||
|
||||
// Must not call ExpConstant() after overwriting temp3!
|
||||
__ li(temp3, Operand(ExternalReference::math_exp_log_table()));
|
||||
__ Lsa(temp3, temp3, temp2, 3);
|
||||
__ lw(temp2, MemOperand(temp3, Register::kMantissaOffset));
|
||||
__ lw(temp3, MemOperand(temp3, Register::kExponentOffset));
|
||||
// The first word is loaded is the lower number register.
|
||||
if (temp2.code() < temp3.code()) {
|
||||
__ sll(at, temp1, 20);
|
||||
__ Or(temp1, temp3, at);
|
||||
__ Move(double_scratch1, temp2, temp1);
|
||||
} else {
|
||||
__ sll(at, temp1, 20);
|
||||
__ Or(temp1, temp2, at);
|
||||
__ Move(double_scratch1, temp3, temp1);
|
||||
}
|
||||
__ mul_d(result, result, double_scratch1);
|
||||
__ BranchShort(&done);
|
||||
|
||||
__ bind(&zero);
|
||||
__ Move(result, kDoubleRegZero);
|
||||
__ BranchShort(&done);
|
||||
|
||||
__ bind(&infinity);
|
||||
__ ldc1(result, ExpConstant(2, temp3));
|
||||
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// nop(CODE_AGE_MARKER_NOP)
|
||||
static const uint32_t kCodeAgePatchFirstInstruction = 0x00010180;
|
||||
|
@ -29,23 +29,6 @@ class StringCharLoadGenerator : public AllStatic {
|
||||
DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator);
|
||||
};
|
||||
|
||||
|
||||
class MathExpGenerator : public AllStatic {
|
||||
public:
|
||||
// Register input isn't modified. All other registers are clobbered.
|
||||
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 internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -17,59 +17,6 @@ namespace internal {
|
||||
#define __ masm.
|
||||
|
||||
|
||||
#if defined(USE_SIMULATOR)
|
||||
byte* fast_exp_mips_machine_code = nullptr;
|
||||
double fast_exp_simulator(double x, Isolate* isolate) {
|
||||
return Simulator::current(isolate)->CallFP(fast_exp_mips_machine_code, x, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
|
||||
size_t actual_size;
|
||||
byte* buffer =
|
||||
static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
|
||||
if (buffer == nullptr) return nullptr;
|
||||
ExternalReference::InitializeMathExpData();
|
||||
|
||||
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
|
||||
CodeObjectRequired::kNo);
|
||||
|
||||
{
|
||||
DoubleRegister input = f12;
|
||||
DoubleRegister result = f0;
|
||||
DoubleRegister double_scratch1 = f4;
|
||||
DoubleRegister double_scratch2 = f6;
|
||||
Register temp1 = a4;
|
||||
Register temp2 = a5;
|
||||
Register temp3 = a6;
|
||||
|
||||
__ MovFromFloatParameter(input);
|
||||
__ Push(temp3, temp2, temp1);
|
||||
MathExpGenerator::EmitMathExp(
|
||||
&masm, input, result, double_scratch1, double_scratch2,
|
||||
temp1, temp2, temp3);
|
||||
__ Pop(temp3, temp2, temp1);
|
||||
__ MovToFloatResult(result);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
CodeDesc desc;
|
||||
masm.GetCode(&desc);
|
||||
DCHECK(!RelocInfo::RequiresRelocation(desc));
|
||||
|
||||
Assembler::FlushICache(isolate, buffer, actual_size);
|
||||
base::OS::ProtectCode(buffer, actual_size);
|
||||
|
||||
#if !defined(USE_SIMULATOR)
|
||||
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
|
||||
#else
|
||||
fast_exp_mips_machine_code = buffer;
|
||||
return &fast_exp_simulator;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined(V8_HOST_ARCH_MIPS)
|
||||
MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
|
||||
MemCopyUint8Function stub) {
|
||||
@ -1090,94 +1037,6 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm,
|
||||
__ 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) {
|
||||
DCHECK(!input.is(result));
|
||||
DCHECK(!input.is(double_scratch1));
|
||||
DCHECK(!input.is(double_scratch2));
|
||||
DCHECK(!result.is(double_scratch1));
|
||||
DCHECK(!result.is(double_scratch2));
|
||||
DCHECK(!double_scratch1.is(double_scratch2));
|
||||
DCHECK(!temp1.is(temp2));
|
||||
DCHECK(!temp1.is(temp3));
|
||||
DCHECK(!temp2.is(temp3));
|
||||
DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
|
||||
DCHECK(!masm->serializer_enabled()); // External references not serializable.
|
||||
|
||||
Label zero, infinity, done;
|
||||
__ li(temp3, Operand(ExternalReference::math_exp_constants(0)));
|
||||
|
||||
__ ldc1(double_scratch1, ExpConstant(0, temp3));
|
||||
__ BranchF(&zero, NULL, ge, double_scratch1, input);
|
||||
|
||||
__ ldc1(double_scratch2, ExpConstant(1, temp3));
|
||||
__ BranchF(&infinity, NULL, ge, input, double_scratch2);
|
||||
|
||||
__ ldc1(double_scratch1, ExpConstant(3, temp3));
|
||||
__ ldc1(result, ExpConstant(4, temp3));
|
||||
__ mul_d(double_scratch1, double_scratch1, input);
|
||||
__ add_d(double_scratch1, double_scratch1, result);
|
||||
__ FmoveLow(temp2, double_scratch1);
|
||||
__ sub_d(double_scratch1, double_scratch1, result);
|
||||
__ ldc1(result, ExpConstant(6, temp3));
|
||||
__ ldc1(double_scratch2, ExpConstant(5, temp3));
|
||||
__ mul_d(double_scratch1, double_scratch1, double_scratch2);
|
||||
__ sub_d(double_scratch1, double_scratch1, input);
|
||||
__ sub_d(result, result, double_scratch1);
|
||||
__ mul_d(double_scratch2, double_scratch1, double_scratch1);
|
||||
__ mul_d(result, result, double_scratch2);
|
||||
__ ldc1(double_scratch2, ExpConstant(7, temp3));
|
||||
__ mul_d(result, result, double_scratch2);
|
||||
__ sub_d(result, result, double_scratch1);
|
||||
// Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
|
||||
DCHECK(*reinterpret_cast<double*>
|
||||
(ExternalReference::math_exp_constants(8).address()) == 1);
|
||||
__ Move(double_scratch2, 1.);
|
||||
__ add_d(result, result, double_scratch2);
|
||||
__ dsrl(temp1, temp2, 11);
|
||||
__ Ext(temp2, temp2, 0, 11);
|
||||
__ Daddu(temp1, temp1, Operand(0x3ff));
|
||||
|
||||
// Must not call ExpConstant() after overwriting temp3!
|
||||
__ li(temp3, Operand(ExternalReference::math_exp_log_table()));
|
||||
__ Dlsa(temp3, temp3, temp2, 3);
|
||||
__ lwu(temp2, MemOperand(temp3, Register::kMantissaOffset));
|
||||
__ lwu(temp3, MemOperand(temp3, Register::kExponentOffset));
|
||||
// The first word is loaded is the lower number register.
|
||||
if (temp2.code() < temp3.code()) {
|
||||
__ dsll(at, temp1, 20);
|
||||
__ Or(temp1, temp3, at);
|
||||
__ Move(double_scratch1, temp2, temp1);
|
||||
} else {
|
||||
__ dsll(at, temp1, 20);
|
||||
__ Or(temp1, temp2, at);
|
||||
__ Move(double_scratch1, temp3, temp1);
|
||||
}
|
||||
__ mul_d(result, result, double_scratch1);
|
||||
__ BranchShort(&done);
|
||||
|
||||
__ bind(&zero);
|
||||
__ Move(result, kDoubleRegZero);
|
||||
__ BranchShort(&done);
|
||||
|
||||
__ bind(&infinity);
|
||||
__ ldc1(result, ExpConstant(2, temp3));
|
||||
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// nop(CODE_AGE_MARKER_NOP)
|
||||
static const uint32_t kCodeAgePatchFirstInstruction = 0x00010180;
|
||||
|
@ -29,23 +29,6 @@ class StringCharLoadGenerator : public AllStatic {
|
||||
DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator);
|
||||
};
|
||||
|
||||
|
||||
class MathExpGenerator : public AllStatic {
|
||||
public:
|
||||
// Register input isn't modified. All other registers are clobbered.
|
||||
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 internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -59,17 +59,6 @@ RUNTIME_FUNCTION(Runtime_RemPiO2) {
|
||||
}
|
||||
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_MathExpRT) {
|
||||
HandleScope scope(isolate);
|
||||
DCHECK(args.length() == 1);
|
||||
isolate->counters()->math_exp_runtime()->Increment();
|
||||
|
||||
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
|
||||
lazily_initialize_fast_exp(isolate);
|
||||
return *isolate->factory()->NewNumber(fast_exp(x, isolate));
|
||||
}
|
||||
|
||||
|
||||
// Slow version of Math.pow. We check for fast paths for special cases.
|
||||
// Used if VFP3 is not available.
|
||||
RUNTIME_FUNCTION(Runtime_MathPow) {
|
||||
|
@ -355,7 +355,6 @@ namespace internal {
|
||||
F(DoubleLo, 1, 1) \
|
||||
F(ConstructDouble, 2, 1) \
|
||||
F(RemPiO2, 2, 1) \
|
||||
F(MathExpRT, 1, 1) \
|
||||
F(MathPow, 2, 1) \
|
||||
F(MathPowRT, 2, 1) \
|
||||
F(GenerateRandomNumbers, 1, 1)
|
||||
|
12
src/third_party/fdlibm/fdlibm.js
vendored
12
src/third_party/fdlibm/fdlibm.js
vendored
@ -31,13 +31,11 @@
|
||||
var GlobalFloat64Array = global.Float64Array;
|
||||
var GlobalMath = global.Math;
|
||||
var MathAbs;
|
||||
var MathExp;
|
||||
var NaN = %GetRootNaN();
|
||||
var rempio2result;
|
||||
|
||||
utils.Import(function(from) {
|
||||
MathAbs = from.MathAbs;
|
||||
MathExp = from.MathExp;
|
||||
});
|
||||
|
||||
utils.CreateDoubleResultArray = function(global) {
|
||||
@ -634,11 +632,11 @@ function MathSinh(x) {
|
||||
return h * (t + t / (t + 1));
|
||||
}
|
||||
// |x| in [22, log(maxdouble)], return 0.5 * exp(|x|)
|
||||
if (ax < LOG_MAXD) return h * MathExp(ax);
|
||||
if (ax < LOG_MAXD) return h * %math_exp(ax);
|
||||
// |x| in [log(maxdouble), overflowthreshold]
|
||||
// overflowthreshold = 710.4758600739426
|
||||
if (ax <= KSINH_OVERFLOW) {
|
||||
var w = MathExp(0.5 * ax);
|
||||
var w = %math_exp(0.5 * ax);
|
||||
var t = h * w;
|
||||
return t * w;
|
||||
}
|
||||
@ -684,14 +682,14 @@ function MathCosh(x) {
|
||||
}
|
||||
// |x| in [0.5*log2, 22], return (exp(|x|)+1/exp(|x|)/2
|
||||
if (ix < 0x40360000) {
|
||||
var t = MathExp(MathAbs(x));
|
||||
var t = %math_exp(MathAbs(x));
|
||||
return 0.5 * t + 0.5 / t;
|
||||
}
|
||||
// |x| in [22, log(maxdouble)], return half*exp(|x|)
|
||||
if (ix < 0x40862e42) return 0.5 * MathExp(MathAbs(x));
|
||||
if (ix < 0x40862e42) return 0.5 * %math_exp(MathAbs(x));
|
||||
// |x| in [log(maxdouble), overflowthreshold]
|
||||
if (MathAbs(x) <= KCOSH_OVERFLOW) {
|
||||
var w = MathExp(0.5 * MathAbs(x));
|
||||
var w = %math_exp(0.5 * MathAbs(x));
|
||||
var t = 0.5 * w;
|
||||
return t * w;
|
||||
}
|
||||
|
@ -45,7 +45,6 @@ void V8::TearDown() {
|
||||
Bootstrapper::TearDownExtensions();
|
||||
ElementsAccessor::TearDown();
|
||||
LOperand::TearDownCaches();
|
||||
ExternalReference::TearDownMathExpData();
|
||||
RegisteredExtension::UnregisterAll();
|
||||
Isolate::GlobalTearDown();
|
||||
sampler::Sampler::TearDown();
|
||||
|
@ -32,38 +32,6 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
|
||||
#define __ masm.
|
||||
|
||||
|
||||
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
|
||||
size_t actual_size;
|
||||
byte* buffer =
|
||||
static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
|
||||
if (buffer == nullptr) return nullptr;
|
||||
ExternalReference::InitializeMathExpData();
|
||||
|
||||
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
|
||||
CodeObjectRequired::kNo);
|
||||
// xmm0: raw double input.
|
||||
XMMRegister input = xmm0;
|
||||
XMMRegister result = xmm1;
|
||||
__ pushq(rax);
|
||||
__ pushq(rbx);
|
||||
|
||||
MathExpGenerator::EmitMathExp(&masm, input, result, xmm2, rax, rbx);
|
||||
|
||||
__ popq(rbx);
|
||||
__ popq(rax);
|
||||
__ Movsd(xmm0, result);
|
||||
__ Ret();
|
||||
|
||||
CodeDesc desc;
|
||||
masm.GetCode(&desc);
|
||||
DCHECK(!RelocInfo::RequiresRelocation(desc));
|
||||
|
||||
Assembler::FlushICache(isolate, buffer, actual_size);
|
||||
base::OS::ProtectCode(buffer, actual_size);
|
||||
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
|
||||
}
|
||||
|
||||
|
||||
UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
|
||||
size_t actual_size;
|
||||
// Allocate buffer in executable space.
|
||||
@ -499,59 +467,6 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm,
|
||||
__ bind(&done);
|
||||
}
|
||||
|
||||
|
||||
void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
|
||||
XMMRegister input,
|
||||
XMMRegister result,
|
||||
XMMRegister double_scratch,
|
||||
Register temp1,
|
||||
Register temp2) {
|
||||
DCHECK(!input.is(result));
|
||||
DCHECK(!input.is(double_scratch));
|
||||
DCHECK(!result.is(double_scratch));
|
||||
DCHECK(!temp1.is(temp2));
|
||||
DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
|
||||
DCHECK(!masm->serializer_enabled()); // External references not serializable.
|
||||
|
||||
Label done;
|
||||
|
||||
__ Move(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));
|
||||
__ leaq(temp1, Operand(temp2, 0x1ff800));
|
||||
__ andq(temp2, Immediate(0x7ff));
|
||||
__ shrq(temp1, Immediate(11));
|
||||
__ Mulsd(double_scratch, Operand(kScratchRegister, 5 * kDoubleSize));
|
||||
__ Move(kScratchRegister, ExternalReference::math_exp_log_table());
|
||||
__ shlq(temp1, Immediate(52));
|
||||
__ orq(temp1, Operand(kScratchRegister, temp2, times_8, 0));
|
||||
__ Move(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 __
|
||||
|
||||
|
||||
|
@ -28,20 +28,6 @@ class StringCharLoadGenerator : public AllStatic {
|
||||
};
|
||||
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
enum StackArgumentsAccessorReceiverMode {
|
||||
ARGUMENTS_CONTAIN_RECEIVER,
|
||||
ARGUMENTS_DONT_CONTAIN_RECEIVER
|
||||
|
@ -5517,6 +5517,19 @@ TEST(RunFloat64Atan2) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RunFloat64Exp) {
|
||||
BufferedRawMachineAssemblerTester<double> m(MachineType::Float64());
|
||||
m.Return(m.Float64Exp(m.Parameter(0)));
|
||||
CHECK(std::isnan(m.Call(std::numeric_limits<double>::quiet_NaN())));
|
||||
CHECK(std::isnan(m.Call(std::numeric_limits<double>::signaling_NaN())));
|
||||
CHECK_EQ(0.0, m.Call(-std::numeric_limits<double>::infinity()));
|
||||
CHECK_DOUBLE_EQ(1.0, m.Call(-0.0));
|
||||
CHECK_DOUBLE_EQ(1.0, m.Call(0.0));
|
||||
CHECK_DOUBLE_EQ(std::numeric_limits<double>::infinity(),
|
||||
m.Call(std::numeric_limits<double>::infinity()));
|
||||
FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(ieee754::exp(*i), m.Call(*i)); }
|
||||
}
|
||||
|
||||
TEST(RunFloat64Log) {
|
||||
BufferedRawMachineAssemblerTester<double> m(MachineType::Float64());
|
||||
m.Return(m.Float64Log(m.Parameter(0)));
|
||||
|
@ -54,6 +54,23 @@ TEST(Ieee754, Atan2) {
|
||||
-std::numeric_limits<double>::infinity()));
|
||||
}
|
||||
|
||||
TEST(Ieee754, Exp) {
|
||||
EXPECT_THAT(exp(std::numeric_limits<double>::quiet_NaN()), IsNaN());
|
||||
EXPECT_THAT(exp(std::numeric_limits<double>::signaling_NaN()), IsNaN());
|
||||
EXPECT_EQ(0.0, exp(-std::numeric_limits<double>::infinity()));
|
||||
EXPECT_EQ(std::numeric_limits<double>::infinity(),
|
||||
exp(std::numeric_limits<double>::infinity()));
|
||||
EXPECT_EQ(3.307553003638408e-308, exp(-708.0));
|
||||
EXPECT_EQ(2.2250738585072626e-308, exp(-708.39641853226408));
|
||||
EXPECT_EQ(0.36787944117144233, exp(-1.0));
|
||||
EXPECT_EQ(1.0, exp(-0.0));
|
||||
EXPECT_EQ(1.0, exp(0.0));
|
||||
EXPECT_EQ(2.7182818284590455, exp(1.0));
|
||||
EXPECT_EQ(2.6881171418161356e+43, exp(100.0));
|
||||
EXPECT_EQ(8.218407461554972e+307, exp(709.0));
|
||||
EXPECT_EQ(std::numeric_limits<double>::infinity(), exp(710.0));
|
||||
}
|
||||
|
||||
TEST(Ieee754, Log) {
|
||||
EXPECT_THAT(log(std::numeric_limits<double>::quiet_NaN()), IsNaN());
|
||||
EXPECT_THAT(log(std::numeric_limits<double>::signaling_NaN()), IsNaN());
|
||||
|
@ -263,6 +263,45 @@ TEST_F(JSBuiltinReducerTest, MathClz32WithPlainPrimitive) {
|
||||
IsNumberClz32(IsNumberToUint32(IsPlainPrimitiveToNumber(p0))));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Math.exp
|
||||
|
||||
TEST_F(JSBuiltinReducerTest, MathExpWithNumber) {
|
||||
Node* function = MathFunction("exp");
|
||||
|
||||
Node* effect = graph()->start();
|
||||
Node* control = graph()->start();
|
||||
Node* context = UndefinedConstant();
|
||||
Node* frame_state = graph()->start();
|
||||
TRACED_FOREACH(Type*, t0, kNumberTypes) {
|
||||
Node* p0 = Parameter(t0, 0);
|
||||
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
|
||||
UndefinedConstant(), p0, context, frame_state,
|
||||
effect, control);
|
||||
Reduction r = Reduce(call);
|
||||
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsNumberExp(p0));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(JSBuiltinReducerTest, MathExpWithPlainPrimitive) {
|
||||
Node* function = MathFunction("exp");
|
||||
|
||||
Node* effect = graph()->start();
|
||||
Node* control = graph()->start();
|
||||
Node* context = UndefinedConstant();
|
||||
Node* frame_state = graph()->start();
|
||||
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
|
||||
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
|
||||
UndefinedConstant(), p0, context, frame_state,
|
||||
effect, control);
|
||||
Reduction r = Reduce(call);
|
||||
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(), IsNumberExp(IsPlainPrimitiveToNumber(p0)));
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Math.floor
|
||||
|
||||
|
@ -1447,6 +1447,19 @@ TEST_F(MachineOperatorReducerTest, Float64Atan2WithNaN) {
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Float64Exp
|
||||
|
||||
TEST_F(MachineOperatorReducerTest, Float64ExpWithConstant) {
|
||||
TRACED_FOREACH(double, x, kFloat64Values) {
|
||||
Reduction const r =
|
||||
Reduce(graph()->NewNode(machine()->Float64Exp(), Float64Constant(x)));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(r.replacement(),
|
||||
IsFloat64Constant(NanSensitiveDoubleEq(base::ieee754::exp(x))));
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Float64Log
|
||||
|
||||
|
@ -2313,6 +2313,7 @@ IS_UNOP_MATCHER(Float64ExtractHighWord32)
|
||||
IS_UNOP_MATCHER(NumberAtan)
|
||||
IS_UNOP_MATCHER(NumberCeil)
|
||||
IS_UNOP_MATCHER(NumberClz32)
|
||||
IS_UNOP_MATCHER(NumberExp)
|
||||
IS_UNOP_MATCHER(NumberFloor)
|
||||
IS_UNOP_MATCHER(NumberFround)
|
||||
IS_UNOP_MATCHER(NumberLog)
|
||||
|
@ -229,6 +229,7 @@ Matcher<Node*> IsNumberAtan2(const Matcher<Node*>& lhs_matcher,
|
||||
const Matcher<Node*>& rhs_matcher);
|
||||
Matcher<Node*> IsNumberCeil(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberClz32(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberExp(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberFloor(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberFround(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberLog(const Matcher<Node*>& value_matcher);
|
||||
|
Loading…
Reference in New Issue
Block a user