add pet_expr_map_top_down
[pet.git] / context.c
blobc3fa99446876d3f32eee411a923d485363cb06d9
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"
45 #include "pet_expr_to_isl_pw_aff.h"
47 /* A pet_context represents the context in which a pet_expr
48 * in converted to an affine expression.
50 * "domain" prescribes the domain of the affine expressions.
52 * "assignments" maps variable names to their currently known values.
53 * Internally, the domains of the values may be equal to some prefix
54 * of the space of "domain", but the domains are updated to be
55 * equal to the space of "domain" before passing them to the user.
57 * If "allow_nested" is set, then the affine expression created
58 * in this context may involve new parameters that encode a pet_expr.
60 * "extracted_affine" caches the results of pet_expr_extract_affine.
61 * It may be NULL if no results have been cached so far and
62 * it is cleared (in pet_context_cow) whenever the context is changed.
64 struct pet_context {
65 int ref;
67 isl_set *domain;
68 isl_id_to_pw_aff *assignments;
69 int allow_nested;
71 pet_expr_to_isl_pw_aff *extracted_affine;
74 /* Create a pet_context with the given domain, assignments,
75 * and value for allow_nested.
77 static __isl_give pet_context *context_alloc(__isl_take isl_set *domain,
78 __isl_take isl_id_to_pw_aff *assignments, int allow_nested)
80 pet_context *pc;
82 if (!domain || !assignments)
83 goto error;
85 pc = isl_calloc_type(isl_set_get_ctx(domain), struct pet_context);
86 if (!pc)
87 goto error;
89 pc->ref = 1;
90 pc->domain = domain;
91 pc->assignments = assignments;
92 pc->allow_nested = allow_nested;
94 return pc;
95 error:
96 isl_set_free(domain);
97 isl_id_to_pw_aff_free(assignments);
98 return NULL;
101 /* Create a pet_context with the given domain.
103 * Initially, there are no assigned values and parameters that
104 * encode a pet_expr are not allowed.
106 __isl_give pet_context *pet_context_alloc(__isl_take isl_set *domain)
108 isl_id_to_pw_aff *assignments;
110 if (!domain)
111 return NULL;
113 assignments = isl_id_to_pw_aff_alloc(isl_set_get_ctx(domain), 0);
114 return context_alloc(domain, assignments, 0);
117 /* Return an independent duplicate of "pc".
119 static __isl_give pet_context *pet_context_dup(__isl_keep pet_context *pc)
121 pet_context *dup;
123 if (!pc)
124 return NULL;
126 dup = context_alloc(isl_set_copy(pc->domain),
127 isl_id_to_pw_aff_copy(pc->assignments),
128 pc->allow_nested);
130 return dup;
133 /* Return a pet_context that is equal to "pc" and that has only one reference.
135 * If "pc" itself only has one reference, then clear the cache of
136 * pet_expr_extract_affine results since the returned pet_context
137 * will be modified and the cached results may no longer be valid
138 * after these modifications.
140 static __isl_give pet_context *pet_context_cow(__isl_take pet_context *pc)
142 if (!pc)
143 return NULL;
145 if (pc->ref == 1) {
146 pet_expr_to_isl_pw_aff_free(pc->extracted_affine);
147 pc->extracted_affine = NULL;
148 return pc;
150 pc->ref--;
151 return pet_context_dup(pc);
154 /* Return an extra reference to "pc".
156 __isl_give pet_context *pet_context_copy(__isl_keep pet_context *pc)
158 if (!pc)
159 return NULL;
161 pc->ref++;
162 return pc;
165 /* Free a reference to "pc" and return NULL.
167 __isl_null pet_context *pet_context_free(__isl_take pet_context *pc)
169 if (!pc)
170 return NULL;
171 if (--pc->ref > 0)
172 return NULL;
174 isl_set_free(pc->domain);
175 isl_id_to_pw_aff_free(pc->assignments);
176 pet_expr_to_isl_pw_aff_free(pc->extracted_affine);
177 free(pc);
178 return NULL;
181 /* If an isl_pw_aff corresponding to "expr" has been cached in "pc",
182 * then return a copy of that isl_pw_aff.
183 * Otherwise, return (isl_bool_false, NULL).
185 __isl_give isl_maybe_isl_pw_aff pet_context_get_extracted_affine(
186 __isl_keep pet_context *pc, __isl_keep pet_expr *expr)
188 isl_maybe_isl_pw_aff m = { isl_bool_false, NULL };
190 if (!pc)
191 goto error;
192 if (!pc->extracted_affine)
193 return m;
194 return pet_expr_to_isl_pw_aff_try_get(pc->extracted_affine, expr);
195 error:
196 m.valid = isl_bool_error;
197 return m;
200 /* Keep track of the fact that "expr" maps to "pa" in "pc".
202 isl_stat pet_context_set_extracted_affine(__isl_keep pet_context *pc,
203 __isl_keep pet_expr *expr, __isl_keep isl_pw_aff *pa)
205 if (!pc || !expr)
206 return isl_stat_error;
208 if (!pc->extracted_affine) {
209 isl_ctx *ctx;
211 ctx = pet_context_get_ctx(pc);
212 pc->extracted_affine = pet_expr_to_isl_pw_aff_alloc(ctx, 1);
215 pc->extracted_affine = pet_expr_to_isl_pw_aff_set(pc->extracted_affine,
216 pet_expr_copy(expr), isl_pw_aff_copy(pa));
217 if (!pc->extracted_affine)
218 return isl_stat_error;
220 return isl_stat_ok;
223 /* Return the isl_ctx in which "pc" was created.
225 isl_ctx *pet_context_get_ctx(__isl_keep pet_context *pc)
227 return pc ? isl_set_get_ctx(pc->domain) : NULL;
230 /* Return the domain of "pc".
232 __isl_give isl_set *pet_context_get_domain(__isl_keep pet_context *pc)
234 if (!pc)
235 return NULL;
236 return isl_set_copy(pc->domain);
239 /* Return the domain of "pc" in a form that is suitable
240 * for use as a gist context.
241 * In particular, remove all references to nested expression parameters
242 * so that they do not get introduced in the gisted expression.
244 __isl_give isl_set *pet_context_get_gist_domain(__isl_keep pet_context *pc)
246 isl_set *domain;
248 domain = pet_context_get_domain(pc);
249 domain = pet_nested_remove_from_set(domain);
250 return domain;
253 /* Return the domain space of "pc".
255 * The domain of "pc" may have constraints involving parameters
256 * that encode a pet_expr. These parameters are not relevant
257 * outside this domain. Furthermore, they need to be resolved
258 * from the final result, so we do not want to propagate them needlessly.
260 __isl_give isl_space *pet_context_get_space(__isl_keep pet_context *pc)
262 isl_space *space;
264 if (!pc)
265 return NULL;
267 space = isl_set_get_space(pc->domain);
268 space = pet_nested_remove_from_space(space);
269 return space;
272 /* Return the dimension of the domain space of "pc".
274 unsigned pet_context_dim(__isl_keep pet_context *pc)
276 if (!pc)
277 return 0;
278 return isl_set_dim(pc->domain, isl_dim_set);
281 /* Return the assignments of "pc".
283 __isl_give isl_id_to_pw_aff *pet_context_get_assignments(
284 __isl_keep pet_context *pc)
286 if (!pc)
287 return NULL;
288 return isl_id_to_pw_aff_copy(pc->assignments);
291 /* Is "id" assigned any value in "pc"?
293 int pet_context_is_assigned(__isl_keep pet_context *pc, __isl_keep isl_id *id)
295 if (!pc || !id)
296 return -1;
297 return isl_id_to_pw_aff_has(pc->assignments, id);
300 /* Return the value assigned to "id" in "pc".
302 * Some dimensions may have been added to pc->domain after the value
303 * associated to "id" was added. We therefore need to adjust the domain
304 * of the stored value to match pc->domain by adding the missing
305 * dimensions.
307 __isl_give isl_pw_aff *pet_context_get_value(__isl_keep pet_context *pc,
308 __isl_take isl_id *id)
310 int dim;
311 isl_pw_aff *pa;
312 isl_multi_aff *ma;
314 if (!pc || !id)
315 goto error;
317 pa = isl_id_to_pw_aff_get(pc->assignments, id);
318 dim = isl_pw_aff_dim(pa, isl_dim_in);
319 if (dim == isl_set_dim(pc->domain, isl_dim_set))
320 return pa;
322 ma = pet_prefix_projection(pet_context_get_space(pc), dim);
323 pa = isl_pw_aff_pullback_multi_aff(pa, ma);
325 return pa;
326 error:
327 isl_id_free(id);
328 return NULL;
331 /* Assign the value "value" to "id" in "pc", replacing the previously
332 * assigned value, if any.
334 __isl_give pet_context *pet_context_set_value(__isl_take pet_context *pc,
335 __isl_take isl_id *id, isl_pw_aff *value)
337 pc = pet_context_cow(pc);
338 if (!pc)
339 goto error;
340 pc->assignments = isl_id_to_pw_aff_set(pc->assignments, id, value);
341 if (!pc->assignments)
342 return pet_context_free(pc);
343 return pc;
344 error:
345 isl_id_free(id);
346 isl_pw_aff_free(value);
347 return NULL;
350 /* Remove any assignment to "id" in "pc".
352 __isl_give pet_context *pet_context_clear_value(__isl_keep pet_context *pc,
353 __isl_take isl_id *id)
355 pc = pet_context_cow(pc);
356 if (!pc)
357 goto error;
358 pc->assignments = isl_id_to_pw_aff_drop(pc->assignments, id);
359 if (!pc->assignments)
360 return pet_context_free(pc);
361 return pc;
362 error:
363 isl_id_free(id);
364 return NULL;
367 /* Are affine expressions created in this context allowed to involve
368 * parameters that encode a pet_expr?
370 int pet_context_allow_nesting(__isl_keep pet_context *pc)
372 if (!pc)
373 return -1;
374 return pc->allow_nested;
377 /* Allow affine expressions created in this context to involve
378 * parameters that encode a pet_expr based on the value of "allow_nested".
380 __isl_give pet_context *pet_context_set_allow_nested(__isl_take pet_context *pc,
381 int allow_nested)
383 if (!pc)
384 return NULL;
385 if (pc->allow_nested == allow_nested)
386 return pc;
387 pc = pet_context_cow(pc);
388 if (!pc)
389 return NULL;
390 pc->allow_nested = allow_nested;
391 return pc;
394 /* If the access expression "expr" writes to a (non-virtual) scalar,
395 * then remove any assignment to the scalar in "pc".
397 static int clear_write(__isl_keep pet_expr *expr, void *user)
399 isl_id *id;
400 pet_context **pc = (pet_context **) user;
402 if (!pet_expr_access_is_write(expr))
403 return 0;
404 if (!pet_expr_is_scalar_access(expr))
405 return 0;
407 id = pet_expr_access_get_id(expr);
408 if (isl_id_get_user(id))
409 *pc = pet_context_clear_value(*pc, id);
410 else
411 isl_id_free(id);
413 return 0;
416 /* Look for any writes to scalar variables in "expr" and
417 * remove any assignment to them in "pc".
419 __isl_give pet_context *pet_context_clear_writes_in_expr(
420 __isl_take pet_context *pc, __isl_keep pet_expr *expr)
422 if (pet_expr_foreach_access_expr(expr, &clear_write, &pc) < 0)
423 pc = pet_context_free(pc);
425 return pc;
428 /* Look for any writes to scalar variables in "tree" and
429 * remove any assignment to them in "pc".
431 __isl_give pet_context *pet_context_clear_writes_in_tree(
432 __isl_take pet_context *pc, __isl_keep pet_tree *tree)
434 if (pet_tree_foreach_access_expr(tree, &clear_write, &pc) < 0)
435 pc = pet_context_free(pc);
437 return pc;
440 /* Internal data structure for pet_context_add_parameters.
442 * "pc" is the context that is being updated.
443 * "get_array_size" is a callback function that can be used to determine
444 * the size of the array that is accessed by a given access expression.
445 * "user" is the user data for this callback.
447 struct pet_context_add_parameter_data {
448 pet_context *pc;
449 __isl_give pet_expr *(*get_array_size)(__isl_keep pet_expr *access,
450 void *user);
451 void *user;
454 /* Given an access expression "expr", add a parameter assignment to data->pc
455 * to the variable being accessed, provided it is a read from an integer
456 * scalar variable.
457 * If an array is being accesed, then recursively call the function
458 * on each of the access expressions in the size expression of the array.
460 static int add_parameter(__isl_keep pet_expr *expr, void *user)
462 struct pet_context_add_parameter_data *data = user;
463 int pos;
464 isl_id *id;
465 isl_space *space;
466 isl_local_space *ls;
467 isl_aff *aff;
468 isl_pw_aff *pa;
470 if (!pet_expr_is_scalar_access(expr)) {
471 pet_expr *size = data->get_array_size(expr, data->user);
472 if (pet_expr_foreach_access_expr(size,
473 &add_parameter, data) < 0)
474 data->pc = pet_context_free(data->pc);
475 pet_expr_free(size);
476 return 0;
478 if (!pet_expr_access_is_read(expr))
479 return 0;
480 if (pet_expr_get_type_size(expr) == 0)
481 return 0;
483 id = pet_expr_access_get_id(expr);
484 if (pet_context_is_assigned(data->pc, id)) {
485 isl_id_free(id);
486 return 0;
489 space = pet_context_get_space(data->pc);
490 pos = isl_space_find_dim_by_id(space, isl_dim_param, id);
491 if (pos < 0) {
492 pos = isl_space_dim(space, isl_dim_param);
493 space = isl_space_add_dims(space, isl_dim_param, 1);
494 space = isl_space_set_dim_id(space, isl_dim_param, pos,
495 isl_id_copy(id));
498 ls = isl_local_space_from_space(space);
499 aff = isl_aff_var_on_domain(ls, isl_dim_param, pos);
500 pa = isl_pw_aff_from_aff(aff);
501 data->pc = pet_context_set_value(data->pc, id, pa);
503 return 0;
506 /* Add an assignment to "pc" for each parameter in "tree".
507 * "get_array_size" is a callback function that can be used to determine
508 * the size of the array that is accessed by a given access expression.
510 * We initially treat as parameters any integer variable that is read
511 * anywhere in "tree" or in any of the size expressions for any of
512 * the arrays accessed in "tree".
513 * Then we remove from those variables that are written anywhere
514 * inside "tree".
516 __isl_give pet_context *pet_context_add_parameters(__isl_take pet_context *pc,
517 __isl_keep pet_tree *tree,
518 __isl_give pet_expr *(*get_array_size)(__isl_keep pet_expr *access,
519 void *user), void *user)
521 struct pet_context_add_parameter_data data;
523 data.pc = pc;
524 data.get_array_size = get_array_size;
525 data.user = user;
526 if (pet_tree_foreach_access_expr(tree, &add_parameter, &data) < 0)
527 data.pc = pet_context_free(data.pc);
529 data.pc = pet_context_clear_writes_in_tree(data.pc, tree);
531 return data.pc;
534 /* Given an access expression, check if it reads a scalar variable
535 * that has a known value in "pc".
536 * If so, then replace the access by an access to that value.
538 static __isl_give pet_expr *access_plug_in_affine_read(
539 __isl_take pet_expr *expr, void *user)
541 pet_context *pc = user;
542 isl_pw_aff *pa;
544 if (pet_expr_access_is_write(expr))
545 return expr;
546 if (!pet_expr_is_scalar_access(expr))
547 return expr;
549 pa = pet_expr_extract_affine(expr, pc);
550 if (!pa)
551 return pet_expr_free(expr);
552 if (isl_pw_aff_involves_nan(pa)) {
553 isl_pw_aff_free(pa);
554 return expr;
557 pet_expr_free(expr);
558 expr = pet_expr_from_index(isl_multi_pw_aff_from_pw_aff(pa));
560 return expr;
563 /* Replace every read access in "expr" to a scalar variable
564 * that has a known value in "pc" by that known value.
566 static __isl_give pet_expr *plug_in_affine_read(__isl_take pet_expr *expr,
567 __isl_keep pet_context *pc)
569 return pet_expr_map_access(expr, &access_plug_in_affine_read, pc);
572 /* Add an extra affine expression to "mpa" that is equal to
573 * an extra dimension in the range of the wrapped relation in the domain
574 * of "mpa". "n_arg" is the original number of dimensions in this range.
576 * That is, if "n_arg" is 0, then the input has the form
578 * D(i) -> [f(i)]
580 * and the output has the form
582 * [D(i) -> [y]] -> [f(i), y]
584 * If "n_arg" is different from 0, then the input has the form
586 * [D(i) -> [x]] -> [f(i,x)]
588 * with x consisting of "n_arg" dimensions, and the output has the form
590 * [D(i) -> [x,y]] -> [f(i,x), y]
593 * We first adjust the domain of "mpa" and then add the extra
594 * affine expression (y).
596 static __isl_give isl_multi_pw_aff *add_arg(__isl_take isl_multi_pw_aff *mpa,
597 int n_arg)
599 int dim;
600 isl_space *space;
601 isl_multi_aff *ma;
602 isl_multi_pw_aff *mpa2;
604 if (n_arg == 0) {
605 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
606 dim = isl_space_dim(space, isl_dim_set);
607 space = isl_space_from_domain(space);
608 space = isl_space_add_dims(space, isl_dim_set, 1);
609 ma = isl_multi_aff_domain_map(space);
610 } else {
611 isl_multi_aff *ma2;
612 isl_space *dom, *ran;
614 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
615 space = isl_space_unwrap(space);
616 dom = isl_space_domain(isl_space_copy(space));
617 dim = isl_space_dim(dom, isl_dim_set);
618 ran = isl_space_range(space);
619 ran = isl_space_add_dims(ran, isl_dim_set, 1);
620 space = isl_space_map_from_set(dom);
621 ma = isl_multi_aff_identity(space);
622 ma2 = isl_multi_aff_project_out_map(ran, isl_dim_set, n_arg, 1);
623 ma = isl_multi_aff_product(ma, ma2);
626 mpa = isl_multi_pw_aff_pullback_multi_aff(mpa, ma);
627 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
628 ma = isl_multi_aff_project_out_map(space, isl_dim_set, 0, dim + n_arg);
629 mpa2 = isl_multi_pw_aff_from_multi_aff(ma);
630 mpa = isl_multi_pw_aff_flat_range_product(mpa, mpa2);
632 return mpa;
635 /* Add the integer value from "arg" to "mpa".
637 static __isl_give isl_multi_pw_aff *add_int(__isl_take isl_multi_pw_aff *mpa,
638 __isl_take pet_expr *arg)
640 isl_space *space;
641 isl_val *v;
642 isl_aff *aff;
643 isl_multi_pw_aff *mpa_arg;
645 v = pet_expr_int_get_val(arg);
646 pet_expr_free(arg);
648 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
649 aff = isl_aff_val_on_domain(isl_local_space_from_space(space), v);
650 mpa_arg = isl_multi_pw_aff_from_pw_aff(isl_pw_aff_from_aff(aff));
652 mpa = isl_multi_pw_aff_flat_range_product(mpa, mpa_arg);
654 return mpa;
657 /* Add the affine expression from "arg" to "mpa".
658 * "n_arg" is the number of dimensions in the range of the wrapped
659 * relation in the domain of "mpa".
661 static __isl_give isl_multi_pw_aff *add_aff(__isl_take isl_multi_pw_aff *mpa,
662 int n_arg, __isl_take pet_expr *arg)
664 isl_multi_pw_aff *mpa_arg;
666 mpa_arg = pet_expr_access_get_index(arg);
667 pet_expr_free(arg);
669 if (n_arg > 0) {
670 isl_space *space;
671 isl_multi_aff *ma;
673 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
674 space = isl_space_unwrap(space);
675 ma = isl_multi_aff_domain_map(space);
676 mpa_arg = isl_multi_pw_aff_pullback_multi_aff(mpa_arg, ma);
679 mpa = isl_multi_pw_aff_flat_range_product(mpa, mpa_arg);
681 return mpa;
684 /* Combine the index expression of "expr" with the subaccess relation "access".
685 * If "add" is set, then it is not the index expression of "expr" itself
686 * that is passed to the function, but its address.
688 * We call patch_map on each map in "access" and return the combined results.
690 static __isl_give isl_union_map *patch(__isl_take isl_union_map *access,
691 __isl_keep pet_expr *expr, int add)
693 isl_multi_pw_aff *prefix;
695 prefix = pet_expr_access_get_index(expr);
696 return pet_patch_union_map(prefix, access, add, 1);
699 /* Set the access relations of "expr", which appears in the argument
700 * at position "pos" in a call expression by composing the access
701 * relations in "summary" with the expression "int_arg" of the integer
702 * arguments in terms of the domain and expression arguments of "expr" and
703 * combining the result with the index expression passed to the function.
704 * If "add" is set, then it is not "expr" itself that is passed
705 * to the function, but the address of "expr".
707 * We reset the read an write flag of "expr" and rely on
708 * pet_expr_access_set_access setting the flags based on
709 * the access relations.
711 * After relating each access relation of the called function
712 * to the domain and expression arguments at the call site,
713 * the result is combined with the index expression by the function patch
714 * and then stored in the access expression.
716 static __isl_give pet_expr *set_access_relations(__isl_take pet_expr *expr,
717 __isl_keep pet_function_summary *summary, int pos,
718 __isl_take isl_multi_pw_aff *int_arg, int add)
720 enum pet_expr_access_type type;
722 expr = pet_expr_access_set_read(expr, 0);
723 expr = pet_expr_access_set_write(expr, 0);
724 for (type = pet_expr_access_begin; type < pet_expr_access_end; ++type) {
725 isl_union_map *access;
727 access = pet_function_summary_arg_get_access(summary,
728 pos, type);
729 access = isl_union_map_preimage_domain_multi_pw_aff(access,
730 isl_multi_pw_aff_copy(int_arg));
731 access = patch(access, expr, add);
732 expr = pet_expr_access_set_access(expr, type, access);
734 isl_multi_pw_aff_free(int_arg);
736 return expr;
739 /* Set the access relations of "arg", which appears in the argument
740 * at position "pos" in the call expression "call" based on the
741 * information in "summary".
742 * If "add" is set, then it is not "arg" itself that is passed
743 * to the function, but the address of "arg".
745 * We create an affine function "int_arg" that expresses
746 * the integer function call arguments in terms of the domain of "arg"
747 * (i.e., the outer loop iterators) and the expression arguments.
748 * If the actual argument is not an affine expression or if it itself
749 * has expression arguments, then it is added as an argument to "arg" and
750 * "int_arg" is made to reference this additional expression argument.
752 * Finally, we call set_access_relations to plug in the actual arguments
753 * (expressed in "int_arg") into the access relations in "summary" and
754 * to add the resulting access relations to "arg".
756 static __isl_give pet_expr *access_plug_in_summary(__isl_take pet_expr *arg,
757 __isl_keep pet_expr *call, __isl_keep pet_function_summary *summary,
758 int pos, int add)
760 int j, n;
761 isl_space *space;
762 isl_multi_pw_aff *int_arg;
763 int arg_n_arg;
765 space = pet_expr_access_get_augmented_domain_space(arg);
766 space = isl_space_from_domain(space);
767 arg_n_arg = pet_expr_get_n_arg(arg);
768 int_arg = isl_multi_pw_aff_zero(space);
769 n = pet_function_summary_get_n_arg(summary);
770 for (j = 0; j < n; ++j) {
771 pet_expr *arg_j;
772 int arg_j_n_arg;
774 if (!pet_function_summary_arg_is_int(summary, j))
775 continue;
777 arg_j = pet_expr_get_arg(call, j);
778 arg_j_n_arg = pet_expr_get_n_arg(arg_j);
779 if (pet_expr_get_type(arg_j) == pet_expr_int) {
780 int_arg = add_int(int_arg, arg_j);
781 } else if (arg_j_n_arg != 0 || !pet_expr_is_affine(arg_j)) {
782 arg = pet_expr_insert_arg(arg, arg_n_arg,
783 arg_j);
784 int_arg = add_arg(int_arg, arg_n_arg);
785 arg_n_arg++;
786 } else {
787 int_arg = add_aff(int_arg, arg_n_arg, arg_j);
790 arg = set_access_relations(arg, summary, pos, int_arg, add);
792 return arg;
795 /* Given the argument "arg" at position "pos" of "call",
796 * check if it is either an access expression or the address
797 * of an access expression. If so, use the information in "summary"
798 * to set the access relations of the access expression.
800 static __isl_give pet_expr *arg_plug_in_summary(__isl_take pet_expr *arg,
801 __isl_keep pet_expr *call, __isl_keep pet_function_summary *summary,
802 int pos)
804 enum pet_expr_type type;
805 pet_expr *arg2;
807 type = pet_expr_get_type(arg);
808 if (type == pet_expr_access)
809 return access_plug_in_summary(arg, call, summary, pos, 0);
810 if (!pet_expr_is_address_of(arg))
811 return arg;
813 arg2 = pet_expr_get_arg(arg, 0);
814 if (pet_expr_get_type(arg2) == pet_expr_access)
815 arg2 = access_plug_in_summary(arg2, call, summary, pos, 1);
816 arg = pet_expr_set_arg(arg, 0, arg2);
818 return arg;
821 /* Given a call expression, check if the integer arguments can
822 * be represented by affine expressions in the context "pc"
823 * (assuming they are not already affine expressions).
824 * If so, replace these arguments by the corresponding affine expressions.
826 static __isl_give pet_expr *call_plug_in_affine_args(__isl_take pet_expr *call,
827 __isl_keep pet_context *pc)
829 int i, n;
831 n = pet_expr_get_n_arg(call);
832 for (i = 0; i < n; ++i) {
833 pet_expr *arg;
834 isl_pw_aff *pa;
836 arg = pet_expr_get_arg(call, i);
837 if (!arg)
838 return pet_expr_free(call);
839 if (pet_expr_get_type_size(arg) == 0 ||
840 pet_expr_is_affine(arg)) {
841 pet_expr_free(arg);
842 continue;
845 pa = pet_expr_extract_affine(arg, pc);
846 pet_expr_free(arg);
847 if (!pa)
848 return pet_expr_free(call);
849 if (isl_pw_aff_involves_nan(pa)) {
850 isl_pw_aff_free(pa);
851 continue;
854 arg = pet_expr_from_index(isl_multi_pw_aff_from_pw_aff(pa));
855 call = pet_expr_set_arg(call, i, arg);
858 return call;
861 /* If "call" has an associated function summary, then use it
862 * to set the access relations of the array arguments of the function call.
864 * We first plug in affine expressions for the integer arguments
865 * whenever possible as these arguments will be plugged in
866 * in the access relations of the array arguments.
868 static __isl_give pet_expr *call_plug_in_summary(__isl_take pet_expr *call,
869 void *user)
871 pet_context *pc = user;
872 pet_function_summary *summary;
873 int i, n;
875 if (!pet_expr_call_has_summary(call))
876 return call;
878 call = call_plug_in_affine_args(call, pc);
880 summary = pet_expr_call_get_summary(call);
881 if (!summary)
882 return pet_expr_free(call);
884 n = pet_expr_get_n_arg(call);
885 for (i = 0; i < n; ++i) {
886 pet_expr *arg_i;
888 if (!pet_function_summary_arg_is_array(summary, i))
889 continue;
891 arg_i = pet_expr_get_arg(call, i);
892 arg_i = arg_plug_in_summary(arg_i, call, summary, i);
893 call = pet_expr_set_arg(call, i, arg_i);
896 pet_function_summary_free(summary);
897 return call;
900 /* For each call subexpression of "expr", plug in the access relations
901 * from the associated function summary (if any).
903 static __isl_give pet_expr *plug_in_summaries(__isl_take pet_expr *expr,
904 __isl_keep pet_context *pc)
906 return pet_expr_map_call(expr, &call_plug_in_summary, pc);
909 /* Evaluate "expr" in the context of "pc".
911 * In particular, we first make sure that all the access expressions
912 * inside "expr" have the same domain as "pc".
913 * Then, we plug in affine expressions for scalar reads,
914 * plug in the arguments of all access expressions in "expr" and
915 * plug in the access relations from the summary functions associated
916 * to call expressions.
918 __isl_give pet_expr *pet_context_evaluate_expr(__isl_keep pet_context *pc,
919 __isl_take pet_expr *expr)
921 expr = pet_expr_insert_domain(expr, pet_context_get_space(pc));
922 expr = plug_in_affine_read(expr, pc);
923 expr = pet_expr_plug_in_args(expr, pc);
924 expr = plug_in_summaries(expr, pc);
925 return expr;
928 /* Wrapper around pet_context_evaluate_expr
929 * for use as a callback to pet_tree_map_expr.
931 static __isl_give pet_expr *evaluate_expr(__isl_take pet_expr *expr,
932 void *user)
934 pet_context *pc = user;
936 return pet_context_evaluate_expr(pc, expr);
939 /* Evaluate "tree" in the context of "pc".
940 * That is, evaluate all the expressions of "tree" in the context of "pc".
942 __isl_give pet_tree *pet_context_evaluate_tree(__isl_keep pet_context *pc,
943 __isl_take pet_tree *tree)
945 return pet_tree_map_expr(tree, &evaluate_expr, pc);
948 /* Add an unbounded inner dimension "id" to pc->domain.
950 * The assignments are not adjusted here and therefore keep
951 * their original domain. These domains need to be adjusted before
952 * these assigned values can be used. This is taken care of by
953 * pet_context_get_value.
955 static __isl_give pet_context *extend_domain(__isl_take pet_context *pc,
956 __isl_take isl_id *id)
958 int pos;
960 pc = pet_context_cow(pc);
961 if (!pc || !id)
962 goto error;
964 pos = pet_context_dim(pc);
965 pc->domain = isl_set_add_dims(pc->domain, isl_dim_set, 1);
966 pc->domain = isl_set_set_dim_id(pc->domain, isl_dim_set, pos, id);
967 if (!pc->domain)
968 return pet_context_free(pc);
970 return pc;
971 error:
972 pet_context_free(pc);
973 isl_id_free(id);
974 return NULL;
977 /* Add an unbounded inner iterator "id" to pc->domain.
978 * Additionally, mark the variable "id" as having the value of this
979 * new inner iterator.
981 __isl_give pet_context *pet_context_add_inner_iterator(
982 __isl_take pet_context *pc, __isl_take isl_id *id)
984 int pos;
985 isl_space *space;
986 isl_local_space *ls;
987 isl_aff *aff;
988 isl_pw_aff *pa;
990 if (!pc || !id)
991 goto error;
993 pos = pet_context_dim(pc);
994 pc = extend_domain(pc, isl_id_copy(id));
995 if (!pc)
996 goto error;
998 space = pet_context_get_space(pc);
999 ls = isl_local_space_from_space(space);
1000 aff = isl_aff_var_on_domain(ls, isl_dim_set, pos);
1001 pa = isl_pw_aff_from_aff(aff);
1003 pc = pet_context_set_value(pc, id, pa);
1005 return pc;
1006 error:
1007 pet_context_free(pc);
1008 isl_id_free(id);
1009 return NULL;
1012 /* Add an inner iterator to pc->domain.
1013 * In particular, extend the domain with an inner loop { [t] : t >= 0 }.
1015 __isl_give pet_context *pet_context_add_infinite_loop(
1016 __isl_take pet_context *pc)
1018 int dim;
1019 isl_ctx *ctx;
1020 isl_id *id;
1022 if (!pc)
1023 return NULL;
1025 dim = pet_context_dim(pc);
1026 ctx = pet_context_get_ctx(pc);
1027 id = isl_id_alloc(ctx, "t", NULL);
1028 pc = extend_domain(pc, id);
1029 pc = pet_context_cow(pc);
1030 if (!pc)
1031 return NULL;
1032 pc->domain = isl_set_lower_bound_si(pc->domain, isl_dim_set, dim, 0);
1033 if (!pc->domain)
1034 return pet_context_free(pc);
1036 return pc;
1039 /* Internal data structure for preimage_domain.
1041 * "ma" is the function under which the preimage should be computed.
1042 * "assignments" collects the results.
1044 struct pet_preimage_domain_data {
1045 isl_multi_aff *ma;
1046 isl_id_to_pw_aff *assignments;
1049 /* Add the assignment to "key" of the preimage of "val" under data->ma
1050 * to data->assignments.
1052 * Some dimensions may have been added to the domain of the enclosing
1053 * pet_context after the value "val" was added. We therefore need to
1054 * adjust the domain of "val" to match the range of data->ma (which
1055 * in turn matches the domain of the pet_context), by adding the missing
1056 * dimensions.
1058 static isl_stat preimage_domain_pair(__isl_take isl_id *key,
1059 __isl_take isl_pw_aff *val, void *user)
1061 struct pet_preimage_domain_data *data = user;
1062 int dim;
1063 isl_multi_aff *ma;
1065 ma = isl_multi_aff_copy(data->ma);
1067 dim = isl_pw_aff_dim(val, isl_dim_in);
1068 if (dim != isl_multi_aff_dim(data->ma, isl_dim_out)) {
1069 isl_space *space;
1070 isl_multi_aff *proj;
1071 space = isl_multi_aff_get_space(data->ma);
1072 space = isl_space_range(space);
1073 proj = pet_prefix_projection(space, dim);
1074 ma = isl_multi_aff_pullback_multi_aff(proj, ma);
1077 val = isl_pw_aff_pullback_multi_aff(val, ma);
1078 data->assignments = isl_id_to_pw_aff_set(data->assignments, key, val);
1080 return isl_stat_ok;
1083 /* Compute the preimage of "assignments" under the function represented by "ma".
1084 * In other words, plug in "ma" in the domains of the assigned values.
1086 static __isl_give isl_id_to_pw_aff *preimage_domain(
1087 __isl_take isl_id_to_pw_aff *assignments, __isl_keep isl_multi_aff *ma)
1089 struct pet_preimage_domain_data data = { ma };
1090 isl_ctx *ctx;
1092 ctx = isl_id_to_pw_aff_get_ctx(assignments);
1093 data.assignments = isl_id_to_pw_aff_alloc(ctx, 0);
1094 if (isl_id_to_pw_aff_foreach(assignments, &preimage_domain_pair,
1095 &data) < 0)
1096 data.assignments = isl_id_to_pw_aff_free(data.assignments);
1097 isl_id_to_pw_aff_free(assignments);
1099 return data.assignments;
1102 /* Compute the preimage of "pc" under the function represented by "ma".
1103 * In other words, plug in "ma" in the domain of "pc".
1105 __isl_give pet_context *pet_context_preimage_domain(__isl_take pet_context *pc,
1106 __isl_keep isl_multi_aff *ma)
1108 pc = pet_context_cow(pc);
1109 if (!pc)
1110 return NULL;
1111 pc->domain = isl_set_preimage_multi_aff(pc->domain,
1112 isl_multi_aff_copy(ma));
1113 pc->assignments = preimage_domain(pc->assignments, ma);
1114 if (!pc->domain || !pc->assignments)
1115 return pet_context_free(pc);
1116 return pc;
1119 /* Add the constraints of "set" to the domain of "pc".
1121 __isl_give pet_context *pet_context_intersect_domain(__isl_take pet_context *pc,
1122 __isl_take isl_set *set)
1124 pc = pet_context_cow(pc);
1125 if (!pc)
1126 goto error;
1127 pc->domain = isl_set_intersect(pc->domain, set);
1128 if (!pc->domain)
1129 return pet_context_free(pc);
1130 return pc;
1131 error:
1132 pet_context_free(pc);
1133 isl_set_free(set);
1134 return NULL;
1137 void pet_context_dump(__isl_keep pet_context *pc)
1139 if (!pc)
1140 return;
1141 fprintf(stderr, "domain: ");
1142 isl_set_dump(pc->domain);
1143 fprintf(stderr, "assignments: ");
1144 isl_id_to_pw_aff_dump(pc->assignments);
1145 fprintf(stderr, "nesting allowed: %d\n", pc->allow_nested);