privately export pet_expr_access_get_dependent_access
[pet.git] / context.c
blob4533e9c2e40e8db52022fc261e4dda62b459bf9b
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 "tree.h"
45 /* A pet_context represents the context in which a pet_expr
46 * in converted to an affine expression.
48 * "domain" prescribes the domain of the affine expressions.
50 * "assignments" maps variable names to their currently known values.
51 * Internally, the domains of the values may be equal to some prefix
52 * of the space of "domain", but the domains are updated to be
53 * equal to the space of "domain" before passing them to the user.
55 * If "allow_nested" is set, then the affine expression created
56 * in this context may involve new parameters that encode a pet_expr.
58 struct pet_context {
59 int ref;
61 isl_set *domain;
62 isl_id_to_pw_aff *assignments;
63 int allow_nested;
66 /* Create a pet_context with the given domain, assignments,
67 * and value for allow_nested.
69 static __isl_give pet_context *context_alloc(__isl_take isl_set *domain,
70 __isl_take isl_id_to_pw_aff *assignments, int allow_nested)
72 pet_context *pc;
74 if (!domain || !assignments)
75 goto error;
77 pc = isl_calloc_type(isl_set_get_ctx(domain), struct pet_context);
78 if (!pc)
79 goto error;
81 pc->ref = 1;
82 pc->domain = domain;
83 pc->assignments = assignments;
84 pc->allow_nested = allow_nested;
86 return pc;
87 error:
88 isl_set_free(domain);
89 isl_id_to_pw_aff_free(assignments);
90 return NULL;
93 /* Create a pet_context with the given domain.
95 * Initially, there are no assigned values and parameters that
96 * encode a pet_expr are not allowed.
98 __isl_give pet_context *pet_context_alloc(__isl_take isl_set *domain)
100 isl_id_to_pw_aff *assignments;
102 if (!domain)
103 return NULL;
105 assignments = isl_id_to_pw_aff_alloc(isl_set_get_ctx(domain), 0);;
106 return context_alloc(domain, assignments, 0);
109 /* Return an independent duplicate of "pc".
111 static __isl_give pet_context *pet_context_dup(__isl_keep pet_context *pc)
113 pet_context *dup;
115 if (!pc)
116 return NULL;
118 dup = context_alloc(isl_set_copy(pc->domain),
119 isl_id_to_pw_aff_copy(pc->assignments),
120 pc->allow_nested);
122 return dup;
125 /* Return a pet_context that is equal to "pc" and that has only one reference.
127 static __isl_give pet_context *pet_context_cow(__isl_take pet_context *pc)
129 if (!pc)
130 return NULL;
132 if (pc->ref == 1)
133 return pc;
134 pc->ref--;
135 return pet_context_dup(pc);
138 /* Return an extra reference to "pc".
140 __isl_give pet_context *pet_context_copy(__isl_keep pet_context *pc)
142 if (!pc)
143 return NULL;
145 pc->ref++;
146 return pc;
149 /* Free a reference to "pc" and return NULL.
151 __isl_null pet_context *pet_context_free(__isl_take pet_context *pc)
153 if (!pc)
154 return NULL;
155 if (--pc->ref > 0)
156 return NULL;
158 isl_set_free(pc->domain);
159 isl_id_to_pw_aff_free(pc->assignments);
160 free(pc);
161 return NULL;
164 /* Return the isl_ctx in which "pc" was created.
166 isl_ctx *pet_context_get_ctx(__isl_keep pet_context *pc)
168 return pc ? isl_set_get_ctx(pc->domain) : NULL;
171 /* Return the domain of "pc".
173 __isl_give isl_set *pet_context_get_domain(__isl_keep pet_context *pc)
175 if (!pc)
176 return NULL;
177 return isl_set_copy(pc->domain);
180 /* Return the domain of "pc" in a form that is suitable
181 * for use as a gist context.
182 * In particular, remove all references to nested expression parameters
183 * so that they do not get introduced in the gisted expression.
185 __isl_give isl_set *pet_context_get_gist_domain(__isl_keep pet_context *pc)
187 isl_set *domain;
189 domain = pet_context_get_domain(pc);
190 domain = pet_nested_remove_from_set(domain);
191 return domain;
194 /* Return the domain space of "pc".
196 * The domain of "pc" may have constraints involving parameters
197 * that encode a pet_expr. These parameters are not relevant
198 * outside this domain. Furthermore, they need to be resolved
199 * from the final result, so we do not want to propagate them needlessly.
201 __isl_give isl_space *pet_context_get_space(__isl_keep pet_context *pc)
203 isl_space *space;
205 if (!pc)
206 return NULL;
208 space = isl_set_get_space(pc->domain);
209 space = pet_nested_remove_from_space(space);
210 return space;
213 /* Return the dimension of the domain space of "pc".
215 unsigned pet_context_dim(__isl_keep pet_context *pc)
217 if (!pc)
218 return 0;
219 return isl_set_dim(pc->domain, isl_dim_set);
222 /* Return the assignments of "pc".
224 __isl_give isl_id_to_pw_aff *pet_context_get_assignments(
225 __isl_keep pet_context *pc)
227 if (!pc)
228 return NULL;
229 return isl_id_to_pw_aff_copy(pc->assignments);
232 /* Is "id" assigned any value in "pc"?
234 int pet_context_is_assigned(__isl_keep pet_context *pc, __isl_keep isl_id *id)
236 if (!pc || !id)
237 return -1;
238 return isl_id_to_pw_aff_has(pc->assignments, id);
241 /* Return the value assigned to "id" in "pc".
243 * Some dimensions may have been added to pc->domain after the value
244 * associated to "id" was added. We therefore need to adjust the domain
245 * of the stored value to match pc->domain by adding the missing
246 * dimensions.
248 __isl_give isl_pw_aff *pet_context_get_value(__isl_keep pet_context *pc,
249 __isl_take isl_id *id)
251 int dim;
252 isl_pw_aff *pa;
253 isl_multi_aff *ma;
255 if (!pc || !id)
256 goto error;
258 pa = isl_id_to_pw_aff_get(pc->assignments, id);
259 dim = isl_pw_aff_dim(pa, isl_dim_in);
260 if (dim == isl_set_dim(pc->domain, isl_dim_set))
261 return pa;
263 ma = pet_prefix_projection(pet_context_get_space(pc), dim);
264 pa = isl_pw_aff_pullback_multi_aff(pa, ma);
266 return pa;
267 error:
268 isl_id_free(id);
269 return NULL;
272 /* Assign the value "value" to "id" in "pc", replacing the previously
273 * assigned value, if any.
275 __isl_give pet_context *pet_context_set_value(__isl_take pet_context *pc,
276 __isl_take isl_id *id, isl_pw_aff *value)
278 pc = pet_context_cow(pc);
279 if (!pc)
280 goto error;
281 pc->assignments = isl_id_to_pw_aff_set(pc->assignments, id, value);
282 if (!pc->assignments)
283 return pet_context_free(pc);
284 return pc;
285 error:
286 isl_id_free(id);
287 isl_pw_aff_free(value);
288 return NULL;
291 /* Remove any assignment to "id" in "pc".
293 __isl_give pet_context *pet_context_clear_value(__isl_keep pet_context *pc,
294 __isl_take isl_id *id)
296 pc = pet_context_cow(pc);
297 if (!pc)
298 goto error;
299 pc->assignments = isl_id_to_pw_aff_drop(pc->assignments, id);
300 if (!pc->assignments)
301 return pet_context_free(pc);
302 return pc;
303 error:
304 isl_id_free(id);
305 return NULL;
308 /* Are affine expressions created in this context allowed to involve
309 * parameters that encode a pet_expr?
311 int pet_context_allow_nesting(__isl_keep pet_context *pc)
313 if (!pc)
314 return -1;
315 return pc->allow_nested;
318 /* Allow affine expressions created in this context to involve
319 * parameters that encode a pet_expr based on the value of "allow_nested".
321 __isl_give pet_context *pet_context_set_allow_nested(__isl_take pet_context *pc,
322 int allow_nested)
324 if (!pc)
325 return NULL;
326 if (pc->allow_nested == allow_nested)
327 return pc;
328 pc = pet_context_cow(pc);
329 if (!pc)
330 return NULL;
331 pc->allow_nested = allow_nested;
332 return pc;
335 /* If the access expression "expr" writes to a (non-virtual) scalar,
336 * then remove any assignment to the scalar in "pc".
338 static int clear_write(__isl_keep pet_expr *expr, void *user)
340 isl_id *id;
341 pet_context **pc = (pet_context **) user;
343 if (!pet_expr_access_is_write(expr))
344 return 0;
345 if (!pet_expr_is_scalar_access(expr))
346 return 0;
348 id = pet_expr_access_get_id(expr);
349 if (isl_id_get_user(id))
350 *pc = pet_context_clear_value(*pc, id);
351 else
352 isl_id_free(id);
354 return 0;
357 /* Look for any writes to scalar variables in "expr" and
358 * remove any assignment to them in "pc".
360 __isl_give pet_context *pet_context_clear_writes_in_expr(
361 __isl_take pet_context *pc, __isl_keep pet_expr *expr)
363 if (pet_expr_foreach_access_expr(expr, &clear_write, &pc) < 0)
364 pc = pet_context_free(pc);
366 return pc;
369 /* Look for any writes to scalar variables in "tree" and
370 * remove any assignment to them in "pc".
372 __isl_give pet_context *pet_context_clear_writes_in_tree(
373 __isl_take pet_context *pc, __isl_keep pet_tree *tree)
375 if (pet_tree_foreach_access_expr(tree, &clear_write, &pc) < 0)
376 pc = pet_context_free(pc);
378 return pc;
381 /* Internal data structure for pet_context_add_parameters.
383 * "pc" is the context that is being updated.
384 * "get_array_size" is a callback function that can be used to determine
385 * the size of the array that is accessed by a given access expression.
386 * "user" is the user data for this callback.
388 struct pet_context_add_parameter_data {
389 pet_context *pc;
390 __isl_give pet_expr *(*get_array_size)(__isl_keep pet_expr *access,
391 void *user);
392 void *user;
395 /* Given an access expression "expr", add a parameter assignment to data->pc
396 * to the variable being accessed, provided it is a read from an integer
397 * scalar variable.
398 * If an array is being accesed, then recursively call the function
399 * on each of the access expressions in the size expression of the array.
401 static int add_parameter(__isl_keep pet_expr *expr, void *user)
403 struct pet_context_add_parameter_data *data = user;
404 int pos;
405 isl_id *id;
406 isl_space *space;
407 isl_local_space *ls;
408 isl_aff *aff;
409 isl_pw_aff *pa;
411 if (!pet_expr_is_scalar_access(expr)) {
412 pet_expr *size = data->get_array_size(expr, data->user);
413 if (pet_expr_foreach_access_expr(size,
414 &add_parameter, data) < 0)
415 data->pc = pet_context_free(data->pc);
416 pet_expr_free(size);
417 return 0;
419 if (!pet_expr_access_is_read(expr))
420 return 0;
421 if (pet_expr_get_type_size(expr) == 0)
422 return 0;
424 id = pet_expr_access_get_id(expr);
425 if (pet_context_is_assigned(data->pc, id)) {
426 isl_id_free(id);
427 return 0;
430 space = pet_context_get_space(data->pc);
431 pos = isl_space_find_dim_by_id(space, isl_dim_param, id);
432 if (pos < 0) {
433 pos = isl_space_dim(space, isl_dim_param);
434 space = isl_space_add_dims(space, isl_dim_param, 1);
435 space = isl_space_set_dim_id(space, isl_dim_param, pos,
436 isl_id_copy(id));
439 ls = isl_local_space_from_space(space);
440 aff = isl_aff_var_on_domain(ls, isl_dim_param, pos);
441 pa = isl_pw_aff_from_aff(aff);
442 data->pc = pet_context_set_value(data->pc, id, pa);
444 return 0;
447 /* Add an assignment to "pc" for each parameter in "tree".
448 * "get_array_size" is a callback function that can be used to determine
449 * the size of the array that is accessed by a given access expression.
451 * We initially treat as parameters any integer variable that is read
452 * anywhere in "tree" or in any of the size expressions for any of
453 * the arrays accessed in "tree".
454 * Then we remove from those variables that are written anywhere
455 * inside "tree".
457 __isl_give pet_context *pet_context_add_parameters(__isl_take pet_context *pc,
458 __isl_keep pet_tree *tree,
459 __isl_give pet_expr *(*get_array_size)(__isl_keep pet_expr *access,
460 void *user), void *user)
462 struct pet_context_add_parameter_data data;
464 data.pc = pc;
465 data.get_array_size = get_array_size;
466 data.user = user;
467 if (pet_tree_foreach_access_expr(tree, &add_parameter, &data) < 0)
468 data.pc = pet_context_free(data.pc);
470 data.pc = pet_context_clear_writes_in_tree(data.pc, tree);
472 return data.pc;
475 /* Given an access expression, check if it reads a scalar variable
476 * that has a known value in "pc".
477 * If so, then replace the access by an access to that value.
479 static __isl_give pet_expr *access_plug_in_affine_read(
480 __isl_take pet_expr *expr, void *user)
482 pet_context *pc = user;
483 isl_pw_aff *pa;
485 if (pet_expr_access_is_write(expr))
486 return expr;
487 if (!pet_expr_is_scalar_access(expr))
488 return expr;
490 pa = pet_expr_extract_affine(expr, pc);
491 if (!pa)
492 return pet_expr_free(expr);
493 if (isl_pw_aff_involves_nan(pa)) {
494 isl_pw_aff_free(pa);
495 return expr;
498 pet_expr_free(expr);
499 expr = pet_expr_from_index(isl_multi_pw_aff_from_pw_aff(pa));
501 return expr;
504 /* Replace every read access in "expr" to a scalar variable
505 * that has a known value in "pc" by that known value.
507 static __isl_give pet_expr *plug_in_affine_read(__isl_take pet_expr *expr,
508 __isl_keep pet_context *pc)
510 return pet_expr_map_access(expr, &access_plug_in_affine_read, pc);
513 /* Add an extra affine expression to "mpa" that is equal to
514 * an extra dimension in the range of the wrapped relation in the domain
515 * of "mpa". "n_arg" is the original number of dimensions in this range.
517 * That is, if "n_arg" is 0, then the input has the form
519 * D(i) -> [f(i)]
521 * and the output has the form
523 * [D(i) -> [y]] -> [f(i), y]
525 * If "n_arg" is different from 0, then the input has the form
527 * [D(i) -> [x]] -> [f(i,x)]
529 * with x consisting of "n_arg" dimensions, and the output has the form
531 * [D(i) -> [x,y]] -> [f(i,x), y]
534 * We first adjust the domain of "mpa" and then add the extra
535 * affine expression (y).
537 static __isl_give isl_multi_pw_aff *add_arg(__isl_take isl_multi_pw_aff *mpa,
538 int n_arg)
540 int dim;
541 isl_space *space;
542 isl_multi_aff *ma;
543 isl_multi_pw_aff *mpa2;
545 if (n_arg == 0) {
546 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
547 dim = isl_space_dim(space, isl_dim_set);
548 space = isl_space_from_domain(space);
549 space = isl_space_add_dims(space, isl_dim_set, 1);
550 ma = isl_multi_aff_domain_map(space);
551 } else {
552 isl_multi_aff *ma2;;
553 isl_space *dom, *ran;
555 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
556 space = isl_space_unwrap(space);
557 dom = isl_space_domain(isl_space_copy(space));
558 dim = isl_space_dim(dom, isl_dim_set);
559 ran = isl_space_range(space);
560 ran = isl_space_add_dims(ran, isl_dim_set, 1);
561 space = isl_space_map_from_set(dom);
562 ma = isl_multi_aff_identity(space);
563 ma2 = isl_multi_aff_project_out_map(ran, isl_dim_set, n_arg, 1);
564 ma = isl_multi_aff_product(ma, ma2);
567 mpa = isl_multi_pw_aff_pullback_multi_aff(mpa, ma);
568 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
569 ma = isl_multi_aff_project_out_map(space, isl_dim_set, 0, dim + n_arg);
570 mpa2 = isl_multi_pw_aff_from_multi_aff(ma);
571 mpa = isl_multi_pw_aff_flat_range_product(mpa, mpa2);
573 return mpa;
576 /* Add the integer value from "arg" to "mpa".
578 static __isl_give isl_multi_pw_aff *add_int(__isl_take isl_multi_pw_aff *mpa,
579 __isl_take pet_expr *arg)
581 isl_space *space;
582 isl_val *v;
583 isl_aff *aff;
584 isl_multi_pw_aff *mpa_arg;
586 v = pet_expr_int_get_val(arg);
587 pet_expr_free(arg);
589 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
590 aff = isl_aff_val_on_domain(isl_local_space_from_space(space), v);
591 mpa_arg = isl_multi_pw_aff_from_pw_aff(isl_pw_aff_from_aff(aff));
593 mpa = isl_multi_pw_aff_flat_range_product(mpa, mpa_arg);
595 return mpa;
598 /* Add the affine expression from "arg" to "mpa".
599 * "n_arg" is the number of dimensions in the range of the wrapped
600 * relation in the domain of "mpa".
602 static __isl_give isl_multi_pw_aff *add_aff(__isl_take isl_multi_pw_aff *mpa,
603 int n_arg, __isl_take pet_expr *arg)
605 isl_multi_pw_aff *mpa_arg;
607 mpa_arg = pet_expr_access_get_index(arg);
608 pet_expr_free(arg);
610 if (n_arg > 0) {
611 isl_space *space;
612 isl_multi_aff *ma;
614 space = isl_space_domain(isl_multi_pw_aff_get_space(mpa));
615 space = isl_space_unwrap(space);
616 ma = isl_multi_aff_domain_map(space);
617 mpa_arg = isl_multi_pw_aff_pullback_multi_aff(mpa_arg, ma);
620 mpa = isl_multi_pw_aff_flat_range_product(mpa, mpa_arg);
622 return mpa;
625 /* Given the data space "space1" of an index expression passed
626 * to a function and the data space "space2" of the corresponding
627 * array accessed in the function, construct and return the complete
628 * data space from the perspective of the function call.
629 * If add is set, then it is not the index expression with space "space1" itself
630 * that is passed to the function, but its address.
632 * In the simplest case, no member accesses are involved and "add" is not set.
633 * Let "space1" be of the form A[x] and "space2" of the form B[y].
634 * Then the returned space is A[x,y].
635 * That is, the dimension is the sum of the dimensions and the name
636 * is that of "space1".
637 * If "add" is set, then the final dimension of "space1" is the same
638 * as the initial dimension of "space2" and the dimension of the result
639 * is one less that the sum. This also applies when the dimension
640 * of "space1" is zero. The dimension of "space2" can never be zero
641 * when "add" is set since a pointer value is passed to the function,
642 * which is treated as an array of dimension at least 1.
644 * If "space1" involves any member accesses, then it is the innermost
645 * array space of "space1" that needs to be extended with "space2".
646 * This innermost array space appears in the range of the wrapped
647 * relation in "space1".
649 * If "space2" involves any member accesses, then it is the outermost
650 * array space of "space2" that needs to be combined with innermost
651 * array space of "space1". This outermost array space appears
652 * in the deepest nesting of the domains and is therefore handled
653 * recursively.
655 * For example, if "space1" is of the form
657 * s_a[s[x] -> a[y]]
659 * and "space2" is of the form
661 * d_b_c[d_b[d[z] -> b[u]] -> c[v]]
663 * then the resulting space is
665 * s_a_b_c[s_a_b[s_a[s[x] -> a[y,z]] -> b[u]] -> c[v]]
667 static __isl_give isl_space *patch_space(__isl_take isl_space *space1,
668 __isl_take isl_space *space2, int add)
670 int dim;
671 isl_id *id;
673 if (!space1 || !space2)
674 goto error;
676 if (isl_space_is_wrapping(space2)) {
677 isl_ctx *ctx;
678 isl_space *dom;
679 const char *name1, *name2;
680 char *name;
682 ctx = isl_space_get_ctx(space1);
683 space2 = isl_space_unwrap(space2);
684 dom = isl_space_domain(isl_space_copy(space2));
685 space1 = patch_space(space1, dom, add);
686 space2 = isl_space_range(space2);
687 name1 = isl_space_get_tuple_name(space1, isl_dim_set);
688 name2 = isl_space_get_tuple_name(space2, isl_dim_set);
689 name = pet_array_member_access_name(ctx, name1, name2);
690 space1 = isl_space_product(space1, space2);
691 space1 = isl_space_set_tuple_name(space1, isl_dim_set, name);
692 free(name);
693 return space1;
696 dim = isl_space_dim(space2, isl_dim_set) - add;
697 id = isl_space_get_tuple_id(space1, isl_dim_set);
698 if (isl_space_is_wrapping(space1)) {
699 isl_id *id;
701 space1 = isl_space_unwrap(space1);
702 id = isl_space_get_tuple_id(space1, isl_dim_out);
703 space1 = isl_space_add_dims(space1, isl_dim_out, dim);
704 space1 = isl_space_set_tuple_id(space1, isl_dim_out, id);
705 space1 = isl_space_wrap(space1);
706 } else {
707 space1 = isl_space_add_dims(space1, isl_dim_out, dim);
709 space1 = isl_space_set_tuple_id(space1, isl_dim_set, id);
711 isl_space_free(space2);
712 return space1;
713 error:
714 isl_space_free(space1);
715 isl_space_free(space2);
716 return NULL;
719 /* Drop the initial dimension of "map", assuming that it is equal to zero.
720 * If it turns out not to be equal to zero, then drop the initial dimension
721 * of "map" after setting the value to zero and print a warning.
723 static __isl_give isl_map *drop_initial_zero(__isl_take isl_map *map,
724 __isl_keep isl_map *prefix)
726 isl_map *zeroed;
728 zeroed = isl_map_copy(map);
729 zeroed = isl_map_fix_si(zeroed, isl_dim_out, 0, 0);
730 map = isl_map_subtract(map, isl_map_copy(zeroed));
731 if (!isl_map_is_empty(map)) {
732 fprintf(stderr, "possible out-of-bounds accesses\n");
733 isl_map_dump(map);
734 fprintf(stderr, "when passing\n");
735 isl_map_dump(prefix);
737 isl_map_free(map);
738 map = zeroed;
739 map = isl_map_project_out(map, isl_dim_out, 0, 1);
740 return map;
743 /* Given an identity mapping "id" that adds structure to
744 * the range of "map" with dimensions "pos" and "pos + 1" replaced
745 * by their sum, adjust "id" to apply to the range of "map" directly.
746 * That is, plug in
748 * [i_0, ..., i_pos, i_{pos+1}, i_{pos+2}, ...] ->
749 * [i_0, ..., i_pos + i_{pos+1}, i_{pos+2}, ...]
751 * in "id", where the domain of this mapping corresponds to the range
752 * of "map" and the range of this mapping corresponds to the original
753 * domain of "id".
755 static __isl_give isl_map *patch_map_add(__isl_take isl_map *id,
756 __isl_keep isl_map *map, int pos)
758 isl_space *space;
759 isl_multi_aff *ma;
760 isl_aff *aff1, *aff2;
762 space = isl_space_range(isl_map_get_space(map));
763 ma = isl_multi_aff_identity(isl_space_map_from_set(space));
764 aff1 = isl_multi_aff_get_aff(ma, pos);
765 aff2 = isl_multi_aff_get_aff(ma, pos + 1);
766 aff1 = isl_aff_add(aff1, aff2);
767 ma = isl_multi_aff_set_aff(ma, pos, aff1);
768 ma = isl_multi_aff_drop_dims(ma, isl_dim_out, pos + 1, 1);
769 id = isl_map_preimage_domain_multi_aff(id, ma);
771 return id;
774 /* Return the dimension of the innermost array in the data space "space".
775 * If "space" is not a wrapping space, the it does not involve any
776 * member accesses and the innermost array is simply the accessed
777 * array itself.
778 * Otherwise, the innermost array is encoded in the range of the
779 * wrapped space.
781 static int innermost_dim(__isl_keep isl_space *space)
783 int dim;
785 if (!isl_space_is_wrapping(space))
786 return isl_space_dim(space, isl_dim_set);
788 space = isl_space_copy(space);
789 space = isl_space_unwrap(space);
790 dim = isl_space_dim(space, isl_dim_out);
791 isl_space_free(space);
793 return dim;
796 /* Internal data structure for patch_map.
798 * "prefix" is the index expression passed to the function
799 * "add" is set if it is the address of "prefix" that is passed to the function.
800 * "res" collects the results.
802 struct pet_patch_map_data {
803 isl_map *prefix;
804 int add;
806 isl_union_map *res;
809 /* Combine the index expression data->prefix with the subaccess relation "map".
810 * If data->add is set, then it is not the index expression data->prefix itself
811 * that is passed to the function, but its address.
813 * If data->add is not set, then we essentially need to concatenate
814 * data->prefix with map, except that we need to make sure that
815 * the target space is set correctly. This target space is computed
816 * by the function patch_space. We then simply compute the flat
817 * range product and subsequently reset the target space.
819 * If data->add is set then the outer dimension of "map" is an offset
820 * with respect to the inner dimension of data->prefix and we therefore
821 * need to add these two dimensions rather than simply concatenating them.
822 * This computation is performed in patch_map_add.
823 * If however, the innermost accessed array of data->prefix is
824 * zero-dimensional, then there is no innermost dimension of data->prefix
825 * to add to the outermost dimension of "map", Instead, we are passing
826 * a pointer to a scalar member, meaning that the outermost dimension
827 * of "map" needs to be zero and that this zero needs to be removed
828 * from the concatenation. This computation is performed in drop_initial_zero.
830 static int patch_map(__isl_take isl_map *map, void *user)
832 struct pet_patch_map_data *data = user;
833 isl_space *space;
834 isl_map *id;
835 int pos, dim;
837 space = isl_space_range(isl_map_get_space(data->prefix));
838 dim = innermost_dim(space);
839 pos = isl_space_dim(space, isl_dim_set) - dim;
840 space = patch_space(space, isl_space_range(isl_map_get_space(map)),
841 data->add);
842 if (data->add && dim == 0)
843 map = drop_initial_zero(map, data->prefix);
844 map = isl_map_flat_range_product(isl_map_copy(data->prefix), map);
845 space = isl_space_map_from_set(space);
846 space = isl_space_add_dims(space, isl_dim_in, 0);
847 id = isl_map_identity(space);
848 if (data->add && dim != 0)
849 id = patch_map_add(id, map, pos + dim - 1);
850 map = isl_map_apply_range(map, id);
851 data->res = isl_union_map_add_map(data->res, map);
853 return 0;
856 /* Combine the index expression of "expr" with the subaccess relation "access".
857 * If "add" is set, then it is not the index expression of "expr" itself
858 * that is passed to the function, but its address.
860 * We call patch_map on each map in "access" and return the combined results.
862 static __isl_give isl_union_map *patch(__isl_take isl_union_map *access,
863 __isl_keep pet_expr *expr, int add)
865 struct pet_patch_map_data data;
866 isl_map *map;
868 map = isl_map_from_multi_pw_aff(pet_expr_access_get_index(expr));
869 map = isl_map_align_params(map, isl_union_map_get_space(access));
870 access = isl_union_map_align_params(access, isl_map_get_space(map));
871 data.prefix = map;
872 data.add = add;
873 data.res = isl_union_map_empty(isl_union_map_get_space(access));
874 if (isl_union_map_foreach_map(access, &patch_map, &data) < 0)
875 data.res = isl_union_map_free(data.res);
876 isl_union_map_free(access);
877 isl_map_free(data.prefix);
879 return data.res;
882 /* Set the access relations of "expr", which appears in the argument
883 * at position "pos" in a call expression by composing the access
884 * relations in "summary" with the expression "int_arg" of the integer
885 * arguments in terms of the domain and expression arguments of "expr" and
886 * combining the result with the index expression passed to the function.
887 * If "add" is set, then it is not "expr" itself that is passed
888 * to the function, but the address of "expr".
890 * We reset the read an write flag of "expr" and rely on
891 * pet_expr_access_set_access setting the flags based on
892 * the access relations.
894 * After relating each access relation of the called function
895 * to the domain and expression arguments at the call site,
896 * the result is combined with the index expression by the function patch
897 * and then stored in the access expression.
899 static __isl_give pet_expr *set_access_relations(__isl_take pet_expr *expr,
900 __isl_keep pet_function_summary *summary, int pos,
901 __isl_take isl_multi_pw_aff *int_arg, int add)
903 enum pet_expr_access_type type;
905 expr = pet_expr_access_set_read(expr, 0);
906 expr = pet_expr_access_set_write(expr, 0);
907 for (type = pet_expr_access_begin; type < pet_expr_access_end; ++type) {
908 isl_union_map *access;
910 access = pet_function_summary_arg_get_access(summary,
911 pos, type);
912 access = isl_union_map_preimage_domain_multi_pw_aff(access,
913 isl_multi_pw_aff_copy(int_arg));
914 access = patch(access, expr, add);
915 expr = pet_expr_access_set_access(expr, type, access);
917 isl_multi_pw_aff_free(int_arg);
919 return expr;
922 /* Set the access relations of "arg", which appears in the argument
923 * at position "pos" in the call expression "call" based on the
924 * information in "summary".
925 * If "add" is set, then it is not "arg" itself that is passed
926 * to the function, but the address of "arg".
928 * We create an affine function "int_arg" that expresses
929 * the integer function call arguments in terms of the domain of "arg"
930 * (i.e., the outer loop iterators) and the expression arguments.
931 * If the actual argument is not an affine expression or if it itself
932 * has expression arguments, then it is added as an argument to "arg" and
933 * "int_arg" is made to reference this additional expression argument.
935 * Finally, we call set_access_relations to plug in the actual arguments
936 * (expressed in "int_arg") into the access relations in "summary" and
937 * to add the resulting access relations to "arg".
939 static __isl_give pet_expr *access_plug_in_summary(__isl_take pet_expr *arg,
940 __isl_keep pet_expr *call, __isl_keep pet_function_summary *summary,
941 int pos, int add)
943 int j, n;
944 isl_space *space;
945 isl_multi_pw_aff *int_arg;
946 int arg_n_arg;
948 space = pet_expr_access_get_augmented_domain_space(arg);
949 space = isl_space_from_domain(space);
950 arg_n_arg = pet_expr_get_n_arg(arg);
951 int_arg = isl_multi_pw_aff_zero(space);
952 n = pet_function_summary_get_n_arg(summary);
953 for (j = 0; j < n; ++j) {
954 pet_expr *arg_j;
955 int arg_j_n_arg;
957 if (!pet_function_summary_arg_is_int(summary, j))
958 continue;
960 arg_j = pet_expr_get_arg(call, j);
961 arg_j_n_arg = pet_expr_get_n_arg(arg_j);
962 if (pet_expr_get_type(arg_j) == pet_expr_int) {
963 int_arg = add_int(int_arg, arg_j);
964 } else if (arg_j_n_arg != 0 || !pet_expr_is_affine(arg_j)) {
965 arg = pet_expr_insert_arg(arg, arg_n_arg,
966 arg_j);
967 int_arg = add_arg(int_arg, arg_n_arg);
968 arg_n_arg++;
969 } else {
970 int_arg = add_aff(int_arg, arg_n_arg, arg_j);
973 arg = set_access_relations(arg, summary, pos, int_arg, add);
975 return arg;
978 /* Given the argument "arg" at position "pos" of "call",
979 * check if it is either an access expression or the address
980 * of an access expression. If so, use the information in "summary"
981 * to set the access relations of the access expression.
983 static __isl_give pet_expr *arg_plug_in_summary(__isl_take pet_expr *arg,
984 __isl_keep pet_expr *call, __isl_keep pet_function_summary *summary,
985 int pos)
987 enum pet_expr_type type;
988 pet_expr *arg2;
990 type = pet_expr_get_type(arg);
991 if (type == pet_expr_access)
992 return access_plug_in_summary(arg, call, summary, pos, 0);
993 if (type != pet_expr_op)
994 return arg;
995 if (pet_expr_op_get_type(arg) != pet_op_address_of)
996 return arg;
998 arg2 = pet_expr_get_arg(arg, 0);
999 if (pet_expr_get_type(arg2) == pet_expr_access)
1000 arg2 = access_plug_in_summary(arg2, call, summary, pos, 1);
1001 arg = pet_expr_set_arg(arg, 0, arg2);
1003 return arg;
1006 /* Given a call expression, check if the integer arguments can
1007 * be represented by affine expressions in the context "pc"
1008 * (assuming they are not already affine expressions).
1009 * If so, replace these arguments by the corresponding affine expressions.
1011 static __isl_give pet_expr *call_plug_in_affine_args(__isl_take pet_expr *call,
1012 __isl_keep pet_context *pc)
1014 int i, n;
1016 n = pet_expr_get_n_arg(call);
1017 for (i = 0; i < n; ++i) {
1018 pet_expr *arg;
1019 isl_pw_aff *pa;
1021 arg = pet_expr_get_arg(call, i);
1022 if (!arg)
1023 return pet_expr_free(call);
1024 if (pet_expr_get_type_size(arg) == 0 ||
1025 pet_expr_is_affine(arg)) {
1026 pet_expr_free(arg);
1027 continue;
1030 pa = pet_expr_extract_affine(arg, pc);
1031 pet_expr_free(arg);
1032 if (!pa)
1033 return pet_expr_free(call);
1034 if (isl_pw_aff_involves_nan(pa)) {
1035 isl_pw_aff_free(pa);
1036 continue;
1039 arg = pet_expr_from_index(isl_multi_pw_aff_from_pw_aff(pa));
1040 call = pet_expr_set_arg(call, i, arg);
1043 return call;
1046 /* If "call" has an associated function summary, then use it
1047 * to set the access relations of the array arguments of the function call.
1049 * We first plug in affine expressions for the integer arguments
1050 * whenever possible as these arguments will be plugged in
1051 * in the access relations of the array arguments.
1053 static __isl_give pet_expr *call_plug_in_summary(__isl_take pet_expr *call,
1054 void *user)
1056 pet_context *pc = user;
1057 pet_function_summary *summary;
1058 int i, n;
1060 if (!pet_expr_call_has_summary(call))
1061 return call;
1063 call = call_plug_in_affine_args(call, pc);
1065 summary = pet_expr_call_get_summary(call);
1066 if (!summary)
1067 return pet_expr_free(call);
1069 n = pet_expr_get_n_arg(call);
1070 for (i = 0; i < n; ++i) {
1071 pet_expr *arg_i;
1073 if (!pet_function_summary_arg_is_array(summary, i))
1074 continue;
1076 arg_i = pet_expr_get_arg(call, i);
1077 arg_i = arg_plug_in_summary(arg_i, call, summary, i);
1078 call = pet_expr_set_arg(call, i, arg_i);
1081 pet_function_summary_free(summary);
1082 return call;
1085 /* For each call subexpression of "expr", plug in the access relations
1086 * from the associated function summary (if any).
1088 static __isl_give pet_expr *plug_in_summaries(__isl_take pet_expr *expr,
1089 __isl_keep pet_context *pc)
1091 return pet_expr_map_call(expr, &call_plug_in_summary, pc);
1094 /* Evaluate "expr" in the context of "pc".
1096 * In particular, we first make sure that all the access expressions
1097 * inside "expr" have the same domain as "pc".
1098 * Then, we plug in affine expressions for scalar reads,
1099 * plug in the arguments of all access expressions in "expr" and
1100 * plug in the access relations from the summary functions associated
1101 * to call expressions.
1103 __isl_give pet_expr *pet_context_evaluate_expr(__isl_keep pet_context *pc,
1104 __isl_take pet_expr *expr)
1106 expr = pet_expr_insert_domain(expr, pet_context_get_space(pc));
1107 expr = plug_in_affine_read(expr, pc);
1108 expr = pet_expr_plug_in_args(expr, pc);
1109 expr = plug_in_summaries(expr, pc);
1110 return expr;
1113 /* Wrapper around pet_context_evaluate_expr
1114 * for use as a callback to pet_tree_map_expr.
1116 static __isl_give pet_expr *evaluate_expr(__isl_take pet_expr *expr,
1117 void *user)
1119 pet_context *pc = user;
1121 return pet_context_evaluate_expr(pc, expr);
1124 /* Evaluate "tree" in the context of "pc".
1125 * That is, evaluate all the expressions of "tree" in the context of "pc".
1127 __isl_give pet_tree *pet_context_evaluate_tree(__isl_keep pet_context *pc,
1128 __isl_take pet_tree *tree)
1130 return pet_tree_map_expr(tree, &evaluate_expr, pc);
1133 /* Add an unbounded inner dimension "id" to pc->domain.
1135 * The assignments are not adjusted here and therefore keep
1136 * their original domain. These domains need to be adjusted before
1137 * these assigned values can be used. This is taken care of by
1138 * pet_context_get_value.
1140 static __isl_give pet_context *extend_domain(__isl_take pet_context *pc,
1141 __isl_take isl_id *id)
1143 int pos;
1145 pc = pet_context_cow(pc);
1146 if (!pc || !id)
1147 goto error;
1149 pos = pet_context_dim(pc);
1150 pc->domain = isl_set_add_dims(pc->domain, isl_dim_set, 1);
1151 pc->domain = isl_set_set_dim_id(pc->domain, isl_dim_set, pos, id);
1152 if (!pc->domain)
1153 return pet_context_free(pc);
1155 return pc;
1156 error:
1157 pet_context_free(pc);
1158 isl_id_free(id);
1159 return NULL;
1162 /* Add an unbounded inner iterator "id" to pc->domain.
1163 * Additionally, mark the variable "id" as having the value of this
1164 * new inner iterator.
1166 __isl_give pet_context *pet_context_add_inner_iterator(
1167 __isl_take pet_context *pc, __isl_take isl_id *id)
1169 int pos;
1170 isl_space *space;
1171 isl_local_space *ls;
1172 isl_aff *aff;
1173 isl_pw_aff *pa;
1175 if (!pc || !id)
1176 goto error;
1178 pos = pet_context_dim(pc);
1179 pc = extend_domain(pc, isl_id_copy(id));
1180 if (!pc)
1181 goto error;
1183 space = pet_context_get_space(pc);
1184 ls = isl_local_space_from_space(space);
1185 aff = isl_aff_var_on_domain(ls, isl_dim_set, pos);
1186 pa = isl_pw_aff_from_aff(aff);
1188 pc = pet_context_set_value(pc, id, pa);
1190 return pc;
1191 error:
1192 pet_context_free(pc);
1193 isl_id_free(id);
1194 return NULL;
1197 /* Add an inner iterator to pc->domain.
1198 * In particular, extend the domain with an inner loop { [t] : t >= 0 }.
1200 __isl_give pet_context *pet_context_add_infinite_loop(
1201 __isl_take pet_context *pc)
1203 int dim;
1204 isl_ctx *ctx;
1205 isl_id *id;
1207 if (!pc)
1208 return NULL;
1210 dim = pet_context_dim(pc);
1211 ctx = pet_context_get_ctx(pc);
1212 id = isl_id_alloc(ctx, "t", NULL);
1213 pc = extend_domain(pc, id);
1214 pc = pet_context_cow(pc);
1215 if (!pc)
1216 return NULL;
1217 pc->domain = isl_set_lower_bound_si(pc->domain, isl_dim_set, dim, 0);
1218 if (!pc->domain)
1219 return pet_context_free(pc);
1221 return pc;
1224 /* Internal data structure for preimage_domain.
1226 * "ma" is the function under which the preimage should be computed.
1227 * "assignments" collects the results.
1229 struct pet_preimage_domain_data {
1230 isl_multi_aff *ma;
1231 isl_id_to_pw_aff *assignments;
1234 /* Add the assignment to "key" of the preimage of "val" under data->ma
1235 * to data->assignments.
1237 * Some dimensions may have been added to the domain of the enclosing
1238 * pet_context after the value "val" was added. We therefore need to
1239 * adjust the domain of "val" to match the range of data->ma (which
1240 * in turn matches the domain of the pet_context), by adding the missing
1241 * dimensions.
1243 static int preimage_domain_pair(__isl_take isl_id *key,
1244 __isl_take isl_pw_aff *val, void *user)
1246 struct pet_preimage_domain_data *data = user;
1247 int dim;
1248 isl_multi_aff *ma;
1250 ma = isl_multi_aff_copy(data->ma);
1252 dim = isl_pw_aff_dim(val, isl_dim_in);
1253 if (dim != isl_multi_aff_dim(data->ma, isl_dim_out)) {
1254 isl_space *space;
1255 isl_multi_aff *proj;
1256 space = isl_multi_aff_get_space(data->ma);
1257 space = isl_space_range(space);
1258 proj = pet_prefix_projection(space, dim);
1259 ma = isl_multi_aff_pullback_multi_aff(proj, ma);
1262 val = isl_pw_aff_pullback_multi_aff(val, ma);
1263 data->assignments = isl_id_to_pw_aff_set(data->assignments, key, val);
1265 return 0;
1268 /* Compute the preimage of "assignments" under the function represented by "ma".
1269 * In other words, plug in "ma" in the domains of the assigned values.
1271 static __isl_give isl_id_to_pw_aff *preimage_domain(
1272 __isl_take isl_id_to_pw_aff *assignments, __isl_keep isl_multi_aff *ma)
1274 struct pet_preimage_domain_data data = { ma };
1275 isl_ctx *ctx;
1277 ctx = isl_id_to_pw_aff_get_ctx(assignments);
1278 data.assignments = isl_id_to_pw_aff_alloc(ctx, 0);
1279 if (isl_id_to_pw_aff_foreach(assignments, &preimage_domain_pair,
1280 &data) < 0)
1281 data.assignments = isl_id_to_pw_aff_free(data.assignments);
1282 isl_id_to_pw_aff_free(assignments);
1284 return data.assignments;
1287 /* Compute the preimage of "pc" under the function represented by "ma".
1288 * In other words, plug in "ma" in the domain of "pc".
1290 __isl_give pet_context *pet_context_preimage_domain(__isl_take pet_context *pc,
1291 __isl_keep isl_multi_aff *ma)
1293 pc = pet_context_cow(pc);
1294 if (!pc)
1295 return NULL;
1296 pc->domain = isl_set_preimage_multi_aff(pc->domain,
1297 isl_multi_aff_copy(ma));
1298 pc->assignments = preimage_domain(pc->assignments, ma);
1299 if (!pc->domain || !pc->assignments)
1300 return pet_context_free(pc);
1301 return pc;
1304 /* Add the constraints of "set" to the domain of "pc".
1306 __isl_give pet_context *pet_context_intersect_domain(__isl_take pet_context *pc,
1307 __isl_take isl_set *set)
1309 pc = pet_context_cow(pc);
1310 if (!pc)
1311 goto error;
1312 pc->domain = isl_set_intersect(pc->domain, set);
1313 if (!pc->domain)
1314 return pet_context_free(pc);
1315 return pc;
1316 error:
1317 pet_context_free(pc);
1318 isl_set_free(set);
1319 return NULL;
1322 void pet_context_dump(__isl_keep pet_context *pc)
1324 if (!pc)
1325 return;
1326 fprintf(stderr, "domain: ");
1327 isl_set_dump(pc->domain);
1328 fprintf(stderr, "assignments: ");
1329 isl_id_to_pw_aff_dump(pc->assignments);
1330 fprintf(stderr, "nesting allowed: %d\n", pc->allow_nested);