From c8a2ab6d0cba93c47b539695202773b276360745 Mon Sep 17 00:00:00 2001 From: Sebastian Pop Date: Wed, 30 Jun 2004 17:37:42 +0200 Subject: [PATCH] Makefile.in (OBJS-common): Add tree-chrec.o. * Makefile.in (OBJS-common): Add tree-chrec.o. (tree-chrec.o): New rule. (GTFILES): Add tree-chrec.h. * gengtype.c (open_base_files): Add tree-chrec.h. * tree-chrec.c: New file. * tree-chrec.h: New file. * tree.def (SCEV_KNOWN, SCEV_NOT_KNOWN, POLYNOMIAL_CHREC): New nodes. From-SVN: r83909 --- gcc/ChangeLog | 10 + gcc/Makefile.in | 4 + gcc/gengtype.c | 1 + gcc/tree-chrec.c | 1019 ++++++++++++++++++++++++++++++++++++++++++++++ gcc/tree-chrec.h | 206 ++++++++++ gcc/tree.def | 12 + 6 files changed, 1252 insertions(+) create mode 100644 gcc/tree-chrec.c create mode 100644 gcc/tree-chrec.h diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 86bb7fa2883..1a1f1f3cc06 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2004-06-30 Sebastian Pop + + * Makefile.in (OBJS-common): Add tree-chrec.o. + (tree-chrec.o): New rule. + (GTFILES): Add tree-chrec.h. + * gengtype.c (open_base_files): Add tree-chrec.h. + * tree-chrec.c: New file. + * tree-chrec.h: New file. + * tree.def (SCEV_KNOWN, SCEV_NOT_KNOWN, POLYNOMIAL_CHREC): New nodes. + 2004-06-30 Roger Sayle * combine.c: Include "output.h" to define dump_file. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 35dcb4fed5f..183d63332ec 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -885,6 +885,7 @@ C_OBJS = c-parse.o c-lang.o stub-objc.o $(C_AND_OBJC_OBJS) # Language-independent object files. OBJS-common = \ + tree-chrec.o \ tree-cfg.o tree-dfa.o tree-eh.o tree-ssa.o tree-optimize.o tree-gimple.o \ tree-alias-type.o gimplify.o tree-pretty-print.o tree-into-ssa.o \ tree-outof-ssa.o tree-alias-common.o tree-ssa-ccp.o tree-vn.o \ @@ -1699,6 +1700,8 @@ gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \ tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \ $(TREE_H) errors.h tree-inline.h diagnostic.h $(HASHTAB_H) \ $(TM_H) coretypes.h +tree-chrec.o: tree-chrec.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ + errors.h $(GGC_H) $(TREE_H) tree-chrec.h tree-pass.h tree-gimple.o : tree-gimple.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(EXPR_H) \ $(RTL_H) $(TREE_GIMPLE_H) $(TM_H) coretypes.h bitmap.h $(GGC_H) tree-mudflap.o : $(CONFIG_H) errors.h $(SYSTEM_H) $(TREE_H) tree-inline.h \ @@ -2339,6 +2342,7 @@ GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \ $(srcdir)/tree-iterator.c $(srcdir)/gimplify.c \ $(srcdir)/tree-alias-type.h $(srcdir)/tree-alias-common.h \ $(srcdir)/tree-alias-type.c $(srcdir)/tree-alias-common.c \ + $(srcdir)/tree-chrec.h \ $(srcdir)/tree-ssa-operands.h $(srcdir)/tree-ssa-operands.c \ $(srcdir)/tree-profile.c $(srcdir)/rtl-profile.c $(srcdir)/tree-nested.c \ $(out_file) \ diff --git a/gcc/gengtype.c b/gcc/gengtype.c index 5d7082437b0..85e856f89fd 100644 --- a/gcc/gengtype.c +++ b/gcc/gengtype.c @@ -1110,6 +1110,7 @@ open_base_files (void) "libfuncs.h", "debug.h", "ggc.h", "cgraph.h", "tree-alias-type.h", "tree-flow.h", "reload.h", "cpp-id-data.h", + "tree-chrec.h", NULL }; const char *const *ifp; diff --git a/gcc/tree-chrec.c b/gcc/tree-chrec.c new file mode 100644 index 00000000000..9146ec36b36 --- /dev/null +++ b/gcc/tree-chrec.c @@ -0,0 +1,1019 @@ +/* Chains of recurrences. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Contributed by Sebastian Pop + +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-chrec.h" +#include "tree-pass.h" + + +/* This part will be removed once the merging is finished. */ + + + +/* The following trees are unique elements. Thus the comparison of + another element to these elements should be done on the pointer to + these trees, and not on their value. */ + +/* The SSA_NAMEs that are not yet analyzed are qualified with NULL_TREE. */ +tree chrec_not_analyzed_yet; + +/* Reserved to the cases where the analyzer has detected an + undecidable property at compile time. */ +tree chrec_dont_know; + +/* When the analyzer has detected that a property will never + happen, then it qualifies it with chrec_known. */ +tree chrec_known; + +/* Empty hook. Will be replaced by the main function from + tree-scalar-evolution.c. */ + +tree +count_ev_in_wider_type (tree foo ATTRIBUTE_UNUSED, + tree bar ATTRIBUTE_UNUSED) +{ + return NULL_TREE; +} + +/* Empty hook. Will be replaced by the main function from + tree-scalar-evolution.c. */ + +bool +chrec_contains_symbols_defined_in_loop (tree chrec ATTRIBUTE_UNUSED, + unsigned loop_nb ATTRIBUTE_UNUSED) +{ + return true; +} + + + + +/* 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); +} + +/* 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_dont_know; + } +} + +/* 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 (type, CHREC_RIGHT (poly1), + convert (type, 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 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)))); +} + +/* When the operands are automatically_generated_chrec_p, the fold has + to respect the semantics of the operands. */ + +static inline tree +chrec_fold_automatically_generated_operands (tree op0, + tree op1) +{ + if (op0 == chrec_dont_know + || op1 == chrec_dont_know) + return chrec_dont_know; + + if (op0 == chrec_known + || op1 == chrec_known) + return chrec_known; + + 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_dont_know; +} + +/* Fold the addition of two chrecs. */ + +static tree +chrec_fold_plus_1 (enum tree_code code, + 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_plus_poly_poly (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)); + } + + 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))); + + 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)) + return op1; + if (integer_zerop (op1)) + return op0; + + return chrec_fold_plus_1 (PLUS_EXPR, type, op0, op1); +} + +/* Fold the subtraction of two chrecs. */ + +tree +chrec_fold_minus (tree type, + tree op0, + tree op1) +{ + if (integer_zerop (op1)) + return op0; + + return chrec_fold_plus_1 (MINUS_EXPR, type, op0, op1); +} + +/* 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); + + default: + if (integer_onep (op1)) + return op0; + if (integer_zerop (op1)) + return convert (type, 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)); + } + + default: + if (integer_onep (op0)) + return op1; + + if (integer_zerop (op0)) + return convert (type, 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)); + + default: + if (integer_onep (op1)) + return op0; + if (integer_zerop (op1)) + return convert (type, integer_zero_node); + return fold (build (MULT_EXPR, type, op0, op1)); + } + } +} + + + +/* Operations. */ + +/* The factorial. */ + +static tree +tree_fold_factorial (tree f) +{ + if (tree_int_cst_sgn (f) <= 0) + return integer_one_node; + else + return fold + (build (MULT_EXPR, integer_type_node, f, + tree_fold_factorial (fold (build (MINUS_EXPR, integer_type_node, + f, integer_one_node))))); +} + +/* The binomial coefficient. */ + +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))))))); +} + +/* 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 type = chrec_type (chrec); + tree binomial_n_k = tree_fold_binomial (n, k); + + 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 + (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)); + } + else + return fold (build (MULT_EXPR, type, binomial_n_k, chrec)); +} + +/* Evaluates "CHREC (X)" when the varying variable is VAR. + Example: Given the following parameters, + + var = 1 + chrec = {3, +, 4}_1 + x = 10 + + The result is given by the Newton's interpolating formula: + 3 * \binom{10}{0} + 4 * \binom{10}{1}. +*/ + +tree +chrec_apply (unsigned var, + tree chrec, + tree x) +{ + tree type = chrec_type (chrec); + tree res = chrec_dont_know; + + if (automatically_generated_chrec_p (chrec) + || automatically_generated_chrec_p (x) + + /* When the symbols are defined in an outer loop, it is possible + to symbolically compute the apply, since the symbols are + constants with respect to the varying loop. */ + || chrec_contains_symbols_defined_in_loop (chrec, var) + || chrec_contains_symbols (x)) + return chrec_dont_know; + + 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 (type, CHREC_RIGHT (chrec), x); + + else + res = chrec_fold_plus (type, CHREC_LEFT (chrec), + chrec_fold_multiply (type, + CHREC_RIGHT (chrec), x)); + } + + else if (TREE_CODE (chrec) != POLYNOMIAL_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_dont_know; + + 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)); + + 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) + return initial_condition (CHREC_LEFT (chrec)); + else + 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); + + 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); + + 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_dont_know, 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 + && 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 + && CHREC_VARIABLE (chrec) == loop_num) + chrec = CHREC_LEFT (chrec); + + return build_polynomial_chrec (loop_num, chrec, new_evol); +} + +/* 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_dont_know + || chrec2 == chrec_dont_know) + return chrec_dont_know; + + if (chrec1 == chrec_known + || chrec2 == chrec_known) + return chrec_known; + + 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; + + return chrec_dont_know; +} + + + +/* 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) + { + 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) + return (is_multivariate_chrec_rec (CHREC_LEFT (chrec), + CHREC_VARIABLE (chrec)) + || is_multivariate_chrec_rec (CHREC_RIGHT (chrec), + CHREC_VARIABLE (chrec))); + else + return false; +} + +/* 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_dont_know + || 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 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 (TREE_CODE (CHREC_RIGHT (chrec)) == POLYNOMIAL_CHREC + && 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)) + && TREE_CODE (CHREC_LEFT (chrec)) == POLYNOMIAL_CHREC + && CHREC_VARIABLE (CHREC_LEFT (chrec)) != CHREC_VARIABLE (chrec) + && evolution_function_is_affine_multivariate_p + (CHREC_LEFT (chrec))) + return true; + else + return false; + } + + 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: + switch (TREE_CODE (CHREC_LEFT (chrec))) + { + case POLYNOMIAL_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: + 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 count_ev_in_wider_type (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))); + + default: + { + tree res = convert (type, chrec); + + /* Don't propagate overflows. */ + TREE_OVERFLOW (res) = 0; + if (TREE_CODE_CLASS (TREE_CODE (res)) == 'c') + TREE_CONSTANT_OVERFLOW (res) = 0; + return res; + } + } +} + +/* Returns the type of the chrec. */ + +tree +chrec_type (tree chrec) +{ + if (automatically_generated_chrec_p (chrec)) + return NULL_TREE; + + return TREE_TYPE (chrec); +} + +extern void initialize_scalar_evolutions_analyzer (void); + +/* Initializer. */ + +void +initialize_scalar_evolutions_analyzer (void) +{ + /* The elements below are unique. */ + if (chrec_dont_know == NULL_TREE) + { + chrec_not_analyzed_yet = NULL_TREE; + chrec_dont_know = make_node (SCEV_NOT_KNOWN); + chrec_known = make_node (SCEV_KNOWN); + TREE_TYPE (chrec_dont_know) = NULL_TREE; + TREE_TYPE (chrec_known) = NULL_TREE; + } +} diff --git a/gcc/tree-chrec.h b/gcc/tree-chrec.h new file mode 100644 index 00000000000..8e355f0ac35 --- /dev/null +++ b/gcc/tree-chrec.h @@ -0,0 +1,206 @@ +/* Chains of recurrences. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + Contributed by Sebastian Pop + +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. */ + +#ifndef GCC_TREE_CHREC_H +#define GCC_TREE_CHREC_H + +/* Accessors for the chains of recurrences. */ +#define CHREC_VAR(NODE) TREE_OPERAND (NODE, 0) +#define CHREC_LEFT(NODE) TREE_OPERAND (NODE, 1) +#define CHREC_RIGHT(NODE) TREE_OPERAND (NODE, 2) +#define CHREC_VARIABLE(NODE) TREE_INT_CST_LOW (CHREC_VAR (NODE)) + + + +/* The following trees are unique elements. Thus the comparison of another + element to these elements should be done on the pointer to these trees, + and not on their value. */ + +extern tree chrec_not_analyzed_yet; +extern GTY(()) tree chrec_dont_know; +extern GTY(()) tree chrec_known; + +/* After having added an automatically generated element, please + include it in the following function. */ + +static inline bool +automatically_generated_chrec_p (tree chrec) +{ + return (chrec == chrec_not_analyzed_yet + || chrec == chrec_dont_know + || chrec == chrec_known); +} + +/* The tree nodes aka. CHRECs. */ + +static inline bool +tree_is_chrec (tree expr) +{ + if (TREE_CODE (expr) == POLYNOMIAL_CHREC + || automatically_generated_chrec_p (expr)) + return true; + else + return false; +} + + + +/* Chrec folding functions. */ +extern tree chrec_fold_plus (tree, tree, tree); +extern tree chrec_fold_minus (tree, tree, tree); +extern tree chrec_fold_multiply (tree, tree, tree); +extern tree chrec_convert (tree, tree); +extern tree count_ev_in_wider_type (tree, tree); +extern tree chrec_type (tree); + +/* Operations. */ +extern tree chrec_apply (unsigned, tree, tree); +extern tree chrec_replace_initial_condition (tree, tree); +extern tree update_initial_condition_to_origin (tree); +extern tree initial_condition (tree); +extern tree evolution_part_in_loop_num (tree, unsigned); +extern tree hide_evolution_in_other_loops_than_loop (tree, unsigned); +extern tree reset_evolution_in_loop (unsigned, tree, tree); +extern tree chrec_merge (tree, tree); + +/* Observers. */ +extern bool is_multivariate_chrec (tree); +extern bool chrec_is_positive (tree, bool *); +extern bool chrec_contains_symbols (tree); +extern bool chrec_contains_symbols_defined_in_loop (tree, unsigned); +extern bool chrec_contains_undetermined (tree); +extern bool tree_contains_chrecs (tree); +extern bool evolution_function_is_affine_multivariate_p (tree); +extern bool evolution_function_is_univariate_p (tree); + + + +/* Build a polynomial chain of recurrence. */ + +static inline tree +build_polynomial_chrec (unsigned loop_num, + tree left, + tree right) +{ + if (left == chrec_dont_know + || right == chrec_dont_know) + return chrec_dont_know; + + return build (POLYNOMIAL_CHREC, TREE_TYPE (left), + build_int_2 (loop_num, 0), left, right); +} + + + +/* Observers. */ + +/* Determines whether CHREC is equal to zero. */ + +static inline bool +chrec_zerop (tree chrec) +{ + if (chrec == NULL_TREE) + return false; + + if (TREE_CODE (chrec) == INTEGER_CST) + return integer_zerop (chrec); + + return false; +} + +/* Determines whether the expression CHREC is a constant. */ + +static inline bool +evolution_function_is_constant_p (tree chrec) +{ + if (chrec == NULL_TREE) + return false; + + switch (TREE_CODE (chrec)) + { + case INTEGER_CST: + case REAL_CST: + return true; + + default: + return false; + } +} + +/* Determine whether the given tree is an affine evolution function or not. */ + +static inline bool +evolution_function_is_affine_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)) + && evolution_function_is_constant_p (CHREC_RIGHT (chrec))) + return true; + else + return false; + + default: + return false; + } +} + +/* Determine whether the given tree is an affine or constant evolution + function. */ + +static inline bool +evolution_function_is_affine_or_constant_p (tree chrec) +{ + return evolution_function_is_affine_p (chrec) + || evolution_function_is_constant_p (chrec); +} + +/* Determines whether EXPR does not contains chrec expressions. */ + +static inline bool +tree_does_not_contain_chrecs (tree expr) +{ + return !tree_contains_chrecs (expr); +} + +/* Determines whether CHREC is a loop invariant with respect to LOOP_NUM. + Set the result in RES and return true when the property can be computed. */ + +static inline bool +no_evolution_in_loop_p (tree chrec, unsigned loop_num, bool *res) +{ + tree scev; + + if (chrec == chrec_not_analyzed_yet + || chrec == chrec_dont_know + || chrec_contains_symbols_defined_in_loop (chrec, loop_num)) + return false; + + scev = hide_evolution_in_other_loops_than_loop (chrec, loop_num); + *res = !tree_is_chrec (scev); + return true; +} + +#endif /* GCC_TREE_CHREC_H */ diff --git a/gcc/tree.def b/gcc/tree.def index d1268953690..15172077bdc 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -898,6 +898,18 @@ DEFTREECODE (CATCH_EXPR, "catch_expr", 's', 2) expanding. */ DEFTREECODE (EH_FILTER_EXPR, "eh_filter_expr", 's', 2) +/* Node used for describing a property that is known at compile + time. */ +DEFTREECODE (SCEV_KNOWN, "scev_known", 'e', 0) + +/* Node used for describing a property that is not known at compile + time. */ +DEFTREECODE (SCEV_NOT_KNOWN, "scev_not_known", 'e', 0) + +/* Polynomial chains of recurrences. + Under the form: cr = {CHREC_LEFT (cr), +, CHREC_RIGHT (cr)}. */ +DEFTREECODE (POLYNOMIAL_CHREC, "polynomial_chrec", 'e', 3) + /* Used to chain children of container statements together. Use the interface in tree-iterator.h to access this node. */ DEFTREECODE (STATEMENT_LIST, "statement_list", 'x', 0)