2 * Copyright 2011 Leiden University. All rights reserved.
3 * Copyright 2014 Ecole Normale Superieure. All rights reserved.
4 * Copyright 2015 Sven Verdoolaege. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY LEIDEN UNIVERSITY ''AS IS'' AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LEIDEN UNIVERSITY OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
25 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 * The views and conclusions contained in the software and documentation
31 * are those of the authors and should not be interpreted as
32 * representing official policies, either expressed or implied, of
40 /* Given the data space "space1" of an index expression passed
41 * to a function and the data space "space2" of the corresponding
42 * array accessed in the function, construct and return the complete
43 * data space from the perspective of the function call.
44 * If add is set, then it is not the index expression with space "space1" itself
45 * that is passed to the function, but its address.
47 * In the simplest case, no member accesses are involved and "add" is not set.
48 * Let "space1" be of the form A[x] and "space2" of the form B[y].
49 * Then the returned space is A[x,y].
50 * That is, the dimension is the sum of the dimensions and the name
51 * is that of "space1".
52 * If "add" is set, then the final dimension of "space1" is the same
53 * as the initial dimension of "space2" and the dimension of the result
54 * is one less that the sum. This also applies when the dimension
55 * of "space1" is zero. The dimension of "space2" can never be zero
56 * when "add" is set since a pointer value is passed to the function,
57 * which is treated as an array of dimension at least 1.
59 * If "space1" involves any member accesses, then it is the innermost
60 * array space of "space1" that needs to be extended with "space2".
61 * This innermost array space appears in the range of the wrapped
62 * relation in "space1".
64 * If "space2" involves any member accesses, then it is the outermost
65 * array space of "space2" that needs to be combined with innermost
66 * array space of "space1". This outermost array space appears
67 * in the deepest nesting of the domains and is therefore handled
70 * For example, if "space1" is of the form
74 * and "space2" is of the form
76 * d_b_c[d_b[d[z] -> b[u]] -> c[v]]
78 * then the resulting space is
80 * s_a_b_c[s_a_b[s_a[s[x] -> a[y,z]] -> b[u]] -> c[v]]
82 static __isl_give isl_space
*patch_space(__isl_take isl_space
*space1
,
83 __isl_take isl_space
*space2
, int add
)
88 if (!space1
|| !space2
)
91 if (isl_space_is_wrapping(space2
)) {
94 const char *name1
, *name2
;
97 ctx
= isl_space_get_ctx(space1
);
98 space2
= isl_space_unwrap(space2
);
99 dom
= isl_space_domain(isl_space_copy(space2
));
100 space1
= patch_space(space1
, dom
, add
);
101 space2
= isl_space_range(space2
);
102 name1
= isl_space_get_tuple_name(space1
, isl_dim_set
);
103 name2
= isl_space_get_tuple_name(space2
, isl_dim_set
);
104 name
= pet_array_member_access_name(ctx
, name1
, name2
);
105 space1
= isl_space_product(space1
, space2
);
106 space1
= isl_space_set_tuple_name(space1
, isl_dim_set
, name
);
111 dim
= isl_space_dim(space2
, isl_dim_set
) - add
;
112 id
= isl_space_get_tuple_id(space1
, isl_dim_set
);
113 if (isl_space_is_wrapping(space1
)) {
116 space1
= isl_space_unwrap(space1
);
117 id
= isl_space_get_tuple_id(space1
, isl_dim_out
);
118 space1
= isl_space_add_dims(space1
, isl_dim_out
, dim
);
119 space1
= isl_space_set_tuple_id(space1
, isl_dim_out
, id
);
120 space1
= isl_space_wrap(space1
);
122 space1
= isl_space_add_dims(space1
, isl_dim_out
, dim
);
124 space1
= isl_space_set_tuple_id(space1
, isl_dim_set
, id
);
126 isl_space_free(space2
);
129 isl_space_free(space1
);
130 isl_space_free(space2
);
134 /* Drop the initial dimension of "map", assuming that it is equal to zero.
135 * If it turns out not to be equal to zero, then drop the initial dimension
136 * of "map" after setting the value to zero and print a warning (if "warn"
139 static __isl_give isl_map
*drop_initial_zero(__isl_take isl_map
*map
,
140 __isl_keep isl_map
*prefix
, int warn
)
144 zeroed
= isl_map_copy(map
);
145 zeroed
= isl_map_fix_si(zeroed
, isl_dim_out
, 0, 0);
146 map
= isl_map_subtract(map
, isl_map_copy(zeroed
));
147 if (warn
&& !isl_map_is_empty(map
)) {
148 fprintf(stderr
, "possible out-of-bounds accesses\n");
150 fprintf(stderr
, "when passing\n");
151 isl_map_dump(prefix
);
155 map
= isl_map_project_out(map
, isl_dim_out
, 0, 1);
159 /* Drop the initial dimension of "mpa", assuming that it is equal to zero.
161 static __isl_give isl_multi_pw_aff
*mpa_drop_initial_zero(
162 __isl_take isl_multi_pw_aff
*mpa
)
167 pa
= isl_multi_pw_aff_get_pw_aff(mpa
, 0);
168 cond
= isl_pw_aff_zero_set(pa
);
169 mpa
= isl_multi_pw_aff_drop_dims(mpa
, isl_dim_out
, 0, 1);
170 mpa
= isl_multi_pw_aff_intersect_domain(mpa
, cond
);
175 /* Construct an isl_multi_aff of the form
177 * [i_0, ..., i_pos, i_{pos+1}, i_{pos+2}, ...] ->
178 * [i_0, ..., i_pos + i_{pos+1}, i_{pos+2}, ...]
180 * "space" prescribes the domain of this function.
182 static __isl_give isl_multi_aff
*patch_add(__isl_take isl_space
*space
,
186 isl_aff
*aff1
, *aff2
;
188 ma
= isl_multi_aff_identity(isl_space_map_from_set(space
));
189 aff1
= isl_multi_aff_get_aff(ma
, pos
);
190 aff2
= isl_multi_aff_get_aff(ma
, pos
+ 1);
191 aff1
= isl_aff_add(aff1
, aff2
);
192 ma
= isl_multi_aff_set_aff(ma
, pos
, aff1
);
193 ma
= isl_multi_aff_drop_dims(ma
, isl_dim_out
, pos
+ 1, 1);
198 /* Given an identity mapping "id" that adds structure to
199 * the range of "map" with dimensions "pos" and "pos + 1" replaced
200 * by their sum, adjust "id" to apply to the range of "map" directly.
203 * [i_0, ..., i_pos, i_{pos+1}, i_{pos+2}, ...] ->
204 * [i_0, ..., i_pos + i_{pos+1}, i_{pos+2}, ...]
206 * in "id", where the domain of this mapping corresponds to the range
207 * of "map" and the range of this mapping corresponds to the original
210 static __isl_give isl_map
*patch_map_add(__isl_take isl_map
*id
,
211 __isl_keep isl_map
*map
, int pos
)
216 space
= isl_space_range(isl_map_get_space(map
));
217 ma
= patch_add(space
, pos
);
218 id
= isl_map_preimage_domain_multi_aff(id
, ma
);
223 /* Given an identity mapping "id" that adds structure to
224 * the range of "mpa" with dimensions "pos" and "pos + 1" replaced
225 * by their sum, adjust "id" to apply to the range of "mpa" directly.
228 * [i_0, ..., i_pos, i_{pos+1}, i_{pos+2}, ...] ->
229 * [i_0, ..., i_pos + i_{pos+1}, i_{pos+2}, ...]
231 * in "id", where the domain of this mapping corresponds to the range
232 * of "mpa" and the range of this mapping corresponds to the original
235 static __isl_give isl_multi_pw_aff
*patch_mpa_add(
236 __isl_take isl_multi_pw_aff
*id
, __isl_keep isl_multi_pw_aff
*mpa
,
242 space
= isl_space_range(isl_multi_pw_aff_get_space(mpa
));
243 ma
= patch_add(space
, pos
);
244 id
= isl_multi_pw_aff_pullback_multi_aff(id
, ma
);
249 /* Return the dimension of the innermost array in the data space "space".
250 * If "space" is not a wrapping space, then it does not involve any
251 * member accesses and the innermost array is simply the accessed
253 * Otherwise, the innermost array is encoded in the range of the
256 static int innermost_dim(__isl_keep isl_space
*space
)
260 if (!isl_space_is_wrapping(space
))
261 return isl_space_dim(space
, isl_dim_set
);
263 space
= isl_space_copy(space
);
264 space
= isl_space_unwrap(space
);
265 dim
= isl_space_dim(space
, isl_dim_out
);
266 isl_space_free(space
);
271 /* Internal data structure for patch_map.
273 * "prefix" is the index expression passed to the function
274 * "add" is set if it is the address of "prefix" that is passed to the function.
275 * "warn" is set if a warning should be printed when an initial index
276 * expression is not (obviously) zero when it should be.
277 * "res" collects the results.
279 struct pet_patch_map_data
{
287 /* Combine the index expression data->prefix with the subaccess relation "map".
288 * If data->add is set, then it is not the index expression data->prefix itself
289 * that is passed to the function, but its address.
291 * If data->add is not set, then we essentially need to concatenate
292 * data->prefix with map, except that we need to make sure that
293 * the target space is set correctly. This target space is computed
294 * by the function patch_space. We then simply compute the flat
295 * range product and subsequently reset the target space.
297 * If data->add is set then the outer dimension of "map" is an offset
298 * with respect to the inner dimension of data->prefix and we therefore
299 * need to add these two dimensions rather than simply concatenating them.
300 * This computation is performed in patch_map_add.
301 * If however, the innermost accessed array of data->prefix is
302 * zero-dimensional, then there is no innermost dimension of data->prefix
303 * to add to the outermost dimension of "map", Instead, we are passing
304 * a pointer to a scalar member, meaning that the outermost dimension
305 * of "map" needs to be zero and that this zero needs to be removed
306 * from the concatenation. This computation is performed in drop_initial_zero.
308 static isl_stat
patch_map(__isl_take isl_map
*map
, void *user
)
310 struct pet_patch_map_data
*data
= user
;
315 space
= isl_space_range(isl_map_get_space(data
->prefix
));
316 dim
= innermost_dim(space
);
317 pos
= isl_space_dim(space
, isl_dim_set
) - dim
;
318 space
= patch_space(space
, isl_space_range(isl_map_get_space(map
)),
320 if (data
->add
&& dim
== 0)
321 map
= drop_initial_zero(map
, data
->prefix
, data
->warn
);
322 map
= isl_map_flat_range_product(isl_map_copy(data
->prefix
), map
);
323 space
= isl_space_map_from_set(space
);
324 space
= isl_space_add_dims(space
, isl_dim_in
, 0);
325 id
= isl_map_identity(space
);
326 if (data
->add
&& dim
!= 0)
327 id
= patch_map_add(id
, map
, pos
+ dim
- 1);
328 map
= isl_map_apply_range(map
, id
);
329 data
->res
= isl_union_map_add_map(data
->res
, map
);
334 /* Combine the index expression "prefix" with the index expression "mpa".
335 * If add is set, then it is not the index expression "prefix" itself
336 * that is passed to the function, but its address.
338 * If add is not set, then we essentially need to concatenate
339 * "prefix" with "mpa", except that we need to make sure that
340 * the target space is set correctly. This target space is computed
341 * by the function patch_space. We then simply compute the flat
342 * range product and subsequently reset the target space.
344 * If add is set then the outer dimension of "mpa" is an offset
345 * with respect to the inner dimension of "prefix" and we therefore
346 * need to add these two dimensions rather than simply concatenating them.
347 * This computation is performed in patch_mpa_add.
348 * If however, the innermost accessed array of "prefix" is
349 * zero-dimensional, then there is no innermost dimension of "prefix"
350 * to add to the outermost dimension of "mpa", Instead, we are passing
351 * a pointer to a scalar member, meaning that the outermost dimension
352 * of "mpa" needs to be zero and that this zero needs to be removed
353 * from the concatenation. This computation is performed in
354 * mpa_drop_initial_zero.
356 __isl_give isl_multi_pw_aff
*pet_patch_multi_pw_aff(
357 __isl_take isl_multi_pw_aff
*prefix
, __isl_take isl_multi_pw_aff
*mpa
,
362 isl_multi_pw_aff
*id
;
364 space
= isl_space_range(isl_multi_pw_aff_get_space(prefix
));
365 dim
= innermost_dim(space
);
366 pos
= isl_space_dim(space
, isl_dim_set
) - dim
;
367 space
= patch_space(space
,
368 isl_space_range(isl_multi_pw_aff_get_space(mpa
)), add
);
370 mpa
= mpa_drop_initial_zero(mpa
);
371 mpa
= isl_multi_pw_aff_flat_range_product(prefix
, mpa
);
372 space
= isl_space_map_from_set(space
);
373 space
= isl_space_add_dims(space
, isl_dim_in
, 0);
374 id
= isl_multi_pw_aff_identity(space
);
376 id
= patch_mpa_add(id
, mpa
, pos
+ dim
- 1);
377 mpa
= isl_multi_pw_aff_pullback_multi_pw_aff(id
, mpa
);
382 /* Combine the index expression "prefix" with the subaccess relation "umap".
383 * If "add" is set, then it is not the index expression "prefix" itself
384 * that was passed to the function, but its address.
385 * If "warn" is set, then a warning is printed when an initial index
386 * expression is not (obviously) zero when it should be.
388 * We call patch_map on each map in "umap" and return the combined results.
390 __isl_give isl_union_map
*pet_patch_union_map(
391 __isl_take isl_multi_pw_aff
*prefix
, __isl_take isl_union_map
*umap
,
394 struct pet_patch_map_data data
;
397 map
= isl_map_from_multi_pw_aff(prefix
);
398 map
= isl_map_align_params(map
, isl_union_map_get_space(umap
));
399 umap
= isl_union_map_align_params(umap
, isl_map_get_space(map
));
403 data
.res
= isl_union_map_empty(isl_union_map_get_space(umap
));
404 if (isl_union_map_foreach_map(umap
, &patch_map
, &data
) < 0)
405 data
.res
= isl_union_map_free(data
.res
);
406 isl_union_map_free(umap
);
407 isl_map_free(data
.prefix
);