pet_context_evaluate_expr: plug in affine expressions outside index expressions
[pet.git] / context.c
blob569f7428fb8c146cf927984ff0fc66216b380584
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 /* Given an access expression "expr", check that it is an affine
910 * access expression and set *only_affine to 1.
911 * If "expr" is not an affine access expression, then set *only_affine to 0
912 * and abort.
914 static int check_only_affine(__isl_keep pet_expr *expr, void *user)
916 int *only_affine = user;
917 int is_affine;
919 is_affine = pet_expr_is_affine(expr);
920 if (is_affine < 0)
921 return -1;
922 if (!is_affine) {
923 *only_affine = 0;
924 return -1;
926 *only_affine = 1;
928 return 0;
931 /* Does "expr" have any affine access subexpression and no other
932 * access subexpressions?
934 * only_affine is initialized to -1 and set to 1 as soon as one affine
935 * access subexpression has been found and to 0 if some other access
936 * subexpression has been found. In this latter case, the search is
937 * aborted.
939 static isl_bool has_only_affine_access_sub_expr(__isl_keep pet_expr *expr)
941 int only_affine = -1;
943 if (pet_expr_foreach_access_expr(expr, &check_only_affine,
944 &only_affine) < 0 &&
945 only_affine != 0)
946 return isl_bool_error;
948 return only_affine > 0;
951 /* Try and replace "expr" by an affine access expression by essentially
952 * evaluating operations and/or special calls on affine access expressions.
953 * It therefore only makes sense to do this if "expr" is a call or an operation
954 * and if it has at least one affine access subexpression and no other
955 * access subexpressions.
957 static __isl_give pet_expr *expr_plug_in_affine(__isl_take pet_expr *expr,
958 void *user)
960 enum pet_expr_type type;
961 pet_context *pc = user;
962 isl_pw_aff *pa;
963 isl_bool contains_access;
965 type = pet_expr_get_type(expr);
966 if (type != pet_expr_call && type != pet_expr_op)
967 return expr;
968 contains_access = has_only_affine_access_sub_expr(expr);
969 if (contains_access < 0)
970 return pet_expr_free(expr);
971 if (!contains_access)
972 return expr;
974 pa = pet_expr_extract_affine(expr, pc);
975 if (!pa)
976 return pet_expr_free(expr);
977 if (isl_pw_aff_involves_nan(pa)) {
978 isl_pw_aff_free(pa);
979 return expr;
982 pet_expr_free(expr);
983 expr = pet_expr_from_index(isl_multi_pw_aff_from_pw_aff(pa));
985 return expr;
988 /* Detect affine subexpressions in "expr".
990 * The detection is performed top-down in order to be able
991 * to exploit the min/max optimization in comparisons.
992 * That is, if some subexpression is of the form max(a,b) <= min(c,d)
993 * and if the affine expressions were being detected bottom-up, then
994 * affine expressions for max(a,b) and min(c,d) would be constructed
995 * first and it would no longer be possible to optimize the extraction
996 * of the comparison as a <= c && a <= d && b <= c && b <= d.
998 static __isl_give pet_expr *plug_in_affine(__isl_take pet_expr *expr,
999 __isl_keep pet_context *pc)
1001 return pet_expr_map_top_down(expr, &expr_plug_in_affine, pc);
1004 /* Evaluate "expr" in the context of "pc".
1006 * In particular, we first make sure that all the access expressions
1007 * inside "expr" have the same domain as "pc".
1008 * Then, we plug in affine expressions for scalar reads,
1009 * plug in the arguments of all access expressions in "expr" as well
1010 * as any other affine expressions that may appear inside "expr" and
1011 * plug in the access relations from the summary functions associated
1012 * to call expressions.
1014 __isl_give pet_expr *pet_context_evaluate_expr(__isl_keep pet_context *pc,
1015 __isl_take pet_expr *expr)
1017 expr = pet_expr_insert_domain(expr, pet_context_get_space(pc));
1018 expr = plug_in_affine_read(expr, pc);
1019 expr = pet_expr_plug_in_args(expr, pc);
1020 expr = plug_in_affine(expr, pc);
1021 expr = plug_in_summaries(expr, pc);
1022 return expr;
1025 /* Wrapper around pet_context_evaluate_expr
1026 * for use as a callback to pet_tree_map_expr.
1028 static __isl_give pet_expr *evaluate_expr(__isl_take pet_expr *expr,
1029 void *user)
1031 pet_context *pc = user;
1033 return pet_context_evaluate_expr(pc, expr);
1036 /* Evaluate "tree" in the context of "pc".
1037 * That is, evaluate all the expressions of "tree" in the context of "pc".
1039 __isl_give pet_tree *pet_context_evaluate_tree(__isl_keep pet_context *pc,
1040 __isl_take pet_tree *tree)
1042 return pet_tree_map_expr(tree, &evaluate_expr, pc);
1045 /* Add an unbounded inner dimension "id" to pc->domain.
1047 * The assignments are not adjusted here and therefore keep
1048 * their original domain. These domains need to be adjusted before
1049 * these assigned values can be used. This is taken care of by
1050 * pet_context_get_value.
1052 static __isl_give pet_context *extend_domain(__isl_take pet_context *pc,
1053 __isl_take isl_id *id)
1055 int pos;
1057 pc = pet_context_cow(pc);
1058 if (!pc || !id)
1059 goto error;
1061 pos = pet_context_dim(pc);
1062 pc->domain = isl_set_add_dims(pc->domain, isl_dim_set, 1);
1063 pc->domain = isl_set_set_dim_id(pc->domain, isl_dim_set, pos, id);
1064 if (!pc->domain)
1065 return pet_context_free(pc);
1067 return pc;
1068 error:
1069 pet_context_free(pc);
1070 isl_id_free(id);
1071 return NULL;
1074 /* Add an unbounded inner iterator "id" to pc->domain.
1075 * Additionally, mark the variable "id" as having the value of this
1076 * new inner iterator.
1078 __isl_give pet_context *pet_context_add_inner_iterator(
1079 __isl_take pet_context *pc, __isl_take isl_id *id)
1081 int pos;
1082 isl_space *space;
1083 isl_local_space *ls;
1084 isl_aff *aff;
1085 isl_pw_aff *pa;
1087 if (!pc || !id)
1088 goto error;
1090 pos = pet_context_dim(pc);
1091 pc = extend_domain(pc, isl_id_copy(id));
1092 if (!pc)
1093 goto error;
1095 space = pet_context_get_space(pc);
1096 ls = isl_local_space_from_space(space);
1097 aff = isl_aff_var_on_domain(ls, isl_dim_set, pos);
1098 pa = isl_pw_aff_from_aff(aff);
1100 pc = pet_context_set_value(pc, id, pa);
1102 return pc;
1103 error:
1104 pet_context_free(pc);
1105 isl_id_free(id);
1106 return NULL;
1109 /* Add an inner iterator to pc->domain.
1110 * In particular, extend the domain with an inner loop { [t] : t >= 0 }.
1112 __isl_give pet_context *pet_context_add_infinite_loop(
1113 __isl_take pet_context *pc)
1115 int dim;
1116 isl_ctx *ctx;
1117 isl_id *id;
1119 if (!pc)
1120 return NULL;
1122 dim = pet_context_dim(pc);
1123 ctx = pet_context_get_ctx(pc);
1124 id = isl_id_alloc(ctx, "t", NULL);
1125 pc = extend_domain(pc, id);
1126 pc = pet_context_cow(pc);
1127 if (!pc)
1128 return NULL;
1129 pc->domain = isl_set_lower_bound_si(pc->domain, isl_dim_set, dim, 0);
1130 if (!pc->domain)
1131 return pet_context_free(pc);
1133 return pc;
1136 /* Internal data structure for preimage_domain.
1138 * "ma" is the function under which the preimage should be computed.
1139 * "assignments" collects the results.
1141 struct pet_preimage_domain_data {
1142 isl_multi_aff *ma;
1143 isl_id_to_pw_aff *assignments;
1146 /* Add the assignment to "key" of the preimage of "val" under data->ma
1147 * to data->assignments.
1149 * Some dimensions may have been added to the domain of the enclosing
1150 * pet_context after the value "val" was added. We therefore need to
1151 * adjust the domain of "val" to match the range of data->ma (which
1152 * in turn matches the domain of the pet_context), by adding the missing
1153 * dimensions.
1155 static isl_stat preimage_domain_pair(__isl_take isl_id *key,
1156 __isl_take isl_pw_aff *val, void *user)
1158 struct pet_preimage_domain_data *data = user;
1159 int dim;
1160 isl_multi_aff *ma;
1162 ma = isl_multi_aff_copy(data->ma);
1164 dim = isl_pw_aff_dim(val, isl_dim_in);
1165 if (dim != isl_multi_aff_dim(data->ma, isl_dim_out)) {
1166 isl_space *space;
1167 isl_multi_aff *proj;
1168 space = isl_multi_aff_get_space(data->ma);
1169 space = isl_space_range(space);
1170 proj = pet_prefix_projection(space, dim);
1171 ma = isl_multi_aff_pullback_multi_aff(proj, ma);
1174 val = isl_pw_aff_pullback_multi_aff(val, ma);
1175 data->assignments = isl_id_to_pw_aff_set(data->assignments, key, val);
1177 return isl_stat_ok;
1180 /* Compute the preimage of "assignments" under the function represented by "ma".
1181 * In other words, plug in "ma" in the domains of the assigned values.
1183 static __isl_give isl_id_to_pw_aff *preimage_domain(
1184 __isl_take isl_id_to_pw_aff *assignments, __isl_keep isl_multi_aff *ma)
1186 struct pet_preimage_domain_data data = { ma };
1187 isl_ctx *ctx;
1189 ctx = isl_id_to_pw_aff_get_ctx(assignments);
1190 data.assignments = isl_id_to_pw_aff_alloc(ctx, 0);
1191 if (isl_id_to_pw_aff_foreach(assignments, &preimage_domain_pair,
1192 &data) < 0)
1193 data.assignments = isl_id_to_pw_aff_free(data.assignments);
1194 isl_id_to_pw_aff_free(assignments);
1196 return data.assignments;
1199 /* Compute the preimage of "pc" under the function represented by "ma".
1200 * In other words, plug in "ma" in the domain of "pc".
1202 __isl_give pet_context *pet_context_preimage_domain(__isl_take pet_context *pc,
1203 __isl_keep isl_multi_aff *ma)
1205 pc = pet_context_cow(pc);
1206 if (!pc)
1207 return NULL;
1208 pc->domain = isl_set_preimage_multi_aff(pc->domain,
1209 isl_multi_aff_copy(ma));
1210 pc->assignments = preimage_domain(pc->assignments, ma);
1211 if (!pc->domain || !pc->assignments)
1212 return pet_context_free(pc);
1213 return pc;
1216 /* Add the constraints of "set" to the domain of "pc".
1218 __isl_give pet_context *pet_context_intersect_domain(__isl_take pet_context *pc,
1219 __isl_take isl_set *set)
1221 pc = pet_context_cow(pc);
1222 if (!pc)
1223 goto error;
1224 pc->domain = isl_set_intersect(pc->domain, set);
1225 if (!pc->domain)
1226 return pet_context_free(pc);
1227 return pc;
1228 error:
1229 pet_context_free(pc);
1230 isl_set_free(set);
1231 return NULL;
1234 void pet_context_dump(__isl_keep pet_context *pc)
1236 if (!pc)
1237 return;
1238 fprintf(stderr, "domain: ");
1239 isl_set_dump(pc->domain);
1240 fprintf(stderr, "assignments: ");
1241 isl_id_to_pw_aff_dump(pc->assignments);
1242 fprintf(stderr, "nesting allowed: %d\n", pc->allow_nested);