skip.c: add missing copyright statement
[pet.git] / context.c
blobe91043b509087119ec16beba5b22c14e0fa22832
1 /*
2 * Copyright 2011 Leiden University. All rights reserved.
3 * Copyright 2014 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>
37 #include "aff.h"
38 #include "array.h"
39 #include "context.h"
40 #include "expr.h"
41 #include "expr_arg.h"
42 #include "nest.h"
43 #include "patch.h"
44 #include "tree.h"
46 /* A pet_context represents the context in which a pet_expr
47 * in converted to an affine expression.
49 * "domain" prescribes the domain of the affine expressions.
51 * "assignments" maps variable names to their currently known values.
52 * Internally, the domains of the values may be equal to some prefix
53 * of the space of "domain", but the domains are updated to be
54 * equal to the space of "domain" before passing them to the user.
56 * If "allow_nested" is set, then the affine expression created
57 * in this context may involve new parameters that encode a pet_expr.
59 struct pet_context {
60 int ref;
62 isl_set *domain;
63 isl_id_to_pw_aff *assignments;
64 int allow_nested;
67 /* Create a pet_context with the given domain, assignments,
68 * and value for allow_nested.
70 static __isl_give pet_context *context_alloc(__isl_take isl_set *domain,
71 __isl_take isl_id_to_pw_aff *assignments, int allow_nested)
73 pet_context *pc;
75 if (!domain || !assignments)
76 goto error;
78 pc = isl_calloc_type(isl_set_get_ctx(domain), struct pet_context);
79 if (!pc)
80 goto error;
82 pc->ref = 1;
83 pc->domain = domain;
84 pc->assignments = assignments;
85 pc->allow_nested = allow_nested;
87 return pc;
88 error:
89 isl_set_free(domain);
90 isl_id_to_pw_aff_free(assignments);
91 return NULL;
94 /* Create a pet_context with the given domain.
96 * Initially, there are no assigned values and parameters that
97 * encode a pet_expr are not allowed.
99 __isl_give pet_context *pet_context_alloc(__isl_take isl_set *domain)
101 isl_id_to_pw_aff *assignments;
103 if (!domain)
104 return NULL;
106 assignments = isl_id_to_pw_aff_alloc(isl_set_get_ctx(domain), 0);
107 return context_alloc(domain, assignments, 0);
110 /* Return an independent duplicate of "pc".
112 static __isl_give pet_context *pet_context_dup(__isl_keep pet_context *pc)
114 pet_context *dup;
116 if (!pc)
117 return NULL;
119 dup = context_alloc(isl_set_copy(pc->domain),
120 isl_id_to_pw_aff_copy(pc->assignments),
121 pc->allow_nested);
123 return dup;
126 /* Return a pet_context that is equal to "pc" and that has only one reference.
128 static __isl_give pet_context *pet_context_cow(__isl_take pet_context *pc)
130 if (!pc)
131 return NULL;
133 if (pc->ref == 1)
134 return pc;
135 pc->ref--;
136 return pet_context_dup(pc);
139 /* Return an extra reference to "pc".
141 __isl_give pet_context *pet_context_copy(__isl_keep pet_context *pc)
143 if (!pc)
144 return NULL;
146 pc->ref++;
147 return pc;
150 /* Free a reference to "pc" and return NULL.
152 __isl_null pet_context *pet_context_free(__isl_take pet_context *pc)
154 if (!pc)
155 return NULL;
156 if (--pc->ref > 0)
157 return NULL;
159 isl_set_free(pc->domain);
160 isl_id_to_pw_aff_free(pc->assignments);
161 free(pc);
162 return NULL;
165 /* Return the isl_ctx in which "pc" was created.
167 isl_ctx *pet_context_get_ctx(__isl_keep pet_context *pc)
169 return pc ? isl_set_get_ctx(pc->domain) : NULL;
172 /* Return the domain of "pc".
174 __isl_give isl_set *pet_context_get_domain(__isl_keep pet_context *pc)
176 if (!pc)
177 return NULL;
178 return isl_set_copy(pc->domain);
181 /* Return the domain of "pc" in a form that is suitable
182 * for use as a gist context.
183 * In particular, remove all references to nested expression parameters
184 * so that they do not get introduced in the gisted expression.
186 __isl_give isl_set *pet_context_get_gist_domain(__isl_keep pet_context *pc)
188 isl_set *domain;
190 domain = pet_context_get_domain(pc);
191 domain = pet_nested_remove_from_set(domain);
192 return domain;
195 /* Return the domain space of "pc".
197 * The domain of "pc" may have constraints involving parameters
198 * that encode a pet_expr. These parameters are not relevant
199 * outside this domain. Furthermore, they need to be resolved
200 * from the final result, so we do not want to propagate them needlessly.
202 __isl_give isl_space *pet_context_get_space(__isl_keep pet_context *pc)
204 isl_space *space;
206 if (!pc)
207 return NULL;
209 space = isl_set_get_space(pc->domain);
210 space = pet_nested_remove_from_space(space);
211 return space;
214 /* Return the dimension of the domain space of "pc".
216 unsigned pet_context_dim(__isl_keep pet_context *pc)
218 if (!pc)
219 return 0;
220 return isl_set_dim(pc->domain, isl_dim_set);
223 /* Return the assignments of "pc".
225 __isl_give isl_id_to_pw_aff *pet_context_get_assignments(
226 __isl_keep pet_context *pc)
228 if (!pc)
229 return NULL;
230 return isl_id_to_pw_aff_copy(pc->assignments);
233 /* Is "id" assigned any value in "pc"?
235 int pet_context_is_assigned(__isl_keep pet_context *pc, __isl_keep isl_id *id)
237 if (!pc || !id)
238 return -1;
239 return isl_id_to_pw_aff_has(pc->assignments, id);
242 /* Return the value assigned to "id" in "pc".
244 * Some dimensions may have been added to pc->domain after the value
245 * associated to "id" was added. We therefore need to adjust the domain
246 * of the stored value to match pc->domain by adding the missing
247 * dimensions.
249 __isl_give isl_pw_aff *pet_context_get_value(__isl_keep pet_context *pc,
250 __isl_take isl_id *id)
252 int dim;
253 isl_pw_aff *pa;
254 isl_multi_aff *ma;
256 if (!pc || !id)
257 goto error;
259 pa = isl_id_to_pw_aff_get(pc->assignments, id);
260 dim = isl_pw_aff_dim(pa, isl_dim_in);
261 if (dim == isl_set_dim(pc->domain, isl_dim_set))
262 return pa;
264 ma = pet_prefix_projection(pet_context_get_space(pc), dim);
265 pa = isl_pw_aff_pullback_multi_aff(pa, ma);
267 return pa;
268 error:
269 isl_id_free(id);
270 return NULL;
273 /* Assign the value "value" to "id" in "pc", replacing the previously
274 * assigned value, if any.
276 __isl_give pet_context *pet_context_set_value(__isl_take pet_context *pc,
277 __isl_take isl_id *id, isl_pw_aff *value)
279 pc = pet_context_cow(pc);
280 if (!pc)
281 goto error;
282 pc->assignments = isl_id_to_pw_aff_set(pc->assignments, id, value);
283 if (!pc->assignments)
284 return pet_context_free(pc);
285 return pc;
286 error:
287 isl_id_free(id);
288 isl_pw_aff_free(value);
289 return NULL;
292 /* Remove any assignment to "id" in "pc".
294 __isl_give pet_context *pet_context_clear_value(__isl_keep pet_context *pc,
295 __isl_take isl_id *id)
297 pc = pet_context_cow(pc);
298 if (!pc)
299 goto error;
300 pc->assignments = isl_id_to_pw_aff_drop(pc->assignments, id);
301 if (!pc->assignments)
302 return pet_context_free(pc);
303 return pc;
304 error:
305 isl_id_free(id);
306 return NULL;
309 /* Are affine expressions created in this context allowed to involve
310 * parameters that encode a pet_expr?
312 int pet_context_allow_nesting(__isl_keep pet_context *pc)
314 if (!pc)
315 return -1;
316 return pc->allow_nested;
319 /* Allow affine expressions created in this context to involve
320 * parameters that encode a pet_expr based on the value of "allow_nested".
322 __isl_give pet_context *pet_context_set_allow_nested(__isl_take pet_context *pc,
323 int allow_nested)
325 if (!pc)
326 return NULL;
327 if (pc->allow_nested == allow_nested)
328 return pc;
329 pc = pet_context_cow(pc);
330 if (!pc)
331 return NULL;
332 pc->allow_nested = allow_nested;
333 return pc;
336 /* If the access expression "expr" writes to a (non-virtual) scalar,
337 * then remove any assignment to the scalar in "pc".
339 static int clear_write(__isl_keep pet_expr *expr, void *user)
341 isl_id *id;
342 pet_context **pc = (pet_context **) user;
344 if (!pet_expr_access_is_write(expr))
345 return 0;
346 if (!pet_expr_is_scalar_access(expr))
347 return 0;
349 id = pet_expr_access_get_id(expr);
350 if (isl_id_get_user(id))
351 *pc = pet_context_clear_value(*pc, id);
352 else
353 isl_id_free(id);
355 return 0;
358 /* Look for any writes to scalar variables in "expr" and
359 * remove any assignment to them in "pc".
361 __isl_give pet_context *pet_context_clear_writes_in_expr(
362 __isl_take pet_context *pc, __isl_keep pet_expr *expr)
364 if (pet_expr_foreach_access_expr(expr, &clear_write, &pc) < 0)
365 pc = pet_context_free(pc);
367 return pc;
370 /* Look for any writes to scalar variables in "tree" and
371 * remove any assignment to them in "pc".
373 __isl_give pet_context *pet_context_clear_writes_in_tree(
374 __isl_take pet_context *pc, __isl_keep pet_tree *tree)
376 if (pet_tree_foreach_access_expr(tree, &clear_write, &pc) < 0)
377 pc = pet_context_free(pc);
379 return pc;
382 /* Internal data structure for pet_context_add_parameters.
384 * "pc" is the context that is being updated.
385 * "get_array_size" is a callback function that can be used to determine
386 * the size of the array that is accessed by a given access expression.
387 * "user" is the user data for this callback.
389 struct pet_context_add_parameter_data {
390 pet_context *pc;
391 __isl_give pet_expr *(*get_array_size)(__isl_keep pet_expr *access,
392 void *user);
393 void *user;
396 /* Given an access expression "expr", add a parameter assignment to data->pc
397 * to the variable being accessed, provided it is a read from an integer
398 * scalar variable.
399 * If an array is being accesed, then recursively call the function
400 * on each of the access expressions in the size expression of the array.
402 static int add_parameter(__isl_keep pet_expr *expr, void *user)
404 struct pet_context_add_parameter_data *data = user;
405 int pos;
406 isl_id *id;
407 isl_space *space;
408 isl_local_space *ls;
409 isl_aff *aff;
410 isl_pw_aff *pa;
412 if (!pet_expr_is_scalar_access(expr)) {
413 pet_expr *size = data->get_array_size(expr, data->user);
414 if (pet_expr_foreach_access_expr(size,
415 &add_parameter, data) < 0)
416 data->pc = pet_context_free(data->pc);
417 pet_expr_free(size);
418 return 0;
420 if (!pet_expr_access_is_read(expr))
421 return 0;
422 if (pet_expr_get_type_size(expr) == 0)
423 return 0;
425 id = pet_expr_access_get_id(expr);
426 if (pet_context_is_assigned(data->pc, id)) {
427 isl_id_free(id);
428 return 0;
431 space = pet_context_get_space(data->pc);
432 pos = isl_space_find_dim_by_id(space, isl_dim_param, id);
433 if (pos < 0) {
434 pos = isl_space_dim(space, isl_dim_param);
435 space = isl_space_add_dims(space, isl_dim_param, 1);
436 space = isl_space_set_dim_id(space, isl_dim_param, pos,
437 isl_id_copy(id));
440 ls = isl_local_space_from_space(space);
441 aff = isl_aff_var_on_domain(ls, isl_dim_param, pos);
442 pa = isl_pw_aff_from_aff(aff);
443 data->pc = pet_context_set_value(data->pc, id, pa);
445 return 0;
448 /* Add an assignment to "pc" for each parameter in "tree".
449 * "get_array_size" is a callback function that can be used to determine
450 * the size of the array that is accessed by a given access expression.
452 * We initially treat as parameters any integer variable that is read
453 * anywhere in "tree" or in any of the size expressions for any of
454 * the arrays accessed in "tree".
455 * Then we remove from those variables that are written anywhere
456 * inside "tree".
458 __isl_give pet_context *pet_context_add_parameters(__isl_take pet_context *pc,
459 __isl_keep pet_tree *tree,
460 __isl_give pet_expr *(*get_array_size)(__isl_keep pet_expr *access,
461 void *user), void *user)
463 struct pet_context_add_parameter_data data;
465 data.pc = pc;
466 data.get_array_size = get_array_size;
467 data.user = user;
468 if (pet_tree_foreach_access_expr(tree, &add_parameter, &data) < 0)
469 data.pc = pet_context_free(data.pc);
471 data.pc = pet_context_clear_writes_in_tree(data.pc, tree);
473 return data.pc;
476 /* Given an access expression, check if it reads a scalar variable
477 * that has a known value in "pc".
478 * If so, then replace the access by an access to that value.
480 static __isl_give pet_expr *access_plug_in_affine_read(
481 __isl_take pet_expr *expr, void *user)
483 pet_context *pc = user;
484 isl_pw_aff *pa;
486 if (pet_expr_access_is_write(expr))
487 return expr;
488 if (!pet_expr_is_scalar_access(expr))
489 return expr;
491 pa = pet_expr_extract_affine(expr, pc);
492 if (!pa)
493 return pet_expr_free(expr);
494 if (isl_pw_aff_involves_nan(pa)) {
495 isl_pw_aff_free(pa);
496 return expr;
499 pet_expr_free(expr);
500 expr = pet_expr_from_index(isl_multi_pw_aff_from_pw_aff(pa));
502 return expr;
505 /* Replace every read access in "expr" to a scalar variable
506 * that has a known value in "pc" by that known value.
508 static __isl_give pet_expr *plug_in_affine_read(__isl_take pet_expr *expr,
509 __isl_keep pet_context *pc)
511 return pet_expr_map_access(expr, &access_plug_in_affine_read, pc);
514 /* Add an extra affine expression to "mpa" that is equal to
515 * an extra dimension in the range of the wrapped relation in the domain
516 * of "mpa". "n_arg" is the original number of dimensions in this range.
518 * That is, if "n_arg" is 0, then the input has the form
520 * D(i) -> [f(i)]
522 * and the output has the form
524 * [D(i) -> [y]] -> [f(i), y]
526 * If "n_arg" is different from 0, then the input has the form
528 * [D(i) -> [x]] -> [f(i,x)]
530 * with x consisting of "n_arg" dimensions, and the output has the form
532 * [D(i) -> [x,y]] -> [f(i,x), y]
535 * We first adjust the domain of "mpa" and then add the extra
536 * affine expression (y).
538 static __isl_give isl_multi_pw_aff *add_arg(__isl_take isl_multi_pw_aff *mpa,
539 int n_arg)
541 int dim;
542 isl_space *space;
543 isl_multi_aff *ma;
544 isl_multi_pw_aff *mpa2;
546 if (n_arg == 0) {
547 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
548 dim = isl_space_dim(space, isl_dim_set);
549 space = isl_space_from_domain(space);
550 space = isl_space_add_dims(space, isl_dim_set, 1);
551 ma = isl_multi_aff_domain_map(space);
552 } else {
553 isl_multi_aff *ma2;
554 isl_space *dom, *ran;
556 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
557 space = isl_space_unwrap(space);
558 dom = isl_space_domain(isl_space_copy(space));
559 dim = isl_space_dim(dom, isl_dim_set);
560 ran = isl_space_range(space);
561 ran = isl_space_add_dims(ran, isl_dim_set, 1);
562 space = isl_space_map_from_set(dom);
563 ma = isl_multi_aff_identity(space);
564 ma2 = isl_multi_aff_project_out_map(ran, isl_dim_set, n_arg, 1);
565 ma = isl_multi_aff_product(ma, ma2);
568 mpa = isl_multi_pw_aff_pullback_multi_aff(mpa, ma);
569 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
570 ma = isl_multi_aff_project_out_map(space, isl_dim_set, 0, dim + n_arg);
571 mpa2 = isl_multi_pw_aff_from_multi_aff(ma);
572 mpa = isl_multi_pw_aff_flat_range_product(mpa, mpa2);
574 return mpa;
577 /* Add the integer value from "arg" to "mpa".
579 static __isl_give isl_multi_pw_aff *add_int(__isl_take isl_multi_pw_aff *mpa,
580 __isl_take pet_expr *arg)
582 isl_space *space;
583 isl_val *v;
584 isl_aff *aff;
585 isl_multi_pw_aff *mpa_arg;
587 v = pet_expr_int_get_val(arg);
588 pet_expr_free(arg);
590 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
591 aff = isl_aff_val_on_domain(isl_local_space_from_space(space), v);
592 mpa_arg = isl_multi_pw_aff_from_pw_aff(isl_pw_aff_from_aff(aff));
594 mpa = isl_multi_pw_aff_flat_range_product(mpa, mpa_arg);
596 return mpa;
599 /* Add the affine expression from "arg" to "mpa".
600 * "n_arg" is the number of dimensions in the range of the wrapped
601 * relation in the domain of "mpa".
603 static __isl_give isl_multi_pw_aff *add_aff(__isl_take isl_multi_pw_aff *mpa,
604 int n_arg, __isl_take pet_expr *arg)
606 isl_multi_pw_aff *mpa_arg;
608 mpa_arg = pet_expr_access_get_index(arg);
609 pet_expr_free(arg);
611 if (n_arg > 0) {
612 isl_space *space;
613 isl_multi_aff *ma;
615 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
616 space = isl_space_unwrap(space);
617 ma = isl_multi_aff_domain_map(space);
618 mpa_arg = isl_multi_pw_aff_pullback_multi_aff(mpa_arg, ma);
621 mpa = isl_multi_pw_aff_flat_range_product(mpa, mpa_arg);
623 return mpa;
626 /* Combine the index expression of "expr" with the subaccess relation "access".
627 * If "add" is set, then it is not the index expression of "expr" itself
628 * that is passed to the function, but its address.
630 * We call patch_map on each map in "access" and return the combined results.
632 static __isl_give isl_union_map *patch(__isl_take isl_union_map *access,
633 __isl_keep pet_expr *expr, int add)
635 isl_multi_pw_aff *prefix;
637 prefix = pet_expr_access_get_index(expr);
638 return pet_patch_union_map(prefix, access, add, 1);
641 /* Set the access relations of "expr", which appears in the argument
642 * at position "pos" in a call expression by composing the access
643 * relations in "summary" with the expression "int_arg" of the integer
644 * arguments in terms of the domain and expression arguments of "expr" and
645 * combining the result with the index expression passed to the function.
646 * If "add" is set, then it is not "expr" itself that is passed
647 * to the function, but the address of "expr".
649 * We reset the read an write flag of "expr" and rely on
650 * pet_expr_access_set_access setting the flags based on
651 * the access relations.
653 * After relating each access relation of the called function
654 * to the domain and expression arguments at the call site,
655 * the result is combined with the index expression by the function patch
656 * and then stored in the access expression.
658 static __isl_give pet_expr *set_access_relations(__isl_take pet_expr *expr,
659 __isl_keep pet_function_summary *summary, int pos,
660 __isl_take isl_multi_pw_aff *int_arg, int add)
662 enum pet_expr_access_type type;
664 expr = pet_expr_access_set_read(expr, 0);
665 expr = pet_expr_access_set_write(expr, 0);
666 for (type = pet_expr_access_begin; type < pet_expr_access_end; ++type) {
667 isl_union_map *access;
669 access = pet_function_summary_arg_get_access(summary,
670 pos, type);
671 access = isl_union_map_preimage_domain_multi_pw_aff(access,
672 isl_multi_pw_aff_copy(int_arg));
673 access = patch(access, expr, add);
674 expr = pet_expr_access_set_access(expr, type, access);
676 isl_multi_pw_aff_free(int_arg);
678 return expr;
681 /* Set the access relations of "arg", which appears in the argument
682 * at position "pos" in the call expression "call" based on the
683 * information in "summary".
684 * If "add" is set, then it is not "arg" itself that is passed
685 * to the function, but the address of "arg".
687 * We create an affine function "int_arg" that expresses
688 * the integer function call arguments in terms of the domain of "arg"
689 * (i.e., the outer loop iterators) and the expression arguments.
690 * If the actual argument is not an affine expression or if it itself
691 * has expression arguments, then it is added as an argument to "arg" and
692 * "int_arg" is made to reference this additional expression argument.
694 * Finally, we call set_access_relations to plug in the actual arguments
695 * (expressed in "int_arg") into the access relations in "summary" and
696 * to add the resulting access relations to "arg".
698 static __isl_give pet_expr *access_plug_in_summary(__isl_take pet_expr *arg,
699 __isl_keep pet_expr *call, __isl_keep pet_function_summary *summary,
700 int pos, int add)
702 int j, n;
703 isl_space *space;
704 isl_multi_pw_aff *int_arg;
705 int arg_n_arg;
707 space = pet_expr_access_get_augmented_domain_space(arg);
708 space = isl_space_from_domain(space);
709 arg_n_arg = pet_expr_get_n_arg(arg);
710 int_arg = isl_multi_pw_aff_zero(space);
711 n = pet_function_summary_get_n_arg(summary);
712 for (j = 0; j < n; ++j) {
713 pet_expr *arg_j;
714 int arg_j_n_arg;
716 if (!pet_function_summary_arg_is_int(summary, j))
717 continue;
719 arg_j = pet_expr_get_arg(call, j);
720 arg_j_n_arg = pet_expr_get_n_arg(arg_j);
721 if (pet_expr_get_type(arg_j) == pet_expr_int) {
722 int_arg = add_int(int_arg, arg_j);
723 } else if (arg_j_n_arg != 0 || !pet_expr_is_affine(arg_j)) {
724 arg = pet_expr_insert_arg(arg, arg_n_arg,
725 arg_j);
726 int_arg = add_arg(int_arg, arg_n_arg);
727 arg_n_arg++;
728 } else {
729 int_arg = add_aff(int_arg, arg_n_arg, arg_j);
732 arg = set_access_relations(arg, summary, pos, int_arg, add);
734 return arg;
737 /* Given the argument "arg" at position "pos" of "call",
738 * check if it is either an access expression or the address
739 * of an access expression. If so, use the information in "summary"
740 * to set the access relations of the access expression.
742 static __isl_give pet_expr *arg_plug_in_summary(__isl_take pet_expr *arg,
743 __isl_keep pet_expr *call, __isl_keep pet_function_summary *summary,
744 int pos)
746 enum pet_expr_type type;
747 pet_expr *arg2;
749 type = pet_expr_get_type(arg);
750 if (type == pet_expr_access)
751 return access_plug_in_summary(arg, call, summary, pos, 0);
752 if (!pet_expr_is_address_of(arg))
753 return arg;
755 arg2 = pet_expr_get_arg(arg, 0);
756 if (pet_expr_get_type(arg2) == pet_expr_access)
757 arg2 = access_plug_in_summary(arg2, call, summary, pos, 1);
758 arg = pet_expr_set_arg(arg, 0, arg2);
760 return arg;
763 /* Given a call expression, check if the integer arguments can
764 * be represented by affine expressions in the context "pc"
765 * (assuming they are not already affine expressions).
766 * If so, replace these arguments by the corresponding affine expressions.
768 static __isl_give pet_expr *call_plug_in_affine_args(__isl_take pet_expr *call,
769 __isl_keep pet_context *pc)
771 int i, n;
773 n = pet_expr_get_n_arg(call);
774 for (i = 0; i < n; ++i) {
775 pet_expr *arg;
776 isl_pw_aff *pa;
778 arg = pet_expr_get_arg(call, i);
779 if (!arg)
780 return pet_expr_free(call);
781 if (pet_expr_get_type_size(arg) == 0 ||
782 pet_expr_is_affine(arg)) {
783 pet_expr_free(arg);
784 continue;
787 pa = pet_expr_extract_affine(arg, pc);
788 pet_expr_free(arg);
789 if (!pa)
790 return pet_expr_free(call);
791 if (isl_pw_aff_involves_nan(pa)) {
792 isl_pw_aff_free(pa);
793 continue;
796 arg = pet_expr_from_index(isl_multi_pw_aff_from_pw_aff(pa));
797 call = pet_expr_set_arg(call, i, arg);
800 return call;
803 /* If "call" has an associated function summary, then use it
804 * to set the access relations of the array arguments of the function call.
806 * We first plug in affine expressions for the integer arguments
807 * whenever possible as these arguments will be plugged in
808 * in the access relations of the array arguments.
810 static __isl_give pet_expr *call_plug_in_summary(__isl_take pet_expr *call,
811 void *user)
813 pet_context *pc = user;
814 pet_function_summary *summary;
815 int i, n;
817 if (!pet_expr_call_has_summary(call))
818 return call;
820 call = call_plug_in_affine_args(call, pc);
822 summary = pet_expr_call_get_summary(call);
823 if (!summary)
824 return pet_expr_free(call);
826 n = pet_expr_get_n_arg(call);
827 for (i = 0; i < n; ++i) {
828 pet_expr *arg_i;
830 if (!pet_function_summary_arg_is_array(summary, i))
831 continue;
833 arg_i = pet_expr_get_arg(call, i);
834 arg_i = arg_plug_in_summary(arg_i, call, summary, i);
835 call = pet_expr_set_arg(call, i, arg_i);
838 pet_function_summary_free(summary);
839 return call;
842 /* For each call subexpression of "expr", plug in the access relations
843 * from the associated function summary (if any).
845 static __isl_give pet_expr *plug_in_summaries(__isl_take pet_expr *expr,
846 __isl_keep pet_context *pc)
848 return pet_expr_map_call(expr, &call_plug_in_summary, pc);
851 /* Evaluate "expr" in the context of "pc".
853 * In particular, we first make sure that all the access expressions
854 * inside "expr" have the same domain as "pc".
855 * Then, we plug in affine expressions for scalar reads,
856 * plug in the arguments of all access expressions in "expr" and
857 * plug in the access relations from the summary functions associated
858 * to call expressions.
860 __isl_give pet_expr *pet_context_evaluate_expr(__isl_keep pet_context *pc,
861 __isl_take pet_expr *expr)
863 expr = pet_expr_insert_domain(expr, pet_context_get_space(pc));
864 expr = plug_in_affine_read(expr, pc);
865 expr = pet_expr_plug_in_args(expr, pc);
866 expr = plug_in_summaries(expr, pc);
867 return expr;
870 /* Wrapper around pet_context_evaluate_expr
871 * for use as a callback to pet_tree_map_expr.
873 static __isl_give pet_expr *evaluate_expr(__isl_take pet_expr *expr,
874 void *user)
876 pet_context *pc = user;
878 return pet_context_evaluate_expr(pc, expr);
881 /* Evaluate "tree" in the context of "pc".
882 * That is, evaluate all the expressions of "tree" in the context of "pc".
884 __isl_give pet_tree *pet_context_evaluate_tree(__isl_keep pet_context *pc,
885 __isl_take pet_tree *tree)
887 return pet_tree_map_expr(tree, &evaluate_expr, pc);
890 /* Add an unbounded inner dimension "id" to pc->domain.
892 * The assignments are not adjusted here and therefore keep
893 * their original domain. These domains need to be adjusted before
894 * these assigned values can be used. This is taken care of by
895 * pet_context_get_value.
897 static __isl_give pet_context *extend_domain(__isl_take pet_context *pc,
898 __isl_take isl_id *id)
900 int pos;
902 pc = pet_context_cow(pc);
903 if (!pc || !id)
904 goto error;
906 pos = pet_context_dim(pc);
907 pc->domain = isl_set_add_dims(pc->domain, isl_dim_set, 1);
908 pc->domain = isl_set_set_dim_id(pc->domain, isl_dim_set, pos, id);
909 if (!pc->domain)
910 return pet_context_free(pc);
912 return pc;
913 error:
914 pet_context_free(pc);
915 isl_id_free(id);
916 return NULL;
919 /* Add an unbounded inner iterator "id" to pc->domain.
920 * Additionally, mark the variable "id" as having the value of this
921 * new inner iterator.
923 __isl_give pet_context *pet_context_add_inner_iterator(
924 __isl_take pet_context *pc, __isl_take isl_id *id)
926 int pos;
927 isl_space *space;
928 isl_local_space *ls;
929 isl_aff *aff;
930 isl_pw_aff *pa;
932 if (!pc || !id)
933 goto error;
935 pos = pet_context_dim(pc);
936 pc = extend_domain(pc, isl_id_copy(id));
937 if (!pc)
938 goto error;
940 space = pet_context_get_space(pc);
941 ls = isl_local_space_from_space(space);
942 aff = isl_aff_var_on_domain(ls, isl_dim_set, pos);
943 pa = isl_pw_aff_from_aff(aff);
945 pc = pet_context_set_value(pc, id, pa);
947 return pc;
948 error:
949 pet_context_free(pc);
950 isl_id_free(id);
951 return NULL;
954 /* Add an inner iterator to pc->domain.
955 * In particular, extend the domain with an inner loop { [t] : t >= 0 }.
957 __isl_give pet_context *pet_context_add_infinite_loop(
958 __isl_take pet_context *pc)
960 int dim;
961 isl_ctx *ctx;
962 isl_id *id;
964 if (!pc)
965 return NULL;
967 dim = pet_context_dim(pc);
968 ctx = pet_context_get_ctx(pc);
969 id = isl_id_alloc(ctx, "t", NULL);
970 pc = extend_domain(pc, id);
971 pc = pet_context_cow(pc);
972 if (!pc)
973 return NULL;
974 pc->domain = isl_set_lower_bound_si(pc->domain, isl_dim_set, dim, 0);
975 if (!pc->domain)
976 return pet_context_free(pc);
978 return pc;
981 /* Internal data structure for preimage_domain.
983 * "ma" is the function under which the preimage should be computed.
984 * "assignments" collects the results.
986 struct pet_preimage_domain_data {
987 isl_multi_aff *ma;
988 isl_id_to_pw_aff *assignments;
991 /* Add the assignment to "key" of the preimage of "val" under data->ma
992 * to data->assignments.
994 * Some dimensions may have been added to the domain of the enclosing
995 * pet_context after the value "val" was added. We therefore need to
996 * adjust the domain of "val" to match the range of data->ma (which
997 * in turn matches the domain of the pet_context), by adding the missing
998 * dimensions.
1000 static isl_stat preimage_domain_pair(__isl_take isl_id *key,
1001 __isl_take isl_pw_aff *val, void *user)
1003 struct pet_preimage_domain_data *data = user;
1004 int dim;
1005 isl_multi_aff *ma;
1007 ma = isl_multi_aff_copy(data->ma);
1009 dim = isl_pw_aff_dim(val, isl_dim_in);
1010 if (dim != isl_multi_aff_dim(data->ma, isl_dim_out)) {
1011 isl_space *space;
1012 isl_multi_aff *proj;
1013 space = isl_multi_aff_get_space(data->ma);
1014 space = isl_space_range(space);
1015 proj = pet_prefix_projection(space, dim);
1016 ma = isl_multi_aff_pullback_multi_aff(proj, ma);
1019 val = isl_pw_aff_pullback_multi_aff(val, ma);
1020 data->assignments = isl_id_to_pw_aff_set(data->assignments, key, val);
1022 return isl_stat_ok;
1025 /* Compute the preimage of "assignments" under the function represented by "ma".
1026 * In other words, plug in "ma" in the domains of the assigned values.
1028 static __isl_give isl_id_to_pw_aff *preimage_domain(
1029 __isl_take isl_id_to_pw_aff *assignments, __isl_keep isl_multi_aff *ma)
1031 struct pet_preimage_domain_data data = { ma };
1032 isl_ctx *ctx;
1034 ctx = isl_id_to_pw_aff_get_ctx(assignments);
1035 data.assignments = isl_id_to_pw_aff_alloc(ctx, 0);
1036 if (isl_id_to_pw_aff_foreach(assignments, &preimage_domain_pair,
1037 &data) < 0)
1038 data.assignments = isl_id_to_pw_aff_free(data.assignments);
1039 isl_id_to_pw_aff_free(assignments);
1041 return data.assignments;
1044 /* Compute the preimage of "pc" under the function represented by "ma".
1045 * In other words, plug in "ma" in the domain of "pc".
1047 __isl_give pet_context *pet_context_preimage_domain(__isl_take pet_context *pc,
1048 __isl_keep isl_multi_aff *ma)
1050 pc = pet_context_cow(pc);
1051 if (!pc)
1052 return NULL;
1053 pc->domain = isl_set_preimage_multi_aff(pc->domain,
1054 isl_multi_aff_copy(ma));
1055 pc->assignments = preimage_domain(pc->assignments, ma);
1056 if (!pc->domain || !pc->assignments)
1057 return pet_context_free(pc);
1058 return pc;
1061 /* Add the constraints of "set" to the domain of "pc".
1063 __isl_give pet_context *pet_context_intersect_domain(__isl_take pet_context *pc,
1064 __isl_take isl_set *set)
1066 pc = pet_context_cow(pc);
1067 if (!pc)
1068 goto error;
1069 pc->domain = isl_set_intersect(pc->domain, set);
1070 if (!pc->domain)
1071 return pet_context_free(pc);
1072 return pc;
1073 error:
1074 pet_context_free(pc);
1075 isl_set_free(set);
1076 return NULL;
1079 void pet_context_dump(__isl_keep pet_context *pc)
1081 if (!pc)
1082 return;
1083 fprintf(stderr, "domain: ");
1084 isl_set_dump(pc->domain);
1085 fprintf(stderr, "assignments: ");
1086 isl_id_to_pw_aff_dump(pc->assignments);
1087 fprintf(stderr, "nesting allowed: %d\n", pc->allow_nested);