pet_extract_nested_from_space: embed arguments in given space
[pet.git] / scop.c
blobd622e7a80e03a362d0fe94d043495b3954757c80
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 "print.h"
46 #include "value_bounds.h"
48 /* pet_scop with extra information that is used during parsing and printing.
50 * In particular, we keep track of conditions under which we want
51 * to skip the rest of the current loop iteration (skip[pet_skip_now])
52 * and of conditions under which we want to skip subsequent
53 * loop iterations (skip[pet_skip_later]).
55 * The conditions are represented as index expressions defined
56 * over a zero-dimensional domain. The index expression is either
57 * a boolean affine expression or an access to a variable, which
58 * is assumed to attain values zero and one. The condition holds
59 * if the variable has value one or if the affine expression
60 * has value one (typically for only part of the parameter space).
62 * A missing condition (skip[type] == NULL) means that we don't want
63 * to skip anything.
65 * Additionally, we keep track of the original input file
66 * inside pet_transform_C_source.
68 struct pet_scop_ext {
69 struct pet_scop scop;
71 isl_multi_pw_aff *skip[2];
72 FILE *input;
75 /* Construct a pet_stmt with given domain, location and statement
76 * number from a pet_expr.
77 * The input domain is anonymous and is the same as the domains
78 * of the access expressions inside "expr".
79 * These domains are modified to include the name of the statement.
80 * This name is given by "label" if it is non-NULL.
81 * Otherwise, the name is constructed as S_<id>.
83 struct pet_stmt *pet_stmt_from_pet_expr(__isl_take isl_set *domain,
84 __isl_take pet_loc *loc, __isl_take isl_id *label, int id,
85 __isl_take pet_expr *expr)
87 struct pet_stmt *stmt;
88 isl_ctx *ctx;
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 || !loc || !expr)
96 goto error;
98 ctx = pet_expr_get_ctx(expr);
99 stmt = isl_calloc_type(ctx, struct pet_stmt);
100 if (!stmt)
101 goto error;
103 if (!label) {
104 snprintf(name, sizeof(name), "S_%d", id);
105 label = isl_id_alloc(ctx, name, NULL);
107 domain = isl_set_set_tuple_id(domain, label);
108 space = isl_set_get_space(domain);
109 space = pet_nested_remove_from_space(space);
110 sched = isl_map_universe(isl_space_from_domain(isl_space_copy(space)));
111 ma = pet_prefix_projection(space, isl_space_dim(space, isl_dim_set));
113 add_name = isl_multi_pw_aff_from_multi_aff(ma);
114 expr = pet_expr_update_domain(expr, add_name);
116 stmt->loc = loc;
117 stmt->domain = domain;
118 stmt->schedule = sched;
119 stmt->body = expr;
121 if (!stmt->domain || !stmt->schedule || !stmt->body)
122 return pet_stmt_free(stmt);
124 return stmt;
125 error:
126 isl_set_free(domain);
127 isl_id_free(label);
128 pet_loc_free(loc);
129 pet_expr_free(expr);
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_expr_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_expr_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 * We currently only take into account the parameters 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 space = isl_space_params(space);
286 scop->context = isl_set_universe(isl_space_copy(space));
287 scop->context_value = isl_set_universe(space);
288 scop->stmts = isl_calloc_array(ctx, struct pet_stmt *, n);
289 if (!scop->context || !scop->stmts)
290 return pet_scop_free(scop);
292 scop->loc = &pet_loc_dummy;
293 scop->n_stmt = n;
295 return scop;
298 /* Construct a pet_scop in the given space containing 0 statements.
300 struct pet_scop *pet_scop_empty(__isl_take isl_space *space)
302 return scop_alloc(space, 0);
305 /* Update "context" with respect to the valid parameter values for "access".
307 static __isl_give isl_set *access_extract_context(__isl_keep isl_map *access,
308 __isl_take isl_set *context)
310 context = isl_set_intersect(context,
311 isl_map_params(isl_map_copy(access)));
312 return context;
315 /* Update "context" with respect to the valid parameter values for "expr".
317 * If "expr" represents a conditional operator, then a parameter value
318 * needs to be valid for the condition and for at least one of the
319 * remaining two arguments.
320 * If the condition is an affine expression, then we can be a bit more specific.
321 * The parameter then has to be valid for the second argument for
322 * non-zero accesses and valid for the third argument for zero accesses.
324 static __isl_give isl_set *expr_extract_context(__isl_keep pet_expr *expr,
325 __isl_take isl_set *context)
327 int i;
329 if (expr->type == pet_expr_op && expr->op == pet_op_cond) {
330 int is_aff;
331 isl_set *context1, *context2;
333 is_aff = pet_expr_is_affine(expr->args[0]);
334 if (is_aff < 0)
335 goto error;
337 context = expr_extract_context(expr->args[0], context);
338 context1 = expr_extract_context(expr->args[1],
339 isl_set_copy(context));
340 context2 = expr_extract_context(expr->args[2], context);
342 if (is_aff) {
343 isl_map *access;
344 isl_set *zero_set;
346 access = isl_map_copy(expr->args[0]->acc.access);
347 access = isl_map_fix_si(access, isl_dim_out, 0, 0);
348 zero_set = isl_map_params(access);
349 context1 = isl_set_subtract(context1,
350 isl_set_copy(zero_set));
351 context2 = isl_set_intersect(context2, zero_set);
354 context = isl_set_union(context1, context2);
355 context = isl_set_coalesce(context);
357 return context;
360 for (i = 0; i < expr->n_arg; ++i)
361 context = expr_extract_context(expr->args[i], context);
363 if (expr->type == pet_expr_access)
364 context = access_extract_context(expr->acc.access, context);
366 return context;
367 error:
368 isl_set_free(context);
369 return NULL;
372 /* Update "context" with respect to the valid parameter values for "stmt".
374 * If the statement is an assume statement with an affine expression,
375 * then intersect "context" with that expression.
376 * Otherwise, intersect "context" with the contexts of the expressions
377 * inside "stmt".
379 static __isl_give isl_set *stmt_extract_context(struct pet_stmt *stmt,
380 __isl_take isl_set *context)
382 int i;
384 if (pet_stmt_is_assume(stmt) &&
385 pet_expr_is_affine(stmt->body->args[0])) {
386 isl_multi_pw_aff *index;
387 isl_pw_aff *pa;
388 isl_set *cond;
390 index = stmt->body->args[0]->acc.index;
391 pa = isl_multi_pw_aff_get_pw_aff(index, 0);
392 cond = isl_set_params(isl_pw_aff_non_zero_set(pa));
393 return isl_set_intersect(context, cond);
396 for (i = 0; i < stmt->n_arg; ++i)
397 context = expr_extract_context(stmt->args[i], context);
399 context = expr_extract_context(stmt->body, context);
401 return context;
404 /* Construct a pet_scop in the given space that contains the given pet_stmt.
406 struct pet_scop *pet_scop_from_pet_stmt(__isl_take isl_space *space,
407 struct pet_stmt *stmt)
409 struct pet_scop *scop;
411 if (!stmt)
412 space = isl_space_free(space);
414 scop = scop_alloc(space, 1);
415 if (!scop)
416 goto error;
418 scop->context = stmt_extract_context(stmt, scop->context);
419 if (!scop->context)
420 goto error;
422 scop->stmts[0] = stmt;
423 scop->loc = pet_loc_copy(stmt->loc);
425 if (!scop->loc)
426 return pet_scop_free(scop);
428 return scop;
429 error:
430 pet_stmt_free(stmt);
431 pet_scop_free(scop);
432 return NULL;
435 /* Does "mpa" represent an access to an element of an unnamed space, i.e.,
436 * does it represent an affine expression?
438 static int multi_pw_aff_is_affine(__isl_keep isl_multi_pw_aff *mpa)
440 int has_id;
442 has_id = isl_multi_pw_aff_has_tuple_id(mpa, isl_dim_out);
443 if (has_id < 0)
444 return -1;
446 return !has_id;
449 /* Return the piecewise affine expression "set ? 1 : 0" defined on "dom".
451 static __isl_give isl_pw_aff *indicator_function(__isl_take isl_set *set,
452 __isl_take isl_set *dom)
454 isl_pw_aff *pa;
455 pa = isl_set_indicator_function(set);
456 pa = isl_pw_aff_intersect_domain(pa, dom);
457 return pa;
460 /* Return "lhs || rhs", defined on the shared definition domain.
462 static __isl_give isl_pw_aff *pw_aff_or(__isl_take isl_pw_aff *lhs,
463 __isl_take isl_pw_aff *rhs)
465 isl_set *cond;
466 isl_set *dom;
468 dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(lhs)),
469 isl_pw_aff_domain(isl_pw_aff_copy(rhs)));
470 cond = isl_set_union(isl_pw_aff_non_zero_set(lhs),
471 isl_pw_aff_non_zero_set(rhs));
472 cond = isl_set_coalesce(cond);
473 return indicator_function(cond, dom);
476 /* Combine ext1->skip[type] and ext2->skip[type] into ext->skip[type].
477 * ext may be equal to either ext1 or ext2.
479 * The two skips that need to be combined are assumed to be affine expressions.
481 * We need to skip in ext if we need to skip in either ext1 or ext2.
482 * We don't need to skip in ext if we don't need to skip in both ext1 and ext2.
484 static struct pet_scop_ext *combine_skips(struct pet_scop_ext *ext,
485 struct pet_scop_ext *ext1, struct pet_scop_ext *ext2,
486 enum pet_skip type)
488 isl_pw_aff *skip, *skip1, *skip2;
490 if (!ext)
491 return NULL;
492 if (!ext1->skip[type] && !ext2->skip[type])
493 return ext;
494 if (!ext1->skip[type]) {
495 if (ext == ext2)
496 return ext;
497 ext->skip[type] = ext2->skip[type];
498 ext2->skip[type] = NULL;
499 return ext;
501 if (!ext2->skip[type]) {
502 if (ext == ext1)
503 return ext;
504 ext->skip[type] = ext1->skip[type];
505 ext1->skip[type] = NULL;
506 return ext;
509 if (!multi_pw_aff_is_affine(ext1->skip[type]) ||
510 !multi_pw_aff_is_affine(ext2->skip[type]))
511 isl_die(isl_multi_pw_aff_get_ctx(ext1->skip[type]),
512 isl_error_internal, "can only combine affine skips",
513 goto error);
515 skip1 = isl_multi_pw_aff_get_pw_aff(ext1->skip[type], 0);
516 skip2 = isl_multi_pw_aff_get_pw_aff(ext2->skip[type], 0);
517 skip = pw_aff_or(skip1, skip2);
518 isl_multi_pw_aff_free(ext1->skip[type]);
519 ext1->skip[type] = NULL;
520 isl_multi_pw_aff_free(ext2->skip[type]);
521 ext2->skip[type] = NULL;
522 ext->skip[type] = isl_multi_pw_aff_from_pw_aff(skip);
523 if (!ext->skip[type])
524 goto error;
526 return ext;
527 error:
528 pet_scop_free(&ext->scop);
529 return NULL;
532 /* Combine scop1->skip[type] and scop2->skip[type] into scop->skip[type],
533 * where type takes on the values pet_skip_now and pet_skip_later.
534 * scop may be equal to either scop1 or scop2.
536 static struct pet_scop *scop_combine_skips(struct pet_scop *scop,
537 struct pet_scop *scop1, struct pet_scop *scop2)
539 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
540 struct pet_scop_ext *ext1 = (struct pet_scop_ext *) scop1;
541 struct pet_scop_ext *ext2 = (struct pet_scop_ext *) scop2;
543 ext = combine_skips(ext, ext1, ext2, pet_skip_now);
544 ext = combine_skips(ext, ext1, ext2, pet_skip_later);
545 return &ext->scop;
548 /* Update start and end of scop->loc to include the region from "start"
549 * to "end". In particular, if scop->loc == &pet_loc_dummy, then "scop"
550 * does not have any offset information yet and we simply take the information
551 * from "start" and "end". Otherwise, we update loc using "start" and "end".
553 struct pet_scop *pet_scop_update_start_end(struct pet_scop *scop,
554 unsigned start, unsigned end)
556 if (!scop)
557 return NULL;
559 if (scop->loc == &pet_loc_dummy)
560 scop->loc = pet_loc_alloc(isl_set_get_ctx(scop->context),
561 start, end, -1);
562 else
563 scop->loc = pet_loc_update_start_end(scop->loc, start, end);
565 if (!scop->loc)
566 return pet_scop_free(scop);
568 return scop;
571 /* Update start and end of scop->loc to include the region identified
572 * by "loc".
574 struct pet_scop *pet_scop_update_start_end_from_loc(struct pet_scop *scop,
575 __isl_keep pet_loc *loc)
577 return pet_scop_update_start_end(scop, pet_loc_get_start(loc),
578 pet_loc_get_end(loc));
581 /* Replace the location of "scop" by "loc".
583 struct pet_scop *pet_scop_set_loc(struct pet_scop *scop,
584 __isl_take pet_loc *loc)
586 if (!scop || !loc)
587 goto error;
589 pet_loc_free(scop->loc);
590 scop->loc = loc;
592 return scop;
593 error:
594 pet_loc_free(loc);
595 pet_scop_free(scop);
596 return NULL;
599 /* Does "implication" appear in the list of implications of "scop"?
601 static int is_known_implication(struct pet_scop *scop,
602 struct pet_implication *implication)
604 int i;
606 for (i = 0; i < scop->n_implication; ++i) {
607 struct pet_implication *pi = scop->implications[i];
608 int equal;
610 if (pi->satisfied != implication->satisfied)
611 continue;
612 equal = isl_map_is_equal(pi->extension, implication->extension);
613 if (equal < 0)
614 return -1;
615 if (equal)
616 return 1;
619 return 0;
622 /* Store the concatenation of the implications of "scop1" and "scop2"
623 * in "scop", removing duplicates (i.e., implications in "scop2" that
624 * already appear in "scop1").
626 static struct pet_scop *scop_collect_implications(isl_ctx *ctx,
627 struct pet_scop *scop, struct pet_scop *scop1, struct pet_scop *scop2)
629 int i, j;
631 if (!scop)
632 return NULL;
634 if (scop2->n_implication == 0) {
635 scop->n_implication = scop1->n_implication;
636 scop->implications = scop1->implications;
637 scop1->n_implication = 0;
638 scop1->implications = NULL;
639 return scop;
642 if (scop1->n_implication == 0) {
643 scop->n_implication = scop2->n_implication;
644 scop->implications = scop2->implications;
645 scop2->n_implication = 0;
646 scop2->implications = NULL;
647 return scop;
650 scop->implications = isl_calloc_array(ctx, struct pet_implication *,
651 scop1->n_implication + scop2->n_implication);
652 if (!scop->implications)
653 return pet_scop_free(scop);
655 for (i = 0; i < scop1->n_implication; ++i) {
656 scop->implications[i] = scop1->implications[i];
657 scop1->implications[i] = NULL;
660 scop->n_implication = scop1->n_implication;
661 j = scop1->n_implication;
662 for (i = 0; i < scop2->n_implication; ++i) {
663 int known;
665 known = is_known_implication(scop, scop2->implications[i]);
666 if (known < 0)
667 return pet_scop_free(scop);
668 if (known)
669 continue;
670 scop->implications[j++] = scop2->implications[i];
671 scop2->implications[i] = NULL;
673 scop->n_implication = j;
675 return scop;
678 /* Combine the offset information of "scop1" and "scop2" into "scop".
680 static struct pet_scop *scop_combine_start_end(struct pet_scop *scop,
681 struct pet_scop *scop1, struct pet_scop *scop2)
683 if (scop1->loc != &pet_loc_dummy)
684 scop = pet_scop_update_start_end_from_loc(scop, scop1->loc);
685 if (scop2->loc != &pet_loc_dummy)
686 scop = pet_scop_update_start_end_from_loc(scop, scop2->loc);
687 return scop;
690 /* Construct a pet_scop that contains the offset information,
691 * arrays, statements and skip information in "scop1" and "scop2".
693 static struct pet_scop *pet_scop_add(isl_ctx *ctx, struct pet_scop *scop1,
694 struct pet_scop *scop2)
696 int i;
697 isl_space *space;
698 struct pet_scop *scop = NULL;
700 if (!scop1 || !scop2)
701 goto error;
703 if (scop1->n_stmt == 0) {
704 scop2 = scop_combine_skips(scop2, scop1, scop2);
705 pet_scop_free(scop1);
706 return scop2;
709 if (scop2->n_stmt == 0) {
710 scop1 = scop_combine_skips(scop1, scop1, scop2);
711 pet_scop_free(scop2);
712 return scop1;
715 space = isl_set_get_space(scop1->context);
716 scop = scop_alloc(space, scop1->n_stmt + scop2->n_stmt);
717 if (!scop)
718 goto error;
720 scop->arrays = isl_calloc_array(ctx, struct pet_array *,
721 scop1->n_array + scop2->n_array);
722 if (!scop->arrays)
723 goto error;
724 scop->n_array = scop1->n_array + scop2->n_array;
726 for (i = 0; i < scop1->n_stmt; ++i) {
727 scop->stmts[i] = scop1->stmts[i];
728 scop1->stmts[i] = NULL;
731 for (i = 0; i < scop2->n_stmt; ++i) {
732 scop->stmts[scop1->n_stmt + i] = scop2->stmts[i];
733 scop2->stmts[i] = NULL;
736 for (i = 0; i < scop1->n_array; ++i) {
737 scop->arrays[i] = scop1->arrays[i];
738 scop1->arrays[i] = NULL;
741 for (i = 0; i < scop2->n_array; ++i) {
742 scop->arrays[scop1->n_array + i] = scop2->arrays[i];
743 scop2->arrays[i] = NULL;
746 scop = scop_collect_implications(ctx, scop, scop1, scop2);
747 scop = pet_scop_restrict_context(scop, isl_set_copy(scop1->context));
748 scop = pet_scop_restrict_context(scop, isl_set_copy(scop2->context));
749 scop = scop_combine_skips(scop, scop1, scop2);
750 scop = scop_combine_start_end(scop, scop1, scop2);
752 pet_scop_free(scop1);
753 pet_scop_free(scop2);
754 return scop;
755 error:
756 pet_scop_free(scop1);
757 pet_scop_free(scop2);
758 pet_scop_free(scop);
759 return NULL;
762 /* Apply the skip condition "skip" to "scop".
763 * That is, make sure "scop" is not executed when the condition holds.
765 * If "skip" is an affine expression, we add the conditions under
766 * which the expression is zero to the iteration domains.
767 * Otherwise, we add a filter on the variable attaining the value zero.
769 static struct pet_scop *restrict_skip(struct pet_scop *scop,
770 __isl_take isl_multi_pw_aff *skip)
772 isl_set *zero;
773 isl_pw_aff *pa;
774 int is_aff;
776 if (!scop || !skip)
777 goto error;
779 is_aff = multi_pw_aff_is_affine(skip);
780 if (is_aff < 0)
781 goto error;
783 if (!is_aff)
784 return pet_scop_filter(scop, skip, 0);
786 pa = isl_multi_pw_aff_get_pw_aff(skip, 0);
787 isl_multi_pw_aff_free(skip);
788 zero = isl_set_params(isl_pw_aff_zero_set(pa));
789 scop = pet_scop_restrict(scop, zero);
791 return scop;
792 error:
793 isl_multi_pw_aff_free(skip);
794 return pet_scop_free(scop);
797 /* Construct a pet_scop that contains the arrays, statements and
798 * skip information in "scop1" and "scop2", where the two scops
799 * are executed "in sequence". That is, breaks and continues
800 * in scop1 have an effect on scop2.
802 struct pet_scop *pet_scop_add_seq(isl_ctx *ctx, struct pet_scop *scop1,
803 struct pet_scop *scop2)
805 if (scop1 && pet_scop_has_skip(scop1, pet_skip_now))
806 scop2 = restrict_skip(scop2,
807 pet_scop_get_skip(scop1, pet_skip_now));
808 return pet_scop_add(ctx, scop1, scop2);
811 /* Construct a pet_scop that contains the arrays, statements and
812 * skip information in "scop1" and "scop2", where the two scops
813 * are executed "in parallel". That is, any break or continue
814 * in scop1 has no effect on scop2.
816 struct pet_scop *pet_scop_add_par(isl_ctx *ctx, struct pet_scop *scop1,
817 struct pet_scop *scop2)
819 return pet_scop_add(ctx, scop1, scop2);
822 void *pet_implication_free(struct pet_implication *implication)
824 int i;
826 if (!implication)
827 return NULL;
829 isl_map_free(implication->extension);
831 free(implication);
832 return NULL;
835 struct pet_scop *pet_scop_free(struct pet_scop *scop)
837 int i;
838 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
840 if (!scop)
841 return NULL;
842 pet_loc_free(scop->loc);
843 isl_set_free(scop->context);
844 isl_set_free(scop->context_value);
845 if (scop->types)
846 for (i = 0; i < scop->n_type; ++i)
847 pet_type_free(scop->types[i]);
848 free(scop->types);
849 if (scop->arrays)
850 for (i = 0; i < scop->n_array; ++i)
851 pet_array_free(scop->arrays[i]);
852 free(scop->arrays);
853 if (scop->stmts)
854 for (i = 0; i < scop->n_stmt; ++i)
855 pet_stmt_free(scop->stmts[i]);
856 free(scop->stmts);
857 if (scop->implications)
858 for (i = 0; i < scop->n_implication; ++i)
859 pet_implication_free(scop->implications[i]);
860 free(scop->implications);
861 isl_multi_pw_aff_free(ext->skip[pet_skip_now]);
862 isl_multi_pw_aff_free(ext->skip[pet_skip_later]);
863 free(scop);
864 return NULL;
867 void pet_type_dump(struct pet_type *type)
869 if (!type)
870 return;
872 fprintf(stderr, "%s -> %s\n", type->name, type->definition);
875 void pet_implication_dump(struct pet_implication *implication)
877 if (!implication)
878 return;
880 fprintf(stderr, "%d\n", implication->satisfied);
881 isl_map_dump(implication->extension);
884 void pet_scop_dump(struct pet_scop *scop)
886 int i;
887 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
889 if (!scop)
890 return;
892 isl_set_dump(scop->context);
893 isl_set_dump(scop->context_value);
894 for (i = 0; i < scop->n_type; ++i)
895 pet_type_dump(scop->types[i]);
896 for (i = 0; i < scop->n_array; ++i)
897 pet_array_dump(scop->arrays[i]);
898 for (i = 0; i < scop->n_stmt; ++i)
899 pet_stmt_dump(scop->stmts[i]);
900 for (i = 0; i < scop->n_implication; ++i)
901 pet_implication_dump(scop->implications[i]);
903 if (ext->skip[0]) {
904 fprintf(stderr, "skip\n");
905 isl_multi_pw_aff_dump(ext->skip[0]);
906 isl_multi_pw_aff_dump(ext->skip[1]);
910 /* Return 1 if the two pet_arrays are equivalent.
912 * We don't compare element_size as this may be target dependent.
914 int pet_array_is_equal(struct pet_array *array1, struct pet_array *array2)
916 if (!array1 || !array2)
917 return 0;
919 if (!isl_set_is_equal(array1->context, array2->context))
920 return 0;
921 if (!isl_set_is_equal(array1->extent, array2->extent))
922 return 0;
923 if (!!array1->value_bounds != !!array2->value_bounds)
924 return 0;
925 if (array1->value_bounds &&
926 !isl_set_is_equal(array1->value_bounds, array2->value_bounds))
927 return 0;
928 if (strcmp(array1->element_type, array2->element_type))
929 return 0;
930 if (array1->element_is_record != array2->element_is_record)
931 return 0;
932 if (array1->live_out != array2->live_out)
933 return 0;
934 if (array1->uniquely_defined != array2->uniquely_defined)
935 return 0;
936 if (array1->declared != array2->declared)
937 return 0;
938 if (array1->exposed != array2->exposed)
939 return 0;
941 return 1;
944 /* Return 1 if the two pet_stmts are equivalent.
946 int pet_stmt_is_equal(struct pet_stmt *stmt1, struct pet_stmt *stmt2)
948 int i;
950 if (!stmt1 || !stmt2)
951 return 0;
953 if (pet_loc_get_line(stmt1->loc) != pet_loc_get_line(stmt2->loc))
954 return 0;
955 if (!isl_set_is_equal(stmt1->domain, stmt2->domain))
956 return 0;
957 if (!isl_map_is_equal(stmt1->schedule, stmt2->schedule))
958 return 0;
959 if (!pet_expr_is_equal(stmt1->body, stmt2->body))
960 return 0;
961 if (stmt1->n_arg != stmt2->n_arg)
962 return 0;
963 for (i = 0; i < stmt1->n_arg; ++i) {
964 if (!pet_expr_is_equal(stmt1->args[i], stmt2->args[i]))
965 return 0;
968 return 1;
971 /* Return 1 if the two pet_types are equivalent.
973 * We only compare the names of the types since the exact representation
974 * of the definition may depend on the version of clang being used.
976 int pet_type_is_equal(struct pet_type *type1, struct pet_type *type2)
978 if (!type1 || !type2)
979 return 0;
981 if (strcmp(type1->name, type2->name))
982 return 0;
984 return 1;
987 /* Return 1 if the two pet_implications are equivalent.
989 int pet_implication_is_equal(struct pet_implication *implication1,
990 struct pet_implication *implication2)
992 if (!implication1 || !implication2)
993 return 0;
995 if (implication1->satisfied != implication2->satisfied)
996 return 0;
997 if (!isl_map_is_equal(implication1->extension, implication2->extension))
998 return 0;
1000 return 1;
1003 /* Return 1 if the two pet_scops are equivalent.
1005 int pet_scop_is_equal(struct pet_scop *scop1, struct pet_scop *scop2)
1007 int i;
1009 if (!scop1 || !scop2)
1010 return 0;
1012 if (!isl_set_is_equal(scop1->context, scop2->context))
1013 return 0;
1014 if (!isl_set_is_equal(scop1->context_value, scop2->context_value))
1015 return 0;
1017 if (scop1->n_type != scop2->n_type)
1018 return 0;
1019 for (i = 0; i < scop1->n_type; ++i)
1020 if (!pet_type_is_equal(scop1->types[i], scop2->types[i]))
1021 return 0;
1023 if (scop1->n_array != scop2->n_array)
1024 return 0;
1025 for (i = 0; i < scop1->n_array; ++i)
1026 if (!pet_array_is_equal(scop1->arrays[i], scop2->arrays[i]))
1027 return 0;
1029 if (scop1->n_stmt != scop2->n_stmt)
1030 return 0;
1031 for (i = 0; i < scop1->n_stmt; ++i)
1032 if (!pet_stmt_is_equal(scop1->stmts[i], scop2->stmts[i]))
1033 return 0;
1035 if (scop1->n_implication != scop2->n_implication)
1036 return 0;
1037 for (i = 0; i < scop1->n_implication; ++i)
1038 if (!pet_implication_is_equal(scop1->implications[i],
1039 scop2->implications[i]))
1040 return 0;
1042 return 1;
1045 /* Does the set "extent" reference a virtual array, i.e.,
1046 * one with user pointer equal to NULL?
1047 * A virtual array does not have any members.
1049 static int extent_is_virtual_array(__isl_keep isl_set *extent)
1051 isl_id *id;
1052 int is_virtual;
1054 if (!isl_set_has_tuple_id(extent))
1055 return 0;
1056 if (isl_set_is_wrapping(extent))
1057 return 0;
1058 id = isl_set_get_tuple_id(extent);
1059 is_virtual = !isl_id_get_user(id);
1060 isl_id_free(id);
1062 return is_virtual;
1065 /* Intersect the initial dimensions of "array" with "domain", provided
1066 * that "array" represents a virtual array.
1068 * If "array" is virtual, then We take the preimage of "domain"
1069 * over the projection of the extent of "array" onto its initial dimensions
1070 * and intersect this extent with the result.
1072 static struct pet_array *virtual_array_intersect_domain_prefix(
1073 struct pet_array *array, __isl_take isl_set *domain)
1075 int n;
1076 isl_space *space;
1077 isl_multi_aff *ma;
1079 if (!array || !extent_is_virtual_array(array->extent)) {
1080 isl_set_free(domain);
1081 return array;
1084 space = isl_set_get_space(array->extent);
1085 n = isl_set_dim(domain, isl_dim_set);
1086 ma = pet_prefix_projection(space, n);
1087 domain = isl_set_preimage_multi_aff(domain, ma);
1089 array->extent = isl_set_intersect(array->extent, domain);
1090 if (!array->extent)
1091 return pet_array_free(array);
1093 return array;
1096 /* Intersect the initial dimensions of the domain of "stmt"
1097 * with "domain".
1099 * We take the preimage of "domain" over the projection of the
1100 * domain of "stmt" onto its initial dimensions and intersect
1101 * the domain of "stmt" with the result.
1103 static struct pet_stmt *stmt_intersect_domain_prefix(struct pet_stmt *stmt,
1104 __isl_take isl_set *domain)
1106 int n;
1107 isl_space *space;
1108 isl_multi_aff *ma;
1110 if (!stmt)
1111 goto error;
1113 space = isl_set_get_space(stmt->domain);
1114 n = isl_set_dim(domain, isl_dim_set);
1115 ma = pet_prefix_projection(space, n);
1116 domain = isl_set_preimage_multi_aff(domain, ma);
1118 stmt->domain = isl_set_intersect(stmt->domain, domain);
1119 if (!stmt->domain)
1120 return pet_stmt_free(stmt);
1122 return stmt;
1123 error:
1124 isl_set_free(domain);
1125 return pet_stmt_free(stmt);
1128 /* Intersect the initial dimensions of the domain of "implication"
1129 * with "domain".
1131 * We take the preimage of "domain" over the projection of the
1132 * domain of "implication" onto its initial dimensions and intersect
1133 * the domain of "implication" with the result.
1135 static struct pet_implication *implication_intersect_domain_prefix(
1136 struct pet_implication *implication, __isl_take isl_set *domain)
1138 int n;
1139 isl_space *space;
1140 isl_multi_aff *ma;
1142 if (!implication)
1143 goto error;
1145 space = isl_map_get_space(implication->extension);
1146 n = isl_set_dim(domain, isl_dim_set);
1147 ma = pet_prefix_projection(isl_space_domain(space), n);
1148 domain = isl_set_preimage_multi_aff(domain, ma);
1150 implication->extension =
1151 isl_map_intersect_domain(implication->extension, domain);
1152 if (!implication->extension)
1153 return pet_implication_free(implication);
1155 return implication;
1156 error:
1157 isl_set_free(domain);
1158 return pet_implication_free(implication);
1161 /* Intersect the initial dimensions of the domains in "scop" with "domain".
1163 * The extents of the virtual arrays match the iteration domains,
1164 * so if the iteration domain changes, we need to change those extents too.
1166 struct pet_scop *pet_scop_intersect_domain_prefix(struct pet_scop *scop,
1167 __isl_take isl_set *domain)
1169 int i;
1171 if (!scop)
1172 goto error;
1174 for (i = 0; i < scop->n_array; ++i) {
1175 scop->arrays[i] = virtual_array_intersect_domain_prefix(
1176 scop->arrays[i], isl_set_copy(domain));
1177 if (!scop->arrays[i])
1178 goto error;
1181 for (i = 0; i < scop->n_stmt; ++i) {
1182 scop->stmts[i] = stmt_intersect_domain_prefix(scop->stmts[i],
1183 isl_set_copy(domain));
1184 if (!scop->stmts[i])
1185 goto error;
1188 for (i = 0; i < scop->n_implication; ++i) {
1189 scop->implications[i] =
1190 implication_intersect_domain_prefix(scop->implications[i],
1191 isl_set_copy(domain));
1192 if (!scop->implications[i])
1193 return pet_scop_free(scop);
1196 isl_set_free(domain);
1197 return scop;
1198 error:
1199 isl_set_free(domain);
1200 return pet_scop_free(scop);
1203 /* Prefix the schedule of "stmt" with an extra dimension with constant
1204 * value "pos".
1206 struct pet_stmt *pet_stmt_prefix(struct pet_stmt *stmt, int pos)
1208 if (!stmt)
1209 return NULL;
1211 stmt->schedule = isl_map_insert_dims(stmt->schedule, isl_dim_out, 0, 1);
1212 stmt->schedule = isl_map_fix_si(stmt->schedule, isl_dim_out, 0, pos);
1213 if (!stmt->schedule)
1214 return pet_stmt_free(stmt);
1216 return stmt;
1219 /* Prefix the schedules of all statements in "scop" with an extra
1220 * dimension with constant value "pos".
1222 struct pet_scop *pet_scop_prefix(struct pet_scop *scop, int pos)
1224 int i;
1226 if (!scop)
1227 return NULL;
1229 for (i = 0; i < scop->n_stmt; ++i) {
1230 scop->stmts[i] = pet_stmt_prefix(scop->stmts[i], pos);
1231 if (!scop->stmts[i])
1232 return pet_scop_free(scop);
1235 return scop;
1238 /* Given a set with a parameter at "param_pos" that refers to the
1239 * iterator, "move" the iterator to the first set dimension.
1240 * That is, essentially equate the parameter to the first set dimension
1241 * and then project it out.
1243 * The first set dimension may however refer to a virtual iterator,
1244 * while the parameter refers to the "real" iterator.
1245 * We therefore need to take into account the affine expression "iv_map", which
1246 * expresses the real iterator in terms of the virtual iterator.
1247 * In particular, we equate the set dimension to the input of the map
1248 * and the parameter to the output of the map and then project out
1249 * everything we don't need anymore.
1251 static __isl_give isl_set *internalize_iv(__isl_take isl_set *set,
1252 int param_pos, __isl_take isl_aff *iv_map)
1254 isl_map *map, *map2;
1255 map = isl_map_from_domain(set);
1256 map = isl_map_add_dims(map, isl_dim_out, 1);
1257 map = isl_map_equate(map, isl_dim_in, 0, isl_dim_out, 0);
1258 map2 = isl_map_from_aff(iv_map);
1259 map2 = isl_map_align_params(map2, isl_map_get_space(map));
1260 map = isl_map_apply_range(map, map2);
1261 map = isl_map_equate(map, isl_dim_param, param_pos, isl_dim_out, 0);
1262 map = isl_map_project_out(map, isl_dim_param, param_pos, 1);
1263 return isl_map_domain(map);
1266 /* Data used in embed_access.
1267 * extend adds an iterator to the iteration domain (through precomposition).
1268 * iv_map expresses the real iterator in terms of the virtual iterator
1269 * var_id represents the induction variable of the corresponding loop
1271 struct pet_embed_access {
1272 isl_multi_pw_aff *extend;
1273 isl_aff *iv_map;
1274 isl_id *var_id;
1277 /* Given an index expression, return an expression for the outer iterator.
1279 static __isl_give isl_aff *index_outer_iterator(
1280 __isl_take isl_multi_pw_aff *index)
1282 isl_space *space;
1283 isl_local_space *ls;
1285 space = isl_multi_pw_aff_get_domain_space(index);
1286 isl_multi_pw_aff_free(index);
1288 ls = isl_local_space_from_space(space);
1289 return isl_aff_var_on_domain(ls, isl_dim_set, 0);
1292 /* Replace an index expression that references the new (outer) iterator variable
1293 * by one that references the corresponding (real) iterator.
1295 * The input index expression is of the form
1297 * { S[i',...] -> i[] }
1299 * where i' refers to the virtual iterator.
1301 * iv_map is of the form
1303 * { [i'] -> [i] }
1305 * Return the index expression
1307 * { S[i',...] -> [i] }
1309 static __isl_give isl_multi_pw_aff *replace_by_iterator(
1310 __isl_take isl_multi_pw_aff *index, __isl_take isl_aff *iv_map)
1312 isl_space *space;
1313 isl_aff *aff;
1315 aff = index_outer_iterator(index);
1316 space = isl_aff_get_space(aff);
1317 iv_map = isl_aff_align_params(iv_map, space);
1318 aff = isl_aff_pullback_aff(iv_map, aff);
1320 return isl_multi_pw_aff_from_pw_aff(isl_pw_aff_from_aff(aff));
1323 /* Given an index expression "index" that refers to the (real) iterator
1324 * through the parameter at position "pos", plug in "iv_map", expressing
1325 * the real iterator in terms of the virtual (outer) iterator.
1327 * In particular, the index expression is of the form
1329 * [..., i, ...] -> { S[i',...] -> ... i ... }
1331 * where i refers to the real iterator and i' refers to the virtual iterator.
1333 * iv_map is of the form
1335 * { [i'] -> [i] }
1337 * Return the index expression
1339 * [..., ...] -> { S[i',...] -> ... iv_map(i') ... }
1342 * We first move the parameter to the input
1344 * [..., ...] -> { [i, i',...] -> ... i ... }
1346 * and construct
1348 * { S[i',...] -> [i=iv_map(i'), i', ...] }
1350 * and then combine the two to obtain the desired result.
1352 static __isl_give isl_multi_pw_aff *index_internalize_iv(
1353 __isl_take isl_multi_pw_aff *index, int pos, __isl_take isl_aff *iv_map)
1355 isl_space *space = isl_multi_pw_aff_get_domain_space(index);
1356 isl_multi_aff *ma;
1358 space = isl_space_drop_dims(space, isl_dim_param, pos, 1);
1359 index = isl_multi_pw_aff_move_dims(index, isl_dim_in, 0,
1360 isl_dim_param, pos, 1);
1362 space = isl_space_map_from_set(space);
1363 ma = isl_multi_aff_identity(isl_space_copy(space));
1364 iv_map = isl_aff_align_params(iv_map, space);
1365 iv_map = isl_aff_pullback_aff(iv_map, isl_multi_aff_get_aff(ma, 0));
1366 ma = isl_multi_aff_flat_range_product(
1367 isl_multi_aff_from_aff(iv_map), ma);
1368 index = isl_multi_pw_aff_pullback_multi_aff(index, ma);
1370 return index;
1373 /* Does the index expression "index" reference a virtual array, i.e.,
1374 * one with user pointer equal to NULL?
1375 * A virtual array does not have any members.
1377 static int index_is_virtual_array(__isl_keep isl_multi_pw_aff *index)
1379 isl_id *id;
1380 int is_virtual;
1382 if (!isl_multi_pw_aff_has_tuple_id(index, isl_dim_out))
1383 return 0;
1384 if (isl_multi_pw_aff_range_is_wrapping(index))
1385 return 0;
1386 id = isl_multi_pw_aff_get_tuple_id(index, isl_dim_out);
1387 is_virtual = !isl_id_get_user(id);
1388 isl_id_free(id);
1390 return is_virtual;
1393 /* Does the access relation "access" reference a virtual array, i.e.,
1394 * one with user pointer equal to NULL?
1395 * A virtual array does not have any members.
1397 static int access_is_virtual_array(__isl_keep isl_map *access)
1399 isl_id *id;
1400 int is_virtual;
1402 if (!isl_map_has_tuple_id(access, isl_dim_out))
1403 return 0;
1404 if (isl_map_range_is_wrapping(access))
1405 return 0;
1406 id = isl_map_get_tuple_id(access, isl_dim_out);
1407 is_virtual = !isl_id_get_user(id);
1408 isl_id_free(id);
1410 return is_virtual;
1413 /* Embed the given index expression in an extra outer loop.
1414 * The domain of the index expression has already been updated.
1416 * If the access refers to the induction variable, then it is
1417 * turned into an access to the set of integers with index (and value)
1418 * equal to the induction variable.
1420 * If the accessed array is a virtual array (with user
1421 * pointer equal to NULL), as created by create_test_index,
1422 * then it is extended along with the domain of the index expression.
1424 static __isl_give isl_multi_pw_aff *embed_index_expression(
1425 __isl_take isl_multi_pw_aff *index, struct pet_embed_access *data)
1427 isl_id *array_id = NULL;
1428 int pos;
1430 if (isl_multi_pw_aff_has_tuple_id(index, isl_dim_out))
1431 array_id = isl_multi_pw_aff_get_tuple_id(index, isl_dim_out);
1432 if (array_id == data->var_id) {
1433 index = replace_by_iterator(index, isl_aff_copy(data->iv_map));
1434 } else if (index_is_virtual_array(index)) {
1435 isl_aff *aff;
1436 isl_multi_pw_aff *mpa;
1438 aff = index_outer_iterator(isl_multi_pw_aff_copy(index));
1439 mpa = isl_multi_pw_aff_from_pw_aff(isl_pw_aff_from_aff(aff));
1440 index = isl_multi_pw_aff_flat_range_product(mpa, index);
1441 index = isl_multi_pw_aff_set_tuple_id(index, isl_dim_out,
1442 isl_id_copy(array_id));
1444 isl_id_free(array_id);
1446 pos = isl_multi_pw_aff_find_dim_by_id(index,
1447 isl_dim_param, data->var_id);
1448 if (pos >= 0)
1449 index = index_internalize_iv(index, pos,
1450 isl_aff_copy(data->iv_map));
1451 index = isl_multi_pw_aff_set_dim_id(index, isl_dim_in, 0,
1452 isl_id_copy(data->var_id));
1454 return index;
1457 /* Embed the given access relation in an extra outer loop.
1458 * The domain of the access relation has already been updated.
1460 * If the access refers to the induction variable, then it is
1461 * turned into an access to the set of integers with index (and value)
1462 * equal to the induction variable.
1464 * If the induction variable appears in the constraints (as a parameter),
1465 * then the parameter is equated to the newly introduced iteration
1466 * domain dimension and subsequently projected out.
1468 * Similarly, if the accessed array is a virtual array (with user
1469 * pointer equal to NULL), as created by create_test_index,
1470 * then it is extended along with the domain of the access.
1472 static __isl_give isl_map *embed_access_relation(__isl_take isl_map *access,
1473 struct pet_embed_access *data)
1475 isl_id *array_id = NULL;
1476 int pos;
1478 if (isl_map_has_tuple_id(access, isl_dim_out))
1479 array_id = isl_map_get_tuple_id(access, isl_dim_out);
1480 if (array_id == data->var_id || access_is_virtual_array(access)) {
1481 access = isl_map_insert_dims(access, isl_dim_out, 0, 1);
1482 access = isl_map_equate(access,
1483 isl_dim_in, 0, isl_dim_out, 0);
1484 if (array_id == data->var_id)
1485 access = isl_map_apply_range(access,
1486 isl_map_from_aff(isl_aff_copy(data->iv_map)));
1487 else
1488 access = isl_map_set_tuple_id(access, isl_dim_out,
1489 isl_id_copy(array_id));
1491 isl_id_free(array_id);
1493 pos = isl_map_find_dim_by_id(access, isl_dim_param, data->var_id);
1494 if (pos >= 0) {
1495 isl_set *set = isl_map_wrap(access);
1496 set = internalize_iv(set, pos, isl_aff_copy(data->iv_map));
1497 access = isl_set_unwrap(set);
1499 access = isl_map_set_dim_id(access, isl_dim_in, 0,
1500 isl_id_copy(data->var_id));
1502 return access;
1505 /* Given an access expression, embed the associated access relation and
1506 * index expression in an extra outer loop.
1508 * We first update the domains to insert the extra dimension and
1509 * then update the access relation and index expression to take
1510 * into account the mapping "iv_map" from virtual iterator
1511 * to real iterator.
1513 static __isl_give pet_expr *embed_access(__isl_take pet_expr *expr, void *user)
1515 struct pet_embed_access *data = user;
1517 expr = pet_expr_cow(expr);
1518 expr = pet_expr_access_update_domain(expr, data->extend);
1519 if (!expr)
1520 return NULL;
1522 expr->acc.access = embed_access_relation(expr->acc.access, data);
1523 expr->acc.index = embed_index_expression(expr->acc.index, data);
1524 if (!expr->acc.access || !expr->acc.index)
1525 return pet_expr_free(expr);
1527 return expr;
1530 /* Embed all access subexpressions of "expr" in an extra loop.
1531 * "extend" inserts an outer loop iterator in the iteration domains
1532 * (through precomposition).
1533 * "iv_map" expresses the real iterator in terms of the virtual iterator
1534 * "var_id" represents the induction variable.
1536 static __isl_give pet_expr *expr_embed(__isl_take pet_expr *expr,
1537 __isl_take isl_multi_pw_aff *extend, __isl_take isl_aff *iv_map,
1538 __isl_keep isl_id *var_id)
1540 struct pet_embed_access data =
1541 { .extend = extend, .iv_map = iv_map, .var_id = var_id };
1543 expr = pet_expr_map_access(expr, &embed_access, &data);
1544 isl_aff_free(iv_map);
1545 isl_multi_pw_aff_free(extend);
1546 return expr;
1549 /* Embed the given pet_stmt in an extra outer loop with iteration domain
1550 * "dom" and schedule "sched". "var_id" represents the induction variable
1551 * of the loop. "iv_map" maps a possibly virtual iterator to the real iterator.
1552 * That is, it expresses the iterator that some of the parameters in "stmt"
1553 * may refer to in terms of the iterator used in "dom" and
1554 * the domain of "sched".
1556 * The iteration domain and schedule of the statement are updated
1557 * according to the iteration domain and schedule of the new loop.
1558 * If stmt->domain is a wrapped map, then the iteration domain
1559 * is the domain of this map, so we need to be careful to adjust
1560 * this domain.
1562 * If the induction variable appears in the constraints (as a parameter)
1563 * of the current iteration domain or the schedule of the statement,
1564 * then the parameter is equated to the newly introduced iteration
1565 * domain dimension and subsequently projected out.
1567 * Finally, all access relations are updated based on the extra loop.
1569 static struct pet_stmt *pet_stmt_embed(struct pet_stmt *stmt,
1570 __isl_take isl_set *dom, __isl_take isl_map *sched,
1571 __isl_take isl_aff *iv_map, __isl_take isl_id *var_id)
1573 int i;
1574 int pos;
1575 isl_id *stmt_id;
1576 isl_space *dim;
1577 isl_multi_pw_aff *extend;
1579 if (!stmt)
1580 goto error;
1582 if (isl_set_is_wrapping(stmt->domain)) {
1583 isl_map *map;
1584 isl_map *ext;
1585 isl_space *ran_dim;
1587 map = isl_set_unwrap(stmt->domain);
1588 stmt_id = isl_map_get_tuple_id(map, isl_dim_in);
1589 ran_dim = isl_space_range(isl_map_get_space(map));
1590 ext = isl_map_from_domain_and_range(isl_set_copy(dom),
1591 isl_set_universe(ran_dim));
1592 map = isl_map_flat_domain_product(ext, map);
1593 map = isl_map_set_tuple_id(map, isl_dim_in,
1594 isl_id_copy(stmt_id));
1595 dim = isl_space_domain(isl_map_get_space(map));
1596 stmt->domain = isl_map_wrap(map);
1597 } else {
1598 stmt_id = isl_set_get_tuple_id(stmt->domain);
1599 stmt->domain = isl_set_flat_product(isl_set_copy(dom),
1600 stmt->domain);
1601 stmt->domain = isl_set_set_tuple_id(stmt->domain,
1602 isl_id_copy(stmt_id));
1603 dim = isl_set_get_space(stmt->domain);
1606 pos = isl_set_find_dim_by_id(stmt->domain, isl_dim_param, var_id);
1607 if (pos >= 0)
1608 stmt->domain = internalize_iv(stmt->domain, pos,
1609 isl_aff_copy(iv_map));
1611 stmt->schedule = isl_map_flat_product(sched, stmt->schedule);
1612 stmt->schedule = isl_map_set_tuple_id(stmt->schedule,
1613 isl_dim_in, stmt_id);
1615 pos = isl_map_find_dim_by_id(stmt->schedule, isl_dim_param, var_id);
1616 if (pos >= 0) {
1617 isl_set *set = isl_map_wrap(stmt->schedule);
1618 set = internalize_iv(set, pos, isl_aff_copy(iv_map));
1619 stmt->schedule = isl_set_unwrap(set);
1622 dim = isl_space_map_from_set(dim);
1623 extend = isl_multi_pw_aff_identity(dim);
1624 extend = isl_multi_pw_aff_drop_dims(extend, isl_dim_out, 0, 1);
1625 extend = isl_multi_pw_aff_set_tuple_id(extend, isl_dim_out,
1626 isl_multi_pw_aff_get_tuple_id(extend, isl_dim_in));
1627 for (i = 0; i < stmt->n_arg; ++i)
1628 stmt->args[i] = expr_embed(stmt->args[i],
1629 isl_multi_pw_aff_copy(extend),
1630 isl_aff_copy(iv_map), var_id);
1631 stmt->body = expr_embed(stmt->body, extend, iv_map, var_id);
1633 isl_set_free(dom);
1634 isl_id_free(var_id);
1636 for (i = 0; i < stmt->n_arg; ++i)
1637 if (!stmt->args[i])
1638 return pet_stmt_free(stmt);
1639 if (!stmt->domain || !stmt->schedule || !stmt->body)
1640 return pet_stmt_free(stmt);
1641 return stmt;
1642 error:
1643 isl_set_free(dom);
1644 isl_map_free(sched);
1645 isl_aff_free(iv_map);
1646 isl_id_free(var_id);
1647 return NULL;
1650 /* Embed the given pet_array in an extra outer loop with iteration domain
1651 * "dom".
1652 * This embedding only has an effect on virtual arrays (those with
1653 * user pointer equal to NULL), which need to be extended along with
1654 * the iteration domain.
1656 static struct pet_array *pet_array_embed(struct pet_array *array,
1657 __isl_take isl_set *dom)
1659 isl_id *array_id = NULL;
1661 if (!array)
1662 goto error;
1663 if (!extent_is_virtual_array(array->extent)) {
1664 isl_set_free(dom);
1665 return array;
1668 array_id = isl_set_get_tuple_id(array->extent);
1669 array->extent = isl_set_flat_product(dom, array->extent);
1670 array->extent = isl_set_set_tuple_id(array->extent, array_id);
1671 if (!array->extent)
1672 return pet_array_free(array);
1674 return array;
1675 error:
1676 isl_set_free(dom);
1677 return NULL;
1680 /* Update the context with respect to an embedding into a loop
1681 * with iteration domain "dom" and induction variable "id".
1682 * "iv_map" expresses the real iterator (parameter "id") in terms
1683 * of a possibly virtual iterator (used in "dom").
1685 * If the current context is independent of "id", we don't need
1686 * to do anything.
1687 * Otherwise, a parameter value is invalid for the embedding if
1688 * any of the corresponding iterator values is invalid.
1689 * That is, a parameter value is valid only if all the corresponding
1690 * iterator values are valid.
1691 * We therefore compute the set of parameters
1693 * forall i in dom : valid (i)
1695 * or
1697 * not exists i in dom : not valid(i)
1699 * i.e.,
1701 * not exists i in dom \ valid(i)
1703 * Before we subtract valid(i) from dom, we first need to substitute
1704 * the real iterator for the virtual iterator.
1706 * If there are any unnamed parameters in "dom", then we consider
1707 * a parameter value to be valid if it is valid for any value of those
1708 * unnamed parameters. They are therefore projected out at the end.
1710 static __isl_give isl_set *context_embed(__isl_take isl_set *context,
1711 __isl_keep isl_set *dom, __isl_keep isl_aff *iv_map,
1712 __isl_keep isl_id *id)
1714 int pos;
1715 isl_multi_aff *ma;
1717 pos = isl_set_find_dim_by_id(context, isl_dim_param, id);
1718 if (pos < 0)
1719 return context;
1721 context = isl_set_from_params(context);
1722 context = isl_set_add_dims(context, isl_dim_set, 1);
1723 context = isl_set_equate(context, isl_dim_param, pos, isl_dim_set, 0);
1724 context = isl_set_project_out(context, isl_dim_param, pos, 1);
1725 ma = isl_multi_aff_from_aff(isl_aff_copy(iv_map));
1726 context = isl_set_preimage_multi_aff(context, ma);
1727 context = isl_set_subtract(isl_set_copy(dom), context);
1728 context = isl_set_params(context);
1729 context = isl_set_complement(context);
1730 context = pet_nested_remove_from_set(context);
1731 return context;
1734 /* Update the implication with respect to an embedding into a loop
1735 * with iteration domain "dom".
1737 * Since embed_access extends virtual arrays along with the domain
1738 * of the access, we need to do the same with domain and range
1739 * of the implication. Since the original implication is only valid
1740 * within a given iteration of the loop, the extended implication
1741 * maps the extra array dimension corresponding to the extra loop
1742 * to itself.
1744 static struct pet_implication *pet_implication_embed(
1745 struct pet_implication *implication, __isl_take isl_set *dom)
1747 isl_id *id;
1748 isl_map *map;
1750 if (!implication)
1751 goto error;
1753 map = isl_set_identity(dom);
1754 id = isl_map_get_tuple_id(implication->extension, isl_dim_in);
1755 map = isl_map_flat_product(map, implication->extension);
1756 map = isl_map_set_tuple_id(map, isl_dim_in, isl_id_copy(id));
1757 map = isl_map_set_tuple_id(map, isl_dim_out, id);
1758 implication->extension = map;
1759 if (!implication->extension)
1760 return pet_implication_free(implication);
1762 return implication;
1763 error:
1764 isl_set_free(dom);
1765 return NULL;
1768 /* Embed all statements and arrays in "scop" in an extra outer loop
1769 * with iteration domain "dom" and schedule "sched".
1770 * "id" represents the induction variable of the loop.
1771 * "iv_map" maps a possibly virtual iterator to the real iterator.
1772 * That is, it expresses the iterator that some of the parameters in "scop"
1773 * may refer to in terms of the iterator used in "dom" and
1774 * the domain of "sched".
1776 * Any skip conditions within the loop have no effect outside of the loop.
1777 * The caller is responsible for making sure skip[pet_skip_later] has been
1778 * taken into account.
1780 struct pet_scop *pet_scop_embed(struct pet_scop *scop, __isl_take isl_set *dom,
1781 __isl_take isl_aff *sched, __isl_take isl_aff *iv_map,
1782 __isl_take isl_id *id)
1784 int i;
1785 isl_map *sched_map;
1787 sched_map = isl_map_from_aff(sched);
1789 if (!scop)
1790 goto error;
1792 pet_scop_reset_skip(scop, pet_skip_now);
1793 pet_scop_reset_skip(scop, pet_skip_later);
1795 scop->context = context_embed(scop->context, dom, iv_map, id);
1796 if (!scop->context)
1797 goto error;
1799 for (i = 0; i < scop->n_stmt; ++i) {
1800 scop->stmts[i] = pet_stmt_embed(scop->stmts[i],
1801 isl_set_copy(dom), isl_map_copy(sched_map),
1802 isl_aff_copy(iv_map), isl_id_copy(id));
1803 if (!scop->stmts[i])
1804 goto error;
1807 for (i = 0; i < scop->n_array; ++i) {
1808 scop->arrays[i] = pet_array_embed(scop->arrays[i],
1809 isl_set_copy(dom));
1810 if (!scop->arrays[i])
1811 goto error;
1814 for (i = 0; i < scop->n_implication; ++i) {
1815 scop->implications[i] =
1816 pet_implication_embed(scop->implications[i],
1817 isl_set_copy(dom));
1818 if (!scop->implications[i])
1819 goto error;
1822 isl_set_free(dom);
1823 isl_map_free(sched_map);
1824 isl_aff_free(iv_map);
1825 isl_id_free(id);
1826 return scop;
1827 error:
1828 isl_set_free(dom);
1829 isl_map_free(sched_map);
1830 isl_aff_free(iv_map);
1831 isl_id_free(id);
1832 return pet_scop_free(scop);
1835 /* Add extra conditions on the parameters to the iteration domain of "stmt".
1837 static struct pet_stmt *stmt_restrict(struct pet_stmt *stmt,
1838 __isl_take isl_set *cond)
1840 if (!stmt)
1841 goto error;
1843 stmt->domain = isl_set_intersect_params(stmt->domain, cond);
1845 return stmt;
1846 error:
1847 isl_set_free(cond);
1848 return pet_stmt_free(stmt);
1851 /* Add extra conditions to scop->skip[type].
1853 * The new skip condition only holds if it held before
1854 * and the condition is true. It does not hold if it did not hold
1855 * before or the condition is false.
1857 * The skip condition is assumed to be an affine expression.
1859 static struct pet_scop *pet_scop_restrict_skip(struct pet_scop *scop,
1860 enum pet_skip type, __isl_keep isl_set *cond)
1862 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
1863 isl_pw_aff *skip;
1864 isl_set *dom;
1866 if (!scop)
1867 return NULL;
1868 if (!ext->skip[type])
1869 return scop;
1871 if (!multi_pw_aff_is_affine(ext->skip[type]))
1872 isl_die(isl_multi_pw_aff_get_ctx(ext->skip[type]),
1873 isl_error_internal, "can only restrict affine skips",
1874 return pet_scop_free(scop));
1876 skip = isl_multi_pw_aff_get_pw_aff(ext->skip[type], 0);
1877 dom = isl_pw_aff_domain(isl_pw_aff_copy(skip));
1878 cond = isl_set_copy(cond);
1879 cond = isl_set_from_params(cond);
1880 cond = isl_set_intersect(cond, isl_pw_aff_non_zero_set(skip));
1881 skip = indicator_function(cond, dom);
1882 isl_multi_pw_aff_free(ext->skip[type]);
1883 ext->skip[type] = isl_multi_pw_aff_from_pw_aff(skip);
1884 if (!ext->skip[type])
1885 return pet_scop_free(scop);
1887 return scop;
1890 /* Add extra conditions on the parameters to all iteration domains
1891 * and skip conditions.
1893 * A parameter value is valid for the result if it was valid
1894 * for the original scop and satisfies "cond" or if it does
1895 * not satisfy "cond" as in this case the scop is not executed
1896 * and the original constraints on the parameters are irrelevant.
1898 struct pet_scop *pet_scop_restrict(struct pet_scop *scop,
1899 __isl_take isl_set *cond)
1901 int i;
1903 scop = pet_scop_restrict_skip(scop, pet_skip_now, cond);
1904 scop = pet_scop_restrict_skip(scop, pet_skip_later, cond);
1906 if (!scop)
1907 goto error;
1909 scop->context = isl_set_intersect(scop->context, isl_set_copy(cond));
1910 scop->context = isl_set_union(scop->context,
1911 isl_set_complement(isl_set_copy(cond)));
1912 scop->context = isl_set_coalesce(scop->context);
1913 scop->context = pet_nested_remove_from_set(scop->context);
1914 if (!scop->context)
1915 goto error;
1917 for (i = 0; i < scop->n_stmt; ++i) {
1918 scop->stmts[i] = stmt_restrict(scop->stmts[i],
1919 isl_set_copy(cond));
1920 if (!scop->stmts[i])
1921 goto error;
1924 isl_set_free(cond);
1925 return scop;
1926 error:
1927 isl_set_free(cond);
1928 return pet_scop_free(scop);
1931 /* Insert an argument expression corresponding to "test" in front
1932 * of the list of arguments described by *n_arg and *args.
1934 static int args_insert_access(unsigned *n_arg, pet_expr ***args,
1935 __isl_keep isl_multi_pw_aff *test)
1937 int i;
1938 isl_ctx *ctx = isl_multi_pw_aff_get_ctx(test);
1940 if (!test)
1941 return -1;
1943 if (!*args) {
1944 *args = isl_calloc_array(ctx, pet_expr *, 1);
1945 if (!*args)
1946 return -1;
1947 } else {
1948 pet_expr **ext;
1949 ext = isl_calloc_array(ctx, pet_expr *, 1 + *n_arg);
1950 if (!ext)
1951 return -1;
1952 for (i = 0; i < *n_arg; ++i)
1953 ext[1 + i] = (*args)[i];
1954 free(*args);
1955 *args = ext;
1957 (*n_arg)++;
1958 (*args)[0] = pet_expr_from_index(isl_multi_pw_aff_copy(test));
1959 if (!(*args)[0])
1960 return -1;
1962 return 0;
1965 /* Look through the applications in "scop" for any that can be
1966 * applied to the filter expressed by "map" and "satisified".
1967 * If there is any, then apply it to "map" and return the result.
1968 * Otherwise, return "map".
1969 * "id" is the identifier of the virtual array.
1971 * We only introduce at most one implication for any given virtual array,
1972 * so we can apply the implication and return as soon as we find one.
1974 static __isl_give isl_map *apply_implications(struct pet_scop *scop,
1975 __isl_take isl_map *map, __isl_keep isl_id *id, int satisfied)
1977 int i;
1979 for (i = 0; i < scop->n_implication; ++i) {
1980 struct pet_implication *pi = scop->implications[i];
1981 isl_id *pi_id;
1983 if (pi->satisfied != satisfied)
1984 continue;
1985 pi_id = isl_map_get_tuple_id(pi->extension, isl_dim_in);
1986 isl_id_free(pi_id);
1987 if (pi_id != id)
1988 continue;
1990 return isl_map_apply_range(map, isl_map_copy(pi->extension));
1993 return map;
1996 /* Is the filter expressed by "test" and "satisfied" implied
1997 * by filter "pos" on "domain", with filter "expr", taking into
1998 * account the implications of "scop"?
2000 * For filter on domain implying that expressed by "test" and "satisfied",
2001 * the filter needs to be an access to the same (virtual) array as "test" and
2002 * the filter value needs to be equal to "satisfied".
2003 * Moreover, the filter access relation, possibly extended by
2004 * the implications in "scop" needs to contain "test".
2006 static int implies_filter(struct pet_scop *scop,
2007 __isl_keep isl_map *domain, int pos, __isl_keep pet_expr *expr,
2008 __isl_keep isl_map *test, int satisfied)
2010 isl_id *test_id, *arg_id;
2011 isl_val *val;
2012 int is_int;
2013 int s;
2014 int is_subset;
2015 isl_map *implied;
2017 if (expr->type != pet_expr_access)
2018 return 0;
2019 test_id = isl_map_get_tuple_id(test, isl_dim_out);
2020 arg_id = pet_expr_access_get_id(expr);
2021 isl_id_free(arg_id);
2022 isl_id_free(test_id);
2023 if (test_id != arg_id)
2024 return 0;
2025 val = isl_map_plain_get_val_if_fixed(domain, isl_dim_out, pos);
2026 is_int = isl_val_is_int(val);
2027 if (is_int)
2028 s = isl_val_get_num_si(val);
2029 isl_val_free(val);
2030 if (!val)
2031 return -1;
2032 if (!is_int)
2033 return 0;
2034 if (s != satisfied)
2035 return 0;
2037 implied = isl_map_copy(expr->acc.access);
2038 implied = apply_implications(scop, implied, test_id, satisfied);
2039 is_subset = isl_map_is_subset(test, implied);
2040 isl_map_free(implied);
2042 return is_subset;
2045 /* Is the filter expressed by "test" and "satisfied" implied
2046 * by any of the filters on the domain of "stmt", taking into
2047 * account the implications of "scop"?
2049 static int filter_implied(struct pet_scop *scop,
2050 struct pet_stmt *stmt, __isl_keep isl_multi_pw_aff *test, int satisfied)
2052 int i;
2053 int implied;
2054 isl_id *test_id;
2055 isl_map *domain;
2056 isl_map *test_map;
2058 if (!scop || !stmt || !test)
2059 return -1;
2060 if (scop->n_implication == 0)
2061 return 0;
2062 if (stmt->n_arg == 0)
2063 return 0;
2065 domain = isl_set_unwrap(isl_set_copy(stmt->domain));
2066 test_map = isl_map_from_multi_pw_aff(isl_multi_pw_aff_copy(test));
2068 implied = 0;
2069 for (i = 0; i < stmt->n_arg; ++i) {
2070 implied = implies_filter(scop, domain, i, stmt->args[i],
2071 test_map, satisfied);
2072 if (implied < 0 || implied)
2073 break;
2076 isl_map_free(test_map);
2077 isl_map_free(domain);
2078 return implied;
2081 /* Make the statement "stmt" depend on the value of "test"
2082 * being equal to "satisfied" by adjusting stmt->domain.
2084 * The domain of "test" corresponds to the (zero or more) outer dimensions
2085 * of the iteration domain.
2087 * We first extend "test" to apply to the entire iteration domain and
2088 * then check if the filter that we are about to add is implied
2089 * by any of the current filters, possibly taking into account
2090 * the implications in "scop". If so, we leave "stmt" untouched and return.
2092 * Otherwise, we insert an argument corresponding to a read to "test"
2093 * from the iteration domain of "stmt" in front of the list of arguments.
2094 * We also insert a corresponding output dimension in the wrapped
2095 * map contained in stmt->domain, with value set to "satisfied".
2097 static struct pet_stmt *stmt_filter(struct pet_scop *scop,
2098 struct pet_stmt *stmt, __isl_take isl_multi_pw_aff *test, int satisfied)
2100 int i;
2101 int implied;
2102 isl_id *id;
2103 isl_ctx *ctx;
2104 isl_pw_multi_aff *pma;
2105 isl_multi_aff *add_dom;
2106 isl_space *space;
2107 isl_local_space *ls;
2108 int n_test_dom;
2110 if (!stmt || !test)
2111 goto error;
2113 space = pet_stmt_get_space(stmt);
2114 n_test_dom = isl_multi_pw_aff_dim(test, isl_dim_in);
2115 space = isl_space_from_domain(space);
2116 space = isl_space_add_dims(space, isl_dim_out, n_test_dom);
2117 add_dom = isl_multi_aff_zero(isl_space_copy(space));
2118 ls = isl_local_space_from_space(isl_space_domain(space));
2119 for (i = 0; i < n_test_dom; ++i) {
2120 isl_aff *aff;
2121 aff = isl_aff_var_on_domain(isl_local_space_copy(ls),
2122 isl_dim_set, i);
2123 add_dom = isl_multi_aff_set_aff(add_dom, i, aff);
2125 isl_local_space_free(ls);
2126 test = isl_multi_pw_aff_pullback_multi_aff(test, add_dom);
2128 implied = filter_implied(scop, stmt, test, satisfied);
2129 if (implied < 0)
2130 goto error;
2131 if (implied) {
2132 isl_multi_pw_aff_free(test);
2133 return stmt;
2136 id = isl_multi_pw_aff_get_tuple_id(test, isl_dim_out);
2137 pma = pet_filter_insert_pma(isl_set_get_space(stmt->domain),
2138 id, satisfied);
2139 stmt->domain = isl_set_preimage_pw_multi_aff(stmt->domain, pma);
2141 if (args_insert_access(&stmt->n_arg, &stmt->args, test) < 0)
2142 goto error;
2144 isl_multi_pw_aff_free(test);
2145 return stmt;
2146 error:
2147 isl_multi_pw_aff_free(test);
2148 return pet_stmt_free(stmt);
2151 /* Does "scop" have a skip condition of the given "type"?
2153 int pet_scop_has_skip(struct pet_scop *scop, enum pet_skip type)
2155 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2157 if (!scop)
2158 return -1;
2159 return ext->skip[type] != NULL;
2162 /* Does "scop" have a skip condition of the given "type" that
2163 * is an affine expression?
2165 int pet_scop_has_affine_skip(struct pet_scop *scop, enum pet_skip type)
2167 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2169 if (!scop)
2170 return -1;
2171 if (!ext->skip[type])
2172 return 0;
2173 return multi_pw_aff_is_affine(ext->skip[type]);
2176 /* Does "scop" have a skip condition of the given "type" that
2177 * is not an affine expression?
2179 int pet_scop_has_var_skip(struct pet_scop *scop, enum pet_skip type)
2181 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2182 int aff;
2184 if (!scop)
2185 return -1;
2186 if (!ext->skip[type])
2187 return 0;
2188 aff = multi_pw_aff_is_affine(ext->skip[type]);
2189 if (aff < 0)
2190 return -1;
2191 return !aff;
2194 /* Does "scop" have a skip condition of the given "type" that
2195 * is affine and holds on the entire domain?
2197 int pet_scop_has_universal_skip(struct pet_scop *scop, enum pet_skip type)
2199 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2200 isl_pw_aff *pa;
2201 isl_set *set;
2202 int is_aff;
2203 int is_univ;
2205 is_aff = pet_scop_has_affine_skip(scop, type);
2206 if (is_aff < 0 || !is_aff)
2207 return is_aff;
2209 pa = isl_multi_pw_aff_get_pw_aff(ext->skip[type], 0);
2210 set = isl_pw_aff_non_zero_set(pa);
2211 is_univ = isl_set_plain_is_universe(set);
2212 isl_set_free(set);
2214 return is_univ;
2217 /* Replace scop->skip[type] by "skip".
2219 struct pet_scop *pet_scop_set_skip(struct pet_scop *scop,
2220 enum pet_skip type, __isl_take isl_multi_pw_aff *skip)
2222 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2224 if (!scop || !skip)
2225 goto error;
2227 isl_multi_pw_aff_free(ext->skip[type]);
2228 ext->skip[type] = skip;
2230 return scop;
2231 error:
2232 isl_multi_pw_aff_free(skip);
2233 return pet_scop_free(scop);
2236 /* Return a copy of scop->skip[type].
2238 __isl_give isl_multi_pw_aff *pet_scop_get_skip(struct pet_scop *scop,
2239 enum pet_skip type)
2241 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2243 if (!scop)
2244 return NULL;
2246 return isl_multi_pw_aff_copy(ext->skip[type]);
2249 /* Assuming scop->skip[type] is an affine expression,
2250 * return the constraints on the parameters for which the skip condition
2251 * holds.
2253 __isl_give isl_set *pet_scop_get_affine_skip_domain(struct pet_scop *scop,
2254 enum pet_skip type)
2256 isl_multi_pw_aff *skip;
2257 isl_pw_aff *pa;
2259 skip = pet_scop_get_skip(scop, type);
2260 pa = isl_multi_pw_aff_get_pw_aff(skip, 0);
2261 isl_multi_pw_aff_free(skip);
2262 return isl_set_params(isl_pw_aff_non_zero_set(pa));
2265 /* Return the identifier of the variable that is accessed by
2266 * the skip condition of the given type.
2268 * The skip condition is assumed not to be an affine condition.
2270 __isl_give isl_id *pet_scop_get_skip_id(struct pet_scop *scop,
2271 enum pet_skip type)
2273 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2275 if (!scop)
2276 return NULL;
2278 return isl_multi_pw_aff_get_tuple_id(ext->skip[type], isl_dim_out);
2281 /* Return an access pet_expr corresponding to the skip condition
2282 * of the given type.
2284 __isl_give pet_expr *pet_scop_get_skip_expr(struct pet_scop *scop,
2285 enum pet_skip type)
2287 return pet_expr_from_index(pet_scop_get_skip(scop, type));
2290 /* Drop the the skip condition scop->skip[type].
2292 void pet_scop_reset_skip(struct pet_scop *scop, enum pet_skip type)
2294 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
2296 if (!scop)
2297 return;
2299 isl_multi_pw_aff_free(ext->skip[type]);
2300 ext->skip[type] = NULL;
2303 /* Make the skip condition (if any) depend on the value of "test" being
2304 * equal to "satisfied".
2306 * We only support the case where the original skip condition is universal,
2307 * i.e., where skipping is unconditional, and where satisfied == 1.
2308 * In this case, the skip condition is changed to skip only when
2309 * "test" is equal to one.
2311 static struct pet_scop *pet_scop_filter_skip(struct pet_scop *scop,
2312 enum pet_skip type, __isl_keep isl_multi_pw_aff *test, int satisfied)
2314 int is_univ = 0;
2316 if (!scop)
2317 return NULL;
2318 if (!pet_scop_has_skip(scop, type))
2319 return scop;
2321 if (satisfied)
2322 is_univ = pet_scop_has_universal_skip(scop, type);
2323 if (is_univ < 0)
2324 return pet_scop_free(scop);
2325 if (satisfied && is_univ) {
2326 isl_multi_pw_aff *skip;
2327 skip = isl_multi_pw_aff_copy(test);
2328 scop = pet_scop_set_skip(scop, type, skip);
2329 if (!scop)
2330 return NULL;
2331 } else {
2332 isl_die(isl_multi_pw_aff_get_ctx(test), isl_error_internal,
2333 "skip expression cannot be filtered",
2334 return pet_scop_free(scop));
2337 return scop;
2340 /* Make all statements in "scop" depend on the value of "test"
2341 * being equal to "satisfied" by adjusting their domains.
2343 struct pet_scop *pet_scop_filter(struct pet_scop *scop,
2344 __isl_take isl_multi_pw_aff *test, int satisfied)
2346 int i;
2348 scop = pet_scop_filter_skip(scop, pet_skip_now, test, satisfied);
2349 scop = pet_scop_filter_skip(scop, pet_skip_later, test, satisfied);
2351 if (!scop || !test)
2352 goto error;
2354 for (i = 0; i < scop->n_stmt; ++i) {
2355 scop->stmts[i] = stmt_filter(scop, scop->stmts[i],
2356 isl_multi_pw_aff_copy(test), satisfied);
2357 if (!scop->stmts[i])
2358 goto error;
2361 isl_multi_pw_aff_free(test);
2362 return scop;
2363 error:
2364 isl_multi_pw_aff_free(test);
2365 return pet_scop_free(scop);
2368 /* Add all parameters in "expr" to "space" and return the result.
2370 static __isl_give isl_space *expr_collect_params(__isl_keep pet_expr *expr,
2371 __isl_take isl_space *space)
2373 int i;
2375 if (!expr)
2376 goto error;
2377 for (i = 0; i < expr->n_arg; ++i)
2378 space = expr_collect_params(expr->args[i], space);
2380 if (expr->type == pet_expr_access)
2381 space = isl_space_align_params(space,
2382 isl_map_get_space(expr->acc.access));
2384 return space;
2385 error:
2386 pet_expr_free(expr);
2387 return isl_space_free(space);
2390 /* Add all parameters in "stmt" to "space" and return the result.
2392 static __isl_give isl_space *stmt_collect_params(struct pet_stmt *stmt,
2393 __isl_take isl_space *space)
2395 int i;
2397 if (!stmt)
2398 return isl_space_free(space);
2400 space = isl_space_align_params(space, isl_set_get_space(stmt->domain));
2401 space = isl_space_align_params(space,
2402 isl_map_get_space(stmt->schedule));
2403 for (i = 0; i < stmt->n_arg; ++i)
2404 space = expr_collect_params(stmt->args[i], space);
2405 space = expr_collect_params(stmt->body, space);
2407 return space;
2410 /* Add all parameters in "array" to "space" and return the result.
2412 static __isl_give isl_space *array_collect_params(struct pet_array *array,
2413 __isl_take isl_space *space)
2415 if (!array)
2416 return isl_space_free(space);
2418 space = isl_space_align_params(space,
2419 isl_set_get_space(array->context));
2420 space = isl_space_align_params(space, isl_set_get_space(array->extent));
2422 return space;
2425 /* Add all parameters in "scop" to "space" and return the result.
2427 static __isl_give isl_space *scop_collect_params(struct pet_scop *scop,
2428 __isl_take isl_space *space)
2430 int i;
2432 if (!scop)
2433 return isl_space_free(space);
2435 for (i = 0; i < scop->n_array; ++i)
2436 space = array_collect_params(scop->arrays[i], space);
2438 for (i = 0; i < scop->n_stmt; ++i)
2439 space = stmt_collect_params(scop->stmts[i], space);
2441 return space;
2444 /* Add all parameters in "space" to the domain, schedule and
2445 * all access relations in "stmt".
2447 static struct pet_stmt *stmt_propagate_params(struct pet_stmt *stmt,
2448 __isl_take isl_space *space)
2450 int i;
2452 if (!stmt)
2453 goto error;
2455 stmt->domain = isl_set_align_params(stmt->domain,
2456 isl_space_copy(space));
2457 stmt->schedule = isl_map_align_params(stmt->schedule,
2458 isl_space_copy(space));
2460 for (i = 0; i < stmt->n_arg; ++i) {
2461 stmt->args[i] = pet_expr_align_params(stmt->args[i],
2462 isl_space_copy(space));
2463 if (!stmt->args[i])
2464 goto error;
2466 stmt->body = pet_expr_align_params(stmt->body, isl_space_copy(space));
2468 if (!stmt->domain || !stmt->schedule || !stmt->body)
2469 goto error;
2471 isl_space_free(space);
2472 return stmt;
2473 error:
2474 isl_space_free(space);
2475 return pet_stmt_free(stmt);
2478 /* Add all parameters in "space" to "array".
2480 static struct pet_array *array_propagate_params(struct pet_array *array,
2481 __isl_take isl_space *space)
2483 if (!array)
2484 goto error;
2486 array->context = isl_set_align_params(array->context,
2487 isl_space_copy(space));
2488 array->extent = isl_set_align_params(array->extent,
2489 isl_space_copy(space));
2490 if (array->value_bounds) {
2491 array->value_bounds = isl_set_align_params(array->value_bounds,
2492 isl_space_copy(space));
2493 if (!array->value_bounds)
2494 goto error;
2497 if (!array->context || !array->extent)
2498 goto error;
2500 isl_space_free(space);
2501 return array;
2502 error:
2503 isl_space_free(space);
2504 return pet_array_free(array);
2507 /* Add all parameters in "space" to "scop".
2509 static struct pet_scop *scop_propagate_params(struct pet_scop *scop,
2510 __isl_take isl_space *space)
2512 int i;
2514 if (!scop)
2515 goto error;
2517 for (i = 0; i < scop->n_array; ++i) {
2518 scop->arrays[i] = array_propagate_params(scop->arrays[i],
2519 isl_space_copy(space));
2520 if (!scop->arrays[i])
2521 goto error;
2524 for (i = 0; i < scop->n_stmt; ++i) {
2525 scop->stmts[i] = stmt_propagate_params(scop->stmts[i],
2526 isl_space_copy(space));
2527 if (!scop->stmts[i])
2528 goto error;
2531 isl_space_free(space);
2532 return scop;
2533 error:
2534 isl_space_free(space);
2535 return pet_scop_free(scop);
2538 /* Update all isl_sets and isl_maps in "scop" such that they all
2539 * have the same parameters.
2541 struct pet_scop *pet_scop_align_params(struct pet_scop *scop)
2543 isl_space *space;
2545 if (!scop)
2546 return NULL;
2548 space = isl_set_get_space(scop->context);
2549 space = scop_collect_params(scop, space);
2551 scop->context = isl_set_align_params(scop->context,
2552 isl_space_copy(space));
2553 scop = scop_propagate_params(scop, space);
2555 if (scop && !scop->context)
2556 return pet_scop_free(scop);
2558 return scop;
2561 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
2562 * in "space" by a value equal to the corresponding parameter.
2564 static struct pet_stmt *stmt_detect_parameter_accesses(struct pet_stmt *stmt,
2565 __isl_take isl_space *space)
2567 if (!stmt)
2568 goto error;
2570 stmt->body = pet_expr_detect_parameter_accesses(stmt->body,
2571 isl_space_copy(space));
2573 if (!stmt->domain || !stmt->schedule || !stmt->body)
2574 goto error;
2576 isl_space_free(space);
2577 return stmt;
2578 error:
2579 isl_space_free(space);
2580 return pet_stmt_free(stmt);
2583 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
2584 * in "space" by a value equal to the corresponding parameter.
2586 static struct pet_scop *scop_detect_parameter_accesses(struct pet_scop *scop,
2587 __isl_take isl_space *space)
2589 int i;
2591 if (!scop)
2592 goto error;
2594 for (i = 0; i < scop->n_stmt; ++i) {
2595 scop->stmts[i] = stmt_detect_parameter_accesses(scop->stmts[i],
2596 isl_space_copy(space));
2597 if (!scop->stmts[i])
2598 goto error;
2601 isl_space_free(space);
2602 return scop;
2603 error:
2604 isl_space_free(space);
2605 return pet_scop_free(scop);
2608 /* Replace all accesses to (0D) arrays that correspond to any of
2609 * the parameters used in "scop" by a value equal
2610 * to the corresponding parameter.
2612 struct pet_scop *pet_scop_detect_parameter_accesses(struct pet_scop *scop)
2614 isl_space *space;
2616 if (!scop)
2617 return NULL;
2619 space = isl_set_get_space(scop->context);
2620 space = scop_collect_params(scop, space);
2622 scop = scop_detect_parameter_accesses(scop, space);
2624 return scop;
2627 /* Add the access relation of the access expression "expr" to "accesses" and
2628 * return the result.
2629 * The domain of the access relation is intersected with "domain".
2630 * If "tag" is set, then the access relation is tagged with
2631 * the corresponding reference identifier.
2633 static __isl_give isl_union_map *expr_collect_access(__isl_keep pet_expr *expr,
2634 int tag, __isl_take isl_union_map *accesses, __isl_keep isl_set *domain)
2636 isl_map *access;
2638 access = pet_expr_access_get_may_access(expr);
2639 access = isl_map_intersect_domain(access, isl_set_copy(domain));
2640 if (tag)
2641 access = pet_expr_tag_access(expr, access);
2642 return isl_union_map_add_map(accesses, access);
2645 /* Add all read access relations (if "read" is set) and/or all write
2646 * access relations (if "write" is set) to "accesses" and return the result.
2647 * The domains of the access relations are intersected with "domain".
2648 * If "tag" is set, then the access relations are tagged with
2649 * the corresponding reference identifiers.
2651 * If "must" is set, then we only add the accesses that are definitely
2652 * performed. Otherwise, we add all potential accesses.
2653 * In particular, if the access has any arguments, then if "must" is
2654 * set we currently skip the access completely. If "must" is not set,
2655 * we project out the values of the access arguments.
2657 static __isl_give isl_union_map *expr_collect_accesses(
2658 __isl_keep pet_expr *expr, int read, int write, int must, int tag,
2659 __isl_take isl_union_map *accesses, __isl_keep isl_set *domain)
2661 int i;
2662 isl_id *id;
2663 isl_space *dim;
2665 if (!expr)
2666 return isl_union_map_free(accesses);
2668 for (i = 0; i < expr->n_arg; ++i)
2669 accesses = expr_collect_accesses(expr->args[i],
2670 read, write, must, tag, accesses, domain);
2672 if (expr->type == pet_expr_access && !pet_expr_is_affine(expr) &&
2673 ((read && expr->acc.read) || (write && expr->acc.write)) &&
2674 (!must || expr->n_arg == 0)) {
2675 accesses = expr_collect_access(expr, tag, accesses, domain);
2678 return accesses;
2681 /* Collect and return all read access relations (if "read" is set)
2682 * and/or all write access relations (if "write" is set) in "stmt".
2683 * If "tag" is set, then the access relations are tagged with
2684 * the corresponding reference identifiers.
2685 * If "kill" is set, then "stmt" is a kill statement and we simply
2686 * add the argument of the kill operation.
2688 * If "must" is set, then we only add the accesses that are definitely
2689 * performed. Otherwise, we add all potential accesses.
2690 * In particular, if the statement has any arguments, then if "must" is
2691 * set we currently skip the statement completely. If "must" is not set,
2692 * we project out the values of the statement arguments.
2694 static __isl_give isl_union_map *stmt_collect_accesses(struct pet_stmt *stmt,
2695 int read, int write, int kill, int must, int tag,
2696 __isl_take isl_space *dim)
2698 isl_union_map *accesses;
2699 isl_set *domain;
2701 if (!stmt)
2702 return NULL;
2704 accesses = isl_union_map_empty(dim);
2706 if (must && stmt->n_arg > 0)
2707 return accesses;
2709 domain = isl_set_copy(stmt->domain);
2710 if (isl_set_is_wrapping(domain))
2711 domain = isl_map_domain(isl_set_unwrap(domain));
2713 if (kill)
2714 accesses = expr_collect_access(stmt->body->args[0], tag,
2715 accesses, domain);
2716 else
2717 accesses = expr_collect_accesses(stmt->body, read, write,
2718 must, tag, accesses, domain);
2719 isl_set_free(domain);
2721 return accesses;
2724 /* Is "stmt" an assignment statement?
2726 int pet_stmt_is_assign(struct pet_stmt *stmt)
2728 if (!stmt)
2729 return 0;
2730 if (stmt->body->type != pet_expr_op)
2731 return 0;
2732 return stmt->body->op == pet_op_assign;
2735 /* Is "stmt" a kill statement?
2737 int pet_stmt_is_kill(struct pet_stmt *stmt)
2739 if (!stmt)
2740 return 0;
2741 if (stmt->body->type != pet_expr_op)
2742 return 0;
2743 return stmt->body->op == pet_op_kill;
2746 /* Is "stmt" an assume statement?
2748 int pet_stmt_is_assume(struct pet_stmt *stmt)
2750 if (!stmt)
2751 return 0;
2752 return pet_expr_is_assume(stmt->body);
2755 /* Compute a mapping from all arrays (of structs) in scop
2756 * to their innermost arrays.
2758 * In particular, for each array of a primitive type, the result
2759 * contains the identity mapping on that array.
2760 * For each array involving member accesses, the result
2761 * contains a mapping from the elements of any intermediate array of structs
2762 * to all corresponding elements of the innermost nested arrays.
2764 static __isl_give isl_union_map *compute_to_inner(struct pet_scop *scop)
2766 int i;
2767 isl_union_map *to_inner;
2769 to_inner = isl_union_map_empty(isl_set_get_space(scop->context));
2771 for (i = 0; i < scop->n_array; ++i) {
2772 struct pet_array *array = scop->arrays[i];
2773 isl_set *set;
2774 isl_map *map, *gist;
2776 if (array->element_is_record)
2777 continue;
2779 map = isl_set_identity(isl_set_copy(array->extent));
2781 set = isl_map_domain(isl_map_copy(map));
2782 gist = isl_map_copy(map);
2783 gist = isl_map_gist_domain(gist, isl_set_copy(set));
2784 to_inner = isl_union_map_add_map(to_inner, gist);
2786 while (set && isl_set_is_wrapping(set)) {
2787 isl_id *id;
2788 isl_map *wrapped;
2790 id = isl_set_get_tuple_id(set);
2791 wrapped = isl_set_unwrap(set);
2792 wrapped = isl_map_domain_map(wrapped);
2793 wrapped = isl_map_set_tuple_id(wrapped, isl_dim_in, id);
2794 map = isl_map_apply_domain(map, wrapped);
2795 set = isl_map_domain(isl_map_copy(map));
2796 gist = isl_map_copy(map);
2797 gist = isl_map_gist_domain(gist, isl_set_copy(set));
2798 to_inner = isl_union_map_add_map(to_inner, gist);
2801 isl_set_free(set);
2802 isl_map_free(map);
2805 return to_inner;
2808 /* Collect and return all read access relations (if "read" is set)
2809 * and/or all write access relations (if "write" is set) in "scop".
2810 * If "kill" is set, then we only add the arguments of kill operations.
2811 * If "must" is set, then we only add the accesses that are definitely
2812 * performed. Otherwise, we add all potential accesses.
2813 * If "tag" is set, then the access relations are tagged with
2814 * the corresponding reference identifiers.
2815 * For accesses to structures, the returned access relation accesses
2816 * all individual fields in the structures.
2818 static __isl_give isl_union_map *scop_collect_accesses(struct pet_scop *scop,
2819 int read, int write, int kill, int must, int tag)
2821 int i;
2822 isl_union_map *accesses;
2823 isl_union_set *arrays;
2824 isl_union_map *to_inner;
2826 if (!scop)
2827 return NULL;
2829 accesses = isl_union_map_empty(isl_set_get_space(scop->context));
2831 for (i = 0; i < scop->n_stmt; ++i) {
2832 struct pet_stmt *stmt = scop->stmts[i];
2833 isl_union_map *accesses_i;
2834 isl_space *space;
2836 if (kill && !pet_stmt_is_kill(stmt))
2837 continue;
2839 space = isl_set_get_space(scop->context);
2840 accesses_i = stmt_collect_accesses(stmt, read, write, kill,
2841 must, tag, space);
2842 accesses = isl_union_map_union(accesses, accesses_i);
2845 arrays = isl_union_set_empty(isl_union_map_get_space(accesses));
2846 for (i = 0; i < scop->n_array; ++i) {
2847 isl_set *extent = isl_set_copy(scop->arrays[i]->extent);
2848 arrays = isl_union_set_add_set(arrays, extent);
2850 accesses = isl_union_map_intersect_range(accesses, arrays);
2852 to_inner = compute_to_inner(scop);
2853 accesses = isl_union_map_apply_range(accesses, to_inner);
2855 return accesses;
2858 /* Collect all potential read access relations.
2860 __isl_give isl_union_map *pet_scop_collect_may_reads(struct pet_scop *scop)
2862 return scop_collect_accesses(scop, 1, 0, 0, 0, 0);
2865 /* Collect all potential write access relations.
2867 __isl_give isl_union_map *pet_scop_collect_may_writes(struct pet_scop *scop)
2869 return scop_collect_accesses(scop, 0, 1, 0, 0, 0);
2872 /* Collect all definite write access relations.
2874 __isl_give isl_union_map *pet_scop_collect_must_writes(struct pet_scop *scop)
2876 return scop_collect_accesses(scop, 0, 1, 0, 1, 0);
2879 /* Collect all definite kill access relations.
2881 __isl_give isl_union_map *pet_scop_collect_must_kills(struct pet_scop *scop)
2883 return scop_collect_accesses(scop, 0, 0, 1, 1, 0);
2886 /* Collect all tagged potential read access relations.
2888 __isl_give isl_union_map *pet_scop_collect_tagged_may_reads(
2889 struct pet_scop *scop)
2891 return scop_collect_accesses(scop, 1, 0, 0, 0, 1);
2894 /* Collect all tagged potential write access relations.
2896 __isl_give isl_union_map *pet_scop_collect_tagged_may_writes(
2897 struct pet_scop *scop)
2899 return scop_collect_accesses(scop, 0, 1, 0, 0, 1);
2902 /* Collect all tagged definite write access relations.
2904 __isl_give isl_union_map *pet_scop_collect_tagged_must_writes(
2905 struct pet_scop *scop)
2907 return scop_collect_accesses(scop, 0, 1, 0, 1, 1);
2910 /* Collect all tagged definite kill access relations.
2912 __isl_give isl_union_map *pet_scop_collect_tagged_must_kills(
2913 struct pet_scop *scop)
2915 return scop_collect_accesses(scop, 0, 0, 1, 1, 1);
2918 /* Collect and return the union of iteration domains in "scop".
2920 __isl_give isl_union_set *pet_scop_collect_domains(struct pet_scop *scop)
2922 int i;
2923 isl_set *domain_i;
2924 isl_union_set *domain;
2926 if (!scop)
2927 return NULL;
2929 domain = isl_union_set_empty(isl_set_get_space(scop->context));
2931 for (i = 0; i < scop->n_stmt; ++i) {
2932 domain_i = isl_set_copy(scop->stmts[i]->domain);
2933 domain = isl_union_set_add_set(domain, domain_i);
2936 return domain;
2939 /* Collect and return the schedules of the statements in "scop".
2940 * The range is normalized to the maximal number of scheduling
2941 * dimensions.
2943 __isl_give isl_union_map *pet_scop_collect_schedule(struct pet_scop *scop)
2945 int i, j;
2946 isl_map *schedule_i;
2947 isl_union_map *schedule;
2948 int depth, max_depth = 0;
2950 if (!scop)
2951 return NULL;
2953 schedule = isl_union_map_empty(isl_set_get_space(scop->context));
2955 for (i = 0; i < scop->n_stmt; ++i) {
2956 depth = isl_map_dim(scop->stmts[i]->schedule, isl_dim_out);
2957 if (depth > max_depth)
2958 max_depth = depth;
2961 for (i = 0; i < scop->n_stmt; ++i) {
2962 schedule_i = isl_map_copy(scop->stmts[i]->schedule);
2963 depth = isl_map_dim(schedule_i, isl_dim_out);
2964 schedule_i = isl_map_add_dims(schedule_i, isl_dim_out,
2965 max_depth - depth);
2966 for (j = depth; j < max_depth; ++j)
2967 schedule_i = isl_map_fix_si(schedule_i,
2968 isl_dim_out, j, 0);
2969 schedule = isl_union_map_add_map(schedule, schedule_i);
2972 return schedule;
2975 /* Add a reference identifier to all access expressions in "stmt".
2976 * "n_ref" points to an integer that contains the sequence number
2977 * of the next reference.
2979 static struct pet_stmt *stmt_add_ref_ids(struct pet_stmt *stmt, int *n_ref)
2981 int i;
2983 if (!stmt)
2984 return NULL;
2986 for (i = 0; i < stmt->n_arg; ++i) {
2987 stmt->args[i] = pet_expr_add_ref_ids(stmt->args[i], n_ref);
2988 if (!stmt->args[i])
2989 return pet_stmt_free(stmt);
2992 stmt->body = pet_expr_add_ref_ids(stmt->body, n_ref);
2993 if (!stmt->body)
2994 return pet_stmt_free(stmt);
2996 return stmt;
2999 /* Add a reference identifier to all access expressions in "scop".
3001 struct pet_scop *pet_scop_add_ref_ids(struct pet_scop *scop)
3003 int i;
3004 int n_ref;
3006 if (!scop)
3007 return NULL;
3009 n_ref = 0;
3010 for (i = 0; i < scop->n_stmt; ++i) {
3011 scop->stmts[i] = stmt_add_ref_ids(scop->stmts[i], &n_ref);
3012 if (!scop->stmts[i])
3013 return pet_scop_free(scop);
3016 return scop;
3019 /* Reset the user pointer on all parameter ids in "array".
3021 static struct pet_array *array_anonymize(struct pet_array *array)
3023 if (!array)
3024 return NULL;
3026 array->context = isl_set_reset_user(array->context);
3027 array->extent = isl_set_reset_user(array->extent);
3028 if (!array->context || !array->extent)
3029 return pet_array_free(array);
3031 return array;
3034 /* Reset the user pointer on all parameter and tuple ids in "stmt".
3036 static struct pet_stmt *stmt_anonymize(struct pet_stmt *stmt)
3038 int i;
3039 isl_space *space;
3040 isl_set *domain;
3042 if (!stmt)
3043 return NULL;
3045 stmt->domain = isl_set_reset_user(stmt->domain);
3046 stmt->schedule = isl_map_reset_user(stmt->schedule);
3047 if (!stmt->domain || !stmt->schedule)
3048 return pet_stmt_free(stmt);
3050 for (i = 0; i < stmt->n_arg; ++i) {
3051 stmt->args[i] = pet_expr_anonymize(stmt->args[i]);
3052 if (!stmt->args[i])
3053 return pet_stmt_free(stmt);
3056 stmt->body = pet_expr_anonymize(stmt->body);
3057 if (!stmt->body)
3058 return pet_stmt_free(stmt);
3060 return stmt;
3063 /* Reset the user pointer on the tuple ids and all parameter ids
3064 * in "implication".
3066 static struct pet_implication *implication_anonymize(
3067 struct pet_implication *implication)
3069 if (!implication)
3070 return NULL;
3072 implication->extension = isl_map_reset_user(implication->extension);
3073 if (!implication->extension)
3074 return pet_implication_free(implication);
3076 return implication;
3079 /* Reset the user pointer on all parameter and tuple ids in "scop".
3081 struct pet_scop *pet_scop_anonymize(struct pet_scop *scop)
3083 int i;
3085 if (!scop)
3086 return NULL;
3088 scop->context = isl_set_reset_user(scop->context);
3089 scop->context_value = isl_set_reset_user(scop->context_value);
3090 if (!scop->context || !scop->context_value)
3091 return pet_scop_free(scop);
3093 for (i = 0; i < scop->n_array; ++i) {
3094 scop->arrays[i] = array_anonymize(scop->arrays[i]);
3095 if (!scop->arrays[i])
3096 return pet_scop_free(scop);
3099 for (i = 0; i < scop->n_stmt; ++i) {
3100 scop->stmts[i] = stmt_anonymize(scop->stmts[i]);
3101 if (!scop->stmts[i])
3102 return pet_scop_free(scop);
3105 for (i = 0; i < scop->n_implication; ++i) {
3106 scop->implications[i] =
3107 implication_anonymize(scop->implications[i]);
3108 if (!scop->implications[i])
3109 return pet_scop_free(scop);
3112 return scop;
3115 /* Compute the gist of the iteration domain and all access relations
3116 * of "stmt" based on the constraints on the parameters specified by "context"
3117 * and the constraints on the values of nested accesses specified
3118 * by "value_bounds".
3120 static struct pet_stmt *stmt_gist(struct pet_stmt *stmt,
3121 __isl_keep isl_set *context, __isl_keep isl_union_map *value_bounds)
3123 int i;
3124 isl_set *domain;
3126 if (!stmt)
3127 return NULL;
3129 domain = isl_set_copy(stmt->domain);
3130 if (stmt->n_arg > 0)
3131 domain = isl_map_domain(isl_set_unwrap(domain));
3133 domain = isl_set_intersect_params(domain, isl_set_copy(context));
3135 for (i = 0; i < stmt->n_arg; ++i) {
3136 stmt->args[i] = pet_expr_gist(stmt->args[i],
3137 domain, value_bounds);
3138 if (!stmt->args[i])
3139 goto error;
3142 stmt->body = pet_expr_gist(stmt->body, domain, value_bounds);
3143 if (!stmt->body)
3144 goto error;
3146 isl_set_free(domain);
3148 domain = isl_set_universe(pet_stmt_get_space(stmt));
3149 domain = isl_set_intersect_params(domain, isl_set_copy(context));
3150 if (stmt->n_arg > 0)
3151 domain = pet_value_bounds_apply(domain, stmt->n_arg, stmt->args,
3152 value_bounds);
3153 stmt->domain = isl_set_gist(stmt->domain, domain);
3154 if (!stmt->domain)
3155 return pet_stmt_free(stmt);
3157 return stmt;
3158 error:
3159 isl_set_free(domain);
3160 return pet_stmt_free(stmt);
3163 /* Compute the gist of the extent of the array
3164 * based on the constraints on the parameters specified by "context".
3166 static struct pet_array *array_gist(struct pet_array *array,
3167 __isl_keep isl_set *context)
3169 if (!array)
3170 return NULL;
3172 array->extent = isl_set_gist_params(array->extent,
3173 isl_set_copy(context));
3174 if (!array->extent)
3175 return pet_array_free(array);
3177 return array;
3180 /* Compute the gist of all sets and relations in "scop"
3181 * based on the constraints on the parameters specified by "scop->context"
3182 * and the constraints on the values of nested accesses specified
3183 * by "value_bounds".
3185 struct pet_scop *pet_scop_gist(struct pet_scop *scop,
3186 __isl_keep isl_union_map *value_bounds)
3188 int i;
3190 if (!scop)
3191 return NULL;
3193 scop->context = isl_set_coalesce(scop->context);
3194 if (!scop->context)
3195 return pet_scop_free(scop);
3197 for (i = 0; i < scop->n_array; ++i) {
3198 scop->arrays[i] = array_gist(scop->arrays[i], scop->context);
3199 if (!scop->arrays[i])
3200 return pet_scop_free(scop);
3203 for (i = 0; i < scop->n_stmt; ++i) {
3204 scop->stmts[i] = stmt_gist(scop->stmts[i], scop->context,
3205 value_bounds);
3206 if (!scop->stmts[i])
3207 return pet_scop_free(scop);
3210 return scop;
3213 /* Intersect the context of "scop" with "context".
3214 * To ensure that we don't introduce any unnamed parameters in
3215 * the context of "scop", we first remove the unnamed parameters
3216 * from "context".
3218 struct pet_scop *pet_scop_restrict_context(struct pet_scop *scop,
3219 __isl_take isl_set *context)
3221 if (!scop)
3222 goto error;
3224 context = pet_nested_remove_from_set(context);
3225 scop->context = isl_set_intersect(scop->context, context);
3226 if (!scop->context)
3227 return pet_scop_free(scop);
3229 return scop;
3230 error:
3231 isl_set_free(context);
3232 return pet_scop_free(scop);
3235 /* Drop the current context of "scop". That is, replace the context
3236 * by a universal set.
3238 struct pet_scop *pet_scop_reset_context(struct pet_scop *scop)
3240 isl_space *space;
3242 if (!scop)
3243 return NULL;
3245 space = isl_set_get_space(scop->context);
3246 isl_set_free(scop->context);
3247 scop->context = isl_set_universe(space);
3248 if (!scop->context)
3249 return pet_scop_free(scop);
3251 return scop;
3254 /* Append "array" to the arrays of "scop".
3256 struct pet_scop *pet_scop_add_array(struct pet_scop *scop,
3257 struct pet_array *array)
3259 isl_ctx *ctx;
3260 struct pet_array **arrays;
3262 if (!array || !scop)
3263 goto error;
3265 ctx = isl_set_get_ctx(scop->context);
3266 arrays = isl_realloc_array(ctx, scop->arrays, struct pet_array *,
3267 scop->n_array + 1);
3268 if (!arrays)
3269 goto error;
3270 scop->arrays = arrays;
3271 scop->arrays[scop->n_array] = array;
3272 scop->n_array++;
3274 return scop;
3275 error:
3276 pet_array_free(array);
3277 return pet_scop_free(scop);
3280 /* Create an index expression for an access to a virtual array
3281 * representing the result of a condition.
3282 * Unlike other accessed data, the id of the array is NULL as
3283 * there is no ValueDecl in the program corresponding to the virtual
3284 * array.
3285 * The index expression is created as an identity mapping on "space".
3286 * That is, the dimension of the array is the same as that of "space".
3287 * Currently, the array starts out as a scalar, but grows along with the
3288 * statement writing to the array in pet_scop_embed.
3290 __isl_give isl_multi_pw_aff *pet_create_test_index(__isl_take isl_space *space,
3291 int test_nr)
3293 isl_id *id;
3294 char name[50];
3296 snprintf(name, sizeof(name), "__pet_test_%d", test_nr);
3297 id = isl_id_alloc(isl_space_get_ctx(space), name, NULL);
3298 space = isl_space_map_from_set(space);
3299 space = isl_space_set_tuple_id(space, isl_dim_out, id);
3300 return isl_multi_pw_aff_identity(space);
3303 /* Add an array with the given extent to the list
3304 * of arrays in "scop" and return the extended pet_scop.
3305 * Specifically, the extent is determined by the image of "domain"
3306 * under "index".
3307 * "int_size" is the number of bytes needed to represent values of type "int".
3308 * The array is marked as attaining values 0 and 1 only and
3309 * as each element being assigned at most once.
3311 struct pet_scop *pet_scop_add_boolean_array(struct pet_scop *scop,
3312 __isl_take isl_set *domain, __isl_take isl_multi_pw_aff *index,
3313 int int_size)
3315 isl_ctx *ctx;
3316 isl_space *space;
3317 struct pet_array *array;
3318 isl_map *access;
3320 if (!scop || !domain || !index)
3321 goto error;
3323 ctx = isl_multi_pw_aff_get_ctx(index);
3324 array = isl_calloc_type(ctx, struct pet_array);
3325 if (!array)
3326 goto error;
3328 access = isl_map_from_multi_pw_aff(index);
3329 access = isl_map_intersect_domain(access, domain);
3330 array->extent = isl_map_range(access);
3331 space = isl_space_params_alloc(ctx, 0);
3332 array->context = isl_set_universe(space);
3333 space = isl_space_set_alloc(ctx, 0, 1);
3334 array->value_bounds = isl_set_universe(space);
3335 array->value_bounds = isl_set_lower_bound_si(array->value_bounds,
3336 isl_dim_set, 0, 0);
3337 array->value_bounds = isl_set_upper_bound_si(array->value_bounds,
3338 isl_dim_set, 0, 1);
3339 array->element_type = strdup("int");
3340 array->element_size = int_size;
3341 array->uniquely_defined = 1;
3343 if (!array->extent || !array->context)
3344 array = pet_array_free(array);
3346 scop = pet_scop_add_array(scop, array);
3348 return scop;
3349 error:
3350 isl_set_free(domain);
3351 isl_multi_pw_aff_free(index);
3352 return pet_scop_free(scop);
3355 /* Create and return an implication on filter values equal to "satisfied"
3356 * with extension "map".
3358 static struct pet_implication *new_implication(__isl_take isl_map *map,
3359 int satisfied)
3361 isl_ctx *ctx;
3362 struct pet_implication *implication;
3364 if (!map)
3365 return NULL;
3366 ctx = isl_map_get_ctx(map);
3367 implication = isl_alloc_type(ctx, struct pet_implication);
3368 if (!implication)
3369 goto error;
3371 implication->extension = map;
3372 implication->satisfied = satisfied;
3374 return implication;
3375 error:
3376 isl_map_free(map);
3377 return NULL;
3380 /* Add an implication on filter values equal to "satisfied"
3381 * with extension "map" to "scop".
3383 struct pet_scop *pet_scop_add_implication(struct pet_scop *scop,
3384 __isl_take isl_map *map, int satisfied)
3386 isl_ctx *ctx;
3387 struct pet_implication *implication;
3388 struct pet_implication **implications;
3390 implication = new_implication(map, satisfied);
3391 if (!scop || !implication)
3392 goto error;
3394 ctx = isl_set_get_ctx(scop->context);
3395 implications = isl_realloc_array(ctx, scop->implications,
3396 struct pet_implication *,
3397 scop->n_implication + 1);
3398 if (!implications)
3399 goto error;
3400 scop->implications = implications;
3401 scop->implications[scop->n_implication] = implication;
3402 scop->n_implication++;
3404 return scop;
3405 error:
3406 pet_implication_free(implication);
3407 return pet_scop_free(scop);
3410 /* Given an access expression, check if it is data dependent.
3411 * If so, set *found and abort the search.
3413 static int is_data_dependent(__isl_keep pet_expr *expr, void *user)
3415 int *found = user;
3417 if (pet_expr_get_n_arg(expr) > 0) {
3418 *found = 1;
3419 return -1;
3422 return 0;
3425 /* Does "scop" contain any data dependent accesses?
3427 * Check the body of each statement for such accesses.
3429 int pet_scop_has_data_dependent_accesses(struct pet_scop *scop)
3431 int i;
3432 int found = 0;
3434 if (!scop)
3435 return -1;
3437 for (i = 0; i < scop->n_stmt; ++i) {
3438 int r = pet_expr_foreach_access_expr(scop->stmts[i]->body,
3439 &is_data_dependent, &found);
3440 if (r < 0 && !found)
3441 return -1;
3442 if (found)
3443 return found;
3446 return found;
3449 /* Does "scop" contain and data dependent conditions?
3451 int pet_scop_has_data_dependent_conditions(struct pet_scop *scop)
3453 int i;
3455 if (!scop)
3456 return -1;
3458 for (i = 0; i < scop->n_stmt; ++i)
3459 if (scop->stmts[i]->n_arg > 0)
3460 return 1;
3462 return 0;
3465 /* Keep track of the "input" file inside the (extended) "scop".
3467 struct pet_scop *pet_scop_set_input_file(struct pet_scop *scop, FILE *input)
3469 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
3471 if (!scop)
3472 return NULL;
3474 ext->input = input;
3476 return scop;
3479 /* Print the original code corresponding to "scop" to printer "p".
3481 * pet_scop_print_original can only be called from
3482 * a pet_transform_C_source callback. This means that the input
3483 * file is stored in the extended scop and that the printer prints
3484 * to a file.
3486 __isl_give isl_printer *pet_scop_print_original(struct pet_scop *scop,
3487 __isl_take isl_printer *p)
3489 struct pet_scop_ext *ext = (struct pet_scop_ext *) scop;
3490 FILE *output;
3491 unsigned start, end;
3493 if (!scop || !p)
3494 return isl_printer_free(p);
3496 if (!ext->input)
3497 isl_die(isl_printer_get_ctx(p), isl_error_invalid,
3498 "no input file stored in scop",
3499 return isl_printer_free(p));
3501 output = isl_printer_get_file(p);
3502 if (!output)
3503 return isl_printer_free(p);
3505 start = pet_loc_get_start(scop->loc);
3506 end = pet_loc_get_end(scop->loc);
3507 if (copy(ext->input, output, start, end) < 0)
3508 return isl_printer_free(p);
3510 return p;