[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.

CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_chromium_rel_ng;tryserver.blink:linux_blink_rel
BUG=v8:3266,v8:3468,v8:3493,v8:5086,v8:5108,chromium:620786
R=mvstanton@chromium.org

Committed: https://crrev.com/93e26314afc9da9b5b8bd998688262444ed73260
Review-Url: https://codereview.chromium.org/2077533002
Cr-Original-Commit-Position: refs/heads/master@{#37037}
Cr-Commit-Position: refs/heads/master@{#37047}
This commit is contained in:
bmeurer 2016-06-16 22:19:35 -07:00 committed by Commit bot
parent d3597aee1f
commit d5f2ac5e33
77 changed files with 407 additions and 1181 deletions

View File

@ -16,68 +16,6 @@ namespace internal {
#define __ masm.
#if defined(USE_SIMULATOR)
byte* fast_exp_arm_machine_code = nullptr;
double fast_exp_simulator(double x, Isolate* isolate) {
return Simulator::current(isolate)
->CallFPReturnsDouble(fast_exp_arm_machine_code, x, 0);
}
#endif
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
size_t actual_size;
byte* buffer =
static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
if (buffer == nullptr) return nullptr;
ExternalReference::InitializeMathExpData();
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
CodeObjectRequired::kNo);
{
DwVfpRegister input = d0;
DwVfpRegister result = d1;
DwVfpRegister double_scratch1 = d2;
DwVfpRegister double_scratch2 = d3;
Register temp1 = r4;
Register temp2 = r5;
Register temp3 = r6;
if (masm.use_eabi_hardfloat()) {
// Input value is in d0 anyway, nothing to do.
} else {
__ vmov(input, r0, r1);
}
__ Push(temp3, temp2, temp1);
MathExpGenerator::EmitMathExp(
&masm, input, result, double_scratch1, double_scratch2,
temp1, temp2, temp3);
__ Pop(temp3, temp2, temp1);
if (masm.use_eabi_hardfloat()) {
__ vmov(d0, result);
} else {
__ vmov(r0, r1, result);
}
__ Ret();
}
CodeDesc desc;
masm.GetCode(&desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
Assembler::FlushICache(isolate, buffer, actual_size);
base::OS::ProtectCode(buffer, actual_size);
#if !defined(USE_SIMULATOR)
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
#else
fast_exp_arm_machine_code = buffer;
return &fast_exp_simulator;
#endif
}
#if defined(V8_HOST_ARCH_ARM)
MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
MemCopyUint8Function stub) {
@ -794,94 +732,6 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm,
__ bind(&done);
}
static MemOperand ExpConstant(int index, Register base) {
return MemOperand(base, index * kDoubleSize);
}
void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
DwVfpRegister input,
DwVfpRegister result,
DwVfpRegister double_scratch1,
DwVfpRegister double_scratch2,
Register temp1,
Register temp2,
Register temp3) {
DCHECK(!input.is(result));
DCHECK(!input.is(double_scratch1));
DCHECK(!input.is(double_scratch2));
DCHECK(!result.is(double_scratch1));
DCHECK(!result.is(double_scratch2));
DCHECK(!double_scratch1.is(double_scratch2));
DCHECK(!temp1.is(temp2));
DCHECK(!temp1.is(temp3));
DCHECK(!temp2.is(temp3));
DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
DCHECK(!masm->serializer_enabled()); // External references not serializable.
Label zero, infinity, done;
__ mov(temp3, Operand(ExternalReference::math_exp_constants(0)));
__ vldr(double_scratch1, ExpConstant(0, temp3));
__ VFPCompareAndSetFlags(double_scratch1, input);
__ b(ge, &zero);
__ vldr(double_scratch2, ExpConstant(1, temp3));
__ VFPCompareAndSetFlags(input, double_scratch2);
__ b(ge, &infinity);
__ vldr(double_scratch1, ExpConstant(3, temp3));
__ vldr(result, ExpConstant(4, temp3));
__ vmul(double_scratch1, double_scratch1, input);
__ vadd(double_scratch1, double_scratch1, result);
__ VmovLow(temp2, double_scratch1);
__ vsub(double_scratch1, double_scratch1, result);
__ vldr(result, ExpConstant(6, temp3));
__ vldr(double_scratch2, ExpConstant(5, temp3));
__ vmul(double_scratch1, double_scratch1, double_scratch2);
__ vsub(double_scratch1, double_scratch1, input);
__ vsub(result, result, double_scratch1);
__ vmul(double_scratch2, double_scratch1, double_scratch1);
__ vmul(result, result, double_scratch2);
__ vldr(double_scratch2, ExpConstant(7, temp3));
__ vmul(result, result, double_scratch2);
__ vsub(result, result, double_scratch1);
// Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
DCHECK(*reinterpret_cast<double*>
(ExternalReference::math_exp_constants(8).address()) == 1);
__ vmov(double_scratch2, 1);
__ vadd(result, result, double_scratch2);
__ mov(temp1, Operand(temp2, LSR, 11));
__ Ubfx(temp2, temp2, 0, 11);
__ add(temp1, temp1, Operand(0x3ff));
// Must not call ExpConstant() after overwriting temp3!
__ mov(temp3, Operand(ExternalReference::math_exp_log_table()));
__ add(temp3, temp3, Operand(temp2, LSL, 3));
__ ldm(ia, temp3, temp2.bit() | temp3.bit());
// The first word is loaded is the lower number register.
if (temp2.code() < temp3.code()) {
__ orr(temp1, temp3, Operand(temp1, LSL, 20));
__ vmov(double_scratch1, temp2, temp1);
} else {
__ orr(temp1, temp2, Operand(temp1, LSL, 20));
__ vmov(double_scratch1, temp3, temp1);
}
__ vmul(result, result, double_scratch1);
__ b(&done);
__ bind(&zero);
__ vmov(result, kDoubleRegZero);
__ b(&done);
__ bind(&infinity);
__ vldr(result, ExpConstant(2, temp3));
__ bind(&done);
}
#undef __
#ifdef DEBUG

View File

@ -28,22 +28,6 @@ class StringCharLoadGenerator : public AllStatic {
};
class MathExpGenerator : public AllStatic {
public:
// Register input isn't modified. All other registers are clobbered.
static void EmitMathExp(MacroAssembler* masm,
DwVfpRegister input,
DwVfpRegister result,
DwVfpRegister double_scratch1,
DwVfpRegister double_scratch2,
Register temp1,
Register temp2,
Register temp3);
private:
DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
};
} // namespace internal
} // namespace v8

View File

@ -15,66 +15,6 @@ namespace internal {
#define __ ACCESS_MASM(masm)
#if defined(USE_SIMULATOR)
byte* fast_exp_arm64_machine_code = nullptr;
double fast_exp_simulator(double x, Isolate* isolate) {
Simulator * simulator = Simulator::current(isolate);
Simulator::CallArgument args[] = {
Simulator::CallArgument(x),
Simulator::CallArgument::End()
};
return simulator->CallDouble(fast_exp_arm64_machine_code, args);
}
#endif
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
// Use the Math.exp implemetation in MathExpGenerator::EmitMathExp() to create
// an AAPCS64-compliant exp() function. This will be faster than the C
// library's exp() function, but probably less accurate.
size_t actual_size;
byte* buffer =
static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
if (buffer == nullptr) return nullptr;
ExternalReference::InitializeMathExpData();
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
CodeObjectRequired::kNo);
masm.SetStackPointer(csp);
// The argument will be in d0 on entry.
DoubleRegister input = d0;
// Use other caller-saved registers for all other values.
DoubleRegister result = d1;
DoubleRegister double_temp1 = d2;
DoubleRegister double_temp2 = d3;
Register temp1 = x10;
Register temp2 = x11;
Register temp3 = x12;
MathExpGenerator::EmitMathExp(&masm, input, result,
double_temp1, double_temp2,
temp1, temp2, temp3);
// Move the result to the return register.
masm.Fmov(d0, result);
masm.Ret();
CodeDesc desc;
masm.GetCode(&desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
Assembler::FlushICache(isolate, buffer, actual_size);
base::OS::ProtectCode(buffer, actual_size);
#if !defined(USE_SIMULATOR)
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
#else
fast_exp_arm64_machine_code = buffer;
return &fast_exp_simulator;
#endif
}
UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
return nullptr;
}
@ -510,127 +450,6 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm,
__ Bind(&done);
}
static MemOperand ExpConstant(Register base, int index) {
return MemOperand(base, index * kDoubleSize);
}
void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
DoubleRegister input,
DoubleRegister result,
DoubleRegister double_temp1,
DoubleRegister double_temp2,
Register temp1,
Register temp2,
Register temp3) {
// TODO(jbramley): There are several instances where fnmsub could be used
// instead of fmul and fsub. Doing this changes the result, but since this is
// an estimation anyway, does it matter?
DCHECK(!AreAliased(input, result,
double_temp1, double_temp2,
temp1, temp2, temp3));
DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
DCHECK(!masm->serializer_enabled()); // External references not serializable.
Label done;
DoubleRegister double_temp3 = result;
Register constants = temp3;
// The algorithm used relies on some magic constants which are initialized in
// ExternalReference::InitializeMathExpData().
// Load the address of the start of the array.
__ Mov(constants, ExternalReference::math_exp_constants(0));
// We have to do a four-way split here:
// - If input <= about -708.4, the output always rounds to zero.
// - If input >= about 709.8, the output always rounds to +infinity.
// - If the input is NaN, the output is NaN.
// - Otherwise, the result needs to be calculated.
Label result_is_finite_non_zero;
// Assert that we can load offset 0 (the small input threshold) and offset 1
// (the large input threshold) with a single ldp.
DCHECK(kDRegSize == (ExpConstant(constants, 1).offset() -
ExpConstant(constants, 0).offset()));
__ Ldp(double_temp1, double_temp2, ExpConstant(constants, 0));
__ Fcmp(input, double_temp1);
__ Fccmp(input, double_temp2, NoFlag, hi);
// At this point, the condition flags can be in one of five states:
// NZCV
// 1000 -708.4 < input < 709.8 result = exp(input)
// 0110 input == 709.8 result = +infinity
// 0010 input > 709.8 result = +infinity
// 0011 input is NaN result = input
// 0000 input <= -708.4 result = +0.0
// Continue the common case first. 'mi' tests N == 1.
__ B(&result_is_finite_non_zero, mi);
// TODO(jbramley): Consider adding a +infinity register for ARM64.
__ Ldr(double_temp2, ExpConstant(constants, 2)); // Synthesize +infinity.
// Select between +0.0 and +infinity. 'lo' tests C == 0.
__ Fcsel(result, fp_zero, double_temp2, lo);
// Select between {+0.0 or +infinity} and input. 'vc' tests V == 0.
__ Fcsel(result, result, input, vc);
__ B(&done);
// The rest is magic, as described in InitializeMathExpData().
__ Bind(&result_is_finite_non_zero);
// Assert that we can load offset 3 and offset 4 with a single ldp.
DCHECK(kDRegSize == (ExpConstant(constants, 4).offset() -
ExpConstant(constants, 3).offset()));
__ Ldp(double_temp1, double_temp3, ExpConstant(constants, 3));
__ Fmadd(double_temp1, double_temp1, input, double_temp3);
__ Fmov(temp2.W(), double_temp1.S());
__ Fsub(double_temp1, double_temp1, double_temp3);
// Assert that we can load offset 5 and offset 6 with a single ldp.
DCHECK(kDRegSize == (ExpConstant(constants, 6).offset() -
ExpConstant(constants, 5).offset()));
__ Ldp(double_temp2, double_temp3, ExpConstant(constants, 5));
// TODO(jbramley): Consider using Fnmsub here.
__ Fmul(double_temp1, double_temp1, double_temp2);
__ Fsub(double_temp1, double_temp1, input);
__ Fmul(double_temp2, double_temp1, double_temp1);
__ Fsub(double_temp3, double_temp3, double_temp1);
__ Fmul(double_temp3, double_temp3, double_temp2);
__ Mov(temp1.W(), Operand(temp2.W(), LSR, 11));
__ Ldr(double_temp2, ExpConstant(constants, 7));
// TODO(jbramley): Consider using Fnmsub here.
__ Fmul(double_temp3, double_temp3, double_temp2);
__ Fsub(double_temp3, double_temp3, double_temp1);
// The 8th constant is 1.0, so use an immediate move rather than a load.
// We can't generate a runtime assertion here as we would need to call Abort
// in the runtime and we don't have an Isolate when we generate this code.
__ Fmov(double_temp2, 1.0);
__ Fadd(double_temp3, double_temp3, double_temp2);
__ And(temp2, temp2, 0x7ff);
__ Add(temp1, temp1, 0x3ff);
// Do the final table lookup.
__ Mov(temp3, ExternalReference::math_exp_log_table());
__ Add(temp3, temp3, Operand(temp2, LSL, kDRegSizeLog2));
__ Ldp(temp2.W(), temp3.W(), MemOperand(temp3));
__ Orr(temp1.W(), temp3.W(), Operand(temp1.W(), LSL, 20));
__ Bfi(temp2, temp1, 32, 32);
__ Fmov(double_temp1, temp2);
__ Fmul(result, double_temp3, double_temp1);
__ Bind(&done);
}
#undef __
} // namespace internal

View File

@ -27,22 +27,6 @@ class StringCharLoadGenerator : public AllStatic {
DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator);
};
class MathExpGenerator : public AllStatic {
public:
static void EmitMathExp(MacroAssembler* masm,
DoubleRegister input,
DoubleRegister result,
DoubleRegister double_scratch1,
DoubleRegister double_scratch2,
Register temp1,
Register temp2,
Register temp3);
private:
DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
};
} // namespace internal
} // namespace v8

View File

@ -178,11 +178,6 @@ static DoubleConstant double_constants;
const char* const RelocInfo::kFillerCommentString = "DEOPTIMIZATION PADDING";
static bool math_exp_data_initialized = false;
static base::Mutex* math_exp_data_mutex = NULL;
static double* math_exp_constants_array = NULL;
static double* math_exp_log_table_array = NULL;
// -----------------------------------------------------------------------------
// Implementation of AssemblerBase
@ -1006,61 +1001,6 @@ void ExternalReference::SetUp() {
double_constants.negative_infinity = -V8_INFINITY;
double_constants.uint32_bias =
static_cast<double>(static_cast<uint32_t>(0xFFFFFFFF)) + 1;
math_exp_data_mutex = new base::Mutex();
}
void ExternalReference::InitializeMathExpData() {
// Early return?
if (math_exp_data_initialized) return;
base::LockGuard<base::Mutex> lock_guard(math_exp_data_mutex);
if (!math_exp_data_initialized) {
// If this is changed, generated code must be adapted too.
const int kTableSizeBits = 11;
const int kTableSize = 1 << kTableSizeBits;
const double kTableSizeDouble = static_cast<double>(kTableSize);
math_exp_constants_array = new double[9];
// Input values smaller than this always return 0.
math_exp_constants_array[0] = -708.39641853226408;
// Input values larger than this always return +Infinity.
math_exp_constants_array[1] = 709.78271289338397;
math_exp_constants_array[2] = V8_INFINITY;
// The rest is black magic. Do not attempt to understand it. It is
// loosely based on the "expd" function published at:
// http://herumi.blogspot.com/2011/08/fast-double-precision-exponential.html
const double constant3 = (1 << kTableSizeBits) / base::ieee754::log(2.0);
math_exp_constants_array[3] = constant3;
math_exp_constants_array[4] =
static_cast<double>(static_cast<int64_t>(3) << 51);
math_exp_constants_array[5] = 1 / constant3;
math_exp_constants_array[6] = 3.0000000027955394;
math_exp_constants_array[7] = 0.16666666685227835;
math_exp_constants_array[8] = 1;
math_exp_log_table_array = new double[kTableSize];
for (int i = 0; i < kTableSize; i++) {
double value = std::pow(2, i / kTableSizeDouble);
uint64_t bits = bit_cast<uint64_t, double>(value);
bits &= (static_cast<uint64_t>(1) << 52) - 1;
double mantissa = bit_cast<double, uint64_t>(bits);
math_exp_log_table_array[i] = mantissa;
}
math_exp_data_initialized = true;
}
}
void ExternalReference::TearDownMathExpData() {
delete[] math_exp_constants_array;
math_exp_constants_array = NULL;
delete[] math_exp_log_table_array;
math_exp_log_table_array = NULL;
delete math_exp_data_mutex;
math_exp_data_mutex = NULL;
}
@ -1353,7 +1293,7 @@ ExternalReference ExternalReference::f64_tan_wrapper_function(
}
static void f64_exp_wrapper(double* param) {
WriteDoubleValue(param, std::exp(ReadDoubleValue(param)));
WriteDoubleValue(param, base::ieee754::exp(ReadDoubleValue(param)));
}
ExternalReference ExternalReference::f64_exp_wrapper_function(
@ -1628,6 +1568,11 @@ ExternalReference ExternalReference::ieee754_atan2_function(Isolate* isolate) {
isolate, FUNCTION_ADDR(base::ieee754::atan2), BUILTIN_FP_FP_CALL));
}
ExternalReference ExternalReference::ieee754_exp_function(Isolate* isolate) {
return ExternalReference(
Redirect(isolate, FUNCTION_ADDR(base::ieee754::exp), BUILTIN_FP_CALL));
}
ExternalReference ExternalReference::ieee754_log_function(Isolate* isolate) {
return ExternalReference(
Redirect(isolate, FUNCTION_ADDR(base::ieee754::log), BUILTIN_FP_CALL));
@ -1648,19 +1593,6 @@ ExternalReference ExternalReference::ieee754_log10_function(Isolate* isolate) {
Redirect(isolate, FUNCTION_ADDR(base::ieee754::log10), BUILTIN_FP_CALL));
}
ExternalReference ExternalReference::math_exp_constants(int constant_index) {
DCHECK(math_exp_data_initialized);
return ExternalReference(
reinterpret_cast<void*>(math_exp_constants_array + constant_index));
}
ExternalReference ExternalReference::math_exp_log_table() {
DCHECK(math_exp_data_initialized);
return ExternalReference(reinterpret_cast<void*>(math_exp_log_table_array));
}
ExternalReference ExternalReference::page_flags(Page* page) {
return ExternalReference(reinterpret_cast<Address>(page) +
MemoryChunk::kFlagsOffset);

View File

@ -897,8 +897,6 @@ class ExternalReference BASE_EMBEDDED {
};
static void SetUp();
static void InitializeMathExpData();
static void TearDownMathExpData();
typedef void* ExternalReferenceRedirector(Isolate* isolate, void* original,
Type type);
@ -1044,14 +1042,12 @@ class ExternalReference BASE_EMBEDDED {
// IEEE 754 functions.
static ExternalReference ieee754_atan_function(Isolate* isolate);
static ExternalReference ieee754_atan2_function(Isolate* isolate);
static ExternalReference ieee754_exp_function(Isolate* isolate);
static ExternalReference ieee754_log_function(Isolate* isolate);
static ExternalReference ieee754_log1p_function(Isolate* isolate);
static ExternalReference ieee754_log2_function(Isolate* isolate);
static ExternalReference ieee754_log10_function(Isolate* isolate);
static ExternalReference math_exp_constants(int constant_index);
static ExternalReference math_exp_log_table();
static ExternalReference page_flags(Page* page);
static ExternalReference ForDeoptEntry(Address entry);

View File

@ -392,6 +392,152 @@ double atan2(double y, double x) {
}
}
/* exp(x)
* Returns the exponential of x.
*
* Method
* 1. Argument reduction:
* Reduce x to an r so that |r| <= 0.5*ln2 ~ 0.34658.
* Given x, find r and integer k such that
*
* x = k*ln2 + r, |r| <= 0.5*ln2.
*
* Here r will be represented as r = hi-lo for better
* accuracy.
*
* 2. Approximation of exp(r) by a special rational function on
* the interval [0,0.34658]:
* Write
* R(r**2) = r*(exp(r)+1)/(exp(r)-1) = 2 + r*r/6 - r**4/360 + ...
* We use a special Remes algorithm on [0,0.34658] to generate
* a polynomial of degree 5 to approximate R. The maximum error
* of this polynomial approximation is bounded by 2**-59. In
* other words,
* R(z) ~ 2.0 + P1*z + P2*z**2 + P3*z**3 + P4*z**4 + P5*z**5
* (where z=r*r, and the values of P1 to P5 are listed below)
* and
* | 5 | -59
* | 2.0+P1*z+...+P5*z - R(z) | <= 2
* | |
* The computation of exp(r) thus becomes
* 2*r
* exp(r) = 1 + -------
* R - r
* r*R1(r)
* = 1 + r + ----------- (for better accuracy)
* 2 - R1(r)
* where
* 2 4 10
* R1(r) = r - (P1*r + P2*r + ... + P5*r ).
*
* 3. Scale back to obtain exp(x):
* From step 1, we have
* exp(x) = 2^k * exp(r)
*
* Special cases:
* exp(INF) is INF, exp(NaN) is NaN;
* exp(-INF) is 0, and
* for finite argument, only exp(0)=1 is exact.
*
* Accuracy:
* according to an error analysis, the error is always less than
* 1 ulp (unit in the last place).
*
* Misc. info.
* For IEEE double
* if x > 7.09782712893383973096e+02 then exp(x) overflow
* if x < -7.45133219101941108420e+02 then exp(x) underflow
*
* Constants:
* The hexadecimal values are the intended ones for the following
* constants. The decimal values may be used, provided that the
* compiler will convert from decimal to binary accurately enough
* to produce the hexadecimal values shown.
*/
double exp(double x) {
static const double
one = 1.0,
halF[2] = {0.5, -0.5},
o_threshold = 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */
u_threshold = -7.45133219101941108420e+02, /* 0xc0874910, 0xD52D3051 */
ln2HI[2] = {6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */
-6.93147180369123816490e-01}, /* 0xbfe62e42, 0xfee00000 */
ln2LO[2] = {1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */
-1.90821492927058770002e-10}, /* 0xbdea39ef, 0x35793c76 */
invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */
P1 = 1.66666666666666019037e-01, /* 0x3FC55555, 0x5555553E */
P2 = -2.77777777770155933842e-03, /* 0xBF66C16C, 0x16BEBD93 */
P3 = 6.61375632143793436117e-05, /* 0x3F11566A, 0xAF25DE2C */
P4 = -1.65339022054652515390e-06, /* 0xBEBBBD41, 0xC5D26BF1 */
P5 = 4.13813679705723846039e-08; /* 0x3E663769, 0x72BEA4D0 */
static volatile double
huge = 1.0e+300,
twom1000 = 9.33263618503218878990e-302, /* 2**-1000=0x01700000,0*/
two1023 = 8.988465674311579539e307; /* 0x1p1023 */
double y, hi = 0.0, lo = 0.0, c, t, twopk;
int32_t k = 0, xsb;
u_int32_t hx;
GET_HIGH_WORD(hx, x);
xsb = (hx >> 31) & 1; /* sign bit of x */
hx &= 0x7fffffff; /* high word of |x| */
/* filter out non-finite argument */
if (hx >= 0x40862E42) { /* if |x|>=709.78... */
if (hx >= 0x7ff00000) {
u_int32_t lx;
GET_LOW_WORD(lx, x);
if (((hx & 0xfffff) | lx) != 0)
return x + x; /* NaN */
else
return (xsb == 0) ? x : 0.0; /* exp(+-inf)={inf,0} */
}
if (x > o_threshold) return huge * huge; /* overflow */
if (x < u_threshold) return twom1000 * twom1000; /* underflow */
}
/* argument reduction */
if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */
if (hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */
hi = x - ln2HI[xsb];
lo = ln2LO[xsb];
k = 1 - xsb - xsb;
} else {
k = static_cast<int>(invln2 * x + halF[xsb]);
t = k;
hi = x - t * ln2HI[0]; /* t*ln2HI is exact here */
lo = t * ln2LO[0];
}
STRICT_ASSIGN(double, x, hi - lo);
} else if (hx < 0x3e300000) { /* when |x|<2**-28 */
if (huge + x > one) return one + x; /* trigger inexact */
} else {
k = 0;
}
/* x is now in primary range */
t = x * x;
if (k >= -1021) {
INSERT_WORDS(twopk, 0x3ff00000 + (k << 20), 0);
} else {
INSERT_WORDS(twopk, 0x3ff00000 + ((k + 1000) << 20), 0);
}
c = x - t * (P1 + t * (P2 + t * (P3 + t * (P4 + t * P5))));
if (k == 0) {
return one - ((x * c) / (c - 2.0) - x);
} else {
y = one - ((lo - (x * c) / (2.0 - c)) - hi);
}
if (k >= -1021) {
if (k == 1024) return y * 2.0 * two1023;
return y * twopk;
} else {
return y * twopk * twom1000;
}
}
/* log(x)
* Return the logrithm of x
*

View File

@ -17,6 +17,9 @@ double atan(double x);
// the two arguments to determine the quadrant of the result.
double atan2(double y, double x);
// Returns the base-e exponential of |x|.
double exp(double x);
// Returns the natural logarithm of |x|.
double log(double x);

View File

@ -1676,6 +1676,9 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
SimpleInstallFunction(math, "atan2", Builtins::kMathAtan2, 2, true);
SimpleInstallFunction(math, "ceil", Builtins::kMathCeil, 1, true);
SimpleInstallFunction(math, "clz32", Builtins::kMathClz32, 1, true);
Handle<JSFunction> math_exp =
SimpleInstallFunction(math, "exp", Builtins::kMathExp, 1, true);
native_context()->set_math_exp(*math_exp);
Handle<JSFunction> math_floor =
SimpleInstallFunction(math, "floor", Builtins::kMathFloor, 1, true);
native_context()->set_math_floor(*math_floor);

View File

@ -2452,6 +2452,18 @@ void Builtins::Generate_MathClz32(CodeStubAssembler* assembler) {
}
}
// ES6 section 20.2.2.14 Math.exp ( x )
void Builtins::Generate_MathExp(CodeStubAssembler* assembler) {
using compiler::Node;
Node* x = assembler->Parameter(1);
Node* context = assembler->Parameter(4);
Node* x_value = assembler->TruncateTaggedToFloat64(context, x);
Node* value = assembler->Float64Exp(x_value);
Node* result = assembler->ChangeFloat64ToTagged(value);
assembler->Return(result);
}
// ES6 section 20.2.2.16 Math.floor ( x )
void Builtins::Generate_MathFloor(CodeStubAssembler* assembler) {
Generate_MathRoundingOperation(assembler, &CodeStubAssembler::Float64Floor);

View File

@ -320,6 +320,7 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(MathAtan2, 3) \
V(MathCeil, 2) \
V(MathClz32, 2) \
V(MathExp, 2) \
V(MathFloor, 2) \
V(MathLog, 2) \
V(MathLog1p, 2) \
@ -634,6 +635,8 @@ class Builtins {
static void Generate_MathCeil(CodeStubAssembler* assembler);
// ES6 section 20.2.2.11 Math.clz32 ( x )
static void Generate_MathClz32(CodeStubAssembler* assembler);
// ES6 section 20.2.2.14 Math.exp ( x )
static void Generate_MathExp(CodeStubAssembler* assembler);
// ES6 section 20.2.2.16 Math.floor ( x )
static void Generate_MathFloor(CodeStubAssembler* assembler);
// ES6 section 20.2.2.20 Math.log ( x )

View File

@ -60,7 +60,6 @@ double modulo(double x, double y) {
}
UNARY_MATH_FUNCTION(sqrt, CreateSqrtFunction)
UNARY_MATH_FUNCTION(exp, CreateExpFunction)
#undef UNARY_MATH_FUNCTION

View File

@ -93,16 +93,13 @@ class CodeGenerator {
// generated code both in runtime and compiled code.
typedef double (*UnaryMathFunctionWithIsolate)(double x, Isolate* isolate);
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate);
UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate);
double modulo(double x, double y);
// Custom implementation of math functions.
double fast_exp(double input, Isolate* isolate);
double fast_sqrt(double input, Isolate* isolate);
void lazily_initialize_fast_exp(Isolate* isolate);
void lazily_initialize_fast_sqrt(Isolate* isolate);

View File

@ -709,6 +709,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kIeee754Float64Atan2:
ASSEMBLE_IEEE754_BINOP(atan2);
break;
case kIeee754Float64Exp:
ASSEMBLE_IEEE754_UNOP(exp);
break;
case kIeee754Float64Log:
ASSEMBLE_IEEE754_UNOP(log);
break;

View File

@ -813,6 +813,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kIeee754Float64Atan2:
ASSEMBLE_IEEE754_BINOP(atan2);
break;
case kIeee754Float64Exp:
ASSEMBLE_IEEE754_UNOP(exp);
break;
case kIeee754Float64Log:
ASSEMBLE_IEEE754_UNOP(log);
break;

View File

@ -108,6 +108,7 @@ class Schedule;
#define CODE_ASSEMBLER_UNARY_OP_LIST(V) \
V(Float64Atan) \
V(Float64Exp) \
V(Float64Log) \
V(Float64Log1p) \
V(Float64Log2) \

View File

@ -655,6 +655,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kIeee754Float64Atan2:
ASSEMBLE_IEEE754_BINOP(atan2);
break;
case kIeee754Float64Exp:
ASSEMBLE_IEEE754_UNOP(exp);
break;
case kIeee754Float64Log:
ASSEMBLE_IEEE754_UNOP(log);
break;

View File

@ -91,6 +91,7 @@ enum class RecordWriteMode { kValueIsMap, kValueIsPointer, kValueIsAny };
V(AtomicStoreWord32) \
V(Ieee754Float64Atan) \
V(Ieee754Float64Atan2) \
V(Ieee754Float64Exp) \
V(Ieee754Float64Log) \
V(Ieee754Float64Log1p) \
V(Ieee754Float64Log2) \

View File

@ -226,6 +226,7 @@ int InstructionScheduler::GetInstructionFlags(const Instruction* instr) const {
case kArchComment:
case kIeee754Float64Atan:
case kIeee754Float64Atan2:
case kIeee754Float64Exp:
case kIeee754Float64Log:
case kIeee754Float64Log1p:
case kIeee754Float64Log2:

View File

@ -1138,6 +1138,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsFloat64(node), VisitFloat64Atan(node);
case IrOpcode::kFloat64Atan2:
return MarkAsFloat64(node), VisitFloat64Atan2(node);
case IrOpcode::kFloat64Exp:
return MarkAsFloat64(node), VisitFloat64Exp(node);
case IrOpcode::kFloat64Log:
return MarkAsFloat64(node), VisitFloat64Log(node);
case IrOpcode::kFloat64Log1p:
@ -1259,6 +1261,10 @@ void InstructionSelector::VisitFloat64Atan2(Node* node) {
VisitFloat64Ieee754Binop(node, kIeee754Float64Atan2);
}
void InstructionSelector::VisitFloat64Exp(Node* node) {
VisitFloat64Ieee754Unop(node, kIeee754Float64Exp);
}
void InstructionSelector::VisitFloat64Log(Node* node) {
VisitFloat64Ieee754Unop(node, kIeee754Float64Log);
}

View File

@ -142,6 +142,18 @@ Reduction JSBuiltinReducer::ReduceMathClz32(Node* node) {
return NoChange();
}
// ES6 section 20.2.2.14 Math.exp ( x )
Reduction JSBuiltinReducer::ReduceMathExp(Node* node) {
JSCallReduction r(node);
if (r.InputsMatchOne(Type::PlainPrimitive())) {
// Math.exp(a:plain-primitive) -> NumberExp(ToNumber(a))
Node* input = ToNumber(r.GetJSCallInput(0));
Node* value = graph()->NewNode(simplified()->NumberExp(), input);
return Replace(value);
}
return NoChange();
}
// ES6 section 20.2.2.16 Math.floor ( x )
Reduction JSBuiltinReducer::ReduceMathFloor(Node* node) {
JSCallReduction r(node);
@ -348,6 +360,9 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
case kMathCeil:
reduction = ReduceMathCeil(node);
break;
case kMathExp:
reduction = ReduceMathExp(node);
break;
case kMathFloor:
reduction = ReduceMathFloor(node);
break;

View File

@ -33,6 +33,7 @@ class JSBuiltinReducer final : public AdvancedReducer {
Reduction ReduceMathAtan2(Node* node);
Reduction ReduceMathCeil(Node* node);
Reduction ReduceMathClz32(Node* node);
Reduction ReduceMathExp(Node* node);
Reduction ReduceMathFloor(Node* node);
Reduction ReduceMathFround(Node* node);
Reduction ReduceMathImul(Node* node);

View File

@ -396,6 +396,11 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
}
break;
}
case IrOpcode::kFloat64Exp: {
Float64Matcher m(node->InputAt(0));
if (m.HasValue()) return ReplaceFloat64(base::ieee754::exp(m.Value()));
break;
}
case IrOpcode::kFloat64Log: {
Float64Matcher m(node->InputAt(0));
if (m.HasValue()) return ReplaceFloat64(base::ieee754::log(m.Value()));

View File

@ -157,6 +157,7 @@ MachineRepresentation AtomicStoreRepresentationOf(Operator const* op) {
V(Float64Abs, Operator::kNoProperties, 1, 0, 1) \
V(Float64Atan, Operator::kNoProperties, 1, 0, 1) \
V(Float64Atan2, Operator::kNoProperties, 2, 0, 1) \
V(Float64Exp, Operator::kNoProperties, 1, 0, 1) \
V(Float64Log, Operator::kNoProperties, 1, 0, 1) \
V(Float64Log1p, Operator::kNoProperties, 1, 0, 1) \
V(Float64Log2, Operator::kNoProperties, 1, 0, 1) \

View File

@ -372,6 +372,9 @@ class MachineOperatorBuilder final : public ZoneObject {
const Operator* Float64Atan();
const Operator* Float64Atan2();
// Floating point exponential functions.
const Operator* Float64Exp();
// Floating point logarithm (double-precision).
const Operator* Float64Log();
const Operator* Float64Log1p();

View File

@ -747,6 +747,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kIeee754Float64Atan2:
ASSEMBLE_IEEE754_BINOP(atan2);
break;
case kIeee754Float64Exp:
ASSEMBLE_IEEE754_UNOP(exp);
break;
case kIeee754Float64Log:
ASSEMBLE_IEEE754_UNOP(log);
break;

View File

@ -756,6 +756,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kIeee754Float64Atan2:
ASSEMBLE_IEEE754_BINOP(atan2);
break;
case kIeee754Float64Exp:
ASSEMBLE_IEEE754_UNOP(exp);
break;
case kIeee754Float64Log:
ASSEMBLE_IEEE754_UNOP(log);
break;

View File

@ -203,6 +203,7 @@
V(NumberFround) \
V(NumberAtan) \
V(NumberAtan2) \
V(NumberExp) \
V(NumberLog) \
V(NumberLog1p) \
V(NumberLog2) \
@ -371,6 +372,7 @@
V(Float64Abs) \
V(Float64Atan) \
V(Float64Atan2) \
V(Float64Exp) \
V(Float64Log) \
V(Float64Log1p) \
V(Float64Log2) \

View File

@ -464,6 +464,7 @@ class RawMachineAssembler {
Node* Float64Atan2(Node* a, Node* b) {
return AddNode(machine()->Float64Atan2(), a, b);
}
Node* Float64Exp(Node* a) { return AddNode(machine()->Float64Exp(), a); }
Node* Float64Log(Node* a) { return AddNode(machine()->Float64Log(), a); }
Node* Float64Log1p(Node* a) { return AddNode(machine()->Float64Log1p(), a); }
Node* Float64Log2(Node* a) { return AddNode(machine()->Float64Log2(), a); }

View File

@ -671,6 +671,8 @@ const Operator* RepresentationChanger::Float64OperatorFor(
return machine()->Float64Atan();
case IrOpcode::kNumberAtan2:
return machine()->Float64Atan2();
case IrOpcode::kNumberExp:
return machine()->Float64Exp();
case IrOpcode::kNumberFround:
return machine()->TruncateFloat64ToFloat32();
case IrOpcode::kNumberLog:

View File

@ -1442,6 +1442,7 @@ class RepresentationSelector {
return;
}
case IrOpcode::kNumberAtan:
case IrOpcode::kNumberExp:
case IrOpcode::kNumberLog:
case IrOpcode::kNumberLog1p:
case IrOpcode::kNumberLog2:

View File

@ -254,6 +254,7 @@ CompareOperationHints::Hint CompareOperationHintOf(const Operator* op) {
V(NumberFround, Operator::kNoProperties, 1) \
V(NumberAtan, Operator::kNoProperties, 1) \
V(NumberAtan2, Operator::kNoProperties, 2) \
V(NumberExp, Operator::kNoProperties, 1) \
V(NumberLog, Operator::kNoProperties, 1) \
V(NumberLog1p, Operator::kNoProperties, 1) \
V(NumberLog2, Operator::kNoProperties, 1) \

View File

@ -181,6 +181,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
const Operator* NumberFround();
const Operator* NumberAtan();
const Operator* NumberAtan2();
const Operator* NumberExp();
const Operator* NumberLog();
const Operator* NumberLog1p();
const Operator* NumberLog2();

View File

@ -1543,9 +1543,10 @@ Type* Typer::Visitor::JSCallFunctionTyper(Type* fun, Typer* t) {
case kMathTrunc:
return t->cache_.kIntegerOrMinusZeroOrNaN;
// Unary math functions.
case kMathExp:
return Type::Union(Type::PlainNumber(), Type::NaN(), t->zone());
case kMathAbs:
case kMathLog:
case kMathExp:
case kMathSqrt:
case kMathCos:
case kMathSin:
@ -1800,6 +1801,10 @@ Type* Typer::Visitor::TypeNumberAtan(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberAtan2(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberExp(Node* node) {
return Type::Union(Type::PlainNumber(), Type::NaN(), zone());
}
Type* Typer::Visitor::TypeNumberLog(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeNumberLog1p(Node* node) { return Type::Number(); }
@ -2559,6 +2564,8 @@ Type* Typer::Visitor::TypeFloat64Atan(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeFloat64Atan2(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeFloat64Exp(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeFloat64Log(Node* node) { return Type::Number(); }
Type* Typer::Visitor::TypeFloat64Log1p(Node* node) { return Type::Number(); }

View File

@ -753,6 +753,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kNumberFloor:
case IrOpcode::kNumberFround:
case IrOpcode::kNumberAtan:
case IrOpcode::kNumberExp:
case IrOpcode::kNumberLog:
case IrOpcode::kNumberLog1p:
case IrOpcode::kNumberLog2:
@ -1070,6 +1071,7 @@ void Verifier::Visitor::Check(Node* node) {
case IrOpcode::kFloat64Abs:
case IrOpcode::kFloat64Atan:
case IrOpcode::kFloat64Atan2:
case IrOpcode::kFloat64Exp:
case IrOpcode::kFloat64Log:
case IrOpcode::kFloat64Log1p:
case IrOpcode::kFloat64Log2:

View File

@ -873,6 +873,9 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
case kIeee754Float64Atan2:
ASSEMBLE_IEEE754_BINOP(atan2);
break;
case kIeee754Float64Exp:
ASSEMBLE_IEEE754_UNOP(exp);
break;
case kIeee754Float64Log:
ASSEMBLE_IEEE754_UNOP(log);
break;

View File

@ -86,9 +86,10 @@ enum BindingFlags {
V(REFLECT_DELETE_PROPERTY_INDEX, JSFunction, reflect_delete_property) \
V(SPREAD_ARGUMENTS_INDEX, JSFunction, spread_arguments) \
V(SPREAD_ITERABLE_INDEX, JSFunction, spread_iterable) \
V(MATH_FLOOR, JSFunction, math_floor) \
V(MATH_LOG, JSFunction, math_log) \
V(MATH_SQRT, JSFunction, math_sqrt)
V(MATH_EXP_INDEX, JSFunction, math_exp) \
V(MATH_FLOOR_INDEX, JSFunction, math_floor) \
V(MATH_LOG_INDEX, JSFunction, math_log) \
V(MATH_SQRT_INDEX, JSFunction, math_sqrt)
#define NATIVE_CONTEXT_IMPORTED_FIELDS(V) \
V(ARRAY_CONCAT_INDEX, JSFunction, array_concat) \

View File

@ -1138,12 +1138,8 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
DCHECK(instr->representation().IsDouble());
DCHECK(instr->value()->representation().IsDouble());
LOperand* input = UseRegister(instr->value());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LOperand* double_temp = TempDoubleRegister();
LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
return DefineAsRegister(result);
LOperand* input = UseFixedDouble(instr->value(), d0);
return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), d0), instr);
}

View File

@ -905,24 +905,11 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
};
class LMathExp final : public LTemplateInstruction<1, 1, 3> {
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
public:
LMathExp(LOperand* value,
LOperand* double_temp,
LOperand* temp1,
LOperand* temp2) {
inputs_[0] = value;
temps_[0] = temp1;
temps_[1] = temp2;
temps_[2] = double_temp;
ExternalReference::InitializeMathExpData();
}
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
LOperand* double_temp() { return temps_[2]; }
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
};

View File

@ -3540,16 +3540,10 @@ void LCodeGen::DoPower(LPower* instr) {
void LCodeGen::DoMathExp(LMathExp* instr) {
DwVfpRegister input = ToDoubleRegister(instr->value());
DwVfpRegister result = ToDoubleRegister(instr->result());
DwVfpRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
DwVfpRegister double_scratch2 = double_scratch0();
Register temp1 = ToRegister(instr->temp1());
Register temp2 = ToRegister(instr->temp2());
MathExpGenerator::EmitMathExp(
masm(), input, result, double_scratch1, double_scratch2,
temp1, temp2, scratch0());
__ PrepareCallCFunction(0, 1, scratch0());
__ MovToFloatParameter(ToDoubleRegister(instr->value()));
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 0, 1);
__ MovFromFloatResult(ToDoubleRegister(instr->result()));
}

View File

@ -2462,14 +2462,9 @@ LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
case kMathExp: {
DCHECK(instr->representation().IsDouble());
DCHECK(instr->value()->representation().IsDouble());
LOperand* input = UseRegister(instr->value());
LOperand* double_temp1 = TempDoubleRegister();
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LOperand* temp3 = TempRegister();
LMathExp* result = new(zone()) LMathExp(input, double_temp1,
temp1, temp2, temp3);
return DefineAsRegister(result);
LOperand* input = UseFixedDouble(instr->value(), d0);
LMathExp* result = new (zone()) LMathExp(input);
return MarkAsCall(DefineFixedDouble(result, d0), instr);
}
case kMathFloor: {
DCHECK(instr->value()->representation().IsDouble());

View File

@ -1763,26 +1763,9 @@ class LMathAbsTagged: public LTemplateInstruction<1, 2, 3> {
DECLARE_HYDROGEN_ACCESSOR(UnaryMathOperation)
};
class LMathExp final : public LUnaryMathOperation<4> {
class LMathExp final : public LUnaryMathOperation<0> {
public:
LMathExp(LOperand* value,
LOperand* double_temp1,
LOperand* temp1,
LOperand* temp2,
LOperand* temp3)
: LUnaryMathOperation<4>(value) {
temps_[0] = double_temp1;
temps_[1] = temp1;
temps_[2] = temp2;
temps_[3] = temp3;
ExternalReference::InitializeMathExpData();
}
LOperand* double_temp1() { return temps_[0]; }
LOperand* temp1() { return temps_[1]; }
LOperand* temp2() { return temps_[2]; }
LOperand* temp3() { return temps_[3]; }
explicit LMathExp(LOperand* value) : LUnaryMathOperation<0>(value) {}
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
};

View File

@ -3548,17 +3548,10 @@ void LCodeGen::DoMathAbsTagged(LMathAbsTagged* instr) {
void LCodeGen::DoMathExp(LMathExp* instr) {
DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
DoubleRegister double_temp1 = ToDoubleRegister(instr->double_temp1());
DoubleRegister double_temp2 = double_scratch();
Register temp1 = ToRegister(instr->temp1());
Register temp2 = ToRegister(instr->temp2());
Register temp3 = ToRegister(instr->temp3());
MathExpGenerator::EmitMathExp(masm(), input, result,
double_temp1, double_temp2,
temp1, temp2, temp3);
DCHECK(instr->IsMarkedAsCall());
DCHECK(ToDoubleRegister(instr->value()).is(d0));
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 0, 1);
DCHECK(ToDoubleRegister(instr->result()).Is(d0));
}

View File

@ -3423,8 +3423,7 @@ HInstruction* HUnaryMathOperation::New(Isolate* isolate, Zone* zone,
}
switch (op) {
case kMathExp:
lazily_initialize_fast_exp(isolate);
return H_CONSTANT_DOUBLE(fast_exp(d, isolate));
return H_CONSTANT_DOUBLE(base::ieee754::exp(d));
case kMathLog:
return H_CONSTANT_DOUBLE(base::ieee754::log(d));
case kMathSqrt:

View File

@ -8856,8 +8856,6 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) {
// we inline here do not observe if they were tail called or not.
switch (id) {
case kMathExp:
if (!FLAG_fast_math) break;
// Fall through if FLAG_fast_math.
case kMathRound:
case kMathFround:
case kMathFloor:

View File

@ -3425,11 +3425,16 @@ void LCodeGen::DoMathClz32(LMathClz32* instr) {
void LCodeGen::DoMathExp(LMathExp* instr) {
XMMRegister input = ToDoubleRegister(instr->value());
XMMRegister result = ToDoubleRegister(instr->result());
XMMRegister temp0 = double_scratch0();
Register temp1 = ToRegister(instr->temp1());
Register temp2 = ToRegister(instr->temp2());
MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2);
// Pass one double as argument on the stack.
__ PrepareCallCFunction(2, eax);
__ movsd(Operand(esp, 0 * kDoubleSize), input);
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 2);
// Return value is in st(0) on ia32.
// Store it into the result register.
__ sub(esp, Immediate(kDoubleSize));
__ fstp_d(Operand(esp, 0));
__ movsd(result, Operand(esp, 0));
__ add(esp, Immediate(kDoubleSize));
}
void LCodeGen::PrepareForTailCall(const ParameterCount& actual,

View File

@ -1181,11 +1181,8 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
DCHECK(instr->representation().IsDouble());
DCHECK(instr->value()->representation().IsDouble());
LOperand* value = UseTempRegister(instr->value());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
return DefineAsRegister(result);
LOperand* input = UseRegisterAtStart(instr->value());
return MarkAsCall(DefineSameAsFirst(new (zone()) LMathExp(input)), instr);
}

View File

@ -912,21 +912,11 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
};
class LMathExp final : public LTemplateInstruction<1, 1, 2> {
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
public:
LMathExp(LOperand* value,
LOperand* temp1,
LOperand* temp2) {
inputs_[0] = value;
temps_[0] = temp1;
temps_[1] = temp2;
ExternalReference::InitializeMathExpData();
}
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
};

View File

@ -3492,16 +3492,10 @@ void LCodeGen::DoPower(LPower* instr) {
void LCodeGen::DoMathExp(LMathExp* instr) {
DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
DoubleRegister double_scratch2 = double_scratch0();
Register temp1 = ToRegister(instr->temp1());
Register temp2 = ToRegister(instr->temp2());
MathExpGenerator::EmitMathExp(
masm(), input, result, double_scratch1, double_scratch2,
temp1, temp2, scratch0());
__ PrepareCallCFunction(0, 1, scratch0());
__ MovToFloatParameter(ToDoubleRegister(instr->value()));
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 0, 1);
__ MovFromFloatResult(ToDoubleRegister(instr->result()));
}

View File

@ -1107,12 +1107,8 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
DCHECK(instr->representation().IsDouble());
DCHECK(instr->value()->representation().IsDouble());
LOperand* input = UseRegister(instr->value());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LOperand* double_temp = TempDoubleRegister();
LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
return DefineAsRegister(result);
LOperand* input = UseFixedDouble(instr->value(), f4);
return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), f4), instr);
}

View File

@ -882,24 +882,11 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
};
class LMathExp final : public LTemplateInstruction<1, 1, 3> {
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
public:
LMathExp(LOperand* value,
LOperand* double_temp,
LOperand* temp1,
LOperand* temp2) {
inputs_[0] = value;
temps_[0] = temp1;
temps_[1] = temp2;
temps_[2] = double_temp;
ExternalReference::InitializeMathExpData();
}
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
LOperand* double_temp() { return temps_[2]; }
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
};

View File

@ -3695,16 +3695,10 @@ void LCodeGen::DoPower(LPower* instr) {
void LCodeGen::DoMathExp(LMathExp* instr) {
DoubleRegister input = ToDoubleRegister(instr->value());
DoubleRegister result = ToDoubleRegister(instr->result());
DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
DoubleRegister double_scratch2 = double_scratch0();
Register temp1 = ToRegister(instr->temp1());
Register temp2 = ToRegister(instr->temp2());
MathExpGenerator::EmitMathExp(
masm(), input, result, double_scratch1, double_scratch2,
temp1, temp2, scratch0());
__ PrepareCallCFunction(0, 1, scratch0());
__ MovToFloatParameter(ToDoubleRegister(instr->value()));
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 0, 1);
__ MovFromFloatResult(ToDoubleRegister(instr->result()));
}

View File

@ -1107,12 +1107,8 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
DCHECK(instr->representation().IsDouble());
DCHECK(instr->value()->representation().IsDouble());
LOperand* input = UseRegister(instr->value());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LOperand* double_temp = TempDoubleRegister();
LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
return DefineAsRegister(result);
LOperand* input = UseFixedDouble(instr->value(), f4);
return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), f4), instr);
}

View File

@ -900,24 +900,11 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
};
class LMathExp final : public LTemplateInstruction<1, 1, 3> {
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
public:
LMathExp(LOperand* value,
LOperand* double_temp,
LOperand* temp1,
LOperand* temp2) {
inputs_[0] = value;
temps_[0] = temp1;
temps_[1] = temp2;
temps_[2] = double_temp;
ExternalReference::InitializeMathExpData();
}
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
LOperand* double_temp() { return temps_[2]; }
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
};

View File

@ -3600,13 +3600,10 @@ void LCodeGen::DoPower(LPower* instr) {
void LCodeGen::DoMathExp(LMathExp* instr) {
XMMRegister input = ToDoubleRegister(instr->value());
XMMRegister result = ToDoubleRegister(instr->result());
XMMRegister temp0 = double_scratch0();
Register temp1 = ToRegister(instr->temp1());
Register temp2 = ToRegister(instr->temp2());
MathExpGenerator::EmitMathExp(masm(), input, result, temp0, temp1, temp2);
DCHECK(ToDoubleRegister(instr->value()).is(xmm0));
DCHECK(ToDoubleRegister(instr->result()).is(xmm0));
__ PrepareCallCFunction(1);
__ CallCFunction(ExternalReference::ieee754_exp_function(isolate()), 1);
}

View File

@ -1171,11 +1171,9 @@ LInstruction* LChunkBuilder::DoMathClz32(HUnaryMathOperation* instr) {
LInstruction* LChunkBuilder::DoMathExp(HUnaryMathOperation* instr) {
DCHECK(instr->representation().IsDouble());
DCHECK(instr->value()->representation().IsDouble());
LOperand* value = UseTempRegister(instr->value());
LOperand* temp1 = TempRegister();
LOperand* temp2 = TempRegister();
LMathExp* result = new(zone()) LMathExp(value, temp1, temp2);
return DefineAsRegister(result);
LOperand* input = UseFixedDouble(instr->value(), xmm0);
return MarkAsCall(DefineFixedDouble(new (zone()) LMathExp(input), xmm0),
instr);
}

View File

@ -909,19 +909,11 @@ class LMathClz32 final : public LTemplateInstruction<1, 1, 0> {
DECLARE_CONCRETE_INSTRUCTION(MathClz32, "math-clz32")
};
class LMathExp final : public LTemplateInstruction<1, 1, 2> {
class LMathExp final : public LTemplateInstruction<1, 1, 0> {
public:
LMathExp(LOperand* value, LOperand* temp1, LOperand* temp2) {
inputs_[0] = value;
temps_[0] = temp1;
temps_[1] = temp2;
ExternalReference::InitializeMathExpData();
}
explicit LMathExp(LOperand* value) { inputs_[0] = value; }
LOperand* value() { return inputs_[0]; }
LOperand* temp1() { return temps_[0]; }
LOperand* temp2() { return temps_[1]; }
DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
};

View File

@ -71,6 +71,8 @@ ExternalReferenceTable::ExternalReferenceTable(Isolate* isolate) {
"base::ieee754::atan");
Add(ExternalReference::ieee754_atan2_function(isolate).address(),
"base::ieee754::atan2");
Add(ExternalReference::ieee754_exp_function(isolate).address(),
"base::ieee754::exp");
Add(ExternalReference::ieee754_log_function(isolate).address(),
"base::ieee754::log");
Add(ExternalReference::ieee754_log1p_function(isolate).address(),

View File

@ -34,43 +34,6 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
#define __ masm.
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
size_t actual_size;
byte* buffer =
static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
if (buffer == nullptr) return nullptr;
ExternalReference::InitializeMathExpData();
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
CodeObjectRequired::kNo);
// esp[1 * kPointerSize]: raw double input
// esp[0 * kPointerSize]: return address
{
XMMRegister input = xmm1;
XMMRegister result = xmm2;
__ movsd(input, Operand(esp, 1 * kPointerSize));
__ push(eax);
__ push(ebx);
MathExpGenerator::EmitMathExp(&masm, input, result, xmm0, eax, ebx);
__ pop(ebx);
__ pop(eax);
__ movsd(Operand(esp, 1 * kPointerSize), result);
__ fld_d(Operand(esp, 1 * kPointerSize));
__ Ret();
}
CodeDesc desc;
masm.GetCode(&desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
Assembler::FlushICache(isolate, buffer, actual_size);
base::OS::ProtectCode(buffer, actual_size);
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
}
UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
size_t actual_size;
// Allocate buffer in executable space.
@ -928,64 +891,6 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm,
__ bind(&done);
}
static Operand ExpConstant(int index) {
return Operand::StaticVariable(ExternalReference::math_exp_constants(index));
}
void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
XMMRegister input,
XMMRegister result,
XMMRegister double_scratch,
Register temp1,
Register temp2) {
DCHECK(!input.is(double_scratch));
DCHECK(!input.is(result));
DCHECK(!result.is(double_scratch));
DCHECK(!temp1.is(temp2));
DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
DCHECK(!masm->serializer_enabled()); // External references not serializable.
Label done;
__ movsd(double_scratch, ExpConstant(0));
__ xorpd(result, result);
__ ucomisd(double_scratch, input);
__ j(above_equal, &done);
__ ucomisd(input, ExpConstant(1));
__ movsd(result, ExpConstant(2));
__ j(above_equal, &done);
__ movsd(double_scratch, ExpConstant(3));
__ movsd(result, ExpConstant(4));
__ mulsd(double_scratch, input);
__ addsd(double_scratch, result);
__ movd(temp2, double_scratch);
__ subsd(double_scratch, result);
__ movsd(result, ExpConstant(6));
__ mulsd(double_scratch, ExpConstant(5));
__ subsd(double_scratch, input);
__ subsd(result, double_scratch);
__ movsd(input, double_scratch);
__ mulsd(input, double_scratch);
__ mulsd(result, input);
__ mov(temp1, temp2);
__ mulsd(result, ExpConstant(7));
__ subsd(result, double_scratch);
__ add(temp1, Immediate(0x1ff800));
__ addsd(result, ExpConstant(8));
__ and_(temp2, Immediate(0x7ff));
__ shr(temp1, 11);
__ shl(temp1, 20);
__ movd(input, temp1);
__ pshufd(input, input, static_cast<uint8_t>(0xe1)); // Order: 11 10 00 01
__ movsd(double_scratch, Operand::StaticArray(
temp2, times_8, ExternalReference::math_exp_log_table()));
__ orps(input, double_scratch);
__ mulsd(result, input);
__ bind(&done);
}
#undef __

View File

@ -29,19 +29,6 @@ class StringCharLoadGenerator : public AllStatic {
};
class MathExpGenerator : public AllStatic {
public:
static void EmitMathExp(MacroAssembler* masm,
XMMRegister input,
XMMRegister result,
XMMRegister double_scratch,
Register temp1,
Register temp2);
private:
DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
};
} // namespace internal
} // namespace v8

View File

@ -29,11 +29,6 @@ function MathAbs(x) {
return (x > 0) ? x : 0 - x;
}
// ECMA 262 - 15.8.2.8
function MathExp(x) {
return %MathExpRT(TO_NUMBER(x));
}
// ECMA 262 - 15.8.2.13
function MathPowJS(x, y) {
return %_MathPow(TO_NUMBER(x), TO_NUMBER(y));
@ -184,7 +179,6 @@ utils.InstallConstants(GlobalMath, [
utils.InstallFunctions(GlobalMath, DONT_ENUM, [
"random", MathRandom,
"abs", MathAbs,
"exp", MathExp,
"pow", MathPowJS,
"sign", MathSign,
"asinh", MathAsinh,
@ -203,7 +197,6 @@ utils.InstallFunctions(GlobalMath, DONT_ENUM, [
utils.Export(function(to) {
to.MathAbs = MathAbs;
to.MathExp = MathExp;
to.IntRandom = MathRandomRaw;
});

View File

@ -16,60 +16,6 @@ namespace internal {
#define __ masm.
#if defined(USE_SIMULATOR)
byte* fast_exp_mips_machine_code = nullptr;
double fast_exp_simulator(double x, Isolate* isolate) {
return Simulator::current(isolate)->CallFP(fast_exp_mips_machine_code, x, 0);
}
#endif
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
size_t actual_size;
byte* buffer =
static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
if (buffer == nullptr) return nullptr;
ExternalReference::InitializeMathExpData();
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
CodeObjectRequired::kNo);
{
DoubleRegister input = f12;
DoubleRegister result = f0;
DoubleRegister double_scratch1 = f4;
DoubleRegister double_scratch2 = f6;
Register temp1 = t0;
Register temp2 = t1;
Register temp3 = t2;
__ MovFromFloatParameter(input);
__ Push(temp3, temp2, temp1);
MathExpGenerator::EmitMathExp(
&masm, input, result, double_scratch1, double_scratch2,
temp1, temp2, temp3);
__ Pop(temp3, temp2, temp1);
__ MovToFloatResult(result);
__ Ret();
}
CodeDesc desc;
masm.GetCode(&desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
Assembler::FlushICache(isolate, buffer, actual_size);
base::OS::ProtectCode(buffer, actual_size);
#if !defined(USE_SIMULATOR)
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
#else
fast_exp_mips_machine_code = buffer;
return &fast_exp_simulator;
#endif
}
#if defined(V8_HOST_ARCH_MIPS)
MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
MemCopyUint8Function stub) {
@ -1092,95 +1038,6 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm,
__ bind(&done);
}
static MemOperand ExpConstant(int index, Register base) {
return MemOperand(base, index * kDoubleSize);
}
void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
DoubleRegister input,
DoubleRegister result,
DoubleRegister double_scratch1,
DoubleRegister double_scratch2,
Register temp1,
Register temp2,
Register temp3) {
DCHECK(!input.is(result));
DCHECK(!input.is(double_scratch1));
DCHECK(!input.is(double_scratch2));
DCHECK(!result.is(double_scratch1));
DCHECK(!result.is(double_scratch2));
DCHECK(!double_scratch1.is(double_scratch2));
DCHECK(!temp1.is(temp2));
DCHECK(!temp1.is(temp3));
DCHECK(!temp2.is(temp3));
DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
DCHECK(!masm->serializer_enabled()); // External references not serializable.
Label zero, infinity, done;
__ li(temp3, Operand(ExternalReference::math_exp_constants(0)));
__ ldc1(double_scratch1, ExpConstant(0, temp3));
__ BranchF(&zero, NULL, ge, double_scratch1, input);
__ ldc1(double_scratch2, ExpConstant(1, temp3));
__ BranchF(&infinity, NULL, ge, input, double_scratch2);
__ ldc1(double_scratch1, ExpConstant(3, temp3));
__ ldc1(result, ExpConstant(4, temp3));
__ mul_d(double_scratch1, double_scratch1, input);
__ add_d(double_scratch1, double_scratch1, result);
__ FmoveLow(temp2, double_scratch1);
__ sub_d(double_scratch1, double_scratch1, result);
__ ldc1(result, ExpConstant(6, temp3));
__ ldc1(double_scratch2, ExpConstant(5, temp3));
__ mul_d(double_scratch1, double_scratch1, double_scratch2);
__ sub_d(double_scratch1, double_scratch1, input);
__ sub_d(result, result, double_scratch1);
__ mul_d(double_scratch2, double_scratch1, double_scratch1);
__ mul_d(result, result, double_scratch2);
__ ldc1(double_scratch2, ExpConstant(7, temp3));
__ mul_d(result, result, double_scratch2);
__ sub_d(result, result, double_scratch1);
// Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
DCHECK(*reinterpret_cast<double*>
(ExternalReference::math_exp_constants(8).address()) == 1);
__ Move(double_scratch2, 1.);
__ add_d(result, result, double_scratch2);
__ srl(temp1, temp2, 11);
__ Ext(temp2, temp2, 0, 11);
__ Addu(temp1, temp1, Operand(0x3ff));
// Must not call ExpConstant() after overwriting temp3!
__ li(temp3, Operand(ExternalReference::math_exp_log_table()));
__ Lsa(temp3, temp3, temp2, 3);
__ lw(temp2, MemOperand(temp3, Register::kMantissaOffset));
__ lw(temp3, MemOperand(temp3, Register::kExponentOffset));
// The first word is loaded is the lower number register.
if (temp2.code() < temp3.code()) {
__ sll(at, temp1, 20);
__ Or(temp1, temp3, at);
__ Move(double_scratch1, temp2, temp1);
} else {
__ sll(at, temp1, 20);
__ Or(temp1, temp2, at);
__ Move(double_scratch1, temp3, temp1);
}
__ mul_d(result, result, double_scratch1);
__ BranchShort(&done);
__ bind(&zero);
__ Move(result, kDoubleRegZero);
__ BranchShort(&done);
__ bind(&infinity);
__ ldc1(result, ExpConstant(2, temp3));
__ bind(&done);
}
#ifdef DEBUG
// nop(CODE_AGE_MARKER_NOP)
static const uint32_t kCodeAgePatchFirstInstruction = 0x00010180;

View File

@ -29,23 +29,6 @@ class StringCharLoadGenerator : public AllStatic {
DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator);
};
class MathExpGenerator : public AllStatic {
public:
// Register input isn't modified. All other registers are clobbered.
static void EmitMathExp(MacroAssembler* masm,
DoubleRegister input,
DoubleRegister result,
DoubleRegister double_scratch1,
DoubleRegister double_scratch2,
Register temp1,
Register temp2,
Register temp3);
private:
DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
};
} // namespace internal
} // namespace v8

View File

@ -17,59 +17,6 @@ namespace internal {
#define __ masm.
#if defined(USE_SIMULATOR)
byte* fast_exp_mips_machine_code = nullptr;
double fast_exp_simulator(double x, Isolate* isolate) {
return Simulator::current(isolate)->CallFP(fast_exp_mips_machine_code, x, 0);
}
#endif
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
size_t actual_size;
byte* buffer =
static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
if (buffer == nullptr) return nullptr;
ExternalReference::InitializeMathExpData();
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
CodeObjectRequired::kNo);
{
DoubleRegister input = f12;
DoubleRegister result = f0;
DoubleRegister double_scratch1 = f4;
DoubleRegister double_scratch2 = f6;
Register temp1 = a4;
Register temp2 = a5;
Register temp3 = a6;
__ MovFromFloatParameter(input);
__ Push(temp3, temp2, temp1);
MathExpGenerator::EmitMathExp(
&masm, input, result, double_scratch1, double_scratch2,
temp1, temp2, temp3);
__ Pop(temp3, temp2, temp1);
__ MovToFloatResult(result);
__ Ret();
}
CodeDesc desc;
masm.GetCode(&desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
Assembler::FlushICache(isolate, buffer, actual_size);
base::OS::ProtectCode(buffer, actual_size);
#if !defined(USE_SIMULATOR)
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
#else
fast_exp_mips_machine_code = buffer;
return &fast_exp_simulator;
#endif
}
#if defined(V8_HOST_ARCH_MIPS)
MemCopyUint8Function CreateMemCopyUint8Function(Isolate* isolate,
MemCopyUint8Function stub) {
@ -1090,94 +1037,6 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm,
__ bind(&done);
}
static MemOperand ExpConstant(int index, Register base) {
return MemOperand(base, index * kDoubleSize);
}
void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
DoubleRegister input,
DoubleRegister result,
DoubleRegister double_scratch1,
DoubleRegister double_scratch2,
Register temp1,
Register temp2,
Register temp3) {
DCHECK(!input.is(result));
DCHECK(!input.is(double_scratch1));
DCHECK(!input.is(double_scratch2));
DCHECK(!result.is(double_scratch1));
DCHECK(!result.is(double_scratch2));
DCHECK(!double_scratch1.is(double_scratch2));
DCHECK(!temp1.is(temp2));
DCHECK(!temp1.is(temp3));
DCHECK(!temp2.is(temp3));
DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
DCHECK(!masm->serializer_enabled()); // External references not serializable.
Label zero, infinity, done;
__ li(temp3, Operand(ExternalReference::math_exp_constants(0)));
__ ldc1(double_scratch1, ExpConstant(0, temp3));
__ BranchF(&zero, NULL, ge, double_scratch1, input);
__ ldc1(double_scratch2, ExpConstant(1, temp3));
__ BranchF(&infinity, NULL, ge, input, double_scratch2);
__ ldc1(double_scratch1, ExpConstant(3, temp3));
__ ldc1(result, ExpConstant(4, temp3));
__ mul_d(double_scratch1, double_scratch1, input);
__ add_d(double_scratch1, double_scratch1, result);
__ FmoveLow(temp2, double_scratch1);
__ sub_d(double_scratch1, double_scratch1, result);
__ ldc1(result, ExpConstant(6, temp3));
__ ldc1(double_scratch2, ExpConstant(5, temp3));
__ mul_d(double_scratch1, double_scratch1, double_scratch2);
__ sub_d(double_scratch1, double_scratch1, input);
__ sub_d(result, result, double_scratch1);
__ mul_d(double_scratch2, double_scratch1, double_scratch1);
__ mul_d(result, result, double_scratch2);
__ ldc1(double_scratch2, ExpConstant(7, temp3));
__ mul_d(result, result, double_scratch2);
__ sub_d(result, result, double_scratch1);
// Mov 1 in double_scratch2 as math_exp_constants_array[8] == 1.
DCHECK(*reinterpret_cast<double*>
(ExternalReference::math_exp_constants(8).address()) == 1);
__ Move(double_scratch2, 1.);
__ add_d(result, result, double_scratch2);
__ dsrl(temp1, temp2, 11);
__ Ext(temp2, temp2, 0, 11);
__ Daddu(temp1, temp1, Operand(0x3ff));
// Must not call ExpConstant() after overwriting temp3!
__ li(temp3, Operand(ExternalReference::math_exp_log_table()));
__ Dlsa(temp3, temp3, temp2, 3);
__ lwu(temp2, MemOperand(temp3, Register::kMantissaOffset));
__ lwu(temp3, MemOperand(temp3, Register::kExponentOffset));
// The first word is loaded is the lower number register.
if (temp2.code() < temp3.code()) {
__ dsll(at, temp1, 20);
__ Or(temp1, temp3, at);
__ Move(double_scratch1, temp2, temp1);
} else {
__ dsll(at, temp1, 20);
__ Or(temp1, temp2, at);
__ Move(double_scratch1, temp3, temp1);
}
__ mul_d(result, result, double_scratch1);
__ BranchShort(&done);
__ bind(&zero);
__ Move(result, kDoubleRegZero);
__ BranchShort(&done);
__ bind(&infinity);
__ ldc1(result, ExpConstant(2, temp3));
__ bind(&done);
}
#ifdef DEBUG
// nop(CODE_AGE_MARKER_NOP)
static const uint32_t kCodeAgePatchFirstInstruction = 0x00010180;

View File

@ -29,23 +29,6 @@ class StringCharLoadGenerator : public AllStatic {
DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator);
};
class MathExpGenerator : public AllStatic {
public:
// Register input isn't modified. All other registers are clobbered.
static void EmitMathExp(MacroAssembler* masm,
DoubleRegister input,
DoubleRegister result,
DoubleRegister double_scratch1,
DoubleRegister double_scratch2,
Register temp1,
Register temp2,
Register temp3);
private:
DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
};
} // namespace internal
} // namespace v8

View File

@ -59,17 +59,6 @@ RUNTIME_FUNCTION(Runtime_RemPiO2) {
}
RUNTIME_FUNCTION(Runtime_MathExpRT) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
isolate->counters()->math_exp_runtime()->Increment();
CONVERT_DOUBLE_ARG_CHECKED(x, 0);
lazily_initialize_fast_exp(isolate);
return *isolate->factory()->NewNumber(fast_exp(x, isolate));
}
// Slow version of Math.pow. We check for fast paths for special cases.
// Used if VFP3 is not available.
RUNTIME_FUNCTION(Runtime_MathPow) {

View File

@ -355,7 +355,6 @@ namespace internal {
F(DoubleLo, 1, 1) \
F(ConstructDouble, 2, 1) \
F(RemPiO2, 2, 1) \
F(MathExpRT, 1, 1) \
F(MathPow, 2, 1) \
F(MathPowRT, 2, 1) \
F(GenerateRandomNumbers, 1, 1)

View File

@ -31,13 +31,11 @@
var GlobalFloat64Array = global.Float64Array;
var GlobalMath = global.Math;
var MathAbs;
var MathExp;
var NaN = %GetRootNaN();
var rempio2result;
utils.Import(function(from) {
MathAbs = from.MathAbs;
MathExp = from.MathExp;
});
utils.CreateDoubleResultArray = function(global) {
@ -634,11 +632,11 @@ function MathSinh(x) {
return h * (t + t / (t + 1));
}
// |x| in [22, log(maxdouble)], return 0.5 * exp(|x|)
if (ax < LOG_MAXD) return h * MathExp(ax);
if (ax < LOG_MAXD) return h * %math_exp(ax);
// |x| in [log(maxdouble), overflowthreshold]
// overflowthreshold = 710.4758600739426
if (ax <= KSINH_OVERFLOW) {
var w = MathExp(0.5 * ax);
var w = %math_exp(0.5 * ax);
var t = h * w;
return t * w;
}
@ -684,14 +682,14 @@ function MathCosh(x) {
}
// |x| in [0.5*log2, 22], return (exp(|x|)+1/exp(|x|)/2
if (ix < 0x40360000) {
var t = MathExp(MathAbs(x));
var t = %math_exp(MathAbs(x));
return 0.5 * t + 0.5 / t;
}
// |x| in [22, log(maxdouble)], return half*exp(|x|)
if (ix < 0x40862e42) return 0.5 * MathExp(MathAbs(x));
if (ix < 0x40862e42) return 0.5 * %math_exp(MathAbs(x));
// |x| in [log(maxdouble), overflowthreshold]
if (MathAbs(x) <= KCOSH_OVERFLOW) {
var w = MathExp(0.5 * MathAbs(x));
var w = %math_exp(0.5 * MathAbs(x));
var t = 0.5 * w;
return t * w;
}

View File

@ -45,7 +45,6 @@ void V8::TearDown() {
Bootstrapper::TearDownExtensions();
ElementsAccessor::TearDown();
LOperand::TearDownCaches();
ExternalReference::TearDownMathExpData();
RegisteredExtension::UnregisterAll();
Isolate::GlobalTearDown();
sampler::Sampler::TearDown();

View File

@ -32,38 +32,6 @@ void StubRuntimeCallHelper::AfterCall(MacroAssembler* masm) const {
#define __ masm.
UnaryMathFunctionWithIsolate CreateExpFunction(Isolate* isolate) {
size_t actual_size;
byte* buffer =
static_cast<byte*>(base::OS::Allocate(1 * KB, &actual_size, true));
if (buffer == nullptr) return nullptr;
ExternalReference::InitializeMathExpData();
MacroAssembler masm(isolate, buffer, static_cast<int>(actual_size),
CodeObjectRequired::kNo);
// xmm0: raw double input.
XMMRegister input = xmm0;
XMMRegister result = xmm1;
__ pushq(rax);
__ pushq(rbx);
MathExpGenerator::EmitMathExp(&masm, input, result, xmm2, rax, rbx);
__ popq(rbx);
__ popq(rax);
__ Movsd(xmm0, result);
__ Ret();
CodeDesc desc;
masm.GetCode(&desc);
DCHECK(!RelocInfo::RequiresRelocation(desc));
Assembler::FlushICache(isolate, buffer, actual_size);
base::OS::ProtectCode(buffer, actual_size);
return FUNCTION_CAST<UnaryMathFunctionWithIsolate>(buffer);
}
UnaryMathFunctionWithIsolate CreateSqrtFunction(Isolate* isolate) {
size_t actual_size;
// Allocate buffer in executable space.
@ -499,59 +467,6 @@ void StringCharLoadGenerator::Generate(MacroAssembler* masm,
__ bind(&done);
}
void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
XMMRegister input,
XMMRegister result,
XMMRegister double_scratch,
Register temp1,
Register temp2) {
DCHECK(!input.is(result));
DCHECK(!input.is(double_scratch));
DCHECK(!result.is(double_scratch));
DCHECK(!temp1.is(temp2));
DCHECK(ExternalReference::math_exp_constants(0).address() != NULL);
DCHECK(!masm->serializer_enabled()); // External references not serializable.
Label done;
__ Move(kScratchRegister, ExternalReference::math_exp_constants(0));
__ Movsd(double_scratch, Operand(kScratchRegister, 0 * kDoubleSize));
__ Xorpd(result, result);
__ Ucomisd(double_scratch, input);
__ j(above_equal, &done);
__ Ucomisd(input, Operand(kScratchRegister, 1 * kDoubleSize));
__ Movsd(result, Operand(kScratchRegister, 2 * kDoubleSize));
__ j(above_equal, &done);
__ Movsd(double_scratch, Operand(kScratchRegister, 3 * kDoubleSize));
__ Movsd(result, Operand(kScratchRegister, 4 * kDoubleSize));
__ Mulsd(double_scratch, input);
__ Addsd(double_scratch, result);
__ Movq(temp2, double_scratch);
__ Subsd(double_scratch, result);
__ Movsd(result, Operand(kScratchRegister, 6 * kDoubleSize));
__ leaq(temp1, Operand(temp2, 0x1ff800));
__ andq(temp2, Immediate(0x7ff));
__ shrq(temp1, Immediate(11));
__ Mulsd(double_scratch, Operand(kScratchRegister, 5 * kDoubleSize));
__ Move(kScratchRegister, ExternalReference::math_exp_log_table());
__ shlq(temp1, Immediate(52));
__ orq(temp1, Operand(kScratchRegister, temp2, times_8, 0));
__ Move(kScratchRegister, ExternalReference::math_exp_constants(0));
__ Subsd(double_scratch, input);
__ Movsd(input, double_scratch);
__ Subsd(result, double_scratch);
__ Mulsd(input, double_scratch);
__ Mulsd(result, input);
__ Movq(input, temp1);
__ Mulsd(result, Operand(kScratchRegister, 7 * kDoubleSize));
__ Subsd(result, double_scratch);
__ Addsd(result, Operand(kScratchRegister, 8 * kDoubleSize));
__ Mulsd(result, input);
__ bind(&done);
}
#undef __

View File

@ -28,20 +28,6 @@ class StringCharLoadGenerator : public AllStatic {
};
class MathExpGenerator : public AllStatic {
public:
static void EmitMathExp(MacroAssembler* masm,
XMMRegister input,
XMMRegister result,
XMMRegister double_scratch,
Register temp1,
Register temp2);
private:
DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
};
enum StackArgumentsAccessorReceiverMode {
ARGUMENTS_CONTAIN_RECEIVER,
ARGUMENTS_DONT_CONTAIN_RECEIVER

View File

@ -5517,6 +5517,19 @@ TEST(RunFloat64Atan2) {
}
}
TEST(RunFloat64Exp) {
BufferedRawMachineAssemblerTester<double> m(MachineType::Float64());
m.Return(m.Float64Exp(m.Parameter(0)));
CHECK(std::isnan(m.Call(std::numeric_limits<double>::quiet_NaN())));
CHECK(std::isnan(m.Call(std::numeric_limits<double>::signaling_NaN())));
CHECK_EQ(0.0, m.Call(-std::numeric_limits<double>::infinity()));
CHECK_DOUBLE_EQ(1.0, m.Call(-0.0));
CHECK_DOUBLE_EQ(1.0, m.Call(0.0));
CHECK_DOUBLE_EQ(std::numeric_limits<double>::infinity(),
m.Call(std::numeric_limits<double>::infinity()));
FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(ieee754::exp(*i), m.Call(*i)); }
}
TEST(RunFloat64Log) {
BufferedRawMachineAssemblerTester<double> m(MachineType::Float64());
m.Return(m.Float64Log(m.Parameter(0)));

View File

@ -54,6 +54,34 @@ 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(0.0, exp(-1000));
EXPECT_EQ(0.0, exp(-745.1332191019412));
EXPECT_EQ(2.2250738585072626e-308, exp(-708.39641853226408));
EXPECT_EQ(3.307553003638408e-308, exp(-708.0));
EXPECT_EQ(4.9406564584124654e-324, exp(-7.45133219101941108420e+02));
EXPECT_EQ(0.36787944117144233, exp(-1.0));
EXPECT_EQ(1.0, exp(-0.0));
EXPECT_EQ(1.0, exp(0.0));
EXPECT_EQ(1.0, exp(2.2250738585072014e-308));
EXPECT_GE(exp(1.0), exp(0.9999999999999999));
EXPECT_LE(exp(1.0), exp(1.0000000000000002));
EXPECT_EQ(2.7182818284590455, exp(1.0));
EXPECT_EQ(7.38905609893065e0, exp(2.0));
EXPECT_EQ(1.7976931348622732e308, exp(7.09782712893383973096e+02));
EXPECT_EQ(2.6881171418161356e+43, exp(100.0));
EXPECT_EQ(8.218407461554972e+307, exp(709.0));
EXPECT_EQ(1.7968190737295725e308, exp(709.7822265625e0));
EXPECT_EQ(std::numeric_limits<double>::infinity(), exp(709.7827128933841e0));
EXPECT_EQ(std::numeric_limits<double>::infinity(), exp(710.0));
EXPECT_EQ(std::numeric_limits<double>::infinity(), exp(1000.0));
EXPECT_EQ(std::numeric_limits<double>::infinity(),
exp(std::numeric_limits<double>::infinity()));
}
TEST(Ieee754, Log) {
EXPECT_THAT(log(std::numeric_limits<double>::quiet_NaN()), IsNaN());
EXPECT_THAT(log(std::numeric_limits<double>::signaling_NaN()), IsNaN());

View File

@ -263,6 +263,45 @@ TEST_F(JSBuiltinReducerTest, MathClz32WithPlainPrimitive) {
IsNumberClz32(IsNumberToUint32(IsPlainPrimitiveToNumber(p0))));
}
// -----------------------------------------------------------------------------
// Math.exp
TEST_F(JSBuiltinReducerTest, MathExpWithNumber) {
Node* function = MathFunction("exp");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
TRACED_FOREACH(Type*, t0, kNumberTypes) {
Node* p0 = Parameter(t0, 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberExp(p0));
}
}
TEST_F(JSBuiltinReducerTest, MathExpWithPlainPrimitive) {
Node* function = MathFunction("exp");
Node* effect = graph()->start();
Node* control = graph()->start();
Node* context = UndefinedConstant();
Node* frame_state = graph()->start();
Node* p0 = Parameter(Type::PlainPrimitive(), 0);
Node* call = graph()->NewNode(javascript()->CallFunction(3), function,
UndefinedConstant(), p0, context, frame_state,
effect, control);
Reduction r = Reduce(call);
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(), IsNumberExp(IsPlainPrimitiveToNumber(p0)));
}
// -----------------------------------------------------------------------------
// Math.floor

View File

@ -1463,6 +1463,19 @@ TEST_F(MachineOperatorReducerTest, Float64Atan2WithNaN) {
}
}
// -----------------------------------------------------------------------------
// Float64Exp
TEST_F(MachineOperatorReducerTest, Float64ExpWithConstant) {
TRACED_FOREACH(double, x, kFloat64Values) {
Reduction const r =
Reduce(graph()->NewNode(machine()->Float64Exp(), Float64Constant(x)));
ASSERT_TRUE(r.Changed());
EXPECT_THAT(r.replacement(),
IsFloat64Constant(NanSensitiveDoubleEq(base::ieee754::exp(x))));
}
}
// -----------------------------------------------------------------------------
// Float64Log

View File

@ -2313,6 +2313,7 @@ IS_UNOP_MATCHER(Float64ExtractHighWord32)
IS_UNOP_MATCHER(NumberAtan)
IS_UNOP_MATCHER(NumberCeil)
IS_UNOP_MATCHER(NumberClz32)
IS_UNOP_MATCHER(NumberExp)
IS_UNOP_MATCHER(NumberFloor)
IS_UNOP_MATCHER(NumberFround)
IS_UNOP_MATCHER(NumberLog)

View File

@ -229,6 +229,7 @@ Matcher<Node*> IsNumberAtan2(const Matcher<Node*>& lhs_matcher,
const Matcher<Node*>& rhs_matcher);
Matcher<Node*> IsNumberCeil(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberClz32(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberExp(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberFloor(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberFround(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsNumberLog(const Matcher<Node*>& value_matcher);