/* Data dependence analysis for Graphite.
- Copyright (C) 2009 Free Software Foundation, Inc.
+ Copyright (C) 2009-2020 Free Software Foundation, Inc.
Contributed by Sebastian Pop <sebastian.pop@amd.com> and
Konrad Trifunovic <konrad.trifunovic@inria.fr>.
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+#define USES_ISL
+
#include "config.h"
+
+#ifdef HAVE_isl
+
#include "system.h"
#include "coretypes.h"
-#include "tm.h"
-#include "ggc.h"
+#include "backend.h"
+#include "cfghooks.h"
#include "tree.h"
-#include "rtl.h"
-#include "basic-block.h"
-#include "diagnostic.h"
-#include "tree-flow.h"
-#include "toplev.h"
-#include "tree-dump.h"
-#include "timevar.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-chrec.h"
#include "tree-data-ref.h"
-#include "tree-scalar-evolution.h"
-#include "tree-pass.h"
-#include "domwalk.h"
-#include "pointer-set.h"
-#include "gimple.h"
-
-#ifdef HAVE_cloog
-#include "cloog/cloog.h"
-#include "ppl_c.h"
-#include "sese.h"
-#include "graphite-ppl.h"
#include "graphite.h"
-#include "graphite-poly.h"
-#include "graphite-dependences.h"
-
-/* Returns a new polyhedral Data Dependence Relation (DDR). SOURCE is
- the source data reference, SINK is the sink data reference. SOURCE
- and SINK define an edge in the Data Dependence Graph (DDG). */
-
-static poly_ddr_p
-new_poly_ddr (poly_dr_p source, poly_dr_p sink,
- ppl_Pointset_Powerset_C_Polyhedron_t ddp)
-{
- poly_ddr_p pddr;
-
- pddr = XNEW (struct poly_ddr);
- PDDR_SOURCE (pddr) = source;
- PDDR_SINK (pddr) = sink;
- PDDR_DDP (pddr) = ddp;
- PDDR_KIND (pddr) = unknown_dependence;
-
- return pddr;
-}
-
-/* Free the poly_ddr_p P. */
-
-void
-free_poly_ddr (void *p)
-{
- poly_ddr_p pddr = (poly_ddr_p) p;
- ppl_delete_Pointset_Powerset_C_Polyhedron (PDDR_DDP (pddr));
- free (pddr);
-}
-
-/* Comparison function for poly_ddr hash table. */
-
-int
-eq_poly_ddr_p (const void *pddr1, const void *pddr2)
-{
- const struct poly_ddr *p1 = (const struct poly_ddr *) pddr1;
- const struct poly_ddr *p2 = (const struct poly_ddr *) pddr2;
- return (PDDR_SOURCE (p1) == PDDR_SOURCE (p2)
- && PDDR_SINK (p1) == PDDR_SINK (p2));
-}
-
-/* Hash function for poly_ddr hashtable. */
+/* Add the constraints from the set S to the domain of MAP. */
-hashval_t
-hash_poly_ddr_p (const void *pddr)
+static isl_map *
+constrain_domain (isl_map *map, isl_set *s)
{
- const struct poly_ddr *p = (const struct poly_ddr *) pddr;
+ isl_space *d = isl_map_get_space (map);
+ isl_id *id = isl_space_get_tuple_id (d, isl_dim_in);
- return (hashval_t) ((long) PDDR_SOURCE (p) + (long) PDDR_SINK (p));
+ s = isl_set_set_tuple_id (s, id);
+ isl_space_free (d);
+ return isl_map_coalesce (isl_map_intersect_domain (map, s));
}
-/* Returns true when PDDR has no dependence. */
-
-static bool
-pddr_is_empty (poly_ddr_p pddr)
-{
- if (PDDR_KIND (pddr) != unknown_dependence)
- return PDDR_KIND (pddr) == no_dependence ? true : false;
-
- if (ppl_Pointset_Powerset_C_Polyhedron_is_empty (PDDR_DDP (pddr)))
- {
- PDDR_KIND (pddr) = no_dependence;
- return true;
- }
-
- PDDR_KIND (pddr) = has_dependence;
- return false;
-}
-
-/* Returns a polyhedron of dimension DIM.
-
- Maps the dimensions [0, ..., cut - 1] of polyhedron P to OFFSET0
- and the dimensions [cut, ..., nb_dim] to DIM - GDIM. */
+/* Constrain pdr->accesses with pdr->subscript_sizes and pbb->domain. */
-static ppl_Pointset_Powerset_C_Polyhedron_t
-map_into_dep_poly (graphite_dim_t dim, graphite_dim_t gdim,
- ppl_Pointset_Powerset_C_Polyhedron_t p,
- graphite_dim_t cut,
- graphite_dim_t offset)
+static isl_map *
+add_pdr_constraints (poly_dr_p pdr, poly_bb_p pbb)
{
- ppl_Pointset_Powerset_C_Polyhedron_t res;
-
- ppl_new_Pointset_Powerset_C_Polyhedron_from_Pointset_Powerset_C_Polyhedron
- (&res, p);
- ppl_insert_dimensions_pointset (res, 0, offset);
- ppl_insert_dimensions_pointset (res, offset + cut,
- dim - offset - cut - gdim);
-
- return res;
+ 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));
}
-/* Swap [cut0, ..., cut1] to the end of DR: "a CUT0 b CUT1 c" is
- transformed into "a CUT0 c CUT1' b"
-
- Add NB0 zeros before "a": "00...0 a CUT0 c CUT1' b"
- Add NB1 zeros between "a" and "c": "00...0 a 00...0 c CUT1' b"
- Add DIM - NB0 - NB1 - PDIM zeros between "c" and "b":
- "00...0 a 00...0 c 00...0 b". */
-
-static ppl_Pointset_Powerset_C_Polyhedron_t
-map_dr_into_dep_poly (graphite_dim_t dim,
- ppl_Pointset_Powerset_C_Polyhedron_t dr,
- graphite_dim_t cut0, graphite_dim_t cut1,
- graphite_dim_t nb0, graphite_dim_t nb1)
-{
- ppl_dimension_type pdim;
- ppl_dimension_type *map;
- ppl_Pointset_Powerset_C_Polyhedron_t res;
- ppl_dimension_type i;
-
- ppl_new_Pointset_Powerset_C_Polyhedron_from_Pointset_Powerset_C_Polyhedron
- (&res, dr);
- ppl_Pointset_Powerset_C_Polyhedron_space_dimension (res, &pdim);
-
- map = (ppl_dimension_type *) XNEWVEC (ppl_dimension_type, pdim);
-
- /* First mapping: move 'g' vector to right position. */
- for (i = 0; i < cut0; i++)
- map[i] = i;
-
- for (i = cut0; i < cut1; i++)
- map[i] = pdim - cut1 + i;
-
- for (i = cut1; i < pdim; i++)
- map[i] = cut0 + i - cut1;
-
- ppl_Pointset_Powerset_C_Polyhedron_map_space_dimensions (res, map, pdim);
- free (map);
-
- /* After swapping 's' and 'g' vectors, we have to update a new cut. */
- cut1 = pdim - cut1 + cut0;
-
- ppl_insert_dimensions_pointset (res, 0, nb0);
- ppl_insert_dimensions_pointset (res, nb0 + cut0, nb1);
- ppl_insert_dimensions_pointset (res, nb0 + nb1 + cut1,
- dim - nb0 - nb1 - pdim);
-
- return res;
-}
-
-/* Builds a constraints of the form "POS1 - POS2 CSTR_TYPE C" */
-
-static ppl_Constraint_t
-build_pairwise_constraint (graphite_dim_t dim,
- graphite_dim_t pos1, graphite_dim_t pos2,
- int c, enum ppl_enum_Constraint_Type cstr_type)
-{
- ppl_Linear_Expression_t expr;
- ppl_Constraint_t cstr;
- ppl_Coefficient_t coef;
- Value v, v_op, v_c;
-
- value_init (v);
- value_init (v_op);
- value_init (v_c);
-
- value_set_si (v, 1);
- value_set_si (v_op, -1);
- value_set_si (v_c, c);
-
- ppl_new_Coefficient (&coef);
- ppl_new_Linear_Expression_with_dimension (&expr, dim);
-
- ppl_assign_Coefficient_from_mpz_t (coef, v);
- ppl_Linear_Expression_add_to_coefficient (expr, pos1, coef);
- ppl_assign_Coefficient_from_mpz_t (coef, v_op);
- ppl_Linear_Expression_add_to_coefficient (expr, pos2, coef);
- ppl_assign_Coefficient_from_mpz_t (coef, v_c);
- ppl_Linear_Expression_add_to_inhomogeneous (expr, coef);
-
- ppl_new_Constraint (&cstr, expr, cstr_type);
-
- ppl_delete_Linear_Expression (expr);
- ppl_delete_Coefficient (coef);
- value_clear (v);
- value_clear (v_op);
- value_clear (v_c);
-
- return cstr;
-}
-
-/* Builds subscript equality constraints. */
-
-static ppl_Pointset_Powerset_C_Polyhedron_t
-dr_equality_constraints (graphite_dim_t dim,
- graphite_dim_t pos, graphite_dim_t nb_subscripts)
-{
- ppl_Polyhedron_t subscript_equalities;
- ppl_Pointset_Powerset_C_Polyhedron_t res;
- Value v, v_op;
- graphite_dim_t i;
-
- value_init (v);
- value_init (v_op);
- value_set_si (v, 1);
- value_set_si (v_op, -1);
-
- ppl_new_C_Polyhedron_from_space_dimension (&subscript_equalities, dim, 0);
- for (i = 0; i < nb_subscripts; i++)
- {
- ppl_Linear_Expression_t expr;
- ppl_Constraint_t cstr;
- ppl_Coefficient_t coef;
-
- ppl_new_Coefficient (&coef);
- ppl_new_Linear_Expression_with_dimension (&expr, dim);
-
- ppl_assign_Coefficient_from_mpz_t (coef, v);
- ppl_Linear_Expression_add_to_coefficient (expr, pos + i, coef);
- ppl_assign_Coefficient_from_mpz_t (coef, v_op);
- ppl_Linear_Expression_add_to_coefficient (expr, pos + i + nb_subscripts,
- coef);
-
- ppl_new_Constraint (&cstr, expr, PPL_CONSTRAINT_TYPE_EQUAL);
- ppl_Polyhedron_add_constraint (subscript_equalities, cstr);
-
- ppl_delete_Linear_Expression (expr);
- ppl_delete_Constraint (cstr);
- ppl_delete_Coefficient (coef);
- }
-
- ppl_new_Pointset_Powerset_C_Polyhedron_from_C_Polyhedron
- (&res, subscript_equalities);
- value_clear (v);
- value_clear (v_op);
- ppl_delete_Polyhedron (subscript_equalities);
-
- return res;
-}
-
-/* Builds scheduling equality constraints. */
-
-static ppl_Pointset_Powerset_C_Polyhedron_t
-build_pairwise_scheduling_equality (graphite_dim_t dim,
- graphite_dim_t pos, graphite_dim_t offset)
-{
- ppl_Pointset_Powerset_C_Polyhedron_t res;
- ppl_Polyhedron_t equalities;
- ppl_Constraint_t cstr;
-
- ppl_new_C_Polyhedron_from_space_dimension (&equalities, dim, 0);
-
- cstr = build_pairwise_constraint (dim, pos, pos + offset, 0,
- PPL_CONSTRAINT_TYPE_EQUAL);
- ppl_Polyhedron_add_constraint (equalities, cstr);
- ppl_delete_Constraint (cstr);
-
- ppl_new_Pointset_Powerset_C_Polyhedron_from_C_Polyhedron (&res, equalities);
- ppl_delete_Polyhedron (equalities);
- return res;
-}
-
-/* Builds scheduling inequality constraints. */
-
-static ppl_Pointset_Powerset_C_Polyhedron_t
-build_pairwise_scheduling_inequality (graphite_dim_t dim,
- graphite_dim_t pos,
- graphite_dim_t offset,
- bool direction)
-{
- ppl_Pointset_Powerset_C_Polyhedron_t res;
- ppl_Polyhedron_t equalities;
- ppl_Constraint_t cstr;
-
- ppl_new_C_Polyhedron_from_space_dimension (&equalities, dim, 0);
-
- if (direction)
- cstr = build_pairwise_constraint (dim, pos, pos + offset, -1,
- PPL_CONSTRAINT_TYPE_GREATER_OR_EQUAL);
- else
- cstr = build_pairwise_constraint (dim, pos, pos + offset, 1,
- PPL_CONSTRAINT_TYPE_LESS_OR_EQUAL);
-
- ppl_Polyhedron_add_constraint (equalities, cstr);
- ppl_delete_Constraint (cstr);
-
- ppl_new_Pointset_Powerset_C_Polyhedron_from_C_Polyhedron (&res, equalities);
- ppl_delete_Polyhedron (equalities);
- return res;
-}
-
-/* Returns true when adding the lexicographical constraints at level I
- to the RES dependence polyhedron returns an empty polyhedron. */
-
-static bool
-lexicographically_gt_p (ppl_Pointset_Powerset_C_Polyhedron_t res,
- graphite_dim_t dim,
- graphite_dim_t offset,
- bool direction, graphite_dim_t i)
-{
- ppl_Pointset_Powerset_C_Polyhedron_t ineq;
- bool empty_p;
-
- ineq = build_pairwise_scheduling_inequality (dim, i, offset,
- direction);
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (ineq, res);
- empty_p = ppl_Pointset_Powerset_C_Polyhedron_is_empty (ineq);
- if (!empty_p)
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, ineq);
- ppl_delete_Pointset_Powerset_C_Polyhedron (ineq);
-
- return !empty_p;
-}
-
-/* Build the precedence constraints for the lexicographical comparison
- of time vectors RES following the lexicographical order. */
+/* 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
-build_lexicographically_gt_constraint (ppl_Pointset_Powerset_C_Polyhedron_t *res,
- graphite_dim_t dim,
- graphite_dim_t tdim1,
- graphite_dim_t offset,
- bool direction)
+scop_get_reads_and_writes (scop_p scop, isl_union_map *&reads,
+ isl_union_map *&must_writes,
+ isl_union_map *&may_writes)
{
- graphite_dim_t i;
-
- if (lexicographically_gt_p (*res, dim, offset, direction, 0))
- return;
-
- for (i = 0; i < tdim1 - 1; i++)
- {
- ppl_Pointset_Powerset_C_Polyhedron_t sceq;
-
- sceq = build_pairwise_scheduling_equality (dim, i, offset);
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (*res, sceq);
- ppl_delete_Pointset_Powerset_C_Polyhedron (sceq);
-
- if (lexicographically_gt_p (*res, dim, offset, direction, i + 1))
- return;
- }
+ int i, j;
+ poly_bb_p pbb;
+ poly_dr_p pdr;
- if (i == tdim1 - 1)
+ FOR_EACH_VEC_ELT (scop->pbbs, i, pbb)
{
- ppl_delete_Pointset_Powerset_C_Polyhedron (*res);
- ppl_new_Pointset_Powerset_C_Polyhedron_from_space_dimension (res, dim, 1);
+ 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);
+ }
+ }
+ }
}
}
-/* Build the dependence polyhedron for data references PDR1 and PDR2. */
+/* Helper function used on each MAP of a isl_union_map. Computes the
+ maximal output dimension. */
-static poly_ddr_p
-dependence_polyhedron_1 (poly_bb_p pbb1, poly_bb_p pbb2,
- ppl_Pointset_Powerset_C_Polyhedron_t d1,
- ppl_Pointset_Powerset_C_Polyhedron_t d2,
- poly_dr_p pdr1, poly_dr_p pdr2,
- ppl_Polyhedron_t s1, ppl_Polyhedron_t s2,
- bool direction,
- bool original_scattering_p)
+static isl_stat
+max_number_of_out_dimensions (__isl_take isl_map *map, void *user)
{
- scop_p scop = PBB_SCOP (pbb1);
- graphite_dim_t tdim1 = original_scattering_p ?
- pbb_nb_scattering_orig (pbb1) : pbb_nb_scattering_transform (pbb1);
- graphite_dim_t tdim2 = original_scattering_p ?
- pbb_nb_scattering_orig (pbb2) : pbb_nb_scattering_transform (pbb2);
- graphite_dim_t ddim1 = pbb_dim_iter_domain (pbb1);
- graphite_dim_t ddim2 = pbb_dim_iter_domain (pbb2);
- graphite_dim_t sdim1 = PDR_NB_SUBSCRIPTS (pdr1) + 1;
- graphite_dim_t gdim = scop_nb_params (scop);
- graphite_dim_t dim1 = pdr_dim (pdr1);
- graphite_dim_t dim2 = pdr_dim (pdr2);
- graphite_dim_t dim = tdim1 + tdim2 + dim1 + dim2;
- ppl_Pointset_Powerset_C_Polyhedron_t res;
- ppl_Pointset_Powerset_C_Polyhedron_t id1, id2, isc1, isc2, idr1, idr2;
- ppl_Pointset_Powerset_C_Polyhedron_t sc1, sc2, dreq;
-
- gcc_assert (PBB_SCOP (pbb1) == PBB_SCOP (pbb2));
- ppl_new_Pointset_Powerset_C_Polyhedron_from_C_Polyhedron (&sc1, s1);
- ppl_new_Pointset_Powerset_C_Polyhedron_from_C_Polyhedron (&sc2, s2);
-
- id1 = map_into_dep_poly (dim, gdim, d1, ddim1, tdim1);
- id2 = map_into_dep_poly (dim, gdim, d2, ddim2, tdim1 + ddim1 + tdim2);
- isc1 = map_into_dep_poly (dim, gdim, sc1, ddim1 + tdim1, 0);
- isc2 = map_into_dep_poly (dim, gdim, sc2, ddim2 + tdim2, tdim1 + ddim1);
-
- idr1 = map_dr_into_dep_poly (dim, PDR_ACCESSES (pdr1), ddim1, ddim1 + gdim,
- tdim1, tdim2 + ddim2);
- idr2 = map_dr_into_dep_poly (dim, PDR_ACCESSES (pdr2), ddim2, ddim2 + gdim,
- tdim1 + ddim1 + tdim2, sdim1);
-
- /* Now add the subscript equalities. */
- dreq = dr_equality_constraints (dim, tdim1 + ddim1 + tdim2 + ddim2, sdim1);
-
- ppl_new_Pointset_Powerset_C_Polyhedron_from_space_dimension (&res, dim, 0);
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, id1);
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, id2);
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, isc1);
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, isc2);
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, idr1);
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, idr2);
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, dreq);
- ppl_delete_Pointset_Powerset_C_Polyhedron (id1);
- ppl_delete_Pointset_Powerset_C_Polyhedron (id2);
- ppl_delete_Pointset_Powerset_C_Polyhedron (sc1);
- ppl_delete_Pointset_Powerset_C_Polyhedron (sc2);
- ppl_delete_Pointset_Powerset_C_Polyhedron (isc1);
- ppl_delete_Pointset_Powerset_C_Polyhedron (isc2);
- ppl_delete_Pointset_Powerset_C_Polyhedron (idr1);
- ppl_delete_Pointset_Powerset_C_Polyhedron (idr2);
- ppl_delete_Pointset_Powerset_C_Polyhedron (dreq);
-
- if (!ppl_Pointset_Powerset_C_Polyhedron_is_empty (res))
- build_lexicographically_gt_constraint (&res, dim, MIN (tdim1, tdim2),
- tdim1 + ddim1, direction);
-
- return new_poly_ddr (pdr1, pdr2, res);
-}
-
-/* Build the dependence polyhedron for data references PDR1 and PDR2.
- If possible use already cached information. */
-
-static poly_ddr_p
-dependence_polyhedron (poly_bb_p pbb1, poly_bb_p pbb2,
- ppl_Pointset_Powerset_C_Polyhedron_t d1,
- ppl_Pointset_Powerset_C_Polyhedron_t d2,
- poly_dr_p pdr1, poly_dr_p pdr2,
- ppl_Polyhedron_t s1, ppl_Polyhedron_t s2,
- bool direction,
- bool original_scattering_p)
-{
- PTR *x = NULL;
- poly_ddr_p res;
+ int global_max = *((int *) user);
+ isl_space *space = isl_map_get_space (map);
+ int nb_out = isl_space_dim (space, isl_dim_out);
- if (original_scattering_p)
- {
- struct poly_ddr tmp;
-
- tmp.source = pdr1;
- tmp.sink = pdr2;
- x = htab_find_slot (SCOP_ORIGINAL_PDDRS (PBB_SCOP (pbb1)),
- &tmp, INSERT);
+ if (global_max < nb_out)
+ *((int *) user) = nb_out;
- if (x && *x)
- return (poly_ddr_p) *x;
- }
-
- res = dependence_polyhedron_1 (pbb1, pbb2, d1, d2, pdr1, pdr2,
- s1, s2, direction, original_scattering_p);
-
- if (original_scattering_p)
- *x = res;
-
- return res;
+ isl_map_free (map);
+ isl_space_free (space);
+ return isl_stat_ok;
}
-static bool
-poly_drs_may_alias_p (poly_dr_p pdr1, poly_dr_p pdr2);
-
-/* Returns the PDDR corresponding to the original schedule, or NULL if
- the dependence relation is empty or unknown (Can't judge dependency
- under polyhedral model. */
+/* Extends the output dimension of MAP to MAX dimensions. */
-static poly_ddr_p
-pddr_original_scattering (poly_bb_p pbb1, poly_bb_p pbb2,
- poly_dr_p pdr1, poly_dr_p pdr2)
+static __isl_give isl_map *
+extend_map (__isl_take isl_map *map, int max)
{
- poly_ddr_p pddr;
- ppl_Pointset_Powerset_C_Polyhedron_t d1 = PBB_DOMAIN (pbb1);
- ppl_Pointset_Powerset_C_Polyhedron_t d2 = PBB_DOMAIN (pbb2);
- ppl_Polyhedron_t so1 = PBB_ORIGINAL_SCATTERING (pbb1);
- ppl_Polyhedron_t so2 = PBB_ORIGINAL_SCATTERING (pbb2);
-
- if ((pdr_read_p (pdr1) && pdr_read_p (pdr2))
- || PDR_BASE_OBJECT_SET (pdr1) != PDR_BASE_OBJECT_SET (pdr2)
- || PDR_NB_SUBSCRIPTS (pdr1) != PDR_NB_SUBSCRIPTS (pdr2))
- return NULL;
-
- pddr = dependence_polyhedron (pbb1, pbb2, d1, d2, pdr1, pdr2, so1, so2,
- true, true);
- if (pddr_is_empty (pddr))
- return NULL;
-
- return pddr;
-}
-
-/* Return true when the data dependence relation between the data
- references PDR1 belonging to PBB1 and PDR2 is part of a
- reduction. */
-
-static inline bool
-reduction_dr_1 (poly_bb_p pbb1, poly_dr_p pdr1, poly_dr_p pdr2)
-{
- int i;
- poly_dr_p pdr;
-
- /* PBB1 should be a reduction PBB. Reduction PBBs should have only
- one write. */
- gcc_assert (PBB_IS_REDUCTION (pbb1)
- && number_of_write_pdrs (pbb1) == 1);
+ isl_space *space = isl_map_get_space (map);
+ int n = isl_space_dim (space, isl_dim_out);
- for (i = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb1), i, pdr); i++)
- if (PDR_TYPE (pdr) == PDR_WRITE)
- break;
-
- return same_pdr_p (pdr, pdr1) && same_pdr_p (pdr, pdr2);
+ isl_space_free (space);
+ return isl_map_add_dims (map, isl_dim_out, max - n);
}
-/* Return true when the data dependence relation between the data
- references PDR1 belonging to PBB1 and PDR2 belonging to PBB2 is
- part of a reduction. */
-
-static inline bool
-reduction_dr_p (poly_bb_p pbb1, poly_bb_p pbb2,
- poly_dr_p pdr1, poly_dr_p pdr2)
-{
- if (PBB_IS_REDUCTION (pbb1))
- return reduction_dr_1 (pbb1, pdr1, pdr2);
+/* Structure used to pass parameters to extend_schedule_1. */
- if (PBB_IS_REDUCTION (pbb2))
- return reduction_dr_1 (pbb2, pdr2, pdr1);
-
- return false;
-}
+struct extend_schedule_str {
+ int max;
+ isl_union_map *umap;
+};
-/* Returns true when the PBB_TRANSFORMED_SCATTERING functions of PBB1
- and PBB2 respect the data dependences of PBB_ORIGINAL_SCATTERING
- functions. */
+/* Helper function for extend_schedule. */
-static bool
-graphite_legal_transform_dr (poly_bb_p pbb1, poly_bb_p pbb2,
- poly_dr_p pdr1, poly_dr_p pdr2)
+static isl_stat
+extend_schedule_1 (__isl_take isl_map *map, void *user)
{
- ppl_Polyhedron_t st1, st2;
- ppl_Pointset_Powerset_C_Polyhedron_t po, pt;
- graphite_dim_t ddim1, otdim1, otdim2, ttdim1, ttdim2;
- ppl_Pointset_Powerset_C_Polyhedron_t temp;
- ppl_dimension_type pdim;
- bool is_empty_p;
- poly_ddr_p pddr;
- ppl_Pointset_Powerset_C_Polyhedron_t d1 = PBB_DOMAIN (pbb1);
- ppl_Pointset_Powerset_C_Polyhedron_t d2 = PBB_DOMAIN (pbb2);
-
- if (reduction_dr_p (pbb1, pbb2, pdr1, pdr2))
- return true;
-
- pddr = pddr_original_scattering (pbb1, pbb2, pdr1, pdr2);
- if (!pddr)
- return true;
-
- po = PDDR_DDP (pddr);
-
- if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "\nloop carries dependency.\n");
-
- st1 = PBB_TRANSFORMED_SCATTERING (pbb1);
- st2 = PBB_TRANSFORMED_SCATTERING (pbb2);
- ddim1 = pbb_dim_iter_domain (pbb1);
- otdim1 = pbb_nb_scattering_orig (pbb1);
- otdim2 = pbb_nb_scattering_orig (pbb2);
- ttdim1 = pbb_nb_scattering_transform (pbb1);
- ttdim2 = pbb_nb_scattering_transform (pbb2);
-
- /* Copy the PO polyhedron into the TEMP, so it is not destroyed.
- Keep in mind, that PO polyhedron might be restored from the cache
- and should not be modified! */
- ppl_Pointset_Powerset_C_Polyhedron_space_dimension (po, &pdim);
- ppl_new_Pointset_Powerset_C_Polyhedron_from_space_dimension (&temp, pdim, 0);
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (temp, po);
-
- pddr = dependence_polyhedron (pbb1, pbb2, d1, d2, pdr1, pdr2, st1, st2,
- false, false);
- pt = PDDR_DDP (pddr);
-
- /* Extend PO and PT to have the same dimensions. */
- ppl_insert_dimensions_pointset (temp, otdim1, ttdim1);
- ppl_insert_dimensions_pointset (temp, otdim1 + ttdim1 + ddim1 + otdim2, ttdim2);
- ppl_insert_dimensions_pointset (pt, 0, otdim1);
- ppl_insert_dimensions_pointset (pt, otdim1 + ttdim1 + ddim1, otdim2);
-
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (temp, pt);
- is_empty_p = ppl_Pointset_Powerset_C_Polyhedron_is_empty (temp);
-
- ppl_delete_Pointset_Powerset_C_Polyhedron (temp);
- free_poly_ddr (pddr);
-
- return is_empty_p;
+ 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 true when the data dependence relation for PBB1 and PBB2 is
- part of a reduction. */
+/* Return a relation that has uniform output dimensions. */
-static inline bool
-reduction_ddr_p (poly_bb_p pbb1, poly_bb_p pbb2)
+static __isl_give isl_union_map *
+extend_schedule (__isl_take isl_union_map *x)
{
- return pbb1 == pbb2 && PBB_IS_REDUCTION (pbb1);
+ 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);
}
-/* Iterates over the data references of PBB1 and PBB2 and detect
- whether the transformed schedule is correct. */
+/* Applies SCHEDULE to the in and out dimensions of the dependences
+ DEPS and return the resulting relation. */
-static bool
-graphite_legal_transform_bb (poly_bb_p pbb1, poly_bb_p pbb2)
+static isl_map *
+apply_schedule_on_deps (__isl_keep isl_union_map *schedule,
+ __isl_keep isl_union_map *deps)
{
- int i, j;
- poly_dr_p pdr1, pdr2;
-
- if (!PBB_PDR_DUPLICATES_REMOVED (pbb1))
- pbb_remove_duplicate_pdrs (pbb1);
-
- if (!PBB_PDR_DUPLICATES_REMOVED (pbb2))
- pbb_remove_duplicate_pdrs (pbb2);
+ 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 (reduction_ddr_p (pbb1, pbb2))
- return true;
+ if (!isl_union_map_is_empty (ux))
+ return isl_map_from_union_map (ux);
- for (i = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb1), i, pdr1); i++)
- for (j = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb2), j, pdr2); j++)
- if (!graphite_legal_transform_dr (pbb1, pbb2, pdr1, pdr2))
- return false;
-
- return true;
+ isl_union_map_free (ux);
+ return NULL;
}
-/* Iterates over the SCOP and detect whether the transformed schedule
- is correct. */
+/* 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
-graphite_legal_transform (scop_p scop)
-{
- int i, j;
- poly_bb_p pbb1, pbb2;
-
- timevar_push (TV_GRAPHITE_DATA_DEPS);
-
- for (i = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), i, pbb1); i++)
- for (j = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), j, pbb2); j++)
- if (!graphite_legal_transform_bb (pbb1, pbb2))
- {
- timevar_pop (TV_GRAPHITE_DATA_DEPS);
- return false;
- }
-
- timevar_pop (TV_GRAPHITE_DATA_DEPS);
- return true;
-}
-
-/* Remove all the dimensions except alias information at dimension
- ALIAS_DIM. */
-
-static void
-build_alias_set_powerset (ppl_Pointset_Powerset_C_Polyhedron_t alias_powerset,
- ppl_dimension_type alias_dim)
-{
- ppl_dimension_type *ds;
- ppl_dimension_type access_dim;
- unsigned i, pos = 0;
-
- ppl_Pointset_Powerset_C_Polyhedron_space_dimension (alias_powerset,
- &access_dim);
- ds = XNEWVEC (ppl_dimension_type, access_dim-1);
- for (i = 0; i < access_dim; i++)
- {
- if (i == alias_dim)
- continue;
-
- ds[pos] = i;
- pos++;
- }
-
- ppl_Pointset_Powerset_C_Polyhedron_remove_space_dimensions (alias_powerset,
- ds,
- access_dim - 1);
- free (ds);
-}
-
-/* Return true when PDR1 and PDR2 may alias. */
-
-static bool
-poly_drs_may_alias_p (poly_dr_p pdr1, poly_dr_p pdr2)
+carries_deps (__isl_keep isl_union_map *schedule,
+ __isl_keep isl_union_map *deps,
+ int depth)
{
- ppl_Pointset_Powerset_C_Polyhedron_t alias_powerset1, alias_powerset2;
- ppl_Pointset_Powerset_C_Polyhedron_t accesses1 = PDR_ACCESSES (pdr1);
- ppl_Pointset_Powerset_C_Polyhedron_t accesses2 = PDR_ACCESSES (pdr2);
- ppl_dimension_type alias_dim1 = pdr_alias_set_dim (pdr1);
- ppl_dimension_type alias_dim2 = pdr_alias_set_dim (pdr2);
- int empty_p;
-
- ppl_new_Pointset_Powerset_C_Polyhedron_from_Pointset_Powerset_C_Polyhedron
- (&alias_powerset1, accesses1);
- ppl_new_Pointset_Powerset_C_Polyhedron_from_Pointset_Powerset_C_Polyhedron
- (&alias_powerset2, accesses2);
-
- build_alias_set_powerset (alias_powerset1, alias_dim1);
- build_alias_set_powerset (alias_powerset2, alias_dim2);
-
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign
- (alias_powerset1, alias_powerset2);
-
- empty_p = ppl_Pointset_Powerset_C_Polyhedron_is_empty (alias_powerset1);
-
- ppl_delete_Pointset_Powerset_C_Polyhedron (alias_powerset1);
- ppl_delete_Pointset_Powerset_C_Polyhedron (alias_powerset2);
-
- return !empty_p;
-}
-
-/* Returns TRUE when the dependence polyhedron between PDR1 and
- PDR2 represents a loop carried dependence at level LEVEL. */
-
-static bool
-graphite_carried_dependence_level_k (poly_dr_p pdr1, poly_dr_p pdr2,
- int level)
-{
- poly_bb_p pbb1 = PDR_PBB (pdr1);
- poly_bb_p pbb2 = PDR_PBB (pdr2);
- ppl_Pointset_Powerset_C_Polyhedron_t d1 = PBB_DOMAIN (pbb1);
- ppl_Pointset_Powerset_C_Polyhedron_t d2 = PBB_DOMAIN (pbb2);
- ppl_Polyhedron_t so1 = PBB_TRANSFORMED_SCATTERING (pbb1);
- ppl_Polyhedron_t so2 = PBB_TRANSFORMED_SCATTERING (pbb2);
- ppl_Pointset_Powerset_C_Polyhedron_t po;
- ppl_Pointset_Powerset_C_Polyhedron_t eqpp;
- graphite_dim_t tdim1 = pbb_nb_scattering_transform (pbb1);
- graphite_dim_t ddim1 = pbb_dim_iter_domain (pbb1);
- ppl_dimension_type dim;
- bool empty_p;
- poly_ddr_p pddr;
- int obj_base_set1 = PDR_BASE_OBJECT_SET (pdr1);
- int obj_base_set2 = PDR_BASE_OBJECT_SET (pdr2);
-
- if ((pdr_read_p (pdr1) && pdr_read_p (pdr2))
- || !poly_drs_may_alias_p (pdr1, pdr2))
+ if (isl_union_map_is_empty (deps))
return false;
- if (obj_base_set1 != obj_base_set2)
- return true;
-
- if (PDR_NB_SUBSCRIPTS (pdr1) != PDR_NB_SUBSCRIPTS (pdr2))
+ isl_map *x = apply_schedule_on_deps (schedule, deps);
+ if (x == NULL)
return false;
- pddr = dependence_polyhedron (pbb1, pbb2, d1, d2, pdr1, pdr2, so1, so2,
- true, 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)));
- if (pddr_is_empty (pddr))
- return false;
-
- po = PDDR_DDP (pddr);
- ppl_Pointset_Powerset_C_Polyhedron_space_dimension (po, &dim);
- eqpp = build_pairwise_scheduling_inequality (dim, level, tdim1 + ddim1, 1);
+ for (int i = 0; i < depth - 1; i++)
+ lex = isl_map_equate (lex, isl_dim_in, i, isl_dim_out, i);
- ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (eqpp, po);
- empty_p = ppl_Pointset_Powerset_C_Polyhedron_is_empty (eqpp);
+ /* 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);
- ppl_delete_Pointset_Powerset_C_Polyhedron (eqpp);
- return !empty_p;
+ isl_map_free (x);
+ return res;
}
-/* Check data dependency between PBB1 and PBB2 at level LEVEL. */
+/* 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. */
-bool
-dependency_between_pbbs_p (poly_bb_p pbb1, poly_bb_p pbb2, int level)
+void
+scop_get_dependences (scop_p scop)
{
- int i, j;
- poly_dr_p pdr1, pdr2;
-
- timevar_push (TV_GRAPHITE_DATA_DEPS);
-
- for (i = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb1), i, pdr1); i++)
- for (j = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb2), j, pdr2); j++)
- if (graphite_carried_dependence_level_k (pdr1, pdr2, level))
- {
- timevar_pop (TV_GRAPHITE_DATA_DEPS);
- return true;
- }
-
- timevar_pop (TV_GRAPHITE_DATA_DEPS);
- return false;
-}
+ if (scop->dependence)
+ return;
-/* Pretty print to FILE all the data dependences of SCoP in DOT
- format. */
+ 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);
-static void
-dot_deps_1 (FILE *file, scop_p scop)
-{
- int i, j, k, l;
- poly_bb_p pbb1, pbb2;
- poly_dr_p pdr1, pdr2;
-
- fputs ("digraph all {\n", file);
-
- for (i = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), i, pbb1); i++)
- for (j = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), j, pbb2); j++)
- for (k = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb1), k, pdr1); k++)
- for (l = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb2), l, pdr2); l++)
- if (pddr_original_scattering (pbb1, pbb2, pdr1, pdr2))
- fprintf (file, "S%d_D%d -> S%d_D%d\n",
- pbb_index (pbb1), PDR_ID (pdr1),
- pbb_index (pbb2), PDR_ID (pdr2));
-
- fputs ("}\n\n", file);
-}
+ 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");
+ }
-/* Display all the data dependences in SCoP using dotty. */
+ 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");
+ }
-void
-dot_deps (scop_p scop)
-{
- /* When debugging, enable the following code. This cannot be used
- in production compilers because it calls "system". */
-#if 0
- int x;
- FILE *stream = fopen ("/tmp/scopdeps.dot", "w");
- gcc_assert (stream);
-
- dot_deps_1 (stream, scop);
- fclose (stream);
-
- x = system ("dotty /tmp/scopdeps.dot");
-#else
- dot_deps_1 (stderr, scop);
-#endif
+ scop->dependence = dependences;
}
-
-#endif
+#endif /* HAVE_isl */