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]

[Committed] PR576: constant folding vs. FP rounding modes


The following patch improves/fixes the behaviour of GCC's -frounding-math
to prevent compile-time evaluation of floating point expressions whose
result may be affected by the run-time FP rounding mode.  The compiler
option -frounding-math, which is off by default, is used to disable
transformations of FP expressions that may be affected by rounding mode,
and is intended to be used when it's known the program makes use of
non-default FPU control settings.  Previously, however, compile-time
evaluation of FP operators with constant operands were unaffected.

The following patch tweaks the interface of real.c such that it now
returns a Boolean result indicating whether the result may potentially
be inexact due to overflow or lack of precision.  This result is then
used in fold-const.c and simplify-rtx.c to prevent compile-time
evaluation of expressions *only* when the -frounding-math is specified
*and* the result is not perfectly representable in the specified machine
mode.  Hence, there's no functional change when flag_rounding_math is
false, by default, and when the user specifies -frounding-math we
continue to evaluate 1.0/2.0, but leave 1.0/3.0 to be evaluated at
run-time.

These changes now provides a work-around/solution for PR optimization/576
where, when compiled with "-O2 -ffloat-store -frounding-math" the
testcase attached to that PR now generates the expected results.

Additionally, these improvements to the middle-end's infrastructure
provide the logical next step towards implementing C99's FENV_ACCESS
pragma (which might intially be emulated via flag_rounding_math, but
ultimately requires extra bits and/or operand codes) and also fixing
the current "long double" issues on Darwin/IRIX where the use of pairs
of IEEE  doubles can provide effective mantissa precision beyond that
available to GCC's internal floating point emulation.


The following patch has been tested on i686-pc-linux-gnu with a full
"make bootstrap", all default languages, and regression tested with
a top-level "make -k check" with no new failures.

Committed to mainline CVS.



2005-01-21  Roger Sayle  <roger@eyesopen.com>

	PR rtl-optimization/576
	* real.c (real_arithmetic): Change return type from void to bool
	to return an indication that the result may be inexact.
	* real.h (real_arithmeric): Update prototype.
	* fold-const.c (const_binop):  Don't constant fold floating
	point expressions when the user specifies -frounding-math and
	the result may depend upon the run-time rounding mode.
	(fold_convert_const_real_from_real): Clean-up.
	(fold_initializer): Ignore flag_rounding_math for initializers.
	* simplify-rtx.c (simplify_binary_operation): Likewise, don't
	constant fold FP operations with flag_rounding_math if the
	result may depend upon the run-time rounding mode.


Index: real.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.c,v
retrieving revision 1.149
diff -c -3 -p -r1.149 real.c
*** real.c	20 Jan 2005 21:53:31 -0000	1.149
--- real.c	21 Jan 2005 04:31:56 -0000
*************** do_fix_trunc (REAL_VALUE_TYPE *r, const
*** 972,980 ****
  }

  /* Perform the binary or unary operation described by CODE.
!    For a unary operation, leave OP1 NULL.  */

! void
  real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0,
  		 const REAL_VALUE_TYPE *op1)
  {
--- 972,981 ----
  }

  /* Perform the binary or unary operation described by CODE.
!    For a unary operation, leave OP1 NULL.  This function returns
!    true if the result may be inexact due to loss of precision.  */

! bool
  real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0,
  		 const REAL_VALUE_TYPE *op1)
  {
*************** real_arithmetic (REAL_VALUE_TYPE *r, int
*** 983,1002 ****
    switch (code)
      {
      case PLUS_EXPR:
!       do_add (r, op0, op1, 0);
!       break;

      case MINUS_EXPR:
!       do_add (r, op0, op1, 1);
!       break;

      case MULT_EXPR:
!       do_multiply (r, op0, op1);
!       break;

      case RDIV_EXPR:
!       do_divide (r, op0, op1);
!       break;

      case MIN_EXPR:
        if (op1->cl == rvc_nan)
--- 984,999 ----
    switch (code)
      {
      case PLUS_EXPR:
!       return do_add (r, op0, op1, 0);

      case MINUS_EXPR:
!       return do_add (r, op0, op1, 1);

      case MULT_EXPR:
!       return do_multiply (r, op0, op1);

      case RDIV_EXPR:
!       return do_divide (r, op0, op1);

      case MIN_EXPR:
        if (op1->cl == rvc_nan)
*************** real_arithmetic (REAL_VALUE_TYPE *r, int
*** 1033,1038 ****
--- 1030,1036 ----
      default:
        gcc_unreachable ();
      }
+   return false;
  }

  /* Legacy.  Similar, but return the result directly.  */
Index: real.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/real.h,v
retrieving revision 1.79
diff -c -3 -p -r1.79 real.h
*** real.h	25 Jul 2004 17:57:23 -0000	1.79
--- real.h	21 Jan 2005 04:31:56 -0000
*************** extern const struct real_format *
*** 160,166 ****
  /* Declare functions in real.c.  */

  /* Binary or unary arithmetic on tree_code.  */
! extern void real_arithmetic (REAL_VALUE_TYPE *, int, const REAL_VALUE_TYPE *,
  			     const REAL_VALUE_TYPE *);

  /* Compare reals by tree_code.  */
--- 160,166 ----
  /* Declare functions in real.c.  */

  /* Binary or unary arithmetic on tree_code.  */
! extern bool real_arithmetic (REAL_VALUE_TYPE *, int, const REAL_VALUE_TYPE *,
  			     const REAL_VALUE_TYPE *);

  /* Compare reals by tree_code.  */
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.495
diff -c -3 -p -r1.495 fold-const.c
*** fold-const.c	18 Jan 2005 23:06:56 -0000	1.495
--- fold-const.c	21 Jan 2005 04:31:59 -0000
*************** const_binop (enum tree_code code, tree a
*** 1482,1487 ****
--- 1482,1489 ----
        REAL_VALUE_TYPE d1;
        REAL_VALUE_TYPE d2;
        REAL_VALUE_TYPE value;
+       REAL_VALUE_TYPE result;
+       bool inexact;
        tree t, type;

        d1 = TREE_REAL_CST (arg1);
*************** const_binop (enum tree_code code, tree a
*** 1510,1518 ****
        else if (REAL_VALUE_ISNAN (d2))
  	return arg2;

!       REAL_ARITHMETIC (value, code, d1, d2);

!       t = build_real (type, real_value_truncate (mode, value));

        TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2);
        TREE_CONSTANT_OVERFLOW (t)
--- 1512,1529 ----
        else if (REAL_VALUE_ISNAN (d2))
  	return arg2;

!       inexact = real_arithmetic (&value, code, &d1, &d2);
!       real_convert (&result, mode, &value);

!       /* Don't constant fold this floating point operation if the
! 	 result may dependent upon the run-time rounding mode and
! 	 flag_rounding_math is set.  */
!
!       if (flag_rounding_math
! 	  && (inexact || !real_identical (&result, &value)))
! 	return NULL_TREE;
!
!       t = build_real (type, result);

        TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2);
        TREE_CONSTANT_OVERFLOW (t)
*************** fold_convert_const_int_from_real (enum t
*** 1808,1827 ****
  static tree
  fold_convert_const_real_from_real (tree type, tree arg1)
  {
    tree t;

!   if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg1)))
!     {
!       /* We make a copy of ARG1 so that we don't modify an
! 	 existing constant tree.  */
!       t = copy_node (arg1);
!       TREE_TYPE (t) = type;
!       return t;
!     }
!
!   t = build_real (type,
! 		  real_value_truncate (TYPE_MODE (type),
! 				       TREE_REAL_CST (arg1)));

    TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1);
    TREE_CONSTANT_OVERFLOW (t)
--- 1819,1829 ----
  static tree
  fold_convert_const_real_from_real (tree type, tree arg1)
  {
+   REAL_VALUE_TYPE value;
    tree t;

!   real_convert (&value, TYPE_MODE (type), &TREE_REAL_CST (arg1));
!   t = build_real (type, value);

    TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1);
    TREE_CONSTANT_OVERFLOW (t)
*************** fold_initializer (tree expr)
*** 9506,9522 ****
--- 9508,9527 ----
  {
    int saved_signaling_nans = flag_signaling_nans;
    int saved_trapping_math = flag_trapping_math;
+   int saved_rounding_math = flag_rounding_math;
    int saved_trapv = flag_trapv;
    tree result;

    flag_signaling_nans = 0;
    flag_trapping_math = 0;
+   flag_rounding_math = 0;
    flag_trapv = 0;

    result = fold (expr);

    flag_signaling_nans = saved_signaling_nans;
    flag_trapping_math = saved_trapping_math;
+   flag_rounding_math = saved_rounding_math;
    flag_trapv = saved_trapv;

    return result;
Index: simplify-rtx.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/simplify-rtx.c,v
retrieving revision 1.222
diff -c -3 -p -r1.222 simplify-rtx.c
*** simplify-rtx.c	14 Jan 2005 04:17:13 -0000	1.222
--- simplify-rtx.c	21 Jan 2005 04:31:59 -0000
*************** simplify_binary_operation (enum rtx_code
*** 1288,1299 ****
  	}
        else
  	{
! 	  REAL_VALUE_TYPE f0, f1, value;

  	  REAL_VALUE_FROM_CONST_DOUBLE (f0, trueop0);
  	  REAL_VALUE_FROM_CONST_DOUBLE (f1, trueop1);
! 	  f0 = real_value_truncate (mode, f0);
! 	  f1 = real_value_truncate (mode, f1);

  	  if (HONOR_SNANS (mode)
  	      && (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1)))
--- 1288,1300 ----
  	}
        else
  	{
! 	  REAL_VALUE_TYPE f0, f1, value, result;
! 	  bool inexact;

  	  REAL_VALUE_FROM_CONST_DOUBLE (f0, trueop0);
  	  REAL_VALUE_FROM_CONST_DOUBLE (f1, trueop1);
! 	  real_convert (&f0, mode, &f0);
! 	  real_convert (&f1, mode, &f1);

  	  if (HONOR_SNANS (mode)
  	      && (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1)))
*************** simplify_binary_operation (enum rtx_code
*** 1339,1348 ****
  	    /* Inf * 0 = NaN plus exception.  */
  	    return 0;

! 	  REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1);

! 	  value = real_value_truncate (mode, value);
! 	  return CONST_DOUBLE_FROM_REAL_VALUE (value, mode);
  	}
      }

--- 1340,1357 ----
  	    /* Inf * 0 = NaN plus exception.  */
  	    return 0;

! 	  inexact = real_arithmetic (&value, rtx_to_tree_code (code),
! 				     &f0, &f1);
! 	  real_convert (&result, mode, &value);
!
! 	  /* Don't constant fold this floating point operation if the
! 	     result may dependent upon the run-time rounding mode and
! 	     flag_rounding_math is set.  */
! 	  if (flag_rounding_math
! 	      && (inexact || !real_identical (&result, &value)))
! 	    return NULL_RTX;

! 	  return CONST_DOUBLE_FROM_REAL_VALUE (result, mode);
  	}
      }


Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833


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