aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorZdenek Dvorak <dvorakz@suse.cz>2006-06-15 09:42:03 +0000
committerZdenek Dvorak <dvorakz@suse.cz>2006-06-15 09:42:03 +0000
commit9f00c65a8610042aaee371eae3619faaebd877ae (patch)
tree85c42d4a341bc337e0b43abae07320d96c49e60f /gcc
parent2a8da666a6958bb7a68339c7d25c7936842a2c73 (diff)
* 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. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@114674 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/double-int.c12
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/loop-18.c24
-rw-r--r--gcc/tree-ssa-loop-niter.c141
5 files changed, 172 insertions, 18 deletions
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 <dvorakz@suse.cz>
+
+ * 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 <bonzini@gnu.org>
* 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 <dvorakz@suse.cz>
+
+ * gcc.dg/tree-ssa/loop-18.c: New test.
+
2006-06-14 Mark Mitchell <mark@codesourcery.com>
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
+/* Returns true if we can prove that COND ==> VAL >= 0. */
+
+static bool
+implies_nonnegative_p (tree cond, tree val)
+{
+ tree type = TREE_TYPE (val);
+ tree compare;
+
+ 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).
+ VAL is at most (unsigned) MAX_INT). */
- TODO -- actually do something nontrivial here. */
-
-static tree
-derive_constant_upper_bound (tree val, tree additional ATTRIBUTE_UNUSED)
+static double_int
+derive_constant_upper_bound (tree val, tree additional)
{
tree type = TREE_TYPE (val);
- tree unsigned_type = unsigned_type_for (type);
+ 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;
+ }
- if (TREE_CODE (val) != INTEGER_CST)
- val = upper_bound_in_type (type, type);
- return fold_convert (unsigned_type, val);
+ /* 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))
{