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