/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/External/isl/isl_factorization.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2005-2007 Universiteit Leiden |
3 | | * Copyright 2008-2009 Katholieke Universiteit Leuven |
4 | | * Copyright 2010 INRIA Saclay |
5 | | * |
6 | | * Use of this software is governed by the MIT license |
7 | | * |
8 | | * Written by Sven Verdoolaege, Leiden Institute of Advanced Computer Science, |
9 | | * Universiteit Leiden, Niels Bohrweg 1, 2333 CA Leiden, The Netherlands |
10 | | * and K.U.Leuven, Departement Computerwetenschappen, Celestijnenlaan 200A, |
11 | | * B-3001 Leuven, Belgium |
12 | | * and INRIA Saclay - Ile-de-France, Parc Club Orsay Universite, |
13 | | * ZAC des vignes, 4 rue Jacques Monod, 91893 Orsay, France |
14 | | */ |
15 | | |
16 | | #include <isl_map_private.h> |
17 | | #include <isl_factorization.h> |
18 | | #include <isl_space_private.h> |
19 | | #include <isl_mat_private.h> |
20 | | |
21 | | static __isl_give isl_factorizer *isl_factorizer_alloc( |
22 | | __isl_take isl_morph *morph, int n_group) |
23 | 198k | { |
24 | 198k | isl_factorizer *f = NULL; |
25 | 198k | int *len = NULL; |
26 | 198k | |
27 | 198k | if (!morph) |
28 | 0 | return NULL; |
29 | 198k | |
30 | 198k | if (n_group > 0) { |
31 | 94.0k | len = isl_alloc_array(morph->dom->ctx, int, n_group); |
32 | 94.0k | if (!len) |
33 | 0 | goto error; |
34 | 198k | } |
35 | 198k | |
36 | 198k | f = isl_alloc_type(morph->dom->ctx, struct isl_factorizer); |
37 | 198k | if (!f) |
38 | 0 | goto error; |
39 | 198k | |
40 | 198k | f->morph = morph; |
41 | 198k | f->n_group = n_group; |
42 | 198k | f->len = len; |
43 | 198k | |
44 | 198k | return f; |
45 | 0 | error: |
46 | 0 | free(len); |
47 | 0 | isl_morph_free(morph); |
48 | 0 | return NULL; |
49 | 198k | } |
50 | | |
51 | | void isl_factorizer_free(__isl_take isl_factorizer *f) |
52 | 198k | { |
53 | 198k | if (!f) |
54 | 0 | return; |
55 | 198k | |
56 | 198k | isl_morph_free(f->morph); |
57 | 198k | free(f->len); |
58 | 198k | free(f); |
59 | 198k | } |
60 | | |
61 | | void isl_factorizer_dump(__isl_take isl_factorizer *f) |
62 | 0 | { |
63 | 0 | int i; |
64 | 0 |
|
65 | 0 | if (!f) |
66 | 0 | return; |
67 | 0 | |
68 | 0 | isl_morph_print_internal(f->morph, stderr); |
69 | 0 | fprintf(stderr, "["); |
70 | 0 | for (i = 0; i < f->n_group; ++i) { |
71 | 0 | if (i) |
72 | 0 | fprintf(stderr, ", "); |
73 | 0 | fprintf(stderr, "%d", f->len[i]); |
74 | 0 | } |
75 | 0 | fprintf(stderr, "]\n"); |
76 | 0 | } |
77 | | |
78 | | __isl_give isl_factorizer *isl_factorizer_identity(__isl_keep isl_basic_set *bset) |
79 | 104k | { |
80 | 104k | return isl_factorizer_alloc(isl_morph_identity(bset), 0); |
81 | 104k | } |
82 | | |
83 | | __isl_give isl_factorizer *isl_factorizer_groups(__isl_keep isl_basic_set *bset, |
84 | | __isl_take isl_mat *Q, __isl_take isl_mat *U, int n, int *len) |
85 | 94.0k | { |
86 | 94.0k | int i; |
87 | 94.0k | unsigned nvar; |
88 | 94.0k | unsigned ovar; |
89 | 94.0k | isl_space *dim; |
90 | 94.0k | isl_basic_set *dom; |
91 | 94.0k | isl_basic_set *ran; |
92 | 94.0k | isl_morph *morph; |
93 | 94.0k | isl_factorizer *f; |
94 | 94.0k | isl_mat *id; |
95 | 94.0k | |
96 | 94.0k | if (!bset || !Q || !U) |
97 | 0 | goto error; |
98 | 94.0k | |
99 | 94.0k | ovar = 1 + isl_space_offset(bset->dim, isl_dim_set); |
100 | 94.0k | id = isl_mat_identity(bset->ctx, ovar); |
101 | 94.0k | Q = isl_mat_diagonal(isl_mat_copy(id), Q); |
102 | 94.0k | U = isl_mat_diagonal(id, U); |
103 | 94.0k | |
104 | 94.0k | nvar = isl_basic_set_dim(bset, isl_dim_set); |
105 | 94.0k | dim = isl_basic_set_get_space(bset); |
106 | 94.0k | dom = isl_basic_set_universe(isl_space_copy(dim)); |
107 | 94.0k | dim = isl_space_drop_dims(dim, isl_dim_set, 0, nvar); |
108 | 94.0k | dim = isl_space_add_dims(dim, isl_dim_set, nvar); |
109 | 94.0k | ran = isl_basic_set_universe(dim); |
110 | 94.0k | morph = isl_morph_alloc(dom, ran, Q, U); |
111 | 94.0k | f = isl_factorizer_alloc(morph, n); |
112 | 94.0k | if (!f) |
113 | 0 | return NULL; |
114 | 419k | for (i = 0; 94.0k i < n; ++i325k ) |
115 | 325k | f->len[i] = len[i]; |
116 | 94.0k | return f; |
117 | 0 | error: |
118 | 0 | isl_mat_free(Q); |
119 | 0 | isl_mat_free(U); |
120 | 0 | return NULL; |
121 | 94.0k | } |
122 | | |
123 | | struct isl_factor_groups { |
124 | | int *pos; /* for each column: row position of pivot */ |
125 | | int *group; /* group to which a column belongs */ |
126 | | int *cnt; /* number of columns in the group */ |
127 | | int *rowgroup; /* group to which a constraint belongs */ |
128 | | }; |
129 | | |
130 | | /* Initialize isl_factor_groups structure: find pivot row positions, |
131 | | * each column initially belongs to its own group and the groups |
132 | | * of the constraints are still unknown. |
133 | | */ |
134 | | static int init_groups(struct isl_factor_groups *g, __isl_keep isl_mat *H) |
135 | 198k | { |
136 | 198k | int i, j; |
137 | 198k | |
138 | 198k | if (!H) |
139 | 0 | return -1; |
140 | 198k | |
141 | 198k | g->pos = isl_alloc_array(H->ctx, int, H->n_col); |
142 | 198k | g->group = isl_alloc_array(H->ctx, int, H->n_col); |
143 | 198k | g->cnt = isl_alloc_array(H->ctx, int, H->n_col); |
144 | 198k | g->rowgroup = isl_alloc_array(H->ctx, int, H->n_row); |
145 | 198k | |
146 | 198k | if (!g->pos || !g->group || !g->cnt || !g->rowgroup) |
147 | 0 | return -1; |
148 | 198k | |
149 | 1.62M | for (i = 0; 198k i < H->n_row; ++i1.42M ) |
150 | 1.42M | g->rowgroup[i] = -1; |
151 | 878k | for (i = 0, j = 0; i < H->n_col; ++i680k ) { |
152 | 1.47M | for ( ; j < H->n_row; ++j797k ) |
153 | 1.47M | if (!isl_int_is_zero(H->row[j][i])) |
154 | 1.47M | break680k ; |
155 | 680k | g->pos[i] = j; |
156 | 680k | } |
157 | 878k | for (i = 0; i < H->n_col; ++i680k ) { |
158 | 680k | g->group[i] = i; |
159 | 680k | g->cnt[i] = 1; |
160 | 680k | } |
161 | 198k | |
162 | 198k | return 0; |
163 | 198k | } |
164 | | |
165 | | /* Update group[k] to the group column k belongs to. |
166 | | * When merging two groups, only the group of the current |
167 | | * group leader is changed. Here we change the group of |
168 | | * the other members to also point to the group that the |
169 | | * old group leader now points to. |
170 | | */ |
171 | | static void update_group(struct isl_factor_groups *g, int k) |
172 | 2.53M | { |
173 | 2.53M | int p = g->group[k]; |
174 | 2.53M | while (g->cnt[p] == 0) |
175 | 170 | p = g->group[p]; |
176 | 2.53M | g->group[k] = p; |
177 | 2.53M | } |
178 | | |
179 | | /* Merge group i with all groups of the subsequent columns |
180 | | * with non-zero coefficients in row j of H. |
181 | | * (The previous columns are all zero; otherwise we would have handled |
182 | | * the row before.) |
183 | | */ |
184 | | static int update_group_i_with_row_j(struct isl_factor_groups *g, int i, int j, |
185 | | __isl_keep isl_mat *H) |
186 | 758k | { |
187 | 758k | int k; |
188 | 758k | |
189 | 758k | g->rowgroup[j] = g->group[i]; |
190 | 1.78M | for (k = i + 1; k < H->n_col && j >= g->pos[k]1.35M ; ++k1.02M ) { |
191 | 1.02M | update_group(g, k); |
192 | 1.02M | update_group(g, i); |
193 | 1.02M | if (g->group[k] != g->group[i] && |
194 | 1.02M | !742k isl_int_is_zero742k (H->row[j][k])) { |
195 | 250k | isl_assert(H->ctx, g->cnt[g->group[k]] != 0, return -1); |
196 | 250k | isl_assert(H->ctx, g->cnt[g->group[i]] != 0, return -1); |
197 | 250k | if (g->group[i] < g->group[k]) { |
198 | 249k | g->cnt[g->group[i]] += g->cnt[g->group[k]]; |
199 | 249k | g->cnt[g->group[k]] = 0; |
200 | 249k | g->group[g->group[k]] = g->group[i]; |
201 | 249k | } else { |
202 | 1.01k | g->cnt[g->group[k]] += g->cnt[g->group[i]]; |
203 | 1.01k | g->cnt[g->group[i]] = 0; |
204 | 1.01k | g->group[g->group[i]] = g->group[k]; |
205 | 1.01k | } |
206 | 250k | } |
207 | 1.02M | } |
208 | 758k | |
209 | 758k | return 0; |
210 | 758k | } |
211 | | |
212 | | /* Update the group information based on the constraint matrix. |
213 | | */ |
214 | | static int update_groups(struct isl_factor_groups *g, __isl_keep isl_mat *H) |
215 | 198k | { |
216 | 198k | int i, j; |
217 | 198k | |
218 | 745k | for (i = 0; i < H->n_col && g->cnt[0] < H->n_col651k ; ++i546k ) { |
219 | 546k | if (g->pos[i] == H->n_row) |
220 | 0 | continue; /* A line direction */ |
221 | 546k | if (g->rowgroup[g->pos[i]] == -1) |
222 | 522k | g->rowgroup[g->pos[i]] = i; |
223 | 6.03M | for (j = g->pos[i] + 1; j < H->n_row; ++j5.48M ) { |
224 | 5.48M | if (isl_int_is_zero(H->row[j][i])) |
225 | 5.48M | continue4.57M ; |
226 | 908k | if (g->rowgroup[j] != -1) |
227 | 150k | continue; |
228 | 758k | if (update_group_i_with_row_j(g, i, j, H) < 0) |
229 | 0 | return -1; |
230 | 758k | } |
231 | 546k | } |
232 | 680k | for (i = 1; 198k i < H->n_col; ++i481k ) |
233 | 481k | update_group(g, i); |
234 | 198k | |
235 | 198k | return 0; |
236 | 198k | } |
237 | | |
238 | | static void clear_groups(struct isl_factor_groups *g) |
239 | 198k | { |
240 | 198k | if (!g) |
241 | 0 | return; |
242 | 198k | free(g->pos); |
243 | 198k | free(g->group); |
244 | 198k | free(g->cnt); |
245 | 198k | free(g->rowgroup); |
246 | 198k | } |
247 | | |
248 | | /* Determine if the set variables of the basic set can be factorized and |
249 | | * return the results in an isl_factorizer. |
250 | | * |
251 | | * The algorithm works by first computing the Hermite normal form |
252 | | * and then grouping columns linked by one or more constraints together, |
253 | | * where a constraints "links" two or more columns if the constraint |
254 | | * has nonzero coefficients in the columns. |
255 | | */ |
256 | | __isl_give isl_factorizer *isl_basic_set_factorizer( |
257 | | __isl_keep isl_basic_set *bset) |
258 | 198k | { |
259 | 198k | int i, j, n, done; |
260 | 198k | isl_mat *H, *U, *Q; |
261 | 198k | unsigned nvar; |
262 | 198k | struct isl_factor_groups g = { 0 }; |
263 | 198k | isl_factorizer *f; |
264 | 198k | |
265 | 198k | if (!bset) |
266 | 0 | return NULL; |
267 | 198k | |
268 | 198k | isl_assert(bset->ctx, isl_basic_set_dim(bset, isl_dim_div) == 0, |
269 | 198k | return NULL); |
270 | 198k | |
271 | 198k | nvar = isl_basic_set_dim(bset, isl_dim_set); |
272 | 198k | if (nvar <= 1) |
273 | 1 | return isl_factorizer_identity(bset); |
274 | 198k | |
275 | 198k | H = isl_mat_alloc(bset->ctx, bset->n_eq + bset->n_ineq, nvar); |
276 | 198k | if (!H) |
277 | 0 | return NULL; |
278 | 198k | isl_mat_sub_copy(bset->ctx, H->row, bset->eq, bset->n_eq, |
279 | 198k | 0, 1 + isl_space_offset(bset->dim, isl_dim_set), nvar); |
280 | 198k | isl_mat_sub_copy(bset->ctx, H->row + bset->n_eq, bset->ineq, bset->n_ineq, |
281 | 198k | 0, 1 + isl_space_offset(bset->dim, isl_dim_set), nvar); |
282 | 198k | H = isl_mat_left_hermite(H, 0, &U, &Q); |
283 | 198k | |
284 | 198k | if (init_groups(&g, H) < 0) |
285 | 0 | goto error; |
286 | 198k | if (update_groups(&g, H) < 0) |
287 | 0 | goto error; |
288 | 198k | |
289 | 198k | if (g.cnt[0] == nvar) { |
290 | 104k | isl_mat_free(H); |
291 | 104k | isl_mat_free(U); |
292 | 104k | isl_mat_free(Q); |
293 | 104k | clear_groups(&g); |
294 | 104k | |
295 | 104k | return isl_factorizer_identity(bset); |
296 | 104k | } |
297 | 94.0k | |
298 | 94.0k | done = 0; |
299 | 94.0k | n = 0; |
300 | 419k | while (done != nvar) { |
301 | 325k | int group = g.group[done]; |
302 | 439k | for (i = 1; i < g.cnt[group]; ++i113k ) { |
303 | 113k | if (g.group[done + i] == group) |
304 | 64.4k | continue; |
305 | 116k | for (j = done + g.cnt[group]; 49.4k j < nvar; ++j67.2k ) |
306 | 116k | if (g.group[j] == group) |
307 | 49.4k | break; |
308 | 49.4k | if (j == nvar) |
309 | 49.4k | isl_die0 (bset->ctx, isl_error_internal, |
310 | 49.4k | "internal error", goto error); |
311 | 49.4k | g.group[j] = g.group[done + i]; |
312 | 49.4k | Q = isl_mat_swap_rows(Q, done + i, j); |
313 | 49.4k | U = isl_mat_swap_cols(U, done + i, j); |
314 | 49.4k | } |
315 | 325k | done += g.cnt[group]; |
316 | 325k | g.pos[n++] = g.cnt[group]; |
317 | 325k | } |
318 | 94.0k | |
319 | 94.0k | f = isl_factorizer_groups(bset, Q, U, n, g.pos); |
320 | 94.0k | |
321 | 94.0k | isl_mat_free(H); |
322 | 94.0k | clear_groups(&g); |
323 | 94.0k | |
324 | 94.0k | return f; |
325 | 0 | error: |
326 | 0 | isl_mat_free(H); |
327 | 0 | isl_mat_free(U); |
328 | 0 | isl_mat_free(Q); |
329 | 0 | clear_groups(&g); |
330 | 0 | return NULL; |
331 | 94.0k | } |