diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc index a7b38ffee6..4014aba10e 100644 --- a/src/arm/codegen-arm.cc +++ b/src/arm/codegen-arm.cc @@ -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(base::OS::Allocate(1 * KB, &actual_size, true)); + if (buffer == nullptr) return nullptr; + ExternalReference::InitializeMathExpData(); + + MacroAssembler masm(isolate, buffer, static_cast(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(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 + (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 diff --git a/src/arm/codegen-arm.h b/src/arm/codegen-arm.h index 00867392ed..880825a1be 100644 --- a/src/arm/codegen-arm.h +++ b/src/arm/codegen-arm.h @@ -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 diff --git a/src/arm64/codegen-arm64.cc b/src/arm64/codegen-arm64.cc index edd289900e..990dd4101f 100644 --- a/src/arm64/codegen-arm64.cc +++ b/src/arm64/codegen-arm64.cc @@ -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(base::OS::Allocate(1 * KB, &actual_size, true)); + if (buffer == nullptr) return nullptr; + + ExternalReference::InitializeMathExpData(); + MacroAssembler masm(isolate, buffer, static_cast(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(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 diff --git a/src/arm64/codegen-arm64.h b/src/arm64/codegen-arm64.h index b0490a8a03..573f6fe159 100644 --- a/src/arm64/codegen-arm64.h +++ b/src/arm64/codegen-arm64.h @@ -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 diff --git a/src/assembler.cc b/src/assembler.cc index 14b993abbb..2332408f16 100644 --- a/src/assembler.cc +++ b/src/assembler.cc @@ -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(static_cast(0xFFFFFFFF)) + 1; + + math_exp_data_mutex = new base::Mutex(); +} + + +void ExternalReference::InitializeMathExpData() { + // Early return? + if (math_exp_data_initialized) return; + + base::LockGuard 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(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(static_cast(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(value); + bits &= (static_cast(1) << 52) - 1; + double mantissa = bit_cast(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(math_exp_constants_array + constant_index)); +} + + +ExternalReference ExternalReference::math_exp_log_table() { + DCHECK(math_exp_data_initialized); + return ExternalReference(reinterpret_cast(math_exp_log_table_array)); +} + + ExternalReference ExternalReference::page_flags(Page* page) { return ExternalReference(reinterpret_cast
(page) + MemoryChunk::kFlagsOffset); diff --git a/src/assembler.h b/src/assembler.h index 836c8304bc..38078f3d22 100644 --- a/src/assembler.h +++ b/src/assembler.h @@ -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); diff --git a/src/base/ieee754.cc b/src/base/ieee754.cc index e642b6327a..4d11bdafe8 100644 --- a/src/base/ieee754.cc +++ b/src/base/ieee754.cc @@ -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(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 * diff --git a/src/base/ieee754.h b/src/base/ieee754.h index 17034e50fc..5a2e534289 100644 --- a/src/base/ieee754.h +++ b/src/base/ieee754.h @@ -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); diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 67fe134569..57f3e68a8a 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -1676,9 +1676,6 @@ void Genesis::InitializeGlobal(Handle global_object, SimpleInstallFunction(math, "atan2", Builtins::kMathAtan2, 2, true); SimpleInstallFunction(math, "ceil", Builtins::kMathCeil, 1, true); SimpleInstallFunction(math, "clz32", Builtins::kMathClz32, 1, true); - Handle math_exp = - SimpleInstallFunction(math, "exp", Builtins::kMathExp, 1, true); - native_context()->set_math_exp(*math_exp); Handle math_floor = SimpleInstallFunction(math, "floor", Builtins::kMathFloor, 1, true); native_context()->set_math_floor(*math_floor); diff --git a/src/builtins.cc b/src/builtins.cc index 905427606b..3181477700 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -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); diff --git a/src/builtins.h b/src/builtins.h index 4b6bffad9e..67ffabfe3e 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -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 ) diff --git a/src/codegen.cc b/src/codegen.cc index 4597ae2766..6ed9f49522 100644 --- a/src/codegen.cc +++ b/src/codegen.cc @@ -60,6 +60,7 @@ double modulo(double x, double y) { } UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction) +UNARY_MATH_FUNCTION(exp, CreateExpFunction) #undef UNARY_MATH_FUNCTION diff --git a/src/codegen.h b/src/codegen.h index 82962ad802..f941696774 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -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); diff --git a/src/compiler/arm/code-generator-arm.cc b/src/compiler/arm/code-generator-arm.cc index 5f0ad0b4d9..88f3d79360 100644 --- a/src/compiler/arm/code-generator-arm.cc +++ b/src/compiler/arm/code-generator-arm.cc @@ -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; diff --git a/src/compiler/arm64/code-generator-arm64.cc b/src/compiler/arm64/code-generator-arm64.cc index a5333762c7..d933bbf3fb 100644 --- a/src/compiler/arm64/code-generator-arm64.cc +++ b/src/compiler/arm64/code-generator-arm64.cc @@ -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; diff --git a/src/compiler/code-assembler.h b/src/compiler/code-assembler.h index f2ed403aaa..033d947755 100644 --- a/src/compiler/code-assembler.h +++ b/src/compiler/code-assembler.h @@ -108,7 +108,6 @@ class Schedule; #define CODE_ASSEMBLER_UNARY_OP_LIST(V) \ V(Float64Atan) \ - V(Float64Exp) \ V(Float64Log) \ V(Float64Log1p) \ V(Float64Log2) \ diff --git a/src/compiler/ia32/code-generator-ia32.cc b/src/compiler/ia32/code-generator-ia32.cc index 81b0475316..c4122f6b25 100644 --- a/src/compiler/ia32/code-generator-ia32.cc +++ b/src/compiler/ia32/code-generator-ia32.cc @@ -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; diff --git a/src/compiler/instruction-codes.h b/src/compiler/instruction-codes.h index ecec346658..99db5b5d33 100644 --- a/src/compiler/instruction-codes.h +++ b/src/compiler/instruction-codes.h @@ -91,7 +91,6 @@ enum class RecordWriteMode { kValueIsMap, kValueIsPointer, kValueIsAny }; V(AtomicStoreWord32) \ V(Ieee754Float64Atan) \ V(Ieee754Float64Atan2) \ - V(Ieee754Float64Exp) \ V(Ieee754Float64Log) \ V(Ieee754Float64Log1p) \ V(Ieee754Float64Log2) \ diff --git a/src/compiler/instruction-scheduler.cc b/src/compiler/instruction-scheduler.cc index dd78a9c9c0..308ee94392 100644 --- a/src/compiler/instruction-scheduler.cc +++ b/src/compiler/instruction-scheduler.cc @@ -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: diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc index 048875732f..7b9b8e1e1a 100644 --- a/src/compiler/instruction-selector.cc +++ b/src/compiler/instruction-selector.cc @@ -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); } diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc index 84c07dc9d5..363ad9db4e 100644 --- a/src/compiler/js-builtin-reducer.cc +++ b/src/compiler/js-builtin-reducer.cc @@ -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; diff --git a/src/compiler/js-builtin-reducer.h b/src/compiler/js-builtin-reducer.h index 79265f2b8c..e9ec4e749e 100644 --- a/src/compiler/js-builtin-reducer.h +++ b/src/compiler/js-builtin-reducer.h @@ -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); diff --git a/src/compiler/machine-operator-reducer.cc b/src/compiler/machine-operator-reducer.cc index d0e1eb1ab7..54ac617775 100644 --- a/src/compiler/machine-operator-reducer.cc +++ b/src/compiler/machine-operator-reducer.cc @@ -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())); diff --git a/src/compiler/machine-operator.cc b/src/compiler/machine-operator.cc index 2267eef7fa..e4feeaea42 100644 --- a/src/compiler/machine-operator.cc +++ b/src/compiler/machine-operator.cc @@ -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) \ diff --git a/src/compiler/machine-operator.h b/src/compiler/machine-operator.h index 2478e3fe5a..a56d325ac3 100644 --- a/src/compiler/machine-operator.h +++ b/src/compiler/machine-operator.h @@ -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(); diff --git a/src/compiler/mips/code-generator-mips.cc b/src/compiler/mips/code-generator-mips.cc index e4a87cb909..792ddc01eb 100644 --- a/src/compiler/mips/code-generator-mips.cc +++ b/src/compiler/mips/code-generator-mips.cc @@ -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; diff --git a/src/compiler/mips64/code-generator-mips64.cc b/src/compiler/mips64/code-generator-mips64.cc index 10950e26e4..4fc696a245 100644 --- a/src/compiler/mips64/code-generator-mips64.cc +++ b/src/compiler/mips64/code-generator-mips64.cc @@ -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; diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h index d203316278..73d3a36022 100644 --- a/src/compiler/opcodes.h +++ b/src/compiler/opcodes.h @@ -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) \ diff --git a/src/compiler/raw-machine-assembler.h b/src/compiler/raw-machine-assembler.h index e0400115ec..0e4e2dcd22 100644 --- a/src/compiler/raw-machine-assembler.h +++ b/src/compiler/raw-machine-assembler.h @@ -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); } diff --git a/src/compiler/representation-change.cc b/src/compiler/representation-change.cc index e6e66b6479..eaf1eb46da 100644 --- a/src/compiler/representation-change.cc +++ b/src/compiler/representation-change.cc @@ -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: diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc index fc30c76c91..3cbaca7810 100644 --- a/src/compiler/simplified-lowering.cc +++ b/src/compiler/simplified-lowering.cc @@ -1442,7 +1442,6 @@ class RepresentationSelector { return; } case IrOpcode::kNumberAtan: - case IrOpcode::kNumberExp: case IrOpcode::kNumberLog: case IrOpcode::kNumberLog1p: case IrOpcode::kNumberLog2: diff --git a/src/compiler/simplified-operator.cc b/src/compiler/simplified-operator.cc index 0c73e5d482..2fe003e7e7 100644 --- a/src/compiler/simplified-operator.cc +++ b/src/compiler/simplified-operator.cc @@ -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) \ diff --git a/src/compiler/simplified-operator.h b/src/compiler/simplified-operator.h index f2098a90b8..266af20e3f 100644 --- a/src/compiler/simplified-operator.h +++ b/src/compiler/simplified-operator.h @@ -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(); diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc index 7826e1703c..7caf16dff9 100644 --- a/src/compiler/typer.cc +++ b/src/compiler/typer.cc @@ -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(); } diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc index c27e1cc09e..2eadd2edbc 100644 --- a/src/compiler/verifier.cc +++ b/src/compiler/verifier.cc @@ -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: diff --git a/src/compiler/x64/code-generator-x64.cc b/src/compiler/x64/code-generator-x64.cc index 25a7cc1541..ab32274596 100644 --- a/src/compiler/x64/code-generator-x64.cc +++ b/src/compiler/x64/code-generator-x64.cc @@ -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; diff --git a/src/contexts.h b/src/contexts.h index c2678b6040..e53bf88674 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -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) \ diff --git a/src/crankshaft/arm/lithium-arm.cc b/src/crankshaft/arm/lithium-arm.cc index f0f9327a50..b015d06299 100644 --- a/src/crankshaft/arm/lithium-arm.cc +++ b/src/crankshaft/arm/lithium-arm.cc @@ -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); } diff --git a/src/crankshaft/arm/lithium-arm.h b/src/crankshaft/arm/lithium-arm.h index 1f18392d69..2ec992fd3e 100644 --- a/src/crankshaft/arm/lithium-arm.h +++ b/src/crankshaft/arm/lithium-arm.h @@ -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") }; diff --git a/src/crankshaft/arm/lithium-codegen-arm.cc b/src/crankshaft/arm/lithium-codegen-arm.cc index 65ad7107e1..8eda5922f4 100644 --- a/src/crankshaft/arm/lithium-codegen-arm.cc +++ b/src/crankshaft/arm/lithium-codegen-arm.cc @@ -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()); } diff --git a/src/crankshaft/arm64/lithium-arm64.cc b/src/crankshaft/arm64/lithium-arm64.cc index e18fca528b..d00bc17d47 100644 --- a/src/crankshaft/arm64/lithium-arm64.cc +++ b/src/crankshaft/arm64/lithium-arm64.cc @@ -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()); diff --git a/src/crankshaft/arm64/lithium-arm64.h b/src/crankshaft/arm64/lithium-arm64.h index 98902434a9..383e5c33c1 100644 --- a/src/crankshaft/arm64/lithium-arm64.h +++ b/src/crankshaft/arm64/lithium-arm64.h @@ -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") }; diff --git a/src/crankshaft/arm64/lithium-codegen-arm64.cc b/src/crankshaft/arm64/lithium-codegen-arm64.cc index 0754b85029..422b7271b4 100644 --- a/src/crankshaft/arm64/lithium-codegen-arm64.cc +++ b/src/crankshaft/arm64/lithium-codegen-arm64.cc @@ -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); } diff --git a/src/crankshaft/hydrogen-instructions.cc b/src/crankshaft/hydrogen-instructions.cc index 5d3c56d5b6..70b3f6d541 100644 --- a/src/crankshaft/hydrogen-instructions.cc +++ b/src/crankshaft/hydrogen-instructions.cc @@ -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: diff --git a/src/crankshaft/hydrogen.cc b/src/crankshaft/hydrogen.cc index 43f2539606..a7958e1d60 100644 --- a/src/crankshaft/hydrogen.cc +++ b/src/crankshaft/hydrogen.cc @@ -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: diff --git a/src/crankshaft/ia32/lithium-codegen-ia32.cc b/src/crankshaft/ia32/lithium-codegen-ia32.cc index 48a7f3f135..cdd96a0826 100644 --- a/src/crankshaft/ia32/lithium-codegen-ia32.cc +++ b/src/crankshaft/ia32/lithium-codegen-ia32.cc @@ -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, diff --git a/src/crankshaft/ia32/lithium-ia32.cc b/src/crankshaft/ia32/lithium-ia32.cc index 22e923e868..5e9561bfc0 100644 --- a/src/crankshaft/ia32/lithium-ia32.cc +++ b/src/crankshaft/ia32/lithium-ia32.cc @@ -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); } diff --git a/src/crankshaft/ia32/lithium-ia32.h b/src/crankshaft/ia32/lithium-ia32.h index 894f6f0944..d1d5a06dc4 100644 --- a/src/crankshaft/ia32/lithium-ia32.h +++ b/src/crankshaft/ia32/lithium-ia32.h @@ -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") }; diff --git a/src/crankshaft/mips/lithium-codegen-mips.cc b/src/crankshaft/mips/lithium-codegen-mips.cc index 3cee6db394..d351db1c56 100644 --- a/src/crankshaft/mips/lithium-codegen-mips.cc +++ b/src/crankshaft/mips/lithium-codegen-mips.cc @@ -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()); } diff --git a/src/crankshaft/mips/lithium-mips.cc b/src/crankshaft/mips/lithium-mips.cc index ea14026d9a..7b481db188 100644 --- a/src/crankshaft/mips/lithium-mips.cc +++ b/src/crankshaft/mips/lithium-mips.cc @@ -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); } diff --git a/src/crankshaft/mips/lithium-mips.h b/src/crankshaft/mips/lithium-mips.h index d6fd59e443..ea5e79289f 100644 --- a/src/crankshaft/mips/lithium-mips.h +++ b/src/crankshaft/mips/lithium-mips.h @@ -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") }; diff --git a/src/crankshaft/mips64/lithium-codegen-mips64.cc b/src/crankshaft/mips64/lithium-codegen-mips64.cc index 9a0b54037f..c5c93b9029 100644 --- a/src/crankshaft/mips64/lithium-codegen-mips64.cc +++ b/src/crankshaft/mips64/lithium-codegen-mips64.cc @@ -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()); } diff --git a/src/crankshaft/mips64/lithium-mips64.cc b/src/crankshaft/mips64/lithium-mips64.cc index f001ee487a..17f59d84fc 100644 --- a/src/crankshaft/mips64/lithium-mips64.cc +++ b/src/crankshaft/mips64/lithium-mips64.cc @@ -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); } diff --git a/src/crankshaft/mips64/lithium-mips64.h b/src/crankshaft/mips64/lithium-mips64.h index cc44ae6f43..5d282ec7aa 100644 --- a/src/crankshaft/mips64/lithium-mips64.h +++ b/src/crankshaft/mips64/lithium-mips64.h @@ -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") }; diff --git a/src/crankshaft/x64/lithium-codegen-x64.cc b/src/crankshaft/x64/lithium-codegen-x64.cc index 236157a24c..0a2a0b687c 100644 --- a/src/crankshaft/x64/lithium-codegen-x64.cc +++ b/src/crankshaft/x64/lithium-codegen-x64.cc @@ -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); } diff --git a/src/crankshaft/x64/lithium-x64.cc b/src/crankshaft/x64/lithium-x64.cc index 192c3beac9..22d8ac5b77 100644 --- a/src/crankshaft/x64/lithium-x64.cc +++ b/src/crankshaft/x64/lithium-x64.cc @@ -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); } diff --git a/src/crankshaft/x64/lithium-x64.h b/src/crankshaft/x64/lithium-x64.h index 2ee0e4e6f9..91f554137a 100644 --- a/src/crankshaft/x64/lithium-x64.h +++ b/src/crankshaft/x64/lithium-x64.h @@ -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") }; diff --git a/src/external-reference-table.cc b/src/external-reference-table.cc index 5d280bfd87..ac9d0bd578 100644 --- a/src/external-reference-table.cc +++ b/src/external-reference-table.cc @@ -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(), diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc index 18e53641e6..267fe5c596 100644 --- a/src/ia32/codegen-ia32.cc +++ b/src/ia32/codegen-ia32.cc @@ -34,6 +34,43 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { #define __ masm. +UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) { + size_t actual_size; + byte* buffer = + static_cast(base::OS::Allocate(1 * KB, &actual_size, true)); + if (buffer == nullptr) return nullptr; + ExternalReference::InitializeMathExpData(); + + MacroAssembler masm(isolate, buffer, static_cast(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(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(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 __ diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h index 46468e9aa5..133b1adbdf 100644 --- a/src/ia32/codegen-ia32.h +++ b/src/ia32/codegen-ia32.h @@ -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 diff --git a/src/js/math.js b/src/js/math.js index abb1251e3d..9224010ca6 100644 --- a/src/js/math.js +++ b/src/js/math.js @@ -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; }); diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc index 07cab80699..63bbda3168 100644 --- a/src/mips/codegen-mips.cc +++ b/src/mips/codegen-mips.cc @@ -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(base::OS::Allocate(1 * KB, &actual_size, true)); + if (buffer == nullptr) return nullptr; + ExternalReference::InitializeMathExpData(); + + MacroAssembler masm(isolate, buffer, static_cast(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(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 + (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; diff --git a/src/mips/codegen-mips.h b/src/mips/codegen-mips.h index a4f818425a..ad7abb30c5 100644 --- a/src/mips/codegen-mips.h +++ b/src/mips/codegen-mips.h @@ -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 diff --git a/src/mips64/codegen-mips64.cc b/src/mips64/codegen-mips64.cc index a8f5890401..678f606cb5 100644 --- a/src/mips64/codegen-mips64.cc +++ b/src/mips64/codegen-mips64.cc @@ -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(base::OS::Allocate(1 * KB, &actual_size, true)); + if (buffer == nullptr) return nullptr; + ExternalReference::InitializeMathExpData(); + + MacroAssembler masm(isolate, buffer, static_cast(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(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 + (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; diff --git a/src/mips64/codegen-mips64.h b/src/mips64/codegen-mips64.h index a4f818425a..ad7abb30c5 100644 --- a/src/mips64/codegen-mips64.h +++ b/src/mips64/codegen-mips64.h @@ -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 diff --git a/src/runtime/runtime-maths.cc b/src/runtime/runtime-maths.cc index fb8e083deb..47fe705400 100644 --- a/src/runtime/runtime-maths.cc +++ b/src/runtime/runtime-maths.cc @@ -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) { diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 80007466b9..e8d4353c87 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -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) diff --git a/src/third_party/fdlibm/fdlibm.js b/src/third_party/fdlibm/fdlibm.js index 935b777b31..b9c9b3375f 100644 --- a/src/third_party/fdlibm/fdlibm.js +++ b/src/third_party/fdlibm/fdlibm.js @@ -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; } diff --git a/src/v8.cc b/src/v8.cc index d660b58c10..6a7aaab062 100644 --- a/src/v8.cc +++ b/src/v8.cc @@ -45,6 +45,7 @@ void V8::TearDown() { Bootstrapper::TearDownExtensions(); ElementsAccessor::TearDown(); LOperand::TearDownCaches(); + ExternalReference::TearDownMathExpData(); RegisteredExtension::UnregisterAll(); Isolate::GlobalTearDown(); sampler::Sampler::TearDown(); diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc index 911f3cb64a..6731e9eba8 100644 --- a/src/x64/codegen-x64.cc +++ b/src/x64/codegen-x64.cc @@ -32,6 +32,38 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const { #define __ masm. +UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) { + size_t actual_size; + byte* buffer = + static_cast(base::OS::Allocate(1 * KB, &actual_size, true)); + if (buffer == nullptr) return nullptr; + ExternalReference::InitializeMathExpData(); + + MacroAssembler masm(isolate, buffer, static_cast(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(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 __ diff --git a/src/x64/codegen-x64.h b/src/x64/codegen-x64.h index 62945f70f8..1403781c67 100644 --- a/src/x64/codegen-x64.h +++ b/src/x64/codegen-x64.h @@ -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 diff --git a/test/cctest/compiler/test-run-machops.cc b/test/cctest/compiler/test-run-machops.cc index 1f497f1a24..ab5c7d9093 100644 --- a/test/cctest/compiler/test-run-machops.cc +++ b/test/cctest/compiler/test-run-machops.cc @@ -5517,19 +5517,6 @@ TEST(RunFloat64Atan2) { } } -TEST(RunFloat64Exp) { - BufferedRawMachineAssemblerTester m(MachineType::Float64()); - m.Return(m.Float64Exp(m.Parameter(0))); - CHECK(std::isnan(m.Call(std::numeric_limits::quiet_NaN()))); - CHECK(std::isnan(m.Call(std::numeric_limits::signaling_NaN()))); - CHECK_EQ(0.0, m.Call(-std::numeric_limits::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::infinity(), - m.Call(std::numeric_limits::infinity())); - FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(ieee754::exp(*i), m.Call(*i)); } -} - TEST(RunFloat64Log) { BufferedRawMachineAssemblerTester m(MachineType::Float64()); m.Return(m.Float64Log(m.Parameter(0))); diff --git a/test/unittests/base/ieee754-unittest.cc b/test/unittests/base/ieee754-unittest.cc index 7246ece345..8ee69ec266 100644 --- a/test/unittests/base/ieee754-unittest.cc +++ b/test/unittests/base/ieee754-unittest.cc @@ -54,23 +54,6 @@ TEST(Ieee754, Atan2) { -std::numeric_limits::infinity())); } -TEST(Ieee754, Exp) { - EXPECT_THAT(exp(std::numeric_limits::quiet_NaN()), IsNaN()); - EXPECT_THAT(exp(std::numeric_limits::signaling_NaN()), IsNaN()); - EXPECT_EQ(0.0, exp(-std::numeric_limits::infinity())); - EXPECT_EQ(std::numeric_limits::infinity(), - exp(std::numeric_limits::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::infinity(), exp(710.0)); -} - TEST(Ieee754, Log) { EXPECT_THAT(log(std::numeric_limits::quiet_NaN()), IsNaN()); EXPECT_THAT(log(std::numeric_limits::signaling_NaN()), IsNaN()); diff --git a/test/unittests/compiler/js-builtin-reducer-unittest.cc b/test/unittests/compiler/js-builtin-reducer-unittest.cc index 60d996cca2..5ec29c45e9 100644 --- a/test/unittests/compiler/js-builtin-reducer-unittest.cc +++ b/test/unittests/compiler/js-builtin-reducer-unittest.cc @@ -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 diff --git a/test/unittests/compiler/machine-operator-reducer-unittest.cc b/test/unittests/compiler/machine-operator-reducer-unittest.cc index 2a161ce82d..9d7482af76 100644 --- a/test/unittests/compiler/machine-operator-reducer-unittest.cc +++ b/test/unittests/compiler/machine-operator-reducer-unittest.cc @@ -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 diff --git a/test/unittests/compiler/node-test-utils.cc b/test/unittests/compiler/node-test-utils.cc index bba12769c9..c60fdedb7a 100644 --- a/test/unittests/compiler/node-test-utils.cc +++ b/test/unittests/compiler/node-test-utils.cc @@ -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) diff --git a/test/unittests/compiler/node-test-utils.h b/test/unittests/compiler/node-test-utils.h index edbef01046..cd4af76f55 100644 --- a/test/unittests/compiler/node-test-utils.h +++ b/test/unittests/compiler/node-test-utils.h @@ -229,7 +229,6 @@ Matcher IsNumberAtan2(const Matcher& lhs_matcher, const Matcher& rhs_matcher); Matcher IsNumberCeil(const Matcher& value_matcher); Matcher IsNumberClz32(const Matcher& value_matcher); -Matcher IsNumberExp(const Matcher& value_matcher); Matcher IsNumberFloor(const Matcher& value_matcher); Matcher IsNumberFround(const Matcher& value_matcher); Matcher IsNumberLog(const Matcher& value_matcher);