| 1 | /* |
| 2 | * Copyright 2008-2009 Katholieke Universiteit Leuven |
| 3 | * Copyright 2010 INRIA Saclay |
| 4 | * |
| 5 | * Use of this software is governed by the MIT license |
| 6 | * |
| 7 | * Written by Sven Verdoolaege, K.U.Leuven, Departement |
| 8 | * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium |
| 9 | * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite, |
| 10 | * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France |
| 11 | */ |
| 12 | |
| 13 | #include <isl_map_private.h> |
| 14 | #include <isl_constraint_private.h> |
| 15 | #include <isl_space_private.h> |
| 16 | #include <isl_seq.h> |
| 17 | #include <isl_aff_private.h> |
| 18 | #include <isl_local_space_private.h> |
| 19 | #include <isl_val_private.h> |
| 20 | #include <isl_vec_private.h> |
| 21 | |
| 22 | #include <bset_to_bmap.c> |
| 23 | #include <bset_from_bmap.c> |
| 24 | |
| 25 | #undef EL_BASE |
| 26 | #define EL_BASE constraint |
| 27 | |
| 28 | #include <isl_list_templ.c> |
| 29 | |
| 30 | isl_ctx *isl_constraint_get_ctx(__isl_keep isl_constraint *c) |
| 31 | { |
| 32 | return c ? isl_local_space_get_ctx(ls: c->ls) : NULL; |
| 33 | } |
| 34 | |
| 35 | static isl_size n(__isl_keep isl_constraint *c, enum isl_dim_type type) |
| 36 | { |
| 37 | return isl_local_space_dim(ls: c->ls, type); |
| 38 | } |
| 39 | |
| 40 | static unsigned offset(__isl_keep isl_constraint *c, enum isl_dim_type type) |
| 41 | { |
| 42 | return isl_local_space_offset(ls: c->ls, type); |
| 43 | } |
| 44 | |
| 45 | __isl_give isl_constraint *isl_constraint_alloc_vec(int eq, |
| 46 | __isl_take isl_local_space *ls, __isl_take isl_vec *v) |
| 47 | { |
| 48 | isl_constraint *constraint; |
| 49 | |
| 50 | if (!ls || !v) |
| 51 | goto error; |
| 52 | |
| 53 | constraint = isl_alloc_type(isl_vec_get_ctx(v), isl_constraint); |
| 54 | if (!constraint) |
| 55 | goto error; |
| 56 | |
| 57 | constraint->ref = 1; |
| 58 | constraint->eq = eq; |
| 59 | constraint->ls = ls; |
| 60 | constraint->v = v; |
| 61 | |
| 62 | return constraint; |
| 63 | error: |
| 64 | isl_local_space_free(ls); |
| 65 | isl_vec_free(vec: v); |
| 66 | return NULL; |
| 67 | } |
| 68 | |
| 69 | __isl_give isl_constraint *isl_constraint_alloc(int eq, |
| 70 | __isl_take isl_local_space *ls) |
| 71 | { |
| 72 | isl_size dim; |
| 73 | isl_ctx *ctx; |
| 74 | isl_vec *v; |
| 75 | |
| 76 | dim = isl_local_space_dim(ls, type: isl_dim_all); |
| 77 | if (dim < 0) |
| 78 | ls = isl_local_space_free(ls); |
| 79 | if (!ls) |
| 80 | return NULL; |
| 81 | |
| 82 | ctx = isl_local_space_get_ctx(ls); |
| 83 | v = isl_vec_alloc(ctx, size: 1 + dim); |
| 84 | v = isl_vec_clr(vec: v); |
| 85 | return isl_constraint_alloc_vec(eq, ls, v); |
| 86 | } |
| 87 | |
| 88 | __isl_give isl_constraint *isl_basic_map_constraint( |
| 89 | __isl_take isl_basic_map *bmap, isl_int **line) |
| 90 | { |
| 91 | int eq; |
| 92 | isl_size dim; |
| 93 | isl_ctx *ctx; |
| 94 | isl_vec *v; |
| 95 | isl_local_space *ls = NULL; |
| 96 | isl_constraint *constraint; |
| 97 | |
| 98 | if (!bmap || !line) |
| 99 | goto error; |
| 100 | |
| 101 | eq = line >= bmap->eq; |
| 102 | |
| 103 | ctx = isl_basic_map_get_ctx(bmap); |
| 104 | ls = isl_basic_map_get_local_space(bmap); |
| 105 | dim = isl_local_space_dim(ls, type: isl_dim_all); |
| 106 | if (dim < 0) |
| 107 | goto error; |
| 108 | v = isl_vec_alloc(ctx, size: 1 + dim); |
| 109 | if (!v) |
| 110 | goto error; |
| 111 | isl_seq_cpy(dst: v->el, src: line[0], len: v->size); |
| 112 | constraint = isl_constraint_alloc_vec(eq, ls, v); |
| 113 | |
| 114 | isl_basic_map_free(bmap); |
| 115 | return constraint; |
| 116 | error: |
| 117 | isl_local_space_free(ls); |
| 118 | isl_basic_map_free(bmap); |
| 119 | return NULL; |
| 120 | } |
| 121 | |
| 122 | __isl_give isl_constraint *isl_basic_set_constraint( |
| 123 | __isl_take isl_basic_set *bset, isl_int **line) |
| 124 | { |
| 125 | return isl_basic_map_constraint(bmap: bset_to_bmap(bset), line); |
| 126 | } |
| 127 | |
| 128 | __isl_give isl_constraint *isl_constraint_alloc_equality( |
| 129 | __isl_take isl_local_space *ls) |
| 130 | { |
| 131 | return isl_constraint_alloc(eq: 1, ls); |
| 132 | } |
| 133 | |
| 134 | __isl_give isl_constraint *isl_constraint_alloc_inequality( |
| 135 | __isl_take isl_local_space *ls) |
| 136 | { |
| 137 | return isl_constraint_alloc(eq: 0, ls); |
| 138 | } |
| 139 | |
| 140 | __isl_give isl_constraint *isl_constraint_dup(__isl_keep isl_constraint *c) |
| 141 | { |
| 142 | if (!c) |
| 143 | return NULL; |
| 144 | |
| 145 | return isl_constraint_alloc_vec(eq: c->eq, ls: isl_local_space_copy(ls: c->ls), |
| 146 | v: isl_vec_copy(vec: c->v)); |
| 147 | } |
| 148 | |
| 149 | __isl_give isl_constraint *isl_constraint_cow(__isl_take isl_constraint *c) |
| 150 | { |
| 151 | if (!c) |
| 152 | return NULL; |
| 153 | |
| 154 | if (c->ref == 1) |
| 155 | return c; |
| 156 | c->ref--; |
| 157 | return isl_constraint_dup(c); |
| 158 | } |
| 159 | |
| 160 | __isl_give isl_constraint *isl_constraint_copy( |
| 161 | __isl_keep isl_constraint *constraint) |
| 162 | { |
| 163 | if (!constraint) |
| 164 | return NULL; |
| 165 | |
| 166 | constraint->ref++; |
| 167 | return constraint; |
| 168 | } |
| 169 | |
| 170 | __isl_null isl_constraint *isl_constraint_free(__isl_take isl_constraint *c) |
| 171 | { |
| 172 | if (!c) |
| 173 | return NULL; |
| 174 | |
| 175 | if (--c->ref > 0) |
| 176 | return NULL; |
| 177 | |
| 178 | isl_local_space_free(ls: c->ls); |
| 179 | isl_vec_free(vec: c->v); |
| 180 | free(ptr: c); |
| 181 | |
| 182 | return NULL; |
| 183 | } |
| 184 | |
| 185 | /* Return the number of constraints in "bmap", i.e., the |
| 186 | * number of times isl_basic_map_foreach_constraint will |
| 187 | * call the callback. |
| 188 | */ |
| 189 | isl_size isl_basic_map_n_constraint(__isl_keep isl_basic_map *bmap) |
| 190 | { |
| 191 | if (!bmap) |
| 192 | return isl_size_error; |
| 193 | |
| 194 | return bmap->n_eq + bmap->n_ineq; |
| 195 | } |
| 196 | |
| 197 | /* Return the number of constraints in "bset", i.e., the |
| 198 | * number of times isl_basic_set_foreach_constraint will |
| 199 | * call the callback. |
| 200 | */ |
| 201 | isl_size isl_basic_set_n_constraint(__isl_keep isl_basic_set *bset) |
| 202 | { |
| 203 | return isl_basic_map_n_constraint(bmap: bset); |
| 204 | } |
| 205 | |
| 206 | isl_stat isl_basic_map_foreach_constraint(__isl_keep isl_basic_map *bmap, |
| 207 | isl_stat (*fn)(__isl_take isl_constraint *c, void *user), void *user) |
| 208 | { |
| 209 | int i; |
| 210 | struct isl_constraint *c; |
| 211 | |
| 212 | if (!bmap) |
| 213 | return isl_stat_error; |
| 214 | |
| 215 | isl_assert(bmap->ctx, ISL_F_ISSET(bmap, ISL_BASIC_MAP_FINAL), |
| 216 | return isl_stat_error); |
| 217 | |
| 218 | for (i = 0; i < bmap->n_eq; ++i) { |
| 219 | c = isl_basic_map_constraint(bmap: isl_basic_map_copy(bmap), |
| 220 | line: &bmap->eq[i]); |
| 221 | if (!c) |
| 222 | return isl_stat_error; |
| 223 | if (fn(c, user) < 0) |
| 224 | return isl_stat_error; |
| 225 | } |
| 226 | |
| 227 | for (i = 0; i < bmap->n_ineq; ++i) { |
| 228 | c = isl_basic_map_constraint(bmap: isl_basic_map_copy(bmap), |
| 229 | line: &bmap->ineq[i]); |
| 230 | if (!c) |
| 231 | return isl_stat_error; |
| 232 | if (fn(c, user) < 0) |
| 233 | return isl_stat_error; |
| 234 | } |
| 235 | |
| 236 | return isl_stat_ok; |
| 237 | } |
| 238 | |
| 239 | isl_stat isl_basic_set_foreach_constraint(__isl_keep isl_basic_set *bset, |
| 240 | isl_stat (*fn)(__isl_take isl_constraint *c, void *user), void *user) |
| 241 | { |
| 242 | return isl_basic_map_foreach_constraint(bmap: bset_to_bmap(bset), fn, user); |
| 243 | } |
| 244 | |
| 245 | /* Add the constraint to the list that "user" points to, if it is not |
| 246 | * a div constraint. |
| 247 | */ |
| 248 | static isl_stat collect_constraint(__isl_take isl_constraint *constraint, |
| 249 | void *user) |
| 250 | { |
| 251 | isl_constraint_list **list = user; |
| 252 | isl_bool is_div; |
| 253 | |
| 254 | is_div = isl_constraint_is_div_constraint(constraint); |
| 255 | if (is_div < 0 || is_div) |
| 256 | isl_constraint_free(c: constraint); |
| 257 | else |
| 258 | *list = isl_constraint_list_add(list: *list, el: constraint); |
| 259 | |
| 260 | return is_div < 0 ? isl_stat_error : isl_stat_ok; |
| 261 | } |
| 262 | |
| 263 | /* Return a list of constraints that, when combined, are equivalent |
| 264 | * to "bmap". The input is required to have only known divs. |
| 265 | * |
| 266 | * There is no need to include the div constraints as they are |
| 267 | * implied by the div expressions. |
| 268 | */ |
| 269 | __isl_give isl_constraint_list *isl_basic_map_get_constraint_list( |
| 270 | __isl_keep isl_basic_map *bmap) |
| 271 | { |
| 272 | isl_size n; |
| 273 | isl_bool known; |
| 274 | isl_ctx *ctx; |
| 275 | isl_constraint_list *list; |
| 276 | |
| 277 | known = isl_basic_map_divs_known(bmap); |
| 278 | if (known < 0) |
| 279 | return NULL; |
| 280 | ctx = isl_basic_map_get_ctx(bmap); |
| 281 | if (!known) |
| 282 | isl_die(ctx, isl_error_invalid, |
| 283 | "input involves unknown divs" , return NULL); |
| 284 | |
| 285 | n = isl_basic_map_n_constraint(bmap); |
| 286 | if (n < 0) |
| 287 | return NULL; |
| 288 | list = isl_constraint_list_alloc(ctx, n); |
| 289 | if (isl_basic_map_foreach_constraint(bmap, |
| 290 | fn: &collect_constraint, user: &list) < 0) |
| 291 | list = isl_constraint_list_free(list); |
| 292 | |
| 293 | return list; |
| 294 | } |
| 295 | |
| 296 | /* Return a list of constraints that, when combined, are equivalent |
| 297 | * to "bset". The input is required to have only known divs. |
| 298 | */ |
| 299 | __isl_give isl_constraint_list *isl_basic_set_get_constraint_list( |
| 300 | __isl_keep isl_basic_set *bset) |
| 301 | { |
| 302 | return isl_basic_map_get_constraint_list(bmap: bset); |
| 303 | } |
| 304 | |
| 305 | int isl_constraint_is_equal(__isl_keep isl_constraint *constraint1, |
| 306 | __isl_keep isl_constraint *constraint2) |
| 307 | { |
| 308 | int equal; |
| 309 | |
| 310 | if (!constraint1 || !constraint2) |
| 311 | return 0; |
| 312 | if (constraint1->eq != constraint2->eq) |
| 313 | return 0; |
| 314 | equal = isl_local_space_is_equal(ls1: constraint1->ls, ls2: constraint2->ls); |
| 315 | if (equal < 0 || !equal) |
| 316 | return equal; |
| 317 | return isl_vec_is_equal(vec1: constraint1->v, vec2: constraint2->v); |
| 318 | } |
| 319 | |
| 320 | __isl_give isl_basic_map *isl_basic_map_add_constraint( |
| 321 | __isl_take isl_basic_map *bmap, __isl_take isl_constraint *constraint) |
| 322 | { |
| 323 | isl_ctx *ctx; |
| 324 | isl_space *space; |
| 325 | int equal_space; |
| 326 | |
| 327 | if (!bmap || !constraint) |
| 328 | goto error; |
| 329 | |
| 330 | ctx = isl_constraint_get_ctx(c: constraint); |
| 331 | space = isl_constraint_get_space(constraint); |
| 332 | equal_space = isl_space_is_equal(space1: bmap->dim, space2: space); |
| 333 | isl_space_free(space); |
| 334 | isl_assert(ctx, equal_space, goto error); |
| 335 | |
| 336 | bmap = isl_basic_map_intersect(bmap1: bmap, |
| 337 | bmap2: isl_basic_map_from_constraint(constraint)); |
| 338 | return bmap; |
| 339 | error: |
| 340 | isl_basic_map_free(bmap); |
| 341 | isl_constraint_free(c: constraint); |
| 342 | return NULL; |
| 343 | } |
| 344 | |
| 345 | __isl_give isl_basic_set *isl_basic_set_add_constraint( |
| 346 | __isl_take isl_basic_set *bset, __isl_take isl_constraint *constraint) |
| 347 | { |
| 348 | return bset_from_bmap(bmap: isl_basic_map_add_constraint(bmap: bset_to_bmap(bset), |
| 349 | constraint)); |
| 350 | } |
| 351 | |
| 352 | __isl_give isl_map *isl_map_add_constraint(__isl_take isl_map *map, |
| 353 | __isl_take isl_constraint *constraint) |
| 354 | { |
| 355 | isl_basic_map *bmap; |
| 356 | |
| 357 | bmap = isl_basic_map_from_constraint(constraint); |
| 358 | map = isl_map_intersect(map1: map, map2: isl_map_from_basic_map(bmap)); |
| 359 | |
| 360 | return map; |
| 361 | } |
| 362 | |
| 363 | __isl_give isl_set *isl_set_add_constraint(__isl_take isl_set *set, |
| 364 | __isl_take isl_constraint *constraint) |
| 365 | { |
| 366 | return isl_map_add_constraint(map: set, constraint); |
| 367 | } |
| 368 | |
| 369 | /* Return the space of "constraint". |
| 370 | */ |
| 371 | static __isl_keep isl_space *isl_constraint_peek_space( |
| 372 | __isl_keep isl_constraint *constraint) |
| 373 | { |
| 374 | return constraint ? isl_local_space_peek_space(ls: constraint->ls) : NULL; |
| 375 | } |
| 376 | |
| 377 | __isl_give isl_space *isl_constraint_get_space( |
| 378 | __isl_keep isl_constraint *constraint) |
| 379 | { |
| 380 | return constraint ? isl_local_space_get_space(ls: constraint->ls) : NULL; |
| 381 | } |
| 382 | |
| 383 | __isl_give isl_local_space *isl_constraint_get_local_space( |
| 384 | __isl_keep isl_constraint *constraint) |
| 385 | { |
| 386 | return constraint ? isl_local_space_copy(ls: constraint->ls) : NULL; |
| 387 | } |
| 388 | |
| 389 | isl_size isl_constraint_dim(__isl_keep isl_constraint *constraint, |
| 390 | enum isl_dim_type type) |
| 391 | { |
| 392 | if (!constraint) |
| 393 | return isl_size_error; |
| 394 | return n(c: constraint, type); |
| 395 | } |
| 396 | |
| 397 | #undef TYPE |
| 398 | #define TYPE isl_constraint |
| 399 | static |
| 400 | #include "check_type_range_templ.c" |
| 401 | |
| 402 | isl_bool isl_constraint_involves_dims(__isl_keep isl_constraint *constraint, |
| 403 | enum isl_dim_type type, unsigned first, unsigned n) |
| 404 | { |
| 405 | int i; |
| 406 | int *active = NULL; |
| 407 | isl_bool involves = isl_bool_false; |
| 408 | |
| 409 | if (!constraint) |
| 410 | return isl_bool_error; |
| 411 | if (n == 0) |
| 412 | return isl_bool_false; |
| 413 | |
| 414 | if (isl_constraint_check_range(obj: constraint, type, first, n) < 0) |
| 415 | return isl_bool_error; |
| 416 | |
| 417 | active = isl_local_space_get_active(ls: constraint->ls, |
| 418 | l: constraint->v->el + 1); |
| 419 | if (!active) |
| 420 | goto error; |
| 421 | |
| 422 | first += isl_local_space_offset(ls: constraint->ls, type) - 1; |
| 423 | for (i = 0; i < n; ++i) |
| 424 | if (active[first + i]) { |
| 425 | involves = isl_bool_true; |
| 426 | break; |
| 427 | } |
| 428 | |
| 429 | free(ptr: active); |
| 430 | |
| 431 | return involves; |
| 432 | error: |
| 433 | free(ptr: active); |
| 434 | return isl_bool_error; |
| 435 | } |
| 436 | |
| 437 | /* Does the given constraint represent a lower bound on the given |
| 438 | * dimension? |
| 439 | */ |
| 440 | isl_bool isl_constraint_is_lower_bound(__isl_keep isl_constraint *constraint, |
| 441 | enum isl_dim_type type, unsigned pos) |
| 442 | { |
| 443 | if (isl_constraint_check_range(obj: constraint, type, first: pos, n: 1) < 0) |
| 444 | return isl_bool_error; |
| 445 | |
| 446 | pos += isl_local_space_offset(ls: constraint->ls, type); |
| 447 | return isl_bool_ok(isl_int_is_pos(constraint->v->el[pos])); |
| 448 | } |
| 449 | |
| 450 | /* Does the given constraint represent an upper bound on the given |
| 451 | * dimension? |
| 452 | */ |
| 453 | isl_bool isl_constraint_is_upper_bound(__isl_keep isl_constraint *constraint, |
| 454 | enum isl_dim_type type, unsigned pos) |
| 455 | { |
| 456 | if (isl_constraint_check_range(obj: constraint, type, first: pos, n: 1) < 0) |
| 457 | return isl_bool_error; |
| 458 | |
| 459 | pos += isl_local_space_offset(ls: constraint->ls, type); |
| 460 | return isl_bool_ok(isl_int_is_neg(constraint->v->el[pos])); |
| 461 | } |
| 462 | |
| 463 | const char *isl_constraint_get_dim_name(__isl_keep isl_constraint *constraint, |
| 464 | enum isl_dim_type type, unsigned pos) |
| 465 | { |
| 466 | return constraint ? |
| 467 | isl_local_space_get_dim_name(ls: constraint->ls, type, pos) : NULL; |
| 468 | } |
| 469 | |
| 470 | void isl_constraint_get_constant(__isl_keep isl_constraint *constraint, |
| 471 | isl_int *v) |
| 472 | { |
| 473 | if (!constraint) |
| 474 | return; |
| 475 | isl_int_set(*v, constraint->v->el[0]); |
| 476 | } |
| 477 | |
| 478 | /* Return the constant term of "constraint". |
| 479 | */ |
| 480 | __isl_give isl_val *isl_constraint_get_constant_val( |
| 481 | __isl_keep isl_constraint *constraint) |
| 482 | { |
| 483 | isl_ctx *ctx; |
| 484 | |
| 485 | if (!constraint) |
| 486 | return NULL; |
| 487 | |
| 488 | ctx = isl_constraint_get_ctx(c: constraint); |
| 489 | return isl_val_int_from_isl_int(ctx, n: constraint->v->el[0]); |
| 490 | } |
| 491 | |
| 492 | void isl_constraint_get_coefficient(__isl_keep isl_constraint *constraint, |
| 493 | enum isl_dim_type type, int pos, isl_int *v) |
| 494 | { |
| 495 | if (isl_constraint_check_range(obj: constraint, type, first: pos, n: 1) < 0) |
| 496 | return; |
| 497 | |
| 498 | pos += isl_local_space_offset(ls: constraint->ls, type); |
| 499 | isl_int_set(*v, constraint->v->el[pos]); |
| 500 | } |
| 501 | |
| 502 | /* Return the coefficient of the variable of type "type" at position "pos" |
| 503 | * of "constraint". |
| 504 | */ |
| 505 | __isl_give isl_val *isl_constraint_get_coefficient_val( |
| 506 | __isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos) |
| 507 | { |
| 508 | isl_ctx *ctx; |
| 509 | |
| 510 | if (isl_constraint_check_range(obj: constraint, type, first: pos, n: 1) < 0) |
| 511 | return NULL; |
| 512 | |
| 513 | ctx = isl_constraint_get_ctx(c: constraint); |
| 514 | pos += isl_local_space_offset(ls: constraint->ls, type); |
| 515 | return isl_val_int_from_isl_int(ctx, n: constraint->v->el[pos]); |
| 516 | } |
| 517 | |
| 518 | __isl_give isl_aff *isl_constraint_get_div(__isl_keep isl_constraint *constraint, |
| 519 | int pos) |
| 520 | { |
| 521 | if (!constraint) |
| 522 | return NULL; |
| 523 | |
| 524 | return isl_local_space_get_div(ls: constraint->ls, pos); |
| 525 | } |
| 526 | |
| 527 | __isl_give isl_constraint *isl_constraint_set_constant( |
| 528 | __isl_take isl_constraint *constraint, isl_int v) |
| 529 | { |
| 530 | constraint = isl_constraint_cow(c: constraint); |
| 531 | if (!constraint) |
| 532 | return NULL; |
| 533 | |
| 534 | constraint->v = isl_vec_cow(vec: constraint->v); |
| 535 | if (!constraint->v) |
| 536 | return isl_constraint_free(c: constraint); |
| 537 | |
| 538 | isl_int_set(constraint->v->el[0], v); |
| 539 | return constraint; |
| 540 | } |
| 541 | |
| 542 | /* Replace the constant term of "constraint" by "v". |
| 543 | */ |
| 544 | __isl_give isl_constraint *isl_constraint_set_constant_val( |
| 545 | __isl_take isl_constraint *constraint, __isl_take isl_val *v) |
| 546 | { |
| 547 | constraint = isl_constraint_cow(c: constraint); |
| 548 | if (!constraint || !v) |
| 549 | goto error; |
| 550 | if (!isl_val_is_int(v)) |
| 551 | isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid, |
| 552 | "expecting integer value" , goto error); |
| 553 | constraint->v = isl_vec_set_element_val(vec: constraint->v, pos: 0, v); |
| 554 | if (!constraint->v) |
| 555 | constraint = isl_constraint_free(c: constraint); |
| 556 | return constraint; |
| 557 | error: |
| 558 | isl_val_free(v); |
| 559 | return isl_constraint_free(c: constraint); |
| 560 | } |
| 561 | |
| 562 | __isl_give isl_constraint *isl_constraint_set_constant_si( |
| 563 | __isl_take isl_constraint *constraint, int v) |
| 564 | { |
| 565 | constraint = isl_constraint_cow(c: constraint); |
| 566 | if (!constraint) |
| 567 | return NULL; |
| 568 | |
| 569 | constraint->v = isl_vec_cow(vec: constraint->v); |
| 570 | if (!constraint->v) |
| 571 | return isl_constraint_free(c: constraint); |
| 572 | |
| 573 | isl_int_set_si(constraint->v->el[0], v); |
| 574 | return constraint; |
| 575 | } |
| 576 | |
| 577 | /* Replace the coefficient of the variable of type "type" at position "pos" |
| 578 | * of "constraint" by "v". |
| 579 | */ |
| 580 | __isl_give isl_constraint *isl_constraint_set_coefficient_val( |
| 581 | __isl_take isl_constraint *constraint, |
| 582 | enum isl_dim_type type, int pos, __isl_take isl_val *v) |
| 583 | { |
| 584 | constraint = isl_constraint_cow(c: constraint); |
| 585 | if (!constraint || !v) |
| 586 | goto error; |
| 587 | if (!isl_val_is_int(v)) |
| 588 | isl_die(isl_constraint_get_ctx(constraint), isl_error_invalid, |
| 589 | "expecting integer value" , goto error); |
| 590 | if (isl_constraint_check_range(obj: constraint, type, first: pos, n: 1) < 0) |
| 591 | goto error; |
| 592 | |
| 593 | pos += isl_local_space_offset(ls: constraint->ls, type); |
| 594 | constraint->v = isl_vec_set_element_val(vec: constraint->v, pos, v); |
| 595 | if (!constraint->v) |
| 596 | constraint = isl_constraint_free(c: constraint); |
| 597 | return constraint; |
| 598 | error: |
| 599 | isl_val_free(v); |
| 600 | return isl_constraint_free(c: constraint); |
| 601 | } |
| 602 | |
| 603 | __isl_give isl_constraint *isl_constraint_set_coefficient_si( |
| 604 | __isl_take isl_constraint *constraint, |
| 605 | enum isl_dim_type type, int pos, int v) |
| 606 | { |
| 607 | constraint = isl_constraint_cow(c: constraint); |
| 608 | if (isl_constraint_check_range(obj: constraint, type, first: pos, n: 1) < 0) |
| 609 | return isl_constraint_free(c: constraint); |
| 610 | |
| 611 | constraint->v = isl_vec_cow(vec: constraint->v); |
| 612 | if (!constraint->v) |
| 613 | return isl_constraint_free(c: constraint); |
| 614 | |
| 615 | pos += isl_local_space_offset(ls: constraint->ls, type); |
| 616 | isl_int_set_si(constraint->v->el[pos], v); |
| 617 | |
| 618 | return constraint; |
| 619 | } |
| 620 | |
| 621 | __isl_give isl_constraint *isl_constraint_negate( |
| 622 | __isl_take isl_constraint *constraint) |
| 623 | { |
| 624 | isl_ctx *ctx; |
| 625 | |
| 626 | constraint = isl_constraint_cow(c: constraint); |
| 627 | if (!constraint) |
| 628 | return NULL; |
| 629 | |
| 630 | ctx = isl_constraint_get_ctx(c: constraint); |
| 631 | if (isl_constraint_is_equality(constraint)) |
| 632 | isl_die(ctx, isl_error_invalid, "cannot negate equality" , |
| 633 | return isl_constraint_free(constraint)); |
| 634 | constraint->v = isl_vec_neg(vec: constraint->v); |
| 635 | constraint->v = isl_vec_cow(vec: constraint->v); |
| 636 | if (!constraint->v) |
| 637 | return isl_constraint_free(c: constraint); |
| 638 | isl_int_sub_ui(constraint->v->el[0], constraint->v->el[0], 1); |
| 639 | return constraint; |
| 640 | } |
| 641 | |
| 642 | isl_bool isl_constraint_is_equality(struct isl_constraint *constraint) |
| 643 | { |
| 644 | if (!constraint) |
| 645 | return isl_bool_error; |
| 646 | return isl_bool_ok(b: constraint->eq); |
| 647 | } |
| 648 | |
| 649 | isl_bool isl_constraint_is_div_constraint(__isl_keep isl_constraint *constraint) |
| 650 | { |
| 651 | int i; |
| 652 | isl_size n_div; |
| 653 | |
| 654 | if (!constraint) |
| 655 | return isl_bool_error; |
| 656 | if (isl_constraint_is_equality(constraint)) |
| 657 | return isl_bool_false; |
| 658 | n_div = isl_constraint_dim(constraint, type: isl_dim_div); |
| 659 | if (n_div < 0) |
| 660 | return isl_bool_error; |
| 661 | for (i = 0; i < n_div; ++i) { |
| 662 | isl_bool is_div; |
| 663 | is_div = isl_local_space_is_div_constraint(ls: constraint->ls, |
| 664 | constraint: constraint->v->el, div: i); |
| 665 | if (is_div < 0 || is_div) |
| 666 | return is_div; |
| 667 | } |
| 668 | |
| 669 | return isl_bool_false; |
| 670 | } |
| 671 | |
| 672 | /* Is "constraint" an equality that corresponds to integer division "div"? |
| 673 | * |
| 674 | * That is, given an integer division of the form |
| 675 | * |
| 676 | * a = floor((f + c)/m) |
| 677 | * |
| 678 | * is the equality of the form |
| 679 | * |
| 680 | * -f + m d + c' = 0 |
| 681 | * ? |
| 682 | * Note that the constant term is not checked explicitly, but given |
| 683 | * that this is a valid equality constraint, the constant c' necessarily |
| 684 | * has a value close to -c. |
| 685 | */ |
| 686 | isl_bool isl_constraint_is_div_equality(__isl_keep isl_constraint *constraint, |
| 687 | unsigned div) |
| 688 | { |
| 689 | isl_bool equality; |
| 690 | |
| 691 | equality = isl_constraint_is_equality(constraint); |
| 692 | if (equality < 0 || !equality) |
| 693 | return equality; |
| 694 | return isl_local_space_is_div_equality(ls: constraint->ls, |
| 695 | constraint: constraint->v->el, div); |
| 696 | } |
| 697 | |
| 698 | /* We manually set ISL_BASIC_SET_FINAL instead of calling |
| 699 | * isl_basic_map_finalize because we want to keep the position |
| 700 | * of the divs and we therefore do not want to throw away redundant divs. |
| 701 | * This is arguably a bit fragile. |
| 702 | */ |
| 703 | __isl_give isl_basic_map *isl_basic_map_from_constraint( |
| 704 | __isl_take isl_constraint *constraint) |
| 705 | { |
| 706 | int k; |
| 707 | isl_local_space *ls; |
| 708 | struct isl_basic_map *bmap; |
| 709 | isl_int *c; |
| 710 | isl_size total; |
| 711 | |
| 712 | if (!constraint) |
| 713 | return NULL; |
| 714 | |
| 715 | ls = isl_local_space_copy(ls: constraint->ls); |
| 716 | bmap = isl_basic_map_from_local_space(ls); |
| 717 | bmap = isl_basic_map_extend_constraints(base: bmap, n_eq: 1, n_ineq: 1); |
| 718 | if (isl_constraint_is_equality(constraint)) { |
| 719 | k = isl_basic_map_alloc_equality(bmap); |
| 720 | if (k < 0) |
| 721 | goto error; |
| 722 | c = bmap->eq[k]; |
| 723 | } |
| 724 | else { |
| 725 | k = isl_basic_map_alloc_inequality(bmap); |
| 726 | if (k < 0) |
| 727 | goto error; |
| 728 | c = bmap->ineq[k]; |
| 729 | } |
| 730 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
| 731 | if (total < 0) |
| 732 | goto error; |
| 733 | isl_seq_cpy(dst: c, src: constraint->v->el, len: 1 + total); |
| 734 | isl_constraint_free(c: constraint); |
| 735 | if (bmap) |
| 736 | ISL_F_SET(bmap, ISL_BASIC_SET_FINAL); |
| 737 | return bmap; |
| 738 | error: |
| 739 | isl_constraint_free(c: constraint); |
| 740 | isl_basic_map_free(bmap); |
| 741 | return NULL; |
| 742 | } |
| 743 | |
| 744 | __isl_give isl_basic_set *isl_basic_set_from_constraint( |
| 745 | __isl_take isl_constraint *constraint) |
| 746 | { |
| 747 | isl_space *space; |
| 748 | |
| 749 | space = isl_constraint_peek_space(constraint); |
| 750 | if (isl_space_check_is_set(space) < 0) |
| 751 | goto error; |
| 752 | return bset_from_bmap(bmap: isl_basic_map_from_constraint(constraint)); |
| 753 | error: |
| 754 | isl_constraint_free(c: constraint); |
| 755 | return NULL; |
| 756 | } |
| 757 | |
| 758 | /* Is the variable of "type" at position "pos" of "bmap" defined |
| 759 | * in terms of earlier dimensions through an equality? |
| 760 | * |
| 761 | * If so, and if c is not NULL, then return a copy of this equality in *c. |
| 762 | */ |
| 763 | isl_bool isl_basic_map_has_defining_equality( |
| 764 | __isl_keep isl_basic_map *bmap, enum isl_dim_type type, int pos, |
| 765 | __isl_give isl_constraint **c) |
| 766 | { |
| 767 | int i; |
| 768 | unsigned offset; |
| 769 | isl_size total; |
| 770 | |
| 771 | if (isl_basic_map_check_range(bmap, type, first: pos, n: 1) < 0) |
| 772 | return isl_bool_error; |
| 773 | offset = isl_basic_map_offset(bmap, type); |
| 774 | total = isl_basic_map_dim(bmap, type: isl_dim_all); |
| 775 | if (total < 0) |
| 776 | return isl_bool_error; |
| 777 | for (i = 0; i < bmap->n_eq; ++i) { |
| 778 | if (isl_int_is_zero(bmap->eq[i][offset + pos]) || |
| 779 | isl_seq_first_non_zero(p: bmap->eq[i]+offset+pos+1, |
| 780 | len: 1+total-offset-pos-1) != -1) |
| 781 | continue; |
| 782 | if (c) |
| 783 | *c = isl_basic_map_constraint(bmap: isl_basic_map_copy(bmap), |
| 784 | line: &bmap->eq[i]); |
| 785 | return isl_bool_true; |
| 786 | } |
| 787 | return isl_bool_false; |
| 788 | } |
| 789 | |
| 790 | /* Is the variable of "type" at position "pos" of "bset" defined |
| 791 | * in terms of earlier dimensions through an equality? |
| 792 | * |
| 793 | * If so, and if c is not NULL, then return a copy of this equality in *c. |
| 794 | */ |
| 795 | isl_bool isl_basic_set_has_defining_equality( |
| 796 | __isl_keep isl_basic_set *bset, enum isl_dim_type type, int pos, |
| 797 | __isl_give isl_constraint **c) |
| 798 | { |
| 799 | return isl_basic_map_has_defining_equality(bmap: bset_to_bmap(bset), |
| 800 | type, pos, c); |
| 801 | } |
| 802 | |
| 803 | isl_bool isl_basic_set_has_defining_inequalities( |
| 804 | struct isl_basic_set *bset, enum isl_dim_type type, int pos, |
| 805 | struct isl_constraint **lower, |
| 806 | struct isl_constraint **upper) |
| 807 | { |
| 808 | int i, j; |
| 809 | unsigned offset; |
| 810 | isl_size total; |
| 811 | isl_int m; |
| 812 | isl_int **lower_line, **upper_line; |
| 813 | |
| 814 | if (isl_basic_set_check_range(bset, type, first: pos, n: 1) < 0) |
| 815 | return isl_bool_error; |
| 816 | offset = isl_basic_set_offset(bset, type); |
| 817 | total = isl_basic_set_dim(bset, type: isl_dim_all); |
| 818 | if (total < 0) |
| 819 | return isl_bool_error; |
| 820 | isl_int_init(m); |
| 821 | for (i = 0; i < bset->n_ineq; ++i) { |
| 822 | if (isl_int_is_zero(bset->ineq[i][offset + pos])) |
| 823 | continue; |
| 824 | if (isl_int_is_one(bset->ineq[i][offset + pos])) |
| 825 | continue; |
| 826 | if (isl_int_is_negone(bset->ineq[i][offset + pos])) |
| 827 | continue; |
| 828 | if (isl_seq_first_non_zero(p: bset->ineq[i]+offset+pos+1, |
| 829 | len: 1+total-offset-pos-1) != -1) |
| 830 | continue; |
| 831 | for (j = i + 1; j < bset->n_ineq; ++j) { |
| 832 | if (!isl_seq_is_neg(p1: bset->ineq[i]+1, p2: bset->ineq[j]+1, |
| 833 | len: total)) |
| 834 | continue; |
| 835 | isl_int_add(m, bset->ineq[i][0], bset->ineq[j][0]); |
| 836 | if (isl_int_abs_ge(m, bset->ineq[i][offset+pos])) |
| 837 | continue; |
| 838 | |
| 839 | if (isl_int_is_pos(bset->ineq[i][offset+pos])) { |
| 840 | lower_line = &bset->ineq[i]; |
| 841 | upper_line = &bset->ineq[j]; |
| 842 | } else { |
| 843 | lower_line = &bset->ineq[j]; |
| 844 | upper_line = &bset->ineq[i]; |
| 845 | } |
| 846 | *lower = isl_basic_set_constraint( |
| 847 | bset: isl_basic_set_copy(bset), line: lower_line); |
| 848 | *upper = isl_basic_set_constraint( |
| 849 | bset: isl_basic_set_copy(bset), line: upper_line); |
| 850 | isl_int_clear(m); |
| 851 | return isl_bool_true; |
| 852 | } |
| 853 | } |
| 854 | *lower = NULL; |
| 855 | *upper = NULL; |
| 856 | isl_int_clear(m); |
| 857 | return isl_bool_false; |
| 858 | } |
| 859 | |
| 860 | /* Given two constraints "a" and "b" on the variable at position "abs_pos" |
| 861 | * (in "a" and "b"), add a constraint to "bset" that ensures that the |
| 862 | * bound implied by "a" is (strictly) larger than the bound implied by "b". |
| 863 | * |
| 864 | * If both constraints imply lower bounds, then this means that "a" is |
| 865 | * active in the result. |
| 866 | * If both constraints imply upper bounds, then this means that "b" is |
| 867 | * active in the result. |
| 868 | */ |
| 869 | static __isl_give isl_basic_set *add_larger_bound_constraint( |
| 870 | __isl_take isl_basic_set *bset, isl_int *a, isl_int *b, |
| 871 | unsigned abs_pos, int strict) |
| 872 | { |
| 873 | int k; |
| 874 | isl_int t; |
| 875 | isl_size total; |
| 876 | |
| 877 | total = isl_basic_set_dim(bset, type: isl_dim_all); |
| 878 | if (total < 0) |
| 879 | return isl_basic_set_free(bset); |
| 880 | k = isl_basic_set_alloc_inequality(bset); |
| 881 | if (k < 0) |
| 882 | goto error; |
| 883 | |
| 884 | isl_int_init(t); |
| 885 | isl_int_neg(t, b[1 + abs_pos]); |
| 886 | |
| 887 | isl_seq_combine(dst: bset->ineq[k], m1: t, src1: a, m2: a[1 + abs_pos], src2: b, len: 1 + abs_pos); |
| 888 | isl_seq_combine(dst: bset->ineq[k] + 1 + abs_pos, |
| 889 | m1: t, src1: a + 1 + abs_pos + 1, m2: a[1 + abs_pos], src2: b + 1 + abs_pos + 1, |
| 890 | len: total - abs_pos); |
| 891 | |
| 892 | if (strict) |
| 893 | isl_int_sub_ui(bset->ineq[k][0], bset->ineq[k][0], 1); |
| 894 | |
| 895 | isl_int_clear(t); |
| 896 | |
| 897 | return bset; |
| 898 | error: |
| 899 | isl_basic_set_free(bset); |
| 900 | return NULL; |
| 901 | } |
| 902 | |
| 903 | /* Add constraints to "context" that ensure that "u" is the smallest |
| 904 | * (and therefore active) upper bound on "abs_pos" in "bset" and return |
| 905 | * the resulting basic set. |
| 906 | */ |
| 907 | static __isl_give isl_basic_set *set_smallest_upper_bound( |
| 908 | __isl_keep isl_basic_set *context, |
| 909 | __isl_keep isl_basic_set *bset, unsigned abs_pos, int n_upper, int u) |
| 910 | { |
| 911 | int j; |
| 912 | |
| 913 | context = isl_basic_set_copy(bset: context); |
| 914 | context = isl_basic_set_cow(bset: context); |
| 915 | |
| 916 | context = isl_basic_set_extend_constraints(base: context, n_eq: 0, n_ineq: n_upper - 1); |
| 917 | |
| 918 | for (j = 0; j < bset->n_ineq; ++j) { |
| 919 | if (j == u) |
| 920 | continue; |
| 921 | if (!isl_int_is_neg(bset->ineq[j][1 + abs_pos])) |
| 922 | continue; |
| 923 | context = add_larger_bound_constraint(bset: context, |
| 924 | a: bset->ineq[j], b: bset->ineq[u], abs_pos, strict: j > u); |
| 925 | } |
| 926 | |
| 927 | context = isl_basic_set_simplify(bset: context); |
| 928 | context = isl_basic_set_finalize(bset: context); |
| 929 | |
| 930 | return context; |
| 931 | } |
| 932 | |
| 933 | /* Add constraints to "context" that ensure that "u" is the largest |
| 934 | * (and therefore active) upper bound on "abs_pos" in "bset" and return |
| 935 | * the resulting basic set. |
| 936 | */ |
| 937 | static __isl_give isl_basic_set *set_largest_lower_bound( |
| 938 | __isl_keep isl_basic_set *context, |
| 939 | __isl_keep isl_basic_set *bset, unsigned abs_pos, int n_lower, int l) |
| 940 | { |
| 941 | int j; |
| 942 | |
| 943 | context = isl_basic_set_copy(bset: context); |
| 944 | context = isl_basic_set_cow(bset: context); |
| 945 | |
| 946 | context = isl_basic_set_extend_constraints(base: context, n_eq: 0, n_ineq: n_lower - 1); |
| 947 | |
| 948 | for (j = 0; j < bset->n_ineq; ++j) { |
| 949 | if (j == l) |
| 950 | continue; |
| 951 | if (!isl_int_is_pos(bset->ineq[j][1 + abs_pos])) |
| 952 | continue; |
| 953 | context = add_larger_bound_constraint(bset: context, |
| 954 | a: bset->ineq[l], b: bset->ineq[j], abs_pos, strict: j > l); |
| 955 | } |
| 956 | |
| 957 | context = isl_basic_set_simplify(bset: context); |
| 958 | context = isl_basic_set_finalize(bset: context); |
| 959 | |
| 960 | return context; |
| 961 | } |
| 962 | |
| 963 | static isl_stat foreach_upper_bound(__isl_keep isl_basic_set *bset, |
| 964 | enum isl_dim_type type, unsigned abs_pos, |
| 965 | __isl_take isl_basic_set *context, int n_upper, |
| 966 | isl_stat (*fn)(__isl_take isl_constraint *lower, |
| 967 | __isl_take isl_constraint *upper, |
| 968 | __isl_take isl_basic_set *bset, void *user), void *user) |
| 969 | { |
| 970 | isl_basic_set *context_i; |
| 971 | isl_constraint *upper = NULL; |
| 972 | int i; |
| 973 | |
| 974 | for (i = 0; i < bset->n_ineq; ++i) { |
| 975 | if (isl_int_is_zero(bset->ineq[i][1 + abs_pos])) |
| 976 | continue; |
| 977 | |
| 978 | context_i = set_smallest_upper_bound(context, bset, |
| 979 | abs_pos, n_upper, u: i); |
| 980 | if (isl_basic_set_is_empty(bset: context_i)) { |
| 981 | isl_basic_set_free(bset: context_i); |
| 982 | continue; |
| 983 | } |
| 984 | upper = isl_basic_set_constraint(bset: isl_basic_set_copy(bset), |
| 985 | line: &bset->ineq[i]); |
| 986 | if (!upper || !context_i) |
| 987 | goto error; |
| 988 | if (fn(NULL, upper, context_i, user) < 0) |
| 989 | break; |
| 990 | } |
| 991 | |
| 992 | isl_basic_set_free(bset: context); |
| 993 | |
| 994 | if (i < bset->n_ineq) |
| 995 | return isl_stat_error; |
| 996 | |
| 997 | return isl_stat_ok; |
| 998 | error: |
| 999 | isl_constraint_free(c: upper); |
| 1000 | isl_basic_set_free(bset: context_i); |
| 1001 | isl_basic_set_free(bset: context); |
| 1002 | return isl_stat_error; |
| 1003 | } |
| 1004 | |
| 1005 | static isl_stat foreach_lower_bound(__isl_keep isl_basic_set *bset, |
| 1006 | enum isl_dim_type type, unsigned abs_pos, |
| 1007 | __isl_take isl_basic_set *context, int n_lower, |
| 1008 | isl_stat (*fn)(__isl_take isl_constraint *lower, |
| 1009 | __isl_take isl_constraint *upper, |
| 1010 | __isl_take isl_basic_set *bset, void *user), void *user) |
| 1011 | { |
| 1012 | isl_basic_set *context_i; |
| 1013 | isl_constraint *lower = NULL; |
| 1014 | int i; |
| 1015 | |
| 1016 | for (i = 0; i < bset->n_ineq; ++i) { |
| 1017 | if (isl_int_is_zero(bset->ineq[i][1 + abs_pos])) |
| 1018 | continue; |
| 1019 | |
| 1020 | context_i = set_largest_lower_bound(context, bset, |
| 1021 | abs_pos, n_lower, l: i); |
| 1022 | if (isl_basic_set_is_empty(bset: context_i)) { |
| 1023 | isl_basic_set_free(bset: context_i); |
| 1024 | continue; |
| 1025 | } |
| 1026 | lower = isl_basic_set_constraint(bset: isl_basic_set_copy(bset), |
| 1027 | line: &bset->ineq[i]); |
| 1028 | if (!lower || !context_i) |
| 1029 | goto error; |
| 1030 | if (fn(lower, NULL, context_i, user) < 0) |
| 1031 | break; |
| 1032 | } |
| 1033 | |
| 1034 | isl_basic_set_free(bset: context); |
| 1035 | |
| 1036 | if (i < bset->n_ineq) |
| 1037 | return isl_stat_error; |
| 1038 | |
| 1039 | return isl_stat_ok; |
| 1040 | error: |
| 1041 | isl_constraint_free(c: lower); |
| 1042 | isl_basic_set_free(bset: context_i); |
| 1043 | isl_basic_set_free(bset: context); |
| 1044 | return isl_stat_error; |
| 1045 | } |
| 1046 | |
| 1047 | static isl_stat foreach_bound_pair(__isl_keep isl_basic_set *bset, |
| 1048 | enum isl_dim_type type, unsigned abs_pos, |
| 1049 | __isl_take isl_basic_set *context, int n_lower, int n_upper, |
| 1050 | isl_stat (*fn)(__isl_take isl_constraint *lower, |
| 1051 | __isl_take isl_constraint *upper, |
| 1052 | __isl_take isl_basic_set *bset, void *user), void *user) |
| 1053 | { |
| 1054 | isl_basic_set *context_i, *context_j; |
| 1055 | isl_constraint *lower = NULL; |
| 1056 | isl_constraint *upper = NULL; |
| 1057 | int i, j; |
| 1058 | |
| 1059 | for (i = 0; i < bset->n_ineq; ++i) { |
| 1060 | if (!isl_int_is_pos(bset->ineq[i][1 + abs_pos])) |
| 1061 | continue; |
| 1062 | |
| 1063 | context_i = set_largest_lower_bound(context, bset, |
| 1064 | abs_pos, n_lower, l: i); |
| 1065 | if (isl_basic_set_is_empty(bset: context_i)) { |
| 1066 | isl_basic_set_free(bset: context_i); |
| 1067 | continue; |
| 1068 | } |
| 1069 | |
| 1070 | for (j = 0; j < bset->n_ineq; ++j) { |
| 1071 | if (!isl_int_is_neg(bset->ineq[j][1 + abs_pos])) |
| 1072 | continue; |
| 1073 | |
| 1074 | context_j = set_smallest_upper_bound(context: context_i, bset, |
| 1075 | abs_pos, n_upper, u: j); |
| 1076 | context_j = isl_basic_set_extend_constraints(base: context_j, |
| 1077 | n_eq: 0, n_ineq: 1); |
| 1078 | context_j = add_larger_bound_constraint(bset: context_j, |
| 1079 | a: bset->ineq[i], b: bset->ineq[j], abs_pos, strict: 0); |
| 1080 | context_j = isl_basic_set_simplify(bset: context_j); |
| 1081 | context_j = isl_basic_set_finalize(bset: context_j); |
| 1082 | if (isl_basic_set_is_empty(bset: context_j)) { |
| 1083 | isl_basic_set_free(bset: context_j); |
| 1084 | continue; |
| 1085 | } |
| 1086 | lower = isl_basic_set_constraint(bset: isl_basic_set_copy(bset), |
| 1087 | line: &bset->ineq[i]); |
| 1088 | upper = isl_basic_set_constraint(bset: isl_basic_set_copy(bset), |
| 1089 | line: &bset->ineq[j]); |
| 1090 | if (!lower || !upper || !context_j) |
| 1091 | goto error; |
| 1092 | if (fn(lower, upper, context_j, user) < 0) |
| 1093 | break; |
| 1094 | } |
| 1095 | |
| 1096 | isl_basic_set_free(bset: context_i); |
| 1097 | |
| 1098 | if (j < bset->n_ineq) |
| 1099 | break; |
| 1100 | } |
| 1101 | |
| 1102 | isl_basic_set_free(bset: context); |
| 1103 | |
| 1104 | if (i < bset->n_ineq) |
| 1105 | return isl_stat_error; |
| 1106 | |
| 1107 | return isl_stat_ok; |
| 1108 | error: |
| 1109 | isl_constraint_free(c: lower); |
| 1110 | isl_constraint_free(c: upper); |
| 1111 | isl_basic_set_free(bset: context_i); |
| 1112 | isl_basic_set_free(bset: context_j); |
| 1113 | isl_basic_set_free(bset: context); |
| 1114 | return isl_stat_error; |
| 1115 | } |
| 1116 | |
| 1117 | /* For each pair of lower and upper bounds on the variable "pos" |
| 1118 | * of type "type", call "fn" with these lower and upper bounds and the |
| 1119 | * set of constraints on the remaining variables where these bounds |
| 1120 | * are active, i.e., (stricly) larger/smaller than the other lower/upper bounds. |
| 1121 | * |
| 1122 | * If the designated variable is equal to an affine combination of the |
| 1123 | * other variables then fn is called with both lower and upper |
| 1124 | * set to the corresponding equality. |
| 1125 | * |
| 1126 | * If there is no lower (or upper) bound, then NULL is passed |
| 1127 | * as the corresponding bound. |
| 1128 | * |
| 1129 | * We first check if the variable is involved in any equality. |
| 1130 | * If not, we count the number of lower and upper bounds and |
| 1131 | * act accordingly. |
| 1132 | */ |
| 1133 | isl_stat isl_basic_set_foreach_bound_pair(__isl_keep isl_basic_set *bset, |
| 1134 | enum isl_dim_type type, unsigned pos, |
| 1135 | isl_stat (*fn)(__isl_take isl_constraint *lower, |
| 1136 | __isl_take isl_constraint *upper, |
| 1137 | __isl_take isl_basic_set *bset, void *user), void *user) |
| 1138 | { |
| 1139 | int i; |
| 1140 | isl_constraint *lower = NULL; |
| 1141 | isl_constraint *upper = NULL; |
| 1142 | isl_basic_set *context = NULL; |
| 1143 | unsigned abs_pos; |
| 1144 | int n_lower, n_upper; |
| 1145 | isl_size off; |
| 1146 | |
| 1147 | if (isl_basic_set_check_range(bset, type, first: pos, n: 1) < 0) |
| 1148 | return isl_stat_error; |
| 1149 | isl_assert(bset->ctx, type == isl_dim_param || type == isl_dim_set, |
| 1150 | return isl_stat_error); |
| 1151 | |
| 1152 | off = isl_basic_set_var_offset(bset, type); |
| 1153 | if (off < 0) |
| 1154 | return isl_stat_error; |
| 1155 | abs_pos = off + pos; |
| 1156 | |
| 1157 | for (i = 0; i < bset->n_eq; ++i) { |
| 1158 | if (isl_int_is_zero(bset->eq[i][1 + abs_pos])) |
| 1159 | continue; |
| 1160 | |
| 1161 | lower = isl_basic_set_constraint(bset: isl_basic_set_copy(bset), |
| 1162 | line: &bset->eq[i]); |
| 1163 | upper = isl_constraint_copy(constraint: lower); |
| 1164 | context = isl_basic_set_remove_dims(bset: isl_basic_set_copy(bset), |
| 1165 | type, first: pos, n: 1); |
| 1166 | if (!lower || !upper || !context) |
| 1167 | goto error; |
| 1168 | return fn(lower, upper, context, user); |
| 1169 | } |
| 1170 | |
| 1171 | n_lower = 0; |
| 1172 | n_upper = 0; |
| 1173 | for (i = 0; i < bset->n_ineq; ++i) { |
| 1174 | if (isl_int_is_pos(bset->ineq[i][1 + abs_pos])) |
| 1175 | n_lower++; |
| 1176 | else if (isl_int_is_neg(bset->ineq[i][1 + abs_pos])) |
| 1177 | n_upper++; |
| 1178 | } |
| 1179 | |
| 1180 | context = isl_basic_set_copy(bset); |
| 1181 | context = isl_basic_set_cow(bset: context); |
| 1182 | if (!context) |
| 1183 | goto error; |
| 1184 | for (i = context->n_ineq - 1; i >= 0; --i) |
| 1185 | if (!isl_int_is_zero(context->ineq[i][1 + abs_pos])) |
| 1186 | isl_basic_set_drop_inequality(bset: context, pos: i); |
| 1187 | |
| 1188 | context = isl_basic_set_drop(bset: context, type, first: pos, n: 1); |
| 1189 | if (!n_lower && !n_upper) |
| 1190 | return fn(NULL, NULL, context, user); |
| 1191 | if (!n_lower) |
| 1192 | return foreach_upper_bound(bset, type, abs_pos, context, n_upper, |
| 1193 | fn, user); |
| 1194 | if (!n_upper) |
| 1195 | return foreach_lower_bound(bset, type, abs_pos, context, n_lower, |
| 1196 | fn, user); |
| 1197 | return foreach_bound_pair(bset, type, abs_pos, context, n_lower, n_upper, |
| 1198 | fn, user); |
| 1199 | error: |
| 1200 | isl_constraint_free(c: lower); |
| 1201 | isl_constraint_free(c: upper); |
| 1202 | isl_basic_set_free(bset: context); |
| 1203 | return isl_stat_error; |
| 1204 | } |
| 1205 | |
| 1206 | __isl_give isl_aff *isl_constraint_get_bound( |
| 1207 | __isl_keep isl_constraint *constraint, enum isl_dim_type type, int pos) |
| 1208 | { |
| 1209 | isl_space *space; |
| 1210 | isl_aff *aff; |
| 1211 | isl_ctx *ctx; |
| 1212 | |
| 1213 | if (isl_constraint_check_range(obj: constraint, type, first: pos, n: 1) < 0) |
| 1214 | return NULL; |
| 1215 | space = isl_constraint_peek_space(constraint); |
| 1216 | if (isl_space_check_is_set(space) < 0) |
| 1217 | return NULL; |
| 1218 | |
| 1219 | ctx = isl_constraint_get_ctx(c: constraint); |
| 1220 | pos += offset(c: constraint, type); |
| 1221 | if (isl_int_is_zero(constraint->v->el[pos])) |
| 1222 | isl_die(ctx, isl_error_invalid, |
| 1223 | "constraint does not define a bound on given dimension" , |
| 1224 | return NULL); |
| 1225 | |
| 1226 | aff = isl_aff_alloc(ls: isl_local_space_copy(ls: constraint->ls)); |
| 1227 | if (!aff) |
| 1228 | return NULL; |
| 1229 | |
| 1230 | if (isl_int_is_neg(constraint->v->el[pos])) |
| 1231 | isl_seq_cpy(dst: aff->v->el + 1, src: constraint->v->el, len: aff->v->size - 1); |
| 1232 | else |
| 1233 | isl_seq_neg(dst: aff->v->el + 1, src: constraint->v->el, len: aff->v->size - 1); |
| 1234 | isl_int_set_si(aff->v->el[1 + pos], 0); |
| 1235 | isl_int_abs(aff->v->el[0], constraint->v->el[pos]); |
| 1236 | aff = isl_aff_normalize(aff); |
| 1237 | |
| 1238 | return aff; |
| 1239 | } |
| 1240 | |
| 1241 | /* For an inequality constraint |
| 1242 | * |
| 1243 | * f >= 0 |
| 1244 | * |
| 1245 | * or an equality constraint |
| 1246 | * |
| 1247 | * f = 0 |
| 1248 | * |
| 1249 | * return the affine expression f. |
| 1250 | */ |
| 1251 | __isl_give isl_aff *isl_constraint_get_aff( |
| 1252 | __isl_keep isl_constraint *constraint) |
| 1253 | { |
| 1254 | isl_aff *aff; |
| 1255 | |
| 1256 | if (!constraint) |
| 1257 | return NULL; |
| 1258 | |
| 1259 | aff = isl_aff_alloc(ls: isl_local_space_copy(ls: constraint->ls)); |
| 1260 | if (!aff) |
| 1261 | return NULL; |
| 1262 | |
| 1263 | isl_seq_cpy(dst: aff->v->el + 1, src: constraint->v->el, len: aff->v->size - 1); |
| 1264 | isl_int_set_si(aff->v->el[0], 1); |
| 1265 | |
| 1266 | return aff; |
| 1267 | } |
| 1268 | |
| 1269 | /* Construct an inequality (eq = 0) or equality (eq = 1) constraint from "aff". |
| 1270 | * In particular, construct aff >= 0 or aff = 0. |
| 1271 | * |
| 1272 | * The denominator of "aff" can be ignored. |
| 1273 | */ |
| 1274 | static __isl_give isl_constraint *isl_constraint_alloc_aff(int eq, |
| 1275 | __isl_take isl_aff *aff) |
| 1276 | { |
| 1277 | isl_local_space *ls; |
| 1278 | isl_vec *v; |
| 1279 | |
| 1280 | if (!aff) |
| 1281 | return NULL; |
| 1282 | ls = isl_aff_get_domain_local_space(aff); |
| 1283 | v = isl_vec_drop_els(vec: isl_vec_copy(vec: aff->v), pos: 0, n: 1); |
| 1284 | isl_aff_free(aff); |
| 1285 | |
| 1286 | return isl_constraint_alloc_vec(eq, ls, v); |
| 1287 | } |
| 1288 | |
| 1289 | /* Construct an equality constraint equating the given affine expression |
| 1290 | * to zero. |
| 1291 | */ |
| 1292 | __isl_give isl_constraint *isl_equality_from_aff(__isl_take isl_aff *aff) |
| 1293 | { |
| 1294 | return isl_constraint_alloc_aff(eq: 1, aff); |
| 1295 | } |
| 1296 | |
| 1297 | /* Construct an inequality constraint enforcing the given affine expression |
| 1298 | * to be non-negative. |
| 1299 | */ |
| 1300 | __isl_give isl_constraint *isl_inequality_from_aff(__isl_take isl_aff *aff) |
| 1301 | { |
| 1302 | return isl_constraint_alloc_aff(eq: 0, aff); |
| 1303 | } |
| 1304 | |
| 1305 | /* Compare two isl_constraints. |
| 1306 | * |
| 1307 | * Return -1 if "c1" is "smaller" than "c2", 1 if "c1" is "greater" |
| 1308 | * than "c2" and 0 if they are equal. |
| 1309 | * |
| 1310 | * The order is fairly arbitrary. We do consider constraints that only involve |
| 1311 | * earlier dimensions as "smaller". |
| 1312 | */ |
| 1313 | int isl_constraint_plain_cmp(__isl_keep isl_constraint *c1, |
| 1314 | __isl_keep isl_constraint *c2) |
| 1315 | { |
| 1316 | int cmp; |
| 1317 | int last1, last2; |
| 1318 | |
| 1319 | if (c1 == c2) |
| 1320 | return 0; |
| 1321 | if (!c1) |
| 1322 | return -1; |
| 1323 | if (!c2) |
| 1324 | return 1; |
| 1325 | cmp = isl_local_space_cmp(ls1: c1->ls, ls2: c2->ls); |
| 1326 | if (cmp != 0) |
| 1327 | return cmp; |
| 1328 | |
| 1329 | last1 = isl_seq_last_non_zero(p: c1->v->el + 1, len: c1->v->size - 1); |
| 1330 | last2 = isl_seq_last_non_zero(p: c2->v->el + 1, len: c1->v->size - 1); |
| 1331 | if (last1 != last2) |
| 1332 | return last1 - last2; |
| 1333 | |
| 1334 | return isl_seq_cmp(p1: c1->v->el, p2: c2->v->el, len: c1->v->size); |
| 1335 | } |
| 1336 | |
| 1337 | /* Compare two constraints based on their final (non-zero) coefficients. |
| 1338 | * In particular, the constraint that involves later variables or |
| 1339 | * that has a larger coefficient for a shared latest variable |
| 1340 | * is considered "greater" than the other constraint. |
| 1341 | * |
| 1342 | * Return -1 if "c1" is "smaller" than "c2", 1 if "c1" is "greater" |
| 1343 | * than "c2" and 0 if they are equal. |
| 1344 | * |
| 1345 | * If the constraints live in different local spaces, then we cannot |
| 1346 | * really compare the constraints so we compare the local spaces instead. |
| 1347 | */ |
| 1348 | int isl_constraint_cmp_last_non_zero(__isl_keep isl_constraint *c1, |
| 1349 | __isl_keep isl_constraint *c2) |
| 1350 | { |
| 1351 | int cmp; |
| 1352 | int last1, last2; |
| 1353 | |
| 1354 | if (c1 == c2) |
| 1355 | return 0; |
| 1356 | if (!c1) |
| 1357 | return -1; |
| 1358 | if (!c2) |
| 1359 | return 1; |
| 1360 | cmp = isl_local_space_cmp(ls1: c1->ls, ls2: c2->ls); |
| 1361 | if (cmp != 0) |
| 1362 | return cmp; |
| 1363 | |
| 1364 | last1 = isl_seq_last_non_zero(p: c1->v->el + 1, len: c1->v->size - 1); |
| 1365 | last2 = isl_seq_last_non_zero(p: c2->v->el + 1, len: c1->v->size - 1); |
| 1366 | if (last1 != last2) |
| 1367 | return last1 - last2; |
| 1368 | if (last1 == -1) |
| 1369 | return 0; |
| 1370 | return isl_int_abs_cmp(c1->v->el[1 + last1], c2->v->el[1 + last2]); |
| 1371 | } |
| 1372 | |