Blame isl-0.14/isl_schedule.c

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
}