10027 lines · c
1/*2 * Copyright 2011 INRIA Saclay3 * Copyright 2011 Sven Verdoolaege4 * Copyright 2012-2014 Ecole Normale Superieure5 * Copyright 2014 INRIA Rocquencourt6 * Copyright 2016 Sven Verdoolaege7 * Copyright 2018,2020 Cerebras Systems8 * Copyright 2021 Sven Verdoolaege9 * Copyright 2022 Cerebras Systems10 *11 * Use of this software is governed by the MIT license12 *13 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,14 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,15 * 91893 Orsay, France16 * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France17 * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt,18 * B.P. 105 - 78153 Le Chesnay, France19 * and Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA20 * and Cerebras Systems, 1237 E Arques Ave, Sunnyvale, CA, USA21 */22 23#include <isl_ctx_private.h>24#include <isl_map_private.h>25#include <isl_union_map_private.h>26#include <isl_aff_private.h>27#include <isl_space_private.h>28#include <isl_local_space_private.h>29#include <isl_vec_private.h>30#include <isl_mat_private.h>31#include <isl_id_private.h>32#include <isl/constraint.h>33#include <isl_seq.h>34#include <isl/set.h>35#include <isl_val_private.h>36#include <isl_point_private.h>37#include <isl_config.h>38 39#undef EL_BASE40#define EL_BASE aff41 42#include <isl_list_templ.c>43#include <isl_list_read_templ.c>44 45#undef EL_BASE46#define EL_BASE pw_aff47 48#include <isl_list_templ.c>49#include <isl_list_read_templ.c>50 51#undef EL_BASE52#define EL_BASE pw_multi_aff53 54#include <isl_list_templ.c>55#include <isl_list_read_templ.c>56 57#undef EL_BASE58#define EL_BASE union_pw_aff59 60#include <isl_list_templ.c>61#include <isl_list_read_templ.c>62 63#undef EL_BASE64#define EL_BASE union_pw_multi_aff65 66#include <isl_list_templ.c>67 68/* Construct an isl_aff from the given domain local space "ls" and69 * coefficients "v", where the local space is known to be valid70 * for an affine expression.71 */72static __isl_give isl_aff *isl_aff_alloc_vec_validated(73 __isl_take isl_local_space *ls, __isl_take isl_vec *v)74{75 isl_aff *aff;76 77 if (!ls || !v)78 goto error;79 80 aff = isl_calloc_type(v->ctx, struct isl_aff);81 if (!aff)82 goto error;83 84 aff->ref = 1;85 aff->ls = ls;86 aff->v = v;87 88 return aff;89error:90 isl_local_space_free(ls);91 isl_vec_free(v);92 return NULL;93}94 95/* Construct an isl_aff from the given domain local space "ls" and96 * coefficients "v".97 *98 * First check that "ls" is a valid domain local space99 * for an affine expression.100 */101__isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls,102 __isl_take isl_vec *v)103{104 isl_ctx *ctx;105 106 if (!ls)107 return NULL;108 109 ctx = isl_local_space_get_ctx(ls);110 if (!isl_local_space_divs_known(ls))111 isl_die(ctx, isl_error_invalid, "local space has unknown divs",112 goto error);113 if (!isl_local_space_is_set(ls))114 isl_die(ctx, isl_error_invalid,115 "domain of affine expression should be a set",116 goto error);117 return isl_aff_alloc_vec_validated(ls, v);118error:119 isl_local_space_free(ls);120 isl_vec_free(v);121 return NULL;122}123 124__isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls)125{126 isl_ctx *ctx;127 isl_vec *v;128 isl_size total;129 130 if (!ls)131 return NULL;132 133 ctx = isl_local_space_get_ctx(ls);134 135 total = isl_local_space_dim(ls, isl_dim_all);136 if (total < 0)137 goto error;138 v = isl_vec_alloc(ctx, 1 + 1 + total);139 return isl_aff_alloc_vec(ls, v);140error:141 isl_local_space_free(ls);142 return NULL;143}144 145__isl_give isl_aff *isl_aff_copy(__isl_keep isl_aff *aff)146{147 if (!aff)148 return NULL;149 150 aff->ref++;151 return aff;152}153 154__isl_give isl_aff *isl_aff_dup(__isl_keep isl_aff *aff)155{156 if (!aff)157 return NULL;158 159 return isl_aff_alloc_vec_validated(isl_local_space_copy(aff->ls),160 isl_vec_copy(aff->v));161}162 163__isl_give isl_aff *isl_aff_cow(__isl_take isl_aff *aff)164{165 if (!aff)166 return NULL;167 168 if (aff->ref == 1)169 return aff;170 aff->ref--;171 return isl_aff_dup(aff);172}173 174__isl_give isl_aff *isl_aff_zero_on_domain(__isl_take isl_local_space *ls)175{176 isl_aff *aff;177 178 aff = isl_aff_alloc(ls);179 if (!aff)180 return NULL;181 182 isl_int_set_si(aff->v->el[0], 1);183 isl_seq_clr(aff->v->el + 1, aff->v->size - 1);184 185 return aff;186}187 188/* Return an affine expression that is equal to zero on domain space "space".189 */190__isl_give isl_aff *isl_aff_zero_on_domain_space(__isl_take isl_space *space)191{192 return isl_aff_zero_on_domain(isl_local_space_from_space(space));193}194 195/* This function performs the same operation as isl_aff_zero_on_domain_space,196 * but is considered as a function on an isl_space when exported.197 */198__isl_give isl_aff *isl_space_zero_aff_on_domain(__isl_take isl_space *space)199{200 return isl_aff_zero_on_domain_space(space);201}202 203/* Return a piecewise affine expression defined on the specified domain204 * that is equal to zero.205 */206__isl_give isl_pw_aff *isl_pw_aff_zero_on_domain(__isl_take isl_local_space *ls)207{208 return isl_pw_aff_from_aff(isl_aff_zero_on_domain(ls));209}210 211/* Change "aff" into a NaN.212 *213 * Note that this function gets called from isl_aff_nan_on_domain,214 * so "aff" may not have been initialized yet.215 */216static __isl_give isl_aff *isl_aff_set_nan(__isl_take isl_aff *aff)217{218 aff = isl_aff_cow(aff);219 if (!aff)220 return NULL;221 222 aff->v = isl_vec_clr(aff->v);223 if (!aff->v)224 return isl_aff_free(aff);225 226 return aff;227}228 229/* Return an affine expression defined on the specified domain230 * that represents NaN.231 */232__isl_give isl_aff *isl_aff_nan_on_domain(__isl_take isl_local_space *ls)233{234 isl_aff *aff;235 236 aff = isl_aff_alloc(ls);237 return isl_aff_set_nan(aff);238}239 240/* Return an affine expression defined on the specified domain space241 * that represents NaN.242 */243__isl_give isl_aff *isl_aff_nan_on_domain_space(__isl_take isl_space *space)244{245 return isl_aff_nan_on_domain(isl_local_space_from_space(space));246}247 248/* Return a piecewise affine expression defined on the specified domain space249 * that represents NaN.250 */251__isl_give isl_pw_aff *isl_pw_aff_nan_on_domain_space(252 __isl_take isl_space *space)253{254 return isl_pw_aff_from_aff(isl_aff_nan_on_domain_space(space));255}256 257/* Return a piecewise affine expression defined on the specified domain258 * that represents NaN.259 */260__isl_give isl_pw_aff *isl_pw_aff_nan_on_domain(__isl_take isl_local_space *ls)261{262 return isl_pw_aff_from_aff(isl_aff_nan_on_domain(ls));263}264 265/* Return an affine expression that is equal to "val" on266 * domain local space "ls".267 *268 * Note that the encoding for the special value NaN269 * is the same in isl_val and isl_aff, so this does not need270 * to be treated in any special way.271 */272__isl_give isl_aff *isl_aff_val_on_domain(__isl_take isl_local_space *ls,273 __isl_take isl_val *val)274{275 isl_aff *aff;276 277 if (!ls || !val)278 goto error;279 if (!isl_val_is_rat(val) && !isl_val_is_nan(val))280 isl_die(isl_val_get_ctx(val), isl_error_invalid,281 "expecting rational value or NaN", goto error);282 283 aff = isl_aff_alloc(isl_local_space_copy(ls));284 if (!aff)285 goto error;286 287 isl_seq_clr(aff->v->el + 2, aff->v->size - 2);288 isl_int_set(aff->v->el[1], val->n);289 isl_int_set(aff->v->el[0], val->d);290 291 isl_local_space_free(ls);292 isl_val_free(val);293 return aff;294error:295 isl_local_space_free(ls);296 isl_val_free(val);297 return NULL;298}299 300/* Return an affine expression that is equal to "val" on domain space "space".301 */302__isl_give isl_aff *isl_aff_val_on_domain_space(__isl_take isl_space *space,303 __isl_take isl_val *val)304{305 return isl_aff_val_on_domain(isl_local_space_from_space(space), val);306}307 308/* Return an affine expression that is equal to the specified dimension309 * in "ls".310 */311__isl_give isl_aff *isl_aff_var_on_domain(__isl_take isl_local_space *ls,312 enum isl_dim_type type, unsigned pos)313{314 isl_space *space;315 isl_aff *aff;316 317 if (!ls)318 return NULL;319 320 space = isl_local_space_get_space(ls);321 if (!space)322 goto error;323 if (isl_space_is_map(space))324 isl_die(isl_space_get_ctx(space), isl_error_invalid,325 "expecting (parameter) set space", goto error);326 if (isl_local_space_check_range(ls, type, pos, 1) < 0)327 goto error;328 329 isl_space_free(space);330 aff = isl_aff_alloc(ls);331 if (!aff)332 return NULL;333 334 pos += isl_local_space_offset(aff->ls, type);335 336 isl_int_set_si(aff->v->el[0], 1);337 isl_seq_clr(aff->v->el + 1, aff->v->size - 1);338 isl_int_set_si(aff->v->el[1 + pos], 1);339 340 return aff;341error:342 isl_local_space_free(ls);343 isl_space_free(space);344 return NULL;345}346 347/* Return a piecewise affine expression that is equal to348 * the specified dimension in "ls".349 */350__isl_give isl_pw_aff *isl_pw_aff_var_on_domain(__isl_take isl_local_space *ls,351 enum isl_dim_type type, unsigned pos)352{353 return isl_pw_aff_from_aff(isl_aff_var_on_domain(ls, type, pos));354}355 356/* Return an affine expression that is equal to the parameter357 * in the domain space "space" with identifier "id".358 */359__isl_give isl_aff *isl_aff_param_on_domain_space_id(360 __isl_take isl_space *space, __isl_take isl_id *id)361{362 int pos;363 isl_local_space *ls;364 365 if (!space || !id)366 goto error;367 pos = isl_space_find_dim_by_id(space, isl_dim_param, id);368 if (pos < 0)369 isl_die(isl_space_get_ctx(space), isl_error_invalid,370 "parameter not found in space", goto error);371 isl_id_free(id);372 ls = isl_local_space_from_space(space);373 return isl_aff_var_on_domain(ls, isl_dim_param, pos);374error:375 isl_space_free(space);376 isl_id_free(id);377 return NULL;378}379 380/* This function performs the same operation as381 * isl_aff_param_on_domain_space_id,382 * but is considered as a function on an isl_space when exported.383 */384__isl_give isl_aff *isl_space_param_aff_on_domain_id(385 __isl_take isl_space *space, __isl_take isl_id *id)386{387 return isl_aff_param_on_domain_space_id(space, id);388}389 390__isl_null isl_aff *isl_aff_free(__isl_take isl_aff *aff)391{392 if (!aff)393 return NULL;394 395 if (--aff->ref > 0)396 return NULL;397 398 isl_local_space_free(aff->ls);399 isl_vec_free(aff->v);400 401 free(aff);402 403 return NULL;404}405 406isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff)407{408 return aff ? isl_local_space_get_ctx(aff->ls) : NULL;409}410 411/* Return a hash value that digests "aff".412 */413uint32_t isl_aff_get_hash(__isl_keep isl_aff *aff)414{415 uint32_t hash, ls_hash, v_hash;416 417 if (!aff)418 return 0;419 420 hash = isl_hash_init();421 ls_hash = isl_local_space_get_hash(aff->ls);422 isl_hash_hash(hash, ls_hash);423 v_hash = isl_vec_get_hash(aff->v);424 isl_hash_hash(hash, v_hash);425 426 return hash;427}428 429/* Return the domain local space of "aff".430 */431static __isl_keep isl_local_space *isl_aff_peek_domain_local_space(432 __isl_keep isl_aff *aff)433{434 return aff ? aff->ls : NULL;435}436 437/* Return the number of variables of the given type in the domain of "aff".438 */439isl_size isl_aff_domain_dim(__isl_keep isl_aff *aff, enum isl_dim_type type)440{441 isl_local_space *ls;442 443 ls = isl_aff_peek_domain_local_space(aff);444 return isl_local_space_dim(ls, type);445}446 447/* Externally, an isl_aff has a map space, but internally, the448 * ls field corresponds to the domain of that space.449 */450isl_size isl_aff_dim(__isl_keep isl_aff *aff, enum isl_dim_type type)451{452 if (!aff)453 return isl_size_error;454 if (type == isl_dim_out)455 return 1;456 if (type == isl_dim_in)457 type = isl_dim_set;458 return isl_aff_domain_dim(aff, type);459}460 461/* Return the offset of the first coefficient of type "type" in462 * the domain of "aff".463 */464isl_size isl_aff_domain_offset(__isl_keep isl_aff *aff, enum isl_dim_type type)465{466 isl_local_space *ls;467 468 ls = isl_aff_peek_domain_local_space(aff);469 return isl_local_space_offset(ls, type);470}471 472/* Return the position of the dimension of the given type and name473 * in "aff".474 * Return -1 if no such dimension can be found.475 */476int isl_aff_find_dim_by_name(__isl_keep isl_aff *aff, enum isl_dim_type type,477 const char *name)478{479 if (!aff)480 return -1;481 if (type == isl_dim_out)482 return -1;483 if (type == isl_dim_in)484 type = isl_dim_set;485 return isl_local_space_find_dim_by_name(aff->ls, type, name);486}487 488/* Return the domain space of "aff".489 */490static __isl_keep isl_space *isl_aff_peek_domain_space(__isl_keep isl_aff *aff)491{492 return aff ? isl_local_space_peek_space(aff->ls) : NULL;493}494 495__isl_give isl_space *isl_aff_get_domain_space(__isl_keep isl_aff *aff)496{497 return isl_space_copy(isl_aff_peek_domain_space(aff));498}499 500__isl_give isl_space *isl_aff_get_space(__isl_keep isl_aff *aff)501{502 isl_space *space;503 if (!aff)504 return NULL;505 space = isl_local_space_get_space(aff->ls);506 space = isl_space_from_domain(space);507 space = isl_space_add_dims(space, isl_dim_out, 1);508 return space;509}510 511/* Return a copy of the domain space of "aff".512 */513__isl_give isl_local_space *isl_aff_get_domain_local_space(514 __isl_keep isl_aff *aff)515{516 return isl_local_space_copy(isl_aff_peek_domain_local_space(aff));517}518 519__isl_give isl_local_space *isl_aff_get_local_space(__isl_keep isl_aff *aff)520{521 isl_local_space *ls;522 if (!aff)523 return NULL;524 ls = isl_local_space_copy(aff->ls);525 ls = isl_local_space_from_domain(ls);526 ls = isl_local_space_add_dims(ls, isl_dim_out, 1);527 return ls;528}529 530/* Return the local space of the domain of "aff".531 * This may be either a copy or the local space itself532 * if there is only one reference to "aff".533 * This allows the local space to be modified inplace534 * if both the expression and its local space have only a single reference.535 * The caller is not allowed to modify "aff" between this call and536 * a subsequent call to isl_aff_restore_domain_local_space.537 * The only exception is that isl_aff_free can be called instead.538 */539__isl_give isl_local_space *isl_aff_take_domain_local_space(540 __isl_keep isl_aff *aff)541{542 isl_local_space *ls;543 544 if (!aff)545 return NULL;546 if (aff->ref != 1)547 return isl_aff_get_domain_local_space(aff);548 ls = aff->ls;549 aff->ls = NULL;550 return ls;551}552 553/* Set the local space of the domain of "aff" to "ls",554 * where the local space of "aff" may be missing555 * due to a preceding call to isl_aff_take_domain_local_space.556 * However, in this case, "aff" only has a single reference and557 * then the call to isl_aff_cow has no effect.558 */559__isl_give isl_aff *isl_aff_restore_domain_local_space(560 __isl_keep isl_aff *aff, __isl_take isl_local_space *ls)561{562 if (!aff || !ls)563 goto error;564 565 if (aff->ls == ls) {566 isl_local_space_free(ls);567 return aff;568 }569 570 aff = isl_aff_cow(aff);571 if (!aff)572 goto error;573 isl_local_space_free(aff->ls);574 aff->ls = ls;575 576 return aff;577error:578 isl_aff_free(aff);579 isl_local_space_free(ls);580 return NULL;581}582 583/* Externally, an isl_aff has a map space, but internally, the584 * ls field corresponds to the domain of that space.585 */586const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff,587 enum isl_dim_type type, unsigned pos)588{589 if (!aff)590 return NULL;591 if (type == isl_dim_out)592 return NULL;593 if (type == isl_dim_in)594 type = isl_dim_set;595 return isl_local_space_get_dim_name(aff->ls, type, pos);596}597 598__isl_give isl_aff *isl_aff_reset_domain_space(__isl_take isl_aff *aff,599 __isl_take isl_space *space)600{601 aff = isl_aff_cow(aff);602 if (!aff || !space)603 goto error;604 605 aff->ls = isl_local_space_reset_space(aff->ls, space);606 if (!aff->ls)607 return isl_aff_free(aff);608 609 return aff;610error:611 isl_aff_free(aff);612 isl_space_free(space);613 return NULL;614}615 616/* Reset the space of "aff". This function is called from isl_pw_templ.c617 * and doesn't know if the space of an element object is represented618 * directly or through its domain. It therefore passes along both.619 */620__isl_give isl_aff *isl_aff_reset_space_and_domain(__isl_take isl_aff *aff,621 __isl_take isl_space *space, __isl_take isl_space *domain)622{623 isl_space_free(space);624 return isl_aff_reset_domain_space(aff, domain);625}626 627/* Reorder the dimensions of the domain of "aff" according628 * to the given reordering.629 */630__isl_give isl_aff *isl_aff_realign_domain(__isl_take isl_aff *aff,631 __isl_take isl_reordering *r)632{633 aff = isl_aff_cow(aff);634 if (!aff)635 goto error;636 637 r = isl_reordering_extend(r, aff->ls->div->n_row);638 aff->v = isl_vec_reorder(aff->v, 2, isl_reordering_copy(r));639 aff->ls = isl_local_space_realign(aff->ls, r);640 641 if (!aff->v || !aff->ls)642 return isl_aff_free(aff);643 644 return aff;645error:646 isl_aff_free(aff);647 isl_reordering_free(r);648 return NULL;649}650 651__isl_give isl_aff *isl_aff_align_params(__isl_take isl_aff *aff,652 __isl_take isl_space *model)653{654 isl_space *domain_space;655 isl_bool equal_params;656 657 domain_space = isl_aff_peek_domain_space(aff);658 equal_params = isl_space_has_equal_params(domain_space, model);659 if (equal_params < 0)660 goto error;661 if (!equal_params) {662 isl_reordering *exp;663 664 exp = isl_parameter_alignment_reordering(domain_space, model);665 aff = isl_aff_realign_domain(aff, exp);666 }667 668 isl_space_free(model);669 return aff;670error:671 isl_space_free(model);672 isl_aff_free(aff);673 return NULL;674}675 676#undef TYPE677#define TYPE isl_aff678#include "isl_unbind_params_templ.c"679 680/* Is "aff" obviously equal to zero?681 *682 * If the denominator is zero, then "aff" is not equal to zero.683 */684isl_bool isl_aff_plain_is_zero(__isl_keep isl_aff *aff)685{686 int pos;687 688 if (!aff)689 return isl_bool_error;690 691 if (isl_int_is_zero(aff->v->el[0]))692 return isl_bool_false;693 pos = isl_seq_first_non_zero(aff->v->el + 1, aff->v->size - 1);694 return isl_bool_ok(pos < 0);695}696 697/* Does "aff" represent NaN?698 */699isl_bool isl_aff_is_nan(__isl_keep isl_aff *aff)700{701 if (!aff)702 return isl_bool_error;703 704 return isl_bool_ok(isl_seq_first_non_zero(aff->v->el, 2) < 0);705}706 707/* Are "aff1" and "aff2" obviously equal?708 *709 * NaN is not equal to anything, not even to another NaN.710 */711isl_bool isl_aff_plain_is_equal(__isl_keep isl_aff *aff1,712 __isl_keep isl_aff *aff2)713{714 isl_bool equal;715 716 if (!aff1 || !aff2)717 return isl_bool_error;718 719 if (isl_aff_is_nan(aff1) || isl_aff_is_nan(aff2))720 return isl_bool_false;721 722 equal = isl_local_space_is_equal(aff1->ls, aff2->ls);723 if (equal < 0 || !equal)724 return equal;725 726 return isl_vec_is_equal(aff1->v, aff2->v);727}728 729/* Return the common denominator of "aff" in "v".730 *731 * We cannot return anything meaningful in case of a NaN.732 */733isl_stat isl_aff_get_denominator(__isl_keep isl_aff *aff, isl_int *v)734{735 if (!aff)736 return isl_stat_error;737 if (isl_aff_is_nan(aff))738 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,739 "cannot get denominator of NaN", return isl_stat_error);740 isl_int_set(*v, aff->v->el[0]);741 return isl_stat_ok;742}743 744/* Return the common denominator of "aff".745 */746__isl_give isl_val *isl_aff_get_denominator_val(__isl_keep isl_aff *aff)747{748 isl_ctx *ctx;749 750 if (!aff)751 return NULL;752 753 ctx = isl_aff_get_ctx(aff);754 if (isl_aff_is_nan(aff))755 return isl_val_nan(ctx);756 return isl_val_int_from_isl_int(ctx, aff->v->el[0]);757}758 759/* Return the constant term of "aff".760 */761__isl_give isl_val *isl_aff_get_constant_val(__isl_keep isl_aff *aff)762{763 isl_ctx *ctx;764 isl_val *v;765 766 if (!aff)767 return NULL;768 769 ctx = isl_aff_get_ctx(aff);770 if (isl_aff_is_nan(aff))771 return isl_val_nan(ctx);772 v = isl_val_rat_from_isl_int(ctx, aff->v->el[1], aff->v->el[0]);773 return isl_val_normalize(v);774}775 776/* Return the coefficient of the variable of type "type" at position "pos"777 * of "aff".778 */779__isl_give isl_val *isl_aff_get_coefficient_val(__isl_keep isl_aff *aff,780 enum isl_dim_type type, int pos)781{782 isl_ctx *ctx;783 isl_val *v;784 785 if (!aff)786 return NULL;787 788 ctx = isl_aff_get_ctx(aff);789 if (type == isl_dim_out)790 isl_die(ctx, isl_error_invalid,791 "output/set dimension does not have a coefficient",792 return NULL);793 if (type == isl_dim_in)794 type = isl_dim_set;795 796 if (isl_local_space_check_range(aff->ls, type, pos, 1) < 0)797 return NULL;798 799 if (isl_aff_is_nan(aff))800 return isl_val_nan(ctx);801 pos += isl_local_space_offset(aff->ls, type);802 v = isl_val_rat_from_isl_int(ctx, aff->v->el[1 + pos], aff->v->el[0]);803 return isl_val_normalize(v);804}805 806/* Return the sign of the coefficient of the variable of type "type"807 * at position "pos" of "aff".808 */809int isl_aff_coefficient_sgn(__isl_keep isl_aff *aff, enum isl_dim_type type,810 int pos)811{812 isl_ctx *ctx;813 814 if (!aff)815 return 0;816 817 ctx = isl_aff_get_ctx(aff);818 if (type == isl_dim_out)819 isl_die(ctx, isl_error_invalid,820 "output/set dimension does not have a coefficient",821 return 0);822 if (type == isl_dim_in)823 type = isl_dim_set;824 825 if (isl_local_space_check_range(aff->ls, type, pos, 1) < 0)826 return 0;827 828 pos += isl_local_space_offset(aff->ls, type);829 return isl_int_sgn(aff->v->el[1 + pos]);830}831 832/* Replace the numerator of the constant term of "aff" by "v".833 *834 * A NaN is unaffected by this operation.835 */836__isl_give isl_aff *isl_aff_set_constant(__isl_take isl_aff *aff, isl_int v)837{838 if (!aff)839 return NULL;840 if (isl_aff_is_nan(aff))841 return aff;842 aff = isl_aff_cow(aff);843 if (!aff)844 return NULL;845 846 aff->v = isl_vec_cow(aff->v);847 if (!aff->v)848 return isl_aff_free(aff);849 850 isl_int_set(aff->v->el[1], v);851 852 return aff;853}854 855/* Replace the constant term of "aff" by "v".856 *857 * A NaN is unaffected by this operation.858 */859__isl_give isl_aff *isl_aff_set_constant_val(__isl_take isl_aff *aff,860 __isl_take isl_val *v)861{862 if (!aff || !v)863 goto error;864 865 if (isl_aff_is_nan(aff)) {866 isl_val_free(v);867 return aff;868 }869 870 if (!isl_val_is_rat(v))871 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,872 "expecting rational value", goto error);873 874 if (isl_int_eq(aff->v->el[1], v->n) &&875 isl_int_eq(aff->v->el[0], v->d)) {876 isl_val_free(v);877 return aff;878 }879 880 aff = isl_aff_cow(aff);881 if (!aff)882 goto error;883 aff->v = isl_vec_cow(aff->v);884 if (!aff->v)885 goto error;886 887 if (isl_int_eq(aff->v->el[0], v->d)) {888 isl_int_set(aff->v->el[1], v->n);889 } else if (isl_int_is_one(v->d)) {890 isl_int_mul(aff->v->el[1], aff->v->el[0], v->n);891 } else {892 isl_seq_scale(aff->v->el + 1,893 aff->v->el + 1, v->d, aff->v->size - 1);894 isl_int_mul(aff->v->el[1], aff->v->el[0], v->n);895 isl_int_mul(aff->v->el[0], aff->v->el[0], v->d);896 aff->v = isl_vec_normalize(aff->v);897 if (!aff->v)898 goto error;899 }900 901 isl_val_free(v);902 return aff;903error:904 isl_aff_free(aff);905 isl_val_free(v);906 return NULL;907}908 909/* Add "v" to the constant term of "aff".910 *911 * A NaN is unaffected by this operation.912 */913__isl_give isl_aff *isl_aff_add_constant(__isl_take isl_aff *aff, isl_int v)914{915 if (isl_int_is_zero(v))916 return aff;917 918 if (!aff)919 return NULL;920 if (isl_aff_is_nan(aff))921 return aff;922 aff = isl_aff_cow(aff);923 if (!aff)924 return NULL;925 926 aff->v = isl_vec_cow(aff->v);927 if (!aff->v)928 return isl_aff_free(aff);929 930 isl_int_addmul(aff->v->el[1], aff->v->el[0], v);931 932 return aff;933}934 935/* Add "v" to the constant term of "aff",936 * in case "aff" is a rational expression.937 */938static __isl_give isl_aff *isl_aff_add_rat_constant_val(__isl_take isl_aff *aff,939 __isl_take isl_val *v)940{941 aff = isl_aff_cow(aff);942 if (!aff)943 goto error;944 945 aff->v = isl_vec_cow(aff->v);946 if (!aff->v)947 goto error;948 949 if (isl_int_is_one(v->d)) {950 isl_int_addmul(aff->v->el[1], aff->v->el[0], v->n);951 } else if (isl_int_eq(aff->v->el[0], v->d)) {952 isl_int_add(aff->v->el[1], aff->v->el[1], v->n);953 aff->v = isl_vec_normalize(aff->v);954 if (!aff->v)955 goto error;956 } else {957 isl_seq_scale(aff->v->el + 1,958 aff->v->el + 1, v->d, aff->v->size - 1);959 isl_int_addmul(aff->v->el[1], aff->v->el[0], v->n);960 isl_int_mul(aff->v->el[0], aff->v->el[0], v->d);961 aff->v = isl_vec_normalize(aff->v);962 if (!aff->v)963 goto error;964 }965 966 isl_val_free(v);967 return aff;968error:969 isl_aff_free(aff);970 isl_val_free(v);971 return NULL;972}973 974/* Return the first argument and free the second.975 */976static __isl_give isl_aff *pick_free(__isl_take isl_aff *aff,977 __isl_take isl_val *v)978{979 isl_val_free(v);980 return aff;981}982 983/* Replace the first argument by NaN and free the second argument.984 */985static __isl_give isl_aff *set_nan_free_val(__isl_take isl_aff *aff,986 __isl_take isl_val *v)987{988 isl_val_free(v);989 return isl_aff_set_nan(aff);990}991 992/* Add "v" to the constant term of "aff".993 *994 * A NaN is unaffected by this operation.995 * Conversely, adding a NaN turns "aff" into a NaN.996 */997__isl_give isl_aff *isl_aff_add_constant_val(__isl_take isl_aff *aff,998 __isl_take isl_val *v)999{1000 isl_bool is_nan, is_zero, is_rat;1001 1002 is_nan = isl_aff_is_nan(aff);1003 is_zero = isl_val_is_zero(v);1004 if (is_nan < 0 || is_zero < 0)1005 goto error;1006 if (is_nan || is_zero)1007 return pick_free(aff, v);1008 1009 is_nan = isl_val_is_nan(v);1010 is_rat = isl_val_is_rat(v);1011 if (is_nan < 0 || is_rat < 0)1012 goto error;1013 if (is_nan)1014 return set_nan_free_val(aff, v);1015 if (!is_rat)1016 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,1017 "expecting rational value or NaN", goto error);1018 1019 return isl_aff_add_rat_constant_val(aff, v);1020error:1021 isl_aff_free(aff);1022 isl_val_free(v);1023 return NULL;1024}1025 1026__isl_give isl_aff *isl_aff_add_constant_si(__isl_take isl_aff *aff, int v)1027{1028 isl_int t;1029 1030 isl_int_init(t);1031 isl_int_set_si(t, v);1032 aff = isl_aff_add_constant(aff, t);1033 isl_int_clear(t);1034 1035 return aff;1036}1037 1038/* Add "v" to the numerator of the constant term of "aff".1039 *1040 * A NaN is unaffected by this operation.1041 */1042__isl_give isl_aff *isl_aff_add_constant_num(__isl_take isl_aff *aff, isl_int v)1043{1044 if (isl_int_is_zero(v))1045 return aff;1046 1047 if (!aff)1048 return NULL;1049 if (isl_aff_is_nan(aff))1050 return aff;1051 aff = isl_aff_cow(aff);1052 if (!aff)1053 return NULL;1054 1055 aff->v = isl_vec_cow(aff->v);1056 if (!aff->v)1057 return isl_aff_free(aff);1058 1059 isl_int_add(aff->v->el[1], aff->v->el[1], v);1060 1061 return aff;1062}1063 1064/* Add "v" to the numerator of the constant term of "aff".1065 *1066 * A NaN is unaffected by this operation.1067 */1068__isl_give isl_aff *isl_aff_add_constant_num_si(__isl_take isl_aff *aff, int v)1069{1070 isl_int t;1071 1072 if (v == 0)1073 return aff;1074 1075 isl_int_init(t);1076 isl_int_set_si(t, v);1077 aff = isl_aff_add_constant_num(aff, t);1078 isl_int_clear(t);1079 1080 return aff;1081}1082 1083/* Replace the numerator of the constant term of "aff" by "v".1084 *1085 * A NaN is unaffected by this operation.1086 */1087__isl_give isl_aff *isl_aff_set_constant_si(__isl_take isl_aff *aff, int v)1088{1089 if (!aff)1090 return NULL;1091 if (isl_aff_is_nan(aff))1092 return aff;1093 aff = isl_aff_cow(aff);1094 if (!aff)1095 return NULL;1096 1097 aff->v = isl_vec_cow(aff->v);1098 if (!aff->v)1099 return isl_aff_free(aff);1100 1101 isl_int_set_si(aff->v->el[1], v);1102 1103 return aff;1104}1105 1106/* Replace the numerator of the coefficient of the variable of type "type"1107 * at position "pos" of "aff" by "v".1108 *1109 * A NaN is unaffected by this operation.1110 */1111__isl_give isl_aff *isl_aff_set_coefficient(__isl_take isl_aff *aff,1112 enum isl_dim_type type, int pos, isl_int v)1113{1114 if (!aff)1115 return NULL;1116 1117 if (type == isl_dim_out)1118 isl_die(aff->v->ctx, isl_error_invalid,1119 "output/set dimension does not have a coefficient",1120 return isl_aff_free(aff));1121 if (type == isl_dim_in)1122 type = isl_dim_set;1123 1124 if (isl_local_space_check_range(aff->ls, type, pos, 1) < 0)1125 return isl_aff_free(aff);1126 1127 if (isl_aff_is_nan(aff))1128 return aff;1129 aff = isl_aff_cow(aff);1130 if (!aff)1131 return NULL;1132 1133 aff->v = isl_vec_cow(aff->v);1134 if (!aff->v)1135 return isl_aff_free(aff);1136 1137 pos += isl_local_space_offset(aff->ls, type);1138 isl_int_set(aff->v->el[1 + pos], v);1139 1140 return aff;1141}1142 1143/* Replace the numerator of the coefficient of the variable of type "type"1144 * at position "pos" of "aff" by "v".1145 *1146 * A NaN is unaffected by this operation.1147 */1148__isl_give isl_aff *isl_aff_set_coefficient_si(__isl_take isl_aff *aff,1149 enum isl_dim_type type, int pos, int v)1150{1151 if (!aff)1152 return NULL;1153 1154 if (type == isl_dim_out)1155 isl_die(aff->v->ctx, isl_error_invalid,1156 "output/set dimension does not have a coefficient",1157 return isl_aff_free(aff));1158 if (type == isl_dim_in)1159 type = isl_dim_set;1160 1161 if (isl_local_space_check_range(aff->ls, type, pos, 1) < 0)1162 return isl_aff_free(aff);1163 1164 if (isl_aff_is_nan(aff))1165 return aff;1166 pos += isl_local_space_offset(aff->ls, type);1167 if (isl_int_cmp_si(aff->v->el[1 + pos], v) == 0)1168 return aff;1169 1170 aff = isl_aff_cow(aff);1171 if (!aff)1172 return NULL;1173 1174 aff->v = isl_vec_cow(aff->v);1175 if (!aff->v)1176 return isl_aff_free(aff);1177 1178 isl_int_set_si(aff->v->el[1 + pos], v);1179 1180 return aff;1181}1182 1183/* Replace the coefficient of the variable of type "type" at position "pos"1184 * of "aff" by "v".1185 *1186 * A NaN is unaffected by this operation.1187 */1188__isl_give isl_aff *isl_aff_set_coefficient_val(__isl_take isl_aff *aff,1189 enum isl_dim_type type, int pos, __isl_take isl_val *v)1190{1191 if (!aff || !v)1192 goto error;1193 1194 if (type == isl_dim_out)1195 isl_die(aff->v->ctx, isl_error_invalid,1196 "output/set dimension does not have a coefficient",1197 goto error);1198 if (type == isl_dim_in)1199 type = isl_dim_set;1200 1201 if (isl_local_space_check_range(aff->ls, type, pos, 1) < 0)1202 return isl_aff_free(aff);1203 1204 if (isl_aff_is_nan(aff)) {1205 isl_val_free(v);1206 return aff;1207 }1208 if (!isl_val_is_rat(v))1209 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,1210 "expecting rational value", goto error);1211 1212 pos += isl_local_space_offset(aff->ls, type);1213 if (isl_int_eq(aff->v->el[1 + pos], v->n) &&1214 isl_int_eq(aff->v->el[0], v->d)) {1215 isl_val_free(v);1216 return aff;1217 }1218 1219 aff = isl_aff_cow(aff);1220 if (!aff)1221 goto error;1222 aff->v = isl_vec_cow(aff->v);1223 if (!aff->v)1224 goto error;1225 1226 if (isl_int_eq(aff->v->el[0], v->d)) {1227 isl_int_set(aff->v->el[1 + pos], v->n);1228 } else if (isl_int_is_one(v->d)) {1229 isl_int_mul(aff->v->el[1 + pos], aff->v->el[0], v->n);1230 } else {1231 isl_seq_scale(aff->v->el + 1,1232 aff->v->el + 1, v->d, aff->v->size - 1);1233 isl_int_mul(aff->v->el[1 + pos], aff->v->el[0], v->n);1234 isl_int_mul(aff->v->el[0], aff->v->el[0], v->d);1235 aff->v = isl_vec_normalize(aff->v);1236 if (!aff->v)1237 goto error;1238 }1239 1240 isl_val_free(v);1241 return aff;1242error:1243 isl_aff_free(aff);1244 isl_val_free(v);1245 return NULL;1246}1247 1248/* Add "v" to the coefficient of the variable of type "type"1249 * at position "pos" of "aff".1250 *1251 * A NaN is unaffected by this operation.1252 */1253__isl_give isl_aff *isl_aff_add_coefficient(__isl_take isl_aff *aff,1254 enum isl_dim_type type, int pos, isl_int v)1255{1256 if (!aff)1257 return NULL;1258 1259 if (type == isl_dim_out)1260 isl_die(aff->v->ctx, isl_error_invalid,1261 "output/set dimension does not have a coefficient",1262 return isl_aff_free(aff));1263 if (type == isl_dim_in)1264 type = isl_dim_set;1265 1266 if (isl_local_space_check_range(aff->ls, type, pos, 1) < 0)1267 return isl_aff_free(aff);1268 1269 if (isl_aff_is_nan(aff))1270 return aff;1271 aff = isl_aff_cow(aff);1272 if (!aff)1273 return NULL;1274 1275 aff->v = isl_vec_cow(aff->v);1276 if (!aff->v)1277 return isl_aff_free(aff);1278 1279 pos += isl_local_space_offset(aff->ls, type);1280 isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v);1281 1282 return aff;1283}1284 1285/* Add "v" to the coefficient of the variable of type "type"1286 * at position "pos" of "aff".1287 *1288 * A NaN is unaffected by this operation.1289 */1290__isl_give isl_aff *isl_aff_add_coefficient_val(__isl_take isl_aff *aff,1291 enum isl_dim_type type, int pos, __isl_take isl_val *v)1292{1293 if (!aff || !v)1294 goto error;1295 1296 if (isl_val_is_zero(v)) {1297 isl_val_free(v);1298 return aff;1299 }1300 1301 if (type == isl_dim_out)1302 isl_die(aff->v->ctx, isl_error_invalid,1303 "output/set dimension does not have a coefficient",1304 goto error);1305 if (type == isl_dim_in)1306 type = isl_dim_set;1307 1308 if (isl_local_space_check_range(aff->ls, type, pos, 1) < 0)1309 goto error;1310 1311 if (isl_aff_is_nan(aff)) {1312 isl_val_free(v);1313 return aff;1314 }1315 if (!isl_val_is_rat(v))1316 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,1317 "expecting rational value", goto error);1318 1319 aff = isl_aff_cow(aff);1320 if (!aff)1321 goto error;1322 1323 aff->v = isl_vec_cow(aff->v);1324 if (!aff->v)1325 goto error;1326 1327 pos += isl_local_space_offset(aff->ls, type);1328 if (isl_int_is_one(v->d)) {1329 isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v->n);1330 } else if (isl_int_eq(aff->v->el[0], v->d)) {1331 isl_int_add(aff->v->el[1 + pos], aff->v->el[1 + pos], v->n);1332 aff->v = isl_vec_normalize(aff->v);1333 if (!aff->v)1334 goto error;1335 } else {1336 isl_seq_scale(aff->v->el + 1,1337 aff->v->el + 1, v->d, aff->v->size - 1);1338 isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v->n);1339 isl_int_mul(aff->v->el[0], aff->v->el[0], v->d);1340 aff->v = isl_vec_normalize(aff->v);1341 if (!aff->v)1342 goto error;1343 }1344 1345 isl_val_free(v);1346 return aff;1347error:1348 isl_aff_free(aff);1349 isl_val_free(v);1350 return NULL;1351}1352 1353__isl_give isl_aff *isl_aff_add_coefficient_si(__isl_take isl_aff *aff,1354 enum isl_dim_type type, int pos, int v)1355{1356 isl_int t;1357 1358 isl_int_init(t);1359 isl_int_set_si(t, v);1360 aff = isl_aff_add_coefficient(aff, type, pos, t);1361 isl_int_clear(t);1362 1363 return aff;1364}1365 1366__isl_give isl_aff *isl_aff_get_div(__isl_keep isl_aff *aff, int pos)1367{1368 if (!aff)1369 return NULL;1370 1371 return isl_local_space_get_div(aff->ls, pos);1372}1373 1374/* Return the negation of "aff".1375 *1376 * As a special case, -NaN = NaN.1377 */1378__isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff)1379{1380 if (!aff)1381 return NULL;1382 if (isl_aff_is_nan(aff))1383 return aff;1384 aff = isl_aff_cow(aff);1385 if (!aff)1386 return NULL;1387 aff->v = isl_vec_cow(aff->v);1388 if (!aff->v)1389 return isl_aff_free(aff);1390 1391 isl_seq_neg(aff->v->el + 1, aff->v->el + 1, aff->v->size - 1);1392 1393 return aff;1394}1395 1396/* Remove divs from the local space that do not appear in the affine1397 * expression.1398 * We currently only remove divs at the end.1399 * Some intermediate divs may also not appear directly in the affine1400 * expression, but we would also need to check that no other divs are1401 * defined in terms of them.1402 */1403__isl_give isl_aff *isl_aff_remove_unused_divs(__isl_take isl_aff *aff)1404{1405 int pos;1406 isl_size off;1407 isl_size n;1408 1409 n = isl_aff_domain_dim(aff, isl_dim_div);1410 off = isl_aff_domain_offset(aff, isl_dim_div);1411 if (n < 0 || off < 0)1412 return isl_aff_free(aff);1413 1414 pos = isl_seq_last_non_zero(aff->v->el + 1 + off, n) + 1;1415 if (pos == n)1416 return aff;1417 1418 aff = isl_aff_cow(aff);1419 if (!aff)1420 return NULL;1421 1422 aff->ls = isl_local_space_drop_dims(aff->ls, isl_dim_div, pos, n - pos);1423 aff->v = isl_vec_drop_els(aff->v, 1 + off + pos, n - pos);1424 if (!aff->ls || !aff->v)1425 return isl_aff_free(aff);1426 1427 return aff;1428}1429 1430/* Look for any divs in the aff->ls with a denominator equal to one1431 * and plug them into the affine expression and any subsequent divs1432 * that may reference the div.1433 */1434static __isl_give isl_aff *plug_in_integral_divs(__isl_take isl_aff *aff)1435{1436 int i;1437 isl_size n;1438 int len;1439 isl_int v;1440 isl_vec *vec;1441 isl_local_space *ls;1442 isl_size off;1443 1444 n = isl_aff_domain_dim(aff, isl_dim_div);1445 off = isl_aff_domain_offset(aff, isl_dim_div);1446 if (n < 0 || off < 0)1447 return isl_aff_free(aff);1448 len = aff->v->size;1449 for (i = 0; i < n; ++i) {1450 if (!isl_int_is_one(aff->ls->div->row[i][0]))1451 continue;1452 ls = isl_local_space_copy(aff->ls);1453 ls = isl_local_space_substitute_seq(ls, isl_dim_div, i,1454 aff->ls->div->row[i], len, i + 1, n - (i + 1));1455 vec = isl_vec_copy(aff->v);1456 vec = isl_vec_cow(vec);1457 if (!ls || !vec)1458 goto error;1459 1460 isl_int_init(v);1461 1462 isl_seq_substitute(vec->el, off + i, aff->ls->div->row[i],1463 len, len, v);1464 1465 isl_int_clear(v);1466 1467 isl_vec_free(aff->v);1468 aff->v = vec;1469 isl_local_space_free(aff->ls);1470 aff->ls = ls;1471 }1472 1473 return aff;1474error:1475 isl_vec_free(vec);1476 isl_local_space_free(ls);1477 return isl_aff_free(aff);1478}1479 1480/* Look for any divs j that appear with a unit coefficient inside1481 * the definitions of other divs i and plug them into the definitions1482 * of the divs i.1483 *1484 * In particular, an expression of the form1485 *1486 * floor((f(..) + floor(g(..)/n))/m)1487 *1488 * is simplified to1489 *1490 * floor((n * f(..) + g(..))/(n * m))1491 *1492 * This simplification is correct because we can move the expression1493 * f(..) into the inner floor in the original expression to obtain1494 *1495 * floor(floor((n * f(..) + g(..))/n)/m)1496 *1497 * from which we can derive the simplified expression.1498 */1499static __isl_give isl_aff *plug_in_unit_divs(__isl_take isl_aff *aff)1500{1501 int i, j;1502 isl_size n;1503 isl_size off;1504 1505 n = isl_aff_domain_dim(aff, isl_dim_div);1506 off = isl_aff_domain_offset(aff, isl_dim_div);1507 if (n < 0 || off < 0)1508 return isl_aff_free(aff);1509 for (i = 1; i < n; ++i) {1510 for (j = 0; j < i; ++j) {1511 if (!isl_int_is_one(aff->ls->div->row[i][1 + off + j]))1512 continue;1513 aff->ls = isl_local_space_substitute_seq(aff->ls,1514 isl_dim_div, j, aff->ls->div->row[j],1515 aff->v->size, i, 1);1516 if (!aff->ls)1517 return isl_aff_free(aff);1518 }1519 }1520 1521 return aff;1522}1523 1524/* Swap divs "a" and "b" in "aff", which is assumed to be non-NULL.1525 *1526 * Even though this function is only called on isl_affs with a single1527 * reference, we are careful to only change aff->v and aff->ls together.1528 */1529static __isl_give isl_aff *swap_div(__isl_take isl_aff *aff, int a, int b)1530{1531 isl_size off = isl_aff_domain_offset(aff, isl_dim_div);1532 isl_local_space *ls;1533 isl_vec *v;1534 1535 if (off < 0)1536 return isl_aff_free(aff);1537 1538 ls = isl_local_space_copy(aff->ls);1539 ls = isl_local_space_swap_div(ls, a, b);1540 v = isl_vec_copy(aff->v);1541 v = isl_vec_cow(v);1542 if (!ls || !v)1543 goto error;1544 1545 isl_int_swap(v->el[1 + off + a], v->el[1 + off + b]);1546 isl_vec_free(aff->v);1547 aff->v = v;1548 isl_local_space_free(aff->ls);1549 aff->ls = ls;1550 1551 return aff;1552error:1553 isl_vec_free(v);1554 isl_local_space_free(ls);1555 return isl_aff_free(aff);1556}1557 1558/* Merge divs "a" and "b" in "aff", which is assumed to be non-NULL.1559 *1560 * We currently do not actually remove div "b", but simply add its1561 * coefficient to that of "a" and then zero it out.1562 */1563static __isl_give isl_aff *merge_divs(__isl_take isl_aff *aff, int a, int b)1564{1565 isl_size off = isl_aff_domain_offset(aff, isl_dim_div);1566 1567 if (off < 0)1568 return isl_aff_free(aff);1569 1570 if (isl_int_is_zero(aff->v->el[1 + off + b]))1571 return aff;1572 1573 aff->v = isl_vec_cow(aff->v);1574 if (!aff->v)1575 return isl_aff_free(aff);1576 1577 isl_int_add(aff->v->el[1 + off + a],1578 aff->v->el[1 + off + a], aff->v->el[1 + off + b]);1579 isl_int_set_si(aff->v->el[1 + off + b], 0);1580 1581 return aff;1582}1583 1584/* Sort the divs in the local space of "aff" according to1585 * the comparison function "cmp_row" in isl_local_space.c,1586 * combining the coefficients of identical divs.1587 *1588 * Reordering divs does not change the semantics of "aff",1589 * so there is no need to call isl_aff_cow.1590 * Moreover, this function is currently only called on isl_affs1591 * with a single reference.1592 */1593static __isl_give isl_aff *sort_divs(__isl_take isl_aff *aff)1594{1595 isl_size n;1596 int i, j;1597 1598 n = isl_aff_dim(aff, isl_dim_div);1599 if (n < 0)1600 return isl_aff_free(aff);1601 for (i = 1; i < n; ++i) {1602 for (j = i - 1; j >= 0; --j) {1603 int cmp = isl_mat_cmp_div(aff->ls->div, j, j + 1);1604 if (cmp < 0)1605 break;1606 if (cmp == 0)1607 aff = merge_divs(aff, j, j + 1);1608 else1609 aff = swap_div(aff, j, j + 1);1610 if (!aff)1611 return NULL;1612 }1613 }1614 1615 return aff;1616}1617 1618/* Normalize the representation of "aff".1619 *1620 * This function should only be called on "new" isl_affs, i.e.,1621 * with only a single reference. We therefore do not need to1622 * worry about affecting other instances.1623 */1624__isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *aff)1625{1626 if (!aff)1627 return NULL;1628 aff->v = isl_vec_normalize(aff->v);1629 if (!aff->v)1630 return isl_aff_free(aff);1631 aff = plug_in_integral_divs(aff);1632 aff = plug_in_unit_divs(aff);1633 aff = sort_divs(aff);1634 aff = isl_aff_remove_unused_divs(aff);1635 return aff;1636}1637 1638/* Given f, return floor(f).1639 * If f is an integer expression, then just return f.1640 * If f is a constant, then return the constant floor(f).1641 * Otherwise, if f = g/m, write g = q m + r,1642 * create a new div d = [r/m] and return the expression q + d.1643 * The coefficients in r are taken to lie between -m/2 and m/2.1644 *1645 * reduce_div_coefficients performs the same normalization.1646 *1647 * As a special case, floor(NaN) = NaN.1648 */1649__isl_give isl_aff *isl_aff_floor(__isl_take isl_aff *aff)1650{1651 int i;1652 int size;1653 isl_ctx *ctx;1654 isl_vec *div;1655 1656 if (!aff)1657 return NULL;1658 1659 if (isl_aff_is_nan(aff))1660 return aff;1661 if (isl_int_is_one(aff->v->el[0]))1662 return aff;1663 1664 aff = isl_aff_cow(aff);1665 if (!aff)1666 return NULL;1667 1668 aff->v = isl_vec_cow(aff->v);1669 if (!aff->v)1670 return isl_aff_free(aff);1671 1672 if (isl_aff_is_cst(aff)) {1673 isl_int_fdiv_q(aff->v->el[1], aff->v->el[1], aff->v->el[0]);1674 isl_int_set_si(aff->v->el[0], 1);1675 return aff;1676 }1677 1678 div = isl_vec_copy(aff->v);1679 div = isl_vec_cow(div);1680 if (!div)1681 return isl_aff_free(aff);1682 1683 ctx = isl_aff_get_ctx(aff);1684 isl_int_fdiv_q(aff->v->el[0], aff->v->el[0], ctx->two);1685 for (i = 1; i < aff->v->size; ++i) {1686 isl_int_fdiv_r(div->el[i], div->el[i], div->el[0]);1687 isl_int_fdiv_q(aff->v->el[i], aff->v->el[i], div->el[0]);1688 if (isl_int_gt(div->el[i], aff->v->el[0])) {1689 isl_int_sub(div->el[i], div->el[i], div->el[0]);1690 isl_int_add_ui(aff->v->el[i], aff->v->el[i], 1);1691 }1692 }1693 1694 aff->ls = isl_local_space_add_div(aff->ls, div);1695 if (!aff->ls)1696 return isl_aff_free(aff);1697 1698 size = aff->v->size;1699 aff->v = isl_vec_extend(aff->v, size + 1);1700 if (!aff->v)1701 return isl_aff_free(aff);1702 isl_int_set_si(aff->v->el[0], 1);1703 isl_int_set_si(aff->v->el[size], 1);1704 1705 aff = isl_aff_normalize(aff);1706 1707 return aff;1708}1709 1710/* Compute1711 *1712 * aff mod m = aff - m * floor(aff/m)1713 *1714 * with m an integer value.1715 */1716__isl_give isl_aff *isl_aff_mod_val(__isl_take isl_aff *aff,1717 __isl_take isl_val *m)1718{1719 isl_aff *res;1720 1721 if (!aff || !m)1722 goto error;1723 1724 if (!isl_val_is_int(m))1725 isl_die(isl_val_get_ctx(m), isl_error_invalid,1726 "expecting integer modulo", goto error);1727 1728 res = isl_aff_copy(aff);1729 aff = isl_aff_scale_down_val(aff, isl_val_copy(m));1730 aff = isl_aff_floor(aff);1731 aff = isl_aff_scale_val(aff, m);1732 res = isl_aff_sub(res, aff);1733 1734 return res;1735error:1736 isl_aff_free(aff);1737 isl_val_free(m);1738 return NULL;1739}1740 1741/* Compute1742 *1743 * pwaff mod m = pwaff - m * floor(pwaff/m)1744 */1745__isl_give isl_pw_aff *isl_pw_aff_mod(__isl_take isl_pw_aff *pwaff, isl_int m)1746{1747 isl_pw_aff *res;1748 1749 res = isl_pw_aff_copy(pwaff);1750 pwaff = isl_pw_aff_scale_down(pwaff, m);1751 pwaff = isl_pw_aff_floor(pwaff);1752 pwaff = isl_pw_aff_scale(pwaff, m);1753 res = isl_pw_aff_sub(res, pwaff);1754 1755 return res;1756}1757 1758/* Compute1759 *1760 * pa mod m = pa - m * floor(pa/m)1761 *1762 * with m an integer value.1763 */1764__isl_give isl_pw_aff *isl_pw_aff_mod_val(__isl_take isl_pw_aff *pa,1765 __isl_take isl_val *m)1766{1767 if (!pa || !m)1768 goto error;1769 if (!isl_val_is_int(m))1770 isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,1771 "expecting integer modulo", goto error);1772 pa = isl_pw_aff_mod(pa, m->n);1773 isl_val_free(m);1774 return pa;1775error:1776 isl_pw_aff_free(pa);1777 isl_val_free(m);1778 return NULL;1779}1780 1781/* Given f, return ceil(f).1782 * If f is an integer expression, then just return f.1783 * Otherwise, let f be the expression1784 *1785 * e/m1786 *1787 * then return1788 *1789 * floor((e + m - 1)/m)1790 *1791 * As a special case, ceil(NaN) = NaN.1792 */1793__isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff)1794{1795 if (!aff)1796 return NULL;1797 1798 if (isl_aff_is_nan(aff))1799 return aff;1800 if (isl_int_is_one(aff->v->el[0]))1801 return aff;1802 1803 aff = isl_aff_cow(aff);1804 if (!aff)1805 return NULL;1806 aff->v = isl_vec_cow(aff->v);1807 if (!aff->v)1808 return isl_aff_free(aff);1809 1810 isl_int_add(aff->v->el[1], aff->v->el[1], aff->v->el[0]);1811 isl_int_sub_ui(aff->v->el[1], aff->v->el[1], 1);1812 aff = isl_aff_floor(aff);1813 1814 return aff;1815}1816 1817/* Apply the expansion computed by isl_merge_divs.1818 * The expansion itself is given by "exp" while the resulting1819 * list of divs is given by "div".1820 */1821__isl_give isl_aff *isl_aff_expand_divs(__isl_take isl_aff *aff,1822 __isl_take isl_mat *div, int *exp)1823{1824 isl_size old_n_div;1825 isl_size new_n_div;1826 isl_size offset;1827 1828 aff = isl_aff_cow(aff);1829 1830 offset = isl_aff_domain_offset(aff, isl_dim_div);1831 old_n_div = isl_aff_domain_dim(aff, isl_dim_div);1832 new_n_div = isl_mat_rows(div);1833 if (offset < 0 || old_n_div < 0 || new_n_div < 0)1834 goto error;1835 1836 aff->v = isl_vec_expand(aff->v, 1 + offset, old_n_div, exp, new_n_div);1837 aff->ls = isl_local_space_replace_divs(aff->ls, div);1838 if (!aff->v || !aff->ls)1839 return isl_aff_free(aff);1840 return aff;1841error:1842 isl_aff_free(aff);1843 isl_mat_free(div);1844 return NULL;1845}1846 1847/* Add two affine expressions that live in the same local space.1848 */1849static __isl_give isl_aff *add_expanded(__isl_take isl_aff *aff1,1850 __isl_take isl_aff *aff2)1851{1852 isl_int gcd, f;1853 1854 aff1 = isl_aff_cow(aff1);1855 if (!aff1 || !aff2)1856 goto error;1857 1858 aff1->v = isl_vec_cow(aff1->v);1859 if (!aff1->v)1860 goto error;1861 1862 isl_int_init(gcd);1863 isl_int_init(f);1864 isl_int_gcd(gcd, aff1->v->el[0], aff2->v->el[0]);1865 isl_int_divexact(f, aff2->v->el[0], gcd);1866 isl_seq_scale(aff1->v->el + 1, aff1->v->el + 1, f, aff1->v->size - 1);1867 isl_int_divexact(f, aff1->v->el[0], gcd);1868 isl_seq_addmul(aff1->v->el + 1, f, aff2->v->el + 1, aff1->v->size - 1);1869 isl_int_divexact(f, aff2->v->el[0], gcd);1870 isl_int_mul(aff1->v->el[0], aff1->v->el[0], f);1871 isl_int_clear(f);1872 isl_int_clear(gcd);1873 1874 isl_aff_free(aff2);1875 aff1 = isl_aff_normalize(aff1);1876 return aff1;1877error:1878 isl_aff_free(aff1);1879 isl_aff_free(aff2);1880 return NULL;1881}1882 1883/* Replace one of the arguments by a NaN and free the other one.1884 */1885static __isl_give isl_aff *set_nan_free(__isl_take isl_aff *aff1,1886 __isl_take isl_aff *aff2)1887{1888 isl_aff_free(aff2);1889 return isl_aff_set_nan(aff1);1890}1891 1892/* Return the sum of "aff1" and "aff2".1893 *1894 * If either of the two is NaN, then the result is NaN.1895 */1896__isl_give isl_aff *isl_aff_add(__isl_take isl_aff *aff1,1897 __isl_take isl_aff *aff2)1898{1899 isl_ctx *ctx;1900 int *exp1 = NULL;1901 int *exp2 = NULL;1902 isl_mat *div;1903 isl_size n_div1, n_div2;1904 1905 if (!aff1 || !aff2)1906 goto error;1907 1908 ctx = isl_aff_get_ctx(aff1);1909 if (!isl_space_is_equal(aff1->ls->dim, aff2->ls->dim))1910 isl_die(ctx, isl_error_invalid,1911 "spaces don't match", goto error);1912 1913 if (isl_aff_is_nan(aff1)) {1914 isl_aff_free(aff2);1915 return aff1;1916 }1917 if (isl_aff_is_nan(aff2)) {1918 isl_aff_free(aff1);1919 return aff2;1920 }1921 1922 n_div1 = isl_aff_dim(aff1, isl_dim_div);1923 n_div2 = isl_aff_dim(aff2, isl_dim_div);1924 if (n_div1 < 0 || n_div2 < 0)1925 goto error;1926 if (n_div1 == 0 && n_div2 == 0)1927 return add_expanded(aff1, aff2);1928 1929 exp1 = isl_alloc_array(ctx, int, n_div1);1930 exp2 = isl_alloc_array(ctx, int, n_div2);1931 if ((n_div1 && !exp1) || (n_div2 && !exp2))1932 goto error;1933 1934 div = isl_merge_divs(aff1->ls->div, aff2->ls->div, exp1, exp2);1935 aff1 = isl_aff_expand_divs(aff1, isl_mat_copy(div), exp1);1936 aff2 = isl_aff_expand_divs(aff2, div, exp2);1937 free(exp1);1938 free(exp2);1939 1940 return add_expanded(aff1, aff2);1941error:1942 free(exp1);1943 free(exp2);1944 isl_aff_free(aff1);1945 isl_aff_free(aff2);1946 return NULL;1947}1948 1949__isl_give isl_aff *isl_aff_sub(__isl_take isl_aff *aff1,1950 __isl_take isl_aff *aff2)1951{1952 return isl_aff_add(aff1, isl_aff_neg(aff2));1953}1954 1955/* Return the result of scaling "aff" by a factor of "f".1956 *1957 * As a special case, f * NaN = NaN.1958 */1959__isl_give isl_aff *isl_aff_scale(__isl_take isl_aff *aff, isl_int f)1960{1961 isl_int gcd;1962 1963 if (!aff)1964 return NULL;1965 if (isl_aff_is_nan(aff))1966 return aff;1967 1968 if (isl_int_is_one(f))1969 return aff;1970 1971 aff = isl_aff_cow(aff);1972 if (!aff)1973 return NULL;1974 aff->v = isl_vec_cow(aff->v);1975 if (!aff->v)1976 return isl_aff_free(aff);1977 1978 if (isl_int_is_pos(f) && isl_int_is_divisible_by(aff->v->el[0], f)) {1979 isl_int_divexact(aff->v->el[0], aff->v->el[0], f);1980 return aff;1981 }1982 1983 isl_int_init(gcd);1984 isl_int_gcd(gcd, aff->v->el[0], f);1985 isl_int_divexact(aff->v->el[0], aff->v->el[0], gcd);1986 isl_int_divexact(gcd, f, gcd);1987 isl_seq_scale(aff->v->el + 1, aff->v->el + 1, gcd, aff->v->size - 1);1988 isl_int_clear(gcd);1989 1990 return aff;1991}1992 1993/* Multiple "aff" by "v".1994 */1995__isl_give isl_aff *isl_aff_scale_val(__isl_take isl_aff *aff,1996 __isl_take isl_val *v)1997{1998 if (!aff || !v)1999 goto error;2000 2001 if (isl_val_is_one(v)) {2002 isl_val_free(v);2003 return aff;2004 }2005 2006 if (!isl_val_is_rat(v))2007 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,2008 "expecting rational factor", goto error);2009 2010 aff = isl_aff_scale(aff, v->n);2011 aff = isl_aff_scale_down(aff, v->d);2012 2013 isl_val_free(v);2014 return aff;2015error:2016 isl_aff_free(aff);2017 isl_val_free(v);2018 return NULL;2019}2020 2021/* Return the result of scaling "aff" down by a factor of "f".2022 *2023 * As a special case, NaN/f = NaN.2024 */2025__isl_give isl_aff *isl_aff_scale_down(__isl_take isl_aff *aff, isl_int f)2026{2027 isl_int gcd;2028 2029 if (!aff)2030 return NULL;2031 if (isl_aff_is_nan(aff))2032 return aff;2033 2034 if (isl_int_is_one(f))2035 return aff;2036 2037 aff = isl_aff_cow(aff);2038 if (!aff)2039 return NULL;2040 2041 if (isl_int_is_zero(f))2042 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,2043 "cannot scale down by zero", return isl_aff_free(aff));2044 2045 aff->v = isl_vec_cow(aff->v);2046 if (!aff->v)2047 return isl_aff_free(aff);2048 2049 isl_int_init(gcd);2050 isl_seq_gcd(aff->v->el + 1, aff->v->size - 1, &gcd);2051 isl_int_gcd(gcd, gcd, f);2052 isl_seq_scale_down(aff->v->el + 1, aff->v->el + 1, gcd, aff->v->size - 1);2053 isl_int_divexact(gcd, f, gcd);2054 isl_int_mul(aff->v->el[0], aff->v->el[0], gcd);2055 isl_int_clear(gcd);2056 2057 return aff;2058}2059 2060/* Divide "aff" by "v".2061 */2062__isl_give isl_aff *isl_aff_scale_down_val(__isl_take isl_aff *aff,2063 __isl_take isl_val *v)2064{2065 if (!aff || !v)2066 goto error;2067 2068 if (isl_val_is_one(v)) {2069 isl_val_free(v);2070 return aff;2071 }2072 2073 if (!isl_val_is_rat(v))2074 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,2075 "expecting rational factor", goto error);2076 if (!isl_val_is_pos(v))2077 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,2078 "factor needs to be positive", goto error);2079 2080 aff = isl_aff_scale(aff, v->d);2081 aff = isl_aff_scale_down(aff, v->n);2082 2083 isl_val_free(v);2084 return aff;2085error:2086 isl_aff_free(aff);2087 isl_val_free(v);2088 return NULL;2089}2090 2091__isl_give isl_aff *isl_aff_scale_down_ui(__isl_take isl_aff *aff, unsigned f)2092{2093 isl_int v;2094 2095 if (f == 1)2096 return aff;2097 2098 isl_int_init(v);2099 isl_int_set_ui(v, f);2100 aff = isl_aff_scale_down(aff, v);2101 isl_int_clear(v);2102 2103 return aff;2104}2105 2106__isl_give isl_aff *isl_aff_set_dim_name(__isl_take isl_aff *aff,2107 enum isl_dim_type type, unsigned pos, const char *s)2108{2109 aff = isl_aff_cow(aff);2110 if (!aff)2111 return NULL;2112 if (type == isl_dim_out)2113 isl_die(aff->v->ctx, isl_error_invalid,2114 "cannot set name of output/set dimension",2115 return isl_aff_free(aff));2116 if (type == isl_dim_in)2117 type = isl_dim_set;2118 aff->ls = isl_local_space_set_dim_name(aff->ls, type, pos, s);2119 if (!aff->ls)2120 return isl_aff_free(aff);2121 2122 return aff;2123}2124 2125__isl_give isl_aff *isl_aff_set_dim_id(__isl_take isl_aff *aff,2126 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)2127{2128 aff = isl_aff_cow(aff);2129 if (!aff)2130 goto error;2131 if (type == isl_dim_out)2132 isl_die(aff->v->ctx, isl_error_invalid,2133 "cannot set name of output/set dimension",2134 goto error);2135 if (type == isl_dim_in)2136 type = isl_dim_set;2137 aff->ls = isl_local_space_set_dim_id(aff->ls, type, pos, id);2138 if (!aff->ls)2139 return isl_aff_free(aff);2140 2141 return aff;2142error:2143 isl_id_free(id);2144 isl_aff_free(aff);2145 return NULL;2146}2147 2148/* Replace the identifier of the input tuple of "aff" by "id".2149 * type is currently required to be equal to isl_dim_in2150 */2151__isl_give isl_aff *isl_aff_set_tuple_id(__isl_take isl_aff *aff,2152 enum isl_dim_type type, __isl_take isl_id *id)2153{2154 aff = isl_aff_cow(aff);2155 if (!aff)2156 goto error;2157 if (type != isl_dim_in)2158 isl_die(aff->v->ctx, isl_error_invalid,2159 "cannot only set id of input tuple", goto error);2160 aff->ls = isl_local_space_set_tuple_id(aff->ls, isl_dim_set, id);2161 if (!aff->ls)2162 return isl_aff_free(aff);2163 2164 return aff;2165error:2166 isl_id_free(id);2167 isl_aff_free(aff);2168 return NULL;2169}2170 2171/* Exploit the equalities in "eq" to simplify the affine expression2172 * and the expressions of the integer divisions in the local space.2173 * The integer divisions in this local space are assumed to appear2174 * as regular dimensions in "eq".2175 */2176static __isl_give isl_aff *isl_aff_substitute_equalities_lifted(2177 __isl_take isl_aff *aff, __isl_take isl_basic_set *eq)2178{2179 int i, j;2180 unsigned o_div;2181 unsigned n_div;2182 2183 if (!eq)2184 goto error;2185 if (eq->n_eq == 0) {2186 isl_basic_set_free(eq);2187 return aff;2188 }2189 2190 aff = isl_aff_cow(aff);2191 if (!aff)2192 goto error;2193 2194 aff->ls = isl_local_space_substitute_equalities(aff->ls,2195 isl_basic_set_copy(eq));2196 aff->v = isl_vec_cow(aff->v);2197 if (!aff->ls || !aff->v)2198 goto error;2199 2200 o_div = isl_basic_set_offset(eq, isl_dim_div);2201 n_div = eq->n_div;2202 for (i = 0; i < eq->n_eq; ++i) {2203 j = isl_seq_last_non_zero(eq->eq[i], o_div + n_div);2204 if (j < 0 || j == 0 || j >= o_div)2205 continue;2206 2207 isl_seq_elim(aff->v->el + 1, eq->eq[i], j, o_div,2208 &aff->v->el[0]);2209 }2210 2211 isl_basic_set_free(eq);2212 aff = isl_aff_normalize(aff);2213 return aff;2214error:2215 isl_basic_set_free(eq);2216 isl_aff_free(aff);2217 return NULL;2218}2219 2220/* Exploit the equalities in "eq" to simplify the affine expression2221 * and the expressions of the integer divisions in the local space.2222 */2223__isl_give isl_aff *isl_aff_substitute_equalities(__isl_take isl_aff *aff,2224 __isl_take isl_basic_set *eq)2225{2226 isl_size n_div;2227 2228 n_div = isl_aff_domain_dim(aff, isl_dim_div);2229 if (n_div < 0)2230 goto error;2231 if (n_div > 0)2232 eq = isl_basic_set_add_dims(eq, isl_dim_set, n_div);2233 return isl_aff_substitute_equalities_lifted(aff, eq);2234error:2235 isl_basic_set_free(eq);2236 isl_aff_free(aff);2237 return NULL;2238}2239 2240/* Look for equalities among the variables shared by context and aff2241 * and the integer divisions of aff, if any.2242 * The equalities are then used to eliminate coefficients and/or integer2243 * divisions from aff.2244 */2245__isl_give isl_aff *isl_aff_gist(__isl_take isl_aff *aff,2246 __isl_take isl_set *context)2247{2248 isl_local_space *ls;2249 isl_basic_set *hull;2250 2251 ls = isl_aff_get_domain_local_space(aff);2252 context = isl_local_space_lift_set(ls, context);2253 2254 hull = isl_set_affine_hull(context);2255 return isl_aff_substitute_equalities_lifted(aff, hull);2256}2257 2258__isl_give isl_aff *isl_aff_gist_params(__isl_take isl_aff *aff,2259 __isl_take isl_set *context)2260{2261 isl_set *dom_context = isl_set_universe(isl_aff_get_domain_space(aff));2262 dom_context = isl_set_intersect_params(dom_context, context);2263 return isl_aff_gist(aff, dom_context);2264}2265 2266/* Return a basic set containing those elements in the space2267 * of aff where it is positive. "rational" should not be set.2268 *2269 * If "aff" is NaN, then it is not positive.2270 */2271static __isl_give isl_basic_set *aff_pos_basic_set(__isl_take isl_aff *aff,2272 int rational, void *user)2273{2274 isl_constraint *ineq;2275 isl_basic_set *bset;2276 isl_val *c;2277 2278 if (!aff)2279 return NULL;2280 if (isl_aff_is_nan(aff)) {2281 isl_space *space = isl_aff_get_domain_space(aff);2282 isl_aff_free(aff);2283 return isl_basic_set_empty(space);2284 }2285 if (rational)2286 isl_die(isl_aff_get_ctx(aff), isl_error_unsupported,2287 "rational sets not supported", goto error);2288 2289 ineq = isl_inequality_from_aff(aff);2290 c = isl_constraint_get_constant_val(ineq);2291 c = isl_val_sub_ui(c, 1);2292 ineq = isl_constraint_set_constant_val(ineq, c);2293 2294 bset = isl_basic_set_from_constraint(ineq);2295 bset = isl_basic_set_simplify(bset);2296 return bset;2297error:2298 isl_aff_free(aff);2299 return NULL;2300}2301 2302/* Return a basic set containing those elements in the space2303 * of aff where it is non-negative.2304 * If "rational" is set, then return a rational basic set.2305 *2306 * If "aff" is NaN, then it is not non-negative (it's not negative either).2307 */2308static __isl_give isl_basic_set *aff_nonneg_basic_set(2309 __isl_take isl_aff *aff, int rational, void *user)2310{2311 isl_constraint *ineq;2312 isl_basic_set *bset;2313 2314 if (!aff)2315 return NULL;2316 if (isl_aff_is_nan(aff)) {2317 isl_space *space = isl_aff_get_domain_space(aff);2318 isl_aff_free(aff);2319 return isl_basic_set_empty(space);2320 }2321 2322 ineq = isl_inequality_from_aff(aff);2323 2324 bset = isl_basic_set_from_constraint(ineq);2325 if (rational)2326 bset = isl_basic_set_set_rational(bset);2327 bset = isl_basic_set_simplify(bset);2328 return bset;2329}2330 2331/* Return a basic set containing those elements in the space2332 * of aff where it is non-negative.2333 */2334__isl_give isl_basic_set *isl_aff_nonneg_basic_set(__isl_take isl_aff *aff)2335{2336 return aff_nonneg_basic_set(aff, 0, NULL);2337}2338 2339/* Return a basic set containing those elements in the domain space2340 * of "aff" where it is positive.2341 */2342__isl_give isl_basic_set *isl_aff_pos_basic_set(__isl_take isl_aff *aff)2343{2344 aff = isl_aff_add_constant_num_si(aff, -1);2345 return isl_aff_nonneg_basic_set(aff);2346}2347 2348/* Return a basic set containing those elements in the domain space2349 * of aff where it is negative.2350 */2351__isl_give isl_basic_set *isl_aff_neg_basic_set(__isl_take isl_aff *aff)2352{2353 aff = isl_aff_neg(aff);2354 return isl_aff_pos_basic_set(aff);2355}2356 2357/* Return a basic set containing those elements in the space2358 * of aff where it is zero.2359 * If "rational" is set, then return a rational basic set.2360 *2361 * If "aff" is NaN, then it is not zero.2362 */2363static __isl_give isl_basic_set *aff_zero_basic_set(__isl_take isl_aff *aff,2364 int rational, void *user)2365{2366 isl_constraint *ineq;2367 isl_basic_set *bset;2368 2369 if (!aff)2370 return NULL;2371 if (isl_aff_is_nan(aff)) {2372 isl_space *space = isl_aff_get_domain_space(aff);2373 isl_aff_free(aff);2374 return isl_basic_set_empty(space);2375 }2376 2377 ineq = isl_equality_from_aff(aff);2378 2379 bset = isl_basic_set_from_constraint(ineq);2380 if (rational)2381 bset = isl_basic_set_set_rational(bset);2382 bset = isl_basic_set_simplify(bset);2383 return bset;2384}2385 2386/* Return a basic set containing those elements in the space2387 * of aff where it is zero.2388 */2389__isl_give isl_basic_set *isl_aff_zero_basic_set(__isl_take isl_aff *aff)2390{2391 return aff_zero_basic_set(aff, 0, NULL);2392}2393 2394/* Return a basic set containing those elements in the shared space2395 * of aff1 and aff2 where aff1 is greater than or equal to aff2.2396 */2397__isl_give isl_basic_set *isl_aff_ge_basic_set(__isl_take isl_aff *aff1,2398 __isl_take isl_aff *aff2)2399{2400 aff1 = isl_aff_sub(aff1, aff2);2401 2402 return isl_aff_nonneg_basic_set(aff1);2403}2404 2405/* Return a basic set containing those elements in the shared domain space2406 * of "aff1" and "aff2" where "aff1" is greater than "aff2".2407 */2408__isl_give isl_basic_set *isl_aff_gt_basic_set(__isl_take isl_aff *aff1,2409 __isl_take isl_aff *aff2)2410{2411 aff1 = isl_aff_sub(aff1, aff2);2412 2413 return isl_aff_pos_basic_set(aff1);2414}2415 2416/* Return a set containing those elements in the shared space2417 * of aff1 and aff2 where aff1 is greater than or equal to aff2.2418 */2419__isl_give isl_set *isl_aff_ge_set(__isl_take isl_aff *aff1,2420 __isl_take isl_aff *aff2)2421{2422 return isl_set_from_basic_set(isl_aff_ge_basic_set(aff1, aff2));2423}2424 2425/* Return a set containing those elements in the shared domain space2426 * of aff1 and aff2 where aff1 is greater than aff2.2427 *2428 * If either of the two inputs is NaN, then the result is empty,2429 * as comparisons with NaN always return false.2430 */2431__isl_give isl_set *isl_aff_gt_set(__isl_take isl_aff *aff1,2432 __isl_take isl_aff *aff2)2433{2434 return isl_set_from_basic_set(isl_aff_gt_basic_set(aff1, aff2));2435}2436 2437/* Return a basic set containing those elements in the shared space2438 * of aff1 and aff2 where aff1 is smaller than or equal to aff2.2439 */2440__isl_give isl_basic_set *isl_aff_le_basic_set(__isl_take isl_aff *aff1,2441 __isl_take isl_aff *aff2)2442{2443 return isl_aff_ge_basic_set(aff2, aff1);2444}2445 2446/* Return a basic set containing those elements in the shared domain space2447 * of "aff1" and "aff2" where "aff1" is smaller than "aff2".2448 */2449__isl_give isl_basic_set *isl_aff_lt_basic_set(__isl_take isl_aff *aff1,2450 __isl_take isl_aff *aff2)2451{2452 return isl_aff_gt_basic_set(aff2, aff1);2453}2454 2455/* Return a set containing those elements in the shared space2456 * of aff1 and aff2 where aff1 is smaller than or equal to aff2.2457 */2458__isl_give isl_set *isl_aff_le_set(__isl_take isl_aff *aff1,2459 __isl_take isl_aff *aff2)2460{2461 return isl_aff_ge_set(aff2, aff1);2462}2463 2464/* Return a set containing those elements in the shared domain space2465 * of "aff1" and "aff2" where "aff1" is smaller than "aff2".2466 */2467__isl_give isl_set *isl_aff_lt_set(__isl_take isl_aff *aff1,2468 __isl_take isl_aff *aff2)2469{2470 return isl_set_from_basic_set(isl_aff_lt_basic_set(aff1, aff2));2471}2472 2473/* Return a basic set containing those elements in the shared space2474 * of aff1 and aff2 where aff1 and aff2 are equal.2475 */2476__isl_give isl_basic_set *isl_aff_eq_basic_set(__isl_take isl_aff *aff1,2477 __isl_take isl_aff *aff2)2478{2479 aff1 = isl_aff_sub(aff1, aff2);2480 2481 return isl_aff_zero_basic_set(aff1);2482}2483 2484/* Return a set containing those elements in the shared space2485 * of aff1 and aff2 where aff1 and aff2 are equal.2486 */2487__isl_give isl_set *isl_aff_eq_set(__isl_take isl_aff *aff1,2488 __isl_take isl_aff *aff2)2489{2490 return isl_set_from_basic_set(isl_aff_eq_basic_set(aff1, aff2));2491}2492 2493/* Return a set containing those elements in the shared domain space2494 * of aff1 and aff2 where aff1 and aff2 are not equal.2495 *2496 * If either of the two inputs is NaN, then the result is empty,2497 * as comparisons with NaN always return false.2498 */2499__isl_give isl_set *isl_aff_ne_set(__isl_take isl_aff *aff1,2500 __isl_take isl_aff *aff2)2501{2502 isl_set *set_lt, *set_gt;2503 2504 set_lt = isl_aff_lt_set(isl_aff_copy(aff1),2505 isl_aff_copy(aff2));2506 set_gt = isl_aff_gt_set(aff1, aff2);2507 return isl_set_union_disjoint(set_lt, set_gt);2508}2509 2510__isl_give isl_aff *isl_aff_add_on_domain(__isl_keep isl_set *dom,2511 __isl_take isl_aff *aff1, __isl_take isl_aff *aff2)2512{2513 aff1 = isl_aff_add(aff1, aff2);2514 aff1 = isl_aff_gist(aff1, isl_set_copy(dom));2515 return aff1;2516}2517 2518isl_bool isl_aff_is_empty(__isl_keep isl_aff *aff)2519{2520 if (!aff)2521 return isl_bool_error;2522 2523 return isl_bool_false;2524}2525 2526#undef TYPE2527#define TYPE isl_aff2528static2529#include "check_type_range_templ.c"2530 2531/* Check whether the given affine expression has non-zero coefficient2532 * for any dimension in the given range or if any of these dimensions2533 * appear with non-zero coefficients in any of the integer divisions2534 * involved in the affine expression.2535 */2536isl_bool isl_aff_involves_dims(__isl_keep isl_aff *aff,2537 enum isl_dim_type type, unsigned first, unsigned n)2538{2539 int i;2540 int *active = NULL;2541 isl_bool involves = isl_bool_false;2542 2543 if (!aff)2544 return isl_bool_error;2545 if (n == 0)2546 return isl_bool_false;2547 if (isl_aff_check_range(aff, type, first, n) < 0)2548 return isl_bool_error;2549 2550 active = isl_local_space_get_active(aff->ls, aff->v->el + 2);2551 if (!active)2552 goto error;2553 2554 first += isl_local_space_offset(aff->ls, type) - 1;2555 for (i = 0; i < n; ++i)2556 if (active[first + i]) {2557 involves = isl_bool_true;2558 break;2559 }2560 2561 free(active);2562 2563 return involves;2564error:2565 free(active);2566 return isl_bool_error;2567}2568 2569/* Does "aff" involve any local variables, i.e., integer divisions?2570 */2571isl_bool isl_aff_involves_locals(__isl_keep isl_aff *aff)2572{2573 isl_size n;2574 2575 n = isl_aff_dim(aff, isl_dim_div);2576 if (n < 0)2577 return isl_bool_error;2578 return isl_bool_ok(n > 0);2579}2580 2581__isl_give isl_aff *isl_aff_drop_dims(__isl_take isl_aff *aff,2582 enum isl_dim_type type, unsigned first, unsigned n)2583{2584 if (!aff)2585 return NULL;2586 if (type == isl_dim_out)2587 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,2588 "cannot drop output/set dimension",2589 return isl_aff_free(aff));2590 if (type == isl_dim_in)2591 type = isl_dim_set;2592 if (n == 0 && !isl_local_space_is_named_or_nested(aff->ls, type))2593 return aff;2594 2595 if (isl_local_space_check_range(aff->ls, type, first, n) < 0)2596 return isl_aff_free(aff);2597 2598 aff = isl_aff_cow(aff);2599 if (!aff)2600 return NULL;2601 2602 aff->ls = isl_local_space_drop_dims(aff->ls, type, first, n);2603 if (!aff->ls)2604 return isl_aff_free(aff);2605 2606 first += 1 + isl_local_space_offset(aff->ls, type);2607 aff->v = isl_vec_drop_els(aff->v, first, n);2608 if (!aff->v)2609 return isl_aff_free(aff);2610 2611 return aff;2612}2613 2614/* Is the domain of "aff" a product?2615 */2616static isl_bool isl_aff_domain_is_product(__isl_keep isl_aff *aff)2617{2618 return isl_space_is_product(isl_aff_peek_domain_space(aff));2619}2620 2621#undef TYPE2622#define TYPE isl_aff2623#include <isl_domain_factor_templ.c>2624 2625/* Project the domain of the affine expression onto its parameter space.2626 * The affine expression may not involve any of the domain dimensions.2627 */2628__isl_give isl_aff *isl_aff_project_domain_on_params(__isl_take isl_aff *aff)2629{2630 isl_space *space;2631 isl_size n;2632 2633 n = isl_aff_dim(aff, isl_dim_in);2634 if (n < 0)2635 return isl_aff_free(aff);2636 aff = isl_aff_drop_domain(aff, 0, n);2637 space = isl_aff_get_domain_space(aff);2638 space = isl_space_params(space);2639 aff = isl_aff_reset_domain_space(aff, space);2640 return aff;2641}2642 2643/* Convert an affine expression defined over a parameter domain2644 * into one that is defined over a zero-dimensional set.2645 */2646__isl_give isl_aff *isl_aff_from_range(__isl_take isl_aff *aff)2647{2648 isl_local_space *ls;2649 2650 ls = isl_aff_take_domain_local_space(aff);2651 ls = isl_local_space_set_from_params(ls);2652 aff = isl_aff_restore_domain_local_space(aff, ls);2653 2654 return aff;2655}2656 2657__isl_give isl_aff *isl_aff_insert_dims(__isl_take isl_aff *aff,2658 enum isl_dim_type type, unsigned first, unsigned n)2659{2660 if (!aff)2661 return NULL;2662 if (type == isl_dim_out)2663 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,2664 "cannot insert output/set dimensions",2665 return isl_aff_free(aff));2666 if (type == isl_dim_in)2667 type = isl_dim_set;2668 if (n == 0 && !isl_local_space_is_named_or_nested(aff->ls, type))2669 return aff;2670 2671 if (isl_local_space_check_range(aff->ls, type, first, 0) < 0)2672 return isl_aff_free(aff);2673 2674 aff = isl_aff_cow(aff);2675 if (!aff)2676 return NULL;2677 2678 aff->ls = isl_local_space_insert_dims(aff->ls, type, first, n);2679 if (!aff->ls)2680 return isl_aff_free(aff);2681 2682 first += 1 + isl_local_space_offset(aff->ls, type);2683 aff->v = isl_vec_insert_zero_els(aff->v, first, n);2684 if (!aff->v)2685 return isl_aff_free(aff);2686 2687 return aff;2688}2689 2690__isl_give isl_aff *isl_aff_add_dims(__isl_take isl_aff *aff,2691 enum isl_dim_type type, unsigned n)2692{2693 isl_size pos;2694 2695 pos = isl_aff_dim(aff, type);2696 if (pos < 0)2697 return isl_aff_free(aff);2698 2699 return isl_aff_insert_dims(aff, type, pos, n);2700}2701 2702/* Move the "n" dimensions of "src_type" starting at "src_pos" of "aff"2703 * to dimensions of "dst_type" at "dst_pos".2704 *2705 * We only support moving input dimensions to parameters and vice versa.2706 */2707__isl_give isl_aff *isl_aff_move_dims(__isl_take isl_aff *aff,2708 enum isl_dim_type dst_type, unsigned dst_pos,2709 enum isl_dim_type src_type, unsigned src_pos, unsigned n)2710{2711 unsigned g_dst_pos;2712 unsigned g_src_pos;2713 isl_size src_off, dst_off;2714 2715 if (!aff)2716 return NULL;2717 if (n == 0 &&2718 !isl_local_space_is_named_or_nested(aff->ls, src_type) &&2719 !isl_local_space_is_named_or_nested(aff->ls, dst_type))2720 return aff;2721 2722 if (dst_type == isl_dim_out || src_type == isl_dim_out)2723 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,2724 "cannot move output/set dimension",2725 return isl_aff_free(aff));2726 if (dst_type == isl_dim_div || src_type == isl_dim_div)2727 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,2728 "cannot move divs", return isl_aff_free(aff));2729 if (dst_type == isl_dim_in)2730 dst_type = isl_dim_set;2731 if (src_type == isl_dim_in)2732 src_type = isl_dim_set;2733 2734 if (isl_local_space_check_range(aff->ls, src_type, src_pos, n) < 0)2735 return isl_aff_free(aff);2736 if (dst_type == src_type)2737 isl_die(isl_aff_get_ctx(aff), isl_error_unsupported,2738 "moving dims within the same type not supported",2739 return isl_aff_free(aff));2740 2741 aff = isl_aff_cow(aff);2742 src_off = isl_aff_domain_offset(aff, src_type);2743 dst_off = isl_aff_domain_offset(aff, dst_type);2744 if (src_off < 0 || dst_off < 0)2745 return isl_aff_free(aff);2746 2747 g_src_pos = 1 + src_off + src_pos;2748 g_dst_pos = 1 + dst_off + dst_pos;2749 if (dst_type > src_type)2750 g_dst_pos -= n;2751 2752 aff->v = isl_vec_move_els(aff->v, g_dst_pos, g_src_pos, n);2753 aff->ls = isl_local_space_move_dims(aff->ls, dst_type, dst_pos,2754 src_type, src_pos, n);2755 if (!aff->v || !aff->ls)2756 return isl_aff_free(aff);2757 2758 aff = sort_divs(aff);2759 2760 return aff;2761}2762 2763/* Return a zero isl_aff in the given space.2764 *2765 * This is a helper function for isl_pw_*_as_* that ensures a uniform2766 * interface over all piecewise types.2767 */2768static __isl_give isl_aff *isl_aff_zero_in_space(__isl_take isl_space *space)2769{2770 isl_local_space *ls;2771 2772 ls = isl_local_space_from_space(isl_space_domain(space));2773 return isl_aff_zero_on_domain(ls);2774}2775 2776#define isl_aff_involves_nan isl_aff_is_nan2777 2778#undef PW2779#define PW isl_pw_aff2780#undef BASE2781#define BASE aff2782#undef EL_IS_ZERO2783#define EL_IS_ZERO is_empty2784#undef ZERO2785#define ZERO empty2786#undef IS_ZERO2787#define IS_ZERO is_empty2788#undef FIELD2789#define FIELD aff2790#undef DEFAULT_IS_ZERO2791#define DEFAULT_IS_ZERO 02792 2793#include <isl_pw_templ.c>2794#include <isl_pw_un_op_templ.c>2795#include <isl_pw_add_constant_val_templ.c>2796#include <isl_pw_add_disjoint_templ.c>2797#include <isl_pw_bind_domain_templ.c>2798#include <isl_pw_eval.c>2799#include <isl_pw_hash.c>2800#include <isl_pw_fix_templ.c>2801#include <isl_pw_from_range_templ.c>2802#include <isl_pw_insert_dims_templ.c>2803#include <isl_pw_insert_domain_templ.c>2804#include <isl_pw_move_dims_templ.c>2805#include <isl_pw_neg_templ.c>2806#include <isl_pw_pullback_templ.c>2807#include <isl_pw_scale_templ.c>2808#include <isl_pw_sub_templ.c>2809#include <isl_pw_union_opt.c>2810 2811#undef BASE2812#define BASE pw_aff2813 2814#include <isl_union_single.c>2815#include <isl_union_neg.c>2816#include <isl_union_sub_templ.c>2817 2818#undef BASE2819#define BASE aff2820 2821#include <isl_union_pw_templ.c>2822 2823/* Compute a piecewise quasi-affine expression with a domain that2824 * is the union of those of pwaff1 and pwaff2 and such that on each2825 * cell, the quasi-affine expression is the maximum of those of pwaff12826 * and pwaff2. If only one of pwaff1 or pwaff2 is defined on a given2827 * cell, then the associated expression is the defined one.2828 */2829__isl_give isl_pw_aff *isl_pw_aff_union_max(__isl_take isl_pw_aff *pwaff1,2830 __isl_take isl_pw_aff *pwaff2)2831{2832 isl_pw_aff_align_params_bin(&pwaff1, &pwaff2);2833 return isl_pw_aff_union_opt_cmp(pwaff1, pwaff2, &isl_aff_ge_set);2834}2835 2836/* Compute a piecewise quasi-affine expression with a domain that2837 * is the union of those of pwaff1 and pwaff2 and such that on each2838 * cell, the quasi-affine expression is the minimum of those of pwaff12839 * and pwaff2. If only one of pwaff1 or pwaff2 is defined on a given2840 * cell, then the associated expression is the defined one.2841 */2842__isl_give isl_pw_aff *isl_pw_aff_union_min(__isl_take isl_pw_aff *pwaff1,2843 __isl_take isl_pw_aff *pwaff2)2844{2845 isl_pw_aff_align_params_bin(&pwaff1, &pwaff2);2846 return isl_pw_aff_union_opt_cmp(pwaff1, pwaff2, &isl_aff_le_set);2847}2848 2849__isl_give isl_pw_aff *isl_pw_aff_union_opt(__isl_take isl_pw_aff *pwaff1,2850 __isl_take isl_pw_aff *pwaff2, int max)2851{2852 if (max)2853 return isl_pw_aff_union_max(pwaff1, pwaff2);2854 else2855 return isl_pw_aff_union_min(pwaff1, pwaff2);2856}2857 2858/* Is the domain of "pa" a product?2859 */2860static isl_bool isl_pw_aff_domain_is_product(__isl_keep isl_pw_aff *pa)2861{2862 return isl_space_domain_is_wrapping(isl_pw_aff_peek_space(pa));2863}2864 2865#undef TYPE2866#define TYPE isl_pw_aff2867#include <isl_domain_factor_templ.c>2868 2869/* Return a set containing those elements in the domain2870 * of "pwaff" where it satisfies "fn" (if complement is 0) or2871 * does not satisfy "fn" (if complement is 1).2872 *2873 * The pieces with a NaN never belong to the result since2874 * NaN does not satisfy any property.2875 */2876static __isl_give isl_set *pw_aff_locus(__isl_take isl_pw_aff *pwaff,2877 __isl_give isl_basic_set *(*fn)(__isl_take isl_aff *aff, int rational,2878 void *user),2879 int complement, void *user)2880{2881 int i;2882 isl_set *set;2883 2884 if (!pwaff)2885 return NULL;2886 2887 set = isl_set_empty(isl_pw_aff_get_domain_space(pwaff));2888 2889 for (i = 0; i < pwaff->n; ++i) {2890 isl_basic_set *bset;2891 isl_set *set_i, *locus;2892 isl_bool rational;2893 2894 if (isl_aff_is_nan(pwaff->p[i].aff))2895 continue;2896 2897 rational = isl_set_has_rational(pwaff->p[i].set);2898 bset = fn(isl_aff_copy(pwaff->p[i].aff), rational, user);2899 locus = isl_set_from_basic_set(bset);2900 set_i = isl_set_copy(pwaff->p[i].set);2901 if (complement)2902 set_i = isl_set_subtract(set_i, locus);2903 else2904 set_i = isl_set_intersect(set_i, locus);2905 set = isl_set_union_disjoint(set, set_i);2906 }2907 2908 isl_pw_aff_free(pwaff);2909 2910 return set;2911}2912 2913/* Return a set containing those elements in the domain2914 * of "pa" where it is positive.2915 */2916__isl_give isl_set *isl_pw_aff_pos_set(__isl_take isl_pw_aff *pa)2917{2918 return pw_aff_locus(pa, &aff_pos_basic_set, 0, NULL);2919}2920 2921/* Return a set containing those elements in the domain2922 * of pwaff where it is non-negative.2923 */2924__isl_give isl_set *isl_pw_aff_nonneg_set(__isl_take isl_pw_aff *pwaff)2925{2926 return pw_aff_locus(pwaff, &aff_nonneg_basic_set, 0, NULL);2927}2928 2929/* Return a set containing those elements in the domain2930 * of pwaff where it is zero.2931 */2932__isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff)2933{2934 return pw_aff_locus(pwaff, &aff_zero_basic_set, 0, NULL);2935}2936 2937/* Return a set containing those elements in the domain2938 * of pwaff where it is not zero.2939 */2940__isl_give isl_set *isl_pw_aff_non_zero_set(__isl_take isl_pw_aff *pwaff)2941{2942 return pw_aff_locus(pwaff, &aff_zero_basic_set, 1, NULL);2943}2944 2945/* Bind the affine function "aff" to the parameter "id",2946 * returning the elements in the domain where the affine expression2947 * is equal to the parameter.2948 */2949__isl_give isl_basic_set *isl_aff_bind_id(__isl_take isl_aff *aff,2950 __isl_take isl_id *id)2951{2952 isl_space *space;2953 isl_aff *aff_id;2954 2955 space = isl_aff_get_domain_space(aff);2956 space = isl_space_add_param_id(space, isl_id_copy(id));2957 2958 aff = isl_aff_align_params(aff, isl_space_copy(space));2959 aff_id = isl_aff_param_on_domain_space_id(space, id);2960 2961 return isl_aff_eq_basic_set(aff, aff_id);2962}2963 2964/* Wrapper around isl_aff_bind_id for use as pw_aff_locus callback.2965 * "rational" should not be set.2966 */2967static __isl_give isl_basic_set *aff_bind_id(__isl_take isl_aff *aff,2968 int rational, void *user)2969{2970 isl_id *id = user;2971 2972 if (!aff)2973 return NULL;2974 if (rational)2975 isl_die(isl_aff_get_ctx(aff), isl_error_unsupported,2976 "rational binding not supported", goto error);2977 return isl_aff_bind_id(aff, isl_id_copy(id));2978error:2979 isl_aff_free(aff);2980 return NULL;2981}2982 2983/* Bind the piecewise affine function "pa" to the parameter "id",2984 * returning the elements in the domain where the expression2985 * is equal to the parameter.2986 */2987__isl_give isl_set *isl_pw_aff_bind_id(__isl_take isl_pw_aff *pa,2988 __isl_take isl_id *id)2989{2990 isl_set *bound;2991 2992 bound = pw_aff_locus(pa, &aff_bind_id, 0, id);2993 isl_id_free(id);2994 2995 return bound;2996}2997 2998/* Return a set containing those elements in the shared domain2999 * of pwaff1 and pwaff2 where pwaff1 is greater than (or equal) to pwaff2.3000 *3001 * We compute the difference on the shared domain and then construct3002 * the set of values where this difference is non-negative.3003 * If strict is set, we first subtract 1 from the difference.3004 * If equal is set, we only return the elements where pwaff1 and pwaff23005 * are equal.3006 */3007static __isl_give isl_set *pw_aff_gte_set(__isl_take isl_pw_aff *pwaff1,3008 __isl_take isl_pw_aff *pwaff2, int strict, int equal)3009{3010 isl_set *set1, *set2;3011 3012 set1 = isl_pw_aff_domain(isl_pw_aff_copy(pwaff1));3013 set2 = isl_pw_aff_domain(isl_pw_aff_copy(pwaff2));3014 set1 = isl_set_intersect(set1, set2);3015 pwaff1 = isl_pw_aff_intersect_domain(pwaff1, isl_set_copy(set1));3016 pwaff2 = isl_pw_aff_intersect_domain(pwaff2, isl_set_copy(set1));3017 pwaff1 = isl_pw_aff_add(pwaff1, isl_pw_aff_neg(pwaff2));3018 3019 if (strict) {3020 isl_space *space = isl_set_get_space(set1);3021 isl_aff *aff;3022 aff = isl_aff_zero_on_domain(isl_local_space_from_space(space));3023 aff = isl_aff_add_constant_si(aff, -1);3024 pwaff1 = isl_pw_aff_add(pwaff1, isl_pw_aff_alloc(set1, aff));3025 } else3026 isl_set_free(set1);3027 3028 if (equal)3029 return isl_pw_aff_zero_set(pwaff1);3030 return isl_pw_aff_nonneg_set(pwaff1);3031}3032 3033/* Return a set containing those elements in the shared domain3034 * of pwaff1 and pwaff2 where pwaff1 is equal to pwaff2.3035 */3036__isl_give isl_set *isl_pw_aff_eq_set(__isl_take isl_pw_aff *pwaff1,3037 __isl_take isl_pw_aff *pwaff2)3038{3039 isl_pw_aff_align_params_bin(&pwaff1, &pwaff2);3040 return pw_aff_gte_set(pwaff1, pwaff2, 0, 1);3041}3042 3043/* Return a set containing those elements in the shared domain3044 * of pwaff1 and pwaff2 where pwaff1 is greater than or equal to pwaff2.3045 */3046__isl_give isl_set *isl_pw_aff_ge_set(__isl_take isl_pw_aff *pwaff1,3047 __isl_take isl_pw_aff *pwaff2)3048{3049 isl_pw_aff_align_params_bin(&pwaff1, &pwaff2);3050 return pw_aff_gte_set(pwaff1, pwaff2, 0, 0);3051}3052 3053/* Return a set containing those elements in the shared domain3054 * of pwaff1 and pwaff2 where pwaff1 is strictly greater than pwaff2.3055 */3056__isl_give isl_set *isl_pw_aff_gt_set(__isl_take isl_pw_aff *pwaff1,3057 __isl_take isl_pw_aff *pwaff2)3058{3059 isl_pw_aff_align_params_bin(&pwaff1, &pwaff2);3060 return pw_aff_gte_set(pwaff1, pwaff2, 1, 0);3061}3062 3063__isl_give isl_set *isl_pw_aff_le_set(__isl_take isl_pw_aff *pwaff1,3064 __isl_take isl_pw_aff *pwaff2)3065{3066 return isl_pw_aff_ge_set(pwaff2, pwaff1);3067}3068 3069__isl_give isl_set *isl_pw_aff_lt_set(__isl_take isl_pw_aff *pwaff1,3070 __isl_take isl_pw_aff *pwaff2)3071{3072 return isl_pw_aff_gt_set(pwaff2, pwaff1);3073}3074 3075/* Return a map containing pairs of elements in the domains of "pa1" and "pa2"3076 * where the function values are ordered in the same way as "order",3077 * which returns a set in the shared domain of its two arguments.3078 *3079 * Let "pa1" and "pa2" be defined on domains A and B respectively.3080 * We first pull back the two functions such that they are defined on3081 * the domain [A -> B]. Then we apply "order", resulting in a set3082 * in the space [A -> B]. Finally, we unwrap this set to obtain3083 * a map in the space A -> B.3084 */3085static __isl_give isl_map *isl_pw_aff_order_map(3086 __isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2,3087 __isl_give isl_set *(*order)(__isl_take isl_pw_aff *pa1,3088 __isl_take isl_pw_aff *pa2))3089{3090 isl_space *space1, *space2;3091 isl_multi_aff *ma;3092 isl_set *set;3093 3094 isl_pw_aff_align_params_bin(&pa1, &pa2);3095 space1 = isl_space_domain(isl_pw_aff_get_space(pa1));3096 space2 = isl_space_domain(isl_pw_aff_get_space(pa2));3097 space1 = isl_space_map_from_domain_and_range(space1, space2);3098 ma = isl_multi_aff_domain_map(isl_space_copy(space1));3099 pa1 = isl_pw_aff_pullback_multi_aff(pa1, ma);3100 ma = isl_multi_aff_range_map(space1);3101 pa2 = isl_pw_aff_pullback_multi_aff(pa2, ma);3102 set = order(pa1, pa2);3103 3104 return isl_set_unwrap(set);3105}3106 3107/* Return a map containing pairs of elements in the domains of "pa1" and "pa2"3108 * where the function values are equal.3109 */3110__isl_give isl_map *isl_pw_aff_eq_map(__isl_take isl_pw_aff *pa1,3111 __isl_take isl_pw_aff *pa2)3112{3113 return isl_pw_aff_order_map(pa1, pa2, &isl_pw_aff_eq_set);3114}3115 3116/* Return a map containing pairs of elements in the domains of "pa1" and "pa2"3117 * where the function value of "pa1" is less than or equal to3118 * the function value of "pa2".3119 */3120__isl_give isl_map *isl_pw_aff_le_map(__isl_take isl_pw_aff *pa1,3121 __isl_take isl_pw_aff *pa2)3122{3123 return isl_pw_aff_order_map(pa1, pa2, &isl_pw_aff_le_set);3124}3125 3126/* Return a map containing pairs of elements in the domains of "pa1" and "pa2"3127 * where the function value of "pa1" is less than the function value of "pa2".3128 */3129__isl_give isl_map *isl_pw_aff_lt_map(__isl_take isl_pw_aff *pa1,3130 __isl_take isl_pw_aff *pa2)3131{3132 return isl_pw_aff_order_map(pa1, pa2, &isl_pw_aff_lt_set);3133}3134 3135/* Return a map containing pairs of elements in the domains of "pa1" and "pa2"3136 * where the function value of "pa1" is greater than or equal to3137 * the function value of "pa2".3138 */3139__isl_give isl_map *isl_pw_aff_ge_map(__isl_take isl_pw_aff *pa1,3140 __isl_take isl_pw_aff *pa2)3141{3142 return isl_pw_aff_order_map(pa1, pa2, &isl_pw_aff_ge_set);3143}3144 3145/* Return a map containing pairs of elements in the domains of "pa1" and "pa2"3146 * where the function value of "pa1" is greater than the function value3147 * of "pa2".3148 */3149__isl_give isl_map *isl_pw_aff_gt_map(__isl_take isl_pw_aff *pa1,3150 __isl_take isl_pw_aff *pa2)3151{3152 return isl_pw_aff_order_map(pa1, pa2, &isl_pw_aff_gt_set);3153}3154 3155/* Return a set containing those elements in the shared domain3156 * of the elements of list1 and list2 where each element in list13157 * has the relation specified by "fn" with each element in list2.3158 */3159static __isl_give isl_set *pw_aff_list_set(__isl_take isl_pw_aff_list *list1,3160 __isl_take isl_pw_aff_list *list2,3161 __isl_give isl_set *(*fn)(__isl_take isl_pw_aff *pwaff1,3162 __isl_take isl_pw_aff *pwaff2))3163{3164 int i, j;3165 isl_ctx *ctx;3166 isl_set *set;3167 3168 if (!list1 || !list2)3169 goto error;3170 3171 ctx = isl_pw_aff_list_get_ctx(list1);3172 if (list1->n < 1 || list2->n < 1)3173 isl_die(ctx, isl_error_invalid,3174 "list should contain at least one element", goto error);3175 3176 set = isl_set_universe(isl_pw_aff_get_domain_space(list1->p[0]));3177 for (i = 0; i < list1->n; ++i)3178 for (j = 0; j < list2->n; ++j) {3179 isl_set *set_ij;3180 3181 set_ij = fn(isl_pw_aff_copy(list1->p[i]),3182 isl_pw_aff_copy(list2->p[j]));3183 set = isl_set_intersect(set, set_ij);3184 }3185 3186 isl_pw_aff_list_free(list1);3187 isl_pw_aff_list_free(list2);3188 return set;3189error:3190 isl_pw_aff_list_free(list1);3191 isl_pw_aff_list_free(list2);3192 return NULL;3193}3194 3195/* Return a set containing those elements in the shared domain3196 * of the elements of list1 and list2 where each element in list13197 * is equal to each element in list2.3198 */3199__isl_give isl_set *isl_pw_aff_list_eq_set(__isl_take isl_pw_aff_list *list1,3200 __isl_take isl_pw_aff_list *list2)3201{3202 return pw_aff_list_set(list1, list2, &isl_pw_aff_eq_set);3203}3204 3205__isl_give isl_set *isl_pw_aff_list_ne_set(__isl_take isl_pw_aff_list *list1,3206 __isl_take isl_pw_aff_list *list2)3207{3208 return pw_aff_list_set(list1, list2, &isl_pw_aff_ne_set);3209}3210 3211/* Return a set containing those elements in the shared domain3212 * of the elements of list1 and list2 where each element in list13213 * is less than or equal to each element in list2.3214 */3215__isl_give isl_set *isl_pw_aff_list_le_set(__isl_take isl_pw_aff_list *list1,3216 __isl_take isl_pw_aff_list *list2)3217{3218 return pw_aff_list_set(list1, list2, &isl_pw_aff_le_set);3219}3220 3221__isl_give isl_set *isl_pw_aff_list_lt_set(__isl_take isl_pw_aff_list *list1,3222 __isl_take isl_pw_aff_list *list2)3223{3224 return pw_aff_list_set(list1, list2, &isl_pw_aff_lt_set);3225}3226 3227__isl_give isl_set *isl_pw_aff_list_ge_set(__isl_take isl_pw_aff_list *list1,3228 __isl_take isl_pw_aff_list *list2)3229{3230 return pw_aff_list_set(list1, list2, &isl_pw_aff_ge_set);3231}3232 3233__isl_give isl_set *isl_pw_aff_list_gt_set(__isl_take isl_pw_aff_list *list1,3234 __isl_take isl_pw_aff_list *list2)3235{3236 return pw_aff_list_set(list1, list2, &isl_pw_aff_gt_set);3237}3238 3239 3240/* Return a set containing those elements in the shared domain3241 * of pwaff1 and pwaff2 where pwaff1 is not equal to pwaff2.3242 */3243__isl_give isl_set *isl_pw_aff_ne_set(__isl_take isl_pw_aff *pwaff1,3244 __isl_take isl_pw_aff *pwaff2)3245{3246 isl_set *set_lt, *set_gt;3247 3248 isl_pw_aff_align_params_bin(&pwaff1, &pwaff2);3249 set_lt = isl_pw_aff_lt_set(isl_pw_aff_copy(pwaff1),3250 isl_pw_aff_copy(pwaff2));3251 set_gt = isl_pw_aff_gt_set(pwaff1, pwaff2);3252 return isl_set_union_disjoint(set_lt, set_gt);3253}3254 3255__isl_give isl_pw_aff *isl_pw_aff_scale_down(__isl_take isl_pw_aff *pwaff,3256 isl_int v)3257{3258 int i;3259 3260 if (isl_int_is_one(v))3261 return pwaff;3262 if (!isl_int_is_pos(v))3263 isl_die(isl_pw_aff_get_ctx(pwaff), isl_error_invalid,3264 "factor needs to be positive",3265 return isl_pw_aff_free(pwaff));3266 pwaff = isl_pw_aff_cow(pwaff);3267 if (!pwaff)3268 return NULL;3269 if (pwaff->n == 0)3270 return pwaff;3271 3272 for (i = 0; i < pwaff->n; ++i) {3273 pwaff->p[i].aff = isl_aff_scale_down(pwaff->p[i].aff, v);3274 if (!pwaff->p[i].aff)3275 return isl_pw_aff_free(pwaff);3276 }3277 3278 return pwaff;3279}3280 3281__isl_give isl_pw_aff *isl_pw_aff_floor(__isl_take isl_pw_aff *pwaff)3282{3283 return isl_pw_aff_un_op(pwaff, &isl_aff_floor);3284}3285 3286__isl_give isl_pw_aff *isl_pw_aff_ceil(__isl_take isl_pw_aff *pwaff)3287{3288 return isl_pw_aff_un_op(pwaff, &isl_aff_ceil);3289}3290 3291/* Assuming that "cond1" and "cond2" are disjoint,3292 * return an affine expression that is equal to pwaff1 on cond13293 * and to pwaff2 on cond2.3294 */3295static __isl_give isl_pw_aff *isl_pw_aff_select(3296 __isl_take isl_set *cond1, __isl_take isl_pw_aff *pwaff1,3297 __isl_take isl_set *cond2, __isl_take isl_pw_aff *pwaff2)3298{3299 pwaff1 = isl_pw_aff_intersect_domain(pwaff1, cond1);3300 pwaff2 = isl_pw_aff_intersect_domain(pwaff2, cond2);3301 3302 return isl_pw_aff_add_disjoint(pwaff1, pwaff2);3303}3304 3305/* Return an affine expression that is equal to pwaff_true for elements3306 * where "cond" is non-zero and to pwaff_false for elements where "cond"3307 * is zero.3308 * That is, return cond ? pwaff_true : pwaff_false;3309 *3310 * If "cond" involves and NaN, then we conservatively return a NaN3311 * on its entire domain. In principle, we could consider the pieces3312 * where it is NaN separately from those where it is not.3313 *3314 * If "pwaff_true" and "pwaff_false" are obviously equal to each other,3315 * then only use the domain of "cond" to restrict the domain.3316 */3317__isl_give isl_pw_aff *isl_pw_aff_cond(__isl_take isl_pw_aff *cond,3318 __isl_take isl_pw_aff *pwaff_true, __isl_take isl_pw_aff *pwaff_false)3319{3320 isl_set *cond_true, *cond_false;3321 isl_bool equal;3322 3323 if (!cond)3324 goto error;3325 if (isl_pw_aff_involves_nan(cond)) {3326 isl_space *space = isl_pw_aff_get_domain_space(cond);3327 isl_local_space *ls = isl_local_space_from_space(space);3328 isl_pw_aff_free(cond);3329 isl_pw_aff_free(pwaff_true);3330 isl_pw_aff_free(pwaff_false);3331 return isl_pw_aff_nan_on_domain(ls);3332 }3333 3334 pwaff_true = isl_pw_aff_align_params(pwaff_true,3335 isl_pw_aff_get_space(pwaff_false));3336 pwaff_false = isl_pw_aff_align_params(pwaff_false,3337 isl_pw_aff_get_space(pwaff_true));3338 equal = isl_pw_aff_plain_is_equal(pwaff_true, pwaff_false);3339 if (equal < 0)3340 goto error;3341 if (equal) {3342 isl_set *dom;3343 3344 dom = isl_set_coalesce(isl_pw_aff_domain(cond));3345 isl_pw_aff_free(pwaff_false);3346 return isl_pw_aff_intersect_domain(pwaff_true, dom);3347 }3348 3349 cond_true = isl_pw_aff_non_zero_set(isl_pw_aff_copy(cond));3350 cond_false = isl_pw_aff_zero_set(cond);3351 return isl_pw_aff_select(cond_true, pwaff_true,3352 cond_false, pwaff_false);3353error:3354 isl_pw_aff_free(cond);3355 isl_pw_aff_free(pwaff_true);3356 isl_pw_aff_free(pwaff_false);3357 return NULL;3358}3359 3360isl_bool isl_aff_is_cst(__isl_keep isl_aff *aff)3361{3362 int pos;3363 3364 if (!aff)3365 return isl_bool_error;3366 3367 pos = isl_seq_first_non_zero(aff->v->el + 2, aff->v->size - 2);3368 return isl_bool_ok(pos == -1);3369}3370 3371/* Check whether pwaff is a piecewise constant.3372 */3373isl_bool isl_pw_aff_is_cst(__isl_keep isl_pw_aff *pwaff)3374{3375 int i;3376 3377 if (!pwaff)3378 return isl_bool_error;3379 3380 for (i = 0; i < pwaff->n; ++i) {3381 isl_bool is_cst = isl_aff_is_cst(pwaff->p[i].aff);3382 if (is_cst < 0 || !is_cst)3383 return is_cst;3384 }3385 3386 return isl_bool_true;3387}3388 3389/* Return the product of "aff1" and "aff2".3390 *3391 * If either of the two is NaN, then the result is NaN.3392 *3393 * Otherwise, at least one of "aff1" or "aff2" needs to be a constant.3394 */3395__isl_give isl_aff *isl_aff_mul(__isl_take isl_aff *aff1,3396 __isl_take isl_aff *aff2)3397{3398 if (!aff1 || !aff2)3399 goto error;3400 3401 if (isl_aff_is_nan(aff1)) {3402 isl_aff_free(aff2);3403 return aff1;3404 }3405 if (isl_aff_is_nan(aff2)) {3406 isl_aff_free(aff1);3407 return aff2;3408 }3409 3410 if (!isl_aff_is_cst(aff2) && isl_aff_is_cst(aff1))3411 return isl_aff_mul(aff2, aff1);3412 3413 if (!isl_aff_is_cst(aff2))3414 isl_die(isl_aff_get_ctx(aff1), isl_error_invalid,3415 "at least one affine expression should be constant",3416 goto error);3417 3418 aff1 = isl_aff_cow(aff1);3419 if (!aff1 || !aff2)3420 goto error;3421 3422 aff1 = isl_aff_scale(aff1, aff2->v->el[1]);3423 aff1 = isl_aff_scale_down(aff1, aff2->v->el[0]);3424 3425 isl_aff_free(aff2);3426 return aff1;3427error:3428 isl_aff_free(aff1);3429 isl_aff_free(aff2);3430 return NULL;3431}3432 3433/* Divide "aff1" by "aff2", assuming "aff2" is a constant.3434 *3435 * If either of the two is NaN, then the result is NaN.3436 * A division by zero also results in NaN.3437 */3438__isl_give isl_aff *isl_aff_div(__isl_take isl_aff *aff1,3439 __isl_take isl_aff *aff2)3440{3441 isl_bool is_cst, is_zero;3442 int neg;3443 3444 if (!aff1 || !aff2)3445 goto error;3446 3447 if (isl_aff_is_nan(aff1)) {3448 isl_aff_free(aff2);3449 return aff1;3450 }3451 if (isl_aff_is_nan(aff2)) {3452 isl_aff_free(aff1);3453 return aff2;3454 }3455 3456 is_cst = isl_aff_is_cst(aff2);3457 if (is_cst < 0)3458 goto error;3459 if (!is_cst)3460 isl_die(isl_aff_get_ctx(aff2), isl_error_invalid,3461 "second argument should be a constant", goto error);3462 is_zero = isl_aff_plain_is_zero(aff2);3463 if (is_zero < 0)3464 goto error;3465 if (is_zero)3466 return set_nan_free(aff1, aff2);3467 3468 neg = isl_int_is_neg(aff2->v->el[1]);3469 if (neg) {3470 isl_int_neg(aff2->v->el[0], aff2->v->el[0]);3471 isl_int_neg(aff2->v->el[1], aff2->v->el[1]);3472 }3473 3474 aff1 = isl_aff_scale(aff1, aff2->v->el[0]);3475 aff1 = isl_aff_scale_down(aff1, aff2->v->el[1]);3476 3477 if (neg) {3478 isl_int_neg(aff2->v->el[0], aff2->v->el[0]);3479 isl_int_neg(aff2->v->el[1], aff2->v->el[1]);3480 }3481 3482 isl_aff_free(aff2);3483 return aff1;3484error:3485 isl_aff_free(aff1);3486 isl_aff_free(aff2);3487 return NULL;3488}3489 3490__isl_give isl_pw_aff *isl_pw_aff_add(__isl_take isl_pw_aff *pwaff1,3491 __isl_take isl_pw_aff *pwaff2)3492{3493 isl_pw_aff_align_params_bin(&pwaff1, &pwaff2);3494 return isl_pw_aff_on_shared_domain(pwaff1, pwaff2, &isl_aff_add);3495}3496 3497__isl_give isl_pw_aff *isl_pw_aff_mul(__isl_take isl_pw_aff *pwaff1,3498 __isl_take isl_pw_aff *pwaff2)3499{3500 isl_pw_aff_align_params_bin(&pwaff1, &pwaff2);3501 return isl_pw_aff_on_shared_domain(pwaff1, pwaff2, &isl_aff_mul);3502}3503 3504/* Divide "pa1" by "pa2", assuming "pa2" is a piecewise constant.3505 */3506__isl_give isl_pw_aff *isl_pw_aff_div(__isl_take isl_pw_aff *pa1,3507 __isl_take isl_pw_aff *pa2)3508{3509 int is_cst;3510 3511 is_cst = isl_pw_aff_is_cst(pa2);3512 if (is_cst < 0)3513 goto error;3514 if (!is_cst)3515 isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid,3516 "second argument should be a piecewise constant",3517 goto error);3518 isl_pw_aff_align_params_bin(&pa1, &pa2);3519 return isl_pw_aff_on_shared_domain(pa1, pa2, &isl_aff_div);3520error:3521 isl_pw_aff_free(pa1);3522 isl_pw_aff_free(pa2);3523 return NULL;3524}3525 3526/* Compute the quotient of the integer division of "pa1" by "pa2"3527 * with rounding towards zero.3528 * "pa2" is assumed to be a piecewise constant.3529 *3530 * In particular, return3531 *3532 * pa1 >= 0 ? floor(pa1/pa2) : ceil(pa1/pa2)3533 *3534 */3535__isl_give isl_pw_aff *isl_pw_aff_tdiv_q(__isl_take isl_pw_aff *pa1,3536 __isl_take isl_pw_aff *pa2)3537{3538 int is_cst;3539 isl_set *cond;3540 isl_pw_aff *f, *c;3541 3542 is_cst = isl_pw_aff_is_cst(pa2);3543 if (is_cst < 0)3544 goto error;3545 if (!is_cst)3546 isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid,3547 "second argument should be a piecewise constant",3548 goto error);3549 3550 pa1 = isl_pw_aff_div(pa1, pa2);3551 3552 cond = isl_pw_aff_nonneg_set(isl_pw_aff_copy(pa1));3553 f = isl_pw_aff_floor(isl_pw_aff_copy(pa1));3554 c = isl_pw_aff_ceil(pa1);3555 return isl_pw_aff_cond(isl_set_indicator_function(cond), f, c);3556error:3557 isl_pw_aff_free(pa1);3558 isl_pw_aff_free(pa2);3559 return NULL;3560}3561 3562/* Compute the remainder of the integer division of "pa1" by "pa2"3563 * with rounding towards zero.3564 * "pa2" is assumed to be a piecewise constant.3565 *3566 * In particular, return3567 *3568 * pa1 - pa2 * (pa1 >= 0 ? floor(pa1/pa2) : ceil(pa1/pa2))3569 *3570 */3571__isl_give isl_pw_aff *isl_pw_aff_tdiv_r(__isl_take isl_pw_aff *pa1,3572 __isl_take isl_pw_aff *pa2)3573{3574 int is_cst;3575 isl_pw_aff *res;3576 3577 is_cst = isl_pw_aff_is_cst(pa2);3578 if (is_cst < 0)3579 goto error;3580 if (!is_cst)3581 isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid,3582 "second argument should be a piecewise constant",3583 goto error);3584 res = isl_pw_aff_tdiv_q(isl_pw_aff_copy(pa1), isl_pw_aff_copy(pa2));3585 res = isl_pw_aff_mul(pa2, res);3586 res = isl_pw_aff_sub(pa1, res);3587 return res;3588error:3589 isl_pw_aff_free(pa1);3590 isl_pw_aff_free(pa2);3591 return NULL;3592}3593 3594/* Does either of "pa1" or "pa2" involve any NaN?3595 */3596static isl_bool either_involves_nan(__isl_keep isl_pw_aff *pa1,3597 __isl_keep isl_pw_aff *pa2)3598{3599 isl_bool has_nan;3600 3601 has_nan = isl_pw_aff_involves_nan(pa1);3602 if (has_nan < 0 || has_nan)3603 return has_nan;3604 return isl_pw_aff_involves_nan(pa2);3605}3606 3607/* Return a piecewise affine expression defined on the specified domain3608 * that represents NaN.3609 */3610static __isl_give isl_pw_aff *nan_on_domain_set(__isl_take isl_set *dom)3611{3612 isl_local_space *ls;3613 isl_pw_aff *pa;3614 3615 ls = isl_local_space_from_space(isl_set_get_space(dom));3616 pa = isl_pw_aff_nan_on_domain(ls);3617 pa = isl_pw_aff_intersect_domain(pa, dom);3618 3619 return pa;3620}3621 3622/* Replace "pa1" and "pa2" (at least one of which involves a NaN)3623 * by a NaN on their shared domain.3624 *3625 * In principle, the result could be refined to only being NaN3626 * on the parts of this domain where at least one of "pa1" or "pa2" is NaN.3627 */3628static __isl_give isl_pw_aff *replace_by_nan(__isl_take isl_pw_aff *pa1,3629 __isl_take isl_pw_aff *pa2)3630{3631 isl_set *dom;3632 3633 dom = isl_set_intersect(isl_pw_aff_domain(pa1), isl_pw_aff_domain(pa2));3634 return nan_on_domain_set(dom);3635}3636 3637static __isl_give isl_pw_aff *pw_aff_min(__isl_take isl_pw_aff *pwaff1,3638 __isl_take isl_pw_aff *pwaff2)3639{3640 isl_set *le;3641 isl_set *dom;3642 3643 dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)),3644 isl_pw_aff_domain(isl_pw_aff_copy(pwaff2)));3645 le = isl_pw_aff_le_set(isl_pw_aff_copy(pwaff1),3646 isl_pw_aff_copy(pwaff2));3647 dom = isl_set_subtract(dom, isl_set_copy(le));3648 return isl_pw_aff_select(le, pwaff1, dom, pwaff2);3649}3650 3651static __isl_give isl_pw_aff *pw_aff_max(__isl_take isl_pw_aff *pwaff1,3652 __isl_take isl_pw_aff *pwaff2)3653{3654 isl_set *ge;3655 isl_set *dom;3656 3657 dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)),3658 isl_pw_aff_domain(isl_pw_aff_copy(pwaff2)));3659 ge = isl_pw_aff_ge_set(isl_pw_aff_copy(pwaff1),3660 isl_pw_aff_copy(pwaff2));3661 dom = isl_set_subtract(dom, isl_set_copy(ge));3662 return isl_pw_aff_select(ge, pwaff1, dom, pwaff2);3663}3664 3665/* Return an expression for the minimum (if "max" is not set) or3666 * the maximum (if "max" is set) of "pa1" and "pa2".3667 * If either expression involves any NaN, then return a NaN3668 * on the shared domain as result.3669 */3670static __isl_give isl_pw_aff *pw_aff_min_max(__isl_take isl_pw_aff *pa1,3671 __isl_take isl_pw_aff *pa2, int max)3672{3673 isl_bool has_nan;3674 3675 has_nan = either_involves_nan(pa1, pa2);3676 if (has_nan < 0)3677 pa1 = isl_pw_aff_free(pa1);3678 else if (has_nan)3679 return replace_by_nan(pa1, pa2);3680 3681 isl_pw_aff_align_params_bin(&pa1, &pa2);3682 if (max)3683 return pw_aff_max(pa1, pa2);3684 else3685 return pw_aff_min(pa1, pa2);3686}3687 3688/* Return an expression for the minimum of "pwaff1" and "pwaff2".3689 */3690__isl_give isl_pw_aff *isl_pw_aff_min(__isl_take isl_pw_aff *pwaff1,3691 __isl_take isl_pw_aff *pwaff2)3692{3693 return pw_aff_min_max(pwaff1, pwaff2, 0);3694}3695 3696/* Return an expression for the maximum of "pwaff1" and "pwaff2".3697 */3698__isl_give isl_pw_aff *isl_pw_aff_max(__isl_take isl_pw_aff *pwaff1,3699 __isl_take isl_pw_aff *pwaff2)3700{3701 return pw_aff_min_max(pwaff1, pwaff2, 1);3702}3703 3704/* Does "pa" not involve any NaN?3705 */3706static isl_bool pw_aff_no_nan(__isl_keep isl_pw_aff *pa, void *user)3707{3708 return isl_bool_not(isl_pw_aff_involves_nan(pa));3709}3710 3711/* Does any element of "list" involve any NaN?3712 *3713 * That is, is it not the case that every element does not involve any NaN?3714 */3715static isl_bool isl_pw_aff_list_involves_nan(__isl_keep isl_pw_aff_list *list)3716{3717 return isl_bool_not(isl_pw_aff_list_every(list, &pw_aff_no_nan, NULL));3718}3719 3720/* Replace "list" (consisting of "n" elements, of which3721 * at least one element involves a NaN)3722 * by a NaN on the shared domain of the elements.3723 *3724 * In principle, the result could be refined to only being NaN3725 * on the parts of this domain where at least one of the elements is NaN.3726 */3727static __isl_give isl_pw_aff *replace_list_by_nan(3728 __isl_take isl_pw_aff_list *list, int n)3729{3730 int i;3731 isl_set *dom;3732 3733 dom = isl_pw_aff_domain(isl_pw_aff_list_get_at(list, 0));3734 for (i = 1; i < n; ++i) {3735 isl_set *dom_i;3736 3737 dom_i = isl_pw_aff_domain(isl_pw_aff_list_get_at(list, i));3738 dom = isl_set_intersect(dom, dom_i);3739 }3740 3741 isl_pw_aff_list_free(list);3742 return nan_on_domain_set(dom);3743}3744 3745/* Return the set where the element at "pos1" of "list" is less than or3746 * equal to the element at "pos2".3747 * Equality is only allowed if "pos1" is smaller than "pos2".3748 */3749static __isl_give isl_set *less(__isl_keep isl_pw_aff_list *list,3750 int pos1, int pos2)3751{3752 isl_pw_aff *pa1, *pa2;3753 3754 pa1 = isl_pw_aff_list_get_at(list, pos1);3755 pa2 = isl_pw_aff_list_get_at(list, pos2);3756 3757 if (pos1 < pos2)3758 return isl_pw_aff_le_set(pa1, pa2);3759 else3760 return isl_pw_aff_lt_set(pa1, pa2);3761}3762 3763/* Return an isl_pw_aff that maps each element in the intersection of the3764 * domains of the piecewise affine expressions in "list"3765 * to the maximal (if "max" is set) or minimal (if "max" is not set)3766 * expression in "list" at that element.3767 * If any expression involves any NaN, then return a NaN3768 * on the shared domain as result.3769 *3770 * If "list" has n elements, then the result consists of n pieces,3771 * where, in the case of a minimum, each piece has as value expression3772 * the value expression of one of the elements and as domain3773 * the set of elements where that value expression3774 * is less than (or equal) to the other value expressions.3775 * In the case of a maximum, the condition is3776 * that all the other value expressions are less than (or equal)3777 * to the given value expression.3778 *3779 * In order to produce disjoint pieces, a pair of elements3780 * in the original domain is only allowed to be equal to each other3781 * on exactly one of the two pieces corresponding to the two elements.3782 * The position in the list is used to break ties.3783 * In particular, in the case of a minimum,3784 * in the piece corresponding to a given element,3785 * this element is allowed to be equal to any later element in the list,3786 * but not to any earlier element in the list.3787 */3788static __isl_give isl_pw_aff *isl_pw_aff_list_opt(3789 __isl_take isl_pw_aff_list *list, int max)3790{3791 int i, j;3792 isl_bool has_nan;3793 isl_size n;3794 isl_space *space;3795 isl_pw_aff *pa, *res;3796 3797 n = isl_pw_aff_list_size(list);3798 if (n < 0)3799 goto error;3800 if (n < 1)3801 isl_die(isl_pw_aff_list_get_ctx(list), isl_error_invalid,3802 "list should contain at least one element", goto error);3803 3804 has_nan = isl_pw_aff_list_involves_nan(list);3805 if (has_nan < 0)3806 goto error;3807 if (has_nan)3808 return replace_list_by_nan(list, n);3809 3810 pa = isl_pw_aff_list_get_at(list, 0);3811 space = isl_pw_aff_get_space(pa);3812 isl_pw_aff_free(pa);3813 res = isl_pw_aff_empty(space);3814 3815 for (i = 0; i < n; ++i) {3816 pa = isl_pw_aff_list_get_at(list, i);3817 for (j = 0; j < n; ++j) {3818 isl_set *dom;3819 3820 if (j == i)3821 continue;3822 if (max)3823 dom = less(list, j, i);3824 else3825 dom = less(list, i, j);3826 3827 pa = isl_pw_aff_intersect_domain(pa, dom);3828 }3829 res = isl_pw_aff_add_disjoint(res, pa);3830 }3831 3832 isl_pw_aff_list_free(list);3833 return res;3834error:3835 isl_pw_aff_list_free(list);3836 return NULL;3837}3838 3839/* Return an isl_pw_aff that maps each element in the intersection of the3840 * domains of the elements of list to the minimal corresponding affine3841 * expression.3842 */3843__isl_give isl_pw_aff *isl_pw_aff_list_min(__isl_take isl_pw_aff_list *list)3844{3845 return isl_pw_aff_list_opt(list, 0);3846}3847 3848/* Return an isl_pw_aff that maps each element in the intersection of the3849 * domains of the elements of list to the maximal corresponding affine3850 * expression.3851 */3852__isl_give isl_pw_aff *isl_pw_aff_list_max(__isl_take isl_pw_aff_list *list)3853{3854 return isl_pw_aff_list_opt(list, 1);3855}3856 3857/* Mark the domains of "pwaff" as rational.3858 */3859__isl_give isl_pw_aff *isl_pw_aff_set_rational(__isl_take isl_pw_aff *pwaff)3860{3861 int i;3862 3863 pwaff = isl_pw_aff_cow(pwaff);3864 if (!pwaff)3865 return NULL;3866 if (pwaff->n == 0)3867 return pwaff;3868 3869 for (i = 0; i < pwaff->n; ++i) {3870 pwaff->p[i].set = isl_set_set_rational(pwaff->p[i].set);3871 if (!pwaff->p[i].set)3872 return isl_pw_aff_free(pwaff);3873 }3874 3875 return pwaff;3876}3877 3878/* Mark the domains of the elements of "list" as rational.3879 */3880__isl_give isl_pw_aff_list *isl_pw_aff_list_set_rational(3881 __isl_take isl_pw_aff_list *list)3882{3883 int i, n;3884 3885 if (!list)3886 return NULL;3887 if (list->n == 0)3888 return list;3889 3890 n = list->n;3891 for (i = 0; i < n; ++i) {3892 isl_pw_aff *pa;3893 3894 pa = isl_pw_aff_list_get_pw_aff(list, i);3895 pa = isl_pw_aff_set_rational(pa);3896 list = isl_pw_aff_list_set_pw_aff(list, i, pa);3897 }3898 3899 return list;3900}3901 3902/* Do the parameters of "aff" match those of "space"?3903 */3904isl_bool isl_aff_matching_params(__isl_keep isl_aff *aff,3905 __isl_keep isl_space *space)3906{3907 isl_space *aff_space;3908 isl_bool match;3909 3910 if (!aff || !space)3911 return isl_bool_error;3912 3913 aff_space = isl_aff_get_domain_space(aff);3914 3915 match = isl_space_has_equal_params(space, aff_space);3916 3917 isl_space_free(aff_space);3918 return match;3919}3920 3921/* Check that the domain space of "aff" matches "space".3922 */3923isl_stat isl_aff_check_match_domain_space(__isl_keep isl_aff *aff,3924 __isl_keep isl_space *space)3925{3926 isl_space *aff_space;3927 isl_bool match;3928 3929 if (!aff || !space)3930 return isl_stat_error;3931 3932 aff_space = isl_aff_get_domain_space(aff);3933 3934 match = isl_space_has_equal_params(space, aff_space);3935 if (match < 0)3936 goto error;3937 if (!match)3938 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,3939 "parameters don't match", goto error);3940 match = isl_space_tuple_is_equal(space, isl_dim_in,3941 aff_space, isl_dim_set);3942 if (match < 0)3943 goto error;3944 if (!match)3945 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,3946 "domains don't match", goto error);3947 isl_space_free(aff_space);3948 return isl_stat_ok;3949error:3950 isl_space_free(aff_space);3951 return isl_stat_error;3952}3953 3954/* Return the shared (universe) domain of the elements of "ma".3955 *3956 * Since an isl_multi_aff (and an isl_aff) is always total,3957 * the domain is always the universe set in its domain space.3958 * This is a helper function for use in the generic isl_multi_*_bind.3959 */3960static __isl_give isl_basic_set *isl_multi_aff_domain(3961 __isl_take isl_multi_aff *ma)3962{3963 isl_space *space;3964 3965 space = isl_multi_aff_get_space(ma);3966 isl_multi_aff_free(ma);3967 3968 return isl_basic_set_universe(isl_space_domain(space));3969}3970 3971#undef BASE3972#define BASE aff3973 3974#include <isl_multi_no_explicit_domain.c>3975#include <isl_multi_templ.c>3976#include <isl_multi_un_op_templ.c>3977#include <isl_multi_bin_val_templ.c>3978#include <isl_multi_add_constant_templ.c>3979#include <isl_multi_apply_set.c>3980#include <isl_multi_arith_templ.c>3981#include <isl_multi_bind_domain_templ.c>3982#include <isl_multi_cmp.c>3983#include <isl_multi_dim_id_templ.c>3984#include <isl_multi_dims.c>3985#include <isl_multi_floor.c>3986#include <isl_multi_from_base_templ.c>3987#include <isl_multi_identity_templ.c>3988#include <isl_multi_insert_domain_templ.c>3989#include <isl_multi_locals_templ.c>3990#include <isl_multi_move_dims_templ.c>3991#include <isl_multi_nan_templ.c>3992#include <isl_multi_product_templ.c>3993#include <isl_multi_splice_templ.c>3994#include <isl_multi_tuple_id_templ.c>3995#include <isl_multi_unbind_params_templ.c>3996#include <isl_multi_zero_templ.c>3997 3998#undef DOMBASE3999#define DOMBASE set4000#include <isl_multi_gist.c>4001 4002#undef DOMBASE4003#define DOMBASE basic_set4004#include <isl_multi_bind_templ.c>4005 4006/* Construct an isl_multi_aff living in "space" that corresponds4007 * to the affine transformation matrix "mat".4008 */4009__isl_give isl_multi_aff *isl_multi_aff_from_aff_mat(4010 __isl_take isl_space *space, __isl_take isl_mat *mat)4011{4012 isl_ctx *ctx;4013 isl_local_space *ls = NULL;4014 isl_multi_aff *ma = NULL;4015 isl_size n_row, n_col, n_out, total;4016 int i;4017 4018 if (!space || !mat)4019 goto error;4020 4021 ctx = isl_mat_get_ctx(mat);4022 4023 n_row = isl_mat_rows(mat);4024 n_col = isl_mat_cols(mat);4025 n_out = isl_space_dim(space, isl_dim_out);4026 total = isl_space_dim(space, isl_dim_all);4027 if (n_row < 0 || n_col < 0 || n_out < 0 || total < 0)4028 goto error;4029 if (n_row < 1)4030 isl_die(ctx, isl_error_invalid,4031 "insufficient number of rows", goto error);4032 if (n_col < 1)4033 isl_die(ctx, isl_error_invalid,4034 "insufficient number of columns", goto error);4035 if (1 + n_out != n_row || 2 + total != n_row + n_col)4036 isl_die(ctx, isl_error_invalid,4037 "dimension mismatch", goto error);4038 4039 ma = isl_multi_aff_zero(isl_space_copy(space));4040 space = isl_space_domain(space);4041 ls = isl_local_space_from_space(isl_space_copy(space));4042 4043 for (i = 0; i < n_row - 1; ++i) {4044 isl_vec *v;4045 isl_aff *aff;4046 4047 v = isl_vec_alloc(ctx, 1 + n_col);4048 if (!v)4049 goto error;4050 isl_int_set(v->el[0], mat->row[0][0]);4051 isl_seq_cpy(v->el + 1, mat->row[1 + i], n_col);4052 v = isl_vec_normalize(v);4053 aff = isl_aff_alloc_vec_validated(isl_local_space_copy(ls), v);4054 ma = isl_multi_aff_set_aff(ma, i, aff);4055 }4056 4057 isl_space_free(space);4058 isl_local_space_free(ls);4059 isl_mat_free(mat);4060 return ma;4061error:4062 isl_space_free(space);4063 isl_local_space_free(ls);4064 isl_mat_free(mat);4065 isl_multi_aff_free(ma);4066 return NULL;4067}4068 4069/* Return the constant terms of the affine expressions of "ma".4070 */4071__isl_give isl_multi_val *isl_multi_aff_get_constant_multi_val(4072 __isl_keep isl_multi_aff *ma)4073{4074 int i;4075 isl_size n;4076 isl_space *space;4077 isl_multi_val *mv;4078 4079 n = isl_multi_aff_size(ma);4080 if (n < 0)4081 return NULL;4082 space = isl_space_range(isl_multi_aff_get_space(ma));4083 space = isl_space_drop_all_params(space);4084 mv = isl_multi_val_zero(space);4085 4086 for (i = 0; i < n; ++i) {4087 isl_aff *aff;4088 isl_val *val;4089 4090 aff = isl_multi_aff_get_at(ma, i);4091 val = isl_aff_get_constant_val(aff);4092 isl_aff_free(aff);4093 mv = isl_multi_val_set_at(mv, i, val);4094 }4095 4096 return mv;4097}4098 4099/* Remove any internal structure of the domain of "ma".4100 * If there is any such internal structure in the input,4101 * then the name of the corresponding space is also removed.4102 */4103__isl_give isl_multi_aff *isl_multi_aff_flatten_domain(4104 __isl_take isl_multi_aff *ma)4105{4106 isl_space *space;4107 4108 if (!ma)4109 return NULL;4110 4111 if (!ma->space->nested[0])4112 return ma;4113 4114 space = isl_multi_aff_get_space(ma);4115 space = isl_space_flatten_domain(space);4116 ma = isl_multi_aff_reset_space(ma, space);4117 4118 return ma;4119}4120 4121/* Given a map space, return an isl_multi_aff that maps a wrapped copy4122 * of the space to its domain.4123 */4124__isl_give isl_multi_aff *isl_multi_aff_domain_map(__isl_take isl_space *space)4125{4126 int i;4127 isl_size n_in;4128 isl_local_space *ls;4129 isl_multi_aff *ma;4130 4131 if (!space)4132 return NULL;4133 if (!isl_space_is_map(space))4134 isl_die(isl_space_get_ctx(space), isl_error_invalid,4135 "not a map space", goto error);4136 4137 n_in = isl_space_dim(space, isl_dim_in);4138 if (n_in < 0)4139 goto error;4140 space = isl_space_domain_map(space);4141 4142 ma = isl_multi_aff_alloc(isl_space_copy(space));4143 if (n_in == 0) {4144 isl_space_free(space);4145 return ma;4146 }4147 4148 space = isl_space_domain(space);4149 ls = isl_local_space_from_space(space);4150 for (i = 0; i < n_in; ++i) {4151 isl_aff *aff;4152 4153 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),4154 isl_dim_set, i);4155 ma = isl_multi_aff_set_aff(ma, i, aff);4156 }4157 isl_local_space_free(ls);4158 return ma;4159error:4160 isl_space_free(space);4161 return NULL;4162}4163 4164/* This function performs the same operation as isl_multi_aff_domain_map,4165 * but is considered as a function on an isl_space when exported.4166 */4167__isl_give isl_multi_aff *isl_space_domain_map_multi_aff(4168 __isl_take isl_space *space)4169{4170 return isl_multi_aff_domain_map(space);4171}4172 4173/* Given a map space, return an isl_multi_aff that maps a wrapped copy4174 * of the space to its range.4175 */4176__isl_give isl_multi_aff *isl_multi_aff_range_map(__isl_take isl_space *space)4177{4178 int i;4179 isl_size n_in, n_out;4180 isl_local_space *ls;4181 isl_multi_aff *ma;4182 4183 if (!space)4184 return NULL;4185 if (!isl_space_is_map(space))4186 isl_die(isl_space_get_ctx(space), isl_error_invalid,4187 "not a map space", goto error);4188 4189 n_in = isl_space_dim(space, isl_dim_in);4190 n_out = isl_space_dim(space, isl_dim_out);4191 if (n_in < 0 || n_out < 0)4192 goto error;4193 space = isl_space_range_map(space);4194 4195 ma = isl_multi_aff_alloc(isl_space_copy(space));4196 if (n_out == 0) {4197 isl_space_free(space);4198 return ma;4199 }4200 4201 space = isl_space_domain(space);4202 ls = isl_local_space_from_space(space);4203 for (i = 0; i < n_out; ++i) {4204 isl_aff *aff;4205 4206 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),4207 isl_dim_set, n_in + i);4208 ma = isl_multi_aff_set_aff(ma, i, aff);4209 }4210 isl_local_space_free(ls);4211 return ma;4212error:4213 isl_space_free(space);4214 return NULL;4215}4216 4217/* This function performs the same operation as isl_multi_aff_range_map,4218 * but is considered as a function on an isl_space when exported.4219 */4220__isl_give isl_multi_aff *isl_space_range_map_multi_aff(4221 __isl_take isl_space *space)4222{4223 return isl_multi_aff_range_map(space);4224}4225 4226/* Given a map space, return an isl_pw_multi_aff that maps a wrapped copy4227 * of the space to its domain.4228 */4229__isl_give isl_pw_multi_aff *isl_pw_multi_aff_domain_map(4230 __isl_take isl_space *space)4231{4232 return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_domain_map(space));4233}4234 4235/* This function performs the same operation as isl_pw_multi_aff_domain_map,4236 * but is considered as a function on an isl_space when exported.4237 */4238__isl_give isl_pw_multi_aff *isl_space_domain_map_pw_multi_aff(4239 __isl_take isl_space *space)4240{4241 return isl_pw_multi_aff_domain_map(space);4242}4243 4244/* Given a map space, return an isl_pw_multi_aff that maps a wrapped copy4245 * of the space to its range.4246 */4247__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_map(4248 __isl_take isl_space *space)4249{4250 return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_range_map(space));4251}4252 4253/* This function performs the same operation as isl_pw_multi_aff_range_map,4254 * but is considered as a function on an isl_space when exported.4255 */4256__isl_give isl_pw_multi_aff *isl_space_range_map_pw_multi_aff(4257 __isl_take isl_space *space)4258{4259 return isl_pw_multi_aff_range_map(space);4260}4261 4262/* Given the space of a set and a range of set dimensions,4263 * construct an isl_multi_aff that projects out those dimensions.4264 */4265__isl_give isl_multi_aff *isl_multi_aff_project_out_map(4266 __isl_take isl_space *space, enum isl_dim_type type,4267 unsigned first, unsigned n)4268{4269 int i;4270 isl_size dim;4271 isl_local_space *ls;4272 isl_multi_aff *ma;4273 4274 if (!space)4275 return NULL;4276 if (!isl_space_is_set(space))4277 isl_die(isl_space_get_ctx(space), isl_error_unsupported,4278 "expecting set space", goto error);4279 if (type != isl_dim_set)4280 isl_die(isl_space_get_ctx(space), isl_error_invalid,4281 "only set dimensions can be projected out", goto error);4282 if (isl_space_check_range(space, type, first, n) < 0)4283 goto error;4284 4285 dim = isl_space_dim(space, isl_dim_set);4286 if (dim < 0)4287 goto error;4288 4289 space = isl_space_from_domain(space);4290 space = isl_space_add_dims(space, isl_dim_out, dim - n);4291 4292 if (dim == n)4293 return isl_multi_aff_alloc(space);4294 4295 ma = isl_multi_aff_alloc(isl_space_copy(space));4296 space = isl_space_domain(space);4297 ls = isl_local_space_from_space(space);4298 4299 for (i = 0; i < first; ++i) {4300 isl_aff *aff;4301 4302 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),4303 isl_dim_set, i);4304 ma = isl_multi_aff_set_aff(ma, i, aff);4305 }4306 4307 for (i = 0; i < dim - (first + n); ++i) {4308 isl_aff *aff;4309 4310 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),4311 isl_dim_set, first + n + i);4312 ma = isl_multi_aff_set_aff(ma, first + i, aff);4313 }4314 4315 isl_local_space_free(ls);4316 return ma;4317error:4318 isl_space_free(space);4319 return NULL;4320}4321 4322/* Given the space of a set and a range of set dimensions,4323 * construct an isl_pw_multi_aff that projects out those dimensions.4324 */4325__isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_out_map(4326 __isl_take isl_space *space, enum isl_dim_type type,4327 unsigned first, unsigned n)4328{4329 isl_multi_aff *ma;4330 4331 ma = isl_multi_aff_project_out_map(space, type, first, n);4332 return isl_pw_multi_aff_from_multi_aff(ma);4333}4334 4335/* This function performs the same operation as isl_pw_multi_aff_from_multi_aff,4336 * but is considered as a function on an isl_multi_aff when exported.4337 */4338__isl_give isl_pw_multi_aff *isl_multi_aff_to_pw_multi_aff(4339 __isl_take isl_multi_aff *ma)4340{4341 return isl_pw_multi_aff_from_multi_aff(ma);4342}4343 4344/* Create a piecewise multi-affine expression in the given space that maps each4345 * input dimension to the corresponding output dimension.4346 */4347__isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity(4348 __isl_take isl_space *space)4349{4350 return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_identity(space));4351}4352 4353/* Create a piecewise multi expression that maps elements in the given space4354 * to themselves.4355 */4356__isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity_on_domain_space(4357 __isl_take isl_space *space)4358{4359 isl_multi_aff *ma;4360 4361 ma = isl_multi_aff_identity_on_domain_space(space);4362 return isl_pw_multi_aff_from_multi_aff(ma);4363}4364 4365/* This function performs the same operation as4366 * isl_pw_multi_aff_identity_on_domain_space,4367 * but is considered as a function on an isl_space when exported.4368 */4369__isl_give isl_pw_multi_aff *isl_space_identity_pw_multi_aff_on_domain(4370 __isl_take isl_space *space)4371{4372 return isl_pw_multi_aff_identity_on_domain_space(space);4373}4374 4375/* Exploit the equalities in "eq" to simplify the affine expressions.4376 */4377static __isl_give isl_multi_aff *isl_multi_aff_substitute_equalities(4378 __isl_take isl_multi_aff *maff, __isl_take isl_basic_set *eq)4379{4380 isl_size n;4381 int i;4382 4383 n = isl_multi_aff_size(maff);4384 if (n < 0 || !eq)4385 goto error;4386 4387 for (i = 0; i < n; ++i) {4388 isl_aff *aff;4389 4390 aff = isl_multi_aff_take_at(maff, i);4391 aff = isl_aff_substitute_equalities(aff,4392 isl_basic_set_copy(eq));4393 maff = isl_multi_aff_restore_at(maff, i, aff);4394 }4395 4396 isl_basic_set_free(eq);4397 return maff;4398error:4399 isl_basic_set_free(eq);4400 isl_multi_aff_free(maff);4401 return NULL;4402}4403 4404__isl_give isl_multi_aff *isl_multi_aff_scale(__isl_take isl_multi_aff *maff,4405 isl_int f)4406{4407 isl_size n;4408 int i;4409 4410 n = isl_multi_aff_size(maff);4411 if (n < 0)4412 return isl_multi_aff_free(maff);4413 4414 for (i = 0; i < n; ++i) {4415 isl_aff *aff;4416 4417 aff = isl_multi_aff_take_at(maff, i);4418 aff = isl_aff_scale(aff, f);4419 maff = isl_multi_aff_restore_at(maff, i, aff);4420 }4421 4422 return maff;4423}4424 4425__isl_give isl_multi_aff *isl_multi_aff_add_on_domain(__isl_keep isl_set *dom,4426 __isl_take isl_multi_aff *maff1, __isl_take isl_multi_aff *maff2)4427{4428 maff1 = isl_multi_aff_add(maff1, maff2);4429 maff1 = isl_multi_aff_gist(maff1, isl_set_copy(dom));4430 return maff1;4431}4432 4433isl_bool isl_multi_aff_is_empty(__isl_keep isl_multi_aff *maff)4434{4435 if (!maff)4436 return isl_bool_error;4437 4438 return isl_bool_false;4439}4440 4441/* Return the set of domain elements where "ma1" is lexicographically4442 * smaller than or equal to "ma2".4443 */4444__isl_give isl_set *isl_multi_aff_lex_le_set(__isl_take isl_multi_aff *ma1,4445 __isl_take isl_multi_aff *ma2)4446{4447 return isl_multi_aff_lex_ge_set(ma2, ma1);4448}4449 4450/* Return the set of domain elements where "ma1" is lexicographically4451 * smaller than "ma2".4452 */4453__isl_give isl_set *isl_multi_aff_lex_lt_set(__isl_take isl_multi_aff *ma1,4454 __isl_take isl_multi_aff *ma2)4455{4456 return isl_multi_aff_lex_gt_set(ma2, ma1);4457}4458 4459/* Return the set of domain elements where "ma1" is lexicographically4460 * greater than to "ma2". If "equal" is set, then include the domain4461 * elements where they are equal.4462 * Do this for the case where there are no entries.4463 * In this case, "ma1" cannot be greater than "ma2",4464 * but it is (greater than or) equal to "ma2".4465 */4466static __isl_give isl_set *isl_multi_aff_lex_gte_set_0d(4467 __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2, int equal)4468{4469 isl_space *space;4470 4471 space = isl_multi_aff_get_domain_space(ma1);4472 4473 isl_multi_aff_free(ma1);4474 isl_multi_aff_free(ma2);4475 4476 if (equal)4477 return isl_set_universe(space);4478 else4479 return isl_set_empty(space);4480}4481 4482/* Return the set where entry "i" of "ma1" and "ma2"4483 * satisfy the relation prescribed by "cmp".4484 */4485static __isl_give isl_set *isl_multi_aff_order_at(__isl_keep isl_multi_aff *ma1,4486 __isl_keep isl_multi_aff *ma2, int i,4487 __isl_give isl_set *(*cmp)(__isl_take isl_aff *aff1,4488 __isl_take isl_aff *aff2))4489{4490 isl_aff *aff1, *aff2;4491 4492 aff1 = isl_multi_aff_get_at(ma1, i);4493 aff2 = isl_multi_aff_get_at(ma2, i);4494 return cmp(aff1, aff2);4495}4496 4497/* Return the set of domain elements where "ma1" is lexicographically4498 * greater than to "ma2". If "equal" is set, then include the domain4499 * elements where they are equal.4500 *4501 * In particular, for all but the final entry,4502 * include the set of elements where this entry is strictly greater in "ma1"4503 * and all previous entries are equal.4504 * The final entry is also allowed to be equal in the two functions4505 * if "equal" is set.4506 *4507 * The case where there are no entries is handled separately.4508 */4509static __isl_give isl_set *isl_multi_aff_lex_gte_set(4510 __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2, int equal)4511{4512 int i;4513 isl_size n;4514 isl_space *space;4515 isl_set *res;4516 isl_set *equal_set;4517 isl_set *gte;4518 4519 if (isl_multi_aff_check_equal_space(ma1, ma2) < 0)4520 goto error;4521 n = isl_multi_aff_size(ma1);4522 if (n < 0)4523 goto error;4524 if (n == 0)4525 return isl_multi_aff_lex_gte_set_0d(ma1, ma2, equal);4526 4527 space = isl_multi_aff_get_domain_space(ma1);4528 res = isl_set_empty(isl_space_copy(space));4529 equal_set = isl_set_universe(space);4530 4531 for (i = 0; i + 1 < n; ++i) {4532 isl_bool empty;4533 isl_set *gt, *eq;4534 4535 gt = isl_multi_aff_order_at(ma1, ma2, i, &isl_aff_gt_set);4536 gt = isl_set_intersect(gt, isl_set_copy(equal_set));4537 res = isl_set_union(res, gt);4538 eq = isl_multi_aff_order_at(ma1, ma2, i, &isl_aff_eq_set);4539 equal_set = isl_set_intersect(equal_set, eq);4540 4541 empty = isl_set_is_empty(equal_set);4542 if (empty >= 0 && empty)4543 break;4544 }4545 4546 if (equal)4547 gte = isl_multi_aff_order_at(ma1, ma2, n - 1, &isl_aff_ge_set);4548 else4549 gte = isl_multi_aff_order_at(ma1, ma2, n - 1, &isl_aff_gt_set);4550 isl_multi_aff_free(ma1);4551 isl_multi_aff_free(ma2);4552 4553 gte = isl_set_intersect(gte, equal_set);4554 return isl_set_union(res, gte);4555error:4556 isl_multi_aff_free(ma1);4557 isl_multi_aff_free(ma2);4558 return NULL;4559}4560 4561/* Return the set of domain elements where "ma1" is lexicographically4562 * greater than or equal to "ma2".4563 */4564__isl_give isl_set *isl_multi_aff_lex_ge_set(__isl_take isl_multi_aff *ma1,4565 __isl_take isl_multi_aff *ma2)4566{4567 return isl_multi_aff_lex_gte_set(ma1, ma2, 1);4568}4569 4570/* Return the set of domain elements where "ma1" is lexicographically4571 * greater than "ma2".4572 */4573__isl_give isl_set *isl_multi_aff_lex_gt_set(__isl_take isl_multi_aff *ma1,4574 __isl_take isl_multi_aff *ma2)4575{4576 return isl_multi_aff_lex_gte_set(ma1, ma2, 0);4577}4578 4579#define isl_multi_aff_zero_in_space isl_multi_aff_zero4580 4581#undef PW4582#define PW isl_pw_multi_aff4583#undef BASE4584#define BASE multi_aff4585#undef EL_IS_ZERO4586#define EL_IS_ZERO is_empty4587#undef ZERO4588#define ZERO empty4589#undef IS_ZERO4590#define IS_ZERO is_empty4591#undef FIELD4592#define FIELD maff4593#undef DEFAULT_IS_ZERO4594#define DEFAULT_IS_ZERO 04595 4596#include <isl_pw_templ.c>4597#include <isl_pw_un_op_templ.c>4598#include <isl_pw_add_constant_multi_val_templ.c>4599#include <isl_pw_add_constant_val_templ.c>4600#include <isl_pw_add_disjoint_templ.c>4601#include <isl_pw_bind_domain_templ.c>4602#include <isl_pw_fix_templ.c>4603#include <isl_pw_from_range_templ.c>4604#include <isl_pw_insert_dims_templ.c>4605#include <isl_pw_insert_domain_templ.c>4606#include <isl_pw_locals_templ.c>4607#include <isl_pw_move_dims_templ.c>4608#include <isl_pw_neg_templ.c>4609#include <isl_pw_pullback_templ.c>4610#include <isl_pw_range_tuple_id_templ.c>4611#include <isl_pw_union_opt.c>4612 4613#undef BASE4614#define BASE pw_multi_aff4615 4616#include <isl_union_multi.c>4617#include "isl_union_locals_templ.c"4618#include <isl_union_neg.c>4619#include <isl_union_sub_templ.c>4620 4621#undef BASE4622#define BASE multi_aff4623 4624#include <isl_union_pw_templ.c>4625 4626/* Generic function for extracting a factor from a product "pma".4627 * "check_space" checks that the space is that of the right kind of product.4628 * "space_factor" extracts the factor from the space.4629 * "multi_aff_factor" extracts the factor from the constituent functions.4630 */4631static __isl_give isl_pw_multi_aff *pw_multi_aff_factor(4632 __isl_take isl_pw_multi_aff *pma,4633 isl_stat (*check_space)(__isl_keep isl_pw_multi_aff *pma),4634 __isl_give isl_space *(*space_factor)(__isl_take isl_space *space),4635 __isl_give isl_multi_aff *(*multi_aff_factor)(4636 __isl_take isl_multi_aff *ma))4637{4638 int i;4639 isl_space *space;4640 4641 if (check_space(pma) < 0)4642 return isl_pw_multi_aff_free(pma);4643 4644 space = isl_pw_multi_aff_take_space(pma);4645 space = space_factor(space);4646 4647 for (i = 0; pma && i < pma->n; ++i) {4648 isl_multi_aff *ma;4649 4650 ma = isl_pw_multi_aff_take_base_at(pma, i);4651 ma = multi_aff_factor(ma);4652 pma = isl_pw_multi_aff_restore_base_at(pma, i, ma);4653 }4654 4655 pma = isl_pw_multi_aff_restore_space(pma, space);4656 4657 return pma;4658}4659 4660/* Is the range of "pma" a wrapped relation?4661 */4662static isl_bool isl_pw_multi_aff_range_is_wrapping(4663 __isl_keep isl_pw_multi_aff *pma)4664{4665 return isl_space_range_is_wrapping(isl_pw_multi_aff_peek_space(pma));4666}4667 4668/* Check that the range of "pma" is a product.4669 */4670static isl_stat pw_multi_aff_check_range_product(4671 __isl_keep isl_pw_multi_aff *pma)4672{4673 isl_bool wraps;4674 4675 wraps = isl_pw_multi_aff_range_is_wrapping(pma);4676 if (wraps < 0)4677 return isl_stat_error;4678 if (!wraps)4679 isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,4680 "range is not a product", return isl_stat_error);4681 return isl_stat_ok;4682}4683 4684/* Given a function A -> [B -> C], extract the function A -> B.4685 */4686__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_factor_domain(4687 __isl_take isl_pw_multi_aff *pma)4688{4689 return pw_multi_aff_factor(pma, &pw_multi_aff_check_range_product,4690 &isl_space_range_factor_domain,4691 &isl_multi_aff_range_factor_domain);4692}4693 4694/* Given a function A -> [B -> C], extract the function A -> C.4695 */4696__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_factor_range(4697 __isl_take isl_pw_multi_aff *pma)4698{4699 return pw_multi_aff_factor(pma, &pw_multi_aff_check_range_product,4700 &isl_space_range_factor_range,4701 &isl_multi_aff_range_factor_range);4702}4703 4704/* Given two piecewise multi affine expressions, return a piecewise4705 * multi-affine expression defined on the union of the definition domains4706 * of the inputs that is equal to the lexicographic maximum of the two4707 * inputs on each cell. If only one of the two inputs is defined on4708 * a given cell, then it is considered to be the maximum.4709 */4710__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmax(4711 __isl_take isl_pw_multi_aff *pma1,4712 __isl_take isl_pw_multi_aff *pma2)4713{4714 isl_pw_multi_aff_align_params_bin(&pma1, &pma2);4715 return isl_pw_multi_aff_union_opt_cmp(pma1, pma2,4716 &isl_multi_aff_lex_ge_set);4717}4718 4719/* Given two piecewise multi affine expressions, return a piecewise4720 * multi-affine expression defined on the union of the definition domains4721 * of the inputs that is equal to the lexicographic minimum of the two4722 * inputs on each cell. If only one of the two inputs is defined on4723 * a given cell, then it is considered to be the minimum.4724 */4725__isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmin(4726 __isl_take isl_pw_multi_aff *pma1,4727 __isl_take isl_pw_multi_aff *pma2)4728{4729 isl_pw_multi_aff_align_params_bin(&pma1, &pma2);4730 return isl_pw_multi_aff_union_opt_cmp(pma1, pma2,4731 &isl_multi_aff_lex_le_set);4732}4733 4734__isl_give isl_pw_multi_aff *isl_pw_multi_aff_add(4735 __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)4736{4737 isl_pw_multi_aff_align_params_bin(&pma1, &pma2);4738 return isl_pw_multi_aff_on_shared_domain(pma1, pma2,4739 &isl_multi_aff_add);4740}4741 4742/* Subtract "pma2" from "pma1" and return the result.4743 */4744__isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub(4745 __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)4746{4747 isl_pw_multi_aff_align_params_bin(&pma1, &pma2);4748 return isl_pw_multi_aff_on_shared_domain(pma1, pma2,4749 &isl_multi_aff_sub);4750}4751 4752/* Given two piecewise multi-affine expressions A -> B and C -> D,4753 * construct a piecewise multi-affine expression [A -> C] -> [B -> D].4754 */4755__isl_give isl_pw_multi_aff *isl_pw_multi_aff_product(4756 __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)4757{4758 int i, j, n;4759 isl_space *space;4760 isl_pw_multi_aff *res;4761 4762 if (isl_pw_multi_aff_align_params_bin(&pma1, &pma2) < 0)4763 goto error;4764 4765 n = pma1->n * pma2->n;4766 space = isl_space_product(isl_space_copy(pma1->dim),4767 isl_space_copy(pma2->dim));4768 res = isl_pw_multi_aff_alloc_size(space, n);4769 4770 for (i = 0; i < pma1->n; ++i) {4771 for (j = 0; j < pma2->n; ++j) {4772 isl_set *domain;4773 isl_multi_aff *ma;4774 4775 domain = isl_set_product(isl_set_copy(pma1->p[i].set),4776 isl_set_copy(pma2->p[j].set));4777 ma = isl_multi_aff_product(4778 isl_multi_aff_copy(pma1->p[i].maff),4779 isl_multi_aff_copy(pma2->p[j].maff));4780 res = isl_pw_multi_aff_add_piece(res, domain, ma);4781 }4782 }4783 4784 isl_pw_multi_aff_free(pma1);4785 isl_pw_multi_aff_free(pma2);4786 return res;4787error:4788 isl_pw_multi_aff_free(pma1);4789 isl_pw_multi_aff_free(pma2);4790 return NULL;4791}4792 4793/* Subtract the initial "n" elements in "ma" with coefficients in "c" and4794 * denominator "denom".4795 * "denom" is allowed to be negative, in which case the actual denominator4796 * is -denom and the expressions are added instead.4797 */4798static __isl_give isl_aff *subtract_initial(__isl_take isl_aff *aff,4799 __isl_keep isl_multi_aff *ma, int n, isl_int *c, isl_int denom)4800{4801 int i, first;4802 int sign;4803 isl_int d;4804 4805 first = isl_seq_first_non_zero(c, n);4806 if (first == -1)4807 return aff;4808 4809 sign = isl_int_sgn(denom);4810 isl_int_init(d);4811 isl_int_abs(d, denom);4812 for (i = first; i < n; ++i) {4813 isl_aff *aff_i;4814 4815 if (isl_int_is_zero(c[i]))4816 continue;4817 aff_i = isl_multi_aff_get_aff(ma, i);4818 aff_i = isl_aff_scale(aff_i, c[i]);4819 aff_i = isl_aff_scale_down(aff_i, d);4820 if (sign >= 0)4821 aff = isl_aff_sub(aff, aff_i);4822 else4823 aff = isl_aff_add(aff, aff_i);4824 }4825 isl_int_clear(d);4826 4827 return aff;4828}4829 4830/* Extract an affine expression that expresses the output dimension "pos"4831 * of "bmap" in terms of the parameters and input dimensions from4832 * equality "eq".4833 * Note that this expression may involve integer divisions defined4834 * in terms of parameters and input dimensions.4835 * The equality may also involve references to earlier (but not later)4836 * output dimensions. These are replaced by the corresponding elements4837 * in "ma".4838 *4839 * If the equality is of the form4840 *4841 * f(i) + h(j) + a x + g(i) = 0,4842 *4843 * with f(i) a linear combinations of the parameters and input dimensions,4844 * g(i) a linear combination of integer divisions defined in terms of the same4845 * and h(j) a linear combinations of earlier output dimensions,4846 * then the affine expression is4847 *4848 * (-f(i) - g(i))/a - h(j)/a4849 *4850 * If the equality is of the form4851 *4852 * f(i) + h(j) - a x + g(i) = 0,4853 *4854 * then the affine expression is4855 *4856 * (f(i) + g(i))/a - h(j)/(-a)4857 *4858 *4859 * If "div" refers to an integer division (i.e., it is smaller than4860 * the number of integer divisions), then the equality constraint4861 * does involve an integer division (the one at position "div") that4862 * is defined in terms of output dimensions. However, this integer4863 * division can be eliminated by exploiting a pair of constraints4864 * x >= l and x <= l + n, with n smaller than the coefficient of "div"4865 * in the equality constraint. "ineq" refers to inequality x >= l, i.e.,4866 * -l + x >= 0.4867 * In particular, let4868 *4869 * x = e(i) + m floor(...)4870 *4871 * with e(i) the expression derived above and floor(...) the integer4872 * division involving output dimensions.4873 * From4874 *4875 * l <= x <= l + n,4876 *4877 * we have4878 *4879 * 0 <= x - l <= n4880 *4881 * This means4882 *4883 * e(i) + m floor(...) - l = (e(i) + m floor(...) - l) mod m4884 * = (e(i) - l) mod m4885 *4886 * Therefore,4887 *4888 * x - l = (e(i) - l) mod m4889 *4890 * or4891 *4892 * x = ((e(i) - l) mod m) + l4893 *4894 * The variable "shift" below contains the expression -l, which may4895 * also involve a linear combination of earlier output dimensions.4896 */4897static __isl_give isl_aff *extract_aff_from_equality(4898 __isl_keep isl_basic_map *bmap, int pos, int eq, int div, int ineq,4899 __isl_keep isl_multi_aff *ma)4900{4901 unsigned o_out;4902 isl_size n_div, n_out;4903 isl_ctx *ctx;4904 isl_local_space *ls;4905 isl_aff *aff, *shift;4906 isl_val *mod;4907 4908 ctx = isl_basic_map_get_ctx(bmap);4909 ls = isl_basic_map_get_local_space(bmap);4910 ls = isl_local_space_domain(ls);4911 aff = isl_aff_alloc(isl_local_space_copy(ls));4912 if (!aff)4913 goto error;4914 o_out = isl_basic_map_offset(bmap, isl_dim_out);4915 n_out = isl_basic_map_dim(bmap, isl_dim_out);4916 n_div = isl_basic_map_dim(bmap, isl_dim_div);4917 if (n_out < 0 || n_div < 0)4918 goto error;4919 if (isl_int_is_neg(bmap->eq[eq][o_out + pos])) {4920 isl_seq_cpy(aff->v->el + 1, bmap->eq[eq], o_out);4921 isl_seq_cpy(aff->v->el + 1 + o_out,4922 bmap->eq[eq] + o_out + n_out, n_div);4923 } else {4924 isl_seq_neg(aff->v->el + 1, bmap->eq[eq], o_out);4925 isl_seq_neg(aff->v->el + 1 + o_out,4926 bmap->eq[eq] + o_out + n_out, n_div);4927 }4928 if (div < n_div)4929 isl_int_set_si(aff->v->el[1 + o_out + div], 0);4930 isl_int_abs(aff->v->el[0], bmap->eq[eq][o_out + pos]);4931 aff = subtract_initial(aff, ma, pos, bmap->eq[eq] + o_out,4932 bmap->eq[eq][o_out + pos]);4933 if (div < n_div) {4934 shift = isl_aff_alloc(isl_local_space_copy(ls));4935 if (!shift)4936 goto error;4937 isl_seq_cpy(shift->v->el + 1, bmap->ineq[ineq], o_out);4938 isl_seq_cpy(shift->v->el + 1 + o_out,4939 bmap->ineq[ineq] + o_out + n_out, n_div);4940 isl_int_set_si(shift->v->el[0], 1);4941 shift = subtract_initial(shift, ma, pos,4942 bmap->ineq[ineq] + o_out, ctx->negone);4943 aff = isl_aff_add(aff, isl_aff_copy(shift));4944 mod = isl_val_int_from_isl_int(ctx,4945 bmap->eq[eq][o_out + n_out + div]);4946 mod = isl_val_abs(mod);4947 aff = isl_aff_mod_val(aff, mod);4948 aff = isl_aff_sub(aff, shift);4949 }4950 4951 isl_local_space_free(ls);4952 return aff;4953error:4954 isl_local_space_free(ls);4955 isl_aff_free(aff);4956 return NULL;4957}4958 4959/* Given a basic map with output dimensions defined4960 * in terms of the parameters input dimensions and earlier4961 * output dimensions using an equality (and possibly a pair on inequalities),4962 * extract an isl_aff that expresses output dimension "pos" in terms4963 * of the parameters and input dimensions.4964 * Note that this expression may involve integer divisions defined4965 * in terms of parameters and input dimensions.4966 * "ma" contains the expressions corresponding to earlier output dimensions.4967 *4968 * This function shares some similarities with4969 * isl_basic_map_has_defining_equality and isl_constraint_get_bound.4970 */4971static __isl_give isl_aff *extract_isl_aff_from_basic_map(4972 __isl_keep isl_basic_map *bmap, int pos, __isl_keep isl_multi_aff *ma)4973{4974 int eq, div, ineq;4975 isl_aff *aff;4976 4977 if (!bmap)4978 return NULL;4979 eq = isl_basic_map_output_defining_equality(bmap, pos, &div, &ineq);4980 if (eq >= bmap->n_eq)4981 isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid,4982 "unable to find suitable equality", return NULL);4983 aff = extract_aff_from_equality(bmap, pos, eq, div, ineq, ma);4984 4985 aff = isl_aff_remove_unused_divs(aff);4986 return aff;4987}4988 4989/* Given a basic map where each output dimension is defined4990 * in terms of the parameters and input dimensions using an equality,4991 * extract an isl_multi_aff that expresses the output dimensions in terms4992 * of the parameters and input dimensions.4993 */4994static __isl_give isl_multi_aff *extract_isl_multi_aff_from_basic_map(4995 __isl_take isl_basic_map *bmap)4996{4997 int i;4998 isl_size n_out;4999 isl_multi_aff *ma;5000 5001 if (!bmap)5002 return NULL;5003 5004 ma = isl_multi_aff_alloc(isl_basic_map_get_space(bmap));5005 n_out = isl_basic_map_dim(bmap, isl_dim_out);5006 if (n_out < 0)5007 ma = isl_multi_aff_free(ma);5008 5009 for (i = 0; i < n_out; ++i) {5010 isl_aff *aff;5011 5012 aff = extract_isl_aff_from_basic_map(bmap, i, ma);5013 ma = isl_multi_aff_set_aff(ma, i, aff);5014 }5015 5016 isl_basic_map_free(bmap);5017 5018 return ma;5019}5020 5021/* Given a basic set where each set dimension is defined5022 * in terms of the parameters using an equality,5023 * extract an isl_multi_aff that expresses the set dimensions in terms5024 * of the parameters.5025 */5026__isl_give isl_multi_aff *isl_multi_aff_from_basic_set_equalities(5027 __isl_take isl_basic_set *bset)5028{5029 return extract_isl_multi_aff_from_basic_map(bset);5030}5031 5032/* Create an isl_pw_multi_aff that is equivalent to5033 * isl_map_intersect_domain(isl_map_from_basic_map(bmap), domain).5034 * The given basic map is such that each output dimension is defined5035 * in terms of the parameters and input dimensions using an equality.5036 *5037 * Since some applications expect the result of isl_pw_multi_aff_from_map5038 * to only contain integer affine expressions, we compute the floor5039 * of the expression before returning.5040 *5041 * Remove all constraints involving local variables without5042 * an explicit representation (resulting in the removal of those5043 * local variables) prior to the actual extraction to ensure5044 * that the local spaces in which the resulting affine expressions5045 * are created do not contain any unknown local variables.5046 * Removing such constraints is safe because constraints involving5047 * unknown local variables are not used to determine whether5048 * a basic map is obviously single-valued.5049 */5050static __isl_give isl_pw_multi_aff *plain_pw_multi_aff_from_map(5051 __isl_take isl_set *domain, __isl_take isl_basic_map *bmap)5052{5053 isl_multi_aff *ma;5054 5055 bmap = isl_basic_map_drop_constraints_involving_unknown_divs(bmap);5056 ma = extract_isl_multi_aff_from_basic_map(bmap);5057 ma = isl_multi_aff_floor(ma);5058 return isl_pw_multi_aff_alloc(domain, ma);5059}5060 5061/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map.5062 * This obviously only works if the input "map" is single-valued.5063 * If so, we compute the lexicographic minimum of the image in the form5064 * of an isl_pw_multi_aff. Since the image is unique, it is equal5065 * to its lexicographic minimum.5066 * If the input is not single-valued, we produce an error.5067 */5068static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_base(5069 __isl_take isl_map *map)5070{5071 int i;5072 int sv;5073 isl_pw_multi_aff *pma;5074 5075 sv = isl_map_is_single_valued(map);5076 if (sv < 0)5077 goto error;5078 if (!sv)5079 isl_die(isl_map_get_ctx(map), isl_error_invalid,5080 "map is not single-valued", goto error);5081 map = isl_map_make_disjoint(map);5082 if (!map)5083 return NULL;5084 5085 pma = isl_pw_multi_aff_empty(isl_map_get_space(map));5086 5087 for (i = 0; i < map->n; ++i) {5088 isl_pw_multi_aff *pma_i;5089 isl_basic_map *bmap;5090 bmap = isl_basic_map_copy(map->p[i]);5091 pma_i = isl_basic_map_lexmin_pw_multi_aff(bmap);5092 pma = isl_pw_multi_aff_add_disjoint(pma, pma_i);5093 }5094 5095 isl_map_free(map);5096 return pma;5097error:5098 isl_map_free(map);5099 return NULL;5100}5101 5102/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map,5103 * taking into account that the output dimension at position "d"5104 * can be represented as5105 *5106 * x = floor((e(...) + c1) / m)5107 *5108 * given that constraint "i" is of the form5109 *5110 * e(...) + c1 - m x >= 05111 *5112 *5113 * Let "map" be of the form5114 *5115 * A -> B5116 *5117 * We construct a mapping5118 *5119 * A -> [A -> x = floor(...)]5120 *5121 * apply that to the map, obtaining5122 *5123 * [A -> x = floor(...)] -> B5124 *5125 * and equate dimension "d" to x.5126 * We then compute a isl_pw_multi_aff representation of the resulting map5127 * and plug in the mapping above.5128 */5129static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_div(5130 __isl_take isl_map *map, __isl_take isl_basic_map *hull, int d, int i)5131{5132 isl_ctx *ctx;5133 isl_space *space = NULL;5134 isl_local_space *ls;5135 isl_multi_aff *ma;5136 isl_aff *aff;5137 isl_vec *v;5138 isl_map *insert;5139 int offset;5140 isl_size n;5141 isl_size n_in;5142 isl_pw_multi_aff *pma;5143 isl_bool is_set;5144 5145 is_set = isl_map_is_set(map);5146 if (is_set < 0)5147 goto error;5148 5149 offset = isl_basic_map_offset(hull, isl_dim_out);5150 ctx = isl_map_get_ctx(map);5151 space = isl_space_domain(isl_map_get_space(map));5152 n_in = isl_space_dim(space, isl_dim_set);5153 n = isl_space_dim(space, isl_dim_all);5154 if (n_in < 0 || n < 0)5155 goto error;5156 5157 v = isl_vec_alloc(ctx, 1 + 1 + n);5158 if (v) {5159 isl_int_neg(v->el[0], hull->ineq[i][offset + d]);5160 isl_seq_cpy(v->el + 1, hull->ineq[i], 1 + n);5161 }5162 isl_basic_map_free(hull);5163 5164 ls = isl_local_space_from_space(isl_space_copy(space));5165 aff = isl_aff_alloc_vec_validated(ls, v);5166 aff = isl_aff_floor(aff);5167 if (is_set) {5168 isl_space_free(space);5169 ma = isl_multi_aff_from_aff(aff);5170 } else {5171 ma = isl_multi_aff_identity(isl_space_map_from_set(space));5172 ma = isl_multi_aff_range_product(ma,5173 isl_multi_aff_from_aff(aff));5174 }5175 5176 insert = isl_map_from_multi_aff_internal(isl_multi_aff_copy(ma));5177 map = isl_map_apply_domain(map, insert);5178 map = isl_map_equate(map, isl_dim_in, n_in, isl_dim_out, d);5179 pma = isl_pw_multi_aff_from_map(map);5180 pma = isl_pw_multi_aff_pullback_multi_aff(pma, ma);5181 5182 return pma;5183error:5184 isl_space_free(space);5185 isl_map_free(map);5186 isl_basic_map_free(hull);5187 return NULL;5188}5189 5190/* Is constraint "c" of the form5191 *5192 * e(...) + c1 - m x >= 05193 *5194 * or5195 *5196 * -e(...) + c2 + m x >= 05197 *5198 * where m > 1 and e only depends on parameters and input dimensions?5199 *5200 * "offset" is the offset of the output dimensions5201 * "pos" is the position of output dimension x.5202 */5203static int is_potential_div_constraint(isl_int *c, int offset, int d, int total)5204{5205 if (isl_int_is_zero(c[offset + d]))5206 return 0;5207 if (isl_int_is_one(c[offset + d]))5208 return 0;5209 if (isl_int_is_negone(c[offset + d]))5210 return 0;5211 if (isl_seq_first_non_zero(c + offset, d) != -1)5212 return 0;5213 if (isl_seq_first_non_zero(c + offset + d + 1,5214 total - (offset + d + 1)) != -1)5215 return 0;5216 return 1;5217}5218 5219/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map.5220 *5221 * As a special case, we first check if there is any pair of constraints,5222 * shared by all the basic maps in "map" that force a given dimension5223 * to be equal to the floor of some affine combination of the input dimensions.5224 *5225 * In particular, if we can find two constraints5226 *5227 * e(...) + c1 - m x >= 0 i.e., m x <= e(...) + c15228 *5229 * and5230 *5231 * -e(...) + c2 + m x >= 0 i.e., m x >= e(...) - c25232 *5233 * where m > 1 and e only depends on parameters and input dimensions,5234 * and such that5235 *5236 * c1 + c2 < m i.e., -c2 >= c1 - (m - 1)5237 *5238 * then we know that we can take5239 *5240 * x = floor((e(...) + c1) / m)5241 *5242 * without having to perform any computation.5243 *5244 * Note that we know that5245 *5246 * c1 + c2 >= 15247 *5248 * If c1 + c2 were 0, then we would have detected an equality during5249 * simplification. If c1 + c2 were negative, then we would have detected5250 * a contradiction.5251 */5252static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_check_div(5253 __isl_take isl_map *map)5254{5255 int d;5256 isl_size dim;5257 int i, j, n;5258 int offset;5259 isl_size total;5260 isl_int sum;5261 isl_basic_map *hull;5262 5263 hull = isl_map_unshifted_simple_hull(isl_map_copy(map));5264 dim = isl_map_dim(map, isl_dim_out);5265 total = isl_basic_map_dim(hull, isl_dim_all);5266 if (dim < 0 || total < 0)5267 goto error;5268 5269 isl_int_init(sum);5270 offset = isl_basic_map_offset(hull, isl_dim_out);5271 n = hull->n_ineq;5272 for (d = 0; d < dim; ++d) {5273 for (i = 0; i < n; ++i) {5274 if (!is_potential_div_constraint(hull->ineq[i],5275 offset, d, 1 + total))5276 continue;5277 for (j = i + 1; j < n; ++j) {5278 if (!isl_seq_is_neg(hull->ineq[i] + 1,5279 hull->ineq[j] + 1, total))5280 continue;5281 isl_int_add(sum, hull->ineq[i][0],5282 hull->ineq[j][0]);5283 if (isl_int_abs_lt(sum,5284 hull->ineq[i][offset + d]))5285 break;5286 5287 }5288 if (j >= n)5289 continue;5290 isl_int_clear(sum);5291 if (isl_int_is_pos(hull->ineq[j][offset + d]))5292 j = i;5293 return pw_multi_aff_from_map_div(map, hull, d, j);5294 }5295 }5296 isl_int_clear(sum);5297 isl_basic_map_free(hull);5298 return pw_multi_aff_from_map_base(map);5299error:5300 isl_map_free(map);5301 isl_basic_map_free(hull);5302 return NULL;5303}5304 5305/* Given an affine expression5306 *5307 * [A -> B] -> f(A,B)5308 *5309 * construct an isl_multi_aff5310 *5311 * [A -> B] -> B'5312 *5313 * such that dimension "d" in B' is set to "aff" and the remaining5314 * dimensions are set equal to the corresponding dimensions in B.5315 * "n_in" is the dimension of the space A.5316 * "n_out" is the dimension of the space B.5317 *5318 * If "is_set" is set, then the affine expression is of the form5319 *5320 * [B] -> f(B)5321 *5322 * and we construct an isl_multi_aff5323 *5324 * B -> B'5325 */5326static __isl_give isl_multi_aff *range_map(__isl_take isl_aff *aff, int d,5327 unsigned n_in, unsigned n_out, int is_set)5328{5329 int i;5330 isl_multi_aff *ma;5331 isl_space *space, *space2;5332 isl_local_space *ls;5333 5334 space = isl_aff_get_domain_space(aff);5335 ls = isl_local_space_from_space(isl_space_copy(space));5336 space2 = isl_space_copy(space);5337 if (!is_set)5338 space2 = isl_space_range(isl_space_unwrap(space2));5339 space = isl_space_map_from_domain_and_range(space, space2);5340 ma = isl_multi_aff_alloc(space);5341 ma = isl_multi_aff_set_aff(ma, d, aff);5342 5343 for (i = 0; i < n_out; ++i) {5344 if (i == d)5345 continue;5346 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),5347 isl_dim_set, n_in + i);5348 ma = isl_multi_aff_set_aff(ma, i, aff);5349 }5350 5351 isl_local_space_free(ls);5352 5353 return ma;5354}5355 5356/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map,5357 * taking into account that the dimension at position "d" can be written as5358 *5359 * x = m a + f(..) (1)5360 *5361 * where m is equal to "gcd".5362 * "i" is the index of the equality in "hull" that defines f(..).5363 * In particular, the equality is of the form5364 *5365 * f(..) - x + m g(existentials) = 05366 *5367 * or5368 *5369 * -f(..) + x + m g(existentials) = 05370 *5371 * We basically plug (1) into "map", resulting in a map with "a"5372 * in the range instead of "x". The corresponding isl_pw_multi_aff5373 * defining "a" is then plugged back into (1) to obtain a definition for "x".5374 *5375 * Specifically, given the input map5376 *5377 * A -> B5378 *5379 * We first wrap it into a set5380 *5381 * [A -> B]5382 *5383 * and define (1) on top of the corresponding space, resulting in "aff".5384 * We use this to create an isl_multi_aff that maps the output position "d"5385 * from "a" to "x", leaving all other (intput and output) dimensions unchanged.5386 * We plug this into the wrapped map, unwrap the result and compute the5387 * corresponding isl_pw_multi_aff.5388 * The result is an expression5389 *5390 * A -> T(A)5391 *5392 * We adjust that to5393 *5394 * A -> [A -> T(A)]5395 *5396 * so that we can plug that into "aff", after extending the latter to5397 * a mapping5398 *5399 * [A -> B] -> B'5400 *5401 *5402 * If "map" is actually a set, then there is no "A" space, meaning5403 * that we do not need to perform any wrapping, and that the result5404 * of the recursive call is of the form5405 *5406 * [T]5407 *5408 * which is plugged into a mapping of the form5409 *5410 * B -> B'5411 */5412static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_stride(5413 __isl_take isl_map *map, __isl_take isl_basic_map *hull, int d, int i,5414 isl_int gcd)5415{5416 isl_set *set;5417 isl_space *space;5418 isl_local_space *ls;5419 isl_aff *aff;5420 isl_multi_aff *ma;5421 isl_pw_multi_aff *pma, *id;5422 isl_size n_in;5423 unsigned o_out;5424 isl_size n_out;5425 isl_bool is_set;5426 5427 is_set = isl_map_is_set(map);5428 if (is_set < 0)5429 goto error;5430 5431 n_in = isl_basic_map_dim(hull, isl_dim_in);5432 n_out = isl_basic_map_dim(hull, isl_dim_out);5433 if (n_in < 0 || n_out < 0)5434 goto error;5435 o_out = isl_basic_map_offset(hull, isl_dim_out);5436 5437 if (is_set)5438 set = map;5439 else5440 set = isl_map_wrap(map);5441 space = isl_space_map_from_set(isl_set_get_space(set));5442 ma = isl_multi_aff_identity(space);5443 ls = isl_local_space_from_space(isl_set_get_space(set));5444 aff = isl_aff_alloc(ls);5445 if (aff) {5446 isl_int_set_si(aff->v->el[0], 1);5447 if (isl_int_is_one(hull->eq[i][o_out + d]))5448 isl_seq_neg(aff->v->el + 1, hull->eq[i],5449 aff->v->size - 1);5450 else5451 isl_seq_cpy(aff->v->el + 1, hull->eq[i],5452 aff->v->size - 1);5453 isl_int_set(aff->v->el[1 + o_out + d], gcd);5454 }5455 ma = isl_multi_aff_set_aff(ma, n_in + d, isl_aff_copy(aff));5456 set = isl_set_preimage_multi_aff(set, ma);5457 5458 ma = range_map(aff, d, n_in, n_out, is_set);5459 5460 if (is_set)5461 map = set;5462 else5463 map = isl_set_unwrap(set);5464 pma = isl_pw_multi_aff_from_map(map);5465 5466 if (!is_set) {5467 space = isl_pw_multi_aff_get_domain_space(pma);5468 space = isl_space_map_from_set(space);5469 id = isl_pw_multi_aff_identity(space);5470 pma = isl_pw_multi_aff_range_product(id, pma);5471 }5472 id = isl_pw_multi_aff_from_multi_aff(ma);5473 pma = isl_pw_multi_aff_pullback_pw_multi_aff(id, pma);5474 5475 isl_basic_map_free(hull);5476 return pma;5477error:5478 isl_map_free(map);5479 isl_basic_map_free(hull);5480 return NULL;5481}5482 5483/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map.5484 * "hull" contains the equalities valid for "map".5485 *5486 * Check if any of the output dimensions is "strided".5487 * That is, we check if it can be written as5488 *5489 * x = m a + f(..)5490 *5491 * with m greater than 1, a some combination of existentially quantified5492 * variables and f an expression in the parameters and input dimensions.5493 * If so, we remove the stride in pw_multi_aff_from_map_stride.5494 *5495 * Otherwise, we continue with pw_multi_aff_from_map_check_div for a further5496 * special case.5497 */5498static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_check_strides(5499 __isl_take isl_map *map, __isl_take isl_basic_map *hull)5500{5501 int i, j;5502 isl_size n_out;5503 unsigned o_out;5504 isl_size n_div;5505 unsigned o_div;5506 isl_int gcd;5507 5508 n_div = isl_basic_map_dim(hull, isl_dim_div);5509 n_out = isl_basic_map_dim(hull, isl_dim_out);5510 if (n_div < 0 || n_out < 0)5511 goto error;5512 5513 if (n_div == 0) {5514 isl_basic_map_free(hull);5515 return pw_multi_aff_from_map_check_div(map);5516 }5517 5518 isl_int_init(gcd);5519 5520 o_div = isl_basic_map_offset(hull, isl_dim_div);5521 o_out = isl_basic_map_offset(hull, isl_dim_out);5522 5523 for (i = 0; i < n_out; ++i) {5524 for (j = 0; j < hull->n_eq; ++j) {5525 isl_int *eq = hull->eq[j];5526 isl_pw_multi_aff *res;5527 5528 if (!isl_int_is_one(eq[o_out + i]) &&5529 !isl_int_is_negone(eq[o_out + i]))5530 continue;5531 if (isl_seq_first_non_zero(eq + o_out, i) != -1)5532 continue;5533 if (isl_seq_first_non_zero(eq + o_out + i + 1,5534 n_out - (i + 1)) != -1)5535 continue;5536 isl_seq_gcd(eq + o_div, n_div, &gcd);5537 if (isl_int_is_zero(gcd))5538 continue;5539 if (isl_int_is_one(gcd))5540 continue;5541 5542 res = pw_multi_aff_from_map_stride(map, hull,5543 i, j, gcd);5544 isl_int_clear(gcd);5545 return res;5546 }5547 }5548 5549 isl_int_clear(gcd);5550 isl_basic_map_free(hull);5551 return pw_multi_aff_from_map_check_div(map);5552error:5553 isl_map_free(map);5554 isl_basic_map_free(hull);5555 return NULL;5556}5557 5558/* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map.5559 *5560 * As a special case, we first check if all output dimensions are uniquely5561 * defined in terms of the parameters and input dimensions over the entire5562 * domain. If so, we extract the desired isl_pw_multi_aff directly5563 * from the affine hull of "map" and its domain.5564 *5565 * Otherwise, continue with pw_multi_aff_from_map_check_strides for more5566 * special cases.5567 */5568__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_map(__isl_take isl_map *map)5569{5570 isl_bool sv;5571 isl_size n;5572 isl_basic_map *hull;5573 5574 n = isl_map_n_basic_map(map);5575 if (n < 0)5576 goto error;5577 5578 if (n == 1) {5579 hull = isl_map_unshifted_simple_hull(isl_map_copy(map));5580 hull = isl_basic_map_plain_affine_hull(hull);5581 sv = isl_basic_map_plain_is_single_valued(hull);5582 if (sv >= 0 && sv)5583 return plain_pw_multi_aff_from_map(isl_map_domain(map),5584 hull);5585 isl_basic_map_free(hull);5586 }5587 map = isl_map_detect_equalities(map);5588 hull = isl_map_unshifted_simple_hull(isl_map_copy(map));5589 sv = isl_basic_map_plain_is_single_valued(hull);5590 if (sv >= 0 && sv)5591 return plain_pw_multi_aff_from_map(isl_map_domain(map), hull);5592 if (sv >= 0)5593 return pw_multi_aff_from_map_check_strides(map, hull);5594 isl_basic_map_free(hull);5595error:5596 isl_map_free(map);5597 return NULL;5598}5599 5600/* This function performs the same operation as isl_pw_multi_aff_from_map,5601 * but is considered as a function on an isl_map when exported.5602 */5603__isl_give isl_pw_multi_aff *isl_map_as_pw_multi_aff(__isl_take isl_map *map)5604{5605 return isl_pw_multi_aff_from_map(map);5606}5607 5608__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(__isl_take isl_set *set)5609{5610 return isl_pw_multi_aff_from_map(set);5611}5612 5613/* This function performs the same operation as isl_pw_multi_aff_from_set,5614 * but is considered as a function on an isl_set when exported.5615 */5616__isl_give isl_pw_multi_aff *isl_set_as_pw_multi_aff(__isl_take isl_set *set)5617{5618 return isl_pw_multi_aff_from_set(set);5619}5620 5621/* Convert "map" into an isl_pw_multi_aff (if possible) and5622 * add it to *user.5623 */5624static isl_stat pw_multi_aff_from_map(__isl_take isl_map *map, void *user)5625{5626 isl_union_pw_multi_aff **upma = user;5627 isl_pw_multi_aff *pma;5628 5629 pma = isl_pw_multi_aff_from_map(map);5630 *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma);5631 5632 return *upma ? isl_stat_ok : isl_stat_error;5633}5634 5635/* Create an isl_union_pw_multi_aff with the given isl_aff on a universe5636 * domain.5637 */5638__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_aff(5639 __isl_take isl_aff *aff)5640{5641 isl_multi_aff *ma;5642 isl_pw_multi_aff *pma;5643 5644 ma = isl_multi_aff_from_aff(aff);5645 pma = isl_pw_multi_aff_from_multi_aff(ma);5646 return isl_union_pw_multi_aff_from_pw_multi_aff(pma);5647}5648 5649/* Try and create an isl_union_pw_multi_aff that is equivalent5650 * to the given isl_union_map.5651 * The isl_union_map is required to be single-valued in each space.5652 * Otherwise, an error is produced.5653 */5654__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_map(5655 __isl_take isl_union_map *umap)5656{5657 isl_space *space;5658 isl_union_pw_multi_aff *upma;5659 5660 space = isl_union_map_get_space(umap);5661 upma = isl_union_pw_multi_aff_empty(space);5662 if (isl_union_map_foreach_map(umap, &pw_multi_aff_from_map, &upma) < 0)5663 upma = isl_union_pw_multi_aff_free(upma);5664 isl_union_map_free(umap);5665 5666 return upma;5667}5668 5669/* This function performs the same operation as5670 * isl_union_pw_multi_aff_from_union_map,5671 * but is considered as a function on an isl_union_map when exported.5672 */5673__isl_give isl_union_pw_multi_aff *isl_union_map_as_union_pw_multi_aff(5674 __isl_take isl_union_map *umap)5675{5676 return isl_union_pw_multi_aff_from_union_map(umap);5677}5678 5679/* Try and create an isl_union_pw_multi_aff that is equivalent5680 * to the given isl_union_set.5681 * The isl_union_set is required to be a singleton in each space.5682 * Otherwise, an error is produced.5683 */5684__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_set(5685 __isl_take isl_union_set *uset)5686{5687 return isl_union_pw_multi_aff_from_union_map(uset);5688}5689 5690/* Return the piecewise affine expression "set ? 1 : 0".5691 */5692__isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set)5693{5694 isl_pw_aff *pa;5695 isl_space *space = isl_set_get_space(set);5696 isl_local_space *ls = isl_local_space_from_space(space);5697 isl_aff *zero = isl_aff_zero_on_domain(isl_local_space_copy(ls));5698 isl_aff *one = isl_aff_zero_on_domain(ls);5699 5700 one = isl_aff_add_constant_si(one, 1);5701 pa = isl_pw_aff_alloc(isl_set_copy(set), one);5702 set = isl_set_complement(set);5703 pa = isl_pw_aff_add_disjoint(pa, isl_pw_aff_alloc(set, zero));5704 5705 return pa;5706}5707 5708/* Plug in "subs" for dimension "type", "pos" of "aff".5709 *5710 * Let i be the dimension to replace and let "subs" be of the form5711 *5712 * f/d5713 *5714 * and "aff" of the form5715 *5716 * (a i + g)/m5717 *5718 * The result is5719 *5720 * (a f + d g')/(m d)5721 *5722 * where g' is the result of plugging in "subs" in each of the integer5723 * divisions in g.5724 */5725__isl_give isl_aff *isl_aff_substitute(__isl_take isl_aff *aff,5726 enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)5727{5728 isl_ctx *ctx;5729 isl_int v;5730 isl_size n_div;5731 5732 aff = isl_aff_cow(aff);5733 if (!aff || !subs)5734 return isl_aff_free(aff);5735 5736 ctx = isl_aff_get_ctx(aff);5737 if (!isl_space_is_equal(aff->ls->dim, subs->ls->dim))5738 isl_die(ctx, isl_error_invalid,5739 "spaces don't match", return isl_aff_free(aff));5740 n_div = isl_aff_domain_dim(subs, isl_dim_div);5741 if (n_div < 0)5742 return isl_aff_free(aff);5743 if (n_div != 0)5744 isl_die(ctx, isl_error_unsupported,5745 "cannot handle divs yet", return isl_aff_free(aff));5746 5747 aff->ls = isl_local_space_substitute(aff->ls, type, pos, subs);5748 if (!aff->ls)5749 return isl_aff_free(aff);5750 5751 aff->v = isl_vec_cow(aff->v);5752 if (!aff->v)5753 return isl_aff_free(aff);5754 5755 pos += isl_local_space_offset(aff->ls, type);5756 5757 isl_int_init(v);5758 isl_seq_substitute(aff->v->el, pos, subs->v->el,5759 aff->v->size, subs->v->size, v);5760 isl_int_clear(v);5761 5762 return aff;5763}5764 5765/* Plug in "subs" for dimension "type", "pos" in each of the affine5766 * expressions in "maff".5767 */5768__isl_give isl_multi_aff *isl_multi_aff_substitute(5769 __isl_take isl_multi_aff *maff, enum isl_dim_type type, unsigned pos,5770 __isl_keep isl_aff *subs)5771{5772 isl_size n;5773 int i;5774 5775 n = isl_multi_aff_size(maff);5776 if (n < 0 || !subs)5777 return isl_multi_aff_free(maff);5778 5779 if (type == isl_dim_in)5780 type = isl_dim_set;5781 5782 for (i = 0; i < n; ++i) {5783 isl_aff *aff;5784 5785 aff = isl_multi_aff_take_at(maff, i);5786 aff = isl_aff_substitute(aff, type, pos, subs);5787 maff = isl_multi_aff_restore_at(maff, i, aff);5788 }5789 5790 return maff;5791}5792 5793/* Plug in "subs" for input dimension "pos" of "pma".5794 *5795 * pma is of the form5796 *5797 * A_i(v) -> M_i(v)5798 *5799 * while subs is of the form5800 *5801 * v' = B_j(v) -> S_j5802 *5803 * Each pair i,j such that C_ij = A_i \cap B_i is non-empty5804 * has a contribution in the result, in particular5805 *5806 * C_ij(S_j) -> M_i(S_j)5807 *5808 * Note that plugging in S_j in C_ij may also result in an empty set5809 * and this contribution should simply be discarded.5810 */5811__isl_give isl_pw_multi_aff *isl_pw_multi_aff_substitute(5812 __isl_take isl_pw_multi_aff *pma, unsigned pos,5813 __isl_keep isl_pw_aff *subs)5814{5815 int i, j, n;5816 isl_pw_multi_aff *res;5817 5818 if (!pma || !subs)5819 return isl_pw_multi_aff_free(pma);5820 5821 n = pma->n * subs->n;5822 res = isl_pw_multi_aff_alloc_size(isl_space_copy(pma->dim), n);5823 5824 for (i = 0; i < pma->n; ++i) {5825 for (j = 0; j < subs->n; ++j) {5826 isl_set *common;5827 isl_multi_aff *res_ij;5828 int empty;5829 5830 common = isl_set_intersect(5831 isl_set_copy(pma->p[i].set),5832 isl_set_copy(subs->p[j].set));5833 common = isl_set_substitute(common,5834 pos, subs->p[j].aff);5835 empty = isl_set_plain_is_empty(common);5836 if (empty < 0 || empty) {5837 isl_set_free(common);5838 if (empty < 0)5839 goto error;5840 continue;5841 }5842 5843 res_ij = isl_multi_aff_substitute(5844 isl_multi_aff_copy(pma->p[i].maff),5845 isl_dim_in, pos, subs->p[j].aff);5846 5847 res = isl_pw_multi_aff_add_piece(res, common, res_ij);5848 }5849 }5850 5851 isl_pw_multi_aff_free(pma);5852 return res;5853error:5854 isl_pw_multi_aff_free(pma);5855 isl_pw_multi_aff_free(res);5856 return NULL;5857}5858 5859/* Compute the preimage of a range of dimensions in the affine expression "src"5860 * under "ma" and put the result in "dst". The number of dimensions in "src"5861 * that precede the range is given by "n_before". The number of dimensions5862 * in the range is given by the number of output dimensions of "ma".5863 * The number of dimensions that follow the range is given by "n_after".5864 * If "has_denom" is set (to one),5865 * then "src" and "dst" have an extra initial denominator.5866 * "n_div_ma" is the number of existentials in "ma"5867 * "n_div_bset" is the number of existentials in "src"5868 * The resulting "dst" (which is assumed to have been allocated by5869 * the caller) contains coefficients for both sets of existentials,5870 * first those in "ma" and then those in "src".5871 * f, c1, c2 and g are temporary objects that have been initialized5872 * by the caller.5873 *5874 * Let src represent the expression5875 *5876 * (a(p) + f_u u + b v + f_w w + c(divs))/d5877 *5878 * and let ma represent the expressions5879 *5880 * v_i = (r_i(p) + s_i(y) + t_i(divs'))/m_i5881 *5882 * We start out with the following expression for dst:5883 *5884 * (a(p) + f_u u + 0 y + f_w w + 0 divs' + c(divs) + f \sum_i b_i v_i)/d5885 *5886 * with the multiplication factor f initially equal to 15887 * and f \sum_i b_i v_i kept separately.5888 * For each x_i that we substitute, we multiply the numerator5889 * (and denominator) of dst by c_1 = m_i and add the numerator5890 * of the x_i expression multiplied by c_2 = f b_i,5891 * after removing the common factors of c_1 and c_2.5892 * The multiplication factor f also needs to be multiplied by c_15893 * for the next x_j, j > i.5894 */5895isl_stat isl_seq_preimage(isl_int *dst, isl_int *src,5896 __isl_keep isl_multi_aff *ma, int n_before, int n_after,5897 int n_div_ma, int n_div_bmap,5898 isl_int f, isl_int c1, isl_int c2, isl_int g, int has_denom)5899{5900 int i;5901 isl_size n_param, n_in, n_out;5902 int o_dst, o_src;5903 5904 n_param = isl_multi_aff_dim(ma, isl_dim_param);5905 n_in = isl_multi_aff_dim(ma, isl_dim_in);5906 n_out = isl_multi_aff_dim(ma, isl_dim_out);5907 if (n_param < 0 || n_in < 0 || n_out < 0)5908 return isl_stat_error;5909 5910 isl_seq_cpy(dst, src, has_denom + 1 + n_param + n_before);5911 o_dst = o_src = has_denom + 1 + n_param + n_before;5912 isl_seq_clr(dst + o_dst, n_in);5913 o_dst += n_in;5914 o_src += n_out;5915 isl_seq_cpy(dst + o_dst, src + o_src, n_after);5916 o_dst += n_after;5917 o_src += n_after;5918 isl_seq_clr(dst + o_dst, n_div_ma);5919 o_dst += n_div_ma;5920 isl_seq_cpy(dst + o_dst, src + o_src, n_div_bmap);5921 5922 isl_int_set_si(f, 1);5923 5924 for (i = 0; i < n_out; ++i) {5925 int offset = has_denom + 1 + n_param + n_before + i;5926 5927 if (isl_int_is_zero(src[offset]))5928 continue;5929 isl_int_set(c1, ma->u.p[i]->v->el[0]);5930 isl_int_mul(c2, f, src[offset]);5931 isl_int_gcd(g, c1, c2);5932 isl_int_divexact(c1, c1, g);5933 isl_int_divexact(c2, c2, g);5934 5935 isl_int_mul(f, f, c1);5936 o_dst = has_denom;5937 o_src = 1;5938 isl_seq_combine(dst + o_dst, c1, dst + o_dst,5939 c2, ma->u.p[i]->v->el + o_src, 1 + n_param);5940 o_dst += 1 + n_param;5941 o_src += 1 + n_param;5942 isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_before);5943 o_dst += n_before;5944 isl_seq_combine(dst + o_dst, c1, dst + o_dst,5945 c2, ma->u.p[i]->v->el + o_src, n_in);5946 o_dst += n_in;5947 o_src += n_in;5948 isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_after);5949 o_dst += n_after;5950 isl_seq_combine(dst + o_dst, c1, dst + o_dst,5951 c2, ma->u.p[i]->v->el + o_src, n_div_ma);5952 o_dst += n_div_ma;5953 o_src += n_div_ma;5954 isl_seq_scale(dst + o_dst, dst + o_dst, c1, n_div_bmap);5955 if (has_denom)5956 isl_int_mul(dst[0], dst[0], c1);5957 }5958 5959 return isl_stat_ok;5960}5961 5962/* Compute the pullback of "aff" by the function represented by "ma".5963 * In other words, plug in "ma" in "aff". The result is an affine expression5964 * defined over the domain space of "ma".5965 *5966 * If "aff" is represented by5967 *5968 * (a(p) + b x + c(divs))/d5969 *5970 * and ma is represented by5971 *5972 * x = D(p) + F(y) + G(divs')5973 *5974 * then the result is5975 *5976 * (a(p) + b D(p) + b F(y) + b G(divs') + c(divs))/d5977 *5978 * The divs in the local space of the input are similarly adjusted5979 * through a call to isl_local_space_preimage_multi_aff.5980 */5981__isl_give isl_aff *isl_aff_pullback_multi_aff(__isl_take isl_aff *aff,5982 __isl_take isl_multi_aff *ma)5983{5984 isl_aff *res = NULL;5985 isl_local_space *ls;5986 isl_size n_div_aff, n_div_ma;5987 isl_int f, c1, c2, g;5988 5989 ma = isl_multi_aff_align_divs(ma);5990 if (!aff || !ma)5991 goto error;5992 5993 n_div_aff = isl_aff_dim(aff, isl_dim_div);5994 n_div_ma = ma->n ? isl_aff_dim(ma->u.p[0], isl_dim_div) : 0;5995 if (n_div_aff < 0 || n_div_ma < 0)5996 goto error;5997 5998 ls = isl_aff_get_domain_local_space(aff);5999 ls = isl_local_space_preimage_multi_aff(ls, isl_multi_aff_copy(ma));6000 res = isl_aff_alloc(ls);6001 if (!res)6002 goto error;6003 6004 isl_int_init(f);6005 isl_int_init(c1);6006 isl_int_init(c2);6007 isl_int_init(g);6008 6009 if (isl_seq_preimage(res->v->el, aff->v->el, ma, 0, 0,6010 n_div_ma, n_div_aff, f, c1, c2, g, 1) < 0)6011 res = isl_aff_free(res);6012 6013 isl_int_clear(f);6014 isl_int_clear(c1);6015 isl_int_clear(c2);6016 isl_int_clear(g);6017 6018 isl_aff_free(aff);6019 isl_multi_aff_free(ma);6020 res = isl_aff_normalize(res);6021 return res;6022error:6023 isl_aff_free(aff);6024 isl_multi_aff_free(ma);6025 isl_aff_free(res);6026 return NULL;6027}6028 6029/* Compute the pullback of "aff1" by the function represented by "aff2".6030 * In other words, plug in "aff2" in "aff1". The result is an affine expression6031 * defined over the domain space of "aff1".6032 *6033 * The domain of "aff1" should match the range of "aff2", which means6034 * that it should be single-dimensional.6035 */6036__isl_give isl_aff *isl_aff_pullback_aff(__isl_take isl_aff *aff1,6037 __isl_take isl_aff *aff2)6038{6039 isl_multi_aff *ma;6040 6041 ma = isl_multi_aff_from_aff(aff2);6042 return isl_aff_pullback_multi_aff(aff1, ma);6043}6044 6045/* Compute the pullback of "ma1" by the function represented by "ma2".6046 * In other words, plug in "ma2" in "ma1".6047 */6048__isl_give isl_multi_aff *isl_multi_aff_pullback_multi_aff(6049 __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2)6050{6051 int i;6052 isl_size n;6053 isl_space *space = NULL;6054 6055 isl_multi_aff_align_params_bin(&ma1, &ma2);6056 ma2 = isl_multi_aff_align_divs(ma2);6057 n = isl_multi_aff_size(ma1);6058 if (n < 0 || !ma2)6059 goto error;6060 6061 space = isl_space_join(isl_multi_aff_get_space(ma2),6062 isl_multi_aff_get_space(ma1));6063 6064 for (i = 0; i < n; ++i) {6065 isl_aff *aff;6066 6067 aff = isl_multi_aff_take_at(ma1, i);6068 aff = isl_aff_pullback_multi_aff(aff, isl_multi_aff_copy(ma2));6069 ma1 = isl_multi_aff_restore_at(ma1, i, aff);6070 }6071 6072 ma1 = isl_multi_aff_reset_space(ma1, space);6073 isl_multi_aff_free(ma2);6074 return ma1;6075error:6076 isl_space_free(space);6077 isl_multi_aff_free(ma2);6078 isl_multi_aff_free(ma1);6079 return NULL;6080}6081 6082/* Extend the local space of "dst" to include the divs6083 * in the local space of "src".6084 *6085 * If "src" does not have any divs or if the local spaces of "dst" and6086 * "src" are the same, then no extension is required.6087 */6088__isl_give isl_aff *isl_aff_align_divs(__isl_take isl_aff *dst,6089 __isl_keep isl_aff *src)6090{6091 isl_ctx *ctx;6092 isl_size src_n_div, dst_n_div;6093 int *exp1 = NULL;6094 int *exp2 = NULL;6095 isl_bool equal;6096 isl_mat *div;6097 6098 if (!src || !dst)6099 return isl_aff_free(dst);6100 6101 ctx = isl_aff_get_ctx(src);6102 equal = isl_local_space_has_equal_space(src->ls, dst->ls);6103 if (equal < 0)6104 return isl_aff_free(dst);6105 if (!equal)6106 isl_die(ctx, isl_error_invalid,6107 "spaces don't match", goto error);6108 6109 src_n_div = isl_aff_domain_dim(src, isl_dim_div);6110 dst_n_div = isl_aff_domain_dim(dst, isl_dim_div);6111 if (src_n_div == 0)6112 return dst;6113 equal = isl_local_space_is_equal(src->ls, dst->ls);6114 if (equal < 0 || src_n_div < 0 || dst_n_div < 0)6115 return isl_aff_free(dst);6116 if (equal)6117 return dst;6118 6119 exp1 = isl_alloc_array(ctx, int, src_n_div);6120 exp2 = isl_alloc_array(ctx, int, dst_n_div);6121 if (!exp1 || (dst_n_div && !exp2))6122 goto error;6123 6124 div = isl_merge_divs(src->ls->div, dst->ls->div, exp1, exp2);6125 dst = isl_aff_expand_divs(dst, div, exp2);6126 free(exp1);6127 free(exp2);6128 6129 return dst;6130error:6131 free(exp1);6132 free(exp2);6133 return isl_aff_free(dst);6134}6135 6136/* Adjust the local spaces of the affine expressions in "maff"6137 * such that they all have the save divs.6138 */6139__isl_give isl_multi_aff *isl_multi_aff_align_divs(6140 __isl_take isl_multi_aff *maff)6141{6142 isl_aff *aff_0;6143 isl_size n;6144 int i;6145 6146 n = isl_multi_aff_size(maff);6147 if (n < 0)6148 return isl_multi_aff_free(maff);6149 if (n <= 1)6150 return maff;6151 6152 aff_0 = isl_multi_aff_take_at(maff, 0);6153 for (i = 1; i < n; ++i) {6154 isl_aff *aff_i;6155 6156 aff_i = isl_multi_aff_peek_at(maff, i);6157 aff_0 = isl_aff_align_divs(aff_0, aff_i);6158 }6159 maff = isl_multi_aff_restore_at(maff, 0, aff_0);6160 6161 aff_0 = isl_multi_aff_peek_at(maff, 0);6162 for (i = 1; i < n; ++i) {6163 isl_aff *aff_i;6164 6165 aff_i = isl_multi_aff_take_at(maff, i);6166 aff_i = isl_aff_align_divs(aff_i, aff_0);6167 maff = isl_multi_aff_restore_at(maff, i, aff_i);6168 }6169 6170 return maff;6171}6172 6173__isl_give isl_aff *isl_aff_lift(__isl_take isl_aff *aff)6174{6175 aff = isl_aff_cow(aff);6176 if (!aff)6177 return NULL;6178 6179 aff->ls = isl_local_space_lift(aff->ls);6180 if (!aff->ls)6181 return isl_aff_free(aff);6182 6183 return aff;6184}6185 6186/* Lift "maff" to a space with extra dimensions such that the result6187 * has no more existentially quantified variables.6188 * If "ls" is not NULL, then *ls is assigned the local space that lies6189 * at the basis of the lifting applied to "maff".6190 */6191__isl_give isl_multi_aff *isl_multi_aff_lift(__isl_take isl_multi_aff *maff,6192 __isl_give isl_local_space **ls)6193{6194 int i;6195 isl_space *space;6196 isl_aff *aff;6197 isl_size n, n_div;6198 6199 if (ls)6200 *ls = NULL;6201 6202 n = isl_multi_aff_size(maff);6203 if (n < 0)6204 return isl_multi_aff_free(maff);6205 6206 if (n == 0) {6207 if (ls) {6208 isl_space *space = isl_multi_aff_get_domain_space(maff);6209 *ls = isl_local_space_from_space(space);6210 if (!*ls)6211 return isl_multi_aff_free(maff);6212 }6213 return maff;6214 }6215 6216 maff = isl_multi_aff_align_divs(maff);6217 6218 aff = isl_multi_aff_peek_at(maff, 0);6219 n_div = isl_aff_dim(aff, isl_dim_div);6220 if (n_div < 0)6221 return isl_multi_aff_free(maff);6222 space = isl_multi_aff_get_space(maff);6223 space = isl_space_lift(isl_space_domain(space), n_div);6224 space = isl_space_extend_domain_with_range(space,6225 isl_multi_aff_get_space(maff));6226 maff = isl_multi_aff_restore_space(maff, space);6227 6228 if (ls) {6229 aff = isl_multi_aff_peek_at(maff, 0);6230 *ls = isl_aff_get_domain_local_space(aff);6231 if (!*ls)6232 return isl_multi_aff_free(maff);6233 }6234 6235 for (i = 0; i < n; ++i) {6236 aff = isl_multi_aff_take_at(maff, i);6237 aff = isl_aff_lift(aff);6238 maff = isl_multi_aff_restore_at(maff, i, aff);6239 }6240 6241 return maff;6242}6243 6244#undef TYPE6245#define TYPE isl_pw_multi_aff6246static6247#include "check_type_range_templ.c"6248 6249/* Extract an isl_pw_aff corresponding to output dimension "pos" of "pma".6250 */6251__isl_give isl_pw_aff *isl_pw_multi_aff_get_at(6252 __isl_keep isl_pw_multi_aff *pma, int pos)6253{6254 int i;6255 isl_size n_out;6256 isl_space *space;6257 isl_pw_aff *pa;6258 6259 if (isl_pw_multi_aff_check_range(pma, isl_dim_out, pos, 1) < 0)6260 return NULL;6261 6262 n_out = isl_pw_multi_aff_dim(pma, isl_dim_out);6263 if (n_out < 0)6264 return NULL;6265 6266 space = isl_pw_multi_aff_get_space(pma);6267 space = isl_space_drop_dims(space, isl_dim_out,6268 pos + 1, n_out - pos - 1);6269 space = isl_space_drop_dims(space, isl_dim_out, 0, pos);6270 6271 pa = isl_pw_aff_alloc_size(space, pma->n);6272 for (i = 0; i < pma->n; ++i) {6273 isl_aff *aff;6274 aff = isl_multi_aff_get_aff(pma->p[i].maff, pos);6275 pa = isl_pw_aff_add_piece(pa, isl_set_copy(pma->p[i].set), aff);6276 }6277 6278 return pa;6279}6280 6281/* This is an alternative name for the function above.6282 */6283__isl_give isl_pw_aff *isl_pw_multi_aff_get_pw_aff(6284 __isl_keep isl_pw_multi_aff *pma, int pos)6285{6286 return isl_pw_multi_aff_get_at(pma, pos);6287}6288 6289/* Return an isl_pw_multi_aff with the given "set" as domain and6290 * an unnamed zero-dimensional range.6291 */6292__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_domain(6293 __isl_take isl_set *set)6294{6295 isl_multi_aff *ma;6296 isl_space *space;6297 6298 space = isl_set_get_space(set);6299 space = isl_space_from_domain(space);6300 ma = isl_multi_aff_zero(space);6301 return isl_pw_multi_aff_alloc(set, ma);6302}6303 6304/* Add an isl_pw_multi_aff with the given "set" as domain and6305 * an unnamed zero-dimensional range to *user.6306 */6307static isl_stat add_pw_multi_aff_from_domain(__isl_take isl_set *set,6308 void *user)6309{6310 isl_union_pw_multi_aff **upma = user;6311 isl_pw_multi_aff *pma;6312 6313 pma = isl_pw_multi_aff_from_domain(set);6314 *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma);6315 6316 return isl_stat_ok;6317}6318 6319/* Return an isl_union_pw_multi_aff with the given "uset" as domain and6320 * an unnamed zero-dimensional range.6321 */6322__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_domain(6323 __isl_take isl_union_set *uset)6324{6325 isl_space *space;6326 isl_union_pw_multi_aff *upma;6327 6328 if (!uset)6329 return NULL;6330 6331 space = isl_union_set_get_space(uset);6332 upma = isl_union_pw_multi_aff_empty(space);6333 6334 if (isl_union_set_foreach_set(uset,6335 &add_pw_multi_aff_from_domain, &upma) < 0)6336 goto error;6337 6338 isl_union_set_free(uset);6339 return upma;6340error:6341 isl_union_set_free(uset);6342 isl_union_pw_multi_aff_free(upma);6343 return NULL;6344}6345 6346/* Local data for bin_entry and the callback "fn".6347 */6348struct isl_union_pw_multi_aff_bin_data {6349 isl_union_pw_multi_aff *upma2;6350 isl_union_pw_multi_aff *res;6351 isl_pw_multi_aff *pma;6352 isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma, void *user);6353};6354 6355/* Given an isl_pw_multi_aff from upma1, store it in data->pma6356 * and call data->fn for each isl_pw_multi_aff in data->upma2.6357 */6358static isl_stat bin_entry(__isl_take isl_pw_multi_aff *pma, void *user)6359{6360 struct isl_union_pw_multi_aff_bin_data *data = user;6361 isl_stat r;6362 6363 data->pma = pma;6364 r = isl_union_pw_multi_aff_foreach_pw_multi_aff(data->upma2,6365 data->fn, data);6366 isl_pw_multi_aff_free(pma);6367 6368 return r;6369}6370 6371/* Call "fn" on each pair of isl_pw_multi_affs in "upma1" and "upma2".6372 * The isl_pw_multi_aff from upma1 is stored in data->pma (where data is6373 * passed as user field) and the isl_pw_multi_aff from upma2 is available6374 * as *entry. The callback should adjust data->res if desired.6375 */6376static __isl_give isl_union_pw_multi_aff *bin_op(6377 __isl_take isl_union_pw_multi_aff *upma1,6378 __isl_take isl_union_pw_multi_aff *upma2,6379 isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma, void *user))6380{6381 isl_space *space;6382 struct isl_union_pw_multi_aff_bin_data data = { NULL, NULL, NULL, fn };6383 6384 space = isl_union_pw_multi_aff_get_space(upma2);6385 upma1 = isl_union_pw_multi_aff_align_params(upma1, space);6386 space = isl_union_pw_multi_aff_get_space(upma1);6387 upma2 = isl_union_pw_multi_aff_align_params(upma2, space);6388 6389 if (!upma1 || !upma2)6390 goto error;6391 6392 data.upma2 = upma2;6393 data.res = isl_union_pw_multi_aff_alloc_same_size(upma1);6394 if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma1,6395 &bin_entry, &data) < 0)6396 goto error;6397 6398 isl_union_pw_multi_aff_free(upma1);6399 isl_union_pw_multi_aff_free(upma2);6400 return data.res;6401error:6402 isl_union_pw_multi_aff_free(upma1);6403 isl_union_pw_multi_aff_free(upma2);6404 isl_union_pw_multi_aff_free(data.res);6405 return NULL;6406}6407 6408/* Given two isl_pw_multi_affs A -> B and C -> D,6409 * construct an isl_pw_multi_aff (A * C) -> [B -> D].6410 */6411__isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_product(6412 __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)6413{6414 isl_space *space;6415 6416 isl_pw_multi_aff_align_params_bin(&pma1, &pma2);6417 space = isl_space_range_product(isl_pw_multi_aff_get_space(pma1),6418 isl_pw_multi_aff_get_space(pma2));6419 return isl_pw_multi_aff_on_shared_domain_in(pma1, pma2, space,6420 &isl_multi_aff_range_product);6421}6422 6423/* Given two isl_pw_multi_affs A -> B and C -> D,6424 * construct an isl_pw_multi_aff (A * C) -> (B, D).6425 */6426__isl_give isl_pw_multi_aff *isl_pw_multi_aff_flat_range_product(6427 __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)6428{6429 isl_space *space;6430 6431 isl_pw_multi_aff_align_params_bin(&pma1, &pma2);6432 space = isl_space_range_product(isl_pw_multi_aff_get_space(pma1),6433 isl_pw_multi_aff_get_space(pma2));6434 space = isl_space_flatten_range(space);6435 return isl_pw_multi_aff_on_shared_domain_in(pma1, pma2, space,6436 &isl_multi_aff_flat_range_product);6437}6438 6439/* If data->pma and "pma2" have the same domain space, then use "range_product"6440 * to compute some form of range product and add the result to data->res.6441 */6442static isl_stat gen_range_product_entry(__isl_take isl_pw_multi_aff *pma2,6443 __isl_give isl_pw_multi_aff *(*range_product)(6444 __isl_take isl_pw_multi_aff *pma1,6445 __isl_take isl_pw_multi_aff *pma2),6446 void *user)6447{6448 struct isl_union_pw_multi_aff_bin_data *data = user;6449 isl_bool match;6450 isl_space *space1, *space2;6451 6452 space1 = isl_pw_multi_aff_peek_space(data->pma);6453 space2 = isl_pw_multi_aff_peek_space(pma2);6454 match = isl_space_tuple_is_equal(space1, isl_dim_in,6455 space2, isl_dim_in);6456 if (match < 0 || !match) {6457 isl_pw_multi_aff_free(pma2);6458 return match < 0 ? isl_stat_error : isl_stat_ok;6459 }6460 6461 pma2 = range_product(isl_pw_multi_aff_copy(data->pma), pma2);6462 6463 data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma2);6464 6465 return isl_stat_ok;6466}6467 6468/* If data->pma and "pma2" have the same domain space, then compute6469 * their flat range product and add the result to data->res.6470 */6471static isl_stat flat_range_product_entry(__isl_take isl_pw_multi_aff *pma2,6472 void *user)6473{6474 return gen_range_product_entry(pma2,6475 &isl_pw_multi_aff_flat_range_product, user);6476}6477 6478/* Given two isl_union_pw_multi_affs A -> B and C -> D,6479 * construct an isl_union_pw_multi_aff (A * C) -> (B, D).6480 */6481__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_flat_range_product(6482 __isl_take isl_union_pw_multi_aff *upma1,6483 __isl_take isl_union_pw_multi_aff *upma2)6484{6485 return bin_op(upma1, upma2, &flat_range_product_entry);6486}6487 6488/* If data->pma and "pma2" have the same domain space, then compute6489 * their range product and add the result to data->res.6490 */6491static isl_stat range_product_entry(__isl_take isl_pw_multi_aff *pma2,6492 void *user)6493{6494 return gen_range_product_entry(pma2,6495 &isl_pw_multi_aff_range_product, user);6496}6497 6498/* Given two isl_union_pw_multi_affs A -> B and C -> D,6499 * construct an isl_union_pw_multi_aff (A * C) -> [B -> D].6500 */6501__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_range_product(6502 __isl_take isl_union_pw_multi_aff *upma1,6503 __isl_take isl_union_pw_multi_aff *upma2)6504{6505 return bin_op(upma1, upma2, &range_product_entry);6506}6507 6508/* Replace the affine expressions at position "pos" in "pma" by "pa".6509 * The parameters are assumed to have been aligned.6510 *6511 * The implementation essentially performs an isl_pw_*_on_shared_domain,6512 * except that it works on two different isl_pw_* types.6513 */6514static __isl_give isl_pw_multi_aff *pw_multi_aff_set_pw_aff(6515 __isl_take isl_pw_multi_aff *pma, unsigned pos,6516 __isl_take isl_pw_aff *pa)6517{6518 int i, j, n;6519 isl_pw_multi_aff *res = NULL;6520 6521 if (!pma || !pa)6522 goto error;6523 6524 if (!isl_space_tuple_is_equal(pma->dim, isl_dim_in,6525 pa->dim, isl_dim_in))6526 isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,6527 "domains don't match", goto error);6528 if (isl_pw_multi_aff_check_range(pma, isl_dim_out, pos, 1) < 0)6529 goto error;6530 6531 n = pma->n * pa->n;6532 res = isl_pw_multi_aff_alloc_size(isl_pw_multi_aff_get_space(pma), n);6533 6534 for (i = 0; i < pma->n; ++i) {6535 for (j = 0; j < pa->n; ++j) {6536 isl_set *common;6537 isl_multi_aff *res_ij;6538 int empty;6539 6540 common = isl_set_intersect(isl_set_copy(pma->p[i].set),6541 isl_set_copy(pa->p[j].set));6542 empty = isl_set_plain_is_empty(common);6543 if (empty < 0 || empty) {6544 isl_set_free(common);6545 if (empty < 0)6546 goto error;6547 continue;6548 }6549 6550 res_ij = isl_multi_aff_set_aff(6551 isl_multi_aff_copy(pma->p[i].maff), pos,6552 isl_aff_copy(pa->p[j].aff));6553 res_ij = isl_multi_aff_gist(res_ij,6554 isl_set_copy(common));6555 6556 res = isl_pw_multi_aff_add_piece(res, common, res_ij);6557 }6558 }6559 6560 isl_pw_multi_aff_free(pma);6561 isl_pw_aff_free(pa);6562 return res;6563error:6564 isl_pw_multi_aff_free(pma);6565 isl_pw_aff_free(pa);6566 return isl_pw_multi_aff_free(res);6567}6568 6569/* Replace the affine expressions at position "pos" in "pma" by "pa".6570 */6571__isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_pw_aff(6572 __isl_take isl_pw_multi_aff *pma, unsigned pos,6573 __isl_take isl_pw_aff *pa)6574{6575 isl_bool equal_params;6576 6577 if (!pma || !pa)6578 goto error;6579 equal_params = isl_space_has_equal_params(pma->dim, pa->dim);6580 if (equal_params < 0)6581 goto error;6582 if (equal_params)6583 return pw_multi_aff_set_pw_aff(pma, pos, pa);6584 if (isl_pw_multi_aff_check_named_params(pma) < 0 ||6585 isl_pw_aff_check_named_params(pa) < 0)6586 goto error;6587 pma = isl_pw_multi_aff_align_params(pma, isl_pw_aff_get_space(pa));6588 pa = isl_pw_aff_align_params(pa, isl_pw_multi_aff_get_space(pma));6589 return pw_multi_aff_set_pw_aff(pma, pos, pa);6590error:6591 isl_pw_multi_aff_free(pma);6592 isl_pw_aff_free(pa);6593 return NULL;6594}6595 6596/* Do the parameters of "pa" match those of "space"?6597 */6598isl_bool isl_pw_aff_matching_params(__isl_keep isl_pw_aff *pa,6599 __isl_keep isl_space *space)6600{6601 isl_space *pa_space;6602 isl_bool match;6603 6604 if (!pa || !space)6605 return isl_bool_error;6606 6607 pa_space = isl_pw_aff_get_space(pa);6608 6609 match = isl_space_has_equal_params(space, pa_space);6610 6611 isl_space_free(pa_space);6612 return match;6613}6614 6615/* Check that the domain space of "pa" matches "space".6616 */6617isl_stat isl_pw_aff_check_match_domain_space(__isl_keep isl_pw_aff *pa,6618 __isl_keep isl_space *space)6619{6620 isl_space *pa_space;6621 isl_bool match;6622 6623 if (!pa || !space)6624 return isl_stat_error;6625 6626 pa_space = isl_pw_aff_get_space(pa);6627 6628 match = isl_space_has_equal_params(space, pa_space);6629 if (match < 0)6630 goto error;6631 if (!match)6632 isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,6633 "parameters don't match", goto error);6634 match = isl_space_tuple_is_equal(space, isl_dim_in,6635 pa_space, isl_dim_in);6636 if (match < 0)6637 goto error;6638 if (!match)6639 isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,6640 "domains don't match", goto error);6641 isl_space_free(pa_space);6642 return isl_stat_ok;6643error:6644 isl_space_free(pa_space);6645 return isl_stat_error;6646}6647 6648#undef BASE6649#define BASE pw_aff6650#undef DOMBASE6651#define DOMBASE set6652 6653#include <isl_multi_explicit_domain.c>6654#include <isl_multi_pw_aff_explicit_domain.c>6655#include <isl_multi_templ.c>6656#include <isl_multi_un_op_templ.c>6657#include <isl_multi_bin_val_templ.c>6658#include <isl_multi_add_constant_templ.c>6659#include <isl_multi_apply_set.c>6660#include <isl_multi_arith_templ.c>6661#include <isl_multi_bind_templ.c>6662#include <isl_multi_bind_domain_templ.c>6663#include <isl_multi_coalesce.c>6664#include <isl_multi_domain_templ.c>6665#include <isl_multi_dim_id_templ.c>6666#include <isl_multi_dims.c>6667#include <isl_multi_from_base_templ.c>6668#include <isl_multi_gist.c>6669#include <isl_multi_hash.c>6670#include <isl_multi_identity_templ.c>6671#include <isl_multi_align_set.c>6672#include <isl_multi_insert_domain_templ.c>6673#include <isl_multi_intersect.c>6674#include <isl_multi_min_max_templ.c>6675#include <isl_multi_move_dims_templ.c>6676#include <isl_multi_nan_templ.c>6677#include <isl_multi_param_templ.c>6678#include <isl_multi_product_templ.c>6679#include <isl_multi_splice_templ.c>6680#include <isl_multi_tuple_id_templ.c>6681#include <isl_multi_union_add_templ.c>6682#include <isl_multi_zero_templ.c>6683#include <isl_multi_unbind_params_templ.c>6684 6685/* Is every element of "mpa" defined over a single universe domain?6686 */6687isl_bool isl_multi_pw_aff_isa_multi_aff(__isl_keep isl_multi_pw_aff *mpa)6688{6689 return isl_multi_pw_aff_every(mpa, &isl_pw_aff_isa_aff);6690}6691 6692/* Given that every element of "mpa" is defined over a single universe domain,6693 * return the corresponding base expressions.6694 */6695__isl_give isl_multi_aff *isl_multi_pw_aff_as_multi_aff(6696 __isl_take isl_multi_pw_aff *mpa)6697{6698 int i;6699 isl_size n;6700 isl_multi_aff *ma;6701 6702 n = isl_multi_pw_aff_size(mpa);6703 if (n < 0)6704 mpa = isl_multi_pw_aff_free(mpa);6705 ma = isl_multi_aff_alloc(isl_multi_pw_aff_get_space(mpa));6706 for (i = 0; i < n; ++i) {6707 isl_aff *aff;6708 6709 aff = isl_pw_aff_as_aff(isl_multi_pw_aff_get_at(mpa, i));6710 ma = isl_multi_aff_set_aff(ma, i, aff);6711 }6712 isl_multi_pw_aff_free(mpa);6713 return ma;6714}6715 6716/* If "mpa" has an explicit domain, then intersect the domain of "map"6717 * with this explicit domain.6718 */6719__isl_give isl_map *isl_map_intersect_multi_pw_aff_explicit_domain(6720 __isl_take isl_map *map, __isl_keep isl_multi_pw_aff *mpa)6721{6722 isl_set *dom;6723 6724 if (!isl_multi_pw_aff_has_explicit_domain(mpa))6725 return map;6726 6727 dom = isl_multi_pw_aff_domain(isl_multi_pw_aff_copy(mpa));6728 map = isl_map_intersect_domain(map, dom);6729 6730 return map;6731}6732 6733/* Are all elements of "mpa" piecewise constants?6734 */6735isl_bool isl_multi_pw_aff_is_cst(__isl_keep isl_multi_pw_aff *mpa)6736{6737 return isl_multi_pw_aff_every(mpa, &isl_pw_aff_is_cst);6738}6739 6740/* Does "mpa" have a non-trivial explicit domain?6741 *6742 * The explicit domain, if present, is trivial if it represents6743 * an (obviously) universe set.6744 */6745isl_bool isl_multi_pw_aff_has_non_trivial_domain(6746 __isl_keep isl_multi_pw_aff *mpa)6747{6748 if (!mpa)6749 return isl_bool_error;6750 if (!isl_multi_pw_aff_has_explicit_domain(mpa))6751 return isl_bool_false;6752 return isl_bool_not(isl_set_plain_is_universe(mpa->u.dom));6753}6754 6755#undef BASE6756#define BASE set6757 6758#include "isl_opt_mpa_templ.c"6759 6760/* Compute the minima of the set dimensions as a function of the6761 * parameters, but independently of the other set dimensions.6762 */6763__isl_give isl_multi_pw_aff *isl_set_min_multi_pw_aff(__isl_take isl_set *set)6764{6765 return set_opt_mpa(set, &isl_set_dim_min);6766}6767 6768/* Compute the maxima of the set dimensions as a function of the6769 * parameters, but independently of the other set dimensions.6770 */6771__isl_give isl_multi_pw_aff *isl_set_max_multi_pw_aff(__isl_take isl_set *set)6772{6773 return set_opt_mpa(set, &isl_set_dim_max);6774}6775 6776#undef BASE6777#define BASE map6778 6779#include "isl_opt_mpa_templ.c"6780 6781/* Compute the minima of the output dimensions as a function of the6782 * parameters and input dimensions, but independently of6783 * the other output dimensions.6784 */6785__isl_give isl_multi_pw_aff *isl_map_min_multi_pw_aff(__isl_take isl_map *map)6786{6787 return map_opt_mpa(map, &isl_map_dim_min);6788}6789 6790/* Compute the maxima of the output dimensions as a function of the6791 * parameters and input dimensions, but independently of6792 * the other output dimensions.6793 */6794__isl_give isl_multi_pw_aff *isl_map_max_multi_pw_aff(__isl_take isl_map *map)6795{6796 return map_opt_mpa(map, &isl_map_dim_max);6797}6798 6799#undef TYPE6800#define TYPE isl_pw_multi_aff6801#include "isl_type_check_match_range_multi_val.c"6802 6803/* Apply "fn" to the base expressions of "pma" and "mv".6804 */6805static __isl_give isl_pw_multi_aff *isl_pw_multi_aff_op_multi_val(6806 __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv,6807 __isl_give isl_multi_aff *(*fn)(__isl_take isl_multi_aff *ma,6808 __isl_take isl_multi_val *mv))6809{6810 int i;6811 isl_size n;6812 6813 if (isl_pw_multi_aff_check_match_range_multi_val(pma, mv) < 0)6814 goto error;6815 6816 n = isl_pw_multi_aff_n_piece(pma);6817 if (n < 0)6818 goto error;6819 6820 for (i = 0; i < n; ++i) {6821 isl_multi_aff *ma;6822 6823 ma = isl_pw_multi_aff_take_base_at(pma, i);6824 ma = fn(ma, isl_multi_val_copy(mv));6825 pma = isl_pw_multi_aff_restore_base_at(pma, i, ma);6826 }6827 6828 isl_multi_val_free(mv);6829 return pma;6830error:6831 isl_multi_val_free(mv);6832 isl_pw_multi_aff_free(pma);6833 return NULL;6834}6835 6836/* Scale the elements of "pma" by the corresponding elements of "mv".6837 */6838__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_multi_val(6839 __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv)6840{6841 return isl_pw_multi_aff_op_multi_val(pma, mv,6842 &isl_multi_aff_scale_multi_val);6843}6844 6845/* Scale the elements of "pma" down by the corresponding elements of "mv".6846 */6847__isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_down_multi_val(6848 __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv)6849{6850 return isl_pw_multi_aff_op_multi_val(pma, mv,6851 &isl_multi_aff_scale_down_multi_val);6852}6853 6854/* This function is called for each entry of an isl_union_pw_multi_aff.6855 * If the space of the entry matches that of data->mv,6856 * then apply isl_pw_multi_aff_scale_multi_val and return the result.6857 * Otherwise, return an empty isl_pw_multi_aff.6858 */6859static __isl_give isl_pw_multi_aff *union_pw_multi_aff_scale_multi_val_entry(6860 __isl_take isl_pw_multi_aff *pma, void *user)6861{6862 isl_bool equal;6863 isl_multi_val *mv = user;6864 6865 equal = isl_pw_multi_aff_match_range_multi_val(pma, mv);6866 if (equal < 0)6867 return isl_pw_multi_aff_free(pma);6868 if (!equal) {6869 isl_space *space = isl_pw_multi_aff_get_space(pma);6870 isl_pw_multi_aff_free(pma);6871 return isl_pw_multi_aff_empty(space);6872 }6873 6874 return isl_pw_multi_aff_scale_multi_val(pma, isl_multi_val_copy(mv));6875}6876 6877/* Scale the elements of "upma" by the corresponding elements of "mv",6878 * for those entries that match the space of "mv".6879 */6880__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_multi_val(6881 __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_multi_val *mv)6882{6883 struct isl_union_pw_multi_aff_transform_control control = {6884 .fn = &union_pw_multi_aff_scale_multi_val_entry,6885 .fn_user = mv,6886 };6887 6888 upma = isl_union_pw_multi_aff_align_params(upma,6889 isl_multi_val_get_space(mv));6890 mv = isl_multi_val_align_params(mv,6891 isl_union_pw_multi_aff_get_space(upma));6892 if (!upma || !mv)6893 goto error;6894 6895 return isl_union_pw_multi_aff_transform(upma, &control);6896 6897 isl_multi_val_free(mv);6898 return upma;6899error:6900 isl_multi_val_free(mv);6901 isl_union_pw_multi_aff_free(upma);6902 return NULL;6903}6904 6905/* Construct and return a piecewise multi affine expression6906 * in the given space with value zero in each of the output dimensions and6907 * a universe domain.6908 */6909__isl_give isl_pw_multi_aff *isl_pw_multi_aff_zero(__isl_take isl_space *space)6910{6911 return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_zero(space));6912}6913 6914/* Construct and return a piecewise multi affine expression6915 * that is equal to the given piecewise affine expression.6916 */6917__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_pw_aff(6918 __isl_take isl_pw_aff *pa)6919{6920 int i;6921 isl_space *space;6922 isl_pw_multi_aff *pma;6923 6924 if (!pa)6925 return NULL;6926 6927 space = isl_pw_aff_get_space(pa);6928 pma = isl_pw_multi_aff_alloc_size(space, pa->n);6929 6930 for (i = 0; i < pa->n; ++i) {6931 isl_set *set;6932 isl_multi_aff *ma;6933 6934 set = isl_set_copy(pa->p[i].set);6935 ma = isl_multi_aff_from_aff(isl_aff_copy(pa->p[i].aff));6936 pma = isl_pw_multi_aff_add_piece(pma, set, ma);6937 }6938 6939 isl_pw_aff_free(pa);6940 return pma;6941}6942 6943/* Construct and return a piecewise multi affine expression6944 * that is equal to the given multi piecewise affine expression6945 * on the shared domain of the piecewise affine expressions,6946 * in the special case of a 0D multi piecewise affine expression.6947 *6948 * Create a piecewise multi affine expression with the explicit domain of6949 * the 0D multi piecewise affine expression as domain.6950 */6951static __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_pw_aff_0D(6952 __isl_take isl_multi_pw_aff *mpa)6953{6954 isl_space *space;6955 isl_set *dom;6956 isl_multi_aff *ma;6957 6958 space = isl_multi_pw_aff_get_space(mpa);6959 dom = isl_multi_pw_aff_get_explicit_domain(mpa);6960 isl_multi_pw_aff_free(mpa);6961 6962 ma = isl_multi_aff_zero(space);6963 return isl_pw_multi_aff_alloc(dom, ma);6964}6965 6966/* Construct and return a piecewise multi affine expression6967 * that is equal to the given multi piecewise affine expression6968 * on the shared domain of the piecewise affine expressions.6969 */6970__isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_pw_aff(6971 __isl_take isl_multi_pw_aff *mpa)6972{6973 int i;6974 isl_space *space;6975 isl_pw_aff *pa;6976 isl_pw_multi_aff *pma;6977 6978 if (!mpa)6979 return NULL;6980 6981 if (mpa->n == 0)6982 return isl_pw_multi_aff_from_multi_pw_aff_0D(mpa);6983 6984 space = isl_multi_pw_aff_get_space(mpa);6985 pa = isl_multi_pw_aff_get_pw_aff(mpa, 0);6986 pma = isl_pw_multi_aff_from_pw_aff(pa);6987 6988 for (i = 1; i < mpa->n; ++i) {6989 isl_pw_multi_aff *pma_i;6990 6991 pa = isl_multi_pw_aff_get_pw_aff(mpa, i);6992 pma_i = isl_pw_multi_aff_from_pw_aff(pa);6993 pma = isl_pw_multi_aff_range_product(pma, pma_i);6994 }6995 6996 pma = isl_pw_multi_aff_reset_space(pma, space);6997 6998 isl_multi_pw_aff_free(mpa);6999 return pma;7000}7001 7002/* Convenience function that constructs an isl_multi_pw_aff7003 * directly from an isl_aff.7004 */7005__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_aff(__isl_take isl_aff *aff)7006{7007 return isl_multi_pw_aff_from_pw_aff(isl_pw_aff_from_aff(aff));7008}7009 7010/* Construct and return a multi piecewise affine expression7011 * that is equal to the given multi affine expression.7012 */7013__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_multi_aff(7014 __isl_take isl_multi_aff *ma)7015{7016 int i;7017 isl_size n;7018 isl_multi_pw_aff *mpa;7019 7020 n = isl_multi_aff_dim(ma, isl_dim_out);7021 if (n < 0)7022 ma = isl_multi_aff_free(ma);7023 if (!ma)7024 return NULL;7025 7026 mpa = isl_multi_pw_aff_alloc(isl_multi_aff_get_space(ma));7027 7028 for (i = 0; i < n; ++i) {7029 isl_pw_aff *pa;7030 7031 pa = isl_pw_aff_from_aff(isl_multi_aff_get_aff(ma, i));7032 mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa);7033 }7034 7035 isl_multi_aff_free(ma);7036 return mpa;7037}7038 7039/* This function performs the same operation as isl_multi_pw_aff_from_multi_aff,7040 * but is considered as a function on an isl_multi_aff when exported.7041 */7042__isl_give isl_multi_pw_aff *isl_multi_aff_to_multi_pw_aff(7043 __isl_take isl_multi_aff *ma)7044{7045 return isl_multi_pw_aff_from_multi_aff(ma);7046}7047 7048/* Construct and return a multi piecewise affine expression7049 * that is equal to the given piecewise multi affine expression.7050 *7051 * If the resulting multi piecewise affine expression has7052 * an explicit domain, then assign it the domain of the input.7053 * In other cases, the domain is stored in the individual elements.7054 */7055__isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_multi_aff(7056 __isl_take isl_pw_multi_aff *pma)7057{7058 int i;7059 isl_size n;7060 isl_space *space;7061 isl_multi_pw_aff *mpa;7062 7063 n = isl_pw_multi_aff_dim(pma, isl_dim_out);7064 if (n < 0)7065 pma = isl_pw_multi_aff_free(pma);7066 space = isl_pw_multi_aff_get_space(pma);7067 mpa = isl_multi_pw_aff_alloc(space);7068 7069 for (i = 0; i < n; ++i) {7070 isl_pw_aff *pa;7071 7072 pa = isl_pw_multi_aff_get_pw_aff(pma, i);7073 mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa);7074 }7075 if (isl_multi_pw_aff_has_explicit_domain(mpa)) {7076 isl_set *dom;7077 7078 dom = isl_pw_multi_aff_domain(isl_pw_multi_aff_copy(pma));7079 mpa = isl_multi_pw_aff_intersect_domain(mpa, dom);7080 }7081 7082 isl_pw_multi_aff_free(pma);7083 return mpa;7084}7085 7086/* This function performs the same operation as7087 * isl_multi_pw_aff_from_pw_multi_aff,7088 * but is considered as a function on an isl_pw_multi_aff when exported.7089 */7090__isl_give isl_multi_pw_aff *isl_pw_multi_aff_to_multi_pw_aff(7091 __isl_take isl_pw_multi_aff *pma)7092{7093 return isl_multi_pw_aff_from_pw_multi_aff(pma);7094}7095 7096/* Do "pa1" and "pa2" represent the same function?7097 *7098 * We first check if they are obviously equal.7099 * If not, we convert them to maps and check if those are equal.7100 *7101 * If "pa1" or "pa2" contain any NaNs, then they are considered7102 * not to be the same. A NaN is not equal to anything, not even7103 * to another NaN.7104 */7105isl_bool isl_pw_aff_is_equal(__isl_keep isl_pw_aff *pa1,7106 __isl_keep isl_pw_aff *pa2)7107{7108 isl_bool equal;7109 isl_bool has_nan;7110 isl_map *map1, *map2;7111 7112 if (!pa1 || !pa2)7113 return isl_bool_error;7114 7115 equal = isl_pw_aff_plain_is_equal(pa1, pa2);7116 if (equal < 0 || equal)7117 return equal;7118 has_nan = either_involves_nan(pa1, pa2);7119 if (has_nan < 0)7120 return isl_bool_error;7121 if (has_nan)7122 return isl_bool_false;7123 7124 map1 = isl_map_from_pw_aff_internal(isl_pw_aff_copy(pa1));7125 map2 = isl_map_from_pw_aff_internal(isl_pw_aff_copy(pa2));7126 equal = isl_map_is_equal(map1, map2);7127 isl_map_free(map1);7128 isl_map_free(map2);7129 7130 return equal;7131}7132 7133/* Do "mpa1" and "mpa2" represent the same function?7134 *7135 * Note that we cannot convert the entire isl_multi_pw_aff7136 * to a map because the domains of the piecewise affine expressions7137 * may not be the same.7138 */7139isl_bool isl_multi_pw_aff_is_equal(__isl_keep isl_multi_pw_aff *mpa1,7140 __isl_keep isl_multi_pw_aff *mpa2)7141{7142 int i;7143 isl_bool equal, equal_params;7144 7145 if (!mpa1 || !mpa2)7146 return isl_bool_error;7147 7148 equal_params = isl_space_has_equal_params(mpa1->space, mpa2->space);7149 if (equal_params < 0)7150 return isl_bool_error;7151 if (!equal_params) {7152 if (!isl_space_has_named_params(mpa1->space))7153 return isl_bool_false;7154 if (!isl_space_has_named_params(mpa2->space))7155 return isl_bool_false;7156 mpa1 = isl_multi_pw_aff_copy(mpa1);7157 mpa2 = isl_multi_pw_aff_copy(mpa2);7158 mpa1 = isl_multi_pw_aff_align_params(mpa1,7159 isl_multi_pw_aff_get_space(mpa2));7160 mpa2 = isl_multi_pw_aff_align_params(mpa2,7161 isl_multi_pw_aff_get_space(mpa1));7162 equal = isl_multi_pw_aff_is_equal(mpa1, mpa2);7163 isl_multi_pw_aff_free(mpa1);7164 isl_multi_pw_aff_free(mpa2);7165 return equal;7166 }7167 7168 equal = isl_space_is_equal(mpa1->space, mpa2->space);7169 if (equal < 0 || !equal)7170 return equal;7171 7172 for (i = 0; i < mpa1->n; ++i) {7173 equal = isl_pw_aff_is_equal(mpa1->u.p[i], mpa2->u.p[i]);7174 if (equal < 0 || !equal)7175 return equal;7176 }7177 7178 return isl_bool_true;7179}7180 7181/* Do "pma1" and "pma2" represent the same function?7182 *7183 * First check if they are obviously equal.7184 * If not, then convert them to maps and check if those are equal.7185 *7186 * If "pa1" or "pa2" contain any NaNs, then they are considered7187 * not to be the same. A NaN is not equal to anything, not even7188 * to another NaN.7189 */7190isl_bool isl_pw_multi_aff_is_equal(__isl_keep isl_pw_multi_aff *pma1,7191 __isl_keep isl_pw_multi_aff *pma2)7192{7193 isl_bool equal;7194 isl_bool has_nan;7195 isl_map *map1, *map2;7196 7197 if (!pma1 || !pma2)7198 return isl_bool_error;7199 7200 equal = isl_pw_multi_aff_plain_is_equal(pma1, pma2);7201 if (equal < 0 || equal)7202 return equal;7203 has_nan = isl_pw_multi_aff_involves_nan(pma1);7204 if (has_nan >= 0 && !has_nan)7205 has_nan = isl_pw_multi_aff_involves_nan(pma2);7206 if (has_nan < 0 || has_nan)7207 return isl_bool_not(has_nan);7208 7209 map1 = isl_map_from_pw_multi_aff_internal(isl_pw_multi_aff_copy(pma1));7210 map2 = isl_map_from_pw_multi_aff_internal(isl_pw_multi_aff_copy(pma2));7211 equal = isl_map_is_equal(map1, map2);7212 isl_map_free(map1);7213 isl_map_free(map2);7214 7215 return equal;7216}7217 7218#undef BASE7219#define BASE multi_aff7220 7221#include "isl_multi_pw_aff_pullback_templ.c"7222 7223#undef BASE7224#define BASE pw_multi_aff7225 7226#include "isl_multi_pw_aff_pullback_templ.c"7227 7228/* Apply "aff" to "mpa". The range of "mpa" needs to be compatible7229 * with the domain of "aff". The domain of the result is the same7230 * as that of "mpa".7231 * "mpa" and "aff" are assumed to have been aligned.7232 *7233 * We first extract the parametric constant from "aff", defined7234 * over the correct domain.7235 * Then we add the appropriate combinations of the members of "mpa".7236 * Finally, we add the integer divisions through recursive calls.7237 */7238static __isl_give isl_pw_aff *isl_multi_pw_aff_apply_aff_aligned(7239 __isl_take isl_multi_pw_aff *mpa, __isl_take isl_aff *aff)7240{7241 int i;7242 isl_size n_in, n_div, n_mpa_in;7243 isl_space *space;7244 isl_val *v;7245 isl_pw_aff *pa;7246 isl_aff *tmp;7247 7248 n_in = isl_aff_dim(aff, isl_dim_in);7249 n_div = isl_aff_dim(aff, isl_dim_div);7250 n_mpa_in = isl_multi_pw_aff_dim(mpa, isl_dim_in);7251 if (n_in < 0 || n_div < 0 || n_mpa_in < 0)7252 goto error;7253 7254 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));7255 tmp = isl_aff_copy(aff);7256 tmp = isl_aff_drop_dims(tmp, isl_dim_div, 0, n_div);7257 tmp = isl_aff_drop_dims(tmp, isl_dim_in, 0, n_in);7258 tmp = isl_aff_add_dims(tmp, isl_dim_in, n_mpa_in);7259 tmp = isl_aff_reset_domain_space(tmp, space);7260 pa = isl_pw_aff_from_aff(tmp);7261 7262 for (i = 0; i < n_in; ++i) {7263 isl_pw_aff *pa_i;7264 7265 if (!isl_aff_involves_dims(aff, isl_dim_in, i, 1))7266 continue;7267 v = isl_aff_get_coefficient_val(aff, isl_dim_in, i);7268 pa_i = isl_multi_pw_aff_get_pw_aff(mpa, i);7269 pa_i = isl_pw_aff_scale_val(pa_i, v);7270 pa = isl_pw_aff_add(pa, pa_i);7271 }7272 7273 for (i = 0; i < n_div; ++i) {7274 isl_aff *div;7275 isl_pw_aff *pa_i;7276 7277 if (!isl_aff_involves_dims(aff, isl_dim_div, i, 1))7278 continue;7279 div = isl_aff_get_div(aff, i);7280 pa_i = isl_multi_pw_aff_apply_aff_aligned(7281 isl_multi_pw_aff_copy(mpa), div);7282 pa_i = isl_pw_aff_floor(pa_i);7283 v = isl_aff_get_coefficient_val(aff, isl_dim_div, i);7284 pa_i = isl_pw_aff_scale_val(pa_i, v);7285 pa = isl_pw_aff_add(pa, pa_i);7286 }7287 7288 isl_multi_pw_aff_free(mpa);7289 isl_aff_free(aff);7290 7291 return pa;7292error:7293 isl_multi_pw_aff_free(mpa);7294 isl_aff_free(aff);7295 return NULL;7296}7297 7298/* Apply "aff" to "mpa". The range of "mpa" needs to be compatible7299 * with the domain of "aff". The domain of the result is the same7300 * as that of "mpa".7301 */7302__isl_give isl_pw_aff *isl_multi_pw_aff_apply_aff(7303 __isl_take isl_multi_pw_aff *mpa, __isl_take isl_aff *aff)7304{7305 isl_bool equal_params;7306 7307 if (!aff || !mpa)7308 goto error;7309 equal_params = isl_space_has_equal_params(aff->ls->dim, mpa->space);7310 if (equal_params < 0)7311 goto error;7312 if (equal_params)7313 return isl_multi_pw_aff_apply_aff_aligned(mpa, aff);7314 7315 aff = isl_aff_align_params(aff, isl_multi_pw_aff_get_space(mpa));7316 mpa = isl_multi_pw_aff_align_params(mpa, isl_aff_get_space(aff));7317 7318 return isl_multi_pw_aff_apply_aff_aligned(mpa, aff);7319error:7320 isl_aff_free(aff);7321 isl_multi_pw_aff_free(mpa);7322 return NULL;7323}7324 7325/* Apply "pa" to "mpa". The range of "mpa" needs to be compatible7326 * with the domain of "pa". The domain of the result is the same7327 * as that of "mpa".7328 * "mpa" and "pa" are assumed to have been aligned.7329 *7330 * We consider each piece in turn. Note that the domains of the7331 * pieces are assumed to be disjoint and they remain disjoint7332 * after taking the preimage (over the same function).7333 */7334static __isl_give isl_pw_aff *isl_multi_pw_aff_apply_pw_aff_aligned(7335 __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_aff *pa)7336{7337 isl_space *space;7338 isl_pw_aff *res;7339 int i;7340 7341 if (!mpa || !pa)7342 goto error;7343 7344 space = isl_space_join(isl_multi_pw_aff_get_space(mpa),7345 isl_pw_aff_get_space(pa));7346 res = isl_pw_aff_empty(space);7347 7348 for (i = 0; i < pa->n; ++i) {7349 isl_pw_aff *pa_i;7350 isl_set *domain;7351 7352 pa_i = isl_multi_pw_aff_apply_aff_aligned(7353 isl_multi_pw_aff_copy(mpa),7354 isl_aff_copy(pa->p[i].aff));7355 domain = isl_set_copy(pa->p[i].set);7356 domain = isl_set_preimage_multi_pw_aff(domain,7357 isl_multi_pw_aff_copy(mpa));7358 pa_i = isl_pw_aff_intersect_domain(pa_i, domain);7359 res = isl_pw_aff_add_disjoint(res, pa_i);7360 }7361 7362 isl_pw_aff_free(pa);7363 isl_multi_pw_aff_free(mpa);7364 return res;7365error:7366 isl_pw_aff_free(pa);7367 isl_multi_pw_aff_free(mpa);7368 return NULL;7369}7370 7371/* Apply "pa" to "mpa". The range of "mpa" needs to be compatible7372 * with the domain of "pa". The domain of the result is the same7373 * as that of "mpa".7374 */7375__isl_give isl_pw_aff *isl_multi_pw_aff_apply_pw_aff(7376 __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_aff *pa)7377{7378 isl_bool equal_params;7379 7380 if (!pa || !mpa)7381 goto error;7382 equal_params = isl_space_has_equal_params(pa->dim, mpa->space);7383 if (equal_params < 0)7384 goto error;7385 if (equal_params)7386 return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa);7387 7388 pa = isl_pw_aff_align_params(pa, isl_multi_pw_aff_get_space(mpa));7389 mpa = isl_multi_pw_aff_align_params(mpa, isl_pw_aff_get_space(pa));7390 7391 return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa);7392error:7393 isl_pw_aff_free(pa);7394 isl_multi_pw_aff_free(mpa);7395 return NULL;7396}7397 7398/* Compute the pullback of "pa" by the function represented by "mpa".7399 * In other words, plug in "mpa" in "pa".7400 *7401 * The pullback is computed by applying "pa" to "mpa".7402 */7403__isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff(7404 __isl_take isl_pw_aff *pa, __isl_take isl_multi_pw_aff *mpa)7405{7406 return isl_multi_pw_aff_apply_pw_aff(mpa, pa);7407}7408 7409#undef BASE7410#define BASE multi_pw_aff7411 7412#include "isl_multi_pw_aff_pullback_templ.c"7413 7414/* Align the parameters of "mpa1" and "mpa2", check that the ranges7415 * of "mpa1" and "mpa2" live in the same space, construct map space7416 * between the domain spaces of "mpa1" and "mpa2" and call "order"7417 * with this map space as extract argument.7418 */7419static __isl_give isl_map *isl_multi_pw_aff_order_map(7420 __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2,7421 __isl_give isl_map *(*order)(__isl_keep isl_multi_pw_aff *mpa1,7422 __isl_keep isl_multi_pw_aff *mpa2, __isl_take isl_space *space))7423{7424 int match;7425 isl_space *space1, *space2;7426 isl_map *res;7427 7428 mpa1 = isl_multi_pw_aff_align_params(mpa1,7429 isl_multi_pw_aff_get_space(mpa2));7430 mpa2 = isl_multi_pw_aff_align_params(mpa2,7431 isl_multi_pw_aff_get_space(mpa1));7432 if (!mpa1 || !mpa2)7433 goto error;7434 match = isl_space_tuple_is_equal(mpa1->space, isl_dim_out,7435 mpa2->space, isl_dim_out);7436 if (match < 0)7437 goto error;7438 if (!match)7439 isl_die(isl_multi_pw_aff_get_ctx(mpa1), isl_error_invalid,7440 "range spaces don't match", goto error);7441 space1 = isl_space_domain(isl_multi_pw_aff_get_space(mpa1));7442 space2 = isl_space_domain(isl_multi_pw_aff_get_space(mpa2));7443 space1 = isl_space_map_from_domain_and_range(space1, space2);7444 7445 res = order(mpa1, mpa2, space1);7446 isl_multi_pw_aff_free(mpa1);7447 isl_multi_pw_aff_free(mpa2);7448 return res;7449error:7450 isl_multi_pw_aff_free(mpa1);7451 isl_multi_pw_aff_free(mpa2);7452 return NULL;7453}7454 7455/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"7456 * where the function values are equal. "space" is the space of the result.7457 * The parameters of "mpa1" and "mpa2" are assumed to have been aligned.7458 *7459 * "mpa1" and "mpa2" are equal when each of the pairs of elements7460 * in the sequences are equal.7461 */7462static __isl_give isl_map *isl_multi_pw_aff_eq_map_on_space(7463 __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2,7464 __isl_take isl_space *space)7465{7466 int i;7467 isl_size n;7468 isl_map *res;7469 7470 n = isl_multi_pw_aff_dim(mpa1, isl_dim_out);7471 if (n < 0)7472 space = isl_space_free(space);7473 res = isl_map_universe(space);7474 7475 for (i = 0; i < n; ++i) {7476 isl_pw_aff *pa1, *pa2;7477 isl_map *map;7478 7479 pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i);7480 pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i);7481 map = isl_pw_aff_eq_map(pa1, pa2);7482 res = isl_map_intersect(res, map);7483 }7484 7485 return res;7486}7487 7488/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"7489 * where the function values are equal.7490 */7491__isl_give isl_map *isl_multi_pw_aff_eq_map(__isl_take isl_multi_pw_aff *mpa1,7492 __isl_take isl_multi_pw_aff *mpa2)7493{7494 return isl_multi_pw_aff_order_map(mpa1, mpa2,7495 &isl_multi_pw_aff_eq_map_on_space);7496}7497 7498/* Intersect "map" with the result of applying "order"7499 * on two copies of "mpa".7500 */7501static __isl_give isl_map *isl_map_order_at_multi_pw_aff(7502 __isl_take isl_map *map, __isl_take isl_multi_pw_aff *mpa,7503 __isl_give isl_map *(*order)(__isl_take isl_multi_pw_aff *mpa1,7504 __isl_take isl_multi_pw_aff *mpa2))7505{7506 return isl_map_intersect(map, order(mpa, isl_multi_pw_aff_copy(mpa)));7507}7508 7509/* Return the subset of "map" where the domain and the range7510 * have equal "mpa" values.7511 */7512__isl_give isl_map *isl_map_eq_at_multi_pw_aff(__isl_take isl_map *map,7513 __isl_take isl_multi_pw_aff *mpa)7514{7515 return isl_map_order_at_multi_pw_aff(map, mpa,7516 &isl_multi_pw_aff_eq_map);7517}7518 7519/* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2"7520 * where the function values of "mpa1" lexicographically satisfies7521 * "strict_base"/"base" compared to that of "mpa2".7522 * "space" is the space of the result.7523 * The parameters of "mpa1" and "mpa2" are assumed to have been aligned.7524 *7525 * "mpa1" lexicographically satisfies "strict_base"/"base" compared to "mpa2"7526 * if, for some i, the i-th element of "mpa1" satisfies "strict_base"/"base"7527 * when compared to the i-th element of "mpa2" while all previous elements are7528 * pairwise equal.7529 * In particular, if i corresponds to the final elements7530 * then they need to satisfy "base", while "strict_base" needs to be satisfied7531 * for other values of i.7532 * If "base" is a strict order, then "base" and "strict_base" are the same.7533 */7534static __isl_give isl_map *isl_multi_pw_aff_lex_map_on_space(7535 __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2,7536 __isl_give isl_map *(*strict_base)(__isl_take isl_pw_aff *pa1,7537 __isl_take isl_pw_aff *pa2),7538 __isl_give isl_map *(*base)(__isl_take isl_pw_aff *pa1,7539 __isl_take isl_pw_aff *pa2),7540 __isl_take isl_space *space)7541{7542 int i;7543 isl_size n;7544 isl_map *res, *rest;7545 7546 n = isl_multi_pw_aff_dim(mpa1, isl_dim_out);7547 if (n < 0)7548 space = isl_space_free(space);7549 res = isl_map_empty(isl_space_copy(space));7550 rest = isl_map_universe(space);7551 7552 for (i = 0; i < n; ++i) {7553 int last;7554 isl_pw_aff *pa1, *pa2;7555 isl_map *map;7556 7557 last = i == n - 1;7558 7559 pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i);7560 pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i);7561 map = last ? base(pa1, pa2) : strict_base(pa1, pa2);7562 map = isl_map_intersect(map, isl_map_copy(rest));7563 res = isl_map_union(res, map);7564 7565 if (last)7566 continue;7567 7568 pa1 = isl_multi_pw_aff_get_pw_aff(mpa1, i);7569 pa2 = isl_multi_pw_aff_get_pw_aff(mpa2, i);7570 map = isl_pw_aff_eq_map(pa1, pa2);7571 rest = isl_map_intersect(rest, map);7572 }7573 7574 isl_map_free(rest);7575 return res;7576}7577 7578#undef ORDER7579#define ORDER le7580#undef STRICT_ORDER7581#define STRICT_ORDER lt7582#include "isl_aff_lex_templ.c"7583 7584#undef ORDER7585#define ORDER lt7586#undef STRICT_ORDER7587#define STRICT_ORDER lt7588#include "isl_aff_lex_templ.c"7589 7590#undef ORDER7591#define ORDER ge7592#undef STRICT_ORDER7593#define STRICT_ORDER gt7594#include "isl_aff_lex_templ.c"7595 7596#undef ORDER7597#define ORDER gt7598#undef STRICT_ORDER7599#define STRICT_ORDER gt7600#include "isl_aff_lex_templ.c"7601 7602/* Compare two isl_affs.7603 *7604 * Return -1 if "aff1" is "smaller" than "aff2", 1 if "aff1" is "greater"7605 * than "aff2" and 0 if they are equal.7606 *7607 * The order is fairly arbitrary. We do consider expressions that only involve7608 * earlier dimensions as "smaller".7609 */7610int isl_aff_plain_cmp(__isl_keep isl_aff *aff1, __isl_keep isl_aff *aff2)7611{7612 int cmp;7613 int last1, last2;7614 7615 if (aff1 == aff2)7616 return 0;7617 7618 if (!aff1)7619 return -1;7620 if (!aff2)7621 return 1;7622 7623 cmp = isl_local_space_cmp(aff1->ls, aff2->ls);7624 if (cmp != 0)7625 return cmp;7626 7627 last1 = isl_seq_last_non_zero(aff1->v->el + 1, aff1->v->size - 1);7628 last2 = isl_seq_last_non_zero(aff2->v->el + 1, aff1->v->size - 1);7629 if (last1 != last2)7630 return last1 - last2;7631 7632 return isl_seq_cmp(aff1->v->el, aff2->v->el, aff1->v->size);7633}7634 7635/* Compare two isl_pw_affs.7636 *7637 * Return -1 if "pa1" is "smaller" than "pa2", 1 if "pa1" is "greater"7638 * than "pa2" and 0 if they are equal.7639 *7640 * The order is fairly arbitrary. We do consider expressions that only involve7641 * earlier dimensions as "smaller".7642 */7643int isl_pw_aff_plain_cmp(__isl_keep isl_pw_aff *pa1,7644 __isl_keep isl_pw_aff *pa2)7645{7646 int i;7647 int cmp;7648 7649 if (pa1 == pa2)7650 return 0;7651 7652 if (!pa1)7653 return -1;7654 if (!pa2)7655 return 1;7656 7657 cmp = isl_space_cmp(pa1->dim, pa2->dim);7658 if (cmp != 0)7659 return cmp;7660 7661 if (pa1->n != pa2->n)7662 return pa1->n - pa2->n;7663 7664 for (i = 0; i < pa1->n; ++i) {7665 cmp = isl_set_plain_cmp(pa1->p[i].set, pa2->p[i].set);7666 if (cmp != 0)7667 return cmp;7668 cmp = isl_aff_plain_cmp(pa1->p[i].aff, pa2->p[i].aff);7669 if (cmp != 0)7670 return cmp;7671 }7672 7673 return 0;7674}7675 7676/* Return a piecewise affine expression that is equal to "v" on "domain".7677 */7678__isl_give isl_pw_aff *isl_pw_aff_val_on_domain(__isl_take isl_set *domain,7679 __isl_take isl_val *v)7680{7681 isl_space *space;7682 isl_local_space *ls;7683 isl_aff *aff;7684 7685 space = isl_set_get_space(domain);7686 ls = isl_local_space_from_space(space);7687 aff = isl_aff_val_on_domain(ls, v);7688 7689 return isl_pw_aff_alloc(domain, aff);7690}7691 7692/* This function performs the same operation as isl_pw_aff_val_on_domain,7693 * but is considered as a function on an isl_set when exported.7694 */7695__isl_give isl_pw_aff *isl_set_pw_aff_on_domain_val(__isl_take isl_set *domain,7696 __isl_take isl_val *v)7697{7698 return isl_pw_aff_val_on_domain(domain, v);7699}7700 7701/* Return a piecewise affine expression that is equal to the parameter7702 * with identifier "id" on "domain".7703 */7704__isl_give isl_pw_aff *isl_pw_aff_param_on_domain_id(7705 __isl_take isl_set *domain, __isl_take isl_id *id)7706{7707 isl_space *space;7708 isl_aff *aff;7709 7710 space = isl_set_get_space(domain);7711 space = isl_space_add_param_id(space, isl_id_copy(id));7712 domain = isl_set_align_params(domain, isl_space_copy(space));7713 aff = isl_aff_param_on_domain_space_id(space, id);7714 7715 return isl_pw_aff_alloc(domain, aff);7716}7717 7718/* This function performs the same operation as7719 * isl_pw_aff_param_on_domain_id,7720 * but is considered as a function on an isl_set when exported.7721 */7722__isl_give isl_pw_aff *isl_set_param_pw_aff_on_domain_id(7723 __isl_take isl_set *domain, __isl_take isl_id *id)7724{7725 return isl_pw_aff_param_on_domain_id(domain, id);7726}7727 7728/* Return a multi affine expression that is equal to "mv" on domain7729 * space "space".7730 */7731__isl_give isl_multi_aff *isl_multi_aff_multi_val_on_domain_space(7732 __isl_take isl_space *space, __isl_take isl_multi_val *mv)7733{7734 int i;7735 isl_size n;7736 isl_space *space2;7737 isl_local_space *ls;7738 isl_multi_aff *ma;7739 7740 n = isl_multi_val_dim(mv, isl_dim_set);7741 if (!space || n < 0)7742 goto error;7743 7744 space2 = isl_multi_val_get_space(mv);7745 space2 = isl_space_align_params(space2, isl_space_copy(space));7746 space = isl_space_align_params(space, isl_space_copy(space2));7747 space = isl_space_map_from_domain_and_range(space, space2);7748 ma = isl_multi_aff_alloc(isl_space_copy(space));7749 ls = isl_local_space_from_space(isl_space_domain(space));7750 for (i = 0; i < n; ++i) {7751 isl_val *v;7752 isl_aff *aff;7753 7754 v = isl_multi_val_get_val(mv, i);7755 aff = isl_aff_val_on_domain(isl_local_space_copy(ls), v);7756 ma = isl_multi_aff_set_aff(ma, i, aff);7757 }7758 isl_local_space_free(ls);7759 7760 isl_multi_val_free(mv);7761 return ma;7762error:7763 isl_space_free(space);7764 isl_multi_val_free(mv);7765 return NULL;7766}7767 7768/* This is an alternative name for the function above.7769 */7770__isl_give isl_multi_aff *isl_multi_aff_multi_val_on_space(7771 __isl_take isl_space *space, __isl_take isl_multi_val *mv)7772{7773 return isl_multi_aff_multi_val_on_domain_space(space, mv);7774}7775 7776/* This function performs the same operation as7777 * isl_multi_aff_multi_val_on_domain_space,7778 * but is considered as a function on an isl_space when exported.7779 */7780__isl_give isl_multi_aff *isl_space_multi_aff_on_domain_multi_val(7781 __isl_take isl_space *space, __isl_take isl_multi_val *mv)7782{7783 return isl_multi_aff_multi_val_on_domain_space(space, mv);7784}7785 7786/* Return a piecewise multi-affine expression7787 * that is equal to "mv" on "domain".7788 */7789__isl_give isl_pw_multi_aff *isl_pw_multi_aff_multi_val_on_domain(7790 __isl_take isl_set *domain, __isl_take isl_multi_val *mv)7791{7792 isl_space *space;7793 isl_multi_aff *ma;7794 7795 space = isl_set_get_space(domain);7796 ma = isl_multi_aff_multi_val_on_space(space, mv);7797 7798 return isl_pw_multi_aff_alloc(domain, ma);7799}7800 7801/* This function performs the same operation as7802 * isl_pw_multi_aff_multi_val_on_domain,7803 * but is considered as a function on an isl_set when exported.7804 */7805__isl_give isl_pw_multi_aff *isl_set_pw_multi_aff_on_domain_multi_val(7806 __isl_take isl_set *domain, __isl_take isl_multi_val *mv)7807{7808 return isl_pw_multi_aff_multi_val_on_domain(domain, mv);7809}7810 7811/* Internal data structure for isl_union_pw_multi_aff_multi_val_on_domain.7812 * mv is the value that should be attained on each domain set7813 * res collects the results7814 */7815struct isl_union_pw_multi_aff_multi_val_on_domain_data {7816 isl_multi_val *mv;7817 isl_union_pw_multi_aff *res;7818};7819 7820/* Create an isl_pw_multi_aff equal to data->mv on "domain"7821 * and add it to data->res.7822 */7823static isl_stat pw_multi_aff_multi_val_on_domain(__isl_take isl_set *domain,7824 void *user)7825{7826 struct isl_union_pw_multi_aff_multi_val_on_domain_data *data = user;7827 isl_pw_multi_aff *pma;7828 isl_multi_val *mv;7829 7830 mv = isl_multi_val_copy(data->mv);7831 pma = isl_pw_multi_aff_multi_val_on_domain(domain, mv);7832 data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma);7833 7834 return data->res ? isl_stat_ok : isl_stat_error;7835}7836 7837/* Return a union piecewise multi-affine expression7838 * that is equal to "mv" on "domain".7839 */7840__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_multi_val_on_domain(7841 __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv)7842{7843 struct isl_union_pw_multi_aff_multi_val_on_domain_data data;7844 isl_space *space;7845 7846 space = isl_union_set_get_space(domain);7847 data.res = isl_union_pw_multi_aff_empty(space);7848 data.mv = mv;7849 if (isl_union_set_foreach_set(domain,7850 &pw_multi_aff_multi_val_on_domain, &data) < 0)7851 data.res = isl_union_pw_multi_aff_free(data.res);7852 isl_union_set_free(domain);7853 isl_multi_val_free(mv);7854 return data.res;7855}7856 7857/* Compute the pullback of data->pma by the function represented by "pma2",7858 * provided the spaces match, and add the results to data->res.7859 */7860static isl_stat pullback_entry(__isl_take isl_pw_multi_aff *pma2, void *user)7861{7862 struct isl_union_pw_multi_aff_bin_data *data = user;7863 7864 if (!isl_space_tuple_is_equal(data->pma->dim, isl_dim_in,7865 pma2->dim, isl_dim_out)) {7866 isl_pw_multi_aff_free(pma2);7867 return isl_stat_ok;7868 }7869 7870 pma2 = isl_pw_multi_aff_pullback_pw_multi_aff(7871 isl_pw_multi_aff_copy(data->pma), pma2);7872 7873 data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma2);7874 if (!data->res)7875 return isl_stat_error;7876 7877 return isl_stat_ok;7878}7879 7880/* Compute the pullback of "upma1" by the function represented by "upma2".7881 */7882__isl_give isl_union_pw_multi_aff *7883isl_union_pw_multi_aff_pullback_union_pw_multi_aff(7884 __isl_take isl_union_pw_multi_aff *upma1,7885 __isl_take isl_union_pw_multi_aff *upma2)7886{7887 return bin_op(upma1, upma2, &pullback_entry);7888}7889 7890/* Apply "upma2" to "upma1".7891 *7892 * That is, compute the pullback of "upma2" by "upma1".7893 */7894__isl_give isl_union_pw_multi_aff *7895isl_union_pw_multi_aff_apply_union_pw_multi_aff(7896 __isl_take isl_union_pw_multi_aff *upma1,7897 __isl_take isl_union_pw_multi_aff *upma2)7898{7899 return isl_union_pw_multi_aff_pullback_union_pw_multi_aff(upma2, upma1);7900}7901 7902#undef TYPE7903#define TYPE isl_pw_multi_aff7904static7905#include "isl_copy_tuple_id_templ.c"7906 7907/* Given a function "pma1" of the form A[B -> C] -> D and7908 * a function "pma2" of the form E -> B,7909 * replace the domain of the wrapped relation inside the domain of "pma1"7910 * by the preimage with respect to "pma2".7911 * In other words, plug in "pma2" in this nested domain.7912 * The result is of the form A[E -> C] -> D.7913 *7914 * In particular, extend E -> B to A[E -> C] -> A[B -> C] and7915 * plug that into "pma1".7916 */7917__isl_give isl_pw_multi_aff *7918isl_pw_multi_aff_preimage_domain_wrapped_domain_pw_multi_aff(7919 __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2)7920{7921 isl_space *pma1_space, *pma2_space;7922 isl_space *space;7923 isl_pw_multi_aff *id;7924 7925 pma1_space = isl_pw_multi_aff_peek_space(pma1);7926 pma2_space = isl_pw_multi_aff_peek_space(pma2);7927 7928 if (isl_space_check_domain_is_wrapping(pma1_space) < 0)7929 goto error;7930 if (isl_space_check_wrapped_tuple_is_equal(pma1_space,7931 isl_dim_in, isl_dim_in, pma2_space, isl_dim_out) < 0)7932 goto error;7933 7934 space = isl_space_domain(isl_space_copy(pma1_space));7935 space = isl_space_range(isl_space_unwrap(space));7936 id = isl_pw_multi_aff_identity_on_domain_space(space);7937 pma2 = isl_pw_multi_aff_product(pma2, id);7938 7939 pma2 = isl_pw_multi_aff_copy_tuple_id(pma2, isl_dim_in,7940 pma1_space, isl_dim_in);7941 pma2 = isl_pw_multi_aff_copy_tuple_id(pma2, isl_dim_out,7942 pma1_space, isl_dim_in);7943 7944 return isl_pw_multi_aff_pullback_pw_multi_aff(pma1, pma2);7945error:7946 isl_pw_multi_aff_free(pma1);7947 isl_pw_multi_aff_free(pma2);7948 return NULL;7949}7950 7951/* If data->pma and "pma2" are such that7952 * data->pma is of the form A[B -> C] -> D and7953 * "pma2" is of the form E -> B,7954 * then replace the domain of the wrapped relation7955 * inside the domain of data->pma by the preimage with respect to "pma2" and7956 * add the result to data->res.7957 */7958static isl_stat preimage_domain_wrapped_domain_entry(7959 __isl_take isl_pw_multi_aff *pma2, void *user)7960{7961 struct isl_union_pw_multi_aff_bin_data *data = user;7962 isl_space *pma1_space, *pma2_space;7963 isl_bool match;7964 7965 pma1_space = isl_pw_multi_aff_peek_space(data->pma);7966 pma2_space = isl_pw_multi_aff_peek_space(pma2);7967 7968 match = isl_space_domain_is_wrapping(pma1_space);7969 if (match >= 0 && match)7970 match = isl_space_wrapped_tuple_is_equal(pma1_space, isl_dim_in,7971 isl_dim_in, pma2_space, isl_dim_out);7972 if (match < 0 || !match) {7973 isl_pw_multi_aff_free(pma2);7974 return match < 0 ? isl_stat_error : isl_stat_ok;7975 }7976 7977 pma2 = isl_pw_multi_aff_preimage_domain_wrapped_domain_pw_multi_aff(7978 isl_pw_multi_aff_copy(data->pma), pma2);7979 7980 data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma2);7981 7982 return isl_stat_non_null(data->res);7983}7984 7985/* For each pair of functions A[B -> C] -> D in "upma1" and7986 * E -> B in "upma2",7987 * replace the domain of the wrapped relation inside the domain of the first7988 * by the preimage with respect to the second and collect the results.7989 * In other words, plug in the second function in this nested domain.7990 * The results are of the form A[E -> C] -> D.7991 */7992__isl_give isl_union_pw_multi_aff *7993isl_union_pw_multi_aff_preimage_domain_wrapped_domain_union_pw_multi_aff(7994 __isl_take isl_union_pw_multi_aff *upma1,7995 __isl_take isl_union_pw_multi_aff *upma2)7996{7997 return bin_op(upma1, upma2, &preimage_domain_wrapped_domain_entry);7998}7999 8000/* Check that the domain space of "upa" matches "space".8001 *8002 * This function is called from isl_multi_union_pw_aff_set_union_pw_aff and8003 * can in principle never fail since the space "space" is that8004 * of the isl_multi_union_pw_aff and is a set space such that8005 * there is no domain space to match.8006 *8007 * We check the parameters and double-check that "space" is8008 * indeed that of a set.8009 */8010static isl_stat isl_union_pw_aff_check_match_domain_space(8011 __isl_keep isl_union_pw_aff *upa, __isl_keep isl_space *space)8012{8013 isl_space *upa_space;8014 isl_bool match;8015 8016 if (!upa || !space)8017 return isl_stat_error;8018 8019 match = isl_space_is_set(space);8020 if (match < 0)8021 return isl_stat_error;8022 if (!match)8023 isl_die(isl_space_get_ctx(space), isl_error_invalid,8024 "expecting set space", return isl_stat_error);8025 8026 upa_space = isl_union_pw_aff_get_space(upa);8027 match = isl_space_has_equal_params(space, upa_space);8028 if (match < 0)8029 goto error;8030 if (!match)8031 isl_die(isl_space_get_ctx(space), isl_error_invalid,8032 "parameters don't match", goto error);8033 8034 isl_space_free(upa_space);8035 return isl_stat_ok;8036error:8037 isl_space_free(upa_space);8038 return isl_stat_error;8039}8040 8041/* Do the parameters of "upa" match those of "space"?8042 */8043static isl_bool isl_union_pw_aff_matching_params(8044 __isl_keep isl_union_pw_aff *upa, __isl_keep isl_space *space)8045{8046 isl_space *upa_space;8047 isl_bool match;8048 8049 if (!upa || !space)8050 return isl_bool_error;8051 8052 upa_space = isl_union_pw_aff_get_space(upa);8053 8054 match = isl_space_has_equal_params(space, upa_space);8055 8056 isl_space_free(upa_space);8057 return match;8058}8059 8060/* Internal data structure for isl_union_pw_aff_reset_domain_space.8061 * space represents the new parameters.8062 * res collects the results.8063 */8064struct isl_union_pw_aff_reset_params_data {8065 isl_space *space;8066 isl_union_pw_aff *res;8067};8068 8069/* Replace the parameters of "pa" by data->space and8070 * add the result to data->res.8071 */8072static isl_stat reset_params(__isl_take isl_pw_aff *pa, void *user)8073{8074 struct isl_union_pw_aff_reset_params_data *data = user;8075 isl_space *space;8076 8077 space = isl_pw_aff_get_space(pa);8078 space = isl_space_replace_params(space, data->space);8079 pa = isl_pw_aff_reset_space(pa, space);8080 data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);8081 8082 return data->res ? isl_stat_ok : isl_stat_error;8083}8084 8085/* Replace the domain space of "upa" by "space".8086 * Since a union expression does not have a (single) domain space,8087 * "space" is necessarily a parameter space.8088 *8089 * Since the order and the names of the parameters determine8090 * the hash value, we need to create a new hash table.8091 */8092static __isl_give isl_union_pw_aff *isl_union_pw_aff_reset_domain_space(8093 __isl_take isl_union_pw_aff *upa, __isl_take isl_space *space)8094{8095 struct isl_union_pw_aff_reset_params_data data = { space };8096 isl_bool match;8097 8098 match = isl_union_pw_aff_matching_params(upa, space);8099 if (match < 0)8100 upa = isl_union_pw_aff_free(upa);8101 else if (match) {8102 isl_space_free(space);8103 return upa;8104 }8105 8106 data.res = isl_union_pw_aff_empty(isl_space_copy(space));8107 if (isl_union_pw_aff_foreach_pw_aff(upa, &reset_params, &data) < 0)8108 data.res = isl_union_pw_aff_free(data.res);8109 8110 isl_union_pw_aff_free(upa);8111 isl_space_free(space);8112 return data.res;8113}8114 8115/* Return the floor of "pa".8116 */8117static __isl_give isl_pw_aff *floor_entry(__isl_take isl_pw_aff *pa, void *user)8118{8119 return isl_pw_aff_floor(pa);8120}8121 8122/* Given f, return floor(f).8123 */8124__isl_give isl_union_pw_aff *isl_union_pw_aff_floor(8125 __isl_take isl_union_pw_aff *upa)8126{8127 return isl_union_pw_aff_transform_inplace(upa, &floor_entry, NULL);8128}8129 8130/* Compute8131 *8132 * upa mod m = upa - m * floor(upa/m)8133 *8134 * with m an integer value.8135 */8136__isl_give isl_union_pw_aff *isl_union_pw_aff_mod_val(8137 __isl_take isl_union_pw_aff *upa, __isl_take isl_val *m)8138{8139 isl_union_pw_aff *res;8140 8141 if (!upa || !m)8142 goto error;8143 8144 if (!isl_val_is_int(m))8145 isl_die(isl_val_get_ctx(m), isl_error_invalid,8146 "expecting integer modulo", goto error);8147 if (!isl_val_is_pos(m))8148 isl_die(isl_val_get_ctx(m), isl_error_invalid,8149 "expecting positive modulo", goto error);8150 8151 res = isl_union_pw_aff_copy(upa);8152 upa = isl_union_pw_aff_scale_down_val(upa, isl_val_copy(m));8153 upa = isl_union_pw_aff_floor(upa);8154 upa = isl_union_pw_aff_scale_val(upa, m);8155 res = isl_union_pw_aff_sub(res, upa);8156 8157 return res;8158error:8159 isl_val_free(m);8160 isl_union_pw_aff_free(upa);8161 return NULL;8162}8163 8164/* Internal data structure for isl_union_pw_multi_aff_get_union_pw_aff.8165 * pos is the output position that needs to be extracted.8166 * res collects the results.8167 */8168struct isl_union_pw_multi_aff_get_union_pw_aff_data {8169 int pos;8170 isl_union_pw_aff *res;8171};8172 8173/* Extract an isl_pw_aff corresponding to output dimension "pos" of "pma"8174 * (assuming it has such a dimension) and add it to data->res.8175 */8176static isl_stat get_union_pw_aff(__isl_take isl_pw_multi_aff *pma, void *user)8177{8178 struct isl_union_pw_multi_aff_get_union_pw_aff_data *data = user;8179 isl_size n_out;8180 isl_pw_aff *pa;8181 8182 n_out = isl_pw_multi_aff_dim(pma, isl_dim_out);8183 if (n_out < 0)8184 return isl_stat_error;8185 if (data->pos >= n_out) {8186 isl_pw_multi_aff_free(pma);8187 return isl_stat_ok;8188 }8189 8190 pa = isl_pw_multi_aff_get_pw_aff(pma, data->pos);8191 isl_pw_multi_aff_free(pma);8192 8193 data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);8194 8195 return data->res ? isl_stat_ok : isl_stat_error;8196}8197 8198/* Extract an isl_union_pw_aff corresponding to8199 * output dimension "pos" of "upma".8200 */8201__isl_give isl_union_pw_aff *isl_union_pw_multi_aff_get_union_pw_aff(8202 __isl_keep isl_union_pw_multi_aff *upma, int pos)8203{8204 struct isl_union_pw_multi_aff_get_union_pw_aff_data data;8205 isl_space *space;8206 8207 if (!upma)8208 return NULL;8209 8210 if (pos < 0)8211 isl_die(isl_union_pw_multi_aff_get_ctx(upma), isl_error_invalid,8212 "cannot extract at negative position", return NULL);8213 8214 space = isl_union_pw_multi_aff_get_space(upma);8215 data.res = isl_union_pw_aff_empty(space);8216 data.pos = pos;8217 if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,8218 &get_union_pw_aff, &data) < 0)8219 data.res = isl_union_pw_aff_free(data.res);8220 8221 return data.res;8222}8223 8224/* Return a union piecewise affine expression8225 * that is equal to "aff" on "domain".8226 */8227__isl_give isl_union_pw_aff *isl_union_pw_aff_aff_on_domain(8228 __isl_take isl_union_set *domain, __isl_take isl_aff *aff)8229{8230 isl_pw_aff *pa;8231 8232 pa = isl_pw_aff_from_aff(aff);8233 return isl_union_pw_aff_pw_aff_on_domain(domain, pa);8234}8235 8236/* Return a union piecewise affine expression8237 * that is equal to the parameter identified by "id" on "domain".8238 *8239 * Make sure the parameter appears in the space passed to8240 * isl_aff_param_on_domain_space_id.8241 */8242__isl_give isl_union_pw_aff *isl_union_pw_aff_param_on_domain_id(8243 __isl_take isl_union_set *domain, __isl_take isl_id *id)8244{8245 isl_space *space;8246 isl_aff *aff;8247 8248 space = isl_union_set_get_space(domain);8249 space = isl_space_add_param_id(space, isl_id_copy(id));8250 aff = isl_aff_param_on_domain_space_id(space, id);8251 return isl_union_pw_aff_aff_on_domain(domain, aff);8252}8253 8254/* Internal data structure for isl_union_pw_aff_pw_aff_on_domain.8255 * "pa" is the piecewise symbolic value that the resulting isl_union_pw_aff8256 * needs to attain.8257 * "res" collects the results.8258 */8259struct isl_union_pw_aff_pw_aff_on_domain_data {8260 isl_pw_aff *pa;8261 isl_union_pw_aff *res;8262};8263 8264/* Construct a piecewise affine expression that is equal to data->pa8265 * on "domain" and add the result to data->res.8266 */8267static isl_stat pw_aff_on_domain(__isl_take isl_set *domain, void *user)8268{8269 struct isl_union_pw_aff_pw_aff_on_domain_data *data = user;8270 isl_pw_aff *pa;8271 isl_size dim;8272 8273 pa = isl_pw_aff_copy(data->pa);8274 dim = isl_set_dim(domain, isl_dim_set);8275 if (dim < 0)8276 pa = isl_pw_aff_free(pa);8277 pa = isl_pw_aff_from_range(pa);8278 pa = isl_pw_aff_add_dims(pa, isl_dim_in, dim);8279 pa = isl_pw_aff_reset_domain_space(pa, isl_set_get_space(domain));8280 pa = isl_pw_aff_intersect_domain(pa, domain);8281 data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);8282 8283 return data->res ? isl_stat_ok : isl_stat_error;8284}8285 8286/* Return a union piecewise affine expression8287 * that is equal to "pa" on "domain", assuming "domain" and "pa"8288 * have been aligned.8289 *8290 * Construct an isl_pw_aff on each of the sets in "domain" and8291 * collect the results.8292 */8293static __isl_give isl_union_pw_aff *isl_union_pw_aff_pw_aff_on_domain_aligned(8294 __isl_take isl_union_set *domain, __isl_take isl_pw_aff *pa)8295{8296 struct isl_union_pw_aff_pw_aff_on_domain_data data;8297 isl_space *space;8298 8299 space = isl_union_set_get_space(domain);8300 data.res = isl_union_pw_aff_empty(space);8301 data.pa = pa;8302 if (isl_union_set_foreach_set(domain, &pw_aff_on_domain, &data) < 0)8303 data.res = isl_union_pw_aff_free(data.res);8304 isl_union_set_free(domain);8305 isl_pw_aff_free(pa);8306 return data.res;8307}8308 8309/* Return a union piecewise affine expression8310 * that is equal to "pa" on "domain".8311 *8312 * Check that "pa" is a parametric expression,8313 * align the parameters if needed and call8314 * isl_union_pw_aff_pw_aff_on_domain_aligned.8315 */8316__isl_give isl_union_pw_aff *isl_union_pw_aff_pw_aff_on_domain(8317 __isl_take isl_union_set *domain, __isl_take isl_pw_aff *pa)8318{8319 isl_bool is_set;8320 isl_bool equal_params;8321 isl_space *domain_space, *pa_space;8322 8323 pa_space = isl_pw_aff_peek_space(pa);8324 is_set = isl_space_is_set(pa_space);8325 if (is_set < 0)8326 goto error;8327 if (!is_set)8328 isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,8329 "expecting parametric expression", goto error);8330 8331 domain_space = isl_union_set_get_space(domain);8332 pa_space = isl_pw_aff_get_space(pa);8333 equal_params = isl_space_has_equal_params(domain_space, pa_space);8334 if (equal_params >= 0 && !equal_params) {8335 isl_space *space;8336 8337 space = isl_space_align_params(domain_space, pa_space);8338 pa = isl_pw_aff_align_params(pa, isl_space_copy(space));8339 domain = isl_union_set_align_params(domain, space);8340 } else {8341 isl_space_free(domain_space);8342 isl_space_free(pa_space);8343 }8344 8345 if (equal_params < 0)8346 goto error;8347 return isl_union_pw_aff_pw_aff_on_domain_aligned(domain, pa);8348error:8349 isl_union_set_free(domain);8350 isl_pw_aff_free(pa);8351 return NULL;8352}8353 8354/* Internal data structure for isl_union_pw_aff_val_on_domain.8355 * "v" is the value that the resulting isl_union_pw_aff needs to attain.8356 * "res" collects the results.8357 */8358struct isl_union_pw_aff_val_on_domain_data {8359 isl_val *v;8360 isl_union_pw_aff *res;8361};8362 8363/* Construct a piecewise affine expression that is equal to data->v8364 * on "domain" and add the result to data->res.8365 */8366static isl_stat pw_aff_val_on_domain(__isl_take isl_set *domain, void *user)8367{8368 struct isl_union_pw_aff_val_on_domain_data *data = user;8369 isl_pw_aff *pa;8370 isl_val *v;8371 8372 v = isl_val_copy(data->v);8373 pa = isl_pw_aff_val_on_domain(domain, v);8374 data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);8375 8376 return data->res ? isl_stat_ok : isl_stat_error;8377}8378 8379/* Return a union piecewise affine expression8380 * that is equal to "v" on "domain".8381 *8382 * Construct an isl_pw_aff on each of the sets in "domain" and8383 * collect the results.8384 */8385__isl_give isl_union_pw_aff *isl_union_pw_aff_val_on_domain(8386 __isl_take isl_union_set *domain, __isl_take isl_val *v)8387{8388 struct isl_union_pw_aff_val_on_domain_data data;8389 isl_space *space;8390 8391 space = isl_union_set_get_space(domain);8392 data.res = isl_union_pw_aff_empty(space);8393 data.v = v;8394 if (isl_union_set_foreach_set(domain, &pw_aff_val_on_domain, &data) < 0)8395 data.res = isl_union_pw_aff_free(data.res);8396 isl_union_set_free(domain);8397 isl_val_free(v);8398 return data.res;8399}8400 8401/* Construct a piecewise multi affine expression8402 * that is equal to "pa" and add it to upma.8403 */8404static isl_stat pw_multi_aff_from_pw_aff_entry(__isl_take isl_pw_aff *pa,8405 void *user)8406{8407 isl_union_pw_multi_aff **upma = user;8408 isl_pw_multi_aff *pma;8409 8410 pma = isl_pw_multi_aff_from_pw_aff(pa);8411 *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma);8412 8413 return *upma ? isl_stat_ok : isl_stat_error;8414}8415 8416/* Construct and return a union piecewise multi affine expression8417 * that is equal to the given union piecewise affine expression.8418 */8419__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_pw_aff(8420 __isl_take isl_union_pw_aff *upa)8421{8422 isl_space *space;8423 isl_union_pw_multi_aff *upma;8424 8425 if (!upa)8426 return NULL;8427 8428 space = isl_union_pw_aff_get_space(upa);8429 upma = isl_union_pw_multi_aff_empty(space);8430 8431 if (isl_union_pw_aff_foreach_pw_aff(upa,8432 &pw_multi_aff_from_pw_aff_entry, &upma) < 0)8433 upma = isl_union_pw_multi_aff_free(upma);8434 8435 isl_union_pw_aff_free(upa);8436 return upma;8437}8438 8439/* Compute the set of elements in the domain of "pa" where it is zero and8440 * add this set to "uset".8441 */8442static isl_stat zero_union_set(__isl_take isl_pw_aff *pa, void *user)8443{8444 isl_union_set **uset = (isl_union_set **)user;8445 8446 *uset = isl_union_set_add_set(*uset, isl_pw_aff_zero_set(pa));8447 8448 return *uset ? isl_stat_ok : isl_stat_error;8449}8450 8451/* Return a union set containing those elements in the domain8452 * of "upa" where it is zero.8453 */8454__isl_give isl_union_set *isl_union_pw_aff_zero_union_set(8455 __isl_take isl_union_pw_aff *upa)8456{8457 isl_union_set *zero;8458 8459 zero = isl_union_set_empty(isl_union_pw_aff_get_space(upa));8460 if (isl_union_pw_aff_foreach_pw_aff(upa, &zero_union_set, &zero) < 0)8461 zero = isl_union_set_free(zero);8462 8463 isl_union_pw_aff_free(upa);8464 return zero;8465}8466 8467/* Internal data structure for isl_union_pw_aff_bind_id,8468 * storing the parameter that needs to be bound and8469 * the accumulated results.8470 */8471struct isl_bind_id_data {8472 isl_id *id;8473 isl_union_set *bound;8474};8475 8476/* Bind the piecewise affine function "pa" to the parameter data->id,8477 * adding the resulting elements in the domain where the expression8478 * is equal to the parameter to data->bound.8479 */8480static isl_stat bind_id(__isl_take isl_pw_aff *pa, void *user)8481{8482 struct isl_bind_id_data *data = user;8483 isl_set *bound;8484 8485 bound = isl_pw_aff_bind_id(pa, isl_id_copy(data->id));8486 data->bound = isl_union_set_add_set(data->bound, bound);8487 8488 return data->bound ? isl_stat_ok : isl_stat_error;8489}8490 8491/* Bind the union piecewise affine function "upa" to the parameter "id",8492 * returning the elements in the domain where the expression8493 * is equal to the parameter.8494 */8495__isl_give isl_union_set *isl_union_pw_aff_bind_id(8496 __isl_take isl_union_pw_aff *upa, __isl_take isl_id *id)8497{8498 struct isl_bind_id_data data = { id };8499 8500 data.bound = isl_union_set_empty(isl_union_pw_aff_get_space(upa));8501 if (isl_union_pw_aff_foreach_pw_aff(upa, &bind_id, &data) < 0)8502 data.bound = isl_union_set_free(data.bound);8503 8504 isl_union_pw_aff_free(upa);8505 isl_id_free(id);8506 return data.bound;8507}8508 8509/* Internal data structure for isl_union_pw_aff_pullback_union_pw_multi_aff.8510 * upma is the function that is plugged in.8511 * pa is the current part of the function in which upma is plugged in.8512 * res collects the results.8513 */8514struct isl_union_pw_aff_pullback_upma_data {8515 isl_union_pw_multi_aff *upma;8516 isl_pw_aff *pa;8517 isl_union_pw_aff *res;8518};8519 8520/* Check if "pma" can be plugged into data->pa.8521 * If so, perform the pullback and add the result to data->res.8522 */8523static isl_stat pa_pb_pma(__isl_take isl_pw_multi_aff *pma, void *user)8524{8525 struct isl_union_pw_aff_pullback_upma_data *data = user;8526 isl_pw_aff *pa;8527 8528 if (!isl_space_tuple_is_equal(data->pa->dim, isl_dim_in,8529 pma->dim, isl_dim_out)) {8530 isl_pw_multi_aff_free(pma);8531 return isl_stat_ok;8532 }8533 8534 pa = isl_pw_aff_copy(data->pa);8535 pa = isl_pw_aff_pullback_pw_multi_aff(pa, pma);8536 8537 data->res = isl_union_pw_aff_add_pw_aff(data->res, pa);8538 8539 return data->res ? isl_stat_ok : isl_stat_error;8540}8541 8542/* Check if any of the elements of data->upma can be plugged into pa,8543 * add if so add the result to data->res.8544 */8545static isl_stat upa_pb_upma(__isl_take isl_pw_aff *pa, void *user)8546{8547 struct isl_union_pw_aff_pullback_upma_data *data = user;8548 isl_stat r;8549 8550 data->pa = pa;8551 r = isl_union_pw_multi_aff_foreach_pw_multi_aff(data->upma,8552 &pa_pb_pma, data);8553 isl_pw_aff_free(pa);8554 8555 return r;8556}8557 8558/* Compute the pullback of "upa" by the function represented by "upma".8559 * In other words, plug in "upma" in "upa". The result contains8560 * expressions defined over the domain space of "upma".8561 *8562 * Run over all pairs of elements in "upa" and "upma", perform8563 * the pullback when appropriate and collect the results.8564 * If the hash value were based on the domain space rather than8565 * the function space, then we could run through all elements8566 * of "upma" and directly pick out the corresponding element of "upa".8567 */8568__isl_give isl_union_pw_aff *isl_union_pw_aff_pullback_union_pw_multi_aff(8569 __isl_take isl_union_pw_aff *upa,8570 __isl_take isl_union_pw_multi_aff *upma)8571{8572 struct isl_union_pw_aff_pullback_upma_data data = { NULL, NULL };8573 isl_space *space;8574 8575 space = isl_union_pw_multi_aff_get_space(upma);8576 upa = isl_union_pw_aff_align_params(upa, space);8577 space = isl_union_pw_aff_get_space(upa);8578 upma = isl_union_pw_multi_aff_align_params(upma, space);8579 8580 if (!upa || !upma)8581 goto error;8582 8583 data.upma = upma;8584 data.res = isl_union_pw_aff_alloc_same_size(upa);8585 if (isl_union_pw_aff_foreach_pw_aff(upa, &upa_pb_upma, &data) < 0)8586 data.res = isl_union_pw_aff_free(data.res);8587 8588 isl_union_pw_aff_free(upa);8589 isl_union_pw_multi_aff_free(upma);8590 return data.res;8591error:8592 isl_union_pw_aff_free(upa);8593 isl_union_pw_multi_aff_free(upma);8594 return NULL;8595}8596 8597#undef BASE8598#define BASE union_pw_aff8599#undef DOMBASE8600#define DOMBASE union_set8601 8602#include <isl_multi_explicit_domain.c>8603#include <isl_multi_union_pw_aff_explicit_domain.c>8604#include <isl_multi_templ.c>8605#include <isl_multi_un_op_templ.c>8606#include <isl_multi_bin_val_templ.c>8607#include <isl_multi_apply_set.c>8608#include <isl_multi_apply_union_set.c>8609#include <isl_multi_arith_templ.c>8610#include <isl_multi_bind_templ.c>8611#include <isl_multi_coalesce.c>8612#include <isl_multi_dim_id_templ.c>8613#include <isl_multi_floor.c>8614#include <isl_multi_from_base_templ.c>8615#include <isl_multi_gist.c>8616#include <isl_multi_align_set.c>8617#include <isl_multi_align_union_set.c>8618#include <isl_multi_intersect.c>8619#include <isl_multi_nan_templ.c>8620#include <isl_multi_tuple_id_templ.c>8621#include <isl_multi_union_add_templ.c>8622#include <isl_multi_zero_space_templ.c>8623 8624/* Does "mupa" have a non-trivial explicit domain?8625 *8626 * The explicit domain, if present, is trivial if it represents8627 * an (obviously) universe parameter set.8628 */8629isl_bool isl_multi_union_pw_aff_has_non_trivial_domain(8630 __isl_keep isl_multi_union_pw_aff *mupa)8631{8632 isl_bool is_params, trivial;8633 isl_set *set;8634 8635 if (!mupa)8636 return isl_bool_error;8637 if (!isl_multi_union_pw_aff_has_explicit_domain(mupa))8638 return isl_bool_false;8639 is_params = isl_union_set_is_params(mupa->u.dom);8640 if (is_params < 0 || !is_params)8641 return isl_bool_not(is_params);8642 set = isl_set_from_union_set(isl_union_set_copy(mupa->u.dom));8643 trivial = isl_set_plain_is_universe(set);8644 isl_set_free(set);8645 return isl_bool_not(trivial);8646}8647 8648/* Construct a multiple union piecewise affine expression8649 * in the given space with value zero in each of the output dimensions.8650 *8651 * Since there is no canonical zero value for8652 * a union piecewise affine expression, we can only construct8653 * a zero-dimensional "zero" value.8654 */8655__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_zero(8656 __isl_take isl_space *space)8657{8658 isl_bool params;8659 isl_size dim;8660 8661 if (!space)8662 return NULL;8663 8664 params = isl_space_is_params(space);8665 if (params < 0)8666 goto error;8667 if (params)8668 isl_die(isl_space_get_ctx(space), isl_error_invalid,8669 "expecting proper set space", goto error);8670 if (!isl_space_is_set(space))8671 isl_die(isl_space_get_ctx(space), isl_error_invalid,8672 "expecting set space", goto error);8673 dim = isl_space_dim(space, isl_dim_out);8674 if (dim < 0)8675 goto error;8676 if (dim != 0)8677 isl_die(isl_space_get_ctx(space), isl_error_invalid,8678 "expecting 0D space", goto error);8679 8680 return isl_multi_union_pw_aff_alloc(space);8681error:8682 isl_space_free(space);8683 return NULL;8684}8685 8686/* Construct and return a multi union piecewise affine expression8687 * that is equal to the given multi affine expression.8688 */8689__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_aff(8690 __isl_take isl_multi_aff *ma)8691{8692 isl_multi_pw_aff *mpa;8693 8694 mpa = isl_multi_pw_aff_from_multi_aff(ma);8695 return isl_multi_union_pw_aff_from_multi_pw_aff(mpa);8696}8697 8698/* This function performs the same operation as8699 * isl_multi_union_pw_aff_from_multi_aff, but is considered as a function on an8700 * isl_multi_aff when exported.8701 */8702__isl_give isl_multi_union_pw_aff *isl_multi_aff_to_multi_union_pw_aff(8703 __isl_take isl_multi_aff *ma)8704{8705 return isl_multi_union_pw_aff_from_multi_aff(ma);8706}8707 8708/* Construct and return a multi union piecewise affine expression8709 * that is equal to the given multi piecewise affine expression.8710 *8711 * If the resulting multi union piecewise affine expression has8712 * an explicit domain, then assign it the domain of the input.8713 * In other cases, the domain is stored in the individual elements.8714 */8715__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_pw_aff(8716 __isl_take isl_multi_pw_aff *mpa)8717{8718 int i;8719 isl_size n;8720 isl_space *space;8721 isl_multi_union_pw_aff *mupa;8722 8723 n = isl_multi_pw_aff_dim(mpa, isl_dim_out);8724 if (n < 0)8725 mpa = isl_multi_pw_aff_free(mpa);8726 if (!mpa)8727 return NULL;8728 8729 space = isl_multi_pw_aff_get_space(mpa);8730 space = isl_space_range(space);8731 mupa = isl_multi_union_pw_aff_alloc(space);8732 8733 for (i = 0; i < n; ++i) {8734 isl_pw_aff *pa;8735 isl_union_pw_aff *upa;8736 8737 pa = isl_multi_pw_aff_get_pw_aff(mpa, i);8738 upa = isl_union_pw_aff_from_pw_aff(pa);8739 mupa = isl_multi_union_pw_aff_restore_check_space(mupa, i, upa);8740 }8741 if (isl_multi_union_pw_aff_has_explicit_domain(mupa)) {8742 isl_union_set *dom;8743 isl_multi_pw_aff *copy;8744 8745 copy = isl_multi_pw_aff_copy(mpa);8746 dom = isl_union_set_from_set(isl_multi_pw_aff_domain(copy));8747 mupa = isl_multi_union_pw_aff_intersect_domain(mupa, dom);8748 }8749 8750 isl_multi_pw_aff_free(mpa);8751 8752 return mupa;8753}8754 8755/* Extract the range space of "pma" and assign it to *space.8756 * If *space has already been set (through a previous call to this function),8757 * then check that the range space is the same.8758 */8759static isl_stat extract_space(__isl_take isl_pw_multi_aff *pma, void *user)8760{8761 isl_space **space = user;8762 isl_space *pma_space;8763 isl_bool equal;8764 8765 pma_space = isl_space_range(isl_pw_multi_aff_get_space(pma));8766 isl_pw_multi_aff_free(pma);8767 8768 if (!pma_space)8769 return isl_stat_error;8770 if (!*space) {8771 *space = pma_space;8772 return isl_stat_ok;8773 }8774 8775 equal = isl_space_is_equal(pma_space, *space);8776 isl_space_free(pma_space);8777 8778 if (equal < 0)8779 return isl_stat_error;8780 if (!equal)8781 isl_die(isl_space_get_ctx(*space), isl_error_invalid,8782 "range spaces not the same", return isl_stat_error);8783 return isl_stat_ok;8784}8785 8786/* Construct and return a multi union piecewise affine expression8787 * that is equal to the given union piecewise multi affine expression.8788 *8789 * In order to be able to perform the conversion, the input8790 * needs to be non-empty and may only involve a single range space.8791 *8792 * If the resulting multi union piecewise affine expression has8793 * an explicit domain, then assign it the domain of the input.8794 * In other cases, the domain is stored in the individual elements.8795 */8796__isl_give isl_multi_union_pw_aff *8797isl_multi_union_pw_aff_from_union_pw_multi_aff(8798 __isl_take isl_union_pw_multi_aff *upma)8799{8800 isl_space *space = NULL;8801 isl_multi_union_pw_aff *mupa;8802 int i;8803 isl_size n;8804 8805 n = isl_union_pw_multi_aff_n_pw_multi_aff(upma);8806 if (n < 0)8807 goto error;8808 if (n == 0)8809 isl_die(isl_union_pw_multi_aff_get_ctx(upma), isl_error_invalid,8810 "cannot extract range space from empty input",8811 goto error);8812 if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma, &extract_space,8813 &space) < 0)8814 goto error;8815 8816 if (!space)8817 goto error;8818 8819 n = isl_space_dim(space, isl_dim_set);8820 if (n < 0)8821 space = isl_space_free(space);8822 mupa = isl_multi_union_pw_aff_alloc(space);8823 8824 for (i = 0; i < n; ++i) {8825 isl_union_pw_aff *upa;8826 8827 upa = isl_union_pw_multi_aff_get_union_pw_aff(upma, i);8828 mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);8829 }8830 if (isl_multi_union_pw_aff_has_explicit_domain(mupa)) {8831 isl_union_set *dom;8832 isl_union_pw_multi_aff *copy;8833 8834 copy = isl_union_pw_multi_aff_copy(upma);8835 dom = isl_union_pw_multi_aff_domain(copy);8836 mupa = isl_multi_union_pw_aff_intersect_domain(mupa, dom);8837 }8838 8839 isl_union_pw_multi_aff_free(upma);8840 return mupa;8841error:8842 isl_space_free(space);8843 isl_union_pw_multi_aff_free(upma);8844 return NULL;8845}8846 8847/* This function performs the same operation as8848 * isl_multi_union_pw_aff_from_union_pw_multi_aff,8849 * but is considered as a function on an isl_union_pw_multi_aff when exported.8850 */8851__isl_give isl_multi_union_pw_aff *8852isl_union_pw_multi_aff_as_multi_union_pw_aff(8853 __isl_take isl_union_pw_multi_aff *upma)8854{8855 return isl_multi_union_pw_aff_from_union_pw_multi_aff(upma);8856}8857 8858/* Try and create an isl_multi_union_pw_aff that is equivalent8859 * to the given isl_union_map.8860 * The isl_union_map is required to be single-valued in each space.8861 * Moreover, it cannot be empty and all range spaces need to be the same.8862 * Otherwise, an error is produced.8863 */8864__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_union_map(8865 __isl_take isl_union_map *umap)8866{8867 isl_union_pw_multi_aff *upma;8868 8869 upma = isl_union_pw_multi_aff_from_union_map(umap);8870 return isl_multi_union_pw_aff_from_union_pw_multi_aff(upma);8871}8872 8873/* This function performs the same operation as8874 * isl_multi_union_pw_aff_from_union_map,8875 * but is considered as a function on an isl_union_map when exported.8876 */8877__isl_give isl_multi_union_pw_aff *isl_union_map_as_multi_union_pw_aff(8878 __isl_take isl_union_map *umap)8879{8880 return isl_multi_union_pw_aff_from_union_map(umap);8881}8882 8883/* Return a multiple union piecewise affine expression8884 * that is equal to "mv" on "domain", assuming "domain" and "mv"8885 * have been aligned.8886 *8887 * If the resulting multi union piecewise affine expression has8888 * an explicit domain, then assign it the input domain.8889 * In other cases, the domain is stored in the individual elements.8890 */8891static __isl_give isl_multi_union_pw_aff *8892isl_multi_union_pw_aff_multi_val_on_domain_aligned(8893 __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv)8894{8895 int i;8896 isl_size n;8897 isl_space *space;8898 isl_multi_union_pw_aff *mupa;8899 8900 n = isl_multi_val_dim(mv, isl_dim_set);8901 if (!domain || n < 0)8902 goto error;8903 8904 space = isl_multi_val_get_space(mv);8905 mupa = isl_multi_union_pw_aff_alloc(space);8906 for (i = 0; i < n; ++i) {8907 isl_val *v;8908 isl_union_pw_aff *upa;8909 8910 v = isl_multi_val_get_val(mv, i);8911 upa = isl_union_pw_aff_val_on_domain(isl_union_set_copy(domain),8912 v);8913 mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);8914 }8915 if (isl_multi_union_pw_aff_has_explicit_domain(mupa))8916 mupa = isl_multi_union_pw_aff_intersect_domain(mupa,8917 isl_union_set_copy(domain));8918 8919 isl_union_set_free(domain);8920 isl_multi_val_free(mv);8921 return mupa;8922error:8923 isl_union_set_free(domain);8924 isl_multi_val_free(mv);8925 return NULL;8926}8927 8928/* Return a multiple union piecewise affine expression8929 * that is equal to "mv" on "domain".8930 */8931__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_val_on_domain(8932 __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv)8933{8934 isl_bool equal_params;8935 8936 if (!domain || !mv)8937 goto error;8938 equal_params = isl_space_has_equal_params(domain->dim, mv->space);8939 if (equal_params < 0)8940 goto error;8941 if (equal_params)8942 return isl_multi_union_pw_aff_multi_val_on_domain_aligned(8943 domain, mv);8944 domain = isl_union_set_align_params(domain,8945 isl_multi_val_get_space(mv));8946 mv = isl_multi_val_align_params(mv, isl_union_set_get_space(domain));8947 return isl_multi_union_pw_aff_multi_val_on_domain_aligned(domain, mv);8948error:8949 isl_union_set_free(domain);8950 isl_multi_val_free(mv);8951 return NULL;8952}8953 8954/* Return a multiple union piecewise affine expression8955 * that is equal to "ma" on "domain".8956 */8957__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_aff_on_domain(8958 __isl_take isl_union_set *domain, __isl_take isl_multi_aff *ma)8959{8960 isl_pw_multi_aff *pma;8961 8962 pma = isl_pw_multi_aff_from_multi_aff(ma);8963 return isl_multi_union_pw_aff_pw_multi_aff_on_domain(domain, pma);8964}8965 8966/* Return a multiple union piecewise affine expression8967 * that is equal to "pma" on "domain", assuming "domain" and "pma"8968 * have been aligned.8969 *8970 * If the resulting multi union piecewise affine expression has8971 * an explicit domain, then assign it the input domain.8972 * In other cases, the domain is stored in the individual elements.8973 */8974static __isl_give isl_multi_union_pw_aff *8975isl_multi_union_pw_aff_pw_multi_aff_on_domain_aligned(8976 __isl_take isl_union_set *domain, __isl_take isl_pw_multi_aff *pma)8977{8978 int i;8979 isl_size n;8980 isl_space *space;8981 isl_multi_union_pw_aff *mupa;8982 8983 n = isl_pw_multi_aff_dim(pma, isl_dim_set);8984 if (!domain || n < 0)8985 goto error;8986 space = isl_pw_multi_aff_get_space(pma);8987 mupa = isl_multi_union_pw_aff_alloc(space);8988 for (i = 0; i < n; ++i) {8989 isl_pw_aff *pa;8990 isl_union_pw_aff *upa;8991 8992 pa = isl_pw_multi_aff_get_pw_aff(pma, i);8993 upa = isl_union_pw_aff_pw_aff_on_domain(8994 isl_union_set_copy(domain), pa);8995 mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);8996 }8997 if (isl_multi_union_pw_aff_has_explicit_domain(mupa))8998 mupa = isl_multi_union_pw_aff_intersect_domain(mupa,8999 isl_union_set_copy(domain));9000 9001 isl_union_set_free(domain);9002 isl_pw_multi_aff_free(pma);9003 return mupa;9004error:9005 isl_union_set_free(domain);9006 isl_pw_multi_aff_free(pma);9007 return NULL;9008}9009 9010/* Return a multiple union piecewise affine expression9011 * that is equal to "pma" on "domain".9012 */9013__isl_give isl_multi_union_pw_aff *9014isl_multi_union_pw_aff_pw_multi_aff_on_domain(__isl_take isl_union_set *domain,9015 __isl_take isl_pw_multi_aff *pma)9016{9017 isl_bool equal_params;9018 isl_space *space;9019 9020 space = isl_pw_multi_aff_peek_space(pma);9021 equal_params = isl_union_set_space_has_equal_params(domain, space);9022 if (equal_params < 0)9023 goto error;9024 if (equal_params)9025 return isl_multi_union_pw_aff_pw_multi_aff_on_domain_aligned(9026 domain, pma);9027 domain = isl_union_set_align_params(domain,9028 isl_pw_multi_aff_get_space(pma));9029 pma = isl_pw_multi_aff_align_params(pma,9030 isl_union_set_get_space(domain));9031 return isl_multi_union_pw_aff_pw_multi_aff_on_domain_aligned(domain,9032 pma);9033error:9034 isl_union_set_free(domain);9035 isl_pw_multi_aff_free(pma);9036 return NULL;9037}9038 9039/* Return a union set containing those elements in the domains9040 * of the elements of "mupa" where they are all zero.9041 *9042 * If there are no elements, then simply return the entire domain.9043 */9044__isl_give isl_union_set *isl_multi_union_pw_aff_zero_union_set(9045 __isl_take isl_multi_union_pw_aff *mupa)9046{9047 int i;9048 isl_size n;9049 isl_union_pw_aff *upa;9050 isl_union_set *zero;9051 9052 n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);9053 if (n < 0)9054 mupa = isl_multi_union_pw_aff_free(mupa);9055 if (!mupa)9056 return NULL;9057 9058 if (n == 0)9059 return isl_multi_union_pw_aff_domain(mupa);9060 9061 upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0);9062 zero = isl_union_pw_aff_zero_union_set(upa);9063 9064 for (i = 1; i < n; ++i) {9065 isl_union_set *zero_i;9066 9067 upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);9068 zero_i = isl_union_pw_aff_zero_union_set(upa);9069 9070 zero = isl_union_set_intersect(zero, zero_i);9071 }9072 9073 isl_multi_union_pw_aff_free(mupa);9074 return zero;9075}9076 9077/* Construct a union map mapping the shared domain9078 * of the union piecewise affine expressions to the range of "mupa"9079 * in the special case of a 0D multi union piecewise affine expression.9080 *9081 * Construct a map between the explicit domain of "mupa" and9082 * the range space.9083 * Note that this assumes that the domain consists of explicit elements.9084 */9085static __isl_give isl_union_map *isl_union_map_from_multi_union_pw_aff_0D(9086 __isl_take isl_multi_union_pw_aff *mupa)9087{9088 isl_bool is_params;9089 isl_space *space;9090 isl_union_set *dom, *ran;9091 9092 space = isl_multi_union_pw_aff_get_space(mupa);9093 dom = isl_multi_union_pw_aff_domain(mupa);9094 ran = isl_union_set_from_set(isl_set_universe(space));9095 9096 is_params = isl_union_set_is_params(dom);9097 if (is_params < 0)9098 dom = isl_union_set_free(dom);9099 else if (is_params)9100 isl_die(isl_union_set_get_ctx(dom), isl_error_invalid,9101 "cannot create union map from expression without "9102 "explicit domain elements",9103 dom = isl_union_set_free(dom));9104 9105 return isl_union_map_from_domain_and_range(dom, ran);9106}9107 9108/* Construct a union map mapping the shared domain9109 * of the union piecewise affine expressions to the range of "mupa"9110 * with each dimension in the range equated to the9111 * corresponding union piecewise affine expression.9112 *9113 * If the input is zero-dimensional, then construct a mapping9114 * from its explicit domain.9115 */9116__isl_give isl_union_map *isl_union_map_from_multi_union_pw_aff(9117 __isl_take isl_multi_union_pw_aff *mupa)9118{9119 int i;9120 isl_size n;9121 isl_space *space;9122 isl_union_map *umap;9123 isl_union_pw_aff *upa;9124 9125 n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);9126 if (n < 0)9127 mupa = isl_multi_union_pw_aff_free(mupa);9128 if (!mupa)9129 return NULL;9130 9131 if (n == 0)9132 return isl_union_map_from_multi_union_pw_aff_0D(mupa);9133 9134 upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0);9135 umap = isl_union_map_from_union_pw_aff(upa);9136 9137 for (i = 1; i < n; ++i) {9138 isl_union_map *umap_i;9139 9140 upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);9141 umap_i = isl_union_map_from_union_pw_aff(upa);9142 umap = isl_union_map_flat_range_product(umap, umap_i);9143 }9144 9145 space = isl_multi_union_pw_aff_get_space(mupa);9146 umap = isl_union_map_reset_range_space(umap, space);9147 9148 isl_multi_union_pw_aff_free(mupa);9149 return umap;9150}9151 9152/* Internal data structure for isl_union_pw_multi_aff_reset_range_space.9153 * "range" is the space from which to set the range space.9154 * "res" collects the results.9155 */9156struct isl_union_pw_multi_aff_reset_range_space_data {9157 isl_space *range;9158 isl_union_pw_multi_aff *res;9159};9160 9161/* Replace the range space of "pma" by the range space of data->range and9162 * add the result to data->res.9163 */9164static isl_stat reset_range_space(__isl_take isl_pw_multi_aff *pma, void *user)9165{9166 struct isl_union_pw_multi_aff_reset_range_space_data *data = user;9167 isl_space *space;9168 9169 space = isl_pw_multi_aff_get_space(pma);9170 space = isl_space_domain(space);9171 space = isl_space_extend_domain_with_range(space,9172 isl_space_copy(data->range));9173 pma = isl_pw_multi_aff_reset_space(pma, space);9174 data->res = isl_union_pw_multi_aff_add_pw_multi_aff(data->res, pma);9175 9176 return data->res ? isl_stat_ok : isl_stat_error;9177}9178 9179/* Replace the range space of all the piecewise affine expressions in "upma" by9180 * the range space of "space".9181 *9182 * This assumes that all these expressions have the same output dimension.9183 *9184 * Since the spaces of the expressions change, so do their hash values.9185 * We therefore need to create a new isl_union_pw_multi_aff.9186 * Note that the hash value is currently computed based on the entire9187 * space even though there can only be a single expression with a given9188 * domain space.9189 */9190static __isl_give isl_union_pw_multi_aff *9191isl_union_pw_multi_aff_reset_range_space(9192 __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_space *space)9193{9194 struct isl_union_pw_multi_aff_reset_range_space_data data = { space };9195 isl_space *space_upma;9196 9197 space_upma = isl_union_pw_multi_aff_get_space(upma);9198 data.res = isl_union_pw_multi_aff_empty(space_upma);9199 if (isl_union_pw_multi_aff_foreach_pw_multi_aff(upma,9200 &reset_range_space, &data) < 0)9201 data.res = isl_union_pw_multi_aff_free(data.res);9202 9203 isl_space_free(space);9204 isl_union_pw_multi_aff_free(upma);9205 return data.res;9206}9207 9208/* Construct and return a union piecewise multi affine expression9209 * that is equal to the given multi union piecewise affine expression,9210 * in the special case of a 0D multi union piecewise affine expression.9211 *9212 * Construct a union piecewise multi affine expression9213 * on top of the explicit domain of the input.9214 */9215__isl_give isl_union_pw_multi_aff *9216isl_union_pw_multi_aff_from_multi_union_pw_aff_0D(9217 __isl_take isl_multi_union_pw_aff *mupa)9218{9219 isl_space *space;9220 isl_multi_val *mv;9221 isl_union_set *domain;9222 9223 space = isl_multi_union_pw_aff_get_space(mupa);9224 mv = isl_multi_val_zero(space);9225 domain = isl_multi_union_pw_aff_domain(mupa);9226 return isl_union_pw_multi_aff_multi_val_on_domain(domain, mv);9227}9228 9229/* Construct and return a union piecewise multi affine expression9230 * that is equal to the given multi union piecewise affine expression.9231 *9232 * If the input is zero-dimensional, then9233 * construct a union piecewise multi affine expression9234 * on top of the explicit domain of the input.9235 */9236__isl_give isl_union_pw_multi_aff *9237isl_union_pw_multi_aff_from_multi_union_pw_aff(9238 __isl_take isl_multi_union_pw_aff *mupa)9239{9240 int i;9241 isl_size n;9242 isl_space *space;9243 isl_union_pw_multi_aff *upma;9244 isl_union_pw_aff *upa;9245 9246 n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);9247 if (n < 0)9248 mupa = isl_multi_union_pw_aff_free(mupa);9249 if (!mupa)9250 return NULL;9251 9252 if (n == 0)9253 return isl_union_pw_multi_aff_from_multi_union_pw_aff_0D(mupa);9254 9255 space = isl_multi_union_pw_aff_get_space(mupa);9256 upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0);9257 upma = isl_union_pw_multi_aff_from_union_pw_aff(upa);9258 9259 for (i = 1; i < n; ++i) {9260 isl_union_pw_multi_aff *upma_i;9261 9262 upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);9263 upma_i = isl_union_pw_multi_aff_from_union_pw_aff(upa);9264 upma = isl_union_pw_multi_aff_flat_range_product(upma, upma_i);9265 }9266 9267 upma = isl_union_pw_multi_aff_reset_range_space(upma, space);9268 9269 isl_multi_union_pw_aff_free(mupa);9270 return upma;9271}9272 9273/* Intersect the range of "mupa" with "range",9274 * in the special case where "mupa" is 0D.9275 *9276 * Intersect the domain of "mupa" with the constraints on the parameters9277 * of "range".9278 */9279static __isl_give isl_multi_union_pw_aff *mupa_intersect_range_0D(9280 __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *range)9281{9282 range = isl_set_params(range);9283 mupa = isl_multi_union_pw_aff_intersect_params(mupa, range);9284 return mupa;9285}9286 9287/* Intersect the range of "mupa" with "range".9288 * That is, keep only those domain elements that have a function value9289 * in "range".9290 */9291__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_range(9292 __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *range)9293{9294 isl_union_pw_multi_aff *upma;9295 isl_union_set *domain;9296 isl_space *space;9297 isl_size n;9298 int match;9299 9300 n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);9301 if (n < 0 || !range)9302 goto error;9303 9304 space = isl_set_get_space(range);9305 match = isl_space_tuple_is_equal(mupa->space, isl_dim_set,9306 space, isl_dim_set);9307 isl_space_free(space);9308 if (match < 0)9309 goto error;9310 if (!match)9311 isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid,9312 "space don't match", goto error);9313 if (n == 0)9314 return mupa_intersect_range_0D(mupa, range);9315 9316 upma = isl_union_pw_multi_aff_from_multi_union_pw_aff(9317 isl_multi_union_pw_aff_copy(mupa));9318 domain = isl_union_set_from_set(range);9319 domain = isl_union_set_preimage_union_pw_multi_aff(domain, upma);9320 mupa = isl_multi_union_pw_aff_intersect_domain(mupa, domain);9321 9322 return mupa;9323error:9324 isl_multi_union_pw_aff_free(mupa);9325 isl_set_free(range);9326 return NULL;9327}9328 9329/* Return the shared domain of the elements of "mupa",9330 * in the special case where "mupa" is zero-dimensional.9331 *9332 * Return the explicit domain of "mupa".9333 * Note that this domain may be a parameter set, either9334 * because "mupa" is meant to live in a set space or9335 * because no explicit domain has been set.9336 */9337__isl_give isl_union_set *isl_multi_union_pw_aff_domain_0D(9338 __isl_take isl_multi_union_pw_aff *mupa)9339{9340 isl_union_set *dom;9341 9342 dom = isl_multi_union_pw_aff_get_explicit_domain(mupa);9343 isl_multi_union_pw_aff_free(mupa);9344 9345 return dom;9346}9347 9348/* Return the shared domain of the elements of "mupa".9349 *9350 * If "mupa" is zero-dimensional, then return its explicit domain.9351 */9352__isl_give isl_union_set *isl_multi_union_pw_aff_domain(9353 __isl_take isl_multi_union_pw_aff *mupa)9354{9355 int i;9356 isl_size n;9357 isl_union_pw_aff *upa;9358 isl_union_set *dom;9359 9360 n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);9361 if (n < 0)9362 mupa = isl_multi_union_pw_aff_free(mupa);9363 if (!mupa)9364 return NULL;9365 9366 if (n == 0)9367 return isl_multi_union_pw_aff_domain_0D(mupa);9368 9369 upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, 0);9370 dom = isl_union_pw_aff_domain(upa);9371 for (i = 1; i < n; ++i) {9372 isl_union_set *dom_i;9373 9374 upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);9375 dom_i = isl_union_pw_aff_domain(upa);9376 dom = isl_union_set_intersect(dom, dom_i);9377 }9378 9379 isl_multi_union_pw_aff_free(mupa);9380 return dom;9381}9382 9383/* Apply "aff" to "mupa". The space of "mupa" is equal to the domain of "aff".9384 * In particular, the spaces have been aligned.9385 * The result is defined over the shared domain of the elements of "mupa"9386 *9387 * We first extract the parametric constant part of "aff" and9388 * define that over the shared domain.9389 * Then we iterate over all input dimensions of "aff" and add the corresponding9390 * multiples of the elements of "mupa".9391 * Finally, we consider the integer divisions, calling the function9392 * recursively to obtain an isl_union_pw_aff corresponding to the9393 * integer division argument.9394 */9395static __isl_give isl_union_pw_aff *multi_union_pw_aff_apply_aff(9396 __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff)9397{9398 int i;9399 isl_size n_in, n_div;9400 isl_union_pw_aff *upa;9401 isl_union_set *uset;9402 isl_val *v;9403 isl_aff *cst;9404 9405 n_in = isl_aff_dim(aff, isl_dim_in);9406 n_div = isl_aff_dim(aff, isl_dim_div);9407 if (n_in < 0 || n_div < 0)9408 goto error;9409 9410 uset = isl_multi_union_pw_aff_domain(isl_multi_union_pw_aff_copy(mupa));9411 cst = isl_aff_copy(aff);9412 cst = isl_aff_drop_dims(cst, isl_dim_div, 0, n_div);9413 cst = isl_aff_drop_dims(cst, isl_dim_in, 0, n_in);9414 cst = isl_aff_project_domain_on_params(cst);9415 upa = isl_union_pw_aff_aff_on_domain(uset, cst);9416 9417 for (i = 0; i < n_in; ++i) {9418 isl_union_pw_aff *upa_i;9419 9420 if (!isl_aff_involves_dims(aff, isl_dim_in, i, 1))9421 continue;9422 v = isl_aff_get_coefficient_val(aff, isl_dim_in, i);9423 upa_i = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);9424 upa_i = isl_union_pw_aff_scale_val(upa_i, v);9425 upa = isl_union_pw_aff_add(upa, upa_i);9426 }9427 9428 for (i = 0; i < n_div; ++i) {9429 isl_aff *div;9430 isl_union_pw_aff *upa_i;9431 9432 if (!isl_aff_involves_dims(aff, isl_dim_div, i, 1))9433 continue;9434 div = isl_aff_get_div(aff, i);9435 upa_i = multi_union_pw_aff_apply_aff(9436 isl_multi_union_pw_aff_copy(mupa), div);9437 upa_i = isl_union_pw_aff_floor(upa_i);9438 v = isl_aff_get_coefficient_val(aff, isl_dim_div, i);9439 upa_i = isl_union_pw_aff_scale_val(upa_i, v);9440 upa = isl_union_pw_aff_add(upa, upa_i);9441 }9442 9443 isl_multi_union_pw_aff_free(mupa);9444 isl_aff_free(aff);9445 9446 return upa;9447error:9448 isl_multi_union_pw_aff_free(mupa);9449 isl_aff_free(aff);9450 return NULL;9451}9452 9453/* Apply "aff" to "mupa". The space of "mupa" needs to be compatible9454 * with the domain of "aff".9455 * Furthermore, the dimension of this space needs to be greater than zero.9456 * The result is defined over the shared domain of the elements of "mupa"9457 *9458 * We perform these checks and then hand over control to9459 * multi_union_pw_aff_apply_aff.9460 */9461__isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_aff(9462 __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff)9463{9464 isl_size dim;9465 isl_space *space1, *space2;9466 isl_bool equal;9467 9468 mupa = isl_multi_union_pw_aff_align_params(mupa,9469 isl_aff_get_space(aff));9470 aff = isl_aff_align_params(aff, isl_multi_union_pw_aff_get_space(mupa));9471 if (!mupa || !aff)9472 goto error;9473 9474 space1 = isl_multi_union_pw_aff_get_space(mupa);9475 space2 = isl_aff_get_domain_space(aff);9476 equal = isl_space_is_equal(space1, space2);9477 isl_space_free(space1);9478 isl_space_free(space2);9479 if (equal < 0)9480 goto error;9481 if (!equal)9482 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,9483 "spaces don't match", goto error);9484 dim = isl_aff_dim(aff, isl_dim_in);9485 if (dim < 0)9486 goto error;9487 if (dim == 0)9488 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,9489 "cannot determine domains", goto error);9490 9491 return multi_union_pw_aff_apply_aff(mupa, aff);9492error:9493 isl_multi_union_pw_aff_free(mupa);9494 isl_aff_free(aff);9495 return NULL;9496}9497 9498/* Apply "ma" to "mupa", in the special case where "mupa" is 0D.9499 * The space of "mupa" is known to be compatible with the domain of "ma".9500 *9501 * Construct an isl_multi_union_pw_aff that is equal to "ma"9502 * on the domain of "mupa".9503 */9504static __isl_give isl_multi_union_pw_aff *mupa_apply_multi_aff_0D(9505 __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_multi_aff *ma)9506{9507 isl_union_set *dom;9508 9509 dom = isl_multi_union_pw_aff_domain(mupa);9510 ma = isl_multi_aff_project_domain_on_params(ma);9511 9512 return isl_multi_union_pw_aff_multi_aff_on_domain(dom, ma);9513}9514 9515/* Apply "ma" to "mupa". The space of "mupa" needs to be compatible9516 * with the domain of "ma".9517 * The result is defined over the shared domain of the elements of "mupa"9518 */9519__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_multi_aff(9520 __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_multi_aff *ma)9521{9522 isl_space *space1, *space2;9523 isl_multi_union_pw_aff *res;9524 isl_bool equal;9525 int i;9526 isl_size n_in, n_out;9527 9528 mupa = isl_multi_union_pw_aff_align_params(mupa,9529 isl_multi_aff_get_space(ma));9530 ma = isl_multi_aff_align_params(ma,9531 isl_multi_union_pw_aff_get_space(mupa));9532 n_in = isl_multi_aff_dim(ma, isl_dim_in);9533 n_out = isl_multi_aff_dim(ma, isl_dim_out);9534 if (!mupa || n_in < 0 || n_out < 0)9535 goto error;9536 9537 space1 = isl_multi_union_pw_aff_get_space(mupa);9538 space2 = isl_multi_aff_get_domain_space(ma);9539 equal = isl_space_is_equal(space1, space2);9540 isl_space_free(space1);9541 isl_space_free(space2);9542 if (equal < 0)9543 goto error;9544 if (!equal)9545 isl_die(isl_multi_aff_get_ctx(ma), isl_error_invalid,9546 "spaces don't match", goto error);9547 if (n_in == 0)9548 return mupa_apply_multi_aff_0D(mupa, ma);9549 9550 space1 = isl_space_range(isl_multi_aff_get_space(ma));9551 res = isl_multi_union_pw_aff_alloc(space1);9552 9553 for (i = 0; i < n_out; ++i) {9554 isl_aff *aff;9555 isl_union_pw_aff *upa;9556 9557 aff = isl_multi_aff_get_aff(ma, i);9558 upa = multi_union_pw_aff_apply_aff(9559 isl_multi_union_pw_aff_copy(mupa), aff);9560 res = isl_multi_union_pw_aff_set_union_pw_aff(res, i, upa);9561 }9562 9563 isl_multi_aff_free(ma);9564 isl_multi_union_pw_aff_free(mupa);9565 return res;9566error:9567 isl_multi_union_pw_aff_free(mupa);9568 isl_multi_aff_free(ma);9569 return NULL;9570}9571 9572/* Apply "pa" to "mupa", in the special case where "mupa" is 0D.9573 * The space of "mupa" is known to be compatible with the domain of "pa".9574 *9575 * Construct an isl_multi_union_pw_aff that is equal to "pa"9576 * on the domain of "mupa".9577 */9578static __isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_pw_aff_0D(9579 __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_pw_aff *pa)9580{9581 isl_union_set *dom;9582 9583 dom = isl_multi_union_pw_aff_domain(mupa);9584 pa = isl_pw_aff_project_domain_on_params(pa);9585 9586 return isl_union_pw_aff_pw_aff_on_domain(dom, pa);9587}9588 9589/* Apply "pa" to "mupa". The space of "mupa" needs to be compatible9590 * with the domain of "pa".9591 * Furthermore, the dimension of this space needs to be greater than zero.9592 * The result is defined over the shared domain of the elements of "mupa"9593 */9594__isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_pw_aff(9595 __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_pw_aff *pa)9596{9597 int i;9598 isl_bool equal;9599 isl_size n_in;9600 isl_space *space, *space2;9601 isl_union_pw_aff *upa;9602 9603 mupa = isl_multi_union_pw_aff_align_params(mupa,9604 isl_pw_aff_get_space(pa));9605 pa = isl_pw_aff_align_params(pa,9606 isl_multi_union_pw_aff_get_space(mupa));9607 if (!mupa || !pa)9608 goto error;9609 9610 space = isl_multi_union_pw_aff_get_space(mupa);9611 space2 = isl_pw_aff_get_domain_space(pa);9612 equal = isl_space_is_equal(space, space2);9613 isl_space_free(space);9614 isl_space_free(space2);9615 if (equal < 0)9616 goto error;9617 if (!equal)9618 isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid,9619 "spaces don't match", goto error);9620 n_in = isl_pw_aff_dim(pa, isl_dim_in);9621 if (n_in < 0)9622 goto error;9623 if (n_in == 0)9624 return isl_multi_union_pw_aff_apply_pw_aff_0D(mupa, pa);9625 9626 space = isl_space_params(isl_multi_union_pw_aff_get_space(mupa));9627 upa = isl_union_pw_aff_empty(space);9628 9629 for (i = 0; i < pa->n; ++i) {9630 isl_aff *aff;9631 isl_set *domain;9632 isl_multi_union_pw_aff *mupa_i;9633 isl_union_pw_aff *upa_i;9634 9635 mupa_i = isl_multi_union_pw_aff_copy(mupa);9636 domain = isl_set_copy(pa->p[i].set);9637 mupa_i = isl_multi_union_pw_aff_intersect_range(mupa_i, domain);9638 aff = isl_aff_copy(pa->p[i].aff);9639 upa_i = multi_union_pw_aff_apply_aff(mupa_i, aff);9640 upa = isl_union_pw_aff_union_add(upa, upa_i);9641 }9642 9643 isl_multi_union_pw_aff_free(mupa);9644 isl_pw_aff_free(pa);9645 return upa;9646error:9647 isl_multi_union_pw_aff_free(mupa);9648 isl_pw_aff_free(pa);9649 return NULL;9650}9651 9652/* Apply "pma" to "mupa", in the special case where "mupa" is 0D.9653 * The space of "mupa" is known to be compatible with the domain of "pma".9654 *9655 * Construct an isl_multi_union_pw_aff that is equal to "pma"9656 * on the domain of "mupa".9657 */9658static __isl_give isl_multi_union_pw_aff *mupa_apply_pw_multi_aff_0D(9659 __isl_take isl_multi_union_pw_aff *mupa,9660 __isl_take isl_pw_multi_aff *pma)9661{9662 isl_union_set *dom;9663 9664 dom = isl_multi_union_pw_aff_domain(mupa);9665 pma = isl_pw_multi_aff_project_domain_on_params(pma);9666 9667 return isl_multi_union_pw_aff_pw_multi_aff_on_domain(dom, pma);9668}9669 9670/* Apply "pma" to "mupa". The space of "mupa" needs to be compatible9671 * with the domain of "pma".9672 * The result is defined over the shared domain of the elements of "mupa"9673 */9674__isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_pw_multi_aff(9675 __isl_take isl_multi_union_pw_aff *mupa,9676 __isl_take isl_pw_multi_aff *pma)9677{9678 isl_space *space1, *space2;9679 isl_multi_union_pw_aff *res;9680 isl_bool equal;9681 int i;9682 isl_size n_in, n_out;9683 9684 mupa = isl_multi_union_pw_aff_align_params(mupa,9685 isl_pw_multi_aff_get_space(pma));9686 pma = isl_pw_multi_aff_align_params(pma,9687 isl_multi_union_pw_aff_get_space(mupa));9688 if (!mupa || !pma)9689 goto error;9690 9691 space1 = isl_multi_union_pw_aff_get_space(mupa);9692 space2 = isl_pw_multi_aff_get_domain_space(pma);9693 equal = isl_space_is_equal(space1, space2);9694 isl_space_free(space1);9695 isl_space_free(space2);9696 if (equal < 0)9697 goto error;9698 if (!equal)9699 isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid,9700 "spaces don't match", goto error);9701 n_in = isl_pw_multi_aff_dim(pma, isl_dim_in);9702 n_out = isl_pw_multi_aff_dim(pma, isl_dim_out);9703 if (n_in < 0 || n_out < 0)9704 goto error;9705 if (n_in == 0)9706 return mupa_apply_pw_multi_aff_0D(mupa, pma);9707 9708 space1 = isl_space_range(isl_pw_multi_aff_get_space(pma));9709 res = isl_multi_union_pw_aff_alloc(space1);9710 9711 for (i = 0; i < n_out; ++i) {9712 isl_pw_aff *pa;9713 isl_union_pw_aff *upa;9714 9715 pa = isl_pw_multi_aff_get_pw_aff(pma, i);9716 upa = isl_multi_union_pw_aff_apply_pw_aff(9717 isl_multi_union_pw_aff_copy(mupa), pa);9718 res = isl_multi_union_pw_aff_set_union_pw_aff(res, i, upa);9719 }9720 9721 isl_pw_multi_aff_free(pma);9722 isl_multi_union_pw_aff_free(mupa);9723 return res;9724error:9725 isl_multi_union_pw_aff_free(mupa);9726 isl_pw_multi_aff_free(pma);9727 return NULL;9728}9729 9730/* Replace the explicit domain of "mupa" by its preimage under "upma".9731 * If the explicit domain only keeps track of constraints on the parameters,9732 * then only update those constraints.9733 */9734static __isl_give isl_multi_union_pw_aff *preimage_explicit_domain(9735 __isl_take isl_multi_union_pw_aff *mupa,9736 __isl_keep isl_union_pw_multi_aff *upma)9737{9738 isl_bool is_params;9739 9740 if (isl_multi_union_pw_aff_check_has_explicit_domain(mupa) < 0)9741 return isl_multi_union_pw_aff_free(mupa);9742 9743 mupa = isl_multi_union_pw_aff_cow(mupa);9744 if (!mupa)9745 return NULL;9746 9747 is_params = isl_union_set_is_params(mupa->u.dom);9748 if (is_params < 0)9749 return isl_multi_union_pw_aff_free(mupa);9750 9751 upma = isl_union_pw_multi_aff_copy(upma);9752 if (is_params)9753 mupa->u.dom = isl_union_set_intersect_params(mupa->u.dom,9754 isl_union_set_params(isl_union_pw_multi_aff_domain(upma)));9755 else9756 mupa->u.dom = isl_union_set_preimage_union_pw_multi_aff(9757 mupa->u.dom, upma);9758 if (!mupa->u.dom)9759 return isl_multi_union_pw_aff_free(mupa);9760 return mupa;9761}9762 9763/* Compute the pullback of "mupa" by the function represented by "upma".9764 * In other words, plug in "upma" in "mupa". The result contains9765 * expressions defined over the domain space of "upma".9766 *9767 * Run over all elements of "mupa" and plug in "upma" in each of them.9768 *9769 * If "mupa" has an explicit domain, then it is this domain9770 * that needs to undergo a pullback instead, i.e., a preimage.9771 */9772__isl_give isl_multi_union_pw_aff *9773isl_multi_union_pw_aff_pullback_union_pw_multi_aff(9774 __isl_take isl_multi_union_pw_aff *mupa,9775 __isl_take isl_union_pw_multi_aff *upma)9776{9777 int i;9778 isl_size n;9779 9780 mupa = isl_multi_union_pw_aff_align_params(mupa,9781 isl_union_pw_multi_aff_get_space(upma));9782 upma = isl_union_pw_multi_aff_align_params(upma,9783 isl_multi_union_pw_aff_get_space(mupa));9784 mupa = isl_multi_union_pw_aff_cow(mupa);9785 n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);9786 if (n < 0 || !upma)9787 goto error;9788 9789 for (i = 0; i < n; ++i) {9790 isl_union_pw_aff *upa;9791 9792 upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);9793 upa = isl_union_pw_aff_pullback_union_pw_multi_aff(upa,9794 isl_union_pw_multi_aff_copy(upma));9795 mupa = isl_multi_union_pw_aff_set_union_pw_aff(mupa, i, upa);9796 }9797 9798 if (isl_multi_union_pw_aff_has_explicit_domain(mupa))9799 mupa = preimage_explicit_domain(mupa, upma);9800 9801 isl_union_pw_multi_aff_free(upma);9802 return mupa;9803error:9804 isl_multi_union_pw_aff_free(mupa);9805 isl_union_pw_multi_aff_free(upma);9806 return NULL;9807}9808 9809/* Extract the sequence of elements in "mupa" with domain space "space"9810 * (ignoring parameters).9811 *9812 * For the elements of "mupa" that are not defined on the specified space,9813 * the corresponding element in the result is empty.9814 */9815__isl_give isl_multi_pw_aff *isl_multi_union_pw_aff_extract_multi_pw_aff(9816 __isl_keep isl_multi_union_pw_aff *mupa, __isl_take isl_space *space)9817{9818 int i;9819 isl_size n;9820 isl_space *space_mpa;9821 isl_multi_pw_aff *mpa;9822 9823 n = isl_multi_union_pw_aff_dim(mupa, isl_dim_set);9824 if (n < 0 || !space)9825 goto error;9826 9827 space_mpa = isl_multi_union_pw_aff_get_space(mupa);9828 space = isl_space_replace_params(space, space_mpa);9829 space_mpa = isl_space_map_from_domain_and_range(isl_space_copy(space),9830 space_mpa);9831 mpa = isl_multi_pw_aff_alloc(space_mpa);9832 9833 space = isl_space_from_domain(space);9834 space = isl_space_add_dims(space, isl_dim_out, 1);9835 for (i = 0; i < n; ++i) {9836 isl_union_pw_aff *upa;9837 isl_pw_aff *pa;9838 9839 upa = isl_multi_union_pw_aff_get_union_pw_aff(mupa, i);9840 pa = isl_union_pw_aff_extract_pw_aff(upa,9841 isl_space_copy(space));9842 mpa = isl_multi_pw_aff_set_pw_aff(mpa, i, pa);9843 isl_union_pw_aff_free(upa);9844 }9845 9846 isl_space_free(space);9847 return mpa;9848error:9849 isl_space_free(space);9850 return NULL;9851}9852 9853/* Data structure that specifies how isl_union_pw_multi_aff_un_op9854 * should modify the base expressions in the input.9855 *9856 * If "filter" is not NULL, then only the base expressions that satisfy "filter"9857 * are taken into account.9858 * "fn" is applied to each entry in the input.9859 */9860struct isl_union_pw_multi_aff_un_op_control {9861 isl_bool (*filter)(__isl_keep isl_pw_multi_aff *part);9862 __isl_give isl_pw_multi_aff *(*fn)(__isl_take isl_pw_multi_aff *pma);9863};9864 9865/* Wrapper for isl_union_pw_multi_aff_un_op filter functions (which do not take9866 * a second argument) for use as an isl_union_pw_multi_aff_transform9867 * filter function (which does take a second argument).9868 * Simply call control->filter without the second argument.9869 */9870static isl_bool isl_union_pw_multi_aff_un_op_filter_drop_user(9871 __isl_take isl_pw_multi_aff *pma, void *user)9872{9873 struct isl_union_pw_multi_aff_un_op_control *control = user;9874 9875 return control->filter(pma);9876}9877 9878/* Wrapper for isl_union_pw_multi_aff_un_op base functions (which do not take9879 * a second argument) for use as an isl_union_pw_multi_aff_transform9880 * base function (which does take a second argument).9881 * Simply call control->fn without the second argument.9882 */9883static __isl_give isl_pw_multi_aff *isl_union_pw_multi_aff_un_op_drop_user(9884 __isl_take isl_pw_multi_aff *pma, void *user)9885{9886 struct isl_union_pw_multi_aff_un_op_control *control = user;9887 9888 return control->fn(pma);9889}9890 9891/* Construct an isl_union_pw_multi_aff that is obtained by9892 * modifying "upma" according to "control".9893 *9894 * isl_union_pw_multi_aff_transform performs essentially9895 * the same operation, but takes a filter and a callback function9896 * of a different form (with an extra argument).9897 * Call isl_union_pw_multi_aff_transform with wrappers9898 * that remove this extra argument.9899 */9900static __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_un_op(9901 __isl_take isl_union_pw_multi_aff *upma,9902 struct isl_union_pw_multi_aff_un_op_control *control)9903{9904 struct isl_union_pw_multi_aff_transform_control t_control = {9905 .filter = &isl_union_pw_multi_aff_un_op_filter_drop_user,9906 .filter_user = control,9907 .fn = &isl_union_pw_multi_aff_un_op_drop_user,9908 .fn_user = control,9909 };9910 9911 return isl_union_pw_multi_aff_transform(upma, &t_control);9912}9913 9914/* For each function in "upma" of the form A -> [B -> C],9915 * extract the function A -> B and collect the results.9916 */9917__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_range_factor_domain(9918 __isl_take isl_union_pw_multi_aff *upma)9919{9920 struct isl_union_pw_multi_aff_un_op_control control = {9921 .filter = &isl_pw_multi_aff_range_is_wrapping,9922 .fn = &isl_pw_multi_aff_range_factor_domain,9923 };9924 return isl_union_pw_multi_aff_un_op(upma, &control);9925}9926 9927/* For each function in "upma" of the form A -> [B -> C],9928 * extract the function A -> C and collect the results.9929 */9930__isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_range_factor_range(9931 __isl_take isl_union_pw_multi_aff *upma)9932{9933 struct isl_union_pw_multi_aff_un_op_control control = {9934 .filter = &isl_pw_multi_aff_range_is_wrapping,9935 .fn = &isl_pw_multi_aff_range_factor_range,9936 };9937 return isl_union_pw_multi_aff_un_op(upma, &control);9938}9939 9940/* Evaluate the affine function "aff" in the void point "pnt".9941 * In particular, return the value NaN.9942 */9943static __isl_give isl_val *eval_void(__isl_take isl_aff *aff,9944 __isl_take isl_point *pnt)9945{9946 isl_ctx *ctx;9947 9948 ctx = isl_point_get_ctx(pnt);9949 isl_aff_free(aff);9950 isl_point_free(pnt);9951 return isl_val_nan(ctx);9952}9953 9954/* Evaluate the affine expression "aff"9955 * in the coordinates (with denominator) "pnt".9956 */9957static __isl_give isl_val *eval(__isl_keep isl_vec *aff,9958 __isl_keep isl_vec *pnt)9959{9960 isl_int n, d;9961 isl_ctx *ctx;9962 isl_val *v;9963 9964 if (!aff || !pnt)9965 return NULL;9966 9967 ctx = isl_vec_get_ctx(aff);9968 isl_int_init(n);9969 isl_int_init(d);9970 isl_seq_inner_product(aff->el + 1, pnt->el, pnt->size, &n);9971 isl_int_mul(d, aff->el[0], pnt->el[0]);9972 v = isl_val_rat_from_isl_int(ctx, n, d);9973 v = isl_val_normalize(v);9974 isl_int_clear(n);9975 isl_int_clear(d);9976 9977 return v;9978}9979 9980/* Check that the domain space of "aff" is equal to "space".9981 */9982static isl_stat isl_aff_check_has_domain_space(__isl_keep isl_aff *aff,9983 __isl_keep isl_space *space)9984{9985 isl_bool ok;9986 9987 ok = isl_space_is_equal(isl_aff_peek_domain_space(aff), space);9988 if (ok < 0)9989 return isl_stat_error;9990 if (!ok)9991 isl_die(isl_aff_get_ctx(aff), isl_error_invalid,9992 "incompatible spaces", return isl_stat_error);9993 return isl_stat_ok;9994}9995 9996/* Evaluate the affine function "aff" in "pnt".9997 */9998__isl_give isl_val *isl_aff_eval(__isl_take isl_aff *aff,9999 __isl_take isl_point *pnt)10000{10001 isl_bool is_void;10002 isl_val *v;10003 isl_local_space *ls;10004 10005 if (isl_aff_check_has_domain_space(aff, isl_point_peek_space(pnt)) < 0)10006 goto error;10007 is_void = isl_point_is_void(pnt);10008 if (is_void < 0)10009 goto error;10010 if (is_void)10011 return eval_void(aff, pnt);10012 10013 ls = isl_aff_get_domain_local_space(aff);10014 pnt = isl_local_space_lift_point(ls, pnt);10015 10016 v = eval(aff->v, isl_point_peek_vec(pnt));10017 10018 isl_aff_free(aff);10019 isl_point_free(pnt);10020 10021 return v;10022error:10023 isl_aff_free(aff);10024 isl_point_free(pnt);10025 return NULL;10026}10027