jit: add test-benchmark.c
[official-gcc.git] / gcc / graphite-dependences.c
blobedd357d870e2276812f5847a1a964e646fe6216d
1 /* Data dependence analysis for Graphite.
2 Copyright (C) 2009-2015 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_isl
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 #endif
32 #include "system.h"
33 #include "coretypes.h"
34 #include "hash-set.h"
35 #include "machmode.h"
36 #include "vec.h"
37 #include "double-int.h"
38 #include "input.h"
39 #include "alias.h"
40 #include "symtab.h"
41 #include "options.h"
42 #include "wide-int.h"
43 #include "inchash.h"
44 #include "tree.h"
45 #include "fold-const.h"
46 #include "predict.h"
47 #include "tm.h"
48 #include "hard-reg-set.h"
49 #include "input.h"
50 #include "function.h"
51 #include "dominance.h"
52 #include "cfg.h"
53 #include "basic-block.h"
54 #include "tree-ssa-alias.h"
55 #include "internal-fn.h"
56 #include "gimple-expr.h"
57 #include "is-a.h"
58 #include "gimple.h"
59 #include "gimple-iterator.h"
60 #include "tree-ssa-loop.h"
61 #include "tree-pass.h"
62 #include "cfgloop.h"
63 #include "tree-chrec.h"
64 #include "tree-data-ref.h"
65 #include "tree-scalar-evolution.h"
66 #include "sese.h"
68 #ifdef HAVE_isl
69 #include "graphite-poly.h"
71 isl_union_map *
72 scop_get_dependences (scop_p scop)
74 isl_union_map *dependences;
76 if (!scop->must_raw)
77 compute_deps (scop, SCOP_BBS (scop),
78 &scop->must_raw, &scop->may_raw,
79 &scop->must_raw_no_source, &scop->may_raw_no_source,
80 &scop->must_war, &scop->may_war,
81 &scop->must_war_no_source, &scop->may_war_no_source,
82 &scop->must_waw, &scop->may_waw,
83 &scop->must_waw_no_source, &scop->may_waw_no_source);
85 dependences = isl_union_map_copy (scop->must_raw);
86 dependences = isl_union_map_union (dependences,
87 isl_union_map_copy (scop->must_war));
88 dependences = isl_union_map_union (dependences,
89 isl_union_map_copy (scop->must_waw));
90 dependences = isl_union_map_union (dependences,
91 isl_union_map_copy (scop->may_raw));
92 dependences = isl_union_map_union (dependences,
93 isl_union_map_copy (scop->may_war));
94 dependences = isl_union_map_union (dependences,
95 isl_union_map_copy (scop->may_waw));
97 return dependences;
100 /* Add the constraints from the set S to the domain of MAP. */
102 static isl_map *
103 constrain_domain (isl_map *map, isl_set *s)
105 isl_space *d = isl_map_get_space (map);
106 isl_id *id = isl_space_get_tuple_id (d, isl_dim_in);
108 s = isl_set_set_tuple_id (s, id);
109 isl_space_free (d);
110 return isl_map_intersect_domain (map, s);
113 /* Constrain pdr->accesses with pdr->extent and pbb->domain. */
115 static isl_map *
116 add_pdr_constraints (poly_dr_p pdr, poly_bb_p pbb)
118 isl_map *x = isl_map_intersect_range (isl_map_copy (pdr->accesses),
119 isl_set_copy (pdr->extent));
120 x = constrain_domain (x, isl_set_copy (pbb->domain));
121 return x;
124 /* Returns all the memory reads in SCOP. */
126 static isl_union_map *
127 scop_get_reads (scop_p scop, vec<poly_bb_p> pbbs)
129 int i, j;
130 poly_bb_p pbb;
131 poly_dr_p pdr;
132 isl_space *space = isl_set_get_space (scop->context);
133 isl_union_map *res = isl_union_map_empty (space);
135 FOR_EACH_VEC_ELT (pbbs, i, pbb)
137 FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
138 if (pdr_read_p (pdr))
139 res = isl_union_map_add_map (res, add_pdr_constraints (pdr, pbb));
142 return res;
145 /* Returns all the memory must writes in SCOP. */
147 static isl_union_map *
148 scop_get_must_writes (scop_p scop, vec<poly_bb_p> pbbs)
150 int i, j;
151 poly_bb_p pbb;
152 poly_dr_p pdr;
153 isl_space *space = isl_set_get_space (scop->context);
154 isl_union_map *res = isl_union_map_empty (space);
156 FOR_EACH_VEC_ELT (pbbs, i, pbb)
158 FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
159 if (pdr_write_p (pdr))
160 res = isl_union_map_add_map (res, add_pdr_constraints (pdr, pbb));
163 return res;
166 /* Returns all the memory may writes in SCOP. */
168 static isl_union_map *
169 scop_get_may_writes (scop_p scop, vec<poly_bb_p> pbbs)
171 int i, j;
172 poly_bb_p pbb;
173 poly_dr_p pdr;
174 isl_space *space = isl_set_get_space (scop->context);
175 isl_union_map *res = isl_union_map_empty (space);
177 FOR_EACH_VEC_ELT (pbbs, i, pbb)
179 FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
180 if (pdr_may_write_p (pdr))
181 res = isl_union_map_add_map (res, add_pdr_constraints (pdr, pbb));
184 return res;
187 /* Returns all the original schedules in SCOP. */
189 static isl_union_map *
190 scop_get_original_schedule (scop_p scop, vec<poly_bb_p> pbbs)
192 int i;
193 poly_bb_p pbb;
194 isl_space *space = isl_set_get_space (scop->context);
195 isl_union_map *res = isl_union_map_empty (space);
197 FOR_EACH_VEC_ELT (pbbs, i, pbb)
199 res = isl_union_map_add_map
200 (res, constrain_domain (isl_map_copy (pbb->schedule),
201 isl_set_copy (pbb->domain)));
204 return res;
207 /* Returns all the transformed schedules in SCOP. */
209 static isl_union_map *
210 scop_get_transformed_schedule (scop_p scop, vec<poly_bb_p> pbbs)
212 int i;
213 poly_bb_p pbb;
214 isl_space *space = isl_set_get_space (scop->context);
215 isl_union_map *res = isl_union_map_empty (space);
217 FOR_EACH_VEC_ELT (pbbs, i, pbb)
219 res = isl_union_map_add_map
220 (res, constrain_domain (isl_map_copy (pbb->transformed),
221 isl_set_copy (pbb->domain)));
224 return res;
227 /* Helper function used on each MAP of a isl_union_map. Computes the
228 maximal output dimension. */
230 static int
231 max_number_of_out_dimensions (__isl_take isl_map *map, void *user)
233 int global_max = *((int *) user);
234 isl_space *space = isl_map_get_space (map);
235 int nb_out = isl_space_dim (space, isl_dim_out);
237 if (global_max < nb_out)
238 *((int *) user) = nb_out;
240 isl_map_free (map);
241 isl_space_free (space);
242 return 0;
245 /* Extends the output dimension of MAP to MAX dimensions. */
247 static __isl_give isl_map *
248 extend_map (__isl_take isl_map *map, int max)
250 isl_space *space = isl_map_get_space (map);
251 int n = isl_space_dim (space, isl_dim_out);
253 isl_space_free (space);
254 return isl_map_add_dims (map, isl_dim_out, max - n);
257 /* Structure used to pass parameters to extend_schedule_1. */
259 struct extend_schedule_str {
260 int max;
261 isl_union_map *umap;
264 /* Helper function for extend_schedule. */
266 static int
267 extend_schedule_1 (__isl_take isl_map *map, void *user)
269 struct extend_schedule_str *str = (struct extend_schedule_str *) user;
270 str->umap = isl_union_map_add_map (str->umap, extend_map (map, str->max));
271 return 0;
274 /* Return a relation that has uniform output dimensions. */
276 __isl_give isl_union_map *
277 extend_schedule (__isl_take isl_union_map *x)
279 int max = 0;
280 int res;
281 struct extend_schedule_str str;
283 res = isl_union_map_foreach_map (x, max_number_of_out_dimensions, (void *) &max);
284 gcc_assert (res == 0);
286 str.max = max;
287 str.umap = isl_union_map_empty (isl_union_map_get_space (x));
288 res = isl_union_map_foreach_map (x, extend_schedule_1, (void *) &str);
289 gcc_assert (res == 0);
291 isl_union_map_free (x);
292 return str.umap;
295 /* Applies SCHEDULE to the in and out dimensions of the dependences
296 DEPS and return the resulting relation. */
298 static isl_map *
299 apply_schedule_on_deps (__isl_keep isl_union_map *schedule,
300 __isl_keep isl_union_map *deps)
302 isl_map *x;
303 isl_union_map *ux, *trans;
305 trans = isl_union_map_copy (schedule);
306 trans = extend_schedule (trans);
307 ux = isl_union_map_copy (deps);
308 ux = isl_union_map_apply_domain (ux, isl_union_map_copy (trans));
309 ux = isl_union_map_apply_range (ux, trans);
310 if (isl_union_map_is_empty (ux))
312 isl_union_map_free (ux);
313 return NULL;
315 x = isl_map_from_union_map (ux);
317 return x;
320 /* Return true when SCHEDULE does not violate the data DEPS: that is
321 when the intersection of LEX with the DEPS transformed by SCHEDULE
322 is empty. LEX is the relation in which the outputs occur before
323 the inputs. */
325 static bool
326 no_violations (__isl_keep isl_union_map *schedule,
327 __isl_keep isl_union_map *deps)
329 bool res;
330 isl_space *space;
331 isl_map *lex, *x;
333 if (isl_union_map_is_empty (deps))
334 return true;
336 x = apply_schedule_on_deps (schedule, deps);
337 space = isl_map_get_space (x);
338 space = isl_space_range (space);
339 lex = isl_map_lex_ge (space);
340 x = isl_map_intersect (x, lex);
341 res = isl_map_is_empty (x);
343 isl_map_free (x);
344 return res;
347 /* Return true when DEPS is non empty and the intersection of LEX with
348 the DEPS transformed by SCHEDULE is non empty. LEX is the relation
349 in which all the inputs before DEPTH occur at the same time as the
350 output, and the input at DEPTH occurs before output. */
352 bool
353 carries_deps (__isl_keep isl_union_map *schedule,
354 __isl_keep isl_union_map *deps,
355 int depth)
357 bool res;
358 int i;
359 isl_space *space;
360 isl_map *lex, *x;
361 isl_constraint *ineq;
363 if (isl_union_map_is_empty (deps))
364 return false;
366 x = apply_schedule_on_deps (schedule, deps);
367 if (x == NULL)
368 return false;
369 space = isl_map_get_space (x);
370 space = isl_space_range (space);
371 lex = isl_map_lex_le (space);
372 space = isl_map_get_space (x);
373 ineq = isl_inequality_alloc (isl_local_space_from_space (space));
375 for (i = 0; i < depth - 1; i++)
376 lex = isl_map_equate (lex, isl_dim_in, i, isl_dim_out, i);
378 /* in + 1 <= out */
379 ineq = isl_constraint_set_coefficient_si (ineq, isl_dim_out, depth - 1, 1);
380 ineq = isl_constraint_set_coefficient_si (ineq, isl_dim_in, depth - 1, -1);
381 ineq = isl_constraint_set_constant_si (ineq, -1);
382 lex = isl_map_add_constraint (lex, ineq);
383 x = isl_map_intersect (x, lex);
384 res = !isl_map_is_empty (x);
386 isl_map_free (x);
387 return res;
390 /* Subtract from the RAW, WAR, and WAW dependences those relations
391 that have been marked as belonging to an associative commutative
392 reduction. */
394 static void
395 subtract_commutative_associative_deps (scop_p scop,
396 vec<poly_bb_p> pbbs,
397 isl_union_map *original,
398 isl_union_map **must_raw,
399 isl_union_map **may_raw,
400 isl_union_map **must_raw_no_source,
401 isl_union_map **may_raw_no_source,
402 isl_union_map **must_war,
403 isl_union_map **may_war,
404 isl_union_map **must_war_no_source,
405 isl_union_map **may_war_no_source,
406 isl_union_map **must_waw,
407 isl_union_map **may_waw,
408 isl_union_map **must_waw_no_source,
409 isl_union_map **may_waw_no_source)
411 int i, j;
412 poly_bb_p pbb;
413 poly_dr_p pdr;
414 isl_space *space = isl_set_get_space (scop->context);
416 FOR_EACH_VEC_ELT (pbbs, i, pbb)
417 if (PBB_IS_REDUCTION (pbb))
419 int res;
420 isl_union_map *r = isl_union_map_empty (isl_space_copy (space));
421 isl_union_map *must_w = isl_union_map_empty (isl_space_copy (space));
422 isl_union_map *may_w = isl_union_map_empty (isl_space_copy (space));
423 isl_union_map *all_w;
424 isl_union_map *empty;
425 isl_union_map *x_must_raw;
426 isl_union_map *x_may_raw;
427 isl_union_map *x_must_raw_no_source;
428 isl_union_map *x_may_raw_no_source;
429 isl_union_map *x_must_war;
430 isl_union_map *x_may_war;
431 isl_union_map *x_must_war_no_source;
432 isl_union_map *x_may_war_no_source;
433 isl_union_map *x_must_waw;
434 isl_union_map *x_may_waw;
435 isl_union_map *x_must_waw_no_source;
436 isl_union_map *x_may_waw_no_source;
438 FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
439 if (pdr_read_p (pdr))
440 r = isl_union_map_add_map (r, add_pdr_constraints (pdr, pbb));
442 FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
443 if (pdr_write_p (pdr))
444 must_w = isl_union_map_add_map (must_w,
445 add_pdr_constraints (pdr, pbb));
447 FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
448 if (pdr_may_write_p (pdr))
449 may_w = isl_union_map_add_map (may_w,
450 add_pdr_constraints (pdr, pbb));
452 all_w = isl_union_map_union
453 (isl_union_map_copy (must_w), isl_union_map_copy (may_w));
454 empty = isl_union_map_empty (isl_union_map_get_space (all_w));
456 res = isl_union_map_compute_flow (isl_union_map_copy (r),
457 isl_union_map_copy (must_w),
458 isl_union_map_copy (may_w),
459 isl_union_map_copy (original),
460 &x_must_raw, &x_may_raw,
461 &x_must_raw_no_source,
462 &x_may_raw_no_source);
463 gcc_assert (res == 0);
464 res = isl_union_map_compute_flow (isl_union_map_copy (all_w),
465 r, empty,
466 isl_union_map_copy (original),
467 &x_must_war, &x_may_war,
468 &x_must_war_no_source,
469 &x_may_war_no_source);
470 gcc_assert (res == 0);
471 res = isl_union_map_compute_flow (all_w, must_w, may_w,
472 isl_union_map_copy (original),
473 &x_must_waw, &x_may_waw,
474 &x_must_waw_no_source,
475 &x_may_waw_no_source);
476 gcc_assert (res == 0);
478 if (must_raw)
479 *must_raw = isl_union_map_subtract (*must_raw, x_must_raw);
480 else
481 isl_union_map_free (x_must_raw);
483 if (may_raw)
484 *may_raw = isl_union_map_subtract (*may_raw, x_may_raw);
485 else
486 isl_union_map_free (x_may_raw);
488 if (must_raw_no_source)
489 *must_raw_no_source = isl_union_map_subtract (*must_raw_no_source,
490 x_must_raw_no_source);
491 else
492 isl_union_map_free (x_must_raw_no_source);
494 if (may_raw_no_source)
495 *may_raw_no_source = isl_union_map_subtract (*may_raw_no_source,
496 x_may_raw_no_source);
497 else
498 isl_union_map_free (x_may_raw_no_source);
500 if (must_war)
501 *must_war = isl_union_map_subtract (*must_war, x_must_war);
502 else
503 isl_union_map_free (x_must_war);
505 if (may_war)
506 *may_war = isl_union_map_subtract (*may_war, x_may_war);
507 else
508 isl_union_map_free (x_may_war);
510 if (must_war_no_source)
511 *must_war_no_source = isl_union_map_subtract (*must_war_no_source,
512 x_must_war_no_source);
513 else
514 isl_union_map_free (x_must_war_no_source);
516 if (may_war_no_source)
517 *may_war_no_source = isl_union_map_subtract (*may_war_no_source,
518 x_may_war_no_source);
519 else
520 isl_union_map_free (x_may_war_no_source);
522 if (must_waw)
523 *must_waw = isl_union_map_subtract (*must_waw, x_must_waw);
524 else
525 isl_union_map_free (x_must_waw);
527 if (may_waw)
528 *may_waw = isl_union_map_subtract (*may_waw, x_may_waw);
529 else
530 isl_union_map_free (x_may_waw);
532 if (must_waw_no_source)
533 *must_waw_no_source = isl_union_map_subtract (*must_waw_no_source,
534 x_must_waw_no_source);
535 else
536 isl_union_map_free (x_must_waw_no_source);
538 if (may_waw_no_source)
539 *may_waw_no_source = isl_union_map_subtract (*may_waw_no_source,
540 x_may_waw_no_source);
541 else
542 isl_union_map_free (x_may_waw_no_source);
545 isl_union_map_free (original);
546 isl_space_free (space);
549 /* Compute the original data dependences in SCOP for all the reads and
550 writes in PBBS. */
552 void
553 compute_deps (scop_p scop, vec<poly_bb_p> pbbs,
554 isl_union_map **must_raw,
555 isl_union_map **may_raw,
556 isl_union_map **must_raw_no_source,
557 isl_union_map **may_raw_no_source,
558 isl_union_map **must_war,
559 isl_union_map **may_war,
560 isl_union_map **must_war_no_source,
561 isl_union_map **may_war_no_source,
562 isl_union_map **must_waw,
563 isl_union_map **may_waw,
564 isl_union_map **must_waw_no_source,
565 isl_union_map **may_waw_no_source)
567 isl_union_map *reads = scop_get_reads (scop, pbbs);
568 isl_union_map *must_writes = scop_get_must_writes (scop, pbbs);
569 isl_union_map *may_writes = scop_get_may_writes (scop, pbbs);
570 isl_union_map *all_writes = isl_union_map_union
571 (isl_union_map_copy (must_writes), isl_union_map_copy (may_writes));
572 isl_space *space = isl_union_map_get_space (all_writes);
573 isl_union_map *empty = isl_union_map_empty (space);
574 isl_union_map *original = scop_get_original_schedule (scop, pbbs);
575 int res;
577 res = isl_union_map_compute_flow (isl_union_map_copy (reads),
578 isl_union_map_copy (must_writes),
579 isl_union_map_copy (may_writes),
580 isl_union_map_copy (original),
581 must_raw, may_raw, must_raw_no_source,
582 may_raw_no_source);
583 gcc_assert (res == 0);
584 res = isl_union_map_compute_flow (isl_union_map_copy (all_writes),
585 reads, empty,
586 isl_union_map_copy (original),
587 must_war, may_war, must_war_no_source,
588 may_war_no_source);
589 gcc_assert (res == 0);
590 res = isl_union_map_compute_flow (all_writes, must_writes, may_writes,
591 isl_union_map_copy (original),
592 must_waw, may_waw, must_waw_no_source,
593 may_waw_no_source);
594 gcc_assert (res == 0);
596 subtract_commutative_associative_deps
597 (scop, pbbs, original,
598 must_raw, may_raw, must_raw_no_source, may_raw_no_source,
599 must_war, may_war, must_war_no_source, may_war_no_source,
600 must_waw, may_waw, must_waw_no_source, may_waw_no_source);
603 /* Given a TRANSFORM, check whether it respects the original
604 dependences in SCOP. Returns true when TRANSFORM is a safe
605 transformation. */
607 static bool
608 transform_is_safe (scop_p scop, isl_union_map *transform)
610 bool res;
612 if (!scop->must_raw)
613 compute_deps (scop, SCOP_BBS (scop),
614 &scop->must_raw, &scop->may_raw,
615 &scop->must_raw_no_source, &scop->may_raw_no_source,
616 &scop->must_war, &scop->may_war,
617 &scop->must_war_no_source, &scop->may_war_no_source,
618 &scop->must_waw, &scop->may_waw,
619 &scop->must_waw_no_source, &scop->may_waw_no_source);
621 res = (no_violations (transform, scop->must_raw)
622 && no_violations (transform, scop->may_raw)
623 && no_violations (transform, scop->must_war)
624 && no_violations (transform, scop->may_war)
625 && no_violations (transform, scop->must_waw)
626 && no_violations (transform, scop->may_waw));
628 isl_union_map_free (transform);
629 return res;
632 /* Return true when the SCOP transformed schedule is correct. */
634 bool
635 graphite_legal_transform (scop_p scop)
637 int res;
638 isl_union_map *transform;
640 timevar_push (TV_GRAPHITE_DATA_DEPS);
641 transform = scop_get_transformed_schedule (scop, SCOP_BBS (scop));
642 res = transform_is_safe (scop, transform);
643 timevar_pop (TV_GRAPHITE_DATA_DEPS);
645 return res;
648 #endif