1 #include <assert.h>
2 #include <ctype.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <isl/ctx.h>
7 #include <isl/val.h>
8 #include <isl/space.h>
9 #include <isl/aff.h>
10 #include <isl/obj.h>
11 #include <isl/stream.h>
12 #include <isl/set.h>
13 #include <isl/map.h>
14 #include <isl/union_set.h>
15 #include <isl/union_map.h>
16 #include <isl/vertices.h>
17 #include <isl/flow.h>
18 #include <isl/schedule.h>
19 #include <isl/ast_build.h>
20 #include <isl/printer.h>
21 #include <isl_obj_list.h>
22 #include <isl_obj_str.h>
23 #include <barvinok/isl.h>
24 #include <barvinok/options.h>
25 #include "lattice_width.h"
26 
27 #include "config.h"
28 
29 #ifdef HAVE_SIGACTION
30 #include <signal.h>
31 
32 static isl_ctx *main_ctx;
33 
handler(int signum)34 static void handler(int signum)
35 {
36 	if (isl_ctx_aborted(main_ctx))
37 		exit(EXIT_FAILURE);
38 	isl_ctx_abort(main_ctx);
39 }
40 
41 static struct sigaction sa_old;
42 
install_signal_handler(isl_ctx * ctx)43 static void install_signal_handler(isl_ctx *ctx)
44 {
45 	struct sigaction sa;
46 
47 	main_ctx = ctx;
48 
49 	memset(&sa, 0, sizeof(struct sigaction));
50 	sa.sa_handler = &handler;
51 	sa.sa_flags = SA_RESTART;
52 	sigaction(SIGINT, &sa, &sa_old);
53 }
54 
remove_signal_handler(isl_ctx * ctx)55 static void remove_signal_handler(isl_ctx *ctx)
56 {
57 	sigaction(SIGINT, &sa_old, NULL);
58 }
59 
60 #else
61 
install_signal_handler(isl_ctx * ctx)62 static void install_signal_handler(isl_ctx *ctx)
63 {
64 }
65 
remove_signal_handler(isl_ctx * ctx)66 static void remove_signal_handler(isl_ctx *ctx)
67 {
68 }
69 
70 #endif
71 
72 #ifdef HAVE_PET
73 #include <pet.h>
74 #else
75 struct pet_options;
pet_options_set_autodetect(isl_ctx * ctx,int val)76 int pet_options_set_autodetect(isl_ctx *ctx, int val)
77 {
78 	return -1;
79 }
pet_options_set_encapsulate_dynamic_control(isl_ctx * ctx,int val)80 int pet_options_set_encapsulate_dynamic_control(isl_ctx *ctx, int val)
81 {
82 	return -1;
83 }
84 #endif
85 
86 static int iscc_bool_false = 0;
87 static int iscc_bool_true = 1;
88 static int iscc_bool_error = -1;
89 
90 enum iscc_op { ISCC_READ, ISCC_WRITE, ISCC_SOURCE, ISCC_VERTICES,
91 	       ISCC_LAST, ISCC_ANY, ISCC_BEFORE, ISCC_UNDER,
92 	       ISCC_SCHEDULE,
93 	       ISCC_MINIMIZING, ISCC_RESPECTING,
94 	       ISCC_CODEGEN, ISCC_USING,
95 	       ISCC_TYPEOF, ISCC_PRINT, ISCC_ASSERT,
96 	       ISCC_N_OP };
97 static const char *op_name[ISCC_N_OP] = {
98 	[ISCC_ASSERT] = "assert",
99 	[ISCC_READ] = "read",
100 	[ISCC_WRITE] = "write",
101 	[ISCC_PRINT] = "print",
102 	[ISCC_SOURCE] = "source",
103 	[ISCC_VERTICES] = "vertices",
104 	[ISCC_LAST] = "last",
105 	[ISCC_ANY] = "any",
106 	[ISCC_BEFORE] = "before",
107 	[ISCC_UNDER] = "under",
108 	[ISCC_SCHEDULE] = "schedule",
109 	[ISCC_MINIMIZING] = "minimizing",
110 	[ISCC_RESPECTING] = "respecting",
111 	[ISCC_CODEGEN] = "codegen",
112 	[ISCC_USING] = "using",
113 	[ISCC_TYPEOF] = "typeof"
114 };
115 static enum isl_token_type iscc_op[ISCC_N_OP];
116 
117 struct isl_arg_choice iscc_format[] = {
118 	{"isl",		ISL_FORMAT_ISL},
119 	{"omega",	ISL_FORMAT_OMEGA},
120 	{"polylib",	ISL_FORMAT_POLYLIB},
121 	{"ext-polylib",	ISL_FORMAT_EXT_POLYLIB},
122 	{"latex",	ISL_FORMAT_LATEX},
123 	{"C",		ISL_FORMAT_C},
124 	{0}
125 };
126 
127 struct iscc_options {
128 	struct barvinok_options	*barvinok;
129 	struct pet_options	*pet;
130 	unsigned		 format;
131 	int			 io;
132 };
133 
ISL_ARGS_START(struct iscc_options,iscc_options_args)134 ISL_ARGS_START(struct iscc_options, iscc_options_args)
135 ISL_ARG_CHILD(struct iscc_options, barvinok, "barvinok", &barvinok_options_args,
136 	"barvinok options")
137 #ifdef HAVE_PET
138 ISL_ARG_CHILD(struct iscc_options, pet, "pet", &pet_options_args, "pet options")
139 #endif
140 ISL_ARG_CHOICE(struct iscc_options, format, 0, "format", \
141 	iscc_format,	ISL_FORMAT_ISL, "output format")
142 ISL_ARG_BOOL(struct iscc_options, io, 0, "io", 1,
143 	"allow read and write operations")
144 ISL_ARGS_END
145 
146 ISL_ARG_DEF(iscc_options, struct iscc_options, iscc_options_args)
147 ISL_ARG_CTX_DEF(iscc_options, struct iscc_options, iscc_options_args)
148 
149 static void *isl_obj_bool_copy(void *v)
150 {
151 	return v;
152 }
153 
isl_obj_bool_free(void * v)154 static void isl_obj_bool_free(void *v)
155 {
156 }
157 
isl_obj_bool_print(__isl_take isl_printer * p,void * v)158 static __isl_give isl_printer *isl_obj_bool_print(__isl_take isl_printer *p,
159 	void *v)
160 {
161 	if (v == &iscc_bool_true)
162 		return isl_printer_print_str(p, "True");
163 	else if (v == &iscc_bool_false)
164 		return isl_printer_print_str(p, "False");
165 	else
166 		return isl_printer_print_str(p, "Error");
167 }
168 
isl_obj_bool_add(void * v1,void * v2)169 static void *isl_obj_bool_add(void *v1, void *v2)
170 {
171 	return v1;
172 }
173 
174 struct isl_obj_vtable isl_obj_bool_vtable = {
175 	isl_obj_bool_copy,
176 	isl_obj_bool_add,
177 	isl_obj_bool_print,
178 	isl_obj_bool_free
179 };
180 #define isl_obj_bool		(&isl_obj_bool_vtable)
181 
iscc_bool_from_int(int res)182 int *iscc_bool_from_int(int res)
183 {
184 	return res < 0 ? &iscc_bool_error :
185 	       res ? &iscc_bool_true : &iscc_bool_false;
186 }
187 
188 /* Conjunction of "b1" and "b2".
189  * The result is returned as an integer because it is post-processed by
190  * iscc_bool_from_int.
191  */
isl_bool_and(isl_bool * b1,__isl_take isl_bool * b2)192 static int isl_bool_and(isl_bool *b1, __isl_take isl_bool *b2)
193 {
194 	if (b1 == &iscc_bool_error || b2 == &iscc_bool_error)
195 		return -1;
196 	return b1 == &iscc_bool_true && b2 == &iscc_bool_true;
197 }
198 
199 /* Disjunction of "b1" and "b2".
200  * The result is returned as an integer because it is post-processed by
201  * iscc_bool_from_int.
202  */
isl_bool_or(isl_bool * b1,__isl_take isl_bool * b2)203 static int isl_bool_or(isl_bool *b1, __isl_take isl_bool *b2)
204 {
205 	if (b1 == &iscc_bool_error || b2 == &iscc_bool_error)
206 		return -1;
207 	return b1 == &iscc_bool_true || b2 == &iscc_bool_true;
208 }
209 
isl_union_map_is_superset(__isl_take isl_union_map * map1,__isl_take isl_union_map * map2)210 static int isl_union_map_is_superset(__isl_take isl_union_map *map1,
211 	__isl_take isl_union_map *map2)
212 {
213 	return isl_union_map_is_subset(map2, map1);
214 }
isl_union_set_is_superset(__isl_take isl_union_set * set1,__isl_take isl_union_set * set2)215 static int isl_union_set_is_superset(__isl_take isl_union_set *set1,
216 	__isl_take isl_union_set *set2)
217 {
218 	return isl_union_set_is_subset(set2, set1);
219 }
220 
isl_union_map_is_strict_superset(__isl_take isl_union_map * map1,__isl_take isl_union_map * map2)221 static int isl_union_map_is_strict_superset(__isl_take isl_union_map *map1,
222 	__isl_take isl_union_map *map2)
223 {
224 	return isl_union_map_is_strict_subset(map2, map1);
225 }
isl_union_set_is_strict_superset(__isl_take isl_union_set * set1,__isl_take isl_union_set * set2)226 static int isl_union_set_is_strict_superset(__isl_take isl_union_set *set1,
227 	__isl_take isl_union_set *set2)
228 {
229 	return isl_union_set_is_strict_subset(set2, set1);
230 }
231 
232 extern struct isl_obj_vtable isl_obj_list_vtable;
233 #define isl_obj_list		(&isl_obj_list_vtable)
234 
235 typedef void *(*isc_bin_op_fn)(void *lhs, void *rhs);
236 typedef int (*isc_bin_test_fn)(void *lhs, void *rhs);
237 struct isc_bin_op {
238 	enum isl_token_type	op;
239 	isl_obj_type		lhs;
240 	isl_obj_type		rhs;
241 	isl_obj_type		res;
242 	union {
243 		isc_bin_op_fn		fn;
244 		isc_bin_test_fn		test;
245 	} o;
246 };
247 struct isc_named_bin_op {
248 	char			*name;
249 	struct isc_bin_op	op;
250 };
251 /* Compound binary operator.
252  * "full" is only used to generate a unique token number for op.op
253  * in register_named_ops.
254  * "op1" is the first part of the compound operator.
255  * "op2" is the second part of the compound operator.
256  */
257 struct iscc_compound_bin_op {
258 	char			*full;
259 	enum isl_token_type	op1;
260 	enum isl_token_type	op2;
261 	struct isc_bin_op	op;
262 };
263 
264 struct iscc_at {
265 	isl_union_pw_qpolynomial *upwqp;
266 	isl_union_pw_qpolynomial *res;
267 };
268 
eval_at(__isl_take isl_point * pnt,void * user)269 static isl_stat eval_at(__isl_take isl_point *pnt, void *user)
270 {
271 	struct iscc_at *at = (struct iscc_at *) user;
272 	isl_val *v;
273 	isl_qpolynomial *qp;
274 	isl_set *set;
275 
276 	set = isl_set_from_point(isl_point_copy(pnt));
277 	v = isl_union_pw_qpolynomial_eval(
278 				isl_union_pw_qpolynomial_copy(at->upwqp), pnt);
279 	qp = isl_qpolynomial_val_on_domain(isl_set_get_space(set), v);
280 
281 	at->res = isl_union_pw_qpolynomial_add(at->res,
282 			isl_union_pw_qpolynomial_from_pw_qpolynomial(
283 				isl_pw_qpolynomial_alloc(set, qp)));
284 
285 	return isl_stat_ok;
286 }
287 
isl_union_pw_qpolynomial_at(__isl_take isl_union_pw_qpolynomial * upwqp,__isl_take isl_union_set * uset)288 __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_at(
289 	__isl_take isl_union_pw_qpolynomial *upwqp,
290 	__isl_take isl_union_set *uset)
291 {
292 	struct iscc_at at;
293 
294 	at.upwqp = upwqp;
295 	at.res = isl_union_pw_qpolynomial_zero(isl_union_set_get_space(uset));
296 
297 	isl_union_set_foreach_point(uset, eval_at, &at);
298 
299 	isl_union_pw_qpolynomial_free(upwqp);
300 	isl_union_set_free(uset);
301 
302 	return at.res;
303 }
304 
305 struct iscc_fold_at {
306 	isl_union_pw_qpolynomial_fold *upwf;
307 	isl_union_pw_qpolynomial *res;
308 };
309 
eval_fold_at(__isl_take isl_point * pnt,void * user)310 static isl_stat eval_fold_at(__isl_take isl_point *pnt, void *user)
311 {
312 	struct iscc_fold_at *at = (struct iscc_fold_at *) user;
313 	isl_val *v;
314 	isl_qpolynomial *qp;
315 	isl_set *set;
316 
317 	set = isl_set_from_point(isl_point_copy(pnt));
318 	v = isl_union_pw_qpolynomial_fold_eval(
319 			    isl_union_pw_qpolynomial_fold_copy(at->upwf), pnt);
320 	qp = isl_qpolynomial_val_on_domain(isl_set_get_space(set), v);
321 
322 	at->res = isl_union_pw_qpolynomial_add(at->res,
323 			isl_union_pw_qpolynomial_from_pw_qpolynomial(
324 				isl_pw_qpolynomial_alloc(set, qp)));
325 
326 	return isl_stat_ok;
327 }
328 
isl_union_pw_qpolynomial_fold_at(__isl_take isl_union_pw_qpolynomial_fold * upwf,__isl_take isl_union_set * uset)329 __isl_give isl_union_pw_qpolynomial *isl_union_pw_qpolynomial_fold_at(
330 	__isl_take isl_union_pw_qpolynomial_fold *upwf,
331 	__isl_take isl_union_set *uset)
332 {
333 	struct iscc_fold_at at;
334 
335 	at.upwf = upwf;
336 	at.res = isl_union_pw_qpolynomial_zero(isl_union_set_get_space(uset));
337 
338 	isl_union_set_foreach_point(uset, eval_fold_at, &at);
339 
340 	isl_union_pw_qpolynomial_fold_free(upwf);
341 	isl_union_set_free(uset);
342 
343 	return at.res;
344 }
345 
union_pw_qpolynomial_add_union_pw_qpolynomial_fold(__isl_take isl_union_pw_qpolynomial * upwqp,__isl_take isl_union_pw_qpolynomial_fold * upwf)346 static __isl_give isl_union_pw_qpolynomial_fold *union_pw_qpolynomial_add_union_pw_qpolynomial_fold(
347 	__isl_take isl_union_pw_qpolynomial *upwqp,
348 	__isl_take isl_union_pw_qpolynomial_fold *upwf)
349 {
350 	return isl_union_pw_qpolynomial_fold_add_union_pw_qpolynomial(upwf,
351 									upwqp);
352 }
353 
union_map_apply_union_pw_qpolynomial_fold(__isl_take isl_union_map * umap,__isl_take isl_union_pw_qpolynomial_fold * upwf)354 static __isl_give struct isl_list *union_map_apply_union_pw_qpolynomial_fold(
355 	__isl_take isl_union_map *umap,
356 	__isl_take isl_union_pw_qpolynomial_fold *upwf)
357 {
358 	isl_ctx *ctx;
359 	struct isl_list *list;
360 	int tight;
361 
362 	ctx = isl_union_map_get_ctx(umap);
363 	list = isl_list_alloc(ctx, 2);
364 	if (!list)
365 		goto error2;
366 
367 	list->obj[0].type = isl_obj_union_pw_qpolynomial_fold;
368 	list->obj[0].v = isl_union_map_apply_union_pw_qpolynomial_fold(umap,
369 							upwf, &tight);
370 	list->obj[1].type = isl_obj_bool;
371 	list->obj[1].v = tight ? &iscc_bool_true : &iscc_bool_false;
372 	if (tight < 0 || !list->obj[0].v)
373 		goto error;
374 
375 	return list;
376 error2:
377 	isl_union_map_free(umap);
378 	isl_union_pw_qpolynomial_fold_free(upwf);
379 error:
380 	isl_list_free(list);
381 	return NULL;
382 }
383 
union_set_apply_union_pw_qpolynomial_fold(__isl_take isl_union_set * uset,__isl_take isl_union_pw_qpolynomial_fold * upwf)384 static __isl_give struct isl_list *union_set_apply_union_pw_qpolynomial_fold(
385 	__isl_take isl_union_set *uset,
386 	__isl_take isl_union_pw_qpolynomial_fold *upwf)
387 {
388 	isl_ctx *ctx;
389 	struct isl_list *list;
390 	int tight;
391 
392 	ctx = isl_union_set_get_ctx(uset);
393 	list = isl_list_alloc(ctx, 2);
394 	if (!list)
395 		goto error2;
396 
397 	list->obj[0].type = isl_obj_union_pw_qpolynomial_fold;
398 	list->obj[0].v = isl_union_set_apply_union_pw_qpolynomial_fold(uset,
399 							upwf, &tight);
400 	list->obj[1].type = isl_obj_bool;
401 	list->obj[1].v = tight ? &iscc_bool_true : &iscc_bool_false;
402 	if (tight < 0 || !list->obj[0].v)
403 		goto error;
404 
405 	return list;
406 error2:
407 	isl_union_set_free(uset);
408 	isl_union_pw_qpolynomial_fold_free(upwf);
409 error:
410 	isl_list_free(list);
411 	return NULL;
412 }
413 
isl_val_mul_union_pw_qpolynomial(__isl_take isl_val * v,__isl_take isl_union_pw_qpolynomial * upwqp)414 static __isl_give isl_union_pw_qpolynomial *isl_val_mul_union_pw_qpolynomial(
415 	__isl_take isl_val *v, __isl_take isl_union_pw_qpolynomial *upwqp)
416 {
417 	return isl_union_pw_qpolynomial_scale_val(upwqp, v);
418 }
419 
420 static __isl_give isl_union_pw_qpolynomial_fold *
int_val_mul_union_pw_qpolynomial_fold(__isl_take isl_val * v,__isl_take isl_union_pw_qpolynomial_fold * upwf)421 int_val_mul_union_pw_qpolynomial_fold(__isl_take isl_val *v,
422 	__isl_take isl_union_pw_qpolynomial_fold *upwf)
423 {
424 	return isl_union_pw_qpolynomial_fold_scale_val(upwf, v);
425 }
426 
427 /* Are the two strings "str1" and "str2" equal to each other?
428  */
str_eq(__isl_keep isl_str * str1,__isl_keep isl_str * str2)429 static int str_eq(__isl_keep isl_str *str1, __isl_keep isl_str *str2)
430 {
431 	if (!str1 || !str2)
432 		return -1;
433 
434 	return !strcmp(str1->s, str2->s);
435 }
436 
437 struct isc_bin_op bin_ops[] = {
438 	{ '+',	isl_obj_bool,	isl_obj_bool, isl_obj_bool,
439 		(isc_bin_op_fn) &isl_bool_or },
440 	{ '*',	isl_obj_bool,	isl_obj_bool, isl_obj_bool,
441 		(isc_bin_op_fn) &isl_bool_and },
442 	{ '+',	isl_obj_val,	isl_obj_val, isl_obj_val,
443 		(isc_bin_op_fn) &isl_val_add },
444 	{ '-',	isl_obj_val,	isl_obj_val, isl_obj_val,
445 		(isc_bin_op_fn) &isl_val_sub },
446 	{ '*',	isl_obj_val,	isl_obj_val, isl_obj_val,
447 		(isc_bin_op_fn) &isl_val_mul },
448 	{ '+',	isl_obj_pw_multi_aff,	isl_obj_pw_multi_aff,
449 		isl_obj_pw_multi_aff,
450 		(isc_bin_op_fn) &isl_pw_multi_aff_add },
451 	{ '+',	isl_obj_union_set,	isl_obj_union_set,
452 		isl_obj_union_set,
453 		(isc_bin_op_fn) &isl_union_set_union },
454 	{ '+',	isl_obj_union_map,	isl_obj_union_map,
455 		isl_obj_union_map,
456 		(isc_bin_op_fn) &isl_union_map_union },
457 	{ '-',	isl_obj_union_set,	isl_obj_union_set,
458 		isl_obj_union_set,
459 		(isc_bin_op_fn) &isl_union_set_subtract },
460 	{ '-',	isl_obj_union_map,	isl_obj_union_map,
461 		isl_obj_union_map,
462 		(isc_bin_op_fn) &isl_union_map_subtract },
463 	{ '-',	isl_obj_union_map,	isl_obj_union_set,
464 		isl_obj_union_map,
465 		(isc_bin_op_fn) &isl_union_map_subtract_domain },
466 	{ '*',	isl_obj_union_set,	isl_obj_union_set,
467 		isl_obj_union_set,
468 		(isc_bin_op_fn) &isl_union_set_intersect },
469 	{ '*',	isl_obj_union_map,	isl_obj_union_map,
470 		isl_obj_union_map,
471 		(isc_bin_op_fn) &isl_union_map_intersect },
472 	{ '*',	isl_obj_union_map,	isl_obj_union_set,
473 		isl_obj_union_map,
474 		(isc_bin_op_fn) &isl_union_map_intersect_domain },
475 	{ '.',	isl_obj_union_map,	isl_obj_union_map,
476 		isl_obj_union_map,
477 		(isc_bin_op_fn) &isl_union_map_apply_range },
478 	{ '.',	isl_obj_union_map,	isl_obj_union_pw_qpolynomial,
479 		isl_obj_union_pw_qpolynomial,
480 		(isc_bin_op_fn) &isl_union_map_apply_union_pw_qpolynomial },
481 	{ '.',	isl_obj_union_map,	isl_obj_union_pw_qpolynomial_fold,
482 		isl_obj_list,
483 		(isc_bin_op_fn) &union_map_apply_union_pw_qpolynomial_fold },
484 	{ ISL_TOKEN_TO,	isl_obj_union_set,	isl_obj_union_set,
485 		isl_obj_union_map,
486 		(isc_bin_op_fn) &isl_union_map_from_domain_and_range },
487 	{ '=', isl_obj_union_set,	isl_obj_union_set,	isl_obj_bool,
488 		{ .test = (isc_bin_test_fn) &isl_union_set_is_equal } },
489 	{ '=', isl_obj_union_map,	isl_obj_union_map,	isl_obj_bool,
490 		{ .test = (isc_bin_test_fn) &isl_union_map_is_equal } },
491 	{ ISL_TOKEN_LE, isl_obj_union_set,	isl_obj_union_set,
492 		isl_obj_bool,
493 		{ .test = (isc_bin_test_fn) &isl_union_set_is_subset } },
494 	{ ISL_TOKEN_LE, isl_obj_union_map,	isl_obj_union_map,
495 		isl_obj_bool,
496 		{ .test = (isc_bin_test_fn) &isl_union_map_is_subset } },
497 	{ ISL_TOKEN_LT, isl_obj_union_set,	isl_obj_union_set,
498 		isl_obj_bool,
499 		{ .test = (isc_bin_test_fn) &isl_union_set_is_strict_subset } },
500 	{ ISL_TOKEN_LT, isl_obj_union_map,	isl_obj_union_map,
501 		isl_obj_bool,
502 		{ .test = (isc_bin_test_fn) &isl_union_map_is_strict_subset } },
503 	{ ISL_TOKEN_GE, isl_obj_union_set,	isl_obj_union_set,
504 		isl_obj_bool,
505 		{ .test = (isc_bin_test_fn) &isl_union_set_is_superset } },
506 	{ ISL_TOKEN_GE, isl_obj_union_map,	isl_obj_union_map,
507 		isl_obj_bool,
508 		{ .test = (isc_bin_test_fn) &isl_union_map_is_superset } },
509 	{ ISL_TOKEN_GT, isl_obj_union_set,	isl_obj_union_set,
510 		isl_obj_bool,
511 		{ .test =
512 			(isc_bin_test_fn) &isl_union_set_is_strict_superset } },
513 	{ ISL_TOKEN_GT, isl_obj_union_map,	isl_obj_union_map,
514 		isl_obj_bool,
515 		{ .test =
516 			(isc_bin_test_fn) &isl_union_map_is_strict_superset } },
517 	{ ISL_TOKEN_LEX_LE,	isl_obj_union_set,	isl_obj_union_set,
518 		isl_obj_union_map,
519 		(isc_bin_op_fn) &isl_union_set_lex_le_union_set },
520 	{ ISL_TOKEN_LEX_LT,	isl_obj_union_set,	isl_obj_union_set,
521 		isl_obj_union_map,
522 		(isc_bin_op_fn) &isl_union_set_lex_lt_union_set },
523 	{ ISL_TOKEN_LEX_GE,	isl_obj_union_set,	isl_obj_union_set,
524 		isl_obj_union_map,
525 		(isc_bin_op_fn) &isl_union_set_lex_ge_union_set },
526 	{ ISL_TOKEN_LEX_GT,	isl_obj_union_set,	isl_obj_union_set,
527 		isl_obj_union_map,
528 		(isc_bin_op_fn) &isl_union_set_lex_gt_union_set },
529 	{ ISL_TOKEN_LEX_LE,	isl_obj_union_map,	isl_obj_union_map,
530 		isl_obj_union_map,
531 		(isc_bin_op_fn) &isl_union_map_lex_le_union_map },
532 	{ ISL_TOKEN_LEX_LT,	isl_obj_union_map,	isl_obj_union_map,
533 		isl_obj_union_map,
534 		(isc_bin_op_fn) &isl_union_map_lex_lt_union_map },
535 	{ ISL_TOKEN_LEX_GE,	isl_obj_union_map,	isl_obj_union_map,
536 		isl_obj_union_map,
537 		(isc_bin_op_fn) &isl_union_map_lex_ge_union_map },
538 	{ ISL_TOKEN_LEX_GT,	isl_obj_union_map,	isl_obj_union_map,
539 		isl_obj_union_map,
540 		(isc_bin_op_fn) &isl_union_map_lex_gt_union_map },
541 	{ '.',	isl_obj_union_pw_qpolynomial_fold,
542 		isl_obj_union_pw_qpolynomial_fold,
543 		isl_obj_union_pw_qpolynomial_fold,
544 		(isc_bin_op_fn) &isl_union_pw_qpolynomial_fold_fold },
545 	{ '+',	isl_obj_union_pw_qpolynomial,	isl_obj_union_pw_qpolynomial,
546 		isl_obj_union_pw_qpolynomial,
547 		(isc_bin_op_fn) &isl_union_pw_qpolynomial_add },
548 	{ '+',	isl_obj_union_pw_qpolynomial,
549 		isl_obj_union_pw_qpolynomial_fold,
550 		isl_obj_union_pw_qpolynomial_fold,
551 		(isc_bin_op_fn) &union_pw_qpolynomial_add_union_pw_qpolynomial_fold },
552 	{ '+',	isl_obj_union_pw_qpolynomial_fold,
553 		isl_obj_union_pw_qpolynomial,
554 		isl_obj_union_pw_qpolynomial_fold,
555 		(isc_bin_op_fn) &isl_union_pw_qpolynomial_fold_add_union_pw_qpolynomial },
556 	{ '-',	isl_obj_union_pw_qpolynomial,	isl_obj_union_pw_qpolynomial,
557 		isl_obj_union_pw_qpolynomial,
558 		(isc_bin_op_fn) &isl_union_pw_qpolynomial_sub },
559 	{ '*',	isl_obj_val,	isl_obj_union_pw_qpolynomial,
560 		isl_obj_union_pw_qpolynomial,
561 		(isc_bin_op_fn) &isl_val_mul_union_pw_qpolynomial },
562 	{ '*',	isl_obj_union_pw_qpolynomial,	isl_obj_val,
563 		isl_obj_union_pw_qpolynomial,
564 		(isc_bin_op_fn) &isl_union_pw_qpolynomial_scale_val },
565 	{ '*',	isl_obj_val,	isl_obj_union_pw_qpolynomial_fold,
566 		isl_obj_union_pw_qpolynomial_fold,
567 		(isc_bin_op_fn) &int_val_mul_union_pw_qpolynomial_fold },
568 	{ '*',	isl_obj_union_pw_qpolynomial_fold,	isl_obj_val,
569 		isl_obj_union_pw_qpolynomial_fold,
570 		(isc_bin_op_fn) &isl_union_pw_qpolynomial_fold_scale_val },
571 	{ '*',	isl_obj_union_pw_qpolynomial,	isl_obj_union_pw_qpolynomial,
572 		isl_obj_union_pw_qpolynomial,
573 		(isc_bin_op_fn) &isl_union_pw_qpolynomial_mul },
574 	{ '*',	isl_obj_union_pw_qpolynomial,	isl_obj_union_set,
575 		isl_obj_union_pw_qpolynomial,
576 		(isc_bin_op_fn) &isl_union_pw_qpolynomial_intersect_domain },
577 	{ '*',	isl_obj_union_pw_qpolynomial_fold,	isl_obj_union_set,
578 		isl_obj_union_pw_qpolynomial_fold,
579 		(isc_bin_op_fn) &isl_union_pw_qpolynomial_fold_intersect_domain },
580 	{ '@',	isl_obj_union_pw_qpolynomial, isl_obj_union_set,
581 		isl_obj_union_pw_qpolynomial,
582 		(isc_bin_op_fn) &isl_union_pw_qpolynomial_at },
583 	{ '@',	isl_obj_union_pw_qpolynomial_fold, isl_obj_union_set,
584 		isl_obj_union_pw_qpolynomial,
585 		(isc_bin_op_fn) &isl_union_pw_qpolynomial_fold_at },
586 	{ '%',	isl_obj_union_set,	isl_obj_union_set,
587 		isl_obj_union_set,
588 		(isc_bin_op_fn) &isl_union_set_gist },
589 	{ '%',	isl_obj_union_map,	isl_obj_union_map,
590 		isl_obj_union_map,
591 		(isc_bin_op_fn) &isl_union_map_gist },
592 	{ '%',	isl_obj_union_map,	isl_obj_union_set,
593 		isl_obj_union_map,
594 		(isc_bin_op_fn) &isl_union_map_gist_domain },
595 	{ '%',	isl_obj_union_pw_qpolynomial,	isl_obj_union_set,
596 		isl_obj_union_pw_qpolynomial,
597 		(isc_bin_op_fn) &isl_union_pw_qpolynomial_gist },
598 	{ '%',	isl_obj_union_pw_qpolynomial_fold,	isl_obj_union_set,
599 		isl_obj_union_pw_qpolynomial_fold,
600 		(isc_bin_op_fn) &isl_union_pw_qpolynomial_fold_gist },
601 	{ ISL_TOKEN_EQ_EQ, isl_obj_union_pw_qpolynomial,
602 		isl_obj_union_pw_qpolynomial, isl_obj_bool,
603 		{ .test = (isc_bin_test_fn)
604 			    &isl_union_pw_qpolynomial_plain_is_equal } },
605 	{ ISL_TOKEN_EQ_EQ, isl_obj_union_pw_qpolynomial_fold,
606 		isl_obj_union_pw_qpolynomial_fold, isl_obj_bool,
607 		{ .test = (isc_bin_test_fn)
608 			    &isl_union_pw_qpolynomial_fold_plain_is_equal } },
609 	{ '+',	isl_obj_str,	isl_obj_str,	isl_obj_str,
610 		(isc_bin_op_fn) &isl_str_concat },
611 	{ '=',	isl_obj_str,	isl_obj_str,	isl_obj_bool,
612 		{ .test = (isc_bin_test_fn) &str_eq } },
613 	0
614 };
615 
616 struct iscc_compound_bin_op compound_bin_ops[] = {
617 	{ "->*",	ISL_TOKEN_TO,	'*',
618 	  { -1,	isl_obj_union_map,	isl_obj_union_set,
619 		isl_obj_union_map,
620 		(isc_bin_op_fn) &isl_union_map_intersect_range } },
621 	{ "->-",	ISL_TOKEN_TO,	'-',
622 	  { -1,	isl_obj_union_map,	isl_obj_union_set,
623 		isl_obj_union_map,
624 		(isc_bin_op_fn) &isl_union_map_subtract_range } },
625 	0
626 };
627 
map_after_map(__isl_take isl_union_map * umap1,__isl_take isl_union_map * umap2)628 static __isl_give isl_union_map *map_after_map(__isl_take isl_union_map *umap1,
629 	__isl_take isl_union_map *umap2)
630 {
631 	return isl_union_map_apply_range(umap2, umap1);
632 }
633 
qpolynomial_after_map(__isl_take isl_union_pw_qpolynomial * upwqp,__isl_take isl_union_map * umap)634 static __isl_give isl_union_pw_qpolynomial *qpolynomial_after_map(
635 	__isl_take isl_union_pw_qpolynomial *upwqp,
636 	__isl_take isl_union_map *umap)
637 {
638 	return isl_union_map_apply_union_pw_qpolynomial(umap, upwqp);
639 }
640 
qpolynomial_fold_after_map(__isl_take isl_union_pw_qpolynomial_fold * upwf,__isl_take isl_union_map * umap)641 static __isl_give struct isl_list *qpolynomial_fold_after_map(
642 	__isl_take isl_union_pw_qpolynomial_fold *upwf,
643 	__isl_take isl_union_map *umap)
644 {
645 	return union_map_apply_union_pw_qpolynomial_fold(umap, upwf);
646 }
647 
648 struct isc_named_bin_op named_bin_ops[] = {
649 	{ "after",	{ -1, isl_obj_union_map,	isl_obj_union_map,
650 		isl_obj_union_map,
651 		(isc_bin_op_fn) &map_after_map } },
652 	{ "after",	{ -1, isl_obj_union_pw_qpolynomial,
653 		isl_obj_union_map, isl_obj_union_pw_qpolynomial,
654 		(isc_bin_op_fn) &qpolynomial_after_map } },
655 	{ "after",	{ -1, isl_obj_union_pw_qpolynomial_fold,
656 		isl_obj_union_map, isl_obj_list,
657 		(isc_bin_op_fn) &qpolynomial_fold_after_map } },
658 	{ "before",	{ -1, isl_obj_union_map,	isl_obj_union_map,
659 		isl_obj_union_map,
660 		(isc_bin_op_fn) &isl_union_map_apply_range } },
661 	{ "before",	{ -1, isl_obj_union_map,
662 		isl_obj_union_pw_qpolynomial, isl_obj_union_pw_qpolynomial,
663 		(isc_bin_op_fn) &isl_union_map_apply_union_pw_qpolynomial } },
664 	{ "before",	{ -1, isl_obj_union_map,
665 		isl_obj_union_pw_qpolynomial_fold, isl_obj_list,
666 		(isc_bin_op_fn) &union_map_apply_union_pw_qpolynomial_fold } },
667 	{ "cross",	{ -1,	isl_obj_union_set,	isl_obj_union_set,
668 		isl_obj_union_set,
669 		(isc_bin_op_fn) &isl_union_set_product } },
670 	{ "cross",	{ -1,	isl_obj_union_map,	isl_obj_union_map,
671 		isl_obj_union_map,
672 		(isc_bin_op_fn) &isl_union_map_product } },
673 	{ "cross_range",	{ -1,	isl_obj_union_map,
674 		isl_obj_union_map, isl_obj_union_map,
675 		(isc_bin_op_fn) &isl_union_map_range_product } },
676 	NULL
677 };
678 
union_set_sample(__isl_take isl_union_set * uset)679 __isl_give isl_set *union_set_sample(__isl_take isl_union_set *uset)
680 {
681 	return isl_set_from_basic_set(isl_union_set_sample(uset));
682 }
683 
union_map_sample(__isl_take isl_union_map * umap)684 __isl_give isl_map *union_map_sample(__isl_take isl_union_map *umap)
685 {
686 	return isl_map_from_basic_map(isl_union_map_sample(umap));
687 }
688 
union_map_power(__isl_take isl_union_map * umap)689 static __isl_give struct isl_list *union_map_power(
690 	__isl_take isl_union_map *umap)
691 {
692 	isl_ctx *ctx;
693 	struct isl_list *list;
694 	int exact;
695 
696 	ctx = isl_union_map_get_ctx(umap);
697 	list = isl_list_alloc(ctx, 2);
698 	if (!list)
699 		goto error2;
700 
701 	list->obj[0].type = isl_obj_union_map;
702 	list->obj[0].v = isl_union_map_power(umap, &exact);
703 	list->obj[1].type = isl_obj_bool;
704 	list->obj[1].v = exact ? &iscc_bool_true : &iscc_bool_false;
705 	if (exact < 0 || !list->obj[0].v)
706 		goto error;
707 
708 	return list;
709 error2:
710 	isl_union_map_free(umap);
711 error:
712 	isl_list_free(list);
713 	return NULL;
714 }
715 
716 /* Compute a lower or upper bound on "upwqp" depending on "type" and
717  * return a list containing two elements, the bound and a boolean
718  * indicating whether the result is tight.
719  */
union_pw_qpolynomial_bound(__isl_take isl_union_pw_qpolynomial * upwqp,enum isl_fold type)720 static __isl_give struct isl_list *union_pw_qpolynomial_bound(
721 	__isl_take isl_union_pw_qpolynomial *upwqp, enum isl_fold type)
722 {
723 	isl_ctx *ctx;
724 	struct isl_list *list;
725 	int tight;
726 
727 	ctx = isl_union_pw_qpolynomial_get_ctx(upwqp);
728 	list = isl_list_alloc(ctx, 2);
729 	if (!list)
730 		goto error2;
731 
732 	list->obj[0].type = isl_obj_union_pw_qpolynomial_fold;
733 	list->obj[0].v = isl_union_pw_qpolynomial_bound(upwqp, type, &tight);
734 	list->obj[1].type = isl_obj_bool;
735 	list->obj[1].v = tight ? &iscc_bool_true : &iscc_bool_false;
736 	if (tight < 0 || !list->obj[0].v)
737 		goto error;
738 
739 	return list;
740 error2:
741 	isl_union_pw_qpolynomial_free(upwqp);
742 error:
743 	isl_list_free(list);
744 	return NULL;
745 }
746 
747 /* Compute a lower bound on "upwqp" and return a list containing
748  * two elements, the bound and a booleanindicating whether
749  * the result is tight.
750  */
union_pw_qpolynomial_lower_bound(__isl_take isl_union_pw_qpolynomial * upwqp)751 static __isl_give struct isl_list *union_pw_qpolynomial_lower_bound(
752 	__isl_take isl_union_pw_qpolynomial *upwqp)
753 {
754 	return union_pw_qpolynomial_bound(upwqp, isl_fold_min);
755 }
756 
757 /* Compute a upper bound on "upwqp" and return a list containing
758  * two elements, the bound and a booleanindicating whether
759  * the result is tight.
760  */
union_pw_qpolynomial_upper_bound(__isl_take isl_union_pw_qpolynomial * upwqp)761 static __isl_give struct isl_list *union_pw_qpolynomial_upper_bound(
762 	__isl_take isl_union_pw_qpolynomial *upwqp)
763 {
764 	return union_pw_qpolynomial_bound(upwqp, isl_fold_max);
765 }
766 
767 #ifdef HAVE_PET
768 /* Collect all statement instances, except those of kill statements.
769  */
collect_non_kill_instances(struct pet_scop * scop)770 static __isl_give isl_union_set *collect_non_kill_instances(
771 	struct pet_scop *scop)
772 {
773 	int i;
774 	isl_set *domain_i;
775 	isl_union_set *domain;
776 
777 	if (!scop)
778 		return NULL;
779 
780 	domain = isl_union_set_empty(isl_set_get_space(scop->context));
781 
782 	for (i = 0; i < scop->n_stmt; ++i) {
783 		struct pet_stmt *stmt = scop->stmts[i];
784 
785 		if (pet_stmt_is_kill(stmt))
786 			continue;
787 		domain_i = isl_set_copy(stmt->domain);
788 		if (scop->stmts[i]->n_arg > 0)
789 			domain_i = isl_map_domain(isl_set_unwrap(domain_i));
790 		domain = isl_union_set_add_set(domain, domain_i);
791 	}
792 
793 	return domain;
794 }
795 
parse(__isl_take isl_str * str)796 static __isl_give isl_list *parse(__isl_take isl_str *str)
797 {
798 	isl_ctx *ctx;
799 	struct isl_list *list;
800 	struct pet_scop *scop;
801 	isl_schedule *sched;
802 	isl_union_map *may_reads, *must_writes, *may_writes;
803 	isl_union_set *domain;
804 	struct iscc_options *options;
805 
806 	if (!str)
807 		return NULL;
808 	ctx = str->ctx;
809 
810 	options = isl_ctx_peek_iscc_options(ctx);
811 	if (!options || !options->io) {
812 		isl_str_free(str);
813 		isl_die(ctx, isl_error_invalid,
814 			"parse_file operation not allowed", return NULL);
815 	}
816 
817 	list = isl_list_alloc(ctx, 5);
818 	if (!list)
819 		goto error;
820 
821 	scop = pet_scop_extract_from_C_source(ctx, str->s, NULL);
822 	domain = collect_non_kill_instances(scop);
823 	sched = pet_scop_get_schedule(scop);
824 	sched = isl_schedule_intersect_domain(sched,
825 						isl_union_set_copy(domain));
826 	may_reads = pet_scop_get_may_reads(scop);
827 	may_writes = pet_scop_get_may_writes(scop);
828 	must_writes = pet_scop_get_must_writes(scop);
829 	pet_scop_free(scop);
830 
831 	list->obj[0].type = isl_obj_union_set;
832 	list->obj[0].v = domain;
833 	list->obj[1].type = isl_obj_union_map;
834 	list->obj[1].v = must_writes;
835 	list->obj[2].type = isl_obj_union_map;
836 	list->obj[2].v = may_writes;
837 	list->obj[3].type = isl_obj_union_map;
838 	list->obj[3].v = may_reads;
839 	list->obj[4].type = isl_obj_schedule;
840 	list->obj[4].v = sched;
841 
842 	if (!list->obj[0].v || !list->obj[1].v ||
843 	    !list->obj[2].v || !list->obj[3].v || !list->obj[4].v)
844 		goto error;
845 
846 	isl_str_free(str);
847 	return list;
848 error:
849 	isl_list_free(list);
850 	isl_str_free(str);
851 	return NULL;
852 }
853 #endif
854 
add_point(__isl_take isl_point * pnt,void * user)855 static isl_stat add_point(__isl_take isl_point *pnt, void *user)
856 {
857 	isl_union_set **scan = (isl_union_set **) user;
858 
859 	*scan = isl_union_set_add_set(*scan, isl_set_from_point(pnt));
860 
861 	return isl_stat_ok;
862 }
863 
union_set_scan(__isl_take isl_union_set * uset)864 static __isl_give isl_union_set *union_set_scan(__isl_take isl_union_set *uset)
865 {
866 	isl_union_set *scan;
867 
868 	scan = isl_union_set_empty(isl_union_set_get_space(uset));
869 
870 	if (isl_union_set_foreach_point(uset, add_point, &scan) < 0) {
871 		isl_union_set_free(scan);
872 		return uset;
873 	}
874 
875 	isl_union_set_free(uset);
876 	return scan;
877 }
878 
union_map_scan(__isl_take isl_union_map * umap)879 static __isl_give isl_union_map *union_map_scan(__isl_take isl_union_map *umap)
880 {
881 	return isl_union_set_unwrap(union_set_scan(isl_union_map_wrap(umap)));
882 }
883 
union_pw_qpolynomial_poly(__isl_take isl_union_pw_qpolynomial * upwqp)884 static __isl_give isl_union_pw_qpolynomial *union_pw_qpolynomial_poly(
885 	__isl_take isl_union_pw_qpolynomial *upwqp)
886 {
887 	return isl_union_pw_qpolynomial_to_polynomial(upwqp, 0);
888 }
889 
union_pw_qpolynomial_lpoly(__isl_take isl_union_pw_qpolynomial * upwqp)890 static __isl_give isl_union_pw_qpolynomial *union_pw_qpolynomial_lpoly(
891 	__isl_take isl_union_pw_qpolynomial *upwqp)
892 {
893 	return isl_union_pw_qpolynomial_to_polynomial(upwqp, -1);
894 }
895 
union_pw_qpolynomial_upoly(__isl_take isl_union_pw_qpolynomial * upwqp)896 static __isl_give isl_union_pw_qpolynomial *union_pw_qpolynomial_upoly(
897 	__isl_take isl_union_pw_qpolynomial *upwqp)
898 {
899 	return isl_union_pw_qpolynomial_to_polynomial(upwqp, 1);
900 }
901 
902 /* Return the domain of "schedule".
903  */
schedule_domain(__isl_take isl_schedule * schedule)904 static __isl_give isl_union_set *schedule_domain(
905 	__isl_take isl_schedule *schedule)
906 {
907 	isl_union_set *domain;
908 
909 	domain = isl_schedule_get_domain(schedule);
910 	isl_schedule_free(schedule);
911 
912 	return domain;
913 }
914 
915 /* Convert "schedule" to a union map representation.
916  */
schedule_map(__isl_take isl_schedule * schedule)917 static __isl_give isl_union_map *schedule_map(__isl_take isl_schedule *schedule)
918 {
919 	isl_union_map *map;
920 
921 	map = isl_schedule_get_map(schedule);
922 	isl_schedule_free(schedule);
923 
924 	return map;
925 }
926 
927 typedef void *(*isc_un_op_fn)(void *arg);
928 struct isc_un_op {
929 	enum isl_token_type	op;
930 	isl_obj_type		arg;
931 	isl_obj_type		res;
932 	isc_un_op_fn		fn;
933 };
934 struct isc_named_un_op {
935 	char			*name;
936 	struct isc_un_op	op;
937 };
938 struct isc_named_un_op named_un_ops[] = {
939 	{"aff",	{ -1,	isl_obj_union_map,	isl_obj_union_map,
940 		(isc_un_op_fn) &isl_union_map_affine_hull } },
941 	{"aff",	{ -1,	isl_obj_union_set,	isl_obj_union_set,
942 		(isc_un_op_fn) &isl_union_set_affine_hull } },
943 	{"card",	{ -1,	isl_obj_union_set,
944 		isl_obj_union_pw_qpolynomial,
945 		(isc_un_op_fn) &isl_union_set_card } },
946 	{"card",	{ -1,	isl_obj_union_map,
947 		isl_obj_union_pw_qpolynomial,
948 		(isc_un_op_fn) &isl_union_map_card } },
949 	{"coalesce",	{ -1,	isl_obj_union_set,	isl_obj_union_set,
950 		(isc_un_op_fn) &isl_union_set_coalesce } },
951 	{"coalesce",	{ -1,	isl_obj_union_map,	isl_obj_union_map,
952 		(isc_un_op_fn) &isl_union_map_coalesce } },
953 	{"coalesce",	{ -1,	isl_obj_union_pw_qpolynomial,
954 		isl_obj_union_pw_qpolynomial,
955 		(isc_un_op_fn) &isl_union_pw_qpolynomial_coalesce } },
956 	{"coalesce",	{ -1,	isl_obj_union_pw_qpolynomial_fold,
957 		isl_obj_union_pw_qpolynomial_fold,
958 		(isc_un_op_fn) &isl_union_pw_qpolynomial_fold_coalesce } },
959 	{"coefficients",	{ -1,	isl_obj_union_set,
960 		isl_obj_union_set,
961 		(isc_un_op_fn) &isl_union_set_coefficients } },
962 	{"solutions",	{ -1,	isl_obj_union_set,	isl_obj_union_set,
963 		(isc_un_op_fn) &isl_union_set_solutions } },
964 	{"deltas",	{ -1,	isl_obj_union_map,	isl_obj_union_set,
965 		(isc_un_op_fn) &isl_union_map_deltas } },
966 	{"deltas_map",	{ -1,	isl_obj_union_map,	isl_obj_union_map,
967 		(isc_un_op_fn) &isl_union_map_deltas_map } },
968 	{"dom",	{ -1,	isl_obj_schedule,	isl_obj_union_set,
969 		(isc_un_op_fn) &schedule_domain } },
970 	{"dom",	{ -1,	isl_obj_union_map,	isl_obj_union_set,
971 		(isc_un_op_fn) &isl_union_map_domain } },
972 	{"dom",	{ -1,	isl_obj_union_pw_qpolynomial,	isl_obj_union_set,
973 		(isc_un_op_fn) &isl_union_pw_qpolynomial_domain } },
974 	{"dom",	{ -1,	isl_obj_union_pw_qpolynomial_fold,
975 		isl_obj_union_set,
976 		(isc_un_op_fn) &isl_union_pw_qpolynomial_fold_domain } },
977 	{"domain",	{ -1,	isl_obj_schedule,	isl_obj_union_set,
978 		(isc_un_op_fn) &schedule_domain } },
979 	{"domain",	{ -1,	isl_obj_union_map,	isl_obj_union_set,
980 		(isc_un_op_fn) &isl_union_map_domain } },
981 	{"domain",	{ -1,	isl_obj_union_pw_qpolynomial,
982 		isl_obj_union_set,
983 		(isc_un_op_fn) &isl_union_pw_qpolynomial_domain } },
984 	{"domain",	{ -1,	isl_obj_union_pw_qpolynomial_fold,
985 		isl_obj_union_set,
986 		(isc_un_op_fn) &isl_union_pw_qpolynomial_fold_domain } },
987 	{"domain_map",	{ -1,	isl_obj_union_map,	isl_obj_union_map,
988 		(isc_un_op_fn) &isl_union_map_domain_map } },
989 	{"ran",	{ -1,	isl_obj_union_map,	isl_obj_union_set,
990 		(isc_un_op_fn) &isl_union_map_range } },
991 	{"range",	{ -1,	isl_obj_union_map,	isl_obj_union_set,
992 		(isc_un_op_fn) &isl_union_map_range } },
993 	{"range_map",	{ -1,	isl_obj_union_map,	isl_obj_union_map,
994 		(isc_un_op_fn) &isl_union_map_range_map } },
995 	{"identity",	{ -1,	isl_obj_union_set,	isl_obj_union_map,
996 		(isc_un_op_fn) &isl_union_set_identity } },
997 	{"lattice_width",	{ -1,	isl_obj_union_set,
998 		isl_obj_union_pw_qpolynomial,
999 		(isc_un_op_fn) &isl_union_set_lattice_width } },
1000 	{"lb",		{ -1,	isl_obj_union_pw_qpolynomial, isl_obj_list,
1001 		(isc_un_op_fn) &union_pw_qpolynomial_lower_bound } },
1002 	{"lexmin",	{ -1,	isl_obj_union_map,	isl_obj_union_map,
1003 		(isc_un_op_fn) &isl_union_map_lexmin } },
1004 	{"lexmax",	{ -1,	isl_obj_union_map,	isl_obj_union_map,
1005 		(isc_un_op_fn) &isl_union_map_lexmax } },
1006 	{"lexmin",	{ -1,	isl_obj_union_set,	isl_obj_union_set,
1007 		(isc_un_op_fn) &isl_union_set_lexmin } },
1008 	{"lexmax",	{ -1,	isl_obj_union_set,	isl_obj_union_set,
1009 		(isc_un_op_fn) &isl_union_set_lexmax } },
1010 	{"lift",	{ -1,	isl_obj_union_set,	isl_obj_union_set,
1011 		(isc_un_op_fn) &isl_union_set_lift } },
1012 	{"map",	{ -1,	isl_obj_schedule,	isl_obj_union_map,
1013 		(isc_un_op_fn) &schedule_map } },
1014 	{"params",	{ -1,	isl_obj_union_map,	isl_obj_set,
1015 		(isc_un_op_fn) &isl_union_map_params } },
1016 	{"params",	{ -1,	isl_obj_union_set,	isl_obj_set,
1017 		(isc_un_op_fn) &isl_union_set_params } },
1018 	{"poly",	{ -1,	isl_obj_union_map,	isl_obj_union_map,
1019 		(isc_un_op_fn) &isl_union_map_polyhedral_hull } },
1020 	{"poly",	{ -1,	isl_obj_union_set,	isl_obj_union_set,
1021 		(isc_un_op_fn) &isl_union_set_polyhedral_hull } },
1022 	{"poly",	{ -1,	isl_obj_union_pw_qpolynomial,
1023 		isl_obj_union_pw_qpolynomial,
1024 		(isc_un_op_fn) &union_pw_qpolynomial_poly } },
1025 	{"lpoly",	{ -1,	isl_obj_union_pw_qpolynomial,
1026 		isl_obj_union_pw_qpolynomial,
1027 		(isc_un_op_fn) &union_pw_qpolynomial_lpoly } },
1028 	{"upoly",	{ -1,	isl_obj_union_pw_qpolynomial,
1029 		isl_obj_union_pw_qpolynomial,
1030 		(isc_un_op_fn) &union_pw_qpolynomial_upoly } },
1031 #ifdef HAVE_PET
1032 	{"parse_file",	{ -1,	isl_obj_str,	isl_obj_list,
1033 		(isc_un_op_fn) &parse } },
1034 #endif
1035 	{"pow",	{ -1,	isl_obj_union_map,	isl_obj_list,
1036 		(isc_un_op_fn) &union_map_power } },
1037 	{"sample",	{ -1,	isl_obj_union_set,	isl_obj_set,
1038 		(isc_un_op_fn) &union_set_sample } },
1039 	{"sample",	{ -1,	isl_obj_union_map,	isl_obj_map,
1040 		(isc_un_op_fn) &union_map_sample } },
1041 	{"scan",	{ -1,	isl_obj_union_set,	isl_obj_union_set,
1042 		(isc_un_op_fn) &union_set_scan } },
1043 	{"scan",	{ -1,	isl_obj_union_map,	isl_obj_union_map,
1044 		(isc_un_op_fn) &union_map_scan } },
1045 	{"sum",		{ -1,	isl_obj_union_pw_qpolynomial,
1046 		isl_obj_union_pw_qpolynomial,
1047 		(isc_un_op_fn) &isl_union_pw_qpolynomial_sum } },
1048 	{"ub",		{ -1,	isl_obj_union_pw_qpolynomial, isl_obj_list,
1049 		(isc_un_op_fn) &union_pw_qpolynomial_upper_bound } },
1050 	{"unwrap",	{ -1,	isl_obj_union_set,	isl_obj_union_map,
1051 		(isc_un_op_fn) &isl_union_set_unwrap } },
1052 	{"wrap",	{ -1,	isl_obj_union_map,	isl_obj_union_set,
1053 		(isc_un_op_fn) &isl_union_map_wrap } },
1054 	{"zip",	{ -1,	isl_obj_union_map,	isl_obj_union_map,
1055 		(isc_un_op_fn) &isl_union_map_zip } },
1056 	NULL
1057 };
1058 
1059 struct isl_named_obj {
1060 	char		*name;
1061 	struct isl_obj	obj;
1062 };
1063 
free_obj(struct isl_obj obj)1064 static void free_obj(struct isl_obj obj)
1065 {
1066 	obj.type->free(obj.v);
1067 }
1068 
same_name(const void * entry,const void * val)1069 static int same_name(const void *entry, const void *val)
1070 {
1071 	const struct isl_named_obj *named = (const struct isl_named_obj *)entry;
1072 
1073 	return !strcmp(named->name, val);
1074 }
1075 
do_assign(struct isl_ctx * ctx,struct isl_hash_table * table,char * name,struct isl_obj obj)1076 static int do_assign(struct isl_ctx *ctx, struct isl_hash_table *table,
1077 	char *name, struct isl_obj obj)
1078 {
1079 	struct isl_hash_table_entry *entry;
1080 	uint32_t name_hash;
1081 	struct isl_named_obj *named;
1082 
1083 	name_hash = isl_hash_string(isl_hash_init(), name);
1084 	entry = isl_hash_table_find(ctx, table, name_hash, same_name, name, 1);
1085 	if (!entry)
1086 		goto error;
1087 	if (entry->data) {
1088 		named = entry->data;
1089 		free_obj(named->obj);
1090 		free(name);
1091 	} else {
1092 		named = isl_alloc_type(ctx, struct isl_named_obj);
1093 		if (!named)
1094 			goto error;
1095 		named->name = name;
1096 		entry->data = named;
1097 	}
1098 	named->obj = obj;
1099 
1100 	return 0;
1101 error:
1102 	free_obj(obj);
1103 	free(name);
1104 	return -1;
1105 }
1106 
stored_obj(struct isl_ctx * ctx,struct isl_hash_table * table,char * name)1107 static struct isl_obj stored_obj(struct isl_ctx *ctx,
1108 	struct isl_hash_table *table, char *name)
1109 {
1110 	struct isl_obj obj = { isl_obj_none, NULL };
1111 	struct isl_hash_table_entry *entry;
1112 	uint32_t name_hash;
1113 
1114 	name_hash = isl_hash_string(isl_hash_init(), name);
1115 	entry = isl_hash_table_find(ctx, table, name_hash, same_name, name, 0);
1116 	if (!entry) {
1117 	} else if (entry != isl_hash_table_entry_none) {
1118 		struct isl_named_obj *named;
1119 		named = entry->data;
1120 		obj = named->obj;
1121 	} else if (isdigit(name[0]))
1122 		fprintf(stderr, "unknown identifier '$%s'\n", name);
1123 	else
1124 		fprintf(stderr, "unknown identifier '%s'\n", name);
1125 
1126 	free(name);
1127 	obj.v = obj.type->copy(obj.v);
1128 	return obj;
1129 }
1130 
is_subtype(struct isl_obj obj,isl_obj_type super)1131 static int is_subtype(struct isl_obj obj, isl_obj_type super)
1132 {
1133 	if (obj.type == super)
1134 		return 1;
1135 	if (obj.type == isl_obj_map && super == isl_obj_union_map)
1136 		return 1;
1137 	if (obj.type == isl_obj_set && super == isl_obj_union_set)
1138 		return 1;
1139 	if (obj.type == isl_obj_schedule && super == isl_obj_union_map)
1140 		return 1;
1141 	if (obj.type == isl_obj_pw_multi_aff && super == isl_obj_union_set) {
1142 		isl_space *space = isl_pw_multi_aff_get_space(obj.v);
1143 		int is_set = isl_space_is_set(space);
1144 		isl_space_free(space);
1145 		return is_set;
1146 	}
1147 	if (obj.type == isl_obj_pw_qpolynomial &&
1148 	    super == isl_obj_union_pw_qpolynomial)
1149 		return 1;
1150 	if (obj.type == isl_obj_pw_qpolynomial_fold &&
1151 	    super == isl_obj_union_pw_qpolynomial_fold)
1152 		return 1;
1153 	if (obj.type == isl_obj_union_set && isl_union_set_is_empty(obj.v))
1154 		return 1;
1155 	if (obj.type == isl_obj_list) {
1156 		struct isl_list *list = obj.v;
1157 		if (list->n == 2 && list->obj[1].type == isl_obj_bool)
1158 			return is_subtype(list->obj[0], super);
1159 	}
1160 	if (super == isl_obj_str)
1161 		return 1;
1162 	return 0;
1163 }
1164 
obj_at(struct isl_obj obj,int i)1165 static struct isl_obj obj_at(struct isl_obj obj, int i)
1166 {
1167 	struct isl_list *list = obj.v;
1168 
1169 	obj = list->obj[i];
1170 	obj.v = obj.type->copy(obj.v);
1171 
1172 	isl_list_free(list);
1173 
1174 	return obj;
1175 }
1176 
convert(isl_ctx * ctx,struct isl_obj obj,isl_obj_type type)1177 static struct isl_obj convert(isl_ctx *ctx, struct isl_obj obj,
1178 	isl_obj_type type)
1179 {
1180 	if (obj.type == type)
1181 		return obj;
1182 	if (obj.type == isl_obj_pw_multi_aff && type == isl_obj_union_set) {
1183 		isl_set *set = isl_set_from_pw_multi_aff(obj.v);
1184 		obj.type = isl_obj_union_set;
1185 		obj.v = isl_union_set_from_set(set);
1186 		return obj;
1187 	}
1188 	if (obj.type == isl_obj_map && type == isl_obj_union_map) {
1189 		obj.type = isl_obj_union_map;
1190 		obj.v = isl_union_map_from_map(obj.v);
1191 		return obj;
1192 	}
1193 	if (obj.type == isl_obj_schedule && type == isl_obj_union_map) {
1194 		obj.type = isl_obj_union_map;
1195 		obj.v = schedule_map(obj.v);
1196 		return obj;
1197 	}
1198 	if (obj.type == isl_obj_set && type == isl_obj_union_set) {
1199 		obj.type = isl_obj_union_set;
1200 		obj.v = isl_union_set_from_set(obj.v);
1201 		return obj;
1202 	}
1203 	if (obj.type == isl_obj_pw_qpolynomial &&
1204 	    type == isl_obj_union_pw_qpolynomial) {
1205 		obj.type = isl_obj_union_pw_qpolynomial;
1206 		obj.v = isl_union_pw_qpolynomial_from_pw_qpolynomial(obj.v);
1207 		return obj;
1208 	}
1209 	if (obj.type == isl_obj_pw_qpolynomial_fold &&
1210 	    type == isl_obj_union_pw_qpolynomial_fold) {
1211 		obj.type = isl_obj_union_pw_qpolynomial_fold;
1212 		obj.v = isl_union_pw_qpolynomial_fold_from_pw_qpolynomial_fold(obj.v);
1213 		return obj;
1214 	}
1215 	if (obj.type == isl_obj_union_set && isl_union_set_is_empty(obj.v)) {
1216 		if (type == isl_obj_union_map) {
1217 			obj.type = isl_obj_union_map;
1218 			return obj;
1219 		}
1220 		if (type == isl_obj_union_pw_qpolynomial) {
1221 			isl_space *dim = isl_union_set_get_space(obj.v);
1222 			isl_union_set_free(obj.v);
1223 			obj.v = isl_union_pw_qpolynomial_zero(dim);
1224 			obj.type = isl_obj_union_pw_qpolynomial;
1225 			return obj;
1226 		}
1227 		if (type == isl_obj_union_pw_qpolynomial_fold) {
1228 			isl_space *dim = isl_union_set_get_space(obj.v);
1229 			isl_union_set_free(obj.v);
1230 			obj.v = isl_union_pw_qpolynomial_fold_zero(dim,
1231 								isl_fold_list);
1232 			obj.type = isl_obj_union_pw_qpolynomial_fold;
1233 			return obj;
1234 		}
1235 	}
1236 	if (obj.type == isl_obj_list) {
1237 		struct isl_list *list = obj.v;
1238 		if (list->n == 2 && list->obj[1].type == isl_obj_bool)
1239 			return convert(ctx, obj_at(obj, 0), type);
1240 	}
1241 	if (type == isl_obj_str) {
1242 		isl_str *str;
1243 		isl_printer *p;
1244 		char *s;
1245 
1246 		p = isl_printer_to_str(ctx);
1247 		if (!p)
1248 			goto error;
1249 		p = obj.type->print(p, obj.v);
1250 		s = isl_printer_get_str(p);
1251 		isl_printer_free(p);
1252 
1253 		str = isl_str_from_string(ctx, s);
1254 		if (!str)
1255 			goto error;
1256 		free_obj(obj);
1257 		obj.v = str;
1258 		obj.type = isl_obj_str;
1259 		return obj;
1260 
1261 	}
1262 error:
1263 	free_obj(obj);
1264 	obj.type = isl_obj_none;
1265 	obj.v = NULL;
1266 	return obj;
1267 }
1268 
read_bin_op_if_available(struct isl_stream * s,struct isl_obj lhs)1269 static struct isc_bin_op *read_bin_op_if_available(struct isl_stream *s,
1270 	struct isl_obj lhs)
1271 {
1272 	int i;
1273 	int read_tok2 = 0;
1274 	struct isl_token *tok, *tok2;
1275 
1276 	tok = isl_stream_next_token(s);
1277 	if (!tok)
1278 		return NULL;
1279 
1280 	for (i = 0; ; ++i) {
1281 		if (!bin_ops[i].op)
1282 			break;
1283 		if (bin_ops[i].op != isl_token_get_type(tok))
1284 			continue;
1285 		if (!is_subtype(lhs, bin_ops[i].lhs))
1286 			continue;
1287 
1288 		isl_token_free(tok);
1289 		return &bin_ops[i];
1290 	}
1291 
1292 	for (i = 0; ; ++i) {
1293 		if (!named_bin_ops[i].name)
1294 			break;
1295 		if (named_bin_ops[i].op.op != isl_token_get_type(tok))
1296 			continue;
1297 		if (!is_subtype(lhs, named_bin_ops[i].op.lhs))
1298 			continue;
1299 
1300 		isl_token_free(tok);
1301 		return &named_bin_ops[i].op;
1302 	}
1303 
1304 	for (i = 0; ; ++i) {
1305 		if (!compound_bin_ops[i].full)
1306 			break;
1307 		if (compound_bin_ops[i].op1 != isl_token_get_type(tok))
1308 			continue;
1309 		if (!read_tok2)
1310 			tok2 = isl_stream_next_token(s);
1311 		read_tok2 = 1;
1312 		if (compound_bin_ops[i].op2 != isl_token_get_type(tok2))
1313 			continue;
1314 		if (!is_subtype(lhs, compound_bin_ops[i].op.lhs))
1315 			continue;
1316 
1317 		isl_token_free(tok2);
1318 		isl_token_free(tok);
1319 		return &compound_bin_ops[i].op;
1320 	}
1321 
1322 	if (read_tok2)
1323 		isl_stream_push_token(s, tok2);
1324 	isl_stream_push_token(s, tok);
1325 
1326 	return NULL;
1327 }
1328 
read_prefix_un_op_if_available(struct isl_stream * s)1329 static struct isc_un_op *read_prefix_un_op_if_available(struct isl_stream *s)
1330 {
1331 	int i;
1332 	struct isl_token *tok;
1333 
1334 	tok = isl_stream_next_token(s);
1335 	if (!tok)
1336 		return NULL;
1337 
1338 	for (i = 0; ; ++i) {
1339 		if (!named_un_ops[i].name)
1340 			break;
1341 		if (named_un_ops[i].op.op != isl_token_get_type(tok))
1342 			continue;
1343 
1344 		isl_token_free(tok);
1345 		return &named_un_ops[i].op;
1346 	}
1347 
1348 	isl_stream_push_token(s, tok);
1349 
1350 	return NULL;
1351 }
1352 
find_matching_un_op(struct isc_un_op * like,struct isl_obj arg)1353 static struct isc_un_op *find_matching_un_op(struct isc_un_op *like,
1354 	struct isl_obj arg)
1355 {
1356 	int i;
1357 
1358 	for (i = 0; ; ++i) {
1359 		if (!named_un_ops[i].name)
1360 			break;
1361 		if (named_un_ops[i].op.op != like->op)
1362 			continue;
1363 		if (!is_subtype(arg, named_un_ops[i].op.arg))
1364 			continue;
1365 
1366 		return &named_un_ops[i].op;
1367 	}
1368 
1369 	return NULL;
1370 }
1371 
is_assign(struct isl_stream * s)1372 static int is_assign(struct isl_stream *s)
1373 {
1374 	struct isl_token *tok;
1375 	struct isl_token *tok2;
1376 	int assign;
1377 
1378 	tok = isl_stream_next_token(s);
1379 	if (!tok)
1380 		return 0;
1381 	if (isl_token_get_type(tok) != ISL_TOKEN_IDENT) {
1382 		isl_stream_push_token(s, tok);
1383 		return 0;
1384 	}
1385 
1386 	tok2 = isl_stream_next_token(s);
1387 	if (!tok2) {
1388 		isl_stream_push_token(s, tok);
1389 		return 0;
1390 	}
1391 	assign = isl_token_get_type(tok2) == ISL_TOKEN_DEF;
1392 	isl_stream_push_token(s, tok2);
1393 	isl_stream_push_token(s, tok);
1394 
1395 	return assign;
1396 }
1397 
1398 static struct isl_obj read_obj(struct isl_stream *s,
1399 	struct isl_hash_table *table);
1400 static struct isl_obj read_expr(struct isl_stream *s,
1401 	struct isl_hash_table *table);
1402 
read_un_op_expr(struct isl_stream * s,struct isl_hash_table * table,struct isc_un_op * op)1403 static struct isl_obj read_un_op_expr(struct isl_stream *s,
1404 	struct isl_hash_table *table, struct isc_un_op *op)
1405 {
1406 	isl_ctx *ctx;
1407 	struct isl_obj obj = { isl_obj_none, NULL };
1408 
1409 	obj = read_obj(s, table);
1410 	if (!obj.v)
1411 		goto error;
1412 
1413 	op = find_matching_un_op(op, obj);
1414 
1415 	ctx = isl_stream_get_ctx(s);
1416 	if (!op)
1417 		isl_die(ctx, isl_error_invalid,
1418 			"no such unary operator defined on given operand",
1419 			goto error);
1420 
1421 	obj = convert(ctx, obj, op->arg);
1422 	obj.v = op->fn(obj.v);
1423 	obj.type = op->res;
1424 
1425 	return obj;
1426 error:
1427 	free_obj(obj);
1428 	obj.type = isl_obj_none;
1429 	obj.v = NULL;
1430 	return obj;
1431 }
1432 
transitive_closure(struct isl_ctx * ctx,struct isl_obj obj)1433 static struct isl_obj transitive_closure(struct isl_ctx *ctx, struct isl_obj obj)
1434 {
1435 	struct isl_list *list;
1436 	int exact;
1437 
1438 	if (obj.type != isl_obj_union_map)
1439 		obj = convert(ctx, obj, isl_obj_union_map);
1440 	isl_assert(ctx, obj.type == isl_obj_union_map, goto error);
1441 	list = isl_list_alloc(ctx, 2);
1442 	if (!list)
1443 		goto error;
1444 
1445 	list->obj[0].type = isl_obj_union_map;
1446 	list->obj[0].v = isl_union_map_transitive_closure(obj.v, &exact);
1447 	list->obj[1].type = isl_obj_bool;
1448 	list->obj[1].v = exact ? &iscc_bool_true : &iscc_bool_false;
1449 	obj.v = list;
1450 	obj.type = isl_obj_list;
1451 	if (exact < 0 || !list->obj[0].v)
1452 		goto error;
1453 
1454 	return obj;
1455 error:
1456 	free_obj(obj);
1457 	obj.type = isl_obj_none;
1458 	obj.v = NULL;
1459 	return obj;
1460 }
1461 
obj_at_index(struct isl_stream * s,struct isl_obj obj)1462 static struct isl_obj obj_at_index(struct isl_stream *s, struct isl_obj obj)
1463 {
1464 	struct isl_list *list = obj.v;
1465 	struct isl_token *tok;
1466 	isl_ctx *ctx;
1467 	isl_val *v;
1468 	int i;
1469 
1470 	tok = isl_stream_next_token(s);
1471 	if (!tok || isl_token_get_type(tok) != ISL_TOKEN_VALUE) {
1472 		isl_stream_error(s, tok, "expecting index");
1473 		if (tok)
1474 			isl_stream_push_token(s, tok);
1475 		goto error;
1476 	}
1477 	ctx = isl_stream_get_ctx(s);
1478 	v = isl_token_get_val(ctx, tok);
1479 	i = isl_val_get_num_si(v);
1480 	isl_val_free(v);
1481 	isl_token_free(tok);
1482 	isl_assert(ctx, i < list->n, goto error);
1483 	if (isl_stream_eat(s, ']'))
1484 		goto error;
1485 
1486 	return obj_at(obj, i);
1487 error:
1488 	free_obj(obj);
1489 	obj.type = isl_obj_none;
1490 	obj.v = NULL;
1491 	return obj;
1492 }
1493 
apply(struct isl_stream * s,__isl_take isl_union_map * umap,struct isl_hash_table * table)1494 static struct isl_obj apply(struct isl_stream *s, __isl_take isl_union_map *umap,
1495 	struct isl_hash_table *table)
1496 {
1497 	isl_ctx *ctx;
1498 	struct isl_obj obj;
1499 
1500 	obj = read_expr(s, table);
1501 	ctx = isl_stream_get_ctx(s);
1502 	isl_assert(ctx, is_subtype(obj, isl_obj_union_set) ||
1503 			   is_subtype(obj, isl_obj_union_map), goto error);
1504 
1505 	if (obj.type == isl_obj_list) {
1506 		struct isl_list *list = obj.v;
1507 		if (list->n == 2 && list->obj[1].type == isl_obj_bool)
1508 			obj = obj_at(obj, 0);
1509 	}
1510 	if (obj.type == isl_obj_set)
1511 		obj = convert(ctx, obj, isl_obj_union_set);
1512 	else if (obj.type == isl_obj_map)
1513 		obj = convert(ctx, obj, isl_obj_union_map);
1514 	if (obj.type == isl_obj_union_set) {
1515 		obj.v = isl_union_set_apply(obj.v, umap);
1516 	} else
1517 		obj.v = isl_union_map_apply_range(obj.v, umap);
1518 	if (!obj.v)
1519 		goto error2;
1520 
1521 	if (isl_stream_eat(s, ')'))
1522 		goto error2;
1523 
1524 	return obj;
1525 error:
1526 	isl_union_map_free(umap);
1527 error2:
1528 	free_obj(obj);
1529 	obj.type = isl_obj_none;
1530 	obj.v = NULL;
1531 	return obj;
1532 }
1533 
apply_fun_set(struct isl_obj obj,__isl_take isl_union_set * uset)1534 static struct isl_obj apply_fun_set(struct isl_obj obj,
1535 	__isl_take isl_union_set *uset)
1536 {
1537 	if (obj.type == isl_obj_union_pw_qpolynomial) {
1538 		obj.v = isl_union_set_apply_union_pw_qpolynomial(uset, obj.v);
1539 	} else {
1540 		obj.type = isl_obj_list;
1541 		obj.v = union_set_apply_union_pw_qpolynomial_fold(uset, obj.v);
1542 	}
1543 	return obj;
1544 }
1545 
apply_fun_map(struct isl_obj obj,__isl_take isl_union_map * umap)1546 static struct isl_obj apply_fun_map(struct isl_obj obj,
1547 	__isl_take isl_union_map *umap)
1548 {
1549 	if (obj.type == isl_obj_union_pw_qpolynomial) {
1550 		obj.v = isl_union_map_apply_union_pw_qpolynomial(umap, obj.v);
1551 	} else {
1552 		obj.type = isl_obj_list;
1553 		obj.v = union_map_apply_union_pw_qpolynomial_fold(umap, obj.v);
1554 	}
1555 	return obj;
1556 }
1557 
apply_fun(struct isl_stream * s,struct isl_obj obj,struct isl_hash_table * table)1558 static struct isl_obj apply_fun(struct isl_stream *s,
1559 	struct isl_obj obj, struct isl_hash_table *table)
1560 {
1561 	struct isl_obj arg;
1562 	isl_ctx *ctx;
1563 
1564 	arg = read_expr(s, table);
1565 	ctx = isl_stream_get_ctx(s);
1566 	if (!is_subtype(arg, isl_obj_union_map) &&
1567 	    !is_subtype(arg, isl_obj_union_set))
1568 		isl_die(ctx, isl_error_invalid,
1569 			"expecting set of map argument", goto error);
1570 
1571 	if (arg.type == isl_obj_list) {
1572 		struct isl_list *list = arg.v;
1573 		if (list->n == 2 && list->obj[1].type == isl_obj_bool)
1574 			arg = obj_at(arg, 0);
1575 	}
1576 	if (arg.type == isl_obj_set)
1577 		arg = convert(ctx, arg, isl_obj_union_set);
1578 	else if (arg.type == isl_obj_map)
1579 		arg = convert(ctx, arg, isl_obj_union_map);
1580 	if (arg.type == isl_obj_union_set)
1581 		obj = apply_fun_set(obj, arg.v);
1582 	else
1583 		obj = apply_fun_map(obj, arg.v);
1584 	if (!obj.v)
1585 		goto error2;
1586 
1587 	if (isl_stream_eat(s, ')'))
1588 		goto error2;
1589 
1590 	return obj;
1591 error:
1592 	free_obj(arg);
1593 error2:
1594 	free_obj(obj);
1595 	obj.type = isl_obj_none;
1596 	obj.v = NULL;
1597 	return obj;
1598 }
1599 
1600 struct add_vertex_data {
1601 	struct isl_list *list;
1602 	int i;
1603 };
1604 
add_vertex(__isl_take isl_vertex * vertex,void * user)1605 static isl_stat add_vertex(__isl_take isl_vertex *vertex, void *user)
1606 {
1607 	struct add_vertex_data *data = (struct add_vertex_data *)user;
1608 	isl_multi_aff *ma;
1609 	isl_set *dom;
1610 
1611 	ma = isl_vertex_get_expr(vertex);
1612 	dom = isl_set_from_basic_set(isl_vertex_get_domain(vertex));
1613 
1614 	data->list->obj[data->i].type = isl_obj_pw_multi_aff;
1615 	data->list->obj[data->i].v = isl_pw_multi_aff_alloc(dom, ma);
1616 	data->i++;
1617 
1618 	isl_vertex_free(vertex);
1619 
1620 	return isl_stat_ok;
1621 }
1622 
set_vertices(__isl_take isl_set * set,void * user)1623 static isl_stat set_vertices(__isl_take isl_set *set, void *user)
1624 {
1625 	isl_ctx *ctx;
1626 	isl_basic_set *hull;
1627 	isl_vertices *vertices = NULL;
1628 	struct isl_list *list = NULL;
1629 	isl_stat r;
1630 	struct add_vertex_data *data = (struct add_vertex_data *)user;
1631 
1632 	set = isl_set_remove_divs(set);
1633 	hull = isl_set_convex_hull(set);
1634 	vertices = isl_basic_set_compute_vertices(hull);
1635 	isl_basic_set_free(hull);
1636 
1637 	list = data->list;
1638 
1639 	ctx = isl_vertices_get_ctx(vertices);
1640 	data->list = isl_list_alloc(ctx, isl_vertices_get_n_vertices(vertices));
1641 	if (!data->list)
1642 		goto error;
1643 
1644 	data->i = 0;
1645 	r = isl_vertices_foreach_vertex(vertices, &add_vertex, user);
1646 
1647 	data->list = isl_list_concat(list, data->list);
1648 
1649 	isl_vertices_free(vertices);
1650 
1651 	return r;
1652 error:
1653 	data->list = list;
1654 	isl_vertices_free(vertices);
1655 	return isl_stat_error;
1656 }
1657 
vertices(struct isl_stream * s,struct isl_hash_table * table)1658 static struct isl_obj vertices(struct isl_stream *s,
1659 	struct isl_hash_table *table)
1660 {
1661 	isl_ctx *ctx;
1662 	struct isl_obj obj;
1663 	struct isl_list *list = NULL;
1664 	isl_union_set *uset = NULL;
1665 	struct add_vertex_data data = { NULL };
1666 
1667 	obj = read_expr(s, table);
1668 	ctx = isl_stream_get_ctx(s);
1669 	obj = convert(ctx, obj, isl_obj_union_set);
1670 	isl_assert(ctx, obj.type == isl_obj_union_set, goto error);
1671 	uset = obj.v;
1672 	obj.v = NULL;
1673 
1674 	list = isl_list_alloc(ctx, 0);
1675 	if (!list)
1676 		goto error;
1677 
1678 	data.list = list;
1679 
1680 	if (isl_union_set_foreach_set(uset, &set_vertices, &data) < 0)
1681 		goto error;
1682 
1683 	isl_union_set_free(uset);
1684 
1685 	obj.type = isl_obj_list;
1686 	obj.v = data.list;
1687 
1688 	return obj;
1689 error:
1690 	isl_union_set_free(uset);
1691 	isl_list_free(data.list);
1692 	free_obj(obj);
1693 	obj.type = isl_obj_none;
1694 	obj.v = NULL;
1695 	return obj;
1696 }
1697 
type_of(struct isl_stream * s,struct isl_hash_table * table)1698 static struct isl_obj type_of(struct isl_stream *s,
1699 	struct isl_hash_table *table)
1700 {
1701 	struct isl_obj obj;
1702 	const char *type = "unknown";
1703 
1704 	obj = read_expr(s, table);
1705 
1706 	if (obj.type == isl_obj_map ||
1707 	    obj.type == isl_obj_union_map)
1708 		type = "map";
1709 	if (obj.type == isl_obj_set ||
1710 	    obj.type == isl_obj_union_set)
1711 		type = "set";
1712 	if (obj.type == isl_obj_pw_multi_aff)
1713 		type = "piecewise multi-quasiaffine expression";
1714 	if (obj.type == isl_obj_pw_qpolynomial ||
1715 	    obj.type == isl_obj_union_pw_qpolynomial)
1716 		type = "piecewise quasipolynomial";
1717 	if (obj.type == isl_obj_pw_qpolynomial_fold ||
1718 	    obj.type == isl_obj_union_pw_qpolynomial_fold)
1719 		type = "piecewise quasipolynomial fold";
1720 	if (obj.type == isl_obj_list)
1721 		type = "list";
1722 	if (obj.type == isl_obj_bool)
1723 		type = "boolean";
1724 	if (obj.type == isl_obj_str)
1725 		type = "string";
1726 	if (obj.type == isl_obj_val)
1727 		type = "value";
1728 	if (obj.type == isl_obj_schedule)
1729 		type = "schedule";
1730 
1731 	free_obj(obj);
1732 	obj.type = isl_obj_str;
1733 	obj.v = isl_str_from_string(isl_stream_get_ctx(s), strdup(type));
1734 
1735 	return obj;
1736 }
1737 
read_set(struct isl_stream * s,struct isl_hash_table * table)1738 static __isl_give isl_union_set *read_set(struct isl_stream *s,
1739 	struct isl_hash_table *table)
1740 {
1741 	struct isl_obj obj;
1742 	isl_ctx *ctx;
1743 
1744 	obj = read_obj(s, table);
1745 	ctx = isl_stream_get_ctx(s);
1746 	obj = convert(ctx, obj, isl_obj_union_set);
1747 	isl_assert(ctx, obj.type == isl_obj_union_set, goto error);
1748 	return obj.v;
1749 error:
1750 	free_obj(obj);
1751 	return NULL;
1752 }
1753 
read_map(struct isl_stream * s,struct isl_hash_table * table)1754 static __isl_give isl_union_map *read_map(struct isl_stream *s,
1755 	struct isl_hash_table *table)
1756 {
1757 	struct isl_obj obj;
1758 	isl_ctx *ctx;
1759 
1760 	obj = read_obj(s, table);
1761 	ctx = isl_stream_get_ctx(s);
1762 	obj = convert(ctx, obj, isl_obj_union_map);
1763 	isl_assert(ctx, obj.type == isl_obj_union_map, goto error);
1764 	return obj.v;
1765 error:
1766 	free_obj(obj);
1767 	return NULL;
1768 }
1769 
1770 /* Read a schedule in the form of either a schedule (tree) or a union map
1771  * from "s" and store the schedule in "access".
1772  */
access_info_set_schedule(__isl_take isl_union_access_info * access,struct isl_stream * s,struct isl_hash_table * table)1773 static __isl_give isl_union_access_info *access_info_set_schedule(
1774 	__isl_take isl_union_access_info *access, struct isl_stream *s,
1775 	struct isl_hash_table *table)
1776 {
1777 	struct isl_obj obj;
1778 	isl_ctx *ctx;
1779 
1780 	obj = read_obj(s, table);
1781 	if (obj.type == isl_obj_schedule)
1782 		return isl_union_access_info_set_schedule(access, obj.v);
1783 	ctx = isl_stream_get_ctx(s);
1784 	obj = convert(ctx, obj, isl_obj_union_map);
1785 
1786 	return isl_union_access_info_set_schedule_map(access, obj.v);
1787 }
1788 
last_any(struct isl_stream * s,struct isl_hash_table * table,__isl_take isl_union_map * must_source,__isl_take isl_union_map * may_source)1789 static struct isl_obj last_any(struct isl_stream *s,
1790 	struct isl_hash_table *table, __isl_take isl_union_map *must_source,
1791 	__isl_take isl_union_map *may_source)
1792 {
1793 	struct isl_obj obj = { isl_obj_none, NULL };
1794 	isl_union_access_info *access;
1795 	isl_union_flow *flow;
1796 	isl_union_map *sink = NULL;
1797 	isl_union_map *may_dep;
1798 
1799 	if (isl_stream_eat(s, iscc_op[ISCC_BEFORE]))
1800 		goto error;
1801 
1802 	sink = read_map(s, table);
1803 	if (!sink)
1804 		goto error;
1805 
1806 	if (isl_stream_eat(s, iscc_op[ISCC_UNDER]))
1807 		goto error;
1808 
1809 	access = isl_union_access_info_from_sink(sink);
1810 	access = isl_union_access_info_set_must_source(access, must_source);
1811 	access = isl_union_access_info_set_may_source(access, may_source);
1812 	access = access_info_set_schedule(access, s, table);
1813 	flow = isl_union_access_info_compute_flow(access);
1814 	may_dep = isl_union_flow_get_may_dependence(flow);
1815 	isl_union_flow_free(flow);
1816 
1817 	if (!may_dep)
1818 		return obj;
1819 
1820 	obj.type = isl_obj_union_map;
1821 	obj.v = may_dep;
1822 
1823 	return obj;
1824 error:
1825 	isl_union_map_free(may_source);
1826 	isl_union_map_free(must_source);
1827 	isl_union_map_free(sink);
1828 	free_obj(obj);
1829 	obj.type = isl_obj_none;
1830 	obj.v = NULL;
1831 	return obj;
1832 }
1833 
any(struct isl_stream * s,struct isl_hash_table * table)1834 static struct isl_obj any(struct isl_stream *s, struct isl_hash_table *table)
1835 {
1836 	struct isl_obj obj = { isl_obj_none, NULL };
1837 	isl_union_access_info *access;
1838 	isl_union_flow *flow;
1839 	isl_union_map *may_source = NULL;
1840 	isl_union_map *sink = NULL;
1841 	isl_union_map *may_dep;
1842 
1843 	may_source = read_map(s, table);
1844 	if (!may_source)
1845 		goto error;
1846 
1847 	if (isl_stream_eat_if_available(s, iscc_op[ISCC_LAST])) {
1848 		isl_union_map *must_source;
1849 		must_source = read_map(s, table);
1850 		if (!must_source)
1851 			goto error;
1852 		return last_any(s, table, must_source, may_source);
1853 	}
1854 
1855 	if (isl_stream_eat(s, iscc_op[ISCC_BEFORE]))
1856 		goto error;
1857 
1858 	sink = read_map(s, table);
1859 	if (!sink)
1860 		goto error;
1861 
1862 	if (isl_stream_eat(s, iscc_op[ISCC_UNDER]))
1863 		goto error;
1864 
1865 	access = isl_union_access_info_from_sink(sink);
1866 	access = isl_union_access_info_set_may_source(access, may_source);
1867 	access = access_info_set_schedule(access, s, table);
1868 	flow = isl_union_access_info_compute_flow(access);
1869 	may_dep = isl_union_flow_get_may_dependence(flow);
1870 	isl_union_flow_free(flow);
1871 
1872 	if (!may_dep)
1873 		return obj;
1874 
1875 	obj.type = isl_obj_union_map;
1876 	obj.v = may_dep;
1877 
1878 	return obj;
1879 error:
1880 	isl_union_map_free(may_source);
1881 	isl_union_map_free(sink);
1882 	free_obj(obj);
1883 	obj.type = isl_obj_none;
1884 	obj.v = NULL;
1885 	return obj;
1886 }
1887 
last(struct isl_stream * s,struct isl_hash_table * table)1888 static struct isl_obj last(struct isl_stream *s, struct isl_hash_table *table)
1889 {
1890 	struct isl_obj obj = { isl_obj_none, NULL };
1891 	struct isl_list *list = NULL;
1892 	isl_union_access_info *access;
1893 	isl_union_flow *flow;
1894 	isl_union_map *must_source = NULL;
1895 	isl_union_map *sink = NULL;
1896 	isl_union_map *must_dep;
1897 	isl_union_map *must_no_source;
1898 
1899 	must_source = read_map(s, table);
1900 	if (!must_source)
1901 		goto error;
1902 
1903 	if (isl_stream_eat_if_available(s, iscc_op[ISCC_ANY])) {
1904 		isl_union_map *may_source;
1905 		may_source = read_map(s, table);
1906 		if (!may_source)
1907 			goto error;
1908 		return last_any(s, table, must_source, may_source);
1909 	}
1910 
1911 	list = isl_list_alloc(isl_stream_get_ctx(s), 2);
1912 	if (!list)
1913 		goto error;
1914 
1915 	if (isl_stream_eat(s, iscc_op[ISCC_BEFORE]))
1916 		goto error;
1917 
1918 	sink = read_map(s, table);
1919 	if (!sink)
1920 		goto error;
1921 
1922 	if (isl_stream_eat(s, iscc_op[ISCC_UNDER]))
1923 		goto error;
1924 
1925 	access = isl_union_access_info_from_sink(sink);
1926 	access = isl_union_access_info_set_must_source(access, must_source);
1927 	access = access_info_set_schedule(access, s, table);
1928 	flow = isl_union_access_info_compute_flow(access);
1929 	must_dep = isl_union_flow_get_must_dependence(flow);
1930 	must_no_source = isl_union_flow_get_must_no_source(flow);
1931 	isl_union_flow_free(flow);
1932 
1933 	list->obj[0].type = isl_obj_union_map;
1934 	list->obj[0].v = must_dep;
1935 	list->obj[1].type = isl_obj_union_map;
1936 	list->obj[1].v = must_no_source;
1937 
1938 	if (!must_dep || !must_no_source) {
1939 		isl_list_free(list);
1940 		return obj;
1941 	}
1942 
1943 	obj.v = list;
1944 	obj.type = isl_obj_list;
1945 
1946 	return obj;
1947 error:
1948 	isl_list_free(list);
1949 	isl_union_map_free(must_source);
1950 	isl_union_map_free(sink);
1951 	free_obj(obj);
1952 	obj.type = isl_obj_none;
1953 	obj.v = NULL;
1954 	return obj;
1955 }
1956 
get_schedule(struct isl_stream * s,struct isl_hash_table * table)1957 static __isl_give isl_schedule *get_schedule(struct isl_stream *s,
1958 	struct isl_hash_table *table)
1959 {
1960 	isl_union_set *domain;
1961 	isl_union_map *validity;
1962 	isl_union_map *proximity;
1963 
1964 	domain = read_set(s, table);
1965 	if (!domain)
1966 		return NULL;
1967 
1968 	validity = isl_union_map_empty(isl_union_set_get_space(domain));
1969 	proximity = isl_union_map_empty(isl_union_set_get_space(domain));
1970 
1971 	for (;;) {
1972 		isl_union_map *umap;
1973 		if (isl_stream_eat_if_available(s, iscc_op[ISCC_RESPECTING])) {
1974 			umap = read_map(s, table);
1975 			validity = isl_union_map_union(validity, umap);
1976 		} else if (isl_stream_eat_if_available(s, iscc_op[ISCC_MINIMIZING])) {
1977 			umap = read_map(s, table);
1978 			proximity = isl_union_map_union(proximity, umap);
1979 		} else
1980 			break;
1981 	}
1982 
1983 	return isl_union_set_compute_schedule(domain, validity, proximity);
1984 }
1985 
schedule(struct isl_stream * s,struct isl_hash_table * table)1986 static struct isl_obj schedule(struct isl_stream *s,
1987 	struct isl_hash_table *table)
1988 {
1989 	struct isl_obj obj = { isl_obj_none, NULL };
1990 	isl_schedule *schedule;
1991 
1992 	schedule = get_schedule(s, table);
1993 
1994 	obj.v = schedule;
1995 	obj.type = isl_obj_schedule;
1996 
1997 	return obj;
1998 }
1999 
2000 /* Read a schedule for code generation in the form of either
2001  * a schedule tree or a union map.
2002  */
get_codegen_schedule(struct isl_stream * s,struct isl_hash_table * table)2003 static struct isl_obj get_codegen_schedule(struct isl_stream *s,
2004 	struct isl_hash_table *table)
2005 {
2006 	struct isl_obj obj;
2007 	isl_ctx *ctx;
2008 
2009 	obj = read_obj(s, table);
2010 	ctx = isl_stream_get_ctx(s);
2011 
2012 	if (obj.type == isl_obj_schedule)
2013 		return obj;
2014 	if (is_subtype(obj, isl_obj_union_map))
2015 		return convert(ctx, obj, isl_obj_union_map);
2016 
2017 	free_obj(obj);
2018 	obj.v = NULL;
2019 	obj.type = isl_obj_none;
2020 	isl_die(ctx, isl_error_invalid, "expecting schedule or map",
2021 		return obj);
2022 }
2023 
2024 /* Generate an AST for the given schedule and options and return the AST.
2025  */
get_ast_from_union_map(__isl_take isl_union_map * schedule,__isl_take isl_union_map * options)2026 static __isl_give isl_ast_node *get_ast_from_union_map(
2027 	__isl_take isl_union_map *schedule, __isl_take isl_union_map *options)
2028 {
2029 	isl_space *space;
2030 	isl_set *context;
2031 	isl_ast_build *build;
2032 	isl_ast_node *tree;
2033 
2034 	space = isl_union_map_get_space(schedule);
2035 	context = isl_set_universe(isl_space_params(space));
2036 
2037 	build = isl_ast_build_from_context(context);
2038 	build = isl_ast_build_set_options(build, options);
2039 	tree = isl_ast_build_ast_from_schedule(build, schedule);
2040 	isl_ast_build_free(build);
2041 
2042 	return tree;
2043 }
2044 
2045 /* Generate an AST for the given schedule and return the AST.
2046  */
get_ast_from_schedule(__isl_take isl_schedule * schedule)2047 static __isl_give isl_ast_node *get_ast_from_schedule(
2048 	__isl_take isl_schedule *schedule)
2049 {
2050 	isl_ast_build *build;
2051 	isl_ast_node *tree;
2052 
2053 	build = isl_ast_build_alloc(isl_schedule_get_ctx(schedule));
2054 	tree = isl_ast_build_node_from_schedule(build, schedule);
2055 	isl_ast_build_free(build);
2056 
2057 	return tree;
2058 }
2059 
2060 /* Print the AST "tree" on the printer "p".
2061  */
print_ast(__isl_take isl_printer * p,__isl_take isl_ast_node * tree)2062 static __isl_give isl_printer *print_ast(__isl_take isl_printer *p,
2063 	__isl_take isl_ast_node *tree)
2064 {
2065 	int format;
2066 
2067 	format = isl_printer_get_output_format(p);
2068 	p = isl_printer_set_output_format(p, ISL_FORMAT_C);
2069 	p = isl_printer_print_ast_node(p, tree);
2070 	p = isl_printer_set_output_format(p, format);
2071 
2072 	isl_ast_node_free(tree);
2073 
2074 	return p;
2075 }
2076 
2077 /* Perform the codegen operation.
2078  * In particular, read a schedule, check if the user has specified any options
2079  * and then generate an AST from the schedule (and options) and print it.
2080  * In case the schedule is specified as a schedule tree, the AST generation
2081  * options are embedded in the schedule, so they are not read in separately.
2082  */
codegen(struct isl_stream * s,struct isl_hash_table * table,__isl_take isl_printer * p)2083 static __isl_give isl_printer *codegen(struct isl_stream *s,
2084 	struct isl_hash_table *table, __isl_take isl_printer *p)
2085 {
2086 	struct isl_obj obj;
2087 	isl_ast_node *tree;
2088 
2089 	obj = get_codegen_schedule(s, table);
2090 	if (!obj.v)
2091 		return p;
2092 
2093 	if (obj.type == isl_obj_schedule) {
2094 		isl_schedule *schedule = obj.v;
2095 
2096 		tree = get_ast_from_schedule(schedule);
2097 	} else {
2098 		isl_union_map *schedule = obj.v;
2099 		isl_union_map *options;
2100 
2101 		if (isl_stream_eat_if_available(s, iscc_op[ISCC_USING]))
2102 			options = read_map(s, table);
2103 		else
2104 			options = isl_union_map_empty(
2105 					    isl_union_map_get_space(schedule));
2106 
2107 		tree = get_ast_from_union_map(schedule, options);
2108 	}
2109 
2110 	if (tree)
2111 		p = print_ast(p, tree);
2112 
2113 	isl_stream_eat(s, ';');
2114 
2115 	return p;
2116 }
2117 
power(struct isl_stream * s,struct isl_obj obj)2118 static struct isl_obj power(struct isl_stream *s, struct isl_obj obj)
2119 {
2120 	struct isl_token *tok;
2121 	isl_ctx *ctx;
2122 	isl_val *v;
2123 
2124 	ctx = isl_stream_get_ctx(s);
2125 	if (isl_stream_eat_if_available(s, '+'))
2126 		return transitive_closure(ctx, obj);
2127 
2128 	isl_assert(ctx, is_subtype(obj, isl_obj_union_map), goto error);
2129 	if (obj.type != isl_obj_union_map)
2130 		obj = convert(ctx, obj, isl_obj_union_map);
2131 
2132 	tok = isl_stream_next_token(s);
2133 	if (!tok || isl_token_get_type(tok) != ISL_TOKEN_VALUE) {
2134 		isl_stream_error(s, tok, "expecting integer exponent");
2135 		if (tok)
2136 			isl_stream_push_token(s, tok);
2137 		goto error;
2138 	}
2139 
2140 	v = isl_token_get_val(ctx, tok);
2141 	if (isl_val_is_zero(v)) {
2142 		isl_stream_error(s, tok, "expecting non-zero exponent");
2143 		isl_val_free(v);
2144 		if (tok)
2145 			isl_stream_push_token(s, tok);
2146 		goto error;
2147 	}
2148 
2149 	obj.v = isl_union_map_fixed_power_val(obj.v, v);
2150 	isl_token_free(tok);
2151 	if (!obj.v)
2152 		goto error;
2153 
2154 	return obj;
2155 error:
2156 	free_obj(obj);
2157 	obj.type = isl_obj_none;
2158 	obj.v = NULL;
2159 	return obj;
2160 }
2161 
check_assert(struct isl_stream * s,struct isl_hash_table * table)2162 static struct isl_obj check_assert(struct isl_stream *s,
2163 	struct isl_hash_table *table)
2164 {
2165 	struct isl_obj obj;
2166 	isl_ctx *ctx;
2167 
2168 	obj = read_expr(s, table);
2169 	ctx = isl_stream_get_ctx(s);
2170 	if (obj.type != isl_obj_bool)
2171 		isl_die(ctx, isl_error_invalid,
2172 			"expecting boolean expression", goto error);
2173 	if (obj.v != &iscc_bool_true)
2174 		isl_die(ctx, isl_error_unknown,
2175 			"assertion failed", abort());
2176 error:
2177 	free_obj(obj);
2178 	obj.type = isl_obj_none;
2179 	obj.v = NULL;
2180 	return obj;
2181 }
2182 
read_from_file(struct isl_stream * s)2183 static struct isl_obj read_from_file(struct isl_stream *s)
2184 {
2185 	isl_ctx *ctx;
2186 	struct isl_obj obj;
2187 	struct isl_token *tok;
2188 	struct isl_stream *s_file;
2189 	struct iscc_options *options;
2190 	char *name;
2191 	FILE *file;
2192 
2193 	tok = isl_stream_next_token(s);
2194 	if (!tok || isl_token_get_type(tok) != ISL_TOKEN_STRING) {
2195 		isl_stream_error(s, tok, "expecting filename");
2196 		isl_token_free(tok);
2197 		goto error;
2198 	}
2199 
2200 	ctx = isl_stream_get_ctx(s);
2201 	options = isl_ctx_peek_iscc_options(ctx);
2202 	if (!options || !options->io) {
2203 		isl_token_free(tok);
2204 		isl_die(ctx, isl_error_invalid,
2205 			"read operation not allowed", goto error);
2206 	}
2207 
2208 	name = isl_token_get_str(ctx, tok);
2209 	isl_token_free(tok);
2210 	file = fopen(name, "r");
2211 	free(name);
2212 	isl_assert(ctx, file, goto error);
2213 
2214 	s_file = isl_stream_new_file(ctx, file);
2215 	if (!s_file) {
2216 		fclose(file);
2217 		goto error;
2218 	}
2219 
2220 	obj = isl_stream_read_obj(s_file);
2221 
2222 	isl_stream_free(s_file);
2223 	fclose(file);
2224 
2225 	return obj;
2226 error:
2227 	obj.type = isl_obj_none;
2228 	obj.v = NULL;
2229 	return obj;
2230 }
2231 
write_to_file(struct isl_stream * s,struct isl_hash_table * table)2232 static struct isl_obj write_to_file(struct isl_stream *s,
2233 	struct isl_hash_table *table)
2234 {
2235 	struct isl_obj obj = { isl_obj_none, NULL };
2236 	struct isl_token *tok;
2237 	struct iscc_options *options;
2238 	char *name;
2239 	FILE *file;
2240 	isl_ctx *ctx;
2241 	isl_printer *p;
2242 
2243 	tok = isl_stream_next_token(s);
2244 	if (!tok || isl_token_get_type(tok) != ISL_TOKEN_STRING) {
2245 		isl_stream_error(s, tok, "expecting filename");
2246 		isl_token_free(tok);
2247 		goto error;
2248 	}
2249 
2250 	obj = read_expr(s, table);
2251 
2252 	ctx = isl_stream_get_ctx(s);
2253 	options = isl_ctx_peek_iscc_options(ctx);
2254 	if (!options || !options->io) {
2255 		isl_token_free(tok);
2256 		isl_die(ctx, isl_error_invalid,
2257 			"write operation not allowed", goto error);
2258 	}
2259 
2260 	name = isl_token_get_str(ctx, tok);
2261 	isl_token_free(tok);
2262 	file = fopen(name, "w");
2263 	free(name);
2264 	if (!file)
2265 		isl_die(ctx, isl_error_unknown,
2266 			"could not open file for writing", goto error);
2267 
2268 	p = isl_printer_to_file(ctx, file);
2269 	p = isl_printer_set_output_format(p, options->format);
2270 	p = obj.type->print(p, obj.v);
2271 	p = isl_printer_end_line(p);
2272 	isl_printer_free(p);
2273 
2274 	fclose(file);
2275 error:
2276 	free_obj(obj);
2277 	obj.type = isl_obj_none;
2278 	obj.v = NULL;
2279 	return obj;
2280 }
2281 
read_string_if_available(struct isl_stream * s)2282 static struct isl_obj read_string_if_available(struct isl_stream *s)
2283 {
2284 	struct isl_token *tok;
2285 	struct isl_obj obj = { isl_obj_none, NULL };
2286 
2287 	tok = isl_stream_next_token(s);
2288 	if (!tok)
2289 		return obj;
2290 	if (isl_token_get_type(tok) == ISL_TOKEN_STRING) {
2291 		isl_str *str;
2292 		str = isl_str_alloc(isl_stream_get_ctx(s));
2293 		if (!str)
2294 			goto error;
2295 		str->s = isl_token_get_str(isl_stream_get_ctx(s), tok);
2296 		isl_token_free(tok);
2297 		obj.v = str;
2298 		obj.type = isl_obj_str;
2299 	} else
2300 		isl_stream_push_token(s, tok);
2301 	return obj;
2302 error:
2303 	isl_token_free(tok);
2304 	return obj;
2305 }
2306 
read_bool_if_available(struct isl_stream * s)2307 static struct isl_obj read_bool_if_available(struct isl_stream *s)
2308 {
2309 	struct isl_token *tok;
2310 	struct isl_obj obj = { isl_obj_none, NULL };
2311 	int type;
2312 
2313 	tok = isl_stream_next_token(s);
2314 	if (!tok)
2315 		return obj;
2316 	type = isl_token_get_type(tok);
2317 	if (type == ISL_TOKEN_FALSE || type == ISL_TOKEN_TRUE) {
2318 		int is_true = type == ISL_TOKEN_TRUE;
2319 		isl_token_free(tok);
2320 		obj.v = is_true ? &iscc_bool_true : &iscc_bool_false;
2321 		obj.type = isl_obj_bool;
2322 	} else
2323 		isl_stream_push_token(s, tok);
2324 	return obj;
2325 }
2326 
read_ident(struct isl_stream * s)2327 static __isl_give char *read_ident(struct isl_stream *s)
2328 {
2329 	char *name;
2330 	isl_val *v;
2331 	struct isl_token *tok, *tok2;
2332 
2333 	name = isl_stream_read_ident_if_available(s);
2334 	if (name)
2335 		return name;
2336 
2337 	tok = isl_stream_next_token(s);
2338 	if (!tok)
2339 		return NULL;
2340 	if (isl_token_get_type(tok) != '$') {
2341 		isl_stream_push_token(s, tok);
2342 		return NULL;
2343 	}
2344 	tok2 = isl_stream_next_token(s);
2345 	if (!tok2 || isl_token_get_type(tok2) != ISL_TOKEN_VALUE) {
2346 		if (tok2)
2347 			isl_stream_push_token(s, tok2);
2348 		isl_stream_push_token(s, tok);
2349 		return NULL;
2350 	}
2351 
2352 	v = isl_token_get_val(isl_stream_get_ctx(s), tok2);
2353 	name = isl_val_to_str(v);
2354 	isl_val_free(v);
2355 	isl_token_free(tok);
2356 	isl_token_free(tok2);
2357 
2358 	return name;
2359 }
2360 
read_list(struct isl_stream * s,struct isl_hash_table * table,struct isl_obj obj)2361 static struct isl_obj read_list(struct isl_stream *s,
2362 	struct isl_hash_table *table, struct isl_obj obj)
2363 {
2364 	struct isl_list *list;
2365 
2366 	list = isl_list_alloc(isl_stream_get_ctx(s), 2);
2367 	if (!list)
2368 		goto error;
2369 	list->obj[0] = obj;
2370 	list->obj[1] = read_obj(s, table);
2371 	obj.v = list;
2372 	obj.type = isl_obj_list;
2373 
2374 	if (!list->obj[1].v)
2375 		goto error;
2376 
2377 	while (isl_stream_eat_if_available(s, ',')) {
2378 		obj.v = list = isl_list_add_obj(list, read_obj(s, table));
2379 		if (!obj.v)
2380 			goto error;
2381 	}
2382 
2383 	return obj;
2384 error:
2385 	free_obj(obj);
2386 	obj.type = isl_obj_none;
2387 	obj.v = NULL;
2388 	return obj;
2389 }
2390 
read_obj(struct isl_stream * s,struct isl_hash_table * table)2391 static struct isl_obj read_obj(struct isl_stream *s,
2392 	struct isl_hash_table *table)
2393 {
2394 	isl_ctx *ctx;
2395 	struct isl_obj obj = { isl_obj_none, NULL };
2396 	char *name = NULL;
2397 	struct isc_un_op *op = NULL;
2398 
2399 	obj = read_string_if_available(s);
2400 	if (obj.v)
2401 		return obj;
2402 	obj = read_bool_if_available(s);
2403 	if (obj.v)
2404 		return obj;
2405 	ctx = isl_stream_get_ctx(s);
2406 	if (isl_stream_eat_if_available(s, '(')) {
2407 		if (isl_stream_next_token_is(s, ')')) {
2408 			obj.type = isl_obj_list;
2409 			obj.v = isl_list_alloc(ctx, 0);
2410 		} else {
2411 			obj = read_expr(s, table);
2412 			if (obj.v && isl_stream_eat_if_available(s, ','))
2413 				obj = read_list(s, table, obj);
2414 		}
2415 		if (!obj.v || isl_stream_eat(s, ')'))
2416 			goto error;
2417 	} else {
2418 		op = read_prefix_un_op_if_available(s);
2419 		if (op)
2420 			return read_un_op_expr(s, table, op);
2421 
2422 		if (isl_stream_eat_if_available(s, iscc_op[ISCC_ASSERT]))
2423 			return check_assert(s, table);
2424 		if (isl_stream_eat_if_available(s, iscc_op[ISCC_READ]))
2425 			return read_from_file(s);
2426 		if (isl_stream_eat_if_available(s, iscc_op[ISCC_WRITE]))
2427 			return write_to_file(s, table);
2428 		if (isl_stream_eat_if_available(s, iscc_op[ISCC_VERTICES]))
2429 			return vertices(s, table);
2430 		if (isl_stream_eat_if_available(s, iscc_op[ISCC_ANY]))
2431 			return any(s, table);
2432 		if (isl_stream_eat_if_available(s, iscc_op[ISCC_LAST]))
2433 			return last(s, table);
2434 		if (isl_stream_eat_if_available(s, iscc_op[ISCC_SCHEDULE]))
2435 			return schedule(s, table);
2436 		if (isl_stream_eat_if_available(s, iscc_op[ISCC_TYPEOF]))
2437 			return type_of(s, table);
2438 
2439 		name = read_ident(s);
2440 		if (name)
2441 			obj = stored_obj(ctx, table, name);
2442 		else
2443 			obj = isl_stream_read_obj(s);
2444 		if (!obj.v)
2445 			goto error;
2446 	}
2447 
2448 	if (isl_stream_eat_if_available(s, '^'))
2449 		obj = power(s, obj);
2450 	else if (obj.type == isl_obj_list && isl_stream_eat_if_available(s, '['))
2451 		obj = obj_at_index(s, obj);
2452 	else if (is_subtype(obj, isl_obj_union_map) &&
2453 		 isl_stream_eat_if_available(s, '(')) {
2454 		obj = convert(ctx, obj, isl_obj_union_map);
2455 		obj = apply(s, obj.v, table);
2456 	} else if (is_subtype(obj, isl_obj_union_pw_qpolynomial) &&
2457 		   isl_stream_eat_if_available(s, '(')) {
2458 		obj = convert(ctx, obj, isl_obj_union_pw_qpolynomial);
2459 		obj = apply_fun(s, obj, table);
2460 	} else if (is_subtype(obj, isl_obj_union_pw_qpolynomial_fold) &&
2461 		   isl_stream_eat_if_available(s, '(')) {
2462 		obj = convert(ctx, obj, isl_obj_union_pw_qpolynomial_fold);
2463 		obj = apply_fun(s, obj, table);
2464 	}
2465 
2466 	return obj;
2467 error:
2468 	free_obj(obj);
2469 	obj.type = isl_obj_none;
2470 	obj.v = NULL;
2471 	return obj;
2472 }
2473 
find_matching_bin_op(struct isc_bin_op * like,struct isl_obj lhs,struct isl_obj rhs)2474 static struct isc_bin_op *find_matching_bin_op(struct isc_bin_op *like,
2475 	struct isl_obj lhs, struct isl_obj rhs)
2476 {
2477 	int i;
2478 
2479 	for (i = 0; ; ++i) {
2480 		if (!bin_ops[i].op)
2481 			break;
2482 		if (bin_ops[i].op != like->op)
2483 			continue;
2484 		if (!is_subtype(lhs, bin_ops[i].lhs))
2485 			continue;
2486 		if (!is_subtype(rhs, bin_ops[i].rhs))
2487 			continue;
2488 
2489 		return &bin_ops[i];
2490 	}
2491 
2492 	for (i = 0; ; ++i) {
2493 		if (!named_bin_ops[i].name)
2494 			break;
2495 		if (named_bin_ops[i].op.op != like->op)
2496 			continue;
2497 		if (!is_subtype(lhs, named_bin_ops[i].op.lhs))
2498 			continue;
2499 		if (!is_subtype(rhs, named_bin_ops[i].op.rhs))
2500 			continue;
2501 
2502 		return &named_bin_ops[i].op;
2503 	}
2504 
2505 	for (i = 0; ; ++i) {
2506 		if (!compound_bin_ops[i].full)
2507 			break;
2508 		if (compound_bin_ops[i].op.op != like->op)
2509 			continue;
2510 		if (!is_subtype(lhs, compound_bin_ops[i].op.lhs))
2511 			continue;
2512 		if (!is_subtype(rhs, compound_bin_ops[i].op.rhs))
2513 			continue;
2514 
2515 		return &compound_bin_ops[i].op;
2516 	}
2517 
2518 	return NULL;
2519 }
2520 
next_is_neg_int(struct isl_stream * s)2521 static int next_is_neg_int(struct isl_stream *s)
2522 {
2523 	struct isl_token *tok;
2524 	int ret;
2525 
2526 	tok = isl_stream_next_token(s);
2527 	if (tok && isl_token_get_type(tok) == ISL_TOKEN_VALUE) {
2528 		isl_val *v;
2529 		v = isl_token_get_val(isl_stream_get_ctx(s), tok);
2530 		ret = isl_val_is_neg(v);
2531 		isl_val_free(v);
2532 	} else
2533 		ret = 0;
2534 	isl_stream_push_token(s, tok);
2535 
2536 	return ret;
2537 }
2538 
call_bin_op(isl_ctx * ctx,struct isc_bin_op * op,struct isl_obj lhs,struct isl_obj rhs)2539 static struct isl_obj call_bin_op(isl_ctx *ctx, struct isc_bin_op *op,
2540 	struct isl_obj lhs, struct isl_obj rhs)
2541 {
2542 	struct isl_obj obj;
2543 
2544 	lhs = convert(ctx, lhs, op->lhs);
2545 	rhs = convert(ctx, rhs, op->rhs);
2546 	if (op->res != isl_obj_bool)
2547 		obj.v = op->o.fn(lhs.v, rhs.v);
2548 	else {
2549 		int res = op->o.test(lhs.v, rhs.v);
2550 		free_obj(lhs);
2551 		free_obj(rhs);
2552 		obj.v = iscc_bool_from_int(res);
2553 	}
2554 	obj.type = op->res;
2555 
2556 	return obj;
2557 }
2558 
read_expr(struct isl_stream * s,struct isl_hash_table * table)2559 static struct isl_obj read_expr(struct isl_stream *s,
2560 	struct isl_hash_table *table)
2561 {
2562 	isl_ctx *ctx;
2563 	struct isl_obj obj = { isl_obj_none, NULL };
2564 	struct isl_obj right_obj = { isl_obj_none, NULL };
2565 
2566 	obj = read_obj(s, table);
2567 	ctx = isl_stream_get_ctx(s);
2568 	for (; obj.v;) {
2569 		struct isc_bin_op *op = NULL;
2570 
2571 		op = read_bin_op_if_available(s, obj);
2572 		if (!op)
2573 			break;
2574 
2575 		right_obj = read_obj(s, table);
2576 
2577 		op = find_matching_bin_op(op, obj, right_obj);
2578 
2579 		if (!op)
2580 			isl_die(ctx, isl_error_invalid,
2581 			    "no such binary operator defined on given operands",
2582 			    goto error);
2583 
2584 		obj = call_bin_op(ctx, op, obj, right_obj);
2585 	}
2586 
2587 	if (obj.type == isl_obj_val && next_is_neg_int(s)) {
2588 		right_obj = read_obj(s, table);
2589 		obj.v = isl_val_add(obj.v, right_obj.v);
2590 	}
2591 
2592 	return obj;
2593 error:
2594 	free_obj(right_obj);
2595 	free_obj(obj);
2596 	obj.type = isl_obj_none;
2597 	obj.v = NULL;
2598 	return obj;
2599 }
2600 
2601 static __isl_give isl_printer *source_file(struct isl_stream *s,
2602 	struct isl_hash_table *table, __isl_take isl_printer *p);
2603 
2604 /* Print "obj" to the printer "p".
2605  * If the object is a schedule, then print it in block format.
2606  */
print_obj(__isl_take isl_printer * p,struct isl_obj obj)2607 static __isl_give isl_printer *print_obj(__isl_take isl_printer *p,
2608 	struct isl_obj obj)
2609 {
2610 	if (obj.type != isl_obj_schedule)
2611 		return obj.type->print(p, obj.v);
2612 
2613 	p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_BLOCK);
2614 	p = obj.type->print(p, obj.v);
2615 	p = isl_printer_set_yaml_style(p, ISL_YAML_STYLE_FLOW);
2616 
2617 	return p;
2618 }
2619 
read_line(struct isl_stream * s,struct isl_hash_table * table,__isl_take isl_printer * p,int tty)2620 static __isl_give isl_printer *read_line(struct isl_stream *s,
2621 	struct isl_hash_table *table, __isl_take isl_printer *p, int tty)
2622 {
2623 	isl_ctx *ctx;
2624 	struct isl_obj obj = { isl_obj_none, NULL };
2625 	char *lhs = NULL;
2626 	int assign = 0;
2627 	int only_print = 0;
2628 	char buf[30];
2629 
2630 	if (!p)
2631 		return NULL;
2632 	if (isl_stream_is_empty(s))
2633 		return p;
2634 
2635 	if (isl_stream_eat_if_available(s, iscc_op[ISCC_SOURCE]))
2636 		return source_file(s, table, p);
2637 	if (isl_stream_eat_if_available(s, iscc_op[ISCC_CODEGEN]))
2638 		return codegen(s, table, p);
2639 
2640 	assign = is_assign(s);
2641 	if (assign) {
2642 		lhs = isl_stream_read_ident_if_available(s);
2643 		if (isl_stream_eat(s, ISL_TOKEN_DEF))
2644 			goto error;
2645 	} else if (isl_stream_eat_if_available(s, iscc_op[ISCC_PRINT]))
2646 		only_print = 1;
2647 	else if (!tty)
2648 		only_print = 1;
2649 
2650 	obj = read_expr(s, table);
2651 	ctx = isl_stream_get_ctx(s);
2652 	if (isl_stream_eat(s, ';'))
2653 		goto error;
2654 
2655 	if (only_print) {
2656 		if (obj.type != isl_obj_none && obj.v != NULL) {
2657 			p = print_obj(p, obj);
2658 			p = isl_printer_end_line(p);
2659 		}
2660 		free_obj(obj);
2661 		return p;
2662 	}
2663 	if (!assign && obj.type != isl_obj_none && obj.v != NULL) {
2664 		static int count = 0;
2665 		snprintf(buf, sizeof(buf), "$%d", count++);
2666 		lhs = strdup(buf + 1);
2667 
2668 		p = isl_printer_print_str(p, buf);
2669 		p = isl_printer_print_str(p, " := ");
2670 		p = obj.type->print(p, obj.v);
2671 		p = isl_printer_end_line(p);
2672 	}
2673 	if (lhs && do_assign(ctx, table, lhs, obj))
2674 		return p;
2675 
2676 	return p;
2677 error:
2678 	isl_stream_flush_tokens(s);
2679 	isl_stream_skip_line(s);
2680 	free(lhs);
2681 	free_obj(obj);
2682 	return p;
2683 }
2684 
free_cb(void ** entry,void * user)2685 static isl_stat free_cb(void **entry, void *user)
2686 {
2687 	struct isl_named_obj *named = *entry;
2688 
2689 	free_obj(named->obj);
2690 	free(named->name);
2691 	free(named);
2692 
2693 	return isl_stat_ok;
2694 }
2695 
register_named_ops(struct isl_stream * s)2696 static void register_named_ops(struct isl_stream *s)
2697 {
2698 	int i;
2699 
2700 	for (i = 0; i < ISCC_N_OP; ++i) {
2701 		iscc_op[i] = isl_stream_register_keyword(s, op_name[i]);
2702 		assert(iscc_op[i] != ISL_TOKEN_ERROR);
2703 	}
2704 
2705 	for (i = 0; ; ++i) {
2706 		if (!named_un_ops[i].name)
2707 			break;
2708 		named_un_ops[i].op.op = isl_stream_register_keyword(s,
2709 							named_un_ops[i].name);
2710 		assert(named_un_ops[i].op.op != ISL_TOKEN_ERROR);
2711 	}
2712 
2713 	for (i = 0; ; ++i) {
2714 		if (!named_bin_ops[i].name)
2715 			break;
2716 		named_bin_ops[i].op.op = isl_stream_register_keyword(s,
2717 							named_bin_ops[i].name);
2718 		assert(named_bin_ops[i].op.op != ISL_TOKEN_ERROR);
2719 	}
2720 
2721 	for (i = 0; ; ++i) {
2722 		if (!compound_bin_ops[i].full)
2723 			break;
2724 		compound_bin_ops[i].op.op = isl_stream_register_keyword(s,
2725 						    compound_bin_ops[i].full);
2726 		assert(compound_bin_ops[i].op.op != ISL_TOKEN_ERROR);
2727 	}
2728 }
2729 
source_file(struct isl_stream * s,struct isl_hash_table * table,__isl_take isl_printer * p)2730 static __isl_give isl_printer *source_file(struct isl_stream *s,
2731 	struct isl_hash_table *table, __isl_take isl_printer *p)
2732 {
2733 	isl_ctx *ctx;
2734 	struct isl_token *tok;
2735 	struct isl_stream *s_file;
2736 	struct iscc_options *options;
2737 	char *name;
2738 	FILE *file;
2739 
2740 	tok = isl_stream_next_token(s);
2741 	if (!tok || isl_token_get_type(tok) != ISL_TOKEN_STRING) {
2742 		isl_stream_error(s, tok, "expecting filename");
2743 		isl_token_free(tok);
2744 		return p;
2745 	}
2746 
2747 	isl_stream_eat(s, ';');
2748 
2749 	ctx = isl_stream_get_ctx(s);
2750 	options = isl_ctx_peek_iscc_options(ctx);
2751 	if (!options || !options->io) {
2752 		isl_token_free(tok);
2753 		isl_die(ctx, isl_error_invalid,
2754 			"source operation not allowed", return p);
2755 	}
2756 
2757 	name = isl_token_get_str(ctx, tok);
2758 	isl_token_free(tok);
2759 	file = fopen(name, "r");
2760 	free(name);
2761 	isl_assert(ctx, file, return p);
2762 
2763 	s_file = isl_stream_new_file(ctx, file);
2764 	if (!s_file) {
2765 		fclose(file);
2766 		return p;
2767 	}
2768 
2769 	register_named_ops(s_file);
2770 
2771 	while (!isl_stream_is_empty(s_file))
2772 		p = read_line(s_file, table, p, 0);
2773 
2774 	isl_stream_free(s_file);
2775 	fclose(file);
2776 
2777 	return p;
2778 }
2779 
main(int argc,char ** argv)2780 int main(int argc, char **argv)
2781 {
2782 	struct isl_ctx *ctx;
2783 	struct isl_stream *s;
2784 	struct isl_hash_table *table;
2785 	struct iscc_options *options;
2786 	isl_printer *p;
2787 	int tty = isatty(0);
2788 
2789 	options = iscc_options_new_with_defaults();
2790 	assert(options);
2791 
2792 	ctx = isl_ctx_alloc_with_options(&iscc_options_args, options);
2793 	pet_options_set_autodetect(ctx, 1);
2794 	pet_options_set_encapsulate_dynamic_control(ctx, 1);
2795 	argc = isl_ctx_parse_options(ctx, argc, argv, ISL_ARG_ALL);
2796 	s = isl_stream_new_file(ctx, stdin);
2797 	assert(s);
2798 	table = isl_hash_table_alloc(ctx, 10);
2799 	assert(table);
2800 	p = isl_printer_to_file(ctx, stdout);
2801 	p = isl_printer_set_output_format(p, options->format);
2802 	assert(p);
2803 
2804 	register_named_ops(s);
2805 
2806 	install_signal_handler(ctx);
2807 
2808 	while (p) {
2809 		int empty;
2810 
2811 		empty = isl_stream_is_empty(s);
2812 		if (empty && isl_ctx_last_error(ctx) != isl_error_abort)
2813 			break;
2814 		if (!empty)
2815 			p = read_line(s, table, p, tty);
2816 		if (isl_ctx_last_error(ctx) == isl_error_abort) {
2817 			fprintf(stderr, "Interrupted\n");
2818 			isl_ctx_resume(ctx);
2819 			isl_ctx_reset_error(ctx);
2820 		}
2821 	}
2822 
2823 	remove_signal_handler(ctx);
2824 
2825 	isl_printer_free(p);
2826 	isl_hash_table_foreach(ctx, table, free_cb, NULL);
2827 	isl_hash_table_free(ctx, table);
2828 	isl_stream_free(s);
2829 	isl_ctx_free(ctx);
2830 
2831 	return 0;
2832 }
2833