2002fb668902c7aa3020c44293cc63059c708a15
[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         return dim;
851 error:
852         isl_dim_free(dim);
853         return NULL;
854 }
855
856 struct isl_dim *isl_dim_drop_inputs(struct isl_dim *dim,
857                 unsigned first, unsigned n)
858 {
859         if (!dim)
860                 return NULL;
861         return isl_dim_drop(dim, isl_dim_in, first, n);
862 }
863
864 struct isl_dim *isl_dim_drop_outputs(struct isl_dim *dim,
865                 unsigned first, unsigned n)
866 {
867         if (!dim)
868                 return NULL;
869         return isl_dim_drop(dim, isl_dim_out, first, n);
870 }
871
872 struct isl_dim *isl_dim_domain(struct isl_dim *dim)
873 {
874         if (!dim)
875                 return NULL;
876         dim = isl_dim_drop_outputs(dim, 0, dim->n_out);
877         return isl_dim_reverse(dim);
878 }
879
880 __isl_give isl_dim *isl_dim_from_domain(__isl_take isl_dim *dim)
881 {
882         return isl_dim_reverse(dim);
883 }
884
885 struct isl_dim *isl_dim_range(struct isl_dim *dim)
886 {
887         if (!dim)
888                 return NULL;
889         return isl_dim_drop_inputs(dim, 0, dim->n_in);
890 }
891
892 __isl_give isl_dim *isl_dim_from_range(__isl_take isl_dim *dim)
893 {
894         return dim;
895 }
896
897 __isl_give isl_dim *isl_dim_as_set_dim(__isl_take isl_dim *dim)
898 {
899         dim = isl_dim_cow(dim);
900         if (!dim)
901                 return NULL;
902
903         dim->n_out += dim->n_in;
904         dim->n_in = 0;
905         dim = isl_dim_reset(dim, isl_dim_in);
906         dim = isl_dim_reset(dim, isl_dim_out);
907
908         return dim;
909 }
910
911 struct isl_dim *isl_dim_underlying(struct isl_dim *dim, unsigned n_div)
912 {
913         int i;
914
915         if (!dim)
916                 return NULL;
917         if (n_div == 0 &&
918             dim->nparam == 0 && dim->n_in == 0 && dim->n_name == 0)
919                 return isl_dim_reset(isl_dim_reset(dim, isl_dim_in), isl_dim_out);
920         dim = isl_dim_cow(dim);
921         if (!dim)
922                 return NULL;
923         dim->n_out += dim->nparam + dim->n_in + n_div;
924         dim->nparam = 0;
925         dim->n_in = 0;
926
927         for (i = 0; i < dim->n_name; ++i)
928                 isl_name_free(dim->ctx, get_name(dim, isl_dim_out, i));
929         dim->n_name = 0;
930         dim = isl_dim_reset(dim, isl_dim_in);
931         dim = isl_dim_reset(dim, isl_dim_out);
932
933         return dim;
934 }
935
936 unsigned isl_dim_total(struct isl_dim *dim)
937 {
938         return dim->nparam + dim->n_in + dim->n_out;
939 }
940
941 int isl_dim_equal(struct isl_dim *dim1, struct isl_dim *dim2)
942 {
943         return match(dim1, isl_dim_param, dim2, isl_dim_param) &&
944                isl_dim_tuple_match(dim1, isl_dim_in, dim2, isl_dim_in) &&
945                isl_dim_tuple_match(dim1, isl_dim_out, dim2, isl_dim_out);
946 }
947
948 int isl_dim_compatible(struct isl_dim *dim1, struct isl_dim *dim2)
949 {
950         return dim1->nparam == dim2->nparam &&
951                dim1->n_in + dim1->n_out == dim2->n_in + dim2->n_out;
952 }
953
954 static uint32_t isl_hash_dim(uint32_t hash, __isl_keep isl_dim *dim)
955 {
956         int i;
957         struct isl_name *name;
958
959         if (!dim)
960                 return hash;
961
962         hash = isl_hash_builtin(hash, dim->nparam);
963         hash = isl_hash_builtin(hash, dim->n_in);
964         hash = isl_hash_builtin(hash, dim->n_out);
965
966         for (i = 0; i < dim->nparam; ++i) {
967                 name = get_name(dim, isl_dim_param, i);
968                 hash = isl_hash_builtin(hash, name);
969         }
970
971         name = tuple_name(dim, isl_dim_in);
972         hash = isl_hash_builtin(hash, name);
973         name = tuple_name(dim, isl_dim_out);
974         hash = isl_hash_builtin(hash, name);
975
976         hash = isl_hash_dim(hash, dim->nested[0]);
977         hash = isl_hash_dim(hash, dim->nested[1]);
978
979         return hash;
980 }
981
982 uint32_t isl_dim_get_hash(__isl_keep isl_dim *dim)
983 {
984         uint32_t hash;
985
986         if (!dim)
987                 return 0;
988
989         hash = isl_hash_init();
990         hash = isl_hash_dim(hash, dim);
991
992         return hash;
993 }
994
995 int isl_dim_is_wrapping(__isl_keep isl_dim *dim)
996 {
997         if (!dim)
998                 return -1;
999
1000         if (dim->n_in != 0 || dim->tuple_name[0] || dim->nested[0])
1001                 return 0;
1002
1003         return dim->nested[1] != NULL;
1004 }
1005
1006 __isl_give isl_dim *isl_dim_wrap(__isl_take isl_dim *dim)
1007 {
1008         isl_dim *wrap;
1009
1010         if (!dim)
1011                 return NULL;
1012
1013         wrap = isl_dim_alloc(dim->ctx, dim->nparam, 0, dim->n_in + dim->n_out);
1014
1015         wrap = copy_names(wrap, isl_dim_param, 0, dim, isl_dim_param);
1016         wrap = copy_names(wrap, isl_dim_set, 0, dim, isl_dim_in);
1017         wrap = copy_names(wrap, isl_dim_set, dim->n_in, dim, isl_dim_out);
1018
1019         if (!wrap)
1020                 goto error;
1021
1022         wrap->nested[1] = dim;
1023
1024         return wrap;
1025 error:
1026         isl_dim_free(dim);
1027         return NULL;
1028 }
1029
1030 __isl_give isl_dim *isl_dim_unwrap(__isl_take isl_dim *dim)
1031 {
1032         isl_dim *unwrap;
1033
1034         if (!dim)
1035                 return NULL;
1036
1037         if (!isl_dim_is_wrapping(dim))
1038                 isl_die(dim->ctx, isl_error_invalid, "not a wrapping dim",
1039                         goto error);
1040
1041         unwrap = isl_dim_copy(dim->nested[1]);
1042         isl_dim_free(dim);
1043
1044         return unwrap;
1045 error:
1046         isl_dim_free(dim);
1047         return NULL;
1048 }
1049
1050 int isl_dim_is_named_or_nested(__isl_keep isl_dim *dim, enum isl_dim_type type)
1051 {
1052         if (type != isl_dim_in && type != isl_dim_out)
1053                 return 0;
1054         if (!dim)
1055                 return -1;
1056         if (dim->tuple_name[type - isl_dim_in])
1057                 return 1;
1058         if (dim->nested[type - isl_dim_in])
1059                 return 1;
1060         return 0;
1061 }
1062
1063 __isl_give isl_dim *isl_dim_reset(__isl_take isl_dim *dim,
1064         enum isl_dim_type type)
1065 {
1066         if (!isl_dim_is_named_or_nested(dim, type))
1067                 return dim;
1068
1069         dim = isl_dim_cow(dim);
1070         if (!dim)
1071                 return NULL;
1072
1073         isl_name_free(dim->ctx, dim->tuple_name[type - isl_dim_in]);
1074         dim->tuple_name[type - isl_dim_in] = NULL;
1075         isl_dim_free(dim->nested[type - isl_dim_in]);
1076         dim->nested[type - isl_dim_in] = NULL;
1077
1078         return dim;
1079 }
1080
1081 __isl_give isl_dim *isl_dim_flatten(__isl_take isl_dim *dim)
1082 {
1083         if (!dim)
1084                 return NULL;
1085         if (!dim->nested[0] && !dim->nested[1])
1086                 return dim;
1087
1088         isl_dim_free(dim->nested[0]);
1089         dim->nested[0] = NULL;
1090         isl_dim_free(dim->nested[1]);
1091         dim->nested[1] = NULL;
1092
1093         return dim;
1094 }
1095
1096 /* Replace the dimensions of the given type of dst by those of src.
1097  */
1098 __isl_give isl_dim *isl_dim_replace(__isl_take isl_dim *dst,
1099         enum isl_dim_type type, __isl_keep isl_dim *src)
1100 {
1101         if (!dst || !src)
1102                 goto error;
1103
1104         if (type == isl_dim_param) {
1105                 int i;
1106                 for (i = 0; i <= 1; ++i) {
1107                         if (!dst->nested[i])
1108                                 continue;
1109                         dst->nested[i] = isl_dim_replace(dst->nested[i],
1110                                                          type, src);
1111                         if (!dst->nested[i])
1112                                 goto error;
1113                 }
1114         }
1115
1116         dst = isl_dim_drop(dst, type, 0, isl_dim_size(dst, type));
1117         dst = isl_dim_add(dst, type, isl_dim_size(src, type));
1118         dst = copy_names(dst, type, 0, src, type);
1119
1120         return dst;
1121 error:
1122         isl_dim_free(dst);
1123         return NULL;
1124 }