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
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
37 #include <isl/ast_build.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
{
52 __isl_give isl_multi_pw_aff
*(*fn_index
)(
53 __isl_take isl_multi_pw_aff
*mpa
, __isl_keep isl_id
*id
,
56 __isl_give isl_ast_expr
*(*fn_expr
)(__isl_take isl_ast_expr
*expr
,
57 __isl_keep isl_id
*id
, void *user
);
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
)
82 isl_space
*space
, *space2
;
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,
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
) {
105 aff
= isl_aff_var_on_domain(isl_local_space_copy(ls
),
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
)
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
);
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
160 static __isl_give isl_ast_expr
*pet_expr_build_ast_expr(struct pet_expr
*expr
,
161 struct pet_build_ast_expr_data
*data
)
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
;
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
);
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
);
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
);
194 ast_expr
= isl_ast_expr_substitute_ids(ast_expr
, id2expr
);
196 ast_expr
= data
->fn_expr(ast_expr
, expr
->acc
.ref_id
,
202 /* Construct an AST expression from the access expression "expr" and
203 * add the mapping from reference identifier to AST expression to
206 static int add_access(struct pet_expr
*expr
, void *user
)
208 struct pet_build_ast_expr_data
*data
= user
;
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
);
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"
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
};
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
;
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
;
270 p
= isl_printer_print_str(p
, "(");
271 p
= isl_printer_print_ast_expr(p
, ast_expr
);
273 p
= isl_printer_print_str(p
, ")");
274 isl_ast_expr_free(ast_expr
);
279 /* Is "op" a postfix operator?
281 static int is_postfix(enum pet_op_type op
)
284 case pet_op_post_inc
:
285 case pet_op_post_dec
:
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
)
305 switch (expr
->type
) {
306 case pet_expr_double
:
307 p
= isl_printer_print_str(p
, expr
->d
.s
);
309 case pet_expr_access
:
310 p
= print_access(p
, expr
, ref2expr
);
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
));
321 p
= isl_printer_print_str(p
, ")");
323 case pet_expr_binary
:
325 p
= isl_printer_print_str(p
, "(");
326 p
= print_pet_expr(p
, expr
->args
[pet_bin_lhs
], 0,
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,
334 p
= isl_printer_print_str(p
, ")");
336 case pet_expr_ternary
:
338 p
= isl_printer_print_str(p
, "(");
339 p
= print_pet_expr(p
, expr
->args
[pet_ter_cond
], 0,
341 p
= isl_printer_print_str(p
, " ? ");
342 p
= print_pet_expr(p
, expr
->args
[pet_ter_true
], 0,
344 p
= isl_printer_print_str(p
, " : ");
345 p
= print_pet_expr(p
, expr
->args
[pet_ter_false
], 0,
348 p
= isl_printer_print_str(p
, ")");
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
) {
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
, ")");
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
);
368 p
= isl_printer_print_str(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 * If the statement is an assume statement, then we print nothing.
382 __isl_give isl_printer
*pet_stmt_print_body(struct pet_stmt
*stmt
,
383 __isl_take isl_printer
*p
, __isl_keep isl_id_to_ast_expr
*ref2expr
)
386 return isl_printer_free(p
);
387 if (pet_stmt_is_assume(stmt
))
389 p
= isl_printer_start_line(p
);
390 p
= print_pet_expr(p
, stmt
->body
, 1, ref2expr
);
391 p
= isl_printer_print_str(p
, ";");
392 p
= isl_printer_end_line(p
);
397 /* Copy the contents of "input" from offset "start" to "end" to "output".
399 int copy(FILE *input
, FILE *output
, long start
, long end
)
405 fseek(input
, 0, SEEK_END
);
409 fseek(input
, start
, SEEK_SET
);
411 while (start
< end
) {
415 n
= fread(buffer
, 1, n
, input
);
418 m
= fwrite(buffer
, 1, n
, output
);