1 /*
2  * Copyright 2011 Leiden University. All rights reserved.
3  * Copyright 2012-2014 Ecole Normale Superieure. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  *    1. Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *
12  *    2. Redistributions in binary form must reproduce the above
13  *       copyright notice, this list of conditions and the following
14  *       disclaimer in the documentation and/or other materials provided
15  *       with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY LEIDEN UNIVERSITY ''AS IS'' AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LEIDEN UNIVERSITY OR
21  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  * The views and conclusions contained in the software and documentation
30  * are those of the authors and should not be interpreted as
31  * representing official policies, either expressed or implied, of
32  * Leiden University.
33  */
34 
35 #include <isl/id.h>
36 #include <isl/space.h>
37 #include <isl/local_space.h>
38 #include <isl/aff.h>
39 #include <isl/ast.h>
40 #include <isl/ast_build.h>
41 #include <isl/printer.h>
42 #include <isl/val.h>
43 #include <pet.h>
44 #include "expr.h"
45 #include "print.h"
46 #include "scop.h"
47 
48 /* Return the dimension of the domain of the embedded map
49  * in the domain of "mpa".
50  */
domain_domain_dim(__isl_keep isl_multi_pw_aff * mpa)51 static int domain_domain_dim(__isl_keep isl_multi_pw_aff *mpa)
52 {
53 	int dim;
54 	isl_space *space;
55 
56 	space = isl_multi_pw_aff_get_space(mpa);
57 	space = isl_space_unwrap(isl_space_domain(space));
58 	dim = isl_space_dim(space, isl_dim_in);
59 	isl_space_free(space);
60 
61 	return dim;
62 }
63 
64 /* Given an access expression, check if any of the arguments
65  * for which an isl_ast_expr would be constructed by
66  * pet_expr_build_nested_ast_exprs are not themselves access expressions.
67  * If so, set *found and abort the search.
68  */
depends_on_expressions(__isl_keep pet_expr * expr,void * user)69 static int depends_on_expressions(__isl_keep pet_expr *expr, void *user)
70 {
71 	int i, dim;
72 	int *found = user;
73 
74 	if (expr->n_arg == 0)
75 		return 0;
76 
77 	dim = domain_domain_dim(expr->acc.index);
78 
79 	for (i = 0; i < expr->n_arg; ++i) {
80 		if (!isl_multi_pw_aff_involves_dims(expr->acc.index,
81 						    isl_dim_in, dim + i, 1))
82 			continue;
83 		if (expr->args[i]->type != pet_expr_access) {
84 			*found = 1;
85 			return -1;
86 		}
87 	}
88 
89 	return 0;
90 }
91 
92 /* pet_stmt_build_ast_exprs is currently limited to only handle
93  * some forms of data dependent accesses.
94  * If pet_stmt_can_build_ast_exprs returns 1, then pet_stmt_build_ast_exprs
95  * can safely be called on "stmt".
96  */
pet_stmt_can_build_ast_exprs(struct pet_stmt * stmt)97 int pet_stmt_can_build_ast_exprs(struct pet_stmt *stmt)
98 {
99 	int r;
100 	int found = 0;
101 
102 	if (!stmt)
103 		return -1;
104 
105 	r = pet_tree_foreach_access_expr(stmt->body,
106 					&depends_on_expressions, &found);
107 	if (r < 0 && !found)
108 		return -1;
109 
110 	return !found;
111 }
112 
113 /* pet_stmt_build_ast_exprs is currently limited to only handle
114  * some forms of data dependent accesses.
115  * If pet_scop_can_build_ast_exprs returns 1, then pet_stmt_build_ast_exprs
116  * can safely be called on all statements in the scop.
117  */
pet_scop_can_build_ast_exprs(struct pet_scop * scop)118 int pet_scop_can_build_ast_exprs(struct pet_scop *scop)
119 {
120 	int i;
121 
122 	if (!scop)
123 		return -1;
124 
125 	for (i = 0; i < scop->n_stmt; ++i) {
126 		int ok = pet_stmt_can_build_ast_exprs(scop->stmts[i]);
127 		if (ok < 0 || !ok)
128 			return ok;
129 	}
130 
131 	return 1;
132 }
133 
134 /* Internal data structure for pet_stmt_build_ast_exprs.
135  *
136  * "build" is used to construct an AST expression from an index expression.
137  * "fn_index" is used to transform the index expression prior to
138  *	the construction of the AST expression.
139  * "fn_expr" is used to transform the constructed AST expression.
140  * "ref2expr" collects the results.
141  */
142 struct pet_build_ast_expr_data {
143 	isl_ast_build *build;
144 	__isl_give isl_multi_pw_aff *(*fn_index)(
145 		__isl_take isl_multi_pw_aff *mpa, __isl_keep isl_id *id,
146 		void *user);
147 	void *user_index;
148 	__isl_give isl_ast_expr *(*fn_expr)(__isl_take isl_ast_expr *expr,
149 		__isl_keep isl_id *id, void *user);
150 	void *user_expr;
151 	isl_id_to_ast_expr *ref2expr;
152 };
153 
154 /* Given an index expression "index" with nested expressions, replace
155  * those nested expressions by parameters.  The identifiers
156  * of those parameters reference the corresponding arguments
157  * of "expr".  The same identifiers are used in
158  * pet_expr_build_nested_ast_exprs.
159  *
160  * In particular, if "index" is of the form
161  *
162  *	{ [domain -> [e_1, ..., e_n]] -> array[f(e_1, ..., e_n)] }
163  *
164  * then we construct the expression
165  *
166  *	[p_1, ..., p_n] -> { domain -> array[f(p_1, ..., p_n)] }
167  *
168  */
parametrize_nested_exprs(__isl_take isl_multi_pw_aff * index,__isl_keep pet_expr * expr)169 static __isl_give isl_multi_pw_aff *parametrize_nested_exprs(
170 	__isl_take isl_multi_pw_aff *index, __isl_keep pet_expr *expr)
171 {
172 	int i;
173 	isl_ctx *ctx;
174 	isl_space *space, *space2;
175 	isl_local_space *ls;
176 	isl_multi_aff *ma, *ma2;
177 
178 	ctx = isl_multi_pw_aff_get_ctx(index);
179 	space = isl_multi_pw_aff_get_domain_space(index);
180 	space = isl_space_unwrap(space);
181 
182 	space2 = isl_space_domain(isl_space_copy(space));
183 	ma = isl_multi_aff_identity(isl_space_map_from_set(space2));
184 
185 	space = isl_space_insert_dims(space, isl_dim_param, 0,
186 					expr->n_arg);
187 	for (i = 0; i < expr->n_arg; ++i) {
188 		isl_id *id = isl_id_alloc(ctx, NULL, expr->args[i]);
189 
190 		space = isl_space_set_dim_id(space, isl_dim_param, i, id);
191 	}
192 	space2 = isl_space_domain(isl_space_copy(space));
193 	ls = isl_local_space_from_space(space2);
194 	ma2 = isl_multi_aff_zero(space);
195 	for (i = 0; i < expr->n_arg; ++i) {
196 		isl_aff *aff;
197 		aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
198 						isl_dim_param, i);
199 		ma2 = isl_multi_aff_set_aff(ma2, i, aff);
200 	}
201 	isl_local_space_free(ls);
202 
203 	ma = isl_multi_aff_range_product(ma, ma2);
204 
205 	return isl_multi_pw_aff_pullback_multi_aff(index, ma);
206 }
207 
208 static __isl_give isl_ast_expr *pet_expr_build_ast_expr(
209 	__isl_keep pet_expr *expr, struct pet_build_ast_expr_data *data);
210 
211 /* Construct an associative array from identifiers for the nested
212  * expressions of "expr" to the corresponding isl_ast_expr.
213  * The identifiers reference the corresponding arguments of "expr".
214  * The same identifiers are used in parametrize_nested_exprs.
215  * Note that we only need to construct isl_ast_expr objects for
216  * those arguments that actually appear in the index expression of "expr".
217  */
pet_expr_build_nested_ast_exprs(__isl_keep pet_expr * expr,struct pet_build_ast_expr_data * data)218 static __isl_give isl_id_to_ast_expr *pet_expr_build_nested_ast_exprs(
219 	__isl_keep pet_expr *expr, struct pet_build_ast_expr_data *data)
220 {
221 	int i, dim;
222 	isl_ctx *ctx = isl_ast_build_get_ctx(data->build);
223 	isl_id_to_ast_expr *id2expr;
224 
225 	dim = domain_domain_dim(expr->acc.index);
226 	id2expr = isl_id_to_ast_expr_alloc(ctx, expr->n_arg);
227 
228 	for (i = 0; i < expr->n_arg; ++i) {
229 		isl_id *id;
230 		isl_ast_expr *ast_expr;
231 
232 		if (!isl_multi_pw_aff_involves_dims(expr->acc.index,
233 						    isl_dim_in, dim + i, 1))
234 			continue;
235 
236 		id = isl_id_alloc(ctx, NULL, expr->args[i]);
237 		ast_expr = pet_expr_build_ast_expr(expr->args[i], data);
238 		id2expr = isl_id_to_ast_expr_set(id2expr, id, ast_expr);
239 	}
240 
241 	return id2expr;
242 }
243 
244 /* Construct an AST expression from an access expression.
245  *
246  * If the expression has any arguments, we first convert those
247  * to AST expressions and replace the references to those arguments
248  * in the index expression by parameters.
249  *
250  * Then we apply the index transformation if any was provided by the user.
251  *
252  * If the "access" is actually an affine expression, we print is as such.
253  * Otherwise, we print a proper access.
254  *
255  * If the original expression had any arguments, then they are plugged in now.
256  *
257  * Finally, we apply an AST transformation on the result, if any was provided
258  * by the user.
259  */
pet_expr_build_ast_expr(__isl_keep pet_expr * expr,struct pet_build_ast_expr_data * data)260 static __isl_give isl_ast_expr *pet_expr_build_ast_expr(
261 	__isl_keep pet_expr *expr, struct pet_build_ast_expr_data *data)
262 {
263 	isl_pw_aff *pa;
264 	isl_multi_pw_aff *mpa;
265 	isl_ast_expr *ast_expr;
266 	isl_id_to_ast_expr *id2expr;
267 	isl_ast_build *build = data->build;
268 
269 	if (!expr)
270 		return NULL;
271 	if (expr->type != pet_expr_access)
272 		isl_die(isl_ast_build_get_ctx(build), isl_error_invalid,
273 			"not an access expression", return NULL);
274 
275 	mpa = isl_multi_pw_aff_copy(expr->acc.index);
276 
277 	if (expr->n_arg > 0) {
278 		mpa = parametrize_nested_exprs(mpa, expr);
279 		id2expr = pet_expr_build_nested_ast_exprs(expr, data);
280 	}
281 
282 	if (data->fn_index)
283 		mpa = data->fn_index(mpa, expr->acc.ref_id, data->user_index);
284 	mpa = isl_multi_pw_aff_coalesce(mpa);
285 
286 	if (!pet_expr_is_affine(expr)) {
287 		ast_expr = isl_ast_build_access_from_multi_pw_aff(build, mpa);
288 	} else {
289 		pa = isl_multi_pw_aff_get_pw_aff(mpa, 0);
290 		ast_expr = isl_ast_build_expr_from_pw_aff(build, pa);
291 		isl_multi_pw_aff_free(mpa);
292 	}
293 	if (expr->n_arg > 0)
294 		ast_expr = isl_ast_expr_substitute_ids(ast_expr, id2expr);
295 	if (data->fn_expr)
296 		ast_expr = data->fn_expr(ast_expr, expr->acc.ref_id,
297 					    data->user_index);
298 
299 	return ast_expr;
300 }
301 
302 /* Construct an AST expression from the access expression "expr" and
303  * add the mapping from reference identifier to AST expression to
304  * data->ref2expr.
305  */
add_access(__isl_keep pet_expr * expr,void * user)306 static int add_access(__isl_keep pet_expr *expr, void *user)
307 {
308 	struct pet_build_ast_expr_data *data = user;
309 	isl_id *id;
310 	isl_ast_expr *ast_expr;
311 
312 	ast_expr = pet_expr_build_ast_expr(expr, data);
313 
314 	id = isl_id_copy(expr->acc.ref_id);
315 	data->ref2expr = isl_id_to_ast_expr_set(data->ref2expr, id, ast_expr);
316 
317 	return 0;
318 }
319 
320 /* Construct an associative array from reference identifiers of
321  * access expressions in "stmt" to the corresponding isl_ast_expr.
322  * Each index expression is first transformed through "fn_index"
323  * (if not NULL).  Then an AST expression is generated using "build".
324  * Finally, the AST expression is transformed using "fn_expr"
325  * (if not NULL).
326  */
pet_stmt_build_ast_exprs(struct pet_stmt * stmt,__isl_keep isl_ast_build * build,__isl_give isl_multi_pw_aff * (* fn_index)(__isl_take isl_multi_pw_aff * mpa,__isl_keep isl_id * id,void * user),void * user_index,__isl_give isl_ast_expr * (* fn_expr)(__isl_take isl_ast_expr * expr,__isl_keep isl_id * id,void * user),void * user_expr)327 __isl_give isl_id_to_ast_expr *pet_stmt_build_ast_exprs(struct pet_stmt *stmt,
328 	__isl_keep isl_ast_build *build,
329 	__isl_give isl_multi_pw_aff *(*fn_index)(
330 		__isl_take isl_multi_pw_aff *mpa, __isl_keep isl_id *id,
331 		void *user), void *user_index,
332 	__isl_give isl_ast_expr *(*fn_expr)(__isl_take isl_ast_expr *expr,
333 		__isl_keep isl_id *id, void *user), void *user_expr)
334 {
335 	struct pet_build_ast_expr_data data =
336 		{ build, fn_index, user_index, fn_expr, user_expr };
337 	isl_ctx *ctx;
338 
339 	if (!stmt || !build)
340 		return NULL;
341 
342 	ctx = isl_ast_build_get_ctx(build);
343 	data.ref2expr = isl_id_to_ast_expr_alloc(ctx, 0);
344 	if (pet_tree_foreach_access_expr(stmt->body, &add_access, &data) < 0)
345 		data.ref2expr = isl_id_to_ast_expr_free(data.ref2expr);
346 
347 	return data.ref2expr;
348 }
349 
350 /* Print the access expression "expr" to "p".
351  *
352  * We look up the corresponding isl_ast_expr in "ref2expr"
353  * and print that to "p".
354  */
print_access(__isl_take isl_printer * p,__isl_keep pet_expr * expr,__isl_keep isl_id_to_ast_expr * ref2expr)355 static __isl_give isl_printer *print_access(__isl_take isl_printer *p,
356 	__isl_keep pet_expr *expr, __isl_keep isl_id_to_ast_expr *ref2expr)
357 {
358 	isl_ast_expr *ast_expr;
359 	int is_access;
360 
361 	if (!isl_id_to_ast_expr_has(ref2expr, expr->acc.ref_id))
362 		isl_die(isl_printer_get_ctx(p), isl_error_internal,
363 			"missing expression", return isl_printer_free(p));
364 
365 	ast_expr = isl_id_to_ast_expr_get(ref2expr,
366 					isl_id_copy(expr->acc.ref_id));
367 	is_access = isl_ast_expr_get_type(ast_expr) == isl_ast_expr_op &&
368 		isl_ast_expr_get_op_type(ast_expr) == isl_ast_op_access;
369 	if (!is_access)
370 		p = isl_printer_print_str(p, "(");
371 	p = isl_printer_print_ast_expr(p, ast_expr);
372 	if (!is_access)
373 		p = isl_printer_print_str(p, ")");
374 	isl_ast_expr_free(ast_expr);
375 
376 	return p;
377 }
378 
379 /* Is "op" a postfix operator?
380  */
is_postfix(enum pet_op_type op)381 static int is_postfix(enum pet_op_type op)
382 {
383 	switch (op) {
384 	case pet_op_post_inc:
385 	case pet_op_post_dec:
386 		return 1;
387 	default:
388 		return 0;
389 	}
390 }
391 
392 static __isl_give isl_printer *print_pet_expr(__isl_take isl_printer *p,
393 	__isl_keep pet_expr *expr, int outer,
394 	__isl_keep isl_id_to_ast_expr *ref2expr);
395 
396 /* Print operation expression "expr" to "p".
397  *
398  * The access subexpressions are replaced by the isl_ast_expr
399  * associated to its reference identifier in "ref2expr".
400  */
print_op(__isl_take isl_printer * p,__isl_keep pet_expr * expr,__isl_keep isl_id_to_ast_expr * ref2expr)401 static __isl_give isl_printer *print_op(__isl_take isl_printer *p,
402 	__isl_keep pet_expr *expr, __isl_keep isl_id_to_ast_expr *ref2expr)
403 {
404 	switch (expr->n_arg) {
405 	case 1:
406 		if (!is_postfix(expr->op))
407 			p = isl_printer_print_str(p, pet_op_str(expr->op));
408 		p = print_pet_expr(p, expr->args[pet_un_arg], 0, ref2expr);
409 		if (is_postfix(expr->op))
410 			p = isl_printer_print_str(p, pet_op_str(expr->op));
411 		break;
412 	case 2:
413 		p = print_pet_expr(p, expr->args[pet_bin_lhs], 0,
414 					ref2expr);
415 		p = isl_printer_print_str(p, " ");
416 		p = isl_printer_print_str(p, pet_op_str(expr->op));
417 		p = isl_printer_print_str(p, " ");
418 		p = print_pet_expr(p, expr->args[pet_bin_rhs], 0,
419 					ref2expr);
420 		break;
421 	case 3:
422 		p = print_pet_expr(p, expr->args[pet_ter_cond], 0,
423 					ref2expr);
424 		p = isl_printer_print_str(p, " ? ");
425 		p = print_pet_expr(p, expr->args[pet_ter_true], 0,
426 					ref2expr);
427 		p = isl_printer_print_str(p, " : ");
428 		p = print_pet_expr(p, expr->args[pet_ter_false], 0,
429 					ref2expr);
430 		break;
431 	}
432 
433 	return p;
434 }
435 
436 /* Print "expr" to "p".
437  *
438  * If "outer" is set, then we are printing the outer expression statement.
439  *
440  * The access subexpressions are replaced by the isl_ast_expr
441  * associated to its reference identifier in "ref2expr".
442  */
print_pet_expr(__isl_take isl_printer * p,__isl_keep pet_expr * expr,int outer,__isl_keep isl_id_to_ast_expr * ref2expr)443 static __isl_give isl_printer *print_pet_expr(__isl_take isl_printer *p,
444 	__isl_keep pet_expr *expr, int outer,
445 	__isl_keep isl_id_to_ast_expr *ref2expr)
446 {
447 	int i;
448 
449 	switch (expr->type) {
450 	case pet_expr_error:
451 		p = isl_printer_free(p);
452 		break;
453 	case pet_expr_int:
454 		p = isl_printer_print_val(p, expr->i);
455 		break;
456 	case pet_expr_double:
457 		p = isl_printer_print_str(p, expr->d.s);
458 		break;
459 	case pet_expr_access:
460 		p = print_access(p, expr, ref2expr);
461 		break;
462 	case pet_expr_op:
463 		if (!outer)
464 			p = isl_printer_print_str(p, "(");
465 		p = print_op(p, expr, ref2expr);
466 		if (!outer)
467 			p = isl_printer_print_str(p, ")");
468 		break;
469 	case pet_expr_call:
470 		p = isl_printer_print_str(p, expr->c.name);
471 		p = isl_printer_print_str(p, "(");
472 		for (i = 0; i < expr->n_arg; ++i) {
473 			if (i)
474 				p = isl_printer_print_str(p, ", ");
475 			p = print_pet_expr(p, expr->args[i], 1, ref2expr);
476 		}
477 		p = isl_printer_print_str(p, ")");
478 		break;
479 	case pet_expr_cast:
480 		if (!outer)
481 			p = isl_printer_print_str(p, "(");
482 		p = isl_printer_print_str(p, "(");
483 		p = isl_printer_print_str(p, expr->type_name);
484 		p = isl_printer_print_str(p, ") ");
485 		p = print_pet_expr(p, expr->args[0], 0, ref2expr);
486 		if (!outer)
487 			p = isl_printer_print_str(p, ")");
488 		break;
489 	}
490 
491 	return p;
492 }
493 
494 static __isl_give isl_printer *print_pet_tree(__isl_take isl_printer *p,
495 	__isl_keep pet_tree *tree, int in_block,
496 	__isl_keep isl_id_to_ast_expr *ref2expr);
497 
498 /* Print "tree" to "p", where "tree" is of type pet_tree_block.
499  *
500  * If "in_block" is set, then the caller has just printed a block,
501  * so there is no need to print one for this node.
502  *
503  * The access subexpressions are replaced by the isl_ast_expr
504  * associated to its reference identifier in "ref2expr".
505  */
print_pet_tree_block(__isl_take isl_printer * p,__isl_keep pet_tree * tree,int in_block,__isl_keep isl_id_to_ast_expr * ref2expr)506 static __isl_give isl_printer *print_pet_tree_block(__isl_take isl_printer *p,
507 	__isl_keep pet_tree *tree, int in_block,
508 	__isl_keep isl_id_to_ast_expr *ref2expr)
509 {
510 	int i, n;
511 
512 	if (!in_block) {
513 		p = isl_printer_start_line(p);
514 		p = isl_printer_print_str(p, "{");
515 		p = isl_printer_end_line(p);
516 		p = isl_printer_indent(p, 2);
517 	}
518 
519 	n = pet_tree_block_n_child(tree);
520 
521 	for (i = 0; i < n; ++i) {
522 		pet_tree *child;
523 
524 		child = pet_tree_block_get_child(tree, i);
525 		p = print_pet_tree(p, child, 0, ref2expr);
526 		pet_tree_free(child);
527 	}
528 
529 	if (!in_block) {
530 		p = isl_printer_indent(p, -2);
531 		p = isl_printer_start_line(p);
532 		p = isl_printer_print_str(p, "}");
533 		p = isl_printer_end_line(p);
534 	}
535 
536 	return p;
537 }
538 
539 /* Print "tree" to "p", where "tree" is of type pet_tree_if or
540  * pet_tree_if_else..
541  *
542  * The access subexpressions are replaced by the isl_ast_expr
543  * associated to its reference identifier in "ref2expr".
544  */
print_pet_tree_if(__isl_take isl_printer * p,__isl_keep pet_tree * tree,__isl_keep isl_id_to_ast_expr * ref2expr)545 static __isl_give isl_printer *print_pet_tree_if(__isl_take isl_printer *p,
546 	__isl_keep pet_tree *tree, __isl_keep isl_id_to_ast_expr *ref2expr)
547 {
548 	pet_expr *expr;
549 	pet_tree *body;
550 
551 	p = isl_printer_start_line(p);
552 	p = isl_printer_print_str(p, "if (");
553 	expr = pet_tree_if_get_cond(tree);
554 	p = print_pet_expr(p, expr, 1, ref2expr);
555 	pet_expr_free(expr);
556 	p = isl_printer_print_str(p, ") {");
557 	p = isl_printer_end_line(p);
558 
559 	p = isl_printer_indent(p, 2);
560 	body = pet_tree_if_get_then(tree);
561 	p = print_pet_tree(p, body, 1, ref2expr);
562 	pet_tree_free(body);
563 	p = isl_printer_indent(p, -2);
564 
565 	p = isl_printer_start_line(p);
566 	p = isl_printer_print_str(p, "}");
567 
568 	if (pet_tree_get_type(tree) == pet_tree_if_else) {
569 		p = isl_printer_print_str(p, " else {");
570 		p = isl_printer_end_line(p);
571 
572 		p = isl_printer_indent(p, 2);
573 		body = pet_tree_if_get_else(tree);
574 		p = print_pet_tree(p, body, 1, ref2expr);
575 		pet_tree_free(body);
576 		p = isl_printer_indent(p, -2);
577 
578 		p = isl_printer_start_line(p);
579 		p = isl_printer_print_str(p, "}");
580 	}
581 
582 	p = isl_printer_end_line(p);
583 
584 	return p;
585 }
586 
587 /* Print "tree" to "p", where "tree" is of type pet_tree_for.
588  *
589  * The access subexpressions are replaced by the isl_ast_expr
590  * associated to its reference identifier in "ref2expr".
591  */
print_pet_tree_for(__isl_take isl_printer * p,__isl_keep pet_tree * tree,__isl_keep isl_id_to_ast_expr * ref2expr)592 static __isl_give isl_printer *print_pet_tree_for(__isl_take isl_printer *p,
593 	__isl_keep pet_tree *tree, __isl_keep isl_id_to_ast_expr *ref2expr)
594 {
595 	pet_expr *expr_iv, *expr;
596 	pet_tree *body;
597 
598 	expr_iv = pet_tree_loop_get_var(tree);
599 
600 	p = isl_printer_start_line(p);
601 	p = isl_printer_print_str(p, "for (");
602 	p = print_pet_expr(p, expr_iv, 1, ref2expr);
603 	p = isl_printer_print_str(p, " = ");
604 	expr = pet_tree_loop_get_init(tree);
605 	p = print_pet_expr(p, expr, 0, ref2expr);
606 	pet_expr_free(expr);
607 	p = isl_printer_print_str(p, "; ");
608 	expr = pet_tree_loop_get_cond(tree);
609 	p = print_pet_expr(p, expr, 1, ref2expr);
610 	pet_expr_free(expr);
611 	p = isl_printer_print_str(p, "; ");
612 	p = print_pet_expr(p, expr_iv, 1, ref2expr);
613 	p = isl_printer_print_str(p, " += ");
614 	expr = pet_tree_loop_get_inc(tree);
615 	p = print_pet_expr(p, expr, 0, ref2expr);
616 	pet_expr_free(expr);
617 	p = isl_printer_print_str(p, ") {");
618 	p = isl_printer_end_line(p);
619 
620 	pet_expr_free(expr_iv);
621 
622 	p = isl_printer_indent(p, 2);
623 	body = pet_tree_loop_get_body(tree);
624 	p = print_pet_tree(p, body, 1, ref2expr);
625 	pet_tree_free(body);
626 	p = isl_printer_indent(p, -2);
627 
628 	p = isl_printer_start_line(p);
629 	p = isl_printer_print_str(p, "}");
630 	p = isl_printer_end_line(p);
631 
632 	return p;
633 }
634 
635 /* Print "tree" to "p", where "tree" is of type pet_tree_while or
636  * pet_tree_infinite_loop.
637  *
638  * The access subexpressions are replaced by the isl_ast_expr
639  * associated to its reference identifier in "ref2expr".
640  *
641  * pet_tree_loop_get_cond returns "1" when called on a tree of type
642  * pet_tree_infinite_loop, so we can treat them in the same way
643  * as trees of type pet_tree_while.
644  */
print_pet_tree_while(__isl_take isl_printer * p,__isl_keep pet_tree * tree,__isl_keep isl_id_to_ast_expr * ref2expr)645 static __isl_give isl_printer *print_pet_tree_while(__isl_take isl_printer *p,
646 	__isl_keep pet_tree *tree, __isl_keep isl_id_to_ast_expr *ref2expr)
647 {
648 	pet_expr *expr;
649 	pet_tree *body;
650 
651 	p = isl_printer_start_line(p);
652 	p = isl_printer_print_str(p, "while (");
653 	expr = pet_tree_loop_get_cond(tree);
654 	p = print_pet_expr(p, expr, 1, ref2expr);
655 	pet_expr_free(expr);
656 	p = isl_printer_print_str(p, ") {");
657 	p = isl_printer_end_line(p);
658 
659 	p = isl_printer_indent(p, 2);
660 	body = pet_tree_loop_get_body(tree);
661 	p = print_pet_tree(p, body, 1, ref2expr);
662 	pet_tree_free(body);
663 	p = isl_printer_indent(p, -2);
664 
665 	p = isl_printer_start_line(p);
666 	p = isl_printer_print_str(p, "}");
667 	p = isl_printer_end_line(p);
668 
669 	return p;
670 }
671 
672 /* Print "tree" to "p", where "tree" is of type pet_tree_decl_init.
673  *
674  * We assume all variables have already been declared, so we
675  * only print the assignment implied by the declaration initialization.
676  *
677  * The access subexpressions are replaced by the isl_ast_expr
678  * associated to its reference identifier in "ref2expr".
679  */
print_pet_tree_decl_init(__isl_take isl_printer * p,__isl_keep pet_tree * tree,__isl_keep isl_id_to_ast_expr * ref2expr)680 static __isl_give isl_printer *print_pet_tree_decl_init(
681 	__isl_take isl_printer *p, __isl_keep pet_tree *tree,
682 	__isl_keep isl_id_to_ast_expr *ref2expr)
683 {
684 	pet_expr *var, *init;
685 
686 	p = isl_printer_start_line(p);
687 
688 	var = pet_tree_decl_get_var(tree);
689 	p = print_pet_expr(p, var, 1, ref2expr);
690 	pet_expr_free(var);
691 
692 	p = isl_printer_print_str(p, " = ");
693 
694 	init = pet_tree_decl_get_init(tree);
695 	p = print_pet_expr(p, init, 1, ref2expr);
696 	pet_expr_free(init);
697 
698 	p = isl_printer_print_str(p, ";");
699 	p = isl_printer_end_line(p);
700 
701 	return p;
702 }
703 
704 /* Print "tree" to "p", where "tree" is of type pet_tree_return.
705  *
706  * The access subexpressions are replaced by the isl_ast_expr
707  * associated to its reference identifier in "ref2expr".
708  */
print_pet_tree_return(__isl_take isl_printer * p,__isl_keep pet_tree * tree,__isl_keep isl_id_to_ast_expr * ref2expr)709 static __isl_give isl_printer *print_pet_tree_return(__isl_take isl_printer *p,
710 	__isl_keep pet_tree *tree, __isl_keep isl_id_to_ast_expr *ref2expr)
711 {
712 	pet_expr *expr;
713 
714 	expr = pet_tree_expr_get_expr(tree);
715 	p = isl_printer_start_line(p);
716 	p = isl_printer_print_str(p, "return ");
717 	p = print_pet_expr(p, expr, 1, ref2expr);
718 	p = isl_printer_print_str(p, ";");
719 	p = isl_printer_end_line(p);
720 	pet_expr_free(expr);
721 
722 	return p;
723 }
724 
725 /* Print "tree" to "p".
726  *
727  * If "in_block" is set, then the caller has just printed a block,
728  * so there is no need to print one for this node.
729  *
730  * The access subexpressions are replaced by the isl_ast_expr
731  * associated to its reference identifier in "ref2expr".
732  *
733  * We assume all variables have already been declared,
734  * so there is nothing to print for nodes of type pet_tree_decl.
735  */
print_pet_tree(__isl_take isl_printer * p,__isl_keep pet_tree * tree,int in_block,__isl_keep isl_id_to_ast_expr * ref2expr)736 static __isl_give isl_printer *print_pet_tree(__isl_take isl_printer *p,
737 	__isl_keep pet_tree *tree, int in_block,
738 	__isl_keep isl_id_to_ast_expr *ref2expr)
739 {
740 	pet_expr *expr;
741 	enum pet_tree_type type;
742 
743 	type = pet_tree_get_type(tree);
744 	switch (type) {
745 	case pet_tree_error:
746 		return isl_printer_free(p);
747 	case pet_tree_block:
748 		return print_pet_tree_block(p, tree, in_block, ref2expr);
749 	case pet_tree_break:
750 	case pet_tree_continue:
751 		p = isl_printer_start_line(p);
752 		if (type == pet_tree_break)
753 			p = isl_printer_print_str(p, "break;");
754 		else
755 			p = isl_printer_print_str(p, "continue;");
756 		return isl_printer_end_line(p);
757 	case pet_tree_expr:
758 		expr = pet_tree_expr_get_expr(tree);
759 		p = isl_printer_start_line(p);
760 		p = print_pet_expr(p, expr, 1, ref2expr);
761 		p = isl_printer_print_str(p, ";");
762 		p = isl_printer_end_line(p);
763 		pet_expr_free(expr);
764 		break;
765 	case pet_tree_return:
766 		return print_pet_tree_return(p, tree, ref2expr);
767 	case pet_tree_if:
768 	case pet_tree_if_else:
769 		return print_pet_tree_if(p, tree, ref2expr);
770 	case pet_tree_for:
771 		return print_pet_tree_for(p, tree, ref2expr);
772 	case pet_tree_while:
773 	case pet_tree_infinite_loop:
774 		return print_pet_tree_while(p, tree, ref2expr);
775 	case pet_tree_decl:
776 		return p;
777 	case pet_tree_decl_init:
778 		return print_pet_tree_decl_init(p, tree, ref2expr);
779 	}
780 
781 	return p;
782 }
783 
784 /* Print "stmt" to "p".
785  *
786  * The access expressions in "stmt" are replaced by the isl_ast_expr
787  * associated to its reference identifier in "ref2expr".
788  *
789  * If the statement is an assume or a kill statement, then we print nothing.
790  */
pet_stmt_print_body(struct pet_stmt * stmt,__isl_take isl_printer * p,__isl_keep isl_id_to_ast_expr * ref2expr)791 __isl_give isl_printer *pet_stmt_print_body(struct pet_stmt *stmt,
792 	__isl_take isl_printer *p, __isl_keep isl_id_to_ast_expr *ref2expr)
793 {
794 	if (!stmt)
795 		return isl_printer_free(p);
796 	if (pet_stmt_is_assume(stmt))
797 		return p;
798 	if (pet_stmt_is_kill(stmt))
799 		return p;
800 	p = print_pet_tree(p, stmt->body, 0, ref2expr);
801 
802 	return p;
803 }
804 
805 /* Copy the contents of "input" from offset "start" to "end" to "output".
806  */
copy(FILE * input,FILE * output,long start,long end)807 int copy(FILE *input, FILE *output, long start, long end)
808 {
809 	char buffer[1024];
810 	size_t n, m;
811 
812 	if (end < 0) {
813 		fseek(input, 0, SEEK_END);
814 		end = ftell(input);
815 	}
816 
817 	fseek(input, start, SEEK_SET);
818 
819 	while (start < end) {
820 		n = end - start;
821 		if (n > 1024)
822 			n = 1024;
823 		n = fread(buffer, 1, n, input);
824 		if (n <= 0)
825 			return -1;
826 		m = fwrite(buffer, 1, n, output);
827 		if (n != m)
828 			return -1;
829 		start += n;
830 	}
831 
832 	return 0;
833 }
834