On Mon, Feb 5, 2018 at 11:26 AM, Ian Lance Taylor <[email protected]> wrote:
> On Mon, Feb 5, 2018 at 10:47 AM, Rainer Orth
> <[email protected]> wrote:
>>
>>> This patch to the Go frontend checks for negative numbers with very
>>> small magnitudes that will round to negative zero, and forces them to
>>> positive zero instead. This implements the spec clarification in
>>> https://golang.org/cl/14727. The test is in
>>> https://golang.org/cl/91895. This fixes golang.org/issue/12621.
>>> Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed
>>> to mainline.
>>
>> unfortunately, this broke bootstrap with mpfr 2.4.2, which is still the
>> minimum version documented in install.texi:
>
> Bother. Thanks for the note. I've rolled back the patch, as follows.
I have now reimplemented the patch, using only MPFR 2.4.2 API. This
version is better anyhow. Committed as follows after testing.
Ian
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE (revision 257413)
+++ gcc/go/gofrontend/MERGE (working copy)
@@ -1,4 +1,4 @@
-1927b40e59e7c2067ecb03384b331d1be3cb5eea
+02f11a2d5cf0db2c2675c13d92bb69529f2175dd
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc (revision 257393)
+++ gcc/go/gofrontend/expressions.cc (working copy)
@@ -16158,10 +16158,16 @@ Numeric_constant::set_float(Type* type,
this->clear();
this->classification_ = NC_FLOAT;
this->type_ = type;
+
// Numeric constants do not have negative zero values, so remove
// them here. They also don't have infinity or NaN values, but we
// should never see them here.
- if (mpfr_zero_p(val))
+ int bits = 0;
+ if (type != NULL
+ && type->float_type() != NULL
+ && !type->float_type()->is_abstract())
+ bits = type->float_type()->bits();
+ if (Numeric_constant::is_float_neg_zero(val, bits))
mpfr_init_set_ui(this->u_.float_val, 0, GMP_RNDN);
else
mpfr_init_set(this->u_.float_val, val, GMP_RNDN);
@@ -16175,8 +16181,60 @@ Numeric_constant::set_complex(Type* type
this->clear();
this->classification_ = NC_COMPLEX;
this->type_ = type;
+
+ // Avoid negative zero as in set_float.
+ int bits = 0;
+ if (type != NULL
+ && type->complex_type() != NULL
+ && !type->complex_type()->is_abstract())
+ bits = type->complex_type()->bits() / 2;
+
+ mpfr_t real;
+ mpfr_init_set(real, mpc_realref(val), GMP_RNDN);
+ if (Numeric_constant::is_float_neg_zero(real, bits))
+ mpfr_set_ui(real, 0, GMP_RNDN);
+
+ mpfr_t imag;
+ mpfr_init_set(imag, mpc_imagref(val), GMP_RNDN);
+ if (Numeric_constant::is_float_neg_zero(imag, bits))
+ mpfr_set_ui(imag, 0, GMP_RNDN);
+
mpc_init2(this->u_.complex_val, mpc_precision);
- mpc_set(this->u_.complex_val, val, MPC_RNDNN);
+ mpc_set_fr_fr(this->u_.complex_val, real, imag, MPC_RNDNN);
+
+ mpfr_clear(real);
+ mpfr_clear(imag);
+}
+
+// Return whether VAL, at a precision of BITS, is a negative zero.
+// BITS may be zero in which case it is ignored.
+
+bool
+Numeric_constant::is_float_neg_zero(const mpfr_t val, int bits)
+{
+ if (!mpfr_signbit(val))
+ return false;
+ if (mpfr_zero_p(val))
+ return true;
+ mp_exp_t min_exp;
+ switch (bits)
+ {
+ case 0:
+ return false;
+ case 32:
+ // In a denormalized float32 the exponent is -126, and there are
+ // 24 bits of which at least the last must be 1, so the smallest
+ // representable non-zero exponent is -126 - (24 - 1) == -149.
+ min_exp = -149;
+ break;
+ case 64:
+ // Minimum exponent is -1022, there are 53 bits.
+ min_exp = -1074;
+ break;
+ default:
+ go_unreachable();
+ }
+ return mpfr_get_exp(val) < min_exp;
}
// Get an int value.
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h (revision 257393)
+++ gcc/go/gofrontend/expressions.h (working copy)
@@ -4220,6 +4220,9 @@ class Numeric_constant
bool
check_complex_type(Complex_type*, bool, Location);
+ static bool
+ is_float_neg_zero(const mpfr_t, int bits);
+
// The kinds of constants.
enum Classification
{