1 /* 2 * Copyright 2008-2009 Katholieke Universiteit Leuven 3 * Copyright 2010 INRIA Saclay 4 * Copyright 2013-2014 Ecole Normale Superieure 5 * Copyright 2018-2019 Cerebras Systems 6 * 7 * Use of this software is governed by the MIT license 8 * 9 * Written by Sven Verdoolaege, K.U.Leuven, Departement 10 * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium 11 * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite, 12 * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 13 * and Ecole Normale Superieure, 45 rue dUlm, 75230 Paris, France 14 * and Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA 15 */ 16 17 #include <stdlib.h> 18 #include <string.h> 19 #include <isl_space_private.h> 20 #include <isl_id_private.h> 21 #include <isl_reordering.h> 22 23 isl_ctx *isl_space_get_ctx(__isl_keep isl_space *space) 24 { 25 return space ? space->ctx : NULL; 26 } 27 28 __isl_give isl_space *isl_space_alloc(isl_ctx *ctx, 29 unsigned nparam, unsigned n_in, unsigned n_out) 30 { 31 isl_space *space; 32 33 space = isl_alloc_type(ctx, struct isl_space); 34 if (!space) 35 return NULL; 36 37 space->ctx = ctx; 38 isl_ctx_ref(ctx); 39 space->ref = 1; 40 space->nparam = nparam; 41 space->n_in = n_in; 42 space->n_out = n_out; 43 44 space->tuple_id[0] = NULL; 45 space->tuple_id[1] = NULL; 46 47 space->nested[0] = NULL; 48 space->nested[1] = NULL; 49 50 space->n_id = 0; 51 space->ids = NULL; 52 53 return space; 54 } 55 56 /* Mark the space as being that of a set, by setting the domain tuple 57 * to isl_id_none. 58 */ 59 static __isl_give isl_space *mark_as_set(__isl_take isl_space *space) 60 { 61 space = isl_space_cow(space); 62 if (!space) 63 return NULL; 64 space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none); 65 return space; 66 } 67 68 /* Is the space that of a set? 69 */ 70 isl_bool isl_space_is_set(__isl_keep isl_space *space) 71 { 72 if (!space) 73 return isl_bool_error; 74 if (space->n_in != 0 || space->nested[0]) 75 return isl_bool_false; 76 if (space->tuple_id[0] != &isl_id_none) 77 return isl_bool_false; 78 return isl_bool_true; 79 } 80 81 /* Check that "space" is a set space. 82 */ 83 isl_stat isl_space_check_is_set(__isl_keep isl_space *space) 84 { 85 isl_bool is_set; 86 87 is_set = isl_space_is_set(space); 88 if (is_set < 0) 89 return isl_stat_error; 90 if (!is_set) 91 isl_die(isl_space_get_ctx(space), isl_error_invalid, 92 "space is not a set", return isl_stat_error); 93 return isl_stat_ok; 94 } 95 96 /* Is the given space that of a map? 97 */ 98 isl_bool isl_space_is_map(__isl_keep isl_space *space) 99 { 100 int r; 101 102 if (!space) 103 return isl_bool_error; 104 r = space->tuple_id[0] != &isl_id_none && 105 space->tuple_id[1] != &isl_id_none; 106 return isl_bool_ok(r); 107 } 108 109 /* Check that "space" is the space of a map. 110 */ 111 static isl_stat isl_space_check_is_map(__isl_keep isl_space *space) 112 { 113 isl_bool is_space; 114 115 is_space = isl_space_is_map(space); 116 if (is_space < 0) 117 return isl_stat_error; 118 if (!is_space) 119 isl_die(isl_space_get_ctx(space), isl_error_invalid, 120 "expecting map space", return isl_stat_error); 121 return isl_stat_ok; 122 } 123 124 /* Check that "space" is the space of a set wrapping a map space. 125 */ 126 isl_stat isl_space_check_is_wrapping(__isl_keep isl_space *space) 127 { 128 isl_bool wrapping; 129 130 wrapping = isl_space_is_wrapping(space); 131 if (wrapping < 0) 132 return isl_stat_error; 133 if (!wrapping) 134 isl_die(isl_space_get_ctx(space), isl_error_invalid, 135 "not a product", return isl_stat_error); 136 return isl_stat_ok; 137 } 138 139 /* Check that "space" is the space of a map 140 * where the domain is a wrapped map space. 141 */ 142 isl_stat isl_space_check_domain_is_wrapping(__isl_keep isl_space *space) 143 { 144 isl_bool wrapping; 145 146 wrapping = isl_space_domain_is_wrapping(space); 147 if (wrapping < 0) 148 return isl_stat_error; 149 if (!wrapping) 150 isl_die(isl_space_get_ctx(space), isl_error_invalid, 151 "domain not a product", return isl_stat_error); 152 return isl_stat_ok; 153 } 154 155 /* Check that "space" is the space of a map 156 * where the range is a wrapped map space. 157 */ 158 isl_stat isl_space_check_range_is_wrapping(__isl_keep isl_space *space) 159 { 160 isl_bool wrapping; 161 162 wrapping = isl_space_range_is_wrapping(space); 163 if (wrapping < 0) 164 return isl_stat_error; 165 if (!wrapping) 166 isl_die(isl_space_get_ctx(space), isl_error_invalid, 167 "range not a product", return isl_stat_error); 168 return isl_stat_ok; 169 } 170 171 __isl_give isl_space *isl_space_set_alloc(isl_ctx *ctx, 172 unsigned nparam, unsigned dim) 173 { 174 isl_space *space; 175 space = isl_space_alloc(ctx, nparam, 0, dim); 176 space = mark_as_set(space); 177 return space; 178 } 179 180 /* Mark the space as being that of a parameter domain, by setting 181 * both tuples to isl_id_none. 182 */ 183 static __isl_give isl_space *mark_as_params(isl_space *space) 184 { 185 if (!space) 186 return NULL; 187 space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none); 188 space = isl_space_set_tuple_id(space, isl_dim_out, &isl_id_none); 189 return space; 190 } 191 192 /* Is the space that of a parameter domain? 193 */ 194 isl_bool isl_space_is_params(__isl_keep isl_space *space) 195 { 196 if (!space) 197 return isl_bool_error; 198 if (space->n_in != 0 || space->nested[0] || 199 space->n_out != 0 || space->nested[1]) 200 return isl_bool_false; 201 if (space->tuple_id[0] != &isl_id_none) 202 return isl_bool_false; 203 if (space->tuple_id[1] != &isl_id_none) 204 return isl_bool_false; 205 return isl_bool_true; 206 } 207 208 /* Create a space for a parameter domain. 209 */ 210 __isl_give isl_space *isl_space_params_alloc(isl_ctx *ctx, unsigned nparam) 211 { 212 isl_space *space; 213 space = isl_space_alloc(ctx, nparam, 0, 0); 214 space = mark_as_params(space); 215 return space; 216 } 217 218 /* Create a space for a parameter domain, without any parameters. 219 */ 220 __isl_give isl_space *isl_space_unit(isl_ctx *ctx) 221 { 222 return isl_space_params_alloc(ctx, 0); 223 } 224 225 static isl_size global_pos(__isl_keep isl_space *space, 226 enum isl_dim_type type, unsigned pos) 227 { 228 if (isl_space_check_range(space, type, pos, 1) < 0) 229 return isl_size_error; 230 231 switch (type) { 232 case isl_dim_param: 233 return pos; 234 case isl_dim_in: 235 return pos + space->nparam; 236 case isl_dim_out: 237 return pos + space->nparam + space->n_in; 238 default: 239 isl_assert(isl_space_get_ctx(space), 0, return isl_size_error); 240 } 241 return isl_size_error; 242 } 243 244 /* Extend length of ids array to the total number of dimensions. 245 */ 246 static __isl_give isl_space *extend_ids(__isl_take isl_space *space) 247 { 248 isl_id **ids; 249 int i; 250 isl_size dim; 251 252 dim = isl_space_dim(space, isl_dim_all); 253 if (dim < 0) 254 return isl_space_free(space); 255 if (dim <= space->n_id) 256 return space; 257 258 if (!space->ids) { 259 space->ids = isl_calloc_array(space->ctx, isl_id *, dim); 260 if (!space->ids) 261 goto error; 262 } else { 263 ids = isl_realloc_array(space->ctx, space->ids, isl_id *, dim); 264 if (!ids) 265 goto error; 266 space->ids = ids; 267 for (i = space->n_id; i < dim; ++i) 268 space->ids[i] = NULL; 269 } 270 271 space->n_id = dim; 272 273 return space; 274 error: 275 isl_space_free(space); 276 return NULL; 277 } 278 279 static __isl_give isl_space *set_id(__isl_take isl_space *space, 280 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) 281 { 282 isl_size gpos; 283 284 space = isl_space_cow(space); 285 286 gpos = global_pos(space, type, pos); 287 if (gpos < 0) 288 goto error; 289 290 if (gpos >= space->n_id) { 291 if (!id) 292 return space; 293 space = extend_ids(space); 294 if (!space) 295 goto error; 296 } 297 298 space->ids[gpos] = id; 299 300 return space; 301 error: 302 isl_id_free(id); 303 isl_space_free(space); 304 return NULL; 305 } 306 307 static __isl_keep isl_id *get_id(__isl_keep isl_space *space, 308 enum isl_dim_type type, unsigned pos) 309 { 310 isl_size gpos; 311 312 gpos = global_pos(space, type, pos); 313 if (gpos < 0) 314 return NULL; 315 if (gpos >= space->n_id) 316 return NULL; 317 return space->ids[gpos]; 318 } 319 320 /* Return the nested space at the given position. 321 */ 322 static __isl_keep isl_space *isl_space_peek_nested(__isl_keep isl_space *space, 323 int pos) 324 { 325 if (!space) 326 return NULL; 327 if (!space->nested[pos]) 328 isl_die(isl_space_get_ctx(space), isl_error_invalid, 329 "no nested space", return NULL); 330 return space->nested[pos]; 331 } 332 333 static unsigned offset(__isl_keep isl_space *space, enum isl_dim_type type) 334 { 335 switch (type) { 336 case isl_dim_param: return 0; 337 case isl_dim_in: return space->nparam; 338 case isl_dim_out: return space->nparam + space->n_in; 339 default: return 0; 340 } 341 } 342 343 static unsigned n(__isl_keep isl_space *space, enum isl_dim_type type) 344 { 345 switch (type) { 346 case isl_dim_param: return space->nparam; 347 case isl_dim_in: return space->n_in; 348 case isl_dim_out: return space->n_out; 349 case isl_dim_all: 350 return space->nparam + space->n_in + space->n_out; 351 default: return 0; 352 } 353 } 354 355 isl_size isl_space_dim(__isl_keep isl_space *space, enum isl_dim_type type) 356 { 357 if (!space) 358 return isl_size_error; 359 return n(space, type); 360 } 361 362 /* Return the dimensionality of tuple "inner" within the wrapped relation 363 * inside tuple "outer". 364 */ 365 isl_size isl_space_wrapped_dim(__isl_keep isl_space *space, 366 enum isl_dim_type outer, enum isl_dim_type inner) 367 { 368 int pos; 369 370 if (!space) 371 return isl_size_error; 372 if (outer != isl_dim_in && outer != isl_dim_out) 373 isl_die(isl_space_get_ctx(space), isl_error_invalid, 374 "only input, output and set tuples " 375 "can have nested relations", return isl_size_error); 376 pos = outer - isl_dim_in; 377 return isl_space_dim(isl_space_peek_nested(space, pos), inner); 378 } 379 380 isl_size isl_space_offset(__isl_keep isl_space *space, enum isl_dim_type type) 381 { 382 if (!space) 383 return isl_size_error; 384 return offset(space, type); 385 } 386 387 static __isl_give isl_space *copy_ids(__isl_take isl_space *dst, 388 enum isl_dim_type dst_type, unsigned offset, __isl_keep isl_space *src, 389 enum isl_dim_type src_type) 390 { 391 int i; 392 isl_id *id; 393 394 if (!dst) 395 return NULL; 396 397 for (i = 0; i < n(src, src_type); ++i) { 398 id = get_id(src, src_type, i); 399 if (!id) 400 continue; 401 isl_id_free(get_id(dst, dst_type, offset + i)); 402 dst = set_id(dst, dst_type, offset + i, isl_id_copy(id)); 403 if (!dst) 404 return NULL; 405 } 406 return dst; 407 } 408 409 __isl_give isl_space *isl_space_dup(__isl_keep isl_space *space) 410 { 411 isl_space *dup; 412 if (!space) 413 return NULL; 414 dup = isl_space_alloc(space->ctx, 415 space->nparam, space->n_in, space->n_out); 416 if (!dup) 417 return NULL; 418 if (space->tuple_id[0] && 419 !(dup->tuple_id[0] = isl_id_copy(space->tuple_id[0]))) 420 goto error; 421 if (space->tuple_id[1] && 422 !(dup->tuple_id[1] = isl_id_copy(space->tuple_id[1]))) 423 goto error; 424 if (space->nested[0] && 425 !(dup->nested[0] = isl_space_copy(space->nested[0]))) 426 goto error; 427 if (space->nested[1] && 428 !(dup->nested[1] = isl_space_copy(space->nested[1]))) 429 goto error; 430 if (!space->ids) 431 return dup; 432 dup = copy_ids(dup, isl_dim_param, 0, space, isl_dim_param); 433 dup = copy_ids(dup, isl_dim_in, 0, space, isl_dim_in); 434 dup = copy_ids(dup, isl_dim_out, 0, space, isl_dim_out); 435 return dup; 436 error: 437 isl_space_free(dup); 438 return NULL; 439 } 440 441 __isl_give isl_space *isl_space_cow(__isl_take isl_space *space) 442 { 443 if (!space) 444 return NULL; 445 446 if (space->ref == 1) 447 return space; 448 space->ref--; 449 return isl_space_dup(space); 450 } 451 452 __isl_give isl_space *isl_space_copy(__isl_keep isl_space *space) 453 { 454 if (!space) 455 return NULL; 456 457 space->ref++; 458 return space; 459 } 460 461 __isl_null isl_space *isl_space_free(__isl_take isl_space *space) 462 { 463 int i; 464 465 if (!space) 466 return NULL; 467 468 if (--space->ref > 0) 469 return NULL; 470 471 isl_id_free(space->tuple_id[0]); 472 isl_id_free(space->tuple_id[1]); 473 474 isl_space_free(space->nested[0]); 475 isl_space_free(space->nested[1]); 476 477 for (i = 0; i < space->n_id; ++i) 478 isl_id_free(space->ids[i]); 479 free(space->ids); 480 isl_ctx_deref(space->ctx); 481 482 free(space); 483 484 return NULL; 485 } 486 487 /* Check if "s" is a valid dimension or tuple name. 488 * We currently only forbid names that look like a number. 489 * 490 * s is assumed to be non-NULL. 491 */ 492 static int name_ok(isl_ctx *ctx, const char *s) 493 { 494 char *p; 495 496 strtol(s, &p, 0); 497 if (p != s) 498 isl_die(ctx, isl_error_invalid, "name looks like a number", 499 return 0); 500 501 return 1; 502 } 503 504 /* Return a copy of the nested space at the given position. 505 */ 506 static __isl_keep isl_space *isl_space_get_nested(__isl_keep isl_space *space, 507 int pos) 508 { 509 return isl_space_copy(isl_space_peek_nested(space, pos)); 510 } 511 512 /* Return the nested space at the given position. 513 * This may be either a copy or the nested space itself 514 * if there is only one reference to "space". 515 * This allows the nested space to be modified inplace 516 * if both "space" and the nested space have only a single reference. 517 * The caller is not allowed to modify "space" between this call and 518 * a subsequent call to isl_space_restore_nested. 519 * The only exception is that isl_space_free can be called instead. 520 */ 521 static __isl_give isl_space *isl_space_take_nested(__isl_keep isl_space *space, 522 int pos) 523 { 524 isl_space *nested; 525 526 if (!space) 527 return NULL; 528 if (space->ref != 1) 529 return isl_space_get_nested(space, pos); 530 nested = space->nested[pos]; 531 space->nested[pos] = NULL; 532 return nested; 533 } 534 535 /* Replace the nested space at the given position by "nested", 536 * where this nested space of "space" may be missing 537 * due to a preceding call to isl_space_take_nested. 538 * However, in this case, "space" only has a single reference and 539 * then the call to isl_space_cow has no effect. 540 */ 541 static __isl_give isl_space *isl_space_restore_nested( 542 __isl_take isl_space *space, int pos, __isl_take isl_space *nested) 543 { 544 if (!space || !nested) 545 goto error; 546 547 if (space->nested[pos] == nested) { 548 isl_space_free(nested); 549 return space; 550 } 551 552 space = isl_space_cow(space); 553 if (!space) 554 goto error; 555 isl_space_free(space->nested[pos]); 556 space->nested[pos] = nested; 557 558 return space; 559 error: 560 isl_space_free(space); 561 isl_space_free(nested); 562 return NULL; 563 } 564 565 /* Is it possible for the given dimension type to have a tuple id? 566 */ 567 static int space_can_have_id(__isl_keep isl_space *space, 568 enum isl_dim_type type) 569 { 570 if (!space) 571 return 0; 572 if (isl_space_is_params(space)) 573 isl_die(space->ctx, isl_error_invalid, 574 "parameter spaces don't have tuple ids", return 0); 575 if (isl_space_is_set(space) && type != isl_dim_set) 576 isl_die(space->ctx, isl_error_invalid, 577 "set spaces can only have a set id", return 0); 578 if (type != isl_dim_in && type != isl_dim_out) 579 isl_die(space->ctx, isl_error_invalid, 580 "only input, output and set tuples can have ids", 581 return 0); 582 583 return 1; 584 } 585 586 /* Does the tuple have an id? 587 */ 588 isl_bool isl_space_has_tuple_id(__isl_keep isl_space *space, 589 enum isl_dim_type type) 590 { 591 if (!space_can_have_id(space, type)) 592 return isl_bool_error; 593 return isl_bool_ok(space->tuple_id[type - isl_dim_in] != NULL); 594 } 595 596 /* Does the domain tuple of the map space "space" have an identifier? 597 */ 598 isl_bool isl_space_has_domain_tuple_id(__isl_keep isl_space *space) 599 { 600 if (isl_space_check_is_map(space) < 0) 601 return isl_bool_error; 602 return isl_space_has_tuple_id(space, isl_dim_in); 603 } 604 605 /* Does the range tuple of the map space "space" have an identifier? 606 */ 607 isl_bool isl_space_has_range_tuple_id(__isl_keep isl_space *space) 608 { 609 if (isl_space_check_is_map(space) < 0) 610 return isl_bool_error; 611 return isl_space_has_tuple_id(space, isl_dim_out); 612 } 613 614 __isl_give isl_id *isl_space_get_tuple_id(__isl_keep isl_space *space, 615 enum isl_dim_type type) 616 { 617 int has_id; 618 619 if (!space) 620 return NULL; 621 has_id = isl_space_has_tuple_id(space, type); 622 if (has_id < 0) 623 return NULL; 624 if (!has_id) 625 isl_die(space->ctx, isl_error_invalid, 626 "tuple has no id", return NULL); 627 return isl_id_copy(space->tuple_id[type - isl_dim_in]); 628 } 629 630 /* Return the identifier of the domain tuple of the map space "space", 631 * assuming it has one. 632 */ 633 __isl_give isl_id *isl_space_get_domain_tuple_id( 634 __isl_keep isl_space *space) 635 { 636 if (isl_space_check_is_map(space) < 0) 637 return NULL; 638 return isl_space_get_tuple_id(space, isl_dim_in); 639 } 640 641 /* Return the identifier of the range tuple of the map space "space", 642 * assuming it has one. 643 */ 644 __isl_give isl_id *isl_space_get_range_tuple_id( 645 __isl_keep isl_space *space) 646 { 647 if (isl_space_check_is_map(space) < 0) 648 return NULL; 649 return isl_space_get_tuple_id(space, isl_dim_out); 650 } 651 652 __isl_give isl_space *isl_space_set_tuple_id(__isl_take isl_space *space, 653 enum isl_dim_type type, __isl_take isl_id *id) 654 { 655 space = isl_space_cow(space); 656 if (!space || !id) 657 goto error; 658 if (type != isl_dim_in && type != isl_dim_out) 659 isl_die(space->ctx, isl_error_invalid, 660 "only input, output and set tuples can have names", 661 goto error); 662 663 isl_id_free(space->tuple_id[type - isl_dim_in]); 664 space->tuple_id[type - isl_dim_in] = id; 665 666 return space; 667 error: 668 isl_id_free(id); 669 isl_space_free(space); 670 return NULL; 671 } 672 673 /* Replace the identifier of the domain tuple of the map space "space" 674 * by "id". 675 */ 676 __isl_give isl_space *isl_space_set_domain_tuple_id( 677 __isl_take isl_space *space, __isl_take isl_id *id) 678 { 679 if (isl_space_check_is_map(space) < 0) 680 space = isl_space_free(space); 681 return isl_space_set_tuple_id(space, isl_dim_in, id); 682 } 683 684 /* Replace the identifier of the range tuple of the map space "space" 685 * by "id". 686 */ 687 __isl_give isl_space *isl_space_set_range_tuple_id( 688 __isl_take isl_space *space, __isl_take isl_id *id) 689 { 690 if (isl_space_check_is_map(space) < 0) 691 space = isl_space_free(space); 692 return isl_space_set_tuple_id(space, isl_dim_out, id); 693 } 694 695 __isl_give isl_space *isl_space_reset_tuple_id(__isl_take isl_space *space, 696 enum isl_dim_type type) 697 { 698 space = isl_space_cow(space); 699 if (!space) 700 return NULL; 701 if (type != isl_dim_in && type != isl_dim_out) 702 isl_die(space->ctx, isl_error_invalid, 703 "only input, output and set tuples can have names", 704 goto error); 705 706 isl_id_free(space->tuple_id[type - isl_dim_in]); 707 space->tuple_id[type - isl_dim_in] = NULL; 708 709 return space; 710 error: 711 isl_space_free(space); 712 return NULL; 713 } 714 715 /* Set the id of the given dimension of "space" to "id". 716 * If the dimension already has an id, then it is replaced. 717 * If the dimension is a parameter, then we need to change it 718 * in the nested spaces (if any) as well. 719 */ 720 __isl_give isl_space *isl_space_set_dim_id(__isl_take isl_space *space, 721 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) 722 { 723 space = isl_space_cow(space); 724 if (!space || !id) 725 goto error; 726 727 if (type == isl_dim_param) { 728 int i; 729 730 for (i = 0; i < 2; ++i) { 731 if (!space->nested[i]) 732 continue; 733 space->nested[i] = 734 isl_space_set_dim_id(space->nested[i], 735 type, pos, isl_id_copy(id)); 736 if (!space->nested[i]) 737 goto error; 738 } 739 } 740 741 isl_id_free(get_id(space, type, pos)); 742 return set_id(space, type, pos, id); 743 error: 744 isl_id_free(id); 745 isl_space_free(space); 746 return NULL; 747 } 748 749 /* Reset the id of the given dimension of "space". 750 * If the dimension already has an id, then it is removed. 751 * If the dimension is a parameter, then we need to reset it 752 * in the nested spaces (if any) as well. 753 */ 754 __isl_give isl_space *isl_space_reset_dim_id(__isl_take isl_space *space, 755 enum isl_dim_type type, unsigned pos) 756 { 757 space = isl_space_cow(space); 758 if (!space) 759 goto error; 760 761 if (type == isl_dim_param) { 762 int i; 763 764 for (i = 0; i < 2; ++i) { 765 if (!space->nested[i]) 766 continue; 767 space->nested[i] = 768 isl_space_reset_dim_id(space->nested[i], 769 type, pos); 770 if (!space->nested[i]) 771 goto error; 772 } 773 } 774 775 isl_id_free(get_id(space, type, pos)); 776 return set_id(space, type, pos, NULL); 777 error: 778 isl_space_free(space); 779 return NULL; 780 } 781 782 isl_bool isl_space_has_dim_id(__isl_keep isl_space *space, 783 enum isl_dim_type type, unsigned pos) 784 { 785 if (!space) 786 return isl_bool_error; 787 return isl_bool_ok(get_id(space, type, pos) != NULL); 788 } 789 790 __isl_give isl_id *isl_space_get_dim_id(__isl_keep isl_space *space, 791 enum isl_dim_type type, unsigned pos) 792 { 793 if (!space) 794 return NULL; 795 if (!get_id(space, type, pos)) 796 isl_die(space->ctx, isl_error_invalid, 797 "dim has no id", return NULL); 798 return isl_id_copy(get_id(space, type, pos)); 799 } 800 801 __isl_give isl_space *isl_space_set_tuple_name(__isl_take isl_space *space, 802 enum isl_dim_type type, const char *s) 803 { 804 isl_id *id; 805 806 if (!space) 807 return NULL; 808 809 if (!s) 810 return isl_space_reset_tuple_id(space, type); 811 812 if (!name_ok(space->ctx, s)) 813 goto error; 814 815 id = isl_id_alloc(space->ctx, s, NULL); 816 return isl_space_set_tuple_id(space, type, id); 817 error: 818 isl_space_free(space); 819 return NULL; 820 } 821 822 /* Does the tuple have a name? 823 */ 824 isl_bool isl_space_has_tuple_name(__isl_keep isl_space *space, 825 enum isl_dim_type type) 826 { 827 isl_id *id; 828 829 if (!space_can_have_id(space, type)) 830 return isl_bool_error; 831 id = space->tuple_id[type - isl_dim_in]; 832 return isl_bool_ok(id && id->name); 833 } 834 835 __isl_keep const char *isl_space_get_tuple_name(__isl_keep isl_space *space, 836 enum isl_dim_type type) 837 { 838 isl_id *id; 839 if (!space) 840 return NULL; 841 if (type != isl_dim_in && type != isl_dim_out) 842 return NULL; 843 id = space->tuple_id[type - isl_dim_in]; 844 return id ? id->name : NULL; 845 } 846 847 __isl_give isl_space *isl_space_set_dim_name(__isl_take isl_space *space, 848 enum isl_dim_type type, unsigned pos, 849 const char *s) 850 { 851 isl_id *id; 852 853 if (!space) 854 return NULL; 855 if (!s) 856 return isl_space_reset_dim_id(space, type, pos); 857 if (!name_ok(space->ctx, s)) 858 goto error; 859 id = isl_id_alloc(space->ctx, s, NULL); 860 return isl_space_set_dim_id(space, type, pos, id); 861 error: 862 isl_space_free(space); 863 return NULL; 864 } 865 866 /* Does the given dimension have a name? 867 */ 868 isl_bool isl_space_has_dim_name(__isl_keep isl_space *space, 869 enum isl_dim_type type, unsigned pos) 870 { 871 isl_id *id; 872 873 if (!space) 874 return isl_bool_error; 875 id = get_id(space, type, pos); 876 return isl_bool_ok(id && id->name); 877 } 878 879 __isl_keep const char *isl_space_get_dim_name(__isl_keep isl_space *space, 880 enum isl_dim_type type, unsigned pos) 881 { 882 isl_id *id = get_id(space, type, pos); 883 return id ? id->name : NULL; 884 } 885 886 int isl_space_find_dim_by_id(__isl_keep isl_space *space, 887 enum isl_dim_type type, __isl_keep isl_id *id) 888 { 889 int i; 890 isl_size offset; 891 isl_size n; 892 893 n = isl_space_dim(space, type); 894 offset = isl_space_offset(space, type); 895 if (n < 0 || offset < 0 || !id) 896 return -1; 897 898 for (i = 0; i < n && offset + i < space->n_id; ++i) 899 if (space->ids[offset + i] == id) 900 return i; 901 902 return -1; 903 } 904 905 int isl_space_find_dim_by_name(__isl_keep isl_space *space, 906 enum isl_dim_type type, const char *name) 907 { 908 int i; 909 isl_size offset; 910 isl_size n; 911 912 n = isl_space_dim(space, type); 913 offset = isl_space_offset(space, type); 914 if (n < 0 || offset < 0 || !name) 915 return -1; 916 917 for (i = 0; i < n && offset + i < space->n_id; ++i) { 918 isl_id *id = get_id(space, type, i); 919 if (id && id->name && !strcmp(id->name, name)) 920 return i; 921 } 922 923 return -1; 924 } 925 926 /* Reset the user pointer on all identifiers of parameters and tuples 927 * of "space". 928 */ 929 __isl_give isl_space *isl_space_reset_user(__isl_take isl_space *space) 930 { 931 int i; 932 isl_ctx *ctx; 933 isl_id *id; 934 const char *name; 935 936 if (!space) 937 return NULL; 938 939 ctx = isl_space_get_ctx(space); 940 941 for (i = 0; i < space->nparam && i < space->n_id; ++i) { 942 if (!isl_id_get_user(space->ids[i])) 943 continue; 944 space = isl_space_cow(space); 945 if (!space) 946 return NULL; 947 name = isl_id_get_name(space->ids[i]); 948 id = isl_id_alloc(ctx, name, NULL); 949 isl_id_free(space->ids[i]); 950 space->ids[i] = id; 951 if (!id) 952 return isl_space_free(space); 953 } 954 955 for (i = 0; i < 2; ++i) { 956 if (!space->tuple_id[i]) 957 continue; 958 if (!isl_id_get_user(space->tuple_id[i])) 959 continue; 960 space = isl_space_cow(space); 961 if (!space) 962 return NULL; 963 name = isl_id_get_name(space->tuple_id[i]); 964 id = isl_id_alloc(ctx, name, NULL); 965 isl_id_free(space->tuple_id[i]); 966 space->tuple_id[i] = id; 967 if (!id) 968 return isl_space_free(space); 969 } 970 971 for (i = 0; i < 2; ++i) { 972 isl_space *nested; 973 974 if (!space->nested[i]) 975 continue; 976 nested = isl_space_take_nested(space, i); 977 nested = isl_space_reset_user(nested); 978 space = isl_space_restore_nested(space, i, nested); 979 if (!space) 980 return NULL; 981 } 982 983 return space; 984 } 985 986 static __isl_keep isl_id *tuple_id(__isl_keep isl_space *space, 987 enum isl_dim_type type) 988 { 989 if (!space) 990 return NULL; 991 if (type == isl_dim_in) 992 return space->tuple_id[0]; 993 if (type == isl_dim_out) 994 return space->tuple_id[1]; 995 return NULL; 996 } 997 998 static __isl_keep isl_space *nested(__isl_keep isl_space *space, 999 enum isl_dim_type type) 1000 { 1001 if (!space) 1002 return NULL; 1003 if (type == isl_dim_in) 1004 return space->nested[0]; 1005 if (type == isl_dim_out) 1006 return space->nested[1]; 1007 return NULL; 1008 } 1009 1010 /* Are the two spaces the same, apart from positions and names of parameters? 1011 */ 1012 isl_bool isl_space_has_equal_tuples(__isl_keep isl_space *space1, 1013 __isl_keep isl_space *space2) 1014 { 1015 if (!space1 || !space2) 1016 return isl_bool_error; 1017 if (space1 == space2) 1018 return isl_bool_true; 1019 return isl_space_tuple_is_equal(space1, isl_dim_in, 1020 space2, isl_dim_in) && 1021 isl_space_tuple_is_equal(space1, isl_dim_out, 1022 space2, isl_dim_out); 1023 } 1024 1025 /* Check that a match involving "space" was successful. 1026 * That is, check that "match" is equal to isl_bool_true. 1027 */ 1028 static isl_stat check_match(__isl_keep isl_space *space, isl_bool match) 1029 { 1030 if (match < 0) 1031 return isl_stat_error; 1032 if (!match) 1033 isl_die(isl_space_get_ctx(space), isl_error_invalid, 1034 "incompatible spaces", return isl_stat_error); 1035 1036 return isl_stat_ok; 1037 } 1038 1039 /* Check that the two spaces are the same, 1040 * apart from positions and names of parameters. 1041 */ 1042 isl_stat isl_space_check_equal_tuples(__isl_keep isl_space *space1, 1043 __isl_keep isl_space *space2) 1044 { 1045 isl_bool is_equal; 1046 1047 is_equal = isl_space_has_equal_tuples(space1, space2); 1048 return check_match(space1, is_equal); 1049 } 1050 1051 /* Check if the tuple of type "type1" of "space1" is the same as 1052 * the tuple of type "type2" of "space2". 1053 * 1054 * That is, check if the tuples have the same identifier, the same dimension 1055 * and the same internal structure. 1056 * The identifiers of the dimensions inside the tuples do not affect the result. 1057 * 1058 * Note that this function only checks the tuples themselves. 1059 * If nested tuples are involved, then we need to be careful not 1060 * to have result affected by possibly differing parameters 1061 * in those nested tuples. 1062 */ 1063 isl_bool isl_space_tuple_is_equal(__isl_keep isl_space *space1, 1064 enum isl_dim_type type1, __isl_keep isl_space *space2, 1065 enum isl_dim_type type2) 1066 { 1067 isl_id *id1, *id2; 1068 isl_space *nested1, *nested2; 1069 1070 if (!space1 || !space2) 1071 return isl_bool_error; 1072 1073 if (space1 == space2 && type1 == type2) 1074 return isl_bool_true; 1075 1076 if (n(space1, type1) != n(space2, type2)) 1077 return isl_bool_false; 1078 id1 = tuple_id(space1, type1); 1079 id2 = tuple_id(space2, type2); 1080 if (!id1 ^ !id2) 1081 return isl_bool_false; 1082 if (id1 && id1 != id2) 1083 return isl_bool_false; 1084 nested1 = nested(space1, type1); 1085 nested2 = nested(space2, type2); 1086 if (!nested1 ^ !nested2) 1087 return isl_bool_false; 1088 if (nested1 && !isl_space_has_equal_tuples(nested1, nested2)) 1089 return isl_bool_false; 1090 return isl_bool_true; 1091 } 1092 1093 /* Is the tuple "inner" within the wrapped relation inside tuple "outer" 1094 * of "space1" equal to tuple "type2" of "space2"? 1095 */ 1096 isl_bool isl_space_wrapped_tuple_is_equal(__isl_keep isl_space *space1, 1097 enum isl_dim_type outer, enum isl_dim_type inner, 1098 __isl_keep isl_space *space2, enum isl_dim_type type2) 1099 { 1100 int pos; 1101 isl_space *nested; 1102 1103 if (!space1) 1104 return isl_bool_error; 1105 if (outer != isl_dim_in && outer != isl_dim_out) 1106 isl_die(isl_space_get_ctx(space1), isl_error_invalid, 1107 "only input, output and set tuples " 1108 "can have nested relations", return isl_bool_error); 1109 pos = outer - isl_dim_in; 1110 nested = isl_space_peek_nested(space1, pos); 1111 return isl_space_tuple_is_equal(nested, inner, space2, type2); 1112 } 1113 1114 /* Check that the tuple "inner" within the wrapped relation inside tuple "outer" 1115 * of "space1" is equal to tuple "type2" of "space2". 1116 */ 1117 isl_stat isl_space_check_wrapped_tuple_is_equal(__isl_keep isl_space *space1, 1118 enum isl_dim_type outer, enum isl_dim_type inner, 1119 __isl_keep isl_space *space2, enum isl_dim_type type2) 1120 { 1121 isl_bool is_equal; 1122 1123 is_equal = isl_space_wrapped_tuple_is_equal(space1, outer, inner, 1124 space2, type2); 1125 return check_match(space1, is_equal); 1126 } 1127 1128 static isl_bool match(__isl_keep isl_space *space1, enum isl_dim_type type1, 1129 __isl_keep isl_space *space2, enum isl_dim_type type2) 1130 { 1131 int i; 1132 isl_bool equal; 1133 1134 if (!space1 || !space2) 1135 return isl_bool_error; 1136 1137 if (space1 == space2 && type1 == type2) 1138 return isl_bool_true; 1139 1140 equal = isl_space_tuple_is_equal(space1, type1, space2, type2); 1141 if (equal < 0 || !equal) 1142 return equal; 1143 1144 if (!space1->ids && !space2->ids) 1145 return isl_bool_true; 1146 1147 for (i = 0; i < n(space1, type1); ++i) { 1148 if (get_id(space1, type1, i) != get_id(space2, type2, i)) 1149 return isl_bool_false; 1150 } 1151 return isl_bool_true; 1152 } 1153 1154 /* Do "space1" and "space2" have the same parameters? 1155 */ 1156 isl_bool isl_space_has_equal_params(__isl_keep isl_space *space1, 1157 __isl_keep isl_space *space2) 1158 { 1159 return match(space1, isl_dim_param, space2, isl_dim_param); 1160 } 1161 1162 /* Do "space1" and "space2" have the same identifiers for all 1163 * the tuple variables? 1164 */ 1165 isl_bool isl_space_has_equal_ids(__isl_keep isl_space *space1, 1166 __isl_keep isl_space *space2) 1167 { 1168 isl_bool equal; 1169 1170 equal = match(space1, isl_dim_in, space2, isl_dim_in); 1171 if (equal < 0 || !equal) 1172 return equal; 1173 return match(space1, isl_dim_out, space2, isl_dim_out); 1174 } 1175 1176 isl_bool isl_space_match(__isl_keep isl_space *space1, enum isl_dim_type type1, 1177 __isl_keep isl_space *space2, enum isl_dim_type type2) 1178 { 1179 return match(space1, type1, space2, type2); 1180 } 1181 1182 static void get_ids(__isl_keep isl_space *space, enum isl_dim_type type, 1183 unsigned first, unsigned n, __isl_keep isl_id **ids) 1184 { 1185 int i; 1186 1187 for (i = 0; i < n ; ++i) 1188 ids[i] = get_id(space, type, first + i); 1189 } 1190 1191 static __isl_give isl_space *space_extend(__isl_take isl_space *space, 1192 unsigned nparam, unsigned n_in, unsigned n_out) 1193 { 1194 isl_id **ids = NULL; 1195 1196 if (!space) 1197 return NULL; 1198 if (space->nparam == nparam && 1199 space->n_in == n_in && space->n_out == n_out) 1200 return space; 1201 1202 isl_assert(space->ctx, space->nparam <= nparam, goto error); 1203 isl_assert(space->ctx, space->n_in <= n_in, goto error); 1204 isl_assert(space->ctx, space->n_out <= n_out, goto error); 1205 1206 space = isl_space_cow(space); 1207 if (!space) 1208 goto error; 1209 1210 if (space->ids) { 1211 unsigned n; 1212 n = nparam + n_in + n_out; 1213 if (n < nparam || n < n_in || n < n_out) 1214 isl_die(isl_space_get_ctx(space), isl_error_invalid, 1215 "overflow in total number of dimensions", 1216 goto error); 1217 ids = isl_calloc_array(space->ctx, isl_id *, n); 1218 if (!ids) 1219 goto error; 1220 get_ids(space, isl_dim_param, 0, space->nparam, ids); 1221 get_ids(space, isl_dim_in, 0, space->n_in, ids + nparam); 1222 get_ids(space, isl_dim_out, 0, space->n_out, 1223 ids + nparam + n_in); 1224 free(space->ids); 1225 space->ids = ids; 1226 space->n_id = nparam + n_in + n_out; 1227 } 1228 space->nparam = nparam; 1229 space->n_in = n_in; 1230 space->n_out = n_out; 1231 1232 return space; 1233 error: 1234 free(ids); 1235 isl_space_free(space); 1236 return NULL; 1237 } 1238 1239 __isl_give isl_space *isl_space_extend(__isl_take isl_space *space, 1240 unsigned nparam, unsigned n_in, unsigned n_out) 1241 { 1242 return space_extend(space, nparam, n_in, n_out); 1243 } 1244 1245 __isl_give isl_space *isl_space_add_dims(__isl_take isl_space *space, 1246 enum isl_dim_type type, unsigned n) 1247 { 1248 space = isl_space_reset(space, type); 1249 if (!space) 1250 return NULL; 1251 switch (type) { 1252 case isl_dim_param: 1253 space = space_extend(space, 1254 space->nparam + n, space->n_in, space->n_out); 1255 if (space && space->nested[0] && 1256 !(space->nested[0] = isl_space_add_dims(space->nested[0], 1257 isl_dim_param, n))) 1258 goto error; 1259 if (space && space->nested[1] && 1260 !(space->nested[1] = isl_space_add_dims(space->nested[1], 1261 isl_dim_param, n))) 1262 goto error; 1263 return space; 1264 case isl_dim_in: 1265 return space_extend(space, 1266 space->nparam, space->n_in + n, space->n_out); 1267 case isl_dim_out: 1268 return space_extend(space, 1269 space->nparam, space->n_in, space->n_out + n); 1270 default: 1271 isl_die(space->ctx, isl_error_invalid, 1272 "cannot add dimensions of specified type", goto error); 1273 } 1274 error: 1275 isl_space_free(space); 1276 return NULL; 1277 } 1278 1279 /* Add a parameter with identifier "id" to "space", provided 1280 * it does not already appear in "space". 1281 */ 1282 __isl_give isl_space *isl_space_add_param_id(__isl_take isl_space *space, 1283 __isl_take isl_id *id) 1284 { 1285 isl_size pos; 1286 1287 if (!space || !id) 1288 goto error; 1289 1290 if (isl_space_find_dim_by_id(space, isl_dim_param, id) >= 0) { 1291 isl_id_free(id); 1292 return space; 1293 } 1294 1295 pos = isl_space_dim(space, isl_dim_param); 1296 if (pos < 0) 1297 goto error; 1298 space = isl_space_add_dims(space, isl_dim_param, 1); 1299 space = isl_space_set_dim_id(space, isl_dim_param, pos, id); 1300 1301 return space; 1302 error: 1303 isl_space_free(space); 1304 isl_id_free(id); 1305 return NULL; 1306 } 1307 1308 static int valid_dim_type(enum isl_dim_type type) 1309 { 1310 switch (type) { 1311 case isl_dim_param: 1312 case isl_dim_in: 1313 case isl_dim_out: 1314 return 1; 1315 default: 1316 return 0; 1317 } 1318 } 1319 1320 #undef TYPE 1321 #define TYPE isl_space 1322 #include "check_type_range_templ.c" 1323 1324 /* Insert "n" dimensions of type "type" at position "pos". 1325 * If we are inserting parameters, then they are also inserted in 1326 * any nested spaces. 1327 */ 1328 __isl_give isl_space *isl_space_insert_dims(__isl_take isl_space *space, 1329 enum isl_dim_type type, unsigned pos, unsigned n) 1330 { 1331 isl_ctx *ctx; 1332 isl_id **ids = NULL; 1333 1334 if (!space) 1335 return NULL; 1336 if (n == 0) 1337 return isl_space_reset(space, type); 1338 1339 ctx = isl_space_get_ctx(space); 1340 if (!valid_dim_type(type)) 1341 isl_die(ctx, isl_error_invalid, 1342 "cannot insert dimensions of specified type", 1343 goto error); 1344 1345 if (isl_space_check_range(space, type, pos, 0) < 0) 1346 return isl_space_free(space); 1347 1348 space = isl_space_cow(space); 1349 if (!space) 1350 return NULL; 1351 1352 if (space->ids) { 1353 enum isl_dim_type t, o = isl_dim_param; 1354 int off; 1355 int s[3]; 1356 ids = isl_calloc_array(ctx, isl_id *, 1357 space->nparam + space->n_in + space->n_out + n); 1358 if (!ids) 1359 goto error; 1360 off = 0; 1361 s[isl_dim_param - o] = space->nparam; 1362 s[isl_dim_in - o] = space->n_in; 1363 s[isl_dim_out - o] = space->n_out; 1364 for (t = isl_dim_param; t <= isl_dim_out; ++t) { 1365 if (t != type) { 1366 get_ids(space, t, 0, s[t - o], ids + off); 1367 off += s[t - o]; 1368 } else { 1369 get_ids(space, t, 0, pos, ids + off); 1370 off += pos + n; 1371 get_ids(space, t, pos, s[t - o] - pos, 1372 ids + off); 1373 off += s[t - o] - pos; 1374 } 1375 } 1376 free(space->ids); 1377 space->ids = ids; 1378 space->n_id = space->nparam + space->n_in + space->n_out + n; 1379 } 1380 switch (type) { 1381 case isl_dim_param: space->nparam += n; break; 1382 case isl_dim_in: space->n_in += n; break; 1383 case isl_dim_out: space->n_out += n; break; 1384 default: ; 1385 } 1386 space = isl_space_reset(space, type); 1387 1388 if (type == isl_dim_param) { 1389 if (space && space->nested[0] && 1390 !(space->nested[0] = isl_space_insert_dims(space->nested[0], 1391 isl_dim_param, pos, n))) 1392 goto error; 1393 if (space && space->nested[1] && 1394 !(space->nested[1] = isl_space_insert_dims(space->nested[1], 1395 isl_dim_param, pos, n))) 1396 goto error; 1397 } 1398 1399 return space; 1400 error: 1401 isl_space_free(space); 1402 return NULL; 1403 } 1404 1405 __isl_give isl_space *isl_space_move_dims(__isl_take isl_space *space, 1406 enum isl_dim_type dst_type, unsigned dst_pos, 1407 enum isl_dim_type src_type, unsigned src_pos, unsigned n) 1408 { 1409 int i; 1410 1411 space = isl_space_reset(space, src_type); 1412 space = isl_space_reset(space, dst_type); 1413 if (!space) 1414 return NULL; 1415 if (n == 0) 1416 return space; 1417 1418 if (isl_space_check_range(space, src_type, src_pos, n) < 0) 1419 return isl_space_free(space); 1420 1421 if (dst_type == src_type && dst_pos == src_pos) 1422 return space; 1423 1424 isl_assert(space->ctx, dst_type != src_type, goto error); 1425 1426 space = isl_space_cow(space); 1427 if (!space) 1428 return NULL; 1429 1430 if (space->ids) { 1431 isl_id **ids; 1432 enum isl_dim_type t, o = isl_dim_param; 1433 int off; 1434 int s[3]; 1435 ids = isl_calloc_array(space->ctx, isl_id *, 1436 space->nparam + space->n_in + space->n_out); 1437 if (!ids) 1438 goto error; 1439 off = 0; 1440 s[isl_dim_param - o] = space->nparam; 1441 s[isl_dim_in - o] = space->n_in; 1442 s[isl_dim_out - o] = space->n_out; 1443 for (t = isl_dim_param; t <= isl_dim_out; ++t) { 1444 if (t == dst_type) { 1445 get_ids(space, t, 0, dst_pos, ids + off); 1446 off += dst_pos; 1447 get_ids(space, src_type, src_pos, n, ids + off); 1448 off += n; 1449 get_ids(space, t, dst_pos, s[t - o] - dst_pos, 1450 ids + off); 1451 off += s[t - o] - dst_pos; 1452 } else if (t == src_type) { 1453 get_ids(space, t, 0, src_pos, ids + off); 1454 off += src_pos; 1455 get_ids(space, t, src_pos + n, 1456 s[t - o] - src_pos - n, ids + off); 1457 off += s[t - o] - src_pos - n; 1458 } else { 1459 get_ids(space, t, 0, s[t - o], ids + off); 1460 off += s[t - o]; 1461 } 1462 } 1463 free(space->ids); 1464 space->ids = ids; 1465 space->n_id = space->nparam + space->n_in + space->n_out; 1466 } 1467 1468 switch (dst_type) { 1469 case isl_dim_param: space->nparam += n; break; 1470 case isl_dim_in: space->n_in += n; break; 1471 case isl_dim_out: space->n_out += n; break; 1472 default: ; 1473 } 1474 1475 switch (src_type) { 1476 case isl_dim_param: space->nparam -= n; break; 1477 case isl_dim_in: space->n_in -= n; break; 1478 case isl_dim_out: space->n_out -= n; break; 1479 default: ; 1480 } 1481 1482 if (dst_type != isl_dim_param && src_type != isl_dim_param) 1483 return space; 1484 1485 for (i = 0; i < 2; ++i) { 1486 isl_space *nested; 1487 1488 if (!space->nested[i]) 1489 continue; 1490 nested = isl_space_take_nested(space, i); 1491 nested = isl_space_replace_params(nested, space); 1492 space = isl_space_restore_nested(space, i, nested); 1493 if (!space) 1494 return NULL; 1495 } 1496 1497 return space; 1498 error: 1499 isl_space_free(space); 1500 return NULL; 1501 } 1502 1503 /* Check that "space1" and "space2" have the same parameters, 1504 * reporting an error if they do not. 1505 */ 1506 isl_stat isl_space_check_equal_params(__isl_keep isl_space *space1, 1507 __isl_keep isl_space *space2) 1508 { 1509 isl_bool equal; 1510 1511 equal = isl_space_has_equal_params(space1, space2); 1512 if (equal < 0) 1513 return isl_stat_error; 1514 if (!equal) 1515 isl_die(isl_space_get_ctx(space1), isl_error_invalid, 1516 "parameters need to match", return isl_stat_error); 1517 return isl_stat_ok; 1518 } 1519 1520 __isl_give isl_space *isl_space_join(__isl_take isl_space *left, 1521 __isl_take isl_space *right) 1522 { 1523 isl_space *space; 1524 1525 if (isl_space_check_equal_params(left, right) < 0) 1526 goto error; 1527 1528 isl_assert(left->ctx, 1529 isl_space_tuple_is_equal(left, isl_dim_out, right, isl_dim_in), 1530 goto error); 1531 1532 space = isl_space_alloc(left->ctx, 1533 left->nparam, left->n_in, right->n_out); 1534 if (!space) 1535 goto error; 1536 1537 space = copy_ids(space, isl_dim_param, 0, left, isl_dim_param); 1538 space = copy_ids(space, isl_dim_in, 0, left, isl_dim_in); 1539 space = copy_ids(space, isl_dim_out, 0, right, isl_dim_out); 1540 1541 if (space && left->tuple_id[0] && 1542 !(space->tuple_id[0] = isl_id_copy(left->tuple_id[0]))) 1543 goto error; 1544 if (space && right->tuple_id[1] && 1545 !(space->tuple_id[1] = isl_id_copy(right->tuple_id[1]))) 1546 goto error; 1547 if (space && left->nested[0] && 1548 !(space->nested[0] = isl_space_copy(left->nested[0]))) 1549 goto error; 1550 if (space && right->nested[1] && 1551 !(space->nested[1] = isl_space_copy(right->nested[1]))) 1552 goto error; 1553 1554 isl_space_free(left); 1555 isl_space_free(right); 1556 1557 return space; 1558 error: 1559 isl_space_free(left); 1560 isl_space_free(right); 1561 return NULL; 1562 } 1563 1564 /* Given two map spaces { A -> C } and { B -> D }, construct the space 1565 * { [A -> B] -> [C -> D] }. 1566 * Given two set spaces { A } and { B }, construct the space { [A -> B] }. 1567 */ 1568 __isl_give isl_space *isl_space_product(__isl_take isl_space *left, 1569 __isl_take isl_space *right) 1570 { 1571 isl_space *dom1, *dom2, *nest1, *nest2; 1572 int is_set; 1573 1574 if (!left || !right) 1575 goto error; 1576 1577 is_set = isl_space_is_set(left); 1578 if (is_set != isl_space_is_set(right)) 1579 isl_die(isl_space_get_ctx(left), isl_error_invalid, 1580 "expecting either two set spaces or two map spaces", 1581 goto error); 1582 if (is_set) 1583 return isl_space_range_product(left, right); 1584 1585 if (isl_space_check_equal_params(left, right) < 0) 1586 goto error; 1587 1588 dom1 = isl_space_domain(isl_space_copy(left)); 1589 dom2 = isl_space_domain(isl_space_copy(right)); 1590 nest1 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2)); 1591 1592 dom1 = isl_space_range(left); 1593 dom2 = isl_space_range(right); 1594 nest2 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2)); 1595 1596 return isl_space_join(isl_space_reverse(nest1), nest2); 1597 error: 1598 isl_space_free(left); 1599 isl_space_free(right); 1600 return NULL; 1601 } 1602 1603 /* Given two spaces { A -> C } and { B -> C }, construct the space 1604 * { [A -> B] -> C } 1605 */ 1606 __isl_give isl_space *isl_space_domain_product(__isl_take isl_space *left, 1607 __isl_take isl_space *right) 1608 { 1609 isl_space *ran, *dom1, *dom2, *nest; 1610 1611 if (isl_space_check_equal_params(left, right) < 0) 1612 goto error; 1613 1614 if (!isl_space_tuple_is_equal(left, isl_dim_out, right, isl_dim_out)) 1615 isl_die(left->ctx, isl_error_invalid, 1616 "ranges need to match", goto error); 1617 1618 ran = isl_space_range(isl_space_copy(left)); 1619 1620 dom1 = isl_space_domain(left); 1621 dom2 = isl_space_domain(right); 1622 nest = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2)); 1623 1624 return isl_space_join(isl_space_reverse(nest), ran); 1625 error: 1626 isl_space_free(left); 1627 isl_space_free(right); 1628 return NULL; 1629 } 1630 1631 __isl_give isl_space *isl_space_range_product(__isl_take isl_space *left, 1632 __isl_take isl_space *right) 1633 { 1634 isl_space *dom, *ran1, *ran2, *nest; 1635 1636 if (isl_space_check_equal_params(left, right) < 0) 1637 goto error; 1638 1639 if (!isl_space_tuple_is_equal(left, isl_dim_in, right, isl_dim_in)) 1640 isl_die(left->ctx, isl_error_invalid, 1641 "domains need to match", goto error); 1642 1643 dom = isl_space_domain(isl_space_copy(left)); 1644 1645 ran1 = isl_space_range(left); 1646 ran2 = isl_space_range(right); 1647 nest = isl_space_wrap(isl_space_join(isl_space_reverse(ran1), ran2)); 1648 1649 return isl_space_join(isl_space_reverse(dom), nest); 1650 error: 1651 isl_space_free(left); 1652 isl_space_free(right); 1653 return NULL; 1654 } 1655 1656 /* Given a space of the form [A -> B] -> C, return the space A -> C. 1657 */ 1658 __isl_give isl_space *isl_space_domain_factor_domain( 1659 __isl_take isl_space *space) 1660 { 1661 isl_space *nested; 1662 isl_space *domain; 1663 1664 if (isl_space_check_domain_is_wrapping(space) < 0) 1665 return isl_space_free(space); 1666 1667 nested = space->nested[0]; 1668 domain = isl_space_copy(space); 1669 domain = isl_space_drop_dims(domain, isl_dim_in, 1670 nested->n_in, nested->n_out); 1671 if (!domain) 1672 return isl_space_free(space); 1673 if (nested->tuple_id[0]) { 1674 domain->tuple_id[0] = isl_id_copy(nested->tuple_id[0]); 1675 if (!domain->tuple_id[0]) 1676 goto error; 1677 } 1678 if (nested->nested[0]) { 1679 domain->nested[0] = isl_space_copy(nested->nested[0]); 1680 if (!domain->nested[0]) 1681 goto error; 1682 } 1683 1684 isl_space_free(space); 1685 return domain; 1686 error: 1687 isl_space_free(space); 1688 isl_space_free(domain); 1689 return NULL; 1690 } 1691 1692 /* Given a space of the form [A -> B] -> C, return the space B -> C. 1693 */ 1694 __isl_give isl_space *isl_space_domain_factor_range( 1695 __isl_take isl_space *space) 1696 { 1697 isl_space *nested; 1698 isl_space *range; 1699 1700 if (isl_space_check_domain_is_wrapping(space) < 0) 1701 return isl_space_free(space); 1702 1703 nested = space->nested[0]; 1704 range = isl_space_copy(space); 1705 range = isl_space_drop_dims(range, isl_dim_in, 0, nested->n_in); 1706 if (!range) 1707 return isl_space_free(space); 1708 if (nested->tuple_id[1]) { 1709 range->tuple_id[0] = isl_id_copy(nested->tuple_id[1]); 1710 if (!range->tuple_id[0]) 1711 goto error; 1712 } 1713 if (nested->nested[1]) { 1714 range->nested[0] = isl_space_copy(nested->nested[1]); 1715 if (!range->nested[0]) 1716 goto error; 1717 } 1718 1719 isl_space_free(space); 1720 return range; 1721 error: 1722 isl_space_free(space); 1723 isl_space_free(range); 1724 return NULL; 1725 } 1726 1727 /* Internal function that selects the domain of the map that is 1728 * embedded in either a set space or the range of a map space. 1729 * In particular, given a space of the form [A -> B], return the space A. 1730 * Given a space of the form A -> [B -> C], return the space A -> B. 1731 */ 1732 static __isl_give isl_space *range_factor_domain(__isl_take isl_space *space) 1733 { 1734 isl_space *nested; 1735 isl_space *domain; 1736 1737 if (!space) 1738 return NULL; 1739 1740 nested = space->nested[1]; 1741 domain = isl_space_copy(space); 1742 domain = isl_space_drop_dims(domain, isl_dim_out, 1743 nested->n_in, nested->n_out); 1744 if (!domain) 1745 return isl_space_free(space); 1746 if (nested->tuple_id[0]) { 1747 domain->tuple_id[1] = isl_id_copy(nested->tuple_id[0]); 1748 if (!domain->tuple_id[1]) 1749 goto error; 1750 } 1751 if (nested->nested[0]) { 1752 domain->nested[1] = isl_space_copy(nested->nested[0]); 1753 if (!domain->nested[1]) 1754 goto error; 1755 } 1756 1757 isl_space_free(space); 1758 return domain; 1759 error: 1760 isl_space_free(space); 1761 isl_space_free(domain); 1762 return NULL; 1763 } 1764 1765 /* Given a space of the form A -> [B -> C], return the space A -> B. 1766 */ 1767 __isl_give isl_space *isl_space_range_factor_domain( 1768 __isl_take isl_space *space) 1769 { 1770 if (isl_space_check_range_is_wrapping(space) < 0) 1771 return isl_space_free(space); 1772 1773 return range_factor_domain(space); 1774 } 1775 1776 /* Given a space of the form [A -> B], return the space A. 1777 */ 1778 static __isl_give isl_space *set_factor_domain(__isl_take isl_space *space) 1779 { 1780 if (!space) 1781 return NULL; 1782 if (!isl_space_is_wrapping(space)) 1783 isl_die(isl_space_get_ctx(space), isl_error_invalid, 1784 "not a product", return isl_space_free(space)); 1785 1786 return range_factor_domain(space); 1787 } 1788 1789 /* Given a space of the form [A -> B] -> [C -> D], return the space A -> C. 1790 * Given a space of the form [A -> B], return the space A. 1791 */ 1792 __isl_give isl_space *isl_space_factor_domain(__isl_take isl_space *space) 1793 { 1794 if (!space) 1795 return NULL; 1796 if (isl_space_is_set(space)) 1797 return set_factor_domain(space); 1798 space = isl_space_domain_factor_domain(space); 1799 space = isl_space_range_factor_domain(space); 1800 return space; 1801 } 1802 1803 /* Internal function that selects the range of the map that is 1804 * embedded in either a set space or the range of a map space. 1805 * In particular, given a space of the form [A -> B], return the space B. 1806 * Given a space of the form A -> [B -> C], return the space A -> C. 1807 */ 1808 static __isl_give isl_space *range_factor_range(__isl_take isl_space *space) 1809 { 1810 isl_space *nested; 1811 isl_space *range; 1812 1813 if (!space) 1814 return NULL; 1815 1816 nested = space->nested[1]; 1817 range = isl_space_copy(space); 1818 range = isl_space_drop_dims(range, isl_dim_out, 0, nested->n_in); 1819 if (!range) 1820 return isl_space_free(space); 1821 if (nested->tuple_id[1]) { 1822 range->tuple_id[1] = isl_id_copy(nested->tuple_id[1]); 1823 if (!range->tuple_id[1]) 1824 goto error; 1825 } 1826 if (nested->nested[1]) { 1827 range->nested[1] = isl_space_copy(nested->nested[1]); 1828 if (!range->nested[1]) 1829 goto error; 1830 } 1831 1832 isl_space_free(space); 1833 return range; 1834 error: 1835 isl_space_free(space); 1836 isl_space_free(range); 1837 return NULL; 1838 } 1839 1840 /* Given a space of the form A -> [B -> C], return the space A -> C. 1841 */ 1842 __isl_give isl_space *isl_space_range_factor_range( 1843 __isl_take isl_space *space) 1844 { 1845 if (isl_space_check_range_is_wrapping(space) < 0) 1846 return isl_space_free(space); 1847 1848 return range_factor_range(space); 1849 } 1850 1851 /* Given a space of the form [A -> B], return the space B. 1852 */ 1853 static __isl_give isl_space *set_factor_range(__isl_take isl_space *space) 1854 { 1855 if (!space) 1856 return NULL; 1857 if (!isl_space_is_wrapping(space)) 1858 isl_die(isl_space_get_ctx(space), isl_error_invalid, 1859 "not a product", return isl_space_free(space)); 1860 1861 return range_factor_range(space); 1862 } 1863 1864 /* Given a space of the form [A -> B] -> [C -> D], return the space B -> D. 1865 * Given a space of the form [A -> B], return the space B. 1866 */ 1867 __isl_give isl_space *isl_space_factor_range(__isl_take isl_space *space) 1868 { 1869 if (!space) 1870 return NULL; 1871 if (isl_space_is_set(space)) 1872 return set_factor_range(space); 1873 space = isl_space_domain_factor_range(space); 1874 space = isl_space_range_factor_range(space); 1875 return space; 1876 } 1877 1878 /* Given a space of the form [A -> B] -> C, return the space A. 1879 */ 1880 __isl_give isl_space *isl_space_domain_wrapped_domain( 1881 __isl_take isl_space *space) 1882 { 1883 return isl_space_factor_domain(isl_space_domain(space)); 1884 } 1885 1886 /* Given a space of the form [A -> B] -> C, return the space B. 1887 */ 1888 __isl_give isl_space *isl_space_domain_wrapped_range( 1889 __isl_take isl_space *space) 1890 { 1891 return isl_space_factor_range(isl_space_domain(space)); 1892 } 1893 1894 /* Given a space of the form A -> [B -> C], return the space B. 1895 */ 1896 __isl_give isl_space *isl_space_range_wrapped_domain( 1897 __isl_take isl_space *space) 1898 { 1899 return isl_space_factor_domain(isl_space_range(space)); 1900 } 1901 1902 /* Given a space of the form A -> [B -> C], return the space C. 1903 */ 1904 __isl_give isl_space *isl_space_range_wrapped_range( 1905 __isl_take isl_space *space) 1906 { 1907 return isl_space_factor_range(isl_space_range(space)); 1908 } 1909 1910 __isl_give isl_space *isl_space_map_from_set(__isl_take isl_space *space) 1911 { 1912 isl_ctx *ctx; 1913 isl_id **ids = NULL; 1914 int n_id; 1915 1916 if (!space) 1917 return NULL; 1918 ctx = isl_space_get_ctx(space); 1919 if (!isl_space_is_set(space)) 1920 isl_die(ctx, isl_error_invalid, "not a set space", goto error); 1921 space = isl_space_cow(space); 1922 if (!space) 1923 return NULL; 1924 n_id = space->nparam + space->n_out + space->n_out; 1925 if (n_id > 0 && space->ids) { 1926 ids = isl_calloc_array(space->ctx, isl_id *, n_id); 1927 if (!ids) 1928 goto error; 1929 get_ids(space, isl_dim_param, 0, space->nparam, ids); 1930 get_ids(space, isl_dim_out, 0, space->n_out, 1931 ids + space->nparam); 1932 } 1933 space->n_in = space->n_out; 1934 if (ids) { 1935 free(space->ids); 1936 space->ids = ids; 1937 space->n_id = n_id; 1938 space = copy_ids(space, isl_dim_out, 0, space, isl_dim_in); 1939 } 1940 isl_id_free(space->tuple_id[0]); 1941 space->tuple_id[0] = isl_id_copy(space->tuple_id[1]); 1942 isl_space_free(space->nested[0]); 1943 space->nested[0] = isl_space_copy(space->nested[1]); 1944 return space; 1945 error: 1946 isl_space_free(space); 1947 return NULL; 1948 } 1949 1950 __isl_give isl_space *isl_space_map_from_domain_and_range( 1951 __isl_take isl_space *domain, __isl_take isl_space *range) 1952 { 1953 if (!domain || !range) 1954 goto error; 1955 if (!isl_space_is_set(domain)) 1956 isl_die(isl_space_get_ctx(domain), isl_error_invalid, 1957 "domain is not a set space", goto error); 1958 if (!isl_space_is_set(range)) 1959 isl_die(isl_space_get_ctx(range), isl_error_invalid, 1960 "range is not a set space", goto error); 1961 return isl_space_join(isl_space_reverse(domain), range); 1962 error: 1963 isl_space_free(domain); 1964 isl_space_free(range); 1965 return NULL; 1966 } 1967 1968 static __isl_give isl_space *set_ids(__isl_take isl_space *space, 1969 enum isl_dim_type type, 1970 unsigned first, unsigned n, __isl_take isl_id **ids) 1971 { 1972 int i; 1973 1974 for (i = 0; i < n ; ++i) 1975 space = set_id(space, type, first + i, ids[i]); 1976 1977 return space; 1978 } 1979 1980 __isl_give isl_space *isl_space_reverse(__isl_take isl_space *space) 1981 { 1982 unsigned t; 1983 isl_bool equal; 1984 isl_space *nested; 1985 isl_id **ids = NULL; 1986 isl_id *id; 1987 1988 equal = match(space, isl_dim_in, space, isl_dim_out); 1989 if (equal < 0) 1990 return isl_space_free(space); 1991 if (equal) 1992 return space; 1993 1994 space = isl_space_cow(space); 1995 if (!space) 1996 return NULL; 1997 1998 id = space->tuple_id[0]; 1999 space->tuple_id[0] = space->tuple_id[1]; 2000 space->tuple_id[1] = id; 2001 2002 nested = space->nested[0]; 2003 space->nested[0] = space->nested[1]; 2004 space->nested[1] = nested; 2005 2006 if (space->ids) { 2007 int n_id = space->n_in + space->n_out; 2008 ids = isl_alloc_array(space->ctx, isl_id *, n_id); 2009 if (n_id && !ids) 2010 goto error; 2011 get_ids(space, isl_dim_in, 0, space->n_in, ids); 2012 get_ids(space, isl_dim_out, 0, space->n_out, ids + space->n_in); 2013 } 2014 2015 t = space->n_in; 2016 space->n_in = space->n_out; 2017 space->n_out = t; 2018 2019 if (space->ids) { 2020 space = set_ids(space, isl_dim_out, 0, space->n_out, ids); 2021 space = set_ids(space, isl_dim_in, 0, space->n_in, 2022 ids + space->n_out); 2023 free(ids); 2024 } 2025 2026 return space; 2027 error: 2028 free(ids); 2029 isl_space_free(space); 2030 return NULL; 2031 } 2032 2033 /* Given a space where the tuple of type "type" is a wrapped map space, 2034 * swap domain and range of that wrapped space. 2035 * 2036 * If the tuple is named, then the name is only preserved 2037 * if the nested tuples are equal, in which case the output 2038 * of this function is identical to the input, except possibly 2039 * for the dimension identifiers. 2040 * 2041 * Make a reasonable attempt at moving the dimension identifiers 2042 * along with the tuples. 2043 */ 2044 __isl_give isl_space *isl_space_reverse_wrapped(__isl_take isl_space *space, 2045 enum isl_dim_type type) 2046 { 2047 int pos = type - isl_dim_in; 2048 isl_space *nested; 2049 isl_bool equal; 2050 isl_size n_in; 2051 2052 nested = isl_space_peek_nested(space, pos); 2053 equal = isl_space_tuple_is_equal(nested, isl_dim_in, 2054 nested, isl_dim_out); 2055 if (equal < 0) 2056 return isl_space_free(space); 2057 2058 nested = isl_space_take_nested(space, pos); 2059 nested = isl_space_reverse(nested); 2060 space = isl_space_restore_nested(space, pos, nested); 2061 if (!equal) 2062 space = isl_space_reset_tuple_id(space, type); 2063 nested = isl_space_peek_nested(space, pos); 2064 n_in = isl_space_dim(nested, isl_dim_in); 2065 if (n_in < 0) 2066 return isl_space_free(space); 2067 space = copy_ids(space, type, 0, nested, isl_dim_in); 2068 space = copy_ids(space, type, n_in, nested, isl_dim_out); 2069 2070 return space; 2071 } 2072 2073 /* Given a space (A -> B), return the corresponding space 2074 * (B -> A). 2075 * 2076 * If the domain tuple is named, then the name is only preserved 2077 * if A and B are equal tuples, in which case the output 2078 * of this function is identical to the input, except possibly 2079 * for the dimension identifiers. 2080 */ 2081 __isl_give isl_space *isl_space_wrapped_reverse(__isl_take isl_space *space) 2082 { 2083 if (isl_space_check_is_wrapping(space) < 0) 2084 return isl_space_free(space); 2085 space = isl_space_reverse_wrapped(space, isl_dim_set); 2086 2087 return space; 2088 } 2089 2090 /* Given a space (A -> B) -> C, return the corresponding space 2091 * (B -> A) -> C. 2092 * 2093 * If the domain tuple is named, then the name is only preserved 2094 * if A and B are equal tuples, in which case the output 2095 * of this function is identical to the input, except possibly 2096 * for the dimension identifiers. 2097 */ 2098 __isl_give isl_space *isl_space_domain_reverse(__isl_take isl_space *space) 2099 { 2100 if (isl_space_check_domain_is_wrapping(space) < 0) 2101 return isl_space_free(space); 2102 space = isl_space_reverse_wrapped(space, isl_dim_in); 2103 2104 return space; 2105 } 2106 2107 /* Given a space A -> (B -> C), return the corresponding space 2108 * A -> (C -> B). 2109 * 2110 * If the range tuple is named, then the name is only preserved 2111 * if B and C are equal tuples, in which case the output 2112 * of this function is identical to the input, except possibly 2113 * for the dimension identifiers. 2114 */ 2115 __isl_give isl_space *isl_space_range_reverse(__isl_take isl_space *space) 2116 { 2117 if (isl_space_check_range_is_wrapping(space) < 0) 2118 return isl_space_free(space); 2119 space = isl_space_reverse_wrapped(space, isl_dim_out); 2120 2121 return space; 2122 } 2123 2124 __isl_give isl_space *isl_space_drop_dims(__isl_take isl_space *space, 2125 enum isl_dim_type type, unsigned first, unsigned num) 2126 { 2127 int i; 2128 2129 if (!space) 2130 return NULL; 2131 2132 if (num == 0) 2133 return isl_space_reset(space, type); 2134 2135 if (!valid_dim_type(type)) 2136 isl_die(space->ctx, isl_error_invalid, 2137 "cannot drop dimensions of specified type", goto error); 2138 2139 if (isl_space_check_range(space, type, first, num) < 0) 2140 return isl_space_free(space); 2141 space = isl_space_cow(space); 2142 if (!space) 2143 goto error; 2144 if (space->ids) { 2145 space = extend_ids(space); 2146 if (!space) 2147 goto error; 2148 for (i = 0; i < num; ++i) 2149 isl_id_free(get_id(space, type, first + i)); 2150 for (i = first+num; i < n(space, type); ++i) 2151 set_id(space, type, i - num, get_id(space, type, i)); 2152 switch (type) { 2153 case isl_dim_param: 2154 get_ids(space, isl_dim_in, 0, space->n_in, 2155 space->ids + offset(space, isl_dim_in) - num); 2156 case isl_dim_in: 2157 get_ids(space, isl_dim_out, 0, space->n_out, 2158 space->ids + offset(space, isl_dim_out) - num); 2159 default: 2160 ; 2161 } 2162 space->n_id -= num; 2163 } 2164 switch (type) { 2165 case isl_dim_param: space->nparam -= num; break; 2166 case isl_dim_in: space->n_in -= num; break; 2167 case isl_dim_out: space->n_out -= num; break; 2168 default: ; 2169 } 2170 space = isl_space_reset(space, type); 2171 if (type == isl_dim_param) { 2172 if (space && space->nested[0] && 2173 !(space->nested[0] = isl_space_drop_dims(space->nested[0], 2174 isl_dim_param, first, num))) 2175 goto error; 2176 if (space && space->nested[1] && 2177 !(space->nested[1] = isl_space_drop_dims(space->nested[1], 2178 isl_dim_param, first, num))) 2179 goto error; 2180 } 2181 return space; 2182 error: 2183 isl_space_free(space); 2184 return NULL; 2185 } 2186 2187 __isl_give isl_space *isl_space_drop_inputs(__isl_take isl_space *space, 2188 unsigned first, unsigned n) 2189 { 2190 if (!space) 2191 return NULL; 2192 return isl_space_drop_dims(space, isl_dim_in, first, n); 2193 } 2194 2195 __isl_give isl_space *isl_space_drop_outputs(__isl_take isl_space *space, 2196 unsigned first, unsigned n) 2197 { 2198 if (!space) 2199 return NULL; 2200 return isl_space_drop_dims(space, isl_dim_out, first, n); 2201 } 2202 2203 /* Remove all parameters from "space". 2204 */ 2205 __isl_give isl_space *isl_space_drop_all_params(__isl_take isl_space *space) 2206 { 2207 isl_size nparam; 2208 2209 nparam = isl_space_dim(space, isl_dim_param); 2210 if (nparam < 0) 2211 return isl_space_free(space); 2212 return isl_space_drop_dims(space, isl_dim_param, 0, nparam); 2213 } 2214 2215 __isl_give isl_space *isl_space_domain(__isl_take isl_space *space) 2216 { 2217 if (!space) 2218 return NULL; 2219 space = isl_space_drop_dims(space, isl_dim_out, 0, space->n_out); 2220 space = isl_space_reverse(space); 2221 space = mark_as_set(space); 2222 return space; 2223 } 2224 2225 __isl_give isl_space *isl_space_from_domain(__isl_take isl_space *space) 2226 { 2227 if (!space) 2228 return NULL; 2229 if (!isl_space_is_set(space)) 2230 isl_die(isl_space_get_ctx(space), isl_error_invalid, 2231 "not a set space", goto error); 2232 space = isl_space_reverse(space); 2233 space = isl_space_reset(space, isl_dim_out); 2234 return space; 2235 error: 2236 isl_space_free(space); 2237 return NULL; 2238 } 2239 2240 __isl_give isl_space *isl_space_range(__isl_take isl_space *space) 2241 { 2242 if (!space) 2243 return NULL; 2244 space = isl_space_drop_dims(space, isl_dim_in, 0, space->n_in); 2245 space = mark_as_set(space); 2246 return space; 2247 } 2248 2249 __isl_give isl_space *isl_space_from_range(__isl_take isl_space *space) 2250 { 2251 if (!space) 2252 return NULL; 2253 if (!isl_space_is_set(space)) 2254 isl_die(isl_space_get_ctx(space), isl_error_invalid, 2255 "not a set space", goto error); 2256 return isl_space_reset(space, isl_dim_in); 2257 error: 2258 isl_space_free(space); 2259 return NULL; 2260 } 2261 2262 /* Given a map space A -> B, return the map space [A -> B] -> A. 2263 */ 2264 __isl_give isl_space *isl_space_domain_map(__isl_take isl_space *space) 2265 { 2266 isl_space *domain; 2267 2268 domain = isl_space_from_range(isl_space_domain(isl_space_copy(space))); 2269 space = isl_space_from_domain(isl_space_wrap(space)); 2270 space = isl_space_join(space, domain); 2271 2272 return space; 2273 } 2274 2275 /* Given a map space A -> B, return the map space [A -> B] -> B. 2276 */ 2277 __isl_give isl_space *isl_space_range_map(__isl_take isl_space *space) 2278 { 2279 isl_space *range; 2280 2281 range = isl_space_from_range(isl_space_range(isl_space_copy(space))); 2282 space = isl_space_from_domain(isl_space_wrap(space)); 2283 space = isl_space_join(space, range); 2284 2285 return space; 2286 } 2287 2288 __isl_give isl_space *isl_space_params(__isl_take isl_space *space) 2289 { 2290 isl_size n_in, n_out; 2291 2292 if (isl_space_is_params(space)) 2293 return space; 2294 n_in = isl_space_dim(space, isl_dim_in); 2295 n_out = isl_space_dim(space, isl_dim_out); 2296 if (n_in < 0 || n_out < 0) 2297 return isl_space_free(space); 2298 space = isl_space_drop_dims(space, isl_dim_in, 0, n_in); 2299 space = isl_space_drop_dims(space, isl_dim_out, 0, n_out); 2300 space = mark_as_params(space); 2301 return space; 2302 } 2303 2304 __isl_give isl_space *isl_space_set_from_params(__isl_take isl_space *space) 2305 { 2306 if (!space) 2307 return NULL; 2308 if (!isl_space_is_params(space)) 2309 isl_die(isl_space_get_ctx(space), isl_error_invalid, 2310 "not a parameter space", goto error); 2311 return isl_space_reset(space, isl_dim_set); 2312 error: 2313 isl_space_free(space); 2314 return NULL; 2315 } 2316 2317 /* Add an unnamed tuple of dimension "dim" to "space". 2318 * This requires "space" to be a parameter or set space. 2319 * 2320 * In particular, if "space" is a parameter space, then return 2321 * a set space with the given dimension. 2322 * If "space" is a set space, then return a map space 2323 * with "space" as domain and a range of the given dimension. 2324 */ 2325 __isl_give isl_space *isl_space_add_unnamed_tuple_ui( 2326 __isl_take isl_space *space, unsigned dim) 2327 { 2328 isl_bool is_params, is_set; 2329 2330 is_params = isl_space_is_params(space); 2331 is_set = isl_space_is_set(space); 2332 if (is_params < 0 || is_set < 0) 2333 return isl_space_free(space); 2334 if (!is_params && !is_set) 2335 isl_die(isl_space_get_ctx(space), isl_error_invalid, 2336 "cannot add tuple to map space", 2337 return isl_space_free(space)); 2338 if (is_params) 2339 space = isl_space_set_from_params(space); 2340 else 2341 space = isl_space_from_domain(space); 2342 space = isl_space_add_dims(space, isl_dim_out, dim); 2343 return space; 2344 } 2345 2346 /* Add a tuple of dimension "dim" and with tuple identifier "tuple_id" 2347 * to "space". 2348 * This requires "space" to be a parameter or set space. 2349 */ 2350 __isl_give isl_space *isl_space_add_named_tuple_id_ui( 2351 __isl_take isl_space *space, __isl_take isl_id *tuple_id, unsigned dim) 2352 { 2353 space = isl_space_add_unnamed_tuple_ui(space, dim); 2354 space = isl_space_set_tuple_id(space, isl_dim_out, tuple_id); 2355 return space; 2356 } 2357 2358 /* Check that the identifiers in "tuple" do not appear as parameters 2359 * in "space". 2360 */ 2361 static isl_stat check_fresh_params(__isl_keep isl_space *space, 2362 __isl_keep isl_multi_id *tuple) 2363 { 2364 int i; 2365 isl_size n; 2366 2367 n = isl_multi_id_size(tuple); 2368 if (n < 0) 2369 return isl_stat_error; 2370 for (i = 0; i < n; ++i) { 2371 isl_id *id; 2372 int pos; 2373 2374 id = isl_multi_id_get_at(tuple, i); 2375 if (!id) 2376 return isl_stat_error; 2377 pos = isl_space_find_dim_by_id(space, isl_dim_param, id); 2378 isl_id_free(id); 2379 if (pos >= 0) 2380 isl_die(isl_space_get_ctx(space), isl_error_invalid, 2381 "parameters not unique", return isl_stat_error); 2382 } 2383 2384 return isl_stat_ok; 2385 } 2386 2387 /* Add the identifiers in "tuple" as parameters of "space" 2388 * that are known to be fresh. 2389 */ 2390 static __isl_give isl_space *add_bind_params(__isl_take isl_space *space, 2391 __isl_keep isl_multi_id *tuple) 2392 { 2393 int i; 2394 isl_size first, n; 2395 2396 first = isl_space_dim(space, isl_dim_param); 2397 n = isl_multi_id_size(tuple); 2398 if (first < 0 || n < 0) 2399 return isl_space_free(space); 2400 space = isl_space_add_dims(space, isl_dim_param, n); 2401 for (i = 0; i < n; ++i) { 2402 isl_id *id; 2403 2404 id = isl_multi_id_get_at(tuple, i); 2405 space = isl_space_set_dim_id(space, 2406 isl_dim_param, first + i, id); 2407 } 2408 2409 return space; 2410 } 2411 2412 /* Internal function that removes the set tuple of "space", 2413 * which is assumed to correspond to the range space of "tuple", and 2414 * adds the identifiers in "tuple" as fresh parameters. 2415 * In other words, the set dimensions of "space" are reinterpreted 2416 * as parameters, but stay in the same global positions. 2417 */ 2418 __isl_give isl_space *isl_space_bind_set(__isl_take isl_space *space, 2419 __isl_keep isl_multi_id *tuple) 2420 { 2421 isl_space *tuple_space; 2422 2423 if (isl_space_check_is_set(space) < 0) 2424 return isl_space_free(space); 2425 tuple_space = isl_multi_id_peek_space(tuple); 2426 if (isl_space_check_equal_tuples(tuple_space, space) < 0) 2427 return isl_space_free(space); 2428 if (check_fresh_params(space, tuple) < 0) 2429 return isl_space_free(space); 2430 space = isl_space_params(space); 2431 space = add_bind_params(space, tuple); 2432 return space; 2433 } 2434 2435 /* Internal function that removes the domain tuple of the map space "space", 2436 * which is assumed to correspond to the range space of "tuple", and 2437 * adds the identifiers in "tuple" as fresh parameters. 2438 * In other words, the domain dimensions of "space" are reinterpreted 2439 * as parameters, but stay in the same global positions. 2440 */ 2441 __isl_give isl_space *isl_space_bind_map_domain(__isl_take isl_space *space, 2442 __isl_keep isl_multi_id *tuple) 2443 { 2444 isl_space *tuple_space; 2445 2446 if (isl_space_check_is_map(space) < 0) 2447 return isl_space_free(space); 2448 tuple_space = isl_multi_id_peek_space(tuple); 2449 if (isl_space_check_domain_tuples(tuple_space, space) < 0) 2450 return isl_space_free(space); 2451 if (check_fresh_params(space, tuple) < 0) 2452 return isl_space_free(space); 2453 space = isl_space_range(space); 2454 space = add_bind_params(space, tuple); 2455 return space; 2456 } 2457 2458 /* Internal function that, given a space of the form [A -> B] -> C and 2459 * a tuple of identifiers in A, returns a space B -> C with 2460 * the identifiers in "tuple" added as fresh parameters. 2461 * In other words, the domain dimensions of the wrapped relation 2462 * in the domain of "space" are reinterpreted 2463 * as parameters, but stay in the same global positions. 2464 */ 2465 __isl_give isl_space *isl_space_bind_domain_wrapped_domain( 2466 __isl_take isl_space *space, __isl_keep isl_multi_id *tuple) 2467 { 2468 isl_space *tuple_space; 2469 2470 if (isl_space_check_is_map(space) < 0) 2471 return isl_space_free(space); 2472 tuple_space = isl_multi_id_peek_space(tuple); 2473 if (isl_space_check_domain_wrapped_domain_tuples(tuple_space, 2474 space) < 0) 2475 return isl_space_free(space); 2476 if (check_fresh_params(space, tuple) < 0) 2477 return isl_space_free(space); 2478 space = isl_space_domain_factor_range(space); 2479 space = add_bind_params(space, tuple); 2480 return space; 2481 } 2482 2483 /* Insert a domain tuple in "space" corresponding to the set space "domain". 2484 * In particular, if "space" is a parameter space, then the result 2485 * is the set space "domain" combined with the parameters of "space". 2486 * If "space" is a set space, then the result 2487 * is a map space with "domain" as domain and the original space as range. 2488 */ 2489 static __isl_give isl_space *isl_space_insert_domain( 2490 __isl_take isl_space *space, __isl_take isl_space *domain) 2491 { 2492 isl_bool is_params; 2493 2494 domain = isl_space_replace_params(domain, space); 2495 2496 is_params = isl_space_is_params(space); 2497 if (is_params < 0) { 2498 isl_space_free(domain); 2499 space = isl_space_free(space); 2500 } else if (is_params) { 2501 isl_space_free(space); 2502 space = domain; 2503 } else { 2504 space = isl_space_map_from_domain_and_range(domain, space); 2505 } 2506 return space; 2507 } 2508 2509 /* Internal function that introduces a domain in "space" 2510 * corresponding to the range space of "tuple". 2511 * In particular, if "space" is a parameter space, then the result 2512 * is a set space. If "space" is a set space, then the result 2513 * is a map space with the original space as range. 2514 * Parameters that correspond to the identifiers in "tuple" are removed. 2515 * 2516 * The parameters are removed in reverse order (under the assumption 2517 * that they appear in the same order in "multi") because 2518 * it is slightly more efficient to remove parameters at the end. 2519 * 2520 * For pretty-printing purposes, the identifiers of the set dimensions 2521 * of the introduced domain are set to the identifiers in "tuple". 2522 */ 2523 __isl_give isl_space *isl_space_unbind_params_insert_domain( 2524 __isl_take isl_space *space, __isl_keep isl_multi_id *tuple) 2525 { 2526 int i; 2527 isl_size n; 2528 isl_space *tuple_space; 2529 2530 n = isl_multi_id_size(tuple); 2531 if (!space || n < 0) 2532 return isl_space_free(space); 2533 for (i = n - 1; i >= 0; --i) { 2534 isl_id *id; 2535 int pos; 2536 2537 id = isl_multi_id_get_id(tuple, i); 2538 if (!id) 2539 return isl_space_free(space); 2540 pos = isl_space_find_dim_by_id(space, isl_dim_param, id); 2541 isl_id_free(id); 2542 if (pos < 0) 2543 continue; 2544 space = isl_space_drop_dims(space, isl_dim_param, pos, 1); 2545 } 2546 tuple_space = isl_multi_id_get_space(tuple); 2547 for (i = 0; i < n; ++i) { 2548 isl_id *id; 2549 2550 id = isl_multi_id_get_id(tuple, i); 2551 tuple_space = isl_space_set_dim_id(tuple_space, 2552 isl_dim_set, i, id); 2553 } 2554 return isl_space_insert_domain(space, tuple_space); 2555 } 2556 2557 __isl_give isl_space *isl_space_underlying(__isl_take isl_space *space, 2558 unsigned n_div) 2559 { 2560 int i; 2561 isl_bool is_set; 2562 2563 is_set = isl_space_is_set(space); 2564 if (is_set < 0) 2565 return isl_space_free(space); 2566 if (n_div == 0 && is_set && 2567 space->nparam == 0 && space->n_in == 0 && space->n_id == 0) 2568 return isl_space_reset(space, isl_dim_out); 2569 space = isl_space_cow(space); 2570 if (!space) 2571 return NULL; 2572 space->n_out += space->nparam + space->n_in + n_div; 2573 space->nparam = 0; 2574 space->n_in = 0; 2575 2576 for (i = 0; i < space->n_id; ++i) 2577 isl_id_free(get_id(space, isl_dim_out, i)); 2578 space->n_id = 0; 2579 space = isl_space_reset(space, isl_dim_in); 2580 space = isl_space_reset(space, isl_dim_out); 2581 space = mark_as_set(space); 2582 2583 return space; 2584 } 2585 2586 /* Are the two spaces the same, including positions and names of parameters? 2587 */ 2588 isl_bool isl_space_is_equal(__isl_keep isl_space *space1, 2589 __isl_keep isl_space *space2) 2590 { 2591 isl_bool equal; 2592 2593 if (!space1 || !space2) 2594 return isl_bool_error; 2595 if (space1 == space2) 2596 return isl_bool_true; 2597 equal = isl_space_has_equal_params(space1, space2); 2598 if (equal < 0 || !equal) 2599 return equal; 2600 return isl_space_has_equal_tuples(space1, space2); 2601 } 2602 2603 /* Do the tuples of "space1" correspond to those of the domain of "space2"? 2604 * That is, is "space1" equal to the domain of "space2", ignoring parameters. 2605 * 2606 * "space2" is allowed to be a set space, in which case "space1" 2607 * should be a parameter space. 2608 */ 2609 isl_bool isl_space_has_domain_tuples(__isl_keep isl_space *space1, 2610 __isl_keep isl_space *space2) 2611 { 2612 isl_bool is_set; 2613 2614 is_set = isl_space_is_set(space1); 2615 if (is_set < 0 || !is_set) 2616 return is_set; 2617 return isl_space_tuple_is_equal(space1, isl_dim_set, 2618 space2, isl_dim_in); 2619 } 2620 2621 /* Do the tuples of "space1" correspond to those of the range of "space2"? 2622 * That is, is "space1" equal to the range of "space2", ignoring parameters. 2623 * 2624 * "space2" is allowed to be the space of a set, 2625 * in which case it should be equal to "space1", ignoring parameters. 2626 */ 2627 isl_bool isl_space_has_range_tuples(__isl_keep isl_space *space1, 2628 __isl_keep isl_space *space2) 2629 { 2630 isl_bool is_set; 2631 2632 is_set = isl_space_is_set(space1); 2633 if (is_set < 0 || !is_set) 2634 return is_set; 2635 return isl_space_tuple_is_equal(space1, isl_dim_set, 2636 space2, isl_dim_out); 2637 } 2638 2639 /* Check that the tuples of "space1" correspond to those 2640 * of the domain of "space2". 2641 * That is, check that "space1" is equal to the domain of "space2", 2642 * ignoring parameters. 2643 */ 2644 isl_stat isl_space_check_domain_tuples(__isl_keep isl_space *space1, 2645 __isl_keep isl_space *space2) 2646 { 2647 isl_bool is_equal; 2648 2649 is_equal = isl_space_has_domain_tuples(space1, space2); 2650 return check_match(space1, is_equal); 2651 } 2652 2653 /* Check that the tuples of "space1" correspond to those 2654 * of the domain of the wrapped relation in the domain of "space2". 2655 * That is, check that "space1" is equal to this domain, 2656 * ignoring parameters. 2657 */ 2658 isl_stat isl_space_check_domain_wrapped_domain_tuples( 2659 __isl_keep isl_space *space1, __isl_keep isl_space *space2) 2660 { 2661 isl_space *domain; 2662 isl_stat r; 2663 2664 domain = isl_space_unwrap(isl_space_domain(isl_space_copy(space2))); 2665 r = isl_space_check_domain_tuples(space1, domain); 2666 isl_space_free(domain); 2667 2668 return r; 2669 } 2670 2671 /* Is space1 equal to the domain of space2? 2672 * 2673 * In the internal version we also allow space2 to be the space of a set, 2674 * provided space1 is a parameter space. 2675 */ 2676 isl_bool isl_space_is_domain_internal(__isl_keep isl_space *space1, 2677 __isl_keep isl_space *space2) 2678 { 2679 isl_bool equal_params; 2680 2681 if (!space1 || !space2) 2682 return isl_bool_error; 2683 equal_params = isl_space_has_equal_params(space1, space2); 2684 if (equal_params < 0 || !equal_params) 2685 return equal_params; 2686 return isl_space_has_domain_tuples(space1, space2); 2687 } 2688 2689 /* Is space1 equal to the domain of space2? 2690 */ 2691 isl_bool isl_space_is_domain(__isl_keep isl_space *space1, 2692 __isl_keep isl_space *space2) 2693 { 2694 if (!space2) 2695 return isl_bool_error; 2696 if (!isl_space_is_map(space2)) 2697 return isl_bool_false; 2698 return isl_space_is_domain_internal(space1, space2); 2699 } 2700 2701 /* Is space1 equal to the range of space2? 2702 * 2703 * In the internal version, space2 is allowed to be the space of a set, 2704 * in which case it should be equal to space1. 2705 */ 2706 isl_bool isl_space_is_range_internal(__isl_keep isl_space *space1, 2707 __isl_keep isl_space *space2) 2708 { 2709 isl_bool equal_params; 2710 2711 if (!space1 || !space2) 2712 return isl_bool_error; 2713 equal_params = isl_space_has_equal_params(space1, space2); 2714 if (equal_params < 0 || !equal_params) 2715 return equal_params; 2716 return isl_space_has_range_tuples(space1, space2); 2717 } 2718 2719 /* Is space1 equal to the range of space2? 2720 */ 2721 isl_bool isl_space_is_range(__isl_keep isl_space *space1, 2722 __isl_keep isl_space *space2) 2723 { 2724 if (!space2) 2725 return isl_bool_error; 2726 if (!isl_space_is_map(space2)) 2727 return isl_bool_false; 2728 return isl_space_is_range_internal(space1, space2); 2729 } 2730 2731 /* Update "hash" by hashing in the parameters of "space". 2732 */ 2733 static uint32_t isl_hash_params(uint32_t hash, __isl_keep isl_space *space) 2734 { 2735 int i; 2736 isl_id *id; 2737 2738 if (!space) 2739 return hash; 2740 2741 isl_hash_byte(hash, space->nparam % 256); 2742 2743 for (i = 0; i < space->nparam; ++i) { 2744 id = get_id(space, isl_dim_param, i); 2745 hash = isl_hash_id(hash, id); 2746 } 2747 2748 return hash; 2749 } 2750 2751 /* Update "hash" by hashing in the tuples of "space". 2752 * Changes in this function should be reflected in isl_hash_tuples_domain. 2753 */ 2754 static uint32_t isl_hash_tuples(uint32_t hash, __isl_keep isl_space *space) 2755 { 2756 isl_id *id; 2757 2758 if (!space) 2759 return hash; 2760 2761 isl_hash_byte(hash, space->n_in % 256); 2762 isl_hash_byte(hash, space->n_out % 256); 2763 2764 id = tuple_id(space, isl_dim_in); 2765 hash = isl_hash_id(hash, id); 2766 id = tuple_id(space, isl_dim_out); 2767 hash = isl_hash_id(hash, id); 2768 2769 hash = isl_hash_tuples(hash, space->nested[0]); 2770 hash = isl_hash_tuples(hash, space->nested[1]); 2771 2772 return hash; 2773 } 2774 2775 /* Update "hash" by hashing in the domain tuple of "space". 2776 * The result of this function is equal to the result of applying 2777 * isl_hash_tuples to the domain of "space". 2778 */ 2779 static uint32_t isl_hash_tuples_domain(uint32_t hash, 2780 __isl_keep isl_space *space) 2781 { 2782 isl_id *id; 2783 2784 if (!space) 2785 return hash; 2786 2787 isl_hash_byte(hash, 0); 2788 isl_hash_byte(hash, space->n_in % 256); 2789 2790 hash = isl_hash_id(hash, &isl_id_none); 2791 id = tuple_id(space, isl_dim_in); 2792 hash = isl_hash_id(hash, id); 2793 2794 hash = isl_hash_tuples(hash, space->nested[0]); 2795 2796 return hash; 2797 } 2798 2799 /* Return a hash value that digests the tuples of "space", 2800 * i.e., that ignores the parameters. 2801 * Changes in this function should be reflected 2802 * in isl_space_get_tuple_domain_hash. 2803 */ 2804 uint32_t isl_space_get_tuple_hash(__isl_keep isl_space *space) 2805 { 2806 uint32_t hash; 2807 2808 if (!space) 2809 return 0; 2810 2811 hash = isl_hash_init(); 2812 hash = isl_hash_tuples(hash, space); 2813 2814 return hash; 2815 } 2816 2817 /* Return the hash value of "space". 2818 */ 2819 uint32_t isl_space_get_full_hash(__isl_keep isl_space *space) 2820 { 2821 uint32_t hash; 2822 2823 if (!space) 2824 return 0; 2825 2826 hash = isl_hash_init(); 2827 hash = isl_hash_params(hash, space); 2828 hash = isl_hash_tuples(hash, space); 2829 2830 return hash; 2831 } 2832 2833 /* Return the hash value of the domain tuple of "space". 2834 * That is, isl_space_get_tuple_domain_hash(space) is equal to 2835 * isl_space_get_tuple_hash(isl_space_domain(space)). 2836 */ 2837 uint32_t isl_space_get_tuple_domain_hash(__isl_keep isl_space *space) 2838 { 2839 uint32_t hash; 2840 2841 if (!space) 2842 return 0; 2843 2844 hash = isl_hash_init(); 2845 hash = isl_hash_tuples_domain(hash, space); 2846 2847 return hash; 2848 } 2849 2850 /* Is "space" the space of a set wrapping a map space? 2851 */ 2852 isl_bool isl_space_is_wrapping(__isl_keep isl_space *space) 2853 { 2854 if (!space) 2855 return isl_bool_error; 2856 2857 if (!isl_space_is_set(space)) 2858 return isl_bool_false; 2859 2860 return isl_bool_ok(space->nested[1] != NULL); 2861 } 2862 2863 /* Is "space" the space of a map where the domain is a wrapped map space? 2864 */ 2865 isl_bool isl_space_domain_is_wrapping(__isl_keep isl_space *space) 2866 { 2867 if (!space) 2868 return isl_bool_error; 2869 2870 if (isl_space_is_set(space)) 2871 return isl_bool_false; 2872 2873 return isl_bool_ok(space->nested[0] != NULL); 2874 } 2875 2876 /* Is "space" the space of a map where the range is a wrapped map space? 2877 */ 2878 isl_bool isl_space_range_is_wrapping(__isl_keep isl_space *space) 2879 { 2880 if (!space) 2881 return isl_bool_error; 2882 2883 if (isl_space_is_set(space)) 2884 return isl_bool_false; 2885 2886 return isl_bool_ok(space->nested[1] != NULL); 2887 } 2888 2889 /* Is "space" a product of two spaces? 2890 * That is, is it a wrapping set space or a map space 2891 * with wrapping domain and range? 2892 */ 2893 isl_bool isl_space_is_product(__isl_keep isl_space *space) 2894 { 2895 isl_bool is_set; 2896 isl_bool is_product; 2897 2898 is_set = isl_space_is_set(space); 2899 if (is_set < 0) 2900 return isl_bool_error; 2901 if (is_set) 2902 return isl_space_is_wrapping(space); 2903 is_product = isl_space_domain_is_wrapping(space); 2904 if (is_product < 0 || !is_product) 2905 return is_product; 2906 return isl_space_range_is_wrapping(space); 2907 } 2908 2909 __isl_give isl_space *isl_space_wrap(__isl_take isl_space *space) 2910 { 2911 isl_space *wrap; 2912 2913 if (!space) 2914 return NULL; 2915 2916 wrap = isl_space_set_alloc(space->ctx, 2917 space->nparam, space->n_in + space->n_out); 2918 2919 wrap = copy_ids(wrap, isl_dim_param, 0, space, isl_dim_param); 2920 wrap = copy_ids(wrap, isl_dim_set, 0, space, isl_dim_in); 2921 wrap = copy_ids(wrap, isl_dim_set, space->n_in, space, isl_dim_out); 2922 2923 if (!wrap) 2924 goto error; 2925 2926 wrap->nested[1] = space; 2927 2928 return wrap; 2929 error: 2930 isl_space_free(space); 2931 return NULL; 2932 } 2933 2934 __isl_give isl_space *isl_space_unwrap(__isl_take isl_space *space) 2935 { 2936 isl_space *unwrap; 2937 2938 if (!space) 2939 return NULL; 2940 2941 if (!isl_space_is_wrapping(space)) 2942 isl_die(space->ctx, isl_error_invalid, "not a wrapping space", 2943 goto error); 2944 2945 unwrap = isl_space_copy(space->nested[1]); 2946 isl_space_free(space); 2947 2948 return unwrap; 2949 error: 2950 isl_space_free(space); 2951 return NULL; 2952 } 2953 2954 isl_bool isl_space_is_named_or_nested(__isl_keep isl_space *space, 2955 enum isl_dim_type type) 2956 { 2957 if (type != isl_dim_in && type != isl_dim_out) 2958 return isl_bool_false; 2959 if (!space) 2960 return isl_bool_error; 2961 if (space->tuple_id[type - isl_dim_in]) 2962 return isl_bool_true; 2963 if (space->nested[type - isl_dim_in]) 2964 return isl_bool_true; 2965 return isl_bool_false; 2966 } 2967 2968 isl_bool isl_space_may_be_set(__isl_keep isl_space *space) 2969 { 2970 isl_bool nested; 2971 isl_size n_in; 2972 2973 if (!space) 2974 return isl_bool_error; 2975 if (isl_space_is_set(space)) 2976 return isl_bool_true; 2977 n_in = isl_space_dim(space, isl_dim_in); 2978 if (n_in < 0) 2979 return isl_bool_error; 2980 if (n_in != 0) 2981 return isl_bool_false; 2982 nested = isl_space_is_named_or_nested(space, isl_dim_in); 2983 if (nested < 0 || nested) 2984 return isl_bool_not(nested); 2985 return isl_bool_true; 2986 } 2987 2988 __isl_give isl_space *isl_space_reset(__isl_take isl_space *space, 2989 enum isl_dim_type type) 2990 { 2991 if (!isl_space_is_named_or_nested(space, type)) 2992 return space; 2993 2994 space = isl_space_cow(space); 2995 if (!space) 2996 return NULL; 2997 2998 isl_id_free(space->tuple_id[type - isl_dim_in]); 2999 space->tuple_id[type - isl_dim_in] = NULL; 3000 isl_space_free(space->nested[type - isl_dim_in]); 3001 space->nested[type - isl_dim_in] = NULL; 3002 3003 return space; 3004 } 3005 3006 __isl_give isl_space *isl_space_flatten(__isl_take isl_space *space) 3007 { 3008 if (!space) 3009 return NULL; 3010 if (!space->nested[0] && !space->nested[1]) 3011 return space; 3012 3013 if (space->nested[0]) 3014 space = isl_space_reset(space, isl_dim_in); 3015 if (space && space->nested[1]) 3016 space = isl_space_reset(space, isl_dim_out); 3017 3018 return space; 3019 } 3020 3021 __isl_give isl_space *isl_space_flatten_domain(__isl_take isl_space *space) 3022 { 3023 if (!space) 3024 return NULL; 3025 if (!space->nested[0]) 3026 return space; 3027 3028 return isl_space_reset(space, isl_dim_in); 3029 } 3030 3031 __isl_give isl_space *isl_space_flatten_range(__isl_take isl_space *space) 3032 { 3033 if (!space) 3034 return NULL; 3035 if (!space->nested[1]) 3036 return space; 3037 3038 return isl_space_reset(space, isl_dim_out); 3039 } 3040 3041 /* Replace the parameters of dst by those of src. 3042 */ 3043 __isl_give isl_space *isl_space_replace_params(__isl_take isl_space *dst, 3044 __isl_keep isl_space *src) 3045 { 3046 isl_size dst_dim, src_dim; 3047 isl_bool equal_params; 3048 enum isl_dim_type type = isl_dim_param; 3049 3050 equal_params = isl_space_has_equal_params(dst, src); 3051 if (equal_params < 0) 3052 return isl_space_free(dst); 3053 if (equal_params) 3054 return dst; 3055 3056 dst = isl_space_cow(dst); 3057 3058 dst_dim = isl_space_dim(dst, type); 3059 src_dim = isl_space_dim(src, type); 3060 if (dst_dim < 0 || src_dim < 0) 3061 goto error; 3062 3063 dst = isl_space_drop_dims(dst, type, 0, dst_dim); 3064 dst = isl_space_add_dims(dst, type, src_dim); 3065 dst = copy_ids(dst, type, 0, src, type); 3066 3067 if (dst) { 3068 int i; 3069 for (i = 0; i <= 1; ++i) { 3070 isl_space *nested; 3071 3072 if (!dst->nested[i]) 3073 continue; 3074 nested = isl_space_take_nested(dst, i); 3075 nested = isl_space_replace_params(nested, src); 3076 dst = isl_space_restore_nested(dst, i, nested); 3077 if (!dst) 3078 return NULL; 3079 } 3080 } 3081 3082 return dst; 3083 error: 3084 isl_space_free(dst); 3085 return NULL; 3086 } 3087 3088 /* Given two tuples ("dst_type" in "dst" and "src_type" in "src") 3089 * of the same size, check if any of the dimensions in the "dst" tuple 3090 * have no identifier, while the corresponding dimensions in "src" 3091 * does have an identifier, 3092 * If so, copy the identifier over to "dst". 3093 */ 3094 __isl_give isl_space *isl_space_copy_ids_if_unset(__isl_take isl_space *dst, 3095 enum isl_dim_type dst_type, __isl_keep isl_space *src, 3096 enum isl_dim_type src_type) 3097 { 3098 int i; 3099 isl_size n; 3100 3101 n = isl_space_dim(dst, dst_type); 3102 if (n < 0) 3103 return isl_space_free(dst); 3104 for (i = 0; i < n; ++i) { 3105 isl_bool set; 3106 isl_id *id; 3107 3108 set = isl_space_has_dim_id(dst, dst_type, i); 3109 if (set < 0) 3110 return isl_space_free(dst); 3111 if (set) 3112 continue; 3113 3114 set = isl_space_has_dim_id(src, src_type, i); 3115 if (set < 0) 3116 return isl_space_free(dst); 3117 if (!set) 3118 continue; 3119 3120 id = isl_space_get_dim_id(src, src_type, i); 3121 dst = isl_space_set_dim_id(dst, dst_type, i, id); 3122 } 3123 3124 return dst; 3125 } 3126 3127 /* Given a space "space" of a set, create a space 3128 * for the lift of the set. In particular, the result 3129 * is of the form lifted[space -> local[..]], with n_local variables in the 3130 * range of the wrapped map. 3131 */ 3132 __isl_give isl_space *isl_space_lift(__isl_take isl_space *space, 3133 unsigned n_local) 3134 { 3135 isl_space *local_space; 3136 3137 if (!space) 3138 return NULL; 3139 3140 local_space = isl_space_dup(space); 3141 local_space = isl_space_drop_dims(local_space, isl_dim_set, 0, 3142 space->n_out); 3143 local_space = isl_space_add_dims(local_space, isl_dim_set, n_local); 3144 local_space = isl_space_set_tuple_name(local_space, 3145 isl_dim_set, "local"); 3146 space = isl_space_join(isl_space_from_domain(space), 3147 isl_space_from_range(local_space)); 3148 space = isl_space_wrap(space); 3149 space = isl_space_set_tuple_name(space, isl_dim_set, "lifted"); 3150 3151 return space; 3152 } 3153 3154 isl_bool isl_space_can_zip(__isl_keep isl_space *space) 3155 { 3156 isl_bool is_set; 3157 3158 is_set = isl_space_is_set(space); 3159 if (is_set < 0) 3160 return isl_bool_error; 3161 if (is_set) 3162 return isl_bool_false; 3163 return isl_space_is_product(space); 3164 } 3165 3166 __isl_give isl_space *isl_space_zip(__isl_take isl_space *space) 3167 { 3168 isl_space *dom, *ran; 3169 isl_space *dom_dom, *dom_ran, *ran_dom, *ran_ran; 3170 3171 if (!isl_space_can_zip(space)) 3172 isl_die(space->ctx, isl_error_invalid, "space cannot be zipped", 3173 goto error); 3174 3175 if (!space) 3176 return NULL; 3177 dom = isl_space_unwrap(isl_space_domain(isl_space_copy(space))); 3178 ran = isl_space_unwrap(isl_space_range(space)); 3179 dom_dom = isl_space_domain(isl_space_copy(dom)); 3180 dom_ran = isl_space_range(dom); 3181 ran_dom = isl_space_domain(isl_space_copy(ran)); 3182 ran_ran = isl_space_range(ran); 3183 dom = isl_space_join(isl_space_from_domain(dom_dom), 3184 isl_space_from_range(ran_dom)); 3185 ran = isl_space_join(isl_space_from_domain(dom_ran), 3186 isl_space_from_range(ran_ran)); 3187 return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)), 3188 isl_space_from_range(isl_space_wrap(ran))); 3189 error: 3190 isl_space_free(space); 3191 return NULL; 3192 } 3193 3194 /* Can we apply isl_space_curry to "space"? 3195 * That is, does is it have a map space with a nested relation in its domain? 3196 */ 3197 isl_bool isl_space_can_curry(__isl_keep isl_space *space) 3198 { 3199 return isl_space_domain_is_wrapping(space); 3200 } 3201 3202 /* Given a space (A -> B) -> C, return the corresponding space 3203 * A -> (B -> C). 3204 */ 3205 __isl_give isl_space *isl_space_curry(__isl_take isl_space *space) 3206 { 3207 isl_space *dom, *ran; 3208 isl_space *dom_dom, *dom_ran; 3209 3210 if (!space) 3211 return NULL; 3212 3213 if (!isl_space_can_curry(space)) 3214 isl_die(space->ctx, isl_error_invalid, 3215 "space cannot be curried", goto error); 3216 3217 dom = isl_space_unwrap(isl_space_domain(isl_space_copy(space))); 3218 ran = isl_space_range(space); 3219 dom_dom = isl_space_domain(isl_space_copy(dom)); 3220 dom_ran = isl_space_range(dom); 3221 ran = isl_space_join(isl_space_from_domain(dom_ran), 3222 isl_space_from_range(ran)); 3223 return isl_space_join(isl_space_from_domain(dom_dom), 3224 isl_space_from_range(isl_space_wrap(ran))); 3225 error: 3226 isl_space_free(space); 3227 return NULL; 3228 } 3229 3230 /* Can isl_space_range_curry be applied to "space"? 3231 * That is, does it have a nested relation in its range, 3232 * the domain of which is itself a nested relation? 3233 */ 3234 isl_bool isl_space_can_range_curry(__isl_keep isl_space *space) 3235 { 3236 isl_bool can; 3237 3238 if (!space) 3239 return isl_bool_error; 3240 can = isl_space_range_is_wrapping(space); 3241 if (can < 0 || !can) 3242 return can; 3243 return isl_space_can_curry(space->nested[1]); 3244 } 3245 3246 /* Given a space A -> ((B -> C) -> D), return the corresponding space 3247 * A -> (B -> (C -> D)). 3248 */ 3249 __isl_give isl_space *isl_space_range_curry(__isl_take isl_space *space) 3250 { 3251 isl_space *nested; 3252 3253 if (!space) 3254 return NULL; 3255 3256 if (!isl_space_can_range_curry(space)) 3257 isl_die(isl_space_get_ctx(space), isl_error_invalid, 3258 "space range cannot be curried", 3259 return isl_space_free(space)); 3260 3261 nested = isl_space_take_nested(space, 1); 3262 nested = isl_space_curry(nested); 3263 space = isl_space_restore_nested(space, 1, nested); 3264 3265 return space; 3266 } 3267 3268 /* Can we apply isl_space_uncurry to "space"? 3269 * That is, does it have a map space with a nested relation in its range? 3270 */ 3271 isl_bool isl_space_can_uncurry(__isl_keep isl_space *space) 3272 { 3273 return isl_space_range_is_wrapping(space); 3274 } 3275 3276 /* Given a space A -> (B -> C), return the corresponding space 3277 * (A -> B) -> C. 3278 */ 3279 __isl_give isl_space *isl_space_uncurry(__isl_take isl_space *space) 3280 { 3281 isl_space *dom, *ran; 3282 isl_space *ran_dom, *ran_ran; 3283 3284 if (!space) 3285 return NULL; 3286 3287 if (!isl_space_can_uncurry(space)) 3288 isl_die(space->ctx, isl_error_invalid, 3289 "space cannot be uncurried", 3290 return isl_space_free(space)); 3291 3292 dom = isl_space_domain(isl_space_copy(space)); 3293 ran = isl_space_unwrap(isl_space_range(space)); 3294 ran_dom = isl_space_domain(isl_space_copy(ran)); 3295 ran_ran = isl_space_range(ran); 3296 dom = isl_space_join(isl_space_from_domain(dom), 3297 isl_space_from_range(ran_dom)); 3298 return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)), 3299 isl_space_from_range(ran_ran)); 3300 } 3301 3302 isl_bool isl_space_has_named_params(__isl_keep isl_space *space) 3303 { 3304 int i; 3305 isl_size off; 3306 3307 if (!space) 3308 return isl_bool_error; 3309 if (space->nparam == 0) 3310 return isl_bool_true; 3311 off = isl_space_offset(space, isl_dim_param); 3312 if (off < 0) 3313 return isl_bool_error; 3314 if (off + space->nparam > space->n_id) 3315 return isl_bool_false; 3316 for (i = 0; i < space->nparam; ++i) 3317 if (!space->ids[off + i]) 3318 return isl_bool_false; 3319 return isl_bool_true; 3320 } 3321 3322 /* Check that "space" has only named parameters, reporting an error 3323 * if it does not. 3324 */ 3325 isl_stat isl_space_check_named_params(__isl_keep isl_space *space) 3326 { 3327 isl_bool named; 3328 3329 named = isl_space_has_named_params(space); 3330 if (named < 0) 3331 return isl_stat_error; 3332 if (!named) 3333 isl_die(isl_space_get_ctx(space), isl_error_invalid, 3334 "unexpected unnamed parameters", return isl_stat_error); 3335 3336 return isl_stat_ok; 3337 } 3338 3339 /* Align the initial parameters of space1 to match the order in space2. 3340 */ 3341 __isl_give isl_space *isl_space_align_params(__isl_take isl_space *space1, 3342 __isl_take isl_space *space2) 3343 { 3344 isl_reordering *exp; 3345 3346 if (isl_space_check_named_params(space1) < 0 || 3347 isl_space_check_named_params(space2) < 0) 3348 goto error; 3349 3350 exp = isl_parameter_alignment_reordering(space1, space2); 3351 isl_space_free(space1); 3352 isl_space_free(space2); 3353 space1 = isl_reordering_get_space(exp); 3354 isl_reordering_free(exp); 3355 return space1; 3356 error: 3357 isl_space_free(space1); 3358 isl_space_free(space2); 3359 return NULL; 3360 } 3361 3362 /* Given the space of set (domain), construct a space for a map 3363 * with as domain the given space and as range the range of "model". 3364 */ 3365 __isl_give isl_space *isl_space_extend_domain_with_range( 3366 __isl_take isl_space *space, __isl_take isl_space *model) 3367 { 3368 isl_size n_out; 3369 3370 if (!model) 3371 goto error; 3372 3373 space = isl_space_from_domain(space); 3374 n_out = isl_space_dim(model, isl_dim_out); 3375 if (n_out < 0) 3376 goto error; 3377 space = isl_space_add_dims(space, isl_dim_out, n_out); 3378 if (isl_space_has_tuple_id(model, isl_dim_out)) 3379 space = isl_space_set_tuple_id(space, isl_dim_out, 3380 isl_space_get_tuple_id(model, isl_dim_out)); 3381 if (!space) 3382 goto error; 3383 if (model->nested[1]) { 3384 isl_space *nested = isl_space_copy(model->nested[1]); 3385 isl_size n_nested, n_space; 3386 nested = isl_space_align_params(nested, isl_space_copy(space)); 3387 n_nested = isl_space_dim(nested, isl_dim_param); 3388 n_space = isl_space_dim(space, isl_dim_param); 3389 if (n_nested < 0 || n_space < 0) 3390 goto error; 3391 if (n_nested > n_space) 3392 nested = isl_space_drop_dims(nested, isl_dim_param, 3393 n_space, n_nested - n_space); 3394 if (!nested) 3395 goto error; 3396 space->nested[1] = nested; 3397 } 3398 isl_space_free(model); 3399 return space; 3400 error: 3401 isl_space_free(model); 3402 isl_space_free(space); 3403 return NULL; 3404 } 3405 3406 /* Compare the "type" dimensions of two isl_spaces. 3407 * 3408 * The order is fairly arbitrary. 3409 */ 3410 static int isl_space_cmp_type(__isl_keep isl_space *space1, 3411 __isl_keep isl_space *space2, enum isl_dim_type type) 3412 { 3413 int cmp; 3414 isl_size dim1, dim2; 3415 isl_space *nested1, *nested2; 3416 3417 dim1 = isl_space_dim(space1, type); 3418 dim2 = isl_space_dim(space2, type); 3419 if (dim1 < 0 || dim2 < 0) 3420 return 0; 3421 if (dim1 != dim2) 3422 return dim1 - dim2; 3423 3424 cmp = isl_id_cmp(tuple_id(space1, type), tuple_id(space2, type)); 3425 if (cmp != 0) 3426 return cmp; 3427 3428 nested1 = nested(space1, type); 3429 nested2 = nested(space2, type); 3430 if (!nested1 != !nested2) 3431 return !nested1 - !nested2; 3432 3433 if (nested1) 3434 return isl_space_cmp(nested1, nested2); 3435 3436 return 0; 3437 } 3438 3439 /* Compare two isl_spaces. 3440 * 3441 * The order is fairly arbitrary. 3442 */ 3443 int isl_space_cmp(__isl_keep isl_space *space1, __isl_keep isl_space *space2) 3444 { 3445 int i; 3446 int cmp; 3447 3448 if (space1 == space2) 3449 return 0; 3450 if (!space1) 3451 return -1; 3452 if (!space2) 3453 return 1; 3454 3455 cmp = isl_space_cmp_type(space1, space2, isl_dim_param); 3456 if (cmp != 0) 3457 return cmp; 3458 cmp = isl_space_cmp_type(space1, space2, isl_dim_in); 3459 if (cmp != 0) 3460 return cmp; 3461 cmp = isl_space_cmp_type(space1, space2, isl_dim_out); 3462 if (cmp != 0) 3463 return cmp; 3464 3465 if (!space1->ids && !space2->ids) 3466 return 0; 3467 3468 for (i = 0; i < n(space1, isl_dim_param); ++i) { 3469 cmp = isl_id_cmp(get_id(space1, isl_dim_param, i), 3470 get_id(space2, isl_dim_param, i)); 3471 if (cmp != 0) 3472 return cmp; 3473 } 3474 3475 return 0; 3476 } 3477