OSDN Git Service

Replace tabs with spaces in .texi files.
[pf3gnuchains/gcc-fork.git] / gcc / graphite-dependences.c
index ccb32d6..b77de08 100644 (file)
@@ -50,52 +50,78 @@ along with GCC; see the file COPYING3.  If not see
 #include "graphite-poly.h"
 #include "graphite-dependences.h"
 
-/* Creates a new polyhedral data reference pair and
-   returns it.  Parameter SOURCE denotes a source data reference
-   while parameter SINK denotes a sink data reference.  Both
-   SOURCE and SINK define a pair of references, thus they
-   define an edge in DDG (Data Dependence Graph).  */
+/* 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_dr_pair_p
-new_poly_dr_pair (poly_dr_p source,
-                  poly_dr_p sink,
-                  ppl_Pointset_Powerset_C_Polyhedron_t ddp)
+static poly_ddr_p
+new_poly_ddr (poly_dr_p source, poly_dr_p sink,
+             ppl_Pointset_Powerset_C_Polyhedron_t ddp)
 {
-  poly_dr_pair_p pdrpp;
+  poly_ddr_p pddr;
 
-  pdrpp = XNEW (struct poly_dr_pair);
-  pdrpp->source = source;
-  pdrpp->sink = sink;
-  pdrpp->ddp = ddp;
+  pddr = XNEW (struct poly_ddr);
+  PDDR_SOURCE (pddr) = source;
+  PDDR_SINK (pddr) = sink;
+  PDDR_DDP (pddr) = ddp;
+  PDDR_KIND (pddr) = unknown_dependence;
 
-  return pdrpp;
+  return pddr;
 }
 
-/* Comparison function for poly_dr_pair hash table.  */
+/* 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_dr_pair_p (const void *pdrpp1, const void *pdrpp2)
+eq_poly_ddr_p (const void *pddr1, const void *pddr2)
 {
-  const struct poly_dr_pair *p1 = (const struct poly_dr_pair *) pdrpp1;
-  const struct poly_dr_pair *p2 = (const struct poly_dr_pair *) pdrpp2;
+  const struct poly_ddr *p1 = (const struct poly_ddr *) pddr1;
+  const struct poly_ddr *p2 = (const struct poly_ddr *) pddr2;
 
-  return (p1->source == p2->source
-          && p1->sink == p2->sink);
+  return (PDDR_SOURCE (p1) == PDDR_SOURCE (p2)
+          && PDDR_SINK (p1) == PDDR_SINK (p2));
 }
 
-/* Hash function for poly_dr_pair hashtable.  */
+/* Hash function for poly_ddr hashtable.  */
 
 hashval_t
-hash_poly_dr_pair_p (const void *pdrpp)
+hash_poly_ddr_p (const void *pddr)
+{
+  const struct poly_ddr *p = (const struct poly_ddr *) pddr;
+
+  return (hashval_t) ((long) PDDR_SOURCE (p) + (long) PDDR_SINK (p));
+}
+
+/* Returns true when PDDR has no dependence.  */
+
+static bool
+pddr_is_empty (poly_ddr_p pddr)
 {
-  const struct poly_dr_pair *p = (const struct poly_dr_pair *) pdrpp;
+  if (PDDR_KIND (pddr) != unknown_dependence)
+    return PDDR_KIND (pddr) == no_dependence ? true : false;
 
-  return (hashval_t) ((long) p->source + (long) p->sink);
+  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
+   Maps the dimensions [0, ..., cut - 1] of polyhedron P to OFFSET
    and the dimensions [cut, ..., nb_dim] to DIM - GDIM.  */
 
 static ppl_Pointset_Powerset_C_Polyhedron_t
@@ -362,9 +388,18 @@ build_lexicographically_gt_constraint (ppl_Pointset_Powerset_C_Polyhedron_t *res
     }
 }
 
-/* Build the dependence polyhedron for data references PDR1 and PDR2.  */
+/* Build the dependence polyhedron for data references PDR1 and PDR2.
+   The layout of the dependence polyhedron is:
+
+   T1|I1|T2|I2|S1|S2|G
 
-static ppl_Pointset_Powerset_C_Polyhedron_t
+   with
+   | T1 and T2 the scattering dimensions for PDR1 and PDR2
+   | I1 and I2 the iteration domains
+   | S1 and S2 the subscripts
+   | G the global parameters.  */
+
+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,
@@ -384,12 +419,18 @@ dependence_polyhedron_1 (poly_bb_p pbb1, poly_bb_p pbb2,
   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;
+  graphite_dim_t dim = tdim1 + tdim2 + dim1 + dim2 - gdim;
   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;
+  ppl_Pointset_Powerset_C_Polyhedron_t context;
 
   gcc_assert (PBB_SCOP (pbb1) == PBB_SCOP (pbb2));
+
+  ppl_new_Pointset_Powerset_C_Polyhedron_from_Pointset_Powerset_C_Polyhedron
+    (&context, SCOP_CONTEXT (scop));
+  ppl_insert_dimensions_pointset (context, 0, dim - gdim);
+
   ppl_new_Pointset_Powerset_C_Polyhedron_from_C_Polyhedron (&sc1, s1);
   ppl_new_Pointset_Powerset_C_Polyhedron_from_C_Polyhedron (&sc2, s2);
 
@@ -407,6 +448,7 @@ dependence_polyhedron_1 (poly_bb_p pbb1, poly_bb_p pbb2,
   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, context);
   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);
@@ -414,6 +456,7 @@ dependence_polyhedron_1 (poly_bb_p pbb1, poly_bb_p pbb2,
   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 (context);
   ppl_delete_Pointset_Powerset_C_Polyhedron (id1);
   ppl_delete_Pointset_Powerset_C_Polyhedron (id2);
   ppl_delete_Pointset_Powerset_C_Polyhedron (sc1);
@@ -427,13 +470,14 @@ dependence_polyhedron_1 (poly_bb_p pbb1, poly_bb_p pbb2,
   if (!ppl_Pointset_Powerset_C_Polyhedron_is_empty (res))
     build_lexicographically_gt_constraint (&res, dim, MIN (tdim1, tdim2),
                                           tdim1 + ddim1, direction);
-  return res;
+
+  return new_poly_ddr (pdr1, pdr2, res);
 }
 
 /* Build the dependence polyhedron for data references PDR1 and PDR2.
    If possible use already cached information.  */
 
-static ppl_Pointset_Powerset_C_Polyhedron_t
+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,
@@ -442,42 +486,123 @@ dependence_polyhedron (poly_bb_p pbb1, poly_bb_p pbb2,
                       bool direction,
                       bool original_scattering_p)
 {
-  poly_dr_pair tmp;
   PTR *x = NULL;
-  ppl_Pointset_Powerset_C_Polyhedron_t res;
+  poly_ddr_p res;
 
   if (original_scattering_p)
     {
+      struct poly_ddr tmp;
+
       tmp.source = pdr1;
       tmp.sink = pdr2;
-      x = htab_find_slot (SCOP_ORIGINAL_PDR_PAIRS (PBB_SCOP (pbb1)),
+      x = htab_find_slot (SCOP_ORIGINAL_PDDRS (PBB_SCOP (pbb1)),
                           &tmp, INSERT);
 
       if (x && *x)
-        {
-          if (dump_file && (dump_flags & TDF_DETAILS))
-            fprintf (dump_file, "\nddp cache: hit.\n");
-          return ((poly_dr_pair *)*x)->ddp;
-        }
-      else if (dump_file && (dump_flags & TDF_DETAILS))
-        fprintf (dump_file, "\nddp cache: miss.\n");
+       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)
-    {
-      gcc_assert (x && *x == NULL);
-      *x = new_poly_dr_pair (pdr1, pdr2, res);
-
-      if (dump_file && (dump_flags & TDF_DETAILS))
-        fprintf (dump_file, "\nddp cache: add element.\n");
-    }
+    *x = res;
 
   return res;
 }
 
+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 (cannot judge dependency
+   under polyhedral model).  */
+
+static poly_ddr_p
+pddr_original_scattering (poly_bb_p pbb1, poly_bb_p pbb2,
+                         poly_dr_p pdr1, poly_dr_p pdr2)
+{
+  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;
+}
+
+/* Returns the PDDR corresponding to the transformed schedule, or NULL if
+   the dependence relation is empty or unknown (cannot judge dependency
+   under polyhedral model).  */
+
+static poly_ddr_p
+pddr_transformed_scattering (poly_bb_p pbb1, poly_bb_p pbb2,
+                            poly_dr_p pdr1, poly_dr_p pdr2)
+{
+  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 st1 = PBB_ORIGINAL_SCATTERING (pbb1);
+  ppl_Polyhedron_t st2 = 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, st1, st2,
+                               true, false);
+  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;
+
+  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);
+}
+
+/* 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);
+
+  if (PBB_IS_REDUCTION (pbb2))
+    return reduction_dr_1 (pbb2, pdr2, pdr1);
+
+  return false;
+}
+
 /* Returns true when the PBB_TRANSFORMED_SCATTERING functions of PBB1
    and PBB2 respect the data dependences of PBB_ORIGINAL_SCATTERING
    functions.  */
@@ -487,29 +612,24 @@ graphite_legal_transform_dr (poly_bb_p pbb1, poly_bb_p pbb2,
                             poly_dr_p pdr1, poly_dr_p pdr2)
 {
   ppl_Polyhedron_t st1, st2;
-  ppl_Pointset_Powerset_C_Polyhedron_t pt;
+  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;
-  ppl_Pointset_Powerset_C_Polyhedron_t po;
-
+  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);
-  graphite_dim_t sdim1 = PDR_NB_SUBSCRIPTS (pdr1) + 1;
-  graphite_dim_t sdim2 = PDR_NB_SUBSCRIPTS (pdr2) + 1;
 
-  if (sdim1 != sdim2)
+  if (reduction_dr_p (pbb1, pbb2, pdr1, pdr2))
     return true;
 
-  po = dependence_polyhedron (pbb1, pbb2, d1, d2, pdr1, pdr2, so1, so2,
-                             true, true);
-
-  if (ppl_Pointset_Powerset_C_Polyhedron_is_empty (po))
+  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");
 
@@ -528,8 +648,9 @@ graphite_legal_transform_dr (poly_bb_p pbb1, poly_bb_p pbb2,
   ppl_new_Pointset_Powerset_C_Polyhedron_from_space_dimension (&temp, pdim, 0);
   ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (temp, po);
 
-  pt = dependence_polyhedron (pbb1, pbb2, d1, d2, pdr1, pdr2, st1, st2,
-                             false, false);
+  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);
@@ -541,10 +662,20 @@ graphite_legal_transform_dr (poly_bb_p pbb1, poly_bb_p pbb2,
   is_empty_p = ppl_Pointset_Powerset_C_Polyhedron_is_empty (temp);
 
   ppl_delete_Pointset_Powerset_C_Polyhedron (temp);
-  ppl_delete_Pointset_Powerset_C_Polyhedron (pt);
+  free_poly_ddr (pddr);
+
   return is_empty_p;
 }
 
+/* Return true when the data dependence relation for PBB1 and PBB2 is
+   part of a reduction.  */
+
+static inline bool
+reduction_ddr_p (poly_bb_p pbb1, poly_bb_p pbb2)
+{
+  return pbb1 == pbb2 && PBB_IS_REDUCTION (pbb1);
+}
+
 /* Iterates over the data references of PBB1 and PBB2 and detect
    whether the transformed schedule is correct.  */
 
@@ -554,10 +685,19 @@ graphite_legal_transform_bb (poly_bb_p pbb1, poly_bb_p pbb2)
   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);
+
+  if (reduction_ddr_p (pbb1, pbb2))
+    return true;
+
   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 false;
 
   return true;
 }
@@ -646,8 +786,7 @@ poly_drs_may_alias_p (poly_dr_p pdr1, poly_dr_p pdr2)
 }
 
 /* Returns TRUE when the dependence polyhedron between PDR1 and
-   PDR2 represents a loop carried dependence at level LEVEL. Otherwise
-   return FALSE.  */
+   PDR2 represents a loop carried dependence at level LEVEL.  */
 
 static bool
 graphite_carried_dependence_level_k (poly_dr_p pdr1, poly_dr_p pdr2,
@@ -661,28 +800,31 @@ graphite_carried_dependence_level_k (poly_dr_p pdr1, poly_dr_p pdr2,
   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 sdim1 = PDR_NB_SUBSCRIPTS (pdr1) + 1;
-  graphite_dim_t sdim2 = PDR_NB_SUBSCRIPTS (pdr2) + 1;
   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_TYPE (pdr1) == PDR_READ && PDR_TYPE (pdr2) == PDR_READ)
+  if ((pdr_read_p (pdr1) && pdr_read_p (pdr2))
       || !poly_drs_may_alias_p (pdr1, pdr2))
     return false;
 
-  if (sdim1 != sdim2)
+  if (obj_base_set1 != obj_base_set2)
     return true;
 
-  po = dependence_polyhedron (pbb1, pbb2, d1, d2, pdr1, pdr2, so1, so2,
-                             true, false);
-  if (ppl_Pointset_Powerset_C_Polyhedron_is_empty (po))
-    {
-      ppl_delete_Pointset_Powerset_C_Polyhedron (po);
-      return false;
-    }
+  if (PDR_NB_SUBSCRIPTS (pdr1) != PDR_NB_SUBSCRIPTS (pdr2))
+    return false;
+
+  pddr = dependence_polyhedron (pbb1, pbb2, d1, d2, pdr1, pdr2, so1, so2,
+                               true, false);
 
+  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);
 
@@ -715,4 +857,165 @@ dependency_between_pbbs_p (poly_bb_p pbb1, poly_bb_p pbb2, int level)
   return false;
 }
 
+/* Pretty print to FILE all the original data dependences of SCoP in
+   DOT format.  */
+
+static void
+dot_original_deps_stmt_1 (FILE *file, scop_p scop)
+{
+  int i, j, k, l;
+  poly_bb_p pbb1, pbb2;
+  poly_dr_p pdr1, pdr2;
+
+  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, "OS%d -> OS%d\n",
+                        pbb_index (pbb1), pbb_index (pbb2));
+               goto done;
+             }
+      done:;
+      }
+}
+
+/* Pretty print to FILE all the transformed data dependences of SCoP in
+   DOT format.  */
+
+static void
+dot_transformed_deps_stmt_1 (FILE *file, scop_p scop)
+{
+  int i, j, k, l;
+  poly_bb_p pbb1, pbb2;
+  poly_dr_p pdr1, pdr2;
+
+  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_transformed_scattering (pbb1, pbb2, pdr1, pdr2))
+             {
+               fprintf (file, "TS%d -> TS%d\n",
+                        pbb_index (pbb1), pbb_index (pbb2));
+               goto done;
+             }
+      done:;
+      }
+}
+
+
+/* Pretty print to FILE all the data dependences of SCoP in DOT
+   format.  */
+
+static void
+dot_deps_stmt_1 (FILE *file, scop_p scop)
+{
+  fputs ("digraph all {\n", file);
+
+  dot_original_deps_stmt_1 (file, scop);
+  dot_transformed_deps_stmt_1 (file, scop);
+
+  fputs ("}\n\n", file);
+}
+
+/* Pretty print to FILE all the original data dependences of SCoP in
+   DOT format.  */
+
+static void
+dot_original_deps (FILE *file, scop_p scop)
+{
+  int i, j, k, l;
+  poly_bb_p pbb1, pbb2;
+  poly_dr_p pdr1, pdr2;
+
+  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, "OS%d_D%d -> OS%d_D%d\n",
+                    pbb_index (pbb1), PDR_ID (pdr1),
+                    pbb_index (pbb2), PDR_ID (pdr2));
+}
+
+/* Pretty print to FILE all the transformed data dependences of SCoP in
+   DOT format.  */
+
+static void
+dot_transformed_deps (FILE *file, scop_p scop)
+{
+  int i, j, k, l;
+  poly_bb_p pbb1, pbb2;
+  poly_dr_p pdr1, pdr2;
+
+  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_transformed_scattering (pbb1, pbb2, pdr1, pdr2))
+           fprintf (file, "TS%d_D%d -> TS%d_D%d\n",
+                    pbb_index (pbb1), PDR_ID (pdr1),
+                    pbb_index (pbb2), PDR_ID (pdr2));
+}
+
+/* Pretty print to FILE all the data dependences of SCoP in DOT
+   format.  */
+
+static void
+dot_deps_1 (FILE *file, scop_p scop)
+{
+  fputs ("digraph all {\n", file);
+
+  dot_original_deps (file, scop);
+  dot_transformed_deps (file, scop);
+
+  fputs ("}\n\n", file);
+}
+
+/* Display all the data dependences in SCoP using dotty.  */
+
+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
+}
+
+/* Display all the statement dependences in SCoP using dotty.  */
+
+void
+dot_deps_stmt (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_stmt_1 (stream, scop);
+  fclose (stream);
+
+  x = system ("dotty /tmp/scopdeps.dot");
+#else
+  dot_deps_stmt_1 (stderr, scop);
+#endif
+}
+
 #endif