isl_transitive_closure.c: increment: clean up space manipulation
[isl.git] / isl_schedule_band.c
blob652b1614e0cd968a77b779cf07abd6745ee43327
1 /*
2 * Copyright 2013-2014 Ecole Normale Superieure
3 * Copyright 2014 INRIA Rocquencourt
5 * Use of this software is governed by the MIT license
7 * Written by Sven Verdoolaege,
8 * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
9 * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
10 * B.P. 105 - 78153 Le Chesnay, France
13 #include <string.h>
14 #include <isl/val.h>
15 #include <isl/space.h>
16 #include <isl/map.h>
17 #include <isl/schedule_node.h>
18 #include <isl_schedule_band.h>
19 #include <isl_schedule_private.h>
21 isl_ctx *isl_schedule_band_get_ctx(__isl_keep isl_schedule_band *band)
23 return band ? isl_multi_union_pw_aff_get_ctx(band->mupa) : NULL;
26 /* Return a new uninitialized isl_schedule_band.
28 static __isl_give isl_schedule_band *isl_schedule_band_alloc(isl_ctx *ctx)
30 isl_schedule_band *band;
32 band = isl_calloc_type(ctx, isl_schedule_band);
33 if (!band)
34 return NULL;
36 band->ref = 1;
38 return band;
41 /* Return a new isl_schedule_band with partial schedule "mupa".
42 * First replace "mupa" by its greatest integer part to ensure
43 * that the schedule is always integral.
44 * The band is not marked permutable, the dimensions are not
45 * marked coincident and the AST build options are empty.
46 * Since there are no build options, the node is not anchored.
48 __isl_give isl_schedule_band *isl_schedule_band_from_multi_union_pw_aff(
49 __isl_take isl_multi_union_pw_aff *mupa)
51 isl_ctx *ctx;
52 isl_schedule_band *band;
53 isl_space *space;
55 mupa = isl_multi_union_pw_aff_floor(mupa);
56 if (!mupa)
57 return NULL;
58 ctx = isl_multi_union_pw_aff_get_ctx(mupa);
59 band = isl_schedule_band_alloc(ctx);
60 if (!band)
61 goto error;
63 band->n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
64 band->coincident = isl_calloc_array(ctx, int, band->n);
65 band->mupa = mupa;
66 space = isl_space_params_alloc(ctx, 0);
67 band->ast_build_options = isl_union_set_empty(space);
68 band->anchored = 0;
70 if ((band->n && !band->coincident) || !band->ast_build_options)
71 return isl_schedule_band_free(band);
73 return band;
74 error:
75 isl_multi_union_pw_aff_free(mupa);
76 return NULL;
79 /* Create a duplicate of the given isl_schedule_band.
81 __isl_give isl_schedule_band *isl_schedule_band_dup(
82 __isl_keep isl_schedule_band *band)
84 int i;
85 isl_ctx *ctx;
86 isl_schedule_band *dup;
88 if (!band)
89 return NULL;
91 ctx = isl_schedule_band_get_ctx(band);
92 dup = isl_schedule_band_alloc(ctx);
93 if (!dup)
94 return NULL;
96 dup->n = band->n;
97 dup->coincident = isl_alloc_array(ctx, int, band->n);
98 if (band->n && !dup->coincident)
99 return isl_schedule_band_free(dup);
101 for (i = 0; i < band->n; ++i)
102 dup->coincident[i] = band->coincident[i];
103 dup->permutable = band->permutable;
105 dup->mupa = isl_multi_union_pw_aff_copy(band->mupa);
106 dup->ast_build_options = isl_union_set_copy(band->ast_build_options);
107 if (!dup->mupa || !dup->ast_build_options)
108 return isl_schedule_band_free(dup);
110 if (band->loop_type) {
111 dup->loop_type = isl_alloc_array(ctx,
112 enum isl_ast_loop_type, band->n);
113 if (band->n && !dup->loop_type)
114 return isl_schedule_band_free(dup);
115 for (i = 0; i < band->n; ++i)
116 dup->loop_type[i] = band->loop_type[i];
118 if (band->isolate_loop_type) {
119 dup->isolate_loop_type = isl_alloc_array(ctx,
120 enum isl_ast_loop_type, band->n);
121 if (band->n && !dup->isolate_loop_type)
122 return isl_schedule_band_free(dup);
123 for (i = 0; i < band->n; ++i)
124 dup->isolate_loop_type[i] = band->isolate_loop_type[i];
127 return dup;
130 /* Return an isl_schedule_band that is equal to "band" and that has only
131 * a single reference.
133 __isl_give isl_schedule_band *isl_schedule_band_cow(
134 __isl_take isl_schedule_band *band)
136 if (!band)
137 return NULL;
139 if (band->ref == 1)
140 return band;
141 band->ref--;
142 return isl_schedule_band_dup(band);
145 /* Return a new reference to "band".
147 __isl_give isl_schedule_band *isl_schedule_band_copy(
148 __isl_keep isl_schedule_band *band)
150 if (!band)
151 return NULL;
153 band->ref++;
154 return band;
157 /* Free a reference to "band" and return NULL.
159 __isl_null isl_schedule_band *isl_schedule_band_free(
160 __isl_take isl_schedule_band *band)
162 if (!band)
163 return NULL;
165 if (--band->ref > 0)
166 return NULL;
168 isl_multi_union_pw_aff_free(band->mupa);
169 isl_union_set_free(band->ast_build_options);
170 free(band->loop_type);
171 free(band->isolate_loop_type);
172 free(band->coincident);
173 free(band);
175 return NULL;
178 /* Are "band1" and "band2" obviously equal?
180 isl_bool isl_schedule_band_plain_is_equal(__isl_keep isl_schedule_band *band1,
181 __isl_keep isl_schedule_band *band2)
183 int i;
184 isl_bool equal;
186 if (!band1 || !band2)
187 return isl_bool_error;
188 if (band1 == band2)
189 return isl_bool_true;
191 if (band1->n != band2->n)
192 return isl_bool_false;
193 for (i = 0; i < band1->n; ++i)
194 if (band1->coincident[i] != band2->coincident[i])
195 return isl_bool_false;
196 if (band1->permutable != band2->permutable)
197 return isl_bool_false;
199 equal = isl_multi_union_pw_aff_plain_is_equal(band1->mupa, band2->mupa);
200 if (equal < 0 || !equal)
201 return equal;
203 if (!band1->loop_type != !band2->loop_type)
204 return isl_bool_false;
205 if (band1->loop_type)
206 for (i = 0; i < band1->n; ++i)
207 if (band1->loop_type[i] != band2->loop_type[i])
208 return isl_bool_false;
210 if (!band1->isolate_loop_type != !band2->isolate_loop_type)
211 return isl_bool_false;
212 if (band1->isolate_loop_type)
213 for (i = 0; i < band1->n; ++i)
214 if (band1->isolate_loop_type[i] !=
215 band2->isolate_loop_type[i])
216 return isl_bool_false;
218 return isl_union_set_is_equal(band1->ast_build_options,
219 band2->ast_build_options);
222 /* Return the number of scheduling dimensions in the band.
224 int isl_schedule_band_n_member(__isl_keep isl_schedule_band *band)
226 return band ? band->n : 0;
229 /* Is the given scheduling dimension coincident within the band and
230 * with respect to the coincidence constraints?
232 isl_bool isl_schedule_band_member_get_coincident(
233 __isl_keep isl_schedule_band *band, int pos)
235 if (!band)
236 return isl_bool_error;
238 if (pos < 0 || pos >= band->n)
239 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
240 "invalid member position", return isl_bool_error);
242 return band->coincident[pos];
245 /* Mark the given scheduling dimension as being coincident or not
246 * according to "coincident".
248 __isl_give isl_schedule_band *isl_schedule_band_member_set_coincident(
249 __isl_take isl_schedule_band *band, int pos, int coincident)
251 if (!band)
252 return NULL;
253 if (isl_schedule_band_member_get_coincident(band, pos) == coincident)
254 return band;
255 band = isl_schedule_band_cow(band);
256 if (!band)
257 return NULL;
259 if (pos < 0 || pos >= band->n)
260 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
261 "invalid member position",
262 return isl_schedule_band_free(band));
264 band->coincident[pos] = coincident;
266 return band;
269 /* Is the schedule band mark permutable?
271 isl_bool isl_schedule_band_get_permutable(__isl_keep isl_schedule_band *band)
273 if (!band)
274 return isl_bool_error;
275 return band->permutable;
278 /* Mark the schedule band permutable or not according to "permutable"?
280 __isl_give isl_schedule_band *isl_schedule_band_set_permutable(
281 __isl_take isl_schedule_band *band, int permutable)
283 if (!band)
284 return NULL;
285 if (band->permutable == permutable)
286 return band;
287 band = isl_schedule_band_cow(band);
288 if (!band)
289 return NULL;
291 band->permutable = permutable;
293 return band;
296 /* Is the band node "node" anchored? That is, does it reference
297 * the outer band nodes?
299 int isl_schedule_band_is_anchored(__isl_keep isl_schedule_band *band)
301 return band ? band->anchored : -1;
304 /* Return the schedule space of the band.
306 __isl_give isl_space *isl_schedule_band_get_space(
307 __isl_keep isl_schedule_band *band)
309 if (!band)
310 return NULL;
311 return isl_multi_union_pw_aff_get_space(band->mupa);
314 /* Intersect the domain of the band schedule of "band" with "domain".
316 __isl_give isl_schedule_band *isl_schedule_band_intersect_domain(
317 __isl_take isl_schedule_band *band, __isl_take isl_union_set *domain)
319 band = isl_schedule_band_cow(band);
320 if (!band || !domain)
321 goto error;
323 band->mupa = isl_multi_union_pw_aff_intersect_domain(band->mupa,
324 domain);
325 if (!band->mupa)
326 return isl_schedule_band_free(band);
328 return band;
329 error:
330 isl_schedule_band_free(band);
331 isl_union_set_free(domain);
332 return NULL;
335 /* Return the schedule of the band in isolation.
337 __isl_give isl_multi_union_pw_aff *isl_schedule_band_get_partial_schedule(
338 __isl_keep isl_schedule_band *band)
340 return band ? isl_multi_union_pw_aff_copy(band->mupa) : NULL;
343 /* Replace the schedule of "band" by "schedule".
345 __isl_give isl_schedule_band *isl_schedule_band_set_partial_schedule(
346 __isl_take isl_schedule_band *band,
347 __isl_take isl_multi_union_pw_aff *schedule)
349 band = isl_schedule_band_cow(band);
350 if (!band || !schedule)
351 goto error;
353 isl_multi_union_pw_aff_free(band->mupa);
354 band->mupa = schedule;
356 return band;
357 error:
358 isl_schedule_band_free(band);
359 isl_multi_union_pw_aff_free(schedule);
360 return NULL;
363 /* Return the loop AST generation type for the band member of "band"
364 * at position "pos".
366 enum isl_ast_loop_type isl_schedule_band_member_get_ast_loop_type(
367 __isl_keep isl_schedule_band *band, int pos)
369 if (!band)
370 return isl_ast_loop_error;
372 if (pos < 0 || pos >= band->n)
373 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
374 "invalid member position", return isl_ast_loop_error);
376 if (!band->loop_type)
377 return isl_ast_loop_default;
379 return band->loop_type[pos];
382 /* Set the loop AST generation type for the band member of "band"
383 * at position "pos" to "type".
385 __isl_give isl_schedule_band *isl_schedule_band_member_set_ast_loop_type(
386 __isl_take isl_schedule_band *band, int pos,
387 enum isl_ast_loop_type type)
389 if (!band)
390 return NULL;
391 if (isl_schedule_band_member_get_ast_loop_type(band, pos) == type)
392 return band;
394 if (pos < 0 || pos >= band->n)
395 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
396 "invalid member position",
397 return isl_schedule_band_free(band));
399 band = isl_schedule_band_cow(band);
400 if (!band)
401 return isl_schedule_band_free(band);
403 if (!band->loop_type) {
404 isl_ctx *ctx;
406 ctx = isl_schedule_band_get_ctx(band);
407 band->loop_type = isl_calloc_array(ctx,
408 enum isl_ast_loop_type, band->n);
409 if (band->n && !band->loop_type)
410 return isl_schedule_band_free(band);
413 band->loop_type[pos] = type;
415 return band;
418 /* Return the loop AST generation type for the band member of "band"
419 * at position "pos" for the part that has been isolated by the isolate option.
421 enum isl_ast_loop_type isl_schedule_band_member_get_isolate_ast_loop_type(
422 __isl_keep isl_schedule_band *band, int pos)
424 if (!band)
425 return isl_ast_loop_error;
427 if (pos < 0 || pos >= band->n)
428 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
429 "invalid member position", return isl_ast_loop_error);
431 if (!band->isolate_loop_type)
432 return isl_ast_loop_default;
434 return band->isolate_loop_type[pos];
437 /* Set the loop AST generation type for the band member of "band"
438 * at position "pos" to "type" for the part that has been isolated
439 * by the isolate option.
441 __isl_give isl_schedule_band *
442 isl_schedule_band_member_set_isolate_ast_loop_type(
443 __isl_take isl_schedule_band *band, int pos,
444 enum isl_ast_loop_type type)
446 if (!band)
447 return NULL;
448 if (isl_schedule_band_member_get_isolate_ast_loop_type(band, pos) ==
449 type)
450 return band;
452 if (pos < 0 || pos >= band->n)
453 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
454 "invalid member position",
455 return isl_schedule_band_free(band));
457 band = isl_schedule_band_cow(band);
458 if (!band)
459 return isl_schedule_band_free(band);
461 if (!band->isolate_loop_type) {
462 isl_ctx *ctx;
464 ctx = isl_schedule_band_get_ctx(band);
465 band->isolate_loop_type = isl_calloc_array(ctx,
466 enum isl_ast_loop_type, band->n);
467 if (band->n && !band->isolate_loop_type)
468 return isl_schedule_band_free(band);
471 band->isolate_loop_type[pos] = type;
473 return band;
476 static const char *option_str[] = {
477 [isl_ast_loop_atomic] = "atomic",
478 [isl_ast_loop_unroll] = "unroll",
479 [isl_ast_loop_separate] = "separate"
482 /* Given a parameter space "space", extend it to a set space
484 * { type[x] }
486 * or
488 * { [isolate[] -> type[x]] }
490 * depending on whether "isolate" is set.
491 * These can be used to encode loop AST generation options of the given type.
493 static __isl_give isl_space *loop_type_space(__isl_take isl_space *space,
494 enum isl_ast_loop_type type, int isolate)
496 const char *name;
498 name = option_str[type];
499 space = isl_space_set_from_params(space);
500 space = isl_space_add_dims(space, isl_dim_set, 1);
501 space = isl_space_set_tuple_name(space, isl_dim_set, name);
502 if (!isolate)
503 return space;
504 space = isl_space_from_range(space);
505 space = isl_space_set_tuple_name(space, isl_dim_in, "isolate");
506 space = isl_space_wrap(space);
508 return space;
511 /* Add encodings of the "n" loop AST generation options "type" to "options".
512 * If "isolate" is set, then these options refer to the isolated part.
514 * In particular, for each sequence of consecutive identical types "t",
515 * different from the default, add an option
517 * { t[x] : first <= x <= last }
519 * or
521 * { [isolate[] -> t[x]] : first <= x <= last }
523 static __isl_give isl_union_set *add_loop_types(
524 __isl_take isl_union_set *options, int n, enum isl_ast_loop_type *type,
525 int isolate)
527 int i;
529 if (!type)
530 return options;
531 if (!options)
532 return NULL;
534 for (i = 0; i < n; ++i) {
535 int first;
536 isl_space *space;
537 isl_set *option;
539 if (type[i] == isl_ast_loop_default)
540 continue;
542 first = i;
543 while (i + 1 < n && type[i + 1] == type[i])
544 ++i;
546 space = isl_union_set_get_space(options);
547 space = loop_type_space(space, type[i], isolate);
548 option = isl_set_universe(space);
549 option = isl_set_lower_bound_si(option, isl_dim_set, 0, first);
550 option = isl_set_upper_bound_si(option, isl_dim_set, 0, i);
551 options = isl_union_set_add_set(options, option);
554 return options;
557 /* Return the AST build options associated to "band".
559 __isl_give isl_union_set *isl_schedule_band_get_ast_build_options(
560 __isl_keep isl_schedule_band *band)
562 isl_union_set *options;
564 if (!band)
565 return NULL;
567 options = isl_union_set_copy(band->ast_build_options);
568 options = add_loop_types(options, band->n, band->loop_type, 0);
569 options = add_loop_types(options, band->n, band->isolate_loop_type, 1);
571 return options;
574 /* Does "uset" contain any set that satisfies "is"?
575 * "is" is assumed to set its integer argument to isl_bool_true
576 * if it is satisfied.
578 static isl_bool has_any(__isl_keep isl_union_set *uset,
579 isl_stat (*is)(__isl_take isl_set *set, void *user))
581 isl_bool found = isl_bool_false;
583 if (isl_union_set_foreach_set(uset, is, &found) < 0 && !found)
584 return isl_bool_error;
586 return found;
589 /* Does "set" live in a space of the form
591 * isolate[[...] -> [...]]
595 * If so, set *found and abort the search.
597 static isl_stat is_isolate(__isl_take isl_set *set, void *user)
599 isl_bool *found = user;
601 if (isl_set_has_tuple_name(set)) {
602 const char *name;
603 name = isl_set_get_tuple_name(set);
604 if (isl_set_is_wrapping(set) && !strcmp(name, "isolate"))
605 *found = isl_bool_true;
607 isl_set_free(set);
609 return *found ? isl_stat_error : isl_stat_ok;
612 /* Does "options" include an option of the ofrm
614 * isolate[[...] -> [...]]
618 static isl_bool has_isolate_option(__isl_keep isl_union_set *options)
620 return has_any(options, &is_isolate);
623 /* Does "set" encode a loop AST generation option?
625 static isl_stat is_loop_type_option(__isl_take isl_set *set, void *user)
627 isl_bool *found = user;
629 if (isl_set_dim(set, isl_dim_set) == 1 &&
630 isl_set_has_tuple_name(set)) {
631 const char *name;
632 enum isl_ast_loop_type type;
633 name = isl_set_get_tuple_name(set);
634 for (type = isl_ast_loop_atomic;
635 type <= isl_ast_loop_separate; ++type) {
636 if (strcmp(name, option_str[type]))
637 continue;
638 *found = isl_bool_true;
639 break;
642 isl_set_free(set);
644 return *found ? isl_stat_error : isl_stat_ok;
647 /* Does "set" encode a loop AST generation option for the isolated part?
648 * That is, is of the form
650 * { [isolate[] -> t[x]] }
652 * with t equal to "atomic", "unroll" or "separate"?
654 static isl_stat is_isolate_loop_type_option(__isl_take isl_set *set, void *user)
656 isl_bool *found = user;
657 const char *name;
658 enum isl_ast_loop_type type;
659 isl_map *map;
661 if (!isl_set_is_wrapping(set)) {
662 isl_set_free(set);
663 return isl_stat_ok;
665 map = isl_set_unwrap(set);
666 if (!isl_map_has_tuple_name(map, isl_dim_in) ||
667 !isl_map_has_tuple_name(map, isl_dim_out)) {
668 isl_map_free(map);
669 return isl_stat_ok;
671 name = isl_map_get_tuple_name(map, isl_dim_in);
672 if (!strcmp(name, "isolate")) {
673 name = isl_map_get_tuple_name(map, isl_dim_out);
674 for (type = isl_ast_loop_atomic;
675 type <= isl_ast_loop_separate; ++type) {
676 if (strcmp(name, option_str[type]))
677 continue;
678 *found = isl_bool_true;
679 break;
682 isl_map_free(map);
684 return *found ? isl_stat_error : isl_stat_ok;
687 /* Does "options" encode any loop AST generation options
688 * for the isolated part?
690 static isl_bool has_isolate_loop_type_options(__isl_keep isl_union_set *options)
692 return has_any(options, &is_isolate_loop_type_option);
695 /* Does "options" encode any loop AST generation options?
697 static isl_bool has_loop_type_options(__isl_keep isl_union_set *options)
699 return has_any(options, &is_loop_type_option);
702 /* Extract the loop AST generation type for the band member
703 * at position "pos" from "options".
704 * If "isolate" is set, then extract the loop types for the isolated part.
706 static enum isl_ast_loop_type extract_loop_type(
707 __isl_keep isl_union_set *options, int pos, int isolate)
709 isl_ctx *ctx;
710 enum isl_ast_loop_type type, res = isl_ast_loop_default;
712 ctx = isl_union_set_get_ctx(options);
713 for (type = isl_ast_loop_atomic;
714 type <= isl_ast_loop_separate; ++type) {
715 isl_space *space;
716 isl_set *option;
717 int empty;
719 space = isl_union_set_get_space(options);
720 space = loop_type_space(space, type, isolate);
721 option = isl_union_set_extract_set(options, space);
722 option = isl_set_fix_si(option, isl_dim_set, 0, pos);
723 empty = isl_set_is_empty(option);
724 isl_set_free(option);
726 if (empty < 0)
727 return isl_ast_loop_error;
728 if (empty)
729 continue;
730 if (res != isl_ast_loop_default)
731 isl_die(ctx, isl_error_invalid,
732 "conflicting loop type options",
733 return isl_ast_loop_error);
734 res = type;
737 return res;
740 /* Extract the loop AST generation types for the members of "band"
741 * from "options" and store them in band->loop_type.
742 * Return -1 on error.
744 static int extract_loop_types(__isl_keep isl_schedule_band *band,
745 __isl_keep isl_union_set *options)
747 int i;
749 if (!band->loop_type) {
750 isl_ctx *ctx = isl_schedule_band_get_ctx(band);
751 band->loop_type = isl_alloc_array(ctx,
752 enum isl_ast_loop_type, band->n);
753 if (band->n && !band->loop_type)
754 return -1;
756 for (i = 0; i < band->n; ++i) {
757 band->loop_type[i] = extract_loop_type(options, i, 0);
758 if (band->loop_type[i] == isl_ast_loop_error)
759 return -1;
762 return 0;
765 /* Extract the loop AST generation types for the members of "band"
766 * from "options" for the isolated part and
767 * store them in band->isolate_loop_type.
768 * Return -1 on error.
770 static int extract_isolate_loop_types(__isl_keep isl_schedule_band *band,
771 __isl_keep isl_union_set *options)
773 int i;
775 if (!band->isolate_loop_type) {
776 isl_ctx *ctx = isl_schedule_band_get_ctx(band);
777 band->isolate_loop_type = isl_alloc_array(ctx,
778 enum isl_ast_loop_type, band->n);
779 if (band->n && !band->isolate_loop_type)
780 return -1;
782 for (i = 0; i < band->n; ++i) {
783 band->isolate_loop_type[i] = extract_loop_type(options, i, 1);
784 if (band->isolate_loop_type[i] == isl_ast_loop_error)
785 return -1;
788 return 0;
791 /* Construct universe sets of the spaces that encode loop AST generation
792 * types (for the isolated part if "isolate" is set). That is, construct
794 * { atomic[x]; separate[x]; unroll[x] }
796 * or
798 * { [isolate[] -> atomic[x]]; [isolate[] -> separate[x]];
799 * [isolate[] -> unroll[x]] }
801 static __isl_give isl_union_set *loop_types(__isl_take isl_space *space,
802 int isolate)
804 enum isl_ast_loop_type type;
805 isl_union_set *types;
807 types = isl_union_set_empty(space);
808 for (type = isl_ast_loop_atomic;
809 type <= isl_ast_loop_separate; ++type) {
810 isl_set *set;
812 space = isl_union_set_get_space(types);
813 space = loop_type_space(space, type, isolate);
814 set = isl_set_universe(space);
815 types = isl_union_set_add_set(types, set);
818 return types;
821 /* Remove all elements from spaces that encode loop AST generation types
822 * from "options".
824 static __isl_give isl_union_set *clear_loop_types(
825 __isl_take isl_union_set *options)
827 isl_union_set *types;
829 types = loop_types(isl_union_set_get_space(options), 0);
830 options = isl_union_set_subtract(options, types);
832 return options;
835 /* Remove all elements from spaces that encode loop AST generation types
836 * for the isolated part from "options".
838 static __isl_give isl_union_set *clear_isolate_loop_types(
839 __isl_take isl_union_set *options)
841 isl_union_set *types;
843 types = loop_types(isl_union_set_get_space(options), 1);
844 options = isl_union_set_subtract(options, types);
846 return options;
849 /* Replace the AST build options associated to "band" by "options".
850 * If there are any loop AST generation type options, then they
851 * are extracted and stored in band->loop_type. Otherwise,
852 * band->loop_type is removed to indicate that the default applies
853 * to all members. Similarly for the loop AST generation type options
854 * for the isolated part, which are stored in band->isolate_loop_type.
855 * The remaining options are stored in band->ast_build_options.
857 * Set anchored if the options include an isolate option since the
858 * domain of the wrapped map references the outer band node schedules.
860 __isl_give isl_schedule_band *isl_schedule_band_set_ast_build_options(
861 __isl_take isl_schedule_band *band, __isl_take isl_union_set *options)
863 isl_bool has_isolate, has_loop_type, has_isolate_loop_type;
865 band = isl_schedule_band_cow(band);
866 if (!band || !options)
867 goto error;
868 has_isolate = has_isolate_option(options);
869 if (has_isolate < 0)
870 goto error;
871 has_loop_type = has_loop_type_options(options);
872 if (has_loop_type < 0)
873 goto error;
874 has_isolate_loop_type = has_isolate_loop_type_options(options);
875 if (has_isolate_loop_type < 0)
876 goto error;
878 if (!has_loop_type) {
879 free(band->loop_type);
880 band->loop_type = NULL;
881 } else {
882 if (extract_loop_types(band, options) < 0)
883 goto error;
884 options = clear_loop_types(options);
885 if (!options)
886 goto error;
889 if (!has_isolate_loop_type) {
890 free(band->isolate_loop_type);
891 band->isolate_loop_type = NULL;
892 } else {
893 if (extract_isolate_loop_types(band, options) < 0)
894 goto error;
895 options = clear_isolate_loop_types(options);
896 if (!options)
897 goto error;
900 isl_union_set_free(band->ast_build_options);
901 band->ast_build_options = options;
902 band->anchored = has_isolate;
904 return band;
905 error:
906 isl_schedule_band_free(band);
907 isl_union_set_free(options);
908 return NULL;
911 /* Return the "isolate" option associated to "band", assuming
912 * it at appears at schedule depth "depth".
914 * The isolate option is of the form
916 * isolate[[flattened outer bands] -> band]
918 __isl_give isl_set *isl_schedule_band_get_ast_isolate_option(
919 __isl_keep isl_schedule_band *band, int depth)
921 isl_space *space;
922 isl_set *isolate;
924 if (!band)
925 return NULL;
927 space = isl_schedule_band_get_space(band);
928 space = isl_space_from_range(space);
929 space = isl_space_add_dims(space, isl_dim_in, depth);
930 space = isl_space_wrap(space);
931 space = isl_space_set_tuple_name(space, isl_dim_set, "isolate");
933 isolate = isl_union_set_extract_set(band->ast_build_options, space);
935 return isolate;
938 /* Replace the option "drop" in the AST build options by "add".
939 * That is, remove "drop" and add "add".
941 __isl_give isl_schedule_band *isl_schedule_band_replace_ast_build_option(
942 __isl_take isl_schedule_band *band, __isl_take isl_set *drop,
943 __isl_take isl_set *add)
945 isl_union_set *options;
947 band = isl_schedule_band_cow(band);
948 if (!band)
949 goto error;
951 options = band->ast_build_options;
952 options = isl_union_set_subtract(options, isl_union_set_from_set(drop));
953 options = isl_union_set_union(options, isl_union_set_from_set(add));
954 band->ast_build_options = options;
956 if (!band->ast_build_options)
957 return isl_schedule_band_free(band);
959 return band;
960 error:
961 isl_schedule_band_free(band);
962 isl_set_free(drop);
963 isl_set_free(add);
964 return NULL;
967 /* Multiply the partial schedule of "band" with the factors in "mv".
968 * Replace the result by its greatest integer part to ensure
969 * that the schedule is always integral.
971 __isl_give isl_schedule_band *isl_schedule_band_scale(
972 __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv)
974 band = isl_schedule_band_cow(band);
975 if (!band || !mv)
976 goto error;
977 band->mupa = isl_multi_union_pw_aff_scale_multi_val(band->mupa, mv);
978 band->mupa = isl_multi_union_pw_aff_floor(band->mupa);
979 if (!band->mupa)
980 return isl_schedule_band_free(band);
981 return band;
982 error:
983 isl_schedule_band_free(band);
984 isl_multi_val_free(mv);
985 return NULL;
988 /* Divide the partial schedule of "band" by the factors in "mv".
989 * Replace the result by its greatest integer part to ensure
990 * that the schedule is always integral.
992 __isl_give isl_schedule_band *isl_schedule_band_scale_down(
993 __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv)
995 band = isl_schedule_band_cow(band);
996 if (!band || !mv)
997 goto error;
998 band->mupa = isl_multi_union_pw_aff_scale_down_multi_val(band->mupa,
999 mv);
1000 band->mupa = isl_multi_union_pw_aff_floor(band->mupa);
1001 if (!band->mupa)
1002 return isl_schedule_band_free(band);
1003 return band;
1004 error:
1005 isl_schedule_band_free(band);
1006 isl_multi_val_free(mv);
1007 return NULL;
1010 /* Reduce the partial schedule of "band" modulo the factors in "mv".
1012 __isl_give isl_schedule_band *isl_schedule_band_mod(
1013 __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv)
1015 band = isl_schedule_band_cow(band);
1016 if (!band || !mv)
1017 goto error;
1018 band->mupa = isl_multi_union_pw_aff_mod_multi_val(band->mupa, mv);
1019 if (!band->mupa)
1020 return isl_schedule_band_free(band);
1021 return band;
1022 error:
1023 isl_schedule_band_free(band);
1024 isl_multi_val_free(mv);
1025 return NULL;
1028 /* Shift the partial schedule of "band" by "shift" after checking
1029 * that the domain of the partial schedule would not be affected
1030 * by this shift.
1032 __isl_give isl_schedule_band *isl_schedule_band_shift(
1033 __isl_take isl_schedule_band *band,
1034 __isl_take isl_multi_union_pw_aff *shift)
1036 isl_union_set *dom1, *dom2;
1037 isl_bool subset;
1039 band = isl_schedule_band_cow(band);
1040 if (!band || !shift)
1041 goto error;
1042 dom1 = isl_multi_union_pw_aff_domain(
1043 isl_multi_union_pw_aff_copy(band->mupa));
1044 dom2 = isl_multi_union_pw_aff_domain(
1045 isl_multi_union_pw_aff_copy(shift));
1046 subset = isl_union_set_is_subset(dom1, dom2);
1047 isl_union_set_free(dom1);
1048 isl_union_set_free(dom2);
1049 if (subset < 0)
1050 goto error;
1051 if (!subset)
1052 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
1053 "domain of shift needs to include domain of "
1054 "partial schedule", goto error);
1055 band->mupa = isl_multi_union_pw_aff_add(band->mupa, shift);
1056 if (!band->mupa)
1057 return isl_schedule_band_free(band);
1058 return band;
1059 error:
1060 isl_schedule_band_free(band);
1061 isl_multi_union_pw_aff_free(shift);
1062 return NULL;
1065 /* Given the schedule of a band, construct the corresponding
1066 * schedule for the tile loops based on the given tile sizes
1067 * and return the result.
1069 * If the scale tile loops options is set, then the tile loops
1070 * are scaled by the tile sizes.
1072 * That is replace each schedule dimension "i" by either
1073 * "floor(i/s)" or "s * floor(i/s)".
1075 static isl_multi_union_pw_aff *isl_multi_union_pw_aff_tile(
1076 __isl_take isl_multi_union_pw_aff *sched,
1077 __isl_take isl_multi_val *sizes)
1079 isl_ctx *ctx;
1080 int i, n;
1081 isl_val *v;
1082 int scale;
1084 ctx = isl_multi_val_get_ctx(sizes);
1085 scale = isl_options_get_tile_scale_tile_loops(ctx);
1087 n = isl_multi_union_pw_aff_dim(sched, isl_dim_set);
1088 for (i = 0; i < n; ++i) {
1089 isl_union_pw_aff *upa;
1091 upa = isl_multi_union_pw_aff_get_union_pw_aff(sched, i);
1092 v = isl_multi_val_get_val(sizes, i);
1094 upa = isl_union_pw_aff_scale_down_val(upa, isl_val_copy(v));
1095 upa = isl_union_pw_aff_floor(upa);
1096 if (scale)
1097 upa = isl_union_pw_aff_scale_val(upa, isl_val_copy(v));
1098 isl_val_free(v);
1100 sched = isl_multi_union_pw_aff_set_union_pw_aff(sched, i, upa);
1103 isl_multi_val_free(sizes);
1104 return sched;
1107 /* Replace "band" by a band corresponding to the tile loops of a tiling
1108 * with the given tile sizes.
1110 __isl_give isl_schedule_band *isl_schedule_band_tile(
1111 __isl_take isl_schedule_band *band, __isl_take isl_multi_val *sizes)
1113 band = isl_schedule_band_cow(band);
1114 if (!band || !sizes)
1115 goto error;
1116 band->mupa = isl_multi_union_pw_aff_tile(band->mupa, sizes);
1117 if (!band->mupa)
1118 return isl_schedule_band_free(band);
1119 return band;
1120 error:
1121 isl_schedule_band_free(band);
1122 isl_multi_val_free(sizes);
1123 return NULL;
1126 /* Replace "band" by a band corresponding to the point loops of a tiling
1127 * with the given tile sizes.
1128 * "tile" is the corresponding tile loop band.
1130 * If the shift point loops option is set, then the point loops
1131 * are shifted to start at zero. That is, each schedule dimension "i"
1132 * is replaced by "i - s * floor(i/s)".
1133 * The expression "floor(i/s)" (or "s * floor(i/s)") is extracted from
1134 * the tile band.
1136 * Otherwise, the band is left untouched.
1138 __isl_give isl_schedule_band *isl_schedule_band_point(
1139 __isl_take isl_schedule_band *band, __isl_keep isl_schedule_band *tile,
1140 __isl_take isl_multi_val *sizes)
1142 isl_ctx *ctx;
1143 isl_multi_union_pw_aff *scaled;
1145 if (!band || !sizes)
1146 goto error;
1148 ctx = isl_schedule_band_get_ctx(band);
1149 if (!isl_options_get_tile_shift_point_loops(ctx)) {
1150 isl_multi_val_free(sizes);
1151 return band;
1153 band = isl_schedule_band_cow(band);
1154 if (!band)
1155 goto error;
1157 scaled = isl_schedule_band_get_partial_schedule(tile);
1158 if (!isl_options_get_tile_scale_tile_loops(ctx))
1159 scaled = isl_multi_union_pw_aff_scale_multi_val(scaled, sizes);
1160 else
1161 isl_multi_val_free(sizes);
1162 band->mupa = isl_multi_union_pw_aff_sub(band->mupa, scaled);
1163 if (!band->mupa)
1164 return isl_schedule_band_free(band);
1165 return band;
1166 error:
1167 isl_schedule_band_free(band);
1168 isl_multi_val_free(sizes);
1169 return NULL;
1172 /* Drop the "n" dimensions starting at "pos" from "band".
1174 * We apply the transformation even if "n" is zero to ensure consistent
1175 * behavior with respect to changes in the schedule space.
1177 * The caller is responsible for updating the isolate option.
1179 __isl_give isl_schedule_band *isl_schedule_band_drop(
1180 __isl_take isl_schedule_band *band, int pos, int n)
1182 int i;
1184 if (pos < 0 || n < 0 || pos + n > band->n)
1185 isl_die(isl_schedule_band_get_ctx(band), isl_error_internal,
1186 "range out of bounds",
1187 return isl_schedule_band_free(band));
1189 band = isl_schedule_band_cow(band);
1190 if (!band)
1191 return NULL;
1193 band->mupa = isl_multi_union_pw_aff_drop_dims(band->mupa,
1194 isl_dim_set, pos, n);
1195 if (!band->mupa)
1196 return isl_schedule_band_free(band);
1198 for (i = pos + n; i < band->n; ++i)
1199 band->coincident[i - n] = band->coincident[i];
1200 if (band->loop_type)
1201 for (i = pos + n; i < band->n; ++i)
1202 band->loop_type[i - n] = band->loop_type[i];
1203 if (band->isolate_loop_type)
1204 for (i = pos + n; i < band->n; ++i)
1205 band->isolate_loop_type[i - n] =
1206 band->isolate_loop_type[i];
1208 band->n -= n;
1210 return band;
1213 /* Reset the user pointer on all identifiers of parameters and tuples
1214 * in "band".
1216 __isl_give isl_schedule_band *isl_schedule_band_reset_user(
1217 __isl_take isl_schedule_band *band)
1219 band = isl_schedule_band_cow(band);
1220 if (!band)
1221 return NULL;
1223 band->mupa = isl_multi_union_pw_aff_reset_user(band->mupa);
1224 band->ast_build_options =
1225 isl_union_set_reset_user(band->ast_build_options);
1226 if (!band->mupa || !band->ast_build_options)
1227 return isl_schedule_band_free(band);
1229 return band;
1232 /* Align the parameters of "band" to those of "space".
1234 __isl_give isl_schedule_band *isl_schedule_band_align_params(
1235 __isl_take isl_schedule_band *band, __isl_take isl_space *space)
1237 band = isl_schedule_band_cow(band);
1238 if (!band || !space)
1239 goto error;
1241 band->mupa = isl_multi_union_pw_aff_align_params(band->mupa,
1242 isl_space_copy(space));
1243 band->ast_build_options =
1244 isl_union_set_align_params(band->ast_build_options, space);
1245 if (!band->mupa || !band->ast_build_options)
1246 return isl_schedule_band_free(band);
1248 return band;
1249 error:
1250 isl_space_free(space);
1251 isl_schedule_band_free(band);
1252 return NULL;
1255 /* Compute the pullback of "band" by the function represented by "upma".
1256 * In other words, plug in "upma" in the iteration domains of "band".
1258 __isl_give isl_schedule_band *isl_schedule_band_pullback_union_pw_multi_aff(
1259 __isl_take isl_schedule_band *band,
1260 __isl_take isl_union_pw_multi_aff *upma)
1262 band = isl_schedule_band_cow(band);
1263 if (!band || !upma)
1264 goto error;
1266 band->mupa =
1267 isl_multi_union_pw_aff_pullback_union_pw_multi_aff(band->mupa,
1268 upma);
1269 if (!band->mupa)
1270 return isl_schedule_band_free(band);
1272 return band;
1273 error:
1274 isl_union_pw_multi_aff_free(upma);
1275 isl_schedule_band_free(band);
1276 return NULL;
1279 /* Compute the gist of "band" with respect to "context".
1280 * In particular, compute the gist of the associated partial schedule.
1282 __isl_give isl_schedule_band *isl_schedule_band_gist(
1283 __isl_take isl_schedule_band *band, __isl_take isl_union_set *context)
1285 if (!band || !context)
1286 goto error;
1287 if (band->n == 0) {
1288 isl_union_set_free(context);
1289 return band;
1291 band = isl_schedule_band_cow(band);
1292 if (!band)
1293 goto error;
1294 band->mupa = isl_multi_union_pw_aff_gist(band->mupa, context);
1295 if (!band->mupa)
1296 return isl_schedule_band_free(band);
1297 return band;
1298 error:
1299 isl_union_set_free(context);
1300 isl_schedule_band_free(band);
1301 return NULL;