isl_schedule_node.c: collect_filter_prefix: allow caller to initialize filter
[isl.git] / isl_schedule_read.c
blob240120dc76a8a84f658885ba7f1e5f179eb81973
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_domain,
17 isl_schedule_key_filter,
18 isl_schedule_key_leaf,
19 isl_schedule_key_options,
20 isl_schedule_key_permutable,
21 isl_schedule_key_schedule,
22 isl_schedule_key_sequence,
23 isl_schedule_key_set
26 /* Extract a mapping key from the token "tok".
27 * Return isl_schedule_key_error on error, i.e., if "tok" does not
28 * correspond to any known key.
30 static enum isl_schedule_key extract_key(__isl_keep isl_stream *s,
31 struct isl_token *tok)
33 int type;
34 char *name;
35 enum isl_schedule_key key;
36 isl_ctx *ctx;
38 ctx = isl_stream_get_ctx(s);
39 type = isl_token_get_type(tok);
40 if (type != ISL_TOKEN_IDENT && type != ISL_TOKEN_STRING) {
41 isl_stream_error(s, tok, "expecting key");
42 return isl_schedule_key_error;
44 name = isl_token_get_str(ctx, tok);
45 if (!strcmp(name, "child"))
46 key = isl_schedule_key_child;
47 else if (!strcmp(name, "coincident"))
48 key = isl_schedule_key_coincident;
49 else if (!strcmp(name, "context"))
50 key = isl_schedule_key_context;
51 else if (!strcmp(name, "domain"))
52 key = isl_schedule_key_domain;
53 else if (!strcmp(name, "filter"))
54 key = isl_schedule_key_filter;
55 else if (!strcmp(name, "leaf"))
56 key = isl_schedule_key_leaf;
57 else if (!strcmp(name, "options"))
58 key = isl_schedule_key_options;
59 else if (!strcmp(name, "schedule"))
60 key = isl_schedule_key_schedule;
61 else if (!strcmp(name, "sequence"))
62 key = isl_schedule_key_sequence;
63 else if (!strcmp(name, "set"))
64 key = isl_schedule_key_set;
65 else if (!strcmp(name, "permutable"))
66 key = isl_schedule_key_permutable;
67 else
68 isl_die(ctx, isl_error_invalid, "unknown key",
69 key = isl_schedule_key_error);
70 free(name);
71 return key;
74 /* Read a key from "s" and return the corresponding enum.
75 * Return isl_schedule_key_error on error, i.e., if the first token
76 * on the stream does not correspond to any known key.
78 static enum isl_schedule_key get_key(__isl_keep isl_stream *s)
80 struct isl_token *tok;
81 enum isl_schedule_key key;
83 tok = isl_stream_next_token(s);
84 key = extract_key(s, tok);
85 isl_token_free(tok);
87 return key;
90 static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree(
91 __isl_keep isl_stream *s);
93 /* Read a subtree with context root node from "s".
95 static __isl_give isl_schedule_tree *read_context(__isl_keep isl_stream *s)
97 isl_set *context = NULL;
98 isl_schedule_tree *tree;
99 isl_ctx *ctx;
100 struct isl_token *tok;
101 enum isl_schedule_key key;
102 char *str;
103 int more;
105 ctx = isl_stream_get_ctx(s);
107 key = get_key(s);
109 if (isl_stream_yaml_next(s) < 0)
110 return NULL;
112 tok = isl_stream_next_token(s);
113 if (!tok) {
114 isl_stream_error(s, NULL, "unexpected EOF");
115 return NULL;
117 str = isl_token_get_str(ctx, tok);
118 context = isl_set_read_from_str(ctx, str);
119 free(str);
120 isl_token_free(tok);
122 more = isl_stream_yaml_next(s);
123 if (more < 0)
124 goto error;
125 if (!more) {
126 tree = isl_schedule_tree_from_context(context);
127 } else {
128 key = get_key(s);
129 if (key != isl_schedule_key_child)
130 isl_die(ctx, isl_error_invalid, "expecting child",
131 goto error);
132 if (isl_stream_yaml_next(s) < 0)
133 goto error;
134 tree = isl_stream_read_schedule_tree(s);
135 tree = isl_schedule_tree_insert_context(tree, context);
138 return tree;
139 error:
140 isl_set_free(context);
141 return NULL;
144 /* Read a subtree with domain root node from "s".
146 static __isl_give isl_schedule_tree *read_domain(__isl_keep isl_stream *s)
148 isl_union_set *domain = NULL;
149 isl_schedule_tree *tree;
150 isl_ctx *ctx;
151 struct isl_token *tok;
152 enum isl_schedule_key key;
153 char *str;
154 int more;
156 ctx = isl_stream_get_ctx(s);
158 key = get_key(s);
160 if (isl_stream_yaml_next(s) < 0)
161 return NULL;
163 tok = isl_stream_next_token(s);
164 if (!tok) {
165 isl_stream_error(s, NULL, "unexpected EOF");
166 return NULL;
168 str = isl_token_get_str(ctx, tok);
169 domain = isl_union_set_read_from_str(ctx, str);
170 free(str);
171 isl_token_free(tok);
173 more = isl_stream_yaml_next(s);
174 if (more < 0)
175 goto error;
176 if (!more) {
177 tree = isl_schedule_tree_from_domain(domain);
178 } else {
179 key = get_key(s);
180 if (key != isl_schedule_key_child)
181 isl_die(ctx, isl_error_invalid, "expecting child",
182 goto error);
183 if (isl_stream_yaml_next(s) < 0)
184 goto error;
185 tree = isl_stream_read_schedule_tree(s);
186 tree = isl_schedule_tree_insert_domain(tree, domain);
189 return tree;
190 error:
191 isl_union_set_free(domain);
192 return NULL;
195 /* Read a subtree with filter root node from "s".
197 static __isl_give isl_schedule_tree *read_filter(__isl_keep isl_stream *s)
199 isl_union_set *filter = NULL;
200 isl_schedule_tree *tree;
201 isl_ctx *ctx;
202 struct isl_token *tok;
203 enum isl_schedule_key key;
204 char *str;
205 int more;
207 ctx = isl_stream_get_ctx(s);
209 key = get_key(s);
211 if (isl_stream_yaml_next(s) < 0)
212 return NULL;
214 tok = isl_stream_next_token(s);
215 if (!tok) {
216 isl_stream_error(s, NULL, "unexpected EOF");
217 return NULL;
219 str = isl_token_get_str(ctx, tok);
220 filter = isl_union_set_read_from_str(ctx, str);
221 free(str);
222 isl_token_free(tok);
224 more = isl_stream_yaml_next(s);
225 if (more < 0)
226 goto error;
227 if (!more) {
228 tree = isl_schedule_tree_from_filter(filter);
229 } else {
230 key = get_key(s);
231 if (key != isl_schedule_key_child)
232 isl_die(ctx, isl_error_invalid, "expecting child",
233 goto error);
234 if (isl_stream_yaml_next(s) < 0)
235 goto error;
236 tree = isl_stream_read_schedule_tree(s);
237 tree = isl_schedule_tree_insert_filter(tree, filter);
240 return tree;
241 error:
242 isl_union_set_free(filter);
243 return NULL;
246 /* Read a sequence of integers from "s" (representing the coincident
247 * property of a band node).
249 static __isl_give isl_val_list *read_coincident(__isl_keep isl_stream *s)
251 isl_ctx *ctx;
252 isl_val_list *list;
253 int more;
255 ctx = isl_stream_get_ctx(s);
257 if (isl_stream_yaml_read_start_sequence(s) < 0)
258 return NULL;
260 list = isl_val_list_alloc(ctx, 0);
261 while ((more = isl_stream_yaml_next(s)) > 0) {
262 isl_val *val;
264 val = isl_stream_read_val(s);
265 list = isl_val_list_add(list, val);
268 if (more < 0 || isl_stream_yaml_read_end_sequence(s))
269 list = isl_val_list_free(list);
271 return list;
274 /* Set the (initial) coincident properties of "band" according to
275 * the (initial) elements of "coincident".
277 static __isl_give isl_schedule_band *set_coincident(
278 __isl_take isl_schedule_band *band, __isl_take isl_val_list *coincident)
280 int i;
281 int n, m;
283 n = isl_schedule_band_n_member(band);
284 m = isl_val_list_n_val(coincident);
286 for (i = 0; i < n && i < m; ++i) {
287 isl_val *v;
289 v = isl_val_list_get_val(coincident, i);
290 if (!v)
291 band = isl_schedule_band_free(band);
292 band = isl_schedule_band_member_set_coincident(band, i,
293 !isl_val_is_zero(v));
294 isl_val_free(v);
296 isl_val_list_free(coincident);
297 return band;
300 /* Read a subtree with band root node from "s".
302 static __isl_give isl_schedule_tree *read_band(isl_stream *s)
304 isl_multi_union_pw_aff *schedule = NULL;
305 isl_schedule_tree *tree = NULL;
306 isl_val_list *coincident = NULL;
307 isl_union_set *options = NULL;
308 isl_ctx *ctx;
309 isl_schedule_band *band;
310 int permutable = 0;
311 int more;
313 ctx = isl_stream_get_ctx(s);
315 do {
316 struct isl_token *tok;
317 enum isl_schedule_key key;
318 char *str;
319 isl_val *v;
321 key = get_key(s);
322 if (isl_stream_yaml_next(s) < 0)
323 goto error;
325 switch (key) {
326 case isl_schedule_key_schedule:
327 isl_multi_union_pw_aff_free(schedule);
328 tok = isl_stream_next_token(s);
329 if (!tok) {
330 isl_stream_error(s, NULL, "unexpected EOF");
331 goto error;
333 str = isl_token_get_str(ctx, tok);
334 schedule = isl_multi_union_pw_aff_read_from_str(ctx,
335 str);
336 free(str);
337 isl_token_free(tok);
338 if (!schedule)
339 goto error;
340 break;
341 case isl_schedule_key_coincident:
342 coincident = read_coincident(s);
343 if (!coincident)
344 goto error;
345 break;
346 case isl_schedule_key_permutable:
347 v = isl_stream_read_val(s);
348 permutable = !isl_val_is_zero(v);
349 isl_val_free(v);
350 break;
351 case isl_schedule_key_options:
352 isl_union_set_free(options);
353 tok = isl_stream_next_token(s);
354 str = isl_token_get_str(ctx, tok);
355 options = isl_union_set_read_from_str(ctx, str);
356 free(str);
357 isl_token_free(tok);
358 if (!options)
359 goto error;
360 break;
361 case isl_schedule_key_child:
362 isl_schedule_tree_free(tree);
363 tree = isl_stream_read_schedule_tree(s);
364 if (!tree)
365 goto error;
366 break;
367 default:
368 isl_die(ctx, isl_error_invalid, "unexpected key",
369 goto error);
371 } while ((more = isl_stream_yaml_next(s)) > 0);
373 if (more < 0)
374 goto error;
376 if (!schedule)
377 isl_die(ctx, isl_error_invalid, "missing schedule", goto error);
379 band = isl_schedule_band_from_multi_union_pw_aff(schedule);
380 band = isl_schedule_band_set_permutable(band, permutable);
381 if (coincident)
382 band = set_coincident(band, coincident);
383 if (options)
384 band = isl_schedule_band_set_ast_build_options(band, options);
385 if (tree)
386 tree = isl_schedule_tree_insert_band(tree, band);
387 else
388 tree = isl_schedule_tree_from_band(band);
390 return tree;
391 error:
392 isl_val_list_free(coincident);
393 isl_union_set_free(options);
394 isl_schedule_tree_free(tree);
395 isl_multi_union_pw_aff_free(schedule);
396 return NULL;
399 /* Read a subtree with root node of type "type" from "s".
400 * The node is represented by a sequence of children.
402 static __isl_give isl_schedule_tree *read_children(isl_stream *s,
403 enum isl_schedule_node_type type)
405 isl_ctx *ctx;
406 isl_schedule_tree_list *list;
407 int more;
409 ctx = isl_stream_get_ctx(s);
411 isl_token_free(isl_stream_next_token(s));
413 if (isl_stream_yaml_next(s) < 0)
414 return NULL;
416 if (isl_stream_yaml_read_start_sequence(s))
417 return NULL;
419 list = isl_schedule_tree_list_alloc(ctx, 0);
420 while ((more = isl_stream_yaml_next(s)) > 0) {
421 isl_schedule_tree *tree;
423 tree = isl_stream_read_schedule_tree(s);
424 list = isl_schedule_tree_list_add(list, tree);
427 if (more < 0 || isl_stream_yaml_read_end_sequence(s))
428 list = isl_schedule_tree_list_free(list);
430 return isl_schedule_tree_from_children(type, list);
433 /* Read a subtree with sequence root node from "s".
435 static __isl_give isl_schedule_tree *read_sequence(isl_stream *s)
437 return read_children(s, isl_schedule_node_sequence);
440 /* Read a subtree with set root node from "s".
442 static __isl_give isl_schedule_tree *read_set(isl_stream *s)
444 return read_children(s, isl_schedule_node_set);
447 /* Read a schedule (sub)tree from "s".
449 * We first determine the type of the root node based on the first
450 * mapping key and then hand over to a function tailored to reading
451 * nodes of this type.
453 static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree(
454 struct isl_stream *s)
456 enum isl_schedule_key key;
457 struct isl_token *tok;
458 isl_schedule_tree *tree = NULL;
459 int more;
461 if (isl_stream_yaml_read_start_mapping(s))
462 return NULL;
463 more = isl_stream_yaml_next(s);
464 if (more < 0)
465 return NULL;
466 if (!more) {
467 isl_stream_error(s, NULL, "missing key");
468 return NULL;
471 tok = isl_stream_next_token(s);
472 key = extract_key(s, tok);
473 isl_stream_push_token(s, tok);
474 if (key < 0)
475 return NULL;
476 switch (key) {
477 case isl_schedule_key_context:
478 tree = read_context(s);
479 break;
480 case isl_schedule_key_domain:
481 tree = read_domain(s);
482 break;
483 case isl_schedule_key_filter:
484 tree = read_filter(s);
485 break;
486 case isl_schedule_key_leaf:
487 isl_token_free(isl_stream_next_token(s));
488 tree = isl_schedule_tree_leaf(isl_stream_get_ctx(s));
489 break;
490 case isl_schedule_key_sequence:
491 tree = read_sequence(s);
492 break;
493 case isl_schedule_key_set:
494 tree = read_set(s);
495 break;
496 case isl_schedule_key_schedule:
497 case isl_schedule_key_coincident:
498 case isl_schedule_key_options:
499 case isl_schedule_key_permutable:
500 tree = read_band(s);
501 break;
502 case isl_schedule_key_child:
503 isl_die(isl_stream_get_ctx(s), isl_error_unsupported,
504 "cannot identity node type", return NULL);
505 case isl_schedule_key_error:
506 return NULL;
509 if (isl_stream_yaml_read_end_mapping(s) < 0) {
510 isl_stream_error(s, NULL, "unexpected extra elements");
511 return isl_schedule_tree_free(tree);
514 return tree;
517 /* Read an isl_schedule from "s".
519 __isl_give isl_schedule *isl_stream_read_schedule(isl_stream *s)
521 isl_ctx *ctx;
522 isl_schedule_tree *tree;
524 if (!s)
525 return NULL;
527 ctx = isl_stream_get_ctx(s);
528 tree = isl_stream_read_schedule_tree(s);
529 return isl_schedule_from_schedule_tree(ctx, tree);
532 /* Read an isl_schedule from "input".
534 __isl_give isl_schedule *isl_schedule_read_from_file(isl_ctx *ctx, FILE *input)
536 struct isl_stream *s;
537 isl_schedule *schedule;
539 s = isl_stream_new_file(ctx, input);
540 if (!s)
541 return NULL;
542 schedule = isl_stream_read_schedule(s);
543 isl_stream_free(s);
545 return schedule;
548 /* Read an isl_schedule from "str".
550 __isl_give isl_schedule *isl_schedule_read_from_str(isl_ctx *ctx,
551 const char *str)
553 struct isl_stream *s;
554 isl_schedule *schedule;
556 s = isl_stream_new_str(ctx, str);
557 if (!s)
558 return NULL;
559 schedule = isl_stream_read_schedule(s);
560 isl_stream_free(s);
562 return schedule;