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)
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/>. */
25 /* Workaround for GMP 5.1.3 bug, see PR56019. */
30 #include <isl/union_map.h>
32 #include <isl/constraint.h>
35 #include "coretypes.h"
40 #include "fold-const.h"
41 #include "gimple-iterator.h"
42 #include "tree-ssa-loop.h"
43 #include "tree-pass.h"
45 #include "tree-data-ref.h"
46 #include "graphite-poly.h"
50 scop_get_dependences (scop_p scop
)
52 isl_union_map
*dependences
;
55 compute_deps (scop
, SCOP_BBS (scop
),
56 &scop
->must_raw
, &scop
->may_raw
,
57 &scop
->must_raw_no_source
, &scop
->may_raw_no_source
,
58 &scop
->must_war
, &scop
->may_war
,
59 &scop
->must_war_no_source
, &scop
->may_war_no_source
,
60 &scop
->must_waw
, &scop
->may_waw
,
61 &scop
->must_waw_no_source
, &scop
->may_waw_no_source
);
63 dependences
= isl_union_map_copy (scop
->must_raw
);
64 dependences
= isl_union_map_union (dependences
,
65 isl_union_map_copy (scop
->must_war
));
66 dependences
= isl_union_map_union (dependences
,
67 isl_union_map_copy (scop
->must_waw
));
68 dependences
= isl_union_map_union (dependences
,
69 isl_union_map_copy (scop
->may_raw
));
70 dependences
= isl_union_map_union (dependences
,
71 isl_union_map_copy (scop
->may_war
));
72 dependences
= isl_union_map_union (dependences
,
73 isl_union_map_copy (scop
->may_waw
));
78 /* Add the constraints from the set S to the domain of MAP. */
81 constrain_domain (isl_map
*map
, isl_set
*s
)
83 isl_space
*d
= isl_map_get_space (map
);
84 isl_id
*id
= isl_space_get_tuple_id (d
, isl_dim_in
);
86 s
= isl_set_set_tuple_id (s
, id
);
88 return isl_map_intersect_domain (map
, s
);
91 /* Constrain pdr->accesses with pdr->extent and pbb->domain. */
94 add_pdr_constraints (poly_dr_p pdr
, poly_bb_p pbb
)
96 isl_map
*x
= isl_map_intersect_range (isl_map_copy (pdr
->accesses
),
97 isl_set_copy (pdr
->extent
));
98 x
= constrain_domain (x
, isl_set_copy (pbb
->domain
));
102 /* Returns all the memory reads in SCOP. */
104 static isl_union_map
*
105 scop_get_reads (scop_p scop
, vec
<poly_bb_p
> pbbs
)
110 isl_space
*space
= isl_set_get_space (scop
->context
);
111 isl_union_map
*res
= isl_union_map_empty (space
);
113 FOR_EACH_VEC_ELT (pbbs
, i
, pbb
)
115 FOR_EACH_VEC_ELT (PBB_DRS (pbb
), j
, pdr
)
116 if (pdr_read_p (pdr
))
117 res
= isl_union_map_add_map (res
, add_pdr_constraints (pdr
, pbb
));
123 /* Returns all the memory must writes in SCOP. */
125 static isl_union_map
*
126 scop_get_must_writes (scop_p scop
, vec
<poly_bb_p
> pbbs
)
131 isl_space
*space
= isl_set_get_space (scop
->context
);
132 isl_union_map
*res
= isl_union_map_empty (space
);
134 FOR_EACH_VEC_ELT (pbbs
, i
, pbb
)
136 FOR_EACH_VEC_ELT (PBB_DRS (pbb
), j
, pdr
)
137 if (pdr_write_p (pdr
))
138 res
= isl_union_map_add_map (res
, add_pdr_constraints (pdr
, pbb
));
144 /* Returns all the memory may writes in SCOP. */
146 static isl_union_map
*
147 scop_get_may_writes (scop_p scop
, vec
<poly_bb_p
> pbbs
)
152 isl_space
*space
= isl_set_get_space (scop
->context
);
153 isl_union_map
*res
= isl_union_map_empty (space
);
155 FOR_EACH_VEC_ELT (pbbs
, i
, pbb
)
157 FOR_EACH_VEC_ELT (PBB_DRS (pbb
), j
, pdr
)
158 if (pdr_may_write_p (pdr
))
159 res
= isl_union_map_add_map (res
, add_pdr_constraints (pdr
, pbb
));
165 /* Returns all the original schedules in SCOP. */
167 static isl_union_map
*
168 scop_get_original_schedule (scop_p scop
, vec
<poly_bb_p
> pbbs
)
172 isl_space
*space
= isl_set_get_space (scop
->context
);
173 isl_union_map
*res
= isl_union_map_empty (space
);
175 FOR_EACH_VEC_ELT (pbbs
, i
, pbb
)
177 res
= isl_union_map_add_map
178 (res
, constrain_domain (isl_map_copy (pbb
->schedule
),
179 isl_set_copy (pbb
->domain
)));
185 /* Returns all the transformed schedules in SCOP. */
187 static isl_union_map
*
188 scop_get_transformed_schedule (scop_p scop
, vec
<poly_bb_p
> pbbs
)
192 isl_space
*space
= isl_set_get_space (scop
->context
);
193 isl_union_map
*res
= isl_union_map_empty (space
);
195 FOR_EACH_VEC_ELT (pbbs
, i
, pbb
)
197 res
= isl_union_map_add_map
198 (res
, constrain_domain (isl_map_copy (pbb
->transformed
),
199 isl_set_copy (pbb
->domain
)));
205 /* Helper function used on each MAP of a isl_union_map. Computes the
206 maximal output dimension. */
209 max_number_of_out_dimensions (__isl_take isl_map
*map
, void *user
)
211 int global_max
= *((int *) user
);
212 isl_space
*space
= isl_map_get_space (map
);
213 int nb_out
= isl_space_dim (space
, isl_dim_out
);
215 if (global_max
< nb_out
)
216 *((int *) user
) = nb_out
;
219 isl_space_free (space
);
223 /* Extends the output dimension of MAP to MAX dimensions. */
225 static __isl_give isl_map
*
226 extend_map (__isl_take isl_map
*map
, int max
)
228 isl_space
*space
= isl_map_get_space (map
);
229 int n
= isl_space_dim (space
, isl_dim_out
);
231 isl_space_free (space
);
232 return isl_map_add_dims (map
, isl_dim_out
, max
- n
);
235 /* Structure used to pass parameters to extend_schedule_1. */
237 struct extend_schedule_str
{
242 /* Helper function for extend_schedule. */
245 extend_schedule_1 (__isl_take isl_map
*map
, void *user
)
247 struct extend_schedule_str
*str
= (struct extend_schedule_str
*) user
;
248 str
->umap
= isl_union_map_add_map (str
->umap
, extend_map (map
, str
->max
));
252 /* Return a relation that has uniform output dimensions. */
254 __isl_give isl_union_map
*
255 extend_schedule (__isl_take isl_union_map
*x
)
259 struct extend_schedule_str str
;
261 res
= isl_union_map_foreach_map (x
, max_number_of_out_dimensions
, (void *) &max
);
262 gcc_assert (res
== 0);
265 str
.umap
= isl_union_map_empty (isl_union_map_get_space (x
));
266 res
= isl_union_map_foreach_map (x
, extend_schedule_1
, (void *) &str
);
267 gcc_assert (res
== 0);
269 isl_union_map_free (x
);
273 /* Applies SCHEDULE to the in and out dimensions of the dependences
274 DEPS and return the resulting relation. */
277 apply_schedule_on_deps (__isl_keep isl_union_map
*schedule
,
278 __isl_keep isl_union_map
*deps
)
281 isl_union_map
*ux
, *trans
;
283 trans
= isl_union_map_copy (schedule
);
284 trans
= extend_schedule (trans
);
285 ux
= isl_union_map_copy (deps
);
286 ux
= isl_union_map_apply_domain (ux
, isl_union_map_copy (trans
));
287 ux
= isl_union_map_apply_range (ux
, trans
);
288 if (isl_union_map_is_empty (ux
))
290 isl_union_map_free (ux
);
293 x
= isl_map_from_union_map (ux
);
298 /* Return true when SCHEDULE does not violate the data DEPS: that is
299 when the intersection of LEX with the DEPS transformed by SCHEDULE
300 is empty. LEX is the relation in which the outputs occur before
304 no_violations (__isl_keep isl_union_map
*schedule
,
305 __isl_keep isl_union_map
*deps
)
311 if (isl_union_map_is_empty (deps
))
314 x
= apply_schedule_on_deps (schedule
, deps
);
315 space
= isl_map_get_space (x
);
316 space
= isl_space_range (space
);
317 lex
= isl_map_lex_ge (space
);
318 x
= isl_map_intersect (x
, lex
);
319 res
= isl_map_is_empty (x
);
325 /* Return true when DEPS is non empty and the intersection of LEX with
326 the DEPS transformed by SCHEDULE is non empty. LEX is the relation
327 in which all the inputs before DEPTH occur at the same time as the
328 output, and the input at DEPTH occurs before output. */
331 carries_deps (__isl_keep isl_union_map
*schedule
,
332 __isl_keep isl_union_map
*deps
,
339 isl_constraint
*ineq
;
341 if (isl_union_map_is_empty (deps
))
344 x
= apply_schedule_on_deps (schedule
, deps
);
347 space
= isl_map_get_space (x
);
348 space
= isl_space_range (space
);
349 lex
= isl_map_lex_le (space
);
350 space
= isl_map_get_space (x
);
351 ineq
= isl_inequality_alloc (isl_local_space_from_space (space
));
353 for (i
= 0; i
< depth
- 1; i
++)
354 lex
= isl_map_equate (lex
, isl_dim_in
, i
, isl_dim_out
, i
);
357 ineq
= isl_constraint_set_coefficient_si (ineq
, isl_dim_out
, depth
- 1, 1);
358 ineq
= isl_constraint_set_coefficient_si (ineq
, isl_dim_in
, depth
- 1, -1);
359 ineq
= isl_constraint_set_constant_si (ineq
, -1);
360 lex
= isl_map_add_constraint (lex
, ineq
);
361 x
= isl_map_intersect (x
, lex
);
362 res
= !isl_map_is_empty (x
);
368 /* Subtract from the RAW, WAR, and WAW dependences those relations
369 that have been marked as belonging to an associative commutative
373 subtract_commutative_associative_deps (scop_p scop
,
375 isl_union_map
*original
,
376 isl_union_map
**must_raw
,
377 isl_union_map
**may_raw
,
378 isl_union_map
**must_raw_no_source
,
379 isl_union_map
**may_raw_no_source
,
380 isl_union_map
**must_war
,
381 isl_union_map
**may_war
,
382 isl_union_map
**must_war_no_source
,
383 isl_union_map
**may_war_no_source
,
384 isl_union_map
**must_waw
,
385 isl_union_map
**may_waw
,
386 isl_union_map
**must_waw_no_source
,
387 isl_union_map
**may_waw_no_source
)
392 isl_space
*space
= isl_set_get_space (scop
->context
);
394 FOR_EACH_VEC_ELT (pbbs
, i
, pbb
)
395 if (PBB_IS_REDUCTION (pbb
))
398 isl_union_map
*r
= isl_union_map_empty (isl_space_copy (space
));
399 isl_union_map
*must_w
= isl_union_map_empty (isl_space_copy (space
));
400 isl_union_map
*may_w
= isl_union_map_empty (isl_space_copy (space
));
401 isl_union_map
*all_w
;
402 isl_union_map
*empty
;
403 isl_union_map
*x_must_raw
;
404 isl_union_map
*x_may_raw
;
405 isl_union_map
*x_must_raw_no_source
;
406 isl_union_map
*x_may_raw_no_source
;
407 isl_union_map
*x_must_war
;
408 isl_union_map
*x_may_war
;
409 isl_union_map
*x_must_war_no_source
;
410 isl_union_map
*x_may_war_no_source
;
411 isl_union_map
*x_must_waw
;
412 isl_union_map
*x_may_waw
;
413 isl_union_map
*x_must_waw_no_source
;
414 isl_union_map
*x_may_waw_no_source
;
416 FOR_EACH_VEC_ELT (PBB_DRS (pbb
), j
, pdr
)
417 if (pdr_read_p (pdr
))
418 r
= isl_union_map_add_map (r
, add_pdr_constraints (pdr
, pbb
));
420 FOR_EACH_VEC_ELT (PBB_DRS (pbb
), j
, pdr
)
421 if (pdr_write_p (pdr
))
422 must_w
= isl_union_map_add_map (must_w
,
423 add_pdr_constraints (pdr
, pbb
));
425 FOR_EACH_VEC_ELT (PBB_DRS (pbb
), j
, pdr
)
426 if (pdr_may_write_p (pdr
))
427 may_w
= isl_union_map_add_map (may_w
,
428 add_pdr_constraints (pdr
, pbb
));
430 all_w
= isl_union_map_union
431 (isl_union_map_copy (must_w
), isl_union_map_copy (may_w
));
432 empty
= isl_union_map_empty (isl_union_map_get_space (all_w
));
434 res
= isl_union_map_compute_flow (isl_union_map_copy (r
),
435 isl_union_map_copy (must_w
),
436 isl_union_map_copy (may_w
),
437 isl_union_map_copy (original
),
438 &x_must_raw
, &x_may_raw
,
439 &x_must_raw_no_source
,
440 &x_may_raw_no_source
);
441 gcc_assert (res
== 0);
442 res
= isl_union_map_compute_flow (isl_union_map_copy (all_w
),
444 isl_union_map_copy (original
),
445 &x_must_war
, &x_may_war
,
446 &x_must_war_no_source
,
447 &x_may_war_no_source
);
448 gcc_assert (res
== 0);
449 res
= isl_union_map_compute_flow (all_w
, must_w
, may_w
,
450 isl_union_map_copy (original
),
451 &x_must_waw
, &x_may_waw
,
452 &x_must_waw_no_source
,
453 &x_may_waw_no_source
);
454 gcc_assert (res
== 0);
457 *must_raw
= isl_union_map_subtract (*must_raw
, x_must_raw
);
459 isl_union_map_free (x_must_raw
);
462 *may_raw
= isl_union_map_subtract (*may_raw
, x_may_raw
);
464 isl_union_map_free (x_may_raw
);
466 if (must_raw_no_source
)
467 *must_raw_no_source
= isl_union_map_subtract (*must_raw_no_source
,
468 x_must_raw_no_source
);
470 isl_union_map_free (x_must_raw_no_source
);
472 if (may_raw_no_source
)
473 *may_raw_no_source
= isl_union_map_subtract (*may_raw_no_source
,
474 x_may_raw_no_source
);
476 isl_union_map_free (x_may_raw_no_source
);
479 *must_war
= isl_union_map_subtract (*must_war
, x_must_war
);
481 isl_union_map_free (x_must_war
);
484 *may_war
= isl_union_map_subtract (*may_war
, x_may_war
);
486 isl_union_map_free (x_may_war
);
488 if (must_war_no_source
)
489 *must_war_no_source
= isl_union_map_subtract (*must_war_no_source
,
490 x_must_war_no_source
);
492 isl_union_map_free (x_must_war_no_source
);
494 if (may_war_no_source
)
495 *may_war_no_source
= isl_union_map_subtract (*may_war_no_source
,
496 x_may_war_no_source
);
498 isl_union_map_free (x_may_war_no_source
);
501 *must_waw
= isl_union_map_subtract (*must_waw
, x_must_waw
);
503 isl_union_map_free (x_must_waw
);
506 *may_waw
= isl_union_map_subtract (*may_waw
, x_may_waw
);
508 isl_union_map_free (x_may_waw
);
510 if (must_waw_no_source
)
511 *must_waw_no_source
= isl_union_map_subtract (*must_waw_no_source
,
512 x_must_waw_no_source
);
514 isl_union_map_free (x_must_waw_no_source
);
516 if (may_waw_no_source
)
517 *may_waw_no_source
= isl_union_map_subtract (*may_waw_no_source
,
518 x_may_waw_no_source
);
520 isl_union_map_free (x_may_waw_no_source
);
523 isl_union_map_free (original
);
524 isl_space_free (space
);
527 /* Compute the original data dependences in SCOP for all the reads and
531 compute_deps (scop_p scop
, vec
<poly_bb_p
> pbbs
,
532 isl_union_map
**must_raw
,
533 isl_union_map
**may_raw
,
534 isl_union_map
**must_raw_no_source
,
535 isl_union_map
**may_raw_no_source
,
536 isl_union_map
**must_war
,
537 isl_union_map
**may_war
,
538 isl_union_map
**must_war_no_source
,
539 isl_union_map
**may_war_no_source
,
540 isl_union_map
**must_waw
,
541 isl_union_map
**may_waw
,
542 isl_union_map
**must_waw_no_source
,
543 isl_union_map
**may_waw_no_source
)
545 isl_union_map
*reads
= scop_get_reads (scop
, pbbs
);
546 isl_union_map
*must_writes
= scop_get_must_writes (scop
, pbbs
);
547 isl_union_map
*may_writes
= scop_get_may_writes (scop
, pbbs
);
548 isl_union_map
*all_writes
= isl_union_map_union
549 (isl_union_map_copy (must_writes
), isl_union_map_copy (may_writes
));
550 isl_space
*space
= isl_union_map_get_space (all_writes
);
551 isl_union_map
*empty
= isl_union_map_empty (space
);
552 isl_union_map
*original
= scop_get_original_schedule (scop
, pbbs
);
555 res
= isl_union_map_compute_flow (isl_union_map_copy (reads
),
556 isl_union_map_copy (must_writes
),
557 isl_union_map_copy (may_writes
),
558 isl_union_map_copy (original
),
559 must_raw
, may_raw
, must_raw_no_source
,
561 gcc_assert (res
== 0);
562 res
= isl_union_map_compute_flow (isl_union_map_copy (all_writes
),
564 isl_union_map_copy (original
),
565 must_war
, may_war
, must_war_no_source
,
567 gcc_assert (res
== 0);
568 res
= isl_union_map_compute_flow (all_writes
, must_writes
, may_writes
,
569 isl_union_map_copy (original
),
570 must_waw
, may_waw
, must_waw_no_source
,
572 gcc_assert (res
== 0);
574 subtract_commutative_associative_deps
575 (scop
, pbbs
, original
,
576 must_raw
, may_raw
, must_raw_no_source
, may_raw_no_source
,
577 must_war
, may_war
, must_war_no_source
, may_war_no_source
,
578 must_waw
, may_waw
, must_waw_no_source
, may_waw_no_source
);
581 /* Given a TRANSFORM, check whether it respects the original
582 dependences in SCOP. Returns true when TRANSFORM is a safe
586 transform_is_safe (scop_p scop
, isl_union_map
*transform
)
591 compute_deps (scop
, SCOP_BBS (scop
),
592 &scop
->must_raw
, &scop
->may_raw
,
593 &scop
->must_raw_no_source
, &scop
->may_raw_no_source
,
594 &scop
->must_war
, &scop
->may_war
,
595 &scop
->must_war_no_source
, &scop
->may_war_no_source
,
596 &scop
->must_waw
, &scop
->may_waw
,
597 &scop
->must_waw_no_source
, &scop
->may_waw_no_source
);
599 res
= (no_violations (transform
, scop
->must_raw
)
600 && no_violations (transform
, scop
->may_raw
)
601 && no_violations (transform
, scop
->must_war
)
602 && no_violations (transform
, scop
->may_war
)
603 && no_violations (transform
, scop
->must_waw
)
604 && no_violations (transform
, scop
->may_waw
));
606 isl_union_map_free (transform
);
610 /* Return true when the SCOP transformed schedule is correct. */
613 graphite_legal_transform (scop_p scop
)
616 isl_union_map
*transform
;
618 timevar_push (TV_GRAPHITE_DATA_DEPS
);
619 transform
= scop_get_transformed_schedule (scop
, SCOP_BBS (scop
));
620 res
= transform_is_safe (scop
, transform
);
621 timevar_pop (TV_GRAPHITE_DATA_DEPS
);
626 #endif /* HAVE_isl */