pet_tree_dump: fix typo in output
[pet.git] / nest.c
blob45ca26763a7a2076b11bb916fce301b4d53f0bd7
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 parameter "pos" of "umap" refer to a nested access?
131 static int pet_nested_in_union_map(__isl_keep isl_union_map *umap, int pos)
133 int nested;
134 isl_id *id;
136 id = isl_union_map_get_dim_id(umap, isl_dim_param, pos);
137 nested = pet_nested_in_id(id);
138 isl_id_free(id);
140 return nested;
143 /* Does "space" involve any parameters that refer to nested accesses?
145 int pet_nested_any_in_space(__isl_keep isl_space *space)
147 int i;
148 int nparam;
150 nparam = isl_space_dim(space, isl_dim_param);
151 for (i = 0; i < nparam; ++i)
152 if (pet_nested_in_space(space, i))
153 return 1;
155 return 0;
158 /* Does "pa" involve any parameters that refer to nested accesses?
160 int pet_nested_any_in_pw_aff(__isl_keep isl_pw_aff *pa)
162 isl_space *space;
163 int nested;
165 space = isl_pw_aff_get_space(pa);
166 nested = pet_nested_any_in_space(space);
167 isl_space_free(space);
169 return nested;
172 /* How many parameters of "space" refer to nested accesses?
174 int pet_nested_n_in_space(__isl_keep isl_space *space)
176 int i, n = 0;
177 int nparam;
179 nparam = isl_space_dim(space, isl_dim_param);
180 for (i = 0; i < nparam; ++i)
181 if (pet_nested_in_space(space, i))
182 ++n;
184 return n;
187 /* How many parameters of "map" refer to nested accesses?
189 int pet_nested_n_in_map(__isl_keep isl_map *map)
191 isl_space *space;
192 int n;
194 space = isl_map_get_space(map);
195 n = pet_nested_n_in_space(space);
196 isl_space_free(space);
198 return n;
201 /* How many parameters of "set" refer to nested accesses?
203 int pet_nested_n_in_set(__isl_keep isl_set *set)
205 isl_space *space;
206 int n;
208 space = isl_set_get_space(set);
209 n = pet_nested_n_in_space(space);
210 isl_space_free(space);
212 return n;
215 /* Remove all parameters from "space" that refer to nested accesses.
217 __isl_give isl_space *pet_nested_remove_from_space(__isl_take isl_space *space)
219 int i;
220 int nparam;
222 nparam = isl_space_dim(space, isl_dim_param);
223 for (i = nparam - 1; i >= 0; --i)
224 if (pet_nested_in_space(space, i))
225 space = isl_space_drop_dims(space, isl_dim_param, i, 1);
227 return space;
230 /* Remove all parameters from "set" that refer to nested accesses.
232 __isl_give isl_set *pet_nested_remove_from_set(__isl_take isl_set *set)
234 int i;
235 int nparam;
237 nparam = isl_set_dim(set, isl_dim_param);
238 for (i = nparam - 1; i >= 0; --i)
239 if (pet_nested_in_set(set, i))
240 set = isl_set_project_out(set, isl_dim_param, i, 1);
242 return set;
245 /* Remove all parameters from "map" that refer to nested accesses.
247 static __isl_give isl_map *pet_nested_remove_from_map(__isl_take isl_map *map)
249 int i;
250 int nparam;
252 nparam = isl_map_dim(map, isl_dim_param);
253 for (i = nparam - 1; i >= 0; --i)
254 if (pet_nested_in_map(map, i))
255 map = isl_map_project_out(map, isl_dim_param, i, 1);
257 return map;
260 /* Remove all parameters from "umap" that refer to nested accesses.
262 static __isl_give isl_union_map *pet_nested_remove_from_union_map(
263 __isl_take isl_union_map *umap)
265 int i;
266 int nparam;
268 nparam = isl_union_map_dim(umap, isl_dim_param);
269 for (i = nparam - 1; i >= 0; --i)
270 if (pet_nested_in_union_map(umap, i))
271 umap = isl_union_map_project_out(umap,
272 isl_dim_param, i, 1);
274 return umap;
277 /* Remove all parameters from "mpa" that refer to nested accesses.
279 static __isl_give isl_multi_pw_aff *pet_nested_remove_from_multi_pw_aff(
280 __isl_take isl_multi_pw_aff *mpa)
282 int i;
283 int nparam;
284 isl_space *space;
286 space = isl_multi_pw_aff_get_space(mpa);
287 nparam = isl_space_dim(space, isl_dim_param);
288 for (i = nparam - 1; i >= 0; --i) {
289 if (!pet_nested_in_space(space, i))
290 continue;
291 mpa = isl_multi_pw_aff_drop_dims(mpa, isl_dim_param, i, 1);
293 isl_space_free(space);
295 return mpa;
298 /* Remove all parameters from the index expression and
299 * access relations of "expr" that refer to nested accesses.
301 static __isl_give pet_expr *expr_remove_nested_parameters(
302 __isl_take pet_expr *expr, void *user)
304 enum pet_expr_access_type type;
306 expr = pet_expr_cow(expr);
307 if (!expr)
308 return NULL;
310 for (type = pet_expr_access_begin; type < pet_expr_access_end; ++type) {
311 if (!expr->acc.access[type])
312 continue;
313 expr->acc.access[type] =
314 pet_nested_remove_from_union_map(expr->acc.access[type]);
315 if (!expr->acc.access[type])
316 break;
318 expr->acc.index = pet_nested_remove_from_multi_pw_aff(expr->acc.index);
319 if (type < pet_expr_access_end || !expr->acc.index)
320 return pet_expr_free(expr);
322 return expr;
325 /* Remove all nested access parameters from the schedule and all
326 * accesses of "stmt".
327 * There is no need to remove them from the domain as these parameters
328 * have already been removed from the domain when this function is called.
330 struct pet_stmt *pet_stmt_remove_nested_parameters(struct pet_stmt *stmt)
332 int i;
334 if (!stmt)
335 return NULL;
336 stmt->schedule = pet_nested_remove_from_map(stmt->schedule);
337 stmt->body = pet_tree_map_access_expr(stmt->body,
338 &expr_remove_nested_parameters, NULL);
339 if (!stmt->schedule || !stmt->body)
340 goto error;
341 for (i = 0; i < stmt->n_arg; ++i) {
342 stmt->args[i] = pet_expr_map_access(stmt->args[i],
343 &expr_remove_nested_parameters, NULL);
344 if (!stmt->args[i])
345 goto error;
348 return stmt;
349 error:
350 pet_stmt_free(stmt);
351 return NULL;
354 /* Set *dim to the dimension of the domain of the access expression "expr" and
355 * abort the search.
357 static int set_dim(__isl_keep pet_expr *expr, void *user)
359 int *dim = user;
360 isl_space *space;
362 space = pet_expr_access_get_domain_space(expr);
363 *dim = isl_space_dim(space, isl_dim_set);
364 isl_space_free(space);
366 return -1;
369 /* Determine the dimension of the domain of the access expressions in "expr".
371 * In particular, return the dimension of the domain of the first access
372 * expression in "expr" as all access expressions should have the same
373 * domain.
375 * If "expr" does not contain any access expressions, then we return 0.
377 static int pet_expr_domain_dim(__isl_keep pet_expr *expr)
379 int dim = -1;
381 if (pet_expr_foreach_access_expr(expr, &set_dim, &dim) >= 0)
382 return 0;
384 return dim;
387 /* Embed all access expressions in "expr" in the domain "space".
388 * The initial domain of the access expressions
389 * is an anonymous domain of a dimension that may be lower
390 * than the dimension of "space".
391 * We may therefore need to introduce extra dimensions as well as
392 * (potentially) the name of "space".
394 static __isl_give pet_expr *embed(__isl_take pet_expr *expr,
395 __isl_keep isl_space *space)
397 int n;
398 isl_multi_pw_aff *mpa;
400 n = pet_expr_domain_dim(expr);
401 if (n < 0)
402 return pet_expr_free(expr);
404 space = isl_space_copy(space);
405 mpa = isl_multi_pw_aff_from_multi_aff(pet_prefix_projection(space, n));
406 expr = pet_expr_update_domain(expr, mpa);
408 return expr;
411 /* For each nested access parameter in "space",
412 * construct a corresponding pet_expr, place it in args and
413 * record its position in "param2pos".
414 * The constructed pet_expr objects are embedded in "space"
415 * (with the nested access parameters removed).
416 * "n_arg" is the number of elements that are already in args.
417 * The position recorded in "param2pos" takes this number into account.
418 * If the pet_expr corresponding to a parameter is identical to
419 * the pet_expr corresponding to an earlier parameter, then these two
420 * parameters are made to refer to the same element in args.
422 * Return the final number of elements in args or -1 if an error has occurred.
424 int pet_extract_nested_from_space(__isl_keep isl_space *space,
425 int n_arg, __isl_give pet_expr **args, int *param2pos)
427 int i, nparam;
428 isl_space *domain;
430 domain = isl_space_copy(space);
431 domain = pet_nested_remove_from_space(domain);
432 nparam = isl_space_dim(space, isl_dim_param);
433 for (i = 0; i < nparam; ++i) {
434 int j;
435 isl_id *id = isl_space_get_dim_id(space, isl_dim_param, i);
437 if (!pet_nested_in_id(id)) {
438 isl_id_free(id);
439 continue;
442 args[n_arg] = embed(pet_nested_extract_expr(id), domain);
443 isl_id_free(id);
444 if (!args[n_arg])
445 return -1;
447 for (j = 0; j < n_arg; ++j)
448 if (pet_expr_is_equal(args[j], args[n_arg]))
449 break;
451 if (j < n_arg) {
452 pet_expr_free(args[n_arg]);
453 args[n_arg] = NULL;
454 param2pos[i] = j;
455 } else
456 param2pos[i] = n_arg++;
458 isl_space_free(domain);
460 return n_arg;
463 /* For each nested access parameter in the access relations in "expr",
464 * construct a corresponding pet_expr, append it to the arguments of "expr"
465 * and record its position in "param2pos" (relative to the initial
466 * number of arguments).
467 * n is the number of nested access parameters.
469 __isl_give pet_expr *pet_expr_extract_nested(__isl_take pet_expr *expr, int n,
470 int *param2pos)
472 isl_ctx *ctx;
473 isl_space *space;
474 int i, n_arg;
475 pet_expr **args;
477 ctx = pet_expr_get_ctx(expr);
478 args = isl_calloc_array(ctx, pet_expr *, n);
479 if (!args)
480 return pet_expr_free(expr);
482 n_arg = pet_expr_get_n_arg(expr);
483 space = pet_expr_access_get_domain_space(expr);
484 n = pet_extract_nested_from_space(space, 0, args, param2pos);
485 isl_space_free(space);
487 if (n < 0)
488 expr = pet_expr_free(expr);
489 else
490 expr = pet_expr_set_n_arg(expr, n_arg + n);
492 for (i = 0; i < n; ++i)
493 expr = pet_expr_set_arg(expr, n_arg + i, args[i]);
494 free(args);
496 return expr;
499 /* Mark self dependences among the arguments of "expr" starting at "first".
500 * These arguments have already been added to the list of arguments
501 * but are not yet referenced directly from the index expression.
502 * Instead, they are still referenced through parameters encoding
503 * nested accesses.
505 * In particular, if "expr" is a read access, then check the arguments
506 * starting at "first" to see if "expr" accesses a subset of
507 * the elements accessed by the argument, or under more restrictive conditions.
508 * If so, then this nested access can be removed from the constraints
509 * governing the outer access. There is no point in restricting
510 * accesses to an array if in order to evaluate the restriction,
511 * we have to access the same elements (or more).
513 * Rather than removing the argument at this point (which would
514 * complicate the resolution of the other nested accesses), we simply
515 * mark it here by replacing it by a NaN pet_expr.
516 * These NaNs are then later removed in remove_marked_self_dependences.
518 static __isl_give pet_expr *mark_self_dependences(__isl_take pet_expr *expr,
519 int first)
521 int i, n;
523 if (pet_expr_access_is_write(expr))
524 return expr;
526 n = pet_expr_get_n_arg(expr);
527 for (i = first; i < n; ++i) {
528 int mark;
529 pet_expr *arg;
531 arg = pet_expr_get_arg(expr, i);
532 mark = pet_expr_is_sub_access(expr, arg, first);
533 pet_expr_free(arg);
534 if (mark < 0)
535 return pet_expr_free(expr);
536 if (!mark)
537 continue;
539 arg = pet_expr_new_int(isl_val_nan(pet_expr_get_ctx(expr)));
540 expr = pet_expr_set_arg(expr, i, arg);
543 return expr;
546 /* Is "expr" a NaN integer expression?
548 static int expr_is_nan(__isl_keep pet_expr *expr)
550 isl_val *v;
551 int is_nan;
553 if (pet_expr_get_type(expr) != pet_expr_int)
554 return 0;
556 v = pet_expr_int_get_val(expr);
557 is_nan = isl_val_is_nan(v);
558 isl_val_free(v);
560 return is_nan;
563 /* Check if we have marked any self dependences (as NaNs)
564 * in mark_self_dependences and remove them here.
565 * It is safe to project them out since these arguments
566 * can at most be referenced from the condition of the access relation,
567 * but do not appear in the index expression.
568 * "dim" is the dimension of the iteration domain.
570 static __isl_give pet_expr *remove_marked_self_dependences(
571 __isl_take pet_expr *expr, int dim, int first)
573 int i, n;
575 n = pet_expr_get_n_arg(expr);
576 for (i = n - 1; i >= first; --i) {
577 int is_nan;
578 pet_expr *arg;
580 arg = pet_expr_get_arg(expr, i);
581 is_nan = expr_is_nan(arg);
582 pet_expr_free(arg);
583 if (!is_nan)
584 continue;
585 expr = pet_expr_access_project_out_arg(expr, dim, i);
588 return expr;
591 /* Look for parameters in any access relation in "expr" that
592 * refer to nested accesses. In particular, these are
593 * parameters with name "__pet_expr".
595 * If there are any such parameters, then the domain of the index
596 * expression and the access relation, which is either "domain" or
597 * [domain -> [a_1,...,a_m]] at this point, is replaced by
598 * [domain -> [t_1,...,t_n]] or [domain -> [a_1,...,a_m,t_1,...,t_n]],
599 * with m the original number of arguments (n_arg) and
600 * n the number of these parameters
601 * (after identifying identical nested accesses).
603 * This transformation is performed in several steps.
604 * We first extract the arguments in pet_expr_extract_nested.
605 * param2pos maps the original parameter position to the position
606 * of the argument beyond the initial (n_arg) number of arguments.
607 * Then we move these parameters to input dimensions.
608 * t2pos maps the positions of these temporary input dimensions
609 * to the positions of the corresponding arguments inside the space
610 * [domain -> [t_1,...,t_n]].
611 * Finally, we express these temporary dimensions in terms of the domain
612 * [domain -> [a_1,...,a_m,t_1,...,t_n]] and precompose index expression and
613 * access relations with this function.
615 __isl_give pet_expr *pet_expr_resolve_nested(__isl_take pet_expr *expr,
616 __isl_keep isl_space *domain)
618 int i, n, n_arg, dim, n_in;
619 int nparam;
620 isl_ctx *ctx;
621 isl_space *space;
622 isl_local_space *ls;
623 isl_aff *aff;
624 isl_multi_aff *ma;
625 int *param2pos;
626 int *t2pos;
628 if (!expr)
629 return expr;
631 n_arg = pet_expr_get_n_arg(expr);
632 for (i = 0; i < n_arg; ++i) {
633 pet_expr *arg;
634 arg = pet_expr_get_arg(expr, i);
635 arg = pet_expr_resolve_nested(arg, domain);
636 expr = pet_expr_set_arg(expr, i, arg);
639 if (pet_expr_get_type(expr) != pet_expr_access)
640 return expr;
642 dim = isl_space_dim(domain, isl_dim_set);
643 n_in = dim + n_arg;
645 space = pet_expr_access_get_parameter_space(expr);
646 n = pet_nested_n_in_space(space);
647 isl_space_free(space);
648 if (n == 0)
649 return expr;
651 expr = pet_expr_access_align_params(expr);
652 if (!expr)
653 return NULL;
655 space = pet_expr_access_get_parameter_space(expr);
656 nparam = isl_space_dim(space, isl_dim_param);
657 isl_space_free(space);
659 ctx = pet_expr_get_ctx(expr);
661 param2pos = isl_alloc_array(ctx, int, nparam);
662 t2pos = isl_alloc_array(ctx, int, n);
663 if (!param2pos)
664 goto error;
665 expr = pet_expr_extract_nested(expr, n, param2pos);
666 expr = mark_self_dependences(expr, n_arg);
667 if (!expr)
668 goto error;
670 n = 0;
671 space = pet_expr_access_get_parameter_space(expr);
672 nparam = isl_space_dim(space, isl_dim_param);
673 for (i = nparam - 1; i >= 0; --i) {
674 isl_id *id = isl_space_get_dim_id(space, isl_dim_param, i);
675 if (!pet_nested_in_id(id)) {
676 isl_id_free(id);
677 continue;
680 expr = pet_expr_access_move_dims(expr,
681 isl_dim_in, n_in + n, isl_dim_param, i, 1);
682 t2pos[n] = n_in + param2pos[i];
683 n++;
685 isl_id_free(id);
687 isl_space_free(space);
689 space = isl_space_copy(domain);
690 space = isl_space_from_domain(space);
691 space = isl_space_add_dims(space, isl_dim_out,
692 pet_expr_get_n_arg(expr));
693 space = isl_space_wrap(space);
694 ls = isl_local_space_from_space(isl_space_copy(space));
695 space = isl_space_from_domain(space);
696 space = isl_space_add_dims(space, isl_dim_out, n_in + n);
697 ma = isl_multi_aff_zero(space);
699 for (i = 0; i < n_in; ++i) {
700 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
701 isl_dim_set, i);
702 ma = isl_multi_aff_set_aff(ma, i, aff);
704 for (i = 0; i < n; ++i) {
705 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
706 isl_dim_set, t2pos[i]);
707 ma = isl_multi_aff_set_aff(ma, n_in + i, aff);
709 isl_local_space_free(ls);
711 expr = pet_expr_access_pullback_multi_aff(expr, ma);
713 expr = remove_marked_self_dependences(expr, dim, n_arg);
715 free(t2pos);
716 free(param2pos);
717 return expr;
718 error:
719 free(t2pos);
720 free(param2pos);
721 return pet_expr_free(expr);
724 /* Wrapper around pet_expr_resolve_nested
725 * for use as a callback to pet_tree_map_expr.
727 static __isl_give pet_expr *resolve_nested(__isl_take pet_expr *expr,
728 void *user)
730 isl_space *space = user;
732 return pet_expr_resolve_nested(expr, space);
735 /* Call pet_expr_resolve_nested on each of the expressions in "tree".
737 __isl_give pet_tree *pet_tree_resolve_nested(__isl_take pet_tree *tree,
738 __isl_keep isl_space *space)
740 return pet_tree_map_expr(tree, &resolve_nested, space);
743 /* For each nested access parameter in the domain of "stmt",
744 * construct a corresponding pet_expr, place it before the original
745 * elements in stmt->args and record its position in "param2pos".
746 * n is the number of nested access parameters.
748 struct pet_stmt *pet_stmt_extract_nested(struct pet_stmt *stmt, int n,
749 int *param2pos)
751 int i;
752 isl_ctx *ctx;
753 isl_space *space;
754 int n_arg;
755 pet_expr **args;
757 ctx = isl_set_get_ctx(stmt->domain);
759 n_arg = stmt->n_arg;
760 args = isl_calloc_array(ctx, pet_expr *, n + n_arg);
761 if (!args)
762 goto error;
764 space = isl_set_get_space(stmt->domain);
765 if (isl_space_is_wrapping(space))
766 space = isl_space_domain(isl_space_unwrap(space));
767 n_arg = pet_extract_nested_from_space(space, 0, args, param2pos);
768 isl_space_free(space);
770 if (n_arg < 0)
771 goto error;
773 for (i = 0; i < stmt->n_arg; ++i)
774 args[n_arg + i] = stmt->args[i];
775 free(stmt->args);
776 stmt->args = args;
777 stmt->n_arg += n_arg;
779 return stmt;
780 error:
781 if (args) {
782 for (i = 0; i < n; ++i)
783 pet_expr_free(args[i]);
784 free(args);
786 pet_stmt_free(stmt);
787 return NULL;
790 /* Check whether any of the arguments i of "stmt" starting at position "n"
791 * is equal to one of the first "n" arguments j.
792 * If so, combine the constraints on arguments i and j and remove
793 * argument i.
795 static struct pet_stmt *remove_duplicate_arguments(struct pet_stmt *stmt, int n)
797 int i, j;
798 isl_map *map;
800 if (!stmt)
801 return NULL;
802 if (n == 0)
803 return stmt;
804 if (n == stmt->n_arg)
805 return stmt;
807 map = isl_set_unwrap(stmt->domain);
809 for (i = stmt->n_arg - 1; i >= n; --i) {
810 for (j = 0; j < n; ++j)
811 if (pet_expr_is_equal(stmt->args[i], stmt->args[j]))
812 break;
813 if (j >= n)
814 continue;
816 map = isl_map_equate(map, isl_dim_out, i, isl_dim_out, j);
817 map = isl_map_project_out(map, isl_dim_out, i, 1);
819 pet_expr_free(stmt->args[i]);
820 for (j = i; j + 1 < stmt->n_arg; ++j)
821 stmt->args[j] = stmt->args[j + 1];
822 stmt->n_arg--;
825 stmt->domain = isl_map_wrap(map);
826 if (!stmt->domain)
827 goto error;
828 return stmt;
829 error:
830 pet_stmt_free(stmt);
831 return NULL;
834 /* Look for parameters in the iteration domain of "stmt" that
835 * refer to nested accesses. In particular, these are
836 * parameters with name "__pet_expr".
838 * If there are any such parameters, then as many extra variables
839 * (after identifying identical nested accesses) are inserted in the
840 * range of the map wrapped inside the domain, before the original variables.
841 * If the original domain is not a wrapped map, then a new wrapped
842 * map is created with zero output dimensions.
843 * The parameters are then equated to the corresponding output dimensions
844 * and subsequently projected out, from the iteration domain,
845 * the schedule and the access relations.
846 * For each of the output dimensions, a corresponding argument
847 * expression is inserted, embedded in the current iteration domain.
848 * param2pos maps the position of the parameter to the position
849 * of the corresponding output dimension in the wrapped map.
851 struct pet_stmt *pet_stmt_resolve_nested(struct pet_stmt *stmt)
853 int i, n;
854 int pos;
855 int nparam;
856 unsigned n_arg;
857 isl_ctx *ctx;
858 isl_map *map;
859 isl_space *space;
860 isl_multi_aff *ma;
861 int *param2pos;
863 if (!stmt)
864 return NULL;
866 n = pet_nested_n_in_set(stmt->domain);
867 if (n == 0)
868 return stmt;
870 ctx = isl_set_get_ctx(stmt->domain);
872 n_arg = stmt->n_arg;
873 nparam = isl_set_dim(stmt->domain, isl_dim_param);
874 param2pos = isl_alloc_array(ctx, int, nparam);
875 stmt = pet_stmt_extract_nested(stmt, n, param2pos);
876 if (!stmt) {
877 free(param2pos);
878 return NULL;
881 n = stmt->n_arg - n_arg;
882 if (isl_set_is_wrapping(stmt->domain))
883 map = isl_set_unwrap(stmt->domain);
884 else
885 map = isl_map_from_domain(stmt->domain);
886 map = isl_map_insert_dims(map, isl_dim_out, 0, n);
888 for (i = nparam - 1; i >= 0; --i) {
889 isl_id *id;
891 if (!pet_nested_in_map(map, i))
892 continue;
894 id = pet_expr_access_get_id(stmt->args[param2pos[i]]);
895 map = isl_map_set_dim_id(map, isl_dim_out, param2pos[i], id);
896 map = isl_map_equate(map, isl_dim_param, i, isl_dim_out,
897 param2pos[i]);
898 map = isl_map_project_out(map, isl_dim_param, i, 1);
901 stmt->domain = isl_map_wrap(map);
903 stmt = pet_stmt_remove_nested_parameters(stmt);
904 stmt = remove_duplicate_arguments(stmt, n);
906 free(param2pos);
907 return stmt;
910 /* For each statement in "scop", move the parameters that correspond
911 * to nested access into the ranges of the domains and create
912 * corresponding argument expressions.
914 struct pet_scop *pet_scop_resolve_nested(struct pet_scop *scop)
916 int i;
918 if (!scop)
919 return NULL;
921 for (i = 0; i < scop->n_stmt; ++i) {
922 scop->stmts[i] = pet_stmt_resolve_nested(scop->stmts[i]);
923 if (!scop->stmts[i])
924 return pet_scop_free(scop);
927 return scop;