diff --git a/emscripten-version.txt b/emscripten-version.txt index b1a41036cde93..6a10ff7aa230f 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1,2 +1,2 @@ -1.28.0 +1.28.1 diff --git a/emscripten.py b/emscripten.py index 12a1318bf1b89..acfb42f2c5bfb 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1096,8 +1096,7 @@ def make_emulated_param(i): simdfloattypes = ['float32x4'] simdinttypes = ['int32x4'] simdtypes = simdfloattypes + simdinttypes - # TODO: mul - simdfuncs = ['add', 'sub', 'neg', + simdfuncs = ['add', 'sub', 'neg', 'mul', 'equal', 'lessThan', 'greaterThan', 'notEqual', 'lessThanOrEqual', 'greaterThanOrEqual', 'select', 'and', 'or', 'xor', 'not', @@ -1105,11 +1104,13 @@ def make_emulated_param(i): 'withX', 'withY', 'withZ', 'withW', 'load', 'store'] # TODO: fromInt32x4 - simdfloatfuncs = simdfuncs + ['mul', 'div', 'min', 'max', 'minNum', 'maxNum', 'sqrt', + simdfloatfuncs = simdfuncs + ['div', 'min', 'max', 'minNum', 'maxNum', 'sqrt', 'abs', 'fromInt32x4Bits']; # TODO: fromFloat32x4 - # TODO: shiftLeftByScalar, shiftRightArithmeticByScalar, shiftLeftArithmeticByScalar - simdintfuncs = simdfuncs + ['fromFloat32x4Bits']; + simdintfuncs = simdfuncs + ['fromFloat32x4Bits', + 'shiftRightArithmeticByScalar', + 'shiftRightLogicalByScalar', + 'shiftLeftByScalar']; fundamentals = ['Math', 'Int8Array', 'Int16Array', 'Int32Array', 'Uint8Array', 'Uint16Array', 'Uint32Array', 'Float32Array', 'Float64Array'] if metadata['simd']: fundamentals += ['SIMD'] diff --git a/site/source/docs/getting_started/Tutorial.rst b/site/source/docs/getting_started/Tutorial.rst index 77baee7fdcb81..1a524be9c9e6f 100644 --- a/site/source/docs/getting_started/Tutorial.rst +++ b/site/source/docs/getting_started/Tutorial.rst @@ -96,7 +96,7 @@ JavaScript is usually run in the sandboxed environment of a web browser, without Files that you want to access should be :ref:`preloaded <emcc-preload-file>` or :ref:`embedded <emcc-embed-file>` into the virtual file system. Preloading (or embedding) generates a virtual file system that corresponds to the file system structure at *compile* time, *relative to the current directory*. -The `hello_world_file.cpp <https://github.com/kripken/emscripten/blob/master/tests/hello_world.cpp>`_ example shows how to load a file (both the test code and the file to be loaded shown below): +The `hello_world_file.cpp <https://github.com/kripken/emscripten/blob/master/tests/hello_world_file.cpp>`_ example shows how to load a file (both the test code and the file to be loaded shown below): .. include:: ../../../../tests/hello_world_file.cpp :literal: diff --git a/src/library.js b/src/library.js index 711cc7296a4a6..58fb51a4b2755 100644 --- a/src/library.js +++ b/src/library.js @@ -4518,202 +4518,11 @@ LibraryManager.library = { llvm_log_f64: 'Math_log', llvm_exp_f32: 'Math_exp', llvm_exp_f64: 'Math_exp', - cbrt: function(x) { - return Math.pow(x, 1/3); - }, - cbrtf: 'cbrt', - cbrtl: 'cbrt', - - modf: function(x, intpart) { - {{{ makeSetValue('intpart', 0, '(x < 0) ? Math.ceil(x) : Math.floor(x)', 'double') }}}; - return x - {{{ makeGetValue('intpart', 0, 'double') }}}; - }, - modff: function(x, intpart) { - {{{ makeSetValue('intpart', 0, '(x < 0) ? Math.ceil(x) : Math.floor(x)', 'float') }}}; - return x - {{{ makeGetValue('intpart', 0, 'float') }}}; - }, - finite: function(x) { - return isFinite(x); - }, - __finite: 'finite', - isinf: function(x) { - return !isNaN(x) && !isFinite(x); - }, - __isinf: 'isinf', - isnan: function(x) { - return isNaN(x); - }, - __isnan: 'isnan', _reallyNegative: function(x) { return x < 0 || (x === 0 && (1/x) === -Infinity); }, - copysign__deps: ['_reallyNegative'], - copysign: function(a, b) { - return __reallyNegative(a) === __reallyNegative(b) ? a : -a; - }, - copysignf: 'copysign', - copysignl: 'copysign', - __signbit__deps: ['copysign'], - __signbit: function(x) { - // We implement using copysign so that we get support - // for negative zero (once copysign supports that). - return _copysign(1.0, x) < 0; - }, - __signbitd: '__signbit', - __signbitf: '__signbit', - __signbitl: '__signbit', - hypot: function(a, b) { - return Math.sqrt(a*a + b*b); - }, - hypotf: 'hypot', - hypotl: 'hypot', - sinh: function(x) { - var p = Math.pow(Math.E, x); - return (p - (1 / p)) / 2; - }, - sinhf: 'sinh', - sinhl: 'sinh', - cosh: function(x) { - var p = Math.pow(Math.E, x); - return (p + (1 / p)) / 2; - }, - coshf: 'cosh', - coshl: 'cosh', - tanh__deps: ['sinh', 'cosh'], - tanh: function(x) { - return _sinh(x) / _cosh(x); - }, - tanhf: 'tanh', - tanhl: 'tanh', - asinh: function(x) { - return Math.log(x + Math.sqrt(x * x + 1)); - }, - asinhf: 'asinh', - asinhl: 'asinh', - acosh: function(x) { - return Math.log(x * 1 + Math.sqrt(x * x - 1)); - }, - acoshf: 'acosh', - acoshl: 'acosh', - atanh: function(x) { - return Math.log((1 + x) / (1 - x)) / 2; - }, - atanhf: 'atanh', - atanhl: 'atanh', - exp2: function(x) { - return Math.pow(2, x); - }, - exp2f: 'exp2', - exp2l: 'exp2', - expm1: function(x) { - return Math.exp(x) - 1; - }, - expm1f: 'expm1', - expm1l: 'expm1', - round: function(x) { - return (x < 0) ? -Math.round(-x) : Math.round(x); - }, - roundf: 'round', - roundl: 'round', - lround: 'round', - lroundf: 'round', - lroundl: 'round', - llround: 'round', - llroundf: 'round', - llroundl: 'round', - rint: function(x) { - if (Math.abs(x % 1) !== 0.5) return Math.round(x); - return x + x % 2 + ((x < 0) ? 1 : -1); - }, - rintf: 'rint', - rintl: 'rint', - lrint: 'rint', - lrintf: 'rint', - lrintl: 'rint', -#if USE_TYPED_ARRAYS == 2 - llrint: function(x) { - x = (x < 0) ? -Math.round(-x) : Math.round(x); - {{{ makeStructuralReturn(splitI64('x')) }}}; - }, -#else - llrint: 'rint', -#endif - llrintf: 'llrint', - llrintl: 'llrint', - nearbyint: 'rint', - nearbyintf: 'rint', - nearbyintl: 'rint', - trunc: function(x) { - return (x < 0) ? Math.ceil(x) : Math.floor(x); - }, - truncf: 'trunc', - truncl: 'trunc', - fdim: function(x, y) { - return (x > y) ? x - y : 0; - }, - fdimf: 'fdim', - fdiml: 'fdim', - fmax: function(x, y) { - return isNaN(x) ? y : isNaN(y) ? x : Math.max(x, y); - }, - fmaxf: 'fmax', - fmaxl: 'fmax', - fmin: function(x, y) { - return isNaN(x) ? y : isNaN(y) ? x : Math.min(x, y); - }, - fminf: 'fmin', - fminl: 'fmin', - fma: function(x, y, z) { - return x * y + z; - }, - fmaf: 'fma', - fmal: 'fma', - fmod: function(x, y) { - return x % y; - }, - fmodf: 'fmod', - fmodl: 'fmod', - remainder: 'fmod', - remainderf: 'fmod', - remainderl: 'fmod', - log10: function(x) { - return Math.log(x) / Math.LN10; - }, - log10f: 'log10', - log10l: 'log10', - log1p: function(x) { - return Math.log(1 + x); - }, - log1pf: 'log1p', - log1pl: 'log1p', - log2: function(x) { - return Math.log(x) / Math.LN2; - }, - log2f: 'log2', - log2l: 'log2', - nan: function(x) { - return NaN; - }, - nanf: 'nan', - nanl: 'nan', - - sincos: function(x, sine, cosine) { - var sineVal = Math.sin(x), - cosineVal = Math.cos(x); - {{{ makeSetValue('sine', '0', 'sineVal', 'double') }}}; - {{{ makeSetValue('cosine', '0', 'cosineVal', 'double') }}}; - }, - sincosl: 'sincos', - - sincosf: function(x, sine, cosine) { - var sineVal = Math.sin(x), - cosineVal = Math.cos(x); - {{{ makeSetValue('sine', '0', 'sineVal', 'float') }}}; - {{{ makeSetValue('cosine', '0', 'cosineVal', 'float') }}}; - }, - div: function(divt, numer, denom) { var quot = (numer / denom) | 0; var rem = numer - quot * denom; @@ -4722,16 +4531,7 @@ LibraryManager.library = { return divt; }, - __fpclassify: function(x) { - if (isNaN(x)) return {{{ cDefine('FP_NAN') }}}; - if (!isFinite(x)) return {{{ cDefine('FP_INFINITE') }}}; - if (x == 0) return {{{ cDefine('FP_ZERO') }}}; - // FP_SUBNORMAL..? - return {{{ cDefine('FP_NORMAL') }}}; - }, __fpclassifyd: '__fpclassify', // Needed by tests/python/python.le32.bc - __fpclassifyf: '__fpclassify', - __fpclassifyl: '__fpclassify', // ========================================================================== // sys/utsname.h diff --git a/system/lib/libc.symbols b/system/lib/libc.symbols index 2d1d9db0ca2e4..e47df094945b7 100644 --- a/system/lib/libc.symbols +++ b/system/lib/libc.symbols @@ -1,26 +1,76 @@ T __floatscan + T __fpclassify + T __fpclassifyf + T __fpclassifyl T __intscan T __overflow T __shgetc T __shlim + T __signbit + T __signbitf + T __signbitl W __strtod_l W __strtof_l W __strtold_l T __toread T __towrite T __uflow + T acosh + T acoshf + T acoshl + T asinh + T asinhf + T asinhl + T atanh + T atanhf + T atanhl T atof T atoi T atol W bulk_free W calloc + T cbrt + T cbrtf + T cbrtl + T copysign + T copysignf + T copysignl + T cosh + T coshf + T coshl T drand48 T erand48 + T exp2 + T exp2f + T exp2l + T expm1 + T expm1f + T expm1l + T fdim + T fdimf + T fdiml T ffs + T finite + T finitef + T fma + T fmaf + T fmal + T fmax + T fmaxf + T fmaxl + T fmin + T fminf + T fminl + T fmod + T fmodf + T fmodl W free T frexp T frexpf T frexpl + T hypot + T hypotf + T hypotl W independent_calloc W independent_comalloc T initstate @@ -31,8 +81,29 @@ T lcg31 T lcg64 T lcong48 + T llrint + T llrintf + T llrintl + T llround + T llroundf + T llroundl T loadstate + T log10 + T log10f + T log10l + T log1p + T log1pf + T log1pl + T log2 + T log2f + T log2l T lrand48 + T lrint + T lrintf + T lrintl + T lround + T lroundf + T lroundl W mallinfo W malloc W malloc_footprint @@ -44,8 +115,17 @@ W malloc_usable_size W mallopt W memalign + T modf + T modff + T modfl T MUSL_vfprintf T mrand48 + T nan + T nanf + T nanl + T nearbyint + T nearbyintf + T nearbyintl T nrand48 W posix_memalign W pvalloc @@ -54,9 +134,30 @@ T random W realloc W realloc_in_place + T remainder + T remainderf + T remainderl + T rint + T rintf + T rintl + T round + T roundf + T roundl T scalbn T scalbnl + T sincos + T sincosf + T sincosl + T sinh + T sinhf + T sinhl T srand + T tanh + T tanhf + T tanhl + T trunc + T truncf + T truncl T memchr T memcmp T memcpy diff --git a/system/lib/libc/musl/src/math/__fpclassify.c b/system/lib/libc/musl/src/math/__fpclassify.c new file mode 100644 index 0000000000000..f7c0e2dfac828 --- /dev/null +++ b/system/lib/libc/musl/src/math/__fpclassify.c @@ -0,0 +1,11 @@ +#include <math.h> +#include <stdint.h> + +int __fpclassify(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i>>52 & 0x7ff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0x7ff) return u.i<<12 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} diff --git a/system/lib/libc/musl/src/math/__fpclassifyf.c b/system/lib/libc/musl/src/math/__fpclassifyf.c new file mode 100644 index 0000000000000..fd00eb1bcdc62 --- /dev/null +++ b/system/lib/libc/musl/src/math/__fpclassifyf.c @@ -0,0 +1,11 @@ +#include <math.h> +#include <stdint.h> + +int __fpclassifyf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i>>23 & 0xff; + if (!e) return u.i<<1 ? FP_SUBNORMAL : FP_ZERO; + if (e==0xff) return u.i<<9 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} diff --git a/system/lib/libc/musl/src/math/__fpclassifyl.c b/system/lib/libc/musl/src/math/__fpclassifyl.c new file mode 100644 index 0000000000000..6dc10025d2923 --- /dev/null +++ b/system/lib/libc/musl/src/math/__fpclassifyl.c @@ -0,0 +1,32 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 + +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +int __fpclassifyl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int msb = u.i.m>>63; + if (!e && !msb) + return u.i.m ? FP_SUBNORMAL : FP_ZERO; + if (!msb) + return FP_NAN; + if (e == 0x7fff) + return u.i.m << 1 ? FP_NAN : FP_INFINITE; + return FP_NORMAL; +} +#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 +int __fpclassifyl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + if (!e) + return u.i2.lo | u.i2.hi ? FP_SUBNORMAL : FP_ZERO; + if (e == 0x7fff) { + u.i.se = 0; + return u.i2.lo | u.i2.hi ? FP_NAN : FP_INFINITE; + } + return FP_NORMAL; +} +#endif diff --git a/system/lib/libc/musl/src/math/__signbit.c b/system/lib/libc/musl/src/math/__signbit.c new file mode 100644 index 0000000000000..e700b6b75fcb9 --- /dev/null +++ b/system/lib/libc/musl/src/math/__signbit.c @@ -0,0 +1,13 @@ +#include "libm.h" + +// FIXME: macro in math.h +int __signbit(double x) +{ + union { + double d; + uint64_t i; + } y = { x }; + return y.i>>63; +} + + diff --git a/system/lib/libc/musl/src/math/__signbitf.c b/system/lib/libc/musl/src/math/__signbitf.c new file mode 100644 index 0000000000000..40ad3cfd0cbe6 --- /dev/null +++ b/system/lib/libc/musl/src/math/__signbitf.c @@ -0,0 +1,11 @@ +#include "libm.h" + +// FIXME: macro in math.h +int __signbitf(float x) +{ + union { + float f; + uint32_t i; + } y = { x }; + return y.i>>31; +} diff --git a/system/lib/libc/musl/src/math/__signbitl.c b/system/lib/libc/musl/src/math/__signbitl.c new file mode 100644 index 0000000000000..c52c87bba062b --- /dev/null +++ b/system/lib/libc/musl/src/math/__signbitl.c @@ -0,0 +1,9 @@ +#include "libm.h" + +#if (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +int __signbitl(long double x) +{ + union ldshape u = {x}; + return u.i.se >> 15; +} +#endif diff --git a/system/lib/libc/musl/src/math/acosh.c b/system/lib/libc/musl/src/math/acosh.c new file mode 100644 index 0000000000000..badbf9081e644 --- /dev/null +++ b/system/lib/libc/musl/src/math/acosh.c @@ -0,0 +1,24 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==2 +#undef sqrt +#define sqrt sqrtl +#endif + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +double acosh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + + /* x < 1 domain error is handled in the called functions */ + + if (e < 0x3ff + 1) + /* |x| < 2, up to 2ulp error in [1,1.125] */ + return log1p(x-1 + sqrt((x-1)*(x-1)+2*(x-1))); + if (e < 0x3ff + 26) + /* |x| < 0x1p26 */ + return log(2*x - 1/(x+sqrt(x*x-1))); + /* |x| >= 0x1p26 or nan */ + return log(x) + 0.693147180559945309417232121458176568; +} diff --git a/system/lib/libc/musl/src/math/acoshf.c b/system/lib/libc/musl/src/math/acoshf.c new file mode 100644 index 0000000000000..8a4ec4d57ead3 --- /dev/null +++ b/system/lib/libc/musl/src/math/acoshf.c @@ -0,0 +1,26 @@ +#include "libm.h" + +#if FLT_EVAL_METHOD==2 +#undef sqrtf +#define sqrtf sqrtl +#elif FLT_EVAL_METHOD==1 +#undef sqrtf +#define sqrtf sqrt +#endif + +/* acosh(x) = log(x + sqrt(x*x-1)) */ +float acoshf(float x) +{ + union {float f; uint32_t i;} u = {x}; + uint32_t a = u.i & 0x7fffffff; + + if (a < 0x3f800000+(1<<23)) + /* |x| < 2, invalid if x < 1 or nan */ + /* up to 2ulp error in [1,1.125] */ + return log1pf(x-1 + sqrtf((x-1)*(x-1)+2*(x-1))); + if (a < 0x3f800000+(12<<23)) + /* |x| < 0x1p12 */ + return logf(2*x - 1/(x+sqrtf(x*x-1))); + /* x >= 0x1p12 */ + return logf(x) + 0.693147180559945309417232121458176568f; +} diff --git a/system/lib/libc/musl/src/math/acoshl.c b/system/lib/libc/musl/src/math/acoshl.c new file mode 100644 index 0000000000000..4aa84acb2ea36 --- /dev/null +++ b/system/lib/libc/musl/src/math/acoshl.c @@ -0,0 +1,23 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double acoshl(long double x) +{ + return acosh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* acosh(x) = log(x + sqrt(x*x-1)) */ +long double acoshl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + + if (e < 0x3fff + 1) + /* |x| < 2, invalid if x < 1 or nan */ + return log1pl(x-1 + sqrtl((x-1)*(x-1)+2*(x-1))); + if (e < 0x3fff + 32) + /* |x| < 0x1p32 */ + return logl(2*x - 1/(x+sqrtl(x*x-1))); + return logl(x) + 0.693147180559945309417232121458176568L; +} +#endif diff --git a/system/lib/libc/musl/src/math/asinh.c b/system/lib/libc/musl/src/math/asinh.c new file mode 100644 index 0000000000000..0829f228ef9d2 --- /dev/null +++ b/system/lib/libc/musl/src/math/asinh.c @@ -0,0 +1,28 @@ +#include "libm.h" + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +double asinh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + unsigned s = u.i >> 63; + + /* |x| */ + u.i &= (uint64_t)-1/2; + x = u.f; + + if (e >= 0x3ff + 26) { + /* |x| >= 0x1p26 or inf or nan */ + x = log(x) + 0.693147180559945309417232121458176568; + } else if (e >= 0x3ff + 1) { + /* |x| >= 2 */ + x = log(2*x + 1/(sqrt(x*x+1)+x)); + } else if (e >= 0x3ff - 26) { + /* |x| >= 0x1p-26, up to 1.6ulp error in [0.125,0.5] */ + x = log1p(x + x*x/(sqrt(x*x+1)+1)); + } else { + /* |x| < 0x1p-26, raise inexact if x != 0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} diff --git a/system/lib/libc/musl/src/math/asinhf.c b/system/lib/libc/musl/src/math/asinhf.c new file mode 100644 index 0000000000000..fc9f0911bf67f --- /dev/null +++ b/system/lib/libc/musl/src/math/asinhf.c @@ -0,0 +1,28 @@ +#include "libm.h" + +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +float asinhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t i = u.i & 0x7fffffff; + unsigned s = u.i >> 31; + + /* |x| */ + u.i = i; + x = u.f; + + if (i >= 0x3f800000 + (12<<23)) { + /* |x| >= 0x1p12 or inf or nan */ + x = logf(x) + 0.693147180559945309417232121458176568f; + } else if (i >= 0x3f800000 + (1<<23)) { + /* |x| >= 2 */ + x = logf(2*x + 1/(sqrtf(x*x+1)+x)); + } else if (i >= 0x3f800000 - (12<<23)) { + /* |x| >= 0x1p-12, up to 1.6ulp error in [0.125,0.5] */ + x = log1pf(x + x*x/(sqrtf(x*x+1)+1)); + } else { + /* |x| < 0x1p-12, raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} diff --git a/system/lib/libc/musl/src/math/asinhl.c b/system/lib/libc/musl/src/math/asinhl.c new file mode 100644 index 0000000000000..e5f3175121cc6 --- /dev/null +++ b/system/lib/libc/musl/src/math/asinhl.c @@ -0,0 +1,35 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double asinhl(long double x) +{ + return asinh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* asinh(x) = sign(x)*log(|x|+sqrt(x*x+1)) ~= x - x^3/6 + o(x^5) */ +long double asinhl(long double x) +{ + union ldshape u = {x}; + unsigned e = u.i.se & 0x7fff; + unsigned s = u.i.se >> 15; + + /* |x| */ + u.i.se = e; + x = u.f; + + if (e >= 0x3fff + 32) { + /* |x| >= 0x1p32 or inf or nan */ + x = logl(x) + 0.693147180559945309417232121458176568L; + } else if (e >= 0x3fff + 1) { + /* |x| >= 2 */ + x = logl(2*x + 1/(sqrtl(x*x+1)+x)); + } else if (e >= 0x3fff - 32) { + /* |x| >= 0x1p-32 */ + x = log1pl(x + x*x/(sqrtl(x*x+1)+1)); + } else { + /* |x| < 0x1p-32, raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + } + return s ? -x : x; +} +#endif diff --git a/system/lib/libc/musl/src/math/atanh.c b/system/lib/libc/musl/src/math/atanh.c new file mode 100644 index 0000000000000..63a035d7063ae --- /dev/null +++ b/system/lib/libc/musl/src/math/atanh.c @@ -0,0 +1,29 @@ +#include "libm.h" + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +double atanh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + unsigned e = u.i >> 52 & 0x7ff; + unsigned s = u.i >> 63; + double_t y; + + /* |x| */ + u.i &= (uint64_t)-1/2; + y = u.f; + + if (e < 0x3ff - 1) { + if (e < 0x3ff - 32) { + /* handle underflow */ + if (e == 0) + FORCE_EVAL((float)y); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5*log1p(2*y + 2*y*y/(1-y)); + } + } else { + /* avoid overflow */ + y = 0.5*log1p(2*(y/(1-y))); + } + return s ? -y : y; +} diff --git a/system/lib/libc/musl/src/math/atanhf.c b/system/lib/libc/musl/src/math/atanhf.c new file mode 100644 index 0000000000000..65f07c0f4f26e --- /dev/null +++ b/system/lib/libc/musl/src/math/atanhf.c @@ -0,0 +1,28 @@ +#include "libm.h" + +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +float atanhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + unsigned s = u.i >> 31; + float_t y; + + /* |x| */ + u.i &= 0x7fffffff; + y = u.f; + + if (u.i < 0x3f800000 - (1<<23)) { + if (u.i < 0x3f800000 - (32<<23)) { + /* handle underflow */ + if (u.i < (1<<23)) + FORCE_EVAL((float)(y*y)); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + y = 0.5f*log1pf(2*y + 2*y*y/(1-y)); + } + } else { + /* avoid overflow */ + y = 0.5f*log1pf(2*(y/(1-y))); + } + return s ? -y : y; +} diff --git a/system/lib/libc/musl/src/math/atanhl.c b/system/lib/libc/musl/src/math/atanhl.c new file mode 100644 index 0000000000000..f63d60b153fae --- /dev/null +++ b/system/lib/libc/musl/src/math/atanhl.c @@ -0,0 +1,35 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double atanhl(long double x) +{ + return atanh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* atanh(x) = log((1+x)/(1-x))/2 = log1p(2x/(1-x))/2 ~= x + x^3/3 + o(x^5) */ +long double atanhl(long double x) +{ + union ldshape u = {x}; + unsigned e = u.i.se & 0x7fff; + unsigned s = u.i.se >> 15; + + /* |x| */ + u.i.se = e; + x = u.f; + + if (e < 0x3ff - 1) { + if (e < 0x3ff - LDBL_MANT_DIG/2) { + /* handle underflow */ + if (e == 0) + FORCE_EVAL((float)x); + } else { + /* |x| < 0.5, up to 1.7ulp error */ + x = 0.5*log1pl(2*x + 2*x*x/(1-x)); + } + } else { + /* avoid overflow */ + x = 0.5*log1pl(2*(x/(1-x))); + } + return s ? -x : x; +} +#endif diff --git a/system/lib/libc/musl/src/math/cbrt.c b/system/lib/libc/musl/src/math/cbrt.c new file mode 100644 index 0000000000000..7599d3e37d2f6 --- /dev/null +++ b/system/lib/libc/musl/src/math/cbrt.c @@ -0,0 +1,103 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrt.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * Optimized by Bruce D. Evans. + */ +/* cbrt(x) + * Return cube root of x + */ + +#include <math.h> +#include <stdint.h> + +static const uint32_t +B1 = 715094163, /* B1 = (1023-1023/3-0.03306235651)*2**20 */ +B2 = 696219795; /* B2 = (1023-1023/3-54/3-0.03306235651)*2**20 */ + +/* |1/cbrt(x) - p(x)| < 2**-23.5 (~[-7.93e-8, 7.929e-8]). */ +static const double +P0 = 1.87595182427177009643, /* 0x3ffe03e6, 0x0f61e692 */ +P1 = -1.88497979543377169875, /* 0xbffe28e0, 0x92f02420 */ +P2 = 1.621429720105354466140, /* 0x3ff9f160, 0x4a49d6c2 */ +P3 = -0.758397934778766047437, /* 0xbfe844cb, 0xbee751d9 */ +P4 = 0.145996192886612446982; /* 0x3fc2b000, 0xd4e4edd7 */ + +double cbrt(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t r,s,t,w; + uint32_t hx = u.i>>32 & 0x7fffffff; + + if (hx >= 0x7ff00000) /* cbrt(NaN,INF) is itself */ + return x+x; + + /* + * Rough cbrt to 5 bits: + * cbrt(2**e*(1+m) ~= 2**(e/3)*(1+(e%3+m)/3) + * where e is integral and >= 0, m is real and in [0, 1), and "/" and + * "%" are integer division and modulus with rounding towards minus + * infinity. The RHS is always >= the LHS and has a maximum relative + * error of about 1 in 16. Adding a bias of -0.03306235651 to the + * (e%3+m)/3 term reduces the error to about 1 in 32. With the IEEE + * floating point representation, for finite positive normal values, + * ordinary integer divison of the value in bits magically gives + * almost exactly the RHS of the above provided we first subtract the + * exponent bias (1023 for doubles) and later add it back. We do the + * subtraction virtually to keep e >= 0 so that ordinary integer + * division rounds towards minus infinity; this is also efficient. + */ + if (hx < 0x00100000) { /* zero or subnormal? */ + u.f = x*0x1p54; + hx = u.i>>32 & 0x7fffffff; + if (hx == 0) + return x; /* cbrt(0) is itself */ + hx = hx/3 + B2; + } else + hx = hx/3 + B1; + u.i &= 1ULL<<63; + u.i |= (uint64_t)hx << 32; + t = u.f; + + /* + * New cbrt to 23 bits: + * cbrt(x) = t*cbrt(x/t**3) ~= t*P(t**3/x) + * where P(r) is a polynomial of degree 4 that approximates 1/cbrt(r) + * to within 2**-23.5 when |r - 1| < 1/10. The rough approximation + * has produced t such than |t/cbrt(x) - 1| ~< 1/32, and cubing this + * gives us bounds for r = t**3/x. + * + * Try to optimize for parallel evaluation as in __tanf.c. + */ + r = (t*t)*(t/x); + t = t*((P0+r*(P1+r*P2))+((r*r)*r)*(P3+r*P4)); + + /* + * Round t away from zero to 23 bits (sloppily except for ensuring that + * the result is larger in magnitude than cbrt(x) but not much more than + * 2 23-bit ulps larger). With rounding towards zero, the error bound + * would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps + * in the rounded t, the infinite-precision error in the Newton + * approximation barely affects third digit in the final error + * 0.667; the error in the rounded t can be up to about 3 23-bit ulps + * before the final error is larger than 0.667 ulps. + */ + u.f = t; + u.i = (u.i + 0x80000000) & 0xffffffffc0000000ULL; + t = u.f; + + /* one step Newton iteration to 53 bits with error < 0.667 ulps */ + s = t*t; /* t*t is exact */ + r = x/s; /* error <= 0.5 ulps; |r| < |t| */ + w = t+t; /* t+t is exact */ + r = (r-t)/(w+r); /* r-t is exact; w+r ~= 3*t */ + t = t+t*r; /* error <= 0.5 + 0.5/3 + epsilon */ + return t; +} diff --git a/system/lib/libc/musl/src/math/cbrtf.c b/system/lib/libc/musl/src/math/cbrtf.c new file mode 100644 index 0000000000000..89c2c8655da46 --- /dev/null +++ b/system/lib/libc/musl/src/math/cbrtf.c @@ -0,0 +1,66 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Debugged and optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* cbrtf(x) + * Return cube root of x + */ + +#include <math.h> +#include <stdint.h> + +static const unsigned +B1 = 709958130, /* B1 = (127-127.0/3-0.03306235651)*2**23 */ +B2 = 642849266; /* B2 = (127-127.0/3-24/3-0.03306235651)*2**23 */ + +float cbrtf(float x) +{ + double_t r,T; + union {float f; uint32_t i;} u = {x}; + uint32_t hx = u.i & 0x7fffffff; + + if (hx >= 0x7f800000) /* cbrt(NaN,INF) is itself */ + return x + x; + + /* rough cbrt to 5 bits */ + if (hx < 0x00800000) { /* zero or subnormal? */ + if (hx == 0) + return x; /* cbrt(+-0) is itself */ + u.f = x*0x1p24f; + hx = u.i & 0x7fffffff; + hx = hx/3 + B2; + } else + hx = hx/3 + B1; + u.i &= 0x80000000; + u.i |= hx; + + /* + * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In + * double precision so that its terms can be arranged for efficiency + * without causing overflow or underflow. + */ + T = u.f; + r = T*T*T; + T = T*((double_t)x+x+r)/(x+r+r); + + /* + * Second step Newton iteration to 47 bits. In double precision for + * efficiency and accuracy. + */ + r = T*T*T; + T = T*((double_t)x+x+r)/(x+r+r); + + /* rounding to 24 bits is perfect in round-to-nearest mode */ + return T; +} diff --git a/system/lib/libc/musl/src/math/cbrtl.c b/system/lib/libc/musl/src/math/cbrtl.c new file mode 100644 index 0000000000000..ceff9136ebb50 --- /dev/null +++ b/system/lib/libc/musl/src/math/cbrtl.c @@ -0,0 +1,124 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_cbrtl.c */ +/*- + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * Copyright (c) 2009-2011, Bruce D. Evans, Steven G. Kargl, David Schultz. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + * + * The argument reduction and testing for exceptional cases was + * written by Steven G. Kargl with input from Bruce D. Evans + * and David A. Schultz. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double cbrtl(long double x) +{ + return cbrt(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +static const unsigned B1 = 709958130; /* B1 = (127-127.0/3-0.03306235651)*2**23 */ + +long double cbrtl(long double x) +{ + union ldshape u = {x}, v; + union {float f; uint32_t i;} uft; + long double r, s, t, w; + double_t dr, dt, dx; + float_t ft; + int e = u.i.se & 0x7fff; + int sign = u.i.se & 0x8000; + + /* + * If x = +-Inf, then cbrt(x) = +-Inf. + * If x = NaN, then cbrt(x) = NaN. + */ + if (e == 0x7fff) + return x + x; + if (e == 0) { + /* Adjust subnormal numbers. */ + u.f *= 0x1p120; + e = u.i.se & 0x7fff; + /* If x = +-0, then cbrt(x) = +-0. */ + if (e == 0) + return x; + e -= 120; + } + e -= 0x3fff; + u.i.se = 0x3fff; + x = u.f; + switch (e % 3) { + case 1: + case -2: + x *= 2; + e--; + break; + case 2: + case -1: + x *= 4; + e -= 2; + break; + } + v.f = 1.0; + v.i.se = sign | (0x3fff + e/3); + + /* + * The following is the guts of s_cbrtf, with the handling of + * special values removed and extra care for accuracy not taken, + * but with most of the extra accuracy not discarded. + */ + + /* ~5-bit estimate: */ + uft.f = x; + uft.i = (uft.i & 0x7fffffff)/3 + B1; + ft = uft.f; + + /* ~16-bit estimate: */ + dx = x; + dt = ft; + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + + /* ~47-bit estimate: */ + dr = dt * dt * dt; + dt = dt * (dx + dx + dr) / (dx + dr + dr); + +#if LDBL_MANT_DIG == 64 + /* + * dt is cbrtl(x) to ~47 bits (after x has been reduced to 1 <= x < 8). + * Round it away from zero to 32 bits (32 so that t*t is exact, and + * away from zero for technical reasons). + */ + t = dt + (0x1.0p32L + 0x1.0p-31L) - 0x1.0p32; +#elif LDBL_MANT_DIG == 113 + /* + * Round dt away from zero to 47 bits. Since we don't trust the 47, + * add 2 47-bit ulps instead of 1 to round up. Rounding is slow and + * might be avoidable in this case, since on most machines dt will + * have been evaluated in 53-bit precision and the technical reasons + * for rounding up might not apply to either case in cbrtl() since + * dt is much more accurate than needed. + */ + t = dt + 0x2.0p-46 + 0x1.0p60L - 0x1.0p60; +#endif + + /* + * Final step Newton iteration to 64 or 113 bits with + * error < 0.667 ulps + */ + s = t*t; /* t*t is exact */ + r = x/s; /* error <= 0.5 ulps; |r| < |t| */ + w = t+t; /* t+t is exact */ + r = (r-t)/(w+r); /* r-t is exact; w+r ~= 3*t */ + t = t+t*r; /* error <= 0.5 + 0.5/3 + epsilon */ + + t *= v.f; + return t; +} +#endif diff --git a/system/lib/libc/musl/src/math/copysign.c b/system/lib/libc/musl/src/math/copysign.c new file mode 100644 index 0000000000000..b09331b6876e7 --- /dev/null +++ b/system/lib/libc/musl/src/math/copysign.c @@ -0,0 +1,8 @@ +#include "libm.h" + +double copysign(double x, double y) { + union {double f; uint64_t i;} ux={x}, uy={y}; + ux.i &= -1ULL/2; + ux.i |= uy.i & 1ULL<<63; + return ux.f; +} diff --git a/system/lib/libc/musl/src/math/copysignf.c b/system/lib/libc/musl/src/math/copysignf.c new file mode 100644 index 0000000000000..0af6ae9b2155d --- /dev/null +++ b/system/lib/libc/musl/src/math/copysignf.c @@ -0,0 +1,10 @@ +#include <math.h> +#include <stdint.h> + +float copysignf(float x, float y) +{ + union {float f; uint32_t i;} ux={x}, uy={y}; + ux.i &= 0x7fffffff; + ux.i |= uy.i & 0x80000000; + return ux.f; +} diff --git a/system/lib/libc/musl/src/math/copysignl.c b/system/lib/libc/musl/src/math/copysignl.c new file mode 100644 index 0000000000000..9dd933cfa9c55 --- /dev/null +++ b/system/lib/libc/musl/src/math/copysignl.c @@ -0,0 +1,16 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double copysignl(long double x, long double y) +{ + return copysign(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double copysignl(long double x, long double y) +{ + union ldshape ux = {x}, uy = {y}; + ux.i.se &= 0x7fff; + ux.i.se |= uy.i.se & 0x8000; + return ux.f; +} +#endif diff --git a/system/lib/libc/musl/src/math/cosh.c b/system/lib/libc/musl/src/math/cosh.c new file mode 100644 index 0000000000000..100f8231d8829 --- /dev/null +++ b/system/lib/libc/musl/src/math/cosh.c @@ -0,0 +1,40 @@ +#include "libm.h" + +/* cosh(x) = (exp(x) + 1/exp(x))/2 + * = 1 + 0.5*(exp(x)-1)*(exp(x)-1)/exp(x) + * = 1 + x*x/2 + o(x^4) + */ +double cosh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + double t; + + /* |x| */ + u.i &= (uint64_t)-1/2; + x = u.f; + w = u.i >> 32; + + /* |x| < log(2) */ + if (w < 0x3fe62e42) { + if (w < 0x3ff00000 - (26<<20)) { + /* raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(DBL_MAX) */ + if (w < 0x40862e42) { + t = exp(x); + /* note: if x>log(0x1p26) then the 1/t is not needed */ + return 0.5*(t + 1/t); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = __expo2(x); + return t; +} diff --git a/system/lib/libc/musl/src/math/coshf.c b/system/lib/libc/musl/src/math/coshf.c new file mode 100644 index 0000000000000..b09f2ee5751f4 --- /dev/null +++ b/system/lib/libc/musl/src/math/coshf.c @@ -0,0 +1,33 @@ +#include "libm.h" + +float coshf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + float t; + + /* |x| */ + u.i &= 0x7fffffff; + x = u.f; + w = u.i; + + /* |x| < log(2) */ + if (w < 0x3f317217) { + if (w < 0x3f800000 - (12<<23)) { + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1f(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(FLT_MAX) */ + if (w < 0x42b17217) { + t = expf(x); + return 0.5f*(t + 1/t); + } + + /* |x| > log(FLT_MAX) or nan */ + t = __expo2f(x); + return t; +} diff --git a/system/lib/libc/musl/src/math/coshl.c b/system/lib/libc/musl/src/math/coshl.c new file mode 100644 index 0000000000000..080e5eb0425c0 --- /dev/null +++ b/system/lib/libc/musl/src/math/coshl.c @@ -0,0 +1,41 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double coshl(long double x) +{ + return cosh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double coshl(long double x) +{ + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + uint32_t w; + long double t; + + /* |x| */ + u.i.se = ex; + x = u.f; + w = u.i.m >> 32; + + /* |x| < log(2) */ + if (ex < 0x3fff-1 || (ex == 0x3fff-1 && w < 0xb17217f7)) { + if (ex < 0x3fff-32) { + FORCE_EVAL(x + 0x1p120f); + return 1; + } + t = expm1l(x); + return 1 + t*t/(2*(1+t)); + } + + /* |x| < log(LDBL_MAX) */ + if (ex < 0x3fff+13 || (ex == 0x3fff+13 && w < 0xb17217f7)) { + t = expl(x); + return 0.5*(t + 1/t); + } + + /* |x| > log(LDBL_MAX) or nan */ + t = expl(0.5*x); + return 0.5*t*t; +} +#endif diff --git a/system/lib/libc/musl/src/math/exp2.c b/system/lib/libc/musl/src/math/exp2.c new file mode 100644 index 0000000000000..e14adba530e49 --- /dev/null +++ b/system/lib/libc/musl/src/math/exp2.c @@ -0,0 +1,375 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_exp2.c */ +/*- + * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +#define TBLSIZE 256 + +static const double +redux = 0x1.8p52 / TBLSIZE, +P1 = 0x1.62e42fefa39efp-1, +P2 = 0x1.ebfbdff82c575p-3, +P3 = 0x1.c6b08d704a0a6p-5, +P4 = 0x1.3b2ab88f70400p-7, +P5 = 0x1.5d88003875c74p-10; + +static const double tbl[TBLSIZE * 2] = { +/* exp2(z + eps) eps */ + 0x1.6a09e667f3d5dp-1, 0x1.9880p-44, + 0x1.6b052fa751744p-1, 0x1.8000p-50, + 0x1.6c012750bd9fep-1, -0x1.8780p-45, + 0x1.6cfdcddd476bfp-1, 0x1.ec00p-46, + 0x1.6dfb23c651a29p-1, -0x1.8000p-50, + 0x1.6ef9298593ae3p-1, -0x1.c000p-52, + 0x1.6ff7df9519386p-1, -0x1.fd80p-45, + 0x1.70f7466f42da3p-1, -0x1.c880p-45, + 0x1.71f75e8ec5fc3p-1, 0x1.3c00p-46, + 0x1.72f8286eacf05p-1, -0x1.8300p-44, + 0x1.73f9a48a58152p-1, -0x1.0c00p-47, + 0x1.74fbd35d7ccfcp-1, 0x1.f880p-45, + 0x1.75feb564267f1p-1, 0x1.3e00p-47, + 0x1.77024b1ab6d48p-1, -0x1.7d00p-45, + 0x1.780694fde5d38p-1, -0x1.d000p-50, + 0x1.790b938ac1d00p-1, 0x1.3000p-49, + 0x1.7a11473eb0178p-1, -0x1.d000p-49, + 0x1.7b17b0976d060p-1, 0x1.0400p-45, + 0x1.7c1ed0130c133p-1, 0x1.0000p-53, + 0x1.7d26a62ff8636p-1, -0x1.6900p-45, + 0x1.7e2f336cf4e3bp-1, -0x1.2e00p-47, + 0x1.7f3878491c3e8p-1, -0x1.4580p-45, + 0x1.80427543e1b4ep-1, 0x1.3000p-44, + 0x1.814d2add1071ap-1, 0x1.f000p-47, + 0x1.82589994ccd7ep-1, -0x1.1c00p-45, + 0x1.8364c1eb942d0p-1, 0x1.9d00p-45, + 0x1.8471a4623cab5p-1, 0x1.7100p-43, + 0x1.857f4179f5bbcp-1, 0x1.2600p-45, + 0x1.868d99b4491afp-1, -0x1.2c40p-44, + 0x1.879cad931a395p-1, -0x1.3000p-45, + 0x1.88ac7d98a65b8p-1, -0x1.a800p-45, + 0x1.89bd0a4785800p-1, -0x1.d000p-49, + 0x1.8ace5422aa223p-1, 0x1.3280p-44, + 0x1.8be05bad619fap-1, 0x1.2b40p-43, + 0x1.8cf3216b54383p-1, -0x1.ed00p-45, + 0x1.8e06a5e08664cp-1, -0x1.0500p-45, + 0x1.8f1ae99157807p-1, 0x1.8280p-45, + 0x1.902fed0282c0ep-1, -0x1.cb00p-46, + 0x1.9145b0b91ff96p-1, -0x1.5e00p-47, + 0x1.925c353aa2ff9p-1, 0x1.5400p-48, + 0x1.93737b0cdc64ap-1, 0x1.7200p-46, + 0x1.948b82b5f98aep-1, -0x1.9000p-47, + 0x1.95a44cbc852cbp-1, 0x1.5680p-45, + 0x1.96bdd9a766f21p-1, -0x1.6d00p-44, + 0x1.97d829fde4e2ap-1, -0x1.1000p-47, + 0x1.98f33e47a23a3p-1, 0x1.d000p-45, + 0x1.9a0f170ca0604p-1, -0x1.8a40p-44, + 0x1.9b2bb4d53ff89p-1, 0x1.55c0p-44, + 0x1.9c49182a3f15bp-1, 0x1.6b80p-45, + 0x1.9d674194bb8c5p-1, -0x1.c000p-49, + 0x1.9e86319e3238ep-1, 0x1.7d00p-46, + 0x1.9fa5e8d07f302p-1, 0x1.6400p-46, + 0x1.a0c667b5de54dp-1, -0x1.5000p-48, + 0x1.a1e7aed8eb8f6p-1, 0x1.9e00p-47, + 0x1.a309bec4a2e27p-1, 0x1.ad80p-45, + 0x1.a42c980460a5dp-1, -0x1.af00p-46, + 0x1.a5503b23e259bp-1, 0x1.b600p-47, + 0x1.a674a8af46213p-1, 0x1.8880p-44, + 0x1.a799e1330b3a7p-1, 0x1.1200p-46, + 0x1.a8bfe53c12e8dp-1, 0x1.6c00p-47, + 0x1.a9e6b5579fcd2p-1, -0x1.9b80p-45, + 0x1.ab0e521356fb8p-1, 0x1.b700p-45, + 0x1.ac36bbfd3f381p-1, 0x1.9000p-50, + 0x1.ad5ff3a3c2780p-1, 0x1.4000p-49, + 0x1.ae89f995ad2a3p-1, -0x1.c900p-45, + 0x1.afb4ce622f367p-1, 0x1.6500p-46, + 0x1.b0e07298db790p-1, 0x1.fd40p-45, + 0x1.b20ce6c9a89a9p-1, 0x1.2700p-46, + 0x1.b33a2b84f1a4bp-1, 0x1.d470p-43, + 0x1.b468415b747e7p-1, -0x1.8380p-44, + 0x1.b59728de5593ap-1, 0x1.8000p-54, + 0x1.b6c6e29f1c56ap-1, 0x1.ad00p-47, + 0x1.b7f76f2fb5e50p-1, 0x1.e800p-50, + 0x1.b928cf22749b2p-1, -0x1.4c00p-47, + 0x1.ba5b030a10603p-1, -0x1.d700p-47, + 0x1.bb8e0b79a6f66p-1, 0x1.d900p-47, + 0x1.bcc1e904bc1ffp-1, 0x1.2a00p-47, + 0x1.bdf69c3f3a16fp-1, -0x1.f780p-46, + 0x1.bf2c25bd71db8p-1, -0x1.0a00p-46, + 0x1.c06286141b2e9p-1, -0x1.1400p-46, + 0x1.c199bdd8552e0p-1, 0x1.be00p-47, + 0x1.c2d1cd9fa64eep-1, -0x1.9400p-47, + 0x1.c40ab5fffd02fp-1, -0x1.ed00p-47, + 0x1.c544778fafd15p-1, 0x1.9660p-44, + 0x1.c67f12e57d0cbp-1, -0x1.a100p-46, + 0x1.c7ba88988c1b6p-1, -0x1.8458p-42, + 0x1.c8f6d9406e733p-1, -0x1.a480p-46, + 0x1.ca3405751c4dfp-1, 0x1.b000p-51, + 0x1.cb720dcef9094p-1, 0x1.1400p-47, + 0x1.ccb0f2e6d1689p-1, 0x1.0200p-48, + 0x1.cdf0b555dc412p-1, 0x1.3600p-48, + 0x1.cf3155b5bab3bp-1, -0x1.6900p-47, + 0x1.d072d4a0789bcp-1, 0x1.9a00p-47, + 0x1.d1b532b08c8fap-1, -0x1.5e00p-46, + 0x1.d2f87080d8a85p-1, 0x1.d280p-46, + 0x1.d43c8eacaa203p-1, 0x1.1a00p-47, + 0x1.d5818dcfba491p-1, 0x1.f000p-50, + 0x1.d6c76e862e6a1p-1, -0x1.3a00p-47, + 0x1.d80e316c9834ep-1, -0x1.cd80p-47, + 0x1.d955d71ff6090p-1, 0x1.4c00p-48, + 0x1.da9e603db32aep-1, 0x1.f900p-48, + 0x1.dbe7cd63a8325p-1, 0x1.9800p-49, + 0x1.dd321f301b445p-1, -0x1.5200p-48, + 0x1.de7d5641c05bfp-1, -0x1.d700p-46, + 0x1.dfc97337b9aecp-1, -0x1.6140p-46, + 0x1.e11676b197d5ep-1, 0x1.b480p-47, + 0x1.e264614f5a3e7p-1, 0x1.0ce0p-43, + 0x1.e3b333b16ee5cp-1, 0x1.c680p-47, + 0x1.e502ee78b3fb4p-1, -0x1.9300p-47, + 0x1.e653924676d68p-1, -0x1.5000p-49, + 0x1.e7a51fbc74c44p-1, -0x1.7f80p-47, + 0x1.e8f7977cdb726p-1, -0x1.3700p-48, + 0x1.ea4afa2a490e8p-1, 0x1.5d00p-49, + 0x1.eb9f4867ccae4p-1, 0x1.61a0p-46, + 0x1.ecf482d8e680dp-1, 0x1.5500p-48, + 0x1.ee4aaa2188514p-1, 0x1.6400p-51, + 0x1.efa1bee615a13p-1, -0x1.e800p-49, + 0x1.f0f9c1cb64106p-1, -0x1.a880p-48, + 0x1.f252b376bb963p-1, -0x1.c900p-45, + 0x1.f3ac948dd7275p-1, 0x1.a000p-53, + 0x1.f50765b6e4524p-1, -0x1.4f00p-48, + 0x1.f6632798844fdp-1, 0x1.a800p-51, + 0x1.f7bfdad9cbe38p-1, 0x1.abc0p-48, + 0x1.f91d802243c82p-1, -0x1.4600p-50, + 0x1.fa7c1819e908ep-1, -0x1.b0c0p-47, + 0x1.fbdba3692d511p-1, -0x1.0e00p-51, + 0x1.fd3c22b8f7194p-1, -0x1.0de8p-46, + 0x1.fe9d96b2a23eep-1, 0x1.e430p-49, + 0x1.0000000000000p+0, 0x0.0000p+0, + 0x1.00b1afa5abcbep+0, -0x1.3400p-52, + 0x1.0163da9fb3303p+0, -0x1.2170p-46, + 0x1.02168143b0282p+0, 0x1.a400p-52, + 0x1.02c9a3e77806cp+0, 0x1.f980p-49, + 0x1.037d42e11bbcap+0, -0x1.7400p-51, + 0x1.04315e86e7f89p+0, 0x1.8300p-50, + 0x1.04e5f72f65467p+0, -0x1.a3f0p-46, + 0x1.059b0d315855ap+0, -0x1.2840p-47, + 0x1.0650a0e3c1f95p+0, 0x1.1600p-48, + 0x1.0706b29ddf71ap+0, 0x1.5240p-46, + 0x1.07bd42b72a82dp+0, -0x1.9a00p-49, + 0x1.0874518759bd0p+0, 0x1.6400p-49, + 0x1.092bdf66607c8p+0, -0x1.0780p-47, + 0x1.09e3ecac6f383p+0, -0x1.8000p-54, + 0x1.0a9c79b1f3930p+0, 0x1.fa00p-48, + 0x1.0b5586cf988fcp+0, -0x1.ac80p-48, + 0x1.0c0f145e46c8ap+0, 0x1.9c00p-50, + 0x1.0cc922b724816p+0, 0x1.5200p-47, + 0x1.0d83b23395dd8p+0, -0x1.ad00p-48, + 0x1.0e3ec32d3d1f3p+0, 0x1.bac0p-46, + 0x1.0efa55fdfa9a6p+0, -0x1.4e80p-47, + 0x1.0fb66affed2f0p+0, -0x1.d300p-47, + 0x1.1073028d7234bp+0, 0x1.1500p-48, + 0x1.11301d0125b5bp+0, 0x1.c000p-49, + 0x1.11edbab5e2af9p+0, 0x1.6bc0p-46, + 0x1.12abdc06c31d5p+0, 0x1.8400p-49, + 0x1.136a814f2047dp+0, -0x1.ed00p-47, + 0x1.1429aaea92de9p+0, 0x1.8e00p-49, + 0x1.14e95934f3138p+0, 0x1.b400p-49, + 0x1.15a98c8a58e71p+0, 0x1.5300p-47, + 0x1.166a45471c3dfp+0, 0x1.3380p-47, + 0x1.172b83c7d5211p+0, 0x1.8d40p-45, + 0x1.17ed48695bb9fp+0, -0x1.5d00p-47, + 0x1.18af9388c8d93p+0, -0x1.c880p-46, + 0x1.1972658375d66p+0, 0x1.1f00p-46, + 0x1.1a35beb6fcba7p+0, 0x1.0480p-46, + 0x1.1af99f81387e3p+0, -0x1.7390p-43, + 0x1.1bbe084045d54p+0, 0x1.4e40p-45, + 0x1.1c82f95281c43p+0, -0x1.a200p-47, + 0x1.1d4873168b9b2p+0, 0x1.3800p-49, + 0x1.1e0e75eb44031p+0, 0x1.ac00p-49, + 0x1.1ed5022fcd938p+0, 0x1.1900p-47, + 0x1.1f9c18438cdf7p+0, -0x1.b780p-46, + 0x1.2063b88628d8fp+0, 0x1.d940p-45, + 0x1.212be3578a81ep+0, 0x1.8000p-50, + 0x1.21f49917ddd41p+0, 0x1.b340p-45, + 0x1.22bdda2791323p+0, 0x1.9f80p-46, + 0x1.2387a6e7561e7p+0, -0x1.9c80p-46, + 0x1.2451ffb821427p+0, 0x1.2300p-47, + 0x1.251ce4fb2a602p+0, -0x1.3480p-46, + 0x1.25e85711eceb0p+0, 0x1.2700p-46, + 0x1.26b4565e27d16p+0, 0x1.1d00p-46, + 0x1.2780e341de00fp+0, 0x1.1ee0p-44, + 0x1.284dfe1f5633ep+0, -0x1.4c00p-46, + 0x1.291ba7591bb30p+0, -0x1.3d80p-46, + 0x1.29e9df51fdf09p+0, 0x1.8b00p-47, + 0x1.2ab8a66d10e9bp+0, -0x1.27c0p-45, + 0x1.2b87fd0dada3ap+0, 0x1.a340p-45, + 0x1.2c57e39771af9p+0, -0x1.0800p-46, + 0x1.2d285a6e402d9p+0, -0x1.ed00p-47, + 0x1.2df961f641579p+0, -0x1.4200p-48, + 0x1.2ecafa93e2ecfp+0, -0x1.4980p-45, + 0x1.2f9d24abd8822p+0, -0x1.6300p-46, + 0x1.306fe0a31b625p+0, -0x1.2360p-44, + 0x1.31432edeea50bp+0, -0x1.0df8p-40, + 0x1.32170fc4cd7b8p+0, -0x1.2480p-45, + 0x1.32eb83ba8e9a2p+0, -0x1.5980p-45, + 0x1.33c08b2641766p+0, 0x1.ed00p-46, + 0x1.3496266e3fa27p+0, -0x1.c000p-50, + 0x1.356c55f929f0fp+0, -0x1.0d80p-44, + 0x1.36431a2de88b9p+0, 0x1.2c80p-45, + 0x1.371a7373aaa39p+0, 0x1.0600p-45, + 0x1.37f26231e74fep+0, -0x1.6600p-46, + 0x1.38cae6d05d838p+0, -0x1.ae00p-47, + 0x1.39a401b713ec3p+0, -0x1.4720p-43, + 0x1.3a7db34e5a020p+0, 0x1.8200p-47, + 0x1.3b57fbfec6e95p+0, 0x1.e800p-44, + 0x1.3c32dc313a8f2p+0, 0x1.f800p-49, + 0x1.3d0e544ede122p+0, -0x1.7a00p-46, + 0x1.3dea64c1234bbp+0, 0x1.6300p-45, + 0x1.3ec70df1c4eccp+0, -0x1.8a60p-43, + 0x1.3fa4504ac7e8cp+0, -0x1.cdc0p-44, + 0x1.40822c367a0bbp+0, 0x1.5b80p-45, + 0x1.4160a21f72e95p+0, 0x1.ec00p-46, + 0x1.423fb27094646p+0, -0x1.3600p-46, + 0x1.431f5d950a920p+0, 0x1.3980p-45, + 0x1.43ffa3f84b9ebp+0, 0x1.a000p-48, + 0x1.44e0860618919p+0, -0x1.6c00p-48, + 0x1.45c2042a7d201p+0, -0x1.bc00p-47, + 0x1.46a41ed1d0016p+0, -0x1.2800p-46, + 0x1.4786d668b3326p+0, 0x1.0e00p-44, + 0x1.486a2b5c13c00p+0, -0x1.d400p-45, + 0x1.494e1e192af04p+0, 0x1.c200p-47, + 0x1.4a32af0d7d372p+0, -0x1.e500p-46, + 0x1.4b17dea6db801p+0, 0x1.7800p-47, + 0x1.4bfdad53629e1p+0, -0x1.3800p-46, + 0x1.4ce41b817c132p+0, 0x1.0800p-47, + 0x1.4dcb299fddddbp+0, 0x1.c700p-45, + 0x1.4eb2d81d8ab96p+0, -0x1.ce00p-46, + 0x1.4f9b2769d2d02p+0, 0x1.9200p-46, + 0x1.508417f4531c1p+0, -0x1.8c00p-47, + 0x1.516daa2cf662ap+0, -0x1.a000p-48, + 0x1.5257de83f51eap+0, 0x1.a080p-43, + 0x1.5342b569d4edap+0, -0x1.6d80p-45, + 0x1.542e2f4f6ac1ap+0, -0x1.2440p-44, + 0x1.551a4ca5d94dbp+0, 0x1.83c0p-43, + 0x1.56070dde9116bp+0, 0x1.4b00p-45, + 0x1.56f4736b529dep+0, 0x1.15a0p-43, + 0x1.57e27dbe2c40ep+0, -0x1.9e00p-45, + 0x1.58d12d497c76fp+0, -0x1.3080p-45, + 0x1.59c0827ff0b4cp+0, 0x1.dec0p-43, + 0x1.5ab07dd485427p+0, -0x1.4000p-51, + 0x1.5ba11fba87af4p+0, 0x1.0080p-44, + 0x1.5c9268a59460bp+0, -0x1.6c80p-45, + 0x1.5d84590998e3fp+0, 0x1.69a0p-43, + 0x1.5e76f15ad20e1p+0, -0x1.b400p-46, + 0x1.5f6a320dcebcap+0, 0x1.7700p-46, + 0x1.605e1b976dcb8p+0, 0x1.6f80p-45, + 0x1.6152ae6cdf715p+0, 0x1.1000p-47, + 0x1.6247eb03a5531p+0, -0x1.5d00p-46, + 0x1.633dd1d1929b5p+0, -0x1.2d00p-46, + 0x1.6434634ccc313p+0, -0x1.a800p-49, + 0x1.652b9febc8efap+0, -0x1.8600p-45, + 0x1.6623882553397p+0, 0x1.1fe0p-40, + 0x1.671c1c708328ep+0, -0x1.7200p-44, + 0x1.68155d44ca97ep+0, 0x1.6800p-49, + 0x1.690f4b19e9471p+0, -0x1.9780p-45, +}; + +/* + * exp2(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.503 ulp for normalized results. + * + * Method: (accurate tables) + * + * Reduce x: + * x = k + y, for integer k and |y| <= 1/2. + * Thus we have exp2(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z - eps[i] for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z - eps[i]), + * with |z - eps[i]| <= 2**-9 + 2**-39 for the table used. + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z - eps[i]) via + * a degree-5 minimax polynomial with maximum error under 1.3 * 2**-61. + * The values in exp2t[] and eps[] are chosen such that + * exp2t[i] = exp2(i/TBLSIZE + eps[i]), and eps[i] is a small offset such + * that exp2t[i] is accurate to 2**-64. + * + * Note that the range of i is +-TBLSIZE/2, so we actually index the tables + * by i0 = i + TBLSIZE/2. For cache efficiency, exp2t[] and eps[] are + * virtual tables, interleaved in the real table tbl[]. + * + * This method is due to Gal, with many details due to Gal and Bachelis: + * + * Gal, S. and Bachelis, B. An Accurate Elementary Mathematical Library + * for the IEEE Floating Point Standard. TOMS 17(1), 26-46 (1991). + */ +double exp2(double x) +{ + double_t r, t, z; + uint32_t ix, i0; + union {double f; uint64_t i;} u = {x}; + union {uint32_t u; int32_t i;} k; + + /* Filter out exceptional cases. */ + ix = u.i>>32 & 0x7fffffff; + if (ix >= 0x408ff000) { /* |x| >= 1022 or nan */ + if (ix >= 0x40900000 && u.i>>63 == 0) { /* x >= 1024 or nan */ + /* overflow */ + x *= 0x1p1023; + return x; + } + if (ix >= 0x7ff00000) /* -inf or -nan */ + return -1/x; + if (u.i>>63) { /* x <= -1022 */ + /* underflow */ + if (x <= -1075 || x - 0x1p52 + 0x1p52 != x) + FORCE_EVAL((float)(-0x1p-149/x)); + if (x <= -1075) + return 0; + } + } else if (ix < 0x3c900000) { /* |x| < 0x1p-54 */ + return 1.0 + x; + } + + /* Reduce x, computing z, i0, and k. */ + u.f = x + redux; + i0 = u.i; + i0 += TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2(y) = exp2t[i0] * p(z - eps[i]). */ + t = tbl[2*i0]; /* exp2t[i0] */ + z -= tbl[2*i0 + 1]; /* eps[i0] */ + r = t + t * z * (P1 + z * (P2 + z * (P3 + z * (P4 + z * P5)))); + + return scalbn(r, k.i); +} diff --git a/system/lib/libc/musl/src/math/exp2f.c b/system/lib/libc/musl/src/math/exp2f.c new file mode 100644 index 0000000000000..cf6126eea776a --- /dev/null +++ b/system/lib/libc/musl/src/math/exp2f.c @@ -0,0 +1,124 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_exp2f.c */ +/*- + * Copyright (c) 2005 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +#define TBLSIZE 16 + +static const float +redux = 0x1.8p23f / TBLSIZE, +P1 = 0x1.62e430p-1f, +P2 = 0x1.ebfbe0p-3f, +P3 = 0x1.c6b348p-5f, +P4 = 0x1.3b2c9cp-7f; + +static const double exp2ft[TBLSIZE] = { + 0x1.6a09e667f3bcdp-1, + 0x1.7a11473eb0187p-1, + 0x1.8ace5422aa0dbp-1, + 0x1.9c49182a3f090p-1, + 0x1.ae89f995ad3adp-1, + 0x1.c199bdd85529cp-1, + 0x1.d5818dcfba487p-1, + 0x1.ea4afa2a490dap-1, + 0x1.0000000000000p+0, + 0x1.0b5586cf9890fp+0, + 0x1.172b83c7d517bp+0, + 0x1.2387a6e756238p+0, + 0x1.306fe0a31b715p+0, + 0x1.3dea64c123422p+0, + 0x1.4bfdad5362a27p+0, + 0x1.5ab07dd485429p+0, +}; + +/* + * exp2f(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.501 ulp; location of peak: -0.030110927. + * + * Method: (equally-spaced tables) + * + * Reduce x: + * x = k + y, for integer k and |y| <= 1/2. + * Thus we have exp2f(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), + * with |z| <= 2**-(TBLSIZE+1). + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a + * degree-4 minimax polynomial with maximum error under 1.4 * 2**-33. + * Using double precision for everything except the reduction makes + * roundoff error insignificant and simplifies the scaling step. + * + * This method is due to Tang, but I do not use his suggested parameters: + * + * Tang, P. Table-driven Implementation of the Exponential Function + * in IEEE Floating-Point Arithmetic. TOMS 15(2), 144-157 (1989). + */ +float exp2f(float x) +{ + double_t t, r, z; + union {float f; uint32_t i;} u = {x}; + union {double f; uint64_t i;} uk; + uint32_t ix, i0, k; + + /* Filter out exceptional cases. */ + ix = u.i & 0x7fffffff; + if (ix > 0x42fc0000) { /* |x| > 126 */ + if (u.i >= 0x43000000 && u.i < 0x80000000) { /* x >= 128 */ + x *= 0x1p127f; + return x; + } + if (u.i >= 0x80000000) { /* x < -126 */ + if (u.i >= 0xc3160000 || (u.i & 0x0000ffff)) + FORCE_EVAL(-0x1p-149f/x); + if (u.i >= 0xc3160000) /* x <= -150 */ + return 0; + } + } else if (ix <= 0x33000000) { /* |x| <= 0x1p-25 */ + return 1.0f + x; + } + + /* Reduce x, computing z, i0, and k. */ + u.f = x + redux; + i0 = u.i; + i0 += TBLSIZE / 2; + k = i0 / TBLSIZE; + uk.i = (uint64_t)(0x3ff + k)<<52; + i0 &= TBLSIZE - 1; + u.f -= redux; + z = x - u.f; + /* Compute r = exp2(y) = exp2ft[i0] * p(z). */ + r = exp2ft[i0]; + t = r * z; + r = r + t * (P1 + z * P2) + t * (z * z) * (P3 + z * P4); + + /* Scale by 2**k */ + return r * uk.f; +} diff --git a/system/lib/libc/musl/src/math/exp2l.c b/system/lib/libc/musl/src/math/exp2l.c new file mode 100644 index 0000000000000..8fc4037c56015 --- /dev/null +++ b/system/lib/libc/musl/src/math/exp2l.c @@ -0,0 +1,254 @@ +/* origin: FreeBSD /usr/src/lib/msun/ld80/s_exp2l.c */ +/*- + * Copyright (c) 2005-2008 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double exp2l(long double x) +{ + return exp2(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +#define TBLBITS 7 +#define TBLSIZE (1 << TBLBITS) + +static const double +redux = 0x1.8p63 / TBLSIZE, +P1 = 0x1.62e42fefa39efp-1, +P2 = 0x1.ebfbdff82c58fp-3, +P3 = 0x1.c6b08d7049fap-5, +P4 = 0x1.3b2ab6fba4da5p-7, +P5 = 0x1.5d8804780a736p-10, +P6 = 0x1.430918835e33dp-13; + +static const double tbl[TBLSIZE * 2] = { + 0x1.6a09e667f3bcdp-1, -0x1.bdd3413b2648p-55, + 0x1.6c012750bdabfp-1, -0x1.2895667ff0cp-57, + 0x1.6dfb23c651a2fp-1, -0x1.bbe3a683c88p-58, + 0x1.6ff7df9519484p-1, -0x1.83c0f25860fp-56, + 0x1.71f75e8ec5f74p-1, -0x1.16e4786887bp-56, + 0x1.73f9a48a58174p-1, -0x1.0a8d96c65d5p-55, + 0x1.75feb564267c9p-1, -0x1.0245957316ep-55, + 0x1.780694fde5d3fp-1, 0x1.866b80a0216p-55, + 0x1.7a11473eb0187p-1, -0x1.41577ee0499p-56, + 0x1.7c1ed0130c132p-1, 0x1.f124cd1164ep-55, + 0x1.7e2f336cf4e62p-1, 0x1.05d02ba157ap-57, + 0x1.80427543e1a12p-1, -0x1.27c86626d97p-55, + 0x1.82589994cce13p-1, -0x1.d4c1dd41533p-55, + 0x1.8471a4623c7adp-1, -0x1.8d684a341cep-56, + 0x1.868d99b4492edp-1, -0x1.fc6f89bd4f68p-55, + 0x1.88ac7d98a6699p-1, 0x1.994c2f37cb5p-55, + 0x1.8ace5422aa0dbp-1, 0x1.6e9f156864bp-55, + 0x1.8cf3216b5448cp-1, -0x1.0d55e32e9e4p-57, + 0x1.8f1ae99157736p-1, 0x1.5cc13a2e397p-56, + 0x1.9145b0b91ffc6p-1, -0x1.dd6792e5825p-55, + 0x1.93737b0cdc5e5p-1, -0x1.75fc781b58p-58, + 0x1.95a44cbc8520fp-1, -0x1.64b7c96a5fp-57, + 0x1.97d829fde4e5p-1, -0x1.d185b7c1b86p-55, + 0x1.9a0f170ca07bap-1, -0x1.173bd91cee6p-55, + 0x1.9c49182a3f09p-1, 0x1.c7c46b071f2p-57, + 0x1.9e86319e32323p-1, 0x1.824ca78e64cp-57, + 0x1.a0c667b5de565p-1, -0x1.359495d1cd5p-55, + 0x1.a309bec4a2d33p-1, 0x1.6305c7ddc368p-55, + 0x1.a5503b23e255dp-1, -0x1.d2f6edb8d42p-55, + 0x1.a799e1330b358p-1, 0x1.bcb7ecac564p-55, + 0x1.a9e6b5579fdbfp-1, 0x1.0fac90ef7fdp-55, + 0x1.ac36bbfd3f37ap-1, -0x1.f9234cae76dp-56, + 0x1.ae89f995ad3adp-1, 0x1.7a1cd345dcc8p-55, + 0x1.b0e07298db666p-1, -0x1.bdef54c80e4p-55, + 0x1.b33a2b84f15fbp-1, -0x1.2805e3084d8p-58, + 0x1.b59728de5593ap-1, -0x1.c71dfbbba6ep-55, + 0x1.b7f76f2fb5e47p-1, -0x1.5584f7e54acp-57, + 0x1.ba5b030a1064ap-1, -0x1.efcd30e5429p-55, + 0x1.bcc1e904bc1d2p-1, 0x1.23dd07a2d9fp-56, + 0x1.bf2c25bd71e09p-1, -0x1.efdca3f6b9c8p-55, + 0x1.c199bdd85529cp-1, 0x1.11065895049p-56, + 0x1.c40ab5fffd07ap-1, 0x1.b4537e083c6p-55, + 0x1.c67f12e57d14bp-1, 0x1.2884dff483c8p-55, + 0x1.c8f6d9406e7b5p-1, 0x1.1acbc48805cp-57, + 0x1.cb720dcef9069p-1, 0x1.503cbd1e94ap-57, + 0x1.cdf0b555dc3fap-1, -0x1.dd83b53829dp-56, + 0x1.d072d4a07897cp-1, -0x1.cbc3743797a8p-55, + 0x1.d2f87080d89f2p-1, -0x1.d487b719d858p-55, + 0x1.d5818dcfba487p-1, 0x1.2ed02d75b37p-56, + 0x1.d80e316c98398p-1, -0x1.11ec18bedep-55, + 0x1.da9e603db3285p-1, 0x1.c2300696db5p-55, + 0x1.dd321f301b46p-1, 0x1.2da5778f019p-55, + 0x1.dfc97337b9b5fp-1, -0x1.1a5cd4f184b8p-55, + 0x1.e264614f5a129p-1, -0x1.7b627817a148p-55, + 0x1.e502ee78b3ff6p-1, 0x1.39e8980a9cdp-56, + 0x1.e7a51fbc74c83p-1, 0x1.2d522ca0c8ep-55, + 0x1.ea4afa2a490dap-1, -0x1.e9c23179c288p-55, + 0x1.ecf482d8e67f1p-1, -0x1.c93f3b411ad8p-55, + 0x1.efa1bee615a27p-1, 0x1.dc7f486a4b68p-55, + 0x1.f252b376bba97p-1, 0x1.3a1a5bf0d8e8p-55, + 0x1.f50765b6e454p-1, 0x1.9d3e12dd8a18p-55, + 0x1.f7bfdad9cbe14p-1, -0x1.dbb12d00635p-55, + 0x1.fa7c1819e90d8p-1, 0x1.74853f3a593p-56, + 0x1.fd3c22b8f71f1p-1, 0x1.2eb74966578p-58, + 0x1p+0, 0x0p+0, + 0x1.0163da9fb3335p+0, 0x1.b61299ab8cd8p-54, + 0x1.02c9a3e778061p+0, -0x1.19083535b08p-56, + 0x1.04315e86e7f85p+0, -0x1.0a31c1977c98p-54, + 0x1.059b0d3158574p+0, 0x1.d73e2a475b4p-55, + 0x1.0706b29ddf6dep+0, -0x1.c91dfe2b13cp-55, + 0x1.0874518759bc8p+0, 0x1.186be4bb284p-57, + 0x1.09e3ecac6f383p+0, 0x1.14878183161p-54, + 0x1.0b5586cf9890fp+0, 0x1.8a62e4adc61p-54, + 0x1.0cc922b7247f7p+0, 0x1.01edc16e24f8p-54, + 0x1.0e3ec32d3d1a2p+0, 0x1.03a1727c58p-59, + 0x1.0fb66affed31bp+0, -0x1.b9bedc44ebcp-57, + 0x1.11301d0125b51p+0, -0x1.6c51039449bp-54, + 0x1.12abdc06c31ccp+0, -0x1.1b514b36ca8p-58, + 0x1.1429aaea92dep+0, -0x1.32fbf9af1368p-54, + 0x1.15a98c8a58e51p+0, 0x1.2406ab9eeabp-55, + 0x1.172b83c7d517bp+0, -0x1.19041b9d78ap-55, + 0x1.18af9388c8deap+0, -0x1.11023d1970f8p-54, + 0x1.1a35beb6fcb75p+0, 0x1.e5b4c7b4969p-55, + 0x1.1bbe084045cd4p+0, -0x1.95386352ef6p-54, + 0x1.1d4873168b9aap+0, 0x1.e016e00a264p-54, + 0x1.1ed5022fcd91dp+0, -0x1.1df98027bb78p-54, + 0x1.2063b88628cd6p+0, 0x1.dc775814a85p-55, + 0x1.21f49917ddc96p+0, 0x1.2a97e9494a6p-55, + 0x1.2387a6e756238p+0, 0x1.9b07eb6c7058p-54, + 0x1.251ce4fb2a63fp+0, 0x1.ac155bef4f5p-55, + 0x1.26b4565e27cddp+0, 0x1.2bd339940eap-55, + 0x1.284dfe1f56381p+0, -0x1.a4c3a8c3f0d8p-54, + 0x1.29e9df51fdee1p+0, 0x1.612e8afad12p-55, + 0x1.2b87fd0dad99p+0, -0x1.10adcd6382p-59, + 0x1.2d285a6e4030bp+0, 0x1.0024754db42p-54, + 0x1.2ecafa93e2f56p+0, 0x1.1ca0f45d524p-56, + 0x1.306fe0a31b715p+0, 0x1.6f46ad23183p-55, + 0x1.32170fc4cd831p+0, 0x1.a9ce78e1804p-55, + 0x1.33c08b26416ffp+0, 0x1.327218436598p-54, + 0x1.356c55f929ff1p+0, -0x1.b5cee5c4e46p-55, + 0x1.371a7373aa9cbp+0, -0x1.63aeabf42ebp-54, + 0x1.38cae6d05d866p+0, -0x1.e958d3c99048p-54, + 0x1.3a7db34e59ff7p+0, -0x1.5e436d661f6p-56, + 0x1.3c32dc313a8e5p+0, -0x1.efff8375d2ap-54, + 0x1.3dea64c123422p+0, 0x1.ada0911f09fp-55, + 0x1.3fa4504ac801cp+0, -0x1.7d023f956fap-54, + 0x1.4160a21f72e2ap+0, -0x1.ef3691c309p-58, + 0x1.431f5d950a897p+0, -0x1.1c7dde35f7ap-55, + 0x1.44e086061892dp+0, 0x1.89b7a04ef8p-59, + 0x1.46a41ed1d0057p+0, 0x1.c944bd1648a8p-54, + 0x1.486a2b5c13cdp+0, 0x1.3c1a3b69062p-56, + 0x1.4a32af0d7d3dep+0, 0x1.9cb62f3d1be8p-54, + 0x1.4bfdad5362a27p+0, 0x1.d4397afec42p-56, + 0x1.4dcb299fddd0dp+0, 0x1.8ecdbbc6a78p-54, + 0x1.4f9b2769d2ca7p+0, -0x1.4b309d25958p-54, + 0x1.516daa2cf6642p+0, -0x1.f768569bd94p-55, + 0x1.5342b569d4f82p+0, -0x1.07abe1db13dp-55, + 0x1.551a4ca5d920fp+0, -0x1.d689cefede6p-55, + 0x1.56f4736b527dap+0, 0x1.9bb2c011d938p-54, + 0x1.58d12d497c7fdp+0, 0x1.295e15b9a1ep-55, + 0x1.5ab07dd485429p+0, 0x1.6324c0546478p-54, + 0x1.5c9268a5946b7p+0, 0x1.c4b1b81698p-60, + 0x1.5e76f15ad2148p+0, 0x1.ba6f93080e68p-54, + 0x1.605e1b976dc09p+0, -0x1.3e2429b56de8p-54, + 0x1.6247eb03a5585p+0, -0x1.383c17e40b48p-54, + 0x1.6434634ccc32p+0, -0x1.c483c759d89p-55, + 0x1.6623882552225p+0, -0x1.bb60987591cp-54, + 0x1.68155d44ca973p+0, 0x1.038ae44f74p-57, +}; + +/* + * exp2l(x): compute the base 2 exponential of x + * + * Accuracy: Peak error < 0.511 ulp. + * + * Method: (equally-spaced tables) + * + * Reduce x: + * x = 2**k + y, for integer k and |y| <= 1/2. + * Thus we have exp2l(x) = 2**k * exp2(y). + * + * Reduce y: + * y = i/TBLSIZE + z for integer i near y * TBLSIZE. + * Thus we have exp2(y) = exp2(i/TBLSIZE) * exp2(z), + * with |z| <= 2**-(TBLBITS+1). + * + * We compute exp2(i/TBLSIZE) via table lookup and exp2(z) via a + * degree-6 minimax polynomial with maximum error under 2**-69. + * The table entries each have 104 bits of accuracy, encoded as + * a pair of double precision values. + */ +long double exp2l(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double r, z; + uint32_t i0; + union {uint32_t u; int32_t i;} k; + + /* Filter out exceptional cases. */ + if (e >= 0x3fff + 13) { /* |x| >= 8192 or x is NaN */ + if (u.i.se >= 0x3fff + 14 && u.i.se >> 15 == 0) + /* overflow */ + return x * 0x1p16383L; + if (e == 0x7fff) /* -inf or -nan */ + return -1/x; + if (x < -16382) { + if (x <= -16446 || x - 0x1p63 + 0x1p63 != x) + /* underflow */ + FORCE_EVAL((float)(-0x1p-149/x)); + if (x <= -16446) + return 0; + } + } else if (e < 0x3fff - 64) { + return 1 + x; + } + + /* + * Reduce x, computing z, i0, and k. The low bits of x + redux + * contain the 16-bit integer part of the exponent (k) followed by + * TBLBITS fractional bits (i0). We use bit tricks to extract these + * as integers, then set z to the remainder. + * + * Example: Suppose x is 0xabc.123456p0 and TBLBITS is 8. + * Then the low-order word of x + redux is 0x000abc12, + * We split this into k = 0xabc and i0 = 0x12 (adjusted to + * index into the table), then we compute z = 0x0.003456p0. + */ + u.f = x + redux; + i0 = u.i.m + TBLSIZE / 2; + k.u = i0 / TBLSIZE * TBLSIZE; + k.i /= TBLSIZE; + i0 %= TBLSIZE; + u.f -= redux; + z = x - u.f; + + /* Compute r = exp2l(y) = exp2lt[i0] * p(z). */ + long double t_hi = tbl[2*i0]; + long double t_lo = tbl[2*i0 + 1]; + /* XXX This gives > 1 ulp errors outside of FE_TONEAREST mode */ + r = t_lo + (t_hi + t_lo) * z * (P1 + z * (P2 + z * (P3 + z * (P4 + + z * (P5 + z * P6))))) + t_hi; + + return scalbnl(r, k.i); +} +#endif diff --git a/system/lib/libc/musl/src/math/expm1.c b/system/lib/libc/musl/src/math/expm1.c new file mode 100644 index 0000000000000..ac1e61e4f7f6a --- /dev/null +++ b/system/lib/libc/musl/src/math/expm1.c @@ -0,0 +1,201 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* expm1(x) + * Returns exp(x)-1, the exponential of x minus 1. + * + * Method + * 1. Argument reduction: + * Given x, find r and integer k such that + * + * x = k*ln2 + r, |r| <= 0.5*ln2 ~ 0.34658 + * + * Here a correction term c will be computed to compensate + * the error in r when rounded to a floating-point number. + * + * 2. Approximating expm1(r) by a special rational function on + * the interval [0,0.34658]: + * Since + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 - r^4/360 + ... + * we define R1(r*r) by + * r*(exp(r)+1)/(exp(r)-1) = 2+ r^2/6 * R1(r*r) + * That is, + * R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) + * = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) + * = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... + * We use a special Remez algorithm on [0,0.347] to generate + * a polynomial of degree 5 in r*r to approximate R1. The + * maximum error of this polynomial approximation is bounded + * by 2**-61. In other words, + * R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 + * where Q1 = -1.6666666666666567384E-2, + * Q2 = 3.9682539681370365873E-4, + * Q3 = -9.9206344733435987357E-6, + * Q4 = 2.5051361420808517002E-7, + * Q5 = -6.2843505682382617102E-9; + * z = r*r, + * with error bounded by + * | 5 | -61 + * | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2 + * | | + * + * expm1(r) = exp(r)-1 is then computed by the following + * specific way which minimize the accumulation rounding error: + * 2 3 + * r r [ 3 - (R1 + R1*r/2) ] + * expm1(r) = r + --- + --- * [--------------------] + * 2 2 [ 6 - r*(3 - R1*r/2) ] + * + * To compensate the error in the argument reduction, we use + * expm1(r+c) = expm1(r) + c + expm1(r)*c + * ~ expm1(r) + c + r*c + * Thus c+r*c will be added in as the correction terms for + * expm1(r+c). Now rearrange the term to avoid optimization + * screw up: + * ( 2 2 ) + * ({ ( r [ R1 - (3 - R1*r/2) ] ) } r ) + * expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) + * ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 ) + * ( ) + * + * = r - E + * 3. Scale back to obtain expm1(x): + * From step 1, we have + * expm1(x) = either 2^k*[expm1(r)+1] - 1 + * = or 2^k*[expm1(r) + (1-2^-k)] + * 4. Implementation notes: + * (A). To save one multiplication, we scale the coefficient Qi + * to Qi*2^i, and replace z by (x^2)/2. + * (B). To achieve maximum accuracy, we compute expm1(x) by + * (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf) + * (ii) if k=0, return r-E + * (iii) if k=-1, return 0.5*(r-E)-0.5 + * (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E) + * else return 1.0+2.0*(r-E); + * (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) + * (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else + * (vii) return 2^k(1-((E+2^-k)-r)) + * + * Special cases: + * expm1(INF) is INF, expm1(NaN) is NaN; + * expm1(-INF) is -1, and + * for finite argument, only expm1(0)=0 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 expm1(x) overflow + * + * 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. + */ + +#include "libm.h" + +static const double +o_threshold = 7.09782712893383973096e+02, /* 0x40862E42, 0xFEFA39EF */ +ln2_hi = 6.93147180369123816490e-01, /* 0x3fe62e42, 0xfee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 0x3dea39ef, 0x35793c76 */ +invln2 = 1.44269504088896338700e+00, /* 0x3ff71547, 0x652b82fe */ +/* Scaled Q's: Qn_here = 2**n * Qn_above, for R(2*z) where z = hxs = x*x/2: */ +Q1 = -3.33333333333331316428e-02, /* BFA11111 111110F4 */ +Q2 = 1.58730158725481460165e-03, /* 3F5A01A0 19FE5585 */ +Q3 = -7.93650757867487942473e-05, /* BF14CE19 9EAADBB7 */ +Q4 = 4.00821782732936239552e-06, /* 3ED0CFCA 86E65239 */ +Q5 = -2.01099218183624371326e-07; /* BE8AFDB7 6E09C32D */ + +double expm1(double x) +{ + double_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + union {double f; uint64_t i;} u = {x}; + uint32_t hx = u.i>>32 & 0x7fffffff; + int k, sign = u.i>>63; + + /* filter out huge and non-finite argument */ + if (hx >= 0x4043687A) { /* if |x|>=56*ln2 */ + if (isnan(x)) + return x; + if (sign) + return -1; + if (x > o_threshold) { + x *= 0x1p1023; + return x; + } + } + + /* argument reduction */ + if (hx > 0x3fd62e42) { /* if |x| > 0.5 ln2 */ + if (hx < 0x3FF0A2B2) { /* and |x| < 1.5 ln2 */ + if (!sign) { + hi = x - ln2_hi; + lo = ln2_lo; + k = 1; + } else { + hi = x + ln2_hi; + lo = -ln2_lo; + k = -1; + } + } else { + k = invln2*x + (sign ? -0.5 : 0.5); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + x = hi-lo; + c = (hi-x)-lo; + } else if (hx < 0x3c900000) { /* |x| < 2**-54, return x */ + if (hx < 0x00100000) + FORCE_EVAL((float)x); + return x; + } else + k = 0; + + /* x is now in primary range */ + hfx = 0.5*x; + hxs = x*hfx; + r1 = 1.0+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5)))); + t = 3.0-r1*hfx; + e = hxs*((r1-t)/(6.0 - x*t)); + if (k == 0) /* c is 0 */ + return x - (x*e-hxs); + e = x*(e-c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if (k == -1) + return 0.5*(x-e) - 0.5; + if (k == 1) { + if (x < -0.25) + return -2.0*(e-(x+0.5)); + return 1.0+2.0*(x-e); + } + u.i = (uint64_t)(0x3ff + k)<<52; /* 2^k */ + twopk = u.f; + if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */ + y = x - e + 1.0; + if (k == 1024) + y = y*2.0*0x1p1023; + else + y = y*twopk; + return y - 1.0; + } + u.i = (uint64_t)(0x3ff - k)<<52; /* 2^-k */ + if (k < 20) + y = (x-e+(1-u.f))*twopk; + else + y = (x-(e+u.f)+1)*twopk; + return y; +} diff --git a/system/lib/libc/musl/src/math/expm1f.c b/system/lib/libc/musl/src/math/expm1f.c new file mode 100644 index 0000000000000..297e0b44a2ebc --- /dev/null +++ b/system/lib/libc/musl/src/math/expm1f.c @@ -0,0 +1,111 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_expm1f.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +o_threshold = 8.8721679688e+01, /* 0x42b17180 */ +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +invln2 = 1.4426950216e+00, /* 0x3fb8aa3b */ +/* + * Domain [-0.34568, 0.34568], range ~[-6.694e-10, 6.696e-10]: + * |6 / x * (1 + 2 * (1 / (exp(x) - 1) - 1 / x)) - q(x)| < 2**-30.04 + * Scaled coefficients: Qn_here = 2**n * Qn_for_q (see s_expm1.c): + */ +Q1 = -3.3333212137e-2, /* -0x888868.0p-28 */ +Q2 = 1.5807170421e-3; /* 0xcf3010.0p-33 */ + +float expm1f(float x) +{ + float_t y,hi,lo,c,t,e,hxs,hfx,r1,twopk; + union {float f; uint32_t i;} u = {x}; + uint32_t hx = u.i & 0x7fffffff; + int k, sign = u.i >> 31; + + /* filter out huge and non-finite argument */ + if (hx >= 0x4195b844) { /* if |x|>=27*ln2 */ + if (hx > 0x7f800000) /* NaN */ + return x; + if (sign) + return -1; + if (x > o_threshold) { + x *= 0x1p127f; + return x; + } + } + + /* argument reduction */ + if (hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ + if (hx < 0x3F851592) { /* and |x| < 1.5 ln2 */ + if (!sign) { + hi = x - ln2_hi; + lo = ln2_lo; + k = 1; + } else { + hi = x + ln2_hi; + lo = -ln2_lo; + k = -1; + } + } else { + k = invln2*x + (sign ? -0.5f : 0.5f); + t = k; + hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ + lo = t*ln2_lo; + } + x = hi-lo; + c = (hi-x)-lo; + } else if (hx < 0x33000000) { /* when |x|<2**-25, return x */ + if (hx < 0x00800000) + FORCE_EVAL(x*x); + return x; + } else + k = 0; + + /* x is now in primary range */ + hfx = 0.5f*x; + hxs = x*hfx; + r1 = 1.0f+hxs*(Q1+hxs*Q2); + t = 3.0f - r1*hfx; + e = hxs*((r1-t)/(6.0f - x*t)); + if (k == 0) /* c is 0 */ + return x - (x*e-hxs); + e = x*(e-c) - c; + e -= hxs; + /* exp(x) ~ 2^k (x_reduced - e + 1) */ + if (k == -1) + return 0.5f*(x-e) - 0.5f; + if (k == 1) { + if (x < -0.25f) + return -2.0f*(e-(x+0.5f)); + return 1.0f + 2.0f*(x-e); + } + u.i = (0x7f+k)<<23; /* 2^k */ + twopk = u.f; + if (k < 0 || k > 56) { /* suffice to return exp(x)-1 */ + y = x - e + 1.0f; + if (k == 128) + y = y*2.0f*0x1p127f; + else + y = y*twopk; + return y - 1.0f; + } + u.i = (0x7f-k)<<23; /* 2^-k */ + if (k < 23) + y = (x-e+(1-u.f))*twopk; + else + y = (x-(e+u.f)+1)*twopk; + return y; +} diff --git a/system/lib/libc/musl/src/math/expm1l.c b/system/lib/libc/musl/src/math/expm1l.c new file mode 100644 index 0000000000000..21a86c0051878 --- /dev/null +++ b/system/lib/libc/musl/src/math/expm1l.c @@ -0,0 +1,117 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_expm1l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Exponential function, minus 1 + * Long double precision + * + * + * SYNOPSIS: + * + * long double x, y, expm1l(); + * + * y = expm1l( x ); + * + * + * DESCRIPTION: + * + * Returns e (2.71828...) raised to the x power, minus 1. + * + * Range reduction is accomplished by separating the argument + * into an integer k and fraction f such that + * + * x k f + * e = 2 e. + * + * An expansion x + .5 x^2 + x^3 R(x) approximates exp(f) - 1 + * in the basic range [-0.5 ln 2, 0.5 ln 2]. + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -45,+maxarg 200,000 1.2e-19 2.5e-20 + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double expm1l(long double x) +{ + return expm1(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 + +/* exp(x) - 1 = x + 0.5 x^2 + x^3 P(x)/Q(x) + -.5 ln 2 < x < .5 ln 2 + Theoretical peak relative error = 3.4e-22 */ +static const long double +P0 = -1.586135578666346600772998894928250240826E4L, +P1 = 2.642771505685952966904660652518429479531E3L, +P2 = -3.423199068835684263987132888286791620673E2L, +P3 = 1.800826371455042224581246202420972737840E1L, +P4 = -5.238523121205561042771939008061958820811E-1L, +Q0 = -9.516813471998079611319047060563358064497E4L, +Q1 = 3.964866271411091674556850458227710004570E4L, +Q2 = -7.207678383830091850230366618190187434796E3L, +Q3 = 7.206038318724600171970199625081491823079E2L, +Q4 = -4.002027679107076077238836622982900945173E1L, +/* Q5 = 1.000000000000000000000000000000000000000E0 */ +/* C1 + C2 = ln 2 */ +C1 = 6.93145751953125E-1L, +C2 = 1.428606820309417232121458176568075500134E-6L, +/* ln 2^-65 */ +minarg = -4.5054566736396445112120088E1L, +/* ln 2^16384 */ +maxarg = 1.1356523406294143949492E4L; + +long double expm1l(long double x) +{ + long double px, qx, xx; + int k; + + if (isnan(x)) + return x; + if (x > maxarg) + return x*0x1p16383L; /* overflow, unless x==inf */ + if (x == 0.0) + return x; + if (x < minarg) + return -1.0; + + xx = C1 + C2; + /* Express x = ln 2 (k + remainder), remainder not exceeding 1/2. */ + px = floorl(0.5 + x / xx); + k = px; + /* remainder times ln 2 */ + x -= px * C1; + x -= px * C2; + + /* Approximate exp(remainder ln 2).*/ + px = (((( P4 * x + P3) * x + P2) * x + P1) * x + P0) * x; + qx = (((( x + Q4) * x + Q3) * x + Q2) * x + Q1) * x + Q0; + xx = x * x; + qx = x + (0.5 * xx + xx * px / qx); + + /* exp(x) = exp(k ln 2) exp(remainder ln 2) = 2^k exp(remainder ln 2). + We have qx = exp(remainder ln 2) - 1, so + exp(x) - 1 = 2^k (qx + 1) - 1 = 2^k qx + 2^k - 1. */ + px = scalbnl(1.0, k); + x = px * qx + (px - 1.0); + return x; +} +#endif diff --git a/system/lib/libc/musl/src/math/fdim.c b/system/lib/libc/musl/src/math/fdim.c new file mode 100644 index 0000000000000..958546064389b --- /dev/null +++ b/system/lib/libc/musl/src/math/fdim.c @@ -0,0 +1,10 @@ +#include <math.h> + +double fdim(double x, double y) +{ + if (isnan(x)) + return x; + if (isnan(y)) + return y; + return x > y ? x - y : 0; +} diff --git a/system/lib/libc/musl/src/math/fdimf.c b/system/lib/libc/musl/src/math/fdimf.c new file mode 100644 index 0000000000000..543c3648e3ff2 --- /dev/null +++ b/system/lib/libc/musl/src/math/fdimf.c @@ -0,0 +1,10 @@ +#include <math.h> + +float fdimf(float x, float y) +{ + if (isnan(x)) + return x; + if (isnan(y)) + return y; + return x > y ? x - y : 0; +} diff --git a/system/lib/libc/musl/src/math/fdiml.c b/system/lib/libc/musl/src/math/fdiml.c new file mode 100644 index 0000000000000..62e29b7df39e1 --- /dev/null +++ b/system/lib/libc/musl/src/math/fdiml.c @@ -0,0 +1,18 @@ +#include <math.h> +#include <float.h> + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fdiml(long double x, long double y) +{ + return fdim(x, y); +} +#else +long double fdiml(long double x, long double y) +{ + if (isnan(x)) + return x; + if (isnan(y)) + return y; + return x > y ? x - y : 0; +} +#endif diff --git a/system/lib/libc/musl/src/math/finite.c b/system/lib/libc/musl/src/math/finite.c new file mode 100644 index 0000000000000..25a0575fb9757 --- /dev/null +++ b/system/lib/libc/musl/src/math/finite.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include <math.h> + +int finite(double x) +{ + return isfinite(x); +} diff --git a/system/lib/libc/musl/src/math/finitef.c b/system/lib/libc/musl/src/math/finitef.c new file mode 100644 index 0000000000000..2c4c771463a1b --- /dev/null +++ b/system/lib/libc/musl/src/math/finitef.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE +#include <math.h> + +int finitef(float x) +{ + return isfinite(x); +} diff --git a/system/lib/libc/musl/src/math/fma.c b/system/lib/libc/musl/src/math/fma.c new file mode 100644 index 0000000000000..02f5c865519d7 --- /dev/null +++ b/system/lib/libc/musl/src/math/fma.c @@ -0,0 +1,460 @@ +#include <fenv.h> +#include "libm.h" + +#if LDBL_MANT_DIG==64 && LDBL_MAX_EXP==16384 +/* exact add, assumes exponent_x >= exponent_y */ +static void add(long double *hi, long double *lo, long double x, long double y) +{ + long double r; + + r = x + y; + *hi = r; + r -= x; + *lo = y - r; +} + +/* exact mul, assumes no over/underflow */ +static void mul(long double *hi, long double *lo, long double x, long double y) +{ + static const long double c = 1.0 + 0x1p32L; + long double cx, xh, xl, cy, yh, yl; + + cx = c*x; + xh = (x - cx) + cx; + xl = x - xh; + cy = c*y; + yh = (y - cy) + cy; + yl = y - yh; + *hi = x*y; + *lo = (xh*yh - *hi) + xh*yl + xl*yh + xl*yl; +} + +/* +assume (long double)(hi+lo) == hi +return an adjusted hi so that rounding it to double (or less) precision is correct +*/ +static long double adjust(long double hi, long double lo) +{ + union ldshape uhi, ulo; + + if (lo == 0) + return hi; + uhi.f = hi; + if (uhi.i.m & 0x3ff) + return hi; + ulo.f = lo; + if ((uhi.i.se & 0x8000) == (ulo.i.se & 0x8000)) + uhi.i.m++; + else { + /* handle underflow and take care of ld80 implicit msb */ + if (uhi.i.m << 1 == 0) { + uhi.i.m = 0; + uhi.i.se--; + } + uhi.i.m--; + } + return uhi.f; +} + +/* adjusted add so the result is correct when rounded to double (or less) precision */ +static long double dadd(long double x, long double y) +{ + add(&x, &y, x, y); + return adjust(x, y); +} + +/* adjusted mul so the result is correct when rounded to double (or less) precision */ +static long double dmul(long double x, long double y) +{ + mul(&x, &y, x, y); + return adjust(x, y); +} + +static int getexp(long double x) +{ + union ldshape u; + u.f = x; + return u.i.se & 0x7fff; +} + +double fma(double x, double y, double z) +{ + #pragma STDC FENV_ACCESS ON + long double hi, lo1, lo2, xy; + int round, ez, exy; + + /* handle +-inf,nan */ + if (!isfinite(x) || !isfinite(y)) + return x*y + z; + if (!isfinite(z)) + return z; + /* handle +-0 */ + if (x == 0.0 || y == 0.0) + return x*y + z; + round = fegetround(); + if (z == 0.0) { + if (round == FE_TONEAREST) + return dmul(x, y); + return x*y; + } + + /* exact mul and add require nearest rounding */ + /* spurious inexact exceptions may be raised */ + fesetround(FE_TONEAREST); + mul(&xy, &lo1, x, y); + exy = getexp(xy); + ez = getexp(z); + if (ez > exy) { + add(&hi, &lo2, z, xy); + } else if (ez > exy - 12) { + add(&hi, &lo2, xy, z); + if (hi == 0) { + /* + xy + z is 0, but it should be calculated with the + original rounding mode so the sign is correct, if the + compiler does not support FENV_ACCESS ON it does not + know about the changed rounding mode and eliminates + the xy + z below without the volatile memory access + */ + volatile double z_; + fesetround(round); + z_ = z; + return (xy + z_) + lo1; + } + } else { + /* + ez <= exy - 12 + the 12 extra bits (1guard, 11round+sticky) are needed so with + lo = dadd(lo1, lo2) + elo <= ehi - 11, and we use the last 10 bits in adjust so + dadd(hi, lo) + gives correct result when rounded to double + */ + hi = xy; + lo2 = z; + } + /* + the result is stored before return for correct precision and exceptions + + one corner case is when the underflow flag should be raised because + the precise result is an inexact subnormal double, but the calculated + long double result is an exact subnormal double + (so rounding to double does not raise exceptions) + + in nearest rounding mode dadd takes care of this: the last bit of the + result is adjusted so rounding sees an inexact value when it should + + in non-nearest rounding mode fenv is used for the workaround + */ + fesetround(round); + if (round == FE_TONEAREST) + z = dadd(hi, dadd(lo1, lo2)); + else { +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + int e = fetestexcept(FE_INEXACT); + feclearexcept(FE_INEXACT); +#endif + z = hi + (lo1 + lo2); +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (getexp(z) < 0x3fff-1022 && fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else if (e) + feraiseexcept(FE_INEXACT); +#endif + } + return z; +} +#else +/* origin: FreeBSD /usr/src/lib/msun/src/s_fma.c */ +/*- + * Copyright (c) 2005-2011 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * A struct dd represents a floating-point number with twice the precision + * of a double. We maintain the invariant that "hi" stores the 53 high-order + * bits of the result. + */ +struct dd { + double hi; + double lo; +}; + +/* + * Compute a+b exactly, returning the exact result in a struct dd. We assume + * that both a and b are finite, but make no assumptions about their relative + * magnitudes. + */ +static inline struct dd dd_add(double a, double b) +{ + struct dd ret; + double s; + + ret.hi = a + b; + s = ret.hi - a; + ret.lo = (a - (ret.hi - s)) + (b - s); + return (ret); +} + +/* + * Compute a+b, with a small tweak: The least significant bit of the + * result is adjusted into a sticky bit summarizing all the bits that + * were lost to rounding. This adjustment negates the effects of double + * rounding when the result is added to another number with a higher + * exponent. For an explanation of round and sticky bits, see any reference + * on FPU design, e.g., + * + * J. Coonen. An Implementation Guide to a Proposed Standard for + * Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. + */ +static inline double add_adjusted(double a, double b) +{ + struct dd sum; + union {double f; uint64_t i;} uhi, ulo; + + sum = dd_add(a, b); + if (sum.lo != 0) { + uhi.f = sum.hi; + if ((uhi.i & 1) == 0) { + /* hibits += (int)copysign(1.0, sum.hi * sum.lo) */ + ulo.f = sum.lo; + uhi.i += 1 - ((uhi.i ^ ulo.i) >> 62); + sum.hi = uhi.f; + } + } + return (sum.hi); +} + +/* + * Compute ldexp(a+b, scale) with a single rounding error. It is assumed + * that the result will be subnormal, and care is taken to ensure that + * double rounding does not occur. + */ +static inline double add_and_denormalize(double a, double b, int scale) +{ + struct dd sum; + union {double f; uint64_t i;} uhi, ulo; + int bits_lost; + + sum = dd_add(a, b); + + /* + * If we are losing at least two bits of accuracy to denormalization, + * then the first lost bit becomes a round bit, and we adjust the + * lowest bit of sum.hi to make it a sticky bit summarizing all the + * bits in sum.lo. With the sticky bit adjusted, the hardware will + * break any ties in the correct direction. + * + * If we are losing only one bit to denormalization, however, we must + * break the ties manually. + */ + if (sum.lo != 0) { + uhi.f = sum.hi; + bits_lost = -((int)(uhi.i >> 52) & 0x7ff) - scale + 1; + if (bits_lost != 1 ^ (int)(uhi.i & 1)) { + /* hibits += (int)copysign(1.0, sum.hi * sum.lo) */ + ulo.f = sum.lo; + uhi.i += 1 - (((uhi.i ^ ulo.i) >> 62) & 2); + sum.hi = uhi.f; + } + } + return scalbn(sum.hi, scale); +} + +/* + * Compute a*b exactly, returning the exact result in a struct dd. We assume + * that both a and b are normalized, so no underflow or overflow will occur. + * The current rounding mode must be round-to-nearest. + */ +static inline struct dd dd_mul(double a, double b) +{ + static const double split = 0x1p27 + 1.0; + struct dd ret; + double ha, hb, la, lb, p, q; + + p = a * split; + ha = a - p; + ha += p; + la = a - ha; + + p = b * split; + hb = b - p; + hb += p; + lb = b - hb; + + p = ha * hb; + q = ha * lb + la * hb; + + ret.hi = p + q; + ret.lo = p - ret.hi + q + la * lb; + return (ret); +} + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * We use scaling to avoid overflow/underflow, along with the + * canonical precision-doubling technique adapted from: + * + * Dekker, T. A Floating-Point Technique for Extending the + * Available Precision. Numer. Math. 18, 224-242 (1971). + * + * This algorithm is sensitive to the rounding precision. FPUs such + * as the i387 must be set in double-precision mode if variables are + * to be stored in FP registers in order to avoid incorrect results. + * This is the default on FreeBSD, but not on many other systems. + * + * Hardware instructions should be used on architectures that support it, + * since this implementation will likely be several times slower. + */ +double fma(double x, double y, double z) +{ + #pragma STDC FENV_ACCESS ON + double xs, ys, zs, adj; + struct dd xy, r; + int oround; + int ex, ey, ez; + int spread; + + /* + * Handle special cases. The order of operations and the particular + * return values here are crucial in handling special cases involving + * infinities, NaNs, overflows, and signed zeroes correctly. + */ + if (!isfinite(x) || !isfinite(y)) + return (x * y + z); + if (!isfinite(z)) + return (z); + if (x == 0.0 || y == 0.0) + return (x * y + z); + if (z == 0.0) + return (x * y); + + xs = frexp(x, &ex); + ys = frexp(y, &ey); + zs = frexp(z, &ez); + oround = fegetround(); + spread = ex + ey - ez; + + /* + * If x * y and z are many orders of magnitude apart, the scaling + * will overflow, so we handle these cases specially. Rounding + * modes other than FE_TONEAREST are painful. + */ + if (spread < -DBL_MANT_DIG) { +#ifdef FE_INEXACT + feraiseexcept(FE_INEXACT); +#endif +#ifdef FE_UNDERFLOW + if (!isnormal(z)) + feraiseexcept(FE_UNDERFLOW); +#endif + switch (oround) { + default: /* FE_TONEAREST */ + return (z); +#ifdef FE_TOWARDZERO + case FE_TOWARDZERO: + if (x > 0.0 ^ y < 0.0 ^ z < 0.0) + return (z); + else + return (nextafter(z, 0)); +#endif +#ifdef FE_DOWNWARD + case FE_DOWNWARD: + if (x > 0.0 ^ y < 0.0) + return (z); + else + return (nextafter(z, -INFINITY)); +#endif +#ifdef FE_UPWARD + case FE_UPWARD: + if (x > 0.0 ^ y < 0.0) + return (nextafter(z, INFINITY)); + else + return (z); +#endif + } + } + if (spread <= DBL_MANT_DIG * 2) + zs = scalbn(zs, -spread); + else + zs = copysign(DBL_MIN, zs); + + fesetround(FE_TONEAREST); + + /* + * Basic approach for round-to-nearest: + * + * (xy.hi, xy.lo) = x * y (exact) + * (r.hi, r.lo) = xy.hi + z (exact) + * adj = xy.lo + r.lo (inexact; low bit is sticky) + * result = r.hi + adj (correctly rounded) + */ + xy = dd_mul(xs, ys); + r = dd_add(xy.hi, zs); + + spread = ex + ey; + + if (r.hi == 0.0) { + /* + * When the addends cancel to 0, ensure that the result has + * the correct sign. + */ + fesetround(oround); + volatile double vzs = zs; /* XXX gcc CSE bug workaround */ + return xy.hi + vzs + scalbn(xy.lo, spread); + } + + if (oround != FE_TONEAREST) { + /* + * There is no need to worry about double rounding in directed + * rounding modes. + * But underflow may not be raised properly, example in downward rounding: + * fma(0x1.000000001p-1000, 0x1.000000001p-30, -0x1p-1066) + */ + double ret; +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + int e = fetestexcept(FE_INEXACT); + feclearexcept(FE_INEXACT); +#endif + fesetround(oround); + adj = r.lo + xy.lo; + ret = scalbn(r.hi + adj, spread); +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (ilogb(ret) < -1022 && fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else if (e) + feraiseexcept(FE_INEXACT); +#endif + return ret; + } + + adj = add_adjusted(r.lo, xy.lo); + if (spread + ilogb(r.hi) > -1023) + return scalbn(r.hi + adj, spread); + else + return add_and_denormalize(r.hi, adj, spread); +} +#endif diff --git a/system/lib/libc/musl/src/math/fmaf.c b/system/lib/libc/musl/src/math/fmaf.c new file mode 100644 index 0000000000000..aa57feb69567c --- /dev/null +++ b/system/lib/libc/musl/src/math/fmaf.c @@ -0,0 +1,93 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_fmaf.c */ +/*- + * Copyright (c) 2005-2011 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <fenv.h> +#include <math.h> +#include <stdint.h> + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * A double has more than twice as much precision than a float, so + * direct double-precision arithmetic suffices, except where double + * rounding occurs. + */ +float fmaf(float x, float y, float z) +{ + #pragma STDC FENV_ACCESS ON + double xy, result; + union {double f; uint64_t i;} u; + int e; + + xy = (double)x * y; + result = xy + z; + u.f = result; + e = u.i>>52 & 0x7ff; + /* Common case: The double precision result is fine. */ + if ((u.i & 0x1fffffff) != 0x10000000 || /* not a halfway case */ + e == 0x7ff || /* NaN */ + result - xy == z || /* exact */ + fegetround() != FE_TONEAREST) /* not round-to-nearest */ + { + /* + underflow may not be raised correctly, example: + fmaf(0x1p-120f, 0x1p-120f, 0x1p-149f) + */ +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (e < 0x3ff-126 && e >= 0x3ff-149 && fetestexcept(FE_INEXACT)) { + feclearexcept(FE_INEXACT); + /* TODO: gcc and clang bug workaround */ + volatile float vz = z; + result = xy + vz; + if (fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else + feraiseexcept(FE_INEXACT); + } +#endif + z = result; + return z; + } + + /* + * If result is inexact, and exactly halfway between two float values, + * we need to adjust the low-order bit in the direction of the error. + */ +#ifdef FE_TOWARDZERO + fesetround(FE_TOWARDZERO); +#endif + volatile double vxy = xy; /* XXX work around gcc CSE bug */ + double adjusted_result = vxy + z; + fesetround(FE_TONEAREST); + if (result == adjusted_result) { + u.f = adjusted_result; + u.i++; + adjusted_result = u.f; + } + z = adjusted_result; + return z; +} diff --git a/system/lib/libc/musl/src/math/fmal.c b/system/lib/libc/musl/src/math/fmal.c new file mode 100644 index 0000000000000..4506aac6f6abb --- /dev/null +++ b/system/lib/libc/musl/src/math/fmal.c @@ -0,0 +1,293 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_fmal.c */ +/*- + * Copyright (c) 2005-2011 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + +#include "libm.h" +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmal(long double x, long double y, long double z) +{ + return fma(x, y, z); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#include <fenv.h> +#if LDBL_MANT_DIG == 64 +#define LASTBIT(u) (u.i.m & 1) +#define SPLIT (0x1p32L + 1) +#elif LDBL_MANT_DIG == 113 +#define LASTBIT(u) (u.i.lo & 1) +#define SPLIT (0x1p57L + 1) +#endif + +/* + * A struct dd represents a floating-point number with twice the precision + * of a long double. We maintain the invariant that "hi" stores the high-order + * bits of the result. + */ +struct dd { + long double hi; + long double lo; +}; + +/* + * Compute a+b exactly, returning the exact result in a struct dd. We assume + * that both a and b are finite, but make no assumptions about their relative + * magnitudes. + */ +static inline struct dd dd_add(long double a, long double b) +{ + struct dd ret; + long double s; + + ret.hi = a + b; + s = ret.hi - a; + ret.lo = (a - (ret.hi - s)) + (b - s); + return (ret); +} + +/* + * Compute a+b, with a small tweak: The least significant bit of the + * result is adjusted into a sticky bit summarizing all the bits that + * were lost to rounding. This adjustment negates the effects of double + * rounding when the result is added to another number with a higher + * exponent. For an explanation of round and sticky bits, see any reference + * on FPU design, e.g., + * + * J. Coonen. An Implementation Guide to a Proposed Standard for + * Floating-Point Arithmetic. Computer, vol. 13, no. 1, Jan 1980. + */ +static inline long double add_adjusted(long double a, long double b) +{ + struct dd sum; + union ldshape u; + + sum = dd_add(a, b); + if (sum.lo != 0) { + u.f = sum.hi; + if (!LASTBIT(u)) + sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return (sum.hi); +} + +/* + * Compute ldexp(a+b, scale) with a single rounding error. It is assumed + * that the result will be subnormal, and care is taken to ensure that + * double rounding does not occur. + */ +static inline long double add_and_denormalize(long double a, long double b, int scale) +{ + struct dd sum; + int bits_lost; + union ldshape u; + + sum = dd_add(a, b); + + /* + * If we are losing at least two bits of accuracy to denormalization, + * then the first lost bit becomes a round bit, and we adjust the + * lowest bit of sum.hi to make it a sticky bit summarizing all the + * bits in sum.lo. With the sticky bit adjusted, the hardware will + * break any ties in the correct direction. + * + * If we are losing only one bit to denormalization, however, we must + * break the ties manually. + */ + if (sum.lo != 0) { + u.f = sum.hi; + bits_lost = -u.i.se - scale + 1; + if ((bits_lost != 1) ^ LASTBIT(u)) + sum.hi = nextafterl(sum.hi, INFINITY * sum.lo); + } + return scalbnl(sum.hi, scale); +} + +/* + * Compute a*b exactly, returning the exact result in a struct dd. We assume + * that both a and b are normalized, so no underflow or overflow will occur. + * The current rounding mode must be round-to-nearest. + */ +static inline struct dd dd_mul(long double a, long double b) +{ + struct dd ret; + long double ha, hb, la, lb, p, q; + + p = a * SPLIT; + ha = a - p; + ha += p; + la = a - ha; + + p = b * SPLIT; + hb = b - p; + hb += p; + lb = b - hb; + + p = ha * hb; + q = ha * lb + la * hb; + + ret.hi = p + q; + ret.lo = p - ret.hi + q + la * lb; + return (ret); +} + +/* + * Fused multiply-add: Compute x * y + z with a single rounding error. + * + * We use scaling to avoid overflow/underflow, along with the + * canonical precision-doubling technique adapted from: + * + * Dekker, T. A Floating-Point Technique for Extending the + * Available Precision. Numer. Math. 18, 224-242 (1971). + */ +long double fmal(long double x, long double y, long double z) +{ + #pragma STDC FENV_ACCESS ON + long double xs, ys, zs, adj; + struct dd xy, r; + int oround; + int ex, ey, ez; + int spread; + + /* + * Handle special cases. The order of operations and the particular + * return values here are crucial in handling special cases involving + * infinities, NaNs, overflows, and signed zeroes correctly. + */ + if (!isfinite(x) || !isfinite(y)) + return (x * y + z); + if (!isfinite(z)) + return (z); + if (x == 0.0 || y == 0.0) + return (x * y + z); + if (z == 0.0) + return (x * y); + + xs = frexpl(x, &ex); + ys = frexpl(y, &ey); + zs = frexpl(z, &ez); + oround = fegetround(); + spread = ex + ey - ez; + + /* + * If x * y and z are many orders of magnitude apart, the scaling + * will overflow, so we handle these cases specially. Rounding + * modes other than FE_TONEAREST are painful. + */ + if (spread < -LDBL_MANT_DIG) { +#ifdef FE_INEXACT + feraiseexcept(FE_INEXACT); +#endif +#ifdef FE_UNDERFLOW + if (!isnormal(z)) + feraiseexcept(FE_UNDERFLOW); +#endif + switch (oround) { + default: /* FE_TONEAREST */ + return (z); +#ifdef FE_TOWARDZERO + case FE_TOWARDZERO: + if (x > 0.0 ^ y < 0.0 ^ z < 0.0) + return (z); + else + return (nextafterl(z, 0)); +#endif +#ifdef FE_DOWNWARD + case FE_DOWNWARD: + if (x > 0.0 ^ y < 0.0) + return (z); + else + return (nextafterl(z, -INFINITY)); +#endif +#ifdef FE_UPWARD + case FE_UPWARD: + if (x > 0.0 ^ y < 0.0) + return (nextafterl(z, INFINITY)); + else + return (z); +#endif + } + } + if (spread <= LDBL_MANT_DIG * 2) + zs = scalbnl(zs, -spread); + else + zs = copysignl(LDBL_MIN, zs); + + fesetround(FE_TONEAREST); + + /* + * Basic approach for round-to-nearest: + * + * (xy.hi, xy.lo) = x * y (exact) + * (r.hi, r.lo) = xy.hi + z (exact) + * adj = xy.lo + r.lo (inexact; low bit is sticky) + * result = r.hi + adj (correctly rounded) + */ + xy = dd_mul(xs, ys); + r = dd_add(xy.hi, zs); + + spread = ex + ey; + + if (r.hi == 0.0) { + /* + * When the addends cancel to 0, ensure that the result has + * the correct sign. + */ + fesetround(oround); + volatile long double vzs = zs; /* XXX gcc CSE bug workaround */ + return xy.hi + vzs + scalbnl(xy.lo, spread); + } + + if (oround != FE_TONEAREST) { + /* + * There is no need to worry about double rounding in directed + * rounding modes. + * But underflow may not be raised correctly, example in downward rounding: + * fmal(0x1.0000000001p-16000L, 0x1.0000000001p-400L, -0x1p-16440L) + */ + long double ret; +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + int e = fetestexcept(FE_INEXACT); + feclearexcept(FE_INEXACT); +#endif + fesetround(oround); + adj = r.lo + xy.lo; + ret = scalbnl(r.hi + adj, spread); +#if defined(FE_INEXACT) && defined(FE_UNDERFLOW) + if (ilogbl(ret) < -16382 && fetestexcept(FE_INEXACT)) + feraiseexcept(FE_UNDERFLOW); + else if (e) + feraiseexcept(FE_INEXACT); +#endif + return ret; + } + + adj = add_adjusted(r.lo, xy.lo); + if (spread + ilogbl(r.hi) > -16383) + return scalbnl(r.hi + adj, spread); + else + return add_and_denormalize(r.hi, adj, spread); +} +#endif diff --git a/system/lib/libc/musl/src/math/fmax.c b/system/lib/libc/musl/src/math/fmax.c new file mode 100644 index 0000000000000..94f0caa17751b --- /dev/null +++ b/system/lib/libc/musl/src/math/fmax.c @@ -0,0 +1,13 @@ +#include <math.h> + +double fmax(double x, double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? y : x; + return x < y ? y : x; +} diff --git a/system/lib/libc/musl/src/math/fmaxf.c b/system/lib/libc/musl/src/math/fmaxf.c new file mode 100644 index 0000000000000..695d8179c6c1c --- /dev/null +++ b/system/lib/libc/musl/src/math/fmaxf.c @@ -0,0 +1,13 @@ +#include <math.h> + +float fmaxf(float x, float y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeroes, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? y : x; + return x < y ? y : x; +} diff --git a/system/lib/libc/musl/src/math/fmaxl.c b/system/lib/libc/musl/src/math/fmaxl.c new file mode 100644 index 0000000000000..4b03158e06292 --- /dev/null +++ b/system/lib/libc/musl/src/math/fmaxl.c @@ -0,0 +1,21 @@ +#include <math.h> +#include <float.h> + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmaxl(long double x, long double y) +{ + return fmax(x, y); +} +#else +long double fmaxl(long double x, long double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? y : x; + return x < y ? y : x; +} +#endif diff --git a/system/lib/libc/musl/src/math/fmin.c b/system/lib/libc/musl/src/math/fmin.c new file mode 100644 index 0000000000000..08a8fd17f29e3 --- /dev/null +++ b/system/lib/libc/musl/src/math/fmin.c @@ -0,0 +1,13 @@ +#include <math.h> + +double fmin(double x, double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? x : y; + return x < y ? x : y; +} diff --git a/system/lib/libc/musl/src/math/fminf.c b/system/lib/libc/musl/src/math/fminf.c new file mode 100644 index 0000000000000..3573c7de741e1 --- /dev/null +++ b/system/lib/libc/musl/src/math/fminf.c @@ -0,0 +1,13 @@ +#include <math.h> + +float fminf(float x, float y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? x : y; + return x < y ? x : y; +} diff --git a/system/lib/libc/musl/src/math/fminl.c b/system/lib/libc/musl/src/math/fminl.c new file mode 100644 index 0000000000000..69bc24a79bef7 --- /dev/null +++ b/system/lib/libc/musl/src/math/fminl.c @@ -0,0 +1,21 @@ +#include <math.h> +#include <float.h> + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fminl(long double x, long double y) +{ + return fmin(x, y); +} +#else +long double fminl(long double x, long double y) +{ + if (isnan(x)) + return y; + if (isnan(y)) + return x; + /* handle signed zeros, see C99 Annex F.9.9.2 */ + if (signbit(x) != signbit(y)) + return signbit(x) ? x : y; + return x < y ? x : y; +} +#endif diff --git a/system/lib/libc/musl/src/math/fmod.c b/system/lib/libc/musl/src/math/fmod.c new file mode 100644 index 0000000000000..6849722bac50e --- /dev/null +++ b/system/lib/libc/musl/src/math/fmod.c @@ -0,0 +1,68 @@ +#include <math.h> +#include <stdint.h> + +double fmod(double x, double y) +{ + union {double f; uint64_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>52 & 0x7ff; + int ey = uy.i>>52 & 0x7ff; + int sx = ux.i>>63; + uint64_t i; + + /* in the followings uxi should be ux.i, but then gcc wrongly adds */ + /* float load/store to inner loops ruining performance and code size */ + uint64_t uxi = ux.i; + + if (uy.i<<1 == 0 || isnan(y) || ex == 0x7ff) + return (x*y)/(x*y); + if (uxi<<1 <= uy.i<<1) { + if (uxi<<1 == uy.i<<1) + return 0*x; + return x; + } + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<12; i>>63 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1ULL >> 12; + uxi |= 1ULL << 52; + } + if (!ey) { + for (i = uy.i<<12; i>>63 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1ULL >> 12; + uy.i |= 1ULL << 52; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 63 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + for (; uxi>>52 == 0; uxi <<= 1, ex--); + + /* scale result */ + if (ex > 0) { + uxi -= 1ULL << 52; + uxi |= (uint64_t)ex << 52; + } else { + uxi >>= -ex + 1; + } + uxi |= (uint64_t)sx << 63; + ux.i = uxi; + return ux.f; +} diff --git a/system/lib/libc/musl/src/math/fmodf.c b/system/lib/libc/musl/src/math/fmodf.c new file mode 100644 index 0000000000000..ff58f93365b47 --- /dev/null +++ b/system/lib/libc/musl/src/math/fmodf.c @@ -0,0 +1,65 @@ +#include <math.h> +#include <stdint.h> + +float fmodf(float x, float y) +{ + union {float f; uint32_t i;} ux = {x}, uy = {y}; + int ex = ux.i>>23 & 0xff; + int ey = uy.i>>23 & 0xff; + uint32_t sx = ux.i & 0x80000000; + uint32_t i; + uint32_t uxi = ux.i; + + if (uy.i<<1 == 0 || isnan(y) || ex == 0xff) + return (x*y)/(x*y); + if (uxi<<1 <= uy.i<<1) { + if (uxi<<1 == uy.i<<1) + return 0*x; + return x; + } + + /* normalize x and y */ + if (!ex) { + for (i = uxi<<9; i>>31 == 0; ex--, i <<= 1); + uxi <<= -ex + 1; + } else { + uxi &= -1U >> 9; + uxi |= 1U << 23; + } + if (!ey) { + for (i = uy.i<<9; i>>31 == 0; ey--, i <<= 1); + uy.i <<= -ey + 1; + } else { + uy.i &= -1U >> 9; + uy.i |= 1U << 23; + } + + /* x mod y */ + for (; ex > ey; ex--) { + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + uxi <<= 1; + } + i = uxi - uy.i; + if (i >> 31 == 0) { + if (i == 0) + return 0*x; + uxi = i; + } + for (; uxi>>23 == 0; uxi <<= 1, ex--); + + /* scale result up */ + if (ex > 0) { + uxi -= 1U << 23; + uxi |= (uint32_t)ex << 23; + } else { + uxi >>= -ex + 1; + } + uxi |= sx; + ux.i = uxi; + return ux.f; +} diff --git a/system/lib/libc/musl/src/math/fmodl.c b/system/lib/libc/musl/src/math/fmodl.c new file mode 100644 index 0000000000000..54af6a3fd1592 --- /dev/null +++ b/system/lib/libc/musl/src/math/fmodl.c @@ -0,0 +1,105 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double fmodl(long double x, long double y) +{ + return fmod(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +long double fmodl(long double x, long double y) +{ + union ldshape ux = {x}, uy = {y}; + int ex = ux.i.se & 0x7fff; + int ey = uy.i.se & 0x7fff; + int sx = ux.i.se & 0x8000; + + if (y == 0 || isnan(y) || ex == 0x7fff) + return (x*y)/(x*y); + ux.i.se = ex; + uy.i.se = ey; + if (ux.f <= uy.f) { + if (ux.f == uy.f) + return 0*x; + return x; + } + + /* normalize x and y */ + if (!ex) { + ux.f *= 0x1p120f; + ex = ux.i.se - 120; + } + if (!ey) { + uy.f *= 0x1p120f; + ey = uy.i.se - 120; + } + + /* x mod y */ +#if LDBL_MANT_DIG == 64 + uint64_t i, mx, my; + mx = ux.i.m; + my = uy.i.m; + for (; ex > ey; ex--) { + i = mx - my; + if (mx >= my) { + if (i == 0) + return 0*x; + mx = 2*i; + } else if (2*mx < mx) { + mx = 2*mx - my; + } else { + mx = 2*mx; + } + } + i = mx - my; + if (mx >= my) { + if (i == 0) + return 0*x; + mx = i; + } + for (; mx >> 63 == 0; mx *= 2, ex--); + ux.i.m = mx; +#elif LDBL_MANT_DIG == 113 + uint64_t hi, lo, xhi, xlo, yhi, ylo; + xhi = (ux.i2.hi & -1ULL>>16) | 1ULL<<48; + yhi = (uy.i2.hi & -1ULL>>16) | 1ULL<<48; + xlo = ux.i2.lo; + ylo = ux.i2.lo; + for (; ex > ey; ex--) { + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + if ((hi|lo) == 0) + return 0*x; + xhi = 2*hi + (lo>>63); + xlo = 2*lo; + } else { + xhi = 2*xhi + (xlo>>63); + xlo = 2*xlo; + } + } + hi = xhi - yhi; + lo = xlo - ylo; + if (xlo < ylo) + hi -= 1; + if (hi >> 63 == 0) { + if ((hi|lo) == 0) + return 0*x; + xhi = hi; + xlo = lo; + } + for (; xhi >> 48 == 0; xhi = 2*xhi + (xlo>>63), xlo = 2*xlo, ex--); + ux.i2.hi = xhi; + ux.i2.lo = xlo; +#endif + + /* scale result */ + if (ex <= 0) { + ux.i.se = (ex+120)|sx; + ux.f *= 0x1p-120f; + } else + ux.i.se = ex|sx; + return ux.f; +} +#endif diff --git a/system/lib/libc/musl/src/math/hypot.c b/system/lib/libc/musl/src/math/hypot.c new file mode 100644 index 0000000000000..29ec6a476d1bf --- /dev/null +++ b/system/lib/libc/musl/src/math/hypot.c @@ -0,0 +1,67 @@ +#include <math.h> +#include <stdint.h> +#include <float.h> + +#if FLT_EVAL_METHOD > 1U && LDBL_MANT_DIG == 64 +#define SPLIT (0x1p32 + 1) +#else +#define SPLIT (0x1p27 + 1) +#endif + +static void sq(double_t *hi, double_t *lo, double x) +{ + double_t xh, xl, xc; + + xc = x*SPLIT; + xh = x - xc + xc; + xl = x - xh; + *hi = x*x; + *lo = xh*xh - *hi + 2*xh*xl + xl*xl; +} + +double hypot(double x, double y) +{ + union {double f; uint64_t i;} ux = {x}, uy = {y}, ut; + int ex, ey; + double_t hx, lx, hy, ly, z; + + /* arrange |x| >= |y| */ + ux.i &= -1ULL>>1; + uy.i &= -1ULL>>1; + if (ux.i < uy.i) { + ut = ux; + ux = uy; + uy = ut; + } + + /* special cases */ + ex = ux.i>>52; + ey = uy.i>>52; + x = ux.f; + y = uy.f; + /* note: hypot(inf,nan) == inf */ + if (ey == 0x7ff) + return y; + if (ex == 0x7ff || uy.i == 0) + return x; + /* note: hypot(x,y) ~= x + y*y/x/2 with inexact for small y/x */ + /* 64 difference is enough for ld80 double_t */ + if (ex - ey > 64) + return x + y; + + /* precise sqrt argument in nearest rounding mode without overflow */ + /* xh*xh must not overflow and xl*xl must not underflow in sq */ + z = 1; + if (ex > 0x3ff+510) { + z = 0x1p700; + x *= 0x1p-700; + y *= 0x1p-700; + } else if (ey < 0x3ff-450) { + z = 0x1p-700; + x *= 0x1p700; + y *= 0x1p700; + } + sq(&hx, &lx, x); + sq(&hy, &ly, y); + return z*sqrt(ly+lx+hy+hx); +} diff --git a/system/lib/libc/musl/src/math/hypotf.c b/system/lib/libc/musl/src/math/hypotf.c new file mode 100644 index 0000000000000..2fc214b7232e0 --- /dev/null +++ b/system/lib/libc/musl/src/math/hypotf.c @@ -0,0 +1,35 @@ +#include <math.h> +#include <stdint.h> + +float hypotf(float x, float y) +{ + union {float f; uint32_t i;} ux = {x}, uy = {y}, ut; + float_t z; + + ux.i &= -1U>>1; + uy.i &= -1U>>1; + if (ux.i < uy.i) { + ut = ux; + ux = uy; + uy = ut; + } + + x = ux.f; + y = uy.f; + if (uy.i == 0xff<<23) + return y; + if (ux.i >= 0xff<<23 || uy.i == 0 || ux.i - uy.i >= 25<<23) + return x + y; + + z = 1; + if (ux.i >= (0x7f+60)<<23) { + z = 0x1p90f; + x *= 0x1p-90f; + y *= 0x1p-90f; + } else if (uy.i < (0x7f-60)<<23) { + z = 0x1p-90f; + x *= 0x1p90f; + y *= 0x1p90f; + } + return z*sqrtf((double)x*x + (double)y*y); +} diff --git a/system/lib/libc/musl/src/math/hypotl.c b/system/lib/libc/musl/src/math/hypotl.c new file mode 100644 index 0000000000000..479aa92c3dc29 --- /dev/null +++ b/system/lib/libc/musl/src/math/hypotl.c @@ -0,0 +1,66 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double hypotl(long double x, long double y) +{ + return hypot(x, y); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +#define SPLIT (0x1p32L+1) +#elif LDBL_MANT_DIG == 113 +#define SPLIT (0x1p57L+1) +#endif + +static void sq(long double *hi, long double *lo, long double x) +{ + long double xh, xl, xc; + xc = x*SPLIT; + xh = x - xc + xc; + xl = x - xh; + *hi = x*x; + *lo = xh*xh - *hi + 2*xh*xl + xl*xl; +} + +long double hypotl(long double x, long double y) +{ + union ldshape ux = {x}, uy = {y}; + int ex, ey; + long double hx, lx, hy, ly, z; + + ux.i.se &= 0x7fff; + uy.i.se &= 0x7fff; + if (ux.i.se < uy.i.se) { + ex = uy.i.se; + ey = ux.i.se; + x = uy.f; + y = ux.f; + } else { + ex = ux.i.se; + ey = uy.i.se; + x = ux.f; + y = uy.f; + } + + if (ex == 0x7fff && isinf(y)) + return y; + if (ex == 0x7fff || y == 0) + return x; + if (ex - ey > LDBL_MANT_DIG) + return x + y; + + z = 1; + if (ex > 0x3fff+8000) { + z = 0x1p10000L; + x *= 0x1p-10000L; + y *= 0x1p-10000L; + } else if (ey < 0x3fff-8000) { + z = 0x1p-10000L; + x *= 0x1p10000L; + y *= 0x1p10000L; + } + sq(&hx, &lx, x); + sq(&hy, &ly, y); + return z*sqrtl(ly+lx+hy+hx); +} +#endif diff --git a/system/lib/libc/musl/src/math/llrint.c b/system/lib/libc/musl/src/math/llrint.c new file mode 100644 index 0000000000000..4f583ae5536aa --- /dev/null +++ b/system/lib/libc/musl/src/math/llrint.c @@ -0,0 +1,8 @@ +#include <math.h> + +/* uses LLONG_MAX > 2^53, see comments in lrint.c */ + +long long llrint(double x) +{ + return rint(x); +} diff --git a/system/lib/libc/musl/src/math/llrintf.c b/system/lib/libc/musl/src/math/llrintf.c new file mode 100644 index 0000000000000..96949a006ea88 --- /dev/null +++ b/system/lib/libc/musl/src/math/llrintf.c @@ -0,0 +1,8 @@ +#include <math.h> + +/* uses LLONG_MAX > 2^24, see comments in lrint.c */ + +long long llrintf(float x) +{ + return rintf(x); +} diff --git a/system/lib/libc/musl/src/math/llrintl.c b/system/lib/libc/musl/src/math/llrintl.c new file mode 100644 index 0000000000000..3449f6f2b4009 --- /dev/null +++ b/system/lib/libc/musl/src/math/llrintl.c @@ -0,0 +1,36 @@ +#include <limits.h> +#include <fenv.h> +#include "libm.h" + + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long long llrintl(long double x) +{ + return llrint(x); +} +#elif defined(FE_INEXACT) +/* +see comments in lrint.c + +Note that if LLONG_MAX == 0x7fffffffffffffff && LDBL_MANT_DIG == 64 +then x == 2**63 - 0.5 is the only input that overflows and +raises inexact (with tonearest or upward rounding mode) +*/ +long long llrintl(long double x) +{ + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rintl(x); + if (!e && (x > LLONG_MAX || x < LLONG_MIN)) + feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long long llrintl(long double x) +{ + return rintl(x); +} +#endif diff --git a/system/lib/libc/musl/src/math/llround.c b/system/lib/libc/musl/src/math/llround.c new file mode 100644 index 0000000000000..4d94787d62275 --- /dev/null +++ b/system/lib/libc/musl/src/math/llround.c @@ -0,0 +1,6 @@ +#include <math.h> + +long long llround(double x) +{ + return round(x); +} diff --git a/system/lib/libc/musl/src/math/llroundf.c b/system/lib/libc/musl/src/math/llroundf.c new file mode 100644 index 0000000000000..19eb77ee3d568 --- /dev/null +++ b/system/lib/libc/musl/src/math/llroundf.c @@ -0,0 +1,6 @@ +#include <math.h> + +long long llroundf(float x) +{ + return roundf(x); +} diff --git a/system/lib/libc/musl/src/math/llroundl.c b/system/lib/libc/musl/src/math/llroundl.c new file mode 100644 index 0000000000000..2c2ee5ecd6859 --- /dev/null +++ b/system/lib/libc/musl/src/math/llroundl.c @@ -0,0 +1,6 @@ +#include <math.h> + +long long llroundl(long double x) +{ + return roundl(x); +} diff --git a/system/lib/libc/musl/src/math/log10.c b/system/lib/libc/musl/src/math/log10.c new file mode 100644 index 0000000000000..81026876b223d --- /dev/null +++ b/system/lib/libc/musl/src/math/log10.c @@ -0,0 +1,101 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 10 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log10(x) = (f - f*f/2 + r)/log(10) + k*log10(2) + */ + +#include <math.h> +#include <stdint.h> + +static const double +ivln10hi = 4.34294481878168880939e-01, /* 0x3fdbcb7b, 0x15200000 */ +ivln10lo = 2.50829467116452752298e-11, /* 0x3dbb9438, 0xca9aadd5 */ +log10_2hi = 3.01029995663611771306e-01, /* 0x3FD34413, 0x509F6000 */ +log10_2lo = 3.69423907715893078616e-13, /* 0x3D59FEF3, 0x11F12B36 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log10(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,s,z,R,w,t1,t2,dk,y,hi,lo,val_hi,val_lo; + uint32_t hx; + int k; + + hx = u.i>>32; + k = 0; + if (hx < 0x00100000 || hx>>31) { + if (u.i<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (hx>>31) + return (x-x)/0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i>>32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i<<32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx>>20) - 0x3ff; + hx = (hx&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx<<32 | (u.i&0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + + /* See log2.c for details. */ + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + u.f = hi; + u.i &= (uint64_t)-1<<32; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + + /* val_hi+val_lo ~ log10(1+f) + k*log10(2) */ + val_hi = hi*ivln10hi; + dk = k; + y = dk*log10_2hi; + val_lo = dk*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi; + + /* + * Extra precision in for adding y is not strictly needed + * since there is no very large cancellation near x = sqrt(2) or + * x = 1/sqrt(2), but we do it anyway since it costs little on CPUs + * with some parallelism and it reduces the error for many args. + */ + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/system/lib/libc/musl/src/math/log10f.c b/system/lib/libc/musl/src/math/log10f.c new file mode 100644 index 0000000000000..9ca2f017da666 --- /dev/null +++ b/system/lib/libc/musl/src/math/log10f.c @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log10f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log10.c. + */ + +#include <math.h> +#include <stdint.h> + +static const float +ivln10hi = 4.3432617188e-01, /* 0x3ede6000 */ +ivln10lo = -3.1689971365e-05, /* 0xb804ead9 */ +log10_2hi = 3.0102920532e-01, /* 0x3e9a2080 */ +log10_2lo = 7.9034151668e-07, /* 0x355427db */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log10f(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,s,z,R,w,t1,t2,dk,hi,lo; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix>>31) { /* x < 2**-126 */ + if (ix<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (ix>>31) + return (x-x)/0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix>>23) - 0x7f; + ix = (ix&0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + + hi = f - hfsq; + u.f = hi; + u.i &= 0xfffff000; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + dk = k; + return dk*log10_2lo + (lo+hi)*ivln10lo + lo*ivln10hi + hi*ivln10hi + dk*log10_2hi; +} diff --git a/system/lib/libc/musl/src/math/log10l.c b/system/lib/libc/musl/src/math/log10l.c new file mode 100644 index 0000000000000..c7aacf909a451 --- /dev/null +++ b/system/lib/libc/musl/src/math/log10l.c @@ -0,0 +1,185 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_log10l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Common logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log10l(); + * + * y = log10l( x ); + * + * + * DESCRIPTION: + * + * Returns the base 10 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 9.0e-20 2.6e-20 + * IEEE exp(+-10000) 30000 6.0e-20 2.3e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + * + * ERROR MESSAGES: + * + * log singularity: x = 0; returns MINLOG + * log domain: x < 0; returns MINLOG + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log10l(long double x) +{ + return log10(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.2e-22 + */ +static const long double P[] = { + 4.9962495940332550844739E-1L, + 1.0767376367209449010438E1L, + 7.7671073698359539859595E1L, + 2.5620629828144409632571E2L, + 4.2401812743503691187826E2L, + 3.4258224542413922935104E2L, + 1.0747524399916215149070E2L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 2.3479774160285863271658E1L, + 1.9444210022760132894510E2L, + 7.7952888181207260646090E2L, + 1.6911722418503949084863E3L, + 2.0307734695595183428202E3L, + 1.2695660352705325274404E3L, + 3.2242573199748645407652E2L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +/* log10(2) */ +#define L102A 0.3125L +#define L102B -1.1470004336018804786261e-2L +/* log10(e) */ +#define L10EA 0.5L +#define L10EB -6.5705518096748172348871e-2L + +#define SQRTH 0.70710678118654752440L + +long double log10l(long double x) +{ + long double y, z; + int e; + + if (isnan(x)) + return x; + if(x <= 0.0) { + if(x == 0.0) + return -1.0 / (x*x); + return (x - x) / 0.0; + } + if (x == INFINITY) + return INFINITY; + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + y = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + goto done; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0*x - 1.0; + } else { + x = x - 1.0; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 7)); + y = y - 0.5*z; + +done: + /* Multiply log of fraction by log10(e) + * and base 2 exponent by log10(2). + * + * ***CAUTION*** + * + * This sequence of operations is critical and it may + * be horribly defeated by some compiler optimizers. + */ + z = y * (L10EB); + z += x * (L10EB); + z += e * (L102B); + z += y * (L10EA); + z += x * (L10EA); + z += e * (L102A); + return z; +} +#endif diff --git a/system/lib/libc/musl/src/math/log1p.c b/system/lib/libc/musl/src/math/log1p.c new file mode 100644 index 0000000000000..0097134940378 --- /dev/null +++ b/system/lib/libc/musl/src/math/log1p.c @@ -0,0 +1,122 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* double log1p(double x) + * Return the natural logarithm of 1+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 log(1+f): See log.c + * + * 3. Finally, log1p(x) = k*ln2 + log(1+f) + c/u. See log.c + * + * 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. + */ + +#include "libm.h" + +static const double +ln2_hi = 6.93147180369123816490e-01, /* 3fe62e42 fee00000 */ +ln2_lo = 1.90821492927058770002e-10, /* 3dea39ef 35793c76 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log1p(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,c,s,z,R,w,t1,t2,dk; + uint32_t hx,hu; + int k; + + hx = u.i>>32; + k = 1; + if (hx < 0x3fda827a || hx>>31) { /* 1+x < sqrt(2)+ */ + if (hx >= 0xbff00000) { /* x <= -1.0 */ + if (x == -1) + return x/0.0; /* log1p(-1) = -inf */ + return (x-x)/0.0; /* log1p(x<-1) = NaN */ + } + if (hx<<1 < 0x3ca00000<<1) { /* |x| < 2**-53 */ + /* underflow if subnormal */ + if ((hx&0x7ff00000) == 0) + FORCE_EVAL((float)x); + return x; + } + if (hx <= 0xbfd2bec4) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0; + f = x; + } + } else if (hx >= 0x7ff00000) + return x; + if (k) { + u.f = 1 + x; + hu = u.i>>32; + hu += 0x3ff00000 - 0x3fe6a09e; + k = (int)(hu>>20) - 0x3ff; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if (k < 54) { + c = k >= 2 ? 1-(u.f-x) : x-(u.f-1); + c /= u.f; + } else + c = 0; + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + hu = (hu&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hu<<32 | (u.i&0xffffffff); + f = u.f - 1; + } + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + dk = k; + return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi; +} diff --git a/system/lib/libc/musl/src/math/log1pf.c b/system/lib/libc/musl/src/math/log1pf.c new file mode 100644 index 0000000000000..23985c3567584 --- /dev/null +++ b/system/lib/libc/musl/src/math/log1pf.c @@ -0,0 +1,77 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#include "libm.h" + +static const float +ln2_hi = 6.9313812256e-01, /* 0x3f317180 */ +ln2_lo = 9.0580006145e-06, /* 0x3717f7d1 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log1pf(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,c,s,z,R,w,t1,t2,dk; + uint32_t ix,iu; + int k; + + ix = u.i; + k = 1; + if (ix < 0x3ed413d0 || ix>>31) { /* 1+x < sqrt(2)+ */ + if (ix >= 0xbf800000) { /* x <= -1.0 */ + if (x == -1) + return x/0.0f; /* log1p(-1)=+inf */ + return (x-x)/0.0f; /* log1p(x<-1)=NaN */ + } + if (ix<<1 < 0x33800000<<1) { /* |x| < 2**-24 */ + /* underflow if subnormal */ + if ((ix&0x7f800000) == 0) + FORCE_EVAL(x*x); + return x; + } + if (ix <= 0xbe95f619) { /* sqrt(2)/2- <= 1+x < sqrt(2)+ */ + k = 0; + c = 0; + f = x; + } + } else if (ix >= 0x7f800000) + return x; + if (k) { + u.f = 1 + x; + iu = u.i; + iu += 0x3f800000 - 0x3f3504f3; + k = (int)(iu>>23) - 0x7f; + /* correction term ~ log(1+x)-log(u), avoid underflow in c/u */ + if (k < 25) { + c = k >= 2 ? 1-(u.f-x) : x-(u.f-1); + c /= u.f; + } else + c = 0; + /* reduce u into [sqrt(2)/2, sqrt(2)] */ + iu = (iu&0x007fffff) + 0x3f3504f3; + u.i = iu; + f = u.f - 1; + } + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + dk = k; + return s*(hfsq+R) + (dk*ln2_lo+c) - hfsq + f + dk*ln2_hi; +} diff --git a/system/lib/libc/musl/src/math/log1pl.c b/system/lib/libc/musl/src/math/log1pl.c new file mode 100644 index 0000000000000..37da46d23914b --- /dev/null +++ b/system/lib/libc/musl/src/math/log1pl.c @@ -0,0 +1,171 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/s_log1pl.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Relative error logarithm + * Natural logarithm of 1+x, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log1pl(); + * + * y = log1pl( x ); + * + * + * DESCRIPTION: + * + * Returns the base e (2.718...) logarithm of 1+x. + * + * The argument 1+x is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the logarithm + * of the fraction is approximated by + * + * log(1+x) = x - 0.5 x^2 + x^3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z^3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE -1.0, 9.0 100000 8.2e-20 2.5e-20 + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log1pl(long double x) +{ + return log1p(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for log(1+x) = x - x^2 / 2 + x^3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 2.32e-20 + */ +static const long double P[] = { + 4.5270000862445199635215E-5L, + 4.9854102823193375972212E-1L, + 6.5787325942061044846969E0L, + 2.9911919328553073277375E1L, + 6.0949667980987787057556E1L, + 5.7112963590585538103336E1L, + 2.0039553499201281259648E1L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 1.5062909083469192043167E1L, + 8.3047565967967209469434E1L, + 2.2176239823732856465394E2L, + 3.0909872225312059774938E2L, + 2.1642788614495947685003E2L, + 6.0118660497603843919306E1L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +static const long double C1 = 6.9314575195312500000000E-1L; +static const long double C2 = 1.4286068203094172321215E-6L; + +#define SQRTH 0.70710678118654752440L + +long double log1pl(long double xm1) +{ + long double x, y, z; + int e; + + if (isnan(xm1)) + return xm1; + if (xm1 == INFINITY) + return xm1; + if (xm1 == 0.0) + return xm1; + + x = xm1 + 1.0; + + /* Test for domain errors. */ + if (x <= 0.0) { + if (x == 0.0) + return -1/(x*x); /* -inf with divbyzero */ + return 0/0.0f; /* nan with invalid */ + } + + /* Separate mantissa from exponent. + Use frexp so that denormal numbers will be handled properly. */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z^3 P(z)/Q(z), + where z = 2(x-1)/x+1) */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + z = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + z = z + e * C2; + z = z + x; + z = z + e * C1; + return z; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + if (e != 0) + x = 2.0 * x - 1.0; + else + x = xm1; + } else { + if (e != 0) + x = x - 1.0; + else + x = xm1; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 6)); + y = y + e * C2; + z = y - 0.5 * z; + z = z + x; + z = z + e * C1; + return z; +} +#endif diff --git a/system/lib/libc/musl/src/math/log2.c b/system/lib/libc/musl/src/math/log2.c new file mode 100644 index 0000000000000..0aafad4b86c1c --- /dev/null +++ b/system/lib/libc/musl/src/math/log2.c @@ -0,0 +1,122 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunSoft, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * Return the base 2 logarithm of x. See log.c for most comments. + * + * Reduce x to 2^k (1+f) and calculate r = log(1+f) - f + f*f/2 + * as in log.c, then combine and scale in extra precision: + * log2(x) = (f - f*f/2 + r)/log(2) + k + */ + +#include <math.h> +#include <stdint.h> + +static const double +ivln2hi = 1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */ +ivln2lo = 1.67517131648865118353e-10, /* 0x3de705fc, 0x2eefa200 */ +Lg1 = 6.666666666666735130e-01, /* 3FE55555 55555593 */ +Lg2 = 3.999999999940941908e-01, /* 3FD99999 9997FA04 */ +Lg3 = 2.857142874366239149e-01, /* 3FD24924 94229359 */ +Lg4 = 2.222219843214978396e-01, /* 3FCC71C5 1D8E78AF */ +Lg5 = 1.818357216161805012e-01, /* 3FC74664 96CB03DE */ +Lg6 = 1.531383769920937332e-01, /* 3FC39A09 D078C69F */ +Lg7 = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */ + +double log2(double x) +{ + union {double f; uint64_t i;} u = {x}; + double_t hfsq,f,s,z,R,w,t1,t2,y,hi,lo,val_hi,val_lo; + uint32_t hx; + int k; + + hx = u.i>>32; + k = 0; + if (hx < 0x00100000 || hx>>31) { + if (u.i<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (hx>>31) + return (x-x)/0.0; /* log(-#) = NaN */ + /* subnormal number, scale x up */ + k -= 54; + x *= 0x1p54; + u.f = x; + hx = u.i>>32; + } else if (hx >= 0x7ff00000) { + return x; + } else if (hx == 0x3ff00000 && u.i<<32 == 0) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + hx += 0x3ff00000 - 0x3fe6a09e; + k += (int)(hx>>20) - 0x3ff; + hx = (hx&0x000fffff) + 0x3fe6a09e; + u.i = (uint64_t)hx<<32 | (u.i&0xffffffff); + x = u.f; + + f = x - 1.0; + hfsq = 0.5*f*f; + s = f/(2.0+f); + z = s*s; + w = z*z; + t1 = w*(Lg2+w*(Lg4+w*Lg6)); + t2 = z*(Lg1+w*(Lg3+w*(Lg5+w*Lg7))); + R = t2 + t1; + + /* + * f-hfsq must (for args near 1) be evaluated in extra precision + * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2). + * This is fairly efficient since f-hfsq only depends on f, so can + * be evaluated in parallel with R. Not combining hfsq with R also + * keeps R small (though not as small as a true `lo' term would be), + * so that extra precision is not needed for terms involving R. + * + * Compiler bugs involving extra precision used to break Dekker's + * theorem for spitting f-hfsq as hi+lo, unless double_t was used + * or the multi-precision calculations were avoided when double_t + * has extra precision. These problems are now automatically + * avoided as a side effect of the optimization of combining the + * Dekker splitting step with the clear-low-bits step. + * + * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra + * precision to avoid a very large cancellation when x is very near + * these values. Unlike the above cancellations, this problem is + * specific to base 2. It is strange that adding +-1 is so much + * harder than adding +-ln2 or +-log10_2. + * + * This uses Dekker's theorem to normalize y+val_hi, so the + * compiler bugs are back in some configurations, sigh. And I + * don't want to used double_t to avoid them, since that gives a + * pessimization and the support for avoiding the pessimization + * is not yet available. + * + * The multi-precision calculations for the multiplications are + * routine. + */ + + /* hi+lo = f - hfsq + s*(hfsq+R) ~ log(1+f) */ + hi = f - hfsq; + u.f = hi; + u.i &= (uint64_t)-1<<32; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + + val_hi = hi*ivln2hi; + val_lo = (lo+hi)*ivln2lo + lo*ivln2hi; + + /* spadd(val_hi, val_lo, y), except for not using double_t: */ + y = k; + w = y + val_hi; + val_lo += (y - w) + val_hi; + val_hi = w; + + return val_lo + val_hi; +} diff --git a/system/lib/libc/musl/src/math/log2f.c b/system/lib/libc/musl/src/math/log2f.c new file mode 100644 index 0000000000000..b3e305fe2a629 --- /dev/null +++ b/system/lib/libc/musl/src/math/log2f.c @@ -0,0 +1,74 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/e_log2f.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ +/* + * See comments in log2.c. + */ + +#include <math.h> +#include <stdint.h> + +static const float +ivln2hi = 1.4428710938e+00, /* 0x3fb8b000 */ +ivln2lo = -1.7605285393e-04, /* 0xb9389ad4 */ +/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */ +Lg1 = 0xaaaaaa.0p-24, /* 0.66666662693 */ +Lg2 = 0xccce13.0p-25, /* 0.40000972152 */ +Lg3 = 0x91e9ee.0p-25, /* 0.28498786688 */ +Lg4 = 0xf89e26.0p-26; /* 0.24279078841 */ + +float log2f(float x) +{ + union {float f; uint32_t i;} u = {x}; + float_t hfsq,f,s,z,R,w,t1,t2,hi,lo; + uint32_t ix; + int k; + + ix = u.i; + k = 0; + if (ix < 0x00800000 || ix>>31) { /* x < 2**-126 */ + if (ix<<1 == 0) + return -1/(x*x); /* log(+-0)=-inf */ + if (ix>>31) + return (x-x)/0.0f; /* log(-#) = NaN */ + /* subnormal number, scale up x */ + k -= 25; + x *= 0x1p25f; + u.f = x; + ix = u.i; + } else if (ix >= 0x7f800000) { + return x; + } else if (ix == 0x3f800000) + return 0; + + /* reduce x into [sqrt(2)/2, sqrt(2)] */ + ix += 0x3f800000 - 0x3f3504f3; + k += (int)(ix>>23) - 0x7f; + ix = (ix&0x007fffff) + 0x3f3504f3; + u.i = ix; + x = u.f; + + f = x - 1.0f; + s = f/(2.0f + f); + z = s*s; + w = z*z; + t1= w*(Lg2+w*Lg4); + t2= z*(Lg1+w*Lg3); + R = t2 + t1; + hfsq = 0.5f*f*f; + + hi = f - hfsq; + u.f = hi; + u.i &= 0xfffff000; + hi = u.f; + lo = f - hi - hfsq + s*(hfsq+R); + return (lo+hi)*ivln2lo + lo*ivln2hi + hi*ivln2hi + k; +} diff --git a/system/lib/libc/musl/src/math/log2l.c b/system/lib/libc/musl/src/math/log2l.c new file mode 100644 index 0000000000000..d00531d5976e2 --- /dev/null +++ b/system/lib/libc/musl/src/math/log2l.c @@ -0,0 +1,176 @@ +/* origin: OpenBSD /usr/src/lib/libm/src/ld80/e_log2l.c */ +/* + * Copyright (c) 2008 Stephen L. Moshier <steve@moshier.net> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* + * Base 2 logarithm, long double precision + * + * + * SYNOPSIS: + * + * long double x, y, log2l(); + * + * y = log2l( x ); + * + * + * DESCRIPTION: + * + * Returns the base 2 logarithm of x. + * + * The argument is separated into its exponent and fractional + * parts. If the exponent is between -1 and +1, the (natural) + * logarithm of the fraction is approximated by + * + * log(1+x) = x - 0.5 x**2 + x**3 P(x)/Q(x). + * + * Otherwise, setting z = 2(x-1)/x+1), + * + * log(x) = z + z**3 P(z)/Q(z). + * + * + * ACCURACY: + * + * Relative error: + * arithmetic domain # trials peak rms + * IEEE 0.5, 2.0 30000 9.8e-20 2.7e-20 + * IEEE exp(+-10000) 70000 5.4e-20 2.3e-20 + * + * In the tests over the interval exp(+-10000), the logarithms + * of the random arguments were uniformly distributed over + * [-10000, +10000]. + */ + +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double log2l(long double x) +{ + return log2(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +/* Coefficients for ln(1+x) = x - x**2/2 + x**3 P(x)/Q(x) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.2e-22 + */ +static const long double P[] = { + 4.9962495940332550844739E-1L, + 1.0767376367209449010438E1L, + 7.7671073698359539859595E1L, + 2.5620629828144409632571E2L, + 4.2401812743503691187826E2L, + 3.4258224542413922935104E2L, + 1.0747524399916215149070E2L, +}; +static const long double Q[] = { +/* 1.0000000000000000000000E0,*/ + 2.3479774160285863271658E1L, + 1.9444210022760132894510E2L, + 7.7952888181207260646090E2L, + 1.6911722418503949084863E3L, + 2.0307734695595183428202E3L, + 1.2695660352705325274404E3L, + 3.2242573199748645407652E2L, +}; + +/* Coefficients for log(x) = z + z^3 P(z^2)/Q(z^2), + * where z = 2(x-1)/(x+1) + * 1/sqrt(2) <= x < sqrt(2) + * Theoretical peak relative error = 6.16e-22 + */ +static const long double R[4] = { + 1.9757429581415468984296E-3L, +-7.1990767473014147232598E-1L, + 1.0777257190312272158094E1L, +-3.5717684488096787370998E1L, +}; +static const long double S[4] = { +/* 1.00000000000000000000E0L,*/ +-2.6201045551331104417768E1L, + 1.9361891836232102174846E2L, +-4.2861221385716144629696E2L, +}; +/* log2(e) - 1 */ +#define LOG2EA 4.4269504088896340735992e-1L + +#define SQRTH 0.70710678118654752440L + +long double log2l(long double x) +{ + long double y, z; + int e; + + if (isnan(x)) + return x; + if (x == INFINITY) + return x; + if (x <= 0.0) { + if (x == 0.0) + return -1/(x*x); /* -inf with divbyzero */ + return 0/0.0f; /* nan with invalid */ + } + + /* separate mantissa from exponent */ + /* Note, frexp is used so that denormal numbers + * will be handled properly. + */ + x = frexpl(x, &e); + + /* logarithm using log(x) = z + z**3 P(z)/Q(z), + * where z = 2(x-1)/x+1) + */ + if (e > 2 || e < -2) { + if (x < SQRTH) { /* 2(2x-1)/(2x+1) */ + e -= 1; + z = x - 0.5; + y = 0.5 * z + 0.5; + } else { /* 2 (x-1)/(x+1) */ + z = x - 0.5; + z -= 0.5; + y = 0.5 * x + 0.5; + } + x = z / y; + z = x*x; + y = x * (z * __polevll(z, R, 3) / __p1evll(z, S, 3)); + goto done; + } + + /* logarithm using log(1+x) = x - .5x**2 + x**3 P(x)/Q(x) */ + if (x < SQRTH) { + e -= 1; + x = 2.0*x - 1.0; + } else { + x = x - 1.0; + } + z = x*x; + y = x * (z * __polevll(x, P, 6) / __p1evll(x, Q, 7)); + y = y - 0.5*z; + +done: + /* Multiply log of fraction by log2(e) + * and base 2 exponent by 1 + * + * ***CAUTION*** + * + * This sequence of operations is critical and it may + * be horribly defeated by some compiler optimizers. + */ + z = y * LOG2EA; + z += x * LOG2EA; + z += y; + z += x; + z += e; + return z; +} +#endif diff --git a/system/lib/libc/musl/src/math/lrint.c b/system/lib/libc/musl/src/math/lrint.c new file mode 100644 index 0000000000000..bdca8b7cb82ec --- /dev/null +++ b/system/lib/libc/musl/src/math/lrint.c @@ -0,0 +1,46 @@ +#include <limits.h> +#include <fenv.h> +#include "libm.h" + +/* +If the result cannot be represented (overflow, nan), then +lrint raises the invalid exception. + +Otherwise if the input was not an integer then the inexact +exception is raised. + +C99 is a bit vague about whether inexact exception is +allowed to be raised when invalid is raised. +(F.9 explicitly allows spurious inexact exceptions, F.9.6.5 +does not make it clear if that rule applies to lrint, but +IEEE 754r 7.8 seems to forbid spurious inexact exception in +the ineger conversion functions) + +So we try to make sure that no spurious inexact exception is +raised in case of an overflow. + +If the bit size of long > precision of double, then there +cannot be inexact rounding in case the result overflows, +otherwise LONG_MAX and LONG_MIN can be represented exactly +as a double. +*/ + +#if LONG_MAX < 1U<<53 && defined(FE_INEXACT) +long lrint(double x) +{ + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rint(x); + if (!e && (x > LONG_MAX || x < LONG_MIN)) + feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long lrint(double x) +{ + return rint(x); +} +#endif diff --git a/system/lib/libc/musl/src/math/lrintf.c b/system/lib/libc/musl/src/math/lrintf.c new file mode 100644 index 0000000000000..ca0b6a46aaed3 --- /dev/null +++ b/system/lib/libc/musl/src/math/lrintf.c @@ -0,0 +1,8 @@ +#include <math.h> + +/* uses LONG_MAX > 2^24, see comments in lrint.c */ + +long lrintf(float x) +{ + return rintf(x); +} diff --git a/system/lib/libc/musl/src/math/lrintl.c b/system/lib/libc/musl/src/math/lrintl.c new file mode 100644 index 0000000000000..b2a8106d7c6a1 --- /dev/null +++ b/system/lib/libc/musl/src/math/lrintl.c @@ -0,0 +1,36 @@ +#include <limits.h> +#include <fenv.h> +#include "libm.h" + + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long lrintl(long double x) +{ + return lrint(x); +} +#elif defined(FE_INEXACT) +/* +see comments in lrint.c + +Note that if LONG_MAX == 0x7fffffffffffffff && LDBL_MANT_DIG == 64 +then x == 2**63 - 0.5 is the only input that overflows and +raises inexact (with tonearest or upward rounding mode) +*/ +long lrintl(long double x) +{ + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); + x = rintl(x); + if (!e && (x > LONG_MAX || x < LONG_MIN)) + feclearexcept(FE_INEXACT); + /* conversion */ + return x; +} +#else +long lrintl(long double x) +{ + return rintl(x); +} +#endif diff --git a/system/lib/libc/musl/src/math/lround.c b/system/lib/libc/musl/src/math/lround.c new file mode 100644 index 0000000000000..b8b795470f186 --- /dev/null +++ b/system/lib/libc/musl/src/math/lround.c @@ -0,0 +1,6 @@ +#include <math.h> + +long lround(double x) +{ + return round(x); +} diff --git a/system/lib/libc/musl/src/math/lroundf.c b/system/lib/libc/musl/src/math/lroundf.c new file mode 100644 index 0000000000000..c4707e7db712c --- /dev/null +++ b/system/lib/libc/musl/src/math/lroundf.c @@ -0,0 +1,6 @@ +#include <math.h> + +long lroundf(float x) +{ + return roundf(x); +} diff --git a/system/lib/libc/musl/src/math/lroundl.c b/system/lib/libc/musl/src/math/lroundl.c new file mode 100644 index 0000000000000..094fdf6483842 --- /dev/null +++ b/system/lib/libc/musl/src/math/lroundl.c @@ -0,0 +1,6 @@ +#include <math.h> + +long lroundl(long double x) +{ + return roundl(x); +} diff --git a/system/lib/libc/musl/src/math/modf.c b/system/lib/libc/musl/src/math/modf.c new file mode 100644 index 0000000000000..1c8a1db90db7b --- /dev/null +++ b/system/lib/libc/musl/src/math/modf.c @@ -0,0 +1,34 @@ +#include "libm.h" + +double modf(double x, double *iptr) +{ + union {double f; uint64_t i;} u = {x}; + uint64_t mask; + int e = (int)(u.i>>52 & 0x7ff) - 0x3ff; + + /* no fractional part */ + if (e >= 52) { + *iptr = x; + if (e == 0x400 && u.i<<12 != 0) /* nan */ + return x; + u.i &= 1ULL<<63; + return u.f; + } + + /* no integral part*/ + if (e < 0) { + u.i &= 1ULL<<63; + *iptr = u.f; + return x; + } + + mask = -1ULL>>12>>e; + if ((u.i & mask) == 0) { + *iptr = x; + u.i &= 1ULL<<63; + return u.f; + } + u.i &= ~mask; + *iptr = u.f; + return x - u.f; +} diff --git a/system/lib/libc/musl/src/math/modff.c b/system/lib/libc/musl/src/math/modff.c new file mode 100644 index 0000000000000..639514effafcc --- /dev/null +++ b/system/lib/libc/musl/src/math/modff.c @@ -0,0 +1,34 @@ +#include "libm.h" + +float modff(float x, float *iptr) +{ + union {float f; uint32_t i;} u = {x}; + uint32_t mask; + int e = (int)(u.i>>23 & 0xff) - 0x7f; + + /* no fractional part */ + if (e >= 23) { + *iptr = x; + if (e == 0x80 && u.i<<9 != 0) { /* nan */ + return x; + } + u.i &= 0x80000000; + return u.f; + } + /* no integral part */ + if (e < 0) { + u.i &= 0x80000000; + *iptr = u.f; + return x; + } + + mask = 0x007fffff>>e; + if ((u.i & mask) == 0) { + *iptr = x; + u.i &= 0x80000000; + return u.f; + } + u.i &= ~mask; + *iptr = u.f; + return x - u.f; +} diff --git a/system/lib/libc/musl/src/math/modfl.c b/system/lib/libc/musl/src/math/modfl.c new file mode 100644 index 0000000000000..4b03a4be0aa46 --- /dev/null +++ b/system/lib/libc/musl/src/math/modfl.c @@ -0,0 +1,55 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double modfl(long double x, long double *iptr) +{ + double d; + long double r; + + r = modf(x, &d); + *iptr = d; + return r; +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +#define TOINT 0x1p63 +#elif LDBL_MANT_DIG == 113 +#define TOINT 0x1p112 +#endif +long double modfl(long double x, long double *iptr) +{ + union ldshape u = {x}; + int e = (u.i.se & 0x7fff) - 0x3fff; + int s = u.i.se >> 15; + long double absx; + long double y; + + /* no fractional part */ + if (e >= LDBL_MANT_DIG-1) { + *iptr = x; + if (isnan(x)) + return x; + return s ? -0.0 : 0.0; + } + + /* no integral part*/ + if (e < 0) { + *iptr = s ? -0.0 : 0.0; + return x; + } + + /* raises spurious inexact */ + absx = s ? -x : x; + y = absx + TOINT - TOINT - absx; + if (y == 0) { + *iptr = x; + return s ? -0.0 : 0.0; + } + if (y > 0) + y -= 1; + if (s) + y = -y; + *iptr = x + y; + return -y; +} +#endif diff --git a/system/lib/libc/musl/src/math/nan.c b/system/lib/libc/musl/src/math/nan.c new file mode 100644 index 0000000000000..9e0826c77831a --- /dev/null +++ b/system/lib/libc/musl/src/math/nan.c @@ -0,0 +1,6 @@ +#include <math.h> + +double nan(const char *s) +{ + return NAN; +} diff --git a/system/lib/libc/musl/src/math/nanf.c b/system/lib/libc/musl/src/math/nanf.c new file mode 100644 index 0000000000000..752ce5463488e --- /dev/null +++ b/system/lib/libc/musl/src/math/nanf.c @@ -0,0 +1,6 @@ +#include <math.h> + +float nanf(const char *s) +{ + return NAN; +} diff --git a/system/lib/libc/musl/src/math/nanl.c b/system/lib/libc/musl/src/math/nanl.c new file mode 100644 index 0000000000000..969af5641f35e --- /dev/null +++ b/system/lib/libc/musl/src/math/nanl.c @@ -0,0 +1,6 @@ +#include <math.h> + +long double nanl(const char *s) +{ + return NAN; +} diff --git a/system/lib/libc/musl/src/math/nearbyint.c b/system/lib/libc/musl/src/math/nearbyint.c new file mode 100644 index 0000000000000..f4e8aac4f0118 --- /dev/null +++ b/system/lib/libc/musl/src/math/nearbyint.c @@ -0,0 +1,20 @@ +#include <fenv.h> +#include <math.h> + +/* nearbyint is the same as rint, but it must not raise the inexact exception */ + +double nearbyint(double x) +{ +#ifdef FE_INEXACT + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rint(x); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif + return x; +} diff --git a/system/lib/libc/musl/src/math/nearbyintf.c b/system/lib/libc/musl/src/math/nearbyintf.c new file mode 100644 index 0000000000000..092e9ffae56e9 --- /dev/null +++ b/system/lib/libc/musl/src/math/nearbyintf.c @@ -0,0 +1,18 @@ +#include <fenv.h> +#include <math.h> + +float nearbyintf(float x) +{ +#ifdef FE_INEXACT + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rintf(x); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif + return x; +} diff --git a/system/lib/libc/musl/src/math/nearbyintl.c b/system/lib/libc/musl/src/math/nearbyintl.c new file mode 100644 index 0000000000000..82852492f8108 --- /dev/null +++ b/system/lib/libc/musl/src/math/nearbyintl.c @@ -0,0 +1,26 @@ +#include <math.h> +#include <float.h> + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double nearbyintl(long double x) +{ + return nearbyint(x); +} +#else +#include <fenv.h> +long double nearbyintl(long double x) +{ +#ifdef FE_INEXACT + #pragma STDC FENV_ACCESS ON + int e; + + e = fetestexcept(FE_INEXACT); +#endif + x = rintl(x); +#ifdef FE_INEXACT + if (!e) + feclearexcept(FE_INEXACT); +#endif + return x; +} +#endif diff --git a/system/lib/libc/musl/src/math/remainder.c b/system/lib/libc/musl/src/math/remainder.c new file mode 100644 index 0000000000000..6cd089c467cee --- /dev/null +++ b/system/lib/libc/musl/src/math/remainder.c @@ -0,0 +1,10 @@ +#include <math.h> +#include "libc.h" + +double remainder(double x, double y) +{ + int q; + return remquo(x, y, &q); +} + +weak_alias(remainder, drem); diff --git a/system/lib/libc/musl/src/math/remainderf.c b/system/lib/libc/musl/src/math/remainderf.c new file mode 100644 index 0000000000000..420d3bfc447b2 --- /dev/null +++ b/system/lib/libc/musl/src/math/remainderf.c @@ -0,0 +1,10 @@ +#include <math.h> +#include "libc.h" + +float remainderf(float x, float y) +{ + int q; + return remquof(x, y, &q); +} + +weak_alias(remainderf, dremf); diff --git a/system/lib/libc/musl/src/math/remainderl.c b/system/lib/libc/musl/src/math/remainderl.c new file mode 100644 index 0000000000000..2a13c1d5af138 --- /dev/null +++ b/system/lib/libc/musl/src/math/remainderl.c @@ -0,0 +1,15 @@ +#include <math.h> +#include <float.h> + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double remainderl(long double x, long double y) +{ + return remainder(x, y); +} +#else +long double remainderl(long double x, long double y) +{ + int q; + return remquol(x, y, &q); +} +#endif diff --git a/system/lib/libc/musl/src/math/rint.c b/system/lib/libc/musl/src/math/rint.c new file mode 100644 index 0000000000000..81f4e6223b748 --- /dev/null +++ b/system/lib/libc/musl/src/math/rint.c @@ -0,0 +1,20 @@ +#include <math.h> +#include <stdint.h> + +double rint(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i>>52 & 0x7ff; + int s = u.i>>63; + double_t y; + + if (e >= 0x3ff+52) + return x; + if (s) + y = (double)(x - 0x1p52) + 0x1p52; + else + y = (double)(x + 0x1p52) - 0x1p52; + if (y == 0) + return s ? -0.0 : 0; + return y; +} diff --git a/system/lib/libc/musl/src/math/rintf.c b/system/lib/libc/musl/src/math/rintf.c new file mode 100644 index 0000000000000..9cfc2a261f3c7 --- /dev/null +++ b/system/lib/libc/musl/src/math/rintf.c @@ -0,0 +1,20 @@ +#include <math.h> +#include <stdint.h> + +float rintf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i>>23 & 0xff; + int s = u.i>>31; + float_t y; + + if (e >= 0x7f+23) + return x; + if (s) + y = (float)(x - 0x1p23f) + 0x1p23f; + else + y = (float)(x + 0x1p23f) - 0x1p23f; + if (y == 0) + return s ? -0.0f : 0.0f; + return y; +} diff --git a/system/lib/libc/musl/src/math/rintl.c b/system/lib/libc/musl/src/math/rintl.c new file mode 100644 index 0000000000000..267250737f0a8 --- /dev/null +++ b/system/lib/libc/musl/src/math/rintl.c @@ -0,0 +1,31 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double rintl(long double x) +{ + return rint(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +#define TOINT 0x1p63 +#elif LDBL_MANT_DIG == 113 +#define TOINT 0x1p112 +#endif +long double rintl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int s = u.i.se >> 15; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1) + return x; + if (s) + y = x - TOINT + TOINT; + else + y = x + TOINT - TOINT; + if (y == 0) + return 0*x; + return y; +} +#endif diff --git a/system/lib/libc/musl/src/math/round.c b/system/lib/libc/musl/src/math/round.c new file mode 100644 index 0000000000000..4b38d1fdbb2ad --- /dev/null +++ b/system/lib/libc/musl/src/math/round.c @@ -0,0 +1,28 @@ +#include "libm.h" + +double round(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = u.i >> 52 & 0x7ff; + double_t y; + + if (e >= 0x3ff+52) + return x; + if (u.i >> 63) + x = -x; + if (e < 0x3ff-1) { + /* raise inexact if x!=0 */ + FORCE_EVAL(x + 0x1p52); + return 0*u.f; + } + y = (double)(x + 0x1p52) - 0x1p52 - x; + if (y > 0.5) + y = y + x - 1; + else if (y <= -0.5) + y = y + x + 1; + else + y = y + x; + if (u.i >> 63) + y = -y; + return y; +} diff --git a/system/lib/libc/musl/src/math/roundf.c b/system/lib/libc/musl/src/math/roundf.c new file mode 100644 index 0000000000000..c6b277979038e --- /dev/null +++ b/system/lib/libc/musl/src/math/roundf.c @@ -0,0 +1,27 @@ +#include "libm.h" + +float roundf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = u.i >> 23 & 0xff; + float_t y; + + if (e >= 0x7f+23) + return x; + if (u.i >> 31) + x = -x; + if (e < 0x7f-1) { + FORCE_EVAL(x + 0x1p23f); + return 0*u.f; + } + y = (float)(x + 0x1p23f) - 0x1p23f - x; + if (y > 0.5f) + y = y + x - 1; + else if (y <= -0.5f) + y = y + x + 1; + else + y = y + x; + if (u.i >> 31) + y = -y; + return y; +} diff --git a/system/lib/libc/musl/src/math/roundl.c b/system/lib/libc/musl/src/math/roundl.c new file mode 100644 index 0000000000000..8f3f28b348e13 --- /dev/null +++ b/system/lib/libc/musl/src/math/roundl.c @@ -0,0 +1,39 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double roundl(long double x) +{ + return round(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +#define TOINT 0x1p63 +#elif LDBL_MANT_DIG == 113 +#define TOINT 0x1p112 +#endif +long double roundl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1) + return x; + if (u.i.se >> 15) + x = -x; + if (e < 0x3fff-1) { + FORCE_EVAL(x + TOINT); + return 0*u.f; + } + y = x + TOINT - TOINT - x; + if (y > 0.5) + y = y + x - 1; + else if (y <= -0.5) + y = y + x + 1; + else + y = y + x; + if (u.i.se >> 15) + y = -y; + return y; +} +#endif diff --git a/system/lib/libc/musl/src/math/sincos.c b/system/lib/libc/musl/src/math/sincos.c new file mode 100644 index 0000000000000..35b2d923968f1 --- /dev/null +++ b/system/lib/libc/musl/src/math/sincos.c @@ -0,0 +1,69 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sin.c */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +void sincos(double x, double *sin, double *cos) +{ + double y[2], s, c; + uint32_t ix; + unsigned n; + + GET_HIGH_WORD(ix, x); + ix &= 0x7fffffff; + + /* |x| ~< pi/4 */ + if (ix <= 0x3fe921fb) { + /* if |x| < 2**-27 * sqrt(2) */ + if (ix < 0x3e46a09e) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + *sin = x; + *cos = 1.0; + return; + } + *sin = __sin(x, 0.0, 0); + *cos = __cos(x, 0.0); + return; + } + + /* sincos(Inf or NaN) is NaN */ + if (ix >= 0x7ff00000) { + *sin = *cos = x - x; + return; + } + + /* argument reduction needed */ + n = __rem_pio2(x, y); + s = __sin(y[0], y[1], 1); + c = __cos(y[0], y[1]); + switch (n&3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} diff --git a/system/lib/libc/musl/src/math/sincosf.c b/system/lib/libc/musl/src/math/sincosf.c new file mode 100644 index 0000000000000..f8ca7232cfb37 --- /dev/null +++ b/system/lib/libc/musl/src/math/sincosf.c @@ -0,0 +1,117 @@ +/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */ +/* + * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. + * Optimized by Bruce D. Evans. + */ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +#define _GNU_SOURCE +#include "libm.h" + +/* Small multiples of pi/2 rounded to double precision. */ +static const double +s1pio2 = 1*M_PI_2, /* 0x3FF921FB, 0x54442D18 */ +s2pio2 = 2*M_PI_2, /* 0x400921FB, 0x54442D18 */ +s3pio2 = 3*M_PI_2, /* 0x4012D97C, 0x7F3321D2 */ +s4pio2 = 4*M_PI_2; /* 0x401921FB, 0x54442D18 */ + +void sincosf(float x, float *sin, float *cos) +{ + double y; + float_t s, c; + uint32_t ix; + unsigned n, sign; + + GET_FLOAT_WORD(ix, x); + sign = ix >> 31; + ix &= 0x7fffffff; + + /* |x| ~<= pi/4 */ + if (ix <= 0x3f490fda) { + /* |x| < 2**-12 */ + if (ix < 0x39800000) { + /* raise inexact if x!=0 and underflow if subnormal */ + FORCE_EVAL(ix < 0x00100000 ? x/0x1p120f : x+0x1p120f); + *sin = x; + *cos = 1.0f; + return; + } + *sin = __sindf(x); + *cos = __cosdf(x); + return; + } + + /* |x| ~<= 5*pi/4 */ + if (ix <= 0x407b53d1) { + if (ix <= 0x4016cbe3) { /* |x| ~<= 3pi/4 */ + if (sign) { + *sin = -__cosdf(x + s1pio2); + *cos = __sindf(x + s1pio2); + } else { + *sin = __cosdf(s1pio2 - x); + *cos = __sindf(s1pio2 - x); + } + return; + } + /* -sin(x+c) is not correct if x+c could be 0: -0 vs +0 */ + *sin = -__sindf(sign ? x + s2pio2 : x - s2pio2); + *cos = -__cosdf(sign ? x + s2pio2 : x - s2pio2); + return; + } + + /* |x| ~<= 9*pi/4 */ + if (ix <= 0x40e231d5) { + if (ix <= 0x40afeddf) { /* |x| ~<= 7*pi/4 */ + if (sign) { + *sin = __cosdf(x + s3pio2); + *cos = -__sindf(x + s3pio2); + } else { + *sin = -__cosdf(x - s3pio2); + *cos = __sindf(x - s3pio2); + } + return; + } + *sin = __sindf(sign ? x + s4pio2 : x - s4pio2); + *cos = __cosdf(sign ? x + s4pio2 : x - s4pio2); + return; + } + + /* sin(Inf or NaN) is NaN */ + if (ix >= 0x7f800000) { + *sin = *cos = x - x; + return; + } + + /* general argument reduction needed */ + n = __rem_pio2f(x, &y); + s = __sindf(y); + c = __cosdf(y); + switch (n&3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} diff --git a/system/lib/libc/musl/src/math/sincosl.c b/system/lib/libc/musl/src/math/sincosl.c new file mode 100644 index 0000000000000..d3ac1c4c8c29e --- /dev/null +++ b/system/lib/libc/musl/src/math/sincosl.c @@ -0,0 +1,60 @@ +#define _GNU_SOURCE +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +void sincosl(long double x, long double *sin, long double *cos) +{ + double sind, cosd; + sincos(x, &sind, &cosd); + *sin = sind; + *cos = cosd; +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +void sincosl(long double x, long double *sin, long double *cos) +{ + union ldshape u = {x}; + unsigned n; + long double y[2], s, c; + + u.i.se &= 0x7fff; + if (u.i.se == 0x7fff) { + *sin = *cos = x - x; + return; + } + if (u.f < M_PI_4) { + if (u.i.se < 0x3fff - LDBL_MANT_DIG) { + /* raise underflow if subnormal */ + if (u.i.se == 0) FORCE_EVAL(x*0x1p-120f); + *sin = x; + /* raise inexact if x!=0 */ + *cos = 1.0 + x; + return; + } + *sin = __sinl(x, 0, 0); + *cos = __cosl(x, 0); + return; + } + n = __rem_pio2l(x, y); + s = __sinl(y[0], y[1], 1); + c = __cosl(y[0], y[1]); + switch (n & 3) { + case 0: + *sin = s; + *cos = c; + break; + case 1: + *sin = c; + *cos = -s; + break; + case 2: + *sin = -s; + *cos = -c; + break; + case 3: + default: + *sin = -c; + *cos = s; + break; + } +} +#endif diff --git a/system/lib/libc/musl/src/math/sinh.c b/system/lib/libc/musl/src/math/sinh.c new file mode 100644 index 0000000000000..00022c4e6ff6d --- /dev/null +++ b/system/lib/libc/musl/src/math/sinh.c @@ -0,0 +1,39 @@ +#include "libm.h" + +/* sinh(x) = (exp(x) - 1/exp(x))/2 + * = (exp(x)-1 + (exp(x)-1)/exp(x))/2 + * = x + x^3/6 + o(x^5) + */ +double sinh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + double t, h, absx; + + h = 0.5; + if (u.i >> 63) + h = -h; + /* |x| */ + u.i &= (uint64_t)-1/2; + absx = u.f; + w = u.i >> 32; + + /* |x| < log(DBL_MAX) */ + if (w < 0x40862e42) { + t = expm1(absx); + if (w < 0x3ff00000) { + if (w < 0x3ff00000 - (26<<20)) + /* note: inexact and underflow are raised by expm1 */ + /* note: this branch avoids spurious underflow */ + return x; + return h*(2*t - t*t/(t+1)); + } + /* note: |x|>log(0x1p26)+eps could be just h*exp(x) */ + return h*(t + t/(t+1)); + } + + /* |x| > log(DBL_MAX) or nan */ + /* note: the result is stored to handle overflow */ + t = 2*h*__expo2(absx); + return t; +} diff --git a/system/lib/libc/musl/src/math/sinhf.c b/system/lib/libc/musl/src/math/sinhf.c new file mode 100644 index 0000000000000..6ad19ea2b0c8d --- /dev/null +++ b/system/lib/libc/musl/src/math/sinhf.c @@ -0,0 +1,31 @@ +#include "libm.h" + +float sinhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + float t, h, absx; + + h = 0.5; + if (u.i >> 31) + h = -h; + /* |x| */ + u.i &= 0x7fffffff; + absx = u.f; + w = u.i; + + /* |x| < log(FLT_MAX) */ + if (w < 0x42b17217) { + t = expm1f(absx); + if (w < 0x3f800000) { + if (w < 0x3f800000 - (12<<23)) + return x; + return h*(2*t - t*t/(t+1)); + } + return h*(t + t/(t+1)); + } + + /* |x| > logf(FLT_MAX) or nan */ + t = 2*h*__expo2f(absx); + return t; +} diff --git a/system/lib/libc/musl/src/math/sinhl.c b/system/lib/libc/musl/src/math/sinhl.c new file mode 100644 index 0000000000000..4864ddfa6a77c --- /dev/null +++ b/system/lib/libc/musl/src/math/sinhl.c @@ -0,0 +1,37 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double sinhl(long double x) +{ + return sinh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double sinhl(long double x) +{ + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + long double h, t, absx; + + h = 0.5; + if (u.i.se & 0x8000) + h = -h; + /* |x| */ + u.i.se = ex; + absx = u.f; + + /* |x| < log(LDBL_MAX) */ + if (ex < 0x3fff+13 || (ex == 0x3fff+13 && u.i.m>>32 < 0xb17217f7)) { + t = expm1l(absx); + if (ex < 0x3fff) { + if (ex < 0x3fff-32) + return x; + return h*(2*t - t*t/(1+t)); + } + return h*(t + t/(t+1)); + } + + /* |x| > log(LDBL_MAX) or nan */ + t = expl(0.5*absx); + return h*t*t; +} +#endif diff --git a/system/lib/libc/musl/src/math/tanh.c b/system/lib/libc/musl/src/math/tanh.c new file mode 100644 index 0000000000000..20d6dbcf4175c --- /dev/null +++ b/system/lib/libc/musl/src/math/tanh.c @@ -0,0 +1,45 @@ +#include "libm.h" + +/* tanh(x) = (exp(x) - exp(-x))/(exp(x) + exp(-x)) + * = (exp(2*x) - 1)/(exp(2*x) - 1 + 2) + * = (1 - exp(-2*x))/(exp(-2*x) - 1 + 2) + */ +double tanh(double x) +{ + union {double f; uint64_t i;} u = {.f = x}; + uint32_t w; + int sign; + double_t t; + + /* x = |x| */ + sign = u.i >> 63; + u.i &= (uint64_t)-1/2; + x = u.f; + w = u.i >> 32; + + if (w > 0x3fe193ea) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (w > 0x40340000) { + /* |x| > 20 or nan */ + /* note: this branch avoids raising overflow */ + t = 1 - 0/x; + } else { + t = expm1(2*x); + t = 1 - 2/(t+2); + } + } else if (w > 0x3fd058ae) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1(2*x); + t = t/(t+2); + } else if (w >= 0x00100000) { + /* |x| >= 0x1p-1022, up to 2ulp error in [0.1,0.2554] */ + t = expm1(-2*x); + t = -t/(t+2); + } else { + /* |x| is subnormal */ + /* note: the branch above would not raise underflow in [0x1p-1023,0x1p-1022) */ + FORCE_EVAL((float)x); + t = x; + } + return sign ? -t : t; +} diff --git a/system/lib/libc/musl/src/math/tanhf.c b/system/lib/libc/musl/src/math/tanhf.c new file mode 100644 index 0000000000000..10636fbd7be6c --- /dev/null +++ b/system/lib/libc/musl/src/math/tanhf.c @@ -0,0 +1,39 @@ +#include "libm.h" + +float tanhf(float x) +{ + union {float f; uint32_t i;} u = {.f = x}; + uint32_t w; + int sign; + float t; + + /* x = |x| */ + sign = u.i >> 31; + u.i &= 0x7fffffff; + x = u.f; + w = u.i; + + if (w > 0x3f0c9f54) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (w > 0x41200000) { + /* |x| > 10 */ + t = 1 + 0/x; + } else { + t = expm1f(2*x); + t = 1 - 2/(t+2); + } + } else if (w > 0x3e82c578) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1f(2*x); + t = t/(t+2); + } else if (w >= 0x00800000) { + /* |x| >= 0x1p-126 */ + t = expm1f(-2*x); + t = -t/(t+2); + } else { + /* |x| is subnormal */ + FORCE_EVAL(x*x); + t = x; + } + return sign ? -t : t; +} diff --git a/system/lib/libc/musl/src/math/tanhl.c b/system/lib/libc/musl/src/math/tanhl.c new file mode 100644 index 0000000000000..f594b85f3d6ce --- /dev/null +++ b/system/lib/libc/musl/src/math/tanhl.c @@ -0,0 +1,42 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double tanhl(long double x) +{ + return tanh(x); +} +#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 +long double tanhl(long double x) +{ + union ldshape u = {x}; + unsigned ex = u.i.se & 0x7fff; + unsigned sign = u.i.se & 0x8000; + uint32_t w; + long double t; + + /* x = |x| */ + u.i.se = ex; + x = u.f; + w = u.i.m >> 32; + + if (ex > 0x3ffe || (ex == 0x3ffe && w > 0x8c9f53d5)) { + /* |x| > log(3)/2 ~= 0.5493 or nan */ + if (ex >= 0x3fff+5) { + /* |x| >= 32 */ + t = 1 + 0/(x + 0x1p-120f); + } else { + t = expm1l(2*x); + t = 1 - 2/(t+2); + } + } else if (ex > 0x3ffd || (ex == 0x3ffd && w > 0x82c577d4)) { + /* |x| > log(5/3)/2 ~= 0.2554 */ + t = expm1l(2*x); + t = t/(t+2); + } else { + /* |x| is small */ + t = expm1l(-2*x); + t = -t/(t+2); + } + return sign ? -t : t; +} +#endif diff --git a/system/lib/libc/musl/src/math/trunc.c b/system/lib/libc/musl/src/math/trunc.c new file mode 100644 index 0000000000000..d13711b5015e0 --- /dev/null +++ b/system/lib/libc/musl/src/math/trunc.c @@ -0,0 +1,19 @@ +#include "libm.h" + +double trunc(double x) +{ + union {double f; uint64_t i;} u = {x}; + int e = (int)(u.i >> 52 & 0x7ff) - 0x3ff + 12; + uint64_t m; + + if (e >= 52 + 12) + return x; + if (e < 12) + e = 1; + m = -1ULL >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + u.i &= ~m; + return u.f; +} diff --git a/system/lib/libc/musl/src/math/truncf.c b/system/lib/libc/musl/src/math/truncf.c new file mode 100644 index 0000000000000..1a7d03c3bce10 --- /dev/null +++ b/system/lib/libc/musl/src/math/truncf.c @@ -0,0 +1,19 @@ +#include "libm.h" + +float truncf(float x) +{ + union {float f; uint32_t i;} u = {x}; + int e = (int)(u.i >> 23 & 0xff) - 0x7f + 9; + uint32_t m; + + if (e >= 23 + 9) + return x; + if (e < 9) + e = 1; + m = -1U >> e; + if ((u.i & m) == 0) + return x; + FORCE_EVAL(x + 0x1p120f); + u.i &= ~m; + return u.f; +} diff --git a/system/lib/libc/musl/src/math/truncl.c b/system/lib/libc/musl/src/math/truncl.c new file mode 100644 index 0000000000000..3eedb08397131 --- /dev/null +++ b/system/lib/libc/musl/src/math/truncl.c @@ -0,0 +1,36 @@ +#include "libm.h" + +#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024 +long double truncl(long double x) +{ + return trunc(x); +} +#elif (LDBL_MANT_DIG == 64 || LDBL_MANT_DIG == 113) && LDBL_MAX_EXP == 16384 +#if LDBL_MANT_DIG == 64 +#define TOINT 0x1p63 +#elif LDBL_MANT_DIG == 113 +#define TOINT 0x1p112 +#endif +long double truncl(long double x) +{ + union ldshape u = {x}; + int e = u.i.se & 0x7fff; + int s = u.i.se >> 15; + long double y; + + if (e >= 0x3fff+LDBL_MANT_DIG-1) + return x; + if (e <= 0x3fff-1) { + FORCE_EVAL(x + 0x1p120f); + return x*0; + } + /* y = int(|x|) - |x|, where int(|x|) is an integer neighbor of |x| */ + if (s) + x = -x; + y = x + TOINT - TOINT - x; + if (y > 0) + y -= 1; + x += y; + return s ? -x : x; +} +#endif diff --git a/tests/test_other.py b/tests/test_other.py index e88ff62376f10..bd2598a368fdd 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1901,7 +1901,7 @@ def test_js_optimizer(self): ['asm', 'eliminate']), (path_from_root('tools', 'test-js-optimizer-asm-regs.js'), open(path_from_root('tools', 'test-js-optimizer-asm-regs-output.js')).read(), ['asm', 'registerize']), - (path_from_root('tools', 'test-js-optimizer-asm-regs-harder.js'), open(path_from_root('tools', 'test-js-optimizer-asm-regs-harder-output.js')).read(), + (path_from_root('tools', 'test-js-optimizer-asm-regs-harder.js'), [open(path_from_root('tools', 'test-js-optimizer-asm-regs-harder-output.js')).read(), open(path_from_root('tools', 'test-js-optimizer-asm-regs-harder-output2.js')).read(), open(path_from_root('tools', 'test-js-optimizer-asm-regs-harder-output3.js')).read()], ['asm', 'registerizeHarder']), (path_from_root('tools', 'test-js-optimizer-asm-regs-min.js'), open(path_from_root('tools', 'test-js-optimizer-asm-regs-min-output.js')).read(), ['asm', 'registerize', 'minifyLocals']), diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index b94c2beaa0340..523d1c6be9d46 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -2879,7 +2879,7 @@ function registerizeHarder(ast) { // Traverse the tree in execution order and synthesize a basic flow-graph. // It's convenient to build a kind of "dual" graph where the nodes identify - // the junctions between blocks at which control-flow may branch, and each + // the junctions between blocks at which control-flow may branch, and each // basic block is an edge connecting two such junctions. // For each junction we store: // * set of blocks that originate at the junction @@ -2977,9 +2977,9 @@ function registerizeHarder(ast) { } function markNonLocalJump(type, label) { - // Complete a block via 'return', 'break' or 'continue'. + // Complete a block via 'return', 'break' or 'continue'. // This joins the targetted junction and then sets the current junction to null. - // Any code traversed before we get back an existing junction is dead code. + // Any code traversed before we get back to an existing junction is dead code. if (type === 'return') { joinJunction(EXIT_JUNCTION); } else { @@ -3408,7 +3408,7 @@ function registerizeHarder(ast) { // saving/restoring label to the stack. for (var j = 0; j < block.nodes.length - 1; j++) { if (block.nodes[j][0] === 'assign' && block.nodes[j][2][1] === 'label') { - if (block.nodes[j][3][0] !== 'num' && block.nodes[j][3][1] !== 0) { + if (block.nodes[j][3][0] !== 'num' || block.nodes[j][3][1] !== 0) { labelledBlocks = {}; labelledJumps = []; break FINDLABELLEDBLOCKS; @@ -3850,7 +3850,7 @@ function registerizeHarder(ast) { } } } - // If we managed to create an "x=x" assignments, remove them. + // If we managed to create any "x=x" assignments, remove them. for (var j = 0; j < maybeRemoveNodes.length; j++) { var node = maybeRemoveNodes[j][1]; if (node[2][1] === node[3][1]) { diff --git a/tools/js_optimizer.py b/tools/js_optimizer.py index 86ff2f8c68f04..e95bc27999274 100644 --- a/tools/js_optimizer.py +++ b/tools/js_optimizer.py @@ -9,7 +9,7 @@ def path_from_root(*pathelems): return os.path.join(__rootpath__, *pathelems) -NATIVE_PASSES = set(['asm', 'asmPreciseF32', 'receiveJSON', 'emitJSON', 'eliminate', 'eliminateMemSafe', 'simplifyExpressions', 'simplifyIfs', 'optimizeFrounds', 'registerize', 'minifyNames', 'minifyLocals', 'minifyWhitespace', 'cleanup', 'asmLastOpts', 'last', 'noop']) +NATIVE_PASSES = set(['asm', 'asmPreciseF32', 'receiveJSON', 'emitJSON', 'eliminate', 'eliminateMemSafe', 'simplifyExpressions', 'simplifyIfs', 'optimizeFrounds', 'registerize', 'registerizeHarder', 'minifyNames', 'minifyLocals', 'minifyWhitespace', 'cleanup', 'asmLastOpts', 'last', 'noop']) JS_OPTIMIZER = path_from_root('tools', 'js-optimizer.js') diff --git a/tools/optimizer/istring.h b/tools/optimizer/istring.h index d8cd3cc5e17f0..bc525b50667ed 100644 --- a/tools/optimizer/istring.h +++ b/tools/optimizer/istring.h @@ -14,13 +14,13 @@ namespace cashew { struct IString { const char *str; - static size_t hash_c(const char *str) { // TODO: optimize? - uint64_t ret = 0; - while (*str) { - ret = (ret*6364136223846793005ULL) + *str; - str++; + static size_t hash_c(const char *str) { // see http://www.cse.yorku.ca/~oz/hash.html + unsigned int hash = 5381; + int c; + while ((c = *str++)) { + hash = ((hash << 5) + hash) ^ c; } - return (size_t)ret; + return (size_t)hash; } class CStringHash : public std::hash<const char *> { @@ -74,6 +74,9 @@ struct IString { //assert((str == other.str) == !strcmp(str, other.str)); return str != other.str; // fast! } + bool operator<(const IString& other) const { + return strcmp(str ? str : "", other.str ? other.str : "") < 0; + } char operator[](int x) { return str[x]; @@ -96,7 +99,8 @@ namespace std { template <> struct hash<cashew::IString> : public unary_function<cashew::IString, size_t> { size_t operator()(const cashew::IString& str) const { - return cashew::IString::hash_c(str.c_str()); + size_t hash = size_t(str.str); + return hash = ((hash << 5) + hash) ^ 5381; /* (hash * 33) ^ c */ } }; diff --git a/tools/optimizer/optimizer.cpp b/tools/optimizer/optimizer.cpp index beca2b08c4475..4e3475e37a234 100644 --- a/tools/optimizer/optimizer.cpp +++ b/tools/optimizer/optimizer.cpp @@ -2512,7 +2512,7 @@ void registerizeHarder(Ref ast) { // Traverse the tree in execution order and synthesize a basic flow-graph. // It's convenient to build a kind of "dual" graph where the nodes identify - // the junctions between blocks at which control-flow may branch, and each + // the junctions between blocks at which control-flow may branch, and each // basic block is an edge connecting two such junctions. // For each junction we store: // * set of blocks that originate at the junction @@ -2530,13 +2530,14 @@ void registerizeHarder(Ref ast) { int id; std::unordered_set<int> inblocks, outblocks; StringSet live; - Junction(int id_) : id(id_) {} + bool checkedLive; + Junction(int id_) : id(id_), checkedLive(false) {} }; struct Node { }; struct Block { int id, entry, exit; - StringSet labels; + std::unordered_set<int> labels; std::vector<Ref> nodes; std::vector<bool> isexpr; StringIntMap use; @@ -2562,6 +2563,7 @@ void registerizeHarder(Ref ast) { Block* nextBasicBlock = nullptr; int isInExpr = 0; std::vector<LabelState> activeLabels; + activeLabels.resize(1); IString nextLoopLabel; const int ENTRY_JUNCTION = 0; @@ -2618,22 +2620,21 @@ void registerizeHarder(Ref ast) { return id; }; - IString NULL_STR; - auto pushActiveLabels = [&](int onContinue, int onBreak) { // Push the target junctions for continuing/breaking a loop. // This should be called before traversing into a loop. + assert(activeLabels.size() > 0); LabelState& prevLabels = activeLabels.back(); LabelState newLabels = prevLabels; - newLabels[NULL_STR] = ContinueBreak(onContinue, onBreak); + newLabels[EMPTY] = ContinueBreak(onContinue, onBreak); if (!!nextLoopLabel) { newLabels[nextLoopLabel] = ContinueBreak(onContinue, onBreak); - nextLoopLabel = NULL_STR; + nextLoopLabel = EMPTY; } // An unlabelled CONTINUE should jump to innermost loop, // ignoring any nested SWITCH statements. - if (onContinue < 0 && prevLabels.count(NULL_STR) > 0) { - newLabels[NULL_STR].co = prevLabels[NULL_STR].co; + if (onContinue < 0 && prevLabels.count(EMPTY) > 0) { + newLabels[EMPTY].co = prevLabels[EMPTY].co; } activeLabels.push_back(newLabels); }; @@ -2645,12 +2646,13 @@ void registerizeHarder(Ref ast) { }; auto markNonLocalJump = [&](IString type, IString label) { - // Complete a block via RETURN, BREAK or CONTINUE. + // Complete a block via RETURN, BREAK or CONTINUE. // This joins the targetted junction and then sets the current junction to null. - // Any code traversed before we get back an existing junction is dead code. + // Any code traversed before we get back to an existing junction is dead code. if (type == RETURN) { joinJunction(EXIT_JUNCTION, false); } else { + assert(activeLabels.size() > 0); assert(activeLabels.back().count(label) > 0); // 'jump to unknown label'); auto targets = activeLabels.back()[label]; if (type == CONTINUE) { @@ -2703,7 +2705,7 @@ void registerizeHarder(Ref ast) { auto addBlockLabel = [&](Ref node) { assert(nextBasicBlock->nodes.size() == 0); // 'cant add label to an in-progress basic block') if (node[0] == NUM) { - nextBasicBlock->labels.insert(node[1]->getIString()); // XXX? + nextBasicBlock->labels.insert(node[1]->getNumber()); } }; @@ -2726,7 +2728,7 @@ void registerizeHarder(Ref ast) { // Any code traversed without an active entry junction must be dead, // as the resulting block could never be entered. Let's remove it. if (currEntryJunction < 0 && junctions.size() > 0) { - safeCopy(node, makeBlock()); + safeCopy(node, makeEmpty()); return; } @@ -2759,7 +2761,7 @@ void registerizeHarder(Ref ast) { } joinJunction(jExit, false); setJunction(jEnter, false); - if (!!node[3]) { + if (node->size() > 3 && !!node[3]) { buildFlowGraph(node[3]); } joinJunction(jExit, false); @@ -2905,7 +2907,7 @@ void registerizeHarder(Ref ast) { // If there's live code here, assume it jumps to case exit. if (currEntryJunction >= 0 && nextBasicBlock->nodes.size() > 0) { if (!!node[2][i][0]) { - markNonLocalJump(RETURN, IString()); + markNonLocalJump(RETURN, EMPTY); } else { joinJunction(jExit, false); } @@ -2924,9 +2926,9 @@ void registerizeHarder(Ref ast) { buildFlowGraph(node[1]); isInExpr--; } - markNonLocalJump(type->getIString(), IString()); + markNonLocalJump(type->getIString(), EMPTY); } else if (type == BREAK || type == CONTINUE) { - markNonLocalJump(type->getIString(), node[1]->getIString()); + markNonLocalJump(type->getIString(), !!node[1] ? node[1]->getIString() : EMPTY); } else if (type == ASSIGN) { isInExpr++; buildFlowGraph(node[3]); @@ -2968,7 +2970,7 @@ void registerizeHarder(Ref ast) { // treat it as a jump to function exit. if (!isInExpr && node[1][0] == NAME) { if (FUNCTIONS_THAT_ALWAYS_THROW.has(node[1][1])) { - markNonLocalJump(RETURN, IString()); + markNonLocalJump(RETURN, EMPTY); } } } else if (type == SEQ || type == SUB) { @@ -2998,7 +3000,7 @@ void registerizeHarder(Ref ast) { // with that value of LABEL as precondition, we tweak the flow graph so // that the former jumps straight to the later. - std::unordered_map<IString, Block*> labelledBlocks; + std::unordered_map<int, Block*> labelledBlocks; typedef std::pair<Ref, Block*> Jump; std::vector<Jump> labelledJumps; @@ -3034,7 +3036,7 @@ void registerizeHarder(Ref ast) { // saving/restoring label to the stack. for (int j = 0; j < block->nodes.size() - 1; j++) { if (block->nodes[j][0] == ASSIGN && block->nodes[j][2][1] == LABEL) { - if (block->nodes[j][3][0] != NUM && block->nodes[j][3][1]->getNumber() != 0) { + if (block->nodes[j][3][0] != NUM || block->nodes[j][3][1]->getNumber() != 0) { labelledBlocks.clear(); labelledJumps.clear(); goto AFTER_FINDLABELLEDBLOCKS; @@ -3062,7 +3064,7 @@ void registerizeHarder(Ref ast) { for (int i = 0; i < labelledJumps.size(); i++) { auto labelVal = labelledJumps[i].first; auto block = labelledJumps[i].second; - Block* targetBlock = labelledBlocks[labelVal->getIString()]; + Block* targetBlock = labelledBlocks[labelVal->getNumber()]; if (targetBlock) { // Redirect its exit to entry of the target block. junctions[block->exit].inblocks.erase(block->id); @@ -3094,6 +3096,7 @@ void registerizeHarder(Ref ast) { } } junc.live = live; + junc.checkedLive = true; }; auto analyzeBlock = [&](Block* block) { @@ -3182,7 +3185,7 @@ void registerizeHarder(Ref ast) { numUsesInExpr++; } }); - safeCopy(node, makeBlock()); + safeCopy(node, makeEmpty()); j = j - numUsesInExpr; removeUnusedNodes(j, 1 + numUsesInExpr); } @@ -3223,8 +3226,9 @@ void registerizeHarder(Ref ast) { jWorklist.pop_back(); jWorklistMap.erase(junc.id); StringSet oldLive = junc.live; // copy it here, to check for changes later + bool oldChecked = junc.checkedLive; analyzeJunction(junc); - if (oldLive != junc.live) { + if (oldChecked != junc.checkedLive || oldLive != junc.live) { // Live set changed, updated predecessor blocks and junctions. for (auto b : junc.inblocks) { if (bWorklistMap.count(b) == 0) { @@ -3279,7 +3283,7 @@ void registerizeHarder(Ref ast) { std::unordered_map<IString, JuncVar> junctionVariables; auto initializeJunctionVariable = [&](IString name) { - junctionVariables[name] = JuncVar(); // XXX + junctionVariables[name].conf.reserve(asmData.locals.size()); }; for (int i = 0; i < junctions.size(); i++) { @@ -3287,10 +3291,8 @@ void registerizeHarder(Ref ast) { for (auto name : junc.live) { if (junctionVariables.count(name) == 0) initializeJunctionVariable(name); // It conflicts with all other names live at this junction. - for (auto otherName : junc.live) { - if (otherName == name) continue; - junctionVariables[name].conf.insert(otherName); - } + junctionVariables[name].conf.insert(junc.live.begin(), junc.live.end()); // XXX this operation is very expensive + junctionVariables[name].conf.erase(name); // except for itself, of course for (auto b : junc.outblocks) { // It conflicts with any output vars of successor blocks, // if they're assigned before it goes dead in that block. @@ -3305,11 +3307,13 @@ void registerizeHarder(Ref ast) { } } // It links with any linkages in the outgoing blocks. - IString linkName = block->link[name]; - if (!!linkName && linkName != name) { - if (junctionVariables.count(linkName) == 0) initializeJunctionVariable(linkName); - junctionVariables[name].link.insert(linkName); - junctionVariables[linkName].link.insert(name); + if (block->link.has(name)) { + IString linkName = block->link[name]; + if (linkName != name) { + if (junctionVariables.count(linkName) == 0) initializeJunctionVariable(linkName); + junctionVariables[name].link.insert(linkName); + junctionVariables[linkName].link.insert(name); + } } } } @@ -3324,7 +3328,8 @@ void registerizeHarder(Ref ast) { sortedJunctionVariables.push_back(pair.first); } std::sort(sortedJunctionVariables.begin(), sortedJunctionVariables.end(), [&](const IString name1, const IString name2) { - return junctionVariables[name2].conf.size() < junctionVariables[name1].conf.size(); //XXX + //return strcmp(name1.str, name2.str) > 0;// XXX junctionVariables[name1].conf.size() > junctionVariables[name2].conf.size(); + return junctionVariables[name1].conf.size() < junctionVariables[name2].conf.size(); }); // We can now assign a register to each junction variable. @@ -3355,11 +3360,10 @@ void registerizeHarder(Ref ast) { } return true; }; - for (int i = 0; i < sortedJunctionVariables.size(); i++) { IString name = sortedJunctionVariables[i]; // It may already be assigned due to linked-variable propagation. - if (!!junctionVariables[name].reg) { + if (junctionVariables[name].reg > 0) { continue; } // Try to use existing registers first. @@ -3444,7 +3448,7 @@ void registerizeHarder(Ref ast) { int reg = assignedRegs[name]; // XXX may insert a zero if (node[0] == NAME) { // A use. Grab a register if it doesn't have one. - if (!reg) { + if (reg <= 0) { if (inputVars.has(name) && j <= block->firstDeadLoc[name]) { // Assignment to an input variable, must use pre-assigned reg. reg = junctionVariables[name].reg; @@ -3461,18 +3465,21 @@ void registerizeHarder(Ref ast) { for (int k = freeRegs.size() - 1; k >= 0; k--) { reg = freeRegs[k]; // Check for conflict with input registers. - if (block->firstKillLoc[name] <= inputDeadLoc[reg]) { - if (name != inputVarsByReg[reg]) { - continue; + if (inputDeadLoc.count(reg) > 0) { + if (block->firstKillLoc[name] <= inputDeadLoc[reg]) { + if (name != inputVarsByReg[reg]) { + continue; + } } } // Found one! assignedRegs[name] = reg; + assert(reg > 0); freeRegs.erase(freeRegs.begin() + k); break; } // If we didn't find a suitable register, create a new one. - if (!assignedRegs.has(name)) { + if (assignedRegs[name] <= 0) { reg = createReg(name); assignedRegs[name] = reg; } @@ -3481,7 +3488,7 @@ void registerizeHarder(Ref ast) { node[1]->setString(allRegs[reg]); } else { // A kill. This frees the assigned register. - assert(!!reg); //, 'live variable doesnt have a reg?') + assert(reg > 0); //, 'live variable doesnt have a reg?') node[2][1]->setString(allRegs[reg]); freeRegs.push_back(reg); assignedRegs.erase(name); @@ -3490,14 +3497,14 @@ void registerizeHarder(Ref ast) { } } } - // If we managed to create an "x=x" assignments, remove them. + // If we managed to create any "x=x" assignments, remove them. for (int j = 0; j < maybeRemoveNodes.size(); j++) { Ref node = maybeRemoveNodes[j].second; if (node[2][1] == node[3][1]) { if (block->isexpr[maybeRemoveNodes[j].first]) { safeCopy(node, node[2]); } else { - safeCopy(node, makeBlock()); + safeCopy(node, makeEmpty()); } } } @@ -3845,7 +3852,7 @@ int main(int argc, char **argv) { else if (str == "optimizeFrounds") optimizeFrounds(doc); else if (str == "simplifyIfs") simplifyIfs(doc); else if (str == "registerize") registerize(doc); - //else if (str == "registerizeHarder") registerizeHarder(doc); + else if (str == "registerizeHarder") registerizeHarder(doc); else if (str == "minifyLocals") minifyLocals(doc); else if (str == "minifyWhitespace") {} else if (str == "asmLastOpts") asmLastOpts(doc); diff --git a/tools/optimizer/parser.h b/tools/optimizer/parser.h index 16fc92df54e16..4ed8523c104d5 100644 --- a/tools/optimizer/parser.h +++ b/tools/optimizer/parser.h @@ -307,8 +307,12 @@ class Parser { NodeRef parseFunction(Frag& frag, char*& src, const char* seps) { Frag name(src); - assert(name.type == IDENT); - src += name.size; + if (name.type == IDENT) { + src += name.size; + } else { + assert(name.type == SEPARATOR && name.str[0] == '('); + name.str = IString(); + } NodeRef ret = Builder::makeFunction(name.str); src = skipSpace(src); assert(*src == '('); @@ -667,7 +671,7 @@ class Parser { ExpressionParts& parts = expressionPartsStack.back(); // |parts| may have been invalidated by that call // we are the toplevel. sort it all out // collapse right to left, highest priority first - //dumpParts(parts); + //dumpParts(parts, 0); for (auto ops : operatorClasses) { if (ops.rtl) { // right to left diff --git a/tools/system_libs.py b/tools/system_libs.py index e0f6fecabbc86..2b5e30f193b17 100644 --- a/tools/system_libs.py +++ b/tools/system_libs.py @@ -104,11 +104,112 @@ def create_libc(): 'shgetc.c', ]], ['math', [ + '__fpclassify.c', + '__fpclassifyf.c', + '__fpclassifyl.c', + '__signbit.c', + '__signbitf.c', + '__signbitl.c', + 'acosh.c', + 'acoshf.c', + 'acoshl.c', + 'asinh.c', + 'asinhf.c', + 'asinhl.c', + 'atanh.c', + 'atanhf.c', + 'atanhl.c', + 'cbrt.c', + 'cbrtf.c', + 'cbrtl.c', + 'copysign.c', + 'copysignf.c', + 'copysignl.c', + 'cosh.c', + 'coshf.c', + 'coshl.c', + 'exp2.c', + 'exp2f.c', + 'exp2l.c', + 'expm1.c', + 'expm1f.c', + 'expm1l.c', + 'fdim.c', + 'fdimf.c', + 'fdiml.c', + 'finite.c', + 'finitef.c', + 'fma.c', + 'fmaf.c', + 'fmal.c', + 'fmax.c', + 'fmaxf.c', + 'fmaxl.c', + 'fmin.c', + 'fminf.c', + 'fminl.c', + 'fmod.c', + 'fmodf.c', + 'fmodl.c', 'frexp.c', 'frexpf.c', 'frexpl.c', + 'hypot.c', + 'hypotf.c', + 'hypotl.c', + 'llrint.c', + 'llrintf.c', + 'llrintl.c', + 'llround.c', + 'llroundf.c', + 'llroundl.c', + 'log10.c', + 'log10f.c', + 'log10l.c', + 'log1p.c', + 'log1pf.c', + 'log1pl.c', + 'log2.c', + 'log2f.c', + 'log2l.c', + 'lrint.c', + 'lrintf.c', + 'lrintl.c', + 'lround.c', + 'lroundf.c', + 'lroundl.c', + 'modf.c', + 'modff.c', + 'modfl.c', + 'nan.c', + 'nanf.c', + 'nanl.c', + 'nearbyint.c', + 'nearbyintf.c', + 'nearbyintl.c', + 'remainder.c', + 'remainderf.c', + 'remainderl.c', + 'rint.c', + 'rintf.c', + 'rintl.c', + 'round.c', + 'roundf.c', + 'roundl.c', 'scalbn.c', 'scalbnl.c', + 'sincos.c', + 'sincosf.c', + 'sincosl.c', + 'sinh.c', + 'sinhf.c', + 'sinhl.c', + 'tanh.c', + 'tanhf.c', + 'tanhl.c', + 'trunc.c', + 'truncf.c', + 'truncl.c', ]], ['multibyte', [ 'wctomb.c', diff --git a/tools/test-js-optimizer-asm-regs-harder-output2.js b/tools/test-js-optimizer-asm-regs-harder-output2.js new file mode 100644 index 0000000000000..2b1e102d4b209 --- /dev/null +++ b/tools/test-js-optimizer-asm-regs-harder-output2.js @@ -0,0 +1,137 @@ +function asm(d1, i2) { + d1 = +d1; + i2 = i2 | 0; + i2 = d1 + d1 | 0; + d1 = d(Math_max(10, Math_min(5, f()))); + i2 = i2 + 2 | 0; + print(i2); + d1 = d1 * 5; + return d1; +} +function _doit(i3, i2, i1) { + i3 = i3 | 0; + i2 = i2 | 0; + i1 = i1 | 0; + i3 = STACKTOP; + _printf(__str | 0, (tempInt = STACKTOP, STACKTOP = STACKTOP + 8 | 0, HEAP32[(tempInt & 16777215) >> 2] = i2, HEAP32[(tempInt + 4 & 16777215) >> 2] = i1, tempInt)); + STACKTOP = i3; + return 0 | 0; +} +function stackRestore(i1) { + i1 = i1 | 0; + STACKTOP = i1; +} +function switchey(d1, i2) { + d1 = +d1; + i2 = i2 | 0; + switch (d1 | 0) { + case 0: + i2 = d1 + d1 | 0; + d1 = d(Math_max(10, Math_min(5, f()))); + i2 = i2 + 2 | 0; + print(i2); + d1 = d1 * 5; + return d1; + case 1: + return 20; + } +} +function switchey2() { + var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, d6 = +0, d7 = +0; + i4 = STACKTOP; + STACKTOP = STACKTOP + 8 | 0; + i3 = 1; + while (1) switch (i3 | 0) { + case 1: + i5 = i4 | 0; + __ZN6RandomC1Ev(i5); + i1 = 0; + i2 = 0; + i3 = 2; + break; + case 2: + d7 = +__ZN6Random3getEf(8, +1); + d6 = +__ZN6Random3getEf(i5, +1); + _printf(24, (tempInt = STACKTOP, STACKTOP = STACKTOP + 16 | 0, HEAPF64[CHECK_ALIGN_8(tempInt | 0) >> 3] = d7, HEAPF64[CHECK_ALIGN_8(tempInt + 8 | 0) >> 3] = d6, tempInt) | 0); + i2 = (d7 != d6 & 1) + i2 | 0; + i1 = i1 + 1 | 0; + if ((i1 | 0) < 100) { + i3 = 2; + break; + } else { + i3 = 3; + break; + } + case 3: + _printf(16, (tempInt = STACKTOP, STACKTOP = STACKTOP + 8 | 0, HEAP32[CHECK_ALIGN_4(tempInt | 0) >> 2] = i2, tempInt) | 0); + STACKTOP = i4; + return 0; + } + return 0; +} +function iffey() { + var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, d6 = +0, d7 = +0; + i4 = STACKTOP; + STACKTOP = STACKTOP + 8 | 0; + i3 = 1; + while (1) { + if (i3 | 0) { + i5 = i4 | 0; + __ZN6RandomC1Ev(i5); + i1 = 0; + i2 = 0; + i3 = 2; + } else { + d7 = +__ZN6Random3getEf(8, +1); + d6 = +__ZN6Random3getEf(i5, +1); + _printf(24, (tempInt = STACKTOP, STACKTOP = STACKTOP + 16 | 0, HEAPF64[CHECK_ALIGN_8(tempInt | 0) >> 3] = d7, HEAPF64[CHECK_ALIGN_8(tempInt + 8 | 0) >> 3] = d6, tempInt) | 0); + i2 = (d7 != d6 & 1) + i2 | 0; + i1 = i1 + 1 | 0; + if ((i1 | 0) < 100) { + i3 = 2; + } else { + return 10; + } + } + } + return 0; +} +function labelledJump(i2) { + i2 = i2 | 0; + var i1 = 0, i3 = 0; + i1 = 2; + if (i2) { + i1 = 17; + i3 = 1; + } + if (i3 == 1) { + i2 = i1 + 1; + } else { + i2 = i1 + 1; + } + return i2; +} +function linkedVars() { + var i1 = 0, i2 = 0; + while (1) { + i2 = 9; + i1 = 5; + while (i2 > 0 | i1 > 0) { + if (i2 < i1) { + i2 = i2 - 1; + } else { + i1 = i1 - 1; + } + } + if (i2 < i1) { + break; + } + } + return i2 + i1; +} +function deadCondExpr(i2) { + i2 = i2 | 0; + var i1 = 0; + return i1 | 0; +} + diff --git a/tools/test-js-optimizer-asm-regs-harder-output3.js b/tools/test-js-optimizer-asm-regs-harder-output3.js new file mode 100644 index 0000000000000..dff908e6b69dd --- /dev/null +++ b/tools/test-js-optimizer-asm-regs-harder-output3.js @@ -0,0 +1,137 @@ +function asm(d1, i2) { + d1 = +d1; + i2 = i2 | 0; + i2 = d1 + d1 | 0; + d1 = d(Math_max(10, Math_min(5, f()))); + i2 = i2 + 2 | 0; + print(i2); + d1 = d1 * 5; + return d1; +} +function _doit(i3, i1, i2) { + i3 = i3 | 0; + i1 = i1 | 0; + i2 = i2 | 0; + i3 = STACKTOP; + _printf(__str | 0, (tempInt = STACKTOP, STACKTOP = STACKTOP + 8 | 0, HEAP32[(tempInt & 16777215) >> 2] = i1, HEAP32[(tempInt + 4 & 16777215) >> 2] = i2, tempInt)); + STACKTOP = i3; + return 0 | 0; +} +function stackRestore(i1) { + i1 = i1 | 0; + STACKTOP = i1; +} +function switchey(d1, i2) { + d1 = +d1; + i2 = i2 | 0; + switch (d1 | 0) { + case 0: + i2 = d1 + d1 | 0; + d1 = d(Math_max(10, Math_min(5, f()))); + i2 = i2 + 2 | 0; + print(i2); + d1 = d1 * 5; + return d1; + case 1: + return 20; + } +} +function switchey2() { + var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, d6 = +0, d7 = +0; + i4 = STACKTOP; + STACKTOP = STACKTOP + 8 | 0; + i3 = 1; + while (1) switch (i3 | 0) { + case 1: + i5 = i4 | 0; + __ZN6RandomC1Ev(i5); + i1 = 0; + i2 = 0; + i3 = 2; + break; + case 2: + d7 = +__ZN6Random3getEf(8, +1); + d6 = +__ZN6Random3getEf(i5, +1); + _printf(24, (tempInt = STACKTOP, STACKTOP = STACKTOP + 16 | 0, HEAPF64[CHECK_ALIGN_8(tempInt | 0) >> 3] = d7, HEAPF64[CHECK_ALIGN_8(tempInt + 8 | 0) >> 3] = d6, tempInt) | 0); + i2 = (d7 != d6 & 1) + i2 | 0; + i1 = i1 + 1 | 0; + if ((i1 | 0) < 100) { + i3 = 2; + break; + } else { + i3 = 3; + break; + } + case 3: + _printf(16, (tempInt = STACKTOP, STACKTOP = STACKTOP + 8 | 0, HEAP32[CHECK_ALIGN_4(tempInt | 0) >> 2] = i2, tempInt) | 0); + STACKTOP = i4; + return 0; + } + return 0; +} +function iffey() { + var i1 = 0, i2 = 0, i3 = 0, i4 = 0, i5 = 0, d6 = +0, d7 = +0; + i4 = STACKTOP; + STACKTOP = STACKTOP + 8 | 0; + i3 = 1; + while (1) { + if (i3 | 0) { + i5 = i4 | 0; + __ZN6RandomC1Ev(i5); + i1 = 0; + i2 = 0; + i3 = 2; + } else { + d7 = +__ZN6Random3getEf(8, +1); + d6 = +__ZN6Random3getEf(i5, +1); + _printf(24, (tempInt = STACKTOP, STACKTOP = STACKTOP + 16 | 0, HEAPF64[CHECK_ALIGN_8(tempInt | 0) >> 3] = d7, HEAPF64[CHECK_ALIGN_8(tempInt + 8 | 0) >> 3] = d6, tempInt) | 0); + i2 = (d7 != d6 & 1) + i2 | 0; + i1 = i1 + 1 | 0; + if ((i1 | 0) < 100) { + i3 = 2; + } else { + return 10; + } + } + } + return 0; +} +function labelledJump(i2) { + i2 = i2 | 0; + var i1 = 0, i3 = 0; + i1 = 2; + if (i2) { + i1 = 17; + i3 = 1; + } + if (i3 == 1) { + i2 = i1 + 1; + } else { + i2 = i1 + 1; + } + return i2; +} +function linkedVars() { + var i1 = 0, i2 = 0; + while (1) { + i1 = 9; + i2 = 5; + while (i1 > 0 | i2 > 0) { + if (i1 < i2) { + i1 = i1 - 1; + } else { + i2 = i2 - 1; + } + } + if (i1 < i2) { + break; + } + } + return i1 + i2; +} +function deadCondExpr(i2) { + i2 = i2 | 0; + var i1 = 0; + return i1 | 0; +} +