pet_expr_access_get_id: avoid using access relation
[pet.git] / nest.c
blob0cddeeb741b8b3446c717137694377a435d3487e
1 /*
2 * Copyright 2011 Leiden University. All rights reserved.
3 * Copyright 2012-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 <string.h>
37 #include "aff.h"
38 #include "expr.h"
39 #include "expr_arg.h"
40 #include "nest.h"
41 #include "scop.h"
42 #include "tree.h"
44 /* A wrapper around pet_expr_free to be used as an isl_id free user function.
46 static void pet_expr_free_wrap(void *user)
48 pet_expr_free((pet_expr *) user);
51 /* Create an isl_id that refers to the nested access "expr".
53 __isl_give isl_id *pet_nested_pet_expr(__isl_take pet_expr *expr)
55 isl_id *id;
57 id = isl_id_alloc(pet_expr_get_ctx(expr), "__pet_expr", expr);
58 id = isl_id_set_free_user(id, &pet_expr_free_wrap);
60 return id;
63 /* Extract a pet_expr from an isl_id created by pet_nested_pet_expr.
64 * Such an isl_id has name "__pet_expr" and
65 * the user pointer points to a pet_expr object.
67 __isl_give pet_expr *pet_nested_extract_expr(__isl_keep isl_id *id)
69 return pet_expr_copy((pet_expr *) isl_id_get_user(id));
72 /* Does "id" refer to a nested access created by pet_nested_pet_expr?
74 int pet_nested_in_id(__isl_keep isl_id *id)
76 const char *name;
78 if (!id)
79 return 0;
80 if (!isl_id_get_user(id))
81 return 0;
83 name = isl_id_get_name(id);
84 return !strcmp(name, "__pet_expr");
87 /* Does parameter "pos" of "space" refer to a nested access?
89 static int pet_nested_in_space(__isl_keep isl_space *space, int pos)
91 int nested;
92 isl_id *id;
94 id = isl_space_get_dim_id(space, isl_dim_param, pos);
95 nested = pet_nested_in_id(id);
96 isl_id_free(id);
98 return nested;
101 /* Does parameter "pos" of "set" refer to a nested access?
103 int pet_nested_in_set(__isl_keep isl_set *set, int pos)
105 int nested;
106 isl_id *id;
108 id = isl_set_get_dim_id(set, isl_dim_param, pos);
109 nested = pet_nested_in_id(id);
110 isl_id_free(id);
112 return nested;
115 /* Does parameter "pos" of "map" refer to a nested access?
117 int pet_nested_in_map(__isl_keep isl_map *map, int pos)
119 int nested;
120 isl_id *id;
122 id = isl_map_get_dim_id(map, isl_dim_param, pos);
123 nested = pet_nested_in_id(id);
124 isl_id_free(id);
126 return nested;
129 /* Does "space" involve any parameters that refer to nested accesses?
131 int pet_nested_any_in_space(__isl_keep isl_space *space)
133 int i;
134 int nparam;
136 nparam = isl_space_dim(space, isl_dim_param);
137 for (i = 0; i < nparam; ++i)
138 if (pet_nested_in_space(space, i))
139 return 1;
141 return 0;
144 /* Does "pa" involve any parameters that refer to nested accesses?
146 int pet_nested_any_in_pw_aff(__isl_keep isl_pw_aff *pa)
148 isl_space *space;
149 int nested;
151 space = isl_pw_aff_get_space(pa);
152 nested = pet_nested_any_in_space(space);
153 isl_space_free(space);
155 return nested;
158 /* How many parameters of "space" refer to nested accesses?
160 int pet_nested_n_in_space(__isl_keep isl_space *space)
162 int i, n = 0;
163 int nparam;
165 nparam = isl_space_dim(space, isl_dim_param);
166 for (i = 0; i < nparam; ++i)
167 if (pet_nested_in_space(space, i))
168 ++n;
170 return n;
173 /* How many parameters of "map" refer to nested accesses?
175 int pet_nested_n_in_map(__isl_keep isl_map *map)
177 isl_space *space;
178 int n;
180 space = isl_map_get_space(map);
181 n = pet_nested_n_in_space(space);
182 isl_space_free(space);
184 return n;
187 /* How many parameters of "set" refer to nested accesses?
189 int pet_nested_n_in_set(__isl_keep isl_set *set)
191 isl_space *space;
192 int n;
194 space = isl_set_get_space(set);
195 n = pet_nested_n_in_space(space);
196 isl_space_free(space);
198 return n;
201 /* Remove all parameters from "space" that refer to nested accesses.
203 __isl_give isl_space *pet_nested_remove_from_space(__isl_take isl_space *space)
205 int i;
206 int nparam;
208 nparam = isl_space_dim(space, isl_dim_param);
209 for (i = nparam - 1; i >= 0; --i)
210 if (pet_nested_in_space(space, i))
211 space = isl_space_drop_dims(space, isl_dim_param, i, 1);
213 return space;
216 /* Remove all parameters from "set" that refer to nested accesses.
218 __isl_give isl_set *pet_nested_remove_from_set(__isl_take isl_set *set)
220 int i;
221 int nparam;
223 nparam = isl_set_dim(set, isl_dim_param);
224 for (i = nparam - 1; i >= 0; --i)
225 if (pet_nested_in_set(set, i))
226 set = isl_set_project_out(set, isl_dim_param, i, 1);
228 return set;
231 /* Remove all parameters from "map" that refer to nested accesses.
233 static __isl_give isl_map *pet_nested_remove_from_map(__isl_take isl_map *map)
235 int i;
236 int nparam;
238 nparam = isl_map_dim(map, isl_dim_param);
239 for (i = nparam - 1; i >= 0; --i)
240 if (pet_nested_in_map(map, i))
241 map = isl_map_project_out(map, isl_dim_param, i, 1);
243 return map;
246 /* Remove all parameters from "mpa" that refer to nested accesses.
248 static __isl_give isl_multi_pw_aff *pet_nested_remove_from_multi_pw_aff(
249 __isl_take isl_multi_pw_aff *mpa)
251 int i;
252 int nparam;
253 isl_space *space;
255 space = isl_multi_pw_aff_get_space(mpa);
256 nparam = isl_space_dim(space, isl_dim_param);
257 for (i = nparam - 1; i >= 0; --i) {
258 if (!pet_nested_in_space(space, i))
259 continue;
260 mpa = isl_multi_pw_aff_drop_dims(mpa, isl_dim_param, i, 1);
262 isl_space_free(space);
264 return mpa;
267 /* Remove all parameters from the index expression and access relation of "expr"
268 * that refer to nested accesses.
270 static __isl_give pet_expr *expr_remove_nested_parameters(
271 __isl_take pet_expr *expr, void *user)
273 expr = pet_expr_cow(expr);
274 if (!expr)
275 return NULL;
277 expr->acc.access = pet_nested_remove_from_map(expr->acc.access);
278 expr->acc.index = pet_nested_remove_from_multi_pw_aff(expr->acc.index);
279 if (!expr->acc.access || !expr->acc.index)
280 return pet_expr_free(expr);
282 return expr;
285 /* Remove all nested access parameters from the schedule and all
286 * accesses of "stmt".
287 * There is no need to remove them from the domain as these parameters
288 * have already been removed from the domain when this function is called.
290 struct pet_stmt *pet_stmt_remove_nested_parameters(struct pet_stmt *stmt)
292 int i;
294 if (!stmt)
295 return NULL;
296 stmt->schedule = pet_nested_remove_from_map(stmt->schedule);
297 stmt->body = pet_tree_map_access_expr(stmt->body,
298 &expr_remove_nested_parameters, NULL);
299 if (!stmt->schedule || !stmt->body)
300 goto error;
301 for (i = 0; i < stmt->n_arg; ++i) {
302 stmt->args[i] = pet_expr_map_access(stmt->args[i],
303 &expr_remove_nested_parameters, NULL);
304 if (!stmt->args[i])
305 goto error;
308 return stmt;
309 error:
310 pet_stmt_free(stmt);
311 return NULL;
314 /* Set *dim to the dimension of the domain of the access expression "expr" and
315 * abort the search.
317 static int set_dim(__isl_keep pet_expr *expr, void *user)
319 int *dim = user;
320 isl_space *space;
322 space = pet_expr_access_get_domain_space(expr);
323 *dim = isl_space_dim(space, isl_dim_set);
324 isl_space_free(space);
326 return -1;
329 /* Determine the dimension of the domain of the access expressions in "expr".
331 * In particular, return the dimension of the domain of the first access
332 * expression in "expr" as all access expressions should have the same
333 * domain.
335 * If "expr" does not contain any access expressions, then we return 0.
337 static int pet_expr_domain_dim(__isl_keep pet_expr *expr)
339 int dim = -1;
341 if (pet_expr_foreach_access_expr(expr, &set_dim, &dim) >= 0)
342 return 0;
344 return dim;
347 /* Embed all access expressions in "expr" in the domain "space".
348 * The initial domain of the access expressions
349 * is an anonymous domain of a dimension that may be lower
350 * than the dimension of "space".
351 * We may therefore need to introduce extra dimensions as well as
352 * (potentially) the name of "space".
354 static __isl_give pet_expr *embed(__isl_take pet_expr *expr,
355 __isl_keep isl_space *space)
357 int n;
358 isl_multi_pw_aff *mpa;
360 n = pet_expr_domain_dim(expr);
361 if (n < 0)
362 return pet_expr_free(expr);
364 space = isl_space_copy(space);
365 mpa = isl_multi_pw_aff_from_multi_aff(pet_prefix_projection(space, n));
366 expr = pet_expr_update_domain(expr, mpa);
368 return expr;
371 /* For each nested access parameter in "space",
372 * construct a corresponding pet_expr, place it in args and
373 * record its position in "param2pos".
374 * The constructed pet_expr objects are embedded in "space"
375 * (with the nested access parameters removed).
376 * "n_arg" is the number of elements that are already in args.
377 * The position recorded in "param2pos" takes this number into account.
378 * If the pet_expr corresponding to a parameter is identical to
379 * the pet_expr corresponding to an earlier parameter, then these two
380 * parameters are made to refer to the same element in args.
382 * Return the final number of elements in args or -1 if an error has occurred.
384 int pet_extract_nested_from_space(__isl_keep isl_space *space,
385 int n_arg, __isl_give pet_expr **args, int *param2pos)
387 int i, nparam;
388 isl_space *domain;
390 domain = isl_space_copy(space);
391 domain = pet_nested_remove_from_space(domain);
392 nparam = isl_space_dim(space, isl_dim_param);
393 for (i = 0; i < nparam; ++i) {
394 int j;
395 isl_id *id = isl_space_get_dim_id(space, isl_dim_param, i);
397 if (!pet_nested_in_id(id)) {
398 isl_id_free(id);
399 continue;
402 args[n_arg] = embed(pet_nested_extract_expr(id), domain);
403 isl_id_free(id);
404 if (!args[n_arg])
405 return -1;
407 for (j = 0; j < n_arg; ++j)
408 if (pet_expr_is_equal(args[j], args[n_arg]))
409 break;
411 if (j < n_arg) {
412 pet_expr_free(args[n_arg]);
413 args[n_arg] = NULL;
414 param2pos[i] = j;
415 } else
416 param2pos[i] = n_arg++;
418 isl_space_free(domain);
420 return n_arg;
423 /* For each nested access parameter in the access relations in "expr",
424 * construct a corresponding pet_expr, append it to the arguments of "expr"
425 * and record its position in "param2pos" (relative to the initial
426 * number of arguments).
427 * n is the number of nested access parameters.
429 __isl_give pet_expr *pet_expr_extract_nested(__isl_take pet_expr *expr, int n,
430 int *param2pos)
432 isl_ctx *ctx;
433 isl_space *space;
434 int i, n_arg;
435 pet_expr **args;
437 ctx = pet_expr_get_ctx(expr);
438 args = isl_calloc_array(ctx, pet_expr *, n);
439 if (!args)
440 return pet_expr_free(expr);
442 n_arg = pet_expr_get_n_arg(expr);
443 space = pet_expr_access_get_domain_space(expr);
444 n = pet_extract_nested_from_space(space, 0, args, param2pos);
445 isl_space_free(space);
447 if (n < 0)
448 expr = pet_expr_free(expr);
449 else
450 expr = pet_expr_set_n_arg(expr, n_arg + n);
452 for (i = 0; i < n; ++i)
453 expr = pet_expr_set_arg(expr, n_arg + i, args[i]);
454 free(args);
456 return expr;
459 /* Are "expr1" and "expr2" both array accesses such that
460 * the access relation of "expr1" is a subset of that of "expr2"?
461 * Only take into account the first "n_arg" arguments.
463 static int is_sub_access(__isl_keep pet_expr *expr1, __isl_keep pet_expr *expr2,
464 int n_arg)
466 isl_id *id1, *id2;
467 isl_map *access1, *access2;
468 int is_subset;
469 int i, n1, n2;
471 if (!expr1 || !expr2)
472 return 0;
473 if (pet_expr_get_type(expr1) != pet_expr_access)
474 return 0;
475 if (pet_expr_get_type(expr2) != pet_expr_access)
476 return 0;
477 if (pet_expr_is_affine(expr1))
478 return 0;
479 if (pet_expr_is_affine(expr2))
480 return 0;
481 n1 = pet_expr_get_n_arg(expr1);
482 if (n1 > n_arg)
483 n1 = n_arg;
484 n2 = pet_expr_get_n_arg(expr2);
485 if (n2 > n_arg)
486 n2 = n_arg;
487 if (n1 != n2)
488 return 0;
489 for (i = 0; i < n1; ++i) {
490 pet_expr *arg1, *arg2;
491 int equal;
492 arg1 = pet_expr_get_arg(expr1, i);
493 arg2 = pet_expr_get_arg(expr2, i);
494 equal = pet_expr_is_equal(arg1, arg2);
495 pet_expr_free(arg1);
496 pet_expr_free(arg2);
497 if (equal < 0 || !equal)
498 return equal;
500 id1 = pet_expr_access_get_id(expr1);
501 id2 = pet_expr_access_get_id(expr2);
502 isl_id_free(id1);
503 isl_id_free(id2);
504 if (!id1 || !id2)
505 return 0;
506 if (id1 != id2)
507 return 0;
509 access1 = pet_expr_access_get_access(expr1);
510 access2 = pet_expr_access_get_access(expr2);
511 is_subset = isl_map_is_subset(access1, access2);
512 isl_map_free(access1);
513 isl_map_free(access2);
515 return is_subset;
518 /* Mark self dependences among the arguments of "expr" starting at "first".
519 * These arguments have already been added to the list of arguments
520 * but are not yet referenced directly from the index expression.
521 * Instead, they are still referenced through parameters encoding
522 * nested accesses.
524 * In particular, if "expr" is a read access, then check the arguments
525 * starting at "first" to see if "expr" accesses a subset of
526 * the elements accessed by the argument, or under more restrictive conditions.
527 * If so, then this nested access can be removed from the constraints
528 * governing the outer access. There is no point in restricting
529 * accesses to an array if in order to evaluate the restriction,
530 * we have to access the same elements (or more).
532 * Rather than removing the argument at this point (which would
533 * complicate the resolution of the other nested accesses), we simply
534 * mark it here by replacing it by a NaN pet_expr.
535 * These NaNs are then later removed in remove_marked_self_dependences.
537 static __isl_give pet_expr *mark_self_dependences(__isl_take pet_expr *expr,
538 int first)
540 int i, n;
542 if (pet_expr_access_is_write(expr))
543 return expr;
545 n = pet_expr_get_n_arg(expr);
546 for (i = first; i < n; ++i) {
547 int mark;
548 pet_expr *arg;
550 arg = pet_expr_get_arg(expr, i);
551 mark = is_sub_access(expr, arg, first);
552 pet_expr_free(arg);
553 if (mark < 0)
554 return pet_expr_free(expr);
555 if (!mark)
556 continue;
558 arg = pet_expr_new_int(isl_val_nan(pet_expr_get_ctx(expr)));
559 expr = pet_expr_set_arg(expr, i, arg);
562 return expr;
565 /* Is "expr" a NaN integer expression?
567 static int expr_is_nan(__isl_keep pet_expr *expr)
569 isl_val *v;
570 int is_nan;
572 if (pet_expr_get_type(expr) != pet_expr_int)
573 return 0;
575 v = pet_expr_int_get_val(expr);
576 is_nan = isl_val_is_nan(v);
577 isl_val_free(v);
579 return is_nan;
582 /* Check if we have marked any self dependences (as NaNs)
583 * in mark_self_dependences and remove them here.
584 * It is safe to project them out since these arguments
585 * can at most be referenced from the condition of the access relation,
586 * but do not appear in the index expression.
587 * "dim" is the dimension of the iteration domain.
589 static __isl_give pet_expr *remove_marked_self_dependences(
590 __isl_take pet_expr *expr, int dim, int first)
592 int i, n;
594 n = pet_expr_get_n_arg(expr);
595 for (i = n - 1; i >= first; --i) {
596 int is_nan;
597 pet_expr *arg;
599 arg = pet_expr_get_arg(expr, i);
600 is_nan = expr_is_nan(arg);
601 pet_expr_free(arg);
602 if (!is_nan)
603 continue;
604 expr = pet_expr_access_project_out_arg(expr, dim, i);
607 return expr;
610 /* Look for parameters in any access relation in "expr" that
611 * refer to nested accesses. In particular, these are
612 * parameters with name "__pet_expr".
614 * If there are any such parameters, then the domain of the index
615 * expression and the access relation, which is either "domain" or
616 * [domain -> [a_1,...,a_m]] at this point, is replaced by
617 * [domain -> [t_1,...,t_n]] or [domain -> [a_1,...,a_m,t_1,...,t_n]],
618 * with m the original number of arguments (n_arg) and
619 * n the number of these parameters
620 * (after identifying identical nested accesses).
622 * This transformation is performed in several steps.
623 * We first extract the arguments in pet_expr_extract_nested.
624 * param2pos maps the original parameter position to the position
625 * of the argument beyond the initial (n_arg) number of arguments.
626 * Then we move these parameters to input dimensions.
627 * t2pos maps the positions of these temporary input dimensions
628 * to the positions of the corresponding arguments inside the space
629 * [domain -> [t_1,...,t_n]].
630 * Finally, we express these temporary dimensions in terms of the domain
631 * [domain -> [a_1,...,a_m,t_1,...,t_n]] and precompose index expression and
632 * access relations with this function.
634 __isl_give pet_expr *pet_expr_resolve_nested(__isl_take pet_expr *expr,
635 __isl_keep isl_space *domain)
637 int i, n, n_arg, dim, n_in;
638 int nparam;
639 isl_ctx *ctx;
640 isl_space *space;
641 isl_local_space *ls;
642 isl_aff *aff;
643 isl_multi_aff *ma;
644 int *param2pos;
645 int *t2pos;
647 if (!expr)
648 return expr;
650 n_arg = pet_expr_get_n_arg(expr);
651 for (i = 0; i < n_arg; ++i) {
652 pet_expr *arg;
653 arg = pet_expr_get_arg(expr, i);
654 arg = pet_expr_resolve_nested(arg, domain);
655 expr = pet_expr_set_arg(expr, i, arg);
658 if (pet_expr_get_type(expr) != pet_expr_access)
659 return expr;
661 dim = isl_space_dim(domain, isl_dim_set);
662 n_in = dim + n_arg;
664 space = pet_expr_access_get_parameter_space(expr);
665 n = pet_nested_n_in_space(space);
666 isl_space_free(space);
667 if (n == 0)
668 return expr;
670 expr = pet_expr_access_align_params(expr);
671 if (!expr)
672 return NULL;
674 space = pet_expr_access_get_parameter_space(expr);
675 nparam = isl_space_dim(space, isl_dim_param);
676 isl_space_free(space);
678 ctx = pet_expr_get_ctx(expr);
680 param2pos = isl_alloc_array(ctx, int, nparam);
681 t2pos = isl_alloc_array(ctx, int, n);
682 if (!param2pos)
683 goto error;
684 expr = pet_expr_extract_nested(expr, n, param2pos);
685 expr = mark_self_dependences(expr, n_arg);
686 if (!expr)
687 goto error;
689 n = 0;
690 space = pet_expr_access_get_parameter_space(expr);
691 nparam = isl_space_dim(space, isl_dim_param);
692 for (i = nparam - 1; i >= 0; --i) {
693 isl_id *id = isl_space_get_dim_id(space, isl_dim_param, i);
694 if (!pet_nested_in_id(id)) {
695 isl_id_free(id);
696 continue;
699 expr = pet_expr_access_move_dims(expr,
700 isl_dim_in, n_in + n, isl_dim_param, i, 1);
701 t2pos[n] = n_in + param2pos[i];
702 n++;
704 isl_id_free(id);
706 isl_space_free(space);
708 space = isl_space_copy(domain);
709 space = isl_space_from_domain(space);
710 space = isl_space_add_dims(space, isl_dim_out,
711 pet_expr_get_n_arg(expr));
712 space = isl_space_wrap(space);
713 ls = isl_local_space_from_space(isl_space_copy(space));
714 space = isl_space_from_domain(space);
715 space = isl_space_add_dims(space, isl_dim_out, n_in + n);
716 ma = isl_multi_aff_zero(space);
718 for (i = 0; i < n_in; ++i) {
719 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
720 isl_dim_set, i);
721 ma = isl_multi_aff_set_aff(ma, i, aff);
723 for (i = 0; i < n; ++i) {
724 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
725 isl_dim_set, t2pos[i]);
726 ma = isl_multi_aff_set_aff(ma, n_in + i, aff);
728 isl_local_space_free(ls);
730 expr = pet_expr_access_pullback_multi_aff(expr, ma);
732 expr = remove_marked_self_dependences(expr, dim, n_arg);
734 free(t2pos);
735 free(param2pos);
736 return expr;
737 error:
738 free(t2pos);
739 free(param2pos);
740 return pet_expr_free(expr);
743 /* Wrapper around pet_expr_resolve_nested
744 * for use as a callback to pet_tree_map_expr.
746 static __isl_give pet_expr *resolve_nested(__isl_take pet_expr *expr,
747 void *user)
749 isl_space *space = user;
751 return pet_expr_resolve_nested(expr, space);
754 /* Call pet_expr_resolve_nested on each of the expressions in "tree".
756 __isl_give pet_tree *pet_tree_resolve_nested(__isl_take pet_tree *tree,
757 __isl_keep isl_space *space)
759 return pet_tree_map_expr(tree, &resolve_nested, space);
762 /* For each nested access parameter in the domain of "stmt",
763 * construct a corresponding pet_expr, place it before the original
764 * elements in stmt->args and record its position in "param2pos".
765 * n is the number of nested access parameters.
767 struct pet_stmt *pet_stmt_extract_nested(struct pet_stmt *stmt, int n,
768 int *param2pos)
770 int i;
771 isl_ctx *ctx;
772 isl_space *space;
773 int n_arg;
774 pet_expr **args;
776 ctx = isl_set_get_ctx(stmt->domain);
778 n_arg = stmt->n_arg;
779 args = isl_calloc_array(ctx, pet_expr *, n + n_arg);
780 if (!args)
781 goto error;
783 space = isl_set_get_space(stmt->domain);
784 if (isl_space_is_wrapping(space))
785 space = isl_space_domain(isl_space_unwrap(space));
786 n_arg = pet_extract_nested_from_space(space, 0, args, param2pos);
787 isl_space_free(space);
789 if (n_arg < 0)
790 goto error;
792 for (i = 0; i < stmt->n_arg; ++i)
793 args[n_arg + i] = stmt->args[i];
794 free(stmt->args);
795 stmt->args = args;
796 stmt->n_arg += n_arg;
798 return stmt;
799 error:
800 if (args) {
801 for (i = 0; i < n; ++i)
802 pet_expr_free(args[i]);
803 free(args);
805 pet_stmt_free(stmt);
806 return NULL;
809 /* Check whether any of the arguments i of "stmt" starting at position "n"
810 * is equal to one of the first "n" arguments j.
811 * If so, combine the constraints on arguments i and j and remove
812 * argument i.
814 static struct pet_stmt *remove_duplicate_arguments(struct pet_stmt *stmt, int n)
816 int i, j;
817 isl_map *map;
819 if (!stmt)
820 return NULL;
821 if (n == 0)
822 return stmt;
823 if (n == stmt->n_arg)
824 return stmt;
826 map = isl_set_unwrap(stmt->domain);
828 for (i = stmt->n_arg - 1; i >= n; --i) {
829 for (j = 0; j < n; ++j)
830 if (pet_expr_is_equal(stmt->args[i], stmt->args[j]))
831 break;
832 if (j >= n)
833 continue;
835 map = isl_map_equate(map, isl_dim_out, i, isl_dim_out, j);
836 map = isl_map_project_out(map, isl_dim_out, i, 1);
838 pet_expr_free(stmt->args[i]);
839 for (j = i; j + 1 < stmt->n_arg; ++j)
840 stmt->args[j] = stmt->args[j + 1];
841 stmt->n_arg--;
844 stmt->domain = isl_map_wrap(map);
845 if (!stmt->domain)
846 goto error;
847 return stmt;
848 error:
849 pet_stmt_free(stmt);
850 return NULL;
853 /* Look for parameters in the iteration domain of "stmt" that
854 * refer to nested accesses. In particular, these are
855 * parameters with name "__pet_expr".
857 * If there are any such parameters, then as many extra variables
858 * (after identifying identical nested accesses) are inserted in the
859 * range of the map wrapped inside the domain, before the original variables.
860 * If the original domain is not a wrapped map, then a new wrapped
861 * map is created with zero output dimensions.
862 * The parameters are then equated to the corresponding output dimensions
863 * and subsequently projected out, from the iteration domain,
864 * the schedule and the access relations.
865 * For each of the output dimensions, a corresponding argument
866 * expression is inserted, embedded in the current iteration domain.
867 * param2pos maps the position of the parameter to the position
868 * of the corresponding output dimension in the wrapped map.
870 struct pet_stmt *pet_stmt_resolve_nested(struct pet_stmt *stmt)
872 int i, n;
873 int pos;
874 int nparam;
875 unsigned n_arg;
876 isl_ctx *ctx;
877 isl_map *map;
878 isl_space *space;
879 isl_multi_aff *ma;
880 int *param2pos;
882 if (!stmt)
883 return NULL;
885 n = pet_nested_n_in_set(stmt->domain);
886 if (n == 0)
887 return stmt;
889 ctx = isl_set_get_ctx(stmt->domain);
891 n_arg = stmt->n_arg;
892 nparam = isl_set_dim(stmt->domain, isl_dim_param);
893 param2pos = isl_alloc_array(ctx, int, nparam);
894 stmt = pet_stmt_extract_nested(stmt, n, param2pos);
895 if (!stmt) {
896 free(param2pos);
897 return NULL;
900 n = stmt->n_arg - n_arg;
901 if (isl_set_is_wrapping(stmt->domain))
902 map = isl_set_unwrap(stmt->domain);
903 else
904 map = isl_map_from_domain(stmt->domain);
905 map = isl_map_insert_dims(map, isl_dim_out, 0, n);
907 for (i = nparam - 1; i >= 0; --i) {
908 isl_id *id;
910 if (!pet_nested_in_map(map, i))
911 continue;
913 id = pet_expr_access_get_id(stmt->args[param2pos[i]]);
914 map = isl_map_set_dim_id(map, isl_dim_out, param2pos[i], id);
915 map = isl_map_equate(map, isl_dim_param, i, isl_dim_out,
916 param2pos[i]);
917 map = isl_map_project_out(map, isl_dim_param, i, 1);
920 stmt->domain = isl_map_wrap(map);
922 stmt = pet_stmt_remove_nested_parameters(stmt);
923 stmt = remove_duplicate_arguments(stmt, n);
925 free(param2pos);
926 return stmt;
929 /* For each statement in "scop", move the parameters that correspond
930 * to nested access into the ranges of the domains and create
931 * corresponding argument expressions.
933 struct pet_scop *pet_scop_resolve_nested(struct pet_scop *scop)
935 int i;
937 if (!scop)
938 return NULL;
940 for (i = 0; i < scop->n_stmt; ++i) {
941 scop->stmts[i] = pet_stmt_resolve_nested(scop->stmts[i]);
942 if (!scop->stmts[i])
943 return pet_scop_free(scop);
946 return scop;