update isl for isl_space_domain_factor_domain
[pet.git] / expr.c
blobb80cfef6a19ff97cc187c6c802e87e82d8b70cc2
1 /*
2 * Copyright 2011 Leiden University. All rights reserved.
3 * Copyright 2012-2014 Ecole Normale Superieure. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
35 #include <string.h>
37 #include "expr.h"
38 #include "filter.h"
39 #include "value_bounds.h"
41 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
43 static char *type_str[] = {
44 [pet_expr_access] = "access",
45 [pet_expr_call] = "call",
46 [pet_expr_cast] = "cast",
47 [pet_expr_double] = "double",
48 [pet_expr_int] = "int",
49 [pet_expr_op] = "op",
52 static char *op_str[] = {
53 [pet_op_add_assign] = "+=",
54 [pet_op_sub_assign] = "-=",
55 [pet_op_mul_assign] = "*=",
56 [pet_op_div_assign] = "/=",
57 [pet_op_assign] = "=",
58 [pet_op_add] = "+",
59 [pet_op_sub] = "-",
60 [pet_op_mul] = "*",
61 [pet_op_div] = "/",
62 [pet_op_mod] = "%",
63 [pet_op_shl] = "<<",
64 [pet_op_shr] = ">>",
65 [pet_op_eq] = "==",
66 [pet_op_ne] = "!=",
67 [pet_op_le] = "<=",
68 [pet_op_ge] = ">=",
69 [pet_op_lt] = "<",
70 [pet_op_gt] = ">",
71 [pet_op_minus] = "-",
72 [pet_op_post_inc] = "++",
73 [pet_op_post_dec] = "--",
74 [pet_op_pre_inc] = "++",
75 [pet_op_pre_dec] = "--",
76 [pet_op_address_of] = "&",
77 [pet_op_and] = "&",
78 [pet_op_xor] = "^",
79 [pet_op_or] = "|",
80 [pet_op_not] = "~",
81 [pet_op_land] = "&&",
82 [pet_op_lor] = "||",
83 [pet_op_lnot] = "!",
84 [pet_op_cond] = "?:",
85 [pet_op_assume] = "assume",
86 [pet_op_kill] = "kill"
89 const char *pet_op_str(enum pet_op_type op)
91 return op_str[op];
94 int pet_op_is_inc_dec(enum pet_op_type op)
96 return op == pet_op_post_inc || op == pet_op_post_dec ||
97 op == pet_op_pre_inc || op == pet_op_pre_dec;
100 const char *pet_type_str(enum pet_expr_type type)
102 return type_str[type];
105 enum pet_op_type pet_str_op(const char *str)
107 int i;
109 for (i = 0; i < ARRAY_SIZE(op_str); ++i)
110 if (!strcmp(op_str[i], str))
111 return i;
113 return -1;
116 enum pet_expr_type pet_str_type(const char *str)
118 int i;
120 for (i = 0; i < ARRAY_SIZE(type_str); ++i)
121 if (!strcmp(type_str[i], str))
122 return i;
124 return -1;
127 /* Construct an access pet_expr from an access relation and an index expression.
128 * By default, it is considered to be a read access.
130 struct pet_expr *pet_expr_from_access_and_index( __isl_take isl_map *access,
131 __isl_take isl_multi_pw_aff *index)
133 isl_ctx *ctx = isl_map_get_ctx(access);
134 struct pet_expr *expr;
136 if (!index || !access)
137 goto error;
138 expr = isl_calloc_type(ctx, struct pet_expr);
139 if (!expr)
140 goto error;
142 expr->type = pet_expr_access;
143 expr->acc.access = access;
144 expr->acc.index = index;
145 expr->acc.read = 1;
146 expr->acc.write = 0;
148 return expr;
149 error:
150 isl_map_free(access);
151 isl_multi_pw_aff_free(index);
152 return NULL;
155 /* Construct an access pet_expr from an index expression.
156 * By default, the access is considered to be a read access.
158 struct pet_expr *pet_expr_from_index(__isl_take isl_multi_pw_aff *index)
160 isl_map *access;
162 access = isl_map_from_multi_pw_aff(isl_multi_pw_aff_copy(index));
163 return pet_expr_from_access_and_index(access, index);
166 /* Extend the range of "access" with "n" dimensions, retaining
167 * the tuple identifier on this range.
169 * If "access" represents a member access, then extend the range
170 * of the member.
172 static __isl_give isl_map *extend_range(__isl_take isl_map *access, int n)
174 isl_id *id;
176 id = isl_map_get_tuple_id(access, isl_dim_out);
178 if (!isl_map_range_is_wrapping(access)) {
179 access = isl_map_add_dims(access, isl_dim_out, n);
180 } else {
181 isl_map *domain;
183 domain = isl_map_copy(access);
184 domain = isl_map_range_factor_domain(domain);
185 access = isl_map_range_factor_range(access);
186 access = extend_range(access, n);
187 access = isl_map_range_product(domain, access);
190 access = isl_map_set_tuple_id(access, isl_dim_out, id);
192 return access;
195 /* Construct an access pet_expr from an index expression and
196 * the depth of the accessed array.
197 * By default, the access is considered to be a read access.
199 * If the number of indices is smaller than the depth of the array,
200 * then we assume that all elements of the remaining dimensions
201 * are accessed.
203 struct pet_expr *pet_expr_from_index_and_depth(
204 __isl_take isl_multi_pw_aff *index, int depth)
206 isl_map *access;
207 int dim;
209 access = isl_map_from_multi_pw_aff(isl_multi_pw_aff_copy(index));
210 if (!access)
211 goto error;
212 dim = isl_map_dim(access, isl_dim_out);
213 if (dim > depth)
214 isl_die(isl_map_get_ctx(access), isl_error_internal,
215 "number of indices greater than depth",
216 access = isl_map_free(access));
217 if (dim == depth)
218 return pet_expr_from_access_and_index(access, index);
220 access = extend_range(access, depth - dim);
222 return pet_expr_from_access_and_index(access, index);
223 error:
224 isl_multi_pw_aff_free(index);
225 return NULL;
228 /* Construct a pet_expr that kills the elements specified by
229 * the index expression "index" and the access relation "access".
231 struct pet_expr *pet_expr_kill_from_access_and_index(__isl_take isl_map *access,
232 __isl_take isl_multi_pw_aff *index)
234 isl_ctx *ctx;
235 struct pet_expr *expr;
237 if (!access || !index)
238 goto error;
240 ctx = isl_multi_pw_aff_get_ctx(index);
241 expr = pet_expr_from_access_and_index(access, index);
242 if (!expr)
243 return NULL;
244 expr->acc.read = 0;
245 return pet_expr_new_unary(ctx, pet_op_kill, expr);
246 error:
247 isl_map_free(access);
248 isl_multi_pw_aff_free(index);
249 return NULL;
252 /* Construct a unary pet_expr that performs "op" on "arg".
254 struct pet_expr *pet_expr_new_unary(isl_ctx *ctx, enum pet_op_type op,
255 struct pet_expr *arg)
257 struct pet_expr *expr;
259 if (!arg)
260 goto error;
261 expr = isl_alloc_type(ctx, struct pet_expr);
262 if (!expr)
263 goto error;
265 expr->type = pet_expr_op;
266 expr->op = op;
267 expr->n_arg = 1;
268 expr->args = isl_calloc_array(ctx, struct pet_expr *, 1);
269 if (!expr->args)
270 goto error;
271 expr->args[pet_un_arg] = arg;
273 return expr;
274 error:
275 pet_expr_free(arg);
276 return NULL;
279 /* Construct a binary pet_expr that performs "op" on "lhs" and "rhs".
281 struct pet_expr *pet_expr_new_binary(isl_ctx *ctx, enum pet_op_type op,
282 struct pet_expr *lhs, struct pet_expr *rhs)
284 struct pet_expr *expr;
286 if (!lhs || !rhs)
287 goto error;
288 expr = isl_alloc_type(ctx, struct pet_expr);
289 if (!expr)
290 goto error;
292 expr->type = pet_expr_op;
293 expr->op = op;
294 expr->n_arg = 2;
295 expr->args = isl_calloc_array(ctx, struct pet_expr *, 2);
296 if (!expr->args)
297 goto error;
298 expr->args[pet_bin_lhs] = lhs;
299 expr->args[pet_bin_rhs] = rhs;
301 return expr;
302 error:
303 pet_expr_free(lhs);
304 pet_expr_free(rhs);
305 return NULL;
308 /* Construct a ternary pet_expr that performs "cond" ? "lhs" : "rhs".
310 struct pet_expr *pet_expr_new_ternary(isl_ctx *ctx, struct pet_expr *cond,
311 struct pet_expr *lhs, struct pet_expr *rhs)
313 struct pet_expr *expr;
315 if (!cond || !lhs || !rhs)
316 goto error;
317 expr = isl_alloc_type(ctx, struct pet_expr);
318 if (!expr)
319 goto error;
321 expr->type = pet_expr_op;
322 expr->op = pet_op_cond;
323 expr->n_arg = 3;
324 expr->args = isl_calloc_array(ctx, struct pet_expr *, 3);
325 if (!expr->args)
326 goto error;
327 expr->args[pet_ter_cond] = cond;
328 expr->args[pet_ter_true] = lhs;
329 expr->args[pet_ter_false] = rhs;
331 return expr;
332 error:
333 pet_expr_free(cond);
334 pet_expr_free(lhs);
335 pet_expr_free(rhs);
336 return NULL;
339 /* Construct a call pet_expr that calls function "name" with "n_arg"
340 * arguments. The caller is responsible for filling in the arguments.
342 struct pet_expr *pet_expr_new_call(isl_ctx *ctx, const char *name,
343 unsigned n_arg)
345 struct pet_expr *expr;
347 expr = isl_alloc_type(ctx, struct pet_expr);
348 if (!expr)
349 return NULL;
351 expr->type = pet_expr_call;
352 expr->n_arg = n_arg;
353 expr->name = strdup(name);
354 expr->args = isl_calloc_array(ctx, struct pet_expr *, n_arg);
355 if (!expr->name || !expr->args)
356 return pet_expr_free(expr);
358 return expr;
361 /* Construct a pet_expr that represents the cast of "arg" to "type_name".
363 struct pet_expr *pet_expr_new_cast(isl_ctx *ctx, const char *type_name,
364 struct pet_expr *arg)
366 struct pet_expr *expr;
368 if (!arg)
369 return NULL;
371 expr = isl_alloc_type(ctx, struct pet_expr);
372 if (!expr)
373 goto error;
375 expr->type = pet_expr_cast;
376 expr->n_arg = 1;
377 expr->type_name = strdup(type_name);
378 expr->args = isl_calloc_array(ctx, struct pet_expr *, 1);
379 if (!expr->type_name || !expr->args)
380 goto error;
382 expr->args[0] = arg;
384 return expr;
385 error:
386 pet_expr_free(arg);
387 pet_expr_free(expr);
388 return NULL;
391 /* Construct a pet_expr that represents the double "d".
393 struct pet_expr *pet_expr_new_double(isl_ctx *ctx, double val, const char *s)
395 struct pet_expr *expr;
397 expr = isl_calloc_type(ctx, struct pet_expr);
398 if (!expr)
399 return NULL;
401 expr->type = pet_expr_double;
402 expr->d.val = val;
403 expr->d.s = strdup(s);
404 if (!expr->d.s)
405 return pet_expr_free(expr);
407 return expr;
410 /* Construct a pet_expr that represents the integer value "v".
412 struct pet_expr *pet_expr_new_int(__isl_take isl_val *v)
414 isl_ctx *ctx;
415 struct pet_expr *expr;
417 if (!v)
418 return NULL;
420 ctx = isl_val_get_ctx(v);
421 expr = isl_calloc_type(ctx, struct pet_expr);
422 if (!expr)
423 goto error;
425 expr->type = pet_expr_int;
426 expr->i = v;
428 return expr;
429 error:
430 isl_val_free(v);
431 return NULL;
434 struct pet_expr *pet_expr_free(struct pet_expr *expr)
436 int i;
438 if (!expr)
439 return NULL;
441 for (i = 0; i < expr->n_arg; ++i)
442 pet_expr_free(expr->args[i]);
443 free(expr->args);
445 switch (expr->type) {
446 case pet_expr_access:
447 isl_id_free(expr->acc.ref_id);
448 isl_map_free(expr->acc.access);
449 isl_multi_pw_aff_free(expr->acc.index);
450 break;
451 case pet_expr_call:
452 free(expr->name);
453 break;
454 case pet_expr_cast:
455 free(expr->type_name);
456 break;
457 case pet_expr_double:
458 free(expr->d.s);
459 break;
460 case pet_expr_int:
461 isl_val_free(expr->i);
462 break;
463 case pet_expr_op:
464 break;
467 free(expr);
468 return NULL;
471 /* Does "expr" represent an access to an unnamed space, i.e.,
472 * does it represent an affine expression?
474 int pet_expr_is_affine(struct pet_expr *expr)
476 int has_id;
478 if (!expr)
479 return -1;
480 if (expr->type != pet_expr_access)
481 return 0;
483 has_id = isl_map_has_tuple_id(expr->acc.access, isl_dim_out);
484 if (has_id < 0)
485 return -1;
487 return !has_id;
490 /* Does "expr" represent an access to a scalar, i.e., zero-dimensional array?
492 int pet_expr_is_scalar_access(struct pet_expr *expr)
494 if (!expr)
495 return -1;
496 if (expr->type != pet_expr_access)
497 return 0;
499 return isl_map_dim(expr->acc.access, isl_dim_out) == 0;
502 /* Return 1 if the two pet_exprs are equivalent.
504 int pet_expr_is_equal(struct pet_expr *expr1, struct pet_expr *expr2)
506 int i;
508 if (!expr1 || !expr2)
509 return 0;
511 if (expr1->type != expr2->type)
512 return 0;
513 if (expr1->n_arg != expr2->n_arg)
514 return 0;
515 for (i = 0; i < expr1->n_arg; ++i)
516 if (!pet_expr_is_equal(expr1->args[i], expr2->args[i]))
517 return 0;
518 switch (expr1->type) {
519 case pet_expr_double:
520 if (strcmp(expr1->d.s, expr2->d.s))
521 return 0;
522 if (expr1->d.val != expr2->d.val)
523 return 0;
524 break;
525 case pet_expr_int:
526 if (!isl_val_eq(expr1->i, expr2->i))
527 return 0;
528 break;
529 case pet_expr_access:
530 if (expr1->acc.read != expr2->acc.read)
531 return 0;
532 if (expr1->acc.write != expr2->acc.write)
533 return 0;
534 if (expr1->acc.ref_id != expr2->acc.ref_id)
535 return 0;
536 if (!expr1->acc.access || !expr2->acc.access)
537 return 0;
538 if (!isl_map_is_equal(expr1->acc.access, expr2->acc.access))
539 return 0;
540 if (!expr1->acc.index || !expr2->acc.index)
541 return 0;
542 if (!isl_multi_pw_aff_plain_is_equal(expr1->acc.index,
543 expr2->acc.index))
544 return 0;
545 break;
546 case pet_expr_op:
547 if (expr1->op != expr2->op)
548 return 0;
549 break;
550 case pet_expr_call:
551 if (strcmp(expr1->name, expr2->name))
552 return 0;
553 break;
554 case pet_expr_cast:
555 if (strcmp(expr1->type_name, expr2->type_name))
556 return 0;
557 break;
560 return 1;
563 /* Return the identifier of the array accessed by "expr".
565 * If "expr" represents a member access, then return the identifier
566 * of the outer structure array.
568 __isl_give isl_id *pet_expr_access_get_id(struct pet_expr *expr)
570 if (!expr)
571 return NULL;
572 if (expr->type != pet_expr_access)
573 return NULL;
575 if (isl_map_range_is_wrapping(expr->acc.access)) {
576 isl_space *space;
577 isl_id *id;
579 space = isl_map_get_space(expr->acc.access);
580 space = isl_space_range(space);
581 while (space && isl_space_is_wrapping(space))
582 space = isl_space_domain(isl_space_unwrap(space));
583 id = isl_space_get_tuple_id(space, isl_dim_set);
584 isl_space_free(space);
586 return id;
589 return isl_map_get_tuple_id(expr->acc.access, isl_dim_out);
592 /* Return the parameter space of "expr".
594 __isl_give isl_space *pet_expr_access_get_parameter_space(struct pet_expr *expr)
596 isl_space *space;
598 if (!expr)
599 return NULL;
600 if (expr->type != pet_expr_access)
601 return NULL;
603 space = isl_multi_pw_aff_get_space(expr->acc.index);
604 space = isl_space_params(space);
606 return space;
609 /* Return the space of the data accessed by "expr".
611 __isl_give isl_space *pet_expr_access_get_data_space(struct pet_expr *expr)
613 isl_space *space;
615 if (!expr)
616 return NULL;
617 if (expr->type != pet_expr_access)
618 return NULL;
620 space = isl_multi_pw_aff_get_space(expr->acc.index);
621 space = isl_space_range(space);
623 return space;
626 /* Modify all expressions of type pet_expr_access in "expr"
627 * by calling "fn" on them.
629 struct pet_expr *pet_expr_map_access(struct pet_expr *expr,
630 struct pet_expr *(*fn)(struct pet_expr *expr, void *user),
631 void *user)
633 int i;
635 if (!expr)
636 return NULL;
638 for (i = 0; i < expr->n_arg; ++i) {
639 expr->args[i] = pet_expr_map_access(expr->args[i], fn, user);
640 if (!expr->args[i])
641 return pet_expr_free(expr);
644 if (expr->type == pet_expr_access)
645 expr = fn(expr, user);
647 return expr;
650 /* Call "fn" on each of the subexpressions of "expr" of type pet_expr_access.
652 * Return -1 on error (where fn return a negative value is treated as an error).
653 * Otherwise return 0.
655 int pet_expr_foreach_access_expr(struct pet_expr *expr,
656 int (*fn)(struct pet_expr *expr, void *user), void *user)
658 int i;
660 if (!expr)
661 return -1;
663 for (i = 0; i < expr->n_arg; ++i)
664 if (pet_expr_foreach_access_expr(expr->args[i], fn, user) < 0)
665 return -1;
667 if (expr->type == pet_expr_access)
668 return fn(expr, user);
670 return 0;
673 /* Internal data structure for pet_expr_writes.
674 * "id" is the identifier that we are looking for.
675 * "found" is set if we have found the identifier being written to.
677 struct pet_expr_writes_data {
678 isl_id *id;
679 int found;
682 /* Given an access expression, check if it writes to data->id.
683 * If so, set data->found and abort the search.
685 static int writes(struct pet_expr *expr, void *user)
687 struct pet_expr_writes_data *data = user;
688 isl_id *write_id;
690 if (!expr->acc.write)
691 return 0;
692 if (pet_expr_is_affine(expr))
693 return 0;
695 write_id = pet_expr_access_get_id(expr);
696 isl_id_free(write_id);
698 if (!write_id)
699 return -1;
701 if (write_id != data->id)
702 return 0;
704 data->found = 1;
705 return -1;
708 /* Does expression "expr" write to "id"?
710 int pet_expr_writes(struct pet_expr *expr, __isl_keep isl_id *id)
712 struct pet_expr_writes_data data;
714 data.id = id;
715 data.found = 0;
716 if (pet_expr_foreach_access_expr(expr, &writes, &data) < 0 &&
717 !data.found)
718 return -1;
720 return data.found;
723 /* Move the "n" dimensions of "src_type" starting at "src_pos" of
724 * index expression and access relation of "expr"
725 * to dimensions of "dst_type" at "dst_pos".
727 struct pet_expr *pet_expr_access_move_dims(struct pet_expr *expr,
728 enum isl_dim_type dst_type, unsigned dst_pos,
729 enum isl_dim_type src_type, unsigned src_pos, unsigned n)
731 if (!expr)
732 return NULL;
733 if (expr->type != pet_expr_access)
734 return pet_expr_free(expr);
736 expr->acc.access = isl_map_move_dims(expr->acc.access,
737 dst_type, dst_pos, src_type, src_pos, n);
738 expr->acc.index = isl_multi_pw_aff_move_dims(expr->acc.index,
739 dst_type, dst_pos, src_type, src_pos, n);
740 if (!expr->acc.access || !expr->acc.index)
741 return pet_expr_free(expr);
743 return expr;
746 /* Replace the index expression and access relation of "expr"
747 * by their preimages under the function represented by "ma".
749 struct pet_expr *pet_expr_access_pullback_multi_aff(
750 struct pet_expr *expr, __isl_take isl_multi_aff *ma)
752 if (!expr || !ma)
753 goto error;
754 if (expr->type != pet_expr_access)
755 goto error;
757 expr->acc.access = isl_map_preimage_domain_multi_aff(expr->acc.access,
758 isl_multi_aff_copy(ma));
759 expr->acc.index = isl_multi_pw_aff_pullback_multi_aff(expr->acc.index,
760 ma);
761 if (!expr->acc.access || !expr->acc.index)
762 return pet_expr_free(expr);
764 return expr;
765 error:
766 isl_multi_aff_free(ma);
767 pet_expr_free(expr);
768 return NULL;
771 /* Align the parameters of expr->acc.index and expr->acc.access.
773 struct pet_expr *pet_expr_access_align_params(struct pet_expr *expr)
775 if (!expr)
776 return NULL;
777 if (expr->type != pet_expr_access)
778 return pet_expr_free(expr);
780 expr->acc.access = isl_map_align_params(expr->acc.access,
781 isl_multi_pw_aff_get_space(expr->acc.index));
782 expr->acc.index = isl_multi_pw_aff_align_params(expr->acc.index,
783 isl_map_get_space(expr->acc.access));
784 if (!expr->acc.access || !expr->acc.index)
785 return pet_expr_free(expr);
787 return expr;
790 /* Add extra conditions on the parameters to all access relations in "expr".
792 * The conditions are not added to the index expression. Instead, they
793 * are used to try and simplify the index expression.
795 struct pet_expr *pet_expr_restrict(struct pet_expr *expr,
796 __isl_take isl_set *cond)
798 int i;
800 if (!expr)
801 goto error;
803 for (i = 0; i < expr->n_arg; ++i) {
804 expr->args[i] = pet_expr_restrict(expr->args[i],
805 isl_set_copy(cond));
806 if (!expr->args[i])
807 goto error;
810 if (expr->type == pet_expr_access) {
811 expr->acc.access = isl_map_intersect_params(expr->acc.access,
812 isl_set_copy(cond));
813 expr->acc.index = isl_multi_pw_aff_gist_params(
814 expr->acc.index, isl_set_copy(cond));
815 if (!expr->acc.access || !expr->acc.index)
816 goto error;
819 isl_set_free(cond);
820 return expr;
821 error:
822 isl_set_free(cond);
823 return pet_expr_free(expr);
826 /* Modify the access relation and index expression
827 * of the given access expression
828 * based on the given iteration space transformation.
829 * In particular, precompose the access relation and index expression
830 * with the update function.
832 * If the access has any arguments then the domain of the access relation
833 * is a wrapped mapping from the iteration space to the space of
834 * argument values. We only need to change the domain of this wrapped
835 * mapping, so we extend the input transformation with an identity mapping
836 * on the space of argument values.
838 struct pet_expr *pet_expr_access_update_domain(struct pet_expr *expr,
839 __isl_keep isl_multi_pw_aff *update)
841 isl_space *space;
843 update = isl_multi_pw_aff_copy(update);
845 space = isl_map_get_space(expr->acc.access);
846 space = isl_space_domain(space);
847 if (!isl_space_is_wrapping(space))
848 isl_space_free(space);
849 else {
850 isl_multi_pw_aff *id;
851 space = isl_space_unwrap(space);
852 space = isl_space_range(space);
853 space = isl_space_map_from_set(space);
854 id = isl_multi_pw_aff_identity(space);
855 update = isl_multi_pw_aff_product(update, id);
858 expr->acc.access = isl_map_preimage_domain_multi_pw_aff(
859 expr->acc.access,
860 isl_multi_pw_aff_copy(update));
861 expr->acc.index = isl_multi_pw_aff_pullback_multi_pw_aff(
862 expr->acc.index, update);
863 if (!expr->acc.access || !expr->acc.index)
864 return pet_expr_free(expr);
866 return expr;
869 static struct pet_expr *update_domain(struct pet_expr *expr, void *user)
871 isl_multi_pw_aff *update = user;
873 return pet_expr_access_update_domain(expr, update);
876 /* Modify all access relations in "expr" by precomposing them with
877 * the given iteration space transformation.
879 struct pet_expr *pet_expr_update_domain(struct pet_expr *expr,
880 __isl_take isl_multi_pw_aff *update)
882 expr = pet_expr_map_access(expr, &update_domain, update);
883 isl_multi_pw_aff_free(update);
884 return expr;
887 /* Add all parameters in "space" to the access relation and index expression
888 * of "expr".
890 static struct pet_expr *align_params(struct pet_expr *expr, void *user)
892 isl_space *space = user;
894 expr->acc.access = isl_map_align_params(expr->acc.access,
895 isl_space_copy(space));
896 expr->acc.index = isl_multi_pw_aff_align_params(expr->acc.index,
897 isl_space_copy(space));
898 if (!expr->acc.access || !expr->acc.index)
899 return pet_expr_free(expr);
901 return expr;
904 /* Add all parameters in "space" to all access relations and index expressions
905 * in "expr".
907 struct pet_expr *pet_expr_align_params(struct pet_expr *expr,
908 __isl_take isl_space *space)
910 expr = pet_expr_map_access(expr, &align_params, space);
911 isl_space_free(space);
912 return expr;
915 /* Insert an argument expression corresponding to "test" in front
916 * of the list of arguments described by *n_arg and *args.
918 static struct pet_expr *insert_access_arg(struct pet_expr *expr,
919 __isl_keep isl_multi_pw_aff *test)
921 int i;
922 isl_ctx *ctx = isl_multi_pw_aff_get_ctx(test);
924 if (!test)
925 return pet_expr_free(expr);
927 if (!expr->args) {
928 expr->args = isl_calloc_array(ctx, struct pet_expr *, 1);
929 if (!expr->args)
930 return pet_expr_free(expr);
931 } else {
932 struct pet_expr **ext;
933 ext = isl_calloc_array(ctx, struct pet_expr *, 1 + expr->n_arg);
934 if (!ext)
935 return pet_expr_free(expr);
936 for (i = 0; i < expr->n_arg; ++i)
937 ext[1 + i] = expr->args[i];
938 free(expr->args);
939 expr->args = ext;
941 expr->n_arg++;
942 expr->args[0] = pet_expr_from_index(isl_multi_pw_aff_copy(test));
943 if (!expr->args[0])
944 return pet_expr_free(expr);
946 return expr;
949 /* Make the expression "expr" depend on the value of "test"
950 * being equal to "satisfied".
952 * If "test" is an affine expression, we simply add the conditions
953 * on the expression having the value "satisfied" to all access relations
954 * and index expressions.
956 * Otherwise, we add a filter to "expr" (which is then assumed to be
957 * an access expression) corresponding to "test" being equal to "satisfied".
959 struct pet_expr *pet_expr_filter(struct pet_expr *expr,
960 __isl_take isl_multi_pw_aff *test, int satisfied)
962 isl_id *id;
963 isl_ctx *ctx;
964 isl_space *space;
965 isl_pw_multi_aff *pma;
967 if (!expr || !test)
968 goto error;
970 if (!isl_multi_pw_aff_has_tuple_id(test, isl_dim_out)) {
971 isl_pw_aff *pa;
972 isl_set *cond;
974 pa = isl_multi_pw_aff_get_pw_aff(test, 0);
975 isl_multi_pw_aff_free(test);
976 if (satisfied)
977 cond = isl_pw_aff_non_zero_set(pa);
978 else
979 cond = isl_pw_aff_zero_set(pa);
980 return pet_expr_restrict(expr, isl_set_params(cond));
983 ctx = isl_multi_pw_aff_get_ctx(test);
984 if (expr->type != pet_expr_access)
985 isl_die(ctx, isl_error_invalid,
986 "can only filter access expressions", goto error);
988 space = isl_space_domain(isl_map_get_space(expr->acc.access));
989 id = isl_multi_pw_aff_get_tuple_id(test, isl_dim_out);
990 pma = pet_filter_insert_pma(space, id, satisfied);
992 expr->acc.access = isl_map_preimage_domain_pw_multi_aff(
993 expr->acc.access,
994 isl_pw_multi_aff_copy(pma));
995 expr->acc.index = isl_multi_pw_aff_pullback_pw_multi_aff(
996 expr->acc.index, pma);
997 if (!expr->acc.access || !expr->acc.index)
998 goto error;
1000 expr = insert_access_arg(expr, test);
1002 isl_multi_pw_aff_free(test);
1003 return expr;
1004 error:
1005 isl_multi_pw_aff_free(test);
1006 return pet_expr_free(expr);
1009 /* Check if the given index expression accesses a (0D) array that corresponds
1010 * to one of the parameters in "space". If so, replace the array access
1011 * by an access to the set of integers with as index (and value)
1012 * that parameter.
1014 static __isl_give isl_multi_pw_aff *index_detect_parameter(
1015 __isl_take isl_multi_pw_aff *index, __isl_take isl_space *space)
1017 isl_local_space *ls;
1018 isl_id *array_id = NULL;
1019 isl_aff *aff;
1020 int pos = -1;
1022 if (isl_multi_pw_aff_has_tuple_id(index, isl_dim_out)) {
1023 array_id = isl_multi_pw_aff_get_tuple_id(index, isl_dim_out);
1024 pos = isl_space_find_dim_by_id(space, isl_dim_param, array_id);
1026 isl_space_free(space);
1028 if (pos < 0) {
1029 isl_id_free(array_id);
1030 return index;
1033 space = isl_multi_pw_aff_get_domain_space(index);
1034 isl_multi_pw_aff_free(index);
1036 pos = isl_space_find_dim_by_id(space, isl_dim_param, array_id);
1037 if (pos < 0) {
1038 space = isl_space_insert_dims(space, isl_dim_param, 0, 1);
1039 space = isl_space_set_dim_id(space, isl_dim_param, 0, array_id);
1040 pos = 0;
1041 } else
1042 isl_id_free(array_id);
1044 ls = isl_local_space_from_space(space);
1045 aff = isl_aff_var_on_domain(ls, isl_dim_param, pos);
1046 index = isl_multi_pw_aff_from_pw_aff(isl_pw_aff_from_aff(aff));
1048 return index;
1051 /* Check if the given access relation accesses a (0D) array that corresponds
1052 * to one of the parameters in "space". If so, replace the array access
1053 * by an access to the set of integers with as index (and value)
1054 * that parameter.
1056 static __isl_give isl_map *access_detect_parameter(__isl_take isl_map *access,
1057 __isl_take isl_space *space)
1059 isl_id *array_id = NULL;
1060 int pos = -1;
1062 if (isl_map_has_tuple_id(access, isl_dim_out)) {
1063 array_id = isl_map_get_tuple_id(access, isl_dim_out);
1064 pos = isl_space_find_dim_by_id(space, isl_dim_param, array_id);
1066 isl_space_free(space);
1068 if (pos < 0) {
1069 isl_id_free(array_id);
1070 return access;
1073 pos = isl_map_find_dim_by_id(access, isl_dim_param, array_id);
1074 if (pos < 0) {
1075 access = isl_map_insert_dims(access, isl_dim_param, 0, 1);
1076 access = isl_map_set_dim_id(access, isl_dim_param, 0, array_id);
1077 pos = 0;
1078 } else
1079 isl_id_free(array_id);
1081 access = isl_map_insert_dims(access, isl_dim_out, 0, 1);
1082 access = isl_map_equate(access, isl_dim_param, pos, isl_dim_out, 0);
1084 return access;
1087 /* If "expr" accesses a (0D) array that corresponds to one of the parameters
1088 * in "space" then replace it by a value equal to the corresponding parameter.
1090 static struct pet_expr *detect_parameter_accesses(struct pet_expr *expr,
1091 void *user)
1093 isl_space *space = user;
1095 expr->acc.access = access_detect_parameter(expr->acc.access,
1096 isl_space_copy(space));
1097 expr->acc.index = index_detect_parameter(expr->acc.index,
1098 isl_space_copy(space));
1099 if (!expr->acc.access || !expr->acc.index)
1100 return pet_expr_free(expr);
1102 return expr;
1105 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
1106 * in "space" by a value equal to the corresponding parameter.
1108 struct pet_expr *pet_expr_detect_parameter_accesses(struct pet_expr *expr,
1109 __isl_take isl_space *space)
1111 expr = pet_expr_map_access(expr, &detect_parameter_accesses, space);
1112 isl_space_free(space);
1113 return expr;
1116 /* Add a reference identifier to access expression "expr".
1117 * "user" points to an integer that contains the sequence number
1118 * of the next reference.
1120 static struct pet_expr *access_add_ref_id(struct pet_expr *expr, void *user)
1122 isl_ctx *ctx;
1123 char name[50];
1124 int *n_ref = user;
1126 if (!expr)
1127 return expr;
1129 ctx = isl_map_get_ctx(expr->acc.access);
1130 snprintf(name, sizeof(name), "__pet_ref_%d", (*n_ref)++);
1131 expr->acc.ref_id = isl_id_alloc(ctx, name, NULL);
1132 if (!expr->acc.ref_id)
1133 return pet_expr_free(expr);
1135 return expr;
1138 struct pet_expr *pet_expr_add_ref_ids(struct pet_expr *expr, int *n_ref)
1140 return pet_expr_map_access(expr, &access_add_ref_id, n_ref);
1143 /* Reset the user pointer on all parameter and tuple ids in
1144 * the access relation and the index expressions
1145 * of the access expression "expr".
1147 static struct pet_expr *access_anonymize(struct pet_expr *expr, void *user)
1149 expr->acc.access = isl_map_reset_user(expr->acc.access);
1150 expr->acc.index = isl_multi_pw_aff_reset_user(expr->acc.index);
1151 if (!expr->acc.access || !expr->acc.index)
1152 return pet_expr_free(expr);
1154 return expr;
1157 struct pet_expr *pet_expr_anonymize(struct pet_expr *expr)
1159 return pet_expr_map_access(expr, &access_anonymize, NULL);
1162 /* Data used in access_gist() callback.
1164 struct pet_access_gist_data {
1165 isl_set *domain;
1166 isl_union_map *value_bounds;
1169 /* Given an expression "expr" of type pet_expr_access, compute
1170 * the gist of the associated access relation and index expression
1171 * with respect to data->domain and the bounds on the values of the arguments
1172 * of the expression.
1174 static struct pet_expr *access_gist(struct pet_expr *expr, void *user)
1176 struct pet_access_gist_data *data = user;
1177 isl_set *domain;
1179 domain = isl_set_copy(data->domain);
1180 if (expr->n_arg > 0)
1181 domain = pet_value_bounds_apply(domain, expr->n_arg, expr->args,
1182 data->value_bounds);
1184 expr->acc.access = isl_map_gist_domain(expr->acc.access,
1185 isl_set_copy(domain));
1186 expr->acc.index = isl_multi_pw_aff_gist(expr->acc.index, domain);
1187 if (!expr->acc.access || !expr->acc.index)
1188 return pet_expr_free(expr);
1190 return expr;
1193 struct pet_expr *pet_expr_gist(struct pet_expr *expr,
1194 __isl_keep isl_set *context, __isl_keep isl_union_map *value_bounds)
1196 struct pet_access_gist_data data = { context, value_bounds };
1198 return pet_expr_map_access(expr, &access_gist, &data);
1201 /* Tag the access relation "access" with "id".
1202 * That is, insert the id as the range of a wrapped relation
1203 * in the domain of "access".
1205 * If "access" is of the form
1207 * D[i] -> A[a]
1209 * then the result is of the form
1211 * [D[i] -> id[]] -> A[a]
1213 __isl_give isl_map *pet_expr_tag_access(struct pet_expr *expr,
1214 __isl_take isl_map *access)
1216 isl_space *space;
1217 isl_map *add_tag;
1218 isl_id *id;
1220 id = isl_id_copy(expr->acc.ref_id);
1221 space = isl_space_range(isl_map_get_space(access));
1222 space = isl_space_from_range(space);
1223 space = isl_space_set_tuple_id(space, isl_dim_in, id);
1224 add_tag = isl_map_universe(space);
1225 access = isl_map_domain_product(access, add_tag);
1227 return access;
1230 /* Return the relation mapping domain iterations to all possibly
1231 * accessed data elements.
1232 * In particular, take the access relation and project out the values
1233 * of the arguments, if any.
1235 __isl_give isl_map *pet_expr_access_get_may_access(struct pet_expr *expr)
1237 isl_map *access;
1238 isl_space *space;
1239 isl_map *map;
1241 if (!expr)
1242 return NULL;
1243 if (expr->type != pet_expr_access)
1244 return NULL;
1246 access = isl_map_copy(expr->acc.access);
1247 if (expr->n_arg == 0)
1248 return access;
1250 space = isl_space_domain(isl_map_get_space(access));
1251 map = isl_map_universe(isl_space_unwrap(space));
1252 map = isl_map_domain_map(map);
1253 access = isl_map_apply_domain(access, map);
1255 return access;
1258 /* Return the relation mapping domain iterations to all possibly
1259 * accessed data elements, with its domain tagged with the reference
1260 * identifier.
1262 __isl_give isl_map *pet_expr_access_get_tagged_may_access(
1263 struct pet_expr *expr)
1265 isl_map *access;
1267 if (!expr)
1268 return NULL;
1270 access = pet_expr_access_get_may_access(expr);
1271 access = pet_expr_tag_access(expr, access);
1273 return access;
1276 void pet_expr_dump_with_indent(struct pet_expr *expr, int indent)
1278 int i;
1280 if (!expr)
1281 return;
1283 fprintf(stderr, "%*s", indent, "");
1285 switch (expr->type) {
1286 case pet_expr_double:
1287 fprintf(stderr, "%s\n", expr->d.s);
1288 break;
1289 case pet_expr_int:
1290 isl_val_dump(expr->i);
1291 break;
1292 case pet_expr_access:
1293 if (expr->acc.ref_id) {
1294 isl_id_dump(expr->acc.ref_id);
1295 fprintf(stderr, "%*s", indent, "");
1297 isl_map_dump(expr->acc.access);
1298 fprintf(stderr, "%*s", indent, "");
1299 isl_multi_pw_aff_dump(expr->acc.index);
1300 fprintf(stderr, "%*sread: %d\n", indent + 2,
1301 "", expr->acc.read);
1302 fprintf(stderr, "%*swrite: %d\n", indent + 2,
1303 "", expr->acc.write);
1304 for (i = 0; i < expr->n_arg; ++i)
1305 pet_expr_dump_with_indent(expr->args[i], indent + 2);
1306 break;
1307 case pet_expr_op:
1308 fprintf(stderr, "%s\n", op_str[expr->op]);
1309 for (i = 0; i < expr->n_arg; ++i)
1310 pet_expr_dump_with_indent(expr->args[i], indent + 2);
1311 break;
1312 case pet_expr_call:
1313 fprintf(stderr, "%s/%d\n", expr->name, expr->n_arg);
1314 for (i = 0; i < expr->n_arg; ++i)
1315 pet_expr_dump_with_indent(expr->args[i], indent + 2);
1316 break;
1317 case pet_expr_cast:
1318 fprintf(stderr, "(%s)\n", expr->type_name);
1319 for (i = 0; i < expr->n_arg; ++i)
1320 pet_expr_dump_with_indent(expr->args[i], indent + 2);
1321 break;
1325 void pet_expr_dump(struct pet_expr *expr)
1327 pet_expr_dump_with_indent(expr, 0);