1 /*
2  * Copyright 2011      INRIA Saclay
3  * Copyright 2012-2014 Ecole Normale Superieure
4  *
5  * Use of this software is governed by the MIT license
6  *
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
11  */
12 
13 #include <isl_ctx_private.h>
14 #include <isl/id.h>
15 #include <isl_map_private.h>
16 #include <isl_local_space_private.h>
17 #include <isl_space_private.h>
18 #include <isl_mat_private.h>
19 #include <isl_aff_private.h>
20 #include <isl_vec_private.h>
21 #include <isl_point_private.h>
22 #include <isl_seq.h>
23 #include <isl_local.h>
24 
isl_local_space_get_ctx(__isl_keep isl_local_space * ls)25 isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls)
26 {
27 	return ls ? ls->dim->ctx : NULL;
28 }
29 
30 /* Return a hash value that digests "ls".
31  */
isl_local_space_get_hash(__isl_keep isl_local_space * ls)32 uint32_t isl_local_space_get_hash(__isl_keep isl_local_space *ls)
33 {
34 	uint32_t hash, space_hash, div_hash;
35 
36 	if (!ls)
37 		return 0;
38 
39 	hash = isl_hash_init();
40 	space_hash = isl_space_get_full_hash(isl_local_space_peek_space(ls));
41 	isl_hash_hash(hash, space_hash);
42 	div_hash = isl_mat_get_hash(ls->div);
43 	isl_hash_hash(hash, div_hash);
44 
45 	return hash;
46 }
47 
isl_local_space_alloc_div(__isl_take isl_space * space,__isl_take isl_mat * div)48 __isl_give isl_local_space *isl_local_space_alloc_div(
49 	__isl_take isl_space *space, __isl_take isl_mat *div)
50 {
51 	isl_ctx *ctx;
52 	isl_local_space *ls = NULL;
53 
54 	if (!space || !div)
55 		goto error;
56 
57 	ctx = isl_space_get_ctx(space);
58 	ls = isl_calloc_type(ctx, struct isl_local_space);
59 	if (!ls)
60 		goto error;
61 
62 	ls->ref = 1;
63 	ls->dim = space;
64 	ls->div = div;
65 
66 	return ls;
67 error:
68 	isl_mat_free(div);
69 	isl_space_free(space);
70 	isl_local_space_free(ls);
71 	return NULL;
72 }
73 
isl_local_space_alloc(__isl_take isl_space * space,unsigned n_div)74 __isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_space *space,
75 	unsigned n_div)
76 {
77 	isl_ctx *ctx;
78 	isl_mat *div;
79 	isl_size total;
80 
81 	if (!space)
82 		return NULL;
83 
84 	total = isl_space_dim(space, isl_dim_all);
85 	if (total < 0)
86 		return isl_local_space_from_space(isl_space_free(space));
87 
88 	ctx = isl_space_get_ctx(space);
89 	div = isl_mat_alloc(ctx, n_div, 1 + 1 + total + n_div);
90 	return isl_local_space_alloc_div(space, div);
91 }
92 
isl_local_space_from_space(__isl_take isl_space * space)93 __isl_give isl_local_space *isl_local_space_from_space(
94 	__isl_take isl_space *space)
95 {
96 	return isl_local_space_alloc(space, 0);
97 }
98 
isl_local_space_copy(__isl_keep isl_local_space * ls)99 __isl_give isl_local_space *isl_local_space_copy(__isl_keep isl_local_space *ls)
100 {
101 	if (!ls)
102 		return NULL;
103 
104 	ls->ref++;
105 	return ls;
106 }
107 
isl_local_space_dup(__isl_keep isl_local_space * ls)108 __isl_give isl_local_space *isl_local_space_dup(__isl_keep isl_local_space *ls)
109 {
110 	if (!ls)
111 		return NULL;
112 
113 	return isl_local_space_alloc_div(isl_space_copy(ls->dim),
114 					 isl_mat_copy(ls->div));
115 
116 }
117 
isl_local_space_cow(__isl_take isl_local_space * ls)118 __isl_give isl_local_space *isl_local_space_cow(__isl_take isl_local_space *ls)
119 {
120 	if (!ls)
121 		return NULL;
122 
123 	if (ls->ref == 1)
124 		return ls;
125 	ls->ref--;
126 	return isl_local_space_dup(ls);
127 }
128 
isl_local_space_free(__isl_take isl_local_space * ls)129 __isl_null isl_local_space *isl_local_space_free(
130 	__isl_take isl_local_space *ls)
131 {
132 	if (!ls)
133 		return NULL;
134 
135 	if (--ls->ref > 0)
136 		return NULL;
137 
138 	isl_space_free(ls->dim);
139 	isl_mat_free(ls->div);
140 
141 	free(ls);
142 
143 	return NULL;
144 }
145 
146 /* Is the local space that of a parameter domain?
147  */
isl_local_space_is_params(__isl_keep isl_local_space * ls)148 isl_bool isl_local_space_is_params(__isl_keep isl_local_space *ls)
149 {
150 	if (!ls)
151 		return isl_bool_error;
152 	return isl_space_is_params(ls->dim);
153 }
154 
155 /* Is the local space that of a set?
156  */
isl_local_space_is_set(__isl_keep isl_local_space * ls)157 isl_bool isl_local_space_is_set(__isl_keep isl_local_space *ls)
158 {
159 	return ls ? isl_space_is_set(ls->dim) : isl_bool_error;
160 }
161 
162 #undef TYPE
163 #define TYPE	isl_local_space
164 
165 #include "isl_type_has_equal_space_bin_templ.c"
166 #include "isl_type_has_space_templ.c"
167 
168 /* Check that the space of "ls" is equal to "space".
169  */
isl_local_space_check_has_space(__isl_keep isl_local_space * ls,__isl_keep isl_space * space)170 static isl_stat isl_local_space_check_has_space(__isl_keep isl_local_space *ls,
171 	__isl_keep isl_space *space)
172 {
173 	isl_bool ok;
174 
175 	ok = isl_local_space_has_space(ls, space);
176 	if (ok < 0)
177 		return isl_stat_error;
178 	if (!ok)
179 		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
180 			"spaces don't match", return isl_stat_error);
181 	return isl_stat_ok;
182 }
183 
184 /* Return true if the two local spaces are identical, with identical
185  * expressions for the integer divisions.
186  */
isl_local_space_is_equal(__isl_keep isl_local_space * ls1,__isl_keep isl_local_space * ls2)187 isl_bool isl_local_space_is_equal(__isl_keep isl_local_space *ls1,
188 	__isl_keep isl_local_space *ls2)
189 {
190 	isl_bool equal;
191 
192 	equal = isl_local_space_has_equal_space(ls1, ls2);
193 	if (equal < 0 || !equal)
194 		return equal;
195 
196 	if (!isl_local_space_divs_known(ls1))
197 		return isl_bool_false;
198 	if (!isl_local_space_divs_known(ls2))
199 		return isl_bool_false;
200 
201 	return isl_mat_is_equal(ls1->div, ls2->div);
202 }
203 
204 /* Compare two isl_local_spaces.
205  *
206  * Return -1 if "ls1" is "smaller" than "ls2", 1 if "ls1" is "greater"
207  * than "ls2" and 0 if they are equal.
208  */
isl_local_space_cmp(__isl_keep isl_local_space * ls1,__isl_keep isl_local_space * ls2)209 int isl_local_space_cmp(__isl_keep isl_local_space *ls1,
210 	__isl_keep isl_local_space *ls2)
211 {
212 	int cmp;
213 
214 	if (ls1 == ls2)
215 		return 0;
216 	if (!ls1)
217 		return -1;
218 	if (!ls2)
219 		return 1;
220 
221 	cmp = isl_space_cmp(ls1->dim, ls2->dim);
222 	if (cmp != 0)
223 		return cmp;
224 
225 	return isl_local_cmp(ls1->div, ls2->div);
226 }
227 
isl_local_space_dim(__isl_keep isl_local_space * ls,enum isl_dim_type type)228 isl_size isl_local_space_dim(__isl_keep isl_local_space *ls,
229 	enum isl_dim_type type)
230 {
231 	if (!ls)
232 		return isl_size_error;
233 	if (type == isl_dim_div)
234 		return ls->div->n_row;
235 	if (type == isl_dim_all) {
236 		isl_size dim = isl_space_dim(ls->dim, isl_dim_all);
237 		if (dim < 0)
238 			return isl_size_error;
239 		return dim + ls->div->n_row;
240 	}
241 	return isl_space_dim(ls->dim, type);
242 }
243 
244 #undef TYPE
245 #define TYPE	isl_local_space
246 #include "check_type_range_templ.c"
247 
isl_local_space_offset(__isl_keep isl_local_space * ls,enum isl_dim_type type)248 unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
249 	enum isl_dim_type type)
250 {
251 	isl_space *space;
252 
253 	if (!ls)
254 		return 0;
255 
256 	space = ls->dim;
257 	switch (type) {
258 	case isl_dim_cst:	return 0;
259 	case isl_dim_param:	return 1;
260 	case isl_dim_in:	return 1 + space->nparam;
261 	case isl_dim_out:	return 1 + space->nparam + space->n_in;
262 	case isl_dim_div:
263 		return 1 + space->nparam + space->n_in + space->n_out;
264 	default:		return 0;
265 	}
266 }
267 
268 /* Return the position of the dimension of the given type and name
269  * in "ls".
270  * Return -1 if no such dimension can be found.
271  */
isl_local_space_find_dim_by_name(__isl_keep isl_local_space * ls,enum isl_dim_type type,const char * name)272 int isl_local_space_find_dim_by_name(__isl_keep isl_local_space *ls,
273 	enum isl_dim_type type, const char *name)
274 {
275 	if (!ls)
276 		return -1;
277 	if (type == isl_dim_div)
278 		return -1;
279 	return isl_space_find_dim_by_name(ls->dim, type, name);
280 }
281 
282 /* Does the given dimension have a name?
283  */
isl_local_space_has_dim_name(__isl_keep isl_local_space * ls,enum isl_dim_type type,unsigned pos)284 isl_bool isl_local_space_has_dim_name(__isl_keep isl_local_space *ls,
285 	enum isl_dim_type type, unsigned pos)
286 {
287 	return ls ? isl_space_has_dim_name(ls->dim, type, pos) : isl_bool_error;
288 }
289 
isl_local_space_get_dim_name(__isl_keep isl_local_space * ls,enum isl_dim_type type,unsigned pos)290 const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
291 	enum isl_dim_type type, unsigned pos)
292 {
293 	return ls ? isl_space_get_dim_name(ls->dim, type, pos) : NULL;
294 }
295 
isl_local_space_has_dim_id(__isl_keep isl_local_space * ls,enum isl_dim_type type,unsigned pos)296 isl_bool isl_local_space_has_dim_id(__isl_keep isl_local_space *ls,
297 	enum isl_dim_type type, unsigned pos)
298 {
299 	return ls ? isl_space_has_dim_id(ls->dim, type, pos) : isl_bool_error;
300 }
301 
isl_local_space_get_dim_id(__isl_keep isl_local_space * ls,enum isl_dim_type type,unsigned pos)302 __isl_give isl_id *isl_local_space_get_dim_id(__isl_keep isl_local_space *ls,
303 	enum isl_dim_type type, unsigned pos)
304 {
305 	return ls ? isl_space_get_dim_id(ls->dim, type, pos) : NULL;
306 }
307 
308 /* Return the argument of the integer division at position "pos" in "ls".
309  * All local variables in "ls" are known to have a (complete) explicit
310  * representation.
311  */
extract_div(__isl_keep isl_local_space * ls,int pos)312 static __isl_give isl_aff *extract_div(__isl_keep isl_local_space *ls, int pos)
313 {
314 	isl_aff *aff;
315 
316 	aff = isl_aff_alloc(isl_local_space_copy(ls));
317 	if (!aff)
318 		return NULL;
319 	isl_seq_cpy(aff->v->el, ls->div->row[pos], aff->v->size);
320 	return aff;
321 }
322 
323 /* Return the argument of the integer division at position "pos" in "ls".
324  * The integer division at that position is known to have a complete
325  * explicit representation, but some of the others do not.
326  * Remove them first because the domain of an isl_aff
327  * is not allowed to have unknown local variables.
328  */
drop_unknown_divs_and_extract_div(__isl_keep isl_local_space * ls,int pos)329 static __isl_give isl_aff *drop_unknown_divs_and_extract_div(
330 	__isl_keep isl_local_space *ls, int pos)
331 {
332 	int i;
333 	isl_size n;
334 	isl_bool unknown;
335 	isl_aff *aff;
336 
337 	n = isl_local_space_dim(ls, isl_dim_div);
338 	if (n < 0)
339 		return NULL;
340 	ls = isl_local_space_copy(ls);
341 	for (i = n - 1; i >= 0; --i) {
342 		unknown = isl_local_space_div_is_marked_unknown(ls, i);
343 		if (unknown < 0)
344 			ls = isl_local_space_free(ls);
345 		else if (!unknown)
346 			continue;
347 		ls = isl_local_space_drop_dims(ls, isl_dim_div, i, 1);
348 		if (pos > i)
349 			--pos;
350 	}
351 	aff = extract_div(ls, pos);
352 	isl_local_space_free(ls);
353 	return aff;
354 }
355 
356 /* Return the argument of the integer division at position "pos" in "ls".
357  * The integer division is assumed to have a complete explicit
358  * representation.  If some of the other integer divisions
359  * do not have an explicit representation, then they need
360  * to be removed first because the domain of an isl_aff
361  * is not allowed to have unknown local variables.
362  */
isl_local_space_get_div(__isl_keep isl_local_space * ls,int pos)363 __isl_give isl_aff *isl_local_space_get_div(__isl_keep isl_local_space *ls,
364 	int pos)
365 {
366 	isl_bool known;
367 
368 	if (!ls)
369 		return NULL;
370 
371 	if (pos < 0 || pos >= ls->div->n_row)
372 		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
373 			"index out of bounds", return NULL);
374 
375 	known = isl_local_space_div_is_known(ls, pos);
376 	if (known < 0)
377 		return NULL;
378 	if (!known)
379 		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
380 			"expression of div unknown", return NULL);
381 	if (!isl_local_space_is_set(ls))
382 		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
383 			"cannot represent divs of map spaces", return NULL);
384 
385 	known = isl_local_space_divs_known(ls);
386 	if (known < 0)
387 		return NULL;
388 	if (known)
389 		return extract_div(ls, pos);
390 	else
391 		return drop_unknown_divs_and_extract_div(ls, pos);
392 }
393 
394 /* Return the space of "ls".
395  */
isl_local_space_peek_space(__isl_keep isl_local_space * ls)396 __isl_keep isl_space *isl_local_space_peek_space(__isl_keep isl_local_space *ls)
397 {
398 	if (!ls)
399 		return NULL;
400 
401 	return ls->dim;
402 }
403 
isl_local_space_get_space(__isl_keep isl_local_space * ls)404 __isl_give isl_space *isl_local_space_get_space(__isl_keep isl_local_space *ls)
405 {
406 	return isl_space_copy(isl_local_space_peek_space(ls));
407 }
408 
409 /* Return the space of "ls".
410  * This may be either a copy or the space itself
411  * if there is only one reference to "ls".
412  * This allows the space to be modified inplace
413  * if both the local space and its space have only a single reference.
414  * The caller is not allowed to modify "ls" between this call and
415  * a subsequent call to isl_local_space_restore_space.
416  * The only exception is that isl_local_space_free can be called instead.
417  */
isl_local_space_take_space(__isl_keep isl_local_space * ls)418 __isl_give isl_space *isl_local_space_take_space(__isl_keep isl_local_space *ls)
419 {
420 	isl_space *space;
421 
422 	if (!ls)
423 		return NULL;
424 	if (ls->ref != 1)
425 		return isl_local_space_get_space(ls);
426 	space = ls->dim;
427 	ls->dim = NULL;
428 	return space;
429 }
430 
431 /* Set the space of "ls" to "space", where the space of "ls" may be missing
432  * due to a preceding call to isl_local_space_take_space.
433  * However, in this case, "ls" only has a single reference and
434  * then the call to isl_local_space_cow has no effect.
435  */
isl_local_space_restore_space(__isl_take isl_local_space * ls,__isl_take isl_space * space)436 __isl_give isl_local_space *isl_local_space_restore_space(
437 	__isl_take isl_local_space *ls, __isl_take isl_space *space)
438 {
439 	if (!ls || !space)
440 		goto error;
441 
442 	if (ls->dim == space) {
443 		isl_space_free(space);
444 		return ls;
445 	}
446 
447 	ls = isl_local_space_cow(ls);
448 	if (!ls)
449 		goto error;
450 	isl_space_free(ls->dim);
451 	ls->dim = space;
452 
453 	return ls;
454 error:
455 	isl_local_space_free(ls);
456 	isl_space_free(space);
457 	return NULL;
458 }
459 
460 /* Return the local variables of "ls".
461  */
isl_local_space_peek_local(__isl_keep isl_local_space * ls)462 __isl_keep isl_local *isl_local_space_peek_local(__isl_keep isl_local_space *ls)
463 {
464 	return ls ? ls->div : NULL;
465 }
466 
467 /* Replace the identifier of the tuple of type "type" by "id".
468  */
isl_local_space_set_tuple_id(__isl_take isl_local_space * ls,enum isl_dim_type type,__isl_take isl_id * id)469 __isl_give isl_local_space *isl_local_space_set_tuple_id(
470 	__isl_take isl_local_space *ls,
471 	enum isl_dim_type type, __isl_take isl_id *id)
472 {
473 	ls = isl_local_space_cow(ls);
474 	if (!ls)
475 		goto error;
476 	ls->dim = isl_space_set_tuple_id(ls->dim, type, id);
477 	if (!ls->dim)
478 		return isl_local_space_free(ls);
479 	return ls;
480 error:
481 	isl_id_free(id);
482 	return NULL;
483 }
484 
isl_local_space_set_dim_name(__isl_take isl_local_space * ls,enum isl_dim_type type,unsigned pos,const char * s)485 __isl_give isl_local_space *isl_local_space_set_dim_name(
486 	__isl_take isl_local_space *ls,
487 	enum isl_dim_type type, unsigned pos, const char *s)
488 {
489 	ls = isl_local_space_cow(ls);
490 	if (!ls)
491 		return NULL;
492 	ls->dim = isl_space_set_dim_name(ls->dim, type, pos, s);
493 	if (!ls->dim)
494 		return isl_local_space_free(ls);
495 
496 	return ls;
497 }
498 
isl_local_space_set_dim_id(__isl_take isl_local_space * ls,enum isl_dim_type type,unsigned pos,__isl_take isl_id * id)499 __isl_give isl_local_space *isl_local_space_set_dim_id(
500 	__isl_take isl_local_space *ls,
501 	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
502 {
503 	ls = isl_local_space_cow(ls);
504 	if (!ls)
505 		goto error;
506 	ls->dim = isl_space_set_dim_id(ls->dim, type, pos, id);
507 	if (!ls->dim)
508 		return isl_local_space_free(ls);
509 
510 	return ls;
511 error:
512 	isl_id_free(id);
513 	return NULL;
514 }
515 
516 /* Construct a zero-dimensional local space with the given parameter domain.
517  */
isl_local_space_set_from_params(__isl_take isl_local_space * ls)518 __isl_give isl_local_space *isl_local_space_set_from_params(
519 	__isl_take isl_local_space *ls)
520 {
521 	isl_space *space;
522 
523 	space = isl_local_space_take_space(ls);
524 	space = isl_space_set_from_params(space);
525 	ls = isl_local_space_restore_space(ls, space);
526 
527 	return ls;
528 }
529 
isl_local_space_reset_space(__isl_take isl_local_space * ls,__isl_take isl_space * space)530 __isl_give isl_local_space *isl_local_space_reset_space(
531 	__isl_take isl_local_space *ls, __isl_take isl_space *space)
532 {
533 	ls = isl_local_space_cow(ls);
534 	if (!ls || !space)
535 		goto error;
536 
537 	isl_space_free(ls->dim);
538 	ls->dim = space;
539 
540 	return ls;
541 error:
542 	isl_local_space_free(ls);
543 	isl_space_free(space);
544 	return NULL;
545 }
546 
547 /* Reorder the dimensions of "ls" according to the given reordering.
548  * The reordering r is assumed to have been extended with the local
549  * variables, leaving them in the same order.
550  */
isl_local_space_realign(__isl_take isl_local_space * ls,__isl_take isl_reordering * r)551 __isl_give isl_local_space *isl_local_space_realign(
552 	__isl_take isl_local_space *ls, __isl_take isl_reordering *r)
553 {
554 	ls = isl_local_space_cow(ls);
555 	if (!ls || !r)
556 		goto error;
557 
558 	ls->div = isl_local_reorder(ls->div, isl_reordering_copy(r));
559 	if (!ls->div)
560 		goto error;
561 
562 	ls = isl_local_space_reset_space(ls, isl_reordering_get_space(r));
563 
564 	isl_reordering_free(r);
565 	return ls;
566 error:
567 	isl_local_space_free(ls);
568 	isl_reordering_free(r);
569 	return NULL;
570 }
571 
isl_local_space_add_div(__isl_take isl_local_space * ls,__isl_take isl_vec * div)572 __isl_give isl_local_space *isl_local_space_add_div(
573 	__isl_take isl_local_space *ls, __isl_take isl_vec *div)
574 {
575 	ls = isl_local_space_cow(ls);
576 	if (!ls || !div)
577 		goto error;
578 
579 	if (ls->div->n_col != div->size)
580 		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
581 			"incompatible dimensions", goto error);
582 
583 	ls->div = isl_mat_add_zero_cols(ls->div, 1);
584 	ls->div = isl_mat_add_rows(ls->div, 1);
585 	if (!ls->div)
586 		goto error;
587 
588 	isl_seq_cpy(ls->div->row[ls->div->n_row - 1], div->el, div->size);
589 	isl_int_set_si(ls->div->row[ls->div->n_row - 1][div->size], 0);
590 
591 	isl_vec_free(div);
592 	return ls;
593 error:
594 	isl_local_space_free(ls);
595 	isl_vec_free(div);
596 	return NULL;
597 }
598 
isl_local_space_replace_divs(__isl_take isl_local_space * ls,__isl_take isl_mat * div)599 __isl_give isl_local_space *isl_local_space_replace_divs(
600 	__isl_take isl_local_space *ls, __isl_take isl_mat *div)
601 {
602 	ls = isl_local_space_cow(ls);
603 
604 	if (!ls || !div)
605 		goto error;
606 
607 	isl_mat_free(ls->div);
608 	ls->div = div;
609 	return ls;
610 error:
611 	isl_mat_free(div);
612 	isl_local_space_free(ls);
613 	return NULL;
614 }
615 
616 /* Copy row "s" of "src" to row "d" of "dst", applying the expansion
617  * defined by "exp".
618  */
expand_row(__isl_keep isl_mat * dst,int d,__isl_keep isl_mat * src,int s,int * exp)619 static void expand_row(__isl_keep isl_mat *dst, int d,
620 	__isl_keep isl_mat *src, int s, int *exp)
621 {
622 	int i;
623 	unsigned c = src->n_col - src->n_row;
624 
625 	isl_seq_cpy(dst->row[d], src->row[s], c);
626 	isl_seq_clr(dst->row[d] + c, dst->n_col - c);
627 
628 	for (i = 0; i < s; ++i)
629 		isl_int_set(dst->row[d][c + exp[i]], src->row[s][c + i]);
630 }
631 
632 /* Compare (known) divs.
633  * Return non-zero if at least one of the two divs is unknown.
634  * In particular, if both divs are unknown, we respect their
635  * current order.  Otherwise, we sort the known div after the unknown
636  * div only if the known div depends on the unknown div.
637  */
cmp_row(isl_int * row_i,isl_int * row_j,int i,int j,unsigned n_row,unsigned n_col)638 static int cmp_row(isl_int *row_i, isl_int *row_j, int i, int j,
639 	unsigned n_row, unsigned n_col)
640 {
641 	int li, lj;
642 	int unknown_i, unknown_j;
643 
644 	unknown_i = isl_int_is_zero(row_i[0]);
645 	unknown_j = isl_int_is_zero(row_j[0]);
646 
647 	if (unknown_i && unknown_j)
648 		return i - j;
649 
650 	if (unknown_i)
651 		li = n_col - n_row + i;
652 	else
653 		li = isl_seq_last_non_zero(row_i, n_col);
654 	if (unknown_j)
655 		lj = n_col - n_row + j;
656 	else
657 		lj = isl_seq_last_non_zero(row_j, n_col);
658 
659 	if (li != lj)
660 		return li - lj;
661 
662 	return isl_seq_cmp(row_i, row_j, n_col);
663 }
664 
665 /* Call cmp_row for divs in a matrix.
666  */
isl_mat_cmp_div(__isl_keep isl_mat * div,int i,int j)667 int isl_mat_cmp_div(__isl_keep isl_mat *div, int i, int j)
668 {
669 	return cmp_row(div->row[i], div->row[j], i, j, div->n_row, div->n_col);
670 }
671 
672 /* Call cmp_row for divs in a basic map.
673  */
bmap_cmp_row(__isl_keep isl_basic_map * bmap,int i,int j,unsigned total)674 static int bmap_cmp_row(__isl_keep isl_basic_map *bmap, int i, int j,
675 	unsigned total)
676 {
677 	return cmp_row(bmap->div[i], bmap->div[j], i, j, bmap->n_div, total);
678 }
679 
680 /* Sort the divs in "bmap".
681  *
682  * We first make sure divs are placed after divs on which they depend.
683  * Then we perform a simple insertion sort based on the same ordering
684  * that is used in isl_merge_divs.
685  */
isl_basic_map_sort_divs(__isl_take isl_basic_map * bmap)686 __isl_give isl_basic_map *isl_basic_map_sort_divs(
687 	__isl_take isl_basic_map *bmap)
688 {
689 	int i, j;
690 	isl_size total;
691 
692 	bmap = isl_basic_map_order_divs(bmap);
693 	if (!bmap)
694 		return NULL;
695 	if (bmap->n_div <= 1)
696 		return bmap;
697 
698 	total = isl_basic_map_dim(bmap, isl_dim_all);
699 	if (total < 0)
700 		return isl_basic_map_free(bmap);
701 	for (i = 1; i < bmap->n_div; ++i) {
702 		for (j = i - 1; j >= 0; --j) {
703 			if (bmap_cmp_row(bmap, j, j + 1, 2 + total) <= 0)
704 				break;
705 			bmap = isl_basic_map_swap_div(bmap, j, j + 1);
706 			if (!bmap)
707 				return NULL;
708 		}
709 	}
710 
711 	return bmap;
712 }
713 
714 /* Sort the divs in the basic maps of "map".
715  */
isl_map_sort_divs(__isl_take isl_map * map)716 __isl_give isl_map *isl_map_sort_divs(__isl_take isl_map *map)
717 {
718 	return isl_map_inline_foreach_basic_map(map, &isl_basic_map_sort_divs);
719 }
720 
721 /* Combine the two lists of divs into a single list.
722  * For each row i in div1, exp1[i] is set to the position of the corresponding
723  * row in the result.  Similarly for div2 and exp2.
724  * This function guarantees
725  *	exp1[i] >= i
726  *	exp1[i+1] > exp1[i]
727  * For optimal merging, the two input list should have been sorted.
728  */
isl_merge_divs(__isl_keep isl_mat * div1,__isl_keep isl_mat * div2,int * exp1,int * exp2)729 __isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
730 	__isl_keep isl_mat *div2, int *exp1, int *exp2)
731 {
732 	int i, j, k;
733 	isl_mat *div = NULL;
734 	unsigned d;
735 
736 	if (!div1 || !div2)
737 		return NULL;
738 
739 	d = div1->n_col - div1->n_row;
740 	div = isl_mat_alloc(div1->ctx, 1 + div1->n_row + div2->n_row,
741 				d + div1->n_row + div2->n_row);
742 	if (!div)
743 		return NULL;
744 
745 	for (i = 0, j = 0, k = 0; i < div1->n_row && j < div2->n_row; ++k) {
746 		int cmp;
747 
748 		expand_row(div, k, div1, i, exp1);
749 		expand_row(div, k + 1, div2, j, exp2);
750 
751 		cmp = isl_mat_cmp_div(div, k, k + 1);
752 		if (cmp == 0) {
753 			exp1[i++] = k;
754 			exp2[j++] = k;
755 		} else if (cmp < 0) {
756 			exp1[i++] = k;
757 		} else {
758 			exp2[j++] = k;
759 			isl_seq_cpy(div->row[k], div->row[k + 1], div->n_col);
760 		}
761 	}
762 	for (; i < div1->n_row; ++i, ++k) {
763 		expand_row(div, k, div1, i, exp1);
764 		exp1[i] = k;
765 	}
766 	for (; j < div2->n_row; ++j, ++k) {
767 		expand_row(div, k, div2, j, exp2);
768 		exp2[j] = k;
769 	}
770 
771 	div->n_row = k;
772 	div->n_col = d + k;
773 
774 	return div;
775 }
776 
777 /* Swap divs "a" and "b" in "ls".
778  */
isl_local_space_swap_div(__isl_take isl_local_space * ls,int a,int b)779 __isl_give isl_local_space *isl_local_space_swap_div(
780 	__isl_take isl_local_space *ls, int a, int b)
781 {
782 	int offset;
783 
784 	ls = isl_local_space_cow(ls);
785 	if (!ls)
786 		return NULL;
787 	if (a < 0 || a >= ls->div->n_row || b < 0 || b >= ls->div->n_row)
788 		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
789 			"index out of bounds", return isl_local_space_free(ls));
790 	offset = ls->div->n_col - ls->div->n_row;
791 	ls->div = isl_mat_swap_cols(ls->div, offset + a, offset + b);
792 	ls->div = isl_mat_swap_rows(ls->div, a, b);
793 	if (!ls->div)
794 		return isl_local_space_free(ls);
795 	return ls;
796 }
797 
798 /* Construct a local space that contains all the divs in either
799  * "ls1" or "ls2".
800  */
isl_local_space_intersect(__isl_take isl_local_space * ls1,__isl_take isl_local_space * ls2)801 __isl_give isl_local_space *isl_local_space_intersect(
802 	__isl_take isl_local_space *ls1, __isl_take isl_local_space *ls2)
803 {
804 	isl_ctx *ctx;
805 	int *exp1 = NULL;
806 	int *exp2 = NULL;
807 	isl_mat *div = NULL;
808 	isl_bool equal;
809 
810 	if (!ls1 || !ls2)
811 		goto error;
812 
813 	ctx = isl_local_space_get_ctx(ls1);
814 	if (!isl_space_is_equal(ls1->dim, ls2->dim))
815 		isl_die(ctx, isl_error_invalid,
816 			"spaces should be identical", goto error);
817 
818 	if (ls2->div->n_row == 0) {
819 		isl_local_space_free(ls2);
820 		return ls1;
821 	}
822 
823 	if (ls1->div->n_row == 0) {
824 		isl_local_space_free(ls1);
825 		return ls2;
826 	}
827 
828 	exp1 = isl_alloc_array(ctx, int, ls1->div->n_row);
829 	exp2 = isl_alloc_array(ctx, int, ls2->div->n_row);
830 	if (!exp1 || !exp2)
831 		goto error;
832 
833 	div = isl_merge_divs(ls1->div, ls2->div, exp1, exp2);
834 	if (!div)
835 		goto error;
836 
837 	equal = isl_mat_is_equal(ls1->div, div);
838 	if (equal < 0)
839 		goto error;
840 	if (!equal)
841 		ls1 = isl_local_space_cow(ls1);
842 	if (!ls1)
843 		goto error;
844 
845 	free(exp1);
846 	free(exp2);
847 	isl_local_space_free(ls2);
848 	isl_mat_free(ls1->div);
849 	ls1->div = div;
850 
851 	return ls1;
852 error:
853 	free(exp1);
854 	free(exp2);
855 	isl_mat_free(div);
856 	isl_local_space_free(ls1);
857 	isl_local_space_free(ls2);
858 	return NULL;
859 }
860 
861 /* Is the local variable "div" of "ls" marked as not having
862  * an explicit representation?
863  * Note that even if this variable is not marked in this way and therefore
864  * does have an explicit representation, this representation may still
865  * depend (indirectly) on other local variables that do not
866  * have an explicit representation.
867  */
isl_local_space_div_is_marked_unknown(__isl_keep isl_local_space * ls,int div)868 isl_bool isl_local_space_div_is_marked_unknown(__isl_keep isl_local_space *ls,
869 	int div)
870 {
871 	if (!ls)
872 		return isl_bool_error;
873 	return isl_local_div_is_marked_unknown(ls->div, div);
874 }
875 
876 /* Does "ls" have a complete explicit representation for div "div"?
877  */
isl_local_space_div_is_known(__isl_keep isl_local_space * ls,int div)878 isl_bool isl_local_space_div_is_known(__isl_keep isl_local_space *ls, int div)
879 {
880 	if (!ls)
881 		return isl_bool_error;
882 	return isl_local_div_is_known(ls->div, div);
883 }
884 
885 /* Does "ls" have an explicit representation for all local variables?
886  */
isl_local_space_divs_known(__isl_keep isl_local_space * ls)887 isl_bool isl_local_space_divs_known(__isl_keep isl_local_space *ls)
888 {
889 	if (!ls)
890 		return isl_bool_error;
891 	return isl_local_divs_known(ls->div);
892 }
893 
isl_local_space_domain(__isl_take isl_local_space * ls)894 __isl_give isl_local_space *isl_local_space_domain(
895 	__isl_take isl_local_space *ls)
896 {
897 	isl_size n_out;
898 
899 	n_out = isl_local_space_dim(ls, isl_dim_out);
900 	if (n_out < 0)
901 		return isl_local_space_free(ls);
902 	ls = isl_local_space_drop_dims(ls, isl_dim_out, 0, n_out);
903 	ls = isl_local_space_cow(ls);
904 	if (!ls)
905 		return NULL;
906 	ls->dim = isl_space_domain(ls->dim);
907 	if (!ls->dim)
908 		return isl_local_space_free(ls);
909 	return ls;
910 }
911 
isl_local_space_range(__isl_take isl_local_space * ls)912 __isl_give isl_local_space *isl_local_space_range(
913 	__isl_take isl_local_space *ls)
914 {
915 	isl_size n_in;
916 
917 	n_in = isl_local_space_dim(ls, isl_dim_in);
918 	if (n_in < 0)
919 		return isl_local_space_free(ls);
920 	ls = isl_local_space_drop_dims(ls, isl_dim_in, 0, n_in);
921 	ls = isl_local_space_cow(ls);
922 	if (!ls)
923 		return NULL;
924 
925 	ls->dim = isl_space_range(ls->dim);
926 	if (!ls->dim)
927 		return isl_local_space_free(ls);
928 	return ls;
929 }
930 
931 /* Construct a local space for a map that has the given local
932  * space as domain and that has a zero-dimensional range.
933  */
isl_local_space_from_domain(__isl_take isl_local_space * ls)934 __isl_give isl_local_space *isl_local_space_from_domain(
935 	__isl_take isl_local_space *ls)
936 {
937 	ls = isl_local_space_cow(ls);
938 	if (!ls)
939 		return NULL;
940 	ls->dim = isl_space_from_domain(ls->dim);
941 	if (!ls->dim)
942 		return isl_local_space_free(ls);
943 	return ls;
944 }
945 
isl_local_space_add_dims(__isl_take isl_local_space * ls,enum isl_dim_type type,unsigned n)946 __isl_give isl_local_space *isl_local_space_add_dims(
947 	__isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n)
948 {
949 	isl_size pos;
950 
951 	pos = isl_local_space_dim(ls, type);
952 	if (pos < 0)
953 		return isl_local_space_free(ls);
954 	return isl_local_space_insert_dims(ls, type, pos, n);
955 }
956 
957 /* Lift the basic set "bset", living in the space of "ls"
958  * to live in a space with extra coordinates corresponding
959  * to the local variables of "ls".
960  */
isl_local_space_lift_basic_set(__isl_take isl_local_space * ls,__isl_take isl_basic_set * bset)961 __isl_give isl_basic_set *isl_local_space_lift_basic_set(
962 	__isl_take isl_local_space *ls, __isl_take isl_basic_set *bset)
963 {
964 	isl_size n_local;
965 	isl_space *space;
966 	isl_basic_set *ls_bset;
967 
968 	n_local = isl_local_space_dim(ls, isl_dim_div);
969 	space = isl_basic_set_peek_space(bset);
970 	if (n_local < 0 ||
971 	    isl_local_space_check_has_space(ls, space) < 0)
972 		goto error;
973 
974 	if (n_local == 0) {
975 		isl_local_space_free(ls);
976 		return bset;
977 	}
978 
979 	bset = isl_basic_set_add_dims(bset, isl_dim_set, n_local);
980 	ls_bset = isl_basic_set_from_local_space(ls);
981 	ls_bset = isl_basic_set_lift(ls_bset);
982 	ls_bset = isl_basic_set_flatten(ls_bset);
983 	bset = isl_basic_set_intersect(bset, ls_bset);
984 
985 	return bset;
986 error:
987 	isl_local_space_free(ls);
988 	isl_basic_set_free(bset);
989 	return NULL;
990 }
991 
992 /* Lift the set "set", living in the space of "ls"
993  * to live in a space with extra coordinates corresponding
994  * to the local variables of "ls".
995  */
isl_local_space_lift_set(__isl_take isl_local_space * ls,__isl_take isl_set * set)996 __isl_give isl_set *isl_local_space_lift_set(__isl_take isl_local_space *ls,
997 	__isl_take isl_set *set)
998 {
999 	isl_size n_local;
1000 	isl_basic_set *bset;
1001 
1002 	n_local = isl_local_space_dim(ls, isl_dim_div);
1003 	if (n_local < 0 ||
1004 	    isl_local_space_check_has_space(ls, isl_set_peek_space(set)) < 0)
1005 		goto error;
1006 
1007 	if (n_local == 0) {
1008 		isl_local_space_free(ls);
1009 		return set;
1010 	}
1011 
1012 	set = isl_set_add_dims(set, isl_dim_set, n_local);
1013 	bset = isl_basic_set_from_local_space(ls);
1014 	bset = isl_basic_set_lift(bset);
1015 	bset = isl_basic_set_flatten(bset);
1016 	set = isl_set_intersect(set, isl_set_from_basic_set(bset));
1017 
1018 	return set;
1019 error:
1020 	isl_local_space_free(ls);
1021 	isl_set_free(set);
1022 	return NULL;
1023 }
1024 
1025 /* Remove common factor of non-constant terms and denominator.
1026  */
normalize_div(__isl_take isl_local_space * ls,int div)1027 static __isl_give isl_local_space *normalize_div(
1028 	__isl_take isl_local_space *ls, int div)
1029 {
1030 	isl_ctx *ctx = ls->div->ctx;
1031 	unsigned total = ls->div->n_col - 2;
1032 
1033 	isl_seq_gcd(ls->div->row[div] + 2, total, &ctx->normalize_gcd);
1034 	isl_int_gcd(ctx->normalize_gcd,
1035 		    ctx->normalize_gcd, ls->div->row[div][0]);
1036 	if (isl_int_is_one(ctx->normalize_gcd))
1037 		return ls;
1038 
1039 	isl_seq_scale_down(ls->div->row[div] + 2, ls->div->row[div] + 2,
1040 			    ctx->normalize_gcd, total);
1041 	isl_int_divexact(ls->div->row[div][0], ls->div->row[div][0],
1042 			    ctx->normalize_gcd);
1043 	isl_int_fdiv_q(ls->div->row[div][1], ls->div->row[div][1],
1044 			    ctx->normalize_gcd);
1045 
1046 	return ls;
1047 }
1048 
1049 /* Exploit the equalities in "eq" to simplify the expressions of
1050  * the integer divisions in "ls".
1051  * The integer divisions in "ls" are assumed to appear as regular
1052  * dimensions in "eq".
1053  */
isl_local_space_substitute_equalities(__isl_take isl_local_space * ls,__isl_take isl_basic_set * eq)1054 __isl_give isl_local_space *isl_local_space_substitute_equalities(
1055 	__isl_take isl_local_space *ls, __isl_take isl_basic_set *eq)
1056 {
1057 	int i, j, k;
1058 	isl_size total, dim;
1059 	unsigned n_div;
1060 
1061 	if (!ls || !eq)
1062 		goto error;
1063 
1064 	total = isl_space_dim(eq->dim, isl_dim_all);
1065 	dim = isl_local_space_dim(ls, isl_dim_all);
1066 	if (dim < 0 || total < 0)
1067 		goto error;
1068 	if (dim != total)
1069 		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1070 			"spaces don't match", goto error);
1071 	total++;
1072 	n_div = eq->n_div;
1073 	for (i = 0; i < eq->n_eq; ++i) {
1074 		j = isl_seq_last_non_zero(eq->eq[i], total + n_div);
1075 		if (j < 0 || j == 0 || j >= total)
1076 			continue;
1077 
1078 		for (k = 0; k < ls->div->n_row; ++k) {
1079 			if (isl_int_is_zero(ls->div->row[k][1 + j]))
1080 				continue;
1081 			ls = isl_local_space_cow(ls);
1082 			if (!ls)
1083 				goto error;
1084 			ls->div = isl_mat_cow(ls->div);
1085 			if (!ls->div)
1086 				goto error;
1087 			isl_seq_elim(ls->div->row[k] + 1, eq->eq[i], j, total,
1088 					&ls->div->row[k][0]);
1089 			ls = normalize_div(ls, k);
1090 			if (!ls)
1091 				goto error;
1092 		}
1093 	}
1094 
1095 	isl_basic_set_free(eq);
1096 	return ls;
1097 error:
1098 	isl_basic_set_free(eq);
1099 	isl_local_space_free(ls);
1100 	return NULL;
1101 }
1102 
1103 /* Plug in the affine expressions "subs" of length "subs_len" (including
1104  * the denominator and the constant term) into the variable at position "pos"
1105  * of the "n" div expressions starting at "first".
1106  *
1107  * Let i be the dimension to replace and let "subs" be of the form
1108  *
1109  *	f/d
1110  *
1111  * Any integer division starting at "first" with a non-zero coefficient for i,
1112  *
1113  *	floor((a i + g)/m)
1114  *
1115  * is replaced by
1116  *
1117  *	floor((a f + d g)/(m d))
1118  */
isl_local_space_substitute_seq(__isl_take isl_local_space * ls,enum isl_dim_type type,unsigned pos,isl_int * subs,int subs_len,int first,int n)1119 __isl_give isl_local_space *isl_local_space_substitute_seq(
1120 	__isl_take isl_local_space *ls,
1121 	enum isl_dim_type type, unsigned pos, isl_int *subs, int subs_len,
1122 	int first, int n)
1123 {
1124 	int i;
1125 	isl_int v;
1126 
1127 	if (n == 0)
1128 		return ls;
1129 	ls = isl_local_space_cow(ls);
1130 	if (!ls)
1131 		return NULL;
1132 	ls->div = isl_mat_cow(ls->div);
1133 	if (!ls->div)
1134 		return isl_local_space_free(ls);
1135 
1136 	if (first + n > ls->div->n_row)
1137 		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1138 			"index out of bounds", return isl_local_space_free(ls));
1139 
1140 	pos += isl_local_space_offset(ls, type);
1141 
1142 	isl_int_init(v);
1143 	for (i = first; i < first + n; ++i) {
1144 		if (isl_int_is_zero(ls->div->row[i][1 + pos]))
1145 			continue;
1146 		isl_seq_substitute(ls->div->row[i], pos, subs,
1147 			ls->div->n_col, subs_len, v);
1148 		ls = normalize_div(ls, i);
1149 		if (!ls)
1150 			break;
1151 	}
1152 	isl_int_clear(v);
1153 
1154 	return ls;
1155 }
1156 
1157 /* Plug in "subs" for dimension "type", "pos" in the integer divisions
1158  * of "ls".
1159  *
1160  * Let i be the dimension to replace and let "subs" be of the form
1161  *
1162  *	f/d
1163  *
1164  * Any integer division with a non-zero coefficient for i,
1165  *
1166  *	floor((a i + g)/m)
1167  *
1168  * is replaced by
1169  *
1170  *	floor((a f + d g)/(m d))
1171  */
isl_local_space_substitute(__isl_take isl_local_space * ls,enum isl_dim_type type,unsigned pos,__isl_keep isl_aff * subs)1172 __isl_give isl_local_space *isl_local_space_substitute(
1173 	__isl_take isl_local_space *ls,
1174 	enum isl_dim_type type, unsigned pos, __isl_keep isl_aff *subs)
1175 {
1176 	isl_size n_div;
1177 
1178 	ls = isl_local_space_cow(ls);
1179 	if (!ls || !subs)
1180 		return isl_local_space_free(ls);
1181 
1182 	if (!isl_space_is_equal(ls->dim, subs->ls->dim))
1183 		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1184 			"spaces don't match", return isl_local_space_free(ls));
1185 	n_div = isl_local_space_dim(subs->ls, isl_dim_div);
1186 	if (n_div < 0)
1187 		return isl_local_space_free(ls);
1188 	if (n_div != 0)
1189 		isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
1190 			"cannot handle divs yet",
1191 			return isl_local_space_free(ls));
1192 
1193 	return isl_local_space_substitute_seq(ls, type, pos, subs->v->el,
1194 					    subs->v->size, 0, ls->div->n_row);
1195 }
1196 
isl_local_space_is_named_or_nested(__isl_keep isl_local_space * ls,enum isl_dim_type type)1197 isl_bool isl_local_space_is_named_or_nested(__isl_keep isl_local_space *ls,
1198 	enum isl_dim_type type)
1199 {
1200 	if (!ls)
1201 		return isl_bool_error;
1202 	return isl_space_is_named_or_nested(ls->dim, type);
1203 }
1204 
isl_local_space_drop_dims(__isl_take isl_local_space * ls,enum isl_dim_type type,unsigned first,unsigned n)1205 __isl_give isl_local_space *isl_local_space_drop_dims(
1206 	__isl_take isl_local_space *ls,
1207 	enum isl_dim_type type, unsigned first, unsigned n)
1208 {
1209 	if (!ls)
1210 		return NULL;
1211 	if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
1212 		return ls;
1213 
1214 	if (isl_local_space_check_range(ls, type, first, n) < 0)
1215 		return isl_local_space_free(ls);
1216 
1217 	ls = isl_local_space_cow(ls);
1218 	if (!ls)
1219 		return NULL;
1220 
1221 	if (type == isl_dim_div) {
1222 		ls->div = isl_mat_drop_rows(ls->div, first, n);
1223 	} else {
1224 		ls->dim = isl_space_drop_dims(ls->dim, type, first, n);
1225 		if (!ls->dim)
1226 			return isl_local_space_free(ls);
1227 	}
1228 
1229 	first += 1 + isl_local_space_offset(ls, type);
1230 	ls->div = isl_mat_drop_cols(ls->div, first, n);
1231 	if (!ls->div)
1232 		return isl_local_space_free(ls);
1233 
1234 	return ls;
1235 }
1236 
isl_local_space_insert_dims(__isl_take isl_local_space * ls,enum isl_dim_type type,unsigned first,unsigned n)1237 __isl_give isl_local_space *isl_local_space_insert_dims(
1238 	__isl_take isl_local_space *ls,
1239 	enum isl_dim_type type, unsigned first, unsigned n)
1240 {
1241 	if (!ls)
1242 		return NULL;
1243 	if (n == 0 && !isl_local_space_is_named_or_nested(ls, type))
1244 		return ls;
1245 
1246 	if (isl_local_space_check_range(ls, type, first, 0) < 0)
1247 		return isl_local_space_free(ls);
1248 
1249 	ls = isl_local_space_cow(ls);
1250 	if (!ls)
1251 		return NULL;
1252 
1253 	if (type == isl_dim_div) {
1254 		ls->div = isl_mat_insert_zero_rows(ls->div, first, n);
1255 	} else {
1256 		ls->dim = isl_space_insert_dims(ls->dim, type, first, n);
1257 		if (!ls->dim)
1258 			return isl_local_space_free(ls);
1259 	}
1260 
1261 	first += 1 + isl_local_space_offset(ls, type);
1262 	ls->div = isl_mat_insert_zero_cols(ls->div, first, n);
1263 	if (!ls->div)
1264 		return isl_local_space_free(ls);
1265 
1266 	return ls;
1267 }
1268 
1269 /* Does the linear part of "constraint" correspond to
1270  * integer division "div" in "ls"?
1271  *
1272  * That is, given div = floor((c + f)/m), is the constraint of the form
1273  *
1274  *		f - m d + c' >= 0		[sign = 1]
1275  * or
1276  *		-f + m d + c'' >= 0		[sign = -1]
1277  * ?
1278  * If so, set *sign to the corresponding value.
1279  */
is_linear_div_constraint(__isl_keep isl_local_space * ls,isl_int * constraint,unsigned div,int * sign)1280 static isl_bool is_linear_div_constraint(__isl_keep isl_local_space *ls,
1281 	isl_int *constraint, unsigned div, int *sign)
1282 {
1283 	isl_bool unknown;
1284 	unsigned pos;
1285 
1286 	unknown = isl_local_space_div_is_marked_unknown(ls, div);
1287 	if (unknown < 0)
1288 		return isl_bool_error;
1289 	if (unknown)
1290 		return isl_bool_false;
1291 
1292 	pos = isl_local_space_offset(ls, isl_dim_div) + div;
1293 
1294 	if (isl_int_eq(constraint[pos], ls->div->row[div][0])) {
1295 		*sign = -1;
1296 		if (!isl_seq_is_neg(constraint + 1,
1297 				    ls->div->row[div] + 2, pos - 1))
1298 			return isl_bool_false;
1299 	} else if (isl_int_abs_eq(constraint[pos], ls->div->row[div][0])) {
1300 		*sign = 1;
1301 		if (!isl_seq_eq(constraint + 1, ls->div->row[div] + 2, pos - 1))
1302 			return isl_bool_false;
1303 	} else {
1304 		return isl_bool_false;
1305 	}
1306 	if (isl_seq_first_non_zero(constraint + pos + 1,
1307 				    ls->div->n_row - div - 1) != -1)
1308 		return isl_bool_false;
1309 	return isl_bool_true;
1310 }
1311 
1312 /* Check if the constraints pointed to by "constraint" is a div
1313  * constraint corresponding to div "div" in "ls".
1314  *
1315  * That is, if div = floor(f/m), then check if the constraint is
1316  *
1317  *		f - m d >= 0
1318  * or
1319  *		-(f-(m-1)) + m d >= 0
1320  *
1321  * First check if the linear part is of the right form and
1322  * then check the constant term.
1323  */
isl_local_space_is_div_constraint(__isl_keep isl_local_space * ls,isl_int * constraint,unsigned div)1324 isl_bool isl_local_space_is_div_constraint(__isl_keep isl_local_space *ls,
1325 	isl_int *constraint, unsigned div)
1326 {
1327 	int sign;
1328 	isl_bool linear;
1329 
1330 	linear = is_linear_div_constraint(ls, constraint, div, &sign);
1331 	if (linear < 0 || !linear)
1332 		return linear;
1333 
1334 	if (sign < 0) {
1335 		int neg;
1336 		isl_int_sub(ls->div->row[div][1],
1337 				ls->div->row[div][1], ls->div->row[div][0]);
1338 		isl_int_add_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
1339 		neg = isl_seq_is_neg(constraint, ls->div->row[div] + 1, 1);
1340 		isl_int_sub_ui(ls->div->row[div][1], ls->div->row[div][1], 1);
1341 		isl_int_add(ls->div->row[div][1],
1342 				ls->div->row[div][1], ls->div->row[div][0]);
1343 		if (!neg)
1344 			return isl_bool_false;
1345 	} else {
1346 		if (!isl_int_eq(constraint[0], ls->div->row[div][1]))
1347 			return isl_bool_false;
1348 	}
1349 
1350 	return isl_bool_true;
1351 }
1352 
1353 /* Is the constraint pointed to by "constraint" one
1354  * of an equality that corresponds to integer division "div" in "ls"?
1355  *
1356  * That is, given an integer division of the form
1357  *
1358  *	a = floor((f + c)/m)
1359  *
1360  * is the equality of the form
1361  *
1362  *		-f + m d + c' = 0
1363  * ?
1364  * Note that the constant term is not checked explicitly, but given
1365  * that this is a valid equality constraint, the constant c' necessarily
1366  * has a value close to -c.
1367  */
isl_local_space_is_div_equality(__isl_keep isl_local_space * ls,isl_int * constraint,unsigned div)1368 isl_bool isl_local_space_is_div_equality(__isl_keep isl_local_space *ls,
1369 	isl_int *constraint, unsigned div)
1370 {
1371 	int sign;
1372 	isl_bool linear;
1373 
1374 	linear = is_linear_div_constraint(ls, constraint, div, &sign);
1375 	if (linear < 0 || !linear)
1376 		return linear;
1377 
1378 	return isl_bool_ok(sign < 0);
1379 }
1380 
1381 /*
1382  * Set active[i] to 1 if the dimension at position i is involved
1383  * in the linear expression l.
1384  */
isl_local_space_get_active(__isl_keep isl_local_space * ls,isl_int * l)1385 int *isl_local_space_get_active(__isl_keep isl_local_space *ls, isl_int *l)
1386 {
1387 	int i, j;
1388 	isl_ctx *ctx;
1389 	int *active = NULL;
1390 	isl_size total;
1391 	unsigned offset;
1392 
1393 	ctx = isl_local_space_get_ctx(ls);
1394 	total = isl_local_space_dim(ls, isl_dim_all);
1395 	if (total < 0)
1396 		return NULL;
1397 	active = isl_calloc_array(ctx, int, total);
1398 	if (total && !active)
1399 		return NULL;
1400 
1401 	for (i = 0; i < total; ++i)
1402 		active[i] = !isl_int_is_zero(l[i]);
1403 
1404 	offset = isl_local_space_offset(ls, isl_dim_div) - 1;
1405 	for (i = ls->div->n_row - 1; i >= 0; --i) {
1406 		if (!active[offset + i])
1407 			continue;
1408 		for (j = 0; j < total; ++j)
1409 			active[j] |= !isl_int_is_zero(ls->div->row[i][2 + j]);
1410 	}
1411 
1412 	return active;
1413 }
1414 
1415 /* Given a local space "ls" of a set, create a local space
1416  * for the lift of the set.  In particular, the result
1417  * is of the form [dim -> local[..]], with ls->div->n_row variables in the
1418  * range of the wrapped map.
1419  */
isl_local_space_lift(__isl_take isl_local_space * ls)1420 __isl_give isl_local_space *isl_local_space_lift(
1421 	__isl_take isl_local_space *ls)
1422 {
1423 	ls = isl_local_space_cow(ls);
1424 	if (!ls)
1425 		return NULL;
1426 
1427 	ls->dim = isl_space_lift(ls->dim, ls->div->n_row);
1428 	ls->div = isl_mat_drop_rows(ls->div, 0, ls->div->n_row);
1429 	if (!ls->dim || !ls->div)
1430 		return isl_local_space_free(ls);
1431 
1432 	return ls;
1433 }
1434 
1435 /* Construct a basic map that maps a set living in local space "ls"
1436  * to the corresponding lifted local space.
1437  */
isl_local_space_lifting(__isl_take isl_local_space * ls)1438 __isl_give isl_basic_map *isl_local_space_lifting(
1439 	__isl_take isl_local_space *ls)
1440 {
1441 	isl_basic_map *lifting;
1442 	isl_basic_set *bset;
1443 
1444 	if (!ls)
1445 		return NULL;
1446 	if (!isl_local_space_is_set(ls))
1447 		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1448 			"lifting only defined on set spaces", goto error);
1449 
1450 	bset = isl_basic_set_from_local_space(ls);
1451 	lifting = isl_basic_set_unwrap(isl_basic_set_lift(bset));
1452 	lifting = isl_basic_map_domain_map(lifting);
1453 	lifting = isl_basic_map_reverse(lifting);
1454 
1455 	return lifting;
1456 error:
1457 	isl_local_space_free(ls);
1458 	return NULL;
1459 }
1460 
1461 /* Compute the preimage of "ls" under the function represented by "ma".
1462  * In other words, plug in "ma" in "ls".  The result is a local space
1463  * that is part of the domain space of "ma".
1464  *
1465  * If the divs in "ls" are represented as
1466  *
1467  *	floor((a_i(p) + b_i x + c_i(divs))/n_i)
1468  *
1469  * and ma is represented by
1470  *
1471  *	x = D(p) + F(y) + G(divs')
1472  *
1473  * then the resulting divs are
1474  *
1475  *	floor((a_i(p) + b_i D(p) + b_i F(y) + B_i G(divs') + c_i(divs))/n_i)
1476  *
1477  * We first copy over the divs from "ma" and then
1478  * we add the modified divs from "ls".
1479  */
isl_local_space_preimage_multi_aff(__isl_take isl_local_space * ls,__isl_take isl_multi_aff * ma)1480 __isl_give isl_local_space *isl_local_space_preimage_multi_aff(
1481 	__isl_take isl_local_space *ls, __isl_take isl_multi_aff *ma)
1482 {
1483 	int i;
1484 	isl_space *space;
1485 	isl_local_space *res = NULL;
1486 	isl_size n_div_ls, n_div_ma;
1487 	isl_int f, c1, c2, g;
1488 
1489 	ma = isl_multi_aff_align_divs(ma);
1490 	if (!ls || !ma)
1491 		goto error;
1492 	if (!isl_space_is_range_internal(ls->dim, ma->space))
1493 		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1494 			"spaces don't match", goto error);
1495 
1496 	n_div_ls = isl_local_space_dim(ls, isl_dim_div);
1497 	n_div_ma = ma->n ? isl_aff_dim(ma->u.p[0], isl_dim_div) : 0;
1498 	if (n_div_ls < 0 || n_div_ma < 0)
1499 		goto error;
1500 
1501 	space = isl_space_domain(isl_multi_aff_get_space(ma));
1502 	res = isl_local_space_alloc(space, n_div_ma + n_div_ls);
1503 	if (!res)
1504 		goto error;
1505 
1506 	if (n_div_ma) {
1507 		isl_mat_free(res->div);
1508 		res->div = isl_mat_copy(ma->u.p[0]->ls->div);
1509 		res->div = isl_mat_add_zero_cols(res->div, n_div_ls);
1510 		res->div = isl_mat_add_rows(res->div, n_div_ls);
1511 		if (!res->div)
1512 			goto error;
1513 	}
1514 
1515 	isl_int_init(f);
1516 	isl_int_init(c1);
1517 	isl_int_init(c2);
1518 	isl_int_init(g);
1519 
1520 	for (i = 0; i < ls->div->n_row; ++i) {
1521 		if (isl_int_is_zero(ls->div->row[i][0])) {
1522 			isl_int_set_si(res->div->row[n_div_ma + i][0], 0);
1523 			continue;
1524 		}
1525 		if (isl_seq_preimage(res->div->row[n_div_ma + i],
1526 			    ls->div->row[i],
1527 			    ma, 0, 0, n_div_ma, n_div_ls, f, c1, c2, g, 1) < 0)
1528 			res = isl_local_space_free(res);
1529 		res = normalize_div(res, n_div_ma + i);
1530 		if (!res)
1531 			break;
1532 	}
1533 
1534 	isl_int_clear(f);
1535 	isl_int_clear(c1);
1536 	isl_int_clear(c2);
1537 	isl_int_clear(g);
1538 
1539 	isl_local_space_free(ls);
1540 	isl_multi_aff_free(ma);
1541 	return res;
1542 error:
1543 	isl_local_space_free(ls);
1544 	isl_multi_aff_free(ma);
1545 	isl_local_space_free(res);
1546 	return NULL;
1547 }
1548 
1549 /* Move the "n" dimensions of "src_type" starting at "src_pos" of "ls"
1550  * to dimensions of "dst_type" at "dst_pos".
1551  *
1552  * Moving to/from local dimensions is not allowed.
1553  * We currently assume that the dimension type changes.
1554  */
isl_local_space_move_dims(__isl_take isl_local_space * ls,enum isl_dim_type dst_type,unsigned dst_pos,enum isl_dim_type src_type,unsigned src_pos,unsigned n)1555 __isl_give isl_local_space *isl_local_space_move_dims(
1556 	__isl_take isl_local_space *ls,
1557 	enum isl_dim_type dst_type, unsigned dst_pos,
1558 	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1559 {
1560 	unsigned g_dst_pos;
1561 	unsigned g_src_pos;
1562 
1563 	if (!ls)
1564 		return NULL;
1565 	if (n == 0 &&
1566 	    !isl_local_space_is_named_or_nested(ls, src_type) &&
1567 	    !isl_local_space_is_named_or_nested(ls, dst_type))
1568 		return ls;
1569 
1570 	if (isl_local_space_check_range(ls, src_type, src_pos, n) < 0)
1571 		return isl_local_space_free(ls);
1572 	if (isl_local_space_check_range(ls, dst_type, dst_pos, 0) < 0)
1573 		return isl_local_space_free(ls);
1574 	if (src_type == isl_dim_div)
1575 		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1576 			"cannot move divs", return isl_local_space_free(ls));
1577 	if (dst_type == isl_dim_div)
1578 		isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
1579 			"cannot move to divs", return isl_local_space_free(ls));
1580 	if (dst_type == src_type && dst_pos == src_pos)
1581 		return ls;
1582 	if (dst_type == src_type)
1583 		isl_die(isl_local_space_get_ctx(ls), isl_error_unsupported,
1584 			"moving dims within the same type not supported",
1585 			return isl_local_space_free(ls));
1586 
1587 	ls = isl_local_space_cow(ls);
1588 	if (!ls)
1589 		return NULL;
1590 
1591 	g_src_pos = 1 + isl_local_space_offset(ls, src_type) + src_pos;
1592 	g_dst_pos = 1 + isl_local_space_offset(ls, dst_type) + dst_pos;
1593 	if (dst_type > src_type)
1594 		g_dst_pos -= n;
1595 	ls->div = isl_mat_move_cols(ls->div, g_dst_pos, g_src_pos, n);
1596 	if (!ls->div)
1597 		return isl_local_space_free(ls);
1598 	ls->dim = isl_space_move_dims(ls->dim, dst_type, dst_pos,
1599 					src_type, src_pos, n);
1600 	if (!ls->dim)
1601 		return isl_local_space_free(ls);
1602 
1603 	return ls;
1604 }
1605 
1606 /* Remove any internal structure of the domain of "ls".
1607  * If there is any such internal structure in the input,
1608  * then the name of the corresponding space is also removed.
1609  */
isl_local_space_flatten_domain(__isl_take isl_local_space * ls)1610 __isl_give isl_local_space *isl_local_space_flatten_domain(
1611 	__isl_take isl_local_space *ls)
1612 {
1613 	if (!ls)
1614 		return NULL;
1615 
1616 	if (!ls->dim->nested[0])
1617 		return ls;
1618 
1619 	ls = isl_local_space_cow(ls);
1620 	if (!ls)
1621 		return NULL;
1622 
1623 	ls->dim = isl_space_flatten_domain(ls->dim);
1624 	if (!ls->dim)
1625 		return isl_local_space_free(ls);
1626 
1627 	return ls;
1628 }
1629 
1630 /* Remove any internal structure of the range of "ls".
1631  * If there is any such internal structure in the input,
1632  * then the name of the corresponding space is also removed.
1633  */
isl_local_space_flatten_range(__isl_take isl_local_space * ls)1634 __isl_give isl_local_space *isl_local_space_flatten_range(
1635 	__isl_take isl_local_space *ls)
1636 {
1637 	if (!ls)
1638 		return NULL;
1639 
1640 	if (!ls->dim->nested[1])
1641 		return ls;
1642 
1643 	ls = isl_local_space_cow(ls);
1644 	if (!ls)
1645 		return NULL;
1646 
1647 	ls->dim = isl_space_flatten_range(ls->dim);
1648 	if (!ls->dim)
1649 		return isl_local_space_free(ls);
1650 
1651 	return ls;
1652 }
1653 
1654 /* Given the local space "ls" of a map, return the local space of a set
1655  * that lives in a space that wraps the space of "ls" and that has
1656  * the same divs.
1657  */
isl_local_space_wrap(__isl_take isl_local_space * ls)1658 __isl_give isl_local_space *isl_local_space_wrap(__isl_take isl_local_space *ls)
1659 {
1660 	ls = isl_local_space_cow(ls);
1661 	if (!ls)
1662 		return NULL;
1663 
1664 	ls->dim = isl_space_wrap(ls->dim);
1665 	if (!ls->dim)
1666 		return isl_local_space_free(ls);
1667 
1668 	return ls;
1669 }
1670 
1671 /* Lift the point "pnt", living in the (set) space of "ls"
1672  * to live in a space with extra coordinates corresponding
1673  * to the local variables of "ls".
1674  */
isl_local_space_lift_point(__isl_take isl_local_space * ls,__isl_take isl_point * pnt)1675 __isl_give isl_point *isl_local_space_lift_point(__isl_take isl_local_space *ls,
1676 	__isl_take isl_point *pnt)
1677 {
1678 	isl_size n_local;
1679 	isl_space *space;
1680 	isl_local *local;
1681 	isl_vec *vec;
1682 
1683 	if (isl_local_space_check_has_space(ls, isl_point_peek_space(pnt)) < 0)
1684 		goto error;
1685 
1686 	local = isl_local_space_peek_local(ls);
1687 	n_local = isl_local_space_dim(ls, isl_dim_div);
1688 	if (n_local < 0)
1689 		goto error;
1690 
1691 	space = isl_point_take_space(pnt);
1692 	vec = isl_point_take_vec(pnt);
1693 
1694 	space = isl_space_lift(space, n_local);
1695 	vec = isl_local_extend_point_vec(local, vec);
1696 
1697 	pnt = isl_point_restore_vec(pnt, vec);
1698 	pnt = isl_point_restore_space(pnt, space);
1699 
1700 	isl_local_space_free(ls);
1701 
1702 	return pnt;
1703 error:
1704 	isl_local_space_free(ls);
1705 	isl_point_free(pnt);
1706 	return NULL;
1707 }
1708