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
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
36 #include <isl/constraint.h>
37 #include <isl/union_set.h>
42 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
44 static char *type_str
[] = {
45 [pet_expr_access
] = "access",
46 [pet_expr_call
] = "call",
47 [pet_expr_cast
] = "cast",
48 [pet_expr_double
] = "double",
49 [pet_expr_unary
] = "unary",
50 [pet_expr_binary
] = "binary",
51 [pet_expr_ternary
] = "ternary"
54 static char *op_str
[] = {
55 [pet_op_add_assign
] = "+=",
56 [pet_op_sub_assign
] = "-=",
57 [pet_op_mul_assign
] = "*=",
58 [pet_op_div_assign
] = "/=",
59 [pet_op_assign
] = "=",
74 [pet_op_post_inc
] = "++",
75 [pet_op_post_dec
] = "--",
76 [pet_op_pre_inc
] = "++",
77 [pet_op_pre_dec
] = "--",
78 [pet_op_address_of
] = "&",
86 [pet_op_assume
] = "assume",
87 [pet_op_kill
] = "kill"
90 /* pet_scop with extra information that is used during parsing and printing.
92 * In particular, we keep track of conditions under which we want
93 * to skip the rest of the current loop iteration (skip[pet_skip_now])
94 * and of conditions under which we want to skip subsequent
95 * loop iterations (skip[pet_skip_later]).
97 * The conditions are represented as index expressions defined
98 * over a zero-dimensional domain. The index expression is either
99 * a boolean affine expression or an access to a variable, which
100 * is assumed to attain values zero and one. The condition holds
101 * if the variable has value one or if the affine expression
102 * has value one (typically for only part of the parameter space).
104 * A missing condition (skip[type] == NULL) means that we don't want
107 * Additionally, we keep track of the original input file
108 * inside pet_transform_C_source.
110 struct pet_scop_ext
{
111 struct pet_scop scop
;
113 isl_multi_pw_aff
*skip
[2];
117 const char *pet_op_str(enum pet_op_type op
)
122 int pet_op_is_inc_dec(enum pet_op_type op
)
124 return op
== pet_op_post_inc
|| op
== pet_op_post_dec
||
125 op
== pet_op_pre_inc
|| op
== pet_op_pre_dec
;
128 const char *pet_type_str(enum pet_expr_type type
)
130 return type_str
[type
];
133 enum pet_op_type
pet_str_op(const char *str
)
137 for (i
= 0; i
< ARRAY_SIZE(op_str
); ++i
)
138 if (!strcmp(op_str
[i
], str
))
144 enum pet_expr_type
pet_str_type(const char *str
)
148 for (i
= 0; i
< ARRAY_SIZE(type_str
); ++i
)
149 if (!strcmp(type_str
[i
], str
))
155 /* Construct an access pet_expr from an access relation and an index expression.
156 * By default, it is considered to be a read access.
158 struct pet_expr
*pet_expr_from_access_and_index( __isl_take isl_map
*access
,
159 __isl_take isl_multi_pw_aff
*index
)
161 isl_ctx
*ctx
= isl_map_get_ctx(access
);
162 struct pet_expr
*expr
;
164 if (!index
|| !access
)
166 expr
= isl_calloc_type(ctx
, struct pet_expr
);
170 expr
->type
= pet_expr_access
;
171 expr
->acc
.access
= access
;
172 expr
->acc
.index
= index
;
178 isl_map_free(access
);
179 isl_multi_pw_aff_free(index
);
183 /* Construct an access pet_expr from an index expression.
184 * By default, the access is considered to be a read access.
186 struct pet_expr
*pet_expr_from_index(__isl_take isl_multi_pw_aff
*index
)
190 access
= isl_map_from_multi_pw_aff(isl_multi_pw_aff_copy(index
));
191 return pet_expr_from_access_and_index(access
, index
);
194 /* Extend the range of "access" with "n" dimensions, retaining
195 * the tuple identifier on this range.
197 * If "access" represents a member access, then extend the range
200 static __isl_give isl_map
*extend_range(__isl_take isl_map
*access
, int n
)
204 id
= isl_map_get_tuple_id(access
, isl_dim_out
);
206 if (!isl_map_range_is_wrapping(access
)) {
207 access
= isl_map_add_dims(access
, isl_dim_out
, n
);
211 domain
= isl_map_copy(access
);
212 domain
= isl_map_range_factor_domain(domain
);
213 access
= isl_map_range_factor_range(access
);
214 access
= extend_range(access
, n
);
215 access
= isl_map_range_product(domain
, access
);
218 access
= isl_map_set_tuple_id(access
, isl_dim_out
, id
);
223 /* Construct an access pet_expr from an index expression and
224 * the depth of the accessed array.
225 * By default, the access is considered to be a read access.
227 * If the number of indices is smaller than the depth of the array,
228 * then we assume that all elements of the remaining dimensions
231 struct pet_expr
*pet_expr_from_index_and_depth(
232 __isl_take isl_multi_pw_aff
*index
, int depth
)
237 access
= isl_map_from_multi_pw_aff(isl_multi_pw_aff_copy(index
));
240 dim
= isl_map_dim(access
, isl_dim_out
);
242 isl_die(isl_map_get_ctx(access
), isl_error_internal
,
243 "number of indices greater than depth",
244 access
= isl_map_free(access
));
246 return pet_expr_from_access_and_index(access
, index
);
248 access
= extend_range(access
, depth
- dim
);
250 return pet_expr_from_access_and_index(access
, index
);
252 isl_multi_pw_aff_free(index
);
256 /* Construct a pet_expr that kills the elements specified by
257 * the index expression "index" and the access relation "access".
259 struct pet_expr
*pet_expr_kill_from_access_and_index(__isl_take isl_map
*access
,
260 __isl_take isl_multi_pw_aff
*index
)
263 struct pet_expr
*expr
;
265 if (!access
|| !index
)
268 ctx
= isl_multi_pw_aff_get_ctx(index
);
269 expr
= pet_expr_from_access_and_index(access
, index
);
273 return pet_expr_new_unary(ctx
, pet_op_kill
, expr
);
275 isl_map_free(access
);
276 isl_multi_pw_aff_free(index
);
280 /* Construct a unary pet_expr that performs "op" on "arg".
282 struct pet_expr
*pet_expr_new_unary(isl_ctx
*ctx
, enum pet_op_type op
,
283 struct pet_expr
*arg
)
285 struct pet_expr
*expr
;
289 expr
= isl_alloc_type(ctx
, struct pet_expr
);
293 expr
->type
= pet_expr_unary
;
296 expr
->args
= isl_calloc_array(ctx
, struct pet_expr
*, 1);
299 expr
->args
[pet_un_arg
] = arg
;
307 /* Construct a binary pet_expr that performs "op" on "lhs" and "rhs".
309 struct pet_expr
*pet_expr_new_binary(isl_ctx
*ctx
, enum pet_op_type op
,
310 struct pet_expr
*lhs
, struct pet_expr
*rhs
)
312 struct pet_expr
*expr
;
316 expr
= isl_alloc_type(ctx
, struct pet_expr
);
320 expr
->type
= pet_expr_binary
;
323 expr
->args
= isl_calloc_array(ctx
, struct pet_expr
*, 2);
326 expr
->args
[pet_bin_lhs
] = lhs
;
327 expr
->args
[pet_bin_rhs
] = rhs
;
336 /* Construct a ternary pet_expr that performs "cond" ? "lhs" : "rhs".
338 struct pet_expr
*pet_expr_new_ternary(isl_ctx
*ctx
, struct pet_expr
*cond
,
339 struct pet_expr
*lhs
, struct pet_expr
*rhs
)
341 struct pet_expr
*expr
;
343 if (!cond
|| !lhs
|| !rhs
)
345 expr
= isl_alloc_type(ctx
, struct pet_expr
);
349 expr
->type
= pet_expr_ternary
;
351 expr
->args
= isl_calloc_array(ctx
, struct pet_expr
*, 3);
354 expr
->args
[pet_ter_cond
] = cond
;
355 expr
->args
[pet_ter_true
] = lhs
;
356 expr
->args
[pet_ter_false
] = rhs
;
366 /* Construct a call pet_expr that calls function "name" with "n_arg"
367 * arguments. The caller is responsible for filling in the arguments.
369 struct pet_expr
*pet_expr_new_call(isl_ctx
*ctx
, const char *name
,
372 struct pet_expr
*expr
;
374 expr
= isl_alloc_type(ctx
, struct pet_expr
);
378 expr
->type
= pet_expr_call
;
380 expr
->name
= strdup(name
);
381 expr
->args
= isl_calloc_array(ctx
, struct pet_expr
*, n_arg
);
382 if (!expr
->name
|| !expr
->args
)
383 return pet_expr_free(expr
);
388 /* Construct a pet_expr that represents the cast of "arg" to "type_name".
390 struct pet_expr
*pet_expr_new_cast(isl_ctx
*ctx
, const char *type_name
,
391 struct pet_expr
*arg
)
393 struct pet_expr
*expr
;
398 expr
= isl_alloc_type(ctx
, struct pet_expr
);
402 expr
->type
= pet_expr_cast
;
404 expr
->type_name
= strdup(type_name
);
405 expr
->args
= isl_calloc_array(ctx
, struct pet_expr
*, 1);
406 if (!expr
->type_name
|| !expr
->args
)
418 /* Construct a pet_expr that represents the double "d".
420 struct pet_expr
*pet_expr_new_double(isl_ctx
*ctx
, double val
, const char *s
)
422 struct pet_expr
*expr
;
424 expr
= isl_calloc_type(ctx
, struct pet_expr
);
428 expr
->type
= pet_expr_double
;
430 expr
->d
.s
= strdup(s
);
432 return pet_expr_free(expr
);
437 struct pet_expr
*pet_expr_free(struct pet_expr
*expr
)
444 for (i
= 0; i
< expr
->n_arg
; ++i
)
445 pet_expr_free(expr
->args
[i
]);
448 switch (expr
->type
) {
449 case pet_expr_access
:
450 isl_id_free(expr
->acc
.ref_id
);
451 isl_map_free(expr
->acc
.access
);
452 isl_multi_pw_aff_free(expr
->acc
.index
);
458 free(expr
->type_name
);
460 case pet_expr_double
:
464 case pet_expr_binary
:
465 case pet_expr_ternary
:
473 static void expr_dump(struct pet_expr
*expr
, int indent
)
480 fprintf(stderr
, "%*s", indent
, "");
482 switch (expr
->type
) {
483 case pet_expr_double
:
484 fprintf(stderr
, "%s\n", expr
->d
.s
);
486 case pet_expr_access
:
487 if (expr
->acc
.ref_id
) {
488 isl_id_dump(expr
->acc
.ref_id
);
489 fprintf(stderr
, "%*s", indent
, "");
491 isl_map_dump(expr
->acc
.access
);
492 fprintf(stderr
, "%*s", indent
, "");
493 isl_multi_pw_aff_dump(expr
->acc
.index
);
494 fprintf(stderr
, "%*sread: %d\n", indent
+ 2,
496 fprintf(stderr
, "%*swrite: %d\n", indent
+ 2,
497 "", expr
->acc
.write
);
498 for (i
= 0; i
< expr
->n_arg
; ++i
)
499 expr_dump(expr
->args
[i
], indent
+ 2);
502 fprintf(stderr
, "%s\n", op_str
[expr
->op
]);
503 expr_dump(expr
->args
[pet_un_arg
], indent
+ 2);
505 case pet_expr_binary
:
506 fprintf(stderr
, "%s\n", op_str
[expr
->op
]);
507 expr_dump(expr
->args
[pet_bin_lhs
], indent
+ 2);
508 expr_dump(expr
->args
[pet_bin_rhs
], indent
+ 2);
510 case pet_expr_ternary
:
511 fprintf(stderr
, "?:\n");
512 expr_dump(expr
->args
[pet_ter_cond
], indent
+ 2);
513 expr_dump(expr
->args
[pet_ter_true
], indent
+ 2);
514 expr_dump(expr
->args
[pet_ter_false
], indent
+ 2);
517 fprintf(stderr
, "%s/%d\n", expr
->name
, expr
->n_arg
);
518 for (i
= 0; i
< expr
->n_arg
; ++i
)
519 expr_dump(expr
->args
[i
], indent
+ 2);
522 fprintf(stderr
, "(%s)\n", expr
->type_name
);
523 for (i
= 0; i
< expr
->n_arg
; ++i
)
524 expr_dump(expr
->args
[i
], indent
+ 2);
529 void pet_expr_dump(struct pet_expr
*expr
)
534 /* Does "expr" represent an access to an unnamed space, i.e.,
535 * does it represent an affine expression?
537 int pet_expr_is_affine(struct pet_expr
*expr
)
543 if (expr
->type
!= pet_expr_access
)
546 has_id
= isl_map_has_tuple_id(expr
->acc
.access
, isl_dim_out
);
553 /* Return the identifier of the array accessed by "expr".
555 * If "expr" represents a member access, then return the identifier
556 * of the outer structure array.
558 __isl_give isl_id
*pet_expr_access_get_id(struct pet_expr
*expr
)
562 if (expr
->type
!= pet_expr_access
)
565 if (isl_map_range_is_wrapping(expr
->acc
.access
)) {
569 space
= isl_map_get_space(expr
->acc
.access
);
570 space
= isl_space_range(space
);
571 while (space
&& isl_space_is_wrapping(space
))
572 space
= isl_space_domain(isl_space_unwrap(space
));
573 id
= isl_space_get_tuple_id(space
, isl_dim_set
);
574 isl_space_free(space
);
579 return isl_map_get_tuple_id(expr
->acc
.access
, isl_dim_out
);
582 /* Align the parameters of expr->acc.index and expr->acc.access.
584 struct pet_expr
*pet_expr_access_align_params(struct pet_expr
*expr
)
588 if (expr
->type
!= pet_expr_access
)
589 return pet_expr_free(expr
);
591 expr
->acc
.access
= isl_map_align_params(expr
->acc
.access
,
592 isl_multi_pw_aff_get_space(expr
->acc
.index
));
593 expr
->acc
.index
= isl_multi_pw_aff_align_params(expr
->acc
.index
,
594 isl_map_get_space(expr
->acc
.access
));
595 if (!expr
->acc
.access
|| !expr
->acc
.index
)
596 return pet_expr_free(expr
);
601 /* Does "expr" represent an access to a scalar, i.e., zero-dimensional array?
603 int pet_expr_is_scalar_access(struct pet_expr
*expr
)
607 if (expr
->type
!= pet_expr_access
)
610 return isl_map_dim(expr
->acc
.access
, isl_dim_out
) == 0;
613 /* Return 1 if the two pet_exprs are equivalent.
615 int pet_expr_is_equal(struct pet_expr
*expr1
, struct pet_expr
*expr2
)
619 if (!expr1
|| !expr2
)
622 if (expr1
->type
!= expr2
->type
)
624 if (expr1
->n_arg
!= expr2
->n_arg
)
626 for (i
= 0; i
< expr1
->n_arg
; ++i
)
627 if (!pet_expr_is_equal(expr1
->args
[i
], expr2
->args
[i
]))
629 switch (expr1
->type
) {
630 case pet_expr_double
:
631 if (strcmp(expr1
->d
.s
, expr2
->d
.s
))
633 if (expr1
->d
.val
!= expr2
->d
.val
)
636 case pet_expr_access
:
637 if (expr1
->acc
.read
!= expr2
->acc
.read
)
639 if (expr1
->acc
.write
!= expr2
->acc
.write
)
641 if (expr1
->acc
.ref_id
!= expr2
->acc
.ref_id
)
643 if (!expr1
->acc
.access
|| !expr2
->acc
.access
)
645 if (!isl_map_is_equal(expr1
->acc
.access
, expr2
->acc
.access
))
647 if (!expr1
->acc
.index
|| !expr2
->acc
.index
)
649 if (!isl_multi_pw_aff_plain_is_equal(expr1
->acc
.index
,
654 case pet_expr_binary
:
655 case pet_expr_ternary
:
656 if (expr1
->op
!= expr2
->op
)
660 if (strcmp(expr1
->name
, expr2
->name
))
664 if (strcmp(expr1
->type_name
, expr2
->type_name
))
672 /* Add extra conditions on the parameters to all access relations in "expr".
674 * The conditions are not added to the index expression. Instead, they
675 * are used to try and simplify the index expression.
677 struct pet_expr
*pet_expr_restrict(struct pet_expr
*expr
,
678 __isl_take isl_set
*cond
)
685 for (i
= 0; i
< expr
->n_arg
; ++i
) {
686 expr
->args
[i
] = pet_expr_restrict(expr
->args
[i
],
692 if (expr
->type
== pet_expr_access
) {
693 expr
->acc
.access
= isl_map_intersect_params(expr
->acc
.access
,
695 expr
->acc
.index
= isl_multi_pw_aff_gist_params(
696 expr
->acc
.index
, isl_set_copy(cond
));
697 if (!expr
->acc
.access
|| !expr
->acc
.index
)
705 return pet_expr_free(expr
);
708 /* Tag the access relation "access" with "id".
709 * That is, insert the id as the range of a wrapped relation
710 * in the domain of "access".
712 * If "access" is of the form
716 * then the result is of the form
718 * [D[i] -> id[]] -> A[a]
720 static __isl_give isl_map
*tag_access(__isl_take isl_map
*access
,
721 __isl_take isl_id
*id
)
726 space
= isl_space_range(isl_map_get_space(access
));
727 space
= isl_space_from_range(space
);
728 space
= isl_space_set_tuple_id(space
, isl_dim_in
, id
);
729 add_tag
= isl_map_universe(space
);
730 access
= isl_map_domain_product(access
, add_tag
);
735 /* Modify all expressions of type pet_expr_access in "expr"
736 * by calling "fn" on them.
738 struct pet_expr
*pet_expr_map_access(struct pet_expr
*expr
,
739 struct pet_expr
*(*fn
)(struct pet_expr
*expr
, void *user
),
747 for (i
= 0; i
< expr
->n_arg
; ++i
) {
748 expr
->args
[i
] = pet_expr_map_access(expr
->args
[i
], fn
, user
);
750 return pet_expr_free(expr
);
753 if (expr
->type
== pet_expr_access
)
754 expr
= fn(expr
, user
);
759 /* Call "fn" on each of the subexpressions of "expr" of type pet_expr_access.
761 * Return -1 on error (where fn return a negative value is treated as an error).
762 * Otherwise return 0.
764 int pet_expr_foreach_access_expr(struct pet_expr
*expr
,
765 int (*fn
)(struct pet_expr
*expr
, void *user
), void *user
)
772 for (i
= 0; i
< expr
->n_arg
; ++i
)
773 if (pet_expr_foreach_access_expr(expr
->args
[i
], fn
, user
) < 0)
776 if (expr
->type
== pet_expr_access
)
777 return fn(expr
, user
);
782 /* Modify the access relation and index expression
783 * of the given access expression
784 * based on the given iteration space transformation.
785 * In particular, precompose the access relation and index expression
786 * with the update function.
788 * If the access has any arguments then the domain of the access relation
789 * is a wrapped mapping from the iteration space to the space of
790 * argument values. We only need to change the domain of this wrapped
791 * mapping, so we extend the input transformation with an identity mapping
792 * on the space of argument values.
794 static struct pet_expr
*update_domain(struct pet_expr
*expr
, void *user
)
796 isl_multi_pw_aff
*update
= user
;
799 update
= isl_multi_pw_aff_copy(update
);
801 space
= isl_map_get_space(expr
->acc
.access
);
802 space
= isl_space_domain(space
);
803 if (!isl_space_is_wrapping(space
))
804 isl_space_free(space
);
806 isl_multi_pw_aff
*id
;
807 space
= isl_space_unwrap(space
);
808 space
= isl_space_range(space
);
809 space
= isl_space_map_from_set(space
);
810 id
= isl_multi_pw_aff_identity(space
);
811 update
= isl_multi_pw_aff_product(update
, id
);
814 expr
->acc
.access
= isl_map_preimage_domain_multi_pw_aff(
816 isl_multi_pw_aff_copy(update
));
817 expr
->acc
.index
= isl_multi_pw_aff_pullback_multi_pw_aff(
818 expr
->acc
.index
, update
);
819 if (!expr
->acc
.access
|| !expr
->acc
.index
)
820 return pet_expr_free(expr
);
825 /* Modify all access relations in "expr" by precomposing them with
826 * the given iteration space transformation.
828 static struct pet_expr
*expr_update_domain(struct pet_expr
*expr
,
829 __isl_take isl_multi_pw_aff
*update
)
831 expr
= pet_expr_map_access(expr
, &update_domain
, update
);
832 isl_multi_pw_aff_free(update
);
836 /* Construct a pet_stmt with given line number and statement
837 * number from a pet_expr.
838 * The initial iteration domain is the zero-dimensional universe.
839 * The name of the domain is given by "label" if it is non-NULL.
840 * Otherwise, the name is constructed as S_<id>.
841 * The domains of all access relations are modified to refer
842 * to the statement iteration domain.
844 struct pet_stmt
*pet_stmt_from_pet_expr(isl_ctx
*ctx
, int line
,
845 __isl_take isl_id
*label
, int id
, struct pet_expr
*expr
)
847 struct pet_stmt
*stmt
;
851 isl_multi_pw_aff
*add_name
;
857 stmt
= isl_calloc_type(ctx
, struct pet_stmt
);
861 dim
= isl_space_set_alloc(ctx
, 0, 0);
863 dim
= isl_space_set_tuple_id(dim
, isl_dim_set
, label
);
865 snprintf(name
, sizeof(name
), "S_%d", id
);
866 dim
= isl_space_set_tuple_name(dim
, isl_dim_set
, name
);
868 dom
= isl_set_universe(isl_space_copy(dim
));
869 sched
= isl_map_from_domain(isl_set_copy(dom
));
871 dim
= isl_space_from_domain(dim
);
872 add_name
= isl_multi_pw_aff_zero(dim
);
873 expr
= expr_update_domain(expr
, add_name
);
877 stmt
->schedule
= sched
;
880 if (!stmt
->domain
|| !stmt
->schedule
|| !stmt
->body
)
881 return pet_stmt_free(stmt
);
890 void *pet_stmt_free(struct pet_stmt
*stmt
)
897 isl_set_free(stmt
->domain
);
898 isl_map_free(stmt
->schedule
);
899 pet_expr_free(stmt
->body
);
901 for (i
= 0; i
< stmt
->n_arg
; ++i
)
902 pet_expr_free(stmt
->args
[i
]);
909 static void stmt_dump(struct pet_stmt
*stmt
, int indent
)
916 fprintf(stderr
, "%*s%d\n", indent
, "", stmt
->line
);
917 fprintf(stderr
, "%*s", indent
, "");
918 isl_set_dump(stmt
->domain
);
919 fprintf(stderr
, "%*s", indent
, "");
920 isl_map_dump(stmt
->schedule
);
921 expr_dump(stmt
->body
, indent
);
922 for (i
= 0; i
< stmt
->n_arg
; ++i
)
923 expr_dump(stmt
->args
[i
], indent
+ 2);
926 void pet_stmt_dump(struct pet_stmt
*stmt
)
931 /* Allocate a new pet_type with the given "name" and "definition".
933 struct pet_type
*pet_type_alloc(isl_ctx
*ctx
, const char *name
,
934 const char *definition
)
936 struct pet_type
*type
;
938 type
= isl_alloc_type(ctx
, struct pet_type
);
942 type
->name
= strdup(name
);
943 type
->definition
= strdup(definition
);
945 if (!type
->name
|| !type
->definition
)
946 return pet_type_free(type
);
951 /* Free "type" and return NULL.
953 struct pet_type
*pet_type_free(struct pet_type
*type
)
959 free(type
->definition
);
965 struct pet_array
*pet_array_free(struct pet_array
*array
)
970 isl_set_free(array
->context
);
971 isl_set_free(array
->extent
);
972 isl_set_free(array
->value_bounds
);
973 free(array
->element_type
);
979 void pet_array_dump(struct pet_array
*array
)
984 isl_set_dump(array
->context
);
985 isl_set_dump(array
->extent
);
986 isl_set_dump(array
->value_bounds
);
987 fprintf(stderr
, "%s%s%s\n", array
->element_type
,
988 array
->element_is_record
? " element-is-record" : "",
989 array
->live_out
? " live-out" : "");
992 /* Alloc a pet_scop structure, with extra room for information that
993 * is only used during parsing.
995 struct pet_scop
*pet_scop_alloc(isl_ctx
*ctx
)
997 return &isl_calloc_type(ctx
, struct pet_scop_ext
)->scop
;
1000 /* Construct a pet_scop with room for n statements.
1002 static struct pet_scop
*scop_alloc(isl_ctx
*ctx
, int n
)
1005 struct pet_scop
*scop
;
1007 scop
= pet_scop_alloc(ctx
);
1011 space
= isl_space_params_alloc(ctx
, 0);
1012 scop
->context
= isl_set_universe(isl_space_copy(space
));
1013 scop
->context_value
= isl_set_universe(space
);
1014 scop
->stmts
= isl_calloc_array(ctx
, struct pet_stmt
*, n
);
1015 if (!scop
->context
|| !scop
->stmts
)
1016 return pet_scop_free(scop
);
1023 struct pet_scop
*pet_scop_empty(isl_ctx
*ctx
)
1025 return scop_alloc(ctx
, 0);
1028 /* Update "context" with respect to the valid parameter values for "access".
1030 static __isl_give isl_set
*access_extract_context(__isl_keep isl_map
*access
,
1031 __isl_take isl_set
*context
)
1033 context
= isl_set_intersect(context
,
1034 isl_map_params(isl_map_copy(access
)));
1038 /* Update "context" with respect to the valid parameter values for "expr".
1040 * If "expr" represents a ternary operator, then a parameter value
1041 * needs to be valid for the condition and for at least one of the
1042 * remaining two arguments.
1043 * If the condition is an affine expression, then we can be a bit more specific.
1044 * The parameter then has to be valid for the second argument for
1045 * non-zero accesses and valid for the third argument for zero accesses.
1047 static __isl_give isl_set
*expr_extract_context(struct pet_expr
*expr
,
1048 __isl_take isl_set
*context
)
1052 if (expr
->type
== pet_expr_ternary
) {
1054 isl_set
*context1
, *context2
;
1056 is_aff
= pet_expr_is_affine(expr
->args
[0]);
1060 context
= expr_extract_context(expr
->args
[0], context
);
1061 context1
= expr_extract_context(expr
->args
[1],
1062 isl_set_copy(context
));
1063 context2
= expr_extract_context(expr
->args
[2], context
);
1069 access
= isl_map_copy(expr
->args
[0]->acc
.access
);
1070 access
= isl_map_fix_si(access
, isl_dim_out
, 0, 0);
1071 zero_set
= isl_map_params(access
);
1072 context1
= isl_set_subtract(context1
,
1073 isl_set_copy(zero_set
));
1074 context2
= isl_set_intersect(context2
, zero_set
);
1077 context
= isl_set_union(context1
, context2
);
1078 context
= isl_set_coalesce(context
);
1083 for (i
= 0; i
< expr
->n_arg
; ++i
)
1084 context
= expr_extract_context(expr
->args
[i
], context
);
1086 if (expr
->type
== pet_expr_access
)
1087 context
= access_extract_context(expr
->acc
.access
, context
);
1091 isl_set_free(context
);
1095 /* Update "context" with respect to the valid parameter values for "stmt".
1097 * If the statement is an assume statement with an affine expression,
1098 * then intersect "context" with that expression.
1099 * Otherwise, intersect "context" with the contexts of the expressions
1102 static __isl_give isl_set
*stmt_extract_context(struct pet_stmt
*stmt
,
1103 __isl_take isl_set
*context
)
1107 if (pet_stmt_is_assume(stmt
) &&
1108 pet_expr_is_affine(stmt
->body
->args
[0])) {
1109 isl_multi_pw_aff
*index
;
1113 index
= stmt
->body
->args
[0]->acc
.index
;
1114 pa
= isl_multi_pw_aff_get_pw_aff(index
, 0);
1115 cond
= isl_set_params(isl_pw_aff_non_zero_set(pa
));
1116 return isl_set_intersect(context
, cond
);
1119 for (i
= 0; i
< stmt
->n_arg
; ++i
)
1120 context
= expr_extract_context(stmt
->args
[i
], context
);
1122 context
= expr_extract_context(stmt
->body
, context
);
1127 /* Construct a pet_scop that contains the given pet_stmt.
1129 struct pet_scop
*pet_scop_from_pet_stmt(isl_ctx
*ctx
, struct pet_stmt
*stmt
)
1131 struct pet_scop
*scop
;
1136 scop
= scop_alloc(ctx
, 1);
1140 scop
->context
= stmt_extract_context(stmt
, scop
->context
);
1144 scop
->stmts
[0] = stmt
;
1148 pet_stmt_free(stmt
);
1149 pet_scop_free(scop
);
1153 /* Does "mpa" represent an access to an element of an unnamed space, i.e.,
1154 * does it represent an affine expression?
1156 static int multi_pw_aff_is_affine(__isl_keep isl_multi_pw_aff
*mpa
)
1160 has_id
= isl_multi_pw_aff_has_tuple_id(mpa
, isl_dim_out
);
1167 /* Return the piecewise affine expression "set ? 1 : 0" defined on "dom".
1169 static __isl_give isl_pw_aff
*indicator_function(__isl_take isl_set
*set
,
1170 __isl_take isl_set
*dom
)
1173 pa
= isl_set_indicator_function(set
);
1174 pa
= isl_pw_aff_intersect_domain(pa
, dom
);
1178 /* Return "lhs || rhs", defined on the shared definition domain.
1180 static __isl_give isl_pw_aff
*pw_aff_or(__isl_take isl_pw_aff
*lhs
,
1181 __isl_take isl_pw_aff
*rhs
)
1186 dom
= isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(lhs
)),
1187 isl_pw_aff_domain(isl_pw_aff_copy(rhs
)));
1188 cond
= isl_set_union(isl_pw_aff_non_zero_set(lhs
),
1189 isl_pw_aff_non_zero_set(rhs
));
1190 cond
= isl_set_coalesce(cond
);
1191 return indicator_function(cond
, dom
);
1194 /* Combine ext1->skip[type] and ext2->skip[type] into ext->skip[type].
1195 * ext may be equal to either ext1 or ext2.
1197 * The two skips that need to be combined are assumed to be affine expressions.
1199 * We need to skip in ext if we need to skip in either ext1 or ext2.
1200 * We don't need to skip in ext if we don't need to skip in both ext1 and ext2.
1202 static struct pet_scop_ext
*combine_skips(struct pet_scop_ext
*ext
,
1203 struct pet_scop_ext
*ext1
, struct pet_scop_ext
*ext2
,
1206 isl_pw_aff
*skip
, *skip1
, *skip2
;
1210 if (!ext1
->skip
[type
] && !ext2
->skip
[type
])
1212 if (!ext1
->skip
[type
]) {
1215 ext
->skip
[type
] = ext2
->skip
[type
];
1216 ext2
->skip
[type
] = NULL
;
1219 if (!ext2
->skip
[type
]) {
1222 ext
->skip
[type
] = ext1
->skip
[type
];
1223 ext1
->skip
[type
] = NULL
;
1227 if (!multi_pw_aff_is_affine(ext1
->skip
[type
]) ||
1228 !multi_pw_aff_is_affine(ext2
->skip
[type
]))
1229 isl_die(isl_multi_pw_aff_get_ctx(ext1
->skip
[type
]),
1230 isl_error_internal
, "can only combine affine skips",
1233 skip1
= isl_multi_pw_aff_get_pw_aff(ext1
->skip
[type
], 0);
1234 skip2
= isl_multi_pw_aff_get_pw_aff(ext2
->skip
[type
], 0);
1235 skip
= pw_aff_or(skip1
, skip2
);
1236 isl_multi_pw_aff_free(ext1
->skip
[type
]);
1237 ext1
->skip
[type
] = NULL
;
1238 isl_multi_pw_aff_free(ext2
->skip
[type
]);
1239 ext2
->skip
[type
] = NULL
;
1240 ext
->skip
[type
] = isl_multi_pw_aff_from_pw_aff(skip
);
1241 if (!ext
->skip
[type
])
1246 pet_scop_free(&ext
->scop
);
1250 /* Combine scop1->skip[type] and scop2->skip[type] into scop->skip[type],
1251 * where type takes on the values pet_skip_now and pet_skip_later.
1252 * scop may be equal to either scop1 or scop2.
1254 static struct pet_scop
*scop_combine_skips(struct pet_scop
*scop
,
1255 struct pet_scop
*scop1
, struct pet_scop
*scop2
)
1257 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
1258 struct pet_scop_ext
*ext1
= (struct pet_scop_ext
*) scop1
;
1259 struct pet_scop_ext
*ext2
= (struct pet_scop_ext
*) scop2
;
1261 ext
= combine_skips(ext
, ext1
, ext2
, pet_skip_now
);
1262 ext
= combine_skips(ext
, ext1
, ext2
, pet_skip_later
);
1266 /* Update scop->start and scop->end to include the region from "start"
1267 * to "end". In particular, if scop->end == 0, then "scop" does not
1268 * have any offset information yet and we simply take the information
1269 * from "start" and "end". Otherwise, we update the fields if the
1270 * region from "start" to "end" is not already included.
1272 struct pet_scop
*pet_scop_update_start_end(struct pet_scop
*scop
,
1273 unsigned start
, unsigned end
)
1277 if (scop
->end
== 0) {
1278 scop
->start
= start
;
1281 if (start
< scop
->start
)
1282 scop
->start
= start
;
1283 if (end
> scop
->end
)
1290 /* Does "implication" appear in the list of implications of "scop"?
1292 static int is_known_implication(struct pet_scop
*scop
,
1293 struct pet_implication
*implication
)
1297 for (i
= 0; i
< scop
->n_implication
; ++i
) {
1298 struct pet_implication
*pi
= scop
->implications
[i
];
1301 if (pi
->satisfied
!= implication
->satisfied
)
1303 equal
= isl_map_is_equal(pi
->extension
, implication
->extension
);
1313 /* Store the concatenation of the implications of "scop1" and "scop2"
1314 * in "scop", removing duplicates (i.e., implications in "scop2" that
1315 * already appear in "scop1").
1317 static struct pet_scop
*scop_collect_implications(isl_ctx
*ctx
,
1318 struct pet_scop
*scop
, struct pet_scop
*scop1
, struct pet_scop
*scop2
)
1325 if (scop2
->n_implication
== 0) {
1326 scop
->n_implication
= scop1
->n_implication
;
1327 scop
->implications
= scop1
->implications
;
1328 scop1
->n_implication
= 0;
1329 scop1
->implications
= NULL
;
1333 if (scop1
->n_implication
== 0) {
1334 scop
->n_implication
= scop2
->n_implication
;
1335 scop
->implications
= scop2
->implications
;
1336 scop2
->n_implication
= 0;
1337 scop2
->implications
= NULL
;
1341 scop
->implications
= isl_calloc_array(ctx
, struct pet_implication
*,
1342 scop1
->n_implication
+ scop2
->n_implication
);
1343 if (!scop
->implications
)
1344 return pet_scop_free(scop
);
1346 for (i
= 0; i
< scop1
->n_implication
; ++i
) {
1347 scop
->implications
[i
] = scop1
->implications
[i
];
1348 scop1
->implications
[i
] = NULL
;
1351 scop
->n_implication
= scop1
->n_implication
;
1352 j
= scop1
->n_implication
;
1353 for (i
= 0; i
< scop2
->n_implication
; ++i
) {
1356 known
= is_known_implication(scop
, scop2
->implications
[i
]);
1358 return pet_scop_free(scop
);
1361 scop
->implications
[j
++] = scop2
->implications
[i
];
1362 scop2
->implications
[i
] = NULL
;
1364 scop
->n_implication
= j
;
1369 /* Combine the offset information of "scop1" and "scop2" into "scop".
1371 static struct pet_scop
*scop_combine_start_end(struct pet_scop
*scop
,
1372 struct pet_scop
*scop1
, struct pet_scop
*scop2
)
1375 scop
= pet_scop_update_start_end(scop
,
1376 scop1
->start
, scop1
->end
);
1378 scop
= pet_scop_update_start_end(scop
,
1379 scop2
->start
, scop2
->end
);
1383 /* Construct a pet_scop that contains the offset information,
1384 * arrays, statements and skip information in "scop1" and "scop2".
1386 static struct pet_scop
*pet_scop_add(isl_ctx
*ctx
, struct pet_scop
*scop1
,
1387 struct pet_scop
*scop2
)
1390 struct pet_scop
*scop
= NULL
;
1392 if (!scop1
|| !scop2
)
1395 if (scop1
->n_stmt
== 0) {
1396 scop2
= scop_combine_skips(scop2
, scop1
, scop2
);
1397 pet_scop_free(scop1
);
1401 if (scop2
->n_stmt
== 0) {
1402 scop1
= scop_combine_skips(scop1
, scop1
, scop2
);
1403 pet_scop_free(scop2
);
1407 scop
= scop_alloc(ctx
, scop1
->n_stmt
+ scop2
->n_stmt
);
1411 scop
->arrays
= isl_calloc_array(ctx
, struct pet_array
*,
1412 scop1
->n_array
+ scop2
->n_array
);
1415 scop
->n_array
= scop1
->n_array
+ scop2
->n_array
;
1417 for (i
= 0; i
< scop1
->n_stmt
; ++i
) {
1418 scop
->stmts
[i
] = scop1
->stmts
[i
];
1419 scop1
->stmts
[i
] = NULL
;
1422 for (i
= 0; i
< scop2
->n_stmt
; ++i
) {
1423 scop
->stmts
[scop1
->n_stmt
+ i
] = scop2
->stmts
[i
];
1424 scop2
->stmts
[i
] = NULL
;
1427 for (i
= 0; i
< scop1
->n_array
; ++i
) {
1428 scop
->arrays
[i
] = scop1
->arrays
[i
];
1429 scop1
->arrays
[i
] = NULL
;
1432 for (i
= 0; i
< scop2
->n_array
; ++i
) {
1433 scop
->arrays
[scop1
->n_array
+ i
] = scop2
->arrays
[i
];
1434 scop2
->arrays
[i
] = NULL
;
1437 scop
= scop_collect_implications(ctx
, scop
, scop1
, scop2
);
1438 scop
= pet_scop_restrict_context(scop
, isl_set_copy(scop1
->context
));
1439 scop
= pet_scop_restrict_context(scop
, isl_set_copy(scop2
->context
));
1440 scop
= scop_combine_skips(scop
, scop1
, scop2
);
1441 scop
= scop_combine_start_end(scop
, scop1
, scop2
);
1443 pet_scop_free(scop1
);
1444 pet_scop_free(scop2
);
1447 pet_scop_free(scop1
);
1448 pet_scop_free(scop2
);
1449 pet_scop_free(scop
);
1453 /* Apply the skip condition "skip" to "scop".
1454 * That is, make sure "scop" is not executed when the condition holds.
1456 * If "skip" is an affine expression, we add the conditions under
1457 * which the expression is zero to the iteration domains.
1458 * Otherwise, we add a filter on the variable attaining the value zero.
1460 static struct pet_scop
*restrict_skip(struct pet_scop
*scop
,
1461 __isl_take isl_multi_pw_aff
*skip
)
1470 is_aff
= multi_pw_aff_is_affine(skip
);
1475 return pet_scop_filter(scop
, skip
, 0);
1477 pa
= isl_multi_pw_aff_get_pw_aff(skip
, 0);
1478 isl_multi_pw_aff_free(skip
);
1479 zero
= isl_set_params(isl_pw_aff_zero_set(pa
));
1480 scop
= pet_scop_restrict(scop
, zero
);
1484 isl_multi_pw_aff_free(skip
);
1485 return pet_scop_free(scop
);
1488 /* Construct a pet_scop that contains the arrays, statements and
1489 * skip information in "scop1" and "scop2", where the two scops
1490 * are executed "in sequence". That is, breaks and continues
1491 * in scop1 have an effect on scop2.
1493 struct pet_scop
*pet_scop_add_seq(isl_ctx
*ctx
, struct pet_scop
*scop1
,
1494 struct pet_scop
*scop2
)
1496 if (scop1
&& pet_scop_has_skip(scop1
, pet_skip_now
))
1497 scop2
= restrict_skip(scop2
,
1498 pet_scop_get_skip(scop1
, pet_skip_now
));
1499 return pet_scop_add(ctx
, scop1
, scop2
);
1502 /* Construct a pet_scop that contains the arrays, statements and
1503 * skip information in "scop1" and "scop2", where the two scops
1504 * are executed "in parallel". That is, any break or continue
1505 * in scop1 has no effect on scop2.
1507 struct pet_scop
*pet_scop_add_par(isl_ctx
*ctx
, struct pet_scop
*scop1
,
1508 struct pet_scop
*scop2
)
1510 return pet_scop_add(ctx
, scop1
, scop2
);
1513 void *pet_implication_free(struct pet_implication
*implication
)
1520 isl_map_free(implication
->extension
);
1526 struct pet_scop
*pet_scop_free(struct pet_scop
*scop
)
1529 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
1533 isl_set_free(scop
->context
);
1534 isl_set_free(scop
->context_value
);
1536 for (i
= 0; i
< scop
->n_type
; ++i
)
1537 pet_type_free(scop
->types
[i
]);
1540 for (i
= 0; i
< scop
->n_array
; ++i
)
1541 pet_array_free(scop
->arrays
[i
]);
1544 for (i
= 0; i
< scop
->n_stmt
; ++i
)
1545 pet_stmt_free(scop
->stmts
[i
]);
1547 if (scop
->implications
)
1548 for (i
= 0; i
< scop
->n_implication
; ++i
)
1549 pet_implication_free(scop
->implications
[i
]);
1550 free(scop
->implications
);
1551 isl_multi_pw_aff_free(ext
->skip
[pet_skip_now
]);
1552 isl_multi_pw_aff_free(ext
->skip
[pet_skip_later
]);
1557 void pet_type_dump(struct pet_type
*type
)
1562 fprintf(stderr
, "%s -> %s\n", type
->name
, type
->definition
);
1565 void pet_implication_dump(struct pet_implication
*implication
)
1570 fprintf(stderr
, "%d\n", implication
->satisfied
);
1571 isl_map_dump(implication
->extension
);
1574 void pet_scop_dump(struct pet_scop
*scop
)
1577 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
1582 isl_set_dump(scop
->context
);
1583 isl_set_dump(scop
->context_value
);
1584 for (i
= 0; i
< scop
->n_type
; ++i
)
1585 pet_type_dump(scop
->types
[i
]);
1586 for (i
= 0; i
< scop
->n_array
; ++i
)
1587 pet_array_dump(scop
->arrays
[i
]);
1588 for (i
= 0; i
< scop
->n_stmt
; ++i
)
1589 pet_stmt_dump(scop
->stmts
[i
]);
1590 for (i
= 0; i
< scop
->n_implication
; ++i
)
1591 pet_implication_dump(scop
->implications
[i
]);
1594 fprintf(stderr
, "skip\n");
1595 isl_multi_pw_aff_dump(ext
->skip
[0]);
1596 isl_multi_pw_aff_dump(ext
->skip
[1]);
1600 /* Return 1 if the two pet_arrays are equivalent.
1602 * We don't compare element_size as this may be target dependent.
1604 int pet_array_is_equal(struct pet_array
*array1
, struct pet_array
*array2
)
1606 if (!array1
|| !array2
)
1609 if (!isl_set_is_equal(array1
->context
, array2
->context
))
1611 if (!isl_set_is_equal(array1
->extent
, array2
->extent
))
1613 if (!!array1
->value_bounds
!= !!array2
->value_bounds
)
1615 if (array1
->value_bounds
&&
1616 !isl_set_is_equal(array1
->value_bounds
, array2
->value_bounds
))
1618 if (strcmp(array1
->element_type
, array2
->element_type
))
1620 if (array1
->element_is_record
!= array2
->element_is_record
)
1622 if (array1
->live_out
!= array2
->live_out
)
1624 if (array1
->uniquely_defined
!= array2
->uniquely_defined
)
1626 if (array1
->declared
!= array2
->declared
)
1628 if (array1
->exposed
!= array2
->exposed
)
1634 /* Return 1 if the two pet_stmts are equivalent.
1636 int pet_stmt_is_equal(struct pet_stmt
*stmt1
, struct pet_stmt
*stmt2
)
1640 if (!stmt1
|| !stmt2
)
1643 if (stmt1
->line
!= stmt2
->line
)
1645 if (!isl_set_is_equal(stmt1
->domain
, stmt2
->domain
))
1647 if (!isl_map_is_equal(stmt1
->schedule
, stmt2
->schedule
))
1649 if (!pet_expr_is_equal(stmt1
->body
, stmt2
->body
))
1651 if (stmt1
->n_arg
!= stmt2
->n_arg
)
1653 for (i
= 0; i
< stmt1
->n_arg
; ++i
) {
1654 if (!pet_expr_is_equal(stmt1
->args
[i
], stmt2
->args
[i
]))
1661 /* Return 1 if the two pet_types are equivalent.
1663 * We only compare the names of the types since the exact representation
1664 * of the definition may depend on the version of clang being used.
1666 int pet_type_is_equal(struct pet_type
*type1
, struct pet_type
*type2
)
1668 if (!type1
|| !type2
)
1671 if (strcmp(type1
->name
, type2
->name
))
1677 /* Return 1 if the two pet_implications are equivalent.
1679 int pet_implication_is_equal(struct pet_implication
*implication1
,
1680 struct pet_implication
*implication2
)
1682 if (!implication1
|| !implication2
)
1685 if (implication1
->satisfied
!= implication2
->satisfied
)
1687 if (!isl_map_is_equal(implication1
->extension
, implication2
->extension
))
1693 /* Return 1 if the two pet_scops are equivalent.
1695 int pet_scop_is_equal(struct pet_scop
*scop1
, struct pet_scop
*scop2
)
1699 if (!scop1
|| !scop2
)
1702 if (!isl_set_is_equal(scop1
->context
, scop2
->context
))
1704 if (!isl_set_is_equal(scop1
->context_value
, scop2
->context_value
))
1707 if (scop1
->n_type
!= scop2
->n_type
)
1709 for (i
= 0; i
< scop1
->n_type
; ++i
)
1710 if (!pet_type_is_equal(scop1
->types
[i
], scop2
->types
[i
]))
1713 if (scop1
->n_array
!= scop2
->n_array
)
1715 for (i
= 0; i
< scop1
->n_array
; ++i
)
1716 if (!pet_array_is_equal(scop1
->arrays
[i
], scop2
->arrays
[i
]))
1719 if (scop1
->n_stmt
!= scop2
->n_stmt
)
1721 for (i
= 0; i
< scop1
->n_stmt
; ++i
)
1722 if (!pet_stmt_is_equal(scop1
->stmts
[i
], scop2
->stmts
[i
]))
1725 if (scop1
->n_implication
!= scop2
->n_implication
)
1727 for (i
= 0; i
< scop1
->n_implication
; ++i
)
1728 if (!pet_implication_is_equal(scop1
->implications
[i
],
1729 scop2
->implications
[i
]))
1735 /* Prefix the schedule of "stmt" with an extra dimension with constant
1738 struct pet_stmt
*pet_stmt_prefix(struct pet_stmt
*stmt
, int pos
)
1743 stmt
->schedule
= isl_map_insert_dims(stmt
->schedule
, isl_dim_out
, 0, 1);
1744 stmt
->schedule
= isl_map_fix_si(stmt
->schedule
, isl_dim_out
, 0, pos
);
1745 if (!stmt
->schedule
)
1746 return pet_stmt_free(stmt
);
1751 /* Prefix the schedules of all statements in "scop" with an extra
1752 * dimension with constant value "pos".
1754 struct pet_scop
*pet_scop_prefix(struct pet_scop
*scop
, int pos
)
1761 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
1762 scop
->stmts
[i
] = pet_stmt_prefix(scop
->stmts
[i
], pos
);
1763 if (!scop
->stmts
[i
])
1764 return pet_scop_free(scop
);
1770 /* Given a set with a parameter at "param_pos" that refers to the
1771 * iterator, "move" the iterator to the first set dimension.
1772 * That is, essentially equate the parameter to the first set dimension
1773 * and then project it out.
1775 * The first set dimension may however refer to a virtual iterator,
1776 * while the parameter refers to the "real" iterator.
1777 * We therefore need to take into account the affine expression "iv_map", which
1778 * expresses the real iterator in terms of the virtual iterator.
1779 * In particular, we equate the set dimension to the input of the map
1780 * and the parameter to the output of the map and then project out
1781 * everything we don't need anymore.
1783 static __isl_give isl_set
*internalize_iv(__isl_take isl_set
*set
,
1784 int param_pos
, __isl_take isl_aff
*iv_map
)
1786 isl_map
*map
, *map2
;
1787 map
= isl_map_from_domain(set
);
1788 map
= isl_map_add_dims(map
, isl_dim_out
, 1);
1789 map
= isl_map_equate(map
, isl_dim_in
, 0, isl_dim_out
, 0);
1790 map2
= isl_map_from_aff(iv_map
);
1791 map2
= isl_map_align_params(map2
, isl_map_get_space(map
));
1792 map
= isl_map_apply_range(map
, map2
);
1793 map
= isl_map_equate(map
, isl_dim_param
, param_pos
, isl_dim_out
, 0);
1794 map
= isl_map_project_out(map
, isl_dim_param
, param_pos
, 1);
1795 return isl_map_domain(map
);
1798 /* Data used in embed_access.
1799 * extend adds an iterator to the iteration domain (through precomposition).
1800 * iv_map expresses the real iterator in terms of the virtual iterator
1801 * var_id represents the induction variable of the corresponding loop
1803 struct pet_embed_access
{
1804 isl_multi_pw_aff
*extend
;
1809 /* Given an index expression, return an expression for the outer iterator.
1811 static __isl_give isl_aff
*index_outer_iterator(
1812 __isl_take isl_multi_pw_aff
*index
)
1815 isl_local_space
*ls
;
1817 space
= isl_multi_pw_aff_get_domain_space(index
);
1818 isl_multi_pw_aff_free(index
);
1820 ls
= isl_local_space_from_space(space
);
1821 return isl_aff_var_on_domain(ls
, isl_dim_set
, 0);
1824 /* Replace an index expression that references the new (outer) iterator variable
1825 * by one that references the corresponding (real) iterator.
1827 * The input index expression is of the form
1829 * { S[i',...] -> i[] }
1831 * where i' refers to the virtual iterator.
1833 * iv_map is of the form
1837 * Return the index expression
1839 * { S[i',...] -> [i] }
1841 static __isl_give isl_multi_pw_aff
*replace_by_iterator(
1842 __isl_take isl_multi_pw_aff
*index
, __isl_take isl_aff
*iv_map
)
1847 aff
= index_outer_iterator(index
);
1848 space
= isl_aff_get_space(aff
);
1849 iv_map
= isl_aff_align_params(iv_map
, space
);
1850 aff
= isl_aff_pullback_aff(iv_map
, aff
);
1852 return isl_multi_pw_aff_from_pw_aff(isl_pw_aff_from_aff(aff
));
1855 /* Given an index expression "index" that refers to the (real) iterator
1856 * through the parameter at position "pos", plug in "iv_map", expressing
1857 * the real iterator in terms of the virtual (outer) iterator.
1859 * In particular, the index expression is of the form
1861 * [..., i, ...] -> { S[i',...] -> ... i ... }
1863 * where i refers to the real iterator and i' refers to the virtual iterator.
1865 * iv_map is of the form
1869 * Return the index expression
1871 * [..., ...] -> { S[i',...] -> ... iv_map(i') ... }
1874 * We first move the parameter to the input
1876 * [..., ...] -> { [i, i',...] -> ... i ... }
1880 * { S[i',...] -> [i=iv_map(i'), i', ...] }
1882 * and then combine the two to obtain the desired result.
1884 static __isl_give isl_multi_pw_aff
*index_internalize_iv(
1885 __isl_take isl_multi_pw_aff
*index
, int pos
, __isl_take isl_aff
*iv_map
)
1887 isl_space
*space
= isl_multi_pw_aff_get_domain_space(index
);
1890 space
= isl_space_drop_dims(space
, isl_dim_param
, pos
, 1);
1891 index
= isl_multi_pw_aff_move_dims(index
, isl_dim_in
, 0,
1892 isl_dim_param
, pos
, 1);
1894 space
= isl_space_map_from_set(space
);
1895 ma
= isl_multi_aff_identity(isl_space_copy(space
));
1896 iv_map
= isl_aff_align_params(iv_map
, space
);
1897 iv_map
= isl_aff_pullback_aff(iv_map
, isl_multi_aff_get_aff(ma
, 0));
1898 ma
= isl_multi_aff_flat_range_product(
1899 isl_multi_aff_from_aff(iv_map
), ma
);
1900 index
= isl_multi_pw_aff_pullback_multi_aff(index
, ma
);
1905 /* Does the index expression "index" reference a virtual array, i.e.,
1906 * one with user pointer equal to NULL?
1907 * A virtual array does not have any members.
1909 static int index_is_virtual_array(__isl_keep isl_multi_pw_aff
*index
)
1914 if (!isl_multi_pw_aff_has_tuple_id(index
, isl_dim_out
))
1916 if (isl_multi_pw_aff_range_is_wrapping(index
))
1918 id
= isl_multi_pw_aff_get_tuple_id(index
, isl_dim_out
);
1919 is_virtual
= !isl_id_get_user(id
);
1925 /* Does the access relation "access" reference a virtual array, i.e.,
1926 * one with user pointer equal to NULL?
1927 * A virtual array does not have any members.
1929 static int access_is_virtual_array(__isl_keep isl_map
*access
)
1934 if (!isl_map_has_tuple_id(access
, isl_dim_out
))
1936 if (isl_map_range_is_wrapping(access
))
1938 id
= isl_map_get_tuple_id(access
, isl_dim_out
);
1939 is_virtual
= !isl_id_get_user(id
);
1945 /* Embed the given index expression in an extra outer loop.
1946 * The domain of the index expression has already been updated.
1948 * If the access refers to the induction variable, then it is
1949 * turned into an access to the set of integers with index (and value)
1950 * equal to the induction variable.
1952 * If the accessed array is a virtual array (with user
1953 * pointer equal to NULL), as created by create_test_index,
1954 * then it is extended along with the domain of the index expression.
1956 static __isl_give isl_multi_pw_aff
*embed_index_expression(
1957 __isl_take isl_multi_pw_aff
*index
, struct pet_embed_access
*data
)
1959 isl_id
*array_id
= NULL
;
1962 if (isl_multi_pw_aff_has_tuple_id(index
, isl_dim_out
))
1963 array_id
= isl_multi_pw_aff_get_tuple_id(index
, isl_dim_out
);
1964 if (array_id
== data
->var_id
) {
1965 index
= replace_by_iterator(index
, isl_aff_copy(data
->iv_map
));
1966 } else if (index_is_virtual_array(index
)) {
1968 isl_multi_pw_aff
*mpa
;
1970 aff
= index_outer_iterator(isl_multi_pw_aff_copy(index
));
1971 mpa
= isl_multi_pw_aff_from_pw_aff(isl_pw_aff_from_aff(aff
));
1972 index
= isl_multi_pw_aff_flat_range_product(mpa
, index
);
1973 index
= isl_multi_pw_aff_set_tuple_id(index
, isl_dim_out
,
1974 isl_id_copy(array_id
));
1976 isl_id_free(array_id
);
1978 pos
= isl_multi_pw_aff_find_dim_by_id(index
,
1979 isl_dim_param
, data
->var_id
);
1981 index
= index_internalize_iv(index
, pos
,
1982 isl_aff_copy(data
->iv_map
));
1983 index
= isl_multi_pw_aff_set_dim_id(index
, isl_dim_in
, 0,
1984 isl_id_copy(data
->var_id
));
1989 /* Embed the given access relation in an extra outer loop.
1990 * The domain of the access relation has already been updated.
1992 * If the access refers to the induction variable, then it is
1993 * turned into an access to the set of integers with index (and value)
1994 * equal to the induction variable.
1996 * If the induction variable appears in the constraints (as a parameter),
1997 * then the parameter is equated to the newly introduced iteration
1998 * domain dimension and subsequently projected out.
2000 * Similarly, if the accessed array is a virtual array (with user
2001 * pointer equal to NULL), as created by create_test_index,
2002 * then it is extended along with the domain of the access.
2004 static __isl_give isl_map
*embed_access_relation(__isl_take isl_map
*access
,
2005 struct pet_embed_access
*data
)
2007 isl_id
*array_id
= NULL
;
2010 if (isl_map_has_tuple_id(access
, isl_dim_out
))
2011 array_id
= isl_map_get_tuple_id(access
, isl_dim_out
);
2012 if (array_id
== data
->var_id
|| access_is_virtual_array(access
)) {
2013 access
= isl_map_insert_dims(access
, isl_dim_out
, 0, 1);
2014 access
= isl_map_equate(access
,
2015 isl_dim_in
, 0, isl_dim_out
, 0);
2016 if (array_id
== data
->var_id
)
2017 access
= isl_map_apply_range(access
,
2018 isl_map_from_aff(isl_aff_copy(data
->iv_map
)));
2020 access
= isl_map_set_tuple_id(access
, isl_dim_out
,
2021 isl_id_copy(array_id
));
2023 isl_id_free(array_id
);
2025 pos
= isl_map_find_dim_by_id(access
, isl_dim_param
, data
->var_id
);
2027 isl_set
*set
= isl_map_wrap(access
);
2028 set
= internalize_iv(set
, pos
, isl_aff_copy(data
->iv_map
));
2029 access
= isl_set_unwrap(set
);
2031 access
= isl_map_set_dim_id(access
, isl_dim_in
, 0,
2032 isl_id_copy(data
->var_id
));
2037 /* Given an access expression, embed the associated access relation and
2038 * index expression in an extra outer loop.
2040 * We first update the domains to insert the extra dimension and
2041 * then update the access relation and index expression to take
2042 * into account the mapping "iv_map" from virtual iterator
2045 static struct pet_expr
*embed_access(struct pet_expr
*expr
, void *user
)
2047 struct pet_embed_access
*data
= user
;
2049 expr
= update_domain(expr
, data
->extend
);
2053 expr
->acc
.access
= embed_access_relation(expr
->acc
.access
, data
);
2054 expr
->acc
.index
= embed_index_expression(expr
->acc
.index
, data
);
2055 if (!expr
->acc
.access
|| !expr
->acc
.index
)
2056 return pet_expr_free(expr
);
2061 /* Embed all access subexpressions of "expr" in an extra loop.
2062 * "extend" inserts an outer loop iterator in the iteration domains
2063 * (through precomposition).
2064 * "iv_map" expresses the real iterator in terms of the virtual iterator
2065 * "var_id" represents the induction variable.
2067 static struct pet_expr
*expr_embed(struct pet_expr
*expr
,
2068 __isl_take isl_multi_pw_aff
*extend
, __isl_take isl_aff
*iv_map
,
2069 __isl_keep isl_id
*var_id
)
2071 struct pet_embed_access data
=
2072 { .extend
= extend
, .iv_map
= iv_map
, .var_id
= var_id
};
2074 expr
= pet_expr_map_access(expr
, &embed_access
, &data
);
2075 isl_aff_free(iv_map
);
2076 isl_multi_pw_aff_free(extend
);
2080 /* Embed the given pet_stmt in an extra outer loop with iteration domain
2081 * "dom" and schedule "sched". "var_id" represents the induction variable
2082 * of the loop. "iv_map" maps a possibly virtual iterator to the real iterator.
2083 * That is, it expresses the iterator that some of the parameters in "stmt"
2084 * may refer to in terms of the iterator used in "dom" and
2085 * the domain of "sched".
2087 * The iteration domain and schedule of the statement are updated
2088 * according to the iteration domain and schedule of the new loop.
2089 * If stmt->domain is a wrapped map, then the iteration domain
2090 * is the domain of this map, so we need to be careful to adjust
2093 * If the induction variable appears in the constraints (as a parameter)
2094 * of the current iteration domain or the schedule of the statement,
2095 * then the parameter is equated to the newly introduced iteration
2096 * domain dimension and subsequently projected out.
2098 * Finally, all access relations are updated based on the extra loop.
2100 static struct pet_stmt
*pet_stmt_embed(struct pet_stmt
*stmt
,
2101 __isl_take isl_set
*dom
, __isl_take isl_map
*sched
,
2102 __isl_take isl_aff
*iv_map
, __isl_take isl_id
*var_id
)
2108 isl_multi_pw_aff
*extend
;
2113 if (isl_set_is_wrapping(stmt
->domain
)) {
2118 map
= isl_set_unwrap(stmt
->domain
);
2119 stmt_id
= isl_map_get_tuple_id(map
, isl_dim_in
);
2120 ran_dim
= isl_space_range(isl_map_get_space(map
));
2121 ext
= isl_map_from_domain_and_range(isl_set_copy(dom
),
2122 isl_set_universe(ran_dim
));
2123 map
= isl_map_flat_domain_product(ext
, map
);
2124 map
= isl_map_set_tuple_id(map
, isl_dim_in
,
2125 isl_id_copy(stmt_id
));
2126 dim
= isl_space_domain(isl_map_get_space(map
));
2127 stmt
->domain
= isl_map_wrap(map
);
2129 stmt_id
= isl_set_get_tuple_id(stmt
->domain
);
2130 stmt
->domain
= isl_set_flat_product(isl_set_copy(dom
),
2132 stmt
->domain
= isl_set_set_tuple_id(stmt
->domain
,
2133 isl_id_copy(stmt_id
));
2134 dim
= isl_set_get_space(stmt
->domain
);
2137 pos
= isl_set_find_dim_by_id(stmt
->domain
, isl_dim_param
, var_id
);
2139 stmt
->domain
= internalize_iv(stmt
->domain
, pos
,
2140 isl_aff_copy(iv_map
));
2142 stmt
->schedule
= isl_map_flat_product(sched
, stmt
->schedule
);
2143 stmt
->schedule
= isl_map_set_tuple_id(stmt
->schedule
,
2144 isl_dim_in
, stmt_id
);
2146 pos
= isl_map_find_dim_by_id(stmt
->schedule
, isl_dim_param
, var_id
);
2148 isl_set
*set
= isl_map_wrap(stmt
->schedule
);
2149 set
= internalize_iv(set
, pos
, isl_aff_copy(iv_map
));
2150 stmt
->schedule
= isl_set_unwrap(set
);
2153 dim
= isl_space_map_from_set(dim
);
2154 extend
= isl_multi_pw_aff_identity(dim
);
2155 extend
= isl_multi_pw_aff_drop_dims(extend
, isl_dim_out
, 0, 1);
2156 extend
= isl_multi_pw_aff_set_tuple_id(extend
, isl_dim_out
,
2157 isl_multi_pw_aff_get_tuple_id(extend
, isl_dim_in
));
2158 for (i
= 0; i
< stmt
->n_arg
; ++i
)
2159 stmt
->args
[i
] = expr_embed(stmt
->args
[i
],
2160 isl_multi_pw_aff_copy(extend
),
2161 isl_aff_copy(iv_map
), var_id
);
2162 stmt
->body
= expr_embed(stmt
->body
, extend
, iv_map
, var_id
);
2165 isl_id_free(var_id
);
2167 for (i
= 0; i
< stmt
->n_arg
; ++i
)
2169 return pet_stmt_free(stmt
);
2170 if (!stmt
->domain
|| !stmt
->schedule
|| !stmt
->body
)
2171 return pet_stmt_free(stmt
);
2175 isl_map_free(sched
);
2176 isl_aff_free(iv_map
);
2177 isl_id_free(var_id
);
2181 /* Embed the given pet_array in an extra outer loop with iteration domain
2183 * This embedding only has an effect on virtual arrays (those with
2184 * user pointer equal to NULL), which need to be extended along with
2185 * the iteration domain.
2187 static struct pet_array
*pet_array_embed(struct pet_array
*array
,
2188 __isl_take isl_set
*dom
)
2190 isl_id
*array_id
= NULL
;
2195 if (isl_set_has_tuple_id(array
->extent
))
2196 array_id
= isl_set_get_tuple_id(array
->extent
);
2198 if (array_id
&& !isl_id_get_user(array_id
)) {
2199 array
->extent
= isl_set_flat_product(dom
, array
->extent
);
2200 array
->extent
= isl_set_set_tuple_id(array
->extent
, array_id
);
2202 return pet_array_free(array
);
2205 isl_id_free(array_id
);
2214 /* Project out all unnamed parameters from "set" and return the result.
2216 static __isl_give isl_set
*set_project_out_unnamed_params(
2217 __isl_take isl_set
*set
)
2221 n
= isl_set_dim(set
, isl_dim_param
);
2222 for (i
= n
- 1; i
>= 0; --i
) {
2223 if (isl_set_has_dim_name(set
, isl_dim_param
, i
))
2225 set
= isl_set_project_out(set
, isl_dim_param
, i
, 1);
2231 /* Update the context with respect to an embedding into a loop
2232 * with iteration domain "dom" and induction variable "id".
2233 * "iv_map" expresses the real iterator (parameter "id") in terms
2234 * of a possibly virtual iterator (used in "dom").
2236 * If the current context is independent of "id", we don't need
2238 * Otherwise, a parameter value is invalid for the embedding if
2239 * any of the corresponding iterator values is invalid.
2240 * That is, a parameter value is valid only if all the corresponding
2241 * iterator values are valid.
2242 * We therefore compute the set of parameters
2244 * forall i in dom : valid (i)
2248 * not exists i in dom : not valid(i)
2252 * not exists i in dom \ valid(i)
2254 * Before we subtract valid(i) from dom, we first need to substitute
2255 * the real iterator for the virtual iterator.
2257 * If there are any unnamed parameters in "dom", then we consider
2258 * a parameter value to be valid if it is valid for any value of those
2259 * unnamed parameters. They are therefore projected out at the end.
2261 static __isl_give isl_set
*context_embed(__isl_take isl_set
*context
,
2262 __isl_keep isl_set
*dom
, __isl_keep isl_aff
*iv_map
,
2263 __isl_keep isl_id
*id
)
2268 pos
= isl_set_find_dim_by_id(context
, isl_dim_param
, id
);
2272 context
= isl_set_from_params(context
);
2273 context
= isl_set_add_dims(context
, isl_dim_set
, 1);
2274 context
= isl_set_equate(context
, isl_dim_param
, pos
, isl_dim_set
, 0);
2275 context
= isl_set_project_out(context
, isl_dim_param
, pos
, 1);
2276 ma
= isl_multi_aff_from_aff(isl_aff_copy(iv_map
));
2277 context
= isl_set_preimage_multi_aff(context
, ma
);
2278 context
= isl_set_subtract(isl_set_copy(dom
), context
);
2279 context
= isl_set_params(context
);
2280 context
= isl_set_complement(context
);
2281 context
= set_project_out_unnamed_params(context
);
2285 /* Update the implication with respect to an embedding into a loop
2286 * with iteration domain "dom".
2288 * Since embed_access extends virtual arrays along with the domain
2289 * of the access, we need to do the same with domain and range
2290 * of the implication. Since the original implication is only valid
2291 * within a given iteration of the loop, the extended implication
2292 * maps the extra array dimension corresponding to the extra loop
2295 static struct pet_implication
*pet_implication_embed(
2296 struct pet_implication
*implication
, __isl_take isl_set
*dom
)
2304 map
= isl_set_identity(dom
);
2305 id
= isl_map_get_tuple_id(implication
->extension
, isl_dim_in
);
2306 map
= isl_map_flat_product(map
, implication
->extension
);
2307 map
= isl_map_set_tuple_id(map
, isl_dim_in
, isl_id_copy(id
));
2308 map
= isl_map_set_tuple_id(map
, isl_dim_out
, id
);
2309 implication
->extension
= map
;
2310 if (!implication
->extension
)
2311 return pet_implication_free(implication
);
2319 /* Embed all statements and arrays in "scop" in an extra outer loop
2320 * with iteration domain "dom" and schedule "sched".
2321 * "id" represents the induction variable of the loop.
2322 * "iv_map" maps a possibly virtual iterator to the real iterator.
2323 * That is, it expresses the iterator that some of the parameters in "scop"
2324 * may refer to in terms of the iterator used in "dom" and
2325 * the domain of "sched".
2327 * Any skip conditions within the loop have no effect outside of the loop.
2328 * The caller is responsible for making sure skip[pet_skip_later] has been
2329 * taken into account.
2331 struct pet_scop
*pet_scop_embed(struct pet_scop
*scop
, __isl_take isl_set
*dom
,
2332 __isl_take isl_map
*sched
, __isl_take isl_aff
*iv_map
,
2333 __isl_take isl_id
*id
)
2340 pet_scop_reset_skip(scop
, pet_skip_now
);
2341 pet_scop_reset_skip(scop
, pet_skip_later
);
2343 scop
->context
= context_embed(scop
->context
, dom
, iv_map
, id
);
2347 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
2348 scop
->stmts
[i
] = pet_stmt_embed(scop
->stmts
[i
],
2349 isl_set_copy(dom
), isl_map_copy(sched
),
2350 isl_aff_copy(iv_map
), isl_id_copy(id
));
2351 if (!scop
->stmts
[i
])
2355 for (i
= 0; i
< scop
->n_array
; ++i
) {
2356 scop
->arrays
[i
] = pet_array_embed(scop
->arrays
[i
],
2358 if (!scop
->arrays
[i
])
2362 for (i
= 0; i
< scop
->n_implication
; ++i
) {
2363 scop
->implications
[i
] =
2364 pet_implication_embed(scop
->implications
[i
],
2366 if (!scop
->implications
[i
])
2371 isl_map_free(sched
);
2372 isl_aff_free(iv_map
);
2377 isl_map_free(sched
);
2378 isl_aff_free(iv_map
);
2380 return pet_scop_free(scop
);
2383 /* Add extra conditions on the parameters to the iteration domain of "stmt".
2385 static struct pet_stmt
*stmt_restrict(struct pet_stmt
*stmt
,
2386 __isl_take isl_set
*cond
)
2391 stmt
->domain
= isl_set_intersect_params(stmt
->domain
, cond
);
2396 return pet_stmt_free(stmt
);
2399 /* Add extra conditions to scop->skip[type].
2401 * The new skip condition only holds if it held before
2402 * and the condition is true. It does not hold if it did not hold
2403 * before or the condition is false.
2405 * The skip condition is assumed to be an affine expression.
2407 static struct pet_scop
*pet_scop_restrict_skip(struct pet_scop
*scop
,
2408 enum pet_skip type
, __isl_keep isl_set
*cond
)
2410 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
2416 if (!ext
->skip
[type
])
2419 if (!multi_pw_aff_is_affine(ext
->skip
[type
]))
2420 isl_die(isl_multi_pw_aff_get_ctx(ext
->skip
[type
]),
2421 isl_error_internal
, "can only restrict affine skips",
2422 return pet_scop_free(scop
));
2424 skip
= isl_multi_pw_aff_get_pw_aff(ext
->skip
[type
], 0);
2425 dom
= isl_pw_aff_domain(isl_pw_aff_copy(skip
));
2426 cond
= isl_set_copy(cond
);
2427 cond
= isl_set_from_params(cond
);
2428 cond
= isl_set_intersect(cond
, isl_pw_aff_non_zero_set(skip
));
2429 skip
= indicator_function(cond
, dom
);
2430 isl_multi_pw_aff_free(ext
->skip
[type
]);
2431 ext
->skip
[type
] = isl_multi_pw_aff_from_pw_aff(skip
);
2432 if (!ext
->skip
[type
])
2433 return pet_scop_free(scop
);
2438 /* Add extra conditions on the parameters to all iteration domains
2439 * and skip conditions.
2441 * A parameter value is valid for the result if it was valid
2442 * for the original scop and satisfies "cond" or if it does
2443 * not satisfy "cond" as in this case the scop is not executed
2444 * and the original constraints on the parameters are irrelevant.
2446 struct pet_scop
*pet_scop_restrict(struct pet_scop
*scop
,
2447 __isl_take isl_set
*cond
)
2451 scop
= pet_scop_restrict_skip(scop
, pet_skip_now
, cond
);
2452 scop
= pet_scop_restrict_skip(scop
, pet_skip_later
, cond
);
2457 scop
->context
= isl_set_intersect(scop
->context
, isl_set_copy(cond
));
2458 scop
->context
= isl_set_union(scop
->context
,
2459 isl_set_complement(isl_set_copy(cond
)));
2460 scop
->context
= isl_set_coalesce(scop
->context
);
2461 scop
->context
= set_project_out_unnamed_params(scop
->context
);
2465 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
2466 scop
->stmts
[i
] = stmt_restrict(scop
->stmts
[i
],
2467 isl_set_copy(cond
));
2468 if (!scop
->stmts
[i
])
2476 return pet_scop_free(scop
);
2479 /* Construct a function that (upon precomposition) inserts
2480 * a filter value with name "id" and value "satisfied"
2481 * in the list of filter values embedded in the set space "space".
2483 * If "space" does not contain any filter values yet, we first create
2484 * a function that inserts 0 filter values, i.e.,
2486 * [space -> []] -> space
2488 * We can now assume that space is of the form [dom -> [filters]]
2489 * We construct an identity mapping on dom and a mapping on filters
2490 * that (upon precomposition) inserts the new filter
2493 * [satisfied, filters] -> [filters]
2495 * and then compute the cross product
2497 * [dom -> [satisfied, filters]] -> [dom -> [filters]]
2499 static __isl_give isl_pw_multi_aff
*insert_filter_pma(
2500 __isl_take isl_space
*space
, __isl_take isl_id
*id
, int satisfied
)
2504 isl_pw_multi_aff
*pma0
, *pma
, *pma_dom
, *pma_ran
;
2507 if (isl_space_is_wrapping(space
)) {
2508 space2
= isl_space_map_from_set(isl_space_copy(space
));
2509 ma
= isl_multi_aff_identity(space2
);
2510 space
= isl_space_unwrap(space
);
2512 space
= isl_space_from_domain(space
);
2513 ma
= isl_multi_aff_domain_map(isl_space_copy(space
));
2516 space2
= isl_space_domain(isl_space_copy(space
));
2517 pma_dom
= isl_pw_multi_aff_identity(isl_space_map_from_set(space2
));
2518 space
= isl_space_range(space
);
2519 space
= isl_space_insert_dims(space
, isl_dim_set
, 0, 1);
2520 pma_ran
= isl_pw_multi_aff_project_out_map(space
, isl_dim_set
, 0, 1);
2521 pma_ran
= isl_pw_multi_aff_set_dim_id(pma_ran
, isl_dim_in
, 0, id
);
2522 pma_ran
= isl_pw_multi_aff_fix_si(pma_ran
, isl_dim_in
, 0, satisfied
);
2523 pma
= isl_pw_multi_aff_product(pma_dom
, pma_ran
);
2525 pma0
= isl_pw_multi_aff_from_multi_aff(ma
);
2526 pma
= isl_pw_multi_aff_pullback_pw_multi_aff(pma0
, pma
);
2531 /* Insert an argument expression corresponding to "test" in front
2532 * of the list of arguments described by *n_arg and *args.
2534 static int args_insert_access(unsigned *n_arg
, struct pet_expr
***args
,
2535 __isl_keep isl_multi_pw_aff
*test
)
2538 isl_ctx
*ctx
= isl_multi_pw_aff_get_ctx(test
);
2544 *args
= isl_calloc_array(ctx
, struct pet_expr
*, 1);
2548 struct pet_expr
**ext
;
2549 ext
= isl_calloc_array(ctx
, struct pet_expr
*, 1 + *n_arg
);
2552 for (i
= 0; i
< *n_arg
; ++i
)
2553 ext
[1 + i
] = (*args
)[i
];
2558 (*args
)[0] = pet_expr_from_index(isl_multi_pw_aff_copy(test
));
2565 /* Make the expression "expr" depend on the value of "test"
2566 * being equal to "satisfied".
2568 * If "test" is an affine expression, we simply add the conditions
2569 * on the expression having the value "satisfied" to all access relations
2570 * and index expressions.
2572 * Otherwise, we add a filter to "expr" (which is then assumed to be
2573 * an access expression) corresponding to "test" being equal to "satisfied".
2575 struct pet_expr
*pet_expr_filter(struct pet_expr
*expr
,
2576 __isl_take isl_multi_pw_aff
*test
, int satisfied
)
2581 isl_pw_multi_aff
*pma
;
2586 if (!isl_multi_pw_aff_has_tuple_id(test
, isl_dim_out
)) {
2590 pa
= isl_multi_pw_aff_get_pw_aff(test
, 0);
2591 isl_multi_pw_aff_free(test
);
2593 cond
= isl_pw_aff_non_zero_set(pa
);
2595 cond
= isl_pw_aff_zero_set(pa
);
2596 return pet_expr_restrict(expr
, isl_set_params(cond
));
2599 ctx
= isl_multi_pw_aff_get_ctx(test
);
2600 if (expr
->type
!= pet_expr_access
)
2601 isl_die(ctx
, isl_error_invalid
,
2602 "can only filter access expressions", goto error
);
2604 space
= isl_space_domain(isl_map_get_space(expr
->acc
.access
));
2605 id
= isl_multi_pw_aff_get_tuple_id(test
, isl_dim_out
);
2606 pma
= insert_filter_pma(space
, id
, satisfied
);
2608 expr
->acc
.access
= isl_map_preimage_domain_pw_multi_aff(
2610 isl_pw_multi_aff_copy(pma
));
2611 expr
->acc
.index
= isl_multi_pw_aff_pullback_pw_multi_aff(
2612 expr
->acc
.index
, pma
);
2613 if (!expr
->acc
.access
|| !expr
->acc
.index
)
2616 if (args_insert_access(&expr
->n_arg
, &expr
->args
, test
) < 0)
2619 isl_multi_pw_aff_free(test
);
2622 isl_multi_pw_aff_free(test
);
2623 return pet_expr_free(expr
);
2626 /* Look through the applications in "scop" for any that can be
2627 * applied to the filter expressed by "map" and "satisified".
2628 * If there is any, then apply it to "map" and return the result.
2629 * Otherwise, return "map".
2630 * "id" is the identifier of the virtual array.
2632 * We only introduce at most one implication for any given virtual array,
2633 * so we can apply the implication and return as soon as we find one.
2635 static __isl_give isl_map
*apply_implications(struct pet_scop
*scop
,
2636 __isl_take isl_map
*map
, __isl_keep isl_id
*id
, int satisfied
)
2640 for (i
= 0; i
< scop
->n_implication
; ++i
) {
2641 struct pet_implication
*pi
= scop
->implications
[i
];
2644 if (pi
->satisfied
!= satisfied
)
2646 pi_id
= isl_map_get_tuple_id(pi
->extension
, isl_dim_in
);
2651 return isl_map_apply_range(map
, isl_map_copy(pi
->extension
));
2657 /* Is the filter expressed by "test" and "satisfied" implied
2658 * by filter "pos" on "domain", with filter "expr", taking into
2659 * account the implications of "scop"?
2661 * For filter on domain implying that expressed by "test" and "satisfied",
2662 * the filter needs to be an access to the same (virtual) array as "test" and
2663 * the filter value needs to be equal to "satisfied".
2664 * Moreover, the filter access relation, possibly extended by
2665 * the implications in "scop" needs to contain "test".
2667 static int implies_filter(struct pet_scop
*scop
,
2668 __isl_keep isl_map
*domain
, int pos
, struct pet_expr
*expr
,
2669 __isl_keep isl_map
*test
, int satisfied
)
2671 isl_id
*test_id
, *arg_id
;
2678 if (expr
->type
!= pet_expr_access
)
2680 test_id
= isl_map_get_tuple_id(test
, isl_dim_out
);
2681 arg_id
= pet_expr_access_get_id(expr
);
2682 isl_id_free(arg_id
);
2683 isl_id_free(test_id
);
2684 if (test_id
!= arg_id
)
2686 val
= isl_map_plain_get_val_if_fixed(domain
, isl_dim_out
, pos
);
2687 is_int
= isl_val_is_int(val
);
2689 s
= isl_val_get_num_si(val
);
2698 implied
= isl_map_copy(expr
->acc
.access
);
2699 implied
= apply_implications(scop
, implied
, test_id
, satisfied
);
2700 is_subset
= isl_map_is_subset(test
, implied
);
2701 isl_map_free(implied
);
2706 /* Is the filter expressed by "test" and "satisfied" implied
2707 * by any of the filters on the domain of "stmt", taking into
2708 * account the implications of "scop"?
2710 static int filter_implied(struct pet_scop
*scop
,
2711 struct pet_stmt
*stmt
, __isl_keep isl_multi_pw_aff
*test
, int satisfied
)
2719 if (!scop
|| !stmt
|| !test
)
2721 if (scop
->n_implication
== 0)
2723 if (stmt
->n_arg
== 0)
2726 domain
= isl_set_unwrap(isl_set_copy(stmt
->domain
));
2727 test_map
= isl_map_from_multi_pw_aff(isl_multi_pw_aff_copy(test
));
2730 for (i
= 0; i
< stmt
->n_arg
; ++i
) {
2731 implied
= implies_filter(scop
, domain
, i
, stmt
->args
[i
],
2732 test_map
, satisfied
);
2733 if (implied
< 0 || implied
)
2737 isl_map_free(test_map
);
2738 isl_map_free(domain
);
2742 /* Make the statement "stmt" depend on the value of "test"
2743 * being equal to "satisfied" by adjusting stmt->domain.
2745 * The domain of "test" corresponds to the (zero or more) outer dimensions
2746 * of the iteration domain.
2748 * We first extend "test" to apply to the entire iteration domain and
2749 * then check if the filter that we are about to add is implied
2750 * by any of the current filters, possibly taking into account
2751 * the implications in "scop". If so, we leave "stmt" untouched and return.
2753 * Otherwise, we insert an argument corresponding to a read to "test"
2754 * from the iteration domain of "stmt" in front of the list of arguments.
2755 * We also insert a corresponding output dimension in the wrapped
2756 * map contained in stmt->domain, with value set to "satisfied".
2758 static struct pet_stmt
*stmt_filter(struct pet_scop
*scop
,
2759 struct pet_stmt
*stmt
, __isl_take isl_multi_pw_aff
*test
, int satisfied
)
2765 isl_pw_multi_aff
*pma
;
2766 isl_multi_aff
*add_dom
;
2768 isl_local_space
*ls
;
2774 space
= isl_set_get_space(stmt
->domain
);
2775 if (isl_space_is_wrapping(space
))
2776 space
= isl_space_domain(isl_space_unwrap(space
));
2777 n_test_dom
= isl_multi_pw_aff_dim(test
, isl_dim_in
);
2778 space
= isl_space_from_domain(space
);
2779 space
= isl_space_add_dims(space
, isl_dim_out
, n_test_dom
);
2780 add_dom
= isl_multi_aff_zero(isl_space_copy(space
));
2781 ls
= isl_local_space_from_space(isl_space_domain(space
));
2782 for (i
= 0; i
< n_test_dom
; ++i
) {
2784 aff
= isl_aff_var_on_domain(isl_local_space_copy(ls
),
2786 add_dom
= isl_multi_aff_set_aff(add_dom
, i
, aff
);
2788 isl_local_space_free(ls
);
2789 test
= isl_multi_pw_aff_pullback_multi_aff(test
, add_dom
);
2791 implied
= filter_implied(scop
, stmt
, test
, satisfied
);
2795 isl_multi_pw_aff_free(test
);
2799 id
= isl_multi_pw_aff_get_tuple_id(test
, isl_dim_out
);
2800 pma
= insert_filter_pma(isl_set_get_space(stmt
->domain
), id
, satisfied
);
2801 stmt
->domain
= isl_set_preimage_pw_multi_aff(stmt
->domain
, pma
);
2803 if (args_insert_access(&stmt
->n_arg
, &stmt
->args
, test
) < 0)
2806 isl_multi_pw_aff_free(test
);
2809 isl_multi_pw_aff_free(test
);
2810 return pet_stmt_free(stmt
);
2813 /* Does "scop" have a skip condition of the given "type"?
2815 int pet_scop_has_skip(struct pet_scop
*scop
, enum pet_skip type
)
2817 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
2821 return ext
->skip
[type
] != NULL
;
2824 /* Does "scop" have a skip condition of the given "type" that
2825 * is an affine expression?
2827 int pet_scop_has_affine_skip(struct pet_scop
*scop
, enum pet_skip type
)
2829 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
2833 if (!ext
->skip
[type
])
2835 return multi_pw_aff_is_affine(ext
->skip
[type
]);
2838 /* Does "scop" have a skip condition of the given "type" that
2839 * is not an affine expression?
2841 int pet_scop_has_var_skip(struct pet_scop
*scop
, enum pet_skip type
)
2843 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
2848 if (!ext
->skip
[type
])
2850 aff
= multi_pw_aff_is_affine(ext
->skip
[type
]);
2856 /* Does "scop" have a skip condition of the given "type" that
2857 * is affine and holds on the entire domain?
2859 int pet_scop_has_universal_skip(struct pet_scop
*scop
, enum pet_skip type
)
2861 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
2867 is_aff
= pet_scop_has_affine_skip(scop
, type
);
2868 if (is_aff
< 0 || !is_aff
)
2871 pa
= isl_multi_pw_aff_get_pw_aff(ext
->skip
[type
], 0);
2872 set
= isl_pw_aff_non_zero_set(pa
);
2873 is_univ
= isl_set_plain_is_universe(set
);
2879 /* Replace scop->skip[type] by "skip".
2881 struct pet_scop
*pet_scop_set_skip(struct pet_scop
*scop
,
2882 enum pet_skip type
, __isl_take isl_multi_pw_aff
*skip
)
2884 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
2889 isl_multi_pw_aff_free(ext
->skip
[type
]);
2890 ext
->skip
[type
] = skip
;
2894 isl_multi_pw_aff_free(skip
);
2895 return pet_scop_free(scop
);
2898 /* Return a copy of scop->skip[type].
2900 __isl_give isl_multi_pw_aff
*pet_scop_get_skip(struct pet_scop
*scop
,
2903 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
2908 return isl_multi_pw_aff_copy(ext
->skip
[type
]);
2911 /* Assuming scop->skip[type] is an affine expression,
2912 * return the constraints on the parameters for which the skip condition
2915 __isl_give isl_set
*pet_scop_get_affine_skip_domain(struct pet_scop
*scop
,
2918 isl_multi_pw_aff
*skip
;
2921 skip
= pet_scop_get_skip(scop
, type
);
2922 pa
= isl_multi_pw_aff_get_pw_aff(skip
, 0);
2923 isl_multi_pw_aff_free(skip
);
2924 return isl_set_params(isl_pw_aff_non_zero_set(pa
));
2927 /* Return the identifier of the variable that is accessed by
2928 * the skip condition of the given type.
2930 * The skip condition is assumed not to be an affine condition.
2932 __isl_give isl_id
*pet_scop_get_skip_id(struct pet_scop
*scop
,
2935 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
2940 return isl_multi_pw_aff_get_tuple_id(ext
->skip
[type
], isl_dim_out
);
2943 /* Return an access pet_expr corresponding to the skip condition
2944 * of the given type.
2946 struct pet_expr
*pet_scop_get_skip_expr(struct pet_scop
*scop
,
2949 return pet_expr_from_index(pet_scop_get_skip(scop
, type
));
2952 /* Drop the the skip condition scop->skip[type].
2954 void pet_scop_reset_skip(struct pet_scop
*scop
, enum pet_skip type
)
2956 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
2961 isl_multi_pw_aff_free(ext
->skip
[type
]);
2962 ext
->skip
[type
] = NULL
;
2965 /* Make the skip condition (if any) depend on the value of "test" being
2966 * equal to "satisfied".
2968 * We only support the case where the original skip condition is universal,
2969 * i.e., where skipping is unconditional, and where satisfied == 1.
2970 * In this case, the skip condition is changed to skip only when
2971 * "test" is equal to one.
2973 static struct pet_scop
*pet_scop_filter_skip(struct pet_scop
*scop
,
2974 enum pet_skip type
, __isl_keep isl_multi_pw_aff
*test
, int satisfied
)
2980 if (!pet_scop_has_skip(scop
, type
))
2984 is_univ
= pet_scop_has_universal_skip(scop
, type
);
2986 return pet_scop_free(scop
);
2987 if (satisfied
&& is_univ
) {
2988 isl_multi_pw_aff
*skip
;
2989 skip
= isl_multi_pw_aff_copy(test
);
2990 scop
= pet_scop_set_skip(scop
, type
, skip
);
2994 isl_die(isl_multi_pw_aff_get_ctx(test
), isl_error_internal
,
2995 "skip expression cannot be filtered",
2996 return pet_scop_free(scop
));
3002 /* Make all statements in "scop" depend on the value of "test"
3003 * being equal to "satisfied" by adjusting their domains.
3005 struct pet_scop
*pet_scop_filter(struct pet_scop
*scop
,
3006 __isl_take isl_multi_pw_aff
*test
, int satisfied
)
3010 scop
= pet_scop_filter_skip(scop
, pet_skip_now
, test
, satisfied
);
3011 scop
= pet_scop_filter_skip(scop
, pet_skip_later
, test
, satisfied
);
3016 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
3017 scop
->stmts
[i
] = stmt_filter(scop
, scop
->stmts
[i
],
3018 isl_multi_pw_aff_copy(test
), satisfied
);
3019 if (!scop
->stmts
[i
])
3023 isl_multi_pw_aff_free(test
);
3026 isl_multi_pw_aff_free(test
);
3027 return pet_scop_free(scop
);
3030 /* Add all parameters in "expr" to "space" and return the result.
3032 static __isl_give isl_space
*expr_collect_params(struct pet_expr
*expr
,
3033 __isl_take isl_space
*space
)
3039 for (i
= 0; i
< expr
->n_arg
; ++i
)
3040 space
= expr_collect_params(expr
->args
[i
], space
);
3042 if (expr
->type
== pet_expr_access
)
3043 space
= isl_space_align_params(space
,
3044 isl_map_get_space(expr
->acc
.access
));
3048 pet_expr_free(expr
);
3049 return isl_space_free(space
);
3052 /* Add all parameters in "stmt" to "space" and return the result.
3054 static __isl_give isl_space
*stmt_collect_params(struct pet_stmt
*stmt
,
3055 __isl_take isl_space
*space
)
3060 return isl_space_free(space
);
3062 space
= isl_space_align_params(space
, isl_set_get_space(stmt
->domain
));
3063 space
= isl_space_align_params(space
,
3064 isl_map_get_space(stmt
->schedule
));
3065 for (i
= 0; i
< stmt
->n_arg
; ++i
)
3066 space
= expr_collect_params(stmt
->args
[i
], space
);
3067 space
= expr_collect_params(stmt
->body
, space
);
3072 /* Add all parameters in "array" to "space" and return the result.
3074 static __isl_give isl_space
*array_collect_params(struct pet_array
*array
,
3075 __isl_take isl_space
*space
)
3078 return isl_space_free(space
);
3080 space
= isl_space_align_params(space
,
3081 isl_set_get_space(array
->context
));
3082 space
= isl_space_align_params(space
, isl_set_get_space(array
->extent
));
3087 /* Add all parameters in "scop" to "space" and return the result.
3089 static __isl_give isl_space
*scop_collect_params(struct pet_scop
*scop
,
3090 __isl_take isl_space
*space
)
3095 return isl_space_free(space
);
3097 for (i
= 0; i
< scop
->n_array
; ++i
)
3098 space
= array_collect_params(scop
->arrays
[i
], space
);
3100 for (i
= 0; i
< scop
->n_stmt
; ++i
)
3101 space
= stmt_collect_params(scop
->stmts
[i
], space
);
3106 /* Add all parameters in "space" to all access relations and index expressions
3109 static struct pet_expr
*expr_propagate_params(struct pet_expr
*expr
,
3110 __isl_take isl_space
*space
)
3117 for (i
= 0; i
< expr
->n_arg
; ++i
) {
3119 expr_propagate_params(expr
->args
[i
],
3120 isl_space_copy(space
));
3125 if (expr
->type
== pet_expr_access
) {
3126 expr
->acc
.access
= isl_map_align_params(expr
->acc
.access
,
3127 isl_space_copy(space
));
3128 expr
->acc
.index
= isl_multi_pw_aff_align_params(expr
->acc
.index
,
3129 isl_space_copy(space
));
3130 if (!expr
->acc
.access
|| !expr
->acc
.index
)
3134 isl_space_free(space
);
3137 isl_space_free(space
);
3138 return pet_expr_free(expr
);
3141 /* Add all parameters in "space" to the domain, schedule and
3142 * all access relations in "stmt".
3144 static struct pet_stmt
*stmt_propagate_params(struct pet_stmt
*stmt
,
3145 __isl_take isl_space
*space
)
3152 stmt
->domain
= isl_set_align_params(stmt
->domain
,
3153 isl_space_copy(space
));
3154 stmt
->schedule
= isl_map_align_params(stmt
->schedule
,
3155 isl_space_copy(space
));
3157 for (i
= 0; i
< stmt
->n_arg
; ++i
) {
3158 stmt
->args
[i
] = expr_propagate_params(stmt
->args
[i
],
3159 isl_space_copy(space
));
3163 stmt
->body
= expr_propagate_params(stmt
->body
, isl_space_copy(space
));
3165 if (!stmt
->domain
|| !stmt
->schedule
|| !stmt
->body
)
3168 isl_space_free(space
);
3171 isl_space_free(space
);
3172 return pet_stmt_free(stmt
);
3175 /* Add all parameters in "space" to "array".
3177 static struct pet_array
*array_propagate_params(struct pet_array
*array
,
3178 __isl_take isl_space
*space
)
3183 array
->context
= isl_set_align_params(array
->context
,
3184 isl_space_copy(space
));
3185 array
->extent
= isl_set_align_params(array
->extent
,
3186 isl_space_copy(space
));
3187 if (array
->value_bounds
) {
3188 array
->value_bounds
= isl_set_align_params(array
->value_bounds
,
3189 isl_space_copy(space
));
3190 if (!array
->value_bounds
)
3194 if (!array
->context
|| !array
->extent
)
3197 isl_space_free(space
);
3200 isl_space_free(space
);
3201 return pet_array_free(array
);
3204 /* Add all parameters in "space" to "scop".
3206 static struct pet_scop
*scop_propagate_params(struct pet_scop
*scop
,
3207 __isl_take isl_space
*space
)
3214 for (i
= 0; i
< scop
->n_array
; ++i
) {
3215 scop
->arrays
[i
] = array_propagate_params(scop
->arrays
[i
],
3216 isl_space_copy(space
));
3217 if (!scop
->arrays
[i
])
3221 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
3222 scop
->stmts
[i
] = stmt_propagate_params(scop
->stmts
[i
],
3223 isl_space_copy(space
));
3224 if (!scop
->stmts
[i
])
3228 isl_space_free(space
);
3231 isl_space_free(space
);
3232 return pet_scop_free(scop
);
3235 /* Update all isl_sets and isl_maps in "scop" such that they all
3236 * have the same parameters.
3238 struct pet_scop
*pet_scop_align_params(struct pet_scop
*scop
)
3245 space
= isl_set_get_space(scop
->context
);
3246 space
= scop_collect_params(scop
, space
);
3248 scop
->context
= isl_set_align_params(scop
->context
,
3249 isl_space_copy(space
));
3250 scop
= scop_propagate_params(scop
, space
);
3252 if (scop
&& !scop
->context
)
3253 return pet_scop_free(scop
);
3258 /* Check if the given index expression accesses a (0D) array that corresponds
3259 * to one of the parameters in "dim". If so, replace the array access
3260 * by an access to the set of integers with as index (and value)
3263 static __isl_give isl_multi_pw_aff
*index_detect_parameter(
3264 __isl_take isl_multi_pw_aff
*index
, __isl_take isl_space
*space
)
3266 isl_local_space
*ls
;
3267 isl_id
*array_id
= NULL
;
3271 if (isl_multi_pw_aff_has_tuple_id(index
, isl_dim_out
)) {
3272 array_id
= isl_multi_pw_aff_get_tuple_id(index
, isl_dim_out
);
3273 pos
= isl_space_find_dim_by_id(space
, isl_dim_param
, array_id
);
3275 isl_space_free(space
);
3278 isl_id_free(array_id
);
3282 space
= isl_multi_pw_aff_get_domain_space(index
);
3283 isl_multi_pw_aff_free(index
);
3285 pos
= isl_space_find_dim_by_id(space
, isl_dim_param
, array_id
);
3287 space
= isl_space_insert_dims(space
, isl_dim_param
, 0, 1);
3288 space
= isl_space_set_dim_id(space
, isl_dim_param
, 0, array_id
);
3291 isl_id_free(array_id
);
3293 ls
= isl_local_space_from_space(space
);
3294 aff
= isl_aff_var_on_domain(ls
, isl_dim_param
, pos
);
3295 index
= isl_multi_pw_aff_from_pw_aff(isl_pw_aff_from_aff(aff
));
3300 /* Check if the given access relation accesses a (0D) array that corresponds
3301 * to one of the parameters in "dim". If so, replace the array access
3302 * by an access to the set of integers with as index (and value)
3305 static __isl_give isl_map
*access_detect_parameter(__isl_take isl_map
*access
,
3306 __isl_take isl_space
*dim
)
3308 isl_id
*array_id
= NULL
;
3311 if (isl_map_has_tuple_id(access
, isl_dim_out
)) {
3312 array_id
= isl_map_get_tuple_id(access
, isl_dim_out
);
3313 pos
= isl_space_find_dim_by_id(dim
, isl_dim_param
, array_id
);
3315 isl_space_free(dim
);
3318 isl_id_free(array_id
);
3322 pos
= isl_map_find_dim_by_id(access
, isl_dim_param
, array_id
);
3324 access
= isl_map_insert_dims(access
, isl_dim_param
, 0, 1);
3325 access
= isl_map_set_dim_id(access
, isl_dim_param
, 0, array_id
);
3328 isl_id_free(array_id
);
3330 access
= isl_map_insert_dims(access
, isl_dim_out
, 0, 1);
3331 access
= isl_map_equate(access
, isl_dim_param
, pos
, isl_dim_out
, 0);
3336 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
3337 * in "dim" by a value equal to the corresponding parameter.
3339 static struct pet_expr
*expr_detect_parameter_accesses(struct pet_expr
*expr
,
3340 __isl_take isl_space
*dim
)
3347 for (i
= 0; i
< expr
->n_arg
; ++i
) {
3349 expr_detect_parameter_accesses(expr
->args
[i
],
3350 isl_space_copy(dim
));
3355 if (expr
->type
== pet_expr_access
) {
3356 expr
->acc
.access
= access_detect_parameter(expr
->acc
.access
,
3357 isl_space_copy(dim
));
3358 expr
->acc
.index
= index_detect_parameter(expr
->acc
.index
,
3359 isl_space_copy(dim
));
3360 if (!expr
->acc
.access
|| !expr
->acc
.index
)
3364 isl_space_free(dim
);
3367 isl_space_free(dim
);
3368 return pet_expr_free(expr
);
3371 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
3372 * in "dim" by a value equal to the corresponding parameter.
3374 static struct pet_stmt
*stmt_detect_parameter_accesses(struct pet_stmt
*stmt
,
3375 __isl_take isl_space
*dim
)
3380 stmt
->body
= expr_detect_parameter_accesses(stmt
->body
,
3381 isl_space_copy(dim
));
3383 if (!stmt
->domain
|| !stmt
->schedule
|| !stmt
->body
)
3386 isl_space_free(dim
);
3389 isl_space_free(dim
);
3390 return pet_stmt_free(stmt
);
3393 /* Replace all accesses to (0D) arrays that correspond to one of the parameters
3394 * in "dim" by a value equal to the corresponding parameter.
3396 static struct pet_scop
*scop_detect_parameter_accesses(struct pet_scop
*scop
,
3397 __isl_take isl_space
*dim
)
3404 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
3405 scop
->stmts
[i
] = stmt_detect_parameter_accesses(scop
->stmts
[i
],
3406 isl_space_copy(dim
));
3407 if (!scop
->stmts
[i
])
3411 isl_space_free(dim
);
3414 isl_space_free(dim
);
3415 return pet_scop_free(scop
);
3418 /* Replace all accesses to (0D) arrays that correspond to any of
3419 * the parameters used in "scop" by a value equal
3420 * to the corresponding parameter.
3422 struct pet_scop
*pet_scop_detect_parameter_accesses(struct pet_scop
*scop
)
3429 dim
= isl_set_get_space(scop
->context
);
3430 dim
= scop_collect_params(scop
, dim
);
3432 scop
= scop_detect_parameter_accesses(scop
, dim
);
3437 /* Return the relation mapping domain iterations to all possibly
3438 * accessed data elements.
3439 * In particular, take the access relation and project out the values
3440 * of the arguments, if any.
3442 __isl_give isl_map
*pet_expr_access_get_may_access(struct pet_expr
*expr
)
3450 if (expr
->type
!= pet_expr_access
)
3453 access
= isl_map_copy(expr
->acc
.access
);
3454 if (expr
->n_arg
== 0)
3457 space
= isl_space_domain(isl_map_get_space(access
));
3458 map
= isl_map_universe(isl_space_unwrap(space
));
3459 map
= isl_map_domain_map(map
);
3460 access
= isl_map_apply_domain(access
, map
);
3465 /* Return the relation mapping domain iterations to all possibly
3466 * accessed data elements, with its domain tagged with the reference
3469 __isl_give isl_map
*pet_expr_access_get_tagged_may_access(
3470 struct pet_expr
*expr
)
3477 access
= pet_expr_access_get_may_access(expr
);
3478 access
= tag_access(access
, isl_id_copy(expr
->acc
.ref_id
));
3483 /* Add the access relation of the access expression "expr" to "accesses" and
3484 * return the result.
3485 * The domain of the access relation is intersected with "domain".
3486 * If "tag" is set, then the access relation is tagged with
3487 * the corresponding reference identifier.
3489 static __isl_give isl_union_map
*expr_collect_access(struct pet_expr
*expr
,
3490 int tag
, __isl_take isl_union_map
*accesses
, __isl_keep isl_set
*domain
)
3494 access
= pet_expr_access_get_may_access(expr
);
3495 access
= isl_map_intersect_domain(access
, isl_set_copy(domain
));
3497 access
= tag_access(access
, isl_id_copy(expr
->acc
.ref_id
));
3498 return isl_union_map_add_map(accesses
, access
);
3501 /* Add all read access relations (if "read" is set) and/or all write
3502 * access relations (if "write" is set) to "accesses" and return the result.
3503 * The domains of the access relations are intersected with "domain".
3504 * If "tag" is set, then the access relations are tagged with
3505 * the corresponding reference identifiers.
3507 * If "must" is set, then we only add the accesses that are definitely
3508 * performed. Otherwise, we add all potential accesses.
3509 * In particular, if the access has any arguments, then if "must" is
3510 * set we currently skip the access completely. If "must" is not set,
3511 * we project out the values of the access arguments.
3513 static __isl_give isl_union_map
*expr_collect_accesses(struct pet_expr
*expr
,
3514 int read
, int write
, int must
, int tag
,
3515 __isl_take isl_union_map
*accesses
, __isl_keep isl_set
*domain
)
3522 return isl_union_map_free(accesses
);
3524 for (i
= 0; i
< expr
->n_arg
; ++i
)
3525 accesses
= expr_collect_accesses(expr
->args
[i
],
3526 read
, write
, must
, tag
, accesses
, domain
);
3528 if (expr
->type
== pet_expr_access
&& !pet_expr_is_affine(expr
) &&
3529 ((read
&& expr
->acc
.read
) || (write
&& expr
->acc
.write
)) &&
3530 (!must
|| expr
->n_arg
== 0)) {
3531 accesses
= expr_collect_access(expr
, tag
, accesses
, domain
);
3537 /* Collect and return all read access relations (if "read" is set)
3538 * and/or all write access relations (if "write" is set) in "stmt".
3539 * If "tag" is set, then the access relations are tagged with
3540 * the corresponding reference identifiers.
3541 * If "kill" is set, then "stmt" is a kill statement and we simply
3542 * add the argument of the kill operation.
3544 * If "must" is set, then we only add the accesses that are definitely
3545 * performed. Otherwise, we add all potential accesses.
3546 * In particular, if the statement has any arguments, then if "must" is
3547 * set we currently skip the statement completely. If "must" is not set,
3548 * we project out the values of the statement arguments.
3550 static __isl_give isl_union_map
*stmt_collect_accesses(struct pet_stmt
*stmt
,
3551 int read
, int write
, int kill
, int must
, int tag
,
3552 __isl_take isl_space
*dim
)
3554 isl_union_map
*accesses
;
3560 accesses
= isl_union_map_empty(dim
);
3562 if (must
&& stmt
->n_arg
> 0)
3565 domain
= isl_set_copy(stmt
->domain
);
3566 if (isl_set_is_wrapping(domain
))
3567 domain
= isl_map_domain(isl_set_unwrap(domain
));
3570 accesses
= expr_collect_access(stmt
->body
->args
[0], tag
,
3573 accesses
= expr_collect_accesses(stmt
->body
, read
, write
,
3574 must
, tag
, accesses
, domain
);
3575 isl_set_free(domain
);
3580 /* Is "stmt" an assignment statement?
3582 int pet_stmt_is_assign(struct pet_stmt
*stmt
)
3586 if (stmt
->body
->type
!= pet_expr_binary
)
3588 return stmt
->body
->op
== pet_op_assign
;
3591 /* Is "stmt" a kill statement?
3593 int pet_stmt_is_kill(struct pet_stmt
*stmt
)
3597 if (stmt
->body
->type
!= pet_expr_unary
)
3599 return stmt
->body
->op
== pet_op_kill
;
3602 /* Is "stmt" an assume statement?
3604 int pet_stmt_is_assume(struct pet_stmt
*stmt
)
3606 if (stmt
->body
->type
!= pet_expr_unary
)
3608 return stmt
->body
->op
== pet_op_assume
;
3611 /* Compute a mapping from all arrays (of structs) in scop
3612 * to their innermost arrays.
3614 * In particular, for each array of a primitive type, the result
3615 * contains the identity mapping on that array.
3616 * For each array involving member accesses, the result
3617 * contains a mapping from the elements of any intermediate array of structs
3618 * to all corresponding elements of the innermost nested arrays.
3620 static __isl_give isl_union_map
*compute_to_inner(struct pet_scop
*scop
)
3623 isl_union_map
*to_inner
;
3625 to_inner
= isl_union_map_empty(isl_set_get_space(scop
->context
));
3627 for (i
= 0; i
< scop
->n_array
; ++i
) {
3628 struct pet_array
*array
= scop
->arrays
[i
];
3630 isl_map
*map
, *gist
;
3632 if (array
->element_is_record
)
3635 map
= isl_set_identity(isl_set_copy(array
->extent
));
3637 set
= isl_map_domain(isl_map_copy(map
));
3638 gist
= isl_map_copy(map
);
3639 gist
= isl_map_gist_domain(gist
, isl_set_copy(set
));
3640 to_inner
= isl_union_map_add_map(to_inner
, gist
);
3642 while (set
&& isl_set_is_wrapping(set
)) {
3646 id
= isl_set_get_tuple_id(set
);
3647 wrapped
= isl_set_unwrap(set
);
3648 wrapped
= isl_map_domain_map(wrapped
);
3649 wrapped
= isl_map_set_tuple_id(wrapped
, isl_dim_in
, id
);
3650 map
= isl_map_apply_domain(map
, wrapped
);
3651 set
= isl_map_domain(isl_map_copy(map
));
3652 gist
= isl_map_copy(map
);
3653 gist
= isl_map_gist_domain(gist
, isl_set_copy(set
));
3654 to_inner
= isl_union_map_add_map(to_inner
, gist
);
3664 /* Collect and return all read access relations (if "read" is set)
3665 * and/or all write access relations (if "write" is set) in "scop".
3666 * If "kill" is set, then we only add the arguments of kill operations.
3667 * If "must" is set, then we only add the accesses that are definitely
3668 * performed. Otherwise, we add all potential accesses.
3669 * If "tag" is set, then the access relations are tagged with
3670 * the corresponding reference identifiers.
3671 * For accesses to structures, the returned access relation accesses
3672 * all individual fields in the structures.
3674 static __isl_give isl_union_map
*scop_collect_accesses(struct pet_scop
*scop
,
3675 int read
, int write
, int kill
, int must
, int tag
)
3678 isl_union_map
*accesses
;
3679 isl_union_set
*arrays
;
3680 isl_union_map
*to_inner
;
3685 accesses
= isl_union_map_empty(isl_set_get_space(scop
->context
));
3687 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
3688 struct pet_stmt
*stmt
= scop
->stmts
[i
];
3689 isl_union_map
*accesses_i
;
3692 if (kill
&& !pet_stmt_is_kill(stmt
))
3695 space
= isl_set_get_space(scop
->context
);
3696 accesses_i
= stmt_collect_accesses(stmt
, read
, write
, kill
,
3698 accesses
= isl_union_map_union(accesses
, accesses_i
);
3701 arrays
= isl_union_set_empty(isl_union_map_get_space(accesses
));
3702 for (i
= 0; i
< scop
->n_array
; ++i
) {
3703 isl_set
*extent
= isl_set_copy(scop
->arrays
[i
]->extent
);
3704 arrays
= isl_union_set_add_set(arrays
, extent
);
3706 accesses
= isl_union_map_intersect_range(accesses
, arrays
);
3708 to_inner
= compute_to_inner(scop
);
3709 accesses
= isl_union_map_apply_range(accesses
, to_inner
);
3714 /* Collect all potential read access relations.
3716 __isl_give isl_union_map
*pet_scop_collect_may_reads(struct pet_scop
*scop
)
3718 return scop_collect_accesses(scop
, 1, 0, 0, 0, 0);
3721 /* Collect all potential write access relations.
3723 __isl_give isl_union_map
*pet_scop_collect_may_writes(struct pet_scop
*scop
)
3725 return scop_collect_accesses(scop
, 0, 1, 0, 0, 0);
3728 /* Collect all definite write access relations.
3730 __isl_give isl_union_map
*pet_scop_collect_must_writes(struct pet_scop
*scop
)
3732 return scop_collect_accesses(scop
, 0, 1, 0, 1, 0);
3735 /* Collect all definite kill access relations.
3737 __isl_give isl_union_map
*pet_scop_collect_must_kills(struct pet_scop
*scop
)
3739 return scop_collect_accesses(scop
, 0, 0, 1, 1, 0);
3742 /* Collect all tagged potential read access relations.
3744 __isl_give isl_union_map
*pet_scop_collect_tagged_may_reads(
3745 struct pet_scop
*scop
)
3747 return scop_collect_accesses(scop
, 1, 0, 0, 0, 1);
3750 /* Collect all tagged potential write access relations.
3752 __isl_give isl_union_map
*pet_scop_collect_tagged_may_writes(
3753 struct pet_scop
*scop
)
3755 return scop_collect_accesses(scop
, 0, 1, 0, 0, 1);
3758 /* Collect all tagged definite write access relations.
3760 __isl_give isl_union_map
*pet_scop_collect_tagged_must_writes(
3761 struct pet_scop
*scop
)
3763 return scop_collect_accesses(scop
, 0, 1, 0, 1, 1);
3766 /* Collect all tagged definite kill access relations.
3768 __isl_give isl_union_map
*pet_scop_collect_tagged_must_kills(
3769 struct pet_scop
*scop
)
3771 return scop_collect_accesses(scop
, 0, 0, 1, 1, 1);
3774 /* Collect and return the union of iteration domains in "scop".
3776 __isl_give isl_union_set
*pet_scop_collect_domains(struct pet_scop
*scop
)
3780 isl_union_set
*domain
;
3785 domain
= isl_union_set_empty(isl_set_get_space(scop
->context
));
3787 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
3788 domain_i
= isl_set_copy(scop
->stmts
[i
]->domain
);
3789 domain
= isl_union_set_add_set(domain
, domain_i
);
3795 /* Collect and return the schedules of the statements in "scop".
3796 * The range is normalized to the maximal number of scheduling
3799 __isl_give isl_union_map
*pet_scop_collect_schedule(struct pet_scop
*scop
)
3802 isl_map
*schedule_i
;
3803 isl_union_map
*schedule
;
3804 int depth
, max_depth
= 0;
3809 schedule
= isl_union_map_empty(isl_set_get_space(scop
->context
));
3811 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
3812 depth
= isl_map_dim(scop
->stmts
[i
]->schedule
, isl_dim_out
);
3813 if (depth
> max_depth
)
3817 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
3818 schedule_i
= isl_map_copy(scop
->stmts
[i
]->schedule
);
3819 depth
= isl_map_dim(schedule_i
, isl_dim_out
);
3820 schedule_i
= isl_map_add_dims(schedule_i
, isl_dim_out
,
3822 for (j
= depth
; j
< max_depth
; ++j
)
3823 schedule_i
= isl_map_fix_si(schedule_i
,
3825 schedule
= isl_union_map_add_map(schedule
, schedule_i
);
3831 /* Does expression "expr" write to "id"?
3833 static int expr_writes(struct pet_expr
*expr
, __isl_keep isl_id
*id
)
3838 for (i
= 0; i
< expr
->n_arg
; ++i
) {
3839 int writes
= expr_writes(expr
->args
[i
], id
);
3840 if (writes
< 0 || writes
)
3844 if (expr
->type
!= pet_expr_access
)
3846 if (!expr
->acc
.write
)
3848 if (pet_expr_is_affine(expr
))
3851 write_id
= pet_expr_access_get_id(expr
);
3852 isl_id_free(write_id
);
3857 return write_id
== id
;
3860 /* Does statement "stmt" write to "id"?
3862 static int stmt_writes(struct pet_stmt
*stmt
, __isl_keep isl_id
*id
)
3864 return expr_writes(stmt
->body
, id
);
3867 /* Is there any write access in "scop" that accesses "id"?
3869 int pet_scop_writes(struct pet_scop
*scop
, __isl_keep isl_id
*id
)
3876 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
3877 int writes
= stmt_writes(scop
->stmts
[i
], id
);
3878 if (writes
< 0 || writes
)
3885 /* Add a reference identifier to access expression "expr".
3886 * "user" points to an integer that contains the sequence number
3887 * of the next reference.
3889 static struct pet_expr
*access_add_ref_id(struct pet_expr
*expr
, void *user
)
3898 ctx
= isl_map_get_ctx(expr
->acc
.access
);
3899 snprintf(name
, sizeof(name
), "__pet_ref_%d", (*n_ref
)++);
3900 expr
->acc
.ref_id
= isl_id_alloc(ctx
, name
, NULL
);
3901 if (!expr
->acc
.ref_id
)
3902 return pet_expr_free(expr
);
3907 /* Add a reference identifier to all access expressions in "stmt".
3908 * "n_ref" points to an integer that contains the sequence number
3909 * of the next reference.
3911 static struct pet_stmt
*stmt_add_ref_ids(struct pet_stmt
*stmt
, int *n_ref
)
3918 for (i
= 0; i
< stmt
->n_arg
; ++i
) {
3919 stmt
->args
[i
] = pet_expr_map_access(stmt
->args
[i
],
3920 &access_add_ref_id
, n_ref
);
3922 return pet_stmt_free(stmt
);
3925 stmt
->body
= pet_expr_map_access(stmt
->body
, &access_add_ref_id
, n_ref
);
3927 return pet_stmt_free(stmt
);
3932 /* Add a reference identifier to all access expressions in "scop".
3934 struct pet_scop
*pet_scop_add_ref_ids(struct pet_scop
*scop
)
3943 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
3944 scop
->stmts
[i
] = stmt_add_ref_ids(scop
->stmts
[i
], &n_ref
);
3945 if (!scop
->stmts
[i
])
3946 return pet_scop_free(scop
);
3952 /* Reset the user pointer on all parameter ids in "array".
3954 static struct pet_array
*array_anonymize(struct pet_array
*array
)
3959 array
->context
= isl_set_reset_user(array
->context
);
3960 array
->extent
= isl_set_reset_user(array
->extent
);
3961 if (!array
->context
|| !array
->extent
)
3962 return pet_array_free(array
);
3967 /* Reset the user pointer on all parameter and tuple ids in
3968 * the access relation and the index expressions
3969 * of the access expression "expr".
3971 static struct pet_expr
*access_anonymize(struct pet_expr
*expr
, void *user
)
3973 expr
->acc
.access
= isl_map_reset_user(expr
->acc
.access
);
3974 expr
->acc
.index
= isl_multi_pw_aff_reset_user(expr
->acc
.index
);
3975 if (!expr
->acc
.access
|| !expr
->acc
.index
)
3976 return pet_expr_free(expr
);
3981 /* Reset the user pointer on all parameter and tuple ids in "stmt".
3983 static struct pet_stmt
*stmt_anonymize(struct pet_stmt
*stmt
)
3992 stmt
->domain
= isl_set_reset_user(stmt
->domain
);
3993 stmt
->schedule
= isl_map_reset_user(stmt
->schedule
);
3994 if (!stmt
->domain
|| !stmt
->schedule
)
3995 return pet_stmt_free(stmt
);
3997 for (i
= 0; i
< stmt
->n_arg
; ++i
) {
3998 stmt
->args
[i
] = pet_expr_map_access(stmt
->args
[i
],
3999 &access_anonymize
, NULL
);
4001 return pet_stmt_free(stmt
);
4004 stmt
->body
= pet_expr_map_access(stmt
->body
,
4005 &access_anonymize
, NULL
);
4007 return pet_stmt_free(stmt
);
4012 /* Reset the user pointer on the tuple ids and all parameter ids
4015 static struct pet_implication
*implication_anonymize(
4016 struct pet_implication
*implication
)
4021 implication
->extension
= isl_map_reset_user(implication
->extension
);
4022 if (!implication
->extension
)
4023 return pet_implication_free(implication
);
4028 /* Reset the user pointer on all parameter and tuple ids in "scop".
4030 struct pet_scop
*pet_scop_anonymize(struct pet_scop
*scop
)
4037 scop
->context
= isl_set_reset_user(scop
->context
);
4038 scop
->context_value
= isl_set_reset_user(scop
->context_value
);
4039 if (!scop
->context
|| !scop
->context_value
)
4040 return pet_scop_free(scop
);
4042 for (i
= 0; i
< scop
->n_array
; ++i
) {
4043 scop
->arrays
[i
] = array_anonymize(scop
->arrays
[i
]);
4044 if (!scop
->arrays
[i
])
4045 return pet_scop_free(scop
);
4048 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
4049 scop
->stmts
[i
] = stmt_anonymize(scop
->stmts
[i
]);
4050 if (!scop
->stmts
[i
])
4051 return pet_scop_free(scop
);
4054 for (i
= 0; i
< scop
->n_implication
; ++i
) {
4055 scop
->implications
[i
] =
4056 implication_anonymize(scop
->implications
[i
]);
4057 if (!scop
->implications
[i
])
4058 return pet_scop_free(scop
);
4064 /* If "value_bounds" contains any bounds on the variable accessed by "arg",
4065 * then intersect the range of "map" with the valid set of values.
4067 static __isl_give isl_map
*access_apply_value_bounds(__isl_take isl_map
*map
,
4068 struct pet_expr
*arg
, __isl_keep isl_union_map
*value_bounds
)
4073 isl_ctx
*ctx
= isl_map_get_ctx(map
);
4075 id
= pet_expr_access_get_id(arg
);
4076 space
= isl_space_alloc(ctx
, 0, 0, 1);
4077 space
= isl_space_set_tuple_id(space
, isl_dim_in
, id
);
4078 vb
= isl_union_map_extract_map(value_bounds
, space
);
4079 if (!isl_map_plain_is_empty(vb
))
4080 map
= isl_map_intersect_range(map
, isl_map_range(vb
));
4087 /* Given a set "domain", return a wrapped relation with the given set
4088 * as domain and a range of dimension "n_arg", where each coordinate
4089 * is either unbounded or, if the corresponding element of args is of
4090 * type pet_expr_access, bounded by the bounds specified by "value_bounds".
4092 static __isl_give isl_set
*apply_value_bounds(__isl_take isl_set
*domain
,
4093 unsigned n_arg
, struct pet_expr
**args
,
4094 __isl_keep isl_union_map
*value_bounds
)
4100 map
= isl_map_from_domain(domain
);
4101 space
= isl_map_get_space(map
);
4102 space
= isl_space_add_dims(space
, isl_dim_out
, 1);
4104 for (i
= 0; i
< n_arg
; ++i
) {
4106 struct pet_expr
*arg
= args
[i
];
4108 map_i
= isl_map_universe(isl_space_copy(space
));
4109 if (arg
->type
== pet_expr_access
)
4110 map_i
= access_apply_value_bounds(map_i
, arg
,
4112 map
= isl_map_flat_range_product(map
, map_i
);
4114 isl_space_free(space
);
4116 return isl_map_wrap(map
);
4119 /* Data used in access_gist() callback.
4121 struct pet_access_gist_data
{
4123 isl_union_map
*value_bounds
;
4126 /* Given an expression "expr" of type pet_expr_access, compute
4127 * the gist of the associated access relation and index expression
4128 * with respect to data->domain and the bounds on the values of the arguments
4129 * of the expression.
4131 static struct pet_expr
*access_gist(struct pet_expr
*expr
, void *user
)
4133 struct pet_access_gist_data
*data
= user
;
4136 domain
= isl_set_copy(data
->domain
);
4137 if (expr
->n_arg
> 0)
4138 domain
= apply_value_bounds(domain
, expr
->n_arg
, expr
->args
,
4139 data
->value_bounds
);
4141 expr
->acc
.access
= isl_map_gist_domain(expr
->acc
.access
,
4142 isl_set_copy(domain
));
4143 expr
->acc
.index
= isl_multi_pw_aff_gist(expr
->acc
.index
, domain
);
4144 if (!expr
->acc
.access
|| !expr
->acc
.index
)
4145 return pet_expr_free(expr
);
4150 /* Compute the gist of the iteration domain and all access relations
4151 * of "stmt" based on the constraints on the parameters specified by "context"
4152 * and the constraints on the values of nested accesses specified
4153 * by "value_bounds".
4155 static struct pet_stmt
*stmt_gist(struct pet_stmt
*stmt
,
4156 __isl_keep isl_set
*context
, __isl_keep isl_union_map
*value_bounds
)
4161 struct pet_access_gist_data data
;
4166 data
.domain
= isl_set_copy(stmt
->domain
);
4167 data
.value_bounds
= value_bounds
;
4168 if (stmt
->n_arg
> 0)
4169 data
.domain
= isl_map_domain(isl_set_unwrap(data
.domain
));
4171 data
.domain
= isl_set_intersect_params(data
.domain
,
4172 isl_set_copy(context
));
4174 for (i
= 0; i
< stmt
->n_arg
; ++i
) {
4175 stmt
->args
[i
] = pet_expr_map_access(stmt
->args
[i
],
4176 &access_gist
, &data
);
4181 stmt
->body
= pet_expr_map_access(stmt
->body
, &access_gist
, &data
);
4185 isl_set_free(data
.domain
);
4187 space
= isl_set_get_space(stmt
->domain
);
4188 if (isl_space_is_wrapping(space
))
4189 space
= isl_space_domain(isl_space_unwrap(space
));
4190 domain
= isl_set_universe(space
);
4191 domain
= isl_set_intersect_params(domain
, isl_set_copy(context
));
4192 if (stmt
->n_arg
> 0)
4193 domain
= apply_value_bounds(domain
, stmt
->n_arg
, stmt
->args
,
4195 stmt
->domain
= isl_set_gist(stmt
->domain
, domain
);
4197 return pet_stmt_free(stmt
);
4201 isl_set_free(data
.domain
);
4202 return pet_stmt_free(stmt
);
4205 /* Compute the gist of the extent of the array
4206 * based on the constraints on the parameters specified by "context".
4208 static struct pet_array
*array_gist(struct pet_array
*array
,
4209 __isl_keep isl_set
*context
)
4214 array
->extent
= isl_set_gist_params(array
->extent
,
4215 isl_set_copy(context
));
4217 return pet_array_free(array
);
4222 /* Compute the gist of all sets and relations in "scop"
4223 * based on the constraints on the parameters specified by "scop->context"
4224 * and the constraints on the values of nested accesses specified
4225 * by "value_bounds".
4227 struct pet_scop
*pet_scop_gist(struct pet_scop
*scop
,
4228 __isl_keep isl_union_map
*value_bounds
)
4235 scop
->context
= isl_set_coalesce(scop
->context
);
4237 return pet_scop_free(scop
);
4239 for (i
= 0; i
< scop
->n_array
; ++i
) {
4240 scop
->arrays
[i
] = array_gist(scop
->arrays
[i
], scop
->context
);
4241 if (!scop
->arrays
[i
])
4242 return pet_scop_free(scop
);
4245 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
4246 scop
->stmts
[i
] = stmt_gist(scop
->stmts
[i
], scop
->context
,
4248 if (!scop
->stmts
[i
])
4249 return pet_scop_free(scop
);
4255 /* Intersect the context of "scop" with "context".
4256 * To ensure that we don't introduce any unnamed parameters in
4257 * the context of "scop", we first remove the unnamed parameters
4260 struct pet_scop
*pet_scop_restrict_context(struct pet_scop
*scop
,
4261 __isl_take isl_set
*context
)
4266 context
= set_project_out_unnamed_params(context
);
4267 scop
->context
= isl_set_intersect(scop
->context
, context
);
4269 return pet_scop_free(scop
);
4273 isl_set_free(context
);
4274 return pet_scop_free(scop
);
4277 /* Drop the current context of "scop". That is, replace the context
4278 * by a universal set.
4280 struct pet_scop
*pet_scop_reset_context(struct pet_scop
*scop
)
4287 space
= isl_set_get_space(scop
->context
);
4288 isl_set_free(scop
->context
);
4289 scop
->context
= isl_set_universe(space
);
4291 return pet_scop_free(scop
);
4296 /* Append "array" to the arrays of "scop".
4298 struct pet_scop
*pet_scop_add_array(struct pet_scop
*scop
,
4299 struct pet_array
*array
)
4302 struct pet_array
**arrays
;
4304 if (!array
|| !scop
)
4307 ctx
= isl_set_get_ctx(scop
->context
);
4308 arrays
= isl_realloc_array(ctx
, scop
->arrays
, struct pet_array
*,
4312 scop
->arrays
= arrays
;
4313 scop
->arrays
[scop
->n_array
] = array
;
4318 pet_array_free(array
);
4319 return pet_scop_free(scop
);
4322 /* Create and return an implication on filter values equal to "satisfied"
4323 * with extension "map".
4325 static struct pet_implication
*new_implication(__isl_take isl_map
*map
,
4329 struct pet_implication
*implication
;
4333 ctx
= isl_map_get_ctx(map
);
4334 implication
= isl_alloc_type(ctx
, struct pet_implication
);
4338 implication
->extension
= map
;
4339 implication
->satisfied
= satisfied
;
4347 /* Add an implication on filter values equal to "satisfied"
4348 * with extension "map" to "scop".
4350 struct pet_scop
*pet_scop_add_implication(struct pet_scop
*scop
,
4351 __isl_take isl_map
*map
, int satisfied
)
4354 struct pet_implication
*implication
;
4355 struct pet_implication
**implications
;
4357 implication
= new_implication(map
, satisfied
);
4358 if (!scop
|| !implication
)
4361 ctx
= isl_set_get_ctx(scop
->context
);
4362 implications
= isl_realloc_array(ctx
, scop
->implications
,
4363 struct pet_implication
*,
4364 scop
->n_implication
+ 1);
4367 scop
->implications
= implications
;
4368 scop
->implications
[scop
->n_implication
] = implication
;
4369 scop
->n_implication
++;
4373 pet_implication_free(implication
);
4374 return pet_scop_free(scop
);
4377 /* Given an access expression, check if it is data dependent.
4378 * If so, set *found and abort the search.
4380 static int is_data_dependent(struct pet_expr
*expr
, void *user
)
4392 /* Does "scop" contain any data dependent accesses?
4394 * Check the body of each statement for such accesses.
4396 int pet_scop_has_data_dependent_accesses(struct pet_scop
*scop
)
4404 for (i
= 0; i
< scop
->n_stmt
; ++i
) {
4405 int r
= pet_expr_foreach_access_expr(scop
->stmts
[i
]->body
,
4406 &is_data_dependent
, &found
);
4407 if (r
< 0 && !found
)
4416 /* Does "scop" contain and data dependent conditions?
4418 int pet_scop_has_data_dependent_conditions(struct pet_scop
*scop
)
4425 for (i
= 0; i
< scop
->n_stmt
; ++i
)
4426 if (scop
->stmts
[i
]->n_arg
> 0)
4432 /* Keep track of the "input" file inside the (extended) "scop".
4434 struct pet_scop
*pet_scop_set_input_file(struct pet_scop
*scop
, FILE *input
)
4436 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
4446 /* Print the original code corresponding to "scop" to printer "p".
4448 * pet_scop_print_original can only be called from
4449 * a pet_transform_C_source callback. This means that the input
4450 * file is stored in the extended scop and that the printer prints
4453 __isl_give isl_printer
*pet_scop_print_original(struct pet_scop
*scop
,
4454 __isl_take isl_printer
*p
)
4456 struct pet_scop_ext
*ext
= (struct pet_scop_ext
*) scop
;
4460 return isl_printer_free(p
);
4463 isl_die(isl_printer_get_ctx(p
), isl_error_invalid
,
4464 "no input file stored in scop",
4465 return isl_printer_free(p
));
4467 output
= isl_printer_get_file(p
);
4469 return isl_printer_free(p
);
4471 if (copy(ext
->input
, output
, scop
->start
, scop
->end
) < 0)
4472 return isl_printer_free(p
);