doc: fix typos
[isl.git] / isl_flow.c
blob2e51b9296b55a23cec4d89b3f7f6b5c50a1323a3
1 /*
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
16 #include <isl_flow.h>
18 /* A private structure to keep track of a mapping together with
19 * a user-specified identifier.
21 struct isl_labeled_map {
22 struct isl_map *map;
23 void *data;
26 /* A structure containing the input for dependence analysis:
27 * - a sink
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;
34 int max_source;
35 int n_source;
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
43 struct isl_flow {
44 struct isl_set *no_source;
45 int n_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;
57 if (!sink)
58 return NULL;
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));
65 if (!acc)
66 goto error;
68 acc->sink.map = sink;
69 acc->sink.data = sink_user;
70 acc->level_before = fn;
71 acc->max_source = max_source;
72 acc->n_source = 0;
74 return acc;
75 error:
76 isl_map_free(sink);
77 return NULL;
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
83 * he creates.
85 static void isl_access_info_free(__isl_take isl_access_info *acc)
87 int i;
89 if (!acc)
90 return;
91 isl_map_free(acc->sink.map);
92 for (i = 0; i < acc->n_source; ++i)
93 isl_map_free(acc->source[i].map);
94 free(acc);
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,
104 void *source_user)
106 if (!acc)
107 return NULL;
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;
112 acc->n_source++;
114 return acc;
115 error:
116 isl_map_free(source);
117 isl_access_info_free(acc);
118 return NULL;
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;
125 void *source_data;
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
135 * sorted first.
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;
142 int level1, level2;
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)
165 int i;
166 struct isl_access_sort_info *array;
168 if (!acc)
169 return NULL;
170 if (acc->n_source <= 1)
171 return acc;
173 array = isl_alloc_array(acc->sink.map->ctx,
174 struct isl_access_sort_info, acc->n_source);
175 if (!array)
176 goto error;
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;
181 array[i].acc = acc;
184 qsort(array, acc->n_source, sizeof(struct isl_access_sort_info),
185 access_sort_cmp);
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;
192 free(array);
194 return acc;
195 error:
196 isl_access_info_free(acc);
197 return NULL;
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)
207 int i;
208 struct isl_ctx *ctx;
209 struct isl_flow *dep;
211 if (!acc)
212 return NULL;
214 ctx = acc->sink.map->ctx;
215 dep = isl_calloc_type(ctx, struct isl_flow);
216 if (!dep)
217 return NULL;
219 dep->dep = isl_alloc_array(ctx, struct isl_labeled_map, acc->n_source);
220 if (!dep->dep)
221 goto error;
223 dep->n_source = acc->n_source;
224 for (i = 0; i < acc->n_source; ++i) {
225 struct isl_dim *dim;
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;
232 return dep;
233 error:
234 isl_flow_free(dep);
235 return NULL;
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),
246 void *user)
248 int i;
250 if (!deps)
251 return -1;
253 for (i = 0; i < deps->n_source; ++i) {
254 if (isl_map_fast_is_empty(deps->dep[i].map))
255 continue;
256 if (fn(isl_map_copy(deps->dep[i].map), deps->dep[i].data, user) < 0)
257 return -1;
260 return 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)
267 if (!deps)
268 return NULL;
270 return isl_set_copy(deps->no_source);
273 void isl_flow_free(__isl_take isl_flow *deps)
275 int i;
277 if (!deps)
278 return;
279 isl_set_free(deps->no_source);
280 if (deps->dep) {
281 for (i = 0; i < deps->n_source; ++i)
282 isl_map_free(deps->dep[i].map);
283 free(deps->dep);
285 free(deps);
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;
302 if (level % 2)
303 bmap = isl_basic_map_equal(dim, level/2);
304 else
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
313 * in *empty.
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);
334 return 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
341 * after_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)
349 struct isl_dim *dim;
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);
375 return 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)
389 return 0;
390 if ((target_level % 2) && shared_level > target_level)
391 return 0;
392 return 1;
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)
410 int k, 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]))
414 return 0;
416 for (k = j - 1; k >= 0; --k) {
417 int plevel, plevel2;
418 plevel = acc->level_before(acc->source[k].data, acc->sink.data);
419 if (!can_precede_at_level(plevel, sink_level))
420 continue;
422 plevel2 = acc->level_before(acc->source[j].data,
423 acc->source[k].data);
425 for (level = sink_level; level <= depth; ++level) {
426 struct isl_map *T;
427 struct isl_set *trest;
428 struct isl_map *copy;
430 if (!can_precede_at_level(plevel2, level))
431 continue;
433 copy = isl_map_copy(temp_rel[j]);
434 T = last_later_source(acc, copy, j, sink_level, k,
435 level, &trest);
436 if (isl_map_fast_is_empty(T)) {
437 isl_set_free(trest);
438 isl_map_free(T);
439 continue;
441 temp_rel[j] = isl_map_intersect_range(temp_rel[j], trest);
442 temp_rel[k] = isl_map_union_disjoint(temp_rel[k], T);
446 return 0;
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
467 * at that level
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
474 * of dep
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)
480 struct isl_ctx *ctx;
481 struct isl_set *todo;
482 int level, j;
483 int depth;
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);
490 if (!res)
491 goto error;
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))
497 goto done;
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) {
506 struct isl_map *T;
507 struct isl_set *rest;
508 int plevel;
510 plevel = acc->level_before(acc->source[j].data,
511 acc->sink.data);
512 if (!can_precede_at_level(plevel, level))
513 continue;
515 T = last_source(acc, todo, j, level, &rest);
516 temp_rel[j] = isl_map_union_disjoint(temp_rel[j], T);
517 todo = rest;
519 intermediate_sources(acc, temp_rel, j, level);
521 if (isl_set_fast_is_empty(todo))
522 break;
524 for (j = j - 1; j >= 0; --j) {
525 int plevel;
527 plevel = acc->level_before(acc->source[j].data,
528 acc->sink.data);
529 if (!can_precede_at_level(plevel, level))
530 continue;
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,
537 temp_rel[j]);
538 if (isl_set_fast_is_empty(todo))
539 break;
542 free(temp_rel);
543 done:
544 res->no_source = todo;
545 isl_access_info_free(acc);
546 return res;
547 error:
548 isl_access_info_free(acc);
549 return NULL;