2 * Copyright 2011 INRIA Saclay
3 * Copyright 2012-2014 Ecole Normale Superieure
5 * Use of this software is governed by the MIT license
7 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
8 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
10 * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
14 #include <isl_aff_private.h>
18 #include <isl_schedule_private.h>
19 #include <isl_band_private.h>
21 __isl_null isl_schedule
*isl_schedule_free(__isl_take isl_schedule
*sched
)
30 for (i
= 0; i
< sched
->n
; ++i
) {
31 isl_multi_aff_free(sched
->node
[i
].sched
);
32 free(sched
->node
[i
].band_end
);
33 free(sched
->node
[i
].band_id
);
34 free(sched
->node
[i
].coincident
);
36 isl_space_free(sched
->dim
);
37 isl_band_list_free(sched
->band_forest
);
42 isl_ctx
*isl_schedule_get_ctx(__isl_keep isl_schedule
*schedule
)
44 return schedule
? isl_space_get_ctx(schedule
->dim
) : NULL
;
47 /* Set max_out to the maximal number of output dimensions over
50 static int update_max_out(__isl_take isl_map
*map
, void *user
)
53 int n_out
= isl_map_dim(map
, isl_dim_out
);
62 /* Internal data structure for map_pad_range.
64 * "max_out" is the maximal schedule dimension.
65 * "res" collects the results.
67 struct isl_pad_schedule_map_data
{
72 /* Pad the range of the given map with zeros to data->max_out and
73 * then add the result to data->res.
75 static int map_pad_range(__isl_take isl_map
*map
, void *user
)
77 struct isl_pad_schedule_map_data
*data
= user
;
79 int n_out
= isl_map_dim(map
, isl_dim_out
);
81 map
= isl_map_add_dims(map
, isl_dim_out
, data
->max_out
- n_out
);
82 for (i
= n_out
; i
< data
->max_out
; ++i
)
83 map
= isl_map_fix_si(map
, isl_dim_out
, i
, 0);
85 data
->res
= isl_union_map_add_map(data
->res
, map
);
92 /* Pad the ranges of the maps in the union map with zeros such they all have
95 static __isl_give isl_union_map
*pad_schedule_map(
96 __isl_take isl_union_map
*umap
)
98 struct isl_pad_schedule_map_data data
;
102 if (isl_union_map_n_map(umap
) <= 1)
106 if (isl_union_map_foreach_map(umap
, &update_max_out
, &data
.max_out
) < 0)
107 return isl_union_map_free(umap
);
109 data
.res
= isl_union_map_empty(isl_union_map_get_space(umap
));
110 if (isl_union_map_foreach_map(umap
, &map_pad_range
, &data
) < 0)
111 data
.res
= isl_union_map_free(data
.res
);
113 isl_union_map_free(umap
);
117 /* Return an isl_union_map of the schedule. If we have already constructed
118 * a band forest, then this band forest may have been modified so we need
119 * to extract the isl_union_map from the forest rather than from
120 * the originally computed schedule. This reconstructed schedule map
121 * then needs to be padded with zeros to unify the schedule space
122 * since the result of isl_band_list_get_suffix_schedule may not have
123 * a unified schedule space.
125 __isl_give isl_union_map
*isl_schedule_get_map(__isl_keep isl_schedule
*sched
)
133 if (sched
->band_forest
) {
134 umap
= isl_band_list_get_suffix_schedule(sched
->band_forest
);
135 return pad_schedule_map(umap
);
138 umap
= isl_union_map_empty(isl_space_copy(sched
->dim
));
139 for (i
= 0; i
< sched
->n
; ++i
) {
142 ma
= isl_multi_aff_copy(sched
->node
[i
].sched
);
143 umap
= isl_union_map_add_map(umap
, isl_map_from_multi_aff(ma
));
149 static __isl_give isl_band_list
*construct_band_list(
150 __isl_keep isl_schedule
*schedule
, __isl_keep isl_band
*parent
,
151 int band_nr
, int *parent_active
, int n_active
);
153 /* Construct an isl_band structure for the band in the given schedule
154 * with sequence number band_nr for the n_active nodes marked by active.
155 * If the nodes don't have a band with the given sequence number,
156 * then a band without members is created.
158 * Because of the way the schedule is constructed, we know that
159 * the position of the band inside the schedule of a node is the same
160 * for all active nodes.
162 * The partial schedule for the band is created before the children
163 * are created to that construct_band_list can refer to the partial
164 * schedule of the parent.
166 static __isl_give isl_band
*construct_band(__isl_keep isl_schedule
*schedule
,
167 __isl_keep isl_band
*parent
,
168 int band_nr
, int *active
, int n_active
)
171 isl_ctx
*ctx
= isl_schedule_get_ctx(schedule
);
175 band
= isl_band_alloc(ctx
);
179 band
->schedule
= schedule
;
180 band
->parent
= parent
;
182 for (i
= 0; i
< schedule
->n
; ++i
)
186 if (i
>= schedule
->n
)
187 isl_die(ctx
, isl_error_internal
,
188 "band without active statements", goto error
);
190 start
= band_nr
? schedule
->node
[i
].band_end
[band_nr
- 1] : 0;
191 end
= band_nr
< schedule
->node
[i
].n_band
?
192 schedule
->node
[i
].band_end
[band_nr
] : start
;
193 band
->n
= end
- start
;
195 band
->coincident
= isl_alloc_array(ctx
, int, band
->n
);
196 if (band
->n
&& !band
->coincident
)
199 for (j
= 0; j
< band
->n
; ++j
)
200 band
->coincident
[j
] = schedule
->node
[i
].coincident
[start
+ j
];
202 band
->pma
= isl_union_pw_multi_aff_empty(isl_space_copy(schedule
->dim
));
203 for (i
= 0; i
< schedule
->n
; ++i
) {
205 isl_pw_multi_aff
*pma
;
211 ma
= isl_multi_aff_copy(schedule
->node
[i
].sched
);
212 n_out
= isl_multi_aff_dim(ma
, isl_dim_out
);
213 ma
= isl_multi_aff_drop_dims(ma
, isl_dim_out
, end
, n_out
- end
);
214 ma
= isl_multi_aff_drop_dims(ma
, isl_dim_out
, 0, start
);
215 pma
= isl_pw_multi_aff_from_multi_aff(ma
);
216 band
->pma
= isl_union_pw_multi_aff_add_pw_multi_aff(band
->pma
,
222 for (i
= 0; i
< schedule
->n
; ++i
)
223 if (active
[i
] && schedule
->node
[i
].n_band
> band_nr
+ 1)
226 if (i
< schedule
->n
) {
227 band
->children
= construct_band_list(schedule
, band
,
228 band_nr
+ 1, active
, n_active
);
239 /* Internal data structure used inside cmp_band and pw_multi_aff_extract_int.
241 * r is set to a negative value if anything goes wrong.
243 * c1 stores the result of extract_int.
244 * c2 is a temporary value used inside cmp_band_in_ancestor.
245 * t is a temporary value used inside extract_int.
247 * first and equal are used inside extract_int.
248 * first is set if we are looking at the first isl_multi_aff inside
249 * the isl_union_pw_multi_aff.
250 * equal is set if all the isl_multi_affs have been equal so far.
252 struct isl_cmp_band_data
{
263 /* Check if "ma" assigns a constant value.
264 * Note that this function is only called on isl_multi_affs
265 * with a single output dimension.
267 * If "ma" assigns a constant value then we compare it to data->c1
268 * or assign it to data->c1 if this is the first isl_multi_aff we consider.
269 * If "ma" does not assign a constant value or if it assigns a value
270 * that is different from data->c1, then we set data->equal to zero
271 * and terminate the check.
273 static int multi_aff_extract_int(__isl_take isl_set
*set
,
274 __isl_take isl_multi_aff
*ma
, void *user
)
277 struct isl_cmp_band_data
*data
= user
;
279 aff
= isl_multi_aff_get_aff(ma
, 0);
280 data
->r
= isl_aff_is_cst(aff
);
281 if (data
->r
>= 0 && data
->r
) {
282 isl_aff_get_constant(aff
, &data
->t
);
284 isl_int_set(data
->c1
, data
->t
);
286 } else if (!isl_int_eq(data
->c1
, data
->t
))
288 } else if (data
->r
>= 0 && !data
->r
)
293 isl_multi_aff_free(ma
);
302 /* This function is called for each isl_pw_multi_aff in
303 * the isl_union_pw_multi_aff checked by extract_int.
304 * Check all the isl_multi_affs inside "pma".
306 static int pw_multi_aff_extract_int(__isl_take isl_pw_multi_aff
*pma
,
311 r
= isl_pw_multi_aff_foreach_piece(pma
, &multi_aff_extract_int
, user
);
312 isl_pw_multi_aff_free(pma
);
317 /* Check if "upma" assigns a single constant value to its domain.
318 * If so, return 1 and store the result in data->c1.
321 * A negative return value from isl_union_pw_multi_aff_foreach_pw_multi_aff
322 * means that either an error occurred or that we have broken off the check
323 * because we already know the result is going to be negative.
324 * In the latter case, data->equal is set to zero.
326 static int extract_int(__isl_keep isl_union_pw_multi_aff
*upma
,
327 struct isl_cmp_band_data
*data
)
332 if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma
,
333 &pw_multi_aff_extract_int
, data
) < 0) {
339 return !data
->first
&& data
->equal
;
342 /* Compare "b1" and "b2" based on the parent schedule of their ancestor
345 * If the parent of "ancestor" also has a single member, then we
346 * first try to compare the two band based on the partial schedule
349 * Otherwise, or if the result is inconclusive, we look at the partial schedule
350 * of "ancestor" itself.
351 * In particular, we specialize the parent schedule based
352 * on the domains of the child schedules, check if both assign
353 * a single constant value and, if so, compare the two constant values.
354 * If the specialized parent schedules do not assign a constant value,
355 * then they cannot be used to order the two bands and so in this case
358 static int cmp_band_in_ancestor(__isl_keep isl_band
*b1
,
359 __isl_keep isl_band
*b2
, struct isl_cmp_band_data
*data
,
360 __isl_keep isl_band
*ancestor
)
362 isl_union_pw_multi_aff
*upma
;
363 isl_union_set
*domain
;
369 if (ancestor
->parent
&& ancestor
->parent
->n
== 1) {
370 r
= cmp_band_in_ancestor(b1
, b2
, data
, ancestor
->parent
);
377 upma
= isl_union_pw_multi_aff_copy(b1
->pma
);
378 domain
= isl_union_pw_multi_aff_domain(upma
);
379 upma
= isl_union_pw_multi_aff_copy(ancestor
->pma
);
380 upma
= isl_union_pw_multi_aff_intersect_domain(upma
, domain
);
381 r
= extract_int(upma
, data
);
382 isl_union_pw_multi_aff_free(upma
);
389 isl_int_set(data
->c2
, data
->c1
);
391 upma
= isl_union_pw_multi_aff_copy(b2
->pma
);
392 domain
= isl_union_pw_multi_aff_domain(upma
);
393 upma
= isl_union_pw_multi_aff_copy(ancestor
->pma
);
394 upma
= isl_union_pw_multi_aff_intersect_domain(upma
, domain
);
395 r
= extract_int(upma
, data
);
396 isl_union_pw_multi_aff_free(upma
);
403 return isl_int_cmp(data
->c2
, data
->c1
);
406 /* Compare "a" and "b" based on the parent schedule of their parent.
408 static int cmp_band(const void *a
, const void *b
, void *user
)
410 isl_band
*b1
= *(isl_band
* const *) a
;
411 isl_band
*b2
= *(isl_band
* const *) b
;
412 struct isl_cmp_band_data
*data
= user
;
414 return cmp_band_in_ancestor(b1
, b2
, data
, b1
->parent
);
417 /* Sort the elements in "list" based on the partial schedules of its parent
418 * (and ancestors). In particular if the parent assigns constant values
419 * to the domains of the bands in "list", then the elements are sorted
420 * according to that order.
421 * This order should be a more "natural" order for the user, but otherwise
422 * shouldn't have any effect.
423 * If we would be constructing an isl_band forest directly in
424 * isl_schedule_constraints_compute_schedule then there wouldn't be any need
425 * for a reordering, since the children would be added to the list
426 * in their natural order automatically.
428 * If there is only one element in the list, then there is no need to sort
430 * If the partial schedule of the parent has more than one member
431 * (or if there is no parent), then it's
432 * defnitely not assigning constant values to the different children in
433 * the list and so we wouldn't be able to use it to sort the list.
435 static __isl_give isl_band_list
*sort_band_list(__isl_take isl_band_list
*list
,
436 __isl_keep isl_band
*parent
)
438 struct isl_cmp_band_data data
;
444 if (!parent
|| parent
->n
!= 1)
448 isl_int_init(data
.c1
);
449 isl_int_init(data
.c2
);
450 isl_int_init(data
.t
);
451 isl_sort(list
->p
, list
->n
, sizeof(list
->p
[0]), &cmp_band
, &data
);
453 list
= isl_band_list_free(list
);
454 isl_int_clear(data
.c1
);
455 isl_int_clear(data
.c2
);
456 isl_int_clear(data
.t
);
461 /* Construct a list of bands that start at the same position (with
462 * sequence number band_nr) in the schedules of the nodes that
463 * were active in the parent band.
465 * A separate isl_band structure is created for each band_id
466 * and for each node that does not have a band with sequence
467 * number band_nr. In the latter case, a band without members
469 * This ensures that if a band has any children, then each node
470 * that was active in the band is active in exactly one of the children.
472 static __isl_give isl_band_list
*construct_band_list(
473 __isl_keep isl_schedule
*schedule
, __isl_keep isl_band
*parent
,
474 int band_nr
, int *parent_active
, int n_active
)
477 isl_ctx
*ctx
= isl_schedule_get_ctx(schedule
);
483 for (i
= 0; i
< n_active
; ++i
) {
484 for (j
= 0; j
< schedule
->n
; ++j
) {
485 if (!parent_active
[j
])
487 if (schedule
->node
[j
].n_band
<= band_nr
)
489 if (schedule
->node
[j
].band_id
[band_nr
] == i
) {
495 for (j
= 0; j
< schedule
->n
; ++j
)
496 if (schedule
->node
[j
].n_band
<= band_nr
)
501 list
= isl_band_list_alloc(ctx
, n_band
);
502 band
= construct_band(schedule
, parent
, band_nr
,
503 parent_active
, n_active
);
504 return isl_band_list_add(list
, band
);
507 active
= isl_alloc_array(ctx
, int, schedule
->n
);
508 if (schedule
->n
&& !active
)
511 list
= isl_band_list_alloc(ctx
, n_band
);
513 for (i
= 0; i
< n_active
; ++i
) {
517 for (j
= 0; j
< schedule
->n
; ++j
) {
518 active
[j
] = parent_active
[j
] &&
519 schedule
->node
[j
].n_band
> band_nr
&&
520 schedule
->node
[j
].band_id
[band_nr
] == i
;
527 band
= construct_band(schedule
, parent
, band_nr
, active
, n
);
529 list
= isl_band_list_add(list
, band
);
531 for (i
= 0; i
< schedule
->n
; ++i
) {
533 if (!parent_active
[i
])
535 if (schedule
->node
[i
].n_band
> band_nr
)
537 for (j
= 0; j
< schedule
->n
; ++j
)
539 band
= construct_band(schedule
, parent
, band_nr
, active
, 1);
540 list
= isl_band_list_add(list
, band
);
545 list
= sort_band_list(list
, parent
);
550 /* Construct a band forest representation of the schedule and
551 * return the list of roots.
553 static __isl_give isl_band_list
*construct_forest(
554 __isl_keep isl_schedule
*schedule
)
557 isl_ctx
*ctx
= isl_schedule_get_ctx(schedule
);
558 isl_band_list
*forest
;
561 active
= isl_alloc_array(ctx
, int, schedule
->n
);
562 if (schedule
->n
&& !active
)
565 for (i
= 0; i
< schedule
->n
; ++i
)
568 forest
= construct_band_list(schedule
, NULL
, 0, active
, schedule
->n
);
575 /* Return the roots of a band forest representation of the schedule.
577 __isl_give isl_band_list
*isl_schedule_get_band_forest(
578 __isl_keep isl_schedule
*schedule
)
582 if (!schedule
->band_forest
)
583 schedule
->band_forest
= construct_forest(schedule
);
584 return isl_band_list_dup(schedule
->band_forest
);
587 /* Call "fn" on each band in the schedule in depth-first post-order.
589 int isl_schedule_foreach_band(__isl_keep isl_schedule
*sched
,
590 int (*fn
)(__isl_keep isl_band
*band
, void *user
), void *user
)
593 isl_band_list
*forest
;
598 forest
= isl_schedule_get_band_forest(sched
);
599 r
= isl_band_list_foreach_band(forest
, fn
, user
);
600 isl_band_list_free(forest
);
605 static __isl_give isl_printer
*print_band_list(__isl_take isl_printer
*p
,
606 __isl_keep isl_band_list
*list
);
608 static __isl_give isl_printer
*print_band(__isl_take isl_printer
*p
,
609 __isl_keep isl_band
*band
)
611 isl_band_list
*children
;
613 p
= isl_printer_start_line(p
);
614 p
= isl_printer_print_union_pw_multi_aff(p
, band
->pma
);
615 p
= isl_printer_end_line(p
);
617 if (!isl_band_has_children(band
))
620 children
= isl_band_get_children(band
);
622 p
= isl_printer_indent(p
, 4);
623 p
= print_band_list(p
, children
);
624 p
= isl_printer_indent(p
, -4);
626 isl_band_list_free(children
);
631 static __isl_give isl_printer
*print_band_list(__isl_take isl_printer
*p
,
632 __isl_keep isl_band_list
*list
)
636 n
= isl_band_list_n_band(list
);
637 for (i
= 0; i
< n
; ++i
) {
639 band
= isl_band_list_get_band(list
, i
);
640 p
= print_band(p
, band
);
647 __isl_give isl_printer
*isl_printer_print_schedule(__isl_take isl_printer
*p
,
648 __isl_keep isl_schedule
*schedule
)
650 isl_band_list
*forest
;
652 forest
= isl_schedule_get_band_forest(schedule
);
654 p
= print_band_list(p
, forest
);
656 isl_band_list_free(forest
);
661 void isl_schedule_dump(__isl_keep isl_schedule
*schedule
)
663 isl_printer
*printer
;
668 printer
= isl_printer_to_file(isl_schedule_get_ctx(schedule
), stderr
);
669 printer
= isl_printer_print_schedule(printer
, schedule
);
671 isl_printer_free(printer
);