From ef680d1b0105892be643ab8762f315bfe9af2709 Mon Sep 17 00:00:00 2001 From: Scott Violet Date: Wed, 14 Dec 2022 19:16:16 -0800 Subject: [PATCH] Adds flag for which sin/cos implementation to use My plan is to add a finch flag to the chrome side. It'll be a kill switch, but given the history with changing the implementation, I want to make sure we have the ability to switch back. Bug=v8:13477 Change-Id: I1559e10d134bd78699b1119be26934570c6e5241 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4108811 Reviewed-by: Toon Verwaest Commit-Queue: Scott Violet Cr-Commit-Position: refs/heads/main@{#84874} --- src/base/ieee754.cc | 26 +- src/base/ieee754.h | 33 ++- src/builtins/builtins.h | 13 + src/codegen/external-reference.cc | 30 ++- src/compiler/machine-operator-reducer.cc | 5 +- .../turboshaft/machine-optimization-reducer.h | 9 +- src/flags/flag-definitions.h | 4 + test/cctest/compiler/test-run-machops.cc | 5 +- test/unittests/base/ieee754-unittest.cc | 245 +++++++++++++++--- .../machine-operator-reducer-unittest.cc | 5 +- 10 files changed, 290 insertions(+), 85 deletions(-) diff --git a/src/base/ieee754.cc b/src/base/ieee754.cc index f03044611a..e71b63fd7c 100644 --- a/src/base/ieee754.cc +++ b/src/base/ieee754.cc @@ -107,10 +107,8 @@ namespace { int32_t __ieee754_rem_pio2(double x, double* y) V8_WARN_UNUSED_RESULT; int __kernel_rem_pio2(double* x, double* y, int e0, int nx, int prec, const int32_t* ipio2) V8_WARN_UNUSED_RESULT; -#if !defined(V8_USE_LIBM_TRIG_FUNCTIONS) double __kernel_cos(double x, double y) V8_WARN_UNUSED_RESULT; double __kernel_sin(double x, double y, int iy) V8_WARN_UNUSED_RESULT; -#endif /* __ieee754_rem_pio2(x,y) * @@ -271,7 +269,6 @@ int32_t __ieee754_rem_pio2(double x, double *y) { return n; } -#if !defined(V8_USE_LIBM_TRIG_FUNCTIONS) /* __kernel_cos( x, y ) * kernel cos function on [-pi/4, pi/4], pi/4 ~ 0.785398164 * Input x is assumed to be bounded by ~pi/4 in magnitude. @@ -337,7 +334,6 @@ V8_INLINE double __kernel_cos(double x, double y) { return a - (iz - (z * r - x * y)); } } -#endif /* __kernel_rem_pio2(x,y,e0,nx,prec,ipio2) * double x[],y[]; int e0,nx,prec; int ipio2[]; @@ -647,7 +643,6 @@ recompute: return n & 7; } -#if !defined(V8_USE_LIBM_TRIG_FUNCTIONS) /* __kernel_sin( x, y, iy) * kernel sin function on [-pi/4, pi/4], pi/4 ~ 0.7854 * Input x is assumed to be bounded by ~pi/4 in magnitude. @@ -701,7 +696,6 @@ V8_INLINE double __kernel_sin(double x, double y, int iy) { return x - ((z * (half * y - v * r) - y) - v * S1); } } -#endif /* __kernel_tan( x, y, k ) * kernel tan function on [-pi/4, pi/4], pi/4 ~ 0.7854 @@ -1324,7 +1318,6 @@ double atan2(double y, double x) { } } -#if !defined(V8_USE_LIBM_TRIG_FUNCTIONS) /* cos(x) * Return cosine function of x. * @@ -1355,7 +1348,11 @@ double atan2(double y, double x) { * Accuracy: * TRIG(x) returns trig(x) nearly rounded */ +#if defined(V8_USE_LIBM_TRIG_FUNCTIONS) +double fdlibm_cos(double x) { +#else double cos(double x) { +#endif double y[2], z = 0.0; int32_t n, ix; @@ -1384,7 +1381,6 @@ double cos(double x) { } } } -#endif /* exp(x) * Returns the exponential of x. @@ -2418,7 +2414,6 @@ double cbrt(double x) { return (t); } -#if !defined(V8_USE_LIBM_TRIG_FUNCTIONS) /* sin(x) * Return sine function of x. * @@ -2449,7 +2444,11 @@ double cbrt(double x) { * Accuracy: * TRIG(x) returns trig(x) nearly rounded */ +#if defined(V8_USE_LIBM_TRIG_FUNCTIONS) +double fdlibm_sin(double x) { +#else double sin(double x) { +#endif double y[2], z = 0.0; int32_t n, ix; @@ -2478,7 +2477,6 @@ double sin(double x) { } } } -#endif /* tan(x) * Return tangent function of x. @@ -3026,12 +3024,8 @@ double tanh(double x) { #undef SET_LOW_WORD #if defined(V8_USE_LIBM_TRIG_FUNCTIONS) && defined(BUILDING_V8_BASE_SHARED) -double sin(double x) { - return glibc_sin(x); -} -double cos(double x) { - return glibc_cos(x); -} +double libm_sin(double x) { return glibc_sin(x); } +double libm_cos(double x) { return glibc_cos(x); } #endif } // namespace ieee754 diff --git a/src/base/ieee754.h b/src/base/ieee754.h index 53417179e6..953b5b00e6 100644 --- a/src/base/ieee754.h +++ b/src/base/ieee754.h @@ -37,15 +37,23 @@ V8_BASE_EXPORT double atan(double x); // the two arguments to determine the quadrant of the result. V8_BASE_EXPORT double atan2(double y, double x); -// Returns the cosine of |x|, where |x| is given in radians. -#if defined(V8_USE_LIBM_TRIG_FUNCTIONS) && \ - !defined(BUILDING_V8_BASE_SHARED) && \ - !defined(USING_V8_BASE_SHARED) -inline double cos(double x) { - return glibc_cos(x); -} +#if defined(V8_USE_LIBM_TRIG_FUNCTIONS) +// To ensure there aren't problems with libm's sin/cos, both implementations +// are shipped. The plan is to transition to libm once we ensure there are no +// compatibility or performance issues. +V8_BASE_EXPORT double fdlibm_sin(double x); +V8_BASE_EXPORT double fdlibm_cos(double x); + +#if !defined(BUILDING_V8_BASE_SHARED) && !defined(USING_V8_BASE_SHARED) +inline double libm_sin(double x) { return glibc_sin(x); } +inline double libm_cos(double x) { return glibc_cos(x); } +#else +V8_BASE_EXPORT double libm_sin(double x); +V8_BASE_EXPORT double libm_cos(double x); +#endif #else V8_BASE_EXPORT double cos(double x); +V8_BASE_EXPORT double sin(double x); #endif // Returns the base-e exponential of |x|. @@ -80,17 +88,6 @@ V8_BASE_EXPORT double expm1(double x); // behaviour is preserved for compatibility reasons. V8_BASE_EXPORT double pow(double x, double y); -#if defined(V8_USE_LIBM_TRIG_FUNCTIONS) && \ - !defined(BUILDING_V8_BASE_SHARED) && \ - !defined(USING_V8_BASE_SHARED) -inline double sin(double x) { - return glibc_sin(x); -} -#else -// Returns the sine of |x|, where |x| is given in radians. -V8_BASE_EXPORT double sin(double x); -#endif - // Returns the tangent of |x|, where |x| is given in radians. V8_BASE_EXPORT double tan(double x); diff --git a/src/builtins/builtins.h b/src/builtins/builtins.h index c3935b53d0..8924c36f5a 100644 --- a/src/builtins/builtins.h +++ b/src/builtins/builtins.h @@ -359,4 +359,17 @@ Builtin ExampleBuiltinForTorqueFunctionPointerType( } // namespace internal } // namespace v8 +// Helper while transitioning some functions to libm. +#if defined(V8_USE_LIBM_TRIG_FUNCTIONS) +#define SIN_IMPL(X) \ + v8_flags.use_libm_trig_functions ? base::ieee754::libm_sin(X) \ + : base::ieee754::fdlibm_sin(X) +#define COS_IMPL(X) \ + v8_flags.use_libm_trig_functions ? base::ieee754::libm_cos(X) \ + : base::ieee754::fdlibm_cos(X) +#else +#define SIN_IMPL(X) base::ieee754::sin(X) +#define COS_IMPL(X) base::ieee754::cos(X) +#endif + #endif // V8_BUILTINS_BUILTINS_H_ diff --git a/src/codegen/external-reference.cc b/src/codegen/external-reference.cc index 1addb60219..820cae92ca 100644 --- a/src/codegen/external-reference.cc +++ b/src/codegen/external-reference.cc @@ -880,8 +880,6 @@ FUNCTION_REFERENCE_WITH_TYPE(ieee754_atan2_function, base::ieee754::atan2, BUILTIN_FP_FP_CALL) FUNCTION_REFERENCE_WITH_TYPE(ieee754_cbrt_function, base::ieee754::cbrt, BUILTIN_FP_CALL) -FUNCTION_REFERENCE_WITH_TYPE(ieee754_cos_function, base::ieee754::cos, - BUILTIN_FP_CALL) FUNCTION_REFERENCE_WITH_TYPE(ieee754_cosh_function, base::ieee754::cosh, BUILTIN_FP_CALL) FUNCTION_REFERENCE_WITH_TYPE(ieee754_exp_function, base::ieee754::exp, @@ -896,8 +894,6 @@ FUNCTION_REFERENCE_WITH_TYPE(ieee754_log10_function, base::ieee754::log10, BUILTIN_FP_CALL) FUNCTION_REFERENCE_WITH_TYPE(ieee754_log2_function, base::ieee754::log2, BUILTIN_FP_CALL) -FUNCTION_REFERENCE_WITH_TYPE(ieee754_sin_function, base::ieee754::sin, - BUILTIN_FP_CALL) FUNCTION_REFERENCE_WITH_TYPE(ieee754_sinh_function, base::ieee754::sinh, BUILTIN_FP_CALL) FUNCTION_REFERENCE_WITH_TYPE(ieee754_tan_function, base::ieee754::tan, @@ -907,6 +903,32 @@ FUNCTION_REFERENCE_WITH_TYPE(ieee754_tanh_function, base::ieee754::tanh, FUNCTION_REFERENCE_WITH_TYPE(ieee754_pow_function, base::ieee754::pow, BUILTIN_FP_FP_CALL) +#if defined(V8_USE_LIBM_TRIG_FUNCTIONS) +ExternalReference ExternalReference::ieee754_sin_function() { + static_assert( + IsValidExternalReferenceType::value); + static_assert(IsValidExternalReferenceType< + decltype(&base::ieee754::fdlibm_sin)>::value); + auto* f = v8_flags.use_libm_trig_functions ? base::ieee754::libm_sin + : base::ieee754::fdlibm_sin; + return ExternalReference(Redirect(FUNCTION_ADDR(f), BUILTIN_FP_CALL)); +} +ExternalReference ExternalReference::ieee754_cos_function() { + static_assert( + IsValidExternalReferenceType::value); + static_assert(IsValidExternalReferenceType< + decltype(&base::ieee754::fdlibm_cos)>::value); + auto* f = v8_flags.use_libm_trig_functions ? base::ieee754::libm_cos + : base::ieee754::fdlibm_cos; + return ExternalReference(Redirect(FUNCTION_ADDR(f), BUILTIN_FP_CALL)); +} +#else +FUNCTION_REFERENCE_WITH_TYPE(ieee754_sin_function, base::ieee754::sin, + BUILTIN_FP_CALL) +FUNCTION_REFERENCE_WITH_TYPE(ieee754_cos_function, base::ieee754::cos, + BUILTIN_FP_CALL) +#endif + void* libc_memchr(void* string, int character, size_t search_length) { return memchr(string, character, search_length); } diff --git a/src/compiler/machine-operator-reducer.cc b/src/compiler/machine-operator-reducer.cc index 721ed086d1..2c3a6d1c09 100644 --- a/src/compiler/machine-operator-reducer.cc +++ b/src/compiler/machine-operator-reducer.cc @@ -12,6 +12,7 @@ #include "src/base/ieee754.h" #include "src/base/logging.h" #include "src/base/overflowing-math.h" +#include "src/builtins/builtins.h" #include "src/compiler/diamond.h" #include "src/compiler/graph.h" #include "src/compiler/js-operator.h" @@ -771,7 +772,7 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { case IrOpcode::kFloat64Cos: { Float64Matcher m(node->InputAt(0)); if (m.HasResolvedValue()) - return ReplaceFloat64(base::ieee754::cos(m.ResolvedValue())); + return ReplaceFloat64(COS_IMPL(m.ResolvedValue())); break; } case IrOpcode::kFloat64Cosh: { @@ -836,7 +837,7 @@ Reduction MachineOperatorReducer::Reduce(Node* node) { case IrOpcode::kFloat64Sin: { Float64Matcher m(node->InputAt(0)); if (m.HasResolvedValue()) - return ReplaceFloat64(base::ieee754::sin(m.ResolvedValue())); + return ReplaceFloat64(SIN_IMPL(m.ResolvedValue())); break; } case IrOpcode::kFloat64Sinh: { diff --git a/src/compiler/turboshaft/machine-optimization-reducer.h b/src/compiler/turboshaft/machine-optimization-reducer.h index 72cd13ef1b..03817c5a2f 100644 --- a/src/compiler/turboshaft/machine-optimization-reducer.h +++ b/src/compiler/turboshaft/machine-optimization-reducer.h @@ -20,6 +20,7 @@ #include "src/base/overflowing-math.h" #include "src/base/template-utils.h" #include "src/base/vector.h" +#include "src/builtins/builtins.h" #include "src/codegen/machine-type.h" #include "src/compiler/backend/instruction.h" #include "src/compiler/machine-operator-reducer.h" @@ -250,9 +251,9 @@ class MachineOptimizationReducer : public Next { case FloatUnaryOp::Kind::kExpm1: return Asm().Float32Constant(base::ieee754::expm1(k)); case FloatUnaryOp::Kind::kSin: - return Asm().Float32Constant(base::ieee754::sin(k)); + return Asm().Float32Constant(SIN_IMPL(k)); case FloatUnaryOp::Kind::kCos: - return Asm().Float32Constant(base::ieee754::cos(k)); + return Asm().Float32Constant(COS_IMPL(k)); case FloatUnaryOp::Kind::kSinh: return Asm().Float32Constant(base::ieee754::sinh(k)); case FloatUnaryOp::Kind::kCosh: @@ -314,9 +315,9 @@ class MachineOptimizationReducer : public Next { case FloatUnaryOp::Kind::kExpm1: return Asm().Float64Constant(base::ieee754::expm1(k)); case FloatUnaryOp::Kind::kSin: - return Asm().Float64Constant(base::ieee754::sin(k)); + return Asm().Float64Constant(SIN_IMPL(k)); case FloatUnaryOp::Kind::kCos: - return Asm().Float64Constant(base::ieee754::cos(k)); + return Asm().Float64Constant(COS_IMPL(k)); case FloatUnaryOp::Kind::kSinh: return Asm().Float64Constant(base::ieee754::sinh(k)); case FloatUnaryOp::Kind::kCosh: diff --git a/src/flags/flag-definitions.h b/src/flags/flag-definitions.h index 350540516a..927743d311 100644 --- a/src/flags/flag-definitions.h +++ b/src/flags/flag-definitions.h @@ -2394,6 +2394,10 @@ DEFINE_IMPLICATION(verify_predictable, predictable) DEFINE_INT(dump_allocations_digest_at_alloc, -1, "dump allocations digest each n-th allocation") +#if defined(V8_USE_LIBM_TRIG_FUNCTIONS) +DEFINE_BOOL(use_libm_trig_functions, true, "use libm trig functions") +#endif + // Cleanup... #undef FLAG_FULL #undef FLAG_READONLY diff --git a/test/cctest/compiler/test-run-machops.cc b/test/cctest/compiler/test-run-machops.cc index 11a2d7bde0..d3b59147bb 100644 --- a/test/cctest/compiler/test-run-machops.cc +++ b/test/cctest/compiler/test-run-machops.cc @@ -11,6 +11,7 @@ #include "src/base/overflowing-math.h" #include "src/base/safe_conversions.h" #include "src/base/utils/random-number-generator.h" +#include "src/builtins/builtins.h" #include "src/common/ptr-compr-inl.h" #include "src/objects/objects-inl.h" #include "src/utils/boxed-float.h" @@ -6318,7 +6319,7 @@ TEST(RunFloat64Cos) { m.Return(m.Float64Cos(m.Parameter(0))); CHECK(std::isnan(m.Call(std::numeric_limits::quiet_NaN()))); CHECK(std::isnan(m.Call(std::numeric_limits::signaling_NaN()))); - FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(base::ieee754::cos(i), m.Call(i)); } + FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(COS_IMPL(i), m.Call(i)); } } TEST(RunFloat64Cosh) { @@ -6428,7 +6429,7 @@ TEST(RunFloat64Sin) { m.Return(m.Float64Sin(m.Parameter(0))); CHECK(std::isnan(m.Call(std::numeric_limits::quiet_NaN()))); CHECK(std::isnan(m.Call(std::numeric_limits::signaling_NaN()))); - FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(base::ieee754::sin(i), m.Call(i)); } + FOR_FLOAT64_INPUTS(i) { CHECK_DOUBLE_EQ(SIN_IMPL(i), m.Call(i)); } } TEST(RunFloat64Sinh) { diff --git a/test/unittests/base/ieee754-unittest.cc b/test/unittests/base/ieee754-unittest.cc index dbba16a313..e22f3b86b2 100644 --- a/test/unittests/base/ieee754-unittest.cc +++ b/test/unittests/base/ieee754-unittest.cc @@ -131,6 +131,175 @@ TEST(Ieee754, Atanh) { EXPECT_DOUBLE_EQ(0.54930614433405478, atanh(0.5)); } +#if defined(V8_USE_LIBM_TRIG_FUNCTIONS) +TEST(Ieee754, LibmCos) { + // Test values mentioned in the EcmaScript spec. + EXPECT_THAT(libm_cos(kQNaN), IsNaN()); + EXPECT_THAT(libm_cos(kSNaN), IsNaN()); + EXPECT_THAT(libm_cos(kInfinity), IsNaN()); + EXPECT_THAT(libm_cos(-kInfinity), IsNaN()); + + // Tests for cos for |x| < pi/4 + EXPECT_EQ(1.0, 1 / libm_cos(-0.0)); + EXPECT_EQ(1.0, 1 / libm_cos(0.0)); + // cos(x) = 1 for |x| < 2^-27 + EXPECT_EQ(1, libm_cos(2.3283064365386963e-10)); + EXPECT_EQ(1, libm_cos(-2.3283064365386963e-10)); + // Test KERNELCOS for |x| < 0.3. + // cos(pi/20) = sqrt(sqrt(2)*sqrt(sqrt(5)+5)+4)/2^(3/2) + EXPECT_EQ(0.9876883405951378, libm_cos(0.15707963267948966)); + // Test KERNELCOS for x ~= 0.78125 + EXPECT_EQ(0.7100335477927638, libm_cos(0.7812504768371582)); + EXPECT_EQ(0.7100338835660797, libm_cos(0.78125)); + // Test KERNELCOS for |x| > 0.3. + // cos(pi/8) = sqrt(sqrt(2)+1)/2^(3/4) + EXPECT_EQ(0.9238795325112867, libm_cos(0.39269908169872414)); + // Test KERNELTAN for |x| < 0.67434. + EXPECT_EQ(0.9238795325112867, libm_cos(-0.39269908169872414)); + + // Tests for cos. + EXPECT_EQ(1, libm_cos(3.725290298461914e-9)); + // Cover different code paths in KERNELCOS. + EXPECT_EQ(0.9689124217106447, libm_cos(0.25)); + EXPECT_EQ(0.8775825618903728, libm_cos(0.5)); + EXPECT_EQ(0.7073882691671998, libm_cos(0.785)); + // Test that cos(Math.PI/2) != 0 since Math.PI is not exact. + EXPECT_EQ(6.123233995736766e-17, libm_cos(1.5707963267948966)); + // Test cos for various phases. + EXPECT_EQ(0.7071067811865474, libm_cos(7.0 / 4 * kPI)); + EXPECT_EQ(0.7071067811865477, libm_cos(9.0 / 4 * kPI)); + EXPECT_EQ(-0.7071067811865467, libm_cos(11.0 / 4 * kPI)); + EXPECT_EQ(-0.7071067811865471, libm_cos(13.0 / 4 * kPI)); + EXPECT_EQ(0.9367521275331447, libm_cos(1000000.0)); + EXPECT_EQ(-3.435757038074824e-12, libm_cos(1048575.0 / 2 * kPI)); + + // Test Hayne-Panek reduction. + EXPECT_EQ(-0.9258790228548379e0, libm_cos(kTwo120)); + EXPECT_EQ(-0.9258790228548379e0, libm_cos(-kTwo120)); +} + +TEST(Ieee754, LibmSin) { + // Test values mentioned in the EcmaScript spec. + EXPECT_THAT(libm_sin(kQNaN), IsNaN()); + EXPECT_THAT(libm_sin(kSNaN), IsNaN()); + EXPECT_THAT(libm_sin(kInfinity), IsNaN()); + EXPECT_THAT(libm_sin(-kInfinity), IsNaN()); + + // Tests for sin for |x| < pi/4 + EXPECT_EQ(-kInfinity, Divide(1.0, libm_sin(-0.0))); + EXPECT_EQ(kInfinity, Divide(1.0, libm_sin(0.0))); + // sin(x) = x for x < 2^-27 + EXPECT_EQ(2.3283064365386963e-10, libm_sin(2.3283064365386963e-10)); + EXPECT_EQ(-2.3283064365386963e-10, libm_sin(-2.3283064365386963e-10)); + // sin(pi/8) = sqrt(sqrt(2)-1)/2^(3/4) + EXPECT_EQ(0.3826834323650898, libm_sin(0.39269908169872414)); + EXPECT_EQ(-0.3826834323650898, libm_sin(-0.39269908169872414)); + + // Tests for sin. + EXPECT_EQ(0.479425538604203, libm_sin(0.5)); + EXPECT_EQ(-0.479425538604203, libm_sin(-0.5)); + EXPECT_EQ(1, libm_sin(kPI / 2.0)); + EXPECT_EQ(-1, libm_sin(-kPI / 2.0)); + // Test that sin(Math.PI) != 0 since Math.PI is not exact. + EXPECT_EQ(1.2246467991473532e-16, libm_sin(kPI)); + EXPECT_EQ(-7.047032979958965e-14, libm_sin(2200.0 * kPI)); + // Test sin for various phases. + EXPECT_EQ(-0.7071067811865477, libm_sin(7.0 / 4.0 * kPI)); + EXPECT_EQ(0.7071067811865474, libm_sin(9.0 / 4.0 * kPI)); + EXPECT_EQ(0.7071067811865483, libm_sin(11.0 / 4.0 * kPI)); + EXPECT_EQ(-0.7071067811865479, libm_sin(13.0 / 4.0 * kPI)); + EXPECT_EQ(-3.2103381051568376e-11, libm_sin(1048576.0 / 4 * kPI)); + + // Test Hayne-Panek reduction. + EXPECT_EQ(0.377820109360752e0, libm_sin(kTwo120)); + EXPECT_EQ(-0.377820109360752e0, libm_sin(-kTwo120)); +} + +TEST(Ieee754, FdlibmCos) { + // Test values mentioned in the EcmaScript spec. + EXPECT_THAT(fdlibm_cos(kQNaN), IsNaN()); + EXPECT_THAT(fdlibm_cos(kSNaN), IsNaN()); + EXPECT_THAT(fdlibm_cos(kInfinity), IsNaN()); + EXPECT_THAT(fdlibm_cos(-kInfinity), IsNaN()); + + // Tests for cos for |x| < pi/4 + EXPECT_EQ(1.0, 1 / fdlibm_cos(-0.0)); + EXPECT_EQ(1.0, 1 / fdlibm_cos(0.0)); + // cos(x) = 1 for |x| < 2^-27 + EXPECT_EQ(1, fdlibm_cos(2.3283064365386963e-10)); + EXPECT_EQ(1, fdlibm_cos(-2.3283064365386963e-10)); + // Test KERNELCOS for |x| < 0.3. + // cos(pi/20) = sqrt(sqrt(2)*sqrt(sqrt(5)+5)+4)/2^(3/2) + EXPECT_EQ(0.9876883405951378, fdlibm_cos(0.15707963267948966)); + // Test KERNELCOS for x ~= 0.78125 + EXPECT_EQ(0.7100335477927638, fdlibm_cos(0.7812504768371582)); + EXPECT_EQ(0.7100338835660797, fdlibm_cos(0.78125)); + // Test KERNELCOS for |x| > 0.3. + // cos(pi/8) = sqrt(sqrt(2)+1)/2^(3/4) + EXPECT_EQ(0.9238795325112867, fdlibm_cos(0.39269908169872414)); + // Test KERNELTAN for |x| < 0.67434. + EXPECT_EQ(0.9238795325112867, fdlibm_cos(-0.39269908169872414)); + + // Tests for cos. + EXPECT_EQ(1, fdlibm_cos(3.725290298461914e-9)); + // Cover different code paths in KERNELCOS. + EXPECT_EQ(0.9689124217106447, fdlibm_cos(0.25)); + EXPECT_EQ(0.8775825618903728, fdlibm_cos(0.5)); + EXPECT_EQ(0.7073882691671998, fdlibm_cos(0.785)); + // Test that cos(Math.PI/2) != 0 since Math.PI is not exact. + EXPECT_EQ(6.123233995736766e-17, fdlibm_cos(1.5707963267948966)); + // Test cos for various phases. + EXPECT_EQ(0.7071067811865474, fdlibm_cos(7.0 / 4 * kPI)); + EXPECT_EQ(0.7071067811865477, fdlibm_cos(9.0 / 4 * kPI)); + EXPECT_EQ(-0.7071067811865467, fdlibm_cos(11.0 / 4 * kPI)); + EXPECT_EQ(-0.7071067811865471, fdlibm_cos(13.0 / 4 * kPI)); + EXPECT_EQ(0.9367521275331447, fdlibm_cos(1000000.0)); + EXPECT_EQ(-3.435757038074824e-12, fdlibm_cos(1048575.0 / 2 * kPI)); + + // Test Hayne-Panek reduction. + EXPECT_EQ(-0.9258790228548379e0, fdlibm_cos(kTwo120)); + EXPECT_EQ(-0.9258790228548379e0, fdlibm_cos(-kTwo120)); +} + +TEST(Ieee754, FdlibmSin) { + // Test values mentioned in the EcmaScript spec. + EXPECT_THAT(fdlibm_sin(kQNaN), IsNaN()); + EXPECT_THAT(fdlibm_sin(kSNaN), IsNaN()); + EXPECT_THAT(fdlibm_sin(kInfinity), IsNaN()); + EXPECT_THAT(fdlibm_sin(-kInfinity), IsNaN()); + + // Tests for sin for |x| < pi/4 + EXPECT_EQ(-kInfinity, Divide(1.0, fdlibm_sin(-0.0))); + EXPECT_EQ(kInfinity, Divide(1.0, fdlibm_sin(0.0))); + // sin(x) = x for x < 2^-27 + EXPECT_EQ(2.3283064365386963e-10, fdlibm_sin(2.3283064365386963e-10)); + EXPECT_EQ(-2.3283064365386963e-10, fdlibm_sin(-2.3283064365386963e-10)); + // sin(pi/8) = sqrt(sqrt(2)-1)/2^(3/4) + EXPECT_EQ(0.3826834323650898, fdlibm_sin(0.39269908169872414)); + EXPECT_EQ(-0.3826834323650898, fdlibm_sin(-0.39269908169872414)); + + // Tests for sin. + EXPECT_EQ(0.479425538604203, fdlibm_sin(0.5)); + EXPECT_EQ(-0.479425538604203, fdlibm_sin(-0.5)); + EXPECT_EQ(1, fdlibm_sin(kPI / 2.0)); + EXPECT_EQ(-1, fdlibm_sin(-kPI / 2.0)); + // Test that sin(Math.PI) != 0 since Math.PI is not exact. + EXPECT_EQ(1.2246467991473532e-16, fdlibm_sin(kPI)); + EXPECT_EQ(-7.047032979958965e-14, fdlibm_sin(2200.0 * kPI)); + // Test sin for various phases. + EXPECT_EQ(-0.7071067811865477, fdlibm_sin(7.0 / 4.0 * kPI)); + EXPECT_EQ(0.7071067811865474, fdlibm_sin(9.0 / 4.0 * kPI)); + EXPECT_EQ(0.7071067811865483, fdlibm_sin(11.0 / 4.0 * kPI)); + EXPECT_EQ(-0.7071067811865479, fdlibm_sin(13.0 / 4.0 * kPI)); + EXPECT_EQ(-3.2103381051568376e-11, fdlibm_sin(1048576.0 / 4 * kPI)); + + // Test Hayne-Panek reduction. + EXPECT_EQ(0.377820109360752e0, fdlibm_sin(kTwo120)); + EXPECT_EQ(-0.377820109360752e0, fdlibm_sin(-kTwo120)); +} + +#else + TEST(Ieee754, Cos) { // Test values mentioned in the EcmaScript spec. EXPECT_THAT(cos(kQNaN), IsNaN()); @@ -177,6 +346,45 @@ TEST(Ieee754, Cos) { EXPECT_EQ(-0.9258790228548379e0, cos(-kTwo120)); } +TEST(Ieee754, Sin) { + // Test values mentioned in the EcmaScript spec. + EXPECT_THAT(sin(kQNaN), IsNaN()); + EXPECT_THAT(sin(kSNaN), IsNaN()); + EXPECT_THAT(sin(kInfinity), IsNaN()); + EXPECT_THAT(sin(-kInfinity), IsNaN()); + + // Tests for sin for |x| < pi/4 + EXPECT_EQ(-kInfinity, Divide(1.0, sin(-0.0))); + EXPECT_EQ(kInfinity, Divide(1.0, sin(0.0))); + // sin(x) = x for x < 2^-27 + EXPECT_EQ(2.3283064365386963e-10, sin(2.3283064365386963e-10)); + EXPECT_EQ(-2.3283064365386963e-10, sin(-2.3283064365386963e-10)); + // sin(pi/8) = sqrt(sqrt(2)-1)/2^(3/4) + EXPECT_EQ(0.3826834323650898, sin(0.39269908169872414)); + EXPECT_EQ(-0.3826834323650898, sin(-0.39269908169872414)); + + // Tests for sin. + EXPECT_EQ(0.479425538604203, sin(0.5)); + EXPECT_EQ(-0.479425538604203, sin(-0.5)); + EXPECT_EQ(1, sin(kPI / 2.0)); + EXPECT_EQ(-1, sin(-kPI / 2.0)); + // Test that sin(Math.PI) != 0 since Math.PI is not exact. + EXPECT_EQ(1.2246467991473532e-16, sin(kPI)); + EXPECT_EQ(-7.047032979958965e-14, sin(2200.0 * kPI)); + // Test sin for various phases. + EXPECT_EQ(-0.7071067811865477, sin(7.0 / 4.0 * kPI)); + EXPECT_EQ(0.7071067811865474, sin(9.0 / 4.0 * kPI)); + EXPECT_EQ(0.7071067811865483, sin(11.0 / 4.0 * kPI)); + EXPECT_EQ(-0.7071067811865479, sin(13.0 / 4.0 * kPI)); + EXPECT_EQ(-3.2103381051568376e-11, sin(1048576.0 / 4 * kPI)); + + // Test Hayne-Panek reduction. + EXPECT_EQ(0.377820109360752e0, sin(kTwo120)); + EXPECT_EQ(-0.377820109360752e0, sin(-kTwo120)); +} + +#endif + TEST(Ieee754, Cosh) { // Test values mentioned in the EcmaScript spec. EXPECT_THAT(cosh(kQNaN), IsNaN()); @@ -306,43 +514,6 @@ TEST(Ieee754, Cbrt) { EXPECT_EQ(46.415888336127786, cbrt(100000)); } -TEST(Ieee754, Sin) { - // Test values mentioned in the EcmaScript spec. - EXPECT_THAT(sin(kQNaN), IsNaN()); - EXPECT_THAT(sin(kSNaN), IsNaN()); - EXPECT_THAT(sin(kInfinity), IsNaN()); - EXPECT_THAT(sin(-kInfinity), IsNaN()); - - // Tests for sin for |x| < pi/4 - EXPECT_EQ(-kInfinity, Divide(1.0, sin(-0.0))); - EXPECT_EQ(kInfinity, Divide(1.0, sin(0.0))); - // sin(x) = x for x < 2^-27 - EXPECT_EQ(2.3283064365386963e-10, sin(2.3283064365386963e-10)); - EXPECT_EQ(-2.3283064365386963e-10, sin(-2.3283064365386963e-10)); - // sin(pi/8) = sqrt(sqrt(2)-1)/2^(3/4) - EXPECT_EQ(0.3826834323650898, sin(0.39269908169872414)); - EXPECT_EQ(-0.3826834323650898, sin(-0.39269908169872414)); - - // Tests for sin. - EXPECT_EQ(0.479425538604203, sin(0.5)); - EXPECT_EQ(-0.479425538604203, sin(-0.5)); - EXPECT_EQ(1, sin(kPI / 2.0)); - EXPECT_EQ(-1, sin(-kPI / 2.0)); - // Test that sin(Math.PI) != 0 since Math.PI is not exact. - EXPECT_EQ(1.2246467991473532e-16, sin(kPI)); - EXPECT_EQ(-7.047032979958965e-14, sin(2200.0 * kPI)); - // Test sin for various phases. - EXPECT_EQ(-0.7071067811865477, sin(7.0 / 4.0 * kPI)); - EXPECT_EQ(0.7071067811865474, sin(9.0 / 4.0 * kPI)); - EXPECT_EQ(0.7071067811865483, sin(11.0 / 4.0 * kPI)); - EXPECT_EQ(-0.7071067811865479, sin(13.0 / 4.0 * kPI)); - EXPECT_EQ(-3.2103381051568376e-11, sin(1048576.0 / 4 * kPI)); - - // Test Hayne-Panek reduction. - EXPECT_EQ(0.377820109360752e0, sin(kTwo120)); - EXPECT_EQ(-0.377820109360752e0, sin(-kTwo120)); -} - TEST(Ieee754, Sinh) { // Test values mentioned in the EcmaScript spec. EXPECT_THAT(sinh(kQNaN), IsNaN()); diff --git a/test/unittests/compiler/machine-operator-reducer-unittest.cc b/test/unittests/compiler/machine-operator-reducer-unittest.cc index e6a478e7bb..9fa005ff72 100644 --- a/test/unittests/compiler/machine-operator-reducer-unittest.cc +++ b/test/unittests/compiler/machine-operator-reducer-unittest.cc @@ -10,6 +10,7 @@ #include "src/base/division-by-constant.h" #include "src/base/ieee754.h" #include "src/base/overflowing-math.h" +#include "src/builtins/builtins.h" #include "src/compiler/js-graph.h" #include "src/compiler/machine-operator.h" #include "src/numbers/conversions-inl.h" @@ -2840,7 +2841,7 @@ TEST_F(MachineOperatorReducerTest, Float64CosWithConstant) { Reduce(graph()->NewNode(machine()->Float64Cos(), Float64Constant(x))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), - IsFloat64Constant(NanSensitiveDoubleEq(base::ieee754::cos(x)))); + IsFloat64Constant(NanSensitiveDoubleEq(COS_IMPL(x)))); } } @@ -2939,7 +2940,7 @@ TEST_F(MachineOperatorReducerTest, Float64SinWithConstant) { Reduce(graph()->NewNode(machine()->Float64Sin(), Float64Constant(x))); ASSERT_TRUE(r.Changed()); EXPECT_THAT(r.replacement(), - IsFloat64Constant(NanSensitiveDoubleEq(base::ieee754::sin(x)))); + IsFloat64Constant(NanSensitiveDoubleEq(SIN_IMPL(x)))); } }