1 | /* |
2 | * Copyright 2011 INRIA Saclay |
3 | * Copyright 2014 Ecole Normale Superieure |
4 | * Copyright 2015 Sven Verdoolaege |
5 | * |
6 | * Use of this software is governed by the MIT license |
7 | * |
8 | * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France, |
9 | * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod, |
10 | * 91893 Orsay, France |
11 | * and Ecole Normale Superieure, 45 rue d'Ulm, 75230 Paris, France |
12 | */ |
13 | |
14 | #include <isl/space.h> |
15 | #include <isl_vec_private.h> |
16 | #include <isl_mat_private.h> |
17 | #include <isl_reordering.h> |
18 | #include <isl_seq.h> |
19 | #include <isl_local_private.h> |
20 | |
21 | /* Return the isl_ctx to which "local" belongs. |
22 | */ |
23 | isl_ctx *isl_local_get_ctx(__isl_keep isl_local *local) |
24 | { |
25 | if (!local) |
26 | return NULL; |
27 | |
28 | return isl_mat_get_ctx(mat: local); |
29 | } |
30 | |
31 | /* Create an isl_local object from a matrix describing |
32 | * integer divisions. |
33 | * |
34 | * An isl_local object is current defined as exactly such a matrix, |
35 | * so simply return the input. |
36 | */ |
37 | __isl_give isl_local *isl_local_alloc_from_mat(__isl_take isl_mat *mat) |
38 | { |
39 | return mat; |
40 | } |
41 | |
42 | /* Return a new reference to "local". |
43 | */ |
44 | __isl_give isl_local *isl_local_copy(__isl_keep isl_local *local) |
45 | { |
46 | return isl_local_alloc_from_mat(mat: isl_mat_copy(mat: local)); |
47 | } |
48 | |
49 | /* Free "local" and return NULL. |
50 | */ |
51 | __isl_null isl_local *isl_local_free(__isl_take isl_local *local) |
52 | { |
53 | isl_mat_free(mat: local); |
54 | return NULL; |
55 | } |
56 | |
57 | /* Return the number of local variables (isl_dim_div), |
58 | * the number of other variables (isl_dim_set) or |
59 | * the total number of variables (isl_dim_all) in "local". |
60 | * |
61 | * Other types do not have any meaning for an isl_local object. |
62 | */ |
63 | isl_size isl_local_dim(__isl_keep isl_local *local, enum isl_dim_type type) |
64 | { |
65 | isl_mat *mat = local; |
66 | |
67 | if (!local) |
68 | return isl_size_error; |
69 | if (type == isl_dim_div) |
70 | return isl_mat_rows(mat); |
71 | if (type == isl_dim_all) { |
72 | isl_size cols = isl_mat_cols(mat); |
73 | if (cols < 0) |
74 | return isl_size_error; |
75 | return cols - 2; |
76 | } |
77 | if (type == isl_dim_set) { |
78 | isl_size total, n_div; |
79 | |
80 | total = isl_local_dim(local, type: isl_dim_all); |
81 | n_div = isl_local_dim(local, type: isl_dim_div); |
82 | if (total < 0 || n_div < 0) |
83 | return isl_size_error; |
84 | return total - n_div; |
85 | } |
86 | isl_die(isl_local_get_ctx(local), isl_error_unsupported, |
87 | "unsupported dimension type" , return isl_size_error); |
88 | } |
89 | |
90 | #undef TYPE |
91 | #define TYPE isl_local |
92 | static |
93 | #include "check_type_range_templ.c" |
94 | |
95 | /* Check that "pos" is a valid position for a variable in "local". |
96 | */ |
97 | static isl_stat isl_local_check_pos(__isl_keep isl_local *local, int pos) |
98 | { |
99 | return isl_local_check_range(obj: local, type: isl_dim_div, first: pos, n: 1); |
100 | } |
101 | |
102 | /* Given local variables "local", |
103 | * is the variable at position "pos" marked as not having |
104 | * an explicit representation? |
105 | * Note that even if this variable is not marked in this way and therefore |
106 | * does have an explicit representation, this representation may still |
107 | * depend (indirectly) on other local variables that do not |
108 | * have an explicit representation. |
109 | */ |
110 | isl_bool isl_local_div_is_marked_unknown(__isl_keep isl_local *local, int pos) |
111 | { |
112 | isl_mat *mat = local; |
113 | |
114 | if (isl_local_check_pos(local, pos) < 0) |
115 | return isl_bool_error; |
116 | return isl_bool_ok(isl_int_is_zero(mat->row[pos][0])); |
117 | } |
118 | |
119 | /* Given local variables "local", |
120 | * does the variable at position "pos" have a complete explicit representation? |
121 | * Having a complete explicit representation requires not only |
122 | * an explicit representation, but also that all local variables |
123 | * that appear in this explicit representation in turn have |
124 | * a complete explicit representation. |
125 | */ |
126 | isl_bool isl_local_div_is_known(__isl_keep isl_local *local, int pos) |
127 | { |
128 | isl_bool marked; |
129 | int i, off; |
130 | isl_size n, cols; |
131 | isl_mat *mat = local; |
132 | |
133 | if (isl_local_check_pos(local, pos) < 0) |
134 | return isl_bool_error; |
135 | |
136 | marked = isl_local_div_is_marked_unknown(local, pos); |
137 | if (marked < 0 || marked) |
138 | return isl_bool_not(b: marked); |
139 | |
140 | n = isl_local_dim(local, type: isl_dim_div); |
141 | cols = isl_mat_cols(mat); |
142 | if (n < 0 || cols < 0) |
143 | return isl_bool_error; |
144 | off = cols - n; |
145 | |
146 | for (i = n - 1; i >= 0; --i) { |
147 | isl_bool known; |
148 | |
149 | if (isl_int_is_zero(mat->row[pos][off + i])) |
150 | continue; |
151 | known = isl_local_div_is_known(local, pos: i); |
152 | if (known < 0 || !known) |
153 | return known; |
154 | } |
155 | |
156 | return isl_bool_true; |
157 | } |
158 | |
159 | /* Does "local" have an explicit representation for all local variables? |
160 | */ |
161 | isl_bool isl_local_divs_known(__isl_keep isl_local *local) |
162 | { |
163 | int i; |
164 | isl_size n; |
165 | |
166 | n = isl_local_dim(local, type: isl_dim_div); |
167 | if (n < 0) |
168 | return isl_bool_error; |
169 | |
170 | for (i = 0; i < n; ++i) { |
171 | isl_bool unknown = isl_local_div_is_marked_unknown(local, pos: i); |
172 | if (unknown < 0 || unknown) |
173 | return isl_bool_not(b: unknown); |
174 | } |
175 | |
176 | return isl_bool_true; |
177 | } |
178 | |
179 | /* Compare two sets of local variables, defined over |
180 | * the same space. |
181 | * |
182 | * Return -1 if "local1" is "smaller" than "local2", 1 if "local1" is "greater" |
183 | * than "local2" and 0 if they are equal. |
184 | * |
185 | * The order is fairly arbitrary. We do "prefer" divs that only involve |
186 | * earlier dimensions in the sense that we consider matrices where |
187 | * the first differing div involves earlier dimensions to be smaller. |
188 | */ |
189 | int isl_local_cmp(__isl_keep isl_local *local1, __isl_keep isl_local *local2) |
190 | { |
191 | int i; |
192 | int cmp; |
193 | isl_bool unknown1, unknown2; |
194 | int last1, last2; |
195 | isl_size n_col; |
196 | isl_mat *mat1 = local1; |
197 | isl_mat *mat2 = local2; |
198 | |
199 | if (local1 == local2) |
200 | return 0; |
201 | if (!local1) |
202 | return -1; |
203 | if (!local2) |
204 | return 1; |
205 | |
206 | if (mat1->n_row != mat2->n_row) |
207 | return mat1->n_row - mat2->n_row; |
208 | |
209 | n_col = isl_mat_cols(mat: mat1); |
210 | if (n_col < 0) |
211 | return -1; |
212 | for (i = 0; i < mat1->n_row; ++i) { |
213 | unknown1 = isl_local_div_is_marked_unknown(local: local1, pos: i); |
214 | unknown2 = isl_local_div_is_marked_unknown(local: local2, pos: i); |
215 | if (unknown1 && unknown2) |
216 | continue; |
217 | if (unknown1) |
218 | return 1; |
219 | if (unknown2) |
220 | return -1; |
221 | last1 = isl_seq_last_non_zero(p: mat1->row[i] + 1, len: n_col - 1); |
222 | last2 = isl_seq_last_non_zero(p: mat2->row[i] + 1, len: n_col - 1); |
223 | if (last1 != last2) |
224 | return last1 - last2; |
225 | cmp = isl_seq_cmp(p1: mat1->row[i], p2: mat2->row[i], len: n_col); |
226 | if (cmp != 0) |
227 | return cmp; |
228 | } |
229 | |
230 | return 0; |
231 | } |
232 | |
233 | /* Return the position of the variables of the given type |
234 | * within the sequence of variables of "local". |
235 | * |
236 | * Only the position of the local variables can be obtained. |
237 | * It is equal to the total number of variables minus |
238 | * the number of local variables. |
239 | */ |
240 | isl_size isl_local_var_offset(__isl_keep isl_local *local, |
241 | enum isl_dim_type type) |
242 | { |
243 | isl_size n_div, n_all; |
244 | |
245 | if (!local) |
246 | return isl_size_error; |
247 | if (type != isl_dim_div) |
248 | isl_die(isl_local_get_ctx(local), isl_error_unsupported, |
249 | "only the offset of the local variables " |
250 | "can be obtained" , return isl_size_error); |
251 | |
252 | n_div = isl_local_dim(local, type: isl_dim_div); |
253 | n_all = isl_local_dim(local, type: isl_dim_all); |
254 | if (n_div < 0 || n_all < 0) |
255 | return isl_size_error; |
256 | return n_all - n_div; |
257 | } |
258 | |
259 | /* Reorder the columns of the given local variables according to the |
260 | * given reordering. |
261 | * The order of the local variables themselves is assumed not to change. |
262 | */ |
263 | __isl_give isl_local *isl_local_reorder(__isl_take isl_local *local, |
264 | __isl_take isl_reordering *r) |
265 | { |
266 | isl_mat *div = local; |
267 | int i, j; |
268 | isl_mat *mat; |
269 | int ; |
270 | |
271 | if (!local || !r) |
272 | goto error; |
273 | |
274 | extra = r->dst_len - r->src_len; |
275 | mat = isl_mat_alloc(ctx: div->ctx, n_row: div->n_row, n_col: div->n_col + extra); |
276 | if (!mat) |
277 | goto error; |
278 | |
279 | for (i = 0; i < div->n_row; ++i) { |
280 | isl_seq_cpy(dst: mat->row[i], src: div->row[i], len: 2); |
281 | isl_seq_clr(p: mat->row[i] + 2, len: mat->n_col - 2); |
282 | for (j = 0; j < r->src_len; ++j) |
283 | isl_int_set(mat->row[i][2 + r->pos[j]], |
284 | div->row[i][2 + j]); |
285 | } |
286 | |
287 | isl_reordering_free(exp: r); |
288 | isl_local_free(local); |
289 | return isl_local_alloc_from_mat(mat); |
290 | error: |
291 | isl_reordering_free(exp: r); |
292 | isl_local_free(local); |
293 | return NULL; |
294 | } |
295 | |
296 | /* Move the "n" variables starting at "src_pos" of "local" to "dst_pos". |
297 | * |
298 | * Moving local variables is not allowed. |
299 | */ |
300 | __isl_give isl_local *isl_local_move_vars(__isl_take isl_local *local, |
301 | unsigned dst_pos, unsigned src_pos, unsigned n) |
302 | { |
303 | isl_mat *mat = local; |
304 | isl_size v_div; |
305 | |
306 | v_div = isl_local_var_offset(local, type: isl_dim_div); |
307 | if (v_div < 0) |
308 | return isl_local_free(local); |
309 | if (n == 0) |
310 | return local; |
311 | |
312 | if (dst_pos >= v_div || src_pos >= v_div) |
313 | isl_die(isl_local_get_ctx(local), isl_error_invalid, |
314 | "cannot move local variables" , |
315 | return isl_local_free(local)); |
316 | |
317 | mat = isl_mat_move_cols(mat, dst_col: 2 + dst_pos, src_col: 2 + src_pos, n); |
318 | |
319 | return isl_local_alloc_from_mat(mat); |
320 | } |
321 | |
322 | /* Extend a vector "v" representing an integer point |
323 | * in the domain space of "local" |
324 | * to one that also includes values for the local variables. |
325 | * All local variables are required to have an explicit representation. |
326 | * If there are no local variables, then the point is not required |
327 | * to be integral. |
328 | */ |
329 | __isl_give isl_vec *isl_local_extend_point_vec(__isl_keep isl_local *local, |
330 | __isl_take isl_vec *v) |
331 | { |
332 | isl_size dim, n_div, size; |
333 | isl_bool known; |
334 | isl_mat *mat = local; |
335 | |
336 | if (!local || !v) |
337 | return isl_vec_free(vec: v); |
338 | known = isl_local_divs_known(local); |
339 | if (known < 0) |
340 | return isl_vec_free(vec: v); |
341 | if (!known) |
342 | isl_die(isl_local_get_ctx(local), isl_error_invalid, |
343 | "unknown local variables" , return isl_vec_free(v)); |
344 | dim = isl_local_dim(local, type: isl_dim_set); |
345 | n_div = isl_local_dim(local, type: isl_dim_div); |
346 | size = isl_vec_size(vec: v); |
347 | if (dim < 0 || n_div < 0 || size < 0) |
348 | return isl_vec_free(vec: v); |
349 | if (size != 1 + dim) |
350 | isl_die(isl_local_get_ctx(local), isl_error_invalid, |
351 | "incorrect size" , return isl_vec_free(v)); |
352 | if (n_div == 0) |
353 | return v; |
354 | if (!isl_int_is_one(v->el[0])) |
355 | isl_die(isl_local_get_ctx(local), isl_error_invalid, |
356 | "expecting integer point" , return isl_vec_free(v)); |
357 | { |
358 | int i; |
359 | v = isl_vec_add_els(vec: v, n: n_div); |
360 | if (!v) |
361 | return NULL; |
362 | |
363 | for (i = 0; i < n_div; ++i) { |
364 | isl_seq_inner_product(p1: mat->row[i] + 1, p2: v->el, |
365 | len: 1 + dim + i, prod: &v->el[1+dim+i]); |
366 | isl_int_fdiv_q(v->el[1+dim+i], v->el[1+dim+i], |
367 | mat->row[i][0]); |
368 | } |
369 | } |
370 | |
371 | return v; |
372 | } |
373 | |