Revert of [builtins] Introduce proper Float64Exp operator. (patchset #5 id:80001 of https://codereview.chromium.org/2077533002/ )
Reason for revert: [Sheriff] Leads to some different rounding as it seems in some audio layout tests. Please rebase upstream first if intended: https://build.chromium.org/p/client.v8.fyi/builders/V8-Blink%20Linux%2064/builds/7508 Original issue's description: > [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 > > Committed: https://crrev.com/93e26314afc9da9b5b8bd998688262444ed73260 > Cr-Commit-Position: refs/heads/master@{#37037} TBR=mvstanton@chromium.org,ahaas@chromium.org,bmeurer@chromium.org # Skipping CQ checks because original CL landed less than 1 days ago. NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=v8:3266,v8:3468,v8:3493,v8:5086,v8:5108 Review-Url: https://codereview.chromium.org/2070813002 Cr-Commit-Position: refs/heads/master@{#37039}
This commit is contained in:
parent
6fa656fde2
commit
789b0ad77a
@ -16,6 +16,68 @@ 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) {
|
||||
@ -732,6 +794,94 @@ 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,6 +28,22 @@ 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,6 +15,66 @@ 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;
|
||||
}
|
||||
@ -450,6 +510,127 @@ 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,6 +27,22 @@ 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,6 +178,11 @@ 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
|
||||
|
||||
@ -1001,6 +1006,61 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@ -1293,7 +1353,7 @@ ExternalReference ExternalReference::f64_tan_wrapper_function(
|
||||
}
|
||||
|
||||
static void f64_exp_wrapper(double* param) {
|
||||
WriteDoubleValue(param, base::ieee754::exp(ReadDoubleValue(param)));
|
||||
WriteDoubleValue(param, std::exp(ReadDoubleValue(param)));
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::f64_exp_wrapper_function(
|
||||
@ -1568,11 +1628,6 @@ 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));
|
||||
@ -1593,6 +1648,19 @@ 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,6 +897,8 @@ class ExternalReference BASE_EMBEDDED {
|
||||
};
|
||||
|
||||
static void SetUp();
|
||||
static void InitializeMathExpData();
|
||||
static void TearDownMathExpData();
|
||||
|
||||
typedef void* ExternalReferenceRedirector(Isolate* isolate, void* original,
|
||||
Type type);
|
||||
@ -1042,12 +1044,14 @@ 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,152 +392,6 @@ 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,9 +17,6 @@ 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,9 +1676,6 @@ 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,18 +2452,6 @@ 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,7 +320,6 @@ 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) \
|
||||
@ -635,8 +634,6 @@ 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,6 +60,7 @@ double modulo(double x, double y) {
|
||||
}
|
||||
|
||||
UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction)
|
||||
UNARY_MATH_FUNCTION(exp, CreateExpFunction)
|
||||
|
||||
#undef UNARY_MATH_FUNCTION
|
||||
|
||||
|
@ -93,13 +93,16 @@ 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,9 +709,6 @@ 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,9 +813,6 @@ 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,7 +108,6 @@ class Schedule;
|
||||
|
||||
#define CODE_ASSEMBLER_UNARY_OP_LIST(V) \
|
||||
V(Float64Atan) \
|
||||
V(Float64Exp) \
|
||||
V(Float64Log) \
|
||||
V(Float64Log1p) \
|
||||
V(Float64Log2) \
|
||||
|
@ -655,9 +655,6 @@ 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,7 +91,6 @@ enum class RecordWriteMode { kValueIsMap, kValueIsPointer, kValueIsAny };
|
||||
V(AtomicStoreWord32) \
|
||||
V(Ieee754Float64Atan) \
|
||||
V(Ieee754Float64Atan2) \
|
||||
V(Ieee754Float64Exp) \
|
||||
V(Ieee754Float64Log) \
|
||||
V(Ieee754Float64Log1p) \
|
||||
V(Ieee754Float64Log2) \
|
||||
|
@ -226,7 +226,6 @@ int InstructionScheduler::GetInstructionFlags(const Instruction* instr) const {
|
||||
case kArchComment:
|
||||
case kIeee754Float64Atan:
|
||||
case kIeee754Float64Atan2:
|
||||
case kIeee754Float64Exp:
|
||||
case kIeee754Float64Log:
|
||||
case kIeee754Float64Log1p:
|
||||
case kIeee754Float64Log2:
|
||||
|
@ -1138,8 +1138,6 @@ 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:
|
||||
@ -1261,10 +1259,6 @@ 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,18 +142,6 @@ 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);
|
||||
@ -360,9 +348,6 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
|
||||
case kMathCeil:
|
||||
reduction = ReduceMathCeil(node);
|
||||
break;
|
||||
case kMathExp:
|
||||
reduction = ReduceMathExp(node);
|
||||
break;
|
||||
case kMathFloor:
|
||||
reduction = ReduceMathFloor(node);
|
||||
break;
|
||||
|
@ -33,7 +33,6 @@ 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,11 +402,6 @@ 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,7 +157,6 @@ 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,9 +372,6 @@ 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,9 +747,6 @@ 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,9 +756,6 @@ 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,7 +203,6 @@
|
||||
V(NumberFround) \
|
||||
V(NumberAtan) \
|
||||
V(NumberAtan2) \
|
||||
V(NumberExp) \
|
||||
V(NumberLog) \
|
||||
V(NumberLog1p) \
|
||||
V(NumberLog2) \
|
||||
@ -372,7 +371,6 @@
|
||||
V(Float64Abs) \
|
||||
V(Float64Atan) \
|
||||
V(Float64Atan2) \
|
||||
V(Float64Exp) \
|
||||
V(Float64Log) \
|
||||
V(Float64Log1p) \
|
||||
V(Float64Log2) \
|
||||
|
@ -464,7 +464,6 @@ 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,8 +671,6 @@ 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,7 +1442,6 @@ class RepresentationSelector {
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kNumberAtan:
|
||||
case IrOpcode::kNumberExp:
|
||||
case IrOpcode::kNumberLog:
|
||||
case IrOpcode::kNumberLog1p:
|
||||
case IrOpcode::kNumberLog2:
|
||||
|
@ -254,7 +254,6 @@ 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,7 +181,6 @@ 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,10 +1543,9 @@ 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:
|
||||
@ -1801,10 +1800,6 @@ 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(); }
|
||||
@ -2564,8 +2559,6 @@ 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,7 +753,6 @@ 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:
|
||||
@ -1071,7 +1070,6 @@ 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,9 +873,6 @@ 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,10 +86,9 @@ 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_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)
|
||||
V(MATH_FLOOR, JSFunction, math_floor) \
|
||||
V(MATH_LOG, JSFunction, math_log) \
|
||||
V(MATH_SQRT, JSFunction, math_sqrt)
|
||||
|
||||
#define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \
|
||||
V(ARRAY_CONCAT_INDEX, JSFunction, array_concat) \
|
||||
|
@ -1138,8 +1138,12 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
|
||||
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
|
||||
DCHECK(instr->representation().IsDouble());
|
||||
DCHECK(instr->value()->representation().IsDouble());
|
||||
LOperand* input = UseFixedDouble(instr->value(), d0);
|
||||
return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), d0), instr);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -905,11 +905,24 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
|
||||
};
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 3> {
|
||||
public:
|
||||
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
|
||||
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")
|
||||
};
|
||||
|
@ -3540,10 +3540,16 @@ void LCodeGen::DoPower(LPower* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoMathExp(LMathExp* instr) {
|
||||
__ PrepareCallCFunction(0, 1, scratch0());
|
||||
__ MovToFloatParameter(ToDoubleRegister(instr->value()));
|
||||
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 0, 1);
|
||||
__ MovFromFloatResult(ToDoubleRegister(instr->result()));
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -2462,9 +2462,14 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
|
||||
case kMathExp: {
|
||||
DCHECK(instr->representation().IsDouble());
|
||||
DCHECK(instr->value()->representation().IsDouble());
|
||||
LOperand* input = UseFixedDouble(instr->value(), d0);
|
||||
LMathExp* result = new (zone()) LMathExp(input);
|
||||
return MarkAsCall(DefineFixedDouble(result, d0), instr);
|
||||
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);
|
||||
}
|
||||
case kMathFloor: {
|
||||
DCHECK(instr->value()->representation().IsDouble());
|
||||
|
@ -1763,9 +1763,26 @@ class LMathAbsTagged: public LTemplateInstruction<1, 2, 3> {
|
||||
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
|
||||
};
|
||||
|
||||
class LMathExp final : public LUnaryMathOperation<0> {
|
||||
|
||||
class LMathExp final : public LUnaryMathOperation<4> {
|
||||
public:
|
||||
explicit LMathExp(LOperand* value) : LUnaryMathOperation<0>(value) {}
|
||||
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]; }
|
||||
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
|
||||
};
|
||||
|
@ -3548,10 +3548,17 @@ void LCodeGen::DoMathAbsTagged(LMathAbsTagged* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoMathExp(LMathExp* instr) {
|
||||
DCHECK(instr->IsMarkedAsCall());
|
||||
DCHECK(ToDoubleRegister(instr->value()).is(d0));
|
||||
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 0, 1);
|
||||
DCHECK(ToDoubleRegister(instr->result()).Is(d0));
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3423,7 +3423,8 @@ HInstruction* HUnaryMathOperation::New(Isolate* isolate, Zone* zone,
|
||||
}
|
||||
switch (op) {
|
||||
case kMathExp:
|
||||
return H_CONSTANT_DOUBLE(base::ieee754::exp(d));
|
||||
lazily_initialize_fast_exp(isolate);
|
||||
return H_CONSTANT_DOUBLE(fast_exp(d, isolate));
|
||||
case kMathLog:
|
||||
return H_CONSTANT_DOUBLE(base::ieee754::log(d));
|
||||
case kMathSqrt:
|
||||
|
@ -8856,6 +8856,8 @@ 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,16 +3425,11 @@ void LCodeGen::DoMathClz32(LMathClz32* instr) {
|
||||
void LCodeGen::DoMathExp(LMathExp* instr) {
|
||||
XMMRegister input = ToDoubleRegister(instr->value());
|
||||
XMMRegister result = ToDoubleRegister(instr->result());
|
||||
// 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));
|
||||
XMMRegister temp0 = double_scratch0();
|
||||
Register temp1 = ToRegister(instr->temp1());
|
||||
Register temp2 = ToRegister(instr->temp2());
|
||||
|
||||
MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2);
|
||||
}
|
||||
|
||||
void LCodeGen::PrepareForTailCall(const ParameterCount& actual,
|
||||
|
@ -1181,8 +1181,11 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
|
||||
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
|
||||
DCHECK(instr->representation().IsDouble());
|
||||
DCHECK(instr->value()->representation().IsDouble());
|
||||
LOperand* input = UseRegisterAtStart(instr->value());
|
||||
return MarkAsCall(DefineSameAsFirst(new (zone()) LMathExp(input)), instr);
|
||||
LOperand* value = UseTempRegister(instr->value());
|
||||
LOperand* temp1 = TempRegister();
|
||||
LOperand* temp2 = TempRegister();
|
||||
LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
|
||||
return DefineAsRegister(result);
|
||||
}
|
||||
|
||||
|
||||
|
@ -912,11 +912,21 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
|
||||
};
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 2> {
|
||||
public:
|
||||
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
|
||||
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")
|
||||
};
|
||||
|
@ -3492,10 +3492,16 @@ void LCodeGen::DoPower(LPower* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoMathExp(LMathExp* instr) {
|
||||
__ PrepareCallCFunction(0, 1, scratch0());
|
||||
__ MovToFloatParameter(ToDoubleRegister(instr->value()));
|
||||
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 0, 1);
|
||||
__ MovFromFloatResult(ToDoubleRegister(instr->result()));
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1107,8 +1107,12 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
|
||||
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
|
||||
DCHECK(instr->representation().IsDouble());
|
||||
DCHECK(instr->value()->representation().IsDouble());
|
||||
LOperand* input = UseFixedDouble(instr->value(), f4);
|
||||
return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), f4), instr);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -882,11 +882,24 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
|
||||
};
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 3> {
|
||||
public:
|
||||
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
|
||||
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")
|
||||
};
|
||||
|
@ -3695,10 +3695,16 @@ void LCodeGen::DoPower(LPower* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoMathExp(LMathExp* instr) {
|
||||
__ PrepareCallCFunction(0, 1, scratch0());
|
||||
__ MovToFloatParameter(ToDoubleRegister(instr->value()));
|
||||
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 0, 1);
|
||||
__ MovFromFloatResult(ToDoubleRegister(instr->result()));
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1107,8 +1107,12 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
|
||||
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
|
||||
DCHECK(instr->representation().IsDouble());
|
||||
DCHECK(instr->value()->representation().IsDouble());
|
||||
LOperand* input = UseFixedDouble(instr->value(), f4);
|
||||
return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), f4), instr);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -900,11 +900,24 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
|
||||
};
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 3> {
|
||||
public:
|
||||
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
|
||||
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")
|
||||
};
|
||||
|
@ -3600,10 +3600,13 @@ void LCodeGen::DoPower(LPower* instr) {
|
||||
|
||||
|
||||
void LCodeGen::DoMathExp(LMathExp* instr) {
|
||||
DCHECK(ToDoubleRegister(instr->value()).is(xmm0));
|
||||
DCHECK(ToDoubleRegister(instr->result()).is(xmm0));
|
||||
__ PrepareCallCFunction(1);
|
||||
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 1);
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1171,9 +1171,11 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
|
||||
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
|
||||
DCHECK(instr->representation().IsDouble());
|
||||
DCHECK(instr->value()->representation().IsDouble());
|
||||
LOperand* input = UseFixedDouble(instr->value(), xmm0);
|
||||
return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), xmm0),
|
||||
instr);
|
||||
LOperand* value = UseTempRegister(instr->value());
|
||||
LOperand* temp1 = TempRegister();
|
||||
LOperand* temp2 = TempRegister();
|
||||
LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
|
||||
return DefineAsRegister(result);
|
||||
}
|
||||
|
||||
|
||||
|
@ -909,11 +909,19 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
|
||||
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
|
||||
};
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
|
||||
|
||||
class LMathExp final : public LTemplateInstruction<1, 1, 2> {
|
||||
public:
|
||||
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
|
||||
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")
|
||||
};
|
||||
|
@ -71,8 +71,6 @@ 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,6 +34,43 @@ 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.
|
||||
@ -891,6 +928,64 @@ 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,6 +29,19 @@ 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,6 +29,11 @@ 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));
|
||||
@ -179,6 +184,7 @@ utils.InstallConstants(GlobalMath, [
|
||||
utils.InstallFunctions(GlobalMath, DONT_ENUM, [
|
||||
"random", MathRandom,
|
||||
"abs", MathAbs,
|
||||
"exp", MathExp,
|
||||
"pow", MathPowJS,
|
||||
"sign", MathSign,
|
||||
"asinh", MathAsinh,
|
||||
@ -197,6 +203,7 @@ utils.InstallFunctions(GlobalMath, DONT_ENUM, [
|
||||
|
||||
utils.Export(function(to) {
|
||||
to.MathAbs = MathAbs;
|
||||
to.MathExp = MathExp;
|
||||
to.IntRandom = MathRandomRaw;
|
||||
});
|
||||
|
||||
|
@ -16,6 +16,60 @@ 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) {
|
||||
@ -1038,6 +1092,95 @@ 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,6 +29,23 @@ 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,6 +17,59 @@ 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) {
|
||||
@ -1037,6 +1090,94 @@ 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,6 +29,23 @@ 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,6 +59,17 @@ 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,6 +355,7 @@ 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,11 +31,13 @@
|
||||
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) {
|
||||
@ -632,11 +634,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 * %math_exp(ax);
|
||||
if (ax < LOG_MAXD) return h * MathExp(ax);
|
||||
// |x| in [log(maxdouble), overflowthreshold]
|
||||
// overflowthreshold = 710.4758600739426
|
||||
if (ax <= KSINH_OVERFLOW) {
|
||||
var w = %math_exp(0.5 * ax);
|
||||
var w = MathExp(0.5 * ax);
|
||||
var t = h * w;
|
||||
return t * w;
|
||||
}
|
||||
@ -682,14 +684,14 @@ function MathCosh(x) {
|
||||
}
|
||||
// |x| in [0.5*log2, 22], return (exp(|x|)+1/exp(|x|)/2
|
||||
if (ix < 0x40360000) {
|
||||
var t = %math_exp(MathAbs(x));
|
||||
var t = MathExp(MathAbs(x));
|
||||
return 0.5 * t + 0.5 / t;
|
||||
}
|
||||
// |x| in [22, log(maxdouble)], return half*exp(|x|)
|
||||
if (ix < 0x40862e42) return 0.5 * %math_exp(MathAbs(x));
|
||||
if (ix < 0x40862e42) return 0.5 * MathExp(MathAbs(x));
|
||||
// |x| in [log(maxdouble), overflowthreshold]
|
||||
if (MathAbs(x) <= KCOSH_OVERFLOW) {
|
||||
var w = %math_exp(0.5 * MathAbs(x));
|
||||
var w = MathExp(0.5 * MathAbs(x));
|
||||
var t = 0.5 * w;
|
||||
return t * w;
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ void V8::TearDown() {
|
||||
Bootstrapper::TearDownExtensions();
|
||||
ElementsAccessor::TearDown();
|
||||
LOperand::TearDownCaches();
|
||||
ExternalReference::TearDownMathExpData();
|
||||
RegisteredExtension::UnregisterAll();
|
||||
Isolate::GlobalTearDown();
|
||||
sampler::Sampler::TearDown();
|
||||
|
@ -32,6 +32,38 @@ 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.
|
||||
@ -467,6 +499,59 @@ 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,6 +28,20 @@ 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,19 +5517,6 @@ 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,23 +54,6 @@ 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,45 +263,6 @@ 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,19 +1447,6 @@ 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,7 +2313,6 @@ 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,7 +229,6 @@ 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