buildtools/gcc/isl/isl_multi_templ.c
Adrien Destugues 680f0e1112 import ISL 0.24
2022-07-15 15:05:28 +02:00

907 lines
23 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright 2011 Sven Verdoolaege
* Copyright 2012-2014 Ecole Normale Superieure
*
* Use of this software is governed by the MIT license
*
* Written by Sven Verdoolaege,
* Ecole Normale Superieure, 45 rue dUlm, 75230 Paris, France
*/
#include <isl/id.h>
#include <isl_space_private.h>
#include <isl/set.h>
#include <isl_reordering.h>
#include <isl_multi_macro.h>
#define MULTI_NAME(BASE) "isl_multi_" #BASE
isl_ctx *FN(MULTI(BASE),get_ctx)(__isl_keep MULTI(BASE) *multi)
{
return multi ? isl_space_get_ctx(multi->space) : NULL;
}
/* Return the space of "multi".
*/
__isl_keep isl_space *FN(MULTI(BASE),peek_space)(__isl_keep MULTI(BASE) *multi)
{
return multi ? multi->space : NULL;
}
__isl_give isl_space *FN(MULTI(BASE),get_space)(__isl_keep MULTI(BASE) *multi)
{
return isl_space_copy(FN(MULTI(BASE),peek_space)(multi));
}
__isl_give isl_space *FN(MULTI(BASE),get_domain_space)(
__isl_keep MULTI(BASE) *multi)
{
return multi ? isl_space_domain(isl_space_copy(multi->space)) : NULL;
}
/* Allocate a multi expression living in "space".
*
* If the number of base expressions is zero, then make sure
* there is enough room in the structure for the explicit domain,
* in case the type supports such an explicit domain.
*/
__isl_give MULTI(BASE) *FN(MULTI(BASE),alloc)(__isl_take isl_space *space)
{
isl_ctx *ctx;
isl_size n;
MULTI(BASE) *multi;
n = isl_space_dim(space, isl_dim_out);
if (n < 0)
goto error;
ctx = isl_space_get_ctx(space);
if (n > 0)
multi = isl_calloc(ctx, MULTI(BASE),
sizeof(MULTI(BASE)) + (n - 1) * sizeof(struct EL *));
else
multi = isl_calloc(ctx, MULTI(BASE), sizeof(MULTI(BASE)));
if (!multi)
goto error;
multi->space = space;
multi->n = n;
multi->ref = 1;
if (FN(MULTI(BASE),has_explicit_domain)(multi))
multi = FN(MULTI(BASE),init_explicit_domain)(multi);
return multi;
error:
isl_space_free(space);
return NULL;
}
__isl_give MULTI(BASE) *FN(MULTI(BASE),dup)(__isl_keep MULTI(BASE) *multi)
{
int i;
MULTI(BASE) *dup;
if (!multi)
return NULL;
dup = FN(MULTI(BASE),alloc)(isl_space_copy(multi->space));
if (!dup)
return NULL;
for (i = 0; i < multi->n; ++i)
dup = FN(FN(MULTI(BASE),set),BASE)(dup, i,
FN(EL,copy)(multi->u.p[i]));
if (FN(MULTI(BASE),has_explicit_domain)(multi))
dup = FN(MULTI(BASE),copy_explicit_domain)(dup, multi);
return dup;
}
__isl_give MULTI(BASE) *FN(MULTI(BASE),cow)(__isl_take MULTI(BASE) *multi)
{
if (!multi)
return NULL;
if (multi->ref == 1)
return multi;
multi->ref--;
return FN(MULTI(BASE),dup)(multi);
}
__isl_give MULTI(BASE) *FN(MULTI(BASE),copy)(__isl_keep MULTI(BASE) *multi)
{
if (!multi)
return NULL;
multi->ref++;
return multi;
}
__isl_null MULTI(BASE) *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi)
{
int i;
if (!multi)
return NULL;
if (--multi->ref > 0)
return NULL;
isl_space_free(multi->space);
for (i = 0; i < multi->n; ++i)
FN(EL,free)(multi->u.p[i]);
if (FN(MULTI(BASE),has_explicit_domain)(multi))
FN(MULTI(BASE),free_explicit_domain)(multi);
free(multi);
return NULL;
}
isl_size FN(MULTI(BASE),dim)(__isl_keep MULTI(BASE) *multi,
enum isl_dim_type type)
{
return isl_space_dim(FN(MULTI(BASE),peek_space)(multi), type);
}
/* Return the number of base expressions in "multi".
*/
isl_size FN(MULTI(BASE),size)(__isl_keep MULTI(BASE) *multi)
{
return multi ? multi->n : isl_size_error;
}
#undef TYPE
#define TYPE MULTI(BASE)
static
#include "check_type_range_templ.c"
/* Return a copy of the base expression at position "pos" in "multi".
*/
__isl_give EL *FN(MULTI(BASE),get_at)(__isl_keep MULTI(BASE) *multi, int pos)
{
isl_ctx *ctx;
if (FN(MULTI(BASE),check_range)(multi, isl_dim_out, pos, 1) < 0)
return NULL;
ctx = FN(MULTI(BASE),get_ctx)(multi);
return FN(EL,copy)(multi->u.p[pos]);
}
/* This is an alternative name for the function above.
*/
__isl_give EL *FN(FN(MULTI(BASE),get),BASE)(__isl_keep MULTI(BASE) *multi,
int pos)
{
return FN(MULTI(BASE),get_at)(multi, 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 (FN(MULTI(BASE),check_range)(multi, isl_dim_out, pos, 1) < 0)
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;
}
/* Set the element at position "pos" of "multi" to "el",
* where the position may be empty if "multi" has only a single reference.
* However, the space of "multi" is available and is checked
* for compatibility with "el".
*/
static __isl_give MULTI(BASE) *FN(MULTI(BASE),restore_check_space)(
__isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
{
isl_space *space;
space = FN(MULTI(BASE),peek_space)(multi);
if (FN(EL,check_match_domain_space)(el, space) < 0)
multi = FN(MULTI(BASE),free)(multi);
return FN(MULTI(BASE),restore)(multi, pos, el);
}
/* Replace the base expression at position "pos" in "multi" with "el".
*/
__isl_give MULTI(BASE) *FN(MULTI(BASE),set_at)(
__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_space = FN(MULTI(BASE),get_space)(multi);
match = FN(EL,matching_params)(el, multi_space);
if (match < 0)
goto error;
if (!match) {
multi = FN(MULTI(BASE),align_params)(multi,
FN(EL,get_space)(el));
isl_space_free(multi_space);
multi_space = FN(MULTI(BASE),get_space)(multi);
el = FN(EL,align_params)(el, isl_space_copy(multi_space));
}
multi = FN(MULTI(BASE),restore_check_space)(multi, pos, el);
isl_space_free(multi_space);
isl_space_free(el_space);
return multi;
error:
FN(MULTI(BASE),free)(multi);
FN(EL,free)(el);
isl_space_free(multi_space);
isl_space_free(el_space);
return NULL;
}
/* This is an alternative name for the function above.
*/
__isl_give MULTI(BASE) *FN(FN(MULTI(BASE),set),BASE)(
__isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
{
return FN(MULTI(BASE),set_at)(multi, pos, el);
}
/* Return the base expressions of "multi" as a list.
*/
__isl_give LIST(EL) *FN(MULTI(BASE),get_list)(
__isl_keep MULTI(BASE) *multi)
{
isl_size n;
int i;
LIST(EL) *list;
n = FN(MULTI(BASE),size)(multi);
if (n < 0)
return NULL;
list = FN(LIST(EL),alloc)(FN(MULTI(BASE),get_ctx(multi)), n);
for (i = 0; i < n; ++i) {
EL *el = FN(MULTI(BASE),get_at)(multi, i);
list = FN(LIST(EL),add)(list, el);
}
return list;
}
/* Reset the space of "multi". This function is called from isl_pw_templ.c
* and doesn't know if the space of an element object is represented
* directly or through its domain. It therefore passes along both,
* which we pass along to the element function since we don't know how
* that is represented either.
*
* If "multi" has an explicit domain, then the caller is expected
* to make sure that any modification that would change the dimensions
* of the explicit domain has bee applied before this function is called.
*/
__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space_and_domain)(
__isl_take MULTI(BASE) *multi, __isl_take isl_space *space,
__isl_take isl_space *domain)
{
int i;
multi = FN(MULTI(BASE),cow)(multi);
if (!multi || !space || !domain)
goto error;
for (i = 0; i < multi->n; ++i) {
multi->u.p[i] = FN(EL,reset_domain_space)(multi->u.p[i],
isl_space_copy(domain));
if (!multi->u.p[i])
goto error;
}
if (FN(MULTI(BASE),has_explicit_domain)(multi)) {
multi = FN(MULTI(BASE),reset_explicit_domain_space)(multi,
isl_space_copy(domain));
if (!multi)
goto error;
}
isl_space_free(domain);
isl_space_free(multi->space);
multi->space = space;
return multi;
error:
isl_space_free(domain);
isl_space_free(space);
FN(MULTI(BASE),free)(multi);
return NULL;
}
__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_domain_space)(
__isl_take MULTI(BASE) *multi, __isl_take isl_space *domain)
{
isl_space *space;
space = isl_space_extend_domain_with_range(isl_space_copy(domain),
isl_space_copy(multi->space));
return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
}
__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space)(
__isl_take MULTI(BASE) *multi, __isl_take isl_space *space)
{
isl_space *domain;
domain = isl_space_domain(isl_space_copy(space));
return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
}
/* Reset the user pointer on all identifiers of parameters and tuples
* of the space of "multi".
*/
__isl_give MULTI(BASE) *FN(MULTI(BASE),reset_user)(
__isl_take MULTI(BASE) *multi)
{
isl_space *space;
space = FN(MULTI(BASE),get_space)(multi);
space = isl_space_reset_user(space);
return FN(MULTI(BASE),reset_space)(multi, space);
}
__isl_give MULTI(BASE) *FN(MULTI(BASE),realign_domain)(
__isl_take MULTI(BASE) *multi, __isl_take isl_reordering *exp)
{
int i;
isl_space *space;
multi = FN(MULTI(BASE),cow)(multi);
if (!multi || !exp)
goto error;
for (i = 0; i < multi->n; ++i) {
multi->u.p[i] = FN(EL,realign_domain)(multi->u.p[i],
isl_reordering_copy(exp));
if (!multi->u.p[i])
goto error;
}
space = isl_reordering_get_space(exp);
multi = FN(MULTI(BASE),reset_domain_space)(multi, space);
isl_reordering_free(exp);
return multi;
error:
isl_reordering_free(exp);
FN(MULTI(BASE),free)(multi);
return NULL;
}
/* Align the parameters of "multi" to those of "model".
*
* If "multi" has an explicit domain, then align the parameters
* of the domain first.
*/
__isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)(
__isl_take MULTI(BASE) *multi, __isl_take isl_space *model)
{
isl_ctx *ctx;
isl_bool equal_params;
isl_reordering *exp;
if (!multi || !model)
goto error;
equal_params = isl_space_has_equal_params(multi->space, model);
if (equal_params < 0)
goto error;
if (equal_params) {
isl_space_free(model);
return multi;
}
ctx = isl_space_get_ctx(model);
if (!isl_space_has_named_params(model))
isl_die(ctx, isl_error_invalid,
"model has unnamed parameters", goto error);
if (!isl_space_has_named_params(multi->space))
isl_die(ctx, isl_error_invalid,
"input has unnamed parameters", goto error);
if (FN(MULTI(BASE),has_explicit_domain)(multi)) {
multi = FN(MULTI(BASE),align_explicit_domain_params)(multi,
isl_space_copy(model));
if (!multi)
goto error;
}
exp = isl_parameter_alignment_reordering(multi->space, model);
exp = isl_reordering_extend_space(exp,
FN(MULTI(BASE),get_domain_space)(multi));
multi = FN(MULTI(BASE),realign_domain)(multi, exp);
isl_space_free(model);
return multi;
error:
isl_space_free(model);
FN(MULTI(BASE),free)(multi);
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)
{
int i;
isl_size n, dim;
isl_ctx *ctx;
MULTI(BASE) *multi;
dim = isl_space_dim(space, isl_dim_out);
n = FN(FN(LIST(EL),n),BASE)(list);
if (dim < 0 || n < 0)
goto error;
ctx = isl_space_get_ctx(space);
if (n != dim)
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) {
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_check_space)(multi, i, el);
}
isl_space_free(space);
FN(LIST(EL),free)(list);
return multi;
error:
isl_space_free(space);
FN(LIST(EL),free)(list);
return NULL;
}
/* This function performs the same operation as isl_multi_*_from_*_list,
* but is considered as a function on an isl_space when exported.
*/
__isl_give MULTI(BASE) *FN(isl_space_multi,BASE)(__isl_take isl_space *space,
__isl_take LIST(EL) *list)
{
return FN(FN(MULTI(BASE),from),LIST(BASE))(space, list);
}
__isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)(
__isl_take MULTI(BASE) *multi,
enum isl_dim_type type, unsigned first, unsigned n)
{
int i;
multi = FN(MULTI(BASE),cow)(multi);
if (FN(MULTI(BASE),check_range)(multi, type, first, n) < 0)
return FN(MULTI(BASE),free)(multi);
multi->space = isl_space_drop_dims(multi->space, type, first, n);
if (!multi->space)
return FN(MULTI(BASE),free)(multi);
if (type == isl_dim_out) {
for (i = 0; i < n; ++i)
FN(EL,free)(multi->u.p[first + i]);
for (i = first; i + n < multi->n; ++i)
multi->u.p[i] = multi->u.p[i + n];
multi->n -= n;
if (n > 0 && FN(MULTI(BASE),has_explicit_domain)(multi))
multi = FN(MULTI(BASE),init_explicit_domain)(multi);
return multi;
}
if (FN(MULTI(BASE),has_explicit_domain)(multi))
multi = FN(MULTI(BASE),drop_explicit_domain_dims)(multi,
type, first, n);
if (!multi)
return NULL;
for (i = 0; i < multi->n; ++i) {
multi->u.p[i] = FN(EL,drop_dims)(multi->u.p[i], type, first, n);
if (!multi->u.p[i])
return FN(MULTI(BASE),free)(multi);
}
return multi;
}
#undef TYPE
#define TYPE MULTI(BASE)
#include "isl_check_named_params_templ.c"
static
#include "isl_align_params_bin_templ.c"
/* Given two MULTI(BASE)s A -> B and C -> D,
* construct a MULTI(BASE) (A * C) -> [B -> D].
*
* If "multi1" and/or "multi2" has an explicit domain, then
* intersect the domain of the result with these explicit domains.
*/
__isl_give MULTI(BASE) *FN(MULTI(BASE),range_product)(
__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
{
int i;
isl_size n1, n2;
EL *el;
isl_space *space;
MULTI(BASE) *res;
FN(MULTI(BASE),align_params_bin)(&multi1, &multi2);
n1 = FN(MULTI(BASE),size)(multi1);
n2 = FN(MULTI(BASE),size)(multi2);
if (n1 < 0 || n2 < 0)
goto error;
space = isl_space_range_product(FN(MULTI(BASE),get_space)(multi1),
FN(MULTI(BASE),get_space)(multi2));
res = FN(MULTI(BASE),alloc)(space);
for (i = 0; i < n1; ++i) {
el = FN(FN(MULTI(BASE),get),BASE)(multi1, i);
res = FN(FN(MULTI(BASE),set),BASE)(res, i, el);
}
for (i = 0; i < n2; ++i) {
el = FN(FN(MULTI(BASE),get),BASE)(multi2, i);
res = FN(FN(MULTI(BASE),set),BASE)(res, n1 + i, el);
}
if (FN(MULTI(BASE),has_explicit_domain)(multi1))
res = FN(MULTI(BASE),intersect_explicit_domain)(res, multi1);
if (FN(MULTI(BASE),has_explicit_domain)(multi2))
res = FN(MULTI(BASE),intersect_explicit_domain)(res, multi2);
FN(MULTI(BASE),free)(multi1);
FN(MULTI(BASE),free)(multi2);
return res;
error:
FN(MULTI(BASE),free)(multi1);
FN(MULTI(BASE),free)(multi2);
return NULL;
}
/* Is the range of "multi" a wrapped relation?
*/
isl_bool FN(MULTI(BASE),range_is_wrapping)(__isl_keep MULTI(BASE) *multi)
{
if (!multi)
return isl_bool_error;
return isl_space_range_is_wrapping(multi->space);
}
/* Given a function A -> [B -> C], extract the function A -> B.
*/
__isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_domain)(
__isl_take MULTI(BASE) *multi)
{
isl_space *space;
isl_size total, keep;
total = FN(MULTI(BASE),dim)(multi, isl_dim_out);
if (total < 0)
return FN(MULTI(BASE),free)(multi);
if (!isl_space_range_is_wrapping(multi->space))
isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
"range is not a product",
return FN(MULTI(BASE),free)(multi));
space = FN(MULTI(BASE),get_space)(multi);
space = isl_space_range_factor_domain(space);
keep = isl_space_dim(space, isl_dim_out);
if (keep < 0)
multi = FN(MULTI(BASE),free)(multi);
multi = FN(MULTI(BASE),drop_dims)(multi,
isl_dim_out, keep, total - keep);
multi = FN(MULTI(BASE),reset_space)(multi, space);
return multi;
}
/* Given a function A -> [B -> C], extract the function A -> C.
*/
__isl_give MULTI(BASE) *FN(MULTI(BASE),range_factor_range)(
__isl_take MULTI(BASE) *multi)
{
isl_space *space;
isl_size total, keep;
total = FN(MULTI(BASE),dim)(multi, isl_dim_out);
if (total < 0)
return FN(MULTI(BASE),free)(multi);
if (!isl_space_range_is_wrapping(multi->space))
isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
"range is not a product",
return FN(MULTI(BASE),free)(multi));
space = FN(MULTI(BASE),get_space)(multi);
space = isl_space_range_factor_range(space);
keep = isl_space_dim(space, isl_dim_out);
if (keep < 0)
multi = FN(MULTI(BASE),free)(multi);
multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_out, 0, total - keep);
multi = FN(MULTI(BASE),reset_space)(multi, space);
return multi;
}
/* Given a function [B -> C], extract the function C.
*/
__isl_give MULTI(BASE) *FN(MULTI(BASE),factor_range)(
__isl_take MULTI(BASE) *multi)
{
isl_space *space;
isl_size total, keep;
total = FN(MULTI(BASE),dim)(multi, isl_dim_set);
if (total < 0)
return FN(MULTI(BASE),free)(multi);
if (!isl_space_is_wrapping(multi->space))
isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
"not a product", return FN(MULTI(BASE),free)(multi));
space = FN(MULTI(BASE),get_space)(multi);
space = isl_space_factor_range(space);
keep = isl_space_dim(space, isl_dim_set);
if (keep < 0)
multi = FN(MULTI(BASE),free)(multi);
multi = FN(MULTI(BASE),drop_dims)(multi, isl_dim_set, 0, total - keep);
multi = FN(MULTI(BASE),reset_space)(multi, space);
return multi;
}
__isl_give MULTI(BASE) *FN(MULTI(BASE),flatten_range)(
__isl_take MULTI(BASE) *multi)
{
if (!multi)
return NULL;
if (!multi->space->nested[1])
return multi;
multi = FN(MULTI(BASE),cow)(multi);
if (!multi)
return NULL;
multi->space = isl_space_flatten_range(multi->space);
if (!multi->space)
return FN(MULTI(BASE),free)(multi);
return multi;
}
/* Given two MULTI(BASE)s A -> B and C -> D,
* construct a MULTI(BASE) (A * C) -> (B, D).
*/
__isl_give MULTI(BASE) *FN(MULTI(BASE),flat_range_product)(
__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2)
{
MULTI(BASE) *multi;
multi = FN(MULTI(BASE),range_product)(multi1, multi2);
multi = FN(MULTI(BASE),flatten_range)(multi);
return multi;
}
/* Given two multi expressions, "multi1"
*
* [A] -> [B1 B2]
*
* where B2 starts at position "pos", and "multi2"
*
* [A] -> [D]
*
* return the multi expression
*
* [A] -> [B1 D B2]
*/
__isl_give MULTI(BASE) *FN(MULTI(BASE),range_splice)(
__isl_take MULTI(BASE) *multi1, unsigned pos,
__isl_take MULTI(BASE) *multi2)
{
MULTI(BASE) *res;
isl_size dim;
dim = FN(MULTI(BASE),size)(multi1);
if (dim < 0 || !multi2)
goto error;
if (FN(MULTI(BASE),check_range)(multi1, isl_dim_out, pos, 0) < 0)
goto error;
res = FN(MULTI(BASE),copy)(multi1);
res = FN(MULTI(BASE),drop_dims)(res, isl_dim_out, pos, dim - pos);
multi1 = FN(MULTI(BASE),drop_dims)(multi1, isl_dim_out, 0, pos);
res = FN(MULTI(BASE),flat_range_product)(res, multi2);
res = FN(MULTI(BASE),flat_range_product)(res, multi1);
return res;
error:
FN(MULTI(BASE),free)(multi1);
FN(MULTI(BASE),free)(multi2);
return NULL;
}
#undef TYPE
#define TYPE MULTI(BASE)
static
#include "isl_type_has_equal_space_bin_templ.c"
static
#include "isl_type_check_equal_space_templ.c"
/* This function is currently only used from isl_aff.c
*/
static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
__isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
__attribute__ ((unused));
/* Pairwise perform "fn" to the elements of "multi1" and "multi2" and
* return the result.
*
* If "multi2" has an explicit domain, then
* intersect the domain of the result with this explicit domain.
*/
static __isl_give MULTI(BASE) *FN(MULTI(BASE),bin_op)(
__isl_take MULTI(BASE) *multi1, __isl_take MULTI(BASE) *multi2,
__isl_give EL *(*fn)(__isl_take EL *, __isl_take EL *))
{
int i;
FN(MULTI(BASE),align_params_bin)(&multi1, &multi2);
multi1 = FN(MULTI(BASE),cow)(multi1);
if (FN(MULTI(BASE),check_equal_space)(multi1, multi2) < 0)
goto error;
for (i = 0; i < multi1->n; ++i) {
multi1->u.p[i] = fn(multi1->u.p[i],
FN(EL,copy)(multi2->u.p[i]));
if (!multi1->u.p[i])
goto error;
}
if (FN(MULTI(BASE),has_explicit_domain)(multi2))
multi1 = FN(MULTI(BASE),intersect_explicit_domain)(multi1,
multi2);
FN(MULTI(BASE),free)(multi2);
return multi1;
error:
FN(MULTI(BASE),free)(multi1);
FN(MULTI(BASE),free)(multi2);
return NULL;
}
/* Only used on some multi-expressions.
*/
static isl_bool FN(MULTI(BASE),any)(__isl_keep MULTI(BASE) *multi,
isl_bool (*test)(__isl_keep EL *)) __attribute__ ((unused));
/* Does "test" succeed on any base expression of "multi"?
*/
static isl_bool FN(MULTI(BASE),any)(__isl_keep MULTI(BASE) *multi,
isl_bool (*test)(__isl_keep EL *))
{
isl_size n;
int i;
n = FN(MULTI(BASE),size)(multi);
if (n < 0)
return isl_bool_error;
for (i = 0; i < n; ++i) {
isl_bool any = test(multi->u.p[i]);
if (any < 0 || any)
return any;
}
return isl_bool_false;
}
/* Only used on some multi-expressions.
*/
static isl_bool FN(MULTI(BASE),every)(__isl_keep MULTI(BASE) *multi,
isl_bool (*test)(__isl_keep EL *)) __attribute__ ((unused));
/* Does "test" succeed on every base expression of "multi"?
*/
static isl_bool FN(MULTI(BASE),every)(__isl_keep MULTI(BASE) *multi,
isl_bool (*test)(__isl_keep EL *))
{
isl_size n;
int i;
n = FN(MULTI(BASE),size)(multi);
if (n < 0)
return isl_bool_error;
for (i = 0; i < n; ++i) {
isl_bool every = test(multi->u.p[i]);
if (every < 0 || !every)
return every;
}
return isl_bool_true;
}
/* Convert a multiple expression defined over a parameter domain
* into one that is defined over a zero-dimensional set.
*/
__isl_give MULTI(BASE) *FN(MULTI(BASE),from_range)(
__isl_take MULTI(BASE) *multi)
{
isl_space *space;
if (!multi)
return NULL;
if (!isl_space_is_set(multi->space))
isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
"not living in a set space",
return FN(MULTI(BASE),free)(multi));
space = FN(MULTI(BASE),get_space)(multi);
space = isl_space_from_range(space);
multi = FN(MULTI(BASE),reset_space)(multi, space);
return multi;
}
/* Are "multi1" and "multi2" obviously equal?
*/
isl_bool FN(MULTI(BASE),plain_is_equal)(__isl_keep MULTI(BASE) *multi1,
__isl_keep MULTI(BASE) *multi2)
{
int i;
isl_bool equal;
if (!multi1 || !multi2)
return isl_bool_error;
if (multi1->n != multi2->n)
return isl_bool_false;
equal = isl_space_is_equal(multi1->space, multi2->space);
if (equal < 0 || !equal)
return equal;
for (i = 0; i < multi1->n; ++i) {
equal = FN(EL,plain_is_equal)(multi1->u.p[i], multi2->u.p[i]);
if (equal < 0 || !equal)
return equal;
}
if (FN(MULTI(BASE),has_explicit_domain)(multi1) ||
FN(MULTI(BASE),has_explicit_domain)(multi2)) {
equal = FN(MULTI(BASE),equal_explicit_domain)(multi1, multi2);
if (equal < 0 || !equal)
return equal;
}
return isl_bool_true;
}