pet_skip_info_if::extract: take index expression instead of access relation
[pet.git] / scop.c
blobfd062ba869208399804dc009cea232bca51bf0fe
1 /*
2 * Copyright 2011 Leiden University. All rights reserved.
3 * Copyright 2012-2013 Ecole Normale Superieure. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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.
33 */
35 #include <string.h>
36 #include <isl/constraint.h>
37 #include <isl/union_set.h>
39 #include "scop.h"
41 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
43 static char *type_str[] = {
44 [pet_expr_access] = "access",
45 [pet_expr_call] = "call",
46 [pet_expr_cast] = "cast",
47 [pet_expr_double] = "double",
48 [pet_expr_unary] = "unary",
49 [pet_expr_binary] = "binary",
50 [pet_expr_ternary] = "ternary"
53 static char *op_str[] = {
54 [pet_op_add_assign] = "+=",
55 [pet_op_sub_assign] = "-=",
56 [pet_op_mul_assign] = "*=",
57 [pet_op_div_assign] = "/=",
58 [pet_op_assign] = "=",
59 [pet_op_add] = "+",
60 [pet_op_sub] = "-",
61 [pet_op_mul] = "*",
62 [pet_op_div] = "/",
63 [pet_op_mod] = "%",
64 [pet_op_eq] = "==",
65 [pet_op_le] = "<=",
66 [pet_op_lt] = "<",
67 [pet_op_gt] = ">",
68 [pet_op_minus] = "-",
69 [pet_op_post_inc] = "++",
70 [pet_op_post_dec] = "--",
71 [pet_op_pre_inc] = "++",
72 [pet_op_pre_dec] = "--",
73 [pet_op_address_of] = "&",
74 [pet_op_kill] = "kill"
77 /* pet_scop with extra information that is only used during parsing.
79 * In particular, we keep track of conditions under which we want
80 * to skip the rest of the current loop iteration (skip[pet_skip_now])
81 * and of conditions under which we want to skip subsequent
82 * loop iterations (skip[pet_skip_later]).
84 * The conditions are represented either by a variable, which
85 * is assumed to attain values zero and one, or by a boolean affine
86 * expression. The condition holds if the variable has value one
87 * or if the affine expression has value one (typically for only
88 * part of the parameter space).
90 * A missing condition (skip[type] == NULL) means that we don't want
91 * to skip anything.
93 struct pet_scop_ext {
94 struct pet_scop scop;
96 isl_set *skip[2];
99 const char *pet_op_str(enum pet_op_type op)
101 return op_str[op];
104 int pet_op_is_inc_dec(enum pet_op_type op)
106 return op == pet_op_post_inc || op == pet_op_post_dec ||
107 op == pet_op_pre_inc || op == pet_op_pre_dec;
110 const char *pet_type_str(enum pet_expr_type type)
112 return type_str[type];
115 enum pet_op_type pet_str_op(const char *str)
117 int i;
119 for (i = 0; i < ARRAY_SIZE(op_str); ++i)
120 if (!strcmp(op_str[i], str))
121 return i;
123 return -1;
126 enum pet_expr_type pet_str_type(const char *str)
128 int i;
130 for (i = 0; i < ARRAY_SIZE(type_str); ++i)
131 if (!strcmp(type_str[i], str))
132 return i;
134 return -1;
137 /* Construct a pet_expr from an access relation.
138 * By default, it is considered to be a read access.
140 struct pet_expr *pet_expr_from_access(__isl_take isl_map *access)
142 isl_ctx *ctx = isl_map_get_ctx(access);
143 struct pet_expr *expr;
145 if (!access)
146 return NULL;
147 expr = isl_calloc_type(ctx, struct pet_expr);
148 if (!expr)
149 goto error;
151 expr->type = pet_expr_access;
152 expr->acc.access = access;
153 expr->acc.read = 1;
154 expr->acc.write = 0;
156 return expr;
157 error:
158 isl_map_free(access);
159 return NULL;
162 /* Construct an access pet_expr from an index expression.
163 * By default, the access is considered to be a read access.
165 struct pet_expr *pet_expr_from_index(__isl_take isl_multi_pw_aff *index)
167 isl_map *access;
169 access = isl_map_from_multi_pw_aff(index);
170 return pet_expr_from_access(access);
173 /* Construct an access pet_expr from an index expression and
174 * the depth of the accessed array.
175 * By default, the access is considered to be a read access.
177 * If the number of indices is smaller than the depth of the array,
178 * then we assume that all elements of the remaining dimensions
179 * are accessed.
181 struct pet_expr *pet_expr_from_index_and_depth(
182 __isl_take isl_multi_pw_aff *index, int depth)
184 isl_id *id;
185 isl_map *access;
186 int dim;
188 access = isl_map_from_multi_pw_aff(index);
189 if (!access)
190 return NULL;
191 dim = isl_map_dim(access, isl_dim_out);
192 if (dim > depth)
193 isl_die(isl_map_get_ctx(access), isl_error_internal,
194 "number of indices greater than depth",
195 access = isl_map_free(access));
196 if (dim == depth)
197 return pet_expr_from_access(access);
199 id = isl_map_get_tuple_id(access, isl_dim_out);
200 access = isl_map_add_dims(access, isl_dim_out, depth - dim);
201 access = isl_map_set_tuple_id(access, isl_dim_out, id);
203 return pet_expr_from_access(access);
206 /* Construct a pet_expr that kills the elements specified by "access".
208 struct pet_expr *pet_expr_kill_from_access(__isl_take isl_map *access)
210 isl_ctx *ctx;
211 struct pet_expr *expr;
213 ctx = isl_map_get_ctx(access);
214 expr = pet_expr_from_access(access);
215 if (!expr)
216 return NULL;
217 expr->acc.read = 0;
218 return pet_expr_new_unary(ctx, pet_op_kill, expr);
221 /* Construct a pet_expr that kills the elements specified by
222 * the index expression "index" and the access relation "access".
224 * We currently ignore "index".
226 struct pet_expr *pet_expr_kill_from_access_and_index(__isl_take isl_map *access,
227 __isl_take isl_multi_pw_aff *index)
229 if (!access || !index)
230 goto error;
231 isl_multi_pw_aff_free(index);
232 return pet_expr_kill_from_access(access);
233 error:
234 isl_map_free(access);
235 isl_multi_pw_aff_free(index);
236 return NULL;
239 /* Construct a unary pet_expr that performs "op" on "arg".
241 struct pet_expr *pet_expr_new_unary(isl_ctx *ctx, enum pet_op_type op,
242 struct pet_expr *arg)
244 struct pet_expr *expr;
246 if (!arg)
247 goto error;
248 expr = isl_alloc_type(ctx, struct pet_expr);
249 if (!expr)
250 goto error;
252 expr->type = pet_expr_unary;
253 expr->op = op;
254 expr->n_arg = 1;
255 expr->args = isl_calloc_array(ctx, struct pet_expr *, 1);
256 if (!expr->args)
257 goto error;
258 expr->args[pet_un_arg] = arg;
260 return expr;
261 error:
262 pet_expr_free(arg);
263 return NULL;
266 /* Construct a binary pet_expr that performs "op" on "lhs" and "rhs".
268 struct pet_expr *pet_expr_new_binary(isl_ctx *ctx, enum pet_op_type op,
269 struct pet_expr *lhs, struct pet_expr *rhs)
271 struct pet_expr *expr;
273 if (!lhs || !rhs)
274 goto error;
275 expr = isl_alloc_type(ctx, struct pet_expr);
276 if (!expr)
277 goto error;
279 expr->type = pet_expr_binary;
280 expr->op = op;
281 expr->n_arg = 2;
282 expr->args = isl_calloc_array(ctx, struct pet_expr *, 2);
283 if (!expr->args)
284 goto error;
285 expr->args[pet_bin_lhs] = lhs;
286 expr->args[pet_bin_rhs] = rhs;
288 return expr;
289 error:
290 pet_expr_free(lhs);
291 pet_expr_free(rhs);
292 return NULL;
295 /* Construct a ternary pet_expr that performs "cond" ? "lhs" : "rhs".
297 struct pet_expr *pet_expr_new_ternary(isl_ctx *ctx, struct pet_expr *cond,
298 struct pet_expr *lhs, struct pet_expr *rhs)
300 struct pet_expr *expr;
302 if (!cond || !lhs || !rhs)
303 goto error;
304 expr = isl_alloc_type(ctx, struct pet_expr);
305 if (!expr)
306 goto error;
308 expr->type = pet_expr_ternary;
309 expr->n_arg = 3;
310 expr->args = isl_calloc_array(ctx, struct pet_expr *, 3);
311 if (!expr->args)
312 goto error;
313 expr->args[pet_ter_cond] = cond;
314 expr->args[pet_ter_true] = lhs;
315 expr->args[pet_ter_false] = rhs;
317 return expr;
318 error:
319 pet_expr_free(cond);
320 pet_expr_free(lhs);
321 pet_expr_free(rhs);
322 return NULL;
325 /* Construct a call pet_expr that calls function "name" with "n_arg"
326 * arguments. The caller is responsible for filling in the arguments.
328 struct pet_expr *pet_expr_new_call(isl_ctx *ctx, const char *name,
329 unsigned n_arg)
331 struct pet_expr *expr;
333 expr = isl_alloc_type(ctx, struct pet_expr);
334 if (!expr)
335 return NULL;
337 expr->type = pet_expr_call;
338 expr->n_arg = n_arg;
339 expr->name = strdup(name);
340 expr->args = isl_calloc_array(ctx, struct pet_expr *, n_arg);
341 if (!expr->name || !expr->args)
342 return pet_expr_free(expr);
344 return expr;
347 /* Construct a pet_expr that represents the cast of "arg" to "type_name".
349 struct pet_expr *pet_expr_new_cast(isl_ctx *ctx, const char *type_name,
350 struct pet_expr *arg)
352 struct pet_expr *expr;
354 if (!arg)
355 return NULL;
357 expr = isl_alloc_type(ctx, struct pet_expr);
358 if (!expr)
359 goto error;
361 expr->type = pet_expr_cast;
362 expr->n_arg = 1;
363 expr->type_name = strdup(type_name);
364 expr->args = isl_calloc_array(ctx, struct pet_expr *, 1);
365 if (!expr->type_name || !expr->args)
366 goto error;
368 expr->args[0] = arg;
370 return expr;
371 error:
372 pet_expr_free(arg);
373 pet_expr_free(expr);
374 return NULL;
377 /* Construct a pet_expr that represents the double "d".
379 struct pet_expr *pet_expr_new_double(isl_ctx *ctx, double val, const char *s)
381 struct pet_expr *expr;
383 expr = isl_calloc_type(ctx, struct pet_expr);
384 if (!expr)
385 return NULL;
387 expr->type = pet_expr_double;
388 expr->d.val = val;
389 expr->d.s = strdup(s);
390 if (!expr->d.s)
391 return pet_expr_free(expr);
393 return expr;
396 void *pet_expr_free(struct pet_expr *expr)
398 int i;
400 if (!expr)
401 return NULL;
403 for (i = 0; i < expr->n_arg; ++i)
404 pet_expr_free(expr->args[i]);
405 free(expr->args);
407 switch (expr->type) {
408 case pet_expr_access:
409 isl_id_free(expr->acc.ref_id);
410 isl_map_free(expr->acc.access);
411 break;
412 case pet_expr_call:
413 free(expr->name);
414 break;
415 case pet_expr_cast:
416 free(expr->type_name);
417 break;
418 case pet_expr_double:
419 free(expr->d.s);
420 break;
421 case pet_expr_unary:
422 case pet_expr_binary:
423 case pet_expr_ternary:
424 break;
427 free(expr);
428 return NULL;
431 static void expr_dump(struct pet_expr *expr, int indent)
433 int i;
435 if (!expr)
436 return;
438 fprintf(stderr, "%*s", indent, "");
440 switch (expr->type) {
441 case pet_expr_double:
442 fprintf(stderr, "%s\n", expr->d.s);
443 break;
444 case pet_expr_access:
445 isl_id_dump(expr->acc.ref_id);
446 fprintf(stderr, "%*s", indent, "");
447 isl_map_dump(expr->acc.access);
448 fprintf(stderr, "%*sread: %d\n", indent + 2,
449 "", expr->acc.read);
450 fprintf(stderr, "%*swrite: %d\n", indent + 2,
451 "", expr->acc.write);
452 for (i = 0; i < expr->n_arg; ++i)
453 expr_dump(expr->args[i], indent + 2);
454 break;
455 case pet_expr_unary:
456 fprintf(stderr, "%s\n", op_str[expr->op]);
457 expr_dump(expr->args[pet_un_arg], indent + 2);
458 break;
459 case pet_expr_binary:
460 fprintf(stderr, "%s\n", op_str[expr->op]);
461 expr_dump(expr->args[pet_bin_lhs], indent + 2);
462 expr_dump(expr->args[pet_bin_rhs], indent + 2);
463 break;
464 case pet_expr_ternary:
465 fprintf(stderr, "?:\n");
466 expr_dump(expr->args[pet_ter_cond], indent + 2);
467 expr_dump(expr->args[pet_ter_true], indent + 2);
468 expr_dump(expr->args[pet_ter_false], indent + 2);
469 break;
470 case pet_expr_call:
471 fprintf(stderr, "%s/%d\n", expr->name, expr->n_arg);
472 for (i = 0; i < expr->n_arg; ++i)
473 expr_dump(expr->args[i], indent + 2);
474 break;
475 case pet_expr_cast:
476 fprintf(stderr, "(%s)\n", expr->type_name);
477 for (i = 0; i < expr->n_arg; ++i)
478 expr_dump(expr->args[i], indent + 2);
479 break;
483 void pet_expr_dump(struct pet_expr *expr)
485 expr_dump(expr, 0);
488 /* Does "expr" represent an access to an unnamed space, i.e.,
489 * does it represent an affine expression?
491 int pet_expr_is_affine(struct pet_expr *expr)
493 int has_id;
495 if (!expr)
496 return -1;
497 if (expr->type != pet_expr_access)
498 return 0;
500 has_id = isl_map_has_tuple_id(expr->acc.access, isl_dim_out);
501 if (has_id < 0)
502 return -1;
504 return !has_id;
507 /* Return the identifier of the array accessed by "expr".
509 __isl_give isl_id *pet_expr_access_get_id(struct pet_expr *expr)
511 if (!expr)
512 return NULL;
513 if (expr->type != pet_expr_access)
514 return NULL;
515 return isl_map_get_tuple_id(expr->acc.access, isl_dim_out);
518 /* Does "expr" represent an access to a scalar, i.e., zero-dimensional array?
520 int pet_expr_is_scalar_access(struct pet_expr *expr)
522 if (!expr)
523 return -1;
524 if (expr->type != pet_expr_access)
525 return 0;
527 return isl_map_dim(expr->acc.access, isl_dim_out) == 0;
530 /* Return 1 if the two pet_exprs are equivalent.
532 int pet_expr_is_equal(struct pet_expr *expr1, struct pet_expr *expr2)
534 int i;
536 if (!expr1 || !expr2)
537 return 0;
539 if (expr1->type != expr2->type)
540 return 0;
541 if (expr1->n_arg != expr2->n_arg)
542 return 0;
543 for (i = 0; i < expr1->n_arg; ++i)
544 if (!pet_expr_is_equal(expr1->args[i], expr2->args[i]))
545 return 0;
546 switch (expr1->type) {
547 case pet_expr_double:
548 if (strcmp(expr1->d.s, expr2->d.s))
549 return 0;
550 if (expr1->d.val != expr2->d.val)
551 return 0;
552 break;
553 case pet_expr_access:
554 if (expr1->acc.read != expr2->acc.read)
555 return 0;
556 if (expr1->acc.write != expr2->acc.write)
557 return 0;
558 if (expr1->acc.ref_id != expr2->acc.ref_id)
559 return 0;
560 if (!expr1->acc.access || !expr2->acc.access)
561 return 0;
562 if (!isl_map_is_equal(expr1->acc.access, expr2->acc.access))
563 return 0;
564 break;
565 case pet_expr_unary:
566 case pet_expr_binary:
567 case pet_expr_ternary:
568 if (expr1->op != expr2->op)
569 return 0;
570 break;
571 case pet_expr_call:
572 if (strcmp(expr1->name, expr2->name))
573 return 0;
574 break;
575 case pet_expr_cast:
576 if (strcmp(expr1->type_name, expr2->type_name))
577 return 0;
578 break;
581 return 1;
584 /* Add extra conditions on the parameters to all access relations in "expr".
586 struct pet_expr *pet_expr_restrict(struct pet_expr *expr,
587 __isl_take isl_set *cond)
589 int i;
591 if (!expr)
592 goto error;
594 for (i = 0; i < expr->n_arg; ++i) {
595 expr->args[i] = pet_expr_restrict(expr->args[i],
596 isl_set_copy(cond));
597 if (!expr->args[i])
598 goto error;
601 if (expr->type == pet_expr_access) {
602 expr->acc.access = isl_map_intersect_params(expr->acc.access,
603 isl_set_copy(cond));
604 if (!expr->acc.access)
605 goto error;
608 isl_set_free(cond);
609 return expr;
610 error:
611 isl_set_free(cond);
612 return pet_expr_free(expr);
615 /* Modify all expressions of type pet_expr_access in "expr"
616 * by calling "fn" on them.
618 struct pet_expr *pet_expr_map_access(struct pet_expr *expr,
619 struct pet_expr *(*fn)(struct pet_expr *expr, void *user),
620 void *user)
622 int i;
624 if (!expr)
625 return NULL;
627 for (i = 0; i < expr->n_arg; ++i) {
628 expr->args[i] = pet_expr_map_access(expr->args[i], fn, user);
629 if (!expr->args[i])
630 return pet_expr_free(expr);
633 if (expr->type == pet_expr_access)
634 expr = fn(expr, user);
636 return expr;
639 /* Call "fn" on each of the subexpressions of "expr" of type pet_expr_access.
641 * Return -1 on error (where fn return a negative value is treated as an error).
642 * Otherwise return 0.
644 int pet_expr_foreach_access_expr(struct pet_expr *expr,
645 int (*fn)(struct pet_expr *expr, void *user), void *user)
647 int i;
649 if (!expr)
650 return -1;
652 for (i = 0; i < expr->n_arg; ++i)
653 if (pet_expr_foreach_access_expr(expr->args[i], fn, user) < 0)
654 return -1;
656 if (expr->type == pet_expr_access)
657 return fn(expr, user);
659 return 0;
662 /* Modify the access relation of the given access expression
663 * based on the given iteration space transformation.
664 * If the access has any arguments then the domain of the access relation
665 * is a wrapped mapping from the iteration space to the space of
666 * argument values. We only need to change the domain of this wrapped
667 * mapping, so we extend the input transformation with an identity mapping
668 * on the space of argument values.
670 static struct pet_expr *update_domain(struct pet_expr *expr, void *user)
672 isl_map *update = user;
673 isl_space *dim;
675 update = isl_map_copy(update);
677 dim = isl_map_get_space(expr->acc.access);
678 dim = isl_space_domain(dim);
679 if (!isl_space_is_wrapping(dim))
680 isl_space_free(dim);
681 else {
682 isl_map *id;
683 dim = isl_space_unwrap(dim);
684 dim = isl_space_range(dim);
685 dim = isl_space_map_from_set(dim);
686 id = isl_map_identity(dim);
687 update = isl_map_product(update, id);
690 expr->acc.access = isl_map_apply_domain(expr->acc.access, update);
691 if (!expr->acc.access)
692 return pet_expr_free(expr);
694 return expr;
697 /* Modify all access relations in "expr" based on the given iteration space
698 * transformation.
700 static struct pet_expr *expr_update_domain(struct pet_expr *expr,
701 __isl_take isl_map *update)
703 expr = pet_expr_map_access(expr, &update_domain, update);
704 isl_map_free(update);
705 return expr;
708 /* Construct a pet_stmt with given line number and statement
709 * number from a pet_expr.
710 * The initial iteration domain is the zero-dimensional universe.
711 * The name of the domain is given by "label" if it is non-NULL.
712 * Otherwise, the name is constructed as S_<id>.
713 * The domains of all access relations are modified to refer
714 * to the statement iteration domain.
716 struct pet_stmt *pet_stmt_from_pet_expr(isl_ctx *ctx, int line,
717 __isl_take isl_id *label, int id, struct pet_expr *expr)
719 struct pet_stmt *stmt;
720 isl_space *dim;
721 isl_set *dom;
722 isl_map *sched;
723 isl_map *add_name;
724 char name[50];
726 if (!expr)
727 goto error;
729 stmt = isl_calloc_type(ctx, struct pet_stmt);
730 if (!stmt)
731 goto error;
733 dim = isl_space_set_alloc(ctx, 0, 0);
734 if (label)
735 dim = isl_space_set_tuple_id(dim, isl_dim_set, label);
736 else {
737 snprintf(name, sizeof(name), "S_%d", id);
738 dim = isl_space_set_tuple_name(dim, isl_dim_set, name);
740 dom = isl_set_universe(isl_space_copy(dim));
741 sched = isl_map_from_domain(isl_set_copy(dom));
743 dim = isl_space_from_range(dim);
744 add_name = isl_map_universe(dim);
745 expr = expr_update_domain(expr, add_name);
747 stmt->line = line;
748 stmt->domain = dom;
749 stmt->schedule = sched;
750 stmt->body = expr;
752 if (!stmt->domain || !stmt->schedule || !stmt->body)
753 return pet_stmt_free(stmt);
755 return stmt;
756 error:
757 isl_id_free(label);
758 return pet_expr_free(expr);
761 void *pet_stmt_free(struct pet_stmt *stmt)
763 int i;
765 if (!stmt)
766 return NULL;
768 isl_set_free(stmt->domain);
769 isl_map_free(stmt->schedule);
770 pet_expr_free(stmt->body);
772 for (i = 0; i < stmt->n_arg; ++i)
773 pet_expr_free(stmt->args[i]);
774 free(stmt->args);
776 free(stmt);
777 return NULL;
780 static void stmt_dump(struct pet_stmt *stmt, int indent)
782 int i;
784 if (!stmt)
785 return;
787 fprintf(stderr, "%*s%d\n", indent, "", stmt->line);
788 fprintf(stderr, "%*s", indent, "");
789 isl_set_dump(stmt->domain);
790 fprintf(stderr, "%*s", indent, "");
791 isl_map_dump(stmt->schedule);
792 expr_dump(stmt->body, indent);
793 for (i = 0; i < stmt->n_arg; ++i)
794 expr_dump(stmt->args[i], indent + 2);
797 void pet_stmt_dump(struct pet_stmt *stmt)
799 stmt_dump(stmt, 0);
802 struct pet_array *pet_array_free(struct pet_array *array)
804 if (!array)
805 return NULL;
807 isl_set_free(array->context);
808 isl_set_free(array->extent);
809 isl_set_free(array->value_bounds);
810 free(array->element_type);
812 free(array);
813 return NULL;
816 void pet_array_dump(struct pet_array *array)
818 if (!array)
819 return;
821 isl_set_dump(array->context);
822 isl_set_dump(array->extent);
823 isl_set_dump(array->value_bounds);
824 fprintf(stderr, "%s %s\n", array->element_type,
825 array->live_out ? "live-out" : "");
828 /* Alloc a pet_scop structure, with extra room for information that
829 * is only used during parsing.
831 struct pet_scop *pet_scop_alloc(isl_ctx *ctx)
833 return &isl_calloc_type(ctx, struct pet_scop_ext)->scop;
836 /* Construct a pet_scop with room for n statements.
838 static struct pet_scop *scop_alloc(isl_ctx *ctx, int n)
840 isl_space *space;
841 struct pet_scop *scop;
843 scop = pet_scop_alloc(ctx);
844 if (!scop)
845 return NULL;
847 space = isl_space_params_alloc(ctx, 0);
848 scop->context = isl_set_universe(isl_space_copy(space));
849 scop->context_value = isl_set_universe(space);
850 scop->stmts = isl_calloc_array(ctx, struct pet_stmt *, n);
851 if (!scop->context || !scop->stmts)
852 return pet_scop_free(scop);
854 scop->n_stmt = n;
856 return scop;
859 struct pet_scop *pet_scop_empty(isl_ctx *ctx)
861 return scop_alloc(ctx, 0);
864 /* Update "context" with respect to the valid parameter values for "access".
866 static __isl_give isl_set *access_extract_context(__isl_keep isl_map *access,
867 __isl_take isl_set *context)
869 context = isl_set_intersect(context,
870 isl_map_params(isl_map_copy(access)));
871 return context;
874 /* Update "context" with respect to the valid parameter values for "expr".
876 * If "expr" represents a ternary operator, then a parameter value
877 * needs to be valid for the condition and for at least one of the
878 * remaining two arguments.
879 * If the condition is an affine expression, then we can be a bit more specific.
880 * The parameter then has to be valid for the second argument for
881 * non-zero accesses and valid for the third argument for zero accesses.
883 static __isl_give isl_set *expr_extract_context(struct pet_expr *expr,
884 __isl_take isl_set *context)
886 int i;
888 if (expr->type == pet_expr_ternary) {
889 int is_aff;
890 isl_set *context1, *context2;
892 is_aff = pet_expr_is_affine(expr->args[0]);
893 if (is_aff < 0)
894 goto error;
896 context = expr_extract_context(expr->args[0], context);
897 context1 = expr_extract_context(expr->args[1],
898 isl_set_copy(context));
899 context2 = expr_extract_context(expr->args[2], context);
901 if (is_aff) {
902 isl_map *access;
903 isl_set *zero_set;
905 access = isl_map_copy(expr->args[0]->acc.access);
906 access = isl_map_fix_si(access, isl_dim_out, 0, 0);
907 zero_set = isl_map_params(access);
908 context1 = isl_set_subtract(context1,
909 isl_set_copy(zero_set));
910 context2 = isl_set_intersect(context2, zero_set);
913 context = isl_set_union(context1, context2);
914 context = isl_set_coalesce(context);
916 return context;
919 for (i = 0; i < expr->n_arg; ++i)
920 context = expr_extract_context(expr->args[i], context);
922 if (expr->type == pet_expr_access)
923 context = access_extract_context(expr->acc.access, context);
925 return context;
926 error:
927 isl_set_free(context);
928 return NULL;
931 /* Update "context" with respect to the valid parameter values for "stmt".
933 static __isl_give isl_set *stmt_extract_context(struct pet_stmt *stmt,
934 __isl_take isl_set *context)
936 int i;
938 for (i = 0; i < stmt->n_arg; ++i)
939 context = expr_extract_context(stmt->args[i], context);
941 context = expr_extract_context(stmt->body, context);
943 return context;
946 /* Construct a pet_scop that contains the given pet_stmt.
948 struct pet_scop *pet_scop_from_pet_stmt(isl_ctx *ctx, struct pet_stmt *stmt)
950 struct pet_scop *scop;
952 if (!stmt)
953 return NULL;
955 scop = scop_alloc(ctx, 1);
956 if (!scop)
957 goto error;
959 scop->context = stmt_extract_context(stmt, scop->context);
960 if (!scop->context)
961 goto error;
963 scop->stmts[0] = stmt;
965 return scop;
966 error:
967 pet_stmt_free(stmt);
968 pet_scop_free(scop);
969 return NULL;
972 /* Does "set" represent an element of an unnamed space, i.e.,
973 * does it represent an affine expression?
975 static int set_is_affine(__isl_keep isl_set *set)
977 int has_id;
979 has_id = isl_set_has_tuple_id(set);
980 if (has_id < 0)
981 return -1;
983 return !has_id;
986 /* Combine ext1->skip[type] and ext2->skip[type] into ext->skip[type].
987 * ext may be equal to either ext1 or ext2.
989 * The two skips that need to be combined are assumed to be affine expressions.
991 * We need to skip in ext if we need to skip in either ext1 or ext2.
992 * We don't need to skip in ext if we don't need to skip in both ext1 and ext2.
994 static struct pet_scop_ext *combine_skips(struct pet_scop_ext *ext,
995 struct pet_scop_ext *ext1, struct pet_scop_ext *ext2,
996 enum pet_skip type)
998 isl_set *set, *skip1, *skip2;
1000 if (!ext)
1001 return NULL;
1002 if (!ext1->skip[type] && !ext2->skip[type])
1003 return ext;
1004 if (!ext1->skip[type]) {
1005 if (ext == ext2)
1006 return ext;
1007 ext->skip[type] = ext2->skip[type];
1008 ext2->skip[type] = NULL;
1009 return ext;
1011 if (!ext2->skip[type]) {
1012 if (ext == ext1)
1013 return ext;
1014 ext->skip[type] = ext1->skip[type];
1015 ext1->skip[type] = NULL;
1016 return ext;
1019 if (!set_is_affine(ext1->skip[type]) ||
1020 !set_is_affine(ext2->skip[type]))
1021 isl_die(isl_set_get_ctx(ext1->skip[type]), isl_error_internal,
1022 "can only combine affine skips",
1023 return pet_scop_free(&ext->scop));
1025 skip1 = isl_set_copy(ext1->skip[type]);
1026 skip2 = isl_set_copy(ext2->skip[type]);
1027 set = isl_set_intersect(
1028 isl_set_fix_si(isl_set_copy(skip1), isl_dim_set, 0, 0),
1029 isl_set_fix_si(isl_set_copy(skip2), isl_dim_set, 0, 0));
1030 set = isl_set_union(set, isl_set_fix_si(skip1, isl_dim_set, 0, 1));
1031 set = isl_set_union(set, isl_set_fix_si(skip2, isl_dim_set, 0, 1));
1032 set = isl_set_coalesce(set);
1033 isl_set_free(ext1->skip[type]);
1034 ext1->skip[type] = NULL;
1035 isl_set_free(ext2->skip[type]);
1036 ext2->skip[type] = NULL;
1037 ext->skip[type] = set;
1038 if (!ext->skip[type])
1039 return pet_scop_free(&ext->scop);
1041 return ext;
1044 /* Combine scop1->skip[type] and scop2->skip[type] into scop->skip[type],
1045 * where type takes on the values pet_skip_now and pet_skip_later.
1046 * scop may be equal to either scop1 or scop2.
1048 static struct pet_scop *scop_combine_skips(struct pet_scop *scop,
1049 struct pet_scop *scop1, struct pet_scop *scop2)
1051 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1052 struct pet_scop_ext *ext1 = (struct pet_scop_ext *) scop1;
1053 struct pet_scop_ext *ext2 = (struct pet_scop_ext *) scop2;
1055 ext = combine_skips(ext, ext1, ext2, pet_skip_now);
1056 ext = combine_skips(ext, ext1, ext2, pet_skip_later);
1057 return &ext->scop;
1060 /* Update scop->start and scop->end to include the region from "start"
1061 * to "end". In particular, if scop->end == 0, then "scop" does not
1062 * have any offset information yet and we simply take the information
1063 * from "start" and "end". Otherwise, we update the fields if the
1064 * region from "start" to "end" is not already included.
1066 struct pet_scop *pet_scop_update_start_end(struct pet_scop *scop,
1067 unsigned start, unsigned end)
1069 if (!scop)
1070 return NULL;
1071 if (scop->end == 0) {
1072 scop->start = start;
1073 scop->end = end;
1074 } else {
1075 if (start < scop->start)
1076 scop->start = start;
1077 if (end > scop->end)
1078 scop->end = end;
1081 return scop;
1084 /* Does "implication" appear in the list of implications of "scop"?
1086 static int is_known_implication(struct pet_scop *scop,
1087 struct pet_implication *implication)
1089 int i;
1091 for (i = 0; i < scop->n_implication; ++i) {
1092 struct pet_implication *pi = scop->implications[i];
1093 int equal;
1095 if (pi->satisfied != implication->satisfied)
1096 continue;
1097 equal = isl_map_is_equal(pi->extension, implication->extension);
1098 if (equal < 0)
1099 return -1;
1100 if (equal)
1101 return 1;
1104 return 0;
1107 /* Store the concatenation of the impliciations of "scop1" and "scop2"
1108 * in "scop", removing duplicates (i.e., implications in "scop2" that
1109 * already appear in "scop1").
1111 static struct pet_scop *scop_collect_implications(isl_ctx *ctx,
1112 struct pet_scop *scop, struct pet_scop *scop1, struct pet_scop *scop2)
1114 int i, j;
1116 if (!scop)
1117 return NULL;
1119 if (scop2->n_implication == 0) {
1120 scop->n_implication = scop1->n_implication;
1121 scop->implications = scop1->implications;
1122 scop1->n_implication = 0;
1123 scop1->implications = NULL;
1124 return scop;
1127 if (scop1->n_implication == 0) {
1128 scop->n_implication = scop2->n_implication;
1129 scop->implications = scop2->implications;
1130 scop2->n_implication = 0;
1131 scop2->implications = NULL;
1132 return scop;
1135 scop->implications = isl_calloc_array(ctx, struct pet_implication *,
1136 scop1->n_implication + scop2->n_implication);
1137 if (!scop->implications)
1138 return pet_scop_free(scop);
1140 for (i = 0; i < scop1->n_implication; ++i) {
1141 scop->implications[i] = scop1->implications[i];
1142 scop1->implications[i] = NULL;
1145 scop->n_implication = scop1->n_implication;
1146 j = scop1->n_implication;
1147 for (i = 0; i < scop2->n_implication; ++i) {
1148 int known;
1150 known = is_known_implication(scop, scop2->implications[i]);
1151 if (known < 0)
1152 return pet_scop_free(scop);
1153 if (known)
1154 continue;
1155 scop->implications[j++] = scop2->implications[i];
1156 scop2->implications[i] = NULL;
1158 scop->n_implication = j;
1160 return scop;
1163 /* Combine the offset information of "scop1" and "scop2" into "scop".
1165 static struct pet_scop *scop_combine_start_end(struct pet_scop *scop,
1166 struct pet_scop *scop1, struct pet_scop *scop2)
1168 if (scop1->end)
1169 scop = pet_scop_update_start_end(scop,
1170 scop1->start, scop1->end);
1171 if (scop2->end)
1172 scop = pet_scop_update_start_end(scop,
1173 scop2->start, scop2->end);
1174 return scop;
1177 /* Construct a pet_scop that contains the offset information,
1178 * arrays, statements and skip information in "scop1" and "scop2".
1180 static struct pet_scop *pet_scop_add(isl_ctx *ctx, struct pet_scop *scop1,
1181 struct pet_scop *scop2)
1183 int i;
1184 struct pet_scop *scop = NULL;
1186 if (!scop1 || !scop2)
1187 goto error;
1189 if (scop1->n_stmt == 0) {
1190 scop2 = scop_combine_skips(scop2, scop1, scop2);
1191 pet_scop_free(scop1);
1192 return scop2;
1195 if (scop2->n_stmt == 0) {
1196 scop1 = scop_combine_skips(scop1, scop1, scop2);
1197 pet_scop_free(scop2);
1198 return scop1;
1201 scop = scop_alloc(ctx, scop1->n_stmt + scop2->n_stmt);
1202 if (!scop)
1203 goto error;
1205 scop->arrays = isl_calloc_array(ctx, struct pet_array *,
1206 scop1->n_array + scop2->n_array);
1207 if (!scop->arrays)
1208 goto error;
1209 scop->n_array = scop1->n_array + scop2->n_array;
1211 for (i = 0; i < scop1->n_stmt; ++i) {
1212 scop->stmts[i] = scop1->stmts[i];
1213 scop1->stmts[i] = NULL;
1216 for (i = 0; i < scop2->n_stmt; ++i) {
1217 scop->stmts[scop1->n_stmt + i] = scop2->stmts[i];
1218 scop2->stmts[i] = NULL;
1221 for (i = 0; i < scop1->n_array; ++i) {
1222 scop->arrays[i] = scop1->arrays[i];
1223 scop1->arrays[i] = NULL;
1226 for (i = 0; i < scop2->n_array; ++i) {
1227 scop->arrays[scop1->n_array + i] = scop2->arrays[i];
1228 scop2->arrays[i] = NULL;
1231 scop = scop_collect_implications(ctx, scop, scop1, scop2);
1232 scop = pet_scop_restrict_context(scop, isl_set_copy(scop1->context));
1233 scop = pet_scop_restrict_context(scop, isl_set_copy(scop2->context));
1234 scop = scop_combine_skips(scop, scop1, scop2);
1235 scop = scop_combine_start_end(scop, scop1, scop2);
1237 pet_scop_free(scop1);
1238 pet_scop_free(scop2);
1239 return scop;
1240 error:
1241 pet_scop_free(scop1);
1242 pet_scop_free(scop2);
1243 pet_scop_free(scop);
1244 return NULL;
1247 /* Apply the skip condition "skip" to "scop".
1248 * That is, make sure "scop" is not executed when the condition holds.
1250 * If "skip" is an affine expression, we add the conditions under
1251 * which the expression is zero to the iteration domains.
1252 * Otherwise, we add a filter on the variable attaining the value zero.
1254 static struct pet_scop *restrict_skip(struct pet_scop *scop,
1255 __isl_take isl_set *skip)
1257 isl_map *skip_map;
1258 int is_aff;
1260 if (!scop || !skip)
1261 goto error;
1263 is_aff = set_is_affine(skip);
1264 if (is_aff < 0)
1265 goto error;
1267 if (!is_aff)
1268 return pet_scop_filter(scop, isl_map_from_range(skip), 0);
1270 skip = isl_set_fix_si(skip, isl_dim_set, 0, 0);
1271 scop = pet_scop_restrict(scop, isl_set_params(skip));
1273 return scop;
1274 error:
1275 isl_set_free(skip);
1276 return pet_scop_free(scop);
1279 /* Construct a pet_scop that contains the arrays, statements and
1280 * skip information in "scop1" and "scop2", where the two scops
1281 * are executed "in sequence". That is, breaks and continues
1282 * in scop1 have an effect on scop2.
1284 struct pet_scop *pet_scop_add_seq(isl_ctx *ctx, struct pet_scop *scop1,
1285 struct pet_scop *scop2)
1287 if (scop1 && pet_scop_has_skip(scop1, pet_skip_now))
1288 scop2 = restrict_skip(scop2,
1289 pet_scop_get_skip(scop1, pet_skip_now));
1290 return pet_scop_add(ctx, scop1, scop2);
1293 /* Construct a pet_scop that contains the arrays, statements and
1294 * skip information in "scop1" and "scop2", where the two scops
1295 * are executed "in parallel". That is, any break or continue
1296 * in scop1 has no effect on scop2.
1298 struct pet_scop *pet_scop_add_par(isl_ctx *ctx, struct pet_scop *scop1,
1299 struct pet_scop *scop2)
1301 return pet_scop_add(ctx, scop1, scop2);
1304 void *pet_implication_free(struct pet_implication *implication)
1306 int i;
1308 if (!implication)
1309 return NULL;
1311 isl_map_free(implication->extension);
1313 free(implication);
1314 return NULL;
1317 void *pet_scop_free(struct pet_scop *scop)
1319 int i;
1320 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1322 if (!scop)
1323 return NULL;
1324 isl_set_free(scop->context);
1325 isl_set_free(scop->context_value);
1326 if (scop->arrays)
1327 for (i = 0; i < scop->n_array; ++i)
1328 pet_array_free(scop->arrays[i]);
1329 free(scop->arrays);
1330 if (scop->stmts)
1331 for (i = 0; i < scop->n_stmt; ++i)
1332 pet_stmt_free(scop->stmts[i]);
1333 free(scop->stmts);
1334 if (scop->implications)
1335 for (i = 0; i < scop->n_implication; ++i)
1336 pet_implication_free(scop->implications[i]);
1337 free(scop->implications);
1338 isl_set_free(ext->skip[pet_skip_now]);
1339 isl_set_free(ext->skip[pet_skip_later]);
1340 free(scop);
1341 return NULL;
1344 void pet_implication_dump(struct pet_implication *implication)
1346 if (!implication)
1347 return;
1349 fprintf(stderr, "%d\n", implication->satisfied);
1350 isl_map_dump(implication->extension);
1353 void pet_scop_dump(struct pet_scop *scop)
1355 int i;
1356 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1358 if (!scop)
1359 return;
1361 isl_set_dump(scop->context);
1362 isl_set_dump(scop->context_value);
1363 for (i = 0; i < scop->n_array; ++i)
1364 pet_array_dump(scop->arrays[i]);
1365 for (i = 0; i < scop->n_stmt; ++i)
1366 pet_stmt_dump(scop->stmts[i]);
1367 for (i = 0; i < scop->n_implication; ++i)
1368 pet_implication_dump(scop->implications[i]);
1370 if (ext->skip[0]) {
1371 fprintf(stderr, "skip\n");
1372 isl_set_dump(ext->skip[0]);
1373 isl_set_dump(ext->skip[1]);
1377 /* Return 1 if the two pet_arrays are equivalent.
1379 * We don't compare element_size as this may be target dependent.
1381 int pet_array_is_equal(struct pet_array *array1, struct pet_array *array2)
1383 if (!array1 || !array2)
1384 return 0;
1386 if (!isl_set_is_equal(array1->context, array2->context))
1387 return 0;
1388 if (!isl_set_is_equal(array1->extent, array2->extent))
1389 return 0;
1390 if (!!array1->value_bounds != !!array2->value_bounds)
1391 return 0;
1392 if (array1->value_bounds &&
1393 !isl_set_is_equal(array1->value_bounds, array2->value_bounds))
1394 return 0;
1395 if (strcmp(array1->element_type, array2->element_type))
1396 return 0;
1397 if (array1->live_out != array2->live_out)
1398 return 0;
1399 if (array1->uniquely_defined != array2->uniquely_defined)
1400 return 0;
1401 if (array1->declared != array2->declared)
1402 return 0;
1403 if (array1->exposed != array2->exposed)
1404 return 0;
1406 return 1;
1409 /* Return 1 if the two pet_stmts are equivalent.
1411 int pet_stmt_is_equal(struct pet_stmt *stmt1, struct pet_stmt *stmt2)
1413 int i;
1415 if (!stmt1 || !stmt2)
1416 return 0;
1418 if (stmt1->line != stmt2->line)
1419 return 0;
1420 if (!isl_set_is_equal(stmt1->domain, stmt2->domain))
1421 return 0;
1422 if (!isl_map_is_equal(stmt1->schedule, stmt2->schedule))
1423 return 0;
1424 if (!pet_expr_is_equal(stmt1->body, stmt2->body))
1425 return 0;
1426 if (stmt1->n_arg != stmt2->n_arg)
1427 return 0;
1428 for (i = 0; i < stmt1->n_arg; ++i) {
1429 if (!pet_expr_is_equal(stmt1->args[i], stmt2->args[i]))
1430 return 0;
1433 return 1;
1436 /* Return 1 if the two pet_implications are equivalent.
1438 int pet_implication_is_equal(struct pet_implication *implication1,
1439 struct pet_implication *implication2)
1441 if (!implication1 || !implication2)
1442 return 0;
1444 if (implication1->satisfied != implication2->satisfied)
1445 return 0;
1446 if (!isl_map_is_equal(implication1->extension, implication2->extension))
1447 return 0;
1449 return 1;
1452 /* Return 1 if the two pet_scops are equivalent.
1454 int pet_scop_is_equal(struct pet_scop *scop1, struct pet_scop *scop2)
1456 int i;
1458 if (!scop1 || !scop2)
1459 return 0;
1461 if (!isl_set_is_equal(scop1->context, scop2->context))
1462 return 0;
1463 if (!isl_set_is_equal(scop1->context_value, scop2->context_value))
1464 return 0;
1466 if (scop1->n_array != scop2->n_array)
1467 return 0;
1468 for (i = 0; i < scop1->n_array; ++i)
1469 if (!pet_array_is_equal(scop1->arrays[i], scop2->arrays[i]))
1470 return 0;
1472 if (scop1->n_stmt != scop2->n_stmt)
1473 return 0;
1474 for (i = 0; i < scop1->n_stmt; ++i)
1475 if (!pet_stmt_is_equal(scop1->stmts[i], scop2->stmts[i]))
1476 return 0;
1478 if (scop1->n_implication != scop2->n_implication)
1479 return 0;
1480 for (i = 0; i < scop1->n_implication; ++i)
1481 if (!pet_implication_is_equal(scop1->implications[i],
1482 scop2->implications[i]))
1483 return 0;
1485 return 1;
1488 /* Prefix the schedule of "stmt" with an extra dimension with constant
1489 * value "pos".
1491 struct pet_stmt *pet_stmt_prefix(struct pet_stmt *stmt, int pos)
1493 if (!stmt)
1494 return NULL;
1496 stmt->schedule = isl_map_insert_dims(stmt->schedule, isl_dim_out, 0, 1);
1497 stmt->schedule = isl_map_fix_si(stmt->schedule, isl_dim_out, 0, pos);
1498 if (!stmt->schedule)
1499 return pet_stmt_free(stmt);
1501 return stmt;
1504 /* Prefix the schedules of all statements in "scop" with an extra
1505 * dimension with constant value "pos".
1507 struct pet_scop *pet_scop_prefix(struct pet_scop *scop, int pos)
1509 int i;
1511 if (!scop)
1512 return NULL;
1514 for (i = 0; i < scop->n_stmt; ++i) {
1515 scop->stmts[i] = pet_stmt_prefix(scop->stmts[i], pos);
1516 if (!scop->stmts[i])
1517 return pet_scop_free(scop);
1520 return scop;
1523 /* Given a set with a parameter at "param_pos" that refers to the
1524 * iterator, "move" the iterator to the first set dimension.
1525 * That is, essentially equate the parameter to the first set dimension
1526 * and then project it out.
1528 * The first set dimension may however refer to a virtual iterator,
1529 * while the parameter refers to the "real" iterator.
1530 * We therefore need to take into account the affine expression "iv_map", which
1531 * expresses the real iterator in terms of the virtual iterator.
1532 * In particular, we equate the set dimension to the input of the map
1533 * and the parameter to the output of the map and then project out
1534 * everything we don't need anymore.
1536 static __isl_give isl_set *internalize_iv(__isl_take isl_set *set,
1537 int param_pos, __isl_take isl_aff *iv_map)
1539 isl_map *map, *map2;
1540 map = isl_map_from_domain(set);
1541 map = isl_map_add_dims(map, isl_dim_out, 1);
1542 map = isl_map_equate(map, isl_dim_in, 0, isl_dim_out, 0);
1543 map2 = isl_map_from_aff(iv_map);
1544 map2 = isl_map_align_params(map2, isl_map_get_space(map));
1545 map = isl_map_apply_range(map, map2);
1546 map = isl_map_equate(map, isl_dim_param, param_pos, isl_dim_out, 0);
1547 map = isl_map_project_out(map, isl_dim_param, param_pos, 1);
1548 return isl_map_domain(map);
1551 /* Data used in embed_access.
1552 * extend adds an iterator to the iteration domain
1553 * iv_map expresses the real iterator in terms of the virtual iterator
1554 * var_id represents the induction variable of the corresponding loop
1556 struct pet_embed_access {
1557 isl_map *extend;
1558 isl_aff *iv_map;
1559 isl_id *var_id;
1562 /* Given an access expression, embed the associated access relation
1563 * in an extra outer loop.
1565 * We first update the iteration domain to insert the extra dimension.
1567 * If the access refers to the induction variable, then it is
1568 * turned into an access to the set of integers with index (and value)
1569 * equal to the induction variable.
1571 * If the induction variable appears in the constraints (as a parameter),
1572 * then the parameter is equated to the newly introduced iteration
1573 * domain dimension and subsequently projected out.
1575 * Similarly, if the accessed array is a virtual array (with user
1576 * pointer equal to NULL), as created by create_test_index,
1577 * then it is extended along with the domain of the access.
1579 static struct pet_expr *embed_access(struct pet_expr *expr, void *user)
1581 struct pet_embed_access *data = user;
1582 isl_map *access;
1583 isl_id *array_id = NULL;
1584 int pos;
1586 expr = update_domain(expr, data->extend);
1587 if (!expr)
1588 return NULL;
1590 access = expr->acc.access;
1592 if (isl_map_has_tuple_id(access, isl_dim_out))
1593 array_id = isl_map_get_tuple_id(access, isl_dim_out);
1594 if (array_id == data->var_id ||
1595 (array_id && !isl_id_get_user(array_id))) {
1596 access = isl_map_insert_dims(access, isl_dim_out, 0, 1);
1597 access = isl_map_equate(access,
1598 isl_dim_in, 0, isl_dim_out, 0);
1599 if (array_id == data->var_id)
1600 access = isl_map_apply_range(access,
1601 isl_map_from_aff(isl_aff_copy(data->iv_map)));
1602 else
1603 access = isl_map_set_tuple_id(access, isl_dim_out,
1604 isl_id_copy(array_id));
1606 isl_id_free(array_id);
1608 pos = isl_map_find_dim_by_id(access, isl_dim_param, data->var_id);
1609 if (pos >= 0) {
1610 isl_set *set = isl_map_wrap(access);
1611 set = internalize_iv(set, pos, isl_aff_copy(data->iv_map));
1612 access = isl_set_unwrap(set);
1614 expr->acc.access = isl_map_set_dim_id(access, isl_dim_in, 0,
1615 isl_id_copy(data->var_id));
1616 if (!expr->acc.access)
1617 return pet_expr_free(expr);
1619 return expr;
1622 /* Embed all access subexpressions of "expr" in an extra loop.
1623 * "extend" inserts an outer loop iterator in the iteration domains.
1624 * "iv_map" expresses the real iterator in terms of the virtual iterator
1625 * "var_id" represents the induction variable.
1627 static struct pet_expr *expr_embed(struct pet_expr *expr,
1628 __isl_take isl_map *extend, __isl_take isl_aff *iv_map,
1629 __isl_keep isl_id *var_id)
1631 struct pet_embed_access data =
1632 { .extend = extend, .iv_map = iv_map, .var_id = var_id };
1634 expr = pet_expr_map_access(expr, &embed_access, &data);
1635 isl_aff_free(iv_map);
1636 isl_map_free(extend);
1637 return expr;
1640 /* Embed the given pet_stmt in an extra outer loop with iteration domain
1641 * "dom" and schedule "sched". "var_id" represents the induction variable
1642 * of the loop. "iv_map" maps a possibly virtual iterator to the real iterator.
1643 * That is, it expresses the iterator that some of the parameters in "stmt"
1644 * may refer to in terms of the iterator used in "dom" and
1645 * the domain of "sched".
1647 * The iteration domain and schedule of the statement are updated
1648 * according to the iteration domain and schedule of the new loop.
1649 * If stmt->domain is a wrapped map, then the iteration domain
1650 * is the domain of this map, so we need to be careful to adjust
1651 * this domain.
1653 * If the induction variable appears in the constraints (as a parameter)
1654 * of the current iteration domain or the schedule of the statement,
1655 * then the parameter is equated to the newly introduced iteration
1656 * domain dimension and subsequently projected out.
1658 * Finally, all access relations are updated based on the extra loop.
1660 static struct pet_stmt *pet_stmt_embed(struct pet_stmt *stmt,
1661 __isl_take isl_set *dom, __isl_take isl_map *sched,
1662 __isl_take isl_aff *iv_map, __isl_take isl_id *var_id)
1664 int i;
1665 int pos;
1666 isl_id *stmt_id;
1667 isl_space *dim;
1668 isl_map *extend;
1670 if (!stmt)
1671 goto error;
1673 if (isl_set_is_wrapping(stmt->domain)) {
1674 isl_map *map;
1675 isl_map *ext;
1676 isl_space *ran_dim;
1678 map = isl_set_unwrap(stmt->domain);
1679 stmt_id = isl_map_get_tuple_id(map, isl_dim_in);
1680 ran_dim = isl_space_range(isl_map_get_space(map));
1681 ext = isl_map_from_domain_and_range(isl_set_copy(dom),
1682 isl_set_universe(ran_dim));
1683 map = isl_map_flat_domain_product(ext, map);
1684 map = isl_map_set_tuple_id(map, isl_dim_in,
1685 isl_id_copy(stmt_id));
1686 dim = isl_space_domain(isl_map_get_space(map));
1687 stmt->domain = isl_map_wrap(map);
1688 } else {
1689 stmt_id = isl_set_get_tuple_id(stmt->domain);
1690 stmt->domain = isl_set_flat_product(isl_set_copy(dom),
1691 stmt->domain);
1692 stmt->domain = isl_set_set_tuple_id(stmt->domain,
1693 isl_id_copy(stmt_id));
1694 dim = isl_set_get_space(stmt->domain);
1697 pos = isl_set_find_dim_by_id(stmt->domain, isl_dim_param, var_id);
1698 if (pos >= 0)
1699 stmt->domain = internalize_iv(stmt->domain, pos,
1700 isl_aff_copy(iv_map));
1702 stmt->schedule = isl_map_flat_product(sched, stmt->schedule);
1703 stmt->schedule = isl_map_set_tuple_id(stmt->schedule,
1704 isl_dim_in, stmt_id);
1706 pos = isl_map_find_dim_by_id(stmt->schedule, isl_dim_param, var_id);
1707 if (pos >= 0) {
1708 isl_set *set = isl_map_wrap(stmt->schedule);
1709 set = internalize_iv(set, pos, isl_aff_copy(iv_map));
1710 stmt->schedule = isl_set_unwrap(set);
1713 dim = isl_space_map_from_set(dim);
1714 extend = isl_map_identity(dim);
1715 extend = isl_map_remove_dims(extend, isl_dim_in, 0, 1);
1716 extend = isl_map_set_tuple_id(extend, isl_dim_in,
1717 isl_map_get_tuple_id(extend, isl_dim_out));
1718 for (i = 0; i < stmt->n_arg; ++i)
1719 stmt->args[i] = expr_embed(stmt->args[i], isl_map_copy(extend),
1720 isl_aff_copy(iv_map), var_id);
1721 stmt->body = expr_embed(stmt->body, extend, iv_map, var_id);
1723 isl_set_free(dom);
1724 isl_id_free(var_id);
1726 for (i = 0; i < stmt->n_arg; ++i)
1727 if (!stmt->args[i])
1728 return pet_stmt_free(stmt);
1729 if (!stmt->domain || !stmt->schedule || !stmt->body)
1730 return pet_stmt_free(stmt);
1731 return stmt;
1732 error:
1733 isl_set_free(dom);
1734 isl_map_free(sched);
1735 isl_aff_free(iv_map);
1736 isl_id_free(var_id);
1737 return NULL;
1740 /* Embed the given pet_array in an extra outer loop with iteration domain
1741 * "dom".
1742 * This embedding only has an effect on virtual arrays (those with
1743 * user pointer equal to NULL), which need to be extended along with
1744 * the iteration domain.
1746 static struct pet_array *pet_array_embed(struct pet_array *array,
1747 __isl_take isl_set *dom)
1749 isl_id *array_id = NULL;
1751 if (!array)
1752 goto error;
1754 if (isl_set_has_tuple_id(array->extent))
1755 array_id = isl_set_get_tuple_id(array->extent);
1757 if (array_id && !isl_id_get_user(array_id)) {
1758 array->extent = isl_set_flat_product(dom, array->extent);
1759 array->extent = isl_set_set_tuple_id(array->extent, array_id);
1760 if (!array->extent)
1761 return pet_array_free(array);
1762 } else {
1763 isl_set_free(dom);
1764 isl_id_free(array_id);
1767 return array;
1768 error:
1769 isl_set_free(dom);
1770 return NULL;
1773 /* Project out all unnamed parameters from "set" and return the result.
1775 static __isl_give isl_set *set_project_out_unnamed_params(
1776 __isl_take isl_set *set)
1778 int i, n;
1780 n = isl_set_dim(set, isl_dim_param);
1781 for (i = n - 1; i >= 0; --i) {
1782 if (isl_set_has_dim_name(set, isl_dim_param, i))
1783 continue;
1784 set = isl_set_project_out(set, isl_dim_param, i, 1);
1787 return set;
1790 /* Update the context with respect to an embedding into a loop
1791 * with iteration domain "dom" and induction variable "id".
1792 * "iv_map" expresses the real iterator (parameter "id") in terms
1793 * of a possibly virtual iterator (used in "dom").
1795 * If the current context is independent of "id", we don't need
1796 * to do anything.
1797 * Otherwise, a parameter value is invalid for the embedding if
1798 * any of the corresponding iterator values is invalid.
1799 * That is, a parameter value is valid only if all the corresponding
1800 * iterator values are valid.
1801 * We therefore compute the set of parameters
1803 * forall i in dom : valid (i)
1805 * or
1807 * not exists i in dom : not valid(i)
1809 * i.e.,
1811 * not exists i in dom \ valid(i)
1813 * Before we subtract valid(i) from dom, we first need to substitute
1814 * the real iterator for the virtual iterator.
1816 * If there are any unnamed parameters in "dom", then we consider
1817 * a parameter value to be valid if it is valid for any value of those
1818 * unnamed parameters. They are therefore projected out at the end.
1820 static __isl_give isl_set *context_embed(__isl_take isl_set *context,
1821 __isl_keep isl_set *dom, __isl_keep isl_aff *iv_map,
1822 __isl_keep isl_id *id)
1824 int pos;
1825 isl_multi_aff *ma;
1827 pos = isl_set_find_dim_by_id(context, isl_dim_param, id);
1828 if (pos < 0)
1829 return context;
1831 context = isl_set_from_params(context);
1832 context = isl_set_add_dims(context, isl_dim_set, 1);
1833 context = isl_set_equate(context, isl_dim_param, pos, isl_dim_set, 0);
1834 context = isl_set_project_out(context, isl_dim_param, pos, 1);
1835 ma = isl_multi_aff_from_aff(isl_aff_copy(iv_map));
1836 context = isl_set_preimage_multi_aff(context, ma);
1837 context = isl_set_subtract(isl_set_copy(dom), context);
1838 context = isl_set_params(context);
1839 context = isl_set_complement(context);
1840 context = set_project_out_unnamed_params(context);
1841 return context;
1844 /* Update the implication with respect to an embedding into a loop
1845 * with iteration domain "dom".
1847 * Since embed_access extends virtual arrays along with the domain
1848 * of the access, we need to do the same with domain and range
1849 * of the implication. Since the original implication is only valid
1850 * within a given iteration of the loop, the extended implication
1851 * maps the extra array dimension corresponding to the extra loop
1852 * to itself.
1854 static struct pet_implication *pet_implication_embed(
1855 struct pet_implication *implication, __isl_take isl_set *dom)
1857 isl_id *id;
1858 isl_map *map;
1860 if (!implication)
1861 goto error;
1863 map = isl_set_identity(dom);
1864 id = isl_map_get_tuple_id(implication->extension, isl_dim_in);
1865 map = isl_map_flat_product(map, implication->extension);
1866 map = isl_map_set_tuple_id(map, isl_dim_in, isl_id_copy(id));
1867 map = isl_map_set_tuple_id(map, isl_dim_out, id);
1868 implication->extension = map;
1869 if (!implication->extension)
1870 return pet_implication_free(implication);
1872 return implication;
1873 error:
1874 isl_set_free(dom);
1875 return NULL;
1878 /* Embed all statements and arrays in "scop" in an extra outer loop
1879 * with iteration domain "dom" and schedule "sched".
1880 * "id" represents the induction variable of the loop.
1881 * "iv_map" maps a possibly virtual iterator to the real iterator.
1882 * That is, it expresses the iterator that some of the parameters in "scop"
1883 * may refer to in terms of the iterator used in "dom" and
1884 * the domain of "sched".
1886 * Any skip conditions within the loop have no effect outside of the loop.
1887 * The caller is responsible for making sure skip[pet_skip_later] has been
1888 * taken into account.
1890 struct pet_scop *pet_scop_embed(struct pet_scop *scop, __isl_take isl_set *dom,
1891 __isl_take isl_map *sched, __isl_take isl_aff *iv_map,
1892 __isl_take isl_id *id)
1894 int i;
1896 if (!scop)
1897 goto error;
1899 pet_scop_reset_skip(scop, pet_skip_now);
1900 pet_scop_reset_skip(scop, pet_skip_later);
1902 scop->context = context_embed(scop->context, dom, iv_map, id);
1903 if (!scop->context)
1904 goto error;
1906 for (i = 0; i < scop->n_stmt; ++i) {
1907 scop->stmts[i] = pet_stmt_embed(scop->stmts[i],
1908 isl_set_copy(dom), isl_map_copy(sched),
1909 isl_aff_copy(iv_map), isl_id_copy(id));
1910 if (!scop->stmts[i])
1911 goto error;
1914 for (i = 0; i < scop->n_array; ++i) {
1915 scop->arrays[i] = pet_array_embed(scop->arrays[i],
1916 isl_set_copy(dom));
1917 if (!scop->arrays[i])
1918 goto error;
1921 for (i = 0; i < scop->n_implication; ++i) {
1922 scop->implications[i] =
1923 pet_implication_embed(scop->implications[i],
1924 isl_set_copy(dom));
1925 if (!scop->implications[i])
1926 goto error;
1929 isl_set_free(dom);
1930 isl_map_free(sched);
1931 isl_aff_free(iv_map);
1932 isl_id_free(id);
1933 return scop;
1934 error:
1935 isl_set_free(dom);
1936 isl_map_free(sched);
1937 isl_aff_free(iv_map);
1938 isl_id_free(id);
1939 return pet_scop_free(scop);
1942 /* Add extra conditions on the parameters to iteration domain of "stmt".
1944 static struct pet_stmt *stmt_restrict(struct pet_stmt *stmt,
1945 __isl_take isl_set *cond)
1947 if (!stmt)
1948 goto error;
1950 stmt->domain = isl_set_intersect_params(stmt->domain, cond);
1952 return stmt;
1953 error:
1954 isl_set_free(cond);
1955 return pet_stmt_free(stmt);
1958 /* Add extra conditions to scop->skip[type].
1960 * The new skip condition only holds if it held before
1961 * and the condition is true. It does not hold if it did not hold
1962 * before or the condition is false.
1964 * The skip condition is assumed to be an affine expression.
1966 static struct pet_scop *pet_scop_restrict_skip(struct pet_scop *scop,
1967 enum pet_skip type, __isl_keep isl_set *cond)
1969 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1970 isl_set *skip;
1971 isl_set *set;
1973 if (!scop)
1974 return NULL;
1975 if (!ext->skip[type])
1976 return scop;
1978 if (!set_is_affine(ext->skip[type]))
1979 isl_die(isl_set_get_ctx(ext->skip[type]), isl_error_internal,
1980 "can only resrict affine skips",
1981 return pet_scop_free(scop));
1983 skip = ext->skip[type];
1984 skip = isl_set_intersect_params(skip, isl_set_copy(cond));
1985 set = isl_set_from_params(isl_set_copy(cond));
1986 set = isl_set_complement(set);
1987 set = isl_set_add_dims(set, isl_dim_set, 1);
1988 set = isl_set_fix_si(set, isl_dim_set, 0, 0);
1989 skip = isl_set_union(skip, set);
1990 ext->skip[type] = skip;
1991 if (!ext->skip[type])
1992 return pet_scop_free(scop);
1994 return scop;
1997 /* Add extra conditions on the parameters to all iteration domains
1998 * and skip conditions.
2000 * A parameter value is valid for the result if it was valid
2001 * for the original scop and satisfies "cond" or if it does
2002 * not satisfy "cond" as in this case the scop is not executed
2003 * and the original constraints on the parameters are irrelevant.
2005 struct pet_scop *pet_scop_restrict(struct pet_scop *scop,
2006 __isl_take isl_set *cond)
2008 int i;
2010 scop = pet_scop_restrict_skip(scop, pet_skip_now, cond);
2011 scop = pet_scop_restrict_skip(scop, pet_skip_later, cond);
2013 if (!scop)
2014 goto error;
2016 scop->context = isl_set_intersect(scop->context, isl_set_copy(cond));
2017 scop->context = isl_set_union(scop->context,
2018 isl_set_complement(isl_set_copy(cond)));
2019 scop->context = isl_set_coalesce(scop->context);
2020 scop->context = set_project_out_unnamed_params(scop->context);
2021 if (!scop->context)
2022 goto error;
2024 for (i = 0; i < scop->n_stmt; ++i) {
2025 scop->stmts[i] = stmt_restrict(scop->stmts[i],
2026 isl_set_copy(cond));
2027 if (!scop->stmts[i])
2028 goto error;
2031 isl_set_free(cond);
2032 return scop;
2033 error:
2034 isl_set_free(cond);
2035 return pet_scop_free(scop);
2038 /* Construct a map that inserts a filter value with name "id" and value
2039 * "satisfied" in the list of filter values embedded in the set space "space".
2041 * If "space" does not contain any filter values yet, we first create
2042 * a map that inserts 0 filter values, i.e.,
2044 * space -> [space -> []]
2046 * We can now assume that space is of the form [dom -> [filters]]
2047 * We construct an identity mapping on dom and a mapping on filters
2048 * that inserts the new filter
2050 * dom -> dom
2051 * [filters] -> [satisfied, filters]
2053 * and then compute the cross product
2055 * [dom -> [filters]] -> [dom -> [satisfied, filters]]
2057 static __isl_give isl_map *insert_filter_map(__isl_take isl_space *space,
2058 __isl_take isl_id *id, int satisfied)
2060 isl_space *space2;
2061 isl_map *map, *map_dom, *map_ran;
2062 isl_set *dom;
2064 if (isl_space_is_wrapping(space)) {
2065 space2 = isl_space_map_from_set(isl_space_copy(space));
2066 map = isl_map_identity(space2);
2067 space = isl_space_unwrap(space);
2068 } else {
2069 space = isl_space_from_domain(space);
2070 map = isl_map_universe(isl_space_copy(space));
2071 map = isl_map_reverse(isl_map_domain_map(map));
2074 space2 = isl_space_domain(isl_space_copy(space));
2075 map_dom = isl_map_identity(isl_space_map_from_set(space2));
2076 space = isl_space_range(space);
2077 map_ran = isl_map_identity(isl_space_map_from_set(space));
2078 map_ran = isl_map_insert_dims(map_ran, isl_dim_out, 0, 1);
2079 map_ran = isl_map_set_dim_id(map_ran, isl_dim_out, 0, id);
2080 map_ran = isl_map_fix_si(map_ran, isl_dim_out, 0, satisfied);
2082 map = isl_map_apply_range(map, isl_map_product(map_dom, map_ran));
2084 return map;
2087 /* Insert an argument expression corresponding to "test" in front
2088 * of the list of arguments described by *n_arg and *args.
2090 static int args_insert_access(unsigned *n_arg, struct pet_expr ***args,
2091 __isl_keep isl_map *test)
2093 int i;
2094 isl_ctx *ctx = isl_map_get_ctx(test);
2096 if (!test)
2097 return -1;
2099 if (!*args) {
2100 *args = isl_calloc_array(ctx, struct pet_expr *, 1);
2101 if (!*args)
2102 return -1;
2103 } else {
2104 struct pet_expr **ext;
2105 ext = isl_calloc_array(ctx, struct pet_expr *, 1 + *n_arg);
2106 if (!ext)
2107 return -1;
2108 for (i = 0; i < *n_arg; ++i)
2109 ext[1 + i] = (*args)[i];
2110 free(*args);
2111 *args = ext;
2113 (*n_arg)++;
2114 (*args)[0] = pet_expr_from_access(isl_map_copy(test));
2115 if (!(*args)[0])
2116 return -1;
2118 return 0;
2121 /* Make the expression "expr" depend on the value of "test"
2122 * being equal to "satisfied".
2124 * If "test" is an affine expression, we simply add the conditions
2125 * on the expression have the value "satisfied" to all access relations.
2127 * Otherwise, we add a filter to "expr" (which is then assumed to be
2128 * an access expression) corresponding to "test" being equal to "satisfied".
2130 struct pet_expr *pet_expr_filter(struct pet_expr *expr,
2131 __isl_take isl_map *test, int satisfied)
2133 isl_id *id;
2134 isl_ctx *ctx;
2135 isl_space *space;
2136 isl_map *map;
2138 if (!expr || !test)
2139 goto error;
2141 if (!isl_map_has_tuple_id(test, isl_dim_out)) {
2142 test = isl_map_fix_si(test, isl_dim_out, 0, satisfied);
2143 return pet_expr_restrict(expr, isl_map_params(test));
2146 ctx = isl_map_get_ctx(test);
2147 if (expr->type != pet_expr_access)
2148 isl_die(ctx, isl_error_invalid,
2149 "can only filter access expressions", goto error);
2151 space = isl_space_domain(isl_map_get_space(expr->acc.access));
2152 id = isl_map_get_tuple_id(test, isl_dim_out);
2153 map = insert_filter_map(space, id, satisfied);
2155 expr->acc.access = isl_map_apply_domain(expr->acc.access, map);
2156 if (!expr->acc.access)
2157 goto error;
2159 if (args_insert_access(&expr->n_arg, &expr->args, test) < 0)
2160 goto error;
2162 isl_map_free(test);
2163 return expr;
2164 error:
2165 isl_map_free(test);
2166 return pet_expr_free(expr);
2169 /* Look through the applications in "scop" for any that can be
2170 * applied to the filter expressed by "map" and "satisified".
2171 * If there is any, then apply it to "map" and return the result.
2172 * Otherwise, return "map".
2173 * "id" is the identifier of the virtual array.
2175 * We only introduce at most one implication for any given virtual array,
2176 * so we can apply the implication and return as soon as we find one.
2178 static __isl_give isl_map *apply_implications(struct pet_scop *scop,
2179 __isl_take isl_map *map, __isl_keep isl_id *id, int satisfied)
2181 int i;
2183 for (i = 0; i < scop->n_implication; ++i) {
2184 struct pet_implication *pi = scop->implications[i];
2185 isl_id *pi_id;
2187 if (pi->satisfied != satisfied)
2188 continue;
2189 pi_id = isl_map_get_tuple_id(pi->extension, isl_dim_in);
2190 isl_id_free(pi_id);
2191 if (pi_id != id)
2192 continue;
2194 return isl_map_apply_range(map, isl_map_copy(pi->extension));
2197 return map;
2200 /* Is the filter expressed by "test" and "satisfied" implied
2201 * by filter "pos" on "domain", with filter "expr", taking into
2202 * account the implications of "scop"?
2204 * For filter on domain implying that expressed by "test" and "satisfied",
2205 * the filter needs to be an access to the same (virtual) array as "test" and
2206 * the filter value needs to be equal to "satisfied".
2207 * Moreover, the filter access relation, possibly extended by
2208 * the implications in "scop" needs to contain "test".
2210 static int implies_filter(struct pet_scop *scop,
2211 __isl_keep isl_map *domain, int pos, struct pet_expr *expr,
2212 __isl_keep isl_map *test, int satisfied)
2214 isl_id *test_id, *arg_id;
2215 isl_val *val;
2216 int is_int;
2217 int s;
2218 int is_subset;
2219 isl_map *implied;
2221 if (expr->type != pet_expr_access)
2222 return 0;
2223 test_id = isl_map_get_tuple_id(test, isl_dim_out);
2224 arg_id = pet_expr_access_get_id(expr);
2225 isl_id_free(arg_id);
2226 isl_id_free(test_id);
2227 if (test_id != arg_id)
2228 return 0;
2229 val = isl_map_plain_get_val_if_fixed(domain, isl_dim_out, pos);
2230 is_int = isl_val_is_int(val);
2231 if (is_int)
2232 s = isl_val_get_num_si(val);
2233 isl_val_free(val);
2234 if (!val)
2235 return -1;
2236 if (!is_int)
2237 return 0;
2238 if (s != satisfied)
2239 return 0;
2241 implied = isl_map_copy(expr->acc.access);
2242 implied = apply_implications(scop, implied, test_id, satisfied);
2243 is_subset = isl_map_is_subset(test, implied);
2244 isl_map_free(implied);
2246 return is_subset;
2249 /* Is the filter expressed by "test" and "satisfied" implied
2250 * by any of the filters on the domain of "stmt", taking into
2251 * account the implications of "scop"?
2253 static int filter_implied(struct pet_scop *scop,
2254 struct pet_stmt *stmt, __isl_keep isl_map *test, int satisfied)
2256 int i;
2257 int implied;
2258 isl_id *test_id;
2259 isl_map *domain;
2261 if (!scop || !stmt || !test)
2262 return -1;
2263 if (scop->n_implication == 0)
2264 return 0;
2265 if (stmt->n_arg == 0)
2266 return 0;
2268 domain = isl_set_unwrap(isl_set_copy(stmt->domain));
2270 implied = 0;
2271 for (i = 0; i < stmt->n_arg; ++i) {
2272 implied = implies_filter(scop, domain, i, stmt->args[i],
2273 test, satisfied);
2274 if (implied < 0 || implied)
2275 break;
2278 isl_map_free(domain);
2279 return implied;
2282 /* Make the statement "stmt" depend on the value of "test"
2283 * being equal to "satisfied" by adjusting stmt->domain.
2285 * The domain of "test" corresponds to the (zero or more) outer dimensions
2286 * of the iteration domain.
2288 * We first extend "test" to apply to the entire iteration domain and
2289 * then check if the filter that we are about to add is implied
2290 * by any of the current filters, possibly taking into account
2291 * the implications in "scop". If so, we leave "stmt" untouched and return.
2293 * Otherwise, we insert an argument corresponding to a read to "test"
2294 * from the iteration domain of "stmt" in front of the list of arguments.
2295 * We also insert a corresponding output dimension in the wrapped
2296 * map contained in stmt->domain, with value set to "satisfied".
2298 static struct pet_stmt *stmt_filter(struct pet_scop *scop,
2299 struct pet_stmt *stmt, __isl_take isl_map *test, int satisfied)
2301 int i;
2302 int implied;
2303 isl_id *id;
2304 isl_ctx *ctx;
2305 isl_map *map, *add_dom;
2306 isl_space *space;
2307 isl_set *dom;
2308 int n_test_dom;
2310 if (!stmt || !test)
2311 goto error;
2313 space = isl_set_get_space(stmt->domain);
2314 if (isl_space_is_wrapping(space))
2315 space = isl_space_domain(isl_space_unwrap(space));
2316 dom = isl_set_universe(space);
2317 n_test_dom = isl_map_dim(test, isl_dim_in);
2318 add_dom = isl_map_from_range(dom);
2319 add_dom = isl_map_add_dims(add_dom, isl_dim_in, n_test_dom);
2320 for (i = 0; i < n_test_dom; ++i)
2321 add_dom = isl_map_equate(add_dom, isl_dim_in, i,
2322 isl_dim_out, i);
2323 test = isl_map_apply_domain(test, add_dom);
2325 implied = filter_implied(scop, stmt, test, satisfied);
2326 if (implied < 0)
2327 goto error;
2328 if (implied) {
2329 isl_map_free(test);
2330 return stmt;
2333 id = isl_map_get_tuple_id(test, isl_dim_out);
2334 map = insert_filter_map(isl_set_get_space(stmt->domain), id, satisfied);
2335 stmt->domain = isl_set_apply(stmt->domain, map);
2337 if (args_insert_access(&stmt->n_arg, &stmt->args, test) < 0)
2338 goto error;
2340 isl_map_free(test);
2341 return stmt;
2342 error:
2343 isl_map_free(test);
2344 return pet_stmt_free(stmt);
2347 /* Does "scop" have a skip condition of the given "type"?
2349 int pet_scop_has_skip(struct pet_scop *scop, enum pet_skip type)
2351 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2353 if (!scop)
2354 return -1;
2355 return ext->skip[type] != NULL;
2358 /* Does "scop" have a skip condition of the given "type" that
2359 * is an affine expression?
2361 int pet_scop_has_affine_skip(struct pet_scop *scop, enum pet_skip type)
2363 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2365 if (!scop)
2366 return -1;
2367 if (!ext->skip[type])
2368 return 0;
2369 return set_is_affine(ext->skip[type]);
2372 /* Does "scop" have a skip condition of the given "type" that
2373 * is not an affine expression?
2375 int pet_scop_has_var_skip(struct pet_scop *scop, enum pet_skip type)
2377 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2378 int aff;
2380 if (!scop)
2381 return -1;
2382 if (!ext->skip[type])
2383 return 0;
2384 aff = set_is_affine(ext->skip[type]);
2385 if (aff < 0)
2386 return -1;
2387 return !aff;
2390 /* Does "scop" have a skip condition of the given "type" that
2391 * is affine and holds on the entire domain?
2393 int pet_scop_has_universal_skip(struct pet_scop *scop, enum pet_skip type)
2395 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2396 isl_set *set;
2397 int is_aff;
2398 int is_univ;
2400 is_aff = pet_scop_has_affine_skip(scop, type);
2401 if (is_aff < 0 || !is_aff)
2402 return is_aff;
2404 set = isl_set_copy(ext->skip[type]);
2405 set = isl_set_fix_si(set, isl_dim_set, 0, 1);
2406 set = isl_set_params(set);
2407 is_univ = isl_set_plain_is_universe(set);
2408 isl_set_free(set);
2410 return is_univ;
2413 /* Replace scop->skip[type] by "skip".
2415 struct pet_scop *pet_scop_set_skip(struct pet_scop *scop,
2416 enum pet_skip type, __isl_take isl_set *skip)
2418 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2420 if (!scop || !skip)
2421 goto error;
2423 isl_set_free(ext->skip[type]);
2424 ext->skip[type] = skip;
2426 return scop;
2427 error:
2428 isl_set_free(skip);
2429 return pet_scop_free(scop);
2432 /* Return a copy of scop->skip[type].
2434 __isl_give isl_set *pet_scop_get_skip(struct pet_scop *scop,
2435 enum pet_skip type)
2437 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2439 if (!scop)
2440 return NULL;
2442 return isl_set_copy(ext->skip[type]);
2445 /* Assuming scop->skip[type] is an affine expression,
2446 * return the constraints on the parameters for which the skip condition
2447 * holds.
2449 __isl_give isl_set *pet_scop_get_affine_skip_domain(struct pet_scop *scop,
2450 enum pet_skip type)
2452 isl_set *skip;
2454 skip = pet_scop_get_skip(scop, type);
2455 skip = isl_set_fix_si(skip, isl_dim_set, 0, 1);
2456 skip = isl_set_params(skip);
2458 return skip;
2461 /* Return a map to the skip condition of the given type.
2463 __isl_give isl_map *pet_scop_get_skip_map(struct pet_scop *scop,
2464 enum pet_skip type)
2466 return isl_map_from_range(pet_scop_get_skip(scop, type));
2469 /* Return the identifier of the variable that is accessed by
2470 * the skip condition of the given type.
2472 * The skip condition is assumed not to be an affine condition.
2474 __isl_give isl_id *pet_scop_get_skip_id(struct pet_scop *scop,
2475 enum pet_skip type)
2477 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2479 if (!scop)
2480 return NULL;
2482 return isl_set_get_tuple_id(ext->skip[type]);
2485 /* Return an access pet_expr corresponding to the skip condition
2486 * of the given type.
2488 struct pet_expr *pet_scop_get_skip_expr(struct pet_scop *scop,
2489 enum pet_skip type)
2491 return pet_expr_from_access(pet_scop_get_skip_map(scop, type));
2494 /* Drop the the skip condition scop->skip[type].
2496 void pet_scop_reset_skip(struct pet_scop *scop, enum pet_skip type)
2498 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2500 if (!scop)
2501 return;
2503 isl_set_free(ext->skip[type]);
2504 ext->skip[type] = NULL;
2507 /* Make the skip condition (if any) depend on the value of "test" being
2508 * equal to "satisfied".
2510 * We only support the case where the original skip condition is universal,
2511 * i.e., where skipping is unconditional, and where satisfied == 1.
2512 * In this case, the skip condition is changed to skip only when
2513 * "test" is equal to one.
2515 static struct pet_scop *pet_scop_filter_skip(struct pet_scop *scop,
2516 enum pet_skip type, __isl_keep isl_map *test, int satisfied)
2518 int is_univ = 0;
2520 if (!scop)
2521 return NULL;
2522 if (!pet_scop_has_skip(scop, type))
2523 return scop;
2525 if (satisfied)
2526 is_univ = pet_scop_has_universal_skip(scop, type);
2527 if (is_univ < 0)
2528 return pet_scop_free(scop);
2529 if (satisfied && is_univ) {
2530 scop = pet_scop_set_skip(scop, type,
2531 isl_map_range(isl_map_copy(test)));
2532 if (!scop)
2533 return NULL;
2534 } else {
2535 isl_die(isl_map_get_ctx(test), isl_error_internal,
2536 "skip expression cannot be filtered",
2537 return pet_scop_free(scop));
2540 return scop;
2543 /* Make all statements in "scop" depend on the value of "test"
2544 * being equal to "satisfied" by adjusting their domains.
2546 struct pet_scop *pet_scop_filter(struct pet_scop *scop,
2547 __isl_take isl_map *test, int satisfied)
2549 int i;
2551 scop = pet_scop_filter_skip(scop, pet_skip_now, test, satisfied);
2552 scop = pet_scop_filter_skip(scop, pet_skip_later, test, satisfied);
2554 if (!scop || !test)
2555 goto error;
2557 for (i = 0; i < scop->n_stmt; ++i) {
2558 scop->stmts[i] = stmt_filter(scop, scop->stmts[i],
2559 isl_map_copy(test), satisfied);
2560 if (!scop->stmts[i])
2561 goto error;
2564 isl_map_free(test);
2565 return scop;
2566 error:
2567 isl_map_free(test);
2568 return pet_scop_free(scop);
2571 /* Add all parameters in "expr" to "dim" and return the result.
2573 static __isl_give isl_space *expr_collect_params(struct pet_expr *expr,
2574 __isl_take isl_space *dim)
2576 int i;
2578 if (!expr)
2579 goto error;
2580 for (i = 0; i < expr->n_arg; ++i)
2582 dim = expr_collect_params(expr->args[i], dim);
2584 if (expr->type == pet_expr_access)
2585 dim = isl_space_align_params(dim,
2586 isl_map_get_space(expr->acc.access));
2588 return dim;
2589 error:
2590 isl_space_free(dim);
2591 return pet_expr_free(expr);
2594 /* Add all parameters in "stmt" to "dim" and return the result.
2596 static __isl_give isl_space *stmt_collect_params(struct pet_stmt *stmt,
2597 __isl_take isl_space *dim)
2599 if (!stmt)
2600 goto error;
2602 dim = isl_space_align_params(dim, isl_set_get_space(stmt->domain));
2603 dim = isl_space_align_params(dim, isl_map_get_space(stmt->schedule));
2604 dim = expr_collect_params(stmt->body, dim);
2606 return dim;
2607 error:
2608 isl_space_free(dim);
2609 return pet_stmt_free(stmt);
2612 /* Add all parameters in "array" to "dim" and return the result.
2614 static __isl_give isl_space *array_collect_params(struct pet_array *array,
2615 __isl_take isl_space *dim)
2617 if (!array)
2618 goto error;
2620 dim = isl_space_align_params(dim, isl_set_get_space(array->context));
2621 dim = isl_space_align_params(dim, isl_set_get_space(array->extent));
2623 return dim;
2624 error:
2625 pet_array_free(array);
2626 return isl_space_free(dim);
2629 /* Add all parameters in "scop" to "dim" and return the result.
2631 static __isl_give isl_space *scop_collect_params(struct pet_scop *scop,
2632 __isl_take isl_space *dim)
2634 int i;
2636 if (!scop)
2637 goto error;
2639 for (i = 0; i < scop->n_array; ++i)
2640 dim = array_collect_params(scop->arrays[i], dim);
2642 for (i = 0; i < scop->n_stmt; ++i)
2643 dim = stmt_collect_params(scop->stmts[i], dim);
2645 return dim;
2646 error:
2647 isl_space_free(dim);
2648 return pet_scop_free(scop);
2651 /* Add all parameters in "dim" to all access relations in "expr".
2653 static struct pet_expr *expr_propagate_params(struct pet_expr *expr,
2654 __isl_take isl_space *dim)
2656 int i;
2658 if (!expr)
2659 goto error;
2661 for (i = 0; i < expr->n_arg; ++i) {
2662 expr->args[i] =
2663 expr_propagate_params(expr->args[i],
2664 isl_space_copy(dim));
2665 if (!expr->args[i])
2666 goto error;
2669 if (expr->type == pet_expr_access) {
2670 expr->acc.access = isl_map_align_params(expr->acc.access,
2671 isl_space_copy(dim));
2672 if (!expr->acc.access)
2673 goto error;
2676 isl_space_free(dim);
2677 return expr;
2678 error:
2679 isl_space_free(dim);
2680 return pet_expr_free(expr);
2683 /* Add all parameters in "dim" to the domain, schedule and
2684 * all access relations in "stmt".
2686 static struct pet_stmt *stmt_propagate_params(struct pet_stmt *stmt,
2687 __isl_take isl_space *dim)
2689 if (!stmt)
2690 goto error;
2692 stmt->domain = isl_set_align_params(stmt->domain, isl_space_copy(dim));
2693 stmt->schedule = isl_map_align_params(stmt->schedule,
2694 isl_space_copy(dim));
2695 stmt->body = expr_propagate_params(stmt->body, isl_space_copy(dim));
2697 if (!stmt->domain || !stmt->schedule || !stmt->body)
2698 goto error;
2700 isl_space_free(dim);
2701 return stmt;
2702 error:
2703 isl_space_free(dim);
2704 return pet_stmt_free(stmt);
2707 /* Add all parameters in "dim" to "array".
2709 static struct pet_array *array_propagate_params(struct pet_array *array,
2710 __isl_take isl_space *dim)
2712 if (!array)
2713 goto error;
2715 array->context = isl_set_align_params(array->context,
2716 isl_space_copy(dim));
2717 array->extent = isl_set_align_params(array->extent,
2718 isl_space_copy(dim));
2719 if (array->value_bounds) {
2720 array->value_bounds = isl_set_align_params(array->value_bounds,
2721 isl_space_copy(dim));
2722 if (!array->value_bounds)
2723 goto error;
2726 if (!array->context || !array->extent)
2727 goto error;
2729 isl_space_free(dim);
2730 return array;
2731 error:
2732 isl_space_free(dim);
2733 return pet_array_free(array);
2736 /* Add all parameters in "dim" to "scop".
2738 static struct pet_scop *scop_propagate_params(struct pet_scop *scop,
2739 __isl_take isl_space *dim)
2741 int i;
2743 if (!scop)
2744 goto error;
2746 for (i = 0; i < scop->n_array; ++i) {
2747 scop->arrays[i] = array_propagate_params(scop->arrays[i],
2748 isl_space_copy(dim));
2749 if (!scop->arrays[i])
2750 goto error;
2753 for (i = 0; i < scop->n_stmt; ++i) {
2754 scop->stmts[i] = stmt_propagate_params(scop->stmts[i],
2755 isl_space_copy(dim));
2756 if (!scop->stmts[i])
2757 goto error;
2760 isl_space_free(dim);
2761 return scop;
2762 error:
2763 isl_space_free(dim);
2764 return pet_scop_free(scop);
2767 /* Update all isl_sets and isl_maps in "scop" such that they all
2768 * have the same parameters.
2770 struct pet_scop *pet_scop_align_params(struct pet_scop *scop)
2772 isl_space *dim;
2774 if (!scop)
2775 return NULL;
2777 dim = isl_set_get_space(scop->context);
2778 dim = scop_collect_params(scop, dim);
2780 scop->context = isl_set_align_params(scop->context, isl_space_copy(dim));
2781 scop = scop_propagate_params(scop, dim);
2783 return scop;
2786 /* Check if the given access relation accesses a (0D) array that corresponds
2787 * to one of the parameters in "dim". If so, replace the array access
2788 * by an access to the set of integers with as index (and value)
2789 * that parameter.
2791 static __isl_give isl_map *access_detect_parameter(__isl_take isl_map *access,
2792 __isl_take isl_space *dim)
2794 isl_id *array_id = NULL;
2795 int pos = -1;
2797 if (isl_map_has_tuple_id(access, isl_dim_out)) {
2798 array_id = isl_map_get_tuple_id(access, isl_dim_out);
2799 pos = isl_space_find_dim_by_id(dim, isl_dim_param, array_id);
2801 isl_space_free(dim);
2803 if (pos < 0) {
2804 isl_id_free(array_id);
2805 return access;
2808 pos = isl_map_find_dim_by_id(access, isl_dim_param, array_id);
2809 if (pos < 0) {
2810 access = isl_map_insert_dims(access, isl_dim_param, 0, 1);
2811 access = isl_map_set_dim_id(access, isl_dim_param, 0, array_id);
2812 pos = 0;
2813 } else
2814 isl_id_free(array_id);
2816 access = isl_map_insert_dims(access, isl_dim_out, 0, 1);
2817 access = isl_map_equate(access, isl_dim_param, pos, isl_dim_out, 0);
2819 return access;
2822 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
2823 * in "dim" by a value equal to the corresponding parameter.
2825 static struct pet_expr *expr_detect_parameter_accesses(struct pet_expr *expr,
2826 __isl_take isl_space *dim)
2828 int i;
2830 if (!expr)
2831 goto error;
2833 for (i = 0; i < expr->n_arg; ++i) {
2834 expr->args[i] =
2835 expr_detect_parameter_accesses(expr->args[i],
2836 isl_space_copy(dim));
2837 if (!expr->args[i])
2838 goto error;
2841 if (expr->type == pet_expr_access) {
2842 expr->acc.access = access_detect_parameter(expr->acc.access,
2843 isl_space_copy(dim));
2844 if (!expr->acc.access)
2845 goto error;
2848 isl_space_free(dim);
2849 return expr;
2850 error:
2851 isl_space_free(dim);
2852 return pet_expr_free(expr);
2855 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
2856 * in "dim" by a value equal to the corresponding parameter.
2858 static struct pet_stmt *stmt_detect_parameter_accesses(struct pet_stmt *stmt,
2859 __isl_take isl_space *dim)
2861 if (!stmt)
2862 goto error;
2864 stmt->body = expr_detect_parameter_accesses(stmt->body,
2865 isl_space_copy(dim));
2867 if (!stmt->domain || !stmt->schedule || !stmt->body)
2868 goto error;
2870 isl_space_free(dim);
2871 return stmt;
2872 error:
2873 isl_space_free(dim);
2874 return pet_stmt_free(stmt);
2877 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
2878 * in "dim" by a value equal to the corresponding parameter.
2880 static struct pet_scop *scop_detect_parameter_accesses(struct pet_scop *scop,
2881 __isl_take isl_space *dim)
2883 int i;
2885 if (!scop)
2886 goto error;
2888 for (i = 0; i < scop->n_stmt; ++i) {
2889 scop->stmts[i] = stmt_detect_parameter_accesses(scop->stmts[i],
2890 isl_space_copy(dim));
2891 if (!scop->stmts[i])
2892 goto error;
2895 isl_space_free(dim);
2896 return scop;
2897 error:
2898 isl_space_free(dim);
2899 return pet_scop_free(scop);
2902 /* Replace all accesses to (0D) arrays that correspond to any of
2903 * the parameters used in "scop" by a value equal
2904 * to the corresponding parameter.
2906 struct pet_scop *pet_scop_detect_parameter_accesses(struct pet_scop *scop)
2908 isl_space *dim;
2910 if (!scop)
2911 return NULL;
2913 dim = isl_set_get_space(scop->context);
2914 dim = scop_collect_params(scop, dim);
2916 scop = scop_detect_parameter_accesses(scop, dim);
2918 return scop;
2921 /* Add all read access relations (if "read" is set) and/or all write
2922 * access relations (if "write" is set) to "accesses" and return the result.
2924 static __isl_give isl_union_map *expr_collect_accesses(struct pet_expr *expr,
2925 int read, int write, __isl_take isl_union_map *accesses)
2927 int i;
2928 isl_id *id;
2929 isl_space *dim;
2931 if (!expr)
2932 return NULL;
2934 for (i = 0; i < expr->n_arg; ++i)
2935 accesses = expr_collect_accesses(expr->args[i],
2936 read, write, accesses);
2938 if (expr->type == pet_expr_access && !pet_expr_is_affine(expr) &&
2939 ((read && expr->acc.read) || (write && expr->acc.write)))
2940 accesses = isl_union_map_add_map(accesses,
2941 isl_map_copy(expr->acc.access));
2943 return accesses;
2946 /* Collect and return all read access relations (if "read" is set)
2947 * and/or all write access relations (if "write" is set) in "stmt".
2949 static __isl_give isl_union_map *stmt_collect_accesses(struct pet_stmt *stmt,
2950 int read, int write, __isl_take isl_space *dim)
2952 isl_union_map *accesses;
2954 if (!stmt)
2955 return NULL;
2957 accesses = isl_union_map_empty(dim);
2958 accesses = expr_collect_accesses(stmt->body, read, write, accesses);
2959 accesses = isl_union_map_intersect_domain(accesses,
2960 isl_union_set_from_set(isl_set_copy(stmt->domain)));
2962 return accesses;
2965 /* Collect and return all read access relations (if "read" is set)
2966 * and/or all write access relations (if "write" is set) in "scop".
2968 static __isl_give isl_union_map *scop_collect_accesses(struct pet_scop *scop,
2969 int read, int write)
2971 int i;
2972 isl_union_map *accesses;
2974 if (!scop)
2975 return NULL;
2977 accesses = isl_union_map_empty(isl_set_get_space(scop->context));
2979 for (i = 0; i < scop->n_stmt; ++i) {
2980 isl_union_map *accesses_i;
2981 isl_space *dim = isl_set_get_space(scop->context);
2982 accesses_i = stmt_collect_accesses(scop->stmts[i],
2983 read, write, dim);
2984 accesses = isl_union_map_union(accesses, accesses_i);
2987 return accesses;
2990 __isl_give isl_union_map *pet_scop_collect_reads(struct pet_scop *scop)
2992 return scop_collect_accesses(scop, 1, 0);
2995 __isl_give isl_union_map *pet_scop_collect_writes(struct pet_scop *scop)
2997 return scop_collect_accesses(scop, 0, 1);
3000 /* Collect and return the union of iteration domains in "scop".
3002 __isl_give isl_union_set *pet_scop_collect_domains(struct pet_scop *scop)
3004 int i;
3005 isl_set *domain_i;
3006 isl_union_set *domain;
3008 if (!scop)
3009 return NULL;
3011 domain = isl_union_set_empty(isl_set_get_space(scop->context));
3013 for (i = 0; i < scop->n_stmt; ++i) {
3014 domain_i = isl_set_copy(scop->stmts[i]->domain);
3015 domain = isl_union_set_add_set(domain, domain_i);
3018 return domain;
3021 /* Collect and return the schedules of the statements in "scop".
3022 * The range is normalized to the maximal number of scheduling
3023 * dimensions.
3025 __isl_give isl_union_map *pet_scop_collect_schedule(struct pet_scop *scop)
3027 int i, j;
3028 isl_map *schedule_i;
3029 isl_union_map *schedule;
3030 int depth, max_depth = 0;
3032 if (!scop)
3033 return NULL;
3035 schedule = isl_union_map_empty(isl_set_get_space(scop->context));
3037 for (i = 0; i < scop->n_stmt; ++i) {
3038 depth = isl_map_dim(scop->stmts[i]->schedule, isl_dim_out);
3039 if (depth > max_depth)
3040 max_depth = depth;
3043 for (i = 0; i < scop->n_stmt; ++i) {
3044 schedule_i = isl_map_copy(scop->stmts[i]->schedule);
3045 depth = isl_map_dim(schedule_i, isl_dim_out);
3046 schedule_i = isl_map_add_dims(schedule_i, isl_dim_out,
3047 max_depth - depth);
3048 for (j = depth; j < max_depth; ++j)
3049 schedule_i = isl_map_fix_si(schedule_i,
3050 isl_dim_out, j, 0);
3051 schedule = isl_union_map_add_map(schedule, schedule_i);
3054 return schedule;
3057 /* Does expression "expr" write to "id"?
3059 static int expr_writes(struct pet_expr *expr, __isl_keep isl_id *id)
3061 int i;
3062 isl_id *write_id;
3064 for (i = 0; i < expr->n_arg; ++i) {
3065 int writes = expr_writes(expr->args[i], id);
3066 if (writes < 0 || writes)
3067 return writes;
3070 if (expr->type != pet_expr_access)
3071 return 0;
3072 if (!expr->acc.write)
3073 return 0;
3074 if (pet_expr_is_affine(expr))
3075 return 0;
3077 write_id = pet_expr_access_get_id(expr);
3078 isl_id_free(write_id);
3080 if (!write_id)
3081 return -1;
3083 return write_id == id;
3086 /* Does statement "stmt" write to "id"?
3088 static int stmt_writes(struct pet_stmt *stmt, __isl_keep isl_id *id)
3090 return expr_writes(stmt->body, id);
3093 /* Is there any write access in "scop" that accesses "id"?
3095 int pet_scop_writes(struct pet_scop *scop, __isl_keep isl_id *id)
3097 int i;
3099 if (!scop)
3100 return -1;
3102 for (i = 0; i < scop->n_stmt; ++i) {
3103 int writes = stmt_writes(scop->stmts[i], id);
3104 if (writes < 0 || writes)
3105 return writes;
3108 return 0;
3111 /* Add a reference identifier to access expression "expr".
3112 * "user" points to an integer that contains the sequence number
3113 * of the next reference.
3115 static struct pet_expr *access_add_ref_id(struct pet_expr *expr, void *user)
3117 isl_ctx *ctx;
3118 char name[50];
3119 int *n_ref = user;
3121 if (!expr)
3122 return expr;
3124 ctx = isl_map_get_ctx(expr->acc.access);
3125 snprintf(name, sizeof(name), "__pet_ref_%d", (*n_ref)++);
3126 expr->acc.ref_id = isl_id_alloc(ctx, name, NULL);
3127 if (!expr->acc.ref_id)
3128 return pet_expr_free(expr);
3130 return expr;
3133 /* Add a reference identifier to all access expressions in "stmt".
3134 * "n_ref" points to an integer that contains the sequence number
3135 * of the next reference.
3137 static struct pet_stmt *stmt_add_ref_ids(struct pet_stmt *stmt, int *n_ref)
3139 int i;
3141 if (!stmt)
3142 return NULL;
3144 for (i = 0; i < stmt->n_arg; ++i) {
3145 stmt->args[i] = pet_expr_map_access(stmt->args[i],
3146 &access_add_ref_id, n_ref);
3147 if (!stmt->args[i])
3148 return pet_stmt_free(stmt);
3151 stmt->body = pet_expr_map_access(stmt->body, &access_add_ref_id, n_ref);
3152 if (!stmt->body)
3153 return pet_stmt_free(stmt);
3155 return stmt;
3158 /* Add a reference identifier to all access expressions in "scop".
3160 struct pet_scop *pet_scop_add_ref_ids(struct pet_scop *scop)
3162 int i;
3163 int n_ref;
3165 if (!scop)
3166 return NULL;
3168 n_ref = 0;
3169 for (i = 0; i < scop->n_stmt; ++i) {
3170 scop->stmts[i] = stmt_add_ref_ids(scop->stmts[i], &n_ref);
3171 if (!scop->stmts[i])
3172 return pet_scop_free(scop);
3175 return scop;
3178 /* Reset the user pointer on the tuple id and all parameter ids in "set".
3180 static __isl_give isl_set *set_anonymize(__isl_take isl_set *set)
3182 int i, n;
3184 n = isl_set_dim(set, isl_dim_param);
3185 for (i = 0; i < n; ++i) {
3186 isl_id *id = isl_set_get_dim_id(set, isl_dim_param, i);
3187 const char *name = isl_id_get_name(id);
3188 set = isl_set_set_dim_name(set, isl_dim_param, i, name);
3189 isl_id_free(id);
3192 if (!isl_set_is_params(set) && isl_set_has_tuple_id(set)) {
3193 isl_id *id = isl_set_get_tuple_id(set);
3194 const char *name = isl_id_get_name(id);
3195 set = isl_set_set_tuple_name(set, name);
3196 isl_id_free(id);
3199 return set;
3202 /* Reset the user pointer on the tuple ids and all parameter ids in "map".
3204 static __isl_give isl_map *map_anonymize(__isl_take isl_map *map)
3206 int i, n;
3208 n = isl_map_dim(map, isl_dim_param);
3209 for (i = 0; i < n; ++i) {
3210 isl_id *id = isl_map_get_dim_id(map, isl_dim_param, i);
3211 const char *name = isl_id_get_name(id);
3212 map = isl_map_set_dim_name(map, isl_dim_param, i, name);
3213 isl_id_free(id);
3216 if (isl_map_has_tuple_id(map, isl_dim_in)) {
3217 isl_id *id = isl_map_get_tuple_id(map, isl_dim_in);
3218 const char *name = isl_id_get_name(id);
3219 map = isl_map_set_tuple_name(map, isl_dim_in, name);
3220 isl_id_free(id);
3223 if (isl_map_has_tuple_id(map, isl_dim_out)) {
3224 isl_id *id = isl_map_get_tuple_id(map, isl_dim_out);
3225 const char *name = isl_id_get_name(id);
3226 map = isl_map_set_tuple_name(map, isl_dim_out, name);
3227 isl_id_free(id);
3230 return map;
3233 /* Reset the user pointer on all parameter ids in "array".
3235 static struct pet_array *array_anonymize(struct pet_array *array)
3237 if (!array)
3238 return NULL;
3240 array->context = set_anonymize(array->context);
3241 array->extent = set_anonymize(array->extent);
3242 if (!array->context || !array->extent)
3243 return pet_array_free(array);
3245 return array;
3248 /* Reset the user pointer on all parameter and tuple ids in
3249 * the access relation of the access expression "expr".
3251 static struct pet_expr *access_anonymize(struct pet_expr *expr, void *user)
3253 expr->acc.access = map_anonymize(expr->acc.access);
3254 if (!expr->acc.access)
3255 return pet_expr_free(expr);
3257 return expr;
3260 /* Reset the user pointer on all parameter and tuple ids in "stmt".
3262 static struct pet_stmt *stmt_anonymize(struct pet_stmt *stmt)
3264 int i;
3265 isl_space *space;
3266 isl_set *domain;
3268 if (!stmt)
3269 return NULL;
3271 stmt->domain = set_anonymize(stmt->domain);
3272 stmt->schedule = map_anonymize(stmt->schedule);
3273 if (!stmt->domain || !stmt->schedule)
3274 return pet_stmt_free(stmt);
3276 for (i = 0; i < stmt->n_arg; ++i) {
3277 stmt->args[i] = pet_expr_map_access(stmt->args[i],
3278 &access_anonymize, NULL);
3279 if (!stmt->args[i])
3280 return pet_stmt_free(stmt);
3283 stmt->body = pet_expr_map_access(stmt->body,
3284 &access_anonymize, NULL);
3285 if (!stmt->body)
3286 return pet_stmt_free(stmt);
3288 return stmt;
3291 /* Reset the user pointer on the tuple ids and all parameter ids
3292 * in "implication".
3294 static struct pet_implication *implication_anonymize(
3295 struct pet_implication *implication)
3297 if (!implication)
3298 return NULL;
3300 implication->extension = map_anonymize(implication->extension);
3301 if (!implication->extension)
3302 return pet_implication_free(implication);
3304 return implication;
3307 /* Reset the user pointer on all parameter and tuple ids in "scop".
3309 struct pet_scop *pet_scop_anonymize(struct pet_scop *scop)
3311 int i;
3313 if (!scop)
3314 return NULL;
3316 scop->context = set_anonymize(scop->context);
3317 scop->context_value = set_anonymize(scop->context_value);
3318 if (!scop->context || !scop->context_value)
3319 return pet_scop_free(scop);
3321 for (i = 0; i < scop->n_array; ++i) {
3322 scop->arrays[i] = array_anonymize(scop->arrays[i]);
3323 if (!scop->arrays[i])
3324 return pet_scop_free(scop);
3327 for (i = 0; i < scop->n_stmt; ++i) {
3328 scop->stmts[i] = stmt_anonymize(scop->stmts[i]);
3329 if (!scop->stmts[i])
3330 return pet_scop_free(scop);
3333 for (i = 0; i < scop->n_implication; ++i) {
3334 scop->implications[i] =
3335 implication_anonymize(scop->implications[i]);
3336 if (!scop->implications[i])
3337 return pet_scop_free(scop);
3340 return scop;
3343 /* If "value_bounds" contains any bounds on the variable accessed by "arg",
3344 * then intersect the range of "map" with the valid set of values.
3346 static __isl_give isl_map *access_apply_value_bounds(__isl_take isl_map *map,
3347 struct pet_expr *arg, __isl_keep isl_union_map *value_bounds)
3349 isl_id *id;
3350 isl_map *vb;
3351 isl_space *space;
3352 isl_ctx *ctx = isl_map_get_ctx(map);
3354 id = pet_expr_access_get_id(arg);
3355 space = isl_space_alloc(ctx, 0, 0, 1);
3356 space = isl_space_set_tuple_id(space, isl_dim_in, id);
3357 vb = isl_union_map_extract_map(value_bounds, space);
3358 if (!isl_map_plain_is_empty(vb))
3359 map = isl_map_intersect_range(map, isl_map_range(vb));
3360 else
3361 isl_map_free(vb);
3363 return map;
3366 /* Given a set "domain", return a wrapped relation with the given set
3367 * as domain and a range of dimension "n_arg", where each coordinate
3368 * is either unbounded or, if the corresponding element of args is of
3369 * type pet_expr_access, bounded by the bounds specified by "value_bounds".
3371 static __isl_give isl_set *apply_value_bounds(__isl_take isl_set *domain,
3372 unsigned n_arg, struct pet_expr **args,
3373 __isl_keep isl_union_map *value_bounds)
3375 int i;
3376 isl_map *map;
3377 isl_space *space;
3379 map = isl_map_from_domain(domain);
3380 space = isl_map_get_space(map);
3381 space = isl_space_add_dims(space, isl_dim_out, 1);
3383 for (i = 0; i < n_arg; ++i) {
3384 isl_map *map_i;
3385 struct pet_expr *arg = args[i];
3387 map_i = isl_map_universe(isl_space_copy(space));
3388 if (arg->type == pet_expr_access)
3389 map_i = access_apply_value_bounds(map_i, arg,
3390 value_bounds);
3391 map = isl_map_flat_range_product(map, map_i);
3393 isl_space_free(space);
3395 return isl_map_wrap(map);
3398 /* Data used in access_gist() callback.
3400 struct pet_access_gist_data {
3401 isl_set *domain;
3402 isl_union_map *value_bounds;
3405 /* Given an expression "expr" of type pet_expr_access, compute
3406 * the gist of the associated access relation with respect to
3407 * data->domain and the bounds on the values of the arguments
3408 * of the expression.
3410 static struct pet_expr *access_gist(struct pet_expr *expr, void *user)
3412 struct pet_access_gist_data *data = user;
3413 isl_set *domain;
3415 domain = isl_set_copy(data->domain);
3416 if (expr->n_arg > 0)
3417 domain = apply_value_bounds(domain, expr->n_arg, expr->args,
3418 data->value_bounds);
3420 expr->acc.access = isl_map_gist_domain(expr->acc.access, domain);
3421 if (!expr->acc.access)
3422 return pet_expr_free(expr);
3424 return expr;
3427 /* Compute the gist of the iteration domain and all access relations
3428 * of "stmt" based on the constraints on the parameters specified by "context"
3429 * and the constraints on the values of nested accesses specified
3430 * by "value_bounds".
3432 static struct pet_stmt *stmt_gist(struct pet_stmt *stmt,
3433 __isl_keep isl_set *context, __isl_keep isl_union_map *value_bounds)
3435 int i;
3436 isl_space *space;
3437 isl_set *domain;
3438 struct pet_access_gist_data data;
3440 if (!stmt)
3441 return NULL;
3443 data.domain = isl_set_copy(stmt->domain);
3444 data.value_bounds = value_bounds;
3445 if (stmt->n_arg > 0)
3446 data.domain = isl_map_domain(isl_set_unwrap(data.domain));
3448 data.domain = isl_set_intersect_params(data.domain,
3449 isl_set_copy(context));
3451 for (i = 0; i < stmt->n_arg; ++i) {
3452 stmt->args[i] = pet_expr_map_access(stmt->args[i],
3453 &access_gist, &data);
3454 if (!stmt->args[i])
3455 goto error;
3458 stmt->body = pet_expr_map_access(stmt->body, &access_gist, &data);
3459 if (!stmt->body)
3460 goto error;
3462 isl_set_free(data.domain);
3464 space = isl_set_get_space(stmt->domain);
3465 if (isl_space_is_wrapping(space))
3466 space = isl_space_domain(isl_space_unwrap(space));
3467 domain = isl_set_universe(space);
3468 domain = isl_set_intersect_params(domain, isl_set_copy(context));
3469 if (stmt->n_arg > 0)
3470 domain = apply_value_bounds(domain, stmt->n_arg, stmt->args,
3471 value_bounds);
3472 stmt->domain = isl_set_gist(stmt->domain, domain);
3473 if (!stmt->domain)
3474 return pet_stmt_free(stmt);
3476 return stmt;
3477 error:
3478 isl_set_free(data.domain);
3479 return pet_stmt_free(stmt);
3482 /* Compute the gist of the extent of the array
3483 * based on the constraints on the parameters specified by "context".
3485 static struct pet_array *array_gist(struct pet_array *array,
3486 __isl_keep isl_set *context)
3488 if (!array)
3489 return NULL;
3491 array->extent = isl_set_gist_params(array->extent,
3492 isl_set_copy(context));
3493 if (!array->extent)
3494 return pet_array_free(array);
3496 return array;
3499 /* Compute the gist of all sets and relations in "scop"
3500 * based on the constraints on the parameters specified by "scop->context"
3501 * and the constraints on the values of nested accesses specified
3502 * by "value_bounds".
3504 struct pet_scop *pet_scop_gist(struct pet_scop *scop,
3505 __isl_keep isl_union_map *value_bounds)
3507 int i;
3509 if (!scop)
3510 return NULL;
3512 scop->context = isl_set_coalesce(scop->context);
3513 if (!scop->context)
3514 return pet_scop_free(scop);
3516 for (i = 0; i < scop->n_array; ++i) {
3517 scop->arrays[i] = array_gist(scop->arrays[i], scop->context);
3518 if (!scop->arrays[i])
3519 return pet_scop_free(scop);
3522 for (i = 0; i < scop->n_stmt; ++i) {
3523 scop->stmts[i] = stmt_gist(scop->stmts[i], scop->context,
3524 value_bounds);
3525 if (!scop->stmts[i])
3526 return pet_scop_free(scop);
3529 return scop;
3532 /* Intersect the context of "scop" with "context".
3533 * To ensure that we don't introduce any unnamed parameters in
3534 * the context of "scop", we first remove the unnamed parameters
3535 * from "context".
3537 struct pet_scop *pet_scop_restrict_context(struct pet_scop *scop,
3538 __isl_take isl_set *context)
3540 if (!scop)
3541 goto error;
3543 context = set_project_out_unnamed_params(context);
3544 scop->context = isl_set_intersect(scop->context, context);
3545 if (!scop->context)
3546 return pet_scop_free(scop);
3548 return scop;
3549 error:
3550 isl_set_free(context);
3551 return pet_scop_free(scop);
3554 /* Drop the current context of "scop". That is, replace the context
3555 * by a universal set.
3557 struct pet_scop *pet_scop_reset_context(struct pet_scop *scop)
3559 isl_space *space;
3561 if (!scop)
3562 return NULL;
3564 space = isl_set_get_space(scop->context);
3565 isl_set_free(scop->context);
3566 scop->context = isl_set_universe(space);
3567 if (!scop->context)
3568 return pet_scop_free(scop);
3570 return scop;
3573 /* Append "array" to the arrays of "scop".
3575 struct pet_scop *pet_scop_add_array(struct pet_scop *scop,
3576 struct pet_array *array)
3578 isl_ctx *ctx;
3579 struct pet_array **arrays;
3581 if (!array || !scop)
3582 goto error;
3584 ctx = isl_set_get_ctx(scop->context);
3585 arrays = isl_realloc_array(ctx, scop->arrays, struct pet_array *,
3586 scop->n_array + 1);
3587 if (!arrays)
3588 goto error;
3589 scop->arrays = arrays;
3590 scop->arrays[scop->n_array] = array;
3591 scop->n_array++;
3593 return scop;
3594 error:
3595 pet_array_free(array);
3596 return pet_scop_free(scop);
3599 /* Create and return an implication on filter values equal to "satisfied"
3600 * with extension "map".
3602 static struct pet_implication *new_implication(__isl_take isl_map *map,
3603 int satisfied)
3605 isl_ctx *ctx;
3606 struct pet_implication *implication;
3608 if (!map)
3609 return NULL;
3610 ctx = isl_map_get_ctx(map);
3611 implication = isl_alloc_type(ctx, struct pet_implication);
3612 if (!implication)
3613 goto error;
3615 implication->extension = map;
3616 implication->satisfied = satisfied;
3618 return implication;
3619 error:
3620 isl_map_free(map);
3621 return NULL;
3624 /* Add an implication on filter values equal to "satisfied"
3625 * with extension "map" to "scop".
3627 struct pet_scop *pet_scop_add_implication(struct pet_scop *scop,
3628 __isl_take isl_map *map, int satisfied)
3630 isl_ctx *ctx;
3631 struct pet_implication *implication;
3632 struct pet_implication **implications;
3634 implication = new_implication(map, satisfied);
3635 if (!scop || !implication)
3636 goto error;
3638 ctx = isl_set_get_ctx(scop->context);
3639 implications = isl_realloc_array(ctx, scop->implications,
3640 struct pet_implication *,
3641 scop->n_implication + 1);
3642 if (!implications)
3643 goto error;
3644 scop->implications = implications;
3645 scop->implications[scop->n_implication] = implication;
3646 scop->n_implication++;
3648 return scop;
3649 error:
3650 pet_implication_free(implication);
3651 return pet_scop_free(scop);