2014-03-18 Richard Biener <rguenther@suse.de>
[official-gcc.git] / gcc / graphite-dependences.c
blobb0f868077ae0217edf7cbe4296ef4e68c817aad8
1 /* Data dependence analysis for Graphite.
2 Copyright (C) 2009-2014 Free Software Foundation, Inc.
3 Contributed by Sebastian Pop <sebastian.pop@amd.com> and
4 Konrad Trifunovic <konrad.trifunovic@inria.fr>.
6 This file is part of GCC.
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.
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.
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/>. */
22 #include "config.h"
24 #ifdef HAVE_cloog
25 #include <isl/set.h>
26 #include <isl/map.h>
27 #include <isl/union_map.h>
28 #include <isl/flow.h>
29 #include <isl/constraint.h>
30 #include <cloog/cloog.h>
31 #include <cloog/isl/domain.h>
32 #endif
34 #include "system.h"
35 #include "coretypes.h"
36 #include "tree.h"
37 #include "basic-block.h"
38 #include "tree-ssa-alias.h"
39 #include "internal-fn.h"
40 #include "gimple-expr.h"
41 #include "is-a.h"
42 #include "gimple.h"
43 #include "gimple-iterator.h"
44 #include "tree-ssa-loop.h"
45 #include "tree-pass.h"
46 #include "cfgloop.h"
47 #include "tree-chrec.h"
48 #include "tree-data-ref.h"
49 #include "tree-scalar-evolution.h"
50 #include "sese.h"
52 #ifdef HAVE_cloog
53 #include "graphite-poly.h"
54 #include "graphite-htab.h"
56 /* Add the constraints from the set S to the domain of MAP. */
58 static isl_map *
59 constrain_domain (isl_map *map, isl_set *s)
61 isl_space *d = isl_map_get_space (map);
62 isl_id *id = isl_space_get_tuple_id (d, isl_dim_in);
64 s = isl_set_set_tuple_id (s, id);
65 isl_space_free (d);
66 return isl_map_intersect_domain (map, s);
69 /* Constrain pdr->accesses with pdr->extent and pbb->domain. */
71 static isl_map *
72 add_pdr_constraints (poly_dr_p pdr, poly_bb_p pbb)
74 isl_map *x = isl_map_intersect_range (isl_map_copy (pdr->accesses),
75 isl_set_copy (pdr->extent));
76 x = constrain_domain (x, isl_set_copy (pbb->domain));
77 return x;
80 /* Returns all the memory reads in SCOP. */
82 static isl_union_map *
83 scop_get_reads (scop_p scop, vec<poly_bb_p> pbbs)
85 int i, j;
86 poly_bb_p pbb;
87 poly_dr_p pdr;
88 isl_space *space = isl_set_get_space (scop->context);
89 isl_union_map *res = isl_union_map_empty (space);
91 FOR_EACH_VEC_ELT (pbbs, i, pbb)
93 FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
94 if (pdr_read_p (pdr))
95 res = isl_union_map_add_map (res, add_pdr_constraints (pdr, pbb));
98 return res;
101 /* Returns all the memory must writes in SCOP. */
103 static isl_union_map *
104 scop_get_must_writes (scop_p scop, vec<poly_bb_p> pbbs)
106 int i, j;
107 poly_bb_p pbb;
108 poly_dr_p pdr;
109 isl_space *space = isl_set_get_space (scop->context);
110 isl_union_map *res = isl_union_map_empty (space);
112 FOR_EACH_VEC_ELT (pbbs, i, pbb)
114 FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
115 if (pdr_write_p (pdr))
116 res = isl_union_map_add_map (res, add_pdr_constraints (pdr, pbb));
119 return res;
122 /* Returns all the memory may writes in SCOP. */
124 static isl_union_map *
125 scop_get_may_writes (scop_p scop, vec<poly_bb_p> pbbs)
127 int i, j;
128 poly_bb_p pbb;
129 poly_dr_p pdr;
130 isl_space *space = isl_set_get_space (scop->context);
131 isl_union_map *res = isl_union_map_empty (space);
133 FOR_EACH_VEC_ELT (pbbs, i, pbb)
135 FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
136 if (pdr_may_write_p (pdr))
137 res = isl_union_map_add_map (res, add_pdr_constraints (pdr, pbb));
140 return res;
143 /* Returns all the original schedules in SCOP. */
145 static isl_union_map *
146 scop_get_original_schedule (scop_p scop, vec<poly_bb_p> pbbs)
148 int i;
149 poly_bb_p pbb;
150 isl_space *space = isl_set_get_space (scop->context);
151 isl_union_map *res = isl_union_map_empty (space);
153 FOR_EACH_VEC_ELT (pbbs, i, pbb)
155 res = isl_union_map_add_map
156 (res, constrain_domain (isl_map_copy (pbb->schedule),
157 isl_set_copy (pbb->domain)));
160 return res;
163 /* Returns all the transformed schedules in SCOP. */
165 static isl_union_map *
166 scop_get_transformed_schedule (scop_p scop, vec<poly_bb_p> pbbs)
168 int i;
169 poly_bb_p pbb;
170 isl_space *space = isl_set_get_space (scop->context);
171 isl_union_map *res = isl_union_map_empty (space);
173 FOR_EACH_VEC_ELT (pbbs, i, pbb)
175 res = isl_union_map_add_map
176 (res, constrain_domain (isl_map_copy (pbb->transformed),
177 isl_set_copy (pbb->domain)));
180 return res;
183 /* Helper function used on each MAP of a isl_union_map. Computes the
184 maximal output dimension. */
186 static int
187 max_number_of_out_dimensions (__isl_take isl_map *map, void *user)
189 int global_max = *((int *) user);
190 isl_space *space = isl_map_get_space (map);
191 int nb_out = isl_space_dim (space, isl_dim_out);
193 if (global_max < nb_out)
194 *((int *) user) = nb_out;
196 isl_map_free (map);
197 isl_space_free (space);
198 return 0;
201 /* Extends the output dimension of MAP to MAX dimensions. */
203 static __isl_give isl_map *
204 extend_map (__isl_take isl_map *map, int max)
206 isl_space *space = isl_map_get_space (map);
207 int n = isl_space_dim (space, isl_dim_out);
209 isl_space_free (space);
210 return isl_map_add_dims (map, isl_dim_out, max - n);
213 /* Structure used to pass parameters to extend_schedule_1. */
215 struct extend_schedule_str {
216 int max;
217 isl_union_map *umap;
220 /* Helper function for extend_schedule. */
222 static int
223 extend_schedule_1 (__isl_take isl_map *map, void *user)
225 struct extend_schedule_str *str = (struct extend_schedule_str *) user;
226 str->umap = isl_union_map_add_map (str->umap, extend_map (map, str->max));
227 return 0;
230 /* Return a relation that has uniform output dimensions. */
232 __isl_give isl_union_map *
233 extend_schedule (__isl_take isl_union_map *x)
235 int max = 0;
236 int res;
237 struct extend_schedule_str str;
239 res = isl_union_map_foreach_map (x, max_number_of_out_dimensions, (void *) &max);
240 gcc_assert (res == 0);
242 str.max = max;
243 str.umap = isl_union_map_empty (isl_union_map_get_space (x));
244 res = isl_union_map_foreach_map (x, extend_schedule_1, (void *) &str);
245 gcc_assert (res == 0);
247 isl_union_map_free (x);
248 return str.umap;
251 /* Applies SCHEDULE to the in and out dimensions of the dependences
252 DEPS and return the resulting relation. */
254 static isl_map *
255 apply_schedule_on_deps (__isl_keep isl_union_map *schedule,
256 __isl_keep isl_union_map *deps)
258 isl_map *x;
259 isl_union_map *ux, *trans;
261 trans = isl_union_map_copy (schedule);
262 trans = extend_schedule (trans);
263 ux = isl_union_map_copy (deps);
264 ux = isl_union_map_apply_domain (ux, isl_union_map_copy (trans));
265 ux = isl_union_map_apply_range (ux, trans);
266 x = isl_map_from_union_map (ux);
268 return x;
271 /* Return true when SCHEDULE does not violate the data DEPS: that is
272 when the intersection of LEX with the DEPS transformed by SCHEDULE
273 is empty. LEX is the relation in which the outputs occur before
274 the inputs. */
276 static bool
277 no_violations (__isl_keep isl_union_map *schedule,
278 __isl_keep isl_union_map *deps)
280 bool res;
281 isl_space *space;
282 isl_map *lex, *x;
284 if (isl_union_map_is_empty (deps))
285 return true;
287 x = apply_schedule_on_deps (schedule, deps);
288 space = isl_map_get_space (x);
289 space = isl_space_range (space);
290 lex = isl_map_lex_ge (space);
291 x = isl_map_intersect (x, lex);
292 res = isl_map_is_empty (x);
294 isl_map_free (x);
295 return res;
298 /* Return true when DEPS is non empty and the intersection of LEX with
299 the DEPS transformed by SCHEDULE is non empty. LEX is the relation
300 in which all the inputs before DEPTH occur at the same time as the
301 output, and the input at DEPTH occurs before output. */
303 static bool
304 carries_deps (__isl_keep isl_union_map *schedule,
305 __isl_keep isl_union_map *deps,
306 int depth)
308 bool res;
309 int i;
310 isl_space *space;
311 isl_map *lex, *x;
312 isl_constraint *ineq;
314 if (isl_union_map_is_empty (deps))
315 return false;
317 x = apply_schedule_on_deps (schedule, deps);
318 space = isl_map_get_space (x);
319 space = isl_space_range (space);
320 lex = isl_map_lex_le (space);
321 space = isl_map_get_space (x);
322 ineq = isl_inequality_alloc (isl_local_space_from_space (space));
324 for (i = 0; i < depth - 1; i++)
325 lex = isl_map_equate (lex, isl_dim_in, i, isl_dim_out, i);
327 /* in + 1 <= out */
328 ineq = isl_constraint_set_coefficient_si (ineq, isl_dim_out, depth - 1, 1);
329 ineq = isl_constraint_set_coefficient_si (ineq, isl_dim_in, depth - 1, -1);
330 ineq = isl_constraint_set_constant_si (ineq, -1);
331 lex = isl_map_add_constraint (lex, ineq);
332 x = isl_map_intersect (x, lex);
333 res = !isl_map_is_empty (x);
335 isl_map_free (x);
336 return res;
339 /* Subtract from the RAW, WAR, and WAW dependences those relations
340 that have been marked as belonging to an associative commutative
341 reduction. */
343 static void
344 subtract_commutative_associative_deps (scop_p scop,
345 vec<poly_bb_p> pbbs,
346 isl_union_map *original,
347 isl_union_map **must_raw,
348 isl_union_map **may_raw,
349 isl_union_map **must_raw_no_source,
350 isl_union_map **may_raw_no_source,
351 isl_union_map **must_war,
352 isl_union_map **may_war,
353 isl_union_map **must_war_no_source,
354 isl_union_map **may_war_no_source,
355 isl_union_map **must_waw,
356 isl_union_map **may_waw,
357 isl_union_map **must_waw_no_source,
358 isl_union_map **may_waw_no_source)
360 int i, j;
361 poly_bb_p pbb;
362 poly_dr_p pdr;
363 isl_space *space = isl_set_get_space (scop->context);
365 FOR_EACH_VEC_ELT (pbbs, i, pbb)
366 if (PBB_IS_REDUCTION (pbb))
368 int res;
369 isl_union_map *r = isl_union_map_empty (isl_space_copy (space));
370 isl_union_map *must_w = isl_union_map_empty (isl_space_copy (space));
371 isl_union_map *may_w = isl_union_map_empty (isl_space_copy (space));
372 isl_union_map *all_w;
373 isl_union_map *empty;
374 isl_union_map *x_must_raw;
375 isl_union_map *x_may_raw;
376 isl_union_map *x_must_raw_no_source;
377 isl_union_map *x_may_raw_no_source;
378 isl_union_map *x_must_war;
379 isl_union_map *x_may_war;
380 isl_union_map *x_must_war_no_source;
381 isl_union_map *x_may_war_no_source;
382 isl_union_map *x_must_waw;
383 isl_union_map *x_may_waw;
384 isl_union_map *x_must_waw_no_source;
385 isl_union_map *x_may_waw_no_source;
387 FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
388 if (pdr_read_p (pdr))
389 r = isl_union_map_add_map (r, add_pdr_constraints (pdr, pbb));
391 FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
392 if (pdr_write_p (pdr))
393 must_w = isl_union_map_add_map (must_w,
394 add_pdr_constraints (pdr, pbb));
396 FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
397 if (pdr_may_write_p (pdr))
398 may_w = isl_union_map_add_map (may_w,
399 add_pdr_constraints (pdr, pbb));
401 all_w = isl_union_map_union
402 (isl_union_map_copy (must_w), isl_union_map_copy (may_w));
403 empty = isl_union_map_empty (isl_union_map_get_space (all_w));
405 res = isl_union_map_compute_flow (isl_union_map_copy (r),
406 isl_union_map_copy (must_w),
407 isl_union_map_copy (may_w),
408 isl_union_map_copy (original),
409 &x_must_raw, &x_may_raw,
410 &x_must_raw_no_source,
411 &x_may_raw_no_source);
412 gcc_assert (res == 0);
413 res = isl_union_map_compute_flow (isl_union_map_copy (all_w),
414 r, empty,
415 isl_union_map_copy (original),
416 &x_must_war, &x_may_war,
417 &x_must_war_no_source,
418 &x_may_war_no_source);
419 gcc_assert (res == 0);
420 res = isl_union_map_compute_flow (all_w, must_w, may_w,
421 isl_union_map_copy (original),
422 &x_must_waw, &x_may_waw,
423 &x_must_waw_no_source,
424 &x_may_waw_no_source);
425 gcc_assert (res == 0);
427 *must_raw = isl_union_map_subtract (*must_raw, x_must_raw);
428 *may_raw = isl_union_map_subtract (*may_raw, x_may_raw);
429 *must_raw_no_source = isl_union_map_subtract (*must_raw_no_source,
430 x_must_raw_no_source);
431 *may_raw_no_source = isl_union_map_subtract (*may_raw_no_source,
432 x_may_raw_no_source);
433 *must_war = isl_union_map_subtract (*must_war, x_must_war);
434 *may_war = isl_union_map_subtract (*may_war, x_may_war);
435 *must_war_no_source = isl_union_map_subtract (*must_war_no_source,
436 x_must_war_no_source);
437 *may_war_no_source = isl_union_map_subtract (*may_war_no_source,
438 x_may_war_no_source);
439 *must_waw = isl_union_map_subtract (*must_waw, x_must_waw);
440 *may_waw = isl_union_map_subtract (*may_waw, x_may_waw);
441 *must_waw_no_source = isl_union_map_subtract (*must_waw_no_source,
442 x_must_waw_no_source);
443 *may_waw_no_source = isl_union_map_subtract (*may_waw_no_source,
444 x_may_waw_no_source);
447 isl_union_map_free (original);
448 isl_space_free (space);
451 /* Compute the original data dependences in SCOP for all the reads and
452 writes in PBBS. */
454 void
455 compute_deps (scop_p scop, vec<poly_bb_p> pbbs,
456 isl_union_map **must_raw,
457 isl_union_map **may_raw,
458 isl_union_map **must_raw_no_source,
459 isl_union_map **may_raw_no_source,
460 isl_union_map **must_war,
461 isl_union_map **may_war,
462 isl_union_map **must_war_no_source,
463 isl_union_map **may_war_no_source,
464 isl_union_map **must_waw,
465 isl_union_map **may_waw,
466 isl_union_map **must_waw_no_source,
467 isl_union_map **may_waw_no_source)
469 isl_union_map *reads = scop_get_reads (scop, pbbs);
470 isl_union_map *must_writes = scop_get_must_writes (scop, pbbs);
471 isl_union_map *may_writes = scop_get_may_writes (scop, pbbs);
472 isl_union_map *all_writes = isl_union_map_union
473 (isl_union_map_copy (must_writes), isl_union_map_copy (may_writes));
474 isl_space *space = isl_union_map_get_space (all_writes);
475 isl_union_map *empty = isl_union_map_empty (space);
476 isl_union_map *original = scop_get_original_schedule (scop, pbbs);
477 int res;
479 res = isl_union_map_compute_flow (isl_union_map_copy (reads),
480 isl_union_map_copy (must_writes),
481 isl_union_map_copy (may_writes),
482 isl_union_map_copy (original),
483 must_raw, may_raw, must_raw_no_source,
484 may_raw_no_source);
485 gcc_assert (res == 0);
486 res = isl_union_map_compute_flow (isl_union_map_copy (all_writes),
487 reads, empty,
488 isl_union_map_copy (original),
489 must_war, may_war, must_war_no_source,
490 may_war_no_source);
491 gcc_assert (res == 0);
492 res = isl_union_map_compute_flow (all_writes, must_writes, may_writes,
493 isl_union_map_copy (original),
494 must_waw, may_waw, must_waw_no_source,
495 may_waw_no_source);
496 gcc_assert (res == 0);
498 subtract_commutative_associative_deps
499 (scop, pbbs, original,
500 must_raw, may_raw, must_raw_no_source, may_raw_no_source,
501 must_war, may_war, must_war_no_source, may_war_no_source,
502 must_waw, may_waw, must_waw_no_source, may_waw_no_source);
505 /* Given a TRANSFORM, check whether it respects the original
506 dependences in SCOP. Returns true when TRANSFORM is a safe
507 transformation. */
509 static bool
510 transform_is_safe (scop_p scop, isl_union_map *transform)
512 bool res;
514 if (!scop->must_raw)
515 compute_deps (scop, SCOP_BBS (scop),
516 &scop->must_raw, &scop->may_raw,
517 &scop->must_raw_no_source, &scop->may_raw_no_source,
518 &scop->must_war, &scop->may_war,
519 &scop->must_war_no_source, &scop->may_war_no_source,
520 &scop->must_waw, &scop->may_waw,
521 &scop->must_waw_no_source, &scop->may_waw_no_source);
523 res = (no_violations (transform, scop->must_raw)
524 && no_violations (transform, scop->may_raw)
525 && no_violations (transform, scop->must_war)
526 && no_violations (transform, scop->may_war)
527 && no_violations (transform, scop->must_waw)
528 && no_violations (transform, scop->may_waw));
530 isl_union_map_free (transform);
531 return res;
534 /* Return true when the SCOP transformed schedule is correct. */
536 bool
537 graphite_legal_transform (scop_p scop)
539 int res;
540 isl_union_map *transform;
542 timevar_push (TV_GRAPHITE_DATA_DEPS);
543 transform = scop_get_transformed_schedule (scop, SCOP_BBS (scop));
544 res = transform_is_safe (scop, transform);
545 timevar_pop (TV_GRAPHITE_DATA_DEPS);
547 return res;
550 /* Return true when the loop at DEPTH carries dependences. BODY is
551 the body of the loop. */
553 static bool
554 loop_level_carries_dependences (scop_p scop, vec<poly_bb_p> body,
555 int depth)
557 isl_union_map *transform = scop_get_transformed_schedule (scop, body);
558 isl_union_map *must_raw, *may_raw;
559 isl_union_map *must_war, *may_war;
560 isl_union_map *must_waw, *may_waw;
561 int res;
563 compute_deps (scop, body,
564 &must_raw, &may_raw, NULL, NULL,
565 &must_war, &may_war, NULL, NULL,
566 &must_waw, &may_waw, NULL, NULL);
568 res = (carries_deps (transform, must_raw, depth)
569 || carries_deps (transform, may_raw, depth)
570 || carries_deps (transform, must_war, depth)
571 || carries_deps (transform, may_war, depth)
572 || carries_deps (transform, must_waw, depth)
573 || carries_deps (transform, may_waw, depth));
575 isl_union_map_free (transform);
576 isl_union_map_free (must_raw);
577 isl_union_map_free (may_raw);
578 isl_union_map_free (must_war);
579 isl_union_map_free (may_war);
580 isl_union_map_free (must_waw);
581 isl_union_map_free (may_waw);
582 return res;
585 /* Returns true when the loop L at level DEPTH is parallel.
586 BB_PBB_MAPPING is a map between a basic_block and its related
587 poly_bb_p. */
589 bool
590 loop_is_parallel_p (loop_p loop, bb_pbb_htab_type bb_pbb_mapping, int depth)
592 bool dependences;
593 scop_p scop;
595 timevar_push (TV_GRAPHITE_DATA_DEPS);
596 auto_vec<poly_bb_p, 3> body;
597 scop = get_loop_body_pbbs (loop, bb_pbb_mapping, &body);
598 dependences = loop_level_carries_dependences (scop, body, depth);
599 timevar_pop (TV_GRAPHITE_DATA_DEPS);
601 return !dependences;
604 #endif