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