support nested isl_dims
[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 size[3];
524                 names = isl_calloc_array(dim->ctx, struct isl_name *,
525                                      dim->nparam + dim->n_in + dim->n_out + n);
526                 if (!names)
527                         goto error;
528                 off = 0;
529                 size[isl_dim_param] = dim->nparam;
530                 size[isl_dim_in] = dim->n_in;
531                 size[isl_dim_out] = dim->n_out;
532                 for (t = isl_dim_param; t <= isl_dim_out; ++t) {
533                         if (t != type) {
534                                 get_names(dim, t, 0, size[t], names + off);
535                                 off += size[t];
536                         } else {
537                                 get_names(dim, t, 0, pos, names + off);
538                                 off += pos + n;
539                                 get_names(dim, t, pos, size[t]-pos, names+off);
540                                 off += size[t] - pos;
541                         }
542                 }
543                 free(dim->names);
544                 dim->names = names;
545                 dim->n_name = dim->nparam + dim->n_in + dim->n_out + n;
546         }
547         switch (type) {
548         case isl_dim_param:     dim->nparam += n; break;
549         case isl_dim_in:        dim->n_in += n; break;
550         case isl_dim_out:       dim->n_out += n; break;
551         }
552         dim = isl_dim_reset(dim, type);
553
554         return dim;
555 error:
556         isl_dim_free(dim);
557         return NULL;
558 }
559
560 __isl_give isl_dim *isl_dim_move(__isl_take isl_dim *dim,
561         enum isl_dim_type dst_type, unsigned dst_pos,
562         enum isl_dim_type src_type, unsigned src_pos, unsigned n)
563 {
564         if (!dim)
565                 return NULL;
566         if (n == 0)
567                 return dim;
568
569         isl_assert(dim->ctx, src_pos + n <= isl_dim_size(dim, src_type),
570                 goto error);
571
572         if (dst_type == src_type && dst_pos == src_pos)
573                 return dim;
574
575         isl_assert(dim->ctx, dst_type != src_type, goto error);
576
577         dim = isl_dim_reset(dim, src_type);
578         dim = isl_dim_reset(dim, dst_type);
579
580         dim = isl_dim_cow(dim);
581         if (!dim)
582                 return NULL;
583
584         if (dim->names) {
585                 struct isl_name **names;
586                 enum isl_dim_type t;
587                 int off;
588                 int size[3];
589                 names = isl_calloc_array(dim->ctx, struct isl_name *,
590                                          dim->nparam + dim->n_in + dim->n_out);
591                 if (!names)
592                         goto error;
593                 off = 0;
594                 size[isl_dim_param] = dim->nparam;
595                 size[isl_dim_in] = dim->n_in;
596                 size[isl_dim_out] = dim->n_out;
597                 for (t = isl_dim_param; t <= isl_dim_out; ++t) {
598                         if (t == dst_type) {
599                                 get_names(dim, t, 0, dst_pos, names + off);
600                                 off += dst_pos;
601                                 get_names(dim, src_type, src_pos, n, names+off);
602                                 off += n;
603                                 get_names(dim, t, dst_pos, size[t] - dst_pos,
604                                                 names + off);
605                                 off += size[t] - dst_pos;
606                         } else if (t == src_type) {
607                                 get_names(dim, t, 0, src_pos, names + off);
608                                 off += src_pos;
609                                 get_names(dim, t, src_pos + n,
610                                             size[t] - src_pos - n, names + off);
611                                 off += size[t] - src_pos - n;
612                         } else {
613                                 get_names(dim, t, 0, size[t], names + off);
614                                 off += size[t];
615                         }
616                 }
617                 free(dim->names);
618                 dim->names = names;
619                 dim->n_name = dim->nparam + dim->n_in + dim->n_out;
620         }
621
622         switch (dst_type) {
623         case isl_dim_param:     dim->nparam += n; break;
624         case isl_dim_in:        dim->n_in += n; break;
625         case isl_dim_out:       dim->n_out += n; break;
626         }
627
628         switch (src_type) {
629         case isl_dim_param:     dim->nparam -= n; break;
630         case isl_dim_in:        dim->n_in -= n; break;
631         case isl_dim_out:       dim->n_out -= n; break;
632         }
633
634         return dim;
635 error:
636         isl_dim_free(dim);
637         return NULL;
638 }
639
640 struct isl_dim *isl_dim_join(struct isl_dim *left, struct isl_dim *right)
641 {
642         struct isl_dim *dim;
643
644         if (!left || !right)
645                 goto error;
646
647         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
648                         goto error);
649         isl_assert(left->ctx,
650                 isl_dim_tuple_match(left, isl_dim_out, right, isl_dim_in),
651                 goto error);
652
653         dim = isl_dim_alloc(left->ctx, left->nparam, left->n_in, right->n_out);
654         if (!dim)
655                 goto error;
656
657         dim = copy_names(dim, isl_dim_param, 0, left, isl_dim_param);
658         dim = copy_names(dim, isl_dim_in, 0, left, isl_dim_in);
659         dim = copy_names(dim, isl_dim_out, 0, right, isl_dim_out);
660
661         if (dim && left->tuple_name[0] &&
662             !(dim->tuple_name[0] = isl_name_copy(dim->ctx, left->tuple_name[0])))
663                 goto error;
664         if (dim && right->tuple_name[1] &&
665             !(dim->tuple_name[1] = isl_name_copy(dim->ctx, right->tuple_name[1])))
666                 goto error;
667         if (dim && left->nested[0] &&
668             !(dim->nested[0] = isl_dim_copy(left->nested[0])))
669                 goto error;
670         if (dim && right->nested[1] &&
671             !(dim->nested[1] = isl_dim_copy(right->nested[1])))
672                 goto error;
673
674         isl_dim_free(left);
675         isl_dim_free(right);
676
677         return dim;
678 error:
679         isl_dim_free(left);
680         isl_dim_free(right);
681         return NULL;
682 }
683
684 struct isl_dim *isl_dim_product(struct isl_dim *left, struct isl_dim *right)
685 {
686         struct isl_dim *dim;
687
688         if (!left || !right)
689                 goto error;
690
691         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
692                         goto error);
693
694         dim = isl_dim_alloc(left->ctx, left->nparam,
695                         left->n_in + right->n_in, left->n_out + right->n_out);
696         if (!dim)
697                 goto error;
698
699         dim = copy_names(dim, isl_dim_param, 0, left, isl_dim_param);
700         dim = copy_names(dim, isl_dim_in, 0, left, isl_dim_in);
701         dim = copy_names(dim, isl_dim_in, left->n_in, right, isl_dim_in);
702         dim = copy_names(dim, isl_dim_out, 0, left, isl_dim_out);
703         dim = copy_names(dim, isl_dim_out, left->n_out, right, isl_dim_out);
704
705         isl_dim_free(left);
706         isl_dim_free(right);
707
708         return dim;
709 error:
710         isl_dim_free(left);
711         isl_dim_free(right);
712         return NULL;
713 }
714
715 struct isl_dim *isl_dim_map(struct isl_dim *dim)
716 {
717         struct isl_name **names = NULL;
718
719         if (!dim)
720                 return NULL;
721         isl_assert(dim->ctx, dim->n_in == 0, goto error);
722         if (dim->n_out == 0 && !isl_dim_is_named_or_nested(dim, isl_dim_out))
723                 return dim;
724         dim = isl_dim_cow(dim);
725         if (!dim)
726                 return NULL;
727         if (dim->names) {
728                 names = isl_calloc_array(dim->ctx, struct isl_name *,
729                                         dim->nparam + dim->n_out + dim->n_out);
730                 if (!names)
731                         goto error;
732                 get_names(dim, isl_dim_param, 0, dim->nparam, names);
733                 get_names(dim, isl_dim_out, 0, dim->n_out, names + dim->nparam);
734         }
735         dim->n_in = dim->n_out;
736         if (names) {
737                 free(dim->names);
738                 dim->names = names;
739                 dim->n_name = dim->nparam + dim->n_out + dim->n_out;
740                 dim = copy_names(dim, isl_dim_out, 0, dim, isl_dim_in);
741         }
742         isl_name_free(dim->ctx, dim->tuple_name[0]);
743         dim->tuple_name[0] = isl_name_copy(dim->ctx, dim->tuple_name[1]);
744         isl_dim_free(dim->nested[0]);
745         dim->nested[0] = isl_dim_copy(dim->nested[1]);
746         return dim;
747 error:
748         isl_dim_free(dim);
749         return NULL;
750 }
751
752 static struct isl_dim *set_names(struct isl_dim *dim, enum isl_dim_type type,
753         unsigned first, unsigned n, struct isl_name **names)
754 {
755         int i;
756
757         for (i = 0; i < n ; ++i)
758                 dim = set_name(dim, type, first+i, names[i]);
759
760         return dim;
761 }
762
763 struct isl_dim *isl_dim_reverse(struct isl_dim *dim)
764 {
765         unsigned t;
766         isl_dim *nested;
767         struct isl_name **names = NULL;
768         struct isl_name *name;
769
770         if (!dim)
771                 return NULL;
772         if (match(dim, isl_dim_in, dim, isl_dim_out))
773                 return dim;
774
775         dim = isl_dim_cow(dim);
776         if (!dim)
777                 return NULL;
778
779         name = dim->tuple_name[0];
780         dim->tuple_name[0] = dim->tuple_name[1];
781         dim->tuple_name[1] = name;
782
783         nested = dim->nested[0];
784         dim->nested[0] = dim->nested[1];
785         dim->nested[1] = nested;
786
787         if (dim->names) {
788                 names = isl_alloc_array(dim->ctx, struct isl_name *,
789                                         dim->n_in + dim->n_out);
790                 if (!names)
791                         goto error;
792                 get_names(dim, isl_dim_in, 0, dim->n_in, names);
793                 get_names(dim, isl_dim_out, 0, dim->n_out, names + dim->n_in);
794         }
795
796         t = dim->n_in;
797         dim->n_in = dim->n_out;
798         dim->n_out = t;
799
800         if (dim->names) {
801                 dim = set_names(dim, isl_dim_out, 0, dim->n_out, names);
802                 dim = set_names(dim, isl_dim_in, 0, dim->n_in, names + dim->n_out);
803                 free(names);
804         }
805
806         return dim;
807 error:
808         free(names);
809         isl_dim_free(dim);
810         return NULL;
811 }
812
813 struct isl_dim *isl_dim_drop(struct isl_dim *dim, enum isl_dim_type type,
814                 unsigned first, unsigned num)
815 {
816         int i;
817
818         if (!dim)
819                 return NULL;
820
821         if (n == 0)
822                 return isl_dim_reset(dim, type);
823
824         isl_assert(dim->ctx, first + num <= n(dim, type), goto error);
825         dim = isl_dim_cow(dim);
826         if (!dim)
827                 goto error;
828         if (dim->names) {
829                 dim = extend_names(dim);
830                 if (!dim)
831                         goto error;
832                 for (i = 0; i < num; ++i)
833                         isl_name_free(dim->ctx, get_name(dim, type, first+i));
834                 for (i = first+num; i < n(dim, type); ++i)
835                         set_name(dim, type, i - num, get_name(dim, type, i));
836                 switch (type) {
837                 case isl_dim_param:
838                         get_names(dim, isl_dim_in, 0, dim->n_in,
839                                 dim->names + offset(dim, isl_dim_in) - num);
840                 case isl_dim_in:
841                         get_names(dim, isl_dim_out, 0, dim->n_out,
842                                 dim->names + offset(dim, isl_dim_out) - num);
843                 case isl_dim_out:
844                         ;
845                 }
846                 dim->n_name -= num;
847         }
848         switch (type) {
849         case isl_dim_param:     dim->nparam -= num; break;
850         case isl_dim_in:        dim->n_in -= num; break;
851         case isl_dim_out:       dim->n_out -= num; break;
852         }
853         dim = isl_dim_reset(dim, type);
854         return dim;
855 error:
856         isl_dim_free(dim);
857         return NULL;
858 }
859
860 struct isl_dim *isl_dim_drop_inputs(struct isl_dim *dim,
861                 unsigned first, unsigned n)
862 {
863         if (!dim)
864                 return NULL;
865         return isl_dim_drop(dim, isl_dim_in, first, n);
866 }
867
868 struct isl_dim *isl_dim_drop_outputs(struct isl_dim *dim,
869                 unsigned first, unsigned n)
870 {
871         if (!dim)
872                 return NULL;
873         return isl_dim_drop(dim, isl_dim_out, first, n);
874 }
875
876 struct isl_dim *isl_dim_domain(struct isl_dim *dim)
877 {
878         if (!dim)
879                 return NULL;
880         dim = isl_dim_drop_outputs(dim, 0, dim->n_out);
881         return isl_dim_reverse(dim);
882 }
883
884 struct isl_dim *isl_dim_range(struct isl_dim *dim)
885 {
886         if (!dim)
887                 return NULL;
888         return isl_dim_drop_inputs(dim, 0, dim->n_in);
889 }
890
891 __isl_give isl_dim *isl_dim_as_set_dim(__isl_take isl_dim *dim)
892 {
893         dim = isl_dim_cow(dim);
894         if (!dim)
895                 return NULL;
896
897         dim->n_out += dim->n_in;
898         dim->n_in = 0;
899         dim = isl_dim_reset(dim, isl_dim_in);
900         dim = isl_dim_reset(dim, isl_dim_out);
901
902         return dim;
903 }
904
905 struct isl_dim *isl_dim_underlying(struct isl_dim *dim, unsigned n_div)
906 {
907         int i;
908
909         if (!dim)
910                 return NULL;
911         if (n_div == 0 &&
912             dim->nparam == 0 && dim->n_in == 0 && dim->n_name == 0)
913                 return isl_dim_reset(isl_dim_reset(dim, isl_dim_in), isl_dim_out);
914         dim = isl_dim_cow(dim);
915         if (!dim)
916                 return NULL;
917         dim->n_out += dim->nparam + dim->n_in + n_div;
918         dim->nparam = 0;
919         dim->n_in = 0;
920
921         for (i = 0; i < dim->n_name; ++i)
922                 isl_name_free(dim->ctx, get_name(dim, isl_dim_out, i));
923         dim->n_name = 0;
924         dim = isl_dim_reset(dim, isl_dim_in);
925         dim = isl_dim_reset(dim, isl_dim_out);
926
927         return dim;
928 }
929
930 unsigned isl_dim_total(struct isl_dim *dim)
931 {
932         return dim->nparam + dim->n_in + dim->n_out;
933 }
934
935 int isl_dim_equal(struct isl_dim *dim1, struct isl_dim *dim2)
936 {
937         return match(dim1, isl_dim_param, dim2, isl_dim_param) &&
938                isl_dim_tuple_match(dim1, isl_dim_in, dim2, isl_dim_in) &&
939                isl_dim_tuple_match(dim1, isl_dim_out, dim2, isl_dim_out);
940 }
941
942 int isl_dim_compatible(struct isl_dim *dim1, struct isl_dim *dim2)
943 {
944         return dim1->nparam == dim2->nparam &&
945                dim1->n_in + dim1->n_out == dim2->n_in + dim2->n_out;
946 }
947
948 static uint32_t isl_hash_dim(uint32_t hash, __isl_keep isl_dim *dim)
949 {
950         int i;
951         struct isl_name *name;
952
953         if (!dim)
954                 return hash;
955
956         hash = isl_hash_builtin(hash, dim->nparam);
957         hash = isl_hash_builtin(hash, dim->n_in);
958         hash = isl_hash_builtin(hash, dim->n_out);
959
960         for (i = 0; i < dim->nparam; ++i) {
961                 name = get_name(dim, isl_dim_param, i);
962                 hash = isl_hash_builtin(hash, name);
963         }
964
965         name = tuple_name(dim, isl_dim_in);
966         hash = isl_hash_builtin(hash, name);
967         name = tuple_name(dim, isl_dim_out);
968         hash = isl_hash_builtin(hash, name);
969
970         hash = isl_hash_dim(hash, dim->nested[0]);
971         hash = isl_hash_dim(hash, dim->nested[1]);
972
973         return hash;
974 }
975
976 uint32_t isl_dim_get_hash(__isl_keep isl_dim *dim)
977 {
978         uint32_t hash;
979
980         if (!dim)
981                 return 0;
982
983         hash = isl_hash_init();
984         hash = isl_hash_dim(hash, dim);
985
986         return hash;
987 }
988
989 int isl_dim_is_wrapping(__isl_keep isl_dim *dim)
990 {
991         if (!dim)
992                 return -1;
993
994         if (dim->n_in != 0 || dim->tuple_name[0] || dim->nested[0])
995                 return 0;
996
997         return dim->nested[1] != NULL;
998 }
999
1000 __isl_give isl_dim *isl_dim_wrap(__isl_take isl_dim *dim)
1001 {
1002         isl_dim *wrap;
1003
1004         if (!dim)
1005                 return NULL;
1006
1007         wrap = isl_dim_alloc(dim->ctx, dim->nparam, 0, dim->n_in + dim->n_out);
1008
1009         wrap = copy_names(wrap, isl_dim_param, 0, dim, isl_dim_param);
1010         wrap = copy_names(wrap, isl_dim_set, 0, dim, isl_dim_in);
1011         wrap = copy_names(wrap, isl_dim_set, dim->n_in, dim, isl_dim_out);
1012
1013         if (!wrap)
1014                 goto error;
1015
1016         wrap->nested[1] = dim;
1017
1018         return wrap;
1019 error:
1020         isl_dim_free(dim);
1021         return NULL;
1022 }
1023
1024 __isl_give isl_dim *isl_dim_unwrap(__isl_take isl_dim *dim)
1025 {
1026         isl_dim *unwrap;
1027
1028         if (!dim)
1029                 return NULL;
1030
1031         if (!isl_dim_is_wrapping(dim))
1032                 isl_die(dim->ctx, isl_error_invalid, "not a wrapping dim",
1033                         goto error);
1034
1035         unwrap = isl_dim_copy(dim->nested[1]);
1036         isl_dim_free(dim);
1037
1038         return unwrap;
1039 error:
1040         isl_dim_free(dim);
1041         return NULL;
1042 }
1043
1044 int isl_dim_is_named_or_nested(__isl_keep isl_dim *dim, enum isl_dim_type type)
1045 {
1046         if (type != isl_dim_in && type != isl_dim_out)
1047                 return 0;
1048         if (!dim)
1049                 return -1;
1050         if (dim->tuple_name[type - isl_dim_in])
1051                 return 1;
1052         if (dim->nested[type - isl_dim_in])
1053                 return 1;
1054         return 0;
1055 }
1056
1057 __isl_give isl_dim *isl_dim_reset(__isl_take isl_dim *dim,
1058         enum isl_dim_type type)
1059 {
1060         if (!isl_dim_is_named_or_nested(dim, type))
1061                 return dim;
1062
1063         dim = isl_dim_cow(dim);
1064         if (!dim)
1065                 return NULL;
1066
1067         isl_name_free(dim->ctx, dim->tuple_name[type - isl_dim_in]);
1068         dim->tuple_name[type - isl_dim_in] = NULL;
1069         isl_dim_free(dim->nested[type - isl_dim_in]);
1070         dim->nested[type - isl_dim_in] = NULL;
1071
1072         return dim;
1073 }