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