diff options
author | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2020-03-26 02:53:59 +0000 |
---|---|---|
committer | vlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4> | 2020-03-26 02:53:59 +0000 |
commit | 73cba9f3bad97a57636033bca90b666551497b5b (patch) | |
tree | be1dd45d4d9792930ff41f62673591070ea5d301 /src | |
parent | 35319c556d6ea9d6b2d5eafc01c7d11efdc1c1f5 (diff) | |
download | mpfr-73cba9f3bad97a57636033bca90b666551497b5b.tar.gz |
Attempt to eliminate issues with aliasing rules. But this triggersubf2
a new failure with -Werror=strict-aliasing on src/fma.c due to
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94337>.
git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/branches/ubf2@13820 280ebfd0-de03-0410-8827-d642c229c3f4
Diffstat (limited to 'src')
-rw-r--r-- | src/fma.c | 8 | ||||
-rw-r--r-- | src/fmma.c | 24 | ||||
-rw-r--r-- | src/mpfr-impl.h | 41 | ||||
-rw-r--r-- | src/ubf.c | 8 |
4 files changed, 47 insertions, 34 deletions
@@ -276,11 +276,11 @@ mpfr_fma (mpfr_ptr s, mpfr_srcptr x, mpfr_srcptr y, mpfr_srcptr z, MPFR_TMP_MARK (marker); un = MPFR_LIMB_SIZE (x) + MPFR_LIMB_SIZE (y); - MPFR_TMP_INIT (up, uu, (mpfr_prec_t) un * GMP_NUMB_BITS, un); - mpfr_ubf_mul_exact (uu, x, y); + MPFR_TMP_INIT (up, uu.m, (mpfr_prec_t) un * GMP_NUMB_BITS, un); + mpfr_ubf_mul_exact (uu.u, x, y); mpfr_clear_flags (); - inexact = mpfr_add (s, (mpfr_srcptr) uu, z, rnd_mode); - MPFR_UBF_CLEAR_EXP (uu); + inexact = mpfr_add (s, uu.m, z, rnd_mode); + MPFR_UBF_CLEAR_EXP (uu.m); MPFR_TMP_FREE (marker); } } diff --git a/src/fmma.c b/src/fmma.c index 492e545e5..a9a6ec90a 100644 --- a/src/fmma.c +++ b/src/fmma.c @@ -48,27 +48,29 @@ mpfr_fmma_aux (mpfr_ptr z, mpfr_srcptr a, mpfr_srcptr b, mpfr_srcptr c, un = MPFR_LIMB_SIZE (a) + MPFR_LIMB_SIZE (b); vn = MPFR_LIMB_SIZE (c) + MPFR_LIMB_SIZE (d); - MPFR_TMP_INIT (up, u, (mpfr_prec_t) un * GMP_NUMB_BITS, un); - MPFR_TMP_INIT (vp, v, (mpfr_prec_t) vn * GMP_NUMB_BITS, vn); + MPFR_TMP_INIT (up, u.m, (mpfr_prec_t) un * GMP_NUMB_BITS, un); + MPFR_TMP_INIT (vp, v.m, (mpfr_prec_t) vn * GMP_NUMB_BITS, vn); - mpfr_ubf_mul_exact (u, a, b); - mpfr_ubf_mul_exact (v, c, d); + mpfr_ubf_mul_exact (u.u, a, b); + mpfr_ubf_mul_exact (v.u, c, d); if (prec_z == MPFR_PREC(a) && prec_z == MPFR_PREC(b) && prec_z == MPFR_PREC(c) && prec_z == MPFR_PREC(d) && un == MPFR_PREC2LIMBS(2 * prec_z)) { MPFR_TMP_INIT (zp, zz, 2 * prec_z, un); - MPFR_PREC(u) = MPFR_PREC(v) = 2 * prec_z; - inex = (neg == 0) ? mpfr_add (zz, (mpfr_srcptr) u, (mpfr_srcptr) v, rnd) - : mpfr_sub (zz, (mpfr_srcptr) u, (mpfr_srcptr) v, rnd); + MPFR_PREC(u.m) = MPFR_PREC(v.m) = 2 * prec_z; + inex = (neg == 0) ? + mpfr_add (zz, u.m, v.m, rnd) : + mpfr_sub (zz, u.m, v.m, rnd); inex = mpfr_set_1_2 (z, zz, rnd, inex); } else - inex = (neg == 0) ? mpfr_add (z, (mpfr_srcptr) u, (mpfr_srcptr) v, rnd) - : mpfr_sub (z, (mpfr_srcptr) u, (mpfr_srcptr) v, rnd); + inex = (neg == 0) ? + mpfr_add (z, u.m, v.m, rnd) : + mpfr_sub (z, u.m, v.m, rnd); - MPFR_UBF_CLEAR_EXP (u); - MPFR_UBF_CLEAR_EXP (v); + MPFR_UBF_CLEAR_EXP (u.m); + MPFR_UBF_CLEAR_EXP (v.m); MPFR_TMP_FREE (marker); diff --git a/src/mpfr-impl.h b/src/mpfr-impl.h index cb7c752a5..64a43e516 100644 --- a/src/mpfr-impl.h +++ b/src/mpfr-impl.h @@ -2522,16 +2522,21 @@ __MPFR_DECLSPEC extern int __gmpfr_cov_sum_tmd[MPFR_RND_MAX][2][2][3][2][2]; extern "C" { #endif -/* An UBF is like a MPFR number, but with an additional mpz_t member, - which is assumed to be present (with a value in it) when the usual - exponent field has the value MPFR_EXP_UBF. The goal of this compatible - representation is to easily be able to support UBF in "normal" code - using the public API. This is some form of "subtyping". +/* An UBF is like a MPFR number, but with an additional member _mpfr_zexp + of type mpz_t, which is assumed to be present (with a value in it) + when the usual exponent field has the value MPFR_EXP_UBF. The goal of + this compatible representation is to easily be able to support UBF in + "normal" code using the public API. This is some form of "subtyping". Unfortunately this breaks aliasing rules, and C does not provide any way to avoid that (except with additional syntax ugliness and API breakage): https://news.ycombinator.com/item?id=11753236 + A workaround should be to use mpfr_ptr to access the usual mpfr_t members + and mpfr_ubf_ptr to access the additional member _mpfr_zexp. And never + use __mpfr_ubf_struct as a declared type; otherwise this would force + __mpfr_ubf_struct to be the effective type of the whole object. + The alignment requirement for __mpfr_ubf_struct (UBF) needs to be at least as strong as the one for __mpfr_struct (MPFR number); this is not required by the C standard, but this should always be the case in practice, since @@ -2545,13 +2550,9 @@ extern "C" { with variadic functions, as the compiler will not be able to check in general. See fmma.c as an example of usage. - In general, the type used for values that may be UBF must be either - mpfr_ubf_t or mpfr_ubf_ptr. The type mpfr_ptr or mpfr_srcptr may be - used for UBF only in the case where the pointer has been converted - from mpfr_ubf_ptr, in order to ensure valid alignment. For instance, - in mpfr_fmma_aux, one uses mpfr_ubf_t to generate the exact products - as UBF; then the corresponding pointers are converted to mpfr_srcptr - for mpfr_add (even though they point to UBF). + When generating a pointer of a value that may be a UBF, make sure + that the equivalent of mpfr_ubf_ptr is used, but be careful with + the aliasing rules. Functions that can accept either MPFR arguments (mpfr_ptr type) or UBF arguments (mpfr_ubf_ptr type) must use a pointer type that can @@ -2572,9 +2573,16 @@ typedef struct { mpz_t _mpfr_zexp; } __mpfr_ubf_struct; -typedef __mpfr_ubf_struct mpfr_ubf_t[1]; typedef __mpfr_ubf_struct *mpfr_ubf_ptr; +/* The following is a trick to allocate a UBF as an automatic variable + with the required alignment but without forcing the effective type + to __mpfr_ubf_struct, which would break the aliasing rules. */ +typedef union { + __mpfr_ubf_struct u[1]; + __mpfr_struct m[1]; +} mpfr_ubf_t; + __MPFR_DECLSPEC void mpfr_ubf_mul_exact (mpfr_ubf_ptr, mpfr_srcptr, mpfr_srcptr); __MPFR_DECLSPEC int mpfr_ubf_exp_less_p (mpfr_srcptr, mpfr_srcptr); @@ -2589,11 +2597,12 @@ __MPFR_DECLSPEC mpfr_exp_t mpfr_ubf_diff_exp (mpfr_srcptr, mpfr_srcptr); For practical reasons, the type of the argument x can be either mpfr_ubf_ptr or mpfr_ptr, since the latter is used in functions that accept both MPFR numbers and UBF's; this is checked by the - code "(x)->_mpfr_exp". + code "(x)->_mpfr_exp" (the "sizeof" prevents an access, which + could be undefined behavior, depending on the type of x). This macro can be used when building a UBF. So we do not check that the _mpfr_exp field has the value MPFR_EXP_UBF. */ #define MPFR_ZEXP(x) \ - ((void) (x)->_mpfr_exp, \ + ((void) sizeof ((x)->_mpfr_exp), \ ((mpfr_ubf_ptr) (x))->_mpfr_zexp) /* If x is a UBF, clear its mpz_t exponent. */ @@ -2604,6 +2613,6 @@ __MPFR_DECLSPEC mpfr_exp_t mpfr_ubf_diff_exp (mpfr_srcptr, mpfr_srcptr); the interval [MPFR_EXP_MIN,MPFR_EXP_MAX]). */ #define MPFR_UBF_GET_EXP(x) \ (MPFR_IS_UBF (x) ? mpfr_ubf_zexp2exp (MPFR_ZEXP (x)) : \ - MPFR_GET_EXP ((mpfr_ptr) (x))) + MPFR_GET_EXP (x)) #endif /* __MPFR_IMPL_H__ */ @@ -71,8 +71,10 @@ mpfr_init_get_zexp (mpz_ptr ez, mpfr_srcptr x) (mpfr_srcptr can be seen a bit like void *, but is stronger). This function does not change the flags, except in case of NaN. */ void -mpfr_ubf_mul_exact (mpfr_ubf_ptr a, mpfr_srcptr b, mpfr_srcptr c) +mpfr_ubf_mul_exact (mpfr_ubf_ptr aa, mpfr_srcptr b, mpfr_srcptr c) { + mpfr_ptr a = (mpfr_ptr) aa; + MPFR_LOG_FUNC (("b[%Pu]=%.*Rg c[%Pu]=%.*Rg", mpfr_get_prec (b), mpfr_log_prec, b, @@ -80,8 +82,8 @@ mpfr_ubf_mul_exact (mpfr_ubf_ptr a, mpfr_srcptr b, mpfr_srcptr c) ("a[%Pu]=%.*Rg", mpfr_get_prec (a), mpfr_log_prec, a)); - MPFR_ASSERTD ((mpfr_ptr) a != b); - MPFR_ASSERTD ((mpfr_ptr) a != c); + MPFR_ASSERTD (a != b); + MPFR_ASSERTD (a != c); MPFR_SIGN (a) = MPFR_MULT_SIGN (MPFR_SIGN (b), MPFR_SIGN (c)); if (MPFR_ARE_SINGULAR (b, c)) |