summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2020-03-26 02:53:59 +0000
committervlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2020-03-26 02:53:59 +0000
commit73cba9f3bad97a57636033bca90b666551497b5b (patch)
treebe1dd45d4d9792930ff41f62673591070ea5d301
parent35319c556d6ea9d6b2d5eafc01c7d11efdc1c1f5 (diff)
downloadmpfr-ubf2.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
-rw-r--r--src/fma.c8
-rw-r--r--src/fmma.c24
-rw-r--r--src/mpfr-impl.h41
-rw-r--r--src/ubf.c8
-rw-r--r--tests/tsub.c2
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++)