/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/polly/lib/External/isl/basis_reduction_tab.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2008-2009 Katholieke Universiteit Leuven |
3 | | * |
4 | | * Use of this software is governed by the MIT license |
5 | | * |
6 | | * Written by Sven Verdoolaege, K.U.Leuven, Departement |
7 | | * Computerwetenschappen, Celestijnenlaan 200A, B-3001 Leuven, Belgium |
8 | | */ |
9 | | |
10 | | #include <assert.h> |
11 | | #include <isl_map_private.h> |
12 | | #include <isl_seq.h> |
13 | | #include "isl_tab.h" |
14 | | #include <isl_int.h> |
15 | | #include <isl_config.h> |
16 | | |
17 | | struct tab_lp { |
18 | | struct isl_ctx *ctx; |
19 | | struct isl_vec *row; |
20 | | struct isl_tab *tab; |
21 | | struct isl_tab_undo **stack; |
22 | | isl_int *obj; |
23 | | isl_int opt; |
24 | | isl_int opt_denom; |
25 | | isl_int tmp; |
26 | | isl_int tmp2; |
27 | | int neq; |
28 | | unsigned dim; |
29 | | /* number of constraints in initial product tableau */ |
30 | | int con_offset; |
31 | | /* objective function has fixed or no integer value */ |
32 | | int is_fixed; |
33 | | }; |
34 | | |
35 | | #ifdef USE_GMP_FOR_MP |
36 | | #define GBR_type mpq_t |
37 | | #define GBR_init(v) mpq_init(v) |
38 | | #define GBR_clear(v) mpq_clear(v) |
39 | | #define GBR_set(a,b) mpq_set(a,b) |
40 | | #define GBR_set_ui(a,b) mpq_set_ui(a,b,1) |
41 | | #define GBR_mul(a,b,c) mpq_mul(a,b,c) |
42 | | #define GBR_lt(a,b) (mpq_cmp(a,b) < 0) |
43 | | #define GBR_is_zero(a) (mpq_sgn(a) == 0) |
44 | | #define GBR_numref(a) mpq_numref(a) |
45 | | #define GBR_denref(a) mpq_denref(a) |
46 | | #define GBR_floor(a,b) mpz_fdiv_q(a,GBR_numref(b),GBR_denref(b)) |
47 | | #define GBR_ceil(a,b) mpz_cdiv_q(a,GBR_numref(b),GBR_denref(b)) |
48 | | #define GBR_set_num_neg(a, b) mpz_neg(GBR_numref(*a), b); |
49 | | #define GBR_set_den(a, b) mpz_set(GBR_denref(*a), b); |
50 | | #endif /* USE_GMP_FOR_MP */ |
51 | | |
52 | | #ifdef USE_IMATH_FOR_MP |
53 | | #include <imrat.h> |
54 | | |
55 | 54.7k | #define GBR_type mp_rat |
56 | 178k | #define GBR_init(v) v = mp_rat_alloc() |
57 | 178k | #define GBR_clear(v) mp_rat_free(v) |
58 | 468k | #define GBR_set(a,b) mp_rat_copy(b,a) |
59 | 229k | #define GBR_set_ui(a,b) mp_rat_set_uvalue(a,b,1) |
60 | 215k | #define GBR_mul(a,b,c) mp_rat_mul(b,c,a) |
61 | 141k | #define GBR_lt(a,b) (mp_rat_compare(a,b) < 0) |
62 | 0 | #define GBR_is_zero(a) (mp_rat_compare_zero(a) == 0) |
63 | | #ifdef USE_SMALL_INT_OPT |
64 | 215k | #define GBR_numref(a) isl_sioimath_encode_big(mp_rat_numer_ref(a)) |
65 | 215k | #define GBR_denref(a) isl_sioimath_encode_big(mp_rat_denom_ref(a)) |
66 | 107k | #define GBR_floor(a, b) isl_sioimath_fdiv_q((a), GBR_numref(b), GBR_denref(b)) |
67 | 107k | #define GBR_ceil(a, b) isl_sioimath_cdiv_q((a), GBR_numref(b), GBR_denref(b)) |
68 | | #define GBR_set_num_neg(a, b) \ |
69 | 376k | do { \ |
70 | 376k | isl_sioimath_scratchspace_t scratch; \ |
71 | 376k | impz_neg(mp_rat_numer_ref(*a), \ |
72 | 376k | isl_sioimath_bigarg_src(*b, &scratch));\ |
73 | 376k | } while (0) |
74 | | #define GBR_set_den(a, b) \ |
75 | 376k | do { \ |
76 | 376k | isl_sioimath_scratchspace_t scratch; \ |
77 | 376k | impz_set(mp_rat_denom_ref(*a), \ |
78 | 376k | isl_sioimath_bigarg_src(*b, &scratch));\ |
79 | 376k | } while (0) |
80 | | #else /* USE_SMALL_INT_OPT */ |
81 | | #define GBR_numref(a) mp_rat_numer_ref(a) |
82 | | #define GBR_denref(a) mp_rat_denom_ref(a) |
83 | | #define GBR_floor(a,b) impz_fdiv_q(a,GBR_numref(b),GBR_denref(b)) |
84 | | #define GBR_ceil(a,b) impz_cdiv_q(a,GBR_numref(b),GBR_denref(b)) |
85 | | #define GBR_set_num_neg(a, b) impz_neg(GBR_numref(*a), b) |
86 | | #define GBR_set_den(a, b) impz_set(GBR_denref(*a), b) |
87 | | #endif /* USE_SMALL_INT_OPT */ |
88 | | #endif /* USE_IMATH_FOR_MP */ |
89 | | |
90 | | static struct tab_lp *init_lp(struct isl_tab *tab); |
91 | | static void set_lp_obj(struct tab_lp *lp, isl_int *row, int dim); |
92 | | static int solve_lp(struct tab_lp *lp); |
93 | | static void get_obj_val(struct tab_lp* lp, GBR_type *F); |
94 | | static void delete_lp(struct tab_lp *lp); |
95 | | static int add_lp_row(struct tab_lp *lp, isl_int *row, int dim); |
96 | | static void get_alpha(struct tab_lp* lp, int row, GBR_type *alpha); |
97 | | static int del_lp_row(struct tab_lp *lp) WARN_UNUSED; |
98 | | static int cut_lp_to_hyperplane(struct tab_lp *lp, isl_int *row); |
99 | | |
100 | 6.84k | #define GBR_LP struct tab_lp |
101 | 6.84k | #define GBR_lp_init(P) init_lp(P) |
102 | 102k | #define GBR_lp_set_obj(lp, obj, dim) set_lp_obj(lp, obj, dim) |
103 | 102k | #define GBR_lp_solve(lp) solve_lp(lp) |
104 | 205k | #define GBR_lp_get_obj_val(lp, F) get_obj_val(lp, F) |
105 | 6.84k | #define GBR_lp_delete(lp) delete_lp(lp) |
106 | 39.4k | #define GBR_lp_next_row(lp) lp->neq |
107 | 123k | #define GBR_lp_add_row(lp, row, dim) add_lp_row(lp, row, dim) |
108 | 273k | #define GBR_lp_get_alpha(lp, row, alpha) get_alpha(lp, row, alpha) |
109 | 107k | #define GBR_lp_del_row(lp) del_lp_row(lp) |
110 | 95.9k | #define GBR_lp_is_fixed(lp) (lp)->is_fixed |
111 | 0 | #define GBR_lp_cut(lp, obj) cut_lp_to_hyperplane(lp, obj) |
112 | | #include "basis_reduction_templ.c" |
113 | | |
114 | | /* Set up a tableau for the Cartesian product of bset with itself. |
115 | | * This could be optimized by first setting up a tableau for bset |
116 | | * and then performing the Cartesian product on the tableau. |
117 | | */ |
118 | | static struct isl_tab *gbr_tab(struct isl_tab *tab, struct isl_vec *row) |
119 | 6.84k | { |
120 | 6.84k | unsigned dim; |
121 | 6.84k | struct isl_tab *prod; |
122 | 6.84k | |
123 | 6.84k | if (!tab || !row) |
124 | 0 | return NULL; |
125 | 6.84k | |
126 | 6.84k | dim = tab->n_var; |
127 | 6.84k | prod = isl_tab_product(tab, tab); |
128 | 6.84k | if (isl_tab_extend_cons(prod, 3 * dim + 1) < 0) { |
129 | 0 | isl_tab_free(prod); |
130 | 0 | return NULL; |
131 | 0 | } |
132 | 6.84k | return prod; |
133 | 6.84k | } |
134 | | |
135 | | static struct tab_lp *init_lp(struct isl_tab *tab) |
136 | 6.84k | { |
137 | 6.84k | struct tab_lp *lp = NULL; |
138 | 6.84k | |
139 | 6.84k | if (!tab) |
140 | 0 | return NULL; |
141 | 6.84k | |
142 | 6.84k | lp = isl_calloc_type(tab->mat->ctx, struct tab_lp); |
143 | 6.84k | if (!lp) |
144 | 0 | return NULL; |
145 | 6.84k | |
146 | 6.84k | isl_int_init(lp->opt); |
147 | 6.84k | isl_int_init(lp->opt_denom); |
148 | 6.84k | isl_int_init(lp->tmp); |
149 | 6.84k | isl_int_init(lp->tmp2); |
150 | 6.84k | |
151 | 6.84k | lp->dim = tab->n_var; |
152 | 6.84k | |
153 | 6.84k | lp->ctx = tab->mat->ctx; |
154 | 6.84k | isl_ctx_ref(lp->ctx); |
155 | 6.84k | |
156 | 6.84k | lp->stack = isl_alloc_array(lp->ctx, struct isl_tab_undo *, lp->dim); |
157 | 6.84k | |
158 | 6.84k | lp->row = isl_vec_alloc(lp->ctx, 1 + 2 * lp->dim); |
159 | 6.84k | if (!lp->row) |
160 | 0 | goto error; |
161 | 6.84k | lp->tab = gbr_tab(tab, lp->row); |
162 | 6.84k | if (!lp->tab) |
163 | 0 | goto error; |
164 | 6.84k | lp->con_offset = lp->tab->n_con; |
165 | 6.84k | lp->obj = NULL; |
166 | 6.84k | lp->neq = 0; |
167 | 6.84k | |
168 | 6.84k | return lp; |
169 | 0 | error: |
170 | 0 | delete_lp(lp); |
171 | 0 | return NULL; |
172 | 6.84k | } |
173 | | |
174 | | static void set_lp_obj(struct tab_lp *lp, isl_int *row, int dim) |
175 | 102k | { |
176 | 102k | lp->obj = row; |
177 | 102k | } |
178 | | |
179 | | static int solve_lp(struct tab_lp *lp) |
180 | 102k | { |
181 | 102k | enum isl_lp_result res; |
182 | 102k | unsigned flags = 0; |
183 | 102k | |
184 | 102k | lp->is_fixed = 0; |
185 | 102k | |
186 | 102k | isl_int_set_si(lp->row->el[0], 0); |
187 | 102k | isl_seq_cpy(lp->row->el + 1, lp->obj, lp->dim); |
188 | 102k | isl_seq_neg(lp->row->el + 1 + lp->dim, lp->obj, lp->dim); |
189 | 102k | if (lp->neq) |
190 | 84.2k | flags = ISL_TAB_SAVE_DUAL; |
191 | 102k | res = isl_tab_min(lp->tab, lp->row->el, lp->ctx->one, |
192 | 102k | &lp->opt, &lp->opt_denom, flags); |
193 | 102k | isl_int_mul_ui(lp->opt_denom, lp->opt_denom, 2); |
194 | 102k | if (isl_int_abs_lt(lp->opt, lp->opt_denom)) { |
195 | 13.0k | struct isl_vec *sample = isl_tab_get_sample_value(lp->tab); |
196 | 13.0k | if (!sample) |
197 | 0 | return -1; |
198 | 13.0k | isl_seq_inner_product(lp->obj, sample->el + 1, lp->dim, &lp->tmp); |
199 | 13.0k | isl_seq_inner_product(lp->obj, sample->el + 1 + lp->dim, lp->dim, &lp->tmp2); |
200 | 13.0k | isl_int_cdiv_q(lp->tmp, lp->tmp, sample->el[0]); |
201 | 13.0k | isl_int_fdiv_q(lp->tmp2, lp->tmp2, sample->el[0]); |
202 | 13.0k | if (isl_int_ge(lp->tmp, lp->tmp2)) |
203 | 13.0k | lp->is_fixed = 110.6k ; |
204 | 13.0k | isl_vec_free(sample); |
205 | 13.0k | } |
206 | 102k | isl_int_divexact_ui(lp->opt_denom, lp->opt_denom, 2); |
207 | 102k | if (res < 0) |
208 | 0 | return -1; |
209 | 102k | if (res != isl_lp_ok) |
210 | 102k | isl_die0 (lp->ctx, isl_error_internal, |
211 | 102k | "unexpected missing (bounded) solution", return -1); |
212 | 102k | return 0; |
213 | 102k | } |
214 | | |
215 | | /* The current objective function has a fixed (or no) integer value. |
216 | | * Cut the tableau to the hyperplane that fixes this value in |
217 | | * both halves of the tableau. |
218 | | * Return 1 if the resulting tableau is empty. |
219 | | */ |
220 | | static int cut_lp_to_hyperplane(struct tab_lp *lp, isl_int *row) |
221 | 0 | { |
222 | 0 | enum isl_lp_result res; |
223 | 0 |
|
224 | 0 | isl_int_set_si(lp->row->el[0], 0); |
225 | 0 | isl_seq_cpy(lp->row->el + 1, row, lp->dim); |
226 | 0 | isl_seq_clr(lp->row->el + 1 + lp->dim, lp->dim); |
227 | 0 | res = isl_tab_min(lp->tab, lp->row->el, lp->ctx->one, |
228 | 0 | &lp->tmp, NULL, 0); |
229 | 0 | if (res != isl_lp_ok) |
230 | 0 | return -1; |
231 | 0 | |
232 | 0 | isl_int_neg(lp->row->el[0], lp->tmp); |
233 | 0 | if (isl_tab_add_eq(lp->tab, lp->row->el) < 0) |
234 | 0 | return -1; |
235 | 0 | |
236 | 0 | isl_seq_cpy(lp->row->el + 1 + lp->dim, row, lp->dim); |
237 | 0 | isl_seq_clr(lp->row->el + 1, lp->dim); |
238 | 0 | if (isl_tab_add_eq(lp->tab, lp->row->el) < 0) |
239 | 0 | return -1; |
240 | 0 | |
241 | 0 | lp->con_offset += 2; |
242 | 0 |
|
243 | 0 | return lp->tab->empty; |
244 | 0 | } |
245 | | |
246 | | static void get_obj_val(struct tab_lp* lp, GBR_type *F) |
247 | 102k | { |
248 | 102k | GBR_set_num_neg(F, lp->opt); |
249 | 102k | GBR_set_den(F, lp->opt_denom); |
250 | 102k | } |
251 | | |
252 | | static void delete_lp(struct tab_lp *lp) |
253 | 6.84k | { |
254 | 6.84k | if (!lp) |
255 | 0 | return; |
256 | 6.84k | |
257 | 6.84k | isl_int_clear(lp->opt); |
258 | 6.84k | isl_int_clear(lp->opt_denom); |
259 | 6.84k | isl_int_clear(lp->tmp); |
260 | 6.84k | isl_int_clear(lp->tmp2); |
261 | 6.84k | isl_vec_free(lp->row); |
262 | 6.84k | free(lp->stack); |
263 | 6.84k | isl_tab_free(lp->tab); |
264 | 6.84k | isl_ctx_deref(lp->ctx); |
265 | 6.84k | free(lp); |
266 | 6.84k | } |
267 | | |
268 | | static int add_lp_row(struct tab_lp *lp, isl_int *row, int dim) |
269 | 123k | { |
270 | 123k | lp->stack[lp->neq] = isl_tab_snap(lp->tab); |
271 | 123k | |
272 | 123k | isl_int_set_si(lp->row->el[0], 0); |
273 | 123k | isl_seq_cpy(lp->row->el + 1, row, lp->dim); |
274 | 123k | isl_seq_neg(lp->row->el + 1 + lp->dim, row, lp->dim); |
275 | 123k | |
276 | 123k | if (isl_tab_add_valid_eq(lp->tab, lp->row->el) < 0) |
277 | 0 | return -1; |
278 | 123k | |
279 | 123k | return lp->neq++; |
280 | 123k | } |
281 | | |
282 | | static void get_alpha(struct tab_lp* lp, int row, GBR_type *alpha) |
283 | 273k | { |
284 | 273k | row += lp->con_offset; |
285 | 273k | GBR_set_num_neg(alpha, lp->tab->dual->el[1 + row]); |
286 | 273k | GBR_set_den(alpha, lp->tab->dual->el[0]); |
287 | 273k | } |
288 | | |
289 | | static int del_lp_row(struct tab_lp *lp) |
290 | 107k | { |
291 | 107k | lp->neq--; |
292 | 107k | return isl_tab_rollback(lp->tab, lp->stack[lp->neq]); |
293 | 107k | } |