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
11 #include <isl_schedule_constraints.h>
12 #include <isl/schedule.h>
13 #include <isl/space.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).
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
;
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
)
52 isl_schedule_constraints
*sc_copy
;
55 ctx
= isl_union_set_get_ctx(sc
->domain
);
56 sc_copy
= isl_calloc_type(ctx
, struct isl_schedule_constraints
);
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
);
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(
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
)
97 return isl_schedule_constraints_free(sc
);
98 space
= isl_union_set_get_space(sc
->domain
);
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
])
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
);
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
)
124 isl_schedule_constraints
*sc
;
129 ctx
= isl_union_set_get_ctx(domain
);
130 sc
= isl_schedule_constraints_alloc(ctx
);
135 return isl_schedule_constraints_init(sc
);
137 isl_union_set_free(domain
);
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
)
150 isl_union_set_free(sc
->domain
);
155 isl_schedule_constraints_free(sc
);
156 isl_union_set_free(domain
);
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
)
168 isl_set_free(sc
->context
);
169 sc
->context
= context
;
173 isl_schedule_constraints_free(sc
);
174 isl_set_free(context
);
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
)
187 isl_union_map_free(sc
->constraint
[type
]);
188 sc
->constraint
[type
] = c
;
192 isl_schedule_constraints_free(sc
);
193 isl_union_map_free(c
);
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
,
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"
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
,
240 __isl_null isl_schedule_constraints
*isl_schedule_constraints_free(
241 __isl_take isl_schedule_constraints
*sc
)
243 enum isl_edge_type i
;
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
]);
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
)
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
)
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
)
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
)
347 c
= isl_union_map_union(sc
->constraint
[type
], c
);
348 sc
->constraint
[type
] = c
;
350 return isl_schedule_constraints_free(sc
);
354 isl_schedule_constraints_free(sc
);
355 isl_union_map_free(c
);
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
)
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
);
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
)
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
));
415 t
= apply_factor_domain(t
, umap
);
416 c
= isl_union_map_union(c
, t
);
420 /* Apply "umap" to the domain of the schedule constraints "sc".
422 * The two sides of the various schedule constraints are adjusted
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
;
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
])
441 sc
->domain
= isl_union_set_apply(sc
->domain
, umap
);
443 return isl_schedule_constraints_free(sc
);
447 isl_schedule_constraints_free(sc
);
448 isl_union_map_free(umap
);
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.
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
,
469 /* Textual representations of the YAML keys for an isl_schedule_constraints
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",
484 #include "print_yaml_field_templ.c"
487 #define BASE union_set
488 #include "print_yaml_field_templ.c"
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
)
504 empty
= isl_union_map_plain_is_empty(sc
->constraint
[type
]);
506 return isl_printer_free(p
);
510 p
= print_yaml_field_union_map(p
, key_str
[type
], sc
->constraint
[type
]);
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
521 __isl_give isl_printer
*isl_printer_print_schedule_constraints(
522 __isl_take isl_printer
*p
, __isl_keep isl_schedule_constraints
*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
],
532 universe
= isl_set_plain_is_universe(sc
->context
);
534 return isl_printer_free(p
);
536 p
= print_yaml_field_set(p
, key_str
[isl_sc_key_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
);
549 #define BASE schedule_constraints
550 #include <print_templ_yaml.c>
553 #define KEY enum isl_sc_key
555 #define KEY_ERROR isl_sc_key_error
557 #define KEY_END isl_sc_key_end
558 #include "extract_key.c"
562 #include "read_in_string_templ.c"
565 #define BASE union_set
566 #include "read_in_string_templ.c"
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(
584 isl_schedule_constraints
*sc
;
588 if (isl_stream_yaml_read_start_mapping(s
))
591 ctx
= isl_stream_get_ctx(s
);
592 sc
= isl_schedule_constraints_alloc(ctx
);
593 while ((more
= isl_stream_yaml_next(s
)) > 0) {
596 isl_union_set
*domain
;
597 isl_union_map
*constraints
;
600 if (isl_stream_yaml_next(s
) < 0)
601 return isl_schedule_constraints_free(sc
);
604 case isl_sc_key_error
:
605 return isl_schedule_constraints_free(sc
);
606 case isl_sc_key_domain
:
608 domain
= read_union_set(s
);
609 sc
= isl_schedule_constraints_set_domain(sc
, domain
);
613 case isl_sc_key_context
:
614 context
= read_set(s
);
615 sc
= isl_schedule_constraints_set_context(sc
, context
);
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
);
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
);
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
);
658 sc
= isl_stream_read_schedule_constraints(s
);
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
);
675 sc
= isl_stream_read_schedule_constraints(s
);
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
)
687 enum isl_edge_type i
;
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
);
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
)
717 isl_size n_basic_map
;
719 n_basic_map
= isl_map_n_basic_map(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
;
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)
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
;
752 for (i
= isl_edge_first
; i
<= isl_edge_last
; ++i
) {
755 n_i
= isl_union_map_n_map(sc
->constraint
[i
]);
757 return isl_size_error
;