1 #include <isl/id.h> 2 #include <isl/val.h> 3 #include <isl/schedule.h> 4 #include <isl/stream.h> 5 #include <isl_schedule_private.h> 6 #include <isl_schedule_tree.h> 7 8 /* An enumeration of the various keys that may appear in a YAML mapping 9 * of a schedule. 10 */ 11 enum isl_schedule_key { 12 isl_schedule_key_error = -1, 13 isl_schedule_key_child, 14 isl_schedule_key_coincident, 15 isl_schedule_key_context, 16 isl_schedule_key_contraction, 17 isl_schedule_key_domain, 18 isl_schedule_key_expansion, 19 isl_schedule_key_extension, 20 isl_schedule_key_filter, 21 isl_schedule_key_guard, 22 isl_schedule_key_leaf, 23 isl_schedule_key_mark, 24 isl_schedule_key_options, 25 isl_schedule_key_permutable, 26 isl_schedule_key_schedule, 27 isl_schedule_key_sequence, 28 isl_schedule_key_set, 29 isl_schedule_key_end 30 }; 31 32 /* Textual representations of the YAML keys for an isl_schedule object. 33 */ 34 static char *key_str[] = { 35 [isl_schedule_key_child] = "child", 36 [isl_schedule_key_coincident] = "coincident", 37 [isl_schedule_key_context] = "context", 38 [isl_schedule_key_contraction] = "contraction", 39 [isl_schedule_key_domain] = "domain", 40 [isl_schedule_key_expansion] = "expansion", 41 [isl_schedule_key_extension] = "extension", 42 [isl_schedule_key_filter] = "filter", 43 [isl_schedule_key_guard] = "guard", 44 [isl_schedule_key_leaf] = "leaf", 45 [isl_schedule_key_mark] = "mark", 46 [isl_schedule_key_options] = "options", 47 [isl_schedule_key_permutable] = "permutable", 48 [isl_schedule_key_schedule] = "schedule", 49 [isl_schedule_key_sequence] = "sequence", 50 [isl_schedule_key_set] = "set", 51 }; 52 53 #undef KEY 54 #define KEY enum isl_schedule_key 55 #undef KEY_ERROR 56 #define KEY_ERROR isl_schedule_key_error 57 #undef KEY_END 58 #define KEY_END isl_schedule_key_end 59 #undef KEY_STR 60 #define KEY_STR key_str 61 #undef KEY_EXTRACT 62 #define KEY_EXTRACT extract_key 63 #undef KEY_GET 64 #define KEY_GET get_key 65 #include "extract_key.c" 66 67 static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree( 68 __isl_keep isl_stream *s); 69 70 /* Read a subtree with context root node from "s". 71 */ 72 static __isl_give isl_schedule_tree *read_context(__isl_keep isl_stream *s) 73 { 74 isl_set *context = NULL; 75 isl_schedule_tree *tree; 76 isl_ctx *ctx; 77 struct isl_token *tok; 78 enum isl_schedule_key key; 79 char *str; 80 isl_bool more; 81 82 ctx = isl_stream_get_ctx(s); 83 84 key = get_key(s); 85 86 if (isl_stream_yaml_next(s) < 0) 87 return NULL; 88 89 tok = isl_stream_next_token(s); 90 if (!tok) { 91 isl_stream_error(s, NULL, "unexpected EOF"); 92 return NULL; 93 } 94 str = isl_token_get_str(ctx, tok); 95 context = isl_set_read_from_str(ctx, str); 96 free(str); 97 isl_token_free(tok); 98 99 more = isl_stream_yaml_next(s); 100 if (more < 0) 101 goto error; 102 if (!more) { 103 tree = isl_schedule_tree_from_context(context); 104 } else { 105 key = get_key(s); 106 if (key != isl_schedule_key_child) 107 isl_die(ctx, isl_error_invalid, "expecting child", 108 goto error); 109 if (isl_stream_yaml_next(s) < 0) 110 goto error; 111 tree = isl_stream_read_schedule_tree(s); 112 tree = isl_schedule_tree_insert_context(tree, context); 113 } 114 115 return tree; 116 error: 117 isl_set_free(context); 118 return NULL; 119 } 120 121 /* Read a subtree with domain root node from "s". 122 */ 123 static __isl_give isl_schedule_tree *read_domain(__isl_keep isl_stream *s) 124 { 125 isl_union_set *domain = NULL; 126 isl_schedule_tree *tree; 127 isl_ctx *ctx; 128 struct isl_token *tok; 129 enum isl_schedule_key key; 130 char *str; 131 isl_bool more; 132 133 ctx = isl_stream_get_ctx(s); 134 135 key = get_key(s); 136 137 if (isl_stream_yaml_next(s) < 0) 138 return NULL; 139 140 tok = isl_stream_next_token(s); 141 if (!tok) { 142 isl_stream_error(s, NULL, "unexpected EOF"); 143 return NULL; 144 } 145 str = isl_token_get_str(ctx, tok); 146 domain = isl_union_set_read_from_str(ctx, str); 147 free(str); 148 isl_token_free(tok); 149 150 more = isl_stream_yaml_next(s); 151 if (more < 0) 152 goto error; 153 if (!more) { 154 tree = isl_schedule_tree_from_domain(domain); 155 } else { 156 key = get_key(s); 157 if (key != isl_schedule_key_child) 158 isl_die(ctx, isl_error_invalid, "expecting child", 159 goto error); 160 if (isl_stream_yaml_next(s) < 0) 161 goto error; 162 tree = isl_stream_read_schedule_tree(s); 163 tree = isl_schedule_tree_insert_domain(tree, domain); 164 } 165 166 return tree; 167 error: 168 isl_union_set_free(domain); 169 return NULL; 170 } 171 172 /* Read a subtree with expansion root node from "s". 173 */ 174 static __isl_give isl_schedule_tree *read_expansion(isl_stream *s) 175 { 176 isl_ctx *ctx; 177 isl_union_pw_multi_aff *contraction = NULL; 178 isl_union_map *expansion = NULL; 179 isl_schedule_tree *tree = NULL; 180 isl_bool more; 181 182 ctx = isl_stream_get_ctx(s); 183 184 do { 185 struct isl_token *tok; 186 enum isl_schedule_key key; 187 char *str; 188 189 key = get_key(s); 190 if (isl_stream_yaml_next(s) < 0) 191 goto error; 192 193 switch (key) { 194 case isl_schedule_key_contraction: 195 isl_union_pw_multi_aff_free(contraction); 196 tok = isl_stream_next_token(s); 197 str = isl_token_get_str(ctx, tok); 198 contraction = isl_union_pw_multi_aff_read_from_str(ctx, 199 str); 200 free(str); 201 isl_token_free(tok); 202 if (!contraction) 203 goto error; 204 break; 205 case isl_schedule_key_expansion: 206 isl_union_map_free(expansion); 207 tok = isl_stream_next_token(s); 208 str = isl_token_get_str(ctx, tok); 209 expansion = isl_union_map_read_from_str(ctx, str); 210 free(str); 211 isl_token_free(tok); 212 if (!expansion) 213 goto error; 214 break; 215 case isl_schedule_key_child: 216 isl_schedule_tree_free(tree); 217 tree = isl_stream_read_schedule_tree(s); 218 if (!tree) 219 goto error; 220 break; 221 default: 222 isl_die(ctx, isl_error_invalid, "unexpected key", 223 goto error); 224 } 225 } while ((more = isl_stream_yaml_next(s)) == isl_bool_true); 226 227 if (more < 0) 228 goto error; 229 230 if (!contraction) 231 isl_die(ctx, isl_error_invalid, "missing contraction", 232 goto error); 233 if (!expansion) 234 isl_die(ctx, isl_error_invalid, "missing expansion", 235 goto error); 236 237 if (!tree) 238 return isl_schedule_tree_from_expansion(contraction, expansion); 239 return isl_schedule_tree_insert_expansion(tree, contraction, expansion); 240 error: 241 isl_schedule_tree_free(tree); 242 isl_union_pw_multi_aff_free(contraction); 243 isl_union_map_free(expansion); 244 return NULL; 245 } 246 247 /* Read a subtree with extension root node from "s". 248 */ 249 static __isl_give isl_schedule_tree *read_extension(isl_stream *s) 250 { 251 isl_union_map *extension = NULL; 252 isl_schedule_tree *tree; 253 isl_ctx *ctx; 254 struct isl_token *tok; 255 enum isl_schedule_key key; 256 char *str; 257 isl_bool more; 258 259 ctx = isl_stream_get_ctx(s); 260 261 key = get_key(s); 262 263 if (isl_stream_yaml_next(s) < 0) 264 return NULL; 265 266 tok = isl_stream_next_token(s); 267 if (!tok) { 268 isl_stream_error(s, NULL, "unexpected EOF"); 269 return NULL; 270 } 271 str = isl_token_get_str(ctx, tok); 272 extension = isl_union_map_read_from_str(ctx, str); 273 free(str); 274 isl_token_free(tok); 275 276 more = isl_stream_yaml_next(s); 277 if (more < 0) 278 goto error; 279 if (!more) { 280 tree = isl_schedule_tree_from_extension(extension); 281 } else { 282 key = get_key(s); 283 if (key != isl_schedule_key_child) 284 isl_die(ctx, isl_error_invalid, "expecting child", 285 goto error); 286 if (isl_stream_yaml_next(s) < 0) 287 goto error; 288 tree = isl_stream_read_schedule_tree(s); 289 tree = isl_schedule_tree_insert_extension(tree, extension); 290 } 291 292 return tree; 293 error: 294 isl_union_map_free(extension); 295 return NULL; 296 } 297 298 /* Read a subtree with filter root node from "s". 299 */ 300 static __isl_give isl_schedule_tree *read_filter(__isl_keep isl_stream *s) 301 { 302 isl_union_set *filter = NULL; 303 isl_schedule_tree *tree; 304 isl_ctx *ctx; 305 struct isl_token *tok; 306 enum isl_schedule_key key; 307 char *str; 308 isl_bool more; 309 310 ctx = isl_stream_get_ctx(s); 311 312 key = get_key(s); 313 314 if (isl_stream_yaml_next(s) < 0) 315 return NULL; 316 317 tok = isl_stream_next_token(s); 318 if (!tok) { 319 isl_stream_error(s, NULL, "unexpected EOF"); 320 return NULL; 321 } 322 str = isl_token_get_str(ctx, tok); 323 filter = isl_union_set_read_from_str(ctx, str); 324 free(str); 325 isl_token_free(tok); 326 327 more = isl_stream_yaml_next(s); 328 if (more < 0) 329 goto error; 330 if (!more) { 331 tree = isl_schedule_tree_from_filter(filter); 332 } else { 333 key = get_key(s); 334 if (key != isl_schedule_key_child) 335 isl_die(ctx, isl_error_invalid, "expecting child", 336 goto error); 337 if (isl_stream_yaml_next(s) < 0) 338 goto error; 339 tree = isl_stream_read_schedule_tree(s); 340 tree = isl_schedule_tree_insert_filter(tree, filter); 341 } 342 343 return tree; 344 error: 345 isl_union_set_free(filter); 346 return NULL; 347 } 348 349 /* Read a subtree with guard root node from "s". 350 */ 351 static __isl_give isl_schedule_tree *read_guard(isl_stream *s) 352 { 353 isl_set *guard = NULL; 354 isl_schedule_tree *tree; 355 isl_ctx *ctx; 356 struct isl_token *tok; 357 enum isl_schedule_key key; 358 char *str; 359 isl_bool more; 360 361 ctx = isl_stream_get_ctx(s); 362 363 key = get_key(s); 364 365 if (isl_stream_yaml_next(s) < 0) 366 return NULL; 367 368 tok = isl_stream_next_token(s); 369 if (!tok) { 370 isl_stream_error(s, NULL, "unexpected EOF"); 371 return NULL; 372 } 373 str = isl_token_get_str(ctx, tok); 374 guard = isl_set_read_from_str(ctx, str); 375 free(str); 376 isl_token_free(tok); 377 378 more = isl_stream_yaml_next(s); 379 if (more < 0) 380 goto error; 381 if (!more) { 382 tree = isl_schedule_tree_from_guard(guard); 383 } else { 384 key = get_key(s); 385 if (key != isl_schedule_key_child) 386 isl_die(ctx, isl_error_invalid, "expecting child", 387 goto error); 388 if (isl_stream_yaml_next(s) < 0) 389 goto error; 390 tree = isl_stream_read_schedule_tree(s); 391 tree = isl_schedule_tree_insert_guard(tree, guard); 392 } 393 394 return tree; 395 error: 396 isl_set_free(guard); 397 return NULL; 398 } 399 400 /* Read a subtree with mark root node from "s". 401 */ 402 static __isl_give isl_schedule_tree *read_mark(isl_stream *s) 403 { 404 isl_id *mark; 405 isl_schedule_tree *tree; 406 isl_ctx *ctx; 407 struct isl_token *tok; 408 enum isl_schedule_key key; 409 char *str; 410 isl_bool more; 411 412 ctx = isl_stream_get_ctx(s); 413 414 key = get_key(s); 415 416 if (isl_stream_yaml_next(s) < 0) 417 return NULL; 418 419 tok = isl_stream_next_token(s); 420 if (!tok) { 421 isl_stream_error(s, NULL, "unexpected EOF"); 422 return NULL; 423 } 424 str = isl_token_get_str(ctx, tok); 425 mark = isl_id_alloc(ctx, str, NULL); 426 free(str); 427 isl_token_free(tok); 428 429 more = isl_stream_yaml_next(s); 430 if (more < 0) 431 goto error; 432 if (!more) { 433 isl_die(ctx, isl_error_invalid, "expecting child", 434 goto error); 435 } else { 436 key = get_key(s); 437 if (key != isl_schedule_key_child) 438 isl_die(ctx, isl_error_invalid, "expecting child", 439 goto error); 440 if (isl_stream_yaml_next(s) < 0) 441 goto error; 442 tree = isl_stream_read_schedule_tree(s); 443 tree = isl_schedule_tree_insert_mark(tree, mark); 444 } 445 446 return tree; 447 error: 448 isl_id_free(mark); 449 return NULL; 450 } 451 452 #undef EL_BASE 453 #define EL_BASE val 454 455 #include <isl_list_read_yaml_templ.c> 456 457 /* Read a sequence of integers from "s" (representing the coincident 458 * property of a band node). 459 */ 460 static __isl_give isl_val_list *read_coincident(__isl_keep isl_stream *s) 461 { 462 return isl_stream_yaml_read_val_list(s); 463 } 464 465 /* Set the (initial) coincident properties of "band" according to 466 * the (initial) elements of "coincident". 467 */ 468 static __isl_give isl_schedule_band *set_coincident( 469 __isl_take isl_schedule_band *band, __isl_take isl_val_list *coincident) 470 { 471 int i; 472 isl_size n, m; 473 474 n = isl_schedule_band_n_member(band); 475 m = isl_val_list_n_val(coincident); 476 if (n < 0 || m < 0) 477 band = isl_schedule_band_free(band); 478 479 for (i = 0; i < n && i < m; ++i) { 480 isl_val *v; 481 482 v = isl_val_list_get_val(coincident, i); 483 if (!v) 484 band = isl_schedule_band_free(band); 485 band = isl_schedule_band_member_set_coincident(band, i, 486 !isl_val_is_zero(v)); 487 isl_val_free(v); 488 } 489 isl_val_list_free(coincident); 490 return band; 491 } 492 493 /* Read a subtree with band root node from "s". 494 */ 495 static __isl_give isl_schedule_tree *read_band(isl_stream *s) 496 { 497 isl_multi_union_pw_aff *schedule = NULL; 498 isl_schedule_tree *tree = NULL; 499 isl_val_list *coincident = NULL; 500 isl_union_set *options = NULL; 501 isl_ctx *ctx; 502 isl_schedule_band *band; 503 int permutable = 0; 504 isl_bool more; 505 506 ctx = isl_stream_get_ctx(s); 507 508 do { 509 struct isl_token *tok; 510 enum isl_schedule_key key; 511 char *str; 512 isl_val *v; 513 514 key = get_key(s); 515 if (isl_stream_yaml_next(s) < 0) 516 goto error; 517 518 switch (key) { 519 case isl_schedule_key_schedule: 520 schedule = isl_multi_union_pw_aff_free(schedule); 521 tok = isl_stream_next_token(s); 522 if (!tok) { 523 isl_stream_error(s, NULL, "unexpected EOF"); 524 goto error; 525 } 526 str = isl_token_get_str(ctx, tok); 527 schedule = isl_multi_union_pw_aff_read_from_str(ctx, 528 str); 529 free(str); 530 isl_token_free(tok); 531 if (!schedule) 532 goto error; 533 break; 534 case isl_schedule_key_coincident: 535 coincident = read_coincident(s); 536 if (!coincident) 537 goto error; 538 break; 539 case isl_schedule_key_permutable: 540 v = isl_stream_read_val(s); 541 permutable = !isl_val_is_zero(v); 542 isl_val_free(v); 543 break; 544 case isl_schedule_key_options: 545 isl_union_set_free(options); 546 tok = isl_stream_next_token(s); 547 str = isl_token_get_str(ctx, tok); 548 options = isl_union_set_read_from_str(ctx, str); 549 free(str); 550 isl_token_free(tok); 551 if (!options) 552 goto error; 553 break; 554 case isl_schedule_key_child: 555 isl_schedule_tree_free(tree); 556 tree = isl_stream_read_schedule_tree(s); 557 if (!tree) 558 goto error; 559 break; 560 default: 561 isl_die(ctx, isl_error_invalid, "unexpected key", 562 goto error); 563 } 564 } while ((more = isl_stream_yaml_next(s)) == isl_bool_true); 565 566 if (more < 0) 567 goto error; 568 569 if (!schedule) 570 isl_die(ctx, isl_error_invalid, "missing schedule", goto error); 571 572 band = isl_schedule_band_from_multi_union_pw_aff(schedule); 573 band = isl_schedule_band_set_permutable(band, permutable); 574 if (coincident) 575 band = set_coincident(band, coincident); 576 if (options) 577 band = isl_schedule_band_set_ast_build_options(band, options); 578 if (tree) 579 tree = isl_schedule_tree_insert_band(tree, band); 580 else 581 tree = isl_schedule_tree_from_band(band); 582 583 return tree; 584 error: 585 isl_val_list_free(coincident); 586 isl_union_set_free(options); 587 isl_schedule_tree_free(tree); 588 isl_multi_union_pw_aff_free(schedule); 589 return NULL; 590 } 591 592 #undef EL_BASE 593 #define EL_BASE schedule_tree 594 595 #include <isl_list_read_yaml_templ.c> 596 597 /* Read a subtree with root node of type "type" from "s". 598 * The node is represented by a sequence of children. 599 */ 600 static __isl_give isl_schedule_tree *read_children(isl_stream *s, 601 enum isl_schedule_node_type type) 602 { 603 isl_schedule_tree_list *list; 604 605 isl_token_free(isl_stream_next_token(s)); 606 607 if (isl_stream_yaml_next(s) < 0) 608 return NULL; 609 610 list = isl_stream_yaml_read_schedule_tree_list(s); 611 612 return isl_schedule_tree_from_children(type, list); 613 } 614 615 /* Read a subtree with sequence root node from "s". 616 */ 617 static __isl_give isl_schedule_tree *read_sequence(isl_stream *s) 618 { 619 return read_children(s, isl_schedule_node_sequence); 620 } 621 622 /* Read a subtree with set root node from "s". 623 */ 624 static __isl_give isl_schedule_tree *read_set(isl_stream *s) 625 { 626 return read_children(s, isl_schedule_node_set); 627 } 628 629 /* Read a schedule (sub)tree from "s". 630 * 631 * We first determine the type of the root node based on the first 632 * mapping key and then hand over to a function tailored to reading 633 * nodes of this type. 634 */ 635 static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree( 636 struct isl_stream *s) 637 { 638 enum isl_schedule_key key; 639 struct isl_token *tok; 640 isl_schedule_tree *tree = NULL; 641 isl_bool more; 642 643 if (isl_stream_yaml_read_start_mapping(s) < 0) 644 return NULL; 645 more = isl_stream_yaml_next(s); 646 if (more < 0) 647 return NULL; 648 if (!more) { 649 isl_stream_error(s, NULL, "missing key"); 650 return NULL; 651 } 652 653 tok = isl_stream_next_token(s); 654 key = extract_key(s, tok); 655 isl_stream_push_token(s, tok); 656 if (key < 0) 657 return NULL; 658 switch (key) { 659 case isl_schedule_key_context: 660 tree = read_context(s); 661 break; 662 case isl_schedule_key_domain: 663 tree = read_domain(s); 664 break; 665 case isl_schedule_key_contraction: 666 case isl_schedule_key_expansion: 667 tree = read_expansion(s); 668 break; 669 case isl_schedule_key_extension: 670 tree = read_extension(s); 671 break; 672 case isl_schedule_key_filter: 673 tree = read_filter(s); 674 break; 675 case isl_schedule_key_guard: 676 tree = read_guard(s); 677 break; 678 case isl_schedule_key_leaf: 679 isl_token_free(isl_stream_next_token(s)); 680 tree = isl_schedule_tree_leaf(isl_stream_get_ctx(s)); 681 break; 682 case isl_schedule_key_mark: 683 tree = read_mark(s); 684 break; 685 case isl_schedule_key_sequence: 686 tree = read_sequence(s); 687 break; 688 case isl_schedule_key_set: 689 tree = read_set(s); 690 break; 691 case isl_schedule_key_schedule: 692 case isl_schedule_key_coincident: 693 case isl_schedule_key_options: 694 case isl_schedule_key_permutable: 695 tree = read_band(s); 696 break; 697 case isl_schedule_key_child: 698 isl_die(isl_stream_get_ctx(s), isl_error_unsupported, 699 "cannot identify node type", return NULL); 700 case isl_schedule_key_end: 701 case isl_schedule_key_error: 702 return NULL; 703 } 704 705 if (isl_stream_yaml_read_end_mapping(s) < 0) 706 return isl_schedule_tree_free(tree); 707 708 return tree; 709 } 710 711 /* Read an isl_schedule from "s". 712 */ 713 __isl_give isl_schedule *isl_stream_read_schedule(isl_stream *s) 714 { 715 isl_ctx *ctx; 716 isl_schedule_tree *tree; 717 718 if (!s) 719 return NULL; 720 721 ctx = isl_stream_get_ctx(s); 722 tree = isl_stream_read_schedule_tree(s); 723 return isl_schedule_from_schedule_tree(ctx, tree); 724 } 725 726 /* Read an isl_schedule from "input". 727 */ 728 __isl_give isl_schedule *isl_schedule_read_from_file(isl_ctx *ctx, FILE *input) 729 { 730 struct isl_stream *s; 731 isl_schedule *schedule; 732 733 s = isl_stream_new_file(ctx, input); 734 if (!s) 735 return NULL; 736 schedule = isl_stream_read_schedule(s); 737 isl_stream_free(s); 738 739 return schedule; 740 } 741 742 #undef TYPE_BASE 743 #define TYPE_BASE schedule 744 #include "isl_read_from_str_templ.c" 745