isl_local_space_divs_known: extract out isl_local_divs_known
[isl.git] / isl_local_space.c
blob2e96bf7bf0b49886c88e3fde1c9ce8435a3fd7a4
1 /*
2 * Copyright 2011 INRIA Saclay
3 * Copyright 2012-2014 Ecole Normale Superieure
5 * Use of this software is governed by the MIT license
7 * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
8 * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
9 * 91893 Orsay, France
10 * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
13 #include <isl_ctx_private.h>
14 #include <isl_map_private.h>
15 #include <isl_local_space_private.h>
16 #include <isl_space_private.h>
17 #include <isl_mat_private.h>
18 #include <isl_aff_private.h>
19 #include <isl_vec_private.h>
20 #include <isl_seq.h>
21 #include <isl_local.h>
23 isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls)
25 return ls ? ls->dim->ctx : NULL;
28 /* Return a hash value that digests "ls".
30 uint32_t isl_local_space_get_hash(__isl_keep isl_local_space *ls)
32 uint32_t hash, space_hash, div_hash;
34 if (!ls)
35 return 0;
37 hash = isl_hash_init();
38 space_hash = isl_space_get_hash(ls->dim);
39 isl_hash_hash(hash, space_hash);
40 div_hash = isl_mat_get_hash(ls->div);
41 isl_hash_hash(hash, div_hash);
43 return hash;
46 __isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_space *dim,
47 __isl_take isl_mat *div)
49 isl_ctx *ctx;
50 isl_local_space *ls = NULL;
52 if (!dim || !div)
53 goto error;
55 ctx = isl_space_get_ctx(dim);
56 ls = isl_calloc_type(ctx, struct isl_local_space);
57 if (!ls)
58 goto error;
60 ls->ref = 1;
61 ls->dim = dim;
62 ls->div = div;
64 return ls;
65 error:
66 isl_mat_free(div);
67 isl_space_free(dim);
68 isl_local_space_free(ls);
69 return NULL;
72 __isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *dim,
73 unsigned n_div)
75 isl_ctx *ctx;
76 isl_mat *div;
77 unsigned total;
79 if (!dim)
80 return NULL;
82 total = isl_space_dim(dim, isl_dim_all);
84 ctx = isl_space_get_ctx(dim);
85 div = isl_mat_alloc(ctx, n_div, 1 + 1 + total + n_div);
86 return isl_local_space_alloc_div(dim, div);
89 __isl_give isl_local_space *isl_local_space_from_space(__isl_take isl_space *dim)
91 return isl_local_space_alloc(dim, 0);
94 __isl_give isl_local_space *isl_local_space_copy(__isl_keep isl_local_space *ls)
96 if (!ls)
97 return NULL;
99 ls->ref++;
100 return ls;
103 __isl_give isl_local_space *isl_local_space_dup(__isl_keep isl_local_space *ls)
105 if (!ls)
106 return NULL;
108 return isl_local_space_alloc_div(isl_space_copy(ls->dim),
109 isl_mat_copy(ls->div));
113 __isl_give isl_local_space *isl_local_space_cow(__isl_take isl_local_space *ls)
115 if (!ls)
116 return NULL;
118 if (ls->ref == 1)
119 return ls;
120 ls->ref--;
121 return isl_local_space_dup(ls);
124 __isl_null isl_local_space *isl_local_space_free(
125 __isl_take isl_local_space *ls)
127 if (!ls)
128 return NULL;
130 if (--ls->ref > 0)
131 return NULL;
133 isl_space_free(ls->dim);
134 isl_mat_free(ls->div);
136 free(ls);
138 return NULL;
141 /* Is the local space that of a parameter domain?
143 isl_bool isl_local_space_is_params(__isl_keep isl_local_space *ls)
145 if (!ls)
146 return isl_bool_error;
147 return isl_space_is_params(ls->dim);
150 /* Is the local space that of a set?
152 isl_bool isl_local_space_is_set(__isl_keep isl_local_space *ls)
154 return ls ? isl_space_is_set(ls->dim) : isl_bool_error;
157 /* Do "ls1" and "ls2" have the same space?
159 isl_bool isl_local_space_has_equal_space(__isl_keep isl_local_space *ls1,
160 __isl_keep isl_local_space *ls2)
162 if (!ls1 || !ls2)
163 return isl_bool_error;
165 return isl_space_is_equal(ls1->dim, ls2->dim);
168 /* Return true if the two local spaces are identical, with identical
169 * expressions for the integer divisions.
171 isl_bool isl_local_space_is_equal(__isl_keep isl_local_space *ls1,
172 __isl_keep isl_local_space *ls2)
174 isl_bool equal;
176 equal = isl_local_space_has_equal_space(ls1, ls2);
177 if (equal < 0 || !equal)
178 return equal;
180 if (!isl_local_space_divs_known(ls1))
181 return isl_bool_false;
182 if (!isl_local_space_divs_known(ls2))
183 return isl_bool_false;
185 return isl_mat_is_equal(ls1->div, ls2->div);
188 /* Compare two isl_local_spaces.
190 * Return -1 if "ls1" is "smaller" than "ls2", 1 if "ls1" is "greater"
191 * than "ls2" and 0 if they are equal.
193 int isl_local_space_cmp(__isl_keep isl_local_space *ls1,
194 __isl_keep isl_local_space *ls2)
196 int cmp;
198 if (ls1 == ls2)
199 return 0;
200 if (!ls1)
201 return -1;
202 if (!ls2)
203 return 1;
205 cmp = isl_space_cmp(ls1->dim, ls2->dim);
206 if (cmp != 0)
207 return cmp;
209 return isl_local_cmp(ls1->div, ls2->div);
212 int isl_local_space_dim(__isl_keep isl_local_space *ls,
213 enum isl_dim_type type)
215 if (!ls)
216 return 0;
217 if (type == isl_dim_div)
218 return ls->div->n_row;
219 if (type == isl_dim_all)
220 return isl_space_dim(ls->dim, isl_dim_all) + ls->div->n_row;
221 return isl_space_dim(ls->dim, type);
224 unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
225 enum isl_dim_type type)
227 isl_space *dim;
229 if (!ls)
230 return 0;
232 dim = ls->dim;
233 switch (type) {
234 case isl_dim_cst: return 0;
235 case isl_dim_param: return 1;
236 case isl_dim_in: return 1 + dim->nparam;
237 case isl_dim_out: return 1 + dim->nparam + dim->n_in;
238 case isl_dim_div: return 1 + dim->nparam + dim->n_in + dim->n_out;
239 default: return 0;
243 /* Return the position of the dimension of the given type and name
244 * in "ls".
245 * Return -1 if no such dimension can be found.
247 int isl_local_space_find_dim_by_name(__isl_keep isl_local_space *ls,
248 enum isl_dim_type type, const char *name)
250 if (!ls)
251 return -1;
252 if (type == isl_dim_div)
253 return -1;
254 return isl_space_find_dim_by_name(ls->dim, type, name);
257 /* Does the given dimension have a name?
259 isl_bool isl_local_space_has_dim_name(__isl_keep isl_local_space *ls,
260 enum isl_dim_type type, unsigned pos)
262 return ls ? isl_space_has_dim_name(ls->dim, type, pos) : isl_bool_error;
265 const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
266 enum isl_dim_type type, unsigned pos)
268 return ls ? isl_space_get_dim_name(ls->dim, type, pos) : NULL;
271 isl_bool isl_local_space_has_dim_id(__isl_keep isl_local_space *ls,
272 enum isl_dim_type type, unsigned pos)
274 return ls ? isl_space_has_dim_id(ls->dim, type, pos) : isl_bool_error;
277 __isl_give isl_id *isl_local_space_get_dim_id(__isl_keep isl_local_space *ls,
278 enum isl_dim_type type, unsigned pos)
280 return ls ? isl_space_get_dim_id(ls->dim, type, pos) : NULL;
283 /* Return the argument of the integer division at position "pos" in "ls".
284 * All local variables in "ls" are known to have a (complete) explicit
285 * representation.
287 static __isl_give isl_aff *extract_div(__isl_keep isl_local_space *ls, int pos)
289 isl_aff *aff;
291 aff = isl_aff_alloc(isl_local_space_copy(ls));
292 if (!aff)
293 return NULL;
294 isl_seq_cpy(aff->v->el, ls->div->row[pos], aff->v->size);
295 return aff;
298 /* Return the argument of the integer division at position "pos" in "ls".
299 * The integer division at that position is known to have a complete
300 * explicit representation, but some of the others do not.
301 * Remove them first because the domain of an isl_aff
302 * is not allowed to have unknown local variables.
304 static __isl_give isl_aff *drop_unknown_divs_and_extract_div(
305 __isl_keep isl_local_space *ls, int pos)
307 int i, n;
308 isl_bool unknown;
309 isl_aff *aff;
311 ls = isl_local_space_copy(ls);
312 n = isl_local_space_dim(ls, isl_dim_div);
313 for (i = n - 1; i >= 0; --i) {
314 unknown = isl_local_space_div_is_marked_unknown(ls, i);
315 if (unknown < 0)
316 ls = isl_local_space_free(ls);
317 else if (!unknown)
318 continue;
319 ls = isl_local_space_drop_dims(ls, isl_dim_div, i, 1);
320 if (pos > i)
321 --pos;
323 aff = extract_div(ls, pos);
324 isl_local_space_free(ls);
325 return aff;
328 /* Return the argument of the integer division at position "pos" in "ls".
329 * The integer division is assumed to have a complete explicit
330 * representation. If some of the other integer divisions
331 * do not have an explicit representation, then they need
332 * to be removed first because the domain of an isl_aff
333 * is not allowed to have unknown local variables.
335 __isl_give isl_aff *isl_local_space_get_div(__isl_keep isl_local_space *ls,
336 int pos)
338 isl_bool known;
340 if (!ls)
341 return NULL;
343 if (pos < 0 || pos >= ls->div->n_row)
344 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
345 "index out of bounds", return NULL);
347 known = isl_local_space_div_is_known(ls, pos);
348 if (known < 0)
349 return NULL;
350 if (!known)
351 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
352 "expression of div unknown", return NULL);
353 if (!isl_local_space_is_set(ls))
354 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
355 "cannot represent divs of map spaces", return NULL);
357 known = isl_local_space_divs_known(ls);
358 if (known < 0)
359 return NULL;
360 if (known)
361 return extract_div(ls, pos);
362 else
363 return drop_unknown_divs_and_extract_div(ls, pos);
366 __isl_give isl_space *isl_local_space_get_space(__isl_keep isl_local_space *ls)
368 if (!ls)
369 return NULL;
371 return isl_space_copy(ls->dim);
374 /* Return the space of "ls".
375 * This may be either a copy or the space itself
376 * if there is only one reference to "ls".
377 * This allows the space to be modified inplace
378 * if both the local space and its space have only a single reference.
379 * The caller is not allowed to modify "ls" between this call and
380 * a subsequent call to isl_local_space_restore_space.
381 * The only exception is that isl_local_space_free can be called instead.
383 __isl_give isl_space *isl_local_space_take_space(__isl_keep isl_local_space *ls)
385 isl_space *space;
387 if (!ls)
388 return NULL;
389 if (ls->ref != 1)
390 return isl_local_space_get_space(ls);
391 space = ls->dim;
392 ls->dim = NULL;
393 return space;
396 /* Set the space of "ls" to "space", where the space of "ls" may be missing
397 * due to a preceding call to isl_local_space_take_space.
398 * However, in this case, "ls" only has a single reference and
399 * then the call to isl_local_space_cow has no effect.
401 __isl_give isl_local_space *isl_local_space_restore_space(
402 __isl_take isl_local_space *ls, __isl_take isl_space *space)
404 if (!ls || !space)
405 goto error;
407 if (ls->dim == space) {
408 isl_space_free(space);
409 return ls;
412 ls = isl_local_space_cow(ls);
413 if (!ls)
414 goto error;
415 isl_space_free(ls->dim);
416 ls->dim = space;
418 return ls;
419 error:
420 isl_local_space_free(ls);
421 isl_space_free(space);
422 return NULL;
425 /* Replace the identifier of the tuple of type "type" by "id".
427 __isl_give isl_local_space *isl_local_space_set_tuple_id(
428 __isl_take isl_local_space *ls,
429 enum isl_dim_type type, __isl_take isl_id *id)
431 ls = isl_local_space_cow(ls);
432 if (!ls)
433 goto error;
434 ls->dim = isl_space_set_tuple_id(ls->dim, type, id);
435 if (!ls->dim)
436 return isl_local_space_free(ls);
437 return ls;
438 error:
439 isl_id_free(id);
440 return NULL;
443 __isl_give isl_local_space *isl_local_space_set_dim_name(
444 __isl_take isl_local_space *ls,
445 enum isl_dim_type type, unsigned pos, const char *s)
447 ls = isl_local_space_cow(ls);
448 if (!ls)
449 return NULL;
450 ls->dim = isl_space_set_dim_name(ls->dim, type, pos, s);
451 if (!ls->dim)
452 return isl_local_space_free(ls);
454 return ls;
457 __isl_give isl_local_space *isl_local_space_set_dim_id(
458 __isl_take isl_local_space *ls,
459 enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
461 ls = isl_local_space_cow(ls);
462 if (!ls)
463 goto error;
464 ls->dim = isl_space_set_dim_id(ls->dim, type, pos, id);
465 if (!ls->dim)
466 return isl_local_space_free(ls);
468 return ls;
469 error:
470 isl_id_free(id);
471 return NULL;
474 /* Construct a zero-dimensional local space with the given parameter domain.
476 __isl_give isl_local_space *isl_local_space_set_from_params(
477 __isl_take isl_local_space *ls)
479 isl_space *space;
481 space = isl_local_space_take_space(ls);
482 space = isl_space_set_from_params(space);
483 ls = isl_local_space_restore_space(ls, space);
485 return ls;
488 __isl_give isl_local_space *isl_local_space_reset_space(
489 __isl_take isl_local_space *ls, __isl_take isl_space *dim)
491 ls = isl_local_space_cow(ls);
492 if (!ls || !dim)
493 goto error;
495 isl_space_free(ls->dim);
496 ls->dim = dim;
498 return ls;
499 error:
500 isl_local_space_free(ls);
501 isl_space_free(dim);
502 return NULL;
505 /* Reorder the columns of the given div definitions according to the
506 * given reordering.
507 * The order of the divs themselves is assumed not to change.
509 static __isl_give isl_mat *reorder_divs(__isl_take isl_mat *div,
510 __isl_take isl_reordering *r)
512 int i, j;
513 isl_mat *mat;
514 int extra;
516 if (!div || !r)
517 goto error;
519 extra = isl_space_dim(r->dim, isl_dim_all) + div->n_row - r->len;
520 mat = isl_mat_alloc(div->ctx, div->n_row, div->n_col + extra);
521 if (!mat)
522 goto error;
524 for (i = 0; i < div->n_row; ++i) {
525 isl_seq_cpy(mat->row[i], div->row[i], 2);
526 isl_seq_clr(mat->row[i] + 2, mat->n_col - 2);
527 for (j = 0; j < r->len; ++j)
528 isl_int_set(mat->row[i][2 + r->pos[j]],
529 div->row[i][2 + j]);
532 isl_reordering_free(r);
533 isl_mat_free(div);
534 return mat;
535 error:
536 isl_reordering_free(r);
537 isl_mat_free(div);
538 return NULL;
541 /* Reorder the dimensions of "ls" according to the given reordering.
542 * The reordering r is assumed to have been extended with the local
543 * variables, leaving them in the same order.
545 __isl_give isl_local_space *isl_local_space_realign(
546 __isl_take isl_local_space *ls, __isl_take isl_reordering *r)
548 ls = isl_local_space_cow(ls);
549 if (!ls || !r)
550 goto error;
552 ls->div = reorder_divs(ls->div, isl_reordering_copy(r));
553 if (!ls->div)
554 goto error;
556 ls = isl_local_space_reset_space(ls, isl_space_copy(r->dim));
558 isl_reordering_free(r);
559 return ls;
560 error:
561 isl_local_space_free(ls);
562 isl_reordering_free(r);
563 return NULL;
566 __isl_give isl_local_space *isl_local_space_add_div(
567 __isl_take isl_local_space *ls, __isl_take isl_vec *div)
569 ls = isl_local_space_cow(ls);
570 if (!ls || !div)
571 goto error;
573 if (ls->div->n_col != div->size)
574 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
575 "incompatible dimensions", goto error);
577 ls->div = isl_mat_add_zero_cols(ls->div, 1);
578 ls->div = isl_mat_add_rows(ls->div, 1);
579 if (!ls->div)
580 goto error;
582 isl_seq_cpy(ls->div->row[ls->div->n_row - 1], div->el, div->size);
583 isl_int_set_si(ls->div->row[ls->div->n_row - 1][div->size], 0);
585 isl_vec_free(div);
586 return ls;
587 error:
588 isl_local_space_free(ls);
589 isl_vec_free(div);
590 return NULL;
593 __isl_give isl_local_space *isl_local_space_replace_divs(
594 __isl_take isl_local_space *ls, __isl_take isl_mat *div)
596 ls = isl_local_space_cow(ls);
598 if (!ls || !div)
599 goto error;
601 isl_mat_free(ls->div);
602 ls->div = div;
603 return ls;
604 error:
605 isl_mat_free(div);
606 isl_local_space_free(ls);
607 return NULL;
610 /* Copy row "s" of "src" to row "d" of "dst", applying the expansion
611 * defined by "exp".
613 static void expand_row(__isl_keep isl_mat *dst, int d,
614 __isl_keep isl_mat *src, int s, int *exp)
616 int i;
617 unsigned c = src->n_col - src->n_row;
619 isl_seq_cpy(dst->row[d], src->row[s], c);
620 isl_seq_clr(dst->row[d] + c, dst->n_col - c);
622 for (i = 0; i < s; ++i)
623 isl_int_set(dst->row[d][c + exp[i]], src->row[s][c + i]);
626 /* Compare (known) divs.
627 * Return non-zero if at least one of the two divs is unknown.
628 * In particular, if both divs are unknown, we respect their
629 * current order. Otherwise, we sort the known div after the unknown
630 * div only if the known div depends on the unknown div.
632 static int cmp_row(isl_int *row_i, isl_int *row_j, int i, int j,
633 unsigned n_row, unsigned n_col)
635 int li, lj;
636 int unknown_i, unknown_j;
638 unknown_i = isl_int_is_zero(row_i[0]);
639 unknown_j = isl_int_is_zero(row_j[0]);
641 if (unknown_i && unknown_j)
642 return i - j;
644 if (unknown_i)
645 li = n_col - n_row + i;
646 else
647 li = isl_seq_last_non_zero(row_i, n_col);
648 if (unknown_j)
649 lj = n_col - n_row + j;
650 else
651 lj = isl_seq_last_non_zero(row_j, n_col);
653 if (li != lj)
654 return li - lj;
656 return isl_seq_cmp(row_i, row_j, n_col);
659 /* Call cmp_row for divs in a matrix.
661 int isl_mat_cmp_div(__isl_keep isl_mat *div, int i, int j)
663 return cmp_row(div->row[i], div->row[j], i, j, div->n_row, div->n_col);
666 /* Call cmp_row for divs in a basic map.
668 static int bmap_cmp_row(__isl_keep isl_basic_map *bmap, int i, int j,
669 unsigned total)
671 return cmp_row(bmap->div[i], bmap->div[j], i, j, bmap->n_div, total);
674 /* Sort the divs in "bmap".
676 * We first make sure divs are placed after divs on which they depend.
677 * Then we perform a simple insertion sort based on the same ordering
678 * that is used in isl_merge_divs.
680 __isl_give isl_basic_map *isl_basic_map_sort_divs(
681 __isl_take isl_basic_map *bmap)
683 int i, j;
684 unsigned total;
686 bmap = isl_basic_map_order_divs(bmap);
687 if (!bmap)
688 return NULL;
689 if (bmap->n_div <= 1)
690 return bmap;
692 total = 2 + isl_basic_map_total_dim(bmap);
693 for (i = 1; i < bmap->n_div; ++i) {
694 for (j = i - 1; j >= 0; --j) {
695 if (bmap_cmp_row(bmap, j, j + 1, total) <= 0)
696 break;
697 isl_basic_map_swap_div(bmap, j, j + 1);
701 return bmap;
704 /* Sort the divs in the basic maps of "map".
706 __isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map)
708 return isl_map_inline_foreach_basic_map(map, &isl_basic_map_sort_divs);
711 /* Combine the two lists of divs into a single list.
712 * For each row i in div1, exp1[i] is set to the position of the corresponding
713 * row in the result. Similarly for div2 and exp2.
714 * This function guarantees
715 * exp1[i] >= i
716 * exp1[i+1] > exp1[i]
717 * For optimal merging, the two input list should have been sorted.
719 __isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
720 __isl_keep isl_mat *div2, int *exp1, int *exp2)
722 int i, j, k;
723 isl_mat *div = NULL;
724 unsigned d;
726 if (!div1 || !div2)
727 return NULL;
729 d = div1->n_col - div1->n_row;
730 div = isl_mat_alloc(div1->ctx, 1 + div1->n_row + div2->n_row,
731 d + div1->n_row + div2->n_row);
732 if (!div)
733 return NULL;
735 for (i = 0, j = 0, k = 0; i < div1->n_row && j < div2->n_row; ++k) {
736 int cmp;
738 expand_row(div, k, div1, i, exp1);
739 expand_row(div, k + 1, div2, j, exp2);
741 cmp = isl_mat_cmp_div(div, k, k + 1);
742 if (cmp == 0) {
743 exp1[i++] = k;
744 exp2[j++] = k;
745 } else if (cmp < 0) {
746 exp1[i++] = k;
747 } else {
748 exp2[j++] = k;
749 isl_seq_cpy(div->row[k], div->row[k + 1], div->n_col);
752 for (; i < div1->n_row; ++i, ++k) {
753 expand_row(div, k, div1, i, exp1);
754 exp1[i] = k;
756 for (; j < div2->n_row; ++j, ++k) {
757 expand_row(div, k, div2, j, exp2);
758 exp2[j] = k;
761 div->n_row = k;
762 div->n_col = d + k;
764 return div;
767 /* Swap divs "a" and "b" in "ls".
769 __isl_give isl_local_space *isl_local_space_swap_div(
770 __isl_take isl_local_space *ls, int a, int b)
772 int offset;
774 ls = isl_local_space_cow(ls);
775 if (!ls)
776 return NULL;
777 if (a < 0 || a >= ls->div->n_row || b < 0 || b >= ls->div->n_row)
778 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
779 "index out of bounds", return isl_local_space_free(ls));
780 offset = ls->div->n_col - ls->div->n_row;
781 ls->div = isl_mat_swap_cols(ls->div, offset + a, offset + b);
782 ls->div = isl_mat_swap_rows(ls->div, a, b);
783 if (!ls->div)
784 return isl_local_space_free(ls);
785 return ls;
788 /* Construct a local space that contains all the divs in either
789 * "ls1" or "ls2".
791 __isl_give isl_local_space *isl_local_space_intersect(
792 __isl_take isl_local_space *ls1, __isl_take isl_local_space *ls2)
794 isl_ctx *ctx;
795 int *exp1 = NULL;
796 int *exp2 = NULL;
797 isl_mat *div = NULL;
798 isl_bool equal;
800 if (!ls1 || !ls2)
801 goto error;
803 ctx = isl_local_space_get_ctx(ls1);
804 if (!isl_space_is_equal(ls1->dim, ls2->dim))
805 isl_die(ctx, isl_error_invalid,
806 "spaces should be identical", goto error);
808 if (ls2->div->n_row == 0) {
809 isl_local_space_free(ls2);
810 return ls1;
813 if (ls1->div->n_row == 0) {
814 isl_local_space_free(ls1);
815 return ls2;
818 exp1 = isl_alloc_array(ctx, int, ls1->div->n_row);
819 exp2 = isl_alloc_array(ctx, int, ls2->div->n_row);
820 if (!exp1 || !exp2)
821 goto error;
823 div = isl_merge_divs(ls1->div, ls2->div, exp1, exp2);
824 if (!div)
825 goto error;
827 equal = isl_mat_is_equal(ls1->div, div);
828 if (equal < 0)
829 goto error;
830 if (!equal)
831 ls1 = isl_local_space_cow(ls1);
832 if (!ls1)
833 goto error;
835 free(exp1);
836 free(exp2);
837 isl_local_space_free(ls2);
838 isl_mat_free(ls1->div);
839 ls1->div = div;
841 return ls1;
842 error:
843 free(exp1);
844 free(exp2);
845 isl_mat_free(div);
846 isl_local_space_free(ls1);
847 isl_local_space_free(ls2);
848 return NULL;
851 /* Is the local variable "div" of "ls" marked as not having
852 * an explicit representation?
853 * Note that even if this variable is not marked in this way and therefore
854 * does have an explicit representation, this representation may still
855 * depend (indirectly) on other local variables that do not
856 * have an explicit representation.
858 isl_bool isl_local_space_div_is_marked_unknown(__isl_keep isl_local_space *ls,
859 int div)
861 if (!ls)
862 return isl_bool_error;
863 return isl_local_div_is_marked_unknown(ls->div, div);
866 /* Does "ls" have a complete explicit representation for div "div"?
868 isl_bool isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div)
870 if (!ls)
871 return isl_bool_error;
872 return isl_local_div_is_known(ls->div, div);
875 /* Does "ls" have an explicit representation for all local variables?
877 isl_bool isl_local_space_divs_known(__isl_keep isl_local_space *ls)
879 if (!ls)
880 return isl_bool_error;
881 return isl_local_divs_known(ls->div);
884 __isl_give isl_local_space *isl_local_space_domain(
885 __isl_take isl_local_space *ls)
887 ls = isl_local_space_drop_dims(ls, isl_dim_out,
888 0, isl_local_space_dim(ls, isl_dim_out));
889 ls = isl_local_space_cow(ls);
890 if (!ls)
891 return NULL;
892 ls->dim = isl_space_domain(ls->dim);
893 if (!ls->dim)
894 return isl_local_space_free(ls);
895 return ls;
898 __isl_give isl_local_space *isl_local_space_range(
899 __isl_take isl_local_space *ls)
901 ls = isl_local_space_drop_dims(ls, isl_dim_in,
902 0, isl_local_space_dim(ls, isl_dim_in));
903 ls = isl_local_space_cow(ls);
904 if (!ls)
905 return NULL;
907 ls->dim = isl_space_range(ls->dim);
908 if (!ls->dim)
909 return isl_local_space_free(ls);
910 return ls;
913 /* Construct a local space for a map that has the given local
914 * space as domain and that has a zero-dimensional range.
916 __isl_give isl_local_space *isl_local_space_from_domain(
917 __isl_take isl_local_space *ls)
919 ls = isl_local_space_cow(ls);
920 if (!ls)
921 return NULL;
922 ls->dim = isl_space_from_domain(ls->dim);
923 if (!ls->dim)
924 return isl_local_space_free(ls);
925 return ls;
928 __isl_give isl_local_space *isl_local_space_add_dims(
929 __isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n)
931 int pos;
933 if (!ls)
934 return NULL;
935 pos = isl_local_space_dim(ls, type);
936 return isl_local_space_insert_dims(ls, type, pos, n);
939 /* Remove common factor of non-constant terms and denominator.
941 static void normalize_div(__isl_keep isl_local_space *ls, int div)
943 isl_ctx *ctx = ls->div->ctx;
944 unsigned total = ls->div->n_col - 2;
946 isl_seq_gcd(ls->div->row[div] + 2, total, &ctx->normalize_gcd);
947 isl_int_gcd(ctx->normalize_gcd,
948 ctx->normalize_gcd, ls->div->row[div][0]);
949 if (isl_int_is_one(ctx->normalize_gcd))
950 return;
952 isl_seq_scale_down(ls->div->row[div] + 2, ls->div->row[div] + 2,
953 ctx->normalize_gcd, total);
954 isl_int_divexact(ls->div->row[div][0], ls->div->row[div][0],
955 ctx->normalize_gcd);
956 isl_int_fdiv_q(ls->div->row[div][1], ls->div->row[div][1],
957 ctx->normalize_gcd);
960 /* Exploit the equalities in "eq" to simplify the expressions of
961 * the integer divisions in "ls".
962 * The integer divisions in "ls" are assumed to appear as regular
963 * dimensions in "eq".
965 __isl_give isl_local_space *isl_local_space_substitute_equalities(
966 __isl_take isl_local_space *ls, __isl_take isl_basic_set *eq)
968 int i, j, k;
969 unsigned total;
970 unsigned n_div;
972 if (!ls || !eq)
973 goto error;
975 total = isl_space_dim(eq->dim, isl_dim_all);
976 if (isl_local_space_dim(ls, isl_dim_all) != total)
977 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
978 "spaces don't match", goto error);
979 total++;
980 n_div = eq->n_div;
981 for (i = 0; i < eq->n_eq; ++i) {
982 j = isl_seq_last_non_zero(eq->eq[i], total + n_div);
983 if (j < 0 || j == 0 || j >= total)
984 continue;
986 for (k = 0; k < ls->div->n_row; ++k) {
987 if (isl_int_is_zero(ls->div->row[k][1 + j]))
988 continue;
989 ls = isl_local_space_cow(ls);
990 if (!ls)
991 goto error;
992 ls->div = isl_mat_cow(ls->div);
993 if (!ls->div)
994 goto error;
995 isl_seq_elim(ls->div->row[k] + 1, eq->eq[i], j, total,
996 &ls->div->row[k][0]);
997 normalize_div(ls, k);
1001 isl_basic_set_free(eq);
1002 return ls;
1003 error:
1004 isl_basic_set_free(eq);
1005 isl_local_space_free(ls);
1006 return NULL;
1009 /* Plug in the affine expressions "subs" of length "subs_len" (including
1010 * the denominator and the constant term) into the variable at position "pos"
1011 * of the "n" div expressions starting at "first".
1013 * Let i be the dimension to replace and let "subs" be of the form
1015 * f/d
1017 * Any integer division starting at "first" with a non-zero coefficient for i,
1019 * floor((a i + g)/m)
1021 * is replaced by
1023 * floor((a f + d g)/(m d))
1025 __isl_give isl_local_space *isl_local_space_substitute_seq(
1026 __isl_take isl_local_space *ls,
1027 enum isl_dim_type type, unsigned pos, isl_int *subs, int subs_len,
1028 int first, int n)
1030 int i;
1031 isl_int v;
1033 if (n == 0)
1034 return ls;
1035 ls = isl_local_space_cow(ls);
1036 if (!ls)
1037 return NULL;
1038 ls->div = isl_mat_cow(ls->div);
1039 if (!ls->div)
1040 return isl_local_space_free(ls);
1042 if (first + n > ls->div->n_row)
1043 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1044 "index out of bounds", return isl_local_space_free(ls));
1046 pos += isl_local_space_offset(ls, type);
1048 isl_int_init(v);
1049 for (i = first; i < first + n; ++i) {
1050 if (isl_int_is_zero(ls->div->row[i][1 + pos]))
1051 continue;
1052 isl_seq_substitute(ls->div->row[i], pos, subs,
1053 ls->div->n_col, subs_len, v);
1054 normalize_div(ls, i);
1056 isl_int_clear(v);
1058 return ls;
1061 /* Plug in "subs" for dimension "type", "pos" in the integer divisions
1062 * of "ls".
1064 * Let i be the dimension to replace and let "subs" be of the form
1066 * f/d
1068 * Any integer division with a non-zero coefficient for i,
1070 * floor((a i + g)/m)
1072 * is replaced by
1074 * floor((a f + d g)/(m d))
1076 __isl_give isl_local_space *isl_local_space_substitute(
1077 __isl_take isl_local_space *ls,
1078 enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
1080 ls = isl_local_space_cow(ls);
1081 if (!ls || !subs)
1082 return isl_local_space_free(ls);
1084 if (!isl_space_is_equal(ls->dim, subs->ls->dim))
1085 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1086 "spaces don't match", return isl_local_space_free(ls));
1087 if (isl_local_space_dim(subs->ls, isl_dim_div) != 0)
1088 isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
1089 "cannot handle divs yet",
1090 return isl_local_space_free(ls));
1092 return isl_local_space_substitute_seq(ls, type, pos, subs->v->el,
1093 subs->v->size, 0, ls->div->n_row);
1096 isl_bool isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls,
1097 enum isl_dim_type type)
1099 if (!ls)
1100 return isl_bool_error;
1101 return isl_space_is_named_or_nested(ls->dim, type);
1104 __isl_give isl_local_space *isl_local_space_drop_dims(
1105 __isl_take isl_local_space *ls,
1106 enum isl_dim_type type, unsigned first, unsigned n)
1108 isl_ctx *ctx;
1110 if (!ls)
1111 return NULL;
1112 if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
1113 return ls;
1115 ctx = isl_local_space_get_ctx(ls);
1116 if (first + n > isl_local_space_dim(ls, type))
1117 isl_die(ctx, isl_error_invalid, "range out of bounds",
1118 return isl_local_space_free(ls));
1120 ls = isl_local_space_cow(ls);
1121 if (!ls)
1122 return NULL;
1124 if (type == isl_dim_div) {
1125 ls->div = isl_mat_drop_rows(ls->div, first, n);
1126 } else {
1127 ls->dim = isl_space_drop_dims(ls->dim, type, first, n);
1128 if (!ls->dim)
1129 return isl_local_space_free(ls);
1132 first += 1 + isl_local_space_offset(ls, type);
1133 ls->div = isl_mat_drop_cols(ls->div, first, n);
1134 if (!ls->div)
1135 return isl_local_space_free(ls);
1137 return ls;
1140 __isl_give isl_local_space *isl_local_space_insert_dims(
1141 __isl_take isl_local_space *ls,
1142 enum isl_dim_type type, unsigned first, unsigned n)
1144 isl_ctx *ctx;
1146 if (!ls)
1147 return NULL;
1148 if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
1149 return ls;
1151 ctx = isl_local_space_get_ctx(ls);
1152 if (first > isl_local_space_dim(ls, type))
1153 isl_die(ctx, isl_error_invalid, "position out of bounds",
1154 return isl_local_space_free(ls));
1156 ls = isl_local_space_cow(ls);
1157 if (!ls)
1158 return NULL;
1160 if (type == isl_dim_div) {
1161 ls->div = isl_mat_insert_zero_rows(ls->div, first, n);
1162 } else {
1163 ls->dim = isl_space_insert_dims(ls->dim, type, first, n);
1164 if (!ls->dim)
1165 return isl_local_space_free(ls);
1168 first += 1 + isl_local_space_offset(ls, type);
1169 ls->div = isl_mat_insert_zero_cols(ls->div, first, n);
1170 if (!ls->div)
1171 return isl_local_space_free(ls);
1173 return ls;
1176 /* Check if the constraints pointed to by "constraint" is a div
1177 * constraint corresponding to div "div" in "ls".
1179 * That is, if div = floor(f/m), then check if the constraint is
1181 * f - m d >= 0
1182 * or
1183 * -(f-(m-1)) + m d >= 0
1185 isl_bool isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls,
1186 isl_int *constraint, unsigned div)
1188 unsigned pos;
1190 if (!ls)
1191 return isl_bool_error;
1193 if (isl_int_is_zero(ls->div->row[div][0]))
1194 return isl_bool_false;
1196 pos = isl_local_space_offset(ls, isl_dim_div) + div;
1198 if (isl_int_eq(constraint[pos], ls->div->row[div][0])) {
1199 int neg;
1200 isl_int_sub(ls->div->row[div][1],
1201 ls->div->row[div][1], ls->div->row[div][0]);
1202 isl_int_add_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
1203 neg = isl_seq_is_neg(constraint, ls->div->row[div]+1, pos);
1204 isl_int_sub_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
1205 isl_int_add(ls->div->row[div][1],
1206 ls->div->row[div][1], ls->div->row[div][0]);
1207 if (!neg)
1208 return isl_bool_false;
1209 if (isl_seq_first_non_zero(constraint+pos+1,
1210 ls->div->n_row-div-1) != -1)
1211 return isl_bool_false;
1212 } else if (isl_int_abs_eq(constraint[pos], ls->div->row[div][0])) {
1213 if (!isl_seq_eq(constraint, ls->div->row[div]+1, pos))
1214 return isl_bool_false;
1215 if (isl_seq_first_non_zero(constraint+pos+1,
1216 ls->div->n_row-div-1) != -1)
1217 return isl_bool_false;
1218 } else
1219 return isl_bool_false;
1221 return isl_bool_true;
1225 * Set active[i] to 1 if the dimension at position i is involved
1226 * in the linear expression l.
1228 int *isl_local_space_get_active(__isl_keep isl_local_space *ls, isl_int *l)
1230 int i, j;
1231 isl_ctx *ctx;
1232 int *active = NULL;
1233 unsigned total;
1234 unsigned offset;
1236 ctx = isl_local_space_get_ctx(ls);
1237 total = isl_local_space_dim(ls, isl_dim_all);
1238 active = isl_calloc_array(ctx, int, total);
1239 if (total && !active)
1240 return NULL;
1242 for (i = 0; i < total; ++i)
1243 active[i] = !isl_int_is_zero(l[i]);
1245 offset = isl_local_space_offset(ls, isl_dim_div) - 1;
1246 for (i = ls->div->n_row - 1; i >= 0; --i) {
1247 if (!active[offset + i])
1248 continue;
1249 for (j = 0; j < total; ++j)
1250 active[j] |= !isl_int_is_zero(ls->div->row[i][2 + j]);
1253 return active;
1256 /* Given a local space "ls" of a set, create a local space
1257 * for the lift of the set. In particular, the result
1258 * is of the form [dim -> local[..]], with ls->div->n_row variables in the
1259 * range of the wrapped map.
1261 __isl_give isl_local_space *isl_local_space_lift(
1262 __isl_take isl_local_space *ls)
1264 ls = isl_local_space_cow(ls);
1265 if (!ls)
1266 return NULL;
1268 ls->dim = isl_space_lift(ls->dim, ls->div->n_row);
1269 ls->div = isl_mat_drop_rows(ls->div, 0, ls->div->n_row);
1270 if (!ls->dim || !ls->div)
1271 return isl_local_space_free(ls);
1273 return ls;
1276 /* Construct a basic map that maps a set living in local space "ls"
1277 * to the corresponding lifted local space.
1279 __isl_give isl_basic_map *isl_local_space_lifting(
1280 __isl_take isl_local_space *ls)
1282 isl_basic_map *lifting;
1283 isl_basic_set *bset;
1285 if (!ls)
1286 return NULL;
1287 if (!isl_local_space_is_set(ls))
1288 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1289 "lifting only defined on set spaces", goto error);
1291 bset = isl_basic_set_from_local_space(ls);
1292 lifting = isl_basic_set_unwrap(isl_basic_set_lift(bset));
1293 lifting = isl_basic_map_domain_map(lifting);
1294 lifting = isl_basic_map_reverse(lifting);
1296 return lifting;
1297 error:
1298 isl_local_space_free(ls);
1299 return NULL;
1302 /* Compute the preimage of "ls" under the function represented by "ma".
1303 * In other words, plug in "ma" in "ls". The result is a local space
1304 * that is part of the domain space of "ma".
1306 * If the divs in "ls" are represented as
1308 * floor((a_i(p) + b_i x + c_i(divs))/n_i)
1310 * and ma is represented by
1312 * x = D(p) + F(y) + G(divs')
1314 * then the resulting divs are
1316 * floor((a_i(p) + b_i D(p) + b_i F(y) + B_i G(divs') + c_i(divs))/n_i)
1318 * We first copy over the divs from "ma" and then
1319 * we add the modified divs from "ls".
1321 __isl_give isl_local_space *isl_local_space_preimage_multi_aff(
1322 __isl_take isl_local_space *ls, __isl_take isl_multi_aff *ma)
1324 int i;
1325 isl_space *space;
1326 isl_local_space *res = NULL;
1327 int n_div_ls, n_div_ma;
1328 isl_int f, c1, c2, g;
1330 ma = isl_multi_aff_align_divs(ma);
1331 if (!ls || !ma)
1332 goto error;
1333 if (!isl_space_is_range_internal(ls->dim, ma->space))
1334 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1335 "spaces don't match", goto error);
1337 n_div_ls = isl_local_space_dim(ls, isl_dim_div);
1338 n_div_ma = ma->n ? isl_aff_dim(ma->u.p[0], isl_dim_div) : 0;
1340 space = isl_space_domain(isl_multi_aff_get_space(ma));
1341 res = isl_local_space_alloc(space, n_div_ma + n_div_ls);
1342 if (!res)
1343 goto error;
1345 if (n_div_ma) {
1346 isl_mat_free(res->div);
1347 res->div = isl_mat_copy(ma->u.p[0]->ls->div);
1348 res->div = isl_mat_add_zero_cols(res->div, n_div_ls);
1349 res->div = isl_mat_add_rows(res->div, n_div_ls);
1350 if (!res->div)
1351 goto error;
1354 isl_int_init(f);
1355 isl_int_init(c1);
1356 isl_int_init(c2);
1357 isl_int_init(g);
1359 for (i = 0; i < ls->div->n_row; ++i) {
1360 if (isl_int_is_zero(ls->div->row[i][0])) {
1361 isl_int_set_si(res->div->row[n_div_ma + i][0], 0);
1362 continue;
1364 isl_seq_preimage(res->div->row[n_div_ma + i], ls->div->row[i],
1365 ma, 0, 0, n_div_ma, n_div_ls, f, c1, c2, g, 1);
1366 normalize_div(res, n_div_ma + i);
1369 isl_int_clear(f);
1370 isl_int_clear(c1);
1371 isl_int_clear(c2);
1372 isl_int_clear(g);
1374 isl_local_space_free(ls);
1375 isl_multi_aff_free(ma);
1376 return res;
1377 error:
1378 isl_local_space_free(ls);
1379 isl_multi_aff_free(ma);
1380 isl_local_space_free(res);
1381 return NULL;
1384 /* Move the "n" dimensions of "src_type" starting at "src_pos" of "ls"
1385 * to dimensions of "dst_type" at "dst_pos".
1387 * Moving to/from local dimensions is not allowed.
1388 * We currently assume that the dimension type changes.
1390 __isl_give isl_local_space *isl_local_space_move_dims(
1391 __isl_take isl_local_space *ls,
1392 enum isl_dim_type dst_type, unsigned dst_pos,
1393 enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1395 unsigned g_dst_pos;
1396 unsigned g_src_pos;
1398 if (!ls)
1399 return NULL;
1400 if (n == 0 &&
1401 !isl_local_space_is_named_or_nested(ls, src_type) &&
1402 !isl_local_space_is_named_or_nested(ls, dst_type))
1403 return ls;
1405 if (src_pos + n > isl_local_space_dim(ls, src_type))
1406 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1407 "range out of bounds", return isl_local_space_free(ls));
1408 if (dst_pos > isl_local_space_dim(ls, dst_type))
1409 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1410 "position out of bounds",
1411 return isl_local_space_free(ls));
1412 if (src_type == isl_dim_div)
1413 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1414 "cannot move divs", return isl_local_space_free(ls));
1415 if (dst_type == isl_dim_div)
1416 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1417 "cannot move to divs", return isl_local_space_free(ls));
1418 if (dst_type == src_type && dst_pos == src_pos)
1419 return ls;
1420 if (dst_type == src_type)
1421 isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
1422 "moving dims within the same type not supported",
1423 return isl_local_space_free(ls));
1425 ls = isl_local_space_cow(ls);
1426 if (!ls)
1427 return NULL;
1429 g_src_pos = 1 + isl_local_space_offset(ls, src_type) + src_pos;
1430 g_dst_pos = 1 + isl_local_space_offset(ls, dst_type) + dst_pos;
1431 if (dst_type > src_type)
1432 g_dst_pos -= n;
1433 ls->div = isl_mat_move_cols(ls->div, g_dst_pos, g_src_pos, n);
1434 if (!ls->div)
1435 return isl_local_space_free(ls);
1436 ls->dim = isl_space_move_dims(ls->dim, dst_type, dst_pos,
1437 src_type, src_pos, n);
1438 if (!ls->dim)
1439 return isl_local_space_free(ls);
1441 return ls;
1444 /* Remove any internal structure of the domain of "ls".
1445 * If there is any such internal structure in the input,
1446 * then the name of the corresponding space is also removed.
1448 __isl_give isl_local_space *isl_local_space_flatten_domain(
1449 __isl_take isl_local_space *ls)
1451 if (!ls)
1452 return NULL;
1454 if (!ls->dim->nested[0])
1455 return ls;
1457 ls = isl_local_space_cow(ls);
1458 if (!ls)
1459 return NULL;
1461 ls->dim = isl_space_flatten_domain(ls->dim);
1462 if (!ls->dim)
1463 return isl_local_space_free(ls);
1465 return ls;
1468 /* Remove any internal structure of the range of "ls".
1469 * If there is any such internal structure in the input,
1470 * then the name of the corresponding space is also removed.
1472 __isl_give isl_local_space *isl_local_space_flatten_range(
1473 __isl_take isl_local_space *ls)
1475 if (!ls)
1476 return NULL;
1478 if (!ls->dim->nested[1])
1479 return ls;
1481 ls = isl_local_space_cow(ls);
1482 if (!ls)
1483 return NULL;
1485 ls->dim = isl_space_flatten_range(ls->dim);
1486 if (!ls->dim)
1487 return isl_local_space_free(ls);
1489 return ls;
1492 /* Given the local space "ls" of a map, return the local space of a set
1493 * that lives in a space that wraps the space of "ls" and that has
1494 * the same divs.
1496 __isl_give isl_local_space *isl_local_space_wrap(__isl_take isl_local_space *ls)
1498 ls = isl_local_space_cow(ls);
1499 if (!ls)
1500 return NULL;
1502 ls->dim = isl_space_wrap(ls->dim);
1503 if (!ls->dim)
1504 return isl_local_space_free(ls);
1506 return ls;