isl_dim_replace: recursively replace parameters in nested 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         isl_dim *dom1, *dom2, *nest1, *nest2;
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         dom1 = isl_dim_domain(isl_dim_copy(left));
695         dom2 = isl_dim_domain(isl_dim_copy(right));
696         nest1 = isl_dim_wrap(isl_dim_join(isl_dim_reverse(dom1), dom2));
697
698         dom1 = isl_dim_range(left);
699         dom2 = isl_dim_range(right);
700         nest2 = isl_dim_wrap(isl_dim_join(isl_dim_reverse(dom1), dom2));
701
702         return isl_dim_join(isl_dim_reverse(nest1), nest2);
703 error:
704         isl_dim_free(left);
705         isl_dim_free(right);
706         return NULL;
707 }
708
709 struct isl_dim *isl_dim_map(struct isl_dim *dim)
710 {
711         struct isl_name **names = NULL;
712
713         if (!dim)
714                 return NULL;
715         isl_assert(dim->ctx, dim->n_in == 0, goto error);
716         if (dim->n_out == 0 && !isl_dim_is_named_or_nested(dim, isl_dim_out))
717                 return dim;
718         dim = isl_dim_cow(dim);
719         if (!dim)
720                 return NULL;
721         if (dim->names) {
722                 names = isl_calloc_array(dim->ctx, struct isl_name *,
723                                         dim->nparam + dim->n_out + dim->n_out);
724                 if (!names)
725                         goto error;
726                 get_names(dim, isl_dim_param, 0, dim->nparam, names);
727                 get_names(dim, isl_dim_out, 0, dim->n_out, names + dim->nparam);
728         }
729         dim->n_in = dim->n_out;
730         if (names) {
731                 free(dim->names);
732                 dim->names = names;
733                 dim->n_name = dim->nparam + dim->n_out + dim->n_out;
734                 dim = copy_names(dim, isl_dim_out, 0, dim, isl_dim_in);
735         }
736         isl_name_free(dim->ctx, dim->tuple_name[0]);
737         dim->tuple_name[0] = isl_name_copy(dim->ctx, dim->tuple_name[1]);
738         isl_dim_free(dim->nested[0]);
739         dim->nested[0] = isl_dim_copy(dim->nested[1]);
740         return dim;
741 error:
742         isl_dim_free(dim);
743         return NULL;
744 }
745
746 static struct isl_dim *set_names(struct isl_dim *dim, enum isl_dim_type type,
747         unsigned first, unsigned n, struct isl_name **names)
748 {
749         int i;
750
751         for (i = 0; i < n ; ++i)
752                 dim = set_name(dim, type, first+i, names[i]);
753
754         return dim;
755 }
756
757 struct isl_dim *isl_dim_reverse(struct isl_dim *dim)
758 {
759         unsigned t;
760         isl_dim *nested;
761         struct isl_name **names = NULL;
762         struct isl_name *name;
763
764         if (!dim)
765                 return NULL;
766         if (match(dim, isl_dim_in, dim, isl_dim_out))
767                 return dim;
768
769         dim = isl_dim_cow(dim);
770         if (!dim)
771                 return NULL;
772
773         name = dim->tuple_name[0];
774         dim->tuple_name[0] = dim->tuple_name[1];
775         dim->tuple_name[1] = name;
776
777         nested = dim->nested[0];
778         dim->nested[0] = dim->nested[1];
779         dim->nested[1] = nested;
780
781         if (dim->names) {
782                 names = isl_alloc_array(dim->ctx, struct isl_name *,
783                                         dim->n_in + dim->n_out);
784                 if (!names)
785                         goto error;
786                 get_names(dim, isl_dim_in, 0, dim->n_in, names);
787                 get_names(dim, isl_dim_out, 0, dim->n_out, names + dim->n_in);
788         }
789
790         t = dim->n_in;
791         dim->n_in = dim->n_out;
792         dim->n_out = t;
793
794         if (dim->names) {
795                 dim = set_names(dim, isl_dim_out, 0, dim->n_out, names);
796                 dim = set_names(dim, isl_dim_in, 0, dim->n_in, names + dim->n_out);
797                 free(names);
798         }
799
800         return dim;
801 error:
802         free(names);
803         isl_dim_free(dim);
804         return NULL;
805 }
806
807 struct isl_dim *isl_dim_drop(struct isl_dim *dim, enum isl_dim_type type,
808                 unsigned first, unsigned num)
809 {
810         int i;
811
812         if (!dim)
813                 return NULL;
814
815         if (n == 0)
816                 return isl_dim_reset(dim, type);
817
818         isl_assert(dim->ctx, first + num <= n(dim, type), goto error);
819         dim = isl_dim_cow(dim);
820         if (!dim)
821                 goto error;
822         if (dim->names) {
823                 dim = extend_names(dim);
824                 if (!dim)
825                         goto error;
826                 for (i = 0; i < num; ++i)
827                         isl_name_free(dim->ctx, get_name(dim, type, first+i));
828                 for (i = first+num; i < n(dim, type); ++i)
829                         set_name(dim, type, i - num, get_name(dim, type, i));
830                 switch (type) {
831                 case isl_dim_param:
832                         get_names(dim, isl_dim_in, 0, dim->n_in,
833                                 dim->names + offset(dim, isl_dim_in) - num);
834                 case isl_dim_in:
835                         get_names(dim, isl_dim_out, 0, dim->n_out,
836                                 dim->names + offset(dim, isl_dim_out) - num);
837                 case isl_dim_out:
838                         ;
839                 }
840                 dim->n_name -= num;
841         }
842         switch (type) {
843         case isl_dim_param:     dim->nparam -= num; break;
844         case isl_dim_in:        dim->n_in -= num; break;
845         case isl_dim_out:       dim->n_out -= num; break;
846         }
847         dim = isl_dim_reset(dim, type);
848         return dim;
849 error:
850         isl_dim_free(dim);
851         return NULL;
852 }
853
854 struct isl_dim *isl_dim_drop_inputs(struct isl_dim *dim,
855                 unsigned first, unsigned n)
856 {
857         if (!dim)
858                 return NULL;
859         return isl_dim_drop(dim, isl_dim_in, first, n);
860 }
861
862 struct isl_dim *isl_dim_drop_outputs(struct isl_dim *dim,
863                 unsigned first, unsigned n)
864 {
865         if (!dim)
866                 return NULL;
867         return isl_dim_drop(dim, isl_dim_out, first, n);
868 }
869
870 struct isl_dim *isl_dim_domain(struct isl_dim *dim)
871 {
872         if (!dim)
873                 return NULL;
874         dim = isl_dim_drop_outputs(dim, 0, dim->n_out);
875         return isl_dim_reverse(dim);
876 }
877
878 struct isl_dim *isl_dim_range(struct isl_dim *dim)
879 {
880         if (!dim)
881                 return NULL;
882         return isl_dim_drop_inputs(dim, 0, dim->n_in);
883 }
884
885 __isl_give isl_dim *isl_dim_as_set_dim(__isl_take isl_dim *dim)
886 {
887         dim = isl_dim_cow(dim);
888         if (!dim)
889                 return NULL;
890
891         dim->n_out += dim->n_in;
892         dim->n_in = 0;
893         dim = isl_dim_reset(dim, isl_dim_in);
894         dim = isl_dim_reset(dim, isl_dim_out);
895
896         return dim;
897 }
898
899 struct isl_dim *isl_dim_underlying(struct isl_dim *dim, unsigned n_div)
900 {
901         int i;
902
903         if (!dim)
904                 return NULL;
905         if (n_div == 0 &&
906             dim->nparam == 0 && dim->n_in == 0 && dim->n_name == 0)
907                 return isl_dim_reset(isl_dim_reset(dim, isl_dim_in), isl_dim_out);
908         dim = isl_dim_cow(dim);
909         if (!dim)
910                 return NULL;
911         dim->n_out += dim->nparam + dim->n_in + n_div;
912         dim->nparam = 0;
913         dim->n_in = 0;
914
915         for (i = 0; i < dim->n_name; ++i)
916                 isl_name_free(dim->ctx, get_name(dim, isl_dim_out, i));
917         dim->n_name = 0;
918         dim = isl_dim_reset(dim, isl_dim_in);
919         dim = isl_dim_reset(dim, isl_dim_out);
920
921         return dim;
922 }
923
924 unsigned isl_dim_total(struct isl_dim *dim)
925 {
926         return dim->nparam + dim->n_in + dim->n_out;
927 }
928
929 int isl_dim_equal(struct isl_dim *dim1, struct isl_dim *dim2)
930 {
931         return match(dim1, isl_dim_param, dim2, isl_dim_param) &&
932                isl_dim_tuple_match(dim1, isl_dim_in, dim2, isl_dim_in) &&
933                isl_dim_tuple_match(dim1, isl_dim_out, dim2, isl_dim_out);
934 }
935
936 int isl_dim_compatible(struct isl_dim *dim1, struct isl_dim *dim2)
937 {
938         return dim1->nparam == dim2->nparam &&
939                dim1->n_in + dim1->n_out == dim2->n_in + dim2->n_out;
940 }
941
942 static uint32_t isl_hash_dim(uint32_t hash, __isl_keep isl_dim *dim)
943 {
944         int i;
945         struct isl_name *name;
946
947         if (!dim)
948                 return hash;
949
950         hash = isl_hash_builtin(hash, dim->nparam);
951         hash = isl_hash_builtin(hash, dim->n_in);
952         hash = isl_hash_builtin(hash, dim->n_out);
953
954         for (i = 0; i < dim->nparam; ++i) {
955                 name = get_name(dim, isl_dim_param, i);
956                 hash = isl_hash_builtin(hash, name);
957         }
958
959         name = tuple_name(dim, isl_dim_in);
960         hash = isl_hash_builtin(hash, name);
961         name = tuple_name(dim, isl_dim_out);
962         hash = isl_hash_builtin(hash, name);
963
964         hash = isl_hash_dim(hash, dim->nested[0]);
965         hash = isl_hash_dim(hash, dim->nested[1]);
966
967         return hash;
968 }
969
970 uint32_t isl_dim_get_hash(__isl_keep isl_dim *dim)
971 {
972         uint32_t hash;
973
974         if (!dim)
975                 return 0;
976
977         hash = isl_hash_init();
978         hash = isl_hash_dim(hash, dim);
979
980         return hash;
981 }
982
983 int isl_dim_is_wrapping(__isl_keep isl_dim *dim)
984 {
985         if (!dim)
986                 return -1;
987
988         if (dim->n_in != 0 || dim->tuple_name[0] || dim->nested[0])
989                 return 0;
990
991         return dim->nested[1] != NULL;
992 }
993
994 __isl_give isl_dim *isl_dim_wrap(__isl_take isl_dim *dim)
995 {
996         isl_dim *wrap;
997
998         if (!dim)
999                 return NULL;
1000
1001         wrap = isl_dim_alloc(dim->ctx, dim->nparam, 0, dim->n_in + dim->n_out);
1002
1003         wrap = copy_names(wrap, isl_dim_param, 0, dim, isl_dim_param);
1004         wrap = copy_names(wrap, isl_dim_set, 0, dim, isl_dim_in);
1005         wrap = copy_names(wrap, isl_dim_set, dim->n_in, dim, isl_dim_out);
1006
1007         if (!wrap)
1008                 goto error;
1009
1010         wrap->nested[1] = dim;
1011
1012         return wrap;
1013 error:
1014         isl_dim_free(dim);
1015         return NULL;
1016 }
1017
1018 __isl_give isl_dim *isl_dim_unwrap(__isl_take isl_dim *dim)
1019 {
1020         isl_dim *unwrap;
1021
1022         if (!dim)
1023                 return NULL;
1024
1025         if (!isl_dim_is_wrapping(dim))
1026                 isl_die(dim->ctx, isl_error_invalid, "not a wrapping dim",
1027                         goto error);
1028
1029         unwrap = isl_dim_copy(dim->nested[1]);
1030         isl_dim_free(dim);
1031
1032         return unwrap;
1033 error:
1034         isl_dim_free(dim);
1035         return NULL;
1036 }
1037
1038 int isl_dim_is_named_or_nested(__isl_keep isl_dim *dim, enum isl_dim_type type)
1039 {
1040         if (type != isl_dim_in && type != isl_dim_out)
1041                 return 0;
1042         if (!dim)
1043                 return -1;
1044         if (dim->tuple_name[type - isl_dim_in])
1045                 return 1;
1046         if (dim->nested[type - isl_dim_in])
1047                 return 1;
1048         return 0;
1049 }
1050
1051 __isl_give isl_dim *isl_dim_reset(__isl_take isl_dim *dim,
1052         enum isl_dim_type type)
1053 {
1054         if (!isl_dim_is_named_or_nested(dim, type))
1055                 return dim;
1056
1057         dim = isl_dim_cow(dim);
1058         if (!dim)
1059                 return NULL;
1060
1061         isl_name_free(dim->ctx, dim->tuple_name[type - isl_dim_in]);
1062         dim->tuple_name[type - isl_dim_in] = NULL;
1063         isl_dim_free(dim->nested[type - isl_dim_in]);
1064         dim->nested[type - isl_dim_in] = NULL;
1065
1066         return dim;
1067 }
1068
1069 __isl_give isl_dim *isl_dim_flatten(__isl_take isl_dim *dim)
1070 {
1071         if (!dim)
1072                 return NULL;
1073         if (!dim->nested[0] && !dim->nested[1])
1074                 return dim;
1075
1076         isl_dim_free(dim->nested[0]);
1077         dim->nested[0] = NULL;
1078         isl_dim_free(dim->nested[1]);
1079         dim->nested[1] = NULL;
1080
1081         return dim;
1082 }
1083
1084 /* Replace the dimensions of the given type of dst by those of src.
1085  */
1086 __isl_give isl_dim *isl_dim_replace(__isl_take isl_dim *dst,
1087         enum isl_dim_type type, __isl_keep isl_dim *src)
1088 {
1089         if (!dst || !src)
1090                 goto error;
1091
1092         if (type == isl_dim_param) {
1093                 int i;
1094                 for (i = 0; i <= 1; ++i) {
1095                         if (!dst->nested[i])
1096                                 continue;
1097                         dst->nested[i] = isl_dim_replace(dst->nested[i],
1098                                                          type, src);
1099                         if (!dst->nested[i])
1100                                 goto error;
1101                 }
1102         }
1103
1104         dst = isl_dim_drop(dst, type, 0, isl_dim_size(dst, type));
1105         dst = isl_dim_add(dst, type, isl_dim_size(src, type));
1106         dst = copy_names(dst, type, 0, src, type);
1107
1108         return dst;
1109 error:
1110         isl_dim_free(dst);
1111         return NULL;
1112 }