From 73cba9f3bad97a57636033bca90b666551497b5b Mon Sep 17 00:00:00 2001 From: vlefevre Date: Thu, 26 Mar 2020 02:53:59 +0000 Subject: Attempt to eliminate issues with aliasing rules. But this triggers a new failure with -Werror=strict-aliasing on src/fma.c due to . git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/branches/ubf2@13820 280ebfd0-de03-0410-8827-d642c229c3f4 --- src/fma.c | 8 ++++---- src/fmma.c | 24 +++++++++++++----------- src/mpfr-impl.h | 41 +++++++++++++++++++++++++---------------- src/ubf.c | 8 +++++--- tests/tsub.c | 2 +- 5 files changed, 48 insertions(+), 35 deletions(-) diff --git a/src/fma.c b/src/fma.c index 44a50553b..3be65b2de 100644 --- a/src/fma.c +++ b/src/fma.c @@ -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__ */ diff --git a/src/ubf.c b/src/ubf.c index 8b3ba066b..b1e2391be 100644 --- a/src/ubf.c +++ b/src/ubf.c @@ -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)) diff --git a/tests/tsub.c b/tests/tsub.c index 4493f3a57..58c2b3efc 100644 --- a/tests/tsub.c +++ b/tests/tsub.c @@ -1201,7 +1201,7 @@ static void test_ubf_aux (void) mpfr_init2 (w, 2); for (i = 0; i < 11; i++) - p[i] = (mpfr_ptr) x[i]; + p[i] = x[i].m; /* exact zero result, with small and large exponents */ for (i = 0; i < 2; i++) -- cgit v1.2.1