From 0ad1d5a1d2d7275611ff841ced4642ade1d2a98f Mon Sep 17 00:00:00 2001 From: Zdenek Dvorak Date: Thu, 15 Jun 2006 11:42:03 +0200 Subject: [PATCH] tree-ssa-loop-niter.c (implies_nonnegative_p): New function. * tree-ssa-loop-niter.c (implies_nonnegative_p): New function. (derive_constant_upper_bound): Derive more precise upper bound in common cases. Return type changed to double_int. (record_estimate): Reflect the changed return type of derive_constant_upper_bound. * double-int.c (double_int_zext, double_int_sext): Fix. * gcc.dg/tree-ssa/loop-18.c: New test. From-SVN: r114674 --- gcc/ChangeLog | 9 ++ gcc/double-int.c | 12 +- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/gcc.dg/tree-ssa/loop-18.c | 24 ++++ gcc/tree-ssa-loop-niter.c | 143 +++++++++++++++++++++--- 5 files changed, 173 insertions(+), 19 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/loop-18.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c210afe962d..d4040849dfe 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2006-06-15 Zdenek Dvorak + + * tree-ssa-loop-niter.c (implies_nonnegative_p): New function. + (derive_constant_upper_bound): Derive more precise upper bound in + common cases. Return type changed to double_int. + (record_estimate): Reflect the changed return type of + derive_constant_upper_bound. + * double-int.c (double_int_zext, double_int_sext): Fix. + 2006-06-15 Paolo Bonzini * configure.ac (CFLAGS): Get them from the toplevel or from the diff --git a/gcc/double-int.c b/gcc/double-int.c index ab1975f09a9..5a7b51dbe31 100644 --- a/gcc/double-int.c +++ b/gcc/double-int.c @@ -72,8 +72,8 @@ double_int_zext (double_int cst, unsigned prec) double_int mask = double_int_mask (prec); double_int r; - r.low = cst.low & ~mask.low; - r.high = cst.high & ~mask.high; + r.low = cst.low & mask.low; + r.high = cst.high & mask.high; return r; } @@ -96,13 +96,13 @@ double_int_sext (double_int cst, unsigned prec) } if (((snum >> (prec - 1)) & 1) == 1) { - r.low = cst.low | mask.low; - r.high = cst.high | mask.high; + r.low = cst.low | ~mask.low; + r.high = cst.high | ~mask.high; } else { - r.low = cst.low & ~mask.low; - r.high = cst.high & ~mask.high; + r.low = cst.low & mask.low; + r.high = cst.high & mask.high; } return r; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0a934c9feb2..7f16d28684d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2006-06-15 Zdenek Dvorak + + * gcc.dg/tree-ssa/loop-18.c: New test. + 2006-06-14 Mark Mitchell PR c++/27665 diff --git a/gcc/testsuite/gcc.dg/tree-ssa/loop-18.c b/gcc/testsuite/gcc.dg/tree-ssa/loop-18.c new file mode 100644 index 00000000000..ca75db941e5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/loop-18.c @@ -0,0 +1,24 @@ +/* A test for # of iterations estimation. We know that I does not overflow, + thus we can perform strength reduction (even though the 32-bit variable + i is first extended to 64-bit type). */ + +/* { dg-options "-O2 -fdump-tree-optimized" } */ +/* { dg-do compile { target x86_64-*-* } } */ + +unsigned bar(void); + +void foo(unsigned *p, unsigned n) +{ + unsigned i; + + for (i = 0; i < n; i++) + p[i] = bar (); +} + +/* Check that the memory reference was replaced with MEM, and that there is no + multiplication. */ + +/* { dg-final { scan-tree-dump-times "MEM" 1 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\[^\\n\\r\]*= \\* " 0 "optimized" } } */ + +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c index 6b278973543..e16065602be 100644 --- a/gcc/tree-ssa-loop-niter.c +++ b/gcc/tree-ssa-loop-niter.c @@ -1470,22 +1470,137 @@ find_loop_niter_by_eval (struct loop *loop, edge *exit) */ -/* Returns a constant upper bound on the value of expression VAL. The - condition ADDITIONAL must be satisfied (for example, if VAL is - "(unsigned) n" and ADDITIONAL is "n > 0", then we can derive that - VAL is at most (unsigned) MAX_INT). - - TODO -- actually do something nontrivial here. */ +/* Returns true if we can prove that COND ==> VAL >= 0. */ -static tree -derive_constant_upper_bound (tree val, tree additional ATTRIBUTE_UNUSED) +static bool +implies_nonnegative_p (tree cond, tree val) { tree type = TREE_TYPE (val); - tree unsigned_type = unsigned_type_for (type); + tree compare; - if (TREE_CODE (val) != INTEGER_CST) - val = upper_bound_in_type (type, type); - return fold_convert (unsigned_type, val); + if (tree_expr_nonnegative_p (val)) + return true; + + if (nonzero_p (cond)) + return false; + + compare = fold_build2 (GE_EXPR, + boolean_type_node, val, build_int_cst (type, 0)); + compare = tree_simplify_using_condition_1 (cond, compare); + + return nonzero_p (compare); +} + +/* Returns a constant upper bound on the value of expression VAL. VAL + is considered to be unsigned. If its type is signed, its value must + be nonnegative. + + The condition ADDITIONAL must be satisfied (for example, if VAL is + "(unsigned) n" and ADDITIONAL is "n > 0", then we can derive that + VAL is at most (unsigned) MAX_INT). */ + +static double_int +derive_constant_upper_bound (tree val, tree additional) +{ + tree type = TREE_TYPE (val); + tree op0, op1, subtype, maxt; + double_int bnd, max, mmax, cst; + + if (INTEGRAL_TYPE_P (type)) + maxt = TYPE_MAX_VALUE (type); + else + maxt = upper_bound_in_type (type, type); + + max = tree_to_double_int (maxt); + + switch (TREE_CODE (val)) + { + case INTEGER_CST: + return tree_to_double_int (val); + + case NOP_EXPR: + case CONVERT_EXPR: + op0 = TREE_OPERAND (val, 0); + subtype = TREE_TYPE (op0); + if (!TYPE_UNSIGNED (subtype) + /* If TYPE is also signed, the fact that VAL is nonnegative implies + that OP0 is nonnegative. */ + && TYPE_UNSIGNED (type) + && !implies_nonnegative_p (additional, op0)) + { + /* If we cannot prove that the casted expression is nonnegative, + we cannot establish more useful upper bound than the precision + of the type gives us. */ + return max; + } + + /* We now know that op0 is an nonnegative value. Try deriving an upper + bound for it. */ + bnd = derive_constant_upper_bound (op0, additional); + + /* If the bound does not fit in TYPE, max. value of TYPE could be + attained. */ + if (double_int_ucmp (max, bnd) < 0) + return max; + + return bnd; + + case PLUS_EXPR: + case MINUS_EXPR: + op0 = TREE_OPERAND (val, 0); + op1 = TREE_OPERAND (val, 1); + + if (TREE_CODE (op1) != INTEGER_CST + || !implies_nonnegative_p (additional, op0)) + return max; + + /* Canonicalize to OP0 - CST. */ + cst = tree_to_double_int (op1); + if (TREE_CODE (val) == PLUS_EXPR) + cst = double_int_neg (cst); + + bnd = derive_constant_upper_bound (op0, additional); + + if (double_int_negative_p (cst)) + { + cst = double_int_neg (cst); + /* Avoid CST == 0x80000... */ + if (double_int_negative_p (cst)) + return max;; + + /* Case OP0 + CST. We need to check that + BND <= MAX (type) - CST. */ + + mmax = double_int_add (max, double_int_neg (cst)); + if (double_int_ucmp (bnd, mmax) > 0) + return max; + + return double_int_add (bnd, cst); + } + else + { + if (double_int_ucmp (bnd, cst) < 0) + return max; + + bnd = double_int_add (bnd, double_int_neg (cst)); + } + + return bnd; + + case FLOOR_DIV_EXPR: + case EXACT_DIV_EXPR: + op0 = TREE_OPERAND (val, 0); + op1 = TREE_OPERAND (val, 1); + if (TREE_CODE (op1) != INTEGER_CST + || tree_int_cst_sign_bit (op1)) + return max; + + bnd = derive_constant_upper_bound (op0, additional); + return double_int_udiv (bnd, tree_to_double_int (op1), FLOOR_DIV_EXPR); + + default: + return max; + } } /* Records that AT_STMT is executed at most BOUND times in LOOP. The @@ -1495,7 +1610,9 @@ void record_estimate (struct loop *loop, tree bound, tree additional, tree at_stmt) { struct nb_iter_bound *elt = xmalloc (sizeof (struct nb_iter_bound)); - tree c_bound = derive_constant_upper_bound (bound, additional); + double_int i_bound = derive_constant_upper_bound (bound, additional); + tree c_bound = double_int_to_tree (unsigned_type_for (TREE_TYPE (bound)), + i_bound); if (dump_file && (dump_flags & TDF_DETAILS)) {