add isl_schedule_node_guard
[isl.git] / isl_schedule_read.c
blob39288d19b6584e5c82fda8a5d476e99beb03379c
1 #include <string.h>
3 #include <isl/schedule.h>
4 #include <isl/stream.h>
5 #include <isl_schedule_private.h>
6 #include <isl_schedule_tree.h>
8 /* An enumeration of the various keys that may appear in a YAML mapping
9 * of a schedule.
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_filter,
20 isl_schedule_key_guard,
21 isl_schedule_key_leaf,
22 isl_schedule_key_mark,
23 isl_schedule_key_options,
24 isl_schedule_key_permutable,
25 isl_schedule_key_schedule,
26 isl_schedule_key_sequence,
27 isl_schedule_key_set
30 /* Extract a mapping key from the token "tok".
31 * Return isl_schedule_key_error on error, i.e., if "tok" does not
32 * correspond to any known key.
34 static enum isl_schedule_key extract_key(__isl_keep isl_stream *s,
35 struct isl_token *tok)
37 int type;
38 char *name;
39 enum isl_schedule_key key;
40 isl_ctx *ctx;
42 ctx = isl_stream_get_ctx(s);
43 type = isl_token_get_type(tok);
44 if (type != ISL_TOKEN_IDENT && type != ISL_TOKEN_STRING) {
45 isl_stream_error(s, tok, "expecting key");
46 return isl_schedule_key_error;
48 name = isl_token_get_str(ctx, tok);
49 if (!strcmp(name, "child"))
50 key = isl_schedule_key_child;
51 else if (!strcmp(name, "coincident"))
52 key = isl_schedule_key_coincident;
53 else if (!strcmp(name, "context"))
54 key = isl_schedule_key_context;
55 else if (!strcmp(name, "contraction"))
56 key = isl_schedule_key_contraction;
57 else if (!strcmp(name, "domain"))
58 key = isl_schedule_key_domain;
59 else if (!strcmp(name, "expansion"))
60 key = isl_schedule_key_expansion;
61 else if (!strcmp(name, "filter"))
62 key = isl_schedule_key_filter;
63 else if (!strcmp(name, "guard"))
64 key = isl_schedule_key_guard;
65 else if (!strcmp(name, "leaf"))
66 key = isl_schedule_key_leaf;
67 else if (!strcmp(name, "mark"))
68 key = isl_schedule_key_mark;
69 else if (!strcmp(name, "options"))
70 key = isl_schedule_key_options;
71 else if (!strcmp(name, "schedule"))
72 key = isl_schedule_key_schedule;
73 else if (!strcmp(name, "sequence"))
74 key = isl_schedule_key_sequence;
75 else if (!strcmp(name, "set"))
76 key = isl_schedule_key_set;
77 else if (!strcmp(name, "permutable"))
78 key = isl_schedule_key_permutable;
79 else
80 isl_die(ctx, isl_error_invalid, "unknown key",
81 key = isl_schedule_key_error);
82 free(name);
83 return key;
86 /* Read a key from "s" and return the corresponding enum.
87 * Return isl_schedule_key_error on error, i.e., if the first token
88 * on the stream does not correspond to any known key.
90 static enum isl_schedule_key get_key(__isl_keep isl_stream *s)
92 struct isl_token *tok;
93 enum isl_schedule_key key;
95 tok = isl_stream_next_token(s);
96 key = extract_key(s, tok);
97 isl_token_free(tok);
99 return key;
102 static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree(
103 __isl_keep isl_stream *s);
105 /* Read a subtree with context root node from "s".
107 static __isl_give isl_schedule_tree *read_context(__isl_keep isl_stream *s)
109 isl_set *context = NULL;
110 isl_schedule_tree *tree;
111 isl_ctx *ctx;
112 struct isl_token *tok;
113 enum isl_schedule_key key;
114 char *str;
115 int more;
117 ctx = isl_stream_get_ctx(s);
119 key = get_key(s);
121 if (isl_stream_yaml_next(s) < 0)
122 return NULL;
124 tok = isl_stream_next_token(s);
125 if (!tok) {
126 isl_stream_error(s, NULL, "unexpected EOF");
127 return NULL;
129 str = isl_token_get_str(ctx, tok);
130 context = isl_set_read_from_str(ctx, str);
131 free(str);
132 isl_token_free(tok);
134 more = isl_stream_yaml_next(s);
135 if (more < 0)
136 goto error;
137 if (!more) {
138 tree = isl_schedule_tree_from_context(context);
139 } else {
140 key = get_key(s);
141 if (key != isl_schedule_key_child)
142 isl_die(ctx, isl_error_invalid, "expecting child",
143 goto error);
144 if (isl_stream_yaml_next(s) < 0)
145 goto error;
146 tree = isl_stream_read_schedule_tree(s);
147 tree = isl_schedule_tree_insert_context(tree, context);
150 return tree;
151 error:
152 isl_set_free(context);
153 return NULL;
156 /* Read a subtree with domain root node from "s".
158 static __isl_give isl_schedule_tree *read_domain(__isl_keep isl_stream *s)
160 isl_union_set *domain = NULL;
161 isl_schedule_tree *tree;
162 isl_ctx *ctx;
163 struct isl_token *tok;
164 enum isl_schedule_key key;
165 char *str;
166 int more;
168 ctx = isl_stream_get_ctx(s);
170 key = get_key(s);
172 if (isl_stream_yaml_next(s) < 0)
173 return NULL;
175 tok = isl_stream_next_token(s);
176 if (!tok) {
177 isl_stream_error(s, NULL, "unexpected EOF");
178 return NULL;
180 str = isl_token_get_str(ctx, tok);
181 domain = isl_union_set_read_from_str(ctx, str);
182 free(str);
183 isl_token_free(tok);
185 more = isl_stream_yaml_next(s);
186 if (more < 0)
187 goto error;
188 if (!more) {
189 tree = isl_schedule_tree_from_domain(domain);
190 } else {
191 key = get_key(s);
192 if (key != isl_schedule_key_child)
193 isl_die(ctx, isl_error_invalid, "expecting child",
194 goto error);
195 if (isl_stream_yaml_next(s) < 0)
196 goto error;
197 tree = isl_stream_read_schedule_tree(s);
198 tree = isl_schedule_tree_insert_domain(tree, domain);
201 return tree;
202 error:
203 isl_union_set_free(domain);
204 return NULL;
207 /* Read a subtree with expansion root node from "s".
209 static __isl_give isl_schedule_tree *read_expansion(isl_stream *s)
211 isl_ctx *ctx;
212 isl_union_pw_multi_aff *contraction = NULL;
213 isl_union_map *expansion = NULL;
214 isl_schedule_tree *tree = NULL;
215 int more;
217 ctx = isl_stream_get_ctx(s);
219 do {
220 struct isl_token *tok;
221 enum isl_schedule_key key;
222 char *str;
224 key = get_key(s);
225 if (isl_stream_yaml_next(s) < 0)
226 goto error;
228 switch (key) {
229 case isl_schedule_key_contraction:
230 isl_union_pw_multi_aff_free(contraction);
231 tok = isl_stream_next_token(s);
232 str = isl_token_get_str(ctx, tok);
233 contraction = isl_union_pw_multi_aff_read_from_str(ctx,
234 str);
235 free(str);
236 isl_token_free(tok);
237 if (!contraction)
238 goto error;
239 break;
240 case isl_schedule_key_expansion:
241 isl_union_map_free(expansion);
242 tok = isl_stream_next_token(s);
243 str = isl_token_get_str(ctx, tok);
244 expansion = isl_union_map_read_from_str(ctx, str);
245 free(str);
246 isl_token_free(tok);
247 if (!expansion)
248 goto error;
249 break;
250 case isl_schedule_key_child:
251 isl_schedule_tree_free(tree);
252 tree = isl_stream_read_schedule_tree(s);
253 if (!tree)
254 goto error;
255 break;
256 default:
257 isl_die(ctx, isl_error_invalid, "unexpected key",
258 goto error);
260 } while ((more = isl_stream_yaml_next(s)) > 0);
262 if (more < 0)
263 goto error;
265 if (!contraction)
266 isl_die(ctx, isl_error_invalid, "missing contraction",
267 goto error);
268 if (!expansion)
269 isl_die(ctx, isl_error_invalid, "missing expansion",
270 goto error);
272 if (!tree)
273 return isl_schedule_tree_from_expansion(contraction, expansion);
274 return isl_schedule_tree_insert_expansion(tree, contraction, expansion);
275 error:
276 isl_schedule_tree_free(tree);
277 isl_union_pw_multi_aff_free(contraction);
278 isl_union_map_free(expansion);
279 return NULL;
282 /* Read a subtree with filter root node from "s".
284 static __isl_give isl_schedule_tree *read_filter(__isl_keep isl_stream *s)
286 isl_union_set *filter = NULL;
287 isl_schedule_tree *tree;
288 isl_ctx *ctx;
289 struct isl_token *tok;
290 enum isl_schedule_key key;
291 char *str;
292 int more;
294 ctx = isl_stream_get_ctx(s);
296 key = get_key(s);
298 if (isl_stream_yaml_next(s) < 0)
299 return NULL;
301 tok = isl_stream_next_token(s);
302 if (!tok) {
303 isl_stream_error(s, NULL, "unexpected EOF");
304 return NULL;
306 str = isl_token_get_str(ctx, tok);
307 filter = isl_union_set_read_from_str(ctx, str);
308 free(str);
309 isl_token_free(tok);
311 more = isl_stream_yaml_next(s);
312 if (more < 0)
313 goto error;
314 if (!more) {
315 tree = isl_schedule_tree_from_filter(filter);
316 } else {
317 key = get_key(s);
318 if (key != isl_schedule_key_child)
319 isl_die(ctx, isl_error_invalid, "expecting child",
320 goto error);
321 if (isl_stream_yaml_next(s) < 0)
322 goto error;
323 tree = isl_stream_read_schedule_tree(s);
324 tree = isl_schedule_tree_insert_filter(tree, filter);
327 return tree;
328 error:
329 isl_union_set_free(filter);
330 return NULL;
333 /* Read a subtree with guard root node from "s".
335 static __isl_give isl_schedule_tree *read_guard(isl_stream *s)
337 isl_set *guard = NULL;
338 isl_schedule_tree *tree;
339 isl_ctx *ctx;
340 struct isl_token *tok;
341 enum isl_schedule_key key;
342 char *str;
343 int more;
345 ctx = isl_stream_get_ctx(s);
347 key = get_key(s);
349 if (isl_stream_yaml_next(s) < 0)
350 return NULL;
352 tok = isl_stream_next_token(s);
353 if (!tok) {
354 isl_stream_error(s, NULL, "unexpected EOF");
355 return NULL;
357 str = isl_token_get_str(ctx, tok);
358 guard = isl_set_read_from_str(ctx, str);
359 free(str);
360 isl_token_free(tok);
362 more = isl_stream_yaml_next(s);
363 if (more < 0)
364 goto error;
365 if (!more) {
366 tree = isl_schedule_tree_from_guard(guard);
367 } else {
368 key = get_key(s);
369 if (key != isl_schedule_key_child)
370 isl_die(ctx, isl_error_invalid, "expecting child",
371 goto error);
372 if (isl_stream_yaml_next(s) < 0)
373 goto error;
374 tree = isl_stream_read_schedule_tree(s);
375 tree = isl_schedule_tree_insert_guard(tree, guard);
378 return tree;
379 error:
380 isl_set_free(guard);
381 return NULL;
384 /* Read a subtree with mark root node from "s".
386 static __isl_give isl_schedule_tree *read_mark(isl_stream *s)
388 isl_id *mark;
389 isl_schedule_tree *tree;
390 isl_ctx *ctx;
391 struct isl_token *tok;
392 enum isl_schedule_key key;
393 char *str;
394 int more;
396 ctx = isl_stream_get_ctx(s);
398 key = get_key(s);
400 if (isl_stream_yaml_next(s) < 0)
401 return NULL;
403 tok = isl_stream_next_token(s);
404 if (!tok) {
405 isl_stream_error(s, NULL, "unexpected EOF");
406 return NULL;
408 str = isl_token_get_str(ctx, tok);
409 mark = isl_id_alloc(ctx, str, NULL);
410 free(str);
411 isl_token_free(tok);
413 more = isl_stream_yaml_next(s);
414 if (more < 0)
415 goto error;
416 if (!more) {
417 isl_die(ctx, isl_error_invalid, "expecting child",
418 goto error);
419 } else {
420 key = get_key(s);
421 if (key != isl_schedule_key_child)
422 isl_die(ctx, isl_error_invalid, "expecting child",
423 goto error);
424 if (isl_stream_yaml_next(s) < 0)
425 goto error;
426 tree = isl_stream_read_schedule_tree(s);
427 tree = isl_schedule_tree_insert_mark(tree, mark);
430 return tree;
431 error:
432 isl_id_free(mark);
433 return NULL;
436 /* Read a sequence of integers from "s" (representing the coincident
437 * property of a band node).
439 static __isl_give isl_val_list *read_coincident(__isl_keep isl_stream *s)
441 isl_ctx *ctx;
442 isl_val_list *list;
443 int more;
445 ctx = isl_stream_get_ctx(s);
447 if (isl_stream_yaml_read_start_sequence(s) < 0)
448 return NULL;
450 list = isl_val_list_alloc(ctx, 0);
451 while ((more = isl_stream_yaml_next(s)) > 0) {
452 isl_val *val;
454 val = isl_stream_read_val(s);
455 list = isl_val_list_add(list, val);
458 if (more < 0 || isl_stream_yaml_read_end_sequence(s))
459 list = isl_val_list_free(list);
461 return list;
464 /* Set the (initial) coincident properties of "band" according to
465 * the (initial) elements of "coincident".
467 static __isl_give isl_schedule_band *set_coincident(
468 __isl_take isl_schedule_band *band, __isl_take isl_val_list *coincident)
470 int i;
471 int n, m;
473 n = isl_schedule_band_n_member(band);
474 m = isl_val_list_n_val(coincident);
476 for (i = 0; i < n && i < m; ++i) {
477 isl_val *v;
479 v = isl_val_list_get_val(coincident, i);
480 if (!v)
481 band = isl_schedule_band_free(band);
482 band = isl_schedule_band_member_set_coincident(band, i,
483 !isl_val_is_zero(v));
484 isl_val_free(v);
486 isl_val_list_free(coincident);
487 return band;
490 /* Read a subtree with band root node from "s".
492 static __isl_give isl_schedule_tree *read_band(isl_stream *s)
494 isl_multi_union_pw_aff *schedule = NULL;
495 isl_schedule_tree *tree = NULL;
496 isl_val_list *coincident = NULL;
497 isl_union_set *options = NULL;
498 isl_ctx *ctx;
499 isl_schedule_band *band;
500 int permutable = 0;
501 int more;
503 ctx = isl_stream_get_ctx(s);
505 do {
506 struct isl_token *tok;
507 enum isl_schedule_key key;
508 char *str;
509 isl_val *v;
511 key = get_key(s);
512 if (isl_stream_yaml_next(s) < 0)
513 goto error;
515 switch (key) {
516 case isl_schedule_key_schedule:
517 isl_multi_union_pw_aff_free(schedule);
518 tok = isl_stream_next_token(s);
519 if (!tok) {
520 isl_stream_error(s, NULL, "unexpected EOF");
521 goto error;
523 str = isl_token_get_str(ctx, tok);
524 schedule = isl_multi_union_pw_aff_read_from_str(ctx,
525 str);
526 free(str);
527 isl_token_free(tok);
528 if (!schedule)
529 goto error;
530 break;
531 case isl_schedule_key_coincident:
532 coincident = read_coincident(s);
533 if (!coincident)
534 goto error;
535 break;
536 case isl_schedule_key_permutable:
537 v = isl_stream_read_val(s);
538 permutable = !isl_val_is_zero(v);
539 isl_val_free(v);
540 break;
541 case isl_schedule_key_options:
542 isl_union_set_free(options);
543 tok = isl_stream_next_token(s);
544 str = isl_token_get_str(ctx, tok);
545 options = isl_union_set_read_from_str(ctx, str);
546 free(str);
547 isl_token_free(tok);
548 if (!options)
549 goto error;
550 break;
551 case isl_schedule_key_child:
552 isl_schedule_tree_free(tree);
553 tree = isl_stream_read_schedule_tree(s);
554 if (!tree)
555 goto error;
556 break;
557 default:
558 isl_die(ctx, isl_error_invalid, "unexpected key",
559 goto error);
561 } while ((more = isl_stream_yaml_next(s)) > 0);
563 if (more < 0)
564 goto error;
566 if (!schedule)
567 isl_die(ctx, isl_error_invalid, "missing schedule", goto error);
569 band = isl_schedule_band_from_multi_union_pw_aff(schedule);
570 band = isl_schedule_band_set_permutable(band, permutable);
571 if (coincident)
572 band = set_coincident(band, coincident);
573 if (options)
574 band = isl_schedule_band_set_ast_build_options(band, options);
575 if (tree)
576 tree = isl_schedule_tree_insert_band(tree, band);
577 else
578 tree = isl_schedule_tree_from_band(band);
580 return tree;
581 error:
582 isl_val_list_free(coincident);
583 isl_union_set_free(options);
584 isl_schedule_tree_free(tree);
585 isl_multi_union_pw_aff_free(schedule);
586 return NULL;
589 /* Read a subtree with root node of type "type" from "s".
590 * The node is represented by a sequence of children.
592 static __isl_give isl_schedule_tree *read_children(isl_stream *s,
593 enum isl_schedule_node_type type)
595 isl_ctx *ctx;
596 isl_schedule_tree_list *list;
597 int more;
599 ctx = isl_stream_get_ctx(s);
601 isl_token_free(isl_stream_next_token(s));
603 if (isl_stream_yaml_next(s) < 0)
604 return NULL;
606 if (isl_stream_yaml_read_start_sequence(s))
607 return NULL;
609 list = isl_schedule_tree_list_alloc(ctx, 0);
610 while ((more = isl_stream_yaml_next(s)) > 0) {
611 isl_schedule_tree *tree;
613 tree = isl_stream_read_schedule_tree(s);
614 list = isl_schedule_tree_list_add(list, tree);
617 if (more < 0 || isl_stream_yaml_read_end_sequence(s))
618 list = isl_schedule_tree_list_free(list);
620 return isl_schedule_tree_from_children(type, list);
623 /* Read a subtree with sequence root node from "s".
625 static __isl_give isl_schedule_tree *read_sequence(isl_stream *s)
627 return read_children(s, isl_schedule_node_sequence);
630 /* Read a subtree with set root node from "s".
632 static __isl_give isl_schedule_tree *read_set(isl_stream *s)
634 return read_children(s, isl_schedule_node_set);
637 /* Read a schedule (sub)tree from "s".
639 * We first determine the type of the root node based on the first
640 * mapping key and then hand over to a function tailored to reading
641 * nodes of this type.
643 static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree(
644 struct isl_stream *s)
646 enum isl_schedule_key key;
647 struct isl_token *tok;
648 isl_schedule_tree *tree = NULL;
649 int more;
651 if (isl_stream_yaml_read_start_mapping(s))
652 return NULL;
653 more = isl_stream_yaml_next(s);
654 if (more < 0)
655 return NULL;
656 if (!more) {
657 isl_stream_error(s, NULL, "missing key");
658 return NULL;
661 tok = isl_stream_next_token(s);
662 key = extract_key(s, tok);
663 isl_stream_push_token(s, tok);
664 if (key < 0)
665 return NULL;
666 switch (key) {
667 case isl_schedule_key_context:
668 tree = read_context(s);
669 break;
670 case isl_schedule_key_domain:
671 tree = read_domain(s);
672 break;
673 case isl_schedule_key_contraction:
674 case isl_schedule_key_expansion:
675 tree = read_expansion(s);
676 break;
677 case isl_schedule_key_filter:
678 tree = read_filter(s);
679 break;
680 case isl_schedule_key_guard:
681 tree = read_guard(s);
682 break;
683 case isl_schedule_key_leaf:
684 isl_token_free(isl_stream_next_token(s));
685 tree = isl_schedule_tree_leaf(isl_stream_get_ctx(s));
686 break;
687 case isl_schedule_key_mark:
688 tree = read_mark(s);
689 break;
690 case isl_schedule_key_sequence:
691 tree = read_sequence(s);
692 break;
693 case isl_schedule_key_set:
694 tree = read_set(s);
695 break;
696 case isl_schedule_key_schedule:
697 case isl_schedule_key_coincident:
698 case isl_schedule_key_options:
699 case isl_schedule_key_permutable:
700 tree = read_band(s);
701 break;
702 case isl_schedule_key_child:
703 isl_die(isl_stream_get_ctx(s), isl_error_unsupported,
704 "cannot identity node type", return NULL);
705 case isl_schedule_key_error:
706 return NULL;
709 if (isl_stream_yaml_read_end_mapping(s) < 0) {
710 isl_stream_error(s, NULL, "unexpected extra elements");
711 return isl_schedule_tree_free(tree);
714 return tree;
717 /* Read an isl_schedule from "s".
719 __isl_give isl_schedule *isl_stream_read_schedule(isl_stream *s)
721 isl_ctx *ctx;
722 isl_schedule_tree *tree;
724 if (!s)
725 return NULL;
727 ctx = isl_stream_get_ctx(s);
728 tree = isl_stream_read_schedule_tree(s);
729 return isl_schedule_from_schedule_tree(ctx, tree);
732 /* Read an isl_schedule from "input".
734 __isl_give isl_schedule *isl_schedule_read_from_file(isl_ctx *ctx, FILE *input)
736 struct isl_stream *s;
737 isl_schedule *schedule;
739 s = isl_stream_new_file(ctx, input);
740 if (!s)
741 return NULL;
742 schedule = isl_stream_read_schedule(s);
743 isl_stream_free(s);
745 return schedule;
748 /* Read an isl_schedule from "str".
750 __isl_give isl_schedule *isl_schedule_read_from_str(isl_ctx *ctx,
751 const char *str)
753 struct isl_stream *s;
754 isl_schedule *schedule;
756 s = isl_stream_new_str(ctx, str);
757 if (!s)
758 return NULL;
759 schedule = isl_stream_read_schedule(s);
760 isl_stream_free(s);
762 return schedule;