scop.c: implies_filter: avoid using access relation
[pet.git] / scop.c
blob984a4fc74bec78d0e2c9da34e069fb8298564976
1 /*
2 * Copyright 2011 Leiden University. All rights reserved.
3 * Copyright 2012-2014 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 "aff.h"
40 #include "expr.h"
41 #include "filter.h"
42 #include "loc.h"
43 #include "nest.h"
44 #include "scop.h"
45 #include "tree.h"
46 #include "print.h"
47 #include "value_bounds.h"
49 /* pet_scop with extra information that is used during parsing and printing.
51 * In particular, we keep track of conditions under which we want
52 * to skip the rest of the current loop iteration (skip[pet_skip_now])
53 * and of conditions under which we want to skip subsequent
54 * loop iterations (skip[pet_skip_later]).
56 * The conditions are represented as index expressions defined
57 * over the outer loop iterators. The index expression is either
58 * a boolean affine expression or an access to a variable, which
59 * is assumed to attain values zero and one. The condition holds
60 * if the variable has value one or if the affine expression
61 * has value one (typically for only part of the domain).
63 * A missing condition (skip[type] == NULL) means that we don't want
64 * to skip anything.
66 * Additionally, we keep track of the original input file
67 * inside pet_transform_C_source.
69 struct pet_scop_ext {
70 struct pet_scop scop;
72 isl_multi_pw_aff *skip[2];
73 FILE *input;
76 /* Construct a pet_stmt with given domain and statement number from a pet_tree.
77 * The input domain is anonymous and is the same as the domains
78 * of the access expressions inside "tree".
79 * These domains are modified to include the name of the statement.
80 * This name is given by tree->label if it is non-NULL.
81 * Otherwise, the name is constructed as S_<id>.
83 struct pet_stmt *pet_stmt_from_pet_tree(__isl_take isl_set *domain,
84 int id, __isl_take pet_tree *tree)
86 struct pet_stmt *stmt;
87 isl_ctx *ctx;
88 isl_id *label;
89 isl_space *space;
90 isl_map *sched;
91 isl_multi_aff *ma;
92 isl_multi_pw_aff *add_name;
93 char name[50];
95 if (!domain || !tree)
96 goto error;
98 ctx = pet_tree_get_ctx(tree);
99 stmt = isl_calloc_type(ctx, struct pet_stmt);
100 if (!stmt)
101 goto error;
103 if (tree->label) {
104 label = isl_id_copy(tree->label);
105 } else {
106 snprintf(name, sizeof(name), "S_%d", id);
107 label = isl_id_alloc(ctx, name, NULL);
109 domain = isl_set_set_tuple_id(domain, label);
110 space = isl_set_get_space(domain);
111 space = pet_nested_remove_from_space(space);
112 sched = isl_map_universe(isl_space_from_domain(isl_space_copy(space)));
113 ma = pet_prefix_projection(space, isl_space_dim(space, isl_dim_set));
115 add_name = isl_multi_pw_aff_from_multi_aff(ma);
116 tree = pet_tree_update_domain(tree, add_name);
118 stmt->loc = pet_tree_get_loc(tree);
119 stmt->domain = domain;
120 stmt->schedule = sched;
121 stmt->body = tree;
123 if (!stmt->domain || !stmt->schedule || !stmt->body)
124 return pet_stmt_free(stmt);
126 return stmt;
127 error:
128 isl_set_free(domain);
129 pet_tree_free(tree);
130 return NULL;
133 void *pet_stmt_free(struct pet_stmt *stmt)
135 int i;
137 if (!stmt)
138 return NULL;
140 pet_loc_free(stmt->loc);
141 isl_set_free(stmt->domain);
142 isl_map_free(stmt->schedule);
143 pet_tree_free(stmt->body);
145 for (i = 0; i < stmt->n_arg; ++i)
146 pet_expr_free(stmt->args[i]);
147 free(stmt->args);
149 free(stmt);
150 return NULL;
153 /* Return the iteration space of "stmt".
155 * If the statement has arguments, then stmt->domain is a wrapped map
156 * mapping the iteration domain to the values of the arguments
157 * for which this statement is executed.
158 * In this case, we need to extract the domain space of this wrapped map.
160 __isl_give isl_space *pet_stmt_get_space(struct pet_stmt *stmt)
162 isl_space *space;
164 if (!stmt)
165 return NULL;
167 space = isl_set_get_space(stmt->domain);
168 if (isl_space_is_wrapping(space))
169 space = isl_space_domain(isl_space_unwrap(space));
171 return space;
174 static void stmt_dump(struct pet_stmt *stmt, int indent)
176 int i;
178 if (!stmt)
179 return;
181 fprintf(stderr, "%*s%d\n", indent, "", pet_loc_get_line(stmt->loc));
182 fprintf(stderr, "%*s", indent, "");
183 isl_set_dump(stmt->domain);
184 fprintf(stderr, "%*s", indent, "");
185 isl_map_dump(stmt->schedule);
186 pet_tree_dump_with_indent(stmt->body, indent);
187 for (i = 0; i < stmt->n_arg; ++i)
188 pet_expr_dump_with_indent(stmt->args[i], indent + 2);
191 void pet_stmt_dump(struct pet_stmt *stmt)
193 stmt_dump(stmt, 0);
196 /* Allocate a new pet_type with the given "name" and "definition".
198 struct pet_type *pet_type_alloc(isl_ctx *ctx, const char *name,
199 const char *definition)
201 struct pet_type *type;
203 type = isl_alloc_type(ctx, struct pet_type);
204 if (!type)
205 return NULL;
207 type->name = strdup(name);
208 type->definition = strdup(definition);
210 if (!type->name || !type->definition)
211 return pet_type_free(type);
213 return type;
216 /* Free "type" and return NULL.
218 struct pet_type *pet_type_free(struct pet_type *type)
220 if (!type)
221 return NULL;
223 free(type->name);
224 free(type->definition);
226 free(type);
227 return NULL;
230 struct pet_array *pet_array_free(struct pet_array *array)
232 if (!array)
233 return NULL;
235 isl_set_free(array->context);
236 isl_set_free(array->extent);
237 isl_set_free(array->value_bounds);
238 free(array->element_type);
240 free(array);
241 return NULL;
244 void pet_array_dump(struct pet_array *array)
246 if (!array)
247 return;
249 isl_set_dump(array->context);
250 isl_set_dump(array->extent);
251 isl_set_dump(array->value_bounds);
252 fprintf(stderr, "%s%s%s\n", array->element_type,
253 array->element_is_record ? " element-is-record" : "",
254 array->live_out ? " live-out" : "");
257 /* Alloc a pet_scop structure, with extra room for information that
258 * is only used during parsing.
260 struct pet_scop *pet_scop_alloc(isl_ctx *ctx)
262 return &isl_calloc_type(ctx, struct pet_scop_ext)->scop;
265 /* Construct a pet_scop in the given space and with room for n statements.
267 * The context is initialized as a universe set in "space".
269 * Since no information on the location is known at this point,
270 * scop->loc is initialized with pet_loc_dummy.
272 static struct pet_scop *scop_alloc(__isl_take isl_space *space, int n)
274 isl_ctx *ctx;
275 struct pet_scop *scop;
277 if (!space)
278 return NULL;
280 ctx = isl_space_get_ctx(space);
281 scop = pet_scop_alloc(ctx);
282 if (!scop)
283 return NULL;
285 scop->context = isl_set_universe(isl_space_copy(space));
286 scop->context_value = isl_set_universe(isl_space_params(space));
287 scop->stmts = isl_calloc_array(ctx, struct pet_stmt *, n);
288 if (!scop->context || !scop->stmts)
289 return pet_scop_free(scop);
291 scop->loc = &pet_loc_dummy;
292 scop->n_stmt = n;
294 return scop;
297 /* Construct a pet_scop in the given space containing 0 statements.
299 struct pet_scop *pet_scop_empty(__isl_take isl_space *space)
301 return scop_alloc(space, 0);
304 /* Given either an iteration domain or a wrapped map with
305 * the iteration domain in the domain and some arguments
306 * in the range, return the iteration domain.
307 * That is, drop the arguments if there are any.
309 static __isl_give isl_set *drop_arguments(__isl_take isl_set *domain)
311 if (isl_set_is_wrapping(domain))
312 domain = isl_map_domain(isl_set_unwrap(domain));
313 return domain;
316 /* Update "context" with the constraints imposed on the outer iteration
317 * domain by access expression "expr".
318 * "context" lives in an anonymous space, while the domain of the access
319 * relation of "expr" refers to a particular statement.
320 * This reference therefore needs to be stripped off.
322 static __isl_give isl_set *access_extract_context(__isl_keep pet_expr *expr,
323 __isl_take isl_set *context)
325 isl_multi_pw_aff *mpa;
326 isl_set *domain;
328 mpa = pet_expr_access_get_index(expr);
329 domain = drop_arguments(isl_multi_pw_aff_domain(mpa));
330 domain = isl_set_reset_tuple_id(domain);
331 context = isl_set_intersect(context, domain);
332 return context;
335 /* Update "context" with the constraints imposed on the outer iteration
336 * domain by "expr".
338 * "context" lives in an anonymous space, while the domains of
339 * the access relations in "expr" refer to a particular statement.
340 * This reference therefore needs to be stripped off.
342 * If "expr" represents a conditional operator, then a parameter or outer
343 * iterator value needs to be valid for the condition and
344 * for at least one of the remaining two arguments.
345 * If the condition is an affine expression, then we can be a bit more specific.
346 * The value then has to be valid for the second argument for
347 * non-zero accesses and valid for the third argument for zero accesses.
349 * If "expr" represents a kill statement, then its argument is the entire
350 * extent of the array being killed. Do not update "context" based
351 * on this argument as that would impose constraints that ensure that
352 * the array is non-empty.
354 static __isl_give isl_set *expr_extract_context(__isl_keep pet_expr *expr,
355 __isl_take isl_set *context)
357 int i;
359 if (expr->type == pet_expr_op && expr->op == pet_op_kill)
360 return context;
362 if (expr->type == pet_expr_op && expr->op == pet_op_cond) {
363 int is_aff;
364 isl_set *context1, *context2;
366 is_aff = pet_expr_is_affine(expr->args[0]);
367 if (is_aff < 0)
368 goto error;
370 context = expr_extract_context(expr->args[0], context);
371 context1 = expr_extract_context(expr->args[1],
372 isl_set_copy(context));
373 context2 = expr_extract_context(expr->args[2], context);
375 if (is_aff) {
376 isl_multi_pw_aff *mpa;
377 isl_pw_aff *pa;
378 isl_set *zero_set;
380 mpa = pet_expr_access_get_index(expr->args[0]);
381 pa = isl_multi_pw_aff_get_pw_aff(mpa, 0);
382 isl_multi_pw_aff_free(mpa);
383 zero_set = drop_arguments(isl_pw_aff_zero_set(pa));
384 zero_set = isl_set_reset_tuple_id(zero_set);
385 context1 = isl_set_subtract(context1,
386 isl_set_copy(zero_set));
387 context2 = isl_set_intersect(context2, zero_set);
390 context = isl_set_union(context1, context2);
391 context = isl_set_coalesce(context);
393 return context;
396 for (i = 0; i < expr->n_arg; ++i)
397 context = expr_extract_context(expr->args[i], context);
399 if (expr->type == pet_expr_access)
400 context = access_extract_context(expr, context);
402 return context;
403 error:
404 isl_set_free(context);
405 return NULL;
408 /* Is "stmt" an assume statement with an affine assumption?
410 int pet_stmt_is_affine_assume(struct pet_stmt *stmt)
412 if (!stmt)
413 return 0;
414 return pet_tree_is_affine_assume(stmt->body);
417 /* Given an assume statement "stmt" with an access argument,
418 * return the index expression of the argument.
420 __isl_give isl_multi_pw_aff *pet_stmt_assume_get_index(struct pet_stmt *stmt)
422 if (!stmt)
423 return NULL;
424 return pet_tree_assume_get_index(stmt->body);
427 /* Update "context" with the constraints imposed on the outer iteration
428 * domain by "stmt".
430 * If the statement is an assume statement with an affine expression,
431 * then intersect "context" with that expression.
432 * Otherwise, if the statement body is an expression tree,
433 * then intersect "context" with the context of this expression.
434 * Note that we cannot safely extract a context from subtrees
435 * of the statement body since we cannot tell when those subtrees
436 * are executed, if at all.
438 static __isl_give isl_set *stmt_extract_context(struct pet_stmt *stmt,
439 __isl_take isl_set *context)
441 int i;
442 pet_expr *body;
444 if (pet_stmt_is_affine_assume(stmt)) {
445 isl_multi_pw_aff *index;
446 isl_pw_aff *pa;
447 isl_set *cond;
449 index = pet_stmt_assume_get_index(stmt);
450 pa = isl_multi_pw_aff_get_pw_aff(index, 0);
451 isl_multi_pw_aff_free(index);
452 cond = isl_pw_aff_non_zero_set(pa);
453 cond = isl_set_reset_tuple_id(cond);
454 return isl_set_intersect(context, cond);
457 for (i = 0; i < stmt->n_arg; ++i)
458 context = expr_extract_context(stmt->args[i], context);
460 if (pet_tree_get_type(stmt->body) != pet_tree_expr)
461 return context;
463 body = pet_tree_expr_get_expr(stmt->body);
464 context = expr_extract_context(body, context);
465 pet_expr_free(body);
467 return context;
470 /* Construct a pet_scop in the given space that contains the given pet_stmt.
472 struct pet_scop *pet_scop_from_pet_stmt(__isl_take isl_space *space,
473 struct pet_stmt *stmt)
475 struct pet_scop *scop;
477 if (!stmt)
478 space = isl_space_free(space);
480 scop = scop_alloc(space, 1);
481 if (!scop)
482 goto error;
484 scop->context = stmt_extract_context(stmt, scop->context);
485 if (!scop->context)
486 goto error;
488 scop->stmts[0] = stmt;
489 scop->loc = pet_loc_copy(stmt->loc);
491 if (!scop->loc)
492 return pet_scop_free(scop);
494 return scop;
495 error:
496 pet_stmt_free(stmt);
497 pet_scop_free(scop);
498 return NULL;
501 /* Does "mpa" represent an access to an element of an unnamed space, i.e.,
502 * does it represent an affine expression?
504 static int multi_pw_aff_is_affine(__isl_keep isl_multi_pw_aff *mpa)
506 int has_id;
508 has_id = isl_multi_pw_aff_has_tuple_id(mpa, isl_dim_out);
509 if (has_id < 0)
510 return -1;
512 return !has_id;
515 /* Return the piecewise affine expression "set ? 1 : 0" defined on "dom".
517 static __isl_give isl_pw_aff *indicator_function(__isl_take isl_set *set,
518 __isl_take isl_set *dom)
520 isl_pw_aff *pa;
521 pa = isl_set_indicator_function(set);
522 pa = isl_pw_aff_intersect_domain(pa, dom);
523 return pa;
526 /* Return "lhs || rhs", defined on the shared definition domain.
528 static __isl_give isl_pw_aff *pw_aff_or(__isl_take isl_pw_aff *lhs,
529 __isl_take isl_pw_aff *rhs)
531 isl_set *cond;
532 isl_set *dom;
534 dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(lhs)),
535 isl_pw_aff_domain(isl_pw_aff_copy(rhs)));
536 cond = isl_set_union(isl_pw_aff_non_zero_set(lhs),
537 isl_pw_aff_non_zero_set(rhs));
538 cond = isl_set_coalesce(cond);
539 return indicator_function(cond, dom);
542 /* Combine ext1->skip[type] and ext2->skip[type] into ext->skip[type].
543 * ext may be equal to either ext1 or ext2.
545 * The two skips that need to be combined are assumed to be affine expressions.
547 * We need to skip in ext if we need to skip in either ext1 or ext2.
548 * We don't need to skip in ext if we don't need to skip in both ext1 and ext2.
550 static struct pet_scop_ext *combine_skips(struct pet_scop_ext *ext,
551 struct pet_scop_ext *ext1, struct pet_scop_ext *ext2,
552 enum pet_skip type)
554 isl_pw_aff *skip, *skip1, *skip2;
556 if (!ext)
557 return NULL;
558 if (!ext1->skip[type] && !ext2->skip[type])
559 return ext;
560 if (!ext1->skip[type]) {
561 if (ext == ext2)
562 return ext;
563 ext->skip[type] = ext2->skip[type];
564 ext2->skip[type] = NULL;
565 return ext;
567 if (!ext2->skip[type]) {
568 if (ext == ext1)
569 return ext;
570 ext->skip[type] = ext1->skip[type];
571 ext1->skip[type] = NULL;
572 return ext;
575 if (!multi_pw_aff_is_affine(ext1->skip[type]) ||
576 !multi_pw_aff_is_affine(ext2->skip[type]))
577 isl_die(isl_multi_pw_aff_get_ctx(ext1->skip[type]),
578 isl_error_internal, "can only combine affine skips",
579 goto error);
581 skip1 = isl_multi_pw_aff_get_pw_aff(ext1->skip[type], 0);
582 skip2 = isl_multi_pw_aff_get_pw_aff(ext2->skip[type], 0);
583 skip = pw_aff_or(skip1, skip2);
584 isl_multi_pw_aff_free(ext1->skip[type]);
585 ext1->skip[type] = NULL;
586 isl_multi_pw_aff_free(ext2->skip[type]);
587 ext2->skip[type] = NULL;
588 ext->skip[type] = isl_multi_pw_aff_from_pw_aff(skip);
589 if (!ext->skip[type])
590 goto error;
592 return ext;
593 error:
594 pet_scop_free(&ext->scop);
595 return NULL;
598 /* Combine scop1->skip[type] and scop2->skip[type] into scop->skip[type],
599 * where type takes on the values pet_skip_now and pet_skip_later.
600 * scop may be equal to either scop1 or scop2.
602 static struct pet_scop *scop_combine_skips(struct pet_scop *scop,
603 struct pet_scop *scop1, struct pet_scop *scop2)
605 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
606 struct pet_scop_ext *ext1 = (struct pet_scop_ext *) scop1;
607 struct pet_scop_ext *ext2 = (struct pet_scop_ext *) scop2;
609 ext = combine_skips(ext, ext1, ext2, pet_skip_now);
610 ext = combine_skips(ext, ext1, ext2, pet_skip_later);
611 return &ext->scop;
614 /* Update start and end of scop->loc to include the region from "start"
615 * to "end". In particular, if scop->loc == &pet_loc_dummy, then "scop"
616 * does not have any offset information yet and we simply take the information
617 * from "start" and "end". Otherwise, we update loc using "start" and "end".
619 struct pet_scop *pet_scop_update_start_end(struct pet_scop *scop,
620 unsigned start, unsigned end)
622 if (!scop)
623 return NULL;
625 if (scop->loc == &pet_loc_dummy)
626 scop->loc = pet_loc_alloc(isl_set_get_ctx(scop->context),
627 start, end, -1, strdup(""));
628 else
629 scop->loc = pet_loc_update_start_end(scop->loc, start, end);
631 if (!scop->loc)
632 return pet_scop_free(scop);
634 return scop;
637 /* Update start and end of scop->loc to include the region identified
638 * by "loc".
640 struct pet_scop *pet_scop_update_start_end_from_loc(struct pet_scop *scop,
641 __isl_keep pet_loc *loc)
643 return pet_scop_update_start_end(scop, pet_loc_get_start(loc),
644 pet_loc_get_end(loc));
647 /* Replace the location of "scop" by "loc".
649 struct pet_scop *pet_scop_set_loc(struct pet_scop *scop,
650 __isl_take pet_loc *loc)
652 if (!scop || !loc)
653 goto error;
655 pet_loc_free(scop->loc);
656 scop->loc = loc;
658 return scop;
659 error:
660 pet_loc_free(loc);
661 pet_scop_free(scop);
662 return NULL;
665 /* Does "implication" appear in the list of implications of "scop"?
667 static int is_known_implication(struct pet_scop *scop,
668 struct pet_implication *implication)
670 int i;
672 for (i = 0; i < scop->n_implication; ++i) {
673 struct pet_implication *pi = scop->implications[i];
674 int equal;
676 if (pi->satisfied != implication->satisfied)
677 continue;
678 equal = isl_map_is_equal(pi->extension, implication->extension);
679 if (equal < 0)
680 return -1;
681 if (equal)
682 return 1;
685 return 0;
688 /* Store the concatenation of the implications of "scop1" and "scop2"
689 * in "scop", removing duplicates (i.e., implications in "scop2" that
690 * already appear in "scop1").
692 static struct pet_scop *scop_collect_implications(isl_ctx *ctx,
693 struct pet_scop *scop, struct pet_scop *scop1, struct pet_scop *scop2)
695 int i, j;
697 if (!scop)
698 return NULL;
700 if (scop2->n_implication == 0) {
701 scop->n_implication = scop1->n_implication;
702 scop->implications = scop1->implications;
703 scop1->n_implication = 0;
704 scop1->implications = NULL;
705 return scop;
708 if (scop1->n_implication == 0) {
709 scop->n_implication = scop2->n_implication;
710 scop->implications = scop2->implications;
711 scop2->n_implication = 0;
712 scop2->implications = NULL;
713 return scop;
716 scop->implications = isl_calloc_array(ctx, struct pet_implication *,
717 scop1->n_implication + scop2->n_implication);
718 if (!scop->implications)
719 return pet_scop_free(scop);
721 for (i = 0; i < scop1->n_implication; ++i) {
722 scop->implications[i] = scop1->implications[i];
723 scop1->implications[i] = NULL;
726 scop->n_implication = scop1->n_implication;
727 j = scop1->n_implication;
728 for (i = 0; i < scop2->n_implication; ++i) {
729 int known;
731 known = is_known_implication(scop, scop2->implications[i]);
732 if (known < 0)
733 return pet_scop_free(scop);
734 if (known)
735 continue;
736 scop->implications[j++] = scop2->implications[i];
737 scop2->implications[i] = NULL;
739 scop->n_implication = j;
741 return scop;
744 /* Combine the offset information of "scop1" and "scop2" into "scop".
746 static struct pet_scop *scop_combine_start_end(struct pet_scop *scop,
747 struct pet_scop *scop1, struct pet_scop *scop2)
749 if (scop1->loc != &pet_loc_dummy)
750 scop = pet_scop_update_start_end_from_loc(scop, scop1->loc);
751 if (scop2->loc != &pet_loc_dummy)
752 scop = pet_scop_update_start_end_from_loc(scop, scop2->loc);
753 return scop;
756 /* Create and return an independence that filters out the dependences
757 * in "filter" with local variables "local".
759 static struct pet_independence *new_independence(
760 __isl_take isl_union_map *filter, __isl_take isl_union_set *local)
762 isl_ctx *ctx;
763 struct pet_independence *independence;
765 if (!filter || !local)
766 goto error;
767 ctx = isl_union_map_get_ctx(filter);
768 independence = isl_alloc_type(ctx, struct pet_independence);
769 if (!independence)
770 goto error;
772 independence->filter = filter;
773 independence->local = local;
775 return independence;
776 error:
777 isl_union_map_free(filter);
778 isl_union_set_free(local);
779 return NULL;
782 /* Add an independence that filters out the dependences
783 * in "filter" with local variables "local" to "scop".
785 struct pet_scop *pet_scop_add_independence(struct pet_scop *scop,
786 __isl_take isl_union_map *filter, __isl_take isl_union_set *local)
788 isl_ctx *ctx;
789 struct pet_independence *independence;
790 struct pet_independence **independences;
792 ctx = isl_union_map_get_ctx(filter);
793 independence = new_independence(filter, local);
794 if (!scop || !independence)
795 goto error;
797 independences = isl_realloc_array(ctx, scop->independences,
798 struct pet_independence *,
799 scop->n_independence + 1);
800 if (!independences)
801 goto error;
802 scop->independences = independences;
803 scop->independences[scop->n_independence] = independence;
804 scop->n_independence++;
806 return scop;
807 error:
808 pet_independence_free(independence);
809 pet_scop_free(scop);
810 return NULL;
813 /* Store the concatenation of the independences of "scop1" and "scop2"
814 * in "scop".
816 static struct pet_scop *scop_collect_independences(isl_ctx *ctx,
817 struct pet_scop *scop, struct pet_scop *scop1, struct pet_scop *scop2)
819 int i, off;
821 if (!scop)
822 return NULL;
824 if (scop2->n_independence == 0) {
825 scop->n_independence = scop1->n_independence;
826 scop->independences = scop1->independences;
827 scop1->n_independence = 0;
828 scop1->independences = NULL;
829 return scop;
832 if (scop1->n_independence == 0) {
833 scop->n_independence = scop2->n_independence;
834 scop->independences = scop2->independences;
835 scop2->n_independence = 0;
836 scop2->independences = NULL;
837 return scop;
840 scop->independences = isl_calloc_array(ctx, struct pet_independence *,
841 scop1->n_independence + scop2->n_independence);
842 if (!scop->independences)
843 return pet_scop_free(scop);
845 for (i = 0; i < scop1->n_independence; ++i) {
846 scop->independences[i] = scop1->independences[i];
847 scop1->independences[i] = NULL;
850 off = scop1->n_independence;
851 for (i = 0; i < scop2->n_independence; ++i) {
852 scop->independences[off + i] = scop2->independences[i];
853 scop2->independences[i] = NULL;
855 scop->n_independence = scop1->n_independence + scop2->n_independence;
857 return scop;
860 /* Construct a pet_scop that contains the offset information,
861 * arrays, statements and skip information in "scop1" and "scop2".
863 static struct pet_scop *pet_scop_add(isl_ctx *ctx, struct pet_scop *scop1,
864 struct pet_scop *scop2)
866 int i;
867 isl_space *space;
868 struct pet_scop *scop = NULL;
870 if (!scop1 || !scop2)
871 goto error;
873 if (scop1->n_stmt == 0) {
874 scop2 = scop_combine_skips(scop2, scop1, scop2);
875 pet_scop_free(scop1);
876 return scop2;
879 if (scop2->n_stmt == 0) {
880 scop1 = scop_combine_skips(scop1, scop1, scop2);
881 pet_scop_free(scop2);
882 return scop1;
885 space = isl_set_get_space(scop1->context);
886 scop = scop_alloc(space, scop1->n_stmt + scop2->n_stmt);
887 if (!scop)
888 goto error;
890 scop->arrays = isl_calloc_array(ctx, struct pet_array *,
891 scop1->n_array + scop2->n_array);
892 if (!scop->arrays)
893 goto error;
894 scop->n_array = scop1->n_array + scop2->n_array;
896 for (i = 0; i < scop1->n_stmt; ++i) {
897 scop->stmts[i] = scop1->stmts[i];
898 scop1->stmts[i] = NULL;
901 for (i = 0; i < scop2->n_stmt; ++i) {
902 scop->stmts[scop1->n_stmt + i] = scop2->stmts[i];
903 scop2->stmts[i] = NULL;
906 for (i = 0; i < scop1->n_array; ++i) {
907 scop->arrays[i] = scop1->arrays[i];
908 scop1->arrays[i] = NULL;
911 for (i = 0; i < scop2->n_array; ++i) {
912 scop->arrays[scop1->n_array + i] = scop2->arrays[i];
913 scop2->arrays[i] = NULL;
916 scop = scop_collect_implications(ctx, scop, scop1, scop2);
917 scop = pet_scop_restrict_context(scop, isl_set_copy(scop1->context));
918 scop = pet_scop_restrict_context(scop, isl_set_copy(scop2->context));
919 scop = scop_combine_skips(scop, scop1, scop2);
920 scop = scop_combine_start_end(scop, scop1, scop2);
921 scop = scop_collect_independences(ctx, scop, scop1, scop2);
923 pet_scop_free(scop1);
924 pet_scop_free(scop2);
925 return scop;
926 error:
927 pet_scop_free(scop1);
928 pet_scop_free(scop2);
929 pet_scop_free(scop);
930 return NULL;
933 /* Apply the skip condition "skip" to "scop".
934 * That is, make sure "scop" is not executed when the condition holds.
936 * If "skip" is an affine expression, we add the conditions under
937 * which the expression is zero to the context and the skip conditions
938 * of "scop".
939 * Otherwise, we add a filter on the variable attaining the value zero.
941 static struct pet_scop *restrict_skip(struct pet_scop *scop,
942 __isl_take isl_multi_pw_aff *skip)
944 isl_set *zero;
945 isl_pw_aff *pa;
946 int is_aff;
948 if (!scop || !skip)
949 goto error;
951 is_aff = multi_pw_aff_is_affine(skip);
952 if (is_aff < 0)
953 goto error;
955 if (!is_aff)
956 return pet_scop_filter(scop, skip, 0);
958 pa = isl_multi_pw_aff_get_pw_aff(skip, 0);
959 isl_multi_pw_aff_free(skip);
960 zero = isl_pw_aff_zero_set(pa);
961 scop = pet_scop_restrict(scop, zero);
963 return scop;
964 error:
965 isl_multi_pw_aff_free(skip);
966 return pet_scop_free(scop);
969 /* Construct a pet_scop that contains the arrays, statements and
970 * skip information in "scop1" and "scop2", where the two scops
971 * are executed "in sequence". That is, breaks and continues
972 * in scop1 have an effect on scop2.
974 struct pet_scop *pet_scop_add_seq(isl_ctx *ctx, struct pet_scop *scop1,
975 struct pet_scop *scop2)
977 if (scop1 && pet_scop_has_skip(scop1, pet_skip_now))
978 scop2 = restrict_skip(scop2,
979 pet_scop_get_skip(scop1, pet_skip_now));
980 return pet_scop_add(ctx, scop1, scop2);
983 /* Construct a pet_scop that contains the arrays, statements and
984 * skip information in "scop1" and "scop2", where the two scops
985 * are executed "in parallel". That is, any break or continue
986 * in scop1 has no effect on scop2.
988 struct pet_scop *pet_scop_add_par(isl_ctx *ctx, struct pet_scop *scop1,
989 struct pet_scop *scop2)
991 return pet_scop_add(ctx, scop1, scop2);
994 void *pet_implication_free(struct pet_implication *implication)
996 int i;
998 if (!implication)
999 return NULL;
1001 isl_map_free(implication->extension);
1003 free(implication);
1004 return NULL;
1007 void *pet_independence_free(struct pet_independence *independence)
1009 if (!independence)
1010 return NULL;
1012 isl_union_map_free(independence->filter);
1013 isl_union_set_free(independence->local);
1015 free(independence);
1016 return NULL;
1019 struct pet_scop *pet_scop_free(struct pet_scop *scop)
1021 int i;
1022 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1024 if (!scop)
1025 return NULL;
1026 pet_loc_free(scop->loc);
1027 isl_set_free(scop->context);
1028 isl_set_free(scop->context_value);
1029 if (scop->types)
1030 for (i = 0; i < scop->n_type; ++i)
1031 pet_type_free(scop->types[i]);
1032 free(scop->types);
1033 if (scop->arrays)
1034 for (i = 0; i < scop->n_array; ++i)
1035 pet_array_free(scop->arrays[i]);
1036 free(scop->arrays);
1037 if (scop->stmts)
1038 for (i = 0; i < scop->n_stmt; ++i)
1039 pet_stmt_free(scop->stmts[i]);
1040 free(scop->stmts);
1041 if (scop->implications)
1042 for (i = 0; i < scop->n_implication; ++i)
1043 pet_implication_free(scop->implications[i]);
1044 free(scop->implications);
1045 if (scop->independences)
1046 for (i = 0; i < scop->n_independence; ++i)
1047 pet_independence_free(scop->independences[i]);
1048 free(scop->independences);
1049 isl_multi_pw_aff_free(ext->skip[pet_skip_now]);
1050 isl_multi_pw_aff_free(ext->skip[pet_skip_later]);
1051 free(scop);
1052 return NULL;
1055 void pet_type_dump(struct pet_type *type)
1057 if (!type)
1058 return;
1060 fprintf(stderr, "%s -> %s\n", type->name, type->definition);
1063 void pet_implication_dump(struct pet_implication *implication)
1065 if (!implication)
1066 return;
1068 fprintf(stderr, "%d\n", implication->satisfied);
1069 isl_map_dump(implication->extension);
1072 void pet_scop_dump(struct pet_scop *scop)
1074 int i;
1075 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1077 if (!scop)
1078 return;
1080 isl_set_dump(scop->context);
1081 isl_set_dump(scop->context_value);
1082 for (i = 0; i < scop->n_type; ++i)
1083 pet_type_dump(scop->types[i]);
1084 for (i = 0; i < scop->n_array; ++i)
1085 pet_array_dump(scop->arrays[i]);
1086 for (i = 0; i < scop->n_stmt; ++i)
1087 pet_stmt_dump(scop->stmts[i]);
1088 for (i = 0; i < scop->n_implication; ++i)
1089 pet_implication_dump(scop->implications[i]);
1091 if (ext->skip[0]) {
1092 fprintf(stderr, "skip\n");
1093 isl_multi_pw_aff_dump(ext->skip[0]);
1094 isl_multi_pw_aff_dump(ext->skip[1]);
1098 /* Return 1 if the two pet_arrays are equivalent.
1100 * We don't compare element_size as this may be target dependent.
1102 int pet_array_is_equal(struct pet_array *array1, struct pet_array *array2)
1104 if (!array1 || !array2)
1105 return 0;
1107 if (!isl_set_is_equal(array1->context, array2->context))
1108 return 0;
1109 if (!isl_set_is_equal(array1->extent, array2->extent))
1110 return 0;
1111 if (!!array1->value_bounds != !!array2->value_bounds)
1112 return 0;
1113 if (array1->value_bounds &&
1114 !isl_set_is_equal(array1->value_bounds, array2->value_bounds))
1115 return 0;
1116 if (strcmp(array1->element_type, array2->element_type))
1117 return 0;
1118 if (array1->element_is_record != array2->element_is_record)
1119 return 0;
1120 if (array1->live_out != array2->live_out)
1121 return 0;
1122 if (array1->uniquely_defined != array2->uniquely_defined)
1123 return 0;
1124 if (array1->declared != array2->declared)
1125 return 0;
1126 if (array1->exposed != array2->exposed)
1127 return 0;
1129 return 1;
1132 /* Return 1 if the two pet_stmts are equivalent.
1134 int pet_stmt_is_equal(struct pet_stmt *stmt1, struct pet_stmt *stmt2)
1136 int i;
1138 if (!stmt1 || !stmt2)
1139 return 0;
1141 if (pet_loc_get_line(stmt1->loc) != pet_loc_get_line(stmt2->loc))
1142 return 0;
1143 if (!isl_set_is_equal(stmt1->domain, stmt2->domain))
1144 return 0;
1145 if (!isl_map_is_equal(stmt1->schedule, stmt2->schedule))
1146 return 0;
1147 if (!pet_tree_is_equal(stmt1->body, stmt2->body))
1148 return 0;
1149 if (stmt1->n_arg != stmt2->n_arg)
1150 return 0;
1151 for (i = 0; i < stmt1->n_arg; ++i) {
1152 if (!pet_expr_is_equal(stmt1->args[i], stmt2->args[i]))
1153 return 0;
1156 return 1;
1159 /* Return 1 if the two pet_types are equivalent.
1161 * We only compare the names of the types since the exact representation
1162 * of the definition may depend on the version of clang being used.
1164 int pet_type_is_equal(struct pet_type *type1, struct pet_type *type2)
1166 if (!type1 || !type2)
1167 return 0;
1169 if (strcmp(type1->name, type2->name))
1170 return 0;
1172 return 1;
1175 /* Return 1 if the two pet_implications are equivalent.
1177 int pet_implication_is_equal(struct pet_implication *implication1,
1178 struct pet_implication *implication2)
1180 if (!implication1 || !implication2)
1181 return 0;
1183 if (implication1->satisfied != implication2->satisfied)
1184 return 0;
1185 if (!isl_map_is_equal(implication1->extension, implication2->extension))
1186 return 0;
1188 return 1;
1191 /* Return 1 if the two pet_independences are equivalent.
1193 int pet_independence_is_equal(struct pet_independence *independence1,
1194 struct pet_independence *independence2)
1196 if (!independence1 || !independence2)
1197 return 0;
1199 if (!isl_union_map_is_equal(independence1->filter,
1200 independence2->filter))
1201 return 0;
1202 if (!isl_union_set_is_equal(independence1->local, independence2->local))
1203 return 0;
1205 return 1;
1208 /* Return 1 if the two pet_scops are equivalent.
1210 int pet_scop_is_equal(struct pet_scop *scop1, struct pet_scop *scop2)
1212 int i;
1214 if (!scop1 || !scop2)
1215 return 0;
1217 if (!isl_set_is_equal(scop1->context, scop2->context))
1218 return 0;
1219 if (!isl_set_is_equal(scop1->context_value, scop2->context_value))
1220 return 0;
1222 if (scop1->n_type != scop2->n_type)
1223 return 0;
1224 for (i = 0; i < scop1->n_type; ++i)
1225 if (!pet_type_is_equal(scop1->types[i], scop2->types[i]))
1226 return 0;
1228 if (scop1->n_array != scop2->n_array)
1229 return 0;
1230 for (i = 0; i < scop1->n_array; ++i)
1231 if (!pet_array_is_equal(scop1->arrays[i], scop2->arrays[i]))
1232 return 0;
1234 if (scop1->n_stmt != scop2->n_stmt)
1235 return 0;
1236 for (i = 0; i < scop1->n_stmt; ++i)
1237 if (!pet_stmt_is_equal(scop1->stmts[i], scop2->stmts[i]))
1238 return 0;
1240 if (scop1->n_implication != scop2->n_implication)
1241 return 0;
1242 for (i = 0; i < scop1->n_implication; ++i)
1243 if (!pet_implication_is_equal(scop1->implications[i],
1244 scop2->implications[i]))
1245 return 0;
1247 if (scop1->n_independence != scop2->n_independence)
1248 return 0;
1249 for (i = 0; i < scop1->n_independence; ++i)
1250 if (!pet_independence_is_equal(scop1->independences[i],
1251 scop2->independences[i]))
1252 return 0;
1254 return 1;
1257 /* Does the set "extent" reference a virtual array, i.e.,
1258 * one with user pointer equal to NULL?
1259 * A virtual array does not have any members.
1261 static int extent_is_virtual_array(__isl_keep isl_set *extent)
1263 isl_id *id;
1264 int is_virtual;
1266 if (!isl_set_has_tuple_id(extent))
1267 return 0;
1268 if (isl_set_is_wrapping(extent))
1269 return 0;
1270 id = isl_set_get_tuple_id(extent);
1271 is_virtual = !isl_id_get_user(id);
1272 isl_id_free(id);
1274 return is_virtual;
1277 /* Intersect the initial dimensions of "array" with "domain", provided
1278 * that "array" represents a virtual array.
1280 * If "array" is virtual, then We take the preimage of "domain"
1281 * over the projection of the extent of "array" onto its initial dimensions
1282 * and intersect this extent with the result.
1284 static struct pet_array *virtual_array_intersect_domain_prefix(
1285 struct pet_array *array, __isl_take isl_set *domain)
1287 int n;
1288 isl_space *space;
1289 isl_multi_aff *ma;
1291 if (!array || !extent_is_virtual_array(array->extent)) {
1292 isl_set_free(domain);
1293 return array;
1296 space = isl_set_get_space(array->extent);
1297 n = isl_set_dim(domain, isl_dim_set);
1298 ma = pet_prefix_projection(space, n);
1299 domain = isl_set_preimage_multi_aff(domain, ma);
1301 array->extent = isl_set_intersect(array->extent, domain);
1302 if (!array->extent)
1303 return pet_array_free(array);
1305 return array;
1308 /* Intersect the initial dimensions of the domain of "stmt"
1309 * with "domain".
1311 * We take the preimage of "domain" over the projection of the
1312 * domain of "stmt" onto its initial dimensions and intersect
1313 * the domain of "stmt" with the result.
1315 static struct pet_stmt *stmt_intersect_domain_prefix(struct pet_stmt *stmt,
1316 __isl_take isl_set *domain)
1318 int n;
1319 isl_space *space;
1320 isl_multi_aff *ma;
1322 if (!stmt)
1323 goto error;
1325 space = isl_set_get_space(stmt->domain);
1326 n = isl_set_dim(domain, isl_dim_set);
1327 ma = pet_prefix_projection(space, n);
1328 domain = isl_set_preimage_multi_aff(domain, ma);
1330 stmt->domain = isl_set_intersect(stmt->domain, domain);
1331 if (!stmt->domain)
1332 return pet_stmt_free(stmt);
1334 return stmt;
1335 error:
1336 isl_set_free(domain);
1337 return pet_stmt_free(stmt);
1340 /* Intersect the initial dimensions of the domain of "implication"
1341 * with "domain".
1343 * We take the preimage of "domain" over the projection of the
1344 * domain of "implication" onto its initial dimensions and intersect
1345 * the domain of "implication" with the result.
1347 static struct pet_implication *implication_intersect_domain_prefix(
1348 struct pet_implication *implication, __isl_take isl_set *domain)
1350 int n;
1351 isl_space *space;
1352 isl_multi_aff *ma;
1354 if (!implication)
1355 goto error;
1357 space = isl_map_get_space(implication->extension);
1358 n = isl_set_dim(domain, isl_dim_set);
1359 ma = pet_prefix_projection(isl_space_domain(space), n);
1360 domain = isl_set_preimage_multi_aff(domain, ma);
1362 implication->extension =
1363 isl_map_intersect_domain(implication->extension, domain);
1364 if (!implication->extension)
1365 return pet_implication_free(implication);
1367 return implication;
1368 error:
1369 isl_set_free(domain);
1370 return pet_implication_free(implication);
1373 /* Intersect the initial dimensions of the domains in "scop" with "domain".
1375 * The extents of the virtual arrays match the iteration domains,
1376 * so if the iteration domain changes, we need to change those extents too.
1378 struct pet_scop *pet_scop_intersect_domain_prefix(struct pet_scop *scop,
1379 __isl_take isl_set *domain)
1381 int i;
1383 if (!scop)
1384 goto error;
1386 for (i = 0; i < scop->n_array; ++i) {
1387 scop->arrays[i] = virtual_array_intersect_domain_prefix(
1388 scop->arrays[i], isl_set_copy(domain));
1389 if (!scop->arrays[i])
1390 goto error;
1393 for (i = 0; i < scop->n_stmt; ++i) {
1394 scop->stmts[i] = stmt_intersect_domain_prefix(scop->stmts[i],
1395 isl_set_copy(domain));
1396 if (!scop->stmts[i])
1397 goto error;
1400 for (i = 0; i < scop->n_implication; ++i) {
1401 scop->implications[i] =
1402 implication_intersect_domain_prefix(scop->implications[i],
1403 isl_set_copy(domain));
1404 if (!scop->implications[i])
1405 return pet_scop_free(scop);
1408 isl_set_free(domain);
1409 return scop;
1410 error:
1411 isl_set_free(domain);
1412 return pet_scop_free(scop);
1415 /* Prefix the schedule of "stmt" with an extra dimension with constant
1416 * value "pos".
1418 struct pet_stmt *pet_stmt_prefix(struct pet_stmt *stmt, int pos)
1420 if (!stmt)
1421 return NULL;
1423 stmt->schedule = isl_map_insert_dims(stmt->schedule, isl_dim_out, 0, 1);
1424 stmt->schedule = isl_map_fix_si(stmt->schedule, isl_dim_out, 0, pos);
1425 if (!stmt->schedule)
1426 return pet_stmt_free(stmt);
1428 return stmt;
1431 /* Prefix the schedules of all statements in "scop" with an extra
1432 * dimension with constant value "pos".
1434 struct pet_scop *pet_scop_prefix(struct pet_scop *scop, int pos)
1436 int i;
1438 if (!scop)
1439 return NULL;
1441 for (i = 0; i < scop->n_stmt; ++i) {
1442 scop->stmts[i] = pet_stmt_prefix(scop->stmts[i], pos);
1443 if (!scop->stmts[i])
1444 return pet_scop_free(scop);
1447 return scop;
1450 /* Prefix the schedule of "stmt" with "sched".
1452 * The domain of "sched" refers the current outer loop iterators and
1453 * needs to be mapped to the iteration domain of "stmt" first
1454 * before being prepended to the schedule of "stmt".
1456 static struct pet_stmt *pet_stmt_embed(struct pet_stmt *stmt,
1457 __isl_take isl_map *sched)
1459 int n;
1460 isl_space *space;
1461 isl_multi_aff *ma;
1463 if (!stmt)
1464 goto error;
1466 space = pet_stmt_get_space(stmt);
1467 n = isl_map_dim(sched, isl_dim_in);
1468 ma = pet_prefix_projection(space, n);
1469 sched = isl_map_preimage_domain_multi_aff(sched, ma);
1470 stmt->schedule = isl_map_flat_range_product(sched, stmt->schedule);
1471 if (!stmt->schedule)
1472 return pet_stmt_free(stmt);
1474 return stmt;
1475 error:
1476 isl_map_free(sched);
1477 return NULL;
1480 /* Update the context with respect to an embedding into a loop
1481 * with iteration domain "dom".
1482 * The input context lives in the same space as "dom".
1483 * The output context has the inner dimension removed.
1485 * An outer loop iterator value is invalid for the embedding if
1486 * any of the corresponding inner iterator values is invalid.
1487 * That is, an outer loop iterator value is valid only if all the corresponding
1488 * inner iterator values are valid.
1489 * We therefore compute the set of outer loop iterators l
1491 * forall i: dom(l,i) => valid(l,i)
1493 * or
1495 * forall i: not dom(l,i) or valid(l,i)
1497 * or
1499 * not exists i: dom(l,i) and not valid(l,i)
1501 * i.e.,
1503 * not exists i: (dom \ valid)(l,i)
1505 * If there are any unnamed parameters in "dom", then we consider
1506 * a parameter value to be valid if it is valid for any value of those
1507 * unnamed parameters. They are therefore projected out at the end.
1509 static __isl_give isl_set *context_embed(__isl_take isl_set *context,
1510 __isl_keep isl_set *dom)
1512 int pos;
1514 pos = isl_set_dim(context, isl_dim_set) - 1;
1515 context = isl_set_subtract(isl_set_copy(dom), context);
1516 context = isl_set_project_out(context, isl_dim_set, pos, 1);
1517 context = isl_set_complement(context);
1518 context = pet_nested_remove_from_set(context);
1520 return context;
1523 /* Update the implication with respect to an embedding into a loop
1524 * with iteration domain "dom".
1526 * Since embed_access extends virtual arrays along with the domain
1527 * of the access, we need to do the same with domain and range
1528 * of the implication. Since the original implication is only valid
1529 * within a given iteration of the loop, the extended implication
1530 * maps the extra array dimension corresponding to the extra loop
1531 * to itself.
1533 static struct pet_implication *pet_implication_embed(
1534 struct pet_implication *implication, __isl_take isl_set *dom)
1536 isl_id *id;
1537 isl_map *map;
1539 if (!implication)
1540 goto error;
1542 map = isl_set_identity(dom);
1543 id = isl_map_get_tuple_id(implication->extension, isl_dim_in);
1544 map = isl_map_flat_product(map, implication->extension);
1545 map = isl_map_set_tuple_id(map, isl_dim_in, isl_id_copy(id));
1546 map = isl_map_set_tuple_id(map, isl_dim_out, id);
1547 implication->extension = map;
1548 if (!implication->extension)
1549 return pet_implication_free(implication);
1551 return implication;
1552 error:
1553 isl_set_free(dom);
1554 return NULL;
1557 /* Adjust the context and statement schedules according to an embedding
1558 * in a loop with iteration domain "dom" and schedule "sched".
1560 * Any skip conditions within the loop have no effect outside of the loop.
1561 * The caller is responsible for making sure skip[pet_skip_later] has been
1562 * taken into account.
1564 struct pet_scop *pet_scop_embed(struct pet_scop *scop, __isl_take isl_set *dom,
1565 __isl_take isl_aff *sched)
1567 int i;
1568 isl_map *sched_map;
1570 sched_map = isl_map_from_aff(sched);
1572 if (!scop)
1573 goto error;
1575 pet_scop_reset_skip(scop, pet_skip_now);
1576 pet_scop_reset_skip(scop, pet_skip_later);
1578 scop->context = context_embed(scop->context, dom);
1579 if (!scop->context)
1580 goto error;
1582 for (i = 0; i < scop->n_stmt; ++i) {
1583 scop->stmts[i] = pet_stmt_embed(scop->stmts[i],
1584 isl_map_copy(sched_map));
1585 if (!scop->stmts[i])
1586 goto error;
1589 isl_set_free(dom);
1590 isl_map_free(sched_map);
1591 return scop;
1592 error:
1593 isl_set_free(dom);
1594 isl_map_free(sched_map);
1595 return pet_scop_free(scop);
1598 /* Add extra conditions to scop->skip[type].
1600 * The new skip condition only holds if it held before
1601 * and the condition is true. It does not hold if it did not hold
1602 * before or the condition is false.
1604 * The skip condition is assumed to be an affine expression.
1606 static struct pet_scop *pet_scop_restrict_skip(struct pet_scop *scop,
1607 enum pet_skip type, __isl_keep isl_set *cond)
1609 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1610 isl_pw_aff *skip;
1611 isl_set *dom;
1613 if (!scop)
1614 return NULL;
1615 if (!ext->skip[type])
1616 return scop;
1618 if (!multi_pw_aff_is_affine(ext->skip[type]))
1619 isl_die(isl_multi_pw_aff_get_ctx(ext->skip[type]),
1620 isl_error_internal, "can only restrict affine skips",
1621 return pet_scop_free(scop));
1623 skip = isl_multi_pw_aff_get_pw_aff(ext->skip[type], 0);
1624 dom = isl_pw_aff_domain(isl_pw_aff_copy(skip));
1625 cond = isl_set_copy(cond);
1626 cond = isl_set_intersect(cond, isl_pw_aff_non_zero_set(skip));
1627 skip = indicator_function(cond, dom);
1628 isl_multi_pw_aff_free(ext->skip[type]);
1629 ext->skip[type] = isl_multi_pw_aff_from_pw_aff(skip);
1630 if (!ext->skip[type])
1631 return pet_scop_free(scop);
1633 return scop;
1636 /* Adjust the context and the skip conditions to the fact that
1637 * the scop was created in a context where "cond" holds.
1639 * An outer loop iterator or parameter value is valid for the result
1640 * if it was valid for the original scop and satisfies "cond" or if it does
1641 * not satisfy "cond" as in this case the scop is not executed
1642 * and the original constraints on these values are irrelevant.
1644 struct pet_scop *pet_scop_restrict(struct pet_scop *scop,
1645 __isl_take isl_set *cond)
1647 int i;
1649 scop = pet_scop_restrict_skip(scop, pet_skip_now, cond);
1650 scop = pet_scop_restrict_skip(scop, pet_skip_later, cond);
1652 if (!scop)
1653 goto error;
1655 scop->context = isl_set_intersect(scop->context, isl_set_copy(cond));
1656 scop->context = isl_set_union(scop->context,
1657 isl_set_complement(isl_set_copy(cond)));
1658 scop->context = isl_set_coalesce(scop->context);
1659 scop->context = pet_nested_remove_from_set(scop->context);
1660 if (!scop->context)
1661 goto error;
1663 isl_set_free(cond);
1664 return scop;
1665 error:
1666 isl_set_free(cond);
1667 return pet_scop_free(scop);
1670 /* Insert an argument expression corresponding to "test" in front
1671 * of the list of arguments described by *n_arg and *args.
1673 static int args_insert_access(unsigned *n_arg, pet_expr ***args,
1674 __isl_keep isl_multi_pw_aff *test)
1676 int i;
1677 isl_ctx *ctx = isl_multi_pw_aff_get_ctx(test);
1679 if (!test)
1680 return -1;
1682 if (!*args) {
1683 *args = isl_calloc_array(ctx, pet_expr *, 1);
1684 if (!*args)
1685 return -1;
1686 } else {
1687 pet_expr **ext;
1688 ext = isl_calloc_array(ctx, pet_expr *, 1 + *n_arg);
1689 if (!ext)
1690 return -1;
1691 for (i = 0; i < *n_arg; ++i)
1692 ext[1 + i] = (*args)[i];
1693 free(*args);
1694 *args = ext;
1696 (*n_arg)++;
1697 (*args)[0] = pet_expr_from_index(isl_multi_pw_aff_copy(test));
1698 if (!(*args)[0])
1699 return -1;
1701 return 0;
1704 /* Look through the applications in "scop" for any that can be
1705 * applied to the filter expressed by "map" and "satisified".
1706 * If there is any, then apply it to "map" and return the result.
1707 * Otherwise, return "map".
1708 * "id" is the identifier of the virtual array.
1710 * We only introduce at most one implication for any given virtual array,
1711 * so we can apply the implication and return as soon as we find one.
1713 static __isl_give isl_map *apply_implications(struct pet_scop *scop,
1714 __isl_take isl_map *map, __isl_keep isl_id *id, int satisfied)
1716 int i;
1718 for (i = 0; i < scop->n_implication; ++i) {
1719 struct pet_implication *pi = scop->implications[i];
1720 isl_id *pi_id;
1722 if (pi->satisfied != satisfied)
1723 continue;
1724 pi_id = isl_map_get_tuple_id(pi->extension, isl_dim_in);
1725 isl_id_free(pi_id);
1726 if (pi_id != id)
1727 continue;
1729 return isl_map_apply_range(map, isl_map_copy(pi->extension));
1732 return map;
1735 /* Is the filter expressed by "test" and "satisfied" implied
1736 * by filter "pos" on "domain", with filter "expr", taking into
1737 * account the implications of "scop"?
1739 * For filter on domain implying that expressed by "test" and "satisfied",
1740 * the filter needs to be an access to the same (virtual) array as "test" and
1741 * the filter value needs to be equal to "satisfied".
1742 * Moreover, the filter access relation, possibly extended by
1743 * the implications in "scop" needs to contain "test".
1745 static int implies_filter(struct pet_scop *scop,
1746 __isl_keep isl_map *domain, int pos, __isl_keep pet_expr *expr,
1747 __isl_keep isl_map *test, int satisfied)
1749 isl_id *test_id, *arg_id;
1750 isl_val *val;
1751 int is_int;
1752 int s;
1753 int is_subset;
1754 isl_map *implied;
1756 if (expr->type != pet_expr_access)
1757 return 0;
1758 test_id = isl_map_get_tuple_id(test, isl_dim_out);
1759 arg_id = pet_expr_access_get_id(expr);
1760 isl_id_free(arg_id);
1761 isl_id_free(test_id);
1762 if (test_id != arg_id)
1763 return 0;
1764 val = isl_map_plain_get_val_if_fixed(domain, isl_dim_out, pos);
1765 is_int = isl_val_is_int(val);
1766 if (is_int)
1767 s = isl_val_get_num_si(val);
1768 isl_val_free(val);
1769 if (!val)
1770 return -1;
1771 if (!is_int)
1772 return 0;
1773 if (s != satisfied)
1774 return 0;
1776 implied = isl_map_from_multi_pw_aff(pet_expr_access_get_index(expr));
1777 implied = apply_implications(scop, implied, test_id, satisfied);
1778 is_subset = isl_map_is_subset(test, implied);
1779 isl_map_free(implied);
1781 return is_subset;
1784 /* Is the filter expressed by "test" and "satisfied" implied
1785 * by any of the filters on the domain of "stmt", taking into
1786 * account the implications of "scop"?
1788 static int filter_implied(struct pet_scop *scop,
1789 struct pet_stmt *stmt, __isl_keep isl_multi_pw_aff *test, int satisfied)
1791 int i;
1792 int implied;
1793 isl_id *test_id;
1794 isl_map *domain;
1795 isl_map *test_map;
1797 if (!scop || !stmt || !test)
1798 return -1;
1799 if (scop->n_implication == 0)
1800 return 0;
1801 if (stmt->n_arg == 0)
1802 return 0;
1804 domain = isl_set_unwrap(isl_set_copy(stmt->domain));
1805 test_map = isl_map_from_multi_pw_aff(isl_multi_pw_aff_copy(test));
1807 implied = 0;
1808 for (i = 0; i < stmt->n_arg; ++i) {
1809 implied = implies_filter(scop, domain, i, stmt->args[i],
1810 test_map, satisfied);
1811 if (implied < 0 || implied)
1812 break;
1815 isl_map_free(test_map);
1816 isl_map_free(domain);
1817 return implied;
1820 /* Make the statement "stmt" depend on the value of "test"
1821 * being equal to "satisfied" by adjusting stmt->domain.
1823 * The domain of "test" corresponds to the (zero or more) outer dimensions
1824 * of the iteration domain.
1826 * We first extend "test" to apply to the entire iteration domain and
1827 * then check if the filter that we are about to add is implied
1828 * by any of the current filters, possibly taking into account
1829 * the implications in "scop". If so, we leave "stmt" untouched and return.
1831 * Otherwise, we insert an argument corresponding to a read to "test"
1832 * from the iteration domain of "stmt" in front of the list of arguments.
1833 * We also insert a corresponding output dimension in the wrapped
1834 * map contained in stmt->domain, with value set to "satisfied".
1836 static struct pet_stmt *stmt_filter(struct pet_scop *scop,
1837 struct pet_stmt *stmt, __isl_take isl_multi_pw_aff *test, int satisfied)
1839 int i;
1840 int implied;
1841 isl_id *id;
1842 isl_ctx *ctx;
1843 isl_pw_multi_aff *pma;
1844 isl_multi_aff *add_dom;
1845 isl_space *space;
1846 isl_local_space *ls;
1847 int n_test_dom;
1849 if (!stmt || !test)
1850 goto error;
1852 space = pet_stmt_get_space(stmt);
1853 n_test_dom = isl_multi_pw_aff_dim(test, isl_dim_in);
1854 space = isl_space_from_domain(space);
1855 space = isl_space_add_dims(space, isl_dim_out, n_test_dom);
1856 add_dom = isl_multi_aff_zero(isl_space_copy(space));
1857 ls = isl_local_space_from_space(isl_space_domain(space));
1858 for (i = 0; i < n_test_dom; ++i) {
1859 isl_aff *aff;
1860 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
1861 isl_dim_set, i);
1862 add_dom = isl_multi_aff_set_aff(add_dom, i, aff);
1864 isl_local_space_free(ls);
1865 test = isl_multi_pw_aff_pullback_multi_aff(test, add_dom);
1867 implied = filter_implied(scop, stmt, test, satisfied);
1868 if (implied < 0)
1869 goto error;
1870 if (implied) {
1871 isl_multi_pw_aff_free(test);
1872 return stmt;
1875 id = isl_multi_pw_aff_get_tuple_id(test, isl_dim_out);
1876 pma = pet_filter_insert_pma(isl_set_get_space(stmt->domain),
1877 id, satisfied);
1878 stmt->domain = isl_set_preimage_pw_multi_aff(stmt->domain, pma);
1880 if (args_insert_access(&stmt->n_arg, &stmt->args, test) < 0)
1881 goto error;
1883 isl_multi_pw_aff_free(test);
1884 return stmt;
1885 error:
1886 isl_multi_pw_aff_free(test);
1887 return pet_stmt_free(stmt);
1890 /* Does "scop" have a skip condition of the given "type"?
1892 int pet_scop_has_skip(struct pet_scop *scop, enum pet_skip type)
1894 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1896 if (!scop)
1897 return -1;
1898 return ext->skip[type] != NULL;
1901 /* Does "scop" have a skip condition of the given "type" that
1902 * is an affine expression?
1904 int pet_scop_has_affine_skip(struct pet_scop *scop, enum pet_skip type)
1906 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1908 if (!scop)
1909 return -1;
1910 if (!ext->skip[type])
1911 return 0;
1912 return multi_pw_aff_is_affine(ext->skip[type]);
1915 /* Does "scop" have a skip condition of the given "type" that
1916 * is not an affine expression?
1918 int pet_scop_has_var_skip(struct pet_scop *scop, enum pet_skip type)
1920 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1921 int aff;
1923 if (!scop)
1924 return -1;
1925 if (!ext->skip[type])
1926 return 0;
1927 aff = multi_pw_aff_is_affine(ext->skip[type]);
1928 if (aff < 0)
1929 return -1;
1930 return !aff;
1933 /* Does "scop" have a skip condition of the given "type" that
1934 * is affine and holds on the entire domain?
1936 int pet_scop_has_universal_skip(struct pet_scop *scop, enum pet_skip type)
1938 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1939 isl_pw_aff *pa;
1940 isl_set *set;
1941 int is_aff;
1942 int is_univ;
1944 is_aff = pet_scop_has_affine_skip(scop, type);
1945 if (is_aff < 0 || !is_aff)
1946 return is_aff;
1948 pa = isl_multi_pw_aff_get_pw_aff(ext->skip[type], 0);
1949 set = isl_pw_aff_non_zero_set(pa);
1950 is_univ = isl_set_plain_is_universe(set);
1951 isl_set_free(set);
1953 return is_univ;
1956 /* Replace scop->skip[type] by "skip".
1958 struct pet_scop *pet_scop_set_skip(struct pet_scop *scop,
1959 enum pet_skip type, __isl_take isl_multi_pw_aff *skip)
1961 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1963 if (!scop || !skip)
1964 goto error;
1966 isl_multi_pw_aff_free(ext->skip[type]);
1967 ext->skip[type] = skip;
1969 return scop;
1970 error:
1971 isl_multi_pw_aff_free(skip);
1972 return pet_scop_free(scop);
1975 /* Return a copy of scop->skip[type].
1977 __isl_give isl_multi_pw_aff *pet_scop_get_skip(struct pet_scop *scop,
1978 enum pet_skip type)
1980 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1982 if (!scop)
1983 return NULL;
1985 return isl_multi_pw_aff_copy(ext->skip[type]);
1988 /* Assuming scop->skip[type] is an affine expression,
1989 * return the constraints on the outer loop domain for which the skip condition
1990 * holds.
1992 __isl_give isl_set *pet_scop_get_affine_skip_domain(struct pet_scop *scop,
1993 enum pet_skip type)
1995 isl_multi_pw_aff *skip;
1996 isl_pw_aff *pa;
1998 skip = pet_scop_get_skip(scop, type);
1999 pa = isl_multi_pw_aff_get_pw_aff(skip, 0);
2000 isl_multi_pw_aff_free(skip);
2001 return isl_pw_aff_non_zero_set(pa);
2004 /* Return the identifier of the variable that is accessed by
2005 * the skip condition of the given type.
2007 * The skip condition is assumed not to be an affine condition.
2009 __isl_give isl_id *pet_scop_get_skip_id(struct pet_scop *scop,
2010 enum pet_skip type)
2012 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2014 if (!scop)
2015 return NULL;
2017 return isl_multi_pw_aff_get_tuple_id(ext->skip[type], isl_dim_out);
2020 /* Return an access pet_expr corresponding to the skip condition
2021 * of the given type.
2023 __isl_give pet_expr *pet_scop_get_skip_expr(struct pet_scop *scop,
2024 enum pet_skip type)
2026 return pet_expr_from_index(pet_scop_get_skip(scop, type));
2029 /* Drop the the skip condition scop->skip[type].
2031 void pet_scop_reset_skip(struct pet_scop *scop, enum pet_skip type)
2033 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2035 if (!scop)
2036 return;
2038 isl_multi_pw_aff_free(ext->skip[type]);
2039 ext->skip[type] = NULL;
2042 /* Make the skip condition (if any) depend on the value of "test" being
2043 * equal to "satisfied".
2045 * We only support the case where the original skip condition is universal,
2046 * i.e., where skipping is unconditional, and where satisfied == 1.
2047 * In this case, the skip condition is changed to skip only when
2048 * "test" is equal to one.
2050 static struct pet_scop *pet_scop_filter_skip(struct pet_scop *scop,
2051 enum pet_skip type, __isl_keep isl_multi_pw_aff *test, int satisfied)
2053 int is_univ = 0;
2055 if (!scop)
2056 return NULL;
2057 if (!pet_scop_has_skip(scop, type))
2058 return scop;
2060 if (satisfied)
2061 is_univ = pet_scop_has_universal_skip(scop, type);
2062 if (is_univ < 0)
2063 return pet_scop_free(scop);
2064 if (satisfied && is_univ) {
2065 isl_multi_pw_aff *skip;
2066 skip = isl_multi_pw_aff_copy(test);
2067 scop = pet_scop_set_skip(scop, type, skip);
2068 if (!scop)
2069 return NULL;
2070 } else {
2071 isl_die(isl_multi_pw_aff_get_ctx(test), isl_error_internal,
2072 "skip expression cannot be filtered",
2073 return pet_scop_free(scop));
2076 return scop;
2079 /* Make all statements in "scop" depend on the value of "test"
2080 * being equal to "satisfied" by adjusting their domains.
2082 struct pet_scop *pet_scop_filter(struct pet_scop *scop,
2083 __isl_take isl_multi_pw_aff *test, int satisfied)
2085 int i;
2087 scop = pet_scop_filter_skip(scop, pet_skip_now, test, satisfied);
2088 scop = pet_scop_filter_skip(scop, pet_skip_later, test, satisfied);
2090 if (!scop || !test)
2091 goto error;
2093 for (i = 0; i < scop->n_stmt; ++i) {
2094 scop->stmts[i] = stmt_filter(scop, scop->stmts[i],
2095 isl_multi_pw_aff_copy(test), satisfied);
2096 if (!scop->stmts[i])
2097 goto error;
2100 isl_multi_pw_aff_free(test);
2101 return scop;
2102 error:
2103 isl_multi_pw_aff_free(test);
2104 return pet_scop_free(scop);
2107 /* Add the parameters of the access expression "expr" to "space".
2109 static int access_collect_params(__isl_keep pet_expr *expr, void *user)
2111 int i;
2112 isl_space **space = user;
2114 *space = isl_space_align_params(*space,
2115 isl_map_get_space(expr->acc.access));
2117 return *space ? 0 : -1;
2120 /* Add all parameters in "stmt" to "space" and return the result.
2122 static __isl_give isl_space *stmt_collect_params(struct pet_stmt *stmt,
2123 __isl_take isl_space *space)
2125 int i;
2127 if (!stmt)
2128 return isl_space_free(space);
2130 space = isl_space_align_params(space, isl_set_get_space(stmt->domain));
2131 space = isl_space_align_params(space,
2132 isl_map_get_space(stmt->schedule));
2133 for (i = 0; i < stmt->n_arg; ++i)
2134 if (pet_expr_foreach_access_expr(stmt->args[i],
2135 &access_collect_params, &space) < 0)
2136 space = isl_space_free(space);
2137 if (pet_tree_foreach_access_expr(stmt->body, &access_collect_params,
2138 &space) < 0)
2139 space = isl_space_free(space);
2141 return space;
2144 /* Add all parameters in "array" to "space" and return the result.
2146 static __isl_give isl_space *array_collect_params(struct pet_array *array,
2147 __isl_take isl_space *space)
2149 if (!array)
2150 return isl_space_free(space);
2152 space = isl_space_align_params(space,
2153 isl_set_get_space(array->context));
2154 space = isl_space_align_params(space, isl_set_get_space(array->extent));
2156 return space;
2159 /* Add all parameters in "independence" to "space" and return the result.
2161 static __isl_give isl_space *independence_collect_params(
2162 struct pet_independence *independence, __isl_take isl_space *space)
2164 if (!independence)
2165 return isl_space_free(space);
2167 space = isl_space_align_params(space,
2168 isl_union_map_get_space(independence->filter));
2169 space = isl_space_align_params(space,
2170 isl_union_set_get_space(independence->local));
2172 return space;
2175 /* Add all parameters in "scop" to "space" and return the result.
2177 static __isl_give isl_space *scop_collect_params(struct pet_scop *scop,
2178 __isl_take isl_space *space)
2180 int i;
2182 if (!scop)
2183 return isl_space_free(space);
2185 for (i = 0; i < scop->n_array; ++i)
2186 space = array_collect_params(scop->arrays[i], space);
2188 for (i = 0; i < scop->n_stmt; ++i)
2189 space = stmt_collect_params(scop->stmts[i], space);
2191 for (i = 0; i < scop->n_independence; ++i)
2192 space = independence_collect_params(scop->independences[i],
2193 space);
2195 return space;
2198 /* Add all parameters in "space" to the domain, schedule and
2199 * all access relations in "stmt".
2201 static struct pet_stmt *stmt_propagate_params(struct pet_stmt *stmt,
2202 __isl_take isl_space *space)
2204 int i;
2206 if (!stmt)
2207 goto error;
2209 stmt->domain = isl_set_align_params(stmt->domain,
2210 isl_space_copy(space));
2211 stmt->schedule = isl_map_align_params(stmt->schedule,
2212 isl_space_copy(space));
2214 for (i = 0; i < stmt->n_arg; ++i) {
2215 stmt->args[i] = pet_expr_align_params(stmt->args[i],
2216 isl_space_copy(space));
2217 if (!stmt->args[i])
2218 goto error;
2220 stmt->body = pet_tree_align_params(stmt->body, isl_space_copy(space));
2222 if (!stmt->domain || !stmt->schedule || !stmt->body)
2223 goto error;
2225 isl_space_free(space);
2226 return stmt;
2227 error:
2228 isl_space_free(space);
2229 return pet_stmt_free(stmt);
2232 /* Add all parameters in "space" to "array".
2234 static struct pet_array *array_propagate_params(struct pet_array *array,
2235 __isl_take isl_space *space)
2237 if (!array)
2238 goto error;
2240 array->context = isl_set_align_params(array->context,
2241 isl_space_copy(space));
2242 array->extent = isl_set_align_params(array->extent,
2243 isl_space_copy(space));
2244 if (array->value_bounds) {
2245 array->value_bounds = isl_set_align_params(array->value_bounds,
2246 isl_space_copy(space));
2247 if (!array->value_bounds)
2248 goto error;
2251 if (!array->context || !array->extent)
2252 goto error;
2254 isl_space_free(space);
2255 return array;
2256 error:
2257 isl_space_free(space);
2258 return pet_array_free(array);
2261 /* Add all parameters in "space" to "independence".
2263 static struct pet_independence *independence_propagate_params(
2264 struct pet_independence *independence, __isl_take isl_space *space)
2266 if (!independence)
2267 goto error;
2269 independence->filter = isl_union_map_align_params(independence->filter,
2270 isl_space_copy(space));
2271 independence->local = isl_union_set_align_params(independence->local,
2272 isl_space_copy(space));
2273 if (!independence->filter || !independence->local)
2274 goto error;
2276 isl_space_free(space);
2277 return independence;
2278 error:
2279 isl_space_free(space);
2280 return pet_independence_free(independence);
2283 /* Add all parameters in "space" to "scop".
2285 static struct pet_scop *scop_propagate_params(struct pet_scop *scop,
2286 __isl_take isl_space *space)
2288 int i;
2290 if (!scop)
2291 goto error;
2293 for (i = 0; i < scop->n_array; ++i) {
2294 scop->arrays[i] = array_propagate_params(scop->arrays[i],
2295 isl_space_copy(space));
2296 if (!scop->arrays[i])
2297 goto error;
2300 for (i = 0; i < scop->n_stmt; ++i) {
2301 scop->stmts[i] = stmt_propagate_params(scop->stmts[i],
2302 isl_space_copy(space));
2303 if (!scop->stmts[i])
2304 goto error;
2307 for (i = 0; i < scop->n_independence; ++i) {
2308 scop->independences[i] = independence_propagate_params(
2309 scop->independences[i], isl_space_copy(space));
2310 if (!scop->independences[i])
2311 goto error;
2314 isl_space_free(space);
2315 return scop;
2316 error:
2317 isl_space_free(space);
2318 return pet_scop_free(scop);
2321 /* Update all isl_sets and isl_maps in "scop" such that they all
2322 * have the same parameters.
2324 struct pet_scop *pet_scop_align_params(struct pet_scop *scop)
2326 isl_space *space;
2328 if (!scop)
2329 return NULL;
2331 space = isl_set_get_space(scop->context);
2332 space = scop_collect_params(scop, space);
2334 scop->context = isl_set_align_params(scop->context,
2335 isl_space_copy(space));
2336 scop = scop_propagate_params(scop, space);
2338 if (scop && !scop->context)
2339 return pet_scop_free(scop);
2341 return scop;
2344 /* Add the access relation of the access expression "expr" to "accesses" and
2345 * return the result.
2346 * The domain of the access relation is intersected with "domain".
2347 * If "tag" is set, then the access relation is tagged with
2348 * the corresponding reference identifier.
2350 static __isl_give isl_union_map *expr_collect_access(__isl_keep pet_expr *expr,
2351 int tag, __isl_take isl_union_map *accesses, __isl_keep isl_set *domain)
2353 isl_map *access;
2355 access = pet_expr_access_get_may_access(expr);
2356 access = isl_map_intersect_domain(access, isl_set_copy(domain));
2357 if (tag)
2358 access = pet_expr_tag_access(expr, access);
2359 return isl_union_map_add_map(accesses, access);
2362 /* Internal data structure for expr_collect_accesses.
2364 * "read" is set if we want to collect read accesses.
2365 * "write" is set if we want to collect write accesses.
2366 * "must" is set if we only want definite accesses.
2367 * "tag" is set if the access relations should be tagged with
2368 * the corresponding reference identifiers.
2369 * "domain" are constraints on the domain of the access relations.
2370 * "accesses" collects the results.
2372 struct pet_expr_collect_accesses_data {
2373 int read;
2374 int write;
2375 int must;
2376 int tag;
2377 isl_set *domain;
2379 isl_union_map *accesses;
2382 /* Add the access relation of the access expression "expr"
2383 * to data->accesses if the access expression is a read and data->read is set
2384 * and/or it is a write and data->write is set.
2385 * The domains of the access relations are intersected with data->domain.
2386 * If data->tag is set, then the access relations are tagged with
2387 * the corresponding reference identifiers.
2389 * If data->must is set, then we only add the accesses that are definitely
2390 * performed. Otherwise, we add all potential accesses.
2391 * In particular, if the access has any arguments, then if data->must is
2392 * set we currently skip the access completely. If data->must is not set,
2393 * we project out the values of the access arguments.
2395 static int expr_collect_accesses(__isl_keep pet_expr *expr, void *user)
2397 struct pet_expr_collect_accesses_data *data = user;
2398 int i;
2399 isl_id *id;
2400 isl_space *dim;
2402 if (!expr)
2403 return -1;
2405 if (pet_expr_is_affine(expr))
2406 return 0;
2407 if (data->must && expr->n_arg != 0)
2408 return 0;
2410 if ((data->read && expr->acc.read) || (data->write && expr->acc.write))
2411 data->accesses = expr_collect_access(expr, data->tag,
2412 data->accesses, data->domain);
2414 return data->accesses ? 0 : -1;
2417 /* Collect and return all read access relations (if "read" is set)
2418 * and/or all write access relations (if "write" is set) in "stmt".
2419 * If "tag" is set, then the access relations are tagged with
2420 * the corresponding reference identifiers.
2421 * If "kill" is set, then "stmt" is a kill statement and we simply
2422 * add the argument of the kill operation.
2424 * If "must" is set, then we only add the accesses that are definitely
2425 * performed. Otherwise, we add all potential accesses.
2426 * In particular, if the statement has any arguments, then if "must" is
2427 * set we currently skip the statement completely. If "must" is not set,
2428 * we project out the values of the statement arguments.
2429 * If the statement body is not an expression tree, then we cannot
2430 * know for sure if/when the accesses inside the tree are performed.
2431 * We therefore ignore such statements when "must" is set.
2433 static __isl_give isl_union_map *stmt_collect_accesses(struct pet_stmt *stmt,
2434 int read, int write, int kill, int must, int tag,
2435 __isl_take isl_space *dim)
2437 struct pet_expr_collect_accesses_data data = { read, write, must, tag };
2439 if (!stmt)
2440 return NULL;
2442 data.accesses = isl_union_map_empty(dim);
2444 if (must && stmt->n_arg > 0)
2445 return data.accesses;
2446 if (must && pet_tree_get_type(stmt->body) != pet_tree_expr)
2447 return data.accesses;
2449 data.domain = drop_arguments(isl_set_copy(stmt->domain));
2451 if (kill) {
2452 pet_expr *body, *arg;
2454 body = pet_tree_expr_get_expr(stmt->body);
2455 arg = pet_expr_get_arg(body, 0);
2456 data.accesses = expr_collect_access(arg, tag,
2457 data.accesses, data.domain);
2458 pet_expr_free(arg);
2459 pet_expr_free(body);
2460 } else if (pet_tree_foreach_access_expr(stmt->body,
2461 &expr_collect_accesses, &data) < 0)
2462 data.accesses = isl_union_map_free(data.accesses);
2464 isl_set_free(data.domain);
2466 return data.accesses;
2469 /* Is "stmt" an assignment statement?
2471 int pet_stmt_is_assign(struct pet_stmt *stmt)
2473 if (!stmt)
2474 return 0;
2475 return pet_tree_is_assign(stmt->body);
2478 /* Is "stmt" a kill statement?
2480 int pet_stmt_is_kill(struct pet_stmt *stmt)
2482 if (!stmt)
2483 return 0;
2484 return pet_tree_is_kill(stmt->body);
2487 /* Is "stmt" an assume statement?
2489 int pet_stmt_is_assume(struct pet_stmt *stmt)
2491 if (!stmt)
2492 return 0;
2493 return pet_tree_is_assume(stmt->body);
2496 /* Helper function to add a domain gisted copy of "map" (wrt "set") to "umap".
2498 static __isl_give isl_union_map *add_gisted(__isl_take isl_union_map *umap,
2499 __isl_keep isl_map *map, __isl_keep isl_set *set)
2501 isl_map *gist;
2503 gist = isl_map_copy(map);
2504 gist = isl_map_gist_domain(gist, isl_set_copy(set));
2505 return isl_union_map_add_map(umap, gist);
2508 /* Compute a mapping from all arrays (of structs) in scop
2509 * to their members.
2511 * If "from_outermost" is set, then the domain only consists
2512 * of outermost arrays.
2513 * If "to_innermost" is set, then the range only consists
2514 * of innermost arrays.
2516 static __isl_give isl_union_map *compute_to_inner(struct pet_scop *scop,
2517 int from_outermost, int to_innermost)
2519 int i;
2520 isl_union_map *to_inner;
2522 if (!scop)
2523 return NULL;
2525 to_inner = isl_union_map_empty(isl_set_get_space(scop->context));
2527 for (i = 0; i < scop->n_array; ++i) {
2528 struct pet_array *array = scop->arrays[i];
2529 isl_set *set;
2530 isl_map *map;
2532 if (to_innermost && array->element_is_record)
2533 continue;
2535 set = isl_set_copy(array->extent);
2536 map = isl_set_identity(isl_set_copy(set));
2538 while (set && isl_set_is_wrapping(set)) {
2539 isl_id *id;
2540 isl_map *wrapped;
2542 if (!from_outermost)
2543 to_inner = add_gisted(to_inner, map, set);
2545 id = isl_set_get_tuple_id(set);
2546 wrapped = isl_set_unwrap(set);
2547 wrapped = isl_map_domain_map(wrapped);
2548 wrapped = isl_map_set_tuple_id(wrapped, isl_dim_in, id);
2549 map = isl_map_apply_domain(map, wrapped);
2550 set = isl_map_domain(isl_map_copy(map));
2553 map = isl_map_gist_domain(map, set);
2554 to_inner = isl_union_map_add_map(to_inner, map);
2557 return to_inner;
2560 /* Compute a mapping from all arrays (of structs) in scop
2561 * to their innermost arrays.
2563 * In particular, for each array of a primitive type, the result
2564 * contains the identity mapping on that array.
2565 * For each array involving member accesses, the result
2566 * contains a mapping from the elements of any intermediate array of structs
2567 * to all corresponding elements of the innermost nested arrays.
2569 static __isl_give isl_union_map *pet_scop_compute_any_to_inner(
2570 struct pet_scop *scop)
2572 return compute_to_inner(scop, 0, 1);
2575 /* Compute a mapping from all outermost arrays (of structs) in scop
2576 * to their innermost members.
2578 __isl_give isl_union_map *pet_scop_compute_outer_to_inner(struct pet_scop *scop)
2580 return compute_to_inner(scop, 1, 1);
2583 /* Compute a mapping from all outermost arrays (of structs) in scop
2584 * to their members, including the outermost arrays themselves.
2586 __isl_give isl_union_map *pet_scop_compute_outer_to_any(struct pet_scop *scop)
2588 return compute_to_inner(scop, 1, 0);
2591 /* Collect and return all read access relations (if "read" is set)
2592 * and/or all write access relations (if "write" is set) in "scop".
2593 * If "kill" is set, then we only add the arguments of kill operations.
2594 * If "must" is set, then we only add the accesses that are definitely
2595 * performed. Otherwise, we add all potential accesses.
2596 * If "tag" is set, then the access relations are tagged with
2597 * the corresponding reference identifiers.
2598 * For accesses to structures, the returned access relation accesses
2599 * all individual fields in the structures.
2601 static __isl_give isl_union_map *scop_collect_accesses(struct pet_scop *scop,
2602 int read, int write, int kill, int must, int tag)
2604 int i;
2605 isl_union_map *accesses;
2606 isl_union_set *arrays;
2607 isl_union_map *to_inner;
2609 if (!scop)
2610 return NULL;
2612 accesses = isl_union_map_empty(isl_set_get_space(scop->context));
2614 for (i = 0; i < scop->n_stmt; ++i) {
2615 struct pet_stmt *stmt = scop->stmts[i];
2616 isl_union_map *accesses_i;
2617 isl_space *space;
2619 if (kill && !pet_stmt_is_kill(stmt))
2620 continue;
2622 space = isl_set_get_space(scop->context);
2623 accesses_i = stmt_collect_accesses(stmt, read, write, kill,
2624 must, tag, space);
2625 accesses = isl_union_map_union(accesses, accesses_i);
2628 arrays = isl_union_set_empty(isl_union_map_get_space(accesses));
2629 for (i = 0; i < scop->n_array; ++i) {
2630 isl_set *extent = isl_set_copy(scop->arrays[i]->extent);
2631 arrays = isl_union_set_add_set(arrays, extent);
2633 accesses = isl_union_map_intersect_range(accesses, arrays);
2635 to_inner = pet_scop_compute_any_to_inner(scop);
2636 accesses = isl_union_map_apply_range(accesses, to_inner);
2638 return accesses;
2641 /* Collect all potential read access relations.
2643 __isl_give isl_union_map *pet_scop_collect_may_reads(struct pet_scop *scop)
2645 return scop_collect_accesses(scop, 1, 0, 0, 0, 0);
2648 /* Collect all potential write access relations.
2650 __isl_give isl_union_map *pet_scop_collect_may_writes(struct pet_scop *scop)
2652 return scop_collect_accesses(scop, 0, 1, 0, 0, 0);
2655 /* Collect all definite write access relations.
2657 __isl_give isl_union_map *pet_scop_collect_must_writes(struct pet_scop *scop)
2659 return scop_collect_accesses(scop, 0, 1, 0, 1, 0);
2662 /* Collect all definite kill access relations.
2664 __isl_give isl_union_map *pet_scop_collect_must_kills(struct pet_scop *scop)
2666 return scop_collect_accesses(scop, 0, 0, 1, 1, 0);
2669 /* Collect all tagged potential read access relations.
2671 __isl_give isl_union_map *pet_scop_collect_tagged_may_reads(
2672 struct pet_scop *scop)
2674 return scop_collect_accesses(scop, 1, 0, 0, 0, 1);
2677 /* Collect all tagged potential write access relations.
2679 __isl_give isl_union_map *pet_scop_collect_tagged_may_writes(
2680 struct pet_scop *scop)
2682 return scop_collect_accesses(scop, 0, 1, 0, 0, 1);
2685 /* Collect all tagged definite write access relations.
2687 __isl_give isl_union_map *pet_scop_collect_tagged_must_writes(
2688 struct pet_scop *scop)
2690 return scop_collect_accesses(scop, 0, 1, 0, 1, 1);
2693 /* Collect all tagged definite kill access relations.
2695 __isl_give isl_union_map *pet_scop_collect_tagged_must_kills(
2696 struct pet_scop *scop)
2698 return scop_collect_accesses(scop, 0, 0, 1, 1, 1);
2701 /* Collect and return the union of iteration domains in "scop".
2703 __isl_give isl_union_set *pet_scop_collect_domains(struct pet_scop *scop)
2705 int i;
2706 isl_set *domain_i;
2707 isl_union_set *domain;
2709 if (!scop)
2710 return NULL;
2712 domain = isl_union_set_empty(isl_set_get_space(scop->context));
2714 for (i = 0; i < scop->n_stmt; ++i) {
2715 domain_i = isl_set_copy(scop->stmts[i]->domain);
2716 domain = isl_union_set_add_set(domain, domain_i);
2719 return domain;
2722 /* Collect and return the schedules of the statements in "scop".
2723 * The range is normalized to the maximal number of scheduling
2724 * dimensions.
2726 __isl_give isl_union_map *pet_scop_collect_schedule(struct pet_scop *scop)
2728 int i, j;
2729 isl_map *schedule_i;
2730 isl_union_map *schedule;
2731 int depth, max_depth = 0;
2733 if (!scop)
2734 return NULL;
2736 schedule = isl_union_map_empty(isl_set_get_space(scop->context));
2738 for (i = 0; i < scop->n_stmt; ++i) {
2739 depth = isl_map_dim(scop->stmts[i]->schedule, isl_dim_out);
2740 if (depth > max_depth)
2741 max_depth = depth;
2744 for (i = 0; i < scop->n_stmt; ++i) {
2745 schedule_i = isl_map_copy(scop->stmts[i]->schedule);
2746 depth = isl_map_dim(schedule_i, isl_dim_out);
2747 schedule_i = isl_map_add_dims(schedule_i, isl_dim_out,
2748 max_depth - depth);
2749 for (j = depth; j < max_depth; ++j)
2750 schedule_i = isl_map_fix_si(schedule_i,
2751 isl_dim_out, j, 0);
2752 schedule = isl_union_map_add_map(schedule, schedule_i);
2755 return schedule;
2758 /* Add a reference identifier to all access expressions in "stmt".
2759 * "n_ref" points to an integer that contains the sequence number
2760 * of the next reference.
2762 static struct pet_stmt *stmt_add_ref_ids(struct pet_stmt *stmt, int *n_ref)
2764 int i;
2766 if (!stmt)
2767 return NULL;
2769 for (i = 0; i < stmt->n_arg; ++i) {
2770 stmt->args[i] = pet_expr_add_ref_ids(stmt->args[i], n_ref);
2771 if (!stmt->args[i])
2772 return pet_stmt_free(stmt);
2775 stmt->body = pet_tree_add_ref_ids(stmt->body, n_ref);
2776 if (!stmt->body)
2777 return pet_stmt_free(stmt);
2779 return stmt;
2782 /* Add a reference identifier to all access expressions in "scop".
2784 struct pet_scop *pet_scop_add_ref_ids(struct pet_scop *scop)
2786 int i;
2787 int n_ref;
2789 if (!scop)
2790 return NULL;
2792 n_ref = 0;
2793 for (i = 0; i < scop->n_stmt; ++i) {
2794 scop->stmts[i] = stmt_add_ref_ids(scop->stmts[i], &n_ref);
2795 if (!scop->stmts[i])
2796 return pet_scop_free(scop);
2799 return scop;
2802 /* Reset the user pointer on all parameter ids in "array".
2804 static struct pet_array *array_anonymize(struct pet_array *array)
2806 if (!array)
2807 return NULL;
2809 array->context = isl_set_reset_user(array->context);
2810 array->extent = isl_set_reset_user(array->extent);
2811 if (!array->context || !array->extent)
2812 return pet_array_free(array);
2814 return array;
2817 /* Reset the user pointer on all parameter and tuple ids in "stmt".
2819 static struct pet_stmt *stmt_anonymize(struct pet_stmt *stmt)
2821 int i;
2822 isl_space *space;
2823 isl_set *domain;
2825 if (!stmt)
2826 return NULL;
2828 stmt->domain = isl_set_reset_user(stmt->domain);
2829 stmt->schedule = isl_map_reset_user(stmt->schedule);
2830 if (!stmt->domain || !stmt->schedule)
2831 return pet_stmt_free(stmt);
2833 for (i = 0; i < stmt->n_arg; ++i) {
2834 stmt->args[i] = pet_expr_anonymize(stmt->args[i]);
2835 if (!stmt->args[i])
2836 return pet_stmt_free(stmt);
2839 stmt->body = pet_tree_anonymize(stmt->body);
2840 if (!stmt->body)
2841 return pet_stmt_free(stmt);
2843 return stmt;
2846 /* Reset the user pointer on the tuple ids and all parameter ids
2847 * in "implication".
2849 static struct pet_implication *implication_anonymize(
2850 struct pet_implication *implication)
2852 if (!implication)
2853 return NULL;
2855 implication->extension = isl_map_reset_user(implication->extension);
2856 if (!implication->extension)
2857 return pet_implication_free(implication);
2859 return implication;
2862 /* Reset the user pointer on the tuple ids and all parameter ids
2863 * in "independence".
2865 static struct pet_independence *independence_anonymize(
2866 struct pet_independence *independence)
2868 if (!independence)
2869 return NULL;
2871 independence->filter = isl_union_map_reset_user(independence->filter);
2872 independence->local = isl_union_set_reset_user(independence->local);
2873 if (!independence->filter || !independence->local)
2874 return pet_independence_free(independence);
2876 return independence;
2879 /* Reset the user pointer on all parameter and tuple ids in "scop".
2881 struct pet_scop *pet_scop_anonymize(struct pet_scop *scop)
2883 int i;
2885 if (!scop)
2886 return NULL;
2888 scop->context = isl_set_reset_user(scop->context);
2889 scop->context_value = isl_set_reset_user(scop->context_value);
2890 if (!scop->context || !scop->context_value)
2891 return pet_scop_free(scop);
2893 for (i = 0; i < scop->n_array; ++i) {
2894 scop->arrays[i] = array_anonymize(scop->arrays[i]);
2895 if (!scop->arrays[i])
2896 return pet_scop_free(scop);
2899 for (i = 0; i < scop->n_stmt; ++i) {
2900 scop->stmts[i] = stmt_anonymize(scop->stmts[i]);
2901 if (!scop->stmts[i])
2902 return pet_scop_free(scop);
2905 for (i = 0; i < scop->n_implication; ++i) {
2906 scop->implications[i] =
2907 implication_anonymize(scop->implications[i]);
2908 if (!scop->implications[i])
2909 return pet_scop_free(scop);
2912 for (i = 0; i < scop->n_independence; ++i) {
2913 scop->independences[i] =
2914 independence_anonymize(scop->independences[i]);
2915 if (!scop->independences[i])
2916 return pet_scop_free(scop);
2919 return scop;
2922 /* Compute the gist of the iteration domain and all access relations
2923 * of "stmt" based on the constraints on the parameters specified by "context"
2924 * and the constraints on the values of nested accesses specified
2925 * by "value_bounds".
2927 static struct pet_stmt *stmt_gist(struct pet_stmt *stmt,
2928 __isl_keep isl_set *context, __isl_keep isl_union_map *value_bounds)
2930 int i;
2931 isl_set *domain;
2933 if (!stmt)
2934 return NULL;
2936 domain = isl_set_copy(stmt->domain);
2937 if (stmt->n_arg > 0)
2938 domain = isl_map_domain(isl_set_unwrap(domain));
2940 domain = isl_set_intersect_params(domain, isl_set_copy(context));
2942 for (i = 0; i < stmt->n_arg; ++i) {
2943 stmt->args[i] = pet_expr_gist(stmt->args[i],
2944 domain, value_bounds);
2945 if (!stmt->args[i])
2946 goto error;
2949 stmt->body = pet_tree_gist(stmt->body, domain, value_bounds);
2950 if (!stmt->body)
2951 goto error;
2953 isl_set_free(domain);
2955 domain = isl_set_universe(pet_stmt_get_space(stmt));
2956 domain = isl_set_intersect_params(domain, isl_set_copy(context));
2957 if (stmt->n_arg > 0)
2958 domain = pet_value_bounds_apply(domain, stmt->n_arg, stmt->args,
2959 value_bounds);
2960 stmt->domain = isl_set_gist(stmt->domain, domain);
2961 if (!stmt->domain)
2962 return pet_stmt_free(stmt);
2964 return stmt;
2965 error:
2966 isl_set_free(domain);
2967 return pet_stmt_free(stmt);
2970 /* Compute the gist of the extent of the array
2971 * based on the constraints on the parameters specified by "context".
2973 static struct pet_array *array_gist(struct pet_array *array,
2974 __isl_keep isl_set *context)
2976 if (!array)
2977 return NULL;
2979 array->extent = isl_set_gist_params(array->extent,
2980 isl_set_copy(context));
2981 if (!array->extent)
2982 return pet_array_free(array);
2984 return array;
2987 /* Compute the gist of all sets and relations in "scop"
2988 * based on the constraints on the parameters specified by "scop->context"
2989 * and the constraints on the values of nested accesses specified
2990 * by "value_bounds".
2992 struct pet_scop *pet_scop_gist(struct pet_scop *scop,
2993 __isl_keep isl_union_map *value_bounds)
2995 int i;
2997 if (!scop)
2998 return NULL;
3000 scop->context = isl_set_coalesce(scop->context);
3001 if (!scop->context)
3002 return pet_scop_free(scop);
3004 for (i = 0; i < scop->n_array; ++i) {
3005 scop->arrays[i] = array_gist(scop->arrays[i], scop->context);
3006 if (!scop->arrays[i])
3007 return pet_scop_free(scop);
3010 for (i = 0; i < scop->n_stmt; ++i) {
3011 scop->stmts[i] = stmt_gist(scop->stmts[i], scop->context,
3012 value_bounds);
3013 if (!scop->stmts[i])
3014 return pet_scop_free(scop);
3017 return scop;
3020 /* Intersect the context of "scop" with "context".
3021 * To ensure that we don't introduce any unnamed parameters in
3022 * the context of "scop", we first remove the unnamed parameters
3023 * from "context".
3025 struct pet_scop *pet_scop_restrict_context(struct pet_scop *scop,
3026 __isl_take isl_set *context)
3028 if (!scop)
3029 goto error;
3031 context = pet_nested_remove_from_set(context);
3032 scop->context = isl_set_intersect(scop->context, context);
3033 if (!scop->context)
3034 return pet_scop_free(scop);
3036 return scop;
3037 error:
3038 isl_set_free(context);
3039 return pet_scop_free(scop);
3042 /* Drop the current context of "scop". That is, replace the context
3043 * by a universal set.
3045 struct pet_scop *pet_scop_reset_context(struct pet_scop *scop)
3047 isl_space *space;
3049 if (!scop)
3050 return NULL;
3052 space = isl_set_get_space(scop->context);
3053 isl_set_free(scop->context);
3054 scop->context = isl_set_universe(space);
3055 if (!scop->context)
3056 return pet_scop_free(scop);
3058 return scop;
3061 /* Append "array" to the arrays of "scop".
3063 struct pet_scop *pet_scop_add_array(struct pet_scop *scop,
3064 struct pet_array *array)
3066 isl_ctx *ctx;
3067 struct pet_array **arrays;
3069 if (!array || !scop)
3070 goto error;
3072 ctx = isl_set_get_ctx(scop->context);
3073 arrays = isl_realloc_array(ctx, scop->arrays, struct pet_array *,
3074 scop->n_array + 1);
3075 if (!arrays)
3076 goto error;
3077 scop->arrays = arrays;
3078 scop->arrays[scop->n_array] = array;
3079 scop->n_array++;
3081 return scop;
3082 error:
3083 pet_array_free(array);
3084 return pet_scop_free(scop);
3087 /* Create an index expression for an access to a virtual array
3088 * representing the result of a condition.
3089 * Unlike other accessed data, the id of the array is NULL as
3090 * there is no ValueDecl in the program corresponding to the virtual
3091 * array.
3092 * The index expression is created as an identity mapping on "space".
3093 * That is, the dimension of the array is the same as that of "space".
3095 __isl_give isl_multi_pw_aff *pet_create_test_index(__isl_take isl_space *space,
3096 int test_nr)
3098 isl_id *id;
3099 char name[50];
3101 snprintf(name, sizeof(name), "__pet_test_%d", test_nr);
3102 id = isl_id_alloc(isl_space_get_ctx(space), name, NULL);
3103 space = isl_space_map_from_set(space);
3104 space = isl_space_set_tuple_id(space, isl_dim_out, id);
3105 return isl_multi_pw_aff_identity(space);
3108 /* Add an array with the given extent to the list
3109 * of arrays in "scop" and return the extended pet_scop.
3110 * Specifically, the extent is determined by the image of "domain"
3111 * under "index".
3112 * "int_size" is the number of bytes needed to represent values of type "int".
3113 * The array is marked as attaining values 0 and 1 only and
3114 * as each element being assigned at most once.
3116 struct pet_scop *pet_scop_add_boolean_array(struct pet_scop *scop,
3117 __isl_take isl_set *domain, __isl_take isl_multi_pw_aff *index,
3118 int int_size)
3120 isl_ctx *ctx;
3121 isl_space *space;
3122 struct pet_array *array;
3123 isl_map *access;
3125 if (!scop || !domain || !index)
3126 goto error;
3128 ctx = isl_multi_pw_aff_get_ctx(index);
3129 array = isl_calloc_type(ctx, struct pet_array);
3130 if (!array)
3131 goto error;
3133 access = isl_map_from_multi_pw_aff(index);
3134 access = isl_map_intersect_domain(access, domain);
3135 array->extent = isl_map_range(access);
3136 space = isl_space_params_alloc(ctx, 0);
3137 array->context = isl_set_universe(space);
3138 space = isl_space_set_alloc(ctx, 0, 1);
3139 array->value_bounds = isl_set_universe(space);
3140 array->value_bounds = isl_set_lower_bound_si(array->value_bounds,
3141 isl_dim_set, 0, 0);
3142 array->value_bounds = isl_set_upper_bound_si(array->value_bounds,
3143 isl_dim_set, 0, 1);
3144 array->element_type = strdup("int");
3145 array->element_size = int_size;
3146 array->uniquely_defined = 1;
3148 if (!array->extent || !array->context)
3149 array = pet_array_free(array);
3151 scop = pet_scop_add_array(scop, array);
3153 return scop;
3154 error:
3155 isl_set_free(domain);
3156 isl_multi_pw_aff_free(index);
3157 return pet_scop_free(scop);
3160 /* Create and return an implication on filter values equal to "satisfied"
3161 * with extension "map".
3163 static struct pet_implication *new_implication(__isl_take isl_map *map,
3164 int satisfied)
3166 isl_ctx *ctx;
3167 struct pet_implication *implication;
3169 if (!map)
3170 return NULL;
3171 ctx = isl_map_get_ctx(map);
3172 implication = isl_alloc_type(ctx, struct pet_implication);
3173 if (!implication)
3174 goto error;
3176 implication->extension = map;
3177 implication->satisfied = satisfied;
3179 return implication;
3180 error:
3181 isl_map_free(map);
3182 return NULL;
3185 /* Add an implication on filter values equal to "satisfied"
3186 * with extension "map" to "scop".
3188 struct pet_scop *pet_scop_add_implication(struct pet_scop *scop,
3189 __isl_take isl_map *map, int satisfied)
3191 isl_ctx *ctx;
3192 struct pet_implication *implication;
3193 struct pet_implication **implications;
3195 implication = new_implication(map, satisfied);
3196 if (!scop || !implication)
3197 goto error;
3199 ctx = isl_set_get_ctx(scop->context);
3200 implications = isl_realloc_array(ctx, scop->implications,
3201 struct pet_implication *,
3202 scop->n_implication + 1);
3203 if (!implications)
3204 goto error;
3205 scop->implications = implications;
3206 scop->implications[scop->n_implication] = implication;
3207 scop->n_implication++;
3209 return scop;
3210 error:
3211 pet_implication_free(implication);
3212 return pet_scop_free(scop);
3215 /* Create and return a function that maps the iteration domains
3216 * of the statements in "scop" onto their outer "n" dimensions.
3217 * "space" is the parameters space of the created function.
3219 static __isl_give isl_union_pw_multi_aff *outer_projection(
3220 struct pet_scop *scop, __isl_take isl_space *space, int n)
3222 int i;
3223 isl_union_pw_multi_aff *res;
3225 res = isl_union_pw_multi_aff_empty(space);
3227 if (!scop)
3228 return isl_union_pw_multi_aff_free(res);
3230 for (i = 0; i < scop->n_stmt; ++i) {
3231 struct pet_stmt *stmt = scop->stmts[i];
3232 isl_space *space;
3233 isl_multi_aff *ma;
3234 isl_pw_multi_aff *pma;
3236 space = pet_stmt_get_space(stmt);
3237 ma = pet_prefix_projection(space, n);
3238 pma = isl_pw_multi_aff_from_multi_aff(ma);
3239 res = isl_union_pw_multi_aff_add_pw_multi_aff(res, pma);
3242 return res;
3245 /* Add an independence to "scop" for the inner iterator of "domain"
3246 * with local variables "local", where "domain" represents the outer
3247 * loop iterators of all statements in "scop".
3248 * If "sign" is positive, then the inner iterator increases.
3249 * Otherwise it decreases.
3251 * The independence is supposed to filter out any dependence of
3252 * an iteration of domain on a previous iteration along the inner dimension.
3253 * We therefore create a mapping from an iteration to later iterations and
3254 * then plug in the projection of the iterations domains of "scop"
3255 * onto the outer loop iterators.
3257 struct pet_scop *pet_scop_set_independent(struct pet_scop *scop,
3258 __isl_keep isl_set *domain, __isl_take isl_union_set *local, int sign)
3260 int i, dim;
3261 isl_space *space;
3262 isl_map *map;
3263 isl_union_map *independence;
3264 isl_union_pw_multi_aff *proj;
3266 if (!scop || !domain || !local)
3267 goto error;
3269 dim = isl_set_dim(domain, isl_dim_set);
3270 space = isl_space_map_from_set(isl_set_get_space(domain));
3271 map = isl_map_universe(space);
3272 for (i = 0; i + 1 < dim; ++i)
3273 map = isl_map_equate(map, isl_dim_in, i, isl_dim_out, i);
3274 if (sign > 0)
3275 map = isl_map_order_lt(map,
3276 isl_dim_in, dim - 1, isl_dim_out, dim - 1);
3277 else
3278 map = isl_map_order_gt(map,
3279 isl_dim_in, dim - 1, isl_dim_out, dim - 1);
3281 independence = isl_union_map_from_map(map);
3282 space = isl_space_params(isl_set_get_space(domain));
3283 proj = outer_projection(scop, space, dim);
3284 independence = isl_union_map_preimage_domain_union_pw_multi_aff(
3285 independence, isl_union_pw_multi_aff_copy(proj));
3286 independence = isl_union_map_preimage_range_union_pw_multi_aff(
3287 independence, proj);
3289 scop = pet_scop_add_independence(scop, independence, local);
3291 return scop;
3292 error:
3293 isl_union_set_free(local);
3294 return pet_scop_free(scop);
3297 /* Given an access expression, check if it is data dependent.
3298 * If so, set *found and abort the search.
3300 static int is_data_dependent(__isl_keep pet_expr *expr, void *user)
3302 int *found = user;
3304 if (pet_expr_get_n_arg(expr) > 0) {
3305 *found = 1;
3306 return -1;
3309 return 0;
3312 /* Does "scop" contain any data dependent accesses?
3314 * Check the body of each statement for such accesses.
3316 int pet_scop_has_data_dependent_accesses(struct pet_scop *scop)
3318 int i;
3319 int found = 0;
3321 if (!scop)
3322 return -1;
3324 for (i = 0; i < scop->n_stmt; ++i) {
3325 int r = pet_tree_foreach_access_expr(scop->stmts[i]->body,
3326 &is_data_dependent, &found);
3327 if (r < 0 && !found)
3328 return -1;
3329 if (found)
3330 return found;
3333 return found;
3336 /* Does "scop" contain and data dependent conditions?
3338 int pet_scop_has_data_dependent_conditions(struct pet_scop *scop)
3340 int i;
3342 if (!scop)
3343 return -1;
3345 for (i = 0; i < scop->n_stmt; ++i)
3346 if (scop->stmts[i]->n_arg > 0)
3347 return 1;
3349 return 0;
3352 /* Keep track of the "input" file inside the (extended) "scop".
3354 struct pet_scop *pet_scop_set_input_file(struct pet_scop *scop, FILE *input)
3356 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
3358 if (!scop)
3359 return NULL;
3361 ext->input = input;
3363 return scop;
3366 /* Print the original code corresponding to "scop" to printer "p".
3368 * pet_scop_print_original can only be called from
3369 * a pet_transform_C_source callback. This means that the input
3370 * file is stored in the extended scop and that the printer prints
3371 * to a file.
3373 __isl_give isl_printer *pet_scop_print_original(struct pet_scop *scop,
3374 __isl_take isl_printer *p)
3376 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
3377 FILE *output;
3378 unsigned start, end;
3380 if (!scop || !p)
3381 return isl_printer_free(p);
3383 if (!ext->input)
3384 isl_die(isl_printer_get_ctx(p), isl_error_invalid,
3385 "no input file stored in scop",
3386 return isl_printer_free(p));
3388 output = isl_printer_get_file(p);
3389 if (!output)
3390 return isl_printer_free(p);
3392 start = pet_loc_get_start(scop->loc);
3393 end = pet_loc_get_end(scop->loc);
3394 if (copy(ext->input, output, start, end) < 0)
3395 return isl_printer_free(p);
3397 return p;