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