add isl_local_space_set_dim_name
[platform/upstream/isl.git] / isl_local_space.c
1 /*
2  * Copyright 2011      INRIA Saclay
3  *
4  * Use of this software is governed by the GNU LGPLv2.1 license
5  *
6  * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
7  * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
8  * 91893 Orsay, France
9  */
10
11 #include <isl_map_private.h>
12 #include <isl_local_space_private.h>
13 #include <isl_dim_private.h>
14 #include <isl_mat_private.h>
15 #include <isl/seq.h>
16
17 isl_ctx *isl_local_space_get_ctx(__isl_keep isl_local_space *ls)
18 {
19         return ls ? ls->dim->ctx : NULL;
20 }
21
22 __isl_give isl_local_space *isl_local_space_alloc_div(__isl_take isl_dim *dim,
23         __isl_take isl_mat *div)
24 {
25         isl_ctx *ctx;
26         isl_local_space *ls = NULL;
27
28         if (!dim)
29                 goto error;
30
31         ctx = isl_dim_get_ctx(dim);
32         ls = isl_calloc_type(ctx, struct isl_local_space);
33         if (!ls)
34                 goto error;
35
36         ls->ref = 1;
37         ls->dim = dim;
38         ls->div = div;
39
40         return ls;
41 error:
42         isl_dim_free(dim);
43         isl_local_space_free(ls);
44         return NULL;
45 }
46
47 __isl_give isl_local_space *isl_local_space_alloc(__isl_take isl_dim *dim,
48         unsigned n_div)
49 {
50         isl_ctx *ctx;
51         isl_mat *div;
52         unsigned total;
53
54         if (!dim)
55                 return NULL;
56
57         total = isl_dim_total(dim);
58
59         ctx = isl_dim_get_ctx(dim);
60         div = isl_mat_alloc(ctx, n_div, 1 + 1 + total + n_div);
61         return isl_local_space_alloc_div(dim, div);
62 }
63
64 __isl_give isl_local_space *isl_local_space_from_dim(__isl_take isl_dim *dim)
65 {
66         return isl_local_space_alloc(dim, 0);
67 }
68
69 __isl_give isl_local_space *isl_local_space_copy(__isl_keep isl_local_space *ls)
70 {
71         if (!ls)
72                 return NULL;
73
74         ls->ref++;
75         return ls;
76 }
77
78 __isl_give isl_local_space *isl_local_space_dup(__isl_keep isl_local_space *ls)
79 {
80         if (!ls)
81                 return NULL;
82
83         return isl_local_space_alloc_div(isl_dim_copy(ls->dim),
84                                          isl_mat_copy(ls->div));
85
86 }
87
88 __isl_give isl_local_space *isl_local_space_cow(__isl_take isl_local_space *ls)
89 {
90         if (!ls)
91                 return NULL;
92
93         if (ls->ref == 1)
94                 return ls;
95         ls->ref--;
96         return isl_local_space_dup(ls);
97 }
98
99 void *isl_local_space_free(__isl_take isl_local_space *ls)
100 {
101         if (!ls)
102                 return NULL;
103
104         if (--ls->ref > 0)
105                 return NULL;
106
107         isl_dim_free(ls->dim);
108         isl_mat_free(ls->div);
109
110         free(ls);
111
112         return NULL;
113 }
114
115 /* Return true if the two local spaces are identical, with identical
116  * expressions for the integer divisions.
117  */
118 int isl_local_space_is_equal(__isl_keep isl_local_space *ls1,
119         __isl_keep isl_local_space *ls2)
120 {
121         int equal;
122
123         if (!ls1 || !ls2)
124                 return -1;
125
126         equal = isl_dim_equal(ls1->dim, ls2->dim);
127         if (equal < 0 || !equal)
128                 return equal;
129
130         return isl_mat_is_equal(ls1->div, ls2->div);
131 }
132
133 int isl_local_space_dim(__isl_keep isl_local_space *ls,
134         enum isl_dim_type type)
135 {
136         if (!ls)
137                 return 0;
138         if (type == isl_dim_div)
139                 return ls->div->n_row;
140         if (type == isl_dim_all)
141                 return isl_dim_size(ls->dim, isl_dim_all) + ls->div->n_row;
142         return isl_dim_size(ls->dim, type);
143 }
144
145 unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
146         enum isl_dim_type type)
147 {
148         isl_dim *dim;
149
150         if (!ls)
151                 return 0;
152
153         dim = ls->dim;
154         switch (type) {
155         case isl_dim_cst:       return 0;
156         case isl_dim_param:     return 1;
157         case isl_dim_in:        return 1 + dim->nparam;
158         case isl_dim_out:       return 1 + dim->nparam + dim->n_in;
159         case isl_dim_div:       return 1 + dim->nparam + dim->n_in + dim->n_out;
160         default:                return 0;
161         }
162 }
163
164 const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
165         enum isl_dim_type type, unsigned pos)
166 {
167         return ls ? isl_dim_get_name(ls->dim, type, pos) : NULL;
168 }
169
170 __isl_give isl_div *isl_local_space_get_div(__isl_keep isl_local_space *ls,
171         int pos)
172 {
173         isl_basic_map *bmap;
174
175         if (!ls)
176                 return NULL;
177
178         if (pos < 0 || pos >= ls->div->n_row)
179                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
180                         "index out of bounds", return NULL);
181
182         bmap = isl_basic_map_from_local_space(isl_local_space_copy(ls));
183         return isl_basic_map_div(bmap, pos);
184 }
185
186 __isl_give isl_dim *isl_local_space_get_dim(__isl_keep isl_local_space *ls)
187 {
188         if (!ls)
189                 return NULL;
190
191         return isl_dim_copy(ls->dim);
192 }
193
194 __isl_give isl_local_space *isl_local_space_set_dim_name(
195         __isl_take isl_local_space *ls,
196         enum isl_dim_type type, unsigned pos, const char *s)
197 {
198         ls = isl_local_space_cow(ls);
199         if (!ls)
200                 return NULL;
201         ls->dim = isl_dim_set_name(ls->dim, type, pos, s);
202         if (!ls->dim)
203                 return isl_local_space_free(ls);
204
205         return ls;
206 }
207
208 __isl_give isl_local_space *isl_local_space_add_div(
209         __isl_take isl_local_space *ls, __isl_take isl_vec *div)
210 {
211         ls = isl_local_space_cow(ls);
212         if (!ls || !div)
213                 goto error;
214
215         if (ls->div->n_col != div->size)
216                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
217                         "incompatible dimensions", goto error);
218
219         ls->div = isl_mat_add_zero_cols(ls->div, 1);
220         ls->div = isl_mat_add_rows(ls->div, 1);
221         if (!ls->div)
222                 goto error;
223
224         isl_seq_cpy(ls->div->row[ls->div->n_row - 1], div->el, div->size);
225         isl_int_set_si(ls->div->row[ls->div->n_row - 1][div->size], 0);
226
227         isl_vec_free(div);
228         return ls;
229 error:
230         isl_local_space_free(ls);
231         isl_vec_free(div);
232         return NULL;
233 }
234
235 __isl_give isl_local_space *isl_local_space_replace_divs(
236         __isl_take isl_local_space *ls, __isl_take isl_mat *div)
237 {
238         ls = isl_local_space_cow(ls);
239
240         if (!ls || !div)
241                 goto error;
242
243         isl_mat_free(ls->div);
244         ls->div = div;
245         return ls;
246 error:
247         isl_mat_free(div);
248         isl_local_space_free(ls);
249         return NULL;
250 }
251
252 /* Copy row "s" of "src" to row "d" of "dst", applying the expansion
253  * defined by "exp".
254  */
255 static void expand_row(__isl_keep isl_mat *dst, int d,
256         __isl_keep isl_mat *src, int s, int *exp)
257 {
258         int i;
259         unsigned c = src->n_col - src->n_row;
260
261         isl_seq_cpy(dst->row[d], src->row[s], c);
262         isl_seq_clr(dst->row[d] + c, dst->n_col - c);
263
264         for (i = 0; i < s; ++i)
265                 isl_int_set(dst->row[d][c + exp[i]], src->row[s][c + i]);
266 }
267
268 /* Compare (known) divs.
269  * Return non-zero if at least one of the two divs is unknown.
270  */
271 static int cmp_row(__isl_keep isl_mat *div, int i, int j)
272 {
273         int li, lj;
274
275         if (isl_int_is_zero(div->row[j][0]))
276                 return -1;
277         if (isl_int_is_zero(div->row[i][0]))
278                 return 1;
279
280         li = isl_seq_last_non_zero(div->row[i], div->n_col);
281         lj = isl_seq_last_non_zero(div->row[j], div->n_col);
282
283         if (li != lj)
284                 return li - lj;
285
286         return isl_seq_cmp(div->row[i], div->row[j], div->n_col);
287 }
288
289 /* Combine the two lists of divs into a single list.
290  * For each row i in div1, exp1[i] is set to the position of the corresponding
291  * row in the result.  Similarly for div2 and exp2.
292  * This function guarantees
293  *      exp1[i] >= i
294  *      exp1[i+1] > exp1[i]
295  * For optimal merging, the two input list should have been sorted.
296  */
297 __isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
298         __isl_keep isl_mat *div2, int *exp1, int *exp2)
299 {
300         int i, j, k;
301         isl_mat *div = NULL;
302         unsigned d = div1->n_col - div1->n_row;
303
304         div = isl_mat_alloc(div1->ctx, 1 + div1->n_row + div2->n_row,
305                                 d + div1->n_row + div2->n_row);
306         if (!div)
307                 return NULL;
308
309         for (i = 0, j = 0, k = 0; i < div1->n_row && j < div2->n_row; ++k) {
310                 int cmp;
311
312                 expand_row(div, k, div1, i, exp1);
313                 expand_row(div, k + 1, div2, j, exp2);
314
315                 cmp = cmp_row(div, k, k + 1);
316                 if (cmp == 0) {
317                         exp1[i++] = k;
318                         exp2[j++] = k;
319                 } else if (cmp < 0) {
320                         exp1[i++] = k;
321                 } else {
322                         exp2[j++] = k;
323                         isl_seq_cpy(div->row[k], div->row[k + 1], div->n_col);
324                 }
325         }
326         for (; i < div1->n_row; ++i, ++k) {
327                 expand_row(div, k, div1, i, exp1);
328                 exp1[i] = k;
329         }
330         for (; j < div2->n_row; ++j, ++k) {
331                 expand_row(div, k, div2, j, exp2);
332                 exp2[j] = k;
333         }
334
335         div->n_row = k;
336         div->n_col = d + k;
337
338         return div;
339 }
340
341 int isl_local_space_divs_known(__isl_keep isl_local_space *ls)
342 {
343         int i;
344
345         if (!ls)
346                 return -1;
347
348         for (i = 0; i < ls->div->n_row; ++i)
349                 if (isl_int_is_zero(ls->div->row[i][0]))
350                         return 0;
351
352         return 1;
353 }
354
355 /* Construct a local space for a map that has the given local
356  * space as domain and that has a zero-dimensional range.
357  */
358 __isl_give isl_local_space *isl_local_space_from_domain(
359         __isl_take isl_local_space *ls)
360 {
361         ls = isl_local_space_cow(ls);
362         if (!ls)
363                 return NULL;
364         ls->dim = isl_dim_from_domain(ls->dim);
365         if (!ls->dim)
366                 return isl_local_space_free(ls);
367         return ls;
368 }
369
370 __isl_give isl_local_space *isl_local_space_add_dim(
371         __isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n)
372 {
373         int pos;
374
375         if (n == 0)
376                 return ls;
377
378         ls = isl_local_space_cow(ls);
379         if (!ls)
380                 return NULL;
381
382         pos = isl_local_space_offset(ls, type);
383         pos += isl_local_space_dim(ls, type);
384
385         ls->div = isl_mat_insert_zero_cols(ls->div, 1 + pos, n);
386
387         if (type == isl_dim_div) {
388                 ls->div = isl_mat_add_zero_rows(ls->div, n);
389         } else {
390                 ls->dim = isl_dim_add(ls->dim, type, n);
391                 if (!ls->dim)
392                         return isl_local_space_free(ls);
393         }
394
395         if (!ls->div)
396                 return isl_local_space_free(ls);
397
398         return ls;
399 }