aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-chrec.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-chrec.c')
-rw-r--r--gcc/tree-chrec.c209
1 files changed, 151 insertions, 58 deletions
diff --git a/gcc/tree-chrec.c b/gcc/tree-chrec.c
index 54960449217..25041f03f13 100644
--- a/gcc/tree-chrec.c
+++ b/gcc/tree-chrec.c
@@ -1,5 +1,5 @@
/* Chains of recurrences.
- Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Sebastian Pop <s.pop@laposte.net>
This file is part of GCC.
@@ -35,7 +35,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "varray.h"
#include "tree-chrec.h"
#include "tree-pass.h"
-
+/* APPLE LOCAL mainline 4080945/ PR 20742 */
+#include "params.h"
/* Extended folder for chrecs. */
@@ -286,11 +287,19 @@ chrec_fold_plus_1 (enum tree_code code,
build_int_cst_type (type, -1)));
default:
- if (tree_contains_chrecs (op0)
- || tree_contains_chrecs (op1))
- return build (code, type, op0, op1);
- else
- return fold (build (code, type, op0, op1));
+/* APPLE LOCAL begin mainline 4080945/ PR 20742 */
+ {
+ int size = 0;
+ if ((tree_contains_chrecs (op0, &size)
+ || tree_contains_chrecs (op1, &size))
+ && size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE))
+ return build2 (code, type, op0, op1);
+ else if (size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE))
+ return fold (build2 (code, type, op0, op1));
+ else
+ return chrec_dont_know;
+ }
+/* APPLE LOCAL end mainline 4080945/ PR 20742 */
}
}
}
@@ -383,63 +392,111 @@ chrec_fold_multiply (tree type,
/* Operations. */
-/* The factorial. */
-
+/* Evaluate the binomial coefficient. Return NULL_TREE if the intermediate
+ calculation overflows, otherwise return C(n,k) with type TYPE. */
+
static tree
-tree_fold_factorial (tree f)
+tree_fold_binomial (tree type, tree n, unsigned int k)
{
- if (tree_int_cst_sgn (f) <= 0)
- return integer_one_node;
+ unsigned HOST_WIDE_INT lidx, lnum, ldenom, lres, ldum;
+ HOST_WIDE_INT hidx, hnum, hdenom, hres, hdum;
+ unsigned int i;
+ tree res;
+
+ /* Handle the most frequent cases. */
+ if (k == 0)
+ return build_int_cst (type, 1);
+ if (k == 1)
+ return fold_convert (type, n);
+
+ /* Check that k <= n. */
+ if (TREE_INT_CST_HIGH (n) == 0
+ && TREE_INT_CST_LOW (n) < k)
+ return NULL_TREE;
+
+ /* Numerator = n. */
+ lnum = TREE_INT_CST_LOW (n);
+ hnum = TREE_INT_CST_HIGH (n);
+
+ /* Denominator = 2. */
+ ldenom = 2;
+ hdenom = 0;
+
+ /* Index = Numerator-1. */
+ if (lnum == 0)
+ {
+ hidx = hnum - 1;
+ lidx = ~ (unsigned HOST_WIDE_INT) 0;
+ }
else
- return fold
- (build (MULT_EXPR, integer_type_node, f,
- tree_fold_factorial (fold (build (MINUS_EXPR, integer_type_node,
- f, integer_one_node)))));
-}
+ {
+ hidx = hnum;
+ lidx = lnum - 1;
+ }
-/* The binomial coefficient. */
+ /* Numerator = Numerator*Index = n*(n-1). */
+ if (mul_double (lnum, hnum, lidx, hidx, &lnum, &hnum))
+ return NULL_TREE;
-static tree
-tree_fold_binomial (tree n,
- tree k)
-{
- return fold
- (build (EXACT_DIV_EXPR, integer_type_node, tree_fold_factorial (n),
- fold (build (MULT_EXPR, integer_type_node,
- tree_fold_factorial (k),
- tree_fold_factorial
- (fold (build (MINUS_EXPR, integer_type_node,
- n, k)))))));
+ for (i = 3; i <= k; i++)
+ {
+ /* Index--. */
+ if (lidx == 0)
+ {
+ hidx--;
+ lidx = ~ (unsigned HOST_WIDE_INT) 0;
+ }
+ else
+ lidx--;
+
+ /* Numerator *= Index. */
+ if (mul_double (lnum, hnum, lidx, hidx, &lnum, &hnum))
+ return NULL_TREE;
+
+ /* Denominator *= i. */
+ mul_double (ldenom, hdenom, i, 0, &ldenom, &hdenom);
+ }
+
+ /* Result = Numerator / Denominator. */
+ div_and_round_double (EXACT_DIV_EXPR, 1, lnum, hnum, ldenom, hdenom,
+ &lres, &hres, &ldum, &hdum);
+
+ res = build_int_cst_wide (type, lres, hres);
+ return int_fits_type_p (res, type) ? res : NULL_TREE;
}
/* Helper function. Use the Newton's interpolating formula for
evaluating the value of the evolution function. */
static tree
-chrec_evaluate (unsigned var,
- tree chrec,
- tree n,
- tree k)
+chrec_evaluate (unsigned var, tree chrec, tree n, unsigned int k)
{
- tree type = chrec_type (chrec);
- tree binomial_n_k = tree_fold_binomial (n, k);
-
- if (TREE_CODE (chrec) == POLYNOMIAL_CHREC)
+ tree arg0, arg1, binomial_n_k;
+ tree type = TREE_TYPE (chrec);
+
+ while (TREE_CODE (chrec) == POLYNOMIAL_CHREC
+ && CHREC_VARIABLE (chrec) > var)
+ chrec = CHREC_LEFT (chrec);
+
+ if (TREE_CODE (chrec) == POLYNOMIAL_CHREC
+ && CHREC_VARIABLE (chrec) == var)
{
- if (CHREC_VARIABLE (chrec) > var)
- return chrec_evaluate (var, CHREC_LEFT (chrec), n, k);
-
- if (CHREC_VARIABLE (chrec) == var)
- return chrec_fold_plus
- (type,
- fold (build (MULT_EXPR, type, binomial_n_k, CHREC_LEFT (chrec))),
- chrec_evaluate (var, CHREC_RIGHT (chrec), n,
- fold (build (PLUS_EXPR, type, k, integer_one_node))));
-
- return fold (build (MULT_EXPR, type, binomial_n_k, chrec));
+ arg0 = chrec_evaluate (var, CHREC_RIGHT (chrec), n, k + 1);
+ if (arg0 == chrec_dont_know)
+ return chrec_dont_know;
+ binomial_n_k = tree_fold_binomial (type, n, k);
+ if (!binomial_n_k)
+ return chrec_dont_know;
+ arg1 = fold (build2 (MULT_EXPR, type,
+ CHREC_LEFT (chrec), binomial_n_k));
+ return chrec_fold_plus (type, arg0, arg1);
}
- else
- return fold (build (MULT_EXPR, type, binomial_n_k, chrec));
+
+ binomial_n_k = tree_fold_binomial (type, n, k);
+ if (!binomial_n_k)
+ return chrec_dont_know;
+
+ return fold (build2 (MULT_EXPR, type, chrec, binomial_n_k));
}
/* Evaluates "CHREC (X)" when the varying variable is VAR.
@@ -493,7 +550,7 @@ chrec_apply (unsigned var,
else if (TREE_CODE (x) == INTEGER_CST
&& tree_int_cst_sgn (x) == 1)
/* testsuite/.../ssa-chrec-38.c. */
- res = chrec_evaluate (var, chrec, x, integer_zero_node);
+ res = chrec_evaluate (var, chrec, x, 0);
else
res = chrec_dont_know;
@@ -669,7 +726,8 @@ reset_evolution_in_loop (unsigned loop_num,
{
if (TREE_CODE (chrec) == POLYNOMIAL_CHREC
&& CHREC_VARIABLE (chrec) > loop_num)
- return build
+/* APPLE LOCAL mainline 4080945/ PR 20742 */
+ return build2
(TREE_CODE (chrec),
build_int_cst (NULL_TREE, CHREC_VARIABLE (chrec)),
reset_evolution_in_loop (loop_num, CHREC_LEFT (chrec), new_evol),
@@ -814,29 +872,36 @@ chrec_contains_undetermined (tree chrec)
}
}
-/* Determines whether the tree EXPR contains chrecs. */
+/* APPLE LOCAL begin mainline 4080945/ PR 20742 */
+/* Determines whether the tree EXPR contains chrecs, and increment
+ SIZE if it is not a NULL pointer by an estimation of the depth of
+ the tree. */
bool
-tree_contains_chrecs (tree expr)
+tree_contains_chrecs (tree expr, int *size)
{
if (expr == NULL_TREE)
return false;
+ if (size)
+ (*size)++;
+
if (tree_is_chrec (expr))
return true;
switch (TREE_CODE_LENGTH (TREE_CODE (expr)))
{
case 3:
- if (tree_contains_chrecs (TREE_OPERAND (expr, 2)))
+ if (tree_contains_chrecs (TREE_OPERAND (expr, 2), size))
return true;
case 2:
- if (tree_contains_chrecs (TREE_OPERAND (expr, 1)))
+ if (tree_contains_chrecs (TREE_OPERAND (expr, 1), size))
return true;
case 1:
- if (tree_contains_chrecs (TREE_OPERAND (expr, 0)))
+ if (tree_contains_chrecs (TREE_OPERAND (expr, 0), size))
+/* APPLE LOCAL end mainline 4080945/ PR 20742 */
return true;
default:
@@ -954,7 +1019,23 @@ nb_vars_in_chrec (tree chrec)
-/* Convert the initial condition of chrec to type. */
+/* Convert CHREC to TYPE. The following is rule is always true:
+ TREE_TYPE (chrec) == TREE_TYPE (CHREC_LEFT (chrec)) == TREE_TYPE
+ (CHREC_RIGHT (chrec)). An example of what could happen when adding
+ two chrecs and the type of the CHREC_RIGHT is different than
+ CHREC_LEFT is:
+
+ {(uint) 0, +, (uchar) 10} +
+ {(uint) 0, +, (uchar) 250}
+
+ that would produce a wrong result if CHREC_RIGHT is not (uint):
+
+ {(uint) 0, +, (uchar) 4}
+
+ instead of
+
+ {(uint) 0, +, (uint) 260}
+*/
tree
chrec_convert (tree type,
@@ -989,6 +1070,18 @@ chrec_convert (tree type,
TREE_OVERFLOW (res) = 0;
if (CONSTANT_CLASS_P (res))
TREE_CONSTANT_OVERFLOW (res) = 0;
+
+ /* But reject constants that don't fit in their type after conversion.
+ This can happen if TYPE_MIN_VALUE or TYPE_MAX_VALUE are not the
+ natural values associated with TYPE_PRECISION and TYPE_UNSIGNED,
+ and can cause problems later when computing niters of loops. Note
+ that we don't do the check before converting because we don't want
+ to reject conversions of negative chrecs to unsigned types. */
+ if (TREE_CODE (res) == INTEGER_CST
+ && TREE_CODE (type) == INTEGER_TYPE
+ && !int_fits_type_p (res, type))
+ res = chrec_dont_know;
+
return res;
}
}