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);