Revert of [builtins] Introduce proper Float64Exp operator. (patchset #5 id:80001 of https://codereview.chromium.org/2077533002/ )

Reason for revert:
[Sheriff] Leads to some different rounding as it seems in some audio layout tests. Please rebase upstream first if intended:
https://build.chromium.org/p/client.v8.fyi/builders/V8-Blink%20Linux%2064/builds/7508

Original issue's description:
> [builtins] Introduce proper Float64Exp operator.
>
> Import base::ieee754::exp() from FreeBSD msun and introduce a Float64Exp
> TurboFan operator based on that, similar to what we do for Float64Log.
> Rewrite Math.exp() as TurboFan builtin and use that operator to also
> inline Math.exp() into optimized TurboFan functions.
>
> BUG=v8:3266,v8:3468,v8:3493,v8:5086,v8:5108
> R=mvstanton@chromium.org
>
> Committed: https://crrev.com/93e26314afc9da9b5b8bd998688262444ed73260
> Cr-Commit-Position: refs/heads/master@{#37037}

TBR=mvstanton@chromium.org,ahaas@chromium.org,bmeurer@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=v8:3266,v8:3468,v8:3493,v8:5086,v8:5108

Review-Url: https://codereview.chromium.org/2070813002
Cr-Commit-Position: refs/heads/master@{#37039}
This commit is contained in:
machenbach 2016-06-16 05:48:34 -07:00 committed by Commit bot
parent 6fa656fde2
commit 789b0ad77a
77 changed files with 1181 additions and 396 deletions

View File

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

View File

@ -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

View File

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

View File

@ -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

View File

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

View File

@ -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);

View File

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

View File

@ -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);

View File

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

View File

@ -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);

View File

@ -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 )

View File

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

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

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

View File

@ -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;

View File

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

View File

@ -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:

View File

@ -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);
}

View File

@ -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;

View File

@ -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);

View File

@ -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()));

View File

@ -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) \

View File

@ -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();

View File

@ -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;

View File

@ -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;

View File

@ -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) \

View File

@ -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); }

View File

@ -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:

View File

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

View File

@ -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) \

View File

@ -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();

View File

@ -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(); }

View File

@ -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:

View File

@ -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;

View File

@ -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) \

View File

@ -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);
}

View File

@ -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")
};

View File

@ -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());
}

View File

@ -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());

View File

@ -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")
};

View File

@ -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);
}

View File

@ -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:

View File

@ -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:

View File

@ -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,

View File

@ -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);
}

View File

@ -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")
};

View File

@ -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());
}

View File

@ -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);
}

View File

@ -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")
};

View File

@ -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());
}

View File

@ -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);
}

View File

@ -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")
};

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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")
};

View File

@ -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(),

View File

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

View File

@ -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

View File

@ -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;
});

View File

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

View File

@ -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

View File

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

View File

@ -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

View File

@ -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) {

View File

@ -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)

View File

@ -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;
}

View File

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

View File

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

View File

@ -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

View File

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

View File

@ -54,23 +54,6 @@ TEST(Ieee754, Atan2) {
-std::numeric_limits<double>::infinity()));
}
TEST(Ieee754, Exp) {
EXPECT_THAT(exp(std::numeric_limits<double>::quiet_NaN()), IsNaN());
EXPECT_THAT(exp(std::numeric_limits<double>::signaling_NaN()), IsNaN());
EXPECT_EQ(0.0, exp(-std::numeric_limits<double>::infinity()));
EXPECT_EQ(std::numeric_limits<double>::infinity(),
exp(std::numeric_limits<double>::infinity()));
EXPECT_EQ(3.307553003638408e-308, exp(-708.0));
EXPECT_EQ(2.2250738585072626e-308, exp(-708.39641853226408));
EXPECT_EQ(0.36787944117144233, exp(-1.0));
EXPECT_EQ(1.0, exp(-0.0));
EXPECT_EQ(1.0, exp(0.0));
EXPECT_EQ(2.7182818284590455, exp(1.0));
EXPECT_EQ(2.6881171418161356e+43, exp(100.0));
EXPECT_EQ(8.218407461554972e+307, exp(709.0));
EXPECT_EQ(std::numeric_limits<double>::infinity(), exp(710.0));
}
TEST(Ieee754, Log) {
EXPECT_THAT(log(std::numeric_limits<double>::quiet_NaN()), IsNaN());
EXPECT_THAT(log(std::numeric_limits<double>::signaling_NaN()), IsNaN());

View File

@ -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

View File

@ -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

View File

@ -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)

View File

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