summaryrefslogtreecommitdiff
path: root/gcc/gimple-fold.c
diff options
context:
space:
mode:
authorwschmidt <wschmidt@138bc75d-0d04-0410-961f-82ee72b054a4>2011-06-07 15:12:04 +0000
committerwschmidt <wschmidt@138bc75d-0d04-0410-961f-82ee72b054a4>2011-06-07 15:12:04 +0000
commit0b7ad90050c73f17b9cd6048f1565e970979279f (patch)
tree44dc6b8481b3a6a81e091f03fc34efc38e60abff /gcc/gimple-fold.c
parent9fd75d525b510af57a2ca7a536a18930506e2cd1 (diff)
downloadgcc-0b7ad90050c73f17b9cd6048f1565e970979279f.tar.gz
2011-06-07 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
PR tree-optimization/46728 * tree-ssa-math-opts.c (gimple_expand_builtin_pow): Change FIXME to use gimple_val_nonnegative_real_p. * gimple-fold.c (gimple_val_nonnegative_real_p): New function. * gimple.h (gimple_val_nonnegative_real_p): New declaration. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@174752 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r--gcc/gimple-fold.c131
1 files changed, 131 insertions, 0 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index eaff1b3a4ee..180a51e095a 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -3447,3 +3447,134 @@ fold_const_aggregate_ref (tree t)
{
return fold_const_aggregate_ref_1 (t, NULL);
}
+
+/* Return true iff VAL is a gimple expression that is known to be
+ non-negative. Restricted to floating-point inputs. */
+
+bool
+gimple_val_nonnegative_real_p (tree val)
+{
+ gimple def_stmt;
+
+ gcc_assert (val && SCALAR_FLOAT_TYPE_P (TREE_TYPE (val)));
+
+ /* Use existing logic for non-gimple trees. */
+ if (tree_expr_nonnegative_p (val))
+ return true;
+
+ if (TREE_CODE (val) != SSA_NAME)
+ return false;
+
+ /* Currently we look only at the immediately defining statement
+ to make this determination, since recursion on defining
+ statements of operands can lead to quadratic behavior in the
+ worst case. This is expected to catch almost all occurrences
+ in practice. It would be possible to implement limited-depth
+ recursion if important cases are lost. Alternatively, passes
+ that need this information (such as the pow/powi lowering code
+ in the cse_sincos pass) could be revised to provide it through
+ dataflow propagation. */
+
+ def_stmt = SSA_NAME_DEF_STMT (val);
+
+ if (is_gimple_assign (def_stmt))
+ {
+ tree op0, op1;
+
+ /* See fold-const.c:tree_expr_nonnegative_p for additional
+ cases that could be handled with recursion. */
+
+ switch (gimple_assign_rhs_code (def_stmt))
+ {
+ case ABS_EXPR:
+ /* Always true for floating-point operands. */
+ return true;
+
+ case MULT_EXPR:
+ /* True if the two operands are identical (since we are
+ restricted to floating-point inputs). */
+ op0 = gimple_assign_rhs1 (def_stmt);
+ op1 = gimple_assign_rhs2 (def_stmt);
+
+ if (op0 == op1
+ || operand_equal_p (op0, op1, 0))
+ return true;
+
+ default:
+ return false;
+ }
+ }
+ else if (is_gimple_call (def_stmt))
+ {
+ tree fndecl = gimple_call_fndecl (def_stmt);
+ if (fndecl
+ && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
+ {
+ tree arg1;
+
+ switch (DECL_FUNCTION_CODE (fndecl))
+ {
+ CASE_FLT_FN (BUILT_IN_ACOS):
+ CASE_FLT_FN (BUILT_IN_ACOSH):
+ CASE_FLT_FN (BUILT_IN_CABS):
+ CASE_FLT_FN (BUILT_IN_COSH):
+ CASE_FLT_FN (BUILT_IN_ERFC):
+ CASE_FLT_FN (BUILT_IN_EXP):
+ CASE_FLT_FN (BUILT_IN_EXP10):
+ CASE_FLT_FN (BUILT_IN_EXP2):
+ CASE_FLT_FN (BUILT_IN_FABS):
+ CASE_FLT_FN (BUILT_IN_FDIM):
+ CASE_FLT_FN (BUILT_IN_HYPOT):
+ CASE_FLT_FN (BUILT_IN_POW10):
+ return true;
+
+ CASE_FLT_FN (BUILT_IN_SQRT):
+ /* sqrt(-0.0) is -0.0, and sqrt is not defined over other
+ nonnegative inputs. */
+ if (!HONOR_SIGNED_ZEROS (TYPE_MODE (TREE_TYPE (val))))
+ return true;
+
+ break;
+
+ CASE_FLT_FN (BUILT_IN_POWI):
+ /* True if the second argument is an even integer. */
+ arg1 = gimple_call_arg (def_stmt, 1);
+
+ if (TREE_CODE (arg1) == INTEGER_CST
+ && (TREE_INT_CST_LOW (arg1) & 1) == 0)
+ return true;
+
+ break;
+
+ CASE_FLT_FN (BUILT_IN_POW):
+ /* True if the second argument is an even integer-valued
+ real. */
+ arg1 = gimple_call_arg (def_stmt, 1);
+
+ if (TREE_CODE (arg1) == REAL_CST)
+ {
+ REAL_VALUE_TYPE c;
+ HOST_WIDE_INT n;
+
+ c = TREE_REAL_CST (arg1);
+ 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;
+ }
+ }
+
+ break;
+
+ default:
+ return false;
+ }
+ }
+ }
+
+ return false;
+}