merge test_plain_unshifted_simple_hull and test_unshifted_simple_hull
[isl.git] / isl_schedule_constraints.c
blob3d92b53592f465ece90c1fc507112dcbc64619cd
1 /*
2 * Copyright 2012 Ecole Normale Superieure
3 * Copyright 2015-2016 Sven Verdoolaege
5 * Use of this software is governed by the MIT license
7 * Written by Sven Verdoolaege,
8 * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
9 */
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>
20 /* The constraints that need to be satisfied by a schedule on "domain".
22 * "context" specifies extra constraints on the parameters.
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)
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.
41 struct isl_schedule_constraints {
42 isl_union_set *domain;
43 isl_set *context;
45 isl_union_map *constraint[isl_edge_last + 1];
48 __isl_give isl_schedule_constraints *isl_schedule_constraints_copy(
49 __isl_keep isl_schedule_constraints *sc)
51 isl_ctx *ctx;
52 isl_schedule_constraints *sc_copy;
53 enum isl_edge_type i;
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;
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);
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);
71 return sc_copy;
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.
78 static __isl_give isl_schedule_constraints *isl_schedule_constraints_alloc(
79 isl_ctx *ctx)
81 return isl_calloc_type(ctx, struct isl_schedule_constraints);
84 /* Initialize all the fields of "sc", except domain, which is assumed
85 * to have been set by the caller.
87 static __isl_give isl_schedule_constraints *isl_schedule_constraints_init(
88 __isl_take isl_schedule_constraints *sc)
90 isl_space *space;
91 isl_union_map *empty;
92 enum isl_edge_type i;
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);
109 isl_union_map_free(empty);
111 if (!sc->domain || !sc->context)
112 return isl_schedule_constraints_free(sc);
114 return sc;
117 /* Construct an isl_schedule_constraints object for computing a schedule
118 * on "domain". The initial object does not impose any constraints.
120 __isl_give isl_schedule_constraints *isl_schedule_constraints_on_domain(
121 __isl_take isl_union_set *domain)
123 isl_ctx *ctx;
124 isl_schedule_constraints *sc;
126 if (!domain)
127 return NULL;
129 ctx = isl_union_set_get_ctx(domain);
130 sc = isl_schedule_constraints_alloc(ctx);
131 if (!sc)
132 goto error;
134 sc->domain = domain;
135 return isl_schedule_constraints_init(sc);
136 error:
137 isl_union_set_free(domain);
138 return NULL;
141 /* Replace the domain of "sc" by "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)
147 if (!sc || !domain)
148 goto error;
150 isl_union_set_free(sc->domain);
151 sc->domain = domain;
153 return sc;
154 error:
155 isl_schedule_constraints_free(sc);
156 isl_union_set_free(domain);
157 return NULL;
160 /* Replace the context of "sc" by "context".
162 __isl_give isl_schedule_constraints *isl_schedule_constraints_set_context(
163 __isl_take isl_schedule_constraints *sc, __isl_take isl_set *context)
165 if (!sc || !context)
166 goto error;
168 isl_set_free(sc->context);
169 sc->context = context;
171 return sc;
172 error:
173 isl_schedule_constraints_free(sc);
174 isl_set_free(context);
175 return NULL;
178 /* Replace the constraints of type "type" in "sc" by "c".
180 static __isl_give isl_schedule_constraints *isl_schedule_constraints_set(
181 __isl_take isl_schedule_constraints *sc, enum isl_edge_type type,
182 __isl_take isl_union_map *c)
184 if (!sc || !c)
185 goto error;
187 isl_union_map_free(sc->constraint[type]);
188 sc->constraint[type] = c;
190 return sc;
191 error:
192 isl_schedule_constraints_free(sc);
193 isl_union_map_free(c);
194 return NULL;
197 /* Replace the validity constraints of "sc" by "validity".
199 __isl_give isl_schedule_constraints *isl_schedule_constraints_set_validity(
200 __isl_take isl_schedule_constraints *sc,
201 __isl_take isl_union_map *validity)
203 return isl_schedule_constraints_set(sc, isl_edge_validity, validity);
206 /* Replace the coincidence constraints of "sc" by "coincidence".
208 __isl_give isl_schedule_constraints *isl_schedule_constraints_set_coincidence(
209 __isl_take isl_schedule_constraints *sc,
210 __isl_take isl_union_map *coincidence)
212 return isl_schedule_constraints_set(sc, isl_edge_coincidence,
213 coincidence);
216 /* Replace the proximity constraints of "sc" by "proximity".
218 __isl_give isl_schedule_constraints *isl_schedule_constraints_set_proximity(
219 __isl_take isl_schedule_constraints *sc,
220 __isl_take isl_union_map *proximity)
222 return isl_schedule_constraints_set(sc, isl_edge_proximity, proximity);
225 /* Replace the conditional validity constraints of "sc" by "condition"
226 * and "validity".
228 __isl_give isl_schedule_constraints *
229 isl_schedule_constraints_set_conditional_validity(
230 __isl_take isl_schedule_constraints *sc,
231 __isl_take isl_union_map *condition,
232 __isl_take isl_union_map *validity)
234 sc = isl_schedule_constraints_set(sc, isl_edge_condition, condition);
235 sc = isl_schedule_constraints_set(sc, isl_edge_conditional_validity,
236 validity);
237 return sc;
240 __isl_null isl_schedule_constraints *isl_schedule_constraints_free(
241 __isl_take isl_schedule_constraints *sc)
243 enum isl_edge_type i;
245 if (!sc)
246 return NULL;
248 isl_union_set_free(sc->domain);
249 isl_set_free(sc->context);
250 for (i = isl_edge_first; i <= isl_edge_last; ++i)
251 isl_union_map_free(sc->constraint[i]);
253 free(sc);
255 return NULL;
258 isl_ctx *isl_schedule_constraints_get_ctx(
259 __isl_keep isl_schedule_constraints *sc)
261 return sc ? isl_union_set_get_ctx(sc->domain) : NULL;
264 /* Return the domain of "sc".
266 __isl_give isl_union_set *isl_schedule_constraints_get_domain(
267 __isl_keep isl_schedule_constraints *sc)
269 if (!sc)
270 return NULL;
272 return isl_union_set_copy(sc->domain);
275 /* Return the context of "sc".
277 __isl_give isl_set *isl_schedule_constraints_get_context(
278 __isl_keep isl_schedule_constraints *sc)
280 if (!sc)
281 return NULL;
283 return isl_set_copy(sc->context);
286 /* Return the constraints of type "type" in "sc".
288 __isl_give isl_union_map *isl_schedule_constraints_get(
289 __isl_keep isl_schedule_constraints *sc, enum isl_edge_type type)
291 if (!sc)
292 return NULL;
294 return isl_union_map_copy(sc->constraint[type]);
297 /* Return the validity constraints of "sc".
299 __isl_give isl_union_map *isl_schedule_constraints_get_validity(
300 __isl_keep isl_schedule_constraints *sc)
302 return isl_schedule_constraints_get(sc, isl_edge_validity);
305 /* Return the coincidence constraints of "sc".
307 __isl_give isl_union_map *isl_schedule_constraints_get_coincidence(
308 __isl_keep isl_schedule_constraints *sc)
310 return isl_schedule_constraints_get(sc, isl_edge_coincidence);
313 /* Return the proximity constraints of "sc".
315 __isl_give isl_union_map *isl_schedule_constraints_get_proximity(
316 __isl_keep isl_schedule_constraints *sc)
318 return isl_schedule_constraints_get(sc, isl_edge_proximity);
321 /* Return the conditional validity constraints of "sc".
323 __isl_give isl_union_map *isl_schedule_constraints_get_conditional_validity(
324 __isl_keep isl_schedule_constraints *sc)
326 return isl_schedule_constraints_get(sc, isl_edge_conditional_validity);
329 /* Return the conditions for the conditional validity constraints of "sc".
331 __isl_give isl_union_map *
332 isl_schedule_constraints_get_conditional_validity_condition(
333 __isl_keep isl_schedule_constraints *sc)
335 return isl_schedule_constraints_get(sc, isl_edge_condition);
338 /* Add "c" to the constraints of type "type" in "sc".
340 __isl_give isl_schedule_constraints *isl_schedule_constraints_add(
341 __isl_take isl_schedule_constraints *sc, enum isl_edge_type type,
342 __isl_take isl_union_map *c)
344 if (!sc || !c)
345 goto error;
347 c = isl_union_map_union(sc->constraint[type], c);
348 sc->constraint[type] = c;
349 if (!c)
350 return isl_schedule_constraints_free(sc);
352 return sc;
353 error:
354 isl_schedule_constraints_free(sc);
355 isl_union_map_free(c);
356 return NULL;
359 /* Can a schedule constraint of type "type" be tagged?
361 static int may_be_tagged(enum isl_edge_type type)
363 if (type == isl_edge_condition || type == isl_edge_conditional_validity)
364 return 1;
365 return 0;
368 /* Apply "umap" to the domains of the wrapped relations
369 * inside the domain and range of "c".
371 * That is, for each map of the form
373 * [D -> S] -> [E -> T]
375 * in "c", apply "umap" to D and E.
377 * D is exposed by currying the relation to
379 * D -> [S -> [E -> T]]
381 * E is exposed by doing the same to the inverse of "c".
383 static __isl_give isl_union_map *apply_factor_domain(
384 __isl_take isl_union_map *c, __isl_keep isl_union_map *umap)
386 c = isl_union_map_curry(c);
387 c = isl_union_map_apply_domain(c, isl_union_map_copy(umap));
388 c = isl_union_map_uncurry(c);
390 c = isl_union_map_reverse(c);
391 c = isl_union_map_curry(c);
392 c = isl_union_map_apply_domain(c, isl_union_map_copy(umap));
393 c = isl_union_map_uncurry(c);
394 c = isl_union_map_reverse(c);
396 return c;
399 /* Apply "umap" to domain and range of "c".
400 * If "tag" is set, then "c" may contain tags and then "umap"
401 * needs to be applied to the domains of the wrapped relations
402 * inside the domain and range of "c".
404 static __isl_give isl_union_map *apply(__isl_take isl_union_map *c,
405 __isl_keep isl_union_map *umap, int tag)
407 isl_union_map *t;
409 if (tag)
410 t = isl_union_map_copy(c);
411 c = isl_union_map_apply_domain(c, isl_union_map_copy(umap));
412 c = isl_union_map_apply_range(c, isl_union_map_copy(umap));
413 if (!tag)
414 return c;
415 t = apply_factor_domain(t, umap);
416 c = isl_union_map_union(c, t);
417 return c;
420 /* Apply "umap" to the domain of the schedule constraints "sc".
422 * The two sides of the various schedule constraints are adjusted
423 * accordingly.
425 __isl_give isl_schedule_constraints *isl_schedule_constraints_apply(
426 __isl_take isl_schedule_constraints *sc,
427 __isl_take isl_union_map *umap)
429 enum isl_edge_type i;
431 if (!sc || !umap)
432 goto error;
434 for (i = isl_edge_first; i <= isl_edge_last; ++i) {
435 int tag = may_be_tagged(i);
437 sc->constraint[i] = apply(sc->constraint[i], umap, tag);
438 if (!sc->constraint[i])
439 goto error;
441 sc->domain = isl_union_set_apply(sc->domain, umap);
442 if (!sc->domain)
443 return isl_schedule_constraints_free(sc);
445 return sc;
446 error:
447 isl_schedule_constraints_free(sc);
448 isl_union_map_free(umap);
449 return NULL;
452 /* An enumeration of the various keys that may appear in a YAML mapping
453 * of an isl_schedule_constraints object.
454 * The keys for the edge types are assumed to have the same values
455 * as the edge types in isl_edge_type.
457 enum isl_sc_key {
458 isl_sc_key_error = -1,
459 isl_sc_key_validity = isl_edge_validity,
460 isl_sc_key_coincidence = isl_edge_coincidence,
461 isl_sc_key_condition = isl_edge_condition,
462 isl_sc_key_conditional_validity = isl_edge_conditional_validity,
463 isl_sc_key_proximity = isl_edge_proximity,
464 isl_sc_key_domain,
465 isl_sc_key_context,
466 isl_sc_key_end
469 /* Textual representations of the YAML keys for an isl_schedule_constraints
470 * object.
472 static char *key_str[] = {
473 [isl_sc_key_validity] = "validity",
474 [isl_sc_key_coincidence] = "coincidence",
475 [isl_sc_key_condition] = "condition",
476 [isl_sc_key_conditional_validity] = "conditional_validity",
477 [isl_sc_key_proximity] = "proximity",
478 [isl_sc_key_domain] = "domain",
479 [isl_sc_key_context] = "context",
482 #undef BASE
483 #define BASE set
484 #include "print_yaml_field_templ.c"
486 #undef BASE
487 #define BASE union_set
488 #include "print_yaml_field_templ.c"
490 #undef BASE
491 #define BASE union_map
492 #include "print_yaml_field_templ.c"
494 /* Print a key, value pair for the edge of type "type" in "sc" to "p".
496 * If the edge relation is empty, then it is not printed since
497 * an empty relation is the default value.
499 static __isl_give isl_printer *print_constraint(__isl_take isl_printer *p,
500 __isl_keep isl_schedule_constraints *sc, enum isl_edge_type type)
502 isl_bool empty;
504 empty = isl_union_map_plain_is_empty(sc->constraint[type]);
505 if (empty < 0)
506 return isl_printer_free(p);
507 if (empty)
508 return p;
510 p = print_yaml_field_union_map(p, key_str[type], sc->constraint[type]);
512 return p;
515 /* Print "sc" to "p"
517 * In particular, print the isl_schedule_constraints object as a YAML document.
518 * Fields with values that are (obviously) equal to their default values
519 * are not printed.
521 __isl_give isl_printer *isl_printer_print_schedule_constraints(
522 __isl_take isl_printer *p, __isl_keep isl_schedule_constraints *sc)
524 isl_bool universe;
526 if (!sc)
527 return isl_printer_free(p);
529 p = isl_printer_yaml_start_mapping(p);
530 p = print_yaml_field_union_set(p, key_str[isl_sc_key_domain],
531 sc->domain);
532 universe = isl_set_plain_is_universe(sc->context);
533 if (universe < 0)
534 return isl_printer_free(p);
535 if (!universe)
536 p = print_yaml_field_set(p, key_str[isl_sc_key_context],
537 sc->context);
538 p = print_constraint(p, sc, isl_edge_validity);
539 p = print_constraint(p, sc, isl_edge_proximity);
540 p = print_constraint(p, sc, isl_edge_coincidence);
541 p = print_constraint(p, sc, isl_edge_condition);
542 p = print_constraint(p, sc, isl_edge_conditional_validity);
543 p = isl_printer_yaml_end_mapping(p);
545 return p;
548 #undef BASE
549 #define BASE schedule_constraints
550 #include <print_templ_yaml.c>
552 #undef KEY
553 #define KEY enum isl_sc_key
554 #undef KEY_ERROR
555 #define KEY_ERROR isl_sc_key_error
556 #undef KEY_END
557 #define KEY_END isl_sc_key_end
558 #include "extract_key.c"
560 #undef BASE
561 #define BASE set
562 #include "read_in_string_templ.c"
564 #undef BASE
565 #define BASE union_set
566 #include "read_in_string_templ.c"
568 #undef BASE
569 #define BASE union_map
570 #include "read_in_string_templ.c"
572 /* Read an isl_schedule_constraints object from "s".
574 * Start off with an empty (invalid) isl_schedule_constraints object and
575 * then fill up the fields based on the input.
576 * The input needs to contain at least a description of the domain.
577 * The other fields are set to defaults by isl_schedule_constraints_init
578 * if they are not specified in the input.
580 __isl_give isl_schedule_constraints *isl_stream_read_schedule_constraints(
581 isl_stream *s)
583 isl_ctx *ctx;
584 isl_schedule_constraints *sc;
585 int more;
586 int domain_set = 0;
588 if (isl_stream_yaml_read_start_mapping(s))
589 return NULL;
591 ctx = isl_stream_get_ctx(s);
592 sc = isl_schedule_constraints_alloc(ctx);
593 while ((more = isl_stream_yaml_next(s)) > 0) {
594 enum isl_sc_key key;
595 isl_set *context;
596 isl_union_set *domain;
597 isl_union_map *constraints;
599 key = get_key(s);
600 if (isl_stream_yaml_next(s) < 0)
601 return isl_schedule_constraints_free(sc);
602 switch (key) {
603 case isl_sc_key_end:
604 case isl_sc_key_error:
605 return isl_schedule_constraints_free(sc);
606 case isl_sc_key_domain:
607 domain_set = 1;
608 domain = read_union_set(s);
609 sc = isl_schedule_constraints_set_domain(sc, domain);
610 if (!sc)
611 return NULL;
612 break;
613 case isl_sc_key_context:
614 context = read_set(s);
615 sc = isl_schedule_constraints_set_context(sc, context);
616 if (!sc)
617 return NULL;
618 break;
619 case isl_sc_key_validity:
620 case isl_sc_key_coincidence:
621 case isl_sc_key_condition:
622 case isl_sc_key_conditional_validity:
623 case isl_sc_key_proximity:
624 constraints = read_union_map(s);
625 sc = isl_schedule_constraints_set(sc, key, constraints);
626 if (!sc)
627 return NULL;
628 break;
631 if (more < 0)
632 return isl_schedule_constraints_free(sc);
634 if (isl_stream_yaml_read_end_mapping(s) < 0) {
635 isl_stream_error(s, NULL, "unexpected extra elements");
636 return isl_schedule_constraints_free(sc);
639 if (!domain_set) {
640 isl_stream_error(s, NULL, "no domain specified");
641 return isl_schedule_constraints_free(sc);
644 return isl_schedule_constraints_init(sc);
647 /* Read an isl_schedule_constraints object from the file "input".
649 __isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_file(
650 isl_ctx *ctx, FILE *input)
652 struct isl_stream *s;
653 isl_schedule_constraints *sc;
655 s = isl_stream_new_file(ctx, input);
656 if (!s)
657 return NULL;
658 sc = isl_stream_read_schedule_constraints(s);
659 isl_stream_free(s);
661 return sc;
664 /* Read an isl_schedule_constraints object from the string "str".
666 __isl_give isl_schedule_constraints *isl_schedule_constraints_read_from_str(
667 isl_ctx *ctx, const char *str)
669 struct isl_stream *s;
670 isl_schedule_constraints *sc;
672 s = isl_stream_new_str(ctx, str);
673 if (!s)
674 return NULL;
675 sc = isl_stream_read_schedule_constraints(s);
676 isl_stream_free(s);
678 return sc;
681 /* Align the parameters of the fields of "sc".
683 __isl_give isl_schedule_constraints *
684 isl_schedule_constraints_align_params(__isl_take isl_schedule_constraints *sc)
686 isl_space *space;
687 enum isl_edge_type i;
689 if (!sc)
690 return NULL;
692 space = isl_union_set_get_space(sc->domain);
693 space = isl_space_align_params(space, isl_set_get_space(sc->context));
694 for (i = isl_edge_first; i <= isl_edge_last; ++i)
695 space = isl_space_align_params(space,
696 isl_union_map_get_space(sc->constraint[i]));
698 for (i = isl_edge_first; i <= isl_edge_last; ++i) {
699 sc->constraint[i] = isl_union_map_align_params(
700 sc->constraint[i], isl_space_copy(space));
701 if (!sc->constraint[i])
702 space = isl_space_free(space);
704 sc->context = isl_set_align_params(sc->context, isl_space_copy(space));
705 sc->domain = isl_union_set_align_params(sc->domain, space);
706 if (!sc->context || !sc->domain)
707 return isl_schedule_constraints_free(sc);
709 return sc;
712 /* Add the number of basic maps in "map" to *n.
714 static isl_stat add_n_basic_map(__isl_take isl_map *map, void *user)
716 int *n = user;
717 isl_size n_basic_map;
719 n_basic_map = isl_map_n_basic_map(map);
720 *n += n_basic_map;
721 isl_map_free(map);
723 return n_basic_map < 0 ? isl_stat_error : isl_stat_ok;
726 /* Return the total number of isl_basic_maps in the constraints of "sc".
727 * Return -1 on error.
729 int isl_schedule_constraints_n_basic_map(
730 __isl_keep isl_schedule_constraints *sc)
732 enum isl_edge_type i;
733 int n = 0;
735 if (!sc)
736 return -1;
737 for (i = isl_edge_first; i <= isl_edge_last; ++i)
738 if (isl_union_map_foreach_map(sc->constraint[i],
739 &add_n_basic_map, &n) < 0)
740 return -1;
742 return n;
745 /* Return the total number of isl_maps in the constraints of "sc".
747 isl_size isl_schedule_constraints_n_map(__isl_keep isl_schedule_constraints *sc)
749 enum isl_edge_type i;
750 int n = 0;
752 for (i = isl_edge_first; i <= isl_edge_last; ++i) {
753 isl_size n_i;
755 n_i = isl_union_map_n_map(sc->constraint[i]);
756 if (n_i < 0)
757 return isl_size_error;
758 n += n_i;
761 return n;