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