This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[Committed] PR middle-end/23470: pow(x,2.0) is non-negative
- From: Roger Sayle <roger at eyesopen dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 31 Oct 2006 19:18:11 -0700 (MST)
- Subject: [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
--