2 * Copyright 2011 INRIA Saclay
4 * Use of this software is governed by the MIT license
6 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
7 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
11 #include <isl_band_private.h>
12 #include <isl_schedule_private.h>
13 #include <isl_list_private.h>
15 isl_ctx
*isl_band_get_ctx(__isl_keep isl_band
*band
)
17 return band
? isl_union_pw_multi_aff_get_ctx(band
->pma
) : NULL
;
20 __isl_give isl_band
*isl_band_alloc(isl_ctx
*ctx
)
24 band
= isl_calloc_type(ctx
, isl_band
);
33 /* Create a duplicate of the given band. The duplicate refers
34 * to the same schedule and parent as the input, but does not
35 * increment their reference counts.
37 __isl_give isl_band
*isl_band_dup(__isl_keep isl_band
*band
)
46 ctx
= isl_band_get_ctx(band
);
47 dup
= isl_band_alloc(ctx
);
52 dup
->zero
= isl_alloc_array(ctx
, int, band
->n
);
56 for (i
= 0; i
< band
->n
; ++i
)
57 dup
->zero
[i
] = band
->zero
[i
];
59 dup
->pma
= isl_union_pw_multi_aff_copy(band
->pma
);
60 dup
->schedule
= band
->schedule
;
61 dup
->parent
= band
->parent
;
72 /* We not only increment the reference count of the band,
73 * but also that of the schedule that contains this band.
74 * This ensures that the schedule won't disappear while there
75 * is still a reference to the band outside of the schedule.
76 * There is no need to increment the reference count of the parent
77 * band as the parent band is part of the same schedule.
79 __isl_give isl_band
*isl_band_copy(__isl_keep isl_band
*band
)
85 band
->schedule
->ref
++;
89 /* If this is not the last reference to the band (the one from within the
90 * schedule), then we also need to decrement the reference count of the
91 * containing schedule as it was incremented in isl_band_copy.
93 void *isl_band_free(__isl_take isl_band
*band
)
99 return isl_schedule_free(band
->schedule
);
101 isl_union_pw_multi_aff_free(band
->pma
);
102 isl_band_list_free(band
->children
);
109 int isl_band_has_children(__isl_keep isl_band
*band
)
114 return band
->children
!= NULL
;
117 __isl_give isl_band_list
*isl_band_get_children(
118 __isl_keep isl_band
*band
)
123 isl_die(isl_band_get_ctx(band
), isl_error_invalid
,
124 "band has no children", return NULL
);
125 return isl_band_list_dup(band
->children
);
128 int isl_band_n_member(__isl_keep isl_band
*band
)
130 return band
? band
->n
: 0;
133 /* Is the given scheduling dimension zero distance within the band and
134 * with respect to the proximity dependences.
136 int isl_band_member_is_zero_distance(__isl_keep isl_band
*band
, int pos
)
141 if (pos
< 0 || pos
>= band
->n
)
142 isl_die(isl_band_get_ctx(band
), isl_error_invalid
,
143 "invalid member position", return -1);
145 return band
->zero
[pos
];
148 /* Return the schedule that leads up to this band.
150 __isl_give isl_union_map
*isl_band_get_prefix_schedule(
151 __isl_keep isl_band
*band
)
153 isl_union_set
*domain
;
154 isl_union_pw_multi_aff
*prefix
;
160 prefix
= isl_union_pw_multi_aff_copy(band
->pma
);
161 domain
= isl_union_pw_multi_aff_domain(prefix
);
162 prefix
= isl_union_pw_multi_aff_from_domain(domain
);
164 for (a
= band
->parent
; a
; a
= a
->parent
) {
165 isl_union_pw_multi_aff
*partial
;
167 partial
= isl_union_pw_multi_aff_copy(a
->pma
);
168 prefix
= isl_union_pw_multi_aff_flat_range_product(partial
,
172 return isl_union_map_from_union_pw_multi_aff(prefix
);
175 /* Return the schedule of the band in isolation.
177 __isl_give isl_union_pw_multi_aff
*
178 isl_band_get_partial_schedule_union_pw_multi_aff(__isl_keep isl_band
*band
)
180 return band
? isl_union_pw_multi_aff_copy(band
->pma
) : NULL
;
183 /* Return the schedule of the band in isolation.
185 __isl_give isl_union_map
*isl_band_get_partial_schedule(
186 __isl_keep isl_band
*band
)
188 isl_union_pw_multi_aff
*sched
;
190 sched
= isl_band_get_partial_schedule_union_pw_multi_aff(band
);
191 return isl_union_map_from_union_pw_multi_aff(sched
);
194 __isl_give isl_union_pw_multi_aff
*
195 isl_band_get_suffix_schedule_union_pw_multi_aff(__isl_keep isl_band
*band
);
197 /* Return the schedule for the given band list.
198 * For each band in the list, the schedule is composed of the partial
199 * and suffix schedules of that band.
201 __isl_give isl_union_pw_multi_aff
*
202 isl_band_list_get_suffix_schedule_union_pw_multi_aff(
203 __isl_keep isl_band_list
*list
)
208 isl_union_pw_multi_aff
*suffix
;
213 ctx
= isl_band_list_get_ctx(list
);
214 space
= isl_space_alloc(ctx
, 0, 0, 0);
215 suffix
= isl_union_pw_multi_aff_empty(space
);
216 n
= isl_band_list_n_band(list
);
217 for (i
= 0; i
< n
; ++i
) {
219 isl_union_pw_multi_aff
*partial
;
220 isl_union_pw_multi_aff
*suffix_i
;
222 el
= isl_band_list_get_band(list
, i
);
223 partial
= isl_band_get_partial_schedule_union_pw_multi_aff(el
);
224 suffix_i
= isl_band_get_suffix_schedule_union_pw_multi_aff(el
);
225 suffix_i
= isl_union_pw_multi_aff_flat_range_product(
227 suffix
= isl_union_pw_multi_aff_add(suffix
, suffix_i
);
235 /* Return the schedule for the given band list.
236 * For each band in the list, the schedule is composed of the partial
237 * and suffix schedules of that band.
239 __isl_give isl_union_map
*isl_band_list_get_suffix_schedule(
240 __isl_keep isl_band_list
*list
)
242 isl_union_pw_multi_aff
*suffix
;
244 suffix
= isl_band_list_get_suffix_schedule_union_pw_multi_aff(list
);
245 return isl_union_map_from_union_pw_multi_aff(suffix
);
248 /* Return the schedule for the forest underneath the given band.
250 __isl_give isl_union_pw_multi_aff
*
251 isl_band_get_suffix_schedule_union_pw_multi_aff(__isl_keep isl_band
*band
)
253 isl_union_pw_multi_aff
*suffix
;
258 if (!isl_band_has_children(band
)) {
259 isl_union_set
*domain
;
261 suffix
= isl_union_pw_multi_aff_copy(band
->pma
);
262 domain
= isl_union_pw_multi_aff_domain(suffix
);
263 suffix
= isl_union_pw_multi_aff_from_domain(domain
);
267 list
= isl_band_get_children(band
);
269 isl_band_list_get_suffix_schedule_union_pw_multi_aff(list
);
270 isl_band_list_free(list
);
276 /* Return the schedule for the forest underneath the given band.
278 __isl_give isl_union_map
*isl_band_get_suffix_schedule(
279 __isl_keep isl_band
*band
)
281 isl_union_pw_multi_aff
*suffix
;
283 suffix
= isl_band_get_suffix_schedule_union_pw_multi_aff(band
);
284 return isl_union_map_from_union_pw_multi_aff(suffix
);
287 /* Call "fn" on each band (recursively) in the list
288 * in depth-first post-order.
290 int isl_band_list_foreach_band(__isl_keep isl_band_list
*list
,
291 int (*fn
)(__isl_keep isl_band
*band
, void *user
), void *user
)
298 n
= isl_band_list_n_band(list
);
299 for (i
= 0; i
< n
; ++i
) {
303 band
= isl_band_list_get_band(list
, i
);
304 if (isl_band_has_children(band
)) {
305 isl_band_list
*children
;
307 children
= isl_band_get_children(band
);
308 r
= isl_band_list_foreach_band(children
, fn
, user
);
309 isl_band_list_free(children
);
325 /* Internal data used during the construction of the schedule
326 * for the tile loops.
328 * sizes contains the tile sizes
329 * scale is set if the tile loops should be scaled
330 * tiled collects the result for a single statement
331 * res collects the result for all statements
333 struct isl_band_tile_data
{
335 isl_union_pw_multi_aff
*res
;
336 isl_pw_multi_aff
*tiled
;
340 /* Given part of the schedule of a band, construct the corresponding
341 * schedule for the tile loops based on the tile sizes in data->sizes
342 * and add the result to data->tiled.
344 * If data->scale is set, then dimension i of the schedule will be
347 * m_i * floor(s_i(x) / m_i)
349 * where s_i(x) refers to the original schedule and m_i is the tile size.
350 * If data->scale is not set, then dimension i of the schedule will be
353 * floor(s_i(x) / m_i)
356 static int multi_aff_tile(__isl_take isl_set
*set
,
357 __isl_take isl_multi_aff
*ma
, void *user
)
359 struct isl_band_tile_data
*data
= user
;
360 isl_pw_multi_aff
*pma
;
364 n
= isl_multi_aff_dim(ma
, isl_dim_out
);
365 if (isl_vec_size(data
->sizes
) < n
)
366 n
= isl_vec_size(data
->sizes
);
369 for (i
= 0; i
< n
; ++i
) {
372 aff
= isl_multi_aff_get_aff(ma
, i
);
373 isl_vec_get_element(data
->sizes
, i
, &v
);
375 aff
= isl_aff_scale_down(aff
, v
);
376 aff
= isl_aff_floor(aff
);
378 aff
= isl_aff_scale(aff
, v
);
380 ma
= isl_multi_aff_set_aff(ma
, i
, aff
);
384 pma
= isl_pw_multi_aff_alloc(set
, ma
);
385 data
->tiled
= isl_pw_multi_aff_union_add(data
->tiled
, pma
);
390 /* Given part of the schedule of a band, construct the corresponding
391 * schedule for the tile loops based on the tile sizes in data->sizes
392 * and add the result to data->res.
394 static int pw_multi_aff_tile(__isl_take isl_pw_multi_aff
*pma
, void *user
)
396 struct isl_band_tile_data
*data
= user
;
398 data
->tiled
= isl_pw_multi_aff_empty(isl_pw_multi_aff_get_space(pma
));
400 if (isl_pw_multi_aff_foreach_piece(pma
, &multi_aff_tile
, data
) < 0)
403 isl_pw_multi_aff_free(pma
);
404 data
->res
= isl_union_pw_multi_aff_add_pw_multi_aff(data
->res
,
409 isl_pw_multi_aff_free(pma
);
410 isl_pw_multi_aff_free(data
->tiled
);
414 /* Given the schedule of a band, construct the corresponding
415 * schedule for the tile loops based on the given tile sizes
416 * and return the result.
418 static isl_union_pw_multi_aff
*isl_union_pw_multi_aff_tile(
419 __isl_take isl_union_pw_multi_aff
*sched
, __isl_keep isl_vec
*sizes
)
423 struct isl_band_tile_data data
= { sizes
};
425 ctx
= isl_vec_get_ctx(sizes
);
427 space
= isl_union_pw_multi_aff_get_space(sched
);
428 data
.res
= isl_union_pw_multi_aff_empty(space
);
429 data
.scale
= isl_options_get_tile_scale_tile_loops(ctx
);
431 if (isl_union_pw_multi_aff_foreach_pw_multi_aff(sched
,
432 &pw_multi_aff_tile
, &data
) < 0)
435 isl_union_pw_multi_aff_free(sched
);
438 isl_union_pw_multi_aff_free(sched
);
439 isl_union_pw_multi_aff_free(data
.res
);
443 /* Tile the given band using the specified tile sizes.
444 * The given band is modified to refer to the tile loops and
445 * a child band is created to refer to the point loops.
446 * The children of this point loop band are the children
447 * of the original band.
449 int isl_band_tile(__isl_keep isl_band
*band
, __isl_take isl_vec
*sizes
)
453 isl_band_list
*list
= NULL
;
454 isl_union_pw_multi_aff
*sched
;
459 ctx
= isl_vec_get_ctx(sizes
);
460 child
= isl_band_dup(band
);
461 list
= isl_band_list_alloc(ctx
, 1);
462 list
= isl_band_list_add(list
, child
);
466 sched
= isl_union_pw_multi_aff_copy(band
->pma
);
467 sched
= isl_union_pw_multi_aff_tile(sched
, sizes
);
471 child
->children
= band
->children
;
472 band
->children
= list
;
473 child
->parent
= band
;
474 isl_union_pw_multi_aff_free(band
->pma
);
480 isl_band_list_free(list
);
485 __isl_give isl_printer
*isl_printer_print_band(__isl_take isl_printer
*p
,
486 __isl_keep isl_band
*band
)
488 isl_union_map
*prefix
, *partial
, *suffix
;
490 prefix
= isl_band_get_prefix_schedule(band
);
491 partial
= isl_band_get_partial_schedule(band
);
492 suffix
= isl_band_get_suffix_schedule(band
);
494 p
= isl_printer_print_str(p
, "(");
495 p
= isl_printer_print_union_map(p
, prefix
);
496 p
= isl_printer_print_str(p
, ",");
497 p
= isl_printer_print_union_map(p
, partial
);
498 p
= isl_printer_print_str(p
, ",");
499 p
= isl_printer_print_union_map(p
, suffix
);
500 p
= isl_printer_print_str(p
, ")");
502 isl_union_map_free(prefix
);
503 isl_union_map_free(partial
);
504 isl_union_map_free(suffix
);