brintos

brintos / llvm-project-archived public Read only

0
0
Text · 122.3 KiB · eaafe18 Raw
4611 lines · c
1/*2 * Copyright 2010-2011 INRIA Saclay3 * Copyright 2013-2014 Ecole Normale Superieure4 * Copyright 2014      INRIA Rocquencourt5 * Copyright 2016-2017 Sven Verdoolaege6 *7 * Use of this software is governed by the MIT license8 *9 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,10 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,11 * 91893 Orsay, France 12 * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,13 * B.P. 105 - 78153 Le Chesnay, France14 */15 16#include <isl_map_private.h>17#include <isl_union_map_private.h>18#include <isl/ctx.h>19#include <isl/hash.h>20#include <isl_aff_private.h>21#include <isl/map.h>22#include <isl/set.h>23#include <isl_space_private.h>24#include <isl/union_set.h>25#include <isl_maybe_map.h>26#include <isl_id_private.h>27 28#include <bset_from_bmap.c>29#include <set_to_map.c>30#include <set_from_map.c>31#include <uset_to_umap.c>32#include <uset_from_umap.c>33#include <set_list_from_map_list_inl.c>34 35#undef TYPE36#define TYPE	isl_union_map37static38#include "has_single_reference_templ.c"39static40#include "check_single_reference_templ.c"41 42/* Return the number of parameters of "umap", where "type"43 * is required to be set to isl_dim_param.44 */45isl_size isl_union_map_dim(__isl_keep isl_union_map *umap,46	enum isl_dim_type type)47{48	if (!umap)49		return isl_size_error;50 51	if (type != isl_dim_param)52		isl_die(isl_union_map_get_ctx(umap), isl_error_invalid,53			"can only reference parameters", return isl_size_error);54 55	return isl_space_dim(umap->dim, type);56}57 58/* Return the number of parameters of "uset", where "type"59 * is required to be set to isl_dim_param.60 */61isl_size isl_union_set_dim(__isl_keep isl_union_set *uset,62	enum isl_dim_type type)63{64	return isl_union_map_dim(uset, type);65}66 67/* Return the id of the specified dimension.68 */69__isl_give isl_id *isl_union_map_get_dim_id(__isl_keep isl_union_map *umap,70	enum isl_dim_type type, unsigned pos)71{72	if (!umap)73		return NULL;74 75	if (type != isl_dim_param)76		isl_die(isl_union_map_get_ctx(umap), isl_error_invalid,77			"can only reference parameters", return NULL);78 79	return isl_space_get_dim_id(umap->dim, type, pos);80}81 82/* Is this union set a parameter domain?83 */84isl_bool isl_union_set_is_params(__isl_keep isl_union_set *uset)85{86	isl_set *set;87	isl_bool params;88 89	if (!uset)90		return isl_bool_error;91	if (uset->table.n != 1)92		return isl_bool_false;93 94	set = isl_set_from_union_set(isl_union_set_copy(uset));95	params = isl_set_is_params(set);96	isl_set_free(set);97	return params;98}99 100/* Is this union map actually a parameter domain?101 * Users should never call this function.  Outside of isl,102 * a union map can never be a parameter domain.103 */104isl_bool isl_union_map_is_params(__isl_keep isl_union_map *umap)105{106	return isl_union_set_is_params(uset_from_umap(umap));107}108 109static __isl_give isl_union_map *isl_union_map_alloc(110	__isl_take isl_space *space, int size)111{112	isl_union_map *umap;113 114	space = isl_space_params(space);115	if (!space)116		return NULL;117 118	umap = isl_calloc_type(space->ctx, isl_union_map);119	if (!umap) {120		isl_space_free(space);121		return NULL;122	}123 124	umap->ref = 1;125	umap->dim = space;126	if (isl_hash_table_init(space->ctx, &umap->table, size) < 0)127		return isl_union_map_free(umap);128 129	return umap;130}131 132/* Create an empty union map without specifying any parameters.133 */134__isl_give isl_union_map *isl_union_map_empty_ctx(isl_ctx *ctx)135{136	return isl_union_map_empty_space(isl_space_unit(ctx));137}138 139__isl_give isl_union_map *isl_union_map_empty_space(__isl_take isl_space *space)140{141	return isl_union_map_alloc(space, 16);142}143 144/* This is an alternative name for the function above.145 */146__isl_give isl_union_map *isl_union_map_empty(__isl_take isl_space *space)147{148	return isl_union_map_empty_space(space);149}150 151/* Create an empty union set without specifying any parameters.152 */153__isl_give isl_union_set *isl_union_set_empty_ctx(isl_ctx *ctx)154{155	return uset_from_umap(isl_union_map_empty_ctx(ctx));156}157 158__isl_give isl_union_set *isl_union_set_empty_space(__isl_take isl_space *space)159{160	return uset_from_umap(isl_union_map_empty_space(space));161}162 163/* This is an alternative name for the function above.164 */165__isl_give isl_union_set *isl_union_set_empty(__isl_take isl_space *space)166{167	return isl_union_set_empty_space(space);168}169 170isl_ctx *isl_union_map_get_ctx(__isl_keep isl_union_map *umap)171{172	return umap ? umap->dim->ctx : NULL;173}174 175isl_ctx *isl_union_set_get_ctx(__isl_keep isl_union_set *uset)176{177	return uset ? uset->dim->ctx : NULL;178}179 180/* Return the space of "umap".181 */182__isl_keep isl_space *isl_union_map_peek_space(__isl_keep isl_union_map *umap)183{184	return umap ? umap->dim : NULL;185}186 187/* Return the space of "uset".188 */189__isl_keep isl_space *isl_union_set_peek_space(__isl_keep isl_union_set *uset)190{191	return isl_union_map_peek_space(uset_to_umap(uset));192}193 194__isl_give isl_space *isl_union_map_get_space(__isl_keep isl_union_map *umap)195{196	return isl_space_copy(isl_union_map_peek_space(umap));197}198 199/* Return the position of the parameter with the given name200 * in "umap".201 * Return -1 if no such dimension can be found.202 */203int isl_union_map_find_dim_by_name(__isl_keep isl_union_map *umap,204	enum isl_dim_type type, const char *name)205{206	if (!umap)207		return -1;208	return isl_space_find_dim_by_name(umap->dim, type, name);209}210 211/* Return the position of the parameter with id "id" in "umap".212 * Return -1 if no such dimension can be found.213 */214static int isl_union_map_find_dim_by_id(__isl_keep isl_union_map *umap,215	enum isl_dim_type type, __isl_keep isl_id *id)216{217	isl_space *space;218 219	space = isl_union_map_peek_space(umap);220	return isl_space_find_dim_by_id(space, type, id);221}222 223__isl_give isl_space *isl_union_set_get_space(__isl_keep isl_union_set *uset)224{225	return isl_union_map_get_space(uset);226}227 228static isl_stat free_umap_entry(void **entry, void *user)229{230	isl_map *map = *entry;231	isl_map_free(map);232	return isl_stat_ok;233}234 235static isl_stat add_map(__isl_take isl_map *map, void *user)236{237	isl_union_map **umap = (isl_union_map **)user;238 239	*umap = isl_union_map_add_map(*umap, map);240 241	return isl_stat_ok;242}243 244__isl_give isl_union_map *isl_union_map_dup(__isl_keep isl_union_map *umap)245{246	isl_union_map *dup;247 248	if (!umap)249		return NULL;250 251	dup = isl_union_map_empty(isl_space_copy(umap->dim));252	if (isl_union_map_foreach_map(umap, &add_map, &dup) < 0)253		goto error;254	return dup;255error:256	isl_union_map_free(dup);257	return NULL;258}259 260__isl_give isl_union_map *isl_union_map_cow(__isl_take isl_union_map *umap)261{262	if (!umap)263		return NULL;264 265	if (umap->ref == 1)266		return umap;267	umap->ref--;268	return isl_union_map_dup(umap);269}270 271struct isl_union_align {272	isl_reordering *exp;273	isl_union_map *res;274};275 276static isl_stat align_entry(void **entry, void *user)277{278	isl_map *map = *entry;279	isl_reordering *exp;280	struct isl_union_align *data = user;281 282	exp = isl_reordering_extend_space(isl_reordering_copy(data->exp),283				    isl_map_get_space(map));284 285	data->res = isl_union_map_add_map(data->res,286					isl_map_realign(isl_map_copy(map), exp));287 288	return isl_stat_ok;289}290 291/* Align the parameters of umap along those of model.292 * The result has the parameters of model first, in the same order293 * as they appear in model, followed by any remaining parameters of294 * umap that do not appear in model.295 */296__isl_give isl_union_map *isl_union_map_align_params(297	__isl_take isl_union_map *umap, __isl_take isl_space *model)298{299	struct isl_union_align data = { NULL, NULL };300	isl_space *space;301	isl_bool equal_params;302 303	space = isl_union_map_peek_space(umap);304	equal_params = isl_space_has_equal_params(space, model);305	if (equal_params < 0)306		goto error;307	if (equal_params) {308		isl_space_free(model);309		return umap;310	}311 312	data.exp = isl_parameter_alignment_reordering(space, model);313	if (!data.exp)314		goto error;315 316	data.res = isl_union_map_alloc(isl_reordering_get_space(data.exp),317					umap->table.n);318	if (isl_hash_table_foreach(isl_union_map_get_ctx(umap), &umap->table,319					&align_entry, &data) < 0)320		goto error;321 322	isl_reordering_free(data.exp);323	isl_union_map_free(umap);324	isl_space_free(model);325	return data.res;326error:327	isl_reordering_free(data.exp);328	isl_union_map_free(umap);329	isl_union_map_free(data.res);330	isl_space_free(model);331	return NULL;332}333 334__isl_give isl_union_set *isl_union_set_align_params(335	__isl_take isl_union_set *uset, __isl_take isl_space *model)336{337	return isl_union_map_align_params(uset, model);338}339 340__isl_give isl_union_map *isl_union_map_union(__isl_take isl_union_map *umap1,341	__isl_take isl_union_map *umap2)342{343	umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2));344	umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1));345 346	umap1 = isl_union_map_cow(umap1);347 348	if (!umap1 || !umap2)349		goto error;350 351	if (isl_union_map_foreach_map(umap2, &add_map, &umap1) < 0)352		goto error;353 354	isl_union_map_free(umap2);355 356	return umap1;357error:358	isl_union_map_free(umap1);359	isl_union_map_free(umap2);360	return NULL;361}362 363__isl_give isl_union_set *isl_union_set_union(__isl_take isl_union_set *uset1,364	__isl_take isl_union_set *uset2)365{366	return isl_union_map_union(uset1, uset2);367}368 369__isl_give isl_union_map *isl_union_map_copy(__isl_keep isl_union_map *umap)370{371	if (!umap)372		return NULL;373 374	umap->ref++;375	return umap;376}377 378__isl_give isl_union_set *isl_union_set_copy(__isl_keep isl_union_set *uset)379{380	return isl_union_map_copy(uset);381}382 383__isl_null isl_union_map *isl_union_map_free(__isl_take isl_union_map *umap)384{385	if (!umap)386		return NULL;387 388	if (--umap->ref > 0)389		return NULL;390 391	isl_hash_table_foreach(umap->dim->ctx, &umap->table,392			       &free_umap_entry, NULL);393	isl_hash_table_clear(&umap->table);394	isl_space_free(umap->dim);395	free(umap);396	return NULL;397}398 399__isl_null isl_union_set *isl_union_set_free(__isl_take isl_union_set *uset)400{401	return isl_union_map_free(uset);402}403 404/* Do "umap" and "space" have the same parameters?405 */406isl_bool isl_union_map_space_has_equal_params(__isl_keep isl_union_map *umap,407	__isl_keep isl_space *space)408{409	isl_space *umap_space;410 411	umap_space = isl_union_map_peek_space(umap);412	return isl_space_has_equal_params(umap_space, space);413}414 415/* Do "uset" and "space" have the same parameters?416 */417isl_bool isl_union_set_space_has_equal_params(__isl_keep isl_union_set *uset,418	__isl_keep isl_space *space)419{420	return isl_union_map_space_has_equal_params(uset_to_umap(uset), space);421}422 423/* Is the space of the map at "entry" equal to "space", ignoring parameters?424 */425static isl_bool has_space_tuples(const void *entry, const void *val)426{427	isl_map *map = (isl_map *)entry;428	isl_space *space = (isl_space *) val;429 430	return isl_map_has_space_tuples(map, space);431}432 433/* Find the entry in "umap" with space "space" (ignoring parameters),434 * returning isl_hash_table_entry_none if no such entry appears in "umap" and435 * NULL on error.436 * If "reserve" is set, then an entry is created if it does437 * not exist already.  Since this modifies the hash table in-place,438 * this means "umap" must have a single reference when "reserve" is set.439 */440static struct isl_hash_table_entry *isl_union_map_find_entry(441	__isl_keep isl_union_map *umap, __isl_keep isl_space *space,442	int reserve)443{444	uint32_t hash;445 446	if (!umap || !space)447		return NULL;448	if (reserve && isl_union_map_check_single_reference(umap) < 0)449		return NULL;450 451	hash = isl_space_get_tuple_hash(space);452	return isl_hash_table_find(isl_union_map_get_ctx(umap), &umap->table,453				    hash, &has_space_tuples, space, reserve);454}455 456/* Find the entry in "uset" with space "space" (ignoring parameters),457 * returning isl_hash_table_entry_none if no such entry appears in "uset" and458 * NULL on error.459 * If "reserve" is set, then an entry is created if it does460 * not exist already.  In this case, a NULL return indicates an error.461 */462struct isl_hash_table_entry *isl_union_set_find_entry(463	__isl_keep isl_union_set *uset, __isl_keep isl_space *space,464	int reserve)465{466	return isl_union_map_find_entry(uset_to_umap(uset), space, reserve);467}468 469__isl_give isl_union_map *isl_union_map_add_map(__isl_take isl_union_map *umap,470	__isl_take isl_map *map)471{472	struct isl_hash_table_entry *entry;473	isl_bool aligned;474	isl_space *space;475 476	if (!map || !umap)477		goto error;478 479	if (isl_map_plain_is_empty(map)) {480		isl_map_free(map);481		return umap;482	}483 484	aligned = isl_map_space_has_equal_params(map, umap->dim);485	if (aligned < 0)486		goto error;487	if (!aligned) {488		umap = isl_union_map_align_params(umap, isl_map_get_space(map));489		map = isl_map_align_params(map, isl_union_map_get_space(umap));490	}491 492	umap = isl_union_map_cow(umap);493 494	space = isl_map_peek_space(map);495	entry = isl_union_map_find_entry(umap, space, 1);496	if (!entry)497		goto error;498 499	if (!entry->data)500		entry->data = map;501	else {502		entry->data = isl_map_union(entry->data, isl_map_copy(map));503		if (!entry->data)504			goto error;505		isl_map_free(map);506	}507 508	return umap;509error:510	isl_map_free(map);511	isl_union_map_free(umap);512	return NULL;513}514 515__isl_give isl_union_set *isl_union_set_add_set(__isl_take isl_union_set *uset,516	__isl_take isl_set *set)517{518	return isl_union_map_add_map(uset, set_to_map(set));519}520 521__isl_give isl_union_map *isl_union_map_from_map(__isl_take isl_map *map)522{523	isl_space *space;524	isl_union_map *umap;525 526	if (!map)527		return NULL;528 529	space = isl_map_get_space(map);530	space = isl_space_params(space);531	umap = isl_union_map_empty(space);532	umap = isl_union_map_add_map(umap, map);533 534	return umap;535}536 537/* This function performs the same operation as isl_union_map_from_map,538 * but is considered as a function on an isl_map when exported.539 */540__isl_give isl_union_map *isl_map_to_union_map(__isl_take isl_map *map)541{542	return isl_union_map_from_map(map);543}544 545__isl_give isl_union_set *isl_union_set_from_set(__isl_take isl_set *set)546{547	return isl_union_map_from_map(set_to_map(set));548}549 550/* This function performs the same operation as isl_union_set_from_set,551 * but is considered as a function on an isl_set when exported.552 */553__isl_give isl_union_set *isl_set_to_union_set(__isl_take isl_set *set)554{555	return isl_union_set_from_set(set);556}557 558__isl_give isl_union_map *isl_union_map_from_basic_map(559	__isl_take isl_basic_map *bmap)560{561	return isl_union_map_from_map(isl_map_from_basic_map(bmap));562}563 564__isl_give isl_union_set *isl_union_set_from_basic_set(565	__isl_take isl_basic_set *bset)566{567	return isl_union_map_from_basic_map(bset);568}569 570struct isl_union_map_foreach_data571{572	isl_stat (*fn)(__isl_take isl_map *map, void *user);573	void *user;574};575 576static isl_stat call_on_copy(void **entry, void *user)577{578	isl_map *map = *entry;579	struct isl_union_map_foreach_data *data;580	data = (struct isl_union_map_foreach_data *)user;581 582	return data->fn(isl_map_copy(map), data->user);583}584 585isl_size isl_union_map_n_map(__isl_keep isl_union_map *umap)586{587	return umap ? umap->table.n : isl_size_error;588}589 590isl_size isl_union_set_n_set(__isl_keep isl_union_set *uset)591{592	return uset ? uset->table.n : isl_size_error;593}594 595isl_stat isl_union_map_foreach_map(__isl_keep isl_union_map *umap,596	isl_stat (*fn)(__isl_take isl_map *map, void *user), void *user)597{598	struct isl_union_map_foreach_data data = { fn, user };599 600	if (!umap)601		return isl_stat_error;602 603	return isl_hash_table_foreach(umap->dim->ctx, &umap->table,604				      &call_on_copy, &data);605}606 607/* Internal data structure for isl_union_map_every_map.608 *609 * "test" is the user-specified callback function.610 * "user" is the user-specified callback function argument.611 *612 * "failed" is initialized to 0 and set to 1 if "test" fails613 * on any map.614 */615struct isl_union_map_every_data {616	isl_bool (*test)(__isl_keep isl_map *map, void *user);617	void *user;618	int failed;619};620 621/* Call data->test on "map".622 * If this fails, then set data->failed and abort.623 */624static isl_stat call_every(void **entry, void *user)625{626	isl_map *map = *entry;627	struct isl_union_map_every_data *data = user;628	isl_bool r;629 630	r = data->test(map, data->user);631	if (r < 0)632		return isl_stat_error;633	if (r)634		return isl_stat_ok;635	data->failed = 1;636	return isl_stat_error;637}638 639/* Does "test" succeed on every map in "umap"?640 */641isl_bool isl_union_map_every_map(__isl_keep isl_union_map *umap,642	isl_bool (*test)(__isl_keep isl_map *map, void *user), void *user)643{644	struct isl_union_map_every_data data = { test, user, 0 };645	isl_stat r;646 647	if (!umap)648		return isl_bool_error;649 650	r = isl_hash_table_foreach(isl_union_map_get_ctx(umap), &umap->table,651				      &call_every, &data);652	if (r >= 0)653		return isl_bool_true;654	if (data.failed)655		return isl_bool_false;656	return isl_bool_error;657}658 659/* Add "map" to "list".660 */661static isl_stat add_list_map(__isl_take isl_map *map, void *user)662{663	isl_map_list **list = user;664 665	*list = isl_map_list_add(*list, map);666 667	if (!*list)668		return isl_stat_error;669	return isl_stat_ok;670}671 672/* Return the maps in "umap" as a list.673 *674 * First construct a list of the appropriate size and then add all the675 * elements.676 */677__isl_give isl_map_list *isl_union_map_get_map_list(678	__isl_keep isl_union_map *umap)679{680	isl_size n_maps;681	isl_ctx *ctx;682	isl_map_list *list;683 684	n_maps = isl_union_map_n_map(umap);685	if (n_maps < 0)686		return NULL;687	ctx = isl_union_map_get_ctx(umap);688	list = isl_map_list_alloc(ctx, n_maps);689 690	if (isl_union_map_foreach_map(umap, &add_list_map, &list) < 0)691		list = isl_map_list_free(list);692 693	return list;694}695 696/* Return the sets in "uset" as a list.697 */698__isl_give isl_set_list *isl_union_set_get_set_list(699	__isl_keep isl_union_set *uset)700{701	return set_list_from_map_list(702		isl_union_map_get_map_list(uset_to_umap(uset)));703}704 705/* Can "umap" be converted to an isl_map?706 * That is, does it contain elements in exactly one space?707 */708isl_bool isl_union_map_isa_map(__isl_keep isl_union_map *umap)709{710	isl_size n;711 712	n = isl_union_map_n_map(umap);713	if (n < 0)714		return isl_bool_error;715	return isl_bool_ok(n == 1);716}717 718/* Can "uset" be converted to an isl_set?719 * That is, does it contain elements in exactly one space?720 */721isl_bool isl_union_set_isa_set(__isl_keep isl_union_set *uset)722{723	return isl_union_map_isa_map(uset_to_umap(uset));724}725 726static isl_stat copy_map(void **entry, void *user)727{728	isl_map *map = *entry;729	isl_map **map_p = user;730 731	*map_p = isl_map_copy(map);732 733	return isl_stat_error;734}735 736__isl_give isl_map *isl_map_from_union_map(__isl_take isl_union_map *umap)737{738	isl_bool is_map;739	isl_ctx *ctx;740	isl_map *map = NULL;741 742	is_map = isl_union_map_isa_map(umap);743	if (is_map < 0)744		goto error;745	ctx = isl_union_map_get_ctx(umap);746	if (!is_map)747		isl_die(ctx, isl_error_invalid,748			"union map needs to contain elements in exactly "749			"one space", goto error);750 751	isl_hash_table_foreach(ctx, &umap->table, &copy_map, &map);752 753	isl_union_map_free(umap);754 755	return map;756error:757	isl_union_map_free(umap);758	return NULL;759}760 761/* This function performs the same operation as isl_map_from_union_map,762 * but is considered as a function on an isl_union_map when exported.763 */764__isl_give isl_map *isl_union_map_as_map(__isl_take isl_union_map *umap)765{766	return isl_map_from_union_map(umap);767}768 769__isl_give isl_set *isl_set_from_union_set(__isl_take isl_union_set *uset)770{771	return isl_map_from_union_map(uset);772}773 774/* This function performs the same operation as isl_set_from_union_set,775 * but is considered as a function on an isl_union_set when exported.776 */777__isl_give isl_set *isl_union_set_as_set(__isl_take isl_union_set *uset)778{779	return isl_set_from_union_set(uset);780}781 782/* Extract the map in "umap" that lives in the given space (ignoring783 * parameters).784 */785__isl_give isl_map *isl_union_map_extract_map(__isl_keep isl_union_map *umap,786	__isl_take isl_space *space)787{788	struct isl_hash_table_entry *entry;789 790	entry = isl_union_map_find_entry(umap, space, 0);791	if (!entry)792		goto error;793	if (entry == isl_hash_table_entry_none)794		return isl_map_empty(space);795	isl_space_free(space);796	return isl_map_copy(entry->data);797error:798	isl_space_free(space);799	return NULL;800}801 802__isl_give isl_set *isl_union_set_extract_set(__isl_keep isl_union_set *uset,803	__isl_take isl_space *space)804{805	return set_from_map(isl_union_map_extract_map(uset, space));806}807 808/* Check if umap contains a map in the given space (ignoring parameters).809 */810isl_bool isl_union_map_contains(__isl_keep isl_union_map *umap,811	__isl_keep isl_space *space)812{813	struct isl_hash_table_entry *entry;814 815	space = isl_space_drop_all_params(isl_space_copy(space));816	space = isl_space_align_params(space, isl_union_map_get_space(umap));817	entry = isl_union_map_find_entry(umap, space, 0);818	isl_space_free(space);819	if (!entry)820		return isl_bool_error;821	return isl_bool_ok(entry != isl_hash_table_entry_none);822}823 824isl_bool isl_union_set_contains(__isl_keep isl_union_set *uset,825	__isl_keep isl_space *space)826{827	return isl_union_map_contains(uset, space);828}829 830isl_stat isl_union_set_foreach_set(__isl_keep isl_union_set *uset,831	isl_stat (*fn)(__isl_take isl_set *set, void *user), void *user)832{833	return isl_union_map_foreach_map(uset,834		(isl_stat(*)(__isl_take isl_map *, void*))fn, user);835}836 837/* Internal data structure for isl_union_set_every_set.838 *839 * "test" is the user-specified callback function.840 * "user" is the user-specified callback function argument.841 */842struct isl_test_set_from_map_data {843	isl_bool (*test)(__isl_keep isl_set *set, void *user);844	void *user;845};846 847/* Call data->test on "map", which is part of an isl_union_set and848 * therefore known to be an isl_set.849 */850static isl_bool test_set_from_map(__isl_keep isl_map *map, void *user)851{852	struct isl_test_set_from_map_data *data = user;853 854	return data->test(set_from_map(map), data->user);855}856 857/* Does "test" succeed on every set in "uset"?858 */859isl_bool isl_union_set_every_set(__isl_keep isl_union_set *uset,860	isl_bool (*test)(__isl_keep isl_set *set, void *user), void *user)861{862	struct isl_test_set_from_map_data data = { test, user };863 864	return isl_union_map_every_map(uset_to_umap(uset),865					&test_set_from_map, &data);866}867 868struct isl_union_set_foreach_point_data {869	isl_stat (*fn)(__isl_take isl_point *pnt, void *user);870	void *user;871};872 873static isl_stat foreach_point(__isl_take isl_set *set, void *user)874{875	struct isl_union_set_foreach_point_data *data = user;876	isl_stat r;877 878	r = isl_set_foreach_point(set, data->fn, data->user);879	isl_set_free(set);880 881	return r;882}883 884isl_stat isl_union_set_foreach_point(__isl_keep isl_union_set *uset,885	isl_stat (*fn)(__isl_take isl_point *pnt, void *user), void *user)886{887	struct isl_union_set_foreach_point_data data = { fn, user };888	return isl_union_set_foreach_set(uset, &foreach_point, &data);889}890 891/* Data structure that specifies how gen_bin_op should892 * construct results from the inputs.893 *894 * If "subtract" is set, then a map in the first input is copied to the result895 * if there is no corresponding map in the second input.896 * Otherwise, a map in the first input with no corresponding map897 * in the second input is ignored.898 * If "filter" is not NULL, then it specifies which maps in the first899 * input may have a matching map in the second input.900 * In particular, it makes sure that "match_space" can be called901 * on the space of the map.902 * "match_space" specifies how to transform the space of a map903 * in the first input to the space of the corresponding map904 * in the second input.905 * "fn_map" specifies how the matching maps, one from each input,906 * should be combined to form a map in the result.907 */908struct isl_bin_op_control {909	int subtract;910	isl_bool (*filter)(__isl_keep isl_map *map);911	__isl_give isl_space *(*match_space)(__isl_take isl_space *space);912	__isl_give isl_map *(*fn_map)(__isl_take isl_map *map1,913		__isl_take isl_map *map2);914};915 916/* Internal data structure for gen_bin_op.917 * "control" specifies how the maps in the result should be constructed.918 * "umap2" is a pointer to the second argument.919 * "res" collects the results.920 */921struct isl_union_map_gen_bin_data {922	struct isl_bin_op_control *control;923	isl_union_map *umap2;924	isl_union_map *res;925};926 927/* Add a copy of "map" to "res" and return the result.928 */929static __isl_give isl_union_map *bin_add_map(__isl_take isl_union_map *res,930	__isl_keep isl_map *map)931{932	return isl_union_map_add_map(res, isl_map_copy(map));933}934 935/* Combine "map1" and "map2", add the result to "res" and return the result.936 * Check whether the result is empty before adding it to "res".937 */938static __isl_give isl_union_map *bin_add_pair(__isl_take isl_union_map *res,939	__isl_keep isl_map *map1, __isl_keep isl_map *map2,940	struct isl_union_map_gen_bin_data *data)941{942	isl_bool empty;943	isl_map *map;944 945	map = data->control->fn_map(isl_map_copy(map1), isl_map_copy(map2));946	empty = isl_map_is_empty(map);947	if (empty < 0 || empty) {948		isl_map_free(map);949		if (empty < 0)950			return isl_union_map_free(res);951		return res;952	}953	return isl_union_map_add_map(res, map);954}955 956/* Dummy match_space function that simply returns the input space.957 */958static __isl_give isl_space *identity(__isl_take isl_space *space)959{960	return space;961}962 963/* Look for the map in data->umap2 that corresponds to "map", if any.964 * Return (isl_bool_true, matching map) if there is one,965 * (isl_bool_false, NULL) if there is no matching map and966 * (isl_bool_error, NULL) on error.967 *968 * If not NULL, then data->control->filter specifies whether "map"969 * can have any matching map.  If so,970 * data->control->match_space specifies which map in data->umap2971 * corresponds to "map".972 */973static __isl_keep isl_maybe_isl_map bin_try_get_match(974	struct isl_union_map_gen_bin_data *data, __isl_keep isl_map *map)975{976	struct isl_hash_table_entry *entry2;977	isl_space *space;978	isl_maybe_isl_map res = { isl_bool_error, NULL };979 980	if (data->control->filter) {981		res.valid = data->control->filter(map);982		if (res.valid < 0 || !res.valid)983			return res;984		res.valid = isl_bool_error;985	}986 987	space = isl_map_get_space(map);988	if (data->control->match_space != &identity)989		space = data->control->match_space(space);990	entry2 = isl_union_map_find_entry(data->umap2, space, 0);991	isl_space_free(space);992	if (entry2)993		res.valid = isl_bool_ok(entry2 != isl_hash_table_entry_none);994	if (res.valid >= 0 && res.valid)995		res.value = entry2->data;996 997	return res;998}999 1000/* isl_hash_table_foreach callback for gen_bin_op.1001 * Look for the map in data->umap2 that corresponds1002 * to the map that "entry" points to, apply the binary operation and1003 * add the result to data->res.1004 *1005 * If no corresponding map can be found, then the effect depends1006 * on data->control->subtract.  If it is set, then the current map1007 * is added directly to the result.  Otherwise, it is ignored.1008 */1009static isl_stat gen_bin_entry(void **entry, void *user)1010{1011	struct isl_union_map_gen_bin_data *data = user;1012	isl_map *map = *entry;1013	isl_maybe_isl_map m;1014 1015	m = bin_try_get_match(data, map);1016	if (m.valid < 0)1017		return isl_stat_error;1018	if (!m.valid && !data->control->subtract)1019		return isl_stat_ok;1020 1021	if (!m.valid)1022		data->res = bin_add_map(data->res, map);1023	else1024		data->res = bin_add_pair(data->res, map, m.value, data);1025	if (!data->res)1026		return isl_stat_error;1027 1028	return isl_stat_ok;1029}1030 1031/* Apply a binary operation to "umap1" and "umap2" based on "control".1032 * Run over all maps in "umap1" and look for the corresponding map in "umap2"1033 * in gen_bin_entry.1034 */1035static __isl_give isl_union_map *gen_bin_op(__isl_take isl_union_map *umap1,1036	__isl_take isl_union_map *umap2, struct isl_bin_op_control *control)1037{1038	struct isl_union_map_gen_bin_data data = { control, NULL, NULL };1039 1040	umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2));1041	umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1));1042 1043	if (!umap1 || !umap2)1044		goto error;1045 1046	data.umap2 = umap2;1047	data.res = isl_union_map_alloc(isl_space_copy(umap1->dim),1048				       umap1->table.n);1049	if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table,1050				   &gen_bin_entry, &data) < 0)1051		goto error;1052 1053	isl_union_map_free(umap1);1054	isl_union_map_free(umap2);1055	return data.res;1056error:1057	isl_union_map_free(umap1);1058	isl_union_map_free(umap2);1059	isl_union_map_free(data.res);1060	return NULL;1061}1062 1063__isl_give isl_union_map *isl_union_map_subtract(1064	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)1065{1066	struct isl_bin_op_control control = {1067		.subtract = 1,1068		.match_space = &identity,1069		.fn_map = &isl_map_subtract,1070	};1071 1072	return gen_bin_op(umap1, umap2, &control);1073}1074 1075__isl_give isl_union_set *isl_union_set_subtract(1076	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2)1077{1078	return isl_union_map_subtract(uset1, uset2);1079}1080 1081struct isl_union_map_gen_bin_set_data {1082	isl_set *set;1083	isl_union_map *res;1084};1085 1086static isl_stat intersect_params_entry(void **entry, void *user)1087{1088	struct isl_union_map_gen_bin_set_data *data = user;1089	isl_map *map = *entry;1090	int empty;1091 1092	map = isl_map_copy(map);1093	map = isl_map_intersect_params(map, isl_set_copy(data->set));1094 1095	empty = isl_map_is_empty(map);1096	if (empty < 0) {1097		isl_map_free(map);1098		return isl_stat_error;1099	}1100 1101	data->res = isl_union_map_add_map(data->res, map);1102 1103	return isl_stat_ok;1104}1105 1106static __isl_give isl_union_map *gen_bin_set_op(__isl_take isl_union_map *umap,1107	__isl_take isl_set *set, isl_stat (*fn)(void **, void *))1108{1109	struct isl_union_map_gen_bin_set_data data = { NULL, NULL };1110 1111	umap = isl_union_map_align_params(umap, isl_set_get_space(set));1112	set = isl_set_align_params(set, isl_union_map_get_space(umap));1113 1114	if (!umap || !set)1115		goto error;1116 1117	data.set = set;1118	data.res = isl_union_map_alloc(isl_space_copy(umap->dim),1119				       umap->table.n);1120	if (isl_hash_table_foreach(umap->dim->ctx, &umap->table,1121				   fn, &data) < 0)1122		goto error;1123 1124	isl_union_map_free(umap);1125	isl_set_free(set);1126	return data.res;1127error:1128	isl_union_map_free(umap);1129	isl_set_free(set);1130	isl_union_map_free(data.res);1131	return NULL;1132}1133 1134/* Intersect "umap" with the parameter domain "set".1135 *1136 * If "set" does not have any constraints, then we can return immediately.1137 */1138__isl_give isl_union_map *isl_union_map_intersect_params(1139	__isl_take isl_union_map *umap, __isl_take isl_set *set)1140{1141	int is_universe;1142 1143	is_universe = isl_set_plain_is_universe(set);1144	if (is_universe < 0)1145		goto error;1146	if (is_universe) {1147		isl_set_free(set);1148		return umap;1149	}1150 1151	return gen_bin_set_op(umap, set, &intersect_params_entry);1152error:1153	isl_union_map_free(umap);1154	isl_set_free(set);1155	return NULL;1156}1157 1158__isl_give isl_union_set *isl_union_set_intersect_params(1159	__isl_take isl_union_set *uset, __isl_take isl_set *set)1160{1161	return isl_union_map_intersect_params(uset, set);1162}1163 1164static __isl_give isl_union_map *union_map_intersect_params(1165	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)1166{1167	return isl_union_map_intersect_params(umap,1168						isl_set_from_union_set(uset));1169}1170 1171static __isl_give isl_union_map *union_map_gist_params(1172	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)1173{1174	return isl_union_map_gist_params(umap, isl_set_from_union_set(uset));1175}1176 1177struct isl_union_map_match_bin_data {1178	isl_union_map *umap2;1179	isl_union_map *res;1180	__isl_give isl_map *(*fn)(__isl_take isl_map*, __isl_take isl_map*);1181};1182 1183static isl_stat match_bin_entry(void **entry, void *user)1184{1185	struct isl_union_map_match_bin_data *data = user;1186	struct isl_hash_table_entry *entry2;1187	isl_space *space;1188	isl_map *map = *entry;1189	int empty;1190 1191	space = isl_map_peek_space(map);1192	entry2 = isl_union_map_find_entry(data->umap2, space, 0);1193	if (!entry2)1194		return isl_stat_error;1195	if (entry2 == isl_hash_table_entry_none)1196		return isl_stat_ok;1197 1198	map = isl_map_copy(map);1199	map = data->fn(map, isl_map_copy(entry2->data));1200 1201	empty = isl_map_is_empty(map);1202	if (empty < 0) {1203		isl_map_free(map);1204		return isl_stat_error;1205	}1206	if (empty) {1207		isl_map_free(map);1208		return isl_stat_ok;1209	}1210 1211	data->res = isl_union_map_add_map(data->res, map);1212 1213	return isl_stat_ok;1214}1215 1216static __isl_give isl_union_map *match_bin_op(__isl_take isl_union_map *umap1,1217	__isl_take isl_union_map *umap2,1218	__isl_give isl_map *(*fn)(__isl_take isl_map*, __isl_take isl_map*))1219{1220	struct isl_union_map_match_bin_data data = { NULL, NULL, fn };1221 1222	umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2));1223	umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1));1224 1225	if (!umap1 || !umap2)1226		goto error;1227 1228	data.umap2 = umap2;1229	data.res = isl_union_map_alloc(isl_space_copy(umap1->dim),1230				       umap1->table.n);1231	if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table,1232				   &match_bin_entry, &data) < 0)1233		goto error;1234 1235	isl_union_map_free(umap1);1236	isl_union_map_free(umap2);1237	return data.res;1238error:1239	isl_union_map_free(umap1);1240	isl_union_map_free(umap2);1241	isl_union_map_free(data.res);1242	return NULL;1243}1244 1245__isl_give isl_union_map *isl_union_map_intersect(1246	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)1247{1248	return match_bin_op(umap1, umap2, &isl_map_intersect);1249}1250 1251/* Compute the intersection of the two union_sets.1252 * As a special case, if exactly one of the two union_sets1253 * is a parameter domain, then intersect the parameter domain1254 * of the other one with this set.1255 */1256__isl_give isl_union_set *isl_union_set_intersect(1257	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2)1258{1259	int p1, p2;1260 1261	p1 = isl_union_set_is_params(uset1);1262	p2 = isl_union_set_is_params(uset2);1263	if (p1 < 0 || p2 < 0)1264		goto error;1265	if (!p1 && p2)1266		return union_map_intersect_params(uset1, uset2);1267	if (p1 && !p2)1268		return union_map_intersect_params(uset2, uset1);1269	return isl_union_map_intersect(uset1, uset2);1270error:1271	isl_union_set_free(uset1);1272	isl_union_set_free(uset2);1273	return NULL;1274}1275 1276static isl_stat gist_params_entry(void **entry, void *user)1277{1278	struct isl_union_map_gen_bin_set_data *data = user;1279	isl_map *map = *entry;1280	int empty;1281 1282	map = isl_map_copy(map);1283	map = isl_map_gist_params(map, isl_set_copy(data->set));1284 1285	empty = isl_map_is_empty(map);1286	if (empty < 0) {1287		isl_map_free(map);1288		return isl_stat_error;1289	}1290 1291	data->res = isl_union_map_add_map(data->res, map);1292 1293	return isl_stat_ok;1294}1295 1296__isl_give isl_union_map *isl_union_map_gist_params(1297	__isl_take isl_union_map *umap, __isl_take isl_set *set)1298{1299	return gen_bin_set_op(umap, set, &gist_params_entry);1300}1301 1302__isl_give isl_union_set *isl_union_set_gist_params(1303	__isl_take isl_union_set *uset, __isl_take isl_set *set)1304{1305	return isl_union_map_gist_params(uset, set);1306}1307 1308__isl_give isl_union_map *isl_union_map_gist(__isl_take isl_union_map *umap,1309	__isl_take isl_union_map *context)1310{1311	return match_bin_op(umap, context, &isl_map_gist);1312}1313 1314__isl_give isl_union_set *isl_union_set_gist(__isl_take isl_union_set *uset,1315	__isl_take isl_union_set *context)1316{1317	if (isl_union_set_is_params(context))1318		return union_map_gist_params(uset, context);1319	return isl_union_map_gist(uset, context);1320}1321 1322/* For each map in "umap", remove the constraints in the corresponding map1323 * of "context".1324 * Each map in "context" is assumed to consist of a single disjunct and1325 * to have explicit representations for all local variables.1326 */1327__isl_give isl_union_map *isl_union_map_plain_gist(1328	__isl_take isl_union_map *umap, __isl_take isl_union_map *context)1329{1330	return match_bin_op(umap, context, &isl_map_plain_gist);1331}1332 1333/* For each set in "uset", remove the constraints in the corresponding set1334 * of "context".1335 * Each set in "context" is assumed to consist of a single disjunct and1336 * to have explicit representations for all local variables.1337 */1338__isl_give isl_union_set *isl_union_set_plain_gist(1339	__isl_take isl_union_set *uset, __isl_take isl_union_set *context)1340{1341	return isl_union_map_plain_gist(uset, context);1342}1343 1344static __isl_give isl_map *lex_le_set(__isl_take isl_map *set1,1345	__isl_take isl_map *set2)1346{1347	return isl_set_lex_le_set(set_from_map(set1), set_from_map(set2));1348}1349 1350static __isl_give isl_map *lex_lt_set(__isl_take isl_map *set1,1351	__isl_take isl_map *set2)1352{1353	return isl_set_lex_lt_set(set_from_map(set1), set_from_map(set2));1354}1355 1356__isl_give isl_union_map *isl_union_set_lex_lt_union_set(1357	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2)1358{1359	return match_bin_op(uset1, uset2, &lex_lt_set);1360}1361 1362__isl_give isl_union_map *isl_union_set_lex_le_union_set(1363	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2)1364{1365	return match_bin_op(uset1, uset2, &lex_le_set);1366}1367 1368__isl_give isl_union_map *isl_union_set_lex_gt_union_set(1369	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2)1370{1371	return isl_union_map_reverse(isl_union_set_lex_lt_union_set(uset2, uset1));1372}1373 1374__isl_give isl_union_map *isl_union_set_lex_ge_union_set(1375	__isl_take isl_union_set *uset1, __isl_take isl_union_set *uset2)1376{1377	return isl_union_map_reverse(isl_union_set_lex_le_union_set(uset2, uset1));1378}1379 1380__isl_give isl_union_map *isl_union_map_lex_gt_union_map(1381	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)1382{1383	return isl_union_map_reverse(isl_union_map_lex_lt_union_map(umap2, umap1));1384}1385 1386__isl_give isl_union_map *isl_union_map_lex_ge_union_map(1387	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)1388{1389	return isl_union_map_reverse(isl_union_map_lex_le_union_map(umap2, umap1));1390}1391 1392/* Intersect the domain of "umap" with "uset".1393 */1394static __isl_give isl_union_map *union_map_intersect_domain(1395	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)1396{1397	struct isl_bin_op_control control = {1398		.match_space = &isl_space_domain,1399		.fn_map = &isl_map_intersect_domain,1400	};1401 1402	return gen_bin_op(umap, uset, &control);1403}1404 1405/* Intersect the domain of "umap" with "uset".1406 * If "uset" is a parameters domain, then intersect the parameter1407 * domain of "umap" with this set.1408 */1409__isl_give isl_union_map *isl_union_map_intersect_domain_union_set(1410	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)1411{1412	if (isl_union_set_is_params(uset))1413		return union_map_intersect_params(umap, uset);1414	else1415		return union_map_intersect_domain(umap, uset);1416}1417 1418/* This is an alternative name for the function above.1419 */1420__isl_give isl_union_map *isl_union_map_intersect_domain(1421	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)1422{1423	return isl_union_map_intersect_domain_union_set(umap, uset);1424}1425 1426/* Remove the elements of "uset" from the domain of "umap".1427 */1428__isl_give isl_union_map *isl_union_map_subtract_domain(1429	__isl_take isl_union_map *umap, __isl_take isl_union_set *dom)1430{1431	struct isl_bin_op_control control = {1432		.subtract = 1,1433		.match_space = &isl_space_domain,1434		.fn_map = &isl_map_subtract_domain,1435	};1436 1437	return gen_bin_op(umap, dom, &control);1438}1439 1440/* Remove the elements of "uset" from the range of "umap".1441 */1442__isl_give isl_union_map *isl_union_map_subtract_range(1443	__isl_take isl_union_map *umap, __isl_take isl_union_set *dom)1444{1445	struct isl_bin_op_control control = {1446		.subtract = 1,1447		.match_space = &isl_space_range,1448		.fn_map = &isl_map_subtract_range,1449	};1450 1451	return gen_bin_op(umap, dom, &control);1452}1453 1454/* Compute the gist of "umap" with respect to the domain "uset".1455 */1456static __isl_give isl_union_map *union_map_gist_domain(1457	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)1458{1459	struct isl_bin_op_control control = {1460		.match_space = &isl_space_domain,1461		.fn_map = &isl_map_gist_domain,1462	};1463 1464	return gen_bin_op(umap, uset, &control);1465}1466 1467/* Compute the gist of "umap" with respect to the domain "uset".1468 * If "uset" is a parameters domain, then compute the gist1469 * with respect to this parameter domain.1470 */1471__isl_give isl_union_map *isl_union_map_gist_domain(1472	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)1473{1474	if (isl_union_set_is_params(uset))1475		return union_map_gist_params(umap, uset);1476	else1477		return union_map_gist_domain(umap, uset);1478}1479 1480/* Compute the gist of "umap" with respect to the range "uset".1481 */1482__isl_give isl_union_map *isl_union_map_gist_range(1483	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)1484{1485	struct isl_bin_op_control control = {1486		.match_space = &isl_space_range,1487		.fn_map = &isl_map_gist_range,1488	};1489 1490	return gen_bin_op(umap, uset, &control);1491}1492 1493__isl_give isl_union_map *isl_union_map_intersect_range_union_set(1494	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)1495{1496	struct isl_bin_op_control control = {1497		.match_space = &isl_space_range,1498		.fn_map = &isl_map_intersect_range,1499	};1500 1501	return gen_bin_op(umap, uset, &control);1502}1503 1504/* This is an alternative name for the function above.1505 */1506__isl_give isl_union_map *isl_union_map_intersect_range(1507	__isl_take isl_union_map *umap, __isl_take isl_union_set *uset)1508{1509	return isl_union_map_intersect_range_union_set(umap, uset);1510}1511 1512/* Intersect each map in "umap" in a space [A -> B] -> C1513 * with the corresponding map in "factor" in the space A -> C and1514 * collect the results.1515 */1516__isl_give isl_union_map *isl_union_map_intersect_domain_factor_domain(1517	__isl_take isl_union_map *umap, __isl_take isl_union_map *factor)1518{1519	struct isl_bin_op_control control = {1520		.filter = &isl_map_domain_is_wrapping,1521		.match_space = &isl_space_domain_factor_domain,1522		.fn_map = &isl_map_intersect_domain_factor_domain,1523	};1524 1525	return gen_bin_op(umap, factor, &control);1526}1527 1528/* Intersect each map in "umap" in a space [A -> B] -> C1529 * with the corresponding map in "factor" in the space B -> C and1530 * collect the results.1531 */1532__isl_give isl_union_map *isl_union_map_intersect_domain_factor_range(1533	__isl_take isl_union_map *umap, __isl_take isl_union_map *factor)1534{1535	struct isl_bin_op_control control = {1536		.filter = &isl_map_domain_is_wrapping,1537		.match_space = &isl_space_domain_factor_range,1538		.fn_map = &isl_map_intersect_domain_factor_range,1539	};1540 1541	return gen_bin_op(umap, factor, &control);1542}1543 1544/* Intersect each map in "umap" in a space A -> [B -> C]1545 * with the corresponding map in "factor" in the space A -> B and1546 * collect the results.1547 */1548__isl_give isl_union_map *isl_union_map_intersect_range_factor_domain(1549	__isl_take isl_union_map *umap, __isl_take isl_union_map *factor)1550{1551	struct isl_bin_op_control control = {1552		.filter = &isl_map_range_is_wrapping,1553		.match_space = &isl_space_range_factor_domain,1554		.fn_map = &isl_map_intersect_range_factor_domain,1555	};1556 1557	return gen_bin_op(umap, factor, &control);1558}1559 1560/* Intersect each map in "umap" in a space A -> [B -> C]1561 * with the corresponding map in "factor" in the space A -> C and1562 * collect the results.1563 */1564__isl_give isl_union_map *isl_union_map_intersect_range_factor_range(1565	__isl_take isl_union_map *umap, __isl_take isl_union_map *factor)1566{1567	struct isl_bin_op_control control = {1568		.filter = &isl_map_range_is_wrapping,1569		.match_space = &isl_space_range_factor_range,1570		.fn_map = &isl_map_intersect_range_factor_range,1571	};1572 1573	return gen_bin_op(umap, factor, &control);1574}1575 1576struct isl_union_map_bin_data {1577	isl_union_map *umap2;1578	isl_union_map *res;1579	isl_map *map;1580	isl_stat (*fn)(void **entry, void *user);1581};1582 1583static isl_stat apply_range_entry(void **entry, void *user)1584{1585	struct isl_union_map_bin_data *data = user;1586	isl_map *map2 = *entry;1587	isl_bool empty, match;1588 1589	match = isl_map_tuple_is_equal(data->map, isl_dim_out,1590				map2, isl_dim_in);1591	if (match < 0)1592		return isl_stat_error;1593	if (!match)1594		return isl_stat_ok;1595 1596	map2 = isl_map_apply_range(isl_map_copy(data->map), isl_map_copy(map2));1597 1598	empty = isl_map_is_empty(map2);1599	if (empty < 0) {1600		isl_map_free(map2);1601		return isl_stat_error;1602	}1603	if (empty) {1604		isl_map_free(map2);1605		return isl_stat_ok;1606	}1607 1608	data->res = isl_union_map_add_map(data->res, map2);1609 1610	return isl_stat_ok;1611}1612 1613static isl_stat bin_entry(void **entry, void *user)1614{1615	struct isl_union_map_bin_data *data = user;1616	isl_map *map = *entry;1617 1618	data->map = map;1619	if (isl_hash_table_foreach(data->umap2->dim->ctx, &data->umap2->table,1620				   data->fn, data) < 0)1621		return isl_stat_error;1622 1623	return isl_stat_ok;1624}1625 1626static __isl_give isl_union_map *bin_op(__isl_take isl_union_map *umap1,1627	__isl_take isl_union_map *umap2,1628	isl_stat (*fn)(void **entry, void *user))1629{1630	struct isl_union_map_bin_data data = { NULL, NULL, NULL, fn };1631 1632	umap1 = isl_union_map_align_params(umap1, isl_union_map_get_space(umap2));1633	umap2 = isl_union_map_align_params(umap2, isl_union_map_get_space(umap1));1634 1635	if (!umap1 || !umap2)1636		goto error;1637 1638	data.umap2 = umap2;1639	data.res = isl_union_map_alloc(isl_space_copy(umap1->dim),1640				       umap1->table.n);1641	if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table,1642				   &bin_entry, &data) < 0)1643		goto error;1644 1645	isl_union_map_free(umap1);1646	isl_union_map_free(umap2);1647	return data.res;1648error:1649	isl_union_map_free(umap1);1650	isl_union_map_free(umap2);1651	isl_union_map_free(data.res);1652	return NULL;1653}1654 1655/* Intersect each map in "umap" in a space [A -> B] -> C1656 * with the corresponding set in "domain" in the space A and1657 * collect the results.1658 */1659__isl_give isl_union_map *1660isl_union_map_intersect_domain_wrapped_domain_union_set(1661	__isl_take isl_union_map *umap, __isl_take isl_union_set *domain)1662{1663	struct isl_bin_op_control control = {1664		.filter = &isl_map_domain_is_wrapping,1665		.match_space = &isl_space_domain_wrapped_domain,1666		.fn_map = &isl_map_intersect_domain_wrapped_domain,1667	};1668 1669	return gen_bin_op(umap, domain, &control);1670}1671 1672/* Intersect each map in "umap" in a space A -> [B -> C]1673 * with the corresponding set in "domain" in the space B and1674 * collect the results.1675 */1676__isl_give isl_union_map *1677isl_union_map_intersect_range_wrapped_domain_union_set(1678	__isl_take isl_union_map *umap, __isl_take isl_union_set *domain)1679{1680	struct isl_bin_op_control control = {1681		.filter = &isl_map_range_is_wrapping,1682		.match_space = &isl_space_range_wrapped_domain,1683		.fn_map = &isl_map_intersect_range_wrapped_domain,1684	};1685 1686	return gen_bin_op(umap, domain, &control);1687}1688 1689__isl_give isl_union_map *isl_union_map_apply_range(1690	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)1691{1692	return bin_op(umap1, umap2, &apply_range_entry);1693}1694 1695__isl_give isl_union_map *isl_union_map_apply_domain(1696	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)1697{1698	umap1 = isl_union_map_reverse(umap1);1699	umap1 = isl_union_map_apply_range(umap1, umap2);1700	return isl_union_map_reverse(umap1);1701}1702 1703__isl_give isl_union_set *isl_union_set_apply(1704	__isl_take isl_union_set *uset, __isl_take isl_union_map *umap)1705{1706	return isl_union_map_apply_range(uset, umap);1707}1708 1709static isl_stat map_lex_lt_entry(void **entry, void *user)1710{1711	struct isl_union_map_bin_data *data = user;1712	isl_map *map2 = *entry;1713	isl_bool match;1714 1715	match = isl_map_tuple_is_equal(data->map, isl_dim_out,1716				 map2, isl_dim_out);1717	if (match < 0)1718		return isl_stat_error;1719	if (!match)1720		return isl_stat_ok;1721 1722	map2 = isl_map_lex_lt_map(isl_map_copy(data->map), isl_map_copy(map2));1723 1724	data->res = isl_union_map_add_map(data->res, map2);1725 1726	return isl_stat_ok;1727}1728 1729__isl_give isl_union_map *isl_union_map_lex_lt_union_map(1730	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)1731{1732	return bin_op(umap1, umap2, &map_lex_lt_entry);1733}1734 1735static isl_stat map_lex_le_entry(void **entry, void *user)1736{1737	struct isl_union_map_bin_data *data = user;1738	isl_map *map2 = *entry;1739	isl_bool match;1740 1741	match = isl_map_tuple_is_equal(data->map, isl_dim_out,1742				 map2, isl_dim_out);1743	if (match < 0)1744		return isl_stat_error;1745	if (!match)1746		return isl_stat_ok;1747 1748	map2 = isl_map_lex_le_map(isl_map_copy(data->map), isl_map_copy(map2));1749 1750	data->res = isl_union_map_add_map(data->res, map2);1751 1752	return isl_stat_ok;1753}1754 1755__isl_give isl_union_map *isl_union_map_lex_le_union_map(1756	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)1757{1758	return bin_op(umap1, umap2, &map_lex_le_entry);1759}1760 1761static isl_stat product_entry(void **entry, void *user)1762{1763	struct isl_union_map_bin_data *data = user;1764	isl_map *map2 = *entry;1765 1766	map2 = isl_map_product(isl_map_copy(data->map), isl_map_copy(map2));1767 1768	data->res = isl_union_map_add_map(data->res, map2);1769 1770	return isl_stat_ok;1771}1772 1773__isl_give isl_union_map *isl_union_map_product(__isl_take isl_union_map *umap1,1774	__isl_take isl_union_map *umap2)1775{1776	return bin_op(umap1, umap2, &product_entry);1777}1778 1779static isl_stat set_product_entry(void **entry, void *user)1780{1781	struct isl_union_map_bin_data *data = user;1782	isl_set *set2 = *entry;1783 1784	set2 = isl_set_product(isl_set_copy(data->map), isl_set_copy(set2));1785 1786	data->res = isl_union_set_add_set(data->res, set2);1787 1788	return isl_stat_ok;1789}1790 1791__isl_give isl_union_set *isl_union_set_product(__isl_take isl_union_set *uset1,1792	__isl_take isl_union_set *uset2)1793{1794	return bin_op(uset1, uset2, &set_product_entry);1795}1796 1797static isl_stat domain_product_entry(void **entry, void *user)1798{1799	struct isl_union_map_bin_data *data = user;1800	isl_map *map2 = *entry;1801	isl_bool match;1802 1803	match = isl_map_tuple_is_equal(data->map, isl_dim_out,1804				 map2, isl_dim_out);1805	if (match < 0)1806		return isl_stat_error;1807	if (!match)1808		return isl_stat_ok;1809 1810	map2 = isl_map_domain_product(isl_map_copy(data->map),1811				     isl_map_copy(map2));1812 1813	data->res = isl_union_map_add_map(data->res, map2);1814 1815	return isl_stat_ok;1816}1817 1818/* Given two maps A -> B and C -> D, construct a map [A -> C] -> (B * D)1819 */1820__isl_give isl_union_map *isl_union_map_domain_product(1821	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)1822{1823	return bin_op(umap1, umap2, &domain_product_entry);1824}1825 1826static isl_stat range_product_entry(void **entry, void *user)1827{1828	struct isl_union_map_bin_data *data = user;1829	isl_map *map2 = *entry;1830	isl_bool match;1831 1832	match = isl_map_tuple_is_equal(data->map, isl_dim_in, map2, isl_dim_in);1833	if (match < 0)1834		return isl_stat_error;1835	if (!match)1836		return isl_stat_ok;1837 1838	map2 = isl_map_range_product(isl_map_copy(data->map),1839				     isl_map_copy(map2));1840 1841	data->res = isl_union_map_add_map(data->res, map2);1842 1843	return isl_stat_ok;1844}1845 1846__isl_give isl_union_map *isl_union_map_range_product(1847	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)1848{1849	return bin_op(umap1, umap2, &range_product_entry);1850}1851 1852/* If data->map A -> B and "map2" C -> D have the same range space,1853 * then add (A, C) -> (B * D) to data->res.1854 */1855static isl_stat flat_domain_product_entry(void **entry, void *user)1856{1857	struct isl_union_map_bin_data *data = user;1858	isl_map *map2 = *entry;1859	isl_bool match;1860 1861	match = isl_map_tuple_is_equal(data->map, isl_dim_out,1862				 map2, isl_dim_out);1863	if (match < 0)1864		return isl_stat_error;1865	if (!match)1866		return isl_stat_ok;1867 1868	map2 = isl_map_flat_domain_product(isl_map_copy(data->map),1869					  isl_map_copy(map2));1870 1871	data->res = isl_union_map_add_map(data->res, map2);1872 1873	return isl_stat_ok;1874}1875 1876/* Given two maps A -> B and C -> D, construct a map (A, C) -> (B * D).1877 */1878__isl_give isl_union_map *isl_union_map_flat_domain_product(1879	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)1880{1881	return bin_op(umap1, umap2, &flat_domain_product_entry);1882}1883 1884static isl_stat flat_range_product_entry(void **entry, void *user)1885{1886	struct isl_union_map_bin_data *data = user;1887	isl_map *map2 = *entry;1888	isl_bool match;1889 1890	match = isl_map_tuple_is_equal(data->map, isl_dim_in, map2, isl_dim_in);1891	if (match < 0)1892		return isl_stat_error;1893	if (!match)1894		return isl_stat_ok;1895 1896	map2 = isl_map_flat_range_product(isl_map_copy(data->map),1897					  isl_map_copy(map2));1898 1899	data->res = isl_union_map_add_map(data->res, map2);1900 1901	return isl_stat_ok;1902}1903 1904__isl_give isl_union_map *isl_union_map_flat_range_product(1905	__isl_take isl_union_map *umap1, __isl_take isl_union_map *umap2)1906{1907	return bin_op(umap1, umap2, &flat_range_product_entry);1908}1909 1910/* Data structure that specifies how un_op should modify1911 * the maps in the union map.1912 *1913 * If "inplace" is set, then the maps in the input union map1914 * are modified in place.  This means that "fn_map" should not1915 * change the meaning of the map or that the union map only1916 * has a single reference.1917 * If "total" is set, then all maps need to be modified and1918 * the results need to live in the same space.1919 * Otherwise, a new union map is constructed to store the results.1920 * If "filter" is not NULL, then only the input maps that satisfy "filter"1921 * are taken into account.  "filter_user" is passed as the second argument1922 * to "filter".  No filter can be set if "inplace" or1923 * "total" is set.1924 * At most one of "fn_map" or "fn_map2" can be set, specifying1925 * how the maps (selected by "filter") should be transformed.1926 * If "fn_map2" is set, then "fn_map2_user" is passed as the second argument.1927 */1928struct isl_un_op_control {1929	int inplace;1930	int total;1931	isl_bool (*filter)(__isl_keep isl_map *map, void *user);1932	void *filter_user;1933	__isl_give isl_map *(*fn_map)(__isl_take isl_map *map);1934	__isl_give isl_map *(*fn_map2)(__isl_take isl_map *map, void *user);1935	void *fn_map2_user;1936};1937 1938/* Data structure for wrapping the data for un_op_filter_drop_user.1939 * "filter" is the function that is being wrapped.1940 */1941struct isl_un_op_drop_user_data {1942	isl_bool (*filter)(__isl_keep isl_map *map);1943};1944 1945/* Wrapper for isl_un_op_control filters that do not require1946 * a second argument.1947 * Simply call data->filter without the second argument.1948 */1949static isl_bool un_op_filter_drop_user(__isl_keep isl_map *map, void *user)1950{1951	struct isl_un_op_drop_user_data *data = user;1952	return data->filter(map);1953}1954 1955/* Internal data structure for "un_op".1956 * "control" specifies how the maps in the union map should be modified.1957 * "res" collects the results.1958 */1959struct isl_union_map_un_data {1960	struct isl_un_op_control *control;1961	isl_union_map *res;1962};1963 1964/* isl_hash_table_foreach callback for un_op.1965 * Handle the map that "entry" points to.1966 *1967 * If control->filter is set, then check if this map satisfies the filter.1968 * If so (or if control->filter is not set), modify the map1969 * by calling control->fn_map or control->fn_map2 (if set) and1970 * either add the result to data->res or1971 * replace the original entry by the result (if control->inplace is set).1972 */1973static isl_stat un_entry(void **entry, void *user)1974{1975	struct isl_union_map_un_data *data = user;1976	struct isl_un_op_control *control = data->control;1977	isl_map *map = *entry;1978 1979	if (control->filter) {1980		isl_bool ok;1981 1982		ok = control->filter(map, control->filter_user);1983		if (ok < 0)1984			return isl_stat_error;1985		if (!ok)1986			return isl_stat_ok;1987	}1988 1989	map = isl_map_copy(map);1990	if (control->fn_map2 != NULL)1991		map = control->fn_map2(map, control->fn_map2_user);1992	else if (control->fn_map != NULL)1993		map = control->fn_map(map);1994	if (!map)1995		return isl_stat_error;1996	if (control->inplace) {1997		isl_map_free(*entry);1998		*entry = map;1999	} else {2000		data->res = isl_union_map_add_map(data->res, map);2001		if (!data->res)2002			return isl_stat_error;2003	}2004 2005	return isl_stat_ok;2006}2007 2008/* Modify the maps in "umap" based on "control".2009 * If control->inplace is set, then modify the maps in "umap" in-place.2010 * Otherwise, create a new union map to hold the results.2011 * If control->total is set, then perform an inplace computation2012 * if "umap" is only referenced once.  Otherwise, create a new union map2013 * to store the results.2014 */2015static __isl_give isl_union_map *un_op(__isl_take isl_union_map *umap,2016	struct isl_un_op_control *control)2017{2018	struct isl_union_map_un_data data = { control };2019 2020	if (!umap)2021		return NULL;2022	if (!!control->fn_map && !!control->fn_map2)2023		isl_die(isl_union_map_get_ctx(umap), isl_error_internal,2024			"at most one mapping function can be specified",2025			return isl_union_map_free(umap));2026	if ((control->inplace || control->total) && control->filter)2027		isl_die(isl_union_map_get_ctx(umap), isl_error_invalid,2028			"inplace/total modification cannot be filtered",2029			return isl_union_map_free(umap));2030 2031	if (control->total && umap->ref == 1)2032		control->inplace = 1;2033	if (control->inplace) {2034		data.res = umap;2035	} else {2036		isl_space *space;2037 2038		space = isl_union_map_get_space(umap);2039		data.res = isl_union_map_alloc(space, umap->table.n);2040	}2041	if (isl_hash_table_foreach(isl_union_map_get_ctx(umap),2042				    &umap->table, &un_entry, &data) < 0)2043		data.res = isl_union_map_free(data.res);2044 2045	if (control->inplace)2046		return data.res;2047	isl_union_map_free(umap);2048	return data.res;2049}2050 2051__isl_give isl_union_map *isl_union_map_from_range(2052	__isl_take isl_union_set *uset)2053{2054	struct isl_un_op_control control = {2055		.fn_map = &isl_map_from_range,2056	};2057	return un_op(uset, &control);2058}2059 2060__isl_give isl_union_map *isl_union_map_from_domain(2061	__isl_take isl_union_set *uset)2062{2063	return isl_union_map_reverse(isl_union_map_from_range(uset));2064}2065 2066__isl_give isl_union_map *isl_union_map_from_domain_and_range(2067	__isl_take isl_union_set *domain, __isl_take isl_union_set *range)2068{2069	return isl_union_map_apply_range(isl_union_map_from_domain(domain),2070				         isl_union_map_from_range(range));2071}2072 2073/* Modify the maps in "umap" by applying "fn" on them.2074 * "fn" should apply to all maps in "umap" and should not modify the space.2075 */2076static __isl_give isl_union_map *total(__isl_take isl_union_map *umap,2077	__isl_give isl_map *(*fn)(__isl_take isl_map *))2078{2079	struct isl_un_op_control control = {2080		.total = 1,2081		.fn_map = fn,2082	};2083 2084	return un_op(umap, &control);2085}2086 2087/* Compute the affine hull of "map" and return the result as an isl_map.2088 */2089static __isl_give isl_map *isl_map_affine_hull_map(__isl_take isl_map *map)2090{2091	return isl_map_from_basic_map(isl_map_affine_hull(map));2092}2093 2094__isl_give isl_union_map *isl_union_map_affine_hull(2095	__isl_take isl_union_map *umap)2096{2097	return total(umap, &isl_map_affine_hull_map);2098}2099 2100__isl_give isl_union_set *isl_union_set_affine_hull(2101	__isl_take isl_union_set *uset)2102{2103	return isl_union_map_affine_hull(uset);2104}2105 2106/* Wrapper around isl_set_combined_lineality_space2107 * that returns the combined lineality space in the form of an isl_set2108 * instead of an isl_basic_set.2109 */2110static __isl_give isl_set *combined_lineality_space(__isl_take isl_set *set)2111{2112	return isl_set_from_basic_set(isl_set_combined_lineality_space(set));2113}2114 2115/* For each set in "uset", compute the (linear) hull2116 * of the lineality spaces of its basic sets and2117 * collect and return the results.2118 */2119__isl_give isl_union_set *isl_union_set_combined_lineality_space(2120	__isl_take isl_union_set *uset)2121{2122	struct isl_un_op_control control = {2123		.fn_map = &combined_lineality_space,2124	};2125	return un_op(uset, &control);2126}2127 2128/* Compute the polyhedral hull of "map" and return the result as an isl_map.2129 */2130static __isl_give isl_map *isl_map_polyhedral_hull_map(__isl_take isl_map *map)2131{2132	return isl_map_from_basic_map(isl_map_polyhedral_hull(map));2133}2134 2135__isl_give isl_union_map *isl_union_map_polyhedral_hull(2136	__isl_take isl_union_map *umap)2137{2138	return total(umap, &isl_map_polyhedral_hull_map);2139}2140 2141__isl_give isl_union_set *isl_union_set_polyhedral_hull(2142	__isl_take isl_union_set *uset)2143{2144	return isl_union_map_polyhedral_hull(uset);2145}2146 2147/* Compute a superset of the convex hull of "map" that is described2148 * by only translates of the constraints in the constituents of "map" and2149 * return the result as an isl_map.2150 */2151static __isl_give isl_map *isl_map_simple_hull_map(__isl_take isl_map *map)2152{2153	return isl_map_from_basic_map(isl_map_simple_hull(map));2154}2155 2156__isl_give isl_union_map *isl_union_map_simple_hull(2157	__isl_take isl_union_map *umap)2158{2159	return total(umap, &isl_map_simple_hull_map);2160}2161 2162__isl_give isl_union_set *isl_union_set_simple_hull(2163	__isl_take isl_union_set *uset)2164{2165	return isl_union_map_simple_hull(uset);2166}2167 2168static __isl_give isl_union_map *inplace(__isl_take isl_union_map *umap,2169	__isl_give isl_map *(*fn)(__isl_take isl_map *))2170{2171	struct isl_un_op_control control = {2172		.inplace = 1,2173		.fn_map = fn,2174	};2175 2176	return un_op(umap, &control);2177}2178 2179/* Remove redundant constraints in each of the basic maps of "umap".2180 * Since removing redundant constraints does not change the meaning2181 * or the space, the operation can be performed in-place.2182 */2183__isl_give isl_union_map *isl_union_map_remove_redundancies(2184	__isl_take isl_union_map *umap)2185{2186	return inplace(umap, &isl_map_remove_redundancies);2187}2188 2189/* Remove redundant constraints in each of the basic sets of "uset".2190 */2191__isl_give isl_union_set *isl_union_set_remove_redundancies(2192	__isl_take isl_union_set *uset)2193{2194	return isl_union_map_remove_redundancies(uset);2195}2196 2197__isl_give isl_union_map *isl_union_map_coalesce(2198	__isl_take isl_union_map *umap)2199{2200	return inplace(umap, &isl_map_coalesce);2201}2202 2203__isl_give isl_union_set *isl_union_set_coalesce(2204	__isl_take isl_union_set *uset)2205{2206	return isl_union_map_coalesce(uset);2207}2208 2209__isl_give isl_union_map *isl_union_map_detect_equalities(2210	__isl_take isl_union_map *umap)2211{2212	return inplace(umap, &isl_map_detect_equalities);2213}2214 2215__isl_give isl_union_set *isl_union_set_detect_equalities(2216	__isl_take isl_union_set *uset)2217{2218	return isl_union_map_detect_equalities(uset);2219}2220 2221__isl_give isl_union_map *isl_union_map_compute_divs(2222	__isl_take isl_union_map *umap)2223{2224	return inplace(umap, &isl_map_compute_divs);2225}2226 2227__isl_give isl_union_set *isl_union_set_compute_divs(2228	__isl_take isl_union_set *uset)2229{2230	return isl_union_map_compute_divs(uset);2231}2232 2233__isl_give isl_union_map *isl_union_map_lexmin(2234	__isl_take isl_union_map *umap)2235{2236	return total(umap, &isl_map_lexmin);2237}2238 2239__isl_give isl_union_set *isl_union_set_lexmin(2240	__isl_take isl_union_set *uset)2241{2242	return isl_union_map_lexmin(uset);2243}2244 2245__isl_give isl_union_map *isl_union_map_lexmax(2246	__isl_take isl_union_map *umap)2247{2248	return total(umap, &isl_map_lexmax);2249}2250 2251__isl_give isl_union_set *isl_union_set_lexmax(2252	__isl_take isl_union_set *uset)2253{2254	return isl_union_map_lexmax(uset);2255}2256 2257/* Return the universe in the space of "map".2258 */2259static __isl_give isl_map *universe(__isl_take isl_map *map)2260{2261	isl_space *space;2262 2263	space = isl_map_get_space(map);2264	isl_map_free(map);2265	return isl_map_universe(space);2266}2267 2268__isl_give isl_union_map *isl_union_map_universe(__isl_take isl_union_map *umap)2269{2270	struct isl_un_op_control control = {2271		.fn_map = &universe,2272	};2273	return un_op(umap, &control);2274}2275 2276__isl_give isl_union_set *isl_union_set_universe(__isl_take isl_union_set *uset)2277{2278	return isl_union_map_universe(uset);2279}2280 2281__isl_give isl_union_map *isl_union_map_reverse(__isl_take isl_union_map *umap)2282{2283	struct isl_un_op_control control = {2284		.fn_map = &isl_map_reverse,2285	};2286	return un_op(umap, &control);2287}2288 2289/* Given a union map, take the maps of the form A -> (B -> C) and2290 * return the union of the corresponding maps A -> (C -> B).2291 */2292__isl_give isl_union_map *isl_union_map_range_reverse(2293	__isl_take isl_union_map *umap)2294{2295	struct isl_un_op_drop_user_data data = { &isl_map_range_is_wrapping };2296	struct isl_un_op_control control = {2297		.filter = &un_op_filter_drop_user,2298		.filter_user = &data,2299		.fn_map = &isl_map_range_reverse,2300	};2301	return un_op(umap, &control);2302}2303 2304/* Compute the parameter domain of the given union map.2305 */2306__isl_give isl_set *isl_union_map_params(__isl_take isl_union_map *umap)2307{2308	struct isl_un_op_control control = {2309		.fn_map = &isl_map_params,2310	};2311	int empty;2312 2313	empty = isl_union_map_is_empty(umap);2314	if (empty < 0)2315		goto error;2316	if (empty) {2317		isl_space *space;2318		space = isl_union_map_get_space(umap);2319		isl_union_map_free(umap);2320		return isl_set_empty(space);2321	}2322	return isl_set_from_union_set(un_op(umap, &control));2323error:2324	isl_union_map_free(umap);2325	return NULL;2326}2327 2328/* Compute the parameter domain of the given union set.2329 */2330__isl_give isl_set *isl_union_set_params(__isl_take isl_union_set *uset)2331{2332	return isl_union_map_params(uset);2333}2334 2335__isl_give isl_union_set *isl_union_map_domain(__isl_take isl_union_map *umap)2336{2337	struct isl_un_op_control control = {2338		.fn_map = &isl_map_domain,2339	};2340	return un_op(umap, &control);2341}2342 2343__isl_give isl_union_set *isl_union_map_range(__isl_take isl_union_map *umap)2344{2345	struct isl_un_op_control control = {2346		.fn_map = &isl_map_range,2347	};2348	return un_op(umap, &control);2349}2350 2351__isl_give isl_union_map *isl_union_map_domain_map(2352	__isl_take isl_union_map *umap)2353{2354	struct isl_un_op_control control = {2355		.fn_map = &isl_map_domain_map,2356	};2357	return un_op(umap, &control);2358}2359 2360/* Construct an isl_pw_multi_aff that maps "map" to its domain and2361 * add the result to "res".2362 */2363static isl_stat domain_map_upma(__isl_take isl_map *map, void *user)2364{2365	isl_union_pw_multi_aff **res = user;2366	isl_multi_aff *ma;2367	isl_pw_multi_aff *pma;2368 2369	ma = isl_multi_aff_domain_map(isl_map_get_space(map));2370	pma = isl_pw_multi_aff_alloc(isl_map_wrap(map), ma);2371	*res = isl_union_pw_multi_aff_add_pw_multi_aff(*res, pma);2372 2373	return *res ? isl_stat_ok : isl_stat_error;2374 2375}2376 2377/* Return an isl_union_pw_multi_aff that maps a wrapped copy of "umap"2378 * to its domain.2379 */2380__isl_give isl_union_pw_multi_aff *isl_union_map_domain_map_union_pw_multi_aff(2381	__isl_take isl_union_map *umap)2382{2383	isl_union_pw_multi_aff *res;2384 2385	res = isl_union_pw_multi_aff_empty(isl_union_map_get_space(umap));2386	if (isl_union_map_foreach_map(umap, &domain_map_upma, &res) < 0)2387		res = isl_union_pw_multi_aff_free(res);2388 2389	isl_union_map_free(umap);2390	return res;2391}2392 2393__isl_give isl_union_map *isl_union_map_range_map(2394	__isl_take isl_union_map *umap)2395{2396	struct isl_un_op_control control = {2397		.fn_map = &isl_map_range_map,2398	};2399	return un_op(umap, &control);2400}2401 2402/* Given a collection of wrapped maps of the form A[B -> C],2403 * return the collection of maps A[B -> C] -> B.2404 */2405__isl_give isl_union_map *isl_union_set_wrapped_domain_map(2406	__isl_take isl_union_set *uset)2407{2408	struct isl_un_op_drop_user_data data = { &isl_set_is_wrapping };2409	struct isl_un_op_control control = {2410		.filter = &un_op_filter_drop_user,2411		.filter_user = &data,2412		.fn_map = &isl_set_wrapped_domain_map,2413	};2414	return un_op(uset, &control);2415}2416 2417/* Does "map" relate elements from the same space?2418 */2419static isl_bool equal_tuples(__isl_keep isl_map *map, void *user)2420{2421	return isl_map_tuple_is_equal(map, isl_dim_in, map, isl_dim_out);2422}2423 2424__isl_give isl_union_set *isl_union_map_deltas(__isl_take isl_union_map *umap)2425{2426	struct isl_un_op_control control = {2427		.filter = &equal_tuples,2428		.fn_map = &isl_map_deltas,2429	};2430	return un_op(umap, &control);2431}2432 2433__isl_give isl_union_map *isl_union_map_deltas_map(2434	__isl_take isl_union_map *umap)2435{2436	struct isl_un_op_control control = {2437		.filter = &equal_tuples,2438		.fn_map = &isl_map_deltas_map,2439	};2440	return un_op(umap, &control);2441}2442 2443__isl_give isl_union_map *isl_union_set_identity(__isl_take isl_union_set *uset)2444{2445	struct isl_un_op_control control = {2446		.fn_map = &isl_set_identity,2447	};2448	return un_op(uset, &control);2449}2450 2451/* Construct an identity isl_pw_multi_aff on "set" and add it to *res.2452 */2453static isl_stat identity_upma(__isl_take isl_set *set, void *user)2454{2455	isl_union_pw_multi_aff **res = user;2456	isl_space *space;2457	isl_pw_multi_aff *pma;2458 2459	space = isl_space_map_from_set(isl_set_get_space(set));2460	pma = isl_pw_multi_aff_identity(space);2461	pma = isl_pw_multi_aff_intersect_domain(pma, set);2462	*res = isl_union_pw_multi_aff_add_pw_multi_aff(*res, pma);2463 2464	return *res ? isl_stat_ok : isl_stat_error;2465}2466 2467/* Return an identity function on "uset" in the form2468 * of an isl_union_pw_multi_aff.2469 */2470__isl_give isl_union_pw_multi_aff *isl_union_set_identity_union_pw_multi_aff(2471	__isl_take isl_union_set *uset)2472{2473	isl_union_pw_multi_aff *res;2474 2475	res = isl_union_pw_multi_aff_empty(isl_union_set_get_space(uset));2476	if (isl_union_set_foreach_set(uset, &identity_upma, &res) < 0)2477		res = isl_union_pw_multi_aff_free(res);2478 2479	isl_union_set_free(uset);2480	return res;2481}2482 2483/* For each map in "umap" of the form [A -> B] -> C,2484 * construct the map A -> C and collect the results.2485 */2486__isl_give isl_union_map *isl_union_map_domain_factor_domain(2487	__isl_take isl_union_map *umap)2488{2489	struct isl_un_op_drop_user_data data = { &isl_map_domain_is_wrapping };2490	struct isl_un_op_control control = {2491		.filter = &un_op_filter_drop_user,2492		.filter_user = &data,2493		.fn_map = &isl_map_domain_factor_domain,2494	};2495	return un_op(umap, &control);2496}2497 2498/* For each map in "umap" of the form [A -> B] -> C,2499 * construct the map B -> C and collect the results.2500 */2501__isl_give isl_union_map *isl_union_map_domain_factor_range(2502	__isl_take isl_union_map *umap)2503{2504	struct isl_un_op_drop_user_data data = { &isl_map_domain_is_wrapping };2505	struct isl_un_op_control control = {2506		.filter = &un_op_filter_drop_user,2507		.filter_user = &data,2508		.fn_map = &isl_map_domain_factor_range,2509	};2510	return un_op(umap, &control);2511}2512 2513/* For each map in "umap" of the form A -> [B -> C],2514 * construct the map A -> B and collect the results.2515 */2516__isl_give isl_union_map *isl_union_map_range_factor_domain(2517	__isl_take isl_union_map *umap)2518{2519	struct isl_un_op_drop_user_data data = { &isl_map_range_is_wrapping };2520	struct isl_un_op_control control = {2521		.filter = &un_op_filter_drop_user,2522		.filter_user = &data,2523		.fn_map = &isl_map_range_factor_domain,2524	};2525	return un_op(umap, &control);2526}2527 2528/* For each map in "umap" of the form A -> [B -> C],2529 * construct the map A -> C and collect the results.2530 */2531__isl_give isl_union_map *isl_union_map_range_factor_range(2532	__isl_take isl_union_map *umap)2533{2534	struct isl_un_op_drop_user_data data = { &isl_map_range_is_wrapping };2535	struct isl_un_op_control control = {2536		.filter = &un_op_filter_drop_user,2537		.filter_user = &data,2538		.fn_map = &isl_map_range_factor_range,2539	};2540	return un_op(umap, &control);2541}2542 2543/* For each map in "umap" of the form [A -> B] -> [C -> D],2544 * construct the map A -> C and collect the results.2545 */2546__isl_give isl_union_map *isl_union_map_factor_domain(2547	__isl_take isl_union_map *umap)2548{2549	struct isl_un_op_drop_user_data data = { &isl_map_is_product };2550	struct isl_un_op_control control = {2551		.filter = &un_op_filter_drop_user,2552		.filter_user = &data,2553		.fn_map = &isl_map_factor_domain,2554	};2555	return un_op(umap, &control);2556}2557 2558/* For each map in "umap" of the form [A -> B] -> [C -> D],2559 * construct the map B -> D and collect the results.2560 */2561__isl_give isl_union_map *isl_union_map_factor_range(2562	__isl_take isl_union_map *umap)2563{2564	struct isl_un_op_drop_user_data data = { &isl_map_is_product };2565	struct isl_un_op_control control = {2566		.filter = &un_op_filter_drop_user,2567		.filter_user = &data,2568		.fn_map = &isl_map_factor_range,2569	};2570	return un_op(umap, &control);2571}2572 2573__isl_give isl_union_map *isl_union_set_unwrap(__isl_take isl_union_set *uset)2574{2575	struct isl_un_op_drop_user_data data = { &isl_set_is_wrapping };2576	struct isl_un_op_control control = {2577		.filter = &un_op_filter_drop_user,2578		.filter_user = &data,2579		.fn_map = &isl_set_unwrap,2580	};2581	return un_op(uset, &control);2582}2583 2584__isl_give isl_union_set *isl_union_map_wrap(__isl_take isl_union_map *umap)2585{2586	struct isl_un_op_control control = {2587		.fn_map = &isl_map_wrap,2588	};2589	return un_op(umap, &control);2590}2591 2592struct isl_union_map_is_subset_data {2593	isl_union_map *umap2;2594	isl_bool is_subset;2595};2596 2597static isl_stat is_subset_entry(void **entry, void *user)2598{2599	struct isl_union_map_is_subset_data *data = user;2600	struct isl_hash_table_entry *entry2;2601	isl_space *space;2602	isl_map *map = *entry;2603 2604	space = isl_map_peek_space(map);2605	entry2 = isl_union_map_find_entry(data->umap2, space, 0);2606	if (!entry2)2607		return isl_stat_error;2608	if (entry2 == isl_hash_table_entry_none) {2609		int empty = isl_map_is_empty(map);2610		if (empty < 0)2611			return isl_stat_error;2612		if (empty)2613			return isl_stat_ok;2614		data->is_subset = isl_bool_false;2615		return isl_stat_error;2616	}2617 2618	data->is_subset = isl_map_is_subset(map, entry2->data);2619	if (data->is_subset < 0 || !data->is_subset)2620		return isl_stat_error;2621 2622	return isl_stat_ok;2623}2624 2625isl_bool isl_union_map_is_subset(__isl_keep isl_union_map *umap1,2626	__isl_keep isl_union_map *umap2)2627{2628	struct isl_union_map_is_subset_data data = { NULL, isl_bool_true };2629 2630	if (!umap1 || !umap2)2631		return isl_bool_error;2632 2633	data.umap2 = umap2;2634	if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table,2635				   &is_subset_entry, &data) < 0 &&2636	    data.is_subset)2637		return isl_bool_error;2638 2639	return data.is_subset;2640}2641 2642isl_bool isl_union_set_is_subset(__isl_keep isl_union_set *uset1,2643	__isl_keep isl_union_set *uset2)2644{2645	return isl_union_map_is_subset(uset1, uset2);2646}2647 2648isl_bool isl_union_map_is_equal(__isl_keep isl_union_map *umap1,2649	__isl_keep isl_union_map *umap2)2650{2651	isl_bool is_subset;2652 2653	if (!umap1 || !umap2)2654		return isl_bool_error;2655	is_subset = isl_union_map_is_subset(umap1, umap2);2656	if (is_subset != isl_bool_true)2657		return is_subset;2658	is_subset = isl_union_map_is_subset(umap2, umap1);2659	return is_subset;2660}2661 2662isl_bool isl_union_set_is_equal(__isl_keep isl_union_set *uset1,2663	__isl_keep isl_union_set *uset2)2664{2665	return isl_union_map_is_equal(uset1, uset2);2666}2667 2668isl_bool isl_union_map_is_strict_subset(__isl_keep isl_union_map *umap1,2669	__isl_keep isl_union_map *umap2)2670{2671	isl_bool is_subset;2672 2673	if (!umap1 || !umap2)2674		return isl_bool_error;2675	is_subset = isl_union_map_is_subset(umap1, umap2);2676	if (is_subset != isl_bool_true)2677		return is_subset;2678	is_subset = isl_union_map_is_subset(umap2, umap1);2679	return isl_bool_not(is_subset);2680}2681 2682isl_bool isl_union_set_is_strict_subset(__isl_keep isl_union_set *uset1,2683	__isl_keep isl_union_set *uset2)2684{2685	return isl_union_map_is_strict_subset(uset1, uset2);2686}2687 2688/* Internal data structure for isl_union_map_is_disjoint.2689 * umap2 is the union map with which we are comparing.2690 * is_disjoint is initialized to 1 and is set to 0 as soon2691 * as the union maps turn out not to be disjoint.2692 */2693struct isl_union_map_is_disjoint_data {2694	isl_union_map *umap2;2695	isl_bool is_disjoint;2696};2697 2698/* Check if "map" is disjoint from data->umap2 and abort2699 * the search if it is not.2700 */2701static isl_stat is_disjoint_entry(void **entry, void *user)2702{2703	struct isl_union_map_is_disjoint_data *data = user;2704	struct isl_hash_table_entry *entry2;2705	isl_space *space;2706	isl_map *map = *entry;2707 2708	space = isl_map_peek_space(map);2709	entry2 = isl_union_map_find_entry(data->umap2, space, 0);2710	if (!entry2)2711		return isl_stat_error;2712	if (entry2 == isl_hash_table_entry_none)2713		return isl_stat_ok;2714 2715	data->is_disjoint = isl_map_is_disjoint(map, entry2->data);2716	if (data->is_disjoint < 0 || !data->is_disjoint)2717		return isl_stat_error;2718 2719	return isl_stat_ok;2720}2721 2722/* Are "umap1" and "umap2" disjoint?2723 */2724isl_bool isl_union_map_is_disjoint(__isl_keep isl_union_map *umap1,2725	__isl_keep isl_union_map *umap2)2726{2727	struct isl_union_map_is_disjoint_data data = { NULL, isl_bool_true };2728 2729	umap1 = isl_union_map_copy(umap1);2730	umap2 = isl_union_map_copy(umap2);2731	umap1 = isl_union_map_align_params(umap1,2732						isl_union_map_get_space(umap2));2733	umap2 = isl_union_map_align_params(umap2,2734						isl_union_map_get_space(umap1));2735 2736	if (!umap1 || !umap2)2737		goto error;2738 2739	data.umap2 = umap2;2740	if (isl_hash_table_foreach(umap1->dim->ctx, &umap1->table,2741				   &is_disjoint_entry, &data) < 0 &&2742	    data.is_disjoint)2743		goto error;2744 2745	isl_union_map_free(umap1);2746	isl_union_map_free(umap2);2747 2748	return data.is_disjoint;2749error:2750	isl_union_map_free(umap1);2751	isl_union_map_free(umap2);2752	return isl_bool_error;2753}2754 2755/* Are "uset1" and "uset2" disjoint?2756 */2757isl_bool isl_union_set_is_disjoint(__isl_keep isl_union_set *uset1,2758	__isl_keep isl_union_set *uset2)2759{2760	return isl_union_map_is_disjoint(uset1, uset2);2761}2762 2763static isl_stat sample_entry(void **entry, void *user)2764{2765	isl_basic_map **sample = (isl_basic_map **)user;2766	isl_map *map = *entry;2767 2768	*sample = isl_map_sample(isl_map_copy(map));2769	if (!*sample)2770		return isl_stat_error;2771	if (!isl_basic_map_plain_is_empty(*sample))2772		return isl_stat_error;2773	return isl_stat_ok;2774}2775 2776__isl_give isl_basic_map *isl_union_map_sample(__isl_take isl_union_map *umap)2777{2778	isl_basic_map *sample = NULL;2779 2780	if (!umap)2781		return NULL;2782 2783	if (isl_hash_table_foreach(umap->dim->ctx, &umap->table,2784				   &sample_entry, &sample) < 0 &&2785	    !sample)2786		goto error;2787 2788	if (!sample)2789		sample = isl_basic_map_empty(isl_union_map_get_space(umap));2790 2791	isl_union_map_free(umap);2792 2793	return sample;2794error:2795	isl_union_map_free(umap);2796	return NULL;2797}2798 2799__isl_give isl_basic_set *isl_union_set_sample(__isl_take isl_union_set *uset)2800{2801	return bset_from_bmap(isl_union_map_sample(uset));2802}2803 2804/* Return an element in "uset" in the form of an isl_point.2805 * Return a void isl_point if "uset" is empty.2806 */2807__isl_give isl_point *isl_union_set_sample_point(__isl_take isl_union_set *uset)2808{2809	return isl_basic_set_sample_point(isl_union_set_sample(uset));2810}2811 2812struct isl_forall_data {2813	isl_bool res;2814	isl_bool (*fn)(__isl_keep isl_map *map);2815};2816 2817static isl_stat forall_entry(void **entry, void *user)2818{2819	struct isl_forall_data *data = user;2820	isl_map *map = *entry;2821 2822	data->res = data->fn(map);2823	if (data->res < 0)2824		return isl_stat_error;2825 2826	if (!data->res)2827		return isl_stat_error;2828 2829	return isl_stat_ok;2830}2831 2832static isl_bool union_map_forall(__isl_keep isl_union_map *umap,2833	isl_bool (*fn)(__isl_keep isl_map *map))2834{2835	struct isl_forall_data data = { isl_bool_true, fn };2836 2837	if (!umap)2838		return isl_bool_error;2839 2840	if (isl_hash_table_foreach(umap->dim->ctx, &umap->table,2841				   &forall_entry, &data) < 0 && data.res)2842		return isl_bool_error;2843 2844	return data.res;2845}2846 2847struct isl_forall_user_data {2848	isl_bool res;2849	isl_bool (*fn)(__isl_keep isl_map *map, void *user);2850	void *user;2851};2852 2853static isl_stat forall_user_entry(void **entry, void *user)2854{2855	struct isl_forall_user_data *data = user;2856	isl_map *map = *entry;2857 2858	data->res = data->fn(map, data->user);2859	if (data->res < 0)2860		return isl_stat_error;2861 2862	if (!data->res)2863		return isl_stat_error;2864 2865	return isl_stat_ok;2866}2867 2868/* Check if fn(map, user) returns true for all maps "map" in umap.2869 */2870static isl_bool union_map_forall_user(__isl_keep isl_union_map *umap,2871	isl_bool (*fn)(__isl_keep isl_map *map, void *user), void *user)2872{2873	struct isl_forall_user_data data = { isl_bool_true, fn, user };2874 2875	if (!umap)2876		return isl_bool_error;2877 2878	if (isl_hash_table_foreach(umap->dim->ctx, &umap->table,2879				   &forall_user_entry, &data) < 0 && data.res)2880		return isl_bool_error;2881 2882	return data.res;2883}2884 2885/* Is "umap" obviously empty?2886 */2887isl_bool isl_union_map_plain_is_empty(__isl_keep isl_union_map *umap)2888{2889	isl_size n;2890 2891	n = isl_union_map_n_map(umap);2892	if (n < 0)2893		return isl_bool_error;2894	return n == 0;2895}2896 2897isl_bool isl_union_map_is_empty(__isl_keep isl_union_map *umap)2898{2899	return union_map_forall(umap, &isl_map_is_empty);2900}2901 2902isl_bool isl_union_set_is_empty(__isl_keep isl_union_set *uset)2903{2904	return isl_union_map_is_empty(uset);2905}2906 2907static isl_bool is_subset_of_identity(__isl_keep isl_map *map)2908{2909	isl_bool is_subset;2910	isl_space *space;2911	isl_map *id;2912	isl_bool match;2913 2914	match = isl_map_tuple_is_equal(map, isl_dim_in, map, isl_dim_out);2915	if (match < 0)2916		return isl_bool_error;2917	if (!match)2918		return isl_bool_false;2919 2920	space = isl_map_get_space(map);2921	id = isl_map_identity(space);2922 2923	is_subset = isl_map_is_subset(map, id);2924 2925	isl_map_free(id);2926 2927	return is_subset;2928}2929 2930/* Given an isl_union_map that consists of a single map, check2931 * if it is single-valued.2932 */2933static isl_bool single_map_is_single_valued(__isl_keep isl_union_map *umap)2934{2935	isl_map *map;2936	isl_bool sv;2937 2938	umap = isl_union_map_copy(umap);2939	map = isl_map_from_union_map(umap);2940	sv = isl_map_is_single_valued(map);2941	isl_map_free(map);2942 2943	return sv;2944}2945 2946/* Internal data structure for single_valued_on_domain.2947 *2948 * "umap" is the union map to be tested.2949 * "sv" is set to 1 as long as "umap" may still be single-valued.2950 */2951struct isl_union_map_is_sv_data {2952	isl_union_map *umap;2953	isl_bool sv;2954};2955 2956/* Check if the data->umap is single-valued on "set".2957 *2958 * If data->umap consists of a single map on "set", then test it2959 * as an isl_map.2960 *2961 * Otherwise, compute2962 *2963 *	M \circ M^-12964 *2965 * check if the result is a subset of the identity mapping and2966 * store the result in data->sv.2967 *2968 * Terminate as soon as data->umap has been determined not to2969 * be single-valued.2970 */2971static isl_stat single_valued_on_domain(__isl_take isl_set *set, void *user)2972{2973	struct isl_union_map_is_sv_data *data = user;2974	isl_union_map *umap, *test;2975	isl_size n;2976 2977	umap = isl_union_map_copy(data->umap);2978	umap = isl_union_map_intersect_domain(umap,2979						isl_union_set_from_set(set));2980 2981	n = isl_union_map_n_map(umap);2982	if (n < 0) {2983		data->sv = isl_bool_error;2984	} else if (n == 1) {2985		data->sv = single_map_is_single_valued(umap);2986		isl_union_map_free(umap);2987	} else {2988		test = isl_union_map_reverse(isl_union_map_copy(umap));2989		test = isl_union_map_apply_range(test, umap);2990 2991		data->sv = union_map_forall(test, &is_subset_of_identity);2992 2993		isl_union_map_free(test);2994	}2995 2996	if (data->sv < 0 || !data->sv)2997		return isl_stat_error;2998	return isl_stat_ok;2999}3000 3001/* Check if the given map is single-valued.3002 *3003 * If the union map consists of a single map, then test it as an isl_map.3004 * Otherwise, check if the union map is single-valued on each of its3005 * domain spaces.3006 */3007isl_bool isl_union_map_is_single_valued(__isl_keep isl_union_map *umap)3008{3009	isl_union_map *universe;3010	isl_union_set *domain;3011	struct isl_union_map_is_sv_data data;3012	isl_size n;3013 3014	n = isl_union_map_n_map(umap);3015	if (n < 0)3016		return isl_bool_error;3017	if (n == 1)3018		return single_map_is_single_valued(umap);3019 3020	universe = isl_union_map_universe(isl_union_map_copy(umap));3021	domain = isl_union_map_domain(universe);3022 3023	data.sv = isl_bool_true;3024	data.umap = umap;3025	if (isl_union_set_foreach_set(domain,3026			    &single_valued_on_domain, &data) < 0 && data.sv)3027		data.sv = isl_bool_error;3028	isl_union_set_free(domain);3029 3030	return data.sv;3031}3032 3033isl_bool isl_union_map_is_injective(__isl_keep isl_union_map *umap)3034{3035	isl_bool in;3036 3037	umap = isl_union_map_copy(umap);3038	umap = isl_union_map_reverse(umap);3039	in = isl_union_map_is_single_valued(umap);3040	isl_union_map_free(umap);3041 3042	return in;3043}3044 3045/* Is "map" obviously not an identity relation because3046 * it maps elements from one space to another space?3047 * Update *non_identity accordingly.3048 *3049 * In particular, if the domain and range spaces are the same,3050 * then the map is not considered to obviously not be an identity relation.3051 * Otherwise, the map is considered to obviously not be an identity relation3052 * if it is is non-empty.3053 *3054 * If "map" is determined to obviously not be an identity relation,3055 * then the search is aborted.3056 */3057static isl_stat map_plain_is_not_identity(__isl_take isl_map *map, void *user)3058{3059	isl_bool *non_identity = user;3060	isl_bool equal;3061 3062	equal = isl_map_tuple_is_equal(map, isl_dim_in, map, isl_dim_out);3063	if (equal >= 0 && !equal)3064		*non_identity = isl_bool_not(isl_map_is_empty(map));3065	else3066		*non_identity = isl_bool_not(equal);3067	isl_map_free(map);3068 3069	if (*non_identity < 0 || *non_identity)3070		return isl_stat_error;3071 3072	return isl_stat_ok;3073}3074 3075/* Is "umap" obviously not an identity relation because3076 * it maps elements from one space to another space?3077 *3078 * As soon as a map has been found that maps elements to a different space,3079 * non_identity is changed and the search is aborted.3080 */3081static isl_bool isl_union_map_plain_is_not_identity(3082	__isl_keep isl_union_map *umap)3083{3084	isl_bool non_identity;3085 3086	non_identity = isl_bool_false;3087	if (isl_union_map_foreach_map(umap, &map_plain_is_not_identity,3088					&non_identity) < 0 &&3089	    non_identity == isl_bool_false)3090		return isl_bool_error;3091 3092	return non_identity;3093}3094 3095/* Does "map" only map elements to themselves?3096 * Update *identity accordingly.3097 *3098 * If "map" is determined not to be an identity relation,3099 * then the search is aborted.3100 */3101static isl_stat map_is_identity(__isl_take isl_map *map, void *user)3102{3103	isl_bool *identity = user;3104 3105	*identity = isl_map_is_identity(map);3106	isl_map_free(map);3107 3108	if (*identity < 0 || !*identity)3109		return isl_stat_error;3110 3111	return isl_stat_ok;3112}3113 3114/* Does "umap" only map elements to themselves?3115 *3116 * First check if there are any maps that map elements to different spaces.3117 * If not, then check that all the maps (between identical spaces)3118 * are identity relations.3119 */3120isl_bool isl_union_map_is_identity(__isl_keep isl_union_map *umap)3121{3122	isl_bool non_identity;3123	isl_bool identity;3124 3125	non_identity = isl_union_map_plain_is_not_identity(umap);3126	if (non_identity < 0 || non_identity)3127		return isl_bool_not(non_identity);3128 3129	identity = isl_bool_true;3130	if (isl_union_map_foreach_map(umap, &map_is_identity, &identity) < 0 &&3131	    identity == isl_bool_true)3132		return isl_bool_error;3133 3134	return identity;3135}3136 3137/* Represents a map that has a fixed value (v) for one of its3138 * range dimensions.3139 * The map in this structure is not reference counted, so it3140 * is only valid while the isl_union_map from which it was3141 * obtained is still alive.3142 */3143struct isl_fixed_map {3144	isl_int v;3145	isl_map *map;3146};3147 3148static struct isl_fixed_map *alloc_isl_fixed_map_array(isl_ctx *ctx,3149	int n)3150{3151	int i;3152	struct isl_fixed_map *v;3153 3154	v = isl_calloc_array(ctx, struct isl_fixed_map, n);3155	if (!v)3156		return NULL;3157	for (i = 0; i < n; ++i)3158		isl_int_init(v[i].v);3159	return v;3160}3161 3162static void free_isl_fixed_map_array(struct isl_fixed_map *v, int n)3163{3164	int i;3165 3166	if (!v)3167		return;3168	for (i = 0; i < n; ++i)3169		isl_int_clear(v[i].v);3170	free(v);3171}3172 3173/* Compare the "v" field of two isl_fixed_map structs.3174 */3175static int qsort_fixed_map_cmp(const void *p1, const void *p2)3176{3177	const struct isl_fixed_map *e1 = (const struct isl_fixed_map *) p1;3178	const struct isl_fixed_map *e2 = (const struct isl_fixed_map *) p2;3179 3180	return isl_int_cmp(e1->v, e2->v);3181}3182 3183/* Internal data structure used while checking whether all maps3184 * in a union_map have a fixed value for a given output dimension.3185 * v is the list of maps, with the fixed value for the dimension3186 * n is the number of maps considered so far3187 * pos is the output dimension under investigation3188 */3189struct isl_fixed_dim_data {3190	struct isl_fixed_map *v;3191	int n;3192	int pos;3193};3194 3195static isl_bool fixed_at_pos(__isl_keep isl_map *map, void *user)3196{3197	struct isl_fixed_dim_data *data = user;3198 3199	data->v[data->n].map = map;3200	return isl_map_plain_is_fixed(map, isl_dim_out, data->pos,3201				      &data->v[data->n++].v);3202}3203 3204static isl_bool plain_injective_on_range(__isl_take isl_union_map *umap,3205	int first, int n_range);3206 3207/* Given a list of the maps, with their fixed values at output dimension "pos",3208 * check whether the ranges of the maps form an obvious partition.3209 *3210 * We first sort the maps according to their fixed values.3211 * If all maps have a different value, then we know the ranges form3212 * a partition.3213 * Otherwise, we collect the maps with the same fixed value and3214 * check whether each such collection is obviously injective3215 * based on later dimensions.3216 */3217static int separates(struct isl_fixed_map *v, int n,3218	__isl_take isl_space *space, int pos, int n_range)3219{3220	int i;3221 3222	if (!v)3223		goto error;3224 3225	qsort(v, n, sizeof(*v), &qsort_fixed_map_cmp);3226 3227	for (i = 0; i + 1 < n; ++i) {3228		int j, k;3229		isl_union_map *part;3230		int injective;3231 3232		for (j = i + 1; j < n; ++j)3233			if (isl_int_ne(v[i].v, v[j].v))3234				break;3235 3236		if (j == i + 1)3237			continue;3238 3239		part = isl_union_map_alloc(isl_space_copy(space), j - i);3240		for (k = i; k < j; ++k)3241			part = isl_union_map_add_map(part,3242						     isl_map_copy(v[k].map));3243 3244		injective = plain_injective_on_range(part, pos + 1, n_range);3245		if (injective < 0)3246			goto error;3247		if (!injective)3248			break;3249 3250		i = j - 1;3251	}3252 3253	isl_space_free(space);3254	free_isl_fixed_map_array(v, n);3255	return i + 1 >= n;3256error:3257	isl_space_free(space);3258	free_isl_fixed_map_array(v, n);3259	return -1;3260}3261 3262/* Check whether the maps in umap have obviously distinct ranges.3263 * In particular, check for an output dimension in the range3264 * [first,n_range) for which all maps have a fixed value3265 * and then check if these values, possibly along with fixed values3266 * at later dimensions, entail distinct ranges.3267 */3268static isl_bool plain_injective_on_range(__isl_take isl_union_map *umap,3269	int first, int n_range)3270{3271	isl_ctx *ctx;3272	isl_size n;3273	struct isl_fixed_dim_data data = { NULL };3274 3275	ctx = isl_union_map_get_ctx(umap);3276 3277	n = isl_union_map_n_map(umap);3278	if (n < 0)3279		goto error;3280 3281	if (n <= 1) {3282		isl_union_map_free(umap);3283		return isl_bool_true;3284	}3285 3286	if (first >= n_range) {3287		isl_union_map_free(umap);3288		return isl_bool_false;3289	}3290 3291	data.v = alloc_isl_fixed_map_array(ctx, n);3292	if (!data.v)3293		goto error;3294 3295	for (data.pos = first; data.pos < n_range; ++data.pos) {3296		isl_bool fixed;3297		int injective;3298		isl_space *space;3299 3300		data.n = 0;3301		fixed = union_map_forall_user(umap, &fixed_at_pos, &data);3302		if (fixed < 0)3303			goto error;3304		if (!fixed)3305			continue;3306		space = isl_union_map_get_space(umap);3307		injective = separates(data.v, n, space, data.pos, n_range);3308		isl_union_map_free(umap);3309		return injective;3310	}3311 3312	free_isl_fixed_map_array(data.v, n);3313	isl_union_map_free(umap);3314 3315	return isl_bool_false;3316error:3317	free_isl_fixed_map_array(data.v, n);3318	isl_union_map_free(umap);3319	return isl_bool_error;3320}3321 3322/* Check whether the maps in umap that map to subsets of "ran"3323 * have obviously distinct ranges.3324 */3325static isl_bool plain_injective_on_range_wrap(__isl_keep isl_set *ran,3326	void *user)3327{3328	isl_size dim;3329	isl_union_map *umap = user;3330 3331	dim = isl_set_dim(ran, isl_dim_set);3332	if (dim < 0)3333		return isl_bool_error;3334 3335	umap = isl_union_map_copy(umap);3336	umap = isl_union_map_intersect_range(umap,3337			isl_union_set_from_set(isl_set_copy(ran)));3338	return plain_injective_on_range(umap, 0, dim);3339}3340 3341/* Check if the given union_map is obviously injective.3342 *3343 * In particular, we first check if all individual maps are obviously3344 * injective and then check if all the ranges of these maps are3345 * obviously disjoint.3346 */3347isl_bool isl_union_map_plain_is_injective(__isl_keep isl_union_map *umap)3348{3349	isl_bool in;3350	isl_union_map *univ;3351	isl_union_set *ran;3352 3353	in = union_map_forall(umap, &isl_map_plain_is_injective);3354	if (in < 0)3355		return isl_bool_error;3356	if (!in)3357		return isl_bool_false;3358 3359	univ = isl_union_map_universe(isl_union_map_copy(umap));3360	ran = isl_union_map_range(univ);3361 3362	in = union_map_forall_user(ran, &plain_injective_on_range_wrap, umap);3363 3364	isl_union_set_free(ran);3365 3366	return in;3367}3368 3369isl_bool isl_union_map_is_bijective(__isl_keep isl_union_map *umap)3370{3371	isl_bool sv;3372 3373	sv = isl_union_map_is_single_valued(umap);3374	if (sv < 0 || !sv)3375		return sv;3376 3377	return isl_union_map_is_injective(umap);3378}3379 3380__isl_give isl_union_map *isl_union_map_zip(__isl_take isl_union_map *umap)3381{3382	struct isl_un_op_drop_user_data data = { &isl_map_can_zip };3383	struct isl_un_op_control control = {3384		.filter = &un_op_filter_drop_user,3385		.filter_user = &data,3386		.fn_map = &isl_map_zip,3387	};3388	return un_op(umap, &control);3389}3390 3391/* Given a union map, take the maps of the form A -> (B -> C) and3392 * return the union of the corresponding maps (A -> B) -> C.3393 */3394__isl_give isl_union_map *isl_union_map_uncurry(__isl_take isl_union_map *umap)3395{3396	struct isl_un_op_drop_user_data data = { &isl_map_can_uncurry };3397	struct isl_un_op_control control = {3398		.filter = &un_op_filter_drop_user,3399		.filter_user = &data,3400		.fn_map = &isl_map_uncurry,3401	};3402	return un_op(umap, &control);3403}3404 3405/* Given a union map, take the maps of the form (A -> B) -> C and3406 * return the union of the corresponding maps A -> (B -> C).3407 */3408__isl_give isl_union_map *isl_union_map_curry(__isl_take isl_union_map *umap)3409{3410	struct isl_un_op_drop_user_data data = { &isl_map_can_curry };3411	struct isl_un_op_control control = {3412		.filter = &un_op_filter_drop_user,3413		.filter_user = &data,3414		.fn_map = &isl_map_curry,3415	};3416	return un_op(umap, &control);3417}3418 3419/* Given a union map, take the maps of the form A -> ((B -> C) -> D) and3420 * return the union of the corresponding maps A -> (B -> (C -> D)).3421 */3422__isl_give isl_union_map *isl_union_map_range_curry(3423	__isl_take isl_union_map *umap)3424{3425	struct isl_un_op_drop_user_data data = { &isl_map_can_range_curry };3426	struct isl_un_op_control control = {3427		.filter = &un_op_filter_drop_user,3428		.filter_user = &data,3429		.fn_map = &isl_map_range_curry,3430	};3431	return un_op(umap, &control);3432}3433 3434__isl_give isl_union_set *isl_union_set_lift(__isl_take isl_union_set *uset)3435{3436	struct isl_un_op_control control = {3437		.fn_map = &isl_set_lift,3438	};3439	return un_op(uset, &control);3440}3441 3442static isl_stat coefficients_entry(void **entry, void *user)3443{3444	isl_set *set = *entry;3445	isl_union_set **res = user;3446 3447	set = isl_set_copy(set);3448	set = isl_set_from_basic_set(isl_set_coefficients(set));3449	*res = isl_union_set_add_set(*res, set);3450 3451	return isl_stat_ok;3452}3453 3454__isl_give isl_union_set *isl_union_set_coefficients(3455	__isl_take isl_union_set *uset)3456{3457	isl_ctx *ctx;3458	isl_space *space;3459	isl_union_set *res;3460 3461	if (!uset)3462		return NULL;3463 3464	ctx = isl_union_set_get_ctx(uset);3465	space = isl_space_set_alloc(ctx, 0, 0);3466	res = isl_union_map_alloc(space, uset->table.n);3467	if (isl_hash_table_foreach(uset->dim->ctx, &uset->table,3468				   &coefficients_entry, &res) < 0)3469		goto error;3470 3471	isl_union_set_free(uset);3472	return res;3473error:3474	isl_union_set_free(uset);3475	isl_union_set_free(res);3476	return NULL;3477}3478 3479static isl_stat solutions_entry(void **entry, void *user)3480{3481	isl_set *set = *entry;3482	isl_union_set **res = user;3483 3484	set = isl_set_copy(set);3485	set = isl_set_from_basic_set(isl_set_solutions(set));3486	if (!*res)3487		*res = isl_union_set_from_set(set);3488	else3489		*res = isl_union_set_add_set(*res, set);3490 3491	if (!*res)3492		return isl_stat_error;3493 3494	return isl_stat_ok;3495}3496 3497__isl_give isl_union_set *isl_union_set_solutions(3498	__isl_take isl_union_set *uset)3499{3500	isl_union_set *res = NULL;3501 3502	if (!uset)3503		return NULL;3504 3505	if (uset->table.n == 0) {3506		res = isl_union_set_empty(isl_union_set_get_space(uset));3507		isl_union_set_free(uset);3508		return res;3509	}3510 3511	if (isl_hash_table_foreach(uset->dim->ctx, &uset->table,3512				   &solutions_entry, &res) < 0)3513		goto error;3514 3515	isl_union_set_free(uset);3516	return res;3517error:3518	isl_union_set_free(uset);3519	isl_union_set_free(res);3520	return NULL;3521}3522 3523/* Is the domain space of "map" equal to "space"?3524 */3525static int domain_match(__isl_keep isl_map *map, __isl_keep isl_space *space)3526{3527	return isl_map_space_tuple_is_equal(map, isl_dim_in,3528					space, isl_dim_out);3529}3530 3531/* Is the range space of "map" equal to "space"?3532 */3533static int range_match(__isl_keep isl_map *map, __isl_keep isl_space *space)3534{3535	return isl_map_space_tuple_is_equal(map, isl_dim_out,3536					space, isl_dim_out);3537}3538 3539/* Is the set space of "map" equal to "space"?3540 */3541static int set_match(__isl_keep isl_map *map, __isl_keep isl_space *space)3542{3543	return isl_map_space_tuple_is_equal(map, isl_dim_set,3544					space, isl_dim_out);3545}3546 3547/* Internal data structure for preimage_pw_multi_aff.3548 *3549 * "pma" is the function under which the preimage should be taken.3550 * "space" is the space of "pma".3551 * "res" collects the results.3552 * "fn" computes the preimage for a given map.3553 * "match" returns true if "fn" can be called.3554 */3555struct isl_union_map_preimage_data {3556	isl_space *space;3557	isl_pw_multi_aff *pma;3558	isl_union_map *res;3559	int (*match)(__isl_keep isl_map *map, __isl_keep isl_space *space);3560	__isl_give isl_map *(*fn)(__isl_take isl_map *map,3561		__isl_take isl_pw_multi_aff *pma);3562};3563 3564/* Call data->fn to compute the preimage of the domain or range of *entry3565 * under the function represented by data->pma, provided the domain/range3566 * space of *entry matches the target space of data->pma3567 * (as given by data->match), and add the result to data->res.3568 */3569static isl_stat preimage_entry(void **entry, void *user)3570{3571	int m;3572	isl_map *map = *entry;3573	struct isl_union_map_preimage_data *data = user;3574	isl_bool empty;3575 3576	m = data->match(map, data->space);3577	if (m < 0)3578		return isl_stat_error;3579	if (!m)3580		return isl_stat_ok;3581 3582	map = isl_map_copy(map);3583	map = data->fn(map, isl_pw_multi_aff_copy(data->pma));3584 3585	empty = isl_map_is_empty(map);3586	if (empty < 0 || empty) {3587		isl_map_free(map);3588		return empty < 0 ? isl_stat_error : isl_stat_ok;3589	}3590 3591	data->res = isl_union_map_add_map(data->res, map);3592 3593	return isl_stat_ok;3594}3595 3596/* Compute the preimage of the domain or range of "umap" under the function3597 * represented by "pma".3598 * In other words, plug in "pma" in the domain or range of "umap".3599 * The function "fn" performs the actual preimage computation on a map,3600 * while "match" determines to which maps the function should be applied.3601 */3602static __isl_give isl_union_map *preimage_pw_multi_aff(3603	__isl_take isl_union_map *umap, __isl_take isl_pw_multi_aff *pma,3604	int (*match)(__isl_keep isl_map *map, __isl_keep isl_space *space),3605	__isl_give isl_map *(*fn)(__isl_take isl_map *map,3606		__isl_take isl_pw_multi_aff *pma))3607{3608	isl_ctx *ctx;3609	isl_space *space;3610	struct isl_union_map_preimage_data data;3611 3612	umap = isl_union_map_align_params(umap,3613					    isl_pw_multi_aff_get_space(pma));3614	pma = isl_pw_multi_aff_align_params(pma, isl_union_map_get_space(umap));3615 3616	if (!umap || !pma)3617		goto error;3618 3619	ctx = isl_union_map_get_ctx(umap);3620	space = isl_union_map_get_space(umap);3621	data.space = isl_pw_multi_aff_get_space(pma);3622	data.pma = pma;3623	data.res = isl_union_map_alloc(space, umap->table.n);3624	data.match = match;3625	data.fn = fn;3626	if (isl_hash_table_foreach(ctx, &umap->table, &preimage_entry,3627					&data) < 0)3628		data.res = isl_union_map_free(data.res);3629 3630	isl_space_free(data.space);3631	isl_union_map_free(umap);3632	isl_pw_multi_aff_free(pma);3633	return data.res;3634error:3635	isl_union_map_free(umap);3636	isl_pw_multi_aff_free(pma);3637	return NULL;3638}3639 3640/* Compute the preimage of the domain of "umap" under the function3641 * represented by "pma".3642 * In other words, plug in "pma" in the domain of "umap".3643 * The result contains maps that live in the same spaces as the maps of "umap"3644 * with domain space equal to the target space of "pma",3645 * except that the domain has been replaced by the domain space of "pma".3646 */3647__isl_give isl_union_map *isl_union_map_preimage_domain_pw_multi_aff(3648	__isl_take isl_union_map *umap, __isl_take isl_pw_multi_aff *pma)3649{3650	return preimage_pw_multi_aff(umap, pma, &domain_match,3651					&isl_map_preimage_domain_pw_multi_aff);3652}3653 3654/* Compute the preimage of the range of "umap" under the function3655 * represented by "pma".3656 * In other words, plug in "pma" in the range of "umap".3657 * The result contains maps that live in the same spaces as the maps of "umap"3658 * with range space equal to the target space of "pma",3659 * except that the range has been replaced by the domain space of "pma".3660 */3661__isl_give isl_union_map *isl_union_map_preimage_range_pw_multi_aff(3662	__isl_take isl_union_map *umap, __isl_take isl_pw_multi_aff *pma)3663{3664	return preimage_pw_multi_aff(umap, pma, &range_match,3665					&isl_map_preimage_range_pw_multi_aff);3666}3667 3668/* Compute the preimage of "uset" under the function represented by "pma".3669 * In other words, plug in "pma" in "uset".3670 * The result contains sets that live in the same spaces as the sets of "uset"3671 * with space equal to the target space of "pma",3672 * except that the space has been replaced by the domain space of "pma".3673 */3674__isl_give isl_union_set *isl_union_set_preimage_pw_multi_aff(3675	__isl_take isl_union_set *uset, __isl_take isl_pw_multi_aff *pma)3676{3677	return preimage_pw_multi_aff(uset, pma, &set_match,3678					&isl_set_preimage_pw_multi_aff);3679}3680 3681/* Compute the preimage of the domain of "umap" under the function3682 * represented by "ma".3683 * In other words, plug in "ma" in the domain of "umap".3684 * The result contains maps that live in the same spaces as the maps of "umap"3685 * with domain space equal to the target space of "ma",3686 * except that the domain has been replaced by the domain space of "ma".3687 */3688__isl_give isl_union_map *isl_union_map_preimage_domain_multi_aff(3689	__isl_take isl_union_map *umap, __isl_take isl_multi_aff *ma)3690{3691	return isl_union_map_preimage_domain_pw_multi_aff(umap,3692					isl_pw_multi_aff_from_multi_aff(ma));3693}3694 3695/* Compute the preimage of the range of "umap" under the function3696 * represented by "ma".3697 * In other words, plug in "ma" in the range of "umap".3698 * The result contains maps that live in the same spaces as the maps of "umap"3699 * with range space equal to the target space of "ma",3700 * except that the range has been replaced by the domain space of "ma".3701 */3702__isl_give isl_union_map *isl_union_map_preimage_range_multi_aff(3703	__isl_take isl_union_map *umap, __isl_take isl_multi_aff *ma)3704{3705	return isl_union_map_preimage_range_pw_multi_aff(umap,3706					isl_pw_multi_aff_from_multi_aff(ma));3707}3708 3709/* Compute the preimage of "uset" under the function represented by "ma".3710 * In other words, plug in "ma" in "uset".3711 * The result contains sets that live in the same spaces as the sets of "uset"3712 * with space equal to the target space of "ma",3713 * except that the space has been replaced by the domain space of "ma".3714 */3715__isl_give isl_union_map *isl_union_set_preimage_multi_aff(3716	__isl_take isl_union_set *uset, __isl_take isl_multi_aff *ma)3717{3718	return isl_union_set_preimage_pw_multi_aff(uset,3719					isl_pw_multi_aff_from_multi_aff(ma));3720}3721 3722/* Internal data structure for preimage_multi_pw_aff.3723 *3724 * "mpa" is the function under which the preimage should be taken.3725 * "space" is the space of "mpa".3726 * "res" collects the results.3727 * "fn" computes the preimage for a given map.3728 * "match" returns true if "fn" can be called.3729 */3730struct isl_union_map_preimage_mpa_data {3731	isl_space *space;3732	isl_multi_pw_aff *mpa;3733	isl_union_map *res;3734	int (*match)(__isl_keep isl_map *map, __isl_keep isl_space *space);3735	__isl_give isl_map *(*fn)(__isl_take isl_map *map,3736		__isl_take isl_multi_pw_aff *mpa);3737};3738 3739/* Call data->fn to compute the preimage of the domain or range of *entry3740 * under the function represented by data->mpa, provided the domain/range3741 * space of *entry matches the target space of data->mpa3742 * (as given by data->match), and add the result to data->res.3743 */3744static isl_stat preimage_mpa_entry(void **entry, void *user)3745{3746	int m;3747	isl_map *map = *entry;3748	struct isl_union_map_preimage_mpa_data *data = user;3749	isl_bool empty;3750 3751	m = data->match(map, data->space);3752	if (m < 0)3753		return isl_stat_error;3754	if (!m)3755		return isl_stat_ok;3756 3757	map = isl_map_copy(map);3758	map = data->fn(map, isl_multi_pw_aff_copy(data->mpa));3759 3760	empty = isl_map_is_empty(map);3761	if (empty < 0 || empty) {3762		isl_map_free(map);3763		return empty < 0 ? isl_stat_error : isl_stat_ok;3764	}3765 3766	data->res = isl_union_map_add_map(data->res, map);3767 3768	return isl_stat_ok;3769}3770 3771/* Compute the preimage of the domain or range of "umap" under the function3772 * represented by "mpa".3773 * In other words, plug in "mpa" in the domain or range of "umap".3774 * The function "fn" performs the actual preimage computation on a map,3775 * while "match" determines to which maps the function should be applied.3776 */3777static __isl_give isl_union_map *preimage_multi_pw_aff(3778	__isl_take isl_union_map *umap, __isl_take isl_multi_pw_aff *mpa,3779	int (*match)(__isl_keep isl_map *map, __isl_keep isl_space *space),3780	__isl_give isl_map *(*fn)(__isl_take isl_map *map,3781		__isl_take isl_multi_pw_aff *mpa))3782{3783	isl_ctx *ctx;3784	isl_space *space;3785	struct isl_union_map_preimage_mpa_data data;3786 3787	umap = isl_union_map_align_params(umap,3788					    isl_multi_pw_aff_get_space(mpa));3789	mpa = isl_multi_pw_aff_align_params(mpa, isl_union_map_get_space(umap));3790 3791	if (!umap || !mpa)3792		goto error;3793 3794	ctx = isl_union_map_get_ctx(umap);3795	space = isl_union_map_get_space(umap);3796	data.space = isl_multi_pw_aff_get_space(mpa);3797	data.mpa = mpa;3798	data.res = isl_union_map_alloc(space, umap->table.n);3799	data.match = match;3800	data.fn = fn;3801	if (isl_hash_table_foreach(ctx, &umap->table, &preimage_mpa_entry,3802					&data) < 0)3803		data.res = isl_union_map_free(data.res);3804 3805	isl_space_free(data.space);3806	isl_union_map_free(umap);3807	isl_multi_pw_aff_free(mpa);3808	return data.res;3809error:3810	isl_union_map_free(umap);3811	isl_multi_pw_aff_free(mpa);3812	return NULL;3813}3814 3815/* Compute the preimage of the domain of "umap" under the function3816 * represented by "mpa".3817 * In other words, plug in "mpa" in the domain of "umap".3818 * The result contains maps that live in the same spaces as the maps of "umap"3819 * with domain space equal to the target space of "mpa",3820 * except that the domain has been replaced by the domain space of "mpa".3821 */3822__isl_give isl_union_map *isl_union_map_preimage_domain_multi_pw_aff(3823	__isl_take isl_union_map *umap, __isl_take isl_multi_pw_aff *mpa)3824{3825	return preimage_multi_pw_aff(umap, mpa, &domain_match,3826					&isl_map_preimage_domain_multi_pw_aff);3827}3828 3829/* Internal data structure for preimage_upma.3830 *3831 * "umap" is the map of which the preimage should be computed.3832 * "res" collects the results.3833 * "fn" computes the preimage for a given piecewise multi-affine function.3834 */3835struct isl_union_map_preimage_upma_data {3836	isl_union_map *umap;3837	isl_union_map *res;3838	__isl_give isl_union_map *(*fn)(__isl_take isl_union_map *umap,3839		__isl_take isl_pw_multi_aff *pma);3840};3841 3842/* Call data->fn to compute the preimage of the domain or range of data->umap3843 * under the function represented by pma and add the result to data->res.3844 */3845static isl_stat preimage_upma(__isl_take isl_pw_multi_aff *pma, void *user)3846{3847	struct isl_union_map_preimage_upma_data *data = user;3848	isl_union_map *umap;3849 3850	umap = isl_union_map_copy(data->umap);3851	umap = data->fn(umap, pma);3852	data->res = isl_union_map_union(data->res, umap);3853 3854	return data->res ? isl_stat_ok : isl_stat_error;3855}3856 3857/* Compute the preimage of the domain or range of "umap" under the function3858 * represented by "upma".3859 * In other words, plug in "upma" in the domain or range of "umap".3860 * The function "fn" performs the actual preimage computation3861 * on a piecewise multi-affine function.3862 */3863static __isl_give isl_union_map *preimage_union_pw_multi_aff(3864	__isl_take isl_union_map *umap,3865	__isl_take isl_union_pw_multi_aff *upma,3866	__isl_give isl_union_map *(*fn)(__isl_take isl_union_map *umap,3867		__isl_take isl_pw_multi_aff *pma))3868{3869	struct isl_union_map_preimage_upma_data data;3870 3871	data.umap = umap;3872	data.res = isl_union_map_empty(isl_union_map_get_space(umap));3873	data.fn = fn;3874	if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,3875						    &preimage_upma, &data) < 0)3876		data.res = isl_union_map_free(data.res);3877 3878	isl_union_map_free(umap);3879	isl_union_pw_multi_aff_free(upma);3880 3881	return data.res;3882}3883 3884/* Compute the preimage of the domain of "umap" under the function3885 * represented by "upma".3886 * In other words, plug in "upma" in the domain of "umap".3887 * The result contains maps that live in the same spaces as the maps of "umap"3888 * with domain space equal to one of the target spaces of "upma",3889 * except that the domain has been replaced by one of the domain spaces that3890 * correspond to that target space of "upma".3891 */3892__isl_give isl_union_map *isl_union_map_preimage_domain_union_pw_multi_aff(3893	__isl_take isl_union_map *umap,3894	__isl_take isl_union_pw_multi_aff *upma)3895{3896	return preimage_union_pw_multi_aff(umap, upma,3897				&isl_union_map_preimage_domain_pw_multi_aff);3898}3899 3900/* Compute the preimage of the range of "umap" under the function3901 * represented by "upma".3902 * In other words, plug in "upma" in the range of "umap".3903 * The result contains maps that live in the same spaces as the maps of "umap"3904 * with range space equal to one of the target spaces of "upma",3905 * except that the range has been replaced by one of the domain spaces that3906 * correspond to that target space of "upma".3907 */3908__isl_give isl_union_map *isl_union_map_preimage_range_union_pw_multi_aff(3909	__isl_take isl_union_map *umap,3910	__isl_take isl_union_pw_multi_aff *upma)3911{3912	return preimage_union_pw_multi_aff(umap, upma,3913				&isl_union_map_preimage_range_pw_multi_aff);3914}3915 3916/* Compute the preimage of "uset" under the function represented by "upma".3917 * In other words, plug in "upma" in the range of "uset".3918 * The result contains sets that live in the same spaces as the sets of "uset"3919 * with space equal to one of the target spaces of "upma",3920 * except that the space has been replaced by one of the domain spaces that3921 * correspond to that target space of "upma".3922 */3923__isl_give isl_union_set *isl_union_set_preimage_union_pw_multi_aff(3924	__isl_take isl_union_set *uset,3925	__isl_take isl_union_pw_multi_aff *upma)3926{3927	return preimage_union_pw_multi_aff(uset, upma,3928					&isl_union_set_preimage_pw_multi_aff);3929}3930 3931/* Reset the user pointer on all identifiers of parameters and tuples3932 * of the spaces of "umap".3933 */3934__isl_give isl_union_map *isl_union_map_reset_user(3935	__isl_take isl_union_map *umap)3936{3937	umap = isl_union_map_cow(umap);3938	if (!umap)3939		return NULL;3940	umap->dim = isl_space_reset_user(umap->dim);3941	if (!umap->dim)3942		return isl_union_map_free(umap);3943	return total(umap, &isl_map_reset_user);3944}3945 3946/* Reset the user pointer on all identifiers of parameters and tuples3947 * of the spaces of "uset".3948 */3949__isl_give isl_union_set *isl_union_set_reset_user(3950	__isl_take isl_union_set *uset)3951{3952	return isl_union_map_reset_user(uset);3953}3954 3955/* Remove all existentially quantified variables and integer divisions3956 * from "umap" using Fourier-Motzkin elimination.3957 */3958__isl_give isl_union_map *isl_union_map_remove_divs(3959	__isl_take isl_union_map *umap)3960{3961	return total(umap, &isl_map_remove_divs);3962}3963 3964/* Remove all existentially quantified variables and integer divisions3965 * from "uset" using Fourier-Motzkin elimination.3966 */3967__isl_give isl_union_set *isl_union_set_remove_divs(3968	__isl_take isl_union_set *uset)3969{3970	return isl_union_map_remove_divs(uset);3971}3972 3973/* Internal data structure for isl_union_map_project_out.3974 * "type", "first" and "n" are the arguments for the isl_map_project_out3975 * call.3976 * "res" collects the results.3977 */3978struct isl_union_map_project_out_data {3979	enum isl_dim_type type;3980	unsigned first;3981	unsigned n;3982 3983	isl_union_map *res;3984};3985 3986/* Turn the data->n dimensions of type data->type, starting at data->first3987 * into existentially quantified variables and add the result to data->res.3988 */3989static isl_stat project_out(__isl_take isl_map *map, void *user)3990{3991	struct isl_union_map_project_out_data *data = user;3992 3993	map = isl_map_project_out(map, data->type, data->first, data->n);3994	data->res = isl_union_map_add_map(data->res, map);3995 3996	return isl_stat_ok;3997}3998 3999/* Turn the "n" dimensions of type "type", starting at "first"4000 * into existentially quantified variables.4001 * Since the space of an isl_union_map only contains parameters,4002 * type is required to be equal to isl_dim_param.4003 */4004__isl_give isl_union_map *isl_union_map_project_out(4005	__isl_take isl_union_map *umap,4006	enum isl_dim_type type, unsigned first, unsigned n)4007{4008	isl_space *space;4009	struct isl_union_map_project_out_data data = { type, first, n };4010 4011	if (!umap)4012		return NULL;4013 4014	if (type != isl_dim_param)4015		isl_die(isl_union_map_get_ctx(umap), isl_error_invalid,4016			"can only project out parameters",4017			return isl_union_map_free(umap));4018 4019	space = isl_union_map_get_space(umap);4020	space = isl_space_drop_dims(space, type, first, n);4021	data.res = isl_union_map_empty(space);4022	if (isl_union_map_foreach_map(umap, &project_out, &data) < 0)4023		data.res = isl_union_map_free(data.res);4024 4025	isl_union_map_free(umap);4026 4027	return data.res;4028}4029 4030#undef TYPE4031#define TYPE	isl_union_map4032#include "isl_project_out_all_params_templ.c"4033#include "isl_project_out_param_templ.c"4034 4035/* Turn the "n" dimensions of type "type", starting at "first"4036 * into existentially quantified variables.4037 * Since the space of an isl_union_set only contains parameters,4038 * "type" is required to be equal to isl_dim_param.4039 */4040__isl_give isl_union_set *isl_union_set_project_out(4041	__isl_take isl_union_set *uset,4042	enum isl_dim_type type, unsigned first, unsigned n)4043{4044	return isl_union_map_project_out(uset, type, first, n);4045}4046 4047/* Project out all parameters from "uset" by existentially quantifying4048 * over them.4049 */4050__isl_give isl_union_set *isl_union_set_project_out_all_params(4051	__isl_take isl_union_set *uset)4052{4053	return uset_from_umap(4054		    isl_union_map_project_out_all_params(uset_to_umap(uset)));4055}4056 4057/* Internal data structure for isl_union_map_involves_dims.4058 * "first" and "n" are the arguments for the isl_map_involves_dims calls.4059 */4060struct isl_union_map_involves_dims_data {4061	unsigned first;4062	unsigned n;4063};4064 4065/* Does "map" _not_ involve the data->n parameters starting at data->first?4066 */4067static isl_bool map_excludes(__isl_keep isl_map *map, void *user)4068{4069	struct isl_union_map_involves_dims_data *data = user;4070	isl_bool involves;4071 4072	involves = isl_map_involves_dims(map,4073					isl_dim_param, data->first, data->n);4074	return isl_bool_not(involves);4075}4076 4077/* Does "umap" involve any of the n parameters starting at first?4078 * "type" is required to be set to isl_dim_param.4079 *4080 * "umap" involves any of those parameters if any of its maps4081 * involve the parameters.  In other words, "umap" does not4082 * involve any of the parameters if all its maps to not4083 * involve the parameters.4084 */4085isl_bool isl_union_map_involves_dims(__isl_keep isl_union_map *umap,4086	enum isl_dim_type type, unsigned first, unsigned n)4087{4088	struct isl_union_map_involves_dims_data data = { first, n };4089	isl_bool excludes;4090 4091	if (type != isl_dim_param)4092		isl_die(isl_union_map_get_ctx(umap), isl_error_invalid,4093			"can only reference parameters", return isl_bool_error);4094 4095	excludes = union_map_forall_user(umap, &map_excludes, &data);4096 4097	return isl_bool_not(excludes);4098}4099 4100/* Internal data structure for isl_union_map_reset_range_space.4101 * "range" is the space from which to set the range space.4102 * "res" collects the results.4103 */4104struct isl_union_map_reset_range_space_data {4105	isl_space *range;4106	isl_union_map *res;4107};4108 4109/* Replace the range space of "map" by the range space of data->range and4110 * add the result to data->res.4111 */4112static isl_stat reset_range_space(__isl_take isl_map *map, void *user)4113{4114	struct isl_union_map_reset_range_space_data *data = user;4115	isl_space *space;4116 4117	space = isl_map_get_space(map);4118	space = isl_space_domain(space);4119	space = isl_space_extend_domain_with_range(space,4120						isl_space_copy(data->range));4121	map = isl_map_reset_space(map, space);4122	data->res = isl_union_map_add_map(data->res, map);4123 4124	return data->res ? isl_stat_ok : isl_stat_error;4125}4126 4127/* Replace the range space of all the maps in "umap" by4128 * the range space of "space".4129 *4130 * This assumes that all maps have the same output dimension.4131 * This function should therefore not be made publicly available.4132 *4133 * Since the spaces of the maps change, so do their hash value.4134 * We therefore need to create a new isl_union_map.4135 */4136__isl_give isl_union_map *isl_union_map_reset_range_space(4137	__isl_take isl_union_map *umap, __isl_take isl_space *space)4138{4139	struct isl_union_map_reset_range_space_data data = { space };4140 4141	data.res = isl_union_map_empty(isl_union_map_get_space(umap));4142	if (isl_union_map_foreach_map(umap, &reset_range_space, &data) < 0)4143		data.res = isl_union_map_free(data.res);4144 4145	isl_space_free(space);4146	isl_union_map_free(umap);4147	return data.res;4148}4149 4150/* Check that "umap" and "space" have the same number of parameters.4151 */4152static isl_stat check_union_map_space_equal_dim(__isl_keep isl_union_map *umap,4153	__isl_keep isl_space *space)4154{4155	isl_size dim1, dim2;4156 4157	dim1 = isl_union_map_dim(umap, isl_dim_param);4158	dim2 = isl_space_dim(space, isl_dim_param);4159	if (dim1 < 0 || dim2 < 0)4160		return isl_stat_error;4161	if (dim1 == dim2)4162		return isl_stat_ok;4163	isl_die(isl_union_map_get_ctx(umap), isl_error_invalid,4164		"number of parameters does not match", return isl_stat_error);4165}4166 4167/* Internal data structure for isl_union_map_reset_equal_dim_space.4168 * "space" is the target space.4169 * "res" collects the results.4170 */4171struct isl_union_map_reset_params_data {4172	isl_space *space;4173	isl_union_map *res;4174};4175 4176/* Replace the parameters of "map" by those of data->space and4177 * add the result to data->res.4178 */4179static isl_stat reset_params(__isl_take isl_map *map, void *user)4180{4181	struct isl_union_map_reset_params_data *data = user;4182	isl_space *space;4183 4184	space = isl_map_get_space(map);4185	space = isl_space_replace_params(space, data->space);4186	map = isl_map_reset_equal_dim_space(map, space);4187	data->res = isl_union_map_add_map(data->res, map);4188 4189	return data->res ? isl_stat_ok : isl_stat_error;4190}4191 4192/* Replace the space of "umap" by "space", without modifying4193 * the dimension of "umap", i.e., the number of parameters of "umap".4194 *4195 * Since the hash values of the maps in the union map depend4196 * on the parameters, a new union map needs to be constructed.4197 */4198__isl_give isl_union_map *isl_union_map_reset_equal_dim_space(4199	__isl_take isl_union_map *umap, __isl_take isl_space *space)4200{4201	struct isl_union_map_reset_params_data data = { space };4202	isl_bool equal;4203	isl_space *umap_space;4204 4205	umap_space = isl_union_map_peek_space(umap);4206	equal = isl_space_is_equal(umap_space, space);4207	if (equal < 0)4208		goto error;4209	if (equal) {4210		isl_space_free(space);4211		return umap;4212	}4213	if (check_union_map_space_equal_dim(umap, space) < 0)4214		goto error;4215 4216	data.res = isl_union_map_empty(isl_space_copy(space));4217	if (isl_union_map_foreach_map(umap, &reset_params, &data) < 0)4218		data.res = isl_union_map_free(data.res);4219 4220	isl_space_free(space);4221	isl_union_map_free(umap);4222	return data.res;4223error:4224	isl_union_map_free(umap);4225	isl_space_free(space);4226	return NULL;4227}4228 4229/* Internal data structure for isl_union_map_order_at_multi_union_pw_aff.4230 * "mupa" is the function from which the isl_multi_pw_affs are extracted.4231 * "order" is applied to the extracted isl_multi_pw_affs that correspond4232 * to the domain and the range of each map.4233 * "res" collects the results.4234 */4235struct isl_union_order_at_data {4236	isl_multi_union_pw_aff *mupa;4237	__isl_give isl_map *(*order)(__isl_take isl_multi_pw_aff *mpa1,4238		__isl_take isl_multi_pw_aff *mpa2);4239	isl_union_map *res;4240};4241 4242/* Intersect "map" with the result of applying data->order to4243 * the functions in data->mupa that apply to the domain and the range4244 * of "map" and add the result to data->res.4245 */4246static isl_stat order_at(__isl_take isl_map *map, void *user)4247{4248	struct isl_union_order_at_data *data = user;4249	isl_space *space;4250	isl_multi_pw_aff *mpa1, *mpa2;4251	isl_map *order;4252 4253	space = isl_space_domain(isl_map_get_space(map));4254	mpa1 = isl_multi_union_pw_aff_extract_multi_pw_aff(data->mupa, space);4255	space = isl_space_range(isl_map_get_space(map));4256	mpa2 = isl_multi_union_pw_aff_extract_multi_pw_aff(data->mupa, space);4257	order = data->order(mpa1, mpa2);4258	map = isl_map_intersect(map, order);4259	data->res = isl_union_map_add_map(data->res, map);4260 4261	return data->res ? isl_stat_ok : isl_stat_error;4262}4263 4264/* If "mupa" has a non-trivial explicit domain, then intersect4265 * domain and range of "umap" with this explicit domain.4266 * If the explicit domain only describes constraints on the parameters,4267 * then the intersection only needs to be performed once.4268 */4269static __isl_give isl_union_map *intersect_explicit_domain(4270	__isl_take isl_union_map *umap, __isl_keep isl_multi_union_pw_aff *mupa)4271{4272	isl_bool non_trivial, is_params;4273	isl_union_set *dom;4274 4275	non_trivial = isl_multi_union_pw_aff_has_non_trivial_domain(mupa);4276	if (non_trivial < 0)4277		return isl_union_map_free(umap);4278	if (!non_trivial)4279		return umap;4280	mupa = isl_multi_union_pw_aff_copy(mupa);4281	dom = isl_multi_union_pw_aff_domain(mupa);4282	is_params = isl_union_set_is_params(dom);4283	if (is_params < 0) {4284		isl_union_set_free(dom);4285		return isl_union_map_free(umap);4286	}4287	if (is_params) {4288		isl_set *set;4289 4290		set = isl_union_set_params(dom);4291		umap = isl_union_map_intersect_params(umap, set);4292		return umap;4293	}4294	umap = isl_union_map_intersect_domain(umap, isl_union_set_copy(dom));4295	umap = isl_union_map_intersect_range(umap, dom);4296	return umap;4297}4298 4299/* Intersect each map in "umap" with the result of calling "order"4300 * on the functions is "mupa" that apply to the domain and the range4301 * of the map.4302 */4303static __isl_give isl_union_map *isl_union_map_order_at_multi_union_pw_aff(4304	__isl_take isl_union_map *umap, __isl_take isl_multi_union_pw_aff *mupa,4305	__isl_give isl_map *(*order)(__isl_take isl_multi_pw_aff *mpa1,4306		__isl_take isl_multi_pw_aff *mpa2))4307{4308	struct isl_union_order_at_data data;4309 4310	umap = isl_union_map_align_params(umap,4311				isl_multi_union_pw_aff_get_space(mupa));4312	mupa = isl_multi_union_pw_aff_align_params(mupa,4313				isl_union_map_get_space(umap));4314	umap = intersect_explicit_domain(umap, mupa);4315	data.mupa = mupa;4316	data.order = order;4317	data.res = isl_union_map_empty(isl_union_map_get_space(umap));4318	if (isl_union_map_foreach_map(umap, &order_at, &data) < 0)4319		data.res = isl_union_map_free(data.res);4320 4321	isl_multi_union_pw_aff_free(mupa);4322	isl_union_map_free(umap);4323	return data.res;4324}4325 4326/* Return the subset of "umap" where the domain and the range4327 * have equal "mupa" values.4328 */4329__isl_give isl_union_map *isl_union_map_eq_at_multi_union_pw_aff(4330	__isl_take isl_union_map *umap,4331	__isl_take isl_multi_union_pw_aff *mupa)4332{4333	return isl_union_map_order_at_multi_union_pw_aff(umap, mupa,4334						&isl_multi_pw_aff_eq_map);4335}4336 4337#undef ORDER4338#define ORDER		le4339#include "isl_union_map_lex_templ.c"4340 4341#undef ORDER4342#define ORDER		lt4343#include "isl_union_map_lex_templ.c"4344 4345#undef ORDER4346#define ORDER		ge4347#include "isl_union_map_lex_templ.c"4348 4349#undef ORDER4350#define ORDER		gt4351#include "isl_union_map_lex_templ.c"4352 4353/* Return the union of the elements in the list "list".4354 */4355__isl_give isl_union_set *isl_union_set_list_union(4356	__isl_take isl_union_set_list *list)4357{4358	int i;4359	isl_size n;4360	isl_ctx *ctx;4361	isl_space *space;4362	isl_union_set *res;4363 4364	n = isl_union_set_list_n_union_set(list);4365	if (n < 0)4366		goto error;4367 4368	ctx = isl_union_set_list_get_ctx(list);4369	space = isl_space_params_alloc(ctx, 0);4370	res = isl_union_set_empty(space);4371 4372	for (i = 0; i < n; ++i) {4373		isl_union_set *uset_i;4374 4375		uset_i = isl_union_set_list_get_union_set(list, i);4376		res = isl_union_set_union(res, uset_i);4377	}4378 4379	isl_union_set_list_free(list);4380	return res;4381error:4382	isl_union_set_list_free(list);4383	return NULL;4384}4385 4386/* Update *hash with the hash value of "map".4387 */4388static isl_stat add_hash(__isl_take isl_map *map, void *user)4389{4390	uint32_t *hash = user;4391	uint32_t map_hash;4392 4393	map_hash = isl_map_get_hash(map);4394	isl_hash_hash(*hash, map_hash);4395 4396	isl_map_free(map);4397	return isl_stat_ok;4398}4399 4400/* Return a hash value that digests "umap".4401 */4402uint32_t isl_union_map_get_hash(__isl_keep isl_union_map *umap)4403{4404	uint32_t hash;4405 4406	if (!umap)4407		return 0;4408 4409	hash = isl_hash_init();4410	if (isl_union_map_foreach_map(umap, &add_hash, &hash) < 0)4411		return 0;4412 4413	return hash;4414}4415 4416/* Return a hash value that digests "uset".4417 */4418uint32_t isl_union_set_get_hash(__isl_keep isl_union_set *uset)4419{4420	return isl_union_map_get_hash(uset);4421}4422 4423/* Add the number of basic sets in "set" to "n".4424 */4425static isl_stat add_n(__isl_take isl_set *set, void *user)4426{4427	int *n = user;4428	isl_size set_n;4429 4430	set_n = isl_set_n_basic_set(set);4431	*n += set_n;4432	isl_set_free(set);4433 4434	return set_n < 0 ? isl_stat_error : isl_stat_ok;4435}4436 4437/* Return the total number of basic sets in "uset".4438 */4439int isl_union_set_n_basic_set(__isl_keep isl_union_set *uset)4440{4441	int n = 0;4442 4443	if (isl_union_set_foreach_set(uset, &add_n, &n) < 0)4444		return -1;4445 4446	return n;4447}4448 4449/* Add the basic sets in "set" to "list".4450 */4451static isl_stat add_list(__isl_take isl_set *set, void *user)4452{4453	isl_basic_set_list **list = user;4454	isl_basic_set_list *list_i;4455 4456	list_i = isl_set_get_basic_set_list(set);4457	*list = isl_basic_set_list_concat(*list, list_i);4458	isl_set_free(set);4459 4460	if (!*list)4461		return isl_stat_error;4462	return isl_stat_ok;4463}4464 4465/* Return a list containing all the basic sets in "uset".4466 *4467 * First construct a list of the appropriate size and4468 * then add all the elements.4469 */4470__isl_give isl_basic_set_list *isl_union_set_get_basic_set_list(4471	__isl_keep isl_union_set *uset)4472{4473	int n;4474	isl_ctx *ctx;4475	isl_basic_set_list *list;4476 4477	if (!uset)4478		return NULL;4479	ctx = isl_union_set_get_ctx(uset);4480	n = isl_union_set_n_basic_set(uset);4481	if (n < 0)4482		return NULL;4483	list = isl_basic_set_list_alloc(ctx, n);4484	if (isl_union_set_foreach_set(uset, &add_list, &list) < 0)4485		list = isl_basic_set_list_free(list);4486 4487	return list;4488}4489 4490/* Internal data structure for isl_union_map_remove_map_if.4491 * "fn" and "user" are the arguments to isl_union_map_remove_map_if.4492 */4493struct isl_union_map_remove_map_if_data {4494	isl_bool (*fn)(__isl_keep isl_map *map, void *user);4495	void *user;4496};4497 4498/* isl_un_op_control filter that negates the result of data->fn4499 * called on "map".4500 */4501static isl_bool not(__isl_keep isl_map *map, void *user)4502{4503	struct isl_union_map_remove_map_if_data *data = user;4504 4505	return isl_bool_not(data->fn(map, data->user));4506}4507 4508/* Dummy isl_un_op_control transformation callback that4509 * simply returns the input.4510 */4511static __isl_give isl_map *map_id(__isl_take isl_map *map)4512{4513	return map;4514}4515 4516/* Call "fn" on every map in "umap" and remove those maps4517 * for which the callback returns true.4518 *4519 * Use un_op to keep only those maps that are not filtered out,4520 * applying an identity transformation on them.4521 */4522__isl_give isl_union_map *isl_union_map_remove_map_if(4523	__isl_take isl_union_map *umap,4524	isl_bool (*fn)(__isl_keep isl_map *map, void *user), void *user)4525{4526	struct isl_union_map_remove_map_if_data data = { fn, user };4527	struct isl_un_op_control control = {4528		.filter = &not,4529		.filter_user = &data,4530		.fn_map = &map_id,4531	};4532	return un_op(umap, &control);4533}4534 4535/* Does "map" have "space" as domain (ignoring parameters)?4536 */4537static isl_bool has_domain_space_tuples(__isl_keep isl_map *map, void *user)4538{4539	isl_space *space = user;4540 4541	return isl_space_has_domain_tuples(space, isl_map_peek_space(map));4542}4543 4544/* Does "map" have "space" as range (ignoring parameters)?4545 */4546static isl_bool has_range_space_tuples(__isl_keep isl_map *map, void *user)4547{4548	isl_space *space = user;4549 4550	return isl_space_has_range_tuples(space, isl_map_peek_space(map));4551}4552 4553/* Wrapper around isl_map_bind_range for use as a un_op callback.4554 */4555static __isl_give isl_map *bind_range(__isl_take isl_map *map, void *user)4556{4557	isl_multi_id *tuple = user;4558 4559	return isl_map_bind_range(map, isl_multi_id_copy(tuple));4560}4561 4562/* Bind the output dimensions of "umap" to parameters with identifiers4563 * specified by "tuple", living in the range space of "umap",4564 * for those maps that have a matching range space.4565 */4566__isl_give isl_union_set *isl_union_map_bind_range(4567	__isl_take isl_union_map *umap, __isl_take isl_multi_id *tuple)4568{4569	struct isl_un_op_control control = {4570		.filter = &has_range_space_tuples,4571		.filter_user = isl_multi_id_peek_space(tuple),4572		.fn_map2 = &bind_range,4573		.fn_map2_user = tuple,4574	};4575	isl_union_set *bound;4576 4577	bound = uset_from_umap(un_op(umap, &control));4578	isl_multi_id_free(tuple);4579	return bound;4580}4581 4582/* Only keep those elements in "umap" that have a domain in "space".4583 */4584__isl_give isl_union_map *isl_union_map_intersect_domain_space(4585	__isl_take isl_union_map *umap, __isl_take isl_space *space)4586{4587	struct isl_un_op_control control = {4588		.filter = &has_domain_space_tuples,4589		.filter_user = space,4590	};4591 4592	umap = un_op(umap, &control);4593	isl_space_free(space);4594	return umap;4595}4596 4597/* Only keep those elements in "umap" that have a range in "space".4598 */4599__isl_give isl_union_map *isl_union_map_intersect_range_space(4600	__isl_take isl_union_map *umap, __isl_take isl_space *space)4601{4602	struct isl_un_op_control control = {4603		.filter = &has_range_space_tuples,4604		.filter_user = space,4605	};4606 4607	umap = un_op(umap, &control);4608	isl_space_free(space);4609	return umap;4610}4611