isl_space_set_dim_id: also set id of parameter in nested spaces
[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 int isl_space_has_tuple_id(__isl_keep isl_space *dim, enum isl_dim_type type)
364 {
365         if (!dim)
366                 return -1;
367         if (isl_space_is_params(dim))
368                 isl_die(dim->ctx, isl_error_invalid,
369                         "parameter spaces don't have tuple ids", return -1);
370         if (isl_space_is_set(dim) && type != isl_dim_set)
371                 isl_die(dim->ctx, isl_error_invalid,
372                         "set spaces can only have a set id", return -1);
373         if (type != isl_dim_in && type != isl_dim_out)
374                 isl_die(dim->ctx, isl_error_invalid,
375                         "only input, output and set tuples can have ids",
376                         return -1);
377         return dim->tuple_id[type - isl_dim_in] != NULL;
378 }
379
380 __isl_give isl_id *isl_space_get_tuple_id(__isl_keep isl_space *dim,
381         enum isl_dim_type type)
382 {
383         int has_id;
384
385         if (!dim)
386                 return NULL;
387         has_id = isl_space_has_tuple_id(dim, type);
388         if (has_id < 0)
389                 return NULL;
390         if (!has_id)
391                 isl_die(dim->ctx, isl_error_invalid,
392                         "tuple has no id", return NULL);
393         return isl_id_copy(dim->tuple_id[type - isl_dim_in]);
394 }
395
396 __isl_give isl_space *isl_space_set_tuple_id(__isl_take isl_space *dim,
397         enum isl_dim_type type, __isl_take isl_id *id)
398 {
399         dim = isl_space_cow(dim);
400         if (!dim || !id)
401                 goto error;
402         if (type != isl_dim_in && type != isl_dim_out)
403                 isl_die(dim->ctx, isl_error_invalid,
404                         "only input, output and set tuples can have names",
405                         goto error);
406
407         isl_id_free(dim->tuple_id[type - isl_dim_in]);
408         dim->tuple_id[type - isl_dim_in] = id;
409
410         return dim;
411 error:
412         isl_id_free(id);
413         isl_space_free(dim);
414         return NULL;
415 }
416
417 __isl_give isl_space *isl_space_reset_tuple_id(__isl_take isl_space *dim,
418         enum isl_dim_type type)
419 {
420         dim = isl_space_cow(dim);
421         if (!dim)
422                 return NULL;
423         if (type != isl_dim_in && type != isl_dim_out)
424                 isl_die(dim->ctx, isl_error_invalid,
425                         "only input, output and set tuples can have names",
426                         goto error);
427
428         isl_id_free(dim->tuple_id[type - isl_dim_in]);
429         dim->tuple_id[type - isl_dim_in] = NULL;
430
431         return dim;
432 error:
433         isl_space_free(dim);
434         return NULL;
435 }
436
437 /* Set the id of the given dimension of "space" to "id".
438  * If the dimension already has an id, then it is replaced.
439  * If the dimension is a parameter, then we need to change it
440  * in the nested spaces (if any) as well.
441  */
442 __isl_give isl_space *isl_space_set_dim_id(__isl_take isl_space *space,
443         enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
444 {
445         space = isl_space_cow(space);
446         if (!space || !id)
447                 goto error;
448
449         if (type == isl_dim_param) {
450                 int i;
451
452                 for (i = 0; i < 2; ++i) {
453                         if (!space->nested[i])
454                                 continue;
455                         space->nested[i] =
456                                 isl_space_set_dim_id(space->nested[i],
457                                                 type, pos, isl_id_copy(id));
458                         if (!space->nested[i])
459                                 goto error;
460                 }
461         }
462
463         isl_id_free(get_id(space, type, pos));
464         return set_id(space, type, pos, id);
465 error:
466         isl_id_free(id);
467         isl_space_free(space);
468         return NULL;
469 }
470
471 int isl_space_has_dim_id(__isl_keep isl_space *dim,
472         enum isl_dim_type type, unsigned pos)
473 {
474         if (!dim)
475                 return -1;
476         return get_id(dim, type, pos) != NULL;
477 }
478
479 __isl_give isl_id *isl_space_get_dim_id(__isl_keep isl_space *dim,
480         enum isl_dim_type type, unsigned pos)
481 {
482         if (!dim)
483                 return NULL;
484         if (!get_id(dim, type, pos))
485                 isl_die(dim->ctx, isl_error_invalid,
486                         "dim has no id", return NULL);
487         return isl_id_copy(get_id(dim, type, pos));
488 }
489
490 __isl_give isl_space *isl_space_set_tuple_name(__isl_take isl_space *dim,
491         enum isl_dim_type type, const char *s)
492 {
493         isl_id *id;
494
495         if (!dim)
496                 return NULL;
497
498         if (!s)
499                 return isl_space_reset_tuple_id(dim, type);
500
501         if (!name_ok(dim->ctx, s))
502                 goto error;
503
504         id = isl_id_alloc(dim->ctx, s, NULL);
505         return isl_space_set_tuple_id(dim, type, id);
506 error:
507         isl_space_free(dim);
508         return NULL;
509 }
510
511 const char *isl_space_get_tuple_name(__isl_keep isl_space *dim,
512          enum isl_dim_type type)
513 {
514         isl_id *id;
515         if (!dim)
516                 return NULL;
517         if (type != isl_dim_in && type != isl_dim_out)
518                 return NULL;
519         id = dim->tuple_id[type - isl_dim_in];
520         return id ? id->name : NULL;
521 }
522
523 __isl_give isl_space *isl_space_set_dim_name(__isl_take isl_space *dim,
524                                  enum isl_dim_type type, unsigned pos,
525                                  const char *s)
526 {
527         isl_id *id;
528
529         if (!dim)
530                 return NULL;
531         if (!name_ok(dim->ctx, s))
532                 goto error;
533         id = isl_id_alloc(dim->ctx, s, NULL);
534         return isl_space_set_dim_id(dim, type, pos, id);
535 error:
536         isl_space_free(dim);
537         return NULL;
538 }
539
540 __isl_keep const char *isl_space_get_dim_name(__isl_keep isl_space *dim,
541                                  enum isl_dim_type type, unsigned pos)
542 {
543         isl_id *id = get_id(dim, type, pos);
544         return id ? id->name : NULL;
545 }
546
547 int isl_space_find_dim_by_id(__isl_keep isl_space *dim, enum isl_dim_type type,
548         __isl_keep isl_id *id)
549 {
550         int i;
551         int offset;
552         int n;
553
554         if (!dim || !id)
555                 return -1;
556
557         offset = isl_space_offset(dim, type);
558         n = isl_space_dim(dim, type);
559         for (i = 0; i < n && offset + i < dim->n_id; ++i)
560                 if (dim->ids[offset + i] == id)
561                         return i;
562
563         return -1;
564 }
565
566 int isl_space_find_dim_by_name(__isl_keep isl_space *space,
567         enum isl_dim_type type, const char *name)
568 {
569         int i;
570         int offset;
571         int n;
572
573         if (!space || !name)
574                 return -1;
575
576         offset = isl_space_offset(space, type);
577         n = isl_space_dim(space, type);
578         for (i = 0; i < n && offset + i < space->n_id; ++i)
579                 if (space->ids[offset + i]->name &&
580                     !strcmp(space->ids[offset + i]->name, name))
581                         return i;
582
583         return -1;
584 }
585
586 static __isl_keep isl_id *tuple_id(__isl_keep isl_space *dim,
587         enum isl_dim_type type)
588 {
589         if (!dim)
590                 return NULL;
591         if (type == isl_dim_in)
592                 return dim->tuple_id[0];
593         if (type == isl_dim_out)
594                 return dim->tuple_id[1];
595         return NULL;
596 }
597
598 static __isl_keep isl_space *nested(__isl_keep isl_space *dim,
599         enum isl_dim_type type)
600 {
601         if (!dim)
602                 return NULL;
603         if (type == isl_dim_in)
604                 return dim->nested[0];
605         if (type == isl_dim_out)
606                 return dim->nested[1];
607         return NULL;
608 }
609
610 int isl_space_tuple_match(__isl_keep isl_space *dim1, enum isl_dim_type dim1_type,
611                         __isl_keep isl_space *dim2, enum isl_dim_type dim2_type)
612 {
613         isl_id *id1, *id2;
614         isl_space *nested1, *nested2;
615
616         if (!dim1 || !dim2)
617                 return -1;
618
619         if (dim1 == dim2 && dim1_type == dim2_type)
620                 return 1;
621
622         if (n(dim1, dim1_type) != n(dim2, dim2_type))
623                 return 0;
624         id1 = tuple_id(dim1, dim1_type);
625         id2 = tuple_id(dim2, dim2_type);
626         if (!id1 ^ !id2)
627                 return 0;
628         if (id1 && id1 != id2)
629                 return 0;
630         nested1 = nested(dim1, dim1_type);
631         nested2 = nested(dim2, dim2_type);
632         if (!nested1 ^ !nested2)
633                 return 0;
634         if (nested1 && !isl_space_is_equal(nested1, nested2))
635                 return 0;
636         return 1;
637 }
638
639 static int match(__isl_keep isl_space *dim1, enum isl_dim_type dim1_type,
640         __isl_keep isl_space *dim2, enum isl_dim_type dim2_type)
641 {
642         int i;
643
644         if (dim1 == dim2 && dim1_type == dim2_type)
645                 return 1;
646
647         if (!isl_space_tuple_match(dim1, dim1_type, dim2, dim2_type))
648                 return 0;
649
650         if (!dim1->ids && !dim2->ids)
651                 return 1;
652
653         for (i = 0; i < n(dim1, dim1_type); ++i) {
654                 if (get_id(dim1, dim1_type, i) != get_id(dim2, dim2_type, i))
655                         return 0;
656         }
657         return 1;
658 }
659
660 int isl_space_match(__isl_keep isl_space *dim1, enum isl_dim_type dim1_type,
661         __isl_keep isl_space *dim2, enum isl_dim_type dim2_type)
662 {
663         if (!dim1 || !dim2)
664                 return -1;
665
666         return match(dim1, dim1_type, dim2, dim2_type);
667 }
668
669 static void get_ids(__isl_keep isl_space *dim, enum isl_dim_type type,
670         unsigned first, unsigned n, __isl_keep isl_id **ids)
671 {
672         int i;
673
674         for (i = 0; i < n ; ++i)
675                 ids[i] = get_id(dim, type, first + i);
676 }
677
678 __isl_give isl_space *isl_space_extend(__isl_take isl_space *dim,
679                         unsigned nparam, unsigned n_in, unsigned n_out)
680 {
681         isl_id **ids = NULL;
682
683         if (!dim)
684                 return NULL;
685         if (dim->nparam == nparam && dim->n_in == n_in && dim->n_out == n_out)
686                 return dim;
687
688         isl_assert(dim->ctx, dim->nparam <= nparam, goto error);
689         isl_assert(dim->ctx, dim->n_in <= n_in, goto error);
690         isl_assert(dim->ctx, dim->n_out <= n_out, goto error);
691
692         dim = isl_space_cow(dim);
693
694         if (dim->ids) {
695                 ids = isl_calloc_array(dim->ctx, isl_id *,
696                                          nparam + n_in + n_out);
697                 if (!ids)
698                         goto error;
699                 get_ids(dim, isl_dim_param, 0, dim->nparam, ids);
700                 get_ids(dim, isl_dim_in, 0, dim->n_in, ids + nparam);
701                 get_ids(dim, isl_dim_out, 0, dim->n_out, ids + nparam + n_in);
702                 free(dim->ids);
703                 dim->ids = ids;
704                 dim->n_id = nparam + n_in + n_out;
705         }
706         dim->nparam = nparam;
707         dim->n_in = n_in;
708         dim->n_out = n_out;
709
710         return dim;
711 error:
712         free(ids);
713         isl_space_free(dim);
714         return NULL;
715 }
716
717 __isl_give isl_space *isl_space_add_dims(__isl_take isl_space *dim,
718         enum isl_dim_type type, unsigned n)
719 {
720         if (!dim)
721                 return NULL;
722         dim = isl_space_reset(dim, type);
723         switch (type) {
724         case isl_dim_param:
725                 dim = isl_space_extend(dim,
726                                         dim->nparam + n, dim->n_in, dim->n_out);
727                 if (dim && dim->nested[0] &&
728                     !(dim->nested[0] = isl_space_add_dims(dim->nested[0],
729                                                     isl_dim_param, n)))
730                         goto error;
731                 if (dim && dim->nested[1] &&
732                     !(dim->nested[1] = isl_space_add_dims(dim->nested[1],
733                                                     isl_dim_param, n)))
734                         goto error;
735                 return dim;
736         case isl_dim_in:
737                 return isl_space_extend(dim,
738                                         dim->nparam, dim->n_in + n, dim->n_out);
739         case isl_dim_out:
740                 return isl_space_extend(dim,
741                                         dim->nparam, dim->n_in, dim->n_out + n);
742         default:
743                 isl_die(dim->ctx, isl_error_invalid,
744                         "cannot add dimensions of specified type", goto error);
745         }
746 error:
747         isl_space_free(dim);
748         return NULL;
749 }
750
751 static int valid_dim_type(enum isl_dim_type type)
752 {
753         switch (type) {
754         case isl_dim_param:
755         case isl_dim_in:
756         case isl_dim_out:
757                 return 1;
758         default:
759                 return 0;
760         }
761 }
762
763 __isl_give isl_space *isl_space_insert_dims(__isl_take isl_space *dim,
764         enum isl_dim_type type, unsigned pos, unsigned n)
765 {
766         isl_id **ids = NULL;
767
768         if (!dim)
769                 return NULL;
770         if (n == 0)
771                 return isl_space_reset(dim, type);
772
773         if (!valid_dim_type(type))
774                 isl_die(dim->ctx, isl_error_invalid,
775                         "cannot insert dimensions of specified type",
776                         goto error);
777
778         isl_assert(dim->ctx, pos <= isl_space_dim(dim, type), goto error);
779
780         dim = isl_space_cow(dim);
781         if (!dim)
782                 return NULL;
783
784         if (dim->ids) {
785                 enum isl_dim_type t;
786                 int off;
787                 int s[3];
788                 int *size = s - isl_dim_param;
789                 ids = isl_calloc_array(dim->ctx, isl_id *,
790                                      dim->nparam + dim->n_in + dim->n_out + n);
791                 if (!ids)
792                         goto error;
793                 off = 0;
794                 size[isl_dim_param] = dim->nparam;
795                 size[isl_dim_in] = dim->n_in;
796                 size[isl_dim_out] = dim->n_out;
797                 for (t = isl_dim_param; t <= isl_dim_out; ++t) {
798                         if (t != type) {
799                                 get_ids(dim, t, 0, size[t], ids + off);
800                                 off += size[t];
801                         } else {
802                                 get_ids(dim, t, 0, pos, ids + off);
803                                 off += pos + n;
804                                 get_ids(dim, t, pos, size[t] - pos, ids + off);
805                                 off += size[t] - pos;
806                         }
807                 }
808                 free(dim->ids);
809                 dim->ids = ids;
810                 dim->n_id = dim->nparam + dim->n_in + dim->n_out + n;
811         }
812         switch (type) {
813         case isl_dim_param:     dim->nparam += n; break;
814         case isl_dim_in:        dim->n_in += n; break;
815         case isl_dim_out:       dim->n_out += n; break;
816         default:                ;
817         }
818         dim = isl_space_reset(dim, type);
819
820         return dim;
821 error:
822         isl_space_free(dim);
823         return NULL;
824 }
825
826 __isl_give isl_space *isl_space_move_dims(__isl_take isl_space *dim,
827         enum isl_dim_type dst_type, unsigned dst_pos,
828         enum isl_dim_type src_type, unsigned src_pos, unsigned n)
829 {
830         int i;
831
832         if (!dim)
833                 return NULL;
834         if (n == 0)
835                 return dim;
836
837         isl_assert(dim->ctx, src_pos + n <= isl_space_dim(dim, src_type),
838                 goto error);
839
840         if (dst_type == src_type && dst_pos == src_pos)
841                 return dim;
842
843         isl_assert(dim->ctx, dst_type != src_type, goto error);
844
845         dim = isl_space_reset(dim, src_type);
846         dim = isl_space_reset(dim, dst_type);
847
848         dim = isl_space_cow(dim);
849         if (!dim)
850                 return NULL;
851
852         if (dim->ids) {
853                 isl_id **ids;
854                 enum isl_dim_type t;
855                 int off;
856                 int s[3];
857                 int *size = s - isl_dim_param;
858                 ids = isl_calloc_array(dim->ctx, isl_id *,
859                                          dim->nparam + dim->n_in + dim->n_out);
860                 if (!ids)
861                         goto error;
862                 off = 0;
863                 size[isl_dim_param] = dim->nparam;
864                 size[isl_dim_in] = dim->n_in;
865                 size[isl_dim_out] = dim->n_out;
866                 for (t = isl_dim_param; t <= isl_dim_out; ++t) {
867                         if (t == dst_type) {
868                                 get_ids(dim, t, 0, dst_pos, ids + off);
869                                 off += dst_pos;
870                                 get_ids(dim, src_type, src_pos, n, ids + off);
871                                 off += n;
872                                 get_ids(dim, t, dst_pos, size[t] - dst_pos,
873                                                 ids + off);
874                                 off += size[t] - dst_pos;
875                         } else if (t == src_type) {
876                                 get_ids(dim, t, 0, src_pos, ids + off);
877                                 off += src_pos;
878                                 get_ids(dim, t, src_pos + n,
879                                             size[t] - src_pos - n, ids + off);
880                                 off += size[t] - src_pos - n;
881                         } else {
882                                 get_ids(dim, t, 0, size[t], ids + off);
883                                 off += size[t];
884                         }
885                 }
886                 free(dim->ids);
887                 dim->ids = ids;
888                 dim->n_id = dim->nparam + dim->n_in + dim->n_out;
889         }
890
891         switch (dst_type) {
892         case isl_dim_param:     dim->nparam += n; break;
893         case isl_dim_in:        dim->n_in += n; break;
894         case isl_dim_out:       dim->n_out += n; break;
895         default:                ;
896         }
897
898         switch (src_type) {
899         case isl_dim_param:     dim->nparam -= n; break;
900         case isl_dim_in:        dim->n_in -= n; break;
901         case isl_dim_out:       dim->n_out -= n; break;
902         default:                ;
903         }
904
905         if (dst_type != isl_dim_param && src_type != isl_dim_param)
906                 return dim;
907
908         for (i = 0; i < 2; ++i) {
909                 if (!dim->nested[i])
910                         continue;
911                 dim->nested[i] = isl_space_replace(dim->nested[i],
912                                                  isl_dim_param, dim);
913                 if (!dim->nested[i])
914                         goto error;
915         }
916
917         return dim;
918 error:
919         isl_space_free(dim);
920         return NULL;
921 }
922
923 __isl_give isl_space *isl_space_join(__isl_take isl_space *left,
924         __isl_take isl_space *right)
925 {
926         isl_space *dim;
927
928         if (!left || !right)
929                 goto error;
930
931         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
932                         goto error);
933         isl_assert(left->ctx,
934                 isl_space_tuple_match(left, isl_dim_out, right, isl_dim_in),
935                 goto error);
936
937         dim = isl_space_alloc(left->ctx, left->nparam, left->n_in, right->n_out);
938         if (!dim)
939                 goto error;
940
941         dim = copy_ids(dim, isl_dim_param, 0, left, isl_dim_param);
942         dim = copy_ids(dim, isl_dim_in, 0, left, isl_dim_in);
943         dim = copy_ids(dim, isl_dim_out, 0, right, isl_dim_out);
944
945         if (dim && left->tuple_id[0] &&
946             !(dim->tuple_id[0] = isl_id_copy(left->tuple_id[0])))
947                 goto error;
948         if (dim && right->tuple_id[1] &&
949             !(dim->tuple_id[1] = isl_id_copy(right->tuple_id[1])))
950                 goto error;
951         if (dim && left->nested[0] &&
952             !(dim->nested[0] = isl_space_copy(left->nested[0])))
953                 goto error;
954         if (dim && right->nested[1] &&
955             !(dim->nested[1] = isl_space_copy(right->nested[1])))
956                 goto error;
957
958         isl_space_free(left);
959         isl_space_free(right);
960
961         return dim;
962 error:
963         isl_space_free(left);
964         isl_space_free(right);
965         return NULL;
966 }
967
968 __isl_give isl_space *isl_space_product(__isl_take isl_space *left,
969         __isl_take isl_space *right)
970 {
971         isl_space *dom1, *dom2, *nest1, *nest2;
972
973         if (!left || !right)
974                 goto error;
975
976         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
977                         goto error);
978
979         dom1 = isl_space_domain(isl_space_copy(left));
980         dom2 = isl_space_domain(isl_space_copy(right));
981         nest1 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
982
983         dom1 = isl_space_range(left);
984         dom2 = isl_space_range(right);
985         nest2 = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
986
987         return isl_space_join(isl_space_reverse(nest1), nest2);
988 error:
989         isl_space_free(left);
990         isl_space_free(right);
991         return NULL;
992 }
993
994 /* Given two spaces { A -> C } and { B -> C }, construct the space
995  * { [A -> B] -> C }
996  */
997 __isl_give isl_space *isl_space_domain_product(__isl_take isl_space *left,
998         __isl_take isl_space *right)
999 {
1000         isl_space *ran, *dom1, *dom2, *nest;
1001
1002         if (!left || !right)
1003                 goto error;
1004
1005         if (!match(left, isl_dim_param, right, isl_dim_param))
1006                 isl_die(left->ctx, isl_error_invalid,
1007                         "parameters need to match", goto error);
1008         if (!isl_space_tuple_match(left, isl_dim_out, right, isl_dim_out))
1009                 isl_die(left->ctx, isl_error_invalid,
1010                         "ranges need to match", goto error);
1011
1012         ran = isl_space_range(isl_space_copy(left));
1013
1014         dom1 = isl_space_domain(left);
1015         dom2 = isl_space_domain(right);
1016         nest = isl_space_wrap(isl_space_join(isl_space_reverse(dom1), dom2));
1017
1018         return isl_space_join(isl_space_reverse(nest), ran);
1019 error:
1020         isl_space_free(left);
1021         isl_space_free(right);
1022         return NULL;
1023 }
1024
1025 __isl_give isl_space *isl_space_range_product(__isl_take isl_space *left,
1026         __isl_take isl_space *right)
1027 {
1028         isl_space *dom, *ran1, *ran2, *nest;
1029
1030         if (!left || !right)
1031                 goto error;
1032
1033         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
1034                         goto error);
1035         if (!isl_space_tuple_match(left, isl_dim_in, right, isl_dim_in))
1036                 isl_die(left->ctx, isl_error_invalid,
1037                         "domains need to match", goto error);
1038
1039         dom = isl_space_domain(isl_space_copy(left));
1040
1041         ran1 = isl_space_range(left);
1042         ran2 = isl_space_range(right);
1043         nest = isl_space_wrap(isl_space_join(isl_space_reverse(ran1), ran2));
1044
1045         return isl_space_join(isl_space_reverse(dom), nest);
1046 error:
1047         isl_space_free(left);
1048         isl_space_free(right);
1049         return NULL;
1050 }
1051
1052 __isl_give isl_space *isl_space_map_from_set(__isl_take isl_space *dim)
1053 {
1054         isl_ctx *ctx;
1055         isl_id **ids = NULL;
1056
1057         if (!dim)
1058                 return NULL;
1059         ctx = isl_space_get_ctx(dim);
1060         if (!isl_space_is_set(dim))
1061                 isl_die(ctx, isl_error_invalid, "not a set space", goto error);
1062         dim = isl_space_cow(dim);
1063         if (!dim)
1064                 return NULL;
1065         if (dim->ids) {
1066                 ids = isl_calloc_array(dim->ctx, isl_id *,
1067                                         dim->nparam + dim->n_out + dim->n_out);
1068                 if (!ids)
1069                         goto error;
1070                 get_ids(dim, isl_dim_param, 0, dim->nparam, ids);
1071                 get_ids(dim, isl_dim_out, 0, dim->n_out, ids + dim->nparam);
1072         }
1073         dim->n_in = dim->n_out;
1074         if (ids) {
1075                 free(dim->ids);
1076                 dim->ids = ids;
1077                 dim->n_id = dim->nparam + dim->n_out + dim->n_out;
1078                 dim = copy_ids(dim, isl_dim_out, 0, dim, isl_dim_in);
1079         }
1080         isl_id_free(dim->tuple_id[0]);
1081         dim->tuple_id[0] = isl_id_copy(dim->tuple_id[1]);
1082         isl_space_free(dim->nested[0]);
1083         dim->nested[0] = isl_space_copy(dim->nested[1]);
1084         return dim;
1085 error:
1086         isl_space_free(dim);
1087         return NULL;
1088 }
1089
1090 __isl_give isl_space *isl_space_map_from_domain_and_range(
1091         __isl_take isl_space *domain, __isl_take isl_space *range)
1092 {
1093         if (!domain || !range)
1094                 goto error;
1095         if (!isl_space_is_set(domain))
1096                 isl_die(isl_space_get_ctx(domain), isl_error_invalid,
1097                         "domain is not a set space", goto error);
1098         if (!isl_space_is_set(range))
1099                 isl_die(isl_space_get_ctx(range), isl_error_invalid,
1100                         "range is not a set space", goto error);
1101         return isl_space_join(isl_space_reverse(domain), range);
1102 error:
1103         isl_space_free(domain);
1104         isl_space_free(range);
1105         return NULL;
1106 }
1107
1108 static __isl_give isl_space *set_ids(__isl_take isl_space *dim,
1109         enum isl_dim_type type,
1110         unsigned first, unsigned n, __isl_take isl_id **ids)
1111 {
1112         int i;
1113
1114         for (i = 0; i < n ; ++i)
1115                 dim = set_id(dim, type, first + i, ids[i]);
1116
1117         return dim;
1118 }
1119
1120 __isl_give isl_space *isl_space_reverse(__isl_take isl_space *dim)
1121 {
1122         unsigned t;
1123         isl_space *nested;
1124         isl_id **ids = NULL;
1125         isl_id *id;
1126
1127         if (!dim)
1128                 return NULL;
1129         if (match(dim, isl_dim_in, dim, isl_dim_out))
1130                 return dim;
1131
1132         dim = isl_space_cow(dim);
1133         if (!dim)
1134                 return NULL;
1135
1136         id = dim->tuple_id[0];
1137         dim->tuple_id[0] = dim->tuple_id[1];
1138         dim->tuple_id[1] = id;
1139
1140         nested = dim->nested[0];
1141         dim->nested[0] = dim->nested[1];
1142         dim->nested[1] = nested;
1143
1144         if (dim->ids) {
1145                 ids = isl_alloc_array(dim->ctx, isl_id *,
1146                                         dim->n_in + dim->n_out);
1147                 if (!ids)
1148                         goto error;
1149                 get_ids(dim, isl_dim_in, 0, dim->n_in, ids);
1150                 get_ids(dim, isl_dim_out, 0, dim->n_out, ids + dim->n_in);
1151         }
1152
1153         t = dim->n_in;
1154         dim->n_in = dim->n_out;
1155         dim->n_out = t;
1156
1157         if (dim->ids) {
1158                 dim = set_ids(dim, isl_dim_out, 0, dim->n_out, ids);
1159                 dim = set_ids(dim, isl_dim_in, 0, dim->n_in, ids + dim->n_out);
1160                 free(ids);
1161         }
1162
1163         return dim;
1164 error:
1165         free(ids);
1166         isl_space_free(dim);
1167         return NULL;
1168 }
1169
1170 __isl_give isl_space *isl_space_drop_dims(__isl_take isl_space *dim,
1171         enum isl_dim_type type, unsigned first, unsigned num)
1172 {
1173         int i;
1174
1175         if (!dim)
1176                 return NULL;
1177
1178         if (num == 0)
1179                 return isl_space_reset(dim, type);
1180
1181         if (!valid_dim_type(type))
1182                 isl_die(dim->ctx, isl_error_invalid,
1183                         "cannot drop dimensions of specified type", goto error);
1184
1185         isl_assert(dim->ctx, first + num <= n(dim, type), goto error);
1186         dim = isl_space_cow(dim);
1187         if (!dim)
1188                 goto error;
1189         if (dim->ids) {
1190                 dim = extend_ids(dim);
1191                 if (!dim)
1192                         goto error;
1193                 for (i = 0; i < num; ++i)
1194                         isl_id_free(get_id(dim, type, first + i));
1195                 for (i = first+num; i < n(dim, type); ++i)
1196                         set_id(dim, type, i - num, get_id(dim, type, i));
1197                 switch (type) {
1198                 case isl_dim_param:
1199                         get_ids(dim, isl_dim_in, 0, dim->n_in,
1200                                 dim->ids + offset(dim, isl_dim_in) - num);
1201                 case isl_dim_in:
1202                         get_ids(dim, isl_dim_out, 0, dim->n_out,
1203                                 dim->ids + offset(dim, isl_dim_out) - num);
1204                 default:
1205                         ;
1206                 }
1207                 dim->n_id -= num;
1208         }
1209         switch (type) {
1210         case isl_dim_param:     dim->nparam -= num; break;
1211         case isl_dim_in:        dim->n_in -= num; break;
1212         case isl_dim_out:       dim->n_out -= num; break;
1213         default:                ;
1214         }
1215         dim = isl_space_reset(dim, type);
1216         if (type == isl_dim_param) {
1217                 if (dim && dim->nested[0] &&
1218                     !(dim->nested[0] = isl_space_drop_dims(dim->nested[0],
1219                                                     isl_dim_param, first, num)))
1220                         goto error;
1221                 if (dim && dim->nested[1] &&
1222                     !(dim->nested[1] = isl_space_drop_dims(dim->nested[1],
1223                                                     isl_dim_param, first, num)))
1224                         goto error;
1225         }
1226         return dim;
1227 error:
1228         isl_space_free(dim);
1229         return NULL;
1230 }
1231
1232 __isl_give isl_space *isl_space_drop_inputs(__isl_take isl_space *dim,
1233                 unsigned first, unsigned n)
1234 {
1235         if (!dim)
1236                 return NULL;
1237         return isl_space_drop_dims(dim, isl_dim_in, first, n);
1238 }
1239
1240 __isl_give isl_space *isl_space_drop_outputs(__isl_take isl_space *dim,
1241                 unsigned first, unsigned n)
1242 {
1243         if (!dim)
1244                 return NULL;
1245         return isl_space_drop_dims(dim, isl_dim_out, first, n);
1246 }
1247
1248 __isl_give isl_space *isl_space_domain(__isl_take isl_space *dim)
1249 {
1250         if (!dim)
1251                 return NULL;
1252         dim = isl_space_drop_outputs(dim, 0, dim->n_out);
1253         dim = isl_space_reverse(dim);
1254         dim = mark_as_set(dim);
1255         return dim;
1256 }
1257
1258 __isl_give isl_space *isl_space_from_domain(__isl_take isl_space *dim)
1259 {
1260         if (!dim)
1261                 return NULL;
1262         if (!isl_space_is_set(dim))
1263                 isl_die(isl_space_get_ctx(dim), isl_error_invalid,
1264                         "not a set space", goto error);
1265         dim = isl_space_reverse(dim);
1266         dim = isl_space_reset(dim, isl_dim_out);
1267         return dim;
1268 error:
1269         isl_space_free(dim);
1270         return NULL;
1271 }
1272
1273 __isl_give isl_space *isl_space_range(__isl_take isl_space *dim)
1274 {
1275         if (!dim)
1276                 return NULL;
1277         dim = isl_space_drop_inputs(dim, 0, dim->n_in);
1278         dim = mark_as_set(dim);
1279         return dim;
1280 }
1281
1282 __isl_give isl_space *isl_space_from_range(__isl_take isl_space *dim)
1283 {
1284         if (!dim)
1285                 return NULL;
1286         if (!isl_space_is_set(dim))
1287                 isl_die(isl_space_get_ctx(dim), isl_error_invalid,
1288                         "not a set space", goto error);
1289         return isl_space_reset(dim, isl_dim_in);
1290 error:
1291         isl_space_free(dim);
1292         return NULL;
1293 }
1294
1295 __isl_give isl_space *isl_space_params(__isl_take isl_space *space)
1296 {
1297         if (isl_space_is_params(space))
1298                 return space;
1299         space = isl_space_drop_dims(space,
1300                             isl_dim_in, 0, isl_space_dim(space, isl_dim_in));
1301         space = isl_space_drop_dims(space,
1302                             isl_dim_out, 0, isl_space_dim(space, isl_dim_out));
1303         space = mark_as_params(space);
1304         return space;
1305 }
1306
1307 __isl_give isl_space *isl_space_set_from_params(__isl_take isl_space *space)
1308 {
1309         if (!space)
1310                 return NULL;
1311         if (!isl_space_is_params(space))
1312                 isl_die(isl_space_get_ctx(space), isl_error_invalid,
1313                         "not a parameter space", goto error);
1314         return isl_space_reset(space, isl_dim_set);
1315 error:
1316         isl_space_free(space);
1317         return NULL;
1318 }
1319
1320 __isl_give isl_space *isl_space_as_set_space(__isl_take isl_space *dim)
1321 {
1322         dim = isl_space_cow(dim);
1323         if (!dim)
1324                 return NULL;
1325
1326         dim->n_out += dim->n_in;
1327         dim->n_in = 0;
1328         dim = isl_space_reset(dim, isl_dim_in);
1329         dim = isl_space_reset(dim, isl_dim_out);
1330
1331         return dim;
1332 }
1333
1334 __isl_give isl_space *isl_space_underlying(__isl_take isl_space *dim,
1335         unsigned n_div)
1336 {
1337         int i;
1338
1339         if (!dim)
1340                 return NULL;
1341         if (n_div == 0 &&
1342             dim->nparam == 0 && dim->n_in == 0 && dim->n_id == 0)
1343                 return isl_space_reset(isl_space_reset(dim, isl_dim_in), isl_dim_out);
1344         dim = isl_space_cow(dim);
1345         if (!dim)
1346                 return NULL;
1347         dim->n_out += dim->nparam + dim->n_in + n_div;
1348         dim->nparam = 0;
1349         dim->n_in = 0;
1350
1351         for (i = 0; i < dim->n_id; ++i)
1352                 isl_id_free(get_id(dim, isl_dim_out, i));
1353         dim->n_id = 0;
1354         dim = isl_space_reset(dim, isl_dim_in);
1355         dim = isl_space_reset(dim, isl_dim_out);
1356
1357         return dim;
1358 }
1359
1360 int isl_space_is_equal(__isl_keep isl_space *dim1, __isl_keep isl_space *dim2)
1361 {
1362         if (!dim1 || !dim2)
1363                 return -1;
1364         if (dim1 == dim2)
1365                 return 1;
1366         return match(dim1, isl_dim_param, dim2, isl_dim_param) &&
1367                isl_space_tuple_match(dim1, isl_dim_in, dim2, isl_dim_in) &&
1368                isl_space_tuple_match(dim1, isl_dim_out, dim2, isl_dim_out);
1369 }
1370
1371 /* Is space1 equal to the domain of space2?
1372  */
1373 int isl_space_is_domain(__isl_keep isl_space *space1,
1374         __isl_keep isl_space *space2)
1375 {
1376         if (!space1 || !space2)
1377                 return -1;
1378         if (!isl_space_is_set(space1))
1379                 return 0;
1380         return match(space1, isl_dim_param, space2, isl_dim_param) &&
1381                isl_space_tuple_match(space1, isl_dim_set, space2, isl_dim_in);
1382 }
1383
1384 int isl_space_compatible(__isl_keep isl_space *dim1,
1385         __isl_keep isl_space *dim2)
1386 {
1387         return dim1->nparam == dim2->nparam &&
1388                dim1->n_in + dim1->n_out == dim2->n_in + dim2->n_out;
1389 }
1390
1391 static uint32_t isl_hash_dim(uint32_t hash, __isl_keep isl_space *dim)
1392 {
1393         int i;
1394         isl_id *id;
1395
1396         if (!dim)
1397                 return hash;
1398
1399         hash = isl_hash_builtin(hash, dim->nparam);
1400         hash = isl_hash_builtin(hash, dim->n_in);
1401         hash = isl_hash_builtin(hash, dim->n_out);
1402
1403         for (i = 0; i < dim->nparam; ++i) {
1404                 id = get_id(dim, isl_dim_param, i);
1405                 hash = isl_hash_id(hash, id);
1406         }
1407
1408         id = tuple_id(dim, isl_dim_in);
1409         hash = isl_hash_id(hash, id);
1410         id = tuple_id(dim, isl_dim_out);
1411         hash = isl_hash_id(hash, id);
1412
1413         hash = isl_hash_dim(hash, dim->nested[0]);
1414         hash = isl_hash_dim(hash, dim->nested[1]);
1415
1416         return hash;
1417 }
1418
1419 uint32_t isl_space_get_hash(__isl_keep isl_space *dim)
1420 {
1421         uint32_t hash;
1422
1423         if (!dim)
1424                 return 0;
1425
1426         hash = isl_hash_init();
1427         hash = isl_hash_dim(hash, dim);
1428
1429         return hash;
1430 }
1431
1432 int isl_space_is_wrapping(__isl_keep isl_space *dim)
1433 {
1434         if (!dim)
1435                 return -1;
1436
1437         if (!isl_space_is_set(dim))
1438                 return 0;
1439
1440         return dim->nested[1] != NULL;
1441 }
1442
1443 __isl_give isl_space *isl_space_wrap(__isl_take isl_space *dim)
1444 {
1445         isl_space *wrap;
1446
1447         if (!dim)
1448                 return NULL;
1449
1450         wrap = isl_space_set_alloc(dim->ctx,
1451                                     dim->nparam, dim->n_in + dim->n_out);
1452
1453         wrap = copy_ids(wrap, isl_dim_param, 0, dim, isl_dim_param);
1454         wrap = copy_ids(wrap, isl_dim_set, 0, dim, isl_dim_in);
1455         wrap = copy_ids(wrap, isl_dim_set, dim->n_in, dim, isl_dim_out);
1456
1457         if (!wrap)
1458                 goto error;
1459
1460         wrap->nested[1] = dim;
1461
1462         return wrap;
1463 error:
1464         isl_space_free(dim);
1465         return NULL;
1466 }
1467
1468 __isl_give isl_space *isl_space_unwrap(__isl_take isl_space *dim)
1469 {
1470         isl_space *unwrap;
1471
1472         if (!dim)
1473                 return NULL;
1474
1475         if (!isl_space_is_wrapping(dim))
1476                 isl_die(dim->ctx, isl_error_invalid, "not a wrapping dim",
1477                         goto error);
1478
1479         unwrap = isl_space_copy(dim->nested[1]);
1480         isl_space_free(dim);
1481
1482         return unwrap;
1483 error:
1484         isl_space_free(dim);
1485         return NULL;
1486 }
1487
1488 int isl_space_is_named_or_nested(__isl_keep isl_space *dim, enum isl_dim_type type)
1489 {
1490         if (type != isl_dim_in && type != isl_dim_out)
1491                 return 0;
1492         if (!dim)
1493                 return -1;
1494         if (dim->tuple_id[type - isl_dim_in])
1495                 return 1;
1496         if (dim->nested[type - isl_dim_in])
1497                 return 1;
1498         return 0;
1499 }
1500
1501 int isl_space_may_be_set(__isl_keep isl_space *dim)
1502 {
1503         if (!dim)
1504                 return -1;
1505         if (isl_space_is_set(dim))
1506                 return 1;
1507         if (isl_space_dim(dim, isl_dim_in) != 0)
1508                 return 0;
1509         if (isl_space_is_named_or_nested(dim, isl_dim_in))
1510                 return 0;
1511         return 1;
1512 }
1513
1514 __isl_give isl_space *isl_space_reset(__isl_take isl_space *dim,
1515         enum isl_dim_type type)
1516 {
1517         if (!isl_space_is_named_or_nested(dim, type))
1518                 return dim;
1519
1520         dim = isl_space_cow(dim);
1521         if (!dim)
1522                 return NULL;
1523
1524         isl_id_free(dim->tuple_id[type - isl_dim_in]);
1525         dim->tuple_id[type - isl_dim_in] = NULL;
1526         isl_space_free(dim->nested[type - isl_dim_in]);
1527         dim->nested[type - isl_dim_in] = NULL;
1528
1529         return dim;
1530 }
1531
1532 __isl_give isl_space *isl_space_flatten(__isl_take isl_space *dim)
1533 {
1534         if (!dim)
1535                 return NULL;
1536         if (!dim->nested[0] && !dim->nested[1])
1537                 return dim;
1538
1539         if (dim->nested[0])
1540                 dim = isl_space_reset(dim, isl_dim_in);
1541         if (dim && dim->nested[1])
1542                 dim = isl_space_reset(dim, isl_dim_out);
1543
1544         return dim;
1545 }
1546
1547 __isl_give isl_space *isl_space_flatten_domain(__isl_take isl_space *dim)
1548 {
1549         if (!dim)
1550                 return NULL;
1551         if (!dim->nested[0])
1552                 return dim;
1553
1554         return isl_space_reset(dim, isl_dim_in);
1555 }
1556
1557 __isl_give isl_space *isl_space_flatten_range(__isl_take isl_space *dim)
1558 {
1559         if (!dim)
1560                 return NULL;
1561         if (!dim->nested[1])
1562                 return dim;
1563
1564         return isl_space_reset(dim, isl_dim_out);
1565 }
1566
1567 /* Replace the dimensions of the given type of dst by those of src.
1568  */
1569 __isl_give isl_space *isl_space_replace(__isl_take isl_space *dst,
1570         enum isl_dim_type type, __isl_keep isl_space *src)
1571 {
1572         dst = isl_space_cow(dst);
1573
1574         if (!dst || !src)
1575                 goto error;
1576
1577         dst = isl_space_drop_dims(dst, type, 0, isl_space_dim(dst, type));
1578         dst = isl_space_add_dims(dst, type, isl_space_dim(src, type));
1579         dst = copy_ids(dst, type, 0, src, type);
1580
1581         if (dst && type == isl_dim_param) {
1582                 int i;
1583                 for (i = 0; i <= 1; ++i) {
1584                         if (!dst->nested[i])
1585                                 continue;
1586                         dst->nested[i] = isl_space_replace(dst->nested[i],
1587                                                          type, src);
1588                         if (!dst->nested[i])
1589                                 goto error;
1590                 }
1591         }
1592
1593         return dst;
1594 error:
1595         isl_space_free(dst);
1596         return NULL;
1597 }
1598
1599 /* Given a dimension specification "dim" of a set, create a dimension
1600  * specification for the lift of the set.  In particular, the result
1601  * is of the form [dim -> local[..]], with n_local variables in the
1602  * range of the wrapped map.
1603  */
1604 __isl_give isl_space *isl_space_lift(__isl_take isl_space *dim, unsigned n_local)
1605 {
1606         isl_space *local_dim;
1607
1608         if (!dim)
1609                 return NULL;
1610
1611         local_dim = isl_space_dup(dim);
1612         local_dim = isl_space_drop_dims(local_dim, isl_dim_set, 0, dim->n_out);
1613         local_dim = isl_space_add_dims(local_dim, isl_dim_set, n_local);
1614         local_dim = isl_space_set_tuple_name(local_dim, isl_dim_set, "local");
1615         dim = isl_space_join(isl_space_from_domain(dim),
1616                             isl_space_from_range(local_dim));
1617         dim = isl_space_wrap(dim);
1618         dim = isl_space_set_tuple_name(dim, isl_dim_set, "lifted");
1619
1620         return dim;
1621 }
1622
1623 int isl_space_can_zip(__isl_keep isl_space *dim)
1624 {
1625         if (!dim)
1626                 return -1;
1627
1628         return dim->nested[0] && dim->nested[1];
1629 }
1630
1631 __isl_give isl_space *isl_space_zip(__isl_take isl_space *dim)
1632 {
1633         isl_space *dom, *ran;
1634         isl_space *dom_dom, *dom_ran, *ran_dom, *ran_ran;
1635
1636         if (!isl_space_can_zip(dim))
1637                 isl_die(dim->ctx, isl_error_invalid, "dim cannot be zipped",
1638                         goto error);
1639
1640         if (!dim)
1641                 return 0;
1642         dom = isl_space_unwrap(isl_space_domain(isl_space_copy(dim)));
1643         ran = isl_space_unwrap(isl_space_range(dim));
1644         dom_dom = isl_space_domain(isl_space_copy(dom));
1645         dom_ran = isl_space_range(dom);
1646         ran_dom = isl_space_domain(isl_space_copy(ran));
1647         ran_ran = isl_space_range(ran);
1648         dom = isl_space_join(isl_space_from_domain(dom_dom),
1649                            isl_space_from_range(ran_dom));
1650         ran = isl_space_join(isl_space_from_domain(dom_ran),
1651                            isl_space_from_range(ran_ran));
1652         return isl_space_join(isl_space_from_domain(isl_space_wrap(dom)),
1653                             isl_space_from_range(isl_space_wrap(ran)));
1654 error:
1655         isl_space_free(dim);
1656         return NULL;
1657 }
1658
1659 int isl_space_has_named_params(__isl_keep isl_space *dim)
1660 {
1661         int i;
1662         unsigned off;
1663
1664         if (!dim)
1665                 return -1;
1666         if (dim->nparam == 0)
1667                 return 1;
1668         off = isl_space_offset(dim, isl_dim_param);
1669         if (off + dim->nparam > dim->n_id)
1670                 return 0;
1671         for (i = 0; i < dim->nparam; ++i)
1672                 if (!dim->ids[off + i])
1673                         return 0;
1674         return 1;
1675 }
1676
1677 /* Align the initial parameters of dim1 to match the order in dim2.
1678  */
1679 __isl_give isl_space *isl_space_align_params(__isl_take isl_space *dim1,
1680         __isl_take isl_space *dim2)
1681 {
1682         isl_reordering *exp;
1683
1684         if (!isl_space_has_named_params(dim1) || !isl_space_has_named_params(dim2))
1685                 isl_die(isl_space_get_ctx(dim1), isl_error_invalid,
1686                         "parameter alignment requires named parameters",
1687                         goto error);
1688
1689         dim2 = isl_space_params(dim2);
1690         exp = isl_parameter_alignment_reordering(dim1, dim2);
1691         exp = isl_reordering_extend_space(exp, dim1);
1692         isl_space_free(dim2);
1693         if (!exp)
1694                 return NULL;
1695         dim1 = isl_space_copy(exp->dim);
1696         isl_reordering_free(exp);
1697         return dim1;
1698 error:
1699         isl_space_free(dim1);
1700         isl_space_free(dim2);
1701         return NULL;
1702 }
1703
1704 /* Given the space of set (domain), construct a space for a map
1705  * with as domain the given space and as range the range of "model".
1706  */
1707 __isl_give isl_space *isl_space_extend_domain_with_range(
1708         __isl_take isl_space *domain, __isl_take isl_space *model)
1709 {
1710         isl_space *space;
1711
1712         space = isl_space_from_domain(domain);
1713         space = isl_space_add_dims(space, isl_dim_out,
1714                                     isl_space_dim(model, isl_dim_out));
1715         if (isl_space_has_tuple_id(model, isl_dim_out))
1716                 space = isl_space_set_tuple_id(space, isl_dim_out,
1717                                 isl_space_get_tuple_id(model, isl_dim_out));
1718         isl_space_free(model);
1719         return space;
1720 }