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