diff options
Diffstat (limited to 'main/musl/0013-math-explicitly-promote-expressions-to-excess-precis.patch')
-rw-r--r-- | main/musl/0013-math-explicitly-promote-expressions-to-excess-precis.patch | 84 |
1 files changed, 84 insertions, 0 deletions
diff --git a/main/musl/0013-math-explicitly-promote-expressions-to-excess-precis.patch b/main/musl/0013-math-explicitly-promote-expressions-to-excess-precis.patch new file mode 100644 index 0000000000..c98d9b52b7 --- /dev/null +++ b/main/musl/0013-math-explicitly-promote-expressions-to-excess-precis.patch @@ -0,0 +1,84 @@ +From 8eead3ef18ea71a64ef3cbff8c09bac3b82f1242 Mon Sep 17 00:00:00 2001 +From: Rich Felker <dalias@aerifal.cx> +Date: Sat, 21 Nov 2015 21:23:30 +0000 +Subject: [PATCH] math: explicitly promote expressions to excess-precision + types + +a conforming compiler for an arch with excess precision floating point +(FLT_EVAL_METHOD!=0; presently i386 is the only such arch supported) +computes all intermediate results in the types float_t and double_t +rather than the nominal type of the expression. some incorrect +compilers, however, only keep excess precision in registers, and +convert down to the nominal type when spilling intermediate results to +memory, yielding unpredictable results that depend on the compiler's +choices of what/when to spill. in particular, this happens on old gcc +versions with -ffloat-store, which we need in order to work around +bugs where the compiler wrongly keeps explicitly-dropped excess +precision. + +by explicitly converting to double_t where expressions are expected be +be evaluated in double_t precision, we can avoid depending on the +compiler to get types correct when spilling; the nominal and +intermediate precision now match. this commit should not change the +code generated by correct compilers, or by old ones on non-i386 archs +where double_t is defined as double. + +this fixes a serious bug in argument reduction observed on i386 with +gcc 4.2: for values of x outside the unit circle, sin(x) was producing +results outside the interval [-1,1]. changes made in commit +0ce946cf808274c2d6e5419b139e130c8ad4bd30 were likely responsible for +breaking compatibility with this and other old gcc versions. + +patch by Szabolcs Nagy. +--- + src/math/__rem_pio2.c | 2 +- + src/math/__rem_pio2f.c | 2 +- + src/math/hypot.c | 4 ++-- + 3 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/math/__rem_pio2.c b/src/math/__rem_pio2.c +index a40db9f..d403f81 100644 +--- a/src/math/__rem_pio2.c ++++ b/src/math/__rem_pio2.c +@@ -118,7 +118,7 @@ int __rem_pio2(double x, double *y) + if (ix < 0x413921fb) { /* |x| ~< 2^20*(pi/2), medium size */ + medium: + /* rint(x/(pi/2)), Assume round-to-nearest. */ +- fn = x*invpio2 + toint - toint; ++ fn = (double_t)x*invpio2 + toint - toint; + n = (int32_t)fn; + r = x - fn*pio2_1; + w = fn*pio2_1t; /* 1st round, good to 85 bits */ +diff --git a/src/math/__rem_pio2f.c b/src/math/__rem_pio2f.c +index f516385..4473c1c 100644 +--- a/src/math/__rem_pio2f.c ++++ b/src/math/__rem_pio2f.c +@@ -51,7 +51,7 @@ int __rem_pio2f(float x, double *y) + /* 25+53 bit pi is good enough for medium size */ + if (ix < 0x4dc90fdb) { /* |x| ~< 2^28*(pi/2), medium size */ + /* Use a specialized rint() to get fn. Assume round-to-nearest. */ +- fn = x*invpio2 + toint - toint; ++ fn = (double_t)x*invpio2 + toint - toint; + n = (int32_t)fn; + *y = x - fn*pio2_1 - fn*pio2_1t; + return n; +diff --git a/src/math/hypot.c b/src/math/hypot.c +index 29ec6a4..6071bf1 100644 +--- a/src/math/hypot.c ++++ b/src/math/hypot.c +@@ -12,10 +12,10 @@ static void sq(double_t *hi, double_t *lo, double x) + { + double_t xh, xl, xc; + +- xc = x*SPLIT; ++ xc = (double_t)x*SPLIT; + xh = x - xc + xc; + xl = x - xh; +- *hi = x*x; ++ *hi = (double_t)x*x; + *lo = xh*xh - *hi + 2*xh*xl + xl*xl; + } + +-- +2.7.0 + |