b469808a9e95b6d5d8ccace71fb644a2188b9d9b
[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_id_private.h>
16 #include <isl_reordering.h>
17
18 isl_ctx *isl_dim_get_ctx(__isl_keep isl_dim *dim)
19 {
20         return dim ? dim->ctx : NULL;
21 }
22
23 struct isl_dim *isl_dim_alloc(struct isl_ctx *ctx,
24                         unsigned nparam, unsigned n_in, unsigned n_out)
25 {
26         struct isl_dim *dim;
27
28         dim = isl_alloc_type(ctx, struct isl_dim);
29         if (!dim)
30                 return NULL;
31
32         dim->ctx = ctx;
33         isl_ctx_ref(ctx);
34         dim->ref = 1;
35         dim->nparam = nparam;
36         dim->n_in = n_in;
37         dim->n_out = n_out;
38
39         dim->tuple_id[0] = NULL;
40         dim->tuple_id[1] = NULL;
41
42         dim->nested[0] = NULL;
43         dim->nested[1] = NULL;
44
45         dim->n_id = 0;
46         dim->ids = NULL;
47
48         return dim;
49 }
50
51 struct isl_dim *isl_dim_set_alloc(struct isl_ctx *ctx,
52                         unsigned nparam, unsigned dim)
53 {
54         return isl_dim_alloc(ctx, nparam, 0, dim);
55 }
56
57 static unsigned global_pos(struct isl_dim *dim,
58                                  enum isl_dim_type type, unsigned pos)
59 {
60         struct isl_ctx *ctx = dim->ctx;
61
62         switch (type) {
63         case isl_dim_param:
64                 isl_assert(ctx, pos < dim->nparam, return isl_dim_total(dim));
65                 return pos;
66         case isl_dim_in:
67                 isl_assert(ctx, pos < dim->n_in, return isl_dim_total(dim));
68                 return pos + dim->nparam;
69         case isl_dim_out:
70                 isl_assert(ctx, pos < dim->n_out, return isl_dim_total(dim));
71                 return pos + dim->nparam + dim->n_in;
72         default:
73                 isl_assert(ctx, 0, return isl_dim_total(dim));
74         }
75         return isl_dim_total(dim);
76 }
77
78 /* Extend length of ids array to the total number of dimensions.
79  */
80 static __isl_give isl_dim *extend_ids(__isl_take isl_dim *dim)
81 {
82         isl_id **ids;
83         int i;
84
85         if (isl_dim_total(dim) <= dim->n_id)
86                 return dim;
87
88         if (!dim->ids) {
89                 dim->ids = isl_calloc_array(dim->ctx,
90                                 isl_id *, isl_dim_total(dim));
91                 if (!dim->ids)
92                         goto error;
93         } else {
94                 ids = isl_realloc_array(dim->ctx, dim->ids,
95                                 isl_id *, isl_dim_total(dim));
96                 if (!ids)
97                         goto error;
98                 dim->ids = ids;
99                 for (i = dim->n_id; i < isl_dim_total(dim); ++i)
100                         dim->ids[i] = NULL;
101         }
102
103         dim->n_id = isl_dim_total(dim);
104
105         return dim;
106 error:
107         isl_dim_free(dim);
108         return NULL;
109 }
110
111 static __isl_give isl_dim *set_id(__isl_take isl_dim *dim,
112         enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
113 {
114         dim = isl_dim_cow(dim);
115
116         if (!dim)
117                 goto error;
118
119         pos = global_pos(dim, type, pos);
120         if (pos == isl_dim_total(dim))
121                 goto error;
122
123         if (pos >= dim->n_id) {
124                 if (!id)
125                         return dim;
126                 dim = extend_ids(dim);
127                 if (!dim)
128                         goto error;
129         }
130
131         dim->ids[pos] = id;
132
133         return dim;
134 error:
135         isl_id_free(id);
136         isl_dim_free(dim);
137         return NULL;
138 }
139
140 static __isl_keep isl_id *get_id(__isl_keep 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_id)
150                 return NULL;
151         return dim->ids[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         case isl_dim_all:       return dim->nparam + dim->n_in + 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 __isl_give isl_dim *copy_ids(__isl_take isl_dim *dst,
190         enum isl_dim_type dst_type, unsigned offset, __isl_keep isl_dim *src,
191         enum isl_dim_type src_type)
192 {
193         int i;
194         isl_id *id;
195
196         if (!dst)
197                 return NULL;
198
199         for (i = 0; i < n(src, src_type); ++i) {
200                 id = get_id(src, src_type, i);
201                 if (!id)
202                         continue;
203                 dst = set_id(dst, dst_type, offset + i, isl_id_copy(id));
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_id[0] &&
217             !(dup->tuple_id[0] = isl_id_copy(dim->tuple_id[0])))
218                 goto error;
219         if (dim->tuple_id[1] &&
220             !(dup->tuple_id[1] = isl_id_copy(dim->tuple_id[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->ids)
227                 return dup;
228         dup = copy_ids(dup, isl_dim_param, 0, dim, isl_dim_param);
229         dup = copy_ids(dup, isl_dim_in, 0, dim, isl_dim_in);
230         dup = copy_ids(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_id_free(dim->tuple_id[0]);
268         isl_id_free(dim->tuple_id[1]);
269
270         isl_dim_free(dim->nested[0]);
271         isl_dim_free(dim->nested[1]);
272
273         for (i = 0; i < dim->n_id; ++i)
274                 isl_id_free(dim->ids[i]);
275         free(dim->ids);
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 int isl_dim_has_tuple_id(__isl_keep isl_dim *dim, enum isl_dim_type type)
295 {
296         if (!dim)
297                 return -1;
298         if (type != isl_dim_in && type != isl_dim_out)
299                 isl_die(dim->ctx, isl_error_invalid,
300                         "only input, output and set tuples can have ids",
301                         return -1);
302         return dim->tuple_id[type - isl_dim_in] != NULL;
303 }
304
305 __isl_give isl_id *isl_dim_get_tuple_id(__isl_keep isl_dim *dim,
306         enum isl_dim_type type)
307 {
308         if (!dim)
309                 return NULL;
310         if (type != isl_dim_in && type != isl_dim_out)
311                 return NULL;
312         return isl_id_copy(dim->tuple_id[type - isl_dim_in]);
313 }
314
315 __isl_give isl_dim *isl_dim_set_tuple_id(__isl_take isl_dim *dim,
316         enum isl_dim_type type, __isl_take isl_id *id)
317 {
318         dim = isl_dim_cow(dim);
319         if (!dim || !id)
320                 goto error;
321         if (type != isl_dim_in && type != isl_dim_out)
322                 isl_die(dim->ctx, isl_error_invalid,
323                         "only input, output and set tuples can have names",
324                         goto error);
325
326         isl_id_free(dim->tuple_id[type - isl_dim_in]);
327         dim->tuple_id[type - isl_dim_in] = id;
328
329         return dim;
330 error:
331         isl_id_free(id);
332         isl_dim_free(dim);
333         return NULL;
334 }
335
336 __isl_give isl_dim *isl_dim_reset_tuple_id(__isl_take isl_dim *dim,
337         enum isl_dim_type type)
338 {
339         dim = isl_dim_cow(dim);
340         if (!dim)
341                 return NULL;
342         if (type != isl_dim_in && type != isl_dim_out)
343                 isl_die(dim->ctx, isl_error_invalid,
344                         "only input, output and set tuples can have names",
345                         goto error);
346
347         isl_id_free(dim->tuple_id[type - isl_dim_in]);
348         dim->tuple_id[type - isl_dim_in] = NULL;
349
350         return dim;
351 error:
352         isl_dim_free(dim);
353         return NULL;
354 }
355
356 __isl_give isl_dim *isl_dim_set_dim_id(__isl_take isl_dim *dim,
357         enum isl_dim_type type, unsigned pos, __isl_take isl_id *id)
358 {
359         dim = isl_dim_cow(dim);
360         if (!dim || !id)
361                 goto error;
362         isl_id_free(get_id(dim, type, pos));
363         return set_id(dim, type, pos, id);
364 error:
365         isl_id_free(id);
366         isl_dim_free(dim);
367         return NULL;
368 }
369
370 int isl_dim_has_dim_id(__isl_keep isl_dim *dim,
371         enum isl_dim_type type, unsigned pos)
372 {
373         if (!dim)
374                 return -1;
375         return get_id(dim, type, pos) != NULL;
376 }
377
378 __isl_give isl_id *isl_dim_get_dim_id(__isl_keep isl_dim *dim,
379         enum isl_dim_type type, unsigned pos)
380 {
381         return isl_id_copy(get_id(dim, type, pos));
382 }
383
384 __isl_give isl_dim *isl_dim_set_tuple_name(__isl_take isl_dim *dim,
385         enum isl_dim_type type, const char *s)
386 {
387         isl_id *id;
388
389         if (!dim)
390                 return NULL;
391
392         if (!s)
393                 return isl_dim_reset_tuple_id(dim, type);
394
395         if (!name_ok(dim->ctx, s))
396                 goto error;
397
398         id = isl_id_alloc(dim->ctx, s, NULL);
399         return isl_dim_set_tuple_id(dim, type, id);
400 error:
401         isl_dim_free(dim);
402         return NULL;
403 }
404
405 const char *isl_dim_get_tuple_name(__isl_keep isl_dim *dim,
406          enum isl_dim_type type)
407 {
408         isl_id *id;
409         if (!dim)
410                 return NULL;
411         if (type != isl_dim_in && type != isl_dim_out)
412                 return NULL;
413         id = dim->tuple_id[type - isl_dim_in];
414         return id ? id->name : NULL;
415 }
416
417 struct isl_dim *isl_dim_set_name(struct isl_dim *dim,
418                                  enum isl_dim_type type, unsigned pos,
419                                  const char *s)
420 {
421         isl_id *id;
422
423         if (!dim)
424                 return NULL;
425         if (!name_ok(dim->ctx, s))
426                 goto error;
427         id = isl_id_alloc(dim->ctx, s, NULL);
428         return isl_dim_set_dim_id(dim, type, pos, id);
429 error:
430         isl_dim_free(dim);
431         return NULL;
432 }
433
434 const char *isl_dim_get_name(struct isl_dim *dim,
435                                  enum isl_dim_type type, unsigned pos)
436 {
437         isl_id *id = get_id(dim, type, pos);
438         return id ? id->name : NULL;
439 }
440
441 int isl_dim_find_dim_by_id(__isl_keep isl_dim *dim, enum isl_dim_type type,
442         __isl_keep isl_id *id)
443 {
444         int i;
445         int offset;
446         int n;
447
448         if (!dim || !id)
449                 return -1;
450
451         offset = isl_dim_offset(dim, type);
452         n = isl_dim_size(dim, type);
453         for (i = 0; i < n && offset + i < dim->n_id; ++i)
454                 if (dim->ids[offset + i] == id)
455                         return i;
456
457         return -1;
458 }
459
460 static __isl_keep isl_id *tuple_id(__isl_keep isl_dim *dim,
461         enum isl_dim_type type)
462 {
463         if (!dim)
464                 return NULL;
465         if (type == isl_dim_in)
466                 return dim->tuple_id[0];
467         if (type == isl_dim_out)
468                 return dim->tuple_id[1];
469         return NULL;
470 }
471
472 static __isl_keep isl_dim *nested(__isl_keep isl_dim *dim,
473         enum isl_dim_type type)
474 {
475         if (!dim)
476                 return NULL;
477         if (type == isl_dim_in)
478                 return dim->nested[0];
479         if (type == isl_dim_out)
480                 return dim->nested[1];
481         return NULL;
482 }
483
484 int isl_dim_tuple_match(__isl_keep isl_dim *dim1, enum isl_dim_type dim1_type,
485                         __isl_keep isl_dim *dim2, enum isl_dim_type dim2_type)
486 {
487         isl_id *id1, *id2;
488         isl_dim *nested1, *nested2;
489
490         if (!dim1 || !dim2)
491                 return -1;
492
493         if (n(dim1, dim1_type) != n(dim2, dim2_type))
494                 return 0;
495         id1 = tuple_id(dim1, dim1_type);
496         id2 = tuple_id(dim2, dim2_type);
497         if (!id1 ^ !id2)
498                 return 0;
499         if (id1 && id1 != id2)
500                 return 0;
501         nested1 = nested(dim1, dim1_type);
502         nested2 = nested(dim2, dim2_type);
503         if (!nested1 ^ !nested2)
504                 return 0;
505         if (nested1 && !isl_dim_equal(nested1, nested2))
506                 return 0;
507         return 1;
508 }
509
510 static int match(struct isl_dim *dim1, enum isl_dim_type dim1_type,
511                 struct isl_dim *dim2, enum isl_dim_type dim2_type)
512 {
513         int i;
514
515         if (!isl_dim_tuple_match(dim1, dim1_type, dim2, dim2_type))
516                 return 0;
517
518         if (!dim1->ids && !dim2->ids)
519                 return 1;
520
521         for (i = 0; i < n(dim1, dim1_type); ++i) {
522                 if (get_id(dim1, dim1_type, i) != get_id(dim2, dim2_type, i))
523                         return 0;
524         }
525         return 1;
526 }
527
528 int isl_dim_match(struct isl_dim *dim1, enum isl_dim_type dim1_type,
529                 struct isl_dim *dim2, enum isl_dim_type dim2_type)
530 {
531         return match(dim1, dim1_type, dim2, dim2_type);
532 }
533
534 static void get_ids(struct isl_dim *dim, enum isl_dim_type type,
535         unsigned first, unsigned n, __isl_keep isl_id **ids)
536 {
537         int i;
538
539         for (i = 0; i < n ; ++i)
540                 ids[i] = get_id(dim, type, first + i);
541 }
542
543 struct isl_dim *isl_dim_extend(struct isl_dim *dim,
544                         unsigned nparam, unsigned n_in, unsigned n_out)
545 {
546         isl_id **ids = NULL;
547
548         if (!dim)
549                 return NULL;
550         if (dim->nparam == nparam && dim->n_in == n_in && dim->n_out == n_out)
551                 return dim;
552
553         isl_assert(dim->ctx, dim->nparam <= nparam, goto error);
554         isl_assert(dim->ctx, dim->n_in <= n_in, goto error);
555         isl_assert(dim->ctx, dim->n_out <= n_out, goto error);
556
557         dim = isl_dim_cow(dim);
558
559         if (dim->ids) {
560                 ids = isl_calloc_array(dim->ctx, isl_id *,
561                                          nparam + n_in + n_out);
562                 if (!ids)
563                         goto error;
564                 get_ids(dim, isl_dim_param, 0, dim->nparam, ids);
565                 get_ids(dim, isl_dim_in, 0, dim->n_in, ids + nparam);
566                 get_ids(dim, isl_dim_out, 0, dim->n_out, ids + nparam + n_in);
567                 free(dim->ids);
568                 dim->ids = ids;
569                 dim->n_id = nparam + n_in + n_out;
570         }
571         dim->nparam = nparam;
572         dim->n_in = n_in;
573         dim->n_out = n_out;
574
575         return dim;
576 error:
577         free(ids);
578         isl_dim_free(dim);
579         return NULL;
580 }
581
582 struct isl_dim *isl_dim_add(struct isl_dim *dim, enum isl_dim_type type,
583         unsigned n)
584 {
585         if (!dim)
586                 return NULL;
587         dim = isl_dim_reset(dim, type);
588         switch (type) {
589         case isl_dim_param:
590                 dim = isl_dim_extend(dim,
591                                         dim->nparam + n, dim->n_in, dim->n_out);
592                 if (dim && dim->nested[0] &&
593                     !(dim->nested[0] = isl_dim_add(dim->nested[0],
594                                                     isl_dim_param, n)))
595                         goto error;
596                 if (dim && dim->nested[1] &&
597                     !(dim->nested[1] = isl_dim_add(dim->nested[1],
598                                                     isl_dim_param, n)))
599                         goto error;
600                 return dim;
601         case isl_dim_in:
602                 return isl_dim_extend(dim,
603                                         dim->nparam, dim->n_in + n, dim->n_out);
604         case isl_dim_out:
605                 return isl_dim_extend(dim,
606                                         dim->nparam, dim->n_in, dim->n_out + n);
607         default:
608                 isl_die(dim->ctx, isl_error_invalid,
609                         "cannot add dimensions of specified type", goto error);
610         }
611 error:
612         isl_dim_free(dim);
613         return NULL;
614 }
615
616 static int valid_dim_type(enum isl_dim_type type)
617 {
618         switch (type) {
619         case isl_dim_param:
620         case isl_dim_in:
621         case isl_dim_out:
622                 return 1;
623         default:
624                 return 0;
625         }
626 }
627
628 __isl_give isl_dim *isl_dim_insert(__isl_take isl_dim *dim,
629         enum isl_dim_type type, unsigned pos, unsigned n)
630 {
631         isl_id **ids = NULL;
632
633         if (!dim)
634                 return NULL;
635         if (n == 0)
636                 return isl_dim_reset(dim, type);
637
638         if (!valid_dim_type(type))
639                 isl_die(dim->ctx, isl_error_invalid,
640                         "cannot insert dimensions of specified type",
641                         goto error);
642
643         isl_assert(dim->ctx, pos <= isl_dim_size(dim, type), goto error);
644
645         dim = isl_dim_cow(dim);
646         if (!dim)
647                 return NULL;
648
649         if (dim->ids) {
650                 enum isl_dim_type t;
651                 int off;
652                 int s[3];
653                 int *size = s - isl_dim_param;
654                 ids = isl_calloc_array(dim->ctx, isl_id *,
655                                      dim->nparam + dim->n_in + dim->n_out + n);
656                 if (!ids)
657                         goto error;
658                 off = 0;
659                 size[isl_dim_param] = dim->nparam;
660                 size[isl_dim_in] = dim->n_in;
661                 size[isl_dim_out] = dim->n_out;
662                 for (t = isl_dim_param; t <= isl_dim_out; ++t) {
663                         if (t != type) {
664                                 get_ids(dim, t, 0, size[t], ids + off);
665                                 off += size[t];
666                         } else {
667                                 get_ids(dim, t, 0, pos, ids + off);
668                                 off += pos + n;
669                                 get_ids(dim, t, pos, size[t] - pos, ids + off);
670                                 off += size[t] - pos;
671                         }
672                 }
673                 free(dim->ids);
674                 dim->ids = ids;
675                 dim->n_id = dim->nparam + dim->n_in + dim->n_out + n;
676         }
677         switch (type) {
678         case isl_dim_param:     dim->nparam += n; break;
679         case isl_dim_in:        dim->n_in += n; break;
680         case isl_dim_out:       dim->n_out += n; break;
681         default:                ;
682         }
683         dim = isl_dim_reset(dim, type);
684
685         return dim;
686 error:
687         isl_dim_free(dim);
688         return NULL;
689 }
690
691 __isl_give isl_dim *isl_dim_move(__isl_take isl_dim *dim,
692         enum isl_dim_type dst_type, unsigned dst_pos,
693         enum isl_dim_type src_type, unsigned src_pos, unsigned n)
694 {
695         int i;
696
697         if (!dim)
698                 return NULL;
699         if (n == 0)
700                 return dim;
701
702         isl_assert(dim->ctx, src_pos + n <= isl_dim_size(dim, src_type),
703                 goto error);
704
705         if (dst_type == src_type && dst_pos == src_pos)
706                 return dim;
707
708         isl_assert(dim->ctx, dst_type != src_type, goto error);
709
710         dim = isl_dim_reset(dim, src_type);
711         dim = isl_dim_reset(dim, dst_type);
712
713         dim = isl_dim_cow(dim);
714         if (!dim)
715                 return NULL;
716
717         if (dim->ids) {
718                 isl_id **ids;
719                 enum isl_dim_type t;
720                 int off;
721                 int s[3];
722                 int *size = s - isl_dim_param;
723                 ids = isl_calloc_array(dim->ctx, isl_id *,
724                                          dim->nparam + dim->n_in + dim->n_out);
725                 if (!ids)
726                         goto error;
727                 off = 0;
728                 size[isl_dim_param] = dim->nparam;
729                 size[isl_dim_in] = dim->n_in;
730                 size[isl_dim_out] = dim->n_out;
731                 for (t = isl_dim_param; t <= isl_dim_out; ++t) {
732                         if (t == dst_type) {
733                                 get_ids(dim, t, 0, dst_pos, ids + off);
734                                 off += dst_pos;
735                                 get_ids(dim, src_type, src_pos, n, ids + off);
736                                 off += n;
737                                 get_ids(dim, t, dst_pos, size[t] - dst_pos,
738                                                 ids + off);
739                                 off += size[t] - dst_pos;
740                         } else if (t == src_type) {
741                                 get_ids(dim, t, 0, src_pos, ids + off);
742                                 off += src_pos;
743                                 get_ids(dim, t, src_pos + n,
744                                             size[t] - src_pos - n, ids + off);
745                                 off += size[t] - src_pos - n;
746                         } else {
747                                 get_ids(dim, t, 0, size[t], ids + off);
748                                 off += size[t];
749                         }
750                 }
751                 free(dim->ids);
752                 dim->ids = ids;
753                 dim->n_id = dim->nparam + dim->n_in + dim->n_out;
754         }
755
756         switch (dst_type) {
757         case isl_dim_param:     dim->nparam += n; break;
758         case isl_dim_in:        dim->n_in += n; break;
759         case isl_dim_out:       dim->n_out += n; break;
760         default:                ;
761         }
762
763         switch (src_type) {
764         case isl_dim_param:     dim->nparam -= n; break;
765         case isl_dim_in:        dim->n_in -= n; break;
766         case isl_dim_out:       dim->n_out -= n; break;
767         default:                ;
768         }
769
770         if (dst_type != isl_dim_param && src_type != isl_dim_param)
771                 return dim;
772
773         for (i = 0; i < 2; ++i) {
774                 if (!dim->nested[i])
775                         continue;
776                 dim->nested[i] = isl_dim_replace(dim->nested[i],
777                                                  isl_dim_param, dim);
778                 if (!dim->nested[i])
779                         goto error;
780         }
781
782         return dim;
783 error:
784         isl_dim_free(dim);
785         return NULL;
786 }
787
788 struct isl_dim *isl_dim_join(struct isl_dim *left, struct isl_dim *right)
789 {
790         struct isl_dim *dim;
791
792         if (!left || !right)
793                 goto error;
794
795         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
796                         goto error);
797         isl_assert(left->ctx,
798                 isl_dim_tuple_match(left, isl_dim_out, right, isl_dim_in),
799                 goto error);
800
801         dim = isl_dim_alloc(left->ctx, left->nparam, left->n_in, right->n_out);
802         if (!dim)
803                 goto error;
804
805         dim = copy_ids(dim, isl_dim_param, 0, left, isl_dim_param);
806         dim = copy_ids(dim, isl_dim_in, 0, left, isl_dim_in);
807         dim = copy_ids(dim, isl_dim_out, 0, right, isl_dim_out);
808
809         if (dim && left->tuple_id[0] &&
810             !(dim->tuple_id[0] = isl_id_copy(left->tuple_id[0])))
811                 goto error;
812         if (dim && right->tuple_id[1] &&
813             !(dim->tuple_id[1] = isl_id_copy(right->tuple_id[1])))
814                 goto error;
815         if (dim && left->nested[0] &&
816             !(dim->nested[0] = isl_dim_copy(left->nested[0])))
817                 goto error;
818         if (dim && right->nested[1] &&
819             !(dim->nested[1] = isl_dim_copy(right->nested[1])))
820                 goto error;
821
822         isl_dim_free(left);
823         isl_dim_free(right);
824
825         return dim;
826 error:
827         isl_dim_free(left);
828         isl_dim_free(right);
829         return NULL;
830 }
831
832 struct isl_dim *isl_dim_product(struct isl_dim *left, struct isl_dim *right)
833 {
834         isl_dim *dom1, *dom2, *nest1, *nest2;
835
836         if (!left || !right)
837                 goto error;
838
839         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
840                         goto error);
841
842         dom1 = isl_dim_domain(isl_dim_copy(left));
843         dom2 = isl_dim_domain(isl_dim_copy(right));
844         nest1 = isl_dim_wrap(isl_dim_join(isl_dim_reverse(dom1), dom2));
845
846         dom1 = isl_dim_range(left);
847         dom2 = isl_dim_range(right);
848         nest2 = isl_dim_wrap(isl_dim_join(isl_dim_reverse(dom1), dom2));
849
850         return isl_dim_join(isl_dim_reverse(nest1), nest2);
851 error:
852         isl_dim_free(left);
853         isl_dim_free(right);
854         return NULL;
855 }
856
857 __isl_give isl_dim *isl_dim_range_product(__isl_take isl_dim *left,
858         __isl_take isl_dim *right)
859 {
860         isl_dim *dom, *ran1, *ran2, *nest;
861
862         if (!left || !right)
863                 goto error;
864
865         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
866                         goto error);
867         if (!isl_dim_tuple_match(left, isl_dim_in, right, isl_dim_in))
868                 isl_die(left->ctx, isl_error_invalid,
869                         "domains need to match", goto error);
870
871         dom = isl_dim_domain(isl_dim_copy(left));
872
873         ran1 = isl_dim_range(left);
874         ran2 = isl_dim_range(right);
875         nest = isl_dim_wrap(isl_dim_join(isl_dim_reverse(ran1), ran2));
876
877         return isl_dim_join(isl_dim_reverse(dom), nest);
878 error:
879         isl_dim_free(left);
880         isl_dim_free(right);
881         return NULL;
882 }
883
884 __isl_give isl_dim *isl_dim_map_from_set(__isl_take isl_dim *dim)
885 {
886         isl_id **ids = NULL;
887
888         if (!dim)
889                 return NULL;
890         isl_assert(dim->ctx, dim->n_in == 0, goto error);
891         if (dim->n_out == 0 && !isl_dim_is_named_or_nested(dim, isl_dim_out))
892                 return dim;
893         dim = isl_dim_cow(dim);
894         if (!dim)
895                 return NULL;
896         if (dim->ids) {
897                 ids = isl_calloc_array(dim->ctx, isl_id *,
898                                         dim->nparam + dim->n_out + dim->n_out);
899                 if (!ids)
900                         goto error;
901                 get_ids(dim, isl_dim_param, 0, dim->nparam, ids);
902                 get_ids(dim, isl_dim_out, 0, dim->n_out, ids + dim->nparam);
903         }
904         dim->n_in = dim->n_out;
905         if (ids) {
906                 free(dim->ids);
907                 dim->ids = ids;
908                 dim->n_id = dim->nparam + dim->n_out + dim->n_out;
909                 dim = copy_ids(dim, isl_dim_out, 0, dim, isl_dim_in);
910         }
911         isl_id_free(dim->tuple_id[0]);
912         dim->tuple_id[0] = isl_id_copy(dim->tuple_id[1]);
913         isl_dim_free(dim->nested[0]);
914         dim->nested[0] = isl_dim_copy(dim->nested[1]);
915         return dim;
916 error:
917         isl_dim_free(dim);
918         return NULL;
919 }
920
921 static __isl_give isl_dim *set_ids(struct isl_dim *dim, enum isl_dim_type type,
922         unsigned first, unsigned n, __isl_take isl_id **ids)
923 {
924         int i;
925
926         for (i = 0; i < n ; ++i)
927                 dim = set_id(dim, type, first + i, ids[i]);
928
929         return dim;
930 }
931
932 struct isl_dim *isl_dim_reverse(struct isl_dim *dim)
933 {
934         unsigned t;
935         isl_dim *nested;
936         isl_id **ids = NULL;
937         isl_id *id;
938
939         if (!dim)
940                 return NULL;
941         if (match(dim, isl_dim_in, dim, isl_dim_out))
942                 return dim;
943
944         dim = isl_dim_cow(dim);
945         if (!dim)
946                 return NULL;
947
948         id = dim->tuple_id[0];
949         dim->tuple_id[0] = dim->tuple_id[1];
950         dim->tuple_id[1] = id;
951
952         nested = dim->nested[0];
953         dim->nested[0] = dim->nested[1];
954         dim->nested[1] = nested;
955
956         if (dim->ids) {
957                 ids = isl_alloc_array(dim->ctx, isl_id *,
958                                         dim->n_in + dim->n_out);
959                 if (!ids)
960                         goto error;
961                 get_ids(dim, isl_dim_in, 0, dim->n_in, ids);
962                 get_ids(dim, isl_dim_out, 0, dim->n_out, ids + dim->n_in);
963         }
964
965         t = dim->n_in;
966         dim->n_in = dim->n_out;
967         dim->n_out = t;
968
969         if (dim->ids) {
970                 dim = set_ids(dim, isl_dim_out, 0, dim->n_out, ids);
971                 dim = set_ids(dim, isl_dim_in, 0, dim->n_in, ids + dim->n_out);
972                 free(ids);
973         }
974
975         return dim;
976 error:
977         free(ids);
978         isl_dim_free(dim);
979         return NULL;
980 }
981
982 struct isl_dim *isl_dim_drop(struct isl_dim *dim, enum isl_dim_type type,
983                 unsigned first, unsigned num)
984 {
985         int i;
986
987         if (!dim)
988                 return NULL;
989
990         if (num == 0)
991                 return isl_dim_reset(dim, type);
992
993         if (!valid_dim_type(type))
994                 isl_die(dim->ctx, isl_error_invalid,
995                         "cannot drop dimensions of specified type", goto error);
996
997         isl_assert(dim->ctx, first + num <= n(dim, type), goto error);
998         dim = isl_dim_cow(dim);
999         if (!dim)
1000                 goto error;
1001         if (dim->ids) {
1002                 dim = extend_ids(dim);
1003                 if (!dim)
1004                         goto error;
1005                 for (i = 0; i < num; ++i)
1006                         isl_id_free(get_id(dim, type, first + i));
1007                 for (i = first+num; i < n(dim, type); ++i)
1008                         set_id(dim, type, i - num, get_id(dim, type, i));
1009                 switch (type) {
1010                 case isl_dim_param:
1011                         get_ids(dim, isl_dim_in, 0, dim->n_in,
1012                                 dim->ids + offset(dim, isl_dim_in) - num);
1013                 case isl_dim_in:
1014                         get_ids(dim, isl_dim_out, 0, dim->n_out,
1015                                 dim->ids + offset(dim, isl_dim_out) - num);
1016                 default:
1017                         ;
1018                 }
1019                 dim->n_id -= num;
1020         }
1021         switch (type) {
1022         case isl_dim_param:     dim->nparam -= num; break;
1023         case isl_dim_in:        dim->n_in -= num; break;
1024         case isl_dim_out:       dim->n_out -= num; break;
1025         default:                ;
1026         }
1027         dim = isl_dim_reset(dim, type);
1028         if (type == isl_dim_param) {
1029                 if (dim && dim->nested[0] &&
1030                     !(dim->nested[0] = isl_dim_drop(dim->nested[0],
1031                                                     isl_dim_param, first, num)))
1032                         goto error;
1033                 if (dim && dim->nested[1] &&
1034                     !(dim->nested[1] = isl_dim_drop(dim->nested[1],
1035                                                     isl_dim_param, first, num)))
1036                         goto error;
1037         }
1038         return dim;
1039 error:
1040         isl_dim_free(dim);
1041         return NULL;
1042 }
1043
1044 struct isl_dim *isl_dim_drop_inputs(struct isl_dim *dim,
1045                 unsigned first, unsigned n)
1046 {
1047         if (!dim)
1048                 return NULL;
1049         return isl_dim_drop(dim, isl_dim_in, first, n);
1050 }
1051
1052 struct isl_dim *isl_dim_drop_outputs(struct isl_dim *dim,
1053                 unsigned first, unsigned n)
1054 {
1055         if (!dim)
1056                 return NULL;
1057         return isl_dim_drop(dim, isl_dim_out, first, n);
1058 }
1059
1060 struct isl_dim *isl_dim_domain(struct isl_dim *dim)
1061 {
1062         if (!dim)
1063                 return NULL;
1064         dim = isl_dim_drop_outputs(dim, 0, dim->n_out);
1065         return isl_dim_reverse(dim);
1066 }
1067
1068 __isl_give isl_dim *isl_dim_from_domain(__isl_take isl_dim *dim)
1069 {
1070         return isl_dim_reverse(dim);
1071 }
1072
1073 struct isl_dim *isl_dim_range(struct isl_dim *dim)
1074 {
1075         if (!dim)
1076                 return NULL;
1077         return isl_dim_drop_inputs(dim, 0, dim->n_in);
1078 }
1079
1080 __isl_give isl_dim *isl_dim_from_range(__isl_take isl_dim *dim)
1081 {
1082         return dim;
1083 }
1084
1085 __isl_give isl_dim *isl_dim_as_set_dim(__isl_take isl_dim *dim)
1086 {
1087         dim = isl_dim_cow(dim);
1088         if (!dim)
1089                 return NULL;
1090
1091         dim->n_out += dim->n_in;
1092         dim->n_in = 0;
1093         dim = isl_dim_reset(dim, isl_dim_in);
1094         dim = isl_dim_reset(dim, isl_dim_out);
1095
1096         return dim;
1097 }
1098
1099 struct isl_dim *isl_dim_underlying(struct isl_dim *dim, unsigned n_div)
1100 {
1101         int i;
1102
1103         if (!dim)
1104                 return NULL;
1105         if (n_div == 0 &&
1106             dim->nparam == 0 && dim->n_in == 0 && dim->n_id == 0)
1107                 return isl_dim_reset(isl_dim_reset(dim, isl_dim_in), isl_dim_out);
1108         dim = isl_dim_cow(dim);
1109         if (!dim)
1110                 return NULL;
1111         dim->n_out += dim->nparam + dim->n_in + n_div;
1112         dim->nparam = 0;
1113         dim->n_in = 0;
1114
1115         for (i = 0; i < dim->n_id; ++i)
1116                 isl_id_free(get_id(dim, isl_dim_out, i));
1117         dim->n_id = 0;
1118         dim = isl_dim_reset(dim, isl_dim_in);
1119         dim = isl_dim_reset(dim, isl_dim_out);
1120
1121         return dim;
1122 }
1123
1124 unsigned isl_dim_total(struct isl_dim *dim)
1125 {
1126         return dim ? dim->nparam + dim->n_in + dim->n_out : 0;
1127 }
1128
1129 int isl_dim_equal(struct isl_dim *dim1, struct isl_dim *dim2)
1130 {
1131         if (!dim1 || !dim2)
1132                 return -1;
1133         return match(dim1, isl_dim_param, dim2, isl_dim_param) &&
1134                isl_dim_tuple_match(dim1, isl_dim_in, dim2, isl_dim_in) &&
1135                isl_dim_tuple_match(dim1, isl_dim_out, dim2, isl_dim_out);
1136 }
1137
1138 int isl_dim_compatible(struct isl_dim *dim1, struct isl_dim *dim2)
1139 {
1140         return dim1->nparam == dim2->nparam &&
1141                dim1->n_in + dim1->n_out == dim2->n_in + dim2->n_out;
1142 }
1143
1144 static uint32_t isl_hash_dim(uint32_t hash, __isl_keep isl_dim *dim)
1145 {
1146         int i;
1147         isl_id *id;
1148
1149         if (!dim)
1150                 return hash;
1151
1152         hash = isl_hash_builtin(hash, dim->nparam);
1153         hash = isl_hash_builtin(hash, dim->n_in);
1154         hash = isl_hash_builtin(hash, dim->n_out);
1155
1156         for (i = 0; i < dim->nparam; ++i) {
1157                 id = get_id(dim, isl_dim_param, i);
1158                 hash = isl_hash_id(hash, id);
1159         }
1160
1161         id = tuple_id(dim, isl_dim_in);
1162         hash = isl_hash_id(hash, id);
1163         id = tuple_id(dim, isl_dim_out);
1164         hash = isl_hash_id(hash, id);
1165
1166         hash = isl_hash_dim(hash, dim->nested[0]);
1167         hash = isl_hash_dim(hash, dim->nested[1]);
1168
1169         return hash;
1170 }
1171
1172 uint32_t isl_dim_get_hash(__isl_keep isl_dim *dim)
1173 {
1174         uint32_t hash;
1175
1176         if (!dim)
1177                 return 0;
1178
1179         hash = isl_hash_init();
1180         hash = isl_hash_dim(hash, dim);
1181
1182         return hash;
1183 }
1184
1185 int isl_dim_is_wrapping(__isl_keep isl_dim *dim)
1186 {
1187         if (!dim)
1188                 return -1;
1189
1190         if (dim->n_in != 0 || dim->tuple_id[0] || dim->nested[0])
1191                 return 0;
1192
1193         return dim->nested[1] != NULL;
1194 }
1195
1196 __isl_give isl_dim *isl_dim_wrap(__isl_take isl_dim *dim)
1197 {
1198         isl_dim *wrap;
1199
1200         if (!dim)
1201                 return NULL;
1202
1203         wrap = isl_dim_alloc(dim->ctx, dim->nparam, 0, dim->n_in + dim->n_out);
1204
1205         wrap = copy_ids(wrap, isl_dim_param, 0, dim, isl_dim_param);
1206         wrap = copy_ids(wrap, isl_dim_set, 0, dim, isl_dim_in);
1207         wrap = copy_ids(wrap, isl_dim_set, dim->n_in, dim, isl_dim_out);
1208
1209         if (!wrap)
1210                 goto error;
1211
1212         wrap->nested[1] = dim;
1213
1214         return wrap;
1215 error:
1216         isl_dim_free(dim);
1217         return NULL;
1218 }
1219
1220 __isl_give isl_dim *isl_dim_unwrap(__isl_take isl_dim *dim)
1221 {
1222         isl_dim *unwrap;
1223
1224         if (!dim)
1225                 return NULL;
1226
1227         if (!isl_dim_is_wrapping(dim))
1228                 isl_die(dim->ctx, isl_error_invalid, "not a wrapping dim",
1229                         goto error);
1230
1231         unwrap = isl_dim_copy(dim->nested[1]);
1232         isl_dim_free(dim);
1233
1234         return unwrap;
1235 error:
1236         isl_dim_free(dim);
1237         return NULL;
1238 }
1239
1240 int isl_dim_is_named_or_nested(__isl_keep isl_dim *dim, enum isl_dim_type type)
1241 {
1242         if (type != isl_dim_in && type != isl_dim_out)
1243                 return 0;
1244         if (!dim)
1245                 return -1;
1246         if (dim->tuple_id[type - isl_dim_in])
1247                 return 1;
1248         if (dim->nested[type - isl_dim_in])
1249                 return 1;
1250         return 0;
1251 }
1252
1253 int isl_dim_may_be_set(__isl_keep isl_dim *dim)
1254 {
1255         if (!dim)
1256                 return -1;
1257         if (isl_dim_size(dim, isl_dim_in) != 0)
1258                 return 0;
1259         if (isl_dim_is_named_or_nested(dim, isl_dim_in))
1260                 return 0;
1261         return 1;
1262 }
1263
1264 __isl_give isl_dim *isl_dim_reset(__isl_take isl_dim *dim,
1265         enum isl_dim_type type)
1266 {
1267         if (!isl_dim_is_named_or_nested(dim, type))
1268                 return dim;
1269
1270         dim = isl_dim_cow(dim);
1271         if (!dim)
1272                 return NULL;
1273
1274         isl_id_free(dim->tuple_id[type - isl_dim_in]);
1275         dim->tuple_id[type - isl_dim_in] = NULL;
1276         isl_dim_free(dim->nested[type - isl_dim_in]);
1277         dim->nested[type - isl_dim_in] = NULL;
1278
1279         return dim;
1280 }
1281
1282 __isl_give isl_dim *isl_dim_flatten(__isl_take isl_dim *dim)
1283 {
1284         if (!dim)
1285                 return NULL;
1286         if (!dim->nested[0] && !dim->nested[1])
1287                 return dim;
1288
1289         if (dim->nested[0])
1290                 dim = isl_dim_reset(dim, isl_dim_in);
1291         if (dim && dim->nested[1])
1292                 dim = isl_dim_reset(dim, isl_dim_out);
1293
1294         return dim;
1295 }
1296
1297 __isl_give isl_dim *isl_dim_flatten_range(__isl_take isl_dim *dim)
1298 {
1299         if (!dim)
1300                 return NULL;
1301         if (!dim->nested[1])
1302                 return dim;
1303
1304         return isl_dim_reset(dim, isl_dim_out);
1305 }
1306
1307 /* Replace the dimensions of the given type of dst by those of src.
1308  */
1309 __isl_give isl_dim *isl_dim_replace(__isl_take isl_dim *dst,
1310         enum isl_dim_type type, __isl_keep isl_dim *src)
1311 {
1312         dst = isl_dim_cow(dst);
1313
1314         if (!dst || !src)
1315                 goto error;
1316
1317         dst = isl_dim_drop(dst, type, 0, isl_dim_size(dst, type));
1318         dst = isl_dim_add(dst, type, isl_dim_size(src, type));
1319         dst = copy_ids(dst, type, 0, src, type);
1320
1321         if (dst && type == isl_dim_param) {
1322                 int i;
1323                 for (i = 0; i <= 1; ++i) {
1324                         if (!dst->nested[i])
1325                                 continue;
1326                         dst->nested[i] = isl_dim_replace(dst->nested[i],
1327                                                          type, src);
1328                         if (!dst->nested[i])
1329                                 goto error;
1330                 }
1331         }
1332
1333         return dst;
1334 error:
1335         isl_dim_free(dst);
1336         return NULL;
1337 }
1338
1339 /* Given a dimension specification "dim" of a set, create a dimension
1340  * specification for the lift of the set.  In particular, the result
1341  * is of the form [dim -> local[..]], with n_local variables in the
1342  * range of the wrapped map.
1343  */
1344 __isl_give isl_dim *isl_dim_lift(__isl_take isl_dim *dim, unsigned n_local)
1345 {
1346         isl_dim *local_dim;
1347
1348         if (!dim)
1349                 return NULL;
1350
1351         local_dim = isl_dim_dup(dim);
1352         local_dim = isl_dim_drop(local_dim, isl_dim_set, 0, dim->n_out);
1353         local_dim = isl_dim_add(local_dim, isl_dim_set, n_local);
1354         local_dim = isl_dim_set_tuple_name(local_dim, isl_dim_set, "local");
1355         dim = isl_dim_join(isl_dim_from_domain(dim),
1356                             isl_dim_from_range(local_dim));
1357         dim = isl_dim_wrap(dim);
1358         dim = isl_dim_set_tuple_name(dim, isl_dim_set, "lifted");
1359
1360         return dim;
1361 }
1362
1363 int isl_dim_can_zip(__isl_keep isl_dim *dim)
1364 {
1365         if (!dim)
1366                 return -1;
1367
1368         return dim->nested[0] && dim->nested[1];
1369 }
1370
1371 __isl_give isl_dim *isl_dim_zip(__isl_take isl_dim *dim)
1372 {
1373         isl_dim *dom, *ran;
1374         isl_dim *dom_dom, *dom_ran, *ran_dom, *ran_ran;
1375
1376         if (!isl_dim_can_zip(dim))
1377                 isl_die(dim->ctx, isl_error_invalid, "dim cannot be zipped",
1378                         goto error);
1379
1380         if (!dim)
1381                 return 0;
1382         dom = isl_dim_unwrap(isl_dim_domain(isl_dim_copy(dim)));
1383         ran = isl_dim_unwrap(isl_dim_range(dim));
1384         dom_dom = isl_dim_domain(isl_dim_copy(dom));
1385         dom_ran = isl_dim_range(dom);
1386         ran_dom = isl_dim_domain(isl_dim_copy(ran));
1387         ran_ran = isl_dim_range(ran);
1388         dom = isl_dim_join(isl_dim_from_domain(dom_dom),
1389                            isl_dim_from_range(ran_dom));
1390         ran = isl_dim_join(isl_dim_from_domain(dom_ran),
1391                            isl_dim_from_range(ran_ran));
1392         return isl_dim_join(isl_dim_from_domain(isl_dim_wrap(dom)),
1393                             isl_dim_from_range(isl_dim_wrap(ran)));
1394 error:
1395         isl_dim_free(dim);
1396         return NULL;
1397 }
1398
1399 int isl_dim_has_named_params(__isl_keep isl_dim *dim)
1400 {
1401         int i;
1402         unsigned off;
1403
1404         if (!dim)
1405                 return -1;
1406         if (dim->nparam == 0)
1407                 return 1;
1408         off = isl_dim_offset(dim, isl_dim_param);
1409         if (off + dim->nparam > dim->n_id)
1410                 return 0;
1411         for (i = 0; i < dim->nparam; ++i)
1412                 if (!dim->ids[off + i])
1413                         return 0;
1414         return 1;
1415 }
1416
1417 /* Align the initial parameters of dim1 to match the order in dim2.
1418  */
1419 __isl_give isl_dim *isl_dim_align_params(__isl_take isl_dim *dim1,
1420         __isl_take isl_dim *dim2)
1421 {
1422         isl_reordering *exp;
1423
1424         if (!isl_dim_has_named_params(dim1) || !isl_dim_has_named_params(dim2))
1425                 isl_die(isl_dim_get_ctx(dim1), isl_error_invalid,
1426                         "parameter alignment requires named parameters",
1427                         goto error);
1428
1429         exp = isl_parameter_alignment_reordering(dim1, dim2);
1430         isl_dim_free(dim1);
1431         isl_dim_free(dim2);
1432         if (!exp)
1433                 return NULL;
1434         dim1 = isl_dim_copy(exp->dim);
1435         isl_reordering_free(exp);
1436         return dim1;
1437 error:
1438         isl_dim_free(dim1);
1439         isl_dim_free(dim2);
1440         return NULL;
1441 }