aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-data-ref.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-data-ref.c')
-rw-r--r--gcc/tree-data-ref.c1760
1 files changed, 1760 insertions, 0 deletions
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
new file mode 100644
index 00000000000..deae8f6d223
--- /dev/null
+++ b/gcc/tree-data-ref.c
@@ -0,0 +1,1760 @@
+/* Data references and dependences detectors.
+ 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 pass walks the whole program searching for array references.
+ The array accesses are recorded in DATA_REFERENCE nodes. Since the
+ information in the DATA_REFERENCE nodes is too precise, the
+ dependence testers abstract this information into classic
+ representations: distance vectors, direction vectors, affine
+ dependence functions, ... Both the precise and more abstract
+ informations are then exposed to the other passes.
+
+ The basic test for determining the dependences is:
+ given two access functions chrec1 and chrec2 to a same array, and
+ x and y two vectors from the iteration domain, the same element of
+ the array is accessed twice at iterations x and y if and only if:
+ | chrec1 (x) == chrec2 (y).
+
+ The goals of this analysis are:
+
+ - to determine the independence: the relation between two
+ independent accesses is qualified with the chrec_bot (this
+ information allows a loop parallelization),
+
+ - when two data references access the same data, to qualify the
+ dependence relation with classic dependence representations:
+
+ - distance vectors
+ - direction vectors
+ - loop carried level dependence
+ - polyhedron dependence
+ or with the chains of recurrences based representation,
+
+
+ - to define a knowledge base for storing the data dependeces
+ information,
+
+ - to define an interface to access this data.
+
+
+ Definitions:
+
+ - What is a subscript? Given two array accesses a subscript is the
+ tuple composed of the access functions for a given dimension.
+ Example: Given A[f1][f2][f3] and B[g1][g2][g3], there are three
+ subscripts: (f1, g1), (f2, g2), (f3, g3).
+
+ - Vertical and horizontal couplings. In some of the comments of
+ this analysis, I refer to the overlapping elements of a subscript
+ as the vertical coupling, in opposition to the horizontal coupling
+ that refers to the coupling between subscripts.
+
+ References:
+
+ - "Advanced Compilation for High Performance Computing" by Randy Allen
+ and Ken Kennedy.
+
+ - "Loop Transformations for Restructuring Compilers - The Foundations"
+ by Utpal Banerjee.
+
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "errors.h"
+#include "ggc.h"
+#include "tree.h"
+
+/* These RTL headers are needed for basic-block.h. */
+#include "rtl.h"
+#include "basic-block.h"
+#include "diagnostic.h"
+#include "tree-flow.h"
+#include "tree-dump.h"
+#include "timevar.h"
+#include "cfgloop.h"
+#include "tree-fold-const.h"
+#include "tree-chrec.h"
+#include "tree-data-ref.h"
+#include "tree-scalar-evolution.h"
+#include "tree-pass.h"
+#include "lambda.h"
+
+static void subscript_dependence_tester (struct data_dependence_relation *);
+
+static unsigned int data_ref_id = 0;
+
+
+
+/* Dump into FILE all the data references from DATAREFS. */
+
+void
+dump_data_references (FILE *file,
+ varray_type datarefs)
+{
+ unsigned int i;
+
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++)
+ dump_data_reference (file, VARRAY_GENERIC_PTR (datarefs, i));
+}
+
+/* Dump into FILE all the dependence relations from DDR. */
+
+void
+dump_data_dependence_relations (FILE *file,
+ varray_type ddr)
+{
+ unsigned int i;
+
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (ddr); i++)
+ dump_data_dependence_relation (file, VARRAY_GENERIC_PTR (ddr, i));
+}
+
+/* Dump function for a DATA_REFERENCE structure. */
+
+void
+dump_data_reference (FILE *outf,
+ struct data_reference *dr)
+{
+ unsigned int i;
+
+ fprintf (outf, "(Data Ref %d: \n stmt: ", DR_ID (dr));
+ print_generic_stmt (outf, DR_STMT (dr), 0);
+ fprintf (outf, " ref: ");
+ print_generic_stmt (outf, DR_REF (dr), 0);
+ fprintf (outf, " base_name: ");
+ print_generic_stmt (outf, DR_BASE_NAME (dr), 0);
+
+ for (i = 0; i < DR_NUM_DIMENSIONS (dr); i++)
+ {
+ fprintf (outf, " Access function %d: ", i);
+ print_generic_stmt (outf, DR_ACCESS_FN (dr, i), 0);
+ }
+ fprintf (outf, ")\n");
+}
+
+/* Dump function for a DATA_DEPENDENCE_RELATION structure. */
+
+void
+dump_data_dependence_relation (FILE *outf,
+ struct data_dependence_relation *ddr)
+{
+ unsigned int i;
+ struct data_reference *dra, *drb;
+
+ dra = DDR_A (ddr);
+ drb = DDR_B (ddr);
+
+ fprintf (outf, "\n(Data Dep (A = %d, B = %d):", DR_ID (dra), DR_ID (drb));
+
+ if (DDR_ARE_DEPENDENT (ddr) == chrec_top)
+ fprintf (outf, " (don't know)\n");
+
+ else if (DDR_ARE_DEPENDENT (ddr) == chrec_bot)
+ fprintf (outf, " (no dependence)\n");
+
+ else
+ {
+ for (i = 0; i < DDR_NUM_SUBSCRIPTS (ddr); i++)
+ {
+ tree chrec;
+ struct subscript *subscript = DDR_SUBSCRIPT (ddr, i);
+
+ fprintf (outf, "\n (subscript %d:\n", i);
+ fprintf (outf, " access_fn_A: ");
+ print_generic_stmt (outf, DR_ACCESS_FN (dra, i), 0);
+ fprintf (outf, " access_fn_B: ");
+ print_generic_stmt (outf, DR_ACCESS_FN (drb, i), 0);
+
+ chrec = SUB_CONFLICTS_IN_A (subscript);
+ fprintf (outf, " iterations_that_access_an_element_twice_in_A: ");
+ print_generic_stmt (outf, chrec, 0);
+ if (chrec == chrec_bot)
+ fprintf (outf, " (no dependence)\n");
+ else if (chrec == chrec_top)
+ fprintf (outf, " (don't know)\n");
+ else
+ {
+ tree last_iteration = SUB_LAST_CONFLICT_IN_A (subscript);
+ fprintf (outf, " last_iteration_that_access_an_element_twice_in_A: ");
+ print_generic_stmt (outf, last_iteration, 0);
+ }
+
+ chrec = SUB_CONFLICTS_IN_B (subscript);
+ fprintf (outf, " iterations_that_access_an_element_twice_in_B: ");
+ print_generic_stmt (outf, chrec, 0);
+ if (chrec == chrec_bot)
+ fprintf (outf, " (no dependence)\n");
+ else if (chrec == chrec_top)
+ fprintf (outf, " (don't know)\n");
+ else
+ {
+ tree last_iteration = SUB_LAST_CONFLICT_IN_B (subscript);
+ fprintf (outf, " last_iteration_that_access_an_element_twice_in_B: ");
+ print_generic_stmt (outf, last_iteration, 0);
+ }
+
+ fprintf (outf, " )\n");
+ }
+
+ fprintf (outf, " (Distance Vector: \n");
+ for (i = 0; i < DDR_NUM_SUBSCRIPTS (ddr); i++)
+ {
+ struct subscript *subscript = DDR_SUBSCRIPT (ddr, i);
+
+ fprintf (outf, "(");
+ print_generic_stmt (outf, SUB_DISTANCE (subscript), 0);
+ fprintf (outf, ")\n");
+ }
+ fprintf (outf, " )\n");
+
+ fprintf (outf, " (Direction Vector: \n");
+ for (i = 0; i < DDR_NUM_SUBSCRIPTS (ddr); i++)
+ {
+ struct subscript *subscript = DDR_SUBSCRIPT (ddr, i);
+
+ fprintf (outf, "(");
+ dump_data_dependence_direction (outf, SUB_DIRECTION (subscript));
+ fprintf (outf, ")\n");
+ }
+ fprintf (outf, " )\n");
+ }
+
+ fprintf (outf, "\n)");
+}
+
+
+
+/* Dump function for a DATA_DEPENDENCE_DIRECTION structure. */
+
+void
+dump_data_dependence_direction (FILE *file,
+ enum data_dependence_direction dir)
+{
+ switch (dir)
+ {
+ case dir_positive:
+ fprintf (file, "+");
+ break;
+
+ case dir_negative:
+ fprintf (file, "-");
+ break;
+
+ case dir_equal:
+ fprintf (file, "=");
+ break;
+
+ case dir_positive_or_negative:
+ fprintf (file, "+-");
+ break;
+
+ case dir_positive_or_equal:
+ fprintf (file, "+=");
+ break;
+
+ case dir_negative_or_equal:
+ fprintf (file, "-=");
+ break;
+
+ case dir_star:
+ fprintf (file, "*");
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+
+/* Given an ARRAY_REF node REF, records its access functions.
+ Example: given A[i][3], record the opnd1 function, ie. the constant
+ "3", then recursively call the function on opnd0, ie. the ARRAY_REF
+ "A[i]". The function returns the base name: "A". */
+
+static tree
+analyze_array_indexes (struct loop *loop,
+ varray_type access_fns,
+ tree ref)
+{
+ tree opnd0, opnd1;
+ tree access_fn;
+
+ opnd0 = TREE_OPERAND (ref, 0);
+ opnd1 = TREE_OPERAND (ref, 1);
+
+ /* The detection of the evolution function for this data access is
+ postponed until the dependence test. This lazy strategy avoids
+ the computation of access functions that are of no interest for
+ the optimizers. */
+ access_fn = instantiate_parameters
+ (loop, analyze_scalar_evolution (loop, opnd1));
+
+ VARRAY_PUSH_TREE (access_fns, access_fn);
+
+ /* Recursively record other array access functions. */
+ if (TREE_CODE (opnd0) == ARRAY_REF)
+ return analyze_array_indexes (loop, access_fns, opnd0);
+
+ /* Return the base name of the data access. */
+ else
+ return opnd0;
+}
+
+/* For a data reference REF contained in the statemet STMT, initialize
+ a DATA_REFERENCE structure, and return it. */
+
+struct data_reference *
+analyze_array (tree stmt,
+ tree ref)
+{
+ struct data_reference *res;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "(analyze_array \n");
+ fprintf (dump_file, " (ref = ");
+ print_generic_stmt (dump_file, ref, 0);
+ fprintf (dump_file, ")\n");
+ }
+
+ res = ggc_alloc (sizeof (struct data_reference));
+
+ DR_ID (res) = data_ref_id++;
+ DR_STMT (res) = stmt;
+ DR_REF (res) = ref;
+ VARRAY_TREE_INIT (DR_ACCESS_FNS (res), 5, "access_fns");
+ DR_BASE_NAME (res) = analyze_array_indexes
+ (loop_of_stmt (stmt), DR_ACCESS_FNS (res), ref);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, ")\n");
+
+ return res;
+}
+
+
+
+/* When there exists a dependence relation, determine its distance
+ vector. */
+
+static void
+compute_distance_vector (struct data_dependence_relation *ddr)
+{
+ if (DDR_ARE_DEPENDENT (ddr) == NULL_TREE)
+ {
+ unsigned int i;
+
+ for (i = 0; i < DDR_NUM_SUBSCRIPTS (ddr); i++)
+ {
+ tree conflicts_a, conflicts_b, difference;
+ struct subscript *subscript;
+
+ subscript = DDR_SUBSCRIPT (ddr, i);
+ conflicts_a = SUB_CONFLICTS_IN_A (subscript);
+ conflicts_b = SUB_CONFLICTS_IN_B (subscript);
+ difference = chrec_fold_minus
+ (integer_type_node, conflicts_b, conflicts_a);
+
+ if (evolution_function_is_constant_p (difference))
+ SUB_DISTANCE (subscript) = difference;
+
+ else
+ SUB_DISTANCE (subscript) = chrec_top;
+ }
+ }
+}
+
+/* When there exists a dependence relation, determine its direction
+ vector. */
+
+static void
+compute_direction_vector (struct data_dependence_relation *ddr)
+{
+ if (DDR_ARE_DEPENDENT (ddr) == NULL_TREE)
+ {
+ unsigned int i;
+
+ for (i = 0; i < DDR_NUM_SUBSCRIPTS (ddr); i++)
+ {
+ tree distance;
+ struct subscript *subscript;
+ bool value;
+
+ subscript = DDR_SUBSCRIPT (ddr, i);
+ distance = SUB_DISTANCE (subscript);
+
+ if (distance == chrec_top)
+ SUB_DIRECTION (subscript) = dir_star;
+
+ else if (chrec_zerop (distance))
+ SUB_DIRECTION (subscript) = dir_equal;
+
+ else if (!chrec_is_positive (distance, &value))
+ SUB_DIRECTION (subscript) = dir_star;
+
+ else if (value == true)
+ SUB_DIRECTION (subscript) = dir_positive;
+
+ else
+ SUB_DIRECTION (subscript) = dir_negative;
+ }
+ }
+}
+
+/* Initialize a ddr. */
+
+static struct data_dependence_relation *
+initialize_data_dependence_relation (struct data_reference *a,
+ struct data_reference *b)
+{
+ struct data_dependence_relation *res;
+
+ res = ggc_alloc (sizeof (struct data_dependence_relation));
+ DDR_A (res) = a;
+ DDR_B (res) = b;
+
+ /* When the dimensions of A and B differ, we directly initialize
+ the relation to "there is no dependence": chrec_bot. */
+ if (DR_NUM_DIMENSIONS (a) != DR_NUM_DIMENSIONS (b)
+ || array_base_name_differ_p (a, b))
+ DDR_ARE_DEPENDENT (res) = chrec_bot;
+
+ else
+ {
+ unsigned int i;
+ DDR_ARE_DEPENDENT (res) = NULL_TREE;
+ DDR_SUBSCRIPTS_VECTOR_INIT (res, DR_NUM_DIMENSIONS (a));
+
+ for (i = 0; i < DR_NUM_DIMENSIONS (a); i++)
+ {
+ struct subscript *subscript;
+
+ subscript = ggc_alloc (sizeof (struct subscript));
+ SUB_CONFLICTS_IN_A (subscript) = chrec_top;
+ SUB_CONFLICTS_IN_B (subscript) = chrec_top;
+ SUB_LAST_CONFLICT_IN_A (subscript) = chrec_top;
+ SUB_LAST_CONFLICT_IN_B (subscript) = chrec_top;
+ SUB_DISTANCE (subscript) = chrec_top;
+ SUB_DIRECTION (subscript) = dir_star;
+ VARRAY_PUSH_GENERIC_PTR (DDR_SUBSCRIPTS (res), subscript);
+ }
+ }
+
+ return res;
+}
+
+
+
+/* This section contains the classic Banerjee. The functions are
+ represented by chains of recurrences. */
+
+/* This is the ZIV test. ZIV = Zero Index Variable, ie. both
+ functions do not depend on the iterations of a loop. */
+
+static inline bool
+ziv_subscript_p (tree chrec_a,
+ tree chrec_b)
+{
+ return (evolution_function_is_constant_p (chrec_a)
+ && evolution_function_is_constant_p (chrec_b));
+}
+
+/* Determines whether the subscript depends on the evolution of a
+ single loop or not. SIV = Single Index Variable. */
+
+static bool
+siv_subscript_p (tree chrec_a,
+ tree chrec_b)
+{
+ if ((evolution_function_is_constant_p (chrec_a)
+ && evolution_function_is_univariate_p (chrec_b))
+ || (evolution_function_is_constant_p (chrec_b)
+ && evolution_function_is_univariate_p (chrec_a)))
+ return true;
+
+ if (evolution_function_is_univariate_p (chrec_a)
+ && evolution_function_is_univariate_p (chrec_b))
+ {
+ switch (TREE_CODE (chrec_a))
+ {
+ case POLYNOMIAL_CHREC:
+ case EXPONENTIAL_CHREC:
+ switch (TREE_CODE (chrec_b))
+ {
+ case POLYNOMIAL_CHREC:
+ case EXPONENTIAL_CHREC:
+ if (CHREC_VARIABLE (chrec_a) != CHREC_VARIABLE (chrec_b))
+ return false;
+
+ default:
+ return true;
+ }
+
+ default:
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* Analyze a ZIV (Zero Index Variable) subscript. */
+
+static void
+analyze_ziv_subscript (tree chrec_a,
+ tree chrec_b,
+ tree *overlaps_a,
+ tree *overlaps_b)
+{
+ tree difference;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "(analyze_ziv_subscript \n");
+
+ difference = chrec_fold_minus (integer_type_node, chrec_a, chrec_b);
+
+ switch (TREE_CODE (difference))
+ {
+ case INTEGER_CST:
+ if (integer_zerop (difference))
+ {
+ /* The difference is equal to zero: the accessed index
+ overlaps for each iteration in the loop. */
+ *overlaps_a = integer_zero_node;
+ *overlaps_b = integer_zero_node;
+ }
+ else
+ {
+ /* The accesses do not overlap. */
+ *overlaps_a = chrec_bot;
+ *overlaps_b = chrec_bot;
+ }
+ break;
+
+ case INTERVAL_CHREC:
+ if (integer_zerop (CHREC_LOW (difference))
+ && integer_zerop (CHREC_UP (difference)))
+ {
+ /* The difference is equal to zero: the accessed index
+ overlaps for each iteration in the loop. */
+ *overlaps_a = integer_zero_node;
+ *overlaps_b = integer_zero_node;
+ }
+ else
+ {
+ /* There could be an overlap, conservative answer:
+ "don't know". */
+ *overlaps_a = chrec_top;
+ *overlaps_b = chrec_top;
+ }
+ break;
+
+ default:
+ /* We're not sure whether the indexes overlap. For the moment,
+ conservatively answer "don't know". */
+ *overlaps_a = chrec_top;
+ *overlaps_b = chrec_top;
+ break;
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, ")\n");
+}
+
+/* This is a part of the SIV subscript analyzer (Single Index
+ Variable). */
+
+static void
+analyze_siv_subscript_cst_affine (tree chrec_a,
+ tree chrec_b,
+ tree *overlaps_a,
+ tree *overlaps_b)
+{
+ bool value0, value1, value2;
+ tree difference = chrec_fold_minus
+ (integer_type_node, CHREC_LEFT (chrec_b), chrec_a);
+
+ if (!chrec_is_positive (initial_condition (difference), &value0))
+ {
+ *overlaps_a = chrec_top;
+ *overlaps_b = chrec_top;
+ return;
+ }
+ else
+ {
+ if (value0 == false)
+ {
+ if (!chrec_is_positive (CHREC_RIGHT (chrec_b), &value1))
+ {
+ *overlaps_a = chrec_top;
+ *overlaps_b = chrec_top;
+ return;
+ }
+ else
+ {
+ if (value1 == true)
+ {
+ /* Example:
+ chrec_a = 12
+ chrec_b = {10, +, 1}
+ */
+
+ if (tree_fold_divides_p
+ (integer_type_node, CHREC_RIGHT (chrec_b), difference))
+ {
+ *overlaps_a = integer_zero_node;
+ *overlaps_b = tree_fold_exact_div
+ (integer_type_node,
+ tree_fold_abs (integer_type_node, difference),
+ CHREC_RIGHT (chrec_b));
+ return;
+ }
+
+ /* When the step does not divides the difference, there are
+ no overlaps. */
+ else
+ {
+ *overlaps_a = chrec_bot;
+ *overlaps_b = chrec_bot;
+ return;
+ }
+ }
+
+ else
+ {
+ /* Example:
+ chrec_a = 12
+ chrec_b = {10, +, -1}
+
+ In this case, chrec_a will not overlap with chrec_b. */
+ *overlaps_a = chrec_bot;
+ *overlaps_b = chrec_bot;
+ return;
+ }
+ }
+ }
+ else
+ {
+ if (!chrec_is_positive (CHREC_RIGHT (chrec_b), &value2))
+ {
+ *overlaps_a = chrec_top;
+ *overlaps_b = chrec_top;
+ return;
+ }
+ else
+ {
+ if (value2 == false)
+ {
+ /* Example:
+ chrec_a = 3
+ chrec_b = {10, +, -1}
+ */
+ if (tree_fold_divides_p
+ (integer_type_node, CHREC_RIGHT (chrec_b), difference))
+ {
+ *overlaps_a = integer_zero_node;
+ *overlaps_b = tree_fold_exact_div
+ (integer_type_node, difference, CHREC_RIGHT (chrec_b));
+ return;
+ }
+
+ /* When the step does not divides the difference, there
+ are no overlaps. */
+ else
+ {
+ *overlaps_a = chrec_bot;
+ *overlaps_b = chrec_bot;
+ return;
+ }
+ }
+ else
+ {
+ /* Example:
+ chrec_a = 3
+ chrec_b = {4, +, 1}
+
+ In this case, chrec_a will not overlap with chrec_b. */
+ *overlaps_a = chrec_bot;
+ *overlaps_b = chrec_bot;
+ return;
+ }
+ }
+ }
+ }
+}
+
+/* This is a part of the SIV subscript analyzer (Single Index
+ Variable). */
+
+static void
+analyze_siv_subscript_affine_cst (tree chrec_a,
+ tree chrec_b,
+ tree *overlaps_a,
+ tree *overlaps_b)
+{
+ analyze_siv_subscript_cst_affine (chrec_b, chrec_a, overlaps_b, overlaps_a);
+}
+
+/* This is a part of the SIV subscript analyzer (Single Index
+ Variable). */
+
+static void
+analyze_siv_subscript_affine_affine (tree chrec_a,
+ tree chrec_b,
+ tree *overlaps_a,
+ tree *overlaps_b)
+{
+ tree left_a, left_b, right_a, right_b;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "(analyze_siv_subscript_affine_affine \n");
+
+ /* For determining the initial intersection, we have to solve a
+ Diophantine equation. This is the most time consuming part.
+
+ For answering to the question: "Is there a dependence?" we have
+ to prove that there exists a solution to the Diophantine
+ equation, and that the solution is in the iteration domain,
+ ie. the solution is positive or zero, and that the solution
+ happens before the upper bound loop.nb_iterations. Otherwise
+ there is no dependence. This function outputs a description of
+ the iterations that hold the intersections. */
+
+ left_a = CHREC_LEFT (chrec_a);
+ left_b = CHREC_LEFT (chrec_b);
+ right_a = CHREC_RIGHT (chrec_a);
+ right_b = CHREC_RIGHT (chrec_b);
+
+ if (chrec_zerop (chrec_fold_minus (integer_type_node, left_a, left_b)))
+ {
+ /* The first element accessed twice is on the first
+ iteration. */
+ *overlaps_a = build_polynomial_chrec
+ (CHREC_VARIABLE (chrec_a),
+ integer_zero_node, integer_one_node);
+ *overlaps_b = build_polynomial_chrec
+ (CHREC_VARIABLE (chrec_b),
+ integer_zero_node, integer_one_node);
+ }
+
+ else if (TREE_CODE (left_a) == INTEGER_CST
+ && TREE_CODE (left_b) == INTEGER_CST
+ && TREE_CODE (right_a) == INTEGER_CST
+ && TREE_CODE (right_b) == INTEGER_CST
+
+ /* Both functions should have the same evolution sign. */
+ && ((tree_int_cst_sgn (right_a) > 0
+ && tree_int_cst_sgn (right_b) > 0)
+ || (tree_int_cst_sgn (right_a) < 0
+ && tree_int_cst_sgn (right_b) < 0)))
+ {
+ /* Here we have to solve the Diophantine equation. Reference
+ book: "Loop Transformations for Restructuring Compilers - The
+ Foundations" by Utpal Banerjee, pages 59-80.
+
+ ALPHA * X0 = BETA * Y0 + GAMMA.
+
+ with:
+ ALPHA = RIGHT_A
+ BETA = RIGHT_B
+ GAMMA = LEFT_B - LEFT_A
+ CHREC_A = {LEFT_A, +, RIGHT_A}
+ CHREC_B = {LEFT_B, +, RIGHT_B}
+
+ The Diophantine equation has a solution if and only if gcd
+ (ALPHA, BETA) divides GAMMA. This is commonly known under
+ the name of the "gcd-test".
+ */
+ tree alpha, beta, gamma;
+ tree la, lb;
+ tree gcd_alpha_beta;
+ tree u11, u12, u21, u22;
+
+ /* Both alpha and beta have to be integer_type_node. The gcd
+ function does not work correctly otherwise. */
+ alpha = copy_node (right_a);
+ beta = copy_node (right_b);
+ la = copy_node (left_a);
+ lb = copy_node (left_b);
+ TREE_TYPE (alpha) = integer_type_node;
+ TREE_TYPE (beta) = integer_type_node;
+ TREE_TYPE (la) = integer_type_node;
+ TREE_TYPE (lb) = integer_type_node;
+
+ gamma = tree_fold_minus (integer_type_node, lb, la);
+
+ /* FIXME: Use lambda_*_Hermite for implementing Bezout. */
+ gcd_alpha_beta = tree_fold_bezout
+ (alpha,
+ tree_fold_multiply (integer_type_node, beta, integer_minus_one_node),
+ &u11, &u12,
+ &u21, &u22);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " (alpha = ");
+ print_generic_expr (dump_file, alpha, 0);
+ fprintf (dump_file, ")\n (beta = ");
+ print_generic_expr (dump_file, beta, 0);
+ fprintf (dump_file, ")\n (gamma = ");
+ print_generic_expr (dump_file, gamma, 0);
+ fprintf (dump_file, ")\n (gcd_alpha_beta = ");
+ print_generic_expr (dump_file, gcd_alpha_beta, 0);
+ fprintf (dump_file, ")\n");
+ }
+
+ /* The classic "gcd-test". */
+ if (!tree_fold_divides_p (integer_type_node, gcd_alpha_beta, gamma))
+ {
+ /* The "gcd-test" has determined that there is no integer
+ solution, ie. there is no dependence. */
+ *overlaps_a = chrec_bot;
+ *overlaps_b = chrec_bot;
+ }
+
+ else
+ {
+ /* The solutions are given by:
+ |
+ | [GAMMA/GCD_ALPHA_BETA t].[u11 u12] = [X]
+ | [u21 u22] [Y]
+
+ For a given integer t. Using the following variables,
+
+ | i0 = u11 * gamma / gcd_alpha_beta
+ | j0 = u12 * gamma / gcd_alpha_beta
+ | i1 = u21
+ | j1 = u22
+
+ the solutions are:
+
+ | x = i0 + i1 * t,
+ | y = j0 + j1 * t. */
+
+ tree i0, j0, i1, j1, t;
+ tree gamma_gcd;
+
+ /* X0 and Y0 are the first iterations for which there is a
+ dependence. X0, Y0 are two solutions of the Diophantine
+ equation: chrec_a (X0) = chrec_b (Y0). */
+ tree x0, y0;
+
+ /* Exact div because in this case gcd_alpha_beta divides
+ gamma. */
+ gamma_gcd = tree_fold_exact_div
+ (integer_type_node, gamma, gcd_alpha_beta);
+ i0 = tree_fold_multiply (integer_type_node, u11, gamma_gcd);
+ j0 = tree_fold_multiply (integer_type_node, u12, gamma_gcd);
+ i1 = u21;
+ j1 = u22;
+
+ if ((tree_int_cst_sgn (i1) == 0
+ && tree_int_cst_sgn (i0) < 0)
+ || (tree_int_cst_sgn (j1) == 0
+ && tree_int_cst_sgn (j0) < 0))
+ {
+ /* There is no solution.
+ FIXME: The case "i0 > nb_iterations, j0 > nb_iterations"
+ falls in here, but for the moment we don't look at the
+ upper bound of the iteration domain. */
+ *overlaps_a = chrec_bot;
+ *overlaps_b = chrec_bot;
+ }
+
+ else
+ {
+ if (tree_int_cst_sgn (i1) > 0)
+ {
+ t = tree_fold_ceil_div
+ (integer_type_node,
+ tree_fold_multiply (integer_type_node, i0,
+ integer_minus_one_node),
+ i1);
+
+ if (tree_int_cst_sgn (j1) > 0)
+ {
+ t = tree_fold_max
+ (integer_type_node, t,
+ tree_fold_ceil_div (integer_type_node,
+ tree_fold_multiply
+ (integer_type_node, j0,
+ integer_minus_one_node),
+ j1));
+
+ x0 = tree_fold_plus
+ (integer_type_node, i0,
+ tree_fold_multiply (integer_type_node, i1, t));
+ y0 = tree_fold_plus
+ (integer_type_node, j0,
+ tree_fold_multiply (integer_type_node, j1, t));
+
+ *overlaps_a = build_polynomial_chrec
+ (CHREC_VARIABLE (chrec_a), x0, u21);
+ *overlaps_b = build_polynomial_chrec
+ (CHREC_VARIABLE (chrec_b), y0, u22);
+ }
+ else
+ {
+ /* FIXME: For the moment, the upper bound of the
+ iteration domain for j is not checked. */
+ *overlaps_a = chrec_top;
+ *overlaps_b = chrec_top;
+ }
+ }
+
+ else
+ {
+ /* FIXME: For the moment, the upper bound of the
+ iteration domain for i is not checked. */
+ *overlaps_a = chrec_top;
+ *overlaps_b = chrec_top;
+ }
+ }
+ }
+ }
+
+ else
+ {
+ /* For the moment, "don't know". */
+ *overlaps_a = chrec_top;
+ *overlaps_b = chrec_top;
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " (overlaps_a = ");
+ print_generic_expr (dump_file, *overlaps_a, 0);
+ fprintf (dump_file, ")\n (overlaps_b = ");
+ print_generic_expr (dump_file, *overlaps_b, 0);
+ fprintf (dump_file, ")\n");
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, ")\n");
+}
+
+/* Analyze single index variable subscript. Note that the dependence
+ testing is not commutative, and that's why both versions of
+ analyze_siv_subscript_x_y and analyze_siv_subscript_y_x are
+ implemented. */
+
+static void
+analyze_siv_subscript (tree chrec_a,
+ tree chrec_b,
+ tree *overlaps_a,
+ tree *overlaps_b)
+{
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "(analyze_siv_subscript \n");
+
+ if (evolution_function_is_constant_p (chrec_a)
+ && evolution_function_is_affine_p (chrec_b))
+ analyze_siv_subscript_cst_affine (chrec_a, chrec_b,
+ overlaps_a, overlaps_b);
+
+ else if (evolution_function_is_affine_p (chrec_a)
+ && evolution_function_is_constant_p (chrec_b))
+ analyze_siv_subscript_affine_cst (chrec_a, chrec_b,
+ overlaps_a, overlaps_b);
+
+ else if (evolution_function_is_affine_p (chrec_a)
+ && evolution_function_is_affine_p (chrec_b)
+ && (CHREC_VARIABLE (chrec_a) == CHREC_VARIABLE (chrec_b)))
+ analyze_siv_subscript_affine_affine (chrec_a, chrec_b,
+ overlaps_a, overlaps_b);
+ else
+ {
+ *overlaps_a = chrec_top;
+ *overlaps_b = chrec_top;
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, ")\n");
+}
+
+/* Helper for determining whether the evolution steps of an affine
+ CHREC divide the constant CST. */
+
+static bool
+chrec_steps_divide_constant_p (tree chrec,
+ tree cst)
+{
+ switch (TREE_CODE (chrec))
+ {
+ case POLYNOMIAL_CHREC:
+ return (tree_fold_divides_p (integer_type_node, CHREC_RIGHT (chrec), cst)
+ && chrec_steps_divide_constant_p (CHREC_LEFT (chrec), cst));
+
+ default:
+ /* On the initial condition, return true. */
+ return true;
+ }
+}
+
+/* This is the MIV subscript analyzer (Multiple Index Variable). */
+
+static void
+analyze_miv_subscript (tree chrec_a,
+ tree chrec_b,
+ tree *overlaps_a,
+ tree *overlaps_b)
+{
+ /* FIXME: This is a MIV subscript, not yet handled.
+ Example: (A[{1, +, 1}_1] vs. A[{1, +, 1}_2]) that comes from
+ (A[i] vs. A[j]).
+
+ In the SIV test we had to solve a Diophantine equation with two
+ variables. In the MIV case we have to solve a Diophantine
+ equation with 2*n variables (if the subscript uses n IVs).
+ */
+ tree difference;
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "(analyze_miv_subscript \n");
+
+ difference = chrec_fold_minus (integer_type_node, chrec_a, chrec_b);
+
+ if (chrec_zerop (difference))
+ {
+ /* Access functions are the same: all the elements are accessed
+ in the same order. */
+ *overlaps_a = integer_zero_node;
+ *overlaps_b = integer_zero_node;
+ }
+
+ else if (evolution_function_is_constant_p (difference)
+ /* For the moment, the following is verified:
+ evolution_function_is_affine_multivariate_p (chrec_a) */
+ && !chrec_steps_divide_constant_p (chrec_a, difference))
+ {
+ /* testsuite/.../ssa-chrec-33.c
+ {{21, +, 2}_1, +, -2}_2 vs. {{20, +, 2}_1, +, -2}_2
+
+ The difference is 1, and the evolution steps are equal to 2,
+ consequently there are no overlapping elements. */
+ *overlaps_a = chrec_bot;
+ *overlaps_b = chrec_bot;
+ }
+
+ else if (evolution_function_is_univariate_p (chrec_a)
+ && evolution_function_is_univariate_p (chrec_b))
+ {
+ /* testsuite/.../ssa-chrec-35.c
+ {0, +, 1}_2 vs. {0, +, 1}_3
+ the overlapping elements are respectively located at iterations:
+ {0, +, 1}_3 and {0, +, 1}_2.
+
+ The overlaps are computed by the classic siv tester, then the
+ evolution loops are exchanged.
+ */
+
+ tree fake_b, fake_overlaps_a;
+ fake_b = build_polynomial_chrec
+ (CHREC_VARIABLE (chrec_a),
+ CHREC_LEFT (chrec_b), CHREC_RIGHT (chrec_b));
+ /* Analyze the siv. */
+ analyze_siv_subscript (chrec_a, fake_b,
+ &fake_overlaps_a, overlaps_b);
+
+ /* Exchange the variables. */
+ if (evolution_function_is_constant_p (*overlaps_b))
+ *overlaps_b = build_polynomial_chrec
+ (CHREC_VARIABLE (chrec_a), *overlaps_b,
+ integer_one_node);
+
+ if (evolution_function_is_constant_p (fake_overlaps_a))
+ *overlaps_a = build_polynomial_chrec
+ (CHREC_VARIABLE (chrec_b), fake_overlaps_a,
+ integer_one_node);
+
+ else
+ *overlaps_a = build_polynomial_chrec
+ (CHREC_VARIABLE (chrec_b),
+ CHREC_LEFT (fake_overlaps_a),
+ CHREC_RIGHT (fake_overlaps_a));
+ }
+
+ else
+ {
+ /* When the analysis is too difficult, answer "don't know". */
+ *overlaps_a = chrec_top;
+ *overlaps_b = chrec_top;
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, ")\n");
+}
+
+/* Determines the iterations for which CHREC_A is equal to CHREC_B.
+ OVERLAP_ITERATIONS_A and OVERLAP_ITERATIONS_B are two functions
+ that describe the iterations that contain conflicting elements.
+
+ Remark: For an integer k >= 0, the following equality is true:
+
+ CHREC_A (OVERLAP_ITERATIONS_A (k)) == CHREC_B (OVERLAP_ITERATIONS_B (k)).
+*/
+
+static void
+analyze_overlapping_iterations (tree chrec_a,
+ tree chrec_b,
+ tree *overlap_iterations_a,
+ tree *overlap_iterations_b)
+{
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "(analyze_overlapping_iterations \n");
+ fprintf (dump_file, " (chrec_a = ");
+ print_generic_expr (dump_file, chrec_a, 0);
+ fprintf (dump_file, ")\n chrec_b = ");
+ print_generic_expr (dump_file, chrec_b, 0);
+ fprintf (dump_file, ")\n");
+ }
+
+ if (chrec_a == NULL_TREE
+ || chrec_b == NULL_TREE
+ || chrec_contains_undetermined (chrec_a)
+ || chrec_contains_undetermined (chrec_b)
+ || chrec_contains_symbols (chrec_a)
+ || chrec_contains_symbols (chrec_b)
+ || chrec_contains_intervals (chrec_a)
+ || chrec_contains_intervals (chrec_b))
+ {
+ *overlap_iterations_a = chrec_top;
+ *overlap_iterations_b = chrec_top;
+ }
+
+ else if (ziv_subscript_p (chrec_a, chrec_b))
+ analyze_ziv_subscript (chrec_a, chrec_b,
+ overlap_iterations_a, overlap_iterations_b);
+
+ else if (siv_subscript_p (chrec_a, chrec_b))
+ analyze_siv_subscript (chrec_a, chrec_b,
+ overlap_iterations_a, overlap_iterations_b);
+
+ else
+ analyze_miv_subscript (chrec_a, chrec_b,
+ overlap_iterations_a, overlap_iterations_b);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " (overlap_iterations_a = ");
+ print_generic_expr (dump_file, *overlap_iterations_a, 0);
+ fprintf (dump_file, ")\n (overlap_iterations_b = ");
+ print_generic_expr (dump_file, *overlap_iterations_b, 0);
+ fprintf (dump_file, ")\n");
+ }
+}
+
+
+
+/* This section contains the affine functions dependences detector. */
+
+/* This is the subscript dependence tester (SubDT). It computes the
+ conflicting iterations. */
+
+static void
+subscript_dependence_tester (struct data_dependence_relation *ddr)
+{
+ unsigned int i;
+ struct data_reference *dra = DDR_A (ddr);
+ struct data_reference *drb = DDR_B (ddr);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "(subscript_dependence_tester \n");
+
+ for (i = 0; i < DDR_NUM_SUBSCRIPTS (ddr); i++)
+ {
+ tree overlaps_a, overlaps_b;
+ struct subscript *subscript = DDR_SUBSCRIPT (ddr, i);
+
+ analyze_overlapping_iterations (DR_ACCESS_FN (dra, i),
+ DR_ACCESS_FN (drb, i),
+ &overlaps_a, &overlaps_b);
+
+ if (overlaps_a == chrec_top
+ || overlaps_b == chrec_top)
+ {
+ DDR_ARE_DEPENDENT (ddr) = chrec_top;
+ DDR_SUBSCRIPTS_VECTOR_FINALIZE (ddr);
+ break;
+ }
+
+ else if (overlaps_a == chrec_bot
+ || overlaps_b == chrec_bot)
+ {
+ DDR_ARE_DEPENDENT (ddr) = chrec_bot;
+ DDR_SUBSCRIPTS_VECTOR_FINALIZE (ddr);
+ break;
+ }
+
+ else
+ {
+ SUB_CONFLICTS_IN_A (subscript) = overlaps_a;
+ SUB_CONFLICTS_IN_B (subscript) = overlaps_b;
+ }
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, ")\n");
+}
+
+/* Return value of a constant X.
+ Borrowed from tree-ssa-loop-ivopts.c
+ XXX: Move this into tree.c and remove from both files. */
+
+static HOST_WIDE_INT
+int_cst_value (tree x)
+{
+ unsigned bits = TYPE_PRECISION (TREE_TYPE (x));
+ unsigned HOST_WIDE_INT val = TREE_INT_CST_LOW (x);
+ bool negative = ((val >> (bits - 1)) & 1) != 0;
+
+ if (negative)
+ val |= (~(unsigned HOST_WIDE_INT) 0) << (bits - 1) << 1;
+ else
+ val &= ~((~(unsigned HOST_WIDE_INT) 0) << (bits - 1) << 1);
+
+ return val;
+}
+
+/* Compute the classic per loop distance vector. */
+
+static void
+build_classic_dist_vector (struct data_dependence_relation *res,
+ varray_type *classic_dist,
+ unsigned nb_loops)
+{
+ unsigned i;
+ lambda_vector dist_v, init_v;
+
+ dist_v = lambda_vector_new (nb_loops);
+ init_v = lambda_vector_new (nb_loops);
+ lambda_vector_clear (dist_v, nb_loops);
+ lambda_vector_clear (init_v, nb_loops);
+
+ if (DDR_ARE_DEPENDENT (res) != NULL_TREE)
+ return;
+
+ for (i = 0; i < DDR_NUM_SUBSCRIPTS (res); i++)
+ {
+ struct subscript *subscript = DDR_SUBSCRIPT (res, i);
+
+ if (SUB_DISTANCE (subscript) == chrec_top)
+ return;
+
+ if (TREE_CODE (SUB_CONFLICTS_IN_A (subscript)) == POLYNOMIAL_CHREC)
+ {
+ int dist;
+ unsigned loop_nb;
+ loop_nb = CHREC_VARIABLE (SUB_CONFLICTS_IN_A (subscript));
+ dist = int_cst_value (SUB_DISTANCE (subscript));
+
+ /* This is the subscript coupling test.
+ | loop i = 0, N, 1
+ | T[i+1][i] = ...
+ | ... = T[i][i]
+ | endloop
+ There is no dependence. */
+ if (init_v[loop_nb] != 0
+ && dist_v[loop_nb] != dist)
+ {
+ DDR_ARE_DEPENDENT (res) = chrec_bot;
+ return;
+ }
+
+ dist_v[loop_nb] = dist;
+ init_v[loop_nb] = 1;
+ }
+ }
+
+ /* There is a distance of 1 on all the outer loops:
+
+ Example: there is a dependence of distance 1 on loop_1 for the array A.
+ | loop_1
+ | A[5] = ...
+ | endloop
+ */
+ {
+ struct loop *lca, *loop_a, *loop_b;
+ struct data_reference *a = DDR_A (res);
+ struct data_reference *b = DDR_B (res);
+
+ loop_a = loop_of_stmt (DR_STMT (a));
+ loop_b = loop_of_stmt (DR_STMT (b));
+
+ /* Get the common ancestor loop. */
+ lca = find_common_loop (loop_a, loop_b);
+
+ /* For each outer_loop where init_v is not set, the accesses are
+ in dependence of distance 1 in the loop. */
+ if (lca != loop_a
+ && lca != loop_b
+ && init_v[loop_num (lca)] == 0)
+ dist_v[loop_num (lca)] = 1;
+
+ lca = outer_loop (lca);
+ if (lca)
+ while (loop_depth (lca) != 0)
+ {
+ if (init_v[loop_num (lca)] == 0)
+ dist_v[loop_num (lca)] = 1;
+ lca = outer_loop (lca);
+ }
+ }
+
+ VARRAY_PUSH_GENERIC_PTR (*classic_dist, dist_v);
+}
+
+/* Compute the classic per loop direction vector. */
+
+static void
+build_classic_dir_vector (struct data_dependence_relation *res,
+ varray_type *classic_dir,
+ unsigned nb_loops)
+{
+ unsigned i;
+ lambda_vector dir_v, init_v;
+
+ dir_v = lambda_vector_new (nb_loops);
+ init_v = lambda_vector_new (nb_loops);
+ lambda_vector_clear (dir_v, nb_loops);
+ lambda_vector_clear (init_v, nb_loops);
+
+ if (DDR_ARE_DEPENDENT (res) != NULL_TREE)
+ return;
+
+ for (i = 0; i < DDR_NUM_SUBSCRIPTS (res); i++)
+ {
+ struct subscript *subscript = DDR_SUBSCRIPT (res, i);
+
+ if (TREE_CODE (SUB_CONFLICTS_IN_A (subscript)) == POLYNOMIAL_CHREC
+ && TREE_CODE (SUB_CONFLICTS_IN_B (subscript)) == POLYNOMIAL_CHREC)
+ {
+ unsigned loop_nb = CHREC_VARIABLE (SUB_CONFLICTS_IN_A (subscript));
+ enum data_dependence_direction dir = dir_star;
+
+ if (SUB_DISTANCE (subscript) == chrec_top)
+ {
+
+ }
+ else
+ {
+ int dist = int_cst_value (SUB_DISTANCE (subscript));
+
+ if (dist == 0)
+ dir = dir_equal;
+ else if (dist > 0)
+ dir = dir_positive;
+ else if (dist < 0)
+ dir = dir_negative;
+ }
+
+ /* This is the subscript coupling test.
+ | loop i = 0, N, 1
+ | T[i+1][i] = ...
+ | ... = T[i][i]
+ | endloop
+ There is no dependence. */
+ if (init_v[loop_nb] != 0
+ && (enum data_dependence_direction) dir_v[loop_nb] != dir)
+ {
+ DDR_ARE_DEPENDENT (res) = chrec_bot;
+ return;
+ }
+
+ dir_v[loop_nb] = dir;
+ init_v[loop_nb] = 1;
+ }
+ }
+
+ /* There is a distance of 1 on all the outer loops:
+
+ Example: there is a dependence of distance 1 on loop_1 for the array A.
+ | loop_1
+ | A[5] = ...
+ | endloop
+ */
+ {
+ struct loop *lca, *loop_a, *loop_b;
+ struct data_reference *a = DDR_A (res);
+ struct data_reference *b = DDR_B (res);
+
+ loop_a = loop_of_stmt (DR_STMT (a));
+ loop_b = loop_of_stmt (DR_STMT (b));
+
+ /* Get the common ancestor loop. */
+ lca = find_common_loop (loop_a, loop_b);
+
+ /* For each outer_loop where init_v is not set, the accesses are
+ in dependence of distance 1 in the loop. */
+ if (lca != loop_a
+ && lca != loop_b
+ && init_v[loop_num (lca)] == 0)
+ dir_v[loop_num (lca)] = dir_positive;
+
+ lca = outer_loop (lca);
+ if (lca)
+ while (loop_depth (lca) != 0)
+ {
+ if (init_v[loop_num (lca)] == 0)
+ dir_v[loop_num (lca)] = dir_positive;
+ lca = outer_loop (lca);
+ }
+ }
+
+ VARRAY_PUSH_GENERIC_PTR (*classic_dir, dir_v);
+}
+
+/* For all the subscripts, set the same value: CHREC. */
+
+static void
+set_all_subscripts_to (struct data_dependence_relation *ddr,
+ tree chrec)
+{
+ unsigned int i;
+
+ if (chrec == chrec_top
+ || chrec == chrec_bot)
+ {
+ DDR_ARE_DEPENDENT (ddr) = chrec;
+ DDR_SUBSCRIPTS_VECTOR_FINALIZE (ddr);
+ }
+
+ for (i = 0; i < DDR_NUM_SUBSCRIPTS (ddr); i++)
+ {
+ struct subscript *subscript = DDR_SUBSCRIPT (ddr, i);
+ SUB_CONFLICTS_IN_A (subscript) = chrec;
+ SUB_CONFLICTS_IN_B (subscript) = chrec;
+ }
+}
+
+/* Determine whether the access functions are affine functions, in
+ which case the dependence tester can be runned. */
+
+static bool
+access_functions_are_affine_or_constant_p (struct data_reference *a)
+{
+ unsigned int i;
+ varray_type fns = DR_ACCESS_FNS (a);
+
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (fns); i++)
+ if (!evolution_function_is_constant_p (VARRAY_TREE (fns, i))
+ && !evolution_function_is_affine_multivariate_p (VARRAY_TREE (fns, i)))
+ return false;
+
+ return true;
+}
+
+/* This computes the affine dependence relation between A and B.
+ CHREC_BOT is used for representing the independence between two
+ accesses, while CHREC_TOP is used for representing the unknown
+ relation.
+
+ Note that it is possible to stop the computation of the dependence
+ relation the first time we detect a CHREC_BOT element for a given
+ subscript. */
+
+static void
+compute_affine_dependence (struct data_dependence_relation *ddr)
+{
+ struct data_reference *dra = DDR_A (ddr);
+ struct data_reference *drb = DDR_B (ddr);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "(compute_affine_dependence (%d, %d)\n",
+ DR_ID (dra), DR_ID (drb));
+ fprintf (dump_file, " (stmt_a = \n");
+ print_generic_expr (dump_file, DR_STMT (dra), 0);
+ fprintf (dump_file, ")\n (stmt_b = \n");
+ print_generic_expr (dump_file, DR_STMT (drb), 0);
+ fprintf (dump_file, ")\n");
+ }
+
+ /* Analyze only when the dependence relation is not yet known. */
+ if (DDR_ARE_DEPENDENT (ddr) == NULL_TREE)
+ {
+ if (access_functions_are_affine_or_constant_p (dra)
+ && access_functions_are_affine_or_constant_p (drb))
+ subscript_dependence_tester (ddr);
+
+ /* As a last case, if the dependence cannot be determined, or if
+ the dependence is considered too difficult to determine, answer
+ "don't know". */
+ else
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "I'm not smart enough for this dependence test,"
+ "please teach me what I should answer. \n");
+
+ set_all_subscripts_to (ddr, chrec_top);
+ }
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, ")\n");
+}
+
+/* Compute all the data dependence relations. */
+
+static void
+compute_all_dependences (varray_type datarefs,
+ varray_type *dependence_relations)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (datarefs); i++)
+ for (j = 0; j < VARRAY_ACTIVE_SIZE (datarefs); j++)
+ {
+ struct data_reference *a, *b;
+ struct data_dependence_relation *ddr;
+
+ a = VARRAY_GENERIC_PTR (datarefs, i);
+ b = VARRAY_GENERIC_PTR (datarefs, j);
+ ddr = initialize_data_dependence_relation (a, b);
+
+ VARRAY_PUSH_GENERIC_PTR (*dependence_relations, ddr);
+ compute_affine_dependence (ddr);
+ compute_distance_vector (ddr);
+ compute_direction_vector (ddr);
+ }
+}
+
+/* Search the data references in LOOP, and record the information into
+ DATAREFS.
+
+ FIXME: This is a "dumb" walker over all the trees in the loop body.
+ Find another technique that avoids this costly walk. This is
+ acceptable for the moment, since this function is used only for
+ debugging purposes. */
+
+static void
+find_data_references_in_loop (struct loop *loop, varray_type *datarefs)
+{
+ basic_block bb;
+ block_stmt_iterator bsi;
+
+ FOR_EACH_BB (bb)
+ {
+ if (!flow_bb_inside_loop_p (loop, bb))
+ continue;
+
+ for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ {
+ tree expr = bsi_stmt (bsi);
+ vdef_optype vdefs = VDEF_OPS (stmt_ann (expr));
+ vuse_optype vuses = VUSE_OPS (stmt_ann (expr));
+
+ if (vuses || vdefs)
+ switch (TREE_CODE (expr))
+ {
+ case MODIFY_EXPR:
+ /* In the GIMPLE representation, the left-hand side of
+ a modify expression is either an ARRAY_REF or
+ otherwise it does not contain other ARRAY_REFs. */
+ if (TREE_CODE (TREE_OPERAND (expr, 0)) == ARRAY_REF)
+ VARRAY_PUSH_GENERIC_PTR
+ (*datarefs, analyze_array (expr, TREE_OPERAND (expr, 0)));
+
+ if (TREE_CODE (TREE_OPERAND (expr, 1)) == ARRAY_REF)
+ VARRAY_PUSH_GENERIC_PTR
+ (*datarefs, analyze_array (expr, TREE_OPERAND (expr, 1)));
+
+ break;
+
+ case COND_EXPR:
+ case CALL_EXPR:
+ case VA_ARG_EXPR:
+ case ASM_EXPR:
+ case RETURN_EXPR:
+ /* In the GIMPLE representation, these nodes do not
+ contain ARRAY_REFs in their operands. */
+ break;
+
+ default:
+ debug_tree (expr);
+ /* abort (); */
+ fprintf (dump_file, "Find ARRAY_REFs: abort.\n");
+ break;
+ }
+ }
+ }
+}
+
+
+
+/* This section contains all the entry points. */
+
+/* Yet another entry point. "Give me a loop nest, I will return you a
+ set of distance/direction vectors." */
+
+void
+compute_data_dependences_for_loop (unsigned nb_loops,
+ struct loop *loop,
+ varray_type *datarefs,
+ varray_type *dependence_relations,
+ varray_type *classic_dist,
+ varray_type *classic_dir)
+{
+ unsigned int i;
+
+ find_data_references_in_loop (loop, datarefs);
+ compute_all_dependences (*datarefs, dependence_relations);
+
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (*dependence_relations); i++)
+ {
+ struct data_dependence_relation *ddr;
+ ddr = VARRAY_GENERIC_PTR (*dependence_relations, i);
+ build_classic_dist_vector (ddr, classic_dist, nb_loops);
+ build_classic_dir_vector (ddr, classic_dir, nb_loops);
+ }
+}
+
+/* Entry point. Analyze all the data references and the dependence
+ relations.
+
+ The data references are computed first.
+
+ A relation on these nodes is represented by a complete graph. Some
+ of the relations could be of no interest, thus the relations can be
+ computed on demand.
+
+ In the following function we compute all the relations. This is
+ just a first implementation that is here for:
+ - for showing how to ask for the dependence relations,
+ - for the debugging the whole dependence graph,
+ - for the dejagnu testcases and maintenance.
+
+ It is possible to ask only for a part of the graph, avoiding to
+ compute the whole dependence graph. The computed dependences are
+ stored in a knowledge base (KB) such that later queries don't
+ recompute the same information. The implementation of this KB is
+ transparent to the optimizer, and thus the KB can be changed with a
+ more efficient implementation, or the KB could be disabled. */
+
+void
+analyze_all_data_dependences (struct loops *loops)
+{
+ unsigned int i;
+ varray_type datarefs;
+ varray_type dependence_relations;
+ varray_type classic_dist, classic_dir;
+ int nb_data_refs = 10;
+
+#if 0
+ dump_file = stderr;
+ dump_flags = 31;
+#endif
+
+ VARRAY_GENERIC_PTR_INIT (classic_dist, 10, "classic_dist");
+ VARRAY_GENERIC_PTR_INIT (classic_dir, 10, "classic_dir");
+ VARRAY_GENERIC_PTR_INIT (datarefs, nb_data_refs, "datarefs");
+ VARRAY_GENERIC_PTR_INIT (dependence_relations,
+ nb_data_refs * nb_data_refs,
+ "dependence_relations");
+
+ /* Compute DDs on the whole function. */
+ compute_data_dependences_for_loop (loops->num, loop_from_num (loops, 0),
+ &datarefs, &dependence_relations,
+ &classic_dist, &classic_dir);
+
+ if (dump_file)
+ {
+ dump_data_dependence_relations (dump_file, dependence_relations);
+ fprintf (dump_file, "\n\n");
+ }
+
+ /* Don't dump distances in order to avoid to update the
+ testsuite. */
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (classic_dist); i++)
+ {
+ fprintf (dump_file, "DISTANCE_V (");
+ print_lambda_vector (dump_file,
+ VARRAY_GENERIC_PTR (classic_dist, i),
+ loops->num);
+ fprintf (dump_file, ")\n");
+ }
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (classic_dir); i++)
+ {
+ fprintf (dump_file, "DIRECTION_V (");
+ print_lambda_vector (dump_file,
+ VARRAY_GENERIC_PTR (classic_dir, i),
+ loops->num);
+ fprintf (dump_file, ")\n");
+ }
+ fprintf (dump_file, "\n\n");
+ }
+
+ if (dump_file && (dump_flags & TDF_STATS))
+ {
+ unsigned nb_top_relations = 0;
+ unsigned nb_bot_relations = 0;
+ unsigned nb_basename_differ = 0;
+ unsigned nb_chrec_relations = 0;
+
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (dependence_relations); i++)
+ {
+ struct data_dependence_relation *ddr;
+ ddr = VARRAY_GENERIC_PTR (dependence_relations, i);
+
+ if (DDR_ARE_DEPENDENT (ddr) == chrec_top)
+ nb_top_relations++;
+
+ else if (DDR_ARE_DEPENDENT (ddr) == chrec_bot)
+ {
+ struct data_reference *a = DDR_A (ddr);
+ struct data_reference *b = DDR_B (ddr);
+
+ if (DR_NUM_DIMENSIONS (a) != DR_NUM_DIMENSIONS (b)
+ || array_base_name_differ_p (a, b))
+ nb_basename_differ++;
+ else
+ nb_bot_relations++;
+ }
+
+ else
+ nb_chrec_relations++;
+ }
+
+ fprintf (dump_file, "\n(\n");
+ fprintf (dump_file, "%d\tnb_top_relations\n", nb_top_relations);
+ fprintf (dump_file, "%d\tnb_bot_relations\n", nb_bot_relations);
+ fprintf (dump_file, "%d\tnb_basename_differ\n", nb_basename_differ);
+ fprintf (dump_file, "%d\tnb_distance_relations\n", (int) VARRAY_ACTIVE_SIZE (classic_dist));
+ fprintf (dump_file, "%d\tnb_chrec_relations\n", nb_chrec_relations);
+ fprintf (dump_file, "\n)\n");
+
+ gather_stats_on_scev_database ();
+ }
+
+ varray_clear (dependence_relations);
+ varray_clear (datarefs);
+ varray_clear (classic_dist);
+ varray_clear (classic_dir);
+}
+
+