1 /* 2 * Copyright 2013-2014 Ecole Normale Superieure 3 * Copyright 2014 INRIA Rocquencourt 4 * 5 * Use of this software is governed by the MIT license 6 * 7 * Written by Sven Verdoolaege, 8 * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France 9 * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, 10 * B.P. 105 - 78153 Le Chesnay, France 11 */ 12 13 #include <string.h> 14 #include <isl/val.h> 15 #include <isl/space.h> 16 #include <isl/map.h> 17 #include <isl/schedule_node.h> 18 #include <isl_schedule_band.h> 19 #include <isl_schedule_private.h> 20 21 isl_ctx *isl_schedule_band_get_ctx(__isl_keep isl_schedule_band *band) 22 { 23 return band ? isl_multi_union_pw_aff_get_ctx(band->mupa) : NULL; 24 } 25 26 /* Return a new uninitialized isl_schedule_band. 27 */ 28 static __isl_give isl_schedule_band *isl_schedule_band_alloc(isl_ctx *ctx) 29 { 30 isl_schedule_band *band; 31 32 band = isl_calloc_type(ctx, isl_schedule_band); 33 if (!band) 34 return NULL; 35 36 band->ref = 1; 37 38 return band; 39 } 40 41 /* Return a new isl_schedule_band with partial schedule "mupa". 42 * First replace "mupa" by its greatest integer part to ensure 43 * that the schedule is always integral. 44 * The band is not marked permutable, the dimensions are not 45 * marked coincident and the AST build options are empty. 46 * Since there are no build options, the node is not anchored. 47 */ 48 __isl_give isl_schedule_band *isl_schedule_band_from_multi_union_pw_aff( 49 __isl_take isl_multi_union_pw_aff *mupa) 50 { 51 isl_size dim; 52 isl_ctx *ctx; 53 isl_schedule_band *band; 54 isl_space *space; 55 56 mupa = isl_multi_union_pw_aff_floor(mupa); 57 dim = isl_multi_union_pw_aff_size(mupa); 58 if (dim < 0) 59 goto error; 60 ctx = isl_multi_union_pw_aff_get_ctx(mupa); 61 band = isl_schedule_band_alloc(ctx); 62 if (!band) 63 goto error; 64 65 band->n = dim; 66 band->coincident = isl_calloc_array(ctx, int, band->n); 67 band->mupa = mupa; 68 space = isl_space_params_alloc(ctx, 0); 69 band->ast_build_options = isl_union_set_empty(space); 70 band->anchored = 0; 71 72 if ((band->n && !band->coincident) || !band->ast_build_options) 73 return isl_schedule_band_free(band); 74 75 return band; 76 error: 77 isl_multi_union_pw_aff_free(mupa); 78 return NULL; 79 } 80 81 /* Create a duplicate of the given isl_schedule_band. 82 */ 83 __isl_give isl_schedule_band *isl_schedule_band_dup( 84 __isl_keep isl_schedule_band *band) 85 { 86 int i; 87 isl_ctx *ctx; 88 isl_schedule_band *dup; 89 90 if (!band) 91 return NULL; 92 93 ctx = isl_schedule_band_get_ctx(band); 94 dup = isl_schedule_band_alloc(ctx); 95 if (!dup) 96 return NULL; 97 98 dup->n = band->n; 99 dup->coincident = isl_alloc_array(ctx, int, band->n); 100 if (band->n && !dup->coincident) 101 return isl_schedule_band_free(dup); 102 103 for (i = 0; i < band->n; ++i) 104 dup->coincident[i] = band->coincident[i]; 105 dup->permutable = band->permutable; 106 107 dup->mupa = isl_multi_union_pw_aff_copy(band->mupa); 108 dup->ast_build_options = isl_union_set_copy(band->ast_build_options); 109 if (!dup->mupa || !dup->ast_build_options) 110 return isl_schedule_band_free(dup); 111 112 if (band->loop_type) { 113 dup->loop_type = isl_alloc_array(ctx, 114 enum isl_ast_loop_type, band->n); 115 if (band->n && !dup->loop_type) 116 return isl_schedule_band_free(dup); 117 for (i = 0; i < band->n; ++i) 118 dup->loop_type[i] = band->loop_type[i]; 119 } 120 if (band->isolate_loop_type) { 121 dup->isolate_loop_type = isl_alloc_array(ctx, 122 enum isl_ast_loop_type, band->n); 123 if (band->n && !dup->isolate_loop_type) 124 return isl_schedule_band_free(dup); 125 for (i = 0; i < band->n; ++i) 126 dup->isolate_loop_type[i] = band->isolate_loop_type[i]; 127 } 128 129 return dup; 130 } 131 132 /* Return an isl_schedule_band that is equal to "band" and that has only 133 * a single reference. 134 */ 135 __isl_give isl_schedule_band *isl_schedule_band_cow( 136 __isl_take isl_schedule_band *band) 137 { 138 if (!band) 139 return NULL; 140 141 if (band->ref == 1) 142 return band; 143 band->ref--; 144 return isl_schedule_band_dup(band); 145 } 146 147 /* Return a new reference to "band". 148 */ 149 __isl_give isl_schedule_band *isl_schedule_band_copy( 150 __isl_keep isl_schedule_band *band) 151 { 152 if (!band) 153 return NULL; 154 155 band->ref++; 156 return band; 157 } 158 159 /* Free a reference to "band" and return NULL. 160 */ 161 __isl_null isl_schedule_band *isl_schedule_band_free( 162 __isl_take isl_schedule_band *band) 163 { 164 if (!band) 165 return NULL; 166 167 if (--band->ref > 0) 168 return NULL; 169 170 isl_multi_union_pw_aff_free(band->mupa); 171 isl_union_set_free(band->ast_build_options); 172 free(band->loop_type); 173 free(band->isolate_loop_type); 174 free(band->coincident); 175 free(band); 176 177 return NULL; 178 } 179 180 /* Are "band1" and "band2" obviously equal? 181 */ 182 isl_bool isl_schedule_band_plain_is_equal(__isl_keep isl_schedule_band *band1, 183 __isl_keep isl_schedule_band *band2) 184 { 185 int i; 186 isl_bool equal; 187 188 if (!band1 || !band2) 189 return isl_bool_error; 190 if (band1 == band2) 191 return isl_bool_true; 192 193 if (band1->n != band2->n) 194 return isl_bool_false; 195 for (i = 0; i < band1->n; ++i) 196 if (band1->coincident[i] != band2->coincident[i]) 197 return isl_bool_false; 198 if (band1->permutable != band2->permutable) 199 return isl_bool_false; 200 201 equal = isl_multi_union_pw_aff_plain_is_equal(band1->mupa, band2->mupa); 202 if (equal < 0 || !equal) 203 return equal; 204 205 if (!band1->loop_type != !band2->loop_type) 206 return isl_bool_false; 207 if (band1->loop_type) 208 for (i = 0; i < band1->n; ++i) 209 if (band1->loop_type[i] != band2->loop_type[i]) 210 return isl_bool_false; 211 212 if (!band1->isolate_loop_type != !band2->isolate_loop_type) 213 return isl_bool_false; 214 if (band1->isolate_loop_type) 215 for (i = 0; i < band1->n; ++i) 216 if (band1->isolate_loop_type[i] != 217 band2->isolate_loop_type[i]) 218 return isl_bool_false; 219 220 return isl_union_set_is_equal(band1->ast_build_options, 221 band2->ast_build_options); 222 } 223 224 /* Return the number of scheduling dimensions in the band. 225 */ 226 isl_size isl_schedule_band_n_member(__isl_keep isl_schedule_band *band) 227 { 228 return band ? band->n : isl_size_error; 229 } 230 231 /* Is the given scheduling dimension coincident within the band and 232 * with respect to the coincidence constraints? 233 */ 234 isl_bool isl_schedule_band_member_get_coincident( 235 __isl_keep isl_schedule_band *band, int pos) 236 { 237 if (!band) 238 return isl_bool_error; 239 240 if (pos < 0 || pos >= band->n) 241 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, 242 "invalid member position", return isl_bool_error); 243 244 return isl_bool_ok(band->coincident[pos]); 245 } 246 247 /* Mark the given scheduling dimension as being coincident or not 248 * according to "coincident". 249 */ 250 __isl_give isl_schedule_band *isl_schedule_band_member_set_coincident( 251 __isl_take isl_schedule_band *band, int pos, int coincident) 252 { 253 if (!band) 254 return NULL; 255 if (isl_schedule_band_member_get_coincident(band, pos) == coincident) 256 return band; 257 band = isl_schedule_band_cow(band); 258 if (!band) 259 return NULL; 260 261 if (pos < 0 || pos >= band->n) 262 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, 263 "invalid member position", 264 return isl_schedule_band_free(band)); 265 266 band->coincident[pos] = coincident; 267 268 return band; 269 } 270 271 /* Is the schedule band mark permutable? 272 */ 273 isl_bool isl_schedule_band_get_permutable(__isl_keep isl_schedule_band *band) 274 { 275 if (!band) 276 return isl_bool_error; 277 return isl_bool_ok(band->permutable); 278 } 279 280 /* Mark the schedule band permutable or not according to "permutable"? 281 */ 282 __isl_give isl_schedule_band *isl_schedule_band_set_permutable( 283 __isl_take isl_schedule_band *band, int permutable) 284 { 285 if (!band) 286 return NULL; 287 if (band->permutable == permutable) 288 return band; 289 band = isl_schedule_band_cow(band); 290 if (!band) 291 return NULL; 292 293 band->permutable = permutable; 294 295 return band; 296 } 297 298 /* Is the band node "node" anchored? That is, does it reference 299 * the outer band nodes? 300 */ 301 int isl_schedule_band_is_anchored(__isl_keep isl_schedule_band *band) 302 { 303 return band ? band->anchored : -1; 304 } 305 306 /* Return the schedule space of the band. 307 */ 308 __isl_give isl_space *isl_schedule_band_get_space( 309 __isl_keep isl_schedule_band *band) 310 { 311 if (!band) 312 return NULL; 313 return isl_multi_union_pw_aff_get_space(band->mupa); 314 } 315 316 /* Intersect the domain of the band schedule of "band" with "domain". 317 */ 318 __isl_give isl_schedule_band *isl_schedule_band_intersect_domain( 319 __isl_take isl_schedule_band *band, __isl_take isl_union_set *domain) 320 { 321 band = isl_schedule_band_cow(band); 322 if (!band || !domain) 323 goto error; 324 325 band->mupa = isl_multi_union_pw_aff_intersect_domain(band->mupa, 326 domain); 327 if (!band->mupa) 328 return isl_schedule_band_free(band); 329 330 return band; 331 error: 332 isl_schedule_band_free(band); 333 isl_union_set_free(domain); 334 return NULL; 335 } 336 337 /* Return the schedule of the band in isolation. 338 */ 339 __isl_give isl_multi_union_pw_aff *isl_schedule_band_get_partial_schedule( 340 __isl_keep isl_schedule_band *band) 341 { 342 return band ? isl_multi_union_pw_aff_copy(band->mupa) : NULL; 343 } 344 345 /* Replace the schedule of "band" by "schedule". 346 */ 347 __isl_give isl_schedule_band *isl_schedule_band_set_partial_schedule( 348 __isl_take isl_schedule_band *band, 349 __isl_take isl_multi_union_pw_aff *schedule) 350 { 351 band = isl_schedule_band_cow(band); 352 if (!band || !schedule) 353 goto error; 354 355 isl_multi_union_pw_aff_free(band->mupa); 356 band->mupa = schedule; 357 358 return band; 359 error: 360 isl_schedule_band_free(band); 361 isl_multi_union_pw_aff_free(schedule); 362 return NULL; 363 } 364 365 /* Return the loop AST generation type for the band member of "band" 366 * at position "pos". 367 */ 368 enum isl_ast_loop_type isl_schedule_band_member_get_ast_loop_type( 369 __isl_keep isl_schedule_band *band, int pos) 370 { 371 if (!band) 372 return isl_ast_loop_error; 373 374 if (pos < 0 || pos >= band->n) 375 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, 376 "invalid member position", return isl_ast_loop_error); 377 378 if (!band->loop_type) 379 return isl_ast_loop_default; 380 381 return band->loop_type[pos]; 382 } 383 384 /* Set the loop AST generation type for the band member of "band" 385 * at position "pos" to "type". 386 */ 387 __isl_give isl_schedule_band *isl_schedule_band_member_set_ast_loop_type( 388 __isl_take isl_schedule_band *band, int pos, 389 enum isl_ast_loop_type type) 390 { 391 if (!band) 392 return NULL; 393 if (isl_schedule_band_member_get_ast_loop_type(band, pos) == type) 394 return band; 395 396 if (pos < 0 || pos >= band->n) 397 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, 398 "invalid member position", 399 return isl_schedule_band_free(band)); 400 401 band = isl_schedule_band_cow(band); 402 if (!band) 403 return isl_schedule_band_free(band); 404 405 if (!band->loop_type) { 406 isl_ctx *ctx; 407 408 ctx = isl_schedule_band_get_ctx(band); 409 band->loop_type = isl_calloc_array(ctx, 410 enum isl_ast_loop_type, band->n); 411 if (band->n && !band->loop_type) 412 return isl_schedule_band_free(band); 413 } 414 415 band->loop_type[pos] = type; 416 417 return band; 418 } 419 420 /* Return the loop AST generation type for the band member of "band" 421 * at position "pos" for the part that has been isolated by the isolate option. 422 */ 423 enum isl_ast_loop_type isl_schedule_band_member_get_isolate_ast_loop_type( 424 __isl_keep isl_schedule_band *band, int pos) 425 { 426 if (!band) 427 return isl_ast_loop_error; 428 429 if (pos < 0 || pos >= band->n) 430 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, 431 "invalid member position", return isl_ast_loop_error); 432 433 if (!band->isolate_loop_type) 434 return isl_ast_loop_default; 435 436 return band->isolate_loop_type[pos]; 437 } 438 439 /* Set the loop AST generation type for the band member of "band" 440 * at position "pos" to "type" for the part that has been isolated 441 * by the isolate option. 442 */ 443 __isl_give isl_schedule_band * 444 isl_schedule_band_member_set_isolate_ast_loop_type( 445 __isl_take isl_schedule_band *band, int pos, 446 enum isl_ast_loop_type type) 447 { 448 if (!band) 449 return NULL; 450 if (isl_schedule_band_member_get_isolate_ast_loop_type(band, pos) == 451 type) 452 return band; 453 454 if (pos < 0 || pos >= band->n) 455 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, 456 "invalid member position", 457 return isl_schedule_band_free(band)); 458 459 band = isl_schedule_band_cow(band); 460 if (!band) 461 return isl_schedule_band_free(band); 462 463 if (!band->isolate_loop_type) { 464 isl_ctx *ctx; 465 466 ctx = isl_schedule_band_get_ctx(band); 467 band->isolate_loop_type = isl_calloc_array(ctx, 468 enum isl_ast_loop_type, band->n); 469 if (band->n && !band->isolate_loop_type) 470 return isl_schedule_band_free(band); 471 } 472 473 band->isolate_loop_type[pos] = type; 474 475 return band; 476 } 477 478 static const char *option_str[] = { 479 [isl_ast_loop_atomic] = "atomic", 480 [isl_ast_loop_unroll] = "unroll", 481 [isl_ast_loop_separate] = "separate" 482 }; 483 484 /* Given a parameter space "space", extend it to a set space 485 * 486 * { type[x] } 487 * 488 * or 489 * 490 * { [isolate[] -> type[x]] } 491 * 492 * depending on whether "isolate" is set. 493 * These can be used to encode loop AST generation options of the given type. 494 */ 495 static __isl_give isl_space *loop_type_space(__isl_take isl_space *space, 496 enum isl_ast_loop_type type, int isolate) 497 { 498 const char *name; 499 500 name = option_str[type]; 501 space = isl_space_set_from_params(space); 502 space = isl_space_add_dims(space, isl_dim_set, 1); 503 space = isl_space_set_tuple_name(space, isl_dim_set, name); 504 if (!isolate) 505 return space; 506 space = isl_space_from_range(space); 507 space = isl_space_set_tuple_name(space, isl_dim_in, "isolate"); 508 space = isl_space_wrap(space); 509 510 return space; 511 } 512 513 /* Add encodings of the "n" loop AST generation options "type" to "options". 514 * If "isolate" is set, then these options refer to the isolated part. 515 * 516 * In particular, for each sequence of consecutive identical types "t", 517 * different from the default, add an option 518 * 519 * { t[x] : first <= x <= last } 520 * 521 * or 522 * 523 * { [isolate[] -> t[x]] : first <= x <= last } 524 */ 525 static __isl_give isl_union_set *add_loop_types( 526 __isl_take isl_union_set *options, int n, enum isl_ast_loop_type *type, 527 int isolate) 528 { 529 int i; 530 531 if (!type) 532 return options; 533 if (!options) 534 return NULL; 535 536 for (i = 0; i < n; ++i) { 537 int first; 538 isl_space *space; 539 isl_set *option; 540 541 if (type[i] == isl_ast_loop_default) 542 continue; 543 544 first = i; 545 while (i + 1 < n && type[i + 1] == type[i]) 546 ++i; 547 548 space = isl_union_set_get_space(options); 549 space = loop_type_space(space, type[i], isolate); 550 option = isl_set_universe(space); 551 option = isl_set_lower_bound_si(option, isl_dim_set, 0, first); 552 option = isl_set_upper_bound_si(option, isl_dim_set, 0, i); 553 options = isl_union_set_add_set(options, option); 554 } 555 556 return options; 557 } 558 559 /* Return the AST build options associated to "band". 560 */ 561 __isl_give isl_union_set *isl_schedule_band_get_ast_build_options( 562 __isl_keep isl_schedule_band *band) 563 { 564 isl_union_set *options; 565 566 if (!band) 567 return NULL; 568 569 options = isl_union_set_copy(band->ast_build_options); 570 options = add_loop_types(options, band->n, band->loop_type, 0); 571 options = add_loop_types(options, band->n, band->isolate_loop_type, 1); 572 573 return options; 574 } 575 576 /* Internal data structure for not(). 577 */ 578 struct isl_not_data { 579 isl_bool (*is)(__isl_keep isl_set *set); 580 }; 581 582 /* Does "set" not satisfy data->is()? 583 */ 584 static isl_bool not(__isl_keep isl_set *set, void *user) 585 { 586 struct isl_not_data *data = user; 587 588 return isl_bool_not(data->is(set)); 589 } 590 591 /* Does "uset" contain any set that satisfies "is"? 592 * In other words, is it not the case that all of them do not satisfy "is"? 593 */ 594 static isl_bool has_any(__isl_keep isl_union_set *uset, 595 isl_bool (*is)(__isl_keep isl_set *set)) 596 { 597 struct isl_not_data data = { is }; 598 599 return isl_bool_not(isl_union_set_every_set(uset, ¬, &data)); 600 } 601 602 /* Does "set" live in a space of the form 603 * 604 * isolate[[...] -> [...]] 605 * 606 * ? 607 */ 608 static isl_bool is_isolate(__isl_keep isl_set *set) 609 { 610 if (isl_set_has_tuple_name(set)) { 611 const char *name; 612 name = isl_set_get_tuple_name(set); 613 if (isl_set_is_wrapping(set) && !strcmp(name, "isolate")) 614 return isl_bool_true; 615 } 616 617 return isl_bool_false; 618 } 619 620 /* Does "options" include an option of the ofrm 621 * 622 * isolate[[...] -> [...]] 623 * 624 * ? 625 */ 626 static isl_bool has_isolate_option(__isl_keep isl_union_set *options) 627 { 628 return has_any(options, &is_isolate); 629 } 630 631 /* Does "set" encode a loop AST generation option? 632 */ 633 static isl_bool is_loop_type_option(__isl_keep isl_set *set) 634 { 635 isl_size dim; 636 637 dim = isl_set_dim(set, isl_dim_set); 638 if (dim < 0) 639 return isl_bool_error; 640 if (dim == 1 && isl_set_has_tuple_name(set)) { 641 const char *name; 642 enum isl_ast_loop_type type; 643 name = isl_set_get_tuple_name(set); 644 for (type = isl_ast_loop_atomic; 645 type <= isl_ast_loop_separate; ++type) { 646 if (strcmp(name, option_str[type])) 647 continue; 648 return isl_bool_true; 649 } 650 } 651 652 return isl_bool_false; 653 } 654 655 /* Does "set" encode a loop AST generation option for the isolated part? 656 * That is, is of the form 657 * 658 * { [isolate[] -> t[x]] } 659 * 660 * with t equal to "atomic", "unroll" or "separate"? 661 */ 662 static isl_bool is_isolate_loop_type_option(__isl_keep isl_set *set) 663 { 664 const char *name; 665 enum isl_ast_loop_type type; 666 isl_map *map; 667 668 if (!isl_set_is_wrapping(set)) 669 return isl_bool_false; 670 map = isl_set_unwrap(isl_set_copy(set)); 671 if (!isl_map_has_tuple_name(map, isl_dim_in) || 672 !isl_map_has_tuple_name(map, isl_dim_out)) { 673 isl_map_free(map); 674 return isl_bool_false; 675 } 676 name = isl_map_get_tuple_name(map, isl_dim_in); 677 if (!strcmp(name, "isolate")) { 678 name = isl_map_get_tuple_name(map, isl_dim_out); 679 for (type = isl_ast_loop_atomic; 680 type <= isl_ast_loop_separate; ++type) { 681 if (strcmp(name, option_str[type])) 682 continue; 683 isl_map_free(map); 684 return isl_bool_true; 685 } 686 } 687 isl_map_free(map); 688 689 return isl_bool_false; 690 } 691 692 /* Does "options" encode any loop AST generation options 693 * for the isolated part? 694 */ 695 static isl_bool has_isolate_loop_type_options(__isl_keep isl_union_set *options) 696 { 697 return has_any(options, &is_isolate_loop_type_option); 698 } 699 700 /* Does "options" encode any loop AST generation options? 701 */ 702 static isl_bool has_loop_type_options(__isl_keep isl_union_set *options) 703 { 704 return has_any(options, &is_loop_type_option); 705 } 706 707 /* Extract the loop AST generation type for the band member 708 * at position "pos" from "options". 709 * If "isolate" is set, then extract the loop types for the isolated part. 710 */ 711 static enum isl_ast_loop_type extract_loop_type( 712 __isl_keep isl_union_set *options, int pos, int isolate) 713 { 714 isl_ctx *ctx; 715 enum isl_ast_loop_type type, res = isl_ast_loop_default; 716 717 ctx = isl_union_set_get_ctx(options); 718 for (type = isl_ast_loop_atomic; 719 type <= isl_ast_loop_separate; ++type) { 720 isl_space *space; 721 isl_set *option; 722 int empty; 723 724 space = isl_union_set_get_space(options); 725 space = loop_type_space(space, type, isolate); 726 option = isl_union_set_extract_set(options, space); 727 option = isl_set_fix_si(option, isl_dim_set, 0, pos); 728 empty = isl_set_is_empty(option); 729 isl_set_free(option); 730 731 if (empty < 0) 732 return isl_ast_loop_error; 733 if (empty) 734 continue; 735 if (res != isl_ast_loop_default) 736 isl_die(ctx, isl_error_invalid, 737 "conflicting loop type options", 738 return isl_ast_loop_error); 739 res = type; 740 } 741 742 return res; 743 } 744 745 /* Extract the loop AST generation types for the members of "band" 746 * from "options" and store them in band->loop_type. 747 * Return -1 on error. 748 */ 749 static int extract_loop_types(__isl_keep isl_schedule_band *band, 750 __isl_keep isl_union_set *options) 751 { 752 int i; 753 754 if (!band->loop_type) { 755 isl_ctx *ctx = isl_schedule_band_get_ctx(band); 756 band->loop_type = isl_alloc_array(ctx, 757 enum isl_ast_loop_type, band->n); 758 if (band->n && !band->loop_type) 759 return -1; 760 } 761 for (i = 0; i < band->n; ++i) { 762 band->loop_type[i] = extract_loop_type(options, i, 0); 763 if (band->loop_type[i] == isl_ast_loop_error) 764 return -1; 765 } 766 767 return 0; 768 } 769 770 /* Extract the loop AST generation types for the members of "band" 771 * from "options" for the isolated part and 772 * store them in band->isolate_loop_type. 773 * Return -1 on error. 774 */ 775 static int extract_isolate_loop_types(__isl_keep isl_schedule_band *band, 776 __isl_keep isl_union_set *options) 777 { 778 int i; 779 780 if (!band->isolate_loop_type) { 781 isl_ctx *ctx = isl_schedule_band_get_ctx(band); 782 band->isolate_loop_type = isl_alloc_array(ctx, 783 enum isl_ast_loop_type, band->n); 784 if (band->n && !band->isolate_loop_type) 785 return -1; 786 } 787 for (i = 0; i < band->n; ++i) { 788 band->isolate_loop_type[i] = extract_loop_type(options, i, 1); 789 if (band->isolate_loop_type[i] == isl_ast_loop_error) 790 return -1; 791 } 792 793 return 0; 794 } 795 796 /* Construct universe sets of the spaces that encode loop AST generation 797 * types (for the isolated part if "isolate" is set). That is, construct 798 * 799 * { atomic[x]; separate[x]; unroll[x] } 800 * 801 * or 802 * 803 * { [isolate[] -> atomic[x]]; [isolate[] -> separate[x]]; 804 * [isolate[] -> unroll[x]] } 805 */ 806 static __isl_give isl_union_set *loop_types(__isl_take isl_space *space, 807 int isolate) 808 { 809 enum isl_ast_loop_type type; 810 isl_union_set *types; 811 812 types = isl_union_set_empty(space); 813 for (type = isl_ast_loop_atomic; 814 type <= isl_ast_loop_separate; ++type) { 815 isl_set *set; 816 817 space = isl_union_set_get_space(types); 818 space = loop_type_space(space, type, isolate); 819 set = isl_set_universe(space); 820 types = isl_union_set_add_set(types, set); 821 } 822 823 return types; 824 } 825 826 /* Remove all elements from spaces that encode loop AST generation types 827 * from "options". 828 */ 829 static __isl_give isl_union_set *clear_loop_types( 830 __isl_take isl_union_set *options) 831 { 832 isl_union_set *types; 833 834 types = loop_types(isl_union_set_get_space(options), 0); 835 options = isl_union_set_subtract(options, types); 836 837 return options; 838 } 839 840 /* Remove all elements from spaces that encode loop AST generation types 841 * for the isolated part from "options". 842 */ 843 static __isl_give isl_union_set *clear_isolate_loop_types( 844 __isl_take isl_union_set *options) 845 { 846 isl_union_set *types; 847 848 types = loop_types(isl_union_set_get_space(options), 1); 849 options = isl_union_set_subtract(options, types); 850 851 return options; 852 } 853 854 /* Replace the AST build options associated to "band" by "options". 855 * If there are any loop AST generation type options, then they 856 * are extracted and stored in band->loop_type. Otherwise, 857 * band->loop_type is removed to indicate that the default applies 858 * to all members. Similarly for the loop AST generation type options 859 * for the isolated part, which are stored in band->isolate_loop_type. 860 * The remaining options are stored in band->ast_build_options. 861 * 862 * Set anchored if the options include an isolate option since the 863 * domain of the wrapped map references the outer band node schedules. 864 */ 865 __isl_give isl_schedule_band *isl_schedule_band_set_ast_build_options( 866 __isl_take isl_schedule_band *band, __isl_take isl_union_set *options) 867 { 868 isl_bool has_isolate, has_loop_type, has_isolate_loop_type; 869 870 band = isl_schedule_band_cow(band); 871 if (!band || !options) 872 goto error; 873 has_isolate = has_isolate_option(options); 874 if (has_isolate < 0) 875 goto error; 876 has_loop_type = has_loop_type_options(options); 877 if (has_loop_type < 0) 878 goto error; 879 has_isolate_loop_type = has_isolate_loop_type_options(options); 880 if (has_isolate_loop_type < 0) 881 goto error; 882 883 if (!has_loop_type) { 884 free(band->loop_type); 885 band->loop_type = NULL; 886 } else { 887 if (extract_loop_types(band, options) < 0) 888 goto error; 889 options = clear_loop_types(options); 890 if (!options) 891 goto error; 892 } 893 894 if (!has_isolate_loop_type) { 895 free(band->isolate_loop_type); 896 band->isolate_loop_type = NULL; 897 } else { 898 if (extract_isolate_loop_types(band, options) < 0) 899 goto error; 900 options = clear_isolate_loop_types(options); 901 if (!options) 902 goto error; 903 } 904 905 isl_union_set_free(band->ast_build_options); 906 band->ast_build_options = options; 907 band->anchored = has_isolate; 908 909 return band; 910 error: 911 isl_schedule_band_free(band); 912 isl_union_set_free(options); 913 return NULL; 914 } 915 916 /* Return the "isolate" option associated to "band", assuming 917 * it at appears at schedule depth "depth". 918 * 919 * The isolate option is of the form 920 * 921 * isolate[[flattened outer bands] -> band] 922 */ 923 __isl_give isl_set *isl_schedule_band_get_ast_isolate_option( 924 __isl_keep isl_schedule_band *band, int depth) 925 { 926 isl_space *space; 927 isl_set *isolate; 928 929 if (!band) 930 return NULL; 931 932 space = isl_schedule_band_get_space(band); 933 space = isl_space_from_range(space); 934 space = isl_space_add_dims(space, isl_dim_in, depth); 935 space = isl_space_wrap(space); 936 space = isl_space_set_tuple_name(space, isl_dim_set, "isolate"); 937 938 isolate = isl_union_set_extract_set(band->ast_build_options, space); 939 940 return isolate; 941 } 942 943 /* Replace the option "drop" in the AST build options by "add". 944 * That is, remove "drop" and add "add". 945 */ 946 __isl_give isl_schedule_band *isl_schedule_band_replace_ast_build_option( 947 __isl_take isl_schedule_band *band, __isl_take isl_set *drop, 948 __isl_take isl_set *add) 949 { 950 isl_union_set *options; 951 952 band = isl_schedule_band_cow(band); 953 if (!band) 954 goto error; 955 956 options = band->ast_build_options; 957 options = isl_union_set_subtract(options, isl_union_set_from_set(drop)); 958 options = isl_union_set_union(options, isl_union_set_from_set(add)); 959 band->ast_build_options = options; 960 961 if (!band->ast_build_options) 962 return isl_schedule_band_free(band); 963 964 return band; 965 error: 966 isl_schedule_band_free(band); 967 isl_set_free(drop); 968 isl_set_free(add); 969 return NULL; 970 } 971 972 /* Multiply the partial schedule of "band" with the factors in "mv". 973 * Replace the result by its greatest integer part to ensure 974 * that the schedule is always integral. 975 */ 976 __isl_give isl_schedule_band *isl_schedule_band_scale( 977 __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv) 978 { 979 band = isl_schedule_band_cow(band); 980 if (!band || !mv) 981 goto error; 982 band->mupa = isl_multi_union_pw_aff_scale_multi_val(band->mupa, mv); 983 band->mupa = isl_multi_union_pw_aff_floor(band->mupa); 984 if (!band->mupa) 985 return isl_schedule_band_free(band); 986 return band; 987 error: 988 isl_schedule_band_free(band); 989 isl_multi_val_free(mv); 990 return NULL; 991 } 992 993 /* Divide the partial schedule of "band" by the factors in "mv". 994 * Replace the result by its greatest integer part to ensure 995 * that the schedule is always integral. 996 */ 997 __isl_give isl_schedule_band *isl_schedule_band_scale_down( 998 __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv) 999 { 1000 band = isl_schedule_band_cow(band); 1001 if (!band || !mv) 1002 goto error; 1003 band->mupa = isl_multi_union_pw_aff_scale_down_multi_val(band->mupa, 1004 mv); 1005 band->mupa = isl_multi_union_pw_aff_floor(band->mupa); 1006 if (!band->mupa) 1007 return isl_schedule_band_free(band); 1008 return band; 1009 error: 1010 isl_schedule_band_free(band); 1011 isl_multi_val_free(mv); 1012 return NULL; 1013 } 1014 1015 /* Reduce the partial schedule of "band" modulo the factors in "mv". 1016 */ 1017 __isl_give isl_schedule_band *isl_schedule_band_mod( 1018 __isl_take isl_schedule_band *band, __isl_take isl_multi_val *mv) 1019 { 1020 band = isl_schedule_band_cow(band); 1021 if (!band || !mv) 1022 goto error; 1023 band->mupa = isl_multi_union_pw_aff_mod_multi_val(band->mupa, mv); 1024 if (!band->mupa) 1025 return isl_schedule_band_free(band); 1026 return band; 1027 error: 1028 isl_schedule_band_free(band); 1029 isl_multi_val_free(mv); 1030 return NULL; 1031 } 1032 1033 /* Shift the partial schedule of "band" by "shift" after checking 1034 * that the domain of the partial schedule would not be affected 1035 * by this shift. 1036 */ 1037 __isl_give isl_schedule_band *isl_schedule_band_shift( 1038 __isl_take isl_schedule_band *band, 1039 __isl_take isl_multi_union_pw_aff *shift) 1040 { 1041 isl_union_set *dom1, *dom2; 1042 isl_bool subset; 1043 1044 band = isl_schedule_band_cow(band); 1045 if (!band || !shift) 1046 goto error; 1047 dom1 = isl_multi_union_pw_aff_domain( 1048 isl_multi_union_pw_aff_copy(band->mupa)); 1049 dom2 = isl_multi_union_pw_aff_domain( 1050 isl_multi_union_pw_aff_copy(shift)); 1051 subset = isl_union_set_is_subset(dom1, dom2); 1052 isl_union_set_free(dom1); 1053 isl_union_set_free(dom2); 1054 if (subset < 0) 1055 goto error; 1056 if (!subset) 1057 isl_die(isl_schedule_band_get_ctx(band), isl_error_invalid, 1058 "domain of shift needs to include domain of " 1059 "partial schedule", goto error); 1060 band->mupa = isl_multi_union_pw_aff_add(band->mupa, shift); 1061 if (!band->mupa) 1062 return isl_schedule_band_free(band); 1063 return band; 1064 error: 1065 isl_schedule_band_free(band); 1066 isl_multi_union_pw_aff_free(shift); 1067 return NULL; 1068 } 1069 1070 /* Given the schedule of a band, construct the corresponding 1071 * schedule for the tile loops based on the given tile sizes 1072 * and return the result. 1073 * 1074 * If the scale tile loops options is set, then the tile loops 1075 * are scaled by the tile sizes. 1076 * 1077 * That is replace each schedule dimension "i" by either 1078 * "floor(i/s)" or "s * floor(i/s)". 1079 */ 1080 static isl_multi_union_pw_aff *isl_multi_union_pw_aff_tile( 1081 __isl_take isl_multi_union_pw_aff *sched, 1082 __isl_take isl_multi_val *sizes) 1083 { 1084 isl_ctx *ctx; 1085 int i; 1086 isl_size n; 1087 isl_val *v; 1088 int scale; 1089 1090 ctx = isl_multi_val_get_ctx(sizes); 1091 scale = isl_options_get_tile_scale_tile_loops(ctx); 1092 1093 n = isl_multi_union_pw_aff_size(sched); 1094 if (n < 0) 1095 sched = isl_multi_union_pw_aff_free(sched); 1096 for (i = 0; i < n; ++i) { 1097 isl_union_pw_aff *upa; 1098 1099 upa = isl_multi_union_pw_aff_get_union_pw_aff(sched, i); 1100 v = isl_multi_val_get_val(sizes, i); 1101 1102 upa = isl_union_pw_aff_scale_down_val(upa, isl_val_copy(v)); 1103 upa = isl_union_pw_aff_floor(upa); 1104 if (scale) 1105 upa = isl_union_pw_aff_scale_val(upa, isl_val_copy(v)); 1106 isl_val_free(v); 1107 1108 sched = isl_multi_union_pw_aff_set_union_pw_aff(sched, i, upa); 1109 } 1110 1111 isl_multi_val_free(sizes); 1112 return sched; 1113 } 1114 1115 /* Replace "band" by a band corresponding to the tile loops of a tiling 1116 * with the given tile sizes. 1117 */ 1118 __isl_give isl_schedule_band *isl_schedule_band_tile( 1119 __isl_take isl_schedule_band *band, __isl_take isl_multi_val *sizes) 1120 { 1121 band = isl_schedule_band_cow(band); 1122 if (!band || !sizes) 1123 goto error; 1124 band->mupa = isl_multi_union_pw_aff_tile(band->mupa, sizes); 1125 if (!band->mupa) 1126 return isl_schedule_band_free(band); 1127 return band; 1128 error: 1129 isl_schedule_band_free(band); 1130 isl_multi_val_free(sizes); 1131 return NULL; 1132 } 1133 1134 /* Replace "band" by a band corresponding to the point loops of a tiling 1135 * with the given tile sizes. 1136 * "tile" is the corresponding tile loop band. 1137 * 1138 * If the shift point loops option is set, then the point loops 1139 * are shifted to start at zero. That is, each schedule dimension "i" 1140 * is replaced by "i - s * floor(i/s)". 1141 * The expression "floor(i/s)" (or "s * floor(i/s)") is extracted from 1142 * the tile band. 1143 * 1144 * Otherwise, the band is left untouched. 1145 */ 1146 __isl_give isl_schedule_band *isl_schedule_band_point( 1147 __isl_take isl_schedule_band *band, __isl_keep isl_schedule_band *tile, 1148 __isl_take isl_multi_val *sizes) 1149 { 1150 isl_ctx *ctx; 1151 isl_multi_union_pw_aff *scaled; 1152 1153 if (!band || !sizes) 1154 goto error; 1155 1156 ctx = isl_schedule_band_get_ctx(band); 1157 if (!isl_options_get_tile_shift_point_loops(ctx)) { 1158 isl_multi_val_free(sizes); 1159 return band; 1160 } 1161 band = isl_schedule_band_cow(band); 1162 if (!band) 1163 goto error; 1164 1165 scaled = isl_schedule_band_get_partial_schedule(tile); 1166 if (!isl_options_get_tile_scale_tile_loops(ctx)) 1167 scaled = isl_multi_union_pw_aff_scale_multi_val(scaled, sizes); 1168 else 1169 isl_multi_val_free(sizes); 1170 band->mupa = isl_multi_union_pw_aff_sub(band->mupa, scaled); 1171 if (!band->mupa) 1172 return isl_schedule_band_free(band); 1173 return band; 1174 error: 1175 isl_schedule_band_free(band); 1176 isl_multi_val_free(sizes); 1177 return NULL; 1178 } 1179 1180 /* Drop the "n" dimensions starting at "pos" from "band". 1181 * 1182 * We apply the transformation even if "n" is zero to ensure consistent 1183 * behavior with respect to changes in the schedule space. 1184 * 1185 * The caller is responsible for updating the isolate option. 1186 */ 1187 __isl_give isl_schedule_band *isl_schedule_band_drop( 1188 __isl_take isl_schedule_band *band, int pos, int n) 1189 { 1190 int i; 1191 1192 if (pos < 0 || n < 0 || pos + n > band->n) 1193 isl_die(isl_schedule_band_get_ctx(band), isl_error_internal, 1194 "range out of bounds", 1195 return isl_schedule_band_free(band)); 1196 1197 band = isl_schedule_band_cow(band); 1198 if (!band) 1199 return NULL; 1200 1201 band->mupa = isl_multi_union_pw_aff_drop_dims(band->mupa, 1202 isl_dim_set, pos, n); 1203 if (!band->mupa) 1204 return isl_schedule_band_free(band); 1205 1206 for (i = pos + n; i < band->n; ++i) 1207 band->coincident[i - n] = band->coincident[i]; 1208 if (band->loop_type) 1209 for (i = pos + n; i < band->n; ++i) 1210 band->loop_type[i - n] = band->loop_type[i]; 1211 if (band->isolate_loop_type) 1212 for (i = pos + n; i < band->n; ++i) 1213 band->isolate_loop_type[i - n] = 1214 band->isolate_loop_type[i]; 1215 1216 band->n -= n; 1217 1218 return band; 1219 } 1220 1221 /* Reset the user pointer on all identifiers of parameters and tuples 1222 * in "band". 1223 */ 1224 __isl_give isl_schedule_band *isl_schedule_band_reset_user( 1225 __isl_take isl_schedule_band *band) 1226 { 1227 band = isl_schedule_band_cow(band); 1228 if (!band) 1229 return NULL; 1230 1231 band->mupa = isl_multi_union_pw_aff_reset_user(band->mupa); 1232 band->ast_build_options = 1233 isl_union_set_reset_user(band->ast_build_options); 1234 if (!band->mupa || !band->ast_build_options) 1235 return isl_schedule_band_free(band); 1236 1237 return band; 1238 } 1239 1240 /* Align the parameters of "band" to those of "space". 1241 */ 1242 __isl_give isl_schedule_band *isl_schedule_band_align_params( 1243 __isl_take isl_schedule_band *band, __isl_take isl_space *space) 1244 { 1245 band = isl_schedule_band_cow(band); 1246 if (!band || !space) 1247 goto error; 1248 1249 band->mupa = isl_multi_union_pw_aff_align_params(band->mupa, 1250 isl_space_copy(space)); 1251 band->ast_build_options = 1252 isl_union_set_align_params(band->ast_build_options, space); 1253 if (!band->mupa || !band->ast_build_options) 1254 return isl_schedule_band_free(band); 1255 1256 return band; 1257 error: 1258 isl_space_free(space); 1259 isl_schedule_band_free(band); 1260 return NULL; 1261 } 1262 1263 /* Compute the pullback of "band" by the function represented by "upma". 1264 * In other words, plug in "upma" in the iteration domains of "band". 1265 */ 1266 __isl_give isl_schedule_band *isl_schedule_band_pullback_union_pw_multi_aff( 1267 __isl_take isl_schedule_band *band, 1268 __isl_take isl_union_pw_multi_aff *upma) 1269 { 1270 band = isl_schedule_band_cow(band); 1271 if (!band || !upma) 1272 goto error; 1273 1274 band->mupa = 1275 isl_multi_union_pw_aff_pullback_union_pw_multi_aff(band->mupa, 1276 upma); 1277 if (!band->mupa) 1278 return isl_schedule_band_free(band); 1279 1280 return band; 1281 error: 1282 isl_union_pw_multi_aff_free(upma); 1283 isl_schedule_band_free(band); 1284 return NULL; 1285 } 1286 1287 /* Compute the gist of "band" with respect to "context". 1288 * In particular, compute the gist of the associated partial schedule. 1289 */ 1290 __isl_give isl_schedule_band *isl_schedule_band_gist( 1291 __isl_take isl_schedule_band *band, __isl_take isl_union_set *context) 1292 { 1293 if (!band || !context) 1294 goto error; 1295 if (band->n == 0) { 1296 isl_union_set_free(context); 1297 return band; 1298 } 1299 band = isl_schedule_band_cow(band); 1300 if (!band) 1301 goto error; 1302 band->mupa = isl_multi_union_pw_aff_gist(band->mupa, context); 1303 if (!band->mupa) 1304 return isl_schedule_band_free(band); 1305 return band; 1306 error: 1307 isl_union_set_free(context); 1308 isl_schedule_band_free(band); 1309 return NULL; 1310 } 1311