add dependence analysis
[platform/upstream/isl.git] / isl_flow.c
1 /*
2  * Copyright 2005-2007 Universiteit Leiden
3  * Copyright 2008-2009 Katholieke Universiteit Leuven
4  * Copyright 2010      INRIA Saclay
5  *
6  * Use of this software is governed by the GNU LGPLv2.1 license
7  *
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 
14  */
15
16 #include <isl_flow.h>
17
18 /* A private structure to keep track of a mapping together with
19  * a user-specified identifier.
20  */
21 struct isl_labeled_map {
22         struct isl_map  *map;
23         void            *data;
24 };
25
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
30  */
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];
37 };
38
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
42  */
43 struct isl_flow {
44         struct isl_set          *no_source;
45         int                     n_source;
46         struct isl_labeled_map  *dep;
47 };
48
49 /* Construct an isl_access_info structure and fill it up with
50  * the given data.  The number of sources is set to 0.
51  */
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)
54 {
55         struct isl_access_info *acc;
56
57         if (!sink)
58                 return NULL;
59
60         isl_assert(sink->ctx, max_source >= 0, goto error);
61
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;
67
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;
73
74         return acc;
75 error:
76         isl_map_free(sink);
77         return NULL;
78 }
79
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.
84  */
85 static isl_access_info_free(__isl_take isl_access_info *acc)
86 {
87         int i;
88
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);
95 }
96
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.
101  */
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)
105 {
106         if (!acc)
107                 return NULL;
108         isl_assert(acc->sink.map->ctx, acc->n_source < acc->max_source, goto error);
109
110         acc->source[acc->n_source].map = source;
111         acc->source[acc->n_source].data = source_user;
112         acc->n_source++;
113
114         return acc;
115 error:
116         isl_map_free(source);
117         isl_access_info_free(acc);
118         return NULL;
119 }
120
121 /* A temporary structure used while sorting the accesses in an isl_access_info.
122  */
123 struct isl_access_sort_info {
124         struct isl_map          *source_map;
125         void                    *source_data;
126         struct isl_access_info  *acc;
127 };
128
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.
132  *
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.
138  */
139 static int access_sort_cmp(const void *p1, const void *p2)
140 {
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;
145
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);
148
149         if (level1 != level2 || !level1)
150                 return level1 - level2;
151
152         level1 = i1->acc->level_before(i1->source_data, i2->source_data);
153
154         return (level1 % 2) ? -1 : 1;
155 }
156
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.
161  */
162 static __isl_give isl_access_info *isl_access_info_sort_sources(
163         __isl_take isl_access_info *acc)
164 {
165         int i;
166         struct isl_access_sort_info *array;
167
168         if (!acc)
169                 return NULL;
170         if (acc->n_source <= 1)
171                 return acc;
172
173         array = isl_alloc_array(acc->sink.map->ctx,
174                                 struct isl_access_sort_info, acc->n_source);
175         if (!array)
176                 goto error;
177
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;
182         }
183
184         qsort(array, acc->n_source, sizeof(struct isl_access_sort_info),
185                 access_sort_cmp);
186
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;
190         }
191
192         free(array);
193
194         return acc;
195 error:
196         isl_access_info_free(acc);
197         return NULL;
198 }
199
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.
204  */
205 static __isl_give isl_flow *isl_flow_alloc(__isl_keep isl_access_info *acc)
206 {
207         int i;
208         struct isl_ctx *ctx;
209         struct isl_flow *dep;
210
211         if (!acc)
212                 return NULL;
213
214         ctx = acc->sink.map->ctx;
215         dep = isl_calloc_type(ctx, struct isl_flow);
216         if (!dep)
217                 return NULL;
218
219         dep->dep = isl_alloc_array(ctx, struct isl_labeled_map, acc->n_source);
220         if (!dep->dep)
221                 goto error;
222
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;
230         }
231
232         return dep;
233 error:
234         isl_flow_free(dep);
235         return NULL;
236 }
237
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.
243  */
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)
247 {
248         int i;
249
250         if (!deps)
251                 return -1;
252
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;
258         }
259
260         return 0;
261 }
262
263 /* Return a copy of the subset of the sink for which no source could be found.
264  */
265 __isl_give isl_set *isl_flow_get_no_source(__isl_keep isl_flow *deps)
266 {
267         if (!deps)
268                 return NULL;
269         
270         return isl_set_copy(deps->no_source);
271 }
272
273 void isl_flow_free(__isl_take isl_flow *deps)
274 {
275         int i;
276
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);
284         }
285         free(deps);
286 }
287
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.
297  */
298 static __isl_give isl_map *after_at_level(struct isl_dim *dim, int level)
299 {
300         struct isl_basic_map *bmap;
301
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);
306
307         return isl_map_from_basic_map(bmap);
308 }
309
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.
314  */
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)
318 {
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;
324
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);
333
334         return result;
335 }
336
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.
342  */
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)
348 {
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;
357
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);
361
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);
374
375         return result;
376 }
377
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.
385  */
386 static int can_precede_at_level(int shared_level, int target_level)
387 {
388         if (shared_level < target_level)
389                 return 0;
390         if ((target_level % 2) && shared_level > target_level)
391                 return 0;
392         return 1;
393 }
394
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.
403  *
404  * If temp_rel[j] is empty, then there can be no improvement and
405  * we return immediately.
406  */
407 static int intermediate_sources(__isl_keep isl_access_info *acc,
408         struct isl_map **temp_rel, int j, int sink_level)
409 {
410         int k, level;
411         int depth = 2 * isl_map_dim(acc->source[j].map, isl_dim_in) + 1;
412
413         if (isl_map_fast_is_empty(temp_rel[j]))
414                 return 0;
415
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;
421
422                 plevel2 = acc->level_before(acc->source[j].data,
423                                                 acc->source[k].data);
424
425                 for (level = sink_level; level <= depth; ++level) {
426                         struct isl_map *T;
427                         struct isl_set *trest;
428                         struct isl_map *copy;
429
430                         if (!can_precede_at_level(plevel2, level))
431                                 continue;
432
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;
440                         }
441                         temp_rel[j] = isl_map_intersect_range(temp_rel[j], trest);
442                         temp_rel[k] = isl_map_union_disjoint(temp_rel[k], T);
443                 }
444         }
445
446         return 0;
447 }
448
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.
459  *
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
477  */
478 __isl_give isl_flow *isl_access_info_compute_flow(__isl_take isl_access_info *acc)
479 {
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;
486
487         acc = isl_access_info_sort_sources(acc);
488
489         res = isl_flow_alloc(acc);
490         if (!res)
491                 goto error;
492         ctx = acc->sink.map->ctx;
493
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;
498
499         temp_rel = isl_alloc_array(ctx, struct isl_map *, acc->n_source);
500
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);
504
505                 for (j = acc->n_source - 1; j >= 0; --j) {
506                         struct isl_map *T;
507                         struct isl_set *rest;
508                         int plevel;
509
510                         plevel = acc->level_before(acc->source[j].data,
511                                                      acc->sink.data);
512                         if (!can_precede_at_level(plevel, level))
513                                 continue;
514
515                         T = last_source(acc, todo, j, level, &rest);
516                         temp_rel[j] = isl_map_union_disjoint(temp_rel[j], T);
517                         todo = rest;
518
519                         intermediate_sources(acc, temp_rel, j, level);
520
521                         if (isl_set_fast_is_empty(todo))
522                                 break;
523                 }
524                 for (j = j - 1; j >= 0; --j) {
525                         int plevel;
526
527                         plevel = acc->level_before(acc->source[j].data,
528                                                      acc->sink.data);
529                         if (!can_precede_at_level(plevel, level))
530                                 continue;
531
532                         intermediate_sources(acc, temp_rel, j, level);
533                 }
534
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;
540         }
541
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;
550 }