This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[Patch,Fortran] PR40675: Fix SIGN for negative zero
- From: Tobias Burnus <burnus at net-b dot de>
- To: fortran at gcc dot gnu dot org, gcc-patches at gcc dot gnu dot org
- Date: Wed, 8 Jul 2009 19:02:29 +0200
- Subject: [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