2 * Copyright 2011 Leiden University. All rights reserved.
3 * Copyright 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
45 #include "pet_expr_to_isl_pw_aff.h"
47 /* A pet_context represents the context in which a pet_expr
48 * in converted to an affine expression.
50 * "domain" prescribes the domain of the affine expressions.
52 * "assignments" maps variable names to their currently known values.
53 * Internally, the domains of the values may be equal to some prefix
54 * of the space of "domain", but the domains are updated to be
55 * equal to the space of "domain" before passing them to the user.
57 * If "allow_nested" is set, then the affine expression created
58 * in this context may involve new parameters that encode a pet_expr.
60 * "extracted_affine" caches the results of pet_expr_extract_affine.
61 * It may be NULL if no results have been cached so far and
62 * it is cleared (in pet_context_cow) whenever the context is changed.
68 isl_id_to_pw_aff
*assignments
;
71 pet_expr_to_isl_pw_aff
*extracted_affine
;
74 /* Create a pet_context with the given domain, assignments,
75 * and value for allow_nested.
77 static __isl_give pet_context
*context_alloc(__isl_take isl_set
*domain
,
78 __isl_take isl_id_to_pw_aff
*assignments
, int allow_nested
)
82 if (!domain
|| !assignments
)
85 pc
= isl_calloc_type(isl_set_get_ctx(domain
), struct pet_context
);
91 pc
->assignments
= assignments
;
92 pc
->allow_nested
= allow_nested
;
97 isl_id_to_pw_aff_free(assignments
);
101 /* Create a pet_context with the given domain.
103 * Initially, there are no assigned values and parameters that
104 * encode a pet_expr are not allowed.
106 __isl_give pet_context
*pet_context_alloc(__isl_take isl_set
*domain
)
108 isl_id_to_pw_aff
*assignments
;
113 assignments
= isl_id_to_pw_aff_alloc(isl_set_get_ctx(domain
), 0);
114 return context_alloc(domain
, assignments
, 0);
117 /* Return an independent duplicate of "pc".
119 static __isl_give pet_context
*pet_context_dup(__isl_keep pet_context
*pc
)
126 dup
= context_alloc(isl_set_copy(pc
->domain
),
127 isl_id_to_pw_aff_copy(pc
->assignments
),
133 /* Return a pet_context that is equal to "pc" and that has only one reference.
135 * If "pc" itself only has one reference, then clear the cache of
136 * pet_expr_extract_affine results since the returned pet_context
137 * will be modified and the cached results may no longer be valid
138 * after these modifications.
140 static __isl_give pet_context
*pet_context_cow(__isl_take pet_context
*pc
)
146 pet_expr_to_isl_pw_aff_free(pc
->extracted_affine
);
147 pc
->extracted_affine
= NULL
;
151 return pet_context_dup(pc
);
154 /* Return an extra reference to "pc".
156 __isl_give pet_context
*pet_context_copy(__isl_keep pet_context
*pc
)
165 /* Free a reference to "pc" and return NULL.
167 __isl_null pet_context
*pet_context_free(__isl_take pet_context
*pc
)
174 isl_set_free(pc
->domain
);
175 isl_id_to_pw_aff_free(pc
->assignments
);
176 pet_expr_to_isl_pw_aff_free(pc
->extracted_affine
);
181 /* If an isl_pw_aff corresponding to "expr" has been cached in "pc",
182 * then return a copy of that isl_pw_aff.
183 * Otherwise, return (isl_bool_false, NULL).
185 __isl_give isl_maybe_isl_pw_aff
pet_context_get_extracted_affine(
186 __isl_keep pet_context
*pc
, __isl_keep pet_expr
*expr
)
188 isl_maybe_isl_pw_aff m
= { isl_bool_false
, NULL
};
192 if (!pc
->extracted_affine
)
194 return pet_expr_to_isl_pw_aff_try_get(pc
->extracted_affine
, expr
);
196 m
.valid
= isl_bool_error
;
200 /* Keep track of the fact that "expr" maps to "pa" in "pc".
202 isl_stat
pet_context_set_extracted_affine(__isl_keep pet_context
*pc
,
203 __isl_keep pet_expr
*expr
, __isl_keep isl_pw_aff
*pa
)
206 return isl_stat_error
;
208 if (!pc
->extracted_affine
) {
211 ctx
= pet_context_get_ctx(pc
);
212 pc
->extracted_affine
= pet_expr_to_isl_pw_aff_alloc(ctx
, 1);
215 pc
->extracted_affine
= pet_expr_to_isl_pw_aff_set(pc
->extracted_affine
,
216 pet_expr_copy(expr
), isl_pw_aff_copy(pa
));
217 if (!pc
->extracted_affine
)
218 return isl_stat_error
;
223 /* Return the isl_ctx in which "pc" was created.
225 isl_ctx
*pet_context_get_ctx(__isl_keep pet_context
*pc
)
227 return pc
? isl_set_get_ctx(pc
->domain
) : NULL
;
230 /* Return the domain of "pc".
232 __isl_give isl_set
*pet_context_get_domain(__isl_keep pet_context
*pc
)
236 return isl_set_copy(pc
->domain
);
239 /* Return the domain of "pc" in a form that is suitable
240 * for use as a gist context.
241 * In particular, remove all references to nested expression parameters
242 * so that they do not get introduced in the gisted expression.
244 __isl_give isl_set
*pet_context_get_gist_domain(__isl_keep pet_context
*pc
)
248 domain
= pet_context_get_domain(pc
);
249 domain
= pet_nested_remove_from_set(domain
);
253 /* Return the domain space of "pc".
255 * The domain of "pc" may have constraints involving parameters
256 * that encode a pet_expr. These parameters are not relevant
257 * outside this domain. Furthermore, they need to be resolved
258 * from the final result, so we do not want to propagate them needlessly.
260 __isl_give isl_space
*pet_context_get_space(__isl_keep pet_context
*pc
)
267 space
= isl_set_get_space(pc
->domain
);
268 space
= pet_nested_remove_from_space(space
);
272 /* Return the dimension of the domain space of "pc".
274 unsigned pet_context_dim(__isl_keep pet_context
*pc
)
278 return isl_set_dim(pc
->domain
, isl_dim_set
);
281 /* Return the assignments of "pc".
283 __isl_give isl_id_to_pw_aff
*pet_context_get_assignments(
284 __isl_keep pet_context
*pc
)
288 return isl_id_to_pw_aff_copy(pc
->assignments
);
291 /* Is "id" assigned any value in "pc"?
293 int pet_context_is_assigned(__isl_keep pet_context
*pc
, __isl_keep isl_id
*id
)
297 return isl_id_to_pw_aff_has(pc
->assignments
, id
);
300 /* Return the value assigned to "id" in "pc".
302 * Some dimensions may have been added to pc->domain after the value
303 * associated to "id" was added. We therefore need to adjust the domain
304 * of the stored value to match pc->domain by adding the missing
307 __isl_give isl_pw_aff
*pet_context_get_value(__isl_keep pet_context
*pc
,
308 __isl_take isl_id
*id
)
317 pa
= isl_id_to_pw_aff_get(pc
->assignments
, id
);
318 dim
= isl_pw_aff_dim(pa
, isl_dim_in
);
319 if (dim
== isl_set_dim(pc
->domain
, isl_dim_set
))
322 ma
= pet_prefix_projection(pet_context_get_space(pc
), dim
);
323 pa
= isl_pw_aff_pullback_multi_aff(pa
, ma
);
331 /* Assign the value "value" to "id" in "pc", replacing the previously
332 * assigned value, if any.
334 __isl_give pet_context
*pet_context_set_value(__isl_take pet_context
*pc
,
335 __isl_take isl_id
*id
, isl_pw_aff
*value
)
337 pc
= pet_context_cow(pc
);
340 pc
->assignments
= isl_id_to_pw_aff_set(pc
->assignments
, id
, value
);
341 if (!pc
->assignments
)
342 return pet_context_free(pc
);
346 isl_pw_aff_free(value
);
350 /* Remove any assignment to "id" in "pc".
352 __isl_give pet_context
*pet_context_clear_value(__isl_keep pet_context
*pc
,
353 __isl_take isl_id
*id
)
355 pc
= pet_context_cow(pc
);
358 pc
->assignments
= isl_id_to_pw_aff_drop(pc
->assignments
, id
);
359 if (!pc
->assignments
)
360 return pet_context_free(pc
);
367 /* Are affine expressions created in this context allowed to involve
368 * parameters that encode a pet_expr?
370 int pet_context_allow_nesting(__isl_keep pet_context
*pc
)
374 return pc
->allow_nested
;
377 /* Allow affine expressions created in this context to involve
378 * parameters that encode a pet_expr based on the value of "allow_nested".
380 __isl_give pet_context
*pet_context_set_allow_nested(__isl_take pet_context
*pc
,
385 if (pc
->allow_nested
== allow_nested
)
387 pc
= pet_context_cow(pc
);
390 pc
->allow_nested
= allow_nested
;
394 /* If the access expression "expr" writes to a (non-virtual) scalar,
395 * then remove any assignment to the scalar in "pc".
397 static int clear_write(__isl_keep pet_expr
*expr
, void *user
)
400 pet_context
**pc
= (pet_context
**) user
;
402 if (!pet_expr_access_is_write(expr
))
404 if (!pet_expr_is_scalar_access(expr
))
407 id
= pet_expr_access_get_id(expr
);
408 if (isl_id_get_user(id
))
409 *pc
= pet_context_clear_value(*pc
, id
);
416 /* Look for any writes to scalar variables in "expr" and
417 * remove any assignment to them in "pc".
419 __isl_give pet_context
*pet_context_clear_writes_in_expr(
420 __isl_take pet_context
*pc
, __isl_keep pet_expr
*expr
)
422 if (pet_expr_foreach_access_expr(expr
, &clear_write
, &pc
) < 0)
423 pc
= pet_context_free(pc
);
428 /* Look for any writes to scalar variables in "tree" and
429 * remove any assignment to them in "pc".
431 __isl_give pet_context
*pet_context_clear_writes_in_tree(
432 __isl_take pet_context
*pc
, __isl_keep pet_tree
*tree
)
434 if (pet_tree_foreach_access_expr(tree
, &clear_write
, &pc
) < 0)
435 pc
= pet_context_free(pc
);
440 /* Internal data structure for pet_context_add_parameters.
442 * "pc" is the context that is being updated.
443 * "get_array_size" is a callback function that can be used to determine
444 * the size of the array that is accessed by a given access expression.
445 * "user" is the user data for this callback.
447 struct pet_context_add_parameter_data
{
449 __isl_give pet_expr
*(*get_array_size
)(__isl_keep pet_expr
*access
,
454 /* Given an access expression "expr", add a parameter assignment to data->pc
455 * to the variable being accessed, provided it is a read from an integer
457 * If an array is being accesed, then recursively call the function
458 * on each of the access expressions in the size expression of the array.
460 static int add_parameter(__isl_keep pet_expr
*expr
, void *user
)
462 struct pet_context_add_parameter_data
*data
= user
;
470 if (!pet_expr_is_scalar_access(expr
)) {
471 pet_expr
*size
= data
->get_array_size(expr
, data
->user
);
472 if (pet_expr_foreach_access_expr(size
,
473 &add_parameter
, data
) < 0)
474 data
->pc
= pet_context_free(data
->pc
);
478 if (!pet_expr_access_is_read(expr
))
480 if (pet_expr_get_type_size(expr
) == 0)
483 id
= pet_expr_access_get_id(expr
);
484 if (pet_context_is_assigned(data
->pc
, id
)) {
489 space
= pet_context_get_space(data
->pc
);
490 pos
= isl_space_find_dim_by_id(space
, isl_dim_param
, id
);
492 pos
= isl_space_dim(space
, isl_dim_param
);
493 space
= isl_space_add_dims(space
, isl_dim_param
, 1);
494 space
= isl_space_set_dim_id(space
, isl_dim_param
, pos
,
498 ls
= isl_local_space_from_space(space
);
499 aff
= isl_aff_var_on_domain(ls
, isl_dim_param
, pos
);
500 pa
= isl_pw_aff_from_aff(aff
);
501 data
->pc
= pet_context_set_value(data
->pc
, id
, pa
);
506 /* Add an assignment to "pc" for each parameter in "tree".
507 * "get_array_size" is a callback function that can be used to determine
508 * the size of the array that is accessed by a given access expression.
510 * We initially treat as parameters any integer variable that is read
511 * anywhere in "tree" or in any of the size expressions for any of
512 * the arrays accessed in "tree".
513 * Then we remove from those variables that are written anywhere
516 __isl_give pet_context
*pet_context_add_parameters(__isl_take pet_context
*pc
,
517 __isl_keep pet_tree
*tree
,
518 __isl_give pet_expr
*(*get_array_size
)(__isl_keep pet_expr
*access
,
519 void *user
), void *user
)
521 struct pet_context_add_parameter_data data
;
524 data
.get_array_size
= get_array_size
;
526 if (pet_tree_foreach_access_expr(tree
, &add_parameter
, &data
) < 0)
527 data
.pc
= pet_context_free(data
.pc
);
529 data
.pc
= pet_context_clear_writes_in_tree(data
.pc
, tree
);
534 /* Given an access expression, check if it reads a scalar variable
535 * that has a known value in "pc".
536 * If so, then replace the access by an access to that value.
538 static __isl_give pet_expr
*access_plug_in_affine_read(
539 __isl_take pet_expr
*expr
, void *user
)
541 pet_context
*pc
= user
;
544 if (pet_expr_access_is_write(expr
))
546 if (!pet_expr_is_scalar_access(expr
))
549 pa
= pet_expr_extract_affine(expr
, pc
);
551 return pet_expr_free(expr
);
552 if (isl_pw_aff_involves_nan(pa
)) {
558 expr
= pet_expr_from_index(isl_multi_pw_aff_from_pw_aff(pa
));
563 /* Replace every read access in "expr" to a scalar variable
564 * that has a known value in "pc" by that known value.
566 static __isl_give pet_expr
*plug_in_affine_read(__isl_take pet_expr
*expr
,
567 __isl_keep pet_context
*pc
)
569 return pet_expr_map_access(expr
, &access_plug_in_affine_read
, pc
);
572 /* Add an extra affine expression to "mpa" that is equal to
573 * an extra dimension in the range of the wrapped relation in the domain
574 * of "mpa". "n_arg" is the original number of dimensions in this range.
576 * That is, if "n_arg" is 0, then the input has the form
580 * and the output has the form
582 * [D(i) -> [y]] -> [f(i), y]
584 * If "n_arg" is different from 0, then the input has the form
586 * [D(i) -> [x]] -> [f(i,x)]
588 * with x consisting of "n_arg" dimensions, and the output has the form
590 * [D(i) -> [x,y]] -> [f(i,x), y]
593 * We first adjust the domain of "mpa" and then add the extra
594 * affine expression (y).
596 static __isl_give isl_multi_pw_aff
*add_arg(__isl_take isl_multi_pw_aff
*mpa
,
602 isl_multi_pw_aff
*mpa2
;
605 space
= isl_space_domain(isl_multi_pw_aff_get_space(mpa
));
606 dim
= isl_space_dim(space
, isl_dim_set
);
607 space
= isl_space_from_domain(space
);
608 space
= isl_space_add_dims(space
, isl_dim_set
, 1);
609 ma
= isl_multi_aff_domain_map(space
);
612 isl_space
*dom
, *ran
;
614 space
= isl_space_domain(isl_multi_pw_aff_get_space(mpa
));
615 space
= isl_space_unwrap(space
);
616 dom
= isl_space_domain(isl_space_copy(space
));
617 dim
= isl_space_dim(dom
, isl_dim_set
);
618 ran
= isl_space_range(space
);
619 ran
= isl_space_add_dims(ran
, isl_dim_set
, 1);
620 space
= isl_space_map_from_set(dom
);
621 ma
= isl_multi_aff_identity(space
);
622 ma2
= isl_multi_aff_project_out_map(ran
, isl_dim_set
, n_arg
, 1);
623 ma
= isl_multi_aff_product(ma
, ma2
);
626 mpa
= isl_multi_pw_aff_pullback_multi_aff(mpa
, ma
);
627 space
= isl_space_domain(isl_multi_pw_aff_get_space(mpa
));
628 ma
= isl_multi_aff_project_out_map(space
, isl_dim_set
, 0, dim
+ n_arg
);
629 mpa2
= isl_multi_pw_aff_from_multi_aff(ma
);
630 mpa
= isl_multi_pw_aff_flat_range_product(mpa
, mpa2
);
635 /* Add the integer value from "arg" to "mpa".
637 static __isl_give isl_multi_pw_aff
*add_int(__isl_take isl_multi_pw_aff
*mpa
,
638 __isl_take pet_expr
*arg
)
643 isl_multi_pw_aff
*mpa_arg
;
645 v
= pet_expr_int_get_val(arg
);
648 space
= isl_space_domain(isl_multi_pw_aff_get_space(mpa
));
649 aff
= isl_aff_val_on_domain(isl_local_space_from_space(space
), v
);
650 mpa_arg
= isl_multi_pw_aff_from_pw_aff(isl_pw_aff_from_aff(aff
));
652 mpa
= isl_multi_pw_aff_flat_range_product(mpa
, mpa_arg
);
657 /* Add the affine expression from "arg" to "mpa".
658 * "n_arg" is the number of dimensions in the range of the wrapped
659 * relation in the domain of "mpa".
661 static __isl_give isl_multi_pw_aff
*add_aff(__isl_take isl_multi_pw_aff
*mpa
,
662 int n_arg
, __isl_take pet_expr
*arg
)
664 isl_multi_pw_aff
*mpa_arg
;
666 mpa_arg
= pet_expr_access_get_index(arg
);
673 space
= isl_space_domain(isl_multi_pw_aff_get_space(mpa
));
674 space
= isl_space_unwrap(space
);
675 ma
= isl_multi_aff_domain_map(space
);
676 mpa_arg
= isl_multi_pw_aff_pullback_multi_aff(mpa_arg
, ma
);
679 mpa
= isl_multi_pw_aff_flat_range_product(mpa
, mpa_arg
);
684 /* Combine the index expression of "expr" with the subaccess relation "access".
685 * If "add" is set, then it is not the index expression of "expr" itself
686 * that is passed to the function, but its address.
688 * We call patch_map on each map in "access" and return the combined results.
690 static __isl_give isl_union_map
*patch(__isl_take isl_union_map
*access
,
691 __isl_keep pet_expr
*expr
, int add
)
693 isl_multi_pw_aff
*prefix
;
695 prefix
= pet_expr_access_get_index(expr
);
696 return pet_patch_union_map(prefix
, access
, add
, 1);
699 /* Set the access relations of "expr", which appears in the argument
700 * at position "pos" in a call expression by composing the access
701 * relations in "summary" with the expression "int_arg" of the integer
702 * arguments in terms of the domain and expression arguments of "expr" and
703 * combining the result with the index expression passed to the function.
704 * If "add" is set, then it is not "expr" itself that is passed
705 * to the function, but the address of "expr".
707 * We reset the read an write flag of "expr" and rely on
708 * pet_expr_access_set_access setting the flags based on
709 * the access relations.
711 * After relating each access relation of the called function
712 * to the domain and expression arguments at the call site,
713 * the result is combined with the index expression by the function patch
714 * and then stored in the access expression.
716 static __isl_give pet_expr
*set_access_relations(__isl_take pet_expr
*expr
,
717 __isl_keep pet_function_summary
*summary
, int pos
,
718 __isl_take isl_multi_pw_aff
*int_arg
, int add
)
720 enum pet_expr_access_type type
;
722 expr
= pet_expr_access_set_read(expr
, 0);
723 expr
= pet_expr_access_set_write(expr
, 0);
724 for (type
= pet_expr_access_begin
; type
< pet_expr_access_end
; ++type
) {
725 isl_union_map
*access
;
727 access
= pet_function_summary_arg_get_access(summary
,
729 access
= isl_union_map_preimage_domain_multi_pw_aff(access
,
730 isl_multi_pw_aff_copy(int_arg
));
731 access
= patch(access
, expr
, add
);
732 expr
= pet_expr_access_set_access(expr
, type
, access
);
734 isl_multi_pw_aff_free(int_arg
);
739 /* Set the access relations of "arg", which appears in the argument
740 * at position "pos" in the call expression "call" based on the
741 * information in "summary".
742 * If "add" is set, then it is not "arg" itself that is passed
743 * to the function, but the address of "arg".
745 * We create an affine function "int_arg" that expresses
746 * the integer function call arguments in terms of the domain of "arg"
747 * (i.e., the outer loop iterators) and the expression arguments.
748 * If the actual argument is not an affine expression or if it itself
749 * has expression arguments, then it is added as an argument to "arg" and
750 * "int_arg" is made to reference this additional expression argument.
752 * Finally, we call set_access_relations to plug in the actual arguments
753 * (expressed in "int_arg") into the access relations in "summary" and
754 * to add the resulting access relations to "arg".
756 static __isl_give pet_expr
*access_plug_in_summary(__isl_take pet_expr
*arg
,
757 __isl_keep pet_expr
*call
, __isl_keep pet_function_summary
*summary
,
762 isl_multi_pw_aff
*int_arg
;
765 space
= pet_expr_access_get_augmented_domain_space(arg
);
766 space
= isl_space_from_domain(space
);
767 arg_n_arg
= pet_expr_get_n_arg(arg
);
768 int_arg
= isl_multi_pw_aff_zero(space
);
769 n
= pet_function_summary_get_n_arg(summary
);
770 for (j
= 0; j
< n
; ++j
) {
774 if (!pet_function_summary_arg_is_int(summary
, j
))
777 arg_j
= pet_expr_get_arg(call
, j
);
778 arg_j_n_arg
= pet_expr_get_n_arg(arg_j
);
779 if (pet_expr_get_type(arg_j
) == pet_expr_int
) {
780 int_arg
= add_int(int_arg
, arg_j
);
781 } else if (arg_j_n_arg
!= 0 || !pet_expr_is_affine(arg_j
)) {
782 arg
= pet_expr_insert_arg(arg
, arg_n_arg
,
784 int_arg
= add_arg(int_arg
, arg_n_arg
);
787 int_arg
= add_aff(int_arg
, arg_n_arg
, arg_j
);
790 arg
= set_access_relations(arg
, summary
, pos
, int_arg
, add
);
795 /* Given the argument "arg" at position "pos" of "call",
796 * check if it is either an access expression or the address
797 * of an access expression. If so, use the information in "summary"
798 * to set the access relations of the access expression.
800 static __isl_give pet_expr
*arg_plug_in_summary(__isl_take pet_expr
*arg
,
801 __isl_keep pet_expr
*call
, __isl_keep pet_function_summary
*summary
,
804 enum pet_expr_type type
;
807 type
= pet_expr_get_type(arg
);
808 if (type
== pet_expr_access
)
809 return access_plug_in_summary(arg
, call
, summary
, pos
, 0);
810 if (!pet_expr_is_address_of(arg
))
813 arg2
= pet_expr_get_arg(arg
, 0);
814 if (pet_expr_get_type(arg2
) == pet_expr_access
)
815 arg2
= access_plug_in_summary(arg2
, call
, summary
, pos
, 1);
816 arg
= pet_expr_set_arg(arg
, 0, arg2
);
821 /* Given a call expression, check if the integer arguments can
822 * be represented by affine expressions in the context "pc"
823 * (assuming they are not already affine expressions).
824 * If so, replace these arguments by the corresponding affine expressions.
826 static __isl_give pet_expr
*call_plug_in_affine_args(__isl_take pet_expr
*call
,
827 __isl_keep pet_context
*pc
)
831 n
= pet_expr_get_n_arg(call
);
832 for (i
= 0; i
< n
; ++i
) {
836 arg
= pet_expr_get_arg(call
, i
);
838 return pet_expr_free(call
);
839 if (pet_expr_get_type_size(arg
) == 0 ||
840 pet_expr_is_affine(arg
)) {
845 pa
= pet_expr_extract_affine(arg
, pc
);
848 return pet_expr_free(call
);
849 if (isl_pw_aff_involves_nan(pa
)) {
854 arg
= pet_expr_from_index(isl_multi_pw_aff_from_pw_aff(pa
));
855 call
= pet_expr_set_arg(call
, i
, arg
);
861 /* If "call" has an associated function summary, then use it
862 * to set the access relations of the array arguments of the function call.
864 * We first plug in affine expressions for the integer arguments
865 * whenever possible as these arguments will be plugged in
866 * in the access relations of the array arguments.
868 static __isl_give pet_expr
*call_plug_in_summary(__isl_take pet_expr
*call
,
871 pet_context
*pc
= user
;
872 pet_function_summary
*summary
;
875 if (!pet_expr_call_has_summary(call
))
878 call
= call_plug_in_affine_args(call
, pc
);
880 summary
= pet_expr_call_get_summary(call
);
882 return pet_expr_free(call
);
884 n
= pet_expr_get_n_arg(call
);
885 for (i
= 0; i
< n
; ++i
) {
888 if (!pet_function_summary_arg_is_array(summary
, i
))
891 arg_i
= pet_expr_get_arg(call
, i
);
892 arg_i
= arg_plug_in_summary(arg_i
, call
, summary
, i
);
893 call
= pet_expr_set_arg(call
, i
, arg_i
);
896 pet_function_summary_free(summary
);
900 /* For each call subexpression of "expr", plug in the access relations
901 * from the associated function summary (if any).
903 static __isl_give pet_expr
*plug_in_summaries(__isl_take pet_expr
*expr
,
904 __isl_keep pet_context
*pc
)
906 return pet_expr_map_call(expr
, &call_plug_in_summary
, pc
);
909 /* Given an access expression "expr", check that it is an affine
910 * access expression and set *only_affine to 1.
911 * If "expr" is not an affine access expression, then set *only_affine to 0
914 static int check_only_affine(__isl_keep pet_expr
*expr
, void *user
)
916 int *only_affine
= user
;
919 is_affine
= pet_expr_is_affine(expr
);
931 /* Does "expr" have any affine access subexpression and no other
932 * access subexpressions?
934 * only_affine is initialized to -1 and set to 1 as soon as one affine
935 * access subexpression has been found and to 0 if some other access
936 * subexpression has been found. In this latter case, the search is
939 static isl_bool
has_only_affine_access_sub_expr(__isl_keep pet_expr
*expr
)
941 int only_affine
= -1;
943 if (pet_expr_foreach_access_expr(expr
, &check_only_affine
,
946 return isl_bool_error
;
948 return only_affine
> 0;
951 /* Try and replace "expr" by an affine access expression by essentially
952 * evaluating operations and/or special calls on affine access expressions.
953 * It therefore only makes sense to do this if "expr" is a call or an operation
954 * and if it has at least one affine access subexpression and no other
955 * access subexpressions.
957 static __isl_give pet_expr
*expr_plug_in_affine(__isl_take pet_expr
*expr
,
960 enum pet_expr_type type
;
961 pet_context
*pc
= user
;
963 isl_bool contains_access
;
965 type
= pet_expr_get_type(expr
);
966 if (type
!= pet_expr_call
&& type
!= pet_expr_op
)
968 contains_access
= has_only_affine_access_sub_expr(expr
);
969 if (contains_access
< 0)
970 return pet_expr_free(expr
);
971 if (!contains_access
)
974 pa
= pet_expr_extract_affine(expr
, pc
);
976 return pet_expr_free(expr
);
977 if (isl_pw_aff_involves_nan(pa
)) {
983 expr
= pet_expr_from_index(isl_multi_pw_aff_from_pw_aff(pa
));
988 /* Detect affine subexpressions in "expr".
990 * The detection is performed top-down in order to be able
991 * to exploit the min/max optimization in comparisons.
992 * That is, if some subexpression is of the form max(a,b) <= min(c,d)
993 * and if the affine expressions were being detected bottom-up, then
994 * affine expressions for max(a,b) and min(c,d) would be constructed
995 * first and it would no longer be possible to optimize the extraction
996 * of the comparison as a <= c && a <= d && b <= c && b <= d.
998 static __isl_give pet_expr
*plug_in_affine(__isl_take pet_expr
*expr
,
999 __isl_keep pet_context
*pc
)
1001 return pet_expr_map_top_down(expr
, &expr_plug_in_affine
, pc
);
1004 /* Evaluate "expr" in the context of "pc".
1006 * In particular, we first make sure that all the access expressions
1007 * inside "expr" have the same domain as "pc".
1008 * Then, we plug in affine expressions for scalar reads,
1009 * plug in the arguments of all access expressions in "expr" as well
1010 * as any other affine expressions that may appear inside "expr" and
1011 * plug in the access relations from the summary functions associated
1012 * to call expressions.
1014 __isl_give pet_expr
*pet_context_evaluate_expr(__isl_keep pet_context
*pc
,
1015 __isl_take pet_expr
*expr
)
1017 expr
= pet_expr_insert_domain(expr
, pet_context_get_space(pc
));
1018 expr
= plug_in_affine_read(expr
, pc
);
1019 expr
= pet_expr_plug_in_args(expr
, pc
);
1020 expr
= plug_in_affine(expr
, pc
);
1021 expr
= plug_in_summaries(expr
, pc
);
1025 /* Wrapper around pet_context_evaluate_expr
1026 * for use as a callback to pet_tree_map_expr.
1028 static __isl_give pet_expr
*evaluate_expr(__isl_take pet_expr
*expr
,
1031 pet_context
*pc
= user
;
1033 return pet_context_evaluate_expr(pc
, expr
);
1036 /* Evaluate "tree" in the context of "pc".
1037 * That is, evaluate all the expressions of "tree" in the context of "pc".
1039 __isl_give pet_tree
*pet_context_evaluate_tree(__isl_keep pet_context
*pc
,
1040 __isl_take pet_tree
*tree
)
1042 return pet_tree_map_expr(tree
, &evaluate_expr
, pc
);
1045 /* Add an unbounded inner dimension "id" to pc->domain.
1047 * The assignments are not adjusted here and therefore keep
1048 * their original domain. These domains need to be adjusted before
1049 * these assigned values can be used. This is taken care of by
1050 * pet_context_get_value.
1052 static __isl_give pet_context
*extend_domain(__isl_take pet_context
*pc
,
1053 __isl_take isl_id
*id
)
1057 pc
= pet_context_cow(pc
);
1061 pos
= pet_context_dim(pc
);
1062 pc
->domain
= isl_set_add_dims(pc
->domain
, isl_dim_set
, 1);
1063 pc
->domain
= isl_set_set_dim_id(pc
->domain
, isl_dim_set
, pos
, id
);
1065 return pet_context_free(pc
);
1069 pet_context_free(pc
);
1074 /* Add an unbounded inner iterator "id" to pc->domain.
1075 * Additionally, mark the variable "id" as having the value of this
1076 * new inner iterator.
1078 __isl_give pet_context
*pet_context_add_inner_iterator(
1079 __isl_take pet_context
*pc
, __isl_take isl_id
*id
)
1083 isl_local_space
*ls
;
1090 pos
= pet_context_dim(pc
);
1091 pc
= extend_domain(pc
, isl_id_copy(id
));
1095 space
= pet_context_get_space(pc
);
1096 ls
= isl_local_space_from_space(space
);
1097 aff
= isl_aff_var_on_domain(ls
, isl_dim_set
, pos
);
1098 pa
= isl_pw_aff_from_aff(aff
);
1100 pc
= pet_context_set_value(pc
, id
, pa
);
1104 pet_context_free(pc
);
1109 /* Add an inner iterator to pc->domain.
1110 * In particular, extend the domain with an inner loop { [t] : t >= 0 }.
1112 __isl_give pet_context
*pet_context_add_infinite_loop(
1113 __isl_take pet_context
*pc
)
1122 dim
= pet_context_dim(pc
);
1123 ctx
= pet_context_get_ctx(pc
);
1124 id
= isl_id_alloc(ctx
, "t", NULL
);
1125 pc
= extend_domain(pc
, id
);
1126 pc
= pet_context_cow(pc
);
1129 pc
->domain
= isl_set_lower_bound_si(pc
->domain
, isl_dim_set
, dim
, 0);
1131 return pet_context_free(pc
);
1136 /* Internal data structure for preimage_domain.
1138 * "ma" is the function under which the preimage should be computed.
1139 * "assignments" collects the results.
1141 struct pet_preimage_domain_data
{
1143 isl_id_to_pw_aff
*assignments
;
1146 /* Add the assignment to "key" of the preimage of "val" under data->ma
1147 * to data->assignments.
1149 * Some dimensions may have been added to the domain of the enclosing
1150 * pet_context after the value "val" was added. We therefore need to
1151 * adjust the domain of "val" to match the range of data->ma (which
1152 * in turn matches the domain of the pet_context), by adding the missing
1155 static isl_stat
preimage_domain_pair(__isl_take isl_id
*key
,
1156 __isl_take isl_pw_aff
*val
, void *user
)
1158 struct pet_preimage_domain_data
*data
= user
;
1162 ma
= isl_multi_aff_copy(data
->ma
);
1164 dim
= isl_pw_aff_dim(val
, isl_dim_in
);
1165 if (dim
!= isl_multi_aff_dim(data
->ma
, isl_dim_out
)) {
1167 isl_multi_aff
*proj
;
1168 space
= isl_multi_aff_get_space(data
->ma
);
1169 space
= isl_space_range(space
);
1170 proj
= pet_prefix_projection(space
, dim
);
1171 ma
= isl_multi_aff_pullback_multi_aff(proj
, ma
);
1174 val
= isl_pw_aff_pullback_multi_aff(val
, ma
);
1175 data
->assignments
= isl_id_to_pw_aff_set(data
->assignments
, key
, val
);
1180 /* Compute the preimage of "assignments" under the function represented by "ma".
1181 * In other words, plug in "ma" in the domains of the assigned values.
1183 static __isl_give isl_id_to_pw_aff
*preimage_domain(
1184 __isl_take isl_id_to_pw_aff
*assignments
, __isl_keep isl_multi_aff
*ma
)
1186 struct pet_preimage_domain_data data
= { ma
};
1189 ctx
= isl_id_to_pw_aff_get_ctx(assignments
);
1190 data
.assignments
= isl_id_to_pw_aff_alloc(ctx
, 0);
1191 if (isl_id_to_pw_aff_foreach(assignments
, &preimage_domain_pair
,
1193 data
.assignments
= isl_id_to_pw_aff_free(data
.assignments
);
1194 isl_id_to_pw_aff_free(assignments
);
1196 return data
.assignments
;
1199 /* Compute the preimage of "pc" under the function represented by "ma".
1200 * In other words, plug in "ma" in the domain of "pc".
1202 __isl_give pet_context
*pet_context_preimage_domain(__isl_take pet_context
*pc
,
1203 __isl_keep isl_multi_aff
*ma
)
1205 pc
= pet_context_cow(pc
);
1208 pc
->domain
= isl_set_preimage_multi_aff(pc
->domain
,
1209 isl_multi_aff_copy(ma
));
1210 pc
->assignments
= preimage_domain(pc
->assignments
, ma
);
1211 if (!pc
->domain
|| !pc
->assignments
)
1212 return pet_context_free(pc
);
1216 /* Add the constraints of "set" to the domain of "pc".
1218 __isl_give pet_context
*pet_context_intersect_domain(__isl_take pet_context
*pc
,
1219 __isl_take isl_set
*set
)
1221 pc
= pet_context_cow(pc
);
1224 pc
->domain
= isl_set_intersect(pc
->domain
, set
);
1226 return pet_context_free(pc
);
1229 pet_context_free(pc
);
1234 void pet_context_dump(__isl_keep pet_context
*pc
)
1238 fprintf(stderr
, "domain: ");
1239 isl_set_dump(pc
->domain
);
1240 fprintf(stderr
, "assignments: ");
1241 isl_id_to_pw_aff_dump(pc
->assignments
);
1242 fprintf(stderr
, "nesting allowed: %d\n", pc
->allow_nested
);