/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/External/isl/isl_aff.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2011 INRIA Saclay |
3 | | * Copyright 2011 Sven Verdoolaege |
4 | | * Copyright 2012-2014 Ecole Normale Superieure |
5 | | * Copyright 2014 INRIA Rocquencourt |
6 | | * |
7 | | * Use of this software is governed by the MIT license |
8 | | * |
9 | | * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, |
10 | | * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, |
11 | | * 91893 Orsay, France |
12 | | * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France |
13 | | * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, |
14 | | * B.P. 105 - 78153 Le Chesnay, France |
15 | | */ |
16 | | |
17 | | #include <isl_ctx_private.h> |
18 | | #include <isl_map_private.h> |
19 | | #include <isl_union_map_private.h> |
20 | | #include <isl_aff_private.h> |
21 | | #include <isl_space_private.h> |
22 | | #include <isl_local_space_private.h> |
23 | | #include <isl_vec_private.h> |
24 | | #include <isl_mat_private.h> |
25 | | #include <isl/id.h> |
26 | | #include <isl/constraint.h> |
27 | | #include <isl_seq.h> |
28 | | #include <isl/set.h> |
29 | | #include <isl_val_private.h> |
30 | | #include <isl_point_private.h> |
31 | | #include <isl_config.h> |
32 | | |
33 | | #undef BASE |
34 | | #define BASE aff |
35 | | |
36 | | #include <isl_list_templ.c> |
37 | | |
38 | | #undef BASE |
39 | | #define BASE pw_aff |
40 | | |
41 | | #include <isl_list_templ.c> |
42 | | |
43 | | #undef BASE |
44 | | #define BASE pw_multi_aff |
45 | | |
46 | | #include <isl_list_templ.c> |
47 | | |
48 | | #undef BASE |
49 | | #define BASE union_pw_aff |
50 | | |
51 | | #include <isl_list_templ.c> |
52 | | |
53 | | #undef BASE |
54 | | #define BASE union_pw_multi_aff |
55 | | |
56 | | #include <isl_list_templ.c> |
57 | | |
58 | | __isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls, |
59 | | __isl_take isl_vec *v) |
60 | 342k | { |
61 | 342k | isl_aff *aff; |
62 | 342k | |
63 | 342k | if (!ls || !v) |
64 | 0 | goto error; |
65 | 342k | |
66 | 342k | aff = isl_calloc_type(v->ctx, struct isl_aff); |
67 | 342k | if (!aff) |
68 | 0 | goto error; |
69 | 342k | |
70 | 342k | aff->ref = 1; |
71 | 342k | aff->ls = ls; |
72 | 342k | aff->v = v; |
73 | 342k | |
74 | 342k | return aff; |
75 | 0 | error: |
76 | 0 | isl_local_space_free(ls); |
77 | 0 | isl_vec_free(v); |
78 | 0 | return NULL; |
79 | 342k | } |
80 | | |
81 | | __isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls) |
82 | 180k | { |
83 | 180k | isl_ctx *ctx; |
84 | 180k | isl_vec *v; |
85 | 180k | unsigned total; |
86 | 180k | |
87 | 180k | if (!ls) |
88 | 3 | return NULL; |
89 | 180k | |
90 | 180k | ctx = isl_local_space_get_ctx(ls); |
91 | 180k | if (!isl_local_space_divs_known(ls)) |
92 | 180k | isl_die0 (ctx, isl_error_invalid, "local space has unknown divs", |
93 | 180k | goto error); |
94 | 180k | if (!isl_local_space_is_set(ls)) |
95 | 180k | isl_die0 (ctx, isl_error_invalid, |
96 | 180k | "domain of affine expression should be a set", |
97 | 180k | goto error); |
98 | 180k | |
99 | 180k | total = isl_local_space_dim(ls, isl_dim_all); |
100 | 180k | v = isl_vec_alloc(ctx, 1 + 1 + total); |
101 | 180k | return isl_aff_alloc_vec(ls, v); |
102 | 0 | error: |
103 | 0 | isl_local_space_free(ls); |
104 | 0 | return NULL; |
105 | 180k | } |
106 | | |
107 | | __isl_give isl_aff *isl_aff_zero_on_domain(__isl_take isl_local_space *ls) |
108 | 67.4k | { |
109 | 67.4k | isl_aff *aff; |
110 | 67.4k | |
111 | 67.4k | aff = isl_aff_alloc(ls); |
112 | 67.4k | if (!aff) |
113 | 3 | return NULL; |
114 | 67.4k | |
115 | 67.4k | isl_int_set_si(aff->v->el[0], 1); |
116 | 67.4k | isl_seq_clr(aff->v->el + 1, aff->v->size - 1); |
117 | 67.4k | |
118 | 67.4k | return aff; |
119 | 67.4k | } |
120 | | |
121 | | /* Return a piecewise affine expression defined on the specified domain |
122 | | * that is equal to zero. |
123 | | */ |
124 | | __isl_give isl_pw_aff *isl_pw_aff_zero_on_domain(__isl_take isl_local_space *ls) |
125 | 661 | { |
126 | 661 | return isl_pw_aff_from_aff(isl_aff_zero_on_domain(ls)); |
127 | 661 | } |
128 | | |
129 | | /* Return an affine expression defined on the specified domain |
130 | | * that represents NaN. |
131 | | */ |
132 | | __isl_give isl_aff *isl_aff_nan_on_domain(__isl_take isl_local_space *ls) |
133 | 433 | { |
134 | 433 | isl_aff *aff; |
135 | 433 | |
136 | 433 | aff = isl_aff_alloc(ls); |
137 | 433 | if (!aff) |
138 | 0 | return NULL; |
139 | 433 | |
140 | 433 | isl_seq_clr(aff->v->el, aff->v->size); |
141 | 433 | |
142 | 433 | return aff; |
143 | 433 | } |
144 | | |
145 | | /* Return a piecewise affine expression defined on the specified domain |
146 | | * that represents NaN. |
147 | | */ |
148 | | __isl_give isl_pw_aff *isl_pw_aff_nan_on_domain(__isl_take isl_local_space *ls) |
149 | 32 | { |
150 | 32 | return isl_pw_aff_from_aff(isl_aff_nan_on_domain(ls)); |
151 | 32 | } |
152 | | |
153 | | /* Return an affine expression that is equal to "val" on |
154 | | * domain local space "ls". |
155 | | */ |
156 | | __isl_give isl_aff *isl_aff_val_on_domain(__isl_take isl_local_space *ls, |
157 | | __isl_take isl_val *val) |
158 | 29.2k | { |
159 | 29.2k | isl_aff *aff; |
160 | 29.2k | |
161 | 29.2k | if (!ls || !val) |
162 | 0 | goto error; |
163 | 29.2k | if (!isl_val_is_rat(val)) |
164 | 29.2k | isl_die0 (isl_val_get_ctx(val), isl_error_invalid, |
165 | 29.2k | "expecting rational value", goto error); |
166 | 29.2k | |
167 | 29.2k | aff = isl_aff_alloc(isl_local_space_copy(ls)); |
168 | 29.2k | if (!aff) |
169 | 0 | goto error; |
170 | 29.2k | |
171 | 29.2k | isl_seq_clr(aff->v->el + 2, aff->v->size - 2); |
172 | 29.2k | isl_int_set(aff->v->el[1], val->n); |
173 | 29.2k | isl_int_set(aff->v->el[0], val->d); |
174 | 29.2k | |
175 | 29.2k | isl_local_space_free(ls); |
176 | 29.2k | isl_val_free(val); |
177 | 29.2k | return aff; |
178 | 0 | error: |
179 | 0 | isl_local_space_free(ls); |
180 | 0 | isl_val_free(val); |
181 | 0 | return NULL; |
182 | 29.2k | } |
183 | | |
184 | | /* Return an affine expression that is equal to the specified dimension |
185 | | * in "ls". |
186 | | */ |
187 | | __isl_give isl_aff *isl_aff_var_on_domain(__isl_take isl_local_space *ls, |
188 | | enum isl_dim_type type, unsigned pos) |
189 | 30.8k | { |
190 | 30.8k | isl_space *space; |
191 | 30.8k | isl_aff *aff; |
192 | 30.8k | |
193 | 30.8k | if (!ls) |
194 | 0 | return NULL; |
195 | 30.8k | |
196 | 30.8k | space = isl_local_space_get_space(ls); |
197 | 30.8k | if (!space) |
198 | 0 | goto error; |
199 | 30.8k | if (isl_space_is_map(space)) |
200 | 30.8k | isl_die0 (isl_space_get_ctx(space), isl_error_invalid, |
201 | 30.8k | "expecting (parameter) set space", goto error); |
202 | 30.8k | if (pos >= isl_local_space_dim(ls, type)) |
203 | 30.8k | isl_die0 (isl_space_get_ctx(space), isl_error_invalid, |
204 | 30.8k | "position out of bounds", goto error); |
205 | 30.8k | |
206 | 30.8k | isl_space_free(space); |
207 | 30.8k | aff = isl_aff_alloc(ls); |
208 | 30.8k | if (!aff) |
209 | 0 | return NULL; |
210 | 30.8k | |
211 | 30.8k | pos += isl_local_space_offset(aff->ls, type); |
212 | 30.8k | |
213 | 30.8k | isl_int_set_si(aff->v->el[0], 1); |
214 | 30.8k | isl_seq_clr(aff->v->el + 1, aff->v->size - 1); |
215 | 30.8k | isl_int_set_si(aff->v->el[1 + pos], 1); |
216 | 30.8k | |
217 | 30.8k | return aff; |
218 | 0 | error: |
219 | 0 | isl_local_space_free(ls); |
220 | 0 | isl_space_free(space); |
221 | 0 | return NULL; |
222 | 30.8k | } |
223 | | |
224 | | /* Return a piecewise affine expression that is equal to |
225 | | * the specified dimension in "ls". |
226 | | */ |
227 | | __isl_give isl_pw_aff *isl_pw_aff_var_on_domain(__isl_take isl_local_space *ls, |
228 | | enum isl_dim_type type, unsigned pos) |
229 | 559 | { |
230 | 559 | return isl_pw_aff_from_aff(isl_aff_var_on_domain(ls, type, pos)); |
231 | 559 | } |
232 | | |
233 | | /* Return an affine expression that is equal to the parameter |
234 | | * in the domain space "space" with identifier "id". |
235 | | */ |
236 | | __isl_give isl_aff *isl_aff_param_on_domain_space_id( |
237 | | __isl_take isl_space *space, __isl_take isl_id *id) |
238 | 1 | { |
239 | 1 | int pos; |
240 | 1 | isl_local_space *ls; |
241 | 1 | |
242 | 1 | if (!space || !id) |
243 | 0 | goto error; |
244 | 1 | pos = isl_space_find_dim_by_id(space, isl_dim_param, id); |
245 | 1 | if (pos < 0) |
246 | 1 | isl_die0 (isl_space_get_ctx(space), isl_error_invalid, |
247 | 1 | "parameter not found in space", goto error); |
248 | 1 | isl_id_free(id); |
249 | 1 | ls = isl_local_space_from_space(space); |
250 | 1 | return isl_aff_var_on_domain(ls, isl_dim_param, pos); |
251 | 0 | error: |
252 | 0 | isl_space_free(space); |
253 | 0 | isl_id_free(id); |
254 | 0 | return NULL; |
255 | 1 | } |
256 | | |
257 | | __isl_give isl_aff *isl_aff_copy(__isl_keep isl_aff *aff) |
258 | 1.89M | { |
259 | 1.89M | if (!aff) |
260 | 6 | return NULL; |
261 | 1.89M | |
262 | 1.89M | aff->ref++; |
263 | 1.89M | return aff; |
264 | 1.89M | } |
265 | | |
266 | | __isl_give isl_aff *isl_aff_dup(__isl_keep isl_aff *aff) |
267 | 161k | { |
268 | 161k | if (!aff) |
269 | 0 | return NULL; |
270 | 161k | |
271 | 161k | return isl_aff_alloc_vec(isl_local_space_copy(aff->ls), |
272 | 161k | isl_vec_copy(aff->v)); |
273 | 161k | } |
274 | | |
275 | | __isl_give isl_aff *isl_aff_cow(__isl_take isl_aff *aff) |
276 | 344k | { |
277 | 344k | if (!aff) |
278 | 0 | return NULL; |
279 | 344k | |
280 | 344k | if (aff->ref == 1) |
281 | 182k | return aff; |
282 | 161k | aff->ref--; |
283 | 161k | return isl_aff_dup(aff); |
284 | 161k | } |
285 | | |
286 | | __isl_null isl_aff *isl_aff_free(__isl_take isl_aff *aff) |
287 | 3.62M | { |
288 | 3.62M | if (!aff) |
289 | 1.54M | return NULL; |
290 | 2.07M | |
291 | 2.07M | if (--aff->ref > 0) |
292 | 1.73M | return NULL; |
293 | 342k | |
294 | 342k | isl_local_space_free(aff->ls); |
295 | 342k | isl_vec_free(aff->v); |
296 | 342k | |
297 | 342k | free(aff); |
298 | 342k | |
299 | 342k | return NULL; |
300 | 342k | } |
301 | | |
302 | | isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff) |
303 | 2.73M | { |
304 | 2.73M | return aff ? isl_local_space_get_ctx(aff->ls) : NULL; |
305 | 2.73M | } |
306 | | |
307 | | /* Return a hash value that digests "aff". |
308 | | */ |
309 | | uint32_t isl_aff_get_hash(__isl_keep isl_aff *aff) |
310 | 0 | { |
311 | 0 | uint32_t hash, ls_hash, v_hash; |
312 | 0 |
|
313 | 0 | if (!aff) |
314 | 0 | return 0; |
315 | 0 | |
316 | 0 | hash = isl_hash_init(); |
317 | 0 | ls_hash = isl_local_space_get_hash(aff->ls); |
318 | 0 | isl_hash_hash(hash, ls_hash); |
319 | 0 | v_hash = isl_vec_get_hash(aff->v); |
320 | 0 | isl_hash_hash(hash, v_hash); |
321 | 0 |
|
322 | 0 | return hash; |
323 | 0 | } |
324 | | |
325 | | /* Externally, an isl_aff has a map space, but internally, the |
326 | | * ls field corresponds to the domain of that space. |
327 | | */ |
328 | | int isl_aff_dim(__isl_keep isl_aff *aff, enum isl_dim_type type) |
329 | 421k | { |
330 | 421k | if (!aff) |
331 | 0 | return 0; |
332 | 421k | if (type == isl_dim_out) |
333 | 0 | return 1; |
334 | 421k | if (type == isl_dim_in) |
335 | 36.3k | type = isl_dim_set; |
336 | 421k | return isl_local_space_dim(aff->ls, type); |
337 | 421k | } |
338 | | |
339 | | /* Return the position of the dimension of the given type and name |
340 | | * in "aff". |
341 | | * Return -1 if no such dimension can be found. |
342 | | */ |
343 | | int isl_aff_find_dim_by_name(__isl_keep isl_aff *aff, enum isl_dim_type type, |
344 | | const char *name) |
345 | 0 | { |
346 | 0 | if (!aff) |
347 | 0 | return -1; |
348 | 0 | if (type == isl_dim_out) |
349 | 0 | return -1; |
350 | 0 | if (type == isl_dim_in) |
351 | 0 | type = isl_dim_set; |
352 | 0 | return isl_local_space_find_dim_by_name(aff->ls, type, name); |
353 | 0 | } |
354 | | |
355 | | /* Return the domain space of "aff". |
356 | | */ |
357 | | static __isl_keep isl_space *isl_aff_peek_domain_space(__isl_keep isl_aff *aff) |
358 | 3.17M | { |
359 | 3.17M | return aff ? isl_local_space_peek_space(aff->ls)3.17M : NULL; |
360 | 3.17M | } |
361 | | |
362 | | __isl_give isl_space *isl_aff_get_domain_space(__isl_keep isl_aff *aff) |
363 | 3.17M | { |
364 | 3.17M | return isl_space_copy(isl_aff_peek_domain_space(aff)); |
365 | 3.17M | } |
366 | | |
367 | | __isl_give isl_space *isl_aff_get_space(__isl_keep isl_aff *aff) |
368 | 416k | { |
369 | 416k | isl_space *space; |
370 | 416k | if (!aff) |
371 | 0 | return NULL; |
372 | 416k | space = isl_local_space_get_space(aff->ls); |
373 | 416k | space = isl_space_from_domain(space); |
374 | 416k | space = isl_space_add_dims(space, isl_dim_out, 1); |
375 | 416k | return space; |
376 | 416k | } |
377 | | |
378 | | __isl_give isl_local_space *isl_aff_get_domain_local_space( |
379 | | __isl_keep isl_aff *aff) |
380 | 82.4k | { |
381 | 82.4k | return aff ? isl_local_space_copy(aff->ls) : NULL; |
382 | 82.4k | } |
383 | | |
384 | | __isl_give isl_local_space *isl_aff_get_local_space(__isl_keep isl_aff *aff) |
385 | 80.2k | { |
386 | 80.2k | isl_local_space *ls; |
387 | 80.2k | if (!aff) |
388 | 0 | return NULL; |
389 | 80.2k | ls = isl_local_space_copy(aff->ls); |
390 | 80.2k | ls = isl_local_space_from_domain(ls); |
391 | 80.2k | ls = isl_local_space_add_dims(ls, isl_dim_out, 1); |
392 | 80.2k | return ls; |
393 | 80.2k | } |
394 | | |
395 | | /* Return the local space of the domain of "aff". |
396 | | * This may be either a copy or the local space itself |
397 | | * if there is only one reference to "aff". |
398 | | * This allows the local space to be modified inplace |
399 | | * if both the expression and its local space have only a single reference. |
400 | | * The caller is not allowed to modify "aff" between this call and |
401 | | * a subsequent call to isl_aff_restore_domain_local_space. |
402 | | * The only exception is that isl_aff_free can be called instead. |
403 | | */ |
404 | | __isl_give isl_local_space *isl_aff_take_domain_local_space( |
405 | | __isl_keep isl_aff *aff) |
406 | 0 | { |
407 | 0 | isl_local_space *ls; |
408 | 0 |
|
409 | 0 | if (!aff) |
410 | 0 | return NULL; |
411 | 0 | if (aff->ref != 1) |
412 | 0 | return isl_aff_get_domain_local_space(aff); |
413 | 0 | ls = aff->ls; |
414 | 0 | aff->ls = NULL; |
415 | 0 | return ls; |
416 | 0 | } |
417 | | |
418 | | /* Set the local space of the domain of "aff" to "ls", |
419 | | * where the local space of "aff" may be missing |
420 | | * due to a preceding call to isl_aff_take_domain_local_space. |
421 | | * However, in this case, "aff" only has a single reference and |
422 | | * then the call to isl_aff_cow has no effect. |
423 | | */ |
424 | | __isl_give isl_aff *isl_aff_restore_domain_local_space( |
425 | | __isl_keep isl_aff *aff, __isl_take isl_local_space *ls) |
426 | 0 | { |
427 | 0 | if (!aff || !ls) |
428 | 0 | goto error; |
429 | 0 | |
430 | 0 | if (aff->ls == ls) { |
431 | 0 | isl_local_space_free(ls); |
432 | 0 | return aff; |
433 | 0 | } |
434 | 0 | |
435 | 0 | aff = isl_aff_cow(aff); |
436 | 0 | if (!aff) |
437 | 0 | goto error; |
438 | 0 | isl_local_space_free(aff->ls); |
439 | 0 | aff->ls = ls; |
440 | 0 |
|
441 | 0 | return aff; |
442 | 0 | error: |
443 | 0 | isl_aff_free(aff); |
444 | 0 | isl_local_space_free(ls); |
445 | 0 | return NULL; |
446 | 0 | } |
447 | | |
448 | | /* Externally, an isl_aff has a map space, but internally, the |
449 | | * ls field corresponds to the domain of that space. |
450 | | */ |
451 | | const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff, |
452 | | enum isl_dim_type type, unsigned pos) |
453 | 0 | { |
454 | 0 | if (!aff) |
455 | 0 | return NULL; |
456 | 0 | if (type == isl_dim_out) |
457 | 0 | return NULL; |
458 | 0 | if (type == isl_dim_in) |
459 | 0 | type = isl_dim_set; |
460 | 0 | return isl_local_space_get_dim_name(aff->ls, type, pos); |
461 | 0 | } |
462 | | |
463 | | __isl_give isl_aff *isl_aff_reset_domain_space(__isl_take isl_aff *aff, |
464 | | __isl_take isl_space *dim) |
465 | 89.4k | { |
466 | 89.4k | aff = isl_aff_cow(aff); |
467 | 89.4k | if (!aff || !dim) |
468 | 0 | goto error; |
469 | 89.4k | |
470 | 89.4k | aff->ls = isl_local_space_reset_space(aff->ls, dim); |
471 | 89.4k | if (!aff->ls) |
472 | 0 | return isl_aff_free(aff); |
473 | 89.4k | |
474 | 89.4k | return aff; |
475 | 0 | error: |
476 | 0 | isl_aff_free(aff); |
477 | 0 | isl_space_free(dim); |
478 | 0 | return NULL; |
479 | 89.4k | } |
480 | | |
481 | | /* Reset the space of "aff". This function is called from isl_pw_templ.c |
482 | | * and doesn't know if the space of an element object is represented |
483 | | * directly or through its domain. It therefore passes along both. |
484 | | */ |
485 | | __isl_give isl_aff *isl_aff_reset_space_and_domain(__isl_take isl_aff *aff, |
486 | | __isl_take isl_space *space, __isl_take isl_space *domain) |
487 | 70.5k | { |
488 | 70.5k | isl_space_free(space); |
489 | 70.5k | return isl_aff_reset_domain_space(aff, domain); |
490 | 70.5k | } |
491 | | |
492 | | /* Reorder the coefficients of the affine expression based |
493 | | * on the given reordering. |
494 | | * The reordering r is assumed to have been extended with the local |
495 | | * variables. |
496 | | */ |
497 | | static __isl_give isl_vec *vec_reorder(__isl_take isl_vec *vec, |
498 | | __isl_take isl_reordering *r, int n_div) |
499 | 10.2k | { |
500 | 10.2k | isl_space *space; |
501 | 10.2k | isl_vec *res; |
502 | 10.2k | int i; |
503 | 10.2k | |
504 | 10.2k | if (!vec || !r) |
505 | 0 | goto error; |
506 | 10.2k | |
507 | 10.2k | space = isl_reordering_peek_space(r); |
508 | 10.2k | res = isl_vec_alloc(vec->ctx, |
509 | 10.2k | 2 + isl_space_dim(space, isl_dim_all) + n_div); |
510 | 10.2k | if (!res) |
511 | 0 | goto error; |
512 | 10.2k | isl_seq_cpy(res->el, vec->el, 2); |
513 | 10.2k | isl_seq_clr(res->el + 2, res->size - 2); |
514 | 29.8k | for (i = 0; i < r->len; ++i19.5k ) |
515 | 19.5k | isl_int_set(res->el[2 + r->pos[i]], vec->el[2 + i]); |
516 | 10.2k | |
517 | 10.2k | isl_reordering_free(r); |
518 | 10.2k | isl_vec_free(vec); |
519 | 10.2k | return res; |
520 | 0 | error: |
521 | 0 | isl_vec_free(vec); |
522 | 0 | isl_reordering_free(r); |
523 | 0 | return NULL; |
524 | 10.2k | } |
525 | | |
526 | | /* Reorder the dimensions of the domain of "aff" according |
527 | | * to the given reordering. |
528 | | */ |
529 | | __isl_give isl_aff *isl_aff_realign_domain(__isl_take isl_aff *aff, |
530 | | __isl_take isl_reordering *r) |
531 | 10.2k | { |
532 | 10.2k | aff = isl_aff_cow(aff); |
533 | 10.2k | if (!aff) |
534 | 0 | goto error; |
535 | 10.2k | |
536 | 10.2k | r = isl_reordering_extend(r, aff->ls->div->n_row); |
537 | 10.2k | aff->v = vec_reorder(aff->v, isl_reordering_copy(r), |
538 | 10.2k | aff->ls->div->n_row); |
539 | 10.2k | aff->ls = isl_local_space_realign(aff->ls, r); |
540 | 10.2k | |
541 | 10.2k | if (!aff->v || !aff->ls) |
542 | 0 | return isl_aff_free(aff); |
543 | 10.2k | |
544 | 10.2k | return aff; |
545 | 0 | error: |
546 | 0 | isl_aff_free(aff); |
547 | 0 | isl_reordering_free(r); |
548 | 0 | return NULL; |
549 | 10.2k | } |
550 | | |
551 | | __isl_give isl_aff *isl_aff_align_params(__isl_take isl_aff *aff, |
552 | | __isl_take isl_space *model) |
553 | 1 | { |
554 | 1 | isl_bool equal_params; |
555 | 1 | |
556 | 1 | if (!aff || !model) |
557 | 0 | goto error; |
558 | 1 | |
559 | 1 | equal_params = isl_space_has_equal_params(aff->ls->dim, model); |
560 | 1 | if (equal_params < 0) |
561 | 0 | goto error; |
562 | 1 | if (!equal_params) { |
563 | 0 | isl_reordering *exp; |
564 | 0 |
|
565 | 0 | exp = isl_parameter_alignment_reordering(aff->ls->dim, model); |
566 | 0 | exp = isl_reordering_extend_space(exp, |
567 | 0 | isl_aff_get_domain_space(aff)); |
568 | 0 | aff = isl_aff_realign_domain(aff, exp); |
569 | 0 | } |
570 | 1 | |
571 | 1 | isl_space_free(model); |
572 | 1 | return aff; |
573 | 0 | error: |
574 | 0 | isl_space_free(model); |
575 | 0 | isl_aff_free(aff); |
576 | 0 | return NULL; |
577 | 1 | } |
578 | | |
579 | | /* Is "aff" obviously equal to zero? |
580 | | * |
581 | | * If the denominator is zero, then "aff" is not equal to zero. |
582 | | */ |
583 | | isl_bool isl_aff_plain_is_zero(__isl_keep isl_aff *aff) |
584 | 1 | { |
585 | 1 | if (!aff) |
586 | 0 | return isl_bool_error; |
587 | 1 | |
588 | 1 | if (isl_int_is_zero(aff->v->el[0])) |
589 | 1 | return isl_bool_false0 ; |
590 | 1 | return isl_seq_first_non_zero(aff->v->el + 1, aff->v->size - 1) < 0; |
591 | 1 | } |
592 | | |
593 | | /* Does "aff" represent NaN? |
594 | | */ |
595 | | isl_bool isl_aff_is_nan(__isl_keep isl_aff *aff) |
596 | 550k | { |
597 | 550k | if (!aff) |
598 | 0 | return isl_bool_error; |
599 | 550k | |
600 | 550k | return isl_seq_first_non_zero(aff->v->el, 2) < 0; |
601 | 550k | } |
602 | | |
603 | | /* Are "aff1" and "aff2" obviously equal? |
604 | | * |
605 | | * NaN is not equal to anything, not even to another NaN. |
606 | | */ |
607 | | isl_bool isl_aff_plain_is_equal(__isl_keep isl_aff *aff1, |
608 | | __isl_keep isl_aff *aff2) |
609 | 8.10k | { |
610 | 8.10k | isl_bool equal; |
611 | 8.10k | |
612 | 8.10k | if (!aff1 || !aff2) |
613 | 0 | return isl_bool_error; |
614 | 8.10k | |
615 | 8.10k | if (isl_aff_is_nan(aff1) || isl_aff_is_nan(aff2)) |
616 | 0 | return isl_bool_false; |
617 | 8.10k | |
618 | 8.10k | equal = isl_local_space_is_equal(aff1->ls, aff2->ls); |
619 | 8.10k | if (equal < 0 || !equal) |
620 | 1.59k | return equal; |
621 | 6.51k | |
622 | 6.51k | return isl_vec_is_equal(aff1->v, aff2->v); |
623 | 6.51k | } |
624 | | |
625 | | /* Return the common denominator of "aff" in "v". |
626 | | * |
627 | | * We cannot return anything meaningful in case of a NaN. |
628 | | */ |
629 | | isl_stat isl_aff_get_denominator(__isl_keep isl_aff *aff, isl_int *v) |
630 | 0 | { |
631 | 0 | if (!aff) |
632 | 0 | return isl_stat_error; |
633 | 0 | if (isl_aff_is_nan(aff)) |
634 | 0 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
635 | 0 | "cannot get denominator of NaN", return isl_stat_error); |
636 | 0 | isl_int_set(*v, aff->v->el[0]); |
637 | 0 | return isl_stat_ok; |
638 | 0 | } |
639 | | |
640 | | /* Return the common denominator of "aff". |
641 | | */ |
642 | | __isl_give isl_val *isl_aff_get_denominator_val(__isl_keep isl_aff *aff) |
643 | 8.80k | { |
644 | 8.80k | isl_ctx *ctx; |
645 | 8.80k | |
646 | 8.80k | if (!aff) |
647 | 0 | return NULL; |
648 | 8.80k | |
649 | 8.80k | ctx = isl_aff_get_ctx(aff); |
650 | 8.80k | if (isl_aff_is_nan(aff)) |
651 | 0 | return isl_val_nan(ctx); |
652 | 8.80k | return isl_val_int_from_isl_int(ctx, aff->v->el[0]); |
653 | 8.80k | } |
654 | | |
655 | | /* Return the constant term of "aff". |
656 | | */ |
657 | | __isl_give isl_val *isl_aff_get_constant_val(__isl_keep isl_aff *aff) |
658 | 10.1k | { |
659 | 10.1k | isl_ctx *ctx; |
660 | 10.1k | isl_val *v; |
661 | 10.1k | |
662 | 10.1k | if (!aff) |
663 | 0 | return NULL; |
664 | 10.1k | |
665 | 10.1k | ctx = isl_aff_get_ctx(aff); |
666 | 10.1k | if (isl_aff_is_nan(aff)) |
667 | 0 | return isl_val_nan(ctx); |
668 | 10.1k | v = isl_val_rat_from_isl_int(ctx, aff->v->el[1], aff->v->el[0]); |
669 | 10.1k | return isl_val_normalize(v); |
670 | 10.1k | } |
671 | | |
672 | | /* Return the coefficient of the variable of type "type" at position "pos" |
673 | | * of "aff". |
674 | | */ |
675 | | __isl_give isl_val *isl_aff_get_coefficient_val(__isl_keep isl_aff *aff, |
676 | | enum isl_dim_type type, int pos) |
677 | 59.6k | { |
678 | 59.6k | isl_ctx *ctx; |
679 | 59.6k | isl_val *v; |
680 | 59.6k | |
681 | 59.6k | if (!aff) |
682 | 0 | return NULL; |
683 | 59.6k | |
684 | 59.6k | ctx = isl_aff_get_ctx(aff); |
685 | 59.6k | if (type == isl_dim_out) |
686 | 59.6k | isl_die0 (ctx, isl_error_invalid, |
687 | 59.6k | "output/set dimension does not have a coefficient", |
688 | 59.6k | return NULL); |
689 | 59.6k | if (type == isl_dim_in) |
690 | 50.9k | type = isl_dim_set; |
691 | 59.6k | |
692 | 59.6k | if (pos >= isl_local_space_dim(aff->ls, type)) |
693 | 59.6k | isl_die0 (ctx, isl_error_invalid, |
694 | 59.6k | "position out of bounds", return NULL); |
695 | 59.6k | |
696 | 59.6k | if (isl_aff_is_nan(aff)) |
697 | 0 | return isl_val_nan(ctx); |
698 | 59.6k | pos += isl_local_space_offset(aff->ls, type); |
699 | 59.6k | v = isl_val_rat_from_isl_int(ctx, aff->v->el[1 + pos], aff->v->el[0]); |
700 | 59.6k | return isl_val_normalize(v); |
701 | 59.6k | } |
702 | | |
703 | | /* Return the sign of the coefficient of the variable of type "type" |
704 | | * at position "pos" of "aff". |
705 | | */ |
706 | | int isl_aff_coefficient_sgn(__isl_keep isl_aff *aff, enum isl_dim_type type, |
707 | | int pos) |
708 | 86 | { |
709 | 86 | isl_ctx *ctx; |
710 | 86 | |
711 | 86 | if (!aff) |
712 | 0 | return 0; |
713 | 86 | |
714 | 86 | ctx = isl_aff_get_ctx(aff); |
715 | 86 | if (type == isl_dim_out) |
716 | 86 | isl_die0 (ctx, isl_error_invalid, |
717 | 86 | "output/set dimension does not have a coefficient", |
718 | 86 | return 0); |
719 | 86 | if (type == isl_dim_in) |
720 | 63 | type = isl_dim_set; |
721 | 86 | |
722 | 86 | if (pos >= isl_local_space_dim(aff->ls, type)) |
723 | 86 | isl_die0 (ctx, isl_error_invalid, |
724 | 86 | "position out of bounds", return 0); |
725 | 86 | |
726 | 86 | pos += isl_local_space_offset(aff->ls, type); |
727 | 86 | return isl_int_sgn(aff->v->el[1 + pos]); |
728 | 86 | } |
729 | | |
730 | | /* Replace the numerator of the constant term of "aff" by "v". |
731 | | * |
732 | | * A NaN is unaffected by this operation. |
733 | | */ |
734 | | __isl_give isl_aff *isl_aff_set_constant(__isl_take isl_aff *aff, isl_int v) |
735 | 1.02k | { |
736 | 1.02k | if (!aff) |
737 | 0 | return NULL; |
738 | 1.02k | if (isl_aff_is_nan(aff)) |
739 | 0 | return aff; |
740 | 1.02k | aff = isl_aff_cow(aff); |
741 | 1.02k | if (!aff) |
742 | 0 | return NULL; |
743 | 1.02k | |
744 | 1.02k | aff->v = isl_vec_cow(aff->v); |
745 | 1.02k | if (!aff->v) |
746 | 0 | return isl_aff_free(aff); |
747 | 1.02k | |
748 | 1.02k | isl_int_set(aff->v->el[1], v); |
749 | 1.02k | |
750 | 1.02k | return aff; |
751 | 1.02k | } |
752 | | |
753 | | /* Replace the constant term of "aff" by "v". |
754 | | * |
755 | | * A NaN is unaffected by this operation. |
756 | | */ |
757 | | __isl_give isl_aff *isl_aff_set_constant_val(__isl_take isl_aff *aff, |
758 | | __isl_take isl_val *v) |
759 | 12 | { |
760 | 12 | if (!aff || !v) |
761 | 0 | goto error; |
762 | 12 | |
763 | 12 | if (isl_aff_is_nan(aff)) { |
764 | 0 | isl_val_free(v); |
765 | 0 | return aff; |
766 | 0 | } |
767 | 12 | |
768 | 12 | if (!isl_val_is_rat(v)) |
769 | 12 | isl_die0 (isl_aff_get_ctx(aff), isl_error_invalid, |
770 | 12 | "expecting rational value", goto error); |
771 | 12 | |
772 | 12 | if (isl_int_eq(aff->v->el[1], v->n) && |
773 | 12 | isl_int_eq10 (aff->v->el[0], v->d)) { |
774 | 10 | isl_val_free(v); |
775 | 10 | return aff; |
776 | 10 | } |
777 | 2 | |
778 | 2 | aff = isl_aff_cow(aff); |
779 | 2 | if (!aff) |
780 | 0 | goto error; |
781 | 2 | aff->v = isl_vec_cow(aff->v); |
782 | 2 | if (!aff->v) |
783 | 0 | goto error; |
784 | 2 | |
785 | 2 | if (isl_int_eq(aff->v->el[0], v->d)) { |
786 | 2 | isl_int_set(aff->v->el[1], v->n); |
787 | 2 | } else if (0 isl_int_is_one0 (v->d)) { |
788 | 0 | isl_int_mul(aff->v->el[1], aff->v->el[0], v->n); |
789 | 0 | } else { |
790 | 0 | isl_seq_scale(aff->v->el + 1, |
791 | 0 | aff->v->el + 1, v->d, aff->v->size - 1); |
792 | 0 | isl_int_mul(aff->v->el[1], aff->v->el[0], v->n); |
793 | 0 | isl_int_mul(aff->v->el[0], aff->v->el[0], v->d); |
794 | 0 | aff->v = isl_vec_normalize(aff->v); |
795 | 0 | if (!aff->v) |
796 | 0 | goto error; |
797 | 2 | } |
798 | 2 | |
799 | 2 | isl_val_free(v); |
800 | 2 | return aff; |
801 | 0 | error: |
802 | 0 | isl_aff_free(aff); |
803 | 0 | isl_val_free(v); |
804 | 0 | return NULL; |
805 | 2 | } |
806 | | |
807 | | /* Add "v" to the constant term of "aff". |
808 | | * |
809 | | * A NaN is unaffected by this operation. |
810 | | */ |
811 | | __isl_give isl_aff *isl_aff_add_constant(__isl_take isl_aff *aff, isl_int v) |
812 | 23.7k | { |
813 | 23.7k | if (isl_int_is_zero(v)) |
814 | 23.7k | return aff4.71k ; |
815 | 19.0k | |
816 | 19.0k | if (!aff) |
817 | 3 | return NULL; |
818 | 19.0k | if (isl_aff_is_nan(aff)) |
819 | 0 | return aff; |
820 | 19.0k | aff = isl_aff_cow(aff); |
821 | 19.0k | if (!aff) |
822 | 0 | return NULL; |
823 | 19.0k | |
824 | 19.0k | aff->v = isl_vec_cow(aff->v); |
825 | 19.0k | if (!aff->v) |
826 | 0 | return isl_aff_free(aff); |
827 | 19.0k | |
828 | 19.0k | isl_int_addmul(aff->v->el[1], aff->v->el[0], v); |
829 | 19.0k | |
830 | 19.0k | return aff; |
831 | 19.0k | } |
832 | | |
833 | | /* Add "v" to the constant term of "aff". |
834 | | * |
835 | | * A NaN is unaffected by this operation. |
836 | | */ |
837 | | __isl_give isl_aff *isl_aff_add_constant_val(__isl_take isl_aff *aff, |
838 | | __isl_take isl_val *v) |
839 | 32 | { |
840 | 32 | if (!aff || !v) |
841 | 0 | goto error; |
842 | 32 | |
843 | 32 | if (isl_aff_is_nan(aff) || isl_val_is_zero(v)) { |
844 | 0 | isl_val_free(v); |
845 | 0 | return aff; |
846 | 0 | } |
847 | 32 | |
848 | 32 | if (!isl_val_is_rat(v)) |
849 | 32 | isl_die0 (isl_aff_get_ctx(aff), isl_error_invalid, |
850 | 32 | "expecting rational value", goto error); |
851 | 32 | |
852 | 32 | aff = isl_aff_cow(aff); |
853 | 32 | if (!aff) |
854 | 0 | goto error; |
855 | 32 | |
856 | 32 | aff->v = isl_vec_cow(aff->v); |
857 | 32 | if (!aff->v) |
858 | 0 | goto error; |
859 | 32 | |
860 | 32 | if (isl_int_is_one(v->d)) { |
861 | 32 | isl_int_addmul(aff->v->el[1], aff->v->el[0], v->n); |
862 | 32 | } else if (0 isl_int_eq0 (aff->v->el[0], v->d)) { |
863 | 0 | isl_int_add(aff->v->el[1], aff->v->el[1], v->n); |
864 | 0 | aff->v = isl_vec_normalize(aff->v); |
865 | 0 | if (!aff->v) |
866 | 0 | goto error; |
867 | 0 | } else { |
868 | 0 | isl_seq_scale(aff->v->el + 1, |
869 | 0 | aff->v->el + 1, v->d, aff->v->size - 1); |
870 | 0 | isl_int_addmul(aff->v->el[1], aff->v->el[0], v->n); |
871 | 0 | isl_int_mul(aff->v->el[0], aff->v->el[0], v->d); |
872 | 0 | aff->v = isl_vec_normalize(aff->v); |
873 | 0 | if (!aff->v) |
874 | 0 | goto error; |
875 | 32 | } |
876 | 32 | |
877 | 32 | isl_val_free(v); |
878 | 32 | return aff; |
879 | 0 | error: |
880 | 0 | isl_aff_free(aff); |
881 | 0 | isl_val_free(v); |
882 | 0 | return NULL; |
883 | 32 | } |
884 | | |
885 | | __isl_give isl_aff *isl_aff_add_constant_si(__isl_take isl_aff *aff, int v) |
886 | 17.6k | { |
887 | 17.6k | isl_int t; |
888 | 17.6k | |
889 | 17.6k | isl_int_init(t); |
890 | 17.6k | isl_int_set_si(t, v); |
891 | 17.6k | aff = isl_aff_add_constant(aff, t); |
892 | 17.6k | isl_int_clear(t); |
893 | 17.6k | |
894 | 17.6k | return aff; |
895 | 17.6k | } |
896 | | |
897 | | /* Add "v" to the numerator of the constant term of "aff". |
898 | | * |
899 | | * A NaN is unaffected by this operation. |
900 | | */ |
901 | | __isl_give isl_aff *isl_aff_add_constant_num(__isl_take isl_aff *aff, isl_int v) |
902 | 153 | { |
903 | 153 | if (isl_int_is_zero(v)) |
904 | 153 | return aff0 ; |
905 | 153 | |
906 | 153 | if (!aff) |
907 | 0 | return NULL; |
908 | 153 | if (isl_aff_is_nan(aff)) |
909 | 0 | return aff; |
910 | 153 | aff = isl_aff_cow(aff); |
911 | 153 | if (!aff) |
912 | 0 | return NULL; |
913 | 153 | |
914 | 153 | aff->v = isl_vec_cow(aff->v); |
915 | 153 | if (!aff->v) |
916 | 0 | return isl_aff_free(aff); |
917 | 153 | |
918 | 153 | isl_int_add(aff->v->el[1], aff->v->el[1], v); |
919 | 153 | |
920 | 153 | return aff; |
921 | 153 | } |
922 | | |
923 | | /* Add "v" to the numerator of the constant term of "aff". |
924 | | * |
925 | | * A NaN is unaffected by this operation. |
926 | | */ |
927 | | __isl_give isl_aff *isl_aff_add_constant_num_si(__isl_take isl_aff *aff, int v) |
928 | 153 | { |
929 | 153 | isl_int t; |
930 | 153 | |
931 | 153 | if (v == 0) |
932 | 0 | return aff; |
933 | 153 | |
934 | 153 | isl_int_init(t); |
935 | 153 | isl_int_set_si(t, v); |
936 | 153 | aff = isl_aff_add_constant_num(aff, t); |
937 | 153 | isl_int_clear(t); |
938 | 153 | |
939 | 153 | return aff; |
940 | 153 | } |
941 | | |
942 | | /* Replace the numerator of the constant term of "aff" by "v". |
943 | | * |
944 | | * A NaN is unaffected by this operation. |
945 | | */ |
946 | | __isl_give isl_aff *isl_aff_set_constant_si(__isl_take isl_aff *aff, int v) |
947 | 949 | { |
948 | 949 | if (!aff) |
949 | 0 | return NULL; |
950 | 949 | if (isl_aff_is_nan(aff)) |
951 | 0 | return aff; |
952 | 949 | aff = isl_aff_cow(aff); |
953 | 949 | if (!aff) |
954 | 0 | return NULL; |
955 | 949 | |
956 | 949 | aff->v = isl_vec_cow(aff->v); |
957 | 949 | if (!aff->v) |
958 | 0 | return isl_aff_free(aff); |
959 | 949 | |
960 | 949 | isl_int_set_si(aff->v->el[1], v); |
961 | 949 | |
962 | 949 | return aff; |
963 | 949 | } |
964 | | |
965 | | /* Replace the numerator of the coefficient of the variable of type "type" |
966 | | * at position "pos" of "aff" by "v". |
967 | | * |
968 | | * A NaN is unaffected by this operation. |
969 | | */ |
970 | | __isl_give isl_aff *isl_aff_set_coefficient(__isl_take isl_aff *aff, |
971 | | enum isl_dim_type type, int pos, isl_int v) |
972 | 2.42k | { |
973 | 2.42k | if (!aff) |
974 | 0 | return NULL; |
975 | 2.42k | |
976 | 2.42k | if (type == isl_dim_out) |
977 | 2.42k | isl_die0 (aff->v->ctx, isl_error_invalid, |
978 | 2.42k | "output/set dimension does not have a coefficient", |
979 | 2.42k | return isl_aff_free(aff)); |
980 | 2.42k | if (type == isl_dim_in) |
981 | 1.85k | type = isl_dim_set; |
982 | 2.42k | |
983 | 2.42k | if (pos >= isl_local_space_dim(aff->ls, type)) |
984 | 2.42k | isl_die0 (aff->v->ctx, isl_error_invalid, |
985 | 2.42k | "position out of bounds", return isl_aff_free(aff)); |
986 | 2.42k | |
987 | 2.42k | if (isl_aff_is_nan(aff)) |
988 | 0 | return aff; |
989 | 2.42k | aff = isl_aff_cow(aff); |
990 | 2.42k | if (!aff) |
991 | 0 | return NULL; |
992 | 2.42k | |
993 | 2.42k | aff->v = isl_vec_cow(aff->v); |
994 | 2.42k | if (!aff->v) |
995 | 0 | return isl_aff_free(aff); |
996 | 2.42k | |
997 | 2.42k | pos += isl_local_space_offset(aff->ls, type); |
998 | 2.42k | isl_int_set(aff->v->el[1 + pos], v); |
999 | 2.42k | |
1000 | 2.42k | return aff; |
1001 | 2.42k | } |
1002 | | |
1003 | | /* Replace the numerator of the coefficient of the variable of type "type" |
1004 | | * at position "pos" of "aff" by "v". |
1005 | | * |
1006 | | * A NaN is unaffected by this operation. |
1007 | | */ |
1008 | | __isl_give isl_aff *isl_aff_set_coefficient_si(__isl_take isl_aff *aff, |
1009 | | enum isl_dim_type type, int pos, int v) |
1010 | 3.28k | { |
1011 | 3.28k | if (!aff) |
1012 | 0 | return NULL; |
1013 | 3.28k | |
1014 | 3.28k | if (type == isl_dim_out) |
1015 | 3.28k | isl_die0 (aff->v->ctx, isl_error_invalid, |
1016 | 3.28k | "output/set dimension does not have a coefficient", |
1017 | 3.28k | return isl_aff_free(aff)); |
1018 | 3.28k | if (type == isl_dim_in) |
1019 | 3.14k | type = isl_dim_set; |
1020 | 3.28k | |
1021 | 3.28k | if (pos < 0 || pos >= isl_local_space_dim(aff->ls, type)) |
1022 | 3.28k | isl_die0 (aff->v->ctx, isl_error_invalid, |
1023 | 3.28k | "position out of bounds", return isl_aff_free(aff)); |
1024 | 3.28k | |
1025 | 3.28k | if (isl_aff_is_nan(aff)) |
1026 | 0 | return aff; |
1027 | 3.28k | pos += isl_local_space_offset(aff->ls, type); |
1028 | 3.28k | if (isl_int_cmp_si(aff->v->el[1 + pos], v) == 0) |
1029 | 2 | return aff; |
1030 | 3.28k | |
1031 | 3.28k | aff = isl_aff_cow(aff); |
1032 | 3.28k | if (!aff) |
1033 | 0 | return NULL; |
1034 | 3.28k | |
1035 | 3.28k | aff->v = isl_vec_cow(aff->v); |
1036 | 3.28k | if (!aff->v) |
1037 | 0 | return isl_aff_free(aff); |
1038 | 3.28k | |
1039 | 3.28k | isl_int_set_si(aff->v->el[1 + pos], v); |
1040 | 3.28k | |
1041 | 3.28k | return aff; |
1042 | 3.28k | } |
1043 | | |
1044 | | /* Replace the coefficient of the variable of type "type" at position "pos" |
1045 | | * of "aff" by "v". |
1046 | | * |
1047 | | * A NaN is unaffected by this operation. |
1048 | | */ |
1049 | | __isl_give isl_aff *isl_aff_set_coefficient_val(__isl_take isl_aff *aff, |
1050 | | enum isl_dim_type type, int pos, __isl_take isl_val *v) |
1051 | 0 | { |
1052 | 0 | if (!aff || !v) |
1053 | 0 | goto error; |
1054 | 0 | |
1055 | 0 | if (type == isl_dim_out) |
1056 | 0 | isl_die(aff->v->ctx, isl_error_invalid, |
1057 | 0 | "output/set dimension does not have a coefficient", |
1058 | 0 | goto error); |
1059 | 0 | if (type == isl_dim_in) |
1060 | 0 | type = isl_dim_set; |
1061 | 0 |
|
1062 | 0 | if (pos >= isl_local_space_dim(aff->ls, type)) |
1063 | 0 | isl_die(aff->v->ctx, isl_error_invalid, |
1064 | 0 | "position out of bounds", goto error); |
1065 | 0 |
|
1066 | 0 | if (isl_aff_is_nan(aff)) { |
1067 | 0 | isl_val_free(v); |
1068 | 0 | return aff; |
1069 | 0 | } |
1070 | 0 | if (!isl_val_is_rat(v)) |
1071 | 0 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
1072 | 0 | "expecting rational value", goto error); |
1073 | 0 |
|
1074 | 0 | pos += isl_local_space_offset(aff->ls, type); |
1075 | 0 | if (isl_int_eq(aff->v->el[1 + pos], v->n) && |
1076 | 0 | isl_int_eq(aff->v->el[0], v->d)) { |
1077 | 0 | isl_val_free(v); |
1078 | 0 | return aff; |
1079 | 0 | } |
1080 | 0 | |
1081 | 0 | aff = isl_aff_cow(aff); |
1082 | 0 | if (!aff) |
1083 | 0 | goto error; |
1084 | 0 | aff->v = isl_vec_cow(aff->v); |
1085 | 0 | if (!aff->v) |
1086 | 0 | goto error; |
1087 | 0 | |
1088 | 0 | if (isl_int_eq(aff->v->el[0], v->d)) { |
1089 | 0 | isl_int_set(aff->v->el[1 + pos], v->n); |
1090 | 0 | } else if (isl_int_is_one(v->d)) { |
1091 | 0 | isl_int_mul(aff->v->el[1 + pos], aff->v->el[0], v->n); |
1092 | 0 | } else { |
1093 | 0 | isl_seq_scale(aff->v->el + 1, |
1094 | 0 | aff->v->el + 1, v->d, aff->v->size - 1); |
1095 | 0 | isl_int_mul(aff->v->el[1 + pos], aff->v->el[0], v->n); |
1096 | 0 | isl_int_mul(aff->v->el[0], aff->v->el[0], v->d); |
1097 | 0 | aff->v = isl_vec_normalize(aff->v); |
1098 | 0 | if (!aff->v) |
1099 | 0 | goto error; |
1100 | 0 | } |
1101 | 0 | |
1102 | 0 | isl_val_free(v); |
1103 | 0 | return aff; |
1104 | 0 | error: |
1105 | 0 | isl_aff_free(aff); |
1106 | 0 | isl_val_free(v); |
1107 | 0 | return NULL; |
1108 | 0 | } |
1109 | | |
1110 | | /* Add "v" to the coefficient of the variable of type "type" |
1111 | | * at position "pos" of "aff". |
1112 | | * |
1113 | | * A NaN is unaffected by this operation. |
1114 | | */ |
1115 | | __isl_give isl_aff *isl_aff_add_coefficient(__isl_take isl_aff *aff, |
1116 | | enum isl_dim_type type, int pos, isl_int v) |
1117 | 22.3k | { |
1118 | 22.3k | if (!aff) |
1119 | 0 | return NULL; |
1120 | 22.3k | |
1121 | 22.3k | if (type == isl_dim_out) |
1122 | 22.3k | isl_die0 (aff->v->ctx, isl_error_invalid, |
1123 | 22.3k | "output/set dimension does not have a coefficient", |
1124 | 22.3k | return isl_aff_free(aff)); |
1125 | 22.3k | if (type == isl_dim_in) |
1126 | 20.4k | type = isl_dim_set; |
1127 | 22.3k | |
1128 | 22.3k | if (pos >= isl_local_space_dim(aff->ls, type)) |
1129 | 22.3k | isl_die0 (aff->v->ctx, isl_error_invalid, |
1130 | 22.3k | "position out of bounds", return isl_aff_free(aff)); |
1131 | 22.3k | |
1132 | 22.3k | if (isl_aff_is_nan(aff)) |
1133 | 0 | return aff; |
1134 | 22.3k | aff = isl_aff_cow(aff); |
1135 | 22.3k | if (!aff) |
1136 | 0 | return NULL; |
1137 | 22.3k | |
1138 | 22.3k | aff->v = isl_vec_cow(aff->v); |
1139 | 22.3k | if (!aff->v) |
1140 | 0 | return isl_aff_free(aff); |
1141 | 22.3k | |
1142 | 22.3k | pos += isl_local_space_offset(aff->ls, type); |
1143 | 22.3k | isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v); |
1144 | 22.3k | |
1145 | 22.3k | return aff; |
1146 | 22.3k | } |
1147 | | |
1148 | | /* Add "v" to the coefficient of the variable of type "type" |
1149 | | * at position "pos" of "aff". |
1150 | | * |
1151 | | * A NaN is unaffected by this operation. |
1152 | | */ |
1153 | | __isl_give isl_aff *isl_aff_add_coefficient_val(__isl_take isl_aff *aff, |
1154 | | enum isl_dim_type type, int pos, __isl_take isl_val *v) |
1155 | 0 | { |
1156 | 0 | if (!aff || !v) |
1157 | 0 | goto error; |
1158 | 0 | |
1159 | 0 | if (isl_val_is_zero(v)) { |
1160 | 0 | isl_val_free(v); |
1161 | 0 | return aff; |
1162 | 0 | } |
1163 | 0 | |
1164 | 0 | if (type == isl_dim_out) |
1165 | 0 | isl_die(aff->v->ctx, isl_error_invalid, |
1166 | 0 | "output/set dimension does not have a coefficient", |
1167 | 0 | goto error); |
1168 | 0 | if (type == isl_dim_in) |
1169 | 0 | type = isl_dim_set; |
1170 | 0 |
|
1171 | 0 | if (pos >= isl_local_space_dim(aff->ls, type)) |
1172 | 0 | isl_die(aff->v->ctx, isl_error_invalid, |
1173 | 0 | "position out of bounds", goto error); |
1174 | 0 |
|
1175 | 0 | if (isl_aff_is_nan(aff)) { |
1176 | 0 | isl_val_free(v); |
1177 | 0 | return aff; |
1178 | 0 | } |
1179 | 0 | if (!isl_val_is_rat(v)) |
1180 | 0 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
1181 | 0 | "expecting rational value", goto error); |
1182 | 0 |
|
1183 | 0 | aff = isl_aff_cow(aff); |
1184 | 0 | if (!aff) |
1185 | 0 | goto error; |
1186 | 0 | |
1187 | 0 | aff->v = isl_vec_cow(aff->v); |
1188 | 0 | if (!aff->v) |
1189 | 0 | goto error; |
1190 | 0 | |
1191 | 0 | pos += isl_local_space_offset(aff->ls, type); |
1192 | 0 | if (isl_int_is_one(v->d)) { |
1193 | 0 | isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v->n); |
1194 | 0 | } else if (isl_int_eq(aff->v->el[0], v->d)) { |
1195 | 0 | isl_int_add(aff->v->el[1 + pos], aff->v->el[1 + pos], v->n); |
1196 | 0 | aff->v = isl_vec_normalize(aff->v); |
1197 | 0 | if (!aff->v) |
1198 | 0 | goto error; |
1199 | 0 | } else { |
1200 | 0 | isl_seq_scale(aff->v->el + 1, |
1201 | 0 | aff->v->el + 1, v->d, aff->v->size - 1); |
1202 | 0 | isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v->n); |
1203 | 0 | isl_int_mul(aff->v->el[0], aff->v->el[0], v->d); |
1204 | 0 | aff->v = isl_vec_normalize(aff->v); |
1205 | 0 | if (!aff->v) |
1206 | 0 | goto error; |
1207 | 0 | } |
1208 | 0 | |
1209 | 0 | isl_val_free(v); |
1210 | 0 | return aff; |
1211 | 0 | error: |
1212 | 0 | isl_aff_free(aff); |
1213 | 0 | isl_val_free(v); |
1214 | 0 | return NULL; |
1215 | 0 | } |
1216 | | |
1217 | | __isl_give isl_aff *isl_aff_add_coefficient_si(__isl_take isl_aff *aff, |
1218 | | enum isl_dim_type type, int pos, int v) |
1219 | 22.3k | { |
1220 | 22.3k | isl_int t; |
1221 | 22.3k | |
1222 | 22.3k | isl_int_init(t); |
1223 | 22.3k | isl_int_set_si(t, v); |
1224 | 22.3k | aff = isl_aff_add_coefficient(aff, type, pos, t); |
1225 | 22.3k | isl_int_clear(t); |
1226 | 22.3k | |
1227 | 22.3k | return aff; |
1228 | 22.3k | } |
1229 | | |
1230 | | __isl_give isl_aff *isl_aff_get_div(__isl_keep isl_aff *aff, int pos) |
1231 | 113 | { |
1232 | 113 | if (!aff) |
1233 | 0 | return NULL; |
1234 | 113 | |
1235 | 113 | return isl_local_space_get_div(aff->ls, pos); |
1236 | 113 | } |
1237 | | |
1238 | | /* Return the negation of "aff". |
1239 | | * |
1240 | | * As a special case, -NaN = NaN. |
1241 | | */ |
1242 | | __isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff) |
1243 | 28.0k | { |
1244 | 28.0k | if (!aff) |
1245 | 0 | return NULL; |
1246 | 28.0k | if (isl_aff_is_nan(aff)) |
1247 | 1 | return aff; |
1248 | 28.0k | aff = isl_aff_cow(aff); |
1249 | 28.0k | if (!aff) |
1250 | 0 | return NULL; |
1251 | 28.0k | aff->v = isl_vec_cow(aff->v); |
1252 | 28.0k | if (!aff->v) |
1253 | 0 | return isl_aff_free(aff); |
1254 | 28.0k | |
1255 | 28.0k | isl_seq_neg(aff->v->el + 1, aff->v->el + 1, aff->v->size - 1); |
1256 | 28.0k | |
1257 | 28.0k | return aff; |
1258 | 28.0k | } |
1259 | | |
1260 | | /* Remove divs from the local space that do not appear in the affine |
1261 | | * expression. |
1262 | | * We currently only remove divs at the end. |
1263 | | * Some intermediate divs may also not appear directly in the affine |
1264 | | * expression, but we would also need to check that no other divs are |
1265 | | * defined in terms of them. |
1266 | | */ |
1267 | | __isl_give isl_aff *isl_aff_remove_unused_divs(__isl_take isl_aff *aff) |
1268 | 55.9k | { |
1269 | 55.9k | int pos; |
1270 | 55.9k | int off; |
1271 | 55.9k | int n; |
1272 | 55.9k | |
1273 | 55.9k | if (!aff) |
1274 | 0 | return NULL; |
1275 | 55.9k | |
1276 | 55.9k | n = isl_local_space_dim(aff->ls, isl_dim_div); |
1277 | 55.9k | off = isl_local_space_offset(aff->ls, isl_dim_div); |
1278 | 55.9k | |
1279 | 55.9k | pos = isl_seq_last_non_zero(aff->v->el + 1 + off, n) + 1; |
1280 | 55.9k | if (pos == n) |
1281 | 52.9k | return aff; |
1282 | 2.94k | |
1283 | 2.94k | aff = isl_aff_cow(aff); |
1284 | 2.94k | if (!aff) |
1285 | 0 | return NULL; |
1286 | 2.94k | |
1287 | 2.94k | aff->ls = isl_local_space_drop_dims(aff->ls, isl_dim_div, pos, n - pos); |
1288 | 2.94k | aff->v = isl_vec_drop_els(aff->v, 1 + off + pos, n - pos); |
1289 | 2.94k | if (!aff->ls || !aff->v) |
1290 | 0 | return isl_aff_free(aff); |
1291 | 2.94k | |
1292 | 2.94k | return aff; |
1293 | 2.94k | } |
1294 | | |
1295 | | /* Look for any divs in the aff->ls with a denominator equal to one |
1296 | | * and plug them into the affine expression and any subsequent divs |
1297 | | * that may reference the div. |
1298 | | */ |
1299 | | static __isl_give isl_aff *plug_in_integral_divs(__isl_take isl_aff *aff) |
1300 | 45.4k | { |
1301 | 45.4k | int i, n; |
1302 | 45.4k | int len; |
1303 | 45.4k | isl_int v; |
1304 | 45.4k | isl_vec *vec; |
1305 | 45.4k | isl_local_space *ls; |
1306 | 45.4k | unsigned pos; |
1307 | 45.4k | |
1308 | 45.4k | if (!aff) |
1309 | 0 | return NULL; |
1310 | 45.4k | |
1311 | 45.4k | n = isl_local_space_dim(aff->ls, isl_dim_div); |
1312 | 45.4k | len = aff->v->size; |
1313 | 56.8k | for (i = 0; i < n; ++i11.4k ) { |
1314 | 11.4k | if (!isl_int_is_one(aff->ls->div->row[i][0])) |
1315 | 11.4k | continue10.7k ; |
1316 | 773 | ls = isl_local_space_copy(aff->ls); |
1317 | 773 | ls = isl_local_space_substitute_seq(ls, isl_dim_div, i, |
1318 | 773 | aff->ls->div->row[i], len, i + 1, n - (i + 1)); |
1319 | 773 | vec = isl_vec_copy(aff->v); |
1320 | 773 | vec = isl_vec_cow(vec); |
1321 | 773 | if (!ls || !vec) |
1322 | 0 | goto error; |
1323 | 773 | |
1324 | 773 | isl_int_init(v); |
1325 | 773 | |
1326 | 773 | pos = isl_local_space_offset(aff->ls, isl_dim_div) + i; |
1327 | 773 | isl_seq_substitute(vec->el, pos, aff->ls->div->row[i], |
1328 | 773 | len, len, v); |
1329 | 773 | |
1330 | 773 | isl_int_clear(v); |
1331 | 773 | |
1332 | 773 | isl_vec_free(aff->v); |
1333 | 773 | aff->v = vec; |
1334 | 773 | isl_local_space_free(aff->ls); |
1335 | 773 | aff->ls = ls; |
1336 | 773 | } |
1337 | 45.4k | |
1338 | 45.4k | return aff; |
1339 | 0 | error: |
1340 | 0 | isl_vec_free(vec); |
1341 | 0 | isl_local_space_free(ls); |
1342 | 0 | return isl_aff_free(aff); |
1343 | 45.4k | } |
1344 | | |
1345 | | /* Look for any divs j that appear with a unit coefficient inside |
1346 | | * the definitions of other divs i and plug them into the definitions |
1347 | | * of the divs i. |
1348 | | * |
1349 | | * In particular, an expression of the form |
1350 | | * |
1351 | | * floor((f(..) + floor(g(..)/n))/m) |
1352 | | * |
1353 | | * is simplified to |
1354 | | * |
1355 | | * floor((n * f(..) + g(..))/(n * m)) |
1356 | | * |
1357 | | * This simplification is correct because we can move the expression |
1358 | | * f(..) into the inner floor in the original expression to obtain |
1359 | | * |
1360 | | * floor(floor((n * f(..) + g(..))/n)/m) |
1361 | | * |
1362 | | * from which we can derive the simplified expression. |
1363 | | */ |
1364 | | static __isl_give isl_aff *plug_in_unit_divs(__isl_take isl_aff *aff) |
1365 | 45.4k | { |
1366 | 45.4k | int i, j, n; |
1367 | 45.4k | int off; |
1368 | 45.4k | |
1369 | 45.4k | if (!aff) |
1370 | 0 | return NULL; |
1371 | 45.4k | |
1372 | 45.4k | n = isl_local_space_dim(aff->ls, isl_dim_div); |
1373 | 45.4k | off = isl_local_space_offset(aff->ls, isl_dim_div); |
1374 | 49.0k | for (i = 1; i < n; ++i3.67k ) { |
1375 | 10.0k | for (j = 0; j < i; ++j6.36k ) { |
1376 | 6.36k | if (!isl_int_is_one(aff->ls->div->row[i][1 + off + j])) |
1377 | 6.36k | continue6.16k ; |
1378 | 200 | aff->ls = isl_local_space_substitute_seq(aff->ls, |
1379 | 200 | isl_dim_div, j, aff->ls->div->row[j], |
1380 | 200 | aff->v->size, i, 1); |
1381 | 200 | if (!aff->ls) |
1382 | 0 | return isl_aff_free(aff); |
1383 | 200 | } |
1384 | 3.67k | } |
1385 | 45.4k | |
1386 | 45.4k | return aff; |
1387 | 45.4k | } |
1388 | | |
1389 | | /* Swap divs "a" and "b" in "aff", which is assumed to be non-NULL. |
1390 | | * |
1391 | | * Even though this function is only called on isl_affs with a single |
1392 | | * reference, we are careful to only change aff->v and aff->ls together. |
1393 | | */ |
1394 | | static __isl_give isl_aff *swap_div(__isl_take isl_aff *aff, int a, int b) |
1395 | 1.92k | { |
1396 | 1.92k | unsigned off = isl_local_space_offset(aff->ls, isl_dim_div); |
1397 | 1.92k | isl_local_space *ls; |
1398 | 1.92k | isl_vec *v; |
1399 | 1.92k | |
1400 | 1.92k | ls = isl_local_space_copy(aff->ls); |
1401 | 1.92k | ls = isl_local_space_swap_div(ls, a, b); |
1402 | 1.92k | v = isl_vec_copy(aff->v); |
1403 | 1.92k | v = isl_vec_cow(v); |
1404 | 1.92k | if (!ls || !v) |
1405 | 0 | goto error; |
1406 | 1.92k | |
1407 | 1.92k | isl_int_swap(v->el[1 + off + a], v->el[1 + off + b]); |
1408 | 1.92k | isl_vec_free(aff->v); |
1409 | 1.92k | aff->v = v; |
1410 | 1.92k | isl_local_space_free(aff->ls); |
1411 | 1.92k | aff->ls = ls; |
1412 | 1.92k | |
1413 | 1.92k | return aff; |
1414 | 0 | error: |
1415 | 0 | isl_vec_free(v); |
1416 | 0 | isl_local_space_free(ls); |
1417 | 0 | return isl_aff_free(aff); |
1418 | 1.92k | } |
1419 | | |
1420 | | /* Merge divs "a" and "b" in "aff", which is assumed to be non-NULL. |
1421 | | * |
1422 | | * We currently do not actually remove div "b", but simply add its |
1423 | | * coefficient to that of "a" and then zero it out. |
1424 | | */ |
1425 | | static __isl_give isl_aff *merge_divs(__isl_take isl_aff *aff, int a, int b) |
1426 | 151 | { |
1427 | 151 | unsigned off = isl_local_space_offset(aff->ls, isl_dim_div); |
1428 | 151 | |
1429 | 151 | if (isl_int_is_zero(aff->v->el[1 + off + b])) |
1430 | 151 | return aff74 ; |
1431 | 77 | |
1432 | 77 | aff->v = isl_vec_cow(aff->v); |
1433 | 77 | if (!aff->v) |
1434 | 0 | return isl_aff_free(aff); |
1435 | 77 | |
1436 | 77 | isl_int_add(aff->v->el[1 + off + a], |
1437 | 77 | aff->v->el[1 + off + a], aff->v->el[1 + off + b]); |
1438 | 77 | isl_int_set_si(aff->v->el[1 + off + b], 0); |
1439 | 77 | |
1440 | 77 | return aff; |
1441 | 77 | } |
1442 | | |
1443 | | /* Sort the divs in the local space of "aff" according to |
1444 | | * the comparison function "cmp_row" in isl_local_space.c, |
1445 | | * combining the coefficients of identical divs. |
1446 | | * |
1447 | | * Reordering divs does not change the semantics of "aff", |
1448 | | * so there is no need to call isl_aff_cow. |
1449 | | * Moreover, this function is currently only called on isl_affs |
1450 | | * with a single reference. |
1451 | | */ |
1452 | | static __isl_give isl_aff *sort_divs(__isl_take isl_aff *aff) |
1453 | 45.4k | { |
1454 | 45.4k | int i, j, n; |
1455 | 45.4k | |
1456 | 45.4k | if (!aff) |
1457 | 0 | return NULL; |
1458 | 45.4k | |
1459 | 45.4k | n = isl_aff_dim(aff, isl_dim_div); |
1460 | 49.0k | for (i = 1; i < n; ++i3.67k ) { |
1461 | 5.74k | for (j = i - 1; j >= 0; --j2.07k ) { |
1462 | 4.81k | int cmp = isl_mat_cmp_div(aff->ls->div, j, j + 1); |
1463 | 4.81k | if (cmp < 0) |
1464 | 2.74k | break; |
1465 | 2.07k | if (cmp == 0) |
1466 | 151 | aff = merge_divs(aff, j, j + 1); |
1467 | 1.92k | else |
1468 | 1.92k | aff = swap_div(aff, j, j + 1); |
1469 | 2.07k | if (!aff) |
1470 | 0 | return NULL; |
1471 | 2.07k | } |
1472 | 3.67k | } |
1473 | 45.4k | |
1474 | 45.4k | return aff; |
1475 | 45.4k | } |
1476 | | |
1477 | | /* Normalize the representation of "aff". |
1478 | | * |
1479 | | * This function should only be called of "new" isl_affs, i.e., |
1480 | | * with only a single reference. We therefore do not need to |
1481 | | * worry about affecting other instances. |
1482 | | */ |
1483 | | __isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *aff) |
1484 | 45.4k | { |
1485 | 45.4k | if (!aff) |
1486 | 0 | return NULL; |
1487 | 45.4k | aff->v = isl_vec_normalize(aff->v); |
1488 | 45.4k | if (!aff->v) |
1489 | 0 | return isl_aff_free(aff); |
1490 | 45.4k | aff = plug_in_integral_divs(aff); |
1491 | 45.4k | aff = plug_in_unit_divs(aff); |
1492 | 45.4k | aff = sort_divs(aff); |
1493 | 45.4k | aff = isl_aff_remove_unused_divs(aff); |
1494 | 45.4k | return aff; |
1495 | 45.4k | } |
1496 | | |
1497 | | /* Given f, return floor(f). |
1498 | | * If f is an integer expression, then just return f. |
1499 | | * If f is a constant, then return the constant floor(f). |
1500 | | * Otherwise, if f = g/m, write g = q m + r, |
1501 | | * create a new div d = [r/m] and return the expression q + d. |
1502 | | * The coefficients in r are taken to lie between -m/2 and m/2. |
1503 | | * |
1504 | | * reduce_div_coefficients performs the same normalization. |
1505 | | * |
1506 | | * As a special case, floor(NaN) = NaN. |
1507 | | */ |
1508 | | __isl_give isl_aff *isl_aff_floor(__isl_take isl_aff *aff) |
1509 | 20.2k | { |
1510 | 20.2k | int i; |
1511 | 20.2k | int size; |
1512 | 20.2k | isl_ctx *ctx; |
1513 | 20.2k | isl_vec *div; |
1514 | 20.2k | |
1515 | 20.2k | if (!aff) |
1516 | 0 | return NULL; |
1517 | 20.2k | |
1518 | 20.2k | if (isl_aff_is_nan(aff)) |
1519 | 0 | return aff; |
1520 | 20.2k | if (isl_int_is_one(aff->v->el[0])) |
1521 | 20.2k | return aff15.6k ; |
1522 | 4.56k | |
1523 | 4.56k | aff = isl_aff_cow(aff); |
1524 | 4.56k | if (!aff) |
1525 | 0 | return NULL; |
1526 | 4.56k | |
1527 | 4.56k | aff->v = isl_vec_cow(aff->v); |
1528 | 4.56k | if (!aff->v) |
1529 | 0 | return isl_aff_free(aff); |
1530 | 4.56k | |
1531 | 4.56k | if (isl_aff_is_cst(aff)) { |
1532 | 233 | isl_int_fdiv_q(aff->v->el[1], aff->v->el[1], aff->v->el[0]); |
1533 | 233 | isl_int_set_si(aff->v->el[0], 1); |
1534 | 233 | return aff; |
1535 | 233 | } |
1536 | 4.33k | |
1537 | 4.33k | div = isl_vec_copy(aff->v); |
1538 | 4.33k | div = isl_vec_cow(div); |
1539 | 4.33k | if (!div) |
1540 | 0 | return isl_aff_free(aff); |
1541 | 4.33k | |
1542 | 4.33k | ctx = isl_aff_get_ctx(aff); |
1543 | 4.33k | isl_int_fdiv_q(aff->v->el[0], aff->v->el[0], ctx->two); |
1544 | 19.7k | for (i = 1; i < aff->v->size; ++i15.4k ) { |
1545 | 15.4k | isl_int_fdiv_r(div->el[i], div->el[i], div->el[0]); |
1546 | 15.4k | isl_int_fdiv_q(aff->v->el[i], aff->v->el[i], div->el[0]); |
1547 | 15.4k | if (isl_int_gt(div->el[i], aff->v->el[0])) { |
1548 | 1.60k | isl_int_sub(div->el[i], div->el[i], div->el[0]); |
1549 | 1.60k | isl_int_add_ui(aff->v->el[i], aff->v->el[i], 1); |
1550 | 1.60k | } |
1551 | 15.4k | } |
1552 | 4.33k | |
1553 | 4.33k | aff->ls = isl_local_space_add_div(aff->ls, div); |
1554 | 4.33k | if (!aff->ls) |
1555 | 0 | return isl_aff_free(aff); |
1556 | 4.33k | |
1557 | 4.33k | size = aff->v->size; |
1558 | 4.33k | aff->v = isl_vec_extend(aff->v, size + 1); |
1559 | 4.33k | if (!aff->v) |
1560 | 0 | return isl_aff_free(aff); |
1561 | 4.33k | isl_int_set_si(aff->v->el[0], 1); |
1562 | 4.33k | isl_int_set_si(aff->v->el[size], 1); |
1563 | 4.33k | |
1564 | 4.33k | aff = isl_aff_normalize(aff); |
1565 | 4.33k | |
1566 | 4.33k | return aff; |
1567 | 4.33k | } |
1568 | | |
1569 | | /* Compute |
1570 | | * |
1571 | | * aff mod m = aff - m * floor(aff/m) |
1572 | | * |
1573 | | * with m an integer value. |
1574 | | */ |
1575 | | __isl_give isl_aff *isl_aff_mod_val(__isl_take isl_aff *aff, |
1576 | | __isl_take isl_val *m) |
1577 | 157 | { |
1578 | 157 | isl_aff *res; |
1579 | 157 | |
1580 | 157 | if (!aff || !m) |
1581 | 0 | goto error; |
1582 | 157 | |
1583 | 157 | if (!isl_val_is_int(m)) |
1584 | 157 | isl_die0 (isl_val_get_ctx(m), isl_error_invalid, |
1585 | 157 | "expecting integer modulo", goto error); |
1586 | 157 | |
1587 | 157 | res = isl_aff_copy(aff); |
1588 | 157 | aff = isl_aff_scale_down_val(aff, isl_val_copy(m)); |
1589 | 157 | aff = isl_aff_floor(aff); |
1590 | 157 | aff = isl_aff_scale_val(aff, m); |
1591 | 157 | res = isl_aff_sub(res, aff); |
1592 | 157 | |
1593 | 157 | return res; |
1594 | 0 | error: |
1595 | 0 | isl_aff_free(aff); |
1596 | 0 | isl_val_free(m); |
1597 | 0 | return NULL; |
1598 | 157 | } |
1599 | | |
1600 | | /* Compute |
1601 | | * |
1602 | | * pwaff mod m = pwaff - m * floor(pwaff/m) |
1603 | | */ |
1604 | | __isl_give isl_pw_aff *isl_pw_aff_mod(__isl_take isl_pw_aff *pwaff, isl_int m) |
1605 | 2.92k | { |
1606 | 2.92k | isl_pw_aff *res; |
1607 | 2.92k | |
1608 | 2.92k | res = isl_pw_aff_copy(pwaff); |
1609 | 2.92k | pwaff = isl_pw_aff_scale_down(pwaff, m); |
1610 | 2.92k | pwaff = isl_pw_aff_floor(pwaff); |
1611 | 2.92k | pwaff = isl_pw_aff_scale(pwaff, m); |
1612 | 2.92k | res = isl_pw_aff_sub(res, pwaff); |
1613 | 2.92k | |
1614 | 2.92k | return res; |
1615 | 2.92k | } |
1616 | | |
1617 | | /* Compute |
1618 | | * |
1619 | | * pa mod m = pa - m * floor(pa/m) |
1620 | | * |
1621 | | * with m an integer value. |
1622 | | */ |
1623 | | __isl_give isl_pw_aff *isl_pw_aff_mod_val(__isl_take isl_pw_aff *pa, |
1624 | | __isl_take isl_val *m) |
1625 | 2.92k | { |
1626 | 2.92k | if (!pa || !m) |
1627 | 0 | goto error; |
1628 | 2.92k | if (!isl_val_is_int(m)) |
1629 | 2.92k | isl_die0 (isl_pw_aff_get_ctx(pa), isl_error_invalid, |
1630 | 2.92k | "expecting integer modulo", goto error); |
1631 | 2.92k | pa = isl_pw_aff_mod(pa, m->n); |
1632 | 2.92k | isl_val_free(m); |
1633 | 2.92k | return pa; |
1634 | 0 | error: |
1635 | 0 | isl_pw_aff_free(pa); |
1636 | 0 | isl_val_free(m); |
1637 | 0 | return NULL; |
1638 | 2.92k | } |
1639 | | |
1640 | | /* Given f, return ceil(f). |
1641 | | * If f is an integer expression, then just return f. |
1642 | | * Otherwise, let f be the expression |
1643 | | * |
1644 | | * e/m |
1645 | | * |
1646 | | * then return |
1647 | | * |
1648 | | * floor((e + m - 1)/m) |
1649 | | * |
1650 | | * As a special case, ceil(NaN) = NaN. |
1651 | | */ |
1652 | | __isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff) |
1653 | 3.26k | { |
1654 | 3.26k | if (!aff) |
1655 | 0 | return NULL; |
1656 | 3.26k | |
1657 | 3.26k | if (isl_aff_is_nan(aff)) |
1658 | 0 | return aff; |
1659 | 3.26k | if (isl_int_is_one(aff->v->el[0])) |
1660 | 3.26k | return aff3.15k ; |
1661 | 110 | |
1662 | 110 | aff = isl_aff_cow(aff); |
1663 | 110 | if (!aff) |
1664 | 0 | return NULL; |
1665 | 110 | aff->v = isl_vec_cow(aff->v); |
1666 | 110 | if (!aff->v) |
1667 | 0 | return isl_aff_free(aff); |
1668 | 110 | |
1669 | 110 | isl_int_add(aff->v->el[1], aff->v->el[1], aff->v->el[0]); |
1670 | 110 | isl_int_sub_ui(aff->v->el[1], aff->v->el[1], 1); |
1671 | 110 | aff = isl_aff_floor(aff); |
1672 | 110 | |
1673 | 110 | return aff; |
1674 | 110 | } |
1675 | | |
1676 | | /* Apply the expansion computed by isl_merge_divs. |
1677 | | * The expansion itself is given by "exp" while the resulting |
1678 | | * list of divs is given by "div". |
1679 | | */ |
1680 | | __isl_give isl_aff *isl_aff_expand_divs(__isl_take isl_aff *aff, |
1681 | | __isl_take isl_mat *div, int *exp) |
1682 | 48.1k | { |
1683 | 48.1k | int old_n_div; |
1684 | 48.1k | int new_n_div; |
1685 | 48.1k | int offset; |
1686 | 48.1k | |
1687 | 48.1k | aff = isl_aff_cow(aff); |
1688 | 48.1k | if (!aff || !div) |
1689 | 0 | goto error; |
1690 | 48.1k | |
1691 | 48.1k | old_n_div = isl_local_space_dim(aff->ls, isl_dim_div); |
1692 | 48.1k | new_n_div = isl_mat_rows(div); |
1693 | 48.1k | offset = 1 + isl_local_space_offset(aff->ls, isl_dim_div); |
1694 | 48.1k | |
1695 | 48.1k | aff->v = isl_vec_expand(aff->v, offset, old_n_div, exp, new_n_div); |
1696 | 48.1k | aff->ls = isl_local_space_replace_divs(aff->ls, div); |
1697 | 48.1k | if (!aff->v || !aff->ls) |
1698 | 0 | return isl_aff_free(aff); |
1699 | 48.1k | return aff; |
1700 | 0 | error: |
1701 | 0 | isl_aff_free(aff); |
1702 | 0 | isl_mat_free(div); |
1703 | 0 | return NULL; |
1704 | 48.1k | } |
1705 | | |
1706 | | /* Add two affine expressions that live in the same local space. |
1707 | | */ |
1708 | | static __isl_give isl_aff *add_expanded(__isl_take isl_aff *aff1, |
1709 | | __isl_take isl_aff *aff2) |
1710 | 66.0k | { |
1711 | 66.0k | isl_int gcd, f; |
1712 | 66.0k | |
1713 | 66.0k | aff1 = isl_aff_cow(aff1); |
1714 | 66.0k | if (!aff1 || !aff2) |
1715 | 0 | goto error; |
1716 | 66.0k | |
1717 | 66.0k | aff1->v = isl_vec_cow(aff1->v); |
1718 | 66.0k | if (!aff1->v) |
1719 | 0 | goto error; |
1720 | 66.0k | |
1721 | 66.0k | isl_int_init(gcd); |
1722 | 66.0k | isl_int_init(f); |
1723 | 66.0k | isl_int_gcd(gcd, aff1->v->el[0], aff2->v->el[0]); |
1724 | 66.0k | isl_int_divexact(f, aff2->v->el[0], gcd); |
1725 | 66.0k | isl_seq_scale(aff1->v->el + 1, aff1->v->el + 1, f, aff1->v->size - 1); |
1726 | 66.0k | isl_int_divexact(f, aff1->v->el[0], gcd); |
1727 | 66.0k | isl_seq_addmul(aff1->v->el + 1, f, aff2->v->el + 1, aff1->v->size - 1); |
1728 | 66.0k | isl_int_divexact(f, aff2->v->el[0], gcd); |
1729 | 66.0k | isl_int_mul(aff1->v->el[0], aff1->v->el[0], f); |
1730 | 66.0k | isl_int_clear(f); |
1731 | 66.0k | isl_int_clear(gcd); |
1732 | 66.0k | |
1733 | 66.0k | isl_aff_free(aff2); |
1734 | 66.0k | return aff1; |
1735 | 0 | error: |
1736 | 0 | isl_aff_free(aff1); |
1737 | 0 | isl_aff_free(aff2); |
1738 | 0 | return NULL; |
1739 | 66.0k | } |
1740 | | |
1741 | | /* Return the sum of "aff1" and "aff2". |
1742 | | * |
1743 | | * If either of the two is NaN, then the result is NaN. |
1744 | | */ |
1745 | | __isl_give isl_aff *isl_aff_add(__isl_take isl_aff *aff1, |
1746 | | __isl_take isl_aff *aff2) |
1747 | 66.0k | { |
1748 | 66.0k | isl_ctx *ctx; |
1749 | 66.0k | int *exp1 = NULL; |
1750 | 66.0k | int *exp2 = NULL; |
1751 | 66.0k | isl_mat *div; |
1752 | 66.0k | int n_div1, n_div2; |
1753 | 66.0k | |
1754 | 66.0k | if (!aff1 || !aff2) |
1755 | 0 | goto error; |
1756 | 66.0k | |
1757 | 66.0k | ctx = isl_aff_get_ctx(aff1); |
1758 | 66.0k | if (!isl_space_is_equal(aff1->ls->dim, aff2->ls->dim)) |
1759 | 66.0k | isl_die0 (ctx, isl_error_invalid, |
1760 | 66.0k | "spaces don't match", goto error); |
1761 | 66.0k | |
1762 | 66.0k | if (isl_aff_is_nan(aff1)) { |
1763 | 2 | isl_aff_free(aff2); |
1764 | 2 | return aff1; |
1765 | 2 | } |
1766 | 66.0k | if (isl_aff_is_nan(aff2)) { |
1767 | 32 | isl_aff_free(aff1); |
1768 | 32 | return aff2; |
1769 | 32 | } |
1770 | 66.0k | |
1771 | 66.0k | n_div1 = isl_aff_dim(aff1, isl_dim_div); |
1772 | 66.0k | n_div2 = isl_aff_dim(aff2, isl_dim_div); |
1773 | 66.0k | if (n_div1 == 0 && n_div2 == 052.7k ) |
1774 | 46.0k | return add_expanded(aff1, aff2); |
1775 | 20.0k | |
1776 | 20.0k | exp1 = isl_alloc_array(ctx, int, n_div1); |
1777 | 20.0k | exp2 = isl_alloc_array(ctx, int, n_div2); |
1778 | 20.0k | if ((n_div1 && !exp113.2k ) || (n_div2 && !exp27.51k )) |
1779 | 0 | goto error; |
1780 | 20.0k | |
1781 | 20.0k | div = isl_merge_divs(aff1->ls->div, aff2->ls->div, exp1, exp2); |
1782 | 20.0k | aff1 = isl_aff_expand_divs(aff1, isl_mat_copy(div), exp1); |
1783 | 20.0k | aff2 = isl_aff_expand_divs(aff2, div, exp2); |
1784 | 20.0k | free(exp1); |
1785 | 20.0k | free(exp2); |
1786 | 20.0k | |
1787 | 20.0k | return add_expanded(aff1, aff2); |
1788 | 0 | error: |
1789 | 0 | free(exp1); |
1790 | 0 | free(exp2); |
1791 | 0 | isl_aff_free(aff1); |
1792 | 0 | isl_aff_free(aff2); |
1793 | 0 | return NULL; |
1794 | 20.0k | } |
1795 | | |
1796 | | __isl_give isl_aff *isl_aff_sub(__isl_take isl_aff *aff1, |
1797 | | __isl_take isl_aff *aff2) |
1798 | 816 | { |
1799 | 816 | return isl_aff_add(aff1, isl_aff_neg(aff2)); |
1800 | 816 | } |
1801 | | |
1802 | | /* Return the result of scaling "aff" by a factor of "f". |
1803 | | * |
1804 | | * As a special case, f * NaN = NaN. |
1805 | | */ |
1806 | | __isl_give isl_aff *isl_aff_scale(__isl_take isl_aff *aff, isl_int f) |
1807 | 22.0k | { |
1808 | 22.0k | isl_int gcd; |
1809 | 22.0k | |
1810 | 22.0k | if (!aff) |
1811 | 0 | return NULL; |
1812 | 22.0k | if (isl_aff_is_nan(aff)) |
1813 | 0 | return aff; |
1814 | 22.0k | |
1815 | 22.0k | if (isl_int_is_one(f)) |
1816 | 22.0k | return aff12.1k ; |
1817 | 9.95k | |
1818 | 9.95k | aff = isl_aff_cow(aff); |
1819 | 9.95k | if (!aff) |
1820 | 0 | return NULL; |
1821 | 9.95k | aff->v = isl_vec_cow(aff->v); |
1822 | 9.95k | if (!aff->v) |
1823 | 0 | return isl_aff_free(aff); |
1824 | 9.95k | |
1825 | 9.95k | if (isl_int_is_pos(f) && isl_int_is_divisible_by8.57k (aff->v->el[0], f)) { |
1826 | 160 | isl_int_divexact(aff->v->el[0], aff->v->el[0], f); |
1827 | 160 | return aff; |
1828 | 160 | } |
1829 | 9.79k | |
1830 | 9.79k | isl_int_init(gcd); |
1831 | 9.79k | isl_int_gcd(gcd, aff->v->el[0], f); |
1832 | 9.79k | isl_int_divexact(aff->v->el[0], aff->v->el[0], gcd); |
1833 | 9.79k | isl_int_divexact(gcd, f, gcd); |
1834 | 9.79k | isl_seq_scale(aff->v->el + 1, aff->v->el + 1, gcd, aff->v->size - 1); |
1835 | 9.79k | isl_int_clear(gcd); |
1836 | 9.79k | |
1837 | 9.79k | return aff; |
1838 | 9.79k | } |
1839 | | |
1840 | | /* Multiple "aff" by "v". |
1841 | | */ |
1842 | | __isl_give isl_aff *isl_aff_scale_val(__isl_take isl_aff *aff, |
1843 | | __isl_take isl_val *v) |
1844 | 611 | { |
1845 | 611 | if (!aff || !v) |
1846 | 0 | goto error; |
1847 | 611 | |
1848 | 611 | if (isl_val_is_one(v)) { |
1849 | 68 | isl_val_free(v); |
1850 | 68 | return aff; |
1851 | 68 | } |
1852 | 543 | |
1853 | 543 | if (!isl_val_is_rat(v)) |
1854 | 543 | isl_die0 (isl_aff_get_ctx(aff), isl_error_invalid, |
1855 | 543 | "expecting rational factor", goto error); |
1856 | 543 | |
1857 | 543 | aff = isl_aff_scale(aff, v->n); |
1858 | 543 | aff = isl_aff_scale_down(aff, v->d); |
1859 | 543 | |
1860 | 543 | isl_val_free(v); |
1861 | 543 | return aff; |
1862 | 0 | error: |
1863 | 0 | isl_aff_free(aff); |
1864 | 0 | isl_val_free(v); |
1865 | 0 | return NULL; |
1866 | 543 | } |
1867 | | |
1868 | | /* Return the result of scaling "aff" down by a factor of "f". |
1869 | | * |
1870 | | * As a special case, NaN/f = NaN. |
1871 | | */ |
1872 | | __isl_give isl_aff *isl_aff_scale_down(__isl_take isl_aff *aff, isl_int f) |
1873 | 21.0k | { |
1874 | 21.0k | isl_int gcd; |
1875 | 21.0k | |
1876 | 21.0k | if (!aff) |
1877 | 0 | return NULL; |
1878 | 21.0k | if (isl_aff_is_nan(aff)) |
1879 | 0 | return aff; |
1880 | 21.0k | |
1881 | 21.0k | if (isl_int_is_one(f)) |
1882 | 21.0k | return aff16.8k ; |
1883 | 4.20k | |
1884 | 4.20k | aff = isl_aff_cow(aff); |
1885 | 4.20k | if (!aff) |
1886 | 0 | return NULL; |
1887 | 4.20k | |
1888 | 4.20k | if (isl_int_is_zero(f)) |
1889 | 4.20k | isl_die0 (isl_aff_get_ctx(aff), isl_error_invalid, |
1890 | 4.20k | "cannot scale down by zero", return isl_aff_free(aff)); |
1891 | 4.20k | |
1892 | 4.20k | aff->v = isl_vec_cow(aff->v); |
1893 | 4.20k | if (!aff->v) |
1894 | 0 | return isl_aff_free(aff); |
1895 | 4.20k | |
1896 | 4.20k | isl_int_init(gcd); |
1897 | 4.20k | isl_seq_gcd(aff->v->el + 1, aff->v->size - 1, &gcd); |
1898 | 4.20k | isl_int_gcd(gcd, gcd, f); |
1899 | 4.20k | isl_seq_scale_down(aff->v->el + 1, aff->v->el + 1, gcd, aff->v->size - 1); |
1900 | 4.20k | isl_int_divexact(gcd, f, gcd); |
1901 | 4.20k | isl_int_mul(aff->v->el[0], aff->v->el[0], gcd); |
1902 | 4.20k | isl_int_clear(gcd); |
1903 | 4.20k | |
1904 | 4.20k | return aff; |
1905 | 4.20k | } |
1906 | | |
1907 | | /* Divide "aff" by "v". |
1908 | | */ |
1909 | | __isl_give isl_aff *isl_aff_scale_down_val(__isl_take isl_aff *aff, |
1910 | | __isl_take isl_val *v) |
1911 | 367 | { |
1912 | 367 | if (!aff || !v) |
1913 | 0 | goto error; |
1914 | 367 | |
1915 | 367 | if (isl_val_is_one(v)) { |
1916 | 13 | isl_val_free(v); |
1917 | 13 | return aff; |
1918 | 13 | } |
1919 | 354 | |
1920 | 354 | if (!isl_val_is_rat(v)) |
1921 | 354 | isl_die0 (isl_aff_get_ctx(aff), isl_error_invalid, |
1922 | 354 | "expecting rational factor", goto error); |
1923 | 354 | if (!isl_val_is_pos(v)) |
1924 | 354 | isl_die0 (isl_aff_get_ctx(aff), isl_error_invalid, |
1925 | 354 | "factor needs to be positive", goto error); |
1926 | 354 | |
1927 | 354 | aff = isl_aff_scale(aff, v->d); |
1928 | 354 | aff = isl_aff_scale_down(aff, v->n); |
1929 | 354 | |
1930 | 354 | isl_val_free(v); |
1931 | 354 | return aff; |
1932 | 0 | error: |
1933 | 0 | isl_aff_free(aff); |
1934 | 0 | isl_val_free(v); |
1935 | 0 | return NULL; |
1936 | 354 | } |
1937 | | |
1938 | | __isl_give isl_aff *isl_aff_scale_down_ui(__isl_take isl_aff *aff, unsigned f) |
1939 | 3 | { |
1940 | 3 | isl_int v; |
1941 | 3 | |
1942 | 3 | if (f == 1) |
1943 | 0 | return aff; |
1944 | 3 | |
1945 | 3 | isl_int_init(v); |
1946 | 3 | isl_int_set_ui(v, f); |
1947 | 3 | aff = isl_aff_scale_down(aff, v); |
1948 | 3 | isl_int_clear(v); |
1949 | 3 | |
1950 | 3 | return aff; |
1951 | 3 | } |
1952 | | |
1953 | | __isl_give isl_aff *isl_aff_set_dim_name(__isl_take isl_aff *aff, |
1954 | | enum isl_dim_type type, unsigned pos, const char *s) |
1955 | 0 | { |
1956 | 0 | aff = isl_aff_cow(aff); |
1957 | 0 | if (!aff) |
1958 | 0 | return NULL; |
1959 | 0 | if (type == isl_dim_out) |
1960 | 0 | isl_die(aff->v->ctx, isl_error_invalid, |
1961 | 0 | "cannot set name of output/set dimension", |
1962 | 0 | return isl_aff_free(aff)); |
1963 | 0 | if (type == isl_dim_in) |
1964 | 0 | type = isl_dim_set; |
1965 | 0 | aff->ls = isl_local_space_set_dim_name(aff->ls, type, pos, s); |
1966 | 0 | if (!aff->ls) |
1967 | 0 | return isl_aff_free(aff); |
1968 | 0 | |
1969 | 0 | return aff; |
1970 | 0 | } |
1971 | | |
1972 | | __isl_give isl_aff *isl_aff_set_dim_id(__isl_take isl_aff *aff, |
1973 | | enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) |
1974 | 0 | { |
1975 | 0 | aff = isl_aff_cow(aff); |
1976 | 0 | if (!aff) |
1977 | 0 | goto error; |
1978 | 0 | if (type == isl_dim_out) |
1979 | 0 | isl_die(aff->v->ctx, isl_error_invalid, |
1980 | 0 | "cannot set name of output/set dimension", |
1981 | 0 | goto error); |
1982 | 0 | if (type == isl_dim_in) |
1983 | 0 | type = isl_dim_set; |
1984 | 0 | aff->ls = isl_local_space_set_dim_id(aff->ls, type, pos, id); |
1985 | 0 | if (!aff->ls) |
1986 | 0 | return isl_aff_free(aff); |
1987 | 0 | |
1988 | 0 | return aff; |
1989 | 0 | error: |
1990 | 0 | isl_id_free(id); |
1991 | 0 | isl_aff_free(aff); |
1992 | 0 | return NULL; |
1993 | 0 | } |
1994 | | |
1995 | | /* Replace the identifier of the input tuple of "aff" by "id". |
1996 | | * type is currently required to be equal to isl_dim_in |
1997 | | */ |
1998 | | __isl_give isl_aff *isl_aff_set_tuple_id(__isl_take isl_aff *aff, |
1999 | | enum isl_dim_type type, __isl_take isl_id *id) |
2000 | 1 | { |
2001 | 1 | aff = isl_aff_cow(aff); |
2002 | 1 | if (!aff) |
2003 | 0 | goto error; |
2004 | 1 | if (type != isl_dim_in) |
2005 | 1 | isl_die0 (aff->v->ctx, isl_error_invalid, |
2006 | 1 | "cannot only set id of input tuple", goto error); |
2007 | 1 | aff->ls = isl_local_space_set_tuple_id(aff->ls, isl_dim_set, id); |
2008 | 1 | if (!aff->ls) |
2009 | 0 | return isl_aff_free(aff); |
2010 | 1 | |
2011 | 1 | return aff; |
2012 | 0 | error: |
2013 | 0 | isl_id_free(id); |
2014 | 0 | isl_aff_free(aff); |
2015 | 0 | return NULL; |
2016 | 1 | } |
2017 | | |
2018 | | /* Exploit the equalities in "eq" to simplify the affine expression |
2019 | | * and the expressions of the integer divisions in the local space. |
2020 | | * The integer divisions in this local space are assumed to appear |
2021 | | * as regular dimensions in "eq". |
2022 | | */ |
2023 | | static __isl_give isl_aff *isl_aff_substitute_equalities_lifted( |
2024 | | __isl_take isl_aff *aff, __isl_take isl_basic_set *eq) |
2025 | 150k | { |
2026 | 150k | int i, j; |
2027 | 150k | unsigned total; |
2028 | 150k | unsigned n_div; |
2029 | 150k | |
2030 | 150k | if (!eq) |
2031 | 0 | goto error; |
2032 | 150k | if (eq->n_eq == 0) { |
2033 | 145k | isl_basic_set_free(eq); |
2034 | 145k | return aff; |
2035 | 145k | } |
2036 | 4.92k | |
2037 | 4.92k | aff = isl_aff_cow(aff); |
2038 | 4.92k | if (!aff) |
2039 | 0 | goto error; |
2040 | 4.92k | |
2041 | 4.92k | aff->ls = isl_local_space_substitute_equalities(aff->ls, |
2042 | 4.92k | isl_basic_set_copy(eq)); |
2043 | 4.92k | aff->v = isl_vec_cow(aff->v); |
2044 | 4.92k | if (!aff->ls || !aff->v) |
2045 | 0 | goto error; |
2046 | 4.92k | |
2047 | 4.92k | total = 1 + isl_space_dim(eq->dim, isl_dim_all); |
2048 | 4.92k | n_div = eq->n_div; |
2049 | 11.5k | for (i = 0; i < eq->n_eq; ++i6.60k ) { |
2050 | 6.60k | j = isl_seq_last_non_zero(eq->eq[i], total + n_div); |
2051 | 6.60k | if (j < 0 || j == 0 || j >= total) |
2052 | 806 | continue; |
2053 | 5.80k | |
2054 | 5.80k | isl_seq_elim(aff->v->el + 1, eq->eq[i], j, total, |
2055 | 5.80k | &aff->v->el[0]); |
2056 | 5.80k | } |
2057 | 4.92k | |
2058 | 4.92k | isl_basic_set_free(eq); |
2059 | 4.92k | aff = isl_aff_normalize(aff); |
2060 | 4.92k | return aff; |
2061 | 0 | error: |
2062 | 0 | isl_basic_set_free(eq); |
2063 | 0 | isl_aff_free(aff); |
2064 | 0 | return NULL; |
2065 | 4.92k | } |
2066 | | |
2067 | | /* Exploit the equalities in "eq" to simplify the affine expression |
2068 | | * and the expressions of the integer divisions in the local space. |
2069 | | */ |
2070 | | __isl_give isl_aff *isl_aff_substitute_equalities(__isl_take isl_aff *aff, |
2071 | | __isl_take isl_basic_set *eq) |
2072 | 50.2k | { |
2073 | 50.2k | int n_div; |
2074 | 50.2k | |
2075 | 50.2k | if (!aff || !eq) |
2076 | 0 | goto error; |
2077 | 50.2k | n_div = isl_local_space_dim(aff->ls, isl_dim_div); |
2078 | 50.2k | if (n_div > 0) |
2079 | 7.48k | eq = isl_basic_set_add_dims(eq, isl_dim_set, n_div); |
2080 | 50.2k | return isl_aff_substitute_equalities_lifted(aff, eq); |
2081 | 0 | error: |
2082 | 0 | isl_basic_set_free(eq); |
2083 | 0 | isl_aff_free(aff); |
2084 | 0 | return NULL; |
2085 | 50.2k | } |
2086 | | |
2087 | | /* Look for equalities among the variables shared by context and aff |
2088 | | * and the integer divisions of aff, if any. |
2089 | | * The equalities are then used to eliminate coefficients and/or integer |
2090 | | * divisions from aff. |
2091 | | */ |
2092 | | __isl_give isl_aff *isl_aff_gist(__isl_take isl_aff *aff, |
2093 | | __isl_take isl_set *context) |
2094 | 100k | { |
2095 | 100k | isl_basic_set *hull; |
2096 | 100k | int n_div; |
2097 | 100k | |
2098 | 100k | if (!aff) |
2099 | 0 | goto error; |
2100 | 100k | n_div = isl_local_space_dim(aff->ls, isl_dim_div); |
2101 | 100k | if (n_div > 0) { |
2102 | 20.7k | isl_basic_set *bset; |
2103 | 20.7k | isl_local_space *ls; |
2104 | 20.7k | context = isl_set_add_dims(context, isl_dim_set, n_div); |
2105 | 20.7k | ls = isl_aff_get_domain_local_space(aff); |
2106 | 20.7k | bset = isl_basic_set_from_local_space(ls); |
2107 | 20.7k | bset = isl_basic_set_lift(bset); |
2108 | 20.7k | bset = isl_basic_set_flatten(bset); |
2109 | 20.7k | context = isl_set_intersect(context, |
2110 | 20.7k | isl_set_from_basic_set(bset)); |
2111 | 20.7k | } |
2112 | 100k | |
2113 | 100k | hull = isl_set_affine_hull(context); |
2114 | 100k | return isl_aff_substitute_equalities_lifted(aff, hull); |
2115 | 0 | error: |
2116 | 0 | isl_aff_free(aff); |
2117 | 0 | isl_set_free(context); |
2118 | 0 | return NULL; |
2119 | 100k | } |
2120 | | |
2121 | | __isl_give isl_aff *isl_aff_gist_params(__isl_take isl_aff *aff, |
2122 | | __isl_take isl_set *context) |
2123 | 0 | { |
2124 | 0 | isl_set *dom_context = isl_set_universe(isl_aff_get_domain_space(aff)); |
2125 | 0 | dom_context = isl_set_intersect_params(dom_context, context); |
2126 | 0 | return isl_aff_gist(aff, dom_context); |
2127 | 0 | } |
2128 | | |
2129 | | /* Return a basic set containing those elements in the space |
2130 | | * of aff where it is positive. "rational" should not be set. |
2131 | | * |
2132 | | * If "aff" is NaN, then it is not positive. |
2133 | | */ |
2134 | | static __isl_give isl_basic_set *aff_pos_basic_set(__isl_take isl_aff *aff, |
2135 | | int rational) |
2136 | 183 | { |
2137 | 183 | isl_constraint *ineq; |
2138 | 183 | isl_basic_set *bset; |
2139 | 183 | isl_val *c; |
2140 | 183 | |
2141 | 183 | if (!aff) |
2142 | 0 | return NULL; |
2143 | 183 | if (isl_aff_is_nan(aff)) { |
2144 | 0 | isl_space *space = isl_aff_get_domain_space(aff); |
2145 | 0 | isl_aff_free(aff); |
2146 | 0 | return isl_basic_set_empty(space); |
2147 | 0 | } |
2148 | 183 | if (rational) |
2149 | 183 | isl_die0 (isl_aff_get_ctx(aff), isl_error_unsupported, |
2150 | 183 | "rational sets not supported", goto error); |
2151 | 183 | |
2152 | 183 | ineq = isl_inequality_from_aff(aff); |
2153 | 183 | c = isl_constraint_get_constant_val(ineq); |
2154 | 183 | c = isl_val_sub_ui(c, 1); |
2155 | 183 | ineq = isl_constraint_set_constant_val(ineq, c); |
2156 | 183 | |
2157 | 183 | bset = isl_basic_set_from_constraint(ineq); |
2158 | 183 | bset = isl_basic_set_simplify(bset); |
2159 | 183 | return bset; |
2160 | 0 | error: |
2161 | 0 | isl_aff_free(aff); |
2162 | 0 | return NULL; |
2163 | 183 | } |
2164 | | |
2165 | | /* Return a basic set containing those elements in the space |
2166 | | * of aff where it is non-negative. |
2167 | | * If "rational" is set, then return a rational basic set. |
2168 | | * |
2169 | | * If "aff" is NaN, then it is not non-negative (it's not negative either). |
2170 | | */ |
2171 | | static __isl_give isl_basic_set *aff_nonneg_basic_set( |
2172 | | __isl_take isl_aff *aff, int rational) |
2173 | 16.8k | { |
2174 | 16.8k | isl_constraint *ineq; |
2175 | 16.8k | isl_basic_set *bset; |
2176 | 16.8k | |
2177 | 16.8k | if (!aff) |
2178 | 0 | return NULL; |
2179 | 16.8k | if (isl_aff_is_nan(aff)) { |
2180 | 0 | isl_space *space = isl_aff_get_domain_space(aff); |
2181 | 0 | isl_aff_free(aff); |
2182 | 0 | return isl_basic_set_empty(space); |
2183 | 0 | } |
2184 | 16.8k | |
2185 | 16.8k | ineq = isl_inequality_from_aff(aff); |
2186 | 16.8k | |
2187 | 16.8k | bset = isl_basic_set_from_constraint(ineq); |
2188 | 16.8k | if (rational) |
2189 | 24 | bset = isl_basic_set_set_rational(bset); |
2190 | 16.8k | bset = isl_basic_set_simplify(bset); |
2191 | 16.8k | return bset; |
2192 | 16.8k | } |
2193 | | |
2194 | | /* Return a basic set containing those elements in the space |
2195 | | * of aff where it is non-negative. |
2196 | | */ |
2197 | | __isl_give isl_basic_set *isl_aff_nonneg_basic_set(__isl_take isl_aff *aff) |
2198 | 609 | { |
2199 | 609 | return aff_nonneg_basic_set(aff, 0); |
2200 | 609 | } |
2201 | | |
2202 | | /* Return a basic set containing those elements in the domain space |
2203 | | * of "aff" where it is positive. |
2204 | | */ |
2205 | | __isl_give isl_basic_set *isl_aff_pos_basic_set(__isl_take isl_aff *aff) |
2206 | 153 | { |
2207 | 153 | aff = isl_aff_add_constant_num_si(aff, -1); |
2208 | 153 | return isl_aff_nonneg_basic_set(aff); |
2209 | 153 | } |
2210 | | |
2211 | | /* Return a basic set containing those elements in the domain space |
2212 | | * of aff where it is negative. |
2213 | | */ |
2214 | | __isl_give isl_basic_set *isl_aff_neg_basic_set(__isl_take isl_aff *aff) |
2215 | 153 | { |
2216 | 153 | aff = isl_aff_neg(aff); |
2217 | 153 | return isl_aff_pos_basic_set(aff); |
2218 | 153 | } |
2219 | | |
2220 | | /* Return a basic set containing those elements in the space |
2221 | | * of aff where it is zero. |
2222 | | * If "rational" is set, then return a rational basic set. |
2223 | | * |
2224 | | * If "aff" is NaN, then it is not zero. |
2225 | | */ |
2226 | | static __isl_give isl_basic_set *aff_zero_basic_set(__isl_take isl_aff *aff, |
2227 | | int rational) |
2228 | 9.96k | { |
2229 | 9.96k | isl_constraint *ineq; |
2230 | 9.96k | isl_basic_set *bset; |
2231 | 9.96k | |
2232 | 9.96k | if (!aff) |
2233 | 0 | return NULL; |
2234 | 9.96k | if (isl_aff_is_nan(aff)) { |
2235 | 0 | isl_space *space = isl_aff_get_domain_space(aff); |
2236 | 0 | isl_aff_free(aff); |
2237 | 0 | return isl_basic_set_empty(space); |
2238 | 0 | } |
2239 | 9.96k | |
2240 | 9.96k | ineq = isl_equality_from_aff(aff); |
2241 | 9.96k | |
2242 | 9.96k | bset = isl_basic_set_from_constraint(ineq); |
2243 | 9.96k | if (rational) |
2244 | 255 | bset = isl_basic_set_set_rational(bset); |
2245 | 9.96k | bset = isl_basic_set_simplify(bset); |
2246 | 9.96k | return bset; |
2247 | 9.96k | } |
2248 | | |
2249 | | /* Return a basic set containing those elements in the space |
2250 | | * of aff where it is zero. |
2251 | | */ |
2252 | | __isl_give isl_basic_set *isl_aff_zero_basic_set(__isl_take isl_aff *aff) |
2253 | 73 | { |
2254 | 73 | return aff_zero_basic_set(aff, 0); |
2255 | 73 | } |
2256 | | |
2257 | | /* Return a basic set containing those elements in the shared space |
2258 | | * of aff1 and aff2 where aff1 is greater than or equal to aff2. |
2259 | | */ |
2260 | | __isl_give isl_basic_set *isl_aff_ge_basic_set(__isl_take isl_aff *aff1, |
2261 | | __isl_take isl_aff *aff2) |
2262 | 456 | { |
2263 | 456 | aff1 = isl_aff_sub(aff1, aff2); |
2264 | 456 | |
2265 | 456 | return isl_aff_nonneg_basic_set(aff1); |
2266 | 456 | } |
2267 | | |
2268 | | /* Return a basic set containing those elements in the shared domain space |
2269 | | * of "aff1" and "aff2" where "aff1" is greater than "aff2". |
2270 | | */ |
2271 | | __isl_give isl_basic_set *isl_aff_gt_basic_set(__isl_take isl_aff *aff1, |
2272 | | __isl_take isl_aff *aff2) |
2273 | 0 | { |
2274 | 0 | aff1 = isl_aff_sub(aff1, aff2); |
2275 | 0 |
|
2276 | 0 | return isl_aff_pos_basic_set(aff1); |
2277 | 0 | } |
2278 | | |
2279 | | /* Return a set containing those elements in the shared space |
2280 | | * of aff1 and aff2 where aff1 is greater than or equal to aff2. |
2281 | | */ |
2282 | | __isl_give isl_set *isl_aff_ge_set(__isl_take isl_aff *aff1, |
2283 | | __isl_take isl_aff *aff2) |
2284 | 376 | { |
2285 | 376 | return isl_set_from_basic_set(isl_aff_ge_basic_set(aff1, aff2)); |
2286 | 376 | } |
2287 | | |
2288 | | /* Return a set containing those elements in the shared domain space |
2289 | | * of aff1 and aff2 where aff1 is greater than aff2. |
2290 | | * |
2291 | | * If either of the two inputs is NaN, then the result is empty, |
2292 | | * as comparisons with NaN always return false. |
2293 | | */ |
2294 | | __isl_give isl_set *isl_aff_gt_set(__isl_take isl_aff *aff1, |
2295 | | __isl_take isl_aff *aff2) |
2296 | 0 | { |
2297 | 0 | return isl_set_from_basic_set(isl_aff_gt_basic_set(aff1, aff2)); |
2298 | 0 | } |
2299 | | |
2300 | | /* Return a basic set containing those elements in the shared space |
2301 | | * of aff1 and aff2 where aff1 is smaller than or equal to aff2. |
2302 | | */ |
2303 | | __isl_give isl_basic_set *isl_aff_le_basic_set(__isl_take isl_aff *aff1, |
2304 | | __isl_take isl_aff *aff2) |
2305 | 34 | { |
2306 | 34 | return isl_aff_ge_basic_set(aff2, aff1); |
2307 | 34 | } |
2308 | | |
2309 | | /* Return a basic set containing those elements in the shared domain space |
2310 | | * of "aff1" and "aff2" where "aff1" is smaller than "aff2". |
2311 | | */ |
2312 | | __isl_give isl_basic_set *isl_aff_lt_basic_set(__isl_take isl_aff *aff1, |
2313 | | __isl_take isl_aff *aff2) |
2314 | 0 | { |
2315 | 0 | return isl_aff_gt_basic_set(aff2, aff1); |
2316 | 0 | } |
2317 | | |
2318 | | /* Return a set containing those elements in the shared space |
2319 | | * of aff1 and aff2 where aff1 is smaller than or equal to aff2. |
2320 | | */ |
2321 | | __isl_give isl_set *isl_aff_le_set(__isl_take isl_aff *aff1, |
2322 | | __isl_take isl_aff *aff2) |
2323 | 195 | { |
2324 | 195 | return isl_aff_ge_set(aff2, aff1); |
2325 | 195 | } |
2326 | | |
2327 | | /* Return a set containing those elements in the shared domain space |
2328 | | * of "aff1" and "aff2" where "aff1" is smaller than "aff2". |
2329 | | */ |
2330 | | __isl_give isl_set *isl_aff_lt_set(__isl_take isl_aff *aff1, |
2331 | | __isl_take isl_aff *aff2) |
2332 | 0 | { |
2333 | 0 | return isl_set_from_basic_set(isl_aff_lt_basic_set(aff1, aff2)); |
2334 | 0 | } |
2335 | | |
2336 | | /* Return a basic set containing those elements in the shared space |
2337 | | * of aff1 and aff2 where aff1 and aff2 are equal. |
2338 | | */ |
2339 | | __isl_give isl_basic_set *isl_aff_eq_basic_set(__isl_take isl_aff *aff1, |
2340 | | __isl_take isl_aff *aff2) |
2341 | 34 | { |
2342 | 34 | aff1 = isl_aff_sub(aff1, aff2); |
2343 | 34 | |
2344 | 34 | return isl_aff_zero_basic_set(aff1); |
2345 | 34 | } |
2346 | | |
2347 | | /* Return a set containing those elements in the shared space |
2348 | | * of aff1 and aff2 where aff1 and aff2 are equal. |
2349 | | */ |
2350 | | __isl_give isl_set *isl_aff_eq_set(__isl_take isl_aff *aff1, |
2351 | | __isl_take isl_aff *aff2) |
2352 | 34 | { |
2353 | 34 | return isl_set_from_basic_set(isl_aff_eq_basic_set(aff1, aff2)); |
2354 | 34 | } |
2355 | | |
2356 | | /* Return a set containing those elements in the shared domain space |
2357 | | * of aff1 and aff2 where aff1 and aff2 are not equal. |
2358 | | * |
2359 | | * If either of the two inputs is NaN, then the result is empty, |
2360 | | * as comparisons with NaN always return false. |
2361 | | */ |
2362 | | __isl_give isl_set *isl_aff_ne_set(__isl_take isl_aff *aff1, |
2363 | | __isl_take isl_aff *aff2) |
2364 | 0 | { |
2365 | 0 | isl_set *set_lt, *set_gt; |
2366 | 0 |
|
2367 | 0 | set_lt = isl_aff_lt_set(isl_aff_copy(aff1), |
2368 | 0 | isl_aff_copy(aff2)); |
2369 | 0 | set_gt = isl_aff_gt_set(aff1, aff2); |
2370 | 0 | return isl_set_union_disjoint(set_lt, set_gt); |
2371 | 0 | } |
2372 | | |
2373 | | __isl_give isl_aff *isl_aff_add_on_domain(__isl_keep isl_set *dom, |
2374 | | __isl_take isl_aff *aff1, __isl_take isl_aff *aff2) |
2375 | 2 | { |
2376 | 2 | aff1 = isl_aff_add(aff1, aff2); |
2377 | 2 | aff1 = isl_aff_gist(aff1, isl_set_copy(dom)); |
2378 | 2 | return aff1; |
2379 | 2 | } |
2380 | | |
2381 | | int isl_aff_is_empty(__isl_keep isl_aff *aff) |
2382 | 250k | { |
2383 | 250k | if (!aff) |
2384 | 0 | return -1; |
2385 | 250k | |
2386 | 250k | return 0; |
2387 | 250k | } |
2388 | | |
2389 | | /* Check whether the given affine expression has non-zero coefficient |
2390 | | * for any dimension in the given range or if any of these dimensions |
2391 | | * appear with non-zero coefficients in any of the integer divisions |
2392 | | * involved in the affine expression. |
2393 | | */ |
2394 | | isl_bool isl_aff_involves_dims(__isl_keep isl_aff *aff, |
2395 | | enum isl_dim_type type, unsigned first, unsigned n) |
2396 | 30.3k | { |
2397 | 30.3k | int i; |
2398 | 30.3k | isl_ctx *ctx; |
2399 | 30.3k | int *active = NULL; |
2400 | 30.3k | isl_bool involves = isl_bool_false; |
2401 | 30.3k | |
2402 | 30.3k | if (!aff) |
2403 | 0 | return isl_bool_error; |
2404 | 30.3k | if (n == 0) |
2405 | 19 | return isl_bool_false; |
2406 | 30.3k | |
2407 | 30.3k | ctx = isl_aff_get_ctx(aff); |
2408 | 30.3k | if (first + n > isl_aff_dim(aff, type)) |
2409 | 30.3k | isl_die0 (ctx, isl_error_invalid, |
2410 | 30.3k | "range out of bounds", return isl_bool_error); |
2411 | 30.3k | |
2412 | 30.3k | active = isl_local_space_get_active(aff->ls, aff->v->el + 2); |
2413 | 30.3k | if (!active) |
2414 | 0 | goto error; |
2415 | 30.3k | |
2416 | 30.3k | first += isl_local_space_offset(aff->ls, type) - 1; |
2417 | 54.9k | for (i = 0; i < n; ++i24.5k ) |
2418 | 30.5k | if (active[first + i]) { |
2419 | 5.92k | involves = isl_bool_true; |
2420 | 5.92k | break; |
2421 | 5.92k | } |
2422 | 30.3k | |
2423 | 30.3k | free(active); |
2424 | 30.3k | |
2425 | 30.3k | return involves; |
2426 | 0 | error: |
2427 | 0 | free(active); |
2428 | 0 | return isl_bool_error; |
2429 | 30.3k | } |
2430 | | |
2431 | | __isl_give isl_aff *isl_aff_drop_dims(__isl_take isl_aff *aff, |
2432 | | enum isl_dim_type type, unsigned first, unsigned n) |
2433 | 1.70k | { |
2434 | 1.70k | isl_ctx *ctx; |
2435 | 1.70k | |
2436 | 1.70k | if (!aff) |
2437 | 0 | return NULL; |
2438 | 1.70k | if (type == isl_dim_out) |
2439 | 1.70k | isl_die0 (aff->v->ctx, isl_error_invalid, |
2440 | 1.70k | "cannot drop output/set dimension", |
2441 | 1.70k | return isl_aff_free(aff)); |
2442 | 1.70k | if (type == isl_dim_in) |
2443 | 1.68k | type = isl_dim_set; |
2444 | 1.70k | if (n == 0 && !isl_local_space_is_named_or_nested(aff->ls, type)61 ) |
2445 | 41 | return aff; |
2446 | 1.66k | |
2447 | 1.66k | ctx = isl_aff_get_ctx(aff); |
2448 | 1.66k | if (first + n > isl_local_space_dim(aff->ls, type)) |
2449 | 1.66k | isl_die0 (ctx, isl_error_invalid, "range out of bounds", |
2450 | 1.66k | return isl_aff_free(aff)); |
2451 | 1.66k | |
2452 | 1.66k | aff = isl_aff_cow(aff); |
2453 | 1.66k | if (!aff) |
2454 | 0 | return NULL; |
2455 | 1.66k | |
2456 | 1.66k | aff->ls = isl_local_space_drop_dims(aff->ls, type, first, n); |
2457 | 1.66k | if (!aff->ls) |
2458 | 0 | return isl_aff_free(aff); |
2459 | 1.66k | |
2460 | 1.66k | first += 1 + isl_local_space_offset(aff->ls, type); |
2461 | 1.66k | aff->v = isl_vec_drop_els(aff->v, first, n); |
2462 | 1.66k | if (!aff->v) |
2463 | 0 | return isl_aff_free(aff); |
2464 | 1.66k | |
2465 | 1.66k | return aff; |
2466 | 1.66k | } |
2467 | | |
2468 | | /* Drop the "n" domain dimensions starting at "first" from "aff", |
2469 | | * after checking that they do not appear in the affine expression. |
2470 | | */ |
2471 | | static __isl_give isl_aff *drop_domain(__isl_take isl_aff *aff, unsigned first, |
2472 | | unsigned n) |
2473 | 19 | { |
2474 | 19 | isl_bool involves; |
2475 | 19 | |
2476 | 19 | involves = isl_aff_involves_dims(aff, isl_dim_in, first, n); |
2477 | 19 | if (involves < 0) |
2478 | 0 | return isl_aff_free(aff); |
2479 | 19 | if (involves) |
2480 | 19 | isl_die0 (isl_aff_get_ctx(aff), isl_error_invalid, |
2481 | 19 | "affine expression involves some of the domain dimensions", |
2482 | 19 | return isl_aff_free(aff)); |
2483 | 19 | return isl_aff_drop_dims(aff, isl_dim_in, first, n); |
2484 | 19 | } |
2485 | | |
2486 | | /* Project the domain of the affine expression onto its parameter space. |
2487 | | * The affine expression may not involve any of the domain dimensions. |
2488 | | */ |
2489 | | __isl_give isl_aff *isl_aff_project_domain_on_params(__isl_take isl_aff *aff) |
2490 | 19 | { |
2491 | 19 | isl_space *space; |
2492 | 19 | unsigned n; |
2493 | 19 | |
2494 | 19 | n = isl_aff_dim(aff, isl_dim_in); |
2495 | 19 | aff = drop_domain(aff, 0, n); |
2496 | 19 | space = isl_aff_get_domain_space(aff); |
2497 | 19 | space = isl_space_params(space); |
2498 | 19 | aff = isl_aff_reset_domain_space(aff, space); |
2499 | 19 | return aff; |
2500 | 19 | } |
2501 | | |
2502 | | /* Check that the domain of "aff" is a product. |
2503 | | */ |
2504 | | static isl_stat check_domain_product(__isl_keep isl_aff *aff) |
2505 | 0 | { |
2506 | 0 | isl_bool is_product; |
2507 | 0 |
|
2508 | 0 | is_product = isl_space_is_product(isl_aff_peek_domain_space(aff)); |
2509 | 0 | if (is_product < 0) |
2510 | 0 | return isl_stat_error; |
2511 | 0 | if (!is_product) |
2512 | 0 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
2513 | 0 | "domain is not a product", return isl_stat_error); |
2514 | 0 | return isl_stat_ok; |
2515 | 0 | } |
2516 | | |
2517 | | /* Given an affine function with a domain of the form [A -> B] that |
2518 | | * does not depend on B, return the same function on domain A. |
2519 | | */ |
2520 | | __isl_give isl_aff *isl_aff_domain_factor_domain(__isl_take isl_aff *aff) |
2521 | 0 | { |
2522 | 0 | isl_space *space; |
2523 | 0 | int n, n_in; |
2524 | 0 |
|
2525 | 0 | if (check_domain_product(aff) < 0) |
2526 | 0 | return isl_aff_free(aff); |
2527 | 0 | space = isl_aff_get_domain_space(aff); |
2528 | 0 | n = isl_space_dim(space, isl_dim_set); |
2529 | 0 | space = isl_space_factor_domain(space); |
2530 | 0 | n_in = isl_space_dim(space, isl_dim_set); |
2531 | 0 | aff = drop_domain(aff, n_in, n - n_in); |
2532 | 0 | aff = isl_aff_reset_domain_space(aff, space); |
2533 | 0 | return aff; |
2534 | 0 | } |
2535 | | |
2536 | | /* Convert an affine expression defined over a parameter domain |
2537 | | * into one that is defined over a zero-dimensional set. |
2538 | | */ |
2539 | | __isl_give isl_aff *isl_aff_from_range(__isl_take isl_aff *aff) |
2540 | 0 | { |
2541 | 0 | isl_local_space *ls; |
2542 | 0 |
|
2543 | 0 | ls = isl_aff_take_domain_local_space(aff); |
2544 | 0 | ls = isl_local_space_set_from_params(ls); |
2545 | 0 | aff = isl_aff_restore_domain_local_space(aff, ls); |
2546 | 0 |
|
2547 | 0 | return aff; |
2548 | 0 | } |
2549 | | |
2550 | | __isl_give isl_aff *isl_aff_insert_dims(__isl_take isl_aff *aff, |
2551 | | enum isl_dim_type type, unsigned first, unsigned n) |
2552 | 8.82k | { |
2553 | 8.82k | isl_ctx *ctx; |
2554 | 8.82k | |
2555 | 8.82k | if (!aff) |
2556 | 0 | return NULL; |
2557 | 8.82k | if (type == isl_dim_out) |
2558 | 8.82k | isl_die0 (aff->v->ctx, isl_error_invalid, |
2559 | 8.82k | "cannot insert output/set dimensions", |
2560 | 8.82k | return isl_aff_free(aff)); |
2561 | 8.82k | if (type == isl_dim_in) |
2562 | 8.82k | type = isl_dim_set; |
2563 | 8.82k | if (n == 0 && !isl_local_space_is_named_or_nested(aff->ls, type)1.72k ) |
2564 | 1.71k | return aff; |
2565 | 7.10k | |
2566 | 7.10k | ctx = isl_aff_get_ctx(aff); |
2567 | 7.10k | if (first > isl_local_space_dim(aff->ls, type)) |
2568 | 7.10k | isl_die0 (ctx, isl_error_invalid, "position out of bounds", |
2569 | 7.10k | return isl_aff_free(aff)); |
2570 | 7.10k | |
2571 | 7.10k | aff = isl_aff_cow(aff); |
2572 | 7.10k | if (!aff) |
2573 | 0 | return NULL; |
2574 | 7.10k | |
2575 | 7.10k | aff->ls = isl_local_space_insert_dims(aff->ls, type, first, n); |
2576 | 7.10k | if (!aff->ls) |
2577 | 0 | return isl_aff_free(aff); |
2578 | 7.10k | |
2579 | 7.10k | first += 1 + isl_local_space_offset(aff->ls, type); |
2580 | 7.10k | aff->v = isl_vec_insert_zero_els(aff->v, first, n); |
2581 | 7.10k | if (!aff->v) |
2582 | 0 | return isl_aff_free(aff); |
2583 | 7.10k | |
2584 | 7.10k | return aff; |
2585 | 7.10k | } |
2586 | | |
2587 | | __isl_give isl_aff *isl_aff_add_dims(__isl_take isl_aff *aff, |
2588 | | enum isl_dim_type type, unsigned n) |
2589 | 3 | { |
2590 | 3 | unsigned pos; |
2591 | 3 | |
2592 | 3 | pos = isl_aff_dim(aff, type); |
2593 | 3 | |
2594 | 3 | return isl_aff_insert_dims(aff, type, pos, n); |
2595 | 3 | } |
2596 | | |
2597 | | __isl_give isl_pw_aff *isl_pw_aff_add_dims(__isl_take isl_pw_aff *pwaff, |
2598 | | enum isl_dim_type type, unsigned n) |
2599 | 3.84k | { |
2600 | 3.84k | unsigned pos; |
2601 | 3.84k | |
2602 | 3.84k | pos = isl_pw_aff_dim(pwaff, type); |
2603 | 3.84k | |
2604 | 3.84k | return isl_pw_aff_insert_dims(pwaff, type, pos, n); |
2605 | 3.84k | } |
2606 | | |
2607 | | /* Move the "n" dimensions of "src_type" starting at "src_pos" of "aff" |
2608 | | * to dimensions of "dst_type" at "dst_pos". |
2609 | | * |
2610 | | * We only support moving input dimensions to parameters and vice versa. |
2611 | | */ |
2612 | | __isl_give isl_aff *isl_aff_move_dims(__isl_take isl_aff *aff, |
2613 | | enum isl_dim_type dst_type, unsigned dst_pos, |
2614 | | enum isl_dim_type src_type, unsigned src_pos, unsigned n) |
2615 | 0 | { |
2616 | 0 | unsigned g_dst_pos; |
2617 | 0 | unsigned g_src_pos; |
2618 | 0 |
|
2619 | 0 | if (!aff) |
2620 | 0 | return NULL; |
2621 | 0 | if (n == 0 && |
2622 | 0 | !isl_local_space_is_named_or_nested(aff->ls, src_type) && |
2623 | 0 | !isl_local_space_is_named_or_nested(aff->ls, dst_type)) |
2624 | 0 | return aff; |
2625 | 0 | |
2626 | 0 | if (dst_type == isl_dim_out || src_type == isl_dim_out) |
2627 | 0 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
2628 | 0 | "cannot move output/set dimension", |
2629 | 0 | return isl_aff_free(aff)); |
2630 | 0 | if (dst_type == isl_dim_div || src_type == isl_dim_div) |
2631 | 0 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
2632 | 0 | "cannot move divs", return isl_aff_free(aff)); |
2633 | 0 | if (dst_type == isl_dim_in) |
2634 | 0 | dst_type = isl_dim_set; |
2635 | 0 | if (src_type == isl_dim_in) |
2636 | 0 | src_type = isl_dim_set; |
2637 | 0 |
|
2638 | 0 | if (src_pos + n > isl_local_space_dim(aff->ls, src_type)) |
2639 | 0 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
2640 | 0 | "range out of bounds", return isl_aff_free(aff)); |
2641 | 0 | if (dst_type == src_type) |
2642 | 0 | isl_die(isl_aff_get_ctx(aff), isl_error_unsupported, |
2643 | 0 | "moving dims within the same type not supported", |
2644 | 0 | return isl_aff_free(aff)); |
2645 | 0 |
|
2646 | 0 | aff = isl_aff_cow(aff); |
2647 | 0 | if (!aff) |
2648 | 0 | return NULL; |
2649 | 0 | |
2650 | 0 | g_src_pos = 1 + isl_local_space_offset(aff->ls, src_type) + src_pos; |
2651 | 0 | g_dst_pos = 1 + isl_local_space_offset(aff->ls, dst_type) + dst_pos; |
2652 | 0 | if (dst_type > src_type) |
2653 | 0 | g_dst_pos -= n; |
2654 | 0 |
|
2655 | 0 | aff->v = isl_vec_move_els(aff->v, g_dst_pos, g_src_pos, n); |
2656 | 0 | aff->ls = isl_local_space_move_dims(aff->ls, dst_type, dst_pos, |
2657 | 0 | src_type, src_pos, n); |
2658 | 0 | if (!aff->v || !aff->ls) |
2659 | 0 | return isl_aff_free(aff); |
2660 | 0 | |
2661 | 0 | aff = sort_divs(aff); |
2662 | 0 |
|
2663 | 0 | return aff; |
2664 | 0 | } |
2665 | | |
2666 | | __isl_give isl_pw_aff *isl_pw_aff_from_aff(__isl_take isl_aff *aff) |
2667 | 67.1k | { |
2668 | 67.1k | isl_set *dom = isl_set_universe(isl_aff_get_domain_space(aff)); |
2669 | 67.1k | return isl_pw_aff_alloc(dom, aff); |
2670 | 67.1k | } |
2671 | | |
2672 | 5.15k | #define isl_aff_involves_nan isl_aff_is_nan |
2673 | | |
2674 | | #undef PW |
2675 | 232k | #define PW isl_pw_aff |
2676 | | #undef EL |
2677 | 85.9k | #define EL isl_aff |
2678 | | #undef EL_IS_ZERO |
2679 | | #define EL_IS_ZERO is_empty |
2680 | | #undef ZERO |
2681 | | #define ZERO empty |
2682 | | #undef IS_ZERO |
2683 | | #define IS_ZERO is_empty |
2684 | | #undef FIELD |
2685 | 1.32M | #define FIELD aff |
2686 | | #undef DEFAULT_IS_ZERO |
2687 | 9.48k | #define DEFAULT_IS_ZERO 0 |
2688 | | |
2689 | | #define NO_OPT |
2690 | | #define NO_LIFT |
2691 | | #define NO_MORPH |
2692 | | |
2693 | | #include <isl_pw_templ.c> |
2694 | | #include <isl_pw_eval.c> |
2695 | | #include <isl_pw_hash.c> |
2696 | | #include <isl_pw_union_opt.c> |
2697 | | |
2698 | | #undef BASE |
2699 | | #define BASE pw_aff |
2700 | | |
2701 | | #include <isl_union_single.c> |
2702 | | #include <isl_union_neg.c> |
2703 | | |
2704 | | static __isl_give isl_set *align_params_pw_pw_set_and( |
2705 | | __isl_take isl_pw_aff *pwaff1, __isl_take isl_pw_aff *pwaff2, |
2706 | | __isl_give isl_set *(*fn)(__isl_take isl_pw_aff *pwaff1, |
2707 | | __isl_take isl_pw_aff *pwaff2)) |
2708 | 20.6k | { |
2709 | 20.6k | isl_bool equal_params; |
2710 | 20.6k | |
2711 | 20.6k | if (!pwaff1 || !pwaff2) |
2712 | 0 | goto error; |
2713 | 20.6k | equal_params = isl_space_has_equal_params(pwaff1->dim, pwaff2->dim); |
2714 | 20.6k | if (equal_params < 0) |
2715 | 0 | goto error; |
2716 | 20.6k | if (equal_params) |
2717 | 19.1k | return fn(pwaff1, pwaff2); |
2718 | 1.56k | if (isl_pw_aff_check_named_params(pwaff1) < 0 || |
2719 | 1.56k | isl_pw_aff_check_named_params(pwaff2) < 0) |
2720 | 0 | goto error; |
2721 | 1.56k | pwaff1 = isl_pw_aff_align_params(pwaff1, isl_pw_aff_get_space(pwaff2)); |
2722 | 1.56k | pwaff2 = isl_pw_aff_align_params(pwaff2, isl_pw_aff_get_space(pwaff1)); |
2723 | 1.56k | return fn(pwaff1, pwaff2); |
2724 | 0 | error: |
2725 | 0 | isl_pw_aff_free(pwaff1); |
2726 | 0 | isl_pw_aff_free(pwaff2); |
2727 | 0 | return NULL; |
2728 | 1.56k | } |
2729 | | |
2730 | | /* Align the parameters of the to isl_pw_aff arguments and |
2731 | | * then apply a function "fn" on them that returns an isl_map. |
2732 | | */ |
2733 | | static __isl_give isl_map *align_params_pw_pw_map_and( |
2734 | | __isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2, |
2735 | | __isl_give isl_map *(*fn)(__isl_take isl_pw_aff *pa1, |
2736 | | __isl_take isl_pw_aff *pa2)) |
2737 | 16 | { |
2738 | 16 | isl_bool equal_params; |
2739 | 16 | |
2740 | 16 | if (!pa1 || !pa2) |
2741 | 0 | goto error; |
2742 | 16 | equal_params = isl_space_has_equal_params(pa1->dim, pa2->dim); |
2743 | 16 | if (equal_params < 0) |
2744 | 0 | goto error; |
2745 | 16 | if (equal_params) |
2746 | 16 | return fn(pa1, pa2); |
2747 | 0 | if (isl_pw_aff_check_named_params(pa1) < 0 || |
2748 | 0 | isl_pw_aff_check_named_params(pa2) < 0) |
2749 | 0 | goto error; |
2750 | 0 | pa1 = isl_pw_aff_align_params(pa1, isl_pw_aff_get_space(pa2)); |
2751 | 0 | pa2 = isl_pw_aff_align_params(pa2, isl_pw_aff_get_space(pa1)); |
2752 | 0 | return fn(pa1, pa2); |
2753 | 0 | error: |
2754 | 0 | isl_pw_aff_free(pa1); |
2755 | 0 | isl_pw_aff_free(pa2); |
2756 | 0 | return NULL; |
2757 | 0 | } |
2758 | | |
2759 | | /* Compute a piecewise quasi-affine expression with a domain that |
2760 | | * is the union of those of pwaff1 and pwaff2 and such that on each |
2761 | | * cell, the quasi-affine expression is the maximum of those of pwaff1 |
2762 | | * and pwaff2. If only one of pwaff1 or pwaff2 is defined on a given |
2763 | | * cell, then the associated expression is the defined one. |
2764 | | */ |
2765 | | static __isl_give isl_pw_aff *pw_aff_union_max(__isl_take isl_pw_aff *pwaff1, |
2766 | | __isl_take isl_pw_aff *pwaff2) |
2767 | 178 | { |
2768 | 178 | return isl_pw_aff_union_opt_cmp(pwaff1, pwaff2, &isl_aff_ge_set); |
2769 | 178 | } |
2770 | | |
2771 | | __isl_give isl_pw_aff *isl_pw_aff_union_max(__isl_take isl_pw_aff *pwaff1, |
2772 | | __isl_take isl_pw_aff *pwaff2) |
2773 | 178 | { |
2774 | 178 | return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2, |
2775 | 178 | &pw_aff_union_max); |
2776 | 178 | } |
2777 | | |
2778 | | /* Compute a piecewise quasi-affine expression with a domain that |
2779 | | * is the union of those of pwaff1 and pwaff2 and such that on each |
2780 | | * cell, the quasi-affine expression is the minimum of those of pwaff1 |
2781 | | * and pwaff2. If only one of pwaff1 or pwaff2 is defined on a given |
2782 | | * cell, then the associated expression is the defined one. |
2783 | | */ |
2784 | | static __isl_give isl_pw_aff *pw_aff_union_min(__isl_take isl_pw_aff *pwaff1, |
2785 | | __isl_take isl_pw_aff *pwaff2) |
2786 | 189 | { |
2787 | 189 | return isl_pw_aff_union_opt_cmp(pwaff1, pwaff2, &isl_aff_le_set); |
2788 | 189 | } |
2789 | | |
2790 | | __isl_give isl_pw_aff *isl_pw_aff_union_min(__isl_take isl_pw_aff *pwaff1, |
2791 | | __isl_take isl_pw_aff *pwaff2) |
2792 | 189 | { |
2793 | 189 | return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2, |
2794 | 189 | &pw_aff_union_min); |
2795 | 189 | } |
2796 | | |
2797 | | __isl_give isl_pw_aff *isl_pw_aff_union_opt(__isl_take isl_pw_aff *pwaff1, |
2798 | | __isl_take isl_pw_aff *pwaff2, int max) |
2799 | 367 | { |
2800 | 367 | if (max) |
2801 | 178 | return isl_pw_aff_union_max(pwaff1, pwaff2); |
2802 | 189 | else |
2803 | 189 | return isl_pw_aff_union_min(pwaff1, pwaff2); |
2804 | 367 | } |
2805 | | |
2806 | | /* Return a set containing those elements in the domain |
2807 | | * of "pwaff" where it satisfies "fn" (if complement is 0) or |
2808 | | * does not satisfy "fn" (if complement is 1). |
2809 | | * |
2810 | | * The pieces with a NaN never belong to the result since |
2811 | | * NaN does not satisfy any property. |
2812 | | */ |
2813 | | static __isl_give isl_set *pw_aff_locus(__isl_take isl_pw_aff *pwaff, |
2814 | | __isl_give isl_basic_set *(*fn)(__isl_take isl_aff *aff, int rational), |
2815 | | int complement) |
2816 | 25.4k | { |
2817 | 25.4k | int i; |
2818 | 25.4k | isl_set *set; |
2819 | 25.4k | |
2820 | 25.4k | if (!pwaff) |
2821 | 0 | return NULL; |
2822 | 25.4k | |
2823 | 25.4k | set = isl_set_empty(isl_pw_aff_get_domain_space(pwaff)); |
2824 | 25.4k | |
2825 | 51.6k | for (i = 0; i < pwaff->n; ++i26.2k ) { |
2826 | 26.2k | isl_basic_set *bset; |
2827 | 26.2k | isl_set *set_i, *locus; |
2828 | 26.2k | isl_bool rational; |
2829 | 26.2k | |
2830 | 26.2k | if (isl_aff_is_nan(pwaff->p[i].aff)) |
2831 | 0 | continue; |
2832 | 26.2k | |
2833 | 26.2k | rational = isl_set_has_rational(pwaff->p[i].set); |
2834 | 26.2k | bset = fn(isl_aff_copy(pwaff->p[i].aff), rational); |
2835 | 26.2k | locus = isl_set_from_basic_set(bset); |
2836 | 26.2k | set_i = isl_set_copy(pwaff->p[i].set); |
2837 | 26.2k | if (complement) |
2838 | 159 | set_i = isl_set_subtract(set_i, locus); |
2839 | 26.1k | else |
2840 | 26.1k | set_i = isl_set_intersect(set_i, locus); |
2841 | 26.2k | set = isl_set_union_disjoint(set, set_i); |
2842 | 26.2k | } |
2843 | 25.4k | |
2844 | 25.4k | isl_pw_aff_free(pwaff); |
2845 | 25.4k | |
2846 | 25.4k | return set; |
2847 | 25.4k | } |
2848 | | |
2849 | | /* Return a set containing those elements in the domain |
2850 | | * of "pa" where it is positive. |
2851 | | */ |
2852 | | __isl_give isl_set *isl_pw_aff_pos_set(__isl_take isl_pw_aff *pa) |
2853 | 164 | { |
2854 | 164 | return pw_aff_locus(pa, &aff_pos_basic_set, 0); |
2855 | 164 | } |
2856 | | |
2857 | | /* Return a set containing those elements in the domain |
2858 | | * of pwaff where it is non-negative. |
2859 | | */ |
2860 | | __isl_give isl_set *isl_pw_aff_nonneg_set(__isl_take isl_pw_aff *pwaff) |
2861 | 15.6k | { |
2862 | 15.6k | return pw_aff_locus(pwaff, &aff_nonneg_basic_set, 0); |
2863 | 15.6k | } |
2864 | | |
2865 | | /* Return a set containing those elements in the domain |
2866 | | * of pwaff where it is zero. |
2867 | | */ |
2868 | | __isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff) |
2869 | 9.55k | { |
2870 | 9.55k | return pw_aff_locus(pwaff, &aff_zero_basic_set, 0); |
2871 | 9.55k | } |
2872 | | |
2873 | | /* Return a set containing those elements in the domain |
2874 | | * of pwaff where it is not zero. |
2875 | | */ |
2876 | | __isl_give isl_set *isl_pw_aff_non_zero_set(__isl_take isl_pw_aff *pwaff) |
2877 | 100 | { |
2878 | 100 | return pw_aff_locus(pwaff, &aff_zero_basic_set, 1); |
2879 | 100 | } |
2880 | | |
2881 | | /* Return a set containing those elements in the shared domain |
2882 | | * of pwaff1 and pwaff2 where pwaff1 is greater than (or equal) to pwaff2. |
2883 | | * |
2884 | | * We compute the difference on the shared domain and then construct |
2885 | | * the set of values where this difference is non-negative. |
2886 | | * If strict is set, we first subtract 1 from the difference. |
2887 | | * If equal is set, we only return the elements where pwaff1 and pwaff2 |
2888 | | * are equal. |
2889 | | */ |
2890 | | static __isl_give isl_set *pw_aff_gte_set(__isl_take isl_pw_aff *pwaff1, |
2891 | | __isl_take isl_pw_aff *pwaff2, int strict, int equal) |
2892 | 16.7k | { |
2893 | 16.7k | isl_set *set1, *set2; |
2894 | 16.7k | |
2895 | 16.7k | set1 = isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)); |
2896 | 16.7k | set2 = isl_pw_aff_domain(isl_pw_aff_copy(pwaff2)); |
2897 | 16.7k | set1 = isl_set_intersect(set1, set2); |
2898 | 16.7k | pwaff1 = isl_pw_aff_intersect_domain(pwaff1, isl_set_copy(set1)); |
2899 | 16.7k | pwaff2 = isl_pw_aff_intersect_domain(pwaff2, isl_set_copy(set1)); |
2900 | 16.7k | pwaff1 = isl_pw_aff_add(pwaff1, isl_pw_aff_neg(pwaff2)); |
2901 | 16.7k | |
2902 | 16.7k | if (strict) { |
2903 | 9.91k | isl_space *dim = isl_set_get_space(set1); |
2904 | 9.91k | isl_aff *aff; |
2905 | 9.91k | aff = isl_aff_zero_on_domain(isl_local_space_from_space(dim)); |
2906 | 9.91k | aff = isl_aff_add_constant_si(aff, -1); |
2907 | 9.91k | pwaff1 = isl_pw_aff_add(pwaff1, isl_pw_aff_alloc(set1, aff)); |
2908 | 9.91k | } else |
2909 | 6.83k | isl_set_free(set1); |
2910 | 16.7k | |
2911 | 16.7k | if (equal) |
2912 | 1.29k | return isl_pw_aff_zero_set(pwaff1); |
2913 | 15.4k | return isl_pw_aff_nonneg_set(pwaff1); |
2914 | 15.4k | } |
2915 | | |
2916 | | /* Return a set containing those elements in the shared domain |
2917 | | * of pwaff1 and pwaff2 where pwaff1 is equal to pwaff2. |
2918 | | */ |
2919 | | static __isl_give isl_set *pw_aff_eq_set(__isl_take isl_pw_aff *pwaff1, |
2920 | | __isl_take isl_pw_aff *pwaff2) |
2921 | 1.29k | { |
2922 | 1.29k | return pw_aff_gte_set(pwaff1, pwaff2, 0, 1); |
2923 | 1.29k | } |
2924 | | |
2925 | | __isl_give isl_set *isl_pw_aff_eq_set(__isl_take isl_pw_aff *pwaff1, |
2926 | | __isl_take isl_pw_aff *pwaff2) |
2927 | 1.29k | { |
2928 | 1.29k | return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_eq_set); |
2929 | 1.29k | } |
2930 | | |
2931 | | /* Return a set containing those elements in the shared domain |
2932 | | * of pwaff1 and pwaff2 where pwaff1 is greater than or equal to pwaff2. |
2933 | | */ |
2934 | | static __isl_give isl_set *pw_aff_ge_set(__isl_take isl_pw_aff *pwaff1, |
2935 | | __isl_take isl_pw_aff *pwaff2) |
2936 | 5.53k | { |
2937 | 5.53k | return pw_aff_gte_set(pwaff1, pwaff2, 0, 0); |
2938 | 5.53k | } |
2939 | | |
2940 | | __isl_give isl_set *isl_pw_aff_ge_set(__isl_take isl_pw_aff *pwaff1, |
2941 | | __isl_take isl_pw_aff *pwaff2) |
2942 | 5.53k | { |
2943 | 5.53k | return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_ge_set); |
2944 | 5.53k | } |
2945 | | |
2946 | | /* Return a set containing those elements in the shared domain |
2947 | | * of pwaff1 and pwaff2 where pwaff1 is strictly greater than pwaff2. |
2948 | | */ |
2949 | | static __isl_give isl_set *pw_aff_gt_set(__isl_take isl_pw_aff *pwaff1, |
2950 | | __isl_take isl_pw_aff *pwaff2) |
2951 | 9.91k | { |
2952 | 9.91k | return pw_aff_gte_set(pwaff1, pwaff2, 1, 0); |
2953 | 9.91k | } |
2954 | | |
2955 | | __isl_give isl_set *isl_pw_aff_gt_set(__isl_take isl_pw_aff *pwaff1, |
2956 | | __isl_take isl_pw_aff *pwaff2) |
2957 | 9.91k | { |
2958 | 9.91k | return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_gt_set); |
2959 | 9.91k | } |
2960 | | |
2961 | | __isl_give isl_set *isl_pw_aff_le_set(__isl_take isl_pw_aff *pwaff1, |
2962 | | __isl_take isl_pw_aff *pwaff2) |
2963 | 4.07k | { |
2964 | 4.07k | return isl_pw_aff_ge_set(pwaff2, pwaff1); |
2965 | 4.07k | } |
2966 | | |
2967 | | __isl_give isl_set *isl_pw_aff_lt_set(__isl_take isl_pw_aff *pwaff1, |
2968 | | __isl_take isl_pw_aff *pwaff2) |
2969 | 5.73k | { |
2970 | 5.73k | return isl_pw_aff_gt_set(pwaff2, pwaff1); |
2971 | 5.73k | } |
2972 | | |
2973 | | /* Return a map containing pairs of elements in the domains of "pa1" and "pa2" |
2974 | | * where the function values are ordered in the same way as "order", |
2975 | | * which returns a set in the shared domain of its two arguments. |
2976 | | * The parameters of "pa1" and "pa2" are assumed to have been aligned. |
2977 | | * |
2978 | | * Let "pa1" and "pa2" be defined on domains A and B respectively. |
2979 | | * We first pull back the two functions such that they are defined on |
2980 | | * the domain [A -> B]. Then we apply "order", resulting in a set |
2981 | | * in the space [A -> B]. Finally, we unwrap this set to obtain |
2982 | | * a map in the space A -> B. |
2983 | | */ |
2984 | | static __isl_give isl_map *isl_pw_aff_order_map_aligned( |
2985 | | __isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2, |
2986 | | __isl_give isl_set *(*order)(__isl_take isl_pw_aff *pa1, |
2987 | | __isl_take isl_pw_aff *pa2)) |
2988 | 16 | { |
2989 | 16 | isl_space *space1, *space2; |
2990 | 16 | isl_multi_aff *ma; |
2991 | 16 | isl_set *set; |
2992 | 16 | |
2993 | 16 | space1 = isl_space_domain(isl_pw_aff_get_space(pa1)); |
2994 | 16 | space2 = isl_space_domain(isl_pw_aff_get_space(pa2)); |
2995 | 16 | space1 = isl_space_map_from_domain_and_range(space1, space2); |
2996 | 16 | ma = isl_multi_aff_domain_map(isl_space_copy(space1)); |
2997 | 16 | pa1 = isl_pw_aff_pullback_multi_aff(pa1, ma); |
2998 | 16 | ma = isl_multi_aff_range_map(space1); |
2999 | 16 | pa2 = isl_pw_aff_pullback_multi_aff(pa2, ma); |
3000 | 16 | set = order(pa1, pa2); |
3001 | 16 | |
3002 | 16 | return isl_set_unwrap(set); |
3003 | 16 | } |
3004 | | |
3005 | | /* Return a map containing pairs of elements in the domains of "pa1" and "pa2" |
3006 | | * where the function values are equal. |
3007 | | * The parameters of "pa1" and "pa2" are assumed to have been aligned. |
3008 | | */ |
3009 | | static __isl_give isl_map *isl_pw_aff_eq_map_aligned(__isl_take isl_pw_aff *pa1, |
3010 | | __isl_take isl_pw_aff *pa2) |
3011 | 12 | { |
3012 | 12 | return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_eq_set); |
3013 | 12 | } |
3014 | | |
3015 | | /* Return a map containing pairs of elements in the domains of "pa1" and "pa2" |
3016 | | * where the function values are equal. |
3017 | | */ |
3018 | | __isl_give isl_map *isl_pw_aff_eq_map(__isl_take isl_pw_aff *pa1, |
3019 | | __isl_take isl_pw_aff *pa2) |
3020 | 12 | { |
3021 | 12 | return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_eq_map_aligned); |
3022 | 12 | } |
3023 | | |
3024 | | /* Return a map containing pairs of elements in the domains of "pa1" and "pa2" |
3025 | | * where the function value of "pa1" is less than the function value of "pa2". |
3026 | | * The parameters of "pa1" and "pa2" are assumed to have been aligned. |
3027 | | */ |
3028 | | static __isl_give isl_map *isl_pw_aff_lt_map_aligned(__isl_take isl_pw_aff *pa1, |
3029 | | __isl_take isl_pw_aff *pa2) |
3030 | 2 | { |
3031 | 2 | return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_lt_set); |
3032 | 2 | } |
3033 | | |
3034 | | /* Return a map containing pairs of elements in the domains of "pa1" and "pa2" |
3035 | | * where the function value of "pa1" is less than the function value of "pa2". |
3036 | | */ |
3037 | | __isl_give isl_map *isl_pw_aff_lt_map(__isl_take isl_pw_aff *pa1, |
3038 | | __isl_take isl_pw_aff *pa2) |
3039 | 2 | { |
3040 | 2 | return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_lt_map_aligned); |
3041 | 2 | } |
3042 | | |
3043 | | /* Return a map containing pairs of elements in the domains of "pa1" and "pa2" |
3044 | | * where the function value of "pa1" is greater than the function value |
3045 | | * of "pa2". |
3046 | | * The parameters of "pa1" and "pa2" are assumed to have been aligned. |
3047 | | */ |
3048 | | static __isl_give isl_map *isl_pw_aff_gt_map_aligned(__isl_take isl_pw_aff *pa1, |
3049 | | __isl_take isl_pw_aff *pa2) |
3050 | 2 | { |
3051 | 2 | return isl_pw_aff_order_map_aligned(pa1, pa2, &isl_pw_aff_gt_set); |
3052 | 2 | } |
3053 | | |
3054 | | /* Return a map containing pairs of elements in the domains of "pa1" and "pa2" |
3055 | | * where the function value of "pa1" is greater than the function value |
3056 | | * of "pa2". |
3057 | | */ |
3058 | | __isl_give isl_map *isl_pw_aff_gt_map(__isl_take isl_pw_aff *pa1, |
3059 | | __isl_take isl_pw_aff *pa2) |
3060 | 2 | { |
3061 | 2 | return align_params_pw_pw_map_and(pa1, pa2, &isl_pw_aff_gt_map_aligned); |
3062 | 2 | } |
3063 | | |
3064 | | /* Return a set containing those elements in the shared domain |
3065 | | * of the elements of list1 and list2 where each element in list1 |
3066 | | * has the relation specified by "fn" with each element in list2. |
3067 | | */ |
3068 | | static __isl_give isl_set *pw_aff_list_set(__isl_take isl_pw_aff_list *list1, |
3069 | | __isl_take isl_pw_aff_list *list2, |
3070 | | __isl_give isl_set *(*fn)(__isl_take isl_pw_aff *pwaff1, |
3071 | | __isl_take isl_pw_aff *pwaff2)) |
3072 | 5.54k | { |
3073 | 5.54k | int i, j; |
3074 | 5.54k | isl_ctx *ctx; |
3075 | 5.54k | isl_set *set; |
3076 | 5.54k | |
3077 | 5.54k | if (!list1 || !list2) |
3078 | 0 | goto error; |
3079 | 5.54k | |
3080 | 5.54k | ctx = isl_pw_aff_list_get_ctx(list1); |
3081 | 5.54k | if (list1->n < 1 || list2->n < 1) |
3082 | 5.54k | isl_die0 (ctx, isl_error_invalid, |
3083 | 5.54k | "list should contain at least one element", goto error); |
3084 | 5.54k | |
3085 | 5.54k | set = isl_set_universe(isl_pw_aff_get_domain_space(list1->p[0])); |
3086 | 11.2k | for (i = 0; i < list1->n; ++i5.69k ) |
3087 | 11.5k | for (j = 0; 5.69k j < list2->n; ++j5.89k ) { |
3088 | 5.89k | isl_set *set_ij; |
3089 | 5.89k | |
3090 | 5.89k | set_ij = fn(isl_pw_aff_copy(list1->p[i]), |
3091 | 5.89k | isl_pw_aff_copy(list2->p[j])); |
3092 | 5.89k | set = isl_set_intersect(set, set_ij); |
3093 | 5.89k | } |
3094 | 5.54k | |
3095 | 5.54k | isl_pw_aff_list_free(list1); |
3096 | 5.54k | isl_pw_aff_list_free(list2); |
3097 | 5.54k | return set; |
3098 | 0 | error: |
3099 | 0 | isl_pw_aff_list_free(list1); |
3100 | 0 | isl_pw_aff_list_free(list2); |
3101 | 0 | return NULL; |
3102 | 5.54k | } |
3103 | | |
3104 | | /* Return a set containing those elements in the shared domain |
3105 | | * of the elements of list1 and list2 where each element in list1 |
3106 | | * is equal to each element in list2. |
3107 | | */ |
3108 | | __isl_give isl_set *isl_pw_aff_list_eq_set(__isl_take isl_pw_aff_list *list1, |
3109 | | __isl_take isl_pw_aff_list *list2) |
3110 | 544 | { |
3111 | 544 | return pw_aff_list_set(list1, list2, &isl_pw_aff_eq_set); |
3112 | 544 | } |
3113 | | |
3114 | | __isl_give isl_set *isl_pw_aff_list_ne_set(__isl_take isl_pw_aff_list *list1, |
3115 | | __isl_take isl_pw_aff_list *list2) |
3116 | 12 | { |
3117 | 12 | return pw_aff_list_set(list1, list2, &isl_pw_aff_ne_set); |
3118 | 12 | } |
3119 | | |
3120 | | /* Return a set containing those elements in the shared domain |
3121 | | * of the elements of list1 and list2 where each element in list1 |
3122 | | * is less than or equal to each element in list2. |
3123 | | */ |
3124 | | __isl_give isl_set *isl_pw_aff_list_le_set(__isl_take isl_pw_aff_list *list1, |
3125 | | __isl_take isl_pw_aff_list *list2) |
3126 | 3.12k | { |
3127 | 3.12k | return pw_aff_list_set(list1, list2, &isl_pw_aff_le_set); |
3128 | 3.12k | } |
3129 | | |
3130 | | __isl_give isl_set *isl_pw_aff_list_lt_set(__isl_take isl_pw_aff_list *list1, |
3131 | | __isl_take isl_pw_aff_list *list2) |
3132 | 389 | { |
3133 | 389 | return pw_aff_list_set(list1, list2, &isl_pw_aff_lt_set); |
3134 | 389 | } |
3135 | | |
3136 | | __isl_give isl_set *isl_pw_aff_list_ge_set(__isl_take isl_pw_aff_list *list1, |
3137 | | __isl_take isl_pw_aff_list *list2) |
3138 | 1.35k | { |
3139 | 1.35k | return pw_aff_list_set(list1, list2, &isl_pw_aff_ge_set); |
3140 | 1.35k | } |
3141 | | |
3142 | | __isl_give isl_set *isl_pw_aff_list_gt_set(__isl_take isl_pw_aff_list *list1, |
3143 | | __isl_take isl_pw_aff_list *list2) |
3144 | 128 | { |
3145 | 128 | return pw_aff_list_set(list1, list2, &isl_pw_aff_gt_set); |
3146 | 128 | } |
3147 | | |
3148 | | |
3149 | | /* Return a set containing those elements in the shared domain |
3150 | | * of pwaff1 and pwaff2 where pwaff1 is not equal to pwaff2. |
3151 | | */ |
3152 | | static __isl_give isl_set *pw_aff_ne_set(__isl_take isl_pw_aff *pwaff1, |
3153 | | __isl_take isl_pw_aff *pwaff2) |
3154 | 3.93k | { |
3155 | 3.93k | isl_set *set_lt, *set_gt; |
3156 | 3.93k | |
3157 | 3.93k | set_lt = isl_pw_aff_lt_set(isl_pw_aff_copy(pwaff1), |
3158 | 3.93k | isl_pw_aff_copy(pwaff2)); |
3159 | 3.93k | set_gt = isl_pw_aff_gt_set(pwaff1, pwaff2); |
3160 | 3.93k | return isl_set_union_disjoint(set_lt, set_gt); |
3161 | 3.93k | } |
3162 | | |
3163 | | __isl_give isl_set *isl_pw_aff_ne_set(__isl_take isl_pw_aff *pwaff1, |
3164 | | __isl_take isl_pw_aff *pwaff2) |
3165 | 3.93k | { |
3166 | 3.93k | return align_params_pw_pw_set_and(pwaff1, pwaff2, &pw_aff_ne_set); |
3167 | 3.93k | } |
3168 | | |
3169 | | __isl_give isl_pw_aff *isl_pw_aff_scale_down(__isl_take isl_pw_aff *pwaff, |
3170 | | isl_int v) |
3171 | 3.41k | { |
3172 | 3.41k | int i; |
3173 | 3.41k | |
3174 | 3.41k | if (isl_int_is_one(v)) |
3175 | 3.41k | return pwaff0 ; |
3176 | 3.41k | if (!isl_int_is_pos(v)) |
3177 | 3.41k | isl_die0 (isl_pw_aff_get_ctx(pwaff), isl_error_invalid, |
3178 | 3.41k | "factor needs to be positive", |
3179 | 3.41k | return isl_pw_aff_free(pwaff)); |
3180 | 3.41k | pwaff = isl_pw_aff_cow(pwaff); |
3181 | 3.41k | if (!pwaff) |
3182 | 0 | return NULL; |
3183 | 3.41k | if (pwaff->n == 0) |
3184 | 0 | return pwaff; |
3185 | 3.41k | |
3186 | 7.06k | for (i = 0; 3.41k i < pwaff->n; ++i3.65k ) { |
3187 | 3.65k | pwaff->p[i].aff = isl_aff_scale_down(pwaff->p[i].aff, v); |
3188 | 3.65k | if (!pwaff->p[i].aff) |
3189 | 0 | return isl_pw_aff_free(pwaff); |
3190 | 3.65k | } |
3191 | 3.41k | |
3192 | 3.41k | return pwaff; |
3193 | 3.41k | } |
3194 | | |
3195 | | __isl_give isl_pw_aff *isl_pw_aff_floor(__isl_take isl_pw_aff *pwaff) |
3196 | 7.61k | { |
3197 | 7.61k | int i; |
3198 | 7.61k | |
3199 | 7.61k | pwaff = isl_pw_aff_cow(pwaff); |
3200 | 7.61k | if (!pwaff) |
3201 | 0 | return NULL; |
3202 | 7.61k | if (pwaff->n == 0) |
3203 | 0 | return pwaff; |
3204 | 7.61k | |
3205 | 15.6k | for (i = 0; 7.61k i < pwaff->n; ++i8.06k ) { |
3206 | 8.06k | pwaff->p[i].aff = isl_aff_floor(pwaff->p[i].aff); |
3207 | 8.06k | if (!pwaff->p[i].aff) |
3208 | 0 | return isl_pw_aff_free(pwaff); |
3209 | 8.06k | } |
3210 | 7.61k | |
3211 | 7.61k | return pwaff; |
3212 | 7.61k | } |
3213 | | |
3214 | | __isl_give isl_pw_aff *isl_pw_aff_ceil(__isl_take isl_pw_aff *pwaff) |
3215 | 110 | { |
3216 | 110 | int i; |
3217 | 110 | |
3218 | 110 | pwaff = isl_pw_aff_cow(pwaff); |
3219 | 110 | if (!pwaff) |
3220 | 0 | return NULL; |
3221 | 110 | if (pwaff->n == 0) |
3222 | 0 | return pwaff; |
3223 | 110 | |
3224 | 222 | for (i = 0; 110 i < pwaff->n; ++i112 ) { |
3225 | 112 | pwaff->p[i].aff = isl_aff_ceil(pwaff->p[i].aff); |
3226 | 112 | if (!pwaff->p[i].aff) |
3227 | 0 | return isl_pw_aff_free(pwaff); |
3228 | 112 | } |
3229 | 110 | |
3230 | 110 | return pwaff; |
3231 | 110 | } |
3232 | | |
3233 | | /* Assuming that "cond1" and "cond2" are disjoint, |
3234 | | * return an affine expression that is equal to pwaff1 on cond1 |
3235 | | * and to pwaff2 on cond2. |
3236 | | */ |
3237 | | static __isl_give isl_pw_aff *isl_pw_aff_select( |
3238 | | __isl_take isl_set *cond1, __isl_take isl_pw_aff *pwaff1, |
3239 | | __isl_take isl_set *cond2, __isl_take isl_pw_aff *pwaff2) |
3240 | 187 | { |
3241 | 187 | pwaff1 = isl_pw_aff_intersect_domain(pwaff1, cond1); |
3242 | 187 | pwaff2 = isl_pw_aff_intersect_domain(pwaff2, cond2); |
3243 | 187 | |
3244 | 187 | return isl_pw_aff_add_disjoint(pwaff1, pwaff2); |
3245 | 187 | } |
3246 | | |
3247 | | /* Return an affine expression that is equal to pwaff_true for elements |
3248 | | * where "cond" is non-zero and to pwaff_false for elements where "cond" |
3249 | | * is zero. |
3250 | | * That is, return cond ? pwaff_true : pwaff_false; |
3251 | | * |
3252 | | * If "cond" involves and NaN, then we conservatively return a NaN |
3253 | | * on its entire domain. In principle, we could consider the pieces |
3254 | | * where it is NaN separately from those where it is not. |
3255 | | * |
3256 | | * If "pwaff_true" and "pwaff_false" are obviously equal to each other, |
3257 | | * then only use the domain of "cond" to restrict the domain. |
3258 | | */ |
3259 | | __isl_give isl_pw_aff *isl_pw_aff_cond(__isl_take isl_pw_aff *cond, |
3260 | | __isl_take isl_pw_aff *pwaff_true, __isl_take isl_pw_aff *pwaff_false) |
3261 | 111 | { |
3262 | 111 | isl_set *cond_true, *cond_false; |
3263 | 111 | isl_bool equal; |
3264 | 111 | |
3265 | 111 | if (!cond) |
3266 | 0 | goto error; |
3267 | 111 | if (isl_pw_aff_involves_nan(cond)) { |
3268 | 0 | isl_space *space = isl_pw_aff_get_domain_space(cond); |
3269 | 0 | isl_local_space *ls = isl_local_space_from_space(space); |
3270 | 0 | isl_pw_aff_free(cond); |
3271 | 0 | isl_pw_aff_free(pwaff_true); |
3272 | 0 | isl_pw_aff_free(pwaff_false); |
3273 | 0 | return isl_pw_aff_nan_on_domain(ls); |
3274 | 0 | } |
3275 | 111 | |
3276 | 111 | pwaff_true = isl_pw_aff_align_params(pwaff_true, |
3277 | 111 | isl_pw_aff_get_space(pwaff_false)); |
3278 | 111 | pwaff_false = isl_pw_aff_align_params(pwaff_false, |
3279 | 111 | isl_pw_aff_get_space(pwaff_true)); |
3280 | 111 | equal = isl_pw_aff_plain_is_equal(pwaff_true, pwaff_false); |
3281 | 111 | if (equal < 0) |
3282 | 0 | goto error; |
3283 | 111 | if (equal) { |
3284 | 11 | isl_set *dom; |
3285 | 11 | |
3286 | 11 | dom = isl_set_coalesce(isl_pw_aff_domain(cond)); |
3287 | 11 | isl_pw_aff_free(pwaff_false); |
3288 | 11 | return isl_pw_aff_intersect_domain(pwaff_true, dom); |
3289 | 11 | } |
3290 | 100 | |
3291 | 100 | cond_true = isl_pw_aff_non_zero_set(isl_pw_aff_copy(cond)); |
3292 | 100 | cond_false = isl_pw_aff_zero_set(cond); |
3293 | 100 | return isl_pw_aff_select(cond_true, pwaff_true, |
3294 | 100 | cond_false, pwaff_false); |
3295 | 0 | error: |
3296 | 0 | isl_pw_aff_free(cond); |
3297 | 0 | isl_pw_aff_free(pwaff_true); |
3298 | 0 | isl_pw_aff_free(pwaff_false); |
3299 | 0 | return NULL; |
3300 | 100 | } |
3301 | | |
3302 | | isl_bool isl_aff_is_cst(__isl_keep isl_aff *aff) |
3303 | 44.3k | { |
3304 | 44.3k | if (!aff) |
3305 | 0 | return isl_bool_error; |
3306 | 44.3k | |
3307 | 44.3k | return isl_seq_first_non_zero(aff->v->el + 2, aff->v->size - 2) == -1; |
3308 | 44.3k | } |
3309 | | |
3310 | | /* Check whether pwaff is a piecewise constant. |
3311 | | */ |
3312 | | isl_bool isl_pw_aff_is_cst(__isl_keep isl_pw_aff *pwaff) |
3313 | 326 | { |
3314 | 326 | int i; |
3315 | 326 | |
3316 | 326 | if (!pwaff) |
3317 | 0 | return isl_bool_error; |
3318 | 326 | |
3319 | 652 | for (i = 0; 326 i < pwaff->n; ++i326 ) { |
3320 | 326 | isl_bool is_cst = isl_aff_is_cst(pwaff->p[i].aff); |
3321 | 326 | if (is_cst < 0 || !is_cst) |
3322 | 0 | return is_cst; |
3323 | 326 | } |
3324 | 326 | |
3325 | 326 | return isl_bool_true; |
3326 | 326 | } |
3327 | | |
3328 | | /* Are all elements of "mpa" piecewise constants? |
3329 | | */ |
3330 | | isl_bool isl_multi_pw_aff_is_cst(__isl_keep isl_multi_pw_aff *mpa) |
3331 | 0 | { |
3332 | 0 | int i; |
3333 | 0 |
|
3334 | 0 | if (!mpa) |
3335 | 0 | return isl_bool_error; |
3336 | 0 | |
3337 | 0 | for (i = 0; i < mpa->n; ++i) { |
3338 | 0 | isl_bool is_cst = isl_pw_aff_is_cst(mpa->u.p[i]); |
3339 | 0 | if (is_cst < 0 || !is_cst) |
3340 | 0 | return is_cst; |
3341 | 0 | } |
3342 | 0 |
|
3343 | 0 | return isl_bool_true; |
3344 | 0 | } |
3345 | | |
3346 | | /* Return the product of "aff1" and "aff2". |
3347 | | * |
3348 | | * If either of the two is NaN, then the result is NaN. |
3349 | | * |
3350 | | * Otherwise, at least one of "aff1" or "aff2" needs to be a constant. |
3351 | | */ |
3352 | | __isl_give isl_aff *isl_aff_mul(__isl_take isl_aff *aff1, |
3353 | | __isl_take isl_aff *aff2) |
3354 | 19.5k | { |
3355 | 19.5k | if (!aff1 || !aff2) |
3356 | 0 | goto error; |
3357 | 19.5k | |
3358 | 19.5k | if (isl_aff_is_nan(aff1)) { |
3359 | 2 | isl_aff_free(aff2); |
3360 | 2 | return aff1; |
3361 | 2 | } |
3362 | 19.5k | if (isl_aff_is_nan(aff2)) { |
3363 | 2 | isl_aff_free(aff1); |
3364 | 2 | return aff2; |
3365 | 2 | } |
3366 | 19.5k | |
3367 | 19.5k | if (!isl_aff_is_cst(aff2) && isl_aff_is_cst(aff1)3.18k ) |
3368 | 3.18k | return isl_aff_mul(aff2, aff1); |
3369 | 16.3k | |
3370 | 16.3k | if (!isl_aff_is_cst(aff2)) |
3371 | 16.3k | isl_die0 (isl_aff_get_ctx(aff1), isl_error_invalid, |
3372 | 16.3k | "at least one affine expression should be constant", |
3373 | 16.3k | goto error); |
3374 | 16.3k | |
3375 | 16.3k | aff1 = isl_aff_cow(aff1); |
3376 | 16.3k | if (!aff1 || !aff2) |
3377 | 0 | goto error; |
3378 | 16.3k | |
3379 | 16.3k | aff1 = isl_aff_scale(aff1, aff2->v->el[1]); |
3380 | 16.3k | aff1 = isl_aff_scale_down(aff1, aff2->v->el[0]); |
3381 | 16.3k | |
3382 | 16.3k | isl_aff_free(aff2); |
3383 | 16.3k | return aff1; |
3384 | 0 | error: |
3385 | 0 | isl_aff_free(aff1); |
3386 | 0 | isl_aff_free(aff2); |
3387 | 0 | return NULL; |
3388 | 16.3k | } |
3389 | | |
3390 | | /* Divide "aff1" by "aff2", assuming "aff2" is a constant. |
3391 | | * |
3392 | | * If either of the two is NaN, then the result is NaN. |
3393 | | */ |
3394 | | __isl_give isl_aff *isl_aff_div(__isl_take isl_aff *aff1, |
3395 | | __isl_take isl_aff *aff2) |
3396 | 197 | { |
3397 | 197 | int is_cst; |
3398 | 197 | int neg; |
3399 | 197 | |
3400 | 197 | if (!aff1 || !aff2) |
3401 | 0 | goto error; |
3402 | 197 | |
3403 | 197 | if (isl_aff_is_nan(aff1)) { |
3404 | 2 | isl_aff_free(aff2); |
3405 | 2 | return aff1; |
3406 | 2 | } |
3407 | 195 | if (isl_aff_is_nan(aff2)) { |
3408 | 2 | isl_aff_free(aff1); |
3409 | 2 | return aff2; |
3410 | 2 | } |
3411 | 193 | |
3412 | 193 | is_cst = isl_aff_is_cst(aff2); |
3413 | 193 | if (is_cst < 0) |
3414 | 0 | goto error; |
3415 | 193 | if (!is_cst) |
3416 | 193 | isl_die0 (isl_aff_get_ctx(aff2), isl_error_invalid, |
3417 | 193 | "second argument should be a constant", goto error); |
3418 | 193 | |
3419 | 193 | if (!aff2) |
3420 | 0 | goto error; |
3421 | 193 | |
3422 | 193 | neg = isl_int_is_neg(aff2->v->el[1]); |
3423 | 193 | if (neg) { |
3424 | 23 | isl_int_neg(aff2->v->el[0], aff2->v->el[0]); |
3425 | 23 | isl_int_neg(aff2->v->el[1], aff2->v->el[1]); |
3426 | 23 | } |
3427 | 193 | |
3428 | 193 | aff1 = isl_aff_scale(aff1, aff2->v->el[0]); |
3429 | 193 | aff1 = isl_aff_scale_down(aff1, aff2->v->el[1]); |
3430 | 193 | |
3431 | 193 | if (neg) { |
3432 | 23 | isl_int_neg(aff2->v->el[0], aff2->v->el[0]); |
3433 | 23 | isl_int_neg(aff2->v->el[1], aff2->v->el[1]); |
3434 | 23 | } |
3435 | 193 | |
3436 | 193 | isl_aff_free(aff2); |
3437 | 193 | return aff1; |
3438 | 0 | error: |
3439 | 0 | isl_aff_free(aff1); |
3440 | 0 | isl_aff_free(aff2); |
3441 | 0 | return NULL; |
3442 | 193 | } |
3443 | | |
3444 | | static __isl_give isl_pw_aff *pw_aff_add(__isl_take isl_pw_aff *pwaff1, |
3445 | | __isl_take isl_pw_aff *pwaff2) |
3446 | 62.7k | { |
3447 | 62.7k | return isl_pw_aff_on_shared_domain(pwaff1, pwaff2, &isl_aff_add); |
3448 | 62.7k | } |
3449 | | |
3450 | | __isl_give isl_pw_aff *isl_pw_aff_add(__isl_take isl_pw_aff *pwaff1, |
3451 | | __isl_take isl_pw_aff *pwaff2) |
3452 | 62.7k | { |
3453 | 62.7k | return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2, &pw_aff_add); |
3454 | 62.7k | } |
3455 | | |
3456 | | __isl_give isl_pw_aff *isl_pw_aff_union_add(__isl_take isl_pw_aff *pwaff1, |
3457 | | __isl_take isl_pw_aff *pwaff2) |
3458 | 3.43k | { |
3459 | 3.43k | return isl_pw_aff_union_add_(pwaff1, pwaff2); |
3460 | 3.43k | } |
3461 | | |
3462 | | static __isl_give isl_pw_aff *pw_aff_mul(__isl_take isl_pw_aff *pwaff1, |
3463 | | __isl_take isl_pw_aff *pwaff2) |
3464 | 15.8k | { |
3465 | 15.8k | return isl_pw_aff_on_shared_domain(pwaff1, pwaff2, &isl_aff_mul); |
3466 | 15.8k | } |
3467 | | |
3468 | | __isl_give isl_pw_aff *isl_pw_aff_mul(__isl_take isl_pw_aff *pwaff1, |
3469 | | __isl_take isl_pw_aff *pwaff2) |
3470 | 15.8k | { |
3471 | 15.8k | return isl_pw_aff_align_params_pw_pw_and(pwaff1, pwaff2, &pw_aff_mul); |
3472 | 15.8k | } |
3473 | | |
3474 | | static __isl_give isl_pw_aff *pw_aff_div(__isl_take isl_pw_aff *pa1, |
3475 | | __isl_take isl_pw_aff *pa2) |
3476 | 163 | { |
3477 | 163 | return isl_pw_aff_on_shared_domain(pa1, pa2, &isl_aff_div); |
3478 | 163 | } |
3479 | | |
3480 | | /* Divide "pa1" by "pa2", assuming "pa2" is a piecewise constant. |
3481 | | */ |
3482 | | __isl_give isl_pw_aff *isl_pw_aff_div(__isl_take isl_pw_aff *pa1, |
3483 | | __isl_take isl_pw_aff *pa2) |
3484 | 163 | { |
3485 | 163 | int is_cst; |
3486 | 163 | |
3487 | 163 | is_cst = isl_pw_aff_is_cst(pa2); |
3488 | 163 | if (is_cst < 0) |
3489 | 0 | goto error; |
3490 | 163 | if (!is_cst) |
3491 | 163 | isl_die0 (isl_pw_aff_get_ctx(pa2), isl_error_invalid, |
3492 | 163 | "second argument should be a piecewise constant", |
3493 | 163 | goto error); |
3494 | 163 | return isl_pw_aff_align_params_pw_pw_and(pa1, pa2, &pw_aff_div); |
3495 | 0 | error: |
3496 | 0 | isl_pw_aff_free(pa1); |
3497 | 0 | isl_pw_aff_free(pa2); |
3498 | 0 | return NULL; |
3499 | 163 | } |
3500 | | |
3501 | | /* Compute the quotient of the integer division of "pa1" by "pa2" |
3502 | | * with rounding towards zero. |
3503 | | * "pa2" is assumed to be a piecewise constant. |
3504 | | * |
3505 | | * In particular, return |
3506 | | * |
3507 | | * pa1 >= 0 ? floor(pa1/pa2) : ceil(pa1/pa2) |
3508 | | * |
3509 | | */ |
3510 | | __isl_give isl_pw_aff *isl_pw_aff_tdiv_q(__isl_take isl_pw_aff *pa1, |
3511 | | __isl_take isl_pw_aff *pa2) |
3512 | 110 | { |
3513 | 110 | int is_cst; |
3514 | 110 | isl_set *cond; |
3515 | 110 | isl_pw_aff *f, *c; |
3516 | 110 | |
3517 | 110 | is_cst = isl_pw_aff_is_cst(pa2); |
3518 | 110 | if (is_cst < 0) |
3519 | 0 | goto error; |
3520 | 110 | if (!is_cst) |
3521 | 110 | isl_die0 (isl_pw_aff_get_ctx(pa2), isl_error_invalid, |
3522 | 110 | "second argument should be a piecewise constant", |
3523 | 110 | goto error); |
3524 | 110 | |
3525 | 110 | pa1 = isl_pw_aff_div(pa1, pa2); |
3526 | 110 | |
3527 | 110 | cond = isl_pw_aff_nonneg_set(isl_pw_aff_copy(pa1)); |
3528 | 110 | f = isl_pw_aff_floor(isl_pw_aff_copy(pa1)); |
3529 | 110 | c = isl_pw_aff_ceil(pa1); |
3530 | 110 | return isl_pw_aff_cond(isl_set_indicator_function(cond), f, c); |
3531 | 0 | error: |
3532 | 0 | isl_pw_aff_free(pa1); |
3533 | 0 | isl_pw_aff_free(pa2); |
3534 | 0 | return NULL; |
3535 | 110 | } |
3536 | | |
3537 | | /* Compute the remainder of the integer division of "pa1" by "pa2" |
3538 | | * with rounding towards zero. |
3539 | | * "pa2" is assumed to be a piecewise constant. |
3540 | | * |
3541 | | * In particular, return |
3542 | | * |
3543 | | * pa1 - pa2 * (pa1 >= 0 ? floor(pa1/pa2) : ceil(pa1/pa2)) |
3544 | | * |
3545 | | */ |
3546 | | __isl_give isl_pw_aff *isl_pw_aff_tdiv_r(__isl_take isl_pw_aff *pa1, |
3547 | | __isl_take isl_pw_aff *pa2) |
3548 | 52 | { |
3549 | 52 | int is_cst; |
3550 | 52 | isl_pw_aff *res; |
3551 | 52 | |
3552 | 52 | is_cst = isl_pw_aff_is_cst(pa2); |
3553 | 52 | if (is_cst < 0) |
3554 | 0 | goto error; |
3555 | 52 | if (!is_cst) |
3556 | 52 | isl_die0 (isl_pw_aff_get_ctx(pa2), isl_error_invalid, |
3557 | 52 | "second argument should be a piecewise constant", |
3558 | 52 | goto error); |
3559 | 52 | res = isl_pw_aff_tdiv_q(isl_pw_aff_copy(pa1), isl_pw_aff_copy(pa2)); |
3560 | 52 | res = isl_pw_aff_mul(pa2, res); |
3561 | 52 | res = isl_pw_aff_sub(pa1, res); |
3562 | 52 | return res; |
3563 | 0 | error: |
3564 | 0 | isl_pw_aff_free(pa1); |
3565 | 0 | isl_pw_aff_free(pa2); |
3566 | 0 | return NULL; |
3567 | 52 | } |
3568 | | |
3569 | | /* Does either of "pa1" or "pa2" involve any NaN2? |
3570 | | */ |
3571 | | static isl_bool either_involves_nan(__isl_keep isl_pw_aff *pa1, |
3572 | | __isl_keep isl_pw_aff *pa2) |
3573 | 89 | { |
3574 | 89 | isl_bool has_nan; |
3575 | 89 | |
3576 | 89 | has_nan = isl_pw_aff_involves_nan(pa1); |
3577 | 89 | if (has_nan < 0 || has_nan) |
3578 | 1 | return has_nan; |
3579 | 88 | return isl_pw_aff_involves_nan(pa2); |
3580 | 88 | } |
3581 | | |
3582 | | /* Replace "pa1" and "pa2" (at least one of which involves a NaN) |
3583 | | * by a NaN on their shared domain. |
3584 | | * |
3585 | | * In principle, the result could be refined to only being NaN |
3586 | | * on the parts of this domain where at least one of "pa1" or "pa2" is NaN. |
3587 | | */ |
3588 | | static __isl_give isl_pw_aff *replace_by_nan(__isl_take isl_pw_aff *pa1, |
3589 | | __isl_take isl_pw_aff *pa2) |
3590 | 2 | { |
3591 | 2 | isl_local_space *ls; |
3592 | 2 | isl_set *dom; |
3593 | 2 | isl_pw_aff *pa; |
3594 | 2 | |
3595 | 2 | dom = isl_set_intersect(isl_pw_aff_domain(pa1), isl_pw_aff_domain(pa2)); |
3596 | 2 | ls = isl_local_space_from_space(isl_set_get_space(dom)); |
3597 | 2 | pa = isl_pw_aff_nan_on_domain(ls); |
3598 | 2 | pa = isl_pw_aff_intersect_domain(pa, dom); |
3599 | 2 | |
3600 | 2 | return pa; |
3601 | 2 | } |
3602 | | |
3603 | | static __isl_give isl_pw_aff *pw_aff_min(__isl_take isl_pw_aff *pwaff1, |
3604 | | __isl_take isl_pw_aff *pwaff2) |
3605 | 12 | { |
3606 | 12 | isl_set *le; |
3607 | 12 | isl_set *dom; |
3608 | 12 | |
3609 | 12 | dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)), |
3610 | 12 | isl_pw_aff_domain(isl_pw_aff_copy(pwaff2))); |
3611 | 12 | le = isl_pw_aff_le_set(isl_pw_aff_copy(pwaff1), |
3612 | 12 | isl_pw_aff_copy(pwaff2)); |
3613 | 12 | dom = isl_set_subtract(dom, isl_set_copy(le)); |
3614 | 12 | return isl_pw_aff_select(le, pwaff1, dom, pwaff2); |
3615 | 12 | } |
3616 | | |
3617 | | static __isl_give isl_pw_aff *pw_aff_max(__isl_take isl_pw_aff *pwaff1, |
3618 | | __isl_take isl_pw_aff *pwaff2) |
3619 | 75 | { |
3620 | 75 | isl_set *ge; |
3621 | 75 | isl_set *dom; |
3622 | 75 | |
3623 | 75 | dom = isl_set_intersect(isl_pw_aff_domain(isl_pw_aff_copy(pwaff1)), |
3624 | 75 | isl_pw_aff_domain(isl_pw_aff_copy(pwaff2))); |
3625 | 75 | ge = isl_pw_aff_ge_set(isl_pw_aff_copy(pwaff1), |
3626 | 75 | isl_pw_aff_copy(pwaff2)); |
3627 | 75 | dom = isl_set_subtract(dom, isl_set_copy(ge)); |
3628 | 75 | return isl_pw_aff_select(ge, pwaff1, dom, pwaff2); |
3629 | 75 | } |
3630 | | |
3631 | | /* Return an expression for the minimum (if "max" is not set) or |
3632 | | * the maximum (if "max" is set) of "pa1" and "pa2". |
3633 | | * If either expression involves any NaN, then return a NaN |
3634 | | * on the shared domain as result. |
3635 | | */ |
3636 | | static __isl_give isl_pw_aff *pw_aff_min_max(__isl_take isl_pw_aff *pa1, |
3637 | | __isl_take isl_pw_aff *pa2, int max) |
3638 | 89 | { |
3639 | 89 | isl_bool has_nan; |
3640 | 89 | |
3641 | 89 | has_nan = either_involves_nan(pa1, pa2); |
3642 | 89 | if (has_nan < 0) |
3643 | 0 | pa1 = isl_pw_aff_free(pa1); |
3644 | 89 | else if (has_nan) |
3645 | 2 | return replace_by_nan(pa1, pa2); |
3646 | 87 | |
3647 | 87 | if (max) |
3648 | 75 | return isl_pw_aff_align_params_pw_pw_and(pa1, pa2, &pw_aff_max); |
3649 | 12 | else |
3650 | 12 | return isl_pw_aff_align_params_pw_pw_and(pa1, pa2, &pw_aff_min); |
3651 | 87 | } |
3652 | | |
3653 | | /* Return an expression for the minimum of "pwaff1" and "pwaff2". |
3654 | | */ |
3655 | | __isl_give isl_pw_aff *isl_pw_aff_min(__isl_take isl_pw_aff *pwaff1, |
3656 | | __isl_take isl_pw_aff *pwaff2) |
3657 | 14 | { |
3658 | 14 | return pw_aff_min_max(pwaff1, pwaff2, 0); |
3659 | 14 | } |
3660 | | |
3661 | | /* Return an expression for the maximum of "pwaff1" and "pwaff2". |
3662 | | */ |
3663 | | __isl_give isl_pw_aff *isl_pw_aff_max(__isl_take isl_pw_aff *pwaff1, |
3664 | | __isl_take isl_pw_aff *pwaff2) |
3665 | 75 | { |
3666 | 75 | return pw_aff_min_max(pwaff1, pwaff2, 1); |
3667 | 75 | } |
3668 | | |
3669 | | static __isl_give isl_pw_aff *pw_aff_list_reduce( |
3670 | | __isl_take isl_pw_aff_list *list, |
3671 | | __isl_give isl_pw_aff *(*fn)(__isl_take isl_pw_aff *pwaff1, |
3672 | | __isl_take isl_pw_aff *pwaff2)) |
3673 | 6 | { |
3674 | 6 | int i; |
3675 | 6 | isl_ctx *ctx; |
3676 | 6 | isl_pw_aff *res; |
3677 | 6 | |
3678 | 6 | if (!list) |
3679 | 0 | return NULL; |
3680 | 6 | |
3681 | 6 | ctx = isl_pw_aff_list_get_ctx(list); |
3682 | 6 | if (list->n < 1) |
3683 | 6 | isl_die0 (ctx, isl_error_invalid, |
3684 | 6 | "list should contain at least one element", goto error); |
3685 | 6 | |
3686 | 6 | res = isl_pw_aff_copy(list->p[0]); |
3687 | 12 | for (i = 1; i < list->n; ++i6 ) |
3688 | 6 | res = fn(res, isl_pw_aff_copy(list->p[i])); |
3689 | 6 | |
3690 | 6 | isl_pw_aff_list_free(list); |
3691 | 6 | return res; |
3692 | 0 | error: |
3693 | 0 | isl_pw_aff_list_free(list); |
3694 | 0 | return NULL; |
3695 | 6 | } |
3696 | | |
3697 | | /* Return an isl_pw_aff that maps each element in the intersection of the |
3698 | | * domains of the elements of list to the minimal corresponding affine |
3699 | | * expression. |
3700 | | */ |
3701 | | __isl_give isl_pw_aff *isl_pw_aff_list_min(__isl_take isl_pw_aff_list *list) |
3702 | 5 | { |
3703 | 5 | return pw_aff_list_reduce(list, &isl_pw_aff_min); |
3704 | 5 | } |
3705 | | |
3706 | | /* Return an isl_pw_aff that maps each element in the intersection of the |
3707 | | * domains of the elements of list to the maximal corresponding affine |
3708 | | * expression. |
3709 | | */ |
3710 | | __isl_give isl_pw_aff *isl_pw_aff_list_max(__isl_take isl_pw_aff_list *list) |
3711 | 1 | { |
3712 | 1 | return pw_aff_list_reduce(list, &isl_pw_aff_max); |
3713 | 1 | } |
3714 | | |
3715 | | /* Mark the domains of "pwaff" as rational. |
3716 | | */ |
3717 | | __isl_give isl_pw_aff *isl_pw_aff_set_rational(__isl_take isl_pw_aff *pwaff) |
3718 | 307 | { |
3719 | 307 | int i; |
3720 | 307 | |
3721 | 307 | pwaff = isl_pw_aff_cow(pwaff); |
3722 | 307 | if (!pwaff) |
3723 | 0 | return NULL; |
3724 | 307 | if (pwaff->n == 0) |
3725 | 0 | return pwaff; |
3726 | 307 | |
3727 | 614 | for (i = 0; 307 i < pwaff->n; ++i307 ) { |
3728 | 307 | pwaff->p[i].set = isl_set_set_rational(pwaff->p[i].set); |
3729 | 307 | if (!pwaff->p[i].set) |
3730 | 0 | return isl_pw_aff_free(pwaff); |
3731 | 307 | } |
3732 | 307 | |
3733 | 307 | return pwaff; |
3734 | 307 | } |
3735 | | |
3736 | | /* Mark the domains of the elements of "list" as rational. |
3737 | | */ |
3738 | | __isl_give isl_pw_aff_list *isl_pw_aff_list_set_rational( |
3739 | | __isl_take isl_pw_aff_list *list) |
3740 | 48 | { |
3741 | 48 | int i, n; |
3742 | 48 | |
3743 | 48 | if (!list) |
3744 | 0 | return NULL; |
3745 | 48 | if (list->n == 0) |
3746 | 0 | return list; |
3747 | 48 | |
3748 | 48 | n = list->n; |
3749 | 98 | for (i = 0; i < n; ++i50 ) { |
3750 | 50 | isl_pw_aff *pa; |
3751 | 50 | |
3752 | 50 | pa = isl_pw_aff_list_get_pw_aff(list, i); |
3753 | 50 | pa = isl_pw_aff_set_rational(pa); |
3754 | 50 | list = isl_pw_aff_list_set_pw_aff(list, i, pa); |
3755 | 50 | } |
3756 | 48 | |
3757 | 48 | return list; |
3758 | 48 | } |
3759 | | |
3760 | | /* Do the parameters of "aff" match those of "space"? |
3761 | | */ |
3762 | | isl_bool isl_aff_matching_params(__isl_keep isl_aff *aff, |
3763 | | __isl_keep isl_space *space) |
3764 | 1.55M | { |
3765 | 1.55M | isl_space *aff_space; |
3766 | 1.55M | isl_bool match; |
3767 | 1.55M | |
3768 | 1.55M | if (!aff || !space) |
3769 | 0 | return isl_bool_error; |
3770 | 1.55M | |
3771 | 1.55M | aff_space = isl_aff_get_domain_space(aff); |
3772 | 1.55M | |
3773 | 1.55M | match = isl_space_has_equal_params(space, aff_space); |
3774 | 1.55M | |
3775 | 1.55M | isl_space_free(aff_space); |
3776 | 1.55M | return match; |
3777 | 1.55M | } |
3778 | | |
3779 | | /* Check that the domain space of "aff" matches "space". |
3780 | | */ |
3781 | | isl_stat isl_aff_check_match_domain_space(__isl_keep isl_aff *aff, |
3782 | | __isl_keep isl_space *space) |
3783 | 1.55M | { |
3784 | 1.55M | isl_space *aff_space; |
3785 | 1.55M | isl_bool match; |
3786 | 1.55M | |
3787 | 1.55M | if (!aff || !space) |
3788 | 0 | return isl_stat_error; |
3789 | 1.55M | |
3790 | 1.55M | aff_space = isl_aff_get_domain_space(aff); |
3791 | 1.55M | |
3792 | 1.55M | match = isl_space_has_equal_params(space, aff_space); |
3793 | 1.55M | if (match < 0) |
3794 | 0 | goto error; |
3795 | 1.55M | if (!match) |
3796 | 1.55M | isl_die0 (isl_aff_get_ctx(aff), isl_error_invalid, |
3797 | 1.55M | "parameters don't match", goto error); |
3798 | 1.55M | match = isl_space_tuple_is_equal(space, isl_dim_in, |
3799 | 1.55M | aff_space, isl_dim_set); |
3800 | 1.55M | if (match < 0) |
3801 | 0 | goto error; |
3802 | 1.55M | if (!match) |
3803 | 1.55M | isl_die0 (isl_aff_get_ctx(aff), isl_error_invalid, |
3804 | 1.55M | "domains don't match", goto error); |
3805 | 1.55M | isl_space_free(aff_space); |
3806 | 1.55M | return isl_stat_ok; |
3807 | 0 | error: |
3808 | 0 | isl_space_free(aff_space); |
3809 | 0 | return isl_stat_error; |
3810 | 1.55M | } |
3811 | | |
3812 | | #undef BASE |
3813 | | #define BASE aff |
3814 | | #undef DOMBASE |
3815 | | #define DOMBASE set |
3816 | | #define NO_DOMAIN |
3817 | | |
3818 | | #include <isl_multi_no_explicit_domain.c> |
3819 | | #include <isl_multi_templ.c> |
3820 | | #include <isl_multi_apply_set.c> |
3821 | | #include <isl_multi_cmp.c> |
3822 | | #include <isl_multi_dims.c> |
3823 | | #include <isl_multi_floor.c> |
3824 | | #include <isl_multi_gist.c> |
3825 | | |
3826 | | #undef NO_DOMAIN |
3827 | | |
3828 | | /* Construct an isl_multi_aff living in "space" that corresponds |
3829 | | * to the affine transformation matrix "mat". |
3830 | | */ |
3831 | | __isl_give isl_multi_aff *isl_multi_aff_from_aff_mat( |
3832 | | __isl_take isl_space *space, __isl_take isl_mat *mat) |
3833 | 2 | { |
3834 | 2 | isl_ctx *ctx; |
3835 | 2 | isl_local_space *ls = NULL; |
3836 | 2 | isl_multi_aff *ma = NULL; |
3837 | 2 | int n_row, n_col, n_out, total; |
3838 | 2 | int i; |
3839 | 2 | |
3840 | 2 | if (!space || !mat) |
3841 | 0 | goto error; |
3842 | 2 | |
3843 | 2 | ctx = isl_mat_get_ctx(mat); |
3844 | 2 | |
3845 | 2 | n_row = isl_mat_rows(mat); |
3846 | 2 | n_col = isl_mat_cols(mat); |
3847 | 2 | if (n_row < 1) |
3848 | 2 | isl_die0 (ctx, isl_error_invalid, |
3849 | 2 | "insufficient number of rows", goto error); |
3850 | 2 | if (n_col < 1) |
3851 | 2 | isl_die0 (ctx, isl_error_invalid, |
3852 | 2 | "insufficient number of columns", goto error); |
3853 | 2 | n_out = isl_space_dim(space, isl_dim_out); |
3854 | 2 | total = isl_space_dim(space, isl_dim_all); |
3855 | 2 | if (1 + n_out != n_row || 2 + total != n_row + n_col) |
3856 | 2 | isl_die0 (ctx, isl_error_invalid, |
3857 | 2 | "dimension mismatch", goto error); |
3858 | 2 | |
3859 | 2 | ma = isl_multi_aff_zero(isl_space_copy(space)); |
3860 | 2 | ls = isl_local_space_from_space(isl_space_domain(space)); |
3861 | 2 | |
3862 | 4 | for (i = 0; i < n_row - 1; ++i2 ) { |
3863 | 2 | isl_vec *v; |
3864 | 2 | isl_aff *aff; |
3865 | 2 | |
3866 | 2 | v = isl_vec_alloc(ctx, 1 + n_col); |
3867 | 2 | if (!v) |
3868 | 0 | goto error; |
3869 | 2 | isl_int_set(v->el[0], mat->row[0][0]); |
3870 | 2 | isl_seq_cpy(v->el + 1, mat->row[1 + i], n_col); |
3871 | 2 | v = isl_vec_normalize(v); |
3872 | 2 | aff = isl_aff_alloc_vec(isl_local_space_copy(ls), v); |
3873 | 2 | ma = isl_multi_aff_set_aff(ma, i, aff); |
3874 | 2 | } |
3875 | 2 | |
3876 | 2 | isl_local_space_free(ls); |
3877 | 2 | isl_mat_free(mat); |
3878 | 2 | return ma; |
3879 | 0 | error: |
3880 | 0 | isl_local_space_free(ls); |
3881 | 0 | isl_mat_free(mat); |
3882 | 0 | isl_multi_aff_free(ma); |
3883 | 0 | return NULL; |
3884 | 2 | } |
3885 | | |
3886 | | /* Remove any internal structure of the domain of "ma". |
3887 | | * If there is any such internal structure in the input, |
3888 | | * then the name of the corresponding space is also removed. |
3889 | | */ |
3890 | | __isl_give isl_multi_aff *isl_multi_aff_flatten_domain( |
3891 | | __isl_take isl_multi_aff *ma) |
3892 | 0 | { |
3893 | 0 | isl_space *space; |
3894 | 0 |
|
3895 | 0 | if (!ma) |
3896 | 0 | return NULL; |
3897 | 0 | |
3898 | 0 | if (!ma->space->nested[0]) |
3899 | 0 | return ma; |
3900 | 0 | |
3901 | 0 | space = isl_multi_aff_get_space(ma); |
3902 | 0 | space = isl_space_flatten_domain(space); |
3903 | 0 | ma = isl_multi_aff_reset_space(ma, space); |
3904 | 0 |
|
3905 | 0 | return ma; |
3906 | 0 | } |
3907 | | |
3908 | | /* Given a map space, return an isl_multi_aff that maps a wrapped copy |
3909 | | * of the space to its domain. |
3910 | | */ |
3911 | | __isl_give isl_multi_aff *isl_multi_aff_domain_map(__isl_take isl_space *space) |
3912 | 764 | { |
3913 | 764 | int i, n_in; |
3914 | 764 | isl_local_space *ls; |
3915 | 764 | isl_multi_aff *ma; |
3916 | 764 | |
3917 | 764 | if (!space) |
3918 | 0 | return NULL; |
3919 | 764 | if (!isl_space_is_map(space)) |
3920 | 764 | isl_die0 (isl_space_get_ctx(space), isl_error_invalid, |
3921 | 764 | "not a map space", goto error); |
3922 | 764 | |
3923 | 764 | n_in = isl_space_dim(space, isl_dim_in); |
3924 | 764 | space = isl_space_domain_map(space); |
3925 | 764 | |
3926 | 764 | ma = isl_multi_aff_alloc(isl_space_copy(space)); |
3927 | 764 | if (n_in == 0) { |
3928 | 4 | isl_space_free(space); |
3929 | 4 | return ma; |
3930 | 4 | } |
3931 | 760 | |
3932 | 760 | space = isl_space_domain(space); |
3933 | 760 | ls = isl_local_space_from_space(space); |
3934 | 1.89k | for (i = 0; i < n_in; ++i1.13k ) { |
3935 | 1.13k | isl_aff *aff; |
3936 | 1.13k | |
3937 | 1.13k | aff = isl_aff_var_on_domain(isl_local_space_copy(ls), |
3938 | 1.13k | isl_dim_set, i); |
3939 | 1.13k | ma = isl_multi_aff_set_aff(ma, i, aff); |
3940 | 1.13k | } |
3941 | 760 | isl_local_space_free(ls); |
3942 | 760 | return ma; |
3943 | 0 | error: |
3944 | 0 | isl_space_free(space); |
3945 | 0 | return NULL; |
3946 | 760 | } |
3947 | | |
3948 | | /* Given a map space, return an isl_multi_aff that maps a wrapped copy |
3949 | | * of the space to its range. |
3950 | | */ |
3951 | | __isl_give isl_multi_aff *isl_multi_aff_range_map(__isl_take isl_space *space) |
3952 | 16 | { |
3953 | 16 | int i, n_in, n_out; |
3954 | 16 | isl_local_space *ls; |
3955 | 16 | isl_multi_aff *ma; |
3956 | 16 | |
3957 | 16 | if (!space) |
3958 | 0 | return NULL; |
3959 | 16 | if (!isl_space_is_map(space)) |
3960 | 16 | isl_die0 (isl_space_get_ctx(space), isl_error_invalid, |
3961 | 16 | "not a map space", goto error); |
3962 | 16 | |
3963 | 16 | n_in = isl_space_dim(space, isl_dim_in); |
3964 | 16 | n_out = isl_space_dim(space, isl_dim_out); |
3965 | 16 | space = isl_space_range_map(space); |
3966 | 16 | |
3967 | 16 | ma = isl_multi_aff_alloc(isl_space_copy(space)); |
3968 | 16 | if (n_out == 0) { |
3969 | 0 | isl_space_free(space); |
3970 | 0 | return ma; |
3971 | 0 | } |
3972 | 16 | |
3973 | 16 | space = isl_space_domain(space); |
3974 | 16 | ls = isl_local_space_from_space(space); |
3975 | 48 | for (i = 0; i < n_out; ++i32 ) { |
3976 | 32 | isl_aff *aff; |
3977 | 32 | |
3978 | 32 | aff = isl_aff_var_on_domain(isl_local_space_copy(ls), |
3979 | 32 | isl_dim_set, n_in + i); |
3980 | 32 | ma = isl_multi_aff_set_aff(ma, i, aff); |
3981 | 32 | } |
3982 | 16 | isl_local_space_free(ls); |
3983 | 16 | return ma; |
3984 | 0 | error: |
3985 | 0 | isl_space_free(space); |
3986 | 0 | return NULL; |
3987 | 16 | } |
3988 | | |
3989 | | /* Given a map space, return an isl_pw_multi_aff that maps a wrapped copy |
3990 | | * of the space to its range. |
3991 | | */ |
3992 | | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_map( |
3993 | | __isl_take isl_space *space) |
3994 | 0 | { |
3995 | 0 | return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_range_map(space)); |
3996 | 0 | } |
3997 | | |
3998 | | /* Given the space of a set and a range of set dimensions, |
3999 | | * construct an isl_multi_aff that projects out those dimensions. |
4000 | | */ |
4001 | | __isl_give isl_multi_aff *isl_multi_aff_project_out_map( |
4002 | | __isl_take isl_space *space, enum isl_dim_type type, |
4003 | | unsigned first, unsigned n) |
4004 | 2.64k | { |
4005 | 2.64k | int i, dim; |
4006 | 2.64k | isl_local_space *ls; |
4007 | 2.64k | isl_multi_aff *ma; |
4008 | 2.64k | |
4009 | 2.64k | if (!space) |
4010 | 0 | return NULL; |
4011 | 2.64k | if (!isl_space_is_set(space)) |
4012 | 2.64k | isl_die0 (isl_space_get_ctx(space), isl_error_unsupported, |
4013 | 2.64k | "expecting set space", goto error); |
4014 | 2.64k | if (type != isl_dim_set) |
4015 | 2.64k | isl_die0 (isl_space_get_ctx(space), isl_error_invalid, |
4016 | 2.64k | "only set dimensions can be projected out", goto error); |
4017 | 2.64k | |
4018 | 2.64k | dim = isl_space_dim(space, isl_dim_set); |
4019 | 2.64k | if (first + n > dim) |
4020 | 2.64k | isl_die0 (isl_space_get_ctx(space), isl_error_invalid, |
4021 | 2.64k | "range out of bounds", goto error); |
4022 | 2.64k | |
4023 | 2.64k | space = isl_space_from_domain(space); |
4024 | 2.64k | space = isl_space_add_dims(space, isl_dim_out, dim - n); |
4025 | 2.64k | |
4026 | 2.64k | if (dim == n) |
4027 | 0 | return isl_multi_aff_alloc(space); |
4028 | 2.64k | |
4029 | 2.64k | ma = isl_multi_aff_alloc(isl_space_copy(space)); |
4030 | 2.64k | space = isl_space_domain(space); |
4031 | 2.64k | ls = isl_local_space_from_space(space); |
4032 | 2.64k | |
4033 | 6.00k | for (i = 0; i < first; ++i3.35k ) { |
4034 | 3.35k | isl_aff *aff; |
4035 | 3.35k | |
4036 | 3.35k | aff = isl_aff_var_on_domain(isl_local_space_copy(ls), |
4037 | 3.35k | isl_dim_set, i); |
4038 | 3.35k | ma = isl_multi_aff_set_aff(ma, i, aff); |
4039 | 3.35k | } |
4040 | 2.64k | |
4041 | 2.69k | for (i = 0; i < dim - (first + n); ++i43 ) { |
4042 | 43 | isl_aff *aff; |
4043 | 43 | |
4044 | 43 | aff = isl_aff_var_on_domain(isl_local_space_copy(ls), |
4045 | 43 | isl_dim_set, first + n + i); |
4046 | 43 | ma = isl_multi_aff_set_aff(ma, first + i, aff); |
4047 | 43 | } |
4048 | 2.64k | |
4049 | 2.64k | isl_local_space_free(ls); |
4050 | 2.64k | return ma; |
4051 | 0 | error: |
4052 | 0 | isl_space_free(space); |
4053 | 0 | return NULL; |
4054 | 2.64k | } |
4055 | | |
4056 | | /* Given the space of a set and a range of set dimensions, |
4057 | | * construct an isl_pw_multi_aff that projects out those dimensions. |
4058 | | */ |
4059 | | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_out_map( |
4060 | | __isl_take isl_space *space, enum isl_dim_type type, |
4061 | | unsigned first, unsigned n) |
4062 | 2.57k | { |
4063 | 2.57k | isl_multi_aff *ma; |
4064 | 2.57k | |
4065 | 2.57k | ma = isl_multi_aff_project_out_map(space, type, first, n); |
4066 | 2.57k | return isl_pw_multi_aff_from_multi_aff(ma); |
4067 | 2.57k | } |
4068 | | |
4069 | | /* Create an isl_pw_multi_aff with the given isl_multi_aff on a universe |
4070 | | * domain. |
4071 | | */ |
4072 | | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_aff( |
4073 | | __isl_take isl_multi_aff *ma) |
4074 | 5.96k | { |
4075 | 5.96k | isl_set *dom = isl_set_universe(isl_multi_aff_get_domain_space(ma)); |
4076 | 5.96k | return isl_pw_multi_aff_alloc(dom, ma); |
4077 | 5.96k | } |
4078 | | |
4079 | | /* Create a piecewise multi-affine expression in the given space that maps each |
4080 | | * input dimension to the corresponding output dimension. |
4081 | | */ |
4082 | | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity( |
4083 | | __isl_take isl_space *space) |
4084 | 40 | { |
4085 | 40 | return isl_pw_multi_aff_from_multi_aff(isl_multi_aff_identity(space)); |
4086 | 40 | } |
4087 | | |
4088 | | /* Exploit the equalities in "eq" to simplify the affine expressions. |
4089 | | */ |
4090 | | static __isl_give isl_multi_aff *isl_multi_aff_substitute_equalities( |
4091 | | __isl_take isl_multi_aff *maff, __isl_take isl_basic_set *eq) |
4092 | 3.15k | { |
4093 | 3.15k | int i; |
4094 | 3.15k | |
4095 | 3.15k | maff = isl_multi_aff_cow(maff); |
4096 | 3.15k | if (!maff || !eq) |
4097 | 0 | goto error; |
4098 | 3.15k | |
4099 | 9.92k | for (i = 0; 3.15k i < maff->n; ++i6.77k ) { |
4100 | 6.77k | maff->u.p[i] = isl_aff_substitute_equalities(maff->u.p[i], |
4101 | 6.77k | isl_basic_set_copy(eq)); |
4102 | 6.77k | if (!maff->u.p[i]) |
4103 | 0 | goto error; |
4104 | 6.77k | } |
4105 | 3.15k | |
4106 | 3.15k | isl_basic_set_free(eq); |
4107 | 3.15k | return maff; |
4108 | 0 | error: |
4109 | 0 | isl_basic_set_free(eq); |
4110 | 0 | isl_multi_aff_free(maff); |
4111 | 0 | return NULL; |
4112 | 3.15k | } |
4113 | | |
4114 | | __isl_give isl_multi_aff *isl_multi_aff_scale(__isl_take isl_multi_aff *maff, |
4115 | | isl_int f) |
4116 | 0 | { |
4117 | 0 | int i; |
4118 | 0 |
|
4119 | 0 | maff = isl_multi_aff_cow(maff); |
4120 | 0 | if (!maff) |
4121 | 0 | return NULL; |
4122 | 0 | |
4123 | 0 | for (i = 0; i < maff->n; ++i) { |
4124 | 0 | maff->u.p[i] = isl_aff_scale(maff->u.p[i], f); |
4125 | 0 | if (!maff->u.p[i]) |
4126 | 0 | return isl_multi_aff_free(maff); |
4127 | 0 | } |
4128 | 0 |
|
4129 | 0 | return maff; |
4130 | 0 | } |
4131 | | |
4132 | | __isl_give isl_multi_aff *isl_multi_aff_add_on_domain(__isl_keep isl_set *dom, |
4133 | | __isl_take isl_multi_aff *maff1, __isl_take isl_multi_aff *maff2) |
4134 | 2 | { |
4135 | 2 | maff1 = isl_multi_aff_add(maff1, maff2); |
4136 | 2 | maff1 = isl_multi_aff_gist(maff1, isl_set_copy(dom)); |
4137 | 2 | return maff1; |
4138 | 2 | } |
4139 | | |
4140 | | int isl_multi_aff_is_empty(__isl_keep isl_multi_aff *maff) |
4141 | 34.0k | { |
4142 | 34.0k | if (!maff) |
4143 | 0 | return -1; |
4144 | 34.0k | |
4145 | 34.0k | return 0; |
4146 | 34.0k | } |
4147 | | |
4148 | | /* Return the set of domain elements where "ma1" is lexicographically |
4149 | | * smaller than or equal to "ma2". |
4150 | | */ |
4151 | | __isl_give isl_set *isl_multi_aff_lex_le_set(__isl_take isl_multi_aff *ma1, |
4152 | | __isl_take isl_multi_aff *ma2) |
4153 | 642 | { |
4154 | 642 | return isl_multi_aff_lex_ge_set(ma2, ma1); |
4155 | 642 | } |
4156 | | |
4157 | | /* Return the set of domain elements where "ma1" is lexicographically |
4158 | | * smaller than "ma2". |
4159 | | */ |
4160 | | __isl_give isl_set *isl_multi_aff_lex_lt_set(__isl_take isl_multi_aff *ma1, |
4161 | | __isl_take isl_multi_aff *ma2) |
4162 | 0 | { |
4163 | 0 | return isl_multi_aff_lex_gt_set(ma2, ma1); |
4164 | 0 | } |
4165 | | |
4166 | | /* Return the set of domain elements where "ma1" and "ma2" |
4167 | | * satisfy "order". |
4168 | | */ |
4169 | | static __isl_give isl_set *isl_multi_aff_order_set( |
4170 | | __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2, |
4171 | | __isl_give isl_map *order(__isl_take isl_space *set_space)) |
4172 | 1.35k | { |
4173 | 1.35k | isl_space *space; |
4174 | 1.35k | isl_map *map1, *map2; |
4175 | 1.35k | isl_map *map, *ge; |
4176 | 1.35k | |
4177 | 1.35k | map1 = isl_map_from_multi_aff_internal(ma1); |
4178 | 1.35k | map2 = isl_map_from_multi_aff_internal(ma2); |
4179 | 1.35k | map = isl_map_range_product(map1, map2); |
4180 | 1.35k | space = isl_space_range(isl_map_get_space(map)); |
4181 | 1.35k | space = isl_space_domain(isl_space_unwrap(space)); |
4182 | 1.35k | ge = order(space); |
4183 | 1.35k | map = isl_map_intersect_range(map, isl_map_wrap(ge)); |
4184 | 1.35k | |
4185 | 1.35k | return isl_map_domain(map); |
4186 | 1.35k | } |
4187 | | |
4188 | | /* Return the set of domain elements where "ma1" is lexicographically |
4189 | | * greater than or equal to "ma2". |
4190 | | */ |
4191 | | __isl_give isl_set *isl_multi_aff_lex_ge_set(__isl_take isl_multi_aff *ma1, |
4192 | | __isl_take isl_multi_aff *ma2) |
4193 | 1.35k | { |
4194 | 1.35k | return isl_multi_aff_order_set(ma1, ma2, &isl_map_lex_ge); |
4195 | 1.35k | } |
4196 | | |
4197 | | /* Return the set of domain elements where "ma1" is lexicographically |
4198 | | * greater than "ma2". |
4199 | | */ |
4200 | | __isl_give isl_set *isl_multi_aff_lex_gt_set(__isl_take isl_multi_aff *ma1, |
4201 | | __isl_take isl_multi_aff *ma2) |
4202 | 0 | { |
4203 | 0 | return isl_multi_aff_order_set(ma1, ma2, &isl_map_lex_gt); |
4204 | 0 | } |
4205 | | |
4206 | | #undef PW |
4207 | 30.2k | #define PW isl_pw_multi_aff |
4208 | | #undef EL |
4209 | 5.67k | #define EL isl_multi_aff |
4210 | | #undef EL_IS_ZERO |
4211 | | #define EL_IS_ZERO is_empty |
4212 | | #undef ZERO |
4213 | | #define ZERO empty |
4214 | | #undef IS_ZERO |
4215 | | #define IS_ZERO is_empty |
4216 | | #undef FIELD |
4217 | 145k | #define FIELD maff |
4218 | | #undef DEFAULT_IS_ZERO |
4219 | 0 | #define DEFAULT_IS_ZERO 0 |
4220 | | |
4221 | | #define NO_SUB |
4222 | | #define NO_OPT |
4223 | | #define NO_INSERT_DIMS |
4224 | | #define NO_LIFT |
4225 | | #define NO_MORPH |
4226 | | |
4227 | | #include <isl_pw_templ.c> |
4228 | | #include <isl_pw_union_opt.c> |
4229 | | |
4230 | | #undef NO_SUB |
4231 | | |
4232 | | #undef BASE |
4233 | | #define BASE pw_multi_aff |
4234 | | |
4235 | | #include <isl_union_multi.c> |
4236 | | #include <isl_union_neg.c> |
4237 | | |
4238 | | static __isl_give isl_pw_multi_aff *pw_multi_aff_union_lexmax( |
4239 | | __isl_take isl_pw_multi_aff *pma1, |
4240 | | __isl_take isl_pw_multi_aff *pma2) |
4241 | 792 | { |
4242 | 792 | return isl_pw_multi_aff_union_opt_cmp(pma1, pma2, |
4243 | 792 | &isl_multi_aff_lex_ge_set); |
4244 | 792 | } |
4245 | | |
4246 | | /* Given two piecewise multi affine expressions, return a piecewise |
4247 | | * multi-affine expression defined on the union of the definition domains |
4248 | | * of the inputs that is equal to the lexicographic maximum of the two |
4249 | | * inputs on each cell. If only one of the two inputs is defined on |
4250 | | * a given cell, then it is considered to be the maximum. |
4251 | | */ |
4252 | | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmax( |
4253 | | __isl_take isl_pw_multi_aff *pma1, |
4254 | | __isl_take isl_pw_multi_aff *pma2) |
4255 | 792 | { |
4256 | 792 | return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2, |
4257 | 792 | &pw_multi_aff_union_lexmax); |
4258 | 792 | } |
4259 | | |
4260 | | static __isl_give isl_pw_multi_aff *pw_multi_aff_union_lexmin( |
4261 | | __isl_take isl_pw_multi_aff *pma1, |
4262 | | __isl_take isl_pw_multi_aff *pma2) |
4263 | 698 | { |
4264 | 698 | return isl_pw_multi_aff_union_opt_cmp(pma1, pma2, |
4265 | 698 | &isl_multi_aff_lex_le_set); |
4266 | 698 | } |
4267 | | |
4268 | | /* Given two piecewise multi affine expressions, return a piecewise |
4269 | | * multi-affine expression defined on the union of the definition domains |
4270 | | * of the inputs that is equal to the lexicographic minimum of the two |
4271 | | * inputs on each cell. If only one of the two inputs is defined on |
4272 | | * a given cell, then it is considered to be the minimum. |
4273 | | */ |
4274 | | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmin( |
4275 | | __isl_take isl_pw_multi_aff *pma1, |
4276 | | __isl_take isl_pw_multi_aff *pma2) |
4277 | 698 | { |
4278 | 698 | return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2, |
4279 | 698 | &pw_multi_aff_union_lexmin); |
4280 | 698 | } |
4281 | | |
4282 | | static __isl_give isl_pw_multi_aff *pw_multi_aff_add( |
4283 | | __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) |
4284 | 1 | { |
4285 | 1 | return isl_pw_multi_aff_on_shared_domain(pma1, pma2, |
4286 | 1 | &isl_multi_aff_add); |
4287 | 1 | } |
4288 | | |
4289 | | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_add( |
4290 | | __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) |
4291 | 1 | { |
4292 | 1 | return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2, |
4293 | 1 | &pw_multi_aff_add); |
4294 | 1 | } |
4295 | | |
4296 | | static __isl_give isl_pw_multi_aff *pw_multi_aff_sub( |
4297 | | __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) |
4298 | 0 | { |
4299 | 0 | return isl_pw_multi_aff_on_shared_domain(pma1, pma2, |
4300 | 0 | &isl_multi_aff_sub); |
4301 | 0 | } |
4302 | | |
4303 | | /* Subtract "pma2" from "pma1" and return the result. |
4304 | | */ |
4305 | | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub( |
4306 | | __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) |
4307 | 0 | { |
4308 | 0 | return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2, |
4309 | 0 | &pw_multi_aff_sub); |
4310 | 0 | } |
4311 | | |
4312 | | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_add( |
4313 | | __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) |
4314 | 385 | { |
4315 | 385 | return isl_pw_multi_aff_union_add_(pma1, pma2); |
4316 | 385 | } |
4317 | | |
4318 | | /* Compute the sum of "upa1" and "upa2" on the union of their domains, |
4319 | | * with the actual sum on the shared domain and |
4320 | | * the defined expression on the symmetric difference of the domains. |
4321 | | */ |
4322 | | __isl_give isl_union_pw_aff *isl_union_pw_aff_union_add( |
4323 | | __isl_take isl_union_pw_aff *upa1, __isl_take isl_union_pw_aff *upa2) |
4324 | 332 | { |
4325 | 332 | return isl_union_pw_aff_union_add_(upa1, upa2); |
4326 | 332 | } |
4327 | | |
4328 | | /* Compute the sum of "upma1" and "upma2" on the union of their domains, |
4329 | | * with the actual sum on the shared domain and |
4330 | | * the defined expression on the symmetric difference of the domains. |
4331 | | */ |
4332 | | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_union_add( |
4333 | | __isl_take isl_union_pw_multi_aff *upma1, |
4334 | | __isl_take isl_union_pw_multi_aff *upma2) |
4335 | 120 | { |
4336 | 120 | return isl_union_pw_multi_aff_union_add_(upma1, upma2); |
4337 | 120 | } |
4338 | | |
4339 | | /* Given two piecewise multi-affine expressions A -> B and C -> D, |
4340 | | * construct a piecewise multi-affine expression [A -> C] -> [B -> D]. |
4341 | | */ |
4342 | | static __isl_give isl_pw_multi_aff *pw_multi_aff_product( |
4343 | | __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) |
4344 | 1 | { |
4345 | 1 | int i, j, n; |
4346 | 1 | isl_space *space; |
4347 | 1 | isl_pw_multi_aff *res; |
4348 | 1 | |
4349 | 1 | if (!pma1 || !pma2) |
4350 | 0 | goto error; |
4351 | 1 | |
4352 | 1 | n = pma1->n * pma2->n; |
4353 | 1 | space = isl_space_product(isl_space_copy(pma1->dim), |
4354 | 1 | isl_space_copy(pma2->dim)); |
4355 | 1 | res = isl_pw_multi_aff_alloc_size(space, n); |
4356 | 1 | |
4357 | 3 | for (i = 0; i < pma1->n; ++i2 ) { |
4358 | 4 | for (j = 0; j < pma2->n; ++j2 ) { |
4359 | 2 | isl_set *domain; |
4360 | 2 | isl_multi_aff *ma; |
4361 | 2 | |
4362 | 2 | domain = isl_set_product(isl_set_copy(pma1->p[i].set), |
4363 | 2 | isl_set_copy(pma2->p[j].set)); |
4364 | 2 | ma = isl_multi_aff_product( |
4365 | 2 | isl_multi_aff_copy(pma1->p[i].maff), |
4366 | 2 | isl_multi_aff_copy(pma2->p[j].maff)); |
4367 | 2 | res = isl_pw_multi_aff_add_piece(res, domain, ma); |
4368 | 2 | } |
4369 | 2 | } |
4370 | 1 | |
4371 | 1 | isl_pw_multi_aff_free(pma1); |
4372 | 1 | isl_pw_multi_aff_free(pma2); |
4373 | 1 | return res; |
4374 | 0 | error: |
4375 | 0 | isl_pw_multi_aff_free(pma1); |
4376 | 0 | isl_pw_multi_aff_free(pma2); |
4377 | 0 | return NULL; |
4378 | 1 | } |
4379 | | |
4380 | | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_product( |
4381 | | __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) |
4382 | 1 | { |
4383 | 1 | return isl_pw_multi_aff_align_params_pw_pw_and(pma1, pma2, |
4384 | 1 | &pw_multi_aff_product); |
4385 | 1 | } |
4386 | | |
4387 | | /* Subtract the initial "n" elements in "ma" with coefficients in "c" and |
4388 | | * denominator "denom". |
4389 | | * "denom" is allowed to be negative, in which case the actual denominator |
4390 | | * is -denom and the expressions are added instead. |
4391 | | */ |
4392 | | static __isl_give isl_aff *subtract_initial(__isl_take isl_aff *aff, |
4393 | | __isl_keep isl_multi_aff *ma, int n, isl_int *c, isl_int denom) |
4394 | 10.6k | { |
4395 | 10.6k | int i, first; |
4396 | 10.6k | int sign; |
4397 | 10.6k | isl_int d; |
4398 | 10.6k | |
4399 | 10.6k | first = isl_seq_first_non_zero(c, n); |
4400 | 10.6k | if (first == -1) |
4401 | 10.5k | return aff; |
4402 | 3 | |
4403 | 3 | sign = isl_int_sgn(denom); |
4404 | 3 | isl_int_init(d); |
4405 | 3 | isl_int_abs(d, denom); |
4406 | 6 | for (i = first; i < n; ++i3 ) { |
4407 | 3 | isl_aff *aff_i; |
4408 | 3 | |
4409 | 3 | if (isl_int_is_zero(c[i])) |
4410 | 3 | continue0 ; |
4411 | 3 | aff_i = isl_multi_aff_get_aff(ma, i); |
4412 | 3 | aff_i = isl_aff_scale(aff_i, c[i]); |
4413 | 3 | aff_i = isl_aff_scale_down(aff_i, d); |
4414 | 3 | if (sign >= 0) |
4415 | 2 | aff = isl_aff_sub(aff, aff_i); |
4416 | 1 | else |
4417 | 1 | aff = isl_aff_add(aff, aff_i); |
4418 | 3 | } |
4419 | 3 | isl_int_clear(d); |
4420 | 3 | |
4421 | 3 | return aff; |
4422 | 3 | } |
4423 | | |
4424 | | /* Extract an affine expression that expresses the output dimension "pos" |
4425 | | * of "bmap" in terms of the parameters and input dimensions from |
4426 | | * equality "eq". |
4427 | | * Note that this expression may involve integer divisions defined |
4428 | | * in terms of parameters and input dimensions. |
4429 | | * The equality may also involve references to earlier (but not later) |
4430 | | * output dimensions. These are replaced by the corresponding elements |
4431 | | * in "ma". |
4432 | | * |
4433 | | * If the equality is of the form |
4434 | | * |
4435 | | * f(i) + h(j) + a x + g(i) = 0, |
4436 | | * |
4437 | | * with f(i) a linear combinations of the parameters and input dimensions, |
4438 | | * g(i) a linear combination of integer divisions defined in terms of the same |
4439 | | * and h(j) a linear combinations of earlier output dimensions, |
4440 | | * then the affine expression is |
4441 | | * |
4442 | | * (-f(i) - g(i))/a - h(j)/a |
4443 | | * |
4444 | | * If the equality is of the form |
4445 | | * |
4446 | | * f(i) + h(j) - a x + g(i) = 0, |
4447 | | * |
4448 | | * then the affine expression is |
4449 | | * |
4450 | | * (f(i) + g(i))/a - h(j)/(-a) |
4451 | | * |
4452 | | * |
4453 | | * If "div" refers to an integer division (i.e., it is smaller than |
4454 | | * the number of integer divisions), then the equality constraint |
4455 | | * does involve an integer division (the one at position "div") that |
4456 | | * is defined in terms of output dimensions. However, this integer |
4457 | | * division can be eliminated by exploiting a pair of constraints |
4458 | | * x >= l and x <= l + n, with n smaller than the coefficient of "div" |
4459 | | * in the equality constraint. "ineq" refers to inequality x >= l, i.e., |
4460 | | * -l + x >= 0. |
4461 | | * In particular, let |
4462 | | * |
4463 | | * x = e(i) + m floor(...) |
4464 | | * |
4465 | | * with e(i) the expression derived above and floor(...) the integer |
4466 | | * division involving output dimensions. |
4467 | | * From |
4468 | | * |
4469 | | * l <= x <= l + n, |
4470 | | * |
4471 | | * we have |
4472 | | * |
4473 | | * 0 <= x - l <= n |
4474 | | * |
4475 | | * This means |
4476 | | * |
4477 | | * e(i) + m floor(...) - l = (e(i) + m floor(...) - l) mod m |
4478 | | * = (e(i) - l) mod m |
4479 | | * |
4480 | | * Therefore, |
4481 | | * |
4482 | | * x - l = (e(i) - l) mod m |
4483 | | * |
4484 | | * or |
4485 | | * |
4486 | | * x = ((e(i) - l) mod m) + l |
4487 | | * |
4488 | | * The variable "shift" below contains the expression -l, which may |
4489 | | * also involve a linear combination of earlier output dimensions. |
4490 | | */ |
4491 | | static __isl_give isl_aff *extract_aff_from_equality( |
4492 | | __isl_keep isl_basic_map *bmap, int pos, int eq, int div, int ineq, |
4493 | | __isl_keep isl_multi_aff *ma) |
4494 | 10.5k | { |
4495 | 10.5k | unsigned o_out; |
4496 | 10.5k | unsigned n_div, n_out; |
4497 | 10.5k | isl_ctx *ctx; |
4498 | 10.5k | isl_local_space *ls; |
4499 | 10.5k | isl_aff *aff, *shift; |
4500 | 10.5k | isl_val *mod; |
4501 | 10.5k | |
4502 | 10.5k | ctx = isl_basic_map_get_ctx(bmap); |
4503 | 10.5k | ls = isl_basic_map_get_local_space(bmap); |
4504 | 10.5k | ls = isl_local_space_domain(ls); |
4505 | 10.5k | aff = isl_aff_alloc(isl_local_space_copy(ls)); |
4506 | 10.5k | if (!aff) |
4507 | 0 | goto error; |
4508 | 10.5k | o_out = isl_basic_map_offset(bmap, isl_dim_out); |
4509 | 10.5k | n_out = isl_basic_map_dim(bmap, isl_dim_out); |
4510 | 10.5k | n_div = isl_basic_map_dim(bmap, isl_dim_div); |
4511 | 10.5k | if (isl_int_is_neg(bmap->eq[eq][o_out + pos])) { |
4512 | 357 | isl_seq_cpy(aff->v->el + 1, bmap->eq[eq], o_out); |
4513 | 357 | isl_seq_cpy(aff->v->el + 1 + o_out, |
4514 | 357 | bmap->eq[eq] + o_out + n_out, n_div); |
4515 | 10.1k | } else { |
4516 | 10.1k | isl_seq_neg(aff->v->el + 1, bmap->eq[eq], o_out); |
4517 | 10.1k | isl_seq_neg(aff->v->el + 1 + o_out, |
4518 | 10.1k | bmap->eq[eq] + o_out + n_out, n_div); |
4519 | 10.1k | } |
4520 | 10.5k | if (div < n_div) |
4521 | 10.5k | isl_int_set_si101 (aff->v->el[1 + o_out + div], 0); |
4522 | 10.5k | isl_int_abs(aff->v->el[0], bmap->eq[eq][o_out + pos]); |
4523 | 10.5k | aff = subtract_initial(aff, ma, pos, bmap->eq[eq] + o_out, |
4524 | 10.5k | bmap->eq[eq][o_out + pos]); |
4525 | 10.5k | if (div < n_div) { |
4526 | 101 | shift = isl_aff_alloc(isl_local_space_copy(ls)); |
4527 | 101 | if (!shift) |
4528 | 0 | goto error; |
4529 | 101 | isl_seq_cpy(shift->v->el + 1, bmap->ineq[ineq], o_out); |
4530 | 101 | isl_seq_cpy(shift->v->el + 1 + o_out, |
4531 | 101 | bmap->ineq[ineq] + o_out + n_out, n_div); |
4532 | 101 | isl_int_set_si(shift->v->el[0], 1); |
4533 | 101 | shift = subtract_initial(shift, ma, pos, |
4534 | 101 | bmap->ineq[ineq] + o_out, ctx->negone); |
4535 | 101 | aff = isl_aff_add(aff, isl_aff_copy(shift)); |
4536 | 101 | mod = isl_val_int_from_isl_int(ctx, |
4537 | 101 | bmap->eq[eq][o_out + n_out + div]); |
4538 | 101 | mod = isl_val_abs(mod); |
4539 | 101 | aff = isl_aff_mod_val(aff, mod); |
4540 | 101 | aff = isl_aff_sub(aff, shift); |
4541 | 101 | } |
4542 | 10.5k | |
4543 | 10.5k | isl_local_space_free(ls); |
4544 | 10.5k | return aff; |
4545 | 0 | error: |
4546 | 0 | isl_local_space_free(ls); |
4547 | 0 | isl_aff_free(aff); |
4548 | 0 | return NULL; |
4549 | 10.5k | } |
4550 | | |
4551 | | /* Given a basic map with output dimensions defined |
4552 | | * in terms of the parameters input dimensions and earlier |
4553 | | * output dimensions using an equality (and possibly a pair on inequalities), |
4554 | | * extract an isl_aff that expresses output dimension "pos" in terms |
4555 | | * of the parameters and input dimensions. |
4556 | | * Note that this expression may involve integer divisions defined |
4557 | | * in terms of parameters and input dimensions. |
4558 | | * "ma" contains the expressions corresponding to earlier output dimensions. |
4559 | | * |
4560 | | * This function shares some similarities with |
4561 | | * isl_basic_map_has_defining_equality and isl_constraint_get_bound. |
4562 | | */ |
4563 | | static __isl_give isl_aff *extract_isl_aff_from_basic_map( |
4564 | | __isl_keep isl_basic_map *bmap, int pos, __isl_keep isl_multi_aff *ma) |
4565 | 10.5k | { |
4566 | 10.5k | int eq, div, ineq; |
4567 | 10.5k | isl_aff *aff; |
4568 | 10.5k | |
4569 | 10.5k | if (!bmap) |
4570 | 0 | return NULL; |
4571 | 10.5k | eq = isl_basic_map_output_defining_equality(bmap, pos, &div, &ineq); |
4572 | 10.5k | if (eq >= bmap->n_eq) |
4573 | 10.5k | isl_die0 (isl_basic_map_get_ctx(bmap), isl_error_invalid, |
4574 | 10.5k | "unable to find suitable equality", return NULL); |
4575 | 10.5k | aff = extract_aff_from_equality(bmap, pos, eq, div, ineq, ma); |
4576 | 10.5k | |
4577 | 10.5k | aff = isl_aff_remove_unused_divs(aff); |
4578 | 10.5k | return aff; |
4579 | 10.5k | } |
4580 | | |
4581 | | /* Given a basic map where each output dimension is defined |
4582 | | * in terms of the parameters and input dimensions using an equality, |
4583 | | * extract an isl_multi_aff that expresses the output dimensions in terms |
4584 | | * of the parameters and input dimensions. |
4585 | | */ |
4586 | | static __isl_give isl_multi_aff *extract_isl_multi_aff_from_basic_map( |
4587 | | __isl_take isl_basic_map *bmap) |
4588 | 6.86k | { |
4589 | 6.86k | int i; |
4590 | 6.86k | unsigned n_out; |
4591 | 6.86k | isl_multi_aff *ma; |
4592 | 6.86k | |
4593 | 6.86k | if (!bmap) |
4594 | 0 | return NULL; |
4595 | 6.86k | |
4596 | 6.86k | ma = isl_multi_aff_alloc(isl_basic_map_get_space(bmap)); |
4597 | 6.86k | n_out = isl_basic_map_dim(bmap, isl_dim_out); |
4598 | 6.86k | |
4599 | 17.3k | for (i = 0; i < n_out; ++i10.5k ) { |
4600 | 10.5k | isl_aff *aff; |
4601 | 10.5k | |
4602 | 10.5k | aff = extract_isl_aff_from_basic_map(bmap, i, ma); |
4603 | 10.5k | ma = isl_multi_aff_set_aff(ma, i, aff); |
4604 | 10.5k | } |
4605 | 6.86k | |
4606 | 6.86k | isl_basic_map_free(bmap); |
4607 | 6.86k | |
4608 | 6.86k | return ma; |
4609 | 6.86k | } |
4610 | | |
4611 | | /* Given a basic set where each set dimension is defined |
4612 | | * in terms of the parameters using an equality, |
4613 | | * extract an isl_multi_aff that expresses the set dimensions in terms |
4614 | | * of the parameters. |
4615 | | */ |
4616 | | __isl_give isl_multi_aff *isl_multi_aff_from_basic_set_equalities( |
4617 | | __isl_take isl_basic_set *bset) |
4618 | 9 | { |
4619 | 9 | return extract_isl_multi_aff_from_basic_map(bset); |
4620 | 9 | } |
4621 | | |
4622 | | /* Create an isl_pw_multi_aff that is equivalent to |
4623 | | * isl_map_intersect_domain(isl_map_from_basic_map(bmap), domain). |
4624 | | * The given basic map is such that each output dimension is defined |
4625 | | * in terms of the parameters and input dimensions using an equality. |
4626 | | * |
4627 | | * Since some applications expect the result of isl_pw_multi_aff_from_map |
4628 | | * to only contain integer affine expressions, we compute the floor |
4629 | | * of the expression before returning. |
4630 | | * |
4631 | | * Remove all constraints involving local variables without |
4632 | | * an explicit representation (resulting in the removal of those |
4633 | | * local variables) prior to the actual extraction to ensure |
4634 | | * that the local spaces in which the resulting affine expressions |
4635 | | * are created do not contain any unknown local variables. |
4636 | | * Removing such constraints is safe because constraints involving |
4637 | | * unknown local variables are not used to determine whether |
4638 | | * a basic map is obviously single-valued. |
4639 | | */ |
4640 | | static __isl_give isl_pw_multi_aff *plain_pw_multi_aff_from_map( |
4641 | | __isl_take isl_set *domain, __isl_take isl_basic_map *bmap) |
4642 | 6.85k | { |
4643 | 6.85k | isl_multi_aff *ma; |
4644 | 6.85k | |
4645 | 6.85k | bmap = isl_basic_map_drop_constraint_involving_unknown_divs(bmap); |
4646 | 6.85k | ma = extract_isl_multi_aff_from_basic_map(bmap); |
4647 | 6.85k | ma = isl_multi_aff_floor(ma); |
4648 | 6.85k | return isl_pw_multi_aff_alloc(domain, ma); |
4649 | 6.85k | } |
4650 | | |
4651 | | /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map. |
4652 | | * This obviously only works if the input "map" is single-valued. |
4653 | | * If so, we compute the lexicographic minimum of the image in the form |
4654 | | * of an isl_pw_multi_aff. Since the image is unique, it is equal |
4655 | | * to its lexicographic minimum. |
4656 | | * If the input is not single-valued, we produce an error. |
4657 | | */ |
4658 | | static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_base( |
4659 | | __isl_take isl_map *map) |
4660 | 31 | { |
4661 | 31 | int i; |
4662 | 31 | int sv; |
4663 | 31 | isl_pw_multi_aff *pma; |
4664 | 31 | |
4665 | 31 | sv = isl_map_is_single_valued(map); |
4666 | 31 | if (sv < 0) |
4667 | 0 | goto error; |
4668 | 31 | if (!sv) |
4669 | 31 | isl_die0 (isl_map_get_ctx(map), isl_error_invalid, |
4670 | 31 | "map is not single-valued", goto error); |
4671 | 31 | map = isl_map_make_disjoint(map); |
4672 | 31 | if (!map) |
4673 | 0 | return NULL; |
4674 | 31 | |
4675 | 31 | pma = isl_pw_multi_aff_empty(isl_map_get_space(map)); |
4676 | 31 | |
4677 | 107 | for (i = 0; i < map->n; ++i76 ) { |
4678 | 76 | isl_pw_multi_aff *pma_i; |
4679 | 76 | isl_basic_map *bmap; |
4680 | 76 | bmap = isl_basic_map_copy(map->p[i]); |
4681 | 76 | pma_i = isl_basic_map_lexmin_pw_multi_aff(bmap); |
4682 | 76 | pma = isl_pw_multi_aff_add_disjoint(pma, pma_i); |
4683 | 76 | } |
4684 | 31 | |
4685 | 31 | isl_map_free(map); |
4686 | 31 | return pma; |
4687 | 0 | error: |
4688 | 0 | isl_map_free(map); |
4689 | 0 | return NULL; |
4690 | 31 | } |
4691 | | |
4692 | | /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map, |
4693 | | * taking into account that the output dimension at position "d" |
4694 | | * can be represented as |
4695 | | * |
4696 | | * x = floor((e(...) + c1) / m) |
4697 | | * |
4698 | | * given that constraint "i" is of the form |
4699 | | * |
4700 | | * e(...) + c1 - m x >= 0 |
4701 | | * |
4702 | | * |
4703 | | * Let "map" be of the form |
4704 | | * |
4705 | | * A -> B |
4706 | | * |
4707 | | * We construct a mapping |
4708 | | * |
4709 | | * A -> [A -> x = floor(...)] |
4710 | | * |
4711 | | * apply that to the map, obtaining |
4712 | | * |
4713 | | * [A -> x = floor(...)] -> B |
4714 | | * |
4715 | | * and equate dimension "d" to x. |
4716 | | * We then compute a isl_pw_multi_aff representation of the resulting map |
4717 | | * and plug in the mapping above. |
4718 | | */ |
4719 | | static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_div( |
4720 | | __isl_take isl_map *map, __isl_take isl_basic_map *hull, int d, int i) |
4721 | 104 | { |
4722 | 104 | isl_ctx *ctx; |
4723 | 104 | isl_space *space; |
4724 | 104 | isl_local_space *ls; |
4725 | 104 | isl_multi_aff *ma; |
4726 | 104 | isl_aff *aff; |
4727 | 104 | isl_vec *v; |
4728 | 104 | isl_map *insert; |
4729 | 104 | int offset; |
4730 | 104 | int n; |
4731 | 104 | int n_in; |
4732 | 104 | isl_pw_multi_aff *pma; |
4733 | 104 | isl_bool is_set; |
4734 | 104 | |
4735 | 104 | is_set = isl_map_is_set(map); |
4736 | 104 | if (is_set < 0) |
4737 | 0 | goto error; |
4738 | 104 | |
4739 | 104 | offset = isl_basic_map_offset(hull, isl_dim_out); |
4740 | 104 | ctx = isl_map_get_ctx(map); |
4741 | 104 | space = isl_space_domain(isl_map_get_space(map)); |
4742 | 104 | n_in = isl_space_dim(space, isl_dim_set); |
4743 | 104 | n = isl_space_dim(space, isl_dim_all); |
4744 | 104 | |
4745 | 104 | v = isl_vec_alloc(ctx, 1 + 1 + n); |
4746 | 104 | if (v) { |
4747 | 104 | isl_int_neg(v->el[0], hull->ineq[i][offset + d]); |
4748 | 104 | isl_seq_cpy(v->el + 1, hull->ineq[i], 1 + n); |
4749 | 104 | } |
4750 | 104 | isl_basic_map_free(hull); |
4751 | 104 | |
4752 | 104 | ls = isl_local_space_from_space(isl_space_copy(space)); |
4753 | 104 | aff = isl_aff_alloc_vec(ls, v); |
4754 | 104 | aff = isl_aff_floor(aff); |
4755 | 104 | if (is_set) { |
4756 | 1 | isl_space_free(space); |
4757 | 1 | ma = isl_multi_aff_from_aff(aff); |
4758 | 103 | } else { |
4759 | 103 | ma = isl_multi_aff_identity(isl_space_map_from_set(space)); |
4760 | 103 | ma = isl_multi_aff_range_product(ma, |
4761 | 103 | isl_multi_aff_from_aff(aff)); |
4762 | 103 | } |
4763 | 104 | |
4764 | 104 | insert = isl_map_from_multi_aff_internal(isl_multi_aff_copy(ma)); |
4765 | 104 | map = isl_map_apply_domain(map, insert); |
4766 | 104 | map = isl_map_equate(map, isl_dim_in, n_in, isl_dim_out, d); |
4767 | 104 | pma = isl_pw_multi_aff_from_map(map); |
4768 | 104 | pma = isl_pw_multi_aff_pullback_multi_aff(pma, ma); |
4769 | 104 | |
4770 | 104 | return pma; |
4771 | 0 | error: |
4772 | 0 | isl_map_free(map); |
4773 | 0 | isl_basic_map_free(hull); |
4774 | 0 | return NULL; |
4775 | 104 | } |
4776 | | |
4777 | | /* Is constraint "c" of the form |
4778 | | * |
4779 | | * e(...) + c1 - m x >= 0 |
4780 | | * |
4781 | | * or |
4782 | | * |
4783 | | * -e(...) + c2 + m x >= 0 |
4784 | | * |
4785 | | * where m > 1 and e only depends on parameters and input dimemnsions? |
4786 | | * |
4787 | | * "offset" is the offset of the output dimensions |
4788 | | * "pos" is the position of output dimension x. |
4789 | | */ |
4790 | | static int is_potential_div_constraint(isl_int *c, int offset, int d, int total) |
4791 | 1.27k | { |
4792 | 1.27k | if (isl_int_is_zero(c[offset + d])) |
4793 | 1.27k | return 01.05k ; |
4794 | 226 | if (isl_int_is_one(c[offset + d])) |
4795 | 226 | return 018 ; |
4796 | 208 | if (isl_int_is_negone(c[offset + d])) |
4797 | 208 | return 010 ; |
4798 | 198 | if (isl_seq_first_non_zero(c + offset, d) != -1) |
4799 | 0 | return 0; |
4800 | 198 | if (isl_seq_first_non_zero(c + offset + d + 1, |
4801 | 198 | total - (offset + d + 1)) != -1) |
4802 | 94 | return 0; |
4803 | 104 | return 1; |
4804 | 104 | } |
4805 | | |
4806 | | /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map. |
4807 | | * |
4808 | | * As a special case, we first check if there is any pair of constraints, |
4809 | | * shared by all the basic maps in "map" that force a given dimension |
4810 | | * to be equal to the floor of some affine combination of the input dimensions. |
4811 | | * |
4812 | | * In particular, if we can find two constraints |
4813 | | * |
4814 | | * e(...) + c1 - m x >= 0 i.e., m x <= e(...) + c1 |
4815 | | * |
4816 | | * and |
4817 | | * |
4818 | | * -e(...) + c2 + m x >= 0 i.e., m x >= e(...) - c2 |
4819 | | * |
4820 | | * where m > 1 and e only depends on parameters and input dimemnsions, |
4821 | | * and such that |
4822 | | * |
4823 | | * c1 + c2 < m i.e., -c2 >= c1 - (m - 1) |
4824 | | * |
4825 | | * then we know that we can take |
4826 | | * |
4827 | | * x = floor((e(...) + c1) / m) |
4828 | | * |
4829 | | * without having to perform any computation. |
4830 | | * |
4831 | | * Note that we know that |
4832 | | * |
4833 | | * c1 + c2 >= 1 |
4834 | | * |
4835 | | * If c1 + c2 were 0, then we would have detected an equality during |
4836 | | * simplification. If c1 + c2 were negative, then we would have detected |
4837 | | * a contradiction. |
4838 | | */ |
4839 | | static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_check_div( |
4840 | | __isl_take isl_map *map) |
4841 | 135 | { |
4842 | 135 | int d, dim; |
4843 | 135 | int i, j, n; |
4844 | 135 | int offset, total; |
4845 | 135 | isl_int sum; |
4846 | 135 | isl_basic_map *hull; |
4847 | 135 | |
4848 | 135 | hull = isl_map_unshifted_simple_hull(isl_map_copy(map)); |
4849 | 135 | if (!hull) |
4850 | 0 | goto error; |
4851 | 135 | |
4852 | 135 | isl_int_init(sum); |
4853 | 135 | dim = isl_map_dim(map, isl_dim_out); |
4854 | 135 | offset = isl_basic_map_offset(hull, isl_dim_out); |
4855 | 135 | total = 1 + isl_basic_map_total_dim(hull); |
4856 | 135 | n = hull->n_ineq; |
4857 | 282 | for (d = 0; d < dim; ++d147 ) { |
4858 | 1.42k | for (i = 0; i < n; ++i1.17k ) { |
4859 | 1.27k | if (!is_potential_div_constraint(hull->ineq[i], |
4860 | 1.27k | offset, d, total)) |
4861 | 1.17k | continue; |
4862 | 122 | for (j = i + 1; 104 j < n; ++j18 ) { |
4863 | 122 | if (!isl_seq_is_neg(hull->ineq[i] + 1, |
4864 | 122 | hull->ineq[j] + 1, total - 1)) |
4865 | 18 | continue; |
4866 | 104 | isl_int_add(sum, hull->ineq[i][0], |
4867 | 104 | hull->ineq[j][0]); |
4868 | 104 | if (isl_int_abs_lt(sum, |
4869 | 104 | hull->ineq[i][offset + d])) |
4870 | 104 | break; |
4871 | 104 | |
4872 | 104 | } |
4873 | 104 | if (j >= n) |
4874 | 0 | continue; |
4875 | 104 | isl_int_clear(sum); |
4876 | 104 | if (isl_int_is_pos(hull->ineq[j][offset + d])) |
4877 | 104 | j = i73 ; |
4878 | 104 | return pw_multi_aff_from_map_div(map, hull, d, j); |
4879 | 104 | } |
4880 | 251 | } |
4881 | 135 | isl_int_clear31 (sum); |
4882 | 31 | isl_basic_map_free(hull); |
4883 | 31 | return pw_multi_aff_from_map_base(map); |
4884 | 0 | error: |
4885 | 0 | isl_map_free(map); |
4886 | 0 | isl_basic_map_free(hull); |
4887 | 0 | return NULL; |
4888 | 135 | } |
4889 | | |
4890 | | /* Given an affine expression |
4891 | | * |
4892 | | * [A -> B] -> f(A,B) |
4893 | | * |
4894 | | * construct an isl_multi_aff |
4895 | | * |
4896 | | * [A -> B] -> B' |
4897 | | * |
4898 | | * such that dimension "d" in B' is set to "aff" and the remaining |
4899 | | * dimensions are set equal to the corresponding dimensions in B. |
4900 | | * "n_in" is the dimension of the space A. |
4901 | | * "n_out" is the dimension of the space B. |
4902 | | * |
4903 | | * If "is_set" is set, then the affine expression is of the form |
4904 | | * |
4905 | | * [B] -> f(B) |
4906 | | * |
4907 | | * and we construct an isl_multi_aff |
4908 | | * |
4909 | | * B -> B' |
4910 | | */ |
4911 | | static __isl_give isl_multi_aff *range_map(__isl_take isl_aff *aff, int d, |
4912 | | unsigned n_in, unsigned n_out, int is_set) |
4913 | 18 | { |
4914 | 18 | int i; |
4915 | 18 | isl_multi_aff *ma; |
4916 | 18 | isl_space *space, *space2; |
4917 | 18 | isl_local_space *ls; |
4918 | 18 | |
4919 | 18 | space = isl_aff_get_domain_space(aff); |
4920 | 18 | ls = isl_local_space_from_space(isl_space_copy(space)); |
4921 | 18 | space2 = isl_space_copy(space); |
4922 | 18 | if (!is_set) |
4923 | 18 | space2 = isl_space_range(isl_space_unwrap(space2)); |
4924 | 18 | space = isl_space_map_from_domain_and_range(space, space2); |
4925 | 18 | ma = isl_multi_aff_alloc(space); |
4926 | 18 | ma = isl_multi_aff_set_aff(ma, d, aff); |
4927 | 18 | |
4928 | 78 | for (i = 0; i < n_out; ++i60 ) { |
4929 | 60 | if (i == d) |
4930 | 18 | continue; |
4931 | 42 | aff = isl_aff_var_on_domain(isl_local_space_copy(ls), |
4932 | 42 | isl_dim_set, n_in + i); |
4933 | 42 | ma = isl_multi_aff_set_aff(ma, i, aff); |
4934 | 42 | } |
4935 | 18 | |
4936 | 18 | isl_local_space_free(ls); |
4937 | 18 | |
4938 | 18 | return ma; |
4939 | 18 | } |
4940 | | |
4941 | | /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map, |
4942 | | * taking into account that the dimension at position "d" can be written as |
4943 | | * |
4944 | | * x = m a + f(..) (1) |
4945 | | * |
4946 | | * where m is equal to "gcd". |
4947 | | * "i" is the index of the equality in "hull" that defines f(..). |
4948 | | * In particular, the equality is of the form |
4949 | | * |
4950 | | * f(..) - x + m g(existentials) = 0 |
4951 | | * |
4952 | | * or |
4953 | | * |
4954 | | * -f(..) + x + m g(existentials) = 0 |
4955 | | * |
4956 | | * We basically plug (1) into "map", resulting in a map with "a" |
4957 | | * in the range instead of "x". The corresponding isl_pw_multi_aff |
4958 | | * defining "a" is then plugged back into (1) to obtain a definition for "x". |
4959 | | * |
4960 | | * Specifically, given the input map |
4961 | | * |
4962 | | * A -> B |
4963 | | * |
4964 | | * We first wrap it into a set |
4965 | | * |
4966 | | * [A -> B] |
4967 | | * |
4968 | | * and define (1) on top of the corresponding space, resulting in "aff". |
4969 | | * We use this to create an isl_multi_aff that maps the output position "d" |
4970 | | * from "a" to "x", leaving all other (intput and output) dimensions unchanged. |
4971 | | * We plug this into the wrapped map, unwrap the result and compute the |
4972 | | * corresponding isl_pw_multi_aff. |
4973 | | * The result is an expression |
4974 | | * |
4975 | | * A -> T(A) |
4976 | | * |
4977 | | * We adjust that to |
4978 | | * |
4979 | | * A -> [A -> T(A)] |
4980 | | * |
4981 | | * so that we can plug that into "aff", after extending the latter to |
4982 | | * a mapping |
4983 | | * |
4984 | | * [A -> B] -> B' |
4985 | | * |
4986 | | * |
4987 | | * If "map" is actually a set, then there is no "A" space, meaning |
4988 | | * that we do not need to perform any wrapping, and that the result |
4989 | | * of the recursive call is of the form |
4990 | | * |
4991 | | * [T] |
4992 | | * |
4993 | | * which is plugged into a mapping of the form |
4994 | | * |
4995 | | * B -> B' |
4996 | | */ |
4997 | | static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_stride( |
4998 | | __isl_take isl_map *map, __isl_take isl_basic_map *hull, int d, int i, |
4999 | | isl_int gcd) |
5000 | 18 | { |
5001 | 18 | isl_set *set; |
5002 | 18 | isl_space *space; |
5003 | 18 | isl_local_space *ls; |
5004 | 18 | isl_aff *aff; |
5005 | 18 | isl_multi_aff *ma; |
5006 | 18 | isl_pw_multi_aff *pma, *id; |
5007 | 18 | unsigned n_in; |
5008 | 18 | unsigned o_out; |
5009 | 18 | unsigned n_out; |
5010 | 18 | isl_bool is_set; |
5011 | 18 | |
5012 | 18 | is_set = isl_map_is_set(map); |
5013 | 18 | if (is_set < 0) |
5014 | 0 | goto error; |
5015 | 18 | |
5016 | 18 | n_in = isl_basic_map_dim(hull, isl_dim_in); |
5017 | 18 | n_out = isl_basic_map_dim(hull, isl_dim_out); |
5018 | 18 | o_out = isl_basic_map_offset(hull, isl_dim_out); |
5019 | 18 | |
5020 | 18 | if (is_set) |
5021 | 0 | set = map; |
5022 | 18 | else |
5023 | 18 | set = isl_map_wrap(map); |
5024 | 18 | space = isl_space_map_from_set(isl_set_get_space(set)); |
5025 | 18 | ma = isl_multi_aff_identity(space); |
5026 | 18 | ls = isl_local_space_from_space(isl_set_get_space(set)); |
5027 | 18 | aff = isl_aff_alloc(ls); |
5028 | 18 | if (aff) { |
5029 | 18 | isl_int_set_si(aff->v->el[0], 1); |
5030 | 18 | if (isl_int_is_one(hull->eq[i][o_out + d])) |
5031 | 18 | isl_seq_neg(aff->v->el + 1, hull->eq[i], |
5032 | 0 | aff->v->size - 1); |
5033 | 18 | else |
5034 | 18 | isl_seq_cpy(aff->v->el + 1, hull->eq[i], |
5035 | 18 | aff->v->size - 1); |
5036 | 18 | isl_int_set(aff->v->el[1 + o_out + d], gcd); |
5037 | 18 | } |
5038 | 18 | ma = isl_multi_aff_set_aff(ma, n_in + d, isl_aff_copy(aff)); |
5039 | 18 | set = isl_set_preimage_multi_aff(set, ma); |
5040 | 18 | |
5041 | 18 | ma = range_map(aff, d, n_in, n_out, is_set); |
5042 | 18 | |
5043 | 18 | if (is_set) |
5044 | 0 | map = set; |
5045 | 18 | else |
5046 | 18 | map = isl_set_unwrap(set); |
5047 | 18 | pma = isl_pw_multi_aff_from_map(map); |
5048 | 18 | |
5049 | 18 | if (!is_set) { |
5050 | 18 | space = isl_pw_multi_aff_get_domain_space(pma); |
5051 | 18 | space = isl_space_map_from_set(space); |
5052 | 18 | id = isl_pw_multi_aff_identity(space); |
5053 | 18 | pma = isl_pw_multi_aff_range_product(id, pma); |
5054 | 18 | } |
5055 | 18 | id = isl_pw_multi_aff_from_multi_aff(ma); |
5056 | 18 | pma = isl_pw_multi_aff_pullback_pw_multi_aff(id, pma); |
5057 | 18 | |
5058 | 18 | isl_basic_map_free(hull); |
5059 | 18 | return pma; |
5060 | 0 | error: |
5061 | 0 | isl_map_free(map); |
5062 | 0 | isl_basic_map_free(hull); |
5063 | 0 | return NULL; |
5064 | 18 | } |
5065 | | |
5066 | | /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map. |
5067 | | * "hull" contains the equalities valid for "map". |
5068 | | * |
5069 | | * Check if any of the output dimensions is "strided". |
5070 | | * That is, we check if it can be written as |
5071 | | * |
5072 | | * x = m a + f(..) |
5073 | | * |
5074 | | * with m greater than 1, a some combination of existentially quantified |
5075 | | * variables and f an expression in the parameters and input dimensions. |
5076 | | * If so, we remove the stride in pw_multi_aff_from_map_stride. |
5077 | | * |
5078 | | * Otherwise, we continue with pw_multi_aff_from_map_check_div for a further |
5079 | | * special case. |
5080 | | */ |
5081 | | static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_check_strides( |
5082 | | __isl_take isl_map *map, __isl_take isl_basic_map *hull) |
5083 | 153 | { |
5084 | 153 | int i, j; |
5085 | 153 | unsigned n_out; |
5086 | 153 | unsigned o_out; |
5087 | 153 | unsigned n_div; |
5088 | 153 | unsigned o_div; |
5089 | 153 | isl_int gcd; |
5090 | 153 | |
5091 | 153 | n_div = isl_basic_map_dim(hull, isl_dim_div); |
5092 | 153 | o_div = isl_basic_map_offset(hull, isl_dim_div); |
5093 | 153 | |
5094 | 153 | if (n_div == 0) { |
5095 | 102 | isl_basic_map_free(hull); |
5096 | 102 | return pw_multi_aff_from_map_check_div(map); |
5097 | 102 | } |
5098 | 51 | |
5099 | 51 | isl_int_init(gcd); |
5100 | 51 | |
5101 | 51 | n_out = isl_basic_map_dim(hull, isl_dim_out); |
5102 | 51 | o_out = isl_basic_map_offset(hull, isl_dim_out); |
5103 | 51 | |
5104 | 183 | for (i = 0; i < n_out; ++i132 ) { |
5105 | 351 | for (j = 0; j < hull->n_eq; ++j201 ) { |
5106 | 219 | isl_int *eq = hull->eq[j]; |
5107 | 219 | isl_pw_multi_aff *res; |
5108 | 219 | |
5109 | 219 | if (!isl_int_is_one(eq[o_out + i]) && |
5110 | 219 | !186 isl_int_is_negone186 (eq[o_out + i])) |
5111 | 219 | continue168 ; |
5112 | 51 | if (isl_seq_first_non_zero(eq + o_out, i) != -1) |
5113 | 0 | continue; |
5114 | 51 | if (isl_seq_first_non_zero(eq + o_out + i + 1, |
5115 | 51 | n_out - (i + 1)) != -1) |
5116 | 0 | continue; |
5117 | 51 | isl_seq_gcd(eq + o_div, n_div, &gcd); |
5118 | 51 | if (isl_int_is_zero(gcd)) |
5119 | 51 | continue33 ; |
5120 | 18 | if (isl_int_is_one(gcd)) |
5121 | 18 | continue0 ; |
5122 | 18 | |
5123 | 18 | res = pw_multi_aff_from_map_stride(map, hull, |
5124 | 18 | i, j, gcd); |
5125 | 18 | isl_int_clear(gcd); |
5126 | 18 | return res; |
5127 | 18 | } |
5128 | 150 | } |
5129 | 51 | |
5130 | 51 | isl_int_clear33 (gcd); |
5131 | 33 | isl_basic_map_free(hull); |
5132 | 33 | return pw_multi_aff_from_map_check_div(map); |
5133 | 51 | } |
5134 | | |
5135 | | /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map. |
5136 | | * |
5137 | | * As a special case, we first check if all output dimensions are uniquely |
5138 | | * defined in terms of the parameters and input dimensions over the entire |
5139 | | * domain. If so, we extract the desired isl_pw_multi_aff directly |
5140 | | * from the affine hull of "map" and its domain. |
5141 | | * |
5142 | | * Otherwise, continue with pw_multi_aff_from_map_check_strides for more |
5143 | | * special cases. |
5144 | | */ |
5145 | | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_map(__isl_take isl_map *map) |
5146 | 7.00k | { |
5147 | 7.00k | isl_bool sv; |
5148 | 7.00k | isl_basic_map *hull; |
5149 | 7.00k | |
5150 | 7.00k | if (!map) |
5151 | 0 | return NULL; |
5152 | 7.00k | |
5153 | 7.00k | if (isl_map_n_basic_map(map) == 1) { |
5154 | 6.79k | hull = isl_map_unshifted_simple_hull(isl_map_copy(map)); |
5155 | 6.79k | hull = isl_basic_map_plain_affine_hull(hull); |
5156 | 6.79k | sv = isl_basic_map_plain_is_single_valued(hull); |
5157 | 6.79k | if (sv >= 0 && sv) |
5158 | 6.51k | return plain_pw_multi_aff_from_map(isl_map_domain(map), |
5159 | 6.51k | hull); |
5160 | 281 | isl_basic_map_free(hull); |
5161 | 281 | } |
5162 | 7.00k | map = isl_map_detect_equalities(map); |
5163 | 492 | hull = isl_map_unshifted_simple_hull(isl_map_copy(map)); |
5164 | 492 | sv = isl_basic_map_plain_is_single_valued(hull); |
5165 | 492 | if (sv >= 0 && sv) |
5166 | 339 | return plain_pw_multi_aff_from_map(isl_map_domain(map), hull); |
5167 | 153 | if (sv >= 0) |
5168 | 153 | return pw_multi_aff_from_map_check_strides(map, hull); |
5169 | 0 | isl_basic_map_free(hull); |
5170 | 0 | isl_map_free(map); |
5171 | 0 | return NULL; |
5172 | 0 | } |
5173 | | |
5174 | | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(__isl_take isl_set *set) |
5175 | 111 | { |
5176 | 111 | return isl_pw_multi_aff_from_map(set); |
5177 | 111 | } |
5178 | | |
5179 | | /* Convert "map" into an isl_pw_multi_aff (if possible) and |
5180 | | * add it to *user. |
5181 | | */ |
5182 | | static isl_stat pw_multi_aff_from_map(__isl_take isl_map *map, void *user) |
5183 | 982 | { |
5184 | 982 | isl_union_pw_multi_aff **upma = user; |
5185 | 982 | isl_pw_multi_aff *pma; |
5186 | 982 | |
5187 | 982 | pma = isl_pw_multi_aff_from_map(map); |
5188 | 982 | *upma = isl_union_pw_multi_aff_add_pw_multi_aff(*upma, pma); |
5189 | 982 | |
5190 | 982 | return *upma ? isl_stat_ok : isl_stat_error0 ; |
5191 | 982 | } |
5192 | | |
5193 | | /* Create an isl_union_pw_multi_aff with the given isl_aff on a universe |
5194 | | * domain. |
5195 | | */ |
5196 | | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_aff( |
5197 | | __isl_take isl_aff *aff) |
5198 | 0 | { |
5199 | 0 | isl_multi_aff *ma; |
5200 | 0 | isl_pw_multi_aff *pma; |
5201 | 0 |
|
5202 | 0 | ma = isl_multi_aff_from_aff(aff); |
5203 | 0 | pma = isl_pw_multi_aff_from_multi_aff(ma); |
5204 | 0 | return isl_union_pw_multi_aff_from_pw_multi_aff(pma); |
5205 | 0 | } |
5206 | | |
5207 | | /* Try and create an isl_union_pw_multi_aff that is equivalent |
5208 | | * to the given isl_union_map. |
5209 | | * The isl_union_map is required to be single-valued in each space. |
5210 | | * Otherwise, an error is produced. |
5211 | | */ |
5212 | | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_map( |
5213 | | __isl_take isl_union_map *umap) |
5214 | 489 | { |
5215 | 489 | isl_space *space; |
5216 | 489 | isl_union_pw_multi_aff *upma; |
5217 | 489 | |
5218 | 489 | space = isl_union_map_get_space(umap); |
5219 | 489 | upma = isl_union_pw_multi_aff_empty(space); |
5220 | 489 | if (isl_union_map_foreach_map(umap, &pw_multi_aff_from_map, &upma) < 0) |
5221 | 0 | upma = isl_union_pw_multi_aff_free(upma); |
5222 | 489 | isl_union_map_free(umap); |
5223 | 489 | |
5224 | 489 | return upma; |
5225 | 489 | } |
5226 | | |
5227 | | /* Try and create an isl_union_pw_multi_aff that is equivalent |
5228 | | * to the given isl_union_set. |
5229 | | * The isl_union_set is required to be a singleton in each space. |
5230 | | * Otherwise, an error is produced. |
5231 | | */ |
5232 | | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_set( |
5233 | | __isl_take isl_union_set *uset) |
5234 | 1 | { |
5235 | 1 | return isl_union_pw_multi_aff_from_union_map(uset); |
5236 | 1 | } |
5237 | | |
5238 | | /* Return the piecewise affine expression "set ? 1 : 0". |
5239 | | */ |
5240 | | __isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set) |
5241 | 111 | { |
5242 | 111 | isl_pw_aff *pa; |
5243 | 111 | isl_space *space = isl_set_get_space(set); |
5244 | 111 | isl_local_space *ls = isl_local_space_from_space(space); |
5245 | 111 | isl_aff *zero = isl_aff_zero_on_domain(isl_local_space_copy(ls)); |
5246 | 111 | isl_aff *one = isl_aff_zero_on_domain(ls); |
5247 | 111 | |
5248 | 111 | one = isl_aff_add_constant_si(one, 1); |
5249 | 111 | pa = isl_pw_aff_alloc(isl_set_copy(set), one); |
5250 | 111 | set = isl_set_complement(set); |
5251 | 111 | pa = isl_pw_aff_add_disjoint(pa, isl_pw_aff_alloc(set, zero)); |
5252 | 111 | |
5253 | 111 | return pa; |
5254 | 111 | } |
5255 | | |
5256 | | /* Plug in "subs" for dimension "type", "pos" of "aff". |
5257 | | * |
5258 | | * Let i be the dimension to replace and let "subs" be of the form |
5259 | | * |
5260 | | * f/d |
5261 | | * |
5262 | | * and "aff" of the form |
5263 | | * |
5264 | | * (a i + g)/m |
5265 | | * |
5266 | | * The result is |
5267 | | * |
5268 | | * (a f + d g')/(m d) |
5269 | | * |
5270 | | * where g' is the result of plugging in "subs" in each of the integer |
5271 | | * divisions in g. |
5272 | | */ |
5273 | | __isl_give isl_aff *isl_aff_substitute(__isl_take isl_aff *aff, |
5274 | | enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs) |
5275 | 1.20k | { |
5276 | 1.20k | isl_ctx *ctx; |
5277 | 1.20k | isl_int v; |
5278 | 1.20k | |
5279 | 1.20k | aff = isl_aff_cow(aff); |
5280 | 1.20k | if (!aff || !subs) |
5281 | 0 | return isl_aff_free(aff); |
5282 | 1.20k | |
5283 | 1.20k | ctx = isl_aff_get_ctx(aff); |
5284 | 1.20k | if (!isl_space_is_equal(aff->ls->dim, subs->ls->dim)) |
5285 | 1.20k | isl_die0 (ctx, isl_error_invalid, |
5286 | 1.20k | "spaces don't match", return isl_aff_free(aff)); |
5287 | 1.20k | if (isl_local_space_dim(subs->ls, isl_dim_div) != 0) |
5288 | 1.20k | isl_die0 (ctx, isl_error_unsupported, |
5289 | 1.20k | "cannot handle divs yet", return isl_aff_free(aff)); |
5290 | 1.20k | |
5291 | 1.20k | aff->ls = isl_local_space_substitute(aff->ls, type, pos, subs); |
5292 | 1.20k | if (!aff->ls) |
5293 | 0 | return isl_aff_free(aff); |
5294 | 1.20k | |
5295 | 1.20k | aff->v = isl_vec_cow(aff->v); |
5296 | 1.20k | if (!aff->v) |
5297 | 0 | return isl_aff_free(aff); |
5298 | 1.20k | |
5299 | 1.20k | pos += isl_local_space_offset(aff->ls, type); |
5300 | 1.20k | |
5301 | 1.20k | isl_int_init(v); |
5302 | 1.20k | isl_seq_substitute(aff->v->el, pos, subs->v->el, |
5303 | 1.20k | aff->v->size, subs->v->size, v); |
5304 | 1.20k | isl_int_clear(v); |
5305 | 1.20k | |
5306 | 1.20k | return aff; |
5307 | 1.20k | } |
5308 | | |
5309 | | /* Plug in "subs" for dimension "type", "pos" in each of the affine |
5310 | | * expressions in "maff". |
5311 | | */ |
5312 | | __isl_give isl_multi_aff *isl_multi_aff_substitute( |
5313 | | __isl_take isl_multi_aff *maff, enum isl_dim_type type, unsigned pos, |
5314 | | __isl_keep isl_aff *subs) |
5315 | 360 | { |
5316 | 360 | int i; |
5317 | 360 | |
5318 | 360 | maff = isl_multi_aff_cow(maff); |
5319 | 360 | if (!maff || !subs) |
5320 | 0 | return isl_multi_aff_free(maff); |
5321 | 360 | |
5322 | 360 | if (type == isl_dim_in) |
5323 | 360 | type = isl_dim_set; |
5324 | 360 | |
5325 | 1.56k | for (i = 0; i < maff->n; ++i1.20k ) { |
5326 | 1.20k | maff->u.p[i] = isl_aff_substitute(maff->u.p[i], |
5327 | 1.20k | type, pos, subs); |
5328 | 1.20k | if (!maff->u.p[i]) |
5329 | 0 | return isl_multi_aff_free(maff); |
5330 | 1.20k | } |
5331 | 360 | |
5332 | 360 | return maff; |
5333 | 360 | } |
5334 | | |
5335 | | /* Plug in "subs" for dimension "type", "pos" of "pma". |
5336 | | * |
5337 | | * pma is of the form |
5338 | | * |
5339 | | * A_i(v) -> M_i(v) |
5340 | | * |
5341 | | * while subs is of the form |
5342 | | * |
5343 | | * v' = B_j(v) -> S_j |
5344 | | * |
5345 | | * Each pair i,j such that C_ij = A_i \cap B_i is non-empty |
5346 | | * has a contribution in the result, in particular |
5347 | | * |
5348 | | * C_ij(S_j) -> M_i(S_j) |
5349 | | * |
5350 | | * Note that plugging in S_j in C_ij may also result in an empty set |
5351 | | * and this contribution should simply be discarded. |
5352 | | */ |
5353 | | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_substitute( |
5354 | | __isl_take isl_pw_multi_aff *pma, enum isl_dim_type type, unsigned pos, |
5355 | | __isl_keep isl_pw_aff *subs) |
5356 | 180 | { |
5357 | 180 | int i, j, n; |
5358 | 180 | isl_pw_multi_aff *res; |
5359 | 180 | |
5360 | 180 | if (!pma || !subs) |
5361 | 0 | return isl_pw_multi_aff_free(pma); |
5362 | 180 | |
5363 | 180 | n = pma->n * subs->n; |
5364 | 180 | res = isl_pw_multi_aff_alloc_size(isl_space_copy(pma->dim), n); |
5365 | 180 | |
5366 | 360 | for (i = 0; i < pma->n; ++i180 ) { |
5367 | 540 | for (j = 0; j < subs->n; ++j360 ) { |
5368 | 360 | isl_set *common; |
5369 | 360 | isl_multi_aff *res_ij; |
5370 | 360 | int empty; |
5371 | 360 | |
5372 | 360 | common = isl_set_intersect( |
5373 | 360 | isl_set_copy(pma->p[i].set), |
5374 | 360 | isl_set_copy(subs->p[j].set)); |
5375 | 360 | common = isl_set_substitute(common, |
5376 | 360 | type, pos, subs->p[j].aff); |
5377 | 360 | empty = isl_set_plain_is_empty(common); |
5378 | 360 | if (empty < 0 || empty) { |
5379 | 0 | isl_set_free(common); |
5380 | 0 | if (empty < 0) |
5381 | 0 | goto error; |
5382 | 0 | continue; |
5383 | 0 | } |
5384 | 360 | |
5385 | 360 | res_ij = isl_multi_aff_substitute( |
5386 | 360 | isl_multi_aff_copy(pma->p[i].maff), |
5387 | 360 | type, pos, subs->p[j].aff); |
5388 | 360 | |
5389 | 360 | res = isl_pw_multi_aff_add_piece(res, common, res_ij); |
5390 | 360 | } |
5391 | 180 | } |
5392 | 180 | |
5393 | 180 | isl_pw_multi_aff_free(pma); |
5394 | 180 | return res; |
5395 | |