1 /* 2 * Copyright 2013-2014 Ecole Normale Superieure 3 * Copyright 2014 INRIA Rocquencourt 4 * Copyright 2016 INRIA Paris 5 * 6 * Use of this software is governed by the MIT license 7 * 8 * Written by Sven Verdoolaege, 9 * Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France 10 * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, 11 * B.P. 105 - 78153 Le Chesnay, France 12 * and Centre de Recherche Inria de Paris, 2 rue Simone Iff - Voie DQ12, 13 * CS 42112, 75589 Paris Cedex 12, France 14 */ 15 16 #include <isl/id.h> 17 #include <isl/val.h> 18 #include <isl/space.h> 19 #include <isl/map.h> 20 #include <isl_schedule_band.h> 21 #include <isl_schedule_private.h> 22 23 #undef EL 24 #define EL isl_schedule_tree 25 26 #include <isl_list_templ.h> 27 28 #undef EL_BASE 29 #define EL_BASE schedule_tree 30 31 #include <isl_list_templ.c> 32 33 /* Is "tree" the leaf of a schedule tree? 34 */ 35 int isl_schedule_tree_is_leaf(__isl_keep isl_schedule_tree *tree) 36 { 37 return isl_schedule_tree_get_type(tree) == isl_schedule_node_leaf; 38 } 39 40 /* Create a new schedule tree of type "type". 41 * The caller is responsible for filling in the type specific fields and 42 * the children. 43 * 44 * By default, the single node tree does not have any anchored nodes. 45 * The caller is responsible for updating the anchored field if needed. 46 */ 47 static __isl_give isl_schedule_tree *isl_schedule_tree_alloc(isl_ctx *ctx, 48 enum isl_schedule_node_type type) 49 { 50 isl_schedule_tree *tree; 51 52 if (type == isl_schedule_node_error) 53 return NULL; 54 55 tree = isl_calloc_type(ctx, isl_schedule_tree); 56 if (!tree) 57 return NULL; 58 59 tree->ref = 1; 60 tree->ctx = ctx; 61 isl_ctx_ref(ctx); 62 tree->type = type; 63 tree->anchored = 0; 64 65 return tree; 66 } 67 68 /* Return a fresh copy of "tree". 69 */ 70 __isl_give isl_schedule_tree *isl_schedule_tree_dup( 71 __isl_keep isl_schedule_tree *tree) 72 { 73 isl_ctx *ctx; 74 isl_schedule_tree *dup; 75 76 if (!tree) 77 return NULL; 78 79 ctx = isl_schedule_tree_get_ctx(tree); 80 dup = isl_schedule_tree_alloc(ctx, tree->type); 81 if (!dup) 82 return NULL; 83 84 switch (tree->type) { 85 case isl_schedule_node_error: 86 isl_die(ctx, isl_error_internal, 87 "allocation should have failed", 88 return isl_schedule_tree_free(dup)); 89 case isl_schedule_node_band: 90 dup->band = isl_schedule_band_copy(tree->band); 91 if (!dup->band) 92 return isl_schedule_tree_free(dup); 93 break; 94 case isl_schedule_node_context: 95 dup->context = isl_set_copy(tree->context); 96 if (!dup->context) 97 return isl_schedule_tree_free(dup); 98 break; 99 case isl_schedule_node_domain: 100 dup->domain = isl_union_set_copy(tree->domain); 101 if (!dup->domain) 102 return isl_schedule_tree_free(dup); 103 break; 104 case isl_schedule_node_expansion: 105 dup->contraction = 106 isl_union_pw_multi_aff_copy(tree->contraction); 107 dup->expansion = isl_union_map_copy(tree->expansion); 108 if (!dup->contraction || !dup->expansion) 109 return isl_schedule_tree_free(dup); 110 break; 111 case isl_schedule_node_extension: 112 dup->extension = isl_union_map_copy(tree->extension); 113 if (!dup->extension) 114 return isl_schedule_tree_free(dup); 115 break; 116 case isl_schedule_node_filter: 117 dup->filter = isl_union_set_copy(tree->filter); 118 if (!dup->filter) 119 return isl_schedule_tree_free(dup); 120 break; 121 case isl_schedule_node_guard: 122 dup->guard = isl_set_copy(tree->guard); 123 if (!dup->guard) 124 return isl_schedule_tree_free(dup); 125 break; 126 case isl_schedule_node_mark: 127 dup->mark = isl_id_copy(tree->mark); 128 if (!dup->mark) 129 return isl_schedule_tree_free(dup); 130 break; 131 case isl_schedule_node_leaf: 132 case isl_schedule_node_sequence: 133 case isl_schedule_node_set: 134 break; 135 } 136 137 if (tree->children) { 138 dup->children = isl_schedule_tree_list_copy(tree->children); 139 if (!dup->children) 140 return isl_schedule_tree_free(dup); 141 } 142 dup->anchored = tree->anchored; 143 144 return dup; 145 } 146 147 /* Return an isl_schedule_tree that is equal to "tree" and that has only 148 * a single reference. 149 */ 150 __isl_give isl_schedule_tree *isl_schedule_tree_cow( 151 __isl_take isl_schedule_tree *tree) 152 { 153 if (!tree) 154 return NULL; 155 156 if (tree->ref == 1) 157 return tree; 158 tree->ref--; 159 return isl_schedule_tree_dup(tree); 160 } 161 162 /* Return a new reference to "tree". 163 */ 164 __isl_give isl_schedule_tree *isl_schedule_tree_copy( 165 __isl_keep isl_schedule_tree *tree) 166 { 167 if (!tree) 168 return NULL; 169 170 tree->ref++; 171 return tree; 172 } 173 174 /* Free "tree" and return NULL. 175 */ 176 __isl_null isl_schedule_tree *isl_schedule_tree_free( 177 __isl_take isl_schedule_tree *tree) 178 { 179 if (!tree) 180 return NULL; 181 if (--tree->ref > 0) 182 return NULL; 183 184 switch (tree->type) { 185 case isl_schedule_node_band: 186 isl_schedule_band_free(tree->band); 187 break; 188 case isl_schedule_node_context: 189 isl_set_free(tree->context); 190 break; 191 case isl_schedule_node_domain: 192 isl_union_set_free(tree->domain); 193 break; 194 case isl_schedule_node_expansion: 195 isl_union_pw_multi_aff_free(tree->contraction); 196 isl_union_map_free(tree->expansion); 197 break; 198 case isl_schedule_node_extension: 199 isl_union_map_free(tree->extension); 200 break; 201 case isl_schedule_node_filter: 202 isl_union_set_free(tree->filter); 203 break; 204 case isl_schedule_node_guard: 205 isl_set_free(tree->guard); 206 break; 207 case isl_schedule_node_mark: 208 isl_id_free(tree->mark); 209 break; 210 case isl_schedule_node_sequence: 211 case isl_schedule_node_set: 212 case isl_schedule_node_error: 213 case isl_schedule_node_leaf: 214 break; 215 } 216 isl_schedule_tree_list_free(tree->children); 217 isl_ctx_deref(tree->ctx); 218 free(tree); 219 220 return NULL; 221 } 222 223 /* Create and return a new leaf schedule tree. 224 */ 225 __isl_give isl_schedule_tree *isl_schedule_tree_leaf(isl_ctx *ctx) 226 { 227 return isl_schedule_tree_alloc(ctx, isl_schedule_node_leaf); 228 } 229 230 /* Create a new band schedule tree referring to "band" 231 * with no children. 232 */ 233 __isl_give isl_schedule_tree *isl_schedule_tree_from_band( 234 __isl_take isl_schedule_band *band) 235 { 236 isl_ctx *ctx; 237 isl_schedule_tree *tree; 238 239 if (!band) 240 return NULL; 241 242 ctx = isl_schedule_band_get_ctx(band); 243 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_band); 244 if (!tree) 245 goto error; 246 247 tree->band = band; 248 tree->anchored = isl_schedule_band_is_anchored(band); 249 250 return tree; 251 error: 252 isl_schedule_band_free(band); 253 return NULL; 254 } 255 256 /* Create a new context schedule tree with the given context and no children. 257 * Since the context references the outer schedule dimension, 258 * the tree is anchored. 259 */ 260 __isl_give isl_schedule_tree *isl_schedule_tree_from_context( 261 __isl_take isl_set *context) 262 { 263 isl_ctx *ctx; 264 isl_schedule_tree *tree; 265 266 if (!context) 267 return NULL; 268 269 ctx = isl_set_get_ctx(context); 270 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_context); 271 if (!tree) 272 goto error; 273 274 tree->context = context; 275 tree->anchored = 1; 276 277 return tree; 278 error: 279 isl_set_free(context); 280 return NULL; 281 } 282 283 /* Create a new domain schedule tree with the given domain and no children. 284 */ 285 __isl_give isl_schedule_tree *isl_schedule_tree_from_domain( 286 __isl_take isl_union_set *domain) 287 { 288 isl_ctx *ctx; 289 isl_schedule_tree *tree; 290 291 if (!domain) 292 return NULL; 293 294 ctx = isl_union_set_get_ctx(domain); 295 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_domain); 296 if (!tree) 297 goto error; 298 299 tree->domain = domain; 300 301 return tree; 302 error: 303 isl_union_set_free(domain); 304 return NULL; 305 } 306 307 /* Create a new expansion schedule tree with the given contraction and 308 * expansion and no children. 309 */ 310 __isl_give isl_schedule_tree *isl_schedule_tree_from_expansion( 311 __isl_take isl_union_pw_multi_aff *contraction, 312 __isl_take isl_union_map *expansion) 313 { 314 isl_ctx *ctx; 315 isl_schedule_tree *tree; 316 317 if (!contraction || !expansion) 318 goto error; 319 320 ctx = isl_union_map_get_ctx(expansion); 321 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_expansion); 322 if (!tree) 323 goto error; 324 325 tree->contraction = contraction; 326 tree->expansion = expansion; 327 328 return tree; 329 error: 330 isl_union_pw_multi_aff_free(contraction); 331 isl_union_map_free(expansion); 332 return NULL; 333 } 334 335 /* Create a new extension schedule tree with the given extension and 336 * no children. 337 * Since the domain of the extension refers to the outer schedule dimension, 338 * the tree is anchored. 339 */ 340 __isl_give isl_schedule_tree *isl_schedule_tree_from_extension( 341 __isl_take isl_union_map *extension) 342 { 343 isl_ctx *ctx; 344 isl_schedule_tree *tree; 345 346 if (!extension) 347 return NULL; 348 349 ctx = isl_union_map_get_ctx(extension); 350 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_extension); 351 if (!tree) 352 goto error; 353 354 tree->extension = extension; 355 tree->anchored = 1; 356 357 return tree; 358 error: 359 isl_union_map_free(extension); 360 return NULL; 361 } 362 363 /* Create a new filter schedule tree with the given filter and no children. 364 */ 365 __isl_give isl_schedule_tree *isl_schedule_tree_from_filter( 366 __isl_take isl_union_set *filter) 367 { 368 isl_ctx *ctx; 369 isl_schedule_tree *tree; 370 371 if (!filter) 372 return NULL; 373 374 ctx = isl_union_set_get_ctx(filter); 375 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_filter); 376 if (!tree) 377 goto error; 378 379 tree->filter = filter; 380 381 return tree; 382 error: 383 isl_union_set_free(filter); 384 return NULL; 385 } 386 387 /* Create a new guard schedule tree with the given guard and no children. 388 * Since the guard references the outer schedule dimension, 389 * the tree is anchored. 390 */ 391 __isl_give isl_schedule_tree *isl_schedule_tree_from_guard( 392 __isl_take isl_set *guard) 393 { 394 isl_ctx *ctx; 395 isl_schedule_tree *tree; 396 397 if (!guard) 398 return NULL; 399 400 ctx = isl_set_get_ctx(guard); 401 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_guard); 402 if (!tree) 403 goto error; 404 405 tree->guard = guard; 406 tree->anchored = 1; 407 408 return tree; 409 error: 410 isl_set_free(guard); 411 return NULL; 412 } 413 414 /* Create a new mark schedule tree with the given mark identifier and 415 * no children. 416 */ 417 __isl_give isl_schedule_tree *isl_schedule_tree_from_mark( 418 __isl_take isl_id *mark) 419 { 420 isl_ctx *ctx; 421 isl_schedule_tree *tree; 422 423 if (!mark) 424 return NULL; 425 426 ctx = isl_id_get_ctx(mark); 427 tree = isl_schedule_tree_alloc(ctx, isl_schedule_node_mark); 428 if (!tree) 429 goto error; 430 431 tree->mark = mark; 432 433 return tree; 434 error: 435 isl_id_free(mark); 436 return NULL; 437 } 438 439 /* Does "tree" have any node that depends on its position 440 * in the complete schedule tree? 441 */ 442 isl_bool isl_schedule_tree_is_subtree_anchored( 443 __isl_keep isl_schedule_tree *tree) 444 { 445 return tree ? isl_bool_ok(tree->anchored) : isl_bool_error; 446 } 447 448 /* Does the root node of "tree" depend on its position in the complete 449 * schedule tree? 450 * Band nodes may be anchored depending on the associated AST build options. 451 * Context, extension and guard nodes are always anchored. 452 */ 453 int isl_schedule_tree_is_anchored(__isl_keep isl_schedule_tree *tree) 454 { 455 if (!tree) 456 return -1; 457 458 switch (isl_schedule_tree_get_type(tree)) { 459 case isl_schedule_node_error: 460 return -1; 461 case isl_schedule_node_band: 462 return isl_schedule_band_is_anchored(tree->band); 463 case isl_schedule_node_context: 464 case isl_schedule_node_extension: 465 case isl_schedule_node_guard: 466 return 1; 467 case isl_schedule_node_domain: 468 case isl_schedule_node_expansion: 469 case isl_schedule_node_filter: 470 case isl_schedule_node_leaf: 471 case isl_schedule_node_mark: 472 case isl_schedule_node_sequence: 473 case isl_schedule_node_set: 474 return 0; 475 } 476 477 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, 478 "unhandled case", return -1); 479 } 480 481 /* Update the anchored field of "tree" based on whether the root node 482 * itself in anchored and the anchored fields of the children. 483 * 484 * This function should be called whenever the children of a tree node 485 * are changed or the anchoredness of the tree root itself changes. 486 */ 487 __isl_give isl_schedule_tree *isl_schedule_tree_update_anchored( 488 __isl_take isl_schedule_tree *tree) 489 { 490 int i; 491 isl_size n; 492 int anchored; 493 494 anchored = isl_schedule_tree_is_anchored(tree); 495 n = isl_schedule_tree_n_children(tree); 496 if (anchored < 0 || n < 0) 497 return isl_schedule_tree_free(tree); 498 499 for (i = 0; !anchored && i < n; ++i) { 500 isl_schedule_tree *child; 501 502 child = isl_schedule_tree_get_child(tree, i); 503 if (!child) 504 return isl_schedule_tree_free(tree); 505 anchored = child->anchored; 506 isl_schedule_tree_free(child); 507 } 508 509 if (anchored == tree->anchored) 510 return tree; 511 tree = isl_schedule_tree_cow(tree); 512 if (!tree) 513 return NULL; 514 tree->anchored = anchored; 515 return tree; 516 } 517 518 /* Create a new tree of the given type (isl_schedule_node_sequence or 519 * isl_schedule_node_set) with the given children. 520 */ 521 __isl_give isl_schedule_tree *isl_schedule_tree_from_children( 522 enum isl_schedule_node_type type, 523 __isl_take isl_schedule_tree_list *list) 524 { 525 isl_ctx *ctx; 526 isl_schedule_tree *tree; 527 528 if (!list) 529 return NULL; 530 531 ctx = isl_schedule_tree_list_get_ctx(list); 532 tree = isl_schedule_tree_alloc(ctx, type); 533 if (!tree) 534 goto error; 535 536 tree->children = list; 537 tree = isl_schedule_tree_update_anchored(tree); 538 539 return tree; 540 error: 541 isl_schedule_tree_list_free(list); 542 return NULL; 543 } 544 545 /* Construct a tree with a root node of type "type" and as children 546 * "tree1" and "tree2". 547 * If the root of one (or both) of the input trees is itself of type "type", 548 * then the tree is replaced by its children. 549 */ 550 __isl_give isl_schedule_tree *isl_schedule_tree_from_pair( 551 enum isl_schedule_node_type type, __isl_take isl_schedule_tree *tree1, 552 __isl_take isl_schedule_tree *tree2) 553 { 554 isl_ctx *ctx; 555 isl_schedule_tree_list *list; 556 557 if (!tree1 || !tree2) 558 goto error; 559 560 ctx = isl_schedule_tree_get_ctx(tree1); 561 if (isl_schedule_tree_get_type(tree1) == type) { 562 list = isl_schedule_tree_list_copy(tree1->children); 563 isl_schedule_tree_free(tree1); 564 } else { 565 list = isl_schedule_tree_list_alloc(ctx, 2); 566 list = isl_schedule_tree_list_add(list, tree1); 567 } 568 if (isl_schedule_tree_get_type(tree2) == type) { 569 isl_schedule_tree_list *children; 570 571 children = isl_schedule_tree_list_copy(tree2->children); 572 list = isl_schedule_tree_list_concat(list, children); 573 isl_schedule_tree_free(tree2); 574 } else { 575 list = isl_schedule_tree_list_add(list, tree2); 576 } 577 578 return isl_schedule_tree_from_children(type, list); 579 error: 580 isl_schedule_tree_free(tree1); 581 isl_schedule_tree_free(tree2); 582 return NULL; 583 } 584 585 /* Construct a tree with a sequence root node and as children 586 * "tree1" and "tree2". 587 * If the root of one (or both) of the input trees is itself a sequence, 588 * then the tree is replaced by its children. 589 */ 590 __isl_give isl_schedule_tree *isl_schedule_tree_sequence_pair( 591 __isl_take isl_schedule_tree *tree1, 592 __isl_take isl_schedule_tree *tree2) 593 { 594 return isl_schedule_tree_from_pair(isl_schedule_node_sequence, 595 tree1, tree2); 596 } 597 598 /* Construct a tree with a set root node and as children 599 * "tree1" and "tree2". 600 * If the root of one (or both) of the input trees is itself a set, 601 * then the tree is replaced by its children. 602 */ 603 __isl_give isl_schedule_tree *isl_schedule_tree_set_pair( 604 __isl_take isl_schedule_tree *tree1, 605 __isl_take isl_schedule_tree *tree2) 606 { 607 return isl_schedule_tree_from_pair(isl_schedule_node_set, tree1, tree2); 608 } 609 610 /* Return the isl_ctx to which "tree" belongs. 611 */ 612 isl_ctx *isl_schedule_tree_get_ctx(__isl_keep isl_schedule_tree *tree) 613 { 614 return tree ? tree->ctx : NULL; 615 } 616 617 /* Return the type of the root of the tree or isl_schedule_node_error 618 * on error. 619 */ 620 enum isl_schedule_node_type isl_schedule_tree_get_type( 621 __isl_keep isl_schedule_tree *tree) 622 { 623 return tree ? tree->type : isl_schedule_node_error; 624 } 625 626 /* Are "tree1" and "tree2" obviously equal to each other? 627 */ 628 isl_bool isl_schedule_tree_plain_is_equal(__isl_keep isl_schedule_tree *tree1, 629 __isl_keep isl_schedule_tree *tree2) 630 { 631 isl_bool equal; 632 int i; 633 isl_size n1, n2; 634 635 if (!tree1 || !tree2) 636 return isl_bool_error; 637 if (tree1 == tree2) 638 return isl_bool_true; 639 if (tree1->type != tree2->type) 640 return isl_bool_false; 641 642 switch (tree1->type) { 643 case isl_schedule_node_band: 644 equal = isl_schedule_band_plain_is_equal(tree1->band, 645 tree2->band); 646 break; 647 case isl_schedule_node_context: 648 equal = isl_set_is_equal(tree1->context, tree2->context); 649 break; 650 case isl_schedule_node_domain: 651 equal = isl_union_set_is_equal(tree1->domain, tree2->domain); 652 break; 653 case isl_schedule_node_expansion: 654 equal = isl_union_map_is_equal(tree1->expansion, 655 tree2->expansion); 656 if (equal >= 0 && equal) 657 equal = isl_union_pw_multi_aff_plain_is_equal( 658 tree1->contraction, tree2->contraction); 659 break; 660 case isl_schedule_node_extension: 661 equal = isl_union_map_is_equal(tree1->extension, 662 tree2->extension); 663 break; 664 case isl_schedule_node_filter: 665 equal = isl_union_set_is_equal(tree1->filter, tree2->filter); 666 break; 667 case isl_schedule_node_guard: 668 equal = isl_set_is_equal(tree1->guard, tree2->guard); 669 break; 670 case isl_schedule_node_mark: 671 equal = isl_bool_ok(tree1->mark == tree2->mark); 672 break; 673 case isl_schedule_node_leaf: 674 case isl_schedule_node_sequence: 675 case isl_schedule_node_set: 676 equal = isl_bool_true; 677 break; 678 case isl_schedule_node_error: 679 equal = isl_bool_error; 680 break; 681 } 682 683 if (equal < 0 || !equal) 684 return equal; 685 686 n1 = isl_schedule_tree_n_children(tree1); 687 n2 = isl_schedule_tree_n_children(tree2); 688 if (n1 < 0 || n2 < 0) 689 return isl_bool_error; 690 if (n1 != n2) 691 return isl_bool_false; 692 for (i = 0; i < n1; ++i) { 693 isl_schedule_tree *child1, *child2; 694 695 child1 = isl_schedule_tree_get_child(tree1, i); 696 child2 = isl_schedule_tree_get_child(tree2, i); 697 equal = isl_schedule_tree_plain_is_equal(child1, child2); 698 isl_schedule_tree_free(child1); 699 isl_schedule_tree_free(child2); 700 701 if (equal < 0 || !equal) 702 return equal; 703 } 704 705 return isl_bool_true; 706 } 707 708 /* Does "tree" have any children, other than an implicit leaf. 709 */ 710 int isl_schedule_tree_has_children(__isl_keep isl_schedule_tree *tree) 711 { 712 if (!tree) 713 return -1; 714 715 return tree->children != NULL; 716 } 717 718 /* Return the number of children of "tree", excluding implicit leaves. 719 * The "children" field is NULL if there are 720 * no children (except for the implicit leaves). 721 */ 722 isl_size isl_schedule_tree_n_children(__isl_keep isl_schedule_tree *tree) 723 { 724 if (!tree) 725 return isl_size_error; 726 727 if (!tree->children) 728 return 0; 729 return isl_schedule_tree_list_n_schedule_tree(tree->children); 730 } 731 732 /* Return a copy of the (explicit) child at position "pos" of "tree". 733 */ 734 __isl_give isl_schedule_tree *isl_schedule_tree_get_child( 735 __isl_keep isl_schedule_tree *tree, int pos) 736 { 737 if (!tree) 738 return NULL; 739 if (!tree->children) 740 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, 741 "schedule tree has no explicit children", return NULL); 742 return isl_schedule_tree_list_get_schedule_tree(tree->children, pos); 743 } 744 745 /* Return a copy of the (explicit) child at position "pos" of "tree" and 746 * free "tree". 747 */ 748 __isl_give isl_schedule_tree *isl_schedule_tree_child( 749 __isl_take isl_schedule_tree *tree, int pos) 750 { 751 isl_schedule_tree *child; 752 753 child = isl_schedule_tree_get_child(tree, pos); 754 isl_schedule_tree_free(tree); 755 return child; 756 } 757 758 /* Remove all (explicit) children from "tree". 759 */ 760 __isl_give isl_schedule_tree *isl_schedule_tree_reset_children( 761 __isl_take isl_schedule_tree *tree) 762 { 763 tree = isl_schedule_tree_cow(tree); 764 if (!tree) 765 return NULL; 766 tree->children = isl_schedule_tree_list_free(tree->children); 767 return tree; 768 } 769 770 /* Remove the child at position "pos" from the children of "tree". 771 * If there was only one child to begin with, then remove all children. 772 */ 773 __isl_give isl_schedule_tree *isl_schedule_tree_drop_child( 774 __isl_take isl_schedule_tree *tree, int pos) 775 { 776 isl_size n; 777 778 tree = isl_schedule_tree_cow(tree); 779 780 n = isl_schedule_tree_n_children(tree); 781 if (n < 0) 782 return isl_schedule_tree_free(tree); 783 if (n == 0) 784 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 785 "tree does not have any explicit children", 786 return isl_schedule_tree_free(tree)); 787 if (pos < 0 || pos >= n) 788 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 789 "position out of bounds", 790 return isl_schedule_tree_free(tree)); 791 if (n == 1) 792 return isl_schedule_tree_reset_children(tree); 793 794 tree->children = isl_schedule_tree_list_drop(tree->children, pos, 1); 795 if (!tree->children) 796 return isl_schedule_tree_free(tree); 797 798 return tree; 799 } 800 801 /* Replace the child at position "pos" of "tree" by "child". 802 * 803 * If the new child is a leaf, then it is not explicitly 804 * recorded in the list of children. Instead, the list of children 805 * (which is assumed to have only one element) is removed. 806 * Note that the children of set and sequence nodes are always 807 * filters, so they cannot be replaced by empty trees. 808 */ 809 __isl_give isl_schedule_tree *isl_schedule_tree_replace_child( 810 __isl_take isl_schedule_tree *tree, int pos, 811 __isl_take isl_schedule_tree *child) 812 { 813 tree = isl_schedule_tree_cow(tree); 814 if (!tree || !child) 815 goto error; 816 817 if (isl_schedule_tree_is_leaf(child)) { 818 isl_size n; 819 820 isl_schedule_tree_free(child); 821 if (!tree->children && pos == 0) 822 return tree; 823 n = isl_schedule_tree_n_children(tree); 824 if (n < 0) 825 return isl_schedule_tree_free(tree); 826 if (n != 1) 827 isl_die(isl_schedule_tree_get_ctx(tree), 828 isl_error_internal, 829 "can only replace single child by leaf", 830 goto error); 831 return isl_schedule_tree_reset_children(tree); 832 } 833 834 if (!tree->children && pos == 0) 835 tree->children = 836 isl_schedule_tree_list_from_schedule_tree(child); 837 else 838 tree->children = isl_schedule_tree_list_set_schedule_tree( 839 tree->children, pos, child); 840 841 if (!tree->children) 842 return isl_schedule_tree_free(tree); 843 tree = isl_schedule_tree_update_anchored(tree); 844 845 return tree; 846 error: 847 isl_schedule_tree_free(tree); 848 isl_schedule_tree_free(child); 849 return NULL; 850 } 851 852 /* Replace the (explicit) children of "tree" by "children"? 853 */ 854 __isl_give isl_schedule_tree *isl_schedule_tree_set_children( 855 __isl_take isl_schedule_tree *tree, 856 __isl_take isl_schedule_tree_list *children) 857 { 858 tree = isl_schedule_tree_cow(tree); 859 if (!tree || !children) 860 goto error; 861 isl_schedule_tree_list_free(tree->children); 862 tree->children = children; 863 return tree; 864 error: 865 isl_schedule_tree_free(tree); 866 isl_schedule_tree_list_free(children); 867 return NULL; 868 } 869 870 /* Create a new band schedule tree referring to "band" 871 * with "tree" as single child. 872 */ 873 __isl_give isl_schedule_tree *isl_schedule_tree_insert_band( 874 __isl_take isl_schedule_tree *tree, __isl_take isl_schedule_band *band) 875 { 876 isl_schedule_tree *res; 877 878 res = isl_schedule_tree_from_band(band); 879 return isl_schedule_tree_replace_child(res, 0, tree); 880 } 881 882 /* Create a new context schedule tree with the given context and 883 * with "tree" as single child. 884 */ 885 __isl_give isl_schedule_tree *isl_schedule_tree_insert_context( 886 __isl_take isl_schedule_tree *tree, __isl_take isl_set *context) 887 { 888 isl_schedule_tree *res; 889 890 res = isl_schedule_tree_from_context(context); 891 return isl_schedule_tree_replace_child(res, 0, tree); 892 } 893 894 /* Create a new domain schedule tree with the given domain and 895 * with "tree" as single child. 896 */ 897 __isl_give isl_schedule_tree *isl_schedule_tree_insert_domain( 898 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain) 899 { 900 isl_schedule_tree *res; 901 902 res = isl_schedule_tree_from_domain(domain); 903 return isl_schedule_tree_replace_child(res, 0, tree); 904 } 905 906 /* Create a new expansion schedule tree with the given contraction and 907 * expansion and with "tree" as single child. 908 */ 909 __isl_give isl_schedule_tree *isl_schedule_tree_insert_expansion( 910 __isl_take isl_schedule_tree *tree, 911 __isl_take isl_union_pw_multi_aff *contraction, 912 __isl_take isl_union_map *expansion) 913 { 914 isl_schedule_tree *res; 915 916 res = isl_schedule_tree_from_expansion(contraction, expansion); 917 return isl_schedule_tree_replace_child(res, 0, tree); 918 } 919 920 /* Create a new extension schedule tree with the given extension and 921 * with "tree" as single child. 922 */ 923 __isl_give isl_schedule_tree *isl_schedule_tree_insert_extension( 924 __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension) 925 { 926 isl_schedule_tree *res; 927 928 res = isl_schedule_tree_from_extension(extension); 929 return isl_schedule_tree_replace_child(res, 0, tree); 930 } 931 932 /* Create a new filter schedule tree with the given filter and single child. 933 * 934 * If the root of "tree" is itself a filter node, then the two 935 * filter nodes are merged into one node. 936 */ 937 __isl_give isl_schedule_tree *isl_schedule_tree_insert_filter( 938 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter) 939 { 940 isl_schedule_tree *res; 941 942 if (isl_schedule_tree_get_type(tree) == isl_schedule_node_filter) { 943 isl_union_set *tree_filter; 944 945 tree_filter = isl_schedule_tree_filter_get_filter(tree); 946 tree_filter = isl_union_set_intersect(tree_filter, filter); 947 tree = isl_schedule_tree_filter_set_filter(tree, tree_filter); 948 return tree; 949 } 950 951 res = isl_schedule_tree_from_filter(filter); 952 return isl_schedule_tree_replace_child(res, 0, tree); 953 } 954 955 /* Insert a filter node with filter set "filter" 956 * in each of the children of "tree". 957 */ 958 __isl_give isl_schedule_tree *isl_schedule_tree_children_insert_filter( 959 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter) 960 { 961 int i; 962 isl_size n; 963 964 n = isl_schedule_tree_n_children(tree); 965 if (n < 0 || !filter) 966 goto error; 967 968 for (i = 0; i < n; ++i) { 969 isl_schedule_tree *child; 970 971 child = isl_schedule_tree_get_child(tree, i); 972 child = isl_schedule_tree_insert_filter(child, 973 isl_union_set_copy(filter)); 974 tree = isl_schedule_tree_replace_child(tree, i, child); 975 } 976 977 isl_union_set_free(filter); 978 return tree; 979 error: 980 isl_union_set_free(filter); 981 isl_schedule_tree_free(tree); 982 return NULL; 983 } 984 985 /* Create a new guard schedule tree with the given guard and 986 * with "tree" as single child. 987 */ 988 __isl_give isl_schedule_tree *isl_schedule_tree_insert_guard( 989 __isl_take isl_schedule_tree *tree, __isl_take isl_set *guard) 990 { 991 isl_schedule_tree *res; 992 993 res = isl_schedule_tree_from_guard(guard); 994 return isl_schedule_tree_replace_child(res, 0, tree); 995 } 996 997 /* Create a new mark schedule tree with the given mark identifier and 998 * single child. 999 */ 1000 __isl_give isl_schedule_tree *isl_schedule_tree_insert_mark( 1001 __isl_take isl_schedule_tree *tree, __isl_take isl_id *mark) 1002 { 1003 isl_schedule_tree *res; 1004 1005 res = isl_schedule_tree_from_mark(mark); 1006 return isl_schedule_tree_replace_child(res, 0, tree); 1007 } 1008 1009 /* Return the number of members in the band tree root. 1010 */ 1011 isl_size isl_schedule_tree_band_n_member(__isl_keep isl_schedule_tree *tree) 1012 { 1013 if (!tree) 1014 return isl_size_error; 1015 1016 if (tree->type != isl_schedule_node_band) 1017 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1018 "not a band node", return isl_size_error); 1019 1020 return isl_schedule_band_n_member(tree->band); 1021 } 1022 1023 /* Is the band member at position "pos" of the band tree root 1024 * marked coincident? 1025 */ 1026 isl_bool isl_schedule_tree_band_member_get_coincident( 1027 __isl_keep isl_schedule_tree *tree, int pos) 1028 { 1029 if (!tree) 1030 return isl_bool_error; 1031 1032 if (tree->type != isl_schedule_node_band) 1033 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1034 "not a band node", return isl_bool_error); 1035 1036 return isl_schedule_band_member_get_coincident(tree->band, pos); 1037 } 1038 1039 /* Mark the given band member as being coincident or not 1040 * according to "coincident". 1041 */ 1042 __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_coincident( 1043 __isl_take isl_schedule_tree *tree, int pos, int coincident) 1044 { 1045 if (!tree) 1046 return NULL; 1047 if (tree->type != isl_schedule_node_band) 1048 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1049 "not a band node", return isl_schedule_tree_free(tree)); 1050 if (isl_schedule_tree_band_member_get_coincident(tree, pos) == 1051 coincident) 1052 return tree; 1053 tree = isl_schedule_tree_cow(tree); 1054 if (!tree) 1055 return NULL; 1056 1057 tree->band = isl_schedule_band_member_set_coincident(tree->band, pos, 1058 coincident); 1059 if (!tree->band) 1060 return isl_schedule_tree_free(tree); 1061 return tree; 1062 } 1063 1064 /* Is the band tree root marked permutable? 1065 */ 1066 isl_bool isl_schedule_tree_band_get_permutable( 1067 __isl_keep isl_schedule_tree *tree) 1068 { 1069 if (!tree) 1070 return isl_bool_error; 1071 1072 if (tree->type != isl_schedule_node_band) 1073 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1074 "not a band node", return isl_bool_error); 1075 1076 return isl_schedule_band_get_permutable(tree->band); 1077 } 1078 1079 /* Mark the band tree root permutable or not according to "permutable"? 1080 */ 1081 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_permutable( 1082 __isl_take isl_schedule_tree *tree, int permutable) 1083 { 1084 if (!tree) 1085 return NULL; 1086 if (tree->type != isl_schedule_node_band) 1087 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1088 "not a band node", return isl_schedule_tree_free(tree)); 1089 if (isl_schedule_tree_band_get_permutable(tree) == permutable) 1090 return tree; 1091 tree = isl_schedule_tree_cow(tree); 1092 if (!tree) 1093 return NULL; 1094 1095 tree->band = isl_schedule_band_set_permutable(tree->band, permutable); 1096 if (!tree->band) 1097 return isl_schedule_tree_free(tree); 1098 return tree; 1099 } 1100 1101 /* Return the schedule space of the band tree root. 1102 */ 1103 __isl_give isl_space *isl_schedule_tree_band_get_space( 1104 __isl_keep isl_schedule_tree *tree) 1105 { 1106 if (!tree) 1107 return NULL; 1108 1109 if (tree->type != isl_schedule_node_band) 1110 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1111 "not a band node", return NULL); 1112 1113 return isl_schedule_band_get_space(tree->band); 1114 } 1115 1116 /* Intersect the domain of the band schedule of the band tree root 1117 * with "domain". 1118 */ 1119 __isl_give isl_schedule_tree *isl_schedule_tree_band_intersect_domain( 1120 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain) 1121 { 1122 if (!tree || !domain) 1123 goto error; 1124 1125 if (tree->type != isl_schedule_node_band) 1126 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1127 "not a band node", goto error); 1128 1129 tree->band = isl_schedule_band_intersect_domain(tree->band, domain); 1130 if (!tree->band) 1131 return isl_schedule_tree_free(tree); 1132 1133 return tree; 1134 error: 1135 isl_schedule_tree_free(tree); 1136 isl_union_set_free(domain); 1137 return NULL; 1138 } 1139 1140 /* Return the schedule of the band tree root in isolation. 1141 */ 1142 __isl_give isl_multi_union_pw_aff *isl_schedule_tree_band_get_partial_schedule( 1143 __isl_keep isl_schedule_tree *tree) 1144 { 1145 if (!tree) 1146 return NULL; 1147 1148 if (tree->type != isl_schedule_node_band) 1149 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1150 "not a band node", return NULL); 1151 1152 return isl_schedule_band_get_partial_schedule(tree->band); 1153 } 1154 1155 /* Replace the schedule of the band tree root by "schedule". 1156 */ 1157 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_partial_schedule( 1158 __isl_take isl_schedule_tree *tree, 1159 __isl_take isl_multi_union_pw_aff *schedule) 1160 { 1161 tree = isl_schedule_tree_cow(tree); 1162 if (!tree || !schedule) 1163 goto error; 1164 1165 if (tree->type != isl_schedule_node_band) 1166 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1167 "not a band node", return NULL); 1168 tree->band = isl_schedule_band_set_partial_schedule(tree->band, 1169 schedule); 1170 1171 return tree; 1172 error: 1173 isl_schedule_tree_free(tree); 1174 isl_multi_union_pw_aff_free(schedule); 1175 return NULL; 1176 } 1177 1178 /* Return the loop AST generation type for the band member 1179 * of the band tree root at position "pos". 1180 */ 1181 enum isl_ast_loop_type isl_schedule_tree_band_member_get_ast_loop_type( 1182 __isl_keep isl_schedule_tree *tree, int pos) 1183 { 1184 if (!tree) 1185 return isl_ast_loop_error; 1186 1187 if (tree->type != isl_schedule_node_band) 1188 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1189 "not a band node", return isl_ast_loop_error); 1190 1191 return isl_schedule_band_member_get_ast_loop_type(tree->band, pos); 1192 } 1193 1194 /* Set the loop AST generation type for the band member of the band tree root 1195 * at position "pos" to "type". 1196 */ 1197 __isl_give isl_schedule_tree *isl_schedule_tree_band_member_set_ast_loop_type( 1198 __isl_take isl_schedule_tree *tree, int pos, 1199 enum isl_ast_loop_type type) 1200 { 1201 tree = isl_schedule_tree_cow(tree); 1202 if (!tree) 1203 return NULL; 1204 1205 if (tree->type != isl_schedule_node_band) 1206 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1207 "not a band node", return isl_schedule_tree_free(tree)); 1208 1209 tree->band = isl_schedule_band_member_set_ast_loop_type(tree->band, 1210 pos, type); 1211 if (!tree->band) 1212 return isl_schedule_tree_free(tree); 1213 1214 return tree; 1215 } 1216 1217 /* Return the loop AST generation type for the band member 1218 * of the band tree root at position "pos" for the isolated part. 1219 */ 1220 enum isl_ast_loop_type isl_schedule_tree_band_member_get_isolate_ast_loop_type( 1221 __isl_keep isl_schedule_tree *tree, int pos) 1222 { 1223 if (!tree) 1224 return isl_ast_loop_error; 1225 1226 if (tree->type != isl_schedule_node_band) 1227 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1228 "not a band node", return isl_ast_loop_error); 1229 1230 return isl_schedule_band_member_get_isolate_ast_loop_type(tree->band, 1231 pos); 1232 } 1233 1234 /* Set the loop AST generation type for the band member of the band tree root 1235 * at position "pos" for the isolated part to "type". 1236 */ 1237 __isl_give isl_schedule_tree * 1238 isl_schedule_tree_band_member_set_isolate_ast_loop_type( 1239 __isl_take isl_schedule_tree *tree, int pos, 1240 enum isl_ast_loop_type type) 1241 { 1242 tree = isl_schedule_tree_cow(tree); 1243 if (!tree) 1244 return NULL; 1245 1246 if (tree->type != isl_schedule_node_band) 1247 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1248 "not a band node", return isl_schedule_tree_free(tree)); 1249 1250 tree->band = isl_schedule_band_member_set_isolate_ast_loop_type( 1251 tree->band, pos, type); 1252 if (!tree->band) 1253 return isl_schedule_tree_free(tree); 1254 1255 return tree; 1256 } 1257 1258 /* Return the AST build options associated to the band tree root. 1259 */ 1260 __isl_give isl_union_set *isl_schedule_tree_band_get_ast_build_options( 1261 __isl_keep isl_schedule_tree *tree) 1262 { 1263 if (!tree) 1264 return NULL; 1265 1266 if (tree->type != isl_schedule_node_band) 1267 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1268 "not a band node", return NULL); 1269 1270 return isl_schedule_band_get_ast_build_options(tree->band); 1271 } 1272 1273 /* Replace the AST build options associated to band tree root by "options". 1274 * Updated the anchored field if the anchoredness of the root node itself 1275 * changes. 1276 */ 1277 __isl_give isl_schedule_tree *isl_schedule_tree_band_set_ast_build_options( 1278 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *options) 1279 { 1280 int was_anchored; 1281 1282 tree = isl_schedule_tree_cow(tree); 1283 if (!tree || !options) 1284 goto error; 1285 1286 if (tree->type != isl_schedule_node_band) 1287 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1288 "not a band node", goto error); 1289 1290 was_anchored = isl_schedule_tree_is_anchored(tree); 1291 tree->band = isl_schedule_band_set_ast_build_options(tree->band, 1292 options); 1293 if (!tree->band) 1294 return isl_schedule_tree_free(tree); 1295 if (isl_schedule_tree_is_anchored(tree) != was_anchored) 1296 tree = isl_schedule_tree_update_anchored(tree); 1297 1298 return tree; 1299 error: 1300 isl_schedule_tree_free(tree); 1301 isl_union_set_free(options); 1302 return NULL; 1303 } 1304 1305 /* Return the "isolate" option associated to the band tree root of "tree", 1306 * which is assumed to appear at schedule depth "depth". 1307 */ 1308 __isl_give isl_set *isl_schedule_tree_band_get_ast_isolate_option( 1309 __isl_keep isl_schedule_tree *tree, int depth) 1310 { 1311 if (!tree) 1312 return NULL; 1313 1314 if (tree->type != isl_schedule_node_band) 1315 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1316 "not a band node", return NULL); 1317 1318 return isl_schedule_band_get_ast_isolate_option(tree->band, depth); 1319 } 1320 1321 /* Return the context of the context tree root. 1322 */ 1323 __isl_give isl_set *isl_schedule_tree_context_get_context( 1324 __isl_keep isl_schedule_tree *tree) 1325 { 1326 if (!tree) 1327 return NULL; 1328 1329 if (tree->type != isl_schedule_node_context) 1330 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1331 "not a context node", return NULL); 1332 1333 return isl_set_copy(tree->context); 1334 } 1335 1336 /* Return the domain of the domain tree root. 1337 */ 1338 __isl_give isl_union_set *isl_schedule_tree_domain_get_domain( 1339 __isl_keep isl_schedule_tree *tree) 1340 { 1341 if (!tree) 1342 return NULL; 1343 1344 if (tree->type != isl_schedule_node_domain) 1345 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1346 "not a domain node", return NULL); 1347 1348 return isl_union_set_copy(tree->domain); 1349 } 1350 1351 /* Replace the domain of domain tree root "tree" by "domain". 1352 */ 1353 __isl_give isl_schedule_tree *isl_schedule_tree_domain_set_domain( 1354 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *domain) 1355 { 1356 tree = isl_schedule_tree_cow(tree); 1357 if (!tree || !domain) 1358 goto error; 1359 1360 if (tree->type != isl_schedule_node_domain) 1361 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1362 "not a domain node", goto error); 1363 1364 isl_union_set_free(tree->domain); 1365 tree->domain = domain; 1366 1367 return tree; 1368 error: 1369 isl_schedule_tree_free(tree); 1370 isl_union_set_free(domain); 1371 return NULL; 1372 } 1373 1374 /* Return the contraction of the expansion tree root. 1375 */ 1376 __isl_give isl_union_pw_multi_aff *isl_schedule_tree_expansion_get_contraction( 1377 __isl_keep isl_schedule_tree *tree) 1378 { 1379 if (!tree) 1380 return NULL; 1381 1382 if (tree->type != isl_schedule_node_expansion) 1383 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1384 "not an expansion node", return NULL); 1385 1386 return isl_union_pw_multi_aff_copy(tree->contraction); 1387 } 1388 1389 /* Return the expansion of the expansion tree root. 1390 */ 1391 __isl_give isl_union_map *isl_schedule_tree_expansion_get_expansion( 1392 __isl_keep isl_schedule_tree *tree) 1393 { 1394 if (!tree) 1395 return NULL; 1396 1397 if (tree->type != isl_schedule_node_expansion) 1398 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1399 "not an expansion node", return NULL); 1400 1401 return isl_union_map_copy(tree->expansion); 1402 } 1403 1404 /* Replace the contraction and the expansion of the expansion tree root "tree" 1405 * by "contraction" and "expansion". 1406 */ 1407 __isl_give isl_schedule_tree * 1408 isl_schedule_tree_expansion_set_contraction_and_expansion( 1409 __isl_take isl_schedule_tree *tree, 1410 __isl_take isl_union_pw_multi_aff *contraction, 1411 __isl_take isl_union_map *expansion) 1412 { 1413 tree = isl_schedule_tree_cow(tree); 1414 if (!tree || !contraction || !expansion) 1415 goto error; 1416 1417 if (tree->type != isl_schedule_node_expansion) 1418 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1419 "not an expansion node", return NULL); 1420 1421 isl_union_pw_multi_aff_free(tree->contraction); 1422 tree->contraction = contraction; 1423 isl_union_map_free(tree->expansion); 1424 tree->expansion = expansion; 1425 1426 return tree; 1427 error: 1428 isl_schedule_tree_free(tree); 1429 isl_union_pw_multi_aff_free(contraction); 1430 isl_union_map_free(expansion); 1431 return NULL; 1432 } 1433 1434 /* Return the extension of the extension tree root. 1435 */ 1436 __isl_give isl_union_map *isl_schedule_tree_extension_get_extension( 1437 __isl_take isl_schedule_tree *tree) 1438 { 1439 if (!tree) 1440 return NULL; 1441 1442 if (tree->type != isl_schedule_node_extension) 1443 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1444 "not an extension node", return NULL); 1445 1446 return isl_union_map_copy(tree->extension); 1447 } 1448 1449 /* Replace the extension of extension tree root "tree" by "extension". 1450 */ 1451 __isl_give isl_schedule_tree *isl_schedule_tree_extension_set_extension( 1452 __isl_take isl_schedule_tree *tree, __isl_take isl_union_map *extension) 1453 { 1454 tree = isl_schedule_tree_cow(tree); 1455 if (!tree || !extension) 1456 goto error; 1457 1458 if (tree->type != isl_schedule_node_extension) 1459 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1460 "not an extension node", return NULL); 1461 isl_union_map_free(tree->extension); 1462 tree->extension = extension; 1463 1464 return tree; 1465 error: 1466 isl_schedule_tree_free(tree); 1467 isl_union_map_free(extension); 1468 return NULL; 1469 } 1470 1471 /* Return the filter of the filter tree root. 1472 */ 1473 __isl_give isl_union_set *isl_schedule_tree_filter_get_filter( 1474 __isl_keep isl_schedule_tree *tree) 1475 { 1476 if (!tree) 1477 return NULL; 1478 1479 if (tree->type != isl_schedule_node_filter) 1480 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1481 "not a filter node", return NULL); 1482 1483 return isl_union_set_copy(tree->filter); 1484 } 1485 1486 /* Replace the filter of the filter tree root by "filter". 1487 */ 1488 __isl_give isl_schedule_tree *isl_schedule_tree_filter_set_filter( 1489 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *filter) 1490 { 1491 tree = isl_schedule_tree_cow(tree); 1492 if (!tree || !filter) 1493 goto error; 1494 1495 if (tree->type != isl_schedule_node_filter) 1496 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1497 "not a filter node", return NULL); 1498 1499 isl_union_set_free(tree->filter); 1500 tree->filter = filter; 1501 1502 return tree; 1503 error: 1504 isl_schedule_tree_free(tree); 1505 isl_union_set_free(filter); 1506 return NULL; 1507 } 1508 1509 /* Return the guard of the guard tree root. 1510 */ 1511 __isl_give isl_set *isl_schedule_tree_guard_get_guard( 1512 __isl_take isl_schedule_tree *tree) 1513 { 1514 if (!tree) 1515 return NULL; 1516 1517 if (tree->type != isl_schedule_node_guard) 1518 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1519 "not a guard node", return NULL); 1520 1521 return isl_set_copy(tree->guard); 1522 } 1523 1524 /* Return the mark identifier of the mark tree root "tree". 1525 */ 1526 __isl_give isl_id *isl_schedule_tree_mark_get_id( 1527 __isl_keep isl_schedule_tree *tree) 1528 { 1529 if (!tree) 1530 return NULL; 1531 1532 if (tree->type != isl_schedule_node_mark) 1533 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1534 "not a mark node", return NULL); 1535 1536 return isl_id_copy(tree->mark); 1537 } 1538 1539 /* Set dim to the range dimension of "map" and abort the search. 1540 */ 1541 static isl_stat set_range_dim(__isl_take isl_map *map, void *user) 1542 { 1543 isl_size *dim = user; 1544 1545 *dim = isl_map_dim(map, isl_dim_out); 1546 isl_map_free(map); 1547 1548 return isl_stat_error; 1549 } 1550 1551 /* Return the dimension of the range of "umap". 1552 * "umap" is assumed not to be empty and 1553 * all maps inside "umap" are assumed to have the same range. 1554 * 1555 * We extract the range dimension from the first map in "umap". 1556 */ 1557 static isl_size range_dim(__isl_keep isl_union_map *umap) 1558 { 1559 isl_size dim = isl_size_error; 1560 isl_size n; 1561 1562 n = isl_union_map_n_map(umap); 1563 if (n < 0) 1564 return isl_size_error; 1565 if (n == 0) 1566 isl_die(isl_union_map_get_ctx(umap), isl_error_internal, 1567 "unexpected empty input", return isl_size_error); 1568 1569 isl_union_map_foreach_map(umap, &set_range_dim, &dim); 1570 1571 return dim; 1572 } 1573 1574 /* Append an "extra" number of zeros to the range of "umap" and 1575 * return the result. 1576 */ 1577 static __isl_give isl_union_map *append_range(__isl_take isl_union_map *umap, 1578 int extra) 1579 { 1580 isl_union_set *dom; 1581 isl_space *space; 1582 isl_multi_val *mv; 1583 isl_union_pw_multi_aff *suffix; 1584 isl_union_map *universe; 1585 isl_union_map *suffix_umap; 1586 1587 universe = isl_union_map_universe(isl_union_map_copy(umap)); 1588 dom = isl_union_map_domain(universe); 1589 space = isl_union_set_get_space(dom); 1590 space = isl_space_set_from_params(space); 1591 space = isl_space_add_dims(space, isl_dim_set, extra); 1592 mv = isl_multi_val_zero(space); 1593 1594 suffix = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv); 1595 suffix_umap = isl_union_map_from_union_pw_multi_aff(suffix); 1596 umap = isl_union_map_flat_range_product(umap, suffix_umap); 1597 1598 return umap; 1599 } 1600 1601 /* Should we skip the root of "tree" while looking for the first 1602 * descendant with schedule information? 1603 * That is, is it impossible to derive any information about 1604 * the iteration domain from this node? 1605 * 1606 * We do not want to skip leaf or error nodes because there is 1607 * no point in looking any deeper from these nodes. 1608 * We can only extract partial iteration domain information 1609 * from an extension node, but extension nodes are not supported 1610 * by the caller and it will error out on them. 1611 */ 1612 static isl_bool domain_less(__isl_keep isl_schedule_tree *tree) 1613 { 1614 enum isl_schedule_node_type type; 1615 isl_size n; 1616 1617 type = isl_schedule_tree_get_type(tree); 1618 switch (type) { 1619 case isl_schedule_node_band: 1620 n = isl_schedule_tree_band_n_member(tree); 1621 return n < 0 ? isl_bool_error : isl_bool_ok(n == 0); 1622 case isl_schedule_node_context: 1623 case isl_schedule_node_guard: 1624 case isl_schedule_node_mark: 1625 return isl_bool_true; 1626 case isl_schedule_node_leaf: 1627 case isl_schedule_node_error: 1628 case isl_schedule_node_domain: 1629 case isl_schedule_node_expansion: 1630 case isl_schedule_node_extension: 1631 case isl_schedule_node_filter: 1632 case isl_schedule_node_set: 1633 case isl_schedule_node_sequence: 1634 return isl_bool_false; 1635 } 1636 1637 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, 1638 "unhandled case", return isl_bool_error); 1639 } 1640 1641 /* Move down to the first descendant of "tree" that contains any schedule 1642 * information or return "leaf" if there is no such descendant. 1643 */ 1644 __isl_give isl_schedule_tree *isl_schedule_tree_first_schedule_descendant( 1645 __isl_take isl_schedule_tree *tree, __isl_keep isl_schedule_tree *leaf) 1646 { 1647 isl_bool down; 1648 1649 while ((down = domain_less(tree)) == isl_bool_true) { 1650 if (!isl_schedule_tree_has_children(tree)) { 1651 isl_schedule_tree_free(tree); 1652 return isl_schedule_tree_copy(leaf); 1653 } 1654 tree = isl_schedule_tree_child(tree, 0); 1655 } 1656 1657 if (down < 0) 1658 return isl_schedule_tree_free(tree); 1659 1660 return tree; 1661 } 1662 1663 static __isl_give isl_union_map *subtree_schedule_extend( 1664 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer); 1665 1666 /* Extend the schedule map "outer" with the subtree schedule 1667 * of the (single) child of "tree", if any. 1668 * 1669 * If "tree" does not have any descendants (apart from those that 1670 * do not carry any schedule information), then we simply return "outer". 1671 * Otherwise, we extend the schedule map "outer" with the subtree schedule 1672 * of the single child. 1673 */ 1674 static __isl_give isl_union_map *subtree_schedule_extend_child( 1675 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer) 1676 { 1677 isl_schedule_tree *child; 1678 isl_union_map *res; 1679 1680 if (!tree) 1681 return isl_union_map_free(outer); 1682 if (!isl_schedule_tree_has_children(tree)) 1683 return outer; 1684 child = isl_schedule_tree_get_child(tree, 0); 1685 if (!child) 1686 return isl_union_map_free(outer); 1687 res = subtree_schedule_extend(child, outer); 1688 isl_schedule_tree_free(child); 1689 return res; 1690 } 1691 1692 /* Extract the parameter space from one of the children of "tree", 1693 * which are assumed to be filters. 1694 */ 1695 static __isl_give isl_space *extract_space_from_filter_child( 1696 __isl_keep isl_schedule_tree *tree) 1697 { 1698 isl_space *space; 1699 isl_union_set *dom; 1700 isl_schedule_tree *child; 1701 1702 child = isl_schedule_tree_list_get_schedule_tree(tree->children, 0); 1703 dom = isl_schedule_tree_filter_get_filter(child); 1704 space = isl_union_set_get_space(dom); 1705 isl_union_set_free(dom); 1706 isl_schedule_tree_free(child); 1707 1708 return space; 1709 } 1710 1711 /* Extend the schedule map "outer" with the subtree schedule 1712 * of a set or sequence node. 1713 * 1714 * The schedule for the set or sequence node itself is composed of 1715 * pieces of the form 1716 * 1717 * filter -> [] 1718 * 1719 * or 1720 * 1721 * filter -> [index] 1722 * 1723 * The first form is used if there is only a single child or 1724 * if the current node is a set node and the schedule_separate_components 1725 * option is not set. 1726 * 1727 * Each of the pieces above is extended with the subtree schedule of 1728 * the child of the corresponding filter, if any, padded with zeros 1729 * to ensure that all pieces have the same range dimension. 1730 */ 1731 static __isl_give isl_union_map *subtree_schedule_extend_from_children( 1732 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer) 1733 { 1734 int i; 1735 isl_size n; 1736 isl_size dim; 1737 int separate; 1738 isl_ctx *ctx; 1739 isl_val *v = NULL; 1740 isl_multi_val *mv; 1741 isl_space *space; 1742 isl_union_map *umap; 1743 1744 n = isl_schedule_tree_n_children(tree); 1745 if (n < 0) 1746 return isl_union_map_free(outer); 1747 if (n == 0) 1748 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, 1749 "missing children", return isl_union_map_free(outer)); 1750 1751 ctx = isl_schedule_tree_get_ctx(tree); 1752 separate = n > 1 && (tree->type == isl_schedule_node_sequence || 1753 isl_options_get_schedule_separate_components(ctx)); 1754 1755 space = isl_space_params_alloc(ctx, 0); 1756 1757 umap = isl_union_map_empty(isl_space_copy(space)); 1758 space = isl_space_set_from_params(space); 1759 if (separate) { 1760 space = isl_space_add_dims(space, isl_dim_set, 1); 1761 v = isl_val_zero(ctx); 1762 } 1763 mv = isl_multi_val_zero(space); 1764 1765 dim = isl_multi_val_dim(mv, isl_dim_set); 1766 if (dim < 0) 1767 umap = isl_union_map_free(umap); 1768 for (i = 0; i < n; ++i) { 1769 isl_multi_val *mv_copy; 1770 isl_union_pw_multi_aff *upma; 1771 isl_union_map *umap_i; 1772 isl_union_set *dom; 1773 isl_schedule_tree *child; 1774 isl_size dim_i; 1775 isl_bool empty; 1776 1777 child = isl_schedule_tree_list_get_schedule_tree( 1778 tree->children, i); 1779 dom = isl_schedule_tree_filter_get_filter(child); 1780 1781 if (separate) { 1782 mv = isl_multi_val_set_val(mv, 0, isl_val_copy(v)); 1783 v = isl_val_add_ui(v, 1); 1784 } 1785 mv_copy = isl_multi_val_copy(mv); 1786 space = isl_union_set_get_space(dom); 1787 mv_copy = isl_multi_val_align_params(mv_copy, space); 1788 upma = isl_union_pw_multi_aff_multi_val_on_domain(dom, mv_copy); 1789 umap_i = isl_union_map_from_union_pw_multi_aff(upma); 1790 umap_i = isl_union_map_flat_range_product( 1791 isl_union_map_copy(outer), umap_i); 1792 umap_i = subtree_schedule_extend_child(child, umap_i); 1793 isl_schedule_tree_free(child); 1794 1795 empty = isl_union_map_is_empty(umap_i); 1796 if (empty < 0) 1797 umap_i = isl_union_map_free(umap_i); 1798 else if (empty) { 1799 isl_union_map_free(umap_i); 1800 continue; 1801 } 1802 1803 dim_i = range_dim(umap_i); 1804 if (dim_i < 0) { 1805 umap = isl_union_map_free(umap); 1806 } else if (dim < dim_i) { 1807 umap = append_range(umap, dim_i - dim); 1808 dim = dim_i; 1809 } else if (dim_i < dim) { 1810 umap_i = append_range(umap_i, dim - dim_i); 1811 } 1812 umap = isl_union_map_union(umap, umap_i); 1813 } 1814 1815 isl_val_free(v); 1816 isl_multi_val_free(mv); 1817 isl_union_map_free(outer); 1818 1819 return umap; 1820 } 1821 1822 /* Extend the schedule map "outer" with the subtree schedule of "tree". 1823 * 1824 * If the root of the tree is a set or a sequence, then we extend 1825 * the schedule map in subtree_schedule_extend_from_children. 1826 * Otherwise, we extend the schedule map with the partial schedule 1827 * corresponding to the root of the tree and then continue with 1828 * the single child of this root. 1829 * In the special case of an expansion, the schedule map is "extended" 1830 * by applying the expansion to the domain of the schedule map. 1831 */ 1832 static __isl_give isl_union_map *subtree_schedule_extend( 1833 __isl_keep isl_schedule_tree *tree, __isl_take isl_union_map *outer) 1834 { 1835 isl_multi_union_pw_aff *mupa; 1836 isl_union_map *umap; 1837 isl_union_set *domain; 1838 isl_size n; 1839 1840 if (!tree) 1841 return NULL; 1842 1843 switch (tree->type) { 1844 case isl_schedule_node_error: 1845 return isl_union_map_free(outer); 1846 case isl_schedule_node_extension: 1847 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1848 "cannot construct subtree schedule of tree " 1849 "with extension nodes", 1850 return isl_union_map_free(outer)); 1851 case isl_schedule_node_context: 1852 case isl_schedule_node_guard: 1853 case isl_schedule_node_mark: 1854 return subtree_schedule_extend_child(tree, outer); 1855 case isl_schedule_node_band: 1856 n = isl_schedule_tree_band_n_member(tree); 1857 if (n < 0) 1858 return isl_union_map_free(outer); 1859 if (n == 0) 1860 return subtree_schedule_extend_child(tree, outer); 1861 mupa = isl_schedule_band_get_partial_schedule(tree->band); 1862 umap = isl_union_map_from_multi_union_pw_aff(mupa); 1863 outer = isl_union_map_flat_range_product(outer, umap); 1864 umap = subtree_schedule_extend_child(tree, outer); 1865 break; 1866 case isl_schedule_node_domain: 1867 domain = isl_schedule_tree_domain_get_domain(tree); 1868 umap = isl_union_map_from_domain(domain); 1869 outer = isl_union_map_flat_range_product(outer, umap); 1870 umap = subtree_schedule_extend_child(tree, outer); 1871 break; 1872 case isl_schedule_node_expansion: 1873 umap = isl_schedule_tree_expansion_get_expansion(tree); 1874 outer = isl_union_map_apply_domain(outer, umap); 1875 umap = subtree_schedule_extend_child(tree, outer); 1876 break; 1877 case isl_schedule_node_filter: 1878 domain = isl_schedule_tree_filter_get_filter(tree); 1879 umap = isl_union_map_from_domain(domain); 1880 outer = isl_union_map_flat_range_product(outer, umap); 1881 umap = subtree_schedule_extend_child(tree, outer); 1882 break; 1883 case isl_schedule_node_leaf: 1884 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, 1885 "leaf node should be handled by caller", return NULL); 1886 case isl_schedule_node_set: 1887 case isl_schedule_node_sequence: 1888 umap = subtree_schedule_extend_from_children(tree, outer); 1889 break; 1890 } 1891 1892 return umap; 1893 } 1894 1895 static __isl_give isl_union_set *initial_domain( 1896 __isl_keep isl_schedule_tree *tree); 1897 1898 /* Extract a universe domain from the children of the tree root "tree", 1899 * which is a set or sequence, meaning that its children are filters. 1900 * In particular, return the union of the universes of the filters. 1901 */ 1902 static __isl_give isl_union_set *initial_domain_from_children( 1903 __isl_keep isl_schedule_tree *tree) 1904 { 1905 int i; 1906 isl_size n; 1907 isl_space *space; 1908 isl_union_set *domain; 1909 1910 n = isl_schedule_tree_n_children(tree); 1911 if (n < 0) 1912 return NULL; 1913 if (n == 0) 1914 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, 1915 "missing children", return NULL); 1916 1917 space = extract_space_from_filter_child(tree); 1918 domain = isl_union_set_empty(space); 1919 1920 for (i = 0; i < n; ++i) { 1921 isl_schedule_tree *child; 1922 isl_union_set *domain_i; 1923 1924 child = isl_schedule_tree_get_child(tree, i); 1925 domain_i = initial_domain(child); 1926 domain = isl_union_set_union(domain, domain_i); 1927 isl_schedule_tree_free(child); 1928 } 1929 1930 return domain; 1931 } 1932 1933 /* Extract a universe domain from the tree root "tree". 1934 * The caller is responsible for making sure that this node 1935 * would not be skipped by isl_schedule_tree_first_schedule_descendant 1936 * and that it is not a leaf node. 1937 */ 1938 static __isl_give isl_union_set *initial_domain( 1939 __isl_keep isl_schedule_tree *tree) 1940 { 1941 isl_multi_union_pw_aff *mupa; 1942 isl_union_set *domain; 1943 isl_union_map *exp; 1944 isl_size n; 1945 1946 if (!tree) 1947 return NULL; 1948 1949 switch (tree->type) { 1950 case isl_schedule_node_error: 1951 return NULL; 1952 case isl_schedule_node_context: 1953 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, 1954 "context node should be handled by caller", 1955 return NULL); 1956 case isl_schedule_node_guard: 1957 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, 1958 "guard node should be handled by caller", 1959 return NULL); 1960 case isl_schedule_node_mark: 1961 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, 1962 "mark node should be handled by caller", 1963 return NULL); 1964 case isl_schedule_node_extension: 1965 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 1966 "cannot construct subtree schedule of tree " 1967 "with extension nodes", return NULL); 1968 case isl_schedule_node_band: 1969 n = isl_schedule_tree_band_n_member(tree); 1970 if (n < 0) 1971 return NULL; 1972 if (n == 0) 1973 isl_die(isl_schedule_tree_get_ctx(tree), 1974 isl_error_internal, 1975 "0D band should be handled by caller", 1976 return NULL); 1977 mupa = isl_schedule_band_get_partial_schedule(tree->band); 1978 domain = isl_multi_union_pw_aff_domain(mupa); 1979 domain = isl_union_set_universe(domain); 1980 break; 1981 case isl_schedule_node_domain: 1982 domain = isl_schedule_tree_domain_get_domain(tree); 1983 domain = isl_union_set_universe(domain); 1984 break; 1985 case isl_schedule_node_expansion: 1986 exp = isl_schedule_tree_expansion_get_expansion(tree); 1987 exp = isl_union_map_universe(exp); 1988 domain = isl_union_map_domain(exp); 1989 break; 1990 case isl_schedule_node_filter: 1991 domain = isl_schedule_tree_filter_get_filter(tree); 1992 domain = isl_union_set_universe(domain); 1993 break; 1994 case isl_schedule_node_leaf: 1995 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, 1996 "leaf node should be handled by caller", return NULL); 1997 case isl_schedule_node_set: 1998 case isl_schedule_node_sequence: 1999 domain = initial_domain_from_children(tree); 2000 break; 2001 } 2002 2003 return domain; 2004 } 2005 2006 /* Return the subtree schedule of a node that contains some schedule 2007 * information, i.e., a node that would not be skipped by 2008 * isl_schedule_tree_first_schedule_descendant and that is not a leaf. 2009 * 2010 * If the tree contains any expansions, then the returned subtree 2011 * schedule is formulated in terms of the expanded domains. 2012 * The tree is not allowed to contain any extension nodes. 2013 * 2014 * We start with an initial zero-dimensional subtree schedule based 2015 * on the domain information in the root node and then extend it 2016 * based on the schedule information in the root node and its descendants. 2017 */ 2018 __isl_give isl_union_map *isl_schedule_tree_get_subtree_schedule_union_map( 2019 __isl_keep isl_schedule_tree *tree) 2020 { 2021 isl_union_set *domain; 2022 isl_union_map *umap; 2023 2024 domain = initial_domain(tree); 2025 umap = isl_union_map_from_domain(domain); 2026 return subtree_schedule_extend(tree, umap); 2027 } 2028 2029 /* Multiply the partial schedule of the band root node of "tree" 2030 * with the factors in "mv". 2031 */ 2032 __isl_give isl_schedule_tree *isl_schedule_tree_band_scale( 2033 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv) 2034 { 2035 if (!tree || !mv) 2036 goto error; 2037 if (tree->type != isl_schedule_node_band) 2038 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 2039 "not a band node", goto error); 2040 2041 tree = isl_schedule_tree_cow(tree); 2042 if (!tree) 2043 goto error; 2044 2045 tree->band = isl_schedule_band_scale(tree->band, mv); 2046 if (!tree->band) 2047 return isl_schedule_tree_free(tree); 2048 2049 return tree; 2050 error: 2051 isl_schedule_tree_free(tree); 2052 isl_multi_val_free(mv); 2053 return NULL; 2054 } 2055 2056 /* Divide the partial schedule of the band root node of "tree" 2057 * by the factors in "mv". 2058 */ 2059 __isl_give isl_schedule_tree *isl_schedule_tree_band_scale_down( 2060 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv) 2061 { 2062 if (!tree || !mv) 2063 goto error; 2064 if (tree->type != isl_schedule_node_band) 2065 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 2066 "not a band node", goto error); 2067 2068 tree = isl_schedule_tree_cow(tree); 2069 if (!tree) 2070 goto error; 2071 2072 tree->band = isl_schedule_band_scale_down(tree->band, mv); 2073 if (!tree->band) 2074 return isl_schedule_tree_free(tree); 2075 2076 return tree; 2077 error: 2078 isl_schedule_tree_free(tree); 2079 isl_multi_val_free(mv); 2080 return NULL; 2081 } 2082 2083 /* Reduce the partial schedule of the band root node of "tree" 2084 * modulo the factors in "mv". 2085 */ 2086 __isl_give isl_schedule_tree *isl_schedule_tree_band_mod( 2087 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *mv) 2088 { 2089 if (!tree || !mv) 2090 goto error; 2091 if (tree->type != isl_schedule_node_band) 2092 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 2093 "not a band node", goto error); 2094 2095 tree = isl_schedule_tree_cow(tree); 2096 if (!tree) 2097 goto error; 2098 2099 tree->band = isl_schedule_band_mod(tree->band, mv); 2100 if (!tree->band) 2101 return isl_schedule_tree_free(tree); 2102 2103 return tree; 2104 error: 2105 isl_schedule_tree_free(tree); 2106 isl_multi_val_free(mv); 2107 return NULL; 2108 } 2109 2110 /* Shift the partial schedule of the band root node of "tree" by "shift". 2111 */ 2112 __isl_give isl_schedule_tree *isl_schedule_tree_band_shift( 2113 __isl_take isl_schedule_tree *tree, 2114 __isl_take isl_multi_union_pw_aff *shift) 2115 { 2116 if (!tree || !shift) 2117 goto error; 2118 if (tree->type != isl_schedule_node_band) 2119 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 2120 "not a band node", goto error); 2121 2122 tree = isl_schedule_tree_cow(tree); 2123 if (!tree) 2124 goto error; 2125 2126 tree->band = isl_schedule_band_shift(tree->band, shift); 2127 if (!tree->band) 2128 return isl_schedule_tree_free(tree); 2129 2130 return tree; 2131 error: 2132 isl_schedule_tree_free(tree); 2133 isl_multi_union_pw_aff_free(shift); 2134 return NULL; 2135 } 2136 2137 /* Given two trees with sequence roots, replace the child at position 2138 * "pos" of "tree" with the children of "child". 2139 */ 2140 __isl_give isl_schedule_tree *isl_schedule_tree_sequence_splice( 2141 __isl_take isl_schedule_tree *tree, int pos, 2142 __isl_take isl_schedule_tree *child) 2143 { 2144 isl_size n; 2145 isl_schedule_tree_list *list1, *list2; 2146 2147 tree = isl_schedule_tree_cow(tree); 2148 if (!tree || !child) 2149 goto error; 2150 if (isl_schedule_tree_get_type(tree) != isl_schedule_node_sequence) 2151 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 2152 "not a sequence node", goto error); 2153 n = isl_schedule_tree_n_children(tree); 2154 if (n < 0) 2155 goto error; 2156 if (pos < 0 || pos >= n) 2157 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 2158 "position out of bounds", goto error); 2159 if (isl_schedule_tree_get_type(child) != isl_schedule_node_sequence) 2160 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 2161 "not a sequence node", goto error); 2162 2163 list1 = isl_schedule_tree_list_copy(tree->children); 2164 list1 = isl_schedule_tree_list_drop(list1, pos, n - pos); 2165 list2 = isl_schedule_tree_list_copy(tree->children); 2166 list2 = isl_schedule_tree_list_drop(list2, 0, pos + 1); 2167 list1 = isl_schedule_tree_list_concat(list1, 2168 isl_schedule_tree_list_copy(child->children)); 2169 list1 = isl_schedule_tree_list_concat(list1, list2); 2170 2171 isl_schedule_tree_free(tree); 2172 isl_schedule_tree_free(child); 2173 return isl_schedule_tree_from_children(isl_schedule_node_sequence, 2174 list1); 2175 error: 2176 isl_schedule_tree_free(tree); 2177 isl_schedule_tree_free(child); 2178 return NULL; 2179 } 2180 2181 /* Tile the band root node of "tree" with tile sizes "sizes". 2182 * 2183 * We duplicate the band node, change the schedule of one of them 2184 * to the tile schedule and the other to the point schedule and then 2185 * attach the point band as a child to the tile band. 2186 */ 2187 __isl_give isl_schedule_tree *isl_schedule_tree_band_tile( 2188 __isl_take isl_schedule_tree *tree, __isl_take isl_multi_val *sizes) 2189 { 2190 isl_schedule_tree *child = NULL; 2191 2192 if (!tree || !sizes) 2193 goto error; 2194 if (tree->type != isl_schedule_node_band) 2195 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 2196 "not a band node", goto error); 2197 2198 child = isl_schedule_tree_copy(tree); 2199 tree = isl_schedule_tree_cow(tree); 2200 child = isl_schedule_tree_cow(child); 2201 if (!tree || !child) 2202 goto error; 2203 2204 tree->band = isl_schedule_band_tile(tree->band, 2205 isl_multi_val_copy(sizes)); 2206 if (!tree->band) 2207 goto error; 2208 child->band = isl_schedule_band_point(child->band, tree->band, sizes); 2209 if (!child->band) 2210 child = isl_schedule_tree_free(child); 2211 2212 tree = isl_schedule_tree_replace_child(tree, 0, child); 2213 2214 return tree; 2215 error: 2216 isl_schedule_tree_free(child); 2217 isl_schedule_tree_free(tree); 2218 isl_multi_val_free(sizes); 2219 return NULL; 2220 } 2221 2222 /* Given an isolate AST generation option "isolate" for a band of size pos + n, 2223 * return the corresponding option for a band covering the first "pos" 2224 * members. 2225 * 2226 * The input isolate option is of the form 2227 * 2228 * isolate[[flattened outer bands] -> [pos; n]] 2229 * 2230 * The output isolate option is of the form 2231 * 2232 * isolate[[flattened outer bands] -> [pos]] 2233 */ 2234 static __isl_give isl_set *isolate_initial(__isl_keep isl_set *isolate, 2235 int pos, int n) 2236 { 2237 isl_id *id; 2238 isl_map *map; 2239 2240 isolate = isl_set_copy(isolate); 2241 id = isl_set_get_tuple_id(isolate); 2242 map = isl_set_unwrap(isolate); 2243 map = isl_map_project_out(map, isl_dim_out, pos, n); 2244 isolate = isl_map_wrap(map); 2245 isolate = isl_set_set_tuple_id(isolate, id); 2246 2247 return isolate; 2248 } 2249 2250 /* Given an isolate AST generation option "isolate" for a band of size pos + n, 2251 * return the corresponding option for a band covering the final "n" 2252 * members within a band covering the first "pos" members. 2253 * 2254 * The input isolate option is of the form 2255 * 2256 * isolate[[flattened outer bands] -> [pos; n]] 2257 * 2258 * The output isolate option is of the form 2259 * 2260 * isolate[[flattened outer bands; pos] -> [n]] 2261 * 2262 * 2263 * The range is first split into 2264 * 2265 * isolate[[flattened outer bands] -> [[pos] -> [n]]] 2266 * 2267 * and then the first pos members are moved to the domain 2268 * 2269 * isolate[[[flattened outer bands] -> [pos]] -> [n]] 2270 * 2271 * after which the domain is flattened to obtain the desired output. 2272 */ 2273 static __isl_give isl_set *isolate_final(__isl_keep isl_set *isolate, 2274 int pos, int n) 2275 { 2276 isl_id *id; 2277 isl_space *space; 2278 isl_multi_aff *ma1, *ma2; 2279 isl_map *map; 2280 2281 isolate = isl_set_copy(isolate); 2282 id = isl_set_get_tuple_id(isolate); 2283 map = isl_set_unwrap(isolate); 2284 space = isl_space_range(isl_map_get_space(map)); 2285 ma1 = isl_multi_aff_project_out_map(isl_space_copy(space), 2286 isl_dim_set, pos, n); 2287 ma2 = isl_multi_aff_project_out_map(space, isl_dim_set, 0, pos); 2288 ma1 = isl_multi_aff_range_product(ma1, ma2); 2289 map = isl_map_apply_range(map, isl_map_from_multi_aff(ma1)); 2290 map = isl_map_uncurry(map); 2291 map = isl_map_flatten_domain(map); 2292 isolate = isl_map_wrap(map); 2293 isolate = isl_set_set_tuple_id(isolate, id); 2294 2295 return isolate; 2296 } 2297 2298 /* Split the band root node of "tree" into two nested band nodes, 2299 * one with the first "pos" dimensions and 2300 * one with the remaining dimensions. 2301 * The tree is itself positioned at schedule depth "depth". 2302 * 2303 * The loop AST generation type options and the isolate option 2304 * are split over the two band nodes. 2305 */ 2306 __isl_give isl_schedule_tree *isl_schedule_tree_band_split( 2307 __isl_take isl_schedule_tree *tree, int pos, int depth) 2308 { 2309 isl_size n; 2310 isl_set *isolate, *tree_isolate, *child_isolate; 2311 isl_schedule_tree *child; 2312 2313 if (!tree) 2314 return NULL; 2315 if (tree->type != isl_schedule_node_band) 2316 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 2317 "not a band node", return isl_schedule_tree_free(tree)); 2318 2319 n = isl_schedule_tree_band_n_member(tree); 2320 if (n < 0) 2321 return isl_schedule_tree_free(tree); 2322 if (pos < 0 || pos > n) 2323 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 2324 "position out of bounds", 2325 return isl_schedule_tree_free(tree)); 2326 2327 child = isl_schedule_tree_copy(tree); 2328 tree = isl_schedule_tree_cow(tree); 2329 child = isl_schedule_tree_cow(child); 2330 if (!tree || !child) 2331 goto error; 2332 2333 isolate = isl_schedule_tree_band_get_ast_isolate_option(tree, depth); 2334 tree_isolate = isolate_initial(isolate, pos, n - pos); 2335 child_isolate = isolate_final(isolate, pos, n - pos); 2336 child->band = isl_schedule_band_drop(child->band, 0, pos); 2337 child->band = isl_schedule_band_replace_ast_build_option(child->band, 2338 isl_set_copy(isolate), child_isolate); 2339 tree->band = isl_schedule_band_drop(tree->band, pos, n - pos); 2340 tree->band = isl_schedule_band_replace_ast_build_option(tree->band, 2341 isl_set_copy(isolate), tree_isolate); 2342 isl_set_free(isolate); 2343 if (!child->band || !tree->band) 2344 goto error; 2345 2346 tree = isl_schedule_tree_replace_child(tree, 0, child); 2347 2348 return tree; 2349 error: 2350 isl_schedule_tree_free(child); 2351 isl_schedule_tree_free(tree); 2352 return NULL; 2353 } 2354 2355 /* Attach "tree2" at each of the leaves of "tree1". 2356 * 2357 * If "tree1" does not have any explicit children, then make "tree2" 2358 * its single child. Otherwise, attach "tree2" to the leaves of 2359 * each of the children of "tree1". 2360 */ 2361 __isl_give isl_schedule_tree *isl_schedule_tree_append_to_leaves( 2362 __isl_take isl_schedule_tree *tree1, 2363 __isl_take isl_schedule_tree *tree2) 2364 { 2365 int i; 2366 isl_size n; 2367 2368 n = isl_schedule_tree_n_children(tree1); 2369 if (n < 0 || !tree2) 2370 goto error; 2371 if (n == 0) { 2372 isl_schedule_tree_list *list; 2373 list = isl_schedule_tree_list_from_schedule_tree(tree2); 2374 tree1 = isl_schedule_tree_set_children(tree1, list); 2375 return tree1; 2376 } 2377 for (i = 0; i < n; ++i) { 2378 isl_schedule_tree *child; 2379 2380 child = isl_schedule_tree_get_child(tree1, i); 2381 child = isl_schedule_tree_append_to_leaves(child, 2382 isl_schedule_tree_copy(tree2)); 2383 tree1 = isl_schedule_tree_replace_child(tree1, i, child); 2384 } 2385 2386 isl_schedule_tree_free(tree2); 2387 return tree1; 2388 error: 2389 isl_schedule_tree_free(tree1); 2390 isl_schedule_tree_free(tree2); 2391 return NULL; 2392 } 2393 2394 /* Reset the user pointer on all identifiers of parameters and tuples 2395 * in the root of "tree". 2396 */ 2397 __isl_give isl_schedule_tree *isl_schedule_tree_reset_user( 2398 __isl_take isl_schedule_tree *tree) 2399 { 2400 if (isl_schedule_tree_is_leaf(tree)) 2401 return tree; 2402 2403 tree = isl_schedule_tree_cow(tree); 2404 if (!tree) 2405 return NULL; 2406 2407 switch (tree->type) { 2408 case isl_schedule_node_error: 2409 return isl_schedule_tree_free(tree); 2410 case isl_schedule_node_band: 2411 tree->band = isl_schedule_band_reset_user(tree->band); 2412 if (!tree->band) 2413 return isl_schedule_tree_free(tree); 2414 break; 2415 case isl_schedule_node_context: 2416 tree->context = isl_set_reset_user(tree->context); 2417 if (!tree->context) 2418 return isl_schedule_tree_free(tree); 2419 break; 2420 case isl_schedule_node_domain: 2421 tree->domain = isl_union_set_reset_user(tree->domain); 2422 if (!tree->domain) 2423 return isl_schedule_tree_free(tree); 2424 break; 2425 case isl_schedule_node_expansion: 2426 tree->contraction = 2427 isl_union_pw_multi_aff_reset_user(tree->contraction); 2428 tree->expansion = isl_union_map_reset_user(tree->expansion); 2429 if (!tree->contraction || !tree->expansion) 2430 return isl_schedule_tree_free(tree); 2431 break; 2432 case isl_schedule_node_extension: 2433 tree->extension = isl_union_map_reset_user(tree->extension); 2434 if (!tree->extension) 2435 return isl_schedule_tree_free(tree); 2436 break; 2437 case isl_schedule_node_filter: 2438 tree->filter = isl_union_set_reset_user(tree->filter); 2439 if (!tree->filter) 2440 return isl_schedule_tree_free(tree); 2441 break; 2442 case isl_schedule_node_guard: 2443 tree->guard = isl_set_reset_user(tree->guard); 2444 if (!tree->guard) 2445 return isl_schedule_tree_free(tree); 2446 break; 2447 case isl_schedule_node_leaf: 2448 case isl_schedule_node_mark: 2449 case isl_schedule_node_sequence: 2450 case isl_schedule_node_set: 2451 break; 2452 } 2453 2454 return tree; 2455 } 2456 2457 /* Align the parameters of the root of "tree" to those of "space". 2458 */ 2459 __isl_give isl_schedule_tree *isl_schedule_tree_align_params( 2460 __isl_take isl_schedule_tree *tree, __isl_take isl_space *space) 2461 { 2462 if (!space) 2463 goto error; 2464 2465 if (isl_schedule_tree_is_leaf(tree)) { 2466 isl_space_free(space); 2467 return tree; 2468 } 2469 2470 tree = isl_schedule_tree_cow(tree); 2471 if (!tree) 2472 goto error; 2473 2474 switch (tree->type) { 2475 case isl_schedule_node_error: 2476 goto error; 2477 case isl_schedule_node_band: 2478 tree->band = isl_schedule_band_align_params(tree->band, space); 2479 if (!tree->band) 2480 return isl_schedule_tree_free(tree); 2481 break; 2482 case isl_schedule_node_context: 2483 tree->context = isl_set_align_params(tree->context, space); 2484 if (!tree->context) 2485 return isl_schedule_tree_free(tree); 2486 break; 2487 case isl_schedule_node_domain: 2488 tree->domain = isl_union_set_align_params(tree->domain, space); 2489 if (!tree->domain) 2490 return isl_schedule_tree_free(tree); 2491 break; 2492 case isl_schedule_node_expansion: 2493 tree->contraction = 2494 isl_union_pw_multi_aff_align_params(tree->contraction, 2495 isl_space_copy(space)); 2496 tree->expansion = isl_union_map_align_params(tree->expansion, 2497 space); 2498 if (!tree->contraction || !tree->expansion) 2499 return isl_schedule_tree_free(tree); 2500 break; 2501 case isl_schedule_node_extension: 2502 tree->extension = isl_union_map_align_params(tree->extension, 2503 space); 2504 if (!tree->extension) 2505 return isl_schedule_tree_free(tree); 2506 break; 2507 case isl_schedule_node_filter: 2508 tree->filter = isl_union_set_align_params(tree->filter, space); 2509 if (!tree->filter) 2510 return isl_schedule_tree_free(tree); 2511 break; 2512 case isl_schedule_node_guard: 2513 tree->guard = isl_set_align_params(tree->guard, space); 2514 if (!tree->guard) 2515 return isl_schedule_tree_free(tree); 2516 break; 2517 case isl_schedule_node_leaf: 2518 case isl_schedule_node_mark: 2519 case isl_schedule_node_sequence: 2520 case isl_schedule_node_set: 2521 isl_space_free(space); 2522 break; 2523 } 2524 2525 return tree; 2526 error: 2527 isl_space_free(space); 2528 isl_schedule_tree_free(tree); 2529 return NULL; 2530 } 2531 2532 /* Does "tree" involve the iteration domain? 2533 * That is, does it need to be modified 2534 * by isl_schedule_tree_pullback_union_pw_multi_aff? 2535 */ 2536 static int involves_iteration_domain(__isl_keep isl_schedule_tree *tree) 2537 { 2538 if (!tree) 2539 return -1; 2540 2541 switch (tree->type) { 2542 case isl_schedule_node_error: 2543 return -1; 2544 case isl_schedule_node_band: 2545 case isl_schedule_node_domain: 2546 case isl_schedule_node_expansion: 2547 case isl_schedule_node_extension: 2548 case isl_schedule_node_filter: 2549 return 1; 2550 case isl_schedule_node_context: 2551 case isl_schedule_node_leaf: 2552 case isl_schedule_node_guard: 2553 case isl_schedule_node_mark: 2554 case isl_schedule_node_sequence: 2555 case isl_schedule_node_set: 2556 return 0; 2557 } 2558 2559 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_internal, 2560 "unhandled case", return -1); 2561 } 2562 2563 /* Compute the pullback of the root node of "tree" by the function 2564 * represented by "upma". 2565 * In other words, plug in "upma" in the iteration domains of 2566 * the root node of "tree". 2567 * We currently do not handle expansion nodes. 2568 * 2569 * We first check if the root node involves any iteration domains. 2570 * If so, we handle the specific cases. 2571 */ 2572 __isl_give isl_schedule_tree *isl_schedule_tree_pullback_union_pw_multi_aff( 2573 __isl_take isl_schedule_tree *tree, 2574 __isl_take isl_union_pw_multi_aff *upma) 2575 { 2576 int involves; 2577 2578 if (!tree || !upma) 2579 goto error; 2580 2581 involves = involves_iteration_domain(tree); 2582 if (involves < 0) 2583 goto error; 2584 if (!involves) { 2585 isl_union_pw_multi_aff_free(upma); 2586 return tree; 2587 } 2588 2589 tree = isl_schedule_tree_cow(tree); 2590 if (!tree) 2591 goto error; 2592 2593 if (tree->type == isl_schedule_node_band) { 2594 tree->band = isl_schedule_band_pullback_union_pw_multi_aff( 2595 tree->band, upma); 2596 if (!tree->band) 2597 return isl_schedule_tree_free(tree); 2598 } else if (tree->type == isl_schedule_node_domain) { 2599 tree->domain = 2600 isl_union_set_preimage_union_pw_multi_aff(tree->domain, 2601 upma); 2602 if (!tree->domain) 2603 return isl_schedule_tree_free(tree); 2604 } else if (tree->type == isl_schedule_node_expansion) { 2605 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_unsupported, 2606 "cannot pullback expansion node", goto error); 2607 } else if (tree->type == isl_schedule_node_extension) { 2608 tree->extension = 2609 isl_union_map_preimage_range_union_pw_multi_aff( 2610 tree->extension, upma); 2611 if (!tree->extension) 2612 return isl_schedule_tree_free(tree); 2613 } else if (tree->type == isl_schedule_node_filter) { 2614 tree->filter = 2615 isl_union_set_preimage_union_pw_multi_aff(tree->filter, 2616 upma); 2617 if (!tree->filter) 2618 return isl_schedule_tree_free(tree); 2619 } 2620 2621 return tree; 2622 error: 2623 isl_union_pw_multi_aff_free(upma); 2624 isl_schedule_tree_free(tree); 2625 return NULL; 2626 } 2627 2628 /* Compute the gist of the band tree root with respect to "context". 2629 */ 2630 __isl_give isl_schedule_tree *isl_schedule_tree_band_gist( 2631 __isl_take isl_schedule_tree *tree, __isl_take isl_union_set *context) 2632 { 2633 if (!tree) 2634 return NULL; 2635 if (tree->type != isl_schedule_node_band) 2636 isl_die(isl_schedule_tree_get_ctx(tree), isl_error_invalid, 2637 "not a band node", goto error); 2638 tree = isl_schedule_tree_cow(tree); 2639 if (!tree) 2640 goto error; 2641 2642 tree->band = isl_schedule_band_gist(tree->band, context); 2643 if (!tree->band) 2644 return isl_schedule_tree_free(tree); 2645 return tree; 2646 error: 2647 isl_union_set_free(context); 2648 isl_schedule_tree_free(tree); 2649 return NULL; 2650 } 2651 2652 /* Are any members in "band" marked coincident? 2653 */ 2654 static isl_bool any_coincident(__isl_keep isl_schedule_band *band) 2655 { 2656 int i; 2657 isl_size n; 2658 2659 n = isl_schedule_band_n_member(band); 2660 if (n < 0) 2661 return isl_bool_error; 2662 for (i = 0; i < n; ++i) { 2663 isl_bool coincident; 2664 2665 coincident = isl_schedule_band_member_get_coincident(band, i); 2666 if (coincident < 0 || coincident) 2667 return coincident; 2668 } 2669 2670 return isl_bool_false; 2671 } 2672 2673 /* Print the band node "band" to "p". 2674 * 2675 * The permutable and coincident properties are only printed if they 2676 * are different from the defaults. 2677 * The coincident property is always printed in YAML flow style. 2678 */ 2679 static __isl_give isl_printer *print_tree_band(__isl_take isl_printer *p, 2680 __isl_keep isl_schedule_band *band) 2681 { 2682 isl_union_set *options; 2683 isl_bool empty; 2684 isl_bool coincident; 2685 2686 p = isl_printer_print_str(p, "schedule"); 2687 p = isl_printer_yaml_next(p); 2688 p = isl_printer_print_str(p, "\""); 2689 p = isl_printer_print_multi_union_pw_aff(p, band->mupa); 2690 p = isl_printer_print_str(p, "\""); 2691 if (isl_schedule_band_get_permutable(band)) { 2692 p = isl_printer_yaml_next(p); 2693 p = isl_printer_print_str(p, "permutable"); 2694 p = isl_printer_yaml_next(p); 2695 p = isl_printer_print_int(p, 1); 2696 } 2697 coincident = any_coincident(band); 2698 if (coincident < 0) 2699 return isl_printer_free(p); 2700 if (coincident) { 2701 int i; 2702 isl_size n; 2703 int style; 2704 2705 p = isl_printer_yaml_next(p); 2706 p = isl_printer_print_str(p, "coincident"); 2707 p = isl_printer_yaml_next(p); 2708 style = isl_printer_get_yaml_style(p); 2709 p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW); 2710 p = isl_printer_yaml_start_sequence(p); 2711 n = isl_schedule_band_n_member(band); 2712 if (n < 0) 2713 return isl_printer_free(p); 2714 for (i = 0; i < n; ++i) { 2715 p = isl_printer_print_int(p, 2716 isl_schedule_band_member_get_coincident(band, i)); 2717 p = isl_printer_yaml_next(p); 2718 } 2719 p = isl_printer_yaml_end_sequence(p); 2720 p = isl_printer_set_yaml_style(p, style); 2721 } 2722 options = isl_schedule_band_get_ast_build_options(band); 2723 empty = isl_union_set_is_empty(options); 2724 if (empty < 0) 2725 p = isl_printer_free(p); 2726 if (!empty) { 2727 p = isl_printer_yaml_next(p); 2728 p = isl_printer_print_str(p, "options"); 2729 p = isl_printer_yaml_next(p); 2730 p = isl_printer_print_str(p, "\""); 2731 p = isl_printer_print_union_set(p, options); 2732 p = isl_printer_print_str(p, "\""); 2733 } 2734 isl_union_set_free(options); 2735 2736 return p; 2737 } 2738 2739 #undef BASE 2740 #define BASE str 2741 #define isl_str const char 2742 #include "print_yaml_field_templ.c" 2743 2744 #undef BASE 2745 #define BASE set 2746 #include "print_yaml_field_templ.c" 2747 2748 #undef BASE 2749 #define BASE union_set 2750 #include "print_yaml_field_templ.c" 2751 2752 #undef BASE 2753 #define BASE union_map 2754 #include "print_yaml_field_templ.c" 2755 2756 #undef BASE 2757 #define BASE union_pw_multi_aff 2758 #include "print_yaml_field_templ.c" 2759 2760 /* Print "tree" to "p". 2761 * 2762 * If "n_ancestor" is non-negative, then "child_pos" contains the child 2763 * positions of a descendant of the current node that should be marked 2764 * (by the comment "YOU ARE HERE"). In particular, if "n_ancestor" 2765 * is zero, then the current node should be marked. 2766 * The marking is only printed in YAML block format. 2767 * 2768 * Implicit leaf nodes are not printed, except if they correspond 2769 * to the node that should be marked. 2770 */ 2771 __isl_give isl_printer *isl_printer_print_schedule_tree_mark( 2772 __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree, 2773 int n_ancestor, int *child_pos) 2774 { 2775 int i; 2776 isl_size n; 2777 int sequence = 0; 2778 int block; 2779 2780 block = isl_printer_get_yaml_style(p) == ISL_YAML_STYLE_BLOCK; 2781 2782 p = isl_printer_yaml_start_mapping(p); 2783 if (n_ancestor == 0 && block) { 2784 p = isl_printer_print_str(p, "# YOU ARE HERE"); 2785 p = isl_printer_end_line(p); 2786 p = isl_printer_start_line(p); 2787 } 2788 switch (tree->type) { 2789 case isl_schedule_node_error: 2790 p = isl_printer_print_str(p, "ERROR"); 2791 p = isl_printer_yaml_next(p); 2792 break; 2793 case isl_schedule_node_leaf: 2794 p = isl_printer_print_str(p, "leaf"); 2795 p = isl_printer_yaml_next(p); 2796 break; 2797 case isl_schedule_node_sequence: 2798 p = isl_printer_print_str(p, "sequence"); 2799 p = isl_printer_yaml_next(p); 2800 sequence = 1; 2801 break; 2802 case isl_schedule_node_set: 2803 p = isl_printer_print_str(p, "set"); 2804 p = isl_printer_yaml_next(p); 2805 sequence = 1; 2806 break; 2807 case isl_schedule_node_context: 2808 p = print_yaml_field_set(p, "context", tree->context); 2809 break; 2810 case isl_schedule_node_domain: 2811 p = print_yaml_field_union_set(p, "domain", tree->domain); 2812 break; 2813 case isl_schedule_node_expansion: 2814 p = print_yaml_field_union_pw_multi_aff(p, "contraction", 2815 tree->contraction); 2816 p = print_yaml_field_union_map(p, "expansion", tree->expansion); 2817 break; 2818 case isl_schedule_node_extension: 2819 p = print_yaml_field_union_map(p, "extension", tree->extension); 2820 break; 2821 case isl_schedule_node_filter: 2822 p = print_yaml_field_union_set(p, "filter", tree->filter); 2823 break; 2824 case isl_schedule_node_guard: 2825 p = print_yaml_field_set(p, "guard", tree->guard); 2826 break; 2827 case isl_schedule_node_mark: 2828 p = print_yaml_field_str(p, "mark", 2829 isl_id_get_name(tree->mark)); 2830 break; 2831 case isl_schedule_node_band: 2832 p = print_tree_band(p, tree->band); 2833 p = isl_printer_yaml_next(p); 2834 break; 2835 } 2836 2837 n = isl_schedule_tree_n_children(tree); 2838 if (n < 0) 2839 return isl_printer_free(p); 2840 if (n == 0) { 2841 if (n_ancestor > 0 && block) { 2842 isl_schedule_tree *leaf; 2843 2844 p = isl_printer_print_str(p, "child"); 2845 p = isl_printer_yaml_next(p); 2846 leaf = isl_schedule_tree_leaf(isl_printer_get_ctx(p)); 2847 p = isl_printer_print_schedule_tree_mark(p, 2848 leaf, 0, NULL); 2849 isl_schedule_tree_free(leaf); 2850 p = isl_printer_yaml_next(p); 2851 } 2852 return isl_printer_yaml_end_mapping(p); 2853 } 2854 2855 if (sequence) { 2856 p = isl_printer_yaml_start_sequence(p); 2857 } else { 2858 p = isl_printer_print_str(p, "child"); 2859 p = isl_printer_yaml_next(p); 2860 } 2861 2862 for (i = 0; i < n; ++i) { 2863 isl_schedule_tree *t; 2864 2865 t = isl_schedule_tree_get_child(tree, i); 2866 if (n_ancestor > 0 && child_pos[0] == i) 2867 p = isl_printer_print_schedule_tree_mark(p, t, 2868 n_ancestor - 1, child_pos + 1); 2869 else 2870 p = isl_printer_print_schedule_tree_mark(p, t, 2871 -1, NULL); 2872 isl_schedule_tree_free(t); 2873 2874 p = isl_printer_yaml_next(p); 2875 } 2876 2877 if (sequence) 2878 p = isl_printer_yaml_end_sequence(p); 2879 p = isl_printer_yaml_end_mapping(p); 2880 2881 return p; 2882 } 2883 2884 /* Print "tree" to "p". 2885 */ 2886 __isl_give isl_printer *isl_printer_print_schedule_tree( 2887 __isl_take isl_printer *p, __isl_keep isl_schedule_tree *tree) 2888 { 2889 return isl_printer_print_schedule_tree_mark(p, tree, -1, NULL); 2890 } 2891 2892 void isl_schedule_tree_dump(__isl_keep isl_schedule_tree *tree) 2893 { 2894 isl_ctx *ctx; 2895 isl_printer *printer; 2896 2897 if (!tree) 2898 return; 2899 2900 ctx = isl_schedule_tree_get_ctx(tree); 2901 printer = isl_printer_to_file(ctx, stderr); 2902 printer = isl_printer_set_yaml_style(printer, ISL_YAML_STYLE_BLOCK); 2903 printer = isl_printer_print_schedule_tree(printer, tree); 2904 2905 isl_printer_free(printer); 2906 } 2907