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