|
Packit |
fb9d21 |
/*
|
|
Packit |
fb9d21 |
* Copyright 2011 INRIA Saclay
|
|
Packit |
fb9d21 |
* Copyright 2012-2014 Ecole Normale Superieure
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* Use of this software is governed by the MIT license
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
|
|
Packit |
fb9d21 |
* Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
|
|
Packit |
fb9d21 |
* 91893 Orsay, France
|
|
Packit |
fb9d21 |
* and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
#include <isl/ctx.h>
|
|
Packit |
fb9d21 |
#include <isl_aff_private.h>
|
|
Packit |
fb9d21 |
#include <isl/map.h>
|
|
Packit |
fb9d21 |
#include <isl/set.h>
|
|
Packit |
fb9d21 |
#include <isl_sort.h>
|
|
Packit |
fb9d21 |
#include <isl_schedule_private.h>
|
|
Packit |
fb9d21 |
#include <isl_band_private.h>
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
__isl_null isl_schedule *isl_schedule_free(__isl_take isl_schedule *sched)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
int i;
|
|
Packit |
fb9d21 |
if (!sched)
|
|
Packit |
fb9d21 |
return NULL;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (--sched->ref > 0)
|
|
Packit |
fb9d21 |
return NULL;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
for (i = 0; i < sched->n; ++i) {
|
|
Packit |
fb9d21 |
isl_multi_aff_free(sched->node[i].sched);
|
|
Packit |
fb9d21 |
free(sched->node[i].band_end);
|
|
Packit |
fb9d21 |
free(sched->node[i].band_id);
|
|
Packit |
fb9d21 |
free(sched->node[i].coincident);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
isl_space_free(sched->dim);
|
|
Packit |
fb9d21 |
isl_band_list_free(sched->band_forest);
|
|
Packit |
fb9d21 |
free(sched);
|
|
Packit |
fb9d21 |
return NULL;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
isl_ctx *isl_schedule_get_ctx(__isl_keep isl_schedule *schedule)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
return schedule ? isl_space_get_ctx(schedule->dim) : NULL;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Set max_out to the maximal number of output dimensions over
|
|
Packit |
fb9d21 |
* all maps.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static int update_max_out(__isl_take isl_map *map, void *user)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
int *max_out = user;
|
|
Packit |
fb9d21 |
int n_out = isl_map_dim(map, isl_dim_out);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (n_out > *max_out)
|
|
Packit |
fb9d21 |
*max_out = n_out;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
isl_map_free(map);
|
|
Packit |
fb9d21 |
return 0;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Internal data structure for map_pad_range.
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* "max_out" is the maximal schedule dimension.
|
|
Packit |
fb9d21 |
* "res" collects the results.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
struct isl_pad_schedule_map_data {
|
|
Packit |
fb9d21 |
int max_out;
|
|
Packit |
fb9d21 |
isl_union_map *res;
|
|
Packit |
fb9d21 |
};
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Pad the range of the given map with zeros to data->max_out and
|
|
Packit |
fb9d21 |
* then add the result to data->res.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static int map_pad_range(__isl_take isl_map *map, void *user)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
struct isl_pad_schedule_map_data *data = user;
|
|
Packit |
fb9d21 |
int i;
|
|
Packit |
fb9d21 |
int n_out = isl_map_dim(map, isl_dim_out);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
map = isl_map_add_dims(map, isl_dim_out, data->max_out - n_out);
|
|
Packit |
fb9d21 |
for (i = n_out; i < data->max_out; ++i)
|
|
Packit |
fb9d21 |
map = isl_map_fix_si(map, isl_dim_out, i, 0);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
data->res = isl_union_map_add_map(data->res, map);
|
|
Packit |
fb9d21 |
if (!data->res)
|
|
Packit |
fb9d21 |
return -1;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return 0;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Pad the ranges of the maps in the union map with zeros such they all have
|
|
Packit |
fb9d21 |
* the same dimension.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static __isl_give isl_union_map *pad_schedule_map(
|
|
Packit |
fb9d21 |
__isl_take isl_union_map *umap)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
struct isl_pad_schedule_map_data data;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (!umap)
|
|
Packit |
fb9d21 |
return NULL;
|
|
Packit |
fb9d21 |
if (isl_union_map_n_map(umap) <= 1)
|
|
Packit |
fb9d21 |
return umap;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
data.max_out = 0;
|
|
Packit |
fb9d21 |
if (isl_union_map_foreach_map(umap, &update_max_out, &data.max_out) < 0)
|
|
Packit |
fb9d21 |
return isl_union_map_free(umap);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
data.res = isl_union_map_empty(isl_union_map_get_space(umap));
|
|
Packit |
fb9d21 |
if (isl_union_map_foreach_map(umap, &map_pad_range, &data) < 0)
|
|
Packit |
fb9d21 |
data.res = isl_union_map_free(data.res);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
isl_union_map_free(umap);
|
|
Packit |
fb9d21 |
return data.res;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Return an isl_union_map of the schedule. If we have already constructed
|
|
Packit |
fb9d21 |
* a band forest, then this band forest may have been modified so we need
|
|
Packit |
fb9d21 |
* to extract the isl_union_map from the forest rather than from
|
|
Packit |
fb9d21 |
* the originally computed schedule. This reconstructed schedule map
|
|
Packit |
fb9d21 |
* then needs to be padded with zeros to unify the schedule space
|
|
Packit |
fb9d21 |
* since the result of isl_band_list_get_suffix_schedule may not have
|
|
Packit |
fb9d21 |
* a unified schedule space.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
__isl_give isl_union_map *isl_schedule_get_map(__isl_keep isl_schedule *sched)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
int i;
|
|
Packit |
fb9d21 |
isl_union_map *umap;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (!sched)
|
|
Packit |
fb9d21 |
return NULL;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (sched->band_forest) {
|
|
Packit |
fb9d21 |
umap = isl_band_list_get_suffix_schedule(sched->band_forest);
|
|
Packit |
fb9d21 |
return pad_schedule_map(umap);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
umap = isl_union_map_empty(isl_space_copy(sched->dim));
|
|
Packit |
fb9d21 |
for (i = 0; i < sched->n; ++i) {
|
|
Packit |
fb9d21 |
isl_multi_aff *ma;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
ma = isl_multi_aff_copy(sched->node[i].sched);
|
|
Packit |
fb9d21 |
umap = isl_union_map_add_map(umap, isl_map_from_multi_aff(ma));
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return umap;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
static __isl_give isl_band_list *construct_band_list(
|
|
Packit |
fb9d21 |
__isl_keep isl_schedule *schedule, __isl_keep isl_band *parent,
|
|
Packit |
fb9d21 |
int band_nr, int *parent_active, int n_active);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Construct an isl_band structure for the band in the given schedule
|
|
Packit |
fb9d21 |
* with sequence number band_nr for the n_active nodes marked by active.
|
|
Packit |
fb9d21 |
* If the nodes don't have a band with the given sequence number,
|
|
Packit |
fb9d21 |
* then a band without members is created.
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* Because of the way the schedule is constructed, we know that
|
|
Packit |
fb9d21 |
* the position of the band inside the schedule of a node is the same
|
|
Packit |
fb9d21 |
* for all active nodes.
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* The partial schedule for the band is created before the children
|
|
Packit |
fb9d21 |
* are created to that construct_band_list can refer to the partial
|
|
Packit |
fb9d21 |
* schedule of the parent.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static __isl_give isl_band *construct_band(__isl_keep isl_schedule *schedule,
|
|
Packit |
fb9d21 |
__isl_keep isl_band *parent,
|
|
Packit |
fb9d21 |
int band_nr, int *active, int n_active)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
int i, j;
|
|
Packit |
fb9d21 |
isl_ctx *ctx = isl_schedule_get_ctx(schedule);
|
|
Packit |
fb9d21 |
isl_band *band;
|
|
Packit |
fb9d21 |
unsigned start, end;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
band = isl_band_alloc(ctx);
|
|
Packit |
fb9d21 |
if (!band)
|
|
Packit |
fb9d21 |
return NULL;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
band->schedule = schedule;
|
|
Packit |
fb9d21 |
band->parent = parent;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
for (i = 0; i < schedule->n; ++i)
|
|
Packit |
fb9d21 |
if (active[i])
|
|
Packit |
fb9d21 |
break;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (i >= schedule->n)
|
|
Packit |
fb9d21 |
isl_die(ctx, isl_error_internal,
|
|
Packit |
fb9d21 |
"band without active statements", goto error);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
start = band_nr ? schedule->node[i].band_end[band_nr - 1] : 0;
|
|
Packit |
fb9d21 |
end = band_nr < schedule->node[i].n_band ?
|
|
Packit |
fb9d21 |
schedule->node[i].band_end[band_nr] : start;
|
|
Packit |
fb9d21 |
band->n = end - start;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
band->coincident = isl_alloc_array(ctx, int, band->n);
|
|
Packit |
fb9d21 |
if (band->n && !band->coincident)
|
|
Packit |
fb9d21 |
goto error;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
for (j = 0; j < band->n; ++j)
|
|
Packit |
fb9d21 |
band->coincident[j] = schedule->node[i].coincident[start + j];
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
band->pma = isl_union_pw_multi_aff_empty(isl_space_copy(schedule->dim));
|
|
Packit |
fb9d21 |
for (i = 0; i < schedule->n; ++i) {
|
|
Packit |
fb9d21 |
isl_multi_aff *ma;
|
|
Packit |
fb9d21 |
isl_pw_multi_aff *pma;
|
|
Packit |
fb9d21 |
unsigned n_out;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (!active[i])
|
|
Packit |
fb9d21 |
continue;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
ma = isl_multi_aff_copy(schedule->node[i].sched);
|
|
Packit |
fb9d21 |
n_out = isl_multi_aff_dim(ma, isl_dim_out);
|
|
Packit |
fb9d21 |
ma = isl_multi_aff_drop_dims(ma, isl_dim_out, end, n_out - end);
|
|
Packit |
fb9d21 |
ma = isl_multi_aff_drop_dims(ma, isl_dim_out, 0, start);
|
|
Packit |
fb9d21 |
pma = isl_pw_multi_aff_from_multi_aff(ma);
|
|
Packit |
fb9d21 |
band->pma = isl_union_pw_multi_aff_add_pw_multi_aff(band->pma,
|
|
Packit |
fb9d21 |
pma);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
if (!band->pma)
|
|
Packit |
fb9d21 |
goto error;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
for (i = 0; i < schedule->n; ++i)
|
|
Packit |
fb9d21 |
if (active[i] && schedule->node[i].n_band > band_nr + 1)
|
|
Packit |
fb9d21 |
break;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (i < schedule->n) {
|
|
Packit |
fb9d21 |
band->children = construct_band_list(schedule, band,
|
|
Packit |
fb9d21 |
band_nr + 1, active, n_active);
|
|
Packit |
fb9d21 |
if (!band->children)
|
|
Packit |
fb9d21 |
goto error;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return band;
|
|
Packit |
fb9d21 |
error:
|
|
Packit |
fb9d21 |
isl_band_free(band);
|
|
Packit |
fb9d21 |
return NULL;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Internal data structure used inside cmp_band and pw_multi_aff_extract_int.
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* r is set to a negative value if anything goes wrong.
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* c1 stores the result of extract_int.
|
|
Packit |
fb9d21 |
* c2 is a temporary value used inside cmp_band_in_ancestor.
|
|
Packit |
fb9d21 |
* t is a temporary value used inside extract_int.
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* first and equal are used inside extract_int.
|
|
Packit |
fb9d21 |
* first is set if we are looking at the first isl_multi_aff inside
|
|
Packit |
fb9d21 |
* the isl_union_pw_multi_aff.
|
|
Packit |
fb9d21 |
* equal is set if all the isl_multi_affs have been equal so far.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
struct isl_cmp_band_data {
|
|
Packit |
fb9d21 |
int r;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
int first;
|
|
Packit |
fb9d21 |
int equal;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
isl_int t;
|
|
Packit |
fb9d21 |
isl_int c1;
|
|
Packit |
fb9d21 |
isl_int c2;
|
|
Packit |
fb9d21 |
};
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Check if "ma" assigns a constant value.
|
|
Packit |
fb9d21 |
* Note that this function is only called on isl_multi_affs
|
|
Packit |
fb9d21 |
* with a single output dimension.
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* If "ma" assigns a constant value then we compare it to data->c1
|
|
Packit |
fb9d21 |
* or assign it to data->c1 if this is the first isl_multi_aff we consider.
|
|
Packit |
fb9d21 |
* If "ma" does not assign a constant value or if it assigns a value
|
|
Packit |
fb9d21 |
* that is different from data->c1, then we set data->equal to zero
|
|
Packit |
fb9d21 |
* and terminate the check.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static int multi_aff_extract_int(__isl_take isl_set *set,
|
|
Packit |
fb9d21 |
__isl_take isl_multi_aff *ma, void *user)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
isl_aff *aff;
|
|
Packit |
fb9d21 |
struct isl_cmp_band_data *data = user;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
aff = isl_multi_aff_get_aff(ma, 0);
|
|
Packit |
fb9d21 |
data->r = isl_aff_is_cst(aff);
|
|
Packit |
fb9d21 |
if (data->r >= 0 && data->r) {
|
|
Packit |
fb9d21 |
isl_aff_get_constant(aff, &data->t);
|
|
Packit |
fb9d21 |
if (data->first) {
|
|
Packit |
fb9d21 |
isl_int_set(data->c1, data->t);
|
|
Packit |
fb9d21 |
data->first = 0;
|
|
Packit |
fb9d21 |
} else if (!isl_int_eq(data->c1, data->t))
|
|
Packit |
fb9d21 |
data->equal = 0;
|
|
Packit |
fb9d21 |
} else if (data->r >= 0 && !data->r)
|
|
Packit |
fb9d21 |
data->equal = 0;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
isl_aff_free(aff);
|
|
Packit |
fb9d21 |
isl_set_free(set);
|
|
Packit |
fb9d21 |
isl_multi_aff_free(ma);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (data->r < 0)
|
|
Packit |
fb9d21 |
return -1;
|
|
Packit |
fb9d21 |
if (!data->equal)
|
|
Packit |
fb9d21 |
return -1;
|
|
Packit |
fb9d21 |
return 0;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* This function is called for each isl_pw_multi_aff in
|
|
Packit |
fb9d21 |
* the isl_union_pw_multi_aff checked by extract_int.
|
|
Packit |
fb9d21 |
* Check all the isl_multi_affs inside "pma".
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static int pw_multi_aff_extract_int(__isl_take isl_pw_multi_aff *pma,
|
|
Packit |
fb9d21 |
void *user)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
int r;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
r = isl_pw_multi_aff_foreach_piece(pma, &multi_aff_extract_int, user);
|
|
Packit |
fb9d21 |
isl_pw_multi_aff_free(pma);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return r;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Check if "upma" assigns a single constant value to its domain.
|
|
Packit |
fb9d21 |
* If so, return 1 and store the result in data->c1.
|
|
Packit |
fb9d21 |
* If not, return 0.
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* A negative return value from isl_union_pw_multi_aff_foreach_pw_multi_aff
|
|
Packit |
fb9d21 |
* means that either an error occurred or that we have broken off the check
|
|
Packit |
fb9d21 |
* because we already know the result is going to be negative.
|
|
Packit |
fb9d21 |
* In the latter case, data->equal is set to zero.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static int extract_int(__isl_keep isl_union_pw_multi_aff *upma,
|
|
Packit |
fb9d21 |
struct isl_cmp_band_data *data)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
data->first = 1;
|
|
Packit |
fb9d21 |
data->equal = 1;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,
|
|
Packit |
fb9d21 |
&pw_multi_aff_extract_int, data) < 0) {
|
|
Packit |
fb9d21 |
if (!data->equal)
|
|
Packit |
fb9d21 |
return 0;
|
|
Packit |
fb9d21 |
return -1;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return !data->first && data->equal;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Compare "b1" and "b2" based on the parent schedule of their ancestor
|
|
Packit |
fb9d21 |
* "ancestor".
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* If the parent of "ancestor" also has a single member, then we
|
|
Packit |
fb9d21 |
* first try to compare the two band based on the partial schedule
|
|
Packit |
fb9d21 |
* of this parent.
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* Otherwise, or if the result is inconclusive, we look at the partial schedule
|
|
Packit |
fb9d21 |
* of "ancestor" itself.
|
|
Packit |
fb9d21 |
* In particular, we specialize the parent schedule based
|
|
Packit |
fb9d21 |
* on the domains of the child schedules, check if both assign
|
|
Packit |
fb9d21 |
* a single constant value and, if so, compare the two constant values.
|
|
Packit |
fb9d21 |
* If the specialized parent schedules do not assign a constant value,
|
|
Packit |
fb9d21 |
* then they cannot be used to order the two bands and so in this case
|
|
Packit |
fb9d21 |
* we return 0.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static int cmp_band_in_ancestor(__isl_keep isl_band *b1,
|
|
Packit |
fb9d21 |
__isl_keep isl_band *b2, struct isl_cmp_band_data *data,
|
|
Packit |
fb9d21 |
__isl_keep isl_band *ancestor)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
isl_union_pw_multi_aff *upma;
|
|
Packit |
fb9d21 |
isl_union_set *domain;
|
|
Packit |
fb9d21 |
int r;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (data->r < 0)
|
|
Packit |
fb9d21 |
return 0;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (ancestor->parent && ancestor->parent->n == 1) {
|
|
Packit |
fb9d21 |
r = cmp_band_in_ancestor(b1, b2, data, ancestor->parent);
|
|
Packit |
fb9d21 |
if (data->r < 0)
|
|
Packit |
fb9d21 |
return 0;
|
|
Packit |
fb9d21 |
if (r)
|
|
Packit |
fb9d21 |
return r;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
upma = isl_union_pw_multi_aff_copy(b1->pma);
|
|
Packit |
fb9d21 |
domain = isl_union_pw_multi_aff_domain(upma);
|
|
Packit |
fb9d21 |
upma = isl_union_pw_multi_aff_copy(ancestor->pma);
|
|
Packit |
fb9d21 |
upma = isl_union_pw_multi_aff_intersect_domain(upma, domain);
|
|
Packit |
fb9d21 |
r = extract_int(upma, data);
|
|
Packit |
fb9d21 |
isl_union_pw_multi_aff_free(upma);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (r < 0)
|
|
Packit |
fb9d21 |
data->r = -1;
|
|
Packit |
fb9d21 |
if (r < 0 || !r)
|
|
Packit |
fb9d21 |
return 0;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
isl_int_set(data->c2, data->c1);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
upma = isl_union_pw_multi_aff_copy(b2->pma);
|
|
Packit |
fb9d21 |
domain = isl_union_pw_multi_aff_domain(upma);
|
|
Packit |
fb9d21 |
upma = isl_union_pw_multi_aff_copy(ancestor->pma);
|
|
Packit |
fb9d21 |
upma = isl_union_pw_multi_aff_intersect_domain(upma, domain);
|
|
Packit |
fb9d21 |
r = extract_int(upma, data);
|
|
Packit |
fb9d21 |
isl_union_pw_multi_aff_free(upma);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (r < 0)
|
|
Packit |
fb9d21 |
data->r = -1;
|
|
Packit |
fb9d21 |
if (r < 0 || !r)
|
|
Packit |
fb9d21 |
return 0;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return isl_int_cmp(data->c2, data->c1);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Compare "a" and "b" based on the parent schedule of their parent.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static int cmp_band(const void *a, const void *b, void *user)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
isl_band *b1 = *(isl_band * const *) a;
|
|
Packit |
fb9d21 |
isl_band *b2 = *(isl_band * const *) b;
|
|
Packit |
fb9d21 |
struct isl_cmp_band_data *data = user;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return cmp_band_in_ancestor(b1, b2, data, b1->parent);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Sort the elements in "list" based on the partial schedules of its parent
|
|
Packit |
fb9d21 |
* (and ancestors). In particular if the parent assigns constant values
|
|
Packit |
fb9d21 |
* to the domains of the bands in "list", then the elements are sorted
|
|
Packit |
fb9d21 |
* according to that order.
|
|
Packit |
fb9d21 |
* This order should be a more "natural" order for the user, but otherwise
|
|
Packit |
fb9d21 |
* shouldn't have any effect.
|
|
Packit |
fb9d21 |
* If we would be constructing an isl_band forest directly in
|
|
Packit |
fb9d21 |
* isl_schedule_constraints_compute_schedule then there wouldn't be any need
|
|
Packit |
fb9d21 |
* for a reordering, since the children would be added to the list
|
|
Packit |
fb9d21 |
* in their natural order automatically.
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* If there is only one element in the list, then there is no need to sort
|
|
Packit |
fb9d21 |
* anything.
|
|
Packit |
fb9d21 |
* If the partial schedule of the parent has more than one member
|
|
Packit |
fb9d21 |
* (or if there is no parent), then it's
|
|
Packit |
fb9d21 |
* defnitely not assigning constant values to the different children in
|
|
Packit |
fb9d21 |
* the list and so we wouldn't be able to use it to sort the list.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static __isl_give isl_band_list *sort_band_list(__isl_take isl_band_list *list,
|
|
Packit |
fb9d21 |
__isl_keep isl_band *parent)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
struct isl_cmp_band_data data;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (!list)
|
|
Packit |
fb9d21 |
return NULL;
|
|
Packit |
fb9d21 |
if (list->n <= 1)
|
|
Packit |
fb9d21 |
return list;
|
|
Packit |
fb9d21 |
if (!parent || parent->n != 1)
|
|
Packit |
fb9d21 |
return list;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
data.r = 0;
|
|
Packit |
fb9d21 |
isl_int_init(data.c1);
|
|
Packit |
fb9d21 |
isl_int_init(data.c2);
|
|
Packit |
fb9d21 |
isl_int_init(data.t);
|
|
Packit |
fb9d21 |
isl_sort(list->p, list->n, sizeof(list->p[0]), &cmp_band, &data);
|
|
Packit |
fb9d21 |
if (data.r < 0)
|
|
Packit |
fb9d21 |
list = isl_band_list_free(list);
|
|
Packit |
fb9d21 |
isl_int_clear(data.c1);
|
|
Packit |
fb9d21 |
isl_int_clear(data.c2);
|
|
Packit |
fb9d21 |
isl_int_clear(data.t);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return list;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Construct a list of bands that start at the same position (with
|
|
Packit |
fb9d21 |
* sequence number band_nr) in the schedules of the nodes that
|
|
Packit |
fb9d21 |
* were active in the parent band.
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* A separate isl_band structure is created for each band_id
|
|
Packit |
fb9d21 |
* and for each node that does not have a band with sequence
|
|
Packit |
fb9d21 |
* number band_nr. In the latter case, a band without members
|
|
Packit |
fb9d21 |
* is created.
|
|
Packit |
fb9d21 |
* This ensures that if a band has any children, then each node
|
|
Packit |
fb9d21 |
* that was active in the band is active in exactly one of the children.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static __isl_give isl_band_list *construct_band_list(
|
|
Packit |
fb9d21 |
__isl_keep isl_schedule *schedule, __isl_keep isl_band *parent,
|
|
Packit |
fb9d21 |
int band_nr, int *parent_active, int n_active)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
int i, j;
|
|
Packit |
fb9d21 |
isl_ctx *ctx = isl_schedule_get_ctx(schedule);
|
|
Packit |
fb9d21 |
int *active;
|
|
Packit |
fb9d21 |
int n_band;
|
|
Packit |
fb9d21 |
isl_band_list *list;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
n_band = 0;
|
|
Packit |
fb9d21 |
for (i = 0; i < n_active; ++i) {
|
|
Packit |
fb9d21 |
for (j = 0; j < schedule->n; ++j) {
|
|
Packit |
fb9d21 |
if (!parent_active[j])
|
|
Packit |
fb9d21 |
continue;
|
|
Packit |
fb9d21 |
if (schedule->node[j].n_band <= band_nr)
|
|
Packit |
fb9d21 |
continue;
|
|
Packit |
fb9d21 |
if (schedule->node[j].band_id[band_nr] == i) {
|
|
Packit |
fb9d21 |
n_band++;
|
|
Packit |
fb9d21 |
break;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
for (j = 0; j < schedule->n; ++j)
|
|
Packit |
fb9d21 |
if (schedule->node[j].n_band <= band_nr)
|
|
Packit |
fb9d21 |
n_band++;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (n_band == 1) {
|
|
Packit |
fb9d21 |
isl_band *band;
|
|
Packit |
fb9d21 |
list = isl_band_list_alloc(ctx, n_band);
|
|
Packit |
fb9d21 |
band = construct_band(schedule, parent, band_nr,
|
|
Packit |
fb9d21 |
parent_active, n_active);
|
|
Packit |
fb9d21 |
return isl_band_list_add(list, band);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
active = isl_alloc_array(ctx, int, schedule->n);
|
|
Packit |
fb9d21 |
if (schedule->n && !active)
|
|
Packit |
fb9d21 |
return NULL;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
list = isl_band_list_alloc(ctx, n_band);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
for (i = 0; i < n_active; ++i) {
|
|
Packit |
fb9d21 |
int n = 0;
|
|
Packit |
fb9d21 |
isl_band *band;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
for (j = 0; j < schedule->n; ++j) {
|
|
Packit |
fb9d21 |
active[j] = parent_active[j] &&
|
|
Packit |
fb9d21 |
schedule->node[j].n_band > band_nr &&
|
|
Packit |
fb9d21 |
schedule->node[j].band_id[band_nr] == i;
|
|
Packit |
fb9d21 |
if (active[j])
|
|
Packit |
fb9d21 |
n++;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
if (n == 0)
|
|
Packit |
fb9d21 |
continue;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
band = construct_band(schedule, parent, band_nr, active, n);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
list = isl_band_list_add(list, band);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
for (i = 0; i < schedule->n; ++i) {
|
|
Packit |
fb9d21 |
isl_band *band;
|
|
Packit |
fb9d21 |
if (!parent_active[i])
|
|
Packit |
fb9d21 |
continue;
|
|
Packit |
fb9d21 |
if (schedule->node[i].n_band > band_nr)
|
|
Packit |
fb9d21 |
continue;
|
|
Packit |
fb9d21 |
for (j = 0; j < schedule->n; ++j)
|
|
Packit |
fb9d21 |
active[j] = j == i;
|
|
Packit |
fb9d21 |
band = construct_band(schedule, parent, band_nr, active, 1);
|
|
Packit |
fb9d21 |
list = isl_band_list_add(list, band);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
free(active);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
list = sort_band_list(list, parent);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return list;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Construct a band forest representation of the schedule and
|
|
Packit |
fb9d21 |
* return the list of roots.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static __isl_give isl_band_list *construct_forest(
|
|
Packit |
fb9d21 |
__isl_keep isl_schedule *schedule)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
int i;
|
|
Packit |
fb9d21 |
isl_ctx *ctx = isl_schedule_get_ctx(schedule);
|
|
Packit |
fb9d21 |
isl_band_list *forest;
|
|
Packit |
fb9d21 |
int *active;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
active = isl_alloc_array(ctx, int, schedule->n);
|
|
Packit |
fb9d21 |
if (schedule->n && !active)
|
|
Packit |
fb9d21 |
return NULL;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
for (i = 0; i < schedule->n; ++i)
|
|
Packit |
fb9d21 |
active[i] = 1;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
forest = construct_band_list(schedule, NULL, 0, active, schedule->n);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
free(active);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return forest;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Return the roots of a band forest representation of the schedule.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
__isl_give isl_band_list *isl_schedule_get_band_forest(
|
|
Packit |
fb9d21 |
__isl_keep isl_schedule *schedule)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
if (!schedule)
|
|
Packit |
fb9d21 |
return NULL;
|
|
Packit |
fb9d21 |
if (!schedule->band_forest)
|
|
Packit |
fb9d21 |
schedule->band_forest = construct_forest(schedule);
|
|
Packit |
fb9d21 |
return isl_band_list_dup(schedule->band_forest);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Call "fn" on each band in the schedule in depth-first post-order.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
int isl_schedule_foreach_band(__isl_keep isl_schedule *sched,
|
|
Packit |
fb9d21 |
int (*fn)(__isl_keep isl_band *band, void *user), void *user)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
int r;
|
|
Packit |
fb9d21 |
isl_band_list *forest;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (!sched)
|
|
Packit |
fb9d21 |
return -1;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
forest = isl_schedule_get_band_forest(sched);
|
|
Packit |
fb9d21 |
r = isl_band_list_foreach_band(forest, fn, user);
|
|
Packit |
fb9d21 |
isl_band_list_free(forest);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return r;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
static __isl_give isl_printer *print_band_list(__isl_take isl_printer *p,
|
|
Packit |
fb9d21 |
__isl_keep isl_band_list *list);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
static __isl_give isl_printer *print_band(__isl_take isl_printer *p,
|
|
Packit |
fb9d21 |
__isl_keep isl_band *band)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
isl_band_list *children;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
p = isl_printer_start_line(p);
|
|
Packit |
fb9d21 |
p = isl_printer_print_union_pw_multi_aff(p, band->pma);
|
|
Packit |
fb9d21 |
p = isl_printer_end_line(p);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (!isl_band_has_children(band))
|
|
Packit |
fb9d21 |
return p;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
children = isl_band_get_children(band);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
p = isl_printer_indent(p, 4);
|
|
Packit |
fb9d21 |
p = print_band_list(p, children);
|
|
Packit |
fb9d21 |
p = isl_printer_indent(p, -4);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
isl_band_list_free(children);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return p;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
static __isl_give isl_printer *print_band_list(__isl_take isl_printer *p,
|
|
Packit |
fb9d21 |
__isl_keep isl_band_list *list)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
int i, n;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
n = isl_band_list_n_band(list);
|
|
Packit |
fb9d21 |
for (i = 0; i < n; ++i) {
|
|
Packit |
fb9d21 |
isl_band *band;
|
|
Packit |
fb9d21 |
band = isl_band_list_get_band(list, i);
|
|
Packit |
fb9d21 |
p = print_band(p, band);
|
|
Packit |
fb9d21 |
isl_band_free(band);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return p;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
__isl_give isl_printer *isl_printer_print_schedule(__isl_take isl_printer *p,
|
|
Packit |
fb9d21 |
__isl_keep isl_schedule *schedule)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
isl_band_list *forest;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
forest = isl_schedule_get_band_forest(schedule);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
p = print_band_list(p, forest);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
isl_band_list_free(forest);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return p;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
void isl_schedule_dump(__isl_keep isl_schedule *schedule)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
isl_printer *printer;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (!schedule)
|
|
Packit |
fb9d21 |
return;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
printer = isl_printer_to_file(isl_schedule_get_ctx(schedule), stderr);
|
|
Packit |
fb9d21 |
printer = isl_printer_print_schedule(printer, schedule);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
isl_printer_free(printer);
|
|
Packit |
fb9d21 |
}
|