expr.c: extract out pet_expr_get_affine
[pet.git] / patch.c
blobd32b7ec1bad4856af9cabde4a47c5d17fde609c9
1 /*
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
8 * are met:
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
33 * Leiden University.
36 #include "array.h"
37 #include "expr.h"
38 #include "patch.h"
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
68 * recursively.
70 * For example, if "space1" is of the form
72 * s_a[s[x] -> a[y]]
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)
85 int dim;
86 isl_id *id;
88 if (!space1 || !space2)
89 goto error;
91 if (isl_space_is_wrapping(space2)) {
92 isl_ctx *ctx;
93 isl_space *dom;
94 const char *name1, *name2;
95 char *name;
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);
107 free(name);
108 return space1;
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)) {
114 isl_id *id;
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);
121 } else {
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);
127 return space1;
128 error:
129 isl_space_free(space1);
130 isl_space_free(space2);
131 return NULL;
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"
137 * is set).
139 static __isl_give isl_map *drop_initial_zero(__isl_take isl_map *map,
140 __isl_keep isl_map *prefix, int warn)
142 isl_map *zeroed;
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");
149 isl_map_dump(map);
150 fprintf(stderr, "when passing\n");
151 isl_map_dump(prefix);
153 isl_map_free(map);
154 map = zeroed;
155 map = isl_map_project_out(map, isl_dim_out, 0, 1);
156 return map;
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)
164 isl_pw_aff *pa;
165 isl_set *cond;
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);
172 return mpa;
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,
183 int pos)
185 isl_multi_aff *ma;
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);
195 return ma;
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.
201 * That is, plug in
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
208 * domain of "id".
210 static __isl_give isl_map *patch_map_add(__isl_take isl_map *id,
211 __isl_keep isl_map *map, int pos)
213 isl_space *space;
214 isl_multi_aff *ma;
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);
220 return id;
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.
226 * That is, plug in
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
233 * domain of "id".
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,
237 int pos)
239 isl_space *space;
240 isl_multi_aff *ma;
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);
246 return id;
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
252 * array itself.
253 * Otherwise, the innermost array is encoded in the range of the
254 * wrapped space.
256 static int innermost_dim(__isl_keep isl_space *space)
258 int dim;
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);
268 return dim;
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 {
280 isl_map *prefix;
281 int add;
282 int warn;
284 isl_union_map *res;
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;
311 isl_space *space;
312 isl_map *id;
313 int pos, dim;
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)),
319 data->add);
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);
331 return isl_stat_ok;
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,
358 int add)
360 isl_space *space;
361 int pos, dim;
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);
369 if (add && dim == 0)
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);
375 if (add && dim != 0)
376 id = patch_mpa_add(id, mpa, pos + dim - 1);
377 mpa = isl_multi_pw_aff_pullback_multi_pw_aff(id, mpa);
379 return 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,
392 int add, int warn)
394 struct pet_patch_map_data data;
395 isl_map *map;
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));
400 data.prefix = map;
401 data.add = add;
402 data.warn = warn;
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);
409 return data.res;