aboutsummaryrefslogtreecommitdiff
path: root/gcc/graphite-dependences.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/graphite-dependences.cc')
-rw-r--r--gcc/graphite-dependences.cc342
1 files changed, 342 insertions, 0 deletions
diff --git a/gcc/graphite-dependences.cc b/gcc/graphite-dependences.cc
new file mode 100644
index 0000000..3dd0e66
--- /dev/null
+++ b/gcc/graphite-dependences.cc
@@ -0,0 +1,342 @@
+/* Data dependence analysis for Graphite.
+ Copyright (C) 2009-2022 Free Software Foundation, Inc.
+ Contributed by Sebastian Pop <sebastian.pop@amd.com> and
+ Konrad Trifunovic <konrad.trifunovic@inria.fr>.
+
+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 3, 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 COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#define INCLUDE_ISL
+
+#include "config.h"
+
+#ifdef HAVE_isl
+
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "cfghooks.h"
+#include "tree.h"
+#include "gimple.h"
+#include "fold-const.h"
+#include "gimple-iterator.h"
+#include "tree-ssa-loop.h"
+#include "tree-pass.h"
+#include "cfgloop.h"
+#include "tree-data-ref.h"
+#include "graphite.h"
+
+/* Add the constraints from the set S to the domain of MAP. */
+
+static isl_map *
+constrain_domain (isl_map *map, isl_set *s)
+{
+ isl_space *d = isl_map_get_space (map);
+ isl_id *id = isl_space_get_tuple_id (d, isl_dim_in);
+
+ s = isl_set_set_tuple_id (s, id);
+ isl_space_free (d);
+ return isl_map_coalesce (isl_map_intersect_domain (map, s));
+}
+
+/* Constrain pdr->accesses with pdr->subscript_sizes and pbb->domain. */
+
+static isl_map *
+add_pdr_constraints (poly_dr_p pdr, poly_bb_p pbb)
+{
+ isl_map *x = isl_map_intersect_range (isl_map_copy (pdr->accesses),
+ isl_set_copy (pdr->subscript_sizes));
+ x = isl_map_coalesce (x);
+ return constrain_domain (x, isl_set_copy (pbb->domain));
+}
+
+/* Returns an isl description of all memory operations in SCOP. The memory
+ reads are returned in READS and writes in MUST_WRITES and MAY_WRITES. */
+
+static void
+scop_get_reads_and_writes (scop_p scop, isl_union_map *&reads,
+ isl_union_map *&must_writes,
+ isl_union_map *&may_writes)
+{
+ int i, j;
+ poly_bb_p pbb;
+ poly_dr_p pdr;
+
+ FOR_EACH_VEC_ELT (scop->pbbs, i, pbb)
+ {
+ FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr) {
+ if (pdr_read_p (pdr))
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "Adding read to depedence graph: ");
+ print_pdr (dump_file, pdr);
+ }
+ isl_union_map *um
+ = isl_union_map_from_map (add_pdr_constraints (pdr, pbb));
+ reads = isl_union_map_union (reads, um);
+ if (dump_file)
+ {
+ fprintf (dump_file, "Reads depedence graph: ");
+ print_isl_union_map (dump_file, reads);
+ }
+ }
+ else if (pdr_write_p (pdr))
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "Adding must write to depedence graph: ");
+ print_pdr (dump_file, pdr);
+ }
+ isl_union_map *um
+ = isl_union_map_from_map (add_pdr_constraints (pdr, pbb));
+ must_writes = isl_union_map_union (must_writes, um);
+ if (dump_file)
+ {
+ fprintf (dump_file, "Must writes depedence graph: ");
+ print_isl_union_map (dump_file, must_writes);
+ }
+ }
+ else if (pdr_may_write_p (pdr))
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, "Adding may write to depedence graph: ");
+ print_pdr (dump_file, pdr);
+ }
+ isl_union_map *um
+ = isl_union_map_from_map (add_pdr_constraints (pdr, pbb));
+ may_writes = isl_union_map_union (may_writes, um);
+ if (dump_file)
+ {
+ fprintf (dump_file, "May writes depedence graph: ");
+ print_isl_union_map (dump_file, may_writes);
+ }
+ }
+ }
+ }
+}
+
+/* Helper function used on each MAP of a isl_union_map. Computes the
+ maximal output dimension. */
+
+static isl_stat
+max_number_of_out_dimensions (__isl_take isl_map *map, void *user)
+{
+ int global_max = *((int *) user);
+ isl_space *space = isl_map_get_space (map);
+ int nb_out = isl_space_dim (space, isl_dim_out);
+
+ if (global_max < nb_out)
+ *((int *) user) = nb_out;
+
+ isl_map_free (map);
+ isl_space_free (space);
+ return isl_stat_ok;
+}
+
+/* Extends the output dimension of MAP to MAX dimensions. */
+
+static __isl_give isl_map *
+extend_map (__isl_take isl_map *map, int max)
+{
+ isl_space *space = isl_map_get_space (map);
+ int n = isl_space_dim (space, isl_dim_out);
+
+ isl_space_free (space);
+ return isl_map_add_dims (map, isl_dim_out, max - n);
+}
+
+/* Structure used to pass parameters to extend_schedule_1. */
+
+struct extend_schedule_str {
+ int max;
+ isl_union_map *umap;
+};
+
+/* Helper function for extend_schedule. */
+
+static isl_stat
+extend_schedule_1 (__isl_take isl_map *map, void *user)
+{
+ struct extend_schedule_str *str = (struct extend_schedule_str *) user;
+ str->umap = isl_union_map_add_map (str->umap, extend_map (map, str->max));
+ return isl_stat_ok;
+}
+
+/* Return a relation that has uniform output dimensions. */
+
+static __isl_give isl_union_map *
+extend_schedule (__isl_take isl_union_map *x)
+{
+ int max = 0;
+ struct extend_schedule_str str;
+
+ isl_union_map_foreach_map (x, max_number_of_out_dimensions, (void *) &max);
+ str.max = max;
+ str.umap = isl_union_map_empty (isl_union_map_get_space (x));
+ isl_union_map_foreach_map (x, extend_schedule_1, (void *) &str);
+ isl_union_map_free (x);
+ return isl_union_map_coalesce (str.umap);
+}
+
+/* Applies SCHEDULE to the in and out dimensions of the dependences
+ DEPS and return the resulting relation. */
+
+static isl_map *
+apply_schedule_on_deps (__isl_keep isl_union_map *schedule,
+ __isl_keep isl_union_map *deps)
+{
+ isl_union_map *trans = extend_schedule (isl_union_map_copy (schedule));
+ isl_union_map *ux = isl_union_map_copy (deps);
+ ux = isl_union_map_apply_domain (ux, isl_union_map_copy (trans));
+ ux = isl_union_map_apply_range (ux, trans);
+ ux = isl_union_map_coalesce (ux);
+
+ if (!isl_union_map_is_empty (ux))
+ return isl_map_from_union_map (ux);
+
+ isl_union_map_free (ux);
+ return NULL;
+}
+
+/* Return true when DEPS is non empty and the intersection of LEX with
+ the DEPS transformed by SCHEDULE is non empty. LEX is the relation
+ in which all the inputs before DEPTH occur at the same time as the
+ output, and the input at DEPTH occurs before output. */
+
+bool
+carries_deps (__isl_keep isl_union_map *schedule,
+ __isl_keep isl_union_map *deps,
+ int depth)
+{
+ if (isl_union_map_is_empty (deps))
+ return false;
+
+ isl_map *x = apply_schedule_on_deps (schedule, deps);
+ if (x == NULL)
+ return false;
+
+ isl_space *space = isl_map_get_space (x);
+ isl_map *lex = isl_map_lex_le (isl_space_range (space));
+ isl_constraint *ineq = isl_inequality_alloc
+ (isl_local_space_from_space (isl_map_get_space (x)));
+
+ for (int i = 0; i < depth - 1; i++)
+ lex = isl_map_equate (lex, isl_dim_in, i, isl_dim_out, i);
+
+ /* in + 1 <= out */
+ ineq = isl_constraint_set_coefficient_si (ineq, isl_dim_out, depth - 1, 1);
+ ineq = isl_constraint_set_coefficient_si (ineq, isl_dim_in, depth - 1, -1);
+ ineq = isl_constraint_set_constant_si (ineq, -1);
+ lex = isl_map_add_constraint (lex, ineq);
+ lex = isl_map_coalesce (lex);
+ x = isl_map_intersect (x, lex);
+ bool res = !isl_map_is_empty (x);
+
+ isl_map_free (x);
+ return res;
+}
+
+/* Compute the dependence relations for the SCOP:
+ RAW are read after write dependences,
+ WAR are write after read dependences,
+ WAW are write after write dependences. */
+
+void
+scop_get_dependences (scop_p scop)
+{
+ if (scop->dependence)
+ return;
+
+ isl_space *space = isl_set_get_space (scop->param_context);
+ isl_union_map *reads = isl_union_map_empty (isl_space_copy (space));
+ isl_union_map *must_writes = isl_union_map_empty (isl_space_copy (space));
+ isl_union_map *may_writes = isl_union_map_empty (space);
+ scop_get_reads_and_writes (scop, reads, must_writes, may_writes);
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "\n--- Documentation for datarefs dump: ---\n");
+ fprintf (dump_file, "Statements on the iteration domain are mapped to"
+ " array references.\n");
+ fprintf (dump_file, " To read the following data references:\n\n");
+ fprintf (dump_file, " S_5[i0] -> [106] : i0 >= 0 and i0 <= 3\n");
+ fprintf (dump_file, " S_8[i0] -> [1, i0] : i0 >= 0 and i0 <= 3\n\n");
+
+ fprintf (dump_file, " S_5[i0] is the dynamic instance of statement"
+ " bb_5 in a loop that accesses all iterations 0 <= i0 <= 3.\n");
+ fprintf (dump_file, " [1, i0] is a 'memref' with alias set 1"
+ " and first subscript access i0.\n");
+ fprintf (dump_file, " [106] is a 'scalar reference' which is the sum of"
+ " SSA_NAME_VERSION 6"
+ " and --param graphite-max-arrays-per-scop=100\n");
+ fprintf (dump_file, "-----------------------\n\n");
+
+ fprintf (dump_file, "data references (\n");
+ fprintf (dump_file, " reads: ");
+ print_isl_union_map (dump_file, reads);
+ fprintf (dump_file, " must_writes: ");
+ print_isl_union_map (dump_file, must_writes);
+ fprintf (dump_file, " may_writes: ");
+ print_isl_union_map (dump_file, may_writes);
+ fprintf (dump_file, ")\n");
+ }
+
+ gcc_assert (scop->original_schedule);
+
+ isl_union_access_info *ai;
+ ai = isl_union_access_info_from_sink (isl_union_map_copy (reads));
+ ai = isl_union_access_info_set_must_source (ai, isl_union_map_copy (must_writes));
+ ai = isl_union_access_info_set_may_source (ai, may_writes);
+ ai = isl_union_access_info_set_schedule
+ (ai, isl_schedule_copy (scop->original_schedule));
+ isl_union_flow *flow = isl_union_access_info_compute_flow (ai);
+ isl_union_map *raw = isl_union_flow_get_must_dependence (flow);
+ isl_union_flow_free (flow);
+
+ ai = isl_union_access_info_from_sink (isl_union_map_copy (must_writes));
+ ai = isl_union_access_info_set_must_source (ai, must_writes);
+ ai = isl_union_access_info_set_may_source (ai, reads);
+ ai = isl_union_access_info_set_schedule
+ (ai, isl_schedule_copy (scop->original_schedule));
+ flow = isl_union_access_info_compute_flow (ai);
+
+ isl_union_map *waw = isl_union_flow_get_must_dependence (flow);
+ isl_union_map *war = isl_union_flow_get_may_dependence (flow);
+ war = isl_union_map_subtract (war, isl_union_map_copy (waw));
+ isl_union_flow_free (flow);
+
+ raw = isl_union_map_coalesce (raw);
+ waw = isl_union_map_coalesce (waw);
+ war = isl_union_map_coalesce (war);
+
+ isl_union_map *dependences = raw;
+ dependences = isl_union_map_union (dependences, war);
+ dependences = isl_union_map_union (dependences, waw);
+ dependences = isl_union_map_coalesce (dependences);
+
+ if (dump_file)
+ {
+ fprintf (dump_file, "data dependences (\n");
+ print_isl_union_map (dump_file, dependences);
+ fprintf (dump_file, ")\n");
+ }
+
+ scop->dependence = dependences;
+}
+
+#endif /* HAVE_isl */