isl_union_map_compute_flow: reuse isl_union_access_info_compute_flow
[isl.git] / isl_schedule_read.c
blob95000aeca70869ddbac7cdf72e542eecd68280a9
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_domain,
16 isl_schedule_key_filter,
17 isl_schedule_key_leaf,
18 isl_schedule_key_permutable,
19 isl_schedule_key_schedule,
20 isl_schedule_key_sequence,
21 isl_schedule_key_set
24 /* Extract a mapping key from the token "tok".
25 * Return isl_schedule_key_error on error, i.e., if "tok" does not
26 * correspond to any known key.
28 static enum isl_schedule_key extract_key(__isl_keep isl_stream *s,
29 struct isl_token *tok)
31 int type;
32 char *name;
33 enum isl_schedule_key key;
34 isl_ctx *ctx;
36 ctx = isl_stream_get_ctx(s);
37 type = isl_token_get_type(tok);
38 if (type != ISL_TOKEN_IDENT && type != ISL_TOKEN_STRING) {
39 isl_stream_error(s, tok, "expecting key");
40 return isl_schedule_key_error;
42 name = isl_token_get_str(ctx, tok);
43 if (!strcmp(name, "child"))
44 key = isl_schedule_key_child;
45 else if (!strcmp(name, "coincident"))
46 key = isl_schedule_key_coincident;
47 else if (!strcmp(name, "domain"))
48 key = isl_schedule_key_domain;
49 else if (!strcmp(name, "filter"))
50 key = isl_schedule_key_filter;
51 else if (!strcmp(name, "leaf"))
52 key = isl_schedule_key_leaf;
53 else if (!strcmp(name, "schedule"))
54 key = isl_schedule_key_schedule;
55 else if (!strcmp(name, "sequence"))
56 key = isl_schedule_key_sequence;
57 else if (!strcmp(name, "set"))
58 key = isl_schedule_key_set;
59 else if (!strcmp(name, "permutable"))
60 key = isl_schedule_key_permutable;
61 else
62 isl_die(ctx, isl_error_invalid, "unknown key",
63 key = isl_schedule_key_error);
64 free(name);
65 return key;
68 /* Read a key from "s" and return the corresponding enum.
69 * Return isl_schedule_key_error on error, i.e., if the first token
70 * on the stream does not correspond to any known key.
72 static enum isl_schedule_key get_key(__isl_keep isl_stream *s)
74 struct isl_token *tok;
75 enum isl_schedule_key key;
77 tok = isl_stream_next_token(s);
78 key = extract_key(s, tok);
79 isl_token_free(tok);
81 return key;
84 static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree(
85 __isl_keep isl_stream *s);
87 /* Read a subtree with domain root node from "s".
89 static __isl_give isl_schedule_tree *read_domain(__isl_keep isl_stream *s)
91 isl_union_set *domain = NULL;
92 isl_schedule_tree *tree;
93 isl_ctx *ctx;
94 struct isl_token *tok;
95 enum isl_schedule_key key;
96 char *str;
97 int more;
99 ctx = isl_stream_get_ctx(s);
101 key = get_key(s);
103 if (isl_stream_yaml_next(s) < 0)
104 return NULL;
106 tok = isl_stream_next_token(s);
107 if (!tok) {
108 isl_stream_error(s, NULL, "unexpected EOF");
109 return NULL;
111 str = isl_token_get_str(ctx, tok);
112 domain = isl_union_set_read_from_str(ctx, str);
113 free(str);
114 isl_token_free(tok);
116 more = isl_stream_yaml_next(s);
117 if (more < 0)
118 goto error;
119 if (!more) {
120 tree = isl_schedule_tree_from_domain(domain);
121 } else {
122 key = get_key(s);
123 if (key != isl_schedule_key_child)
124 isl_die(ctx, isl_error_invalid, "expecting child",
125 goto error);
126 if (isl_stream_yaml_next(s) < 0)
127 goto error;
128 tree = isl_stream_read_schedule_tree(s);
129 tree = isl_schedule_tree_insert_domain(tree, domain);
132 return tree;
133 error:
134 isl_union_set_free(domain);
135 return NULL;
138 /* Read a subtree with filter root node from "s".
140 static __isl_give isl_schedule_tree *read_filter(__isl_keep isl_stream *s)
142 isl_union_set *filter = NULL;
143 isl_schedule_tree *tree;
144 isl_ctx *ctx;
145 struct isl_token *tok;
146 enum isl_schedule_key key;
147 char *str;
148 int more;
150 ctx = isl_stream_get_ctx(s);
152 key = get_key(s);
154 if (isl_stream_yaml_next(s) < 0)
155 return NULL;
157 tok = isl_stream_next_token(s);
158 if (!tok) {
159 isl_stream_error(s, NULL, "unexpected EOF");
160 return NULL;
162 str = isl_token_get_str(ctx, tok);
163 filter = isl_union_set_read_from_str(ctx, str);
164 free(str);
165 isl_token_free(tok);
167 more = isl_stream_yaml_next(s);
168 if (more < 0)
169 goto error;
170 if (!more) {
171 tree = isl_schedule_tree_from_filter(filter);
172 } else {
173 key = get_key(s);
174 if (key != isl_schedule_key_child)
175 isl_die(ctx, isl_error_invalid, "expecting child",
176 goto error);
177 if (isl_stream_yaml_next(s) < 0)
178 goto error;
179 tree = isl_stream_read_schedule_tree(s);
180 tree = isl_schedule_tree_insert_filter(tree, filter);
183 return tree;
184 error:
185 isl_union_set_free(filter);
186 return NULL;
189 /* Read a sequence of integers from "s" (representing the coincident
190 * property of a band node).
192 static __isl_give isl_val_list *read_coincident(__isl_keep isl_stream *s)
194 isl_ctx *ctx;
195 isl_val_list *list;
196 int more;
198 ctx = isl_stream_get_ctx(s);
200 if (isl_stream_yaml_read_start_sequence(s) < 0)
201 return NULL;
203 list = isl_val_list_alloc(ctx, 0);
204 while ((more = isl_stream_yaml_next(s)) > 0) {
205 isl_val *val;
207 val = isl_stream_read_val(s);
208 list = isl_val_list_add(list, val);
211 if (more < 0 || isl_stream_yaml_read_end_sequence(s))
212 list = isl_val_list_free(list);
214 return list;
217 /* Set the (initial) coincident properties of "band" according to
218 * the (initial) elements of "coincident".
220 static __isl_give isl_schedule_band *set_coincident(
221 __isl_take isl_schedule_band *band, __isl_take isl_val_list *coincident)
223 int i;
224 int n, m;
226 n = isl_schedule_band_n_member(band);
227 m = isl_val_list_n_val(coincident);
229 for (i = 0; i < n && i < m; ++i) {
230 isl_val *v;
232 v = isl_val_list_get_val(coincident, i);
233 if (!v)
234 band = isl_schedule_band_free(band);
235 band = isl_schedule_band_member_set_coincident(band, i,
236 !isl_val_is_zero(v));
237 isl_val_free(v);
239 isl_val_list_free(coincident);
240 return band;
243 /* Read a subtree with band root node from "s".
245 static __isl_give isl_schedule_tree *read_band(isl_stream *s)
247 isl_multi_union_pw_aff *schedule = NULL;
248 isl_schedule_tree *tree = NULL;
249 isl_val_list *coincident = NULL;
250 isl_ctx *ctx;
251 isl_schedule_band *band;
252 int permutable = 0;
253 int more;
255 ctx = isl_stream_get_ctx(s);
257 do {
258 struct isl_token *tok;
259 enum isl_schedule_key key;
260 char *str;
261 isl_val *v;
263 key = get_key(s);
264 if (isl_stream_yaml_next(s) < 0)
265 goto error;
267 switch (key) {
268 case isl_schedule_key_schedule:
269 isl_multi_union_pw_aff_free(schedule);
270 tok = isl_stream_next_token(s);
271 if (!tok) {
272 isl_stream_error(s, NULL, "unexpected EOF");
273 goto error;
275 str = isl_token_get_str(ctx, tok);
276 schedule = isl_multi_union_pw_aff_read_from_str(ctx,
277 str);
278 free(str);
279 isl_token_free(tok);
280 if (!schedule)
281 goto error;
282 break;
283 case isl_schedule_key_coincident:
284 coincident = read_coincident(s);
285 if (!coincident)
286 goto error;
287 break;
288 case isl_schedule_key_permutable:
289 v = isl_stream_read_val(s);
290 permutable = !isl_val_is_zero(v);
291 isl_val_free(v);
292 break;
293 case isl_schedule_key_child:
294 isl_schedule_tree_free(tree);
295 tree = isl_stream_read_schedule_tree(s);
296 if (!tree)
297 goto error;
298 break;
299 default:
300 isl_die(ctx, isl_error_invalid, "unexpected key",
301 goto error);
303 } while ((more = isl_stream_yaml_next(s)) > 0);
305 if (more < 0)
306 goto error;
308 if (!schedule)
309 isl_die(ctx, isl_error_invalid, "missing schedule", goto error);
311 band = isl_schedule_band_from_multi_union_pw_aff(schedule);
312 band = isl_schedule_band_set_permutable(band, permutable);
313 if (coincident)
314 band = set_coincident(band, coincident);
315 if (tree)
316 tree = isl_schedule_tree_insert_band(tree, band);
317 else
318 tree = isl_schedule_tree_from_band(band);
320 return tree;
321 error:
322 isl_val_list_free(coincident);
323 isl_schedule_tree_free(tree);
324 isl_multi_union_pw_aff_free(schedule);
325 return NULL;
328 /* Read a subtree with root node of type "type" from "s".
329 * The node is represented by a sequence of children.
331 static __isl_give isl_schedule_tree *read_children(isl_stream *s,
332 enum isl_schedule_node_type type)
334 isl_ctx *ctx;
335 isl_schedule_tree_list *list;
336 int more;
338 ctx = isl_stream_get_ctx(s);
340 isl_token_free(isl_stream_next_token(s));
342 if (isl_stream_yaml_next(s) < 0)
343 return NULL;
345 if (isl_stream_yaml_read_start_sequence(s))
346 return NULL;
348 list = isl_schedule_tree_list_alloc(ctx, 0);
349 while ((more = isl_stream_yaml_next(s)) > 0) {
350 isl_schedule_tree *tree;
352 tree = isl_stream_read_schedule_tree(s);
353 list = isl_schedule_tree_list_add(list, tree);
356 if (more < 0 || isl_stream_yaml_read_end_sequence(s))
357 list = isl_schedule_tree_list_free(list);
359 return isl_schedule_tree_from_children(type, list);
362 /* Read a subtree with sequence root node from "s".
364 static __isl_give isl_schedule_tree *read_sequence(isl_stream *s)
366 return read_children(s, isl_schedule_node_sequence);
369 /* Read a subtree with set root node from "s".
371 static __isl_give isl_schedule_tree *read_set(isl_stream *s)
373 return read_children(s, isl_schedule_node_set);
376 /* Read a schedule (sub)tree from "s".
378 * We first determine the type of the root node based on the first
379 * mapping key and then hand over to a function tailored to reading
380 * nodes of this type.
382 static __isl_give isl_schedule_tree *isl_stream_read_schedule_tree(
383 struct isl_stream *s)
385 enum isl_schedule_key key;
386 struct isl_token *tok;
387 isl_schedule_tree *tree = NULL;
388 int more;
390 if (isl_stream_yaml_read_start_mapping(s))
391 return NULL;
392 more = isl_stream_yaml_next(s);
393 if (more < 0)
394 return NULL;
395 if (!more) {
396 isl_stream_error(s, NULL, "missing key");
397 return NULL;
400 tok = isl_stream_next_token(s);
401 key = extract_key(s, tok);
402 isl_stream_push_token(s, tok);
403 if (key < 0)
404 return NULL;
405 switch (key) {
406 case isl_schedule_key_domain:
407 tree = read_domain(s);
408 break;
409 case isl_schedule_key_filter:
410 tree = read_filter(s);
411 break;
412 case isl_schedule_key_leaf:
413 isl_token_free(isl_stream_next_token(s));
414 tree = isl_schedule_tree_leaf(isl_stream_get_ctx(s));
415 break;
416 case isl_schedule_key_sequence:
417 tree = read_sequence(s);
418 break;
419 case isl_schedule_key_set:
420 tree = read_set(s);
421 break;
422 case isl_schedule_key_schedule:
423 case isl_schedule_key_coincident:
424 case isl_schedule_key_permutable:
425 tree = read_band(s);
426 break;
427 case isl_schedule_key_child:
428 isl_die(isl_stream_get_ctx(s), isl_error_unsupported,
429 "cannot identity node type", return NULL);
430 case isl_schedule_key_error:
431 return NULL;
434 if (isl_stream_yaml_read_end_mapping(s) < 0) {
435 isl_stream_error(s, NULL, "unexpected extra elements");
436 return isl_schedule_tree_free(tree);
439 return tree;
442 /* Read an isl_schedule from "s".
444 __isl_give isl_schedule *isl_stream_read_schedule(isl_stream *s)
446 isl_ctx *ctx;
447 isl_schedule_tree *tree;
449 if (!s)
450 return NULL;
452 ctx = isl_stream_get_ctx(s);
453 tree = isl_stream_read_schedule_tree(s);
454 return isl_schedule_from_schedule_tree(ctx, tree);
457 /* Read an isl_schedule from "input".
459 __isl_give isl_schedule *isl_schedule_read_from_file(isl_ctx *ctx, FILE *input)
461 struct isl_stream *s;
462 isl_schedule *schedule;
464 s = isl_stream_new_file(ctx, input);
465 if (!s)
466 return NULL;
467 schedule = isl_stream_read_schedule(s);
468 isl_stream_free(s);
470 return schedule;
473 /* Read an isl_schedule from "str".
475 __isl_give isl_schedule *isl_schedule_read_from_str(isl_ctx *ctx,
476 const char *str)
478 struct isl_stream *s;
479 isl_schedule *schedule;
481 s = isl_stream_new_str(ctx, str);
482 if (!s)
483 return NULL;
484 schedule = isl_stream_read_schedule(s);
485 isl_stream_free(s);
487 return schedule;