compiler: avoid negative zero in float constants
authorIan Lance Taylor <ian@gcc.gnu.org>
Mon, 5 Feb 2018 15:28:59 +0000 (15:28 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Mon, 5 Feb 2018 15:28:59 +0000 (15:28 +0000)
    Check for negative numbers with very small magnitudes that will round
    to negative zero, and force 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.

    Fixes golang/go#12621

    Reviewed-on: https://go-review.googlesource.com/91915

From-SVN: r257390

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h

index 3588a8a7a6ac69c4e741cfc4081738de6aee9245..545b40f42e4f052484dc8d0d165025cd606eb920 100644 (file)
@@ -1,4 +1,4 @@
-36594b69b94326014c331fe50a5a345ef4f8de16
+7eebd495df915ab87926b8dd88f554674cfdacea
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 8555c052980812559fc21c62eb36150ce555f6a0..03f8c68cace113dcd98769e6081de1abe7da4cd4 100644 (file)
@@ -16158,10 +16158,16 @@ Numeric_constant::set_float(Type* type, const mpfr_t val)
   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_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,50 @@ Numeric_constant::set_complex(Type* type, const mpc_t val)
   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_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_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 zero.  BITS may be
+// zero in which case it is ignored.
+
+bool
+Numeric_constant::is_float_zero(const mpfr_t val, int bits)
+{
+  if (mpfr_zero_p(val))
+    return true;
+  switch (bits)
+    {
+    case 0:
+      return false;
+    case 32:
+      return mpfr_get_flt(val, GMP_RNDN) == 0;
+    case 64:
+      return mpfr_get_d(val, GMP_RNDN) == 0;
+    default:
+      go_unreachable();
+    }
 }
 
 // Get an int value.
index d16a284b6b04c766430f7b0c6ee3c4ad11b0480c..3acaeb2b022a1fc71ae2af4c866e41461cd4df18 100644 (file)
@@ -4220,6 +4220,9 @@ class Numeric_constant
   bool
   check_complex_type(Complex_type*, bool, Location);
 
+  static bool
+  is_float_zero(const mpfr_t, int bits);
+
   // The kinds of constants.
   enum Classification
   {