]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/graphite-dependences.c
genattrtab.c (write_header): Include hash-set.h...
[thirdparty/gcc.git] / gcc / graphite-dependences.c
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>.
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
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
31
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"
67
68 #ifdef HAVE_isl
69 #include "graphite-poly.h"
70
71 isl_union_map *
72 scop_get_dependences (scop_p scop)
73 {
74 isl_union_map *dependences;
75
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);
84
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));
96
97 return dependences;
98 }
99
100 /* Add the constraints from the set S to the domain of MAP. */
101
102 static isl_map *
103 constrain_domain (isl_map *map, isl_set *s)
104 {
105 isl_space *d = isl_map_get_space (map);
106 isl_id *id = isl_space_get_tuple_id (d, isl_dim_in);
107
108 s = isl_set_set_tuple_id (s, id);
109 isl_space_free (d);
110 return isl_map_intersect_domain (map, s);
111 }
112
113 /* Constrain pdr->accesses with pdr->extent and pbb->domain. */
114
115 static isl_map *
116 add_pdr_constraints (poly_dr_p pdr, poly_bb_p pbb)
117 {
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;
122 }
123
124 /* Returns all the memory reads in SCOP. */
125
126 static isl_union_map *
127 scop_get_reads (scop_p scop, vec<poly_bb_p> pbbs)
128 {
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);
134
135 FOR_EACH_VEC_ELT (pbbs, i, pbb)
136 {
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));
140 }
141
142 return res;
143 }
144
145 /* Returns all the memory must writes in SCOP. */
146
147 static isl_union_map *
148 scop_get_must_writes (scop_p scop, vec<poly_bb_p> pbbs)
149 {
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);
155
156 FOR_EACH_VEC_ELT (pbbs, i, pbb)
157 {
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));
161 }
162
163 return res;
164 }
165
166 /* Returns all the memory may writes in SCOP. */
167
168 static isl_union_map *
169 scop_get_may_writes (scop_p scop, vec<poly_bb_p> pbbs)
170 {
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);
176
177 FOR_EACH_VEC_ELT (pbbs, i, pbb)
178 {
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));
182 }
183
184 return res;
185 }
186
187 /* Returns all the original schedules in SCOP. */
188
189 static isl_union_map *
190 scop_get_original_schedule (scop_p scop, vec<poly_bb_p> pbbs)
191 {
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);
196
197 FOR_EACH_VEC_ELT (pbbs, i, pbb)
198 {
199 res = isl_union_map_add_map
200 (res, constrain_domain (isl_map_copy (pbb->schedule),
201 isl_set_copy (pbb->domain)));
202 }
203
204 return res;
205 }
206
207 /* Returns all the transformed schedules in SCOP. */
208
209 static isl_union_map *
210 scop_get_transformed_schedule (scop_p scop, vec<poly_bb_p> pbbs)
211 {
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);
216
217 FOR_EACH_VEC_ELT (pbbs, i, pbb)
218 {
219 res = isl_union_map_add_map
220 (res, constrain_domain (isl_map_copy (pbb->transformed),
221 isl_set_copy (pbb->domain)));
222 }
223
224 return res;
225 }
226
227 /* Helper function used on each MAP of a isl_union_map. Computes the
228 maximal output dimension. */
229
230 static int
231 max_number_of_out_dimensions (__isl_take isl_map *map, void *user)
232 {
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);
236
237 if (global_max < nb_out)
238 *((int *) user) = nb_out;
239
240 isl_map_free (map);
241 isl_space_free (space);
242 return 0;
243 }
244
245 /* Extends the output dimension of MAP to MAX dimensions. */
246
247 static __isl_give isl_map *
248 extend_map (__isl_take isl_map *map, int max)
249 {
250 isl_space *space = isl_map_get_space (map);
251 int n = isl_space_dim (space, isl_dim_out);
252
253 isl_space_free (space);
254 return isl_map_add_dims (map, isl_dim_out, max - n);
255 }
256
257 /* Structure used to pass parameters to extend_schedule_1. */
258
259 struct extend_schedule_str {
260 int max;
261 isl_union_map *umap;
262 };
263
264 /* Helper function for extend_schedule. */
265
266 static int
267 extend_schedule_1 (__isl_take isl_map *map, void *user)
268 {
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;
272 }
273
274 /* Return a relation that has uniform output dimensions. */
275
276 __isl_give isl_union_map *
277 extend_schedule (__isl_take isl_union_map *x)
278 {
279 int max = 0;
280 int res;
281 struct extend_schedule_str str;
282
283 res = isl_union_map_foreach_map (x, max_number_of_out_dimensions, (void *) &max);
284 gcc_assert (res == 0);
285
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);
290
291 isl_union_map_free (x);
292 return str.umap;
293 }
294
295 /* Applies SCHEDULE to the in and out dimensions of the dependences
296 DEPS and return the resulting relation. */
297
298 static isl_map *
299 apply_schedule_on_deps (__isl_keep isl_union_map *schedule,
300 __isl_keep isl_union_map *deps)
301 {
302 isl_map *x;
303 isl_union_map *ux, *trans;
304
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))
311 {
312 isl_union_map_free (ux);
313 return NULL;
314 }
315 x = isl_map_from_union_map (ux);
316
317 return x;
318 }
319
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. */
324
325 static bool
326 no_violations (__isl_keep isl_union_map *schedule,
327 __isl_keep isl_union_map *deps)
328 {
329 bool res;
330 isl_space *space;
331 isl_map *lex, *x;
332
333 if (isl_union_map_is_empty (deps))
334 return true;
335
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);
342
343 isl_map_free (x);
344 return res;
345 }
346
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. */
351
352 bool
353 carries_deps (__isl_keep isl_union_map *schedule,
354 __isl_keep isl_union_map *deps,
355 int depth)
356 {
357 bool res;
358 int i;
359 isl_space *space;
360 isl_map *lex, *x;
361 isl_constraint *ineq;
362
363 if (isl_union_map_is_empty (deps))
364 return false;
365
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));
374
375 for (i = 0; i < depth - 1; i++)
376 lex = isl_map_equate (lex, isl_dim_in, i, isl_dim_out, i);
377
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);
385
386 isl_map_free (x);
387 return res;
388 }
389
390 /* Subtract from the RAW, WAR, and WAW dependences those relations
391 that have been marked as belonging to an associative commutative
392 reduction. */
393
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)
410 {
411 int i, j;
412 poly_bb_p pbb;
413 poly_dr_p pdr;
414 isl_space *space = isl_set_get_space (scop->context);
415
416 FOR_EACH_VEC_ELT (pbbs, i, pbb)
417 if (PBB_IS_REDUCTION (pbb))
418 {
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;
437
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));
441
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));
446
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));
451
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));
455
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);
477
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);
482
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);
487
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);
493
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);
499
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);
504
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);
509
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);
515
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);
521
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);
526
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);
531
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);
537
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);
543 }
544
545 isl_union_map_free (original);
546 isl_space_free (space);
547 }
548
549 /* Compute the original data dependences in SCOP for all the reads and
550 writes in PBBS. */
551
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)
566 {
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;
576
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);
595
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);
601 }
602
603 /* Given a TRANSFORM, check whether it respects the original
604 dependences in SCOP. Returns true when TRANSFORM is a safe
605 transformation. */
606
607 static bool
608 transform_is_safe (scop_p scop, isl_union_map *transform)
609 {
610 bool res;
611
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);
620
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));
627
628 isl_union_map_free (transform);
629 return res;
630 }
631
632 /* Return true when the SCOP transformed schedule is correct. */
633
634 bool
635 graphite_legal_transform (scop_p scop)
636 {
637 int res;
638 isl_union_map *transform;
639
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);
644
645 return res;
646 }
647
648 #endif