emit.c: emit_expr: extract out emit_access_expr
[pet.git] / scop.c
blob2a9752c3f8a801189725bf78a715fa444569559c
1 /*
2 * Copyright 2011 Leiden University. All rights reserved.
3 * Copyright 2012-2014 Ecole Normale Superieure. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY LEIDEN UNIVERSITY ''AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LEIDEN UNIVERSITY OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * The views and conclusions contained in the software and documentation
30 * are those of the authors and should not be interpreted as
31 * representing official policies, either expressed or implied, of
32 * Leiden University.
33 */
35 #include <string.h>
36 #include <isl/constraint.h>
37 #include <isl/union_set.h>
39 #include "aff.h"
40 #include "expr.h"
41 #include "filter.h"
42 #include "loc.h"
43 #include "nest.h"
44 #include "scop.h"
45 #include "tree.h"
46 #include "print.h"
47 #include "value_bounds.h"
49 /* pet_scop with extra information that is used during parsing and printing.
51 * In particular, we keep track of conditions under which we want
52 * to skip the rest of the current loop iteration (skip[pet_skip_now])
53 * and of conditions under which we want to skip subsequent
54 * loop iterations (skip[pet_skip_later]).
56 * The conditions are represented as index expressions defined
57 * over the outer loop iterators. The index expression is either
58 * a boolean affine expression or an access to a variable, which
59 * is assumed to attain values zero and one. The condition holds
60 * if the variable has value one or if the affine expression
61 * has value one (typically for only part of the domain).
63 * A missing condition (skip[type] == NULL) means that we don't want
64 * to skip anything.
66 * Additionally, we keep track of the original input file
67 * inside pet_transform_C_source.
69 struct pet_scop_ext {
70 struct pet_scop scop;
72 isl_multi_pw_aff *skip[2];
73 FILE *input;
76 /* Construct a pet_stmt with given domain and statement number from a pet_tree.
77 * The input domain is anonymous and is the same as the domains
78 * of the access expressions inside "tree".
79 * These domains are modified to include the name of the statement.
80 * This name is given by tree->label if it is non-NULL.
81 * Otherwise, the name is constructed as S_<id>.
83 struct pet_stmt *pet_stmt_from_pet_tree(__isl_take isl_set *domain,
84 int id, __isl_take pet_tree *tree)
86 struct pet_stmt *stmt;
87 isl_ctx *ctx;
88 isl_id *label;
89 isl_space *space;
90 isl_map *sched;
91 isl_multi_aff *ma;
92 isl_multi_pw_aff *add_name;
93 char name[50];
95 if (!domain || !tree)
96 goto error;
98 ctx = pet_tree_get_ctx(tree);
99 stmt = isl_calloc_type(ctx, struct pet_stmt);
100 if (!stmt)
101 goto error;
103 if (tree->label) {
104 label = isl_id_copy(tree->label);
105 } else {
106 snprintf(name, sizeof(name), "S_%d", id);
107 label = isl_id_alloc(ctx, name, NULL);
109 domain = isl_set_set_tuple_id(domain, label);
110 space = isl_set_get_space(domain);
111 space = pet_nested_remove_from_space(space);
112 sched = isl_map_universe(isl_space_from_domain(isl_space_copy(space)));
113 ma = pet_prefix_projection(space, isl_space_dim(space, isl_dim_set));
115 add_name = isl_multi_pw_aff_from_multi_aff(ma);
116 tree = pet_tree_update_domain(tree, add_name);
118 stmt->loc = pet_tree_get_loc(tree);
119 stmt->domain = domain;
120 stmt->schedule = sched;
121 stmt->body = tree;
123 if (!stmt->domain || !stmt->schedule || !stmt->body)
124 return pet_stmt_free(stmt);
126 return stmt;
127 error:
128 isl_set_free(domain);
129 pet_tree_free(tree);
130 return NULL;
133 void *pet_stmt_free(struct pet_stmt *stmt)
135 int i;
137 if (!stmt)
138 return NULL;
140 pet_loc_free(stmt->loc);
141 isl_set_free(stmt->domain);
142 isl_map_free(stmt->schedule);
143 pet_tree_free(stmt->body);
145 for (i = 0; i < stmt->n_arg; ++i)
146 pet_expr_free(stmt->args[i]);
147 free(stmt->args);
149 free(stmt);
150 return NULL;
153 /* Return the iteration space of "stmt".
155 * If the statement has arguments, then stmt->domain is a wrapped map
156 * mapping the iteration domain to the values of the arguments
157 * for which this statement is executed.
158 * In this case, we need to extract the domain space of this wrapped map.
160 __isl_give isl_space *pet_stmt_get_space(struct pet_stmt *stmt)
162 isl_space *space;
164 if (!stmt)
165 return NULL;
167 space = isl_set_get_space(stmt->domain);
168 if (isl_space_is_wrapping(space))
169 space = isl_space_domain(isl_space_unwrap(space));
171 return space;
174 static void stmt_dump(struct pet_stmt *stmt, int indent)
176 int i;
178 if (!stmt)
179 return;
181 fprintf(stderr, "%*s%d\n", indent, "", pet_loc_get_line(stmt->loc));
182 fprintf(stderr, "%*s", indent, "");
183 isl_set_dump(stmt->domain);
184 fprintf(stderr, "%*s", indent, "");
185 isl_map_dump(stmt->schedule);
186 pet_tree_dump_with_indent(stmt->body, indent);
187 for (i = 0; i < stmt->n_arg; ++i)
188 pet_expr_dump_with_indent(stmt->args[i], indent + 2);
191 void pet_stmt_dump(struct pet_stmt *stmt)
193 stmt_dump(stmt, 0);
196 /* Allocate a new pet_type with the given "name" and "definition".
198 struct pet_type *pet_type_alloc(isl_ctx *ctx, const char *name,
199 const char *definition)
201 struct pet_type *type;
203 type = isl_alloc_type(ctx, struct pet_type);
204 if (!type)
205 return NULL;
207 type->name = strdup(name);
208 type->definition = strdup(definition);
210 if (!type->name || !type->definition)
211 return pet_type_free(type);
213 return type;
216 /* Free "type" and return NULL.
218 struct pet_type *pet_type_free(struct pet_type *type)
220 if (!type)
221 return NULL;
223 free(type->name);
224 free(type->definition);
226 free(type);
227 return NULL;
230 struct pet_array *pet_array_free(struct pet_array *array)
232 if (!array)
233 return NULL;
235 isl_set_free(array->context);
236 isl_set_free(array->extent);
237 isl_set_free(array->value_bounds);
238 free(array->element_type);
240 free(array);
241 return NULL;
244 void pet_array_dump(struct pet_array *array)
246 if (!array)
247 return;
249 isl_set_dump(array->context);
250 isl_set_dump(array->extent);
251 isl_set_dump(array->value_bounds);
252 fprintf(stderr, "%s%s%s\n", array->element_type,
253 array->element_is_record ? " element-is-record" : "",
254 array->live_out ? " live-out" : "");
257 /* Alloc a pet_scop structure, with extra room for information that
258 * is only used during parsing.
260 struct pet_scop *pet_scop_alloc(isl_ctx *ctx)
262 return &isl_calloc_type(ctx, struct pet_scop_ext)->scop;
265 /* Construct a pet_scop in the given space and with room for n statements.
267 * The context is initialized as a universe set in "space".
269 * Since no information on the location is known at this point,
270 * scop->loc is initialized with pet_loc_dummy.
272 static struct pet_scop *scop_alloc(__isl_take isl_space *space, int n)
274 isl_ctx *ctx;
275 struct pet_scop *scop;
277 if (!space)
278 return NULL;
280 ctx = isl_space_get_ctx(space);
281 scop = pet_scop_alloc(ctx);
282 if (!scop)
283 return NULL;
285 scop->context = isl_set_universe(isl_space_copy(space));
286 scop->context_value = isl_set_universe(isl_space_params(space));
287 scop->stmts = isl_calloc_array(ctx, struct pet_stmt *, n);
288 if (!scop->context || !scop->stmts)
289 return pet_scop_free(scop);
291 scop->loc = &pet_loc_dummy;
292 scop->n_stmt = n;
294 return scop;
297 /* Construct a pet_scop in the given space containing 0 statements.
299 struct pet_scop *pet_scop_empty(__isl_take isl_space *space)
301 return scop_alloc(space, 0);
304 /* Given either an iteration domain or a wrapped map with
305 * the iteration domain in the domain and some arguments
306 * in the range, return the iteration domain.
307 * That is, drop the arguments if there are any.
309 static __isl_give isl_set *drop_arguments(__isl_take isl_set *domain)
311 if (isl_set_is_wrapping(domain))
312 domain = isl_map_domain(isl_set_unwrap(domain));
313 return domain;
316 /* Update "context" with the constraints imposed on the outer iteration
317 * domain by access expression "expr".
318 * "context" lives in an anonymous space, while the domain of the access
319 * relation of "expr" refers to a particular statement.
320 * This reference therefore needs to be stripped off.
322 static __isl_give isl_set *access_extract_context(__isl_keep pet_expr *expr,
323 __isl_take isl_set *context)
325 isl_multi_pw_aff *mpa;
326 isl_set *domain;
328 mpa = pet_expr_access_get_index(expr);
329 domain = drop_arguments(isl_multi_pw_aff_domain(mpa));
330 domain = isl_set_reset_tuple_id(domain);
331 context = isl_set_intersect(context, domain);
332 return context;
335 /* Update "context" with the constraints imposed on the outer iteration
336 * domain by "expr".
338 * "context" lives in an anonymous space, while the domains of
339 * the access relations in "expr" refer to a particular statement.
340 * This reference therefore needs to be stripped off.
342 * If "expr" represents a conditional operator, then a parameter or outer
343 * iterator value needs to be valid for the condition and
344 * for at least one of the remaining two arguments.
345 * If the condition is an affine expression, then we can be a bit more specific.
346 * The value then has to be valid for the second argument for
347 * non-zero accesses and valid for the third argument for zero accesses.
349 * If "expr" represents a kill statement, then its argument is the entire
350 * extent of the array being killed. Do not update "context" based
351 * on this argument as that would impose constraints that ensure that
352 * the array is non-empty.
354 static __isl_give isl_set *expr_extract_context(__isl_keep pet_expr *expr,
355 __isl_take isl_set *context)
357 int i;
359 if (expr->type == pet_expr_op && expr->op == pet_op_kill)
360 return context;
362 if (expr->type == pet_expr_op && expr->op == pet_op_cond) {
363 int is_aff;
364 isl_set *context1, *context2;
366 is_aff = pet_expr_is_affine(expr->args[0]);
367 if (is_aff < 0)
368 goto error;
370 context = expr_extract_context(expr->args[0], context);
371 context1 = expr_extract_context(expr->args[1],
372 isl_set_copy(context));
373 context2 = expr_extract_context(expr->args[2], context);
375 if (is_aff) {
376 isl_multi_pw_aff *mpa;
377 isl_pw_aff *pa;
378 isl_set *zero_set;
380 mpa = pet_expr_access_get_index(expr->args[0]);
381 pa = isl_multi_pw_aff_get_pw_aff(mpa, 0);
382 isl_multi_pw_aff_free(mpa);
383 zero_set = drop_arguments(isl_pw_aff_zero_set(pa));
384 zero_set = isl_set_reset_tuple_id(zero_set);
385 context1 = isl_set_subtract(context1,
386 isl_set_copy(zero_set));
387 context2 = isl_set_intersect(context2, zero_set);
390 context = isl_set_union(context1, context2);
391 context = isl_set_coalesce(context);
393 return context;
396 for (i = 0; i < expr->n_arg; ++i)
397 context = expr_extract_context(expr->args[i], context);
399 if (expr->type == pet_expr_access)
400 context = access_extract_context(expr, context);
402 return context;
403 error:
404 isl_set_free(context);
405 return NULL;
408 /* Is "stmt" an assume statement with an affine assumption?
410 int pet_stmt_is_affine_assume(struct pet_stmt *stmt)
412 if (!stmt)
413 return 0;
414 return pet_tree_is_affine_assume(stmt->body);
417 /* Given an assume statement "stmt" with an access argument,
418 * return the index expression of the argument.
420 __isl_give isl_multi_pw_aff *pet_stmt_assume_get_index(struct pet_stmt *stmt)
422 if (!stmt)
423 return NULL;
424 return pet_tree_assume_get_index(stmt->body);
427 /* Update "context" with the constraints imposed on the outer iteration
428 * domain by "stmt".
430 * If the statement is an assume statement with an affine expression,
431 * then intersect "context" with that expression.
432 * Otherwise, if the statement body is an expression tree,
433 * then intersect "context" with the context of this expression.
434 * Note that we cannot safely extract a context from subtrees
435 * of the statement body since we cannot tell when those subtrees
436 * are executed, if at all.
438 static __isl_give isl_set *stmt_extract_context(struct pet_stmt *stmt,
439 __isl_take isl_set *context)
441 int i;
442 pet_expr *body;
444 if (pet_stmt_is_affine_assume(stmt)) {
445 isl_multi_pw_aff *index;
446 isl_pw_aff *pa;
447 isl_set *cond;
449 index = pet_stmt_assume_get_index(stmt);
450 pa = isl_multi_pw_aff_get_pw_aff(index, 0);
451 isl_multi_pw_aff_free(index);
452 cond = isl_pw_aff_non_zero_set(pa);
453 cond = isl_set_reset_tuple_id(cond);
454 return isl_set_intersect(context, cond);
457 for (i = 0; i < stmt->n_arg; ++i)
458 context = expr_extract_context(stmt->args[i], context);
460 if (pet_tree_get_type(stmt->body) != pet_tree_expr)
461 return context;
463 body = pet_tree_expr_get_expr(stmt->body);
464 context = expr_extract_context(body, context);
465 pet_expr_free(body);
467 return context;
470 /* Construct a pet_scop in the given space that contains the given pet_stmt.
472 struct pet_scop *pet_scop_from_pet_stmt(__isl_take isl_space *space,
473 struct pet_stmt *stmt)
475 struct pet_scop *scop;
477 if (!stmt)
478 space = isl_space_free(space);
480 scop = scop_alloc(space, 1);
481 if (!scop)
482 goto error;
484 scop->context = stmt_extract_context(stmt, scop->context);
485 if (!scop->context)
486 goto error;
488 scop->stmts[0] = stmt;
489 scop->loc = pet_loc_copy(stmt->loc);
491 if (!scop->loc)
492 return pet_scop_free(scop);
494 return scop;
495 error:
496 pet_stmt_free(stmt);
497 pet_scop_free(scop);
498 return NULL;
501 /* Does "mpa" represent an access to an element of an unnamed space, i.e.,
502 * does it represent an affine expression?
504 static int multi_pw_aff_is_affine(__isl_keep isl_multi_pw_aff *mpa)
506 int has_id;
508 has_id = isl_multi_pw_aff_has_tuple_id(mpa, isl_dim_out);
509 if (has_id < 0)
510 return -1;
512 return !has_id;
515 /* Return the piecewise affine expression "set ? 1 : 0" defined on "dom".
517 static __isl_give isl_pw_aff *indicator_function(__isl_take isl_set *set,
518 __isl_take isl_set *dom)
520 isl_pw_aff *pa;
521 pa = isl_set_indicator_function(set);
522 pa = isl_pw_aff_intersect_domain(pa, dom);
523 return pa;
526 /* Return "lhs || rhs", defined on the shared definition domain.
528 static __isl_give isl_pw_aff *pw_aff_or(__isl_take isl_pw_aff *lhs,
529 __isl_take isl_pw_aff *rhs)
531 isl_set *cond;
532 isl_set *dom;
534 dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(lhs)),
535 isl_pw_aff_domain(isl_pw_aff_copy(rhs)));
536 cond = isl_set_union(isl_pw_aff_non_zero_set(lhs),
537 isl_pw_aff_non_zero_set(rhs));
538 cond = isl_set_coalesce(cond);
539 return indicator_function(cond, dom);
542 /* Combine ext1->skip[type] and ext2->skip[type] into ext->skip[type].
543 * ext may be equal to either ext1 or ext2.
545 * The two skips that need to be combined are assumed to be affine expressions.
547 * We need to skip in ext if we need to skip in either ext1 or ext2.
548 * We don't need to skip in ext if we don't need to skip in both ext1 and ext2.
550 static struct pet_scop_ext *combine_skips(struct pet_scop_ext *ext,
551 struct pet_scop_ext *ext1, struct pet_scop_ext *ext2,
552 enum pet_skip type)
554 isl_pw_aff *skip, *skip1, *skip2;
556 if (!ext)
557 return NULL;
558 if (!ext1->skip[type] && !ext2->skip[type])
559 return ext;
560 if (!ext1->skip[type]) {
561 if (ext == ext2)
562 return ext;
563 ext->skip[type] = ext2->skip[type];
564 ext2->skip[type] = NULL;
565 return ext;
567 if (!ext2->skip[type]) {
568 if (ext == ext1)
569 return ext;
570 ext->skip[type] = ext1->skip[type];
571 ext1->skip[type] = NULL;
572 return ext;
575 if (!multi_pw_aff_is_affine(ext1->skip[type]) ||
576 !multi_pw_aff_is_affine(ext2->skip[type]))
577 isl_die(isl_multi_pw_aff_get_ctx(ext1->skip[type]),
578 isl_error_internal, "can only combine affine skips",
579 goto error);
581 skip1 = isl_multi_pw_aff_get_pw_aff(ext1->skip[type], 0);
582 skip2 = isl_multi_pw_aff_get_pw_aff(ext2->skip[type], 0);
583 skip = pw_aff_or(skip1, skip2);
584 isl_multi_pw_aff_free(ext1->skip[type]);
585 ext1->skip[type] = NULL;
586 isl_multi_pw_aff_free(ext2->skip[type]);
587 ext2->skip[type] = NULL;
588 ext->skip[type] = isl_multi_pw_aff_from_pw_aff(skip);
589 if (!ext->skip[type])
590 goto error;
592 return ext;
593 error:
594 pet_scop_free(&ext->scop);
595 return NULL;
598 /* Combine scop1->skip[type] and scop2->skip[type] into scop->skip[type],
599 * where type takes on the values pet_skip_now and pet_skip_later.
600 * scop may be equal to either scop1 or scop2.
602 static struct pet_scop *scop_combine_skips(struct pet_scop *scop,
603 struct pet_scop *scop1, struct pet_scop *scop2)
605 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
606 struct pet_scop_ext *ext1 = (struct pet_scop_ext *) scop1;
607 struct pet_scop_ext *ext2 = (struct pet_scop_ext *) scop2;
609 ext = combine_skips(ext, ext1, ext2, pet_skip_now);
610 ext = combine_skips(ext, ext1, ext2, pet_skip_later);
611 return &ext->scop;
614 /* Update start and end of scop->loc to include the region from "start"
615 * to "end". In particular, if scop->loc == &pet_loc_dummy, then "scop"
616 * does not have any offset information yet and we simply take the information
617 * from "start" and "end". Otherwise, we update loc using "start" and "end".
619 struct pet_scop *pet_scop_update_start_end(struct pet_scop *scop,
620 unsigned start, unsigned end)
622 if (!scop)
623 return NULL;
625 if (scop->loc == &pet_loc_dummy)
626 scop->loc = pet_loc_alloc(isl_set_get_ctx(scop->context),
627 start, end, -1, strdup(""));
628 else
629 scop->loc = pet_loc_update_start_end(scop->loc, start, end);
631 if (!scop->loc)
632 return pet_scop_free(scop);
634 return scop;
637 /* Update start and end of scop->loc to include the region identified
638 * by "loc".
640 struct pet_scop *pet_scop_update_start_end_from_loc(struct pet_scop *scop,
641 __isl_keep pet_loc *loc)
643 return pet_scop_update_start_end(scop, pet_loc_get_start(loc),
644 pet_loc_get_end(loc));
647 /* Replace the location of "scop" by "loc".
649 struct pet_scop *pet_scop_set_loc(struct pet_scop *scop,
650 __isl_take pet_loc *loc)
652 if (!scop || !loc)
653 goto error;
655 pet_loc_free(scop->loc);
656 scop->loc = loc;
658 return scop;
659 error:
660 pet_loc_free(loc);
661 pet_scop_free(scop);
662 return NULL;
665 /* Does "implication" appear in the list of implications of "scop"?
667 static int is_known_implication(struct pet_scop *scop,
668 struct pet_implication *implication)
670 int i;
672 for (i = 0; i < scop->n_implication; ++i) {
673 struct pet_implication *pi = scop->implications[i];
674 int equal;
676 if (pi->satisfied != implication->satisfied)
677 continue;
678 equal = isl_map_is_equal(pi->extension, implication->extension);
679 if (equal < 0)
680 return -1;
681 if (equal)
682 return 1;
685 return 0;
688 /* Store the concatenation of the implications of "scop1" and "scop2"
689 * in "scop", removing duplicates (i.e., implications in "scop2" that
690 * already appear in "scop1").
692 static struct pet_scop *scop_collect_implications(isl_ctx *ctx,
693 struct pet_scop *scop, struct pet_scop *scop1, struct pet_scop *scop2)
695 int i, j;
697 if (!scop)
698 return NULL;
700 if (scop2->n_implication == 0) {
701 scop->n_implication = scop1->n_implication;
702 scop->implications = scop1->implications;
703 scop1->n_implication = 0;
704 scop1->implications = NULL;
705 return scop;
708 if (scop1->n_implication == 0) {
709 scop->n_implication = scop2->n_implication;
710 scop->implications = scop2->implications;
711 scop2->n_implication = 0;
712 scop2->implications = NULL;
713 return scop;
716 scop->implications = isl_calloc_array(ctx, struct pet_implication *,
717 scop1->n_implication + scop2->n_implication);
718 if (!scop->implications)
719 return pet_scop_free(scop);
721 for (i = 0; i < scop1->n_implication; ++i) {
722 scop->implications[i] = scop1->implications[i];
723 scop1->implications[i] = NULL;
726 scop->n_implication = scop1->n_implication;
727 j = scop1->n_implication;
728 for (i = 0; i < scop2->n_implication; ++i) {
729 int known;
731 known = is_known_implication(scop, scop2->implications[i]);
732 if (known < 0)
733 return pet_scop_free(scop);
734 if (known)
735 continue;
736 scop->implications[j++] = scop2->implications[i];
737 scop2->implications[i] = NULL;
739 scop->n_implication = j;
741 return scop;
744 /* Combine the offset information of "scop1" and "scop2" into "scop".
746 static struct pet_scop *scop_combine_start_end(struct pet_scop *scop,
747 struct pet_scop *scop1, struct pet_scop *scop2)
749 if (scop1->loc != &pet_loc_dummy)
750 scop = pet_scop_update_start_end_from_loc(scop, scop1->loc);
751 if (scop2->loc != &pet_loc_dummy)
752 scop = pet_scop_update_start_end_from_loc(scop, scop2->loc);
753 return scop;
756 /* Create and return an independence that filters out the dependences
757 * in "filter" with local variables "local".
759 static struct pet_independence *new_independence(
760 __isl_take isl_union_map *filter, __isl_take isl_union_set *local)
762 isl_ctx *ctx;
763 struct pet_independence *independence;
765 if (!filter || !local)
766 goto error;
767 ctx = isl_union_map_get_ctx(filter);
768 independence = isl_alloc_type(ctx, struct pet_independence);
769 if (!independence)
770 goto error;
772 independence->filter = filter;
773 independence->local = local;
775 return independence;
776 error:
777 isl_union_map_free(filter);
778 isl_union_set_free(local);
779 return NULL;
782 /* Add an independence that filters out the dependences
783 * in "filter" with local variables "local" to "scop".
785 struct pet_scop *pet_scop_add_independence(struct pet_scop *scop,
786 __isl_take isl_union_map *filter, __isl_take isl_union_set *local)
788 isl_ctx *ctx;
789 struct pet_independence *independence;
790 struct pet_independence **independences;
792 ctx = isl_union_map_get_ctx(filter);
793 independence = new_independence(filter, local);
794 if (!scop || !independence)
795 goto error;
797 independences = isl_realloc_array(ctx, scop->independences,
798 struct pet_independence *,
799 scop->n_independence + 1);
800 if (!independences)
801 goto error;
802 scop->independences = independences;
803 scop->independences[scop->n_independence] = independence;
804 scop->n_independence++;
806 return scop;
807 error:
808 pet_independence_free(independence);
809 pet_scop_free(scop);
810 return NULL;
813 /* Store the concatenation of the independences of "scop1" and "scop2"
814 * in "scop".
816 static struct pet_scop *scop_collect_independences(isl_ctx *ctx,
817 struct pet_scop *scop, struct pet_scop *scop1, struct pet_scop *scop2)
819 int i, off;
821 if (!scop)
822 return NULL;
824 if (scop2->n_independence == 0) {
825 scop->n_independence = scop1->n_independence;
826 scop->independences = scop1->independences;
827 scop1->n_independence = 0;
828 scop1->independences = NULL;
829 return scop;
832 if (scop1->n_independence == 0) {
833 scop->n_independence = scop2->n_independence;
834 scop->independences = scop2->independences;
835 scop2->n_independence = 0;
836 scop2->independences = NULL;
837 return scop;
840 scop->independences = isl_calloc_array(ctx, struct pet_independence *,
841 scop1->n_independence + scop2->n_independence);
842 if (!scop->independences)
843 return pet_scop_free(scop);
845 for (i = 0; i < scop1->n_independence; ++i) {
846 scop->independences[i] = scop1->independences[i];
847 scop1->independences[i] = NULL;
850 off = scop1->n_independence;
851 for (i = 0; i < scop2->n_independence; ++i) {
852 scop->independences[off + i] = scop2->independences[i];
853 scop2->independences[i] = NULL;
855 scop->n_independence = scop1->n_independence + scop2->n_independence;
857 return scop;
860 /* Construct a pet_scop that contains the offset information,
861 * arrays, statements and skip information in "scop1" and "scop2".
863 static struct pet_scop *pet_scop_add(isl_ctx *ctx, struct pet_scop *scop1,
864 struct pet_scop *scop2)
866 int i;
867 isl_space *space;
868 struct pet_scop *scop = NULL;
870 if (!scop1 || !scop2)
871 goto error;
873 if (scop1->n_stmt == 0) {
874 scop2 = scop_combine_skips(scop2, scop1, scop2);
875 pet_scop_free(scop1);
876 return scop2;
879 if (scop2->n_stmt == 0) {
880 scop1 = scop_combine_skips(scop1, scop1, scop2);
881 pet_scop_free(scop2);
882 return scop1;
885 space = isl_set_get_space(scop1->context);
886 scop = scop_alloc(space, scop1->n_stmt + scop2->n_stmt);
887 if (!scop)
888 goto error;
890 scop->arrays = isl_calloc_array(ctx, struct pet_array *,
891 scop1->n_array + scop2->n_array);
892 if (!scop->arrays)
893 goto error;
894 scop->n_array = scop1->n_array + scop2->n_array;
896 for (i = 0; i < scop1->n_stmt; ++i) {
897 scop->stmts[i] = scop1->stmts[i];
898 scop1->stmts[i] = NULL;
901 for (i = 0; i < scop2->n_stmt; ++i) {
902 scop->stmts[scop1->n_stmt + i] = scop2->stmts[i];
903 scop2->stmts[i] = NULL;
906 for (i = 0; i < scop1->n_array; ++i) {
907 scop->arrays[i] = scop1->arrays[i];
908 scop1->arrays[i] = NULL;
911 for (i = 0; i < scop2->n_array; ++i) {
912 scop->arrays[scop1->n_array + i] = scop2->arrays[i];
913 scop2->arrays[i] = NULL;
916 scop = scop_collect_implications(ctx, scop, scop1, scop2);
917 scop = pet_scop_restrict_context(scop, isl_set_copy(scop1->context));
918 scop = pet_scop_restrict_context(scop, isl_set_copy(scop2->context));
919 scop = scop_combine_skips(scop, scop1, scop2);
920 scop = scop_combine_start_end(scop, scop1, scop2);
921 scop = scop_collect_independences(ctx, scop, scop1, scop2);
923 pet_scop_free(scop1);
924 pet_scop_free(scop2);
925 return scop;
926 error:
927 pet_scop_free(scop1);
928 pet_scop_free(scop2);
929 pet_scop_free(scop);
930 return NULL;
933 /* Apply the skip condition "skip" to "scop".
934 * That is, make sure "scop" is not executed when the condition holds.
936 * If "skip" is an affine expression, we add the conditions under
937 * which the expression is zero to the context and the skip conditions
938 * of "scop".
939 * Otherwise, we add a filter on the variable attaining the value zero.
941 static struct pet_scop *restrict_skip(struct pet_scop *scop,
942 __isl_take isl_multi_pw_aff *skip)
944 isl_set *zero;
945 isl_pw_aff *pa;
946 int is_aff;
948 if (!scop || !skip)
949 goto error;
951 is_aff = multi_pw_aff_is_affine(skip);
952 if (is_aff < 0)
953 goto error;
955 if (!is_aff)
956 return pet_scop_filter(scop, skip, 0);
958 pa = isl_multi_pw_aff_get_pw_aff(skip, 0);
959 isl_multi_pw_aff_free(skip);
960 zero = isl_pw_aff_zero_set(pa);
961 scop = pet_scop_restrict(scop, zero);
963 return scop;
964 error:
965 isl_multi_pw_aff_free(skip);
966 return pet_scop_free(scop);
969 /* Construct a pet_scop that contains the arrays, statements and
970 * skip information in "scop1" and "scop2", where the two scops
971 * are executed "in sequence". That is, breaks and continues
972 * in scop1 have an effect on scop2.
974 struct pet_scop *pet_scop_add_seq(isl_ctx *ctx, struct pet_scop *scop1,
975 struct pet_scop *scop2)
977 if (scop1 && pet_scop_has_skip(scop1, pet_skip_now))
978 scop2 = restrict_skip(scop2,
979 pet_scop_get_skip(scop1, pet_skip_now));
980 return pet_scop_add(ctx, scop1, scop2);
983 /* Construct a pet_scop that contains the arrays, statements and
984 * skip information in "scop1" and "scop2", where the two scops
985 * are executed "in parallel". That is, any break or continue
986 * in scop1 has no effect on scop2.
988 struct pet_scop *pet_scop_add_par(isl_ctx *ctx, struct pet_scop *scop1,
989 struct pet_scop *scop2)
991 return pet_scop_add(ctx, scop1, scop2);
994 void *pet_implication_free(struct pet_implication *implication)
996 int i;
998 if (!implication)
999 return NULL;
1001 isl_map_free(implication->extension);
1003 free(implication);
1004 return NULL;
1007 void *pet_independence_free(struct pet_independence *independence)
1009 if (!independence)
1010 return NULL;
1012 isl_union_map_free(independence->filter);
1013 isl_union_set_free(independence->local);
1015 free(independence);
1016 return NULL;
1019 struct pet_scop *pet_scop_free(struct pet_scop *scop)
1021 int i;
1022 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1024 if (!scop)
1025 return NULL;
1026 pet_loc_free(scop->loc);
1027 isl_set_free(scop->context);
1028 isl_set_free(scop->context_value);
1029 if (scop->types)
1030 for (i = 0; i < scop->n_type; ++i)
1031 pet_type_free(scop->types[i]);
1032 free(scop->types);
1033 if (scop->arrays)
1034 for (i = 0; i < scop->n_array; ++i)
1035 pet_array_free(scop->arrays[i]);
1036 free(scop->arrays);
1037 if (scop->stmts)
1038 for (i = 0; i < scop->n_stmt; ++i)
1039 pet_stmt_free(scop->stmts[i]);
1040 free(scop->stmts);
1041 if (scop->implications)
1042 for (i = 0; i < scop->n_implication; ++i)
1043 pet_implication_free(scop->implications[i]);
1044 free(scop->implications);
1045 if (scop->independences)
1046 for (i = 0; i < scop->n_independence; ++i)
1047 pet_independence_free(scop->independences[i]);
1048 free(scop->independences);
1049 isl_multi_pw_aff_free(ext->skip[pet_skip_now]);
1050 isl_multi_pw_aff_free(ext->skip[pet_skip_later]);
1051 free(scop);
1052 return NULL;
1055 void pet_type_dump(struct pet_type *type)
1057 if (!type)
1058 return;
1060 fprintf(stderr, "%s -> %s\n", type->name, type->definition);
1063 void pet_implication_dump(struct pet_implication *implication)
1065 if (!implication)
1066 return;
1068 fprintf(stderr, "%d\n", implication->satisfied);
1069 isl_map_dump(implication->extension);
1072 void pet_scop_dump(struct pet_scop *scop)
1074 int i;
1075 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1077 if (!scop)
1078 return;
1080 isl_set_dump(scop->context);
1081 isl_set_dump(scop->context_value);
1082 for (i = 0; i < scop->n_type; ++i)
1083 pet_type_dump(scop->types[i]);
1084 for (i = 0; i < scop->n_array; ++i)
1085 pet_array_dump(scop->arrays[i]);
1086 for (i = 0; i < scop->n_stmt; ++i)
1087 pet_stmt_dump(scop->stmts[i]);
1088 for (i = 0; i < scop->n_implication; ++i)
1089 pet_implication_dump(scop->implications[i]);
1091 if (ext->skip[0]) {
1092 fprintf(stderr, "skip\n");
1093 isl_multi_pw_aff_dump(ext->skip[0]);
1094 isl_multi_pw_aff_dump(ext->skip[1]);
1098 /* Return 1 if the two pet_arrays are equivalent.
1100 * We don't compare element_size as this may be target dependent.
1102 int pet_array_is_equal(struct pet_array *array1, struct pet_array *array2)
1104 if (!array1 || !array2)
1105 return 0;
1107 if (!isl_set_is_equal(array1->context, array2->context))
1108 return 0;
1109 if (!isl_set_is_equal(array1->extent, array2->extent))
1110 return 0;
1111 if (!!array1->value_bounds != !!array2->value_bounds)
1112 return 0;
1113 if (array1->value_bounds &&
1114 !isl_set_is_equal(array1->value_bounds, array2->value_bounds))
1115 return 0;
1116 if (strcmp(array1->element_type, array2->element_type))
1117 return 0;
1118 if (array1->element_is_record != array2->element_is_record)
1119 return 0;
1120 if (array1->live_out != array2->live_out)
1121 return 0;
1122 if (array1->uniquely_defined != array2->uniquely_defined)
1123 return 0;
1124 if (array1->declared != array2->declared)
1125 return 0;
1126 if (array1->exposed != array2->exposed)
1127 return 0;
1129 return 1;
1132 /* Return 1 if the two pet_stmts are equivalent.
1134 int pet_stmt_is_equal(struct pet_stmt *stmt1, struct pet_stmt *stmt2)
1136 int i;
1138 if (!stmt1 || !stmt2)
1139 return 0;
1141 if (pet_loc_get_line(stmt1->loc) != pet_loc_get_line(stmt2->loc))
1142 return 0;
1143 if (!isl_set_is_equal(stmt1->domain, stmt2->domain))
1144 return 0;
1145 if (!isl_map_is_equal(stmt1->schedule, stmt2->schedule))
1146 return 0;
1147 if (!pet_tree_is_equal(stmt1->body, stmt2->body))
1148 return 0;
1149 if (stmt1->n_arg != stmt2->n_arg)
1150 return 0;
1151 for (i = 0; i < stmt1->n_arg; ++i) {
1152 if (!pet_expr_is_equal(stmt1->args[i], stmt2->args[i]))
1153 return 0;
1156 return 1;
1159 /* Return 1 if the two pet_types are equivalent.
1161 * We only compare the names of the types since the exact representation
1162 * of the definition may depend on the version of clang being used.
1164 int pet_type_is_equal(struct pet_type *type1, struct pet_type *type2)
1166 if (!type1 || !type2)
1167 return 0;
1169 if (strcmp(type1->name, type2->name))
1170 return 0;
1172 return 1;
1175 /* Return 1 if the two pet_implications are equivalent.
1177 int pet_implication_is_equal(struct pet_implication *implication1,
1178 struct pet_implication *implication2)
1180 if (!implication1 || !implication2)
1181 return 0;
1183 if (implication1->satisfied != implication2->satisfied)
1184 return 0;
1185 if (!isl_map_is_equal(implication1->extension, implication2->extension))
1186 return 0;
1188 return 1;
1191 /* Return 1 if the two pet_independences are equivalent.
1193 int pet_independence_is_equal(struct pet_independence *independence1,
1194 struct pet_independence *independence2)
1196 if (!independence1 || !independence2)
1197 return 0;
1199 if (!isl_union_map_is_equal(independence1->filter,
1200 independence2->filter))
1201 return 0;
1202 if (!isl_union_set_is_equal(independence1->local, independence2->local))
1203 return 0;
1205 return 1;
1208 /* Return 1 if the two pet_scops are equivalent.
1210 int pet_scop_is_equal(struct pet_scop *scop1, struct pet_scop *scop2)
1212 int i;
1214 if (!scop1 || !scop2)
1215 return 0;
1217 if (!isl_set_is_equal(scop1->context, scop2->context))
1218 return 0;
1219 if (!isl_set_is_equal(scop1->context_value, scop2->context_value))
1220 return 0;
1222 if (scop1->n_type != scop2->n_type)
1223 return 0;
1224 for (i = 0; i < scop1->n_type; ++i)
1225 if (!pet_type_is_equal(scop1->types[i], scop2->types[i]))
1226 return 0;
1228 if (scop1->n_array != scop2->n_array)
1229 return 0;
1230 for (i = 0; i < scop1->n_array; ++i)
1231 if (!pet_array_is_equal(scop1->arrays[i], scop2->arrays[i]))
1232 return 0;
1234 if (scop1->n_stmt != scop2->n_stmt)
1235 return 0;
1236 for (i = 0; i < scop1->n_stmt; ++i)
1237 if (!pet_stmt_is_equal(scop1->stmts[i], scop2->stmts[i]))
1238 return 0;
1240 if (scop1->n_implication != scop2->n_implication)
1241 return 0;
1242 for (i = 0; i < scop1->n_implication; ++i)
1243 if (!pet_implication_is_equal(scop1->implications[i],
1244 scop2->implications[i]))
1245 return 0;
1247 if (scop1->n_independence != scop2->n_independence)
1248 return 0;
1249 for (i = 0; i < scop1->n_independence; ++i)
1250 if (!pet_independence_is_equal(scop1->independences[i],
1251 scop2->independences[i]))
1252 return 0;
1254 return 1;
1257 /* Does the set "extent" reference a virtual array, i.e.,
1258 * one with user pointer equal to NULL?
1259 * A virtual array does not have any members.
1261 static int extent_is_virtual_array(__isl_keep isl_set *extent)
1263 isl_id *id;
1264 int is_virtual;
1266 if (!isl_set_has_tuple_id(extent))
1267 return 0;
1268 if (isl_set_is_wrapping(extent))
1269 return 0;
1270 id = isl_set_get_tuple_id(extent);
1271 is_virtual = !isl_id_get_user(id);
1272 isl_id_free(id);
1274 return is_virtual;
1277 /* Intersect the initial dimensions of "array" with "domain", provided
1278 * that "array" represents a virtual array.
1280 * If "array" is virtual, then We take the preimage of "domain"
1281 * over the projection of the extent of "array" onto its initial dimensions
1282 * and intersect this extent with the result.
1284 static struct pet_array *virtual_array_intersect_domain_prefix(
1285 struct pet_array *array, __isl_take isl_set *domain)
1287 int n;
1288 isl_space *space;
1289 isl_multi_aff *ma;
1291 if (!array || !extent_is_virtual_array(array->extent)) {
1292 isl_set_free(domain);
1293 return array;
1296 space = isl_set_get_space(array->extent);
1297 n = isl_set_dim(domain, isl_dim_set);
1298 ma = pet_prefix_projection(space, n);
1299 domain = isl_set_preimage_multi_aff(domain, ma);
1301 array->extent = isl_set_intersect(array->extent, domain);
1302 if (!array->extent)
1303 return pet_array_free(array);
1305 return array;
1308 /* Intersect the initial dimensions of the domain of "stmt"
1309 * with "domain".
1311 * We take the preimage of "domain" over the projection of the
1312 * domain of "stmt" onto its initial dimensions and intersect
1313 * the domain of "stmt" with the result.
1315 static struct pet_stmt *stmt_intersect_domain_prefix(struct pet_stmt *stmt,
1316 __isl_take isl_set *domain)
1318 int n;
1319 isl_space *space;
1320 isl_multi_aff *ma;
1322 if (!stmt)
1323 goto error;
1325 space = isl_set_get_space(stmt->domain);
1326 n = isl_set_dim(domain, isl_dim_set);
1327 ma = pet_prefix_projection(space, n);
1328 domain = isl_set_preimage_multi_aff(domain, ma);
1330 stmt->domain = isl_set_intersect(stmt->domain, domain);
1331 if (!stmt->domain)
1332 return pet_stmt_free(stmt);
1334 return stmt;
1335 error:
1336 isl_set_free(domain);
1337 return pet_stmt_free(stmt);
1340 /* Intersect the initial dimensions of the domain of "implication"
1341 * with "domain".
1343 * We take the preimage of "domain" over the projection of the
1344 * domain of "implication" onto its initial dimensions and intersect
1345 * the domain of "implication" with the result.
1347 static struct pet_implication *implication_intersect_domain_prefix(
1348 struct pet_implication *implication, __isl_take isl_set *domain)
1350 int n;
1351 isl_space *space;
1352 isl_multi_aff *ma;
1354 if (!implication)
1355 goto error;
1357 space = isl_map_get_space(implication->extension);
1358 n = isl_set_dim(domain, isl_dim_set);
1359 ma = pet_prefix_projection(isl_space_domain(space), n);
1360 domain = isl_set_preimage_multi_aff(domain, ma);
1362 implication->extension =
1363 isl_map_intersect_domain(implication->extension, domain);
1364 if (!implication->extension)
1365 return pet_implication_free(implication);
1367 return implication;
1368 error:
1369 isl_set_free(domain);
1370 return pet_implication_free(implication);
1373 /* Intersect the initial dimensions of the domains in "scop" with "domain".
1375 * The extents of the virtual arrays match the iteration domains,
1376 * so if the iteration domain changes, we need to change those extents too.
1378 struct pet_scop *pet_scop_intersect_domain_prefix(struct pet_scop *scop,
1379 __isl_take isl_set *domain)
1381 int i;
1383 if (!scop)
1384 goto error;
1386 for (i = 0; i < scop->n_array; ++i) {
1387 scop->arrays[i] = virtual_array_intersect_domain_prefix(
1388 scop->arrays[i], isl_set_copy(domain));
1389 if (!scop->arrays[i])
1390 goto error;
1393 for (i = 0; i < scop->n_stmt; ++i) {
1394 scop->stmts[i] = stmt_intersect_domain_prefix(scop->stmts[i],
1395 isl_set_copy(domain));
1396 if (!scop->stmts[i])
1397 goto error;
1400 for (i = 0; i < scop->n_implication; ++i) {
1401 scop->implications[i] =
1402 implication_intersect_domain_prefix(scop->implications[i],
1403 isl_set_copy(domain));
1404 if (!scop->implications[i])
1405 return pet_scop_free(scop);
1408 isl_set_free(domain);
1409 return scop;
1410 error:
1411 isl_set_free(domain);
1412 return pet_scop_free(scop);
1415 /* Prefix the schedule of "stmt" with an extra dimension with constant
1416 * value "pos".
1418 struct pet_stmt *pet_stmt_prefix(struct pet_stmt *stmt, int pos)
1420 if (!stmt)
1421 return NULL;
1423 stmt->schedule = isl_map_insert_dims(stmt->schedule, isl_dim_out, 0, 1);
1424 stmt->schedule = isl_map_fix_si(stmt->schedule, isl_dim_out, 0, pos);
1425 if (!stmt->schedule)
1426 return pet_stmt_free(stmt);
1428 return stmt;
1431 /* Prefix the schedules of all statements in "scop" with an extra
1432 * dimension with constant value "pos".
1434 struct pet_scop *pet_scop_prefix(struct pet_scop *scop, int pos)
1436 int i;
1438 if (!scop)
1439 return NULL;
1441 for (i = 0; i < scop->n_stmt; ++i) {
1442 scop->stmts[i] = pet_stmt_prefix(scop->stmts[i], pos);
1443 if (!scop->stmts[i])
1444 return pet_scop_free(scop);
1447 return scop;
1450 /* Prefix the schedule of "stmt" with "sched".
1452 * The domain of "sched" refers the current outer loop iterators and
1453 * needs to be mapped to the iteration domain of "stmt" first
1454 * before being prepended to the schedule of "stmt".
1456 static struct pet_stmt *pet_stmt_embed(struct pet_stmt *stmt,
1457 __isl_take isl_map *sched)
1459 int n;
1460 isl_space *space;
1461 isl_multi_aff *ma;
1463 if (!stmt)
1464 goto error;
1466 space = pet_stmt_get_space(stmt);
1467 n = isl_map_dim(sched, isl_dim_in);
1468 ma = pet_prefix_projection(space, n);
1469 sched = isl_map_preimage_domain_multi_aff(sched, ma);
1470 stmt->schedule = isl_map_flat_range_product(sched, stmt->schedule);
1471 if (!stmt->schedule)
1472 return pet_stmt_free(stmt);
1474 return stmt;
1475 error:
1476 isl_map_free(sched);
1477 return NULL;
1480 /* Update the context with respect to an embedding into a loop
1481 * with iteration domain "dom".
1482 * The input context lives in the same space as "dom".
1483 * The output context has the inner dimension removed.
1485 * An outer loop iterator value is invalid for the embedding if
1486 * any of the corresponding inner iterator values is invalid.
1487 * That is, an outer loop iterator value is valid only if all the corresponding
1488 * inner iterator values are valid.
1489 * We therefore compute the set of outer loop iterators l
1491 * forall i: dom(l,i) => valid(l,i)
1493 * or
1495 * forall i: not dom(l,i) or valid(l,i)
1497 * or
1499 * not exists i: dom(l,i) and not valid(l,i)
1501 * i.e.,
1503 * not exists i: (dom \ valid)(l,i)
1505 * If there are any unnamed parameters in "dom", then we consider
1506 * a parameter value to be valid if it is valid for any value of those
1507 * unnamed parameters. They are therefore projected out at the end.
1509 static __isl_give isl_set *context_embed(__isl_take isl_set *context,
1510 __isl_keep isl_set *dom)
1512 int pos;
1514 pos = isl_set_dim(context, isl_dim_set) - 1;
1515 context = isl_set_subtract(isl_set_copy(dom), context);
1516 context = isl_set_project_out(context, isl_dim_set, pos, 1);
1517 context = isl_set_complement(context);
1518 context = pet_nested_remove_from_set(context);
1520 return context;
1523 /* Update the implication with respect to an embedding into a loop
1524 * with iteration domain "dom".
1526 * Since embed_access extends virtual arrays along with the domain
1527 * of the access, we need to do the same with domain and range
1528 * of the implication. Since the original implication is only valid
1529 * within a given iteration of the loop, the extended implication
1530 * maps the extra array dimension corresponding to the extra loop
1531 * to itself.
1533 static struct pet_implication *pet_implication_embed(
1534 struct pet_implication *implication, __isl_take isl_set *dom)
1536 isl_id *id;
1537 isl_map *map;
1539 if (!implication)
1540 goto error;
1542 map = isl_set_identity(dom);
1543 id = isl_map_get_tuple_id(implication->extension, isl_dim_in);
1544 map = isl_map_flat_product(map, implication->extension);
1545 map = isl_map_set_tuple_id(map, isl_dim_in, isl_id_copy(id));
1546 map = isl_map_set_tuple_id(map, isl_dim_out, id);
1547 implication->extension = map;
1548 if (!implication->extension)
1549 return pet_implication_free(implication);
1551 return implication;
1552 error:
1553 isl_set_free(dom);
1554 return NULL;
1557 /* Adjust the context and statement schedules according to an embedding
1558 * in a loop with iteration domain "dom" and schedule "sched".
1560 * Any skip conditions within the loop have no effect outside of the loop.
1561 * The caller is responsible for making sure skip[pet_skip_later] has been
1562 * taken into account.
1564 struct pet_scop *pet_scop_embed(struct pet_scop *scop, __isl_take isl_set *dom,
1565 __isl_take isl_aff *sched)
1567 int i;
1568 isl_map *sched_map;
1570 sched_map = isl_map_from_aff(sched);
1572 if (!scop)
1573 goto error;
1575 pet_scop_reset_skip(scop, pet_skip_now);
1576 pet_scop_reset_skip(scop, pet_skip_later);
1578 scop->context = context_embed(scop->context, dom);
1579 if (!scop->context)
1580 goto error;
1582 for (i = 0; i < scop->n_stmt; ++i) {
1583 scop->stmts[i] = pet_stmt_embed(scop->stmts[i],
1584 isl_map_copy(sched_map));
1585 if (!scop->stmts[i])
1586 goto error;
1589 isl_set_free(dom);
1590 isl_map_free(sched_map);
1591 return scop;
1592 error:
1593 isl_set_free(dom);
1594 isl_map_free(sched_map);
1595 return pet_scop_free(scop);
1598 /* Add extra conditions to scop->skip[type].
1600 * The new skip condition only holds if it held before
1601 * and the condition is true. It does not hold if it did not hold
1602 * before or the condition is false.
1604 * The skip condition is assumed to be an affine expression.
1606 static struct pet_scop *pet_scop_restrict_skip(struct pet_scop *scop,
1607 enum pet_skip type, __isl_keep isl_set *cond)
1609 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1610 isl_pw_aff *skip;
1611 isl_set *dom;
1613 if (!scop)
1614 return NULL;
1615 if (!ext->skip[type])
1616 return scop;
1618 if (!multi_pw_aff_is_affine(ext->skip[type]))
1619 isl_die(isl_multi_pw_aff_get_ctx(ext->skip[type]),
1620 isl_error_internal, "can only restrict affine skips",
1621 return pet_scop_free(scop));
1623 skip = isl_multi_pw_aff_get_pw_aff(ext->skip[type], 0);
1624 dom = isl_pw_aff_domain(isl_pw_aff_copy(skip));
1625 cond = isl_set_copy(cond);
1626 cond = isl_set_intersect(cond, isl_pw_aff_non_zero_set(skip));
1627 skip = indicator_function(cond, dom);
1628 isl_multi_pw_aff_free(ext->skip[type]);
1629 ext->skip[type] = isl_multi_pw_aff_from_pw_aff(skip);
1630 if (!ext->skip[type])
1631 return pet_scop_free(scop);
1633 return scop;
1636 /* Adjust the context and the skip conditions to the fact that
1637 * the scop was created in a context where "cond" holds.
1639 * An outer loop iterator or parameter value is valid for the result
1640 * if it was valid for the original scop and satisfies "cond" or if it does
1641 * not satisfy "cond" as in this case the scop is not executed
1642 * and the original constraints on these values are irrelevant.
1644 struct pet_scop *pet_scop_restrict(struct pet_scop *scop,
1645 __isl_take isl_set *cond)
1647 int i;
1649 scop = pet_scop_restrict_skip(scop, pet_skip_now, cond);
1650 scop = pet_scop_restrict_skip(scop, pet_skip_later, cond);
1652 if (!scop)
1653 goto error;
1655 scop->context = isl_set_intersect(scop->context, isl_set_copy(cond));
1656 scop->context = isl_set_union(scop->context,
1657 isl_set_complement(isl_set_copy(cond)));
1658 scop->context = isl_set_coalesce(scop->context);
1659 scop->context = pet_nested_remove_from_set(scop->context);
1660 if (!scop->context)
1661 goto error;
1663 isl_set_free(cond);
1664 return scop;
1665 error:
1666 isl_set_free(cond);
1667 return pet_scop_free(scop);
1670 /* Insert an argument expression corresponding to "test" in front
1671 * of the list of arguments described by *n_arg and *args.
1673 static int args_insert_access(unsigned *n_arg, pet_expr ***args,
1674 __isl_keep isl_multi_pw_aff *test)
1676 int i;
1677 isl_ctx *ctx = isl_multi_pw_aff_get_ctx(test);
1679 if (!test)
1680 return -1;
1682 if (!*args) {
1683 *args = isl_calloc_array(ctx, pet_expr *, 1);
1684 if (!*args)
1685 return -1;
1686 } else {
1687 pet_expr **ext;
1688 ext = isl_calloc_array(ctx, pet_expr *, 1 + *n_arg);
1689 if (!ext)
1690 return -1;
1691 for (i = 0; i < *n_arg; ++i)
1692 ext[1 + i] = (*args)[i];
1693 free(*args);
1694 *args = ext;
1696 (*n_arg)++;
1697 (*args)[0] = pet_expr_from_index(isl_multi_pw_aff_copy(test));
1698 if (!(*args)[0])
1699 return -1;
1701 return 0;
1704 /* Look through the applications in "scop" for any that can be
1705 * applied to the filter expressed by "map" and "satisified".
1706 * If there is any, then apply it to "map" and return the result.
1707 * Otherwise, return "map".
1708 * "id" is the identifier of the virtual array.
1710 * We only introduce at most one implication for any given virtual array,
1711 * so we can apply the implication and return as soon as we find one.
1713 static __isl_give isl_map *apply_implications(struct pet_scop *scop,
1714 __isl_take isl_map *map, __isl_keep isl_id *id, int satisfied)
1716 int i;
1718 for (i = 0; i < scop->n_implication; ++i) {
1719 struct pet_implication *pi = scop->implications[i];
1720 isl_id *pi_id;
1722 if (pi->satisfied != satisfied)
1723 continue;
1724 pi_id = isl_map_get_tuple_id(pi->extension, isl_dim_in);
1725 isl_id_free(pi_id);
1726 if (pi_id != id)
1727 continue;
1729 return isl_map_apply_range(map, isl_map_copy(pi->extension));
1732 return map;
1735 /* Is the filter expressed by "test" and "satisfied" implied
1736 * by filter "pos" on "domain", with filter "expr", taking into
1737 * account the implications of "scop"?
1739 * For filter on domain implying that expressed by "test" and "satisfied",
1740 * the filter needs to be an access to the same (virtual) array as "test" and
1741 * the filter value needs to be equal to "satisfied".
1742 * Moreover, the filter access relation, possibly extended by
1743 * the implications in "scop" needs to contain "test".
1745 static int implies_filter(struct pet_scop *scop,
1746 __isl_keep isl_map *domain, int pos, __isl_keep pet_expr *expr,
1747 __isl_keep isl_map *test, int satisfied)
1749 isl_id *test_id, *arg_id;
1750 isl_val *val;
1751 int is_int;
1752 int s;
1753 int is_subset;
1754 isl_map *implied;
1756 if (expr->type != pet_expr_access)
1757 return 0;
1758 test_id = isl_map_get_tuple_id(test, isl_dim_out);
1759 arg_id = pet_expr_access_get_id(expr);
1760 isl_id_free(arg_id);
1761 isl_id_free(test_id);
1762 if (test_id != arg_id)
1763 return 0;
1764 val = isl_map_plain_get_val_if_fixed(domain, isl_dim_out, pos);
1765 is_int = isl_val_is_int(val);
1766 if (is_int)
1767 s = isl_val_get_num_si(val);
1768 isl_val_free(val);
1769 if (!val)
1770 return -1;
1771 if (!is_int)
1772 return 0;
1773 if (s != satisfied)
1774 return 0;
1776 implied = isl_map_from_multi_pw_aff(pet_expr_access_get_index(expr));
1777 implied = apply_implications(scop, implied, test_id, satisfied);
1778 is_subset = isl_map_is_subset(test, implied);
1779 isl_map_free(implied);
1781 return is_subset;
1784 /* Is the filter expressed by "test" and "satisfied" implied
1785 * by any of the filters on the domain of "stmt", taking into
1786 * account the implications of "scop"?
1788 static int filter_implied(struct pet_scop *scop,
1789 struct pet_stmt *stmt, __isl_keep isl_multi_pw_aff *test, int satisfied)
1791 int i;
1792 int implied;
1793 isl_id *test_id;
1794 isl_map *domain;
1795 isl_map *test_map;
1797 if (!scop || !stmt || !test)
1798 return -1;
1799 if (scop->n_implication == 0)
1800 return 0;
1801 if (stmt->n_arg == 0)
1802 return 0;
1804 domain = isl_set_unwrap(isl_set_copy(stmt->domain));
1805 test_map = isl_map_from_multi_pw_aff(isl_multi_pw_aff_copy(test));
1807 implied = 0;
1808 for (i = 0; i < stmt->n_arg; ++i) {
1809 implied = implies_filter(scop, domain, i, stmt->args[i],
1810 test_map, satisfied);
1811 if (implied < 0 || implied)
1812 break;
1815 isl_map_free(test_map);
1816 isl_map_free(domain);
1817 return implied;
1820 /* Make the statement "stmt" depend on the value of "test"
1821 * being equal to "satisfied" by adjusting stmt->domain.
1823 * The domain of "test" corresponds to the (zero or more) outer dimensions
1824 * of the iteration domain.
1826 * We first extend "test" to apply to the entire iteration domain and
1827 * then check if the filter that we are about to add is implied
1828 * by any of the current filters, possibly taking into account
1829 * the implications in "scop". If so, we leave "stmt" untouched and return.
1831 * Otherwise, we insert an argument corresponding to a read to "test"
1832 * from the iteration domain of "stmt" in front of the list of arguments.
1833 * We also insert a corresponding output dimension in the wrapped
1834 * map contained in stmt->domain, with value set to "satisfied".
1836 static struct pet_stmt *stmt_filter(struct pet_scop *scop,
1837 struct pet_stmt *stmt, __isl_take isl_multi_pw_aff *test, int satisfied)
1839 int i;
1840 int implied;
1841 isl_id *id;
1842 isl_ctx *ctx;
1843 isl_pw_multi_aff *pma;
1844 isl_multi_aff *add_dom;
1845 isl_space *space;
1846 isl_local_space *ls;
1847 int n_test_dom;
1849 if (!stmt || !test)
1850 goto error;
1852 space = pet_stmt_get_space(stmt);
1853 n_test_dom = isl_multi_pw_aff_dim(test, isl_dim_in);
1854 space = isl_space_from_domain(space);
1855 space = isl_space_add_dims(space, isl_dim_out, n_test_dom);
1856 add_dom = isl_multi_aff_zero(isl_space_copy(space));
1857 ls = isl_local_space_from_space(isl_space_domain(space));
1858 for (i = 0; i < n_test_dom; ++i) {
1859 isl_aff *aff;
1860 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
1861 isl_dim_set, i);
1862 add_dom = isl_multi_aff_set_aff(add_dom, i, aff);
1864 isl_local_space_free(ls);
1865 test = isl_multi_pw_aff_pullback_multi_aff(test, add_dom);
1867 implied = filter_implied(scop, stmt, test, satisfied);
1868 if (implied < 0)
1869 goto error;
1870 if (implied) {
1871 isl_multi_pw_aff_free(test);
1872 return stmt;
1875 id = isl_multi_pw_aff_get_tuple_id(test, isl_dim_out);
1876 pma = pet_filter_insert_pma(isl_set_get_space(stmt->domain),
1877 id, satisfied);
1878 stmt->domain = isl_set_preimage_pw_multi_aff(stmt->domain, pma);
1880 if (args_insert_access(&stmt->n_arg, &stmt->args, test) < 0)
1881 goto error;
1883 isl_multi_pw_aff_free(test);
1884 return stmt;
1885 error:
1886 isl_multi_pw_aff_free(test);
1887 return pet_stmt_free(stmt);
1890 /* Does "scop" have a skip condition of the given "type"?
1892 int pet_scop_has_skip(struct pet_scop *scop, enum pet_skip type)
1894 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1896 if (!scop)
1897 return -1;
1898 return ext->skip[type] != NULL;
1901 /* Does "scop" have a skip condition of the given "type" that
1902 * is an affine expression?
1904 int pet_scop_has_affine_skip(struct pet_scop *scop, enum pet_skip type)
1906 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1908 if (!scop)
1909 return -1;
1910 if (!ext->skip[type])
1911 return 0;
1912 return multi_pw_aff_is_affine(ext->skip[type]);
1915 /* Does "scop" have a skip condition of the given "type" that
1916 * is not an affine expression?
1918 int pet_scop_has_var_skip(struct pet_scop *scop, enum pet_skip type)
1920 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1921 int aff;
1923 if (!scop)
1924 return -1;
1925 if (!ext->skip[type])
1926 return 0;
1927 aff = multi_pw_aff_is_affine(ext->skip[type]);
1928 if (aff < 0)
1929 return -1;
1930 return !aff;
1933 /* Does "scop" have a skip condition of the given "type" that
1934 * is affine and holds on the entire domain?
1936 int pet_scop_has_universal_skip(struct pet_scop *scop, enum pet_skip type)
1938 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1939 isl_pw_aff *pa;
1940 isl_set *set;
1941 int is_aff;
1942 int is_univ;
1944 is_aff = pet_scop_has_affine_skip(scop, type);
1945 if (is_aff < 0 || !is_aff)
1946 return is_aff;
1948 pa = isl_multi_pw_aff_get_pw_aff(ext->skip[type], 0);
1949 set = isl_pw_aff_non_zero_set(pa);
1950 is_univ = isl_set_plain_is_universe(set);
1951 isl_set_free(set);
1953 return is_univ;
1956 /* Replace scop->skip[type] by "skip".
1958 struct pet_scop *pet_scop_set_skip(struct pet_scop *scop,
1959 enum pet_skip type, __isl_take isl_multi_pw_aff *skip)
1961 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1963 if (!scop || !skip)
1964 goto error;
1966 isl_multi_pw_aff_free(ext->skip[type]);
1967 ext->skip[type] = skip;
1969 return scop;
1970 error:
1971 isl_multi_pw_aff_free(skip);
1972 return pet_scop_free(scop);
1975 /* Return a copy of scop->skip[type].
1977 __isl_give isl_multi_pw_aff *pet_scop_get_skip(struct pet_scop *scop,
1978 enum pet_skip type)
1980 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1982 if (!scop)
1983 return NULL;
1985 return isl_multi_pw_aff_copy(ext->skip[type]);
1988 /* Assuming scop->skip[type] is an affine expression,
1989 * return the constraints on the outer loop domain for which the skip condition
1990 * holds.
1992 __isl_give isl_set *pet_scop_get_affine_skip_domain(struct pet_scop *scop,
1993 enum pet_skip type)
1995 isl_multi_pw_aff *skip;
1996 isl_pw_aff *pa;
1998 skip = pet_scop_get_skip(scop, type);
1999 pa = isl_multi_pw_aff_get_pw_aff(skip, 0);
2000 isl_multi_pw_aff_free(skip);
2001 return isl_pw_aff_non_zero_set(pa);
2004 /* Return the identifier of the variable that is accessed by
2005 * the skip condition of the given type.
2007 * The skip condition is assumed not to be an affine condition.
2009 __isl_give isl_id *pet_scop_get_skip_id(struct pet_scop *scop,
2010 enum pet_skip type)
2012 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2014 if (!scop)
2015 return NULL;
2017 return isl_multi_pw_aff_get_tuple_id(ext->skip[type], isl_dim_out);
2020 /* Return an access pet_expr corresponding to the skip condition
2021 * of the given type.
2023 __isl_give pet_expr *pet_scop_get_skip_expr(struct pet_scop *scop,
2024 enum pet_skip type)
2026 return pet_expr_from_index(pet_scop_get_skip(scop, type));
2029 /* Drop the the skip condition scop->skip[type].
2031 void pet_scop_reset_skip(struct pet_scop *scop, enum pet_skip type)
2033 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2035 if (!scop)
2036 return;
2038 isl_multi_pw_aff_free(ext->skip[type]);
2039 ext->skip[type] = NULL;
2042 /* Make the skip condition (if any) depend on the value of "test" being
2043 * equal to "satisfied".
2045 * We only support the case where the original skip condition is universal,
2046 * i.e., where skipping is unconditional, and where satisfied == 1.
2047 * In this case, the skip condition is changed to skip only when
2048 * "test" is equal to one.
2050 static struct pet_scop *pet_scop_filter_skip(struct pet_scop *scop,
2051 enum pet_skip type, __isl_keep isl_multi_pw_aff *test, int satisfied)
2053 int is_univ = 0;
2055 if (!scop)
2056 return NULL;
2057 if (!pet_scop_has_skip(scop, type))
2058 return scop;
2060 if (satisfied)
2061 is_univ = pet_scop_has_universal_skip(scop, type);
2062 if (is_univ < 0)
2063 return pet_scop_free(scop);
2064 if (satisfied && is_univ) {
2065 isl_multi_pw_aff *skip;
2066 skip = isl_multi_pw_aff_copy(test);
2067 scop = pet_scop_set_skip(scop, type, skip);
2068 if (!scop)
2069 return NULL;
2070 } else {
2071 isl_die(isl_multi_pw_aff_get_ctx(test), isl_error_internal,
2072 "skip expression cannot be filtered",
2073 return pet_scop_free(scop));
2076 return scop;
2079 /* Make all statements in "scop" depend on the value of "test"
2080 * being equal to "satisfied" by adjusting their domains.
2082 struct pet_scop *pet_scop_filter(struct pet_scop *scop,
2083 __isl_take isl_multi_pw_aff *test, int satisfied)
2085 int i;
2087 scop = pet_scop_filter_skip(scop, pet_skip_now, test, satisfied);
2088 scop = pet_scop_filter_skip(scop, pet_skip_later, test, satisfied);
2090 if (!scop || !test)
2091 goto error;
2093 for (i = 0; i < scop->n_stmt; ++i) {
2094 scop->stmts[i] = stmt_filter(scop, scop->stmts[i],
2095 isl_multi_pw_aff_copy(test), satisfied);
2096 if (!scop->stmts[i])
2097 goto error;
2100 isl_multi_pw_aff_free(test);
2101 return scop;
2102 error:
2103 isl_multi_pw_aff_free(test);
2104 return pet_scop_free(scop);
2107 /* Add the parameters of the access expression "expr" to "space".
2109 static int access_collect_params(__isl_keep pet_expr *expr, void *user)
2111 int i;
2112 isl_space *expr_space;
2113 isl_space **space = user;
2115 expr_space = pet_expr_access_get_parameter_space(expr);
2116 *space = isl_space_align_params(*space, expr_space);
2118 return *space ? 0 : -1;
2121 /* Add all parameters in "stmt" to "space" and return the result.
2123 static __isl_give isl_space *stmt_collect_params(struct pet_stmt *stmt,
2124 __isl_take isl_space *space)
2126 int i;
2128 if (!stmt)
2129 return isl_space_free(space);
2131 space = isl_space_align_params(space, isl_set_get_space(stmt->domain));
2132 space = isl_space_align_params(space,
2133 isl_map_get_space(stmt->schedule));
2134 for (i = 0; i < stmt->n_arg; ++i)
2135 if (pet_expr_foreach_access_expr(stmt->args[i],
2136 &access_collect_params, &space) < 0)
2137 space = isl_space_free(space);
2138 if (pet_tree_foreach_access_expr(stmt->body, &access_collect_params,
2139 &space) < 0)
2140 space = isl_space_free(space);
2142 return space;
2145 /* Add all parameters in "array" to "space" and return the result.
2147 static __isl_give isl_space *array_collect_params(struct pet_array *array,
2148 __isl_take isl_space *space)
2150 if (!array)
2151 return isl_space_free(space);
2153 space = isl_space_align_params(space,
2154 isl_set_get_space(array->context));
2155 space = isl_space_align_params(space, isl_set_get_space(array->extent));
2157 return space;
2160 /* Add all parameters in "independence" to "space" and return the result.
2162 static __isl_give isl_space *independence_collect_params(
2163 struct pet_independence *independence, __isl_take isl_space *space)
2165 if (!independence)
2166 return isl_space_free(space);
2168 space = isl_space_align_params(space,
2169 isl_union_map_get_space(independence->filter));
2170 space = isl_space_align_params(space,
2171 isl_union_set_get_space(independence->local));
2173 return space;
2176 /* Add all parameters in "scop" to "space" and return the result.
2178 static __isl_give isl_space *scop_collect_params(struct pet_scop *scop,
2179 __isl_take isl_space *space)
2181 int i;
2183 if (!scop)
2184 return isl_space_free(space);
2186 for (i = 0; i < scop->n_array; ++i)
2187 space = array_collect_params(scop->arrays[i], space);
2189 for (i = 0; i < scop->n_stmt; ++i)
2190 space = stmt_collect_params(scop->stmts[i], space);
2192 for (i = 0; i < scop->n_independence; ++i)
2193 space = independence_collect_params(scop->independences[i],
2194 space);
2196 return space;
2199 /* Add all parameters in "space" to the domain, schedule and
2200 * all access relations in "stmt".
2202 static struct pet_stmt *stmt_propagate_params(struct pet_stmt *stmt,
2203 __isl_take isl_space *space)
2205 int i;
2207 if (!stmt)
2208 goto error;
2210 stmt->domain = isl_set_align_params(stmt->domain,
2211 isl_space_copy(space));
2212 stmt->schedule = isl_map_align_params(stmt->schedule,
2213 isl_space_copy(space));
2215 for (i = 0; i < stmt->n_arg; ++i) {
2216 stmt->args[i] = pet_expr_align_params(stmt->args[i],
2217 isl_space_copy(space));
2218 if (!stmt->args[i])
2219 goto error;
2221 stmt->body = pet_tree_align_params(stmt->body, isl_space_copy(space));
2223 if (!stmt->domain || !stmt->schedule || !stmt->body)
2224 goto error;
2226 isl_space_free(space);
2227 return stmt;
2228 error:
2229 isl_space_free(space);
2230 return pet_stmt_free(stmt);
2233 /* Add all parameters in "space" to "array".
2235 static struct pet_array *array_propagate_params(struct pet_array *array,
2236 __isl_take isl_space *space)
2238 if (!array)
2239 goto error;
2241 array->context = isl_set_align_params(array->context,
2242 isl_space_copy(space));
2243 array->extent = isl_set_align_params(array->extent,
2244 isl_space_copy(space));
2245 if (array->value_bounds) {
2246 array->value_bounds = isl_set_align_params(array->value_bounds,
2247 isl_space_copy(space));
2248 if (!array->value_bounds)
2249 goto error;
2252 if (!array->context || !array->extent)
2253 goto error;
2255 isl_space_free(space);
2256 return array;
2257 error:
2258 isl_space_free(space);
2259 return pet_array_free(array);
2262 /* Add all parameters in "space" to "independence".
2264 static struct pet_independence *independence_propagate_params(
2265 struct pet_independence *independence, __isl_take isl_space *space)
2267 if (!independence)
2268 goto error;
2270 independence->filter = isl_union_map_align_params(independence->filter,
2271 isl_space_copy(space));
2272 independence->local = isl_union_set_align_params(independence->local,
2273 isl_space_copy(space));
2274 if (!independence->filter || !independence->local)
2275 goto error;
2277 isl_space_free(space);
2278 return independence;
2279 error:
2280 isl_space_free(space);
2281 return pet_independence_free(independence);
2284 /* Add all parameters in "space" to "scop".
2286 static struct pet_scop *scop_propagate_params(struct pet_scop *scop,
2287 __isl_take isl_space *space)
2289 int i;
2291 if (!scop)
2292 goto error;
2294 for (i = 0; i < scop->n_array; ++i) {
2295 scop->arrays[i] = array_propagate_params(scop->arrays[i],
2296 isl_space_copy(space));
2297 if (!scop->arrays[i])
2298 goto error;
2301 for (i = 0; i < scop->n_stmt; ++i) {
2302 scop->stmts[i] = stmt_propagate_params(scop->stmts[i],
2303 isl_space_copy(space));
2304 if (!scop->stmts[i])
2305 goto error;
2308 for (i = 0; i < scop->n_independence; ++i) {
2309 scop->independences[i] = independence_propagate_params(
2310 scop->independences[i], isl_space_copy(space));
2311 if (!scop->independences[i])
2312 goto error;
2315 isl_space_free(space);
2316 return scop;
2317 error:
2318 isl_space_free(space);
2319 return pet_scop_free(scop);
2322 /* Update all isl_sets and isl_maps in "scop" such that they all
2323 * have the same parameters.
2325 struct pet_scop *pet_scop_align_params(struct pet_scop *scop)
2327 isl_space *space;
2329 if (!scop)
2330 return NULL;
2332 space = isl_set_get_space(scop->context);
2333 space = scop_collect_params(scop, space);
2335 scop->context = isl_set_align_params(scop->context,
2336 isl_space_copy(space));
2337 scop = scop_propagate_params(scop, space);
2339 if (scop && !scop->context)
2340 return pet_scop_free(scop);
2342 return scop;
2345 /* Add the access relation of the access expression "expr" to "accesses" and
2346 * return the result.
2347 * The domain of the access relation is intersected with "domain".
2348 * If "tag" is set, then the access relation is tagged with
2349 * the corresponding reference identifier.
2351 static __isl_give isl_union_map *expr_collect_access(__isl_keep pet_expr *expr,
2352 int tag, __isl_take isl_union_map *accesses, __isl_keep isl_set *domain)
2354 isl_map *access;
2356 access = pet_expr_access_get_may_access(expr);
2357 access = isl_map_intersect_domain(access, isl_set_copy(domain));
2358 if (tag)
2359 access = pet_expr_tag_access(expr, access);
2360 return isl_union_map_add_map(accesses, access);
2363 /* Internal data structure for expr_collect_accesses.
2365 * "read" is set if we want to collect read accesses.
2366 * "write" is set if we want to collect write accesses.
2367 * "must" is set if we only want definite accesses.
2368 * "tag" is set if the access relations should be tagged with
2369 * the corresponding reference identifiers.
2370 * "domain" are constraints on the domain of the access relations.
2371 * "accesses" collects the results.
2373 struct pet_expr_collect_accesses_data {
2374 int read;
2375 int write;
2376 int must;
2377 int tag;
2378 isl_set *domain;
2380 isl_union_map *accesses;
2383 /* Add the access relation of the access expression "expr"
2384 * to data->accesses if the access expression is a read and data->read is set
2385 * and/or it is a write and data->write is set.
2386 * The domains of the access relations are intersected with data->domain.
2387 * If data->tag is set, then the access relations are tagged with
2388 * the corresponding reference identifiers.
2390 * If data->must is set, then we only add the accesses that are definitely
2391 * performed. Otherwise, we add all potential accesses.
2392 * In particular, if the access has any arguments, then if data->must is
2393 * set we currently skip the access completely. If data->must is not set,
2394 * we project out the values of the access arguments.
2396 static int expr_collect_accesses(__isl_keep pet_expr *expr, void *user)
2398 struct pet_expr_collect_accesses_data *data = user;
2399 int i;
2400 isl_id *id;
2401 isl_space *dim;
2403 if (!expr)
2404 return -1;
2406 if (pet_expr_is_affine(expr))
2407 return 0;
2408 if (data->must && expr->n_arg != 0)
2409 return 0;
2411 if ((data->read && expr->acc.read) || (data->write && expr->acc.write))
2412 data->accesses = expr_collect_access(expr, data->tag,
2413 data->accesses, data->domain);
2415 return data->accesses ? 0 : -1;
2418 /* Collect and return all read access relations (if "read" is set)
2419 * and/or all write access relations (if "write" is set) in "stmt".
2420 * If "tag" is set, then the access relations are tagged with
2421 * the corresponding reference identifiers.
2422 * If "kill" is set, then "stmt" is a kill statement and we simply
2423 * add the argument of the kill operation.
2425 * If "must" is set, then we only add the accesses that are definitely
2426 * performed. Otherwise, we add all potential accesses.
2427 * In particular, if the statement has any arguments, then if "must" is
2428 * set we currently skip the statement completely. If "must" is not set,
2429 * we project out the values of the statement arguments.
2430 * If the statement body is not an expression tree, then we cannot
2431 * know for sure if/when the accesses inside the tree are performed.
2432 * We therefore ignore such statements when "must" is set.
2434 static __isl_give isl_union_map *stmt_collect_accesses(struct pet_stmt *stmt,
2435 int read, int write, int kill, int must, int tag,
2436 __isl_take isl_space *dim)
2438 struct pet_expr_collect_accesses_data data = { read, write, must, tag };
2440 if (!stmt)
2441 return NULL;
2443 data.accesses = isl_union_map_empty(dim);
2445 if (must && stmt->n_arg > 0)
2446 return data.accesses;
2447 if (must && pet_tree_get_type(stmt->body) != pet_tree_expr)
2448 return data.accesses;
2450 data.domain = drop_arguments(isl_set_copy(stmt->domain));
2452 if (kill) {
2453 pet_expr *body, *arg;
2455 body = pet_tree_expr_get_expr(stmt->body);
2456 arg = pet_expr_get_arg(body, 0);
2457 data.accesses = expr_collect_access(arg, tag,
2458 data.accesses, data.domain);
2459 pet_expr_free(arg);
2460 pet_expr_free(body);
2461 } else if (pet_tree_foreach_access_expr(stmt->body,
2462 &expr_collect_accesses, &data) < 0)
2463 data.accesses = isl_union_map_free(data.accesses);
2465 isl_set_free(data.domain);
2467 return data.accesses;
2470 /* Is "stmt" an assignment statement?
2472 int pet_stmt_is_assign(struct pet_stmt *stmt)
2474 if (!stmt)
2475 return 0;
2476 return pet_tree_is_assign(stmt->body);
2479 /* Is "stmt" a kill statement?
2481 int pet_stmt_is_kill(struct pet_stmt *stmt)
2483 if (!stmt)
2484 return 0;
2485 return pet_tree_is_kill(stmt->body);
2488 /* Is "stmt" an assume statement?
2490 int pet_stmt_is_assume(struct pet_stmt *stmt)
2492 if (!stmt)
2493 return 0;
2494 return pet_tree_is_assume(stmt->body);
2497 /* Helper function to add a domain gisted copy of "map" (wrt "set") to "umap".
2499 static __isl_give isl_union_map *add_gisted(__isl_take isl_union_map *umap,
2500 __isl_keep isl_map *map, __isl_keep isl_set *set)
2502 isl_map *gist;
2504 gist = isl_map_copy(map);
2505 gist = isl_map_gist_domain(gist, isl_set_copy(set));
2506 return isl_union_map_add_map(umap, gist);
2509 /* Compute a mapping from all arrays (of structs) in scop
2510 * to their members.
2512 * If "from_outermost" is set, then the domain only consists
2513 * of outermost arrays.
2514 * If "to_innermost" is set, then the range only consists
2515 * of innermost arrays.
2517 static __isl_give isl_union_map *compute_to_inner(struct pet_scop *scop,
2518 int from_outermost, int to_innermost)
2520 int i;
2521 isl_union_map *to_inner;
2523 if (!scop)
2524 return NULL;
2526 to_inner = isl_union_map_empty(isl_set_get_space(scop->context));
2528 for (i = 0; i < scop->n_array; ++i) {
2529 struct pet_array *array = scop->arrays[i];
2530 isl_set *set;
2531 isl_map *map;
2533 if (to_innermost && array->element_is_record)
2534 continue;
2536 set = isl_set_copy(array->extent);
2537 map = isl_set_identity(isl_set_copy(set));
2539 while (set && isl_set_is_wrapping(set)) {
2540 isl_id *id;
2541 isl_map *wrapped;
2543 if (!from_outermost)
2544 to_inner = add_gisted(to_inner, map, set);
2546 id = isl_set_get_tuple_id(set);
2547 wrapped = isl_set_unwrap(set);
2548 wrapped = isl_map_domain_map(wrapped);
2549 wrapped = isl_map_set_tuple_id(wrapped, isl_dim_in, id);
2550 map = isl_map_apply_domain(map, wrapped);
2551 set = isl_map_domain(isl_map_copy(map));
2554 map = isl_map_gist_domain(map, set);
2555 to_inner = isl_union_map_add_map(to_inner, map);
2558 return to_inner;
2561 /* Compute a mapping from all arrays (of structs) in scop
2562 * to their innermost arrays.
2564 * In particular, for each array of a primitive type, the result
2565 * contains the identity mapping on that array.
2566 * For each array involving member accesses, the result
2567 * contains a mapping from the elements of any intermediate array of structs
2568 * to all corresponding elements of the innermost nested arrays.
2570 static __isl_give isl_union_map *pet_scop_compute_any_to_inner(
2571 struct pet_scop *scop)
2573 return compute_to_inner(scop, 0, 1);
2576 /* Compute a mapping from all outermost arrays (of structs) in scop
2577 * to their innermost members.
2579 __isl_give isl_union_map *pet_scop_compute_outer_to_inner(struct pet_scop *scop)
2581 return compute_to_inner(scop, 1, 1);
2584 /* Compute a mapping from all outermost arrays (of structs) in scop
2585 * to their members, including the outermost arrays themselves.
2587 __isl_give isl_union_map *pet_scop_compute_outer_to_any(struct pet_scop *scop)
2589 return compute_to_inner(scop, 1, 0);
2592 /* Collect and return all read access relations (if "read" is set)
2593 * and/or all write access relations (if "write" is set) in "scop".
2594 * If "kill" is set, then we only add the arguments of kill operations.
2595 * If "must" is set, then we only add the accesses that are definitely
2596 * performed. Otherwise, we add all potential accesses.
2597 * If "tag" is set, then the access relations are tagged with
2598 * the corresponding reference identifiers.
2599 * For accesses to structures, the returned access relation accesses
2600 * all individual fields in the structures.
2602 static __isl_give isl_union_map *scop_collect_accesses(struct pet_scop *scop,
2603 int read, int write, int kill, int must, int tag)
2605 int i;
2606 isl_union_map *accesses;
2607 isl_union_set *arrays;
2608 isl_union_map *to_inner;
2610 if (!scop)
2611 return NULL;
2613 accesses = isl_union_map_empty(isl_set_get_space(scop->context));
2615 for (i = 0; i < scop->n_stmt; ++i) {
2616 struct pet_stmt *stmt = scop->stmts[i];
2617 isl_union_map *accesses_i;
2618 isl_space *space;
2620 if (kill && !pet_stmt_is_kill(stmt))
2621 continue;
2623 space = isl_set_get_space(scop->context);
2624 accesses_i = stmt_collect_accesses(stmt, read, write, kill,
2625 must, tag, space);
2626 accesses = isl_union_map_union(accesses, accesses_i);
2629 arrays = isl_union_set_empty(isl_union_map_get_space(accesses));
2630 for (i = 0; i < scop->n_array; ++i) {
2631 isl_set *extent = isl_set_copy(scop->arrays[i]->extent);
2632 arrays = isl_union_set_add_set(arrays, extent);
2634 accesses = isl_union_map_intersect_range(accesses, arrays);
2636 to_inner = pet_scop_compute_any_to_inner(scop);
2637 accesses = isl_union_map_apply_range(accesses, to_inner);
2639 return accesses;
2642 /* Collect all potential read access relations.
2644 __isl_give isl_union_map *pet_scop_collect_may_reads(struct pet_scop *scop)
2646 return scop_collect_accesses(scop, 1, 0, 0, 0, 0);
2649 /* Collect all potential write access relations.
2651 __isl_give isl_union_map *pet_scop_collect_may_writes(struct pet_scop *scop)
2653 return scop_collect_accesses(scop, 0, 1, 0, 0, 0);
2656 /* Collect all definite write access relations.
2658 __isl_give isl_union_map *pet_scop_collect_must_writes(struct pet_scop *scop)
2660 return scop_collect_accesses(scop, 0, 1, 0, 1, 0);
2663 /* Collect all definite kill access relations.
2665 __isl_give isl_union_map *pet_scop_collect_must_kills(struct pet_scop *scop)
2667 return scop_collect_accesses(scop, 0, 0, 1, 1, 0);
2670 /* Collect all tagged potential read access relations.
2672 __isl_give isl_union_map *pet_scop_collect_tagged_may_reads(
2673 struct pet_scop *scop)
2675 return scop_collect_accesses(scop, 1, 0, 0, 0, 1);
2678 /* Collect all tagged potential write access relations.
2680 __isl_give isl_union_map *pet_scop_collect_tagged_may_writes(
2681 struct pet_scop *scop)
2683 return scop_collect_accesses(scop, 0, 1, 0, 0, 1);
2686 /* Collect all tagged definite write access relations.
2688 __isl_give isl_union_map *pet_scop_collect_tagged_must_writes(
2689 struct pet_scop *scop)
2691 return scop_collect_accesses(scop, 0, 1, 0, 1, 1);
2694 /* Collect all tagged definite kill access relations.
2696 __isl_give isl_union_map *pet_scop_collect_tagged_must_kills(
2697 struct pet_scop *scop)
2699 return scop_collect_accesses(scop, 0, 0, 1, 1, 1);
2702 /* Collect and return the union of iteration domains in "scop".
2704 __isl_give isl_union_set *pet_scop_collect_domains(struct pet_scop *scop)
2706 int i;
2707 isl_set *domain_i;
2708 isl_union_set *domain;
2710 if (!scop)
2711 return NULL;
2713 domain = isl_union_set_empty(isl_set_get_space(scop->context));
2715 for (i = 0; i < scop->n_stmt; ++i) {
2716 domain_i = isl_set_copy(scop->stmts[i]->domain);
2717 domain = isl_union_set_add_set(domain, domain_i);
2720 return domain;
2723 /* Collect and return the schedules of the statements in "scop".
2724 * The range is normalized to the maximal number of scheduling
2725 * dimensions.
2727 __isl_give isl_union_map *pet_scop_collect_schedule(struct pet_scop *scop)
2729 int i, j;
2730 isl_map *schedule_i;
2731 isl_union_map *schedule;
2732 int depth, max_depth = 0;
2734 if (!scop)
2735 return NULL;
2737 schedule = isl_union_map_empty(isl_set_get_space(scop->context));
2739 for (i = 0; i < scop->n_stmt; ++i) {
2740 depth = isl_map_dim(scop->stmts[i]->schedule, isl_dim_out);
2741 if (depth > max_depth)
2742 max_depth = depth;
2745 for (i = 0; i < scop->n_stmt; ++i) {
2746 schedule_i = isl_map_copy(scop->stmts[i]->schedule);
2747 depth = isl_map_dim(schedule_i, isl_dim_out);
2748 schedule_i = isl_map_add_dims(schedule_i, isl_dim_out,
2749 max_depth - depth);
2750 for (j = depth; j < max_depth; ++j)
2751 schedule_i = isl_map_fix_si(schedule_i,
2752 isl_dim_out, j, 0);
2753 schedule = isl_union_map_add_map(schedule, schedule_i);
2756 return schedule;
2759 /* Add a reference identifier to all access expressions in "stmt".
2760 * "n_ref" points to an integer that contains the sequence number
2761 * of the next reference.
2763 static struct pet_stmt *stmt_add_ref_ids(struct pet_stmt *stmt, int *n_ref)
2765 int i;
2767 if (!stmt)
2768 return NULL;
2770 for (i = 0; i < stmt->n_arg; ++i) {
2771 stmt->args[i] = pet_expr_add_ref_ids(stmt->args[i], n_ref);
2772 if (!stmt->args[i])
2773 return pet_stmt_free(stmt);
2776 stmt->body = pet_tree_add_ref_ids(stmt->body, n_ref);
2777 if (!stmt->body)
2778 return pet_stmt_free(stmt);
2780 return stmt;
2783 /* Add a reference identifier to all access expressions in "scop".
2785 struct pet_scop *pet_scop_add_ref_ids(struct pet_scop *scop)
2787 int i;
2788 int n_ref;
2790 if (!scop)
2791 return NULL;
2793 n_ref = 0;
2794 for (i = 0; i < scop->n_stmt; ++i) {
2795 scop->stmts[i] = stmt_add_ref_ids(scop->stmts[i], &n_ref);
2796 if (!scop->stmts[i])
2797 return pet_scop_free(scop);
2800 return scop;
2803 /* Reset the user pointer on all parameter ids in "array".
2805 static struct pet_array *array_anonymize(struct pet_array *array)
2807 if (!array)
2808 return NULL;
2810 array->context = isl_set_reset_user(array->context);
2811 array->extent = isl_set_reset_user(array->extent);
2812 if (!array->context || !array->extent)
2813 return pet_array_free(array);
2815 return array;
2818 /* Reset the user pointer on all parameter and tuple ids in "stmt".
2820 static struct pet_stmt *stmt_anonymize(struct pet_stmt *stmt)
2822 int i;
2823 isl_space *space;
2824 isl_set *domain;
2826 if (!stmt)
2827 return NULL;
2829 stmt->domain = isl_set_reset_user(stmt->domain);
2830 stmt->schedule = isl_map_reset_user(stmt->schedule);
2831 if (!stmt->domain || !stmt->schedule)
2832 return pet_stmt_free(stmt);
2834 for (i = 0; i < stmt->n_arg; ++i) {
2835 stmt->args[i] = pet_expr_anonymize(stmt->args[i]);
2836 if (!stmt->args[i])
2837 return pet_stmt_free(stmt);
2840 stmt->body = pet_tree_anonymize(stmt->body);
2841 if (!stmt->body)
2842 return pet_stmt_free(stmt);
2844 return stmt;
2847 /* Reset the user pointer on the tuple ids and all parameter ids
2848 * in "implication".
2850 static struct pet_implication *implication_anonymize(
2851 struct pet_implication *implication)
2853 if (!implication)
2854 return NULL;
2856 implication->extension = isl_map_reset_user(implication->extension);
2857 if (!implication->extension)
2858 return pet_implication_free(implication);
2860 return implication;
2863 /* Reset the user pointer on the tuple ids and all parameter ids
2864 * in "independence".
2866 static struct pet_independence *independence_anonymize(
2867 struct pet_independence *independence)
2869 if (!independence)
2870 return NULL;
2872 independence->filter = isl_union_map_reset_user(independence->filter);
2873 independence->local = isl_union_set_reset_user(independence->local);
2874 if (!independence->filter || !independence->local)
2875 return pet_independence_free(independence);
2877 return independence;
2880 /* Reset the user pointer on all parameter and tuple ids in "scop".
2882 struct pet_scop *pet_scop_anonymize(struct pet_scop *scop)
2884 int i;
2886 if (!scop)
2887 return NULL;
2889 scop->context = isl_set_reset_user(scop->context);
2890 scop->context_value = isl_set_reset_user(scop->context_value);
2891 if (!scop->context || !scop->context_value)
2892 return pet_scop_free(scop);
2894 for (i = 0; i < scop->n_array; ++i) {
2895 scop->arrays[i] = array_anonymize(scop->arrays[i]);
2896 if (!scop->arrays[i])
2897 return pet_scop_free(scop);
2900 for (i = 0; i < scop->n_stmt; ++i) {
2901 scop->stmts[i] = stmt_anonymize(scop->stmts[i]);
2902 if (!scop->stmts[i])
2903 return pet_scop_free(scop);
2906 for (i = 0; i < scop->n_implication; ++i) {
2907 scop->implications[i] =
2908 implication_anonymize(scop->implications[i]);
2909 if (!scop->implications[i])
2910 return pet_scop_free(scop);
2913 for (i = 0; i < scop->n_independence; ++i) {
2914 scop->independences[i] =
2915 independence_anonymize(scop->independences[i]);
2916 if (!scop->independences[i])
2917 return pet_scop_free(scop);
2920 return scop;
2923 /* Compute the gist of the iteration domain and all access relations
2924 * of "stmt" based on the constraints on the parameters specified by "context"
2925 * and the constraints on the values of nested accesses specified
2926 * by "value_bounds".
2928 static struct pet_stmt *stmt_gist(struct pet_stmt *stmt,
2929 __isl_keep isl_set *context, __isl_keep isl_union_map *value_bounds)
2931 int i;
2932 isl_set *domain;
2934 if (!stmt)
2935 return NULL;
2937 domain = isl_set_copy(stmt->domain);
2938 if (stmt->n_arg > 0)
2939 domain = isl_map_domain(isl_set_unwrap(domain));
2941 domain = isl_set_intersect_params(domain, isl_set_copy(context));
2943 for (i = 0; i < stmt->n_arg; ++i) {
2944 stmt->args[i] = pet_expr_gist(stmt->args[i],
2945 domain, value_bounds);
2946 if (!stmt->args[i])
2947 goto error;
2950 stmt->body = pet_tree_gist(stmt->body, domain, value_bounds);
2951 if (!stmt->body)
2952 goto error;
2954 isl_set_free(domain);
2956 domain = isl_set_universe(pet_stmt_get_space(stmt));
2957 domain = isl_set_intersect_params(domain, isl_set_copy(context));
2958 if (stmt->n_arg > 0)
2959 domain = pet_value_bounds_apply(domain, stmt->n_arg, stmt->args,
2960 value_bounds);
2961 stmt->domain = isl_set_gist(stmt->domain, domain);
2962 if (!stmt->domain)
2963 return pet_stmt_free(stmt);
2965 return stmt;
2966 error:
2967 isl_set_free(domain);
2968 return pet_stmt_free(stmt);
2971 /* Compute the gist of the extent of the array
2972 * based on the constraints on the parameters specified by "context".
2974 static struct pet_array *array_gist(struct pet_array *array,
2975 __isl_keep isl_set *context)
2977 if (!array)
2978 return NULL;
2980 array->extent = isl_set_gist_params(array->extent,
2981 isl_set_copy(context));
2982 if (!array->extent)
2983 return pet_array_free(array);
2985 return array;
2988 /* Compute the gist of all sets and relations in "scop"
2989 * based on the constraints on the parameters specified by "scop->context"
2990 * and the constraints on the values of nested accesses specified
2991 * by "value_bounds".
2993 struct pet_scop *pet_scop_gist(struct pet_scop *scop,
2994 __isl_keep isl_union_map *value_bounds)
2996 int i;
2998 if (!scop)
2999 return NULL;
3001 scop->context = isl_set_coalesce(scop->context);
3002 if (!scop->context)
3003 return pet_scop_free(scop);
3005 for (i = 0; i < scop->n_array; ++i) {
3006 scop->arrays[i] = array_gist(scop->arrays[i], scop->context);
3007 if (!scop->arrays[i])
3008 return pet_scop_free(scop);
3011 for (i = 0; i < scop->n_stmt; ++i) {
3012 scop->stmts[i] = stmt_gist(scop->stmts[i], scop->context,
3013 value_bounds);
3014 if (!scop->stmts[i])
3015 return pet_scop_free(scop);
3018 return scop;
3021 /* Intersect the context of "scop" with "context".
3022 * To ensure that we don't introduce any unnamed parameters in
3023 * the context of "scop", we first remove the unnamed parameters
3024 * from "context".
3026 struct pet_scop *pet_scop_restrict_context(struct pet_scop *scop,
3027 __isl_take isl_set *context)
3029 if (!scop)
3030 goto error;
3032 context = pet_nested_remove_from_set(context);
3033 scop->context = isl_set_intersect(scop->context, context);
3034 if (!scop->context)
3035 return pet_scop_free(scop);
3037 return scop;
3038 error:
3039 isl_set_free(context);
3040 return pet_scop_free(scop);
3043 /* Drop the current context of "scop". That is, replace the context
3044 * by a universal set.
3046 struct pet_scop *pet_scop_reset_context(struct pet_scop *scop)
3048 isl_space *space;
3050 if (!scop)
3051 return NULL;
3053 space = isl_set_get_space(scop->context);
3054 isl_set_free(scop->context);
3055 scop->context = isl_set_universe(space);
3056 if (!scop->context)
3057 return pet_scop_free(scop);
3059 return scop;
3062 /* Append "array" to the arrays of "scop".
3064 struct pet_scop *pet_scop_add_array(struct pet_scop *scop,
3065 struct pet_array *array)
3067 isl_ctx *ctx;
3068 struct pet_array **arrays;
3070 if (!array || !scop)
3071 goto error;
3073 ctx = isl_set_get_ctx(scop->context);
3074 arrays = isl_realloc_array(ctx, scop->arrays, struct pet_array *,
3075 scop->n_array + 1);
3076 if (!arrays)
3077 goto error;
3078 scop->arrays = arrays;
3079 scop->arrays[scop->n_array] = array;
3080 scop->n_array++;
3082 return scop;
3083 error:
3084 pet_array_free(array);
3085 return pet_scop_free(scop);
3088 /* Create an index expression for an access to a virtual array
3089 * representing the result of a condition.
3090 * Unlike other accessed data, the id of the array is NULL as
3091 * there is no ValueDecl in the program corresponding to the virtual
3092 * array.
3093 * The index expression is created as an identity mapping on "space".
3094 * That is, the dimension of the array is the same as that of "space".
3096 __isl_give isl_multi_pw_aff *pet_create_test_index(__isl_take isl_space *space,
3097 int test_nr)
3099 isl_id *id;
3100 char name[50];
3102 snprintf(name, sizeof(name), "__pet_test_%d", test_nr);
3103 id = isl_id_alloc(isl_space_get_ctx(space), name, NULL);
3104 space = isl_space_map_from_set(space);
3105 space = isl_space_set_tuple_id(space, isl_dim_out, id);
3106 return isl_multi_pw_aff_identity(space);
3109 /* Add an array with the given extent to the list
3110 * of arrays in "scop" and return the extended pet_scop.
3111 * Specifically, the extent is determined by the image of "domain"
3112 * under "index".
3113 * "int_size" is the number of bytes needed to represent values of type "int".
3114 * The array is marked as attaining values 0 and 1 only and
3115 * as each element being assigned at most once.
3117 struct pet_scop *pet_scop_add_boolean_array(struct pet_scop *scop,
3118 __isl_take isl_set *domain, __isl_take isl_multi_pw_aff *index,
3119 int int_size)
3121 isl_ctx *ctx;
3122 isl_space *space;
3123 struct pet_array *array;
3124 isl_map *access;
3126 if (!scop || !domain || !index)
3127 goto error;
3129 ctx = isl_multi_pw_aff_get_ctx(index);
3130 array = isl_calloc_type(ctx, struct pet_array);
3131 if (!array)
3132 goto error;
3134 access = isl_map_from_multi_pw_aff(index);
3135 access = isl_map_intersect_domain(access, domain);
3136 array->extent = isl_map_range(access);
3137 space = isl_space_params_alloc(ctx, 0);
3138 array->context = isl_set_universe(space);
3139 space = isl_space_set_alloc(ctx, 0, 1);
3140 array->value_bounds = isl_set_universe(space);
3141 array->value_bounds = isl_set_lower_bound_si(array->value_bounds,
3142 isl_dim_set, 0, 0);
3143 array->value_bounds = isl_set_upper_bound_si(array->value_bounds,
3144 isl_dim_set, 0, 1);
3145 array->element_type = strdup("int");
3146 array->element_size = int_size;
3147 array->uniquely_defined = 1;
3149 if (!array->extent || !array->context)
3150 array = pet_array_free(array);
3152 scop = pet_scop_add_array(scop, array);
3154 return scop;
3155 error:
3156 isl_set_free(domain);
3157 isl_multi_pw_aff_free(index);
3158 return pet_scop_free(scop);
3161 /* Create and return an implication on filter values equal to "satisfied"
3162 * with extension "map".
3164 static struct pet_implication *new_implication(__isl_take isl_map *map,
3165 int satisfied)
3167 isl_ctx *ctx;
3168 struct pet_implication *implication;
3170 if (!map)
3171 return NULL;
3172 ctx = isl_map_get_ctx(map);
3173 implication = isl_alloc_type(ctx, struct pet_implication);
3174 if (!implication)
3175 goto error;
3177 implication->extension = map;
3178 implication->satisfied = satisfied;
3180 return implication;
3181 error:
3182 isl_map_free(map);
3183 return NULL;
3186 /* Add an implication on filter values equal to "satisfied"
3187 * with extension "map" to "scop".
3189 struct pet_scop *pet_scop_add_implication(struct pet_scop *scop,
3190 __isl_take isl_map *map, int satisfied)
3192 isl_ctx *ctx;
3193 struct pet_implication *implication;
3194 struct pet_implication **implications;
3196 implication = new_implication(map, satisfied);
3197 if (!scop || !implication)
3198 goto error;
3200 ctx = isl_set_get_ctx(scop->context);
3201 implications = isl_realloc_array(ctx, scop->implications,
3202 struct pet_implication *,
3203 scop->n_implication + 1);
3204 if (!implications)
3205 goto error;
3206 scop->implications = implications;
3207 scop->implications[scop->n_implication] = implication;
3208 scop->n_implication++;
3210 return scop;
3211 error:
3212 pet_implication_free(implication);
3213 return pet_scop_free(scop);
3216 /* Create and return a function that maps the iteration domains
3217 * of the statements in "scop" onto their outer "n" dimensions.
3218 * "space" is the parameters space of the created function.
3220 static __isl_give isl_union_pw_multi_aff *outer_projection(
3221 struct pet_scop *scop, __isl_take isl_space *space, int n)
3223 int i;
3224 isl_union_pw_multi_aff *res;
3226 res = isl_union_pw_multi_aff_empty(space);
3228 if (!scop)
3229 return isl_union_pw_multi_aff_free(res);
3231 for (i = 0; i < scop->n_stmt; ++i) {
3232 struct pet_stmt *stmt = scop->stmts[i];
3233 isl_space *space;
3234 isl_multi_aff *ma;
3235 isl_pw_multi_aff *pma;
3237 space = pet_stmt_get_space(stmt);
3238 ma = pet_prefix_projection(space, n);
3239 pma = isl_pw_multi_aff_from_multi_aff(ma);
3240 res = isl_union_pw_multi_aff_add_pw_multi_aff(res, pma);
3243 return res;
3246 /* Add an independence to "scop" for the inner iterator of "domain"
3247 * with local variables "local", where "domain" represents the outer
3248 * loop iterators of all statements in "scop".
3249 * If "sign" is positive, then the inner iterator increases.
3250 * Otherwise it decreases.
3252 * The independence is supposed to filter out any dependence of
3253 * an iteration of domain on a previous iteration along the inner dimension.
3254 * We therefore create a mapping from an iteration to later iterations and
3255 * then plug in the projection of the iterations domains of "scop"
3256 * onto the outer loop iterators.
3258 struct pet_scop *pet_scop_set_independent(struct pet_scop *scop,
3259 __isl_keep isl_set *domain, __isl_take isl_union_set *local, int sign)
3261 int i, dim;
3262 isl_space *space;
3263 isl_map *map;
3264 isl_union_map *independence;
3265 isl_union_pw_multi_aff *proj;
3267 if (!scop || !domain || !local)
3268 goto error;
3270 dim = isl_set_dim(domain, isl_dim_set);
3271 space = isl_space_map_from_set(isl_set_get_space(domain));
3272 map = isl_map_universe(space);
3273 for (i = 0; i + 1 < dim; ++i)
3274 map = isl_map_equate(map, isl_dim_in, i, isl_dim_out, i);
3275 if (sign > 0)
3276 map = isl_map_order_lt(map,
3277 isl_dim_in, dim - 1, isl_dim_out, dim - 1);
3278 else
3279 map = isl_map_order_gt(map,
3280 isl_dim_in, dim - 1, isl_dim_out, dim - 1);
3282 independence = isl_union_map_from_map(map);
3283 space = isl_space_params(isl_set_get_space(domain));
3284 proj = outer_projection(scop, space, dim);
3285 independence = isl_union_map_preimage_domain_union_pw_multi_aff(
3286 independence, isl_union_pw_multi_aff_copy(proj));
3287 independence = isl_union_map_preimage_range_union_pw_multi_aff(
3288 independence, proj);
3290 scop = pet_scop_add_independence(scop, independence, local);
3292 return scop;
3293 error:
3294 isl_union_set_free(local);
3295 return pet_scop_free(scop);
3298 /* Given an access expression, check if it is data dependent.
3299 * If so, set *found and abort the search.
3301 static int is_data_dependent(__isl_keep pet_expr *expr, void *user)
3303 int *found = user;
3305 if (pet_expr_get_n_arg(expr) > 0) {
3306 *found = 1;
3307 return -1;
3310 return 0;
3313 /* Does "scop" contain any data dependent accesses?
3315 * Check the body of each statement for such accesses.
3317 int pet_scop_has_data_dependent_accesses(struct pet_scop *scop)
3319 int i;
3320 int found = 0;
3322 if (!scop)
3323 return -1;
3325 for (i = 0; i < scop->n_stmt; ++i) {
3326 int r = pet_tree_foreach_access_expr(scop->stmts[i]->body,
3327 &is_data_dependent, &found);
3328 if (r < 0 && !found)
3329 return -1;
3330 if (found)
3331 return found;
3334 return found;
3337 /* Does "scop" contain and data dependent conditions?
3339 int pet_scop_has_data_dependent_conditions(struct pet_scop *scop)
3341 int i;
3343 if (!scop)
3344 return -1;
3346 for (i = 0; i < scop->n_stmt; ++i)
3347 if (scop->stmts[i]->n_arg > 0)
3348 return 1;
3350 return 0;
3353 /* Keep track of the "input" file inside the (extended) "scop".
3355 struct pet_scop *pet_scop_set_input_file(struct pet_scop *scop, FILE *input)
3357 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
3359 if (!scop)
3360 return NULL;
3362 ext->input = input;
3364 return scop;
3367 /* Print the original code corresponding to "scop" to printer "p".
3369 * pet_scop_print_original can only be called from
3370 * a pet_transform_C_source callback. This means that the input
3371 * file is stored in the extended scop and that the printer prints
3372 * to a file.
3374 __isl_give isl_printer *pet_scop_print_original(struct pet_scop *scop,
3375 __isl_take isl_printer *p)
3377 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
3378 FILE *output;
3379 unsigned start, end;
3381 if (!scop || !p)
3382 return isl_printer_free(p);
3384 if (!ext->input)
3385 isl_die(isl_printer_get_ctx(p), isl_error_invalid,
3386 "no input file stored in scop",
3387 return isl_printer_free(p));
3389 output = isl_printer_get_file(p);
3390 if (!output)
3391 return isl_printer_free(p);
3393 start = pet_loc_get_start(scop->loc);
3394 end = pet_loc_get_end(scop->loc);
3395 if (copy(ext->input, output, start, end) < 0)
3396 return isl_printer_free(p);
3398 return p;