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
39 /* Equate the arguments "pos1" and "pos2" of the access expression "expr".
41 * We may assume that "pos1" is smaller than "pos2".
42 * We replace all references to the argument at position "pos2"
43 * to references to the argument at position "pos1" (leaving all other
44 * variables untouched) and then drop argument "pos2".
46 static __isl_give pet_expr
*equate_arg(__isl_take pet_expr
*expr
, int pos1
,
58 return equate_arg(expr
, pos2
, pos1
);
59 if (pos1
< 0 || pos2
>= expr
->n_arg
)
60 isl_die(pet_expr_get_ctx(expr
), isl_error_invalid
,
61 "position out of bounds", return pet_expr_free(expr
));
63 space
= isl_multi_pw_aff_get_domain_space(expr
->acc
.index
);
64 space
= isl_space_unwrap(space
);
65 in
= isl_space_dim(space
, isl_dim_in
);
66 isl_space_free(space
);
70 space
= isl_multi_pw_aff_get_domain_space(expr
->acc
.index
);
71 space
= isl_space_map_from_set(space
);
72 ma
= isl_multi_aff_identity(space
);
73 ma
= isl_multi_aff_set_aff(ma
, pos2
, isl_multi_aff_get_aff(ma
, pos1
));
74 expr
= pet_expr_access_pullback_multi_aff(expr
, ma
);
75 expr
= pet_expr_access_project_out_arg(expr
, in
, pos2
- in
);
80 /* Remove all arguments of the access expression "expr" that are duplicates
81 * of earlier arguments.
83 __isl_give pet_expr
*pet_expr_remove_duplicate_args(__isl_take pet_expr
*expr
)
92 for (i
= expr
->n_arg
- 1; i
>= 0; --i
) {
93 for (j
= 0; j
< i
; ++j
)
94 if (pet_expr_is_equal(expr
->args
[i
], expr
->args
[j
]))
98 expr
= equate_arg(expr
, j
, i
);
106 /* Insert argument "arg" at position "pos" in the arguments
107 * of access expression "expr".
109 * Besides actually inserting the argument, we also need to make
110 * sure that we adjust the references to the original arguments.
112 * If "expr" has no arguments to start with, then its domain is of the form
116 * otherwise, it is of the form
120 * In the first case, we compute the pullback over
122 * [S[i] -> [arg]] -> S[i]
124 * In the second case, we compute the pullback over
126 * [S[i] -> [args_before_pos,arg,args_after_pos]] -> [S[i] -> [args]]
128 __isl_give pet_expr
*pet_expr_insert_arg(__isl_take pet_expr
*expr
, int pos
,
129 __isl_take pet_expr
*arg
)
137 if (expr
->type
!= pet_expr_access
)
138 isl_die(pet_expr_get_ctx(expr
), isl_error_invalid
,
139 "not an access pet_expr", goto error
);
141 n
= pet_expr_get_n_arg(expr
);
142 if (pos
< 0 || pos
> n
)
143 isl_die(pet_expr_get_ctx(expr
), isl_error_invalid
,
144 "position out of bounds", goto error
);
146 expr
= pet_expr_set_n_arg(expr
, n
+ 1);
147 for (i
= n
; i
> pos
; --i
)
148 pet_expr_set_arg(expr
, i
, pet_expr_get_arg(expr
, i
- 1));
149 expr
= pet_expr_set_arg(expr
, pos
, arg
);
151 space
= pet_expr_access_get_domain_space(expr
);
152 space
= isl_space_from_domain(space
);
153 space
= isl_space_add_dims(space
, isl_dim_out
, n
+ 1);
156 ma
= isl_multi_aff_domain_map(space
);
158 isl_multi_aff
*ma2
, *proj
;
160 ma
= isl_multi_aff_domain_map(isl_space_copy(space
));
161 ma2
= isl_multi_aff_range_map(space
);
162 space
= isl_space_range(isl_multi_aff_get_space(ma2
));
163 proj
= isl_multi_aff_project_out_map(space
,
164 isl_dim_set
, pos
, 1);
165 ma2
= isl_multi_aff_pullback_multi_aff(proj
, ma2
);
166 ma
= isl_multi_aff_range_product(ma
, ma2
);
169 expr
= pet_expr_access_pullback_multi_aff(expr
, ma
);
178 /* Remove the argument at position "pos" in the arguments
179 * of access expression "expr", making sure it is not referenced
180 * from the index expression.
181 * "dim" is the dimension of the iteration domain.
183 * Besides actually removing the argument, we also need to make sure that
184 * we eliminate any reference from the access relation (if any) and that
185 * we adjust the references to the remaining arguments.
187 * If "expr" has a single argument, then we compute the pullback over
189 * S[i] -> [S[i] -> [arg]]
191 * Otherwise, we compute the pullback over
193 * [S[i] -> [args]] -> [S[i] -> [args_before_pos,args_after_pos]]
195 __isl_give pet_expr
*pet_expr_access_project_out_arg(__isl_take pet_expr
*expr
,
200 isl_space
*space
, *dom
, *ran
;
201 isl_multi_aff
*ma1
, *ma2
;
202 enum pet_expr_access_type type
;
206 expr
= pet_expr_cow(expr
);
209 if (expr
->type
!= pet_expr_access
)
210 isl_die(pet_expr_get_ctx(expr
), isl_error_invalid
,
211 "not an access pet_expr", return pet_expr_free(expr
));
212 n
= pet_expr_get_n_arg(expr
);
213 if (pos
< 0 || pos
>= n
)
214 isl_die(pet_expr_get_ctx(expr
), isl_error_invalid
,
215 "position out of bounds", return pet_expr_free(expr
));
217 involves
= isl_multi_pw_aff_involves_dims(expr
->acc
.index
,
218 isl_dim_in
, dim
+ pos
, 1);
220 return pet_expr_free(expr
);
222 isl_die(pet_expr_get_ctx(expr
), isl_error_invalid
,
223 "cannot project out", return pet_expr_free(expr
));
224 space
= isl_multi_pw_aff_get_domain_space(expr
->acc
.index
);
225 map
= isl_map_identity(isl_space_map_from_set(space
));
226 map
= isl_map_eliminate(map
, isl_dim_out
, dim
+ pos
, 1);
227 umap
= isl_union_map_from_map(map
);
228 for (type
= pet_expr_access_begin
; type
< pet_expr_access_end
; ++type
) {
229 if (!expr
->acc
.access
[type
])
231 expr
->acc
.access
[type
] =
232 isl_union_map_apply_domain(expr
->acc
.access
[type
],
233 isl_union_map_copy(umap
));
234 if (!expr
->acc
.access
[type
])
237 isl_union_map_free(umap
);
238 if (!expr
->acc
.index
|| type
< pet_expr_access_end
)
239 return pet_expr_free(expr
);
241 space
= isl_multi_pw_aff_get_domain_space(expr
->acc
.index
);
242 space
= isl_space_unwrap(space
);
243 dom
= isl_space_map_from_set(isl_space_domain(isl_space_copy(space
)));
244 ma1
= isl_multi_aff_identity(dom
);
246 ma2
= isl_multi_aff_zero(space
);
247 ma1
= isl_multi_aff_range_product(ma1
, ma2
);
249 ran
= isl_space_map_from_set(isl_space_range(space
));
250 ma2
= isl_multi_aff_identity(ran
);
251 ma2
= isl_multi_aff_drop_dims(ma2
, isl_dim_in
, pos
, 1);
252 ma1
= isl_multi_aff_product(ma1
, ma2
);
255 expr
= pet_expr_access_pullback_multi_aff(expr
, ma1
);
258 pet_expr_free(expr
->args
[pos
]);
259 for (i
= pos
; i
+ 1 < n
; ++i
)
260 expr
->args
[i
] = expr
->args
[i
+ 1];
266 /* Plug in "value" for the argument at position "pos" of "expr".
268 * The input "value" is of the form
272 * while the index expression of "expr" has domain
276 * We therefore first pullback "value" to this domain, resulting in
278 * [S[i] -> [args]] -> [value(i)]
280 * Then we compute the pullback of "expr" over
282 * [S[i] -> [args]] -> [S[i] -> [args_before_pos,value(i),args_after_pos]]
284 * and drop the now redundant argument at position "pos".
286 static __isl_give pet_expr
*plug_in(__isl_take pet_expr
*expr
, int pos
,
287 __isl_take isl_pw_aff
*value
)
292 isl_multi_pw_aff
*mpa
;
294 space
= isl_multi_pw_aff_get_space(expr
->acc
.index
);
295 space
= isl_space_unwrap(isl_space_domain(space
));
296 n_in
= isl_space_dim(space
, isl_dim_in
);
297 ma
= isl_multi_aff_domain_map(space
);
298 value
= isl_pw_aff_pullback_multi_aff(value
, ma
);
300 space
= isl_multi_pw_aff_get_space(expr
->acc
.index
);
301 space
= isl_space_map_from_set(isl_space_domain(space
));
302 mpa
= isl_multi_pw_aff_identity(space
);
303 mpa
= isl_multi_pw_aff_set_pw_aff(mpa
, n_in
+ pos
, value
);
305 expr
= pet_expr_access_pullback_multi_pw_aff(expr
, mpa
);
306 expr
= pet_expr_access_project_out_arg(expr
, n_in
, pos
);
311 /* Given that the argument of "expr" at position "pos" is a sum
312 * of two expressions, replace references to this argument by the sum
313 * of references to the two expressions.
314 * "dim" is the dimension of the iteration domain.
318 * [S[i] -> [args]] -> [f(i,args_before_pos,arg_pos,args_after_pos)]
322 * [S[i] -> [args_before_pos,arg0,arg1,args_after_pos]] ->
323 * [f(i, args_before_pos, arg0 + arg1, args_after_pos)]
325 * where arg0 and arg1 refer to the arguments of the sum expression
326 * that the original arg_pos referred to.
328 * We introduce (an unreferenced) arg1 and replace arg_pos by arg0
329 * in the arguments and then we compute the pullback over
331 * [S[i] -> [args_before_pos,arg0,arg1,args_after_pos]] ->
332 * [S[i] -> [args_before_pos,arg0+arg1,arg1,args_after_pos]]
334 static __isl_give pet_expr
*splice_sum(__isl_take pet_expr
*expr
, int dim
,
340 isl_aff
*aff1
, *aff2
;
342 arg
= expr
->args
[pos
];
343 expr
= pet_expr_insert_arg(expr
, pos
+ 1, pet_expr_get_arg(arg
, 1));
344 expr
= pet_expr_set_arg(expr
, pos
, pet_expr_get_arg(arg
, 0));
348 space
= isl_multi_pw_aff_get_space(expr
->acc
.index
);
349 space
= isl_space_map_from_set(isl_space_domain(space
));
350 ma
= isl_multi_aff_identity(space
);
351 aff1
= isl_multi_aff_get_aff(ma
, dim
+ pos
);
352 aff2
= isl_multi_aff_get_aff(ma
, dim
+ pos
+ 1);
353 aff1
= isl_aff_add(aff1
, aff2
);
354 ma
= isl_multi_aff_set_aff(ma
, dim
+ pos
, aff1
);
356 expr
= pet_expr_access_pullback_multi_aff(expr
, ma
);
361 /* Try and integrate the arguments of "expr" into the index expression
362 * of "expr" by trying to convert the arguments to affine expressions.
363 * "pc" is the context in which the affine expressions are created.
365 * For example, given an access expression with index expression
367 * [S[i] -> [arg0]] -> A[arg0]
369 * where the first argument is itself an access to a variable "i"
370 * that is assigned the value
374 * by "pc", this value is plugged into
375 * the index expression of "expr", resulting in
377 * [i] -> { S[] -> A[i] }
381 * In particular, we first remove duplicate arguments so that we
382 * only need to convert a given expression once.
384 * Then we try and convert the arguments to affine expressions and
385 * (if successful) we plug them into the index expression.
387 * Occasionally, we may be unable to convert an entire argument, while
388 * we could convert a sub-argument. In particular, this may happen
389 * if the top-level argument is an addition of two expressions
390 * of which only one can be converted to an affine expression.
391 * We therefore replace a reference to a "+" argument by the sum
392 * of references to the summands.
394 __isl_give pet_expr
*pet_expr_access_plug_in_args(__isl_take pet_expr
*expr
,
395 __isl_keep pet_context
*pc
)
399 expr
= pet_expr_remove_duplicate_args(expr
);
402 if (expr
->type
!= pet_expr_access
)
403 isl_die(pet_expr_get_ctx(expr
), isl_error_invalid
,
404 "not an access pet_expr", return pet_expr_free(expr
));
406 n
= pet_expr_get_n_arg(expr
);
410 for (i
= n
- 1; expr
&& i
>= 0; --i
) {
412 pet_expr
*arg
= expr
->args
[i
];
414 pa
= pet_expr_extract_affine(arg
, pc
);
416 return pet_expr_free(expr
);
417 if (!isl_pw_aff_involves_nan(pa
)) {
418 expr
= plug_in(expr
, i
, pa
);
423 if (pet_expr_get_type(arg
) == pet_expr_op
&&
424 pet_expr_op_get_type(arg
) == pet_op_add
) {
425 int dim
= pet_context_dim(pc
);
426 expr
= splice_sum(expr
, dim
, i
);
434 /* A wrapper around pet_expr_access_plug_in_args for use
435 * as a pet_expr_map_access callback.
437 static __isl_give pet_expr
*plug_in_args(__isl_take pet_expr
*expr
, void *user
)
439 struct pet_context
*pc
= user
;
440 return pet_expr_access_plug_in_args(expr
, pc
);
443 /* For each access subexpression of "expr", try and integrate its arguments in
444 * its index expression by trying to convert the arguments
445 * to affine expressions.
446 * "pc" is the context in which the affine expressions are created.
448 __isl_give pet_expr
*pet_expr_plug_in_args(__isl_take pet_expr
*expr
,
449 __isl_keep pet_context
*pc
)
451 return pet_expr_map_access(expr
, &plug_in_args
, pc
);