ee45615c23ccd339db1bdaeb9f1e951eb6307906
[platform/upstream/isl.git] / isl_space.c
1 /*
2  * Copyright 2008-2009 Katholieke Universiteit Leuven
3  * Copyright 2010      INRIA Saclay
4  *
5  * Use of this software is governed by the GNU LGPLv2.1 license
6  *
7  * Written by Sven Verdoolaege, K.U.Leuven, Departement
8  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
9  * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite,
10  * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France 
11  */
12
13 #include <stdlib.h>
14 #include <isl_space_private.h>
15 #include <isl_id_private.h>
16 #include <isl_reordering.h>
17
18 isl_ctx *isl_space_get_ctx(__isl_keep isl_space *dim)
19 {
20         return dim ? dim->ctx : NULL;
21 }
22
23 __isl_give isl_space *isl_space_alloc(isl_ctx *ctx,
24                         unsigned nparam, unsigned n_in, unsigned n_out)
25 {
26         isl_space *dim;
27
28         dim = isl_alloc_type(ctx, struct isl_space);
29         if (!dim)
30                 return NULL;
31
32         dim->ctx = ctx;
33         isl_ctx_ref(ctx);
34         dim->ref = 1;
35         dim->nparam = nparam;
36         dim->n_in = n_in;
37         dim->n_out = n_out;
38
39         dim->tuple_id[0] = NULL;
40         dim->tuple_id[1] = NULL;
41
42         dim->nested[0] = NULL;
43         dim->nested[1] = NULL;
44
45         dim->n_id = 0;
46         dim->ids = NULL;
47
48         return dim;
49 }
50
51 /* Mark the space as being that of a set, by setting the domain tuple
52  * to isl_id_none.
53  */
54 static __isl_give isl_space *mark_as_set(__isl_take isl_space *space)
55 {
56         space = isl_space_cow(space);
57         if (!space)
58                 return NULL;
59         space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none);
60         return space;
61 }
62
63 /* Is the space that of a set?
64  */
65 int isl_space_is_set(__isl_keep isl_space *space)
66 {
67         if (!space)
68                 return -1;
69         if (space->n_in != 0 || space->nested[0])
70                 return 0;
71         if (space->tuple_id[0] != &isl_id_none)
72                 return 0;
73         return 1;
74 }
75
76 __isl_give isl_space *isl_space_set_alloc(isl_ctx *ctx,
77                         unsigned nparam, unsigned dim)
78 {
79         isl_space *space;
80         space = isl_space_alloc(ctx, nparam, 0, dim);
81         space = mark_as_set(space);
82         return space;
83 }
84
85 /* Mark the space as being that of a parameter domain, by setting
86  * both tuples to isl_id_none.
87  */
88 static __isl_give isl_space *mark_as_params(isl_space *space)
89 {
90         if (!space)
91                 return NULL;
92         space = isl_space_set_tuple_id(space, isl_dim_in, &isl_id_none);
93         space = isl_space_set_tuple_id(space, isl_dim_out, &isl_id_none);
94         return space;
95 }
96
97 /* Is the space that of a parameter domain?
98  */
99 int isl_space_is_params(__isl_keep isl_space *space)
100 {
101         if (!space)
102                 return -1;
103         if (space->n_in != 0 || space->nested[0] ||
104             space->n_out != 0 || space->nested[1])
105                 return 0;
106         if (space->tuple_id[0] != &isl_id_none)
107                 return 0;
108         if (space->tuple_id[1] != &isl_id_none)
109                 return 0;
110         return 1;
111 }
112
113 /* Create a space for a parameter domain.
114  */
115 __isl_give isl_space *isl_space_params_alloc(isl_ctx *ctx, unsigned nparam)
116 {
117         isl_space *space;
118         space = isl_space_alloc(ctx, nparam, 0, 0);
119         space = mark_as_params(space);
120         return space;
121 }
122
123 static unsigned global_pos(__isl_keep isl_space *dim,
124                                  enum isl_dim_type type, unsigned pos)
125 {
126         struct isl_ctx *ctx = dim->ctx;
127
128         switch (type) {
129         case isl_dim_param:
130                 isl_assert(ctx, pos < dim->nparam,
131                             return isl_space_dim(dim, isl_dim_all));
132                 return pos;
133         case isl_dim_in:
134                 isl_assert(ctx, pos < dim->n_in,
135                             return isl_space_dim(dim, isl_dim_all));
136                 return pos + dim->nparam;
137         case isl_dim_out:
138                 isl_assert(ctx, pos < dim->n_out,
139                             return isl_space_dim(dim, isl_dim_all));
140                 return pos + dim->nparam + dim->n_in;
141         default:
142                 isl_assert(ctx, 0, return isl_space_dim(dim, isl_dim_all));
143         }
144         return isl_space_dim(dim, isl_dim_all);
145 }
146
147 /* Extend length of ids array to the total number of dimensions.
148  */
149 static __isl_give isl_space *extend_ids(__isl_take isl_space *dim)
150 {
151         isl_id **ids;
152         int i;
153
154         if (isl_space_dim(dim, isl_dim_all) <= dim->n_id)
155                 return dim;
156
157         if (!dim->ids) {
158                 dim->ids = isl_calloc_array(dim->ctx,
159                                 isl_id *, isl_space_dim(dim, isl_dim_all));
160                 if (!dim->ids)
161                         goto error;
162         } else {
163                 ids = isl_realloc_array(dim->ctx, dim->ids,
164                                 isl_id *, isl_space_dim(dim, isl_dim_all));
165                 if (!ids)
166                         goto error;
167                 dim->ids = ids;
168                 for (i = dim->n_id; i < isl_space_dim(dim, isl_dim_all); ++i)
169                         dim->ids[i] = NULL;
170         }
171
172         dim->n_id = isl_space_dim(dim, isl_dim_all);
173
174         return dim;
175 error:
176         isl_space_free(dim);
177         return NULL;
178 }
179
180 static __isl_give isl_space *set_id(__isl_take isl_space *dim,
181         enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
182 {
183         dim = isl_space_cow(dim);
184
185         if (!dim)
186                 goto error;
187
188         pos = global_pos(dim, type, pos);
189         if (pos == isl_space_dim(dim, isl_dim_all))
190                 goto error;
191
192         if (pos >= dim->n_id) {
193                 if (!id)
194                         return dim;
195                 dim = extend_ids(dim);
196                 if (!dim)
197                         goto error;
198         }
199
200         dim->ids[pos] = id;
201
202         return dim;
203 error:
204         isl_id_free(id);
205         isl_space_free(dim);
206         return NULL;
207 }
208
209 static __isl_keep isl_id *get_id(__isl_keep isl_space *dim,
210                                  enum isl_dim_type type, unsigned pos)
211 {
212         if (!dim)
213                 return NULL;
214
215         pos = global_pos(dim, type, pos);
216         if (pos == isl_space_dim(dim, isl_dim_all))
217                 return NULL;
218         if (pos >= dim->n_id)
219                 return NULL;
220         return dim->ids[pos];
221 }
222
223 static unsigned offset(__isl_keep isl_space *dim, enum isl_dim_type type)
224 {
225         switch (type) {
226         case isl_dim_param:     return 0;
227         case isl_dim_in:        return dim->nparam;
228         case isl_dim_out:       return dim->nparam + dim->n_in;
229         default:                return 0;
230         }
231 }
232
233 static unsigned n(__isl_keep isl_space *dim, enum isl_dim_type type)
234 {
235         switch (type) {
236         case isl_dim_param:     return dim->nparam;
237         case isl_dim_in:        return dim->n_in;
238         case isl_dim_out:       return dim->n_out;
239         case isl_dim_all:       return dim->nparam + dim->n_in + dim->n_out;
240         default:                return 0;
241         }
242 }
243
244 unsigned isl_space_dim(__isl_keep isl_space *dim, enum isl_dim_type type)
245 {
246         if (!dim)
247                 return 0;
248         return n(dim, type);
249 }
250
251 unsigned isl_space_offset(__isl_keep isl_space *dim, enum isl_dim_type type)
252 {
253         if (!dim)
254                 return 0;
255         return offset(dim, type);
256 }
257
258 static __isl_give isl_space *copy_ids(__isl_take isl_space *dst,
259         enum isl_dim_type dst_type, unsigned offset, __isl_keep isl_space *src,
260         enum isl_dim_type src_type)
261 {
262         int i;
263         isl_id *id;
264
265         if (!dst)
266                 return NULL;
267
268         for (i = 0; i < n(src, src_type); ++i) {
269                 id = get_id(src, src_type, i);
270                 if (!id)
271                         continue;
272                 dst = set_id(dst, dst_type, offset + i, isl_id_copy(id));
273                 if (!dst)
274                         return NULL;
275         }
276         return dst;
277 }
278
279 __isl_take isl_space *isl_space_dup(__isl_keep isl_space *dim)
280 {
281         isl_space *dup;
282         if (!dim)
283                 return NULL;
284         dup = isl_space_alloc(dim->ctx, dim->nparam, dim->n_in, dim->n_out);
285         if (dim->tuple_id[0] &&
286             !(dup->tuple_id[0] = isl_id_copy(dim->tuple_id[0])))
287                 goto error;
288         if (dim->tuple_id[1] &&
289             !(dup->tuple_id[1] = isl_id_copy(dim->tuple_id[1])))
290                 goto error;
291         if (dim->nested[0] && !(dup->nested[0] = isl_space_copy(dim->nested[0])))
292                 goto error;
293         if (dim->nested[1] && !(dup->nested[1] = isl_space_copy(dim->nested[1])))
294                 goto error;
295         if (!dim->ids)
296                 return dup;
297         dup = copy_ids(dup, isl_dim_param, 0, dim, isl_dim_param);
298         dup = copy_ids(dup, isl_dim_in, 0, dim, isl_dim_in);
299         dup = copy_ids(dup, isl_dim_out, 0, dim, isl_dim_out);
300         return dup;
301 error:
302         isl_space_free(dup);
303         return NULL;
304 }
305
306 __isl_give isl_space *isl_space_cow(__isl_take isl_space *dim)
307 {
308         if (!dim)
309                 return NULL;
310
311         if (dim->ref == 1)
312                 return dim;
313         dim->ref--;
314         return isl_space_dup(dim);
315 }
316
317 __isl_give isl_space *isl_space_copy(__isl_keep isl_space *dim)
318 {
319         if (!dim)
320                 return NULL;
321
322         dim->ref++;
323         return dim;
324 }
325
326 void isl_space_free(__isl_take isl_space *dim)
327 {
328         int i;
329
330         if (!dim)
331                 return;
332
333         if (--dim->ref > 0)
334                 return;
335
336         isl_id_free(dim->tuple_id[0]);
337         isl_id_free(dim->tuple_id[1]);
338
339         isl_space_free(dim->nested[0]);
340         isl_space_free(dim->nested[1]);
341
342         for (i = 0; i < dim->n_id; ++i)
343                 isl_id_free(dim->ids[i]);
344         free(dim->ids);
345         isl_ctx_deref(dim->ctx);
346         
347         free(dim);
348 }
349
350 static int name_ok(isl_ctx *ctx, const char *s)
351 {
352         char *p;
353         long dummy;
354
355         dummy = strtol(s, &p, 0);
356         if (p != s)
357                 isl_die(ctx, isl_error_invalid, "name looks like a number",
358                         return 0);
359
360         return 1;
361 }
362
363 /* Is it possible for the given dimension type to have a tuple id?
364  */
365 static int space_can_have_id(__isl_keep isl_space *space,
366         enum isl_dim_type type)
367 {
368         if (!space)
369                 return 0;
370         if (isl_space_is_params(space))
371                 isl_die(space->ctx, isl_error_invalid,
372                         "parameter spaces don't have tuple ids", return 0);
373         if (isl_space_is_set(space) && type != isl_dim_set)
374                 isl_die(space->ctx, isl_error_invalid,
375                         "set spaces can only have a set id", return 0);
376         if (type != isl_dim_in && type != isl_dim_out)
377                 isl_die(space->ctx, isl_error_invalid,
378                         "only input, output and set tuples can have ids",
379                         return 0);
380
381         return 1;
382 }
383
384 /* Does the tuple have an id?
385  */
386 int isl_space_has_tuple_id(__isl_keep isl_space *dim, enum isl_dim_type type)
387 {
388         if (!space_can_have_id(dim, type))
389                 return -1;
390         return dim->tuple_id[type - isl_dim_in] != NULL;
391 }
392
393 __isl_give isl_id *isl_space_get_tuple_id(__isl_keep isl_space *dim,
394         enum isl_dim_type type)
395 {
396         int has_id;
397
398         if (!dim)
399                 return NULL;
400         has_id = isl_space_has_tuple_id(dim, type);
401         if (has_id < 0)
402                 return NULL;
403         if (!has_id)
404                 isl_die(dim->ctx, isl_error_invalid,
405                         "tuple has no id", return NULL);
406         return isl_id_copy(dim->tuple_id[type - isl_dim_in]);
407 }
408
409 __isl_give isl_space *isl_space_set_tuple_id(__isl_take isl_space *dim,
410         enum isl_dim_type type, __isl_take isl_id *id)
411 {
412         dim = isl_space_cow(dim);
413         if (!dim || !id)
414                 goto error;
415         if (type != isl_dim_in && type != isl_dim_out)
416                 isl_die(dim->ctx, isl_error_invalid,
417                         "only input, output and set tuples can have names",
418                         goto error);
419
420         isl_id_free(dim->tuple_id[type - isl_dim_in]);
421         dim->tuple_id[type - isl_dim_in] = id;
422
423         return dim;
424 error:
425         isl_id_free(id);
426         isl_space_free(dim);
427         return NULL;
428 }
429
430 __isl_give isl_space *isl_space_reset_tuple_id(__isl_take isl_space *dim,
431         enum isl_dim_type type)
432 {
433         dim = isl_space_cow(dim);
434         if (!dim)
435                 return NULL;
436         if (type != isl_dim_in && type != isl_dim_out)
437                 isl_die(dim->ctx, isl_error_invalid,
438                         "only input, output and set tuples can have names",
439                         goto error);
440
441         isl_id_free(dim->tuple_id[type - isl_dim_in]);
442         dim->tuple_id[type - isl_dim_in] = NULL;
443
444         return dim;
445 error:
446         isl_space_free(dim);
447         return NULL;
448 }
449
450 /* Set the id of the given dimension of "space" to "id".
451  * If the dimension already has an id, then it is replaced.
452  * If the dimension is a parameter, then we need to change it
453  * in the nested spaces (if any) as well.
454  */
455 __isl_give isl_space *isl_space_set_dim_id(__isl_take isl_space *space,
456         enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
457 {
458         space = isl_space_cow(space);
459         if (!space || !id)
460                 goto error;
461
462         if (type == isl_dim_param) {
463                 int i;
464
465                 for (i = 0; i < 2; ++i) {
466                         if (!space->nested[i])
467                                 continue;
468                         space->nested[i] =
469                                 isl_space_set_dim_id(space->nested[i],
470                                                 type, pos, isl_id_copy(id));
471                         if (!space->nested[i])
472                                 goto error;
473                 }
474         }
475
476         isl_id_free(get_id(space, type, pos));
477         return set_id(space, type, pos, id);
478 error:
479         isl_id_free(id);
480         isl_space_free(space);
481         return NULL;
482 }
483
484 /* Reset the id of the given dimension of "space".
485  * If the dimension already has an id, then it is removed.
486  * If the dimension is a parameter, then we need to reset it
487  * in the nested spaces (if any) as well.
488  */
489 __isl_give isl_space *isl_space_reset_dim_id(__isl_take isl_space *space,
490         enum isl_dim_type type, unsigned pos)
491 {
492         space = isl_space_cow(space);
493         if (!space)
494                 goto error;
495
496         if (type == isl_dim_param) {
497                 int i;
498
499                 for (i = 0; i < 2; ++i) {
500                         if (!space->nested[i])
501                                 continue;
502                         space->nested[i] =
503                                 isl_space_reset_dim_id(space->nested[i],
504                                                         type, pos);
505                         if (!space->nested[i])
506                                 goto error;
507                 }
508         }
509
510         isl_id_free(get_id(space, type, pos));
511         return set_id(space, type, pos, NULL);
512 error:
513         isl_space_free(space);
514         return NULL;
515 }
516
517 int isl_space_has_dim_id(__isl_keep isl_space *dim,
518         enum isl_dim_type type, unsigned pos)
519 {
520         if (!dim)
521                 return -1;
522         return get_id(dim, type, pos) != NULL;
523 }
524
525 __isl_give isl_id *isl_space_get_dim_id(__isl_keep isl_space *dim,
526         enum isl_dim_type type, unsigned pos)
527 {
528         if (!dim)
529                 return NULL;
530         if (!get_id(dim, type, pos))
531                 isl_die(dim->ctx, isl_error_invalid,
532                         "dim has no id", return NULL);
533         return isl_id_copy(get_id(dim, type, pos));
534 }
535
536 __isl_give isl_space *isl_space_set_tuple_name(__isl_take isl_space *dim,
537         enum isl_dim_type type, const char *s)
538 {
539         isl_id *id;
540
541         if (!dim)
542                 return NULL;
543
544         if (!s)
545                 return isl_space_reset_tuple_id(dim, type);
546
547         if (!name_ok(dim->ctx, s))
548                 goto error;
549
550         id = isl_id_alloc(dim->ctx, s, NULL);
551         return isl_space_set_tuple_id(dim, type, id);
552 error:
553         isl_space_free(dim);
554         return NULL;
555 }
556
557 /* Does the tuple have a name?
558  */
559 int isl_space_has_tuple_name(__isl_keep isl_space *space,
560         enum isl_dim_type type)
561 {
562         isl_id *id;
563
564         if (!space_can_have_id(space, type))
565                 return -1;
566         id = space->tuple_id[type - isl_dim_in];
567         return id && id->name;
568 }
569
570 const char *isl_space_get_tuple_name(__isl_keep isl_space *dim,
571          enum isl_dim_type type)
572 {
573         isl_id *id;
574         if (!dim)
575                 return NULL;
576         if (type != isl_dim_in && type != isl_dim_out)
577                 return NULL;
578         id = dim->tuple_id[type - isl_dim_in];
579         return id ? id->name : NULL;
580 }
581
582 __isl_give isl_space *isl_space_set_dim_name(__isl_take isl_space *dim,
583                                  enum isl_dim_type type, unsigned pos,
584                                  const char *s)
585 {
586         isl_id *id;
587
588         if (!dim)
589                 return NULL;
590         if (!s)
591                 return isl_space_reset_dim_id(dim, type, pos);
592         if (!name_ok(dim->ctx, s))
593                 goto error;
594         id = isl_id_alloc(dim->ctx, s, NULL);
595         return isl_space_set_dim_id(dim, type, pos, id);
596 error:
597         isl_space_free(dim);
598         return NULL;
599 }
600
601 /* Does the given dimension have a name?
602  */
603 int isl_space_has_dim_name(__isl_keep isl_space *space,
604         enum isl_dim_type type, unsigned pos)
605 {
606         isl_id *id;
607
608         if (!space)
609                 return -1;
610         id = get_id(space, type, pos);
611         return id && id->name;
612 }
613
614 __isl_keep const char *isl_space_get_dim_name(__isl_keep isl_space *dim,
615                                  enum isl_dim_type type, unsigned pos)
616 {
617         isl_id *id = get_id(dim, type, pos);
618         return id ? id->name : NULL;
619 }
620
621 int isl_space_find_dim_by_id(__isl_keep isl_space *dim, enum isl_dim_type type,
622         __isl_keep isl_id *id)
623 {
624         int i;
625         int offset;
626         int n;
627
628         if (!dim || !id)
629                 return -1;
630
631         offset = isl_space_offset(dim, type);
632         n = isl_space_dim(dim, type);
633         for (i = 0; i < n && offset + i < dim->n_id; ++i)
634                 if (dim->ids[offset + i] == id)
635                         return i;
636
637         return -1;
638 }
639
640 int isl_space_find_dim_by_name(__isl_keep isl_space *space,
641         enum isl_dim_type type, const char *name)
642 {
643         int i;
644         int offset;
645         int n;
646
647         if (!space || !name)
648                 return -1;
649
650         offset = isl_space_offset(space, type);
651         n = isl_space_dim(space, type);
652         for (i = 0; i < n && offset + i < space->n_id; ++i)
653                 if (space->ids[offset + i]->name &&
654                     !strcmp(space->ids[offset + i]->name, name))
655                         return i;
656
657         return -1;
658 }
659
660 static __isl_keep isl_id *tuple_id(__isl_keep isl_space *dim,
661         enum isl_dim_type type)
662 {
663         if (!dim)
664                 return NULL;
665         if (type == isl_dim_in)
666                 return dim->tuple_id[0];
667         if (type == isl_dim_out)
668                 return dim->tuple_id[1];
669         return NULL;
670 }
671
672 static __isl_keep isl_space *nested(__isl_keep isl_space *dim,
673         enum isl_dim_type type)
674 {
675         if (!dim)
676                 return NULL;
677         if (type == isl_dim_in)
678                 return dim->nested[0];
679         if (type == isl_dim_out)
680                 return dim->nested[1];
681         return NULL;
682 }
683
684 int isl_space_tuple_match(__isl_keep isl_space *dim1, enum isl_dim_type dim1_type,
685                         __isl_keep isl_space *dim2, enum isl_dim_type dim2_type)
686 {
687         isl_id *id1, *id2;
688         isl_space *nested1, *nested2;
689
690         if (!dim1 || !dim2)
691                 return -1;
692
693         if (dim1 == dim2 && dim1_type == dim2_type)
694                 return 1;
695
696         if (n(dim1, dim1_type) != n(dim2, dim2_type))
697                 return 0;
698         id1 = tuple_id(dim1, dim1_type);
699         id2 = tuple_id(dim2, dim2_type);
700         if (!id1 ^ !id2)
701                 return 0;
702         if (id1 && id1 != id2)
703                 return 0;
704         nested1 = nested(dim1, dim1_type);
705         nested2 = nested(dim2, dim2_type);
706         if (!nested1 ^ !nested2)
707                 return 0;
708         if (nested1 && !isl_space_is_equal(nested1, nested2))
709                 return 0;
710         return 1;
711 }
712
713 static int match(__isl_keep isl_space *dim1, enum isl_dim_type dim1_type,
714         __isl_keep isl_space *dim2, enum isl_dim_type dim2_type)
715 {
716         int i;
717
718         if (dim1 == dim2 && dim1_type == dim2_type)
719                 return 1;
720
721         if (!isl_space_tuple_match(dim1, dim1_type, dim2, dim2_type))
722                 return 0;
723
724         if (!dim1->ids && !dim2->ids)
725                 return 1;
726
727         for (i = 0; i < n(dim1, dim1_type); ++i) {
728                 if (get_id(dim1, dim1_type, i) != get_id(dim2, dim2_type, i))
729                         return 0;
730         }
731         return 1;
732 }
733
734 int isl_space_match(__isl_keep isl_space *dim1, enum isl_dim_type dim1_type,
735         __isl_keep isl_space *dim2, enum isl_dim_type dim2_type)
736 {
737         if (!dim1 || !dim2)
738                 return -1;
739
740         return match(dim1, dim1_type, dim2, dim2_type);
741 }
742
743 static void get_ids(__isl_keep isl_space *dim, enum isl_dim_type type,
744         unsigned first, unsigned n, __isl_keep isl_id **ids)
745 {
746         int i;
747
748         for (i = 0; i < n ; ++i)
749                 ids[i] = get_id(dim, type, first + i);
750 }
751
752 __isl_give isl_space *isl_space_extend(__isl_take isl_space *dim,
753                         unsigned nparam, unsigned n_in, unsigned n_out)
754 {
755         isl_id **ids = NULL;
756
757         if (!dim)
758                 return NULL;
759         if (dim->nparam == nparam && dim->n_in == n_in && dim->n_out == n_out)
760                 return dim;
761
762         isl_assert(dim->ctx, dim->nparam <= nparam, goto error);
763         isl_assert(dim->ctx, dim->n_in <= n_in, goto error);
764         isl_assert(dim->ctx, dim->n_out <= n_out, goto error);
765
766         dim = isl_space_cow(dim);
767
768         if (dim->ids) {
769                 ids = isl_calloc_array(dim->ctx, isl_id *,
770                                          nparam + n_in + n_out);
771                 if (!ids)
772                         goto error;
773                 get_ids(dim, isl_dim_param, 0, dim->nparam, ids);
774                 get_ids(dim, isl_dim_in, 0, dim->n_in, ids + nparam);
775                 get_ids(dim, isl_dim_out, 0, dim->n_out, ids + nparam + n_in);
776                 free(dim->ids);
777                 dim->ids = ids;
778                 dim->n_id = nparam + n_in + n_out;
779         }
780         dim->nparam = nparam;
781         dim->n_in = n_in;
782         dim->n_out = n_out;
783
784         return dim;
785 error:
786         free(ids);
787         isl_space_free(dim);
788         return NULL;
789 }
790
791 __isl_give isl_space *isl_space_add_dims(__isl_take isl_space *dim,
792         enum isl_dim_type type, unsigned n)
793 {
794         if (!dim)
795                 return NULL;
796         dim = isl_space_reset(dim, type);
797         switch (type) {
798         case isl_dim_param:
799                 dim = isl_space_extend(dim,
800                                         dim->nparam + n, dim->n_in, dim->n_out);
801                 if (dim && dim->nested[0] &&
802                     !(dim->nested[0] = isl_space_add_dims(dim->nested[0],
803                                                     isl_dim_param, n)))
804                         goto error;
805                 if (dim && dim->nested[1] &&
806                     !(dim->nested[1] = isl_space_add_dims(dim->nested[1],
807                                                     isl_dim_param, n)))
808                         goto error;
809                 return dim;
810         case isl_dim_in:
811                 return isl_space_extend(dim,
812                                         dim->nparam, dim->n_in + n, dim->n_out);
813         case isl_dim_out:
814                 return isl_space_extend(dim,
815                                         dim->nparam, dim->n_in, dim->n_out + n);
816         default:
817                 isl_die(dim->ctx, isl_error_invalid,
818                         "cannot add dimensions of specified type", goto error);
819         }
820 error:
821         isl_space_free(dim);
822         return NULL;
823 }
824
825 static int valid_dim_type(enum isl_dim_type type)
826 {
827         switch (type) {
828         case isl_dim_param:
829         case isl_dim_in:
830         case isl_dim_out:
831                 return 1;
832         default:
833                 return 0;
834         }
835 }
836
837 __isl_give isl_space *isl_space_insert_dims(__isl_take isl_space *dim,
838         enum isl_dim_type type, unsigned pos, unsigned n)
839 {
840         isl_id **ids = NULL;
841
842         if (!dim)
843                 return NULL;
844         if (n == 0)
845                 return isl_space_reset(dim, type);
846
847         if (!valid_dim_type(type))
848                 isl_die(dim->ctx, isl_error_invalid,
849                         "cannot insert dimensions of specified type",
850                         goto error);
851
852         isl_assert(dim->ctx, pos <= isl_space_dim(dim, type), goto error);
853
854         dim = isl_space_cow(dim);
855         if (!dim)
856                 return NULL;
857
858         if (dim->ids) {
859                 enum isl_dim_type t;
860                 int off;
861                 int s[3];
862                 int *size = s - isl_dim_param;
863                 ids = isl_calloc_array(dim->ctx, isl_id *,
864                                      dim->nparam + dim->n_in + dim->n_out + n);
865                 if (!ids)
866                         goto error;
867                 off = 0;
868                 size[isl_dim_param] = dim->nparam;
869                 size[isl_dim_in] = dim->n_in;
870                 size[isl_dim_out] = dim->n_out;
871                 for (t = isl_dim_param; t <= isl_dim_out; ++t) {
872                         if (t != type) {
873                                 get_ids(dim, t, 0, size[t], ids + off);
874                                 off += size[t];
875                         } else {
876                                 get_ids(dim, t, 0, pos, ids + off);
877                                 off += pos + n;
878                                 get_ids(dim, t, pos, size[t] - pos, ids + off);
879                                 off += size[t] - pos;
880                         }
881                 }
882                 free(dim->ids);
883                 dim->ids = ids;
884                 dim->n_id = dim->nparam + dim->n_in + dim->n_out + n;
885         }
886         switch (type) {
887         case isl_dim_param:     dim->nparam += n; break;
888         case isl_dim_in:        dim->n_in += n; break;
889         case isl_dim_out:       dim->n_out += n; break;
890         default:                ;
891         }
892         dim = isl_space_reset(dim, type);
893
894         return dim;
895 error:
896         isl_space_free(dim);
897         return NULL;
898 }
899
900 __isl_give isl_space *isl_space_move_dims(__isl_take isl_space *dim,
901         enum isl_dim_type dst_type, unsigned dst_pos,
902         enum isl_dim_type src_type, unsigned src_pos, unsigned n)
903 {
904         int i;
905
906         if (!dim)
907                 return NULL;
908         if (n == 0)
909                 return dim;
910
911         isl_assert(dim->ctx, src_pos + n <= isl_space_dim(dim, src_type),
912                 goto error);
913
914         if (dst_type == src_type && dst_pos == src_pos)
915                 return dim;
916
917         isl_assert(dim->ctx, dst_type != src_type, goto error);
918
919         dim = isl_space_reset(dim, src_type);
920         dim = isl_space_reset(dim, dst_type);
921
922         dim = isl_space_cow(dim);
923         if (!dim)
924                 return NULL;
925
926         if (dim->ids) {
927                 isl_id **ids;
928                 enum isl_dim_type t;
929                 int off;
930                 int s[3];
931                 int *size = s - isl_dim_param;
932                 ids = isl_calloc_array(dim->ctx, isl_id *,
933                                          dim->nparam + dim->n_in + dim->n_out);
934                 if (!ids)
935                         goto error;
936                 off = 0;
937                 size[isl_dim_param] = dim->nparam;
938                 size[isl_dim_in] = dim->n_in;
939                 size[isl_dim_out] = dim->n_out;
940                 for (t = isl_dim_param; t <= isl_dim_out; ++t) {
941                         if (t == dst_type) {
942                                 get_ids(dim, t, 0, dst_pos, ids + off);
943                                 off += dst_pos;
944                                 get_ids(dim, src_type, src_pos, n, ids + off);
945                                 off += n;
946                                 get_ids(dim, t, dst_pos, size[t] - dst_pos,
947                                                 ids + off);
948                                 off += size[t] - dst_pos;
949                         } else if (t == src_type) {
950                                 get_ids(dim, t, 0, src_pos, ids + off);
951                                 off += src_pos;
952                                 get_ids(dim, t, src_pos + n,
953                                             size[t] - src_pos - n, ids + off);
954                                 off += size[t] - src_pos - n;
955                         } else {
956                                 get_ids(dim, t, 0, size[t], ids + off);
957                                 off += size[t];
958                         }
959                 }
960                 free(dim->ids);
961                 dim->ids = ids;
962                 dim->n_id = dim->nparam + dim->n_in + dim->n_out;
963         }
964
965         switch (dst_type) {
966         case isl_dim_param:     dim->nparam += n; break;
967         case isl_dim_in:        dim->n_in += n; break;
968         case isl_dim_out:       dim->n_out += n; break;
969         default:                ;
970         }
971
972         switch (src_type) {
973         case isl_dim_param:     dim->nparam -= n; break;
974         case isl_dim_in:        dim->n_in -= n; break;
975         case isl_dim_out:       dim->n_out -= n; break;
976         default:                ;
977         }
978
979         if (dst_type != isl_dim_param && src_type != isl_dim_param)
980                 return dim;
981
982         for (i = 0; i < 2; ++i) {
983                 if (!dim->nested[i])
984                         continue;
985                 dim->nested[i] = isl_space_replace(dim->nested[i],
986                                                  isl_dim_param, dim);
987                 if (!dim->nested[i])
988                         goto error;
989         }
990
991         return dim;
992 error:
993         isl_space_free(dim);
994         return NULL;
995 }
996
997 __isl_give isl_space *isl_space_join(__isl_take isl_space *left,
998         __isl_take isl_space *right)
999 {
1000         isl_space *dim;
1001
1002         if (!left || !right)
1003                 goto error;
1004
1005         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
1006                         goto error);
1007         isl_assert(left->ctx,
1008                 isl_space_tuple_match(left, isl_dim_out, right, isl_dim_in),
1009                 goto error);
1010
1011         dim = isl_space_alloc(left->ctx, left->nparam, left->n_in, right->n_out);
1012         if (!dim)
1013                 goto error;
1014
1015         dim = copy_ids(dim, isl_dim_param, 0, left, isl_dim_param);
1016         dim = copy_ids(dim, isl_dim_in, 0, left, isl_dim_in);
1017         dim = copy_ids(dim, isl_dim_out, 0, right, isl_dim_out);
1018
1019         if (dim && left->tuple_id[0] &&
1020             !(dim->tuple_id[0] = isl_id_copy(left->tuple_id[0])))
1021                 goto error;
1022         if (dim && right->tuple_id[1] &&
1023             !(dim->tuple_id[1] = isl_id_copy(right->tuple_id[1])))
1024                 goto error;
1025         if (dim && left->nested[0] &&
1026             !(dim->nested[0] = isl_space_copy(left->nested[0])))
1027                 goto error;
1028         if (dim && right->nested[1] &&
1029             !(dim->nested[1] = isl_space_copy(right->nested[1])))
1030                 goto error;
1031
1032         isl_space_free(left);
1033         isl_space_free(right);
1034
1035         return dim;
1036 error:
1037         isl_space_free(left);
1038         isl_space_free(right);
1039         return NULL;
1040 }
1041
1042 __isl_give isl_space *isl_space_product(__isl_take isl_space *left,
1043         __isl_take isl_space *right)
1044 {
1045         isl_space *dom1, *dom2, *nest1, *nest2;
1046
1047         if (!left || !right)
1048                 goto error;
1049
1050         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
1051                         goto error);
1052
1053         dom1 = isl_space_domain(isl_space_copy(left));
1054         dom2 = isl_space_domain(isl_space_copy(right));
1055         nest1 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
1056
1057         dom1 = isl_space_range(left);
1058         dom2 = isl_space_range(right);
1059         nest2 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
1060
1061         return isl_space_join(isl_space_reverse(nest1), nest2);
1062 error:
1063         isl_space_free(left);
1064         isl_space_free(right);
1065         return NULL;
1066 }
1067
1068 /* Given two spaces { A -> C } and { B -> C }, construct the space
1069  * { [A -> B] -> C }
1070  */
1071 __isl_give isl_space *isl_space_domain_product(__isl_take isl_space *left,
1072         __isl_take isl_space *right)
1073 {
1074         isl_space *ran, *dom1, *dom2, *nest;
1075
1076         if (!left || !right)
1077                 goto error;
1078
1079         if (!match(left, isl_dim_param, right, isl_dim_param))
1080                 isl_die(left->ctx, isl_error_invalid,
1081                         "parameters need to match", goto error);
1082         if (!isl_space_tuple_match(left, isl_dim_out, right, isl_dim_out))
1083                 isl_die(left->ctx, isl_error_invalid,
1084                         "ranges need to match", goto error);
1085
1086         ran = isl_space_range(isl_space_copy(left));
1087
1088         dom1 = isl_space_domain(left);
1089         dom2 = isl_space_domain(right);
1090         nest = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
1091
1092         return isl_space_join(isl_space_reverse(nest), ran);
1093 error:
1094         isl_space_free(left);
1095         isl_space_free(right);
1096         return NULL;
1097 }
1098
1099 __isl_give isl_space *isl_space_range_product(__isl_take isl_space *left,
1100         __isl_take isl_space *right)
1101 {
1102         isl_space *dom, *ran1, *ran2, *nest;
1103
1104         if (!left || !right)
1105                 goto error;
1106
1107         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
1108                         goto error);
1109         if (!isl_space_tuple_match(left, isl_dim_in, right, isl_dim_in))
1110                 isl_die(left->ctx, isl_error_invalid,
1111                         "domains need to match", goto error);
1112
1113         dom = isl_space_domain(isl_space_copy(left));
1114
1115         ran1 = isl_space_range(left);
1116         ran2 = isl_space_range(right);
1117         nest = isl_space_wrap(isl_space_join(isl_space_reverse(ran1), ran2));
1118
1119         return isl_space_join(isl_space_reverse(dom), nest);
1120 error:
1121         isl_space_free(left);
1122         isl_space_free(right);
1123         return NULL;
1124 }
1125
1126 __isl_give isl_space *isl_space_map_from_set(__isl_take isl_space *dim)
1127 {
1128         isl_ctx *ctx;
1129         isl_id **ids = NULL;
1130
1131         if (!dim)
1132                 return NULL;
1133         ctx = isl_space_get_ctx(dim);
1134         if (!isl_space_is_set(dim))
1135                 isl_die(ctx, isl_error_invalid, "not a set space", goto error);
1136         dim = isl_space_cow(dim);
1137         if (!dim)
1138                 return NULL;
1139         if (dim->ids) {
1140                 ids = isl_calloc_array(dim->ctx, isl_id *,
1141                                         dim->nparam + dim->n_out + dim->n_out);
1142                 if (!ids)
1143                         goto error;
1144                 get_ids(dim, isl_dim_param, 0, dim->nparam, ids);
1145                 get_ids(dim, isl_dim_out, 0, dim->n_out, ids + dim->nparam);
1146         }
1147         dim->n_in = dim->n_out;
1148         if (ids) {
1149                 free(dim->ids);
1150                 dim->ids = ids;
1151                 dim->n_id = dim->nparam + dim->n_out + dim->n_out;
1152                 dim = copy_ids(dim, isl_dim_out, 0, dim, isl_dim_in);
1153         }
1154         isl_id_free(dim->tuple_id[0]);
1155         dim->tuple_id[0] = isl_id_copy(dim->tuple_id[1]);
1156         isl_space_free(dim->nested[0]);
1157         dim->nested[0] = isl_space_copy(dim->nested[1]);
1158         return dim;
1159 error:
1160         isl_space_free(dim);
1161         return NULL;
1162 }
1163
1164 __isl_give isl_space *isl_space_map_from_domain_and_range(
1165         __isl_take isl_space *domain, __isl_take isl_space *range)
1166 {
1167         if (!domain || !range)
1168                 goto error;
1169         if (!isl_space_is_set(domain))
1170                 isl_die(isl_space_get_ctx(domain), isl_error_invalid,
1171                         "domain is not a set space", goto error);
1172         if (!isl_space_is_set(range))
1173                 isl_die(isl_space_get_ctx(range), isl_error_invalid,
1174                         "range is not a set space", goto error);
1175         return isl_space_join(isl_space_reverse(domain), range);
1176 error:
1177         isl_space_free(domain);
1178         isl_space_free(range);
1179         return NULL;
1180 }
1181
1182 static __isl_give isl_space *set_ids(__isl_take isl_space *dim,
1183         enum isl_dim_type type,
1184         unsigned first, unsigned n, __isl_take isl_id **ids)
1185 {
1186         int i;
1187
1188         for (i = 0; i < n ; ++i)
1189                 dim = set_id(dim, type, first + i, ids[i]);
1190
1191         return dim;
1192 }
1193
1194 __isl_give isl_space *isl_space_reverse(__isl_take isl_space *dim)
1195 {
1196         unsigned t;
1197         isl_space *nested;
1198         isl_id **ids = NULL;
1199         isl_id *id;
1200
1201         if (!dim)
1202                 return NULL;
1203         if (match(dim, isl_dim_in, dim, isl_dim_out))
1204                 return dim;
1205
1206         dim = isl_space_cow(dim);
1207         if (!dim)
1208                 return NULL;
1209
1210         id = dim->tuple_id[0];
1211         dim->tuple_id[0] = dim->tuple_id[1];
1212         dim->tuple_id[1] = id;
1213
1214         nested = dim->nested[0];
1215         dim->nested[0] = dim->nested[1];
1216         dim->nested[1] = nested;
1217
1218         if (dim->ids) {
1219                 ids = isl_alloc_array(dim->ctx, isl_id *,
1220                                         dim->n_in + dim->n_out);
1221                 if (!ids)
1222                         goto error;
1223                 get_ids(dim, isl_dim_in, 0, dim->n_in, ids);
1224                 get_ids(dim, isl_dim_out, 0, dim->n_out, ids + dim->n_in);
1225         }
1226
1227         t = dim->n_in;
1228         dim->n_in = dim->n_out;
1229         dim->n_out = t;
1230
1231         if (dim->ids) {
1232                 dim = set_ids(dim, isl_dim_out, 0, dim->n_out, ids);
1233                 dim = set_ids(dim, isl_dim_in, 0, dim->n_in, ids + dim->n_out);
1234                 free(ids);
1235         }
1236
1237         return dim;
1238 error:
1239         free(ids);
1240         isl_space_free(dim);
1241         return NULL;
1242 }
1243
1244 __isl_give isl_space *isl_space_drop_dims(__isl_take isl_space *dim,
1245         enum isl_dim_type type, unsigned first, unsigned num)
1246 {
1247         int i;
1248
1249         if (!dim)
1250                 return NULL;
1251
1252         if (num == 0)
1253                 return isl_space_reset(dim, type);
1254
1255         if (!valid_dim_type(type))
1256                 isl_die(dim->ctx, isl_error_invalid,
1257                         "cannot drop dimensions of specified type", goto error);
1258
1259         isl_assert(dim->ctx, first + num <= n(dim, type), goto error);
1260         dim = isl_space_cow(dim);
1261         if (!dim)
1262                 goto error;
1263         if (dim->ids) {
1264                 dim = extend_ids(dim);
1265                 if (!dim)
1266                         goto error;
1267                 for (i = 0; i < num; ++i)
1268                         isl_id_free(get_id(dim, type, first + i));
1269                 for (i = first+num; i < n(dim, type); ++i)
1270                         set_id(dim, type, i - num, get_id(dim, type, i));
1271                 switch (type) {
1272                 case isl_dim_param:
1273                         get_ids(dim, isl_dim_in, 0, dim->n_in,
1274                                 dim->ids + offset(dim, isl_dim_in) - num);
1275                 case isl_dim_in:
1276                         get_ids(dim, isl_dim_out, 0, dim->n_out,
1277                                 dim->ids + offset(dim, isl_dim_out) - num);
1278                 default:
1279                         ;
1280                 }
1281                 dim->n_id -= num;
1282         }
1283         switch (type) {
1284         case isl_dim_param:     dim->nparam -= num; break;
1285         case isl_dim_in:        dim->n_in -= num; break;
1286         case isl_dim_out:       dim->n_out -= num; break;
1287         default:                ;
1288         }
1289         dim = isl_space_reset(dim, type);
1290         if (type == isl_dim_param) {
1291                 if (dim && dim->nested[0] &&
1292                     !(dim->nested[0] = isl_space_drop_dims(dim->nested[0],
1293                                                     isl_dim_param, first, num)))
1294                         goto error;
1295                 if (dim && dim->nested[1] &&
1296                     !(dim->nested[1] = isl_space_drop_dims(dim->nested[1],
1297                                                     isl_dim_param, first, num)))
1298                         goto error;
1299         }
1300         return dim;
1301 error:
1302         isl_space_free(dim);
1303         return NULL;
1304 }
1305
1306 __isl_give isl_space *isl_space_drop_inputs(__isl_take isl_space *dim,
1307                 unsigned first, unsigned n)
1308 {
1309         if (!dim)
1310                 return NULL;
1311         return isl_space_drop_dims(dim, isl_dim_in, first, n);
1312 }
1313
1314 __isl_give isl_space *isl_space_drop_outputs(__isl_take isl_space *dim,
1315                 unsigned first, unsigned n)
1316 {
1317         if (!dim)
1318                 return NULL;
1319         return isl_space_drop_dims(dim, isl_dim_out, first, n);
1320 }
1321
1322 __isl_give isl_space *isl_space_domain(__isl_take isl_space *dim)
1323 {
1324         if (!dim)
1325                 return NULL;
1326         dim = isl_space_drop_outputs(dim, 0, dim->n_out);
1327         dim = isl_space_reverse(dim);
1328         dim = mark_as_set(dim);
1329         return dim;
1330 }
1331
1332 __isl_give isl_space *isl_space_from_domain(__isl_take isl_space *dim)
1333 {
1334         if (!dim)
1335                 return NULL;
1336         if (!isl_space_is_set(dim))
1337                 isl_die(isl_space_get_ctx(dim), isl_error_invalid,
1338                         "not a set space", goto error);
1339         dim = isl_space_reverse(dim);
1340         dim = isl_space_reset(dim, isl_dim_out);
1341         return dim;
1342 error:
1343         isl_space_free(dim);
1344         return NULL;
1345 }
1346
1347 __isl_give isl_space *isl_space_range(__isl_take isl_space *dim)
1348 {
1349         if (!dim)
1350                 return NULL;
1351         dim = isl_space_drop_inputs(dim, 0, dim->n_in);
1352         dim = mark_as_set(dim);
1353         return dim;
1354 }
1355
1356 __isl_give isl_space *isl_space_from_range(__isl_take isl_space *dim)
1357 {
1358         if (!dim)
1359                 return NULL;
1360         if (!isl_space_is_set(dim))
1361                 isl_die(isl_space_get_ctx(dim), isl_error_invalid,
1362                         "not a set space", goto error);
1363         return isl_space_reset(dim, isl_dim_in);
1364 error:
1365         isl_space_free(dim);
1366         return NULL;
1367 }
1368
1369 __isl_give isl_space *isl_space_params(__isl_take isl_space *space)
1370 {
1371         if (isl_space_is_params(space))
1372                 return space;
1373         space = isl_space_drop_dims(space,
1374                             isl_dim_in, 0, isl_space_dim(space, isl_dim_in));
1375         space = isl_space_drop_dims(space,
1376                             isl_dim_out, 0, isl_space_dim(space, isl_dim_out));
1377         space = mark_as_params(space);
1378         return space;
1379 }
1380
1381 __isl_give isl_space *isl_space_set_from_params(__isl_take isl_space *space)
1382 {
1383         if (!space)
1384                 return NULL;
1385         if (!isl_space_is_params(space))
1386                 isl_die(isl_space_get_ctx(space), isl_error_invalid,
1387                         "not a parameter space", goto error);
1388         return isl_space_reset(space, isl_dim_set);
1389 error:
1390         isl_space_free(space);
1391         return NULL;
1392 }
1393
1394 __isl_give isl_space *isl_space_as_set_space(__isl_take isl_space *dim)
1395 {
1396         dim = isl_space_cow(dim);
1397         if (!dim)
1398                 return NULL;
1399
1400         dim->n_out += dim->n_in;
1401         dim->n_in = 0;
1402         dim = isl_space_reset(dim, isl_dim_in);
1403         dim = isl_space_reset(dim, isl_dim_out);
1404
1405         return dim;
1406 }
1407
1408 __isl_give isl_space *isl_space_underlying(__isl_take isl_space *dim,
1409         unsigned n_div)
1410 {
1411         int i;
1412
1413         if (!dim)
1414                 return NULL;
1415         if (n_div == 0 &&
1416             dim->nparam == 0 && dim->n_in == 0 && dim->n_id == 0)
1417                 return isl_space_reset(isl_space_reset(dim, isl_dim_in), isl_dim_out);
1418         dim = isl_space_cow(dim);
1419         if (!dim)
1420                 return NULL;
1421         dim->n_out += dim->nparam + dim->n_in + n_div;
1422         dim->nparam = 0;
1423         dim->n_in = 0;
1424
1425         for (i = 0; i < dim->n_id; ++i)
1426                 isl_id_free(get_id(dim, isl_dim_out, i));
1427         dim->n_id = 0;
1428         dim = isl_space_reset(dim, isl_dim_in);
1429         dim = isl_space_reset(dim, isl_dim_out);
1430
1431         return dim;
1432 }
1433
1434 int isl_space_is_equal(__isl_keep isl_space *dim1, __isl_keep isl_space *dim2)
1435 {
1436         if (!dim1 || !dim2)
1437                 return -1;
1438         if (dim1 == dim2)
1439                 return 1;
1440         return match(dim1, isl_dim_param, dim2, isl_dim_param) &&
1441                isl_space_tuple_match(dim1, isl_dim_in, dim2, isl_dim_in) &&
1442                isl_space_tuple_match(dim1, isl_dim_out, dim2, isl_dim_out);
1443 }
1444
1445 /* Is space1 equal to the domain of space2?
1446  */
1447 int isl_space_is_domain(__isl_keep isl_space *space1,
1448         __isl_keep isl_space *space2)
1449 {
1450         if (!space1 || !space2)
1451                 return -1;
1452         if (!isl_space_is_set(space1))
1453                 return 0;
1454         return match(space1, isl_dim_param, space2, isl_dim_param) &&
1455                isl_space_tuple_match(space1, isl_dim_set, space2, isl_dim_in);
1456 }
1457
1458 int isl_space_compatible(__isl_keep isl_space *dim1,
1459         __isl_keep isl_space *dim2)
1460 {
1461         return dim1->nparam == dim2->nparam &&
1462                dim1->n_in + dim1->n_out == dim2->n_in + dim2->n_out;
1463 }
1464
1465 static uint32_t isl_hash_dim(uint32_t hash, __isl_keep isl_space *dim)
1466 {
1467         int i;
1468         isl_id *id;
1469
1470         if (!dim)
1471                 return hash;
1472
1473         hash = isl_hash_builtin(hash, dim->nparam);
1474         hash = isl_hash_builtin(hash, dim->n_in);
1475         hash = isl_hash_builtin(hash, dim->n_out);
1476
1477         for (i = 0; i < dim->nparam; ++i) {
1478                 id = get_id(dim, isl_dim_param, i);
1479                 hash = isl_hash_id(hash, id);
1480         }
1481
1482         id = tuple_id(dim, isl_dim_in);
1483         hash = isl_hash_id(hash, id);
1484         id = tuple_id(dim, isl_dim_out);
1485         hash = isl_hash_id(hash, id);
1486
1487         hash = isl_hash_dim(hash, dim->nested[0]);
1488         hash = isl_hash_dim(hash, dim->nested[1]);
1489
1490         return hash;
1491 }
1492
1493 uint32_t isl_space_get_hash(__isl_keep isl_space *dim)
1494 {
1495         uint32_t hash;
1496
1497         if (!dim)
1498                 return 0;
1499
1500         hash = isl_hash_init();
1501         hash = isl_hash_dim(hash, dim);
1502
1503         return hash;
1504 }
1505
1506 int isl_space_is_wrapping(__isl_keep isl_space *dim)
1507 {
1508         if (!dim)
1509                 return -1;
1510
1511         if (!isl_space_is_set(dim))
1512                 return 0;
1513
1514         return dim->nested[1] != NULL;
1515 }
1516
1517 __isl_give isl_space *isl_space_wrap(__isl_take isl_space *dim)
1518 {
1519         isl_space *wrap;
1520
1521         if (!dim)
1522                 return NULL;
1523
1524         wrap = isl_space_set_alloc(dim->ctx,
1525                                     dim->nparam, dim->n_in + dim->n_out);
1526
1527         wrap = copy_ids(wrap, isl_dim_param, 0, dim, isl_dim_param);
1528         wrap = copy_ids(wrap, isl_dim_set, 0, dim, isl_dim_in);
1529         wrap = copy_ids(wrap, isl_dim_set, dim->n_in, dim, isl_dim_out);
1530
1531         if (!wrap)
1532                 goto error;
1533
1534         wrap->nested[1] = dim;
1535
1536         return wrap;
1537 error:
1538         isl_space_free(dim);
1539         return NULL;
1540 }
1541
1542 __isl_give isl_space *isl_space_unwrap(__isl_take isl_space *dim)
1543 {
1544         isl_space *unwrap;
1545
1546         if (!dim)
1547                 return NULL;
1548
1549         if (!isl_space_is_wrapping(dim))
1550                 isl_die(dim->ctx, isl_error_invalid, "not a wrapping dim",
1551                         goto error);
1552
1553         unwrap = isl_space_copy(dim->nested[1]);
1554         isl_space_free(dim);
1555
1556         return unwrap;
1557 error:
1558         isl_space_free(dim);
1559         return NULL;
1560 }
1561
1562 int isl_space_is_named_or_nested(__isl_keep isl_space *dim, enum isl_dim_type type)
1563 {
1564         if (type != isl_dim_in && type != isl_dim_out)
1565                 return 0;
1566         if (!dim)
1567                 return -1;
1568         if (dim->tuple_id[type - isl_dim_in])
1569                 return 1;
1570         if (dim->nested[type - isl_dim_in])
1571                 return 1;
1572         return 0;
1573 }
1574
1575 int isl_space_may_be_set(__isl_keep isl_space *dim)
1576 {
1577         if (!dim)
1578                 return -1;
1579         if (isl_space_is_set(dim))
1580                 return 1;
1581         if (isl_space_dim(dim, isl_dim_in) != 0)
1582                 return 0;
1583         if (isl_space_is_named_or_nested(dim, isl_dim_in))
1584                 return 0;
1585         return 1;
1586 }
1587
1588 __isl_give isl_space *isl_space_reset(__isl_take isl_space *dim,
1589         enum isl_dim_type type)
1590 {
1591         if (!isl_space_is_named_or_nested(dim, type))
1592                 return dim;
1593
1594         dim = isl_space_cow(dim);
1595         if (!dim)
1596                 return NULL;
1597
1598         isl_id_free(dim->tuple_id[type - isl_dim_in]);
1599         dim->tuple_id[type - isl_dim_in] = NULL;
1600         isl_space_free(dim->nested[type - isl_dim_in]);
1601         dim->nested[type - isl_dim_in] = NULL;
1602
1603         return dim;
1604 }
1605
1606 __isl_give isl_space *isl_space_flatten(__isl_take isl_space *dim)
1607 {
1608         if (!dim)
1609                 return NULL;
1610         if (!dim->nested[0] && !dim->nested[1])
1611                 return dim;
1612
1613         if (dim->nested[0])
1614                 dim = isl_space_reset(dim, isl_dim_in);
1615         if (dim && dim->nested[1])
1616                 dim = isl_space_reset(dim, isl_dim_out);
1617
1618         return dim;
1619 }
1620
1621 __isl_give isl_space *isl_space_flatten_domain(__isl_take isl_space *dim)
1622 {
1623         if (!dim)
1624                 return NULL;
1625         if (!dim->nested[0])
1626                 return dim;
1627
1628         return isl_space_reset(dim, isl_dim_in);
1629 }
1630
1631 __isl_give isl_space *isl_space_flatten_range(__isl_take isl_space *dim)
1632 {
1633         if (!dim)
1634                 return NULL;
1635         if (!dim->nested[1])
1636                 return dim;
1637
1638         return isl_space_reset(dim, isl_dim_out);
1639 }
1640
1641 /* Replace the dimensions of the given type of dst by those of src.
1642  */
1643 __isl_give isl_space *isl_space_replace(__isl_take isl_space *dst,
1644         enum isl_dim_type type, __isl_keep isl_space *src)
1645 {
1646         dst = isl_space_cow(dst);
1647
1648         if (!dst || !src)
1649                 goto error;
1650
1651         dst = isl_space_drop_dims(dst, type, 0, isl_space_dim(dst, type));
1652         dst = isl_space_add_dims(dst, type, isl_space_dim(src, type));
1653         dst = copy_ids(dst, type, 0, src, type);
1654
1655         if (dst && type == isl_dim_param) {
1656                 int i;
1657                 for (i = 0; i <= 1; ++i) {
1658                         if (!dst->nested[i])
1659                                 continue;
1660                         dst->nested[i] = isl_space_replace(dst->nested[i],
1661                                                          type, src);
1662                         if (!dst->nested[i])
1663                                 goto error;
1664                 }
1665         }
1666
1667         return dst;
1668 error:
1669         isl_space_free(dst);
1670         return NULL;
1671 }
1672
1673 /* Given a dimension specification "dim" of a set, create a dimension
1674  * specification for the lift of the set.  In particular, the result
1675  * is of the form [dim -> local[..]], with n_local variables in the
1676  * range of the wrapped map.
1677  */
1678 __isl_give isl_space *isl_space_lift(__isl_take isl_space *dim, unsigned n_local)
1679 {
1680         isl_space *local_dim;
1681
1682         if (!dim)
1683                 return NULL;
1684
1685         local_dim = isl_space_dup(dim);
1686         local_dim = isl_space_drop_dims(local_dim, isl_dim_set, 0, dim->n_out);
1687         local_dim = isl_space_add_dims(local_dim, isl_dim_set, n_local);
1688         local_dim = isl_space_set_tuple_name(local_dim, isl_dim_set, "local");
1689         dim = isl_space_join(isl_space_from_domain(dim),
1690                             isl_space_from_range(local_dim));
1691         dim = isl_space_wrap(dim);
1692         dim = isl_space_set_tuple_name(dim, isl_dim_set, "lifted");
1693
1694         return dim;
1695 }
1696
1697 int isl_space_can_zip(__isl_keep isl_space *dim)
1698 {
1699         if (!dim)
1700                 return -1;
1701
1702         return dim->nested[0] && dim->nested[1];
1703 }
1704
1705 __isl_give isl_space *isl_space_zip(__isl_take isl_space *dim)
1706 {
1707         isl_space *dom, *ran;
1708         isl_space *dom_dom, *dom_ran, *ran_dom, *ran_ran;
1709
1710         if (!isl_space_can_zip(dim))
1711                 isl_die(dim->ctx, isl_error_invalid, "dim cannot be zipped",
1712                         goto error);
1713
1714         if (!dim)
1715                 return NULL;
1716         dom = isl_space_unwrap(isl_space_domain(isl_space_copy(dim)));
1717         ran = isl_space_unwrap(isl_space_range(dim));
1718         dom_dom = isl_space_domain(isl_space_copy(dom));
1719         dom_ran = isl_space_range(dom);
1720         ran_dom = isl_space_domain(isl_space_copy(ran));
1721         ran_ran = isl_space_range(ran);
1722         dom = isl_space_join(isl_space_from_domain(dom_dom),
1723                            isl_space_from_range(ran_dom));
1724         ran = isl_space_join(isl_space_from_domain(dom_ran),
1725                            isl_space_from_range(ran_ran));
1726         return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)),
1727                             isl_space_from_range(isl_space_wrap(ran)));
1728 error:
1729         isl_space_free(dim);
1730         return NULL;
1731 }
1732
1733 /* Can we apply isl_space_curry to "space"?
1734  * That is, does it have a nested relation in its domain?
1735  */
1736 int isl_space_can_curry(__isl_keep isl_space *space)
1737 {
1738         if (!space)
1739                 return -1;
1740
1741         return !!space->nested[0];
1742 }
1743
1744 /* Given a space (A -> B) -> C, return the corresponding space
1745  * A -> (B -> C).
1746  */
1747 __isl_give isl_space *isl_space_curry(__isl_take isl_space *space)
1748 {
1749         isl_space *dom, *ran;
1750         isl_space *dom_dom, *dom_ran;
1751
1752         if (!space)
1753                 return NULL;
1754
1755         if (!isl_space_can_curry(space))
1756                 isl_die(space->ctx, isl_error_invalid,
1757                         "space cannot be curried", goto error);
1758
1759         dom = isl_space_unwrap(isl_space_domain(isl_space_copy(space)));
1760         ran = isl_space_range(space);
1761         dom_dom = isl_space_domain(isl_space_copy(dom));
1762         dom_ran = isl_space_range(dom);
1763         ran = isl_space_join(isl_space_from_domain(dom_ran),
1764                            isl_space_from_range(ran));
1765         return isl_space_join(isl_space_from_domain(dom_dom),
1766                             isl_space_from_range(isl_space_wrap(ran)));
1767 error:
1768         isl_space_free(space);
1769         return NULL;
1770 }
1771
1772 int isl_space_has_named_params(__isl_keep isl_space *dim)
1773 {
1774         int i;
1775         unsigned off;
1776
1777         if (!dim)
1778                 return -1;
1779         if (dim->nparam == 0)
1780                 return 1;
1781         off = isl_space_offset(dim, isl_dim_param);
1782         if (off + dim->nparam > dim->n_id)
1783                 return 0;
1784         for (i = 0; i < dim->nparam; ++i)
1785                 if (!dim->ids[off + i])
1786                         return 0;
1787         return 1;
1788 }
1789
1790 /* Align the initial parameters of dim1 to match the order in dim2.
1791  */
1792 __isl_give isl_space *isl_space_align_params(__isl_take isl_space *dim1,
1793         __isl_take isl_space *dim2)
1794 {
1795         isl_reordering *exp;
1796
1797         if (!isl_space_has_named_params(dim1) || !isl_space_has_named_params(dim2))
1798                 isl_die(isl_space_get_ctx(dim1), isl_error_invalid,
1799                         "parameter alignment requires named parameters",
1800                         goto error);
1801
1802         dim2 = isl_space_params(dim2);
1803         exp = isl_parameter_alignment_reordering(dim1, dim2);
1804         exp = isl_reordering_extend_space(exp, dim1);
1805         isl_space_free(dim2);
1806         if (!exp)
1807                 return NULL;
1808         dim1 = isl_space_copy(exp->dim);
1809         isl_reordering_free(exp);
1810         return dim1;
1811 error:
1812         isl_space_free(dim1);
1813         isl_space_free(dim2);
1814         return NULL;
1815 }
1816
1817 /* Given the space of set (domain), construct a space for a map
1818  * with as domain the given space and as range the range of "model".
1819  */
1820 __isl_give isl_space *isl_space_extend_domain_with_range(
1821         __isl_take isl_space *domain, __isl_take isl_space *model)
1822 {
1823         isl_space *space;
1824
1825         space = isl_space_from_domain(domain);
1826         space = isl_space_add_dims(space, isl_dim_out,
1827                                     isl_space_dim(model, isl_dim_out));
1828         if (isl_space_has_tuple_id(model, isl_dim_out))
1829                 space = isl_space_set_tuple_id(space, isl_dim_out,
1830                                 isl_space_get_tuple_id(model, isl_dim_out));
1831         isl_space_free(model);
1832         return space;
1833 }