[builtins] Introduce proper Float64Log1p operator.
Import base::ieee754::log1p() from fdlibm and introduce a Float64Log1p TurboFan operator based on that, similar to what we do for Float64Log. Rewrite Math.log1p() as TurboFan builtin and use that operator to also inline Math.log1p() into optimized TurboFan functions. Also unify the handling of the special IEEE 754 functions somewhat in the TurboFan backends. At some point we can hopefully express this completely in the InstructionSelector (once we have an idea what to do with the ST(0) return issue on IA-32/X87). Drive-by-fix: Add some more test coverage for the log function. R=yangguo@chromium.org BUG=v8:5086,v8:5092 Review-Url: https://codereview.chromium.org/2060743002 Cr-Commit-Position: refs/heads/master@{#36914}
This commit is contained in:
parent
b01622c312
commit
7ceed92ac0
@ -1653,6 +1653,10 @@ ExternalReference ExternalReference::ieee754_log_function(Isolate* isolate) {
|
||||
Redirect(isolate, FUNCTION_ADDR(base::ieee754::log), BUILTIN_FP_CALL));
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::ieee754_log1p_function(Isolate* isolate) {
|
||||
return ExternalReference(
|
||||
Redirect(isolate, FUNCTION_ADDR(base::ieee754::log1p), BUILTIN_FP_CALL));
|
||||
}
|
||||
|
||||
ExternalReference ExternalReference::math_exp_constants(int constant_index) {
|
||||
DCHECK(math_exp_data_initialized);
|
||||
|
@ -1037,6 +1037,7 @@ class ExternalReference BASE_EMBEDDED {
|
||||
|
||||
// IEEE 754 functions.
|
||||
static ExternalReference ieee754_log_function(Isolate* isolate);
|
||||
static ExternalReference ieee754_log1p_function(Isolate* isolate);
|
||||
|
||||
static ExternalReference math_exp_constants(int constant_index);
|
||||
static ExternalReference math_exp_log_table();
|
||||
|
@ -163,6 +163,10 @@ typedef union {
|
||||
(d) = sl_u.value; \
|
||||
} while (0)
|
||||
|
||||
/* Support macro. */
|
||||
|
||||
#define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval))
|
||||
|
||||
} // namespace
|
||||
|
||||
/* log(x)
|
||||
@ -294,6 +298,170 @@ double log(double x) {
|
||||
}
|
||||
}
|
||||
|
||||
/* double log1p(double x)
|
||||
*
|
||||
* Method :
|
||||
* 1. Argument Reduction: find k and f such that
|
||||
* 1+x = 2^k * (1+f),
|
||||
* where sqrt(2)/2 < 1+f < sqrt(2) .
|
||||
*
|
||||
* Note. If k=0, then f=x is exact. However, if k!=0, then f
|
||||
* may not be representable exactly. In that case, a correction
|
||||
* term is need. Let u=1+x rounded. Let c = (1+x)-u, then
|
||||
* log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
|
||||
* and add back the correction term c/u.
|
||||
* (Note: when x > 2**53, one can simply return log(x))
|
||||
*
|
||||
* 2. Approximation of log1p(f).
|
||||
* Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
|
||||
* = 2s + 2/3 s**3 + 2/5 s**5 + .....,
|
||||
* = 2s + s*R
|
||||
* We use a special Reme algorithm on [0,0.1716] to generate
|
||||
* a polynomial of degree 14 to approximate R The maximum error
|
||||
* of this polynomial approximation is bounded by 2**-58.45. In
|
||||
* other words,
|
||||
* 2 4 6 8 10 12 14
|
||||
* R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s
|
||||
* (the values of Lp1 to Lp7 are listed in the program)
|
||||
* and
|
||||
* | 2 14 | -58.45
|
||||
* | Lp1*s +...+Lp7*s - R(z) | <= 2
|
||||
* | |
|
||||
* Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
|
||||
* In order to guarantee error in log below 1ulp, we compute log
|
||||
* by
|
||||
* log1p(f) = f - (hfsq - s*(hfsq+R)).
|
||||
*
|
||||
* 3. Finally, log1p(x) = k*ln2 + log1p(f).
|
||||
* = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
|
||||
* Here ln2 is split into two floating point number:
|
||||
* ln2_hi + ln2_lo,
|
||||
* where n*ln2_hi is always exact for |n| < 2000.
|
||||
*
|
||||
* Special cases:
|
||||
* log1p(x) is NaN with signal if x < -1 (including -INF) ;
|
||||
* log1p(+INF) is +INF; log1p(-1) is -INF with signal;
|
||||
* log1p(NaN) is that NaN with no signal.
|
||||
*
|
||||
* Accuracy:
|
||||
* according to an error analysis, the error is always less than
|
||||
* 1 ulp (unit in the last place).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Note: Assuming log() return accurate answer, the following
|
||||
* algorithm can be used to compute log1p(x) to within a few ULP:
|
||||
*
|
||||
* u = 1+x;
|
||||
* if(u==1.0) return x ; else
|
||||
* return log(u)*(x/(u-1.0));
|
||||
*
|
||||
* See HP-15C Advanced Functions Handbook, p.193.
|
||||
*/
|
||||
double log1p(double x) {
|
||||
static const double /* -- */
|
||||
ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */
|
||||
ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */
|
||||
two54 = 1.80143985094819840000e+16, /* 43500000 00000000 */
|
||||
Lp1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */
|
||||
Lp2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */
|
||||
Lp3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */
|
||||
Lp4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */
|
||||
Lp5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */
|
||||
Lp6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */
|
||||
Lp7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
|
||||
|
||||
static const double zero = 0.0;
|
||||
static volatile double vzero = 0.0;
|
||||
|
||||
double hfsq, f, c, s, z, R, u;
|
||||
int32_t k, hx, hu, ax;
|
||||
|
||||
GET_HIGH_WORD(hx, x);
|
||||
ax = hx & 0x7fffffff;
|
||||
|
||||
k = 1;
|
||||
if (hx < 0x3FDA827A) { /* 1+x < sqrt(2)+ */
|
||||
if (ax >= 0x3ff00000) { /* x <= -1.0 */
|
||||
if (x == -1.0)
|
||||
return -two54 / vzero; /* log1p(-1)=+inf */
|
||||
else
|
||||
return (x - x) / (x - x); /* log1p(x<-1)=NaN */
|
||||
}
|
||||
if (ax < 0x3e200000) { /* |x| < 2**-29 */
|
||||
if (two54 + x > zero /* raise inexact */
|
||||
&& ax < 0x3c900000) /* |x| < 2**-54 */
|
||||
return x;
|
||||
else
|
||||
return x - x * x * 0.5;
|
||||
}
|
||||
if (hx > 0 || hx <= static_cast<int32_t>(0xbfd2bec4)) {
|
||||
k = 0;
|
||||
f = x;
|
||||
hu = 1;
|
||||
} /* sqrt(2)/2- <= 1+x < sqrt(2)+ */
|
||||
}
|
||||
if (hx >= 0x7ff00000) return x + x;
|
||||
if (k != 0) {
|
||||
if (hx < 0x43400000) {
|
||||
STRICT_ASSIGN(double, u, 1.0 + x);
|
||||
GET_HIGH_WORD(hu, u);
|
||||
k = (hu >> 20) - 1023;
|
||||
c = (k > 0) ? 1.0 - (u - x) : x - (u - 1.0); /* correction term */
|
||||
c /= u;
|
||||
} else {
|
||||
u = x;
|
||||
GET_HIGH_WORD(hu, u);
|
||||
k = (hu >> 20) - 1023;
|
||||
c = 0;
|
||||
}
|
||||
hu &= 0x000fffff;
|
||||
/*
|
||||
* The approximation to sqrt(2) used in thresholds is not
|
||||
* critical. However, the ones used above must give less
|
||||
* strict bounds than the one here so that the k==0 case is
|
||||
* never reached from here, since here we have committed to
|
||||
* using the correction term but don't use it if k==0.
|
||||
*/
|
||||
if (hu < 0x6a09e) { /* u ~< sqrt(2) */
|
||||
SET_HIGH_WORD(u, hu | 0x3ff00000); /* normalize u */
|
||||
} else {
|
||||
k += 1;
|
||||
SET_HIGH_WORD(u, hu | 0x3fe00000); /* normalize u/2 */
|
||||
hu = (0x00100000 - hu) >> 2;
|
||||
}
|
||||
f = u - 1.0;
|
||||
}
|
||||
hfsq = 0.5 * f * f;
|
||||
if (hu == 0) { /* |f| < 2**-20 */
|
||||
if (f == zero) {
|
||||
if (k == 0) {
|
||||
return zero;
|
||||
} else {
|
||||
c += k * ln2_lo;
|
||||
return k * ln2_hi + c;
|
||||
}
|
||||
}
|
||||
R = hfsq * (1.0 - 0.66666666666666666 * f);
|
||||
if (k == 0)
|
||||
return f - R;
|
||||
else
|
||||
return k * ln2_hi - ((R - (k * ln2_lo + c)) - f);
|
||||
}
|
||||
s = f / (2.0 + f);
|
||||
z = s * s;
|
||||
R = z * (Lp1 +
|
||||
z * (Lp2 + z * (Lp3 + z * (Lp4 + z * (Lp5 + z * (Lp6 + z * Lp7))))));
|
||||
if (k == 0)
|
||||
return f - (hfsq - s * (hfsq + R));
|
||||
else
|
||||
return k * ln2_hi - ((hfsq - (s * (hfsq + R) + (k * ln2_lo + c))) - f);
|
||||
}
|
||||
|
||||
} // namespace ieee754
|
||||
} // namespace base
|
||||
} // namespace v8
|
||||
|
@ -12,6 +12,10 @@ namespace ieee754 {
|
||||
// Returns the natural logarithm of |x|.
|
||||
double log(double x);
|
||||
|
||||
// Returns a value equivalent to |log(1+x)|, but computed in a way that is
|
||||
// accurate even if the value of |x| is near zero.
|
||||
double log1p(double x);
|
||||
|
||||
} // namespace ieee754
|
||||
} // namespace base
|
||||
} // namespace v8
|
||||
|
@ -1682,6 +1682,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
Handle<JSFunction> math_log =
|
||||
SimpleInstallFunction(math, "log", Builtins::kMathLog, 1, true);
|
||||
native_context()->set_math_log(*math_log);
|
||||
SimpleInstallFunction(math, "log1p", Builtins::kMathLog1p, 1, true);
|
||||
SimpleInstallFunction(math, "max", Builtins::kMathMax, 2, false);
|
||||
SimpleInstallFunction(math, "min", Builtins::kMathMin, 2, false);
|
||||
SimpleInstallFunction(math, "round", Builtins::kMathRound, 1, true);
|
||||
|
@ -2474,6 +2474,18 @@ void Builtins::Generate_MathLog(CodeStubAssembler* assembler) {
|
||||
assembler->Return(result);
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.21 Math.log1p ( x )
|
||||
void Builtins::Generate_MathLog1p(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->Float64Log1p(x_value);
|
||||
Node* result = assembler->ChangeFloat64ToTagged(value);
|
||||
assembler->Return(result);
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.28 Math.round ( x )
|
||||
void Builtins::Generate_MathRound(CodeStubAssembler* assembler) {
|
||||
Generate_MathRoundingOperation(assembler, &CodeStubAssembler::Float64Round);
|
||||
|
@ -325,6 +325,7 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
|
||||
V(MathClz32, 2) \
|
||||
V(MathFloor, 2) \
|
||||
V(MathLog, 2) \
|
||||
V(MathLog1p, 2) \
|
||||
V(MathRound, 2) \
|
||||
V(MathSqrt, 2) \
|
||||
V(MathTrunc, 2) \
|
||||
@ -622,6 +623,8 @@ class Builtins {
|
||||
static void Generate_MathFloor(CodeStubAssembler* assembler);
|
||||
// ES6 section 20.2.2.20 Math.log ( x )
|
||||
static void Generate_MathLog(CodeStubAssembler* assembler);
|
||||
// ES6 section 20.2.2.21 Math.log ( x )
|
||||
static void Generate_MathLog1p(CodeStubAssembler* assembler);
|
||||
enum class MathMaxMinKind { kMax, kMin };
|
||||
static void Generate_MathMaxMin(MacroAssembler* masm, MathMaxMinKind kind);
|
||||
// ES6 section 20.2.2.24 Math.max ( value1, value2 , ...values )
|
||||
|
@ -407,6 +407,20 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
|
||||
__ dmb(ISH); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_IEEE754_UNOP(name) \
|
||||
do { \
|
||||
/* TODO(bmeurer): We should really get rid of this special instruction, */ \
|
||||
/* and generate a CallAddress instruction instead. */ \
|
||||
FrameScope scope(masm(), StackFrame::MANUAL); \
|
||||
__ PrepareCallCFunction(0, 1, kScratchReg); \
|
||||
__ MovToFloatParameter(i.InputFloat64Register(0)); \
|
||||
__ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
|
||||
0, 1); \
|
||||
/* Move the result in the double result register. */ \
|
||||
__ MovFromFloatResult(i.OutputFloat64Register()); \
|
||||
DCHECK_EQ(LeaveCC, i.OutputSBit()); \
|
||||
} while (0)
|
||||
|
||||
void CodeGenerator::AssembleDeconstructFrame() {
|
||||
__ LeaveFrame(StackFrame::MANUAL);
|
||||
}
|
||||
@ -674,19 +688,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
__ add(i.OutputRegister(0), base, Operand(offset.offset()));
|
||||
break;
|
||||
}
|
||||
case kIeee754Float64Log: {
|
||||
// TODO(bmeurer): We should really get rid of this special instruction,
|
||||
// and generate a CallAddress instruction instead.
|
||||
FrameScope scope(masm(), StackFrame::MANUAL);
|
||||
__ PrepareCallCFunction(0, 1, kScratchReg);
|
||||
__ MovToFloatParameter(i.InputFloat64Register(0));
|
||||
__ CallCFunction(ExternalReference::ieee754_log_function(isolate()), 0,
|
||||
1);
|
||||
// Move the result in the double result register.
|
||||
__ MovFromFloatResult(i.OutputFloat64Register());
|
||||
DCHECK_EQ(LeaveCC, i.OutputSBit());
|
||||
case kIeee754Float64Log:
|
||||
ASSEMBLE_IEEE754_UNOP(log);
|
||||
break;
|
||||
case kIeee754Float64Log1p:
|
||||
ASSEMBLE_IEEE754_UNOP(log1p);
|
||||
break;
|
||||
}
|
||||
case kArmAdd:
|
||||
__ add(i.OutputRegister(), i.InputRegister(0), i.InputOperand2(1),
|
||||
i.OutputSBit());
|
||||
|
@ -1393,13 +1393,6 @@ void InstructionSelector::VisitFloat64Abs(Node* node) {
|
||||
VisitRR(this, kArmVabsF64, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Log(Node* node) {
|
||||
ArmOperandGenerator g(this);
|
||||
Emit(kIeee754Float64Log, g.DefineAsFixed(node, d0),
|
||||
g.UseFixed(node->InputAt(0), d0))
|
||||
->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat32Sqrt(Node* node) {
|
||||
VisitRR(this, kArmVsqrtF32, node);
|
||||
}
|
||||
@ -1462,6 +1455,13 @@ void InstructionSelector::VisitFloat64Neg(Node* node) {
|
||||
VisitRR(this, kArmVnegF64, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
|
||||
InstructionCode opcode) {
|
||||
ArmOperandGenerator g(this);
|
||||
Emit(opcode, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0))
|
||||
->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitPrepareArguments(
|
||||
ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
|
||||
Node* node) {
|
||||
|
@ -512,6 +512,13 @@ Condition FlagsConditionToCondition(FlagsCondition condition) {
|
||||
__ Dmb(InnerShareable, BarrierAll); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_IEEE754_UNOP(name) \
|
||||
do { \
|
||||
FrameScope scope(masm(), StackFrame::MANUAL); \
|
||||
__ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
|
||||
0, 1); \
|
||||
} while (0)
|
||||
|
||||
void CodeGenerator::AssembleDeconstructFrame() {
|
||||
const CallDescriptor* descriptor = linkage()->GetIncomingDescriptor();
|
||||
if (descriptor->IsCFunctionCall() || descriptor->UseNativeStack()) {
|
||||
@ -792,14 +799,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
__ Add(i.OutputRegister(0), base, Operand(offset.offset()));
|
||||
break;
|
||||
}
|
||||
case kIeee754Float64Log: {
|
||||
FrameScope scope(masm(), StackFrame::MANUAL);
|
||||
DCHECK(d0.is(i.InputDoubleRegister(0)));
|
||||
DCHECK(d0.is(i.OutputDoubleRegister()));
|
||||
__ CallCFunction(ExternalReference::ieee754_log_function(isolate()), 0,
|
||||
1);
|
||||
case kIeee754Float64Log:
|
||||
ASSEMBLE_IEEE754_UNOP(log);
|
||||
break;
|
||||
case kIeee754Float64Log1p:
|
||||
ASSEMBLE_IEEE754_UNOP(log1p);
|
||||
break;
|
||||
}
|
||||
case kArm64Float32RoundDown:
|
||||
__ Frintm(i.OutputFloat32Register(), i.InputFloat32Register(0));
|
||||
break;
|
||||
|
@ -1687,13 +1687,6 @@ void InstructionSelector::VisitFloat64Abs(Node* node) {
|
||||
VisitRR(this, kArm64Float64Abs, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Log(Node* node) {
|
||||
Arm64OperandGenerator g(this);
|
||||
Emit(kIeee754Float64Log, g.DefineAsFixed(node, d0),
|
||||
g.UseFixed(node->InputAt(0), d0))
|
||||
->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat32Sqrt(Node* node) {
|
||||
VisitRR(this, kArm64Float32Sqrt, node);
|
||||
}
|
||||
@ -1756,6 +1749,13 @@ void InstructionSelector::VisitFloat64Neg(Node* node) {
|
||||
VisitRR(this, kArm64Float64Neg, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
|
||||
InstructionCode opcode) {
|
||||
Arm64OperandGenerator g(this);
|
||||
Emit(opcode, g.DefineAsFixed(node, d0), g.UseFixed(node->InputAt(0), d0))
|
||||
->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitPrepareArguments(
|
||||
ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
|
||||
Node* node) {
|
||||
|
@ -107,6 +107,7 @@ class Schedule;
|
||||
|
||||
#define CODE_ASSEMBLER_UNARY_OP_LIST(V) \
|
||||
V(Float64Log) \
|
||||
V(Float64Log1p) \
|
||||
V(Float64Neg) \
|
||||
V(Float64Sqrt) \
|
||||
V(Float64ExtractLowWord32) \
|
||||
|
@ -363,6 +363,21 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_IEEE754_UNOP(name) \
|
||||
do { \
|
||||
/* Pass one double as argument on the stack.*/ \
|
||||
__ PrepareCallCFunction(2, eax); \
|
||||
__ movsd(Operand(esp, 0 * kDoubleSize), i.InputDoubleRegister(0)); \
|
||||
__ CallCFunction(ExternalReference::ieee754_##name##_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(i.OutputDoubleRegister(), Operand(esp, 0)); \
|
||||
__ add(esp, Immediate(kDoubleSize)); \
|
||||
} while (false)
|
||||
|
||||
void CodeGenerator::AssembleDeconstructFrame() {
|
||||
__ mov(esp, ebp);
|
||||
__ pop(ebp);
|
||||
@ -617,19 +632,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
__ lea(i.OutputRegister(), Operand(base, offset.offset()));
|
||||
break;
|
||||
}
|
||||
case kIeee754Float64Log: {
|
||||
// Pass one double as argument on the stack.
|
||||
__ PrepareCallCFunction(2, eax);
|
||||
__ movsd(Operand(esp, 0 * kDoubleSize), i.InputDoubleRegister(0));
|
||||
__ CallCFunction(ExternalReference::ieee754_log_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(i.OutputDoubleRegister(), Operand(esp, 0));
|
||||
__ add(esp, Immediate(kDoubleSize));
|
||||
case kIeee754Float64Log:
|
||||
ASSEMBLE_IEEE754_UNOP(log);
|
||||
break;
|
||||
case kIeee754Float64Log1p:
|
||||
ASSEMBLE_IEEE754_UNOP(log1p);
|
||||
break;
|
||||
}
|
||||
case kIA32Add:
|
||||
if (HasImmediateInput(instr, 1)) {
|
||||
__ add(i.InputOperand(0), i.InputImmediate(1));
|
||||
|
@ -1014,13 +1014,6 @@ void InstructionSelector::VisitFloat64Abs(Node* node) {
|
||||
VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat64Abs, kSSEFloat64Abs);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Log(Node* node) {
|
||||
IA32OperandGenerator g(this);
|
||||
Emit(kIeee754Float64Log, g.DefineSameAsFirst(node),
|
||||
g.UseRegister(node->InputAt(0)))
|
||||
->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat32Sqrt(Node* node) {
|
||||
VisitRO(this, node, kSSEFloat32Sqrt);
|
||||
}
|
||||
@ -1079,6 +1072,13 @@ void InstructionSelector::VisitFloat32Neg(Node* node) { UNREACHABLE(); }
|
||||
|
||||
void InstructionSelector::VisitFloat64Neg(Node* node) { UNREACHABLE(); }
|
||||
|
||||
void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
|
||||
InstructionCode opcode) {
|
||||
IA32OperandGenerator g(this);
|
||||
Emit(opcode, g.DefineSameAsFirst(node), g.UseRegister(node->InputAt(0)))
|
||||
->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitPrepareArguments(
|
||||
ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
|
||||
Node* node) {
|
||||
|
@ -89,7 +89,8 @@ enum class RecordWriteMode { kValueIsMap, kValueIsPointer, kValueIsAny };
|
||||
V(AtomicStoreWord8) \
|
||||
V(AtomicStoreWord16) \
|
||||
V(AtomicStoreWord32) \
|
||||
V(Ieee754Float64Log)
|
||||
V(Ieee754Float64Log) \
|
||||
V(Ieee754Float64Log1p)
|
||||
|
||||
#define ARCH_OPCODE_LIST(V) \
|
||||
COMMON_ARCH_OPCODE_LIST(V) \
|
||||
|
@ -225,6 +225,7 @@ int InstructionScheduler::GetInstructionFlags(const Instruction* instr) const {
|
||||
case kArchDebugBreak:
|
||||
case kArchComment:
|
||||
case kIeee754Float64Log:
|
||||
case kIeee754Float64Log1p:
|
||||
return kNoOpcodeFlags;
|
||||
|
||||
case kArchStackPointer:
|
||||
|
@ -1129,6 +1129,8 @@ void InstructionSelector::VisitNode(Node* node) {
|
||||
return MarkAsFloat64(node), VisitFloat64Abs(node);
|
||||
case IrOpcode::kFloat64Log:
|
||||
return MarkAsFloat64(node), VisitFloat64Log(node);
|
||||
case IrOpcode::kFloat64Log1p:
|
||||
return MarkAsFloat64(node), VisitFloat64Log1p(node);
|
||||
case IrOpcode::kFloat64Sqrt:
|
||||
return MarkAsFloat64(node), VisitFloat64Sqrt(node);
|
||||
case IrOpcode::kFloat64Equal:
|
||||
@ -1234,6 +1236,14 @@ void InstructionSelector::VisitLoadParentFramePointer(Node* node) {
|
||||
Emit(kArchParentFramePointer, g.DefineAsRegister(node));
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Log(Node* node) {
|
||||
VisitFloat64Ieee754Unop(node, kIeee754Float64Log);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Log1p(Node* node) {
|
||||
VisitFloat64Ieee754Unop(node, kIeee754Float64Log1p);
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitTableSwitch(const SwitchInfo& sw,
|
||||
InstructionOperand& index_operand) {
|
||||
OperandGenerator g(this);
|
||||
|
@ -244,6 +244,9 @@ class InstructionSelector final {
|
||||
// Visit the node and generate code, if any.
|
||||
void VisitNode(Node* node);
|
||||
|
||||
// Visit the node and generate code for IEEE 754 functions.
|
||||
void VisitFloat64Ieee754Unop(Node*, InstructionCode code);
|
||||
|
||||
#define DECLARE_GENERATOR(x) void Visit##x(Node* node);
|
||||
MACHINE_OP_LIST(DECLARE_GENERATOR)
|
||||
#undef DECLARE_GENERATOR
|
||||
|
@ -194,6 +194,17 @@ Reduction JSBuiltinReducer::ReduceMathLog(Node* node) {
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.21 Math.log1p ( x )
|
||||
Reduction JSBuiltinReducer::ReduceMathLog1p(Node* node) {
|
||||
JSCallReduction r(node);
|
||||
if (r.InputsMatchOne(Type::Number())) {
|
||||
// Math.log1p(a:number) -> NumberLog1p(a)
|
||||
Node* value = graph()->NewNode(simplified()->NumberLog1p(), r.left());
|
||||
return Replace(value);
|
||||
}
|
||||
return NoChange();
|
||||
}
|
||||
|
||||
// ES6 section 20.2.2.28 Math.round ( x )
|
||||
Reduction JSBuiltinReducer::ReduceMathRound(Node* node) {
|
||||
JSCallReduction r(node);
|
||||
@ -267,6 +278,9 @@ Reduction JSBuiltinReducer::Reduce(Node* node) {
|
||||
case kMathLog:
|
||||
reduction = ReduceMathLog(node);
|
||||
break;
|
||||
case kMathLog1p:
|
||||
reduction = ReduceMathLog1p(node);
|
||||
break;
|
||||
case kMathRound:
|
||||
reduction = ReduceMathRound(node);
|
||||
break;
|
||||
|
@ -38,6 +38,7 @@ class JSBuiltinReducer final : public AdvancedReducer {
|
||||
Reduction ReduceMathFloor(Node* node);
|
||||
Reduction ReduceMathFround(Node* node);
|
||||
Reduction ReduceMathLog(Node* node);
|
||||
Reduction ReduceMathLog1p(Node* node);
|
||||
Reduction ReduceMathRound(Node* node);
|
||||
Reduction ReduceMathSqrt(Node* node);
|
||||
Reduction ReduceMathTrunc(Node* node);
|
||||
|
@ -388,6 +388,11 @@ Reduction MachineOperatorReducer::Reduce(Node* node) {
|
||||
if (m.HasValue()) return ReplaceFloat64(base::ieee754::log(m.Value()));
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kFloat64Log1p: {
|
||||
Float64Matcher m(node->InputAt(0));
|
||||
if (m.HasValue()) return ReplaceFloat64(base::ieee754::log1p(m.Value()));
|
||||
break;
|
||||
}
|
||||
case IrOpcode::kChangeFloat32ToFloat64: {
|
||||
Float32Matcher m(node->InputAt(0));
|
||||
if (m.HasValue()) return ReplaceFloat64(m.Value());
|
||||
|
@ -155,6 +155,7 @@ MachineRepresentation AtomicStoreRepresentationOf(Operator const* op) {
|
||||
V(Float32Sqrt, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float64Abs, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float64Log, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float64Log1p, Operator::kNoProperties, 1, 0, 1) \
|
||||
V(Float64Add, Operator::kCommutative, 2, 0, 1) \
|
||||
V(Float64Sub, Operator::kNoProperties, 2, 0, 1) \
|
||||
V(Float64SubPreserveNan, Operator::kNoProperties, 2, 0, 1) \
|
||||
|
@ -370,6 +370,7 @@ class MachineOperatorBuilder final : public ZoneObject {
|
||||
|
||||
// Floating point logarithm (double-precision).
|
||||
const Operator* Float64Log();
|
||||
const Operator* Float64Log1p();
|
||||
|
||||
// Floating point bit representation.
|
||||
const Operator* Float64ExtractLowWord32();
|
||||
|
@ -485,6 +485,17 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
||||
__ sync(); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_IEEE754_UNOP(name) \
|
||||
do { \
|
||||
FrameScope scope(masm(), StackFrame::MANUAL); \
|
||||
__ PrepareCallCFunction(0, 1, kScratchReg); \
|
||||
__ MovToFloatParameter(i.InputDoubleRegister(0)); \
|
||||
__ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
|
||||
0, 1); \
|
||||
/* Move the result in the double result register. */ \
|
||||
__ MovFromFloatResult(i.OutputDoubleRegister()); \
|
||||
} while (0)
|
||||
|
||||
void CodeGenerator::AssembleDeconstructFrame() {
|
||||
__ mov(sp, fp);
|
||||
__ Pop(ra, fp);
|
||||
@ -718,18 +729,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
Operand(offset.offset()));
|
||||
break;
|
||||
}
|
||||
case kIeee754Float64Log: {
|
||||
// TODO(bmeurer): We should really get rid of this special instruction,
|
||||
// and generate a CallAddress instruction instead.
|
||||
FrameScope scope(masm(), StackFrame::MANUAL);
|
||||
__ PrepareCallCFunction(0, 1, kScratchReg);
|
||||
__ MovToFloatParameter(i.InputDoubleRegister(0));
|
||||
__ CallCFunction(ExternalReference::ieee754_log_function(isolate()), 0,
|
||||
1);
|
||||
// Move the result in the double result register.
|
||||
__ MovFromFloatResult(i.OutputDoubleRegister());
|
||||
case kIeee754Float64Log:
|
||||
ASSEMBLE_IEEE754_UNOP(log);
|
||||
break;
|
||||
case kIeee754Float64Log1p:
|
||||
ASSEMBLE_IEEE754_UNOP(log1p);
|
||||
break;
|
||||
}
|
||||
case kMipsAdd:
|
||||
__ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
|
||||
break;
|
||||
|
@ -876,13 +876,6 @@ void InstructionSelector::VisitFloat64Abs(Node* node) {
|
||||
VisitRR(this, kMipsAbsD, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Log(Node* node) {
|
||||
MipsOperandGenerator g(this);
|
||||
Emit(kIeee754Float64Log, g.DefineAsFixed(node, f0),
|
||||
g.UseFixed(node->InputAt(0), f12))
|
||||
->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat32Sqrt(Node* node) {
|
||||
VisitRR(this, kMipsSqrtS, node);
|
||||
}
|
||||
@ -941,6 +934,13 @@ void InstructionSelector::VisitFloat32Neg(Node* node) { UNREACHABLE(); }
|
||||
|
||||
void InstructionSelector::VisitFloat64Neg(Node* node) { UNREACHABLE(); }
|
||||
|
||||
void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
|
||||
InstructionCode opcode) {
|
||||
MipsOperandGenerator g(this);
|
||||
Emit(opcode, g.DefineAsFixed(node, f0), g.UseFixed(node->InputAt(0), f12))
|
||||
->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitPrepareArguments(
|
||||
ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
|
||||
Node* node) {
|
||||
|
@ -496,6 +496,17 @@ FPUCondition FlagsConditionToConditionCmpFPU(bool& predicate,
|
||||
__ sync(); \
|
||||
} while (0)
|
||||
|
||||
#define ASSEMBLE_IEEE754_UNOP(name) \
|
||||
do { \
|
||||
FrameScope scope(masm(), StackFrame::MANUAL); \
|
||||
__ PrepareCallCFunction(0, 1, kScratchReg); \
|
||||
__ MovToFloatParameter(i.InputDoubleRegister(0)); \
|
||||
__ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
|
||||
0, 1); \
|
||||
/* Move the result in the double result register. */ \
|
||||
__ MovFromFloatResult(i.OutputDoubleRegister()); \
|
||||
} while (0)
|
||||
|
||||
void CodeGenerator::AssembleDeconstructFrame() {
|
||||
__ mov(sp, fp);
|
||||
__ Pop(ra, fp);
|
||||
@ -727,18 +738,12 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
Operand(offset.offset()));
|
||||
break;
|
||||
}
|
||||
case kIeee754Float64Log: {
|
||||
// TODO(bmeurer): We should really get rid of this special instruction,
|
||||
// and generate a CallAddress instruction instead.
|
||||
FrameScope scope(masm(), StackFrame::MANUAL);
|
||||
__ PrepareCallCFunction(0, 1, kScratchReg);
|
||||
__ MovToFloatParameter(i.InputDoubleRegister(0));
|
||||
__ CallCFunction(ExternalReference::ieee754_log_function(isolate()), 0,
|
||||
1);
|
||||
// Move the result in the double result register.
|
||||
__ MovFromFloatResult(i.OutputDoubleRegister());
|
||||
case kIeee754Float64Log:
|
||||
ASSEMBLE_IEEE754_UNOP(log);
|
||||
break;
|
||||
case kIeee754Float64Log1p:
|
||||
ASSEMBLE_IEEE754_UNOP(log1p);
|
||||
break;
|
||||
}
|
||||
case kMips64Add:
|
||||
__ Addu(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
|
||||
break;
|
||||
|
@ -1282,13 +1282,6 @@ void InstructionSelector::VisitFloat64Abs(Node* node) {
|
||||
VisitRR(this, kMips64AbsD, node);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Log(Node* node) {
|
||||
Mips64OperandGenerator g(this);
|
||||
Emit(kIeee754Float64Log, g.DefineAsFixed(node, f0),
|
||||
g.UseFixed(node->InputAt(0), f12))
|
||||
->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat32Sqrt(Node* node) {
|
||||
VisitRR(this, kMips64SqrtS, node);
|
||||
}
|
||||
@ -1347,6 +1340,13 @@ void InstructionSelector::VisitFloat32Neg(Node* node) { UNREACHABLE(); }
|
||||
|
||||
void InstructionSelector::VisitFloat64Neg(Node* node) { UNREACHABLE(); }
|
||||
|
||||
void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
|
||||
InstructionCode opcode) {
|
||||
Mips64OperandGenerator g(this);
|
||||
Emit(opcode, g.DefineAsFixed(node, f0), g.UseFixed(node->InputAt(0), f12))
|
||||
->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitPrepareArguments(
|
||||
ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
|
||||
Node* node) {
|
||||
|
@ -198,6 +198,7 @@
|
||||
V(NumberCeil) \
|
||||
V(NumberFloor) \
|
||||
V(NumberLog) \
|
||||
V(NumberLog1p) \
|
||||
V(NumberRound) \
|
||||
V(NumberTrunc) \
|
||||
V(NumberToInt32) \
|
||||
@ -356,6 +357,7 @@
|
||||
V(Float64Min) \
|
||||
V(Float64Abs) \
|
||||
V(Float64Log) \
|
||||
V(Float64Log1p) \
|
||||
V(Float64Sqrt) \
|
||||
V(Float64RoundDown) \
|
||||
V(Float32RoundUp) \
|
||||
|
@ -461,6 +461,7 @@ class RawMachineAssembler {
|
||||
Node* Float64Abs(Node* a) { return AddNode(machine()->Float64Abs(), a); }
|
||||
Node* Float64Neg(Node* a) { return Float64Sub(Float64Constant(-0.0), a); }
|
||||
Node* Float64Log(Node* a) { return AddNode(machine()->Float64Log(), a); }
|
||||
Node* Float64Log1p(Node* a) { return AddNode(machine()->Float64Log1p(), a); }
|
||||
Node* Float64Sqrt(Node* a) { return AddNode(machine()->Float64Sqrt(), a); }
|
||||
Node* Float64Equal(Node* a, Node* b) {
|
||||
return AddNode(machine()->Float64Equal(), a, b);
|
||||
|
@ -661,6 +661,8 @@ const Operator* RepresentationChanger::Float64OperatorFor(
|
||||
return machine()->Float64LessThanOrEqual();
|
||||
case IrOpcode::kNumberLog:
|
||||
return machine()->Float64Log();
|
||||
case IrOpcode::kNumberLog1p:
|
||||
return machine()->Float64Log1p();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
|
@ -1393,7 +1393,8 @@ class RepresentationSelector {
|
||||
if (lower()) DeferReplacement(node, lowering->Float64Floor(node));
|
||||
return;
|
||||
}
|
||||
case IrOpcode::kNumberLog: {
|
||||
case IrOpcode::kNumberLog:
|
||||
case IrOpcode::kNumberLog1p: {
|
||||
VisitUnop(node, UseInfo::TruncatingFloat64(),
|
||||
MachineRepresentation::kFloat64);
|
||||
if (lower()) NodeProperties::ChangeOp(node, Float64Op(node));
|
||||
|
@ -205,6 +205,7 @@ BinaryOperationHints::Hint BinaryOperationHintOf(const Operator* op) {
|
||||
V(NumberCeil, Operator::kNoProperties, 1) \
|
||||
V(NumberFloor, Operator::kNoProperties, 1) \
|
||||
V(NumberLog, Operator::kNoProperties, 1) \
|
||||
V(NumberLog1p, Operator::kNoProperties, 1) \
|
||||
V(NumberRound, Operator::kNoProperties, 1) \
|
||||
V(NumberTrunc, Operator::kNoProperties, 1) \
|
||||
V(NumberToInt32, Operator::kNoProperties, 1) \
|
||||
|
@ -155,6 +155,7 @@ class SimplifiedOperatorBuilder final : public ZoneObject {
|
||||
const Operator* NumberCeil();
|
||||
const Operator* NumberFloor();
|
||||
const Operator* NumberLog();
|
||||
const Operator* NumberLog1p();
|
||||
const Operator* NumberRound();
|
||||
const Operator* NumberTrunc();
|
||||
const Operator* NumberToInt32();
|
||||
|
@ -1787,6 +1787,8 @@ Type* Typer::Visitor::TypeNumberFloor(Node* node) {
|
||||
|
||||
Type* Typer::Visitor::TypeNumberLog(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeNumberLog1p(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeNumberRound(Node* node) {
|
||||
return TypeUnaryOp(node, NumberRound);
|
||||
}
|
||||
@ -2504,6 +2506,8 @@ Type* Typer::Visitor::TypeFloat64Abs(Node* node) {
|
||||
|
||||
Type* Typer::Visitor::TypeFloat64Log(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeFloat64Log1p(Node* node) { return Type::Number(); }
|
||||
|
||||
Type* Typer::Visitor::TypeFloat64Sqrt(Node* node) { return Type::Number(); }
|
||||
|
||||
|
||||
|
@ -741,6 +741,7 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
case IrOpcode::kNumberCeil:
|
||||
case IrOpcode::kNumberFloor:
|
||||
case IrOpcode::kNumberLog:
|
||||
case IrOpcode::kNumberLog1p:
|
||||
case IrOpcode::kNumberRound:
|
||||
case IrOpcode::kNumberTrunc:
|
||||
// Number -> Number
|
||||
@ -1038,6 +1039,7 @@ void Verifier::Visitor::Check(Node* node) {
|
||||
case IrOpcode::kFloat64Min:
|
||||
case IrOpcode::kFloat64Abs:
|
||||
case IrOpcode::kFloat64Log:
|
||||
case IrOpcode::kFloat64Log1p:
|
||||
case IrOpcode::kFloat64Sqrt:
|
||||
case IrOpcode::kFloat32RoundDown:
|
||||
case IrOpcode::kFloat64RoundDown:
|
||||
|
@ -594,6 +594,13 @@ class OutOfLineRecordWrite final : public OutOfLineCode {
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
#define ASSEMBLE_IEEE754_UNOP(name) \
|
||||
do { \
|
||||
__ PrepareCallCFunction(1); \
|
||||
__ CallCFunction(ExternalReference::ieee754_##name##_function(isolate()), \
|
||||
1); \
|
||||
} while (false)
|
||||
|
||||
void CodeGenerator::AssembleDeconstructFrame() {
|
||||
__ movq(rsp, rbp);
|
||||
__ popq(rbp);
|
||||
@ -841,8 +848,10 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
|
||||
break;
|
||||
}
|
||||
case kIeee754Float64Log:
|
||||
__ PrepareCallCFunction(1);
|
||||
__ CallCFunction(ExternalReference::ieee754_log_function(isolate()), 1);
|
||||
ASSEMBLE_IEEE754_UNOP(log);
|
||||
break;
|
||||
case kIeee754Float64Log1p:
|
||||
ASSEMBLE_IEEE754_UNOP(log1p);
|
||||
break;
|
||||
case kX64Add32:
|
||||
ASSEMBLE_BINOP(addl);
|
||||
|
@ -1355,13 +1355,6 @@ void InstructionSelector::VisitFloat64Abs(Node* node) {
|
||||
VisitFloatUnop(this, node, node->InputAt(0), kAVXFloat64Abs, kSSEFloat64Abs);
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Log(Node* node) {
|
||||
X64OperandGenerator g(this);
|
||||
Emit(kIeee754Float64Log, g.DefineAsFixed(node, xmm0),
|
||||
g.UseFixed(node->InputAt(0), xmm0))
|
||||
->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::VisitFloat64Sqrt(Node* node) {
|
||||
VisitRO(this, node, kSSEFloat64Sqrt);
|
||||
}
|
||||
@ -1415,6 +1408,13 @@ void InstructionSelector::VisitFloat32Neg(Node* node) { UNREACHABLE(); }
|
||||
|
||||
void InstructionSelector::VisitFloat64Neg(Node* node) { UNREACHABLE(); }
|
||||
|
||||
void InstructionSelector::VisitFloat64Ieee754Unop(Node* node,
|
||||
InstructionCode opcode) {
|
||||
X64OperandGenerator g(this);
|
||||
Emit(opcode, g.DefineAsFixed(node, xmm0), g.UseFixed(node->InputAt(0), xmm0))
|
||||
->MarkAsCall();
|
||||
}
|
||||
|
||||
void InstructionSelector::EmitPrepareArguments(
|
||||
ZoneVector<PushParameter>* arguments, const CallDescriptor* descriptor,
|
||||
Node* node) {
|
||||
|
@ -69,6 +69,8 @@ ExternalReferenceTable::ExternalReferenceTable(Isolate* isolate) {
|
||||
"power_double_int_function");
|
||||
Add(ExternalReference::ieee754_log_function(isolate).address(),
|
||||
"base::ieee754::log");
|
||||
Add(ExternalReference::ieee754_log1p_function(isolate).address(),
|
||||
"base::ieee754::log1p");
|
||||
Add(ExternalReference::store_buffer_top(isolate).address(),
|
||||
"store_buffer_top");
|
||||
Add(ExternalReference::address_of_the_hole_nan().address(), "the_hole_nan");
|
||||
|
@ -6587,6 +6587,7 @@ class Script: public Struct {
|
||||
V(Math, ceil, MathCeil) \
|
||||
V(Math, abs, MathAbs) \
|
||||
V(Math, log, MathLog) \
|
||||
V(Math, log1p, MathLog1p) \
|
||||
V(Math, exp, MathExp) \
|
||||
V(Math, sqrt, MathSqrt) \
|
||||
V(Math, pow, MathPow) \
|
||||
|
@ -114,7 +114,7 @@ class CodeEntry {
|
||||
|
||||
private:
|
||||
class TagField : public BitField<Logger::LogEventsAndTags, 0, 8> {};
|
||||
class BuiltinIdField : public BitField<Builtins::Name, 8, 8> {};
|
||||
class BuiltinIdField : public BitField<Builtins::Name, 8, 24> {};
|
||||
|
||||
uint32_t bit_field_;
|
||||
const char* name_prefix_;
|
||||
|
159
src/third_party/fdlibm/fdlibm.js
vendored
159
src/third_party/fdlibm/fdlibm.js
vendored
@ -397,170 +397,12 @@ function MathTan(x) {
|
||||
return KernelTan(y0, y1, (n & 1) ? -1 : 1);
|
||||
}
|
||||
|
||||
// ES6 draft 09-27-13, section 20.2.2.20.
|
||||
// Math.log1p
|
||||
//
|
||||
// Method :
|
||||
// 1. Argument Reduction: find k and f such that
|
||||
// 1+x = 2^k * (1+f),
|
||||
// where sqrt(2)/2 < 1+f < sqrt(2) .
|
||||
//
|
||||
// Note. If k=0, then f=x is exact. However, if k!=0, then f
|
||||
// may not be representable exactly. In that case, a correction
|
||||
// term is need. Let u=1+x rounded. Let c = (1+x)-u, then
|
||||
// log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
|
||||
// and add back the correction term c/u.
|
||||
// (Note: when x > 2**53, one can simply return log(x))
|
||||
//
|
||||
// 2. Approximation of log1p(f).
|
||||
// Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
|
||||
// = 2s + 2/3 s**3 + 2/5 s**5 + .....,
|
||||
// = 2s + s*R
|
||||
// We use a special Reme algorithm on [0,0.1716] to generate
|
||||
// a polynomial of degree 14 to approximate R The maximum error
|
||||
// of this polynomial approximation is bounded by 2**-58.45. In
|
||||
// other words,
|
||||
// 2 4 6 8 10 12 14
|
||||
// R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s +Lp6*s +Lp7*s
|
||||
// (the values of Lp1 to Lp7 are listed in the program)
|
||||
// and
|
||||
// | 2 14 | -58.45
|
||||
// | Lp1*s +...+Lp7*s - R(z) | <= 2
|
||||
// | |
|
||||
// Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
|
||||
// In order to guarantee error in log below 1ulp, we compute log
|
||||
// by
|
||||
// log1p(f) = f - (hfsq - s*(hfsq+R)).
|
||||
//
|
||||
// 3. Finally, log1p(x) = k*ln2 + log1p(f).
|
||||
// = k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
|
||||
// Here ln2 is split into two floating point number:
|
||||
// ln2_hi + ln2_lo,
|
||||
// where n*ln2_hi is always exact for |n| < 2000.
|
||||
//
|
||||
// Special cases:
|
||||
// log1p(x) is NaN with signal if x < -1 (including -INF) ;
|
||||
// log1p(+INF) is +INF; log1p(-1) is -INF with signal;
|
||||
// log1p(NaN) is that NaN with no signal.
|
||||
//
|
||||
// Accuracy:
|
||||
// according to an error analysis, the error is always less than
|
||||
// 1 ulp (unit in the last place).
|
||||
//
|
||||
// Constants:
|
||||
// Constants are found in fdlibm.cc. We assume the C++ compiler to convert
|
||||
// from decimal to binary accurately enough to produce the intended values.
|
||||
//
|
||||
// Note: Assuming log() return accurate answer, the following
|
||||
// algorithm can be used to compute log1p(x) to within a few ULP:
|
||||
//
|
||||
// u = 1+x;
|
||||
// if (u==1.0) return x ; else
|
||||
// return log(u)*(x/(u-1.0));
|
||||
//
|
||||
// See HP-15C Advanced Functions Handbook, p.193.
|
||||
//
|
||||
define LN2_HI = 6.93147180369123816490e-01;
|
||||
define LN2_LO = 1.90821492927058770002e-10;
|
||||
define TWO_THIRD = 6.666666666666666666e-01;
|
||||
define LP1 = 6.666666666666735130e-01;
|
||||
define LP2 = 3.999999999940941908e-01;
|
||||
define LP3 = 2.857142874366239149e-01;
|
||||
define LP4 = 2.222219843214978396e-01;
|
||||
define LP5 = 1.818357216161805012e-01;
|
||||
define LP6 = 1.531383769920937332e-01;
|
||||
define LP7 = 1.479819860511658591e-01;
|
||||
|
||||
// 2^54
|
||||
define TWO54 = 18014398509481984;
|
||||
|
||||
function MathLog1p(x) {
|
||||
x = x * 1; // Convert to number.
|
||||
var hx = %_DoubleHi(x);
|
||||
var ax = hx & 0x7fffffff;
|
||||
var k = 1;
|
||||
var f = x;
|
||||
var hu = 1;
|
||||
var c = 0;
|
||||
var u = x;
|
||||
|
||||
if (hx < 0x3fda827a) {
|
||||
// x < 0.41422
|
||||
if (ax >= 0x3ff00000) { // |x| >= 1
|
||||
if (x === -1) {
|
||||
return -INFINITY; // log1p(-1) = -inf
|
||||
} else {
|
||||
return NaN; // log1p(x<-1) = NaN
|
||||
}
|
||||
} else if (ax < 0x3c900000) {
|
||||
// For |x| < 2^-54 we can return x.
|
||||
return x;
|
||||
} else if (ax < 0x3e200000) {
|
||||
// For |x| < 2^-29 we can use a simple two-term Taylor series.
|
||||
return x - x * x * 0.5;
|
||||
}
|
||||
|
||||
if ((hx > 0) || (hx <= -0x402D413D)) { // (int) 0xbfd2bec3 = -0x402d413d
|
||||
// -.2929 < x < 0.41422
|
||||
k = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Infinity and NaN
|
||||
if (hx >= 0x7ff00000) return x;
|
||||
|
||||
if (k !== 0) {
|
||||
if (hx < 0x43400000) {
|
||||
// x < 2^53
|
||||
u = 1 + x;
|
||||
hu = %_DoubleHi(u);
|
||||
k = (hu >> 20) - 1023;
|
||||
c = (k > 0) ? 1 - (u - x) : x - (u - 1);
|
||||
c = c / u;
|
||||
} else {
|
||||
hu = %_DoubleHi(u);
|
||||
k = (hu >> 20) - 1023;
|
||||
}
|
||||
hu = hu & 0xfffff;
|
||||
if (hu < 0x6a09e) {
|
||||
u = %_ConstructDouble(hu | 0x3ff00000, %_DoubleLo(u)); // Normalize u.
|
||||
} else {
|
||||
++k;
|
||||
u = %_ConstructDouble(hu | 0x3fe00000, %_DoubleLo(u)); // Normalize u/2.
|
||||
hu = (0x00100000 - hu) >> 2;
|
||||
}
|
||||
f = u - 1;
|
||||
}
|
||||
|
||||
var hfsq = 0.5 * f * f;
|
||||
if (hu === 0) {
|
||||
// |f| < 2^-20;
|
||||
if (f === 0) {
|
||||
if (k === 0) {
|
||||
return 0.0;
|
||||
} else {
|
||||
return k * LN2_HI + (c + k * LN2_LO);
|
||||
}
|
||||
}
|
||||
var R = hfsq * (1 - TWO_THIRD * f);
|
||||
if (k === 0) {
|
||||
return f - R;
|
||||
} else {
|
||||
return k * LN2_HI - ((R - (k * LN2_LO + c)) - f);
|
||||
}
|
||||
}
|
||||
|
||||
var s = f / (2 + f);
|
||||
var z = s * s;
|
||||
var R = z * (LP1 + z * (LP2 + z * (LP3 + z * (LP4 +
|
||||
z * (LP5 + z * (LP6 + z * LP7))))));
|
||||
if (k === 0) {
|
||||
return f - (hfsq - s * (hfsq + R));
|
||||
} else {
|
||||
return k * LN2_HI - ((hfsq - (s * (hfsq + R) + (k * LN2_LO + c))) - f);
|
||||
}
|
||||
}
|
||||
|
||||
// ES6 draft 09-27-13, section 20.2.2.14.
|
||||
// Math.expm1
|
||||
// Returns exp(x)-1, the exponential of x minus 1.
|
||||
@ -1107,7 +949,6 @@ utils.InstallFunctions(GlobalMath, DONT_ENUM, [
|
||||
"tanh", MathTanh,
|
||||
"log10", MathLog10,
|
||||
"log2", MathLog2,
|
||||
"log1p", MathLog1p,
|
||||
"expm1", MathExpm1
|
||||
]);
|
||||
|
||||
|
@ -5511,6 +5511,20 @@ TEST(RunFloat64Log) {
|
||||
FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(ieee754::log(*i), m.Call(*i)); }
|
||||
}
|
||||
|
||||
TEST(RunFloat64Log1p) {
|
||||
BufferedRawMachineAssemblerTester<double> m(MachineType::Float64());
|
||||
m.Return(m.Float64Log1p(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(std::isnan(m.Call(-std::numeric_limits<double>::infinity())));
|
||||
CHECK_DOUBLE_EQ(-std::numeric_limits<double>::infinity(), m.Call(-1.0));
|
||||
CHECK_DOUBLE_EQ(0.0, m.Call(0.0));
|
||||
CHECK_DOUBLE_EQ(-0.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::log1p(*i), m.Call(*i)); }
|
||||
}
|
||||
|
||||
static double two_30 = 1 << 30; // 2^30 is a smi boundary.
|
||||
static double two_52 = two_30 * (1 << 22); // 2^52 is a precision boundary.
|
||||
static double kValues[] = {0.1,
|
||||
|
@ -200,6 +200,9 @@ class ValueHelper {
|
||||
0.375,
|
||||
0.5,
|
||||
1.0,
|
||||
1.17549e-38,
|
||||
1.56657e-37,
|
||||
1.0000001,
|
||||
1.25,
|
||||
2,
|
||||
3.1e7,
|
||||
|
57
test/unittests/base/ieee754-unittest.cc
Normal file
57
test/unittests/base/ieee754-unittest.cc
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright 2016 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "src/base/ieee754.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "testing/gmock-support.h"
|
||||
#include "testing/gtest-support.h"
|
||||
|
||||
using testing::IsNaN;
|
||||
|
||||
namespace v8 {
|
||||
namespace base {
|
||||
namespace ieee754 {
|
||||
|
||||
TEST(Ieee754, Log) {
|
||||
EXPECT_THAT(log(std::numeric_limits<double>::quiet_NaN()), IsNaN());
|
||||
EXPECT_THAT(log(std::numeric_limits<double>::signaling_NaN()), IsNaN());
|
||||
EXPECT_THAT(log(-std::numeric_limits<double>::infinity()), IsNaN());
|
||||
EXPECT_THAT(log(-1.0), IsNaN());
|
||||
EXPECT_EQ(-std::numeric_limits<double>::infinity(), log(-0.0));
|
||||
EXPECT_EQ(-std::numeric_limits<double>::infinity(), log(0.0));
|
||||
EXPECT_EQ(0.0, log(1.0));
|
||||
EXPECT_EQ(std::numeric_limits<double>::infinity(),
|
||||
log(std::numeric_limits<double>::infinity()));
|
||||
}
|
||||
|
||||
TEST(Ieee754, Log1p) {
|
||||
EXPECT_THAT(log1p(std::numeric_limits<double>::quiet_NaN()), IsNaN());
|
||||
EXPECT_THAT(log1p(std::numeric_limits<double>::signaling_NaN()), IsNaN());
|
||||
EXPECT_THAT(log1p(-std::numeric_limits<double>::infinity()), IsNaN());
|
||||
EXPECT_EQ(-std::numeric_limits<double>::infinity(), log1p(-1.0));
|
||||
EXPECT_EQ(0.0, log1p(0.0));
|
||||
EXPECT_EQ(-0.0, log1p(-0.0));
|
||||
EXPECT_EQ(std::numeric_limits<double>::infinity(),
|
||||
log1p(std::numeric_limits<double>::infinity()));
|
||||
EXPECT_EQ(6.9756137364252422e-03, log1p(0.007));
|
||||
EXPECT_EQ(709.782712893384, log1p(1.7976931348623157e308));
|
||||
EXPECT_EQ(2.7755575615628914e-17, log1p(2.7755575615628914e-17));
|
||||
EXPECT_EQ(9.313225741817976e-10, log1p(9.313225746154785e-10));
|
||||
EXPECT_EQ(-0.2876820724517809, log1p(-0.25));
|
||||
EXPECT_EQ(0.22314355131420976, log1p(0.25));
|
||||
EXPECT_EQ(2.3978952727983707, log1p(10));
|
||||
EXPECT_EQ(36.841361487904734, log1p(10e15));
|
||||
EXPECT_EQ(37.08337388996168, log1p(12738099905822720));
|
||||
EXPECT_EQ(37.08336444902049, log1p(12737979646738432));
|
||||
EXPECT_EQ(1.3862943611198906, log1p(3));
|
||||
EXPECT_EQ(1.3862945995384413, log1p(3 + 9.5367431640625e-7));
|
||||
EXPECT_EQ(0.5596157879354227, log1p(0.75));
|
||||
EXPECT_EQ(0.8109302162163288, log1p(1.25));
|
||||
}
|
||||
|
||||
} // namespace ieee754
|
||||
} // namespace base
|
||||
} // namespace v8
|
@ -202,6 +202,50 @@ TEST_F(JSBuiltinReducerTest, MathFround) {
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Math.log
|
||||
|
||||
TEST_F(JSBuiltinReducerTest, MathLog) {
|
||||
Node* function = MathFunction("log");
|
||||
|
||||
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(), IsNumberLog(p0));
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Math.log1p
|
||||
|
||||
TEST_F(JSBuiltinReducerTest, MathLog1p) {
|
||||
Node* function = MathFunction("log1p");
|
||||
|
||||
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(), IsNumberLog1p(p0));
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// String.fromCharCode
|
||||
|
||||
|
@ -1413,6 +1413,20 @@ TEST_F(MachineOperatorReducerTest, Float64LogWithConstant) {
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Float64Log1p
|
||||
|
||||
TEST_F(MachineOperatorReducerTest, Float64Log1pWithConstant) {
|
||||
TRACED_FOREACH(double, x, kFloat64Values) {
|
||||
Reduction const r =
|
||||
Reduce(graph()->NewNode(machine()->Float64Log1p(), Float64Constant(x)));
|
||||
ASSERT_TRUE(r.Changed());
|
||||
EXPECT_THAT(
|
||||
r.replacement(),
|
||||
IsFloat64Constant(NanSensitiveDoubleEq(base::ieee754::log1p(x))));
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Float64InsertLowWord32
|
||||
|
||||
|
@ -2309,6 +2309,8 @@ IS_UNOP_MATCHER(Float64RoundTruncate)
|
||||
IS_UNOP_MATCHER(Float64RoundTiesAway)
|
||||
IS_UNOP_MATCHER(Float64ExtractLowWord32)
|
||||
IS_UNOP_MATCHER(Float64ExtractHighWord32)
|
||||
IS_UNOP_MATCHER(NumberLog)
|
||||
IS_UNOP_MATCHER(NumberLog1p)
|
||||
IS_UNOP_MATCHER(NumberToInt32)
|
||||
IS_UNOP_MATCHER(NumberToUint32)
|
||||
IS_UNOP_MATCHER(PlainPrimitiveToNumber)
|
||||
|
@ -224,6 +224,8 @@ Matcher<Node*> IsNumberShiftRightLogical(const Matcher<Node*>& lhs_matcher,
|
||||
const Matcher<Node*>& rhs_matcher);
|
||||
Matcher<Node*> IsNumberImul(const Matcher<Node*>& lhs_matcher,
|
||||
const Matcher<Node*>& rhs_matcher);
|
||||
Matcher<Node*> IsNumberLog(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsNumberLog1p(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsStringFromCharCode(const Matcher<Node*>& value_matcher);
|
||||
Matcher<Node*> IsAllocate(const Matcher<Node*>& size_matcher,
|
||||
const Matcher<Node*>& effect_matcher,
|
||||
|
@ -31,6 +31,7 @@
|
||||
'base/division-by-constant-unittest.cc',
|
||||
'base/flags-unittest.cc',
|
||||
'base/functional-unittest.cc',
|
||||
'base/ieee754-unittest.cc',
|
||||
'base/logging-unittest.cc',
|
||||
'base/iterator-unittest.cc',
|
||||
'base/platform/condition-variable-unittest.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user