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",
482 /* Print a key, value pair for the edge of type "type" in "sc" to "p".
484 * If the edge relation is empty, then it is not printed since
485 * an empty relation is the default value.
487 static __isl_give isl_printer
*print_constraint(__isl_take isl_printer
*p
,
488 __isl_keep isl_schedule_constraints
*sc
, enum isl_edge_type type
)
492 empty
= isl_union_map_plain_is_empty(sc
->constraint
[type
]);
494 return isl_printer_free(p
);
498 p
= isl_printer_print_str(p
, key_str
[type
]);
499 p
= isl_printer_yaml_next(p
);
500 p
= isl_printer_print_union_map(p
, sc
->constraint
[type
]);
501 p
= isl_printer_yaml_next(p
);
508 * In particular, print the isl_schedule_constraints object as a YAML document.
509 * Fields with values that are (obviously) equal to their default values
512 __isl_give isl_printer
*isl_printer_print_schedule_constraints(
513 __isl_take isl_printer
*p
, __isl_keep isl_schedule_constraints
*sc
)
518 return isl_printer_free(p
);
520 p
= isl_printer_yaml_start_mapping(p
);
521 p
= isl_printer_print_str(p
, key_str
[isl_sc_key_domain
]);
522 p
= isl_printer_yaml_next(p
);
523 p
= isl_printer_print_union_set(p
, sc
->domain
);
524 p
= isl_printer_yaml_next(p
);
525 universe
= isl_set_plain_is_universe(sc
->context
);
527 return isl_printer_free(p
);
529 p
= isl_printer_print_str(p
, key_str
[isl_sc_key_context
]);
530 p
= isl_printer_yaml_next(p
);
531 p
= isl_printer_print_set(p
, sc
->context
);
532 p
= isl_printer_yaml_next(p
);
534 p
= print_constraint(p
, sc
, isl_edge_validity
);
535 p
= print_constraint(p
, sc
, isl_edge_proximity
);
536 p
= print_constraint(p
, sc
, isl_edge_coincidence
);
537 p
= print_constraint(p
, sc
, isl_edge_condition
);
538 p
= print_constraint(p
, sc
, isl_edge_conditional_validity
);
539 p
= isl_printer_yaml_end_mapping(p
);
545 #define BASE schedule_constraints
546 #include <print_templ_yaml.c>
549 #define KEY enum isl_sc_key
551 #define KEY_ERROR isl_sc_key_error
553 #define KEY_END isl_sc_key_end
554 #include "extract_key.c"
558 #include "read_in_string_templ.c"
561 #define BASE union_set
562 #include "read_in_string_templ.c"
565 #define BASE union_map
566 #include "read_in_string_templ.c"
568 /* Read an isl_schedule_constraints object from "s".
570 * Start off with an empty (invalid) isl_schedule_constraints object and
571 * then fill up the fields based on the input.
572 * The input needs to contain at least a description of the domain.
573 * The other fields are set to defaults by isl_schedule_constraints_init
574 * if they are not specified in the input.
576 __isl_give isl_schedule_constraints
*isl_stream_read_schedule_constraints(
580 isl_schedule_constraints
*sc
;
584 if (isl_stream_yaml_read_start_mapping(s
))
587 ctx
= isl_stream_get_ctx(s
);
588 sc
= isl_schedule_constraints_alloc(ctx
);
589 while ((more
= isl_stream_yaml_next(s
)) > 0) {
592 isl_union_set
*domain
;
593 isl_union_map
*constraints
;
596 if (isl_stream_yaml_next(s
) < 0)
597 return isl_schedule_constraints_free(sc
);
600 case isl_sc_key_error
:
601 return isl_schedule_constraints_free(sc
);
602 case isl_sc_key_domain
:
604 domain
= read_union_set(s
);
605 sc
= isl_schedule_constraints_set_domain(sc
, domain
);
609 case isl_sc_key_context
:
610 context
= read_set(s
);
611 sc
= isl_schedule_constraints_set_context(sc
, context
);
615 case isl_sc_key_validity
:
616 case isl_sc_key_coincidence
:
617 case isl_sc_key_condition
:
618 case isl_sc_key_conditional_validity
:
619 case isl_sc_key_proximity
:
620 constraints
= read_union_map(s
);
621 sc
= isl_schedule_constraints_set(sc
, key
, constraints
);
628 return isl_schedule_constraints_free(sc
);
630 if (isl_stream_yaml_read_end_mapping(s
) < 0) {
631 isl_stream_error(s
, NULL
, "unexpected extra elements");
632 return isl_schedule_constraints_free(sc
);
636 isl_stream_error(s
, NULL
, "no domain specified");
637 return isl_schedule_constraints_free(sc
);
640 return isl_schedule_constraints_init(sc
);
643 /* Read an isl_schedule_constraints object from the file "input".
645 __isl_give isl_schedule_constraints
*isl_schedule_constraints_read_from_file(
646 isl_ctx
*ctx
, FILE *input
)
648 struct isl_stream
*s
;
649 isl_schedule_constraints
*sc
;
651 s
= isl_stream_new_file(ctx
, input
);
654 sc
= isl_stream_read_schedule_constraints(s
);
660 /* Read an isl_schedule_constraints object from the string "str".
662 __isl_give isl_schedule_constraints
*isl_schedule_constraints_read_from_str(
663 isl_ctx
*ctx
, const char *str
)
665 struct isl_stream
*s
;
666 isl_schedule_constraints
*sc
;
668 s
= isl_stream_new_str(ctx
, str
);
671 sc
= isl_stream_read_schedule_constraints(s
);
677 /* Align the parameters of the fields of "sc".
679 __isl_give isl_schedule_constraints
*
680 isl_schedule_constraints_align_params(__isl_take isl_schedule_constraints
*sc
)
683 enum isl_edge_type i
;
688 space
= isl_union_set_get_space(sc
->domain
);
689 space
= isl_space_align_params(space
, isl_set_get_space(sc
->context
));
690 for (i
= isl_edge_first
; i
<= isl_edge_last
; ++i
)
691 space
= isl_space_align_params(space
,
692 isl_union_map_get_space(sc
->constraint
[i
]));
694 for (i
= isl_edge_first
; i
<= isl_edge_last
; ++i
) {
695 sc
->constraint
[i
] = isl_union_map_align_params(
696 sc
->constraint
[i
], isl_space_copy(space
));
697 if (!sc
->constraint
[i
])
698 space
= isl_space_free(space
);
700 sc
->context
= isl_set_align_params(sc
->context
, isl_space_copy(space
));
701 sc
->domain
= isl_union_set_align_params(sc
->domain
, space
);
702 if (!sc
->context
|| !sc
->domain
)
703 return isl_schedule_constraints_free(sc
);
708 /* Add the number of basic maps in "map" to *n.
710 static isl_stat
add_n_basic_map(__isl_take isl_map
*map
, void *user
)
714 *n
+= isl_map_n_basic_map(map
);
720 /* Return the total number of isl_basic_maps in the constraints of "sc".
721 * Return -1 on error.
723 int isl_schedule_constraints_n_basic_map(
724 __isl_keep isl_schedule_constraints
*sc
)
726 enum isl_edge_type i
;
731 for (i
= isl_edge_first
; i
<= isl_edge_last
; ++i
)
732 if (isl_union_map_foreach_map(sc
->constraint
[i
],
733 &add_n_basic_map
, &n
) < 0)
739 /* Return the total number of isl_maps in the constraints of "sc".
741 int isl_schedule_constraints_n_map(__isl_keep isl_schedule_constraints
*sc
)
743 enum isl_edge_type i
;
746 for (i
= isl_edge_first
; i
<= isl_edge_last
; ++i
)
747 n
+= isl_union_map_n_map(sc
->constraint
[i
]);