2 * Copyright 2005-2007 Universiteit Leiden
3 * Copyright 2008-2009 Katholieke Universiteit Leuven
4 * Copyright 2010 INRIA Saclay
6 * Use of this software is governed by the GNU LGPLv2.1 license
8 * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science,
9 * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands
10 * and K.U.Leuven, Departement Computerwetenschappen, Celestijnenlaan 200A,
11 * B-3001 Leuven, Belgium
12 * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
13 * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
18 /* A private structure to keep track of a mapping together with
19 * a user-specified identifier.
21 struct isl_labeled_map
{
26 /* A structure containing the input for dependence analysis:
28 * - n_source (<= max_source) sources
29 * - a function for determining the relative order of sources and sink
31 struct isl_access_info
{
32 struct isl_labeled_map sink
;
33 isl_access_level_before level_before
;
36 struct isl_labeled_map source
[1];
39 /* A structure containing the output of dependence analysis:
40 * - n_source flow dependences
41 * - a subset of the sink for which no source could be found
44 struct isl_set
*no_source
;
46 struct isl_labeled_map
*dep
;
49 /* Construct an isl_access_info structure and fill it up with
50 * the given data. The number of sources is set to 0.
52 __isl_give isl_access_info
*isl_access_info_alloc(__isl_take isl_map
*sink
,
53 void *sink_user
, isl_access_level_before fn
, int max_source
)
55 struct isl_access_info
*acc
;
60 isl_assert(sink
->ctx
, max_source
>= 0, goto error
);
62 acc
= isl_alloc(sink
->ctx
, struct isl_access_info
,
63 sizeof(struct isl_access_info
) +
64 (max_source
- 1) * sizeof(struct isl_labeled_map
));
69 acc
->sink
.data
= sink_user
;
70 acc
->level_before
= fn
;
71 acc
->max_source
= max_source
;
80 /* Free the given isl_access_info structure.
81 * This function is static because the user is expected to call
82 * isl_access_info_compute_flow on any isl_access_info structure
85 static void isl_access_info_free(__isl_take isl_access_info
*acc
)
91 isl_map_free(acc
->sink
.map
);
92 for (i
= 0; i
< acc
->n_source
; ++i
)
93 isl_map_free(acc
->source
[i
].map
);
97 /* Add another source to an isl_access_info structure.
98 * This function may be called at most max_source times on a
99 * given isl_access_info structure, with max_source as specified
100 * in the call to isl_access_info_alloc that constructed the structure.
102 __isl_give isl_access_info
*isl_access_info_add_source(
103 __isl_take isl_access_info
*acc
, __isl_take isl_map
*source
,
108 isl_assert(acc
->sink
.map
->ctx
, acc
->n_source
< acc
->max_source
, goto error
);
110 acc
->source
[acc
->n_source
].map
= source
;
111 acc
->source
[acc
->n_source
].data
= source_user
;
116 isl_map_free(source
);
117 isl_access_info_free(acc
);
121 /* A temporary structure used while sorting the accesses in an isl_access_info.
123 struct isl_access_sort_info
{
124 struct isl_map
*source_map
;
126 struct isl_access_info
*acc
;
129 /* Return -n, 0 or n (with n a positive value), depending on whether
130 * the source access identified by p1 should be sorted before, together
131 * or after that identified by p2.
133 * If p1 and p2 share a different number of levels with the sink,
134 * then the one with the lowest number of shared levels should be
136 * If they both share no levels, then the order is irrelevant.
137 * Otherwise, if p1 appears before p2, then it should be sorted first.
139 static int access_sort_cmp(const void *p1
, const void *p2
)
141 const struct isl_access_sort_info
*i1
, *i2
;
143 i1
= (const struct isl_access_sort_info
*) p1
;
144 i2
= (const struct isl_access_sort_info
*) p2
;
146 level1
= i1
->acc
->level_before(i1
->source_data
, i1
->acc
->sink
.data
);
147 level2
= i2
->acc
->level_before(i2
->source_data
, i2
->acc
->sink
.data
);
149 if (level1
!= level2
|| !level1
)
150 return level1
- level2
;
152 level1
= i1
->acc
->level_before(i1
->source_data
, i2
->source_data
);
154 return (level1
% 2) ? -1 : 1;
157 /* Sort the source accesses in order of increasing number of shared
158 * levels with the sink access.
159 * Source accesses with the same number of shared levels are sorted
160 * in their textual order.
162 static __isl_give isl_access_info
*isl_access_info_sort_sources(
163 __isl_take isl_access_info
*acc
)
166 struct isl_access_sort_info
*array
;
170 if (acc
->n_source
<= 1)
173 array
= isl_alloc_array(acc
->sink
.map
->ctx
,
174 struct isl_access_sort_info
, acc
->n_source
);
178 for (i
= 0; i
< acc
->n_source
; ++i
) {
179 array
[i
].source_map
= acc
->source
[i
].map
;
180 array
[i
].source_data
= acc
->source
[i
].data
;
184 qsort(array
, acc
->n_source
, sizeof(struct isl_access_sort_info
),
187 for (i
= 0; i
< acc
->n_source
; ++i
) {
188 acc
->source
[i
].map
= array
[i
].source_map
;
189 acc
->source
[i
].data
= array
[i
].source_data
;
196 isl_access_info_free(acc
);
200 /* Initialize an empty isl_flow structure corresponding to a given
201 * isl_access_info structure.
202 * This function is private as isl_flow structures are only supposed
203 * to be created by isl_access_info_compute_flow.
205 static __isl_give isl_flow
*isl_flow_alloc(__isl_keep isl_access_info
*acc
)
209 struct isl_flow
*dep
;
214 ctx
= acc
->sink
.map
->ctx
;
215 dep
= isl_calloc_type(ctx
, struct isl_flow
);
219 dep
->dep
= isl_alloc_array(ctx
, struct isl_labeled_map
, acc
->n_source
);
223 dep
->n_source
= acc
->n_source
;
224 for (i
= 0; i
< acc
->n_source
; ++i
) {
226 dim
= isl_dim_join(isl_dim_copy(acc
->source
[i
].map
->dim
),
227 isl_dim_reverse(isl_dim_copy(acc
->sink
.map
->dim
)));
228 dep
->dep
[i
].map
= isl_map_empty(dim
);
229 dep
->dep
[i
].data
= acc
->source
[i
].data
;
238 /* Iterate over all sources and for each resulting flow dependence
239 * that is not empty, call the user specfied function.
240 * The second argument in this function call identifies the source,
241 * while the third argument correspond to the final argument of
242 * the isl_flow_foreach call.
244 int isl_flow_foreach(__isl_keep isl_flow
*deps
,
245 int (*fn
)(__isl_take isl_map
*dep
, void *dep_user
, void *user
),
253 for (i
= 0; i
< deps
->n_source
; ++i
) {
254 if (isl_map_fast_is_empty(deps
->dep
[i
].map
))
256 if (fn(isl_map_copy(deps
->dep
[i
].map
), deps
->dep
[i
].data
, user
) < 0)
263 /* Return a copy of the subset of the sink for which no source could be found.
265 __isl_give isl_set
*isl_flow_get_no_source(__isl_keep isl_flow
*deps
)
270 return isl_set_copy(deps
->no_source
);
273 void isl_flow_free(__isl_take isl_flow
*deps
)
279 isl_set_free(deps
->no_source
);
281 for (i
= 0; i
< deps
->n_source
; ++i
)
282 isl_map_free(deps
->dep
[i
].map
);
288 /* Return a map that enforces that the domain iteration occurs after
289 * the range iteration at the given level.
290 * If level is odd, then the domain iteration should occur after
291 * the target iteration in their shared level/2 outermost loops.
292 * In this case we simply need to enforce that these outermost
293 * loop iterations are the same.
294 * If level is even, then the loop iterator of the domain should
295 * be greater than the loop iterator of the range at the last
296 * of the level/2 shared loops, i.e., loop level/2 - 1.
298 static __isl_give isl_map
*after_at_level(struct isl_dim
*dim
, int level
)
300 struct isl_basic_map
*bmap
;
303 bmap
= isl_basic_map_equal(dim
, level
/2);
305 bmap
= isl_basic_map_more_at(dim
, level
/2 - 1);
307 return isl_map_from_basic_map(bmap
);
310 /* Compute the last iteration of source j that precedes the sink at the given
311 * level for sink iterations in set_C.
312 * The subset of set_C for which no such iteration can be found is returned
315 static struct isl_map
*last_source(struct isl_access_info
*acc
,
316 struct isl_set
*set_C
,
317 int j
, int level
, struct isl_set
**empty
)
319 struct isl_map
*read_map
;
320 struct isl_map
*write_map
;
321 struct isl_map
*dep_map
;
322 struct isl_map
*after
;
323 struct isl_map
*result
;
325 read_map
= isl_map_copy(acc
->sink
.map
);
326 write_map
= isl_map_copy(acc
->source
[j
].map
);
327 write_map
= isl_map_reverse(write_map
);
328 dep_map
= isl_map_apply_range(read_map
, write_map
);
329 after
= after_at_level(isl_dim_copy(dep_map
->dim
), level
);
330 dep_map
= isl_map_intersect(dep_map
, after
);
331 result
= isl_map_partial_lexmax(dep_map
, set_C
, empty
);
332 result
= isl_map_reverse(result
);
337 /* For a given mapping between iterations of source j and iterations
338 * of the sink, compute the last iteration of source k preceding
339 * the sink at level before_level for any of the sink iterations,
340 * but following the corresponding iteration of source j at level
343 static struct isl_map
*last_later_source(struct isl_access_info
*acc
,
344 struct isl_map
*old_map
,
345 int j
, int before_level
,
346 int k
, int after_level
,
347 struct isl_set
**empty
)
350 struct isl_set
*set_C
;
351 struct isl_map
*read_map
;
352 struct isl_map
*write_map
;
353 struct isl_map
*dep_map
;
354 struct isl_map
*after_write
;
355 struct isl_map
*before_read
;
356 struct isl_map
*result
;
358 set_C
= isl_map_range(isl_map_copy(old_map
));
359 read_map
= isl_map_copy(acc
->sink
.map
);
360 write_map
= isl_map_copy(acc
->source
[k
].map
);
362 write_map
= isl_map_reverse(write_map
);
363 dep_map
= isl_map_apply_range(read_map
, write_map
);
364 dim
= isl_dim_join(isl_dim_copy(acc
->source
[k
].map
->dim
),
365 isl_dim_reverse(isl_dim_copy(acc
->source
[j
].map
->dim
)));
366 after_write
= after_at_level(dim
, after_level
);
367 after_write
= isl_map_apply_range(after_write
, old_map
);
368 after_write
= isl_map_reverse(after_write
);
369 dep_map
= isl_map_intersect(dep_map
, after_write
);
370 before_read
= after_at_level(isl_dim_copy(dep_map
->dim
), before_level
);
371 dep_map
= isl_map_intersect(dep_map
, before_read
);
372 result
= isl_map_partial_lexmax(dep_map
, set_C
, empty
);
373 result
= isl_map_reverse(result
);
378 /* Given a shared_level between two accesses, return 1 if the
379 * the first can precede the second at the requested target_level.
380 * If the target level is odd, i.e., refers to a statement level
381 * dimension, then first needs to precede second at the requested
382 * level, i.e., shared_level must be equal to target_level.
383 * If the target level is odd, then the two loops should share
384 * at least the requested number of outer loops.
386 static int can_precede_at_level(int shared_level
, int target_level
)
388 if (shared_level
< target_level
)
390 if ((target_level
% 2) && shared_level
> target_level
)
395 /* Given a possible flow dependence temp_rel[j] between source j and the sink
396 * at level sink_level, remove those elements for which
397 * there is an iteration of another source k < j that is closer to the sink.
398 * The flow dependences temp_rel[k] are updated with the improved sources.
399 * Any improved source needs to precede the sink at the same level
400 * and needs to follow source j at the same or a deeper level.
401 * The lower this level, the later the execution date of source k.
402 * We therefore consider lower levels first.
404 * If temp_rel[j] is empty, then there can be no improvement and
405 * we return immediately.
407 static int intermediate_sources(__isl_keep isl_access_info
*acc
,
408 struct isl_map
**temp_rel
, int j
, int sink_level
)
411 int depth
= 2 * isl_map_dim(acc
->source
[j
].map
, isl_dim_in
) + 1;
413 if (isl_map_fast_is_empty(temp_rel
[j
]))
416 for (k
= j
- 1; k
>= 0; --k
) {
418 plevel
= acc
->level_before(acc
->source
[k
].data
, acc
->sink
.data
);
419 if (!can_precede_at_level(plevel
, sink_level
))
422 plevel2
= acc
->level_before(acc
->source
[j
].data
,
423 acc
->source
[k
].data
);
425 for (level
= sink_level
; level
<= depth
; ++level
) {
427 struct isl_set
*trest
;
428 struct isl_map
*copy
;
430 if (!can_precede_at_level(plevel2
, level
))
433 copy
= isl_map_copy(temp_rel
[j
]);
434 T
= last_later_source(acc
, copy
, j
, sink_level
, k
,
436 if (isl_map_fast_is_empty(T
)) {
441 temp_rel
[j
] = isl_map_intersect_range(temp_rel
[j
], trest
);
442 temp_rel
[k
] = isl_map_union_disjoint(temp_rel
[k
], T
);
449 /* Given a "sink" access, a list of n "source" accesses,
450 * compute for each iteration of the sink access,
451 * the source access in the list that last accessed the
452 * same element accessed by the sink access before this sink access.
453 * Each access is given as a map from the loop iterators
454 * to the array indices.
455 * The result is a list of n relations between source and sink
456 * iterations and a subset of the domain of the sink access,
457 * corresponding to those iterations that access an element
458 * not previously accessed.
460 * The algorithm considers all levels in which a source may precede the sink,
461 * where a level may either be a statement level or a loop level.
462 * The outermost statement level is 1, the first loop level is 2, etc...
463 * The algorithm basically does the following:
464 * for all levels l of the read access from innermost to outermost
465 * for all sources w that may precede the sink access at that level
466 * compute the last iteration of the source that precedes the sink access
468 * add result to possible last accesses at level l of source w
469 * for all sources w2 that we haven't considered yet at this level that may
470 * also precede the sink access
471 * for all levels l2 of w from l to innermost
472 * for all possible last accesses dep of w at l
473 * compute last iteration of w2 between the source and sink
475 * add result to possible last accesses at level l of write w2
476 * and replace possible last accesses dep by the remainder
478 __isl_give isl_flow
*isl_access_info_compute_flow(__isl_take isl_access_info
*acc
)
481 struct isl_set
*todo
;
484 struct isl_map
**temp_rel
;
485 struct isl_flow
*res
;
487 acc
= isl_access_info_sort_sources(acc
);
489 res
= isl_flow_alloc(acc
);
492 ctx
= acc
->sink
.map
->ctx
;
494 depth
= 2 * isl_map_dim(acc
->sink
.map
, isl_dim_in
) + 1;
495 todo
= isl_map_domain(isl_map_copy(acc
->sink
.map
));
496 if (isl_set_fast_is_empty(todo
))
499 temp_rel
= isl_alloc_array(ctx
, struct isl_map
*, acc
->n_source
);
501 for (level
= depth
; level
>= 1; --level
) {
502 for (j
= acc
->n_source
-1; j
>=0; --j
)
503 temp_rel
[j
] = isl_map_empty_like(res
->dep
[j
].map
);
505 for (j
= acc
->n_source
- 1; j
>= 0; --j
) {
507 struct isl_set
*rest
;
510 plevel
= acc
->level_before(acc
->source
[j
].data
,
512 if (!can_precede_at_level(plevel
, level
))
515 T
= last_source(acc
, todo
, j
, level
, &rest
);
516 temp_rel
[j
] = isl_map_union_disjoint(temp_rel
[j
], T
);
519 intermediate_sources(acc
, temp_rel
, j
, level
);
521 if (isl_set_fast_is_empty(todo
))
524 for (j
= j
- 1; j
>= 0; --j
) {
527 plevel
= acc
->level_before(acc
->source
[j
].data
,
529 if (!can_precede_at_level(plevel
, level
))
532 intermediate_sources(acc
, temp_rel
, j
, level
);
535 for (j
= acc
->n_source
- 1; j
>= 0; --j
)
536 res
->dep
[j
].map
= isl_map_union_disjoint(res
->dep
[j
].map
,
538 if (isl_set_fast_is_empty(todo
))
544 res
->no_source
= todo
;
545 isl_access_info_free(acc
);
548 isl_access_info_free(acc
);