Blame isl-0.16.1/isl_schedule_band.c

Packit fb9d21
/*
Packit fb9d21
 * Copyright 2013-2014 Ecole Normale Superieure
Packit fb9d21
 * Copyright 2014      INRIA Rocquencourt
Packit fb9d21
 *
Packit fb9d21
 * Use of this software is governed by the MIT license
Packit fb9d21
 *
Packit fb9d21
 * Written by Sven Verdoolaege,
Packit fb9d21
 * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France
Packit fb9d21
 * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,
Packit fb9d21
 * B.P. 105 - 78153 Le Chesnay, France
Packit fb9d21
 */
Packit fb9d21
Packit fb9d21
#include <string.h>
Packit fb9d21
#include <isl/map.h>
Packit fb9d21
#include <isl/schedule_node.h>
Packit fb9d21
#include <isl_schedule_band.h>
Packit fb9d21
#include <isl_schedule_private.h>
Packit fb9d21
Packit fb9d21
isl_ctx *isl_schedule_band_get_ctx(__isl_keep isl_schedule_band *band)
Packit fb9d21
{
Packit fb9d21
	return band ? isl_multi_union_pw_aff_get_ctx(band->mupa) : NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Return a new uninitialized isl_schedule_band.
Packit fb9d21
 */
Packit fb9d21
static __isl_give isl_schedule_band *isl_schedule_band_alloc(isl_ctx *ctx)
Packit fb9d21
{
Packit fb9d21
	isl_schedule_band *band;
Packit fb9d21
Packit fb9d21
	band = isl_calloc_type(ctx, isl_schedule_band);
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	band->ref = 1;
Packit fb9d21
Packit fb9d21
	return band;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Return a new isl_schedule_band with partial schedule "mupa".
Packit fb9d21
 * First replace "mupa" by its greatest integer part to ensure
Packit fb9d21
 * that the schedule is always integral.
Packit fb9d21
 * The band is not marked permutable, the dimensions are not
Packit fb9d21
 * marked coincident and the AST build options are empty.
Packit fb9d21
 * Since there are no build options, the node is not anchored.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_from_multi_union_pw_aff(
Packit fb9d21
	__isl_take isl_multi_union_pw_aff *mupa)
Packit fb9d21
{
Packit fb9d21
	isl_ctx *ctx;
Packit fb9d21
	isl_schedule_band *band;
Packit fb9d21
	isl_space *space;
Packit fb9d21
Packit fb9d21
	mupa = isl_multi_union_pw_aff_floor(mupa);
Packit fb9d21
	if (!mupa)
Packit fb9d21
		return NULL;
Packit fb9d21
	ctx = isl_multi_union_pw_aff_get_ctx(mupa);
Packit fb9d21
	band = isl_schedule_band_alloc(ctx);
Packit fb9d21
	if (!band)
Packit fb9d21
		goto error;
Packit fb9d21
Packit fb9d21
	band->n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);
Packit fb9d21
	band->coincident = isl_calloc_array(ctx, int, band->n);
Packit fb9d21
	band->mupa = mupa;
Packit fb9d21
	space = isl_space_params_alloc(ctx, 0);
Packit fb9d21
	band->ast_build_options = isl_union_set_empty(space);
Packit fb9d21
	band->anchored = 0;
Packit fb9d21
Packit fb9d21
	if ((band->n && !band->coincident) || !band->ast_build_options)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
Packit fb9d21
	return band;
Packit fb9d21
error:
Packit fb9d21
	isl_multi_union_pw_aff_free(mupa);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Create a duplicate of the given isl_schedule_band.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_dup(
Packit fb9d21
	__isl_keep isl_schedule_band *band)
Packit fb9d21
{
Packit fb9d21
	int i;
Packit fb9d21
	isl_ctx *ctx;
Packit fb9d21
	isl_schedule_band *dup;
Packit fb9d21
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	ctx = isl_schedule_band_get_ctx(band);
Packit fb9d21
	dup = isl_schedule_band_alloc(ctx);
Packit fb9d21
	if (!dup)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	dup->n = band->n;
Packit fb9d21
	dup->coincident = isl_alloc_array(ctx, int, band->n);
Packit fb9d21
	if (band->n && !dup->coincident)
Packit fb9d21
		return isl_schedule_band_free(dup);
Packit fb9d21
Packit fb9d21
	for (i = 0; i < band->n; ++i)
Packit fb9d21
		dup->coincident[i] = band->coincident[i];
Packit fb9d21
	dup->permutable = band->permutable;
Packit fb9d21
Packit fb9d21
	dup->mupa = isl_multi_union_pw_aff_copy(band->mupa);
Packit fb9d21
	dup->ast_build_options = isl_union_set_copy(band->ast_build_options);
Packit fb9d21
	if (!dup->mupa || !dup->ast_build_options)
Packit fb9d21
		return isl_schedule_band_free(dup);
Packit fb9d21
Packit fb9d21
	if (band->loop_type) {
Packit fb9d21
		dup->loop_type = isl_alloc_array(ctx,
Packit fb9d21
					    enum isl_ast_loop_type, band->n);
Packit fb9d21
		if (band->n && !dup->loop_type)
Packit fb9d21
			return isl_schedule_band_free(dup);
Packit fb9d21
		for (i = 0; i < band->n; ++i)
Packit fb9d21
			dup->loop_type[i] = band->loop_type[i];
Packit fb9d21
	}
Packit fb9d21
	if (band->isolate_loop_type) {
Packit fb9d21
		dup->isolate_loop_type = isl_alloc_array(ctx,
Packit fb9d21
					    enum isl_ast_loop_type, band->n);
Packit fb9d21
		if (band->n && !dup->isolate_loop_type)
Packit fb9d21
			return isl_schedule_band_free(dup);
Packit fb9d21
		for (i = 0; i < band->n; ++i)
Packit fb9d21
			dup->isolate_loop_type[i] = band->isolate_loop_type[i];
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	return dup;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Return an isl_schedule_band that is equal to "band" and that has only
Packit fb9d21
 * a single reference.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_cow(
Packit fb9d21
	__isl_take isl_schedule_band *band)
Packit fb9d21
{
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	if (band->ref == 1)
Packit fb9d21
		return band;
Packit fb9d21
	band->ref--;
Packit fb9d21
	return isl_schedule_band_dup(band);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Return a new reference to "band".
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_copy(
Packit fb9d21
	__isl_keep isl_schedule_band *band)
Packit fb9d21
{
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	band->ref++;
Packit fb9d21
	return band;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Free a reference to "band" and return NULL.
Packit fb9d21
 */
Packit fb9d21
__isl_null isl_schedule_band *isl_schedule_band_free(
Packit fb9d21
	__isl_take isl_schedule_band *band)
Packit fb9d21
{
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	if (--band->ref > 0)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	isl_multi_union_pw_aff_free(band->mupa);
Packit fb9d21
	isl_union_set_free(band->ast_build_options);
Packit fb9d21
	free(band->loop_type);
Packit fb9d21
	free(band->isolate_loop_type);
Packit fb9d21
	free(band->coincident);
Packit fb9d21
	free(band);
Packit fb9d21
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Are "band1" and "band2" obviously equal?
Packit fb9d21
 */
Packit fb9d21
isl_bool isl_schedule_band_plain_is_equal(__isl_keep isl_schedule_band *band1,
Packit fb9d21
	__isl_keep isl_schedule_band *band2)
Packit fb9d21
{
Packit fb9d21
	int i;
Packit fb9d21
	isl_bool equal;
Packit fb9d21
Packit fb9d21
	if (!band1 || !band2)
Packit fb9d21
		return isl_bool_error;
Packit fb9d21
	if (band1 == band2)
Packit fb9d21
		return isl_bool_true;
Packit fb9d21
Packit fb9d21
	if (band1->n != band2->n)
Packit fb9d21
		return isl_bool_false;
Packit fb9d21
	for (i = 0; i < band1->n; ++i)
Packit fb9d21
		if (band1->coincident[i] != band2->coincident[i])
Packit fb9d21
			return isl_bool_false;
Packit fb9d21
	if (band1->permutable != band2->permutable)
Packit fb9d21
		return isl_bool_false;
Packit fb9d21
Packit fb9d21
	equal = isl_multi_union_pw_aff_plain_is_equal(band1->mupa, band2->mupa);
Packit fb9d21
	if (equal < 0 || !equal)
Packit fb9d21
		return equal;
Packit fb9d21
Packit fb9d21
	if (!band1->loop_type != !band2->loop_type)
Packit fb9d21
		return isl_bool_false;
Packit fb9d21
	if (band1->loop_type)
Packit fb9d21
		for (i = 0; i < band1->n; ++i)
Packit fb9d21
			if (band1->loop_type[i] != band2->loop_type[i])
Packit fb9d21
				return isl_bool_false;
Packit fb9d21
Packit fb9d21
	if (!band1->isolate_loop_type != !band2->isolate_loop_type)
Packit fb9d21
		return isl_bool_false;
Packit fb9d21
	if (band1->isolate_loop_type)
Packit fb9d21
		for (i = 0; i < band1->n; ++i)
Packit fb9d21
			if (band1->isolate_loop_type[i] !=
Packit fb9d21
						band2->isolate_loop_type[i])
Packit fb9d21
				return isl_bool_false;
Packit fb9d21
Packit fb9d21
	return isl_union_set_is_equal(band1->ast_build_options,
Packit fb9d21
					band2->ast_build_options);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Return the number of scheduling dimensions in the band.
Packit fb9d21
 */
Packit fb9d21
int isl_schedule_band_n_member(__isl_keep isl_schedule_band *band)
Packit fb9d21
{
Packit fb9d21
	return band ? band->n : 0;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Is the given scheduling dimension coincident within the band and
Packit fb9d21
 * with respect to the coincidence constraints?
Packit fb9d21
 */
Packit fb9d21
isl_bool isl_schedule_band_member_get_coincident(
Packit fb9d21
	__isl_keep isl_schedule_band *band, int pos)
Packit fb9d21
{
Packit fb9d21
	if (!band)
Packit fb9d21
		return isl_bool_error;
Packit fb9d21
Packit fb9d21
	if (pos < 0 || pos >= band->n)
Packit fb9d21
		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
Packit fb9d21
			"invalid member position", return isl_bool_error);
Packit fb9d21
Packit fb9d21
	return band->coincident[pos];
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Mark the given scheduling dimension as being coincident or not
Packit fb9d21
 * according to "coincident".
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_member_set_coincident(
Packit fb9d21
	__isl_take isl_schedule_band *band, int pos, int coincident)
Packit fb9d21
{
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
	if (isl_schedule_band_member_get_coincident(band, pos) == coincident)
Packit fb9d21
		return band;
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	if (pos < 0 || pos >= band->n)
Packit fb9d21
		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
Packit fb9d21
			"invalid member position",
Packit fb9d21
			isl_schedule_band_free(band));
Packit fb9d21
Packit fb9d21
	band->coincident[pos] = coincident;
Packit fb9d21
Packit fb9d21
	return band;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Is the schedule band mark permutable?
Packit fb9d21
 */
Packit fb9d21
isl_bool isl_schedule_band_get_permutable(__isl_keep isl_schedule_band *band)
Packit fb9d21
{
Packit fb9d21
	if (!band)
Packit fb9d21
		return isl_bool_error;
Packit fb9d21
	return band->permutable;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Mark the schedule band permutable or not according to "permutable"?
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_set_permutable(
Packit fb9d21
	__isl_take isl_schedule_band *band, int permutable)
Packit fb9d21
{
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
	if (band->permutable == permutable)
Packit fb9d21
		return band;
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	band->permutable = permutable;
Packit fb9d21
Packit fb9d21
	return band;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Is the band node "node" anchored?  That is, does it reference
Packit fb9d21
 * the outer band nodes?
Packit fb9d21
 */
Packit fb9d21
int isl_schedule_band_is_anchored(__isl_keep isl_schedule_band *band)
Packit fb9d21
{
Packit fb9d21
	return band ? band->anchored : -1;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Return the schedule space of the band.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_space *isl_schedule_band_get_space(
Packit fb9d21
	__isl_keep isl_schedule_band *band)
Packit fb9d21
{
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
	return isl_multi_union_pw_aff_get_space(band->mupa);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Intersect the domain of the band schedule of "band" with "domain".
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_intersect_domain(
Packit fb9d21
	__isl_take isl_schedule_band *band, __isl_take isl_union_set *domain)
Packit fb9d21
{
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band || !domain)
Packit fb9d21
		goto error;
Packit fb9d21
Packit fb9d21
	band->mupa = isl_multi_union_pw_aff_intersect_domain(band->mupa,
Packit fb9d21
								domain);
Packit fb9d21
	if (!band->mupa)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
Packit fb9d21
	return band;
Packit fb9d21
error:
Packit fb9d21
	isl_schedule_band_free(band);
Packit fb9d21
	isl_union_set_free(domain);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Return the schedule of the band in isolation.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_multi_union_pw_aff *isl_schedule_band_get_partial_schedule(
Packit fb9d21
	__isl_keep isl_schedule_band *band)
Packit fb9d21
{
Packit fb9d21
	return band ? isl_multi_union_pw_aff_copy(band->mupa) : NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Replace the schedule of "band" by "schedule".
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_set_partial_schedule(
Packit fb9d21
	__isl_take isl_schedule_band *band,
Packit fb9d21
	__isl_take isl_multi_union_pw_aff *schedule)
Packit fb9d21
{
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band || !schedule)
Packit fb9d21
		goto error;
Packit fb9d21
Packit fb9d21
	isl_multi_union_pw_aff_free(band->mupa);
Packit fb9d21
	band->mupa = schedule;
Packit fb9d21
Packit fb9d21
	return band;
Packit fb9d21
error:
Packit fb9d21
	isl_schedule_band_free(band);
Packit fb9d21
	isl_multi_union_pw_aff_free(schedule);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Return the loop AST generation type for the band member of "band"
Packit fb9d21
 * at position "pos".
Packit fb9d21
 */
Packit fb9d21
enum isl_ast_loop_type isl_schedule_band_member_get_ast_loop_type(
Packit fb9d21
	__isl_keep isl_schedule_band *band, int pos)
Packit fb9d21
{
Packit fb9d21
	if (!band)
Packit fb9d21
		return isl_ast_loop_error;
Packit fb9d21
Packit fb9d21
	if (pos < 0 || pos >= band->n)
Packit fb9d21
		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
Packit fb9d21
			"invalid member position", return -1);
Packit fb9d21
Packit fb9d21
	if (!band->loop_type)
Packit fb9d21
		return isl_ast_loop_default;
Packit fb9d21
Packit fb9d21
	return band->loop_type[pos];
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Set the loop AST generation type for the band member of "band"
Packit fb9d21
 * at position "pos" to "type".
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_member_set_ast_loop_type(
Packit fb9d21
	__isl_take isl_schedule_band *band, int pos,
Packit fb9d21
	enum isl_ast_loop_type type)
Packit fb9d21
{
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
	if (isl_schedule_band_member_get_ast_loop_type(band, pos) == type)
Packit fb9d21
		return band;
Packit fb9d21
Packit fb9d21
	if (pos < 0 || pos >= band->n)
Packit fb9d21
		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
Packit fb9d21
			"invalid member position",
Packit fb9d21
			isl_schedule_band_free(band));
Packit fb9d21
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
Packit fb9d21
	if (!band->loop_type) {
Packit fb9d21
		isl_ctx *ctx;
Packit fb9d21
Packit fb9d21
		ctx = isl_schedule_band_get_ctx(band);
Packit fb9d21
		band->loop_type = isl_calloc_array(ctx,
Packit fb9d21
					    enum isl_ast_loop_type, band->n);
Packit fb9d21
		if (band->n && !band->loop_type)
Packit fb9d21
			return isl_schedule_band_free(band);
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	band->loop_type[pos] = type;
Packit fb9d21
Packit fb9d21
	return band;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Return the loop AST generation type for the band member of "band"
Packit fb9d21
 * at position "pos" for the part that has been isolated by the isolate option.
Packit fb9d21
 */
Packit fb9d21
enum isl_ast_loop_type isl_schedule_band_member_get_isolate_ast_loop_type(
Packit fb9d21
	__isl_keep isl_schedule_band *band, int pos)
Packit fb9d21
{
Packit fb9d21
	if (!band)
Packit fb9d21
		return isl_ast_loop_error;
Packit fb9d21
Packit fb9d21
	if (pos < 0 || pos >= band->n)
Packit fb9d21
		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
Packit fb9d21
			"invalid member position", return -1);
Packit fb9d21
Packit fb9d21
	if (!band->isolate_loop_type)
Packit fb9d21
		return isl_ast_loop_default;
Packit fb9d21
Packit fb9d21
	return band->isolate_loop_type[pos];
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Set the loop AST generation type for the band member of "band"
Packit fb9d21
 * at position "pos" to "type" for the part that has been isolated
Packit fb9d21
 * by the isolate option.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *
Packit fb9d21
isl_schedule_band_member_set_isolate_ast_loop_type(
Packit fb9d21
	__isl_take isl_schedule_band *band, int pos,
Packit fb9d21
	enum isl_ast_loop_type type)
Packit fb9d21
{
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
	if (isl_schedule_band_member_get_isolate_ast_loop_type(band, pos) ==
Packit fb9d21
									type)
Packit fb9d21
		return band;
Packit fb9d21
Packit fb9d21
	if (pos < 0 || pos >= band->n)
Packit fb9d21
		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
Packit fb9d21
			"invalid member position",
Packit fb9d21
			isl_schedule_band_free(band));
Packit fb9d21
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
Packit fb9d21
	if (!band->isolate_loop_type) {
Packit fb9d21
		isl_ctx *ctx;
Packit fb9d21
Packit fb9d21
		ctx = isl_schedule_band_get_ctx(band);
Packit fb9d21
		band->isolate_loop_type = isl_calloc_array(ctx,
Packit fb9d21
					    enum isl_ast_loop_type, band->n);
Packit fb9d21
		if (band->n && !band->isolate_loop_type)
Packit fb9d21
			return isl_schedule_band_free(band);
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	band->isolate_loop_type[pos] = type;
Packit fb9d21
Packit fb9d21
	return band;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
static const char *option_str[] = {
Packit fb9d21
	[isl_ast_loop_atomic] = "atomic",
Packit fb9d21
	[isl_ast_loop_unroll] = "unroll",
Packit fb9d21
	[isl_ast_loop_separate] = "separate"
Packit fb9d21
};
Packit fb9d21
Packit fb9d21
/* Given a parameter space "space", extend it to a set space
Packit fb9d21
 *
Packit fb9d21
 *	{ type[x] }
Packit fb9d21
 *
Packit fb9d21
 * or
Packit fb9d21
 *
Packit fb9d21
 *	{ [isolate[] -> type[x]] }
Packit fb9d21
 *
Packit fb9d21
 * depending on whether "isolate" is set.
Packit fb9d21
 * These can be used to encode loop AST generation options of the given type.
Packit fb9d21
 */
Packit fb9d21
static __isl_give isl_space *loop_type_space(__isl_take isl_space *space,
Packit fb9d21
	enum isl_ast_loop_type type, int isolate)
Packit fb9d21
{
Packit fb9d21
	const char *name;
Packit fb9d21
Packit fb9d21
	name = option_str[type];
Packit fb9d21
	space = isl_space_set_from_params(space);
Packit fb9d21
	space = isl_space_add_dims(space, isl_dim_set, 1);
Packit fb9d21
	space = isl_space_set_tuple_name(space, isl_dim_set, name);
Packit fb9d21
	if (!isolate)
Packit fb9d21
		return space;
Packit fb9d21
	space = isl_space_from_range(space);
Packit fb9d21
	space = isl_space_set_tuple_name(space, isl_dim_in, "isolate");
Packit fb9d21
	space = isl_space_wrap(space);
Packit fb9d21
Packit fb9d21
	return space;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Add encodings of the "n" loop AST generation options "type" to "options".
Packit fb9d21
 * If "isolate" is set, then these options refer to the isolated part.
Packit fb9d21
 *
Packit fb9d21
 * In particular, for each sequence of consecutive identical types "t",
Packit fb9d21
 * different from the default, add an option
Packit fb9d21
 *
Packit fb9d21
 *	{ t[x] : first <= x <= last }
Packit fb9d21
 *
Packit fb9d21
 * or
Packit fb9d21
 *
Packit fb9d21
 *	{ [isolate[] -> t[x]] : first <= x <= last }
Packit fb9d21
 */
Packit fb9d21
static __isl_give isl_union_set *add_loop_types(
Packit fb9d21
	__isl_take isl_union_set *options, int n, enum isl_ast_loop_type *type,
Packit fb9d21
	int isolate)
Packit fb9d21
{
Packit fb9d21
	int i;
Packit fb9d21
	isl_ctx *ctx;
Packit fb9d21
Packit fb9d21
	if (!type)
Packit fb9d21
		return options;
Packit fb9d21
	if (!options)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	ctx = isl_union_set_get_ctx(options);
Packit fb9d21
	for (i = 0; i < n; ++i) {
Packit fb9d21
		int first;
Packit fb9d21
		isl_space *space;
Packit fb9d21
		isl_set *option;
Packit fb9d21
Packit fb9d21
		if (type[i] == isl_ast_loop_default)
Packit fb9d21
			continue;
Packit fb9d21
Packit fb9d21
		first = i;
Packit fb9d21
		while (i + 1 < n && type[i + 1] == type[i])
Packit fb9d21
			++i;
Packit fb9d21
Packit fb9d21
		space = isl_union_set_get_space(options);
Packit fb9d21
		space = loop_type_space(space, type[i], isolate);
Packit fb9d21
		option = isl_set_universe(space);
Packit fb9d21
		option = isl_set_lower_bound_si(option, isl_dim_set, 0, first);
Packit fb9d21
		option = isl_set_upper_bound_si(option, isl_dim_set, 0, i);
Packit fb9d21
		options = isl_union_set_add_set(options, option);
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	return options;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Return the AST build options associated to "band".
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_union_set *isl_schedule_band_get_ast_build_options(
Packit fb9d21
	__isl_keep isl_schedule_band *band)
Packit fb9d21
{
Packit fb9d21
	isl_union_set *options;
Packit fb9d21
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	options = isl_union_set_copy(band->ast_build_options);
Packit fb9d21
	options = add_loop_types(options, band->n, band->loop_type, 0);
Packit fb9d21
	options = add_loop_types(options, band->n, band->isolate_loop_type, 1);
Packit fb9d21
Packit fb9d21
	return options;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Does "uset" contain any set that satisfies "is"?
Packit fb9d21
 * "is" is assumed to set its integer argument to 1 if it is satisfied.
Packit fb9d21
 */
Packit fb9d21
static int has_any(__isl_keep isl_union_set *uset,
Packit fb9d21
	isl_stat (*is)(__isl_take isl_set *set, void *user))
Packit fb9d21
{
Packit fb9d21
	int found = 0;
Packit fb9d21
Packit fb9d21
	if (isl_union_set_foreach_set(uset, is, &found) < 0 && !found)
Packit fb9d21
		return -1;
Packit fb9d21
Packit fb9d21
	return found;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Does "set" live in a space of the form
Packit fb9d21
 *
Packit fb9d21
 *	isolate[[...] -> [...]]
Packit fb9d21
 *
Packit fb9d21
 * ?
Packit fb9d21
 *
Packit fb9d21
 * If so, set *found and abort the search.
Packit fb9d21
 */
Packit fb9d21
static isl_stat is_isolate(__isl_take isl_set *set, void *user)
Packit fb9d21
{
Packit fb9d21
	int *found = user;
Packit fb9d21
Packit fb9d21
	if (isl_set_has_tuple_name(set)) {
Packit fb9d21
		const char *name;
Packit fb9d21
		name = isl_set_get_tuple_name(set);
Packit fb9d21
		if (isl_set_is_wrapping(set) && !strcmp(name, "isolate"))
Packit fb9d21
			*found = 1;
Packit fb9d21
	}
Packit fb9d21
	isl_set_free(set);
Packit fb9d21
Packit fb9d21
	return *found ? isl_stat_error : isl_stat_ok;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Does "options" include an option of the ofrm
Packit fb9d21
 *
Packit fb9d21
 *	isolate[[...] -> [...]]
Packit fb9d21
 *
Packit fb9d21
 * ?
Packit fb9d21
 */
Packit fb9d21
static int has_isolate_option(__isl_keep isl_union_set *options)
Packit fb9d21
{
Packit fb9d21
	return has_any(options, &is_isolate);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Does "set" encode a loop AST generation option?
Packit fb9d21
 */
Packit fb9d21
static isl_stat is_loop_type_option(__isl_take isl_set *set, void *user)
Packit fb9d21
{
Packit fb9d21
	int *found = user;
Packit fb9d21
Packit fb9d21
	if (isl_set_dim(set, isl_dim_set) == 1 &&
Packit fb9d21
	    isl_set_has_tuple_name(set)) {
Packit fb9d21
		const char *name;
Packit fb9d21
		enum isl_ast_loop_type type;
Packit fb9d21
		name = isl_set_get_tuple_name(set);
Packit fb9d21
		for (type = isl_ast_loop_atomic;
Packit fb9d21
		    type <= isl_ast_loop_separate; ++type) {
Packit fb9d21
			if (strcmp(name, option_str[type]))
Packit fb9d21
				continue;
Packit fb9d21
			*found = 1;
Packit fb9d21
			break;
Packit fb9d21
		}
Packit fb9d21
	}
Packit fb9d21
	isl_set_free(set);
Packit fb9d21
Packit fb9d21
	return *found ? isl_stat_error : isl_stat_ok;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Does "set" encode a loop AST generation option for the isolated part?
Packit fb9d21
 * That is, is of the form
Packit fb9d21
 *
Packit fb9d21
 *	{ [isolate[] -> t[x]] }
Packit fb9d21
 *
Packit fb9d21
 * with t equal to "atomic", "unroll" or "separate"?
Packit fb9d21
 */
Packit fb9d21
static isl_stat is_isolate_loop_type_option(__isl_take isl_set *set, void *user)
Packit fb9d21
{
Packit fb9d21
	int *found = user;
Packit fb9d21
	const char *name;
Packit fb9d21
	enum isl_ast_loop_type type;
Packit fb9d21
	isl_map *map;
Packit fb9d21
Packit fb9d21
	if (!isl_set_is_wrapping(set)) {
Packit fb9d21
		isl_set_free(set);
Packit fb9d21
		return isl_stat_ok;
Packit fb9d21
	}
Packit fb9d21
	map = isl_set_unwrap(set);
Packit fb9d21
	if (!isl_map_has_tuple_name(map, isl_dim_in) ||
Packit fb9d21
	    !isl_map_has_tuple_name(map, isl_dim_out)) {
Packit fb9d21
		isl_map_free(map);
Packit fb9d21
		return isl_stat_ok;
Packit fb9d21
	}
Packit fb9d21
	name = isl_map_get_tuple_name(map, isl_dim_in);
Packit fb9d21
	if (!strcmp(name, "isolate")) {
Packit fb9d21
		name = isl_map_get_tuple_name(map, isl_dim_out);
Packit fb9d21
		for (type = isl_ast_loop_atomic;
Packit fb9d21
		    type <= isl_ast_loop_separate; ++type) {
Packit fb9d21
			if (strcmp(name, option_str[type]))
Packit fb9d21
				continue;
Packit fb9d21
			*found = 1;
Packit fb9d21
			break;
Packit fb9d21
		}
Packit fb9d21
	}
Packit fb9d21
	isl_map_free(map);
Packit fb9d21
Packit fb9d21
	return *found ? isl_stat_error : isl_stat_ok;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Does "options" encode any loop AST generation options
Packit fb9d21
 * for the isolated part?
Packit fb9d21
 */
Packit fb9d21
static int has_isolate_loop_type_options(__isl_keep isl_union_set *options)
Packit fb9d21
{
Packit fb9d21
	return has_any(options, &is_isolate_loop_type_option);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Does "options" encode any loop AST generation options?
Packit fb9d21
 */
Packit fb9d21
static int has_loop_type_options(__isl_keep isl_union_set *options)
Packit fb9d21
{
Packit fb9d21
	return has_any(options, &is_loop_type_option);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Extract the loop AST generation type for the band member
Packit fb9d21
 * at position "pos" from "options".
Packit fb9d21
 * If "isolate" is set, then extract the loop types for the isolated part.
Packit fb9d21
 */
Packit fb9d21
static enum isl_ast_loop_type extract_loop_type(
Packit fb9d21
	__isl_keep isl_union_set *options, int pos, int isolate)
Packit fb9d21
{
Packit fb9d21
	isl_ctx *ctx;
Packit fb9d21
	enum isl_ast_loop_type type, res = isl_ast_loop_default;
Packit fb9d21
Packit fb9d21
	ctx = isl_union_set_get_ctx(options);
Packit fb9d21
	for (type = isl_ast_loop_atomic;
Packit fb9d21
	    type <= isl_ast_loop_separate; ++type) {
Packit fb9d21
		isl_space *space;
Packit fb9d21
		isl_set *option;
Packit fb9d21
		int empty;
Packit fb9d21
Packit fb9d21
		space = isl_union_set_get_space(options);
Packit fb9d21
		space = loop_type_space(space, type, isolate);
Packit fb9d21
		option = isl_union_set_extract_set(options, space);
Packit fb9d21
		option = isl_set_fix_si(option, isl_dim_set, 0, pos);
Packit fb9d21
		empty = isl_set_is_empty(option);
Packit fb9d21
		isl_set_free(option);
Packit fb9d21
Packit fb9d21
		if (empty < 0)
Packit fb9d21
			return isl_ast_loop_error;
Packit fb9d21
		if (empty)
Packit fb9d21
			continue;
Packit fb9d21
		if (res != isl_ast_loop_default)
Packit fb9d21
			isl_die(ctx, isl_error_invalid,
Packit fb9d21
				"conflicting loop type options",
Packit fb9d21
				return isl_ast_loop_error);
Packit fb9d21
		res = type;
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	return res;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Extract the loop AST generation types for the members of "band"
Packit fb9d21
 * from "options" and store them in band->loop_type.
Packit fb9d21
 * Return -1 on error.
Packit fb9d21
 */
Packit fb9d21
static int extract_loop_types(__isl_keep isl_schedule_band *band,
Packit fb9d21
	__isl_keep isl_union_set *options)
Packit fb9d21
{
Packit fb9d21
	int i;
Packit fb9d21
Packit fb9d21
	if (!band->loop_type) {
Packit fb9d21
		isl_ctx *ctx = isl_schedule_band_get_ctx(band);
Packit fb9d21
		band->loop_type = isl_alloc_array(ctx,
Packit fb9d21
					    enum isl_ast_loop_type, band->n);
Packit fb9d21
		if (band->n && !band->loop_type)
Packit fb9d21
			return -1;
Packit fb9d21
	}
Packit fb9d21
	for (i = 0; i < band->n; ++i) {
Packit fb9d21
		band->loop_type[i] = extract_loop_type(options, i, 0);
Packit fb9d21
		if (band->loop_type[i] == isl_ast_loop_error)
Packit fb9d21
			return -1;
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	return 0;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Extract the loop AST generation types for the members of "band"
Packit fb9d21
 * from "options" for the isolated part and
Packit fb9d21
 * store them in band->isolate_loop_type.
Packit fb9d21
 * Return -1 on error.
Packit fb9d21
 */
Packit fb9d21
static int extract_isolate_loop_types(__isl_keep isl_schedule_band *band,
Packit fb9d21
	__isl_keep isl_union_set *options)
Packit fb9d21
{
Packit fb9d21
	int i;
Packit fb9d21
Packit fb9d21
	if (!band->isolate_loop_type) {
Packit fb9d21
		isl_ctx *ctx = isl_schedule_band_get_ctx(band);
Packit fb9d21
		band->isolate_loop_type = isl_alloc_array(ctx,
Packit fb9d21
					    enum isl_ast_loop_type, band->n);
Packit fb9d21
		if (band->n && !band->isolate_loop_type)
Packit fb9d21
			return -1;
Packit fb9d21
	}
Packit fb9d21
	for (i = 0; i < band->n; ++i) {
Packit fb9d21
		band->isolate_loop_type[i] = extract_loop_type(options, i, 1);
Packit fb9d21
		if (band->isolate_loop_type[i] == isl_ast_loop_error)
Packit fb9d21
			return -1;
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	return 0;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Construct universe sets of the spaces that encode loop AST generation
Packit fb9d21
 * types (for the isolated part if "isolate" is set).  That is, construct
Packit fb9d21
 *
Packit fb9d21
 *	{ atomic[x]; separate[x]; unroll[x] }
Packit fb9d21
 *
Packit fb9d21
 * or
Packit fb9d21
 *
Packit fb9d21
 *	{ [isolate[] -> atomic[x]]; [isolate[] -> separate[x]];
Packit fb9d21
 *	  [isolate[] -> unroll[x]] }
Packit fb9d21
 */
Packit fb9d21
static __isl_give isl_union_set *loop_types(__isl_take isl_space *space,
Packit fb9d21
	int isolate)
Packit fb9d21
{
Packit fb9d21
	enum isl_ast_loop_type type;
Packit fb9d21
	isl_union_set *types;
Packit fb9d21
Packit fb9d21
	types = isl_union_set_empty(space);
Packit fb9d21
	for (type = isl_ast_loop_atomic;
Packit fb9d21
	    type <= isl_ast_loop_separate; ++type) {
Packit fb9d21
		isl_set *set;
Packit fb9d21
Packit fb9d21
		space = isl_union_set_get_space(types);
Packit fb9d21
		space = loop_type_space(space, type, isolate);
Packit fb9d21
		set = isl_set_universe(space);
Packit fb9d21
		types = isl_union_set_add_set(types, set);
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	return types;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Remove all elements from spaces that encode loop AST generation types
Packit fb9d21
 * from "options".
Packit fb9d21
 */
Packit fb9d21
static __isl_give isl_union_set *clear_loop_types(
Packit fb9d21
	__isl_take isl_union_set *options)
Packit fb9d21
{
Packit fb9d21
	isl_union_set *types;
Packit fb9d21
Packit fb9d21
	types = loop_types(isl_union_set_get_space(options), 0);
Packit fb9d21
	options = isl_union_set_subtract(options, types);
Packit fb9d21
Packit fb9d21
	return options;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Remove all elements from spaces that encode loop AST generation types
Packit fb9d21
 * for the isolated part from "options".
Packit fb9d21
 */
Packit fb9d21
static __isl_give isl_union_set *clear_isolate_loop_types(
Packit fb9d21
	__isl_take isl_union_set *options)
Packit fb9d21
{
Packit fb9d21
	isl_union_set *types;
Packit fb9d21
Packit fb9d21
	types = loop_types(isl_union_set_get_space(options), 1);
Packit fb9d21
	options = isl_union_set_subtract(options, types);
Packit fb9d21
Packit fb9d21
	return options;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Replace the AST build options associated to "band" by "options".
Packit fb9d21
 * If there are any loop AST generation type options, then they
Packit fb9d21
 * are extracted and stored in band->loop_type.  Otherwise,
Packit fb9d21
 * band->loop_type is removed to indicate that the default applies
Packit fb9d21
 * to all members.  Similarly for the loop AST generation type options
Packit fb9d21
 * for the isolated part, which are stored in band->isolate_loop_type.
Packit fb9d21
 * The remaining options are stored in band->ast_build_options.
Packit fb9d21
 *
Packit fb9d21
 * Set anchored if the options include an isolate option since the
Packit fb9d21
 * domain of the wrapped map references the outer band node schedules.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_set_ast_build_options(
Packit fb9d21
	__isl_take isl_schedule_band *band, __isl_take isl_union_set *options)
Packit fb9d21
{
Packit fb9d21
	int has_isolate, has_loop_type, has_isolate_loop_type;
Packit fb9d21
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band || !options)
Packit fb9d21
		goto error;
Packit fb9d21
	has_isolate = has_isolate_option(options);
Packit fb9d21
	if (has_isolate < 0)
Packit fb9d21
		goto error;
Packit fb9d21
	has_loop_type = has_loop_type_options(options);
Packit fb9d21
	if (has_loop_type < 0)
Packit fb9d21
		goto error;
Packit fb9d21
	has_isolate_loop_type = has_isolate_loop_type_options(options);
Packit fb9d21
	if (has_isolate_loop_type < 0)
Packit fb9d21
		goto error;
Packit fb9d21
Packit fb9d21
	if (!has_loop_type) {
Packit fb9d21
		free(band->loop_type);
Packit fb9d21
		band->loop_type = NULL;
Packit fb9d21
	} else {
Packit fb9d21
		if (extract_loop_types(band, options) < 0)
Packit fb9d21
			goto error;
Packit fb9d21
		options = clear_loop_types(options);
Packit fb9d21
		if (!options)
Packit fb9d21
			goto error;
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	if (!has_isolate_loop_type) {
Packit fb9d21
		free(band->isolate_loop_type);
Packit fb9d21
		band->isolate_loop_type = NULL;
Packit fb9d21
	} else {
Packit fb9d21
		if (extract_isolate_loop_types(band, options) < 0)
Packit fb9d21
			goto error;
Packit fb9d21
		options = clear_isolate_loop_types(options);
Packit fb9d21
		if (!options)
Packit fb9d21
			goto error;
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	isl_union_set_free(band->ast_build_options);
Packit fb9d21
	band->ast_build_options = options;
Packit fb9d21
	band->anchored = has_isolate;
Packit fb9d21
Packit fb9d21
	return band;
Packit fb9d21
error:
Packit fb9d21
	isl_schedule_band_free(band);
Packit fb9d21
	isl_union_set_free(options);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Multiply the partial schedule of "band" with the factors in "mv".
Packit fb9d21
 * Replace the result by its greatest integer part to ensure
Packit fb9d21
 * that the schedule is always integral.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_scale(
Packit fb9d21
	__isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv)
Packit fb9d21
{
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band || !mv)
Packit fb9d21
		goto error;
Packit fb9d21
	band->mupa = isl_multi_union_pw_aff_scale_multi_val(band->mupa, mv);
Packit fb9d21
	band->mupa = isl_multi_union_pw_aff_floor(band->mupa);
Packit fb9d21
	if (!band->mupa)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
	return band;
Packit fb9d21
error:
Packit fb9d21
	isl_schedule_band_free(band);
Packit fb9d21
	isl_multi_val_free(mv);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Divide the partial schedule of "band" by the factors in "mv".
Packit fb9d21
 * Replace the result by its greatest integer part to ensure
Packit fb9d21
 * that the schedule is always integral.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_scale_down(
Packit fb9d21
	__isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv)
Packit fb9d21
{
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band || !mv)
Packit fb9d21
		goto error;
Packit fb9d21
	band->mupa = isl_multi_union_pw_aff_scale_down_multi_val(band->mupa,
Packit fb9d21
								mv);
Packit fb9d21
	band->mupa = isl_multi_union_pw_aff_floor(band->mupa);
Packit fb9d21
	if (!band->mupa)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
	return band;
Packit fb9d21
error:
Packit fb9d21
	isl_schedule_band_free(band);
Packit fb9d21
	isl_multi_val_free(mv);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Reduce the partial schedule of "band" modulo the factors in "mv".
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_mod(
Packit fb9d21
	__isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv)
Packit fb9d21
{
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band || !mv)
Packit fb9d21
		goto error;
Packit fb9d21
	band->mupa = isl_multi_union_pw_aff_mod_multi_val(band->mupa, mv);
Packit fb9d21
	if (!band->mupa)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
	return band;
Packit fb9d21
error:
Packit fb9d21
	isl_schedule_band_free(band);
Packit fb9d21
	isl_multi_val_free(mv);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Shift the partial schedule of "band" by "shift" after checking
Packit fb9d21
 * that the domain of the partial schedule would not be affected
Packit fb9d21
 * by this shift.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_shift(
Packit fb9d21
	__isl_take isl_schedule_band *band,
Packit fb9d21
	__isl_take isl_multi_union_pw_aff *shift)
Packit fb9d21
{
Packit fb9d21
	isl_union_set *dom1, *dom2;
Packit fb9d21
	isl_bool subset;
Packit fb9d21
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band || !shift)
Packit fb9d21
		goto error;
Packit fb9d21
	dom1 = isl_multi_union_pw_aff_domain(
Packit fb9d21
				isl_multi_union_pw_aff_copy(band->mupa));
Packit fb9d21
	dom2 = isl_multi_union_pw_aff_domain(
Packit fb9d21
				isl_multi_union_pw_aff_copy(shift));
Packit fb9d21
	subset = isl_union_set_is_subset(dom1, dom2);
Packit fb9d21
	isl_union_set_free(dom1);
Packit fb9d21
	isl_union_set_free(dom2);
Packit fb9d21
	if (subset < 0)
Packit fb9d21
		goto error;
Packit fb9d21
	if (!subset)
Packit fb9d21
		isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid,
Packit fb9d21
			"domain of shift needs to include domain of "
Packit fb9d21
			"partial schedule", goto error);
Packit fb9d21
	band->mupa = isl_multi_union_pw_aff_add(band->mupa, shift);
Packit fb9d21
	if (!band->mupa)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
	return band;
Packit fb9d21
error:
Packit fb9d21
	isl_schedule_band_free(band);
Packit fb9d21
	isl_multi_union_pw_aff_free(shift);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Given the schedule of a band, construct the corresponding
Packit fb9d21
 * schedule for the tile loops based on the given tile sizes
Packit fb9d21
 * and return the result.
Packit fb9d21
 *
Packit fb9d21
 * If the scale tile loops options is set, then the tile loops
Packit fb9d21
 * are scaled by the tile sizes.
Packit fb9d21
 *
Packit fb9d21
 * That is replace each schedule dimension "i" by either
Packit fb9d21
 * "floor(i/s)" or "s * floor(i/s)".
Packit fb9d21
 */
Packit fb9d21
static isl_multi_union_pw_aff *isl_multi_union_pw_aff_tile(
Packit fb9d21
	__isl_take isl_multi_union_pw_aff *sched,
Packit fb9d21
	__isl_take isl_multi_val *sizes)
Packit fb9d21
{
Packit fb9d21
	isl_ctx *ctx;
Packit fb9d21
	int i, n;
Packit fb9d21
	isl_val *v;
Packit fb9d21
	int scale;
Packit fb9d21
Packit fb9d21
	ctx = isl_multi_val_get_ctx(sizes);
Packit fb9d21
	scale = isl_options_get_tile_scale_tile_loops(ctx);
Packit fb9d21
Packit fb9d21
	n = isl_multi_union_pw_aff_dim(sched, isl_dim_set);
Packit fb9d21
	for (i = 0; i < n; ++i) {
Packit fb9d21
		isl_union_pw_aff *upa;
Packit fb9d21
Packit fb9d21
		upa = isl_multi_union_pw_aff_get_union_pw_aff(sched, i);
Packit fb9d21
		v = isl_multi_val_get_val(sizes, i);
Packit fb9d21
Packit fb9d21
		upa = isl_union_pw_aff_scale_down_val(upa, isl_val_copy(v));
Packit fb9d21
		upa = isl_union_pw_aff_floor(upa);
Packit fb9d21
		if (scale)
Packit fb9d21
			upa = isl_union_pw_aff_scale_val(upa, isl_val_copy(v));
Packit fb9d21
		isl_val_free(v);
Packit fb9d21
Packit fb9d21
		sched = isl_multi_union_pw_aff_set_union_pw_aff(sched, i, upa);
Packit fb9d21
	}
Packit fb9d21
Packit fb9d21
	isl_multi_val_free(sizes);
Packit fb9d21
	return sched;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Replace "band" by a band corresponding to the tile loops of a tiling
Packit fb9d21
 * with the given tile sizes.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_tile(
Packit fb9d21
	__isl_take isl_schedule_band *band, __isl_take isl_multi_val *sizes)
Packit fb9d21
{
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band || !sizes)
Packit fb9d21
		goto error;
Packit fb9d21
	band->mupa = isl_multi_union_pw_aff_tile(band->mupa, sizes);
Packit fb9d21
	if (!band->mupa)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
	return band;
Packit fb9d21
error:
Packit fb9d21
	isl_schedule_band_free(band);
Packit fb9d21
	isl_multi_val_free(sizes);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Replace "band" by a band corresponding to the point loops of a tiling
Packit fb9d21
 * with the given tile sizes.
Packit fb9d21
 * "tile" is the corresponding tile loop band.
Packit fb9d21
 *
Packit fb9d21
 * If the shift point loops option is set, then the point loops
Packit fb9d21
 * are shifted to start at zero.  That is, each schedule dimension "i"
Packit fb9d21
 * is replaced by "i - s * floor(i/s)".
Packit fb9d21
 * The expression "floor(i/s)" (or "s * floor(i/s)") is extracted from
Packit fb9d21
 * the tile band.
Packit fb9d21
 *
Packit fb9d21
 * Otherwise, the band is left untouched.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_point(
Packit fb9d21
	__isl_take isl_schedule_band *band, __isl_keep isl_schedule_band *tile,
Packit fb9d21
	__isl_take isl_multi_val *sizes)
Packit fb9d21
{
Packit fb9d21
	isl_ctx *ctx;
Packit fb9d21
	isl_multi_union_pw_aff *scaled;
Packit fb9d21
Packit fb9d21
	if (!band || !sizes)
Packit fb9d21
		goto error;
Packit fb9d21
Packit fb9d21
	ctx = isl_schedule_band_get_ctx(band);
Packit fb9d21
	if (!isl_options_get_tile_shift_point_loops(ctx)) {
Packit fb9d21
		isl_multi_val_free(sizes);
Packit fb9d21
		return band;
Packit fb9d21
	}
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band)
Packit fb9d21
		goto error;
Packit fb9d21
Packit fb9d21
	scaled = isl_schedule_band_get_partial_schedule(tile);
Packit fb9d21
	if (!isl_options_get_tile_scale_tile_loops(ctx))
Packit fb9d21
		scaled = isl_multi_union_pw_aff_scale_multi_val(scaled, sizes);
Packit fb9d21
	else
Packit fb9d21
		isl_multi_val_free(sizes);
Packit fb9d21
	band->mupa = isl_multi_union_pw_aff_sub(band->mupa, scaled);
Packit fb9d21
	if (!band->mupa)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
	return band;
Packit fb9d21
error:
Packit fb9d21
	isl_schedule_band_free(band);
Packit fb9d21
	isl_multi_val_free(sizes);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Drop the "n" dimensions starting at "pos" from "band".
Packit fb9d21
 *
Packit fb9d21
 * We apply the transformation even if "n" is zero to ensure consistent
Packit fb9d21
 * behavior with respect to changes in the schedule space.
Packit fb9d21
 *
Packit fb9d21
 * The loop AST generation types for the isolated part become
Packit fb9d21
 * meaningless after dropping dimensions, so we remove them.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_drop(
Packit fb9d21
	__isl_take isl_schedule_band *band, int pos, int n)
Packit fb9d21
{
Packit fb9d21
	int i;
Packit fb9d21
Packit fb9d21
	if (pos < 0 || n < 0 || pos + n > band->n)
Packit fb9d21
		isl_die(isl_schedule_band_get_ctx(band), isl_error_internal,
Packit fb9d21
			"range out of bounds",
Packit fb9d21
			return isl_schedule_band_free(band));
Packit fb9d21
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	band->mupa = isl_multi_union_pw_aff_drop_dims(band->mupa,
Packit fb9d21
							isl_dim_set, pos, n);
Packit fb9d21
	if (!band->mupa)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
Packit fb9d21
	for (i = pos + n; i < band->n; ++i)
Packit fb9d21
		band->coincident[i - n] = band->coincident[i];
Packit fb9d21
	if (band->loop_type)
Packit fb9d21
		for (i = pos + n; i < band->n; ++i)
Packit fb9d21
			band->loop_type[i - n] = band->loop_type[i];
Packit fb9d21
	free(band->isolate_loop_type);
Packit fb9d21
	band->isolate_loop_type = NULL;
Packit fb9d21
Packit fb9d21
	band->n -= n;
Packit fb9d21
Packit fb9d21
	return band;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Reset the user pointer on all identifiers of parameters and tuples
Packit fb9d21
 * in "band".
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_reset_user(
Packit fb9d21
	__isl_take isl_schedule_band *band)
Packit fb9d21
{
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band)
Packit fb9d21
		return NULL;
Packit fb9d21
Packit fb9d21
	band->mupa = isl_multi_union_pw_aff_reset_user(band->mupa);
Packit fb9d21
	band->ast_build_options =
Packit fb9d21
		isl_union_set_reset_user(band->ast_build_options);
Packit fb9d21
	if (!band->mupa || !band->ast_build_options)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
Packit fb9d21
	return band;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Align the parameters of "band" to those of "space".
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_align_params(
Packit fb9d21
	__isl_take isl_schedule_band *band, __isl_take isl_space *space)
Packit fb9d21
{
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band || !space)
Packit fb9d21
		goto error;
Packit fb9d21
Packit fb9d21
	band->mupa = isl_multi_union_pw_aff_align_params(band->mupa,
Packit fb9d21
						isl_space_copy(space));
Packit fb9d21
	band->ast_build_options =
Packit fb9d21
		isl_union_set_align_params(band->ast_build_options, space);
Packit fb9d21
	if (!band->mupa || !band->ast_build_options)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
Packit fb9d21
	return band;
Packit fb9d21
error:
Packit fb9d21
	isl_space_free(space);
Packit fb9d21
	isl_schedule_band_free(band);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Compute the pullback of "band" by the function represented by "upma".
Packit fb9d21
 * In other words, plug in "upma" in the iteration domains of "band".
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_pullback_union_pw_multi_aff(
Packit fb9d21
	__isl_take isl_schedule_band *band,
Packit fb9d21
	__isl_take isl_union_pw_multi_aff *upma)
Packit fb9d21
{
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band || !upma)
Packit fb9d21
		goto error;
Packit fb9d21
Packit fb9d21
	band->mupa =
Packit fb9d21
		isl_multi_union_pw_aff_pullback_union_pw_multi_aff(band->mupa,
Packit fb9d21
									upma);
Packit fb9d21
	if (!band->mupa)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
Packit fb9d21
	return band;
Packit fb9d21
error:
Packit fb9d21
	isl_union_pw_multi_aff_free(upma);
Packit fb9d21
	isl_schedule_band_free(band);
Packit fb9d21
	return NULL;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
/* Compute the gist of "band" with respect to "context".
Packit fb9d21
 * In particular, compute the gist of the associated partial schedule.
Packit fb9d21
 */
Packit fb9d21
__isl_give isl_schedule_band *isl_schedule_band_gist(
Packit fb9d21
	__isl_take isl_schedule_band *band, __isl_take isl_union_set *context)
Packit fb9d21
{
Packit fb9d21
	if (!band || !context)
Packit fb9d21
		goto error;
Packit fb9d21
	if (band->n == 0) {
Packit fb9d21
		isl_union_set_free(context);
Packit fb9d21
		return band;
Packit fb9d21
	}
Packit fb9d21
	band = isl_schedule_band_cow(band);
Packit fb9d21
	if (!band)
Packit fb9d21
		goto error;
Packit fb9d21
	band->mupa = isl_multi_union_pw_aff_gist(band->mupa, context);
Packit fb9d21
	if (!band->mupa)
Packit fb9d21
		return isl_schedule_band_free(band);
Packit fb9d21
	return band;
Packit fb9d21
error:
Packit fb9d21
	isl_union_set_free(context);
Packit fb9d21
	isl_schedule_band_free(band);
Packit fb9d21
	return NULL;
Packit fb9d21
}