pet_stmt_embed: handle NULL stmt
[pet.git] / scop.c
blob47925428fe322f39879d3348b911018e4cdb0630
1 /*
2 * Copyright 2011 Leiden University. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY LEIDEN UNIVERSITY ''AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LEIDEN UNIVERSITY OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * The views and conclusions contained in the software and documentation
29 * are those of the authors and should not be interpreted as
30 * representing official policies, either expressed or implied, of
31 * Leiden University.
32 */
34 #include <isl/constraint.h>
35 #include <isl/union_set.h>
37 #include "scop.h"
39 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
41 static char *type_str[] = {
42 [pet_expr_access] = "access",
43 [pet_expr_call] = "call",
44 [pet_expr_double] = "double",
45 [pet_expr_unary] = "unary",
46 [pet_expr_binary] = "binary",
47 [pet_expr_ternary] = "ternary"
50 static char *op_str[] = {
51 [pet_op_add_assign] = "+=",
52 [pet_op_sub_assign] = "-=",
53 [pet_op_mul_assign] = "*=",
54 [pet_op_div_assign] = "/=",
55 [pet_op_assign] = "=",
56 [pet_op_add] = "+",
57 [pet_op_sub] = "-",
58 [pet_op_mul] = "*",
59 [pet_op_div] = "/",
60 [pet_op_eq] = "==",
61 [pet_op_le] = "<=",
62 [pet_op_lt] = "<",
63 [pet_op_gt] = ">",
64 [pet_op_minus] = "-"
67 const char *pet_op_str(enum pet_op_type op)
69 return op_str[op];
72 const char *pet_type_str(enum pet_expr_type type)
74 return type_str[type];
77 enum pet_op_type pet_str_op(const char *str)
79 int i;
81 for (i = 0; i < ARRAY_SIZE(op_str); ++i)
82 if (!strcmp(op_str[i], str))
83 return i;
85 return -1;
88 enum pet_expr_type pet_str_type(const char *str)
90 int i;
92 for (i = 0; i < ARRAY_SIZE(type_str); ++i)
93 if (!strcmp(type_str[i], str))
94 return i;
96 return -1;
99 /* Construct a pet_expr from an access relation.
100 * By default, it is considered to be a read access.
102 struct pet_expr *pet_expr_from_access(__isl_take isl_map *access)
104 isl_ctx *ctx = isl_map_get_ctx(access);
105 struct pet_expr *expr;
107 if (!access)
108 return NULL;
109 expr = isl_calloc_type(ctx, struct pet_expr);
110 if (!expr)
111 goto error;
113 expr->type = pet_expr_access;
114 expr->acc.access = access;
115 expr->acc.read = 1;
116 expr->acc.write = 0;
118 return expr;
119 error:
120 isl_map_free(access);
121 return NULL;
124 /* Construct a unary pet_expr that performs "op" on "arg".
126 struct pet_expr *pet_expr_new_unary(isl_ctx *ctx, enum pet_op_type op,
127 struct pet_expr *arg)
129 struct pet_expr *expr;
131 if (!arg)
132 goto error;
133 expr = isl_alloc_type(ctx, struct pet_expr);
134 if (!expr)
135 goto error;
137 expr->type = pet_expr_unary;
138 expr->op = op;
139 expr->n_arg = 1;
140 expr->args = isl_calloc_array(ctx, struct pet_expr *, 1);
141 if (!expr->args)
142 goto error;
143 expr->args[pet_un_arg] = arg;
145 return expr;
146 error:
147 pet_expr_free(arg);
148 return NULL;
151 /* Construct a binary pet_expr that performs "op" on "lhs" and "rhs".
153 struct pet_expr *pet_expr_new_binary(isl_ctx *ctx, enum pet_op_type op,
154 struct pet_expr *lhs, struct pet_expr *rhs)
156 struct pet_expr *expr;
158 if (!lhs || !rhs)
159 goto error;
160 expr = isl_alloc_type(ctx, struct pet_expr);
161 if (!expr)
162 goto error;
164 expr->type = pet_expr_binary;
165 expr->op = op;
166 expr->n_arg = 2;
167 expr->args = isl_calloc_array(ctx, struct pet_expr *, 2);
168 if (!expr->args)
169 goto error;
170 expr->args[pet_bin_lhs] = lhs;
171 expr->args[pet_bin_rhs] = rhs;
173 return expr;
174 error:
175 pet_expr_free(lhs);
176 pet_expr_free(rhs);
177 return NULL;
180 /* Construct a ternary pet_expr that performs "cond" ? "lhs" : "rhs".
182 struct pet_expr *pet_expr_new_ternary(isl_ctx *ctx, struct pet_expr *cond,
183 struct pet_expr *lhs, struct pet_expr *rhs)
185 struct pet_expr *expr;
187 if (!cond || !lhs || !rhs)
188 goto error;
189 expr = isl_alloc_type(ctx, struct pet_expr);
190 if (!expr)
191 goto error;
193 expr->type = pet_expr_ternary;
194 expr->n_arg = 3;
195 expr->args = isl_calloc_array(ctx, struct pet_expr *, 3);
196 if (!expr->args)
197 goto error;
198 expr->args[pet_ter_cond] = cond;
199 expr->args[pet_ter_true] = lhs;
200 expr->args[pet_ter_false] = rhs;
202 return expr;
203 error:
204 pet_expr_free(cond);
205 pet_expr_free(lhs);
206 pet_expr_free(rhs);
207 return NULL;
210 /* Construct a call pet_expr that calls function "name" with "n_arg"
211 * arguments. The caller is responsible for filling in the arguments.
213 struct pet_expr *pet_expr_new_call(isl_ctx *ctx, const char *name,
214 unsigned n_arg)
216 struct pet_expr *expr;
218 expr = isl_alloc_type(ctx, struct pet_expr);
219 if (!expr)
220 return NULL;
222 expr->type = pet_expr_call;
223 expr->n_arg = n_arg;
224 expr->name = strdup(name);
225 expr->args = isl_calloc_array(ctx, struct pet_expr *, n_arg);
226 if (!expr->name || !expr->args)
227 return pet_expr_free(expr);
229 return expr;
232 /* Construct a pet_expr that represents the double "d".
234 struct pet_expr *pet_expr_new_double(isl_ctx *ctx, double d)
236 struct pet_expr *expr;
238 expr = isl_calloc_type(ctx, struct pet_expr);
239 if (!expr)
240 return NULL;
242 expr->type = pet_expr_double;
243 expr->d = d;
245 return expr;
248 void *pet_expr_free(struct pet_expr *expr)
250 int i;
252 if (!expr)
253 return NULL;
255 for (i = 0; i < expr->n_arg; ++i)
256 pet_expr_free(expr->args[i]);
257 free(expr->args);
259 switch (expr->type) {
260 case pet_expr_access:
261 isl_map_free(expr->acc.access);
262 break;
263 case pet_expr_call:
264 free(expr->name);
265 break;
266 case pet_expr_double:
267 case pet_expr_unary:
268 case pet_expr_binary:
269 case pet_expr_ternary:
270 break;
273 free(expr);
274 return NULL;
277 static void expr_dump(struct pet_expr *expr, int indent)
279 int i;
281 if (!expr)
282 return;
284 fprintf(stderr, "%*s", indent, "");
286 switch (expr->type) {
287 case pet_expr_double:
288 fprintf(stderr, "%g\n", expr->d);
289 break;
290 case pet_expr_access:
291 isl_map_dump(expr->acc.access);
292 fprintf(stderr, "%*sread: %d\n", indent + 2,
293 "", expr->acc.read);
294 fprintf(stderr, "%*swrite: %d\n", indent + 2,
295 "", expr->acc.write);
296 for (i = 0; i < expr->n_arg; ++i)
297 expr_dump(expr->args[i], indent + 2);
298 break;
299 case pet_expr_unary:
300 fprintf(stderr, "%s\n", op_str[expr->op]);
301 expr_dump(expr->args[pet_un_arg], indent + 2);
302 break;
303 case pet_expr_binary:
304 fprintf(stderr, "%s\n", op_str[expr->op]);
305 expr_dump(expr->args[pet_bin_lhs], indent + 2);
306 expr_dump(expr->args[pet_bin_rhs], indent + 2);
307 break;
308 case pet_expr_ternary:
309 fprintf(stderr, "?:\n");
310 expr_dump(expr->args[pet_ter_cond], indent + 2);
311 expr_dump(expr->args[pet_ter_true], indent + 2);
312 expr_dump(expr->args[pet_ter_false], indent + 2);
313 break;
314 case pet_expr_call:
315 fprintf(stderr, "%s/%d\n", expr->name, expr->n_arg);
316 for (i = 0; i < expr->n_arg; ++i)
317 expr_dump(expr->args[i], indent + 2);
318 break;
322 void pet_expr_dump(struct pet_expr *expr)
324 expr_dump(expr, 0);
327 /* Return 1 if the two pet_exprs are equivalent.
329 int pet_expr_is_equal(struct pet_expr *expr1, struct pet_expr *expr2)
331 int i;
333 if (!expr1 || !expr2)
334 return 0;
336 if (expr1->type != expr2->type)
337 return 0;
338 if (expr1->n_arg != expr2->n_arg)
339 return 0;
340 for (i = 0; i < expr1->n_arg; ++i)
341 if (!pet_expr_is_equal(expr1->args[i], expr2->args[i]))
342 return 0;
343 switch (expr1->type) {
344 case pet_expr_double:
345 if (expr1->d != expr2->d)
346 return 0;
347 break;
348 case pet_expr_access:
349 if (expr1->acc.read != expr2->acc.read)
350 return 0;
351 if (expr1->acc.write != expr2->acc.write)
352 return 0;
353 if (!expr1->acc.access || !expr2->acc.access)
354 return 0;
355 if (!isl_map_is_equal(expr1->acc.access, expr2->acc.access))
356 return 0;
357 break;
358 case pet_expr_unary:
359 case pet_expr_binary:
360 case pet_expr_ternary:
361 if (expr1->op != expr2->op)
362 return 0;
363 break;
364 case pet_expr_call:
365 if (strcmp(expr1->name, expr2->name))
366 return 0;
367 break;
370 return 1;
373 /* Add extra conditions on the parameters to all access relations in "expr".
375 struct pet_expr *pet_expr_restrict(struct pet_expr *expr,
376 __isl_take isl_set *cond)
378 int i;
380 if (!expr)
381 goto error;
383 for (i = 0; i < expr->n_arg; ++i) {
384 expr->args[i] = pet_expr_restrict(expr->args[i],
385 isl_set_copy(cond));
386 if (!expr->args[i])
387 goto error;
390 if (expr->type == pet_expr_access) {
391 expr->acc.access = isl_map_intersect_params(expr->acc.access,
392 isl_set_copy(cond));
393 if (!expr->acc.access)
394 goto error;
397 isl_set_free(cond);
398 return expr;
399 error:
400 isl_set_free(cond);
401 return pet_expr_free(expr);
404 /* Modify all access relations in "expr" by calling "fn" on them.
406 static struct pet_expr *expr_foreach_access(struct pet_expr *expr,
407 __isl_give isl_map *(*fn)(__isl_take isl_map *access, void *user),
408 void *user)
410 int i;
412 if (!expr)
413 return NULL;
415 for (i = 0; i < expr->n_arg; ++i) {
416 expr->args[i] = expr_foreach_access(expr->args[i], fn, user);
417 if (!expr->args[i])
418 return pet_expr_free(expr);
421 if (expr->type == pet_expr_access) {
422 expr->acc.access = fn(expr->acc.access, user);
423 if (!expr->acc.access)
424 return pet_expr_free(expr);
427 return expr;
430 /* Modify the given access relation based on the given iteration space
431 * transformation.
432 * If the access has any arguments then the domain of the access relation
433 * is a wrapped mapping from the iteration space to the space of
434 * argument values. We only need to change the domain of this wrapped
435 * mapping, so we extend the input transformation with an identity mapping
436 * on the space of argument values.
438 static __isl_give isl_map *update_domain(__isl_take isl_map *access,
439 void *user)
441 isl_map *update = user;
442 isl_space *dim;
444 update = isl_map_copy(update);
446 dim = isl_map_get_space(access);
447 dim = isl_space_domain(dim);
448 if (!isl_space_is_wrapping(dim))
449 isl_space_free(dim);
450 else {
451 isl_map *id;
452 dim = isl_space_unwrap(dim);
453 dim = isl_space_range(dim);
454 dim = isl_space_map_from_set(dim);
455 id = isl_map_identity(dim);
456 update = isl_map_product(update, id);
459 return isl_map_apply_domain(access, update);
462 /* Modify all access relations in "expr" based on the given iteration space
463 * transformation.
465 static struct pet_expr *expr_update_domain(struct pet_expr *expr,
466 __isl_take isl_map *update)
468 expr = expr_foreach_access(expr, &update_domain, update);
469 isl_map_free(update);
470 return expr;
473 /* Construct a pet_stmt with given line number and statement
474 * number from a pet_expr.
475 * The initial iteration domain is the zero-dimensional universe.
476 * The domains of all access relations are modified to refer
477 * to the statement iteration domain.
479 struct pet_stmt *pet_stmt_from_pet_expr(isl_ctx *ctx, int line, int id,
480 struct pet_expr *expr)
482 struct pet_stmt *stmt;
483 isl_space *dim;
484 isl_set *dom;
485 isl_map *sched;
486 isl_map *add_name;
487 char name[50];
489 if (!expr)
490 return NULL;
492 stmt = isl_alloc_type(ctx, struct pet_stmt);
493 if (!stmt)
494 return pet_expr_free(expr);
496 dim = isl_space_set_alloc(ctx, 0, 0);
497 snprintf(name, sizeof(name), "S_%d", id);
498 dim = isl_space_set_tuple_name(dim, isl_dim_set, name);
499 dom = isl_set_universe(isl_space_copy(dim));
500 sched = isl_map_from_domain(isl_set_copy(dom));
502 dim = isl_space_from_range(dim);
503 add_name = isl_map_universe(dim);
504 expr = expr_update_domain(expr, add_name);
506 stmt->line = line;
507 stmt->domain = dom;
508 stmt->schedule = sched;
509 stmt->body = expr;
511 if (!stmt->domain || !stmt->schedule || !stmt->body)
512 return pet_stmt_free(stmt);
514 return stmt;
517 void *pet_stmt_free(struct pet_stmt *stmt)
519 if (!stmt)
520 return NULL;
522 isl_set_free(stmt->domain);
523 isl_map_free(stmt->schedule);
524 pet_expr_free(stmt->body);
526 free(stmt);
527 return NULL;
530 static void stmt_dump(struct pet_stmt *stmt, int indent)
532 if (!stmt)
533 return;
535 fprintf(stderr, "%*s%d\n", indent, "", stmt->line);
536 fprintf(stderr, "%*s", indent, "");
537 isl_set_dump(stmt->domain);
538 fprintf(stderr, "%*s", indent, "");
539 isl_map_dump(stmt->schedule);
540 expr_dump(stmt->body, indent);
543 void pet_stmt_dump(struct pet_stmt *stmt)
545 stmt_dump(stmt, 0);
548 void *pet_array_free(struct pet_array *array)
550 if (!array)
551 return NULL;
553 isl_set_free(array->context);
554 isl_set_free(array->extent);
555 isl_set_free(array->value_bounds);
556 free(array->element_type);
558 free(array);
559 return NULL;
562 void pet_array_dump(struct pet_array *array)
564 if (!array)
565 return;
567 isl_set_dump(array->context);
568 isl_set_dump(array->extent);
569 isl_set_dump(array->value_bounds);
570 fprintf(stderr, "%s %s\n", array->element_type,
571 array->live_out ? "live-out" : "");
574 /* Construct a pet_scop with room for n statements.
576 static struct pet_scop *scop_alloc(isl_ctx *ctx, int n)
578 struct pet_scop *scop;
580 scop = isl_calloc_type(ctx, struct pet_scop);
581 if (!scop)
582 return NULL;
584 scop->context = isl_set_universe(isl_space_params_alloc(ctx, 0));
585 scop->stmts = isl_calloc_array(ctx, struct pet_stmt *, n);
586 if (!scop->context || !scop->stmts)
587 return pet_scop_free(scop);
589 scop->n_stmt = n;
591 return scop;
594 struct pet_scop *pet_scop_empty(isl_ctx *ctx)
596 return scop_alloc(ctx, 0);
599 /* Construct a pet_scop that contains the given pet_stmt.
601 struct pet_scop *pet_scop_from_pet_stmt(isl_ctx *ctx, struct pet_stmt *stmt)
603 struct pet_scop *scop;
605 if (!stmt)
606 return NULL;
608 scop = scop_alloc(ctx, 1);
610 scop->stmts[0] = stmt;
612 return scop;
613 error:
614 pet_stmt_free(stmt);
615 pet_scop_free(scop);
616 return NULL;
619 /* Construct a pet_scop that contains the statements in "scop1" and "scop2".
621 struct pet_scop *pet_scop_add(isl_ctx *ctx, struct pet_scop *scop1,
622 struct pet_scop *scop2)
624 int i;
625 struct pet_scop *scop;
627 if (!scop1 || !scop2)
628 goto error;
630 if (scop1->n_stmt == 0) {
631 pet_scop_free(scop1);
632 return scop2;
635 if (scop2->n_stmt == 0) {
636 pet_scop_free(scop2);
637 return scop1;
640 scop = scop_alloc(ctx, scop1->n_stmt + scop2->n_stmt);
641 if (!scop)
642 goto error;
644 for (i = 0; i < scop1->n_stmt; ++i) {
645 scop->stmts[i] = scop1->stmts[i];
646 scop1->stmts[i] = NULL;
649 for (i = 0; i < scop2->n_stmt; ++i) {
650 scop->stmts[scop1->n_stmt + i] = scop2->stmts[i];
651 scop2->stmts[i] = NULL;
654 pet_scop_free(scop1);
655 pet_scop_free(scop2);
656 return scop;
657 error:
658 pet_scop_free(scop1);
659 pet_scop_free(scop2);
660 return NULL;
663 void *pet_scop_free(struct pet_scop *scop)
665 int i;
667 if (!scop)
668 return NULL;
669 isl_set_free(scop->context);
670 if (scop->arrays)
671 for (i = 0; i < scop->n_array; ++i)
672 pet_array_free(scop->arrays[i]);
673 free(scop->arrays);
674 if (scop->stmts)
675 for (i = 0; i < scop->n_stmt; ++i)
676 pet_stmt_free(scop->stmts[i]);
677 free(scop->stmts);
678 free(scop);
679 return NULL;
682 void pet_scop_dump(struct pet_scop *scop)
684 int i;
686 if (!scop)
687 return;
689 isl_set_dump(scop->context);
690 for (i = 0; i < scop->n_array; ++i)
691 pet_array_dump(scop->arrays[i]);
692 for (i = 0; i < scop->n_stmt; ++i)
693 pet_stmt_dump(scop->stmts[i]);
696 /* Return 1 if the two pet_arrays are equivalent.
698 int pet_array_is_equal(struct pet_array *array1, struct pet_array *array2)
700 if (!array1 || !array2)
701 return 0;
703 if (!isl_set_is_equal(array1->context, array2->context))
704 return 0;
705 if (!isl_set_is_equal(array1->extent, array2->extent))
706 return 0;
707 if (!!array1->value_bounds != !!array2->value_bounds)
708 return 0;
709 if (array1->value_bounds &&
710 !isl_set_is_equal(array1->value_bounds, array2->value_bounds))
711 return 0;
712 if (strcmp(array1->element_type, array2->element_type))
713 return 0;
714 if (array1->live_out != array2->live_out)
715 return 0;
717 return 1;
720 /* Return 1 if the two pet_stmts are equivalent.
722 int pet_stmt_is_equal(struct pet_stmt *stmt1, struct pet_stmt *stmt2)
724 if (!stmt1 || !stmt2)
725 return 0;
727 if (stmt1->line != stmt2->line)
728 return 0;
729 if (!isl_set_is_equal(stmt1->domain, stmt2->domain))
730 return 0;
731 if (!isl_map_is_equal(stmt1->schedule, stmt2->schedule))
732 return 0;
733 if (!pet_expr_is_equal(stmt1->body, stmt2->body))
734 return 0;
736 return 1;
739 /* Return 1 if the two pet_scops are equivalent.
741 int pet_scop_is_equal(struct pet_scop *scop1, struct pet_scop *scop2)
743 int i;
745 if (!scop1 || !scop2)
746 return 0;
748 if (!isl_set_is_equal(scop1->context, scop2->context))
749 return 0;
751 if (scop1->n_array != scop2->n_array)
752 return 0;
753 for (i = 0; i < scop1->n_array; ++i)
754 if (!pet_array_is_equal(scop1->arrays[i], scop2->arrays[i]))
755 return 0;
757 if (scop1->n_stmt != scop2->n_stmt)
758 return 0;
759 for (i = 0; i < scop1->n_stmt; ++i)
760 if (!pet_stmt_is_equal(scop1->stmts[i], scop2->stmts[i]))
761 return 0;
763 return 1;
766 /* Prefix the schedule of "stmt" with an extra dimension with constant
767 * value "pos".
769 struct pet_stmt *pet_stmt_prefix(struct pet_stmt *stmt, int pos)
771 if (!stmt)
772 return NULL;
774 stmt->schedule = isl_map_insert_dims(stmt->schedule, isl_dim_out, 0, 1);
775 stmt->schedule = isl_map_fix_si(stmt->schedule, isl_dim_out, 0, pos);
776 if (!stmt->schedule)
777 return pet_stmt_free(stmt);
779 return stmt;
782 /* Prefix the schedules of all statements in "scop" with an extra
783 * dimension with constant value "pos".
785 struct pet_scop *pet_scop_prefix(struct pet_scop *scop, int pos)
787 int i;
789 if (!scop)
790 return NULL;
792 for (i = 0; i < scop->n_stmt; ++i) {
793 scop->stmts[i] = pet_stmt_prefix(scop->stmts[i], pos);
794 if (!scop->stmts[i])
795 return pet_scop_free(scop);
798 return scop;
801 /* Data used in embed_access.
802 * extend adds an iterator to the iteration domain
803 * var_id represents the induction variable of the corresponding loop
805 struct pet_embed_access {
806 isl_map *extend;
807 isl_id *var_id;
810 /* Embed the access relation in an extra outer loop.
812 * We first update the iteration domain to insert the extra dimension.
814 * If the access refers to the induction variable, then it is
815 * turned into an access to the set of integers with index (and value)
816 * equal to the induction variable.
818 * If the induction variable appears in the constraints (as a parameter),
819 * then the parameter is equated to the newly introduced iteration
820 * domain dimension and subsequently projected out.
822 static __isl_give isl_map *embed_access(__isl_take isl_map *access,
823 void *user)
825 struct pet_embed_access *data = user;
826 isl_id *array_id = NULL;
827 int pos;
829 access = update_domain(access, data->extend);
831 if (isl_map_has_tuple_id(access, isl_dim_out))
832 array_id = isl_map_get_tuple_id(access, isl_dim_out);
833 if (array_id == data->var_id) {
834 access = isl_map_insert_dims(access, isl_dim_out, 0, 1);
835 access = isl_map_equate(access,
836 isl_dim_in, 0, isl_dim_out, 0);
838 isl_id_free(array_id);
840 pos = isl_map_find_dim_by_id(access, isl_dim_param, data->var_id);
841 if (pos >= 0) {
842 access = isl_map_equate(access,
843 isl_dim_param, pos, isl_dim_in, 0);
844 access = isl_map_project_out(access, isl_dim_param, pos, 1);
846 access = isl_map_set_dim_id(access, isl_dim_in, 0,
847 isl_id_copy(data->var_id));
849 return access;
852 /* Embed all access relations in "expr" in an extra loop.
853 * "extend" inserts an outer loop iterator in the iteration domains.
854 * "var_id" represents the induction variable.
856 static struct pet_expr *expr_embed(struct pet_expr *expr,
857 __isl_take isl_map *extend, __isl_keep isl_id *var_id)
859 struct pet_embed_access data = { .extend = extend, .var_id = var_id };
861 expr = expr_foreach_access(expr, &embed_access, &data);
862 isl_map_free(extend);
863 return expr;
866 /* Embed the given pet_stmt in an extra outer loop with iteration domain
867 * "dom" and schedule "sched". "var_id" represents the induction variable
868 * of the loop.
870 * The iteration domain and schedule of the statement are updated
871 * according to the iteration domain and schedule of the new loop.
873 * If the induction variable appears in the constraints (as a parameter)
874 * of the current iteration domain or the schedule of the statement,
875 * then the parameter is equated to the newly introduced iteration
876 * domain dimension and subsequently projected out.
878 * Finally, all access relations are updated based on the extra loop.
880 struct pet_stmt *pet_stmt_embed(struct pet_stmt *stmt, __isl_take isl_set *dom,
881 __isl_take isl_map *sched, __isl_take isl_id *var_id)
883 int pos;
884 isl_id *stmt_id;
885 isl_space *dim;
886 isl_map *extend;
888 if (!stmt)
889 goto error;
891 stmt_id = isl_set_get_tuple_id(stmt->domain);
892 stmt->domain = isl_set_flat_product(isl_set_copy(dom), stmt->domain);
893 stmt->domain = isl_set_set_tuple_id(stmt->domain, isl_id_copy(stmt_id));
895 pos = isl_set_find_dim_by_id(stmt->domain, isl_dim_param, var_id);
896 if (pos >= 0) {
897 stmt->domain = isl_set_equate(stmt->domain,
898 isl_dim_param, pos, isl_dim_set, 0);
899 stmt->domain = isl_set_project_out(stmt->domain,
900 isl_dim_param, pos, 1);
903 stmt->schedule = isl_map_flat_product(sched, stmt->schedule);
904 stmt->schedule = isl_map_set_tuple_id(stmt->schedule,
905 isl_dim_in, stmt_id);
907 pos = isl_map_find_dim_by_id(stmt->schedule, isl_dim_param, var_id);
908 if (pos >= 0) {
909 stmt->schedule = isl_map_equate(stmt->schedule,
910 isl_dim_param, pos, isl_dim_in, 0);
911 stmt->schedule = isl_map_project_out(stmt->schedule,
912 isl_dim_param, pos, 1);
915 dim = isl_space_map_from_set(isl_set_get_space(stmt->domain));
916 extend = isl_map_identity(dim);
917 extend = isl_map_remove_dims(extend, isl_dim_in, 0, 1);
918 extend = isl_map_set_tuple_id(extend, isl_dim_in,
919 isl_map_get_tuple_id(extend, isl_dim_out));
920 stmt->body = expr_embed(stmt->body, extend, var_id);
922 isl_set_free(dom);
923 isl_id_free(var_id);
925 if (!stmt->domain || !stmt->schedule || !stmt->body)
926 return pet_stmt_free(stmt);
927 return stmt;
928 error:
929 isl_set_free(dom);
930 isl_map_free(sched);
931 isl_id_free(var_id);
932 return NULL;
935 /* Embed all statements in "scop" in an extra outer loop with iteration domain
936 * "dom" and schedule "sched". "var_id" represents the induction variable
937 * of the loop.
939 struct pet_scop *pet_scop_embed(struct pet_scop *scop, __isl_take isl_set *dom,
940 __isl_take isl_map *sched, __isl_take isl_id *id)
942 int i;
944 if (!scop)
945 goto error;
947 for (i = 0; i < scop->n_stmt; ++i) {
948 scop->stmts[i] = pet_stmt_embed(scop->stmts[i],
949 isl_set_copy(dom),
950 isl_map_copy(sched), isl_id_copy(id));
951 if (!scop->stmts[i])
952 goto error;
955 isl_set_free(dom);
956 isl_map_free(sched);
957 isl_id_free(id);
958 return scop;
959 error:
960 isl_set_free(dom);
961 isl_map_free(sched);
962 isl_id_free(id);
963 return pet_scop_free(scop);
966 /* Add extra conditions on the parameters to iteration domain of "stmt".
968 static struct pet_stmt *stmt_restrict(struct pet_stmt *stmt,
969 __isl_take isl_set *cond)
971 if (!stmt)
972 goto error;
974 stmt->domain = isl_set_intersect_params(stmt->domain, cond);
976 return stmt;
977 error:
978 isl_set_free(cond);
979 return pet_stmt_free(stmt);
982 /* Add extra conditions on the parameters to all iteration domains.
984 struct pet_scop *pet_scop_restrict(struct pet_scop *scop,
985 __isl_take isl_set *cond)
987 int i;
989 if (!scop)
990 goto error;
992 for (i = 0; i < scop->n_stmt; ++i) {
993 scop->stmts[i] = stmt_restrict(scop->stmts[i],
994 isl_set_copy(cond));
995 if (!scop->stmts[i])
996 goto error;
999 isl_set_free(cond);
1000 return scop;
1001 error:
1002 isl_set_free(cond);
1003 return pet_scop_free(scop);
1006 /* Add all parameters in "expr" to "dim" and return the result.
1008 static __isl_give isl_space *expr_collect_params(struct pet_expr *expr,
1009 __isl_take isl_space *dim)
1011 int i;
1013 if (!expr)
1014 goto error;
1015 for (i = 0; i < expr->n_arg; ++i)
1017 dim = expr_collect_params(expr->args[i], dim);
1019 if (expr->type == pet_expr_access)
1020 dim = isl_space_align_params(dim,
1021 isl_map_get_space(expr->acc.access));
1023 return dim;
1024 error:
1025 isl_space_free(dim);
1026 return pet_expr_free(expr);
1029 /* Add all parameters in "stmt" to "dim" and return the result.
1031 static __isl_give isl_space *stmt_collect_params(struct pet_stmt *stmt,
1032 __isl_take isl_space *dim)
1034 if (!stmt)
1035 goto error;
1037 dim = isl_space_align_params(dim, isl_set_get_space(stmt->domain));
1038 dim = isl_space_align_params(dim, isl_map_get_space(stmt->schedule));
1039 dim = expr_collect_params(stmt->body, dim);
1041 return dim;
1042 error:
1043 isl_space_free(dim);
1044 return pet_stmt_free(stmt);
1047 /* Add all parameters in "array" to "dim" and return the result.
1049 static __isl_give isl_space *array_collect_params(struct pet_array *array,
1050 __isl_take isl_space *dim)
1052 if (!array)
1053 goto error;
1055 dim = isl_space_align_params(dim, isl_set_get_space(array->context));
1056 dim = isl_space_align_params(dim, isl_set_get_space(array->extent));
1058 return dim;
1059 error:
1060 isl_space_free(dim);
1061 return pet_array_free(array);
1064 /* Add all parameters in "scop" to "dim" and return the result.
1066 static __isl_give isl_space *scop_collect_params(struct pet_scop *scop,
1067 __isl_take isl_space *dim)
1069 int i;
1071 if (!scop)
1072 goto error;
1074 for (i = 0; i < scop->n_array; ++i)
1075 dim = array_collect_params(scop->arrays[i], dim);
1077 for (i = 0; i < scop->n_stmt; ++i)
1078 dim = stmt_collect_params(scop->stmts[i], dim);
1080 return dim;
1081 error:
1082 isl_space_free(dim);
1083 return pet_scop_free(scop);
1086 /* Add all parameters in "dim" to all access relations in "expr".
1088 static struct pet_expr *expr_propagate_params(struct pet_expr *expr,
1089 __isl_take isl_space *dim)
1091 int i;
1093 if (!expr)
1094 goto error;
1096 for (i = 0; i < expr->n_arg; ++i) {
1097 expr->args[i] =
1098 expr_propagate_params(expr->args[i],
1099 isl_space_copy(dim));
1100 if (!expr->args[i])
1101 goto error;
1104 if (expr->type == pet_expr_access) {
1105 expr->acc.access = isl_map_align_params(expr->acc.access,
1106 isl_space_copy(dim));
1107 if (!expr->acc.access)
1108 goto error;
1111 isl_space_free(dim);
1112 return expr;
1113 error:
1114 isl_space_free(dim);
1115 return pet_expr_free(expr);
1118 /* Add all parameters in "dim" to the domain, schedule and
1119 * all access relations in "stmt".
1121 static struct pet_stmt *stmt_propagate_params(struct pet_stmt *stmt,
1122 __isl_take isl_space *dim)
1124 if (!stmt)
1125 goto error;
1127 stmt->domain = isl_set_align_params(stmt->domain, isl_space_copy(dim));
1128 stmt->schedule = isl_map_align_params(stmt->schedule,
1129 isl_space_copy(dim));
1130 stmt->body = expr_propagate_params(stmt->body, isl_space_copy(dim));
1132 if (!stmt->domain || !stmt->schedule || !stmt->body)
1133 goto error;
1135 isl_space_free(dim);
1136 return stmt;
1137 error:
1138 isl_space_free(dim);
1139 return pet_stmt_free(stmt);
1142 /* Add all parameters in "dim" to "array".
1144 static struct pet_array *array_propagate_params(struct pet_array *array,
1145 __isl_take isl_space *dim)
1147 if (!array)
1148 goto error;
1150 array->context = isl_set_align_params(array->context,
1151 isl_space_copy(dim));
1152 array->extent = isl_set_align_params(array->extent,
1153 isl_space_copy(dim));
1154 if (array->value_bounds) {
1155 array->value_bounds = isl_set_align_params(array->value_bounds,
1156 isl_space_copy(dim));
1157 if (!array->value_bounds)
1158 goto error;
1161 if (!array->context || !array->extent)
1162 goto error;
1164 isl_space_free(dim);
1165 return array;
1166 error:
1167 isl_space_free(dim);
1168 return pet_array_free(array);
1171 /* Add all parameters in "dim" to "scop".
1173 static struct pet_scop *scop_propagate_params(struct pet_scop *scop,
1174 __isl_take isl_space *dim)
1176 int i;
1178 if (!scop)
1179 goto error;
1181 for (i = 0; i < scop->n_array; ++i) {
1182 scop->arrays[i] = array_propagate_params(scop->arrays[i],
1183 isl_space_copy(dim));
1184 if (!scop->arrays[i])
1185 goto error;
1188 for (i = 0; i < scop->n_stmt; ++i) {
1189 scop->stmts[i] = stmt_propagate_params(scop->stmts[i],
1190 isl_space_copy(dim));
1191 if (!scop->stmts[i])
1192 goto error;
1195 isl_space_free(dim);
1196 return scop;
1197 error:
1198 isl_space_free(dim);
1199 return pet_scop_free(scop);
1202 /* Update all isl_sets and isl_maps in "scop" such that they all
1203 * have the same parameters.
1205 struct pet_scop *pet_scop_align_params(struct pet_scop *scop)
1207 isl_space *dim;
1209 if (!scop)
1210 return NULL;
1212 dim = isl_set_get_space(scop->context);
1213 dim = scop_collect_params(scop, dim);
1215 scop->context = isl_set_align_params(scop->context, isl_space_copy(dim));
1216 scop = scop_propagate_params(scop, dim);
1218 return scop;
1221 /* Check if the given access relation accesses a (0D) array that corresponds
1222 * to one of the parameters in "dim". If so, replace the array access
1223 * by an access to the set of integers with as index (and value)
1224 * that parameter.
1226 static __isl_give isl_map *access_detect_parameter(__isl_take isl_map *access,
1227 __isl_take isl_space *dim)
1229 isl_id *array_id = NULL;
1230 int pos = -1;
1232 if (isl_map_has_tuple_id(access, isl_dim_out)) {
1233 array_id = isl_map_get_tuple_id(access, isl_dim_out);
1234 pos = isl_space_find_dim_by_id(dim, isl_dim_param, array_id);
1236 isl_space_free(dim);
1238 if (pos < 0) {
1239 isl_id_free(array_id);
1240 return access;
1243 pos = isl_map_find_dim_by_id(access, isl_dim_param, array_id);
1244 if (pos < 0) {
1245 access = isl_map_insert_dims(access, isl_dim_param, 0, 1);
1246 access = isl_map_set_dim_id(access, isl_dim_param, 0, array_id);
1247 pos = 0;
1248 } else
1249 isl_id_free(array_id);
1251 access = isl_map_insert_dims(access, isl_dim_out, 0, 1);
1252 access = isl_map_equate(access, isl_dim_param, pos, isl_dim_out, 0);
1254 return access;
1257 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
1258 * in "dim" by a value equal to the corresponding parameter.
1260 static struct pet_expr *expr_detect_parameter_accesses(struct pet_expr *expr,
1261 __isl_take isl_space *dim)
1263 int i;
1265 if (!expr)
1266 goto error;
1268 for (i = 0; i < expr->n_arg; ++i) {
1269 expr->args[i] =
1270 expr_detect_parameter_accesses(expr->args[i],
1271 isl_space_copy(dim));
1272 if (!expr->args[i])
1273 goto error;
1276 if (expr->type == pet_expr_access) {
1277 expr->acc.access = access_detect_parameter(expr->acc.access,
1278 isl_space_copy(dim));
1279 if (!expr->acc.access)
1280 goto error;
1283 isl_space_free(dim);
1284 return expr;
1285 error:
1286 isl_space_free(dim);
1287 return pet_expr_free(expr);
1290 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
1291 * in "dim" by a value equal to the corresponding parameter.
1293 static struct pet_stmt *stmt_detect_parameter_accesses(struct pet_stmt *stmt,
1294 __isl_take isl_space *dim)
1296 if (!stmt)
1297 goto error;
1299 stmt->body = expr_detect_parameter_accesses(stmt->body,
1300 isl_space_copy(dim));
1302 if (!stmt->domain || !stmt->schedule || !stmt->body)
1303 goto error;
1305 isl_space_free(dim);
1306 return stmt;
1307 error:
1308 isl_space_free(dim);
1309 return pet_stmt_free(stmt);
1312 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
1313 * in "dim" by a value equal to the corresponding parameter.
1315 static struct pet_scop *scop_detect_parameter_accesses(struct pet_scop *scop,
1316 __isl_take isl_space *dim)
1318 int i;
1320 if (!scop)
1321 goto error;
1323 for (i = 0; i < scop->n_stmt; ++i) {
1324 scop->stmts[i] = stmt_detect_parameter_accesses(scop->stmts[i],
1325 isl_space_copy(dim));
1326 if (!scop->stmts[i])
1327 goto error;
1330 isl_space_free(dim);
1331 return scop;
1332 error:
1333 isl_space_free(dim);
1334 return pet_scop_free(scop);
1337 /* Replace all accesses to (0D) arrays that correspond to any of
1338 * the parameters used in "scop" by a value equal
1339 * to the corresponding parameter.
1341 struct pet_scop *pet_scop_detect_parameter_accesses(struct pet_scop *scop)
1343 isl_space *dim;
1345 if (!scop)
1346 return NULL;
1348 dim = isl_set_get_space(scop->context);
1349 dim = scop_collect_params(scop, dim);
1351 scop = scop_detect_parameter_accesses(scop, dim);
1353 return scop;
1356 /* Add all read access relations (if "read" is set) and/or all write
1357 * access relations (if "write" is set) to "accesses" and return the result.
1359 static __isl_give isl_union_map *expr_collect_accesses(struct pet_expr *expr,
1360 int read, int write, __isl_take isl_union_map *accesses)
1362 int i;
1363 isl_id *id;
1364 isl_space *dim;
1366 if (!expr)
1367 return NULL;
1369 for (i = 0; i < expr->n_arg; ++i)
1370 accesses = expr_collect_accesses(expr->args[i],
1371 read, write, accesses);
1373 if (expr->type == pet_expr_access &&
1374 isl_map_has_tuple_id(expr->acc.access, isl_dim_out) &&
1375 ((read && expr->acc.read) || (write && expr->acc.write)))
1376 accesses = isl_union_map_add_map(accesses,
1377 isl_map_copy(expr->acc.access));
1379 return accesses;
1382 /* Collect and return all read access relations (if "read" is set)
1383 * and/or all write * access relations (if "write" is set) in "stmt".
1385 static __isl_give isl_union_map *stmt_collect_accesses(struct pet_stmt *stmt,
1386 int read, int write, __isl_take isl_space *dim)
1388 isl_union_map *accesses;
1390 if (!stmt)
1391 return NULL;
1393 accesses = isl_union_map_empty(dim);
1394 accesses = expr_collect_accesses(stmt->body, read, write, accesses);
1395 accesses = isl_union_map_intersect_domain(accesses,
1396 isl_union_set_from_set(isl_set_copy(stmt->domain)));
1398 return accesses;
1401 /* Collect and return all read access relations (if "read" is set)
1402 * and/or all write * access relations (if "write" is set) in "scop".
1404 static __isl_give isl_union_map *scop_collect_accesses(struct pet_scop *scop,
1405 int read, int write)
1407 int i;
1408 isl_union_map *accesses;
1410 if (!scop)
1411 return NULL;
1413 accesses = isl_union_map_empty(isl_set_get_space(scop->context));
1415 for (i = 0; i < scop->n_stmt; ++i) {
1416 isl_union_map *accesses_i;
1417 isl_space *dim = isl_set_get_space(scop->context);
1418 accesses_i = stmt_collect_accesses(scop->stmts[i],
1419 read, write, dim);
1420 accesses = isl_union_map_union(accesses, accesses_i);
1423 return accesses;
1426 __isl_give isl_union_map *pet_scop_collect_reads(struct pet_scop *scop)
1428 return scop_collect_accesses(scop, 1, 0);
1431 __isl_give isl_union_map *pet_scop_collect_writes(struct pet_scop *scop)
1433 return scop_collect_accesses(scop, 0, 1);
1436 /* Collect and return the union of iteration domains in "scop".
1438 __isl_give isl_union_set *pet_scop_collect_domains(struct pet_scop *scop)
1440 int i;
1441 isl_set *domain_i;
1442 isl_union_set *domain;
1444 if (!scop)
1445 return NULL;
1447 domain = isl_union_set_empty(isl_set_get_space(scop->context));
1449 for (i = 0; i < scop->n_stmt; ++i) {
1450 domain_i = isl_set_copy(scop->stmts[i]->domain);
1451 domain = isl_union_set_add_set(domain, domain_i);
1454 return domain;
1457 /* Collect and return the schedules of the statements in "scop".
1458 * The range is normalized to the maximal number of scheduling
1459 * dimensions.
1461 __isl_give isl_union_map *pet_scop_collect_schedule(struct pet_scop *scop)
1463 int i, j;
1464 isl_map *schedule_i;
1465 isl_union_map *schedule;
1466 int depth, max_depth = 0;
1468 if (!scop)
1469 return NULL;
1471 schedule = isl_union_map_empty(isl_set_get_space(scop->context));
1473 for (i = 0; i < scop->n_stmt; ++i) {
1474 depth = isl_map_dim(scop->stmts[i]->schedule, isl_dim_out);
1475 if (depth > max_depth)
1476 max_depth = depth;
1479 for (i = 0; i < scop->n_stmt; ++i) {
1480 schedule_i = isl_map_copy(scop->stmts[i]->schedule);
1481 depth = isl_map_dim(schedule_i, isl_dim_out);
1482 schedule_i = isl_map_add_dims(schedule_i, isl_dim_out,
1483 max_depth - depth);
1484 for (j = depth; j < max_depth; ++j)
1485 schedule_i = isl_map_fix_si(schedule_i,
1486 isl_dim_out, j, 0);
1487 schedule = isl_union_map_add_map(schedule, schedule_i);
1490 return schedule;