This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch,Fortran] PR40675: Fix SIGN for negative zero


Dear all,

the attached patch does two things:

a) It properly treats -0.0 in initialization expressions;
   before 0.0 and -0.0 where treated alike and the code was
   quite complicated. (The new code requires MPFR 2.3.0 but
   that is also what GCC requires.)
   As "-0.0" does not exist, only "-" applied on "0.0"
   (yielding 0.0) and as I failed to come up with a working
   example for a -0.0 (even using nearest and trigonometric
   functions), I think I can negate the practical relevance.

b) For run-time evaluation: One can create programs which
   depend on SIGN(x, 0.0) and sign(x, -0.0) returning the
   same value. Whether such programs are valid Fortran 77/90
   programs is arguable but they are not outright wrong and
   compilers such as g77, ifort (up to 11.1), sunf95, ...
   treat 0.0 and -0.0 as positive in SIGN.
   As we already had -fsign-zero to print "-0.0" as "0.0" for
   Fortran 77 compatibility, I extended this to SIGN, which
   allows a F77 program at Sandia National Lab to run.

Warning: -fsign-zero (gfortran) and -fsigned-zeros (middle end)
shall not be confused!

Build and regtested on x86-64-linux.
OK for the trunk?

Tobias

Sidenote: I actually did not check whether the -0.0 was really
only introduced with Fortran 95 or whether it was already in F90;
I only have indications that is new in F95.

PS: Other compilers such as ifort have also a flag for -0.0
regarding I/O and SIGN.
2009-07-08  Tobias Burnus  <burnus@net-b.de>

	PR fortran/40675
	* simplify.c (gfc_simplify_sign): Handle signed zero correctly.
	* trans-intrinsic.c (gfc_conv_intrinsic_sign): Support
	-fno-sign-zero.
	* invoke.texi (-fno-sign-zero): Add text regarding SIGN intrinsic.

2009-07-08  Tobias Burnus  <burnus@net-b.de>

	PR fortran/40675
	* gfortran.dg/nosigned_zero.f: New test.

Index: gcc/fortran/simplify.c
===================================================================
--- gcc/fortran/simplify.c	(revision 149362)
+++ gcc/fortran/simplify.c	(working copy)
@@ -4957,16 +4957,15 @@ gfc_simplify_sign (gfc_expr *x, gfc_expr
       mpz_abs (result->value.integer, x->value.integer);
       if (mpz_sgn (y->value.integer) < 0)
 	mpz_neg (result->value.integer, result->value.integer);
-
       break;
 
     case BT_REAL:
-      /* TODO: Handle -0.0 and +0.0 correctly on machines that support
-	 it.  */
-      mpfr_abs (result->value.real, x->value.real, GFC_RND_MODE);
-      if (mpfr_sgn (y->value.real) < 0)
-	mpfr_neg (result->value.real, result->value.real, GFC_RND_MODE);
-
+      if (gfc_option.flag_sign_zero)
+	mpfr_copysign (result->value.real, x->value.real, y->value.real,
+		       GFC_RND_MODE);
+      else
+	mpfr_setsign (result->value.real, x->value.real,
+		      mpfr_sgn (y->value.real) < 0 ? 1 : 0, GFC_RND_MODE);
       break;
 
     default:
Index: gcc/fortran/trans-intrinsic.c
===================================================================
--- gcc/fortran/trans-intrinsic.c	(revision 149362)
+++ gcc/fortran/trans-intrinsic.c	(working copy)
@@ -1263,22 +1263,41 @@ gfc_conv_intrinsic_sign (gfc_se * se, gf
   gfc_conv_intrinsic_function_args (se, expr, args, 2);
   if (expr->ts.type == BT_REAL)
     {
+      tree abs;
+
       switch (expr->ts.kind)
 	{
 	case 4:
 	  tmp = built_in_decls[BUILT_IN_COPYSIGNF];
+	  abs = built_in_decls[BUILT_IN_FABSF];
 	  break;
 	case 8:
 	  tmp = built_in_decls[BUILT_IN_COPYSIGN];
+	  abs = built_in_decls[BUILT_IN_FABS];
 	  break;
 	case 10:
 	case 16:
 	  tmp = built_in_decls[BUILT_IN_COPYSIGNL];
+	  abs = built_in_decls[BUILT_IN_FABSL];
 	  break;
 	default:
 	  gcc_unreachable ();
 	}
-      se->expr = build_call_expr (tmp, 2, args[0], args[1]);
+
+      /* We explicitly have to ignore the minus sign. We do so by using
+	 result = (arg1 == 0) ? abs(arg0) : copysign(arg0, arg1).  */
+      if (!gfc_option.flag_sign_zero
+	  && MODE_HAS_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (args[1]))))
+	{
+	  tree cond, zero;
+	  zero = build_real_from_int_cst (TREE_TYPE (args[1]), integer_zero_node);
+	  cond = fold_build2 (EQ_EXPR, boolean_type_node, args[1], zero);
+	  se->expr = fold_build3 (COND_EXPR, TREE_TYPE (args[0]), cond,
+				  build_call_expr (abs, 1, args[0]),
+				  build_call_expr (tmp, 2, args[0], args[1]));
+	}
+      else
+	se->expr = build_call_expr (tmp, 2, args[0], args[1]);
       return;
     }
 
Index: gcc/fortran/invoke.texi
===================================================================
--- gcc/fortran/invoke.texi	(revision 149362)
+++ gcc/fortran/invoke.texi	(working copy)
@@ -1024,9 +1024,12 @@ really useful for use by the gfortran te
 
 @item -fsign-zero
 @opindex @code{fsign-zero}
-When writing zero values, show the negative sign if the sign bit is set.
-@code{fno-sign-zero} does not print the negative sign of zero values for
-compatibility with F77.  Default behavior is to show the negative sign.
+When enabled, floating point numbers of value zero with the sign bit set
+are written as negative number in formatted output and treated as
+negative in the @code{SIGN} intrinsic.  @code{fno-sign-zero} does not
+print the negative sign of zero values and regards zero as positive
+number in the @code{SIGN} intrinsic for compatibility with F77.
+Default behavior is to show the negative sign.
 @end table
 
 @node Code Gen Options
Index: gcc/testsuite/gfortran.dg/nosigned_zero.f
===================================================================
--- gcc/testsuite/gfortran.dg/nosigned_zero.f	(revision 0)
+++ gcc/testsuite/gfortran.dg/nosigned_zero.f	(revision 0)
@@ -0,0 +1,28 @@
+! { dg-do "run" }
+! { dg-option "-fno-sign-zero" }
+!
+! PR fortran/40675
+!
+! Fortran 77 just had: "The value of a signed zero is the same as
+! the value of an unsigned zero." and g77 returned for SIGN(1.0, -0.0) = 1.0
+!
+! Fortran 95+ has for SIGN: "Case  (iv):  If B is of type real and is zero,
+! then ... (c) If B is negative real zero, the value of the result is -|A|".
+! On architectures, where signed zeros are supported, gfortran's SIGN thus
+! returns for B=-0.0 the -|A|. That breaks programs such as the one below, which
+! is semi-conforming to Fortran 77/90.
+!
+! Contributed by Greg Sjaardema <gdsjaar@sandia.gov>.
+!
+      program main
+      val = 0.0
+      test = sign(0.5, val) - sign(0.5, -val)
+      write (*,*) 'With val = ', val, ' test = ', test
+      if (test .eq. 1) then
+         write(*,*) 'fail'
+      elseif (test .eq. 0) then
+         write(*,*) 'pass'
+      endif
+
+      stop
+      end

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]