1 | /* |
2 | * Copyright 2011 INRIA Saclay |
3 | * Copyright 2011 Sven Verdoolaege |
4 | * Copyright 2012-2014 Ecole Normale Superieure |
5 | * Copyright 2014 INRIA Rocquencourt |
6 | * Copyright 2016 Sven Verdoolaege |
7 | * Copyright 2018,2020 Cerebras Systems |
8 | * Copyright 2021 Sven Verdoolaege |
9 | * Copyright 2022 Cerebras Systems |
10 | * |
11 | * Use of this software is governed by the MIT license |
12 | * |
13 | * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, |
14 | * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, |
15 | * 91893 Orsay, France |
16 | * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France |
17 | * and Inria Paris - Rocquencourt, Domaine de Voluceau - Rocquencourt, |
18 | * B.P. 105 - 78153 Le Chesnay, France |
19 | * and Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA |
20 | * and Cerebras Systems, 1237 E Arques Ave, Sunnyvale, CA, USA |
21 | */ |
22 | |
23 | #include <isl_ctx_private.h> |
24 | #include <isl_map_private.h> |
25 | #include <isl_union_map_private.h> |
26 | #include <isl_aff_private.h> |
27 | #include <isl_space_private.h> |
28 | #include <isl_local_space_private.h> |
29 | #include <isl_vec_private.h> |
30 | #include <isl_mat_private.h> |
31 | #include <isl_id_private.h> |
32 | #include <isl/constraint.h> |
33 | #include <isl_seq.h> |
34 | #include <isl/set.h> |
35 | #include <isl_val_private.h> |
36 | #include <isl_point_private.h> |
37 | #include <isl_config.h> |
38 | |
39 | #undef EL_BASE |
40 | #define EL_BASE aff |
41 | |
42 | #include <isl_list_templ.c> |
43 | #include <isl_list_read_templ.c> |
44 | |
45 | #undef EL_BASE |
46 | #define EL_BASE pw_aff |
47 | |
48 | #include <isl_list_templ.c> |
49 | #include <isl_list_read_templ.c> |
50 | |
51 | #undef EL_BASE |
52 | #define EL_BASE pw_multi_aff |
53 | |
54 | #include <isl_list_templ.c> |
55 | #include <isl_list_read_templ.c> |
56 | |
57 | #undef EL_BASE |
58 | #define EL_BASE union_pw_aff |
59 | |
60 | #include <isl_list_templ.c> |
61 | #include <isl_list_read_templ.c> |
62 | |
63 | #undef EL_BASE |
64 | #define EL_BASE union_pw_multi_aff |
65 | |
66 | #include <isl_list_templ.c> |
67 | |
68 | /* Construct an isl_aff from the given domain local space "ls" and |
69 | * coefficients "v", where the local space is known to be valid |
70 | * for an affine expression. |
71 | */ |
72 | static __isl_give isl_aff *isl_aff_alloc_vec_validated( |
73 | __isl_take isl_local_space *ls, __isl_take isl_vec *v) |
74 | { |
75 | isl_aff *aff; |
76 | |
77 | if (!ls || !v) |
78 | goto error; |
79 | |
80 | aff = isl_calloc_type(v->ctx, struct isl_aff); |
81 | if (!aff) |
82 | goto error; |
83 | |
84 | aff->ref = 1; |
85 | aff->ls = ls; |
86 | aff->v = v; |
87 | |
88 | return aff; |
89 | error: |
90 | isl_local_space_free(ls); |
91 | isl_vec_free(vec: v); |
92 | return NULL; |
93 | } |
94 | |
95 | /* Construct an isl_aff from the given domain local space "ls" and |
96 | * coefficients "v". |
97 | * |
98 | * First check that "ls" is a valid domain local space |
99 | * for an affine expression. |
100 | */ |
101 | __isl_give isl_aff *isl_aff_alloc_vec(__isl_take isl_local_space *ls, |
102 | __isl_take isl_vec *v) |
103 | { |
104 | isl_ctx *ctx; |
105 | |
106 | if (!ls) |
107 | return NULL; |
108 | |
109 | ctx = isl_local_space_get_ctx(ls); |
110 | if (!isl_local_space_divs_known(ls)) |
111 | isl_die(ctx, isl_error_invalid, "local space has unknown divs" , |
112 | goto error); |
113 | if (!isl_local_space_is_set(ls)) |
114 | isl_die(ctx, isl_error_invalid, |
115 | "domain of affine expression should be a set" , |
116 | goto error); |
117 | return isl_aff_alloc_vec_validated(ls, v); |
118 | error: |
119 | isl_local_space_free(ls); |
120 | isl_vec_free(vec: v); |
121 | return NULL; |
122 | } |
123 | |
124 | __isl_give isl_aff *isl_aff_alloc(__isl_take isl_local_space *ls) |
125 | { |
126 | isl_ctx *ctx; |
127 | isl_vec *v; |
128 | isl_size total; |
129 | |
130 | if (!ls) |
131 | return NULL; |
132 | |
133 | ctx = isl_local_space_get_ctx(ls); |
134 | |
135 | total = isl_local_space_dim(ls, type: isl_dim_all); |
136 | if (total < 0) |
137 | goto error; |
138 | v = isl_vec_alloc(ctx, size: 1 + 1 + total); |
139 | return isl_aff_alloc_vec(ls, v); |
140 | error: |
141 | isl_local_space_free(ls); |
142 | return NULL; |
143 | } |
144 | |
145 | __isl_give isl_aff *isl_aff_copy(__isl_keep isl_aff *aff) |
146 | { |
147 | if (!aff) |
148 | return NULL; |
149 | |
150 | aff->ref++; |
151 | return aff; |
152 | } |
153 | |
154 | __isl_give isl_aff *isl_aff_dup(__isl_keep isl_aff *aff) |
155 | { |
156 | if (!aff) |
157 | return NULL; |
158 | |
159 | return isl_aff_alloc_vec_validated(ls: isl_local_space_copy(ls: aff->ls), |
160 | v: isl_vec_copy(vec: aff->v)); |
161 | } |
162 | |
163 | __isl_give isl_aff *isl_aff_cow(__isl_take isl_aff *aff) |
164 | { |
165 | if (!aff) |
166 | return NULL; |
167 | |
168 | if (aff->ref == 1) |
169 | return aff; |
170 | aff->ref--; |
171 | return isl_aff_dup(aff); |
172 | } |
173 | |
174 | __isl_give isl_aff *isl_aff_zero_on_domain(__isl_take isl_local_space *ls) |
175 | { |
176 | isl_aff *aff; |
177 | |
178 | aff = isl_aff_alloc(ls); |
179 | if (!aff) |
180 | return NULL; |
181 | |
182 | isl_int_set_si(aff->v->el[0], 1); |
183 | isl_seq_clr(p: aff->v->el + 1, len: aff->v->size - 1); |
184 | |
185 | return aff; |
186 | } |
187 | |
188 | /* Return an affine expression that is equal to zero on domain space "space". |
189 | */ |
190 | __isl_give isl_aff *isl_aff_zero_on_domain_space(__isl_take isl_space *space) |
191 | { |
192 | return isl_aff_zero_on_domain(ls: isl_local_space_from_space(space)); |
193 | } |
194 | |
195 | /* This function performs the same operation as isl_aff_zero_on_domain_space, |
196 | * but is considered as a function on an isl_space when exported. |
197 | */ |
198 | __isl_give isl_aff *isl_space_zero_aff_on_domain(__isl_take isl_space *space) |
199 | { |
200 | return isl_aff_zero_on_domain_space(space); |
201 | } |
202 | |
203 | /* Return a piecewise affine expression defined on the specified domain |
204 | * that is equal to zero. |
205 | */ |
206 | __isl_give isl_pw_aff *isl_pw_aff_zero_on_domain(__isl_take isl_local_space *ls) |
207 | { |
208 | return isl_pw_aff_from_aff(aff: isl_aff_zero_on_domain(ls)); |
209 | } |
210 | |
211 | /* Change "aff" into a NaN. |
212 | * |
213 | * Note that this function gets called from isl_aff_nan_on_domain, |
214 | * so "aff" may not have been initialized yet. |
215 | */ |
216 | static __isl_give isl_aff *isl_aff_set_nan(__isl_take isl_aff *aff) |
217 | { |
218 | aff = isl_aff_cow(aff); |
219 | if (!aff) |
220 | return NULL; |
221 | |
222 | aff->v = isl_vec_clr(vec: aff->v); |
223 | if (!aff->v) |
224 | return isl_aff_free(aff); |
225 | |
226 | return aff; |
227 | } |
228 | |
229 | /* Return an affine expression defined on the specified domain |
230 | * that represents NaN. |
231 | */ |
232 | __isl_give isl_aff *isl_aff_nan_on_domain(__isl_take isl_local_space *ls) |
233 | { |
234 | isl_aff *aff; |
235 | |
236 | aff = isl_aff_alloc(ls); |
237 | return isl_aff_set_nan(aff); |
238 | } |
239 | |
240 | /* Return an affine expression defined on the specified domain space |
241 | * that represents NaN. |
242 | */ |
243 | __isl_give isl_aff *isl_aff_nan_on_domain_space(__isl_take isl_space *space) |
244 | { |
245 | return isl_aff_nan_on_domain(ls: isl_local_space_from_space(space)); |
246 | } |
247 | |
248 | /* Return a piecewise affine expression defined on the specified domain space |
249 | * that represents NaN. |
250 | */ |
251 | __isl_give isl_pw_aff *isl_pw_aff_nan_on_domain_space( |
252 | __isl_take isl_space *space) |
253 | { |
254 | return isl_pw_aff_from_aff(aff: isl_aff_nan_on_domain_space(space)); |
255 | } |
256 | |
257 | /* Return a piecewise affine expression defined on the specified domain |
258 | * that represents NaN. |
259 | */ |
260 | __isl_give isl_pw_aff *isl_pw_aff_nan_on_domain(__isl_take isl_local_space *ls) |
261 | { |
262 | return isl_pw_aff_from_aff(aff: isl_aff_nan_on_domain(ls)); |
263 | } |
264 | |
265 | /* Return an affine expression that is equal to "val" on |
266 | * domain local space "ls". |
267 | * |
268 | * Note that the encoding for the special value NaN |
269 | * is the same in isl_val and isl_aff, so this does not need |
270 | * to be treated in any special way. |
271 | */ |
272 | __isl_give isl_aff *isl_aff_val_on_domain(__isl_take isl_local_space *ls, |
273 | __isl_take isl_val *val) |
274 | { |
275 | isl_aff *aff; |
276 | |
277 | if (!ls || !val) |
278 | goto error; |
279 | if (!isl_val_is_rat(v: val) && !isl_val_is_nan(v: val)) |
280 | isl_die(isl_val_get_ctx(val), isl_error_invalid, |
281 | "expecting rational value or NaN" , goto error); |
282 | |
283 | aff = isl_aff_alloc(ls: isl_local_space_copy(ls)); |
284 | if (!aff) |
285 | goto error; |
286 | |
287 | isl_seq_clr(p: aff->v->el + 2, len: aff->v->size - 2); |
288 | isl_int_set(aff->v->el[1], val->n); |
289 | isl_int_set(aff->v->el[0], val->d); |
290 | |
291 | isl_local_space_free(ls); |
292 | isl_val_free(v: val); |
293 | return aff; |
294 | error: |
295 | isl_local_space_free(ls); |
296 | isl_val_free(v: val); |
297 | return NULL; |
298 | } |
299 | |
300 | /* Return an affine expression that is equal to "val" on domain space "space". |
301 | */ |
302 | __isl_give isl_aff *isl_aff_val_on_domain_space(__isl_take isl_space *space, |
303 | __isl_take isl_val *val) |
304 | { |
305 | return isl_aff_val_on_domain(ls: isl_local_space_from_space(space), val); |
306 | } |
307 | |
308 | /* Return an affine expression that is equal to the specified dimension |
309 | * in "ls". |
310 | */ |
311 | __isl_give isl_aff *isl_aff_var_on_domain(__isl_take isl_local_space *ls, |
312 | enum isl_dim_type type, unsigned pos) |
313 | { |
314 | isl_space *space; |
315 | isl_aff *aff; |
316 | |
317 | if (!ls) |
318 | return NULL; |
319 | |
320 | space = isl_local_space_get_space(ls); |
321 | if (!space) |
322 | goto error; |
323 | if (isl_space_is_map(space)) |
324 | isl_die(isl_space_get_ctx(space), isl_error_invalid, |
325 | "expecting (parameter) set space" , goto error); |
326 | if (isl_local_space_check_range(ls, type, first: pos, n: 1) < 0) |
327 | goto error; |
328 | |
329 | isl_space_free(space); |
330 | aff = isl_aff_alloc(ls); |
331 | if (!aff) |
332 | return NULL; |
333 | |
334 | pos += isl_local_space_offset(ls: aff->ls, type); |
335 | |
336 | isl_int_set_si(aff->v->el[0], 1); |
337 | isl_seq_clr(p: aff->v->el + 1, len: aff->v->size - 1); |
338 | isl_int_set_si(aff->v->el[1 + pos], 1); |
339 | |
340 | return aff; |
341 | error: |
342 | isl_local_space_free(ls); |
343 | isl_space_free(space); |
344 | return NULL; |
345 | } |
346 | |
347 | /* Return a piecewise affine expression that is equal to |
348 | * the specified dimension in "ls". |
349 | */ |
350 | __isl_give isl_pw_aff *isl_pw_aff_var_on_domain(__isl_take isl_local_space *ls, |
351 | enum isl_dim_type type, unsigned pos) |
352 | { |
353 | return isl_pw_aff_from_aff(aff: isl_aff_var_on_domain(ls, type, pos)); |
354 | } |
355 | |
356 | /* Return an affine expression that is equal to the parameter |
357 | * in the domain space "space" with identifier "id". |
358 | */ |
359 | __isl_give isl_aff *isl_aff_param_on_domain_space_id( |
360 | __isl_take isl_space *space, __isl_take isl_id *id) |
361 | { |
362 | int pos; |
363 | isl_local_space *ls; |
364 | |
365 | if (!space || !id) |
366 | goto error; |
367 | pos = isl_space_find_dim_by_id(space, type: isl_dim_param, id); |
368 | if (pos < 0) |
369 | isl_die(isl_space_get_ctx(space), isl_error_invalid, |
370 | "parameter not found in space" , goto error); |
371 | isl_id_free(id); |
372 | ls = isl_local_space_from_space(space); |
373 | return isl_aff_var_on_domain(ls, type: isl_dim_param, pos); |
374 | error: |
375 | isl_space_free(space); |
376 | isl_id_free(id); |
377 | return NULL; |
378 | } |
379 | |
380 | /* This function performs the same operation as |
381 | * isl_aff_param_on_domain_space_id, |
382 | * but is considered as a function on an isl_space when exported. |
383 | */ |
384 | __isl_give isl_aff *isl_space_param_aff_on_domain_id( |
385 | __isl_take isl_space *space, __isl_take isl_id *id) |
386 | { |
387 | return isl_aff_param_on_domain_space_id(space, id); |
388 | } |
389 | |
390 | __isl_null isl_aff *isl_aff_free(__isl_take isl_aff *aff) |
391 | { |
392 | if (!aff) |
393 | return NULL; |
394 | |
395 | if (--aff->ref > 0) |
396 | return NULL; |
397 | |
398 | isl_local_space_free(ls: aff->ls); |
399 | isl_vec_free(vec: aff->v); |
400 | |
401 | free(ptr: aff); |
402 | |
403 | return NULL; |
404 | } |
405 | |
406 | isl_ctx *isl_aff_get_ctx(__isl_keep isl_aff *aff) |
407 | { |
408 | return aff ? isl_local_space_get_ctx(ls: aff->ls) : NULL; |
409 | } |
410 | |
411 | /* Return a hash value that digests "aff". |
412 | */ |
413 | uint32_t isl_aff_get_hash(__isl_keep isl_aff *aff) |
414 | { |
415 | uint32_t hash, ls_hash, v_hash; |
416 | |
417 | if (!aff) |
418 | return 0; |
419 | |
420 | hash = isl_hash_init(); |
421 | ls_hash = isl_local_space_get_hash(ls: aff->ls); |
422 | isl_hash_hash(hash, ls_hash); |
423 | v_hash = isl_vec_get_hash(vec: aff->v); |
424 | isl_hash_hash(hash, v_hash); |
425 | |
426 | return hash; |
427 | } |
428 | |
429 | /* Return the domain local space of "aff". |
430 | */ |
431 | static __isl_keep isl_local_space *isl_aff_peek_domain_local_space( |
432 | __isl_keep isl_aff *aff) |
433 | { |
434 | return aff ? aff->ls : NULL; |
435 | } |
436 | |
437 | /* Return the number of variables of the given type in the domain of "aff". |
438 | */ |
439 | isl_size isl_aff_domain_dim(__isl_keep isl_aff *aff, enum isl_dim_type type) |
440 | { |
441 | isl_local_space *ls; |
442 | |
443 | ls = isl_aff_peek_domain_local_space(aff); |
444 | return isl_local_space_dim(ls, type); |
445 | } |
446 | |
447 | /* Externally, an isl_aff has a map space, but internally, the |
448 | * ls field corresponds to the domain of that space. |
449 | */ |
450 | isl_size isl_aff_dim(__isl_keep isl_aff *aff, enum isl_dim_type type) |
451 | { |
452 | if (!aff) |
453 | return isl_size_error; |
454 | if (type == isl_dim_out) |
455 | return 1; |
456 | if (type == isl_dim_in) |
457 | type = isl_dim_set; |
458 | return isl_aff_domain_dim(aff, type); |
459 | } |
460 | |
461 | /* Return the offset of the first coefficient of type "type" in |
462 | * the domain of "aff". |
463 | */ |
464 | isl_size isl_aff_domain_offset(__isl_keep isl_aff *aff, enum isl_dim_type type) |
465 | { |
466 | isl_local_space *ls; |
467 | |
468 | ls = isl_aff_peek_domain_local_space(aff); |
469 | return isl_local_space_offset(ls, type); |
470 | } |
471 | |
472 | /* Return the position of the dimension of the given type and name |
473 | * in "aff". |
474 | * Return -1 if no such dimension can be found. |
475 | */ |
476 | int isl_aff_find_dim_by_name(__isl_keep isl_aff *aff, enum isl_dim_type type, |
477 | const char *name) |
478 | { |
479 | if (!aff) |
480 | return -1; |
481 | if (type == isl_dim_out) |
482 | return -1; |
483 | if (type == isl_dim_in) |
484 | type = isl_dim_set; |
485 | return isl_local_space_find_dim_by_name(ls: aff->ls, type, name); |
486 | } |
487 | |
488 | /* Return the domain space of "aff". |
489 | */ |
490 | static __isl_keep isl_space *isl_aff_peek_domain_space(__isl_keep isl_aff *aff) |
491 | { |
492 | return aff ? isl_local_space_peek_space(ls: aff->ls) : NULL; |
493 | } |
494 | |
495 | __isl_give isl_space *isl_aff_get_domain_space(__isl_keep isl_aff *aff) |
496 | { |
497 | return isl_space_copy(space: isl_aff_peek_domain_space(aff)); |
498 | } |
499 | |
500 | __isl_give isl_space *isl_aff_get_space(__isl_keep isl_aff *aff) |
501 | { |
502 | isl_space *space; |
503 | if (!aff) |
504 | return NULL; |
505 | space = isl_local_space_get_space(ls: aff->ls); |
506 | space = isl_space_from_domain(space); |
507 | space = isl_space_add_dims(space, type: isl_dim_out, n: 1); |
508 | return space; |
509 | } |
510 | |
511 | /* Return a copy of the domain space of "aff". |
512 | */ |
513 | __isl_give isl_local_space *isl_aff_get_domain_local_space( |
514 | __isl_keep isl_aff *aff) |
515 | { |
516 | return isl_local_space_copy(ls: isl_aff_peek_domain_local_space(aff)); |
517 | } |
518 | |
519 | __isl_give isl_local_space *isl_aff_get_local_space(__isl_keep isl_aff *aff) |
520 | { |
521 | isl_local_space *ls; |
522 | if (!aff) |
523 | return NULL; |
524 | ls = isl_local_space_copy(ls: aff->ls); |
525 | ls = isl_local_space_from_domain(ls); |
526 | ls = isl_local_space_add_dims(ls, type: isl_dim_out, n: 1); |
527 | return ls; |
528 | } |
529 | |
530 | /* Return the local space of the domain of "aff". |
531 | * This may be either a copy or the local space itself |
532 | * if there is only one reference to "aff". |
533 | * This allows the local space to be modified inplace |
534 | * if both the expression and its local space have only a single reference. |
535 | * The caller is not allowed to modify "aff" between this call and |
536 | * a subsequent call to isl_aff_restore_domain_local_space. |
537 | * The only exception is that isl_aff_free can be called instead. |
538 | */ |
539 | __isl_give isl_local_space *isl_aff_take_domain_local_space( |
540 | __isl_keep isl_aff *aff) |
541 | { |
542 | isl_local_space *ls; |
543 | |
544 | if (!aff) |
545 | return NULL; |
546 | if (aff->ref != 1) |
547 | return isl_aff_get_domain_local_space(aff); |
548 | ls = aff->ls; |
549 | aff->ls = NULL; |
550 | return ls; |
551 | } |
552 | |
553 | /* Set the local space of the domain of "aff" to "ls", |
554 | * where the local space of "aff" may be missing |
555 | * due to a preceding call to isl_aff_take_domain_local_space. |
556 | * However, in this case, "aff" only has a single reference and |
557 | * then the call to isl_aff_cow has no effect. |
558 | */ |
559 | __isl_give isl_aff *isl_aff_restore_domain_local_space( |
560 | __isl_keep isl_aff *aff, __isl_take isl_local_space *ls) |
561 | { |
562 | if (!aff || !ls) |
563 | goto error; |
564 | |
565 | if (aff->ls == ls) { |
566 | isl_local_space_free(ls); |
567 | return aff; |
568 | } |
569 | |
570 | aff = isl_aff_cow(aff); |
571 | if (!aff) |
572 | goto error; |
573 | isl_local_space_free(ls: aff->ls); |
574 | aff->ls = ls; |
575 | |
576 | return aff; |
577 | error: |
578 | isl_aff_free(aff); |
579 | isl_local_space_free(ls); |
580 | return NULL; |
581 | } |
582 | |
583 | /* Externally, an isl_aff has a map space, but internally, the |
584 | * ls field corresponds to the domain of that space. |
585 | */ |
586 | const char *isl_aff_get_dim_name(__isl_keep isl_aff *aff, |
587 | enum isl_dim_type type, unsigned pos) |
588 | { |
589 | if (!aff) |
590 | return NULL; |
591 | if (type == isl_dim_out) |
592 | return NULL; |
593 | if (type == isl_dim_in) |
594 | type = isl_dim_set; |
595 | return isl_local_space_get_dim_name(ls: aff->ls, type, pos); |
596 | } |
597 | |
598 | __isl_give isl_aff *isl_aff_reset_domain_space(__isl_take isl_aff *aff, |
599 | __isl_take isl_space *space) |
600 | { |
601 | aff = isl_aff_cow(aff); |
602 | if (!aff || !space) |
603 | goto error; |
604 | |
605 | aff->ls = isl_local_space_reset_space(ls: aff->ls, space); |
606 | if (!aff->ls) |
607 | return isl_aff_free(aff); |
608 | |
609 | return aff; |
610 | error: |
611 | isl_aff_free(aff); |
612 | isl_space_free(space); |
613 | return NULL; |
614 | } |
615 | |
616 | /* Reset the space of "aff". This function is called from isl_pw_templ.c |
617 | * and doesn't know if the space of an element object is represented |
618 | * directly or through its domain. It therefore passes along both. |
619 | */ |
620 | __isl_give isl_aff *isl_aff_reset_space_and_domain(__isl_take isl_aff *aff, |
621 | __isl_take isl_space *space, __isl_take isl_space *domain) |
622 | { |
623 | isl_space_free(space); |
624 | return isl_aff_reset_domain_space(aff, space: domain); |
625 | } |
626 | |
627 | /* Reorder the dimensions of the domain of "aff" according |
628 | * to the given reordering. |
629 | */ |
630 | __isl_give isl_aff *isl_aff_realign_domain(__isl_take isl_aff *aff, |
631 | __isl_take isl_reordering *r) |
632 | { |
633 | aff = isl_aff_cow(aff); |
634 | if (!aff) |
635 | goto error; |
636 | |
637 | r = isl_reordering_extend(exp: r, extra: aff->ls->div->n_row); |
638 | aff->v = isl_vec_reorder(vec: aff->v, offset: 2, r: isl_reordering_copy(exp: r)); |
639 | aff->ls = isl_local_space_realign(ls: aff->ls, r); |
640 | |
641 | if (!aff->v || !aff->ls) |
642 | return isl_aff_free(aff); |
643 | |
644 | return aff; |
645 | error: |
646 | isl_aff_free(aff); |
647 | isl_reordering_free(exp: r); |
648 | return NULL; |
649 | } |
650 | |
651 | __isl_give isl_aff *isl_aff_align_params(__isl_take isl_aff *aff, |
652 | __isl_take isl_space *model) |
653 | { |
654 | isl_space *domain_space; |
655 | isl_bool equal_params; |
656 | |
657 | domain_space = isl_aff_peek_domain_space(aff); |
658 | equal_params = isl_space_has_equal_params(space1: domain_space, space2: model); |
659 | if (equal_params < 0) |
660 | goto error; |
661 | if (!equal_params) { |
662 | isl_reordering *exp; |
663 | |
664 | exp = isl_parameter_alignment_reordering(alignee: domain_space, aligner: model); |
665 | aff = isl_aff_realign_domain(aff, r: exp); |
666 | } |
667 | |
668 | isl_space_free(space: model); |
669 | return aff; |
670 | error: |
671 | isl_space_free(space: model); |
672 | isl_aff_free(aff); |
673 | return NULL; |
674 | } |
675 | |
676 | #undef TYPE |
677 | #define TYPE isl_aff |
678 | #include "isl_unbind_params_templ.c" |
679 | |
680 | /* Is "aff" obviously equal to zero? |
681 | * |
682 | * If the denominator is zero, then "aff" is not equal to zero. |
683 | */ |
684 | isl_bool isl_aff_plain_is_zero(__isl_keep isl_aff *aff) |
685 | { |
686 | int pos; |
687 | |
688 | if (!aff) |
689 | return isl_bool_error; |
690 | |
691 | if (isl_int_is_zero(aff->v->el[0])) |
692 | return isl_bool_false; |
693 | pos = isl_seq_first_non_zero(p: aff->v->el + 1, len: aff->v->size - 1); |
694 | return isl_bool_ok(b: pos < 0); |
695 | } |
696 | |
697 | /* Does "aff" represent NaN? |
698 | */ |
699 | isl_bool isl_aff_is_nan(__isl_keep isl_aff *aff) |
700 | { |
701 | if (!aff) |
702 | return isl_bool_error; |
703 | |
704 | return isl_bool_ok(b: isl_seq_first_non_zero(p: aff->v->el, len: 2) < 0); |
705 | } |
706 | |
707 | /* Are "aff1" and "aff2" obviously equal? |
708 | * |
709 | * NaN is not equal to anything, not even to another NaN. |
710 | */ |
711 | isl_bool isl_aff_plain_is_equal(__isl_keep isl_aff *aff1, |
712 | __isl_keep isl_aff *aff2) |
713 | { |
714 | isl_bool equal; |
715 | |
716 | if (!aff1 || !aff2) |
717 | return isl_bool_error; |
718 | |
719 | if (isl_aff_is_nan(aff: aff1) || isl_aff_is_nan(aff: aff2)) |
720 | return isl_bool_false; |
721 | |
722 | equal = isl_local_space_is_equal(ls1: aff1->ls, ls2: aff2->ls); |
723 | if (equal < 0 || !equal) |
724 | return equal; |
725 | |
726 | return isl_vec_is_equal(vec1: aff1->v, vec2: aff2->v); |
727 | } |
728 | |
729 | /* Return the common denominator of "aff" in "v". |
730 | * |
731 | * We cannot return anything meaningful in case of a NaN. |
732 | */ |
733 | isl_stat isl_aff_get_denominator(__isl_keep isl_aff *aff, isl_int *v) |
734 | { |
735 | if (!aff) |
736 | return isl_stat_error; |
737 | if (isl_aff_is_nan(aff)) |
738 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
739 | "cannot get denominator of NaN" , return isl_stat_error); |
740 | isl_int_set(*v, aff->v->el[0]); |
741 | return isl_stat_ok; |
742 | } |
743 | |
744 | /* Return the common denominator of "aff". |
745 | */ |
746 | __isl_give isl_val *isl_aff_get_denominator_val(__isl_keep isl_aff *aff) |
747 | { |
748 | isl_ctx *ctx; |
749 | |
750 | if (!aff) |
751 | return NULL; |
752 | |
753 | ctx = isl_aff_get_ctx(aff); |
754 | if (isl_aff_is_nan(aff)) |
755 | return isl_val_nan(ctx); |
756 | return isl_val_int_from_isl_int(ctx, n: aff->v->el[0]); |
757 | } |
758 | |
759 | /* Return the constant term of "aff". |
760 | */ |
761 | __isl_give isl_val *isl_aff_get_constant_val(__isl_keep isl_aff *aff) |
762 | { |
763 | isl_ctx *ctx; |
764 | isl_val *v; |
765 | |
766 | if (!aff) |
767 | return NULL; |
768 | |
769 | ctx = isl_aff_get_ctx(aff); |
770 | if (isl_aff_is_nan(aff)) |
771 | return isl_val_nan(ctx); |
772 | v = isl_val_rat_from_isl_int(ctx, n: aff->v->el[1], d: aff->v->el[0]); |
773 | return isl_val_normalize(v); |
774 | } |
775 | |
776 | /* Return the coefficient of the variable of type "type" at position "pos" |
777 | * of "aff". |
778 | */ |
779 | __isl_give isl_val *isl_aff_get_coefficient_val(__isl_keep isl_aff *aff, |
780 | enum isl_dim_type type, int pos) |
781 | { |
782 | isl_ctx *ctx; |
783 | isl_val *v; |
784 | |
785 | if (!aff) |
786 | return NULL; |
787 | |
788 | ctx = isl_aff_get_ctx(aff); |
789 | if (type == isl_dim_out) |
790 | isl_die(ctx, isl_error_invalid, |
791 | "output/set dimension does not have a coefficient" , |
792 | return NULL); |
793 | if (type == isl_dim_in) |
794 | type = isl_dim_set; |
795 | |
796 | if (isl_local_space_check_range(ls: aff->ls, type, first: pos, n: 1) < 0) |
797 | return NULL; |
798 | |
799 | if (isl_aff_is_nan(aff)) |
800 | return isl_val_nan(ctx); |
801 | pos += isl_local_space_offset(ls: aff->ls, type); |
802 | v = isl_val_rat_from_isl_int(ctx, n: aff->v->el[1 + pos], d: aff->v->el[0]); |
803 | return isl_val_normalize(v); |
804 | } |
805 | |
806 | /* Return the sign of the coefficient of the variable of type "type" |
807 | * at position "pos" of "aff". |
808 | */ |
809 | int isl_aff_coefficient_sgn(__isl_keep isl_aff *aff, enum isl_dim_type type, |
810 | int pos) |
811 | { |
812 | isl_ctx *ctx; |
813 | |
814 | if (!aff) |
815 | return 0; |
816 | |
817 | ctx = isl_aff_get_ctx(aff); |
818 | if (type == isl_dim_out) |
819 | isl_die(ctx, isl_error_invalid, |
820 | "output/set dimension does not have a coefficient" , |
821 | return 0); |
822 | if (type == isl_dim_in) |
823 | type = isl_dim_set; |
824 | |
825 | if (isl_local_space_check_range(ls: aff->ls, type, first: pos, n: 1) < 0) |
826 | return 0; |
827 | |
828 | pos += isl_local_space_offset(ls: aff->ls, type); |
829 | return isl_int_sgn(aff->v->el[1 + pos]); |
830 | } |
831 | |
832 | /* Replace the numerator of the constant term of "aff" by "v". |
833 | * |
834 | * A NaN is unaffected by this operation. |
835 | */ |
836 | __isl_give isl_aff *isl_aff_set_constant(__isl_take isl_aff *aff, isl_int v) |
837 | { |
838 | if (!aff) |
839 | return NULL; |
840 | if (isl_aff_is_nan(aff)) |
841 | return aff; |
842 | aff = isl_aff_cow(aff); |
843 | if (!aff) |
844 | return NULL; |
845 | |
846 | aff->v = isl_vec_cow(vec: aff->v); |
847 | if (!aff->v) |
848 | return isl_aff_free(aff); |
849 | |
850 | isl_int_set(aff->v->el[1], v); |
851 | |
852 | return aff; |
853 | } |
854 | |
855 | /* Replace the constant term of "aff" by "v". |
856 | * |
857 | * A NaN is unaffected by this operation. |
858 | */ |
859 | __isl_give isl_aff *isl_aff_set_constant_val(__isl_take isl_aff *aff, |
860 | __isl_take isl_val *v) |
861 | { |
862 | if (!aff || !v) |
863 | goto error; |
864 | |
865 | if (isl_aff_is_nan(aff)) { |
866 | isl_val_free(v); |
867 | return aff; |
868 | } |
869 | |
870 | if (!isl_val_is_rat(v)) |
871 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
872 | "expecting rational value" , goto error); |
873 | |
874 | if (isl_int_eq(aff->v->el[1], v->n) && |
875 | isl_int_eq(aff->v->el[0], v->d)) { |
876 | isl_val_free(v); |
877 | return aff; |
878 | } |
879 | |
880 | aff = isl_aff_cow(aff); |
881 | if (!aff) |
882 | goto error; |
883 | aff->v = isl_vec_cow(vec: aff->v); |
884 | if (!aff->v) |
885 | goto error; |
886 | |
887 | if (isl_int_eq(aff->v->el[0], v->d)) { |
888 | isl_int_set(aff->v->el[1], v->n); |
889 | } else if (isl_int_is_one(v->d)) { |
890 | isl_int_mul(aff->v->el[1], aff->v->el[0], v->n); |
891 | } else { |
892 | isl_seq_scale(dst: aff->v->el + 1, |
893 | src: aff->v->el + 1, f: v->d, len: aff->v->size - 1); |
894 | isl_int_mul(aff->v->el[1], aff->v->el[0], v->n); |
895 | isl_int_mul(aff->v->el[0], aff->v->el[0], v->d); |
896 | aff->v = isl_vec_normalize(vec: aff->v); |
897 | if (!aff->v) |
898 | goto error; |
899 | } |
900 | |
901 | isl_val_free(v); |
902 | return aff; |
903 | error: |
904 | isl_aff_free(aff); |
905 | isl_val_free(v); |
906 | return NULL; |
907 | } |
908 | |
909 | /* Add "v" to the constant term of "aff". |
910 | * |
911 | * A NaN is unaffected by this operation. |
912 | */ |
913 | __isl_give isl_aff *isl_aff_add_constant(__isl_take isl_aff *aff, isl_int v) |
914 | { |
915 | if (isl_int_is_zero(v)) |
916 | return aff; |
917 | |
918 | if (!aff) |
919 | return NULL; |
920 | if (isl_aff_is_nan(aff)) |
921 | return aff; |
922 | aff = isl_aff_cow(aff); |
923 | if (!aff) |
924 | return NULL; |
925 | |
926 | aff->v = isl_vec_cow(vec: aff->v); |
927 | if (!aff->v) |
928 | return isl_aff_free(aff); |
929 | |
930 | isl_int_addmul(aff->v->el[1], aff->v->el[0], v); |
931 | |
932 | return aff; |
933 | } |
934 | |
935 | /* Add "v" to the constant term of "aff", |
936 | * in case "aff" is a rational expression. |
937 | */ |
938 | static __isl_give isl_aff *isl_aff_add_rat_constant_val(__isl_take isl_aff *aff, |
939 | __isl_take isl_val *v) |
940 | { |
941 | aff = isl_aff_cow(aff); |
942 | if (!aff) |
943 | goto error; |
944 | |
945 | aff->v = isl_vec_cow(vec: aff->v); |
946 | if (!aff->v) |
947 | goto error; |
948 | |
949 | if (isl_int_is_one(v->d)) { |
950 | isl_int_addmul(aff->v->el[1], aff->v->el[0], v->n); |
951 | } else if (isl_int_eq(aff->v->el[0], v->d)) { |
952 | isl_int_add(aff->v->el[1], aff->v->el[1], v->n); |
953 | aff->v = isl_vec_normalize(vec: aff->v); |
954 | if (!aff->v) |
955 | goto error; |
956 | } else { |
957 | isl_seq_scale(dst: aff->v->el + 1, |
958 | src: aff->v->el + 1, f: v->d, len: aff->v->size - 1); |
959 | isl_int_addmul(aff->v->el[1], aff->v->el[0], v->n); |
960 | isl_int_mul(aff->v->el[0], aff->v->el[0], v->d); |
961 | aff->v = isl_vec_normalize(vec: aff->v); |
962 | if (!aff->v) |
963 | goto error; |
964 | } |
965 | |
966 | isl_val_free(v); |
967 | return aff; |
968 | error: |
969 | isl_aff_free(aff); |
970 | isl_val_free(v); |
971 | return NULL; |
972 | } |
973 | |
974 | /* Return the first argument and free the second. |
975 | */ |
976 | static __isl_give isl_aff *pick_free(__isl_take isl_aff *aff, |
977 | __isl_take isl_val *v) |
978 | { |
979 | isl_val_free(v); |
980 | return aff; |
981 | } |
982 | |
983 | /* Replace the first argument by NaN and free the second argument. |
984 | */ |
985 | static __isl_give isl_aff *set_nan_free_val(__isl_take isl_aff *aff, |
986 | __isl_take isl_val *v) |
987 | { |
988 | isl_val_free(v); |
989 | return isl_aff_set_nan(aff); |
990 | } |
991 | |
992 | /* Add "v" to the constant term of "aff". |
993 | * |
994 | * A NaN is unaffected by this operation. |
995 | * Conversely, adding a NaN turns "aff" into a NaN. |
996 | */ |
997 | __isl_give isl_aff *isl_aff_add_constant_val(__isl_take isl_aff *aff, |
998 | __isl_take isl_val *v) |
999 | { |
1000 | isl_bool is_nan, is_zero, is_rat; |
1001 | |
1002 | is_nan = isl_aff_is_nan(aff); |
1003 | is_zero = isl_val_is_zero(v); |
1004 | if (is_nan < 0 || is_zero < 0) |
1005 | goto error; |
1006 | if (is_nan || is_zero) |
1007 | return pick_free(aff, v); |
1008 | |
1009 | is_nan = isl_val_is_nan(v); |
1010 | is_rat = isl_val_is_rat(v); |
1011 | if (is_nan < 0 || is_rat < 0) |
1012 | goto error; |
1013 | if (is_nan) |
1014 | return set_nan_free_val(aff, v); |
1015 | if (!is_rat) |
1016 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
1017 | "expecting rational value or NaN" , goto error); |
1018 | |
1019 | return isl_aff_add_rat_constant_val(aff, v); |
1020 | error: |
1021 | isl_aff_free(aff); |
1022 | isl_val_free(v); |
1023 | return NULL; |
1024 | } |
1025 | |
1026 | __isl_give isl_aff *isl_aff_add_constant_si(__isl_take isl_aff *aff, int v) |
1027 | { |
1028 | isl_int t; |
1029 | |
1030 | isl_int_init(t); |
1031 | isl_int_set_si(t, v); |
1032 | aff = isl_aff_add_constant(aff, v: t); |
1033 | isl_int_clear(t); |
1034 | |
1035 | return aff; |
1036 | } |
1037 | |
1038 | /* Add "v" to the numerator of the constant term of "aff". |
1039 | * |
1040 | * A NaN is unaffected by this operation. |
1041 | */ |
1042 | __isl_give isl_aff *isl_aff_add_constant_num(__isl_take isl_aff *aff, isl_int v) |
1043 | { |
1044 | if (isl_int_is_zero(v)) |
1045 | return aff; |
1046 | |
1047 | if (!aff) |
1048 | return NULL; |
1049 | if (isl_aff_is_nan(aff)) |
1050 | return aff; |
1051 | aff = isl_aff_cow(aff); |
1052 | if (!aff) |
1053 | return NULL; |
1054 | |
1055 | aff->v = isl_vec_cow(vec: aff->v); |
1056 | if (!aff->v) |
1057 | return isl_aff_free(aff); |
1058 | |
1059 | isl_int_add(aff->v->el[1], aff->v->el[1], v); |
1060 | |
1061 | return aff; |
1062 | } |
1063 | |
1064 | /* Add "v" to the numerator of the constant term of "aff". |
1065 | * |
1066 | * A NaN is unaffected by this operation. |
1067 | */ |
1068 | __isl_give isl_aff *isl_aff_add_constant_num_si(__isl_take isl_aff *aff, int v) |
1069 | { |
1070 | isl_int t; |
1071 | |
1072 | if (v == 0) |
1073 | return aff; |
1074 | |
1075 | isl_int_init(t); |
1076 | isl_int_set_si(t, v); |
1077 | aff = isl_aff_add_constant_num(aff, v: t); |
1078 | isl_int_clear(t); |
1079 | |
1080 | return aff; |
1081 | } |
1082 | |
1083 | /* Replace the numerator of the constant term of "aff" by "v". |
1084 | * |
1085 | * A NaN is unaffected by this operation. |
1086 | */ |
1087 | __isl_give isl_aff *isl_aff_set_constant_si(__isl_take isl_aff *aff, int v) |
1088 | { |
1089 | if (!aff) |
1090 | return NULL; |
1091 | if (isl_aff_is_nan(aff)) |
1092 | return aff; |
1093 | aff = isl_aff_cow(aff); |
1094 | if (!aff) |
1095 | return NULL; |
1096 | |
1097 | aff->v = isl_vec_cow(vec: aff->v); |
1098 | if (!aff->v) |
1099 | return isl_aff_free(aff); |
1100 | |
1101 | isl_int_set_si(aff->v->el[1], v); |
1102 | |
1103 | return aff; |
1104 | } |
1105 | |
1106 | /* Replace the numerator of the coefficient of the variable of type "type" |
1107 | * at position "pos" of "aff" by "v". |
1108 | * |
1109 | * A NaN is unaffected by this operation. |
1110 | */ |
1111 | __isl_give isl_aff *isl_aff_set_coefficient(__isl_take isl_aff *aff, |
1112 | enum isl_dim_type type, int pos, isl_int v) |
1113 | { |
1114 | if (!aff) |
1115 | return NULL; |
1116 | |
1117 | if (type == isl_dim_out) |
1118 | isl_die(aff->v->ctx, isl_error_invalid, |
1119 | "output/set dimension does not have a coefficient" , |
1120 | return isl_aff_free(aff)); |
1121 | if (type == isl_dim_in) |
1122 | type = isl_dim_set; |
1123 | |
1124 | if (isl_local_space_check_range(ls: aff->ls, type, first: pos, n: 1) < 0) |
1125 | return isl_aff_free(aff); |
1126 | |
1127 | if (isl_aff_is_nan(aff)) |
1128 | return aff; |
1129 | aff = isl_aff_cow(aff); |
1130 | if (!aff) |
1131 | return NULL; |
1132 | |
1133 | aff->v = isl_vec_cow(vec: aff->v); |
1134 | if (!aff->v) |
1135 | return isl_aff_free(aff); |
1136 | |
1137 | pos += isl_local_space_offset(ls: aff->ls, type); |
1138 | isl_int_set(aff->v->el[1 + pos], v); |
1139 | |
1140 | return aff; |
1141 | } |
1142 | |
1143 | /* Replace the numerator of the coefficient of the variable of type "type" |
1144 | * at position "pos" of "aff" by "v". |
1145 | * |
1146 | * A NaN is unaffected by this operation. |
1147 | */ |
1148 | __isl_give isl_aff *isl_aff_set_coefficient_si(__isl_take isl_aff *aff, |
1149 | enum isl_dim_type type, int pos, int v) |
1150 | { |
1151 | if (!aff) |
1152 | return NULL; |
1153 | |
1154 | if (type == isl_dim_out) |
1155 | isl_die(aff->v->ctx, isl_error_invalid, |
1156 | "output/set dimension does not have a coefficient" , |
1157 | return isl_aff_free(aff)); |
1158 | if (type == isl_dim_in) |
1159 | type = isl_dim_set; |
1160 | |
1161 | if (isl_local_space_check_range(ls: aff->ls, type, first: pos, n: 1) < 0) |
1162 | return isl_aff_free(aff); |
1163 | |
1164 | if (isl_aff_is_nan(aff)) |
1165 | return aff; |
1166 | pos += isl_local_space_offset(ls: aff->ls, type); |
1167 | if (isl_int_cmp_si(aff->v->el[1 + pos], v) == 0) |
1168 | return aff; |
1169 | |
1170 | aff = isl_aff_cow(aff); |
1171 | if (!aff) |
1172 | return NULL; |
1173 | |
1174 | aff->v = isl_vec_cow(vec: aff->v); |
1175 | if (!aff->v) |
1176 | return isl_aff_free(aff); |
1177 | |
1178 | isl_int_set_si(aff->v->el[1 + pos], v); |
1179 | |
1180 | return aff; |
1181 | } |
1182 | |
1183 | /* Replace the coefficient of the variable of type "type" at position "pos" |
1184 | * of "aff" by "v". |
1185 | * |
1186 | * A NaN is unaffected by this operation. |
1187 | */ |
1188 | __isl_give isl_aff *isl_aff_set_coefficient_val(__isl_take isl_aff *aff, |
1189 | enum isl_dim_type type, int pos, __isl_take isl_val *v) |
1190 | { |
1191 | if (!aff || !v) |
1192 | goto error; |
1193 | |
1194 | if (type == isl_dim_out) |
1195 | isl_die(aff->v->ctx, isl_error_invalid, |
1196 | "output/set dimension does not have a coefficient" , |
1197 | goto error); |
1198 | if (type == isl_dim_in) |
1199 | type = isl_dim_set; |
1200 | |
1201 | if (isl_local_space_check_range(ls: aff->ls, type, first: pos, n: 1) < 0) |
1202 | return isl_aff_free(aff); |
1203 | |
1204 | if (isl_aff_is_nan(aff)) { |
1205 | isl_val_free(v); |
1206 | return aff; |
1207 | } |
1208 | if (!isl_val_is_rat(v)) |
1209 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
1210 | "expecting rational value" , goto error); |
1211 | |
1212 | pos += isl_local_space_offset(ls: aff->ls, type); |
1213 | if (isl_int_eq(aff->v->el[1 + pos], v->n) && |
1214 | isl_int_eq(aff->v->el[0], v->d)) { |
1215 | isl_val_free(v); |
1216 | return aff; |
1217 | } |
1218 | |
1219 | aff = isl_aff_cow(aff); |
1220 | if (!aff) |
1221 | goto error; |
1222 | aff->v = isl_vec_cow(vec: aff->v); |
1223 | if (!aff->v) |
1224 | goto error; |
1225 | |
1226 | if (isl_int_eq(aff->v->el[0], v->d)) { |
1227 | isl_int_set(aff->v->el[1 + pos], v->n); |
1228 | } else if (isl_int_is_one(v->d)) { |
1229 | isl_int_mul(aff->v->el[1 + pos], aff->v->el[0], v->n); |
1230 | } else { |
1231 | isl_seq_scale(dst: aff->v->el + 1, |
1232 | src: aff->v->el + 1, f: v->d, len: aff->v->size - 1); |
1233 | isl_int_mul(aff->v->el[1 + pos], aff->v->el[0], v->n); |
1234 | isl_int_mul(aff->v->el[0], aff->v->el[0], v->d); |
1235 | aff->v = isl_vec_normalize(vec: aff->v); |
1236 | if (!aff->v) |
1237 | goto error; |
1238 | } |
1239 | |
1240 | isl_val_free(v); |
1241 | return aff; |
1242 | error: |
1243 | isl_aff_free(aff); |
1244 | isl_val_free(v); |
1245 | return NULL; |
1246 | } |
1247 | |
1248 | /* Add "v" to the coefficient of the variable of type "type" |
1249 | * at position "pos" of "aff". |
1250 | * |
1251 | * A NaN is unaffected by this operation. |
1252 | */ |
1253 | __isl_give isl_aff *isl_aff_add_coefficient(__isl_take isl_aff *aff, |
1254 | enum isl_dim_type type, int pos, isl_int v) |
1255 | { |
1256 | if (!aff) |
1257 | return NULL; |
1258 | |
1259 | if (type == isl_dim_out) |
1260 | isl_die(aff->v->ctx, isl_error_invalid, |
1261 | "output/set dimension does not have a coefficient" , |
1262 | return isl_aff_free(aff)); |
1263 | if (type == isl_dim_in) |
1264 | type = isl_dim_set; |
1265 | |
1266 | if (isl_local_space_check_range(ls: aff->ls, type, first: pos, n: 1) < 0) |
1267 | return isl_aff_free(aff); |
1268 | |
1269 | if (isl_aff_is_nan(aff)) |
1270 | return aff; |
1271 | aff = isl_aff_cow(aff); |
1272 | if (!aff) |
1273 | return NULL; |
1274 | |
1275 | aff->v = isl_vec_cow(vec: aff->v); |
1276 | if (!aff->v) |
1277 | return isl_aff_free(aff); |
1278 | |
1279 | pos += isl_local_space_offset(ls: aff->ls, type); |
1280 | isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v); |
1281 | |
1282 | return aff; |
1283 | } |
1284 | |
1285 | /* Add "v" to the coefficient of the variable of type "type" |
1286 | * at position "pos" of "aff". |
1287 | * |
1288 | * A NaN is unaffected by this operation. |
1289 | */ |
1290 | __isl_give isl_aff *isl_aff_add_coefficient_val(__isl_take isl_aff *aff, |
1291 | enum isl_dim_type type, int pos, __isl_take isl_val *v) |
1292 | { |
1293 | if (!aff || !v) |
1294 | goto error; |
1295 | |
1296 | if (isl_val_is_zero(v)) { |
1297 | isl_val_free(v); |
1298 | return aff; |
1299 | } |
1300 | |
1301 | if (type == isl_dim_out) |
1302 | isl_die(aff->v->ctx, isl_error_invalid, |
1303 | "output/set dimension does not have a coefficient" , |
1304 | goto error); |
1305 | if (type == isl_dim_in) |
1306 | type = isl_dim_set; |
1307 | |
1308 | if (isl_local_space_check_range(ls: aff->ls, type, first: pos, n: 1) < 0) |
1309 | goto error; |
1310 | |
1311 | if (isl_aff_is_nan(aff)) { |
1312 | isl_val_free(v); |
1313 | return aff; |
1314 | } |
1315 | if (!isl_val_is_rat(v)) |
1316 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
1317 | "expecting rational value" , goto error); |
1318 | |
1319 | aff = isl_aff_cow(aff); |
1320 | if (!aff) |
1321 | goto error; |
1322 | |
1323 | aff->v = isl_vec_cow(vec: aff->v); |
1324 | if (!aff->v) |
1325 | goto error; |
1326 | |
1327 | pos += isl_local_space_offset(ls: aff->ls, type); |
1328 | if (isl_int_is_one(v->d)) { |
1329 | isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v->n); |
1330 | } else if (isl_int_eq(aff->v->el[0], v->d)) { |
1331 | isl_int_add(aff->v->el[1 + pos], aff->v->el[1 + pos], v->n); |
1332 | aff->v = isl_vec_normalize(vec: aff->v); |
1333 | if (!aff->v) |
1334 | goto error; |
1335 | } else { |
1336 | isl_seq_scale(dst: aff->v->el + 1, |
1337 | src: aff->v->el + 1, f: v->d, len: aff->v->size - 1); |
1338 | isl_int_addmul(aff->v->el[1 + pos], aff->v->el[0], v->n); |
1339 | isl_int_mul(aff->v->el[0], aff->v->el[0], v->d); |
1340 | aff->v = isl_vec_normalize(vec: aff->v); |
1341 | if (!aff->v) |
1342 | goto error; |
1343 | } |
1344 | |
1345 | isl_val_free(v); |
1346 | return aff; |
1347 | error: |
1348 | isl_aff_free(aff); |
1349 | isl_val_free(v); |
1350 | return NULL; |
1351 | } |
1352 | |
1353 | __isl_give isl_aff *isl_aff_add_coefficient_si(__isl_take isl_aff *aff, |
1354 | enum isl_dim_type type, int pos, int v) |
1355 | { |
1356 | isl_int t; |
1357 | |
1358 | isl_int_init(t); |
1359 | isl_int_set_si(t, v); |
1360 | aff = isl_aff_add_coefficient(aff, type, pos, v: t); |
1361 | isl_int_clear(t); |
1362 | |
1363 | return aff; |
1364 | } |
1365 | |
1366 | __isl_give isl_aff *isl_aff_get_div(__isl_keep isl_aff *aff, int pos) |
1367 | { |
1368 | if (!aff) |
1369 | return NULL; |
1370 | |
1371 | return isl_local_space_get_div(ls: aff->ls, pos); |
1372 | } |
1373 | |
1374 | /* Return the negation of "aff". |
1375 | * |
1376 | * As a special case, -NaN = NaN. |
1377 | */ |
1378 | __isl_give isl_aff *isl_aff_neg(__isl_take isl_aff *aff) |
1379 | { |
1380 | if (!aff) |
1381 | return NULL; |
1382 | if (isl_aff_is_nan(aff)) |
1383 | return aff; |
1384 | aff = isl_aff_cow(aff); |
1385 | if (!aff) |
1386 | return NULL; |
1387 | aff->v = isl_vec_cow(vec: aff->v); |
1388 | if (!aff->v) |
1389 | return isl_aff_free(aff); |
1390 | |
1391 | isl_seq_neg(dst: aff->v->el + 1, src: aff->v->el + 1, len: aff->v->size - 1); |
1392 | |
1393 | return aff; |
1394 | } |
1395 | |
1396 | /* Remove divs from the local space that do not appear in the affine |
1397 | * expression. |
1398 | * We currently only remove divs at the end. |
1399 | * Some intermediate divs may also not appear directly in the affine |
1400 | * expression, but we would also need to check that no other divs are |
1401 | * defined in terms of them. |
1402 | */ |
1403 | __isl_give isl_aff *isl_aff_remove_unused_divs(__isl_take isl_aff *aff) |
1404 | { |
1405 | int pos; |
1406 | isl_size off; |
1407 | isl_size n; |
1408 | |
1409 | n = isl_aff_domain_dim(aff, type: isl_dim_div); |
1410 | off = isl_aff_domain_offset(aff, type: isl_dim_div); |
1411 | if (n < 0 || off < 0) |
1412 | return isl_aff_free(aff); |
1413 | |
1414 | pos = isl_seq_last_non_zero(p: aff->v->el + 1 + off, len: n) + 1; |
1415 | if (pos == n) |
1416 | return aff; |
1417 | |
1418 | aff = isl_aff_cow(aff); |
1419 | if (!aff) |
1420 | return NULL; |
1421 | |
1422 | aff->ls = isl_local_space_drop_dims(ls: aff->ls, type: isl_dim_div, first: pos, n: n - pos); |
1423 | aff->v = isl_vec_drop_els(vec: aff->v, pos: 1 + off + pos, n: n - pos); |
1424 | if (!aff->ls || !aff->v) |
1425 | return isl_aff_free(aff); |
1426 | |
1427 | return aff; |
1428 | } |
1429 | |
1430 | /* Look for any divs in the aff->ls with a denominator equal to one |
1431 | * and plug them into the affine expression and any subsequent divs |
1432 | * that may reference the div. |
1433 | */ |
1434 | static __isl_give isl_aff *plug_in_integral_divs(__isl_take isl_aff *aff) |
1435 | { |
1436 | int i; |
1437 | isl_size n; |
1438 | int len; |
1439 | isl_int v; |
1440 | isl_vec *vec; |
1441 | isl_local_space *ls; |
1442 | isl_size off; |
1443 | |
1444 | n = isl_aff_domain_dim(aff, type: isl_dim_div); |
1445 | off = isl_aff_domain_offset(aff, type: isl_dim_div); |
1446 | if (n < 0 || off < 0) |
1447 | return isl_aff_free(aff); |
1448 | len = aff->v->size; |
1449 | for (i = 0; i < n; ++i) { |
1450 | if (!isl_int_is_one(aff->ls->div->row[i][0])) |
1451 | continue; |
1452 | ls = isl_local_space_copy(ls: aff->ls); |
1453 | ls = isl_local_space_substitute_seq(ls, type: isl_dim_div, pos: i, |
1454 | subs: aff->ls->div->row[i], subs_len: len, first: i + 1, n: n - (i + 1)); |
1455 | vec = isl_vec_copy(vec: aff->v); |
1456 | vec = isl_vec_cow(vec); |
1457 | if (!ls || !vec) |
1458 | goto error; |
1459 | |
1460 | isl_int_init(v); |
1461 | |
1462 | isl_seq_substitute(p: vec->el, pos: off + i, subs: aff->ls->div->row[i], |
1463 | p_len: len, subs_len: len, v); |
1464 | |
1465 | isl_int_clear(v); |
1466 | |
1467 | isl_vec_free(vec: aff->v); |
1468 | aff->v = vec; |
1469 | isl_local_space_free(ls: aff->ls); |
1470 | aff->ls = ls; |
1471 | } |
1472 | |
1473 | return aff; |
1474 | error: |
1475 | isl_vec_free(vec); |
1476 | isl_local_space_free(ls); |
1477 | return isl_aff_free(aff); |
1478 | } |
1479 | |
1480 | /* Look for any divs j that appear with a unit coefficient inside |
1481 | * the definitions of other divs i and plug them into the definitions |
1482 | * of the divs i. |
1483 | * |
1484 | * In particular, an expression of the form |
1485 | * |
1486 | * floor((f(..) + floor(g(..)/n))/m) |
1487 | * |
1488 | * is simplified to |
1489 | * |
1490 | * floor((n * f(..) + g(..))/(n * m)) |
1491 | * |
1492 | * This simplification is correct because we can move the expression |
1493 | * f(..) into the inner floor in the original expression to obtain |
1494 | * |
1495 | * floor(floor((n * f(..) + g(..))/n)/m) |
1496 | * |
1497 | * from which we can derive the simplified expression. |
1498 | */ |
1499 | static __isl_give isl_aff *plug_in_unit_divs(__isl_take isl_aff *aff) |
1500 | { |
1501 | int i, j; |
1502 | isl_size n; |
1503 | isl_size off; |
1504 | |
1505 | n = isl_aff_domain_dim(aff, type: isl_dim_div); |
1506 | off = isl_aff_domain_offset(aff, type: isl_dim_div); |
1507 | if (n < 0 || off < 0) |
1508 | return isl_aff_free(aff); |
1509 | for (i = 1; i < n; ++i) { |
1510 | for (j = 0; j < i; ++j) { |
1511 | if (!isl_int_is_one(aff->ls->div->row[i][1 + off + j])) |
1512 | continue; |
1513 | aff->ls = isl_local_space_substitute_seq(ls: aff->ls, |
1514 | type: isl_dim_div, pos: j, subs: aff->ls->div->row[j], |
1515 | subs_len: aff->v->size, first: i, n: 1); |
1516 | if (!aff->ls) |
1517 | return isl_aff_free(aff); |
1518 | } |
1519 | } |
1520 | |
1521 | return aff; |
1522 | } |
1523 | |
1524 | /* Swap divs "a" and "b" in "aff", which is assumed to be non-NULL. |
1525 | * |
1526 | * Even though this function is only called on isl_affs with a single |
1527 | * reference, we are careful to only change aff->v and aff->ls together. |
1528 | */ |
1529 | static __isl_give isl_aff *swap_div(__isl_take isl_aff *aff, int a, int b) |
1530 | { |
1531 | isl_size off = isl_aff_domain_offset(aff, type: isl_dim_div); |
1532 | isl_local_space *ls; |
1533 | isl_vec *v; |
1534 | |
1535 | if (off < 0) |
1536 | return isl_aff_free(aff); |
1537 | |
1538 | ls = isl_local_space_copy(ls: aff->ls); |
1539 | ls = isl_local_space_swap_div(ls, a, b); |
1540 | v = isl_vec_copy(vec: aff->v); |
1541 | v = isl_vec_cow(vec: v); |
1542 | if (!ls || !v) |
1543 | goto error; |
1544 | |
1545 | isl_int_swap(v->el[1 + off + a], v->el[1 + off + b]); |
1546 | isl_vec_free(vec: aff->v); |
1547 | aff->v = v; |
1548 | isl_local_space_free(ls: aff->ls); |
1549 | aff->ls = ls; |
1550 | |
1551 | return aff; |
1552 | error: |
1553 | isl_vec_free(vec: v); |
1554 | isl_local_space_free(ls); |
1555 | return isl_aff_free(aff); |
1556 | } |
1557 | |
1558 | /* Merge divs "a" and "b" in "aff", which is assumed to be non-NULL. |
1559 | * |
1560 | * We currently do not actually remove div "b", but simply add its |
1561 | * coefficient to that of "a" and then zero it out. |
1562 | */ |
1563 | static __isl_give isl_aff *merge_divs(__isl_take isl_aff *aff, int a, int b) |
1564 | { |
1565 | isl_size off = isl_aff_domain_offset(aff, type: isl_dim_div); |
1566 | |
1567 | if (off < 0) |
1568 | return isl_aff_free(aff); |
1569 | |
1570 | if (isl_int_is_zero(aff->v->el[1 + off + b])) |
1571 | return aff; |
1572 | |
1573 | aff->v = isl_vec_cow(vec: aff->v); |
1574 | if (!aff->v) |
1575 | return isl_aff_free(aff); |
1576 | |
1577 | isl_int_add(aff->v->el[1 + off + a], |
1578 | aff->v->el[1 + off + a], aff->v->el[1 + off + b]); |
1579 | isl_int_set_si(aff->v->el[1 + off + b], 0); |
1580 | |
1581 | return aff; |
1582 | } |
1583 | |
1584 | /* Sort the divs in the local space of "aff" according to |
1585 | * the comparison function "cmp_row" in isl_local_space.c, |
1586 | * combining the coefficients of identical divs. |
1587 | * |
1588 | * Reordering divs does not change the semantics of "aff", |
1589 | * so there is no need to call isl_aff_cow. |
1590 | * Moreover, this function is currently only called on isl_affs |
1591 | * with a single reference. |
1592 | */ |
1593 | static __isl_give isl_aff *sort_divs(__isl_take isl_aff *aff) |
1594 | { |
1595 | isl_size n; |
1596 | int i, j; |
1597 | |
1598 | n = isl_aff_dim(aff, type: isl_dim_div); |
1599 | if (n < 0) |
1600 | return isl_aff_free(aff); |
1601 | for (i = 1; i < n; ++i) { |
1602 | for (j = i - 1; j >= 0; --j) { |
1603 | int cmp = isl_mat_cmp_div(div: aff->ls->div, i: j, j: j + 1); |
1604 | if (cmp < 0) |
1605 | break; |
1606 | if (cmp == 0) |
1607 | aff = merge_divs(aff, a: j, b: j + 1); |
1608 | else |
1609 | aff = swap_div(aff, a: j, b: j + 1); |
1610 | if (!aff) |
1611 | return NULL; |
1612 | } |
1613 | } |
1614 | |
1615 | return aff; |
1616 | } |
1617 | |
1618 | /* Normalize the representation of "aff". |
1619 | * |
1620 | * This function should only be called on "new" isl_affs, i.e., |
1621 | * with only a single reference. We therefore do not need to |
1622 | * worry about affecting other instances. |
1623 | */ |
1624 | __isl_give isl_aff *isl_aff_normalize(__isl_take isl_aff *aff) |
1625 | { |
1626 | if (!aff) |
1627 | return NULL; |
1628 | aff->v = isl_vec_normalize(vec: aff->v); |
1629 | if (!aff->v) |
1630 | return isl_aff_free(aff); |
1631 | aff = plug_in_integral_divs(aff); |
1632 | aff = plug_in_unit_divs(aff); |
1633 | aff = sort_divs(aff); |
1634 | aff = isl_aff_remove_unused_divs(aff); |
1635 | return aff; |
1636 | } |
1637 | |
1638 | /* Given f, return floor(f). |
1639 | * If f is an integer expression, then just return f. |
1640 | * If f is a constant, then return the constant floor(f). |
1641 | * Otherwise, if f = g/m, write g = q m + r, |
1642 | * create a new div d = [r/m] and return the expression q + d. |
1643 | * The coefficients in r are taken to lie between -m/2 and m/2. |
1644 | * |
1645 | * reduce_div_coefficients performs the same normalization. |
1646 | * |
1647 | * As a special case, floor(NaN) = NaN. |
1648 | */ |
1649 | __isl_give isl_aff *isl_aff_floor(__isl_take isl_aff *aff) |
1650 | { |
1651 | int i; |
1652 | int size; |
1653 | isl_ctx *ctx; |
1654 | isl_vec *div; |
1655 | |
1656 | if (!aff) |
1657 | return NULL; |
1658 | |
1659 | if (isl_aff_is_nan(aff)) |
1660 | return aff; |
1661 | if (isl_int_is_one(aff->v->el[0])) |
1662 | return aff; |
1663 | |
1664 | aff = isl_aff_cow(aff); |
1665 | if (!aff) |
1666 | return NULL; |
1667 | |
1668 | aff->v = isl_vec_cow(vec: aff->v); |
1669 | if (!aff->v) |
1670 | return isl_aff_free(aff); |
1671 | |
1672 | if (isl_aff_is_cst(aff)) { |
1673 | isl_int_fdiv_q(aff->v->el[1], aff->v->el[1], aff->v->el[0]); |
1674 | isl_int_set_si(aff->v->el[0], 1); |
1675 | return aff; |
1676 | } |
1677 | |
1678 | div = isl_vec_copy(vec: aff->v); |
1679 | div = isl_vec_cow(vec: div); |
1680 | if (!div) |
1681 | return isl_aff_free(aff); |
1682 | |
1683 | ctx = isl_aff_get_ctx(aff); |
1684 | isl_int_fdiv_q(aff->v->el[0], aff->v->el[0], ctx->two); |
1685 | for (i = 1; i < aff->v->size; ++i) { |
1686 | isl_int_fdiv_r(div->el[i], div->el[i], div->el[0]); |
1687 | isl_int_fdiv_q(aff->v->el[i], aff->v->el[i], div->el[0]); |
1688 | if (isl_int_gt(div->el[i], aff->v->el[0])) { |
1689 | isl_int_sub(div->el[i], div->el[i], div->el[0]); |
1690 | isl_int_add_ui(aff->v->el[i], aff->v->el[i], 1); |
1691 | } |
1692 | } |
1693 | |
1694 | aff->ls = isl_local_space_add_div(ls: aff->ls, div); |
1695 | if (!aff->ls) |
1696 | return isl_aff_free(aff); |
1697 | |
1698 | size = aff->v->size; |
1699 | aff->v = isl_vec_extend(vec: aff->v, size: size + 1); |
1700 | if (!aff->v) |
1701 | return isl_aff_free(aff); |
1702 | isl_int_set_si(aff->v->el[0], 1); |
1703 | isl_int_set_si(aff->v->el[size], 1); |
1704 | |
1705 | aff = isl_aff_normalize(aff); |
1706 | |
1707 | return aff; |
1708 | } |
1709 | |
1710 | /* Compute |
1711 | * |
1712 | * aff mod m = aff - m * floor(aff/m) |
1713 | * |
1714 | * with m an integer value. |
1715 | */ |
1716 | __isl_give isl_aff *isl_aff_mod_val(__isl_take isl_aff *aff, |
1717 | __isl_take isl_val *m) |
1718 | { |
1719 | isl_aff *res; |
1720 | |
1721 | if (!aff || !m) |
1722 | goto error; |
1723 | |
1724 | if (!isl_val_is_int(v: m)) |
1725 | isl_die(isl_val_get_ctx(m), isl_error_invalid, |
1726 | "expecting integer modulo" , goto error); |
1727 | |
1728 | res = isl_aff_copy(aff); |
1729 | aff = isl_aff_scale_down_val(aff, v: isl_val_copy(v: m)); |
1730 | aff = isl_aff_floor(aff); |
1731 | aff = isl_aff_scale_val(aff, v: m); |
1732 | res = isl_aff_sub(aff1: res, aff2: aff); |
1733 | |
1734 | return res; |
1735 | error: |
1736 | isl_aff_free(aff); |
1737 | isl_val_free(v: m); |
1738 | return NULL; |
1739 | } |
1740 | |
1741 | /* Compute |
1742 | * |
1743 | * pwaff mod m = pwaff - m * floor(pwaff/m) |
1744 | */ |
1745 | __isl_give isl_pw_aff *isl_pw_aff_mod(__isl_take isl_pw_aff *pwaff, isl_int m) |
1746 | { |
1747 | isl_pw_aff *res; |
1748 | |
1749 | res = isl_pw_aff_copy(pwaff); |
1750 | pwaff = isl_pw_aff_scale_down(pwaff, f: m); |
1751 | pwaff = isl_pw_aff_floor(pwaff); |
1752 | pwaff = isl_pw_aff_scale(pwaff, f: m); |
1753 | res = isl_pw_aff_sub(pwaff1: res, pwaff2: pwaff); |
1754 | |
1755 | return res; |
1756 | } |
1757 | |
1758 | /* Compute |
1759 | * |
1760 | * pa mod m = pa - m * floor(pa/m) |
1761 | * |
1762 | * with m an integer value. |
1763 | */ |
1764 | __isl_give isl_pw_aff *isl_pw_aff_mod_val(__isl_take isl_pw_aff *pa, |
1765 | __isl_take isl_val *m) |
1766 | { |
1767 | if (!pa || !m) |
1768 | goto error; |
1769 | if (!isl_val_is_int(v: m)) |
1770 | isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, |
1771 | "expecting integer modulo" , goto error); |
1772 | pa = isl_pw_aff_mod(pwaff: pa, m: m->n); |
1773 | isl_val_free(v: m); |
1774 | return pa; |
1775 | error: |
1776 | isl_pw_aff_free(pwaff: pa); |
1777 | isl_val_free(v: m); |
1778 | return NULL; |
1779 | } |
1780 | |
1781 | /* Given f, return ceil(f). |
1782 | * If f is an integer expression, then just return f. |
1783 | * Otherwise, let f be the expression |
1784 | * |
1785 | * e/m |
1786 | * |
1787 | * then return |
1788 | * |
1789 | * floor((e + m - 1)/m) |
1790 | * |
1791 | * As a special case, ceil(NaN) = NaN. |
1792 | */ |
1793 | __isl_give isl_aff *isl_aff_ceil(__isl_take isl_aff *aff) |
1794 | { |
1795 | if (!aff) |
1796 | return NULL; |
1797 | |
1798 | if (isl_aff_is_nan(aff)) |
1799 | return aff; |
1800 | if (isl_int_is_one(aff->v->el[0])) |
1801 | return aff; |
1802 | |
1803 | aff = isl_aff_cow(aff); |
1804 | if (!aff) |
1805 | return NULL; |
1806 | aff->v = isl_vec_cow(vec: aff->v); |
1807 | if (!aff->v) |
1808 | return isl_aff_free(aff); |
1809 | |
1810 | isl_int_add(aff->v->el[1], aff->v->el[1], aff->v->el[0]); |
1811 | isl_int_sub_ui(aff->v->el[1], aff->v->el[1], 1); |
1812 | aff = isl_aff_floor(aff); |
1813 | |
1814 | return aff; |
1815 | } |
1816 | |
1817 | /* Apply the expansion computed by isl_merge_divs. |
1818 | * The expansion itself is given by "exp" while the resulting |
1819 | * list of divs is given by "div". |
1820 | */ |
1821 | __isl_give isl_aff *isl_aff_expand_divs(__isl_take isl_aff *aff, |
1822 | __isl_take isl_mat *div, int *exp) |
1823 | { |
1824 | isl_size old_n_div; |
1825 | isl_size new_n_div; |
1826 | isl_size offset; |
1827 | |
1828 | aff = isl_aff_cow(aff); |
1829 | |
1830 | offset = isl_aff_domain_offset(aff, type: isl_dim_div); |
1831 | old_n_div = isl_aff_domain_dim(aff, type: isl_dim_div); |
1832 | new_n_div = isl_mat_rows(mat: div); |
1833 | if (offset < 0 || old_n_div < 0 || new_n_div < 0) |
1834 | goto error; |
1835 | |
1836 | aff->v = isl_vec_expand(vec: aff->v, pos: 1 + offset, n: old_n_div, exp, expanded: new_n_div); |
1837 | aff->ls = isl_local_space_replace_divs(ls: aff->ls, div); |
1838 | if (!aff->v || !aff->ls) |
1839 | return isl_aff_free(aff); |
1840 | return aff; |
1841 | error: |
1842 | isl_aff_free(aff); |
1843 | isl_mat_free(mat: div); |
1844 | return NULL; |
1845 | } |
1846 | |
1847 | /* Add two affine expressions that live in the same local space. |
1848 | */ |
1849 | static __isl_give isl_aff *add_expanded(__isl_take isl_aff *aff1, |
1850 | __isl_take isl_aff *aff2) |
1851 | { |
1852 | isl_int gcd, f; |
1853 | |
1854 | aff1 = isl_aff_cow(aff: aff1); |
1855 | if (!aff1 || !aff2) |
1856 | goto error; |
1857 | |
1858 | aff1->v = isl_vec_cow(vec: aff1->v); |
1859 | if (!aff1->v) |
1860 | goto error; |
1861 | |
1862 | isl_int_init(gcd); |
1863 | isl_int_init(f); |
1864 | isl_int_gcd(gcd, aff1->v->el[0], aff2->v->el[0]); |
1865 | isl_int_divexact(f, aff2->v->el[0], gcd); |
1866 | isl_seq_scale(dst: aff1->v->el + 1, src: aff1->v->el + 1, f, len: aff1->v->size - 1); |
1867 | isl_int_divexact(f, aff1->v->el[0], gcd); |
1868 | isl_seq_addmul(dst: aff1->v->el + 1, f, src: aff2->v->el + 1, len: aff1->v->size - 1); |
1869 | isl_int_divexact(f, aff2->v->el[0], gcd); |
1870 | isl_int_mul(aff1->v->el[0], aff1->v->el[0], f); |
1871 | isl_int_clear(f); |
1872 | isl_int_clear(gcd); |
1873 | |
1874 | isl_aff_free(aff: aff2); |
1875 | aff1 = isl_aff_normalize(aff: aff1); |
1876 | return aff1; |
1877 | error: |
1878 | isl_aff_free(aff: aff1); |
1879 | isl_aff_free(aff: aff2); |
1880 | return NULL; |
1881 | } |
1882 | |
1883 | /* Replace one of the arguments by a NaN and free the other one. |
1884 | */ |
1885 | static __isl_give isl_aff *set_nan_free(__isl_take isl_aff *aff1, |
1886 | __isl_take isl_aff *aff2) |
1887 | { |
1888 | isl_aff_free(aff: aff2); |
1889 | return isl_aff_set_nan(aff: aff1); |
1890 | } |
1891 | |
1892 | /* Return the sum of "aff1" and "aff2". |
1893 | * |
1894 | * If either of the two is NaN, then the result is NaN. |
1895 | */ |
1896 | __isl_give isl_aff *isl_aff_add(__isl_take isl_aff *aff1, |
1897 | __isl_take isl_aff *aff2) |
1898 | { |
1899 | isl_ctx *ctx; |
1900 | int *exp1 = NULL; |
1901 | int *exp2 = NULL; |
1902 | isl_mat *div; |
1903 | isl_size n_div1, n_div2; |
1904 | |
1905 | if (!aff1 || !aff2) |
1906 | goto error; |
1907 | |
1908 | ctx = isl_aff_get_ctx(aff: aff1); |
1909 | if (!isl_space_is_equal(space1: aff1->ls->dim, space2: aff2->ls->dim)) |
1910 | isl_die(ctx, isl_error_invalid, |
1911 | "spaces don't match" , goto error); |
1912 | |
1913 | if (isl_aff_is_nan(aff: aff1)) { |
1914 | isl_aff_free(aff: aff2); |
1915 | return aff1; |
1916 | } |
1917 | if (isl_aff_is_nan(aff: aff2)) { |
1918 | isl_aff_free(aff: aff1); |
1919 | return aff2; |
1920 | } |
1921 | |
1922 | n_div1 = isl_aff_dim(aff: aff1, type: isl_dim_div); |
1923 | n_div2 = isl_aff_dim(aff: aff2, type: isl_dim_div); |
1924 | if (n_div1 < 0 || n_div2 < 0) |
1925 | goto error; |
1926 | if (n_div1 == 0 && n_div2 == 0) |
1927 | return add_expanded(aff1, aff2); |
1928 | |
1929 | exp1 = isl_alloc_array(ctx, int, n_div1); |
1930 | exp2 = isl_alloc_array(ctx, int, n_div2); |
1931 | if ((n_div1 && !exp1) || (n_div2 && !exp2)) |
1932 | goto error; |
1933 | |
1934 | div = isl_merge_divs(div1: aff1->ls->div, div2: aff2->ls->div, exp1, exp2); |
1935 | aff1 = isl_aff_expand_divs(aff: aff1, div: isl_mat_copy(mat: div), exp: exp1); |
1936 | aff2 = isl_aff_expand_divs(aff: aff2, div, exp: exp2); |
1937 | free(ptr: exp1); |
1938 | free(ptr: exp2); |
1939 | |
1940 | return add_expanded(aff1, aff2); |
1941 | error: |
1942 | free(ptr: exp1); |
1943 | free(ptr: exp2); |
1944 | isl_aff_free(aff: aff1); |
1945 | isl_aff_free(aff: aff2); |
1946 | return NULL; |
1947 | } |
1948 | |
1949 | __isl_give isl_aff *isl_aff_sub(__isl_take isl_aff *aff1, |
1950 | __isl_take isl_aff *aff2) |
1951 | { |
1952 | return isl_aff_add(aff1, aff2: isl_aff_neg(aff: aff2)); |
1953 | } |
1954 | |
1955 | /* Return the result of scaling "aff" by a factor of "f". |
1956 | * |
1957 | * As a special case, f * NaN = NaN. |
1958 | */ |
1959 | __isl_give isl_aff *isl_aff_scale(__isl_take isl_aff *aff, isl_int f) |
1960 | { |
1961 | isl_int gcd; |
1962 | |
1963 | if (!aff) |
1964 | return NULL; |
1965 | if (isl_aff_is_nan(aff)) |
1966 | return aff; |
1967 | |
1968 | if (isl_int_is_one(f)) |
1969 | return aff; |
1970 | |
1971 | aff = isl_aff_cow(aff); |
1972 | if (!aff) |
1973 | return NULL; |
1974 | aff->v = isl_vec_cow(vec: aff->v); |
1975 | if (!aff->v) |
1976 | return isl_aff_free(aff); |
1977 | |
1978 | if (isl_int_is_pos(f) && isl_int_is_divisible_by(aff->v->el[0], f)) { |
1979 | isl_int_divexact(aff->v->el[0], aff->v->el[0], f); |
1980 | return aff; |
1981 | } |
1982 | |
1983 | isl_int_init(gcd); |
1984 | isl_int_gcd(gcd, aff->v->el[0], f); |
1985 | isl_int_divexact(aff->v->el[0], aff->v->el[0], gcd); |
1986 | isl_int_divexact(gcd, f, gcd); |
1987 | isl_seq_scale(dst: aff->v->el + 1, src: aff->v->el + 1, f: gcd, len: aff->v->size - 1); |
1988 | isl_int_clear(gcd); |
1989 | |
1990 | return aff; |
1991 | } |
1992 | |
1993 | /* Multiple "aff" by "v". |
1994 | */ |
1995 | __isl_give isl_aff *isl_aff_scale_val(__isl_take isl_aff *aff, |
1996 | __isl_take isl_val *v) |
1997 | { |
1998 | if (!aff || !v) |
1999 | goto error; |
2000 | |
2001 | if (isl_val_is_one(v)) { |
2002 | isl_val_free(v); |
2003 | return aff; |
2004 | } |
2005 | |
2006 | if (!isl_val_is_rat(v)) |
2007 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
2008 | "expecting rational factor" , goto error); |
2009 | |
2010 | aff = isl_aff_scale(aff, f: v->n); |
2011 | aff = isl_aff_scale_down(aff, f: v->d); |
2012 | |
2013 | isl_val_free(v); |
2014 | return aff; |
2015 | error: |
2016 | isl_aff_free(aff); |
2017 | isl_val_free(v); |
2018 | return NULL; |
2019 | } |
2020 | |
2021 | /* Return the result of scaling "aff" down by a factor of "f". |
2022 | * |
2023 | * As a special case, NaN/f = NaN. |
2024 | */ |
2025 | __isl_give isl_aff *isl_aff_scale_down(__isl_take isl_aff *aff, isl_int f) |
2026 | { |
2027 | isl_int gcd; |
2028 | |
2029 | if (!aff) |
2030 | return NULL; |
2031 | if (isl_aff_is_nan(aff)) |
2032 | return aff; |
2033 | |
2034 | if (isl_int_is_one(f)) |
2035 | return aff; |
2036 | |
2037 | aff = isl_aff_cow(aff); |
2038 | if (!aff) |
2039 | return NULL; |
2040 | |
2041 | if (isl_int_is_zero(f)) |
2042 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
2043 | "cannot scale down by zero" , return isl_aff_free(aff)); |
2044 | |
2045 | aff->v = isl_vec_cow(vec: aff->v); |
2046 | if (!aff->v) |
2047 | return isl_aff_free(aff); |
2048 | |
2049 | isl_int_init(gcd); |
2050 | isl_seq_gcd(p: aff->v->el + 1, len: aff->v->size - 1, gcd: &gcd); |
2051 | isl_int_gcd(gcd, gcd, f); |
2052 | isl_seq_scale_down(dst: aff->v->el + 1, src: aff->v->el + 1, f: gcd, len: aff->v->size - 1); |
2053 | isl_int_divexact(gcd, f, gcd); |
2054 | isl_int_mul(aff->v->el[0], aff->v->el[0], gcd); |
2055 | isl_int_clear(gcd); |
2056 | |
2057 | return aff; |
2058 | } |
2059 | |
2060 | /* Divide "aff" by "v". |
2061 | */ |
2062 | __isl_give isl_aff *isl_aff_scale_down_val(__isl_take isl_aff *aff, |
2063 | __isl_take isl_val *v) |
2064 | { |
2065 | if (!aff || !v) |
2066 | goto error; |
2067 | |
2068 | if (isl_val_is_one(v)) { |
2069 | isl_val_free(v); |
2070 | return aff; |
2071 | } |
2072 | |
2073 | if (!isl_val_is_rat(v)) |
2074 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
2075 | "expecting rational factor" , goto error); |
2076 | if (!isl_val_is_pos(v)) |
2077 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
2078 | "factor needs to be positive" , goto error); |
2079 | |
2080 | aff = isl_aff_scale(aff, f: v->d); |
2081 | aff = isl_aff_scale_down(aff, f: v->n); |
2082 | |
2083 | isl_val_free(v); |
2084 | return aff; |
2085 | error: |
2086 | isl_aff_free(aff); |
2087 | isl_val_free(v); |
2088 | return NULL; |
2089 | } |
2090 | |
2091 | __isl_give isl_aff *isl_aff_scale_down_ui(__isl_take isl_aff *aff, unsigned f) |
2092 | { |
2093 | isl_int v; |
2094 | |
2095 | if (f == 1) |
2096 | return aff; |
2097 | |
2098 | isl_int_init(v); |
2099 | isl_int_set_ui(v, f); |
2100 | aff = isl_aff_scale_down(aff, f: v); |
2101 | isl_int_clear(v); |
2102 | |
2103 | return aff; |
2104 | } |
2105 | |
2106 | __isl_give isl_aff *isl_aff_set_dim_name(__isl_take isl_aff *aff, |
2107 | enum isl_dim_type type, unsigned pos, const char *s) |
2108 | { |
2109 | aff = isl_aff_cow(aff); |
2110 | if (!aff) |
2111 | return NULL; |
2112 | if (type == isl_dim_out) |
2113 | isl_die(aff->v->ctx, isl_error_invalid, |
2114 | "cannot set name of output/set dimension" , |
2115 | return isl_aff_free(aff)); |
2116 | if (type == isl_dim_in) |
2117 | type = isl_dim_set; |
2118 | aff->ls = isl_local_space_set_dim_name(ls: aff->ls, type, pos, s); |
2119 | if (!aff->ls) |
2120 | return isl_aff_free(aff); |
2121 | |
2122 | return aff; |
2123 | } |
2124 | |
2125 | __isl_give isl_aff *isl_aff_set_dim_id(__isl_take isl_aff *aff, |
2126 | enum isl_dim_type type, unsigned pos, __isl_take isl_id *id) |
2127 | { |
2128 | aff = isl_aff_cow(aff); |
2129 | if (!aff) |
2130 | goto error; |
2131 | if (type == isl_dim_out) |
2132 | isl_die(aff->v->ctx, isl_error_invalid, |
2133 | "cannot set name of output/set dimension" , |
2134 | goto error); |
2135 | if (type == isl_dim_in) |
2136 | type = isl_dim_set; |
2137 | aff->ls = isl_local_space_set_dim_id(ls: aff->ls, type, pos, id); |
2138 | if (!aff->ls) |
2139 | return isl_aff_free(aff); |
2140 | |
2141 | return aff; |
2142 | error: |
2143 | isl_id_free(id); |
2144 | isl_aff_free(aff); |
2145 | return NULL; |
2146 | } |
2147 | |
2148 | /* Replace the identifier of the input tuple of "aff" by "id". |
2149 | * type is currently required to be equal to isl_dim_in |
2150 | */ |
2151 | __isl_give isl_aff *isl_aff_set_tuple_id(__isl_take isl_aff *aff, |
2152 | enum isl_dim_type type, __isl_take isl_id *id) |
2153 | { |
2154 | aff = isl_aff_cow(aff); |
2155 | if (!aff) |
2156 | goto error; |
2157 | if (type != isl_dim_in) |
2158 | isl_die(aff->v->ctx, isl_error_invalid, |
2159 | "cannot only set id of input tuple" , goto error); |
2160 | aff->ls = isl_local_space_set_tuple_id(ls: aff->ls, type: isl_dim_set, id); |
2161 | if (!aff->ls) |
2162 | return isl_aff_free(aff); |
2163 | |
2164 | return aff; |
2165 | error: |
2166 | isl_id_free(id); |
2167 | isl_aff_free(aff); |
2168 | return NULL; |
2169 | } |
2170 | |
2171 | /* Exploit the equalities in "eq" to simplify the affine expression |
2172 | * and the expressions of the integer divisions in the local space. |
2173 | * The integer divisions in this local space are assumed to appear |
2174 | * as regular dimensions in "eq". |
2175 | */ |
2176 | static __isl_give isl_aff *isl_aff_substitute_equalities_lifted( |
2177 | __isl_take isl_aff *aff, __isl_take isl_basic_set *eq) |
2178 | { |
2179 | int i, j; |
2180 | unsigned o_div; |
2181 | unsigned n_div; |
2182 | |
2183 | if (!eq) |
2184 | goto error; |
2185 | if (eq->n_eq == 0) { |
2186 | isl_basic_set_free(bset: eq); |
2187 | return aff; |
2188 | } |
2189 | |
2190 | aff = isl_aff_cow(aff); |
2191 | if (!aff) |
2192 | goto error; |
2193 | |
2194 | aff->ls = isl_local_space_substitute_equalities(ls: aff->ls, |
2195 | eq: isl_basic_set_copy(bset: eq)); |
2196 | aff->v = isl_vec_cow(vec: aff->v); |
2197 | if (!aff->ls || !aff->v) |
2198 | goto error; |
2199 | |
2200 | o_div = isl_basic_set_offset(bset: eq, type: isl_dim_div); |
2201 | n_div = eq->n_div; |
2202 | for (i = 0; i < eq->n_eq; ++i) { |
2203 | j = isl_seq_last_non_zero(p: eq->eq[i], len: o_div + n_div); |
2204 | if (j < 0 || j == 0 || j >= o_div) |
2205 | continue; |
2206 | |
2207 | isl_seq_elim(dst: aff->v->el + 1, src: eq->eq[i], pos: j, len: o_div, |
2208 | m: &aff->v->el[0]); |
2209 | } |
2210 | |
2211 | isl_basic_set_free(bset: eq); |
2212 | aff = isl_aff_normalize(aff); |
2213 | return aff; |
2214 | error: |
2215 | isl_basic_set_free(bset: eq); |
2216 | isl_aff_free(aff); |
2217 | return NULL; |
2218 | } |
2219 | |
2220 | /* Exploit the equalities in "eq" to simplify the affine expression |
2221 | * and the expressions of the integer divisions in the local space. |
2222 | */ |
2223 | __isl_give isl_aff *isl_aff_substitute_equalities(__isl_take isl_aff *aff, |
2224 | __isl_take isl_basic_set *eq) |
2225 | { |
2226 | isl_size n_div; |
2227 | |
2228 | n_div = isl_aff_domain_dim(aff, type: isl_dim_div); |
2229 | if (n_div < 0) |
2230 | goto error; |
2231 | if (n_div > 0) |
2232 | eq = isl_basic_set_add_dims(bset: eq, type: isl_dim_set, n: n_div); |
2233 | return isl_aff_substitute_equalities_lifted(aff, eq); |
2234 | error: |
2235 | isl_basic_set_free(bset: eq); |
2236 | isl_aff_free(aff); |
2237 | return NULL; |
2238 | } |
2239 | |
2240 | /* Look for equalities among the variables shared by context and aff |
2241 | * and the integer divisions of aff, if any. |
2242 | * The equalities are then used to eliminate coefficients and/or integer |
2243 | * divisions from aff. |
2244 | */ |
2245 | __isl_give isl_aff *isl_aff_gist(__isl_take isl_aff *aff, |
2246 | __isl_take isl_set *context) |
2247 | { |
2248 | isl_local_space *ls; |
2249 | isl_basic_set *hull; |
2250 | |
2251 | ls = isl_aff_get_domain_local_space(aff); |
2252 | context = isl_local_space_lift_set(ls, set: context); |
2253 | |
2254 | hull = isl_set_affine_hull(set: context); |
2255 | return isl_aff_substitute_equalities_lifted(aff, eq: hull); |
2256 | } |
2257 | |
2258 | __isl_give isl_aff *isl_aff_gist_params(__isl_take isl_aff *aff, |
2259 | __isl_take isl_set *context) |
2260 | { |
2261 | isl_set *dom_context = isl_set_universe(space: isl_aff_get_domain_space(aff)); |
2262 | dom_context = isl_set_intersect_params(set: dom_context, params: context); |
2263 | return isl_aff_gist(aff, context: dom_context); |
2264 | } |
2265 | |
2266 | /* Return a basic set containing those elements in the space |
2267 | * of aff where it is positive. "rational" should not be set. |
2268 | * |
2269 | * If "aff" is NaN, then it is not positive. |
2270 | */ |
2271 | static __isl_give isl_basic_set *aff_pos_basic_set(__isl_take isl_aff *aff, |
2272 | int rational, void *user) |
2273 | { |
2274 | isl_constraint *ineq; |
2275 | isl_basic_set *bset; |
2276 | isl_val *c; |
2277 | |
2278 | if (!aff) |
2279 | return NULL; |
2280 | if (isl_aff_is_nan(aff)) { |
2281 | isl_space *space = isl_aff_get_domain_space(aff); |
2282 | isl_aff_free(aff); |
2283 | return isl_basic_set_empty(space); |
2284 | } |
2285 | if (rational) |
2286 | isl_die(isl_aff_get_ctx(aff), isl_error_unsupported, |
2287 | "rational sets not supported" , goto error); |
2288 | |
2289 | ineq = isl_inequality_from_aff(aff); |
2290 | c = isl_constraint_get_constant_val(constraint: ineq); |
2291 | c = isl_val_sub_ui(v1: c, v2: 1); |
2292 | ineq = isl_constraint_set_constant_val(constraint: ineq, v: c); |
2293 | |
2294 | bset = isl_basic_set_from_constraint(constraint: ineq); |
2295 | bset = isl_basic_set_simplify(bset); |
2296 | return bset; |
2297 | error: |
2298 | isl_aff_free(aff); |
2299 | return NULL; |
2300 | } |
2301 | |
2302 | /* Return a basic set containing those elements in the space |
2303 | * of aff where it is non-negative. |
2304 | * If "rational" is set, then return a rational basic set. |
2305 | * |
2306 | * If "aff" is NaN, then it is not non-negative (it's not negative either). |
2307 | */ |
2308 | static __isl_give isl_basic_set *aff_nonneg_basic_set( |
2309 | __isl_take isl_aff *aff, int rational, void *user) |
2310 | { |
2311 | isl_constraint *ineq; |
2312 | isl_basic_set *bset; |
2313 | |
2314 | if (!aff) |
2315 | return NULL; |
2316 | if (isl_aff_is_nan(aff)) { |
2317 | isl_space *space = isl_aff_get_domain_space(aff); |
2318 | isl_aff_free(aff); |
2319 | return isl_basic_set_empty(space); |
2320 | } |
2321 | |
2322 | ineq = isl_inequality_from_aff(aff); |
2323 | |
2324 | bset = isl_basic_set_from_constraint(constraint: ineq); |
2325 | if (rational) |
2326 | bset = isl_basic_set_set_rational(bset); |
2327 | bset = isl_basic_set_simplify(bset); |
2328 | return bset; |
2329 | } |
2330 | |
2331 | /* Return a basic set containing those elements in the space |
2332 | * of aff where it is non-negative. |
2333 | */ |
2334 | __isl_give isl_basic_set *isl_aff_nonneg_basic_set(__isl_take isl_aff *aff) |
2335 | { |
2336 | return aff_nonneg_basic_set(aff, rational: 0, NULL); |
2337 | } |
2338 | |
2339 | /* Return a basic set containing those elements in the domain space |
2340 | * of "aff" where it is positive. |
2341 | */ |
2342 | __isl_give isl_basic_set *isl_aff_pos_basic_set(__isl_take isl_aff *aff) |
2343 | { |
2344 | aff = isl_aff_add_constant_num_si(aff, v: -1); |
2345 | return isl_aff_nonneg_basic_set(aff); |
2346 | } |
2347 | |
2348 | /* Return a basic set containing those elements in the domain space |
2349 | * of aff where it is negative. |
2350 | */ |
2351 | __isl_give isl_basic_set *isl_aff_neg_basic_set(__isl_take isl_aff *aff) |
2352 | { |
2353 | aff = isl_aff_neg(aff); |
2354 | return isl_aff_pos_basic_set(aff); |
2355 | } |
2356 | |
2357 | /* Return a basic set containing those elements in the space |
2358 | * of aff where it is zero. |
2359 | * If "rational" is set, then return a rational basic set. |
2360 | * |
2361 | * If "aff" is NaN, then it is not zero. |
2362 | */ |
2363 | static __isl_give isl_basic_set *aff_zero_basic_set(__isl_take isl_aff *aff, |
2364 | int rational, void *user) |
2365 | { |
2366 | isl_constraint *ineq; |
2367 | isl_basic_set *bset; |
2368 | |
2369 | if (!aff) |
2370 | return NULL; |
2371 | if (isl_aff_is_nan(aff)) { |
2372 | isl_space *space = isl_aff_get_domain_space(aff); |
2373 | isl_aff_free(aff); |
2374 | return isl_basic_set_empty(space); |
2375 | } |
2376 | |
2377 | ineq = isl_equality_from_aff(aff); |
2378 | |
2379 | bset = isl_basic_set_from_constraint(constraint: ineq); |
2380 | if (rational) |
2381 | bset = isl_basic_set_set_rational(bset); |
2382 | bset = isl_basic_set_simplify(bset); |
2383 | return bset; |
2384 | } |
2385 | |
2386 | /* Return a basic set containing those elements in the space |
2387 | * of aff where it is zero. |
2388 | */ |
2389 | __isl_give isl_basic_set *isl_aff_zero_basic_set(__isl_take isl_aff *aff) |
2390 | { |
2391 | return aff_zero_basic_set(aff, rational: 0, NULL); |
2392 | } |
2393 | |
2394 | /* Return a basic set containing those elements in the shared space |
2395 | * of aff1 and aff2 where aff1 is greater than or equal to aff2. |
2396 | */ |
2397 | __isl_give isl_basic_set *isl_aff_ge_basic_set(__isl_take isl_aff *aff1, |
2398 | __isl_take isl_aff *aff2) |
2399 | { |
2400 | aff1 = isl_aff_sub(aff1, aff2); |
2401 | |
2402 | return isl_aff_nonneg_basic_set(aff: aff1); |
2403 | } |
2404 | |
2405 | /* Return a basic set containing those elements in the shared domain space |
2406 | * of "aff1" and "aff2" where "aff1" is greater than "aff2". |
2407 | */ |
2408 | __isl_give isl_basic_set *isl_aff_gt_basic_set(__isl_take isl_aff *aff1, |
2409 | __isl_take isl_aff *aff2) |
2410 | { |
2411 | aff1 = isl_aff_sub(aff1, aff2); |
2412 | |
2413 | return isl_aff_pos_basic_set(aff: aff1); |
2414 | } |
2415 | |
2416 | /* Return a set containing those elements in the shared space |
2417 | * of aff1 and aff2 where aff1 is greater than or equal to aff2. |
2418 | */ |
2419 | __isl_give isl_set *isl_aff_ge_set(__isl_take isl_aff *aff1, |
2420 | __isl_take isl_aff *aff2) |
2421 | { |
2422 | return isl_set_from_basic_set(bset: isl_aff_ge_basic_set(aff1, aff2)); |
2423 | } |
2424 | |
2425 | /* Return a set containing those elements in the shared domain space |
2426 | * of aff1 and aff2 where aff1 is greater than aff2. |
2427 | * |
2428 | * If either of the two inputs is NaN, then the result is empty, |
2429 | * as comparisons with NaN always return false. |
2430 | */ |
2431 | __isl_give isl_set *isl_aff_gt_set(__isl_take isl_aff *aff1, |
2432 | __isl_take isl_aff *aff2) |
2433 | { |
2434 | return isl_set_from_basic_set(bset: isl_aff_gt_basic_set(aff1, aff2)); |
2435 | } |
2436 | |
2437 | /* Return a basic set containing those elements in the shared space |
2438 | * of aff1 and aff2 where aff1 is smaller than or equal to aff2. |
2439 | */ |
2440 | __isl_give isl_basic_set *isl_aff_le_basic_set(__isl_take isl_aff *aff1, |
2441 | __isl_take isl_aff *aff2) |
2442 | { |
2443 | return isl_aff_ge_basic_set(aff1: aff2, aff2: aff1); |
2444 | } |
2445 | |
2446 | /* Return a basic set containing those elements in the shared domain space |
2447 | * of "aff1" and "aff2" where "aff1" is smaller than "aff2". |
2448 | */ |
2449 | __isl_give isl_basic_set *isl_aff_lt_basic_set(__isl_take isl_aff *aff1, |
2450 | __isl_take isl_aff *aff2) |
2451 | { |
2452 | return isl_aff_gt_basic_set(aff1: aff2, aff2: aff1); |
2453 | } |
2454 | |
2455 | /* Return a set containing those elements in the shared space |
2456 | * of aff1 and aff2 where aff1 is smaller than or equal to aff2. |
2457 | */ |
2458 | __isl_give isl_set *isl_aff_le_set(__isl_take isl_aff *aff1, |
2459 | __isl_take isl_aff *aff2) |
2460 | { |
2461 | return isl_aff_ge_set(aff1: aff2, aff2: aff1); |
2462 | } |
2463 | |
2464 | /* Return a set containing those elements in the shared domain space |
2465 | * of "aff1" and "aff2" where "aff1" is smaller than "aff2". |
2466 | */ |
2467 | __isl_give isl_set *isl_aff_lt_set(__isl_take isl_aff *aff1, |
2468 | __isl_take isl_aff *aff2) |
2469 | { |
2470 | return isl_set_from_basic_set(bset: isl_aff_lt_basic_set(aff1, aff2)); |
2471 | } |
2472 | |
2473 | /* Return a basic set containing those elements in the shared space |
2474 | * of aff1 and aff2 where aff1 and aff2 are equal. |
2475 | */ |
2476 | __isl_give isl_basic_set *isl_aff_eq_basic_set(__isl_take isl_aff *aff1, |
2477 | __isl_take isl_aff *aff2) |
2478 | { |
2479 | aff1 = isl_aff_sub(aff1, aff2); |
2480 | |
2481 | return isl_aff_zero_basic_set(aff: aff1); |
2482 | } |
2483 | |
2484 | /* Return a set containing those elements in the shared space |
2485 | * of aff1 and aff2 where aff1 and aff2 are equal. |
2486 | */ |
2487 | __isl_give isl_set *isl_aff_eq_set(__isl_take isl_aff *aff1, |
2488 | __isl_take isl_aff *aff2) |
2489 | { |
2490 | return isl_set_from_basic_set(bset: isl_aff_eq_basic_set(aff1, aff2)); |
2491 | } |
2492 | |
2493 | /* Return a set containing those elements in the shared domain space |
2494 | * of aff1 and aff2 where aff1 and aff2 are not equal. |
2495 | * |
2496 | * If either of the two inputs is NaN, then the result is empty, |
2497 | * as comparisons with NaN always return false. |
2498 | */ |
2499 | __isl_give isl_set *isl_aff_ne_set(__isl_take isl_aff *aff1, |
2500 | __isl_take isl_aff *aff2) |
2501 | { |
2502 | isl_set *set_lt, *set_gt; |
2503 | |
2504 | set_lt = isl_aff_lt_set(aff1: isl_aff_copy(aff: aff1), |
2505 | aff2: isl_aff_copy(aff: aff2)); |
2506 | set_gt = isl_aff_gt_set(aff1, aff2); |
2507 | return isl_set_union_disjoint(set1: set_lt, set2: set_gt); |
2508 | } |
2509 | |
2510 | __isl_give isl_aff *isl_aff_add_on_domain(__isl_keep isl_set *dom, |
2511 | __isl_take isl_aff *aff1, __isl_take isl_aff *aff2) |
2512 | { |
2513 | aff1 = isl_aff_add(aff1, aff2); |
2514 | aff1 = isl_aff_gist(aff: aff1, context: isl_set_copy(set: dom)); |
2515 | return aff1; |
2516 | } |
2517 | |
2518 | isl_bool isl_aff_is_empty(__isl_keep isl_aff *aff) |
2519 | { |
2520 | if (!aff) |
2521 | return isl_bool_error; |
2522 | |
2523 | return isl_bool_false; |
2524 | } |
2525 | |
2526 | #undef TYPE |
2527 | #define TYPE isl_aff |
2528 | static |
2529 | #include "check_type_range_templ.c" |
2530 | |
2531 | /* Check whether the given affine expression has non-zero coefficient |
2532 | * for any dimension in the given range or if any of these dimensions |
2533 | * appear with non-zero coefficients in any of the integer divisions |
2534 | * involved in the affine expression. |
2535 | */ |
2536 | isl_bool isl_aff_involves_dims(__isl_keep isl_aff *aff, |
2537 | enum isl_dim_type type, unsigned first, unsigned n) |
2538 | { |
2539 | int i; |
2540 | int *active = NULL; |
2541 | isl_bool involves = isl_bool_false; |
2542 | |
2543 | if (!aff) |
2544 | return isl_bool_error; |
2545 | if (n == 0) |
2546 | return isl_bool_false; |
2547 | if (isl_aff_check_range(obj: aff, type, first, n) < 0) |
2548 | return isl_bool_error; |
2549 | |
2550 | active = isl_local_space_get_active(ls: aff->ls, l: aff->v->el + 2); |
2551 | if (!active) |
2552 | goto error; |
2553 | |
2554 | first += isl_local_space_offset(ls: aff->ls, type) - 1; |
2555 | for (i = 0; i < n; ++i) |
2556 | if (active[first + i]) { |
2557 | involves = isl_bool_true; |
2558 | break; |
2559 | } |
2560 | |
2561 | free(ptr: active); |
2562 | |
2563 | return involves; |
2564 | error: |
2565 | free(ptr: active); |
2566 | return isl_bool_error; |
2567 | } |
2568 | |
2569 | /* Does "aff" involve any local variables, i.e., integer divisions? |
2570 | */ |
2571 | isl_bool isl_aff_involves_locals(__isl_keep isl_aff *aff) |
2572 | { |
2573 | isl_size n; |
2574 | |
2575 | n = isl_aff_dim(aff, type: isl_dim_div); |
2576 | if (n < 0) |
2577 | return isl_bool_error; |
2578 | return isl_bool_ok(b: n > 0); |
2579 | } |
2580 | |
2581 | __isl_give isl_aff *isl_aff_drop_dims(__isl_take isl_aff *aff, |
2582 | enum isl_dim_type type, unsigned first, unsigned n) |
2583 | { |
2584 | if (!aff) |
2585 | return NULL; |
2586 | if (type == isl_dim_out) |
2587 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
2588 | "cannot drop output/set dimension" , |
2589 | return isl_aff_free(aff)); |
2590 | if (type == isl_dim_in) |
2591 | type = isl_dim_set; |
2592 | if (n == 0 && !isl_local_space_is_named_or_nested(ls: aff->ls, type)) |
2593 | return aff; |
2594 | |
2595 | if (isl_local_space_check_range(ls: aff->ls, type, first, n) < 0) |
2596 | return isl_aff_free(aff); |
2597 | |
2598 | aff = isl_aff_cow(aff); |
2599 | if (!aff) |
2600 | return NULL; |
2601 | |
2602 | aff->ls = isl_local_space_drop_dims(ls: aff->ls, type, first, n); |
2603 | if (!aff->ls) |
2604 | return isl_aff_free(aff); |
2605 | |
2606 | first += 1 + isl_local_space_offset(ls: aff->ls, type); |
2607 | aff->v = isl_vec_drop_els(vec: aff->v, pos: first, n); |
2608 | if (!aff->v) |
2609 | return isl_aff_free(aff); |
2610 | |
2611 | return aff; |
2612 | } |
2613 | |
2614 | /* Is the domain of "aff" a product? |
2615 | */ |
2616 | static isl_bool isl_aff_domain_is_product(__isl_keep isl_aff *aff) |
2617 | { |
2618 | return isl_space_is_product(space: isl_aff_peek_domain_space(aff)); |
2619 | } |
2620 | |
2621 | #undef TYPE |
2622 | #define TYPE isl_aff |
2623 | #include <isl_domain_factor_templ.c> |
2624 | |
2625 | /* Project the domain of the affine expression onto its parameter space. |
2626 | * The affine expression may not involve any of the domain dimensions. |
2627 | */ |
2628 | __isl_give isl_aff *isl_aff_project_domain_on_params(__isl_take isl_aff *aff) |
2629 | { |
2630 | isl_space *space; |
2631 | isl_size n; |
2632 | |
2633 | n = isl_aff_dim(aff, type: isl_dim_in); |
2634 | if (n < 0) |
2635 | return isl_aff_free(aff); |
2636 | aff = isl_aff_drop_domain(obj: aff, first: 0, n); |
2637 | space = isl_aff_get_domain_space(aff); |
2638 | space = isl_space_params(space); |
2639 | aff = isl_aff_reset_domain_space(aff, space); |
2640 | return aff; |
2641 | } |
2642 | |
2643 | /* Convert an affine expression defined over a parameter domain |
2644 | * into one that is defined over a zero-dimensional set. |
2645 | */ |
2646 | __isl_give isl_aff *isl_aff_from_range(__isl_take isl_aff *aff) |
2647 | { |
2648 | isl_local_space *ls; |
2649 | |
2650 | ls = isl_aff_take_domain_local_space(aff); |
2651 | ls = isl_local_space_set_from_params(ls); |
2652 | aff = isl_aff_restore_domain_local_space(aff, ls); |
2653 | |
2654 | return aff; |
2655 | } |
2656 | |
2657 | __isl_give isl_aff *isl_aff_insert_dims(__isl_take isl_aff *aff, |
2658 | enum isl_dim_type type, unsigned first, unsigned n) |
2659 | { |
2660 | if (!aff) |
2661 | return NULL; |
2662 | if (type == isl_dim_out) |
2663 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
2664 | "cannot insert output/set dimensions" , |
2665 | return isl_aff_free(aff)); |
2666 | if (type == isl_dim_in) |
2667 | type = isl_dim_set; |
2668 | if (n == 0 && !isl_local_space_is_named_or_nested(ls: aff->ls, type)) |
2669 | return aff; |
2670 | |
2671 | if (isl_local_space_check_range(ls: aff->ls, type, first, n: 0) < 0) |
2672 | return isl_aff_free(aff); |
2673 | |
2674 | aff = isl_aff_cow(aff); |
2675 | if (!aff) |
2676 | return NULL; |
2677 | |
2678 | aff->ls = isl_local_space_insert_dims(ls: aff->ls, type, first, n); |
2679 | if (!aff->ls) |
2680 | return isl_aff_free(aff); |
2681 | |
2682 | first += 1 + isl_local_space_offset(ls: aff->ls, type); |
2683 | aff->v = isl_vec_insert_zero_els(vec: aff->v, pos: first, n); |
2684 | if (!aff->v) |
2685 | return isl_aff_free(aff); |
2686 | |
2687 | return aff; |
2688 | } |
2689 | |
2690 | __isl_give isl_aff *isl_aff_add_dims(__isl_take isl_aff *aff, |
2691 | enum isl_dim_type type, unsigned n) |
2692 | { |
2693 | isl_size pos; |
2694 | |
2695 | pos = isl_aff_dim(aff, type); |
2696 | if (pos < 0) |
2697 | return isl_aff_free(aff); |
2698 | |
2699 | return isl_aff_insert_dims(aff, type, first: pos, n); |
2700 | } |
2701 | |
2702 | /* Move the "n" dimensions of "src_type" starting at "src_pos" of "aff" |
2703 | * to dimensions of "dst_type" at "dst_pos". |
2704 | * |
2705 | * We only support moving input dimensions to parameters and vice versa. |
2706 | */ |
2707 | __isl_give isl_aff *isl_aff_move_dims(__isl_take isl_aff *aff, |
2708 | enum isl_dim_type dst_type, unsigned dst_pos, |
2709 | enum isl_dim_type src_type, unsigned src_pos, unsigned n) |
2710 | { |
2711 | unsigned g_dst_pos; |
2712 | unsigned g_src_pos; |
2713 | isl_size src_off, dst_off; |
2714 | |
2715 | if (!aff) |
2716 | return NULL; |
2717 | if (n == 0 && |
2718 | !isl_local_space_is_named_or_nested(ls: aff->ls, type: src_type) && |
2719 | !isl_local_space_is_named_or_nested(ls: aff->ls, type: dst_type)) |
2720 | return aff; |
2721 | |
2722 | if (dst_type == isl_dim_out || src_type == isl_dim_out) |
2723 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
2724 | "cannot move output/set dimension" , |
2725 | return isl_aff_free(aff)); |
2726 | if (dst_type == isl_dim_div || src_type == isl_dim_div) |
2727 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
2728 | "cannot move divs" , return isl_aff_free(aff)); |
2729 | if (dst_type == isl_dim_in) |
2730 | dst_type = isl_dim_set; |
2731 | if (src_type == isl_dim_in) |
2732 | src_type = isl_dim_set; |
2733 | |
2734 | if (isl_local_space_check_range(ls: aff->ls, type: src_type, first: src_pos, n) < 0) |
2735 | return isl_aff_free(aff); |
2736 | if (dst_type == src_type) |
2737 | isl_die(isl_aff_get_ctx(aff), isl_error_unsupported, |
2738 | "moving dims within the same type not supported" , |
2739 | return isl_aff_free(aff)); |
2740 | |
2741 | aff = isl_aff_cow(aff); |
2742 | src_off = isl_aff_domain_offset(aff, type: src_type); |
2743 | dst_off = isl_aff_domain_offset(aff, type: dst_type); |
2744 | if (src_off < 0 || dst_off < 0) |
2745 | return isl_aff_free(aff); |
2746 | |
2747 | g_src_pos = 1 + src_off + src_pos; |
2748 | g_dst_pos = 1 + dst_off + dst_pos; |
2749 | if (dst_type > src_type) |
2750 | g_dst_pos -= n; |
2751 | |
2752 | aff->v = isl_vec_move_els(vec: aff->v, dst_col: g_dst_pos, src_col: g_src_pos, n); |
2753 | aff->ls = isl_local_space_move_dims(ls: aff->ls, dst_type, dst_pos, |
2754 | src_type, src_pos, n); |
2755 | if (!aff->v || !aff->ls) |
2756 | return isl_aff_free(aff); |
2757 | |
2758 | aff = sort_divs(aff); |
2759 | |
2760 | return aff; |
2761 | } |
2762 | |
2763 | /* Return a zero isl_aff in the given space. |
2764 | * |
2765 | * This is a helper function for isl_pw_*_as_* that ensures a uniform |
2766 | * interface over all piecewise types. |
2767 | */ |
2768 | static __isl_give isl_aff *isl_aff_zero_in_space(__isl_take isl_space *space) |
2769 | { |
2770 | isl_local_space *ls; |
2771 | |
2772 | ls = isl_local_space_from_space(space: isl_space_domain(space)); |
2773 | return isl_aff_zero_on_domain(ls); |
2774 | } |
2775 | |
2776 | #define isl_aff_involves_nan isl_aff_is_nan |
2777 | |
2778 | #undef PW |
2779 | #define PW isl_pw_aff |
2780 | #undef BASE |
2781 | #define BASE aff |
2782 | #undef EL_IS_ZERO |
2783 | #define EL_IS_ZERO is_empty |
2784 | #undef ZERO |
2785 | #define ZERO empty |
2786 | #undef IS_ZERO |
2787 | #define IS_ZERO is_empty |
2788 | #undef FIELD |
2789 | #define FIELD aff |
2790 | #undef DEFAULT_IS_ZERO |
2791 | #define DEFAULT_IS_ZERO 0 |
2792 | |
2793 | #include <isl_pw_templ.c> |
2794 | #include <isl_pw_un_op_templ.c> |
2795 | #include <isl_pw_add_constant_val_templ.c> |
2796 | #include <isl_pw_add_disjoint_templ.c> |
2797 | #include <isl_pw_bind_domain_templ.c> |
2798 | #include <isl_pw_eval.c> |
2799 | #include <isl_pw_hash.c> |
2800 | #include <isl_pw_fix_templ.c> |
2801 | #include <isl_pw_from_range_templ.c> |
2802 | #include <isl_pw_insert_dims_templ.c> |
2803 | #include <isl_pw_insert_domain_templ.c> |
2804 | #include <isl_pw_move_dims_templ.c> |
2805 | #include <isl_pw_neg_templ.c> |
2806 | #include <isl_pw_pullback_templ.c> |
2807 | #include <isl_pw_scale_templ.c> |
2808 | #include <isl_pw_sub_templ.c> |
2809 | #include <isl_pw_union_opt.c> |
2810 | |
2811 | #undef BASE |
2812 | #define BASE pw_aff |
2813 | |
2814 | #include <isl_union_single.c> |
2815 | #include <isl_union_neg.c> |
2816 | #include <isl_union_sub_templ.c> |
2817 | |
2818 | #undef BASE |
2819 | #define BASE aff |
2820 | |
2821 | #include <isl_union_pw_templ.c> |
2822 | |
2823 | /* Compute a piecewise quasi-affine expression with a domain that |
2824 | * is the union of those of pwaff1 and pwaff2 and such that on each |
2825 | * cell, the quasi-affine expression is the maximum of those of pwaff1 |
2826 | * and pwaff2. If only one of pwaff1 or pwaff2 is defined on a given |
2827 | * cell, then the associated expression is the defined one. |
2828 | */ |
2829 | __isl_give isl_pw_aff *isl_pw_aff_union_max(__isl_take isl_pw_aff *pwaff1, |
2830 | __isl_take isl_pw_aff *pwaff2) |
2831 | { |
2832 | isl_pw_aff_align_params_bin(obj1: &pwaff1, obj2: &pwaff2); |
2833 | return isl_pw_aff_union_opt_cmp(pw1: pwaff1, pw2: pwaff2, cmp: &isl_aff_ge_set); |
2834 | } |
2835 | |
2836 | /* Compute a piecewise quasi-affine expression with a domain that |
2837 | * is the union of those of pwaff1 and pwaff2 and such that on each |
2838 | * cell, the quasi-affine expression is the minimum of those of pwaff1 |
2839 | * and pwaff2. If only one of pwaff1 or pwaff2 is defined on a given |
2840 | * cell, then the associated expression is the defined one. |
2841 | */ |
2842 | __isl_give isl_pw_aff *isl_pw_aff_union_min(__isl_take isl_pw_aff *pwaff1, |
2843 | __isl_take isl_pw_aff *pwaff2) |
2844 | { |
2845 | isl_pw_aff_align_params_bin(obj1: &pwaff1, obj2: &pwaff2); |
2846 | return isl_pw_aff_union_opt_cmp(pw1: pwaff1, pw2: pwaff2, cmp: &isl_aff_le_set); |
2847 | } |
2848 | |
2849 | __isl_give isl_pw_aff *isl_pw_aff_union_opt(__isl_take isl_pw_aff *pwaff1, |
2850 | __isl_take isl_pw_aff *pwaff2, int max) |
2851 | { |
2852 | if (max) |
2853 | return isl_pw_aff_union_max(pwaff1, pwaff2); |
2854 | else |
2855 | return isl_pw_aff_union_min(pwaff1, pwaff2); |
2856 | } |
2857 | |
2858 | /* Is the domain of "pa" a product? |
2859 | */ |
2860 | static isl_bool isl_pw_aff_domain_is_product(__isl_keep isl_pw_aff *pa) |
2861 | { |
2862 | return isl_space_domain_is_wrapping(space: isl_pw_aff_peek_space(pw: pa)); |
2863 | } |
2864 | |
2865 | #undef TYPE |
2866 | #define TYPE isl_pw_aff |
2867 | #include <isl_domain_factor_templ.c> |
2868 | |
2869 | /* Return a set containing those elements in the domain |
2870 | * of "pwaff" where it satisfies "fn" (if complement is 0) or |
2871 | * does not satisfy "fn" (if complement is 1). |
2872 | * |
2873 | * The pieces with a NaN never belong to the result since |
2874 | * NaN does not satisfy any property. |
2875 | */ |
2876 | static __isl_give isl_set *pw_aff_locus(__isl_take isl_pw_aff *pwaff, |
2877 | __isl_give isl_basic_set *(*fn)(__isl_take isl_aff *aff, int rational, |
2878 | void *user), |
2879 | int complement, void *user) |
2880 | { |
2881 | int i; |
2882 | isl_set *set; |
2883 | |
2884 | if (!pwaff) |
2885 | return NULL; |
2886 | |
2887 | set = isl_set_empty(space: isl_pw_aff_get_domain_space(pw: pwaff)); |
2888 | |
2889 | for (i = 0; i < pwaff->n; ++i) { |
2890 | isl_basic_set *bset; |
2891 | isl_set *set_i, *locus; |
2892 | isl_bool rational; |
2893 | |
2894 | if (isl_aff_is_nan(aff: pwaff->p[i].aff)) |
2895 | continue; |
2896 | |
2897 | rational = isl_set_has_rational(set: pwaff->p[i].set); |
2898 | bset = fn(isl_aff_copy(aff: pwaff->p[i].aff), rational, user); |
2899 | locus = isl_set_from_basic_set(bset); |
2900 | set_i = isl_set_copy(set: pwaff->p[i].set); |
2901 | if (complement) |
2902 | set_i = isl_set_subtract(set1: set_i, set2: locus); |
2903 | else |
2904 | set_i = isl_set_intersect(set1: set_i, set2: locus); |
2905 | set = isl_set_union_disjoint(set1: set, set2: set_i); |
2906 | } |
2907 | |
2908 | isl_pw_aff_free(pw: pwaff); |
2909 | |
2910 | return set; |
2911 | } |
2912 | |
2913 | /* Return a set containing those elements in the domain |
2914 | * of "pa" where it is positive. |
2915 | */ |
2916 | __isl_give isl_set *isl_pw_aff_pos_set(__isl_take isl_pw_aff *pa) |
2917 | { |
2918 | return pw_aff_locus(pwaff: pa, fn: &aff_pos_basic_set, complement: 0, NULL); |
2919 | } |
2920 | |
2921 | /* Return a set containing those elements in the domain |
2922 | * of pwaff where it is non-negative. |
2923 | */ |
2924 | __isl_give isl_set *isl_pw_aff_nonneg_set(__isl_take isl_pw_aff *pwaff) |
2925 | { |
2926 | return pw_aff_locus(pwaff, fn: &aff_nonneg_basic_set, complement: 0, NULL); |
2927 | } |
2928 | |
2929 | /* Return a set containing those elements in the domain |
2930 | * of pwaff where it is zero. |
2931 | */ |
2932 | __isl_give isl_set *isl_pw_aff_zero_set(__isl_take isl_pw_aff *pwaff) |
2933 | { |
2934 | return pw_aff_locus(pwaff, fn: &aff_zero_basic_set, complement: 0, NULL); |
2935 | } |
2936 | |
2937 | /* Return a set containing those elements in the domain |
2938 | * of pwaff where it is not zero. |
2939 | */ |
2940 | __isl_give isl_set *isl_pw_aff_non_zero_set(__isl_take isl_pw_aff *pwaff) |
2941 | { |
2942 | return pw_aff_locus(pwaff, fn: &aff_zero_basic_set, complement: 1, NULL); |
2943 | } |
2944 | |
2945 | /* Bind the affine function "aff" to the parameter "id", |
2946 | * returning the elements in the domain where the affine expression |
2947 | * is equal to the parameter. |
2948 | */ |
2949 | __isl_give isl_basic_set *isl_aff_bind_id(__isl_take isl_aff *aff, |
2950 | __isl_take isl_id *id) |
2951 | { |
2952 | isl_space *space; |
2953 | isl_aff *aff_id; |
2954 | |
2955 | space = isl_aff_get_domain_space(aff); |
2956 | space = isl_space_add_param_id(space, id: isl_id_copy(id)); |
2957 | |
2958 | aff = isl_aff_align_params(aff, model: isl_space_copy(space)); |
2959 | aff_id = isl_aff_param_on_domain_space_id(space, id); |
2960 | |
2961 | return isl_aff_eq_basic_set(aff1: aff, aff2: aff_id); |
2962 | } |
2963 | |
2964 | /* Wrapper around isl_aff_bind_id for use as pw_aff_locus callback. |
2965 | * "rational" should not be set. |
2966 | */ |
2967 | static __isl_give isl_basic_set *aff_bind_id(__isl_take isl_aff *aff, |
2968 | int rational, void *user) |
2969 | { |
2970 | isl_id *id = user; |
2971 | |
2972 | if (!aff) |
2973 | return NULL; |
2974 | if (rational) |
2975 | isl_die(isl_aff_get_ctx(aff), isl_error_unsupported, |
2976 | "rational binding not supported" , goto error); |
2977 | return isl_aff_bind_id(aff, id: isl_id_copy(id)); |
2978 | error: |
2979 | isl_aff_free(aff); |
2980 | return NULL; |
2981 | } |
2982 | |
2983 | /* Bind the piecewise affine function "pa" to the parameter "id", |
2984 | * returning the elements in the domain where the expression |
2985 | * is equal to the parameter. |
2986 | */ |
2987 | __isl_give isl_set *isl_pw_aff_bind_id(__isl_take isl_pw_aff *pa, |
2988 | __isl_take isl_id *id) |
2989 | { |
2990 | isl_set *bound; |
2991 | |
2992 | bound = pw_aff_locus(pwaff: pa, fn: &aff_bind_id, complement: 0, user: id); |
2993 | isl_id_free(id); |
2994 | |
2995 | return bound; |
2996 | } |
2997 | |
2998 | /* Return a set containing those elements in the shared domain |
2999 | * of pwaff1 and pwaff2 where pwaff1 is greater than (or equal) to pwaff2. |
3000 | * |
3001 | * We compute the difference on the shared domain and then construct |
3002 | * the set of values where this difference is non-negative. |
3003 | * If strict is set, we first subtract 1 from the difference. |
3004 | * If equal is set, we only return the elements where pwaff1 and pwaff2 |
3005 | * are equal. |
3006 | */ |
3007 | static __isl_give isl_set *pw_aff_gte_set(__isl_take isl_pw_aff *pwaff1, |
3008 | __isl_take isl_pw_aff *pwaff2, int strict, int equal) |
3009 | { |
3010 | isl_set *set1, *set2; |
3011 | |
3012 | set1 = isl_pw_aff_domain(pw: isl_pw_aff_copy(pw: pwaff1)); |
3013 | set2 = isl_pw_aff_domain(pw: isl_pw_aff_copy(pw: pwaff2)); |
3014 | set1 = isl_set_intersect(set1, set2); |
3015 | pwaff1 = isl_pw_aff_intersect_domain(pw: pwaff1, context: isl_set_copy(set: set1)); |
3016 | pwaff2 = isl_pw_aff_intersect_domain(pw: pwaff2, context: isl_set_copy(set: set1)); |
3017 | pwaff1 = isl_pw_aff_add(pwaff1, pwaff2: isl_pw_aff_neg(pw: pwaff2)); |
3018 | |
3019 | if (strict) { |
3020 | isl_space *space = isl_set_get_space(set: set1); |
3021 | isl_aff *aff; |
3022 | aff = isl_aff_zero_on_domain(ls: isl_local_space_from_space(space)); |
3023 | aff = isl_aff_add_constant_si(aff, v: -1); |
3024 | pwaff1 = isl_pw_aff_add(pwaff1, pwaff2: isl_pw_aff_alloc(set: set1, el: aff)); |
3025 | } else |
3026 | isl_set_free(set: set1); |
3027 | |
3028 | if (equal) |
3029 | return isl_pw_aff_zero_set(pwaff: pwaff1); |
3030 | return isl_pw_aff_nonneg_set(pwaff: pwaff1); |
3031 | } |
3032 | |
3033 | /* Return a set containing those elements in the shared domain |
3034 | * of pwaff1 and pwaff2 where pwaff1 is equal to pwaff2. |
3035 | */ |
3036 | __isl_give isl_set *isl_pw_aff_eq_set(__isl_take isl_pw_aff *pwaff1, |
3037 | __isl_take isl_pw_aff *pwaff2) |
3038 | { |
3039 | isl_pw_aff_align_params_bin(obj1: &pwaff1, obj2: &pwaff2); |
3040 | return pw_aff_gte_set(pwaff1, pwaff2, strict: 0, equal: 1); |
3041 | } |
3042 | |
3043 | /* Return a set containing those elements in the shared domain |
3044 | * of pwaff1 and pwaff2 where pwaff1 is greater than or equal to pwaff2. |
3045 | */ |
3046 | __isl_give isl_set *isl_pw_aff_ge_set(__isl_take isl_pw_aff *pwaff1, |
3047 | __isl_take isl_pw_aff *pwaff2) |
3048 | { |
3049 | isl_pw_aff_align_params_bin(obj1: &pwaff1, obj2: &pwaff2); |
3050 | return pw_aff_gte_set(pwaff1, pwaff2, strict: 0, equal: 0); |
3051 | } |
3052 | |
3053 | /* Return a set containing those elements in the shared domain |
3054 | * of pwaff1 and pwaff2 where pwaff1 is strictly greater than pwaff2. |
3055 | */ |
3056 | __isl_give isl_set *isl_pw_aff_gt_set(__isl_take isl_pw_aff *pwaff1, |
3057 | __isl_take isl_pw_aff *pwaff2) |
3058 | { |
3059 | isl_pw_aff_align_params_bin(obj1: &pwaff1, obj2: &pwaff2); |
3060 | return pw_aff_gte_set(pwaff1, pwaff2, strict: 1, equal: 0); |
3061 | } |
3062 | |
3063 | __isl_give isl_set *isl_pw_aff_le_set(__isl_take isl_pw_aff *pwaff1, |
3064 | __isl_take isl_pw_aff *pwaff2) |
3065 | { |
3066 | return isl_pw_aff_ge_set(pwaff1: pwaff2, pwaff2: pwaff1); |
3067 | } |
3068 | |
3069 | __isl_give isl_set *isl_pw_aff_lt_set(__isl_take isl_pw_aff *pwaff1, |
3070 | __isl_take isl_pw_aff *pwaff2) |
3071 | { |
3072 | return isl_pw_aff_gt_set(pwaff1: pwaff2, pwaff2: pwaff1); |
3073 | } |
3074 | |
3075 | /* Return a map containing pairs of elements in the domains of "pa1" and "pa2" |
3076 | * where the function values are ordered in the same way as "order", |
3077 | * which returns a set in the shared domain of its two arguments. |
3078 | * |
3079 | * Let "pa1" and "pa2" be defined on domains A and B respectively. |
3080 | * We first pull back the two functions such that they are defined on |
3081 | * the domain [A -> B]. Then we apply "order", resulting in a set |
3082 | * in the space [A -> B]. Finally, we unwrap this set to obtain |
3083 | * a map in the space A -> B. |
3084 | */ |
3085 | static __isl_give isl_map *isl_pw_aff_order_map( |
3086 | __isl_take isl_pw_aff *pa1, __isl_take isl_pw_aff *pa2, |
3087 | __isl_give isl_set *(*order)(__isl_take isl_pw_aff *pa1, |
3088 | __isl_take isl_pw_aff *pa2)) |
3089 | { |
3090 | isl_space *space1, *space2; |
3091 | isl_multi_aff *ma; |
3092 | isl_set *set; |
3093 | |
3094 | isl_pw_aff_align_params_bin(obj1: &pa1, obj2: &pa2); |
3095 | space1 = isl_space_domain(space: isl_pw_aff_get_space(pw: pa1)); |
3096 | space2 = isl_space_domain(space: isl_pw_aff_get_space(pw: pa2)); |
3097 | space1 = isl_space_map_from_domain_and_range(domain: space1, range: space2); |
3098 | ma = isl_multi_aff_domain_map(space: isl_space_copy(space: space1)); |
3099 | pa1 = isl_pw_aff_pullback_multi_aff(pw: pa1, ma); |
3100 | ma = isl_multi_aff_range_map(space: space1); |
3101 | pa2 = isl_pw_aff_pullback_multi_aff(pw: pa2, ma); |
3102 | set = order(pa1, pa2); |
3103 | |
3104 | return isl_set_unwrap(set); |
3105 | } |
3106 | |
3107 | /* Return a map containing pairs of elements in the domains of "pa1" and "pa2" |
3108 | * where the function values are equal. |
3109 | */ |
3110 | __isl_give isl_map *isl_pw_aff_eq_map(__isl_take isl_pw_aff *pa1, |
3111 | __isl_take isl_pw_aff *pa2) |
3112 | { |
3113 | return isl_pw_aff_order_map(pa1, pa2, order: &isl_pw_aff_eq_set); |
3114 | } |
3115 | |
3116 | /* Return a map containing pairs of elements in the domains of "pa1" and "pa2" |
3117 | * where the function value of "pa1" is less than or equal to |
3118 | * the function value of "pa2". |
3119 | */ |
3120 | __isl_give isl_map *isl_pw_aff_le_map(__isl_take isl_pw_aff *pa1, |
3121 | __isl_take isl_pw_aff *pa2) |
3122 | { |
3123 | return isl_pw_aff_order_map(pa1, pa2, order: &isl_pw_aff_le_set); |
3124 | } |
3125 | |
3126 | /* Return a map containing pairs of elements in the domains of "pa1" and "pa2" |
3127 | * where the function value of "pa1" is less than the function value of "pa2". |
3128 | */ |
3129 | __isl_give isl_map *isl_pw_aff_lt_map(__isl_take isl_pw_aff *pa1, |
3130 | __isl_take isl_pw_aff *pa2) |
3131 | { |
3132 | return isl_pw_aff_order_map(pa1, pa2, order: &isl_pw_aff_lt_set); |
3133 | } |
3134 | |
3135 | /* Return a map containing pairs of elements in the domains of "pa1" and "pa2" |
3136 | * where the function value of "pa1" is greater than or equal to |
3137 | * the function value of "pa2". |
3138 | */ |
3139 | __isl_give isl_map *isl_pw_aff_ge_map(__isl_take isl_pw_aff *pa1, |
3140 | __isl_take isl_pw_aff *pa2) |
3141 | { |
3142 | return isl_pw_aff_order_map(pa1, pa2, order: &isl_pw_aff_ge_set); |
3143 | } |
3144 | |
3145 | /* Return a map containing pairs of elements in the domains of "pa1" and "pa2" |
3146 | * where the function value of "pa1" is greater than the function value |
3147 | * of "pa2". |
3148 | */ |
3149 | __isl_give isl_map *isl_pw_aff_gt_map(__isl_take isl_pw_aff *pa1, |
3150 | __isl_take isl_pw_aff *pa2) |
3151 | { |
3152 | return isl_pw_aff_order_map(pa1, pa2, order: &isl_pw_aff_gt_set); |
3153 | } |
3154 | |
3155 | /* Return a set containing those elements in the shared domain |
3156 | * of the elements of list1 and list2 where each element in list1 |
3157 | * has the relation specified by "fn" with each element in list2. |
3158 | */ |
3159 | static __isl_give isl_set *pw_aff_list_set(__isl_take isl_pw_aff_list *list1, |
3160 | __isl_take isl_pw_aff_list *list2, |
3161 | __isl_give isl_set *(*fn)(__isl_take isl_pw_aff *pwaff1, |
3162 | __isl_take isl_pw_aff *pwaff2)) |
3163 | { |
3164 | int i, j; |
3165 | isl_ctx *ctx; |
3166 | isl_set *set; |
3167 | |
3168 | if (!list1 || !list2) |
3169 | goto error; |
3170 | |
3171 | ctx = isl_pw_aff_list_get_ctx(list: list1); |
3172 | if (list1->n < 1 || list2->n < 1) |
3173 | isl_die(ctx, isl_error_invalid, |
3174 | "list should contain at least one element" , goto error); |
3175 | |
3176 | set = isl_set_universe(space: isl_pw_aff_get_domain_space(pw: list1->p[0])); |
3177 | for (i = 0; i < list1->n; ++i) |
3178 | for (j = 0; j < list2->n; ++j) { |
3179 | isl_set *set_ij; |
3180 | |
3181 | set_ij = fn(isl_pw_aff_copy(pw: list1->p[i]), |
3182 | isl_pw_aff_copy(pw: list2->p[j])); |
3183 | set = isl_set_intersect(set1: set, set2: set_ij); |
3184 | } |
3185 | |
3186 | isl_pw_aff_list_free(list: list1); |
3187 | isl_pw_aff_list_free(list: list2); |
3188 | return set; |
3189 | error: |
3190 | isl_pw_aff_list_free(list: list1); |
3191 | isl_pw_aff_list_free(list: list2); |
3192 | return NULL; |
3193 | } |
3194 | |
3195 | /* Return a set containing those elements in the shared domain |
3196 | * of the elements of list1 and list2 where each element in list1 |
3197 | * is equal to each element in list2. |
3198 | */ |
3199 | __isl_give isl_set *isl_pw_aff_list_eq_set(__isl_take isl_pw_aff_list *list1, |
3200 | __isl_take isl_pw_aff_list *list2) |
3201 | { |
3202 | return pw_aff_list_set(list1, list2, fn: &isl_pw_aff_eq_set); |
3203 | } |
3204 | |
3205 | __isl_give isl_set *isl_pw_aff_list_ne_set(__isl_take isl_pw_aff_list *list1, |
3206 | __isl_take isl_pw_aff_list *list2) |
3207 | { |
3208 | return pw_aff_list_set(list1, list2, fn: &isl_pw_aff_ne_set); |
3209 | } |
3210 | |
3211 | /* Return a set containing those elements in the shared domain |
3212 | * of the elements of list1 and list2 where each element in list1 |
3213 | * is less than or equal to each element in list2. |
3214 | */ |
3215 | __isl_give isl_set *isl_pw_aff_list_le_set(__isl_take isl_pw_aff_list *list1, |
3216 | __isl_take isl_pw_aff_list *list2) |
3217 | { |
3218 | return pw_aff_list_set(list1, list2, fn: &isl_pw_aff_le_set); |
3219 | } |
3220 | |
3221 | __isl_give isl_set *isl_pw_aff_list_lt_set(__isl_take isl_pw_aff_list *list1, |
3222 | __isl_take isl_pw_aff_list *list2) |
3223 | { |
3224 | return pw_aff_list_set(list1, list2, fn: &isl_pw_aff_lt_set); |
3225 | } |
3226 | |
3227 | __isl_give isl_set *isl_pw_aff_list_ge_set(__isl_take isl_pw_aff_list *list1, |
3228 | __isl_take isl_pw_aff_list *list2) |
3229 | { |
3230 | return pw_aff_list_set(list1, list2, fn: &isl_pw_aff_ge_set); |
3231 | } |
3232 | |
3233 | __isl_give isl_set *isl_pw_aff_list_gt_set(__isl_take isl_pw_aff_list *list1, |
3234 | __isl_take isl_pw_aff_list *list2) |
3235 | { |
3236 | return pw_aff_list_set(list1, list2, fn: &isl_pw_aff_gt_set); |
3237 | } |
3238 | |
3239 | |
3240 | /* Return a set containing those elements in the shared domain |
3241 | * of pwaff1 and pwaff2 where pwaff1 is not equal to pwaff2. |
3242 | */ |
3243 | __isl_give isl_set *isl_pw_aff_ne_set(__isl_take isl_pw_aff *pwaff1, |
3244 | __isl_take isl_pw_aff *pwaff2) |
3245 | { |
3246 | isl_set *set_lt, *set_gt; |
3247 | |
3248 | isl_pw_aff_align_params_bin(obj1: &pwaff1, obj2: &pwaff2); |
3249 | set_lt = isl_pw_aff_lt_set(pwaff1: isl_pw_aff_copy(pw: pwaff1), |
3250 | pwaff2: isl_pw_aff_copy(pw: pwaff2)); |
3251 | set_gt = isl_pw_aff_gt_set(pwaff1, pwaff2); |
3252 | return isl_set_union_disjoint(set1: set_lt, set2: set_gt); |
3253 | } |
3254 | |
3255 | __isl_give isl_pw_aff *isl_pw_aff_scale_down(__isl_take isl_pw_aff *pwaff, |
3256 | isl_int v) |
3257 | { |
3258 | int i; |
3259 | |
3260 | if (isl_int_is_one(v)) |
3261 | return pwaff; |
3262 | if (!isl_int_is_pos(v)) |
3263 | isl_die(isl_pw_aff_get_ctx(pwaff), isl_error_invalid, |
3264 | "factor needs to be positive" , |
3265 | return isl_pw_aff_free(pwaff)); |
3266 | pwaff = isl_pw_aff_cow(pw: pwaff); |
3267 | if (!pwaff) |
3268 | return NULL; |
3269 | if (pwaff->n == 0) |
3270 | return pwaff; |
3271 | |
3272 | for (i = 0; i < pwaff->n; ++i) { |
3273 | pwaff->p[i].aff = isl_aff_scale_down(aff: pwaff->p[i].aff, f: v); |
3274 | if (!pwaff->p[i].aff) |
3275 | return isl_pw_aff_free(pw: pwaff); |
3276 | } |
3277 | |
3278 | return pwaff; |
3279 | } |
3280 | |
3281 | __isl_give isl_pw_aff *isl_pw_aff_floor(__isl_take isl_pw_aff *pwaff) |
3282 | { |
3283 | return isl_pw_aff_un_op(pw: pwaff, fn: &isl_aff_floor); |
3284 | } |
3285 | |
3286 | __isl_give isl_pw_aff *isl_pw_aff_ceil(__isl_take isl_pw_aff *pwaff) |
3287 | { |
3288 | return isl_pw_aff_un_op(pw: pwaff, fn: &isl_aff_ceil); |
3289 | } |
3290 | |
3291 | /* Assuming that "cond1" and "cond2" are disjoint, |
3292 | * return an affine expression that is equal to pwaff1 on cond1 |
3293 | * and to pwaff2 on cond2. |
3294 | */ |
3295 | static __isl_give isl_pw_aff *isl_pw_aff_select( |
3296 | __isl_take isl_set *cond1, __isl_take isl_pw_aff *pwaff1, |
3297 | __isl_take isl_set *cond2, __isl_take isl_pw_aff *pwaff2) |
3298 | { |
3299 | pwaff1 = isl_pw_aff_intersect_domain(pw: pwaff1, context: cond1); |
3300 | pwaff2 = isl_pw_aff_intersect_domain(pw: pwaff2, context: cond2); |
3301 | |
3302 | return isl_pw_aff_add_disjoint(pw1: pwaff1, pw2: pwaff2); |
3303 | } |
3304 | |
3305 | /* Return an affine expression that is equal to pwaff_true for elements |
3306 | * where "cond" is non-zero and to pwaff_false for elements where "cond" |
3307 | * is zero. |
3308 | * That is, return cond ? pwaff_true : pwaff_false; |
3309 | * |
3310 | * If "cond" involves and NaN, then we conservatively return a NaN |
3311 | * on its entire domain. In principle, we could consider the pieces |
3312 | * where it is NaN separately from those where it is not. |
3313 | * |
3314 | * If "pwaff_true" and "pwaff_false" are obviously equal to each other, |
3315 | * then only use the domain of "cond" to restrict the domain. |
3316 | */ |
3317 | __isl_give isl_pw_aff *isl_pw_aff_cond(__isl_take isl_pw_aff *cond, |
3318 | __isl_take isl_pw_aff *pwaff_true, __isl_take isl_pw_aff *pwaff_false) |
3319 | { |
3320 | isl_set *cond_true, *cond_false; |
3321 | isl_bool equal; |
3322 | |
3323 | if (!cond) |
3324 | goto error; |
3325 | if (isl_pw_aff_involves_nan(pw: cond)) { |
3326 | isl_space *space = isl_pw_aff_get_domain_space(pw: cond); |
3327 | isl_local_space *ls = isl_local_space_from_space(space); |
3328 | isl_pw_aff_free(pw: cond); |
3329 | isl_pw_aff_free(pw: pwaff_true); |
3330 | isl_pw_aff_free(pw: pwaff_false); |
3331 | return isl_pw_aff_nan_on_domain(ls); |
3332 | } |
3333 | |
3334 | pwaff_true = isl_pw_aff_align_params(pw: pwaff_true, |
3335 | model: isl_pw_aff_get_space(pw: pwaff_false)); |
3336 | pwaff_false = isl_pw_aff_align_params(pw: pwaff_false, |
3337 | model: isl_pw_aff_get_space(pw: pwaff_true)); |
3338 | equal = isl_pw_aff_plain_is_equal(pw1: pwaff_true, pw2: pwaff_false); |
3339 | if (equal < 0) |
3340 | goto error; |
3341 | if (equal) { |
3342 | isl_set *dom; |
3343 | |
3344 | dom = isl_set_coalesce(set: isl_pw_aff_domain(pw: cond)); |
3345 | isl_pw_aff_free(pw: pwaff_false); |
3346 | return isl_pw_aff_intersect_domain(pw: pwaff_true, context: dom); |
3347 | } |
3348 | |
3349 | cond_true = isl_pw_aff_non_zero_set(pwaff: isl_pw_aff_copy(pw: cond)); |
3350 | cond_false = isl_pw_aff_zero_set(pwaff: cond); |
3351 | return isl_pw_aff_select(cond1: cond_true, pwaff1: pwaff_true, |
3352 | cond2: cond_false, pwaff2: pwaff_false); |
3353 | error: |
3354 | isl_pw_aff_free(pw: cond); |
3355 | isl_pw_aff_free(pw: pwaff_true); |
3356 | isl_pw_aff_free(pw: pwaff_false); |
3357 | return NULL; |
3358 | } |
3359 | |
3360 | isl_bool isl_aff_is_cst(__isl_keep isl_aff *aff) |
3361 | { |
3362 | int pos; |
3363 | |
3364 | if (!aff) |
3365 | return isl_bool_error; |
3366 | |
3367 | pos = isl_seq_first_non_zero(p: aff->v->el + 2, len: aff->v->size - 2); |
3368 | return isl_bool_ok(b: pos == -1); |
3369 | } |
3370 | |
3371 | /* Check whether pwaff is a piecewise constant. |
3372 | */ |
3373 | isl_bool isl_pw_aff_is_cst(__isl_keep isl_pw_aff *pwaff) |
3374 | { |
3375 | int i; |
3376 | |
3377 | if (!pwaff) |
3378 | return isl_bool_error; |
3379 | |
3380 | for (i = 0; i < pwaff->n; ++i) { |
3381 | isl_bool is_cst = isl_aff_is_cst(aff: pwaff->p[i].aff); |
3382 | if (is_cst < 0 || !is_cst) |
3383 | return is_cst; |
3384 | } |
3385 | |
3386 | return isl_bool_true; |
3387 | } |
3388 | |
3389 | /* Return the product of "aff1" and "aff2". |
3390 | * |
3391 | * If either of the two is NaN, then the result is NaN. |
3392 | * |
3393 | * Otherwise, at least one of "aff1" or "aff2" needs to be a constant. |
3394 | */ |
3395 | __isl_give isl_aff *isl_aff_mul(__isl_take isl_aff *aff1, |
3396 | __isl_take isl_aff *aff2) |
3397 | { |
3398 | if (!aff1 || !aff2) |
3399 | goto error; |
3400 | |
3401 | if (isl_aff_is_nan(aff: aff1)) { |
3402 | isl_aff_free(aff: aff2); |
3403 | return aff1; |
3404 | } |
3405 | if (isl_aff_is_nan(aff: aff2)) { |
3406 | isl_aff_free(aff: aff1); |
3407 | return aff2; |
3408 | } |
3409 | |
3410 | if (!isl_aff_is_cst(aff: aff2) && isl_aff_is_cst(aff: aff1)) |
3411 | return isl_aff_mul(aff1: aff2, aff2: aff1); |
3412 | |
3413 | if (!isl_aff_is_cst(aff: aff2)) |
3414 | isl_die(isl_aff_get_ctx(aff1), isl_error_invalid, |
3415 | "at least one affine expression should be constant" , |
3416 | goto error); |
3417 | |
3418 | aff1 = isl_aff_cow(aff: aff1); |
3419 | if (!aff1 || !aff2) |
3420 | goto error; |
3421 | |
3422 | aff1 = isl_aff_scale(aff: aff1, f: aff2->v->el[1]); |
3423 | aff1 = isl_aff_scale_down(aff: aff1, f: aff2->v->el[0]); |
3424 | |
3425 | isl_aff_free(aff: aff2); |
3426 | return aff1; |
3427 | error: |
3428 | isl_aff_free(aff: aff1); |
3429 | isl_aff_free(aff: aff2); |
3430 | return NULL; |
3431 | } |
3432 | |
3433 | /* Divide "aff1" by "aff2", assuming "aff2" is a constant. |
3434 | * |
3435 | * If either of the two is NaN, then the result is NaN. |
3436 | * A division by zero also results in NaN. |
3437 | */ |
3438 | __isl_give isl_aff *isl_aff_div(__isl_take isl_aff *aff1, |
3439 | __isl_take isl_aff *aff2) |
3440 | { |
3441 | isl_bool is_cst, is_zero; |
3442 | int neg; |
3443 | |
3444 | if (!aff1 || !aff2) |
3445 | goto error; |
3446 | |
3447 | if (isl_aff_is_nan(aff: aff1)) { |
3448 | isl_aff_free(aff: aff2); |
3449 | return aff1; |
3450 | } |
3451 | if (isl_aff_is_nan(aff: aff2)) { |
3452 | isl_aff_free(aff: aff1); |
3453 | return aff2; |
3454 | } |
3455 | |
3456 | is_cst = isl_aff_is_cst(aff: aff2); |
3457 | if (is_cst < 0) |
3458 | goto error; |
3459 | if (!is_cst) |
3460 | isl_die(isl_aff_get_ctx(aff2), isl_error_invalid, |
3461 | "second argument should be a constant" , goto error); |
3462 | is_zero = isl_aff_plain_is_zero(aff: aff2); |
3463 | if (is_zero < 0) |
3464 | goto error; |
3465 | if (is_zero) |
3466 | return set_nan_free(aff1, aff2); |
3467 | |
3468 | neg = isl_int_is_neg(aff2->v->el[1]); |
3469 | if (neg) { |
3470 | isl_int_neg(aff2->v->el[0], aff2->v->el[0]); |
3471 | isl_int_neg(aff2->v->el[1], aff2->v->el[1]); |
3472 | } |
3473 | |
3474 | aff1 = isl_aff_scale(aff: aff1, f: aff2->v->el[0]); |
3475 | aff1 = isl_aff_scale_down(aff: aff1, f: aff2->v->el[1]); |
3476 | |
3477 | if (neg) { |
3478 | isl_int_neg(aff2->v->el[0], aff2->v->el[0]); |
3479 | isl_int_neg(aff2->v->el[1], aff2->v->el[1]); |
3480 | } |
3481 | |
3482 | isl_aff_free(aff: aff2); |
3483 | return aff1; |
3484 | error: |
3485 | isl_aff_free(aff: aff1); |
3486 | isl_aff_free(aff: aff2); |
3487 | return NULL; |
3488 | } |
3489 | |
3490 | __isl_give isl_pw_aff *isl_pw_aff_add(__isl_take isl_pw_aff *pwaff1, |
3491 | __isl_take isl_pw_aff *pwaff2) |
3492 | { |
3493 | isl_pw_aff_align_params_bin(obj1: &pwaff1, obj2: &pwaff2); |
3494 | return isl_pw_aff_on_shared_domain(pw1: pwaff1, pw2: pwaff2, fn: &isl_aff_add); |
3495 | } |
3496 | |
3497 | __isl_give isl_pw_aff *isl_pw_aff_mul(__isl_take isl_pw_aff *pwaff1, |
3498 | __isl_take isl_pw_aff *pwaff2) |
3499 | { |
3500 | isl_pw_aff_align_params_bin(obj1: &pwaff1, obj2: &pwaff2); |
3501 | return isl_pw_aff_on_shared_domain(pw1: pwaff1, pw2: pwaff2, fn: &isl_aff_mul); |
3502 | } |
3503 | |
3504 | /* Divide "pa1" by "pa2", assuming "pa2" is a piecewise constant. |
3505 | */ |
3506 | __isl_give isl_pw_aff *isl_pw_aff_div(__isl_take isl_pw_aff *pa1, |
3507 | __isl_take isl_pw_aff *pa2) |
3508 | { |
3509 | int is_cst; |
3510 | |
3511 | is_cst = isl_pw_aff_is_cst(pwaff: pa2); |
3512 | if (is_cst < 0) |
3513 | goto error; |
3514 | if (!is_cst) |
3515 | isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid, |
3516 | "second argument should be a piecewise constant" , |
3517 | goto error); |
3518 | isl_pw_aff_align_params_bin(obj1: &pa1, obj2: &pa2); |
3519 | return isl_pw_aff_on_shared_domain(pw1: pa1, pw2: pa2, fn: &isl_aff_div); |
3520 | error: |
3521 | isl_pw_aff_free(pw: pa1); |
3522 | isl_pw_aff_free(pw: pa2); |
3523 | return NULL; |
3524 | } |
3525 | |
3526 | /* Compute the quotient of the integer division of "pa1" by "pa2" |
3527 | * with rounding towards zero. |
3528 | * "pa2" is assumed to be a piecewise constant. |
3529 | * |
3530 | * In particular, return |
3531 | * |
3532 | * pa1 >= 0 ? floor(pa1/pa2) : ceil(pa1/pa2) |
3533 | * |
3534 | */ |
3535 | __isl_give isl_pw_aff *isl_pw_aff_tdiv_q(__isl_take isl_pw_aff *pa1, |
3536 | __isl_take isl_pw_aff *pa2) |
3537 | { |
3538 | int is_cst; |
3539 | isl_set *cond; |
3540 | isl_pw_aff *f, *c; |
3541 | |
3542 | is_cst = isl_pw_aff_is_cst(pwaff: pa2); |
3543 | if (is_cst < 0) |
3544 | goto error; |
3545 | if (!is_cst) |
3546 | isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid, |
3547 | "second argument should be a piecewise constant" , |
3548 | goto error); |
3549 | |
3550 | pa1 = isl_pw_aff_div(pa1, pa2); |
3551 | |
3552 | cond = isl_pw_aff_nonneg_set(pwaff: isl_pw_aff_copy(pw: pa1)); |
3553 | f = isl_pw_aff_floor(pwaff: isl_pw_aff_copy(pw: pa1)); |
3554 | c = isl_pw_aff_ceil(pwaff: pa1); |
3555 | return isl_pw_aff_cond(cond: isl_set_indicator_function(set: cond), pwaff_true: f, pwaff_false: c); |
3556 | error: |
3557 | isl_pw_aff_free(pw: pa1); |
3558 | isl_pw_aff_free(pw: pa2); |
3559 | return NULL; |
3560 | } |
3561 | |
3562 | /* Compute the remainder of the integer division of "pa1" by "pa2" |
3563 | * with rounding towards zero. |
3564 | * "pa2" is assumed to be a piecewise constant. |
3565 | * |
3566 | * In particular, return |
3567 | * |
3568 | * pa1 - pa2 * (pa1 >= 0 ? floor(pa1/pa2) : ceil(pa1/pa2)) |
3569 | * |
3570 | */ |
3571 | __isl_give isl_pw_aff *isl_pw_aff_tdiv_r(__isl_take isl_pw_aff *pa1, |
3572 | __isl_take isl_pw_aff *pa2) |
3573 | { |
3574 | int is_cst; |
3575 | isl_pw_aff *res; |
3576 | |
3577 | is_cst = isl_pw_aff_is_cst(pwaff: pa2); |
3578 | if (is_cst < 0) |
3579 | goto error; |
3580 | if (!is_cst) |
3581 | isl_die(isl_pw_aff_get_ctx(pa2), isl_error_invalid, |
3582 | "second argument should be a piecewise constant" , |
3583 | goto error); |
3584 | res = isl_pw_aff_tdiv_q(pa1: isl_pw_aff_copy(pw: pa1), pa2: isl_pw_aff_copy(pw: pa2)); |
3585 | res = isl_pw_aff_mul(pwaff1: pa2, pwaff2: res); |
3586 | res = isl_pw_aff_sub(pw1: pa1, pw2: res); |
3587 | return res; |
3588 | error: |
3589 | isl_pw_aff_free(pw: pa1); |
3590 | isl_pw_aff_free(pw: pa2); |
3591 | return NULL; |
3592 | } |
3593 | |
3594 | /* Does either of "pa1" or "pa2" involve any NaN? |
3595 | */ |
3596 | static isl_bool either_involves_nan(__isl_keep isl_pw_aff *pa1, |
3597 | __isl_keep isl_pw_aff *pa2) |
3598 | { |
3599 | isl_bool has_nan; |
3600 | |
3601 | has_nan = isl_pw_aff_involves_nan(pw: pa1); |
3602 | if (has_nan < 0 || has_nan) |
3603 | return has_nan; |
3604 | return isl_pw_aff_involves_nan(pw: pa2); |
3605 | } |
3606 | |
3607 | /* Return a piecewise affine expression defined on the specified domain |
3608 | * that represents NaN. |
3609 | */ |
3610 | static __isl_give isl_pw_aff *nan_on_domain_set(__isl_take isl_set *dom) |
3611 | { |
3612 | isl_local_space *ls; |
3613 | isl_pw_aff *pa; |
3614 | |
3615 | ls = isl_local_space_from_space(space: isl_set_get_space(set: dom)); |
3616 | pa = isl_pw_aff_nan_on_domain(ls); |
3617 | pa = isl_pw_aff_intersect_domain(pw: pa, context: dom); |
3618 | |
3619 | return pa; |
3620 | } |
3621 | |
3622 | /* Replace "pa1" and "pa2" (at least one of which involves a NaN) |
3623 | * by a NaN on their shared domain. |
3624 | * |
3625 | * In principle, the result could be refined to only being NaN |
3626 | * on the parts of this domain where at least one of "pa1" or "pa2" is NaN. |
3627 | */ |
3628 | static __isl_give isl_pw_aff *replace_by_nan(__isl_take isl_pw_aff *pa1, |
3629 | __isl_take isl_pw_aff *pa2) |
3630 | { |
3631 | isl_set *dom; |
3632 | |
3633 | dom = isl_set_intersect(set1: isl_pw_aff_domain(pw: pa1), set2: isl_pw_aff_domain(pw: pa2)); |
3634 | return nan_on_domain_set(dom); |
3635 | } |
3636 | |
3637 | static __isl_give isl_pw_aff *pw_aff_min(__isl_take isl_pw_aff *pwaff1, |
3638 | __isl_take isl_pw_aff *pwaff2) |
3639 | { |
3640 | isl_set *le; |
3641 | isl_set *dom; |
3642 | |
3643 | dom = isl_set_intersect(set1: isl_pw_aff_domain(pw: isl_pw_aff_copy(pw: pwaff1)), |
3644 | set2: isl_pw_aff_domain(pw: isl_pw_aff_copy(pw: pwaff2))); |
3645 | le = isl_pw_aff_le_set(pwaff1: isl_pw_aff_copy(pw: pwaff1), |
3646 | pwaff2: isl_pw_aff_copy(pw: pwaff2)); |
3647 | dom = isl_set_subtract(set1: dom, set2: isl_set_copy(set: le)); |
3648 | return isl_pw_aff_select(cond1: le, pwaff1, cond2: dom, pwaff2); |
3649 | } |
3650 | |
3651 | static __isl_give isl_pw_aff *pw_aff_max(__isl_take isl_pw_aff *pwaff1, |
3652 | __isl_take isl_pw_aff *pwaff2) |
3653 | { |
3654 | isl_set *ge; |
3655 | isl_set *dom; |
3656 | |
3657 | dom = isl_set_intersect(set1: isl_pw_aff_domain(pw: isl_pw_aff_copy(pw: pwaff1)), |
3658 | set2: isl_pw_aff_domain(pw: isl_pw_aff_copy(pw: pwaff2))); |
3659 | ge = isl_pw_aff_ge_set(pwaff1: isl_pw_aff_copy(pw: pwaff1), |
3660 | pwaff2: isl_pw_aff_copy(pw: pwaff2)); |
3661 | dom = isl_set_subtract(set1: dom, set2: isl_set_copy(set: ge)); |
3662 | return isl_pw_aff_select(cond1: ge, pwaff1, cond2: dom, pwaff2); |
3663 | } |
3664 | |
3665 | /* Return an expression for the minimum (if "max" is not set) or |
3666 | * the maximum (if "max" is set) of "pa1" and "pa2". |
3667 | * If either expression involves any NaN, then return a NaN |
3668 | * on the shared domain as result. |
3669 | */ |
3670 | static __isl_give isl_pw_aff *pw_aff_min_max(__isl_take isl_pw_aff *pa1, |
3671 | __isl_take isl_pw_aff *pa2, int max) |
3672 | { |
3673 | isl_bool has_nan; |
3674 | |
3675 | has_nan = either_involves_nan(pa1, pa2); |
3676 | if (has_nan < 0) |
3677 | pa1 = isl_pw_aff_free(pw: pa1); |
3678 | else if (has_nan) |
3679 | return replace_by_nan(pa1, pa2); |
3680 | |
3681 | isl_pw_aff_align_params_bin(obj1: &pa1, obj2: &pa2); |
3682 | if (max) |
3683 | return pw_aff_max(pwaff1: pa1, pwaff2: pa2); |
3684 | else |
3685 | return pw_aff_min(pwaff1: pa1, pwaff2: pa2); |
3686 | } |
3687 | |
3688 | /* Return an expression for the minimum of "pwaff1" and "pwaff2". |
3689 | */ |
3690 | __isl_give isl_pw_aff *isl_pw_aff_min(__isl_take isl_pw_aff *pwaff1, |
3691 | __isl_take isl_pw_aff *pwaff2) |
3692 | { |
3693 | return pw_aff_min_max(pa1: pwaff1, pa2: pwaff2, max: 0); |
3694 | } |
3695 | |
3696 | /* Return an expression for the maximum of "pwaff1" and "pwaff2". |
3697 | */ |
3698 | __isl_give isl_pw_aff *isl_pw_aff_max(__isl_take isl_pw_aff *pwaff1, |
3699 | __isl_take isl_pw_aff *pwaff2) |
3700 | { |
3701 | return pw_aff_min_max(pa1: pwaff1, pa2: pwaff2, max: 1); |
3702 | } |
3703 | |
3704 | /* Does "pa" not involve any NaN? |
3705 | */ |
3706 | static isl_bool pw_aff_no_nan(__isl_keep isl_pw_aff *pa, void *user) |
3707 | { |
3708 | return isl_bool_not(b: isl_pw_aff_involves_nan(pw: pa)); |
3709 | } |
3710 | |
3711 | /* Does any element of "list" involve any NaN? |
3712 | * |
3713 | * That is, is it not the case that every element does not involve any NaN? |
3714 | */ |
3715 | static isl_bool isl_pw_aff_list_involves_nan(__isl_keep isl_pw_aff_list *list) |
3716 | { |
3717 | return isl_bool_not(b: isl_pw_aff_list_every(list, test: &pw_aff_no_nan, NULL)); |
3718 | } |
3719 | |
3720 | /* Replace "list" (consisting of "n" elements, of which |
3721 | * at least one element involves a NaN) |
3722 | * by a NaN on the shared domain of the elements. |
3723 | * |
3724 | * In principle, the result could be refined to only being NaN |
3725 | * on the parts of this domain where at least one of the elements is NaN. |
3726 | */ |
3727 | static __isl_give isl_pw_aff *replace_list_by_nan( |
3728 | __isl_take isl_pw_aff_list *list, int n) |
3729 | { |
3730 | int i; |
3731 | isl_set *dom; |
3732 | |
3733 | dom = isl_pw_aff_domain(pw: isl_pw_aff_list_get_at(list, index: 0)); |
3734 | for (i = 1; i < n; ++i) { |
3735 | isl_set *dom_i; |
3736 | |
3737 | dom_i = isl_pw_aff_domain(pw: isl_pw_aff_list_get_at(list, index: i)); |
3738 | dom = isl_set_intersect(set1: dom, set2: dom_i); |
3739 | } |
3740 | |
3741 | isl_pw_aff_list_free(list); |
3742 | return nan_on_domain_set(dom); |
3743 | } |
3744 | |
3745 | /* Return the set where the element at "pos1" of "list" is less than or |
3746 | * equal to the element at "pos2". |
3747 | * Equality is only allowed if "pos1" is smaller than "pos2". |
3748 | */ |
3749 | static __isl_give isl_set *less(__isl_keep isl_pw_aff_list *list, |
3750 | int pos1, int pos2) |
3751 | { |
3752 | isl_pw_aff *pa1, *pa2; |
3753 | |
3754 | pa1 = isl_pw_aff_list_get_at(list, index: pos1); |
3755 | pa2 = isl_pw_aff_list_get_at(list, index: pos2); |
3756 | |
3757 | if (pos1 < pos2) |
3758 | return isl_pw_aff_le_set(pwaff1: pa1, pwaff2: pa2); |
3759 | else |
3760 | return isl_pw_aff_lt_set(pwaff1: pa1, pwaff2: pa2); |
3761 | } |
3762 | |
3763 | /* Return an isl_pw_aff that maps each element in the intersection of the |
3764 | * domains of the piecewise affine expressions in "list" |
3765 | * to the maximal (if "max" is set) or minimal (if "max" is not set) |
3766 | * expression in "list" at that element. |
3767 | * If any expression involves any NaN, then return a NaN |
3768 | * on the shared domain as result. |
3769 | * |
3770 | * If "list" has n elements, then the result consists of n pieces, |
3771 | * where, in the case of a minimum, each piece has as value expression |
3772 | * the value expression of one of the elements and as domain |
3773 | * the set of elements where that value expression |
3774 | * is less than (or equal) to the other value expressions. |
3775 | * In the case of a maximum, the condition is |
3776 | * that all the other value expressions are less than (or equal) |
3777 | * to the given value expression. |
3778 | * |
3779 | * In order to produce disjoint pieces, a pair of elements |
3780 | * in the original domain is only allowed to be equal to each other |
3781 | * on exactly one of the two pieces corresponding to the two elements. |
3782 | * The position in the list is used to break ties. |
3783 | * In particular, in the case of a minimum, |
3784 | * in the piece corresponding to a given element, |
3785 | * this element is allowed to be equal to any later element in the list, |
3786 | * but not to any earlier element in the list. |
3787 | */ |
3788 | static __isl_give isl_pw_aff *isl_pw_aff_list_opt( |
3789 | __isl_take isl_pw_aff_list *list, int max) |
3790 | { |
3791 | int i, j; |
3792 | isl_bool has_nan; |
3793 | isl_size n; |
3794 | isl_space *space; |
3795 | isl_pw_aff *pa, *res; |
3796 | |
3797 | n = isl_pw_aff_list_size(list); |
3798 | if (n < 0) |
3799 | goto error; |
3800 | if (n < 1) |
3801 | isl_die(isl_pw_aff_list_get_ctx(list), isl_error_invalid, |
3802 | "list should contain at least one element" , goto error); |
3803 | |
3804 | has_nan = isl_pw_aff_list_involves_nan(list); |
3805 | if (has_nan < 0) |
3806 | goto error; |
3807 | if (has_nan) |
3808 | return replace_list_by_nan(list, n); |
3809 | |
3810 | pa = isl_pw_aff_list_get_at(list, index: 0); |
3811 | space = isl_pw_aff_get_space(pw: pa); |
3812 | isl_pw_aff_free(pw: pa); |
3813 | res = isl_pw_aff_empty(space); |
3814 | |
3815 | for (i = 0; i < n; ++i) { |
3816 | pa = isl_pw_aff_list_get_at(list, index: i); |
3817 | for (j = 0; j < n; ++j) { |
3818 | isl_set *dom; |
3819 | |
3820 | if (j == i) |
3821 | continue; |
3822 | if (max) |
3823 | dom = less(list, pos1: j, pos2: i); |
3824 | else |
3825 | dom = less(list, pos1: i, pos2: j); |
3826 | |
3827 | pa = isl_pw_aff_intersect_domain(pw: pa, context: dom); |
3828 | } |
3829 | res = isl_pw_aff_add_disjoint(pw1: res, pw2: pa); |
3830 | } |
3831 | |
3832 | isl_pw_aff_list_free(list); |
3833 | return res; |
3834 | error: |
3835 | isl_pw_aff_list_free(list); |
3836 | return NULL; |
3837 | } |
3838 | |
3839 | /* Return an isl_pw_aff that maps each element in the intersection of the |
3840 | * domains of the elements of list to the minimal corresponding affine |
3841 | * expression. |
3842 | */ |
3843 | __isl_give isl_pw_aff *isl_pw_aff_list_min(__isl_take isl_pw_aff_list *list) |
3844 | { |
3845 | return isl_pw_aff_list_opt(list, max: 0); |
3846 | } |
3847 | |
3848 | /* Return an isl_pw_aff that maps each element in the intersection of the |
3849 | * domains of the elements of list to the maximal corresponding affine |
3850 | * expression. |
3851 | */ |
3852 | __isl_give isl_pw_aff *isl_pw_aff_list_max(__isl_take isl_pw_aff_list *list) |
3853 | { |
3854 | return isl_pw_aff_list_opt(list, max: 1); |
3855 | } |
3856 | |
3857 | /* Mark the domains of "pwaff" as rational. |
3858 | */ |
3859 | __isl_give isl_pw_aff *isl_pw_aff_set_rational(__isl_take isl_pw_aff *pwaff) |
3860 | { |
3861 | int i; |
3862 | |
3863 | pwaff = isl_pw_aff_cow(pw: pwaff); |
3864 | if (!pwaff) |
3865 | return NULL; |
3866 | if (pwaff->n == 0) |
3867 | return pwaff; |
3868 | |
3869 | for (i = 0; i < pwaff->n; ++i) { |
3870 | pwaff->p[i].set = isl_set_set_rational(set: pwaff->p[i].set); |
3871 | if (!pwaff->p[i].set) |
3872 | return isl_pw_aff_free(pw: pwaff); |
3873 | } |
3874 | |
3875 | return pwaff; |
3876 | } |
3877 | |
3878 | /* Mark the domains of the elements of "list" as rational. |
3879 | */ |
3880 | __isl_give isl_pw_aff_list *isl_pw_aff_list_set_rational( |
3881 | __isl_take isl_pw_aff_list *list) |
3882 | { |
3883 | int i, n; |
3884 | |
3885 | if (!list) |
3886 | return NULL; |
3887 | if (list->n == 0) |
3888 | return list; |
3889 | |
3890 | n = list->n; |
3891 | for (i = 0; i < n; ++i) { |
3892 | isl_pw_aff *pa; |
3893 | |
3894 | pa = isl_pw_aff_list_get_pw_aff(list, index: i); |
3895 | pa = isl_pw_aff_set_rational(pwaff: pa); |
3896 | list = isl_pw_aff_list_set_pw_aff(list, index: i, el: pa); |
3897 | } |
3898 | |
3899 | return list; |
3900 | } |
3901 | |
3902 | /* Do the parameters of "aff" match those of "space"? |
3903 | */ |
3904 | isl_bool isl_aff_matching_params(__isl_keep isl_aff *aff, |
3905 | __isl_keep isl_space *space) |
3906 | { |
3907 | isl_space *aff_space; |
3908 | isl_bool match; |
3909 | |
3910 | if (!aff || !space) |
3911 | return isl_bool_error; |
3912 | |
3913 | aff_space = isl_aff_get_domain_space(aff); |
3914 | |
3915 | match = isl_space_has_equal_params(space1: space, space2: aff_space); |
3916 | |
3917 | isl_space_free(space: aff_space); |
3918 | return match; |
3919 | } |
3920 | |
3921 | /* Check that the domain space of "aff" matches "space". |
3922 | */ |
3923 | isl_stat isl_aff_check_match_domain_space(__isl_keep isl_aff *aff, |
3924 | __isl_keep isl_space *space) |
3925 | { |
3926 | isl_space *aff_space; |
3927 | isl_bool match; |
3928 | |
3929 | if (!aff || !space) |
3930 | return isl_stat_error; |
3931 | |
3932 | aff_space = isl_aff_get_domain_space(aff); |
3933 | |
3934 | match = isl_space_has_equal_params(space1: space, space2: aff_space); |
3935 | if (match < 0) |
3936 | goto error; |
3937 | if (!match) |
3938 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
3939 | "parameters don't match" , goto error); |
3940 | match = isl_space_tuple_is_equal(space1: space, type1: isl_dim_in, |
3941 | space2: aff_space, type2: isl_dim_set); |
3942 | if (match < 0) |
3943 | goto error; |
3944 | if (!match) |
3945 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
3946 | "domains don't match" , goto error); |
3947 | isl_space_free(space: aff_space); |
3948 | return isl_stat_ok; |
3949 | error: |
3950 | isl_space_free(space: aff_space); |
3951 | return isl_stat_error; |
3952 | } |
3953 | |
3954 | /* Return the shared (universe) domain of the elements of "ma". |
3955 | * |
3956 | * Since an isl_multi_aff (and an isl_aff) is always total, |
3957 | * the domain is always the universe set in its domain space. |
3958 | * This is a helper function for use in the generic isl_multi_*_bind. |
3959 | */ |
3960 | static __isl_give isl_basic_set *isl_multi_aff_domain( |
3961 | __isl_take isl_multi_aff *ma) |
3962 | { |
3963 | isl_space *space; |
3964 | |
3965 | space = isl_multi_aff_get_space(multi: ma); |
3966 | isl_multi_aff_free(multi: ma); |
3967 | |
3968 | return isl_basic_set_universe(space: isl_space_domain(space)); |
3969 | } |
3970 | |
3971 | #undef BASE |
3972 | #define BASE aff |
3973 | |
3974 | #include <isl_multi_no_explicit_domain.c> |
3975 | #include <isl_multi_templ.c> |
3976 | #include <isl_multi_un_op_templ.c> |
3977 | #include <isl_multi_bin_val_templ.c> |
3978 | #include <isl_multi_add_constant_templ.c> |
3979 | #include <isl_multi_apply_set.c> |
3980 | #include <isl_multi_arith_templ.c> |
3981 | #include <isl_multi_bind_domain_templ.c> |
3982 | #include <isl_multi_cmp.c> |
3983 | #include <isl_multi_dim_id_templ.c> |
3984 | #include <isl_multi_dims.c> |
3985 | #include <isl_multi_floor.c> |
3986 | #include <isl_multi_from_base_templ.c> |
3987 | #include <isl_multi_identity_templ.c> |
3988 | #include <isl_multi_insert_domain_templ.c> |
3989 | #include <isl_multi_locals_templ.c> |
3990 | #include <isl_multi_move_dims_templ.c> |
3991 | #include <isl_multi_nan_templ.c> |
3992 | #include <isl_multi_product_templ.c> |
3993 | #include <isl_multi_splice_templ.c> |
3994 | #include <isl_multi_tuple_id_templ.c> |
3995 | #include <isl_multi_unbind_params_templ.c> |
3996 | #include <isl_multi_zero_templ.c> |
3997 | |
3998 | #undef DOMBASE |
3999 | #define DOMBASE set |
4000 | #include <isl_multi_gist.c> |
4001 | |
4002 | #undef DOMBASE |
4003 | #define DOMBASE basic_set |
4004 | #include <isl_multi_bind_templ.c> |
4005 | |
4006 | /* Construct an isl_multi_aff living in "space" that corresponds |
4007 | * to the affine transformation matrix "mat". |
4008 | */ |
4009 | __isl_give isl_multi_aff *isl_multi_aff_from_aff_mat( |
4010 | __isl_take isl_space *space, __isl_take isl_mat *mat) |
4011 | { |
4012 | isl_ctx *ctx; |
4013 | isl_local_space *ls = NULL; |
4014 | isl_multi_aff *ma = NULL; |
4015 | isl_size n_row, n_col, n_out, total; |
4016 | int i; |
4017 | |
4018 | if (!space || !mat) |
4019 | goto error; |
4020 | |
4021 | ctx = isl_mat_get_ctx(mat); |
4022 | |
4023 | n_row = isl_mat_rows(mat); |
4024 | n_col = isl_mat_cols(mat); |
4025 | n_out = isl_space_dim(space, type: isl_dim_out); |
4026 | total = isl_space_dim(space, type: isl_dim_all); |
4027 | if (n_row < 0 || n_col < 0 || n_out < 0 || total < 0) |
4028 | goto error; |
4029 | if (n_row < 1) |
4030 | isl_die(ctx, isl_error_invalid, |
4031 | "insufficient number of rows" , goto error); |
4032 | if (n_col < 1) |
4033 | isl_die(ctx, isl_error_invalid, |
4034 | "insufficient number of columns" , goto error); |
4035 | if (1 + n_out != n_row || 2 + total != n_row + n_col) |
4036 | isl_die(ctx, isl_error_invalid, |
4037 | "dimension mismatch" , goto error); |
4038 | |
4039 | ma = isl_multi_aff_zero(space: isl_space_copy(space)); |
4040 | space = isl_space_domain(space); |
4041 | ls = isl_local_space_from_space(space: isl_space_copy(space)); |
4042 | |
4043 | for (i = 0; i < n_row - 1; ++i) { |
4044 | isl_vec *v; |
4045 | isl_aff *aff; |
4046 | |
4047 | v = isl_vec_alloc(ctx, size: 1 + n_col); |
4048 | if (!v) |
4049 | goto error; |
4050 | isl_int_set(v->el[0], mat->row[0][0]); |
4051 | isl_seq_cpy(dst: v->el + 1, src: mat->row[1 + i], len: n_col); |
4052 | v = isl_vec_normalize(vec: v); |
4053 | aff = isl_aff_alloc_vec_validated(ls: isl_local_space_copy(ls), v); |
4054 | ma = isl_multi_aff_set_aff(multi: ma, pos: i, el: aff); |
4055 | } |
4056 | |
4057 | isl_space_free(space); |
4058 | isl_local_space_free(ls); |
4059 | isl_mat_free(mat); |
4060 | return ma; |
4061 | error: |
4062 | isl_space_free(space); |
4063 | isl_local_space_free(ls); |
4064 | isl_mat_free(mat); |
4065 | isl_multi_aff_free(multi: ma); |
4066 | return NULL; |
4067 | } |
4068 | |
4069 | /* Return the constant terms of the affine expressions of "ma". |
4070 | */ |
4071 | __isl_give isl_multi_val *isl_multi_aff_get_constant_multi_val( |
4072 | __isl_keep isl_multi_aff *ma) |
4073 | { |
4074 | int i; |
4075 | isl_size n; |
4076 | isl_space *space; |
4077 | isl_multi_val *mv; |
4078 | |
4079 | n = isl_multi_aff_size(multi: ma); |
4080 | if (n < 0) |
4081 | return NULL; |
4082 | space = isl_space_range(space: isl_multi_aff_get_space(multi: ma)); |
4083 | space = isl_space_drop_all_params(space); |
4084 | mv = isl_multi_val_zero(space); |
4085 | |
4086 | for (i = 0; i < n; ++i) { |
4087 | isl_aff *aff; |
4088 | isl_val *val; |
4089 | |
4090 | aff = isl_multi_aff_get_at(multi: ma, pos: i); |
4091 | val = isl_aff_get_constant_val(aff); |
4092 | isl_aff_free(aff); |
4093 | mv = isl_multi_val_set_at(multi: mv, pos: i, el: val); |
4094 | } |
4095 | |
4096 | return mv; |
4097 | } |
4098 | |
4099 | /* Remove any internal structure of the domain of "ma". |
4100 | * If there is any such internal structure in the input, |
4101 | * then the name of the corresponding space is also removed. |
4102 | */ |
4103 | __isl_give isl_multi_aff *isl_multi_aff_flatten_domain( |
4104 | __isl_take isl_multi_aff *ma) |
4105 | { |
4106 | isl_space *space; |
4107 | |
4108 | if (!ma) |
4109 | return NULL; |
4110 | |
4111 | if (!ma->space->nested[0]) |
4112 | return ma; |
4113 | |
4114 | space = isl_multi_aff_get_space(multi: ma); |
4115 | space = isl_space_flatten_domain(space); |
4116 | ma = isl_multi_aff_reset_space(multi: ma, space); |
4117 | |
4118 | return ma; |
4119 | } |
4120 | |
4121 | /* Given a map space, return an isl_multi_aff that maps a wrapped copy |
4122 | * of the space to its domain. |
4123 | */ |
4124 | __isl_give isl_multi_aff *isl_multi_aff_domain_map(__isl_take isl_space *space) |
4125 | { |
4126 | int i; |
4127 | isl_size n_in; |
4128 | isl_local_space *ls; |
4129 | isl_multi_aff *ma; |
4130 | |
4131 | if (!space) |
4132 | return NULL; |
4133 | if (!isl_space_is_map(space)) |
4134 | isl_die(isl_space_get_ctx(space), isl_error_invalid, |
4135 | "not a map space" , goto error); |
4136 | |
4137 | n_in = isl_space_dim(space, type: isl_dim_in); |
4138 | if (n_in < 0) |
4139 | goto error; |
4140 | space = isl_space_domain_map(space); |
4141 | |
4142 | ma = isl_multi_aff_alloc(space: isl_space_copy(space)); |
4143 | if (n_in == 0) { |
4144 | isl_space_free(space); |
4145 | return ma; |
4146 | } |
4147 | |
4148 | space = isl_space_domain(space); |
4149 | ls = isl_local_space_from_space(space); |
4150 | for (i = 0; i < n_in; ++i) { |
4151 | isl_aff *aff; |
4152 | |
4153 | aff = isl_aff_var_on_domain(ls: isl_local_space_copy(ls), |
4154 | type: isl_dim_set, pos: i); |
4155 | ma = isl_multi_aff_set_aff(multi: ma, pos: i, el: aff); |
4156 | } |
4157 | isl_local_space_free(ls); |
4158 | return ma; |
4159 | error: |
4160 | isl_space_free(space); |
4161 | return NULL; |
4162 | } |
4163 | |
4164 | /* This function performs the same operation as isl_multi_aff_domain_map, |
4165 | * but is considered as a function on an isl_space when exported. |
4166 | */ |
4167 | __isl_give isl_multi_aff *isl_space_domain_map_multi_aff( |
4168 | __isl_take isl_space *space) |
4169 | { |
4170 | return isl_multi_aff_domain_map(space); |
4171 | } |
4172 | |
4173 | /* Given a map space, return an isl_multi_aff that maps a wrapped copy |
4174 | * of the space to its range. |
4175 | */ |
4176 | __isl_give isl_multi_aff *isl_multi_aff_range_map(__isl_take isl_space *space) |
4177 | { |
4178 | int i; |
4179 | isl_size n_in, n_out; |
4180 | isl_local_space *ls; |
4181 | isl_multi_aff *ma; |
4182 | |
4183 | if (!space) |
4184 | return NULL; |
4185 | if (!isl_space_is_map(space)) |
4186 | isl_die(isl_space_get_ctx(space), isl_error_invalid, |
4187 | "not a map space" , goto error); |
4188 | |
4189 | n_in = isl_space_dim(space, type: isl_dim_in); |
4190 | n_out = isl_space_dim(space, type: isl_dim_out); |
4191 | if (n_in < 0 || n_out < 0) |
4192 | goto error; |
4193 | space = isl_space_range_map(space); |
4194 | |
4195 | ma = isl_multi_aff_alloc(space: isl_space_copy(space)); |
4196 | if (n_out == 0) { |
4197 | isl_space_free(space); |
4198 | return ma; |
4199 | } |
4200 | |
4201 | space = isl_space_domain(space); |
4202 | ls = isl_local_space_from_space(space); |
4203 | for (i = 0; i < n_out; ++i) { |
4204 | isl_aff *aff; |
4205 | |
4206 | aff = isl_aff_var_on_domain(ls: isl_local_space_copy(ls), |
4207 | type: isl_dim_set, pos: n_in + i); |
4208 | ma = isl_multi_aff_set_aff(multi: ma, pos: i, el: aff); |
4209 | } |
4210 | isl_local_space_free(ls); |
4211 | return ma; |
4212 | error: |
4213 | isl_space_free(space); |
4214 | return NULL; |
4215 | } |
4216 | |
4217 | /* This function performs the same operation as isl_multi_aff_range_map, |
4218 | * but is considered as a function on an isl_space when exported. |
4219 | */ |
4220 | __isl_give isl_multi_aff *isl_space_range_map_multi_aff( |
4221 | __isl_take isl_space *space) |
4222 | { |
4223 | return isl_multi_aff_range_map(space); |
4224 | } |
4225 | |
4226 | /* Given a map space, return an isl_pw_multi_aff that maps a wrapped copy |
4227 | * of the space to its domain. |
4228 | */ |
4229 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_domain_map( |
4230 | __isl_take isl_space *space) |
4231 | { |
4232 | return isl_pw_multi_aff_from_multi_aff(ma: isl_multi_aff_domain_map(space)); |
4233 | } |
4234 | |
4235 | /* This function performs the same operation as isl_pw_multi_aff_domain_map, |
4236 | * but is considered as a function on an isl_space when exported. |
4237 | */ |
4238 | __isl_give isl_pw_multi_aff *isl_space_domain_map_pw_multi_aff( |
4239 | __isl_take isl_space *space) |
4240 | { |
4241 | return isl_pw_multi_aff_domain_map(space); |
4242 | } |
4243 | |
4244 | /* Given a map space, return an isl_pw_multi_aff that maps a wrapped copy |
4245 | * of the space to its range. |
4246 | */ |
4247 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_map( |
4248 | __isl_take isl_space *space) |
4249 | { |
4250 | return isl_pw_multi_aff_from_multi_aff(ma: isl_multi_aff_range_map(space)); |
4251 | } |
4252 | |
4253 | /* This function performs the same operation as isl_pw_multi_aff_range_map, |
4254 | * but is considered as a function on an isl_space when exported. |
4255 | */ |
4256 | __isl_give isl_pw_multi_aff *isl_space_range_map_pw_multi_aff( |
4257 | __isl_take isl_space *space) |
4258 | { |
4259 | return isl_pw_multi_aff_range_map(space); |
4260 | } |
4261 | |
4262 | /* Given the space of a set and a range of set dimensions, |
4263 | * construct an isl_multi_aff that projects out those dimensions. |
4264 | */ |
4265 | __isl_give isl_multi_aff *isl_multi_aff_project_out_map( |
4266 | __isl_take isl_space *space, enum isl_dim_type type, |
4267 | unsigned first, unsigned n) |
4268 | { |
4269 | int i; |
4270 | isl_size dim; |
4271 | isl_local_space *ls; |
4272 | isl_multi_aff *ma; |
4273 | |
4274 | if (!space) |
4275 | return NULL; |
4276 | if (!isl_space_is_set(space)) |
4277 | isl_die(isl_space_get_ctx(space), isl_error_unsupported, |
4278 | "expecting set space" , goto error); |
4279 | if (type != isl_dim_set) |
4280 | isl_die(isl_space_get_ctx(space), isl_error_invalid, |
4281 | "only set dimensions can be projected out" , goto error); |
4282 | if (isl_space_check_range(space, type, first, n) < 0) |
4283 | goto error; |
4284 | |
4285 | dim = isl_space_dim(space, type: isl_dim_set); |
4286 | if (dim < 0) |
4287 | goto error; |
4288 | |
4289 | space = isl_space_from_domain(space); |
4290 | space = isl_space_add_dims(space, type: isl_dim_out, n: dim - n); |
4291 | |
4292 | if (dim == n) |
4293 | return isl_multi_aff_alloc(space); |
4294 | |
4295 | ma = isl_multi_aff_alloc(space: isl_space_copy(space)); |
4296 | space = isl_space_domain(space); |
4297 | ls = isl_local_space_from_space(space); |
4298 | |
4299 | for (i = 0; i < first; ++i) { |
4300 | isl_aff *aff; |
4301 | |
4302 | aff = isl_aff_var_on_domain(ls: isl_local_space_copy(ls), |
4303 | type: isl_dim_set, pos: i); |
4304 | ma = isl_multi_aff_set_aff(multi: ma, pos: i, el: aff); |
4305 | } |
4306 | |
4307 | for (i = 0; i < dim - (first + n); ++i) { |
4308 | isl_aff *aff; |
4309 | |
4310 | aff = isl_aff_var_on_domain(ls: isl_local_space_copy(ls), |
4311 | type: isl_dim_set, pos: first + n + i); |
4312 | ma = isl_multi_aff_set_aff(multi: ma, pos: first + i, el: aff); |
4313 | } |
4314 | |
4315 | isl_local_space_free(ls); |
4316 | return ma; |
4317 | error: |
4318 | isl_space_free(space); |
4319 | return NULL; |
4320 | } |
4321 | |
4322 | /* Given the space of a set and a range of set dimensions, |
4323 | * construct an isl_pw_multi_aff that projects out those dimensions. |
4324 | */ |
4325 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_project_out_map( |
4326 | __isl_take isl_space *space, enum isl_dim_type type, |
4327 | unsigned first, unsigned n) |
4328 | { |
4329 | isl_multi_aff *ma; |
4330 | |
4331 | ma = isl_multi_aff_project_out_map(space, type, first, n); |
4332 | return isl_pw_multi_aff_from_multi_aff(ma); |
4333 | } |
4334 | |
4335 | /* This function performs the same operation as isl_pw_multi_aff_from_multi_aff, |
4336 | * but is considered as a function on an isl_multi_aff when exported. |
4337 | */ |
4338 | __isl_give isl_pw_multi_aff *isl_multi_aff_to_pw_multi_aff( |
4339 | __isl_take isl_multi_aff *ma) |
4340 | { |
4341 | return isl_pw_multi_aff_from_multi_aff(ma); |
4342 | } |
4343 | |
4344 | /* Create a piecewise multi-affine expression in the given space that maps each |
4345 | * input dimension to the corresponding output dimension. |
4346 | */ |
4347 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity( |
4348 | __isl_take isl_space *space) |
4349 | { |
4350 | return isl_pw_multi_aff_from_multi_aff(ma: isl_multi_aff_identity(space)); |
4351 | } |
4352 | |
4353 | /* Create a piecewise multi expression that maps elements in the given space |
4354 | * to themselves. |
4355 | */ |
4356 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_identity_on_domain_space( |
4357 | __isl_take isl_space *space) |
4358 | { |
4359 | isl_multi_aff *ma; |
4360 | |
4361 | ma = isl_multi_aff_identity_on_domain_space(space); |
4362 | return isl_pw_multi_aff_from_multi_aff(ma); |
4363 | } |
4364 | |
4365 | /* This function performs the same operation as |
4366 | * isl_pw_multi_aff_identity_on_domain_space, |
4367 | * but is considered as a function on an isl_space when exported. |
4368 | */ |
4369 | __isl_give isl_pw_multi_aff *isl_space_identity_pw_multi_aff_on_domain( |
4370 | __isl_take isl_space *space) |
4371 | { |
4372 | return isl_pw_multi_aff_identity_on_domain_space(space); |
4373 | } |
4374 | |
4375 | /* Exploit the equalities in "eq" to simplify the affine expressions. |
4376 | */ |
4377 | static __isl_give isl_multi_aff *isl_multi_aff_substitute_equalities( |
4378 | __isl_take isl_multi_aff *maff, __isl_take isl_basic_set *eq) |
4379 | { |
4380 | isl_size n; |
4381 | int i; |
4382 | |
4383 | n = isl_multi_aff_size(multi: maff); |
4384 | if (n < 0 || !eq) |
4385 | goto error; |
4386 | |
4387 | for (i = 0; i < n; ++i) { |
4388 | isl_aff *aff; |
4389 | |
4390 | aff = isl_multi_aff_take_at(multi: maff, pos: i); |
4391 | aff = isl_aff_substitute_equalities(aff, |
4392 | eq: isl_basic_set_copy(bset: eq)); |
4393 | maff = isl_multi_aff_restore_at(multi: maff, pos: i, el: aff); |
4394 | } |
4395 | |
4396 | isl_basic_set_free(bset: eq); |
4397 | return maff; |
4398 | error: |
4399 | isl_basic_set_free(bset: eq); |
4400 | isl_multi_aff_free(multi: maff); |
4401 | return NULL; |
4402 | } |
4403 | |
4404 | __isl_give isl_multi_aff *isl_multi_aff_scale(__isl_take isl_multi_aff *maff, |
4405 | isl_int f) |
4406 | { |
4407 | isl_size n; |
4408 | int i; |
4409 | |
4410 | n = isl_multi_aff_size(multi: maff); |
4411 | if (n < 0) |
4412 | return isl_multi_aff_free(multi: maff); |
4413 | |
4414 | for (i = 0; i < n; ++i) { |
4415 | isl_aff *aff; |
4416 | |
4417 | aff = isl_multi_aff_take_at(multi: maff, pos: i); |
4418 | aff = isl_aff_scale(aff, f); |
4419 | maff = isl_multi_aff_restore_at(multi: maff, pos: i, el: aff); |
4420 | } |
4421 | |
4422 | return maff; |
4423 | } |
4424 | |
4425 | __isl_give isl_multi_aff *isl_multi_aff_add_on_domain(__isl_keep isl_set *dom, |
4426 | __isl_take isl_multi_aff *maff1, __isl_take isl_multi_aff *maff2) |
4427 | { |
4428 | maff1 = isl_multi_aff_add(multi1: maff1, multi2: maff2); |
4429 | maff1 = isl_multi_aff_gist(multi: maff1, context: isl_set_copy(set: dom)); |
4430 | return maff1; |
4431 | } |
4432 | |
4433 | isl_bool isl_multi_aff_is_empty(__isl_keep isl_multi_aff *maff) |
4434 | { |
4435 | if (!maff) |
4436 | return isl_bool_error; |
4437 | |
4438 | return isl_bool_false; |
4439 | } |
4440 | |
4441 | /* Return the set of domain elements where "ma1" is lexicographically |
4442 | * smaller than or equal to "ma2". |
4443 | */ |
4444 | __isl_give isl_set *isl_multi_aff_lex_le_set(__isl_take isl_multi_aff *ma1, |
4445 | __isl_take isl_multi_aff *ma2) |
4446 | { |
4447 | return isl_multi_aff_lex_ge_set(ma1: ma2, ma2: ma1); |
4448 | } |
4449 | |
4450 | /* Return the set of domain elements where "ma1" is lexicographically |
4451 | * smaller than "ma2". |
4452 | */ |
4453 | __isl_give isl_set *isl_multi_aff_lex_lt_set(__isl_take isl_multi_aff *ma1, |
4454 | __isl_take isl_multi_aff *ma2) |
4455 | { |
4456 | return isl_multi_aff_lex_gt_set(ma1: ma2, ma2: ma1); |
4457 | } |
4458 | |
4459 | /* Return the set of domain elements where "ma1" is lexicographically |
4460 | * greater than to "ma2". If "equal" is set, then include the domain |
4461 | * elements where they are equal. |
4462 | * Do this for the case where there are no entries. |
4463 | * In this case, "ma1" cannot be greater than "ma2", |
4464 | * but it is (greater than or) equal to "ma2". |
4465 | */ |
4466 | static __isl_give isl_set *isl_multi_aff_lex_gte_set_0d( |
4467 | __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2, int equal) |
4468 | { |
4469 | isl_space *space; |
4470 | |
4471 | space = isl_multi_aff_get_domain_space(multi: ma1); |
4472 | |
4473 | isl_multi_aff_free(multi: ma1); |
4474 | isl_multi_aff_free(multi: ma2); |
4475 | |
4476 | if (equal) |
4477 | return isl_set_universe(space); |
4478 | else |
4479 | return isl_set_empty(space); |
4480 | } |
4481 | |
4482 | /* Return the set where entry "i" of "ma1" and "ma2" |
4483 | * satisfy the relation prescribed by "cmp". |
4484 | */ |
4485 | static __isl_give isl_set *isl_multi_aff_order_at(__isl_keep isl_multi_aff *ma1, |
4486 | __isl_keep isl_multi_aff *ma2, int i, |
4487 | __isl_give isl_set *(*cmp)(__isl_take isl_aff *aff1, |
4488 | __isl_take isl_aff *aff2)) |
4489 | { |
4490 | isl_aff *aff1, *aff2; |
4491 | |
4492 | aff1 = isl_multi_aff_get_at(multi: ma1, pos: i); |
4493 | aff2 = isl_multi_aff_get_at(multi: ma2, pos: i); |
4494 | return cmp(aff1, aff2); |
4495 | } |
4496 | |
4497 | /* Return the set of domain elements where "ma1" is lexicographically |
4498 | * greater than to "ma2". If "equal" is set, then include the domain |
4499 | * elements where they are equal. |
4500 | * |
4501 | * In particular, for all but the final entry, |
4502 | * include the set of elements where this entry is strictly greater in "ma1" |
4503 | * and all previous entries are equal. |
4504 | * The final entry is also allowed to be equal in the two functions |
4505 | * if "equal" is set. |
4506 | * |
4507 | * The case where there are no entries is handled separately. |
4508 | */ |
4509 | static __isl_give isl_set *isl_multi_aff_lex_gte_set( |
4510 | __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2, int equal) |
4511 | { |
4512 | int i; |
4513 | isl_size n; |
4514 | isl_space *space; |
4515 | isl_set *res; |
4516 | isl_set *equal_set; |
4517 | isl_set *gte; |
4518 | |
4519 | if (isl_multi_aff_check_equal_space(obj1: ma1, obj2: ma2) < 0) |
4520 | goto error; |
4521 | n = isl_multi_aff_size(multi: ma1); |
4522 | if (n < 0) |
4523 | goto error; |
4524 | if (n == 0) |
4525 | return isl_multi_aff_lex_gte_set_0d(ma1, ma2, equal); |
4526 | |
4527 | space = isl_multi_aff_get_domain_space(multi: ma1); |
4528 | res = isl_set_empty(space: isl_space_copy(space)); |
4529 | equal_set = isl_set_universe(space); |
4530 | |
4531 | for (i = 0; i + 1 < n; ++i) { |
4532 | isl_bool empty; |
4533 | isl_set *gt, *eq; |
4534 | |
4535 | gt = isl_multi_aff_order_at(ma1, ma2, i, cmp: &isl_aff_gt_set); |
4536 | gt = isl_set_intersect(set1: gt, set2: isl_set_copy(set: equal_set)); |
4537 | res = isl_set_union(set1: res, set2: gt); |
4538 | eq = isl_multi_aff_order_at(ma1, ma2, i, cmp: &isl_aff_eq_set); |
4539 | equal_set = isl_set_intersect(set1: equal_set, set2: eq); |
4540 | |
4541 | empty = isl_set_is_empty(set: equal_set); |
4542 | if (empty >= 0 && empty) |
4543 | break; |
4544 | } |
4545 | |
4546 | if (equal) |
4547 | gte = isl_multi_aff_order_at(ma1, ma2, i: n - 1, cmp: &isl_aff_ge_set); |
4548 | else |
4549 | gte = isl_multi_aff_order_at(ma1, ma2, i: n - 1, cmp: &isl_aff_gt_set); |
4550 | isl_multi_aff_free(multi: ma1); |
4551 | isl_multi_aff_free(multi: ma2); |
4552 | |
4553 | gte = isl_set_intersect(set1: gte, set2: equal_set); |
4554 | return isl_set_union(set1: res, set2: gte); |
4555 | error: |
4556 | isl_multi_aff_free(multi: ma1); |
4557 | isl_multi_aff_free(multi: ma2); |
4558 | return NULL; |
4559 | } |
4560 | |
4561 | /* Return the set of domain elements where "ma1" is lexicographically |
4562 | * greater than or equal to "ma2". |
4563 | */ |
4564 | __isl_give isl_set *isl_multi_aff_lex_ge_set(__isl_take isl_multi_aff *ma1, |
4565 | __isl_take isl_multi_aff *ma2) |
4566 | { |
4567 | return isl_multi_aff_lex_gte_set(ma1, ma2, equal: 1); |
4568 | } |
4569 | |
4570 | /* Return the set of domain elements where "ma1" is lexicographically |
4571 | * greater than "ma2". |
4572 | */ |
4573 | __isl_give isl_set *isl_multi_aff_lex_gt_set(__isl_take isl_multi_aff *ma1, |
4574 | __isl_take isl_multi_aff *ma2) |
4575 | { |
4576 | return isl_multi_aff_lex_gte_set(ma1, ma2, equal: 0); |
4577 | } |
4578 | |
4579 | #define isl_multi_aff_zero_in_space isl_multi_aff_zero |
4580 | |
4581 | #undef PW |
4582 | #define PW isl_pw_multi_aff |
4583 | #undef BASE |
4584 | #define BASE multi_aff |
4585 | #undef EL_IS_ZERO |
4586 | #define EL_IS_ZERO is_empty |
4587 | #undef ZERO |
4588 | #define ZERO empty |
4589 | #undef IS_ZERO |
4590 | #define IS_ZERO is_empty |
4591 | #undef FIELD |
4592 | #define FIELD maff |
4593 | #undef DEFAULT_IS_ZERO |
4594 | #define DEFAULT_IS_ZERO 0 |
4595 | |
4596 | #include <isl_pw_templ.c> |
4597 | #include <isl_pw_un_op_templ.c> |
4598 | #include <isl_pw_add_constant_multi_val_templ.c> |
4599 | #include <isl_pw_add_constant_val_templ.c> |
4600 | #include <isl_pw_add_disjoint_templ.c> |
4601 | #include <isl_pw_bind_domain_templ.c> |
4602 | #include <isl_pw_fix_templ.c> |
4603 | #include <isl_pw_from_range_templ.c> |
4604 | #include <isl_pw_insert_dims_templ.c> |
4605 | #include <isl_pw_insert_domain_templ.c> |
4606 | #include <isl_pw_locals_templ.c> |
4607 | #include <isl_pw_move_dims_templ.c> |
4608 | #include <isl_pw_neg_templ.c> |
4609 | #include <isl_pw_pullback_templ.c> |
4610 | #include <isl_pw_range_tuple_id_templ.c> |
4611 | #include <isl_pw_union_opt.c> |
4612 | |
4613 | #undef BASE |
4614 | #define BASE pw_multi_aff |
4615 | |
4616 | #include <isl_union_multi.c> |
4617 | #include "isl_union_locals_templ.c" |
4618 | #include <isl_union_neg.c> |
4619 | #include <isl_union_sub_templ.c> |
4620 | |
4621 | #undef BASE |
4622 | #define BASE multi_aff |
4623 | |
4624 | #include <isl_union_pw_templ.c> |
4625 | |
4626 | /* Generic function for extracting a factor from a product "pma". |
4627 | * "check_space" checks that the space is that of the right kind of product. |
4628 | * "space_factor" extracts the factor from the space. |
4629 | * "multi_aff_factor" extracts the factor from the constituent functions. |
4630 | */ |
4631 | static __isl_give isl_pw_multi_aff *pw_multi_aff_factor( |
4632 | __isl_take isl_pw_multi_aff *pma, |
4633 | isl_stat (*check_space)(__isl_keep isl_pw_multi_aff *pma), |
4634 | __isl_give isl_space *(*space_factor)(__isl_take isl_space *space), |
4635 | __isl_give isl_multi_aff *(*multi_aff_factor)( |
4636 | __isl_take isl_multi_aff *ma)) |
4637 | { |
4638 | int i; |
4639 | isl_space *space; |
4640 | |
4641 | if (check_space(pma) < 0) |
4642 | return isl_pw_multi_aff_free(pw: pma); |
4643 | |
4644 | space = isl_pw_multi_aff_take_space(pw: pma); |
4645 | space = space_factor(space); |
4646 | |
4647 | for (i = 0; pma && i < pma->n; ++i) { |
4648 | isl_multi_aff *ma; |
4649 | |
4650 | ma = isl_pw_multi_aff_take_base_at(pw: pma, pos: i); |
4651 | ma = multi_aff_factor(ma); |
4652 | pma = isl_pw_multi_aff_restore_base_at(pw: pma, pos: i, el: ma); |
4653 | } |
4654 | |
4655 | pma = isl_pw_multi_aff_restore_space(pw: pma, space); |
4656 | |
4657 | return pma; |
4658 | } |
4659 | |
4660 | /* Is the range of "pma" a wrapped relation? |
4661 | */ |
4662 | static isl_bool isl_pw_multi_aff_range_is_wrapping( |
4663 | __isl_keep isl_pw_multi_aff *pma) |
4664 | { |
4665 | return isl_space_range_is_wrapping(space: isl_pw_multi_aff_peek_space(pw: pma)); |
4666 | } |
4667 | |
4668 | /* Check that the range of "pma" is a product. |
4669 | */ |
4670 | static isl_stat pw_multi_aff_check_range_product( |
4671 | __isl_keep isl_pw_multi_aff *pma) |
4672 | { |
4673 | isl_bool wraps; |
4674 | |
4675 | wraps = isl_pw_multi_aff_range_is_wrapping(pma); |
4676 | if (wraps < 0) |
4677 | return isl_stat_error; |
4678 | if (!wraps) |
4679 | isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, |
4680 | "range is not a product" , return isl_stat_error); |
4681 | return isl_stat_ok; |
4682 | } |
4683 | |
4684 | /* Given a function A -> [B -> C], extract the function A -> B. |
4685 | */ |
4686 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_factor_domain( |
4687 | __isl_take isl_pw_multi_aff *pma) |
4688 | { |
4689 | return pw_multi_aff_factor(pma, check_space: &pw_multi_aff_check_range_product, |
4690 | space_factor: &isl_space_range_factor_domain, |
4691 | multi_aff_factor: &isl_multi_aff_range_factor_domain); |
4692 | } |
4693 | |
4694 | /* Given a function A -> [B -> C], extract the function A -> C. |
4695 | */ |
4696 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_factor_range( |
4697 | __isl_take isl_pw_multi_aff *pma) |
4698 | { |
4699 | return pw_multi_aff_factor(pma, check_space: &pw_multi_aff_check_range_product, |
4700 | space_factor: &isl_space_range_factor_range, |
4701 | multi_aff_factor: &isl_multi_aff_range_factor_range); |
4702 | } |
4703 | |
4704 | /* Given two piecewise multi affine expressions, return a piecewise |
4705 | * multi-affine expression defined on the union of the definition domains |
4706 | * of the inputs that is equal to the lexicographic maximum of the two |
4707 | * inputs on each cell. If only one of the two inputs is defined on |
4708 | * a given cell, then it is considered to be the maximum. |
4709 | */ |
4710 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmax( |
4711 | __isl_take isl_pw_multi_aff *pma1, |
4712 | __isl_take isl_pw_multi_aff *pma2) |
4713 | { |
4714 | isl_pw_multi_aff_align_params_bin(obj1: &pma1, obj2: &pma2); |
4715 | return isl_pw_multi_aff_union_opt_cmp(pw1: pma1, pw2: pma2, |
4716 | cmp: &isl_multi_aff_lex_ge_set); |
4717 | } |
4718 | |
4719 | /* Given two piecewise multi affine expressions, return a piecewise |
4720 | * multi-affine expression defined on the union of the definition domains |
4721 | * of the inputs that is equal to the lexicographic minimum of the two |
4722 | * inputs on each cell. If only one of the two inputs is defined on |
4723 | * a given cell, then it is considered to be the minimum. |
4724 | */ |
4725 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_union_lexmin( |
4726 | __isl_take isl_pw_multi_aff *pma1, |
4727 | __isl_take isl_pw_multi_aff *pma2) |
4728 | { |
4729 | isl_pw_multi_aff_align_params_bin(obj1: &pma1, obj2: &pma2); |
4730 | return isl_pw_multi_aff_union_opt_cmp(pw1: pma1, pw2: pma2, |
4731 | cmp: &isl_multi_aff_lex_le_set); |
4732 | } |
4733 | |
4734 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_add( |
4735 | __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) |
4736 | { |
4737 | isl_pw_multi_aff_align_params_bin(obj1: &pma1, obj2: &pma2); |
4738 | return isl_pw_multi_aff_on_shared_domain(pw1: pma1, pw2: pma2, |
4739 | fn: &isl_multi_aff_add); |
4740 | } |
4741 | |
4742 | /* Subtract "pma2" from "pma1" and return the result. |
4743 | */ |
4744 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_sub( |
4745 | __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) |
4746 | { |
4747 | isl_pw_multi_aff_align_params_bin(obj1: &pma1, obj2: &pma2); |
4748 | return isl_pw_multi_aff_on_shared_domain(pw1: pma1, pw2: pma2, |
4749 | fn: &isl_multi_aff_sub); |
4750 | } |
4751 | |
4752 | /* Given two piecewise multi-affine expressions A -> B and C -> D, |
4753 | * construct a piecewise multi-affine expression [A -> C] -> [B -> D]. |
4754 | */ |
4755 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_product( |
4756 | __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) |
4757 | { |
4758 | int i, j, n; |
4759 | isl_space *space; |
4760 | isl_pw_multi_aff *res; |
4761 | |
4762 | if (isl_pw_multi_aff_align_params_bin(obj1: &pma1, obj2: &pma2) < 0) |
4763 | goto error; |
4764 | |
4765 | n = pma1->n * pma2->n; |
4766 | space = isl_space_product(left: isl_space_copy(space: pma1->dim), |
4767 | right: isl_space_copy(space: pma2->dim)); |
4768 | res = isl_pw_multi_aff_alloc_size(space, n); |
4769 | |
4770 | for (i = 0; i < pma1->n; ++i) { |
4771 | for (j = 0; j < pma2->n; ++j) { |
4772 | isl_set *domain; |
4773 | isl_multi_aff *ma; |
4774 | |
4775 | domain = isl_set_product(set1: isl_set_copy(set: pma1->p[i].set), |
4776 | set2: isl_set_copy(set: pma2->p[j].set)); |
4777 | ma = isl_multi_aff_product( |
4778 | multi1: isl_multi_aff_copy(multi: pma1->p[i].maff), |
4779 | multi2: isl_multi_aff_copy(multi: pma2->p[j].maff)); |
4780 | res = isl_pw_multi_aff_add_piece(pw: res, set: domain, el: ma); |
4781 | } |
4782 | } |
4783 | |
4784 | isl_pw_multi_aff_free(pw: pma1); |
4785 | isl_pw_multi_aff_free(pw: pma2); |
4786 | return res; |
4787 | error: |
4788 | isl_pw_multi_aff_free(pw: pma1); |
4789 | isl_pw_multi_aff_free(pw: pma2); |
4790 | return NULL; |
4791 | } |
4792 | |
4793 | /* Subtract the initial "n" elements in "ma" with coefficients in "c" and |
4794 | * denominator "denom". |
4795 | * "denom" is allowed to be negative, in which case the actual denominator |
4796 | * is -denom and the expressions are added instead. |
4797 | */ |
4798 | static __isl_give isl_aff *subtract_initial(__isl_take isl_aff *aff, |
4799 | __isl_keep isl_multi_aff *ma, int n, isl_int *c, isl_int denom) |
4800 | { |
4801 | int i, first; |
4802 | int sign; |
4803 | isl_int d; |
4804 | |
4805 | first = isl_seq_first_non_zero(p: c, len: n); |
4806 | if (first == -1) |
4807 | return aff; |
4808 | |
4809 | sign = isl_int_sgn(denom); |
4810 | isl_int_init(d); |
4811 | isl_int_abs(d, denom); |
4812 | for (i = first; i < n; ++i) { |
4813 | isl_aff *aff_i; |
4814 | |
4815 | if (isl_int_is_zero(c[i])) |
4816 | continue; |
4817 | aff_i = isl_multi_aff_get_aff(multi: ma, pos: i); |
4818 | aff_i = isl_aff_scale(aff: aff_i, f: c[i]); |
4819 | aff_i = isl_aff_scale_down(aff: aff_i, f: d); |
4820 | if (sign >= 0) |
4821 | aff = isl_aff_sub(aff1: aff, aff2: aff_i); |
4822 | else |
4823 | aff = isl_aff_add(aff1: aff, aff2: aff_i); |
4824 | } |
4825 | isl_int_clear(d); |
4826 | |
4827 | return aff; |
4828 | } |
4829 | |
4830 | /* Extract an affine expression that expresses the output dimension "pos" |
4831 | * of "bmap" in terms of the parameters and input dimensions from |
4832 | * equality "eq". |
4833 | * Note that this expression may involve integer divisions defined |
4834 | * in terms of parameters and input dimensions. |
4835 | * The equality may also involve references to earlier (but not later) |
4836 | * output dimensions. These are replaced by the corresponding elements |
4837 | * in "ma". |
4838 | * |
4839 | * If the equality is of the form |
4840 | * |
4841 | * f(i) + h(j) + a x + g(i) = 0, |
4842 | * |
4843 | * with f(i) a linear combinations of the parameters and input dimensions, |
4844 | * g(i) a linear combination of integer divisions defined in terms of the same |
4845 | * and h(j) a linear combinations of earlier output dimensions, |
4846 | * then the affine expression is |
4847 | * |
4848 | * (-f(i) - g(i))/a - h(j)/a |
4849 | * |
4850 | * If the equality is of the form |
4851 | * |
4852 | * f(i) + h(j) - a x + g(i) = 0, |
4853 | * |
4854 | * then the affine expression is |
4855 | * |
4856 | * (f(i) + g(i))/a - h(j)/(-a) |
4857 | * |
4858 | * |
4859 | * If "div" refers to an integer division (i.e., it is smaller than |
4860 | * the number of integer divisions), then the equality constraint |
4861 | * does involve an integer division (the one at position "div") that |
4862 | * is defined in terms of output dimensions. However, this integer |
4863 | * division can be eliminated by exploiting a pair of constraints |
4864 | * x >= l and x <= l + n, with n smaller than the coefficient of "div" |
4865 | * in the equality constraint. "ineq" refers to inequality x >= l, i.e., |
4866 | * -l + x >= 0. |
4867 | * In particular, let |
4868 | * |
4869 | * x = e(i) + m floor(...) |
4870 | * |
4871 | * with e(i) the expression derived above and floor(...) the integer |
4872 | * division involving output dimensions. |
4873 | * From |
4874 | * |
4875 | * l <= x <= l + n, |
4876 | * |
4877 | * we have |
4878 | * |
4879 | * 0 <= x - l <= n |
4880 | * |
4881 | * This means |
4882 | * |
4883 | * e(i) + m floor(...) - l = (e(i) + m floor(...) - l) mod m |
4884 | * = (e(i) - l) mod m |
4885 | * |
4886 | * Therefore, |
4887 | * |
4888 | * x - l = (e(i) - l) mod m |
4889 | * |
4890 | * or |
4891 | * |
4892 | * x = ((e(i) - l) mod m) + l |
4893 | * |
4894 | * The variable "shift" below contains the expression -l, which may |
4895 | * also involve a linear combination of earlier output dimensions. |
4896 | */ |
4897 | static __isl_give isl_aff *( |
4898 | __isl_keep isl_basic_map *bmap, int pos, int eq, int div, int ineq, |
4899 | __isl_keep isl_multi_aff *ma) |
4900 | { |
4901 | unsigned o_out; |
4902 | isl_size n_div, n_out; |
4903 | isl_ctx *ctx; |
4904 | isl_local_space *ls; |
4905 | isl_aff *aff, *shift; |
4906 | isl_val *mod; |
4907 | |
4908 | ctx = isl_basic_map_get_ctx(bmap); |
4909 | ls = isl_basic_map_get_local_space(bmap); |
4910 | ls = isl_local_space_domain(ls); |
4911 | aff = isl_aff_alloc(ls: isl_local_space_copy(ls)); |
4912 | if (!aff) |
4913 | goto error; |
4914 | o_out = isl_basic_map_offset(bmap, type: isl_dim_out); |
4915 | n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
4916 | n_div = isl_basic_map_dim(bmap, type: isl_dim_div); |
4917 | if (n_out < 0 || n_div < 0) |
4918 | goto error; |
4919 | if (isl_int_is_neg(bmap->eq[eq][o_out + pos])) { |
4920 | isl_seq_cpy(dst: aff->v->el + 1, src: bmap->eq[eq], len: o_out); |
4921 | isl_seq_cpy(dst: aff->v->el + 1 + o_out, |
4922 | src: bmap->eq[eq] + o_out + n_out, len: n_div); |
4923 | } else { |
4924 | isl_seq_neg(dst: aff->v->el + 1, src: bmap->eq[eq], len: o_out); |
4925 | isl_seq_neg(dst: aff->v->el + 1 + o_out, |
4926 | src: bmap->eq[eq] + o_out + n_out, len: n_div); |
4927 | } |
4928 | if (div < n_div) |
4929 | isl_int_set_si(aff->v->el[1 + o_out + div], 0); |
4930 | isl_int_abs(aff->v->el[0], bmap->eq[eq][o_out + pos]); |
4931 | aff = subtract_initial(aff, ma, n: pos, c: bmap->eq[eq] + o_out, |
4932 | denom: bmap->eq[eq][o_out + pos]); |
4933 | if (div < n_div) { |
4934 | shift = isl_aff_alloc(ls: isl_local_space_copy(ls)); |
4935 | if (!shift) |
4936 | goto error; |
4937 | isl_seq_cpy(dst: shift->v->el + 1, src: bmap->ineq[ineq], len: o_out); |
4938 | isl_seq_cpy(dst: shift->v->el + 1 + o_out, |
4939 | src: bmap->ineq[ineq] + o_out + n_out, len: n_div); |
4940 | isl_int_set_si(shift->v->el[0], 1); |
4941 | shift = subtract_initial(aff: shift, ma, n: pos, |
4942 | c: bmap->ineq[ineq] + o_out, denom: ctx->negone); |
4943 | aff = isl_aff_add(aff1: aff, aff2: isl_aff_copy(aff: shift)); |
4944 | mod = isl_val_int_from_isl_int(ctx, |
4945 | n: bmap->eq[eq][o_out + n_out + div]); |
4946 | mod = isl_val_abs(v: mod); |
4947 | aff = isl_aff_mod_val(aff, m: mod); |
4948 | aff = isl_aff_sub(aff1: aff, aff2: shift); |
4949 | } |
4950 | |
4951 | isl_local_space_free(ls); |
4952 | return aff; |
4953 | error: |
4954 | isl_local_space_free(ls); |
4955 | isl_aff_free(aff); |
4956 | return NULL; |
4957 | } |
4958 | |
4959 | /* Given a basic map with output dimensions defined |
4960 | * in terms of the parameters input dimensions and earlier |
4961 | * output dimensions using an equality (and possibly a pair on inequalities), |
4962 | * extract an isl_aff that expresses output dimension "pos" in terms |
4963 | * of the parameters and input dimensions. |
4964 | * Note that this expression may involve integer divisions defined |
4965 | * in terms of parameters and input dimensions. |
4966 | * "ma" contains the expressions corresponding to earlier output dimensions. |
4967 | * |
4968 | * This function shares some similarities with |
4969 | * isl_basic_map_has_defining_equality and isl_constraint_get_bound. |
4970 | */ |
4971 | static __isl_give isl_aff *( |
4972 | __isl_keep isl_basic_map *bmap, int pos, __isl_keep isl_multi_aff *ma) |
4973 | { |
4974 | int eq, div, ineq; |
4975 | isl_aff *aff; |
4976 | |
4977 | if (!bmap) |
4978 | return NULL; |
4979 | eq = isl_basic_map_output_defining_equality(bmap, pos, div: &div, ineq: &ineq); |
4980 | if (eq >= bmap->n_eq) |
4981 | isl_die(isl_basic_map_get_ctx(bmap), isl_error_invalid, |
4982 | "unable to find suitable equality" , return NULL); |
4983 | aff = extract_aff_from_equality(bmap, pos, eq, div, ineq, ma); |
4984 | |
4985 | aff = isl_aff_remove_unused_divs(aff); |
4986 | return aff; |
4987 | } |
4988 | |
4989 | /* Given a basic map where each output dimension is defined |
4990 | * in terms of the parameters and input dimensions using an equality, |
4991 | * extract an isl_multi_aff that expresses the output dimensions in terms |
4992 | * of the parameters and input dimensions. |
4993 | */ |
4994 | static __isl_give isl_multi_aff *( |
4995 | __isl_take isl_basic_map *bmap) |
4996 | { |
4997 | int i; |
4998 | isl_size n_out; |
4999 | isl_multi_aff *ma; |
5000 | |
5001 | if (!bmap) |
5002 | return NULL; |
5003 | |
5004 | ma = isl_multi_aff_alloc(space: isl_basic_map_get_space(bmap)); |
5005 | n_out = isl_basic_map_dim(bmap, type: isl_dim_out); |
5006 | if (n_out < 0) |
5007 | ma = isl_multi_aff_free(multi: ma); |
5008 | |
5009 | for (i = 0; i < n_out; ++i) { |
5010 | isl_aff *aff; |
5011 | |
5012 | aff = extract_isl_aff_from_basic_map(bmap, pos: i, ma); |
5013 | ma = isl_multi_aff_set_aff(multi: ma, pos: i, el: aff); |
5014 | } |
5015 | |
5016 | isl_basic_map_free(bmap); |
5017 | |
5018 | return ma; |
5019 | } |
5020 | |
5021 | /* Given a basic set where each set dimension is defined |
5022 | * in terms of the parameters using an equality, |
5023 | * extract an isl_multi_aff that expresses the set dimensions in terms |
5024 | * of the parameters. |
5025 | */ |
5026 | __isl_give isl_multi_aff *isl_multi_aff_from_basic_set_equalities( |
5027 | __isl_take isl_basic_set *bset) |
5028 | { |
5029 | return extract_isl_multi_aff_from_basic_map(bmap: bset); |
5030 | } |
5031 | |
5032 | /* Create an isl_pw_multi_aff that is equivalent to |
5033 | * isl_map_intersect_domain(isl_map_from_basic_map(bmap), domain). |
5034 | * The given basic map is such that each output dimension is defined |
5035 | * in terms of the parameters and input dimensions using an equality. |
5036 | * |
5037 | * Since some applications expect the result of isl_pw_multi_aff_from_map |
5038 | * to only contain integer affine expressions, we compute the floor |
5039 | * of the expression before returning. |
5040 | * |
5041 | * Remove all constraints involving local variables without |
5042 | * an explicit representation (resulting in the removal of those |
5043 | * local variables) prior to the actual extraction to ensure |
5044 | * that the local spaces in which the resulting affine expressions |
5045 | * are created do not contain any unknown local variables. |
5046 | * Removing such constraints is safe because constraints involving |
5047 | * unknown local variables are not used to determine whether |
5048 | * a basic map is obviously single-valued. |
5049 | */ |
5050 | static __isl_give isl_pw_multi_aff *plain_pw_multi_aff_from_map( |
5051 | __isl_take isl_set *domain, __isl_take isl_basic_map *bmap) |
5052 | { |
5053 | isl_multi_aff *ma; |
5054 | |
5055 | bmap = isl_basic_map_drop_constraints_involving_unknown_divs(bmap); |
5056 | ma = extract_isl_multi_aff_from_basic_map(bmap); |
5057 | ma = isl_multi_aff_floor(multi: ma); |
5058 | return isl_pw_multi_aff_alloc(set: domain, el: ma); |
5059 | } |
5060 | |
5061 | /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map. |
5062 | * This obviously only works if the input "map" is single-valued. |
5063 | * If so, we compute the lexicographic minimum of the image in the form |
5064 | * of an isl_pw_multi_aff. Since the image is unique, it is equal |
5065 | * to its lexicographic minimum. |
5066 | * If the input is not single-valued, we produce an error. |
5067 | */ |
5068 | static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_base( |
5069 | __isl_take isl_map *map) |
5070 | { |
5071 | int i; |
5072 | int sv; |
5073 | isl_pw_multi_aff *pma; |
5074 | |
5075 | sv = isl_map_is_single_valued(map); |
5076 | if (sv < 0) |
5077 | goto error; |
5078 | if (!sv) |
5079 | isl_die(isl_map_get_ctx(map), isl_error_invalid, |
5080 | "map is not single-valued" , goto error); |
5081 | map = isl_map_make_disjoint(map); |
5082 | if (!map) |
5083 | return NULL; |
5084 | |
5085 | pma = isl_pw_multi_aff_empty(space: isl_map_get_space(map)); |
5086 | |
5087 | for (i = 0; i < map->n; ++i) { |
5088 | isl_pw_multi_aff *pma_i; |
5089 | isl_basic_map *bmap; |
5090 | bmap = isl_basic_map_copy(bmap: map->p[i]); |
5091 | pma_i = isl_basic_map_lexmin_pw_multi_aff(bmap); |
5092 | pma = isl_pw_multi_aff_add_disjoint(pw1: pma, pw2: pma_i); |
5093 | } |
5094 | |
5095 | isl_map_free(map); |
5096 | return pma; |
5097 | error: |
5098 | isl_map_free(map); |
5099 | return NULL; |
5100 | } |
5101 | |
5102 | /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map, |
5103 | * taking into account that the output dimension at position "d" |
5104 | * can be represented as |
5105 | * |
5106 | * x = floor((e(...) + c1) / m) |
5107 | * |
5108 | * given that constraint "i" is of the form |
5109 | * |
5110 | * e(...) + c1 - m x >= 0 |
5111 | * |
5112 | * |
5113 | * Let "map" be of the form |
5114 | * |
5115 | * A -> B |
5116 | * |
5117 | * We construct a mapping |
5118 | * |
5119 | * A -> [A -> x = floor(...)] |
5120 | * |
5121 | * apply that to the map, obtaining |
5122 | * |
5123 | * [A -> x = floor(...)] -> B |
5124 | * |
5125 | * and equate dimension "d" to x. |
5126 | * We then compute a isl_pw_multi_aff representation of the resulting map |
5127 | * and plug in the mapping above. |
5128 | */ |
5129 | static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_div( |
5130 | __isl_take isl_map *map, __isl_take isl_basic_map *hull, int d, int i) |
5131 | { |
5132 | isl_ctx *ctx; |
5133 | isl_space *space = NULL; |
5134 | isl_local_space *ls; |
5135 | isl_multi_aff *ma; |
5136 | isl_aff *aff; |
5137 | isl_vec *v; |
5138 | isl_map *insert; |
5139 | int offset; |
5140 | isl_size n; |
5141 | isl_size n_in; |
5142 | isl_pw_multi_aff *pma; |
5143 | isl_bool is_set; |
5144 | |
5145 | is_set = isl_map_is_set(map); |
5146 | if (is_set < 0) |
5147 | goto error; |
5148 | |
5149 | offset = isl_basic_map_offset(bmap: hull, type: isl_dim_out); |
5150 | ctx = isl_map_get_ctx(map); |
5151 | space = isl_space_domain(space: isl_map_get_space(map)); |
5152 | n_in = isl_space_dim(space, type: isl_dim_set); |
5153 | n = isl_space_dim(space, type: isl_dim_all); |
5154 | if (n_in < 0 || n < 0) |
5155 | goto error; |
5156 | |
5157 | v = isl_vec_alloc(ctx, size: 1 + 1 + n); |
5158 | if (v) { |
5159 | isl_int_neg(v->el[0], hull->ineq[i][offset + d]); |
5160 | isl_seq_cpy(dst: v->el + 1, src: hull->ineq[i], len: 1 + n); |
5161 | } |
5162 | isl_basic_map_free(bmap: hull); |
5163 | |
5164 | ls = isl_local_space_from_space(space: isl_space_copy(space)); |
5165 | aff = isl_aff_alloc_vec_validated(ls, v); |
5166 | aff = isl_aff_floor(aff); |
5167 | if (is_set) { |
5168 | isl_space_free(space); |
5169 | ma = isl_multi_aff_from_aff(el: aff); |
5170 | } else { |
5171 | ma = isl_multi_aff_identity(space: isl_space_map_from_set(space)); |
5172 | ma = isl_multi_aff_range_product(multi1: ma, |
5173 | multi2: isl_multi_aff_from_aff(el: aff)); |
5174 | } |
5175 | |
5176 | insert = isl_map_from_multi_aff_internal(ma: isl_multi_aff_copy(multi: ma)); |
5177 | map = isl_map_apply_domain(map1: map, map2: insert); |
5178 | map = isl_map_equate(map, type1: isl_dim_in, pos1: n_in, type2: isl_dim_out, pos2: d); |
5179 | pma = isl_pw_multi_aff_from_map(map); |
5180 | pma = isl_pw_multi_aff_pullback_multi_aff(pw: pma, ma); |
5181 | |
5182 | return pma; |
5183 | error: |
5184 | isl_space_free(space); |
5185 | isl_map_free(map); |
5186 | isl_basic_map_free(bmap: hull); |
5187 | return NULL; |
5188 | } |
5189 | |
5190 | /* Is constraint "c" of the form |
5191 | * |
5192 | * e(...) + c1 - m x >= 0 |
5193 | * |
5194 | * or |
5195 | * |
5196 | * -e(...) + c2 + m x >= 0 |
5197 | * |
5198 | * where m > 1 and e only depends on parameters and input dimensions? |
5199 | * |
5200 | * "offset" is the offset of the output dimensions |
5201 | * "pos" is the position of output dimension x. |
5202 | */ |
5203 | static int is_potential_div_constraint(isl_int *c, int offset, int d, int total) |
5204 | { |
5205 | if (isl_int_is_zero(c[offset + d])) |
5206 | return 0; |
5207 | if (isl_int_is_one(c[offset + d])) |
5208 | return 0; |
5209 | if (isl_int_is_negone(c[offset + d])) |
5210 | return 0; |
5211 | if (isl_seq_first_non_zero(p: c + offset, len: d) != -1) |
5212 | return 0; |
5213 | if (isl_seq_first_non_zero(p: c + offset + d + 1, |
5214 | len: total - (offset + d + 1)) != -1) |
5215 | return 0; |
5216 | return 1; |
5217 | } |
5218 | |
5219 | /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map. |
5220 | * |
5221 | * As a special case, we first check if there is any pair of constraints, |
5222 | * shared by all the basic maps in "map" that force a given dimension |
5223 | * to be equal to the floor of some affine combination of the input dimensions. |
5224 | * |
5225 | * In particular, if we can find two constraints |
5226 | * |
5227 | * e(...) + c1 - m x >= 0 i.e., m x <= e(...) + c1 |
5228 | * |
5229 | * and |
5230 | * |
5231 | * -e(...) + c2 + m x >= 0 i.e., m x >= e(...) - c2 |
5232 | * |
5233 | * where m > 1 and e only depends on parameters and input dimensions, |
5234 | * and such that |
5235 | * |
5236 | * c1 + c2 < m i.e., -c2 >= c1 - (m - 1) |
5237 | * |
5238 | * then we know that we can take |
5239 | * |
5240 | * x = floor((e(...) + c1) / m) |
5241 | * |
5242 | * without having to perform any computation. |
5243 | * |
5244 | * Note that we know that |
5245 | * |
5246 | * c1 + c2 >= 1 |
5247 | * |
5248 | * If c1 + c2 were 0, then we would have detected an equality during |
5249 | * simplification. If c1 + c2 were negative, then we would have detected |
5250 | * a contradiction. |
5251 | */ |
5252 | static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_check_div( |
5253 | __isl_take isl_map *map) |
5254 | { |
5255 | int d; |
5256 | isl_size dim; |
5257 | int i, j, n; |
5258 | int offset; |
5259 | isl_size total; |
5260 | isl_int sum; |
5261 | isl_basic_map *hull; |
5262 | |
5263 | hull = isl_map_unshifted_simple_hull(map: isl_map_copy(map)); |
5264 | dim = isl_map_dim(map, type: isl_dim_out); |
5265 | total = isl_basic_map_dim(bmap: hull, type: isl_dim_all); |
5266 | if (dim < 0 || total < 0) |
5267 | goto error; |
5268 | |
5269 | isl_int_init(sum); |
5270 | offset = isl_basic_map_offset(bmap: hull, type: isl_dim_out); |
5271 | n = hull->n_ineq; |
5272 | for (d = 0; d < dim; ++d) { |
5273 | for (i = 0; i < n; ++i) { |
5274 | if (!is_potential_div_constraint(c: hull->ineq[i], |
5275 | offset, d, total: 1 + total)) |
5276 | continue; |
5277 | for (j = i + 1; j < n; ++j) { |
5278 | if (!isl_seq_is_neg(p1: hull->ineq[i] + 1, |
5279 | p2: hull->ineq[j] + 1, len: total)) |
5280 | continue; |
5281 | isl_int_add(sum, hull->ineq[i][0], |
5282 | hull->ineq[j][0]); |
5283 | if (isl_int_abs_lt(sum, |
5284 | hull->ineq[i][offset + d])) |
5285 | break; |
5286 | |
5287 | } |
5288 | if (j >= n) |
5289 | continue; |
5290 | isl_int_clear(sum); |
5291 | if (isl_int_is_pos(hull->ineq[j][offset + d])) |
5292 | j = i; |
5293 | return pw_multi_aff_from_map_div(map, hull, d, i: j); |
5294 | } |
5295 | } |
5296 | isl_int_clear(sum); |
5297 | isl_basic_map_free(bmap: hull); |
5298 | return pw_multi_aff_from_map_base(map); |
5299 | error: |
5300 | isl_map_free(map); |
5301 | isl_basic_map_free(bmap: hull); |
5302 | return NULL; |
5303 | } |
5304 | |
5305 | /* Given an affine expression |
5306 | * |
5307 | * [A -> B] -> f(A,B) |
5308 | * |
5309 | * construct an isl_multi_aff |
5310 | * |
5311 | * [A -> B] -> B' |
5312 | * |
5313 | * such that dimension "d" in B' is set to "aff" and the remaining |
5314 | * dimensions are set equal to the corresponding dimensions in B. |
5315 | * "n_in" is the dimension of the space A. |
5316 | * "n_out" is the dimension of the space B. |
5317 | * |
5318 | * If "is_set" is set, then the affine expression is of the form |
5319 | * |
5320 | * [B] -> f(B) |
5321 | * |
5322 | * and we construct an isl_multi_aff |
5323 | * |
5324 | * B -> B' |
5325 | */ |
5326 | static __isl_give isl_multi_aff *range_map(__isl_take isl_aff *aff, int d, |
5327 | unsigned n_in, unsigned n_out, int is_set) |
5328 | { |
5329 | int i; |
5330 | isl_multi_aff *ma; |
5331 | isl_space *space, *space2; |
5332 | isl_local_space *ls; |
5333 | |
5334 | space = isl_aff_get_domain_space(aff); |
5335 | ls = isl_local_space_from_space(space: isl_space_copy(space)); |
5336 | space2 = isl_space_copy(space); |
5337 | if (!is_set) |
5338 | space2 = isl_space_range(space: isl_space_unwrap(space: space2)); |
5339 | space = isl_space_map_from_domain_and_range(domain: space, range: space2); |
5340 | ma = isl_multi_aff_alloc(space); |
5341 | ma = isl_multi_aff_set_aff(multi: ma, pos: d, el: aff); |
5342 | |
5343 | for (i = 0; i < n_out; ++i) { |
5344 | if (i == d) |
5345 | continue; |
5346 | aff = isl_aff_var_on_domain(ls: isl_local_space_copy(ls), |
5347 | type: isl_dim_set, pos: n_in + i); |
5348 | ma = isl_multi_aff_set_aff(multi: ma, pos: i, el: aff); |
5349 | } |
5350 | |
5351 | isl_local_space_free(ls); |
5352 | |
5353 | return ma; |
5354 | } |
5355 | |
5356 | /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map, |
5357 | * taking into account that the dimension at position "d" can be written as |
5358 | * |
5359 | * x = m a + f(..) (1) |
5360 | * |
5361 | * where m is equal to "gcd". |
5362 | * "i" is the index of the equality in "hull" that defines f(..). |
5363 | * In particular, the equality is of the form |
5364 | * |
5365 | * f(..) - x + m g(existentials) = 0 |
5366 | * |
5367 | * or |
5368 | * |
5369 | * -f(..) + x + m g(existentials) = 0 |
5370 | * |
5371 | * We basically plug (1) into "map", resulting in a map with "a" |
5372 | * in the range instead of "x". The corresponding isl_pw_multi_aff |
5373 | * defining "a" is then plugged back into (1) to obtain a definition for "x". |
5374 | * |
5375 | * Specifically, given the input map |
5376 | * |
5377 | * A -> B |
5378 | * |
5379 | * We first wrap it into a set |
5380 | * |
5381 | * [A -> B] |
5382 | * |
5383 | * and define (1) on top of the corresponding space, resulting in "aff". |
5384 | * We use this to create an isl_multi_aff that maps the output position "d" |
5385 | * from "a" to "x", leaving all other (intput and output) dimensions unchanged. |
5386 | * We plug this into the wrapped map, unwrap the result and compute the |
5387 | * corresponding isl_pw_multi_aff. |
5388 | * The result is an expression |
5389 | * |
5390 | * A -> T(A) |
5391 | * |
5392 | * We adjust that to |
5393 | * |
5394 | * A -> [A -> T(A)] |
5395 | * |
5396 | * so that we can plug that into "aff", after extending the latter to |
5397 | * a mapping |
5398 | * |
5399 | * [A -> B] -> B' |
5400 | * |
5401 | * |
5402 | * If "map" is actually a set, then there is no "A" space, meaning |
5403 | * that we do not need to perform any wrapping, and that the result |
5404 | * of the recursive call is of the form |
5405 | * |
5406 | * [T] |
5407 | * |
5408 | * which is plugged into a mapping of the form |
5409 | * |
5410 | * B -> B' |
5411 | */ |
5412 | static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_stride( |
5413 | __isl_take isl_map *map, __isl_take isl_basic_map *hull, int d, int i, |
5414 | isl_int gcd) |
5415 | { |
5416 | isl_set *set; |
5417 | isl_space *space; |
5418 | isl_local_space *ls; |
5419 | isl_aff *aff; |
5420 | isl_multi_aff *ma; |
5421 | isl_pw_multi_aff *pma, *id; |
5422 | isl_size n_in; |
5423 | unsigned o_out; |
5424 | isl_size n_out; |
5425 | isl_bool is_set; |
5426 | |
5427 | is_set = isl_map_is_set(map); |
5428 | if (is_set < 0) |
5429 | goto error; |
5430 | |
5431 | n_in = isl_basic_map_dim(bmap: hull, type: isl_dim_in); |
5432 | n_out = isl_basic_map_dim(bmap: hull, type: isl_dim_out); |
5433 | if (n_in < 0 || n_out < 0) |
5434 | goto error; |
5435 | o_out = isl_basic_map_offset(bmap: hull, type: isl_dim_out); |
5436 | |
5437 | if (is_set) |
5438 | set = map; |
5439 | else |
5440 | set = isl_map_wrap(map); |
5441 | space = isl_space_map_from_set(space: isl_set_get_space(set)); |
5442 | ma = isl_multi_aff_identity(space); |
5443 | ls = isl_local_space_from_space(space: isl_set_get_space(set)); |
5444 | aff = isl_aff_alloc(ls); |
5445 | if (aff) { |
5446 | isl_int_set_si(aff->v->el[0], 1); |
5447 | if (isl_int_is_one(hull->eq[i][o_out + d])) |
5448 | isl_seq_neg(dst: aff->v->el + 1, src: hull->eq[i], |
5449 | len: aff->v->size - 1); |
5450 | else |
5451 | isl_seq_cpy(dst: aff->v->el + 1, src: hull->eq[i], |
5452 | len: aff->v->size - 1); |
5453 | isl_int_set(aff->v->el[1 + o_out + d], gcd); |
5454 | } |
5455 | ma = isl_multi_aff_set_aff(multi: ma, pos: n_in + d, el: isl_aff_copy(aff)); |
5456 | set = isl_set_preimage_multi_aff(set, ma); |
5457 | |
5458 | ma = range_map(aff, d, n_in, n_out, is_set); |
5459 | |
5460 | if (is_set) |
5461 | map = set; |
5462 | else |
5463 | map = isl_set_unwrap(set); |
5464 | pma = isl_pw_multi_aff_from_map(map); |
5465 | |
5466 | if (!is_set) { |
5467 | space = isl_pw_multi_aff_get_domain_space(pw: pma); |
5468 | space = isl_space_map_from_set(space); |
5469 | id = isl_pw_multi_aff_identity(space); |
5470 | pma = isl_pw_multi_aff_range_product(pma1: id, pma2: pma); |
5471 | } |
5472 | id = isl_pw_multi_aff_from_multi_aff(el: ma); |
5473 | pma = isl_pw_multi_aff_pullback_pw_multi_aff(pw: id, pma); |
5474 | |
5475 | isl_basic_map_free(bmap: hull); |
5476 | return pma; |
5477 | error: |
5478 | isl_map_free(map); |
5479 | isl_basic_map_free(bmap: hull); |
5480 | return NULL; |
5481 | } |
5482 | |
5483 | /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map. |
5484 | * "hull" contains the equalities valid for "map". |
5485 | * |
5486 | * Check if any of the output dimensions is "strided". |
5487 | * That is, we check if it can be written as |
5488 | * |
5489 | * x = m a + f(..) |
5490 | * |
5491 | * with m greater than 1, a some combination of existentially quantified |
5492 | * variables and f an expression in the parameters and input dimensions. |
5493 | * If so, we remove the stride in pw_multi_aff_from_map_stride. |
5494 | * |
5495 | * Otherwise, we continue with pw_multi_aff_from_map_check_div for a further |
5496 | * special case. |
5497 | */ |
5498 | static __isl_give isl_pw_multi_aff *pw_multi_aff_from_map_check_strides( |
5499 | __isl_take isl_map *map, __isl_take isl_basic_map *hull) |
5500 | { |
5501 | int i, j; |
5502 | isl_size n_out; |
5503 | unsigned o_out; |
5504 | isl_size n_div; |
5505 | unsigned o_div; |
5506 | isl_int gcd; |
5507 | |
5508 | n_div = isl_basic_map_dim(bmap: hull, type: isl_dim_div); |
5509 | n_out = isl_basic_map_dim(bmap: hull, type: isl_dim_out); |
5510 | if (n_div < 0 || n_out < 0) |
5511 | goto error; |
5512 | |
5513 | if (n_div == 0) { |
5514 | isl_basic_map_free(bmap: hull); |
5515 | return pw_multi_aff_from_map_check_div(map); |
5516 | } |
5517 | |
5518 | isl_int_init(gcd); |
5519 | |
5520 | o_div = isl_basic_map_offset(bmap: hull, type: isl_dim_div); |
5521 | o_out = isl_basic_map_offset(bmap: hull, type: isl_dim_out); |
5522 | |
5523 | for (i = 0; i < n_out; ++i) { |
5524 | for (j = 0; j < hull->n_eq; ++j) { |
5525 | isl_int *eq = hull->eq[j]; |
5526 | isl_pw_multi_aff *res; |
5527 | |
5528 | if (!isl_int_is_one(eq[o_out + i]) && |
5529 | !isl_int_is_negone(eq[o_out + i])) |
5530 | continue; |
5531 | if (isl_seq_first_non_zero(p: eq + o_out, len: i) != -1) |
5532 | continue; |
5533 | if (isl_seq_first_non_zero(p: eq + o_out + i + 1, |
5534 | len: n_out - (i + 1)) != -1) |
5535 | continue; |
5536 | isl_seq_gcd(p: eq + o_div, len: n_div, gcd: &gcd); |
5537 | if (isl_int_is_zero(gcd)) |
5538 | continue; |
5539 | if (isl_int_is_one(gcd)) |
5540 | continue; |
5541 | |
5542 | res = pw_multi_aff_from_map_stride(map, hull, |
5543 | d: i, i: j, gcd); |
5544 | isl_int_clear(gcd); |
5545 | return res; |
5546 | } |
5547 | } |
5548 | |
5549 | isl_int_clear(gcd); |
5550 | isl_basic_map_free(bmap: hull); |
5551 | return pw_multi_aff_from_map_check_div(map); |
5552 | error: |
5553 | isl_map_free(map); |
5554 | isl_basic_map_free(bmap: hull); |
5555 | return NULL; |
5556 | } |
5557 | |
5558 | /* Try and create an isl_pw_multi_aff that is equivalent to the given isl_map. |
5559 | * |
5560 | * As a special case, we first check if all output dimensions are uniquely |
5561 | * defined in terms of the parameters and input dimensions over the entire |
5562 | * domain. If so, we extract the desired isl_pw_multi_aff directly |
5563 | * from the affine hull of "map" and its domain. |
5564 | * |
5565 | * Otherwise, continue with pw_multi_aff_from_map_check_strides for more |
5566 | * special cases. |
5567 | */ |
5568 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_map(__isl_take isl_map *map) |
5569 | { |
5570 | isl_bool sv; |
5571 | isl_size n; |
5572 | isl_basic_map *hull; |
5573 | |
5574 | n = isl_map_n_basic_map(map); |
5575 | if (n < 0) |
5576 | goto error; |
5577 | |
5578 | if (n == 1) { |
5579 | hull = isl_map_unshifted_simple_hull(map: isl_map_copy(map)); |
5580 | hull = isl_basic_map_plain_affine_hull(bmap: hull); |
5581 | sv = isl_basic_map_plain_is_single_valued(bmap: hull); |
5582 | if (sv >= 0 && sv) |
5583 | return plain_pw_multi_aff_from_map(domain: isl_map_domain(bmap: map), |
5584 | bmap: hull); |
5585 | isl_basic_map_free(bmap: hull); |
5586 | } |
5587 | map = isl_map_detect_equalities(map); |
5588 | hull = isl_map_unshifted_simple_hull(map: isl_map_copy(map)); |
5589 | sv = isl_basic_map_plain_is_single_valued(bmap: hull); |
5590 | if (sv >= 0 && sv) |
5591 | return plain_pw_multi_aff_from_map(domain: isl_map_domain(bmap: map), bmap: hull); |
5592 | if (sv >= 0) |
5593 | return pw_multi_aff_from_map_check_strides(map, hull); |
5594 | isl_basic_map_free(bmap: hull); |
5595 | error: |
5596 | isl_map_free(map); |
5597 | return NULL; |
5598 | } |
5599 | |
5600 | /* This function performs the same operation as isl_pw_multi_aff_from_map, |
5601 | * but is considered as a function on an isl_map when exported. |
5602 | */ |
5603 | __isl_give isl_pw_multi_aff *isl_map_as_pw_multi_aff(__isl_take isl_map *map) |
5604 | { |
5605 | return isl_pw_multi_aff_from_map(map); |
5606 | } |
5607 | |
5608 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_set(__isl_take isl_set *set) |
5609 | { |
5610 | return isl_pw_multi_aff_from_map(map: set); |
5611 | } |
5612 | |
5613 | /* This function performs the same operation as isl_pw_multi_aff_from_set, |
5614 | * but is considered as a function on an isl_set when exported. |
5615 | */ |
5616 | __isl_give isl_pw_multi_aff *isl_set_as_pw_multi_aff(__isl_take isl_set *set) |
5617 | { |
5618 | return isl_pw_multi_aff_from_set(set); |
5619 | } |
5620 | |
5621 | /* Convert "map" into an isl_pw_multi_aff (if possible) and |
5622 | * add it to *user. |
5623 | */ |
5624 | static isl_stat pw_multi_aff_from_map(__isl_take isl_map *map, void *user) |
5625 | { |
5626 | isl_union_pw_multi_aff **upma = user; |
5627 | isl_pw_multi_aff *pma; |
5628 | |
5629 | pma = isl_pw_multi_aff_from_map(map); |
5630 | *upma = isl_union_pw_multi_aff_add_pw_multi_aff(u: *upma, part: pma); |
5631 | |
5632 | return *upma ? isl_stat_ok : isl_stat_error; |
5633 | } |
5634 | |
5635 | /* Create an isl_union_pw_multi_aff with the given isl_aff on a universe |
5636 | * domain. |
5637 | */ |
5638 | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_aff( |
5639 | __isl_take isl_aff *aff) |
5640 | { |
5641 | isl_multi_aff *ma; |
5642 | isl_pw_multi_aff *pma; |
5643 | |
5644 | ma = isl_multi_aff_from_aff(el: aff); |
5645 | pma = isl_pw_multi_aff_from_multi_aff(el: ma); |
5646 | return isl_union_pw_multi_aff_from_pw_multi_aff(part: pma); |
5647 | } |
5648 | |
5649 | /* Try and create an isl_union_pw_multi_aff that is equivalent |
5650 | * to the given isl_union_map. |
5651 | * The isl_union_map is required to be single-valued in each space. |
5652 | * Otherwise, an error is produced. |
5653 | */ |
5654 | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_map( |
5655 | __isl_take isl_union_map *umap) |
5656 | { |
5657 | isl_space *space; |
5658 | isl_union_pw_multi_aff *upma; |
5659 | |
5660 | space = isl_union_map_get_space(umap); |
5661 | upma = isl_union_pw_multi_aff_empty(space); |
5662 | if (isl_union_map_foreach_map(umap, fn: &pw_multi_aff_from_map, user: &upma) < 0) |
5663 | upma = isl_union_pw_multi_aff_free(u: upma); |
5664 | isl_union_map_free(umap); |
5665 | |
5666 | return upma; |
5667 | } |
5668 | |
5669 | /* This function performs the same operation as |
5670 | * isl_union_pw_multi_aff_from_union_map, |
5671 | * but is considered as a function on an isl_union_map when exported. |
5672 | */ |
5673 | __isl_give isl_union_pw_multi_aff *isl_union_map_as_union_pw_multi_aff( |
5674 | __isl_take isl_union_map *umap) |
5675 | { |
5676 | return isl_union_pw_multi_aff_from_union_map(umap); |
5677 | } |
5678 | |
5679 | /* Try and create an isl_union_pw_multi_aff that is equivalent |
5680 | * to the given isl_union_set. |
5681 | * The isl_union_set is required to be a singleton in each space. |
5682 | * Otherwise, an error is produced. |
5683 | */ |
5684 | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_set( |
5685 | __isl_take isl_union_set *uset) |
5686 | { |
5687 | return isl_union_pw_multi_aff_from_union_map(umap: uset); |
5688 | } |
5689 | |
5690 | /* Return the piecewise affine expression "set ? 1 : 0". |
5691 | */ |
5692 | __isl_give isl_pw_aff *isl_set_indicator_function(__isl_take isl_set *set) |
5693 | { |
5694 | isl_pw_aff *pa; |
5695 | isl_space *space = isl_set_get_space(set); |
5696 | isl_local_space *ls = isl_local_space_from_space(space); |
5697 | isl_aff *zero = isl_aff_zero_on_domain(ls: isl_local_space_copy(ls)); |
5698 | isl_aff *one = isl_aff_zero_on_domain(ls); |
5699 | |
5700 | one = isl_aff_add_constant_si(aff: one, v: 1); |
5701 | pa = isl_pw_aff_alloc(set: isl_set_copy(set), el: one); |
5702 | set = isl_set_complement(set); |
5703 | pa = isl_pw_aff_add_disjoint(pw1: pa, pw2: isl_pw_aff_alloc(set, el: zero)); |
5704 | |
5705 | return pa; |
5706 | } |
5707 | |
5708 | /* Plug in "subs" for dimension "type", "pos" of "aff". |
5709 | * |
5710 | * Let i be the dimension to replace and let "subs" be of the form |
5711 | * |
5712 | * f/d |
5713 | * |
5714 | * and "aff" of the form |
5715 | * |
5716 | * (a i + g)/m |
5717 | * |
5718 | * The result is |
5719 | * |
5720 | * (a f + d g')/(m d) |
5721 | * |
5722 | * where g' is the result of plugging in "subs" in each of the integer |
5723 | * divisions in g. |
5724 | */ |
5725 | __isl_give isl_aff *isl_aff_substitute(__isl_take isl_aff *aff, |
5726 | enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs) |
5727 | { |
5728 | isl_ctx *ctx; |
5729 | isl_int v; |
5730 | isl_size n_div; |
5731 | |
5732 | aff = isl_aff_cow(aff); |
5733 | if (!aff || !subs) |
5734 | return isl_aff_free(aff); |
5735 | |
5736 | ctx = isl_aff_get_ctx(aff); |
5737 | if (!isl_space_is_equal(space1: aff->ls->dim, space2: subs->ls->dim)) |
5738 | isl_die(ctx, isl_error_invalid, |
5739 | "spaces don't match" , return isl_aff_free(aff)); |
5740 | n_div = isl_aff_domain_dim(aff: subs, type: isl_dim_div); |
5741 | if (n_div < 0) |
5742 | return isl_aff_free(aff); |
5743 | if (n_div != 0) |
5744 | isl_die(ctx, isl_error_unsupported, |
5745 | "cannot handle divs yet" , return isl_aff_free(aff)); |
5746 | |
5747 | aff->ls = isl_local_space_substitute(ls: aff->ls, type, pos, subs); |
5748 | if (!aff->ls) |
5749 | return isl_aff_free(aff); |
5750 | |
5751 | aff->v = isl_vec_cow(vec: aff->v); |
5752 | if (!aff->v) |
5753 | return isl_aff_free(aff); |
5754 | |
5755 | pos += isl_local_space_offset(ls: aff->ls, type); |
5756 | |
5757 | isl_int_init(v); |
5758 | isl_seq_substitute(p: aff->v->el, pos, subs: subs->v->el, |
5759 | p_len: aff->v->size, subs_len: subs->v->size, v); |
5760 | isl_int_clear(v); |
5761 | |
5762 | return aff; |
5763 | } |
5764 | |
5765 | /* Plug in "subs" for dimension "type", "pos" in each of the affine |
5766 | * expressions in "maff". |
5767 | */ |
5768 | __isl_give isl_multi_aff *isl_multi_aff_substitute( |
5769 | __isl_take isl_multi_aff *maff, enum isl_dim_type type, unsigned pos, |
5770 | __isl_keep isl_aff *subs) |
5771 | { |
5772 | isl_size n; |
5773 | int i; |
5774 | |
5775 | n = isl_multi_aff_size(multi: maff); |
5776 | if (n < 0 || !subs) |
5777 | return isl_multi_aff_free(multi: maff); |
5778 | |
5779 | if (type == isl_dim_in) |
5780 | type = isl_dim_set; |
5781 | |
5782 | for (i = 0; i < n; ++i) { |
5783 | isl_aff *aff; |
5784 | |
5785 | aff = isl_multi_aff_take_at(multi: maff, pos: i); |
5786 | aff = isl_aff_substitute(aff, type, pos, subs); |
5787 | maff = isl_multi_aff_restore_at(multi: maff, pos: i, el: aff); |
5788 | } |
5789 | |
5790 | return maff; |
5791 | } |
5792 | |
5793 | /* Plug in "subs" for input dimension "pos" of "pma". |
5794 | * |
5795 | * pma is of the form |
5796 | * |
5797 | * A_i(v) -> M_i(v) |
5798 | * |
5799 | * while subs is of the form |
5800 | * |
5801 | * v' = B_j(v) -> S_j |
5802 | * |
5803 | * Each pair i,j such that C_ij = A_i \cap B_i is non-empty |
5804 | * has a contribution in the result, in particular |
5805 | * |
5806 | * C_ij(S_j) -> M_i(S_j) |
5807 | * |
5808 | * Note that plugging in S_j in C_ij may also result in an empty set |
5809 | * and this contribution should simply be discarded. |
5810 | */ |
5811 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_substitute( |
5812 | __isl_take isl_pw_multi_aff *pma, unsigned pos, |
5813 | __isl_keep isl_pw_aff *subs) |
5814 | { |
5815 | int i, j, n; |
5816 | isl_pw_multi_aff *res; |
5817 | |
5818 | if (!pma || !subs) |
5819 | return isl_pw_multi_aff_free(pw: pma); |
5820 | |
5821 | n = pma->n * subs->n; |
5822 | res = isl_pw_multi_aff_alloc_size(space: isl_space_copy(space: pma->dim), n); |
5823 | |
5824 | for (i = 0; i < pma->n; ++i) { |
5825 | for (j = 0; j < subs->n; ++j) { |
5826 | isl_set *common; |
5827 | isl_multi_aff *res_ij; |
5828 | int empty; |
5829 | |
5830 | common = isl_set_intersect( |
5831 | set1: isl_set_copy(set: pma->p[i].set), |
5832 | set2: isl_set_copy(set: subs->p[j].set)); |
5833 | common = isl_set_substitute(set: common, |
5834 | pos, subs: subs->p[j].aff); |
5835 | empty = isl_set_plain_is_empty(set: common); |
5836 | if (empty < 0 || empty) { |
5837 | isl_set_free(set: common); |
5838 | if (empty < 0) |
5839 | goto error; |
5840 | continue; |
5841 | } |
5842 | |
5843 | res_ij = isl_multi_aff_substitute( |
5844 | maff: isl_multi_aff_copy(multi: pma->p[i].maff), |
5845 | type: isl_dim_in, pos, subs: subs->p[j].aff); |
5846 | |
5847 | res = isl_pw_multi_aff_add_piece(pw: res, set: common, el: res_ij); |
5848 | } |
5849 | } |
5850 | |
5851 | isl_pw_multi_aff_free(pw: pma); |
5852 | return res; |
5853 | error: |
5854 | isl_pw_multi_aff_free(pw: pma); |
5855 | isl_pw_multi_aff_free(pw: res); |
5856 | return NULL; |
5857 | } |
5858 | |
5859 | /* Compute the preimage of a range of dimensions in the affine expression "src" |
5860 | * under "ma" and put the result in "dst". The number of dimensions in "src" |
5861 | * that precede the range is given by "n_before". The number of dimensions |
5862 | * in the range is given by the number of output dimensions of "ma". |
5863 | * The number of dimensions that follow the range is given by "n_after". |
5864 | * If "has_denom" is set (to one), |
5865 | * then "src" and "dst" have an extra initial denominator. |
5866 | * "n_div_ma" is the number of existentials in "ma" |
5867 | * "n_div_bset" is the number of existentials in "src" |
5868 | * The resulting "dst" (which is assumed to have been allocated by |
5869 | * the caller) contains coefficients for both sets of existentials, |
5870 | * first those in "ma" and then those in "src". |
5871 | * f, c1, c2 and g are temporary objects that have been initialized |
5872 | * by the caller. |
5873 | * |
5874 | * Let src represent the expression |
5875 | * |
5876 | * (a(p) + f_u u + b v + f_w w + c(divs))/d |
5877 | * |
5878 | * and let ma represent the expressions |
5879 | * |
5880 | * v_i = (r_i(p) + s_i(y) + t_i(divs'))/m_i |
5881 | * |
5882 | * We start out with the following expression for dst: |
5883 | * |
5884 | * (a(p) + f_u u + 0 y + f_w w + 0 divs' + c(divs) + f \sum_i b_i v_i)/d |
5885 | * |
5886 | * with the multiplication factor f initially equal to 1 |
5887 | * and f \sum_i b_i v_i kept separately. |
5888 | * For each x_i that we substitute, we multiply the numerator |
5889 | * (and denominator) of dst by c_1 = m_i and add the numerator |
5890 | * of the x_i expression multiplied by c_2 = f b_i, |
5891 | * after removing the common factors of c_1 and c_2. |
5892 | * The multiplication factor f also needs to be multiplied by c_1 |
5893 | * for the next x_j, j > i. |
5894 | */ |
5895 | isl_stat isl_seq_preimage(isl_int *dst, isl_int *src, |
5896 | __isl_keep isl_multi_aff *ma, int n_before, int n_after, |
5897 | int n_div_ma, int n_div_bmap, |
5898 | isl_int f, isl_int c1, isl_int c2, isl_int g, int has_denom) |
5899 | { |
5900 | int i; |
5901 | isl_size n_param, n_in, n_out; |
5902 | int o_dst, o_src; |
5903 | |
5904 | n_param = isl_multi_aff_dim(multi: ma, type: isl_dim_param); |
5905 | n_in = isl_multi_aff_dim(multi: ma, type: isl_dim_in); |
5906 | n_out = isl_multi_aff_dim(multi: ma, type: isl_dim_out); |
5907 | if (n_param < 0 || n_in < 0 || n_out < 0) |
5908 | return isl_stat_error; |
5909 | |
5910 | isl_seq_cpy(dst, src, len: has_denom + 1 + n_param + n_before); |
5911 | o_dst = o_src = has_denom + 1 + n_param + n_before; |
5912 | isl_seq_clr(p: dst + o_dst, len: n_in); |
5913 | o_dst += n_in; |
5914 | o_src += n_out; |
5915 | isl_seq_cpy(dst: dst + o_dst, src: src + o_src, len: n_after); |
5916 | o_dst += n_after; |
5917 | o_src += n_after; |
5918 | isl_seq_clr(p: dst + o_dst, len: n_div_ma); |
5919 | o_dst += n_div_ma; |
5920 | isl_seq_cpy(dst: dst + o_dst, src: src + o_src, len: n_div_bmap); |
5921 | |
5922 | isl_int_set_si(f, 1); |
5923 | |
5924 | for (i = 0; i < n_out; ++i) { |
5925 | int offset = has_denom + 1 + n_param + n_before + i; |
5926 | |
5927 | if (isl_int_is_zero(src[offset])) |
5928 | continue; |
5929 | isl_int_set(c1, ma->u.p[i]->v->el[0]); |
5930 | isl_int_mul(c2, f, src[offset]); |
5931 | isl_int_gcd(g, c1, c2); |
5932 | isl_int_divexact(c1, c1, g); |
5933 | isl_int_divexact(c2, c2, g); |
5934 | |
5935 | isl_int_mul(f, f, c1); |
5936 | o_dst = has_denom; |
5937 | o_src = 1; |
5938 | isl_seq_combine(dst: dst + o_dst, m1: c1, src1: dst + o_dst, |
5939 | m2: c2, src2: ma->u.p[i]->v->el + o_src, len: 1 + n_param); |
5940 | o_dst += 1 + n_param; |
5941 | o_src += 1 + n_param; |
5942 | isl_seq_scale(dst: dst + o_dst, src: dst + o_dst, f: c1, len: n_before); |
5943 | o_dst += n_before; |
5944 | isl_seq_combine(dst: dst + o_dst, m1: c1, src1: dst + o_dst, |
5945 | m2: c2, src2: ma->u.p[i]->v->el + o_src, len: n_in); |
5946 | o_dst += n_in; |
5947 | o_src += n_in; |
5948 | isl_seq_scale(dst: dst + o_dst, src: dst + o_dst, f: c1, len: n_after); |
5949 | o_dst += n_after; |
5950 | isl_seq_combine(dst: dst + o_dst, m1: c1, src1: dst + o_dst, |
5951 | m2: c2, src2: ma->u.p[i]->v->el + o_src, len: n_div_ma); |
5952 | o_dst += n_div_ma; |
5953 | o_src += n_div_ma; |
5954 | isl_seq_scale(dst: dst + o_dst, src: dst + o_dst, f: c1, len: n_div_bmap); |
5955 | if (has_denom) |
5956 | isl_int_mul(dst[0], dst[0], c1); |
5957 | } |
5958 | |
5959 | return isl_stat_ok; |
5960 | } |
5961 | |
5962 | /* Compute the pullback of "aff" by the function represented by "ma". |
5963 | * In other words, plug in "ma" in "aff". The result is an affine expression |
5964 | * defined over the domain space of "ma". |
5965 | * |
5966 | * If "aff" is represented by |
5967 | * |
5968 | * (a(p) + b x + c(divs))/d |
5969 | * |
5970 | * and ma is represented by |
5971 | * |
5972 | * x = D(p) + F(y) + G(divs') |
5973 | * |
5974 | * then the result is |
5975 | * |
5976 | * (a(p) + b D(p) + b F(y) + b G(divs') + c(divs))/d |
5977 | * |
5978 | * The divs in the local space of the input are similarly adjusted |
5979 | * through a call to isl_local_space_preimage_multi_aff. |
5980 | */ |
5981 | __isl_give isl_aff *isl_aff_pullback_multi_aff(__isl_take isl_aff *aff, |
5982 | __isl_take isl_multi_aff *ma) |
5983 | { |
5984 | isl_aff *res = NULL; |
5985 | isl_local_space *ls; |
5986 | isl_size n_div_aff, n_div_ma; |
5987 | isl_int f, c1, c2, g; |
5988 | |
5989 | ma = isl_multi_aff_align_divs(maff: ma); |
5990 | if (!aff || !ma) |
5991 | goto error; |
5992 | |
5993 | n_div_aff = isl_aff_dim(aff, type: isl_dim_div); |
5994 | n_div_ma = ma->n ? isl_aff_dim(aff: ma->u.p[0], type: isl_dim_div) : 0; |
5995 | if (n_div_aff < 0 || n_div_ma < 0) |
5996 | goto error; |
5997 | |
5998 | ls = isl_aff_get_domain_local_space(aff); |
5999 | ls = isl_local_space_preimage_multi_aff(ls, ma: isl_multi_aff_copy(multi: ma)); |
6000 | res = isl_aff_alloc(ls); |
6001 | if (!res) |
6002 | goto error; |
6003 | |
6004 | isl_int_init(f); |
6005 | isl_int_init(c1); |
6006 | isl_int_init(c2); |
6007 | isl_int_init(g); |
6008 | |
6009 | if (isl_seq_preimage(dst: res->v->el, src: aff->v->el, ma, n_before: 0, n_after: 0, |
6010 | n_div_ma, n_div_bmap: n_div_aff, f, c1, c2, g, has_denom: 1) < 0) |
6011 | res = isl_aff_free(aff: res); |
6012 | |
6013 | isl_int_clear(f); |
6014 | isl_int_clear(c1); |
6015 | isl_int_clear(c2); |
6016 | isl_int_clear(g); |
6017 | |
6018 | isl_aff_free(aff); |
6019 | isl_multi_aff_free(multi: ma); |
6020 | res = isl_aff_normalize(aff: res); |
6021 | return res; |
6022 | error: |
6023 | isl_aff_free(aff); |
6024 | isl_multi_aff_free(multi: ma); |
6025 | isl_aff_free(aff: res); |
6026 | return NULL; |
6027 | } |
6028 | |
6029 | /* Compute the pullback of "aff1" by the function represented by "aff2". |
6030 | * In other words, plug in "aff2" in "aff1". The result is an affine expression |
6031 | * defined over the domain space of "aff1". |
6032 | * |
6033 | * The domain of "aff1" should match the range of "aff2", which means |
6034 | * that it should be single-dimensional. |
6035 | */ |
6036 | __isl_give isl_aff *isl_aff_pullback_aff(__isl_take isl_aff *aff1, |
6037 | __isl_take isl_aff *aff2) |
6038 | { |
6039 | isl_multi_aff *ma; |
6040 | |
6041 | ma = isl_multi_aff_from_aff(el: aff2); |
6042 | return isl_aff_pullback_multi_aff(aff: aff1, ma); |
6043 | } |
6044 | |
6045 | /* Compute the pullback of "ma1" by the function represented by "ma2". |
6046 | * In other words, plug in "ma2" in "ma1". |
6047 | */ |
6048 | __isl_give isl_multi_aff *isl_multi_aff_pullback_multi_aff( |
6049 | __isl_take isl_multi_aff *ma1, __isl_take isl_multi_aff *ma2) |
6050 | { |
6051 | int i; |
6052 | isl_size n; |
6053 | isl_space *space = NULL; |
6054 | |
6055 | isl_multi_aff_align_params_bin(obj1: &ma1, obj2: &ma2); |
6056 | ma2 = isl_multi_aff_align_divs(maff: ma2); |
6057 | n = isl_multi_aff_size(multi: ma1); |
6058 | if (n < 0 || !ma2) |
6059 | goto error; |
6060 | |
6061 | space = isl_space_join(left: isl_multi_aff_get_space(multi: ma2), |
6062 | right: isl_multi_aff_get_space(multi: ma1)); |
6063 | |
6064 | for (i = 0; i < n; ++i) { |
6065 | isl_aff *aff; |
6066 | |
6067 | aff = isl_multi_aff_take_at(multi: ma1, pos: i); |
6068 | aff = isl_aff_pullback_multi_aff(aff, ma: isl_multi_aff_copy(multi: ma2)); |
6069 | ma1 = isl_multi_aff_restore_at(multi: ma1, pos: i, el: aff); |
6070 | } |
6071 | |
6072 | ma1 = isl_multi_aff_reset_space(multi: ma1, space); |
6073 | isl_multi_aff_free(multi: ma2); |
6074 | return ma1; |
6075 | error: |
6076 | isl_space_free(space); |
6077 | isl_multi_aff_free(multi: ma2); |
6078 | isl_multi_aff_free(multi: ma1); |
6079 | return NULL; |
6080 | } |
6081 | |
6082 | /* Extend the local space of "dst" to include the divs |
6083 | * in the local space of "src". |
6084 | * |
6085 | * If "src" does not have any divs or if the local spaces of "dst" and |
6086 | * "src" are the same, then no extension is required. |
6087 | */ |
6088 | __isl_give isl_aff *isl_aff_align_divs(__isl_take isl_aff *dst, |
6089 | __isl_keep isl_aff *src) |
6090 | { |
6091 | isl_ctx *ctx; |
6092 | isl_size src_n_div, dst_n_div; |
6093 | int *exp1 = NULL; |
6094 | int *exp2 = NULL; |
6095 | isl_bool equal; |
6096 | isl_mat *div; |
6097 | |
6098 | if (!src || !dst) |
6099 | return isl_aff_free(aff: dst); |
6100 | |
6101 | ctx = isl_aff_get_ctx(aff: src); |
6102 | equal = isl_local_space_has_equal_space(ls1: src->ls, ls2: dst->ls); |
6103 | if (equal < 0) |
6104 | return isl_aff_free(aff: dst); |
6105 | if (!equal) |
6106 | isl_die(ctx, isl_error_invalid, |
6107 | "spaces don't match" , goto error); |
6108 | |
6109 | src_n_div = isl_aff_domain_dim(aff: src, type: isl_dim_div); |
6110 | dst_n_div = isl_aff_domain_dim(aff: dst, type: isl_dim_div); |
6111 | if (src_n_div == 0) |
6112 | return dst; |
6113 | equal = isl_local_space_is_equal(ls1: src->ls, ls2: dst->ls); |
6114 | if (equal < 0 || src_n_div < 0 || dst_n_div < 0) |
6115 | return isl_aff_free(aff: dst); |
6116 | if (equal) |
6117 | return dst; |
6118 | |
6119 | exp1 = isl_alloc_array(ctx, int, src_n_div); |
6120 | exp2 = isl_alloc_array(ctx, int, dst_n_div); |
6121 | if (!exp1 || (dst_n_div && !exp2)) |
6122 | goto error; |
6123 | |
6124 | div = isl_merge_divs(div1: src->ls->div, div2: dst->ls->div, exp1, exp2); |
6125 | dst = isl_aff_expand_divs(aff: dst, div, exp: exp2); |
6126 | free(ptr: exp1); |
6127 | free(ptr: exp2); |
6128 | |
6129 | return dst; |
6130 | error: |
6131 | free(ptr: exp1); |
6132 | free(ptr: exp2); |
6133 | return isl_aff_free(aff: dst); |
6134 | } |
6135 | |
6136 | /* Adjust the local spaces of the affine expressions in "maff" |
6137 | * such that they all have the save divs. |
6138 | */ |
6139 | __isl_give isl_multi_aff *isl_multi_aff_align_divs( |
6140 | __isl_take isl_multi_aff *maff) |
6141 | { |
6142 | isl_aff *aff_0; |
6143 | isl_size n; |
6144 | int i; |
6145 | |
6146 | n = isl_multi_aff_size(multi: maff); |
6147 | if (n < 0) |
6148 | return isl_multi_aff_free(multi: maff); |
6149 | if (n <= 1) |
6150 | return maff; |
6151 | |
6152 | aff_0 = isl_multi_aff_take_at(multi: maff, pos: 0); |
6153 | for (i = 1; i < n; ++i) { |
6154 | isl_aff *aff_i; |
6155 | |
6156 | aff_i = isl_multi_aff_peek_at(multi: maff, pos: i); |
6157 | aff_0 = isl_aff_align_divs(dst: aff_0, src: aff_i); |
6158 | } |
6159 | maff = isl_multi_aff_restore_at(multi: maff, pos: 0, el: aff_0); |
6160 | |
6161 | aff_0 = isl_multi_aff_peek_at(multi: maff, pos: 0); |
6162 | for (i = 1; i < n; ++i) { |
6163 | isl_aff *aff_i; |
6164 | |
6165 | aff_i = isl_multi_aff_take_at(multi: maff, pos: i); |
6166 | aff_i = isl_aff_align_divs(dst: aff_i, src: aff_0); |
6167 | maff = isl_multi_aff_restore_at(multi: maff, pos: i, el: aff_i); |
6168 | } |
6169 | |
6170 | return maff; |
6171 | } |
6172 | |
6173 | __isl_give isl_aff *isl_aff_lift(__isl_take isl_aff *aff) |
6174 | { |
6175 | aff = isl_aff_cow(aff); |
6176 | if (!aff) |
6177 | return NULL; |
6178 | |
6179 | aff->ls = isl_local_space_lift(ls: aff->ls); |
6180 | if (!aff->ls) |
6181 | return isl_aff_free(aff); |
6182 | |
6183 | return aff; |
6184 | } |
6185 | |
6186 | /* Lift "maff" to a space with extra dimensions such that the result |
6187 | * has no more existentially quantified variables. |
6188 | * If "ls" is not NULL, then *ls is assigned the local space that lies |
6189 | * at the basis of the lifting applied to "maff". |
6190 | */ |
6191 | __isl_give isl_multi_aff *isl_multi_aff_lift(__isl_take isl_multi_aff *maff, |
6192 | __isl_give isl_local_space **ls) |
6193 | { |
6194 | int i; |
6195 | isl_space *space; |
6196 | isl_aff *aff; |
6197 | isl_size n, n_div; |
6198 | |
6199 | if (ls) |
6200 | *ls = NULL; |
6201 | |
6202 | n = isl_multi_aff_size(multi: maff); |
6203 | if (n < 0) |
6204 | return isl_multi_aff_free(multi: maff); |
6205 | |
6206 | if (n == 0) { |
6207 | if (ls) { |
6208 | isl_space *space = isl_multi_aff_get_domain_space(multi: maff); |
6209 | *ls = isl_local_space_from_space(space); |
6210 | if (!*ls) |
6211 | return isl_multi_aff_free(multi: maff); |
6212 | } |
6213 | return maff; |
6214 | } |
6215 | |
6216 | maff = isl_multi_aff_align_divs(maff); |
6217 | |
6218 | aff = isl_multi_aff_peek_at(multi: maff, pos: 0); |
6219 | n_div = isl_aff_dim(aff, type: isl_dim_div); |
6220 | if (n_div < 0) |
6221 | return isl_multi_aff_free(multi: maff); |
6222 | space = isl_multi_aff_get_space(multi: maff); |
6223 | space = isl_space_lift(space: isl_space_domain(space), n_local: n_div); |
6224 | space = isl_space_extend_domain_with_range(domain: space, |
6225 | model: isl_multi_aff_get_space(multi: maff)); |
6226 | maff = isl_multi_aff_restore_space(multi: maff, space); |
6227 | |
6228 | if (ls) { |
6229 | aff = isl_multi_aff_peek_at(multi: maff, pos: 0); |
6230 | *ls = isl_aff_get_domain_local_space(aff); |
6231 | if (!*ls) |
6232 | return isl_multi_aff_free(multi: maff); |
6233 | } |
6234 | |
6235 | for (i = 0; i < n; ++i) { |
6236 | aff = isl_multi_aff_take_at(multi: maff, pos: i); |
6237 | aff = isl_aff_lift(aff); |
6238 | maff = isl_multi_aff_restore_at(multi: maff, pos: i, el: aff); |
6239 | } |
6240 | |
6241 | return maff; |
6242 | } |
6243 | |
6244 | #undef TYPE |
6245 | #define TYPE isl_pw_multi_aff |
6246 | static |
6247 | #include "check_type_range_templ.c" |
6248 | |
6249 | /* Extract an isl_pw_aff corresponding to output dimension "pos" of "pma". |
6250 | */ |
6251 | __isl_give isl_pw_aff *isl_pw_multi_aff_get_at( |
6252 | __isl_keep isl_pw_multi_aff *pma, int pos) |
6253 | { |
6254 | int i; |
6255 | isl_size n_out; |
6256 | isl_space *space; |
6257 | isl_pw_aff *pa; |
6258 | |
6259 | if (isl_pw_multi_aff_check_range(obj: pma, type: isl_dim_out, first: pos, n: 1) < 0) |
6260 | return NULL; |
6261 | |
6262 | n_out = isl_pw_multi_aff_dim(pw: pma, type: isl_dim_out); |
6263 | if (n_out < 0) |
6264 | return NULL; |
6265 | |
6266 | space = isl_pw_multi_aff_get_space(pw: pma); |
6267 | space = isl_space_drop_dims(space, type: isl_dim_out, |
6268 | first: pos + 1, num: n_out - pos - 1); |
6269 | space = isl_space_drop_dims(space, type: isl_dim_out, first: 0, num: pos); |
6270 | |
6271 | pa = isl_pw_aff_alloc_size(space, n: pma->n); |
6272 | for (i = 0; i < pma->n; ++i) { |
6273 | isl_aff *aff; |
6274 | aff = isl_multi_aff_get_aff(multi: pma->p[i].maff, pos); |
6275 | pa = isl_pw_aff_add_piece(pw: pa, set: isl_set_copy(set: pma->p[i].set), el: aff); |
6276 | } |
6277 | |
6278 | return pa; |
6279 | } |
6280 | |
6281 | /* This is an alternative name for the function above. |
6282 | */ |
6283 | __isl_give isl_pw_aff *isl_pw_multi_aff_get_pw_aff( |
6284 | __isl_keep isl_pw_multi_aff *pma, int pos) |
6285 | { |
6286 | return isl_pw_multi_aff_get_at(pma, pos); |
6287 | } |
6288 | |
6289 | /* Return an isl_pw_multi_aff with the given "set" as domain and |
6290 | * an unnamed zero-dimensional range. |
6291 | */ |
6292 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_domain( |
6293 | __isl_take isl_set *set) |
6294 | { |
6295 | isl_multi_aff *ma; |
6296 | isl_space *space; |
6297 | |
6298 | space = isl_set_get_space(set); |
6299 | space = isl_space_from_domain(space); |
6300 | ma = isl_multi_aff_zero(space); |
6301 | return isl_pw_multi_aff_alloc(set, el: ma); |
6302 | } |
6303 | |
6304 | /* Add an isl_pw_multi_aff with the given "set" as domain and |
6305 | * an unnamed zero-dimensional range to *user. |
6306 | */ |
6307 | static isl_stat add_pw_multi_aff_from_domain(__isl_take isl_set *set, |
6308 | void *user) |
6309 | { |
6310 | isl_union_pw_multi_aff **upma = user; |
6311 | isl_pw_multi_aff *pma; |
6312 | |
6313 | pma = isl_pw_multi_aff_from_domain(set); |
6314 | *upma = isl_union_pw_multi_aff_add_pw_multi_aff(u: *upma, part: pma); |
6315 | |
6316 | return isl_stat_ok; |
6317 | } |
6318 | |
6319 | /* Return an isl_union_pw_multi_aff with the given "uset" as domain and |
6320 | * an unnamed zero-dimensional range. |
6321 | */ |
6322 | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_domain( |
6323 | __isl_take isl_union_set *uset) |
6324 | { |
6325 | isl_space *space; |
6326 | isl_union_pw_multi_aff *upma; |
6327 | |
6328 | if (!uset) |
6329 | return NULL; |
6330 | |
6331 | space = isl_union_set_get_space(uset); |
6332 | upma = isl_union_pw_multi_aff_empty(space); |
6333 | |
6334 | if (isl_union_set_foreach_set(uset, |
6335 | fn: &add_pw_multi_aff_from_domain, user: &upma) < 0) |
6336 | goto error; |
6337 | |
6338 | isl_union_set_free(uset); |
6339 | return upma; |
6340 | error: |
6341 | isl_union_set_free(uset); |
6342 | isl_union_pw_multi_aff_free(u: upma); |
6343 | return NULL; |
6344 | } |
6345 | |
6346 | /* Local data for bin_entry and the callback "fn". |
6347 | */ |
6348 | struct isl_union_pw_multi_aff_bin_data { |
6349 | isl_union_pw_multi_aff *upma2; |
6350 | isl_union_pw_multi_aff *res; |
6351 | isl_pw_multi_aff *pma; |
6352 | isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma, void *user); |
6353 | }; |
6354 | |
6355 | /* Given an isl_pw_multi_aff from upma1, store it in data->pma |
6356 | * and call data->fn for each isl_pw_multi_aff in data->upma2. |
6357 | */ |
6358 | static isl_stat bin_entry(__isl_take isl_pw_multi_aff *pma, void *user) |
6359 | { |
6360 | struct isl_union_pw_multi_aff_bin_data *data = user; |
6361 | isl_stat r; |
6362 | |
6363 | data->pma = pma; |
6364 | r = isl_union_pw_multi_aff_foreach_pw_multi_aff(u: data->upma2, |
6365 | fn: data->fn, user: data); |
6366 | isl_pw_multi_aff_free(pw: pma); |
6367 | |
6368 | return r; |
6369 | } |
6370 | |
6371 | /* Call "fn" on each pair of isl_pw_multi_affs in "upma1" and "upma2". |
6372 | * The isl_pw_multi_aff from upma1 is stored in data->pma (where data is |
6373 | * passed as user field) and the isl_pw_multi_aff from upma2 is available |
6374 | * as *entry. The callback should adjust data->res if desired. |
6375 | */ |
6376 | static __isl_give isl_union_pw_multi_aff *bin_op( |
6377 | __isl_take isl_union_pw_multi_aff *upma1, |
6378 | __isl_take isl_union_pw_multi_aff *upma2, |
6379 | isl_stat (*fn)(__isl_take isl_pw_multi_aff *pma, void *user)) |
6380 | { |
6381 | isl_space *space; |
6382 | struct isl_union_pw_multi_aff_bin_data data = { NULL, NULL, NULL, fn }; |
6383 | |
6384 | space = isl_union_pw_multi_aff_get_space(u: upma2); |
6385 | upma1 = isl_union_pw_multi_aff_align_params(u: upma1, model: space); |
6386 | space = isl_union_pw_multi_aff_get_space(u: upma1); |
6387 | upma2 = isl_union_pw_multi_aff_align_params(u: upma2, model: space); |
6388 | |
6389 | if (!upma1 || !upma2) |
6390 | goto error; |
6391 | |
6392 | data.upma2 = upma2; |
6393 | data.res = isl_union_pw_multi_aff_alloc_same_size(u: upma1); |
6394 | if (isl_union_pw_multi_aff_foreach_pw_multi_aff(u: upma1, |
6395 | fn: &bin_entry, user: &data) < 0) |
6396 | goto error; |
6397 | |
6398 | isl_union_pw_multi_aff_free(u: upma1); |
6399 | isl_union_pw_multi_aff_free(u: upma2); |
6400 | return data.res; |
6401 | error: |
6402 | isl_union_pw_multi_aff_free(u: upma1); |
6403 | isl_union_pw_multi_aff_free(u: upma2); |
6404 | isl_union_pw_multi_aff_free(u: data.res); |
6405 | return NULL; |
6406 | } |
6407 | |
6408 | /* Given two isl_pw_multi_affs A -> B and C -> D, |
6409 | * construct an isl_pw_multi_aff (A * C) -> [B -> D]. |
6410 | */ |
6411 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_range_product( |
6412 | __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) |
6413 | { |
6414 | isl_space *space; |
6415 | |
6416 | isl_pw_multi_aff_align_params_bin(obj1: &pma1, obj2: &pma2); |
6417 | space = isl_space_range_product(left: isl_pw_multi_aff_get_space(pw: pma1), |
6418 | right: isl_pw_multi_aff_get_space(pw: pma2)); |
6419 | return isl_pw_multi_aff_on_shared_domain_in(pw1: pma1, pw2: pma2, space, |
6420 | fn: &isl_multi_aff_range_product); |
6421 | } |
6422 | |
6423 | /* Given two isl_pw_multi_affs A -> B and C -> D, |
6424 | * construct an isl_pw_multi_aff (A * C) -> (B, D). |
6425 | */ |
6426 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_flat_range_product( |
6427 | __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) |
6428 | { |
6429 | isl_space *space; |
6430 | |
6431 | isl_pw_multi_aff_align_params_bin(obj1: &pma1, obj2: &pma2); |
6432 | space = isl_space_range_product(left: isl_pw_multi_aff_get_space(pw: pma1), |
6433 | right: isl_pw_multi_aff_get_space(pw: pma2)); |
6434 | space = isl_space_flatten_range(space); |
6435 | return isl_pw_multi_aff_on_shared_domain_in(pw1: pma1, pw2: pma2, space, |
6436 | fn: &isl_multi_aff_flat_range_product); |
6437 | } |
6438 | |
6439 | /* If data->pma and "pma2" have the same domain space, then use "range_product" |
6440 | * to compute some form of range product and add the result to data->res. |
6441 | */ |
6442 | static isl_stat gen_range_product_entry(__isl_take isl_pw_multi_aff *pma2, |
6443 | __isl_give isl_pw_multi_aff *(*range_product)( |
6444 | __isl_take isl_pw_multi_aff *pma1, |
6445 | __isl_take isl_pw_multi_aff *pma2), |
6446 | void *user) |
6447 | { |
6448 | struct isl_union_pw_multi_aff_bin_data *data = user; |
6449 | isl_bool match; |
6450 | isl_space *space1, *space2; |
6451 | |
6452 | space1 = isl_pw_multi_aff_peek_space(pw: data->pma); |
6453 | space2 = isl_pw_multi_aff_peek_space(pw: pma2); |
6454 | match = isl_space_tuple_is_equal(space1, type1: isl_dim_in, |
6455 | space2, type2: isl_dim_in); |
6456 | if (match < 0 || !match) { |
6457 | isl_pw_multi_aff_free(pw: pma2); |
6458 | return match < 0 ? isl_stat_error : isl_stat_ok; |
6459 | } |
6460 | |
6461 | pma2 = range_product(isl_pw_multi_aff_copy(pw: data->pma), pma2); |
6462 | |
6463 | data->res = isl_union_pw_multi_aff_add_pw_multi_aff(u: data->res, part: pma2); |
6464 | |
6465 | return isl_stat_ok; |
6466 | } |
6467 | |
6468 | /* If data->pma and "pma2" have the same domain space, then compute |
6469 | * their flat range product and add the result to data->res. |
6470 | */ |
6471 | static isl_stat flat_range_product_entry(__isl_take isl_pw_multi_aff *pma2, |
6472 | void *user) |
6473 | { |
6474 | return gen_range_product_entry(pma2, |
6475 | range_product: &isl_pw_multi_aff_flat_range_product, user); |
6476 | } |
6477 | |
6478 | /* Given two isl_union_pw_multi_affs A -> B and C -> D, |
6479 | * construct an isl_union_pw_multi_aff (A * C) -> (B, D). |
6480 | */ |
6481 | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_flat_range_product( |
6482 | __isl_take isl_union_pw_multi_aff *upma1, |
6483 | __isl_take isl_union_pw_multi_aff *upma2) |
6484 | { |
6485 | return bin_op(upma1, upma2, fn: &flat_range_product_entry); |
6486 | } |
6487 | |
6488 | /* If data->pma and "pma2" have the same domain space, then compute |
6489 | * their range product and add the result to data->res. |
6490 | */ |
6491 | static isl_stat range_product_entry(__isl_take isl_pw_multi_aff *pma2, |
6492 | void *user) |
6493 | { |
6494 | return gen_range_product_entry(pma2, |
6495 | range_product: &isl_pw_multi_aff_range_product, user); |
6496 | } |
6497 | |
6498 | /* Given two isl_union_pw_multi_affs A -> B and C -> D, |
6499 | * construct an isl_union_pw_multi_aff (A * C) -> [B -> D]. |
6500 | */ |
6501 | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_range_product( |
6502 | __isl_take isl_union_pw_multi_aff *upma1, |
6503 | __isl_take isl_union_pw_multi_aff *upma2) |
6504 | { |
6505 | return bin_op(upma1, upma2, fn: &range_product_entry); |
6506 | } |
6507 | |
6508 | /* Replace the affine expressions at position "pos" in "pma" by "pa". |
6509 | * The parameters are assumed to have been aligned. |
6510 | * |
6511 | * The implementation essentially performs an isl_pw_*_on_shared_domain, |
6512 | * except that it works on two different isl_pw_* types. |
6513 | */ |
6514 | static __isl_give isl_pw_multi_aff *pw_multi_aff_set_pw_aff( |
6515 | __isl_take isl_pw_multi_aff *pma, unsigned pos, |
6516 | __isl_take isl_pw_aff *pa) |
6517 | { |
6518 | int i, j, n; |
6519 | isl_pw_multi_aff *res = NULL; |
6520 | |
6521 | if (!pma || !pa) |
6522 | goto error; |
6523 | |
6524 | if (!isl_space_tuple_is_equal(space1: pma->dim, type1: isl_dim_in, |
6525 | space2: pa->dim, type2: isl_dim_in)) |
6526 | isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, |
6527 | "domains don't match" , goto error); |
6528 | if (isl_pw_multi_aff_check_range(obj: pma, type: isl_dim_out, first: pos, n: 1) < 0) |
6529 | goto error; |
6530 | |
6531 | n = pma->n * pa->n; |
6532 | res = isl_pw_multi_aff_alloc_size(space: isl_pw_multi_aff_get_space(pw: pma), n); |
6533 | |
6534 | for (i = 0; i < pma->n; ++i) { |
6535 | for (j = 0; j < pa->n; ++j) { |
6536 | isl_set *common; |
6537 | isl_multi_aff *res_ij; |
6538 | int empty; |
6539 | |
6540 | common = isl_set_intersect(set1: isl_set_copy(set: pma->p[i].set), |
6541 | set2: isl_set_copy(set: pa->p[j].set)); |
6542 | empty = isl_set_plain_is_empty(set: common); |
6543 | if (empty < 0 || empty) { |
6544 | isl_set_free(set: common); |
6545 | if (empty < 0) |
6546 | goto error; |
6547 | continue; |
6548 | } |
6549 | |
6550 | res_ij = isl_multi_aff_set_aff( |
6551 | multi: isl_multi_aff_copy(multi: pma->p[i].maff), pos, |
6552 | el: isl_aff_copy(aff: pa->p[j].aff)); |
6553 | res_ij = isl_multi_aff_gist(multi: res_ij, |
6554 | context: isl_set_copy(set: common)); |
6555 | |
6556 | res = isl_pw_multi_aff_add_piece(pw: res, set: common, el: res_ij); |
6557 | } |
6558 | } |
6559 | |
6560 | isl_pw_multi_aff_free(pw: pma); |
6561 | isl_pw_aff_free(pw: pa); |
6562 | return res; |
6563 | error: |
6564 | isl_pw_multi_aff_free(pw: pma); |
6565 | isl_pw_aff_free(pw: pa); |
6566 | return isl_pw_multi_aff_free(pw: res); |
6567 | } |
6568 | |
6569 | /* Replace the affine expressions at position "pos" in "pma" by "pa". |
6570 | */ |
6571 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_set_pw_aff( |
6572 | __isl_take isl_pw_multi_aff *pma, unsigned pos, |
6573 | __isl_take isl_pw_aff *pa) |
6574 | { |
6575 | isl_bool equal_params; |
6576 | |
6577 | if (!pma || !pa) |
6578 | goto error; |
6579 | equal_params = isl_space_has_equal_params(space1: pma->dim, space2: pa->dim); |
6580 | if (equal_params < 0) |
6581 | goto error; |
6582 | if (equal_params) |
6583 | return pw_multi_aff_set_pw_aff(pma, pos, pa); |
6584 | if (isl_pw_multi_aff_check_named_params(obj: pma) < 0 || |
6585 | isl_pw_aff_check_named_params(obj: pa) < 0) |
6586 | goto error; |
6587 | pma = isl_pw_multi_aff_align_params(pw: pma, model: isl_pw_aff_get_space(pw: pa)); |
6588 | pa = isl_pw_aff_align_params(pw: pa, model: isl_pw_multi_aff_get_space(pw: pma)); |
6589 | return pw_multi_aff_set_pw_aff(pma, pos, pa); |
6590 | error: |
6591 | isl_pw_multi_aff_free(pw: pma); |
6592 | isl_pw_aff_free(pw: pa); |
6593 | return NULL; |
6594 | } |
6595 | |
6596 | /* Do the parameters of "pa" match those of "space"? |
6597 | */ |
6598 | isl_bool isl_pw_aff_matching_params(__isl_keep isl_pw_aff *pa, |
6599 | __isl_keep isl_space *space) |
6600 | { |
6601 | isl_space *pa_space; |
6602 | isl_bool match; |
6603 | |
6604 | if (!pa || !space) |
6605 | return isl_bool_error; |
6606 | |
6607 | pa_space = isl_pw_aff_get_space(pw: pa); |
6608 | |
6609 | match = isl_space_has_equal_params(space1: space, space2: pa_space); |
6610 | |
6611 | isl_space_free(space: pa_space); |
6612 | return match; |
6613 | } |
6614 | |
6615 | /* Check that the domain space of "pa" matches "space". |
6616 | */ |
6617 | isl_stat isl_pw_aff_check_match_domain_space(__isl_keep isl_pw_aff *pa, |
6618 | __isl_keep isl_space *space) |
6619 | { |
6620 | isl_space *pa_space; |
6621 | isl_bool match; |
6622 | |
6623 | if (!pa || !space) |
6624 | return isl_stat_error; |
6625 | |
6626 | pa_space = isl_pw_aff_get_space(pw: pa); |
6627 | |
6628 | match = isl_space_has_equal_params(space1: space, space2: pa_space); |
6629 | if (match < 0) |
6630 | goto error; |
6631 | if (!match) |
6632 | isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, |
6633 | "parameters don't match" , goto error); |
6634 | match = isl_space_tuple_is_equal(space1: space, type1: isl_dim_in, |
6635 | space2: pa_space, type2: isl_dim_in); |
6636 | if (match < 0) |
6637 | goto error; |
6638 | if (!match) |
6639 | isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, |
6640 | "domains don't match" , goto error); |
6641 | isl_space_free(space: pa_space); |
6642 | return isl_stat_ok; |
6643 | error: |
6644 | isl_space_free(space: pa_space); |
6645 | return isl_stat_error; |
6646 | } |
6647 | |
6648 | #undef BASE |
6649 | #define BASE pw_aff |
6650 | #undef DOMBASE |
6651 | #define DOMBASE set |
6652 | |
6653 | #include <isl_multi_explicit_domain.c> |
6654 | #include <isl_multi_pw_aff_explicit_domain.c> |
6655 | #include <isl_multi_templ.c> |
6656 | #include <isl_multi_un_op_templ.c> |
6657 | #include <isl_multi_bin_val_templ.c> |
6658 | #include <isl_multi_add_constant_templ.c> |
6659 | #include <isl_multi_apply_set.c> |
6660 | #include <isl_multi_arith_templ.c> |
6661 | #include <isl_multi_bind_templ.c> |
6662 | #include <isl_multi_bind_domain_templ.c> |
6663 | #include <isl_multi_coalesce.c> |
6664 | #include <isl_multi_domain_templ.c> |
6665 | #include <isl_multi_dim_id_templ.c> |
6666 | #include <isl_multi_dims.c> |
6667 | #include <isl_multi_from_base_templ.c> |
6668 | #include <isl_multi_gist.c> |
6669 | #include <isl_multi_hash.c> |
6670 | #include <isl_multi_identity_templ.c> |
6671 | #include <isl_multi_align_set.c> |
6672 | #include <isl_multi_insert_domain_templ.c> |
6673 | #include <isl_multi_intersect.c> |
6674 | #include <isl_multi_min_max_templ.c> |
6675 | #include <isl_multi_move_dims_templ.c> |
6676 | #include <isl_multi_nan_templ.c> |
6677 | #include <isl_multi_param_templ.c> |
6678 | #include <isl_multi_product_templ.c> |
6679 | #include <isl_multi_splice_templ.c> |
6680 | #include <isl_multi_tuple_id_templ.c> |
6681 | #include <isl_multi_union_add_templ.c> |
6682 | #include <isl_multi_zero_templ.c> |
6683 | #include <isl_multi_unbind_params_templ.c> |
6684 | |
6685 | /* Is every element of "mpa" defined over a single universe domain? |
6686 | */ |
6687 | isl_bool isl_multi_pw_aff_isa_multi_aff(__isl_keep isl_multi_pw_aff *mpa) |
6688 | { |
6689 | return isl_multi_pw_aff_every(multi: mpa, test: &isl_pw_aff_isa_aff); |
6690 | } |
6691 | |
6692 | /* Given that every element of "mpa" is defined over a single universe domain, |
6693 | * return the corresponding base expressions. |
6694 | */ |
6695 | __isl_give isl_multi_aff *isl_multi_pw_aff_as_multi_aff( |
6696 | __isl_take isl_multi_pw_aff *mpa) |
6697 | { |
6698 | int i; |
6699 | isl_size n; |
6700 | isl_multi_aff *ma; |
6701 | |
6702 | n = isl_multi_pw_aff_size(multi: mpa); |
6703 | if (n < 0) |
6704 | mpa = isl_multi_pw_aff_free(multi: mpa); |
6705 | ma = isl_multi_aff_alloc(space: isl_multi_pw_aff_get_space(multi: mpa)); |
6706 | for (i = 0; i < n; ++i) { |
6707 | isl_aff *aff; |
6708 | |
6709 | aff = isl_pw_aff_as_aff(pw: isl_multi_pw_aff_get_at(multi: mpa, pos: i)); |
6710 | ma = isl_multi_aff_set_aff(multi: ma, pos: i, el: aff); |
6711 | } |
6712 | isl_multi_pw_aff_free(multi: mpa); |
6713 | return ma; |
6714 | } |
6715 | |
6716 | /* If "mpa" has an explicit domain, then intersect the domain of "map" |
6717 | * with this explicit domain. |
6718 | */ |
6719 | __isl_give isl_map *isl_map_intersect_multi_pw_aff_explicit_domain( |
6720 | __isl_take isl_map *map, __isl_keep isl_multi_pw_aff *mpa) |
6721 | { |
6722 | isl_set *dom; |
6723 | |
6724 | if (!isl_multi_pw_aff_has_explicit_domain(multi: mpa)) |
6725 | return map; |
6726 | |
6727 | dom = isl_multi_pw_aff_domain(multi: isl_multi_pw_aff_copy(multi: mpa)); |
6728 | map = isl_map_intersect_domain(map, set: dom); |
6729 | |
6730 | return map; |
6731 | } |
6732 | |
6733 | /* Are all elements of "mpa" piecewise constants? |
6734 | */ |
6735 | isl_bool isl_multi_pw_aff_is_cst(__isl_keep isl_multi_pw_aff *mpa) |
6736 | { |
6737 | return isl_multi_pw_aff_every(multi: mpa, test: &isl_pw_aff_is_cst); |
6738 | } |
6739 | |
6740 | /* Does "mpa" have a non-trivial explicit domain? |
6741 | * |
6742 | * The explicit domain, if present, is trivial if it represents |
6743 | * an (obviously) universe set. |
6744 | */ |
6745 | isl_bool isl_multi_pw_aff_has_non_trivial_domain( |
6746 | __isl_keep isl_multi_pw_aff *mpa) |
6747 | { |
6748 | if (!mpa) |
6749 | return isl_bool_error; |
6750 | if (!isl_multi_pw_aff_has_explicit_domain(multi: mpa)) |
6751 | return isl_bool_false; |
6752 | return isl_bool_not(b: isl_set_plain_is_universe(set: mpa->u.dom)); |
6753 | } |
6754 | |
6755 | #undef BASE |
6756 | #define BASE set |
6757 | |
6758 | #include "isl_opt_mpa_templ.c" |
6759 | |
6760 | /* Compute the minima of the set dimensions as a function of the |
6761 | * parameters, but independently of the other set dimensions. |
6762 | */ |
6763 | __isl_give isl_multi_pw_aff *isl_set_min_multi_pw_aff(__isl_take isl_set *set) |
6764 | { |
6765 | return set_opt_mpa(obj: set, opt: &isl_set_dim_min); |
6766 | } |
6767 | |
6768 | /* Compute the maxima of the set dimensions as a function of the |
6769 | * parameters, but independently of the other set dimensions. |
6770 | */ |
6771 | __isl_give isl_multi_pw_aff *isl_set_max_multi_pw_aff(__isl_take isl_set *set) |
6772 | { |
6773 | return set_opt_mpa(obj: set, opt: &isl_set_dim_max); |
6774 | } |
6775 | |
6776 | #undef BASE |
6777 | #define BASE map |
6778 | |
6779 | #include "isl_opt_mpa_templ.c" |
6780 | |
6781 | /* Compute the minima of the output dimensions as a function of the |
6782 | * parameters and input dimensions, but independently of |
6783 | * the other output dimensions. |
6784 | */ |
6785 | __isl_give isl_multi_pw_aff *isl_map_min_multi_pw_aff(__isl_take isl_map *map) |
6786 | { |
6787 | return map_opt_mpa(obj: map, opt: &isl_map_dim_min); |
6788 | } |
6789 | |
6790 | /* Compute the maxima of the output dimensions as a function of the |
6791 | * parameters and input dimensions, but independently of |
6792 | * the other output dimensions. |
6793 | */ |
6794 | __isl_give isl_multi_pw_aff *isl_map_max_multi_pw_aff(__isl_take isl_map *map) |
6795 | { |
6796 | return map_opt_mpa(obj: map, opt: &isl_map_dim_max); |
6797 | } |
6798 | |
6799 | #undef TYPE |
6800 | #define TYPE isl_pw_multi_aff |
6801 | #include "isl_type_check_match_range_multi_val.c" |
6802 | |
6803 | /* Apply "fn" to the base expressions of "pma" and "mv". |
6804 | */ |
6805 | static __isl_give isl_pw_multi_aff *isl_pw_multi_aff_op_multi_val( |
6806 | __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv, |
6807 | __isl_give isl_multi_aff *(*fn)(__isl_take isl_multi_aff *ma, |
6808 | __isl_take isl_multi_val *mv)) |
6809 | { |
6810 | int i; |
6811 | isl_size n; |
6812 | |
6813 | if (isl_pw_multi_aff_check_match_range_multi_val(obj: pma, mv) < 0) |
6814 | goto error; |
6815 | |
6816 | n = isl_pw_multi_aff_n_piece(pw: pma); |
6817 | if (n < 0) |
6818 | goto error; |
6819 | |
6820 | for (i = 0; i < n; ++i) { |
6821 | isl_multi_aff *ma; |
6822 | |
6823 | ma = isl_pw_multi_aff_take_base_at(pw: pma, pos: i); |
6824 | ma = fn(ma, isl_multi_val_copy(multi: mv)); |
6825 | pma = isl_pw_multi_aff_restore_base_at(pw: pma, pos: i, el: ma); |
6826 | } |
6827 | |
6828 | isl_multi_val_free(multi: mv); |
6829 | return pma; |
6830 | error: |
6831 | isl_multi_val_free(multi: mv); |
6832 | isl_pw_multi_aff_free(pw: pma); |
6833 | return NULL; |
6834 | } |
6835 | |
6836 | /* Scale the elements of "pma" by the corresponding elements of "mv". |
6837 | */ |
6838 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_multi_val( |
6839 | __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv) |
6840 | { |
6841 | return isl_pw_multi_aff_op_multi_val(pma, mv, |
6842 | fn: &isl_multi_aff_scale_multi_val); |
6843 | } |
6844 | |
6845 | /* Scale the elements of "pma" down by the corresponding elements of "mv". |
6846 | */ |
6847 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_scale_down_multi_val( |
6848 | __isl_take isl_pw_multi_aff *pma, __isl_take isl_multi_val *mv) |
6849 | { |
6850 | return isl_pw_multi_aff_op_multi_val(pma, mv, |
6851 | fn: &isl_multi_aff_scale_down_multi_val); |
6852 | } |
6853 | |
6854 | /* This function is called for each entry of an isl_union_pw_multi_aff. |
6855 | * If the space of the entry matches that of data->mv, |
6856 | * then apply isl_pw_multi_aff_scale_multi_val and return the result. |
6857 | * Otherwise, return an empty isl_pw_multi_aff. |
6858 | */ |
6859 | static __isl_give isl_pw_multi_aff *union_pw_multi_aff_scale_multi_val_entry( |
6860 | __isl_take isl_pw_multi_aff *pma, void *user) |
6861 | { |
6862 | isl_bool equal; |
6863 | isl_multi_val *mv = user; |
6864 | |
6865 | equal = isl_pw_multi_aff_match_range_multi_val(obj: pma, mv); |
6866 | if (equal < 0) |
6867 | return isl_pw_multi_aff_free(pw: pma); |
6868 | if (!equal) { |
6869 | isl_space *space = isl_pw_multi_aff_get_space(pw: pma); |
6870 | isl_pw_multi_aff_free(pw: pma); |
6871 | return isl_pw_multi_aff_empty(space); |
6872 | } |
6873 | |
6874 | return isl_pw_multi_aff_scale_multi_val(pma, mv: isl_multi_val_copy(multi: mv)); |
6875 | } |
6876 | |
6877 | /* Scale the elements of "upma" by the corresponding elements of "mv", |
6878 | * for those entries that match the space of "mv". |
6879 | */ |
6880 | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_scale_multi_val( |
6881 | __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_multi_val *mv) |
6882 | { |
6883 | struct isl_union_pw_multi_aff_transform_control control = { |
6884 | .fn = &union_pw_multi_aff_scale_multi_val_entry, |
6885 | .fn_user = mv, |
6886 | }; |
6887 | |
6888 | upma = isl_union_pw_multi_aff_align_params(u: upma, |
6889 | model: isl_multi_val_get_space(multi: mv)); |
6890 | mv = isl_multi_val_align_params(multi: mv, |
6891 | model: isl_union_pw_multi_aff_get_space(u: upma)); |
6892 | if (!upma || !mv) |
6893 | goto error; |
6894 | |
6895 | return isl_union_pw_multi_aff_transform(u: upma, control: &control); |
6896 | |
6897 | isl_multi_val_free(multi: mv); |
6898 | return upma; |
6899 | error: |
6900 | isl_multi_val_free(multi: mv); |
6901 | isl_union_pw_multi_aff_free(u: upma); |
6902 | return NULL; |
6903 | } |
6904 | |
6905 | /* Construct and return a piecewise multi affine expression |
6906 | * in the given space with value zero in each of the output dimensions and |
6907 | * a universe domain. |
6908 | */ |
6909 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_zero(__isl_take isl_space *space) |
6910 | { |
6911 | return isl_pw_multi_aff_from_multi_aff(el: isl_multi_aff_zero(space)); |
6912 | } |
6913 | |
6914 | /* Construct and return a piecewise multi affine expression |
6915 | * that is equal to the given piecewise affine expression. |
6916 | */ |
6917 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_pw_aff( |
6918 | __isl_take isl_pw_aff *pa) |
6919 | { |
6920 | int i; |
6921 | isl_space *space; |
6922 | isl_pw_multi_aff *pma; |
6923 | |
6924 | if (!pa) |
6925 | return NULL; |
6926 | |
6927 | space = isl_pw_aff_get_space(pw: pa); |
6928 | pma = isl_pw_multi_aff_alloc_size(space, n: pa->n); |
6929 | |
6930 | for (i = 0; i < pa->n; ++i) { |
6931 | isl_set *set; |
6932 | isl_multi_aff *ma; |
6933 | |
6934 | set = isl_set_copy(set: pa->p[i].set); |
6935 | ma = isl_multi_aff_from_aff(el: isl_aff_copy(aff: pa->p[i].aff)); |
6936 | pma = isl_pw_multi_aff_add_piece(pw: pma, set, el: ma); |
6937 | } |
6938 | |
6939 | isl_pw_aff_free(pw: pa); |
6940 | return pma; |
6941 | } |
6942 | |
6943 | /* Construct and return a piecewise multi affine expression |
6944 | * that is equal to the given multi piecewise affine expression |
6945 | * on the shared domain of the piecewise affine expressions, |
6946 | * in the special case of a 0D multi piecewise affine expression. |
6947 | * |
6948 | * Create a piecewise multi affine expression with the explicit domain of |
6949 | * the 0D multi piecewise affine expression as domain. |
6950 | */ |
6951 | static __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_pw_aff_0D( |
6952 | __isl_take isl_multi_pw_aff *mpa) |
6953 | { |
6954 | isl_space *space; |
6955 | isl_set *dom; |
6956 | isl_multi_aff *ma; |
6957 | |
6958 | space = isl_multi_pw_aff_get_space(multi: mpa); |
6959 | dom = isl_multi_pw_aff_get_explicit_domain(multi: mpa); |
6960 | isl_multi_pw_aff_free(multi: mpa); |
6961 | |
6962 | ma = isl_multi_aff_zero(space); |
6963 | return isl_pw_multi_aff_alloc(set: dom, el: ma); |
6964 | } |
6965 | |
6966 | /* Construct and return a piecewise multi affine expression |
6967 | * that is equal to the given multi piecewise affine expression |
6968 | * on the shared domain of the piecewise affine expressions. |
6969 | */ |
6970 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_from_multi_pw_aff( |
6971 | __isl_take isl_multi_pw_aff *mpa) |
6972 | { |
6973 | int i; |
6974 | isl_space *space; |
6975 | isl_pw_aff *pa; |
6976 | isl_pw_multi_aff *pma; |
6977 | |
6978 | if (!mpa) |
6979 | return NULL; |
6980 | |
6981 | if (mpa->n == 0) |
6982 | return isl_pw_multi_aff_from_multi_pw_aff_0D(mpa); |
6983 | |
6984 | space = isl_multi_pw_aff_get_space(multi: mpa); |
6985 | pa = isl_multi_pw_aff_get_pw_aff(multi: mpa, pos: 0); |
6986 | pma = isl_pw_multi_aff_from_pw_aff(pa); |
6987 | |
6988 | for (i = 1; i < mpa->n; ++i) { |
6989 | isl_pw_multi_aff *pma_i; |
6990 | |
6991 | pa = isl_multi_pw_aff_get_pw_aff(multi: mpa, pos: i); |
6992 | pma_i = isl_pw_multi_aff_from_pw_aff(pa); |
6993 | pma = isl_pw_multi_aff_range_product(pma1: pma, pma2: pma_i); |
6994 | } |
6995 | |
6996 | pma = isl_pw_multi_aff_reset_space(pw: pma, space); |
6997 | |
6998 | isl_multi_pw_aff_free(multi: mpa); |
6999 | return pma; |
7000 | } |
7001 | |
7002 | /* Convenience function that constructs an isl_multi_pw_aff |
7003 | * directly from an isl_aff. |
7004 | */ |
7005 | __isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_aff(__isl_take isl_aff *aff) |
7006 | { |
7007 | return isl_multi_pw_aff_from_pw_aff(el: isl_pw_aff_from_aff(el: aff)); |
7008 | } |
7009 | |
7010 | /* Construct and return a multi piecewise affine expression |
7011 | * that is equal to the given multi affine expression. |
7012 | */ |
7013 | __isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_multi_aff( |
7014 | __isl_take isl_multi_aff *ma) |
7015 | { |
7016 | int i; |
7017 | isl_size n; |
7018 | isl_multi_pw_aff *mpa; |
7019 | |
7020 | n = isl_multi_aff_dim(multi: ma, type: isl_dim_out); |
7021 | if (n < 0) |
7022 | ma = isl_multi_aff_free(multi: ma); |
7023 | if (!ma) |
7024 | return NULL; |
7025 | |
7026 | mpa = isl_multi_pw_aff_alloc(space: isl_multi_aff_get_space(multi: ma)); |
7027 | |
7028 | for (i = 0; i < n; ++i) { |
7029 | isl_pw_aff *pa; |
7030 | |
7031 | pa = isl_pw_aff_from_aff(el: isl_multi_aff_get_aff(multi: ma, pos: i)); |
7032 | mpa = isl_multi_pw_aff_set_pw_aff(multi: mpa, pos: i, el: pa); |
7033 | } |
7034 | |
7035 | isl_multi_aff_free(multi: ma); |
7036 | return mpa; |
7037 | } |
7038 | |
7039 | /* This function performs the same operation as isl_multi_pw_aff_from_multi_aff, |
7040 | * but is considered as a function on an isl_multi_aff when exported. |
7041 | */ |
7042 | __isl_give isl_multi_pw_aff *isl_multi_aff_to_multi_pw_aff( |
7043 | __isl_take isl_multi_aff *ma) |
7044 | { |
7045 | return isl_multi_pw_aff_from_multi_aff(ma); |
7046 | } |
7047 | |
7048 | /* Construct and return a multi piecewise affine expression |
7049 | * that is equal to the given piecewise multi affine expression. |
7050 | * |
7051 | * If the resulting multi piecewise affine expression has |
7052 | * an explicit domain, then assign it the domain of the input. |
7053 | * In other cases, the domain is stored in the individual elements. |
7054 | */ |
7055 | __isl_give isl_multi_pw_aff *isl_multi_pw_aff_from_pw_multi_aff( |
7056 | __isl_take isl_pw_multi_aff *pma) |
7057 | { |
7058 | int i; |
7059 | isl_size n; |
7060 | isl_space *space; |
7061 | isl_multi_pw_aff *mpa; |
7062 | |
7063 | n = isl_pw_multi_aff_dim(pw: pma, type: isl_dim_out); |
7064 | if (n < 0) |
7065 | pma = isl_pw_multi_aff_free(pw: pma); |
7066 | space = isl_pw_multi_aff_get_space(pw: pma); |
7067 | mpa = isl_multi_pw_aff_alloc(space); |
7068 | |
7069 | for (i = 0; i < n; ++i) { |
7070 | isl_pw_aff *pa; |
7071 | |
7072 | pa = isl_pw_multi_aff_get_pw_aff(pma, pos: i); |
7073 | mpa = isl_multi_pw_aff_set_pw_aff(multi: mpa, pos: i, el: pa); |
7074 | } |
7075 | if (isl_multi_pw_aff_has_explicit_domain(multi: mpa)) { |
7076 | isl_set *dom; |
7077 | |
7078 | dom = isl_pw_multi_aff_domain(pw: isl_pw_multi_aff_copy(pw: pma)); |
7079 | mpa = isl_multi_pw_aff_intersect_domain(multi: mpa, domain: dom); |
7080 | } |
7081 | |
7082 | isl_pw_multi_aff_free(pw: pma); |
7083 | return mpa; |
7084 | } |
7085 | |
7086 | /* This function performs the same operation as |
7087 | * isl_multi_pw_aff_from_pw_multi_aff, |
7088 | * but is considered as a function on an isl_pw_multi_aff when exported. |
7089 | */ |
7090 | __isl_give isl_multi_pw_aff *isl_pw_multi_aff_to_multi_pw_aff( |
7091 | __isl_take isl_pw_multi_aff *pma) |
7092 | { |
7093 | return isl_multi_pw_aff_from_pw_multi_aff(pma); |
7094 | } |
7095 | |
7096 | /* Do "pa1" and "pa2" represent the same function? |
7097 | * |
7098 | * We first check if they are obviously equal. |
7099 | * If not, we convert them to maps and check if those are equal. |
7100 | * |
7101 | * If "pa1" or "pa2" contain any NaNs, then they are considered |
7102 | * not to be the same. A NaN is not equal to anything, not even |
7103 | * to another NaN. |
7104 | */ |
7105 | isl_bool isl_pw_aff_is_equal(__isl_keep isl_pw_aff *pa1, |
7106 | __isl_keep isl_pw_aff *pa2) |
7107 | { |
7108 | isl_bool equal; |
7109 | isl_bool has_nan; |
7110 | isl_map *map1, *map2; |
7111 | |
7112 | if (!pa1 || !pa2) |
7113 | return isl_bool_error; |
7114 | |
7115 | equal = isl_pw_aff_plain_is_equal(pw1: pa1, pw2: pa2); |
7116 | if (equal < 0 || equal) |
7117 | return equal; |
7118 | has_nan = either_involves_nan(pa1, pa2); |
7119 | if (has_nan < 0) |
7120 | return isl_bool_error; |
7121 | if (has_nan) |
7122 | return isl_bool_false; |
7123 | |
7124 | map1 = isl_map_from_pw_aff_internal(pa: isl_pw_aff_copy(pw: pa1)); |
7125 | map2 = isl_map_from_pw_aff_internal(pa: isl_pw_aff_copy(pw: pa2)); |
7126 | equal = isl_map_is_equal(map1, map2); |
7127 | isl_map_free(map: map1); |
7128 | isl_map_free(map: map2); |
7129 | |
7130 | return equal; |
7131 | } |
7132 | |
7133 | /* Do "mpa1" and "mpa2" represent the same function? |
7134 | * |
7135 | * Note that we cannot convert the entire isl_multi_pw_aff |
7136 | * to a map because the domains of the piecewise affine expressions |
7137 | * may not be the same. |
7138 | */ |
7139 | isl_bool isl_multi_pw_aff_is_equal(__isl_keep isl_multi_pw_aff *mpa1, |
7140 | __isl_keep isl_multi_pw_aff *mpa2) |
7141 | { |
7142 | int i; |
7143 | isl_bool equal, equal_params; |
7144 | |
7145 | if (!mpa1 || !mpa2) |
7146 | return isl_bool_error; |
7147 | |
7148 | equal_params = isl_space_has_equal_params(space1: mpa1->space, space2: mpa2->space); |
7149 | if (equal_params < 0) |
7150 | return isl_bool_error; |
7151 | if (!equal_params) { |
7152 | if (!isl_space_has_named_params(space: mpa1->space)) |
7153 | return isl_bool_false; |
7154 | if (!isl_space_has_named_params(space: mpa2->space)) |
7155 | return isl_bool_false; |
7156 | mpa1 = isl_multi_pw_aff_copy(multi: mpa1); |
7157 | mpa2 = isl_multi_pw_aff_copy(multi: mpa2); |
7158 | mpa1 = isl_multi_pw_aff_align_params(multi: mpa1, |
7159 | model: isl_multi_pw_aff_get_space(multi: mpa2)); |
7160 | mpa2 = isl_multi_pw_aff_align_params(multi: mpa2, |
7161 | model: isl_multi_pw_aff_get_space(multi: mpa1)); |
7162 | equal = isl_multi_pw_aff_is_equal(mpa1, mpa2); |
7163 | isl_multi_pw_aff_free(multi: mpa1); |
7164 | isl_multi_pw_aff_free(multi: mpa2); |
7165 | return equal; |
7166 | } |
7167 | |
7168 | equal = isl_space_is_equal(space1: mpa1->space, space2: mpa2->space); |
7169 | if (equal < 0 || !equal) |
7170 | return equal; |
7171 | |
7172 | for (i = 0; i < mpa1->n; ++i) { |
7173 | equal = isl_pw_aff_is_equal(pa1: mpa1->u.p[i], pa2: mpa2->u.p[i]); |
7174 | if (equal < 0 || !equal) |
7175 | return equal; |
7176 | } |
7177 | |
7178 | return isl_bool_true; |
7179 | } |
7180 | |
7181 | /* Do "pma1" and "pma2" represent the same function? |
7182 | * |
7183 | * First check if they are obviously equal. |
7184 | * If not, then convert them to maps and check if those are equal. |
7185 | * |
7186 | * If "pa1" or "pa2" contain any NaNs, then they are considered |
7187 | * not to be the same. A NaN is not equal to anything, not even |
7188 | * to another NaN. |
7189 | */ |
7190 | isl_bool isl_pw_multi_aff_is_equal(__isl_keep isl_pw_multi_aff *pma1, |
7191 | __isl_keep isl_pw_multi_aff *pma2) |
7192 | { |
7193 | isl_bool equal; |
7194 | isl_bool has_nan; |
7195 | isl_map *map1, *map2; |
7196 | |
7197 | if (!pma1 || !pma2) |
7198 | return isl_bool_error; |
7199 | |
7200 | equal = isl_pw_multi_aff_plain_is_equal(pw1: pma1, pw2: pma2); |
7201 | if (equal < 0 || equal) |
7202 | return equal; |
7203 | has_nan = isl_pw_multi_aff_involves_nan(pw: pma1); |
7204 | if (has_nan >= 0 && !has_nan) |
7205 | has_nan = isl_pw_multi_aff_involves_nan(pw: pma2); |
7206 | if (has_nan < 0 || has_nan) |
7207 | return isl_bool_not(b: has_nan); |
7208 | |
7209 | map1 = isl_map_from_pw_multi_aff_internal(pma: isl_pw_multi_aff_copy(pw: pma1)); |
7210 | map2 = isl_map_from_pw_multi_aff_internal(pma: isl_pw_multi_aff_copy(pw: pma2)); |
7211 | equal = isl_map_is_equal(map1, map2); |
7212 | isl_map_free(map: map1); |
7213 | isl_map_free(map: map2); |
7214 | |
7215 | return equal; |
7216 | } |
7217 | |
7218 | #undef BASE |
7219 | #define BASE multi_aff |
7220 | |
7221 | #include "isl_multi_pw_aff_pullback_templ.c" |
7222 | |
7223 | #undef BASE |
7224 | #define BASE pw_multi_aff |
7225 | |
7226 | #include "isl_multi_pw_aff_pullback_templ.c" |
7227 | |
7228 | /* Apply "aff" to "mpa". The range of "mpa" needs to be compatible |
7229 | * with the domain of "aff". The domain of the result is the same |
7230 | * as that of "mpa". |
7231 | * "mpa" and "aff" are assumed to have been aligned. |
7232 | * |
7233 | * We first extract the parametric constant from "aff", defined |
7234 | * over the correct domain. |
7235 | * Then we add the appropriate combinations of the members of "mpa". |
7236 | * Finally, we add the integer divisions through recursive calls. |
7237 | */ |
7238 | static __isl_give isl_pw_aff *isl_multi_pw_aff_apply_aff_aligned( |
7239 | __isl_take isl_multi_pw_aff *mpa, __isl_take isl_aff *aff) |
7240 | { |
7241 | int i; |
7242 | isl_size n_in, n_div, n_mpa_in; |
7243 | isl_space *space; |
7244 | isl_val *v; |
7245 | isl_pw_aff *pa; |
7246 | isl_aff *tmp; |
7247 | |
7248 | n_in = isl_aff_dim(aff, type: isl_dim_in); |
7249 | n_div = isl_aff_dim(aff, type: isl_dim_div); |
7250 | n_mpa_in = isl_multi_pw_aff_dim(multi: mpa, type: isl_dim_in); |
7251 | if (n_in < 0 || n_div < 0 || n_mpa_in < 0) |
7252 | goto error; |
7253 | |
7254 | space = isl_space_domain(space: isl_multi_pw_aff_get_space(multi: mpa)); |
7255 | tmp = isl_aff_copy(aff); |
7256 | tmp = isl_aff_drop_dims(aff: tmp, type: isl_dim_div, first: 0, n: n_div); |
7257 | tmp = isl_aff_drop_dims(aff: tmp, type: isl_dim_in, first: 0, n: n_in); |
7258 | tmp = isl_aff_add_dims(aff: tmp, type: isl_dim_in, n: n_mpa_in); |
7259 | tmp = isl_aff_reset_domain_space(aff: tmp, space); |
7260 | pa = isl_pw_aff_from_aff(el: tmp); |
7261 | |
7262 | for (i = 0; i < n_in; ++i) { |
7263 | isl_pw_aff *pa_i; |
7264 | |
7265 | if (!isl_aff_involves_dims(aff, type: isl_dim_in, first: i, n: 1)) |
7266 | continue; |
7267 | v = isl_aff_get_coefficient_val(aff, type: isl_dim_in, pos: i); |
7268 | pa_i = isl_multi_pw_aff_get_pw_aff(multi: mpa, pos: i); |
7269 | pa_i = isl_pw_aff_scale_val(pw: pa_i, v); |
7270 | pa = isl_pw_aff_add(pwaff1: pa, pwaff2: pa_i); |
7271 | } |
7272 | |
7273 | for (i = 0; i < n_div; ++i) { |
7274 | isl_aff *div; |
7275 | isl_pw_aff *pa_i; |
7276 | |
7277 | if (!isl_aff_involves_dims(aff, type: isl_dim_div, first: i, n: 1)) |
7278 | continue; |
7279 | div = isl_aff_get_div(aff, pos: i); |
7280 | pa_i = isl_multi_pw_aff_apply_aff_aligned( |
7281 | mpa: isl_multi_pw_aff_copy(multi: mpa), aff: div); |
7282 | pa_i = isl_pw_aff_floor(pwaff: pa_i); |
7283 | v = isl_aff_get_coefficient_val(aff, type: isl_dim_div, pos: i); |
7284 | pa_i = isl_pw_aff_scale_val(pw: pa_i, v); |
7285 | pa = isl_pw_aff_add(pwaff1: pa, pwaff2: pa_i); |
7286 | } |
7287 | |
7288 | isl_multi_pw_aff_free(multi: mpa); |
7289 | isl_aff_free(aff); |
7290 | |
7291 | return pa; |
7292 | error: |
7293 | isl_multi_pw_aff_free(multi: mpa); |
7294 | isl_aff_free(aff); |
7295 | return NULL; |
7296 | } |
7297 | |
7298 | /* Apply "aff" to "mpa". The range of "mpa" needs to be compatible |
7299 | * with the domain of "aff". The domain of the result is the same |
7300 | * as that of "mpa". |
7301 | */ |
7302 | __isl_give isl_pw_aff *isl_multi_pw_aff_apply_aff( |
7303 | __isl_take isl_multi_pw_aff *mpa, __isl_take isl_aff *aff) |
7304 | { |
7305 | isl_bool equal_params; |
7306 | |
7307 | if (!aff || !mpa) |
7308 | goto error; |
7309 | equal_params = isl_space_has_equal_params(space1: aff->ls->dim, space2: mpa->space); |
7310 | if (equal_params < 0) |
7311 | goto error; |
7312 | if (equal_params) |
7313 | return isl_multi_pw_aff_apply_aff_aligned(mpa, aff); |
7314 | |
7315 | aff = isl_aff_align_params(aff, model: isl_multi_pw_aff_get_space(multi: mpa)); |
7316 | mpa = isl_multi_pw_aff_align_params(multi: mpa, model: isl_aff_get_space(aff)); |
7317 | |
7318 | return isl_multi_pw_aff_apply_aff_aligned(mpa, aff); |
7319 | error: |
7320 | isl_aff_free(aff); |
7321 | isl_multi_pw_aff_free(multi: mpa); |
7322 | return NULL; |
7323 | } |
7324 | |
7325 | /* Apply "pa" to "mpa". The range of "mpa" needs to be compatible |
7326 | * with the domain of "pa". The domain of the result is the same |
7327 | * as that of "mpa". |
7328 | * "mpa" and "pa" are assumed to have been aligned. |
7329 | * |
7330 | * We consider each piece in turn. Note that the domains of the |
7331 | * pieces are assumed to be disjoint and they remain disjoint |
7332 | * after taking the preimage (over the same function). |
7333 | */ |
7334 | static __isl_give isl_pw_aff *isl_multi_pw_aff_apply_pw_aff_aligned( |
7335 | __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_aff *pa) |
7336 | { |
7337 | isl_space *space; |
7338 | isl_pw_aff *res; |
7339 | int i; |
7340 | |
7341 | if (!mpa || !pa) |
7342 | goto error; |
7343 | |
7344 | space = isl_space_join(left: isl_multi_pw_aff_get_space(multi: mpa), |
7345 | right: isl_pw_aff_get_space(pw: pa)); |
7346 | res = isl_pw_aff_empty(space); |
7347 | |
7348 | for (i = 0; i < pa->n; ++i) { |
7349 | isl_pw_aff *pa_i; |
7350 | isl_set *domain; |
7351 | |
7352 | pa_i = isl_multi_pw_aff_apply_aff_aligned( |
7353 | mpa: isl_multi_pw_aff_copy(multi: mpa), |
7354 | aff: isl_aff_copy(aff: pa->p[i].aff)); |
7355 | domain = isl_set_copy(set: pa->p[i].set); |
7356 | domain = isl_set_preimage_multi_pw_aff(set: domain, |
7357 | mpa: isl_multi_pw_aff_copy(multi: mpa)); |
7358 | pa_i = isl_pw_aff_intersect_domain(pw: pa_i, context: domain); |
7359 | res = isl_pw_aff_add_disjoint(pw1: res, pw2: pa_i); |
7360 | } |
7361 | |
7362 | isl_pw_aff_free(pw: pa); |
7363 | isl_multi_pw_aff_free(multi: mpa); |
7364 | return res; |
7365 | error: |
7366 | isl_pw_aff_free(pw: pa); |
7367 | isl_multi_pw_aff_free(multi: mpa); |
7368 | return NULL; |
7369 | } |
7370 | |
7371 | /* Apply "pa" to "mpa". The range of "mpa" needs to be compatible |
7372 | * with the domain of "pa". The domain of the result is the same |
7373 | * as that of "mpa". |
7374 | */ |
7375 | __isl_give isl_pw_aff *isl_multi_pw_aff_apply_pw_aff( |
7376 | __isl_take isl_multi_pw_aff *mpa, __isl_take isl_pw_aff *pa) |
7377 | { |
7378 | isl_bool equal_params; |
7379 | |
7380 | if (!pa || !mpa) |
7381 | goto error; |
7382 | equal_params = isl_space_has_equal_params(space1: pa->dim, space2: mpa->space); |
7383 | if (equal_params < 0) |
7384 | goto error; |
7385 | if (equal_params) |
7386 | return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa); |
7387 | |
7388 | pa = isl_pw_aff_align_params(pw: pa, model: isl_multi_pw_aff_get_space(multi: mpa)); |
7389 | mpa = isl_multi_pw_aff_align_params(multi: mpa, model: isl_pw_aff_get_space(pw: pa)); |
7390 | |
7391 | return isl_multi_pw_aff_apply_pw_aff_aligned(mpa, pa); |
7392 | error: |
7393 | isl_pw_aff_free(pw: pa); |
7394 | isl_multi_pw_aff_free(multi: mpa); |
7395 | return NULL; |
7396 | } |
7397 | |
7398 | /* Compute the pullback of "pa" by the function represented by "mpa". |
7399 | * In other words, plug in "mpa" in "pa". |
7400 | * |
7401 | * The pullback is computed by applying "pa" to "mpa". |
7402 | */ |
7403 | __isl_give isl_pw_aff *isl_pw_aff_pullback_multi_pw_aff( |
7404 | __isl_take isl_pw_aff *pa, __isl_take isl_multi_pw_aff *mpa) |
7405 | { |
7406 | return isl_multi_pw_aff_apply_pw_aff(mpa, pa); |
7407 | } |
7408 | |
7409 | #undef BASE |
7410 | #define BASE multi_pw_aff |
7411 | |
7412 | #include "isl_multi_pw_aff_pullback_templ.c" |
7413 | |
7414 | /* Align the parameters of "mpa1" and "mpa2", check that the ranges |
7415 | * of "mpa1" and "mpa2" live in the same space, construct map space |
7416 | * between the domain spaces of "mpa1" and "mpa2" and call "order" |
7417 | * with this map space as extract argument. |
7418 | */ |
7419 | static __isl_give isl_map *isl_multi_pw_aff_order_map( |
7420 | __isl_take isl_multi_pw_aff *mpa1, __isl_take isl_multi_pw_aff *mpa2, |
7421 | __isl_give isl_map *(*order)(__isl_keep isl_multi_pw_aff *mpa1, |
7422 | __isl_keep isl_multi_pw_aff *mpa2, __isl_take isl_space *space)) |
7423 | { |
7424 | int match; |
7425 | isl_space *space1, *space2; |
7426 | isl_map *res; |
7427 | |
7428 | mpa1 = isl_multi_pw_aff_align_params(multi: mpa1, |
7429 | model: isl_multi_pw_aff_get_space(multi: mpa2)); |
7430 | mpa2 = isl_multi_pw_aff_align_params(multi: mpa2, |
7431 | model: isl_multi_pw_aff_get_space(multi: mpa1)); |
7432 | if (!mpa1 || !mpa2) |
7433 | goto error; |
7434 | match = isl_space_tuple_is_equal(space1: mpa1->space, type1: isl_dim_out, |
7435 | space2: mpa2->space, type2: isl_dim_out); |
7436 | if (match < 0) |
7437 | goto error; |
7438 | if (!match) |
7439 | isl_die(isl_multi_pw_aff_get_ctx(mpa1), isl_error_invalid, |
7440 | "range spaces don't match" , goto error); |
7441 | space1 = isl_space_domain(space: isl_multi_pw_aff_get_space(multi: mpa1)); |
7442 | space2 = isl_space_domain(space: isl_multi_pw_aff_get_space(multi: mpa2)); |
7443 | space1 = isl_space_map_from_domain_and_range(domain: space1, range: space2); |
7444 | |
7445 | res = order(mpa1, mpa2, space1); |
7446 | isl_multi_pw_aff_free(multi: mpa1); |
7447 | isl_multi_pw_aff_free(multi: mpa2); |
7448 | return res; |
7449 | error: |
7450 | isl_multi_pw_aff_free(multi: mpa1); |
7451 | isl_multi_pw_aff_free(multi: mpa2); |
7452 | return NULL; |
7453 | } |
7454 | |
7455 | /* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" |
7456 | * where the function values are equal. "space" is the space of the result. |
7457 | * The parameters of "mpa1" and "mpa2" are assumed to have been aligned. |
7458 | * |
7459 | * "mpa1" and "mpa2" are equal when each of the pairs of elements |
7460 | * in the sequences are equal. |
7461 | */ |
7462 | static __isl_give isl_map *isl_multi_pw_aff_eq_map_on_space( |
7463 | __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2, |
7464 | __isl_take isl_space *space) |
7465 | { |
7466 | int i; |
7467 | isl_size n; |
7468 | isl_map *res; |
7469 | |
7470 | n = isl_multi_pw_aff_dim(multi: mpa1, type: isl_dim_out); |
7471 | if (n < 0) |
7472 | space = isl_space_free(space); |
7473 | res = isl_map_universe(space); |
7474 | |
7475 | for (i = 0; i < n; ++i) { |
7476 | isl_pw_aff *pa1, *pa2; |
7477 | isl_map *map; |
7478 | |
7479 | pa1 = isl_multi_pw_aff_get_pw_aff(multi: mpa1, pos: i); |
7480 | pa2 = isl_multi_pw_aff_get_pw_aff(multi: mpa2, pos: i); |
7481 | map = isl_pw_aff_eq_map(pa1, pa2); |
7482 | res = isl_map_intersect(map1: res, map2: map); |
7483 | } |
7484 | |
7485 | return res; |
7486 | } |
7487 | |
7488 | /* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" |
7489 | * where the function values are equal. |
7490 | */ |
7491 | __isl_give isl_map *isl_multi_pw_aff_eq_map(__isl_take isl_multi_pw_aff *mpa1, |
7492 | __isl_take isl_multi_pw_aff *mpa2) |
7493 | { |
7494 | return isl_multi_pw_aff_order_map(mpa1, mpa2, |
7495 | order: &isl_multi_pw_aff_eq_map_on_space); |
7496 | } |
7497 | |
7498 | /* Intersect "map" with the result of applying "order" |
7499 | * on two copies of "mpa". |
7500 | */ |
7501 | static __isl_give isl_map *isl_map_order_at_multi_pw_aff( |
7502 | __isl_take isl_map *map, __isl_take isl_multi_pw_aff *mpa, |
7503 | __isl_give isl_map *(*order)(__isl_take isl_multi_pw_aff *mpa1, |
7504 | __isl_take isl_multi_pw_aff *mpa2)) |
7505 | { |
7506 | return isl_map_intersect(map1: map, map2: order(mpa, isl_multi_pw_aff_copy(multi: mpa))); |
7507 | } |
7508 | |
7509 | /* Return the subset of "map" where the domain and the range |
7510 | * have equal "mpa" values. |
7511 | */ |
7512 | __isl_give isl_map *isl_map_eq_at_multi_pw_aff(__isl_take isl_map *map, |
7513 | __isl_take isl_multi_pw_aff *mpa) |
7514 | { |
7515 | return isl_map_order_at_multi_pw_aff(map, mpa, |
7516 | order: &isl_multi_pw_aff_eq_map); |
7517 | } |
7518 | |
7519 | /* Return a map containing pairs of elements in the domains of "mpa1" and "mpa2" |
7520 | * where the function values of "mpa1" lexicographically satisfies |
7521 | * "strict_base"/"base" compared to that of "mpa2". |
7522 | * "space" is the space of the result. |
7523 | * The parameters of "mpa1" and "mpa2" are assumed to have been aligned. |
7524 | * |
7525 | * "mpa1" lexicographically satisfies "strict_base"/"base" compared to "mpa2" |
7526 | * if, for some i, the i-th element of "mpa1" satisfies "strict_base"/"base" |
7527 | * when compared to the i-th element of "mpa2" while all previous elements are |
7528 | * pairwise equal. |
7529 | * In particular, if i corresponds to the final elements |
7530 | * then they need to satisfy "base", while "strict_base" needs to be satisfied |
7531 | * for other values of i. |
7532 | * If "base" is a strict order, then "base" and "strict_base" are the same. |
7533 | */ |
7534 | static __isl_give isl_map *isl_multi_pw_aff_lex_map_on_space( |
7535 | __isl_keep isl_multi_pw_aff *mpa1, __isl_keep isl_multi_pw_aff *mpa2, |
7536 | __isl_give isl_map *(*strict_base)(__isl_take isl_pw_aff *pa1, |
7537 | __isl_take isl_pw_aff *pa2), |
7538 | __isl_give isl_map *(*base)(__isl_take isl_pw_aff *pa1, |
7539 | __isl_take isl_pw_aff *pa2), |
7540 | __isl_take isl_space *space) |
7541 | { |
7542 | int i; |
7543 | isl_size n; |
7544 | isl_map *res, *rest; |
7545 | |
7546 | n = isl_multi_pw_aff_dim(multi: mpa1, type: isl_dim_out); |
7547 | if (n < 0) |
7548 | space = isl_space_free(space); |
7549 | res = isl_map_empty(space: isl_space_copy(space)); |
7550 | rest = isl_map_universe(space); |
7551 | |
7552 | for (i = 0; i < n; ++i) { |
7553 | int last; |
7554 | isl_pw_aff *pa1, *pa2; |
7555 | isl_map *map; |
7556 | |
7557 | last = i == n - 1; |
7558 | |
7559 | pa1 = isl_multi_pw_aff_get_pw_aff(multi: mpa1, pos: i); |
7560 | pa2 = isl_multi_pw_aff_get_pw_aff(multi: mpa2, pos: i); |
7561 | map = last ? base(pa1, pa2) : strict_base(pa1, pa2); |
7562 | map = isl_map_intersect(map1: map, map2: isl_map_copy(map: rest)); |
7563 | res = isl_map_union(map1: res, map2: map); |
7564 | |
7565 | if (last) |
7566 | continue; |
7567 | |
7568 | pa1 = isl_multi_pw_aff_get_pw_aff(multi: mpa1, pos: i); |
7569 | pa2 = isl_multi_pw_aff_get_pw_aff(multi: mpa2, pos: i); |
7570 | map = isl_pw_aff_eq_map(pa1, pa2); |
7571 | rest = isl_map_intersect(map1: rest, map2: map); |
7572 | } |
7573 | |
7574 | isl_map_free(map: rest); |
7575 | return res; |
7576 | } |
7577 | |
7578 | #undef ORDER |
7579 | #define ORDER le |
7580 | #undef STRICT_ORDER |
7581 | #define STRICT_ORDER lt |
7582 | #include "isl_aff_lex_templ.c" |
7583 | |
7584 | #undef ORDER |
7585 | #define ORDER lt |
7586 | #undef STRICT_ORDER |
7587 | #define STRICT_ORDER lt |
7588 | #include "isl_aff_lex_templ.c" |
7589 | |
7590 | #undef ORDER |
7591 | #define ORDER ge |
7592 | #undef STRICT_ORDER |
7593 | #define STRICT_ORDER gt |
7594 | #include "isl_aff_lex_templ.c" |
7595 | |
7596 | #undef ORDER |
7597 | #define ORDER gt |
7598 | #undef STRICT_ORDER |
7599 | #define STRICT_ORDER gt |
7600 | #include "isl_aff_lex_templ.c" |
7601 | |
7602 | /* Compare two isl_affs. |
7603 | * |
7604 | * Return -1 if "aff1" is "smaller" than "aff2", 1 if "aff1" is "greater" |
7605 | * than "aff2" and 0 if they are equal. |
7606 | * |
7607 | * The order is fairly arbitrary. We do consider expressions that only involve |
7608 | * earlier dimensions as "smaller". |
7609 | */ |
7610 | int isl_aff_plain_cmp(__isl_keep isl_aff *aff1, __isl_keep isl_aff *aff2) |
7611 | { |
7612 | int cmp; |
7613 | int last1, last2; |
7614 | |
7615 | if (aff1 == aff2) |
7616 | return 0; |
7617 | |
7618 | if (!aff1) |
7619 | return -1; |
7620 | if (!aff2) |
7621 | return 1; |
7622 | |
7623 | cmp = isl_local_space_cmp(ls1: aff1->ls, ls2: aff2->ls); |
7624 | if (cmp != 0) |
7625 | return cmp; |
7626 | |
7627 | last1 = isl_seq_last_non_zero(p: aff1->v->el + 1, len: aff1->v->size - 1); |
7628 | last2 = isl_seq_last_non_zero(p: aff2->v->el + 1, len: aff1->v->size - 1); |
7629 | if (last1 != last2) |
7630 | return last1 - last2; |
7631 | |
7632 | return isl_seq_cmp(p1: aff1->v->el, p2: aff2->v->el, len: aff1->v->size); |
7633 | } |
7634 | |
7635 | /* Compare two isl_pw_affs. |
7636 | * |
7637 | * Return -1 if "pa1" is "smaller" than "pa2", 1 if "pa1" is "greater" |
7638 | * than "pa2" and 0 if they are equal. |
7639 | * |
7640 | * The order is fairly arbitrary. We do consider expressions that only involve |
7641 | * earlier dimensions as "smaller". |
7642 | */ |
7643 | int isl_pw_aff_plain_cmp(__isl_keep isl_pw_aff *pa1, |
7644 | __isl_keep isl_pw_aff *pa2) |
7645 | { |
7646 | int i; |
7647 | int cmp; |
7648 | |
7649 | if (pa1 == pa2) |
7650 | return 0; |
7651 | |
7652 | if (!pa1) |
7653 | return -1; |
7654 | if (!pa2) |
7655 | return 1; |
7656 | |
7657 | cmp = isl_space_cmp(space1: pa1->dim, space2: pa2->dim); |
7658 | if (cmp != 0) |
7659 | return cmp; |
7660 | |
7661 | if (pa1->n != pa2->n) |
7662 | return pa1->n - pa2->n; |
7663 | |
7664 | for (i = 0; i < pa1->n; ++i) { |
7665 | cmp = isl_set_plain_cmp(set1: pa1->p[i].set, set2: pa2->p[i].set); |
7666 | if (cmp != 0) |
7667 | return cmp; |
7668 | cmp = isl_aff_plain_cmp(aff1: pa1->p[i].aff, aff2: pa2->p[i].aff); |
7669 | if (cmp != 0) |
7670 | return cmp; |
7671 | } |
7672 | |
7673 | return 0; |
7674 | } |
7675 | |
7676 | /* Return a piecewise affine expression that is equal to "v" on "domain". |
7677 | */ |
7678 | __isl_give isl_pw_aff *isl_pw_aff_val_on_domain(__isl_take isl_set *domain, |
7679 | __isl_take isl_val *v) |
7680 | { |
7681 | isl_space *space; |
7682 | isl_local_space *ls; |
7683 | isl_aff *aff; |
7684 | |
7685 | space = isl_set_get_space(set: domain); |
7686 | ls = isl_local_space_from_space(space); |
7687 | aff = isl_aff_val_on_domain(ls, val: v); |
7688 | |
7689 | return isl_pw_aff_alloc(set: domain, el: aff); |
7690 | } |
7691 | |
7692 | /* This function performs the same operation as isl_pw_aff_val_on_domain, |
7693 | * but is considered as a function on an isl_set when exported. |
7694 | */ |
7695 | __isl_give isl_pw_aff *isl_set_pw_aff_on_domain_val(__isl_take isl_set *domain, |
7696 | __isl_take isl_val *v) |
7697 | { |
7698 | return isl_pw_aff_val_on_domain(domain, v); |
7699 | } |
7700 | |
7701 | /* Return a piecewise affine expression that is equal to the parameter |
7702 | * with identifier "id" on "domain". |
7703 | */ |
7704 | __isl_give isl_pw_aff *isl_pw_aff_param_on_domain_id( |
7705 | __isl_take isl_set *domain, __isl_take isl_id *id) |
7706 | { |
7707 | isl_space *space; |
7708 | isl_aff *aff; |
7709 | |
7710 | space = isl_set_get_space(set: domain); |
7711 | space = isl_space_add_param_id(space, id: isl_id_copy(id)); |
7712 | domain = isl_set_align_params(set: domain, model: isl_space_copy(space)); |
7713 | aff = isl_aff_param_on_domain_space_id(space, id); |
7714 | |
7715 | return isl_pw_aff_alloc(set: domain, el: aff); |
7716 | } |
7717 | |
7718 | /* This function performs the same operation as |
7719 | * isl_pw_aff_param_on_domain_id, |
7720 | * but is considered as a function on an isl_set when exported. |
7721 | */ |
7722 | __isl_give isl_pw_aff *isl_set_param_pw_aff_on_domain_id( |
7723 | __isl_take isl_set *domain, __isl_take isl_id *id) |
7724 | { |
7725 | return isl_pw_aff_param_on_domain_id(domain, id); |
7726 | } |
7727 | |
7728 | /* Return a multi affine expression that is equal to "mv" on domain |
7729 | * space "space". |
7730 | */ |
7731 | __isl_give isl_multi_aff *isl_multi_aff_multi_val_on_domain_space( |
7732 | __isl_take isl_space *space, __isl_take isl_multi_val *mv) |
7733 | { |
7734 | int i; |
7735 | isl_size n; |
7736 | isl_space *space2; |
7737 | isl_local_space *ls; |
7738 | isl_multi_aff *ma; |
7739 | |
7740 | n = isl_multi_val_dim(multi: mv, type: isl_dim_set); |
7741 | if (!space || n < 0) |
7742 | goto error; |
7743 | |
7744 | space2 = isl_multi_val_get_space(multi: mv); |
7745 | space2 = isl_space_align_params(space1: space2, space2: isl_space_copy(space)); |
7746 | space = isl_space_align_params(space1: space, space2: isl_space_copy(space: space2)); |
7747 | space = isl_space_map_from_domain_and_range(domain: space, range: space2); |
7748 | ma = isl_multi_aff_alloc(space: isl_space_copy(space)); |
7749 | ls = isl_local_space_from_space(space: isl_space_domain(space)); |
7750 | for (i = 0; i < n; ++i) { |
7751 | isl_val *v; |
7752 | isl_aff *aff; |
7753 | |
7754 | v = isl_multi_val_get_val(multi: mv, pos: i); |
7755 | aff = isl_aff_val_on_domain(ls: isl_local_space_copy(ls), val: v); |
7756 | ma = isl_multi_aff_set_aff(multi: ma, pos: i, el: aff); |
7757 | } |
7758 | isl_local_space_free(ls); |
7759 | |
7760 | isl_multi_val_free(multi: mv); |
7761 | return ma; |
7762 | error: |
7763 | isl_space_free(space); |
7764 | isl_multi_val_free(multi: mv); |
7765 | return NULL; |
7766 | } |
7767 | |
7768 | /* This is an alternative name for the function above. |
7769 | */ |
7770 | __isl_give isl_multi_aff *isl_multi_aff_multi_val_on_space( |
7771 | __isl_take isl_space *space, __isl_take isl_multi_val *mv) |
7772 | { |
7773 | return isl_multi_aff_multi_val_on_domain_space(space, mv); |
7774 | } |
7775 | |
7776 | /* This function performs the same operation as |
7777 | * isl_multi_aff_multi_val_on_domain_space, |
7778 | * but is considered as a function on an isl_space when exported. |
7779 | */ |
7780 | __isl_give isl_multi_aff *isl_space_multi_aff_on_domain_multi_val( |
7781 | __isl_take isl_space *space, __isl_take isl_multi_val *mv) |
7782 | { |
7783 | return isl_multi_aff_multi_val_on_domain_space(space, mv); |
7784 | } |
7785 | |
7786 | /* Return a piecewise multi-affine expression |
7787 | * that is equal to "mv" on "domain". |
7788 | */ |
7789 | __isl_give isl_pw_multi_aff *isl_pw_multi_aff_multi_val_on_domain( |
7790 | __isl_take isl_set *domain, __isl_take isl_multi_val *mv) |
7791 | { |
7792 | isl_space *space; |
7793 | isl_multi_aff *ma; |
7794 | |
7795 | space = isl_set_get_space(set: domain); |
7796 | ma = isl_multi_aff_multi_val_on_space(space, mv); |
7797 | |
7798 | return isl_pw_multi_aff_alloc(set: domain, el: ma); |
7799 | } |
7800 | |
7801 | /* This function performs the same operation as |
7802 | * isl_pw_multi_aff_multi_val_on_domain, |
7803 | * but is considered as a function on an isl_set when exported. |
7804 | */ |
7805 | __isl_give isl_pw_multi_aff *isl_set_pw_multi_aff_on_domain_multi_val( |
7806 | __isl_take isl_set *domain, __isl_take isl_multi_val *mv) |
7807 | { |
7808 | return isl_pw_multi_aff_multi_val_on_domain(domain, mv); |
7809 | } |
7810 | |
7811 | /* Internal data structure for isl_union_pw_multi_aff_multi_val_on_domain. |
7812 | * mv is the value that should be attained on each domain set |
7813 | * res collects the results |
7814 | */ |
7815 | struct isl_union_pw_multi_aff_multi_val_on_domain_data { |
7816 | isl_multi_val *mv; |
7817 | isl_union_pw_multi_aff *res; |
7818 | }; |
7819 | |
7820 | /* Create an isl_pw_multi_aff equal to data->mv on "domain" |
7821 | * and add it to data->res. |
7822 | */ |
7823 | static isl_stat pw_multi_aff_multi_val_on_domain(__isl_take isl_set *domain, |
7824 | void *user) |
7825 | { |
7826 | struct isl_union_pw_multi_aff_multi_val_on_domain_data *data = user; |
7827 | isl_pw_multi_aff *pma; |
7828 | isl_multi_val *mv; |
7829 | |
7830 | mv = isl_multi_val_copy(multi: data->mv); |
7831 | pma = isl_pw_multi_aff_multi_val_on_domain(domain, mv); |
7832 | data->res = isl_union_pw_multi_aff_add_pw_multi_aff(u: data->res, part: pma); |
7833 | |
7834 | return data->res ? isl_stat_ok : isl_stat_error; |
7835 | } |
7836 | |
7837 | /* Return a union piecewise multi-affine expression |
7838 | * that is equal to "mv" on "domain". |
7839 | */ |
7840 | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_multi_val_on_domain( |
7841 | __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv) |
7842 | { |
7843 | struct isl_union_pw_multi_aff_multi_val_on_domain_data data; |
7844 | isl_space *space; |
7845 | |
7846 | space = isl_union_set_get_space(uset: domain); |
7847 | data.res = isl_union_pw_multi_aff_empty(space); |
7848 | data.mv = mv; |
7849 | if (isl_union_set_foreach_set(uset: domain, |
7850 | fn: &pw_multi_aff_multi_val_on_domain, user: &data) < 0) |
7851 | data.res = isl_union_pw_multi_aff_free(u: data.res); |
7852 | isl_union_set_free(uset: domain); |
7853 | isl_multi_val_free(multi: mv); |
7854 | return data.res; |
7855 | } |
7856 | |
7857 | /* Compute the pullback of data->pma by the function represented by "pma2", |
7858 | * provided the spaces match, and add the results to data->res. |
7859 | */ |
7860 | static isl_stat pullback_entry(__isl_take isl_pw_multi_aff *pma2, void *user) |
7861 | { |
7862 | struct isl_union_pw_multi_aff_bin_data *data = user; |
7863 | |
7864 | if (!isl_space_tuple_is_equal(space1: data->pma->dim, type1: isl_dim_in, |
7865 | space2: pma2->dim, type2: isl_dim_out)) { |
7866 | isl_pw_multi_aff_free(pw: pma2); |
7867 | return isl_stat_ok; |
7868 | } |
7869 | |
7870 | pma2 = isl_pw_multi_aff_pullback_pw_multi_aff( |
7871 | pw: isl_pw_multi_aff_copy(pw: data->pma), pma: pma2); |
7872 | |
7873 | data->res = isl_union_pw_multi_aff_add_pw_multi_aff(u: data->res, part: pma2); |
7874 | if (!data->res) |
7875 | return isl_stat_error; |
7876 | |
7877 | return isl_stat_ok; |
7878 | } |
7879 | |
7880 | /* Compute the pullback of "upma1" by the function represented by "upma2". |
7881 | */ |
7882 | __isl_give isl_union_pw_multi_aff * |
7883 | isl_union_pw_multi_aff_pullback_union_pw_multi_aff( |
7884 | __isl_take isl_union_pw_multi_aff *upma1, |
7885 | __isl_take isl_union_pw_multi_aff *upma2) |
7886 | { |
7887 | return bin_op(upma1, upma2, fn: &pullback_entry); |
7888 | } |
7889 | |
7890 | /* Apply "upma2" to "upma1". |
7891 | * |
7892 | * That is, compute the pullback of "upma2" by "upma1". |
7893 | */ |
7894 | __isl_give isl_union_pw_multi_aff * |
7895 | isl_union_pw_multi_aff_apply_union_pw_multi_aff( |
7896 | __isl_take isl_union_pw_multi_aff *upma1, |
7897 | __isl_take isl_union_pw_multi_aff *upma2) |
7898 | { |
7899 | return isl_union_pw_multi_aff_pullback_union_pw_multi_aff(upma1: upma2, upma2: upma1); |
7900 | } |
7901 | |
7902 | #undef TYPE |
7903 | #define TYPE isl_pw_multi_aff |
7904 | static |
7905 | #include "isl_copy_tuple_id_templ.c" |
7906 | |
7907 | /* Given a function "pma1" of the form A[B -> C] -> D and |
7908 | * a function "pma2" of the form E -> B, |
7909 | * replace the domain of the wrapped relation inside the domain of "pma1" |
7910 | * by the preimage with respect to "pma2". |
7911 | * In other words, plug in "pma2" in this nested domain. |
7912 | * The result is of the form A[E -> C] -> D. |
7913 | * |
7914 | * In particular, extend E -> B to A[E -> C] -> A[B -> C] and |
7915 | * plug that into "pma1". |
7916 | */ |
7917 | __isl_give isl_pw_multi_aff * |
7918 | isl_pw_multi_aff_preimage_domain_wrapped_domain_pw_multi_aff( |
7919 | __isl_take isl_pw_multi_aff *pma1, __isl_take isl_pw_multi_aff *pma2) |
7920 | { |
7921 | isl_space *pma1_space, *pma2_space; |
7922 | isl_space *space; |
7923 | isl_pw_multi_aff *id; |
7924 | |
7925 | pma1_space = isl_pw_multi_aff_peek_space(pw: pma1); |
7926 | pma2_space = isl_pw_multi_aff_peek_space(pw: pma2); |
7927 | |
7928 | if (isl_space_check_domain_is_wrapping(space: pma1_space) < 0) |
7929 | goto error; |
7930 | if (isl_space_check_wrapped_tuple_is_equal(space1: pma1_space, |
7931 | outer: isl_dim_in, inner: isl_dim_in, space2: pma2_space, type2: isl_dim_out) < 0) |
7932 | goto error; |
7933 | |
7934 | space = isl_space_domain(space: isl_space_copy(space: pma1_space)); |
7935 | space = isl_space_range(space: isl_space_unwrap(space)); |
7936 | id = isl_pw_multi_aff_identity_on_domain_space(space); |
7937 | pma2 = isl_pw_multi_aff_product(pma1: pma2, pma2: id); |
7938 | |
7939 | pma2 = isl_pw_multi_aff_copy_tuple_id(dst: pma2, dst_type: isl_dim_in, |
7940 | src: pma1_space, src_type: isl_dim_in); |
7941 | pma2 = isl_pw_multi_aff_copy_tuple_id(dst: pma2, dst_type: isl_dim_out, |
7942 | src: pma1_space, src_type: isl_dim_in); |
7943 | |
7944 | return isl_pw_multi_aff_pullback_pw_multi_aff(pw: pma1, pma: pma2); |
7945 | error: |
7946 | isl_pw_multi_aff_free(pw: pma1); |
7947 | isl_pw_multi_aff_free(pw: pma2); |
7948 | return NULL; |
7949 | } |
7950 | |
7951 | /* If data->pma and "pma2" are such that |
7952 | * data->pma is of the form A[B -> C] -> D and |
7953 | * "pma2" is of the form E -> B, |
7954 | * then replace the domain of the wrapped relation |
7955 | * inside the domain of data->pma by the preimage with respect to "pma2" and |
7956 | * add the result to data->res. |
7957 | */ |
7958 | static isl_stat preimage_domain_wrapped_domain_entry( |
7959 | __isl_take isl_pw_multi_aff *pma2, void *user) |
7960 | { |
7961 | struct isl_union_pw_multi_aff_bin_data *data = user; |
7962 | isl_space *pma1_space, *pma2_space; |
7963 | isl_bool match; |
7964 | |
7965 | pma1_space = isl_pw_multi_aff_peek_space(pw: data->pma); |
7966 | pma2_space = isl_pw_multi_aff_peek_space(pw: pma2); |
7967 | |
7968 | match = isl_space_domain_is_wrapping(space: pma1_space); |
7969 | if (match >= 0 && match) |
7970 | match = isl_space_wrapped_tuple_is_equal(space1: pma1_space, outer: isl_dim_in, |
7971 | inner: isl_dim_in, space2: pma2_space, type2: isl_dim_out); |
7972 | if (match < 0 || !match) { |
7973 | isl_pw_multi_aff_free(pw: pma2); |
7974 | return match < 0 ? isl_stat_error : isl_stat_ok; |
7975 | } |
7976 | |
7977 | pma2 = isl_pw_multi_aff_preimage_domain_wrapped_domain_pw_multi_aff( |
7978 | pma1: isl_pw_multi_aff_copy(pw: data->pma), pma2); |
7979 | |
7980 | data->res = isl_union_pw_multi_aff_add_pw_multi_aff(u: data->res, part: pma2); |
7981 | |
7982 | return isl_stat_non_null(obj: data->res); |
7983 | } |
7984 | |
7985 | /* For each pair of functions A[B -> C] -> D in "upma1" and |
7986 | * E -> B in "upma2", |
7987 | * replace the domain of the wrapped relation inside the domain of the first |
7988 | * by the preimage with respect to the second and collect the results. |
7989 | * In other words, plug in the second function in this nested domain. |
7990 | * The results are of the form A[E -> C] -> D. |
7991 | */ |
7992 | __isl_give isl_union_pw_multi_aff * |
7993 | isl_union_pw_multi_aff_preimage_domain_wrapped_domain_union_pw_multi_aff( |
7994 | __isl_take isl_union_pw_multi_aff *upma1, |
7995 | __isl_take isl_union_pw_multi_aff *upma2) |
7996 | { |
7997 | return bin_op(upma1, upma2, fn: &preimage_domain_wrapped_domain_entry); |
7998 | } |
7999 | |
8000 | /* Check that the domain space of "upa" matches "space". |
8001 | * |
8002 | * This function is called from isl_multi_union_pw_aff_set_union_pw_aff and |
8003 | * can in principle never fail since the space "space" is that |
8004 | * of the isl_multi_union_pw_aff and is a set space such that |
8005 | * there is no domain space to match. |
8006 | * |
8007 | * We check the parameters and double-check that "space" is |
8008 | * indeed that of a set. |
8009 | */ |
8010 | static isl_stat isl_union_pw_aff_check_match_domain_space( |
8011 | __isl_keep isl_union_pw_aff *upa, __isl_keep isl_space *space) |
8012 | { |
8013 | isl_space *upa_space; |
8014 | isl_bool match; |
8015 | |
8016 | if (!upa || !space) |
8017 | return isl_stat_error; |
8018 | |
8019 | match = isl_space_is_set(space); |
8020 | if (match < 0) |
8021 | return isl_stat_error; |
8022 | if (!match) |
8023 | isl_die(isl_space_get_ctx(space), isl_error_invalid, |
8024 | "expecting set space" , return isl_stat_error); |
8025 | |
8026 | upa_space = isl_union_pw_aff_get_space(u: upa); |
8027 | match = isl_space_has_equal_params(space1: space, space2: upa_space); |
8028 | if (match < 0) |
8029 | goto error; |
8030 | if (!match) |
8031 | isl_die(isl_space_get_ctx(space), isl_error_invalid, |
8032 | "parameters don't match" , goto error); |
8033 | |
8034 | isl_space_free(space: upa_space); |
8035 | return isl_stat_ok; |
8036 | error: |
8037 | isl_space_free(space: upa_space); |
8038 | return isl_stat_error; |
8039 | } |
8040 | |
8041 | /* Do the parameters of "upa" match those of "space"? |
8042 | */ |
8043 | static isl_bool isl_union_pw_aff_matching_params( |
8044 | __isl_keep isl_union_pw_aff *upa, __isl_keep isl_space *space) |
8045 | { |
8046 | isl_space *upa_space; |
8047 | isl_bool match; |
8048 | |
8049 | if (!upa || !space) |
8050 | return isl_bool_error; |
8051 | |
8052 | upa_space = isl_union_pw_aff_get_space(u: upa); |
8053 | |
8054 | match = isl_space_has_equal_params(space1: space, space2: upa_space); |
8055 | |
8056 | isl_space_free(space: upa_space); |
8057 | return match; |
8058 | } |
8059 | |
8060 | /* Internal data structure for isl_union_pw_aff_reset_domain_space. |
8061 | * space represents the new parameters. |
8062 | * res collects the results. |
8063 | */ |
8064 | struct isl_union_pw_aff_reset_params_data { |
8065 | isl_space *space; |
8066 | isl_union_pw_aff *res; |
8067 | }; |
8068 | |
8069 | /* Replace the parameters of "pa" by data->space and |
8070 | * add the result to data->res. |
8071 | */ |
8072 | static isl_stat reset_params(__isl_take isl_pw_aff *pa, void *user) |
8073 | { |
8074 | struct isl_union_pw_aff_reset_params_data *data = user; |
8075 | isl_space *space; |
8076 | |
8077 | space = isl_pw_aff_get_space(pw: pa); |
8078 | space = isl_space_replace_params(dst: space, src: data->space); |
8079 | pa = isl_pw_aff_reset_space(pw: pa, space); |
8080 | data->res = isl_union_pw_aff_add_pw_aff(u: data->res, part: pa); |
8081 | |
8082 | return data->res ? isl_stat_ok : isl_stat_error; |
8083 | } |
8084 | |
8085 | /* Replace the domain space of "upa" by "space". |
8086 | * Since a union expression does not have a (single) domain space, |
8087 | * "space" is necessarily a parameter space. |
8088 | * |
8089 | * Since the order and the names of the parameters determine |
8090 | * the hash value, we need to create a new hash table. |
8091 | */ |
8092 | static __isl_give isl_union_pw_aff *isl_union_pw_aff_reset_domain_space( |
8093 | __isl_take isl_union_pw_aff *upa, __isl_take isl_space *space) |
8094 | { |
8095 | struct isl_union_pw_aff_reset_params_data data = { space }; |
8096 | isl_bool match; |
8097 | |
8098 | match = isl_union_pw_aff_matching_params(upa, space); |
8099 | if (match < 0) |
8100 | upa = isl_union_pw_aff_free(u: upa); |
8101 | else if (match) { |
8102 | isl_space_free(space); |
8103 | return upa; |
8104 | } |
8105 | |
8106 | data.res = isl_union_pw_aff_empty(space: isl_space_copy(space)); |
8107 | if (isl_union_pw_aff_foreach_pw_aff(u: upa, fn: &reset_params, user: &data) < 0) |
8108 | data.res = isl_union_pw_aff_free(u: data.res); |
8109 | |
8110 | isl_union_pw_aff_free(u: upa); |
8111 | isl_space_free(space); |
8112 | return data.res; |
8113 | } |
8114 | |
8115 | /* Return the floor of "pa". |
8116 | */ |
8117 | static __isl_give isl_pw_aff *floor_entry(__isl_take isl_pw_aff *pa, void *user) |
8118 | { |
8119 | return isl_pw_aff_floor(pwaff: pa); |
8120 | } |
8121 | |
8122 | /* Given f, return floor(f). |
8123 | */ |
8124 | __isl_give isl_union_pw_aff *isl_union_pw_aff_floor( |
8125 | __isl_take isl_union_pw_aff *upa) |
8126 | { |
8127 | return isl_union_pw_aff_transform_inplace(u: upa, fn: &floor_entry, NULL); |
8128 | } |
8129 | |
8130 | /* Compute |
8131 | * |
8132 | * upa mod m = upa - m * floor(upa/m) |
8133 | * |
8134 | * with m an integer value. |
8135 | */ |
8136 | __isl_give isl_union_pw_aff *isl_union_pw_aff_mod_val( |
8137 | __isl_take isl_union_pw_aff *upa, __isl_take isl_val *m) |
8138 | { |
8139 | isl_union_pw_aff *res; |
8140 | |
8141 | if (!upa || !m) |
8142 | goto error; |
8143 | |
8144 | if (!isl_val_is_int(v: m)) |
8145 | isl_die(isl_val_get_ctx(m), isl_error_invalid, |
8146 | "expecting integer modulo" , goto error); |
8147 | if (!isl_val_is_pos(v: m)) |
8148 | isl_die(isl_val_get_ctx(m), isl_error_invalid, |
8149 | "expecting positive modulo" , goto error); |
8150 | |
8151 | res = isl_union_pw_aff_copy(u: upa); |
8152 | upa = isl_union_pw_aff_scale_down_val(u: upa, v: isl_val_copy(v: m)); |
8153 | upa = isl_union_pw_aff_floor(upa); |
8154 | upa = isl_union_pw_aff_scale_val(u: upa, v: m); |
8155 | res = isl_union_pw_aff_sub(u1: res, u2: upa); |
8156 | |
8157 | return res; |
8158 | error: |
8159 | isl_val_free(v: m); |
8160 | isl_union_pw_aff_free(u: upa); |
8161 | return NULL; |
8162 | } |
8163 | |
8164 | /* Internal data structure for isl_union_pw_multi_aff_get_union_pw_aff. |
8165 | * pos is the output position that needs to be extracted. |
8166 | * res collects the results. |
8167 | */ |
8168 | struct isl_union_pw_multi_aff_get_union_pw_aff_data { |
8169 | int pos; |
8170 | isl_union_pw_aff *res; |
8171 | }; |
8172 | |
8173 | /* Extract an isl_pw_aff corresponding to output dimension "pos" of "pma" |
8174 | * (assuming it has such a dimension) and add it to data->res. |
8175 | */ |
8176 | static isl_stat get_union_pw_aff(__isl_take isl_pw_multi_aff *pma, void *user) |
8177 | { |
8178 | struct isl_union_pw_multi_aff_get_union_pw_aff_data *data = user; |
8179 | isl_size n_out; |
8180 | isl_pw_aff *pa; |
8181 | |
8182 | n_out = isl_pw_multi_aff_dim(pw: pma, type: isl_dim_out); |
8183 | if (n_out < 0) |
8184 | return isl_stat_error; |
8185 | if (data->pos >= n_out) { |
8186 | isl_pw_multi_aff_free(pw: pma); |
8187 | return isl_stat_ok; |
8188 | } |
8189 | |
8190 | pa = isl_pw_multi_aff_get_pw_aff(pma, pos: data->pos); |
8191 | isl_pw_multi_aff_free(pw: pma); |
8192 | |
8193 | data->res = isl_union_pw_aff_add_pw_aff(u: data->res, part: pa); |
8194 | |
8195 | return data->res ? isl_stat_ok : isl_stat_error; |
8196 | } |
8197 | |
8198 | /* Extract an isl_union_pw_aff corresponding to |
8199 | * output dimension "pos" of "upma". |
8200 | */ |
8201 | __isl_give isl_union_pw_aff *isl_union_pw_multi_aff_get_union_pw_aff( |
8202 | __isl_keep isl_union_pw_multi_aff *upma, int pos) |
8203 | { |
8204 | struct isl_union_pw_multi_aff_get_union_pw_aff_data data; |
8205 | isl_space *space; |
8206 | |
8207 | if (!upma) |
8208 | return NULL; |
8209 | |
8210 | if (pos < 0) |
8211 | isl_die(isl_union_pw_multi_aff_get_ctx(upma), isl_error_invalid, |
8212 | "cannot extract at negative position" , return NULL); |
8213 | |
8214 | space = isl_union_pw_multi_aff_get_space(u: upma); |
8215 | data.res = isl_union_pw_aff_empty(space); |
8216 | data.pos = pos; |
8217 | if (isl_union_pw_multi_aff_foreach_pw_multi_aff(u: upma, |
8218 | fn: &get_union_pw_aff, user: &data) < 0) |
8219 | data.res = isl_union_pw_aff_free(u: data.res); |
8220 | |
8221 | return data.res; |
8222 | } |
8223 | |
8224 | /* Return a union piecewise affine expression |
8225 | * that is equal to "aff" on "domain". |
8226 | */ |
8227 | __isl_give isl_union_pw_aff *isl_union_pw_aff_aff_on_domain( |
8228 | __isl_take isl_union_set *domain, __isl_take isl_aff *aff) |
8229 | { |
8230 | isl_pw_aff *pa; |
8231 | |
8232 | pa = isl_pw_aff_from_aff(el: aff); |
8233 | return isl_union_pw_aff_pw_aff_on_domain(domain, pa); |
8234 | } |
8235 | |
8236 | /* Return a union piecewise affine expression |
8237 | * that is equal to the parameter identified by "id" on "domain". |
8238 | * |
8239 | * Make sure the parameter appears in the space passed to |
8240 | * isl_aff_param_on_domain_space_id. |
8241 | */ |
8242 | __isl_give isl_union_pw_aff *isl_union_pw_aff_param_on_domain_id( |
8243 | __isl_take isl_union_set *domain, __isl_take isl_id *id) |
8244 | { |
8245 | isl_space *space; |
8246 | isl_aff *aff; |
8247 | |
8248 | space = isl_union_set_get_space(uset: domain); |
8249 | space = isl_space_add_param_id(space, id: isl_id_copy(id)); |
8250 | aff = isl_aff_param_on_domain_space_id(space, id); |
8251 | return isl_union_pw_aff_aff_on_domain(domain, aff); |
8252 | } |
8253 | |
8254 | /* Internal data structure for isl_union_pw_aff_pw_aff_on_domain. |
8255 | * "pa" is the piecewise symbolic value that the resulting isl_union_pw_aff |
8256 | * needs to attain. |
8257 | * "res" collects the results. |
8258 | */ |
8259 | struct isl_union_pw_aff_pw_aff_on_domain_data { |
8260 | isl_pw_aff *pa; |
8261 | isl_union_pw_aff *res; |
8262 | }; |
8263 | |
8264 | /* Construct a piecewise affine expression that is equal to data->pa |
8265 | * on "domain" and add the result to data->res. |
8266 | */ |
8267 | static isl_stat pw_aff_on_domain(__isl_take isl_set *domain, void *user) |
8268 | { |
8269 | struct isl_union_pw_aff_pw_aff_on_domain_data *data = user; |
8270 | isl_pw_aff *pa; |
8271 | isl_size dim; |
8272 | |
8273 | pa = isl_pw_aff_copy(pw: data->pa); |
8274 | dim = isl_set_dim(set: domain, type: isl_dim_set); |
8275 | if (dim < 0) |
8276 | pa = isl_pw_aff_free(pw: pa); |
8277 | pa = isl_pw_aff_from_range(obj: pa); |
8278 | pa = isl_pw_aff_add_dims(pw: pa, type: isl_dim_in, n: dim); |
8279 | pa = isl_pw_aff_reset_domain_space(pw: pa, domain: isl_set_get_space(set: domain)); |
8280 | pa = isl_pw_aff_intersect_domain(pw: pa, context: domain); |
8281 | data->res = isl_union_pw_aff_add_pw_aff(u: data->res, part: pa); |
8282 | |
8283 | return data->res ? isl_stat_ok : isl_stat_error; |
8284 | } |
8285 | |
8286 | /* Return a union piecewise affine expression |
8287 | * that is equal to "pa" on "domain", assuming "domain" and "pa" |
8288 | * have been aligned. |
8289 | * |
8290 | * Construct an isl_pw_aff on each of the sets in "domain" and |
8291 | * collect the results. |
8292 | */ |
8293 | static __isl_give isl_union_pw_aff *isl_union_pw_aff_pw_aff_on_domain_aligned( |
8294 | __isl_take isl_union_set *domain, __isl_take isl_pw_aff *pa) |
8295 | { |
8296 | struct isl_union_pw_aff_pw_aff_on_domain_data data; |
8297 | isl_space *space; |
8298 | |
8299 | space = isl_union_set_get_space(uset: domain); |
8300 | data.res = isl_union_pw_aff_empty(space); |
8301 | data.pa = pa; |
8302 | if (isl_union_set_foreach_set(uset: domain, fn: &pw_aff_on_domain, user: &data) < 0) |
8303 | data.res = isl_union_pw_aff_free(u: data.res); |
8304 | isl_union_set_free(uset: domain); |
8305 | isl_pw_aff_free(pw: pa); |
8306 | return data.res; |
8307 | } |
8308 | |
8309 | /* Return a union piecewise affine expression |
8310 | * that is equal to "pa" on "domain". |
8311 | * |
8312 | * Check that "pa" is a parametric expression, |
8313 | * align the parameters if needed and call |
8314 | * isl_union_pw_aff_pw_aff_on_domain_aligned. |
8315 | */ |
8316 | __isl_give isl_union_pw_aff *isl_union_pw_aff_pw_aff_on_domain( |
8317 | __isl_take isl_union_set *domain, __isl_take isl_pw_aff *pa) |
8318 | { |
8319 | isl_bool is_set; |
8320 | isl_bool equal_params; |
8321 | isl_space *domain_space, *pa_space; |
8322 | |
8323 | pa_space = isl_pw_aff_peek_space(pw: pa); |
8324 | is_set = isl_space_is_set(space: pa_space); |
8325 | if (is_set < 0) |
8326 | goto error; |
8327 | if (!is_set) |
8328 | isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, |
8329 | "expecting parametric expression" , goto error); |
8330 | |
8331 | domain_space = isl_union_set_get_space(uset: domain); |
8332 | pa_space = isl_pw_aff_get_space(pw: pa); |
8333 | equal_params = isl_space_has_equal_params(space1: domain_space, space2: pa_space); |
8334 | if (equal_params >= 0 && !equal_params) { |
8335 | isl_space *space; |
8336 | |
8337 | space = isl_space_align_params(space1: domain_space, space2: pa_space); |
8338 | pa = isl_pw_aff_align_params(pw: pa, model: isl_space_copy(space)); |
8339 | domain = isl_union_set_align_params(uset: domain, model: space); |
8340 | } else { |
8341 | isl_space_free(space: domain_space); |
8342 | isl_space_free(space: pa_space); |
8343 | } |
8344 | |
8345 | if (equal_params < 0) |
8346 | goto error; |
8347 | return isl_union_pw_aff_pw_aff_on_domain_aligned(domain, pa); |
8348 | error: |
8349 | isl_union_set_free(uset: domain); |
8350 | isl_pw_aff_free(pw: pa); |
8351 | return NULL; |
8352 | } |
8353 | |
8354 | /* Internal data structure for isl_union_pw_aff_val_on_domain. |
8355 | * "v" is the value that the resulting isl_union_pw_aff needs to attain. |
8356 | * "res" collects the results. |
8357 | */ |
8358 | struct isl_union_pw_aff_val_on_domain_data { |
8359 | isl_val *v; |
8360 | isl_union_pw_aff *res; |
8361 | }; |
8362 | |
8363 | /* Construct a piecewise affine expression that is equal to data->v |
8364 | * on "domain" and add the result to data->res. |
8365 | */ |
8366 | static isl_stat pw_aff_val_on_domain(__isl_take isl_set *domain, void *user) |
8367 | { |
8368 | struct isl_union_pw_aff_val_on_domain_data *data = user; |
8369 | isl_pw_aff *pa; |
8370 | isl_val *v; |
8371 | |
8372 | v = isl_val_copy(v: data->v); |
8373 | pa = isl_pw_aff_val_on_domain(domain, v); |
8374 | data->res = isl_union_pw_aff_add_pw_aff(u: data->res, part: pa); |
8375 | |
8376 | return data->res ? isl_stat_ok : isl_stat_error; |
8377 | } |
8378 | |
8379 | /* Return a union piecewise affine expression |
8380 | * that is equal to "v" on "domain". |
8381 | * |
8382 | * Construct an isl_pw_aff on each of the sets in "domain" and |
8383 | * collect the results. |
8384 | */ |
8385 | __isl_give isl_union_pw_aff *isl_union_pw_aff_val_on_domain( |
8386 | __isl_take isl_union_set *domain, __isl_take isl_val *v) |
8387 | { |
8388 | struct isl_union_pw_aff_val_on_domain_data data; |
8389 | isl_space *space; |
8390 | |
8391 | space = isl_union_set_get_space(uset: domain); |
8392 | data.res = isl_union_pw_aff_empty(space); |
8393 | data.v = v; |
8394 | if (isl_union_set_foreach_set(uset: domain, fn: &pw_aff_val_on_domain, user: &data) < 0) |
8395 | data.res = isl_union_pw_aff_free(u: data.res); |
8396 | isl_union_set_free(uset: domain); |
8397 | isl_val_free(v); |
8398 | return data.res; |
8399 | } |
8400 | |
8401 | /* Construct a piecewise multi affine expression |
8402 | * that is equal to "pa" and add it to upma. |
8403 | */ |
8404 | static isl_stat pw_multi_aff_from_pw_aff_entry(__isl_take isl_pw_aff *pa, |
8405 | void *user) |
8406 | { |
8407 | isl_union_pw_multi_aff **upma = user; |
8408 | isl_pw_multi_aff *pma; |
8409 | |
8410 | pma = isl_pw_multi_aff_from_pw_aff(pa); |
8411 | *upma = isl_union_pw_multi_aff_add_pw_multi_aff(u: *upma, part: pma); |
8412 | |
8413 | return *upma ? isl_stat_ok : isl_stat_error; |
8414 | } |
8415 | |
8416 | /* Construct and return a union piecewise multi affine expression |
8417 | * that is equal to the given union piecewise affine expression. |
8418 | */ |
8419 | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_from_union_pw_aff( |
8420 | __isl_take isl_union_pw_aff *upa) |
8421 | { |
8422 | isl_space *space; |
8423 | isl_union_pw_multi_aff *upma; |
8424 | |
8425 | if (!upa) |
8426 | return NULL; |
8427 | |
8428 | space = isl_union_pw_aff_get_space(u: upa); |
8429 | upma = isl_union_pw_multi_aff_empty(space); |
8430 | |
8431 | if (isl_union_pw_aff_foreach_pw_aff(u: upa, |
8432 | fn: &pw_multi_aff_from_pw_aff_entry, user: &upma) < 0) |
8433 | upma = isl_union_pw_multi_aff_free(u: upma); |
8434 | |
8435 | isl_union_pw_aff_free(u: upa); |
8436 | return upma; |
8437 | } |
8438 | |
8439 | /* Compute the set of elements in the domain of "pa" where it is zero and |
8440 | * add this set to "uset". |
8441 | */ |
8442 | static isl_stat zero_union_set(__isl_take isl_pw_aff *pa, void *user) |
8443 | { |
8444 | isl_union_set **uset = (isl_union_set **)user; |
8445 | |
8446 | *uset = isl_union_set_add_set(uset: *uset, set: isl_pw_aff_zero_set(pwaff: pa)); |
8447 | |
8448 | return *uset ? isl_stat_ok : isl_stat_error; |
8449 | } |
8450 | |
8451 | /* Return a union set containing those elements in the domain |
8452 | * of "upa" where it is zero. |
8453 | */ |
8454 | __isl_give isl_union_set *isl_union_pw_aff_zero_union_set( |
8455 | __isl_take isl_union_pw_aff *upa) |
8456 | { |
8457 | isl_union_set *zero; |
8458 | |
8459 | zero = isl_union_set_empty(space: isl_union_pw_aff_get_space(u: upa)); |
8460 | if (isl_union_pw_aff_foreach_pw_aff(u: upa, fn: &zero_union_set, user: &zero) < 0) |
8461 | zero = isl_union_set_free(uset: zero); |
8462 | |
8463 | isl_union_pw_aff_free(u: upa); |
8464 | return zero; |
8465 | } |
8466 | |
8467 | /* Internal data structure for isl_union_pw_aff_bind_id, |
8468 | * storing the parameter that needs to be bound and |
8469 | * the accumulated results. |
8470 | */ |
8471 | struct isl_bind_id_data { |
8472 | isl_id *id; |
8473 | isl_union_set *bound; |
8474 | }; |
8475 | |
8476 | /* Bind the piecewise affine function "pa" to the parameter data->id, |
8477 | * adding the resulting elements in the domain where the expression |
8478 | * is equal to the parameter to data->bound. |
8479 | */ |
8480 | static isl_stat bind_id(__isl_take isl_pw_aff *pa, void *user) |
8481 | { |
8482 | struct isl_bind_id_data *data = user; |
8483 | isl_set *bound; |
8484 | |
8485 | bound = isl_pw_aff_bind_id(pa, id: isl_id_copy(id: data->id)); |
8486 | data->bound = isl_union_set_add_set(uset: data->bound, set: bound); |
8487 | |
8488 | return data->bound ? isl_stat_ok : isl_stat_error; |
8489 | } |
8490 | |
8491 | /* Bind the union piecewise affine function "upa" to the parameter "id", |
8492 | * returning the elements in the domain where the expression |
8493 | * is equal to the parameter. |
8494 | */ |
8495 | __isl_give isl_union_set *isl_union_pw_aff_bind_id( |
8496 | __isl_take isl_union_pw_aff *upa, __isl_take isl_id *id) |
8497 | { |
8498 | struct isl_bind_id_data data = { id }; |
8499 | |
8500 | data.bound = isl_union_set_empty(space: isl_union_pw_aff_get_space(u: upa)); |
8501 | if (isl_union_pw_aff_foreach_pw_aff(u: upa, fn: &bind_id, user: &data) < 0) |
8502 | data.bound = isl_union_set_free(uset: data.bound); |
8503 | |
8504 | isl_union_pw_aff_free(u: upa); |
8505 | isl_id_free(id); |
8506 | return data.bound; |
8507 | } |
8508 | |
8509 | /* Internal data structure for isl_union_pw_aff_pullback_union_pw_multi_aff. |
8510 | * upma is the function that is plugged in. |
8511 | * pa is the current part of the function in which upma is plugged in. |
8512 | * res collects the results. |
8513 | */ |
8514 | struct isl_union_pw_aff_pullback_upma_data { |
8515 | isl_union_pw_multi_aff *upma; |
8516 | isl_pw_aff *pa; |
8517 | isl_union_pw_aff *res; |
8518 | }; |
8519 | |
8520 | /* Check if "pma" can be plugged into data->pa. |
8521 | * If so, perform the pullback and add the result to data->res. |
8522 | */ |
8523 | static isl_stat pa_pb_pma(__isl_take isl_pw_multi_aff *pma, void *user) |
8524 | { |
8525 | struct isl_union_pw_aff_pullback_upma_data *data = user; |
8526 | isl_pw_aff *pa; |
8527 | |
8528 | if (!isl_space_tuple_is_equal(space1: data->pa->dim, type1: isl_dim_in, |
8529 | space2: pma->dim, type2: isl_dim_out)) { |
8530 | isl_pw_multi_aff_free(pw: pma); |
8531 | return isl_stat_ok; |
8532 | } |
8533 | |
8534 | pa = isl_pw_aff_copy(pw: data->pa); |
8535 | pa = isl_pw_aff_pullback_pw_multi_aff(pw: pa, pma); |
8536 | |
8537 | data->res = isl_union_pw_aff_add_pw_aff(u: data->res, part: pa); |
8538 | |
8539 | return data->res ? isl_stat_ok : isl_stat_error; |
8540 | } |
8541 | |
8542 | /* Check if any of the elements of data->upma can be plugged into pa, |
8543 | * add if so add the result to data->res. |
8544 | */ |
8545 | static isl_stat upa_pb_upma(__isl_take isl_pw_aff *pa, void *user) |
8546 | { |
8547 | struct isl_union_pw_aff_pullback_upma_data *data = user; |
8548 | isl_stat r; |
8549 | |
8550 | data->pa = pa; |
8551 | r = isl_union_pw_multi_aff_foreach_pw_multi_aff(u: data->upma, |
8552 | fn: &pa_pb_pma, user: data); |
8553 | isl_pw_aff_free(pw: pa); |
8554 | |
8555 | return r; |
8556 | } |
8557 | |
8558 | /* Compute the pullback of "upa" by the function represented by "upma". |
8559 | * In other words, plug in "upma" in "upa". The result contains |
8560 | * expressions defined over the domain space of "upma". |
8561 | * |
8562 | * Run over all pairs of elements in "upa" and "upma", perform |
8563 | * the pullback when appropriate and collect the results. |
8564 | * If the hash value were based on the domain space rather than |
8565 | * the function space, then we could run through all elements |
8566 | * of "upma" and directly pick out the corresponding element of "upa". |
8567 | */ |
8568 | __isl_give isl_union_pw_aff *isl_union_pw_aff_pullback_union_pw_multi_aff( |
8569 | __isl_take isl_union_pw_aff *upa, |
8570 | __isl_take isl_union_pw_multi_aff *upma) |
8571 | { |
8572 | struct isl_union_pw_aff_pullback_upma_data data = { NULL, NULL }; |
8573 | isl_space *space; |
8574 | |
8575 | space = isl_union_pw_multi_aff_get_space(u: upma); |
8576 | upa = isl_union_pw_aff_align_params(u: upa, model: space); |
8577 | space = isl_union_pw_aff_get_space(u: upa); |
8578 | upma = isl_union_pw_multi_aff_align_params(u: upma, model: space); |
8579 | |
8580 | if (!upa || !upma) |
8581 | goto error; |
8582 | |
8583 | data.upma = upma; |
8584 | data.res = isl_union_pw_aff_alloc_same_size(u: upa); |
8585 | if (isl_union_pw_aff_foreach_pw_aff(u: upa, fn: &upa_pb_upma, user: &data) < 0) |
8586 | data.res = isl_union_pw_aff_free(u: data.res); |
8587 | |
8588 | isl_union_pw_aff_free(u: upa); |
8589 | isl_union_pw_multi_aff_free(u: upma); |
8590 | return data.res; |
8591 | error: |
8592 | isl_union_pw_aff_free(u: upa); |
8593 | isl_union_pw_multi_aff_free(u: upma); |
8594 | return NULL; |
8595 | } |
8596 | |
8597 | #undef BASE |
8598 | #define BASE union_pw_aff |
8599 | #undef DOMBASE |
8600 | #define DOMBASE union_set |
8601 | |
8602 | #include <isl_multi_explicit_domain.c> |
8603 | #include <isl_multi_union_pw_aff_explicit_domain.c> |
8604 | #include <isl_multi_templ.c> |
8605 | #include <isl_multi_un_op_templ.c> |
8606 | #include <isl_multi_bin_val_templ.c> |
8607 | #include <isl_multi_apply_set.c> |
8608 | #include <isl_multi_apply_union_set.c> |
8609 | #include <isl_multi_arith_templ.c> |
8610 | #include <isl_multi_bind_templ.c> |
8611 | #include <isl_multi_coalesce.c> |
8612 | #include <isl_multi_dim_id_templ.c> |
8613 | #include <isl_multi_floor.c> |
8614 | #include <isl_multi_from_base_templ.c> |
8615 | #include <isl_multi_gist.c> |
8616 | #include <isl_multi_align_set.c> |
8617 | #include <isl_multi_align_union_set.c> |
8618 | #include <isl_multi_intersect.c> |
8619 | #include <isl_multi_nan_templ.c> |
8620 | #include <isl_multi_tuple_id_templ.c> |
8621 | #include <isl_multi_union_add_templ.c> |
8622 | #include <isl_multi_zero_space_templ.c> |
8623 | |
8624 | /* Does "mupa" have a non-trivial explicit domain? |
8625 | * |
8626 | * The explicit domain, if present, is trivial if it represents |
8627 | * an (obviously) universe parameter set. |
8628 | */ |
8629 | isl_bool isl_multi_union_pw_aff_has_non_trivial_domain( |
8630 | __isl_keep isl_multi_union_pw_aff *mupa) |
8631 | { |
8632 | isl_bool is_params, trivial; |
8633 | isl_set *set; |
8634 | |
8635 | if (!mupa) |
8636 | return isl_bool_error; |
8637 | if (!isl_multi_union_pw_aff_has_explicit_domain(multi: mupa)) |
8638 | return isl_bool_false; |
8639 | is_params = isl_union_set_is_params(uset: mupa->u.dom); |
8640 | if (is_params < 0 || !is_params) |
8641 | return isl_bool_not(b: is_params); |
8642 | set = isl_set_from_union_set(uset: isl_union_set_copy(uset: mupa->u.dom)); |
8643 | trivial = isl_set_plain_is_universe(set); |
8644 | isl_set_free(set); |
8645 | return isl_bool_not(b: trivial); |
8646 | } |
8647 | |
8648 | /* Construct a multiple union piecewise affine expression |
8649 | * in the given space with value zero in each of the output dimensions. |
8650 | * |
8651 | * Since there is no canonical zero value for |
8652 | * a union piecewise affine expression, we can only construct |
8653 | * a zero-dimensional "zero" value. |
8654 | */ |
8655 | __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_zero( |
8656 | __isl_take isl_space *space) |
8657 | { |
8658 | isl_bool params; |
8659 | isl_size dim; |
8660 | |
8661 | if (!space) |
8662 | return NULL; |
8663 | |
8664 | params = isl_space_is_params(space); |
8665 | if (params < 0) |
8666 | goto error; |
8667 | if (params) |
8668 | isl_die(isl_space_get_ctx(space), isl_error_invalid, |
8669 | "expecting proper set space" , goto error); |
8670 | if (!isl_space_is_set(space)) |
8671 | isl_die(isl_space_get_ctx(space), isl_error_invalid, |
8672 | "expecting set space" , goto error); |
8673 | dim = isl_space_dim(space, type: isl_dim_out); |
8674 | if (dim < 0) |
8675 | goto error; |
8676 | if (dim != 0) |
8677 | isl_die(isl_space_get_ctx(space), isl_error_invalid, |
8678 | "expecting 0D space" , goto error); |
8679 | |
8680 | return isl_multi_union_pw_aff_alloc(space); |
8681 | error: |
8682 | isl_space_free(space); |
8683 | return NULL; |
8684 | } |
8685 | |
8686 | /* Construct and return a multi union piecewise affine expression |
8687 | * that is equal to the given multi affine expression. |
8688 | */ |
8689 | __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_aff( |
8690 | __isl_take isl_multi_aff *ma) |
8691 | { |
8692 | isl_multi_pw_aff *mpa; |
8693 | |
8694 | mpa = isl_multi_pw_aff_from_multi_aff(ma); |
8695 | return isl_multi_union_pw_aff_from_multi_pw_aff(mpa); |
8696 | } |
8697 | |
8698 | /* This function performs the same operation as |
8699 | * isl_multi_union_pw_aff_from_multi_aff, but is considered as a function on an |
8700 | * isl_multi_aff when exported. |
8701 | */ |
8702 | __isl_give isl_multi_union_pw_aff *isl_multi_aff_to_multi_union_pw_aff( |
8703 | __isl_take isl_multi_aff *ma) |
8704 | { |
8705 | return isl_multi_union_pw_aff_from_multi_aff(ma); |
8706 | } |
8707 | |
8708 | /* Construct and return a multi union piecewise affine expression |
8709 | * that is equal to the given multi piecewise affine expression. |
8710 | * |
8711 | * If the resulting multi union piecewise affine expression has |
8712 | * an explicit domain, then assign it the domain of the input. |
8713 | * In other cases, the domain is stored in the individual elements. |
8714 | */ |
8715 | __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_multi_pw_aff( |
8716 | __isl_take isl_multi_pw_aff *mpa) |
8717 | { |
8718 | int i; |
8719 | isl_size n; |
8720 | isl_space *space; |
8721 | isl_multi_union_pw_aff *mupa; |
8722 | |
8723 | n = isl_multi_pw_aff_dim(multi: mpa, type: isl_dim_out); |
8724 | if (n < 0) |
8725 | mpa = isl_multi_pw_aff_free(multi: mpa); |
8726 | if (!mpa) |
8727 | return NULL; |
8728 | |
8729 | space = isl_multi_pw_aff_get_space(multi: mpa); |
8730 | space = isl_space_range(space); |
8731 | mupa = isl_multi_union_pw_aff_alloc(space); |
8732 | |
8733 | for (i = 0; i < n; ++i) { |
8734 | isl_pw_aff *pa; |
8735 | isl_union_pw_aff *upa; |
8736 | |
8737 | pa = isl_multi_pw_aff_get_pw_aff(multi: mpa, pos: i); |
8738 | upa = isl_union_pw_aff_from_pw_aff(part: pa); |
8739 | mupa = isl_multi_union_pw_aff_restore_check_space(multi: mupa, pos: i, el: upa); |
8740 | } |
8741 | if (isl_multi_union_pw_aff_has_explicit_domain(multi: mupa)) { |
8742 | isl_union_set *dom; |
8743 | isl_multi_pw_aff *copy; |
8744 | |
8745 | copy = isl_multi_pw_aff_copy(multi: mpa); |
8746 | dom = isl_union_set_from_set(set: isl_multi_pw_aff_domain(multi: copy)); |
8747 | mupa = isl_multi_union_pw_aff_intersect_domain(multi: mupa, domain: dom); |
8748 | } |
8749 | |
8750 | isl_multi_pw_aff_free(multi: mpa); |
8751 | |
8752 | return mupa; |
8753 | } |
8754 | |
8755 | /* Extract the range space of "pma" and assign it to *space. |
8756 | * If *space has already been set (through a previous call to this function), |
8757 | * then check that the range space is the same. |
8758 | */ |
8759 | static isl_stat (__isl_take isl_pw_multi_aff *pma, void *user) |
8760 | { |
8761 | isl_space **space = user; |
8762 | isl_space *pma_space; |
8763 | isl_bool equal; |
8764 | |
8765 | pma_space = isl_space_range(space: isl_pw_multi_aff_get_space(pw: pma)); |
8766 | isl_pw_multi_aff_free(pw: pma); |
8767 | |
8768 | if (!pma_space) |
8769 | return isl_stat_error; |
8770 | if (!*space) { |
8771 | *space = pma_space; |
8772 | return isl_stat_ok; |
8773 | } |
8774 | |
8775 | equal = isl_space_is_equal(space1: pma_space, space2: *space); |
8776 | isl_space_free(space: pma_space); |
8777 | |
8778 | if (equal < 0) |
8779 | return isl_stat_error; |
8780 | if (!equal) |
8781 | isl_die(isl_space_get_ctx(*space), isl_error_invalid, |
8782 | "range spaces not the same" , return isl_stat_error); |
8783 | return isl_stat_ok; |
8784 | } |
8785 | |
8786 | /* Construct and return a multi union piecewise affine expression |
8787 | * that is equal to the given union piecewise multi affine expression. |
8788 | * |
8789 | * In order to be able to perform the conversion, the input |
8790 | * needs to be non-empty and may only involve a single range space. |
8791 | * |
8792 | * If the resulting multi union piecewise affine expression has |
8793 | * an explicit domain, then assign it the domain of the input. |
8794 | * In other cases, the domain is stored in the individual elements. |
8795 | */ |
8796 | __isl_give isl_multi_union_pw_aff * |
8797 | isl_multi_union_pw_aff_from_union_pw_multi_aff( |
8798 | __isl_take isl_union_pw_multi_aff *upma) |
8799 | { |
8800 | isl_space *space = NULL; |
8801 | isl_multi_union_pw_aff *mupa; |
8802 | int i; |
8803 | isl_size n; |
8804 | |
8805 | n = isl_union_pw_multi_aff_n_pw_multi_aff(u: upma); |
8806 | if (n < 0) |
8807 | goto error; |
8808 | if (n == 0) |
8809 | isl_die(isl_union_pw_multi_aff_get_ctx(upma), isl_error_invalid, |
8810 | "cannot extract range space from empty input" , |
8811 | goto error); |
8812 | if (isl_union_pw_multi_aff_foreach_pw_multi_aff(u: upma, fn: &extract_space, |
8813 | user: &space) < 0) |
8814 | goto error; |
8815 | |
8816 | if (!space) |
8817 | goto error; |
8818 | |
8819 | n = isl_space_dim(space, type: isl_dim_set); |
8820 | if (n < 0) |
8821 | space = isl_space_free(space); |
8822 | mupa = isl_multi_union_pw_aff_alloc(space); |
8823 | |
8824 | for (i = 0; i < n; ++i) { |
8825 | isl_union_pw_aff *upa; |
8826 | |
8827 | upa = isl_union_pw_multi_aff_get_union_pw_aff(upma, pos: i); |
8828 | mupa = isl_multi_union_pw_aff_set_union_pw_aff(multi: mupa, pos: i, el: upa); |
8829 | } |
8830 | if (isl_multi_union_pw_aff_has_explicit_domain(multi: mupa)) { |
8831 | isl_union_set *dom; |
8832 | isl_union_pw_multi_aff *copy; |
8833 | |
8834 | copy = isl_union_pw_multi_aff_copy(u: upma); |
8835 | dom = isl_union_pw_multi_aff_domain(u: copy); |
8836 | mupa = isl_multi_union_pw_aff_intersect_domain(multi: mupa, domain: dom); |
8837 | } |
8838 | |
8839 | isl_union_pw_multi_aff_free(u: upma); |
8840 | return mupa; |
8841 | error: |
8842 | isl_space_free(space); |
8843 | isl_union_pw_multi_aff_free(u: upma); |
8844 | return NULL; |
8845 | } |
8846 | |
8847 | /* This function performs the same operation as |
8848 | * isl_multi_union_pw_aff_from_union_pw_multi_aff, |
8849 | * but is considered as a function on an isl_union_pw_multi_aff when exported. |
8850 | */ |
8851 | __isl_give isl_multi_union_pw_aff * |
8852 | isl_union_pw_multi_aff_as_multi_union_pw_aff( |
8853 | __isl_take isl_union_pw_multi_aff *upma) |
8854 | { |
8855 | return isl_multi_union_pw_aff_from_union_pw_multi_aff(upma); |
8856 | } |
8857 | |
8858 | /* Try and create an isl_multi_union_pw_aff that is equivalent |
8859 | * to the given isl_union_map. |
8860 | * The isl_union_map is required to be single-valued in each space. |
8861 | * Moreover, it cannot be empty and all range spaces need to be the same. |
8862 | * Otherwise, an error is produced. |
8863 | */ |
8864 | __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_from_union_map( |
8865 | __isl_take isl_union_map *umap) |
8866 | { |
8867 | isl_union_pw_multi_aff *upma; |
8868 | |
8869 | upma = isl_union_pw_multi_aff_from_union_map(umap); |
8870 | return isl_multi_union_pw_aff_from_union_pw_multi_aff(upma); |
8871 | } |
8872 | |
8873 | /* This function performs the same operation as |
8874 | * isl_multi_union_pw_aff_from_union_map, |
8875 | * but is considered as a function on an isl_union_map when exported. |
8876 | */ |
8877 | __isl_give isl_multi_union_pw_aff *isl_union_map_as_multi_union_pw_aff( |
8878 | __isl_take isl_union_map *umap) |
8879 | { |
8880 | return isl_multi_union_pw_aff_from_union_map(umap); |
8881 | } |
8882 | |
8883 | /* Return a multiple union piecewise affine expression |
8884 | * that is equal to "mv" on "domain", assuming "domain" and "mv" |
8885 | * have been aligned. |
8886 | * |
8887 | * If the resulting multi union piecewise affine expression has |
8888 | * an explicit domain, then assign it the input domain. |
8889 | * In other cases, the domain is stored in the individual elements. |
8890 | */ |
8891 | static __isl_give isl_multi_union_pw_aff * |
8892 | isl_multi_union_pw_aff_multi_val_on_domain_aligned( |
8893 | __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv) |
8894 | { |
8895 | int i; |
8896 | isl_size n; |
8897 | isl_space *space; |
8898 | isl_multi_union_pw_aff *mupa; |
8899 | |
8900 | n = isl_multi_val_dim(multi: mv, type: isl_dim_set); |
8901 | if (!domain || n < 0) |
8902 | goto error; |
8903 | |
8904 | space = isl_multi_val_get_space(multi: mv); |
8905 | mupa = isl_multi_union_pw_aff_alloc(space); |
8906 | for (i = 0; i < n; ++i) { |
8907 | isl_val *v; |
8908 | isl_union_pw_aff *upa; |
8909 | |
8910 | v = isl_multi_val_get_val(multi: mv, pos: i); |
8911 | upa = isl_union_pw_aff_val_on_domain(domain: isl_union_set_copy(uset: domain), |
8912 | v); |
8913 | mupa = isl_multi_union_pw_aff_set_union_pw_aff(multi: mupa, pos: i, el: upa); |
8914 | } |
8915 | if (isl_multi_union_pw_aff_has_explicit_domain(multi: mupa)) |
8916 | mupa = isl_multi_union_pw_aff_intersect_domain(multi: mupa, |
8917 | domain: isl_union_set_copy(uset: domain)); |
8918 | |
8919 | isl_union_set_free(uset: domain); |
8920 | isl_multi_val_free(multi: mv); |
8921 | return mupa; |
8922 | error: |
8923 | isl_union_set_free(uset: domain); |
8924 | isl_multi_val_free(multi: mv); |
8925 | return NULL; |
8926 | } |
8927 | |
8928 | /* Return a multiple union piecewise affine expression |
8929 | * that is equal to "mv" on "domain". |
8930 | */ |
8931 | __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_val_on_domain( |
8932 | __isl_take isl_union_set *domain, __isl_take isl_multi_val *mv) |
8933 | { |
8934 | isl_bool equal_params; |
8935 | |
8936 | if (!domain || !mv) |
8937 | goto error; |
8938 | equal_params = isl_space_has_equal_params(space1: domain->dim, space2: mv->space); |
8939 | if (equal_params < 0) |
8940 | goto error; |
8941 | if (equal_params) |
8942 | return isl_multi_union_pw_aff_multi_val_on_domain_aligned( |
8943 | domain, mv); |
8944 | domain = isl_union_set_align_params(uset: domain, |
8945 | model: isl_multi_val_get_space(multi: mv)); |
8946 | mv = isl_multi_val_align_params(multi: mv, model: isl_union_set_get_space(uset: domain)); |
8947 | return isl_multi_union_pw_aff_multi_val_on_domain_aligned(domain, mv); |
8948 | error: |
8949 | isl_union_set_free(uset: domain); |
8950 | isl_multi_val_free(multi: mv); |
8951 | return NULL; |
8952 | } |
8953 | |
8954 | /* Return a multiple union piecewise affine expression |
8955 | * that is equal to "ma" on "domain". |
8956 | */ |
8957 | __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_multi_aff_on_domain( |
8958 | __isl_take isl_union_set *domain, __isl_take isl_multi_aff *ma) |
8959 | { |
8960 | isl_pw_multi_aff *pma; |
8961 | |
8962 | pma = isl_pw_multi_aff_from_multi_aff(el: ma); |
8963 | return isl_multi_union_pw_aff_pw_multi_aff_on_domain(domain, pma); |
8964 | } |
8965 | |
8966 | /* Return a multiple union piecewise affine expression |
8967 | * that is equal to "pma" on "domain", assuming "domain" and "pma" |
8968 | * have been aligned. |
8969 | * |
8970 | * If the resulting multi union piecewise affine expression has |
8971 | * an explicit domain, then assign it the input domain. |
8972 | * In other cases, the domain is stored in the individual elements. |
8973 | */ |
8974 | static __isl_give isl_multi_union_pw_aff * |
8975 | isl_multi_union_pw_aff_pw_multi_aff_on_domain_aligned( |
8976 | __isl_take isl_union_set *domain, __isl_take isl_pw_multi_aff *pma) |
8977 | { |
8978 | int i; |
8979 | isl_size n; |
8980 | isl_space *space; |
8981 | isl_multi_union_pw_aff *mupa; |
8982 | |
8983 | n = isl_pw_multi_aff_dim(pw: pma, type: isl_dim_set); |
8984 | if (!domain || n < 0) |
8985 | goto error; |
8986 | space = isl_pw_multi_aff_get_space(pw: pma); |
8987 | mupa = isl_multi_union_pw_aff_alloc(space); |
8988 | for (i = 0; i < n; ++i) { |
8989 | isl_pw_aff *pa; |
8990 | isl_union_pw_aff *upa; |
8991 | |
8992 | pa = isl_pw_multi_aff_get_pw_aff(pma, pos: i); |
8993 | upa = isl_union_pw_aff_pw_aff_on_domain( |
8994 | domain: isl_union_set_copy(uset: domain), pa); |
8995 | mupa = isl_multi_union_pw_aff_set_union_pw_aff(multi: mupa, pos: i, el: upa); |
8996 | } |
8997 | if (isl_multi_union_pw_aff_has_explicit_domain(multi: mupa)) |
8998 | mupa = isl_multi_union_pw_aff_intersect_domain(multi: mupa, |
8999 | domain: isl_union_set_copy(uset: domain)); |
9000 | |
9001 | isl_union_set_free(uset: domain); |
9002 | isl_pw_multi_aff_free(pw: pma); |
9003 | return mupa; |
9004 | error: |
9005 | isl_union_set_free(uset: domain); |
9006 | isl_pw_multi_aff_free(pw: pma); |
9007 | return NULL; |
9008 | } |
9009 | |
9010 | /* Return a multiple union piecewise affine expression |
9011 | * that is equal to "pma" on "domain". |
9012 | */ |
9013 | __isl_give isl_multi_union_pw_aff * |
9014 | isl_multi_union_pw_aff_pw_multi_aff_on_domain(__isl_take isl_union_set *domain, |
9015 | __isl_take isl_pw_multi_aff *pma) |
9016 | { |
9017 | isl_bool equal_params; |
9018 | isl_space *space; |
9019 | |
9020 | space = isl_pw_multi_aff_peek_space(pw: pma); |
9021 | equal_params = isl_union_set_space_has_equal_params(uset: domain, space); |
9022 | if (equal_params < 0) |
9023 | goto error; |
9024 | if (equal_params) |
9025 | return isl_multi_union_pw_aff_pw_multi_aff_on_domain_aligned( |
9026 | domain, pma); |
9027 | domain = isl_union_set_align_params(uset: domain, |
9028 | model: isl_pw_multi_aff_get_space(pw: pma)); |
9029 | pma = isl_pw_multi_aff_align_params(pw: pma, |
9030 | model: isl_union_set_get_space(uset: domain)); |
9031 | return isl_multi_union_pw_aff_pw_multi_aff_on_domain_aligned(domain, |
9032 | pma); |
9033 | error: |
9034 | isl_union_set_free(uset: domain); |
9035 | isl_pw_multi_aff_free(pw: pma); |
9036 | return NULL; |
9037 | } |
9038 | |
9039 | /* Return a union set containing those elements in the domains |
9040 | * of the elements of "mupa" where they are all zero. |
9041 | * |
9042 | * If there are no elements, then simply return the entire domain. |
9043 | */ |
9044 | __isl_give isl_union_set *isl_multi_union_pw_aff_zero_union_set( |
9045 | __isl_take isl_multi_union_pw_aff *mupa) |
9046 | { |
9047 | int i; |
9048 | isl_size n; |
9049 | isl_union_pw_aff *upa; |
9050 | isl_union_set *zero; |
9051 | |
9052 | n = isl_multi_union_pw_aff_dim(multi: mupa, type: isl_dim_set); |
9053 | if (n < 0) |
9054 | mupa = isl_multi_union_pw_aff_free(multi: mupa); |
9055 | if (!mupa) |
9056 | return NULL; |
9057 | |
9058 | if (n == 0) |
9059 | return isl_multi_union_pw_aff_domain(mupa); |
9060 | |
9061 | upa = isl_multi_union_pw_aff_get_union_pw_aff(multi: mupa, pos: 0); |
9062 | zero = isl_union_pw_aff_zero_union_set(upa); |
9063 | |
9064 | for (i = 1; i < n; ++i) { |
9065 | isl_union_set *zero_i; |
9066 | |
9067 | upa = isl_multi_union_pw_aff_get_union_pw_aff(multi: mupa, pos: i); |
9068 | zero_i = isl_union_pw_aff_zero_union_set(upa); |
9069 | |
9070 | zero = isl_union_set_intersect(uset1: zero, uset2: zero_i); |
9071 | } |
9072 | |
9073 | isl_multi_union_pw_aff_free(multi: mupa); |
9074 | return zero; |
9075 | } |
9076 | |
9077 | /* Construct a union map mapping the shared domain |
9078 | * of the union piecewise affine expressions to the range of "mupa" |
9079 | * in the special case of a 0D multi union piecewise affine expression. |
9080 | * |
9081 | * Construct a map between the explicit domain of "mupa" and |
9082 | * the range space. |
9083 | * Note that this assumes that the domain consists of explicit elements. |
9084 | */ |
9085 | static __isl_give isl_union_map *isl_union_map_from_multi_union_pw_aff_0D( |
9086 | __isl_take isl_multi_union_pw_aff *mupa) |
9087 | { |
9088 | isl_bool is_params; |
9089 | isl_space *space; |
9090 | isl_union_set *dom, *ran; |
9091 | |
9092 | space = isl_multi_union_pw_aff_get_space(multi: mupa); |
9093 | dom = isl_multi_union_pw_aff_domain(mupa); |
9094 | ran = isl_union_set_from_set(set: isl_set_universe(space)); |
9095 | |
9096 | is_params = isl_union_set_is_params(uset: dom); |
9097 | if (is_params < 0) |
9098 | dom = isl_union_set_free(uset: dom); |
9099 | else if (is_params) |
9100 | isl_die(isl_union_set_get_ctx(dom), isl_error_invalid, |
9101 | "cannot create union map from expression without " |
9102 | "explicit domain elements" , |
9103 | dom = isl_union_set_free(dom)); |
9104 | |
9105 | return isl_union_map_from_domain_and_range(domain: dom, range: ran); |
9106 | } |
9107 | |
9108 | /* Construct a union map mapping the shared domain |
9109 | * of the union piecewise affine expressions to the range of "mupa" |
9110 | * with each dimension in the range equated to the |
9111 | * corresponding union piecewise affine expression. |
9112 | * |
9113 | * If the input is zero-dimensional, then construct a mapping |
9114 | * from its explicit domain. |
9115 | */ |
9116 | __isl_give isl_union_map *isl_union_map_from_multi_union_pw_aff( |
9117 | __isl_take isl_multi_union_pw_aff *mupa) |
9118 | { |
9119 | int i; |
9120 | isl_size n; |
9121 | isl_space *space; |
9122 | isl_union_map *umap; |
9123 | isl_union_pw_aff *upa; |
9124 | |
9125 | n = isl_multi_union_pw_aff_dim(multi: mupa, type: isl_dim_set); |
9126 | if (n < 0) |
9127 | mupa = isl_multi_union_pw_aff_free(multi: mupa); |
9128 | if (!mupa) |
9129 | return NULL; |
9130 | |
9131 | if (n == 0) |
9132 | return isl_union_map_from_multi_union_pw_aff_0D(mupa); |
9133 | |
9134 | upa = isl_multi_union_pw_aff_get_union_pw_aff(multi: mupa, pos: 0); |
9135 | umap = isl_union_map_from_union_pw_aff(upa); |
9136 | |
9137 | for (i = 1; i < n; ++i) { |
9138 | isl_union_map *umap_i; |
9139 | |
9140 | upa = isl_multi_union_pw_aff_get_union_pw_aff(multi: mupa, pos: i); |
9141 | umap_i = isl_union_map_from_union_pw_aff(upa); |
9142 | umap = isl_union_map_flat_range_product(umap1: umap, umap2: umap_i); |
9143 | } |
9144 | |
9145 | space = isl_multi_union_pw_aff_get_space(multi: mupa); |
9146 | umap = isl_union_map_reset_range_space(umap, space); |
9147 | |
9148 | isl_multi_union_pw_aff_free(multi: mupa); |
9149 | return umap; |
9150 | } |
9151 | |
9152 | /* Internal data structure for isl_union_pw_multi_aff_reset_range_space. |
9153 | * "range" is the space from which to set the range space. |
9154 | * "res" collects the results. |
9155 | */ |
9156 | struct isl_union_pw_multi_aff_reset_range_space_data { |
9157 | isl_space *range; |
9158 | isl_union_pw_multi_aff *res; |
9159 | }; |
9160 | |
9161 | /* Replace the range space of "pma" by the range space of data->range and |
9162 | * add the result to data->res. |
9163 | */ |
9164 | static isl_stat reset_range_space(__isl_take isl_pw_multi_aff *pma, void *user) |
9165 | { |
9166 | struct isl_union_pw_multi_aff_reset_range_space_data *data = user; |
9167 | isl_space *space; |
9168 | |
9169 | space = isl_pw_multi_aff_get_space(pw: pma); |
9170 | space = isl_space_domain(space); |
9171 | space = isl_space_extend_domain_with_range(domain: space, |
9172 | model: isl_space_copy(space: data->range)); |
9173 | pma = isl_pw_multi_aff_reset_space(pw: pma, space); |
9174 | data->res = isl_union_pw_multi_aff_add_pw_multi_aff(u: data->res, part: pma); |
9175 | |
9176 | return data->res ? isl_stat_ok : isl_stat_error; |
9177 | } |
9178 | |
9179 | /* Replace the range space of all the piecewise affine expressions in "upma" by |
9180 | * the range space of "space". |
9181 | * |
9182 | * This assumes that all these expressions have the same output dimension. |
9183 | * |
9184 | * Since the spaces of the expressions change, so do their hash values. |
9185 | * We therefore need to create a new isl_union_pw_multi_aff. |
9186 | * Note that the hash value is currently computed based on the entire |
9187 | * space even though there can only be a single expression with a given |
9188 | * domain space. |
9189 | */ |
9190 | static __isl_give isl_union_pw_multi_aff * |
9191 | isl_union_pw_multi_aff_reset_range_space( |
9192 | __isl_take isl_union_pw_multi_aff *upma, __isl_take isl_space *space) |
9193 | { |
9194 | struct isl_union_pw_multi_aff_reset_range_space_data data = { space }; |
9195 | isl_space *space_upma; |
9196 | |
9197 | space_upma = isl_union_pw_multi_aff_get_space(u: upma); |
9198 | data.res = isl_union_pw_multi_aff_empty(space: space_upma); |
9199 | if (isl_union_pw_multi_aff_foreach_pw_multi_aff(u: upma, |
9200 | fn: &reset_range_space, user: &data) < 0) |
9201 | data.res = isl_union_pw_multi_aff_free(u: data.res); |
9202 | |
9203 | isl_space_free(space); |
9204 | isl_union_pw_multi_aff_free(u: upma); |
9205 | return data.res; |
9206 | } |
9207 | |
9208 | /* Construct and return a union piecewise multi affine expression |
9209 | * that is equal to the given multi union piecewise affine expression, |
9210 | * in the special case of a 0D multi union piecewise affine expression. |
9211 | * |
9212 | * Construct a union piecewise multi affine expression |
9213 | * on top of the explicit domain of the input. |
9214 | */ |
9215 | __isl_give isl_union_pw_multi_aff * |
9216 | isl_union_pw_multi_aff_from_multi_union_pw_aff_0D( |
9217 | __isl_take isl_multi_union_pw_aff *mupa) |
9218 | { |
9219 | isl_space *space; |
9220 | isl_multi_val *mv; |
9221 | isl_union_set *domain; |
9222 | |
9223 | space = isl_multi_union_pw_aff_get_space(multi: mupa); |
9224 | mv = isl_multi_val_zero(space); |
9225 | domain = isl_multi_union_pw_aff_domain(mupa); |
9226 | return isl_union_pw_multi_aff_multi_val_on_domain(domain, mv); |
9227 | } |
9228 | |
9229 | /* Construct and return a union piecewise multi affine expression |
9230 | * that is equal to the given multi union piecewise affine expression. |
9231 | * |
9232 | * If the input is zero-dimensional, then |
9233 | * construct a union piecewise multi affine expression |
9234 | * on top of the explicit domain of the input. |
9235 | */ |
9236 | __isl_give isl_union_pw_multi_aff * |
9237 | isl_union_pw_multi_aff_from_multi_union_pw_aff( |
9238 | __isl_take isl_multi_union_pw_aff *mupa) |
9239 | { |
9240 | int i; |
9241 | isl_size n; |
9242 | isl_space *space; |
9243 | isl_union_pw_multi_aff *upma; |
9244 | isl_union_pw_aff *upa; |
9245 | |
9246 | n = isl_multi_union_pw_aff_dim(multi: mupa, type: isl_dim_set); |
9247 | if (n < 0) |
9248 | mupa = isl_multi_union_pw_aff_free(multi: mupa); |
9249 | if (!mupa) |
9250 | return NULL; |
9251 | |
9252 | if (n == 0) |
9253 | return isl_union_pw_multi_aff_from_multi_union_pw_aff_0D(mupa); |
9254 | |
9255 | space = isl_multi_union_pw_aff_get_space(multi: mupa); |
9256 | upa = isl_multi_union_pw_aff_get_union_pw_aff(multi: mupa, pos: 0); |
9257 | upma = isl_union_pw_multi_aff_from_union_pw_aff(upa); |
9258 | |
9259 | for (i = 1; i < n; ++i) { |
9260 | isl_union_pw_multi_aff *upma_i; |
9261 | |
9262 | upa = isl_multi_union_pw_aff_get_union_pw_aff(multi: mupa, pos: i); |
9263 | upma_i = isl_union_pw_multi_aff_from_union_pw_aff(upa); |
9264 | upma = isl_union_pw_multi_aff_flat_range_product(upma1: upma, upma2: upma_i); |
9265 | } |
9266 | |
9267 | upma = isl_union_pw_multi_aff_reset_range_space(upma, space); |
9268 | |
9269 | isl_multi_union_pw_aff_free(multi: mupa); |
9270 | return upma; |
9271 | } |
9272 | |
9273 | /* Intersect the range of "mupa" with "range", |
9274 | * in the special case where "mupa" is 0D. |
9275 | * |
9276 | * Intersect the domain of "mupa" with the constraints on the parameters |
9277 | * of "range". |
9278 | */ |
9279 | static __isl_give isl_multi_union_pw_aff *mupa_intersect_range_0D( |
9280 | __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *range) |
9281 | { |
9282 | range = isl_set_params(set: range); |
9283 | mupa = isl_multi_union_pw_aff_intersect_params(multi: mupa, domain: range); |
9284 | return mupa; |
9285 | } |
9286 | |
9287 | /* Intersect the range of "mupa" with "range". |
9288 | * That is, keep only those domain elements that have a function value |
9289 | * in "range". |
9290 | */ |
9291 | __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_intersect_range( |
9292 | __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_set *range) |
9293 | { |
9294 | isl_union_pw_multi_aff *upma; |
9295 | isl_union_set *domain; |
9296 | isl_space *space; |
9297 | isl_size n; |
9298 | int match; |
9299 | |
9300 | n = isl_multi_union_pw_aff_dim(multi: mupa, type: isl_dim_set); |
9301 | if (n < 0 || !range) |
9302 | goto error; |
9303 | |
9304 | space = isl_set_get_space(set: range); |
9305 | match = isl_space_tuple_is_equal(space1: mupa->space, type1: isl_dim_set, |
9306 | space2: space, type2: isl_dim_set); |
9307 | isl_space_free(space); |
9308 | if (match < 0) |
9309 | goto error; |
9310 | if (!match) |
9311 | isl_die(isl_multi_union_pw_aff_get_ctx(mupa), isl_error_invalid, |
9312 | "space don't match" , goto error); |
9313 | if (n == 0) |
9314 | return mupa_intersect_range_0D(mupa, range); |
9315 | |
9316 | upma = isl_union_pw_multi_aff_from_multi_union_pw_aff( |
9317 | mupa: isl_multi_union_pw_aff_copy(multi: mupa)); |
9318 | domain = isl_union_set_from_set(set: range); |
9319 | domain = isl_union_set_preimage_union_pw_multi_aff(uset: domain, upma); |
9320 | mupa = isl_multi_union_pw_aff_intersect_domain(multi: mupa, domain); |
9321 | |
9322 | return mupa; |
9323 | error: |
9324 | isl_multi_union_pw_aff_free(multi: mupa); |
9325 | isl_set_free(set: range); |
9326 | return NULL; |
9327 | } |
9328 | |
9329 | /* Return the shared domain of the elements of "mupa", |
9330 | * in the special case where "mupa" is zero-dimensional. |
9331 | * |
9332 | * Return the explicit domain of "mupa". |
9333 | * Note that this domain may be a parameter set, either |
9334 | * because "mupa" is meant to live in a set space or |
9335 | * because no explicit domain has been set. |
9336 | */ |
9337 | __isl_give isl_union_set *isl_multi_union_pw_aff_domain_0D( |
9338 | __isl_take isl_multi_union_pw_aff *mupa) |
9339 | { |
9340 | isl_union_set *dom; |
9341 | |
9342 | dom = isl_multi_union_pw_aff_get_explicit_domain(multi: mupa); |
9343 | isl_multi_union_pw_aff_free(multi: mupa); |
9344 | |
9345 | return dom; |
9346 | } |
9347 | |
9348 | /* Return the shared domain of the elements of "mupa". |
9349 | * |
9350 | * If "mupa" is zero-dimensional, then return its explicit domain. |
9351 | */ |
9352 | __isl_give isl_union_set *isl_multi_union_pw_aff_domain( |
9353 | __isl_take isl_multi_union_pw_aff *mupa) |
9354 | { |
9355 | int i; |
9356 | isl_size n; |
9357 | isl_union_pw_aff *upa; |
9358 | isl_union_set *dom; |
9359 | |
9360 | n = isl_multi_union_pw_aff_dim(multi: mupa, type: isl_dim_set); |
9361 | if (n < 0) |
9362 | mupa = isl_multi_union_pw_aff_free(multi: mupa); |
9363 | if (!mupa) |
9364 | return NULL; |
9365 | |
9366 | if (n == 0) |
9367 | return isl_multi_union_pw_aff_domain_0D(mupa); |
9368 | |
9369 | upa = isl_multi_union_pw_aff_get_union_pw_aff(multi: mupa, pos: 0); |
9370 | dom = isl_union_pw_aff_domain(u: upa); |
9371 | for (i = 1; i < n; ++i) { |
9372 | isl_union_set *dom_i; |
9373 | |
9374 | upa = isl_multi_union_pw_aff_get_union_pw_aff(multi: mupa, pos: i); |
9375 | dom_i = isl_union_pw_aff_domain(u: upa); |
9376 | dom = isl_union_set_intersect(uset1: dom, uset2: dom_i); |
9377 | } |
9378 | |
9379 | isl_multi_union_pw_aff_free(multi: mupa); |
9380 | return dom; |
9381 | } |
9382 | |
9383 | /* Apply "aff" to "mupa". The space of "mupa" is equal to the domain of "aff". |
9384 | * In particular, the spaces have been aligned. |
9385 | * The result is defined over the shared domain of the elements of "mupa" |
9386 | * |
9387 | * We first extract the parametric constant part of "aff" and |
9388 | * define that over the shared domain. |
9389 | * Then we iterate over all input dimensions of "aff" and add the corresponding |
9390 | * multiples of the elements of "mupa". |
9391 | * Finally, we consider the integer divisions, calling the function |
9392 | * recursively to obtain an isl_union_pw_aff corresponding to the |
9393 | * integer division argument. |
9394 | */ |
9395 | static __isl_give isl_union_pw_aff *multi_union_pw_aff_apply_aff( |
9396 | __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff) |
9397 | { |
9398 | int i; |
9399 | isl_size n_in, n_div; |
9400 | isl_union_pw_aff *upa; |
9401 | isl_union_set *uset; |
9402 | isl_val *v; |
9403 | isl_aff *cst; |
9404 | |
9405 | n_in = isl_aff_dim(aff, type: isl_dim_in); |
9406 | n_div = isl_aff_dim(aff, type: isl_dim_div); |
9407 | if (n_in < 0 || n_div < 0) |
9408 | goto error; |
9409 | |
9410 | uset = isl_multi_union_pw_aff_domain(mupa: isl_multi_union_pw_aff_copy(multi: mupa)); |
9411 | cst = isl_aff_copy(aff); |
9412 | cst = isl_aff_drop_dims(aff: cst, type: isl_dim_div, first: 0, n: n_div); |
9413 | cst = isl_aff_drop_dims(aff: cst, type: isl_dim_in, first: 0, n: n_in); |
9414 | cst = isl_aff_project_domain_on_params(aff: cst); |
9415 | upa = isl_union_pw_aff_aff_on_domain(domain: uset, aff: cst); |
9416 | |
9417 | for (i = 0; i < n_in; ++i) { |
9418 | isl_union_pw_aff *upa_i; |
9419 | |
9420 | if (!isl_aff_involves_dims(aff, type: isl_dim_in, first: i, n: 1)) |
9421 | continue; |
9422 | v = isl_aff_get_coefficient_val(aff, type: isl_dim_in, pos: i); |
9423 | upa_i = isl_multi_union_pw_aff_get_union_pw_aff(multi: mupa, pos: i); |
9424 | upa_i = isl_union_pw_aff_scale_val(u: upa_i, v); |
9425 | upa = isl_union_pw_aff_add(u1: upa, u2: upa_i); |
9426 | } |
9427 | |
9428 | for (i = 0; i < n_div; ++i) { |
9429 | isl_aff *div; |
9430 | isl_union_pw_aff *upa_i; |
9431 | |
9432 | if (!isl_aff_involves_dims(aff, type: isl_dim_div, first: i, n: 1)) |
9433 | continue; |
9434 | div = isl_aff_get_div(aff, pos: i); |
9435 | upa_i = multi_union_pw_aff_apply_aff( |
9436 | mupa: isl_multi_union_pw_aff_copy(multi: mupa), aff: div); |
9437 | upa_i = isl_union_pw_aff_floor(upa: upa_i); |
9438 | v = isl_aff_get_coefficient_val(aff, type: isl_dim_div, pos: i); |
9439 | upa_i = isl_union_pw_aff_scale_val(u: upa_i, v); |
9440 | upa = isl_union_pw_aff_add(u1: upa, u2: upa_i); |
9441 | } |
9442 | |
9443 | isl_multi_union_pw_aff_free(multi: mupa); |
9444 | isl_aff_free(aff); |
9445 | |
9446 | return upa; |
9447 | error: |
9448 | isl_multi_union_pw_aff_free(multi: mupa); |
9449 | isl_aff_free(aff); |
9450 | return NULL; |
9451 | } |
9452 | |
9453 | /* Apply "aff" to "mupa". The space of "mupa" needs to be compatible |
9454 | * with the domain of "aff". |
9455 | * Furthermore, the dimension of this space needs to be greater than zero. |
9456 | * The result is defined over the shared domain of the elements of "mupa" |
9457 | * |
9458 | * We perform these checks and then hand over control to |
9459 | * multi_union_pw_aff_apply_aff. |
9460 | */ |
9461 | __isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_aff( |
9462 | __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_aff *aff) |
9463 | { |
9464 | isl_size dim; |
9465 | isl_space *space1, *space2; |
9466 | isl_bool equal; |
9467 | |
9468 | mupa = isl_multi_union_pw_aff_align_params(multi: mupa, |
9469 | model: isl_aff_get_space(aff)); |
9470 | aff = isl_aff_align_params(aff, model: isl_multi_union_pw_aff_get_space(multi: mupa)); |
9471 | if (!mupa || !aff) |
9472 | goto error; |
9473 | |
9474 | space1 = isl_multi_union_pw_aff_get_space(multi: mupa); |
9475 | space2 = isl_aff_get_domain_space(aff); |
9476 | equal = isl_space_is_equal(space1, space2); |
9477 | isl_space_free(space: space1); |
9478 | isl_space_free(space: space2); |
9479 | if (equal < 0) |
9480 | goto error; |
9481 | if (!equal) |
9482 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
9483 | "spaces don't match" , goto error); |
9484 | dim = isl_aff_dim(aff, type: isl_dim_in); |
9485 | if (dim < 0) |
9486 | goto error; |
9487 | if (dim == 0) |
9488 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
9489 | "cannot determine domains" , goto error); |
9490 | |
9491 | return multi_union_pw_aff_apply_aff(mupa, aff); |
9492 | error: |
9493 | isl_multi_union_pw_aff_free(multi: mupa); |
9494 | isl_aff_free(aff); |
9495 | return NULL; |
9496 | } |
9497 | |
9498 | /* Apply "ma" to "mupa", in the special case where "mupa" is 0D. |
9499 | * The space of "mupa" is known to be compatible with the domain of "ma". |
9500 | * |
9501 | * Construct an isl_multi_union_pw_aff that is equal to "ma" |
9502 | * on the domain of "mupa". |
9503 | */ |
9504 | static __isl_give isl_multi_union_pw_aff *mupa_apply_multi_aff_0D( |
9505 | __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_multi_aff *ma) |
9506 | { |
9507 | isl_union_set *dom; |
9508 | |
9509 | dom = isl_multi_union_pw_aff_domain(mupa); |
9510 | ma = isl_multi_aff_project_domain_on_params(multi: ma); |
9511 | |
9512 | return isl_multi_union_pw_aff_multi_aff_on_domain(domain: dom, ma); |
9513 | } |
9514 | |
9515 | /* Apply "ma" to "mupa". The space of "mupa" needs to be compatible |
9516 | * with the domain of "ma". |
9517 | * The result is defined over the shared domain of the elements of "mupa" |
9518 | */ |
9519 | __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_multi_aff( |
9520 | __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_multi_aff *ma) |
9521 | { |
9522 | isl_space *space1, *space2; |
9523 | isl_multi_union_pw_aff *res; |
9524 | isl_bool equal; |
9525 | int i; |
9526 | isl_size n_in, n_out; |
9527 | |
9528 | mupa = isl_multi_union_pw_aff_align_params(multi: mupa, |
9529 | model: isl_multi_aff_get_space(multi: ma)); |
9530 | ma = isl_multi_aff_align_params(multi: ma, |
9531 | model: isl_multi_union_pw_aff_get_space(multi: mupa)); |
9532 | n_in = isl_multi_aff_dim(multi: ma, type: isl_dim_in); |
9533 | n_out = isl_multi_aff_dim(multi: ma, type: isl_dim_out); |
9534 | if (!mupa || n_in < 0 || n_out < 0) |
9535 | goto error; |
9536 | |
9537 | space1 = isl_multi_union_pw_aff_get_space(multi: mupa); |
9538 | space2 = isl_multi_aff_get_domain_space(multi: ma); |
9539 | equal = isl_space_is_equal(space1, space2); |
9540 | isl_space_free(space: space1); |
9541 | isl_space_free(space: space2); |
9542 | if (equal < 0) |
9543 | goto error; |
9544 | if (!equal) |
9545 | isl_die(isl_multi_aff_get_ctx(ma), isl_error_invalid, |
9546 | "spaces don't match" , goto error); |
9547 | if (n_in == 0) |
9548 | return mupa_apply_multi_aff_0D(mupa, ma); |
9549 | |
9550 | space1 = isl_space_range(space: isl_multi_aff_get_space(multi: ma)); |
9551 | res = isl_multi_union_pw_aff_alloc(space: space1); |
9552 | |
9553 | for (i = 0; i < n_out; ++i) { |
9554 | isl_aff *aff; |
9555 | isl_union_pw_aff *upa; |
9556 | |
9557 | aff = isl_multi_aff_get_aff(multi: ma, pos: i); |
9558 | upa = multi_union_pw_aff_apply_aff( |
9559 | mupa: isl_multi_union_pw_aff_copy(multi: mupa), aff); |
9560 | res = isl_multi_union_pw_aff_set_union_pw_aff(multi: res, pos: i, el: upa); |
9561 | } |
9562 | |
9563 | isl_multi_aff_free(multi: ma); |
9564 | isl_multi_union_pw_aff_free(multi: mupa); |
9565 | return res; |
9566 | error: |
9567 | isl_multi_union_pw_aff_free(multi: mupa); |
9568 | isl_multi_aff_free(multi: ma); |
9569 | return NULL; |
9570 | } |
9571 | |
9572 | /* Apply "pa" to "mupa", in the special case where "mupa" is 0D. |
9573 | * The space of "mupa" is known to be compatible with the domain of "pa". |
9574 | * |
9575 | * Construct an isl_multi_union_pw_aff that is equal to "pa" |
9576 | * on the domain of "mupa". |
9577 | */ |
9578 | static __isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_pw_aff_0D( |
9579 | __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_pw_aff *pa) |
9580 | { |
9581 | isl_union_set *dom; |
9582 | |
9583 | dom = isl_multi_union_pw_aff_domain(mupa); |
9584 | pa = isl_pw_aff_project_domain_on_params(pw: pa); |
9585 | |
9586 | return isl_union_pw_aff_pw_aff_on_domain(domain: dom, pa); |
9587 | } |
9588 | |
9589 | /* Apply "pa" to "mupa". The space of "mupa" needs to be compatible |
9590 | * with the domain of "pa". |
9591 | * Furthermore, the dimension of this space needs to be greater than zero. |
9592 | * The result is defined over the shared domain of the elements of "mupa" |
9593 | */ |
9594 | __isl_give isl_union_pw_aff *isl_multi_union_pw_aff_apply_pw_aff( |
9595 | __isl_take isl_multi_union_pw_aff *mupa, __isl_take isl_pw_aff *pa) |
9596 | { |
9597 | int i; |
9598 | isl_bool equal; |
9599 | isl_size n_in; |
9600 | isl_space *space, *space2; |
9601 | isl_union_pw_aff *upa; |
9602 | |
9603 | mupa = isl_multi_union_pw_aff_align_params(multi: mupa, |
9604 | model: isl_pw_aff_get_space(pw: pa)); |
9605 | pa = isl_pw_aff_align_params(pw: pa, |
9606 | model: isl_multi_union_pw_aff_get_space(multi: mupa)); |
9607 | if (!mupa || !pa) |
9608 | goto error; |
9609 | |
9610 | space = isl_multi_union_pw_aff_get_space(multi: mupa); |
9611 | space2 = isl_pw_aff_get_domain_space(pw: pa); |
9612 | equal = isl_space_is_equal(space1: space, space2); |
9613 | isl_space_free(space); |
9614 | isl_space_free(space: space2); |
9615 | if (equal < 0) |
9616 | goto error; |
9617 | if (!equal) |
9618 | isl_die(isl_pw_aff_get_ctx(pa), isl_error_invalid, |
9619 | "spaces don't match" , goto error); |
9620 | n_in = isl_pw_aff_dim(pw: pa, type: isl_dim_in); |
9621 | if (n_in < 0) |
9622 | goto error; |
9623 | if (n_in == 0) |
9624 | return isl_multi_union_pw_aff_apply_pw_aff_0D(mupa, pa); |
9625 | |
9626 | space = isl_space_params(space: isl_multi_union_pw_aff_get_space(multi: mupa)); |
9627 | upa = isl_union_pw_aff_empty(space); |
9628 | |
9629 | for (i = 0; i < pa->n; ++i) { |
9630 | isl_aff *aff; |
9631 | isl_set *domain; |
9632 | isl_multi_union_pw_aff *mupa_i; |
9633 | isl_union_pw_aff *upa_i; |
9634 | |
9635 | mupa_i = isl_multi_union_pw_aff_copy(multi: mupa); |
9636 | domain = isl_set_copy(set: pa->p[i].set); |
9637 | mupa_i = isl_multi_union_pw_aff_intersect_range(mupa: mupa_i, range: domain); |
9638 | aff = isl_aff_copy(aff: pa->p[i].aff); |
9639 | upa_i = multi_union_pw_aff_apply_aff(mupa: mupa_i, aff); |
9640 | upa = isl_union_pw_aff_union_add(u1: upa, u2: upa_i); |
9641 | } |
9642 | |
9643 | isl_multi_union_pw_aff_free(multi: mupa); |
9644 | isl_pw_aff_free(pw: pa); |
9645 | return upa; |
9646 | error: |
9647 | isl_multi_union_pw_aff_free(multi: mupa); |
9648 | isl_pw_aff_free(pw: pa); |
9649 | return NULL; |
9650 | } |
9651 | |
9652 | /* Apply "pma" to "mupa", in the special case where "mupa" is 0D. |
9653 | * The space of "mupa" is known to be compatible with the domain of "pma". |
9654 | * |
9655 | * Construct an isl_multi_union_pw_aff that is equal to "pma" |
9656 | * on the domain of "mupa". |
9657 | */ |
9658 | static __isl_give isl_multi_union_pw_aff *mupa_apply_pw_multi_aff_0D( |
9659 | __isl_take isl_multi_union_pw_aff *mupa, |
9660 | __isl_take isl_pw_multi_aff *pma) |
9661 | { |
9662 | isl_union_set *dom; |
9663 | |
9664 | dom = isl_multi_union_pw_aff_domain(mupa); |
9665 | pma = isl_pw_multi_aff_project_domain_on_params(pw: pma); |
9666 | |
9667 | return isl_multi_union_pw_aff_pw_multi_aff_on_domain(domain: dom, pma); |
9668 | } |
9669 | |
9670 | /* Apply "pma" to "mupa". The space of "mupa" needs to be compatible |
9671 | * with the domain of "pma". |
9672 | * The result is defined over the shared domain of the elements of "mupa" |
9673 | */ |
9674 | __isl_give isl_multi_union_pw_aff *isl_multi_union_pw_aff_apply_pw_multi_aff( |
9675 | __isl_take isl_multi_union_pw_aff *mupa, |
9676 | __isl_take isl_pw_multi_aff *pma) |
9677 | { |
9678 | isl_space *space1, *space2; |
9679 | isl_multi_union_pw_aff *res; |
9680 | isl_bool equal; |
9681 | int i; |
9682 | isl_size n_in, n_out; |
9683 | |
9684 | mupa = isl_multi_union_pw_aff_align_params(multi: mupa, |
9685 | model: isl_pw_multi_aff_get_space(pw: pma)); |
9686 | pma = isl_pw_multi_aff_align_params(pw: pma, |
9687 | model: isl_multi_union_pw_aff_get_space(multi: mupa)); |
9688 | if (!mupa || !pma) |
9689 | goto error; |
9690 | |
9691 | space1 = isl_multi_union_pw_aff_get_space(multi: mupa); |
9692 | space2 = isl_pw_multi_aff_get_domain_space(pw: pma); |
9693 | equal = isl_space_is_equal(space1, space2); |
9694 | isl_space_free(space: space1); |
9695 | isl_space_free(space: space2); |
9696 | if (equal < 0) |
9697 | goto error; |
9698 | if (!equal) |
9699 | isl_die(isl_pw_multi_aff_get_ctx(pma), isl_error_invalid, |
9700 | "spaces don't match" , goto error); |
9701 | n_in = isl_pw_multi_aff_dim(pw: pma, type: isl_dim_in); |
9702 | n_out = isl_pw_multi_aff_dim(pw: pma, type: isl_dim_out); |
9703 | if (n_in < 0 || n_out < 0) |
9704 | goto error; |
9705 | if (n_in == 0) |
9706 | return mupa_apply_pw_multi_aff_0D(mupa, pma); |
9707 | |
9708 | space1 = isl_space_range(space: isl_pw_multi_aff_get_space(pw: pma)); |
9709 | res = isl_multi_union_pw_aff_alloc(space: space1); |
9710 | |
9711 | for (i = 0; i < n_out; ++i) { |
9712 | isl_pw_aff *pa; |
9713 | isl_union_pw_aff *upa; |
9714 | |
9715 | pa = isl_pw_multi_aff_get_pw_aff(pma, pos: i); |
9716 | upa = isl_multi_union_pw_aff_apply_pw_aff( |
9717 | mupa: isl_multi_union_pw_aff_copy(multi: mupa), pa); |
9718 | res = isl_multi_union_pw_aff_set_union_pw_aff(multi: res, pos: i, el: upa); |
9719 | } |
9720 | |
9721 | isl_pw_multi_aff_free(pw: pma); |
9722 | isl_multi_union_pw_aff_free(multi: mupa); |
9723 | return res; |
9724 | error: |
9725 | isl_multi_union_pw_aff_free(multi: mupa); |
9726 | isl_pw_multi_aff_free(pw: pma); |
9727 | return NULL; |
9728 | } |
9729 | |
9730 | /* Replace the explicit domain of "mupa" by its preimage under "upma". |
9731 | * If the explicit domain only keeps track of constraints on the parameters, |
9732 | * then only update those constraints. |
9733 | */ |
9734 | static __isl_give isl_multi_union_pw_aff *preimage_explicit_domain( |
9735 | __isl_take isl_multi_union_pw_aff *mupa, |
9736 | __isl_keep isl_union_pw_multi_aff *upma) |
9737 | { |
9738 | isl_bool is_params; |
9739 | |
9740 | if (isl_multi_union_pw_aff_check_has_explicit_domain(multi: mupa) < 0) |
9741 | return isl_multi_union_pw_aff_free(multi: mupa); |
9742 | |
9743 | mupa = isl_multi_union_pw_aff_cow(multi: mupa); |
9744 | if (!mupa) |
9745 | return NULL; |
9746 | |
9747 | is_params = isl_union_set_is_params(uset: mupa->u.dom); |
9748 | if (is_params < 0) |
9749 | return isl_multi_union_pw_aff_free(multi: mupa); |
9750 | |
9751 | upma = isl_union_pw_multi_aff_copy(u: upma); |
9752 | if (is_params) |
9753 | mupa->u.dom = isl_union_set_intersect_params(uset: mupa->u.dom, |
9754 | set: isl_union_set_params(uset: isl_union_pw_multi_aff_domain(u: upma))); |
9755 | else |
9756 | mupa->u.dom = isl_union_set_preimage_union_pw_multi_aff( |
9757 | uset: mupa->u.dom, upma); |
9758 | if (!mupa->u.dom) |
9759 | return isl_multi_union_pw_aff_free(multi: mupa); |
9760 | return mupa; |
9761 | } |
9762 | |
9763 | /* Compute the pullback of "mupa" by the function represented by "upma". |
9764 | * In other words, plug in "upma" in "mupa". The result contains |
9765 | * expressions defined over the domain space of "upma". |
9766 | * |
9767 | * Run over all elements of "mupa" and plug in "upma" in each of them. |
9768 | * |
9769 | * If "mupa" has an explicit domain, then it is this domain |
9770 | * that needs to undergo a pullback instead, i.e., a preimage. |
9771 | */ |
9772 | __isl_give isl_multi_union_pw_aff * |
9773 | isl_multi_union_pw_aff_pullback_union_pw_multi_aff( |
9774 | __isl_take isl_multi_union_pw_aff *mupa, |
9775 | __isl_take isl_union_pw_multi_aff *upma) |
9776 | { |
9777 | int i; |
9778 | isl_size n; |
9779 | |
9780 | mupa = isl_multi_union_pw_aff_align_params(multi: mupa, |
9781 | model: isl_union_pw_multi_aff_get_space(u: upma)); |
9782 | upma = isl_union_pw_multi_aff_align_params(u: upma, |
9783 | model: isl_multi_union_pw_aff_get_space(multi: mupa)); |
9784 | mupa = isl_multi_union_pw_aff_cow(multi: mupa); |
9785 | n = isl_multi_union_pw_aff_dim(multi: mupa, type: isl_dim_set); |
9786 | if (n < 0 || !upma) |
9787 | goto error; |
9788 | |
9789 | for (i = 0; i < n; ++i) { |
9790 | isl_union_pw_aff *upa; |
9791 | |
9792 | upa = isl_multi_union_pw_aff_get_union_pw_aff(multi: mupa, pos: i); |
9793 | upa = isl_union_pw_aff_pullback_union_pw_multi_aff(upa, |
9794 | upma: isl_union_pw_multi_aff_copy(u: upma)); |
9795 | mupa = isl_multi_union_pw_aff_set_union_pw_aff(multi: mupa, pos: i, el: upa); |
9796 | } |
9797 | |
9798 | if (isl_multi_union_pw_aff_has_explicit_domain(multi: mupa)) |
9799 | mupa = preimage_explicit_domain(mupa, upma); |
9800 | |
9801 | isl_union_pw_multi_aff_free(u: upma); |
9802 | return mupa; |
9803 | error: |
9804 | isl_multi_union_pw_aff_free(multi: mupa); |
9805 | isl_union_pw_multi_aff_free(u: upma); |
9806 | return NULL; |
9807 | } |
9808 | |
9809 | /* Extract the sequence of elements in "mupa" with domain space "space" |
9810 | * (ignoring parameters). |
9811 | * |
9812 | * For the elements of "mupa" that are not defined on the specified space, |
9813 | * the corresponding element in the result is empty. |
9814 | */ |
9815 | __isl_give isl_multi_pw_aff *( |
9816 | __isl_keep isl_multi_union_pw_aff *mupa, __isl_take isl_space *space) |
9817 | { |
9818 | int i; |
9819 | isl_size n; |
9820 | isl_space *space_mpa; |
9821 | isl_multi_pw_aff *mpa; |
9822 | |
9823 | n = isl_multi_union_pw_aff_dim(multi: mupa, type: isl_dim_set); |
9824 | if (n < 0 || !space) |
9825 | goto error; |
9826 | |
9827 | space_mpa = isl_multi_union_pw_aff_get_space(multi: mupa); |
9828 | space = isl_space_replace_params(dst: space, src: space_mpa); |
9829 | space_mpa = isl_space_map_from_domain_and_range(domain: isl_space_copy(space), |
9830 | range: space_mpa); |
9831 | mpa = isl_multi_pw_aff_alloc(space: space_mpa); |
9832 | |
9833 | space = isl_space_from_domain(space); |
9834 | space = isl_space_add_dims(space, type: isl_dim_out, n: 1); |
9835 | for (i = 0; i < n; ++i) { |
9836 | isl_union_pw_aff *upa; |
9837 | isl_pw_aff *pa; |
9838 | |
9839 | upa = isl_multi_union_pw_aff_get_union_pw_aff(multi: mupa, pos: i); |
9840 | pa = isl_union_pw_aff_extract_pw_aff(u: upa, |
9841 | space: isl_space_copy(space)); |
9842 | mpa = isl_multi_pw_aff_set_pw_aff(multi: mpa, pos: i, el: pa); |
9843 | isl_union_pw_aff_free(u: upa); |
9844 | } |
9845 | |
9846 | isl_space_free(space); |
9847 | return mpa; |
9848 | error: |
9849 | isl_space_free(space); |
9850 | return NULL; |
9851 | } |
9852 | |
9853 | /* Data structure that specifies how isl_union_pw_multi_aff_un_op |
9854 | * should modify the base expressions in the input. |
9855 | * |
9856 | * If "filter" is not NULL, then only the base expressions that satisfy "filter" |
9857 | * are taken into account. |
9858 | * "fn" is applied to each entry in the input. |
9859 | */ |
9860 | struct isl_union_pw_multi_aff_un_op_control { |
9861 | isl_bool (*filter)(__isl_keep isl_pw_multi_aff *part); |
9862 | __isl_give isl_pw_multi_aff *(*fn)(__isl_take isl_pw_multi_aff *pma); |
9863 | }; |
9864 | |
9865 | /* Wrapper for isl_union_pw_multi_aff_un_op filter functions (which do not take |
9866 | * a second argument) for use as an isl_union_pw_multi_aff_transform |
9867 | * filter function (which does take a second argument). |
9868 | * Simply call control->filter without the second argument. |
9869 | */ |
9870 | static isl_bool isl_union_pw_multi_aff_un_op_filter_drop_user( |
9871 | __isl_take isl_pw_multi_aff *pma, void *user) |
9872 | { |
9873 | struct isl_union_pw_multi_aff_un_op_control *control = user; |
9874 | |
9875 | return control->filter(pma); |
9876 | } |
9877 | |
9878 | /* Wrapper for isl_union_pw_multi_aff_un_op base functions (which do not take |
9879 | * a second argument) for use as an isl_union_pw_multi_aff_transform |
9880 | * base function (which does take a second argument). |
9881 | * Simply call control->fn without the second argument. |
9882 | */ |
9883 | static __isl_give isl_pw_multi_aff *isl_union_pw_multi_aff_un_op_drop_user( |
9884 | __isl_take isl_pw_multi_aff *pma, void *user) |
9885 | { |
9886 | struct isl_union_pw_multi_aff_un_op_control *control = user; |
9887 | |
9888 | return control->fn(pma); |
9889 | } |
9890 | |
9891 | /* Construct an isl_union_pw_multi_aff that is obtained by |
9892 | * modifying "upma" according to "control". |
9893 | * |
9894 | * isl_union_pw_multi_aff_transform performs essentially |
9895 | * the same operation, but takes a filter and a callback function |
9896 | * of a different form (with an extra argument). |
9897 | * Call isl_union_pw_multi_aff_transform with wrappers |
9898 | * that remove this extra argument. |
9899 | */ |
9900 | static __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_un_op( |
9901 | __isl_take isl_union_pw_multi_aff *upma, |
9902 | struct isl_union_pw_multi_aff_un_op_control *control) |
9903 | { |
9904 | struct isl_union_pw_multi_aff_transform_control t_control = { |
9905 | .filter = &isl_union_pw_multi_aff_un_op_filter_drop_user, |
9906 | .filter_user = control, |
9907 | .fn = &isl_union_pw_multi_aff_un_op_drop_user, |
9908 | .fn_user = control, |
9909 | }; |
9910 | |
9911 | return isl_union_pw_multi_aff_transform(u: upma, control: &t_control); |
9912 | } |
9913 | |
9914 | /* For each function in "upma" of the form A -> [B -> C], |
9915 | * extract the function A -> B and collect the results. |
9916 | */ |
9917 | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_range_factor_domain( |
9918 | __isl_take isl_union_pw_multi_aff *upma) |
9919 | { |
9920 | struct isl_union_pw_multi_aff_un_op_control control = { |
9921 | .filter = &isl_pw_multi_aff_range_is_wrapping, |
9922 | .fn = &isl_pw_multi_aff_range_factor_domain, |
9923 | }; |
9924 | return isl_union_pw_multi_aff_un_op(upma, control: &control); |
9925 | } |
9926 | |
9927 | /* For each function in "upma" of the form A -> [B -> C], |
9928 | * extract the function A -> C and collect the results. |
9929 | */ |
9930 | __isl_give isl_union_pw_multi_aff *isl_union_pw_multi_aff_range_factor_range( |
9931 | __isl_take isl_union_pw_multi_aff *upma) |
9932 | { |
9933 | struct isl_union_pw_multi_aff_un_op_control control = { |
9934 | .filter = &isl_pw_multi_aff_range_is_wrapping, |
9935 | .fn = &isl_pw_multi_aff_range_factor_range, |
9936 | }; |
9937 | return isl_union_pw_multi_aff_un_op(upma, control: &control); |
9938 | } |
9939 | |
9940 | /* Evaluate the affine function "aff" in the void point "pnt". |
9941 | * In particular, return the value NaN. |
9942 | */ |
9943 | static __isl_give isl_val *eval_void(__isl_take isl_aff *aff, |
9944 | __isl_take isl_point *pnt) |
9945 | { |
9946 | isl_ctx *ctx; |
9947 | |
9948 | ctx = isl_point_get_ctx(pnt); |
9949 | isl_aff_free(aff); |
9950 | isl_point_free(pnt); |
9951 | return isl_val_nan(ctx); |
9952 | } |
9953 | |
9954 | /* Evaluate the affine expression "aff" |
9955 | * in the coordinates (with denominator) "pnt". |
9956 | */ |
9957 | static __isl_give isl_val *eval(__isl_keep isl_vec *aff, |
9958 | __isl_keep isl_vec *pnt) |
9959 | { |
9960 | isl_int n, d; |
9961 | isl_ctx *ctx; |
9962 | isl_val *v; |
9963 | |
9964 | if (!aff || !pnt) |
9965 | return NULL; |
9966 | |
9967 | ctx = isl_vec_get_ctx(vec: aff); |
9968 | isl_int_init(n); |
9969 | isl_int_init(d); |
9970 | isl_seq_inner_product(p1: aff->el + 1, p2: pnt->el, len: pnt->size, prod: &n); |
9971 | isl_int_mul(d, aff->el[0], pnt->el[0]); |
9972 | v = isl_val_rat_from_isl_int(ctx, n, d); |
9973 | v = isl_val_normalize(v); |
9974 | isl_int_clear(n); |
9975 | isl_int_clear(d); |
9976 | |
9977 | return v; |
9978 | } |
9979 | |
9980 | /* Check that the domain space of "aff" is equal to "space". |
9981 | */ |
9982 | static isl_stat isl_aff_check_has_domain_space(__isl_keep isl_aff *aff, |
9983 | __isl_keep isl_space *space) |
9984 | { |
9985 | isl_bool ok; |
9986 | |
9987 | ok = isl_space_is_equal(space1: isl_aff_peek_domain_space(aff), space2: space); |
9988 | if (ok < 0) |
9989 | return isl_stat_error; |
9990 | if (!ok) |
9991 | isl_die(isl_aff_get_ctx(aff), isl_error_invalid, |
9992 | "incompatible spaces" , return isl_stat_error); |
9993 | return isl_stat_ok; |
9994 | } |
9995 | |
9996 | /* Evaluate the affine function "aff" in "pnt". |
9997 | */ |
9998 | __isl_give isl_val *isl_aff_eval(__isl_take isl_aff *aff, |
9999 | __isl_take isl_point *pnt) |
10000 | { |
10001 | isl_bool is_void; |
10002 | isl_val *v; |
10003 | isl_local_space *ls; |
10004 | |
10005 | if (isl_aff_check_has_domain_space(aff, space: isl_point_peek_space(pnt)) < 0) |
10006 | goto error; |
10007 | is_void = isl_point_is_void(pnt); |
10008 | if (is_void < 0) |
10009 | goto error; |
10010 | if (is_void) |
10011 | return eval_void(aff, pnt); |
10012 | |
10013 | ls = isl_aff_get_domain_local_space(aff); |
10014 | pnt = isl_local_space_lift_point(ls, pnt); |
10015 | |
10016 | v = eval(aff: aff->v, pnt: isl_point_peek_vec(pnt)); |
10017 | |
10018 | isl_aff_free(aff); |
10019 | isl_point_free(pnt); |
10020 | |
10021 | return v; |
10022 | error: |
10023 | isl_aff_free(aff); |
10024 | isl_point_free(pnt); |
10025 | return NULL; |
10026 | } |
10027 | |