078a0a8d39968bf2fd4717c8b73284746ab76e20
[platform/upstream/isl.git] / isl_dim.c
1 /*
2  * Copyright 2008-2009 Katholieke Universiteit Leuven
3  *
4  * Use of this software is governed by the GNU LGPLv2.1 license
5  *
6  * Written by Sven Verdoolaege, K.U.Leuven, Departement
7  * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium
8  */
9
10 #include "isl_dim.h"
11 #include "isl_name.h"
12
13 struct isl_dim *isl_dim_alloc(struct isl_ctx *ctx,
14                         unsigned nparam, unsigned n_in, unsigned n_out)
15 {
16         struct isl_dim *dim;
17
18         dim = isl_alloc_type(ctx, struct isl_dim);
19         if (!dim)
20                 return NULL;
21
22         dim->ctx = ctx;
23         isl_ctx_ref(ctx);
24         dim->ref = 1;
25         dim->nparam = nparam;
26         dim->n_in = n_in;
27         dim->n_out = n_out;
28
29         dim->n_name = 0;
30         dim->names = NULL;
31
32         return dim;
33 }
34
35 struct isl_dim *isl_dim_set_alloc(struct isl_ctx *ctx,
36                         unsigned nparam, unsigned dim)
37 {
38         return isl_dim_alloc(ctx, nparam, 0, dim);
39 }
40
41 static unsigned global_pos(struct isl_dim *dim,
42                                  enum isl_dim_type type, unsigned pos)
43 {
44         struct isl_ctx *ctx = dim->ctx;
45
46         switch (type) {
47         case isl_dim_param:
48                 isl_assert(ctx, pos < dim->nparam, return isl_dim_total(dim));
49                 return pos;
50         case isl_dim_in:
51                 isl_assert(ctx, pos < dim->n_in, return isl_dim_total(dim));
52                 return pos + dim->nparam;
53         case isl_dim_out:
54                 isl_assert(ctx, pos < dim->n_out, return isl_dim_total(dim));
55                 return pos + dim->nparam + dim->n_in;
56         default:
57                 isl_assert(ctx, 0, return isl_dim_total(dim));
58         }
59         return isl_dim_total(dim);
60 }
61
62 /* Extend length of names array to the total number of dimensions.
63  */
64 static __isl_give isl_dim *extend_names(__isl_take isl_dim *dim)
65 {
66         struct isl_name **names;
67         int i;
68
69         if (isl_dim_total(dim) <= dim->n_name)
70                 return dim;
71
72         if (!dim->names) {
73                 dim->names = isl_calloc_array(dim->ctx,
74                                 struct isl_name *, isl_dim_total(dim));
75                 if (!dim->names)
76                         goto error;
77         } else {
78                 names = isl_realloc_array(dim->ctx, dim->names,
79                                 struct isl_name *, isl_dim_total(dim));
80                 if (!names)
81                         goto error;
82                 dim->names = names;
83                 for (i = dim->n_name; i < isl_dim_total(dim); ++i)
84                         dim->names[i] = NULL;
85         }
86
87         dim->n_name = isl_dim_total(dim);
88
89         return dim;
90 error:
91         isl_dim_free(dim);
92         return NULL;
93 }
94
95 static struct isl_dim *set_name(struct isl_dim *dim,
96                                  enum isl_dim_type type, unsigned pos,
97                                  struct isl_name *name)
98 {
99         struct isl_ctx *ctx = dim->ctx;
100         dim = isl_dim_cow(dim);
101
102         if (!dim)
103                 goto error;
104
105         pos = global_pos(dim, type, pos);
106         isl_assert(ctx, pos != isl_dim_total(dim), goto error);
107
108         if (pos >= dim->n_name) {
109                 if (!name)
110                         return dim;
111                 dim = extend_names(dim);
112                 if (!dim)
113                         goto error;
114         }
115
116         dim->names[pos] = name;
117
118         return dim;
119 error:
120         isl_name_free(ctx, name);
121         isl_dim_free(dim);
122         return NULL;
123 }
124
125 static struct isl_name *get_name(struct isl_dim *dim,
126                                  enum isl_dim_type type, unsigned pos)
127 {
128         if (!dim)
129                 return NULL;
130
131         pos = global_pos(dim, type, pos);
132         if (pos == isl_dim_total(dim))
133                 return NULL;
134         if (pos >= dim->n_name)
135                 return NULL;
136         return dim->names[pos];
137 }
138
139 static unsigned offset(struct isl_dim *dim, enum isl_dim_type type)
140 {
141         switch (type) {
142         case isl_dim_param:     return 0;
143         case isl_dim_in:        return dim->nparam;
144         case isl_dim_out:       return dim->nparam + dim->n_in;
145         }
146 }
147
148 static unsigned n(struct isl_dim *dim, enum isl_dim_type type)
149 {
150         switch (type) {
151         case isl_dim_param:     return dim->nparam;
152         case isl_dim_in:        return dim->n_in;
153         case isl_dim_out:       return dim->n_out;
154         }
155 }
156
157 unsigned isl_dim_size(struct isl_dim *dim, enum isl_dim_type type)
158 {
159         if (!dim)
160                 return 0;
161         return n(dim, type);
162 }
163
164 static struct isl_dim *copy_names(struct isl_dim *dst,
165         enum isl_dim_type dst_type, unsigned offset, struct isl_dim *src,
166         enum isl_dim_type src_type)
167 {
168         int i;
169         struct isl_name *name;
170
171         for (i = 0; i < n(src, src_type); ++i) {
172                 name = get_name(src, src_type, i);
173                 if (!name)
174                         continue;
175                 dst = set_name(dst, dst_type, offset + i,
176                                         isl_name_copy(dst->ctx, name));
177                 if (!dst)
178                         return NULL;
179         }
180         return dst;
181 }
182
183 struct isl_dim *isl_dim_dup(struct isl_dim *dim)
184 {
185         struct isl_dim *dup;
186         dup = isl_dim_alloc(dim->ctx, dim->nparam, dim->n_in, dim->n_out);
187         if (!dim->names)
188                 return dup;
189         dup = copy_names(dup, isl_dim_param, 0, dim, isl_dim_param);
190         dup = copy_names(dup, isl_dim_in, 0, dim, isl_dim_in);
191         dup = copy_names(dup, isl_dim_out, 0, dim, isl_dim_out);
192         return dup;
193 }
194
195 struct isl_dim *isl_dim_cow(struct isl_dim *dim)
196 {
197         if (!dim)
198                 return NULL;
199
200         if (dim->ref == 1)
201                 return dim;
202         dim->ref--;
203         return isl_dim_dup(dim);
204 }
205
206 struct isl_dim *isl_dim_copy(struct isl_dim *dim)
207 {
208         if (!dim)
209                 return NULL;
210
211         dim->ref++;
212         return dim;
213 }
214
215 void isl_dim_free(struct isl_dim *dim)
216 {
217         int i;
218
219         if (!dim)
220                 return;
221
222         if (--dim->ref > 0)
223                 return;
224
225         for (i = 0; i < dim->n_name; ++i)
226                 isl_name_free(dim->ctx, dim->names[i]);
227         free(dim->names);
228         isl_ctx_deref(dim->ctx);
229         
230         free(dim);
231 }
232
233 struct isl_dim *isl_dim_set_name(struct isl_dim *dim,
234                                  enum isl_dim_type type, unsigned pos,
235                                  const char *s)
236 {
237         struct isl_name *name;
238         if (!dim)
239                 return NULL;
240         name = isl_name_get(dim->ctx, s);
241         if (!name)
242                 goto error;
243         return set_name(dim, type, pos, name);
244 error:
245         isl_dim_free(dim);
246         return NULL;
247 }
248
249 const char *isl_dim_get_name(struct isl_dim *dim,
250                                  enum isl_dim_type type, unsigned pos)
251 {
252         struct isl_name *name = get_name(dim, type, pos);
253         return name ? name->name : NULL;
254 }
255
256 static int match(struct isl_dim *dim1, enum isl_dim_type dim1_type,
257                 struct isl_dim *dim2, enum isl_dim_type dim2_type)
258 {
259         int i;
260
261         if (n(dim1, dim1_type) != n(dim2, dim2_type))
262                 return 0;
263
264         if (!dim1->names && !dim2->names)
265                 return 1;
266
267         for (i = 0; i < n(dim1, dim1_type); ++i) {
268                 if (get_name(dim1, dim1_type, i) !=
269                     get_name(dim2, dim2_type, i))
270                         return 0;
271         }
272         return 1;
273 }
274
275 int isl_dim_match(struct isl_dim *dim1, enum isl_dim_type dim1_type,
276                 struct isl_dim *dim2, enum isl_dim_type dim2_type)
277 {
278         return match(dim1, dim1_type, dim2, dim2_type);
279 }
280
281 static void get_names(struct isl_dim *dim, enum isl_dim_type type,
282         unsigned first, unsigned n, struct isl_name **names)
283 {
284         int i;
285
286         for (i = 0; i < n ; ++i)
287                 names[i] = get_name(dim, type, first+i);
288 }
289
290 struct isl_dim *isl_dim_extend(struct isl_dim *dim,
291                         unsigned nparam, unsigned n_in, unsigned n_out)
292 {
293         struct isl_name **names = NULL;
294
295         if (!dim)
296                 return NULL;
297         if (dim->nparam == nparam && dim->n_in == n_in && dim->n_out == n_out)
298                 return dim;
299
300         isl_assert(dim->ctx, dim->nparam <= nparam, goto error);
301         isl_assert(dim->ctx, dim->n_in <= n_in, goto error);
302         isl_assert(dim->ctx, dim->n_out <= n_out, goto error);
303
304         dim = isl_dim_cow(dim);
305
306         if (dim->names) {
307                 names = isl_calloc_array(dim->ctx, struct isl_name *,
308                                          nparam + n_in + n_out);
309                 if (!names)
310                         goto error;
311                 get_names(dim, isl_dim_param, 0, dim->nparam, names);
312                 get_names(dim, isl_dim_in, 0, dim->n_in, names + nparam);
313                 get_names(dim, isl_dim_out, 0, dim->n_out,
314                                 names + nparam + n_in);
315                 free(dim->names);
316                 dim->names = names;
317                 dim->n_name = nparam + n_in + n_out;
318         }
319         dim->nparam = nparam;
320         dim->n_in = n_in;
321         dim->n_out = n_out;
322
323         return dim;
324 error:
325         free(names);
326         isl_dim_free(dim);
327         return NULL;
328 }
329
330 struct isl_dim *isl_dim_add(struct isl_dim *dim, enum isl_dim_type type,
331         unsigned n)
332 {
333         switch (type) {
334         case isl_dim_param:
335                 return isl_dim_extend(dim,
336                                         dim->nparam + n, dim->n_in, dim->n_out);
337         case isl_dim_in:
338                 return isl_dim_extend(dim,
339                                         dim->nparam, dim->n_in + n, dim->n_out);
340         case isl_dim_out:
341                 return isl_dim_extend(dim,
342                                         dim->nparam, dim->n_in, dim->n_out + n);
343         }
344         return dim;
345 }
346
347 struct isl_dim *isl_dim_join(struct isl_dim *left, struct isl_dim *right)
348 {
349         struct isl_dim *dim;
350
351         if (!left || !right)
352                 goto error;
353
354         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
355                         goto error);
356         isl_assert(left->ctx, n(left, isl_dim_out) == n(right, isl_dim_in),
357                         goto error);
358
359         dim = isl_dim_alloc(left->ctx, left->nparam, left->n_in, right->n_out);
360         if (!dim)
361                 goto error;
362
363         dim = copy_names(dim, isl_dim_param, 0, left, isl_dim_param);
364         dim = copy_names(dim, isl_dim_in, 0, left, isl_dim_in);
365         dim = copy_names(dim, isl_dim_out, 0, right, isl_dim_out);
366
367         isl_dim_free(left);
368         isl_dim_free(right);
369
370         return dim;
371 error:
372         isl_dim_free(left);
373         isl_dim_free(right);
374         return NULL;
375 }
376
377 struct isl_dim *isl_dim_product(struct isl_dim *left, struct isl_dim *right)
378 {
379         struct isl_dim *dim;
380
381         if (!left || !right)
382                 goto error;
383
384         isl_assert(left->ctx, match(left, isl_dim_param, right, isl_dim_param),
385                         goto error);
386
387         dim = isl_dim_alloc(left->ctx, left->nparam,
388                         left->n_in + right->n_in, left->n_out + right->n_out);
389         if (!dim)
390                 goto error;
391
392         dim = copy_names(dim, isl_dim_param, 0, left, isl_dim_param);
393         dim = copy_names(dim, isl_dim_in, 0, left, isl_dim_in);
394         dim = copy_names(dim, isl_dim_in, left->n_in, right, isl_dim_in);
395         dim = copy_names(dim, isl_dim_out, 0, left, isl_dim_out);
396         dim = copy_names(dim, isl_dim_out, left->n_out, right, isl_dim_out);
397
398         isl_dim_free(left);
399         isl_dim_free(right);
400
401         return dim;
402 error:
403         isl_dim_free(left);
404         isl_dim_free(right);
405         return NULL;
406 }
407
408 struct isl_dim *isl_dim_map(struct isl_dim *dim)
409 {
410         struct isl_name **names = NULL;
411
412         if (!dim)
413                 return NULL;
414         isl_assert(dim->ctx, dim->n_in == 0, goto error);
415         if (dim->n_out == 0)
416                 return dim;
417         dim = isl_dim_cow(dim);
418         if (!dim)
419                 return NULL;
420         if (dim->names) {
421                 names = isl_calloc_array(dim->ctx, struct isl_name *,
422                                         dim->nparam + dim->n_out + dim->n_out);
423                 if (!names)
424                         goto error;
425                 get_names(dim, isl_dim_param, 0, dim->nparam, names);
426                 get_names(dim, isl_dim_out, 0, dim->n_out, names + dim->nparam);
427         }
428         dim->n_in = dim->n_out;
429         if (names) {
430                 free(dim->names);
431                 dim->names = names;
432                 dim->n_name = dim->nparam + dim->n_out + dim->n_out;
433                 dim = copy_names(dim, isl_dim_out, 0, dim, isl_dim_in);
434         }
435         return dim;
436 error:
437         isl_dim_free(dim);
438         return NULL;
439 }
440
441 static struct isl_dim *set_names(struct isl_dim *dim, enum isl_dim_type type,
442         unsigned first, unsigned n, struct isl_name **names)
443 {
444         int i;
445
446         for (i = 0; i < n ; ++i)
447                 dim = set_name(dim, type, first+i, names[i]);
448
449         return dim;
450 }
451
452 struct isl_dim *isl_dim_reverse(struct isl_dim *dim)
453 {
454         unsigned t;
455         struct isl_name **names = NULL;
456
457         if (!dim)
458                 return NULL;
459         if (match(dim, isl_dim_in, dim, isl_dim_out))
460                 return dim;
461
462         dim = isl_dim_cow(dim);
463         if (!dim)
464                 return NULL;
465
466         if (dim->names) {
467                 names = isl_alloc_array(dim->ctx, struct isl_name *,
468                                         dim->n_in + dim->n_out);
469                 if (!names)
470                         goto error;
471                 get_names(dim, isl_dim_in, 0, dim->n_in, names);
472                 get_names(dim, isl_dim_out, 0, dim->n_out, names + dim->n_in);
473         }
474
475         t = dim->n_in;
476         dim->n_in = dim->n_out;
477         dim->n_out = t;
478
479         if (dim->names) {
480                 dim = set_names(dim, isl_dim_out, 0, dim->n_out, names);
481                 dim = set_names(dim, isl_dim_in, 0, dim->n_in, names + dim->n_out);
482                 free(names);
483         }
484
485         return dim;
486 error:
487         free(names);
488         isl_dim_free(dim);
489         return NULL;
490 }
491
492 struct isl_dim *isl_dim_drop(struct isl_dim *dim, enum isl_dim_type type,
493                 unsigned first, unsigned num)
494 {
495         int i;
496
497         if (!dim)
498                 return NULL;
499
500         if (n == 0)
501                 return dim;
502
503         isl_assert(dim->ctx, first + num <= n(dim, type), goto error);
504         dim = isl_dim_cow(dim);
505         if (!dim)
506                 goto error;
507         if (dim->names) {
508                 dim = extend_names(dim);
509                 if (!dim)
510                         goto error;
511                 for (i = 0; i < num; ++i)
512                         isl_name_free(dim->ctx, get_name(dim, type, first+i));
513                 for (i = first+num; i < n(dim, type); ++i)
514                         set_name(dim, type, i - num, get_name(dim, type, i));
515                 switch (type) {
516                 case isl_dim_param:
517                         get_names(dim, isl_dim_in, 0, dim->n_in,
518                                 dim->names + offset(dim, isl_dim_in) - num);
519                 case isl_dim_in:
520                         get_names(dim, isl_dim_out, 0, dim->n_out,
521                                 dim->names + offset(dim, isl_dim_out) - num);
522                 case isl_dim_out:
523                         ;
524                 }
525                 dim->n_name -= num;
526         }
527         switch (type) {
528         case isl_dim_param:     dim->nparam -= num; break;
529         case isl_dim_in:        dim->n_in -= num; break;
530         case isl_dim_out:       dim->n_out -= num; break;
531         }
532         return dim;
533 error:
534         isl_dim_free(dim);
535         return NULL;
536 }
537
538 struct isl_dim *isl_dim_drop_inputs(struct isl_dim *dim,
539                 unsigned first, unsigned n)
540 {
541         return isl_dim_drop(dim, isl_dim_in, first, n);
542 }
543
544 struct isl_dim *isl_dim_drop_outputs(struct isl_dim *dim,
545                 unsigned first, unsigned n)
546 {
547         return isl_dim_drop(dim, isl_dim_out, first, n);
548 }
549
550 struct isl_dim *isl_dim_domain(struct isl_dim *dim)
551 {
552         if (!dim)
553                 return NULL;
554         dim = isl_dim_drop_outputs(dim, 0, dim->n_out);
555         return isl_dim_reverse(dim);
556 }
557
558 struct isl_dim *isl_dim_range(struct isl_dim *dim)
559 {
560         if (!dim)
561                 return NULL;
562         return isl_dim_drop_inputs(dim, 0, dim->n_in);
563 }
564
565 struct isl_dim *isl_dim_underlying(struct isl_dim *dim, unsigned n_div)
566 {
567         int i;
568
569         if (!dim)
570                 return NULL;
571         if (n_div == 0 &&
572             dim->nparam == 0 && dim->n_in == 0 && dim->n_name == 0)
573                 return dim;
574         dim = isl_dim_cow(dim);
575         if (!dim)
576                 return NULL;
577         dim->n_out += dim->nparam + dim->n_in + n_div;
578         dim->nparam = 0;
579         dim->n_in = 0;
580
581         for (i = 0; i < dim->n_name; ++i)
582                 isl_name_free(dim->ctx, get_name(dim, isl_dim_out, i));
583         dim->n_name = 0;
584
585         return dim;
586 }
587
588 unsigned isl_dim_total(struct isl_dim *dim)
589 {
590         return dim->nparam + dim->n_in + dim->n_out;
591 }
592
593 int isl_dim_equal(struct isl_dim *dim1, struct isl_dim *dim2)
594 {
595         return match(dim1, isl_dim_param, dim2, isl_dim_param) &&
596                n(dim1, isl_dim_in) == n(dim2, isl_dim_in) &&
597                n(dim1, isl_dim_out) == n(dim2, isl_dim_out);
598 }
599
600 int isl_dim_compatible(struct isl_dim *dim1, struct isl_dim *dim2)
601 {
602         return dim1->nparam == dim2->nparam &&
603                dim1->n_in + dim1->n_out == dim2->n_in + dim2->n_out;
604 }