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 * 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.
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
)
189 c
= isl_union_map_detect_equalities(c
);
193 isl_union_map_free(sc
->constraint
[type
]);
194 sc
->constraint
[type
] = c
;
198 isl_schedule_constraints_free(sc
);
199 isl_union_map_free(c
);
203 /* Replace the validity constraints of "sc" by "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
)
209 return isl_schedule_constraints_set(sc
, isl_edge_validity
, validity
);
212 /* Replace the coincidence constraints of "sc" by "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
)
218 return isl_schedule_constraints_set(sc
, isl_edge_coincidence
,
222 /* Replace the proximity constraints of "sc" by "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
)
228 return isl_schedule_constraints_set(sc
, isl_edge_proximity
, proximity
);
231 /* Replace the conditional validity constraints of "sc" by "condition"
234 __isl_give isl_schedule_constraints
*
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
)
240 sc
= isl_schedule_constraints_set(sc
, isl_edge_condition
, condition
);
241 sc
= isl_schedule_constraints_set(sc
, isl_edge_conditional_validity
,
246 __isl_null isl_schedule_constraints
*isl_schedule_constraints_free(
247 __isl_take isl_schedule_constraints
*sc
)
249 enum isl_edge_type i
;
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
]);
264 isl_ctx
*isl_schedule_constraints_get_ctx(
265 __isl_keep isl_schedule_constraints
*sc
)
267 return sc
? isl_union_set_get_ctx(sc
->domain
) : NULL
;
270 /* Return the domain of "sc".
272 __isl_give isl_union_set
*isl_schedule_constraints_get_domain(
273 __isl_keep isl_schedule_constraints
*sc
)
278 return isl_union_set_copy(sc
->domain
);
281 /* Return the context of "sc".
283 __isl_give isl_set
*isl_schedule_constraints_get_context(
284 __isl_keep isl_schedule_constraints
*sc
)
289 return isl_set_copy(sc
->context
);
292 /* Return the constraints of type "type" in "sc".
294 __isl_give isl_union_map
*isl_schedule_constraints_get(
295 __isl_keep isl_schedule_constraints
*sc
, enum isl_edge_type type
)
300 return isl_union_map_copy(sc
->constraint
[type
]);
303 /* Return the validity constraints of "sc".
305 __isl_give isl_union_map
*isl_schedule_constraints_get_validity(
306 __isl_keep isl_schedule_constraints
*sc
)
308 return isl_schedule_constraints_get(sc
, isl_edge_validity
);
311 /* Return the coincidence constraints of "sc".
313 __isl_give isl_union_map
*isl_schedule_constraints_get_coincidence(
314 __isl_keep isl_schedule_constraints
*sc
)
316 return isl_schedule_constraints_get(sc
, isl_edge_coincidence
);
319 /* Return the proximity constraints of "sc".
321 __isl_give isl_union_map
*isl_schedule_constraints_get_proximity(
322 __isl_keep isl_schedule_constraints
*sc
)
324 return isl_schedule_constraints_get(sc
, isl_edge_proximity
);
327 /* Return the conditional validity constraints of "sc".
329 __isl_give isl_union_map
*isl_schedule_constraints_get_conditional_validity(
330 __isl_keep isl_schedule_constraints
*sc
)
332 return isl_schedule_constraints_get(sc
, isl_edge_conditional_validity
);
335 /* Return the conditions for the conditional validity constraints of "sc".
337 __isl_give isl_union_map
*
338 isl_schedule_constraints_get_conditional_validity_condition(
339 __isl_keep isl_schedule_constraints
*sc
)
341 return isl_schedule_constraints_get(sc
, isl_edge_condition
);
344 /* Add "c" to the constraints of type "type" in "sc".
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
)
353 c
= isl_union_map_union(sc
->constraint
[type
], c
);
354 sc
->constraint
[type
] = c
;
356 return isl_schedule_constraints_free(sc
);
360 isl_schedule_constraints_free(sc
);
361 isl_union_map_free(c
);
365 /* Can a schedule constraint of type "type" be tagged?
367 static int may_be_tagged(enum isl_edge_type type
)
369 if (type
== isl_edge_condition
|| type
== isl_edge_conditional_validity
)
374 /* Apply "umap" to the domains of the wrapped relations
375 * inside the domain and range of "c".
377 * That is, for each map of the form
379 * [D -> S] -> [E -> T]
381 * in "c", apply "umap" to D and E.
383 * D is exposed by currying the relation to
385 * D -> [S -> [E -> T]]
387 * E is exposed by doing the same to the inverse of "c".
389 static __isl_give isl_union_map
*apply_factor_domain(
390 __isl_take isl_union_map
*c
, __isl_keep isl_union_map
*umap
)
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
);
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
);
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".
410 static __isl_give isl_union_map
*apply(__isl_take isl_union_map
*c
,
411 __isl_keep isl_union_map
*umap
, int 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
));
421 t
= apply_factor_domain(t
, umap
);
422 c
= isl_union_map_union(c
, t
);
426 /* Apply "umap" to the domain of the schedule constraints "sc".
428 * The two sides of the various schedule constraints are adjusted
431 __isl_give isl_schedule_constraints
*isl_schedule_constraints_apply(
432 __isl_take isl_schedule_constraints
*sc
,
433 __isl_take isl_union_map
*umap
)
435 enum isl_edge_type i
;
440 for (i
= isl_edge_first
; i
<= isl_edge_last
; ++i
) {
441 int tag
= may_be_tagged(i
);
443 sc
->constraint
[i
] = apply(sc
->constraint
[i
], umap
, tag
);
444 if (!sc
->constraint
[i
])
447 sc
->domain
= isl_union_set_apply(sc
->domain
, umap
);
449 return isl_schedule_constraints_free(sc
);
453 isl_schedule_constraints_free(sc
);
454 isl_union_map_free(umap
);
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.
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
,
475 /* Textual representations of the YAML keys for an isl_schedule_constraints
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",
490 #include "print_yaml_field_templ.c"
493 #define BASE union_set
494 #include "print_yaml_field_templ.c"
497 #define BASE union_map
498 #include "print_yaml_field_templ.c"
500 /* Print a key, value pair for the edge of type "type" in "sc" to "p".
502 * If the edge relation is empty, then it is not printed since
503 * an empty relation is the default value.
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
)
510 empty
= isl_union_map_plain_is_empty(sc
->constraint
[type
]);
512 return isl_printer_free(p
);
516 p
= print_yaml_field_union_map(p
, key_str
[type
], sc
->constraint
[type
]);
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
527 __isl_give isl_printer
*isl_printer_print_schedule_constraints(
528 __isl_take isl_printer
*p
, __isl_keep isl_schedule_constraints
*sc
)
533 return isl_printer_free(p
);
535 p
= isl_printer_yaml_start_mapping(p
);
536 p
= print_yaml_field_union_set(p
, key_str
[isl_sc_key_domain
],
538 universe
= isl_set_plain_is_universe(sc
->context
);
540 return isl_printer_free(p
);
542 p
= print_yaml_field_set(p
, key_str
[isl_sc_key_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
);
555 #define BASE schedule_constraints
556 #include <print_templ_yaml.c>
559 #define KEY enum isl_sc_key
561 #define KEY_ERROR isl_sc_key_error
563 #define KEY_END isl_sc_key_end
564 #include "extract_key.c"
568 #include "read_in_string_templ.c"
571 #define BASE union_set
572 #include "read_in_string_templ.c"
575 #define BASE union_map
576 #include "read_in_string_templ.c"
578 /* Read an isl_schedule_constraints object from "s".
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.
586 __isl_give isl_schedule_constraints
*isl_stream_read_schedule_constraints(
590 isl_schedule_constraints
*sc
;
594 if (isl_stream_yaml_read_start_mapping(s
))
597 ctx
= isl_stream_get_ctx(s
);
598 sc
= isl_schedule_constraints_alloc(ctx
);
599 while ((more
= isl_stream_yaml_next(s
)) > 0) {
602 isl_union_set
*domain
;
603 isl_union_map
*constraints
;
606 if (isl_stream_yaml_next(s
) < 0)
607 return isl_schedule_constraints_free(sc
);
610 case isl_sc_key_error
:
611 return isl_schedule_constraints_free(sc
);
612 case isl_sc_key_domain
:
614 domain
= read_union_set(s
);
615 sc
= isl_schedule_constraints_set_domain(sc
, domain
);
619 case isl_sc_key_context
:
620 context
= read_set(s
);
621 sc
= isl_schedule_constraints_set_context(sc
, context
);
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
);
638 return isl_schedule_constraints_free(sc
);
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
);
646 isl_stream_error(s
, NULL
, "no domain specified");
647 return isl_schedule_constraints_free(sc
);
650 return isl_schedule_constraints_init(sc
);
653 /* Read an isl_schedule_constraints object from the file "input".
655 __isl_give isl_schedule_constraints
*isl_schedule_constraints_read_from_file(
656 isl_ctx
*ctx
, FILE *input
)
658 struct isl_stream
*s
;
659 isl_schedule_constraints
*sc
;
661 s
= isl_stream_new_file(ctx
, input
);
664 sc
= isl_stream_read_schedule_constraints(s
);
670 /* Read an isl_schedule_constraints object from the string "str".
672 __isl_give isl_schedule_constraints
*isl_schedule_constraints_read_from_str(
673 isl_ctx
*ctx
, const char *str
)
675 struct isl_stream
*s
;
676 isl_schedule_constraints
*sc
;
678 s
= isl_stream_new_str(ctx
, str
);
681 sc
= isl_stream_read_schedule_constraints(s
);
687 /* Align the parameters of the fields of "sc".
689 __isl_give isl_schedule_constraints
*
690 isl_schedule_constraints_align_params(__isl_take isl_schedule_constraints
*sc
)
693 enum isl_edge_type i
;
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
]));
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
);
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
);
718 /* Add the number of basic maps in "map" to *n.
720 static isl_stat
add_n_basic_map(__isl_take isl_map
*map
, void *user
)
723 isl_size n_basic_map
;
725 n_basic_map
= isl_map_n_basic_map(map
);
729 return n_basic_map
< 0 ? isl_stat_error
: isl_stat_ok
;
732 /* Return the total number of isl_basic_maps in the constraints of "sc".
733 * Return -1 on error.
735 int isl_schedule_constraints_n_basic_map(
736 __isl_keep isl_schedule_constraints
*sc
)
738 enum isl_edge_type i
;
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)
751 /* Return the total number of isl_maps in the constraints of "sc".
753 isl_size
isl_schedule_constraints_n_map(__isl_keep isl_schedule_constraints
*sc
)
755 enum isl_edge_type i
;
758 for (i
= isl_edge_first
; i
<= isl_edge_last
; ++i
) {
761 n_i
= isl_union_map_n_map(sc
->constraint
[i
]);
763 return isl_size_error
;