a04fd970abaaa2becff6adcd84e52853ab2127a7
[platform/upstream/isl.git] / isl_dim.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_dim_private.h>
15 #include "isl_name.h"
16
17 isl_ctx *isl_dim_get_ctx(__isl_keep isl_dim *dim)
18 {
19         return dim ? dim->ctx : NULL;
20 }
21
22 struct isl_dim *isl_dim_alloc(struct isl_ctx *ctx,
23                         unsigned nparam, unsigned n_in, unsigned n_out)
24 {
25         struct isl_dim *dim;
26
27         dim = isl_alloc_type(ctx, struct isl_dim);
28         if (!dim)
29                 return NULL;
30
31         dim->ctx = ctx;
32         isl_ctx_ref(ctx);
33         dim->ref = 1;
34         dim->nparam = nparam;
35         dim->n_in = n_in;
36         dim->n_out = n_out;
37
38         dim->tuple_name[0] = NULL;
39         dim->tuple_name[1] = NULL;
40
41         dim->nested[0] = NULL;
42         dim->nested[1] = NULL;
43
44         dim->n_name = 0;
45         dim->names = NULL;
46
47         return dim;
48 }
49
50 struct isl_dim *isl_dim_set_alloc(struct isl_ctx *ctx,
51                         unsigned nparam, unsigned dim)
52 {
53         return isl_dim_alloc(ctx, nparam, 0, dim);
54 }
55
56 static unsigned global_pos(struct isl_dim *dim,
57                                  enum isl_dim_type type, unsigned pos)
58 {
59         struct isl_ctx *ctx = dim->ctx;
60
61         switch (type) {
62         case isl_dim_param:
63                 isl_assert(ctx, pos < dim->nparam, return isl_dim_total(dim));
64                 return pos;
65         case isl_dim_in:
66                 isl_assert(ctx, pos < dim->n_in, return isl_dim_total(dim));
67                 return pos + dim->nparam;
68         case isl_dim_out:
69                 isl_assert(ctx, pos < dim->n_out, return isl_dim_total(dim));
70                 return pos + dim->nparam + dim->n_in;
71         default:
72                 isl_assert(ctx, 0, return isl_dim_total(dim));
73         }
74         return isl_dim_total(dim);
75 }
76
77 /* Extend length of names array to the total number of dimensions.
78  */
79 static __isl_give isl_dim *extend_names(__isl_take isl_dim *dim)
80 {
81         struct isl_name **names;
82         int i;
83
84         if (isl_dim_total(dim) <= dim->n_name)
85                 return dim;
86
87         if (!dim->names) {
88                 dim->names = isl_calloc_array(dim->ctx,
89                                 struct isl_name *, isl_dim_total(dim));
90                 if (!dim->names)
91                         goto error;
92         } else {
93                 names = isl_realloc_array(dim->ctx, dim->names,
94                                 struct isl_name *, isl_dim_total(dim));
95                 if (!names)
96                         goto error;
97                 dim->names = names;
98                 for (i = dim->n_name; i < isl_dim_total(dim); ++i)
99                         dim->names[i] = NULL;
100         }
101
102         dim->n_name = isl_dim_total(dim);
103
104         return dim;
105 error:
106         isl_dim_free(dim);
107         return NULL;
108 }
109
110 static struct isl_dim *set_name(struct isl_dim *dim,
111                                  enum isl_dim_type type, unsigned pos,
112                                  struct isl_name *name)
113 {
114         struct isl_ctx *ctx = dim->ctx;
115         dim = isl_dim_cow(dim);
116
117         if (!dim)
118                 goto error;
119
120         pos = global_pos(dim, type, pos);
121         isl_assert(ctx, pos != isl_dim_total(dim), goto error);
122
123         if (pos >= dim->n_name) {
124                 if (!name)
125                         return dim;
126                 dim = extend_names(dim);
127                 if (!dim)
128                         goto error;
129         }
130
131         dim->names[pos] = name;
132
133         return dim;
134 error:
135         isl_name_free(ctx, name);
136         isl_dim_free(dim);
137         return NULL;
138 }
139
140 static struct isl_name *get_name(struct isl_dim *dim,
141                                  enum isl_dim_type type, unsigned pos)
142 {
143         if (!dim)
144                 return NULL;
145
146         pos = global_pos(dim, type, pos);
147         if (pos == isl_dim_total(dim))
148                 return NULL;
149         if (pos >= dim->n_name)
150                 return NULL;
151         return dim->names[pos];
152 }
153
154 static unsigned offset(struct isl_dim *dim, enum isl_dim_type type)
155 {
156         switch (type) {
157         case isl_dim_param:     return 0;
158         case isl_dim_in:        return dim->nparam;
159         case isl_dim_out:       return dim->nparam + dim->n_in;
160         default:                return 0;
161         }
162 }
163
164 static unsigned n(struct isl_dim *dim, enum isl_dim_type type)
165 {
166         switch (type) {
167         case isl_dim_param:     return dim->nparam;
168         case isl_dim_in:        return dim->n_in;
169         case isl_dim_out:       return dim->n_out;
170         default:                return 0;
171         }
172 }
173
174 unsigned isl_dim_size(struct isl_dim *dim, enum isl_dim_type type)
175 {
176         if (!dim)
177                 return 0;
178         return n(dim, type);
179 }
180
181 unsigned isl_dim_offset(__isl_keep isl_dim *dim, enum isl_dim_type type)
182 {
183         if (!dim)
184                 return 0;
185         return offset(dim, type);
186 }
187
188 static struct isl_dim *copy_names(struct isl_dim *dst,
189         enum isl_dim_type dst_type, unsigned offset, struct isl_dim *src,
190         enum isl_dim_type src_type)
191 {
192         int i;
193         struct isl_name *name;
194
195         if (!dst)
196                 return NULL;
197
198         for (i = 0; i < n(src, src_type); ++i) {
199                 name = get_name(src, src_type, i);
200                 if (!name)
201                         continue;
202                 dst = set_name(dst, dst_type, offset + i,
203                                         isl_name_copy(dst->ctx, name));
204                 if (!dst)
205                         return NULL;
206         }
207         return dst;
208 }
209
210 struct isl_dim *isl_dim_dup(struct isl_dim *dim)
211 {
212         struct isl_dim *dup;
213         if (!dim)
214                 return NULL;
215         dup = isl_dim_alloc(dim->ctx, dim->nparam, dim->n_in, dim->n_out);
216         if (dim->tuple_name[0] &&
217             !(dup->tuple_name[0] = isl_name_copy(dim->ctx, dim->tuple_name[0])))
218                 goto error;
219         if (dim->tuple_name[1] &&
220             !(dup->tuple_name[1] = isl_name_copy(dim->ctx, dim->tuple_name[1])))
221                 goto error;
222         if (dim->nested[0] && !(dup->nested[0] = isl_dim_copy(dim->nested[0])))
223                 goto error;
224         if (dim->nested[1] && !(dup->nested[1] = isl_dim_copy(dim->nested[1])))
225                 goto error;
226         if (!dim->names)
227                 return dup;
228         dup = copy_names(dup, isl_dim_param, 0, dim, isl_dim_param);
229         dup = copy_names(dup, isl_dim_in, 0, dim, isl_dim_in);
230         dup = copy_names(dup, isl_dim_out, 0, dim, isl_dim_out);
231         return dup;
232 error:
233         isl_dim_free(dup);
234         return NULL;
235 }
236
237 struct isl_dim *isl_dim_cow(struct isl_dim *dim)
238 {
239         if (!dim)
240                 return NULL;
241
242         if (dim->ref == 1)
243                 return dim;
244         dim->ref--;
245         return isl_dim_dup(dim);
246 }
247
248 struct isl_dim *isl_dim_copy(struct isl_dim *dim)
249 {
250         if (!dim)
251                 return NULL;
252
253         dim->ref++;
254         return dim;
255 }
256
257 void isl_dim_free(struct isl_dim *dim)
258 {
259         int i;
260
261         if (!dim)
262                 return;
263
264         if (--dim->ref > 0)
265                 return;
266
267         isl_name_free(dim->ctx, dim->tuple_name[0]);
268         isl_name_free(dim->ctx, dim->tuple_name[1]);
269
270         isl_dim_free(dim->nested[0]);
271         isl_dim_free(dim->nested[1]);
272
273         for (i = 0; i < dim->n_name; ++i)
274                 isl_name_free(dim->ctx, dim->names[i]);
275         free(dim->names);
276         isl_ctx_deref(dim->ctx);
277         
278         free(dim);
279 }
280
281 static int name_ok(isl_ctx *ctx, const char *s)
282 {
283         char *p;
284         long dummy;
285
286         dummy = strtol(s, &p, 0);
287         if (p != s)
288                 isl_die(ctx, isl_error_invalid, "name looks like a number",
289                         return 0);
290
291         return 1;
292 }
293
294 __isl_give isl_dim *isl_dim_set_tuple_name(__isl_take isl_dim *dim,
295         enum isl_dim_type type, const char *s)
296 {
297         struct isl_name *name;
298
299         dim = isl_dim_cow(dim);
300         if (!dim)
301                 return NULL;
302         if (type != isl_dim_in && type != isl_dim_out)
303                 isl_die(dim->ctx, isl_error_invalid,
304                         "only input, output and set tuples can have names",
305                         goto error);
306         if (!s) {
307                 name = NULL;
308         } else {
309                 if (!name_ok(dim->ctx, s))
310                         goto error;
311                 name = isl_name_get(dim->ctx, s);
312                 if (!name)
313                         goto error;
314         }
315
316         isl_name_free(dim->ctx, dim->tuple_name[type - isl_dim_in]);
317         dim->tuple_name[type - isl_dim_in] = name;
318
319         return dim;
320 error:
321         isl_dim_free(dim);
322         return NULL;
323 }
324
325 const char *isl_dim_get_tuple_name(__isl_keep isl_dim *dim,
326          enum isl_dim_type type)
327 {
328         struct isl_name *name;
329         if (!dim)
330                 return NULL;
331         if (type != isl_dim_in && type != isl_dim_out)
332                 return NULL;
333         name = dim->tuple_name[type - isl_dim_in];
334         return name ? name->name : NULL;
335 }
336
337 struct isl_dim *isl_dim_set_name(struct isl_dim *dim,
338                                  enum isl_dim_type type, unsigned pos,
339                                  const char *s)
340 {
341         struct isl_name *name;
342
343         if (!dim)
344                 return NULL;
345         if (!name_ok(dim->ctx, s))
346                 goto error;
347         name = isl_name_get(dim->ctx, s);
348         if (!name)
349                 goto error;
350         return set_name(dim, type, pos, name);
351 error:
352         isl_dim_free(dim);
353         return NULL;
354 }
355
356 const char *isl_dim_get_name(struct isl_dim *dim,
357                                  enum isl_dim_type type, unsigned pos)
358 {
359         struct isl_name *name = get_name(dim, type, pos);
360         return name ? name->name : NULL;
361 }
362
363 static struct isl_name *tuple_name(__isl_keep isl_dim *dim,
364         enum isl_dim_type type)
365 {
366         if (!dim)
367                 return NULL;
368         if (type == isl_dim_in)
369                 return dim->tuple_name[0];
370         if (type == isl_dim_out)
371                 return dim->tuple_name[1];
372         return NULL;
373 }
374
375 static __isl_keep isl_dim *nested(__isl_keep isl_dim *dim,
376         enum isl_dim_type type)
377 {
378         if (!dim)
379                 return NULL;
380         if (type == isl_dim_in)
381                 return dim->nested[0];
382         if (type == isl_dim_out)
383                 return dim->nested[1];
384         return NULL;
385 }
386
387 int isl_dim_tuple_match(__isl_keep isl_dim *dim1, enum isl_dim_type dim1_type,
388                         __isl_keep isl_dim *dim2, enum isl_dim_type dim2_type)
389 {
390         struct isl_name *name1, *name2;
391         isl_dim *nested1, *nested2;
392
393         if (n(dim1, dim1_type) != n(dim2, dim2_type))
394                 return 0;
395         name1 = tuple_name(dim1, dim1_type);
396         name2 = tuple_name(dim2, dim2_type);
397         if (!name1 ^ !name2)
398                 return 0;
399         if (name1 && name1->name != name2->name)
400                 return 0;
401         nested1 = nested(dim1, dim1_type);
402         nested2 = nested(dim2, dim2_type);
403         if (!nested1 ^ !nested2)
404                 return 0;
405         if (nested1 && !isl_dim_equal(nested1, nested2))
406                 return 0;
407         return 1;
408 }
409
410 static int match(struct isl_dim *dim1, enum isl_dim_type dim1_type,
411                 struct isl_dim *dim2, enum isl_dim_type dim2_type)
412 {
413         int i;
414
415         if (!isl_dim_tuple_match(dim1, dim1_type, dim2, dim2_type))
416                 return 0;
417
418         if (!dim1->names && !dim2->names)
419                 return 1;
420
421         for (i = 0; i < n(dim1, dim1_type); ++i) {
422                 if (get_name(dim1, dim1_type, i) !=
423                     get_name(dim2, dim2_type, i))
424                         return 0;
425         }
426         return 1;
427 }
428
429 int isl_dim_match(struct isl_dim *dim1, enum isl_dim_type dim1_type,
430                 struct isl_dim *dim2, enum isl_dim_type dim2_type)
431 {
432         return match(dim1, dim1_type, dim2, dim2_type);
433 }
434
435 static void get_names(struct isl_dim *dim, enum isl_dim_type type,
436         unsigned first, unsigned n, struct isl_name **names)
437 {
438         int i;
439
440         for (i = 0; i < n ; ++i)
441                 names[i] = get_name(dim, type, first+i);
442 }
443
444 struct isl_dim *isl_dim_extend(struct isl_dim *dim,
445                         unsigned nparam, unsigned n_in, unsigned n_out)
446 {
447         struct isl_name **names = NULL;
448
449         if (!dim)
450                 return NULL;
451         if (dim->nparam == nparam && dim->n_in == n_in && dim->n_out == n_out)
452                 return dim;
453
454         isl_assert(dim->ctx, dim->nparam <= nparam, goto error);
455         isl_assert(dim->ctx, dim->n_in <= n_in, goto error);
456         isl_assert(dim->ctx, dim->n_out <= n_out, goto error);
457
458         dim = isl_dim_cow(dim);
459
460         if (dim->names) {
461                 names = isl_calloc_array(dim->ctx, struct isl_name *,
462                                          nparam + n_in + n_out);
463                 if (!names)
464                         goto error;
465                 get_names(dim, isl_dim_param, 0, dim->nparam, names);
466                 get_names(dim, isl_dim_in, 0, dim->n_in, names + nparam);
467                 get_names(dim, isl_dim_out, 0, dim->n_out,
468                                 names + nparam + n_in);
469                 free(dim->names);
470                 dim->names = names;
471                 dim->n_name = nparam + n_in + n_out;
472         }
473         dim->nparam = nparam;
474         dim->n_in = n_in;
475         dim->n_out = n_out;
476
477         return dim;
478 error:
479         free(names);
480         isl_dim_free(dim);
481         return NULL;
482 }
483
484 struct isl_dim *isl_dim_add(struct isl_dim *dim, enum isl_dim_type type,
485         unsigned n)
486 {
487         if (!dim)
488                 return NULL;
489         dim = isl_dim_reset(dim, type);
490         switch (type) {
491         case isl_dim_param:
492                 return isl_dim_extend(dim,
493                                         dim->nparam + n, dim->n_in, dim->n_out);
494         case isl_dim_in:
495                 return isl_dim_extend(dim,
496                                         dim->nparam, dim->n_in + n, dim->n_out);
497         case isl_dim_out:
498                 return isl_dim_extend(dim,
499                                         dim->nparam, dim->n_in, dim->n_out + n);
500         }
501         return dim;
502 }
503
504 __isl_give isl_dim *isl_dim_insert(__isl_take isl_dim *dim,
505         enum isl_dim_type type, unsigned pos, unsigned n)
506 {
507         struct isl_name **names = NULL;
508
509         if (!dim)
510                 return NULL;
511         if (n == 0)
512                 return isl_dim_reset(dim, type);
513
514         isl_assert(dim->ctx, pos <= isl_dim_size(dim, type), goto error);
515
516         dim = isl_dim_cow(dim);
517         if (!dim)
518                 return NULL;
519
520         if (dim->names) {
521                 enum isl_dim_type t;
522                 int off;
523                 int s[3];
524                 int *size = s - isl_dim_param;
525                 names = isl_calloc_array(dim->ctx, struct isl_name *,
526                                      dim->nparam + dim->n_in + dim->n_out + n);
527                 if (!names)
528                         goto error;
529                 off = 0;
530                 size[isl_dim_param] = dim->nparam;
531                 size[isl_dim_in] = dim->n_in;
532                 size[isl_dim_out] = dim->n_out;
533                 for (t = isl_dim_param; t <= isl_dim_out; ++t) {
534                         if (t != type) {
535                                 get_names(dim, t, 0, size[t], names + off);
536                                 off += size[t];
537                         } else {
538                                 get_names(dim, t, 0, pos, names + off);
539                                 off += pos + n;
540                                 get_names(dim, t, pos, size[t]-pos, names+off);
541                                 off += size[t] - pos;
542                         }
543                 }
544                 free(dim->names);
545                 dim->names = names;
546                 dim->n_name = dim->nparam + dim->n_in + dim->n_out + n;
547         }
548         switch (type) {
549         case isl_dim_param:     dim->nparam += n; break;
550         case isl_dim_in:        dim->n_in += n; break;
551         case isl_dim_out:       dim->n_out += n; break;
552         }
553         dim = isl_dim_reset(dim, type);
554
555         return dim;
556 error:
557         isl_dim_free(dim);
558         return NULL;
559 }
560
561 __isl_give isl_dim *isl_dim_move(__isl_take isl_dim *dim,
562         enum isl_dim_type dst_type, unsigned dst_pos,
563         enum isl_dim_type src_type, unsigned src_pos, unsigned n)
564 {
565         if (!dim)
566                 return NULL;
567         if (n == 0)
568                 return dim;
569
570         isl_assert(dim->ctx, src_pos + n <= isl_dim_size(dim, src_type),
571                 goto error);
572
573         if (dst_type == src_type && dst_pos == src_pos)
574                 return dim;
575
576         isl_assert(dim->ctx, dst_type != src_type, goto error);
577
578         dim = isl_dim_reset(dim, src_type);
579         dim = isl_dim_reset(dim, dst_type);
580
581         dim = isl_dim_cow(dim);
582         if (!dim)
583                 return NULL;
584
585         if (dim->names) {
586                 struct isl_name **names;
587                 enum isl_dim_type t;
588                 int off;
589                 int s[3];
590                 int *size = s - isl_dim_param;
591                 names = isl_calloc_array(dim->ctx, struct isl_name *,
592                                          dim->nparam + dim->n_in + dim->n_out);
593                 if (!names)
594                         goto error;
595                 off = 0;
596                 size[isl_dim_param] = dim->nparam;
597                 size[isl_dim_in] = dim->n_in;
598                 size[isl_dim_out] = dim->n_out;
599                 for (t = isl_dim_param; t <= isl_dim_out; ++t) {
600                         if (t == dst_type) {
601                                 get_names(dim, t, 0, dst_pos, names + off);
602                                 off += dst_pos;
603                                 get_names(dim, src_type, src_pos, n, names+off);
604                                 off += n;
605                                 get_names(dim, t, dst_pos, size[t] - dst_pos,
606                                                 names + off);
607                                 off += size[t] - dst_pos;
608                         } else if (t == src_type) {
609                                 get_names(dim, t, 0, src_pos, names + off);
610                                 off += src_pos;
611                                 get_names(dim, t, src_pos + n,
612                                             size[t] - src_pos - n, names + off);
613                                 off += size[t] - src_pos - n;
614                         } else {
615                                 get_names(dim, t, 0, size[t], names + off);
616                                 off += size[t];
617                         }
618                 }
619                 free(dim->names);
620                 dim->names = names;
621                 dim->n_name = dim->nparam + dim->n_in + dim->n_out;
622         }
623
624         switch (dst_type) {
625         case isl_dim_param:     dim->nparam += n; break;
626         case isl_dim_in:        dim->n_in += n; break;
627         case isl_dim_out:       dim->n_out += n; break;
628         }
629
630         switch (src_type) {
631         case isl_dim_param:     dim->nparam -= n; break;
632         case isl_dim_in:        dim->n_in -= n; break;
633         case isl_dim_out:       dim->n_out -= n; break;
634         }
635
636         return dim;
637 error:
638         isl_dim_free(dim);
639         return NULL;
640 }
641
642 struct isl_dim *isl_dim_join(struct isl_dim *left, struct isl_dim *right)
643 {
644         struct isl_dim *dim;
645
646         if (!left || !right)
647                 goto error;
648
649         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
650                         goto error);
651         isl_assert(left->ctx,
652                 isl_dim_tuple_match(left, isl_dim_out, right, isl_dim_in),
653                 goto error);
654
655         dim = isl_dim_alloc(left->ctx, left->nparam, left->n_in, right->n_out);
656         if (!dim)
657                 goto error;
658
659         dim = copy_names(dim, isl_dim_param, 0, left, isl_dim_param);
660         dim = copy_names(dim, isl_dim_in, 0, left, isl_dim_in);
661         dim = copy_names(dim, isl_dim_out, 0, right, isl_dim_out);
662
663         if (dim && left->tuple_name[0] &&
664             !(dim->tuple_name[0] = isl_name_copy(dim->ctx, left->tuple_name[0])))
665                 goto error;
666         if (dim && right->tuple_name[1] &&
667             !(dim->tuple_name[1] = isl_name_copy(dim->ctx, right->tuple_name[1])))
668                 goto error;
669         if (dim && left->nested[0] &&
670             !(dim->nested[0] = isl_dim_copy(left->nested[0])))
671                 goto error;
672         if (dim && right->nested[1] &&
673             !(dim->nested[1] = isl_dim_copy(right->nested[1])))
674                 goto error;
675
676         isl_dim_free(left);
677         isl_dim_free(right);
678
679         return dim;
680 error:
681         isl_dim_free(left);
682         isl_dim_free(right);
683         return NULL;
684 }
685
686 struct isl_dim *isl_dim_product(struct isl_dim *left, struct isl_dim *right)
687 {
688         isl_dim *dom1, *dom2, *nest1, *nest2;
689
690         if (!left || !right)
691                 goto error;
692
693         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
694                         goto error);
695
696         dom1 = isl_dim_domain(isl_dim_copy(left));
697         dom2 = isl_dim_domain(isl_dim_copy(right));
698         nest1 = isl_dim_wrap(isl_dim_join(isl_dim_reverse(dom1), dom2));
699
700         dom1 = isl_dim_range(left);
701         dom2 = isl_dim_range(right);
702         nest2 = isl_dim_wrap(isl_dim_join(isl_dim_reverse(dom1), dom2));
703
704         return isl_dim_join(isl_dim_reverse(nest1), nest2);
705 error:
706         isl_dim_free(left);
707         isl_dim_free(right);
708         return NULL;
709 }
710
711 struct isl_dim *isl_dim_map(struct isl_dim *dim)
712 {
713         struct isl_name **names = NULL;
714
715         if (!dim)
716                 return NULL;
717         isl_assert(dim->ctx, dim->n_in == 0, goto error);
718         if (dim->n_out == 0 && !isl_dim_is_named_or_nested(dim, isl_dim_out))
719                 return dim;
720         dim = isl_dim_cow(dim);
721         if (!dim)
722                 return NULL;
723         if (dim->names) {
724                 names = isl_calloc_array(dim->ctx, struct isl_name *,
725                                         dim->nparam + dim->n_out + dim->n_out);
726                 if (!names)
727                         goto error;
728                 get_names(dim, isl_dim_param, 0, dim->nparam, names);
729                 get_names(dim, isl_dim_out, 0, dim->n_out, names + dim->nparam);
730         }
731         dim->n_in = dim->n_out;
732         if (names) {
733                 free(dim->names);
734                 dim->names = names;
735                 dim->n_name = dim->nparam + dim->n_out + dim->n_out;
736                 dim = copy_names(dim, isl_dim_out, 0, dim, isl_dim_in);
737         }
738         isl_name_free(dim->ctx, dim->tuple_name[0]);
739         dim->tuple_name[0] = isl_name_copy(dim->ctx, dim->tuple_name[1]);
740         isl_dim_free(dim->nested[0]);
741         dim->nested[0] = isl_dim_copy(dim->nested[1]);
742         return dim;
743 error:
744         isl_dim_free(dim);
745         return NULL;
746 }
747
748 static struct isl_dim *set_names(struct isl_dim *dim, enum isl_dim_type type,
749         unsigned first, unsigned n, struct isl_name **names)
750 {
751         int i;
752
753         for (i = 0; i < n ; ++i)
754                 dim = set_name(dim, type, first+i, names[i]);
755
756         return dim;
757 }
758
759 struct isl_dim *isl_dim_reverse(struct isl_dim *dim)
760 {
761         unsigned t;
762         isl_dim *nested;
763         struct isl_name **names = NULL;
764         struct isl_name *name;
765
766         if (!dim)
767                 return NULL;
768         if (match(dim, isl_dim_in, dim, isl_dim_out))
769                 return dim;
770
771         dim = isl_dim_cow(dim);
772         if (!dim)
773                 return NULL;
774
775         name = dim->tuple_name[0];
776         dim->tuple_name[0] = dim->tuple_name[1];
777         dim->tuple_name[1] = name;
778
779         nested = dim->nested[0];
780         dim->nested[0] = dim->nested[1];
781         dim->nested[1] = nested;
782
783         if (dim->names) {
784                 names = isl_alloc_array(dim->ctx, struct isl_name *,
785                                         dim->n_in + dim->n_out);
786                 if (!names)
787                         goto error;
788                 get_names(dim, isl_dim_in, 0, dim->n_in, names);
789                 get_names(dim, isl_dim_out, 0, dim->n_out, names + dim->n_in);
790         }
791
792         t = dim->n_in;
793         dim->n_in = dim->n_out;
794         dim->n_out = t;
795
796         if (dim->names) {
797                 dim = set_names(dim, isl_dim_out, 0, dim->n_out, names);
798                 dim = set_names(dim, isl_dim_in, 0, dim->n_in, names + dim->n_out);
799                 free(names);
800         }
801
802         return dim;
803 error:
804         free(names);
805         isl_dim_free(dim);
806         return NULL;
807 }
808
809 struct isl_dim *isl_dim_drop(struct isl_dim *dim, enum isl_dim_type type,
810                 unsigned first, unsigned num)
811 {
812         int i;
813
814         if (!dim)
815                 return NULL;
816
817         if (n == 0)
818                 return isl_dim_reset(dim, type);
819
820         isl_assert(dim->ctx, first + num <= n(dim, type), goto error);
821         dim = isl_dim_cow(dim);
822         if (!dim)
823                 goto error;
824         if (dim->names) {
825                 dim = extend_names(dim);
826                 if (!dim)
827                         goto error;
828                 for (i = 0; i < num; ++i)
829                         isl_name_free(dim->ctx, get_name(dim, type, first+i));
830                 for (i = first+num; i < n(dim, type); ++i)
831                         set_name(dim, type, i - num, get_name(dim, type, i));
832                 switch (type) {
833                 case isl_dim_param:
834                         get_names(dim, isl_dim_in, 0, dim->n_in,
835                                 dim->names + offset(dim, isl_dim_in) - num);
836                 case isl_dim_in:
837                         get_names(dim, isl_dim_out, 0, dim->n_out,
838                                 dim->names + offset(dim, isl_dim_out) - num);
839                 case isl_dim_out:
840                         ;
841                 }
842                 dim->n_name -= num;
843         }
844         switch (type) {
845         case isl_dim_param:     dim->nparam -= num; break;
846         case isl_dim_in:        dim->n_in -= num; break;
847         case isl_dim_out:       dim->n_out -= num; break;
848         }
849         dim = isl_dim_reset(dim, type);
850         if (type == isl_dim_param) {
851                 if (dim && dim->nested[0] &&
852                     !(dim->nested[0] = isl_dim_drop(dim->nested[0],
853                                                     isl_dim_param, first, num)))
854                         goto error;
855                 if (dim && dim->nested[1] &&
856                     !(dim->nested[1] = isl_dim_drop(dim->nested[1],
857                                                     isl_dim_param, first, num)))
858                         goto error;
859         }
860         return dim;
861 error:
862         isl_dim_free(dim);
863         return NULL;
864 }
865
866 struct isl_dim *isl_dim_drop_inputs(struct isl_dim *dim,
867                 unsigned first, unsigned n)
868 {
869         if (!dim)
870                 return NULL;
871         return isl_dim_drop(dim, isl_dim_in, first, n);
872 }
873
874 struct isl_dim *isl_dim_drop_outputs(struct isl_dim *dim,
875                 unsigned first, unsigned n)
876 {
877         if (!dim)
878                 return NULL;
879         return isl_dim_drop(dim, isl_dim_out, first, n);
880 }
881
882 struct isl_dim *isl_dim_domain(struct isl_dim *dim)
883 {
884         if (!dim)
885                 return NULL;
886         dim = isl_dim_drop_outputs(dim, 0, dim->n_out);
887         return isl_dim_reverse(dim);
888 }
889
890 __isl_give isl_dim *isl_dim_from_domain(__isl_take isl_dim *dim)
891 {
892         return isl_dim_reverse(dim);
893 }
894
895 struct isl_dim *isl_dim_range(struct isl_dim *dim)
896 {
897         if (!dim)
898                 return NULL;
899         return isl_dim_drop_inputs(dim, 0, dim->n_in);
900 }
901
902 __isl_give isl_dim *isl_dim_from_range(__isl_take isl_dim *dim)
903 {
904         return dim;
905 }
906
907 __isl_give isl_dim *isl_dim_as_set_dim(__isl_take isl_dim *dim)
908 {
909         dim = isl_dim_cow(dim);
910         if (!dim)
911                 return NULL;
912
913         dim->n_out += dim->n_in;
914         dim->n_in = 0;
915         dim = isl_dim_reset(dim, isl_dim_in);
916         dim = isl_dim_reset(dim, isl_dim_out);
917
918         return dim;
919 }
920
921 struct isl_dim *isl_dim_underlying(struct isl_dim *dim, unsigned n_div)
922 {
923         int i;
924
925         if (!dim)
926                 return NULL;
927         if (n_div == 0 &&
928             dim->nparam == 0 && dim->n_in == 0 && dim->n_name == 0)
929                 return isl_dim_reset(isl_dim_reset(dim, isl_dim_in), isl_dim_out);
930         dim = isl_dim_cow(dim);
931         if (!dim)
932                 return NULL;
933         dim->n_out += dim->nparam + dim->n_in + n_div;
934         dim->nparam = 0;
935         dim->n_in = 0;
936
937         for (i = 0; i < dim->n_name; ++i)
938                 isl_name_free(dim->ctx, get_name(dim, isl_dim_out, i));
939         dim->n_name = 0;
940         dim = isl_dim_reset(dim, isl_dim_in);
941         dim = isl_dim_reset(dim, isl_dim_out);
942
943         return dim;
944 }
945
946 unsigned isl_dim_total(struct isl_dim *dim)
947 {
948         return dim->nparam + dim->n_in + dim->n_out;
949 }
950
951 int isl_dim_equal(struct isl_dim *dim1, struct isl_dim *dim2)
952 {
953         return match(dim1, isl_dim_param, dim2, isl_dim_param) &&
954                isl_dim_tuple_match(dim1, isl_dim_in, dim2, isl_dim_in) &&
955                isl_dim_tuple_match(dim1, isl_dim_out, dim2, isl_dim_out);
956 }
957
958 int isl_dim_compatible(struct isl_dim *dim1, struct isl_dim *dim2)
959 {
960         return dim1->nparam == dim2->nparam &&
961                dim1->n_in + dim1->n_out == dim2->n_in + dim2->n_out;
962 }
963
964 static uint32_t isl_hash_dim(uint32_t hash, __isl_keep isl_dim *dim)
965 {
966         int i;
967         struct isl_name *name;
968
969         if (!dim)
970                 return hash;
971
972         hash = isl_hash_builtin(hash, dim->nparam);
973         hash = isl_hash_builtin(hash, dim->n_in);
974         hash = isl_hash_builtin(hash, dim->n_out);
975
976         for (i = 0; i < dim->nparam; ++i) {
977                 name = get_name(dim, isl_dim_param, i);
978                 hash = isl_hash_builtin(hash, name);
979         }
980
981         name = tuple_name(dim, isl_dim_in);
982         hash = isl_hash_builtin(hash, name);
983         name = tuple_name(dim, isl_dim_out);
984         hash = isl_hash_builtin(hash, name);
985
986         hash = isl_hash_dim(hash, dim->nested[0]);
987         hash = isl_hash_dim(hash, dim->nested[1]);
988
989         return hash;
990 }
991
992 uint32_t isl_dim_get_hash(__isl_keep isl_dim *dim)
993 {
994         uint32_t hash;
995
996         if (!dim)
997                 return 0;
998
999         hash = isl_hash_init();
1000         hash = isl_hash_dim(hash, dim);
1001
1002         return hash;
1003 }
1004
1005 int isl_dim_is_wrapping(__isl_keep isl_dim *dim)
1006 {
1007         if (!dim)
1008                 return -1;
1009
1010         if (dim->n_in != 0 || dim->tuple_name[0] || dim->nested[0])
1011                 return 0;
1012
1013         return dim->nested[1] != NULL;
1014 }
1015
1016 __isl_give isl_dim *isl_dim_wrap(__isl_take isl_dim *dim)
1017 {
1018         isl_dim *wrap;
1019
1020         if (!dim)
1021                 return NULL;
1022
1023         wrap = isl_dim_alloc(dim->ctx, dim->nparam, 0, dim->n_in + dim->n_out);
1024
1025         wrap = copy_names(wrap, isl_dim_param, 0, dim, isl_dim_param);
1026         wrap = copy_names(wrap, isl_dim_set, 0, dim, isl_dim_in);
1027         wrap = copy_names(wrap, isl_dim_set, dim->n_in, dim, isl_dim_out);
1028
1029         if (!wrap)
1030                 goto error;
1031
1032         wrap->nested[1] = dim;
1033
1034         return wrap;
1035 error:
1036         isl_dim_free(dim);
1037         return NULL;
1038 }
1039
1040 __isl_give isl_dim *isl_dim_unwrap(__isl_take isl_dim *dim)
1041 {
1042         isl_dim *unwrap;
1043
1044         if (!dim)
1045                 return NULL;
1046
1047         if (!isl_dim_is_wrapping(dim))
1048                 isl_die(dim->ctx, isl_error_invalid, "not a wrapping dim",
1049                         goto error);
1050
1051         unwrap = isl_dim_copy(dim->nested[1]);
1052         isl_dim_free(dim);
1053
1054         return unwrap;
1055 error:
1056         isl_dim_free(dim);
1057         return NULL;
1058 }
1059
1060 int isl_dim_is_named_or_nested(__isl_keep isl_dim *dim, enum isl_dim_type type)
1061 {
1062         if (type != isl_dim_in && type != isl_dim_out)
1063                 return 0;
1064         if (!dim)
1065                 return -1;
1066         if (dim->tuple_name[type - isl_dim_in])
1067                 return 1;
1068         if (dim->nested[type - isl_dim_in])
1069                 return 1;
1070         return 0;
1071 }
1072
1073 __isl_give isl_dim *isl_dim_reset(__isl_take isl_dim *dim,
1074         enum isl_dim_type type)
1075 {
1076         if (!isl_dim_is_named_or_nested(dim, type))
1077                 return dim;
1078
1079         dim = isl_dim_cow(dim);
1080         if (!dim)
1081                 return NULL;
1082
1083         isl_name_free(dim->ctx, dim->tuple_name[type - isl_dim_in]);
1084         dim->tuple_name[type - isl_dim_in] = NULL;
1085         isl_dim_free(dim->nested[type - isl_dim_in]);
1086         dim->nested[type - isl_dim_in] = NULL;
1087
1088         return dim;
1089 }
1090
1091 __isl_give isl_dim *isl_dim_flatten(__isl_take isl_dim *dim)
1092 {
1093         if (!dim)
1094                 return NULL;
1095         if (!dim->nested[0] && !dim->nested[1])
1096                 return dim;
1097
1098         isl_dim_free(dim->nested[0]);
1099         dim->nested[0] = NULL;
1100         isl_dim_free(dim->nested[1]);
1101         dim->nested[1] = NULL;
1102
1103         return dim;
1104 }
1105
1106 /* Replace the dimensions of the given type of dst by those of src.
1107  */
1108 __isl_give isl_dim *isl_dim_replace(__isl_take isl_dim *dst,
1109         enum isl_dim_type type, __isl_keep isl_dim *src)
1110 {
1111         dst = isl_dim_cow(dst);
1112
1113         if (!dst || !src)
1114                 goto error;
1115
1116         if (type == isl_dim_param) {
1117                 int i;
1118                 for (i = 0; i <= 1; ++i) {
1119                         if (!dst->nested[i])
1120                                 continue;
1121                         dst->nested[i] = isl_dim_replace(dst->nested[i],
1122                                                          type, src);
1123                         if (!dst->nested[i])
1124                                 goto error;
1125                 }
1126         }
1127
1128         dst = isl_dim_drop(dst, type, 0, isl_dim_size(dst, type));
1129         dst = isl_dim_add(dst, type, isl_dim_size(src, type));
1130         dst = copy_names(dst, type, 0, src, type);
1131
1132         return dst;
1133 error:
1134         isl_dim_free(dst);
1135         return NULL;
1136 }