update isl for change in isl_set_read_from_str
[pet.git] / scop.c
blobc9bbfde4269eca39281613bd0d10795acb77771e
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 (!isl_map_is_equal(expr1->acc.access, expr2->acc.access))
354 return 0;
355 break;
356 case pet_expr_unary:
357 case pet_expr_binary:
358 case pet_expr_ternary:
359 if (expr1->op != expr2->op)
360 return 0;
361 break;
362 case pet_expr_call:
363 if (strcmp(expr1->name, expr2->name))
364 return 0;
365 break;
368 return 1;
371 /* Add extra conditions on the parameters to all access relations in "expr".
373 struct pet_expr *pet_expr_restrict(struct pet_expr *expr,
374 __isl_take isl_set *cond)
376 int i;
378 if (!expr)
379 goto error;
381 for (i = 0; i < expr->n_arg; ++i) {
382 expr->args[i] = pet_expr_restrict(expr->args[i],
383 isl_set_copy(cond));
384 if (!expr->args[i])
385 goto error;
388 if (expr->type == pet_expr_access) {
389 expr->acc.access = isl_map_intersect_params(expr->acc.access,
390 isl_set_copy(cond));
391 if (!expr->acc.access)
392 goto error;
395 isl_set_free(cond);
396 return expr;
397 error:
398 isl_set_free(cond);
399 return pet_expr_free(expr);
402 /* Modify all access relations in "expr" by calling "fn" on them.
404 static struct pet_expr *expr_foreach_access(struct pet_expr *expr,
405 __isl_give isl_map *(*fn)(__isl_take isl_map *access, void *user),
406 void *user)
408 int i;
410 if (!expr)
411 return NULL;
413 for (i = 0; i < expr->n_arg; ++i) {
414 expr->args[i] = expr_foreach_access(expr->args[i], fn, user);
415 if (!expr->args[i])
416 return pet_expr_free(expr);
419 if (expr->type == pet_expr_access) {
420 expr->acc.access = fn(expr->acc.access, user);
421 if (!expr->acc.access)
422 return pet_expr_free(expr);
425 return expr;
428 /* Modify the given access relation based on the given iteration space
429 * transformation.
430 * If the access has any arguments then the domain of the access relation
431 * is a wrapped mapping from the iteration space to the space of
432 * argument values. We only need to change the domain of this wrapped
433 * mapping, so we extend the input transformation with an identity mapping
434 * on the space of argument values.
436 static __isl_give isl_map *update_domain(__isl_take isl_map *access,
437 void *user)
439 isl_map *update = user;
440 isl_space *dim;
442 update = isl_map_copy(update);
444 dim = isl_map_get_space(access);
445 dim = isl_space_domain(dim);
446 if (!isl_space_is_wrapping(dim))
447 isl_space_free(dim);
448 else {
449 isl_map *id;
450 dim = isl_space_unwrap(dim);
451 dim = isl_space_range(dim);
452 dim = isl_space_map_from_set(dim);
453 id = isl_map_identity(dim);
454 update = isl_map_product(update, id);
457 return isl_map_apply_domain(access, update);
460 /* Modify all access relations in "expr" based on the given iteration space
461 * transformation.
463 static struct pet_expr *expr_update_domain(struct pet_expr *expr,
464 __isl_take isl_map *update)
466 expr = expr_foreach_access(expr, &update_domain, update);
467 isl_map_free(update);
468 return expr;
471 /* Construct a pet_stmt with given line number and statement
472 * number from a pet_expr.
473 * The initial iteration domain is the zero-dimensional universe.
474 * The domains of all access relations are modified to refer
475 * to the statement iteration domain.
477 struct pet_stmt *pet_stmt_from_pet_expr(isl_ctx *ctx, int line, int id,
478 struct pet_expr *expr)
480 struct pet_stmt *stmt;
481 isl_space *dim;
482 isl_set *dom;
483 isl_map *sched;
484 isl_map *add_name;
485 char name[50];
487 if (!expr)
488 return NULL;
490 stmt = isl_alloc_type(ctx, struct pet_stmt);
491 if (!stmt)
492 return pet_expr_free(expr);
494 dim = isl_space_set_alloc(ctx, 0, 0);
495 snprintf(name, sizeof(name), "S_%d", id);
496 dim = isl_space_set_tuple_name(dim, isl_dim_set, name);
497 dom = isl_set_universe(isl_space_copy(dim));
498 sched = isl_map_from_domain(isl_set_copy(dom));
500 dim = isl_space_from_range(dim);
501 add_name = isl_map_universe(dim);
502 expr = expr_update_domain(expr, add_name);
504 stmt->line = line;
505 stmt->domain = dom;
506 stmt->schedule = sched;
507 stmt->body = expr;
509 if (!stmt->domain || !stmt->schedule || !stmt->body)
510 return pet_stmt_free(stmt);
512 return stmt;
515 void *pet_stmt_free(struct pet_stmt *stmt)
517 if (!stmt)
518 return NULL;
520 isl_set_free(stmt->domain);
521 isl_map_free(stmt->schedule);
522 pet_expr_free(stmt->body);
524 free(stmt);
525 return NULL;
528 static void stmt_dump(struct pet_stmt *stmt, int indent)
530 if (!stmt)
531 return;
533 fprintf(stderr, "%*s%d\n", indent, "", stmt->line);
534 fprintf(stderr, "%*s", indent, "");
535 isl_set_dump(stmt->domain);
536 fprintf(stderr, "%*s", indent, "");
537 isl_map_dump(stmt->schedule);
538 expr_dump(stmt->body, indent);
541 void pet_stmt_dump(struct pet_stmt *stmt)
543 stmt_dump(stmt, 0);
546 void *pet_array_free(struct pet_array *array)
548 if (!array)
549 return NULL;
551 isl_set_free(array->context);
552 isl_set_free(array->extent);
553 isl_set_free(array->value_bounds);
554 free(array->element_type);
556 free(array);
557 return NULL;
560 void pet_array_dump(struct pet_array *array)
562 if (!array)
563 return;
565 isl_set_dump(array->context);
566 isl_set_dump(array->extent);
567 isl_set_dump(array->value_bounds);
568 fprintf(stderr, "%s %s\n", array->element_type,
569 array->live_out ? "live-out" : "");
572 /* Construct a pet_scop with room for n statements.
574 static struct pet_scop *scop_alloc(isl_ctx *ctx, int n)
576 struct pet_scop *scop;
578 scop = isl_calloc_type(ctx, struct pet_scop);
579 if (!scop)
580 return NULL;
582 scop->context = isl_set_universe(isl_space_params_alloc(ctx, 0));
583 scop->stmts = isl_calloc_array(ctx, struct pet_stmt *, n);
584 if (!scop->context || !scop->stmts)
585 return pet_scop_free(scop);
587 scop->n_stmt = n;
589 return scop;
592 struct pet_scop *pet_scop_empty(isl_ctx *ctx)
594 return scop_alloc(ctx, 0);
597 /* Construct a pet_scop that contains the given pet_stmt.
599 struct pet_scop *pet_scop_from_pet_stmt(isl_ctx *ctx, struct pet_stmt *stmt)
601 struct pet_scop *scop;
603 if (!stmt)
604 return NULL;
606 scop = scop_alloc(ctx, 1);
608 scop->stmts[0] = stmt;
610 return scop;
611 error:
612 pet_stmt_free(stmt);
613 pet_scop_free(scop);
614 return NULL;
617 /* Construct a pet_scop that contains the statements in "scop1" and "scop2".
619 struct pet_scop *pet_scop_add(isl_ctx *ctx, struct pet_scop *scop1,
620 struct pet_scop *scop2)
622 int i;
623 struct pet_scop *scop;
625 if (!scop1 || !scop2)
626 goto error;
628 if (scop1->n_stmt == 0) {
629 pet_scop_free(scop1);
630 return scop2;
633 if (scop2->n_stmt == 0) {
634 pet_scop_free(scop2);
635 return scop1;
638 scop = scop_alloc(ctx, scop1->n_stmt + scop2->n_stmt);
639 if (!scop)
640 goto error;
642 for (i = 0; i < scop1->n_stmt; ++i) {
643 scop->stmts[i] = scop1->stmts[i];
644 scop1->stmts[i] = NULL;
647 for (i = 0; i < scop2->n_stmt; ++i) {
648 scop->stmts[scop1->n_stmt + i] = scop2->stmts[i];
649 scop2->stmts[i] = NULL;
652 pet_scop_free(scop1);
653 pet_scop_free(scop2);
654 return scop;
655 error:
656 pet_scop_free(scop1);
657 pet_scop_free(scop2);
658 return NULL;
661 void *pet_scop_free(struct pet_scop *scop)
663 int i;
665 if (!scop)
666 return NULL;
667 isl_set_free(scop->context);
668 if (scop->arrays)
669 for (i = 0; i < scop->n_array; ++i)
670 pet_array_free(scop->arrays[i]);
671 free(scop->arrays);
672 if (scop->stmts)
673 for (i = 0; i < scop->n_stmt; ++i)
674 pet_stmt_free(scop->stmts[i]);
675 free(scop->stmts);
676 free(scop);
677 return NULL;
680 void pet_scop_dump(struct pet_scop *scop)
682 int i;
684 if (!scop)
685 return;
687 isl_set_dump(scop->context);
688 for (i = 0; i < scop->n_array; ++i)
689 pet_array_dump(scop->arrays[i]);
690 for (i = 0; i < scop->n_stmt; ++i)
691 pet_stmt_dump(scop->stmts[i]);
694 /* Return 1 if the two pet_arrays are equivalent.
696 int pet_array_is_equal(struct pet_array *array1, struct pet_array *array2)
698 if (!array1 || !array2)
699 return 0;
701 if (!isl_set_is_equal(array1->context, array2->context))
702 return 0;
703 if (!isl_set_is_equal(array1->extent, array2->extent))
704 return 0;
705 if (!!array1->value_bounds != !!array2->value_bounds)
706 return 0;
707 if (array1->value_bounds &&
708 !isl_set_is_equal(array1->value_bounds, array2->value_bounds))
709 return 0;
710 if (strcmp(array1->element_type, array2->element_type))
711 return 0;
712 if (array1->live_out != array2->live_out)
713 return 0;
715 return 1;
718 /* Return 1 if the two pet_stmts are equivalent.
720 int pet_stmt_is_equal(struct pet_stmt *stmt1, struct pet_stmt *stmt2)
722 if (!stmt1 || !stmt2)
723 return 0;
725 if (stmt1->line != stmt2->line)
726 return 0;
727 if (!isl_set_is_equal(stmt1->domain, stmt2->domain))
728 return 0;
729 if (!isl_map_is_equal(stmt1->schedule, stmt2->schedule))
730 return 0;
731 if (!pet_expr_is_equal(stmt1->body, stmt2->body))
732 return 0;
734 return 1;
737 /* Return 1 if the two pet_scops are equivalent.
739 int pet_scop_is_equal(struct pet_scop *scop1, struct pet_scop *scop2)
741 int i;
743 if (!scop1 || !scop2)
744 return 0;
746 if (!isl_set_is_equal(scop1->context, scop2->context))
747 return 0;
749 if (scop1->n_array != scop2->n_array)
750 return 0;
751 for (i = 0; i < scop1->n_array; ++i)
752 if (!pet_array_is_equal(scop1->arrays[i], scop2->arrays[i]))
753 return 0;
755 if (scop1->n_stmt != scop2->n_stmt)
756 return 0;
757 for (i = 0; i < scop1->n_stmt; ++i)
758 if (!pet_stmt_is_equal(scop1->stmts[i], scop2->stmts[i]))
759 return 0;
761 return 1;
764 /* Prefix the schedule of "stmt" with an extra dimension with constant
765 * value "pos".
767 struct pet_stmt *pet_stmt_prefix(struct pet_stmt *stmt, int pos)
769 if (!stmt)
770 return NULL;
772 stmt->schedule = isl_map_insert_dims(stmt->schedule, isl_dim_out, 0, 1);
773 stmt->schedule = isl_map_fix_si(stmt->schedule, isl_dim_out, 0, pos);
774 if (!stmt->schedule)
775 return pet_stmt_free(stmt);
777 return stmt;
780 /* Prefix the schedules of all statements in "scop" with an extra
781 * dimension with constant value "pos".
783 struct pet_scop *pet_scop_prefix(struct pet_scop *scop, int pos)
785 int i;
787 if (!scop)
788 return NULL;
790 for (i = 0; i < scop->n_stmt; ++i) {
791 scop->stmts[i] = pet_stmt_prefix(scop->stmts[i], pos);
792 if (!scop->stmts[i])
793 return pet_scop_free(scop);
796 return scop;
799 /* Data used in embed_access.
800 * extend adds an iterator to the iteration domain
801 * var_id represents the induction variable of the corresponding loop
803 struct pet_embed_access {
804 isl_map *extend;
805 isl_id *var_id;
808 /* Embed the access relation in an extra outer loop.
810 * We first update the iteration domain to insert the extra dimension.
812 * If the access refers to the induction variable, then it is
813 * turned into an access to the set of integers with index (and value)
814 * equal to the induction variable.
816 * If the induction variable appears in the constraints (as a parameter),
817 * then the parameter is equated to the newly introduced iteration
818 * domain dimension and subsequently projected out.
820 static __isl_give isl_map *embed_access(__isl_take isl_map *access,
821 void *user)
823 struct pet_embed_access *data = user;
824 isl_id *array_id = NULL;
825 int pos;
827 access = update_domain(access, data->extend);
829 if (isl_map_has_tuple_id(access, isl_dim_out))
830 array_id = isl_map_get_tuple_id(access, isl_dim_out);
831 if (array_id == data->var_id) {
832 access = isl_map_insert_dims(access, isl_dim_out, 0, 1);
833 access = isl_map_equate(access,
834 isl_dim_in, 0, isl_dim_out, 0);
836 isl_id_free(array_id);
838 pos = isl_map_find_dim_by_id(access, isl_dim_param, data->var_id);
839 if (pos >= 0) {
840 access = isl_map_equate(access,
841 isl_dim_param, pos, isl_dim_in, 0);
842 access = isl_map_project_out(access, isl_dim_param, pos, 1);
844 access = isl_map_set_dim_id(access, isl_dim_in, 0,
845 isl_id_copy(data->var_id));
847 return access;
850 /* Embed all access relations in "expr" in an extra loop.
851 * "extend" inserts an outer loop iterator in the iteration domains.
852 * "var_id" represents the induction variable.
854 static struct pet_expr *expr_embed(struct pet_expr *expr,
855 __isl_take isl_map *extend, __isl_keep isl_id *var_id)
857 struct pet_embed_access data = { .extend = extend, .var_id = var_id };
859 expr = expr_foreach_access(expr, &embed_access, &data);
860 isl_map_free(extend);
861 return expr;
864 /* Embed the given pet_stmt in an extra outer loop with iteration domain
865 * "dom" and schedule "sched". "var_id" represents the induction variable
866 * of the loop.
868 * The iteration domain and schedule of the statement are updated
869 * according to the iteration domain and schedule of the new loop.
871 * If the induction variable appears in the constraints (as a parameter)
872 * of the current iteration domain or the schedule of the statement,
873 * then the parameter is equated to the newly introduced iteration
874 * domain dimension and subsequently projected out.
876 * Finally, all access relations are updated based on the extra loop.
878 struct pet_stmt *pet_stmt_embed(struct pet_stmt *stmt, __isl_take isl_set *dom,
879 __isl_take isl_map *sched, __isl_take isl_id *var_id)
881 int pos;
882 isl_id *stmt_id;
883 isl_space *dim;
884 isl_map *extend;
886 stmt_id = isl_set_get_tuple_id(stmt->domain);
887 stmt->domain = isl_set_flat_product(isl_set_copy(dom), stmt->domain);
888 stmt->domain = isl_set_set_tuple_id(stmt->domain, isl_id_copy(stmt_id));
890 pos = isl_set_find_dim_by_id(stmt->domain, isl_dim_param, var_id);
891 if (pos >= 0) {
892 stmt->domain = isl_set_equate(stmt->domain,
893 isl_dim_param, pos, isl_dim_set, 0);
894 stmt->domain = isl_set_project_out(stmt->domain,
895 isl_dim_param, pos, 1);
898 stmt->schedule = isl_map_flat_product(sched, stmt->schedule);
899 stmt->schedule = isl_map_set_tuple_id(stmt->schedule,
900 isl_dim_in, stmt_id);
902 pos = isl_map_find_dim_by_id(stmt->schedule, isl_dim_param, var_id);
903 if (pos >= 0) {
904 stmt->schedule = isl_map_equate(stmt->schedule,
905 isl_dim_param, pos, isl_dim_in, 0);
906 stmt->schedule = isl_map_project_out(stmt->schedule,
907 isl_dim_param, pos, 1);
910 dim = isl_space_map_from_set(isl_set_get_space(stmt->domain));
911 extend = isl_map_identity(dim);
912 extend = isl_map_remove_dims(extend, isl_dim_in, 0, 1);
913 extend = isl_map_set_tuple_id(extend, isl_dim_in,
914 isl_map_get_tuple_id(extend, isl_dim_out));
915 stmt->body = expr_embed(stmt->body, extend, var_id);
917 isl_set_free(dom);
918 isl_id_free(var_id);
920 if (!stmt->domain || !stmt->schedule || !stmt->body)
921 return pet_stmt_free(stmt);
922 return stmt;
925 /* Embed all statements in "scop" in an extra outer loop with iteration domain
926 * "dom" and schedule "sched". "var_id" represents the induction variable
927 * of the loop.
929 struct pet_scop *pet_scop_embed(struct pet_scop *scop, __isl_take isl_set *dom,
930 __isl_take isl_map *sched, __isl_take isl_id *id)
932 int i;
934 if (!scop)
935 goto error;
937 for (i = 0; i < scop->n_stmt; ++i) {
938 scop->stmts[i] = pet_stmt_embed(scop->stmts[i],
939 isl_set_copy(dom),
940 isl_map_copy(sched), isl_id_copy(id));
941 if (!scop->stmts[i])
942 goto error;
945 isl_set_free(dom);
946 isl_map_free(sched);
947 isl_id_free(id);
948 return scop;
949 error:
950 isl_set_free(dom);
951 isl_map_free(sched);
952 isl_id_free(id);
953 return pet_scop_free(scop);
956 /* Add extra conditions on the parameters to iteration domain of "stmt".
958 static struct pet_stmt *stmt_restrict(struct pet_stmt *stmt,
959 __isl_take isl_set *cond)
961 if (!stmt)
962 goto error;
964 stmt->domain = isl_set_intersect_params(stmt->domain, cond);
966 return stmt;
967 error:
968 isl_set_free(cond);
969 return pet_stmt_free(stmt);
972 /* Add extra conditions on the parameters to all iteration domains.
974 struct pet_scop *pet_scop_restrict(struct pet_scop *scop,
975 __isl_take isl_set *cond)
977 int i;
979 if (!scop)
980 goto error;
982 for (i = 0; i < scop->n_stmt; ++i) {
983 scop->stmts[i] = stmt_restrict(scop->stmts[i],
984 isl_set_copy(cond));
985 if (!scop->stmts[i])
986 goto error;
989 isl_set_free(cond);
990 return scop;
991 error:
992 isl_set_free(cond);
993 return pet_scop_free(scop);
996 /* Add all parameters in "expr" to "dim" and return the result.
998 static __isl_give isl_space *expr_collect_params(struct pet_expr *expr,
999 __isl_take isl_space *dim)
1001 int i;
1003 if (!expr)
1004 goto error;
1005 for (i = 0; i < expr->n_arg; ++i)
1007 dim = expr_collect_params(expr->args[i], dim);
1009 if (expr->type == pet_expr_access)
1010 dim = isl_space_align_params(dim,
1011 isl_map_get_space(expr->acc.access));
1013 return dim;
1014 error:
1015 isl_space_free(dim);
1016 return pet_expr_free(expr);
1019 /* Add all parameters in "stmt" to "dim" and return the result.
1021 static __isl_give isl_space *stmt_collect_params(struct pet_stmt *stmt,
1022 __isl_take isl_space *dim)
1024 if (!stmt)
1025 goto error;
1027 dim = isl_space_align_params(dim, isl_set_get_space(stmt->domain));
1028 dim = isl_space_align_params(dim, isl_map_get_space(stmt->schedule));
1029 dim = expr_collect_params(stmt->body, dim);
1031 return dim;
1032 error:
1033 isl_space_free(dim);
1034 return pet_stmt_free(stmt);
1037 /* Add all parameters in "array" to "dim" and return the result.
1039 static __isl_give isl_space *array_collect_params(struct pet_array *array,
1040 __isl_take isl_space *dim)
1042 if (!array)
1043 goto error;
1045 dim = isl_space_align_params(dim, isl_set_get_space(array->context));
1046 dim = isl_space_align_params(dim, isl_set_get_space(array->extent));
1048 return dim;
1049 error:
1050 isl_space_free(dim);
1051 return pet_array_free(array);
1054 /* Add all parameters in "scop" to "dim" and return the result.
1056 static __isl_give isl_space *scop_collect_params(struct pet_scop *scop,
1057 __isl_take isl_space *dim)
1059 int i;
1061 if (!scop)
1062 goto error;
1064 for (i = 0; i < scop->n_array; ++i)
1065 dim = array_collect_params(scop->arrays[i], dim);
1067 for (i = 0; i < scop->n_stmt; ++i)
1068 dim = stmt_collect_params(scop->stmts[i], dim);
1070 return dim;
1071 error:
1072 isl_space_free(dim);
1073 return pet_scop_free(scop);
1076 /* Add all parameters in "dim" to all access relations in "expr".
1078 static struct pet_expr *expr_propagate_params(struct pet_expr *expr,
1079 __isl_take isl_space *dim)
1081 int i;
1083 if (!expr)
1084 goto error;
1086 for (i = 0; i < expr->n_arg; ++i) {
1087 expr->args[i] =
1088 expr_propagate_params(expr->args[i],
1089 isl_space_copy(dim));
1090 if (!expr->args[i])
1091 goto error;
1094 if (expr->type == pet_expr_access) {
1095 expr->acc.access = isl_map_align_params(expr->acc.access,
1096 isl_space_copy(dim));
1097 if (!expr->acc.access)
1098 goto error;
1101 isl_space_free(dim);
1102 return expr;
1103 error:
1104 isl_space_free(dim);
1105 return pet_expr_free(expr);
1108 /* Add all parameters in "dim" to the domain, schedule and
1109 * all access relations in "stmt".
1111 static struct pet_stmt *stmt_propagate_params(struct pet_stmt *stmt,
1112 __isl_take isl_space *dim)
1114 if (!stmt)
1115 goto error;
1117 stmt->domain = isl_set_align_params(stmt->domain, isl_space_copy(dim));
1118 stmt->schedule = isl_map_align_params(stmt->schedule,
1119 isl_space_copy(dim));
1120 stmt->body = expr_propagate_params(stmt->body, isl_space_copy(dim));
1122 if (!stmt->domain || !stmt->schedule || !stmt->body)
1123 goto error;
1125 isl_space_free(dim);
1126 return stmt;
1127 error:
1128 isl_space_free(dim);
1129 return pet_stmt_free(stmt);
1132 /* Add all parameters in "dim" to "array".
1134 static struct pet_array *array_propagate_params(struct pet_array *array,
1135 __isl_take isl_space *dim)
1137 if (!array)
1138 goto error;
1140 array->context = isl_set_align_params(array->context,
1141 isl_space_copy(dim));
1142 array->extent = isl_set_align_params(array->extent,
1143 isl_space_copy(dim));
1144 if (array->value_bounds) {
1145 array->value_bounds = isl_set_align_params(array->value_bounds,
1146 isl_space_copy(dim));
1147 if (!array->value_bounds)
1148 goto error;
1151 if (!array->context || !array->extent)
1152 goto error;
1154 isl_space_free(dim);
1155 return array;
1156 error:
1157 isl_space_free(dim);
1158 return pet_array_free(array);
1161 /* Add all parameters in "dim" to "scop".
1163 static struct pet_scop *scop_propagate_params(struct pet_scop *scop,
1164 __isl_take isl_space *dim)
1166 int i;
1168 if (!scop)
1169 goto error;
1171 for (i = 0; i < scop->n_array; ++i) {
1172 scop->arrays[i] = array_propagate_params(scop->arrays[i],
1173 isl_space_copy(dim));
1174 if (!scop->arrays[i])
1175 goto error;
1178 for (i = 0; i < scop->n_stmt; ++i) {
1179 scop->stmts[i] = stmt_propagate_params(scop->stmts[i],
1180 isl_space_copy(dim));
1181 if (!scop->stmts[i])
1182 goto error;
1185 isl_space_free(dim);
1186 return scop;
1187 error:
1188 isl_space_free(dim);
1189 return pet_scop_free(scop);
1192 /* Update all isl_sets and isl_maps in "scop" such that they all
1193 * have the same parameters.
1195 struct pet_scop *pet_scop_align_params(struct pet_scop *scop)
1197 isl_space *dim;
1199 if (!scop)
1200 return NULL;
1202 dim = isl_set_get_space(scop->context);
1203 dim = scop_collect_params(scop, dim);
1205 scop->context = isl_set_align_params(scop->context, isl_space_copy(dim));
1206 scop = scop_propagate_params(scop, dim);
1208 return scop;
1211 /* Check if the given access relation accesses a (0D) array that corresponds
1212 * to one of the parameters in "dim". If so, replace the array access
1213 * by an access to the set of integers with as index (and value)
1214 * that parameter.
1216 static __isl_give isl_map *access_detect_parameter(__isl_take isl_map *access,
1217 __isl_take isl_space *dim)
1219 isl_id *array_id = NULL;
1220 int pos = -1;
1222 if (isl_map_has_tuple_id(access, isl_dim_out)) {
1223 array_id = isl_map_get_tuple_id(access, isl_dim_out);
1224 pos = isl_space_find_dim_by_id(dim, isl_dim_param, array_id);
1226 isl_space_free(dim);
1228 if (pos < 0) {
1229 isl_id_free(array_id);
1230 return access;
1233 pos = isl_map_find_dim_by_id(access, isl_dim_param, array_id);
1234 if (pos < 0) {
1235 access = isl_map_insert_dims(access, isl_dim_param, 0, 1);
1236 access = isl_map_set_dim_id(access, isl_dim_param, 0, array_id);
1237 pos = 0;
1238 } else
1239 isl_id_free(array_id);
1241 access = isl_map_insert_dims(access, isl_dim_out, 0, 1);
1242 access = isl_map_equate(access, isl_dim_param, pos, isl_dim_out, 0);
1244 return access;
1247 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
1248 * in "dim" by a value equal to the corresponding parameter.
1250 static struct pet_expr *expr_detect_parameter_accesses(struct pet_expr *expr,
1251 __isl_take isl_space *dim)
1253 int i;
1255 if (!expr)
1256 goto error;
1258 for (i = 0; i < expr->n_arg; ++i) {
1259 expr->args[i] =
1260 expr_detect_parameter_accesses(expr->args[i],
1261 isl_space_copy(dim));
1262 if (!expr->args[i])
1263 goto error;
1266 if (expr->type == pet_expr_access) {
1267 expr->acc.access = access_detect_parameter(expr->acc.access,
1268 isl_space_copy(dim));
1269 if (!expr->acc.access)
1270 goto error;
1273 isl_space_free(dim);
1274 return expr;
1275 error:
1276 isl_space_free(dim);
1277 return pet_expr_free(expr);
1280 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
1281 * in "dim" by a value equal to the corresponding parameter.
1283 static struct pet_stmt *stmt_detect_parameter_accesses(struct pet_stmt *stmt,
1284 __isl_take isl_space *dim)
1286 if (!stmt)
1287 goto error;
1289 stmt->body = expr_detect_parameter_accesses(stmt->body,
1290 isl_space_copy(dim));
1292 if (!stmt->domain || !stmt->schedule || !stmt->body)
1293 goto error;
1295 isl_space_free(dim);
1296 return stmt;
1297 error:
1298 isl_space_free(dim);
1299 return pet_stmt_free(stmt);
1302 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
1303 * in "dim" by a value equal to the corresponding parameter.
1305 static struct pet_scop *scop_detect_parameter_accesses(struct pet_scop *scop,
1306 __isl_take isl_space *dim)
1308 int i;
1310 if (!scop)
1311 goto error;
1313 for (i = 0; i < scop->n_stmt; ++i) {
1314 scop->stmts[i] = stmt_detect_parameter_accesses(scop->stmts[i],
1315 isl_space_copy(dim));
1316 if (!scop->stmts[i])
1317 goto error;
1320 isl_space_free(dim);
1321 return scop;
1322 error:
1323 isl_space_free(dim);
1324 return pet_scop_free(scop);
1327 /* Replace all accesses to (0D) arrays that correspond to any of
1328 * the parameters used in "scop" by a value equal
1329 * to the corresponding parameter.
1331 struct pet_scop *pet_scop_detect_parameter_accesses(struct pet_scop *scop)
1333 isl_space *dim;
1335 if (!scop)
1336 return NULL;
1338 dim = isl_set_get_space(scop->context);
1339 dim = scop_collect_params(scop, dim);
1341 scop = scop_detect_parameter_accesses(scop, dim);
1343 return scop;
1346 /* Add all read access relations (if "read" is set) and/or all write
1347 * access relations (if "write" is set) to "accesses" and return the result.
1349 static __isl_give isl_union_map *expr_collect_accesses(struct pet_expr *expr,
1350 int read, int write, __isl_take isl_union_map *accesses)
1352 int i;
1353 isl_id *id;
1354 isl_space *dim;
1356 if (!expr)
1357 return NULL;
1359 for (i = 0; i < expr->n_arg; ++i)
1360 accesses = expr_collect_accesses(expr->args[i],
1361 read, write, accesses);
1363 if (expr->type == pet_expr_access &&
1364 isl_map_has_tuple_id(expr->acc.access, isl_dim_out) &&
1365 ((read && expr->acc.read) || (write && expr->acc.write)))
1366 accesses = isl_union_map_add_map(accesses,
1367 isl_map_copy(expr->acc.access));
1369 return accesses;
1372 /* Collect and return all read access relations (if "read" is set)
1373 * and/or all write * access relations (if "write" is set) in "stmt".
1375 static __isl_give isl_union_map *stmt_collect_accesses(struct pet_stmt *stmt,
1376 int read, int write, __isl_take isl_space *dim)
1378 isl_union_map *accesses;
1380 if (!stmt)
1381 return NULL;
1383 accesses = isl_union_map_empty(dim);
1384 accesses = expr_collect_accesses(stmt->body, read, write, accesses);
1385 accesses = isl_union_map_intersect_domain(accesses,
1386 isl_union_set_from_set(isl_set_copy(stmt->domain)));
1388 return accesses;
1391 /* Collect and return all read access relations (if "read" is set)
1392 * and/or all write * access relations (if "write" is set) in "scop".
1394 static __isl_give isl_union_map *scop_collect_accesses(struct pet_scop *scop,
1395 int read, int write)
1397 int i;
1398 isl_union_map *accesses;
1400 if (!scop)
1401 return NULL;
1403 accesses = isl_union_map_empty(isl_set_get_space(scop->context));
1405 for (i = 0; i < scop->n_stmt; ++i) {
1406 isl_union_map *accesses_i;
1407 isl_space *dim = isl_set_get_space(scop->context);
1408 accesses_i = stmt_collect_accesses(scop->stmts[i],
1409 read, write, dim);
1410 accesses = isl_union_map_union(accesses, accesses_i);
1413 return accesses;
1416 __isl_give isl_union_map *pet_scop_collect_reads(struct pet_scop *scop)
1418 return scop_collect_accesses(scop, 1, 0);
1421 __isl_give isl_union_map *pet_scop_collect_writes(struct pet_scop *scop)
1423 return scop_collect_accesses(scop, 0, 1);
1426 /* Collect and return the union of iteration domains in "scop".
1428 __isl_give isl_union_set *pet_scop_collect_domains(struct pet_scop *scop)
1430 int i;
1431 isl_set *domain_i;
1432 isl_union_set *domain;
1434 if (!scop)
1435 return NULL;
1437 domain = isl_union_set_empty(isl_set_get_space(scop->context));
1439 for (i = 0; i < scop->n_stmt; ++i) {
1440 domain_i = isl_set_copy(scop->stmts[i]->domain);
1441 domain = isl_union_set_add_set(domain, domain_i);
1444 return domain;
1447 /* Collect and return the schedules of the statements in "scop".
1448 * The range is normalized to the maximal number of scheduling
1449 * dimensions.
1451 __isl_give isl_union_map *pet_scop_collect_schedule(struct pet_scop *scop)
1453 int i, j;
1454 isl_map *schedule_i;
1455 isl_union_map *schedule;
1456 int depth, max_depth = 0;
1458 if (!scop)
1459 return NULL;
1461 schedule = isl_union_map_empty(isl_set_get_space(scop->context));
1463 for (i = 0; i < scop->n_stmt; ++i) {
1464 depth = isl_map_dim(scop->stmts[i]->schedule, isl_dim_out);
1465 if (depth > max_depth)
1466 max_depth = depth;
1469 for (i = 0; i < scop->n_stmt; ++i) {
1470 schedule_i = isl_map_copy(scop->stmts[i]->schedule);
1471 depth = isl_map_dim(schedule_i, isl_dim_out);
1472 schedule_i = isl_map_add_dims(schedule_i, isl_dim_out,
1473 max_depth - depth);
1474 for (j = depth; j < max_depth; ++j)
1475 schedule_i = isl_map_fix_si(schedule_i,
1476 isl_dim_out, j, 0);
1477 schedule = isl_union_map_add_map(schedule, schedule_i);
1480 return schedule;