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 /* A pet_context represents the context in which a pet_expr
46 * in converted to an affine expression.
48 * "domain" prescribes the domain of the affine expressions.
50 * "assignments" maps variable names to their currently known values.
51 * Internally, the domains of the values may be equal to some prefix
52 * of the space of "domain", but the domains are updated to be
53 * equal to the space of "domain" before passing them to the user.
55 * If "allow_nested" is set, then the affine expression created
56 * in this context may involve new parameters that encode a pet_expr.
62 isl_id_to_pw_aff
*assignments
;
66 /* Create a pet_context with the given domain, assignments,
67 * and value for allow_nested.
69 static __isl_give pet_context
*context_alloc(__isl_take isl_set
*domain
,
70 __isl_take isl_id_to_pw_aff
*assignments
, int allow_nested
)
74 if (!domain
|| !assignments
)
77 pc
= isl_calloc_type(isl_set_get_ctx(domain
), struct pet_context
);
83 pc
->assignments
= assignments
;
84 pc
->allow_nested
= allow_nested
;
89 isl_id_to_pw_aff_free(assignments
);
93 /* Create a pet_context with the given domain.
95 * Initially, there are no assigned values and parameters that
96 * encode a pet_expr are not allowed.
98 __isl_give pet_context
*pet_context_alloc(__isl_take isl_set
*domain
)
100 isl_id_to_pw_aff
*assignments
;
105 assignments
= isl_id_to_pw_aff_alloc(isl_set_get_ctx(domain
), 0);;
106 return context_alloc(domain
, assignments
, 0);
109 /* Return an independent duplicate of "pc".
111 static __isl_give pet_context
*pet_context_dup(__isl_keep pet_context
*pc
)
118 dup
= context_alloc(isl_set_copy(pc
->domain
),
119 isl_id_to_pw_aff_copy(pc
->assignments
),
125 /* Return a pet_context that is equal to "pc" and that has only one reference.
127 static __isl_give pet_context
*pet_context_cow(__isl_take pet_context
*pc
)
135 return pet_context_dup(pc
);
138 /* Return an extra reference to "pc".
140 __isl_give pet_context
*pet_context_copy(__isl_keep pet_context
*pc
)
149 /* Free a reference to "pc" and return NULL.
151 __isl_null pet_context
*pet_context_free(__isl_take pet_context
*pc
)
158 isl_set_free(pc
->domain
);
159 isl_id_to_pw_aff_free(pc
->assignments
);
164 /* Return the isl_ctx in which "pc" was created.
166 isl_ctx
*pet_context_get_ctx(__isl_keep pet_context
*pc
)
168 return pc
? isl_set_get_ctx(pc
->domain
) : NULL
;
171 /* Return the domain of "pc".
173 __isl_give isl_set
*pet_context_get_domain(__isl_keep pet_context
*pc
)
177 return isl_set_copy(pc
->domain
);
180 /* Return the domain of "pc" in a form that is suitable
181 * for use as a gist context.
182 * In particular, remove all references to nested expression parameters
183 * so that they do not get introduced in the gisted expression.
185 __isl_give isl_set
*pet_context_get_gist_domain(__isl_keep pet_context
*pc
)
189 domain
= pet_context_get_domain(pc
);
190 domain
= pet_nested_remove_from_set(domain
);
194 /* Return the domain space of "pc".
196 * The domain of "pc" may have constraints involving parameters
197 * that encode a pet_expr. These parameters are not relevant
198 * outside this domain. Furthermore, they need to be resolved
199 * from the final result, so we do not want to propagate them needlessly.
201 __isl_give isl_space
*pet_context_get_space(__isl_keep pet_context
*pc
)
208 space
= isl_set_get_space(pc
->domain
);
209 space
= pet_nested_remove_from_space(space
);
213 /* Return the dimension of the domain space of "pc".
215 unsigned pet_context_dim(__isl_keep pet_context
*pc
)
219 return isl_set_dim(pc
->domain
, isl_dim_set
);
222 /* Return the assignments of "pc".
224 __isl_give isl_id_to_pw_aff
*pet_context_get_assignments(
225 __isl_keep pet_context
*pc
)
229 return isl_id_to_pw_aff_copy(pc
->assignments
);
232 /* Is "id" assigned any value in "pc"?
234 int pet_context_is_assigned(__isl_keep pet_context
*pc
, __isl_keep isl_id
*id
)
238 return isl_id_to_pw_aff_has(pc
->assignments
, id
);
241 /* Return the value assigned to "id" in "pc".
243 * Some dimensions may have been added to pc->domain after the value
244 * associated to "id" was added. We therefore need to adjust the domain
245 * of the stored value to match pc->domain by adding the missing
248 __isl_give isl_pw_aff
*pet_context_get_value(__isl_keep pet_context
*pc
,
249 __isl_take isl_id
*id
)
258 pa
= isl_id_to_pw_aff_get(pc
->assignments
, id
);
259 dim
= isl_pw_aff_dim(pa
, isl_dim_in
);
260 if (dim
== isl_set_dim(pc
->domain
, isl_dim_set
))
263 ma
= pet_prefix_projection(pet_context_get_space(pc
), dim
);
264 pa
= isl_pw_aff_pullback_multi_aff(pa
, ma
);
272 /* Assign the value "value" to "id" in "pc", replacing the previously
273 * assigned value, if any.
275 __isl_give pet_context
*pet_context_set_value(__isl_take pet_context
*pc
,
276 __isl_take isl_id
*id
, isl_pw_aff
*value
)
278 pc
= pet_context_cow(pc
);
281 pc
->assignments
= isl_id_to_pw_aff_set(pc
->assignments
, id
, value
);
282 if (!pc
->assignments
)
283 return pet_context_free(pc
);
287 isl_pw_aff_free(value
);
291 /* Remove any assignment to "id" in "pc".
293 __isl_give pet_context
*pet_context_clear_value(__isl_keep pet_context
*pc
,
294 __isl_take isl_id
*id
)
296 pc
= pet_context_cow(pc
);
299 pc
->assignments
= isl_id_to_pw_aff_drop(pc
->assignments
, id
);
300 if (!pc
->assignments
)
301 return pet_context_free(pc
);
308 /* Are affine expressions created in this context allowed to involve
309 * parameters that encode a pet_expr?
311 int pet_context_allow_nesting(__isl_keep pet_context
*pc
)
315 return pc
->allow_nested
;
318 /* Allow affine expressions created in this context to involve
319 * parameters that encode a pet_expr based on the value of "allow_nested".
321 __isl_give pet_context
*pet_context_set_allow_nested(__isl_take pet_context
*pc
,
326 if (pc
->allow_nested
== allow_nested
)
328 pc
= pet_context_cow(pc
);
331 pc
->allow_nested
= allow_nested
;
335 /* If the access expression "expr" writes to a (non-virtual) scalar,
336 * then remove any assignment to the scalar in "pc".
338 static int clear_write(__isl_keep pet_expr
*expr
, void *user
)
341 pet_context
**pc
= (pet_context
**) user
;
343 if (!pet_expr_access_is_write(expr
))
345 if (!pet_expr_is_scalar_access(expr
))
348 id
= pet_expr_access_get_id(expr
);
349 if (isl_id_get_user(id
))
350 *pc
= pet_context_clear_value(*pc
, id
);
357 /* Look for any writes to scalar variables in "expr" and
358 * remove any assignment to them in "pc".
360 __isl_give pet_context
*pet_context_clear_writes_in_expr(
361 __isl_take pet_context
*pc
, __isl_keep pet_expr
*expr
)
363 if (pet_expr_foreach_access_expr(expr
, &clear_write
, &pc
) < 0)
364 pc
= pet_context_free(pc
);
369 /* Look for any writes to scalar variables in "tree" and
370 * remove any assignment to them in "pc".
372 __isl_give pet_context
*pet_context_clear_writes_in_tree(
373 __isl_take pet_context
*pc
, __isl_keep pet_tree
*tree
)
375 if (pet_tree_foreach_access_expr(tree
, &clear_write
, &pc
) < 0)
376 pc
= pet_context_free(pc
);
381 /* Internal data structure for pet_context_add_parameters.
383 * "pc" is the context that is being updated.
384 * "get_array_size" is a callback function that can be used to determine
385 * the size of the array that is accessed by a given access expression.
386 * "user" is the user data for this callback.
388 struct pet_context_add_parameter_data
{
390 __isl_give pet_expr
*(*get_array_size
)(__isl_keep pet_expr
*access
,
395 /* Given an access expression "expr", add a parameter assignment to data->pc
396 * to the variable being accessed, provided it is a read from an integer
398 * If an array is being accesed, then recursively call the function
399 * on each of the access expressions in the size expression of the array.
401 static int add_parameter(__isl_keep pet_expr
*expr
, void *user
)
403 struct pet_context_add_parameter_data
*data
= user
;
411 if (!pet_expr_is_scalar_access(expr
)) {
412 pet_expr
*size
= data
->get_array_size(expr
, data
->user
);
413 if (pet_expr_foreach_access_expr(size
,
414 &add_parameter
, data
) < 0)
415 data
->pc
= pet_context_free(data
->pc
);
419 if (!pet_expr_access_is_read(expr
))
421 if (pet_expr_get_type_size(expr
) == 0)
424 id
= pet_expr_access_get_id(expr
);
425 if (pet_context_is_assigned(data
->pc
, id
)) {
430 space
= pet_context_get_space(data
->pc
);
431 pos
= isl_space_find_dim_by_id(space
, isl_dim_param
, id
);
433 pos
= isl_space_dim(space
, isl_dim_param
);
434 space
= isl_space_add_dims(space
, isl_dim_param
, 1);
435 space
= isl_space_set_dim_id(space
, isl_dim_param
, pos
,
439 ls
= isl_local_space_from_space(space
);
440 aff
= isl_aff_var_on_domain(ls
, isl_dim_param
, pos
);
441 pa
= isl_pw_aff_from_aff(aff
);
442 data
->pc
= pet_context_set_value(data
->pc
, id
, pa
);
447 /* Add an assignment to "pc" for each parameter in "tree".
448 * "get_array_size" is a callback function that can be used to determine
449 * the size of the array that is accessed by a given access expression.
451 * We initially treat as parameters any integer variable that is read
452 * anywhere in "tree" or in any of the size expressions for any of
453 * the arrays accessed in "tree".
454 * Then we remove from those variables that are written anywhere
457 __isl_give pet_context
*pet_context_add_parameters(__isl_take pet_context
*pc
,
458 __isl_keep pet_tree
*tree
,
459 __isl_give pet_expr
*(*get_array_size
)(__isl_keep pet_expr
*access
,
460 void *user
), void *user
)
462 struct pet_context_add_parameter_data data
;
465 data
.get_array_size
= get_array_size
;
467 if (pet_tree_foreach_access_expr(tree
, &add_parameter
, &data
) < 0)
468 data
.pc
= pet_context_free(data
.pc
);
470 data
.pc
= pet_context_clear_writes_in_tree(data
.pc
, tree
);
475 /* Given an access expression, check if it reads a scalar variable
476 * that has a known value in "pc".
477 * If so, then replace the access by an access to that value.
479 static __isl_give pet_expr
*access_plug_in_affine_read(
480 __isl_take pet_expr
*expr
, void *user
)
482 pet_context
*pc
= user
;
485 if (pet_expr_access_is_write(expr
))
487 if (!pet_expr_is_scalar_access(expr
))
490 pa
= pet_expr_extract_affine(expr
, pc
);
492 return pet_expr_free(expr
);
493 if (isl_pw_aff_involves_nan(pa
)) {
499 expr
= pet_expr_from_index(isl_multi_pw_aff_from_pw_aff(pa
));
504 /* Replace every read access in "expr" to a scalar variable
505 * that has a known value in "pc" by that known value.
507 static __isl_give pet_expr
*plug_in_affine_read(__isl_take pet_expr
*expr
,
508 __isl_keep pet_context
*pc
)
510 return pet_expr_map_access(expr
, &access_plug_in_affine_read
, pc
);
513 /* Add an extra affine expression to "mpa" that is equal to
514 * an extra dimension in the range of the wrapped relation in the domain
515 * of "mpa". "n_arg" is the original number of dimensions in this range.
517 * That is, if "n_arg" is 0, then the input has the form
521 * and the output has the form
523 * [D(i) -> [y]] -> [f(i), y]
525 * If "n_arg" is different from 0, then the input has the form
527 * [D(i) -> [x]] -> [f(i,x)]
529 * with x consisting of "n_arg" dimensions, and the output has the form
531 * [D(i) -> [x,y]] -> [f(i,x), y]
534 * We first adjust the domain of "mpa" and then add the extra
535 * affine expression (y).
537 static __isl_give isl_multi_pw_aff
*add_arg(__isl_take isl_multi_pw_aff
*mpa
,
543 isl_multi_pw_aff
*mpa2
;
546 space
= isl_space_domain(isl_multi_pw_aff_get_space(mpa
));
547 dim
= isl_space_dim(space
, isl_dim_set
);
548 space
= isl_space_from_domain(space
);
549 space
= isl_space_add_dims(space
, isl_dim_set
, 1);
550 ma
= isl_multi_aff_domain_map(space
);
553 isl_space
*dom
, *ran
;
555 space
= isl_space_domain(isl_multi_pw_aff_get_space(mpa
));
556 space
= isl_space_unwrap(space
);
557 dom
= isl_space_domain(isl_space_copy(space
));
558 dim
= isl_space_dim(dom
, isl_dim_set
);
559 ran
= isl_space_range(space
);
560 ran
= isl_space_add_dims(ran
, isl_dim_set
, 1);
561 space
= isl_space_map_from_set(dom
);
562 ma
= isl_multi_aff_identity(space
);
563 ma2
= isl_multi_aff_project_out_map(ran
, isl_dim_set
, n_arg
, 1);
564 ma
= isl_multi_aff_product(ma
, ma2
);
567 mpa
= isl_multi_pw_aff_pullback_multi_aff(mpa
, ma
);
568 space
= isl_space_domain(isl_multi_pw_aff_get_space(mpa
));
569 ma
= isl_multi_aff_project_out_map(space
, isl_dim_set
, 0, dim
+ n_arg
);
570 mpa2
= isl_multi_pw_aff_from_multi_aff(ma
);
571 mpa
= isl_multi_pw_aff_flat_range_product(mpa
, mpa2
);
576 /* Add the integer value from "arg" to "mpa".
578 static __isl_give isl_multi_pw_aff
*add_int(__isl_take isl_multi_pw_aff
*mpa
,
579 __isl_take pet_expr
*arg
)
584 isl_multi_pw_aff
*mpa_arg
;
586 v
= pet_expr_int_get_val(arg
);
589 space
= isl_space_domain(isl_multi_pw_aff_get_space(mpa
));
590 aff
= isl_aff_val_on_domain(isl_local_space_from_space(space
), v
);
591 mpa_arg
= isl_multi_pw_aff_from_pw_aff(isl_pw_aff_from_aff(aff
));
593 mpa
= isl_multi_pw_aff_flat_range_product(mpa
, mpa_arg
);
598 /* Add the affine expression from "arg" to "mpa".
599 * "n_arg" is the number of dimensions in the range of the wrapped
600 * relation in the domain of "mpa".
602 static __isl_give isl_multi_pw_aff
*add_aff(__isl_take isl_multi_pw_aff
*mpa
,
603 int n_arg
, __isl_take pet_expr
*arg
)
605 isl_multi_pw_aff
*mpa_arg
;
607 mpa_arg
= pet_expr_access_get_index(arg
);
614 space
= isl_space_domain(isl_multi_pw_aff_get_space(mpa
));
615 space
= isl_space_unwrap(space
);
616 ma
= isl_multi_aff_domain_map(space
);
617 mpa_arg
= isl_multi_pw_aff_pullback_multi_aff(mpa_arg
, ma
);
620 mpa
= isl_multi_pw_aff_flat_range_product(mpa
, mpa_arg
);
625 /* Given the data space "space1" of an index expression passed
626 * to a function and the data space "space2" of the corresponding
627 * array accessed in the function, construct and return the complete
628 * data space from the perspective of the function call.
629 * If add is set, then it is not the index expression with space "space1" itself
630 * that is passed to the function, but its address.
632 * In the simplest case, no member accesses are involved and "add" is not set.
633 * Let "space1" be of the form A[x] and "space2" of the form B[y].
634 * Then the returned space is A[x,y].
635 * That is, the dimension is the sum of the dimensions and the name
636 * is that of "space1".
637 * If "add" is set, then the final dimension of "space1" is the same
638 * as the initial dimension of "space2" and the dimension of the result
639 * is one less that the sum. This also applies when the dimension
640 * of "space1" is zero. The dimension of "space2" can never be zero
641 * when "add" is set since a pointer value is passed to the function,
642 * which is treated as an array of dimension at least 1.
644 * If "space1" involves any member accesses, then it is the innermost
645 * array space of "space1" that needs to be extended with "space2".
646 * This innermost array space appears in the range of the wrapped
647 * relation in "space1".
649 * If "space2" involves any member accesses, then it is the outermost
650 * array space of "space2" that needs to be combined with innermost
651 * array space of "space1". This outermost array space appears
652 * in the deepest nesting of the domains and is therefore handled
655 * For example, if "space1" is of the form
659 * and "space2" is of the form
661 * d_b_c[d_b[d[z] -> b[u]] -> c[v]]
663 * then the resulting space is
665 * s_a_b_c[s_a_b[s_a[s[x] -> a[y,z]] -> b[u]] -> c[v]]
667 static __isl_give isl_space
*patch_space(__isl_take isl_space
*space1
,
668 __isl_take isl_space
*space2
, int add
)
673 if (!space1
|| !space2
)
676 if (isl_space_is_wrapping(space2
)) {
679 const char *name1
, *name2
;
682 ctx
= isl_space_get_ctx(space1
);
683 space2
= isl_space_unwrap(space2
);
684 dom
= isl_space_domain(isl_space_copy(space2
));
685 space1
= patch_space(space1
, dom
, add
);
686 space2
= isl_space_range(space2
);
687 name1
= isl_space_get_tuple_name(space1
, isl_dim_set
);
688 name2
= isl_space_get_tuple_name(space2
, isl_dim_set
);
689 name
= pet_array_member_access_name(ctx
, name1
, name2
);
690 space1
= isl_space_product(space1
, space2
);
691 space1
= isl_space_set_tuple_name(space1
, isl_dim_set
, name
);
696 dim
= isl_space_dim(space2
, isl_dim_set
) - add
;
697 id
= isl_space_get_tuple_id(space1
, isl_dim_set
);
698 if (isl_space_is_wrapping(space1
)) {
701 space1
= isl_space_unwrap(space1
);
702 id
= isl_space_get_tuple_id(space1
, isl_dim_out
);
703 space1
= isl_space_add_dims(space1
, isl_dim_out
, dim
);
704 space1
= isl_space_set_tuple_id(space1
, isl_dim_out
, id
);
705 space1
= isl_space_wrap(space1
);
707 space1
= isl_space_add_dims(space1
, isl_dim_out
, dim
);
709 space1
= isl_space_set_tuple_id(space1
, isl_dim_set
, id
);
711 isl_space_free(space2
);
714 isl_space_free(space1
);
715 isl_space_free(space2
);
719 /* Drop the initial dimension of "map", assuming that it is equal to zero.
720 * If it turns out not to be equal to zero, then drop the initial dimension
721 * of "map" after setting the value to zero and print a warning.
723 static __isl_give isl_map
*drop_initial_zero(__isl_take isl_map
*map
,
724 __isl_keep isl_map
*prefix
)
728 zeroed
= isl_map_copy(map
);
729 zeroed
= isl_map_fix_si(zeroed
, isl_dim_out
, 0, 0);
730 map
= isl_map_subtract(map
, isl_map_copy(zeroed
));
731 if (!isl_map_is_empty(map
)) {
732 fprintf(stderr
, "possible out-of-bounds accesses\n");
734 fprintf(stderr
, "when passing\n");
735 isl_map_dump(prefix
);
739 map
= isl_map_project_out(map
, isl_dim_out
, 0, 1);
743 /* Given an identity mapping "id" that adds structure to
744 * the range of "map" with dimensions "pos" and "pos + 1" replaced
745 * by their sum, adjust "id" to apply to the range of "map" directly.
748 * [i_0, ..., i_pos, i_{pos+1}, i_{pos+2}, ...] ->
749 * [i_0, ..., i_pos + i_{pos+1}, i_{pos+2}, ...]
751 * in "id", where the domain of this mapping corresponds to the range
752 * of "map" and the range of this mapping corresponds to the original
755 static __isl_give isl_map
*patch_map_add(__isl_take isl_map
*id
,
756 __isl_keep isl_map
*map
, int pos
)
760 isl_aff
*aff1
, *aff2
;
762 space
= isl_space_range(isl_map_get_space(map
));
763 ma
= isl_multi_aff_identity(isl_space_map_from_set(space
));
764 aff1
= isl_multi_aff_get_aff(ma
, pos
);
765 aff2
= isl_multi_aff_get_aff(ma
, pos
+ 1);
766 aff1
= isl_aff_add(aff1
, aff2
);
767 ma
= isl_multi_aff_set_aff(ma
, pos
, aff1
);
768 ma
= isl_multi_aff_drop_dims(ma
, isl_dim_out
, pos
+ 1, 1);
769 id
= isl_map_preimage_domain_multi_aff(id
, ma
);
774 /* Return the dimension of the innermost array in the data space "space".
775 * If "space" is not a wrapping space, the it does not involve any
776 * member accesses and the innermost array is simply the accessed
778 * Otherwise, the innermost array is encoded in the range of the
781 static int innermost_dim(__isl_keep isl_space
*space
)
785 if (!isl_space_is_wrapping(space
))
786 return isl_space_dim(space
, isl_dim_set
);
788 space
= isl_space_copy(space
);
789 space
= isl_space_unwrap(space
);
790 dim
= isl_space_dim(space
, isl_dim_out
);
791 isl_space_free(space
);
796 /* Internal data structure for patch_map.
798 * "prefix" is the index expression passed to the function
799 * "add" is set if it is the address of "prefix" that is passed to the function.
800 * "res" collects the results.
802 struct pet_patch_map_data
{
809 /* Combine the index expression data->prefix with the subaccess relation "map".
810 * If data->add is set, then it is not the index expression data->prefix itself
811 * that is passed to the function, but its address.
813 * If data->add is not set, then we essentially need to concatenate
814 * data->prefix with map, except that we need to make sure that
815 * the target space is set correctly. This target space is computed
816 * by the function patch_space. We then simply compute the flat
817 * range product and subsequently reset the target space.
819 * If data->add is set then the outer dimension of "map" is an offset
820 * with respect to the inner dimension of data->prefix and we therefore
821 * need to add these two dimensions rather than simply concatenating them.
822 * This computation is performed in patch_map_add.
823 * If however, the innermost accessed array of data->prefix is
824 * zero-dimensional, then there is no innermost dimension of data->prefix
825 * to add to the outermost dimension of "map", Instead, we are passing
826 * a pointer to a scalar member, meaning that the outermost dimension
827 * of "map" needs to be zero and that this zero needs to be removed
828 * from the concatenation. This computation is performed in drop_initial_zero.
830 static int patch_map(__isl_take isl_map
*map
, void *user
)
832 struct pet_patch_map_data
*data
= user
;
837 space
= isl_space_range(isl_map_get_space(data
->prefix
));
838 dim
= innermost_dim(space
);
839 pos
= isl_space_dim(space
, isl_dim_set
) - dim
;
840 space
= patch_space(space
, isl_space_range(isl_map_get_space(map
)),
842 if (data
->add
&& dim
== 0)
843 map
= drop_initial_zero(map
, data
->prefix
);
844 map
= isl_map_flat_range_product(isl_map_copy(data
->prefix
), map
);
845 space
= isl_space_map_from_set(space
);
846 space
= isl_space_add_dims(space
, isl_dim_in
, 0);
847 id
= isl_map_identity(space
);
848 if (data
->add
&& dim
!= 0)
849 id
= patch_map_add(id
, map
, pos
+ dim
- 1);
850 map
= isl_map_apply_range(map
, id
);
851 data
->res
= isl_union_map_add_map(data
->res
, map
);
856 /* Combine the index expression of "expr" with the subaccess relation "access".
857 * If "add" is set, then it is not the index expression of "expr" itself
858 * that is passed to the function, but its address.
860 * We call patch_map on each map in "access" and return the combined results.
862 static __isl_give isl_union_map
*patch(__isl_take isl_union_map
*access
,
863 __isl_keep pet_expr
*expr
, int add
)
865 struct pet_patch_map_data data
;
868 map
= isl_map_from_multi_pw_aff(pet_expr_access_get_index(expr
));
871 data
.res
= isl_union_map_empty(isl_union_map_get_space(access
));
872 if (isl_union_map_foreach_map(access
, &patch_map
, &data
) < 0)
873 data
.res
= isl_union_map_free(data
.res
);
874 isl_union_map_free(access
);
875 isl_map_free(data
.prefix
);
880 /* Set the access relations of "expr", which appears in the argument
881 * at position "pos" in a call expression by composing the access
882 * relations in "summary" with the expression "int_arg" of the integer
883 * arguments in terms of the domain and expression arguments of "expr" and
884 * combining the result with the index expression passed to the function.
885 * If "add" is set, then it is not "expr" itself that is passed
886 * to the function, but the address of "expr".
888 * We reset the read an write flag of "expr" and rely on
889 * pet_expr_access_set_access setting the flags based on
890 * the access relations.
892 * After relating each access relation of the called function
893 * to the domain and expression arguments at the call site,
894 * the result is combined with the index expression by the function patch
895 * and then stored in the access expression.
897 static __isl_give pet_expr
*set_access_relations(__isl_take pet_expr
*expr
,
898 __isl_keep pet_function_summary
*summary
, int pos
,
899 __isl_take isl_multi_pw_aff
*int_arg
, int add
)
901 enum pet_expr_access_type type
;
903 expr
= pet_expr_access_set_read(expr
, 0);
904 expr
= pet_expr_access_set_write(expr
, 0);
905 for (type
= pet_expr_access_begin
; type
< pet_expr_access_end
; ++type
) {
906 isl_union_map
*access
;
908 access
= pet_function_summary_arg_get_access(summary
,
910 access
= isl_union_map_preimage_domain_multi_pw_aff(access
,
911 isl_multi_pw_aff_copy(int_arg
));
912 access
= patch(access
, expr
, add
);
913 expr
= pet_expr_access_set_access(expr
, type
, access
);
915 isl_multi_pw_aff_free(int_arg
);
920 /* Set the access relations of "arg", which appears in the argument
921 * at position "pos" in the call expression "call" based on the
922 * information in "summary".
923 * If "add" is set, then it is not "arg" itself that is passed
924 * to the function, but the address of "arg".
926 * We create an affine function "int_arg" that expresses
927 * the integer function call arguments in terms of the domain of "arg"
928 * (i.e., the outer loop iterators) and the expression arguments.
929 * If the actual argument is not an affine expression or if it itself
930 * has expression arguments, then it is added as an argument to "arg" and
931 * "int_arg" is made to reference this additional expression argument.
933 * Finally, we call set_access_relations to plug in the actual arguments
934 * (expressed in "int_arg") into the access relations in "summary" and
935 * to add the resulting access relations to "arg".
937 static __isl_give pet_expr
*access_plug_in_summary(__isl_take pet_expr
*arg
,
938 __isl_keep pet_expr
*call
, __isl_keep pet_function_summary
*summary
,
943 isl_multi_pw_aff
*int_arg
;
946 space
= pet_expr_access_get_augmented_domain_space(arg
);
947 space
= isl_space_from_domain(space
);
948 arg_n_arg
= pet_expr_get_n_arg(arg
);
949 int_arg
= isl_multi_pw_aff_zero(space
);
950 n
= pet_function_summary_get_n_arg(summary
);
951 for (j
= 0; j
< n
; ++j
) {
955 if (!pet_function_summary_arg_is_int(summary
, j
))
958 arg_j
= pet_expr_get_arg(call
, j
);
959 arg_j_n_arg
= pet_expr_get_n_arg(arg_j
);
960 if (pet_expr_get_type(arg_j
) == pet_expr_int
) {
961 int_arg
= add_int(int_arg
, arg_j
);
962 } else if (arg_j_n_arg
!= 0 || !pet_expr_is_affine(arg_j
)) {
963 arg
= pet_expr_insert_arg(arg
, arg_n_arg
,
965 int_arg
= add_arg(int_arg
, arg_n_arg
);
968 int_arg
= add_aff(int_arg
, arg_n_arg
, arg_j
);
971 arg
= set_access_relations(arg
, summary
, pos
, int_arg
, add
);
976 /* Given the argument "arg" at position "pos" of "call",
977 * check if it is either an access expression or the address
978 * of an access expression. If so, use the information in "summary"
979 * to set the access relations of the access expression.
981 static __isl_give pet_expr
*arg_plug_in_summary(__isl_take pet_expr
*arg
,
982 __isl_keep pet_expr
*call
, __isl_keep pet_function_summary
*summary
,
985 enum pet_expr_type type
;
988 type
= pet_expr_get_type(arg
);
989 if (type
== pet_expr_access
)
990 return access_plug_in_summary(arg
, call
, summary
, pos
, 0);
991 if (type
!= pet_expr_op
)
993 if (pet_expr_op_get_type(arg
) != pet_op_address_of
)
996 arg2
= pet_expr_get_arg(arg
, 0);
997 if (pet_expr_get_type(arg2
) == pet_expr_access
)
998 arg2
= access_plug_in_summary(arg2
, call
, summary
, pos
, 1);
999 arg
= pet_expr_set_arg(arg
, 0, arg2
);
1004 /* Given a call expression, check if the integer arguments can
1005 * be represented by affine expressions in the context "pc"
1006 * (assuming they are not already affine expressions).
1007 * If so, replace these arguments by the corresponding affine expressions.
1009 static __isl_give pet_expr
*call_plug_in_affine_args(__isl_take pet_expr
*call
,
1010 __isl_keep pet_context
*pc
)
1014 n
= pet_expr_get_n_arg(call
);
1015 for (i
= 0; i
< n
; ++i
) {
1019 arg
= pet_expr_get_arg(call
, i
);
1021 return pet_expr_free(call
);
1022 if (pet_expr_get_type_size(arg
) == 0 ||
1023 pet_expr_is_affine(arg
)) {
1028 pa
= pet_expr_extract_affine(arg
, pc
);
1031 return pet_expr_free(call
);
1032 if (isl_pw_aff_involves_nan(pa
)) {
1033 isl_pw_aff_free(pa
);
1037 arg
= pet_expr_from_index(isl_multi_pw_aff_from_pw_aff(pa
));
1038 call
= pet_expr_set_arg(call
, i
, arg
);
1044 /* If "call" has an associated function summary, then use it
1045 * to set the access relations of the array arguments of the function call.
1047 * We first plug in affine expressions for the integer arguments
1048 * whenever possible as these arguments will be plugged in
1049 * in the access relations of the array arguments.
1051 static __isl_give pet_expr
*call_plug_in_summary(__isl_take pet_expr
*call
,
1054 pet_context
*pc
= user
;
1055 pet_function_summary
*summary
;
1058 if (!pet_expr_call_has_summary(call
))
1061 call
= call_plug_in_affine_args(call
, pc
);
1063 summary
= pet_expr_call_get_summary(call
);
1065 return pet_expr_free(call
);
1067 n
= pet_expr_get_n_arg(call
);
1068 for (i
= 0; i
< n
; ++i
) {
1071 if (!pet_function_summary_arg_is_array(summary
, i
))
1074 arg_i
= pet_expr_get_arg(call
, i
);
1075 arg_i
= arg_plug_in_summary(arg_i
, call
, summary
, i
);
1076 call
= pet_expr_set_arg(call
, i
, arg_i
);
1079 pet_function_summary_free(summary
);
1083 /* For each call subexpression of "expr", plug in the access relations
1084 * from the associated function summary (if any).
1086 static __isl_give pet_expr
*plug_in_summaries(__isl_take pet_expr
*expr
,
1087 __isl_keep pet_context
*pc
)
1089 return pet_expr_map_call(expr
, &call_plug_in_summary
, pc
);
1092 /* Evaluate "expr" in the context of "pc".
1094 * In particular, we first make sure that all the access expressions
1095 * inside "expr" have the same domain as "pc".
1096 * Then, we plug in affine expressions for scalar reads,
1097 * plug in the arguments of all access expressions in "expr" and
1098 * plug in the access relations from the summary functions associated
1099 * to call expressions.
1101 __isl_give pet_expr
*pet_context_evaluate_expr(__isl_keep pet_context
*pc
,
1102 __isl_take pet_expr
*expr
)
1104 expr
= pet_expr_insert_domain(expr
, pet_context_get_space(pc
));
1105 expr
= plug_in_affine_read(expr
, pc
);
1106 expr
= pet_expr_plug_in_args(expr
, pc
);
1107 expr
= plug_in_summaries(expr
, pc
);
1111 /* Wrapper around pet_context_evaluate_expr
1112 * for use as a callback to pet_tree_map_expr.
1114 static __isl_give pet_expr
*evaluate_expr(__isl_take pet_expr
*expr
,
1117 pet_context
*pc
= user
;
1119 return pet_context_evaluate_expr(pc
, expr
);
1122 /* Evaluate "tree" in the context of "pc".
1123 * That is, evaluate all the expressions of "tree" in the context of "pc".
1125 __isl_give pet_tree
*pet_context_evaluate_tree(__isl_keep pet_context
*pc
,
1126 __isl_take pet_tree
*tree
)
1128 return pet_tree_map_expr(tree
, &evaluate_expr
, pc
);
1131 /* Add an unbounded inner dimension "id" to pc->domain.
1133 * The assignments are not adjusted here and therefore keep
1134 * their original domain. These domains need to be adjusted before
1135 * these assigned values can be used. This is taken care of by
1136 * pet_context_get_value.
1138 static __isl_give pet_context
*extend_domain(__isl_take pet_context
*pc
,
1139 __isl_take isl_id
*id
)
1143 pc
= pet_context_cow(pc
);
1147 pos
= pet_context_dim(pc
);
1148 pc
->domain
= isl_set_add_dims(pc
->domain
, isl_dim_set
, 1);
1149 pc
->domain
= isl_set_set_dim_id(pc
->domain
, isl_dim_set
, pos
, id
);
1151 return pet_context_free(pc
);
1155 pet_context_free(pc
);
1160 /* Add an unbounded inner iterator "id" to pc->domain.
1161 * Additionally, mark the variable "id" as having the value of this
1162 * new inner iterator.
1164 __isl_give pet_context
*pet_context_add_inner_iterator(
1165 __isl_take pet_context
*pc
, __isl_take isl_id
*id
)
1169 isl_local_space
*ls
;
1176 pos
= pet_context_dim(pc
);
1177 pc
= extend_domain(pc
, isl_id_copy(id
));
1181 space
= pet_context_get_space(pc
);
1182 ls
= isl_local_space_from_space(space
);
1183 aff
= isl_aff_var_on_domain(ls
, isl_dim_set
, pos
);
1184 pa
= isl_pw_aff_from_aff(aff
);
1186 pc
= pet_context_set_value(pc
, id
, pa
);
1190 pet_context_free(pc
);
1195 /* Add an inner iterator to pc->domain.
1196 * In particular, extend the domain with an inner loop { [t] : t >= 0 }.
1198 __isl_give pet_context
*pet_context_add_infinite_loop(
1199 __isl_take pet_context
*pc
)
1208 dim
= pet_context_dim(pc
);
1209 ctx
= pet_context_get_ctx(pc
);
1210 id
= isl_id_alloc(ctx
, "t", NULL
);
1211 pc
= extend_domain(pc
, id
);
1212 pc
= pet_context_cow(pc
);
1215 pc
->domain
= isl_set_lower_bound_si(pc
->domain
, isl_dim_set
, dim
, 0);
1217 return pet_context_free(pc
);
1222 /* Internal data structure for preimage_domain.
1224 * "ma" is the function under which the preimage should be computed.
1225 * "assignments" collects the results.
1227 struct pet_preimage_domain_data
{
1229 isl_id_to_pw_aff
*assignments
;
1232 /* Add the assignment to "key" of the preimage of "val" under data->ma
1233 * to data->assignments.
1235 * Some dimensions may have been added to the domain of the enclosing
1236 * pet_context after the value "val" was added. We therefore need to
1237 * adjust the domain of "val" to match the range of data->ma (which
1238 * in turn matches the domain of the pet_context), by adding the missing
1241 static int preimage_domain_pair(__isl_take isl_id
*key
,
1242 __isl_take isl_pw_aff
*val
, void *user
)
1244 struct pet_preimage_domain_data
*data
= user
;
1248 ma
= isl_multi_aff_copy(data
->ma
);
1250 dim
= isl_pw_aff_dim(val
, isl_dim_in
);
1251 if (dim
!= isl_multi_aff_dim(data
->ma
, isl_dim_out
)) {
1253 isl_multi_aff
*proj
;
1254 space
= isl_multi_aff_get_space(data
->ma
);
1255 space
= isl_space_range(space
);
1256 proj
= pet_prefix_projection(space
, dim
);
1257 ma
= isl_multi_aff_pullback_multi_aff(proj
, ma
);
1260 val
= isl_pw_aff_pullback_multi_aff(val
, ma
);
1261 data
->assignments
= isl_id_to_pw_aff_set(data
->assignments
, key
, val
);
1266 /* Compute the preimage of "assignments" under the function represented by "ma".
1267 * In other words, plug in "ma" in the domains of the assigned values.
1269 static __isl_give isl_id_to_pw_aff
*preimage_domain(
1270 __isl_take isl_id_to_pw_aff
*assignments
, __isl_keep isl_multi_aff
*ma
)
1272 struct pet_preimage_domain_data data
= { ma
};
1275 ctx
= isl_id_to_pw_aff_get_ctx(assignments
);
1276 data
.assignments
= isl_id_to_pw_aff_alloc(ctx
, 0);
1277 if (isl_id_to_pw_aff_foreach(assignments
, &preimage_domain_pair
,
1279 data
.assignments
= isl_id_to_pw_aff_free(data
.assignments
);
1280 isl_id_to_pw_aff_free(assignments
);
1282 return data
.assignments
;
1285 /* Compute the preimage of "pc" under the function represented by "ma".
1286 * In other words, plug in "ma" in the domain of "pc".
1288 __isl_give pet_context
*pet_context_preimage_domain(__isl_take pet_context
*pc
,
1289 __isl_keep isl_multi_aff
*ma
)
1291 pc
= pet_context_cow(pc
);
1294 pc
->domain
= isl_set_preimage_multi_aff(pc
->domain
,
1295 isl_multi_aff_copy(ma
));
1296 pc
->assignments
= preimage_domain(pc
->assignments
, ma
);
1297 if (!pc
->domain
|| !pc
->assignments
)
1298 return pet_context_free(pc
);
1302 /* Add the constraints of "set" to the domain of "pc".
1304 __isl_give pet_context
*pet_context_intersect_domain(__isl_take pet_context
*pc
,
1305 __isl_take isl_set
*set
)
1307 pc
= pet_context_cow(pc
);
1310 pc
->domain
= isl_set_intersect(pc
->domain
, set
);
1312 return pet_context_free(pc
);
1315 pet_context_free(pc
);
1320 void pet_context_dump(__isl_keep pet_context
*pc
)
1324 fprintf(stderr
, "domain: ");
1325 isl_set_dump(pc
->domain
);
1326 fprintf(stderr
, "assignments: ");
1327 isl_id_to_pw_aff_dump(pc
->assignments
);
1328 fprintf(stderr
, "nesting allowed: %d\n", pc
->allow_nested
);