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] PR middle-end/23470: pow(x,2.0) is non-negative


The following patch resolves PR middle-end/23470 by teaching
fold-const.c's tree_expr_nonnegative_p that pow(x,y) and powi(x,y)
are nonnegative if either x is non-negative or y is an even number.
Reading though my documentation this appears correct for C99 even
in the presence of infinities and signed zeros.

The issue in the PR is with -ffast-math, the middle-end internally
handles x*x as __builtin_pow(x,2.0) when x has a floating point type,
and although fold-const.c can determine that x*x is non-negative for
floating point values, it wasn't as clever about __builtin_pow.  With
this change, we can now even optimize "if (x*x*x*x*x*x < 0.0)" when
using -ffast-math.

Whilst I was there I also took the opportunity to change the return
type of tree_expr_nonnegative_p from an "int" to "bool", as part of
the ongoing transition.


The following patch was tested on x86_64-unknown-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 as revision 118355.



2006-10-31  Roger Sayle  <roger@eyesopen.com>

	PR middle-end/23470
	* tree.h (tree_expr_nonnegative_p): Return "bool" instead of "int".
	* fold-const.c (tree_expr_nonnegative_p): Likewise.  Consider
	pow(x,y) and powi(x,y) to be nonnegative if either x is nonnegative
	or y is an even integer.

	* gcc.dg/pr23470-1.c: New test case.


Index: tree.h
===================================================================
*** tree.h	(revision 118188)
--- tree.h	(working copy)
*************** extern HOST_WIDE_INT tree_low_cst (tree,
*** 3606,3612 ****
  extern int tree_int_cst_msb (tree);
  extern int tree_int_cst_sgn (tree);
  extern int tree_int_cst_sign_bit (tree);
! extern int tree_expr_nonnegative_p (tree);
  extern bool may_negate_without_overflow_p (tree);
  extern tree get_inner_array_type (tree);

--- 3606,3612 ----
  extern int tree_int_cst_msb (tree);
  extern int tree_int_cst_sgn (tree);
  extern int tree_int_cst_sign_bit (tree);
! extern bool tree_expr_nonnegative_p (tree);
  extern bool may_negate_without_overflow_p (tree);
  extern tree get_inner_array_type (tree);

Index: fold-const.c
===================================================================
*** fold-const.c	(revision 118188)
--- fold-const.c	(working copy)
*************** multiple_of_p (tree type, tree top, tree
*** 12109,12122 ****

  /* Return true if `t' is known to be non-negative.  */

! int
  tree_expr_nonnegative_p (tree t)
  {
    if (t == error_mark_node)
!     return 0;

    if (TYPE_UNSIGNED (TREE_TYPE (t)))
!     return 1;

    switch (TREE_CODE (t))
      {
--- 12109,12122 ----

  /* Return true if `t' is known to be non-negative.  */

! bool
  tree_expr_nonnegative_p (tree t)
  {
    if (t == error_mark_node)
!     return false;

    if (TYPE_UNSIGNED (TREE_TYPE (t)))
!     return true;

    switch (TREE_CODE (t))
      {
*************** tree_expr_nonnegative_p (tree t)
*** 12129,12135 ****
        /* We can't return 1 if flag_wrapv is set because
  	 ABS_EXPR<INT_MIN> = INT_MIN.  */
        if (!(flag_wrapv && INTEGRAL_TYPE_P (TREE_TYPE (t))))
!         return 1;
        break;

      case INTEGER_CST:
--- 12129,12135 ----
        /* We can't return 1 if flag_wrapv is set because
  	 ABS_EXPR<INT_MIN> = INT_MIN.  */
        if (!(flag_wrapv && INTEGRAL_TYPE_P (TREE_TYPE (t))))
!         return true;
        break;

      case INTEGER_CST:
*************** tree_expr_nonnegative_p (tree t)
*** 12166,12172 ****
  	{
  	  /* x * x for floating point x is always non-negative.  */
  	  if (operand_equal_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1), 0))
! 	    return 1;
  	  return tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
  		 && tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
  	}
--- 12166,12172 ----
  	{
  	  /* x * x for floating point x is always non-negative.  */
  	  if (operand_equal_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1), 0))
! 	    return true;
  	  return tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
  		 && tree_expr_nonnegative_p (TREE_OPERAND (t, 1));
  	}
*************** tree_expr_nonnegative_p (tree t)
*** 12184,12190 ****
  	    return TYPE_PRECISION (inner1) + TYPE_PRECISION (inner2)
  		   < TYPE_PRECISION (TREE_TYPE (t));
  	}
!       return 0;

      case BIT_AND_EXPR:
      case MAX_EXPR:
--- 12184,12190 ----
  	    return TYPE_PRECISION (inner1) + TYPE_PRECISION (inner2)
  		   < TYPE_PRECISION (TREE_TYPE (t));
  	}
!       return false;

      case BIT_AND_EXPR:
      case MAX_EXPR:
*************** tree_expr_nonnegative_p (tree t)
*** 12234,12240 ****
  	    if (TREE_CODE (inner_type) == INTEGER_TYPE)
  	      {
  		if (TYPE_UNSIGNED (inner_type))
! 		  return 1;
  		return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
  	      }
  	  }
--- 12234,12240 ----
  	    if (TREE_CODE (inner_type) == INTEGER_TYPE)
  	      {
  		if (TYPE_UNSIGNED (inner_type))
! 		  return true;
  		return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
  	      }
  	  }
*************** tree_expr_nonnegative_p (tree t)
*** 12277,12283 ****
  	    && TREE_OPERAND (t, 0) == temp)
  	  return tree_expr_nonnegative_p (TREE_OPERAND (t, 1));

! 	return 0;
        }

      case CALL_EXPR:
--- 12277,12283 ----
  	    && TREE_OPERAND (t, 0) == temp)
  	  return tree_expr_nonnegative_p (TREE_OPERAND (t, 1));

! 	return false;
        }

      case CALL_EXPR:
*************** tree_expr_nonnegative_p (tree t)
*** 12303,12314 ****
  	    CASE_INT_FN (BUILT_IN_PARITY):
  	    CASE_INT_FN (BUILT_IN_POPCOUNT):
  	      /* Always true.  */
! 	      return 1;

  	    CASE_FLT_FN (BUILT_IN_SQRT):
  	      /* sqrt(-0.0) is -0.0.  */
  	      if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (t))))
! 		return 1;
  	      return tree_expr_nonnegative_p (TREE_VALUE (arglist));

  	    CASE_FLT_FN (BUILT_IN_ASINH):
--- 12303,12314 ----
  	    CASE_INT_FN (BUILT_IN_PARITY):
  	    CASE_INT_FN (BUILT_IN_POPCOUNT):
  	      /* Always true.  */
! 	      return true;

  	    CASE_FLT_FN (BUILT_IN_SQRT):
  	      /* sqrt(-0.0) is -0.0.  */
  	      if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (t))))
! 		return true;
  	      return tree_expr_nonnegative_p (TREE_VALUE (arglist));

  	    CASE_FLT_FN (BUILT_IN_ASINH):
*************** tree_expr_nonnegative_p (tree t)
*** 12332,12338 ****
  	    CASE_FLT_FN (BUILT_IN_LROUND):
  	    CASE_FLT_FN (BUILT_IN_MODF):
  	    CASE_FLT_FN (BUILT_IN_NEARBYINT):
- 	    CASE_FLT_FN (BUILT_IN_POW):
  	    CASE_FLT_FN (BUILT_IN_RINT):
  	    CASE_FLT_FN (BUILT_IN_ROUND):
  	    CASE_FLT_FN (BUILT_IN_SIGNBIT):
--- 12332,12337 ----
*************** tree_expr_nonnegative_p (tree t)
*** 12356,12361 ****
--- 12355,12392 ----
  	      /* True if the 2nd argument is nonnegative.  */
  	      return tree_expr_nonnegative_p (TREE_VALUE (TREE_CHAIN (arglist)));

+ 	    CASE_FLT_FN (BUILT_IN_POWI):
+ 	      /* True if the 1st argument is nonnegative or the second
+ 		 argument is an even integer.  */
+ 	      if (TREE_CODE (TREE_VALUE (TREE_CHAIN (arglist))) == INTEGER_CST)
+ 		{
+ 		  tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
+ 		  if ((TREE_INT_CST_LOW (arg1) & 1) == 0)
+ 		    return true;
+ 		}
+ 	      return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+
+ 	    CASE_FLT_FN (BUILT_IN_POW):
+ 	      /* True if the 1st argument is nonnegative or the second
+ 		 argument is an even integer valued real.  */
+ 	      if (TREE_CODE (TREE_VALUE (TREE_CHAIN (arglist))) == REAL_CST)
+ 		{
+ 		  REAL_VALUE_TYPE c;
+ 		  HOST_WIDE_INT n;
+
+ 		  c = TREE_REAL_CST (TREE_VALUE (TREE_CHAIN (arglist)));
+ 		  n = real_to_integer (&c);
+ 		  if ((n & 1) == 0)
+ 		    {
+ 		      REAL_VALUE_TYPE cint;
+ 		      real_from_integer (&cint, VOIDmode, n,
+ 					 n < 0 ? -1 : 0, 0);
+ 		      if (real_identical (&c, &cint))
+ 			return true;
+ 		    }
+ 		}
+ 	      return tree_expr_nonnegative_p (TREE_VALUE (arglist));
+
  	    default:
  	      break;
  	    }
*************** tree_expr_nonnegative_p (tree t)
*** 12366,12376 ****
      default:
        if (truth_value_p (TREE_CODE (t)))
  	/* Truth values evaluate to 0 or 1, which is nonnegative.  */
! 	return 1;
      }

    /* We don't know sign of `t', so be conservative and return false.  */
!   return 0;
  }

  /* Return true when T is an address and is known to be nonzero.
--- 12397,12407 ----
      default:
        if (truth_value_p (TREE_CODE (t)))
  	/* Truth values evaluate to 0 or 1, which is nonnegative.  */
! 	return true;
      }

    /* We don't know sign of `t', so be conservative and return false.  */
!   return false;
  }

  /* Return true when T is an address and is known to be nonzero.



/* PR middle-end/23470 */
/* { dg-do compile } */
/* { dg-options "-O2 -ffast-math -fdump-tree-original" } */

int f(double a, double b)
{
  if (((a*a) + (b*b))<0)
    link_error();
}

/* { dg-final { scan-tree-dump-times "if \\(0\\)" 1 "original" } } */
/* { dg-final { cleanup-tree-dump "original" } } */


Roger
--


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