1 /*
2  * Copyright 2012      Ecole Normale Superieure
3  * Copyright 2015-2016 Sven Verdoolaege
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  */
10 
11 #include <isl_schedule_constraints.h>
12 #include <isl/schedule.h>
13 #include <isl/space.h>
14 #include <isl/set.h>
15 #include <isl/map.h>
16 #include <isl/union_set.h>
17 #include <isl/union_map.h>
18 #include <isl/stream.h>
19 
20 /* The constraints that need to be satisfied by a schedule on "domain".
21  *
22  * "context" specifies extra constraints on the parameters.
23  *
24  * "validity" constraints map domain elements i to domain elements
25  * that should be scheduled after i.  (Hard constraint)
26  * "proximity" constraints map domain elements i to domains elements
27  * that should be scheduled as early as possible after i (or before i).
28  * (Soft constraint)
29  *
30  * "condition" and "conditional_validity" constraints map possibly "tagged"
31  * domain elements i -> s to "tagged" domain elements j -> t.
32  * The elements of the "conditional_validity" constraints, but without the
33  * tags (i.e., the elements i -> j) are treated as validity constraints,
34  * except that during the construction of a tilable band,
35  * the elements of the "conditional_validity" constraints may be violated
36  * provided that all adjacent elements of the "condition" constraints
37  * are local within the band.
38  * A dependence is local within a band if domain and range are mapped
39  * to the same schedule point by the band.
40  */
41 struct isl_schedule_constraints {
42 	isl_union_set *domain;
43 	isl_set *context;
44 
45 	isl_union_map *constraint[isl_edge_last + 1];
46 };
47 
isl_schedule_constraints_copy(__isl_keep isl_schedule_constraints * sc)48 __isl_give isl_schedule_constraints *isl_schedule_constraints_copy(
49 	__isl_keep isl_schedule_constraints *sc)
50 {
51 	isl_ctx *ctx;
52 	isl_schedule_constraints *sc_copy;
53 	enum isl_edge_type i;
54 
55 	ctx = isl_union_set_get_ctx(sc->domain);
56 	sc_copy = isl_calloc_type(ctx, struct isl_schedule_constraints);
57 	if (!sc_copy)
58 		return NULL;
59 
60 	sc_copy->domain = isl_union_set_copy(sc->domain);
61 	sc_copy->context = isl_set_copy(sc->context);
62 	if (!sc_copy->domain || !sc_copy->context)
63 		return isl_schedule_constraints_free(sc_copy);
64 
65 	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
66 		sc_copy->constraint[i] = isl_union_map_copy(sc->constraint[i]);
67 		if (!sc_copy->constraint[i])
68 			return isl_schedule_constraints_free(sc_copy);
69 	}
70 
71 	return sc_copy;
72 }
73 
74 /* Construct an empty (invalid) isl_schedule_constraints object.
75  * The caller is responsible for setting the domain and initializing
76  * all the other fields, e.g., by calling isl_schedule_constraints_init.
77  */
isl_schedule_constraints_alloc(isl_ctx * ctx)78 static __isl_give isl_schedule_constraints *isl_schedule_constraints_alloc(
79 	isl_ctx *ctx)
80 {
81 	return isl_calloc_type(ctx, struct isl_schedule_constraints);
82 }
83 
84 /* Initialize all the fields of "sc", except domain, which is assumed
85  * to have been set by the caller.
86  */
isl_schedule_constraints_init(__isl_take isl_schedule_constraints * sc)87 static __isl_give isl_schedule_constraints *isl_schedule_constraints_init(
88 	__isl_take isl_schedule_constraints *sc)
89 {
90 	isl_space *space;
91 	isl_union_map *empty;
92 	enum isl_edge_type i;
93 
94 	if (!sc)
95 		return NULL;
96 	if (!sc->domain)
97 		return isl_schedule_constraints_free(sc);
98 	space = isl_union_set_get_space(sc->domain);
99 	if (!sc->context)
100 		sc->context = isl_set_universe(isl_space_copy(space));
101 	empty = isl_union_map_empty(space);
102 	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
103 		if (sc->constraint[i])
104 			continue;
105 		sc->constraint[i] = isl_union_map_copy(empty);
106 		if (!sc->constraint[i])
107 			sc->domain = isl_union_set_free(sc->domain);
108 	}
109 	isl_union_map_free(empty);
110 
111 	if (!sc->domain || !sc->context)
112 		return isl_schedule_constraints_free(sc);
113 
114 	return sc;
115 }
116 
117 /* Construct an isl_schedule_constraints object for computing a schedule
118  * on "domain".  The initial object does not impose any constraints.
119  */
isl_schedule_constraints_on_domain(__isl_take isl_union_set * domain)120 __isl_give isl_schedule_constraints *isl_schedule_constraints_on_domain(
121 	__isl_take isl_union_set *domain)
122 {
123 	isl_ctx *ctx;
124 	isl_schedule_constraints *sc;
125 
126 	if (!domain)
127 		return NULL;
128 
129 	ctx = isl_union_set_get_ctx(domain);
130 	sc = isl_schedule_constraints_alloc(ctx);
131 	if (!sc)
132 		goto error;
133 
134 	sc->domain = domain;
135 	return isl_schedule_constraints_init(sc);
136 error:
137 	isl_union_set_free(domain);
138 	return NULL;
139 }
140 
141 /* Replace the domain of "sc" by "domain".
142  */
isl_schedule_constraints_set_domain(__isl_take isl_schedule_constraints * sc,__isl_take isl_union_set * domain)143 static __isl_give isl_schedule_constraints *isl_schedule_constraints_set_domain(
144 	__isl_take isl_schedule_constraints *sc,
145 	__isl_take isl_union_set *domain)
146 {
147 	if (!sc || !domain)
148 		goto error;
149 
150 	isl_union_set_free(sc->domain);
151 	sc->domain = domain;
152 
153 	return sc;
154 error:
155 	isl_schedule_constraints_free(sc);
156 	isl_union_set_free(domain);
157 	return NULL;
158 }
159 
160 /* Replace the context of "sc" by "context".
161  */
isl_schedule_constraints_set_context(__isl_take isl_schedule_constraints * sc,__isl_take isl_set * context)162 __isl_give isl_schedule_constraints *isl_schedule_constraints_set_context(
163 	__isl_take isl_schedule_constraints *sc, __isl_take isl_set *context)
164 {
165 	if (!sc || !context)
166 		goto error;
167 
168 	isl_set_free(sc->context);
169 	sc->context = context;
170 
171 	return sc;
172 error:
173 	isl_schedule_constraints_free(sc);
174 	isl_set_free(context);
175 	return NULL;
176 }
177 
178 /* Replace the constraints of type "type" in "sc" by "c".
179  *
180  * First detect any equality constraints that may be implicit in "c"
181  * in order to try and improve the accuracy of the input (and therefore
182  * also the output) of the isl_set_coefficients calls
183  * that are eventually performed on (some of) these constraints.
184  */
isl_schedule_constraints_set(__isl_take isl_schedule_constraints * sc,enum isl_edge_type type,__isl_take isl_union_map * c)185 static __isl_give isl_schedule_constraints *isl_schedule_constraints_set(
186 	__isl_take isl_schedule_constraints *sc, enum isl_edge_type type,
187 	__isl_take isl_union_map *c)
188 {
189 	c = isl_union_map_detect_equalities(c);
190 	if (!sc || !c)
191 		goto error;
192 
193 	isl_union_map_free(sc->constraint[type]);
194 	sc->constraint[type] = c;
195 
196 	return sc;
197 error:
198 	isl_schedule_constraints_free(sc);
199 	isl_union_map_free(c);
200 	return NULL;
201 }
202 
203 /* Replace the validity constraints of "sc" by "validity".
204  */
isl_schedule_constraints_set_validity(__isl_take isl_schedule_constraints * sc,__isl_take isl_union_map * validity)205 __isl_give isl_schedule_constraints *isl_schedule_constraints_set_validity(
206 	__isl_take isl_schedule_constraints *sc,
207 	__isl_take isl_union_map *validity)
208 {
209 	return isl_schedule_constraints_set(sc, isl_edge_validity, validity);
210 }
211 
212 /* Replace the coincidence constraints of "sc" by "coincidence".
213  */
isl_schedule_constraints_set_coincidence(__isl_take isl_schedule_constraints * sc,__isl_take isl_union_map * coincidence)214 __isl_give isl_schedule_constraints *isl_schedule_constraints_set_coincidence(
215 	__isl_take isl_schedule_constraints *sc,
216 	__isl_take isl_union_map *coincidence)
217 {
218 	return isl_schedule_constraints_set(sc, isl_edge_coincidence,
219 						coincidence);
220 }
221 
222 /* Replace the proximity constraints of "sc" by "proximity".
223  */
isl_schedule_constraints_set_proximity(__isl_take isl_schedule_constraints * sc,__isl_take isl_union_map * proximity)224 __isl_give isl_schedule_constraints *isl_schedule_constraints_set_proximity(
225 	__isl_take isl_schedule_constraints *sc,
226 	__isl_take isl_union_map *proximity)
227 {
228 	return isl_schedule_constraints_set(sc, isl_edge_proximity, proximity);
229 }
230 
231 /* Replace the conditional validity constraints of "sc" by "condition"
232  * and "validity".
233  */
234 __isl_give isl_schedule_constraints *
isl_schedule_constraints_set_conditional_validity(__isl_take isl_schedule_constraints * sc,__isl_take isl_union_map * condition,__isl_take isl_union_map * validity)235 isl_schedule_constraints_set_conditional_validity(
236 	__isl_take isl_schedule_constraints *sc,
237 	__isl_take isl_union_map *condition,
238 	__isl_take isl_union_map *validity)
239 {
240 	sc = isl_schedule_constraints_set(sc, isl_edge_condition, condition);
241 	sc = isl_schedule_constraints_set(sc, isl_edge_conditional_validity,
242 						validity);
243 	return sc;
244 }
245 
isl_schedule_constraints_free(__isl_take isl_schedule_constraints * sc)246 __isl_null isl_schedule_constraints *isl_schedule_constraints_free(
247 	__isl_take isl_schedule_constraints *sc)
248 {
249 	enum isl_edge_type i;
250 
251 	if (!sc)
252 		return NULL;
253 
254 	isl_union_set_free(sc->domain);
255 	isl_set_free(sc->context);
256 	for (i = isl_edge_first; i <= isl_edge_last; ++i)
257 		isl_union_map_free(sc->constraint[i]);
258 
259 	free(sc);
260 
261 	return NULL;
262 }
263 
isl_schedule_constraints_get_ctx(__isl_keep isl_schedule_constraints * sc)264 isl_ctx *isl_schedule_constraints_get_ctx(
265 	__isl_keep isl_schedule_constraints *sc)
266 {
267 	return sc ? isl_union_set_get_ctx(sc->domain) : NULL;
268 }
269 
270 /* Return the domain of "sc".
271  */
isl_schedule_constraints_get_domain(__isl_keep isl_schedule_constraints * sc)272 __isl_give isl_union_set *isl_schedule_constraints_get_domain(
273 	__isl_keep isl_schedule_constraints *sc)
274 {
275 	if (!sc)
276 		return NULL;
277 
278 	return isl_union_set_copy(sc->domain);
279 }
280 
281 /* Return the context of "sc".
282  */
isl_schedule_constraints_get_context(__isl_keep isl_schedule_constraints * sc)283 __isl_give isl_set *isl_schedule_constraints_get_context(
284 	__isl_keep isl_schedule_constraints *sc)
285 {
286 	if (!sc)
287 		return NULL;
288 
289 	return isl_set_copy(sc->context);
290 }
291 
292 /* Return the constraints of type "type" in "sc".
293  */
isl_schedule_constraints_get(__isl_keep isl_schedule_constraints * sc,enum isl_edge_type type)294 __isl_give isl_union_map *isl_schedule_constraints_get(
295 	__isl_keep isl_schedule_constraints *sc, enum isl_edge_type type)
296 {
297 	if (!sc)
298 		return NULL;
299 
300 	return isl_union_map_copy(sc->constraint[type]);
301 }
302 
303 /* Return the validity constraints of "sc".
304  */
isl_schedule_constraints_get_validity(__isl_keep isl_schedule_constraints * sc)305 __isl_give isl_union_map *isl_schedule_constraints_get_validity(
306 	__isl_keep isl_schedule_constraints *sc)
307 {
308 	return isl_schedule_constraints_get(sc, isl_edge_validity);
309 }
310 
311 /* Return the coincidence constraints of "sc".
312  */
isl_schedule_constraints_get_coincidence(__isl_keep isl_schedule_constraints * sc)313 __isl_give isl_union_map *isl_schedule_constraints_get_coincidence(
314 	__isl_keep isl_schedule_constraints *sc)
315 {
316 	return isl_schedule_constraints_get(sc, isl_edge_coincidence);
317 }
318 
319 /* Return the proximity constraints of "sc".
320  */
isl_schedule_constraints_get_proximity(__isl_keep isl_schedule_constraints * sc)321 __isl_give isl_union_map *isl_schedule_constraints_get_proximity(
322 	__isl_keep isl_schedule_constraints *sc)
323 {
324 	return isl_schedule_constraints_get(sc, isl_edge_proximity);
325 }
326 
327 /* Return the conditional validity constraints of "sc".
328  */
isl_schedule_constraints_get_conditional_validity(__isl_keep isl_schedule_constraints * sc)329 __isl_give isl_union_map *isl_schedule_constraints_get_conditional_validity(
330 	__isl_keep isl_schedule_constraints *sc)
331 {
332 	return isl_schedule_constraints_get(sc, isl_edge_conditional_validity);
333 }
334 
335 /* Return the conditions for the conditional validity constraints of "sc".
336  */
337 __isl_give isl_union_map *
isl_schedule_constraints_get_conditional_validity_condition(__isl_keep isl_schedule_constraints * sc)338 isl_schedule_constraints_get_conditional_validity_condition(
339 	__isl_keep isl_schedule_constraints *sc)
340 {
341 	return isl_schedule_constraints_get(sc, isl_edge_condition);
342 }
343 
344 /* Add "c" to the constraints of type "type" in "sc".
345  */
isl_schedule_constraints_add(__isl_take isl_schedule_constraints * sc,enum isl_edge_type type,__isl_take isl_union_map * c)346 __isl_give isl_schedule_constraints *isl_schedule_constraints_add(
347 	__isl_take isl_schedule_constraints *sc, enum isl_edge_type type,
348 	__isl_take isl_union_map *c)
349 {
350 	if (!sc || !c)
351 		goto error;
352 
353 	c = isl_union_map_union(sc->constraint[type], c);
354 	sc->constraint[type] = c;
355 	if (!c)
356 		return isl_schedule_constraints_free(sc);
357 
358 	return sc;
359 error:
360 	isl_schedule_constraints_free(sc);
361 	isl_union_map_free(c);
362 	return NULL;
363 }
364 
365 /* Can a schedule constraint of type "type" be tagged?
366  */
may_be_tagged(enum isl_edge_type type)367 static int may_be_tagged(enum isl_edge_type type)
368 {
369 	if (type == isl_edge_condition || type == isl_edge_conditional_validity)
370 		return 1;
371 	return 0;
372 }
373 
374 /* Apply "umap" to the domains of the wrapped relations
375  * inside the domain and range of "c".
376  *
377  * That is, for each map of the form
378  *
379  *	[D -> S] -> [E -> T]
380  *
381  * in "c", apply "umap" to D and E.
382  *
383  * D is exposed by currying the relation to
384  *
385  *	D -> [S -> [E -> T]]
386  *
387  * E is exposed by doing the same to the inverse of "c".
388  */
apply_factor_domain(__isl_take isl_union_map * c,__isl_keep isl_union_map * umap)389 static __isl_give isl_union_map *apply_factor_domain(
390 	__isl_take isl_union_map *c, __isl_keep isl_union_map *umap)
391 {
392 	c = isl_union_map_curry(c);
393 	c = isl_union_map_apply_domain(c, isl_union_map_copy(umap));
394 	c = isl_union_map_uncurry(c);
395 
396 	c = isl_union_map_reverse(c);
397 	c = isl_union_map_curry(c);
398 	c = isl_union_map_apply_domain(c, isl_union_map_copy(umap));
399 	c = isl_union_map_uncurry(c);
400 	c = isl_union_map_reverse(c);
401 
402 	return c;
403 }
404 
405 /* Apply "umap" to domain and range of "c".
406  * If "tag" is set, then "c" may contain tags and then "umap"
407  * needs to be applied to the domains of the wrapped relations
408  * inside the domain and range of "c".
409  */
apply(__isl_take isl_union_map * c,__isl_keep isl_union_map * umap,int tag)410 static __isl_give isl_union_map *apply(__isl_take isl_union_map *c,
411 	__isl_keep isl_union_map *umap, int tag)
412 {
413 	isl_union_map *t;
414 
415 	if (tag)
416 		t = isl_union_map_copy(c);
417 	c = isl_union_map_apply_domain(c, isl_union_map_copy(umap));
418 	c = isl_union_map_apply_range(c, isl_union_map_copy(umap));
419 	if (!tag)
420 		return c;
421 	t = apply_factor_domain(t, umap);
422 	c = isl_union_map_union(c, t);
423 	return c;
424 }
425 
426 /* Apply "umap" to the domain of the schedule constraints "sc".
427  *
428  * The two sides of the various schedule constraints are adjusted
429  * accordingly.
430  */
isl_schedule_constraints_apply(__isl_take isl_schedule_constraints * sc,__isl_take isl_union_map * umap)431 __isl_give isl_schedule_constraints *isl_schedule_constraints_apply(
432 	__isl_take isl_schedule_constraints *sc,
433 	__isl_take isl_union_map *umap)
434 {
435 	enum isl_edge_type i;
436 
437 	if (!sc || !umap)
438 		goto error;
439 
440 	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
441 		int tag = may_be_tagged(i);
442 
443 		sc->constraint[i] = apply(sc->constraint[i], umap, tag);
444 		if (!sc->constraint[i])
445 			goto error;
446 	}
447 	sc->domain = isl_union_set_apply(sc->domain, umap);
448 	if (!sc->domain)
449 		return isl_schedule_constraints_free(sc);
450 
451 	return sc;
452 error:
453 	isl_schedule_constraints_free(sc);
454 	isl_union_map_free(umap);
455 	return NULL;
456 }
457 
458 /* An enumeration of the various keys that may appear in a YAML mapping
459  * of an isl_schedule_constraints object.
460  * The keys for the edge types are assumed to have the same values
461  * as the edge types in isl_edge_type.
462  */
463 enum isl_sc_key {
464 	isl_sc_key_error = -1,
465 	isl_sc_key_validity = isl_edge_validity,
466 	isl_sc_key_coincidence = isl_edge_coincidence,
467 	isl_sc_key_condition = isl_edge_condition,
468 	isl_sc_key_conditional_validity = isl_edge_conditional_validity,
469 	isl_sc_key_proximity = isl_edge_proximity,
470 	isl_sc_key_domain,
471 	isl_sc_key_context,
472 	isl_sc_key_end
473 };
474 
475 /* Textual representations of the YAML keys for an isl_schedule_constraints
476  * object.
477  */
478 static char *key_str[] = {
479 	[isl_sc_key_validity] = "validity",
480 	[isl_sc_key_coincidence] = "coincidence",
481 	[isl_sc_key_condition] = "condition",
482 	[isl_sc_key_conditional_validity] = "conditional_validity",
483 	[isl_sc_key_proximity] = "proximity",
484 	[isl_sc_key_domain] = "domain",
485 	[isl_sc_key_context] = "context",
486 };
487 
488 #undef BASE
489 #define BASE set
490 #include "print_yaml_field_templ.c"
491 
492 #undef BASE
493 #define BASE union_set
494 #include "print_yaml_field_templ.c"
495 
496 #undef BASE
497 #define BASE union_map
498 #include "print_yaml_field_templ.c"
499 
500 /* Print a key, value pair for the edge of type "type" in "sc" to "p".
501  *
502  * If the edge relation is empty, then it is not printed since
503  * an empty relation is the default value.
504  */
print_constraint(__isl_take isl_printer * p,__isl_keep isl_schedule_constraints * sc,enum isl_edge_type type)505 static __isl_give isl_printer *print_constraint(__isl_take isl_printer *p,
506 	__isl_keep isl_schedule_constraints *sc, enum isl_edge_type type)
507 {
508 	isl_bool empty;
509 
510 	empty = isl_union_map_plain_is_empty(sc->constraint[type]);
511 	if (empty < 0)
512 		return isl_printer_free(p);
513 	if (empty)
514 		return p;
515 
516 	p = print_yaml_field_union_map(p, key_str[type], sc->constraint[type]);
517 
518 	return p;
519 }
520 
521 /* Print "sc" to "p"
522  *
523  * In particular, print the isl_schedule_constraints object as a YAML document.
524  * Fields with values that are (obviously) equal to their default values
525  * are not printed.
526  */
isl_printer_print_schedule_constraints(__isl_take isl_printer * p,__isl_keep isl_schedule_constraints * sc)527 __isl_give isl_printer *isl_printer_print_schedule_constraints(
528 	__isl_take isl_printer *p, __isl_keep isl_schedule_constraints *sc)
529 {
530 	isl_bool universe;
531 
532 	if (!sc)
533 		return isl_printer_free(p);
534 
535 	p = isl_printer_yaml_start_mapping(p);
536 	p = print_yaml_field_union_set(p, key_str[isl_sc_key_domain],
537 					sc->domain);
538 	universe = isl_set_plain_is_universe(sc->context);
539 	if (universe < 0)
540 		return isl_printer_free(p);
541 	if (!universe)
542 		p = print_yaml_field_set(p, key_str[isl_sc_key_context],
543 						sc->context);
544 	p = print_constraint(p, sc, isl_edge_validity);
545 	p = print_constraint(p, sc, isl_edge_proximity);
546 	p = print_constraint(p, sc, isl_edge_coincidence);
547 	p = print_constraint(p, sc, isl_edge_condition);
548 	p = print_constraint(p, sc, isl_edge_conditional_validity);
549 	p = isl_printer_yaml_end_mapping(p);
550 
551 	return p;
552 }
553 
554 #undef BASE
555 #define BASE schedule_constraints
556 #include <print_templ_yaml.c>
557 
558 #undef KEY
559 #define KEY enum isl_sc_key
560 #undef KEY_ERROR
561 #define KEY_ERROR isl_sc_key_error
562 #undef KEY_END
563 #define KEY_END isl_sc_key_end
564 #include "extract_key.c"
565 
566 #undef BASE
567 #define BASE set
568 #include "read_in_string_templ.c"
569 
570 #undef BASE
571 #define BASE union_set
572 #include "read_in_string_templ.c"
573 
574 #undef BASE
575 #define BASE union_map
576 #include "read_in_string_templ.c"
577 
578 /* Read an isl_schedule_constraints object from "s".
579  *
580  * Start off with an empty (invalid) isl_schedule_constraints object and
581  * then fill up the fields based on the input.
582  * The input needs to contain at least a description of the domain.
583  * The other fields are set to defaults by isl_schedule_constraints_init
584  * if they are not specified in the input.
585  */
isl_stream_read_schedule_constraints(isl_stream * s)586 __isl_give isl_schedule_constraints *isl_stream_read_schedule_constraints(
587 	isl_stream *s)
588 {
589 	isl_ctx *ctx;
590 	isl_schedule_constraints *sc;
591 	int more;
592 	int domain_set = 0;
593 
594 	if (isl_stream_yaml_read_start_mapping(s))
595 		return NULL;
596 
597 	ctx = isl_stream_get_ctx(s);
598 	sc = isl_schedule_constraints_alloc(ctx);
599 	while ((more = isl_stream_yaml_next(s)) > 0) {
600 		enum isl_sc_key key;
601 		isl_set *context;
602 		isl_union_set *domain;
603 		isl_union_map *constraints;
604 
605 		key = get_key(s);
606 		if (isl_stream_yaml_next(s) < 0)
607 			return isl_schedule_constraints_free(sc);
608 		switch (key) {
609 		case isl_sc_key_end:
610 		case isl_sc_key_error:
611 			return isl_schedule_constraints_free(sc);
612 		case isl_sc_key_domain:
613 			domain_set = 1;
614 			domain = read_union_set(s);
615 			sc = isl_schedule_constraints_set_domain(sc, domain);
616 			if (!sc)
617 				return NULL;
618 			break;
619 		case isl_sc_key_context:
620 			context = read_set(s);
621 			sc = isl_schedule_constraints_set_context(sc, context);
622 			if (!sc)
623 				return NULL;
624 			break;
625 		case isl_sc_key_validity:
626 		case isl_sc_key_coincidence:
627 		case isl_sc_key_condition:
628 		case isl_sc_key_conditional_validity:
629 		case isl_sc_key_proximity:
630 			constraints = read_union_map(s);
631 			sc = isl_schedule_constraints_set(sc, key, constraints);
632 			if (!sc)
633 				return NULL;
634 			break;
635 		}
636 	}
637 	if (more < 0)
638 		return isl_schedule_constraints_free(sc);
639 
640 	if (isl_stream_yaml_read_end_mapping(s) < 0) {
641 		isl_stream_error(s, NULL, "unexpected extra elements");
642 		return isl_schedule_constraints_free(sc);
643 	}
644 
645 	if (!domain_set) {
646 		isl_stream_error(s, NULL, "no domain specified");
647 		return isl_schedule_constraints_free(sc);
648 	}
649 
650 	return isl_schedule_constraints_init(sc);
651 }
652 
653 /* Read an isl_schedule_constraints object from the file "input".
654  */
isl_schedule_constraints_read_from_file(isl_ctx * ctx,FILE * input)655 __isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_file(
656 	isl_ctx *ctx, FILE *input)
657 {
658 	struct isl_stream *s;
659 	isl_schedule_constraints *sc;
660 
661 	s = isl_stream_new_file(ctx, input);
662 	if (!s)
663 		return NULL;
664 	sc = isl_stream_read_schedule_constraints(s);
665 	isl_stream_free(s);
666 
667 	return sc;
668 }
669 
670 /* Read an isl_schedule_constraints object from the string "str".
671  */
isl_schedule_constraints_read_from_str(isl_ctx * ctx,const char * str)672 __isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_str(
673 	isl_ctx *ctx, const char *str)
674 {
675 	struct isl_stream *s;
676 	isl_schedule_constraints *sc;
677 
678 	s = isl_stream_new_str(ctx, str);
679 	if (!s)
680 		return NULL;
681 	sc = isl_stream_read_schedule_constraints(s);
682 	isl_stream_free(s);
683 
684 	return sc;
685 }
686 
687 /* Align the parameters of the fields of "sc".
688  */
689 __isl_give isl_schedule_constraints *
isl_schedule_constraints_align_params(__isl_take isl_schedule_constraints * sc)690 isl_schedule_constraints_align_params(__isl_take isl_schedule_constraints *sc)
691 {
692 	isl_space *space;
693 	enum isl_edge_type i;
694 
695 	if (!sc)
696 		return NULL;
697 
698 	space = isl_union_set_get_space(sc->domain);
699 	space = isl_space_align_params(space, isl_set_get_space(sc->context));
700 	for (i = isl_edge_first; i <= isl_edge_last; ++i)
701 		space = isl_space_align_params(space,
702 				    isl_union_map_get_space(sc->constraint[i]));
703 
704 	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
705 		sc->constraint[i] = isl_union_map_align_params(
706 				    sc->constraint[i], isl_space_copy(space));
707 		if (!sc->constraint[i])
708 			space = isl_space_free(space);
709 	}
710 	sc->context = isl_set_align_params(sc->context, isl_space_copy(space));
711 	sc->domain = isl_union_set_align_params(sc->domain, space);
712 	if (!sc->context || !sc->domain)
713 		return isl_schedule_constraints_free(sc);
714 
715 	return sc;
716 }
717 
718 /* Add the number of basic maps in "map" to *n.
719  */
add_n_basic_map(__isl_take isl_map * map,void * user)720 static isl_stat add_n_basic_map(__isl_take isl_map *map, void *user)
721 {
722 	int *n = user;
723 	isl_size n_basic_map;
724 
725 	n_basic_map = isl_map_n_basic_map(map);
726 	*n += n_basic_map;
727 	isl_map_free(map);
728 
729 	return n_basic_map < 0 ? isl_stat_error : isl_stat_ok;
730 }
731 
732 /* Return the total number of isl_basic_maps in the constraints of "sc".
733  * Return -1 on error.
734  */
isl_schedule_constraints_n_basic_map(__isl_keep isl_schedule_constraints * sc)735 int isl_schedule_constraints_n_basic_map(
736 	__isl_keep isl_schedule_constraints *sc)
737 {
738 	enum isl_edge_type i;
739 	int n = 0;
740 
741 	if (!sc)
742 		return -1;
743 	for (i = isl_edge_first; i <= isl_edge_last; ++i)
744 		if (isl_union_map_foreach_map(sc->constraint[i],
745 						&add_n_basic_map, &n) < 0)
746 			return -1;
747 
748 	return n;
749 }
750 
751 /* Return the total number of isl_maps in the constraints of "sc".
752  */
isl_schedule_constraints_n_map(__isl_keep isl_schedule_constraints * sc)753 isl_size isl_schedule_constraints_n_map(__isl_keep isl_schedule_constraints *sc)
754 {
755 	enum isl_edge_type i;
756 	int n = 0;
757 
758 	for (i = isl_edge_first; i <= isl_edge_last; ++i) {
759 		isl_size n_i;
760 
761 		n_i = isl_union_map_n_map(sc->constraint[i]);
762 		if (n_i < 0)
763 			return isl_size_error;
764 		n += n_i;
765 	}
766 
767 	return n;
768 }
769