add isl_local_space_is_equal
[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_add_div(
195         __isl_take isl_local_space *ls, __isl_take isl_vec *div)
196 {
197         ls = isl_local_space_cow(ls);
198         if (!ls || !div)
199                 goto error;
200
201         if (ls->div->n_col != div->size)
202                 isl_die(isl_local_space_get_ctx(ls), isl_error_invalid,
203                         "incompatible dimensions", goto error);
204
205         ls->div = isl_mat_add_zero_cols(ls->div, 1);
206         ls->div = isl_mat_add_rows(ls->div, 1);
207         if (!ls->div)
208                 goto error;
209
210         isl_seq_cpy(ls->div->row[ls->div->n_row - 1], div->el, div->size);
211         isl_int_set_si(ls->div->row[ls->div->n_row - 1][div->size], 0);
212
213         isl_vec_free(div);
214         return ls;
215 error:
216         isl_local_space_free(ls);
217         isl_vec_free(div);
218         return NULL;
219 }
220
221 __isl_give isl_local_space *isl_local_space_replace_divs(
222         __isl_take isl_local_space *ls, __isl_take isl_mat *div)
223 {
224         ls = isl_local_space_cow(ls);
225
226         if (!ls || !div)
227                 goto error;
228
229         isl_mat_free(ls->div);
230         ls->div = div;
231         return ls;
232 error:
233         isl_mat_free(div);
234         isl_local_space_free(ls);
235         return NULL;
236 }
237
238 /* Copy row "s" of "src" to row "d" of "dst", applying the expansion
239  * defined by "exp".
240  */
241 static void expand_row(__isl_keep isl_mat *dst, int d,
242         __isl_keep isl_mat *src, int s, int *exp)
243 {
244         int i;
245         unsigned c = src->n_col - src->n_row;
246
247         isl_seq_cpy(dst->row[d], src->row[s], c);
248         isl_seq_clr(dst->row[d] + c, dst->n_col - c);
249
250         for (i = 0; i < s; ++i)
251                 isl_int_set(dst->row[d][c + exp[i]], src->row[s][c + i]);
252 }
253
254 /* Compare (known) divs.
255  * Return non-zero if at least one of the two divs is unknown.
256  */
257 static int cmp_row(__isl_keep isl_mat *div, int i, int j)
258 {
259         int li, lj;
260
261         if (isl_int_is_zero(div->row[j][0]))
262                 return -1;
263         if (isl_int_is_zero(div->row[i][0]))
264                 return 1;
265
266         li = isl_seq_last_non_zero(div->row[i], div->n_col);
267         lj = isl_seq_last_non_zero(div->row[j], div->n_col);
268
269         if (li != lj)
270                 return li - lj;
271
272         return isl_seq_cmp(div->row[i], div->row[j], div->n_col);
273 }
274
275 /* Combine the two lists of divs into a single list.
276  * For each row i in div1, exp1[i] is set to the position of the corresponding
277  * row in the result.  Similarly for div2 and exp2.
278  * This function guarantees
279  *      exp1[i] >= i
280  *      exp1[i+1] > exp1[i]
281  * For optimal merging, the two input list should have been sorted.
282  */
283 __isl_give isl_mat *isl_merge_divs(__isl_keep isl_mat *div1,
284         __isl_keep isl_mat *div2, int *exp1, int *exp2)
285 {
286         int i, j, k;
287         isl_mat *div = NULL;
288         unsigned d = div1->n_col - div1->n_row;
289
290         div = isl_mat_alloc(div1->ctx, 1 + div1->n_row + div2->n_row,
291                                 d + div1->n_row + div2->n_row);
292         if (!div)
293                 return NULL;
294
295         for (i = 0, j = 0, k = 0; i < div1->n_row && j < div2->n_row; ++k) {
296                 int cmp;
297
298                 expand_row(div, k, div1, i, exp1);
299                 expand_row(div, k + 1, div2, j, exp2);
300
301                 cmp = cmp_row(div, k, k + 1);
302                 if (cmp == 0) {
303                         exp1[i++] = k;
304                         exp2[j++] = k;
305                 } else if (cmp < 0) {
306                         exp1[i++] = k;
307                 } else {
308                         exp2[j++] = k;
309                         isl_seq_cpy(div->row[k], div->row[k + 1], div->n_col);
310                 }
311         }
312         for (; i < div1->n_row; ++i, ++k) {
313                 expand_row(div, k, div1, i, exp1);
314                 exp1[i] = k;
315         }
316         for (; j < div2->n_row; ++j, ++k) {
317                 expand_row(div, k, div2, j, exp2);
318                 exp2[j] = k;
319         }
320
321         div->n_row = k;
322         div->n_col = d + k;
323
324         return div;
325 }
326
327 int isl_local_space_divs_known(__isl_keep isl_local_space *ls)
328 {
329         int i;
330
331         if (!ls)
332                 return -1;
333
334         for (i = 0; i < ls->div->n_row; ++i)
335                 if (isl_int_is_zero(ls->div->row[i][0]))
336                         return 0;
337
338         return 1;
339 }
340
341 /* Construct a local space for a map that has the given local
342  * space as domain and that has a zero-dimensional range.
343  */
344 __isl_give isl_local_space *isl_local_space_from_domain(
345         __isl_take isl_local_space *ls)
346 {
347         ls = isl_local_space_cow(ls);
348         if (!ls)
349                 return NULL;
350         ls->dim = isl_dim_from_domain(ls->dim);
351         if (!ls->dim)
352                 return isl_local_space_free(ls);
353         return ls;
354 }
355
356 __isl_give isl_local_space *isl_local_space_add_dim(
357         __isl_take isl_local_space *ls, enum isl_dim_type type, unsigned n)
358 {
359         int pos;
360
361         if (n == 0)
362                 return ls;
363
364         ls = isl_local_space_cow(ls);
365         if (!ls)
366                 return NULL;
367
368         pos = isl_local_space_offset(ls, type);
369         pos += isl_local_space_dim(ls, type);
370
371         ls->div = isl_mat_insert_zero_cols(ls->div, 1 + pos, n);
372
373         if (type == isl_dim_div) {
374                 ls->div = isl_mat_add_zero_rows(ls->div, n);
375         } else {
376                 ls->dim = isl_dim_add(ls->dim, type, n);
377                 if (!ls->dim)
378                         return isl_local_space_free(ls);
379         }
380
381         if (!ls->div)
382                 return isl_local_space_free(ls);
383
384         return ls;
385 }