2 * Copyright 2011 INRIA Saclay
3 * Copyright 2012-2013 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
13 #include <isl/space.h>
14 #include <isl_band_private.h>
15 #include <isl_schedule_private.h>
20 #include <isl_list_templ.c>
22 isl_ctx
*isl_band_get_ctx(__isl_keep isl_band
*band
)
24 return band
? isl_union_pw_multi_aff_get_ctx(band
->pma
) : NULL
;
27 __isl_give isl_band
*isl_band_alloc(isl_ctx
*ctx
)
31 band
= isl_calloc_type(ctx
, isl_band
);
40 /* Create a duplicate of the given band. The duplicate refers
41 * to the same schedule and parent as the input, but does not
42 * increment their reference counts.
44 __isl_give isl_band
*isl_band_dup(__isl_keep isl_band
*band
)
53 ctx
= isl_band_get_ctx(band
);
54 dup
= isl_band_alloc(ctx
);
59 dup
->coincident
= isl_alloc_array(ctx
, int, band
->n
);
60 if (band
->n
&& !dup
->coincident
)
63 for (i
= 0; i
< band
->n
; ++i
)
64 dup
->coincident
[i
] = band
->coincident
[i
];
66 dup
->pma
= isl_union_pw_multi_aff_copy(band
->pma
);
67 dup
->schedule
= band
->schedule
;
68 dup
->parent
= band
->parent
;
79 /* We not only increment the reference count of the band,
80 * but also that of the schedule that contains this band.
81 * This ensures that the schedule won't disappear while there
82 * is still a reference to the band outside of the schedule.
83 * There is no need to increment the reference count of the parent
84 * band as the parent band is part of the same schedule.
86 __isl_give isl_band
*isl_band_copy(__isl_keep isl_band
*band
)
92 band
->schedule
->ref
++;
96 /* If this is not the last reference to the band (the one from within the
97 * schedule), then we also need to decrement the reference count of the
98 * containing schedule as it was incremented in isl_band_copy.
100 __isl_null isl_band
*isl_band_free(__isl_take isl_band
*band
)
105 if (--band
->ref
> 0) {
106 isl_schedule_free(band
->schedule
);
110 isl_union_pw_multi_aff_free(band
->pma
);
111 isl_band_list_free(band
->children
);
112 free(band
->coincident
);
118 int isl_band_has_children(__isl_keep isl_band
*band
)
123 return band
->children
!= NULL
;
126 __isl_give isl_band_list
*isl_band_get_children(
127 __isl_keep isl_band
*band
)
132 isl_die(isl_band_get_ctx(band
), isl_error_invalid
,
133 "band has no children", return NULL
);
134 return isl_band_list_dup(band
->children
);
137 int isl_band_n_member(__isl_keep isl_band
*band
)
139 return band
? band
->n
: 0;
142 /* Is the given scheduling dimension coincident within the band and
143 * with respect to the coincidence constraints.
145 int isl_band_member_is_coincident(__isl_keep isl_band
*band
, int pos
)
150 if (pos
< 0 || pos
>= band
->n
)
151 isl_die(isl_band_get_ctx(band
), isl_error_invalid
,
152 "invalid member position", return -1);
154 return band
->coincident
[pos
];
157 /* Return the schedule that leads up to this band.
159 __isl_give isl_union_map
*isl_band_get_prefix_schedule(
160 __isl_keep isl_band
*band
)
162 isl_union_set
*domain
;
163 isl_union_pw_multi_aff
*prefix
;
169 prefix
= isl_union_pw_multi_aff_copy(band
->pma
);
170 domain
= isl_union_pw_multi_aff_domain(prefix
);
171 prefix
= isl_union_pw_multi_aff_from_domain(domain
);
173 for (a
= band
->parent
; a
; a
= a
->parent
) {
174 isl_union_pw_multi_aff
*partial
;
176 partial
= isl_union_pw_multi_aff_copy(a
->pma
);
177 prefix
= isl_union_pw_multi_aff_flat_range_product(partial
,
181 return isl_union_map_from_union_pw_multi_aff(prefix
);
184 /* Return the schedule of the band in isolation.
186 __isl_give isl_union_pw_multi_aff
*
187 isl_band_get_partial_schedule_union_pw_multi_aff(__isl_keep isl_band
*band
)
189 return band
? isl_union_pw_multi_aff_copy(band
->pma
) : NULL
;
192 /* Return the schedule of the band in isolation.
194 __isl_give isl_union_map
*isl_band_get_partial_schedule(
195 __isl_keep isl_band
*band
)
197 isl_union_pw_multi_aff
*sched
;
199 sched
= isl_band_get_partial_schedule_union_pw_multi_aff(band
);
200 return isl_union_map_from_union_pw_multi_aff(sched
);
203 __isl_give isl_union_pw_multi_aff
*
204 isl_band_get_suffix_schedule_union_pw_multi_aff(__isl_keep isl_band
*band
);
206 /* Return the schedule for the given band list.
207 * For each band in the list, the schedule is composed of the partial
208 * and suffix schedules of that band.
210 __isl_give isl_union_pw_multi_aff
*
211 isl_band_list_get_suffix_schedule_union_pw_multi_aff(
212 __isl_keep isl_band_list
*list
)
217 isl_union_pw_multi_aff
*suffix
;
222 ctx
= isl_band_list_get_ctx(list
);
223 space
= isl_space_alloc(ctx
, 0, 0, 0);
224 suffix
= isl_union_pw_multi_aff_empty(space
);
225 n
= isl_band_list_n_band(list
);
226 for (i
= 0; i
< n
; ++i
) {
228 isl_union_pw_multi_aff
*partial
;
229 isl_union_pw_multi_aff
*suffix_i
;
231 el
= isl_band_list_get_band(list
, i
);
232 partial
= isl_band_get_partial_schedule_union_pw_multi_aff(el
);
233 suffix_i
= isl_band_get_suffix_schedule_union_pw_multi_aff(el
);
234 suffix_i
= isl_union_pw_multi_aff_flat_range_product(
236 suffix
= isl_union_pw_multi_aff_union_add(suffix
, suffix_i
);
244 /* Return the schedule for the given band list.
245 * For each band in the list, the schedule is composed of the partial
246 * and suffix schedules of that band.
248 __isl_give isl_union_map
*isl_band_list_get_suffix_schedule(
249 __isl_keep isl_band_list
*list
)
251 isl_union_pw_multi_aff
*suffix
;
253 suffix
= isl_band_list_get_suffix_schedule_union_pw_multi_aff(list
);
254 return isl_union_map_from_union_pw_multi_aff(suffix
);
257 /* Return the schedule for the forest underneath the given band.
259 __isl_give isl_union_pw_multi_aff
*
260 isl_band_get_suffix_schedule_union_pw_multi_aff(__isl_keep isl_band
*band
)
262 isl_union_pw_multi_aff
*suffix
;
267 if (!isl_band_has_children(band
)) {
268 isl_union_set
*domain
;
270 suffix
= isl_union_pw_multi_aff_copy(band
->pma
);
271 domain
= isl_union_pw_multi_aff_domain(suffix
);
272 suffix
= isl_union_pw_multi_aff_from_domain(domain
);
276 list
= isl_band_get_children(band
);
278 isl_band_list_get_suffix_schedule_union_pw_multi_aff(list
);
279 isl_band_list_free(list
);
285 /* Return the schedule for the forest underneath the given band.
287 __isl_give isl_union_map
*isl_band_get_suffix_schedule(
288 __isl_keep isl_band
*band
)
290 isl_union_pw_multi_aff
*suffix
;
292 suffix
= isl_band_get_suffix_schedule_union_pw_multi_aff(band
);
293 return isl_union_map_from_union_pw_multi_aff(suffix
);
296 /* Call "fn" on each band (recursively) in the list
297 * in depth-first post-order.
299 int isl_band_list_foreach_band(__isl_keep isl_band_list
*list
,
300 int (*fn
)(__isl_keep isl_band
*band
, void *user
), void *user
)
307 n
= isl_band_list_n_band(list
);
308 for (i
= 0; i
< n
; ++i
) {
312 band
= isl_band_list_get_band(list
, i
);
313 if (isl_band_has_children(band
)) {
314 isl_band_list
*children
;
316 children
= isl_band_get_children(band
);
317 r
= isl_band_list_foreach_band(children
, fn
, user
);
318 isl_band_list_free(children
);
334 /* Internal data used during the construction of the schedule
335 * for the tile loops.
337 * sizes contains the tile sizes
338 * scale is set if the tile loops should be scaled
339 * tiled collects the result for a single statement
340 * res collects the result for all statements
342 struct isl_band_tile_data
{
343 isl_multi_val
*sizes
;
344 isl_union_pw_multi_aff
*res
;
345 isl_pw_multi_aff
*tiled
;
349 /* Given part of the schedule of a band, construct the corresponding
350 * schedule for the tile loops based on the tile sizes in data->sizes
351 * and add the result to data->tiled.
353 * If data->scale is set, then dimension i of the schedule will be
356 * m_i * floor(s_i(x) / m_i)
358 * where s_i(x) refers to the original schedule and m_i is the tile size.
359 * If data->scale is not set, then dimension i of the schedule will be
362 * floor(s_i(x) / m_i)
365 static isl_stat
multi_aff_tile(__isl_take isl_set
*set
,
366 __isl_take isl_multi_aff
*ma
, void *user
)
368 struct isl_band_tile_data
*data
= user
;
369 isl_pw_multi_aff
*pma
;
373 n
= isl_multi_aff_dim(ma
, isl_dim_out
);
375 for (i
= 0; i
< n
; ++i
) {
378 aff
= isl_multi_aff_get_aff(ma
, i
);
379 v
= isl_multi_val_get_val(data
->sizes
, i
);
381 aff
= isl_aff_scale_down_val(aff
, isl_val_copy(v
));
382 aff
= isl_aff_floor(aff
);
384 aff
= isl_aff_scale_val(aff
, isl_val_copy(v
));
387 ma
= isl_multi_aff_set_aff(ma
, i
, aff
);
390 pma
= isl_pw_multi_aff_alloc(set
, ma
);
391 data
->tiled
= isl_pw_multi_aff_union_add(data
->tiled
, pma
);
396 /* Given part of the schedule of a band, construct the corresponding
397 * schedule for the tile loops based on the tile sizes in data->sizes
398 * and add the result to data->res.
400 static isl_stat
pw_multi_aff_tile(__isl_take isl_pw_multi_aff
*pma
, void *user
)
402 struct isl_band_tile_data
*data
= user
;
404 data
->tiled
= isl_pw_multi_aff_empty(isl_pw_multi_aff_get_space(pma
));
406 if (isl_pw_multi_aff_foreach_piece(pma
, &multi_aff_tile
, data
) < 0)
409 isl_pw_multi_aff_free(pma
);
410 data
->res
= isl_union_pw_multi_aff_add_pw_multi_aff(data
->res
,
415 isl_pw_multi_aff_free(pma
);
416 isl_pw_multi_aff_free(data
->tiled
);
417 return isl_stat_error
;
420 /* Given the schedule of a band, construct the corresponding
421 * schedule for the tile loops based on the given tile sizes
422 * and return the result.
424 static isl_union_pw_multi_aff
*isl_union_pw_multi_aff_tile(
425 __isl_take isl_union_pw_multi_aff
*sched
,
426 __isl_keep isl_multi_val
*sizes
)
430 struct isl_band_tile_data data
= { sizes
};
432 ctx
= isl_multi_val_get_ctx(sizes
);
434 space
= isl_union_pw_multi_aff_get_space(sched
);
435 data
.res
= isl_union_pw_multi_aff_empty(space
);
436 data
.scale
= isl_options_get_tile_scale_tile_loops(ctx
);
438 if (isl_union_pw_multi_aff_foreach_pw_multi_aff(sched
,
439 &pw_multi_aff_tile
, &data
) < 0)
442 isl_union_pw_multi_aff_free(sched
);
445 isl_union_pw_multi_aff_free(sched
);
446 isl_union_pw_multi_aff_free(data
.res
);
450 /* Extract the range space from "pma" and store it in *user.
451 * All entries are expected to have the same range space, so we can
452 * stop after extracting the range space from the first entry.
454 static isl_stat
extract_range_space(__isl_take isl_pw_multi_aff
*pma
,
457 isl_space
**space
= user
;
459 *space
= isl_space_range(isl_pw_multi_aff_get_space(pma
));
460 isl_pw_multi_aff_free(pma
);
462 return isl_stat_error
;
465 /* Extract the range space of "band". All entries in band->pma should
466 * have the same range space. Furthermore, band->pma should have at least
469 static __isl_give isl_space
*band_get_range_space(__isl_keep isl_band
*band
)
477 isl_union_pw_multi_aff_foreach_pw_multi_aff(band
->pma
,
478 &extract_range_space
, &space
);
483 /* Construct and return an isl_multi_val in the given space, with as entries
484 * the first elements of "v", padded with ones if the size of "v" is smaller
485 * than the dimension of "space".
487 static __isl_give isl_multi_val
*multi_val_from_vec(__isl_take isl_space
*space
,
488 __isl_take isl_vec
*v
)
497 ctx
= isl_space_get_ctx(space
);
498 mv
= isl_multi_val_zero(space
);
499 n
= isl_multi_val_dim(mv
, isl_dim_set
);
500 size
= isl_vec_size(v
);
504 for (i
= 0; i
< size
; ++i
) {
505 isl_val
*val
= isl_vec_get_element_val(v
, i
);
506 mv
= isl_multi_val_set_val(mv
, i
, val
);
508 for (i
= size
; i
< n
; ++i
)
509 mv
= isl_multi_val_set_val(mv
, i
, isl_val_one(ctx
));
514 isl_space_free(space
);
519 /* Tile the given band using the specified tile sizes.
520 * The given band is modified to refer to the tile loops and
521 * a child band is created to refer to the point loops.
522 * The children of this point loop band are the children
523 * of the original band.
525 * If the scale tile loops option is set, then the tile loops
526 * are scaled by the tile sizes. If the shift point loops option is set,
527 * then the point loops are shifted to start at zero.
528 * In particular, these options affect the tile and point loop schedules
531 * scale shift original tile point
534 * 1 0 i s * floor(i/s) i
535 * 0 1 i floor(i/s) i - s * floor(i/s)
536 * 1 1 i s * floor(i/s) i - s * floor(i/s)
538 int isl_band_tile(__isl_keep isl_band
*band
, __isl_take isl_vec
*sizes
)
542 isl_band_list
*list
= NULL
;
543 isl_union_pw_multi_aff
*sched
= NULL
, *child_sched
= NULL
;
545 isl_multi_val
*mv_sizes
;
550 ctx
= isl_vec_get_ctx(sizes
);
551 child
= isl_band_dup(band
);
552 list
= isl_band_list_alloc(ctx
, 1);
553 list
= isl_band_list_add(list
, child
);
557 space
= band_get_range_space(band
);
558 mv_sizes
= multi_val_from_vec(space
, isl_vec_copy(sizes
));
559 sched
= isl_union_pw_multi_aff_copy(band
->pma
);
560 sched
= isl_union_pw_multi_aff_tile(sched
, mv_sizes
);
562 child_sched
= isl_union_pw_multi_aff_copy(child
->pma
);
563 if (isl_options_get_tile_shift_point_loops(ctx
)) {
564 isl_union_pw_multi_aff
*scaled
;
565 scaled
= isl_union_pw_multi_aff_copy(sched
);
566 if (!isl_options_get_tile_scale_tile_loops(ctx
))
567 scaled
= isl_union_pw_multi_aff_scale_multi_val(scaled
,
568 isl_multi_val_copy(mv_sizes
));
569 child_sched
= isl_union_pw_multi_aff_sub(child_sched
, scaled
);
571 isl_multi_val_free(mv_sizes
);
572 if (!sched
|| !child_sched
)
575 child
->children
= band
->children
;
576 band
->children
= list
;
577 child
->parent
= band
;
578 isl_union_pw_multi_aff_free(band
->pma
);
580 isl_union_pw_multi_aff_free(child
->pma
);
581 child
->pma
= child_sched
;
586 isl_union_pw_multi_aff_free(sched
);
587 isl_union_pw_multi_aff_free(child_sched
);
588 isl_band_list_free(list
);
593 /* Internal data structure used inside isl_union_pw_multi_aff_drop.
595 * "pos" is the position of the first dimension to drop.
596 * "n" is the number of dimensions to drop.
597 * "res" accumulates the result.
599 struct isl_union_pw_multi_aff_drop_data
{
602 isl_union_pw_multi_aff
*res
;
605 /* Drop the data->n output dimensions starting at data->pos from "pma"
606 * and add the result to data->res.
608 static isl_stat
pw_multi_aff_drop(__isl_take isl_pw_multi_aff
*pma
, void *user
)
610 struct isl_union_pw_multi_aff_drop_data
*data
= user
;
612 pma
= isl_pw_multi_aff_drop_dims(pma
, isl_dim_out
, data
->pos
, data
->n
);
614 data
->res
= isl_union_pw_multi_aff_add_pw_multi_aff(data
->res
, pma
);
616 return isl_stat_error
;
621 /* Drop the "n" output dimensions starting at "pos" from "sched".
623 static isl_union_pw_multi_aff
*isl_union_pw_multi_aff_drop(
624 __isl_take isl_union_pw_multi_aff
*sched
, int pos
, int n
)
627 struct isl_union_pw_multi_aff_drop_data data
= { pos
, n
};
629 space
= isl_union_pw_multi_aff_get_space(sched
);
630 data
.res
= isl_union_pw_multi_aff_empty(space
);
632 if (isl_union_pw_multi_aff_foreach_pw_multi_aff(sched
,
633 &pw_multi_aff_drop
, &data
) < 0)
634 data
.res
= isl_union_pw_multi_aff_free(data
.res
);
636 isl_union_pw_multi_aff_free(sched
);
640 /* Drop the "n" dimensions starting at "pos" from "band".
642 static int isl_band_drop(__isl_keep isl_band
*band
, int pos
, int n
)
645 isl_union_pw_multi_aff
*sched
;
652 sched
= isl_union_pw_multi_aff_copy(band
->pma
);
653 sched
= isl_union_pw_multi_aff_drop(sched
, pos
, n
);
657 isl_union_pw_multi_aff_free(band
->pma
);
660 for (i
= pos
+ n
; i
< band
->n
; ++i
)
661 band
->coincident
[i
- n
] = band
->coincident
[i
];
668 /* Split the given band into two nested bands, one with the first "pos"
669 * dimensions of "band" and one with the remaining band->n - pos dimensions.
671 int isl_band_split(__isl_keep isl_band
*band
, int pos
)
680 ctx
= isl_band_get_ctx(band
);
682 if (pos
< 0 || pos
> band
->n
)
683 isl_die(ctx
, isl_error_invalid
, "position out of bounds",
686 child
= isl_band_dup(band
);
687 if (isl_band_drop(child
, 0, pos
) < 0)
688 child
= isl_band_free(child
);
689 list
= isl_band_list_alloc(ctx
, 1);
690 list
= isl_band_list_add(list
, child
);
694 if (isl_band_drop(band
, pos
, band
->n
- pos
) < 0) {
695 isl_band_list_free(list
);
699 child
->children
= band
->children
;
700 band
->children
= list
;
701 child
->parent
= band
;
706 __isl_give isl_printer
*isl_printer_print_band(__isl_take isl_printer
*p
,
707 __isl_keep isl_band
*band
)
709 isl_union_map
*prefix
, *partial
, *suffix
;
711 prefix
= isl_band_get_prefix_schedule(band
);
712 partial
= isl_band_get_partial_schedule(band
);
713 suffix
= isl_band_get_suffix_schedule(band
);
715 p
= isl_printer_print_str(p
, "(");
716 p
= isl_printer_print_union_map(p
, prefix
);
717 p
= isl_printer_print_str(p
, ",");
718 p
= isl_printer_print_union_map(p
, partial
);
719 p
= isl_printer_print_str(p
, ",");
720 p
= isl_printer_print_union_map(p
, suffix
);
721 p
= isl_printer_print_str(p
, ")");
723 isl_union_map_free(prefix
);
724 isl_union_map_free(partial
);
725 isl_union_map_free(suffix
);