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 */
read_context(__isl_keep isl_stream * s)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 */
read_domain(__isl_keep isl_stream * s)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 */
read_expansion(isl_stream * s)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 */
read_extension(isl_stream * s)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 */
read_filter(__isl_keep isl_stream * s)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 */
read_guard(isl_stream * s)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 */
read_mark(isl_stream * s)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 */
read_coincident(__isl_keep isl_stream * s)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 */
set_coincident(__isl_take isl_schedule_band * band,__isl_take isl_val_list * coincident)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 */
read_band(isl_stream * s)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 */
read_children(isl_stream * s,enum isl_schedule_node_type type)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 */
read_sequence(isl_stream * s)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 */
read_set(isl_stream * s)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 */
isl_stream_read_schedule_tree(struct isl_stream * s)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 */
isl_stream_read_schedule(isl_stream * s)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 */
isl_schedule_read_from_file(isl_ctx * ctx,FILE * input)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