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