update isl to version 0.13
[pet.git] / scop.c
blob5fc4d2a553a0b9744cced2525c3b5394bdccf6d0
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 /* Return the constraints on the iteration domain in the access relation
305 * "access".
306 * If the corresponding access expression has arguments then the domain
307 * of "access" is a wrapped relation with the iteration domain in the domain
308 * and the arguments in the range.
310 static __isl_give isl_set *access_domain(__isl_take isl_map *access)
312 isl_set *domain;
314 domain = isl_map_domain(access);
315 if (isl_set_is_wrapping(domain))
316 domain = isl_map_domain(isl_set_unwrap(domain));
318 return domain;
321 /* Update "context" with the constraints imposed on the outer iteration
322 * domain by "access".
323 * "context" lives in an anonymous space, while the domain of "access"
324 * refers to a particular statement. This reference therefore needs to be
325 * stripped off.
327 static __isl_give isl_set *access_extract_context(__isl_keep isl_map *access,
328 __isl_take isl_set *context)
330 isl_set *domain;
332 domain = access_domain(isl_map_copy(access));
333 domain = isl_set_reset_tuple_id(domain);
334 context = isl_set_intersect(context, domain);
335 return context;
338 /* Update "context" with the constraints imposed on the outer iteration
339 * domain by "expr".
341 * "context" lives in an anonymous space, while the domains of
342 * the access relations in "expr" refer to a particular statement.
343 * This reference therefore needs to be stripped off.
345 * If "expr" represents a conditional operator, then a parameter or outer
346 * iterator value needs to be valid for the condition and
347 * for at least one of the remaining two arguments.
348 * If the condition is an affine expression, then we can be a bit more specific.
349 * The value then has to be valid for the second argument for
350 * non-zero accesses and valid for the third argument for zero accesses.
352 * If "expr" represents a kill statement, then its argument is the entire
353 * extent of the array being killed. Do not update "context" based
354 * on this argument as that would impose constraints that ensure that
355 * the array is non-empty.
357 static __isl_give isl_set *expr_extract_context(__isl_keep pet_expr *expr,
358 __isl_take isl_set *context)
360 int i;
362 if (expr->type == pet_expr_op && expr->op == pet_op_kill)
363 return context;
365 if (expr->type == pet_expr_op && expr->op == pet_op_cond) {
366 int is_aff;
367 isl_set *context1, *context2;
369 is_aff = pet_expr_is_affine(expr->args[0]);
370 if (is_aff < 0)
371 goto error;
373 context = expr_extract_context(expr->args[0], context);
374 context1 = expr_extract_context(expr->args[1],
375 isl_set_copy(context));
376 context2 = expr_extract_context(expr->args[2], context);
378 if (is_aff) {
379 isl_map *access;
380 isl_set *zero_set;
382 access = isl_map_copy(expr->args[0]->acc.access);
383 access = isl_map_fix_si(access, isl_dim_out, 0, 0);
384 zero_set = access_domain(access);
385 zero_set = isl_set_reset_tuple_id(zero_set);
386 context1 = isl_set_subtract(context1,
387 isl_set_copy(zero_set));
388 context2 = isl_set_intersect(context2, zero_set);
391 context = isl_set_union(context1, context2);
392 context = isl_set_coalesce(context);
394 return context;
397 for (i = 0; i < expr->n_arg; ++i)
398 context = expr_extract_context(expr->args[i], context);
400 if (expr->type == pet_expr_access)
401 context = access_extract_context(expr->acc.access, context);
403 return context;
404 error:
405 isl_set_free(context);
406 return NULL;
409 /* Is "stmt" an assume statement with an affine assumption?
411 int pet_stmt_is_affine_assume(struct pet_stmt *stmt)
413 if (!stmt)
414 return 0;
415 return pet_tree_is_affine_assume(stmt->body);
418 /* Given an assume statement "stmt" with an access argument,
419 * return the index expression of the argument.
421 __isl_give isl_multi_pw_aff *pet_stmt_assume_get_index(struct pet_stmt *stmt)
423 if (!stmt)
424 return NULL;
425 return pet_tree_assume_get_index(stmt->body);
428 /* Update "context" with the constraints imposed on the outer iteration
429 * domain by "stmt".
431 * If the statement is an assume statement with an affine expression,
432 * then intersect "context" with that expression.
433 * Otherwise, if the statement body is an expression tree,
434 * then intersect "context" with the context of this expression.
435 * Note that we cannot safely extract a context from subtrees
436 * of the statement body since we cannot tell when those subtrees
437 * are executed, if at all.
439 static __isl_give isl_set *stmt_extract_context(struct pet_stmt *stmt,
440 __isl_take isl_set *context)
442 int i;
443 pet_expr *body;
445 if (pet_stmt_is_affine_assume(stmt)) {
446 isl_multi_pw_aff *index;
447 isl_pw_aff *pa;
448 isl_set *cond;
450 index = pet_stmt_assume_get_index(stmt);
451 pa = isl_multi_pw_aff_get_pw_aff(index, 0);
452 isl_multi_pw_aff_free(index);
453 cond = isl_pw_aff_non_zero_set(pa);
454 cond = isl_set_reset_tuple_id(cond);
455 return isl_set_intersect(context, cond);
458 for (i = 0; i < stmt->n_arg; ++i)
459 context = expr_extract_context(stmt->args[i], context);
461 if (pet_tree_get_type(stmt->body) != pet_tree_expr)
462 return context;
464 body = pet_tree_expr_get_expr(stmt->body);
465 context = expr_extract_context(body, context);
466 pet_expr_free(body);
468 return context;
471 /* Construct a pet_scop in the given space that contains the given pet_stmt.
473 struct pet_scop *pet_scop_from_pet_stmt(__isl_take isl_space *space,
474 struct pet_stmt *stmt)
476 struct pet_scop *scop;
478 if (!stmt)
479 space = isl_space_free(space);
481 scop = scop_alloc(space, 1);
482 if (!scop)
483 goto error;
485 scop->context = stmt_extract_context(stmt, scop->context);
486 if (!scop->context)
487 goto error;
489 scop->stmts[0] = stmt;
490 scop->loc = pet_loc_copy(stmt->loc);
492 if (!scop->loc)
493 return pet_scop_free(scop);
495 return scop;
496 error:
497 pet_stmt_free(stmt);
498 pet_scop_free(scop);
499 return NULL;
502 /* Does "mpa" represent an access to an element of an unnamed space, i.e.,
503 * does it represent an affine expression?
505 static int multi_pw_aff_is_affine(__isl_keep isl_multi_pw_aff *mpa)
507 int has_id;
509 has_id = isl_multi_pw_aff_has_tuple_id(mpa, isl_dim_out);
510 if (has_id < 0)
511 return -1;
513 return !has_id;
516 /* Return the piecewise affine expression "set ? 1 : 0" defined on "dom".
518 static __isl_give isl_pw_aff *indicator_function(__isl_take isl_set *set,
519 __isl_take isl_set *dom)
521 isl_pw_aff *pa;
522 pa = isl_set_indicator_function(set);
523 pa = isl_pw_aff_intersect_domain(pa, dom);
524 return pa;
527 /* Return "lhs || rhs", defined on the shared definition domain.
529 static __isl_give isl_pw_aff *pw_aff_or(__isl_take isl_pw_aff *lhs,
530 __isl_take isl_pw_aff *rhs)
532 isl_set *cond;
533 isl_set *dom;
535 dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(lhs)),
536 isl_pw_aff_domain(isl_pw_aff_copy(rhs)));
537 cond = isl_set_union(isl_pw_aff_non_zero_set(lhs),
538 isl_pw_aff_non_zero_set(rhs));
539 cond = isl_set_coalesce(cond);
540 return indicator_function(cond, dom);
543 /* Combine ext1->skip[type] and ext2->skip[type] into ext->skip[type].
544 * ext may be equal to either ext1 or ext2.
546 * The two skips that need to be combined are assumed to be affine expressions.
548 * We need to skip in ext if we need to skip in either ext1 or ext2.
549 * We don't need to skip in ext if we don't need to skip in both ext1 and ext2.
551 static struct pet_scop_ext *combine_skips(struct pet_scop_ext *ext,
552 struct pet_scop_ext *ext1, struct pet_scop_ext *ext2,
553 enum pet_skip type)
555 isl_pw_aff *skip, *skip1, *skip2;
557 if (!ext)
558 return NULL;
559 if (!ext1->skip[type] && !ext2->skip[type])
560 return ext;
561 if (!ext1->skip[type]) {
562 if (ext == ext2)
563 return ext;
564 ext->skip[type] = ext2->skip[type];
565 ext2->skip[type] = NULL;
566 return ext;
568 if (!ext2->skip[type]) {
569 if (ext == ext1)
570 return ext;
571 ext->skip[type] = ext1->skip[type];
572 ext1->skip[type] = NULL;
573 return ext;
576 if (!multi_pw_aff_is_affine(ext1->skip[type]) ||
577 !multi_pw_aff_is_affine(ext2->skip[type]))
578 isl_die(isl_multi_pw_aff_get_ctx(ext1->skip[type]),
579 isl_error_internal, "can only combine affine skips",
580 goto error);
582 skip1 = isl_multi_pw_aff_get_pw_aff(ext1->skip[type], 0);
583 skip2 = isl_multi_pw_aff_get_pw_aff(ext2->skip[type], 0);
584 skip = pw_aff_or(skip1, skip2);
585 isl_multi_pw_aff_free(ext1->skip[type]);
586 ext1->skip[type] = NULL;
587 isl_multi_pw_aff_free(ext2->skip[type]);
588 ext2->skip[type] = NULL;
589 ext->skip[type] = isl_multi_pw_aff_from_pw_aff(skip);
590 if (!ext->skip[type])
591 goto error;
593 return ext;
594 error:
595 pet_scop_free(&ext->scop);
596 return NULL;
599 /* Combine scop1->skip[type] and scop2->skip[type] into scop->skip[type],
600 * where type takes on the values pet_skip_now and pet_skip_later.
601 * scop may be equal to either scop1 or scop2.
603 static struct pet_scop *scop_combine_skips(struct pet_scop *scop,
604 struct pet_scop *scop1, struct pet_scop *scop2)
606 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
607 struct pet_scop_ext *ext1 = (struct pet_scop_ext *) scop1;
608 struct pet_scop_ext *ext2 = (struct pet_scop_ext *) scop2;
610 ext = combine_skips(ext, ext1, ext2, pet_skip_now);
611 ext = combine_skips(ext, ext1, ext2, pet_skip_later);
612 return &ext->scop;
615 /* Update start and end of scop->loc to include the region from "start"
616 * to "end". In particular, if scop->loc == &pet_loc_dummy, then "scop"
617 * does not have any offset information yet and we simply take the information
618 * from "start" and "end". Otherwise, we update loc using "start" and "end".
620 struct pet_scop *pet_scop_update_start_end(struct pet_scop *scop,
621 unsigned start, unsigned end)
623 if (!scop)
624 return NULL;
626 if (scop->loc == &pet_loc_dummy)
627 scop->loc = pet_loc_alloc(isl_set_get_ctx(scop->context),
628 start, end, -1, strdup(""));
629 else
630 scop->loc = pet_loc_update_start_end(scop->loc, start, end);
632 if (!scop->loc)
633 return pet_scop_free(scop);
635 return scop;
638 /* Update start and end of scop->loc to include the region identified
639 * by "loc".
641 struct pet_scop *pet_scop_update_start_end_from_loc(struct pet_scop *scop,
642 __isl_keep pet_loc *loc)
644 return pet_scop_update_start_end(scop, pet_loc_get_start(loc),
645 pet_loc_get_end(loc));
648 /* Replace the location of "scop" by "loc".
650 struct pet_scop *pet_scop_set_loc(struct pet_scop *scop,
651 __isl_take pet_loc *loc)
653 if (!scop || !loc)
654 goto error;
656 pet_loc_free(scop->loc);
657 scop->loc = loc;
659 return scop;
660 error:
661 pet_loc_free(loc);
662 pet_scop_free(scop);
663 return NULL;
666 /* Does "implication" appear in the list of implications of "scop"?
668 static int is_known_implication(struct pet_scop *scop,
669 struct pet_implication *implication)
671 int i;
673 for (i = 0; i < scop->n_implication; ++i) {
674 struct pet_implication *pi = scop->implications[i];
675 int equal;
677 if (pi->satisfied != implication->satisfied)
678 continue;
679 equal = isl_map_is_equal(pi->extension, implication->extension);
680 if (equal < 0)
681 return -1;
682 if (equal)
683 return 1;
686 return 0;
689 /* Store the concatenation of the implications of "scop1" and "scop2"
690 * in "scop", removing duplicates (i.e., implications in "scop2" that
691 * already appear in "scop1").
693 static struct pet_scop *scop_collect_implications(isl_ctx *ctx,
694 struct pet_scop *scop, struct pet_scop *scop1, struct pet_scop *scop2)
696 int i, j;
698 if (!scop)
699 return NULL;
701 if (scop2->n_implication == 0) {
702 scop->n_implication = scop1->n_implication;
703 scop->implications = scop1->implications;
704 scop1->n_implication = 0;
705 scop1->implications = NULL;
706 return scop;
709 if (scop1->n_implication == 0) {
710 scop->n_implication = scop2->n_implication;
711 scop->implications = scop2->implications;
712 scop2->n_implication = 0;
713 scop2->implications = NULL;
714 return scop;
717 scop->implications = isl_calloc_array(ctx, struct pet_implication *,
718 scop1->n_implication + scop2->n_implication);
719 if (!scop->implications)
720 return pet_scop_free(scop);
722 for (i = 0; i < scop1->n_implication; ++i) {
723 scop->implications[i] = scop1->implications[i];
724 scop1->implications[i] = NULL;
727 scop->n_implication = scop1->n_implication;
728 j = scop1->n_implication;
729 for (i = 0; i < scop2->n_implication; ++i) {
730 int known;
732 known = is_known_implication(scop, scop2->implications[i]);
733 if (known < 0)
734 return pet_scop_free(scop);
735 if (known)
736 continue;
737 scop->implications[j++] = scop2->implications[i];
738 scop2->implications[i] = NULL;
740 scop->n_implication = j;
742 return scop;
745 /* Combine the offset information of "scop1" and "scop2" into "scop".
747 static struct pet_scop *scop_combine_start_end(struct pet_scop *scop,
748 struct pet_scop *scop1, struct pet_scop *scop2)
750 if (scop1->loc != &pet_loc_dummy)
751 scop = pet_scop_update_start_end_from_loc(scop, scop1->loc);
752 if (scop2->loc != &pet_loc_dummy)
753 scop = pet_scop_update_start_end_from_loc(scop, scop2->loc);
754 return scop;
757 /* Create and return an independence that filters out the dependences
758 * in "filter" with local variables "local".
760 static struct pet_independence *new_independence(
761 __isl_take isl_union_map *filter, __isl_take isl_union_set *local)
763 isl_ctx *ctx;
764 struct pet_independence *independence;
766 if (!filter || !local)
767 goto error;
768 ctx = isl_union_map_get_ctx(filter);
769 independence = isl_alloc_type(ctx, struct pet_independence);
770 if (!independence)
771 goto error;
773 independence->filter = filter;
774 independence->local = local;
776 return independence;
777 error:
778 isl_union_map_free(filter);
779 isl_union_set_free(local);
780 return NULL;
783 /* Add an independence that filters out the dependences
784 * in "filter" with local variables "local" to "scop".
786 struct pet_scop *pet_scop_add_independence(struct pet_scop *scop,
787 __isl_take isl_union_map *filter, __isl_take isl_union_set *local)
789 isl_ctx *ctx;
790 struct pet_independence *independence;
791 struct pet_independence **independences;
793 ctx = isl_union_map_get_ctx(filter);
794 independence = new_independence(filter, local);
795 if (!scop || !independence)
796 goto error;
798 independences = isl_realloc_array(ctx, scop->independences,
799 struct pet_independence *,
800 scop->n_independence + 1);
801 if (!independences)
802 goto error;
803 scop->independences = independences;
804 scop->independences[scop->n_independence] = independence;
805 scop->n_independence++;
807 return scop;
808 error:
809 pet_independence_free(independence);
810 pet_scop_free(scop);
811 return NULL;
814 /* Store the concatenation of the independences of "scop1" and "scop2"
815 * in "scop".
817 static struct pet_scop *scop_collect_independences(isl_ctx *ctx,
818 struct pet_scop *scop, struct pet_scop *scop1, struct pet_scop *scop2)
820 int i, off;
822 if (!scop)
823 return NULL;
825 if (scop2->n_independence == 0) {
826 scop->n_independence = scop1->n_independence;
827 scop->independences = scop1->independences;
828 scop1->n_independence = 0;
829 scop1->independences = NULL;
830 return scop;
833 if (scop1->n_independence == 0) {
834 scop->n_independence = scop2->n_independence;
835 scop->independences = scop2->independences;
836 scop2->n_independence = 0;
837 scop2->independences = NULL;
838 return scop;
841 scop->independences = isl_calloc_array(ctx, struct pet_independence *,
842 scop1->n_independence + scop2->n_independence);
843 if (!scop->independences)
844 return pet_scop_free(scop);
846 for (i = 0; i < scop1->n_independence; ++i) {
847 scop->independences[i] = scop1->independences[i];
848 scop1->independences[i] = NULL;
851 off = scop1->n_independence;
852 for (i = 0; i < scop2->n_independence; ++i) {
853 scop->independences[off + i] = scop2->independences[i];
854 scop2->independences[i] = NULL;
856 scop->n_independence = scop1->n_independence + scop2->n_independence;
858 return scop;
861 /* Construct a pet_scop that contains the offset information,
862 * arrays, statements and skip information in "scop1" and "scop2".
864 static struct pet_scop *pet_scop_add(isl_ctx *ctx, struct pet_scop *scop1,
865 struct pet_scop *scop2)
867 int i;
868 isl_space *space;
869 struct pet_scop *scop = NULL;
871 if (!scop1 || !scop2)
872 goto error;
874 if (scop1->n_stmt == 0) {
875 scop2 = scop_combine_skips(scop2, scop1, scop2);
876 pet_scop_free(scop1);
877 return scop2;
880 if (scop2->n_stmt == 0) {
881 scop1 = scop_combine_skips(scop1, scop1, scop2);
882 pet_scop_free(scop2);
883 return scop1;
886 space = isl_set_get_space(scop1->context);
887 scop = scop_alloc(space, scop1->n_stmt + scop2->n_stmt);
888 if (!scop)
889 goto error;
891 scop->arrays = isl_calloc_array(ctx, struct pet_array *,
892 scop1->n_array + scop2->n_array);
893 if (!scop->arrays)
894 goto error;
895 scop->n_array = scop1->n_array + scop2->n_array;
897 for (i = 0; i < scop1->n_stmt; ++i) {
898 scop->stmts[i] = scop1->stmts[i];
899 scop1->stmts[i] = NULL;
902 for (i = 0; i < scop2->n_stmt; ++i) {
903 scop->stmts[scop1->n_stmt + i] = scop2->stmts[i];
904 scop2->stmts[i] = NULL;
907 for (i = 0; i < scop1->n_array; ++i) {
908 scop->arrays[i] = scop1->arrays[i];
909 scop1->arrays[i] = NULL;
912 for (i = 0; i < scop2->n_array; ++i) {
913 scop->arrays[scop1->n_array + i] = scop2->arrays[i];
914 scop2->arrays[i] = NULL;
917 scop = scop_collect_implications(ctx, scop, scop1, scop2);
918 scop = pet_scop_restrict_context(scop, isl_set_copy(scop1->context));
919 scop = pet_scop_restrict_context(scop, isl_set_copy(scop2->context));
920 scop = scop_combine_skips(scop, scop1, scop2);
921 scop = scop_combine_start_end(scop, scop1, scop2);
922 scop = scop_collect_independences(ctx, scop, scop1, scop2);
924 pet_scop_free(scop1);
925 pet_scop_free(scop2);
926 return scop;
927 error:
928 pet_scop_free(scop1);
929 pet_scop_free(scop2);
930 pet_scop_free(scop);
931 return NULL;
934 /* Apply the skip condition "skip" to "scop".
935 * That is, make sure "scop" is not executed when the condition holds.
937 * If "skip" is an affine expression, we add the conditions under
938 * which the expression is zero to the iteration domains.
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_copy(expr->acc.access);
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 = isl_set_copy(stmt->domain);
2450 if (isl_set_is_wrapping(data.domain))
2451 data.domain = isl_map_domain(isl_set_unwrap(data.domain));
2453 if (kill) {
2454 pet_expr *body, *arg;
2456 body = pet_tree_expr_get_expr(stmt->body);
2457 arg = pet_expr_get_arg(body, 0);
2458 data.accesses = expr_collect_access(arg, tag,
2459 data.accesses, data.domain);
2460 pet_expr_free(arg);
2461 pet_expr_free(body);
2462 } else if (pet_tree_foreach_access_expr(stmt->body,
2463 &expr_collect_accesses, &data) < 0)
2464 data.accesses = isl_union_map_free(data.accesses);
2466 isl_set_free(data.domain);
2468 return data.accesses;
2471 /* Is "stmt" an assignment statement?
2473 int pet_stmt_is_assign(struct pet_stmt *stmt)
2475 if (!stmt)
2476 return 0;
2477 return pet_tree_is_assign(stmt->body);
2480 /* Is "stmt" a kill statement?
2482 int pet_stmt_is_kill(struct pet_stmt *stmt)
2484 if (!stmt)
2485 return 0;
2486 return pet_tree_is_kill(stmt->body);
2489 /* Is "stmt" an assume statement?
2491 int pet_stmt_is_assume(struct pet_stmt *stmt)
2493 if (!stmt)
2494 return 0;
2495 return pet_tree_is_assume(stmt->body);
2498 /* Compute a mapping from all arrays (of structs) in scop
2499 * to their innermost arrays.
2501 * In particular, for each array of a primitive type, the result
2502 * contains the identity mapping on that array.
2503 * For each array involving member accesses, the result
2504 * contains a mapping from the elements of any intermediate array of structs
2505 * to all corresponding elements of the innermost nested arrays.
2507 static __isl_give isl_union_map *compute_to_inner(struct pet_scop *scop)
2509 int i;
2510 isl_union_map *to_inner;
2512 to_inner = isl_union_map_empty(isl_set_get_space(scop->context));
2514 for (i = 0; i < scop->n_array; ++i) {
2515 struct pet_array *array = scop->arrays[i];
2516 isl_set *set;
2517 isl_map *map, *gist;
2519 if (array->element_is_record)
2520 continue;
2522 map = isl_set_identity(isl_set_copy(array->extent));
2524 set = isl_map_domain(isl_map_copy(map));
2525 gist = isl_map_copy(map);
2526 gist = isl_map_gist_domain(gist, isl_set_copy(set));
2527 to_inner = isl_union_map_add_map(to_inner, gist);
2529 while (set && isl_set_is_wrapping(set)) {
2530 isl_id *id;
2531 isl_map *wrapped;
2533 id = isl_set_get_tuple_id(set);
2534 wrapped = isl_set_unwrap(set);
2535 wrapped = isl_map_domain_map(wrapped);
2536 wrapped = isl_map_set_tuple_id(wrapped, isl_dim_in, id);
2537 map = isl_map_apply_domain(map, wrapped);
2538 set = isl_map_domain(isl_map_copy(map));
2539 gist = isl_map_copy(map);
2540 gist = isl_map_gist_domain(gist, isl_set_copy(set));
2541 to_inner = isl_union_map_add_map(to_inner, gist);
2544 isl_set_free(set);
2545 isl_map_free(map);
2548 return to_inner;
2551 /* Collect and return all read access relations (if "read" is set)
2552 * and/or all write access relations (if "write" is set) in "scop".
2553 * If "kill" is set, then we only add the arguments of kill operations.
2554 * If "must" is set, then we only add the accesses that are definitely
2555 * performed. Otherwise, we add all potential accesses.
2556 * If "tag" is set, then the access relations are tagged with
2557 * the corresponding reference identifiers.
2558 * For accesses to structures, the returned access relation accesses
2559 * all individual fields in the structures.
2561 static __isl_give isl_union_map *scop_collect_accesses(struct pet_scop *scop,
2562 int read, int write, int kill, int must, int tag)
2564 int i;
2565 isl_union_map *accesses;
2566 isl_union_set *arrays;
2567 isl_union_map *to_inner;
2569 if (!scop)
2570 return NULL;
2572 accesses = isl_union_map_empty(isl_set_get_space(scop->context));
2574 for (i = 0; i < scop->n_stmt; ++i) {
2575 struct pet_stmt *stmt = scop->stmts[i];
2576 isl_union_map *accesses_i;
2577 isl_space *space;
2579 if (kill && !pet_stmt_is_kill(stmt))
2580 continue;
2582 space = isl_set_get_space(scop->context);
2583 accesses_i = stmt_collect_accesses(stmt, read, write, kill,
2584 must, tag, space);
2585 accesses = isl_union_map_union(accesses, accesses_i);
2588 arrays = isl_union_set_empty(isl_union_map_get_space(accesses));
2589 for (i = 0; i < scop->n_array; ++i) {
2590 isl_set *extent = isl_set_copy(scop->arrays[i]->extent);
2591 arrays = isl_union_set_add_set(arrays, extent);
2593 accesses = isl_union_map_intersect_range(accesses, arrays);
2595 to_inner = compute_to_inner(scop);
2596 accesses = isl_union_map_apply_range(accesses, to_inner);
2598 return accesses;
2601 /* Collect all potential read access relations.
2603 __isl_give isl_union_map *pet_scop_collect_may_reads(struct pet_scop *scop)
2605 return scop_collect_accesses(scop, 1, 0, 0, 0, 0);
2608 /* Collect all potential write access relations.
2610 __isl_give isl_union_map *pet_scop_collect_may_writes(struct pet_scop *scop)
2612 return scop_collect_accesses(scop, 0, 1, 0, 0, 0);
2615 /* Collect all definite write access relations.
2617 __isl_give isl_union_map *pet_scop_collect_must_writes(struct pet_scop *scop)
2619 return scop_collect_accesses(scop, 0, 1, 0, 1, 0);
2622 /* Collect all definite kill access relations.
2624 __isl_give isl_union_map *pet_scop_collect_must_kills(struct pet_scop *scop)
2626 return scop_collect_accesses(scop, 0, 0, 1, 1, 0);
2629 /* Collect all tagged potential read access relations.
2631 __isl_give isl_union_map *pet_scop_collect_tagged_may_reads(
2632 struct pet_scop *scop)
2634 return scop_collect_accesses(scop, 1, 0, 0, 0, 1);
2637 /* Collect all tagged potential write access relations.
2639 __isl_give isl_union_map *pet_scop_collect_tagged_may_writes(
2640 struct pet_scop *scop)
2642 return scop_collect_accesses(scop, 0, 1, 0, 0, 1);
2645 /* Collect all tagged definite write access relations.
2647 __isl_give isl_union_map *pet_scop_collect_tagged_must_writes(
2648 struct pet_scop *scop)
2650 return scop_collect_accesses(scop, 0, 1, 0, 1, 1);
2653 /* Collect all tagged definite kill access relations.
2655 __isl_give isl_union_map *pet_scop_collect_tagged_must_kills(
2656 struct pet_scop *scop)
2658 return scop_collect_accesses(scop, 0, 0, 1, 1, 1);
2661 /* Collect and return the union of iteration domains in "scop".
2663 __isl_give isl_union_set *pet_scop_collect_domains(struct pet_scop *scop)
2665 int i;
2666 isl_set *domain_i;
2667 isl_union_set *domain;
2669 if (!scop)
2670 return NULL;
2672 domain = isl_union_set_empty(isl_set_get_space(scop->context));
2674 for (i = 0; i < scop->n_stmt; ++i) {
2675 domain_i = isl_set_copy(scop->stmts[i]->domain);
2676 domain = isl_union_set_add_set(domain, domain_i);
2679 return domain;
2682 /* Collect and return the schedules of the statements in "scop".
2683 * The range is normalized to the maximal number of scheduling
2684 * dimensions.
2686 __isl_give isl_union_map *pet_scop_collect_schedule(struct pet_scop *scop)
2688 int i, j;
2689 isl_map *schedule_i;
2690 isl_union_map *schedule;
2691 int depth, max_depth = 0;
2693 if (!scop)
2694 return NULL;
2696 schedule = isl_union_map_empty(isl_set_get_space(scop->context));
2698 for (i = 0; i < scop->n_stmt; ++i) {
2699 depth = isl_map_dim(scop->stmts[i]->schedule, isl_dim_out);
2700 if (depth > max_depth)
2701 max_depth = depth;
2704 for (i = 0; i < scop->n_stmt; ++i) {
2705 schedule_i = isl_map_copy(scop->stmts[i]->schedule);
2706 depth = isl_map_dim(schedule_i, isl_dim_out);
2707 schedule_i = isl_map_add_dims(schedule_i, isl_dim_out,
2708 max_depth - depth);
2709 for (j = depth; j < max_depth; ++j)
2710 schedule_i = isl_map_fix_si(schedule_i,
2711 isl_dim_out, j, 0);
2712 schedule = isl_union_map_add_map(schedule, schedule_i);
2715 return schedule;
2718 /* Add a reference identifier to all access expressions in "stmt".
2719 * "n_ref" points to an integer that contains the sequence number
2720 * of the next reference.
2722 static struct pet_stmt *stmt_add_ref_ids(struct pet_stmt *stmt, int *n_ref)
2724 int i;
2726 if (!stmt)
2727 return NULL;
2729 for (i = 0; i < stmt->n_arg; ++i) {
2730 stmt->args[i] = pet_expr_add_ref_ids(stmt->args[i], n_ref);
2731 if (!stmt->args[i])
2732 return pet_stmt_free(stmt);
2735 stmt->body = pet_tree_add_ref_ids(stmt->body, n_ref);
2736 if (!stmt->body)
2737 return pet_stmt_free(stmt);
2739 return stmt;
2742 /* Add a reference identifier to all access expressions in "scop".
2744 struct pet_scop *pet_scop_add_ref_ids(struct pet_scop *scop)
2746 int i;
2747 int n_ref;
2749 if (!scop)
2750 return NULL;
2752 n_ref = 0;
2753 for (i = 0; i < scop->n_stmt; ++i) {
2754 scop->stmts[i] = stmt_add_ref_ids(scop->stmts[i], &n_ref);
2755 if (!scop->stmts[i])
2756 return pet_scop_free(scop);
2759 return scop;
2762 /* Reset the user pointer on all parameter ids in "array".
2764 static struct pet_array *array_anonymize(struct pet_array *array)
2766 if (!array)
2767 return NULL;
2769 array->context = isl_set_reset_user(array->context);
2770 array->extent = isl_set_reset_user(array->extent);
2771 if (!array->context || !array->extent)
2772 return pet_array_free(array);
2774 return array;
2777 /* Reset the user pointer on all parameter and tuple ids in "stmt".
2779 static struct pet_stmt *stmt_anonymize(struct pet_stmt *stmt)
2781 int i;
2782 isl_space *space;
2783 isl_set *domain;
2785 if (!stmt)
2786 return NULL;
2788 stmt->domain = isl_set_reset_user(stmt->domain);
2789 stmt->schedule = isl_map_reset_user(stmt->schedule);
2790 if (!stmt->domain || !stmt->schedule)
2791 return pet_stmt_free(stmt);
2793 for (i = 0; i < stmt->n_arg; ++i) {
2794 stmt->args[i] = pet_expr_anonymize(stmt->args[i]);
2795 if (!stmt->args[i])
2796 return pet_stmt_free(stmt);
2799 stmt->body = pet_tree_anonymize(stmt->body);
2800 if (!stmt->body)
2801 return pet_stmt_free(stmt);
2803 return stmt;
2806 /* Reset the user pointer on the tuple ids and all parameter ids
2807 * in "implication".
2809 static struct pet_implication *implication_anonymize(
2810 struct pet_implication *implication)
2812 if (!implication)
2813 return NULL;
2815 implication->extension = isl_map_reset_user(implication->extension);
2816 if (!implication->extension)
2817 return pet_implication_free(implication);
2819 return implication;
2822 /* Reset the user pointer on the tuple ids and all parameter ids
2823 * in "independence".
2825 static struct pet_independence *independence_anonymize(
2826 struct pet_independence *independence)
2828 if (!independence)
2829 return NULL;
2831 independence->filter = isl_union_map_reset_user(independence->filter);
2832 independence->local = isl_union_set_reset_user(independence->local);
2833 if (!independence->filter || !independence->local)
2834 return pet_independence_free(independence);
2836 return independence;
2839 /* Reset the user pointer on all parameter and tuple ids in "scop".
2841 struct pet_scop *pet_scop_anonymize(struct pet_scop *scop)
2843 int i;
2845 if (!scop)
2846 return NULL;
2848 scop->context = isl_set_reset_user(scop->context);
2849 scop->context_value = isl_set_reset_user(scop->context_value);
2850 if (!scop->context || !scop->context_value)
2851 return pet_scop_free(scop);
2853 for (i = 0; i < scop->n_array; ++i) {
2854 scop->arrays[i] = array_anonymize(scop->arrays[i]);
2855 if (!scop->arrays[i])
2856 return pet_scop_free(scop);
2859 for (i = 0; i < scop->n_stmt; ++i) {
2860 scop->stmts[i] = stmt_anonymize(scop->stmts[i]);
2861 if (!scop->stmts[i])
2862 return pet_scop_free(scop);
2865 for (i = 0; i < scop->n_implication; ++i) {
2866 scop->implications[i] =
2867 implication_anonymize(scop->implications[i]);
2868 if (!scop->implications[i])
2869 return pet_scop_free(scop);
2872 for (i = 0; i < scop->n_independence; ++i) {
2873 scop->independences[i] =
2874 independence_anonymize(scop->independences[i]);
2875 if (!scop->independences[i])
2876 return pet_scop_free(scop);
2879 return scop;
2882 /* Compute the gist of the iteration domain and all access relations
2883 * of "stmt" based on the constraints on the parameters specified by "context"
2884 * and the constraints on the values of nested accesses specified
2885 * by "value_bounds".
2887 static struct pet_stmt *stmt_gist(struct pet_stmt *stmt,
2888 __isl_keep isl_set *context, __isl_keep isl_union_map *value_bounds)
2890 int i;
2891 isl_set *domain;
2893 if (!stmt)
2894 return NULL;
2896 domain = isl_set_copy(stmt->domain);
2897 if (stmt->n_arg > 0)
2898 domain = isl_map_domain(isl_set_unwrap(domain));
2900 domain = isl_set_intersect_params(domain, isl_set_copy(context));
2902 for (i = 0; i < stmt->n_arg; ++i) {
2903 stmt->args[i] = pet_expr_gist(stmt->args[i],
2904 domain, value_bounds);
2905 if (!stmt->args[i])
2906 goto error;
2909 stmt->body = pet_tree_gist(stmt->body, domain, value_bounds);
2910 if (!stmt->body)
2911 goto error;
2913 isl_set_free(domain);
2915 domain = isl_set_universe(pet_stmt_get_space(stmt));
2916 domain = isl_set_intersect_params(domain, isl_set_copy(context));
2917 if (stmt->n_arg > 0)
2918 domain = pet_value_bounds_apply(domain, stmt->n_arg, stmt->args,
2919 value_bounds);
2920 stmt->domain = isl_set_gist(stmt->domain, domain);
2921 if (!stmt->domain)
2922 return pet_stmt_free(stmt);
2924 return stmt;
2925 error:
2926 isl_set_free(domain);
2927 return pet_stmt_free(stmt);
2930 /* Compute the gist of the extent of the array
2931 * based on the constraints on the parameters specified by "context".
2933 static struct pet_array *array_gist(struct pet_array *array,
2934 __isl_keep isl_set *context)
2936 if (!array)
2937 return NULL;
2939 array->extent = isl_set_gist_params(array->extent,
2940 isl_set_copy(context));
2941 if (!array->extent)
2942 return pet_array_free(array);
2944 return array;
2947 /* Compute the gist of all sets and relations in "scop"
2948 * based on the constraints on the parameters specified by "scop->context"
2949 * and the constraints on the values of nested accesses specified
2950 * by "value_bounds".
2952 struct pet_scop *pet_scop_gist(struct pet_scop *scop,
2953 __isl_keep isl_union_map *value_bounds)
2955 int i;
2957 if (!scop)
2958 return NULL;
2960 scop->context = isl_set_coalesce(scop->context);
2961 if (!scop->context)
2962 return pet_scop_free(scop);
2964 for (i = 0; i < scop->n_array; ++i) {
2965 scop->arrays[i] = array_gist(scop->arrays[i], scop->context);
2966 if (!scop->arrays[i])
2967 return pet_scop_free(scop);
2970 for (i = 0; i < scop->n_stmt; ++i) {
2971 scop->stmts[i] = stmt_gist(scop->stmts[i], scop->context,
2972 value_bounds);
2973 if (!scop->stmts[i])
2974 return pet_scop_free(scop);
2977 return scop;
2980 /* Intersect the context of "scop" with "context".
2981 * To ensure that we don't introduce any unnamed parameters in
2982 * the context of "scop", we first remove the unnamed parameters
2983 * from "context".
2985 struct pet_scop *pet_scop_restrict_context(struct pet_scop *scop,
2986 __isl_take isl_set *context)
2988 if (!scop)
2989 goto error;
2991 context = pet_nested_remove_from_set(context);
2992 scop->context = isl_set_intersect(scop->context, context);
2993 if (!scop->context)
2994 return pet_scop_free(scop);
2996 return scop;
2997 error:
2998 isl_set_free(context);
2999 return pet_scop_free(scop);
3002 /* Drop the current context of "scop". That is, replace the context
3003 * by a universal set.
3005 struct pet_scop *pet_scop_reset_context(struct pet_scop *scop)
3007 isl_space *space;
3009 if (!scop)
3010 return NULL;
3012 space = isl_set_get_space(scop->context);
3013 isl_set_free(scop->context);
3014 scop->context = isl_set_universe(space);
3015 if (!scop->context)
3016 return pet_scop_free(scop);
3018 return scop;
3021 /* Append "array" to the arrays of "scop".
3023 struct pet_scop *pet_scop_add_array(struct pet_scop *scop,
3024 struct pet_array *array)
3026 isl_ctx *ctx;
3027 struct pet_array **arrays;
3029 if (!array || !scop)
3030 goto error;
3032 ctx = isl_set_get_ctx(scop->context);
3033 arrays = isl_realloc_array(ctx, scop->arrays, struct pet_array *,
3034 scop->n_array + 1);
3035 if (!arrays)
3036 goto error;
3037 scop->arrays = arrays;
3038 scop->arrays[scop->n_array] = array;
3039 scop->n_array++;
3041 return scop;
3042 error:
3043 pet_array_free(array);
3044 return pet_scop_free(scop);
3047 /* Create an index expression for an access to a virtual array
3048 * representing the result of a condition.
3049 * Unlike other accessed data, the id of the array is NULL as
3050 * there is no ValueDecl in the program corresponding to the virtual
3051 * array.
3052 * The index expression is created as an identity mapping on "space".
3053 * That is, the dimension of the array is the same as that of "space".
3055 __isl_give isl_multi_pw_aff *pet_create_test_index(__isl_take isl_space *space,
3056 int test_nr)
3058 isl_id *id;
3059 char name[50];
3061 snprintf(name, sizeof(name), "__pet_test_%d", test_nr);
3062 id = isl_id_alloc(isl_space_get_ctx(space), name, NULL);
3063 space = isl_space_map_from_set(space);
3064 space = isl_space_set_tuple_id(space, isl_dim_out, id);
3065 return isl_multi_pw_aff_identity(space);
3068 /* Add an array with the given extent to the list
3069 * of arrays in "scop" and return the extended pet_scop.
3070 * Specifically, the extent is determined by the image of "domain"
3071 * under "index".
3072 * "int_size" is the number of bytes needed to represent values of type "int".
3073 * The array is marked as attaining values 0 and 1 only and
3074 * as each element being assigned at most once.
3076 struct pet_scop *pet_scop_add_boolean_array(struct pet_scop *scop,
3077 __isl_take isl_set *domain, __isl_take isl_multi_pw_aff *index,
3078 int int_size)
3080 isl_ctx *ctx;
3081 isl_space *space;
3082 struct pet_array *array;
3083 isl_map *access;
3085 if (!scop || !domain || !index)
3086 goto error;
3088 ctx = isl_multi_pw_aff_get_ctx(index);
3089 array = isl_calloc_type(ctx, struct pet_array);
3090 if (!array)
3091 goto error;
3093 access = isl_map_from_multi_pw_aff(index);
3094 access = isl_map_intersect_domain(access, domain);
3095 array->extent = isl_map_range(access);
3096 space = isl_space_params_alloc(ctx, 0);
3097 array->context = isl_set_universe(space);
3098 space = isl_space_set_alloc(ctx, 0, 1);
3099 array->value_bounds = isl_set_universe(space);
3100 array->value_bounds = isl_set_lower_bound_si(array->value_bounds,
3101 isl_dim_set, 0, 0);
3102 array->value_bounds = isl_set_upper_bound_si(array->value_bounds,
3103 isl_dim_set, 0, 1);
3104 array->element_type = strdup("int");
3105 array->element_size = int_size;
3106 array->uniquely_defined = 1;
3108 if (!array->extent || !array->context)
3109 array = pet_array_free(array);
3111 scop = pet_scop_add_array(scop, array);
3113 return scop;
3114 error:
3115 isl_set_free(domain);
3116 isl_multi_pw_aff_free(index);
3117 return pet_scop_free(scop);
3120 /* Create and return an implication on filter values equal to "satisfied"
3121 * with extension "map".
3123 static struct pet_implication *new_implication(__isl_take isl_map *map,
3124 int satisfied)
3126 isl_ctx *ctx;
3127 struct pet_implication *implication;
3129 if (!map)
3130 return NULL;
3131 ctx = isl_map_get_ctx(map);
3132 implication = isl_alloc_type(ctx, struct pet_implication);
3133 if (!implication)
3134 goto error;
3136 implication->extension = map;
3137 implication->satisfied = satisfied;
3139 return implication;
3140 error:
3141 isl_map_free(map);
3142 return NULL;
3145 /* Add an implication on filter values equal to "satisfied"
3146 * with extension "map" to "scop".
3148 struct pet_scop *pet_scop_add_implication(struct pet_scop *scop,
3149 __isl_take isl_map *map, int satisfied)
3151 isl_ctx *ctx;
3152 struct pet_implication *implication;
3153 struct pet_implication **implications;
3155 implication = new_implication(map, satisfied);
3156 if (!scop || !implication)
3157 goto error;
3159 ctx = isl_set_get_ctx(scop->context);
3160 implications = isl_realloc_array(ctx, scop->implications,
3161 struct pet_implication *,
3162 scop->n_implication + 1);
3163 if (!implications)
3164 goto error;
3165 scop->implications = implications;
3166 scop->implications[scop->n_implication] = implication;
3167 scop->n_implication++;
3169 return scop;
3170 error:
3171 pet_implication_free(implication);
3172 return pet_scop_free(scop);
3175 /* Create and return a function that maps the iteration domains
3176 * of the statements in "scop" onto their outer "n" dimensions.
3177 * "space" is the parameters space of the created function.
3179 static __isl_give isl_union_pw_multi_aff *outer_projection(
3180 struct pet_scop *scop, __isl_take isl_space *space, int n)
3182 int i;
3183 isl_union_pw_multi_aff *res;
3185 res = isl_union_pw_multi_aff_empty(space);
3187 if (!scop)
3188 return isl_union_pw_multi_aff_free(res);
3190 for (i = 0; i < scop->n_stmt; ++i) {
3191 struct pet_stmt *stmt = scop->stmts[i];
3192 isl_space *space;
3193 isl_multi_aff *ma;
3194 isl_pw_multi_aff *pma;
3196 space = pet_stmt_get_space(stmt);
3197 ma = pet_prefix_projection(space, n);
3198 pma = isl_pw_multi_aff_from_multi_aff(ma);
3199 res = isl_union_pw_multi_aff_add_pw_multi_aff(res, pma);
3202 return res;
3205 /* Add an independence to "scop" for the inner iterator of "domain"
3206 * with local variables "local", where "domain" represents the outer
3207 * loop iterators of all statements in "scop".
3208 * If "sign" is positive, then the inner iterator increases.
3209 * Otherwise it decreases.
3211 * The independence is supposed to filter out any dependence of
3212 * an iteration of domain on a previous iteration along the inner dimension.
3213 * We therefore create a mapping from an iteration to later iterations and
3214 * then plug in the projection of the iterations domains of "scop"
3215 * onto the outer loop iterators.
3217 struct pet_scop *pet_scop_set_independent(struct pet_scop *scop,
3218 __isl_keep isl_set *domain, __isl_take isl_union_set *local, int sign)
3220 int i, dim;
3221 isl_space *space;
3222 isl_map *map;
3223 isl_union_map *independence;
3224 isl_union_pw_multi_aff *proj;
3226 if (!scop || !domain || !local)
3227 goto error;
3229 dim = isl_set_dim(domain, isl_dim_set);
3230 space = isl_space_map_from_set(isl_set_get_space(domain));
3231 map = isl_map_universe(space);
3232 for (i = 0; i + 1 < dim; ++i)
3233 map = isl_map_equate(map, isl_dim_in, i, isl_dim_out, i);
3234 if (sign > 0)
3235 map = isl_map_order_lt(map,
3236 isl_dim_in, dim - 1, isl_dim_out, dim - 1);
3237 else
3238 map = isl_map_order_gt(map,
3239 isl_dim_in, dim - 1, isl_dim_out, dim - 1);
3241 independence = isl_union_map_from_map(map);
3242 space = isl_space_params(isl_set_get_space(domain));
3243 proj = outer_projection(scop, space, dim);
3244 independence = isl_union_map_preimage_domain_union_pw_multi_aff(
3245 independence, isl_union_pw_multi_aff_copy(proj));
3246 independence = isl_union_map_preimage_range_union_pw_multi_aff(
3247 independence, proj);
3249 scop = pet_scop_add_independence(scop, independence, local);
3251 return scop;
3252 error:
3253 isl_union_set_free(local);
3254 return pet_scop_free(scop);
3257 /* Given an access expression, check if it is data dependent.
3258 * If so, set *found and abort the search.
3260 static int is_data_dependent(__isl_keep pet_expr *expr, void *user)
3262 int *found = user;
3264 if (pet_expr_get_n_arg(expr) > 0) {
3265 *found = 1;
3266 return -1;
3269 return 0;
3272 /* Does "scop" contain any data dependent accesses?
3274 * Check the body of each statement for such accesses.
3276 int pet_scop_has_data_dependent_accesses(struct pet_scop *scop)
3278 int i;
3279 int found = 0;
3281 if (!scop)
3282 return -1;
3284 for (i = 0; i < scop->n_stmt; ++i) {
3285 int r = pet_tree_foreach_access_expr(scop->stmts[i]->body,
3286 &is_data_dependent, &found);
3287 if (r < 0 && !found)
3288 return -1;
3289 if (found)
3290 return found;
3293 return found;
3296 /* Does "scop" contain and data dependent conditions?
3298 int pet_scop_has_data_dependent_conditions(struct pet_scop *scop)
3300 int i;
3302 if (!scop)
3303 return -1;
3305 for (i = 0; i < scop->n_stmt; ++i)
3306 if (scop->stmts[i]->n_arg > 0)
3307 return 1;
3309 return 0;
3312 /* Keep track of the "input" file inside the (extended) "scop".
3314 struct pet_scop *pet_scop_set_input_file(struct pet_scop *scop, FILE *input)
3316 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
3318 if (!scop)
3319 return NULL;
3321 ext->input = input;
3323 return scop;
3326 /* Print the original code corresponding to "scop" to printer "p".
3328 * pet_scop_print_original can only be called from
3329 * a pet_transform_C_source callback. This means that the input
3330 * file is stored in the extended scop and that the printer prints
3331 * to a file.
3333 __isl_give isl_printer *pet_scop_print_original(struct pet_scop *scop,
3334 __isl_take isl_printer *p)
3336 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
3337 FILE *output;
3338 unsigned start, end;
3340 if (!scop || !p)
3341 return isl_printer_free(p);
3343 if (!ext->input)
3344 isl_die(isl_printer_get_ctx(p), isl_error_invalid,
3345 "no input file stored in scop",
3346 return isl_printer_free(p));
3348 output = isl_printer_get_file(p);
3349 if (!output)
3350 return isl_printer_free(p);
3352 start = pet_loc_get_start(scop->loc);
3353 end = pet_loc_get_end(scop->loc);
3354 if (copy(ext->input, output, start, end) < 0)
3355 return isl_printer_free(p);
3357 return p;