Line data Source code
1 : /*
2 : * Copyright 2013-2014 Ecole Normale Superieure
3 : * Copyright 2014 INRIA Rocquencourt
4 : *
5 : * Use of this software is governed by the MIT license
6 : *
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
11 : */
12 :
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>
20 :
21 0 : isl_ctx *isl_schedule_band_get_ctx(__isl_keep isl_schedule_band *band)
22 : {
23 0 : return band ? isl_multi_union_pw_aff_get_ctx(band->mupa) : NULL;
24 : }
25 :
26 : /* Return a new uninitialized isl_schedule_band.
27 : */
28 0 : static __isl_give isl_schedule_band *isl_schedule_band_alloc(isl_ctx *ctx)
29 : {
30 : isl_schedule_band *band;
31 :
32 0 : band = isl_calloc_type(ctx, isl_schedule_band);
33 0 : if (!band)
34 0 : return NULL;
35 :
36 0 : band->ref = 1;
37 :
38 0 : return band;
39 : }
40 :
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.
47 : */
48 0 : __isl_give isl_schedule_band *isl_schedule_band_from_multi_union_pw_aff(
49 : __isl_take isl_multi_union_pw_aff *mupa)
50 : {
51 : isl_ctx *ctx;
52 : isl_schedule_band *band;
53 : isl_space *space;
54 :
55 0 : mupa = isl_multi_union_pw_aff_floor(mupa);
56 0 : if (!mupa)
57 0 : return NULL;
58 0 : ctx = isl_multi_union_pw_aff_get_ctx(mupa);
59 0 : band = isl_schedule_band_alloc(ctx);
60 0 : if (!band)
61 0 : goto error;
62 :
63 0 : band->n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
64 0 : band->coincident = isl_calloc_array(ctx, int, band->n);
65 0 : band->mupa = mupa;
66 0 : space = isl_space_params_alloc(ctx, 0);
67 0 : band->ast_build_options = isl_union_set_empty(space);
68 0 : band->anchored = 0;
69 :
70 0 : if ((band->n && !band->coincident) || !band->ast_build_options)
71 0 : return isl_schedule_band_free(band);
72 :
73 0 : return band;
74 : error:
75 0 : isl_multi_union_pw_aff_free(mupa);
76 0 : return NULL;
77 : }
78 :
79 : /* Create a duplicate of the given isl_schedule_band.
80 : */
81 0 : __isl_give isl_schedule_band *isl_schedule_band_dup(
82 : __isl_keep isl_schedule_band *band)
83 : {
84 : int i;
85 : isl_ctx *ctx;
86 : isl_schedule_band *dup;
87 :
88 0 : if (!band)
89 0 : return NULL;
90 :
91 0 : ctx = isl_schedule_band_get_ctx(band);
92 0 : dup = isl_schedule_band_alloc(ctx);
93 0 : if (!dup)
94 0 : return NULL;
95 :
96 0 : dup->n = band->n;
97 0 : dup->coincident = isl_alloc_array(ctx, int, band->n);
98 0 : if (band->n && !dup->coincident)
99 0 : return isl_schedule_band_free(dup);
100 :
101 0 : for (i = 0; i < band->n; ++i)
102 0 : dup->coincident[i] = band->coincident[i];
103 0 : dup->permutable = band->permutable;
104 :
105 0 : dup->mupa = isl_multi_union_pw_aff_copy(band->mupa);
106 0 : dup->ast_build_options = isl_union_set_copy(band->ast_build_options);
107 0 : if (!dup->mupa || !dup->ast_build_options)
108 0 : return isl_schedule_band_free(dup);
109 :
110 0 : if (band->loop_type) {
111 0 : dup->loop_type = isl_alloc_array(ctx,
112 : enum isl_ast_loop_type, band->n);
113 0 : if (band->n && !dup->loop_type)
114 0 : return isl_schedule_band_free(dup);
115 0 : for (i = 0; i < band->n; ++i)
116 0 : dup->loop_type[i] = band->loop_type[i];
117 : }
118 0 : if (band->isolate_loop_type) {
119 0 : dup->isolate_loop_type = isl_alloc_array(ctx,
120 : enum isl_ast_loop_type, band->n);
121 0 : if (band->n && !dup->isolate_loop_type)
122 0 : return isl_schedule_band_free(dup);
123 0 : for (i = 0; i < band->n; ++i)
124 0 : dup->isolate_loop_type[i] = band->isolate_loop_type[i];
125 : }
126 :
127 0 : return dup;
128 : }
129 :
130 : /* Return an isl_schedule_band that is equal to "band" and that has only
131 : * a single reference.
132 : */
133 0 : __isl_give isl_schedule_band *isl_schedule_band_cow(
134 : __isl_take isl_schedule_band *band)
135 : {
136 0 : if (!band)
137 0 : return NULL;
138 :
139 0 : if (band->ref == 1)
140 0 : return band;
141 0 : band->ref--;
142 0 : return isl_schedule_band_dup(band);
143 : }
144 :
145 : /* Return a new reference to "band".
146 : */
147 0 : __isl_give isl_schedule_band *isl_schedule_band_copy(
148 : __isl_keep isl_schedule_band *band)
149 : {
150 0 : if (!band)
151 0 : return NULL;
152 :
153 0 : band->ref++;
154 0 : return band;
155 : }
156 :
157 : /* Free a reference to "band" and return NULL.
158 : */
159 0 : __isl_null isl_schedule_band *isl_schedule_band_free(
160 : __isl_take isl_schedule_band *band)
161 : {
162 0 : if (!band)
163 0 : return NULL;
164 :
165 0 : if (--band->ref > 0)
166 0 : return NULL;
167 :
168 0 : isl_multi_union_pw_aff_free(band->mupa);
169 0 : isl_union_set_free(band->ast_build_options);
170 0 : free(band->loop_type);
171 0 : free(band->isolate_loop_type);
172 0 : free(band->coincident);
173 0 : free(band);
174 :
175 0 : return NULL;
176 : }
177 :
178 : /* Are "band1" and "band2" obviously equal?
179 : */
180 0 : isl_bool isl_schedule_band_plain_is_equal(__isl_keep isl_schedule_band *band1,
181 : __isl_keep isl_schedule_band *band2)
182 : {
183 : int i;
184 : isl_bool equal;
185 :
186 0 : if (!band1 || !band2)
187 0 : return isl_bool_error;
188 0 : if (band1 == band2)
189 0 : return isl_bool_true;
190 :
191 0 : if (band1->n != band2->n)
192 0 : return isl_bool_false;
193 0 : for (i = 0; i < band1->n; ++i)
194 0 : if (band1->coincident[i] != band2->coincident[i])
195 0 : return isl_bool_false;
196 0 : if (band1->permutable != band2->permutable)
197 0 : return isl_bool_false;
198 :
199 0 : equal = isl_multi_union_pw_aff_plain_is_equal(band1->mupa, band2->mupa);
200 0 : if (equal < 0 || !equal)
201 0 : return equal;
202 :
203 0 : if (!band1->loop_type != !band2->loop_type)
204 0 : return isl_bool_false;
205 0 : if (band1->loop_type)
206 0 : for (i = 0; i < band1->n; ++i)
207 0 : if (band1->loop_type[i] != band2->loop_type[i])
208 0 : return isl_bool_false;
209 :
210 0 : if (!band1->isolate_loop_type != !band2->isolate_loop_type)
211 0 : return isl_bool_false;
212 0 : if (band1->isolate_loop_type)
213 0 : for (i = 0; i < band1->n; ++i)
214 0 : if (band1->isolate_loop_type[i] !=
215 0 : band2->isolate_loop_type[i])
216 0 : return isl_bool_false;
217 :
218 0 : return isl_union_set_is_equal(band1->ast_build_options,
219 : band2->ast_build_options);
220 : }
221 :
222 : /* Return the number of scheduling dimensions in the band.
223 : */
224 0 : int isl_schedule_band_n_member(__isl_keep isl_schedule_band *band)
225 : {
226 0 : return band ? band->n : 0;
227 : }
228 :
229 : /* Is the given scheduling dimension coincident within the band and
230 : * with respect to the coincidence constraints?
231 : */
232 0 : isl_bool isl_schedule_band_member_get_coincident(
233 : __isl_keep isl_schedule_band *band, int pos)
234 : {
235 0 : if (!band)
236 0 : return isl_bool_error;
237 :
238 0 : if (pos < 0 || pos >= band->n)
239 0 : isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
240 : "invalid member position", return isl_bool_error);
241 :
242 0 : return band->coincident[pos];
243 : }
244 :
245 : /* Mark the given scheduling dimension as being coincident or not
246 : * according to "coincident".
247 : */
248 0 : __isl_give isl_schedule_band *isl_schedule_band_member_set_coincident(
249 : __isl_take isl_schedule_band *band, int pos, int coincident)
250 : {
251 0 : if (!band)
252 0 : return NULL;
253 0 : if (isl_schedule_band_member_get_coincident(band, pos) == coincident)
254 0 : return band;
255 0 : band = isl_schedule_band_cow(band);
256 0 : if (!band)
257 0 : return NULL;
258 :
259 0 : if (pos < 0 || pos >= band->n)
260 0 : isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
261 : "invalid member position",
262 : return isl_schedule_band_free(band));
263 :
264 0 : band->coincident[pos] = coincident;
265 :
266 0 : return band;
267 : }
268 :
269 : /* Is the schedule band mark permutable?
270 : */
271 0 : isl_bool isl_schedule_band_get_permutable(__isl_keep isl_schedule_band *band)
272 : {
273 0 : if (!band)
274 0 : return isl_bool_error;
275 0 : return band->permutable;
276 : }
277 :
278 : /* Mark the schedule band permutable or not according to "permutable"?
279 : */
280 0 : __isl_give isl_schedule_band *isl_schedule_band_set_permutable(
281 : __isl_take isl_schedule_band *band, int permutable)
282 : {
283 0 : if (!band)
284 0 : return NULL;
285 0 : if (band->permutable == permutable)
286 0 : return band;
287 0 : band = isl_schedule_band_cow(band);
288 0 : if (!band)
289 0 : return NULL;
290 :
291 0 : band->permutable = permutable;
292 :
293 0 : return band;
294 : }
295 :
296 : /* Is the band node "node" anchored? That is, does it reference
297 : * the outer band nodes?
298 : */
299 0 : int isl_schedule_band_is_anchored(__isl_keep isl_schedule_band *band)
300 : {
301 0 : return band ? band->anchored : -1;
302 : }
303 :
304 : /* Return the schedule space of the band.
305 : */
306 0 : __isl_give isl_space *isl_schedule_band_get_space(
307 : __isl_keep isl_schedule_band *band)
308 : {
309 0 : if (!band)
310 0 : return NULL;
311 0 : return isl_multi_union_pw_aff_get_space(band->mupa);
312 : }
313 :
314 : /* Intersect the domain of the band schedule of "band" with "domain".
315 : */
316 0 : __isl_give isl_schedule_band *isl_schedule_band_intersect_domain(
317 : __isl_take isl_schedule_band *band, __isl_take isl_union_set *domain)
318 : {
319 0 : band = isl_schedule_band_cow(band);
320 0 : if (!band || !domain)
321 : goto error;
322 :
323 0 : band->mupa = isl_multi_union_pw_aff_intersect_domain(band->mupa,
324 : domain);
325 0 : if (!band->mupa)
326 0 : return isl_schedule_band_free(band);
327 :
328 0 : return band;
329 : error:
330 0 : isl_schedule_band_free(band);
331 0 : isl_union_set_free(domain);
332 0 : return NULL;
333 : }
334 :
335 : /* Return the schedule of the band in isolation.
336 : */
337 0 : __isl_give isl_multi_union_pw_aff *isl_schedule_band_get_partial_schedule(
338 : __isl_keep isl_schedule_band *band)
339 : {
340 0 : return band ? isl_multi_union_pw_aff_copy(band->mupa) : NULL;
341 : }
342 :
343 : /* Replace the schedule of "band" by "schedule".
344 : */
345 0 : __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)
348 : {
349 0 : band = isl_schedule_band_cow(band);
350 0 : if (!band || !schedule)
351 : goto error;
352 :
353 0 : isl_multi_union_pw_aff_free(band->mupa);
354 0 : band->mupa = schedule;
355 :
356 0 : return band;
357 : error:
358 0 : isl_schedule_band_free(band);
359 0 : isl_multi_union_pw_aff_free(schedule);
360 0 : return NULL;
361 : }
362 :
363 : /* Return the loop AST generation type for the band member of "band"
364 : * at position "pos".
365 : */
366 0 : enum isl_ast_loop_type isl_schedule_band_member_get_ast_loop_type(
367 : __isl_keep isl_schedule_band *band, int pos)
368 : {
369 0 : if (!band)
370 0 : return isl_ast_loop_error;
371 :
372 0 : if (pos < 0 || pos >= band->n)
373 0 : isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
374 : "invalid member position", return isl_ast_loop_error);
375 :
376 0 : if (!band->loop_type)
377 0 : return isl_ast_loop_default;
378 :
379 0 : return band->loop_type[pos];
380 : }
381 :
382 : /* Set the loop AST generation type for the band member of "band"
383 : * at position "pos" to "type".
384 : */
385 0 : __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)
388 : {
389 0 : if (!band)
390 0 : return NULL;
391 0 : if (isl_schedule_band_member_get_ast_loop_type(band, pos) == type)
392 0 : return band;
393 :
394 0 : if (pos < 0 || pos >= band->n)
395 0 : isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
396 : "invalid member position",
397 : return isl_schedule_band_free(band));
398 :
399 0 : band = isl_schedule_band_cow(band);
400 0 : if (!band)
401 0 : return isl_schedule_band_free(band);
402 :
403 0 : if (!band->loop_type) {
404 : isl_ctx *ctx;
405 :
406 0 : ctx = isl_schedule_band_get_ctx(band);
407 0 : band->loop_type = isl_calloc_array(ctx,
408 : enum isl_ast_loop_type, band->n);
409 0 : if (band->n && !band->loop_type)
410 0 : return isl_schedule_band_free(band);
411 : }
412 :
413 0 : band->loop_type[pos] = type;
414 :
415 0 : return band;
416 : }
417 :
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.
420 : */
421 0 : enum isl_ast_loop_type isl_schedule_band_member_get_isolate_ast_loop_type(
422 : __isl_keep isl_schedule_band *band, int pos)
423 : {
424 0 : if (!band)
425 0 : return isl_ast_loop_error;
426 :
427 0 : if (pos < 0 || pos >= band->n)
428 0 : isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
429 : "invalid member position", return isl_ast_loop_error);
430 :
431 0 : if (!band->isolate_loop_type)
432 0 : return isl_ast_loop_default;
433 :
434 0 : return band->isolate_loop_type[pos];
435 : }
436 :
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.
440 : */
441 : __isl_give isl_schedule_band *
442 0 : 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)
445 : {
446 0 : if (!band)
447 0 : return NULL;
448 0 : if (isl_schedule_band_member_get_isolate_ast_loop_type(band, pos) ==
449 : type)
450 0 : return band;
451 :
452 0 : if (pos < 0 || pos >= band->n)
453 0 : isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
454 : "invalid member position",
455 : return isl_schedule_band_free(band));
456 :
457 0 : band = isl_schedule_band_cow(band);
458 0 : if (!band)
459 0 : return isl_schedule_band_free(band);
460 :
461 0 : if (!band->isolate_loop_type) {
462 : isl_ctx *ctx;
463 :
464 0 : ctx = isl_schedule_band_get_ctx(band);
465 0 : band->isolate_loop_type = isl_calloc_array(ctx,
466 : enum isl_ast_loop_type, band->n);
467 0 : if (band->n && !band->isolate_loop_type)
468 0 : return isl_schedule_band_free(band);
469 : }
470 :
471 0 : band->isolate_loop_type[pos] = type;
472 :
473 0 : return band;
474 : }
475 :
476 : static const char *option_str[] = {
477 : [isl_ast_loop_atomic] = "atomic",
478 : [isl_ast_loop_unroll] = "unroll",
479 : [isl_ast_loop_separate] = "separate"
480 : };
481 :
482 : /* Given a parameter space "space", extend it to a set space
483 : *
484 : * { type[x] }
485 : *
486 : * or
487 : *
488 : * { [isolate[] -> type[x]] }
489 : *
490 : * depending on whether "isolate" is set.
491 : * These can be used to encode loop AST generation options of the given type.
492 : */
493 0 : static __isl_give isl_space *loop_type_space(__isl_take isl_space *space,
494 : enum isl_ast_loop_type type, int isolate)
495 : {
496 : const char *name;
497 :
498 0 : name = option_str[type];
499 0 : space = isl_space_set_from_params(space);
500 0 : space = isl_space_add_dims(space, isl_dim_set, 1);
501 0 : space = isl_space_set_tuple_name(space, isl_dim_set, name);
502 0 : if (!isolate)
503 0 : return space;
504 0 : space = isl_space_from_range(space);
505 0 : space = isl_space_set_tuple_name(space, isl_dim_in, "isolate");
506 0 : space = isl_space_wrap(space);
507 :
508 0 : return space;
509 : }
510 :
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.
513 : *
514 : * In particular, for each sequence of consecutive identical types "t",
515 : * different from the default, add an option
516 : *
517 : * { t[x] : first <= x <= last }
518 : *
519 : * or
520 : *
521 : * { [isolate[] -> t[x]] : first <= x <= last }
522 : */
523 0 : 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)
526 : {
527 : int i;
528 :
529 0 : if (!type)
530 0 : return options;
531 0 : if (!options)
532 0 : return NULL;
533 :
534 0 : for (i = 0; i < n; ++i) {
535 : int first;
536 : isl_space *space;
537 : isl_set *option;
538 :
539 0 : if (type[i] == isl_ast_loop_default)
540 0 : continue;
541 :
542 0 : first = i;
543 0 : while (i + 1 < n && type[i + 1] == type[i])
544 0 : ++i;
545 :
546 0 : space = isl_union_set_get_space(options);
547 0 : space = loop_type_space(space, type[i], isolate);
548 0 : option = isl_set_universe(space);
549 0 : option = isl_set_lower_bound_si(option, isl_dim_set, 0, first);
550 0 : option = isl_set_upper_bound_si(option, isl_dim_set, 0, i);
551 0 : options = isl_union_set_add_set(options, option);
552 : }
553 :
554 0 : return options;
555 : }
556 :
557 : /* Return the AST build options associated to "band".
558 : */
559 0 : __isl_give isl_union_set *isl_schedule_band_get_ast_build_options(
560 : __isl_keep isl_schedule_band *band)
561 : {
562 : isl_union_set *options;
563 :
564 0 : if (!band)
565 0 : return NULL;
566 :
567 0 : options = isl_union_set_copy(band->ast_build_options);
568 0 : options = add_loop_types(options, band->n, band->loop_type, 0);
569 0 : options = add_loop_types(options, band->n, band->isolate_loop_type, 1);
570 :
571 0 : return options;
572 : }
573 :
574 : /* Does "uset" contain any set that satisfies "is"?
575 : * "is" is assumed to set its integer argument to 1 if it is satisfied.
576 : */
577 0 : static int has_any(__isl_keep isl_union_set *uset,
578 : isl_stat (*is)(__isl_take isl_set *set, void *user))
579 : {
580 0 : int found = 0;
581 :
582 0 : if (isl_union_set_foreach_set(uset, is, &found) < 0 && !found)
583 0 : return -1;
584 :
585 0 : return found;
586 : }
587 :
588 : /* Does "set" live in a space of the form
589 : *
590 : * isolate[[...] -> [...]]
591 : *
592 : * ?
593 : *
594 : * If so, set *found and abort the search.
595 : */
596 0 : static isl_stat is_isolate(__isl_take isl_set *set, void *user)
597 : {
598 0 : int *found = user;
599 :
600 0 : if (isl_set_has_tuple_name(set)) {
601 : const char *name;
602 0 : name = isl_set_get_tuple_name(set);
603 0 : if (isl_set_is_wrapping(set) && !strcmp(name, "isolate"))
604 0 : *found = 1;
605 : }
606 0 : isl_set_free(set);
607 :
608 0 : return *found ? isl_stat_error : isl_stat_ok;
609 : }
610 :
611 : /* Does "options" include an option of the ofrm
612 : *
613 : * isolate[[...] -> [...]]
614 : *
615 : * ?
616 : */
617 0 : static int has_isolate_option(__isl_keep isl_union_set *options)
618 : {
619 0 : return has_any(options, &is_isolate);
620 : }
621 :
622 : /* Does "set" encode a loop AST generation option?
623 : */
624 0 : static isl_stat is_loop_type_option(__isl_take isl_set *set, void *user)
625 : {
626 0 : int *found = user;
627 :
628 0 : if (isl_set_dim(set, isl_dim_set) == 1 &&
629 0 : isl_set_has_tuple_name(set)) {
630 : const char *name;
631 : enum isl_ast_loop_type type;
632 0 : name = isl_set_get_tuple_name(set);
633 0 : for (type = isl_ast_loop_atomic;
634 0 : type <= isl_ast_loop_separate; ++type) {
635 0 : if (strcmp(name, option_str[type]))
636 0 : continue;
637 0 : *found = 1;
638 0 : break;
639 : }
640 : }
641 0 : isl_set_free(set);
642 :
643 0 : return *found ? isl_stat_error : isl_stat_ok;
644 : }
645 :
646 : /* Does "set" encode a loop AST generation option for the isolated part?
647 : * That is, is of the form
648 : *
649 : * { [isolate[] -> t[x]] }
650 : *
651 : * with t equal to "atomic", "unroll" or "separate"?
652 : */
653 0 : static isl_stat is_isolate_loop_type_option(__isl_take isl_set *set, void *user)
654 : {
655 0 : int *found = user;
656 : const char *name;
657 : enum isl_ast_loop_type type;
658 : isl_map *map;
659 :
660 0 : if (!isl_set_is_wrapping(set)) {
661 0 : isl_set_free(set);
662 0 : return isl_stat_ok;
663 : }
664 0 : map = isl_set_unwrap(set);
665 0 : if (!isl_map_has_tuple_name(map, isl_dim_in) ||
666 0 : !isl_map_has_tuple_name(map, isl_dim_out)) {
667 0 : isl_map_free(map);
668 0 : return isl_stat_ok;
669 : }
670 0 : name = isl_map_get_tuple_name(map, isl_dim_in);
671 0 : if (!strcmp(name, "isolate")) {
672 0 : name = isl_map_get_tuple_name(map, isl_dim_out);
673 0 : for (type = isl_ast_loop_atomic;
674 0 : type <= isl_ast_loop_separate; ++type) {
675 0 : if (strcmp(name, option_str[type]))
676 0 : continue;
677 0 : *found = 1;
678 0 : break;
679 : }
680 : }
681 0 : isl_map_free(map);
682 :
683 0 : return *found ? isl_stat_error : isl_stat_ok;
684 : }
685 :
686 : /* Does "options" encode any loop AST generation options
687 : * for the isolated part?
688 : */
689 0 : static int has_isolate_loop_type_options(__isl_keep isl_union_set *options)
690 : {
691 0 : return has_any(options, &is_isolate_loop_type_option);
692 : }
693 :
694 : /* Does "options" encode any loop AST generation options?
695 : */
696 0 : static int has_loop_type_options(__isl_keep isl_union_set *options)
697 : {
698 0 : return has_any(options, &is_loop_type_option);
699 : }
700 :
701 : /* Extract the loop AST generation type for the band member
702 : * at position "pos" from "options".
703 : * If "isolate" is set, then extract the loop types for the isolated part.
704 : */
705 0 : static enum isl_ast_loop_type extract_loop_type(
706 : __isl_keep isl_union_set *options, int pos, int isolate)
707 : {
708 : isl_ctx *ctx;
709 0 : enum isl_ast_loop_type type, res = isl_ast_loop_default;
710 :
711 0 : ctx = isl_union_set_get_ctx(options);
712 0 : for (type = isl_ast_loop_atomic;
713 0 : type <= isl_ast_loop_separate; ++type) {
714 : isl_space *space;
715 : isl_set *option;
716 : int empty;
717 :
718 0 : space = isl_union_set_get_space(options);
719 0 : space = loop_type_space(space, type, isolate);
720 0 : option = isl_union_set_extract_set(options, space);
721 0 : option = isl_set_fix_si(option, isl_dim_set, 0, pos);
722 0 : empty = isl_set_is_empty(option);
723 0 : isl_set_free(option);
724 :
725 0 : if (empty < 0)
726 0 : return isl_ast_loop_error;
727 0 : if (empty)
728 0 : continue;
729 0 : if (res != isl_ast_loop_default)
730 0 : isl_die(ctx, isl_error_invalid,
731 : "conflicting loop type options",
732 : return isl_ast_loop_error);
733 0 : res = type;
734 : }
735 :
736 0 : return res;
737 : }
738 :
739 : /* Extract the loop AST generation types for the members of "band"
740 : * from "options" and store them in band->loop_type.
741 : * Return -1 on error.
742 : */
743 0 : static int extract_loop_types(__isl_keep isl_schedule_band *band,
744 : __isl_keep isl_union_set *options)
745 : {
746 : int i;
747 :
748 0 : if (!band->loop_type) {
749 0 : isl_ctx *ctx = isl_schedule_band_get_ctx(band);
750 0 : band->loop_type = isl_alloc_array(ctx,
751 : enum isl_ast_loop_type, band->n);
752 0 : if (band->n && !band->loop_type)
753 0 : return -1;
754 : }
755 0 : for (i = 0; i < band->n; ++i) {
756 0 : band->loop_type[i] = extract_loop_type(options, i, 0);
757 0 : if (band->loop_type[i] == isl_ast_loop_error)
758 0 : return -1;
759 : }
760 :
761 0 : return 0;
762 : }
763 :
764 : /* Extract the loop AST generation types for the members of "band"
765 : * from "options" for the isolated part and
766 : * store them in band->isolate_loop_type.
767 : * Return -1 on error.
768 : */
769 0 : static int extract_isolate_loop_types(__isl_keep isl_schedule_band *band,
770 : __isl_keep isl_union_set *options)
771 : {
772 : int i;
773 :
774 0 : if (!band->isolate_loop_type) {
775 0 : isl_ctx *ctx = isl_schedule_band_get_ctx(band);
776 0 : band->isolate_loop_type = isl_alloc_array(ctx,
777 : enum isl_ast_loop_type, band->n);
778 0 : if (band->n && !band->isolate_loop_type)
779 0 : return -1;
780 : }
781 0 : for (i = 0; i < band->n; ++i) {
782 0 : band->isolate_loop_type[i] = extract_loop_type(options, i, 1);
783 0 : if (band->isolate_loop_type[i] == isl_ast_loop_error)
784 0 : return -1;
785 : }
786 :
787 0 : return 0;
788 : }
789 :
790 : /* Construct universe sets of the spaces that encode loop AST generation
791 : * types (for the isolated part if "isolate" is set). That is, construct
792 : *
793 : * { atomic[x]; separate[x]; unroll[x] }
794 : *
795 : * or
796 : *
797 : * { [isolate[] -> atomic[x]]; [isolate[] -> separate[x]];
798 : * [isolate[] -> unroll[x]] }
799 : */
800 0 : static __isl_give isl_union_set *loop_types(__isl_take isl_space *space,
801 : int isolate)
802 : {
803 : enum isl_ast_loop_type type;
804 : isl_union_set *types;
805 :
806 0 : types = isl_union_set_empty(space);
807 0 : for (type = isl_ast_loop_atomic;
808 0 : type <= isl_ast_loop_separate; ++type) {
809 : isl_set *set;
810 :
811 0 : space = isl_union_set_get_space(types);
812 0 : space = loop_type_space(space, type, isolate);
813 0 : set = isl_set_universe(space);
814 0 : types = isl_union_set_add_set(types, set);
815 : }
816 :
817 0 : return types;
818 : }
819 :
820 : /* Remove all elements from spaces that encode loop AST generation types
821 : * from "options".
822 : */
823 0 : static __isl_give isl_union_set *clear_loop_types(
824 : __isl_take isl_union_set *options)
825 : {
826 : isl_union_set *types;
827 :
828 0 : types = loop_types(isl_union_set_get_space(options), 0);
829 0 : options = isl_union_set_subtract(options, types);
830 :
831 0 : return options;
832 : }
833 :
834 : /* Remove all elements from spaces that encode loop AST generation types
835 : * for the isolated part from "options".
836 : */
837 0 : static __isl_give isl_union_set *clear_isolate_loop_types(
838 : __isl_take isl_union_set *options)
839 : {
840 : isl_union_set *types;
841 :
842 0 : types = loop_types(isl_union_set_get_space(options), 1);
843 0 : options = isl_union_set_subtract(options, types);
844 :
845 0 : return options;
846 : }
847 :
848 : /* Replace the AST build options associated to "band" by "options".
849 : * If there are any loop AST generation type options, then they
850 : * are extracted and stored in band->loop_type. Otherwise,
851 : * band->loop_type is removed to indicate that the default applies
852 : * to all members. Similarly for the loop AST generation type options
853 : * for the isolated part, which are stored in band->isolate_loop_type.
854 : * The remaining options are stored in band->ast_build_options.
855 : *
856 : * Set anchored if the options include an isolate option since the
857 : * domain of the wrapped map references the outer band node schedules.
858 : */
859 0 : __isl_give isl_schedule_band *isl_schedule_band_set_ast_build_options(
860 : __isl_take isl_schedule_band *band, __isl_take isl_union_set *options)
861 : {
862 : int has_isolate, has_loop_type, has_isolate_loop_type;
863 :
864 0 : band = isl_schedule_band_cow(band);
865 0 : if (!band || !options)
866 : goto error;
867 0 : has_isolate = has_isolate_option(options);
868 0 : if (has_isolate < 0)
869 0 : goto error;
870 0 : has_loop_type = has_loop_type_options(options);
871 0 : if (has_loop_type < 0)
872 0 : goto error;
873 0 : has_isolate_loop_type = has_isolate_loop_type_options(options);
874 0 : if (has_isolate_loop_type < 0)
875 0 : goto error;
876 :
877 0 : if (!has_loop_type) {
878 0 : free(band->loop_type);
879 0 : band->loop_type = NULL;
880 : } else {
881 0 : if (extract_loop_types(band, options) < 0)
882 0 : goto error;
883 0 : options = clear_loop_types(options);
884 0 : if (!options)
885 0 : goto error;
886 : }
887 :
888 0 : if (!has_isolate_loop_type) {
889 0 : free(band->isolate_loop_type);
890 0 : band->isolate_loop_type = NULL;
891 : } else {
892 0 : if (extract_isolate_loop_types(band, options) < 0)
893 0 : goto error;
894 0 : options = clear_isolate_loop_types(options);
895 0 : if (!options)
896 0 : goto error;
897 : }
898 :
899 0 : isl_union_set_free(band->ast_build_options);
900 0 : band->ast_build_options = options;
901 0 : band->anchored = has_isolate;
902 :
903 0 : return band;
904 : error:
905 0 : isl_schedule_band_free(band);
906 0 : isl_union_set_free(options);
907 0 : return NULL;
908 : }
909 :
910 : /* Return the "isolate" option associated to "band", assuming
911 : * it at appears at schedule depth "depth".
912 : *
913 : * The isolate option is of the form
914 : *
915 : * isolate[[flattened outer bands] -> band]
916 : */
917 0 : __isl_give isl_set *isl_schedule_band_get_ast_isolate_option(
918 : __isl_keep isl_schedule_band *band, int depth)
919 : {
920 : isl_space *space;
921 : isl_set *isolate;
922 :
923 0 : if (!band)
924 0 : return NULL;
925 :
926 0 : space = isl_schedule_band_get_space(band);
927 0 : space = isl_space_from_range(space);
928 0 : space = isl_space_add_dims(space, isl_dim_in, depth);
929 0 : space = isl_space_wrap(space);
930 0 : space = isl_space_set_tuple_name(space, isl_dim_set, "isolate");
931 :
932 0 : isolate = isl_union_set_extract_set(band->ast_build_options, space);
933 :
934 0 : return isolate;
935 : }
936 :
937 : /* Replace the option "drop" in the AST build options by "add".
938 : * That is, remove "drop" and add "add".
939 : */
940 0 : __isl_give isl_schedule_band *isl_schedule_band_replace_ast_build_option(
941 : __isl_take isl_schedule_band *band, __isl_take isl_set *drop,
942 : __isl_take isl_set *add)
943 : {
944 : isl_union_set *options;
945 :
946 0 : band = isl_schedule_band_cow(band);
947 0 : if (!band)
948 0 : goto error;
949 :
950 0 : options = band->ast_build_options;
951 0 : options = isl_union_set_subtract(options, isl_union_set_from_set(drop));
952 0 : options = isl_union_set_union(options, isl_union_set_from_set(add));
953 0 : band->ast_build_options = options;
954 :
955 0 : if (!band->ast_build_options)
956 0 : return isl_schedule_band_free(band);
957 :
958 0 : return band;
959 : error:
960 0 : isl_schedule_band_free(band);
961 0 : isl_set_free(drop);
962 0 : isl_set_free(add);
963 0 : return NULL;
964 : }
965 :
966 : /* Multiply the partial schedule of "band" with the factors in "mv".
967 : * Replace the result by its greatest integer part to ensure
968 : * that the schedule is always integral.
969 : */
970 0 : __isl_give isl_schedule_band *isl_schedule_band_scale(
971 : __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv)
972 : {
973 0 : band = isl_schedule_band_cow(band);
974 0 : if (!band || !mv)
975 : goto error;
976 0 : band->mupa = isl_multi_union_pw_aff_scale_multi_val(band->mupa, mv);
977 0 : band->mupa = isl_multi_union_pw_aff_floor(band->mupa);
978 0 : if (!band->mupa)
979 0 : return isl_schedule_band_free(band);
980 0 : return band;
981 : error:
982 0 : isl_schedule_band_free(band);
983 0 : isl_multi_val_free(mv);
984 0 : return NULL;
985 : }
986 :
987 : /* Divide the partial schedule of "band" by the factors in "mv".
988 : * Replace the result by its greatest integer part to ensure
989 : * that the schedule is always integral.
990 : */
991 0 : __isl_give isl_schedule_band *isl_schedule_band_scale_down(
992 : __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv)
993 : {
994 0 : band = isl_schedule_band_cow(band);
995 0 : if (!band || !mv)
996 : goto error;
997 0 : band->mupa = isl_multi_union_pw_aff_scale_down_multi_val(band->mupa,
998 : mv);
999 0 : band->mupa = isl_multi_union_pw_aff_floor(band->mupa);
1000 0 : if (!band->mupa)
1001 0 : return isl_schedule_band_free(band);
1002 0 : return band;
1003 : error:
1004 0 : isl_schedule_band_free(band);
1005 0 : isl_multi_val_free(mv);
1006 0 : return NULL;
1007 : }
1008 :
1009 : /* Reduce the partial schedule of "band" modulo the factors in "mv".
1010 : */
1011 0 : __isl_give isl_schedule_band *isl_schedule_band_mod(
1012 : __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv)
1013 : {
1014 0 : band = isl_schedule_band_cow(band);
1015 0 : if (!band || !mv)
1016 : goto error;
1017 0 : band->mupa = isl_multi_union_pw_aff_mod_multi_val(band->mupa, mv);
1018 0 : if (!band->mupa)
1019 0 : return isl_schedule_band_free(band);
1020 0 : return band;
1021 : error:
1022 0 : isl_schedule_band_free(band);
1023 0 : isl_multi_val_free(mv);
1024 0 : return NULL;
1025 : }
1026 :
1027 : /* Shift the partial schedule of "band" by "shift" after checking
1028 : * that the domain of the partial schedule would not be affected
1029 : * by this shift.
1030 : */
1031 0 : __isl_give isl_schedule_band *isl_schedule_band_shift(
1032 : __isl_take isl_schedule_band *band,
1033 : __isl_take isl_multi_union_pw_aff *shift)
1034 : {
1035 : isl_union_set *dom1, *dom2;
1036 : isl_bool subset;
1037 :
1038 0 : band = isl_schedule_band_cow(band);
1039 0 : if (!band || !shift)
1040 : goto error;
1041 0 : dom1 = isl_multi_union_pw_aff_domain(
1042 : isl_multi_union_pw_aff_copy(band->mupa));
1043 0 : dom2 = isl_multi_union_pw_aff_domain(
1044 : isl_multi_union_pw_aff_copy(shift));
1045 0 : subset = isl_union_set_is_subset(dom1, dom2);
1046 0 : isl_union_set_free(dom1);
1047 0 : isl_union_set_free(dom2);
1048 0 : if (subset < 0)
1049 0 : goto error;
1050 0 : if (!subset)
1051 0 : isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
1052 : "domain of shift needs to include domain of "
1053 : "partial schedule", goto error);
1054 0 : band->mupa = isl_multi_union_pw_aff_add(band->mupa, shift);
1055 0 : if (!band->mupa)
1056 0 : return isl_schedule_band_free(band);
1057 0 : return band;
1058 : error:
1059 0 : isl_schedule_band_free(band);
1060 0 : isl_multi_union_pw_aff_free(shift);
1061 0 : return NULL;
1062 : }
1063 :
1064 : /* Given the schedule of a band, construct the corresponding
1065 : * schedule for the tile loops based on the given tile sizes
1066 : * and return the result.
1067 : *
1068 : * If the scale tile loops options is set, then the tile loops
1069 : * are scaled by the tile sizes.
1070 : *
1071 : * That is replace each schedule dimension "i" by either
1072 : * "floor(i/s)" or "s * floor(i/s)".
1073 : */
1074 0 : static isl_multi_union_pw_aff *isl_multi_union_pw_aff_tile(
1075 : __isl_take isl_multi_union_pw_aff *sched,
1076 : __isl_take isl_multi_val *sizes)
1077 : {
1078 : isl_ctx *ctx;
1079 : int i, n;
1080 : isl_val *v;
1081 : int scale;
1082 :
1083 0 : ctx = isl_multi_val_get_ctx(sizes);
1084 0 : scale = isl_options_get_tile_scale_tile_loops(ctx);
1085 :
1086 0 : n = isl_multi_union_pw_aff_dim(sched, isl_dim_set);
1087 0 : for (i = 0; i < n; ++i) {
1088 : isl_union_pw_aff *upa;
1089 :
1090 0 : upa = isl_multi_union_pw_aff_get_union_pw_aff(sched, i);
1091 0 : v = isl_multi_val_get_val(sizes, i);
1092 :
1093 0 : upa = isl_union_pw_aff_scale_down_val(upa, isl_val_copy(v));
1094 0 : upa = isl_union_pw_aff_floor(upa);
1095 0 : if (scale)
1096 0 : upa = isl_union_pw_aff_scale_val(upa, isl_val_copy(v));
1097 0 : isl_val_free(v);
1098 :
1099 0 : sched = isl_multi_union_pw_aff_set_union_pw_aff(sched, i, upa);
1100 : }
1101 :
1102 0 : isl_multi_val_free(sizes);
1103 0 : return sched;
1104 : }
1105 :
1106 : /* Replace "band" by a band corresponding to the tile loops of a tiling
1107 : * with the given tile sizes.
1108 : */
1109 0 : __isl_give isl_schedule_band *isl_schedule_band_tile(
1110 : __isl_take isl_schedule_band *band, __isl_take isl_multi_val *sizes)
1111 : {
1112 0 : band = isl_schedule_band_cow(band);
1113 0 : if (!band || !sizes)
1114 : goto error;
1115 0 : band->mupa = isl_multi_union_pw_aff_tile(band->mupa, sizes);
1116 0 : if (!band->mupa)
1117 0 : return isl_schedule_band_free(band);
1118 0 : return band;
1119 : error:
1120 0 : isl_schedule_band_free(band);
1121 0 : isl_multi_val_free(sizes);
1122 0 : return NULL;
1123 : }
1124 :
1125 : /* Replace "band" by a band corresponding to the point loops of a tiling
1126 : * with the given tile sizes.
1127 : * "tile" is the corresponding tile loop band.
1128 : *
1129 : * If the shift point loops option is set, then the point loops
1130 : * are shifted to start at zero. That is, each schedule dimension "i"
1131 : * is replaced by "i - s * floor(i/s)".
1132 : * The expression "floor(i/s)" (or "s * floor(i/s)") is extracted from
1133 : * the tile band.
1134 : *
1135 : * Otherwise, the band is left untouched.
1136 : */
1137 0 : __isl_give isl_schedule_band *isl_schedule_band_point(
1138 : __isl_take isl_schedule_band *band, __isl_keep isl_schedule_band *tile,
1139 : __isl_take isl_multi_val *sizes)
1140 : {
1141 : isl_ctx *ctx;
1142 : isl_multi_union_pw_aff *scaled;
1143 :
1144 0 : if (!band || !sizes)
1145 : goto error;
1146 :
1147 0 : ctx = isl_schedule_band_get_ctx(band);
1148 0 : if (!isl_options_get_tile_shift_point_loops(ctx)) {
1149 0 : isl_multi_val_free(sizes);
1150 0 : return band;
1151 : }
1152 0 : band = isl_schedule_band_cow(band);
1153 0 : if (!band)
1154 0 : goto error;
1155 :
1156 0 : scaled = isl_schedule_band_get_partial_schedule(tile);
1157 0 : if (!isl_options_get_tile_scale_tile_loops(ctx))
1158 0 : scaled = isl_multi_union_pw_aff_scale_multi_val(scaled, sizes);
1159 : else
1160 0 : isl_multi_val_free(sizes);
1161 0 : band->mupa = isl_multi_union_pw_aff_sub(band->mupa, scaled);
1162 0 : if (!band->mupa)
1163 0 : return isl_schedule_band_free(band);
1164 0 : return band;
1165 : error:
1166 0 : isl_schedule_band_free(band);
1167 0 : isl_multi_val_free(sizes);
1168 0 : return NULL;
1169 : }
1170 :
1171 : /* Drop the "n" dimensions starting at "pos" from "band".
1172 : *
1173 : * We apply the transformation even if "n" is zero to ensure consistent
1174 : * behavior with respect to changes in the schedule space.
1175 : *
1176 : * The caller is responsible for updating the isolate option.
1177 : */
1178 0 : __isl_give isl_schedule_band *isl_schedule_band_drop(
1179 : __isl_take isl_schedule_band *band, int pos, int n)
1180 : {
1181 : int i;
1182 :
1183 0 : if (pos < 0 || n < 0 || pos + n > band->n)
1184 0 : isl_die(isl_schedule_band_get_ctx(band), isl_error_internal,
1185 : "range out of bounds",
1186 : return isl_schedule_band_free(band));
1187 :
1188 0 : band = isl_schedule_band_cow(band);
1189 0 : if (!band)
1190 0 : return NULL;
1191 :
1192 0 : band->mupa = isl_multi_union_pw_aff_drop_dims(band->mupa,
1193 : isl_dim_set, pos, n);
1194 0 : if (!band->mupa)
1195 0 : return isl_schedule_band_free(band);
1196 :
1197 0 : for (i = pos + n; i < band->n; ++i)
1198 0 : band->coincident[i - n] = band->coincident[i];
1199 0 : if (band->loop_type)
1200 0 : for (i = pos + n; i < band->n; ++i)
1201 0 : band->loop_type[i - n] = band->loop_type[i];
1202 0 : if (band->isolate_loop_type)
1203 0 : for (i = pos + n; i < band->n; ++i)
1204 0 : band->isolate_loop_type[i - n] =
1205 0 : band->isolate_loop_type[i];
1206 :
1207 0 : band->n -= n;
1208 :
1209 0 : return band;
1210 : }
1211 :
1212 : /* Reset the user pointer on all identifiers of parameters and tuples
1213 : * in "band".
1214 : */
1215 0 : __isl_give isl_schedule_band *isl_schedule_band_reset_user(
1216 : __isl_take isl_schedule_band *band)
1217 : {
1218 0 : band = isl_schedule_band_cow(band);
1219 0 : if (!band)
1220 0 : return NULL;
1221 :
1222 0 : band->mupa = isl_multi_union_pw_aff_reset_user(band->mupa);
1223 0 : band->ast_build_options =
1224 0 : isl_union_set_reset_user(band->ast_build_options);
1225 0 : if (!band->mupa || !band->ast_build_options)
1226 0 : return isl_schedule_band_free(band);
1227 :
1228 0 : return band;
1229 : }
1230 :
1231 : /* Align the parameters of "band" to those of "space".
1232 : */
1233 0 : __isl_give isl_schedule_band *isl_schedule_band_align_params(
1234 : __isl_take isl_schedule_band *band, __isl_take isl_space *space)
1235 : {
1236 0 : band = isl_schedule_band_cow(band);
1237 0 : if (!band || !space)
1238 : goto error;
1239 :
1240 0 : band->mupa = isl_multi_union_pw_aff_align_params(band->mupa,
1241 : isl_space_copy(space));
1242 0 : band->ast_build_options =
1243 0 : isl_union_set_align_params(band->ast_build_options, space);
1244 0 : if (!band->mupa || !band->ast_build_options)
1245 0 : return isl_schedule_band_free(band);
1246 :
1247 0 : return band;
1248 : error:
1249 0 : isl_space_free(space);
1250 0 : isl_schedule_band_free(band);
1251 0 : return NULL;
1252 : }
1253 :
1254 : /* Compute the pullback of "band" by the function represented by "upma".
1255 : * In other words, plug in "upma" in the iteration domains of "band".
1256 : */
1257 0 : __isl_give isl_schedule_band *isl_schedule_band_pullback_union_pw_multi_aff(
1258 : __isl_take isl_schedule_band *band,
1259 : __isl_take isl_union_pw_multi_aff *upma)
1260 : {
1261 0 : band = isl_schedule_band_cow(band);
1262 0 : if (!band || !upma)
1263 : goto error;
1264 :
1265 0 : band->mupa =
1266 0 : isl_multi_union_pw_aff_pullback_union_pw_multi_aff(band->mupa,
1267 : upma);
1268 0 : if (!band->mupa)
1269 0 : return isl_schedule_band_free(band);
1270 :
1271 0 : return band;
1272 : error:
1273 0 : isl_union_pw_multi_aff_free(upma);
1274 0 : isl_schedule_band_free(band);
1275 0 : return NULL;
1276 : }
1277 :
1278 : /* Compute the gist of "band" with respect to "context".
1279 : * In particular, compute the gist of the associated partial schedule.
1280 : */
1281 0 : __isl_give isl_schedule_band *isl_schedule_band_gist(
1282 : __isl_take isl_schedule_band *band, __isl_take isl_union_set *context)
1283 : {
1284 0 : if (!band || !context)
1285 : goto error;
1286 0 : if (band->n == 0) {
1287 0 : isl_union_set_free(context);
1288 0 : return band;
1289 : }
1290 0 : band = isl_schedule_band_cow(band);
1291 0 : if (!band)
1292 0 : goto error;
1293 0 : band->mupa = isl_multi_union_pw_aff_gist(band->mupa, context);
1294 0 : if (!band->mupa)
1295 0 : return isl_schedule_band_free(band);
1296 0 : return band;
1297 : error:
1298 0 : isl_union_set_free(context);
1299 0 : isl_schedule_band_free(band);
1300 0 : return NULL;
1301 : }
|