Clarify comments and use build_pddr.
[gcc.git] / gcc / graphite-dependences.c
1 /* Data dependence analysis for Graphite.
2 Copyright (C) 2009 Free Software Foundation, Inc.
3 Contributed by Sebastian Pop <sebastian.pop@amd.com> and
4 Konrad Trifunovic <konrad.trifunovic@inria.fr>.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
12
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "ggc.h"
27 #include "tree.h"
28 #include "rtl.h"
29 #include "basic-block.h"
30 #include "diagnostic.h"
31 #include "tree-flow.h"
32 #include "toplev.h"
33 #include "tree-dump.h"
34 #include "timevar.h"
35 #include "cfgloop.h"
36 #include "tree-chrec.h"
37 #include "tree-data-ref.h"
38 #include "tree-scalar-evolution.h"
39 #include "tree-pass.h"
40 #include "domwalk.h"
41 #include "pointer-set.h"
42 #include "gimple.h"
43
44 #ifdef HAVE_cloog
45 #include "cloog/cloog.h"
46 #include "ppl_c.h"
47 #include "sese.h"
48 #include "graphite-ppl.h"
49 #include "graphite.h"
50 #include "graphite-poly.h"
51 #include "graphite-dependences.h"
52
53 /* Returns a new polyhedral Data Dependence Relation (DDR). SOURCE is
54 the source data reference, SINK is the sink data reference. SOURCE
55 and SINK define an edge in the Data Dependence Graph (DDG). */
56
57 static poly_ddr_p
58 new_poly_ddr (poly_dr_p source, poly_dr_p sink,
59 ppl_Pointset_Powerset_C_Polyhedron_t ddp)
60 {
61 poly_ddr_p pddr;
62
63 pddr = XNEW (struct poly_ddr);
64 PDDR_SOURCE (pddr) = source;
65 PDDR_SINK (pddr) = sink;
66 PDDR_DDP (pddr) = ddp;
67 PDDR_KIND (pddr) = unknown_dependence;
68
69 return pddr;
70 }
71
72 /* Free the poly_ddr_p P. */
73
74 void
75 free_poly_ddr (void *p)
76 {
77 poly_ddr_p pddr = (poly_ddr_p) p;
78 ppl_delete_Pointset_Powerset_C_Polyhedron (PDDR_DDP (pddr));
79 free (pddr);
80 }
81
82 /* Comparison function for poly_ddr hash table. */
83
84 int
85 eq_poly_ddr_p (const void *pddr1, const void *pddr2)
86 {
87 const struct poly_ddr *p1 = (const struct poly_ddr *) pddr1;
88 const struct poly_ddr *p2 = (const struct poly_ddr *) pddr2;
89
90 return (PDDR_SOURCE (p1) == PDDR_SOURCE (p2)
91 && PDDR_SINK (p1) == PDDR_SINK (p2));
92 }
93
94 /* Hash function for poly_ddr hashtable. */
95
96 hashval_t
97 hash_poly_ddr_p (const void *pddr)
98 {
99 const struct poly_ddr *p = (const struct poly_ddr *) pddr;
100
101 return (hashval_t) ((long) PDDR_SOURCE (p) + (long) PDDR_SINK (p));
102 }
103
104 /* Returns true when PDDR has no dependence. */
105
106 static bool
107 pddr_is_empty (poly_ddr_p pddr)
108 {
109 if (PDDR_KIND (pddr) != unknown_dependence)
110 return PDDR_KIND (pddr) == no_dependence ? true : false;
111
112 if (ppl_Pointset_Powerset_C_Polyhedron_is_empty (PDDR_DDP (pddr)))
113 {
114 PDDR_KIND (pddr) = no_dependence;
115 return true;
116 }
117
118 PDDR_KIND (pddr) = has_dependence;
119 return false;
120 }
121
122 /* Returns a polyhedron of dimension DIM.
123
124 Maps the dimensions [0, ..., cut - 1] of polyhedron P to OFFSET
125 and the dimensions [cut, ..., nb_dim] to DIM - GDIM. */
126
127 static ppl_Pointset_Powerset_C_Polyhedron_t
128 map_into_dep_poly (graphite_dim_t dim, graphite_dim_t gdim,
129 ppl_Pointset_Powerset_C_Polyhedron_t p,
130 graphite_dim_t cut,
131 graphite_dim_t offset)
132 {
133 ppl_Pointset_Powerset_C_Polyhedron_t res;
134
135 ppl_new_Pointset_Powerset_C_Polyhedron_from_Pointset_Powerset_C_Polyhedron
136 (&res, p);
137 ppl_insert_dimensions_pointset (res, 0, offset);
138 ppl_insert_dimensions_pointset (res, offset + cut,
139 dim - offset - cut - gdim);
140
141 return res;
142 }
143
144 /* Swap [cut0, ..., cut1] to the end of DR: "a CUT0 b CUT1 c" is
145 transformed into "a CUT0 c CUT1' b"
146
147 Add NB0 zeros before "a": "00...0 a CUT0 c CUT1' b"
148 Add NB1 zeros between "a" and "c": "00...0 a 00...0 c CUT1' b"
149 Add DIM - NB0 - NB1 - PDIM zeros between "c" and "b":
150 "00...0 a 00...0 c 00...0 b". */
151
152 static ppl_Pointset_Powerset_C_Polyhedron_t
153 map_dr_into_dep_poly (graphite_dim_t dim,
154 ppl_Pointset_Powerset_C_Polyhedron_t dr,
155 graphite_dim_t cut0, graphite_dim_t cut1,
156 graphite_dim_t nb0, graphite_dim_t nb1)
157 {
158 ppl_dimension_type pdim;
159 ppl_dimension_type *map;
160 ppl_Pointset_Powerset_C_Polyhedron_t res;
161 ppl_dimension_type i;
162
163 ppl_new_Pointset_Powerset_C_Polyhedron_from_Pointset_Powerset_C_Polyhedron
164 (&res, dr);
165 ppl_Pointset_Powerset_C_Polyhedron_space_dimension (res, &pdim);
166
167 map = (ppl_dimension_type *) XNEWVEC (ppl_dimension_type, pdim);
168
169 /* First mapping: move 'g' vector to right position. */
170 for (i = 0; i < cut0; i++)
171 map[i] = i;
172
173 for (i = cut0; i < cut1; i++)
174 map[i] = pdim - cut1 + i;
175
176 for (i = cut1; i < pdim; i++)
177 map[i] = cut0 + i - cut1;
178
179 ppl_Pointset_Powerset_C_Polyhedron_map_space_dimensions (res, map, pdim);
180 free (map);
181
182 /* After swapping 's' and 'g' vectors, we have to update a new cut. */
183 cut1 = pdim - cut1 + cut0;
184
185 ppl_insert_dimensions_pointset (res, 0, nb0);
186 ppl_insert_dimensions_pointset (res, nb0 + cut0, nb1);
187 ppl_insert_dimensions_pointset (res, nb0 + nb1 + cut1,
188 dim - nb0 - nb1 - pdim);
189
190 return res;
191 }
192
193 /* Builds subscript equality constraints. */
194
195 static ppl_Pointset_Powerset_C_Polyhedron_t
196 dr_equality_constraints (graphite_dim_t dim,
197 graphite_dim_t pos, graphite_dim_t nb_subscripts)
198 {
199 ppl_Polyhedron_t eqs;
200 ppl_Pointset_Powerset_C_Polyhedron_t res;
201 graphite_dim_t i;
202
203 ppl_new_C_Polyhedron_from_space_dimension (&eqs, dim, 0);
204
205 for (i = 0; i < nb_subscripts; i++)
206 {
207 ppl_Constraint_t cstr
208 = ppl_build_relation (dim, pos + i, pos + i + nb_subscripts,
209 0, PPL_CONSTRAINT_TYPE_EQUAL);
210 ppl_Polyhedron_add_constraint (eqs, cstr);
211 ppl_delete_Constraint (cstr);
212 }
213
214 ppl_new_Pointset_Powerset_C_Polyhedron_from_C_Polyhedron (&res, eqs);
215 ppl_delete_Polyhedron (eqs);
216 return res;
217 }
218
219 /* Builds scheduling inequality constraints: when DIRECTION is
220 1 builds a GE constraint,
221 0 builds an EQ constraint,
222 -1 builds a LE constraint. */
223
224 static ppl_Pointset_Powerset_C_Polyhedron_t
225 build_pairwise_scheduling (graphite_dim_t dim,
226 graphite_dim_t pos,
227 graphite_dim_t offset,
228 int direction)
229 {
230 ppl_Pointset_Powerset_C_Polyhedron_t res;
231 ppl_Polyhedron_t equalities;
232 ppl_Constraint_t cstr;
233
234 ppl_new_C_Polyhedron_from_space_dimension (&equalities, dim, 0);
235
236 switch (direction)
237 {
238 case -1:
239 cstr = ppl_build_relation (dim, pos, pos + offset, 1,
240 PPL_CONSTRAINT_TYPE_LESS_OR_EQUAL);
241 break;
242
243 case 0:
244 cstr = ppl_build_relation (dim, pos, pos + offset, 0,
245 PPL_CONSTRAINT_TYPE_EQUAL);
246 break;
247
248 case 1:
249 cstr = ppl_build_relation (dim, pos, pos + offset, -1,
250 PPL_CONSTRAINT_TYPE_GREATER_OR_EQUAL);
251 break;
252
253 default:
254 gcc_unreachable ();
255 }
256
257 ppl_Polyhedron_add_constraint (equalities, cstr);
258 ppl_delete_Constraint (cstr);
259
260 ppl_new_Pointset_Powerset_C_Polyhedron_from_C_Polyhedron (&res, equalities);
261 ppl_delete_Polyhedron (equalities);
262 return res;
263 }
264
265 /* Returns true when adding to the RES dependence polyhedron the
266 lexicographical constraint: "DIM compared to DIM + OFFSET" returns
267 an empty polyhedron. The comparison depends on DIRECTION as: if
268 DIRECTION is equal to -1, the first dimension DIM to be compared
269 comes before the second dimension DIM + OFFSET, equal to 0 when DIM
270 and DIM + OFFSET are equal, and DIRECTION is set to 1 when DIM
271 comes after DIM + OFFSET. */
272
273 static bool
274 lexicographically_gt_p (ppl_Pointset_Powerset_C_Polyhedron_t res,
275 graphite_dim_t dim,
276 graphite_dim_t offset,
277 int direction, graphite_dim_t i)
278 {
279 ppl_Pointset_Powerset_C_Polyhedron_t ineq;
280 bool empty_p;
281
282 ineq = build_pairwise_scheduling (dim, i, offset, direction);
283 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (ineq, res);
284 empty_p = ppl_Pointset_Powerset_C_Polyhedron_is_empty (ineq);
285 if (!empty_p)
286 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, ineq);
287 ppl_delete_Pointset_Powerset_C_Polyhedron (ineq);
288
289 return !empty_p;
290 }
291
292 /* Add to a non empty polyhedron RES the precedence constraints for
293 the lexicographical comparison of time vectors in RES following the
294 lexicographical order. DIM is the dimension of the polyhedron RES.
295 TDIM is the number of loops common to the two statements that are
296 compared lexicographically, i.e. the number of loops containing
297 both statements. OFFSET is the number of dimensions needed to
298 represent the first statement, i.e. dimT1 + dimI1 in the layout of
299 the RES polyhedron: T1|I1|T2|I2|S1|S2|G. When DIRECTION is set to
300 1, compute the direct dependence from PDR1 to PDR2, and when
301 DIRECTION is -1, compute the reversed dependence relation, from
302 PDR2 to PDR1. */
303
304 static void
305 build_lexicographically_gt_constraint (ppl_Pointset_Powerset_C_Polyhedron_t *res,
306 graphite_dim_t dim,
307 graphite_dim_t tdim,
308 graphite_dim_t offset,
309 int direction)
310 {
311 graphite_dim_t i;
312
313 if (lexicographically_gt_p (*res, dim, offset, direction, 0))
314 return;
315
316 for (i = 0; i < tdim - 1; i++)
317 {
318 ppl_Pointset_Powerset_C_Polyhedron_t sceq;
319
320 /* All the dimensions up to I are equal, ... */
321 sceq = build_pairwise_scheduling (dim, i, offset, 0);
322 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (*res, sceq);
323 ppl_delete_Pointset_Powerset_C_Polyhedron (sceq);
324
325 /* ... and at depth I+1 they are not equal anymore. */
326 if (lexicographically_gt_p (*res, dim, offset, direction, i + 1))
327 return;
328 }
329
330 if (i == tdim - 1)
331 {
332 ppl_delete_Pointset_Powerset_C_Polyhedron (*res);
333 ppl_new_Pointset_Powerset_C_Polyhedron_from_space_dimension (res, dim, 1);
334 }
335 }
336
337 /* Build the dependence polyhedron for data references PDR1 and PDR2.
338 The layout of the dependence polyhedron is:
339
340 T1|I1|T2|I2|S1|S2|G
341
342 with
343 | T1 and T2 the scattering dimensions for PDR1 and PDR2
344 | I1 and I2 the iteration domains
345 | S1 and S2 the subscripts
346 | G the global parameters.
347
348 D1 and D2 are the iteration domains of PDR1 and PDR2.
349
350 SCAT1 and SCAT2 are the scattering polyhedra for PDR1 and PDR2.
351 When ORIGINAL_SCATTERING_P is true, then the scattering polyhedra
352 SCAT1 and SCAT2 correspond to the original scattering of the
353 program, otherwise they correspond to the transformed scattering.
354
355 When DIRECTION is set to 1, compute the direct dependence from PDR1
356 to PDR2, and when DIRECTION is -1, compute the reversed dependence
357 relation, from PDR2 to PDR1. */
358
359 static poly_ddr_p
360 dependence_polyhedron_1 (poly_bb_p pbb1, poly_bb_p pbb2,
361 ppl_Pointset_Powerset_C_Polyhedron_t d1,
362 ppl_Pointset_Powerset_C_Polyhedron_t d2,
363 poly_dr_p pdr1, poly_dr_p pdr2,
364 ppl_Polyhedron_t scat1, ppl_Polyhedron_t scat2,
365 int direction,
366 bool original_scattering_p)
367 {
368 scop_p scop = PBB_SCOP (pbb1);
369 graphite_dim_t tdim1 = original_scattering_p ?
370 pbb_nb_scattering_orig (pbb1) : pbb_nb_scattering_transform (pbb1);
371 graphite_dim_t tdim2 = original_scattering_p ?
372 pbb_nb_scattering_orig (pbb2) : pbb_nb_scattering_transform (pbb2);
373 graphite_dim_t ddim1 = pbb_dim_iter_domain (pbb1);
374 graphite_dim_t ddim2 = pbb_dim_iter_domain (pbb2);
375 graphite_dim_t sdim1 = PDR_NB_SUBSCRIPTS (pdr1) + 1;
376 graphite_dim_t gdim = scop_nb_params (scop);
377 graphite_dim_t dim1 = pdr_dim (pdr1);
378 graphite_dim_t dim2 = pdr_dim (pdr2);
379 graphite_dim_t dim = tdim1 + tdim2 + dim1 + dim2 - gdim;
380 ppl_Pointset_Powerset_C_Polyhedron_t res;
381 ppl_Pointset_Powerset_C_Polyhedron_t id1, id2, isc1, isc2, idr1, idr2;
382 ppl_Pointset_Powerset_C_Polyhedron_t sc1, sc2, dreq;
383 ppl_Pointset_Powerset_C_Polyhedron_t context;
384
385 gcc_assert (PBB_SCOP (pbb1) == PBB_SCOP (pbb2));
386
387 ppl_new_Pointset_Powerset_C_Polyhedron_from_Pointset_Powerset_C_Polyhedron
388 (&context, SCOP_CONTEXT (scop));
389 ppl_insert_dimensions_pointset (context, 0, dim - gdim);
390
391 ppl_new_Pointset_Powerset_C_Polyhedron_from_C_Polyhedron (&sc1, scat1);
392 ppl_new_Pointset_Powerset_C_Polyhedron_from_C_Polyhedron (&sc2, scat2);
393
394 id1 = map_into_dep_poly (dim, gdim, d1, ddim1, tdim1);
395 id2 = map_into_dep_poly (dim, gdim, d2, ddim2, tdim1 + ddim1 + tdim2);
396 isc1 = map_into_dep_poly (dim, gdim, sc1, ddim1 + tdim1, 0);
397 isc2 = map_into_dep_poly (dim, gdim, sc2, ddim2 + tdim2, tdim1 + ddim1);
398
399 idr1 = map_dr_into_dep_poly (dim, PDR_ACCESSES (pdr1), ddim1, ddim1 + gdim,
400 tdim1, tdim2 + ddim2);
401 idr2 = map_dr_into_dep_poly (dim, PDR_ACCESSES (pdr2), ddim2, ddim2 + gdim,
402 tdim1 + ddim1 + tdim2, sdim1);
403
404 /* Now add the subscript equalities. */
405 dreq = dr_equality_constraints (dim, tdim1 + ddim1 + tdim2 + ddim2, sdim1);
406
407 ppl_new_Pointset_Powerset_C_Polyhedron_from_space_dimension (&res, dim, 0);
408 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, context);
409 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, id1);
410 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, id2);
411 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, isc1);
412 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, isc2);
413 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, idr1);
414 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, idr2);
415 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (res, dreq);
416 ppl_delete_Pointset_Powerset_C_Polyhedron (context);
417 ppl_delete_Pointset_Powerset_C_Polyhedron (id1);
418 ppl_delete_Pointset_Powerset_C_Polyhedron (id2);
419 ppl_delete_Pointset_Powerset_C_Polyhedron (sc1);
420 ppl_delete_Pointset_Powerset_C_Polyhedron (sc2);
421 ppl_delete_Pointset_Powerset_C_Polyhedron (isc1);
422 ppl_delete_Pointset_Powerset_C_Polyhedron (isc2);
423 ppl_delete_Pointset_Powerset_C_Polyhedron (idr1);
424 ppl_delete_Pointset_Powerset_C_Polyhedron (idr2);
425 ppl_delete_Pointset_Powerset_C_Polyhedron (dreq);
426
427 if (!ppl_Pointset_Powerset_C_Polyhedron_is_empty (res))
428 build_lexicographically_gt_constraint (&res, dim, MIN (tdim1, tdim2),
429 tdim1 + ddim1, direction);
430
431 return new_poly_ddr (pdr1, pdr2, res);
432 }
433
434 /* Build the dependence polyhedron for data references PDR1 and PDR2.
435 If possible use already cached information.
436
437 D1 and D2 are the iteration domains of PDR1 and PDR2.
438
439 SCAT1 and SCAT2 are the scattering polyhedra for PDR1 and PDR2.
440 When ORIGINAL_SCATTERING_P is true, then the scattering polyhedra
441 SCAT1 and SCAT2 correspond to the original scattering of the
442 program, otherwise they correspond to the transformed scattering.
443
444 When DIRECTION is set to 1, compute the direct dependence from PDR1
445 to PDR2, and when DIRECTION is -1, compute the reversed dependence
446 relation, from PDR2 to PDR1. */
447
448 static poly_ddr_p
449 dependence_polyhedron (poly_bb_p pbb1, poly_bb_p pbb2,
450 ppl_Pointset_Powerset_C_Polyhedron_t d1,
451 ppl_Pointset_Powerset_C_Polyhedron_t d2,
452 poly_dr_p pdr1, poly_dr_p pdr2,
453 ppl_Polyhedron_t scat1, ppl_Polyhedron_t scat2,
454 int direction,
455 bool original_scattering_p)
456 {
457 PTR *x = NULL;
458 poly_ddr_p res;
459
460 if (original_scattering_p)
461 {
462 struct poly_ddr tmp;
463
464 tmp.source = pdr1;
465 tmp.sink = pdr2;
466 x = htab_find_slot (SCOP_ORIGINAL_PDDRS (PBB_SCOP (pbb1)),
467 &tmp, INSERT);
468
469 if (x && *x)
470 return (poly_ddr_p) *x;
471 }
472
473 res = dependence_polyhedron_1 (pbb1, pbb2, d1, d2, pdr1, pdr2,
474 scat1, scat2, direction, original_scattering_p);
475
476 if (original_scattering_p)
477 *x = res;
478
479 return res;
480 }
481
482 /* Returns the Polyhedral Data Dependence Relation (PDDR) between PDR1
483 contained in PBB1 and PDR2 contained in PBB2. When
484 ORIGINAL_SCATTERING_P is true, return the PDDR corresponding to the
485 original scattering, or NULL if the dependence relation is empty.
486 When ORIGINAL_SCATTERING_P is false, return the PDDR corresponding
487 to the transformed scattering. When DIRECTION is set to 1, compute
488 the direct dependence from PDR1 to PDR2, and when DIRECTION is -1,
489 compute the reversed dependence relation, from PDR2 to PDR1. */
490
491 static poly_ddr_p
492 build_pddr (poly_bb_p pbb1, poly_bb_p pbb2, poly_dr_p pdr1, poly_dr_p pdr2,
493 int direction, bool original_scattering_p)
494 {
495 poly_ddr_p pddr;
496 ppl_Pointset_Powerset_C_Polyhedron_t d1 = PBB_DOMAIN (pbb1);
497 ppl_Pointset_Powerset_C_Polyhedron_t d2 = PBB_DOMAIN (pbb2);
498 ppl_Polyhedron_t scat1 = original_scattering_p ?
499 PBB_ORIGINAL_SCATTERING (pbb1) : PBB_TRANSFORMED_SCATTERING (pbb1);
500 ppl_Polyhedron_t scat2 = original_scattering_p ?
501 PBB_ORIGINAL_SCATTERING (pbb2) : PBB_TRANSFORMED_SCATTERING (pbb2);
502
503 if ((pdr_read_p (pdr1) && pdr_read_p (pdr2))
504 || PDR_BASE_OBJECT_SET (pdr1) != PDR_BASE_OBJECT_SET (pdr2)
505 || PDR_NB_SUBSCRIPTS (pdr1) != PDR_NB_SUBSCRIPTS (pdr2))
506 return NULL;
507
508 pddr = dependence_polyhedron (pbb1, pbb2, d1, d2, pdr1, pdr2, scat1, scat2,
509 direction, original_scattering_p);
510 if (pddr_is_empty (pddr))
511 return NULL;
512
513 return pddr;
514 }
515
516 /* Return true when the data dependence relation between the data
517 references PDR1 belonging to PBB1 and PDR2 is part of a
518 reduction. */
519
520 static inline bool
521 reduction_dr_1 (poly_bb_p pbb1, poly_dr_p pdr1, poly_dr_p pdr2)
522 {
523 int i;
524 poly_dr_p pdr;
525
526 for (i = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb1), i, pdr); i++)
527 if (PDR_TYPE (pdr) == PDR_WRITE)
528 break;
529
530 return same_pdr_p (pdr, pdr1) && same_pdr_p (pdr, pdr2);
531 }
532
533 /* Return true when the data dependence relation between the data
534 references PDR1 belonging to PBB1 and PDR2 belonging to PBB2 is
535 part of a reduction. */
536
537 static inline bool
538 reduction_dr_p (poly_bb_p pbb1, poly_bb_p pbb2,
539 poly_dr_p pdr1, poly_dr_p pdr2)
540 {
541 if (PBB_IS_REDUCTION (pbb1))
542 return reduction_dr_1 (pbb1, pdr1, pdr2);
543
544 if (PBB_IS_REDUCTION (pbb2))
545 return reduction_dr_1 (pbb2, pdr2, pdr1);
546
547 return false;
548 }
549
550 /* Returns true when the PBB_TRANSFORMED_SCATTERING functions of PBB1
551 and PBB2 respect the data dependences of PBB_ORIGINAL_SCATTERING
552 functions. */
553
554 static bool
555 graphite_legal_transform_dr (poly_bb_p pbb1, poly_bb_p pbb2,
556 poly_dr_p pdr1, poly_dr_p pdr2)
557 {
558 ppl_Polyhedron_t st1, st2;
559 ppl_Pointset_Powerset_C_Polyhedron_t po, pt;
560 graphite_dim_t ddim1, otdim1, otdim2, ttdim1, ttdim2;
561 ppl_Pointset_Powerset_C_Polyhedron_t temp;
562 ppl_dimension_type pdim;
563 bool is_empty_p;
564 poly_ddr_p pddr;
565
566 if (reduction_dr_p (pbb1, pbb2, pdr1, pdr2))
567 return true;
568
569 pddr = build_pddr (pbb1, pbb2, pdr1, pdr2, 1, true);
570 if (!pddr)
571 /* There are no dependences between PDR1 and PDR2 in the original
572 version of the program, so the transform is legal. */
573 return true;
574
575 po = PDDR_DDP (pddr);
576
577 if (dump_file && (dump_flags & TDF_DETAILS))
578 fprintf (dump_file, "\nloop carries dependency.\n");
579
580 st1 = PBB_TRANSFORMED_SCATTERING (pbb1);
581 st2 = PBB_TRANSFORMED_SCATTERING (pbb2);
582 ddim1 = pbb_dim_iter_domain (pbb1);
583 otdim1 = pbb_nb_scattering_orig (pbb1);
584 otdim2 = pbb_nb_scattering_orig (pbb2);
585 ttdim1 = pbb_nb_scattering_transform (pbb1);
586 ttdim2 = pbb_nb_scattering_transform (pbb2);
587
588 /* Copy the PO polyhedron into the TEMP, so it is not destroyed.
589 Keep in mind, that PO polyhedron might be restored from the cache
590 and should not be modified! */
591 ppl_Pointset_Powerset_C_Polyhedron_space_dimension (po, &pdim);
592 ppl_new_Pointset_Powerset_C_Polyhedron_from_space_dimension (&temp, pdim, 0);
593 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (temp, po);
594
595 /* We build the reverse dependence relation for the transformed
596 scattering, such that when we intersect it with the original PO,
597 we get an empty intersection when the transform is legal:
598 i.e. the transform should reverse no dependences, and so PT, the
599 reversed transformed PDDR, should have no constraint from PO. */
600 pddr = build_pddr (pbb1, pbb2, pdr1, pdr2, -1, false);
601 if (!pddr)
602 /* There are no dependences after the transform, so the transform
603 is legal. */
604 return true;
605
606 pt = PDDR_DDP (pddr);
607
608 /* Extend PO and PT to have the same dimensions. */
609 ppl_insert_dimensions_pointset (temp, otdim1, ttdim1);
610 ppl_insert_dimensions_pointset (temp, otdim1 + ttdim1 + ddim1 + otdim2, ttdim2);
611 ppl_insert_dimensions_pointset (pt, 0, otdim1);
612 ppl_insert_dimensions_pointset (pt, otdim1 + ttdim1 + ddim1, otdim2);
613
614 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (temp, pt);
615 is_empty_p = ppl_Pointset_Powerset_C_Polyhedron_is_empty (temp);
616
617 ppl_delete_Pointset_Powerset_C_Polyhedron (temp);
618 free_poly_ddr (pddr);
619
620 return is_empty_p;
621 }
622
623 /* Return true when the data dependence relation for PBB1 and PBB2 is
624 part of a reduction. */
625
626 static inline bool
627 reduction_ddr_p (poly_bb_p pbb1, poly_bb_p pbb2)
628 {
629 return pbb1 == pbb2 && PBB_IS_REDUCTION (pbb1);
630 }
631
632 /* Iterates over the data references of PBB1 and PBB2 and detect
633 whether the transformed schedule is correct. */
634
635 static bool
636 graphite_legal_transform_bb (poly_bb_p pbb1, poly_bb_p pbb2)
637 {
638 int i, j;
639 poly_dr_p pdr1, pdr2;
640
641 if (!PBB_PDR_DUPLICATES_REMOVED (pbb1))
642 pbb_remove_duplicate_pdrs (pbb1);
643
644 if (!PBB_PDR_DUPLICATES_REMOVED (pbb2))
645 pbb_remove_duplicate_pdrs (pbb2);
646
647 if (reduction_ddr_p (pbb1, pbb2))
648 return true;
649
650 for (i = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb1), i, pdr1); i++)
651 for (j = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb2), j, pdr2); j++)
652 if (!graphite_legal_transform_dr (pbb1, pbb2, pdr1, pdr2))
653 return false;
654
655 return true;
656 }
657
658 /* Iterates over the SCOP and detect whether the transformed schedule
659 is correct. */
660
661 bool
662 graphite_legal_transform (scop_p scop)
663 {
664 int i, j;
665 poly_bb_p pbb1, pbb2;
666
667 timevar_push (TV_GRAPHITE_DATA_DEPS);
668
669 for (i = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), i, pbb1); i++)
670 for (j = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), j, pbb2); j++)
671 if (!graphite_legal_transform_bb (pbb1, pbb2))
672 {
673 timevar_pop (TV_GRAPHITE_DATA_DEPS);
674 return false;
675 }
676
677 timevar_pop (TV_GRAPHITE_DATA_DEPS);
678 return true;
679 }
680
681 /* Remove all the dimensions except alias information at dimension
682 ALIAS_DIM. */
683
684 static void
685 build_alias_set_powerset (ppl_Pointset_Powerset_C_Polyhedron_t alias_powerset,
686 ppl_dimension_type alias_dim)
687 {
688 ppl_dimension_type *ds;
689 ppl_dimension_type access_dim;
690 unsigned i, pos = 0;
691
692 ppl_Pointset_Powerset_C_Polyhedron_space_dimension (alias_powerset,
693 &access_dim);
694 ds = XNEWVEC (ppl_dimension_type, access_dim-1);
695 for (i = 0; i < access_dim; i++)
696 {
697 if (i == alias_dim)
698 continue;
699
700 ds[pos] = i;
701 pos++;
702 }
703
704 ppl_Pointset_Powerset_C_Polyhedron_remove_space_dimensions (alias_powerset,
705 ds,
706 access_dim - 1);
707 free (ds);
708 }
709
710 /* Return true when PDR1 and PDR2 may alias. */
711
712 static bool
713 poly_drs_may_alias_p (poly_dr_p pdr1, poly_dr_p pdr2)
714 {
715 ppl_Pointset_Powerset_C_Polyhedron_t alias_powerset1, alias_powerset2;
716 ppl_Pointset_Powerset_C_Polyhedron_t accesses1 = PDR_ACCESSES (pdr1);
717 ppl_Pointset_Powerset_C_Polyhedron_t accesses2 = PDR_ACCESSES (pdr2);
718 ppl_dimension_type alias_dim1 = pdr_alias_set_dim (pdr1);
719 ppl_dimension_type alias_dim2 = pdr_alias_set_dim (pdr2);
720 int empty_p;
721
722 ppl_new_Pointset_Powerset_C_Polyhedron_from_Pointset_Powerset_C_Polyhedron
723 (&alias_powerset1, accesses1);
724 ppl_new_Pointset_Powerset_C_Polyhedron_from_Pointset_Powerset_C_Polyhedron
725 (&alias_powerset2, accesses2);
726
727 build_alias_set_powerset (alias_powerset1, alias_dim1);
728 build_alias_set_powerset (alias_powerset2, alias_dim2);
729
730 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign
731 (alias_powerset1, alias_powerset2);
732
733 empty_p = ppl_Pointset_Powerset_C_Polyhedron_is_empty (alias_powerset1);
734
735 ppl_delete_Pointset_Powerset_C_Polyhedron (alias_powerset1);
736 ppl_delete_Pointset_Powerset_C_Polyhedron (alias_powerset2);
737
738 return !empty_p;
739 }
740
741 /* Returns TRUE when the dependence polyhedron between PDR1 and
742 PDR2 represents a loop carried dependence at level LEVEL. */
743
744 static bool
745 graphite_carried_dependence_level_k (poly_dr_p pdr1, poly_dr_p pdr2,
746 int level)
747 {
748 poly_bb_p pbb1 = PDR_PBB (pdr1);
749 poly_bb_p pbb2 = PDR_PBB (pdr2);
750 ppl_Pointset_Powerset_C_Polyhedron_t d1 = PBB_DOMAIN (pbb1);
751 ppl_Pointset_Powerset_C_Polyhedron_t d2 = PBB_DOMAIN (pbb2);
752 ppl_Polyhedron_t so1 = PBB_TRANSFORMED_SCATTERING (pbb1);
753 ppl_Polyhedron_t so2 = PBB_TRANSFORMED_SCATTERING (pbb2);
754 ppl_Pointset_Powerset_C_Polyhedron_t po;
755 ppl_Pointset_Powerset_C_Polyhedron_t eqpp;
756 graphite_dim_t tdim1 = pbb_nb_scattering_transform (pbb1);
757 graphite_dim_t ddim1 = pbb_dim_iter_domain (pbb1);
758 ppl_dimension_type dim;
759 bool empty_p;
760 poly_ddr_p pddr;
761 int obj_base_set1 = PDR_BASE_OBJECT_SET (pdr1);
762 int obj_base_set2 = PDR_BASE_OBJECT_SET (pdr2);
763
764 if ((pdr_read_p (pdr1) && pdr_read_p (pdr2))
765 || !poly_drs_may_alias_p (pdr1, pdr2))
766 return false;
767
768 if (obj_base_set1 != obj_base_set2)
769 return true;
770
771 if (PDR_NB_SUBSCRIPTS (pdr1) != PDR_NB_SUBSCRIPTS (pdr2))
772 return false;
773
774 pddr = dependence_polyhedron (pbb1, pbb2, d1, d2, pdr1, pdr2, so1, so2,
775 1, false);
776
777 if (pddr_is_empty (pddr))
778 return false;
779
780 po = PDDR_DDP (pddr);
781 ppl_Pointset_Powerset_C_Polyhedron_space_dimension (po, &dim);
782 eqpp = build_pairwise_scheduling (dim, level, tdim1 + ddim1, 1);
783
784 ppl_Pointset_Powerset_C_Polyhedron_intersection_assign (eqpp, po);
785 empty_p = ppl_Pointset_Powerset_C_Polyhedron_is_empty (eqpp);
786
787 ppl_delete_Pointset_Powerset_C_Polyhedron (eqpp);
788 return !empty_p;
789 }
790
791 /* Check data dependency between PBB1 and PBB2 at level LEVEL. */
792
793 bool
794 dependency_between_pbbs_p (poly_bb_p pbb1, poly_bb_p pbb2, int level)
795 {
796 int i, j;
797 poly_dr_p pdr1, pdr2;
798
799 timevar_push (TV_GRAPHITE_DATA_DEPS);
800
801 for (i = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb1), i, pdr1); i++)
802 for (j = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb2), j, pdr2); j++)
803 if (graphite_carried_dependence_level_k (pdr1, pdr2, level))
804 {
805 timevar_pop (TV_GRAPHITE_DATA_DEPS);
806 return true;
807 }
808
809 timevar_pop (TV_GRAPHITE_DATA_DEPS);
810 return false;
811 }
812
813 /* Pretty print to FILE all the original data dependences of SCoP in
814 DOT format. */
815
816 static void
817 dot_original_deps_stmt_1 (FILE *file, scop_p scop)
818 {
819 int i, j, k, l;
820 poly_bb_p pbb1, pbb2;
821 poly_dr_p pdr1, pdr2;
822
823 for (i = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), i, pbb1); i++)
824 for (j = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), j, pbb2); j++)
825 {
826 for (k = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb1), k, pdr1); k++)
827 for (l = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb2), l, pdr2); l++)
828 if (build_pddr (pbb1, pbb2, pdr1, pdr2, 1, true))
829 {
830 fprintf (file, "OS%d -> OS%d\n",
831 pbb_index (pbb1), pbb_index (pbb2));
832 goto done;
833 }
834 done:;
835 }
836 }
837
838 /* Pretty print to FILE all the transformed data dependences of SCoP in
839 DOT format. */
840
841 static void
842 dot_transformed_deps_stmt_1 (FILE *file, scop_p scop)
843 {
844 int i, j, k, l;
845 poly_bb_p pbb1, pbb2;
846 poly_dr_p pdr1, pdr2;
847 poly_ddr_p pddr;
848
849 for (i = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), i, pbb1); i++)
850 for (j = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), j, pbb2); j++)
851 {
852 for (k = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb1), k, pdr1); k++)
853 for (l = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb2), l, pdr2); l++)
854 if ((pddr = build_pddr (pbb1, pbb2, pdr1, pdr2, 1, false)))
855 {
856 fprintf (file, "TS%d -> TS%d\n",
857 pbb_index (pbb1), pbb_index (pbb2));
858 free_poly_ddr (pddr);
859 goto done;
860 }
861 done:;
862 }
863 }
864
865
866 /* Pretty print to FILE all the data dependences of SCoP in DOT
867 format. */
868
869 static void
870 dot_deps_stmt_1 (FILE *file, scop_p scop)
871 {
872 fputs ("digraph all {\n", file);
873
874 dot_original_deps_stmt_1 (file, scop);
875 dot_transformed_deps_stmt_1 (file, scop);
876
877 fputs ("}\n\n", file);
878 }
879
880 /* Pretty print to FILE all the original data dependences of SCoP in
881 DOT format. */
882
883 static void
884 dot_original_deps (FILE *file, scop_p scop)
885 {
886 int i, j, k, l;
887 poly_bb_p pbb1, pbb2;
888 poly_dr_p pdr1, pdr2;
889
890 for (i = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), i, pbb1); i++)
891 for (j = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), j, pbb2); j++)
892 for (k = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb1), k, pdr1); k++)
893 for (l = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb2), l, pdr2); l++)
894 if (build_pddr (pbb1, pbb2, pdr1, pdr2, 1, true))
895 fprintf (file, "OS%d_D%d -> OS%d_D%d\n",
896 pbb_index (pbb1), PDR_ID (pdr1),
897 pbb_index (pbb2), PDR_ID (pdr2));
898 }
899
900 /* Pretty print to FILE all the transformed data dependences of SCoP in
901 DOT format. */
902
903 static void
904 dot_transformed_deps (FILE *file, scop_p scop)
905 {
906 int i, j, k, l;
907 poly_bb_p pbb1, pbb2;
908 poly_dr_p pdr1, pdr2;
909 poly_ddr_p pddr;
910
911 for (i = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), i, pbb1); i++)
912 for (j = 0; VEC_iterate (poly_bb_p, SCOP_BBS (scop), j, pbb2); j++)
913 for (k = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb1), k, pdr1); k++)
914 for (l = 0; VEC_iterate (poly_dr_p, PBB_DRS (pbb2), l, pdr2); l++)
915 if ((pddr = build_pddr (pbb1, pbb2, pdr1, pdr2, 1, false)))
916 {
917 fprintf (file, "TS%d_D%d -> TS%d_D%d\n",
918 pbb_index (pbb1), PDR_ID (pdr1),
919 pbb_index (pbb2), PDR_ID (pdr2));
920 free_poly_ddr (pddr);
921 }
922 }
923
924 /* Pretty print to FILE all the data dependences of SCoP in DOT
925 format. */
926
927 static void
928 dot_deps_1 (FILE *file, scop_p scop)
929 {
930 fputs ("digraph all {\n", file);
931
932 dot_original_deps (file, scop);
933 dot_transformed_deps (file, scop);
934
935 fputs ("}\n\n", file);
936 }
937
938 /* Display all the data dependences in SCoP using dotty. */
939
940 void
941 dot_deps (scop_p scop)
942 {
943 /* When debugging, enable the following code. This cannot be used
944 in production compilers because it calls "system". */
945 #if 0
946 int x;
947 FILE *stream = fopen ("/tmp/scopdeps.dot", "w");
948 gcc_assert (stream);
949
950 dot_deps_1 (stream, scop);
951 fclose (stream);
952
953 x = system ("dotty /tmp/scopdeps.dot");
954 #else
955 dot_deps_1 (stderr, scop);
956 #endif
957 }
958
959 /* Display all the statement dependences in SCoP using dotty. */
960
961 void
962 dot_deps_stmt (scop_p scop)
963 {
964 /* When debugging, enable the following code. This cannot be used
965 in production compilers because it calls "system". */
966 #if 0
967 int x;
968 FILE *stream = fopen ("/tmp/scopdeps.dot", "w");
969 gcc_assert (stream);
970
971 dot_deps_stmt_1 (stream, scop);
972 fclose (stream);
973
974 x = system ("dotty /tmp/scopdeps.dot");
975 #else
976 dot_deps_stmt_1 (stderr, scop);
977 #endif
978 }
979
980 #endif