8638aab73b1c412c05582d62f465ee857e22d256
[platform/upstream/isl.git] / isl_multi_templ.c
1 /*
2  * Copyright 2011      Sven Verdoolaege
3  *
4  * Use of this software is governed by the MIT license
5  */
6
7 #define xCAT(A,B) A ## B
8 #define CAT(A,B) xCAT(A,B)
9 #undef EL
10 #define EL CAT(isl_,BASE)
11 #define xFN(TYPE,NAME) TYPE ## _ ## NAME
12 #define FN(TYPE,NAME) xFN(TYPE,NAME)
13 #define xMULTI(BASE) isl_multi_ ## BASE
14 #define MULTI(BASE) xMULTI(BASE)
15 #define MULTI_NAME(BASE) "isl_multi_" #BASE
16 #define xLIST(EL) EL ## _list
17 #define LIST(EL) xLIST(EL)
18
19 isl_ctx *FN(MULTI(BASE),get_ctx)(__isl_keep MULTI(BASE) *multi)
20 {
21         return multi ? isl_space_get_ctx(multi->space) : NULL;
22 }
23
24 __isl_give isl_space *FN(MULTI(BASE),get_space)(__isl_keep MULTI(BASE) *multi)
25 {
26         return multi ? isl_space_copy(multi->space) : NULL;
27 }
28
29 __isl_give isl_space *FN(MULTI(BASE),get_domain_space)(
30         __isl_keep MULTI(BASE) *multi)
31 {
32         return multi ? isl_space_domain(isl_space_copy(multi->space)) : NULL;
33 }
34
35 __isl_give MULTI(BASE) *FN(MULTI(BASE),alloc)(__isl_take isl_space *space)
36 {
37         isl_ctx *ctx;
38         int n;
39         MULTI(BASE) *multi;
40
41         if (!space)
42                 return NULL;
43
44         ctx = isl_space_get_ctx(space);
45         n = isl_space_dim(space, isl_dim_out);
46         multi = isl_calloc(ctx, MULTI(BASE),
47                          sizeof(MULTI(BASE)) + (n - 1) * sizeof(struct EL *));
48         if (!multi)
49                 goto error;
50
51         multi->space = space;
52         multi->n = n;
53         multi->ref = 1;
54         return multi;
55 error:
56         isl_space_free(space);
57         return NULL;
58 }
59
60 __isl_give MULTI(BASE) *FN(MULTI(BASE),dup)(__isl_keep MULTI(BASE) *multi)
61 {
62         int i;
63         MULTI(BASE) *dup;
64
65         if (!multi)
66                 return NULL;
67
68         dup = FN(MULTI(BASE),alloc)(isl_space_copy(multi->space));
69         if (!dup)
70                 return NULL;
71
72         for (i = 0; i < multi->n; ++i)
73                 dup = FN(FN(MULTI(BASE),set),BASE)(dup, i,
74                                                     FN(EL,copy)(multi->p[i]));
75
76         return dup;
77 }
78
79 __isl_give MULTI(BASE) *FN(MULTI(BASE),cow)(__isl_take MULTI(BASE) *multi)
80 {
81         if (!multi)
82                 return NULL;
83
84         if (multi->ref == 1)
85                 return multi;
86
87         multi->ref--;
88         return FN(MULTI(BASE),dup)(multi);
89 }
90
91 __isl_give MULTI(BASE) *FN(MULTI(BASE),copy)(__isl_keep MULTI(BASE) *multi)
92 {
93         if (!multi)
94                 return NULL;
95
96         multi->ref++;
97         return multi;
98 }
99
100 void *FN(MULTI(BASE),free)(__isl_take MULTI(BASE) *multi)
101 {
102         int i;
103
104         if (!multi)
105                 return NULL;
106
107         if (--multi->ref > 0)
108                 return NULL;
109
110         isl_space_free(multi->space);
111         for (i = 0; i < multi->n; ++i)
112                 FN(EL,free)(multi->p[i]);
113         free(multi);
114
115         return NULL;
116 }
117
118 unsigned FN(MULTI(BASE),dim)(__isl_keep MULTI(BASE) *multi,
119         enum isl_dim_type type)
120 {
121         return multi ? isl_space_dim(multi->space, type) : 0;
122 }
123
124 __isl_give MULTI(BASE) *FN(MULTI(BASE),set_dim_name)(
125         __isl_take MULTI(BASE) *multi,
126         enum isl_dim_type type, unsigned pos, const char *s)
127 {
128         int i;
129
130         multi = FN(MULTI(BASE),cow)(multi);
131         if (!multi)
132                 return NULL;
133
134         multi->space = isl_space_set_dim_name(multi->space, type, pos, s);
135         if (!multi->space)
136                 return FN(MULTI(BASE),free)(multi);
137
138         if (type == isl_dim_out)
139                 return multi;
140         for (i = 0; i < multi->n; ++i) {
141                 multi->p[i] = FN(EL,set_dim_name)(multi->p[i], type, pos, s);
142                 if (!multi->p[i])
143                         return FN(MULTI(BASE),free)(multi);
144         }
145
146         return multi;
147 }
148
149 const char *FN(MULTI(BASE),get_tuple_name)(__isl_keep MULTI(BASE) *multi,
150         enum isl_dim_type type)
151 {
152         return multi ? isl_space_get_tuple_name(multi->space, type) : NULL;
153 }
154
155 __isl_give EL *FN(FN(MULTI(BASE),get),BASE)(__isl_keep MULTI(BASE) *multi,
156         int pos)
157 {
158         isl_ctx *ctx;
159
160         if (!multi)
161                 return NULL;
162         ctx = FN(MULTI(BASE),get_ctx)(multi);
163         if (pos < 0 || pos >= multi->n)
164                 isl_die(ctx, isl_error_invalid,
165                         "index out of bounds", return NULL);
166         return FN(EL,copy)(multi->p[pos]);
167 }
168
169 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),set),BASE)(
170         __isl_take MULTI(BASE) *multi, int pos, __isl_take EL *el)
171 {
172         isl_space *multi_space = NULL;
173         isl_space *el_space = NULL;
174
175         multi = FN(MULTI(BASE),cow)(multi);
176         if (!multi || !el)
177                 goto error;
178
179         multi_space = FN(MULTI(BASE),get_space)(multi);
180         el_space = FN(EL,get_space)(el);
181
182         if (!isl_space_match(multi_space, isl_dim_param,
183                             el_space, isl_dim_param))
184                 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
185                         "parameters don't match", goto error);
186         if (!isl_space_tuple_match(multi_space, isl_dim_in,
187                             el_space, isl_dim_in))
188                 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
189                         "domains don't match", goto error);
190
191         if (pos < 0 || pos >= multi->n)
192                 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
193                         "index out of bounds", goto error);
194
195         FN(EL,free)(multi->p[pos]);
196         multi->p[pos] = el;
197
198         isl_space_free(multi_space);
199         isl_space_free(el_space);
200
201         return multi;
202 error:
203         FN(MULTI(BASE),free)(multi);
204         FN(EL,free)(el);
205         isl_space_free(multi_space);
206         isl_space_free(el_space);
207         return NULL;
208 }
209
210 /* Reset the space of "multi".  This function is called from isl_pw_templ.c
211  * and doesn't know if the space of an element object is represented
212  * directly or through its domain.  It therefore passes along both,
213  * which we pass along to the element function since we don't how
214  * that is represented either.
215  */
216 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space_and_domain)(
217         __isl_take MULTI(BASE) *multi, __isl_take isl_space *space,
218         __isl_take isl_space *domain)
219 {
220         int i;
221
222         multi = FN(MULTI(BASE),cow)(multi);
223         if (!multi || !space || !domain)
224                 goto error;
225
226         for (i = 0; i < multi->n; ++i) {
227                 multi->p[i] = FN(EL,reset_space_and_domain)(multi->p[i],
228                                  isl_space_copy(space), isl_space_copy(domain));
229                 if (!multi->p[i])
230                         goto error;
231         }
232         isl_space_free(domain);
233         isl_space_free(multi->space);
234         multi->space = space;
235
236         return multi;
237 error:
238         isl_space_free(domain);
239         isl_space_free(space);
240         FN(MULTI(BASE),free)(multi);
241         return NULL;
242 }
243
244 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_domain_space)(
245         __isl_take MULTI(BASE) *multi, __isl_take isl_space *domain)
246 {
247         isl_space *space;
248
249         space = isl_space_extend_domain_with_range(isl_space_copy(domain),
250                                                 isl_space_copy(multi->space));
251         return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
252 }
253
254 __isl_give MULTI(BASE) *FN(MULTI(BASE),reset_space)(
255         __isl_take MULTI(BASE) *multi, __isl_take isl_space *space)
256 {
257         isl_space *domain;
258
259         domain = isl_space_domain(isl_space_copy(space));
260         return FN(MULTI(BASE),reset_space_and_domain)(multi, space, domain);
261 }
262
263 __isl_give MULTI(BASE) *FN(MULTI(BASE),set_tuple_id)(
264         __isl_keep MULTI(BASE) *multi, enum isl_dim_type type,
265         __isl_take isl_id *id)
266 {
267         isl_space *space;
268
269         multi = FN(MULTI(BASE),cow)(multi);
270         if (!multi)
271                 return isl_id_free(id);
272
273         space = FN(MULTI(BASE),get_space)(multi);
274         space = isl_space_set_tuple_id(space, type, id);
275
276         return FN(MULTI(BASE),reset_space)(multi, space);
277 }
278
279 __isl_give MULTI(BASE) *FN(MULTI(BASE),realign_domain)(
280         __isl_take MULTI(BASE) *multi, __isl_take isl_reordering *exp)
281 {
282         int i;
283
284         multi = FN(MULTI(BASE),cow)(multi);
285         if (!multi || !exp)
286                 return NULL;
287
288         for (i = 0; i < multi->n; ++i) {
289                 multi->p[i] = FN(EL,realign_domain)(multi->p[i],
290                                                 isl_reordering_copy(exp));
291                 if (!multi->p[i])
292                         goto error;
293         }
294
295         multi = FN(MULTI(BASE),reset_domain_space)(multi,
296                                                     isl_space_copy(exp->dim));
297
298         isl_reordering_free(exp);
299         return multi;
300 error:
301         isl_reordering_free(exp);
302         FN(MULTI(BASE),free)(multi);
303         return NULL;
304 }
305
306 /* Align the parameters of "multi" to those of "model".
307  */
308 __isl_give MULTI(BASE) *FN(MULTI(BASE),align_params)(
309         __isl_take MULTI(BASE) *multi, __isl_take isl_space *model)
310 {
311         isl_ctx *ctx;
312
313         if (!multi || !model)
314                 goto error;
315
316         ctx = isl_space_get_ctx(model);
317         if (!isl_space_has_named_params(model))
318                 isl_die(ctx, isl_error_invalid,
319                         "model has unnamed parameters", goto error);
320         if (!isl_space_has_named_params(multi->space))
321                 isl_die(ctx, isl_error_invalid,
322                         "input has unnamed parameters", goto error);
323         if (!isl_space_match(multi->space, isl_dim_param,
324                              model, isl_dim_param)) {
325                 isl_reordering *exp;
326
327                 model = isl_space_params(model);
328                 exp = isl_parameter_alignment_reordering(multi->space, model);
329                 exp = isl_reordering_extend_space(exp,
330                                     FN(MULTI(BASE),get_domain_space)(multi));
331                 multi = FN(MULTI(BASE),realign_domain)(multi, exp);
332         }
333
334         isl_space_free(model);
335         return multi;
336 error:
337         isl_space_free(model);
338         FN(MULTI(BASE),free)(multi);
339         return NULL;
340 }
341
342 static __isl_give MULTI(BASE) *align_params_multi_set_and(
343         __isl_take MULTI(BASE) *multi, __isl_take isl_set *set,
344         __isl_give MULTI(BASE) *(*fn)(__isl_take MULTI(BASE) *multi,
345                                         __isl_take isl_set *set))
346 {
347         isl_ctx *ctx;
348
349         if (!multi || !set)
350                 goto error;
351         if (isl_space_match(multi->space, isl_dim_param,
352                             set->dim, isl_dim_param))
353                 return fn(multi, set);
354         ctx = FN(MULTI(BASE),get_ctx)(multi);
355         if (!isl_space_has_named_params(multi->space) ||
356             !isl_space_has_named_params(set->dim))
357                 isl_die(ctx, isl_error_invalid,
358                         "unaligned unnamed parameters", goto error);
359         multi = FN(MULTI(BASE),align_params)(multi, isl_set_get_space(set));
360         set = isl_set_align_params(set, FN(MULTI(BASE),get_space)(multi));
361         return fn(multi, set);
362 error:
363         FN(MULTI(BASE),free)(multi);
364         isl_set_free(set);
365         return NULL;
366 }
367
368 __isl_give MULTI(BASE) *FN(MULTI(BASE),gist_aligned)(
369         __isl_take MULTI(BASE) *multi, __isl_take isl_set *context)
370 {
371         int i;
372
373         if (!multi || !context)
374                 goto error;
375
376         for (i = 0; i < multi->n; ++i) {
377                 multi->p[i] = FN(EL,gist)(multi->p[i], isl_set_copy(context));
378                 if (!multi->p[i])
379                         goto error;
380         }
381
382         isl_set_free(context);
383         return multi;
384 error:
385         isl_set_free(context);
386         FN(MULTI(BASE),free)(multi);
387         return NULL;
388 }
389
390 __isl_give MULTI(BASE) *FN(MULTI(BASE),gist)(__isl_take MULTI(BASE) *multi,
391         __isl_take isl_set *context)
392 {
393         return align_params_multi_set_and(multi, context,
394                                                 &FN(MULTI(BASE),gist_aligned));
395 }
396
397 __isl_give MULTI(BASE) *FN(MULTI(BASE),gist_params)(
398         __isl_take MULTI(BASE) *multi, __isl_take isl_set *context)
399 {
400         isl_space *space = FN(MULTI(BASE),get_domain_space)(multi);
401         isl_set *dom_context = isl_set_universe(space);
402         dom_context = isl_set_intersect_params(dom_context, context);
403         return FN(MULTI(BASE),gist)(multi, dom_context);
404 }
405
406 __isl_give MULTI(BASE) *FN(FN(MULTI(BASE),from),LIST(BASE))(
407         __isl_take isl_space *space, __isl_take LIST(EL) *list)
408 {
409         int i;
410         int n;
411         isl_ctx *ctx;
412         MULTI(BASE) *multi;
413
414         if (!space || !list)
415                 goto error;
416
417         ctx = isl_space_get_ctx(space);
418         n = FN(FN(LIST(EL),n),BASE)(list);
419         if (n != isl_space_dim(space, isl_dim_out))
420                 isl_die(ctx, isl_error_invalid,
421                         "invalid number of elements in list", goto error);
422
423         multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
424         for (i = 0; i < n; ++i) {
425                 multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
426                                         FN(FN(LIST(EL),get),BASE)(list, i));
427         }
428
429         isl_space_free(space);
430         FN(LIST(EL),free)(list);
431         return multi;
432 error:
433         isl_space_free(space);
434         FN(LIST(EL),free)(list);
435         return NULL;
436 }
437
438 /* Create a multi expression in the given space that maps each
439  * input dimension to the corresponding output dimension.
440  */
441 __isl_give MULTI(BASE) *FN(MULTI(BASE),identity)(__isl_take isl_space *space)
442 {
443         int i, n;
444         isl_local_space *ls;
445         MULTI(BASE) *multi;
446
447         if (!space)
448                 return NULL;
449
450         if (isl_space_is_set(space))
451                 isl_die(isl_space_get_ctx(space), isl_error_invalid,
452                         "expecting map space", goto error);
453
454         n = isl_space_dim(space, isl_dim_out);
455         if (n != isl_space_dim(space, isl_dim_in))
456                 isl_die(isl_space_get_ctx(space), isl_error_invalid,
457                         "number of input and output dimensions needs to be "
458                         "the same", goto error);
459
460         multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
461
462         if (!n) {
463                 isl_space_free(space);
464                 return multi;
465         }
466
467         space = isl_space_domain(space);
468         ls = isl_local_space_from_space(space);
469
470         for (i = 0; i < n; ++i) {
471                 EL *el;
472                 el = FN(EL,var_on_domain)(isl_local_space_copy(ls),
473                                                 isl_dim_set, i);
474                 multi = FN(FN(MULTI(BASE),set),BASE)(multi, i, el);
475         }
476
477         isl_local_space_free(ls);
478
479         return multi;
480 error:
481         isl_space_free(space);
482         return NULL;
483 }
484
485 /* Construct a multi expression in the given space with value zero in
486  * each of the output dimensions.
487  */
488 __isl_give MULTI(BASE) *FN(MULTI(BASE),zero)(__isl_take isl_space *space)
489 {
490         int n;
491         MULTI(BASE) *multi;
492
493         if (!space)
494                 return NULL;
495
496         n = isl_space_dim(space , isl_dim_out);
497         multi = FN(MULTI(BASE),alloc)(isl_space_copy(space));
498
499         if (!n)
500                 isl_space_free(space);
501         else {
502                 int i;
503                 isl_local_space *ls;
504                 EL *el;
505
506                 space = isl_space_domain(space);
507                 ls = isl_local_space_from_space(space);
508                 el = FN(EL,zero_on_domain)(ls);
509
510                 for (i = 0; i < n; ++i)
511                         multi = FN(FN(MULTI(BASE),set),BASE)(multi, i,
512                                                             FN(EL,copy)(el));
513
514                 FN(EL,free)(el);
515         }
516
517         return multi;
518 }
519
520 __isl_give MULTI(BASE) *FN(MULTI(BASE),drop_dims)(
521         __isl_take MULTI(BASE) *multi,
522         enum isl_dim_type type, unsigned first, unsigned n)
523 {
524         int i;
525         unsigned dim;
526
527         multi = FN(MULTI(BASE),cow)(multi);
528         if (!multi)
529                 return NULL;
530
531         dim = FN(MULTI(BASE),dim)(multi, type);
532         if (first + n > dim || first + n < first)
533                 isl_die(FN(MULTI(BASE),get_ctx)(multi), isl_error_invalid,
534                         "index out of bounds",
535                         return FN(MULTI(BASE),cow)(multi));
536
537         multi->space = isl_space_drop_dims(multi->space, type, first, n);
538         if (!multi->space)
539                 return FN(MULTI(BASE),cow)(multi);
540
541         if (type == isl_dim_out) {
542                 for (i = 0; i < n; ++i)
543                         FN(EL,free)(multi->p[first + i]);
544                 for (i = first; i + n < multi->n; ++i)
545                         multi->p[i] = multi->p[i + n];
546                 multi->n -= n;
547
548                 return multi;
549         }
550
551         for (i = 0; i < multi->n; ++i) {
552                 multi->p[i] = FN(EL,drop_dims)(multi->p[i], type, first, n);
553                 if (!multi->p[i])
554                         return FN(MULTI(BASE),cow)(multi);
555         }
556
557         return multi;
558 }