xref: /netbsd-src/external/mit/isl/dist/isl_space.c (revision 5971e316fdea024efff6be8f03536623db06833e)
1 /*
2  * Copyright 2008-2009 Katholieke Universiteit Leuven
3  * Copyright 2010      INRIA Saclay
4  * Copyright 2013-2014 Ecole Normale Superieure
5  * Copyright 2018-2019 Cerebras Systems
6  *
7  * Use of this software is governed by the MIT license
8  *
9  * Written by Sven Verdoolaege, K.U.Leuven, Departement
10  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
11  * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
12  * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France
13  * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
14  * and Cerebras Systems, 175 S San Antonio Rd, Los Altos, CA, USA
15  */
16 
17 #include <stdlib.h>
18 #include <string.h>
19 #include <isl_space_private.h>
20 #include <isl_id_private.h>
21 #include <isl_reordering.h>
22 
isl_space_get_ctx(__isl_keep isl_space * space)23 isl_ctx *isl_space_get_ctx(__isl_keep isl_space *space)
24 {
25 	return space ? space->ctx : NULL;
26 }
27 
isl_space_alloc(isl_ctx * ctx,unsigned nparam,unsigned n_in,unsigned n_out)28 __isl_give isl_space *isl_space_alloc(isl_ctx *ctx,
29 			unsigned nparam, unsigned n_in, unsigned n_out)
30 {
31 	isl_space *space;
32 
33 	space = isl_alloc_type(ctx, struct isl_space);
34 	if (!space)
35 		return NULL;
36 
37 	space->ctx = ctx;
38 	isl_ctx_ref(ctx);
39 	space->ref = 1;
40 	space->nparam = nparam;
41 	space->n_in = n_in;
42 	space->n_out = n_out;
43 
44 	space->tuple_id[0] = NULL;
45 	space->tuple_id[1] = NULL;
46 
47 	space->nested[0] = NULL;
48 	space->nested[1] = NULL;
49 
50 	space->n_id = 0;
51 	space->ids = NULL;
52 
53 	return space;
54 }
55 
56 /* Mark the space as being that of a set, by setting the domain tuple
57  * to isl_id_none.
58  */
mark_as_set(__isl_take isl_space * space)59 static __isl_give isl_space *mark_as_set(__isl_take isl_space *space)
60 {
61 	space = isl_space_cow(space);
62 	if (!space)
63 		return NULL;
64 	space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none);
65 	return space;
66 }
67 
68 /* Is the space that of a set?
69  */
isl_space_is_set(__isl_keep isl_space * space)70 isl_bool isl_space_is_set(__isl_keep isl_space *space)
71 {
72 	if (!space)
73 		return isl_bool_error;
74 	if (space->n_in != 0 || space->nested[0])
75 		return isl_bool_false;
76 	if (space->tuple_id[0] != &isl_id_none)
77 		return isl_bool_false;
78 	return isl_bool_true;
79 }
80 
81 /* Check that "space" is a set space.
82  */
isl_space_check_is_set(__isl_keep isl_space * space)83 isl_stat isl_space_check_is_set(__isl_keep isl_space *space)
84 {
85 	isl_bool is_set;
86 
87 	is_set = isl_space_is_set(space);
88 	if (is_set < 0)
89 		return isl_stat_error;
90 	if (!is_set)
91 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
92 			"space is not a set", return isl_stat_error);
93 	return isl_stat_ok;
94 }
95 
96 /* Is the given space that of a map?
97  */
isl_space_is_map(__isl_keep isl_space * space)98 isl_bool isl_space_is_map(__isl_keep isl_space *space)
99 {
100 	int r;
101 
102 	if (!space)
103 		return isl_bool_error;
104 	r = space->tuple_id[0] != &isl_id_none &&
105 	    space->tuple_id[1] != &isl_id_none;
106 	return isl_bool_ok(r);
107 }
108 
109 /* Check that "space" is the space of a map.
110  */
isl_space_check_is_map(__isl_keep isl_space * space)111 static isl_stat isl_space_check_is_map(__isl_keep isl_space *space)
112 {
113 	isl_bool is_space;
114 
115 	is_space = isl_space_is_map(space);
116 	if (is_space < 0)
117 		return isl_stat_error;
118 	if (!is_space)
119 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
120 			"expecting map space", return isl_stat_error);
121 	return isl_stat_ok;
122 }
123 
124 /* Check that "space" is the space of a set wrapping a map space.
125  */
isl_space_check_is_wrapping(__isl_keep isl_space * space)126 isl_stat isl_space_check_is_wrapping(__isl_keep isl_space *space)
127 {
128 	isl_bool wrapping;
129 
130 	wrapping = isl_space_is_wrapping(space);
131 	if (wrapping < 0)
132 		return isl_stat_error;
133 	if (!wrapping)
134 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
135 			"not a product", return isl_stat_error);
136 	return isl_stat_ok;
137 }
138 
139 /* Check that "space" is the space of a map
140  * where the domain is a wrapped map space.
141  */
isl_space_check_domain_is_wrapping(__isl_keep isl_space * space)142 isl_stat isl_space_check_domain_is_wrapping(__isl_keep isl_space *space)
143 {
144 	isl_bool wrapping;
145 
146 	wrapping = isl_space_domain_is_wrapping(space);
147 	if (wrapping < 0)
148 		return isl_stat_error;
149 	if (!wrapping)
150 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
151 			"domain not a product", return isl_stat_error);
152 	return isl_stat_ok;
153 }
154 
155 /* Check that "space" is the space of a map
156  * where the range is a wrapped map space.
157  */
isl_space_check_range_is_wrapping(__isl_keep isl_space * space)158 isl_stat isl_space_check_range_is_wrapping(__isl_keep isl_space *space)
159 {
160 	isl_bool wrapping;
161 
162 	wrapping = isl_space_range_is_wrapping(space);
163 	if (wrapping < 0)
164 		return isl_stat_error;
165 	if (!wrapping)
166 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
167 			"range not a product", return isl_stat_error);
168 	return isl_stat_ok;
169 }
170 
isl_space_set_alloc(isl_ctx * ctx,unsigned nparam,unsigned dim)171 __isl_give isl_space *isl_space_set_alloc(isl_ctx *ctx,
172 			unsigned nparam, unsigned dim)
173 {
174 	isl_space *space;
175 	space = isl_space_alloc(ctx, nparam, 0, dim);
176 	space = mark_as_set(space);
177 	return space;
178 }
179 
180 /* Mark the space as being that of a parameter domain, by setting
181  * both tuples to isl_id_none.
182  */
mark_as_params(isl_space * space)183 static __isl_give isl_space *mark_as_params(isl_space *space)
184 {
185 	if (!space)
186 		return NULL;
187 	space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none);
188 	space = isl_space_set_tuple_id(space, isl_dim_out, &isl_id_none);
189 	return space;
190 }
191 
192 /* Is the space that of a parameter domain?
193  */
isl_space_is_params(__isl_keep isl_space * space)194 isl_bool isl_space_is_params(__isl_keep isl_space *space)
195 {
196 	if (!space)
197 		return isl_bool_error;
198 	if (space->n_in != 0 || space->nested[0] ||
199 	    space->n_out != 0 || space->nested[1])
200 		return isl_bool_false;
201 	if (space->tuple_id[0] != &isl_id_none)
202 		return isl_bool_false;
203 	if (space->tuple_id[1] != &isl_id_none)
204 		return isl_bool_false;
205 	return isl_bool_true;
206 }
207 
208 /* Create a space for a parameter domain.
209  */
isl_space_params_alloc(isl_ctx * ctx,unsigned nparam)210 __isl_give isl_space *isl_space_params_alloc(isl_ctx *ctx, unsigned nparam)
211 {
212 	isl_space *space;
213 	space = isl_space_alloc(ctx, nparam, 0, 0);
214 	space = mark_as_params(space);
215 	return space;
216 }
217 
218 /* Create a space for a parameter domain, without any parameters.
219  */
isl_space_unit(isl_ctx * ctx)220 __isl_give isl_space *isl_space_unit(isl_ctx *ctx)
221 {
222 	return isl_space_params_alloc(ctx, 0);
223 }
224 
global_pos(__isl_keep isl_space * space,enum isl_dim_type type,unsigned pos)225 static isl_size global_pos(__isl_keep isl_space *space,
226 				 enum isl_dim_type type, unsigned pos)
227 {
228 	if (isl_space_check_range(space, type, pos, 1) < 0)
229 		return isl_size_error;
230 
231 	switch (type) {
232 	case isl_dim_param:
233 		return pos;
234 	case isl_dim_in:
235 		return pos + space->nparam;
236 	case isl_dim_out:
237 		return pos + space->nparam + space->n_in;
238 	default:
239 		isl_assert(isl_space_get_ctx(space), 0, return isl_size_error);
240 	}
241 	return isl_size_error;
242 }
243 
244 /* Extend length of ids array to the total number of dimensions.
245  */
extend_ids(__isl_take isl_space * space)246 static __isl_give isl_space *extend_ids(__isl_take isl_space *space)
247 {
248 	isl_id **ids;
249 	int i;
250 	isl_size dim;
251 
252 	dim = isl_space_dim(space, isl_dim_all);
253 	if (dim < 0)
254 		return isl_space_free(space);
255 	if (dim <= space->n_id)
256 		return space;
257 
258 	if (!space->ids) {
259 		space->ids = isl_calloc_array(space->ctx, isl_id *, dim);
260 		if (!space->ids)
261 			goto error;
262 	} else {
263 		ids = isl_realloc_array(space->ctx, space->ids, isl_id *, dim);
264 		if (!ids)
265 			goto error;
266 		space->ids = ids;
267 		for (i = space->n_id; i < dim; ++i)
268 			space->ids[i] = NULL;
269 	}
270 
271 	space->n_id = dim;
272 
273 	return space;
274 error:
275 	isl_space_free(space);
276 	return NULL;
277 }
278 
set_id(__isl_take isl_space * space,enum isl_dim_type type,unsigned pos,__isl_take isl_id * id)279 static __isl_give isl_space *set_id(__isl_take isl_space *space,
280 	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
281 {
282 	isl_size gpos;
283 
284 	space = isl_space_cow(space);
285 
286 	gpos = global_pos(space, type, pos);
287 	if (gpos < 0)
288 		goto error;
289 
290 	if (gpos >= space->n_id) {
291 		if (!id)
292 			return space;
293 		space = extend_ids(space);
294 		if (!space)
295 			goto error;
296 	}
297 
298 	space->ids[gpos] = id;
299 
300 	return space;
301 error:
302 	isl_id_free(id);
303 	isl_space_free(space);
304 	return NULL;
305 }
306 
get_id(__isl_keep isl_space * space,enum isl_dim_type type,unsigned pos)307 static __isl_keep isl_id *get_id(__isl_keep isl_space *space,
308 				 enum isl_dim_type type, unsigned pos)
309 {
310 	isl_size gpos;
311 
312 	gpos = global_pos(space, type, pos);
313 	if (gpos < 0)
314 		return NULL;
315 	if (gpos >= space->n_id)
316 		return NULL;
317 	return space->ids[gpos];
318 }
319 
320 /* Return the nested space at the given position.
321  */
isl_space_peek_nested(__isl_keep isl_space * space,int pos)322 static __isl_keep isl_space *isl_space_peek_nested(__isl_keep isl_space *space,
323 	int pos)
324 {
325 	if (!space)
326 		return NULL;
327 	if (!space->nested[pos])
328 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
329 			"no nested space", return NULL);
330 	return space->nested[pos];
331 }
332 
offset(__isl_keep isl_space * space,enum isl_dim_type type)333 static unsigned offset(__isl_keep isl_space *space, enum isl_dim_type type)
334 {
335 	switch (type) {
336 	case isl_dim_param:	return 0;
337 	case isl_dim_in:	return space->nparam;
338 	case isl_dim_out:	return space->nparam + space->n_in;
339 	default:		return 0;
340 	}
341 }
342 
n(__isl_keep isl_space * space,enum isl_dim_type type)343 static unsigned n(__isl_keep isl_space *space, enum isl_dim_type type)
344 {
345 	switch (type) {
346 	case isl_dim_param:	return space->nparam;
347 	case isl_dim_in:	return space->n_in;
348 	case isl_dim_out:	return space->n_out;
349 	case isl_dim_all:
350 		return space->nparam + space->n_in + space->n_out;
351 	default:		return 0;
352 	}
353 }
354 
isl_space_dim(__isl_keep isl_space * space,enum isl_dim_type type)355 isl_size isl_space_dim(__isl_keep isl_space *space, enum isl_dim_type type)
356 {
357 	if (!space)
358 		return isl_size_error;
359 	return n(space, type);
360 }
361 
362 /* Return the dimensionality of tuple "inner" within the wrapped relation
363  * inside tuple "outer".
364  */
isl_space_wrapped_dim(__isl_keep isl_space * space,enum isl_dim_type outer,enum isl_dim_type inner)365 isl_size isl_space_wrapped_dim(__isl_keep isl_space *space,
366 	enum isl_dim_type outer, enum isl_dim_type inner)
367 {
368 	int pos;
369 
370 	if (!space)
371 		return isl_size_error;
372 	if (outer != isl_dim_in && outer != isl_dim_out)
373 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
374 			"only input, output and set tuples "
375 			"can have nested relations", return isl_size_error);
376 	pos = outer - isl_dim_in;
377 	return isl_space_dim(isl_space_peek_nested(space, pos), inner);
378 }
379 
isl_space_offset(__isl_keep isl_space * space,enum isl_dim_type type)380 isl_size isl_space_offset(__isl_keep isl_space *space, enum isl_dim_type type)
381 {
382 	if (!space)
383 		return isl_size_error;
384 	return offset(space, type);
385 }
386 
copy_ids(__isl_take isl_space * dst,enum isl_dim_type dst_type,unsigned offset,__isl_keep isl_space * src,enum isl_dim_type src_type)387 static __isl_give isl_space *copy_ids(__isl_take isl_space *dst,
388 	enum isl_dim_type dst_type, unsigned offset, __isl_keep isl_space *src,
389 	enum isl_dim_type src_type)
390 {
391 	int i;
392 	isl_id *id;
393 
394 	if (!dst)
395 		return NULL;
396 
397 	for (i = 0; i < n(src, src_type); ++i) {
398 		id = get_id(src, src_type, i);
399 		if (!id)
400 			continue;
401 		isl_id_free(get_id(dst, dst_type, offset + i));
402 		dst = set_id(dst, dst_type, offset + i, isl_id_copy(id));
403 		if (!dst)
404 			return NULL;
405 	}
406 	return dst;
407 }
408 
isl_space_dup(__isl_keep isl_space * space)409 __isl_give isl_space *isl_space_dup(__isl_keep isl_space *space)
410 {
411 	isl_space *dup;
412 	if (!space)
413 		return NULL;
414 	dup = isl_space_alloc(space->ctx,
415 				space->nparam, space->n_in, space->n_out);
416 	if (!dup)
417 		return NULL;
418 	if (space->tuple_id[0] &&
419 	    !(dup->tuple_id[0] = isl_id_copy(space->tuple_id[0])))
420 		goto error;
421 	if (space->tuple_id[1] &&
422 	    !(dup->tuple_id[1] = isl_id_copy(space->tuple_id[1])))
423 		goto error;
424 	if (space->nested[0] &&
425 	    !(dup->nested[0] = isl_space_copy(space->nested[0])))
426 		goto error;
427 	if (space->nested[1] &&
428 	    !(dup->nested[1] = isl_space_copy(space->nested[1])))
429 		goto error;
430 	if (!space->ids)
431 		return dup;
432 	dup = copy_ids(dup, isl_dim_param, 0, space, isl_dim_param);
433 	dup = copy_ids(dup, isl_dim_in, 0, space, isl_dim_in);
434 	dup = copy_ids(dup, isl_dim_out, 0, space, isl_dim_out);
435 	return dup;
436 error:
437 	isl_space_free(dup);
438 	return NULL;
439 }
440 
isl_space_cow(__isl_take isl_space * space)441 __isl_give isl_space *isl_space_cow(__isl_take isl_space *space)
442 {
443 	if (!space)
444 		return NULL;
445 
446 	if (space->ref == 1)
447 		return space;
448 	space->ref--;
449 	return isl_space_dup(space);
450 }
451 
isl_space_copy(__isl_keep isl_space * space)452 __isl_give isl_space *isl_space_copy(__isl_keep isl_space *space)
453 {
454 	if (!space)
455 		return NULL;
456 
457 	space->ref++;
458 	return space;
459 }
460 
isl_space_free(__isl_take isl_space * space)461 __isl_null isl_space *isl_space_free(__isl_take isl_space *space)
462 {
463 	int i;
464 
465 	if (!space)
466 		return NULL;
467 
468 	if (--space->ref > 0)
469 		return NULL;
470 
471 	isl_id_free(space->tuple_id[0]);
472 	isl_id_free(space->tuple_id[1]);
473 
474 	isl_space_free(space->nested[0]);
475 	isl_space_free(space->nested[1]);
476 
477 	for (i = 0; i < space->n_id; ++i)
478 		isl_id_free(space->ids[i]);
479 	free(space->ids);
480 	isl_ctx_deref(space->ctx);
481 
482 	free(space);
483 
484 	return NULL;
485 }
486 
487 /* Check if "s" is a valid dimension or tuple name.
488  * We currently only forbid names that look like a number.
489  *
490  * s is assumed to be non-NULL.
491  */
name_ok(isl_ctx * ctx,const char * s)492 static int name_ok(isl_ctx *ctx, const char *s)
493 {
494 	char *p;
495 
496 	strtol(s, &p, 0);
497 	if (p != s)
498 		isl_die(ctx, isl_error_invalid, "name looks like a number",
499 			return 0);
500 
501 	return 1;
502 }
503 
504 /* Return a copy of the nested space at the given position.
505  */
isl_space_get_nested(__isl_keep isl_space * space,int pos)506 static __isl_keep isl_space *isl_space_get_nested(__isl_keep isl_space *space,
507 	int pos)
508 {
509 	return isl_space_copy(isl_space_peek_nested(space, pos));
510 }
511 
512 /* Return the nested space at the given position.
513  * This may be either a copy or the nested space itself
514  * if there is only one reference to "space".
515  * This allows the nested space to be modified inplace
516  * if both "space" and the nested space have only a single reference.
517  * The caller is not allowed to modify "space" between this call and
518  * a subsequent call to isl_space_restore_nested.
519  * The only exception is that isl_space_free can be called instead.
520  */
isl_space_take_nested(__isl_keep isl_space * space,int pos)521 static __isl_give isl_space *isl_space_take_nested(__isl_keep isl_space *space,
522 	int pos)
523 {
524 	isl_space *nested;
525 
526 	if (!space)
527 		return NULL;
528 	if (space->ref != 1)
529 		return isl_space_get_nested(space, pos);
530 	nested = space->nested[pos];
531 	space->nested[pos] = NULL;
532 	return nested;
533 }
534 
535 /* Replace the nested space at the given position by "nested",
536  * where this nested space of "space" may be missing
537  * due to a preceding call to isl_space_take_nested.
538  * However, in this case, "space" only has a single reference and
539  * then the call to isl_space_cow has no effect.
540  */
isl_space_restore_nested(__isl_take isl_space * space,int pos,__isl_take isl_space * nested)541 static __isl_give isl_space *isl_space_restore_nested(
542 	__isl_take isl_space *space, int pos, __isl_take isl_space *nested)
543 {
544 	if (!space || !nested)
545 		goto error;
546 
547 	if (space->nested[pos] == nested) {
548 		isl_space_free(nested);
549 		return space;
550 	}
551 
552 	space = isl_space_cow(space);
553 	if (!space)
554 		goto error;
555 	isl_space_free(space->nested[pos]);
556 	space->nested[pos] = nested;
557 
558 	return space;
559 error:
560 	isl_space_free(space);
561 	isl_space_free(nested);
562 	return NULL;
563 }
564 
565 /* Is it possible for the given dimension type to have a tuple id?
566  */
space_can_have_id(__isl_keep isl_space * space,enum isl_dim_type type)567 static int space_can_have_id(__isl_keep isl_space *space,
568 	enum isl_dim_type type)
569 {
570 	if (!space)
571 		return 0;
572 	if (isl_space_is_params(space))
573 		isl_die(space->ctx, isl_error_invalid,
574 			"parameter spaces don't have tuple ids", return 0);
575 	if (isl_space_is_set(space) && type != isl_dim_set)
576 		isl_die(space->ctx, isl_error_invalid,
577 			"set spaces can only have a set id", return 0);
578 	if (type != isl_dim_in && type != isl_dim_out)
579 		isl_die(space->ctx, isl_error_invalid,
580 			"only input, output and set tuples can have ids",
581 			return 0);
582 
583 	return 1;
584 }
585 
586 /* Does the tuple have an id?
587  */
isl_space_has_tuple_id(__isl_keep isl_space * space,enum isl_dim_type type)588 isl_bool isl_space_has_tuple_id(__isl_keep isl_space *space,
589 	enum isl_dim_type type)
590 {
591 	if (!space_can_have_id(space, type))
592 		return isl_bool_error;
593 	return isl_bool_ok(space->tuple_id[type - isl_dim_in] != NULL);
594 }
595 
596 /* Does the domain tuple of the map space "space" have an identifier?
597  */
isl_space_has_domain_tuple_id(__isl_keep isl_space * space)598 isl_bool isl_space_has_domain_tuple_id(__isl_keep isl_space *space)
599 {
600 	if (isl_space_check_is_map(space) < 0)
601 		return isl_bool_error;
602 	return isl_space_has_tuple_id(space, isl_dim_in);
603 }
604 
605 /* Does the range tuple of the map space "space" have an identifier?
606  */
isl_space_has_range_tuple_id(__isl_keep isl_space * space)607 isl_bool isl_space_has_range_tuple_id(__isl_keep isl_space *space)
608 {
609 	if (isl_space_check_is_map(space) < 0)
610 		return isl_bool_error;
611 	return isl_space_has_tuple_id(space, isl_dim_out);
612 }
613 
isl_space_get_tuple_id(__isl_keep isl_space * space,enum isl_dim_type type)614 __isl_give isl_id *isl_space_get_tuple_id(__isl_keep isl_space *space,
615 	enum isl_dim_type type)
616 {
617 	int has_id;
618 
619 	if (!space)
620 		return NULL;
621 	has_id = isl_space_has_tuple_id(space, type);
622 	if (has_id < 0)
623 		return NULL;
624 	if (!has_id)
625 		isl_die(space->ctx, isl_error_invalid,
626 			"tuple has no id", return NULL);
627 	return isl_id_copy(space->tuple_id[type - isl_dim_in]);
628 }
629 
630 /* Return the identifier of the domain tuple of the map space "space",
631  * assuming it has one.
632  */
isl_space_get_domain_tuple_id(__isl_keep isl_space * space)633 __isl_give isl_id *isl_space_get_domain_tuple_id(
634 	__isl_keep isl_space *space)
635 {
636 	if (isl_space_check_is_map(space) < 0)
637 		return NULL;
638 	return isl_space_get_tuple_id(space, isl_dim_in);
639 }
640 
641 /* Return the identifier of the range tuple of the map space "space",
642  * assuming it has one.
643  */
isl_space_get_range_tuple_id(__isl_keep isl_space * space)644 __isl_give isl_id *isl_space_get_range_tuple_id(
645 	__isl_keep isl_space *space)
646 {
647 	if (isl_space_check_is_map(space) < 0)
648 		return NULL;
649 	return isl_space_get_tuple_id(space, isl_dim_out);
650 }
651 
isl_space_set_tuple_id(__isl_take isl_space * space,enum isl_dim_type type,__isl_take isl_id * id)652 __isl_give isl_space *isl_space_set_tuple_id(__isl_take isl_space *space,
653 	enum isl_dim_type type, __isl_take isl_id *id)
654 {
655 	space = isl_space_cow(space);
656 	if (!space || !id)
657 		goto error;
658 	if (type != isl_dim_in && type != isl_dim_out)
659 		isl_die(space->ctx, isl_error_invalid,
660 			"only input, output and set tuples can have names",
661 			goto error);
662 
663 	isl_id_free(space->tuple_id[type - isl_dim_in]);
664 	space->tuple_id[type - isl_dim_in] = id;
665 
666 	return space;
667 error:
668 	isl_id_free(id);
669 	isl_space_free(space);
670 	return NULL;
671 }
672 
673 /* Replace the identifier of the domain tuple of the map space "space"
674  * by "id".
675  */
isl_space_set_domain_tuple_id(__isl_take isl_space * space,__isl_take isl_id * id)676 __isl_give isl_space *isl_space_set_domain_tuple_id(
677 	__isl_take isl_space *space, __isl_take isl_id *id)
678 {
679 	if (isl_space_check_is_map(space) < 0)
680 		space = isl_space_free(space);
681 	return isl_space_set_tuple_id(space, isl_dim_in, id);
682 }
683 
684 /* Replace the identifier of the range tuple of the map space "space"
685  * by "id".
686  */
isl_space_set_range_tuple_id(__isl_take isl_space * space,__isl_take isl_id * id)687 __isl_give isl_space *isl_space_set_range_tuple_id(
688 	__isl_take isl_space *space, __isl_take isl_id *id)
689 {
690 	if (isl_space_check_is_map(space) < 0)
691 		space = isl_space_free(space);
692 	return isl_space_set_tuple_id(space, isl_dim_out, id);
693 }
694 
isl_space_reset_tuple_id(__isl_take isl_space * space,enum isl_dim_type type)695 __isl_give isl_space *isl_space_reset_tuple_id(__isl_take isl_space *space,
696 	enum isl_dim_type type)
697 {
698 	space = isl_space_cow(space);
699 	if (!space)
700 		return NULL;
701 	if (type != isl_dim_in && type != isl_dim_out)
702 		isl_die(space->ctx, isl_error_invalid,
703 			"only input, output and set tuples can have names",
704 			goto error);
705 
706 	isl_id_free(space->tuple_id[type - isl_dim_in]);
707 	space->tuple_id[type - isl_dim_in] = NULL;
708 
709 	return space;
710 error:
711 	isl_space_free(space);
712 	return NULL;
713 }
714 
715 /* Set the id of the given dimension of "space" to "id".
716  * If the dimension already has an id, then it is replaced.
717  * If the dimension is a parameter, then we need to change it
718  * in the nested spaces (if any) as well.
719  */
isl_space_set_dim_id(__isl_take isl_space * space,enum isl_dim_type type,unsigned pos,__isl_take isl_id * id)720 __isl_give isl_space *isl_space_set_dim_id(__isl_take isl_space *space,
721 	enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
722 {
723 	space = isl_space_cow(space);
724 	if (!space || !id)
725 		goto error;
726 
727 	if (type == isl_dim_param) {
728 		int i;
729 
730 		for (i = 0; i < 2; ++i) {
731 			if (!space->nested[i])
732 				continue;
733 			space->nested[i] =
734 				isl_space_set_dim_id(space->nested[i],
735 						type, pos, isl_id_copy(id));
736 			if (!space->nested[i])
737 				goto error;
738 		}
739 	}
740 
741 	isl_id_free(get_id(space, type, pos));
742 	return set_id(space, type, pos, id);
743 error:
744 	isl_id_free(id);
745 	isl_space_free(space);
746 	return NULL;
747 }
748 
749 /* Reset the id of the given dimension of "space".
750  * If the dimension already has an id, then it is removed.
751  * If the dimension is a parameter, then we need to reset it
752  * in the nested spaces (if any) as well.
753  */
isl_space_reset_dim_id(__isl_take isl_space * space,enum isl_dim_type type,unsigned pos)754 __isl_give isl_space *isl_space_reset_dim_id(__isl_take isl_space *space,
755 	enum isl_dim_type type, unsigned pos)
756 {
757 	space = isl_space_cow(space);
758 	if (!space)
759 		goto error;
760 
761 	if (type == isl_dim_param) {
762 		int i;
763 
764 		for (i = 0; i < 2; ++i) {
765 			if (!space->nested[i])
766 				continue;
767 			space->nested[i] =
768 				isl_space_reset_dim_id(space->nested[i],
769 							type, pos);
770 			if (!space->nested[i])
771 				goto error;
772 		}
773 	}
774 
775 	isl_id_free(get_id(space, type, pos));
776 	return set_id(space, type, pos, NULL);
777 error:
778 	isl_space_free(space);
779 	return NULL;
780 }
781 
isl_space_has_dim_id(__isl_keep isl_space * space,enum isl_dim_type type,unsigned pos)782 isl_bool isl_space_has_dim_id(__isl_keep isl_space *space,
783 	enum isl_dim_type type, unsigned pos)
784 {
785 	if (!space)
786 		return isl_bool_error;
787 	return isl_bool_ok(get_id(space, type, pos) != NULL);
788 }
789 
isl_space_get_dim_id(__isl_keep isl_space * space,enum isl_dim_type type,unsigned pos)790 __isl_give isl_id *isl_space_get_dim_id(__isl_keep isl_space *space,
791 	enum isl_dim_type type, unsigned pos)
792 {
793 	if (!space)
794 		return NULL;
795 	if (!get_id(space, type, pos))
796 		isl_die(space->ctx, isl_error_invalid,
797 			"dim has no id", return NULL);
798 	return isl_id_copy(get_id(space, type, pos));
799 }
800 
isl_space_set_tuple_name(__isl_take isl_space * space,enum isl_dim_type type,const char * s)801 __isl_give isl_space *isl_space_set_tuple_name(__isl_take isl_space *space,
802 	enum isl_dim_type type, const char *s)
803 {
804 	isl_id *id;
805 
806 	if (!space)
807 		return NULL;
808 
809 	if (!s)
810 		return isl_space_reset_tuple_id(space, type);
811 
812 	if (!name_ok(space->ctx, s))
813 		goto error;
814 
815 	id = isl_id_alloc(space->ctx, s, NULL);
816 	return isl_space_set_tuple_id(space, type, id);
817 error:
818 	isl_space_free(space);
819 	return NULL;
820 }
821 
822 /* Does the tuple have a name?
823  */
isl_space_has_tuple_name(__isl_keep isl_space * space,enum isl_dim_type type)824 isl_bool isl_space_has_tuple_name(__isl_keep isl_space *space,
825 	enum isl_dim_type type)
826 {
827 	isl_id *id;
828 
829 	if (!space_can_have_id(space, type))
830 		return isl_bool_error;
831 	id = space->tuple_id[type - isl_dim_in];
832 	return isl_bool_ok(id && id->name);
833 }
834 
isl_space_get_tuple_name(__isl_keep isl_space * space,enum isl_dim_type type)835 __isl_keep const char *isl_space_get_tuple_name(__isl_keep isl_space *space,
836 	 enum isl_dim_type type)
837 {
838 	isl_id *id;
839 	if (!space)
840 		return NULL;
841 	if (type != isl_dim_in && type != isl_dim_out)
842 		return NULL;
843 	id = space->tuple_id[type - isl_dim_in];
844 	return id ? id->name : NULL;
845 }
846 
isl_space_set_dim_name(__isl_take isl_space * space,enum isl_dim_type type,unsigned pos,const char * s)847 __isl_give isl_space *isl_space_set_dim_name(__isl_take isl_space *space,
848 				 enum isl_dim_type type, unsigned pos,
849 				 const char *s)
850 {
851 	isl_id *id;
852 
853 	if (!space)
854 		return NULL;
855 	if (!s)
856 		return isl_space_reset_dim_id(space, type, pos);
857 	if (!name_ok(space->ctx, s))
858 		goto error;
859 	id = isl_id_alloc(space->ctx, s, NULL);
860 	return isl_space_set_dim_id(space, type, pos, id);
861 error:
862 	isl_space_free(space);
863 	return NULL;
864 }
865 
866 /* Does the given dimension have a name?
867  */
isl_space_has_dim_name(__isl_keep isl_space * space,enum isl_dim_type type,unsigned pos)868 isl_bool isl_space_has_dim_name(__isl_keep isl_space *space,
869 	enum isl_dim_type type, unsigned pos)
870 {
871 	isl_id *id;
872 
873 	if (!space)
874 		return isl_bool_error;
875 	id = get_id(space, type, pos);
876 	return isl_bool_ok(id && id->name);
877 }
878 
isl_space_get_dim_name(__isl_keep isl_space * space,enum isl_dim_type type,unsigned pos)879 __isl_keep const char *isl_space_get_dim_name(__isl_keep isl_space *space,
880 				 enum isl_dim_type type, unsigned pos)
881 {
882 	isl_id *id = get_id(space, type, pos);
883 	return id ? id->name : NULL;
884 }
885 
isl_space_find_dim_by_id(__isl_keep isl_space * space,enum isl_dim_type type,__isl_keep isl_id * id)886 int isl_space_find_dim_by_id(__isl_keep isl_space *space,
887 	enum isl_dim_type type, __isl_keep isl_id *id)
888 {
889 	int i;
890 	isl_size offset;
891 	isl_size n;
892 
893 	n = isl_space_dim(space, type);
894 	offset = isl_space_offset(space, type);
895 	if (n < 0 || offset < 0 || !id)
896 		return -1;
897 
898 	for (i = 0; i < n && offset + i < space->n_id; ++i)
899 		if (space->ids[offset + i] == id)
900 			return i;
901 
902 	return -1;
903 }
904 
isl_space_find_dim_by_name(__isl_keep isl_space * space,enum isl_dim_type type,const char * name)905 int isl_space_find_dim_by_name(__isl_keep isl_space *space,
906 	enum isl_dim_type type, const char *name)
907 {
908 	int i;
909 	isl_size offset;
910 	isl_size n;
911 
912 	n = isl_space_dim(space, type);
913 	offset = isl_space_offset(space, type);
914 	if (n < 0 || offset < 0 || !name)
915 		return -1;
916 
917 	for (i = 0; i < n && offset + i < space->n_id; ++i) {
918 		isl_id *id = get_id(space, type, i);
919 		if (id && id->name && !strcmp(id->name, name))
920 			return i;
921 	}
922 
923 	return -1;
924 }
925 
926 /* Reset the user pointer on all identifiers of parameters and tuples
927  * of "space".
928  */
isl_space_reset_user(__isl_take isl_space * space)929 __isl_give isl_space *isl_space_reset_user(__isl_take isl_space *space)
930 {
931 	int i;
932 	isl_ctx *ctx;
933 	isl_id *id;
934 	const char *name;
935 
936 	if (!space)
937 		return NULL;
938 
939 	ctx = isl_space_get_ctx(space);
940 
941 	for (i = 0; i < space->nparam && i < space->n_id; ++i) {
942 		if (!isl_id_get_user(space->ids[i]))
943 			continue;
944 		space = isl_space_cow(space);
945 		if (!space)
946 			return NULL;
947 		name = isl_id_get_name(space->ids[i]);
948 		id = isl_id_alloc(ctx, name, NULL);
949 		isl_id_free(space->ids[i]);
950 		space->ids[i] = id;
951 		if (!id)
952 			return isl_space_free(space);
953 	}
954 
955 	for (i = 0; i < 2; ++i) {
956 		if (!space->tuple_id[i])
957 			continue;
958 		if (!isl_id_get_user(space->tuple_id[i]))
959 			continue;
960 		space = isl_space_cow(space);
961 		if (!space)
962 			return NULL;
963 		name = isl_id_get_name(space->tuple_id[i]);
964 		id = isl_id_alloc(ctx, name, NULL);
965 		isl_id_free(space->tuple_id[i]);
966 		space->tuple_id[i] = id;
967 		if (!id)
968 			return isl_space_free(space);
969 	}
970 
971 	for (i = 0; i < 2; ++i) {
972 		isl_space *nested;
973 
974 		if (!space->nested[i])
975 			continue;
976 		nested = isl_space_take_nested(space, i);
977 		nested = isl_space_reset_user(nested);
978 		space = isl_space_restore_nested(space, i, nested);
979 		if (!space)
980 			return NULL;
981 	}
982 
983 	return space;
984 }
985 
tuple_id(__isl_keep isl_space * space,enum isl_dim_type type)986 static __isl_keep isl_id *tuple_id(__isl_keep isl_space *space,
987 	enum isl_dim_type type)
988 {
989 	if (!space)
990 		return NULL;
991 	if (type == isl_dim_in)
992 		return space->tuple_id[0];
993 	if (type == isl_dim_out)
994 		return space->tuple_id[1];
995 	return NULL;
996 }
997 
nested(__isl_keep isl_space * space,enum isl_dim_type type)998 static __isl_keep isl_space *nested(__isl_keep isl_space *space,
999 	enum isl_dim_type type)
1000 {
1001 	if (!space)
1002 		return NULL;
1003 	if (type == isl_dim_in)
1004 		return space->nested[0];
1005 	if (type == isl_dim_out)
1006 		return space->nested[1];
1007 	return NULL;
1008 }
1009 
1010 /* Are the two spaces the same, apart from positions and names of parameters?
1011  */
isl_space_has_equal_tuples(__isl_keep isl_space * space1,__isl_keep isl_space * space2)1012 isl_bool isl_space_has_equal_tuples(__isl_keep isl_space *space1,
1013 	__isl_keep isl_space *space2)
1014 {
1015 	if (!space1 || !space2)
1016 		return isl_bool_error;
1017 	if (space1 == space2)
1018 		return isl_bool_true;
1019 	return isl_space_tuple_is_equal(space1, isl_dim_in,
1020 					space2, isl_dim_in) &&
1021 	       isl_space_tuple_is_equal(space1, isl_dim_out,
1022 					space2, isl_dim_out);
1023 }
1024 
1025 /* Check that a match involving "space" was successful.
1026  * That is, check that "match" is equal to isl_bool_true.
1027  */
check_match(__isl_keep isl_space * space,isl_bool match)1028 static isl_stat check_match(__isl_keep isl_space *space, isl_bool match)
1029 {
1030 	if (match < 0)
1031 		return isl_stat_error;
1032 	if (!match)
1033 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
1034 			"incompatible spaces", return isl_stat_error);
1035 
1036 	return isl_stat_ok;
1037 }
1038 
1039 /* Check that the two spaces are the same,
1040  * apart from positions and names of parameters.
1041  */
isl_space_check_equal_tuples(__isl_keep isl_space * space1,__isl_keep isl_space * space2)1042 isl_stat isl_space_check_equal_tuples(__isl_keep isl_space *space1,
1043 	__isl_keep isl_space *space2)
1044 {
1045 	isl_bool is_equal;
1046 
1047 	is_equal = isl_space_has_equal_tuples(space1, space2);
1048 	return check_match(space1, is_equal);
1049 }
1050 
1051 /* Check if the tuple of type "type1" of "space1" is the same as
1052  * the tuple of type "type2" of "space2".
1053  *
1054  * That is, check if the tuples have the same identifier, the same dimension
1055  * and the same internal structure.
1056  * The identifiers of the dimensions inside the tuples do not affect the result.
1057  *
1058  * Note that this function only checks the tuples themselves.
1059  * If nested tuples are involved, then we need to be careful not
1060  * to have result affected by possibly differing parameters
1061  * in those nested tuples.
1062  */
isl_space_tuple_is_equal(__isl_keep isl_space * space1,enum isl_dim_type type1,__isl_keep isl_space * space2,enum isl_dim_type type2)1063 isl_bool isl_space_tuple_is_equal(__isl_keep isl_space *space1,
1064 	enum isl_dim_type type1, __isl_keep isl_space *space2,
1065 	enum isl_dim_type type2)
1066 {
1067 	isl_id *id1, *id2;
1068 	isl_space *nested1, *nested2;
1069 
1070 	if (!space1 || !space2)
1071 		return isl_bool_error;
1072 
1073 	if (space1 == space2 && type1 == type2)
1074 		return isl_bool_true;
1075 
1076 	if (n(space1, type1) != n(space2, type2))
1077 		return isl_bool_false;
1078 	id1 = tuple_id(space1, type1);
1079 	id2 = tuple_id(space2, type2);
1080 	if (!id1 ^ !id2)
1081 		return isl_bool_false;
1082 	if (id1 && id1 != id2)
1083 		return isl_bool_false;
1084 	nested1 = nested(space1, type1);
1085 	nested2 = nested(space2, type2);
1086 	if (!nested1 ^ !nested2)
1087 		return isl_bool_false;
1088 	if (nested1 && !isl_space_has_equal_tuples(nested1, nested2))
1089 		return isl_bool_false;
1090 	return isl_bool_true;
1091 }
1092 
1093 /* Is the tuple "inner" within the wrapped relation inside tuple "outer"
1094  * of "space1" equal to tuple "type2" of "space2"?
1095  */
isl_space_wrapped_tuple_is_equal(__isl_keep isl_space * space1,enum isl_dim_type outer,enum isl_dim_type inner,__isl_keep isl_space * space2,enum isl_dim_type type2)1096 isl_bool isl_space_wrapped_tuple_is_equal(__isl_keep isl_space *space1,
1097 	enum isl_dim_type outer, enum isl_dim_type inner,
1098 	__isl_keep isl_space *space2, enum isl_dim_type type2)
1099 {
1100 	int pos;
1101 	isl_space *nested;
1102 
1103 	if (!space1)
1104 		return isl_bool_error;
1105 	if (outer != isl_dim_in && outer != isl_dim_out)
1106 		isl_die(isl_space_get_ctx(space1), isl_error_invalid,
1107 			"only input, output and set tuples "
1108 			"can have nested relations", return isl_bool_error);
1109 	pos = outer - isl_dim_in;
1110 	nested = isl_space_peek_nested(space1, pos);
1111 	return isl_space_tuple_is_equal(nested, inner, space2, type2);
1112 }
1113 
1114 /* Check that the tuple "inner" within the wrapped relation inside tuple "outer"
1115  * of "space1" is equal to tuple "type2" of "space2".
1116  */
isl_space_check_wrapped_tuple_is_equal(__isl_keep isl_space * space1,enum isl_dim_type outer,enum isl_dim_type inner,__isl_keep isl_space * space2,enum isl_dim_type type2)1117 isl_stat isl_space_check_wrapped_tuple_is_equal(__isl_keep isl_space *space1,
1118 	enum isl_dim_type outer, enum isl_dim_type inner,
1119 	__isl_keep isl_space *space2, enum isl_dim_type type2)
1120 {
1121 	isl_bool is_equal;
1122 
1123 	is_equal = isl_space_wrapped_tuple_is_equal(space1, outer, inner,
1124 							space2, type2);
1125 	return check_match(space1, is_equal);
1126 }
1127 
match(__isl_keep isl_space * space1,enum isl_dim_type type1,__isl_keep isl_space * space2,enum isl_dim_type type2)1128 static isl_bool match(__isl_keep isl_space *space1, enum isl_dim_type type1,
1129 	__isl_keep isl_space *space2, enum isl_dim_type type2)
1130 {
1131 	int i;
1132 	isl_bool equal;
1133 
1134 	if (!space1 || !space2)
1135 		return isl_bool_error;
1136 
1137 	if (space1 == space2 && type1 == type2)
1138 		return isl_bool_true;
1139 
1140 	equal = isl_space_tuple_is_equal(space1, type1, space2, type2);
1141 	if (equal < 0 || !equal)
1142 		return equal;
1143 
1144 	if (!space1->ids && !space2->ids)
1145 		return isl_bool_true;
1146 
1147 	for (i = 0; i < n(space1, type1); ++i) {
1148 		if (get_id(space1, type1, i) != get_id(space2, type2, i))
1149 			return isl_bool_false;
1150 	}
1151 	return isl_bool_true;
1152 }
1153 
1154 /* Do "space1" and "space2" have the same parameters?
1155  */
isl_space_has_equal_params(__isl_keep isl_space * space1,__isl_keep isl_space * space2)1156 isl_bool isl_space_has_equal_params(__isl_keep isl_space *space1,
1157 	__isl_keep isl_space *space2)
1158 {
1159 	return match(space1, isl_dim_param, space2, isl_dim_param);
1160 }
1161 
1162 /* Do "space1" and "space2" have the same identifiers for all
1163  * the tuple variables?
1164  */
isl_space_has_equal_ids(__isl_keep isl_space * space1,__isl_keep isl_space * space2)1165 isl_bool isl_space_has_equal_ids(__isl_keep isl_space *space1,
1166 	__isl_keep isl_space *space2)
1167 {
1168 	isl_bool equal;
1169 
1170 	equal = match(space1, isl_dim_in, space2, isl_dim_in);
1171 	if (equal < 0 || !equal)
1172 		return equal;
1173 	return match(space1, isl_dim_out, space2, isl_dim_out);
1174 }
1175 
isl_space_match(__isl_keep isl_space * space1,enum isl_dim_type type1,__isl_keep isl_space * space2,enum isl_dim_type type2)1176 isl_bool isl_space_match(__isl_keep isl_space *space1, enum isl_dim_type type1,
1177 	__isl_keep isl_space *space2, enum isl_dim_type type2)
1178 {
1179 	return match(space1, type1, space2, type2);
1180 }
1181 
get_ids(__isl_keep isl_space * space,enum isl_dim_type type,unsigned first,unsigned n,__isl_keep isl_id ** ids)1182 static void get_ids(__isl_keep isl_space *space, enum isl_dim_type type,
1183 	unsigned first, unsigned n, __isl_keep isl_id **ids)
1184 {
1185 	int i;
1186 
1187 	for (i = 0; i < n ; ++i)
1188 		ids[i] = get_id(space, type, first + i);
1189 }
1190 
space_extend(__isl_take isl_space * space,unsigned nparam,unsigned n_in,unsigned n_out)1191 static __isl_give isl_space *space_extend(__isl_take isl_space *space,
1192 			unsigned nparam, unsigned n_in, unsigned n_out)
1193 {
1194 	isl_id **ids = NULL;
1195 
1196 	if (!space)
1197 		return NULL;
1198 	if (space->nparam == nparam &&
1199 	    space->n_in == n_in && space->n_out == n_out)
1200 		return space;
1201 
1202 	isl_assert(space->ctx, space->nparam <= nparam, goto error);
1203 	isl_assert(space->ctx, space->n_in <= n_in, goto error);
1204 	isl_assert(space->ctx, space->n_out <= n_out, goto error);
1205 
1206 	space = isl_space_cow(space);
1207 	if (!space)
1208 		goto error;
1209 
1210 	if (space->ids) {
1211 		unsigned n;
1212 		n = nparam + n_in + n_out;
1213 		if (n < nparam || n < n_in || n < n_out)
1214 			isl_die(isl_space_get_ctx(space), isl_error_invalid,
1215 				"overflow in total number of dimensions",
1216 				goto error);
1217 		ids = isl_calloc_array(space->ctx, isl_id *, n);
1218 		if (!ids)
1219 			goto error;
1220 		get_ids(space, isl_dim_param, 0, space->nparam, ids);
1221 		get_ids(space, isl_dim_in, 0, space->n_in, ids + nparam);
1222 		get_ids(space, isl_dim_out, 0, space->n_out,
1223 			ids + nparam + n_in);
1224 		free(space->ids);
1225 		space->ids = ids;
1226 		space->n_id = nparam + n_in + n_out;
1227 	}
1228 	space->nparam = nparam;
1229 	space->n_in = n_in;
1230 	space->n_out = n_out;
1231 
1232 	return space;
1233 error:
1234 	free(ids);
1235 	isl_space_free(space);
1236 	return NULL;
1237 }
1238 
isl_space_extend(__isl_take isl_space * space,unsigned nparam,unsigned n_in,unsigned n_out)1239 __isl_give isl_space *isl_space_extend(__isl_take isl_space *space,
1240 	unsigned nparam, unsigned n_in, unsigned n_out)
1241 {
1242 	return space_extend(space, nparam, n_in, n_out);
1243 }
1244 
isl_space_add_dims(__isl_take isl_space * space,enum isl_dim_type type,unsigned n)1245 __isl_give isl_space *isl_space_add_dims(__isl_take isl_space *space,
1246 	enum isl_dim_type type, unsigned n)
1247 {
1248 	space = isl_space_reset(space, type);
1249 	if (!space)
1250 		return NULL;
1251 	switch (type) {
1252 	case isl_dim_param:
1253 		space = space_extend(space,
1254 				space->nparam + n, space->n_in, space->n_out);
1255 		if (space && space->nested[0] &&
1256 		    !(space->nested[0] = isl_space_add_dims(space->nested[0],
1257 						    isl_dim_param, n)))
1258 			goto error;
1259 		if (space && space->nested[1] &&
1260 		    !(space->nested[1] = isl_space_add_dims(space->nested[1],
1261 						    isl_dim_param, n)))
1262 			goto error;
1263 		return space;
1264 	case isl_dim_in:
1265 		return space_extend(space,
1266 				space->nparam, space->n_in + n, space->n_out);
1267 	case isl_dim_out:
1268 		return space_extend(space,
1269 				space->nparam, space->n_in, space->n_out + n);
1270 	default:
1271 		isl_die(space->ctx, isl_error_invalid,
1272 			"cannot add dimensions of specified type", goto error);
1273 	}
1274 error:
1275 	isl_space_free(space);
1276 	return NULL;
1277 }
1278 
1279 /* Add a parameter with identifier "id" to "space", provided
1280  * it does not already appear in "space".
1281  */
isl_space_add_param_id(__isl_take isl_space * space,__isl_take isl_id * id)1282 __isl_give isl_space *isl_space_add_param_id(__isl_take isl_space *space,
1283 	__isl_take isl_id *id)
1284 {
1285 	isl_size pos;
1286 
1287 	if (!space || !id)
1288 		goto error;
1289 
1290 	if (isl_space_find_dim_by_id(space, isl_dim_param, id) >= 0) {
1291 		isl_id_free(id);
1292 		return space;
1293 	}
1294 
1295 	pos = isl_space_dim(space, isl_dim_param);
1296 	if (pos < 0)
1297 		goto error;
1298 	space = isl_space_add_dims(space, isl_dim_param, 1);
1299 	space = isl_space_set_dim_id(space, isl_dim_param, pos, id);
1300 
1301 	return space;
1302 error:
1303 	isl_space_free(space);
1304 	isl_id_free(id);
1305 	return NULL;
1306 }
1307 
valid_dim_type(enum isl_dim_type type)1308 static int valid_dim_type(enum isl_dim_type type)
1309 {
1310 	switch (type) {
1311 	case isl_dim_param:
1312 	case isl_dim_in:
1313 	case isl_dim_out:
1314 		return 1;
1315 	default:
1316 		return 0;
1317 	}
1318 }
1319 
1320 #undef TYPE
1321 #define TYPE	isl_space
1322 #include "check_type_range_templ.c"
1323 
1324 /* Insert "n" dimensions of type "type" at position "pos".
1325  * If we are inserting parameters, then they are also inserted in
1326  * any nested spaces.
1327  */
isl_space_insert_dims(__isl_take isl_space * space,enum isl_dim_type type,unsigned pos,unsigned n)1328 __isl_give isl_space *isl_space_insert_dims(__isl_take isl_space *space,
1329 	enum isl_dim_type type, unsigned pos, unsigned n)
1330 {
1331 	isl_ctx *ctx;
1332 	isl_id **ids = NULL;
1333 
1334 	if (!space)
1335 		return NULL;
1336 	if (n == 0)
1337 		return isl_space_reset(space, type);
1338 
1339 	ctx = isl_space_get_ctx(space);
1340 	if (!valid_dim_type(type))
1341 		isl_die(ctx, isl_error_invalid,
1342 			"cannot insert dimensions of specified type",
1343 			goto error);
1344 
1345 	if (isl_space_check_range(space, type, pos, 0) < 0)
1346 		return isl_space_free(space);
1347 
1348 	space = isl_space_cow(space);
1349 	if (!space)
1350 		return NULL;
1351 
1352 	if (space->ids) {
1353 		enum isl_dim_type t, o = isl_dim_param;
1354 		int off;
1355 		int s[3];
1356 		ids = isl_calloc_array(ctx, isl_id *,
1357 			     space->nparam + space->n_in + space->n_out + n);
1358 		if (!ids)
1359 			goto error;
1360 		off = 0;
1361 		s[isl_dim_param - o] = space->nparam;
1362 		s[isl_dim_in - o] = space->n_in;
1363 		s[isl_dim_out - o] = space->n_out;
1364 		for (t = isl_dim_param; t <= isl_dim_out; ++t) {
1365 			if (t != type) {
1366 				get_ids(space, t, 0, s[t - o], ids + off);
1367 				off += s[t - o];
1368 			} else {
1369 				get_ids(space, t, 0, pos, ids + off);
1370 				off += pos + n;
1371 				get_ids(space, t, pos, s[t - o] - pos,
1372 					ids + off);
1373 				off += s[t - o] - pos;
1374 			}
1375 		}
1376 		free(space->ids);
1377 		space->ids = ids;
1378 		space->n_id = space->nparam + space->n_in + space->n_out + n;
1379 	}
1380 	switch (type) {
1381 	case isl_dim_param:	space->nparam += n; break;
1382 	case isl_dim_in:	space->n_in += n; break;
1383 	case isl_dim_out:	space->n_out += n; break;
1384 	default:		;
1385 	}
1386 	space = isl_space_reset(space, type);
1387 
1388 	if (type == isl_dim_param) {
1389 		if (space && space->nested[0] &&
1390 		    !(space->nested[0] = isl_space_insert_dims(space->nested[0],
1391 						    isl_dim_param, pos, n)))
1392 			goto error;
1393 		if (space && space->nested[1] &&
1394 		    !(space->nested[1] = isl_space_insert_dims(space->nested[1],
1395 						    isl_dim_param, pos, n)))
1396 			goto error;
1397 	}
1398 
1399 	return space;
1400 error:
1401 	isl_space_free(space);
1402 	return NULL;
1403 }
1404 
isl_space_move_dims(__isl_take isl_space * space,enum isl_dim_type dst_type,unsigned dst_pos,enum isl_dim_type src_type,unsigned src_pos,unsigned n)1405 __isl_give isl_space *isl_space_move_dims(__isl_take isl_space *space,
1406 	enum isl_dim_type dst_type, unsigned dst_pos,
1407 	enum isl_dim_type src_type, unsigned src_pos, unsigned n)
1408 {
1409 	int i;
1410 
1411 	space = isl_space_reset(space, src_type);
1412 	space = isl_space_reset(space, dst_type);
1413 	if (!space)
1414 		return NULL;
1415 	if (n == 0)
1416 		return space;
1417 
1418 	if (isl_space_check_range(space, src_type, src_pos, n) < 0)
1419 		return isl_space_free(space);
1420 
1421 	if (dst_type == src_type && dst_pos == src_pos)
1422 		return space;
1423 
1424 	isl_assert(space->ctx, dst_type != src_type, goto error);
1425 
1426 	space = isl_space_cow(space);
1427 	if (!space)
1428 		return NULL;
1429 
1430 	if (space->ids) {
1431 		isl_id **ids;
1432 		enum isl_dim_type t, o = isl_dim_param;
1433 		int off;
1434 		int s[3];
1435 		ids = isl_calloc_array(space->ctx, isl_id *,
1436 				 space->nparam + space->n_in + space->n_out);
1437 		if (!ids)
1438 			goto error;
1439 		off = 0;
1440 		s[isl_dim_param - o] = space->nparam;
1441 		s[isl_dim_in - o] = space->n_in;
1442 		s[isl_dim_out - o] = space->n_out;
1443 		for (t = isl_dim_param; t <= isl_dim_out; ++t) {
1444 			if (t == dst_type) {
1445 				get_ids(space, t, 0, dst_pos, ids + off);
1446 				off += dst_pos;
1447 				get_ids(space, src_type, src_pos, n, ids + off);
1448 				off += n;
1449 				get_ids(space, t, dst_pos, s[t - o] - dst_pos,
1450 						ids + off);
1451 				off += s[t - o] - dst_pos;
1452 			} else if (t == src_type) {
1453 				get_ids(space, t, 0, src_pos, ids + off);
1454 				off += src_pos;
1455 				get_ids(space, t, src_pos + n,
1456 					    s[t - o] - src_pos - n, ids + off);
1457 				off += s[t - o] - src_pos - n;
1458 			} else {
1459 				get_ids(space, t, 0, s[t - o], ids + off);
1460 				off += s[t - o];
1461 			}
1462 		}
1463 		free(space->ids);
1464 		space->ids = ids;
1465 		space->n_id = space->nparam + space->n_in + space->n_out;
1466 	}
1467 
1468 	switch (dst_type) {
1469 	case isl_dim_param:	space->nparam += n; break;
1470 	case isl_dim_in:	space->n_in += n; break;
1471 	case isl_dim_out:	space->n_out += n; break;
1472 	default:		;
1473 	}
1474 
1475 	switch (src_type) {
1476 	case isl_dim_param:	space->nparam -= n; break;
1477 	case isl_dim_in:	space->n_in -= n; break;
1478 	case isl_dim_out:	space->n_out -= n; break;
1479 	default:		;
1480 	}
1481 
1482 	if (dst_type != isl_dim_param && src_type != isl_dim_param)
1483 		return space;
1484 
1485 	for (i = 0; i < 2; ++i) {
1486 		isl_space *nested;
1487 
1488 		if (!space->nested[i])
1489 			continue;
1490 		nested = isl_space_take_nested(space, i);
1491 		nested = isl_space_replace_params(nested, space);
1492 		space = isl_space_restore_nested(space, i, nested);
1493 		if (!space)
1494 			return NULL;
1495 	}
1496 
1497 	return space;
1498 error:
1499 	isl_space_free(space);
1500 	return NULL;
1501 }
1502 
1503 /* Check that "space1" and "space2" have the same parameters,
1504  * reporting an error if they do not.
1505  */
isl_space_check_equal_params(__isl_keep isl_space * space1,__isl_keep isl_space * space2)1506 isl_stat isl_space_check_equal_params(__isl_keep isl_space *space1,
1507 	__isl_keep isl_space *space2)
1508 {
1509 	isl_bool equal;
1510 
1511 	equal = isl_space_has_equal_params(space1, space2);
1512 	if (equal < 0)
1513 		return isl_stat_error;
1514 	if (!equal)
1515 		isl_die(isl_space_get_ctx(space1), isl_error_invalid,
1516 			"parameters need to match", return isl_stat_error);
1517 	return isl_stat_ok;
1518 }
1519 
isl_space_join(__isl_take isl_space * left,__isl_take isl_space * right)1520 __isl_give isl_space *isl_space_join(__isl_take isl_space *left,
1521 	__isl_take isl_space *right)
1522 {
1523 	isl_space *space;
1524 
1525 	if (isl_space_check_equal_params(left, right) < 0)
1526 		goto error;
1527 
1528 	isl_assert(left->ctx,
1529 		isl_space_tuple_is_equal(left, isl_dim_out, right, isl_dim_in),
1530 		goto error);
1531 
1532 	space = isl_space_alloc(left->ctx,
1533 				left->nparam, left->n_in, right->n_out);
1534 	if (!space)
1535 		goto error;
1536 
1537 	space = copy_ids(space, isl_dim_param, 0, left, isl_dim_param);
1538 	space = copy_ids(space, isl_dim_in, 0, left, isl_dim_in);
1539 	space = copy_ids(space, isl_dim_out, 0, right, isl_dim_out);
1540 
1541 	if (space && left->tuple_id[0] &&
1542 	    !(space->tuple_id[0] = isl_id_copy(left->tuple_id[0])))
1543 		goto error;
1544 	if (space && right->tuple_id[1] &&
1545 	    !(space->tuple_id[1] = isl_id_copy(right->tuple_id[1])))
1546 		goto error;
1547 	if (space && left->nested[0] &&
1548 	    !(space->nested[0] = isl_space_copy(left->nested[0])))
1549 		goto error;
1550 	if (space && right->nested[1] &&
1551 	    !(space->nested[1] = isl_space_copy(right->nested[1])))
1552 		goto error;
1553 
1554 	isl_space_free(left);
1555 	isl_space_free(right);
1556 
1557 	return space;
1558 error:
1559 	isl_space_free(left);
1560 	isl_space_free(right);
1561 	return NULL;
1562 }
1563 
1564 /* Given two map spaces { A -> C } and { B -> D }, construct the space
1565  * { [A -> B] -> [C -> D] }.
1566  * Given two set spaces { A } and { B }, construct the space { [A -> B] }.
1567  */
isl_space_product(__isl_take isl_space * left,__isl_take isl_space * right)1568 __isl_give isl_space *isl_space_product(__isl_take isl_space *left,
1569 	__isl_take isl_space *right)
1570 {
1571 	isl_space *dom1, *dom2, *nest1, *nest2;
1572 	int is_set;
1573 
1574 	if (!left || !right)
1575 		goto error;
1576 
1577 	is_set = isl_space_is_set(left);
1578 	if (is_set != isl_space_is_set(right))
1579 		isl_die(isl_space_get_ctx(left), isl_error_invalid,
1580 			"expecting either two set spaces or two map spaces",
1581 			goto error);
1582 	if (is_set)
1583 		return isl_space_range_product(left, right);
1584 
1585 	if (isl_space_check_equal_params(left, right) < 0)
1586 		goto error;
1587 
1588 	dom1 = isl_space_domain(isl_space_copy(left));
1589 	dom2 = isl_space_domain(isl_space_copy(right));
1590 	nest1 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
1591 
1592 	dom1 = isl_space_range(left);
1593 	dom2 = isl_space_range(right);
1594 	nest2 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
1595 
1596 	return isl_space_join(isl_space_reverse(nest1), nest2);
1597 error:
1598 	isl_space_free(left);
1599 	isl_space_free(right);
1600 	return NULL;
1601 }
1602 
1603 /* Given two spaces { A -> C } and { B -> C }, construct the space
1604  * { [A -> B] -> C }
1605  */
isl_space_domain_product(__isl_take isl_space * left,__isl_take isl_space * right)1606 __isl_give isl_space *isl_space_domain_product(__isl_take isl_space *left,
1607 	__isl_take isl_space *right)
1608 {
1609 	isl_space *ran, *dom1, *dom2, *nest;
1610 
1611 	if (isl_space_check_equal_params(left, right) < 0)
1612 		goto error;
1613 
1614 	if (!isl_space_tuple_is_equal(left, isl_dim_out, right, isl_dim_out))
1615 		isl_die(left->ctx, isl_error_invalid,
1616 			"ranges need to match", goto error);
1617 
1618 	ran = isl_space_range(isl_space_copy(left));
1619 
1620 	dom1 = isl_space_domain(left);
1621 	dom2 = isl_space_domain(right);
1622 	nest = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
1623 
1624 	return isl_space_join(isl_space_reverse(nest), ran);
1625 error:
1626 	isl_space_free(left);
1627 	isl_space_free(right);
1628 	return NULL;
1629 }
1630 
isl_space_range_product(__isl_take isl_space * left,__isl_take isl_space * right)1631 __isl_give isl_space *isl_space_range_product(__isl_take isl_space *left,
1632 	__isl_take isl_space *right)
1633 {
1634 	isl_space *dom, *ran1, *ran2, *nest;
1635 
1636 	if (isl_space_check_equal_params(left, right) < 0)
1637 		goto error;
1638 
1639 	if (!isl_space_tuple_is_equal(left, isl_dim_in, right, isl_dim_in))
1640 		isl_die(left->ctx, isl_error_invalid,
1641 			"domains need to match", goto error);
1642 
1643 	dom = isl_space_domain(isl_space_copy(left));
1644 
1645 	ran1 = isl_space_range(left);
1646 	ran2 = isl_space_range(right);
1647 	nest = isl_space_wrap(isl_space_join(isl_space_reverse(ran1), ran2));
1648 
1649 	return isl_space_join(isl_space_reverse(dom), nest);
1650 error:
1651 	isl_space_free(left);
1652 	isl_space_free(right);
1653 	return NULL;
1654 }
1655 
1656 /* Given a space of the form [A -> B] -> C, return the space A -> C.
1657  */
isl_space_domain_factor_domain(__isl_take isl_space * space)1658 __isl_give isl_space *isl_space_domain_factor_domain(
1659 	__isl_take isl_space *space)
1660 {
1661 	isl_space *nested;
1662 	isl_space *domain;
1663 
1664 	if (isl_space_check_domain_is_wrapping(space) < 0)
1665 		return isl_space_free(space);
1666 
1667 	nested = space->nested[0];
1668 	domain = isl_space_copy(space);
1669 	domain = isl_space_drop_dims(domain, isl_dim_in,
1670 					nested->n_in, nested->n_out);
1671 	if (!domain)
1672 		return isl_space_free(space);
1673 	if (nested->tuple_id[0]) {
1674 		domain->tuple_id[0] = isl_id_copy(nested->tuple_id[0]);
1675 		if (!domain->tuple_id[0])
1676 			goto error;
1677 	}
1678 	if (nested->nested[0]) {
1679 		domain->nested[0] = isl_space_copy(nested->nested[0]);
1680 		if (!domain->nested[0])
1681 			goto error;
1682 	}
1683 
1684 	isl_space_free(space);
1685 	return domain;
1686 error:
1687 	isl_space_free(space);
1688 	isl_space_free(domain);
1689 	return NULL;
1690 }
1691 
1692 /* Given a space of the form [A -> B] -> C, return the space B -> C.
1693  */
isl_space_domain_factor_range(__isl_take isl_space * space)1694 __isl_give isl_space *isl_space_domain_factor_range(
1695 	__isl_take isl_space *space)
1696 {
1697 	isl_space *nested;
1698 	isl_space *range;
1699 
1700 	if (isl_space_check_domain_is_wrapping(space) < 0)
1701 		return isl_space_free(space);
1702 
1703 	nested = space->nested[0];
1704 	range = isl_space_copy(space);
1705 	range = isl_space_drop_dims(range, isl_dim_in, 0, nested->n_in);
1706 	if (!range)
1707 		return isl_space_free(space);
1708 	if (nested->tuple_id[1]) {
1709 		range->tuple_id[0] = isl_id_copy(nested->tuple_id[1]);
1710 		if (!range->tuple_id[0])
1711 			goto error;
1712 	}
1713 	if (nested->nested[1]) {
1714 		range->nested[0] = isl_space_copy(nested->nested[1]);
1715 		if (!range->nested[0])
1716 			goto error;
1717 	}
1718 
1719 	isl_space_free(space);
1720 	return range;
1721 error:
1722 	isl_space_free(space);
1723 	isl_space_free(range);
1724 	return NULL;
1725 }
1726 
1727 /* Internal function that selects the domain of the map that is
1728  * embedded in either a set space or the range of a map space.
1729  * In particular, given a space of the form [A -> B], return the space A.
1730  * Given a space of the form A -> [B -> C], return the space A -> B.
1731  */
range_factor_domain(__isl_take isl_space * space)1732 static __isl_give isl_space *range_factor_domain(__isl_take isl_space *space)
1733 {
1734 	isl_space *nested;
1735 	isl_space *domain;
1736 
1737 	if (!space)
1738 		return NULL;
1739 
1740 	nested = space->nested[1];
1741 	domain = isl_space_copy(space);
1742 	domain = isl_space_drop_dims(domain, isl_dim_out,
1743 					nested->n_in, nested->n_out);
1744 	if (!domain)
1745 		return isl_space_free(space);
1746 	if (nested->tuple_id[0]) {
1747 		domain->tuple_id[1] = isl_id_copy(nested->tuple_id[0]);
1748 		if (!domain->tuple_id[1])
1749 			goto error;
1750 	}
1751 	if (nested->nested[0]) {
1752 		domain->nested[1] = isl_space_copy(nested->nested[0]);
1753 		if (!domain->nested[1])
1754 			goto error;
1755 	}
1756 
1757 	isl_space_free(space);
1758 	return domain;
1759 error:
1760 	isl_space_free(space);
1761 	isl_space_free(domain);
1762 	return NULL;
1763 }
1764 
1765 /* Given a space of the form A -> [B -> C], return the space A -> B.
1766  */
isl_space_range_factor_domain(__isl_take isl_space * space)1767 __isl_give isl_space *isl_space_range_factor_domain(
1768 	__isl_take isl_space *space)
1769 {
1770 	if (isl_space_check_range_is_wrapping(space) < 0)
1771 		return isl_space_free(space);
1772 
1773 	return range_factor_domain(space);
1774 }
1775 
1776 /* Given a space of the form [A -> B], return the space A.
1777  */
set_factor_domain(__isl_take isl_space * space)1778 static __isl_give isl_space *set_factor_domain(__isl_take isl_space *space)
1779 {
1780 	if (!space)
1781 		return NULL;
1782 	if (!isl_space_is_wrapping(space))
1783 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
1784 			"not a product", return isl_space_free(space));
1785 
1786 	return range_factor_domain(space);
1787 }
1788 
1789 /* Given a space of the form [A -> B] -> [C -> D], return the space A -> C.
1790  * Given a space of the form [A -> B], return the space A.
1791  */
isl_space_factor_domain(__isl_take isl_space * space)1792 __isl_give isl_space *isl_space_factor_domain(__isl_take isl_space *space)
1793 {
1794 	if (!space)
1795 		return NULL;
1796 	if (isl_space_is_set(space))
1797 		return set_factor_domain(space);
1798 	space = isl_space_domain_factor_domain(space);
1799 	space = isl_space_range_factor_domain(space);
1800 	return space;
1801 }
1802 
1803 /* Internal function that selects the range of the map that is
1804  * embedded in either a set space or the range of a map space.
1805  * In particular, given a space of the form [A -> B], return the space B.
1806  * Given a space of the form A -> [B -> C], return the space A -> C.
1807  */
range_factor_range(__isl_take isl_space * space)1808 static __isl_give isl_space *range_factor_range(__isl_take isl_space *space)
1809 {
1810 	isl_space *nested;
1811 	isl_space *range;
1812 
1813 	if (!space)
1814 		return NULL;
1815 
1816 	nested = space->nested[1];
1817 	range = isl_space_copy(space);
1818 	range = isl_space_drop_dims(range, isl_dim_out, 0, nested->n_in);
1819 	if (!range)
1820 		return isl_space_free(space);
1821 	if (nested->tuple_id[1]) {
1822 		range->tuple_id[1] = isl_id_copy(nested->tuple_id[1]);
1823 		if (!range->tuple_id[1])
1824 			goto error;
1825 	}
1826 	if (nested->nested[1]) {
1827 		range->nested[1] = isl_space_copy(nested->nested[1]);
1828 		if (!range->nested[1])
1829 			goto error;
1830 	}
1831 
1832 	isl_space_free(space);
1833 	return range;
1834 error:
1835 	isl_space_free(space);
1836 	isl_space_free(range);
1837 	return NULL;
1838 }
1839 
1840 /* Given a space of the form A -> [B -> C], return the space A -> C.
1841  */
isl_space_range_factor_range(__isl_take isl_space * space)1842 __isl_give isl_space *isl_space_range_factor_range(
1843 	__isl_take isl_space *space)
1844 {
1845 	if (isl_space_check_range_is_wrapping(space) < 0)
1846 		return isl_space_free(space);
1847 
1848 	return range_factor_range(space);
1849 }
1850 
1851 /* Given a space of the form [A -> B], return the space B.
1852  */
set_factor_range(__isl_take isl_space * space)1853 static __isl_give isl_space *set_factor_range(__isl_take isl_space *space)
1854 {
1855 	if (!space)
1856 		return NULL;
1857 	if (!isl_space_is_wrapping(space))
1858 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
1859 			"not a product", return isl_space_free(space));
1860 
1861 	return range_factor_range(space);
1862 }
1863 
1864 /* Given a space of the form [A -> B] -> [C -> D], return the space B -> D.
1865  * Given a space of the form [A -> B], return the space B.
1866  */
isl_space_factor_range(__isl_take isl_space * space)1867 __isl_give isl_space *isl_space_factor_range(__isl_take isl_space *space)
1868 {
1869 	if (!space)
1870 		return NULL;
1871 	if (isl_space_is_set(space))
1872 		return set_factor_range(space);
1873 	space = isl_space_domain_factor_range(space);
1874 	space = isl_space_range_factor_range(space);
1875 	return space;
1876 }
1877 
1878 /* Given a space of the form [A -> B] -> C, return the space A.
1879  */
isl_space_domain_wrapped_domain(__isl_take isl_space * space)1880 __isl_give isl_space *isl_space_domain_wrapped_domain(
1881 	__isl_take isl_space *space)
1882 {
1883 	return isl_space_factor_domain(isl_space_domain(space));
1884 }
1885 
1886 /* Given a space of the form [A -> B] -> C, return the space B.
1887  */
isl_space_domain_wrapped_range(__isl_take isl_space * space)1888 __isl_give isl_space *isl_space_domain_wrapped_range(
1889 	__isl_take isl_space *space)
1890 {
1891 	return isl_space_factor_range(isl_space_domain(space));
1892 }
1893 
1894 /* Given a space of the form A -> [B -> C], return the space B.
1895  */
isl_space_range_wrapped_domain(__isl_take isl_space * space)1896 __isl_give isl_space *isl_space_range_wrapped_domain(
1897 	__isl_take isl_space *space)
1898 {
1899 	return isl_space_factor_domain(isl_space_range(space));
1900 }
1901 
1902 /* Given a space of the form A -> [B -> C], return the space C.
1903  */
isl_space_range_wrapped_range(__isl_take isl_space * space)1904 __isl_give isl_space *isl_space_range_wrapped_range(
1905 	__isl_take isl_space *space)
1906 {
1907 	return isl_space_factor_range(isl_space_range(space));
1908 }
1909 
isl_space_map_from_set(__isl_take isl_space * space)1910 __isl_give isl_space *isl_space_map_from_set(__isl_take isl_space *space)
1911 {
1912 	isl_ctx *ctx;
1913 	isl_id **ids = NULL;
1914 	int n_id;
1915 
1916 	if (!space)
1917 		return NULL;
1918 	ctx = isl_space_get_ctx(space);
1919 	if (!isl_space_is_set(space))
1920 		isl_die(ctx, isl_error_invalid, "not a set space", goto error);
1921 	space = isl_space_cow(space);
1922 	if (!space)
1923 		return NULL;
1924 	n_id = space->nparam + space->n_out + space->n_out;
1925 	if (n_id > 0 && space->ids) {
1926 		ids = isl_calloc_array(space->ctx, isl_id *, n_id);
1927 		if (!ids)
1928 			goto error;
1929 		get_ids(space, isl_dim_param, 0, space->nparam, ids);
1930 		get_ids(space, isl_dim_out, 0, space->n_out,
1931 			ids + space->nparam);
1932 	}
1933 	space->n_in = space->n_out;
1934 	if (ids) {
1935 		free(space->ids);
1936 		space->ids = ids;
1937 		space->n_id = n_id;
1938 		space = copy_ids(space, isl_dim_out, 0, space, isl_dim_in);
1939 	}
1940 	isl_id_free(space->tuple_id[0]);
1941 	space->tuple_id[0] = isl_id_copy(space->tuple_id[1]);
1942 	isl_space_free(space->nested[0]);
1943 	space->nested[0] = isl_space_copy(space->nested[1]);
1944 	return space;
1945 error:
1946 	isl_space_free(space);
1947 	return NULL;
1948 }
1949 
isl_space_map_from_domain_and_range(__isl_take isl_space * domain,__isl_take isl_space * range)1950 __isl_give isl_space *isl_space_map_from_domain_and_range(
1951 	__isl_take isl_space *domain, __isl_take isl_space *range)
1952 {
1953 	if (!domain || !range)
1954 		goto error;
1955 	if (!isl_space_is_set(domain))
1956 		isl_die(isl_space_get_ctx(domain), isl_error_invalid,
1957 			"domain is not a set space", goto error);
1958 	if (!isl_space_is_set(range))
1959 		isl_die(isl_space_get_ctx(range), isl_error_invalid,
1960 			"range is not a set space", goto error);
1961 	return isl_space_join(isl_space_reverse(domain), range);
1962 error:
1963 	isl_space_free(domain);
1964 	isl_space_free(range);
1965 	return NULL;
1966 }
1967 
set_ids(__isl_take isl_space * space,enum isl_dim_type type,unsigned first,unsigned n,__isl_take isl_id ** ids)1968 static __isl_give isl_space *set_ids(__isl_take isl_space *space,
1969 	enum isl_dim_type type,
1970 	unsigned first, unsigned n, __isl_take isl_id **ids)
1971 {
1972 	int i;
1973 
1974 	for (i = 0; i < n ; ++i)
1975 		space = set_id(space, type, first + i, ids[i]);
1976 
1977 	return space;
1978 }
1979 
isl_space_reverse(__isl_take isl_space * space)1980 __isl_give isl_space *isl_space_reverse(__isl_take isl_space *space)
1981 {
1982 	unsigned t;
1983 	isl_bool equal;
1984 	isl_space *nested;
1985 	isl_id **ids = NULL;
1986 	isl_id *id;
1987 
1988 	equal = match(space, isl_dim_in, space, isl_dim_out);
1989 	if (equal < 0)
1990 		return isl_space_free(space);
1991 	if (equal)
1992 		return space;
1993 
1994 	space = isl_space_cow(space);
1995 	if (!space)
1996 		return NULL;
1997 
1998 	id = space->tuple_id[0];
1999 	space->tuple_id[0] = space->tuple_id[1];
2000 	space->tuple_id[1] = id;
2001 
2002 	nested = space->nested[0];
2003 	space->nested[0] = space->nested[1];
2004 	space->nested[1] = nested;
2005 
2006 	if (space->ids) {
2007 		int n_id = space->n_in + space->n_out;
2008 		ids = isl_alloc_array(space->ctx, isl_id *, n_id);
2009 		if (n_id && !ids)
2010 			goto error;
2011 		get_ids(space, isl_dim_in, 0, space->n_in, ids);
2012 		get_ids(space, isl_dim_out, 0, space->n_out, ids + space->n_in);
2013 	}
2014 
2015 	t = space->n_in;
2016 	space->n_in = space->n_out;
2017 	space->n_out = t;
2018 
2019 	if (space->ids) {
2020 		space = set_ids(space, isl_dim_out, 0, space->n_out, ids);
2021 		space = set_ids(space, isl_dim_in, 0, space->n_in,
2022 				ids + space->n_out);
2023 		free(ids);
2024 	}
2025 
2026 	return space;
2027 error:
2028 	free(ids);
2029 	isl_space_free(space);
2030 	return NULL;
2031 }
2032 
2033 /* Given a space where the tuple of type "type" is a wrapped map space,
2034  * swap domain and range of that wrapped space.
2035  *
2036  * If the tuple is named, then the name is only preserved
2037  * if the nested tuples are equal, in which case the output
2038  * of this function is identical to the input, except possibly
2039  * for the dimension identifiers.
2040  *
2041  * Make a reasonable attempt at moving the dimension identifiers
2042  * along with the tuples.
2043  */
isl_space_reverse_wrapped(__isl_take isl_space * space,enum isl_dim_type type)2044 __isl_give isl_space *isl_space_reverse_wrapped(__isl_take isl_space *space,
2045 	enum isl_dim_type type)
2046 {
2047 	int pos = type - isl_dim_in;
2048 	isl_space *nested;
2049 	isl_bool equal;
2050 	isl_size n_in;
2051 
2052 	nested = isl_space_peek_nested(space, pos);
2053 	equal = isl_space_tuple_is_equal(nested, isl_dim_in,
2054 					nested, isl_dim_out);
2055 	if (equal < 0)
2056 		return isl_space_free(space);
2057 
2058 	nested = isl_space_take_nested(space, pos);
2059 	nested = isl_space_reverse(nested);
2060 	space = isl_space_restore_nested(space, pos, nested);
2061 	if (!equal)
2062 		space = isl_space_reset_tuple_id(space, type);
2063 	nested = isl_space_peek_nested(space, pos);
2064 	n_in = isl_space_dim(nested, isl_dim_in);
2065 	if (n_in < 0)
2066 		return isl_space_free(space);
2067 	space = copy_ids(space, type, 0, nested, isl_dim_in);
2068 	space = copy_ids(space, type, n_in, nested, isl_dim_out);
2069 
2070 	return space;
2071 }
2072 
2073 /* Given a space (A -> B), return the corresponding space
2074  * (B -> A).
2075  *
2076  * If the domain tuple is named, then the name is only preserved
2077  * if A and B are equal tuples, in which case the output
2078  * of this function is identical to the input, except possibly
2079  * for the dimension identifiers.
2080  */
isl_space_wrapped_reverse(__isl_take isl_space * space)2081 __isl_give isl_space *isl_space_wrapped_reverse(__isl_take isl_space *space)
2082 {
2083 	if (isl_space_check_is_wrapping(space) < 0)
2084 		return isl_space_free(space);
2085 	space = isl_space_reverse_wrapped(space, isl_dim_set);
2086 
2087 	return space;
2088 }
2089 
2090 /* Given a space (A -> B) -> C, return the corresponding space
2091  * (B -> A) -> C.
2092  *
2093  * If the domain tuple is named, then the name is only preserved
2094  * if A and B are equal tuples, in which case the output
2095  * of this function is identical to the input, except possibly
2096  * for the dimension identifiers.
2097  */
isl_space_domain_reverse(__isl_take isl_space * space)2098 __isl_give isl_space *isl_space_domain_reverse(__isl_take isl_space *space)
2099 {
2100 	if (isl_space_check_domain_is_wrapping(space) < 0)
2101 		return isl_space_free(space);
2102 	space = isl_space_reverse_wrapped(space, isl_dim_in);
2103 
2104 	return space;
2105 }
2106 
2107 /* Given a space A -> (B -> C), return the corresponding space
2108  * A -> (C -> B).
2109  *
2110  * If the range tuple is named, then the name is only preserved
2111  * if B and C are equal tuples, in which case the output
2112  * of this function is identical to the input, except possibly
2113  * for the dimension identifiers.
2114  */
isl_space_range_reverse(__isl_take isl_space * space)2115 __isl_give isl_space *isl_space_range_reverse(__isl_take isl_space *space)
2116 {
2117 	if (isl_space_check_range_is_wrapping(space) < 0)
2118 		return isl_space_free(space);
2119 	space = isl_space_reverse_wrapped(space, isl_dim_out);
2120 
2121 	return space;
2122 }
2123 
isl_space_drop_dims(__isl_take isl_space * space,enum isl_dim_type type,unsigned first,unsigned num)2124 __isl_give isl_space *isl_space_drop_dims(__isl_take isl_space *space,
2125 	enum isl_dim_type type, unsigned first, unsigned num)
2126 {
2127 	int i;
2128 
2129 	if (!space)
2130 		return NULL;
2131 
2132 	if (num == 0)
2133 		return isl_space_reset(space, type);
2134 
2135 	if (!valid_dim_type(type))
2136 		isl_die(space->ctx, isl_error_invalid,
2137 			"cannot drop dimensions of specified type", goto error);
2138 
2139 	if (isl_space_check_range(space, type, first, num) < 0)
2140 		return isl_space_free(space);
2141 	space = isl_space_cow(space);
2142 	if (!space)
2143 		goto error;
2144 	if (space->ids) {
2145 		space = extend_ids(space);
2146 		if (!space)
2147 			goto error;
2148 		for (i = 0; i < num; ++i)
2149 			isl_id_free(get_id(space, type, first + i));
2150 		for (i = first+num; i < n(space, type); ++i)
2151 			set_id(space, type, i - num, get_id(space, type, i));
2152 		switch (type) {
2153 		case isl_dim_param:
2154 			get_ids(space, isl_dim_in, 0, space->n_in,
2155 				space->ids + offset(space, isl_dim_in) - num);
2156 		case isl_dim_in:
2157 			get_ids(space, isl_dim_out, 0, space->n_out,
2158 				space->ids + offset(space, isl_dim_out) - num);
2159 		default:
2160 			;
2161 		}
2162 		space->n_id -= num;
2163 	}
2164 	switch (type) {
2165 	case isl_dim_param:	space->nparam -= num; break;
2166 	case isl_dim_in:	space->n_in -= num; break;
2167 	case isl_dim_out:	space->n_out -= num; break;
2168 	default:		;
2169 	}
2170 	space = isl_space_reset(space, type);
2171 	if (type == isl_dim_param) {
2172 		if (space && space->nested[0] &&
2173 		    !(space->nested[0] = isl_space_drop_dims(space->nested[0],
2174 						    isl_dim_param, first, num)))
2175 			goto error;
2176 		if (space && space->nested[1] &&
2177 		    !(space->nested[1] = isl_space_drop_dims(space->nested[1],
2178 						    isl_dim_param, first, num)))
2179 			goto error;
2180 	}
2181 	return space;
2182 error:
2183 	isl_space_free(space);
2184 	return NULL;
2185 }
2186 
isl_space_drop_inputs(__isl_take isl_space * space,unsigned first,unsigned n)2187 __isl_give isl_space *isl_space_drop_inputs(__isl_take isl_space *space,
2188 		unsigned first, unsigned n)
2189 {
2190 	if (!space)
2191 		return NULL;
2192 	return isl_space_drop_dims(space, isl_dim_in, first, n);
2193 }
2194 
isl_space_drop_outputs(__isl_take isl_space * space,unsigned first,unsigned n)2195 __isl_give isl_space *isl_space_drop_outputs(__isl_take isl_space *space,
2196 		unsigned first, unsigned n)
2197 {
2198 	if (!space)
2199 		return NULL;
2200 	return isl_space_drop_dims(space, isl_dim_out, first, n);
2201 }
2202 
2203 /* Remove all parameters from "space".
2204  */
isl_space_drop_all_params(__isl_take isl_space * space)2205 __isl_give isl_space *isl_space_drop_all_params(__isl_take isl_space *space)
2206 {
2207 	isl_size nparam;
2208 
2209 	nparam = isl_space_dim(space, isl_dim_param);
2210 	if (nparam < 0)
2211 		return isl_space_free(space);
2212 	return isl_space_drop_dims(space, isl_dim_param, 0, nparam);
2213 }
2214 
isl_space_domain(__isl_take isl_space * space)2215 __isl_give isl_space *isl_space_domain(__isl_take isl_space *space)
2216 {
2217 	if (!space)
2218 		return NULL;
2219 	space = isl_space_drop_dims(space, isl_dim_out, 0, space->n_out);
2220 	space = isl_space_reverse(space);
2221 	space = mark_as_set(space);
2222 	return space;
2223 }
2224 
isl_space_from_domain(__isl_take isl_space * space)2225 __isl_give isl_space *isl_space_from_domain(__isl_take isl_space *space)
2226 {
2227 	if (!space)
2228 		return NULL;
2229 	if (!isl_space_is_set(space))
2230 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
2231 			"not a set space", goto error);
2232 	space = isl_space_reverse(space);
2233 	space = isl_space_reset(space, isl_dim_out);
2234 	return space;
2235 error:
2236 	isl_space_free(space);
2237 	return NULL;
2238 }
2239 
isl_space_range(__isl_take isl_space * space)2240 __isl_give isl_space *isl_space_range(__isl_take isl_space *space)
2241 {
2242 	if (!space)
2243 		return NULL;
2244 	space = isl_space_drop_dims(space, isl_dim_in, 0, space->n_in);
2245 	space = mark_as_set(space);
2246 	return space;
2247 }
2248 
isl_space_from_range(__isl_take isl_space * space)2249 __isl_give isl_space *isl_space_from_range(__isl_take isl_space *space)
2250 {
2251 	if (!space)
2252 		return NULL;
2253 	if (!isl_space_is_set(space))
2254 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
2255 			"not a set space", goto error);
2256 	return isl_space_reset(space, isl_dim_in);
2257 error:
2258 	isl_space_free(space);
2259 	return NULL;
2260 }
2261 
2262 /* Given a map space A -> B, return the map space [A -> B] -> A.
2263  */
isl_space_domain_map(__isl_take isl_space * space)2264 __isl_give isl_space *isl_space_domain_map(__isl_take isl_space *space)
2265 {
2266 	isl_space *domain;
2267 
2268 	domain = isl_space_from_range(isl_space_domain(isl_space_copy(space)));
2269 	space = isl_space_from_domain(isl_space_wrap(space));
2270 	space = isl_space_join(space, domain);
2271 
2272 	return space;
2273 }
2274 
2275 /* Given a map space A -> B, return the map space [A -> B] -> B.
2276  */
isl_space_range_map(__isl_take isl_space * space)2277 __isl_give isl_space *isl_space_range_map(__isl_take isl_space *space)
2278 {
2279 	isl_space *range;
2280 
2281 	range = isl_space_from_range(isl_space_range(isl_space_copy(space)));
2282 	space = isl_space_from_domain(isl_space_wrap(space));
2283 	space = isl_space_join(space, range);
2284 
2285 	return space;
2286 }
2287 
isl_space_params(__isl_take isl_space * space)2288 __isl_give isl_space *isl_space_params(__isl_take isl_space *space)
2289 {
2290 	isl_size n_in, n_out;
2291 
2292 	if (isl_space_is_params(space))
2293 		return space;
2294 	n_in = isl_space_dim(space, isl_dim_in);
2295 	n_out = isl_space_dim(space, isl_dim_out);
2296 	if (n_in < 0 || n_out < 0)
2297 		return isl_space_free(space);
2298 	space = isl_space_drop_dims(space, isl_dim_in, 0, n_in);
2299 	space = isl_space_drop_dims(space, isl_dim_out, 0, n_out);
2300 	space = mark_as_params(space);
2301 	return space;
2302 }
2303 
isl_space_set_from_params(__isl_take isl_space * space)2304 __isl_give isl_space *isl_space_set_from_params(__isl_take isl_space *space)
2305 {
2306 	if (!space)
2307 		return NULL;
2308 	if (!isl_space_is_params(space))
2309 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
2310 			"not a parameter space", goto error);
2311 	return isl_space_reset(space, isl_dim_set);
2312 error:
2313 	isl_space_free(space);
2314 	return NULL;
2315 }
2316 
2317 /* Add an unnamed tuple of dimension "dim" to "space".
2318  * This requires "space" to be a parameter or set space.
2319  *
2320  * In particular, if "space" is a parameter space, then return
2321  * a set space with the given dimension.
2322  * If "space" is a set space, then return a map space
2323  * with "space" as domain and a range of the given dimension.
2324  */
isl_space_add_unnamed_tuple_ui(__isl_take isl_space * space,unsigned dim)2325 __isl_give isl_space *isl_space_add_unnamed_tuple_ui(
2326 	__isl_take isl_space *space, unsigned dim)
2327 {
2328 	isl_bool is_params, is_set;
2329 
2330 	is_params = isl_space_is_params(space);
2331 	is_set = isl_space_is_set(space);
2332 	if (is_params < 0 || is_set < 0)
2333 		return isl_space_free(space);
2334 	if (!is_params && !is_set)
2335 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
2336 			"cannot add tuple to map space",
2337 			return isl_space_free(space));
2338 	if (is_params)
2339 		space = isl_space_set_from_params(space);
2340 	else
2341 		space = isl_space_from_domain(space);
2342 	space = isl_space_add_dims(space, isl_dim_out, dim);
2343 	return space;
2344 }
2345 
2346 /* Add a tuple of dimension "dim" and with tuple identifier "tuple_id"
2347  * to "space".
2348  * This requires "space" to be a parameter or set space.
2349  */
isl_space_add_named_tuple_id_ui(__isl_take isl_space * space,__isl_take isl_id * tuple_id,unsigned dim)2350 __isl_give isl_space *isl_space_add_named_tuple_id_ui(
2351 	__isl_take isl_space *space, __isl_take isl_id *tuple_id, unsigned dim)
2352 {
2353 	space = isl_space_add_unnamed_tuple_ui(space, dim);
2354 	space = isl_space_set_tuple_id(space, isl_dim_out, tuple_id);
2355 	return space;
2356 }
2357 
2358 /* Check that the identifiers in "tuple" do not appear as parameters
2359  * in "space".
2360  */
check_fresh_params(__isl_keep isl_space * space,__isl_keep isl_multi_id * tuple)2361 static isl_stat check_fresh_params(__isl_keep isl_space *space,
2362 	__isl_keep isl_multi_id *tuple)
2363 {
2364 	int i;
2365 	isl_size n;
2366 
2367 	n = isl_multi_id_size(tuple);
2368 	if (n < 0)
2369 		return isl_stat_error;
2370 	for (i = 0; i < n; ++i) {
2371 		isl_id *id;
2372 		int pos;
2373 
2374 		id = isl_multi_id_get_at(tuple, i);
2375 		if (!id)
2376 			return isl_stat_error;
2377 		pos = isl_space_find_dim_by_id(space, isl_dim_param, id);
2378 		isl_id_free(id);
2379 		if (pos >= 0)
2380 			isl_die(isl_space_get_ctx(space), isl_error_invalid,
2381 				"parameters not unique", return isl_stat_error);
2382 	}
2383 
2384 	return isl_stat_ok;
2385 }
2386 
2387 /* Add the identifiers in "tuple" as parameters of "space"
2388  * that are known to be fresh.
2389  */
add_bind_params(__isl_take isl_space * space,__isl_keep isl_multi_id * tuple)2390 static __isl_give isl_space *add_bind_params(__isl_take isl_space *space,
2391 	__isl_keep isl_multi_id *tuple)
2392 {
2393 	int i;
2394 	isl_size first, n;
2395 
2396 	first = isl_space_dim(space, isl_dim_param);
2397 	n = isl_multi_id_size(tuple);
2398 	if (first < 0 || n < 0)
2399 		return isl_space_free(space);
2400 	space = isl_space_add_dims(space, isl_dim_param, n);
2401 	for (i = 0; i < n; ++i) {
2402 		isl_id *id;
2403 
2404 		id = isl_multi_id_get_at(tuple, i);
2405 		space = isl_space_set_dim_id(space,
2406 						isl_dim_param, first + i, id);
2407 	}
2408 
2409 	return space;
2410 }
2411 
2412 /* Internal function that removes the set tuple of "space",
2413  * which is assumed to correspond to the range space of "tuple", and
2414  * adds the identifiers in "tuple" as fresh parameters.
2415  * In other words, the set dimensions of "space" are reinterpreted
2416  * as parameters, but stay in the same global positions.
2417  */
isl_space_bind_set(__isl_take isl_space * space,__isl_keep isl_multi_id * tuple)2418 __isl_give isl_space *isl_space_bind_set(__isl_take isl_space *space,
2419 	__isl_keep isl_multi_id *tuple)
2420 {
2421 	isl_space *tuple_space;
2422 
2423 	if (isl_space_check_is_set(space) < 0)
2424 		return isl_space_free(space);
2425 	tuple_space = isl_multi_id_peek_space(tuple);
2426 	if (isl_space_check_equal_tuples(tuple_space, space) < 0)
2427 		return isl_space_free(space);
2428 	if (check_fresh_params(space, tuple) < 0)
2429 		return isl_space_free(space);
2430 	space = isl_space_params(space);
2431 	space = add_bind_params(space, tuple);
2432 	return space;
2433 }
2434 
2435 /* Internal function that removes the domain tuple of the map space "space",
2436  * which is assumed to correspond to the range space of "tuple", and
2437  * adds the identifiers in "tuple" as fresh parameters.
2438  * In other words, the domain dimensions of "space" are reinterpreted
2439  * as parameters, but stay in the same global positions.
2440  */
isl_space_bind_map_domain(__isl_take isl_space * space,__isl_keep isl_multi_id * tuple)2441 __isl_give isl_space *isl_space_bind_map_domain(__isl_take isl_space *space,
2442 	__isl_keep isl_multi_id *tuple)
2443 {
2444 	isl_space *tuple_space;
2445 
2446 	if (isl_space_check_is_map(space) < 0)
2447 		return isl_space_free(space);
2448 	tuple_space = isl_multi_id_peek_space(tuple);
2449 	if (isl_space_check_domain_tuples(tuple_space, space) < 0)
2450 		return isl_space_free(space);
2451 	if (check_fresh_params(space, tuple) < 0)
2452 		return isl_space_free(space);
2453 	space = isl_space_range(space);
2454 	space = add_bind_params(space, tuple);
2455 	return space;
2456 }
2457 
2458 /* Internal function that, given a space of the form [A -> B] -> C and
2459  * a tuple of identifiers in A, returns a space B -> C with
2460  * the identifiers in "tuple" added as fresh parameters.
2461  * In other words, the domain dimensions of the wrapped relation
2462  * in the domain of "space" are reinterpreted
2463  * as parameters, but stay in the same global positions.
2464  */
isl_space_bind_domain_wrapped_domain(__isl_take isl_space * space,__isl_keep isl_multi_id * tuple)2465 __isl_give isl_space *isl_space_bind_domain_wrapped_domain(
2466 	__isl_take isl_space *space, __isl_keep isl_multi_id *tuple)
2467 {
2468 	isl_space *tuple_space;
2469 
2470 	if (isl_space_check_is_map(space) < 0)
2471 		return isl_space_free(space);
2472 	tuple_space = isl_multi_id_peek_space(tuple);
2473 	if (isl_space_check_domain_wrapped_domain_tuples(tuple_space,
2474 							space) < 0)
2475 		  return isl_space_free(space);
2476 	if (check_fresh_params(space, tuple) < 0)
2477 		return isl_space_free(space);
2478 	space = isl_space_domain_factor_range(space);
2479 	space = add_bind_params(space, tuple);
2480 	return space;
2481 }
2482 
2483 /* Insert a domain tuple in "space" corresponding to the set space "domain".
2484  * In particular, if "space" is a parameter space, then the result
2485  * is the set space "domain" combined with the parameters of "space".
2486  * If "space" is a set space, then the result
2487  * is a map space with "domain" as domain and the original space as range.
2488  */
isl_space_insert_domain(__isl_take isl_space * space,__isl_take isl_space * domain)2489 static __isl_give isl_space *isl_space_insert_domain(
2490 	__isl_take isl_space *space, __isl_take isl_space *domain)
2491 {
2492 	isl_bool is_params;
2493 
2494 	domain = isl_space_replace_params(domain, space);
2495 
2496 	is_params = isl_space_is_params(space);
2497 	if (is_params < 0) {
2498 		isl_space_free(domain);
2499 		space = isl_space_free(space);
2500 	} else if (is_params) {
2501 		isl_space_free(space);
2502 		space = domain;
2503 	} else {
2504 		space = isl_space_map_from_domain_and_range(domain, space);
2505 	}
2506 	return space;
2507 }
2508 
2509 /* Internal function that introduces a domain in "space"
2510  * corresponding to the range space of "tuple".
2511  * In particular, if "space" is a parameter space, then the result
2512  * is a set space.  If "space" is a set space, then the result
2513  * is a map space with the original space as range.
2514  * Parameters that correspond to the identifiers in "tuple" are removed.
2515  *
2516  * The parameters are removed in reverse order (under the assumption
2517  * that they appear in the same order in "multi") because
2518  * it is slightly more efficient to remove parameters at the end.
2519  *
2520  * For pretty-printing purposes, the identifiers of the set dimensions
2521  * of the introduced domain are set to the identifiers in "tuple".
2522  */
isl_space_unbind_params_insert_domain(__isl_take isl_space * space,__isl_keep isl_multi_id * tuple)2523 __isl_give isl_space *isl_space_unbind_params_insert_domain(
2524 	__isl_take isl_space *space, __isl_keep isl_multi_id *tuple)
2525 {
2526 	int i;
2527 	isl_size n;
2528 	isl_space *tuple_space;
2529 
2530 	n = isl_multi_id_size(tuple);
2531 	if (!space || n < 0)
2532 		return isl_space_free(space);
2533 	for (i = n - 1; i >= 0; --i) {
2534 		isl_id *id;
2535 		int pos;
2536 
2537 		id = isl_multi_id_get_id(tuple, i);
2538 		if (!id)
2539 			return isl_space_free(space);
2540 		pos = isl_space_find_dim_by_id(space, isl_dim_param, id);
2541 		isl_id_free(id);
2542 		if (pos < 0)
2543 			continue;
2544 		space = isl_space_drop_dims(space, isl_dim_param, pos, 1);
2545 	}
2546 	tuple_space = isl_multi_id_get_space(tuple);
2547 	for (i = 0; i < n; ++i) {
2548 		isl_id *id;
2549 
2550 		id = isl_multi_id_get_id(tuple, i);
2551 		tuple_space = isl_space_set_dim_id(tuple_space,
2552 						    isl_dim_set, i, id);
2553 	}
2554 	return isl_space_insert_domain(space, tuple_space);
2555 }
2556 
isl_space_underlying(__isl_take isl_space * space,unsigned n_div)2557 __isl_give isl_space *isl_space_underlying(__isl_take isl_space *space,
2558 	unsigned n_div)
2559 {
2560 	int i;
2561 	isl_bool is_set;
2562 
2563 	is_set = isl_space_is_set(space);
2564 	if (is_set < 0)
2565 		return isl_space_free(space);
2566 	if (n_div == 0 && is_set &&
2567 	    space->nparam == 0 && space->n_in == 0 && space->n_id == 0)
2568 		return isl_space_reset(space, isl_dim_out);
2569 	space = isl_space_cow(space);
2570 	if (!space)
2571 		return NULL;
2572 	space->n_out += space->nparam + space->n_in + n_div;
2573 	space->nparam = 0;
2574 	space->n_in = 0;
2575 
2576 	for (i = 0; i < space->n_id; ++i)
2577 		isl_id_free(get_id(space, isl_dim_out, i));
2578 	space->n_id = 0;
2579 	space = isl_space_reset(space, isl_dim_in);
2580 	space = isl_space_reset(space, isl_dim_out);
2581 	space = mark_as_set(space);
2582 
2583 	return space;
2584 }
2585 
2586 /* Are the two spaces the same, including positions and names of parameters?
2587  */
isl_space_is_equal(__isl_keep isl_space * space1,__isl_keep isl_space * space2)2588 isl_bool isl_space_is_equal(__isl_keep isl_space *space1,
2589 	__isl_keep isl_space *space2)
2590 {
2591 	isl_bool equal;
2592 
2593 	if (!space1 || !space2)
2594 		return isl_bool_error;
2595 	if (space1 == space2)
2596 		return isl_bool_true;
2597 	equal = isl_space_has_equal_params(space1, space2);
2598 	if (equal < 0 || !equal)
2599 		return equal;
2600 	return isl_space_has_equal_tuples(space1, space2);
2601 }
2602 
2603 /* Do the tuples of "space1" correspond to those of the domain of "space2"?
2604  * That is, is "space1" equal to the domain of "space2", ignoring parameters.
2605  *
2606  * "space2" is allowed to be a set space, in which case "space1"
2607  * should be a parameter space.
2608  */
isl_space_has_domain_tuples(__isl_keep isl_space * space1,__isl_keep isl_space * space2)2609 isl_bool isl_space_has_domain_tuples(__isl_keep isl_space *space1,
2610 	__isl_keep isl_space *space2)
2611 {
2612 	isl_bool is_set;
2613 
2614 	is_set = isl_space_is_set(space1);
2615 	if (is_set < 0 || !is_set)
2616 		return is_set;
2617 	return isl_space_tuple_is_equal(space1, isl_dim_set,
2618 					space2, isl_dim_in);
2619 }
2620 
2621 /* Do the tuples of "space1" correspond to those of the range of "space2"?
2622  * That is, is "space1" equal to the range of "space2", ignoring parameters.
2623  *
2624  * "space2" is allowed to be the space of a set,
2625  * in which case it should be equal to "space1", ignoring parameters.
2626  */
isl_space_has_range_tuples(__isl_keep isl_space * space1,__isl_keep isl_space * space2)2627 isl_bool isl_space_has_range_tuples(__isl_keep isl_space *space1,
2628 	__isl_keep isl_space *space2)
2629 {
2630 	isl_bool is_set;
2631 
2632 	is_set = isl_space_is_set(space1);
2633 	if (is_set < 0 || !is_set)
2634 		return is_set;
2635 	return isl_space_tuple_is_equal(space1, isl_dim_set,
2636 					space2, isl_dim_out);
2637 }
2638 
2639 /* Check that the tuples of "space1" correspond to those
2640  * of the domain of "space2".
2641  * That is, check that "space1" is equal to the domain of "space2",
2642  * ignoring parameters.
2643  */
isl_space_check_domain_tuples(__isl_keep isl_space * space1,__isl_keep isl_space * space2)2644 isl_stat isl_space_check_domain_tuples(__isl_keep isl_space *space1,
2645 	__isl_keep isl_space *space2)
2646 {
2647 	isl_bool is_equal;
2648 
2649 	is_equal = isl_space_has_domain_tuples(space1, space2);
2650 	return check_match(space1, is_equal);
2651 }
2652 
2653 /* Check that the tuples of "space1" correspond to those
2654  * of the domain of the wrapped relation in the domain of "space2".
2655  * That is, check that "space1" is equal to this domain,
2656  * ignoring parameters.
2657  */
isl_space_check_domain_wrapped_domain_tuples(__isl_keep isl_space * space1,__isl_keep isl_space * space2)2658 isl_stat isl_space_check_domain_wrapped_domain_tuples(
2659 	__isl_keep isl_space *space1, __isl_keep isl_space *space2)
2660 {
2661 	isl_space *domain;
2662 	isl_stat r;
2663 
2664 	domain = isl_space_unwrap(isl_space_domain(isl_space_copy(space2)));
2665 	r = isl_space_check_domain_tuples(space1, domain);
2666 	isl_space_free(domain);
2667 
2668 	return r;
2669 }
2670 
2671 /* Is space1 equal to the domain of space2?
2672  *
2673  * In the internal version we also allow space2 to be the space of a set,
2674  * provided space1 is a parameter space.
2675  */
isl_space_is_domain_internal(__isl_keep isl_space * space1,__isl_keep isl_space * space2)2676 isl_bool isl_space_is_domain_internal(__isl_keep isl_space *space1,
2677 	__isl_keep isl_space *space2)
2678 {
2679 	isl_bool equal_params;
2680 
2681 	if (!space1 || !space2)
2682 		return isl_bool_error;
2683 	equal_params = isl_space_has_equal_params(space1, space2);
2684 	if (equal_params < 0 || !equal_params)
2685 		return equal_params;
2686 	return isl_space_has_domain_tuples(space1, space2);
2687 }
2688 
2689 /* Is space1 equal to the domain of space2?
2690  */
isl_space_is_domain(__isl_keep isl_space * space1,__isl_keep isl_space * space2)2691 isl_bool isl_space_is_domain(__isl_keep isl_space *space1,
2692 	__isl_keep isl_space *space2)
2693 {
2694 	if (!space2)
2695 		return isl_bool_error;
2696 	if (!isl_space_is_map(space2))
2697 		return isl_bool_false;
2698 	return isl_space_is_domain_internal(space1, space2);
2699 }
2700 
2701 /* Is space1 equal to the range of space2?
2702  *
2703  * In the internal version, space2 is allowed to be the space of a set,
2704  * in which case it should be equal to space1.
2705  */
isl_space_is_range_internal(__isl_keep isl_space * space1,__isl_keep isl_space * space2)2706 isl_bool isl_space_is_range_internal(__isl_keep isl_space *space1,
2707 	__isl_keep isl_space *space2)
2708 {
2709 	isl_bool equal_params;
2710 
2711 	if (!space1 || !space2)
2712 		return isl_bool_error;
2713 	equal_params = isl_space_has_equal_params(space1, space2);
2714 	if (equal_params < 0 || !equal_params)
2715 		return equal_params;
2716 	return isl_space_has_range_tuples(space1, space2);
2717 }
2718 
2719 /* Is space1 equal to the range of space2?
2720  */
isl_space_is_range(__isl_keep isl_space * space1,__isl_keep isl_space * space2)2721 isl_bool isl_space_is_range(__isl_keep isl_space *space1,
2722 	__isl_keep isl_space *space2)
2723 {
2724 	if (!space2)
2725 		return isl_bool_error;
2726 	if (!isl_space_is_map(space2))
2727 		return isl_bool_false;
2728 	return isl_space_is_range_internal(space1, space2);
2729 }
2730 
2731 /* Update "hash" by hashing in the parameters of "space".
2732  */
isl_hash_params(uint32_t hash,__isl_keep isl_space * space)2733 static uint32_t isl_hash_params(uint32_t hash, __isl_keep isl_space *space)
2734 {
2735 	int i;
2736 	isl_id *id;
2737 
2738 	if (!space)
2739 		return hash;
2740 
2741 	isl_hash_byte(hash, space->nparam % 256);
2742 
2743 	for (i = 0; i < space->nparam; ++i) {
2744 		id = get_id(space, isl_dim_param, i);
2745 		hash = isl_hash_id(hash, id);
2746 	}
2747 
2748 	return hash;
2749 }
2750 
2751 /* Update "hash" by hashing in the tuples of "space".
2752  * Changes in this function should be reflected in isl_hash_tuples_domain.
2753  */
isl_hash_tuples(uint32_t hash,__isl_keep isl_space * space)2754 static uint32_t isl_hash_tuples(uint32_t hash, __isl_keep isl_space *space)
2755 {
2756 	isl_id *id;
2757 
2758 	if (!space)
2759 		return hash;
2760 
2761 	isl_hash_byte(hash, space->n_in % 256);
2762 	isl_hash_byte(hash, space->n_out % 256);
2763 
2764 	id = tuple_id(space, isl_dim_in);
2765 	hash = isl_hash_id(hash, id);
2766 	id = tuple_id(space, isl_dim_out);
2767 	hash = isl_hash_id(hash, id);
2768 
2769 	hash = isl_hash_tuples(hash, space->nested[0]);
2770 	hash = isl_hash_tuples(hash, space->nested[1]);
2771 
2772 	return hash;
2773 }
2774 
2775 /* Update "hash" by hashing in the domain tuple of "space".
2776  * The result of this function is equal to the result of applying
2777  * isl_hash_tuples to the domain of "space".
2778  */
isl_hash_tuples_domain(uint32_t hash,__isl_keep isl_space * space)2779 static uint32_t isl_hash_tuples_domain(uint32_t hash,
2780 	__isl_keep isl_space *space)
2781 {
2782 	isl_id *id;
2783 
2784 	if (!space)
2785 		return hash;
2786 
2787 	isl_hash_byte(hash, 0);
2788 	isl_hash_byte(hash, space->n_in % 256);
2789 
2790 	hash = isl_hash_id(hash, &isl_id_none);
2791 	id = tuple_id(space, isl_dim_in);
2792 	hash = isl_hash_id(hash, id);
2793 
2794 	hash = isl_hash_tuples(hash, space->nested[0]);
2795 
2796 	return hash;
2797 }
2798 
2799 /* Return a hash value that digests the tuples of "space",
2800  * i.e., that ignores the parameters.
2801  * Changes in this function should be reflected
2802  * in isl_space_get_tuple_domain_hash.
2803  */
isl_space_get_tuple_hash(__isl_keep isl_space * space)2804 uint32_t isl_space_get_tuple_hash(__isl_keep isl_space *space)
2805 {
2806 	uint32_t hash;
2807 
2808 	if (!space)
2809 		return 0;
2810 
2811 	hash = isl_hash_init();
2812 	hash = isl_hash_tuples(hash, space);
2813 
2814 	return hash;
2815 }
2816 
2817 /* Return the hash value of "space".
2818  */
isl_space_get_full_hash(__isl_keep isl_space * space)2819 uint32_t isl_space_get_full_hash(__isl_keep isl_space *space)
2820 {
2821 	uint32_t hash;
2822 
2823 	if (!space)
2824 		return 0;
2825 
2826 	hash = isl_hash_init();
2827 	hash = isl_hash_params(hash, space);
2828 	hash = isl_hash_tuples(hash, space);
2829 
2830 	return hash;
2831 }
2832 
2833 /* Return the hash value of the domain tuple of "space".
2834  * That is, isl_space_get_tuple_domain_hash(space) is equal to
2835  * isl_space_get_tuple_hash(isl_space_domain(space)).
2836  */
isl_space_get_tuple_domain_hash(__isl_keep isl_space * space)2837 uint32_t isl_space_get_tuple_domain_hash(__isl_keep isl_space *space)
2838 {
2839 	uint32_t hash;
2840 
2841 	if (!space)
2842 		return 0;
2843 
2844 	hash = isl_hash_init();
2845 	hash = isl_hash_tuples_domain(hash, space);
2846 
2847 	return hash;
2848 }
2849 
2850 /* Is "space" the space of a set wrapping a map space?
2851  */
isl_space_is_wrapping(__isl_keep isl_space * space)2852 isl_bool isl_space_is_wrapping(__isl_keep isl_space *space)
2853 {
2854 	if (!space)
2855 		return isl_bool_error;
2856 
2857 	if (!isl_space_is_set(space))
2858 		return isl_bool_false;
2859 
2860 	return isl_bool_ok(space->nested[1] != NULL);
2861 }
2862 
2863 /* Is "space" the space of a map where the domain is a wrapped map space?
2864  */
isl_space_domain_is_wrapping(__isl_keep isl_space * space)2865 isl_bool isl_space_domain_is_wrapping(__isl_keep isl_space *space)
2866 {
2867 	if (!space)
2868 		return isl_bool_error;
2869 
2870 	if (isl_space_is_set(space))
2871 		return isl_bool_false;
2872 
2873 	return isl_bool_ok(space->nested[0] != NULL);
2874 }
2875 
2876 /* Is "space" the space of a map where the range is a wrapped map space?
2877  */
isl_space_range_is_wrapping(__isl_keep isl_space * space)2878 isl_bool isl_space_range_is_wrapping(__isl_keep isl_space *space)
2879 {
2880 	if (!space)
2881 		return isl_bool_error;
2882 
2883 	if (isl_space_is_set(space))
2884 		return isl_bool_false;
2885 
2886 	return isl_bool_ok(space->nested[1] != NULL);
2887 }
2888 
2889 /* Is "space" a product of two spaces?
2890  * That is, is it a wrapping set space or a map space
2891  * with wrapping domain and range?
2892  */
isl_space_is_product(__isl_keep isl_space * space)2893 isl_bool isl_space_is_product(__isl_keep isl_space *space)
2894 {
2895 	isl_bool is_set;
2896 	isl_bool is_product;
2897 
2898 	is_set = isl_space_is_set(space);
2899 	if (is_set < 0)
2900 		return isl_bool_error;
2901 	if (is_set)
2902 		return isl_space_is_wrapping(space);
2903 	is_product = isl_space_domain_is_wrapping(space);
2904 	if (is_product < 0 || !is_product)
2905 		return is_product;
2906 	return isl_space_range_is_wrapping(space);
2907 }
2908 
isl_space_wrap(__isl_take isl_space * space)2909 __isl_give isl_space *isl_space_wrap(__isl_take isl_space *space)
2910 {
2911 	isl_space *wrap;
2912 
2913 	if (!space)
2914 		return NULL;
2915 
2916 	wrap = isl_space_set_alloc(space->ctx,
2917 				    space->nparam, space->n_in + space->n_out);
2918 
2919 	wrap = copy_ids(wrap, isl_dim_param, 0, space, isl_dim_param);
2920 	wrap = copy_ids(wrap, isl_dim_set, 0, space, isl_dim_in);
2921 	wrap = copy_ids(wrap, isl_dim_set, space->n_in, space, isl_dim_out);
2922 
2923 	if (!wrap)
2924 		goto error;
2925 
2926 	wrap->nested[1] = space;
2927 
2928 	return wrap;
2929 error:
2930 	isl_space_free(space);
2931 	return NULL;
2932 }
2933 
isl_space_unwrap(__isl_take isl_space * space)2934 __isl_give isl_space *isl_space_unwrap(__isl_take isl_space *space)
2935 {
2936 	isl_space *unwrap;
2937 
2938 	if (!space)
2939 		return NULL;
2940 
2941 	if (!isl_space_is_wrapping(space))
2942 		isl_die(space->ctx, isl_error_invalid, "not a wrapping space",
2943 			goto error);
2944 
2945 	unwrap = isl_space_copy(space->nested[1]);
2946 	isl_space_free(space);
2947 
2948 	return unwrap;
2949 error:
2950 	isl_space_free(space);
2951 	return NULL;
2952 }
2953 
isl_space_is_named_or_nested(__isl_keep isl_space * space,enum isl_dim_type type)2954 isl_bool isl_space_is_named_or_nested(__isl_keep isl_space *space,
2955 	enum isl_dim_type type)
2956 {
2957 	if (type != isl_dim_in && type != isl_dim_out)
2958 		return isl_bool_false;
2959 	if (!space)
2960 		return isl_bool_error;
2961 	if (space->tuple_id[type - isl_dim_in])
2962 		return isl_bool_true;
2963 	if (space->nested[type - isl_dim_in])
2964 		return isl_bool_true;
2965 	return isl_bool_false;
2966 }
2967 
isl_space_may_be_set(__isl_keep isl_space * space)2968 isl_bool isl_space_may_be_set(__isl_keep isl_space *space)
2969 {
2970 	isl_bool nested;
2971 	isl_size n_in;
2972 
2973 	if (!space)
2974 		return isl_bool_error;
2975 	if (isl_space_is_set(space))
2976 		return isl_bool_true;
2977 	n_in = isl_space_dim(space, isl_dim_in);
2978 	if (n_in < 0)
2979 		return isl_bool_error;
2980 	if (n_in != 0)
2981 		return isl_bool_false;
2982 	nested = isl_space_is_named_or_nested(space, isl_dim_in);
2983 	if (nested < 0 || nested)
2984 		return isl_bool_not(nested);
2985 	return isl_bool_true;
2986 }
2987 
isl_space_reset(__isl_take isl_space * space,enum isl_dim_type type)2988 __isl_give isl_space *isl_space_reset(__isl_take isl_space *space,
2989 	enum isl_dim_type type)
2990 {
2991 	if (!isl_space_is_named_or_nested(space, type))
2992 		return space;
2993 
2994 	space = isl_space_cow(space);
2995 	if (!space)
2996 		return NULL;
2997 
2998 	isl_id_free(space->tuple_id[type - isl_dim_in]);
2999 	space->tuple_id[type - isl_dim_in] = NULL;
3000 	isl_space_free(space->nested[type - isl_dim_in]);
3001 	space->nested[type - isl_dim_in] = NULL;
3002 
3003 	return space;
3004 }
3005 
isl_space_flatten(__isl_take isl_space * space)3006 __isl_give isl_space *isl_space_flatten(__isl_take isl_space *space)
3007 {
3008 	if (!space)
3009 		return NULL;
3010 	if (!space->nested[0] && !space->nested[1])
3011 		return space;
3012 
3013 	if (space->nested[0])
3014 		space = isl_space_reset(space, isl_dim_in);
3015 	if (space && space->nested[1])
3016 		space = isl_space_reset(space, isl_dim_out);
3017 
3018 	return space;
3019 }
3020 
isl_space_flatten_domain(__isl_take isl_space * space)3021 __isl_give isl_space *isl_space_flatten_domain(__isl_take isl_space *space)
3022 {
3023 	if (!space)
3024 		return NULL;
3025 	if (!space->nested[0])
3026 		return space;
3027 
3028 	return isl_space_reset(space, isl_dim_in);
3029 }
3030 
isl_space_flatten_range(__isl_take isl_space * space)3031 __isl_give isl_space *isl_space_flatten_range(__isl_take isl_space *space)
3032 {
3033 	if (!space)
3034 		return NULL;
3035 	if (!space->nested[1])
3036 		return space;
3037 
3038 	return isl_space_reset(space, isl_dim_out);
3039 }
3040 
3041 /* Replace the parameters of dst by those of src.
3042  */
isl_space_replace_params(__isl_take isl_space * dst,__isl_keep isl_space * src)3043 __isl_give isl_space *isl_space_replace_params(__isl_take isl_space *dst,
3044 	__isl_keep isl_space *src)
3045 {
3046 	isl_size dst_dim, src_dim;
3047 	isl_bool equal_params;
3048 	enum isl_dim_type type = isl_dim_param;
3049 
3050 	equal_params = isl_space_has_equal_params(dst, src);
3051 	if (equal_params < 0)
3052 		return isl_space_free(dst);
3053 	if (equal_params)
3054 		return dst;
3055 
3056 	dst = isl_space_cow(dst);
3057 
3058 	dst_dim = isl_space_dim(dst, type);
3059 	src_dim = isl_space_dim(src, type);
3060 	if (dst_dim < 0 || src_dim < 0)
3061 		goto error;
3062 
3063 	dst = isl_space_drop_dims(dst, type, 0, dst_dim);
3064 	dst = isl_space_add_dims(dst, type, src_dim);
3065 	dst = copy_ids(dst, type, 0, src, type);
3066 
3067 	if (dst) {
3068 		int i;
3069 		for (i = 0; i <= 1; ++i) {
3070 			isl_space *nested;
3071 
3072 			if (!dst->nested[i])
3073 				continue;
3074 			nested = isl_space_take_nested(dst, i);
3075 			nested = isl_space_replace_params(nested, src);
3076 			dst = isl_space_restore_nested(dst, i, nested);
3077 			if (!dst)
3078 				return NULL;
3079 		}
3080 	}
3081 
3082 	return dst;
3083 error:
3084 	isl_space_free(dst);
3085 	return NULL;
3086 }
3087 
3088 /* Given two tuples ("dst_type" in "dst" and "src_type" in "src")
3089  * of the same size, check if any of the dimensions in the "dst" tuple
3090  * have no identifier, while the corresponding dimensions in "src"
3091  * does have an identifier,
3092  * If so, copy the identifier over to "dst".
3093  */
isl_space_copy_ids_if_unset(__isl_take isl_space * dst,enum isl_dim_type dst_type,__isl_keep isl_space * src,enum isl_dim_type src_type)3094 __isl_give isl_space *isl_space_copy_ids_if_unset(__isl_take isl_space *dst,
3095 	enum isl_dim_type dst_type, __isl_keep isl_space *src,
3096 	enum isl_dim_type src_type)
3097 {
3098 	int i;
3099 	isl_size n;
3100 
3101 	n = isl_space_dim(dst, dst_type);
3102 	if (n < 0)
3103 		return isl_space_free(dst);
3104 	for (i = 0; i < n; ++i) {
3105 		isl_bool set;
3106 		isl_id *id;
3107 
3108 		set = isl_space_has_dim_id(dst, dst_type, i);
3109 		if (set < 0)
3110 			return isl_space_free(dst);
3111 		if (set)
3112 			continue;
3113 
3114 		set = isl_space_has_dim_id(src, src_type, i);
3115 		if (set < 0)
3116 			return isl_space_free(dst);
3117 		if (!set)
3118 			continue;
3119 
3120 		id = isl_space_get_dim_id(src, src_type, i);
3121 		dst = isl_space_set_dim_id(dst, dst_type, i, id);
3122 	}
3123 
3124 	return dst;
3125 }
3126 
3127 /* Given a space "space" of a set, create a space
3128  * for the lift of the set.  In particular, the result
3129  * is of the form lifted[space -> local[..]], with n_local variables in the
3130  * range of the wrapped map.
3131  */
isl_space_lift(__isl_take isl_space * space,unsigned n_local)3132 __isl_give isl_space *isl_space_lift(__isl_take isl_space *space,
3133 	unsigned n_local)
3134 {
3135 	isl_space *local_space;
3136 
3137 	if (!space)
3138 		return NULL;
3139 
3140 	local_space = isl_space_dup(space);
3141 	local_space = isl_space_drop_dims(local_space, isl_dim_set, 0,
3142 					space->n_out);
3143 	local_space = isl_space_add_dims(local_space, isl_dim_set, n_local);
3144 	local_space = isl_space_set_tuple_name(local_space,
3145 						isl_dim_set, "local");
3146 	space = isl_space_join(isl_space_from_domain(space),
3147 			    isl_space_from_range(local_space));
3148 	space = isl_space_wrap(space);
3149 	space = isl_space_set_tuple_name(space, isl_dim_set, "lifted");
3150 
3151 	return space;
3152 }
3153 
isl_space_can_zip(__isl_keep isl_space * space)3154 isl_bool isl_space_can_zip(__isl_keep isl_space *space)
3155 {
3156 	isl_bool is_set;
3157 
3158 	is_set = isl_space_is_set(space);
3159 	if (is_set < 0)
3160 		return isl_bool_error;
3161 	if (is_set)
3162 		return isl_bool_false;
3163 	return isl_space_is_product(space);
3164 }
3165 
isl_space_zip(__isl_take isl_space * space)3166 __isl_give isl_space *isl_space_zip(__isl_take isl_space *space)
3167 {
3168 	isl_space *dom, *ran;
3169 	isl_space *dom_dom, *dom_ran, *ran_dom, *ran_ran;
3170 
3171 	if (!isl_space_can_zip(space))
3172 		isl_die(space->ctx, isl_error_invalid, "space cannot be zipped",
3173 			goto error);
3174 
3175 	if (!space)
3176 		return NULL;
3177 	dom = isl_space_unwrap(isl_space_domain(isl_space_copy(space)));
3178 	ran = isl_space_unwrap(isl_space_range(space));
3179 	dom_dom = isl_space_domain(isl_space_copy(dom));
3180 	dom_ran = isl_space_range(dom);
3181 	ran_dom = isl_space_domain(isl_space_copy(ran));
3182 	ran_ran = isl_space_range(ran);
3183 	dom = isl_space_join(isl_space_from_domain(dom_dom),
3184 			   isl_space_from_range(ran_dom));
3185 	ran = isl_space_join(isl_space_from_domain(dom_ran),
3186 			   isl_space_from_range(ran_ran));
3187 	return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)),
3188 			    isl_space_from_range(isl_space_wrap(ran)));
3189 error:
3190 	isl_space_free(space);
3191 	return NULL;
3192 }
3193 
3194 /* Can we apply isl_space_curry to "space"?
3195  * That is, does is it have a map space with a nested relation in its domain?
3196  */
isl_space_can_curry(__isl_keep isl_space * space)3197 isl_bool isl_space_can_curry(__isl_keep isl_space *space)
3198 {
3199 	return isl_space_domain_is_wrapping(space);
3200 }
3201 
3202 /* Given a space (A -> B) -> C, return the corresponding space
3203  * A -> (B -> C).
3204  */
isl_space_curry(__isl_take isl_space * space)3205 __isl_give isl_space *isl_space_curry(__isl_take isl_space *space)
3206 {
3207 	isl_space *dom, *ran;
3208 	isl_space *dom_dom, *dom_ran;
3209 
3210 	if (!space)
3211 		return NULL;
3212 
3213 	if (!isl_space_can_curry(space))
3214 		isl_die(space->ctx, isl_error_invalid,
3215 			"space cannot be curried", goto error);
3216 
3217 	dom = isl_space_unwrap(isl_space_domain(isl_space_copy(space)));
3218 	ran = isl_space_range(space);
3219 	dom_dom = isl_space_domain(isl_space_copy(dom));
3220 	dom_ran = isl_space_range(dom);
3221 	ran = isl_space_join(isl_space_from_domain(dom_ran),
3222 			   isl_space_from_range(ran));
3223 	return isl_space_join(isl_space_from_domain(dom_dom),
3224 			    isl_space_from_range(isl_space_wrap(ran)));
3225 error:
3226 	isl_space_free(space);
3227 	return NULL;
3228 }
3229 
3230 /* Can isl_space_range_curry be applied to "space"?
3231  * That is, does it have a nested relation in its range,
3232  * the domain of which is itself a nested relation?
3233  */
isl_space_can_range_curry(__isl_keep isl_space * space)3234 isl_bool isl_space_can_range_curry(__isl_keep isl_space *space)
3235 {
3236 	isl_bool can;
3237 
3238 	if (!space)
3239 		return isl_bool_error;
3240 	can = isl_space_range_is_wrapping(space);
3241 	if (can < 0 || !can)
3242 		return can;
3243 	return isl_space_can_curry(space->nested[1]);
3244 }
3245 
3246 /* Given a space A -> ((B -> C) -> D), return the corresponding space
3247  * A -> (B -> (C -> D)).
3248  */
isl_space_range_curry(__isl_take isl_space * space)3249 __isl_give isl_space *isl_space_range_curry(__isl_take isl_space *space)
3250 {
3251 	isl_space *nested;
3252 
3253 	if (!space)
3254 		return NULL;
3255 
3256 	if (!isl_space_can_range_curry(space))
3257 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
3258 			"space range cannot be curried",
3259 			return isl_space_free(space));
3260 
3261 	nested = isl_space_take_nested(space, 1);
3262 	nested = isl_space_curry(nested);
3263 	space = isl_space_restore_nested(space, 1, nested);
3264 
3265 	return space;
3266 }
3267 
3268 /* Can we apply isl_space_uncurry to "space"?
3269  * That is, does it have a map space with a nested relation in its range?
3270  */
isl_space_can_uncurry(__isl_keep isl_space * space)3271 isl_bool isl_space_can_uncurry(__isl_keep isl_space *space)
3272 {
3273 	return isl_space_range_is_wrapping(space);
3274 }
3275 
3276 /* Given a space A -> (B -> C), return the corresponding space
3277  * (A -> B) -> C.
3278  */
isl_space_uncurry(__isl_take isl_space * space)3279 __isl_give isl_space *isl_space_uncurry(__isl_take isl_space *space)
3280 {
3281 	isl_space *dom, *ran;
3282 	isl_space *ran_dom, *ran_ran;
3283 
3284 	if (!space)
3285 		return NULL;
3286 
3287 	if (!isl_space_can_uncurry(space))
3288 		isl_die(space->ctx, isl_error_invalid,
3289 			"space cannot be uncurried",
3290 			return isl_space_free(space));
3291 
3292 	dom = isl_space_domain(isl_space_copy(space));
3293 	ran = isl_space_unwrap(isl_space_range(space));
3294 	ran_dom = isl_space_domain(isl_space_copy(ran));
3295 	ran_ran = isl_space_range(ran);
3296 	dom = isl_space_join(isl_space_from_domain(dom),
3297 			   isl_space_from_range(ran_dom));
3298 	return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)),
3299 			    isl_space_from_range(ran_ran));
3300 }
3301 
isl_space_has_named_params(__isl_keep isl_space * space)3302 isl_bool isl_space_has_named_params(__isl_keep isl_space *space)
3303 {
3304 	int i;
3305 	isl_size off;
3306 
3307 	if (!space)
3308 		return isl_bool_error;
3309 	if (space->nparam == 0)
3310 		return isl_bool_true;
3311 	off = isl_space_offset(space, isl_dim_param);
3312 	if (off < 0)
3313 		return isl_bool_error;
3314 	if (off + space->nparam > space->n_id)
3315 		return isl_bool_false;
3316 	for (i = 0; i < space->nparam; ++i)
3317 		if (!space->ids[off + i])
3318 			return isl_bool_false;
3319 	return isl_bool_true;
3320 }
3321 
3322 /* Check that "space" has only named parameters, reporting an error
3323  * if it does not.
3324  */
isl_space_check_named_params(__isl_keep isl_space * space)3325 isl_stat isl_space_check_named_params(__isl_keep isl_space *space)
3326 {
3327 	isl_bool named;
3328 
3329 	named = isl_space_has_named_params(space);
3330 	if (named < 0)
3331 		return isl_stat_error;
3332 	if (!named)
3333 		isl_die(isl_space_get_ctx(space), isl_error_invalid,
3334 			"unexpected unnamed parameters", return isl_stat_error);
3335 
3336 	return isl_stat_ok;
3337 }
3338 
3339 /* Align the initial parameters of space1 to match the order in space2.
3340  */
isl_space_align_params(__isl_take isl_space * space1,__isl_take isl_space * space2)3341 __isl_give isl_space *isl_space_align_params(__isl_take isl_space *space1,
3342 	__isl_take isl_space *space2)
3343 {
3344 	isl_reordering *exp;
3345 
3346 	if (isl_space_check_named_params(space1) < 0 ||
3347 	    isl_space_check_named_params(space2) < 0)
3348 		goto error;
3349 
3350 	exp = isl_parameter_alignment_reordering(space1, space2);
3351 	isl_space_free(space1);
3352 	isl_space_free(space2);
3353 	space1 = isl_reordering_get_space(exp);
3354 	isl_reordering_free(exp);
3355 	return space1;
3356 error:
3357 	isl_space_free(space1);
3358 	isl_space_free(space2);
3359 	return NULL;
3360 }
3361 
3362 /* Given the space of set (domain), construct a space for a map
3363  * with as domain the given space and as range the range of "model".
3364  */
isl_space_extend_domain_with_range(__isl_take isl_space * space,__isl_take isl_space * model)3365 __isl_give isl_space *isl_space_extend_domain_with_range(
3366 	__isl_take isl_space *space, __isl_take isl_space *model)
3367 {
3368 	isl_size n_out;
3369 
3370 	if (!model)
3371 		goto error;
3372 
3373 	space = isl_space_from_domain(space);
3374 	n_out = isl_space_dim(model, isl_dim_out);
3375 	if (n_out < 0)
3376 		goto error;
3377 	space = isl_space_add_dims(space, isl_dim_out, n_out);
3378 	if (isl_space_has_tuple_id(model, isl_dim_out))
3379 		space = isl_space_set_tuple_id(space, isl_dim_out,
3380 				isl_space_get_tuple_id(model, isl_dim_out));
3381 	if (!space)
3382 		goto error;
3383 	if (model->nested[1]) {
3384 		isl_space *nested = isl_space_copy(model->nested[1]);
3385 		isl_size n_nested, n_space;
3386 		nested = isl_space_align_params(nested, isl_space_copy(space));
3387 		n_nested = isl_space_dim(nested, isl_dim_param);
3388 		n_space = isl_space_dim(space, isl_dim_param);
3389 		if (n_nested < 0 || n_space < 0)
3390 			goto error;
3391 		if (n_nested > n_space)
3392 			nested = isl_space_drop_dims(nested, isl_dim_param,
3393 						n_space, n_nested - n_space);
3394 		if (!nested)
3395 			goto error;
3396 		space->nested[1] = nested;
3397 	}
3398 	isl_space_free(model);
3399 	return space;
3400 error:
3401 	isl_space_free(model);
3402 	isl_space_free(space);
3403 	return NULL;
3404 }
3405 
3406 /* Compare the "type" dimensions of two isl_spaces.
3407  *
3408  * The order is fairly arbitrary.
3409  */
isl_space_cmp_type(__isl_keep isl_space * space1,__isl_keep isl_space * space2,enum isl_dim_type type)3410 static int isl_space_cmp_type(__isl_keep isl_space *space1,
3411 	__isl_keep isl_space *space2, enum isl_dim_type type)
3412 {
3413 	int cmp;
3414 	isl_size dim1, dim2;
3415 	isl_space *nested1, *nested2;
3416 
3417 	dim1 = isl_space_dim(space1, type);
3418 	dim2 = isl_space_dim(space2, type);
3419 	if (dim1 < 0 || dim2 < 0)
3420 		return 0;
3421 	if (dim1 != dim2)
3422 		return dim1 - dim2;
3423 
3424 	cmp = isl_id_cmp(tuple_id(space1, type), tuple_id(space2, type));
3425 	if (cmp != 0)
3426 		return cmp;
3427 
3428 	nested1 = nested(space1, type);
3429 	nested2 = nested(space2, type);
3430 	if (!nested1 != !nested2)
3431 		return !nested1 - !nested2;
3432 
3433 	if (nested1)
3434 		return isl_space_cmp(nested1, nested2);
3435 
3436 	return 0;
3437 }
3438 
3439 /* Compare two isl_spaces.
3440  *
3441  * The order is fairly arbitrary.
3442  */
isl_space_cmp(__isl_keep isl_space * space1,__isl_keep isl_space * space2)3443 int isl_space_cmp(__isl_keep isl_space *space1, __isl_keep isl_space *space2)
3444 {
3445 	int i;
3446 	int cmp;
3447 
3448 	if (space1 == space2)
3449 		return 0;
3450 	if (!space1)
3451 		return -1;
3452 	if (!space2)
3453 		return 1;
3454 
3455 	cmp = isl_space_cmp_type(space1, space2, isl_dim_param);
3456 	if (cmp != 0)
3457 		return cmp;
3458 	cmp = isl_space_cmp_type(space1, space2, isl_dim_in);
3459 	if (cmp != 0)
3460 		return cmp;
3461 	cmp = isl_space_cmp_type(space1, space2, isl_dim_out);
3462 	if (cmp != 0)
3463 		return cmp;
3464 
3465 	if (!space1->ids && !space2->ids)
3466 		return 0;
3467 
3468 	for (i = 0; i < n(space1, isl_dim_param); ++i) {
3469 		cmp = isl_id_cmp(get_id(space1, isl_dim_param, i),
3470 				 get_id(space2, isl_dim_param, i));
3471 		if (cmp != 0)
3472 			return cmp;
3473 	}
3474 
3475 	return 0;
3476 }
3477