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.c2000
1 files changed, 2000 insertions, 0 deletions
diff --git a/gcc/tree-chrec.c b/gcc/tree-chrec.c
new file mode 100644
index 00000000000..d00aabb24f7
--- /dev/null
+++ b/gcc/tree-chrec.c
@@ -0,0 +1,2000 @@
+/* Chains of recurrences.
+ Copyright (C) 2003 Free Software Foundation, Inc.
+ Contributed by Sebastian Pop <s.pop@laposte.net>
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING. If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA. */
+
+/* This file implements operations on chains of recurrences. Chains
+ of recurrences are used for modeling evolution functions of scalar
+ variables.
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "errors.h"
+#include "ggc.h"
+#include "tree.h"
+#include "diagnostic.h"
+#include "varray.h"
+#include "tree-fold-const.h"
+#include "tree-chrec.h"
+#include "tree-pass.h"
+
+
+/* Extended folder for chrecs. */
+
+/* Determines whether CST is not a constant evolution. */
+
+static inline bool
+is_not_constant_evolution (tree cst)
+{
+ return (TREE_CODE (cst) == POLYNOMIAL_CHREC
+ || TREE_CODE (cst) == EXPONENTIAL_CHREC
+ || TREE_CODE (cst) == PEELED_CHREC);
+}
+
+/* Fold CODE for a polynomial function and a constant. */
+
+static inline tree
+chrec_fold_poly_cst (enum tree_code code,
+ tree type,
+ tree poly,
+ tree cst)
+{
+#if defined ENABLE_CHECKING
+ if (poly == NULL_TREE
+ || cst == NULL_TREE
+ || TREE_CODE (poly) != POLYNOMIAL_CHREC
+ || is_not_constant_evolution (cst))
+ abort ();
+#endif
+
+ switch (code)
+ {
+ case PLUS_EXPR:
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (poly),
+ chrec_fold_plus (type, CHREC_LEFT (poly), cst),
+ CHREC_RIGHT (poly));
+
+ case MINUS_EXPR:
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (poly),
+ chrec_fold_minus (type, CHREC_LEFT (poly), cst),
+ CHREC_RIGHT (poly));
+
+ case MULT_EXPR:
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (poly),
+ chrec_fold_multiply (type, CHREC_LEFT (poly), cst),
+ chrec_fold_multiply (type, CHREC_RIGHT (poly), cst));
+
+ default:
+ return chrec_top;
+ }
+}
+
+/* Fold the addition of a peeled chrec and a constant. */
+
+static inline tree
+chrec_fold_plus_peel_cst (tree type,
+ tree peel,
+ tree cst)
+{
+#if defined ENABLE_CHECKING
+ if (peel == NULL_TREE
+ || cst == NULL_TREE
+ || TREE_CODE (peel) != PEELED_CHREC
+ || is_not_constant_evolution (cst))
+ abort ();
+#endif
+
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel),
+ chrec_fold_plus (type, CHREC_LEFT (peel), cst),
+ chrec_fold_plus (type, CHREC_RIGHT (peel), cst));
+}
+
+/* Fold the addition of an exponential function and a constant. */
+
+static inline tree
+chrec_fold_plus_expo_cst (enum tree_code code,
+ tree type,
+ tree expo,
+ tree cst)
+{
+#if defined ENABLE_CHECKING
+ if (expo == NULL_TREE
+ || cst == NULL_TREE
+ || TREE_CODE (expo) != EXPONENTIAL_CHREC
+ || is_not_constant_evolution (cst))
+ abort ();
+#endif
+
+ /* For the moment, we don't know how to fold this further. */
+ return build (code, type, expo, cst);
+}
+
+/* Fold the addition of an exponential function and a constant. */
+
+static inline tree
+chrec_fold_plus_cst_expo (enum tree_code code,
+ tree type,
+ tree cst,
+ tree expo)
+{
+#if defined ENABLE_CHECKING
+ if (expo == NULL_TREE
+ || cst == NULL_TREE
+ || TREE_CODE (expo) != EXPONENTIAL_CHREC
+ || is_not_constant_evolution (cst))
+ abort ();
+#endif
+
+ /* For the moment, we don't know how to fold this further. */
+ return build (code, type, cst, expo);
+}
+
+/* Fold the addition of two polynomial functions. */
+
+static inline tree
+chrec_fold_plus_poly_poly (enum tree_code code,
+ tree type,
+ tree poly0,
+ tree poly1)
+{
+ tree left, right;
+
+#if defined ENABLE_CHECKING
+ if (poly0 == NULL_TREE
+ || poly1 == NULL_TREE
+ || TREE_CODE (poly0) != POLYNOMIAL_CHREC
+ || TREE_CODE (poly1) != POLYNOMIAL_CHREC)
+ abort ();
+#endif
+
+ /*
+ {a, +, b}_1 + {c, +, d}_2 -> {{a, +, b}_1 + c, +, d}_2,
+ {a, +, b}_2 + {c, +, d}_1 -> {{c, +, d}_1 + a, +, b}_2,
+ {a, +, b}_x + {c, +, d}_x -> {a+c, +, b+d}_x. */
+ if (CHREC_VARIABLE (poly0) < CHREC_VARIABLE (poly1))
+ {
+ if (code == PLUS_EXPR)
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (poly1),
+ chrec_fold_plus (type, poly0, CHREC_LEFT (poly1)),
+ CHREC_RIGHT (poly1));
+ else
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (poly1),
+ chrec_fold_minus (type, poly0, CHREC_LEFT (poly1)),
+ chrec_fold_multiply (integer_type_node, CHREC_RIGHT (poly1),
+ integer_minus_one_node));
+ }
+
+ if (CHREC_VARIABLE (poly0) > CHREC_VARIABLE (poly1))
+ {
+ if (code == PLUS_EXPR)
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (poly0),
+ chrec_fold_plus (type, CHREC_LEFT (poly0), poly1),
+ CHREC_RIGHT (poly0));
+ else
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (poly0),
+ chrec_fold_minus (type, CHREC_LEFT (poly0), poly1),
+ CHREC_RIGHT (poly0));
+ }
+
+ if (code == PLUS_EXPR)
+ {
+ left = chrec_fold_plus
+ (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1));
+ right = chrec_fold_plus
+ (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1));
+ }
+ else
+ {
+ left = chrec_fold_minus
+ (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1));
+ right = chrec_fold_minus
+ (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1));
+ }
+
+ if (chrec_zerop (right))
+ return left;
+ else
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (poly0), left, right);
+}
+
+/* Fold the addition of a polynomial and a peeled chrec. */
+
+static inline tree
+chrec_fold_plus_poly_peel (enum tree_code code,
+ tree type,
+ tree poly,
+ tree peel)
+{
+#if defined ENABLE_CHECKING
+ if (peel == NULL_TREE
+ || poly == NULL_TREE
+ || TREE_CODE (peel) != PEELED_CHREC
+ || TREE_CODE (poly) != POLYNOMIAL_CHREC)
+ abort ();
+#endif
+
+ /*
+ {a, +, b}_1 + (c, d)_2 -> ({a, +, b}_1 + c, {a, +, b}_1 + d)_2,
+ {a, +, b}_2 + (c, d)_1 -> {a + (c, d)_1, +, b}_2,
+ {a, +, b}_x + (c, d)_x -> ({a, +, b}_x + c, {a, +, b}_x + d)_x. */
+ if (CHREC_VARIABLE (poly) < CHREC_VARIABLE (peel))
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, poly, CHREC_LEFT (peel)) :
+ chrec_fold_minus (type, poly, CHREC_LEFT (peel))),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, poly, CHREC_RIGHT (peel)) :
+ chrec_fold_minus (type, poly, CHREC_RIGHT (peel))));
+
+ if (CHREC_VARIABLE (poly) > CHREC_VARIABLE (peel))
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (poly),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, CHREC_LEFT (poly), peel) :
+ chrec_fold_minus (type, CHREC_LEFT (poly), peel)),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, CHREC_RIGHT (poly), peel) :
+ chrec_fold_minus (type, CHREC_RIGHT (poly), peel)));
+
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, poly, CHREC_LEFT (peel)) :
+ chrec_fold_minus (type, poly, CHREC_LEFT (peel))),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, poly, CHREC_RIGHT (peel)) :
+ chrec_fold_minus (type, poly, CHREC_RIGHT (peel))));
+}
+
+/* Fold the addition of a polynomial and a peeled chrec. */
+
+static inline tree
+chrec_fold_plus_peel_poly (enum tree_code code,
+ tree type,
+ tree peel,
+ tree poly)
+{
+#if defined ENABLE_CHECKING
+ if (peel == NULL_TREE
+ || poly == NULL_TREE
+ || TREE_CODE (peel) != PEELED_CHREC
+ || TREE_CODE (poly) != POLYNOMIAL_CHREC)
+ abort ();
+#endif
+
+ /*
+ {a, +, b}_1 + (c, d)_2 -> ({a, +, b}_1 + c, {a, +, b}_1 + d)_2,
+ {a, +, b}_2 + (c, d)_1 -> {a + (c, d)_1, +, b}_2,
+ {a, +, b}_x + (c, d)_x -> ({a, +, b}_x + c, {a, +, b}_x + d)_x. */
+ if (CHREC_VARIABLE (poly) < CHREC_VARIABLE (peel))
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, CHREC_LEFT (peel), poly) :
+ chrec_fold_minus (type, CHREC_LEFT (peel), poly)),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, CHREC_RIGHT (peel), poly) :
+ chrec_fold_minus (type, CHREC_RIGHT (peel), poly)));
+
+ if (CHREC_VARIABLE (poly) > CHREC_VARIABLE (peel))
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (poly),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, peel, CHREC_LEFT (poly)) :
+ chrec_fold_minus (type, peel, CHREC_LEFT (poly))),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, peel, CHREC_RIGHT (poly)) :
+ chrec_fold_minus (type, peel, CHREC_RIGHT (poly))));
+
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, CHREC_LEFT (peel), poly) :
+ chrec_fold_minus (type, CHREC_LEFT (peel), poly)),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, CHREC_RIGHT (peel), poly) :
+ chrec_fold_minus (type, CHREC_RIGHT (peel), poly)));
+}
+
+/* Fold the addition of a polynomial and an exponential functions. */
+
+static inline tree
+chrec_fold_plus_poly_expo (enum tree_code code,
+ tree type,
+ tree poly,
+ tree expo)
+{
+#if defined ENABLE_CHECKING
+ if (expo == NULL_TREE
+ || poly == NULL_TREE
+ || TREE_CODE (expo) != EXPONENTIAL_CHREC
+ || TREE_CODE (poly) != POLYNOMIAL_CHREC)
+ abort ();
+#endif
+
+ /* For the moment, we don't know how to fold this further. */
+ return build (code, type, poly, expo);
+}
+
+/* Fold the addition of a polynomial and an exponential functions. */
+
+static inline tree
+chrec_fold_plus_expo_poly (enum tree_code code,
+ tree type,
+ tree expo,
+ tree poly)
+{
+#if defined ENABLE_CHECKING
+ if (expo == NULL_TREE
+ || poly == NULL_TREE
+ || TREE_CODE (expo) != EXPONENTIAL_CHREC
+ || TREE_CODE (poly) != POLYNOMIAL_CHREC)
+ abort ();
+#endif
+
+ /* For the moment, we don't know how to fold this further. */
+ return build (code, type, expo, poly);
+}
+
+/* Fold the addition of two peeled chrecs. */
+
+static inline tree
+chrec_fold_plus_peel_peel (tree type,
+ tree peel0,
+ tree peel1)
+{
+#if defined ENABLE_CHECKING
+ if (peel0 == NULL_TREE
+ || peel1 == NULL_TREE
+ || TREE_CODE (peel0) != PEELED_CHREC
+ || TREE_CODE (peel1) != PEELED_CHREC)
+ abort ();
+#endif
+
+ /*
+ (a, b)_1 + (c, d)_2 -> ((a, b)_1 + c, (a, b)_1 + d)_2,
+ (a, b)_2 + (c, d)_1 -> (a + (c, d)_1, b + (c, d)_1)_2,
+ (a, b)_x + (c, d)_x -> (a + c, b + d)_x. */
+ if (CHREC_VARIABLE (peel0) < CHREC_VARIABLE (peel1))
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel1),
+ chrec_fold_plus (type, peel0, CHREC_LEFT (peel1)),
+ chrec_fold_plus (type, peel0, CHREC_RIGHT (peel1)));
+
+ if (CHREC_VARIABLE (peel0) > CHREC_VARIABLE (peel1))
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel0),
+ chrec_fold_plus (type, CHREC_LEFT (peel0), peel1),
+ chrec_fold_plus (type, CHREC_RIGHT (peel0), peel1));
+
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel0),
+ chrec_fold_plus (type, CHREC_LEFT (peel0), CHREC_LEFT (peel1)),
+ chrec_fold_plus (type, CHREC_RIGHT (peel0), CHREC_RIGHT (peel1)));
+}
+
+/* Fold the addition of two exponential functions. */
+
+static inline tree
+chrec_fold_plus_expo_expo (enum tree_code code,
+ tree type,
+ tree expo0,
+ tree expo1)
+{
+#if defined ENABLE_CHECKING
+ if (expo0 == NULL_TREE
+ || expo1 == NULL_TREE
+ || TREE_CODE (expo0) != EXPONENTIAL_CHREC
+ || TREE_CODE (expo1) != EXPONENTIAL_CHREC)
+ abort ();
+#endif
+
+ /* For the moment, we don't know how to fold this further. */
+ return build (code, type, expo0, expo1);
+}
+
+
+
+/* Fold the multiplication of a peeled chrec and a constant. */
+
+static inline tree
+chrec_fold_multiply_peel_cst (tree type,
+ tree peel,
+ tree cst)
+{
+#if defined ENABLE_CHECKING
+ if (peel == NULL_TREE
+ || cst == NULL_TREE
+ || TREE_CODE (peel) != PEELED_CHREC
+ || is_not_constant_evolution (cst))
+ abort ();
+#endif
+
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel),
+ chrec_fold_multiply (type, CHREC_LEFT (peel), cst),
+ chrec_fold_multiply (type, CHREC_RIGHT (peel), cst));
+}
+
+/* Fold the multiplication of an interval and a constant. */
+
+static inline tree
+chrec_fold_multiply_ival_cst (tree type,
+ tree ival,
+ tree cst)
+{
+ tree lowm, upm;
+ bool pos;
+
+#if defined ENABLE_CHECKING
+ if (ival == NULL_TREE
+ || cst == NULL_TREE
+ || TREE_CODE (ival) != INTERVAL_CHREC
+ || is_not_constant_evolution (cst))
+ abort ();
+#endif
+
+ /* Don't modify abstract values. */
+ if (ival == chrec_top)
+ return chrec_top;
+ if (ival == chrec_bot)
+ return chrec_bot;
+
+ if (!chrec_is_positive (cst, &pos))
+ return chrec_top;
+
+ lowm = chrec_fold_multiply (type, CHREC_LOW (ival), cst);
+ upm = chrec_fold_multiply (type, CHREC_UP (ival), cst);
+
+ if (pos)
+ return build_interval_chrec (lowm, upm);
+ else
+ return build_interval_chrec (upm, lowm);
+}
+
+/* Fold the multiplication of two polynomial functions. */
+
+static inline tree
+chrec_fold_multiply_poly_poly (tree type,
+ tree poly0,
+ tree poly1)
+{
+#if defined ENABLE_CHECKING
+ if (poly0 == NULL_TREE
+ || poly1 == NULL_TREE
+ || TREE_CODE (poly0) != POLYNOMIAL_CHREC
+ || TREE_CODE (poly1) != POLYNOMIAL_CHREC)
+ abort ();
+#endif
+
+ /* {a, +, b}_1 * {c, +, d}_2 -> {c*{a, +, b}_1, +, d}_2,
+ {a, +, b}_2 * {c, +, d}_1 -> {a*{c, +, d}_1, +, b}_2,
+ {a, +, b}_x * {c, +, d}_x -> {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x. */
+ if (CHREC_VARIABLE (poly0) < CHREC_VARIABLE (poly1))
+ /* poly0 is a constant wrt. poly1. */
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (poly1),
+ chrec_fold_multiply (type, CHREC_LEFT (poly1), poly0),
+ CHREC_RIGHT (poly1));
+
+ if (CHREC_VARIABLE (poly1) < CHREC_VARIABLE (poly0))
+ /* poly1 is a constant wrt. poly0. */
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (poly0),
+ chrec_fold_multiply (type, CHREC_LEFT (poly0), poly1),
+ CHREC_RIGHT (poly0));
+
+ /* poly0 and poly1 are two polynomials in the same variable,
+ {a, +, b}_x * {c, +, d}_x -> {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x. */
+ return
+ build_polynomial_chrec
+ (CHREC_VARIABLE (poly0),
+ build_polynomial_chrec
+ (CHREC_VARIABLE (poly0),
+
+ /* "a*c". */
+ chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)),
+
+ /* "a*d + b*c + b*d". */
+ chrec_fold_plus
+ (type, chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_RIGHT (poly1)),
+
+ chrec_fold_plus
+ (type,
+ chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_LEFT (poly1)),
+ chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1))))),
+
+ /* "2*b*d". */
+ chrec_fold_multiply
+ (type, build_int_2 (2, 0),
+ chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1))));
+}
+
+/* Fold the addition of a polynomial and a peeled chrec. */
+
+static inline tree
+chrec_fold_multiply_poly_peel (tree type,
+ tree poly,
+ tree peel)
+{
+#if defined ENABLE_CHECKING
+ if (peel == NULL_TREE
+ || poly == NULL_TREE
+ || TREE_CODE (peel) != PEELED_CHREC
+ || TREE_CODE (poly) != POLYNOMIAL_CHREC)
+ abort ();
+#endif
+
+ /*
+ {a, +, b}_1 * (c, d)_2 -> ({a, +, b}_1 * c, {a, +, b}_1 * d)_2,
+ {a, +, b}_2 * (c, d)_1 -> {a * (c, d)_1, +, b}_2,
+ {a, +, b}_x * (c, d)_x -> ({a, +, b}_x * c, {a, +, b}_x * d)_x. */
+ if (CHREC_VARIABLE (poly) < CHREC_VARIABLE (peel))
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel),
+ chrec_fold_multiply (type, poly, CHREC_LEFT (peel)),
+ chrec_fold_multiply (type, poly, CHREC_RIGHT (peel)));
+
+ if (CHREC_VARIABLE (poly) > CHREC_VARIABLE (peel))
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (poly),
+ chrec_fold_multiply (type, CHREC_LEFT (poly), peel),
+ chrec_fold_multiply (type, CHREC_RIGHT (poly), peel));
+
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel),
+ chrec_fold_multiply (type, poly, CHREC_LEFT (peel)),
+ chrec_fold_multiply (type, poly, CHREC_RIGHT (peel)));
+}
+
+/* Fold the multiplication of a polynomial and an exponential
+ functions. */
+
+static inline tree
+chrec_fold_multiply_poly_expo (tree type,
+ tree poly,
+ tree expo)
+{
+#if defined ENABLE_CHECKING
+ if (expo == NULL_TREE
+ || poly == NULL_TREE
+ || TREE_CODE (expo) != EXPONENTIAL_CHREC
+ || TREE_CODE (poly) != POLYNOMIAL_CHREC)
+ abort ();
+#endif
+
+ /* For the moment, we don't know how to fold this further. */
+ return build (MULT_EXPR, type, expo, poly);
+}
+
+/* Fold the addition of two peeled chrecs. */
+
+static inline tree
+chrec_fold_multiply_peel_peel (tree type,
+ tree peel0,
+ tree peel1)
+{
+#if defined ENABLE_CHECKING
+ if (peel0 == NULL_TREE
+ || peel1 == NULL_TREE
+ || TREE_CODE (peel0) != PEELED_CHREC
+ || TREE_CODE (peel1) != PEELED_CHREC)
+ abort ();
+#endif
+
+ /*
+ (a, b)_1 * (c, d)_2 -> ((a, b)_1 * c, (a, b)_1 * d)_2,
+ (a, b)_2 * (c, d)_1 -> (a * (c, d)_1, b * (c, d)_1)_2,
+ (a, b)_x * (c, d)_x -> (a * c, b * d)_x. */
+ if (CHREC_VARIABLE (peel0) < CHREC_VARIABLE (peel1))
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel1),
+ chrec_fold_multiply (type, peel0, CHREC_LEFT (peel1)),
+ chrec_fold_multiply (type, peel0, CHREC_RIGHT (peel1)));
+
+ if (CHREC_VARIABLE (peel0) > CHREC_VARIABLE (peel1))
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel0),
+ chrec_fold_multiply (type, CHREC_LEFT (peel0), peel1),
+ chrec_fold_multiply (type, CHREC_RIGHT (peel0), peel1));
+
+ return build_peeled_chrec
+ (CHREC_VARIABLE (peel0),
+ chrec_fold_multiply (type, CHREC_LEFT (peel0), CHREC_LEFT (peel1)),
+ chrec_fold_multiply (type, CHREC_RIGHT (peel0), CHREC_RIGHT (peel1)));
+}
+
+/* Fold the multiplication of two exponential functions. */
+
+static inline tree
+chrec_fold_multiply_expo_expo (tree type,
+ tree expo0,
+ tree expo1)
+{
+#if defined ENABLE_CHECKING
+ if (expo0 == NULL_TREE
+ || expo1 == NULL_TREE
+ || TREE_CODE (expo0) != EXPONENTIAL_CHREC
+ || TREE_CODE (expo1) != EXPONENTIAL_CHREC)
+ abort ();
+#endif
+
+ if (CHREC_VARIABLE (expo0) < CHREC_VARIABLE (expo1))
+ /* expo0 is a constant wrt. expo1. */
+ return build_exponential_chrec
+ (CHREC_VARIABLE (expo1),
+ chrec_fold_multiply (type, CHREC_LEFT (expo1), expo0),
+ CHREC_RIGHT (expo1));
+
+ if (CHREC_VARIABLE (expo1) < CHREC_VARIABLE (expo0))
+ /* expo1 is a constant wrt. expo0. */
+ return build_exponential_chrec
+ (CHREC_VARIABLE (expo0),
+ chrec_fold_multiply (type, CHREC_LEFT (expo0), expo1),
+ CHREC_RIGHT (expo0));
+
+ return build_exponential_chrec
+ (CHREC_VARIABLE (expo0),
+ chrec_fold_multiply (type, CHREC_LEFT (expo0), CHREC_LEFT (expo1)),
+ chrec_fold_multiply (type, CHREC_RIGHT (expo0), CHREC_RIGHT (expo1)));
+}
+
+/* Fold the multiplication of two intervals. */
+
+static inline tree
+chrec_fold_multiply_ival_ival (tree type,
+ tree ival0,
+ tree ival1)
+{
+ tree ac, ad, bc, bd;
+
+#if defined ENABLE_CHECKING
+ if (ival0 == NULL_TREE
+ || ival1 == NULL_TREE
+ || TREE_CODE (ival0) != INTERVAL_CHREC
+ || TREE_CODE (ival1) != INTERVAL_CHREC)
+ abort ();
+#endif
+
+ /* Don't modify abstract values. */
+ if (automatically_generated_chrec_p (ival0)
+ || automatically_generated_chrec_p (ival1))
+ chrec_fold_automatically_generated_operands (ival0, ival1);
+
+ ac = tree_fold_multiply (type, CHREC_LOW (ival0), CHREC_LOW (ival1));
+ ad = tree_fold_multiply (type, CHREC_LOW (ival0), CHREC_UP (ival1));
+ bc = tree_fold_multiply (type, CHREC_UP (ival0), CHREC_LOW (ival1));
+ bd = tree_fold_multiply (type, CHREC_UP (ival0), CHREC_UP (ival1));
+
+ /* [a, b] * [c, d] -> [min (ac, ad, bc, bd), max (ac, ad, bc, bd)],
+ for reference, see Moore's "Interval Arithmetic". */
+ return build_interval_chrec
+ (tree_fold_min
+ (type, tree_fold_min
+ (type, tree_fold_min (type, ac, ad), bc), bd),
+ tree_fold_max
+ (type, tree_fold_max
+ (type, tree_fold_max (type, ac, ad), bc), bd));
+}
+
+/* When the operands are automatically_generated_chrec_p, the fold has
+ to respect the semantics of the operands. */
+
+tree
+chrec_fold_automatically_generated_operands (tree op0,
+ tree op1)
+{
+ /* TOP op x = TOP,
+ x op TOP = TOP. */
+ if (op0 == chrec_top
+ || op1 == chrec_top)
+ return chrec_top;
+
+ /* BOT op TOP = TOP,
+ TOP op BOT = TOP,
+ BOT op x = BOT,
+ x op BOT = BOT. */
+ if (op0 == chrec_bot
+ || op1 == chrec_bot)
+ return chrec_bot;
+
+ if (op0 == chrec_not_analyzed_yet
+ || op1 == chrec_not_analyzed_yet)
+ return chrec_not_analyzed_yet;
+
+ /* The default case produces a safe result. */
+ return chrec_top;
+}
+
+/* Fold the addition of two chrecs. */
+
+static tree
+chrec_fold_plus_1 (enum tree_code code,
+ tree type,
+ tree op0,
+ tree op1)
+{
+ tree t1, t2;
+
+ if (automatically_generated_chrec_p (op0)
+ || automatically_generated_chrec_p (op1))
+ return chrec_fold_automatically_generated_operands (op0, op1);
+
+ switch (TREE_CODE (op0))
+ {
+ case POLYNOMIAL_CHREC:
+ switch (TREE_CODE (op1))
+ {
+ case POLYNOMIAL_CHREC:
+ return chrec_fold_plus_poly_poly (code, type, op0, op1);
+
+ case EXPONENTIAL_CHREC:
+ return chrec_fold_plus_poly_expo (code, type, op0, op1);
+
+ case PEELED_CHREC:
+ return chrec_fold_plus_poly_peel (code, type, op0, op1);
+
+ default:
+ if (code == PLUS_EXPR)
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (op0),
+ chrec_fold_plus (type, CHREC_LEFT (op0), op1),
+ CHREC_RIGHT (op0));
+ else
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (op0),
+ chrec_fold_minus (type, CHREC_LEFT (op0), op1),
+ CHREC_RIGHT (op0));
+ }
+
+ case EXPONENTIAL_CHREC:
+ switch (TREE_CODE (op1))
+ {
+ case POLYNOMIAL_CHREC:
+ return chrec_fold_plus_expo_poly (code, type, op0, op1);
+
+ case EXPONENTIAL_CHREC:
+ return chrec_fold_plus_expo_expo (code, type, op0, op1);
+
+ case PEELED_CHREC:
+ return build (code, type, op0, op1);
+
+ default:
+ return chrec_fold_plus_expo_cst (code, type, op0, op1);
+ }
+
+ case PEELED_CHREC:
+ switch (TREE_CODE (op1))
+ {
+ case POLYNOMIAL_CHREC:
+ return chrec_fold_plus_peel_poly (code, type, op0, op1);
+
+ case PEELED_CHREC:
+ return chrec_fold_plus_peel_peel (type, op0, op1);
+
+ case EXPONENTIAL_CHREC:
+ return build (code, type, op0, op1);
+
+ default:
+ return build_peeled_chrec
+ (CHREC_VARIABLE (op0),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, CHREC_LEFT (op0), op1) :
+ chrec_fold_minus (type, CHREC_LEFT (op0), op1)),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, CHREC_RIGHT (op0), op1) :
+ chrec_fold_minus (type, CHREC_RIGHT (op0), op1)));
+ }
+
+ case INTERVAL_CHREC:
+ switch (TREE_CODE (op1))
+ {
+ case POLYNOMIAL_CHREC:
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (op1),
+ (code == PLUS_EXPR ?
+ chrec_fold_plus (type, op0, CHREC_LEFT (op1)) :
+ chrec_fold_minus (type, op0, CHREC_LEFT (op1))),
+ CHREC_RIGHT (op1));
+
+ case EXPONENTIAL_CHREC:
+ return chrec_fold_plus_cst_expo (code, type, op0, op1);
+
+ case INTERVAL_CHREC:
+ t1 = (code == PLUS_EXPR ?
+ chrec_fold_plus (type, CHREC_LOW (op0), CHREC_LOW (op1)) :
+ chrec_fold_minus (type, CHREC_LOW (op0), CHREC_LOW (op1)));
+ t2 = (code == PLUS_EXPR ?
+ chrec_fold_plus (type, CHREC_UP (op0), CHREC_UP (op1)) :
+ chrec_fold_minus (type, CHREC_UP (op0), CHREC_UP (op1)));
+
+ return build_interval_chrec
+ (tree_fold_min (type, t1, t2),
+ tree_fold_max (type, t1, t2));
+
+ default:
+ t1 = (code == PLUS_EXPR ?
+ chrec_fold_plus (type, CHREC_LOW (op0), op1) :
+ chrec_fold_minus (type, CHREC_LOW (op0), op1));
+ t2 = (code == PLUS_EXPR ?
+ chrec_fold_plus (type, CHREC_UP (op0), op1) :
+ chrec_fold_minus (type, CHREC_UP (op0), op1));
+
+ return build_interval_chrec
+ (tree_fold_min (type, t1, t2),
+ tree_fold_max (type, t1, t2));
+ }
+
+ default:
+ switch (TREE_CODE (op1))
+ {
+ case POLYNOMIAL_CHREC:
+ if (code == PLUS_EXPR)
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (op1),
+ chrec_fold_plus (type, op0, CHREC_LEFT (op1)),
+ CHREC_RIGHT (op1));
+ else
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (op1),
+ chrec_fold_minus (type, op0, CHREC_LEFT (op1)),
+ chrec_fold_multiply (type, CHREC_RIGHT (op1),
+ convert (type,
+ integer_minus_one_node)));
+
+ case EXPONENTIAL_CHREC:
+ return chrec_fold_plus_cst_expo (code, type, op0, op1);
+
+ case PEELED_CHREC:
+ if (code == PLUS_EXPR)
+ return build_peeled_chrec
+ (CHREC_VARIABLE (op1),
+ chrec_fold_plus (type, op0, CHREC_LEFT (op1)),
+ chrec_fold_plus (type, op0, CHREC_RIGHT (op1)));
+ else
+ return build_peeled_chrec
+ (CHREC_VARIABLE (op1),
+ chrec_fold_minus (type, op0, CHREC_LEFT (op1)),
+ chrec_fold_minus (type, op0, CHREC_RIGHT (op1)));
+
+ case INTERVAL_CHREC:
+ t1 = (code == PLUS_EXPR ?
+ chrec_fold_plus (type, op0, CHREC_LOW (op1)) :
+ chrec_fold_minus (type, op0, CHREC_LOW (op1)));
+ t2 = (code == PLUS_EXPR ?
+ chrec_fold_plus (type, op0, CHREC_UP (op1)) :
+ chrec_fold_minus (type, op0, CHREC_UP (op1)));
+
+ return build_interval_chrec
+ (tree_fold_min (type, t1, t2),
+ tree_fold_max (type, t1, t2));
+
+ default:
+ if (tree_contains_chrecs (op0)
+ || tree_contains_chrecs (op1))
+ return build (code, type, op0, op1);
+ else
+ return fold (build (code, type, op0, op1));
+ }
+ }
+}
+
+/* Fold the addition of two chrecs. */
+
+tree
+chrec_fold_plus (tree type,
+ tree op0,
+ tree op1)
+{
+ if (integer_zerop (op0)
+ || (TREE_CODE (op0) == INTERVAL_CHREC
+ && integer_zerop (CHREC_LOW (op0))
+ && integer_zerop (CHREC_UP (op0))))
+ return op1;
+ if (integer_zerop (op1)
+ || (TREE_CODE (op1) == INTERVAL_CHREC
+ && integer_zerop (CHREC_LOW (op1))
+ && integer_zerop (CHREC_UP (op1))))
+ return op0;
+
+ return chrec_fold_plus_1 (PLUS_EXPR, type, op0, op1);
+}
+
+/* Fold the substraction of two chrecs. */
+
+tree
+chrec_fold_minus (tree type,
+ tree op0,
+ tree op1)
+{
+ if (integer_zerop (op1)
+ || (TREE_CODE (op1) == INTERVAL_CHREC
+ && integer_zerop (CHREC_LOW (op1))
+ && integer_zerop (CHREC_UP (op1))))
+ return op0;
+
+ return chrec_fold_plus_1 (MINUS_EXPR, type, op0, op1);
+}
+
+/* Fold the negation of a two chrec. */
+
+tree
+chrec_fold_negate (tree type, tree op0)
+{
+ if (integer_zerop (op0)
+ || (TREE_CODE (op0) == INTERVAL_CHREC
+ && integer_zerop (CHREC_LOW (op0))
+ && integer_zerop (CHREC_UP (op0))))
+ return op0;
+
+ return chrec_fold_plus_1 (MINUS_EXPR, type,
+ convert (type, integer_zero_node),
+ op0);
+}
+/* Fold the multiplication of two chrecs. */
+
+tree
+chrec_fold_multiply (tree type,
+ tree op0,
+ tree op1)
+{
+ if (automatically_generated_chrec_p (op0)
+ || automatically_generated_chrec_p (op1))
+ return chrec_fold_automatically_generated_operands (op0, op1);
+
+ switch (TREE_CODE (op0))
+ {
+ case POLYNOMIAL_CHREC:
+ switch (TREE_CODE (op1))
+ {
+ case POLYNOMIAL_CHREC:
+ return chrec_fold_multiply_poly_poly (type, op0, op1);
+
+ case PEELED_CHREC:
+ return chrec_fold_multiply_poly_peel (type, op0, op1);
+
+ case EXPONENTIAL_CHREC:
+ return chrec_fold_multiply_poly_expo (type, op0, op1);
+
+ default:
+ if (integer_onep (op1))
+ return op0;
+ if (integer_zerop (op1))
+ return integer_zero_node;
+
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (op0),
+ chrec_fold_multiply (type, CHREC_LEFT (op0), op1),
+ chrec_fold_multiply (type, CHREC_RIGHT (op0), op1));
+ }
+
+ case PEELED_CHREC:
+ switch (TREE_CODE (op1))
+ {
+ case POLYNOMIAL_CHREC:
+ return chrec_fold_multiply_poly_peel (type, op1, op0);
+
+ case PEELED_CHREC:
+ return chrec_fold_multiply_peel_peel (type, op0, op1);
+
+ default:
+ if (integer_onep (op1))
+ return op0;
+ if (integer_zerop (op1))
+ return integer_zero_node;
+
+ return build_peeled_chrec
+ (CHREC_VARIABLE (op0),
+ chrec_fold_multiply (type, CHREC_LEFT (op0), op1),
+ chrec_fold_multiply (type, CHREC_RIGHT (op0), op1));
+ }
+
+ case EXPONENTIAL_CHREC:
+ switch (TREE_CODE (op1))
+ {
+ case POLYNOMIAL_CHREC:
+ return chrec_fold_multiply_poly_expo (type, op1, op0);
+
+ case EXPONENTIAL_CHREC:
+ return chrec_fold_multiply_expo_expo (type, op0, op1);
+
+ default:
+ if (integer_onep (op1))
+ return op0;
+ if (integer_zerop (op1))
+ return integer_zero_node;
+
+ return build_exponential_chrec
+ (CHREC_VARIABLE (op0),
+ chrec_fold_multiply (type, CHREC_LEFT (op0), op1),
+ CHREC_RIGHT (op0));
+ }
+
+ case INTERVAL_CHREC:
+ switch (TREE_CODE (op1))
+ {
+ case POLYNOMIAL_CHREC:
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (op1),
+ chrec_fold_multiply (type, CHREC_LEFT (op1), op0),
+ chrec_fold_multiply (type, CHREC_RIGHT (op1), op0));
+
+ case PEELED_CHREC:
+ return build_peeled_chrec
+ (CHREC_VARIABLE (op1),
+ chrec_fold_multiply (type, CHREC_LEFT (op1), op0),
+ chrec_fold_multiply (type, CHREC_RIGHT (op1), op0));
+
+ case EXPONENTIAL_CHREC:
+ return build_exponential_chrec
+ (CHREC_VARIABLE (op1),
+ chrec_fold_multiply (type, CHREC_LEFT (op1), op0),
+ CHREC_RIGHT (op1));
+
+ case INTERVAL_CHREC:
+ return chrec_fold_multiply_ival_ival (type, op0, op1);
+
+ default:
+ if (integer_onep (op1))
+ return op0;
+ if (integer_zerop (op1))
+ return integer_zero_node;
+ return chrec_fold_multiply_ival_cst (type, op0, op1);
+ }
+
+ default:
+ if (integer_onep (op0))
+ return op1;
+
+ if (integer_zerop (op0))
+ return integer_zero_node;
+
+ switch (TREE_CODE (op1))
+ {
+ case POLYNOMIAL_CHREC:
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (op1),
+ chrec_fold_multiply (type, CHREC_LEFT (op1), op0),
+ chrec_fold_multiply (type, CHREC_RIGHT (op1), op0));
+
+ case PEELED_CHREC:
+ return build_peeled_chrec
+ (CHREC_VARIABLE (op1),
+ chrec_fold_multiply (type, CHREC_LEFT (op1), op0),
+ chrec_fold_multiply (type, CHREC_RIGHT (op1), op0));
+
+ case EXPONENTIAL_CHREC:
+ return build_exponential_chrec
+ (CHREC_VARIABLE (op1),
+ chrec_fold_multiply (type, CHREC_LEFT (op1), op0),
+ CHREC_RIGHT (op1));
+
+ case INTERVAL_CHREC:
+ return chrec_fold_multiply_ival_cst (type, op1, op0);
+
+ default:
+ if (integer_onep (op1))
+ return op0;
+ if (integer_zerop (op1))
+ return integer_zero_node;
+ return tree_fold_multiply (type, op0, op1);
+ }
+ }
+}
+
+
+
+/* Operations. */
+
+/* Try to recognize the nature of the peeled chrec and to transform it
+ into a more specific chrec: polynomial, periodic, ... For example,
+ this function transforms (6, {9, +, 3}_1)_1 into {6, +, 3}_1. */
+
+tree
+simplify_peeled_chrec (tree peel)
+{
+ tree res = peel;
+
+ return res;
+}
+
+/* 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)
+{
+ tree binomial_n_k = tree_fold_binomial (n, k);
+
+ if (TREE_CODE (chrec) == EXPONENTIAL_CHREC
+ && CHREC_VARIABLE (chrec) == var)
+ return chrec_top;
+
+ if (TREE_CODE (chrec) == POLYNOMIAL_CHREC)
+ {
+ if (CHREC_VARIABLE (chrec) > var)
+ return chrec_evaluate (var, CHREC_LEFT (chrec), n, k);
+
+ if (CHREC_VARIABLE (chrec) == var)
+ return chrec_fold_plus
+ (chrec_type (chrec),
+ chrec_fold_multiply (chrec_type (CHREC_LEFT (chrec)),
+ binomial_n_k,
+ CHREC_LEFT (chrec)),
+ chrec_evaluate (var, CHREC_RIGHT (chrec), n,
+ tree_fold_plus (integer_type_node,
+ k, integer_one_node)));
+
+ return chrec_fold_multiply (chrec_type (chrec), binomial_n_k, chrec);
+ }
+ else
+ return chrec_fold_multiply (chrec_type (chrec), binomial_n_k, chrec);
+}
+
+/* Evaluates "CHREC (X)" when the varying variable is VAR.
+ Example: Given the following parameters,
+
+ var = 1
+ chrec = {5, +, {3, +, 4}_1}_1
+ x = 10
+
+ The result is given by the Newton's interpolating formula:
+ 5 * \binom{10}{0} + 3 * \binom{10}{1} + 4 * \binom{10}{2}.
+*/
+
+tree
+chrec_apply (unsigned var,
+ tree chrec,
+ tree x)
+{
+ tree res = chrec_top;
+
+ if (automatically_generated_chrec_p (chrec)
+ || automatically_generated_chrec_p (x))
+ return chrec_top;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "(chrec_apply \n");
+
+ if (evolution_function_is_affine_p (chrec))
+ {
+ /* "{a, +, b} (x)" -> "a + b*x". */
+ if (TREE_CODE (CHREC_LEFT (chrec)) == INTEGER_CST
+ && integer_zerop (CHREC_LEFT (chrec)))
+ res = chrec_fold_multiply
+ (chrec_type (chrec), CHREC_RIGHT (chrec), x);
+
+ else
+ res = chrec_fold_plus (chrec_type (chrec),
+ CHREC_LEFT (chrec),
+ chrec_fold_multiply
+ (chrec_type (chrec), CHREC_RIGHT (chrec), x));
+ }
+
+ else if (TREE_CODE (chrec) != POLYNOMIAL_CHREC
+ && TREE_CODE (chrec) != EXPONENTIAL_CHREC)
+ res = chrec;
+
+ 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);
+
+ else
+ res = chrec_top;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " (varying_loop = %d\n", var);
+ fprintf (dump_file, ")\n (chrec = ");
+ print_generic_expr (dump_file, chrec, 0);
+ fprintf (dump_file, ")\n (x = ");
+ print_generic_expr (dump_file, x, 0);
+ fprintf (dump_file, ")\n (res = ");
+ print_generic_expr (dump_file, res, 0);
+ fprintf (dump_file, "))\n");
+ }
+
+ return res;
+}
+
+/* Replaces the initial condition in CHREC with INIT_COND. */
+
+tree
+chrec_replace_initial_condition (tree chrec,
+ tree init_cond)
+{
+ if (automatically_generated_chrec_p (chrec))
+ return chrec;
+
+ switch (TREE_CODE (chrec))
+ {
+ case POLYNOMIAL_CHREC:
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (chrec),
+ chrec_replace_initial_condition (CHREC_LEFT (chrec), init_cond),
+ CHREC_RIGHT (chrec));
+
+ case EXPONENTIAL_CHREC:
+ return build_exponential_chrec
+ (CHREC_VARIABLE (chrec),
+ chrec_replace_initial_condition (CHREC_LEFT (chrec), init_cond),
+ CHREC_RIGHT (chrec));
+
+ case PEELED_CHREC:
+ return chrec_top;
+
+ default:
+ return init_cond;
+ }
+}
+
+/* Returns the initial condition of a given CHREC. */
+
+tree
+initial_condition (tree chrec)
+{
+ if (automatically_generated_chrec_p (chrec))
+ return chrec;
+
+ if (TREE_CODE (chrec) == POLYNOMIAL_CHREC
+ || TREE_CODE (chrec) == EXPONENTIAL_CHREC)
+ return initial_condition (CHREC_LEFT (chrec));
+ else
+ return chrec;
+}
+
+/* Returns a multivariate function that has no evolution in LOOP_NUM.
+ Mask the evolution LOOP_NUM. */
+
+tree
+hide_evolution_in_loop (tree chrec, unsigned loop_num)
+{
+ if (automatically_generated_chrec_p (chrec))
+ return chrec;
+
+ switch (TREE_CODE (chrec))
+ {
+ case POLYNOMIAL_CHREC:
+ if (CHREC_VARIABLE (chrec) >= loop_num)
+ return hide_evolution_in_loop (CHREC_LEFT (chrec), loop_num);
+
+ else
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (chrec),
+ hide_evolution_in_loop (CHREC_LEFT (chrec), loop_num),
+ CHREC_RIGHT (chrec));
+
+ case EXPONENTIAL_CHREC:
+ if (CHREC_VARIABLE (chrec) >= loop_num)
+ return hide_evolution_in_loop (CHREC_LEFT (chrec), loop_num);
+
+ else
+ return build_exponential_chrec
+ (CHREC_VARIABLE (chrec),
+ hide_evolution_in_loop (CHREC_LEFT (chrec), loop_num),
+ CHREC_RIGHT (chrec));
+
+ default:
+ return chrec;
+ }
+}
+
+/* Returns a univariate function that represents the evolution in
+ LOOP_NUM. Mask the evolution of any other loop. */
+
+tree
+hide_evolution_in_other_loops_than_loop (tree chrec,
+ unsigned loop_num)
+{
+ if (automatically_generated_chrec_p (chrec))
+ return chrec;
+
+ switch (TREE_CODE (chrec))
+ {
+ case POLYNOMIAL_CHREC:
+ if (CHREC_VARIABLE (chrec) == loop_num)
+ return build_polynomial_chrec
+ (loop_num,
+ hide_evolution_in_other_loops_than_loop (CHREC_LEFT (chrec),
+ loop_num),
+ CHREC_RIGHT (chrec));
+
+ else if (CHREC_VARIABLE (chrec) < loop_num)
+ /* There is no evolution in this loop. */
+ return initial_condition (chrec);
+
+ else
+ return hide_evolution_in_other_loops_than_loop (CHREC_LEFT (chrec),
+ loop_num);
+
+ case EXPONENTIAL_CHREC:
+ if (CHREC_VARIABLE (chrec) == loop_num)
+ return build_exponential_chrec
+ (loop_num,
+ hide_evolution_in_other_loops_than_loop (CHREC_LEFT (chrec),
+ loop_num),
+ CHREC_RIGHT (chrec));
+
+ else if (CHREC_VARIABLE (chrec) < loop_num)
+ /* There is no evolution in this loop. */
+ return initial_condition (chrec);
+
+ else
+ return hide_evolution_in_other_loops_than_loop (CHREC_LEFT (chrec),
+ loop_num);
+
+ default:
+ return chrec;
+ }
+}
+
+/* Returns the evolution part in LOOP_NUM. Example: the call
+ get_evolution_in_loop (1, {{0, +, 1}_1, +, 2}_1) returns
+ {1, +, 2}_1 */
+
+tree
+evolution_part_in_loop_num (tree chrec,
+ unsigned loop_num)
+{
+ if (automatically_generated_chrec_p (chrec))
+ return chrec;
+
+ switch (TREE_CODE (chrec))
+ {
+ case POLYNOMIAL_CHREC:
+ if (CHREC_VARIABLE (chrec) == loop_num)
+ {
+ if (TREE_CODE (CHREC_LEFT (chrec)) != POLYNOMIAL_CHREC
+ || CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec))
+ return CHREC_RIGHT (chrec);
+
+ else
+ return build_polynomial_chrec
+ (loop_num,
+ evolution_part_in_loop_num (CHREC_LEFT (chrec), loop_num),
+ CHREC_RIGHT (chrec));
+ }
+
+ else if (CHREC_VARIABLE (chrec) < loop_num)
+ /* There is no evolution part in this loop. */
+ return NULL_TREE;
+
+ else
+ return evolution_part_in_loop_num (CHREC_LEFT (chrec), loop_num);
+
+ case EXPONENTIAL_CHREC:
+ if (CHREC_VARIABLE (chrec) == loop_num)
+ {
+ if (TREE_CODE (CHREC_LEFT (chrec)) != EXPONENTIAL_CHREC
+ || CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec))
+ return CHREC_RIGHT (chrec);
+
+ else
+ return build_exponential_chrec
+ (loop_num,
+ evolution_part_in_loop_num (CHREC_LEFT (chrec), loop_num),
+ CHREC_RIGHT (chrec));
+ }
+
+ else if (CHREC_VARIABLE (chrec) < loop_num)
+ /* There is no evolution part in this loop. */
+ return NULL_TREE;
+
+ else
+ return evolution_part_in_loop_num (CHREC_LEFT (chrec), loop_num);
+
+ default:
+ return NULL_TREE;
+ }
+}
+
+/* Set or reset the evolution of CHREC to NEW_EVOL in loop LOOP_NUM.
+ This function is essentially used for setting the evolution to
+ chrec_top, for example after having determined that it is
+ impossible to say how many times a loop will execute. */
+
+tree
+reset_evolution_in_loop (unsigned loop_num,
+ tree chrec,
+ tree new_evol)
+{
+ if ((TREE_CODE (chrec) == POLYNOMIAL_CHREC
+ || TREE_CODE (chrec) == EXPONENTIAL_CHREC)
+ && CHREC_VARIABLE (chrec) > loop_num)
+ return build
+ (TREE_CODE (chrec),
+ build_int_2 (CHREC_VARIABLE (chrec), 0),
+ reset_evolution_in_loop (loop_num, CHREC_LEFT (chrec), new_evol),
+ reset_evolution_in_loop (loop_num, CHREC_RIGHT (chrec), new_evol));
+
+ while ((TREE_CODE (chrec) == POLYNOMIAL_CHREC
+ || TREE_CODE (chrec) == EXPONENTIAL_CHREC)
+ && CHREC_VARIABLE (chrec) == loop_num)
+ chrec = CHREC_LEFT (chrec);
+
+ return build_polynomial_chrec (loop_num, chrec, new_evol);
+}
+
+
+/* Returns the value of the variable after one execution of the loop
+ LOOP_NB, supposing that CHREC is the evolution function of the
+ variable.
+
+ Example:
+ chrec_eval_next_init_cond (4, {{1, +, 3}_2, +, 10}_4) = 11. */
+
+tree
+chrec_eval_next_init_cond (unsigned loop_nb,
+ tree chrec)
+{
+ tree init_cond;
+
+ init_cond = initial_condition (chrec);
+
+ if (TREE_CODE (chrec) == POLYNOMIAL_CHREC
+ || TREE_CODE (chrec) == EXPONENTIAL_CHREC)
+ {
+ if (CHREC_VARIABLE (chrec) < loop_nb)
+ /* There is no evolution in this dimension. */
+ return init_cond;
+
+ while ((TREE_CODE (CHREC_LEFT (chrec)) == POLYNOMIAL_CHREC
+ || TREE_CODE (CHREC_LEFT (chrec)) == EXPONENTIAL_CHREC)
+ && CHREC_VARIABLE (CHREC_LEFT (chrec)) >= loop_nb)
+ chrec = CHREC_LEFT (chrec);
+
+ if (CHREC_VARIABLE (chrec) != loop_nb)
+ /* There is no evolution in this dimension. */
+ return init_cond;
+
+ if (TREE_CODE (chrec) == POLYNOMIAL_CHREC)
+ /* testsuite/.../ssa-chrec-14.c */
+ return chrec_fold_plus (chrec_type (init_cond), init_cond,
+ initial_condition (CHREC_RIGHT (chrec)));
+
+ else
+ return chrec_fold_multiply (chrec_type (init_cond), init_cond,
+ initial_condition (CHREC_RIGHT (chrec)));
+ }
+
+ else
+ return init_cond;
+}
+
+/* Determine the type of the result after the merge of types TYPE0 and
+ TYPE1. */
+
+static inline tree
+chrec_merge_types (tree type0,
+ tree type1)
+{
+ if (type0 == type1)
+ return type0;
+
+ else
+ /* FIXME. */
+ return NULL_TREE;
+}
+
+/* Merge the information contained in intervals or scalar constants.
+ merge ([a, b], [c, d]) -> [min (a, c), max (b, d)],
+ merge ([a, b], c) -> [min (a, c), max (b, c)],
+ merge (a, [b, c]) -> [min (a, b), max (a, c)],
+ merge (a, b) -> [min (a, b), max (a, b)]. */
+
+static inline tree
+chrec_merge_intervals (tree chrec1,
+ tree chrec2)
+{
+ tree type1 = chrec_type (chrec1);
+ tree type2 = chrec_type (chrec2);
+ tree type = chrec_merge_types (type1, type2);
+
+ if (type == NULL_TREE)
+ return chrec_top;
+
+ if (TREE_CODE (chrec1) == INTERVAL_CHREC)
+ {
+ if (TREE_CODE (chrec2) == INTERVAL_CHREC)
+ return build_interval_chrec
+ (tree_fold_min (type, CHREC_LOW (chrec1), CHREC_LOW (chrec2)),
+ tree_fold_max (type, CHREC_UP (chrec1), CHREC_UP (chrec2)));
+ else
+ return build_interval_chrec
+ (tree_fold_min (type, CHREC_LOW (chrec1), chrec2),
+ tree_fold_max (type, CHREC_UP (chrec1), chrec2));
+ }
+ else if (TREE_CODE (chrec2) == INTERVAL_CHREC)
+ return build_interval_chrec
+ (tree_fold_min (type, CHREC_LOW (chrec2), chrec1),
+ tree_fold_max (type, CHREC_UP (chrec2), chrec1));
+ else
+ return build_interval_chrec
+ (tree_fold_min (type, chrec1, chrec2),
+ tree_fold_max (type, chrec1, chrec2));
+}
+
+/* Merges two evolution functions that were found by following two
+ alternate paths of a conditional expression. */
+
+tree
+chrec_merge (tree chrec1,
+ tree chrec2)
+{
+ if (chrec1 == chrec_top
+ || chrec2 == chrec_top)
+ return chrec_top;
+
+ if (chrec1 == chrec_bot
+ || chrec2 == chrec_bot)
+ return chrec_bot;
+
+ if (chrec1 == chrec_not_analyzed_yet)
+ return chrec2;
+ if (chrec2 == chrec_not_analyzed_yet)
+ return chrec1;
+
+ if (operand_equal_p (chrec1, chrec2, 0))
+ return chrec1;
+
+ switch (TREE_CODE (chrec1))
+ {
+ case INTEGER_CST:
+ case INTERVAL_CHREC:
+ switch (TREE_CODE (chrec2))
+ {
+ case INTEGER_CST:
+ case INTERVAL_CHREC:
+ return chrec_merge_intervals (chrec1, chrec2);
+
+ case POLYNOMIAL_CHREC:
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (chrec2),
+ chrec_merge (chrec1, CHREC_LEFT (chrec2)),
+ chrec_merge (integer_zero_node, CHREC_RIGHT (chrec2)));
+
+ case EXPONENTIAL_CHREC:
+ return build_exponential_chrec
+ (CHREC_VARIABLE (chrec2),
+ chrec_merge (chrec1, CHREC_LEFT (chrec2)),
+ chrec_merge (integer_one_node, CHREC_RIGHT (chrec2)));
+
+ default:
+ return chrec_top;
+ }
+
+ case POLYNOMIAL_CHREC:
+ switch (TREE_CODE (chrec2))
+ {
+ case INTEGER_CST:
+ case INTERVAL_CHREC:
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (chrec1),
+ chrec_merge (CHREC_LEFT (chrec1), chrec2),
+ chrec_merge (CHREC_RIGHT (chrec1), integer_zero_node));
+
+ case POLYNOMIAL_CHREC:
+ if (CHREC_VARIABLE (chrec1) == CHREC_VARIABLE (chrec2))
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (chrec2),
+ chrec_merge (CHREC_LEFT (chrec1), CHREC_LEFT (chrec2)),
+ chrec_merge (CHREC_RIGHT (chrec1), CHREC_RIGHT (chrec2)));
+ else if (CHREC_VARIABLE (chrec1) < CHREC_VARIABLE (chrec2))
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (chrec2),
+ chrec_merge (chrec1, CHREC_LEFT (chrec2)),
+ chrec_merge (integer_zero_node, CHREC_RIGHT (chrec2)));
+ else
+ return build_polynomial_chrec
+ (CHREC_VARIABLE (chrec1),
+ chrec_merge (CHREC_LEFT (chrec1), chrec2),
+ chrec_merge (CHREC_RIGHT (chrec1), integer_zero_node));
+
+ case EXPONENTIAL_CHREC:
+ return chrec_top;
+
+ default:
+ return chrec_top;
+ }
+
+ case EXPONENTIAL_CHREC:
+ return chrec_top;
+
+ default:
+ return chrec_top;
+ }
+}
+
+
+
+/* Observers. */
+
+/* Helper function for is_multivariate_chrec. */
+
+static bool
+is_multivariate_chrec_rec (tree chrec, unsigned int rec_var)
+{
+ if (chrec == NULL_TREE)
+ return false;
+
+ if (TREE_CODE (chrec) == POLYNOMIAL_CHREC
+ || TREE_CODE (chrec) == EXPONENTIAL_CHREC)
+ {
+ if (CHREC_VARIABLE (chrec) != rec_var)
+ return true;
+ else
+ return (is_multivariate_chrec_rec (CHREC_LEFT (chrec), rec_var)
+ || is_multivariate_chrec_rec (CHREC_RIGHT (chrec), rec_var));
+ }
+ else
+ return false;
+}
+
+/* Determine whether the given chrec is multivariate or not. */
+
+bool
+is_multivariate_chrec (tree chrec)
+{
+ if (chrec == NULL_TREE)
+ return false;
+
+ if (TREE_CODE (chrec) == POLYNOMIAL_CHREC
+ || TREE_CODE (chrec) == EXPONENTIAL_CHREC)
+ return (is_multivariate_chrec_rec (CHREC_LEFT (chrec),
+ CHREC_VARIABLE (chrec))
+ || is_multivariate_chrec_rec (CHREC_RIGHT (chrec),
+ CHREC_VARIABLE (chrec)));
+ else
+ return false;
+}
+
+/* Determine whether the given chrec is a polynomial or not. */
+
+bool
+is_pure_sum_chrec (tree chrec)
+{
+ if (chrec == NULL_TREE)
+ return true;
+
+ if (TREE_CODE (chrec) == EXPONENTIAL_CHREC)
+ return false;
+
+ if (TREE_CODE (chrec) == POLYNOMIAL_CHREC)
+ return (is_pure_sum_chrec (CHREC_LEFT (chrec))
+ && is_pure_sum_chrec (CHREC_RIGHT (chrec)));
+
+ return true;
+}
+
+/* Determines whether CHREC is a loop invariant wrt. LOOP_NUM. */
+
+bool
+no_evolution_in_loop_p (tree chrec,
+ unsigned loop_num)
+{
+ tree scev;
+
+ if (chrec == chrec_not_analyzed_yet)
+ return true;
+ if (chrec == chrec_top)
+ return false;
+
+ scev = hide_evolution_in_other_loops_than_loop (chrec, loop_num);
+ return (TREE_CODE (scev) != POLYNOMIAL_CHREC
+ && TREE_CODE (scev) != EXPONENTIAL_CHREC);
+}
+
+/* Determines whether the chrec contains symbolic names or not. */
+
+bool
+chrec_contains_symbols (tree chrec)
+{
+ if (chrec == NULL_TREE)
+ return false;
+
+ if (TREE_CODE (chrec) == SSA_NAME
+ || TREE_CODE (chrec) == VAR_DECL
+ || TREE_CODE (chrec) == PARM_DECL
+ || TREE_CODE (chrec) == FUNCTION_DECL
+ || TREE_CODE (chrec) == LABEL_DECL
+ || TREE_CODE (chrec) == RESULT_DECL
+ || TREE_CODE (chrec) == FIELD_DECL)
+ return true;
+
+ switch (TREE_CODE_LENGTH (TREE_CODE (chrec)))
+ {
+ case 3:
+ if (chrec_contains_symbols (TREE_OPERAND (chrec, 2)))
+ return true;
+
+ case 2:
+ if (chrec_contains_symbols (TREE_OPERAND (chrec, 1)))
+ return true;
+
+ case 1:
+ if (chrec_contains_symbols (TREE_OPERAND (chrec, 0)))
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Determines whether the chrec contains undetermined coefficients. */
+
+bool
+chrec_contains_undetermined (tree chrec)
+{
+ if (chrec == chrec_top
+ || chrec == chrec_not_analyzed_yet
+ || chrec == NULL_TREE)
+ return true;
+
+ switch (TREE_CODE_LENGTH (TREE_CODE (chrec)))
+ {
+ case 3:
+ if (chrec_contains_undetermined (TREE_OPERAND (chrec, 2)))
+ return true;
+
+ case 2:
+ if (chrec_contains_undetermined (TREE_OPERAND (chrec, 1)))
+ return true;
+
+ case 1:
+ if (chrec_contains_undetermined (TREE_OPERAND (chrec, 0)))
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Determines whether the chrec contains interval coefficients. */
+
+bool
+chrec_contains_intervals (tree chrec)
+{
+ if (chrec == NULL_TREE
+ || automatically_generated_chrec_p (chrec))
+ return false;
+
+ if (TREE_CODE (chrec) == INTERVAL_CHREC)
+ return true;
+
+ switch (TREE_CODE_LENGTH (TREE_CODE (chrec)))
+ {
+ case 3:
+ if (chrec_contains_intervals (TREE_OPERAND (chrec, 2)))
+ return true;
+
+ case 2:
+ if (chrec_contains_intervals (TREE_OPERAND (chrec, 1)))
+ return true;
+
+ case 1:
+ if (chrec_contains_intervals (TREE_OPERAND (chrec, 0)))
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Determines whether the tree EXPR contains chrecs. */
+
+bool
+tree_contains_chrecs (tree expr)
+{
+ if (expr == NULL_TREE)
+ return false;
+
+ if (tree_is_chrec (expr))
+ return true;
+
+ switch (TREE_CODE_LENGTH (TREE_CODE (expr)))
+ {
+ case 3:
+ if (tree_contains_chrecs (TREE_OPERAND (expr, 2)))
+ return true;
+
+ case 2:
+ if (tree_contains_chrecs (TREE_OPERAND (expr, 1)))
+ return true;
+
+ case 1:
+ if (tree_contains_chrecs (TREE_OPERAND (expr, 0)))
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* Determine whether the given tree is an affine multivariate
+ evolution. */
+
+bool
+evolution_function_is_affine_multivariate_p (tree chrec)
+{
+ if (chrec == NULL_TREE)
+ return false;
+
+ switch (TREE_CODE (chrec))
+ {
+ case POLYNOMIAL_CHREC:
+ if (evolution_function_is_constant_p (CHREC_LEFT (chrec)))
+ {
+ if (evolution_function_is_constant_p (CHREC_RIGHT (chrec)))
+ return true;
+ else
+ {
+ if (CHREC_VARIABLE (CHREC_RIGHT (chrec))
+ != CHREC_VARIABLE (chrec)
+ && evolution_function_is_affine_multivariate_p
+ (CHREC_RIGHT (chrec)))
+ return true;
+ else
+ return false;
+ }
+ }
+ else
+ {
+ if (evolution_function_is_constant_p (CHREC_RIGHT (chrec))
+ && CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec)
+ && evolution_function_is_affine_multivariate_p
+ (CHREC_LEFT (chrec)))
+ return true;
+ else
+ return false;
+ }
+
+
+ case EXPONENTIAL_CHREC:
+ case INTERVAL_CHREC:
+ default:
+ return false;
+ }
+}
+
+/* Determine whether the given tree is a function in zero or one
+ variables. */
+
+bool
+evolution_function_is_univariate_p (tree chrec)
+{
+ if (chrec == NULL_TREE)
+ return true;
+
+ switch (TREE_CODE (chrec))
+ {
+ case POLYNOMIAL_CHREC:
+ case EXPONENTIAL_CHREC:
+ switch (TREE_CODE (CHREC_LEFT (chrec)))
+ {
+ case POLYNOMIAL_CHREC:
+ case EXPONENTIAL_CHREC:
+ if (CHREC_VARIABLE (chrec) != CHREC_VARIABLE (CHREC_LEFT (chrec)))
+ return false;
+ if (!evolution_function_is_univariate_p (CHREC_LEFT (chrec)))
+ return false;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (TREE_CODE (CHREC_RIGHT (chrec)))
+ {
+ case POLYNOMIAL_CHREC:
+ case EXPONENTIAL_CHREC:
+ if (CHREC_VARIABLE (chrec) != CHREC_VARIABLE (CHREC_RIGHT (chrec)))
+ return false;
+ if (!evolution_function_is_univariate_p (CHREC_RIGHT (chrec)))
+ return false;
+ break;
+
+ default:
+ break;
+ }
+
+ default:
+ return true;
+ }
+}
+
+
+
+/* Convert the initial condition of chrec to type. */
+
+tree
+chrec_convert (tree type,
+ tree chrec)
+{
+ tree ct;
+
+ if (automatically_generated_chrec_p (chrec))
+ return chrec;
+
+ ct = chrec_type (chrec);
+ if (ct == type)
+ return chrec;
+
+ if (TYPE_PRECISION (ct) < TYPE_PRECISION (type))
+ return convert (type, chrec);
+
+ switch (TREE_CODE (chrec))
+ {
+ case POLYNOMIAL_CHREC:
+ return build_polynomial_chrec (CHREC_VARIABLE (chrec),
+ chrec_convert (type,
+ CHREC_LEFT (chrec)),
+ chrec_convert (type,
+ CHREC_RIGHT (chrec)));
+
+ case EXPONENTIAL_CHREC:
+ return build_exponential_chrec (CHREC_VARIABLE (chrec),
+ chrec_convert (type,
+ CHREC_LEFT (chrec)),
+ chrec_convert (type,
+ CHREC_RIGHT (chrec)));
+
+ case PEELED_CHREC:
+ return build_peeled_chrec
+ (CHREC_VARIABLE (chrec),
+ chrec_convert (type, CHREC_LEFT (chrec)),
+ chrec_convert (type, CHREC_RIGHT (chrec)));
+
+ case INTERVAL_CHREC:
+ return build_interval_chrec
+ (chrec_convert (type, CHREC_LOW (chrec)),
+ chrec_convert (type, CHREC_UP (chrec)));
+
+ default:
+ return convert (type, chrec);
+ }
+}
+
+/* Returns the type of the chrec. */
+
+tree
+chrec_type (tree chrec)
+{
+ if (automatically_generated_chrec_p (chrec))
+ return NULL_TREE;
+
+ return TREE_TYPE (chrec);
+}
+