Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify construction of parameteric pw affs #25

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ m4/ltsugar.m4
m4/ltversion.m4
m4/lt~obsolete.m4
missing
piplib
py-compile
stamp-h1
test-driver
Expand Down
28 changes: 24 additions & 4 deletions doc/user.pod
Original file line number Diff line number Diff line change
Expand Up @@ -3072,8 +3072,9 @@ created using the following functions.
__isl_take isl_set *set,
__isl_take isl_qpolynomial *qp);

The following convenience functions first create a base expression and
then create a piecewise expression over a universe domain.
The following convenience functions first create a base expression and then
create a piecewise expression over a domain that is a universe set in the given
(local) space.

#include <isl/aff.h>
__isl_give isl_pw_aff *isl_pw_aff_zero_on_domain(
Expand All @@ -3099,6 +3100,18 @@ then create a piecewise expression over a universe domain.
__isl_give isl_pw_qpolynomial *isl_pw_qpolynomial_zero(
__isl_take isl_space *space);

The following convenience functions first create a base expression and then
create a piecewise expression over a universe domain of a parameter space which
contains exactly one parameter dimension corresponding to the given isl id or
zero parameter dimensions in case an expression for a non-parametric constant
value is constructed.

#include <isl/aff.h>
__isl_give isl_pw_aff *isl_pw_aff_param_from_id(__isl_take isl_id *id);
__isl_give isl_pw_aff *isl_pw_aff_val_from_val(__isl_take isl_val *val);
__isl_give isl_pw_aff *isl_pw_aff_val_from_si(__isl_keep isl_ctx *ctx,
int val);

The following convenience functions first create a base expression and
then create a piecewise expression over a given domain.

Expand Down Expand Up @@ -9959,18 +9972,22 @@ Exact division. That is, the result is known to be an integer.

Result of integer division, rounded towards negative
infinity.
The divisor is known to be positive.

=item C<isl_ast_op_pdiv_q>

Result of integer division, where dividend is known to be non-negative.
The divisor is known to be positive.

=item C<isl_ast_op_pdiv_r>

Remainder of integer division, where dividend is known to be non-negative.
The divisor is known to be positive.

=item C<isl_ast_op_zdiv_r>

Equal to zero iff the remainder on integer division is zero.
The divisor is known to be positive.

=item C<isl_ast_op_cond>

Expand Down Expand Up @@ -10139,7 +10156,10 @@ the context of an C<isl_ast_build>.

The function C<isl_ast_expr_address_of> can be applied to an
C<isl_ast_expr> of type C<isl_ast_op_access> only. It is meant
to represent the address of the C<isl_ast_expr_access>. The function
to represent the address of the C<isl_ast_expr_access>.
The second argument of the functions C<isl_ast_expr_pdiv_q> and
C<isl_ast_expr_pdiv_r> should always evaluate to a positive number.
The function
C<isl_ast_expr_and_then> as well as C<isl_ast_expr_or_else> are short-circuit
versions of C<isl_ast_expr_and> and C<isl_ast_expr_or>, respectively.

Expand Down Expand Up @@ -10167,7 +10187,7 @@ versions of C<isl_ast_expr_and> and C<isl_ast_expr_or>, respectively.
__isl_keep isl_ast_build *build,
__isl_take isl_multi_pw_aff *mpa);

The set <set> and
The set C<set> and
the domains of C<pa>, C<mpa> and C<pma> should correspond
to the schedule space of C<build>.
The tuple id of C<mpa> or C<pma> is used as the array being accessed or
Expand Down
5 changes: 5 additions & 0 deletions include/isl/aff.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,11 @@ __isl_give isl_pw_aff *isl_pw_aff_zero_on_domain(
__isl_take isl_local_space *ls);
__isl_give isl_pw_aff *isl_pw_aff_var_on_domain(__isl_take isl_local_space *ls,
enum isl_dim_type type, unsigned pos);

__isl_give isl_pw_aff *isl_pw_aff_param_from_id(__isl_take isl_id *id);
__isl_give isl_pw_aff *isl_pw_aff_val_from_val(__isl_take isl_val *val);
__isl_give isl_pw_aff *isl_pw_aff_val_from_si(__isl_keep isl_ctx *ctx, int val);

__isl_give isl_pw_aff *isl_pw_aff_nan_on_domain(__isl_take isl_local_space *ls);
__isl_give isl_pw_aff *isl_pw_aff_val_on_domain(__isl_take isl_set *domain,
__isl_take isl_val *v);
Expand Down
50 changes: 50 additions & 0 deletions isl_aff.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,56 @@ __isl_give isl_aff *isl_aff_var_on_domain(__isl_take isl_local_space *ls,
return NULL;
}

/* Return a piecewise affine expression defined over a one-dimensional
* parameter space. The identifier of the single parameter dimension is "id".
* The value of the affine expression is equal to the single parameter
* identified by "id".
*/
__isl_give isl_pw_aff *isl_pw_aff_param_from_id(__isl_take isl_id *id)
{
isl_space *space;
isl_aff *aff;

if (!id)
return NULL;

space = isl_space_params_alloc(isl_id_get_ctx(id), 1);
space = isl_space_set_dim_id(space, isl_dim_param, 0, isl_id_copy(id));
aff = isl_aff_param_on_domain_space_id(space, id);

return isl_pw_aff_from_aff(aff);
}

/* Return a piecewise affine expression defined over a zero-dimensional
* parameter space. The value of the affine expression is "val".
*/
__isl_give isl_pw_aff *isl_pw_aff_val_from_val(__isl_take isl_val *val)
{
isl_space *space;

if (!val)
return NULL;

space = isl_space_params_alloc(isl_val_get_ctx(val), 0);

return isl_pw_aff_val_on_domain(isl_set_universe(space), val);
}

/* Return a piecewise affine expression defined over a zero-dimensional
* parameter space. The value of the affine expression is "val".
*/
__isl_give isl_pw_aff *isl_pw_aff_val_from_si(__isl_keep isl_ctx *ctx, int val)
{
isl_val *v;

if (!ctx)
return NULL;

v = isl_val_int_from_si(ctx, v);

return isl_pw_aff_val_from_val(v);
}

/* Return a piecewise affine expression that is equal to
* the specified dimension in "ls".
*/
Expand Down
13 changes: 11 additions & 2 deletions isl_list_templ.c
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,20 @@ int FN(FN(LIST(EL),n),BASE)(__isl_keep LIST(EL) *list)
return list ? list->n : 0;
}

__isl_give EL *FN(FN(LIST(EL),get),BASE)(__isl_keep LIST(EL) *list, int index)
/* Return the element at position "index" in "list".
*/
static __isl_keep EL *FN(LIST(EL),peek)(__isl_keep LIST(EL) *list, int index)
{
if (FN(LIST(EL),check_index)(list, index) < 0)
return NULL;
return FN(EL,copy)(list->p[index]);
return list->p[index];
}

/* Return a copy of the element at position "index" in "list".
*/
__isl_give EL *FN(FN(LIST(EL),get),BASE)(__isl_keep LIST(EL) *list, int index)
{
return FN(EL,copy)(FN(LIST(EL),peek)(list, index));
}

/* Replace the element at position "index" in "list" by "el".
Expand Down
51 changes: 39 additions & 12 deletions isl_multi_templ.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,17 +235,37 @@ __isl_give EL *FN(FN(MULTI(BASE),get),BASE)(__isl_keep MULTI(BASE) *multi,
return FN(EL,copy)(multi->u.p[pos]);
}

/* Set the element at position "pos" of "multi" to "el",
* where the position may be empty if "multi" has only a single reference.
*/
static __isl_give MULTI(BASE) *FN(MULTI(BASE),restore)(
__isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
{
multi = FN(MULTI(BASE),cow)(multi);
if (!multi || !el)
goto error;

if (pos < 0 || pos >= multi->n)
isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
"index out of bounds", goto error);

FN(EL,free)(multi->u.p[pos]);
multi->u.p[pos] = el;

return multi;
error:
FN(MULTI(BASE),free)(multi);
FN(EL,free)(el);
return NULL;
}

__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),set),BASE)(
__isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
{
isl_space *multi_space = NULL;
isl_space *el_space = NULL;
isl_bool match;

multi = FN(MULTI(BASE),cow)(multi);
if (!multi || !el)
goto error;

multi_space = FN(MULTI(BASE),get_space)(multi);
match = FN(EL,matching_params)(el, multi_space);
if (match < 0)
Expand All @@ -260,12 +280,7 @@ __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),set),BASE)(
if (FN(EL,check_match_domain_space)(el, multi_space) < 0)
goto error;

if (pos < 0 || pos >= multi->n)
isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
"index out of bounds", goto error);

FN(EL,free)(multi->u.p[pos]);
multi->u.p[pos] = el;
multi = FN(MULTI(BASE),restore)(multi, pos, el);

isl_space_free(multi_space);
isl_space_free(el_space);
Expand Down Expand Up @@ -514,6 +529,13 @@ __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)(
return NULL;
}

/* Create a multi expression in the given space with the elements of "list"
* as base expressions.
*
* Since isl_multi_*_restore_* assumes that the element and
* the multi expression have matching spaces, the alignment
* (if any) needs to be performed beforehand.
*/
__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))(
__isl_take isl_space *space, __isl_take LIST(EL) *list)
{
Expand All @@ -531,10 +553,15 @@ __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))(
isl_die(ctx, isl_error_invalid,
"invalid number of elements in list", goto error);

for (i = 0; i < n; ++i) {
EL *el = FN(LIST(EL),peek)(list, i);
space = isl_space_align_params(space, FN(EL,get_space)(el));
}
multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
for (i = 0; i < n; ++i) {
multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
FN(FN(LIST(EL),get),BASE)(list, i));
EL *el = FN(FN(LIST(EL),get),BASE)(list, i);
el = FN(EL,align_params)(el, isl_space_copy(space));
multi = FN(MULTI(BASE),restore)(multi, i, el);
}

isl_space_free(space);
Expand Down
103 changes: 102 additions & 1 deletion isl_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -4763,6 +4763,68 @@ static isl_bool union_pw_aff_plain_is_equal(__isl_keep isl_union_pw_aff *upa,
return equal;
}

/* Basic tests on isl_pw_aff.
*
* In particular, test the construction of a single-parameter pw_aff from an id
* or the construction of a zero-parameter pw_aff from an isl val or a signed
* integer.
*/
static isl_stat test_pa(isl_ctx *ctx) {
isl_id *id;
isl_val *val;
isl_pw_aff *pwa, *pwa2;
isl_bool equal;

id = isl_id_alloc(ctx, "P", NULL);
pwa = isl_pw_aff_param_from_id(id);
pwa2 = isl_pw_aff_read_from_str(ctx, "[P] -> { [(P)] }");

equal = isl_pw_aff_plain_is_equal(pwa, pwa2);

isl_pw_aff_free(pwa);
isl_pw_aff_free(pwa2);

if (equal < 0)
return isl_stat_error;
if (!equal)
isl_die(ctx, isl_error_unknown,
"can not construct piecewise aff from id",
return isl_stat_error);

val = isl_val_int_from_si(ctx, 10);
pwa = isl_pw_aff_val_from_val(val);
pwa2 = isl_pw_aff_read_from_str(ctx, "{ [(10)] }");

equal = isl_pw_aff_plain_is_equal(pwa, pwa2);

isl_pw_aff_free(pwa);
isl_pw_aff_free(pwa2);

if (equal < 0)
return isl_stat_error;
if (!equal)
isl_die(ctx, isl_error_unknown,
"can not construct piecewise aff from val",
return isl_stat_error);

pwa = isl_pw_aff_val_from_si(ctx, 10);
pwa2 = isl_pw_aff_read_from_str(ctx, "{ [(10)] }");

equal = isl_pw_aff_plain_is_equal(pwa, pwa2);

isl_pw_aff_free(pwa);
isl_pw_aff_free(pwa2);

if (equal < 0)
return isl_stat_error;
if (!equal)
isl_die(ctx, isl_error_unknown,
"can not construct piecewise aff from signed integer",
return isl_stat_error);

return isl_stat_ok;
}

/* Check that "upa" is obviously equal to the isl_union_pw_aff
* represented by "str".
*/
Expand Down Expand Up @@ -6048,6 +6110,8 @@ int test_aff(isl_ctx *ctx)
isl_aff *aff;
int zero, equal;

if (test_pa(ctx) < 0)
return -1;
if (test_upa(ctx) < 0)
return -1;
if (test_bin_aff(ctx) < 0)
Expand Down Expand Up @@ -7171,7 +7235,7 @@ static int test_residue_class(isl_ctx *ctx)
return res;
}

int test_align_parameters(isl_ctx *ctx)
static int test_align_parameters_1(isl_ctx *ctx)
{
const char *str;
isl_space *space;
Expand Down Expand Up @@ -7202,6 +7266,43 @@ int test_align_parameters(isl_ctx *ctx)
return 0;
}

/* Check the isl_multi_*_from_*_list operation in case inputs
* have unaligned parameters.
* In particular, older versions of isl would simply fail
* (without printing any error message).
*/
static isl_stat test_align_parameters_2(isl_ctx *ctx)
{
isl_space *space;
isl_map *map;
isl_aff *aff;
isl_multi_aff *ma;

map = isl_map_read_from_str(ctx, "{ A[] -> M[x] }");
space = isl_map_get_space(map);
isl_map_free(map);

aff = isl_aff_read_from_str(ctx, "[N] -> { A[] -> [N] }");
ma = isl_multi_aff_from_aff_list(space, isl_aff_list_from_aff(aff));
isl_multi_aff_free(ma);

if (!ma)
return isl_stat_error;
return isl_stat_ok;
}

/* Perform basic parameter alignment tests.
*/
static int test_align_parameters(isl_ctx *ctx)
{
if (test_align_parameters_1(ctx) < 0)
return -1;
if (test_align_parameters_2(ctx) < 0)
return -1;

return 0;
}

/* Check that isl_*_drop_unused_params actually drops the unused parameters
* by comparing the result using isl_*_plain_is_equal.
* Note that this assumes that isl_*_plain_is_equal does not consider
Expand Down