|
Packit |
fb9d21 |
/*
|
|
Packit |
fb9d21 |
* Copyright 2010 INRIA Saclay
|
|
Packit |
fb9d21 |
* Copyright 2013 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_hash_private.h>
|
|
Packit |
fb9d21 |
#include <isl_union_macro.h>
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* A union of expressions defined over different domain spaces.
|
|
Packit |
fb9d21 |
* "space" describes the parameters.
|
|
Packit |
fb9d21 |
* The entries of "table" are keyed on the domain space of the entry.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
struct UNION {
|
|
Packit |
fb9d21 |
int ref;
|
|
Packit |
fb9d21 |
#ifdef HAS_TYPE
|
|
Packit |
fb9d21 |
enum isl_fold type;
|
|
Packit |
fb9d21 |
#endif
|
|
Packit |
fb9d21 |
isl_space *space;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
struct isl_hash_table table;
|
|
Packit |
fb9d21 |
};
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Return the number of base expressions in "u".
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
int FN(FN(UNION,n),PARTS)(__isl_keep UNION *u)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
return u ? u->table.n : 0;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
S(UNION,foreach_data)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
isl_stat (*fn)(__isl_take PART *part, void *user);
|
|
Packit |
fb9d21 |
void *user;
|
|
Packit |
fb9d21 |
};
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
static isl_stat FN(UNION,call_on_copy)(void **entry, void *user)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
PART *part = *entry;
|
|
Packit |
fb9d21 |
S(UNION,foreach_data) *data = (S(UNION,foreach_data) *)user;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
part = FN(PART,copy)(part);
|
|
Packit |
fb9d21 |
if (!part)
|
|
Packit |
fb9d21 |
return isl_stat_error;
|
|
Packit |
fb9d21 |
return data->fn(part, data->user);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
isl_stat FN(FN(UNION,foreach),PARTS)(__isl_keep UNION *u,
|
|
Packit |
fb9d21 |
isl_stat (*fn)(__isl_take PART *part, void *user), void *user)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
S(UNION,foreach_data) data = { fn, user };
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (!u)
|
|
Packit |
fb9d21 |
return isl_stat_error;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return isl_hash_table_foreach(u->space->ctx, &u->table,
|
|
Packit |
fb9d21 |
&FN(UNION,call_on_copy), &data);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Is the domain space of "entry" equal to the domain of "space"?
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static int FN(UNION,has_same_domain_space)(const void *entry, const void *val)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
PART *part = (PART *)entry;
|
|
Packit |
fb9d21 |
isl_space *space = (isl_space *) val;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (isl_space_is_set(space))
|
|
Packit |
fb9d21 |
return isl_space_is_set(part->dim);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return isl_space_tuple_is_equal(part->dim, isl_dim_in,
|
|
Packit |
fb9d21 |
space, isl_dim_in);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Return the entry, if any, in "u" that lives in "space".
|
|
Packit |
fb9d21 |
* If "reserve" is set, then an entry is created if it does not exist yet.
|
|
Packit |
fb9d21 |
* Return NULL on error and isl_hash_table_entry_none if no entry was found.
|
|
Packit |
fb9d21 |
* Note that when "reserve" is set, the function will never return
|
|
Packit |
fb9d21 |
* isl_hash_table_entry_none.
|
|
Packit |
fb9d21 |
*
|
|
Packit |
fb9d21 |
* First look for the entry (if any) with the same domain space.
|
|
Packit |
fb9d21 |
* If it exists, then check if the range space also matches.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static struct isl_hash_table_entry *FN(UNION,find_part_entry)(
|
|
Packit |
fb9d21 |
__isl_keep UNION *u, __isl_keep isl_space *space, int reserve)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
isl_ctx *ctx;
|
|
Packit |
fb9d21 |
uint32_t hash;
|
|
Packit |
fb9d21 |
struct isl_hash_table_entry *entry;
|
|
Packit |
fb9d21 |
isl_bool equal;
|
|
Packit |
fb9d21 |
PART *part;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (!u || !space)
|
|
Packit |
fb9d21 |
return NULL;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
ctx = FN(UNION,get_ctx)(u);
|
|
Packit |
fb9d21 |
hash = isl_space_get_domain_hash(space);
|
|
Packit |
fb9d21 |
entry = isl_hash_table_find(ctx, &u->table, hash,
|
|
Packit |
fb9d21 |
&FN(UNION,has_same_domain_space), space, reserve);
|
|
Packit |
fb9d21 |
if (!entry)
|
|
Packit |
fb9d21 |
return reserve ? NULL : isl_hash_table_entry_none;
|
|
Packit |
fb9d21 |
if (reserve && !entry->data)
|
|
Packit |
fb9d21 |
return entry;
|
|
Packit |
fb9d21 |
part = entry->data;
|
|
Packit |
fb9d21 |
equal = isl_space_tuple_is_equal(part->dim, isl_dim_out,
|
|
Packit |
fb9d21 |
space, isl_dim_out);
|
|
Packit |
fb9d21 |
if (equal < 0)
|
|
Packit |
fb9d21 |
return NULL;
|
|
Packit |
fb9d21 |
if (equal)
|
|
Packit |
fb9d21 |
return entry;
|
|
Packit |
fb9d21 |
if (!reserve)
|
|
Packit |
fb9d21 |
return isl_hash_table_entry_none;
|
|
Packit |
fb9d21 |
isl_die(FN(UNION,get_ctx)(u), isl_error_invalid,
|
|
Packit |
fb9d21 |
"union expression can only contain a single "
|
|
Packit |
fb9d21 |
"expression over a given domain", return NULL);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Remove "part_entry" from the hash table of "u".
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static __isl_give UNION *FN(UNION,remove_part_entry)(__isl_take UNION *u,
|
|
Packit |
fb9d21 |
struct isl_hash_table_entry *part_entry)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
isl_ctx *ctx;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (!u || !part_entry)
|
|
Packit |
fb9d21 |
return FN(UNION,free)(u);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
ctx = FN(UNION,get_ctx)(u);
|
|
Packit |
fb9d21 |
isl_hash_table_remove(ctx, &u->table, part_entry);
|
|
Packit |
fb9d21 |
FN(PART,free)(part_entry->data);
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
return u;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Check that the domain of "part" is disjoint from the domain of the entries
|
|
Packit |
fb9d21 |
* in "u" that are defined on the same domain space, but have a different
|
|
Packit |
fb9d21 |
* target space.
|
|
Packit |
fb9d21 |
* Since a UNION with a single entry per domain space is not allowed
|
|
Packit |
fb9d21 |
* to contain two entries with the same domain space, there cannot be
|
|
Packit |
fb9d21 |
* any such other entry.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static isl_stat FN(UNION,check_disjoint_domain_other)(__isl_keep UNION *u,
|
|
Packit |
fb9d21 |
__isl_keep PART *part)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
return isl_stat_ok;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Check that the domain of "part1" is disjoint from the domain of "part2".
|
|
Packit |
fb9d21 |
* This check is performed before "part2" is added to a UNION to ensure
|
|
Packit |
fb9d21 |
* that the UNION expression remains a function.
|
|
Packit |
fb9d21 |
* Since a UNION with a single entry per domain space is not allowed
|
|
Packit |
fb9d21 |
* to contain two entries with the same domain space, fail unconditionally.
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static isl_stat FN(UNION,check_disjoint_domain)(__isl_keep PART *part1,
|
|
Packit |
fb9d21 |
__isl_keep PART *part2)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
isl_die(FN(PART,get_ctx)(part1), isl_error_invalid,
|
|
Packit |
fb9d21 |
"additional part should live on separate space",
|
|
Packit |
fb9d21 |
return isl_stat_error);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Call "fn" on each part entry of "u".
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static isl_stat FN(UNION,foreach_inplace)(__isl_keep UNION *u,
|
|
Packit |
fb9d21 |
isl_stat (*fn)(void **part, void *user), void *user)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
isl_ctx *ctx;
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
if (!u)
|
|
Packit |
fb9d21 |
return isl_stat_error;
|
|
Packit |
fb9d21 |
ctx = FN(UNION,get_ctx)(u);
|
|
Packit |
fb9d21 |
return isl_hash_table_foreach(ctx, &u->table, fn, user);
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
/* Does "u" have a single reference?
|
|
Packit |
fb9d21 |
* That is, can we change "u" inplace?
|
|
Packit |
fb9d21 |
*/
|
|
Packit |
fb9d21 |
static isl_bool FN(UNION,has_single_reference)(__isl_keep UNION *u)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
if (!u)
|
|
Packit |
fb9d21 |
return isl_bool_error;
|
|
Packit |
fb9d21 |
return u->ref == 1;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
static isl_stat FN(UNION,free_u_entry)(void **entry, void *user)
|
|
Packit |
fb9d21 |
{
|
|
Packit |
fb9d21 |
PART *part = *entry;
|
|
Packit |
fb9d21 |
FN(PART,free)(part);
|
|
Packit |
fb9d21 |
return isl_stat_ok;
|
|
Packit |
fb9d21 |
}
|
|
Packit |
fb9d21 |
|
|
Packit |
fb9d21 |
#include <isl_union_templ.c>
|