296ef192feb2fa8bf4521db0ec2c3608b2102c2b
[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 int isl_local_space_dim(__isl_keep isl_local_space *ls,
116         enum isl_dim_type type)
117 {
118         if (!ls)
119                 return 0;
120         if (type == isl_dim_div)
121                 return ls->div->n_row;
122         if (type == isl_dim_all)
123                 return isl_dim_size(ls->dim, isl_dim_all) + ls->div->n_row;
124         return isl_dim_size(ls->dim, type);
125 }
126
127 unsigned isl_local_space_offset(__isl_keep isl_local_space *ls,
128         enum isl_dim_type type)
129 {
130         isl_dim *dim;
131
132         if (!ls)
133                 return 0;
134
135         dim = ls->dim;
136         switch (type) {
137         case isl_dim_cst:       return 0;
138         case isl_dim_param:     return 1;
139         case isl_dim_in:        return 1 + dim->nparam;
140         case isl_dim_out:       return 1 + dim->nparam + dim->n_in;
141         case isl_dim_div:       return 1 + dim->nparam + dim->n_in + dim->n_out;
142         default:                return 0;
143         }
144 }
145
146 const char *isl_local_space_get_dim_name(__isl_keep isl_local_space *ls,
147         enum isl_dim_type type, unsigned pos)
148 {
149         return ls ? isl_dim_get_name(ls->dim, type, pos) : NULL;
150 }
151
152 __isl_give isl_div *isl_local_space_get_div(__isl_keep isl_local_space *ls,
153         int pos)
154 {
155         isl_basic_map *bmap;
156
157         if (!ls)
158                 return NULL;
159
160         if (pos < 0 || pos >= ls->div->n_row)
161                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
162                         "index out of bounds", return NULL);
163
164         bmap = isl_basic_map_from_local_space(isl_local_space_copy(ls));
165         return isl_basic_map_div(bmap, pos);
166 }
167
168 __isl_give isl_dim *isl_local_space_get_dim(__isl_keep isl_local_space *ls)
169 {
170         if (!ls)
171                 return NULL;
172
173         return isl_dim_copy(ls->dim);
174 }
175
176 __isl_give isl_local_space *isl_local_space_add_div(
177         __isl_take isl_local_space *ls, __isl_take isl_vec *div)
178 {
179         ls = isl_local_space_cow(ls);
180         if (!ls || !div)
181                 goto error;
182
183         if (ls->div->n_col != div->size)
184                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
185                         "incompatible dimensions", goto error);
186
187         ls->div = isl_mat_add_zero_cols(ls->div, 1);
188         ls->div = isl_mat_add_rows(ls->div, 1);
189         if (!ls->div)
190                 goto error;
191
192         isl_seq_cpy(ls->div->row[ls->div->n_row - 1], div->el, div->size);
193         isl_int_set_si(ls->div->row[ls->div->n_row - 1][div->size], 0);
194
195         isl_vec_free(div);
196         return ls;
197 error:
198         isl_local_space_free(ls);
199         isl_vec_free(div);
200         return NULL;
201 }
202
203 __isl_give isl_local_space *isl_local_space_replace_divs(
204         __isl_take isl_local_space *ls, __isl_take isl_mat *div)
205 {
206         ls = isl_local_space_cow(ls);
207
208         if (!ls || !div)
209                 goto error;
210
211         isl_mat_free(ls->div);
212         ls->div = div;
213         return ls;
214 error:
215         isl_mat_free(div);
216         isl_local_space_free(ls);
217         return NULL;
218 }
219
220 /* Copy row "s" of "src" to row "d" of "dst", applying the expansion
221  * defined by "exp".
222  */
223 static void expand_row(__isl_keep isl_mat *dst, int d,
224         __isl_keep isl_mat *src, int s, int *exp)
225 {
226         int i;
227         unsigned c = src->n_col - src->n_row;
228
229         isl_seq_cpy(dst->row[d], src->row[s], c);
230         isl_seq_clr(dst->row[d] + c, dst->n_col - c);
231
232         for (i = 0; i < s; ++i)
233                 isl_int_set(dst->row[d][c + exp[i]], src->row[s][c + i]);
234 }
235
236 /* Compare (known) divs.
237  * Return non-zero if at least one of the two divs is unknown.
238  */
239 static int cmp_row(__isl_keep isl_mat *div, int i, int j)
240 {
241         int li, lj;
242
243         if (isl_int_is_zero(div->row[j][0]))
244                 return -1;
245         if (isl_int_is_zero(div->row[i][0]))
246                 return 1;
247
248         li = isl_seq_last_non_zero(div->row[i], div->n_col);
249         lj = isl_seq_last_non_zero(div->row[j], div->n_col);
250
251         if (li != lj)
252                 return li - lj;
253
254         return isl_seq_cmp(div->row[i], div->row[j], div->n_col);
255 }
256
257 /* Combine the two lists of divs into a single list.
258  * For each row i in div1, exp1[i] is set to the position of the corresponding
259  * row in the result.  Similarly for div2 and exp2.
260  * This function guarantees
261  *      exp1[i] >= i
262  *      exp1[i+1] > exp1[i]
263  * For optimal merging, the two input list should have been sorted.
264  */
265 __isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
266         __isl_keep isl_mat *div2, int *exp1, int *exp2)
267 {
268         int i, j, k;
269         isl_mat *div = NULL;
270         unsigned d = div1->n_col - div1->n_row;
271
272         div = isl_mat_alloc(div1->ctx, 1 + div1->n_row + div2->n_row,
273                                 d + div1->n_row + div2->n_row);
274         if (!div)
275                 return NULL;
276
277         for (i = 0, j = 0, k = 0; i < div1->n_row && j < div2->n_row; ++k) {
278                 int cmp;
279
280                 expand_row(div, k, div1, i, exp1);
281                 expand_row(div, k + 1, div2, j, exp2);
282
283                 cmp = cmp_row(div, k, k + 1);
284                 if (cmp == 0) {
285                         exp1[i++] = k;
286                         exp2[j++] = k;
287                 } else if (cmp < 0) {
288                         exp1[i++] = k;
289                 } else {
290                         exp2[j++] = k;
291                         isl_seq_cpy(div->row[k], div->row[k + 1], div->n_col);
292                 }
293         }
294         for (; i < div1->n_row; ++i, ++k) {
295                 expand_row(div, k, div1, i, exp1);
296                 exp1[i] = k;
297         }
298         for (; j < div2->n_row; ++j, ++k) {
299                 expand_row(div, k, div2, j, exp2);
300                 exp2[j] = k;
301         }
302
303         div->n_row = k;
304         div->n_col = d + k;
305
306         return div;
307 }
308
309 int isl_local_space_divs_known(__isl_keep isl_local_space *ls)
310 {
311         int i;
312
313         if (!ls)
314                 return -1;
315
316         for (i = 0; i < ls->div->n_row; ++i)
317                 if (isl_int_is_zero(ls->div->row[i][0]))
318                         return 0;
319
320         return 1;
321 }
322
323 /* Construct a local space for a map that has the given local
324  * space as domain and that has a zero-dimensional range.
325  */
326 __isl_give isl_local_space *isl_local_space_from_domain(
327         __isl_take isl_local_space *ls)
328 {
329         ls = isl_local_space_cow(ls);
330         if (!ls)
331                 return NULL;
332         ls->dim = isl_dim_from_domain(ls->dim);
333         if (!ls->dim)
334                 return isl_local_space_free(ls);
335         return ls;
336 }
337
338 __isl_give isl_local_space *isl_local_space_add_dim(
339         __isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n)
340 {
341         int pos;
342
343         if (n == 0)
344                 return ls;
345
346         ls = isl_local_space_cow(ls);
347         if (!ls)
348                 return NULL;
349
350         pos = isl_local_space_offset(ls, type);
351         pos += isl_local_space_dim(ls, type);
352
353         ls->div = isl_mat_insert_zero_cols(ls->div, 1 + pos, n);
354
355         if (type == isl_dim_div) {
356                 ls->div = isl_mat_add_zero_rows(ls->div, n);
357         } else {
358                 ls->dim = isl_dim_add(ls->dim, type, n);
359                 if (!ls->dim)
360                         return isl_local_space_free(ls);
361         }
362
363         if (!ls->div)
364                 return isl_local_space_free(ls);
365
366         return ls;
367 }