scop.c: extract out expr_collect_access
[pet.git] / print.c
blob4a9ab272372a3bb6f37a701ccea817f8dbe2f8da
1 /*
2 * Copyright 2011 Leiden University. All rights reserved.
3 * Copyright 2012-2013 Ecole Normale Superieure. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
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.
35 #include <isl/aff.h>
36 #include <isl/ast.h>
37 #include <isl/ast_build.h>
38 #include <pet.h>
39 #include "print.h"
40 #include "scop.h"
42 /* Internal data structure for pet_stmt_build_ast_exprs.
44 * "build" is used to construct an AST expression from an index expression.
45 * "fn_index" is used to transform the index expression prior to
46 * the construction of the AST expression.
47 * "fn_expr" is used to transform the constructed AST expression.
48 * "ref2expr" collects the results.
50 struct pet_build_ast_expr_data {
51 isl_ast_build *build;
52 __isl_give isl_multi_pw_aff *(*fn_index)(
53 __isl_take isl_multi_pw_aff *mpa, __isl_keep isl_id *id,
54 void *user);
55 void *user_index;
56 __isl_give isl_ast_expr *(*fn_expr)(__isl_take isl_ast_expr *expr,
57 __isl_keep isl_id *id, void *user);
58 void *user_expr;
59 isl_id_to_ast_expr *ref2expr;
62 /* Given an index expression "index" with nested expressions, replace
63 * those nested expressions by parameters. The identifiers
64 * of those parameters reference the corresponding arguments
65 * of "expr". The same identifiers are used in
66 * pet_expr_build_nested_ast_exprs.
68 * In particular, if "index" is of the form
70 * { [domain -> [e_1, ..., e_n]] -> array[f(e_1, ..., e_n)] }
72 * then we construct the expression
74 * [p_1, ..., p_n] -> { domain -> array[f(p_1, ..., p_n)] }
77 static __isl_give isl_multi_pw_aff *parametrize_nested_exprs(
78 __isl_take isl_multi_pw_aff *index, struct pet_expr *expr)
80 int i;
81 isl_ctx *ctx;
82 isl_space *space, *space2;
83 isl_local_space *ls;
84 isl_multi_aff *ma, *ma2;
86 ctx = isl_multi_pw_aff_get_ctx(index);
87 space = isl_multi_pw_aff_get_domain_space(index);
88 space = isl_space_unwrap(space);
90 space2 = isl_space_domain(isl_space_copy(space));
91 ma = isl_multi_aff_identity(isl_space_map_from_set(space2));
93 space = isl_space_insert_dims(space, isl_dim_param, 0,
94 expr->n_arg);
95 for (i = 0; i < expr->n_arg; ++i) {
96 isl_id *id = isl_id_alloc(ctx, NULL, expr->args[i]);
98 space = isl_space_set_dim_id(space, isl_dim_param, i, id);
100 space2 = isl_space_domain(isl_space_copy(space));
101 ls = isl_local_space_from_space(space2);
102 ma2 = isl_multi_aff_zero(space);
103 for (i = 0; i < expr->n_arg; ++i) {
104 isl_aff *aff;
105 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
106 isl_dim_param, i);
107 ma2 = isl_multi_aff_set_aff(ma2, i, aff);
109 isl_local_space_free(ls);
111 ma = isl_multi_aff_range_product(ma, ma2);
113 return isl_multi_pw_aff_pullback_multi_aff(index, ma);
116 static __isl_give isl_ast_expr *pet_expr_build_ast_expr(struct pet_expr *expr,
117 struct pet_build_ast_expr_data *data);
119 /* Construct an associative array from identifiers for the nested
120 * expressions of "expr" to the corresponding isl_ast_expr.
121 * The identifiers reference the corresponding arguments of "expr".
122 * The same identifiers are used in parametrize_nested_exprs.
124 static __isl_give isl_id_to_ast_expr *pet_expr_build_nested_ast_exprs(
125 struct pet_expr *expr, struct pet_build_ast_expr_data *data)
127 int i;
128 isl_ctx *ctx = isl_ast_build_get_ctx(data->build);
129 isl_id_to_ast_expr *id2expr;
131 id2expr = isl_id_to_ast_expr_alloc(ctx, expr->n_arg);
133 for (i = 0; i < expr->n_arg; ++i) {
134 isl_id *id = isl_id_alloc(ctx, NULL, expr->args[i]);
135 isl_ast_expr *ast_expr;
137 ast_expr = pet_expr_build_ast_expr(expr->args[i], data);
138 id2expr = isl_id_to_ast_expr_set(id2expr, id, ast_expr);
141 return id2expr;
144 /* Construct an AST expression from an access expression.
146 * If the expression has any arguments, we first convert those
147 * to AST expressions and replace the references to those arguments
148 * in the index expression by parameters.
150 * Then we apply the index transformation if any was provided by the user.
152 * If the "access" is actually an affine expression, we print is as such.
153 * Otherwise, we print a proper access.
155 * If the original expression had any arguments, then they are plugged in now.
157 * Finally, we apply an AST transformation on the result, if any was provided
158 * by the user.
160 static __isl_give isl_ast_expr *pet_expr_build_ast_expr(struct pet_expr *expr,
161 struct pet_build_ast_expr_data *data)
163 isl_pw_aff *pa;
164 isl_multi_pw_aff *mpa;
165 isl_ast_expr *ast_expr;
166 isl_id_to_ast_expr *id2expr;
167 isl_ast_build *build = data->build;
169 if (!expr)
170 return NULL;
171 if (expr->type != pet_expr_access)
172 isl_die(isl_ast_build_get_ctx(build), isl_error_invalid,
173 "not an access expression", return NULL);
175 mpa = isl_multi_pw_aff_copy(expr->acc.index);
177 if (expr->n_arg > 0) {
178 mpa = parametrize_nested_exprs(mpa, expr);
179 id2expr = pet_expr_build_nested_ast_exprs(expr, data);
182 if (data->fn_index)
183 mpa = data->fn_index(mpa, expr->acc.ref_id, data->user_index);
184 mpa = isl_multi_pw_aff_coalesce(mpa);
186 if (!pet_expr_is_affine(expr)) {
187 ast_expr = isl_ast_build_access_from_multi_pw_aff(build, mpa);
188 } else {
189 pa = isl_multi_pw_aff_get_pw_aff(mpa, 0);
190 ast_expr = isl_ast_build_expr_from_pw_aff(build, pa);
191 isl_multi_pw_aff_free(mpa);
193 if (expr->n_arg > 0)
194 ast_expr = isl_ast_expr_substitute_ids(ast_expr, id2expr);
195 if (data->fn_expr)
196 ast_expr = data->fn_expr(ast_expr, expr->acc.ref_id,
197 data->user_index);
199 return ast_expr;
202 /* Construct an AST expression from the access expression "expr" and
203 * add the mapping from reference identifier to AST expression to
204 * data->ref2expr.
206 static int add_access(struct pet_expr *expr, void *user)
208 struct pet_build_ast_expr_data *data = user;
209 isl_id *id;
210 isl_ast_expr *ast_expr;
212 ast_expr = pet_expr_build_ast_expr(expr, data);
214 id = isl_id_copy(expr->acc.ref_id);
215 data->ref2expr = isl_id_to_ast_expr_set(data->ref2expr, id, ast_expr);
217 return 0;
220 /* Construct an associative array from reference identifiers of
221 * access expressions in "stmt" to the corresponding isl_ast_expr.
222 * Each index expression is first transformed through "fn_index"
223 * (if not NULL). Then an AST expression is generated using "build".
224 * Finally, the AST expression is transformed using "fn_expr"
225 * (if not NULL).
227 __isl_give isl_id_to_ast_expr *pet_stmt_build_ast_exprs(struct pet_stmt *stmt,
228 __isl_keep isl_ast_build *build,
229 __isl_give isl_multi_pw_aff *(*fn_index)(
230 __isl_take isl_multi_pw_aff *mpa, __isl_keep isl_id *id,
231 void *user), void *user_index,
232 __isl_give isl_ast_expr *(*fn_expr)(__isl_take isl_ast_expr *expr,
233 __isl_keep isl_id *id, void *user), void *user_expr)
235 struct pet_build_ast_expr_data data =
236 { build, fn_index, user_index, fn_expr, user_expr };
237 isl_ctx *ctx;
239 if (!stmt || !build)
240 return NULL;
242 ctx = isl_ast_build_get_ctx(build);
243 data.ref2expr = isl_id_to_ast_expr_alloc(ctx, 0);
244 if (pet_expr_foreach_access_expr(stmt->body, &add_access, &data) < 0)
245 data.ref2expr = isl_id_to_ast_expr_free(data.ref2expr);
247 return data.ref2expr;
250 /* Print the access expression "expr" to "p".
252 * We look up the corresponding isl_ast_expr in "ref2expr"
253 * and print that to "p".
255 static __isl_give isl_printer *print_access(__isl_take isl_printer *p,
256 struct pet_expr *expr, __isl_keep isl_id_to_ast_expr *ref2expr)
258 isl_ast_expr *ast_expr;
259 int is_access;
261 if (!isl_id_to_ast_expr_has(ref2expr, expr->acc.ref_id))
262 isl_die(isl_printer_get_ctx(p), isl_error_internal,
263 "missing expression", return isl_printer_free(p));
265 ast_expr = isl_id_to_ast_expr_get(ref2expr,
266 isl_id_copy(expr->acc.ref_id));
267 is_access = isl_ast_expr_get_type(ast_expr) == isl_ast_expr_op &&
268 isl_ast_expr_get_op_type(ast_expr) == isl_ast_op_access;
269 if (!is_access)
270 p = isl_printer_print_str(p, "(");
271 p = isl_printer_print_ast_expr(p, ast_expr);
272 if (!is_access)
273 p = isl_printer_print_str(p, ")");
274 isl_ast_expr_free(ast_expr);
276 return p;
279 /* Is "op" a postfix operator?
281 static int is_postfix(enum pet_op_type op)
283 switch (op) {
284 case pet_op_post_inc:
285 case pet_op_post_dec:
286 return 1;
287 default:
288 return 0;
292 /* Print "expr" to "p".
294 * If "outer" is set, then we are printing the outer expression statement.
296 * The access subexpressions are replaced by the isl_ast_expr
297 * associated to its reference identifier in "ref2expr".
299 static __isl_take isl_printer *print_pet_expr(__isl_take isl_printer *p,
300 struct pet_expr *expr, int outer,
301 __isl_keep isl_id_to_ast_expr *ref2expr)
303 int i;
305 switch (expr->type) {
306 case pet_expr_double:
307 p = isl_printer_print_str(p, expr->d.s);
308 break;
309 case pet_expr_access:
310 p = print_access(p, expr, ref2expr);
311 break;
312 case pet_expr_unary:
313 if (!outer)
314 p = isl_printer_print_str(p, "(");
315 if (!is_postfix(expr->op))
316 p = isl_printer_print_str(p, pet_op_str(expr->op));
317 p = print_pet_expr(p, expr->args[pet_un_arg], 0, ref2expr);
318 if (is_postfix(expr->op))
319 p = isl_printer_print_str(p, pet_op_str(expr->op));
320 if (!outer)
321 p = isl_printer_print_str(p, ")");
322 break;
323 case pet_expr_binary:
324 if (!outer)
325 p = isl_printer_print_str(p, "(");
326 p = print_pet_expr(p, expr->args[pet_bin_lhs], 0,
327 ref2expr);
328 p = isl_printer_print_str(p, " ");
329 p = isl_printer_print_str(p, pet_op_str(expr->op));
330 p = isl_printer_print_str(p, " ");
331 p = print_pet_expr(p, expr->args[pet_bin_rhs], 0,
332 ref2expr);
333 if (!outer)
334 p = isl_printer_print_str(p, ")");
335 break;
336 case pet_expr_ternary:
337 if (!outer)
338 p = isl_printer_print_str(p, "(");
339 p = print_pet_expr(p, expr->args[pet_ter_cond], 0,
340 ref2expr);
341 p = isl_printer_print_str(p, " ? ");
342 p = print_pet_expr(p, expr->args[pet_ter_true], 0,
343 ref2expr);
344 p = isl_printer_print_str(p, " : ");
345 p = print_pet_expr(p, expr->args[pet_ter_false], 0,
346 ref2expr);
347 if (!outer)
348 p = isl_printer_print_str(p, ")");
349 break;
350 case pet_expr_call:
351 p = isl_printer_print_str(p, expr->name);
352 p = isl_printer_print_str(p, "(");
353 for (i = 0; i < expr->n_arg; ++i) {
354 if (i)
355 p = isl_printer_print_str(p, ", ");
356 p = print_pet_expr(p, expr->args[i], 1, ref2expr);
358 p = isl_printer_print_str(p, ")");
359 break;
360 case pet_expr_cast:
361 if (!outer)
362 p = isl_printer_print_str(p, "(");
363 p = isl_printer_print_str(p, "(");
364 p = isl_printer_print_str(p, expr->type_name);
365 p = isl_printer_print_str(p, ") ");
366 p = print_pet_expr(p, expr->args[0], 0, ref2expr);
367 if (!outer)
368 p = isl_printer_print_str(p, ")");
369 break;
372 return p;
375 /* Print "stmt" to "p".
377 * The access expressions in "stmt" are replaced by the isl_ast_expr
378 * associated to its reference identifier in "ref2expr".
380 __isl_give isl_printer *pet_stmt_print_body(struct pet_stmt *stmt,
381 __isl_take isl_printer *p, __isl_keep isl_id_to_ast_expr *ref2expr)
383 if (!stmt)
384 return isl_printer_free(p);
385 p = isl_printer_start_line(p);
386 p = print_pet_expr(p, stmt->body, 1, ref2expr);
387 p = isl_printer_print_str(p, ";");
388 p = isl_printer_end_line(p);
390 return p;
393 /* Copy the contents of "input" from offset "start" to "end" to "output".
395 int copy(FILE *input, FILE *output, long start, long end)
397 char buffer[1024];
398 size_t n, m;
400 if (end < 0) {
401 fseek(input, 0, SEEK_END);
402 end = ftell(input);
405 fseek(input, start, SEEK_SET);
407 while (start < end) {
408 n = end - start;
409 if (n > 1024)
410 n = 1024;
411 n = fread(buffer, 1, n, input);
412 if (n <= 0)
413 return -1;
414 m = fwrite(buffer, 1, n, output);
415 if (n != m)
416 return -1;
417 start += n;
420 return 0;