Add piplib.h.in file
[candl.git] / source / pruning.c
blobdb4a90fe6597e24d00cac235eecd4c5fc08fbab7
2 /**------ ( ----------------------------------------------------------**
3 ** )\ CAnDL **
4 **----- / ) --------------------------------------------------------**
5 ** ( * ( pruning.c **
6 **---- \#/ --------------------------------------------------------**
7 ** .-"#'-. First version: July 17th 2011 **
8 **--- |"-.-"| -------------------------------------------------------**
9 | |
10 | |
11 ******** | | *************************************************************
12 * CAnDL '-._,-' the Chunky Analyzer for Dependences in Loops (experimental) *
13 ******************************************************************************
14 * *
15 * Copyright (C) 2003-2008 Cedric Bastoul *
16 * *
17 * This is free software; you can redistribute it and/or modify it under the *
18 * terms of the GNU Lesser General Public License as published by the Free *
19 * Software Foundation; either version 3 of the License, or (at your option) *
20 * any later version. *
21 * *
22 * This software is distributed in the hope that it will be useful, but *
23 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
24 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
25 * for more details. *
26 * *
27 * You should have received a copy of the GNU Lesser General Public License *
28 * along with software; if not, write to the Free Software Foundation, Inc., *
29 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
30 * *
31 * CAnDL, the Chunky Dependence Analyzer *
32 * Written by Cedric Bastoul, Cedric.Bastoul@inria.fr *
33 * *
34 ******************************************************************************/
35 /**
36 * \file pruning.c
37 * \author Louis-Noel Pouchet
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <assert.h>
44 #include <osl/statement.h>
45 #include <osl/relation.h>
46 #include <candl/statement.h>
47 #include <candl/dependence.h>
50 #if defined(CANDL_COMPILE_PRUNNING_C)
53 #define BUFF_SIZE 1024
55 /**
56 * Finds all paths in the graph represented by the list of dependences
57 * 'alldeps', that start from statement label 'tgt_id' and ends at
58 * statement label 'final_id', of length <= 'max_length'.
59 * Paths are stored as list of lists of dependences in 'paths_list'.
61 static
62 void find_paths_rec(int tgt_id, int cur_length, int max_length,
63 int final_id,
64 osl_dependence_p* alldeps,
65 osl_dependence_p* cur_path,
66 osl_dependence_p*** paths_list) {
67 int i;
69 for (i = 0; alldeps[i]; ++i) {
70 if (alldeps[i]->usr == NULL) {
71 ((candl_statement_usr_p)target->usr)->label
72 if (alldeps[i]->((candl_statement_usr_p)source->usr)->label == tgt_id) {
73 // Ensure the path flow is consistent.
74 if (cur_length > 1) {
75 if (cur_path[cur_length - 1]->type == CANDL_RAW ||
76 cur_path[cur_length - 1]->type == CANDL_RAW_SCALPRIV ||
77 cur_path[cur_length - 1]->type == CANDL_RAR) {
78 // RAW or RAR.
79 if (alldeps[i]->type != CANDL_RAR &&
80 alldeps[i]->type != CANDL_WAR)
81 continue;
83 else {
84 // WAW or WAR.
85 if (alldeps[i]->type != CANDL_WAW &&
86 alldeps[i]->type != CANDL_RAW)
87 continue;
90 if (cur_length + 1 == max_length) {
91 if (alldeps[i]->((candl_statement_usr_p)target->usr)->label == final_id) {
92 // Found a path.
93 int j, pos;
94 for (pos = 0; (*paths_list)[pos]; ++pos)
96 if (pos + 1 % BUFF_SIZE == 0) {
97 *paths_list = (osl_dependence_p**)
98 realloc(*paths_list, sizeof(osl_dependence_p*) *
99 (BUFF_SIZE + pos + 1));
100 *paths_list[pos + 1] = NULL;
102 (*paths_list)[pos] = (osl_dependence_p*)
103 malloc((max_length + 1) * sizeof(osl_dependence_p));
104 for (j = 0; j < max_length - 1; ++j)
105 (*paths_list)[pos][j] = cur_path[j];
106 (*paths_list)[pos][j++] = alldeps[i];
107 (*paths_list)[pos][j] = NULL;
110 else {
111 // Store the current node in the path.
112 cur_path[cur_length] = alldeps[i];
113 // Mark the dependence as processed.
114 alldeps[i]->usr = alldeps[i];
115 // Look for the next node.
116 find_paths_rec(alldeps[i]->((candl_statement_usr_p)target->usr)->label,
117 cur_length + 1, max_length, final_id, alldeps,
118 cur_path, paths_list);
119 // Reset the dependence.
120 alldeps[i]->usr = NULL;
129 * Returns a list of list of dependences containing all paths in the
130 * graph represented by the list of dependences 'ardeps', that start
131 * from statement label 'source->label' and ends at statement label
132 * 'target->label'.
134 static
135 osl_dependence_p** find_dep_paths(osl_dependence_p* ardeps,
136 osl_statement_p source,
137 osl_statement_p target) {
138 int i, nb_dep;
139 for (nb_dep = 0; ardeps[nb_dep]; ++nb_dep)
141 if (nb_dep < 2)
142 return NULL;
143 osl_dependence_p *cur_path =
144 (osl_dependence_p*) malloc(sizeof(osl_dependence_p) *
145 (nb_dep + 1));
146 osl_dependence_p** paths_list =
147 (osl_dependence_p**)malloc(BUFF_SIZE * sizeof(osl_dependence_p*));
148 for (i = 0; i < BUFF_SIZE; ++i)
149 paths_list[i] = NULL;
150 // Iterate on all possible paths length, from Sx to Sy, of length y-x.
151 for (i = 2; i <= ((candl_statement_usr_p)target->usr)->label -
152 ((candl_statement_usr_p)source->usr)->label; ++i)
153 find_paths_rec(((candl_statement_usr_p)source->usr)->label, 0, i,
154 ((candl_statement_usr_p)target->usr)->label, ardeps,
155 cur_path, &paths_list);
156 free(cur_path);
157 return paths_list;
162 * Return true if the 'size' first variables in a quast are strictly
163 * equal.
165 static
166 int quast_are_equal (PipQuast* q1, PipQuast* q2, int size) {
167 if (q1 == NULL && q2 == NULL)
168 return 1;
169 if (q1 == NULL || q2 == NULL)
170 return 0;
172 // Inspect conditions.
173 if (q1->condition != NULL && q2->condition != NULL) {
174 PipList c1; c1.next = NULL; c1.vector = q1->condition;
175 PipList c2; c2.next = NULL; c2.vector = q2->condition;
176 if (! piplist_are_equal(&c1, &c2, size))
177 return 0;
178 return quast_are_equal(q1->next_then, q2->next_then, size) &&
179 quast_are_equal(q1->next_else, q2->next_else, size);
181 if (q1->condition != NULL || q2->condition != NULL)
182 return 0;
183 return piplist_are_equal(q1->list, q2->list, size);
187 * Return true if 'dep' is fully covered by the transitive dependences
188 * in 'path'. This is a conservative functions (works only on
189 * unimodular access functions + iteration domains for the sub-matrix
190 * corresponding to loop iterators).
192 static
193 int is_covering(osl_dependence_p dep, osl_dependence_p* path) {
194 int i, path_length;
196 for (path_length = 0; path[path_length]; ++path_length)
199 /// FIXME: This may be overly conservative.
200 // Check the path extremal points type.
201 if (dep->type == CANDL_RAW || dep->type == CANDL_RAW_SCALPRIV
202 || dep->type == CANDL_WAW) {
203 // RAW or WAW.
204 if (path[0]->type != CANDL_RAW && path[0]->type != CANDL_RAW_SCALPRIV &&
205 path[0]->type != CANDL_WAW)
206 return 0;
207 if (dep->type == CANDL_RAW || dep->type == CANDL_RAW_SCALPRIV)
208 if (path[path_length - 1]->type != CANDL_RAW &&
209 path[path_length - 1]->type != CANDL_RAW_SCALPRIV &&
210 path[path_length - 1]->type != CANDL_RAR)
211 return 0;
212 if (dep->type == CANDL_WAW)
213 if (path[path_length - 1]->type != CANDL_WAR &&
214 path[path_length - 1]->type != CANDL_WAW)
215 return 0;
217 else {
218 // WAR or RAR.
219 if (path[0]->type != CANDL_WAR && path[0]->type != CANDL_RAR)
220 return 0;
221 if (dep->type == CANDL_WAR)
222 if (path[path_length - 1]->type != CANDL_WAW &&
223 path[path_length - 1]->type != CANDL_WAR)
224 return 0;
225 if (dep->type == CANDL_RAR)
226 if (path[path_length - 1]->type != CANDL_RAR &&
227 path[path_length - 1]->type != CANDL_RAW_SCALPRIV &&
228 path[path_length - 1]->type != CANDL_RAW)
229 return 0;
232 // a- Fast check. Ensure the dependence depth is consistent across
233 // the path. We may correctly cover _more_ points and still have a
234 // perfect transitive cover.
235 /// FIXME: ambiguous test?
236 /* for (i = 0; i < path_length; ++i) */
237 /* if (path[i]->depth > dep->depth) */
238 /* return 0; */
240 // b- Check the covering property. Works only if
241 // the iterator part of iteration domains and access functions are
242 // unimodular matrices.
243 // Build a large system with all dependences.
244 int nb_par = path[0]->domain->nb_parameters;
245 int nb_iters = 0;
246 int nb_rows = 0;
247 for (i = 0; i < path_length; ++i) {
248 nb_iters += path[i]->source_nb_output_dims_domain +
249 path[i]->target_nb_output_dims_domain;
250 nb_rows += path[i]->domain->nb_rows;
251 if (i > 0)
252 nb_iters -= ((candl_statement_usr_p) path[i]->source->usr)->depth;
255 CandlMatrix* syst = candl_matrix_malloc(nb_rows, nb_iters + nb_par + 2);
256 int pos = 0;
257 int j, k;
258 int iter_off = 0;
259 for (k = 0; k < path_length; ++k) {
260 for (i = 0; i < path[k]->domain->NbRows; ++i) {
261 CANDL_assign(syst->p[pos][0], path[k]->domain->p[i][0]);
262 for (j = 1; j < path[k]->domain->NbColumns - 1 - nb_par; ++j)
263 CANDL_assign(syst->p[pos][j + iter_off], path[k]->domain->p[i][j]);
264 for (; j < path[k]->domain->NbColumns; ++j) {
265 int parpos = j - (path[k]->domain->NbColumns - 1 - nb_par) +
266 syst->NbColumns - nb_par - 1;
267 CANDL_assign(syst->p[pos][parpos], path[k]->domain->p[i][j]);
269 ++pos;
271 iter_off += path[k]->source->depth;
274 // Algo:
275 // lexmin(dep, R) == lexmin(path, R) && lexmax(dep, R) == lexmax(path, R) &&
276 // lexmin(dep, S) == lexmin(path, S) && lexmax(dep, S) == lexmax(path, S)
277 PipOptions* options;
278 options = pip_options_init();
279 options->Simplify = 1;
280 options->Urs_parms = -1;
281 options->Urs_unknowns = -1;
282 CandlMatrix* context = candl_matrix_malloc(0, nb_par + 2);
283 PipQuast* qpath = pip_solve(syst, context, -1, options);
284 PipQuast* qdep = pip_solve(dep->domain, context, -1, options);
285 int are_equal = quast_are_equal(qpath, qdep, dep->source->depth);
286 if (are_equal) {
287 pip_quast_free (qpath);
288 pip_quast_free (qdep);
289 options->Maximize = 1;
290 qpath = pip_solve(syst, context, -1, options);
291 qdep = pip_solve(dep->domain, context, -1, options);
292 are_equal = quast_are_equal(qpath, qdep, dep->source->depth);
294 if (are_equal) {
295 pip_quast_free(qpath);
296 pip_quast_free(qdep);
297 options->Maximize = 0;
298 // Permute columns for first and last iterators.
299 for (i = 0; i < dep->target->depth; ++i) {
300 for (j = 0; j < syst->NbRows; ++j) {
301 int tmp = CANDL_get_si(syst->p[j][1]);
302 int pos = syst->NbColumns - 1 - nb_par - dep->target->depth + i;
303 CANDL_assign(syst->p[j][1], syst->p[j][pos]);
304 CANDL_set_si(syst->p[j][pos], tmp);
307 qpath = pip_solve(syst, context, -1, options);
308 qdep = pip_solve(dep->domain, context, -1, options);
309 are_equal = quast_are_equal(qpath, qdep, dep->target->depth);
311 if (are_equal) {
312 pip_quast_free(qpath);
313 pip_quast_free(qdep);
314 options->Maximize = 1;
315 qpath = pip_solve(syst, context, -1, options);
316 qdep = pip_solve(dep->domain, context, -1, options);
317 are_equal = quast_are_equal(qpath, qdep, dep->target->depth);
320 pip_options_free(options);
321 pip_quast_free(qpath);
322 pip_quast_free(qdep);
323 pip_matrix_free(syst);
325 return are_equal;
328 static
329 int is_iter_unimodular(osl_dependence_p dep) {
330 // Check unimodular on the iterator part.
331 int i, j;
332 int n;
333 int precision = dep->domain->precision;
334 osl_relation_p matrix;
336 matrix = dep->source->domain;
337 for (i = 0 ; i < matrix->nb_rows ; i++)
338 for (j = 1 ; j <= matrix->nb_output_dims ; j++) {
339 n = osl_int_get_si(precision, matrix->m[i][j]);
340 if (n < -1 || n > 1)
341 return 0;
344 matrix = dep->target->domain;
345 for (i = 0 ; i < matrix->nb_rows ; i++)
346 for (j = 1 ; j <= matrix->nb_output_dims ; j++) {
347 n = osl_int_get_si(precision, matrix->m[i][j]);
348 if (n < -1 || n > 1)
349 return 0;
352 return 1;
356 * Remove somes dependences that are duplicates under transitive closure.
357 * In-place modification of the list of dependence polyhedra.
360 osl_dependence_p osl_dependence_prune_transitively_covered(
361 osl_dependence_p deps) {
362 if (deps == NULL)
363 return NULL;
365 osl_dependence_p tmp;
366 osl_dependence_p *ardeps;
367 osl_relation_p srcmat;
368 osl_relation_p *allarrays;
369 osl_dependence_p** path;
370 osl_dependence_p *curardeps;
371 candl_statement_usr_p s_usr, t_usr;
372 int precision = deps->domain->precision;
373 int nb_deps;
375 // 1- Collect all arrays that occur in dependences.
376 int cnt, i, j, k, l;
377 int nb_stmts = 0;
378 for (tmp = deps, cnt = 0; tmp; tmp = tmp->next) {
379 s_usr = tmp->source->usr;
380 t_usr = tmp->target->usr;
381 nb_stmts = s_usr->label > nb_stmts ? s_usr->label : nb_stmts;
382 nb_stmts = t_usr->label > nb_stmts ? t_usr->label : nb_stmts;
383 ++cnt;
385 ++nb_stmts;
386 nb_deps = cnt;
387 allarrays = (osl_relation_p*)malloc(sizeof(osl_relation_p)*cnt);
389 for (tmp = deps, cnt = 0; tmp; tmp = tmp->next) {
390 srcmat = candl_dependence_get_relation_ref_source_in_dep(tmp);
391 for (i = 0; i < cnt; ++i)
392 if (allarrays[i] == srcmat)
393 break;
394 if (i == cnt)
395 allarrays[cnt++] = srcmat;
397 allarrays[cnt] = NULL;
399 // 2- Iterate on all arrays.
400 for (i = 0 ; allarrays[i] != NULL ; ++i) {
401 ardeps = (osl_dependence_p*) malloc(sizeof(osl_dependence_p) *
402 (nb_deps + 1));
404 // a- Collect all dependences to this array.
405 for (tmp = deps, cnt = 0; tmp; tmp = tmp->next) {
406 srcmat = candl_dependence_get_relation_ref_source_in_dep(tmp);
407 if (allarrays[i] == srcmat)
408 ardeps[cnt++] = tmp;
410 ardeps[cnt] = NULL;
412 // b- First pruning. Remove all dependence polyhedra that are equal.
413 for (j = 0; ardeps[j]; ++j)
414 for (k = j + 1; ardeps[k]; ++k)
415 if (ardeps[j]->source == ardeps[k]->source &&
416 ardeps[j]->target == ardeps[k]->target &&
417 ardeps[j]->depth == ardeps[k]->depth &&
418 osl_relation_equal(ardeps[j]->domain, ardeps[k]->domain)) {
419 ardeps[k - 1]->next = ardeps[k+1];
420 for (l = k; ardeps[l + 1]; ++l)
421 ardeps[l] = ardeps[l + 1];
422 ardeps[l] = NULL;
423 --k;
426 // c- Local pruning. Remove all self-dependences (1-cycles)
427 // and all backward-dependences.
428 for (j = 0; ardeps[j]; ++j) {
429 s_usr = ardeps[j]->source->usr;
430 t_usr = ardeps[j]->target->usr;
431 if (s_usr->label >= t_usr->label) {
432 for (k = j; ardeps[k + 1]; ++k)
433 ardeps[k] = ardeps[k + 1];
434 ardeps[k] = NULL;
435 --j;
439 // d- Local pruning. Remove all dependences where source/target
440 // are not unimodular in the iterator part of the access function and
441 // iteration domain.
442 for (j = 0; ardeps[j]; ++j)
443 if (! is_iter_unimodular(ardeps[j])) {
444 for (k = j; ardeps[k + 1]; ++k)
445 ardeps[k] = ardeps[k + 1];
446 ardeps[k] = NULL;
447 --j;
450 // d- Given a pair of statements, check if there is a dependence
451 // path from its source to its target, of same type of a found
452 // direct dependence.
453 int source_label, target_label;
454 for (source_label = 0; source_label < nb_stmts - 2; ++source_label)
455 for (target_label = source_label + 2; target_label < nb_stmts;
456 ++target_label) {
457 // Ensure there exists a direct dependence between source_label
458 // and target_label.
459 //printf ("consider S%d -> S%d\n", source_label, target_label);
460 for (j = 0; ardeps[j]; ++j) {
461 s_usr = ardeps[j]->source->usr;
462 t_usr = ardeps[j]->target->usr;
463 if (s_usr->label == source_label &&
464 t_usr->label == target_label)
465 break;
467 if (ardeps[j]) {
468 osl_statement_p source = ardeps[j]->source;
469 osl_statement_p target = ardeps[j]->target;
471 // Subset of deps that can be on the path.
472 curardeps = (osl_dependence_p*) malloc(sizeof(osl_dependence_p) *
473 (nb_deps + 1));
475 for (k = 0, l = 0; ardeps[k]; ++k) {
476 s_usr = ardeps[k]->source->usr;
477 t_usr = ardeps[k]->target->usr;
478 if (s_usr->label >= source->label &&
479 s_usr->label <= target->label &&
480 t_usr->label >= source->label &&
481 t_usr->label <= target->label)
482 curardeps[l++] = ardeps[k];
484 curardeps[l] = NULL;
485 paths = find_dep_paths(curardeps, source, target);
487 if (paths) {
488 for (j = 0; ardeps[j]; ++j) {
489 s_usr = ardeps[j]->source->usr;
490 t_usr = ardeps[j]->target->usr;
491 if (s_usr->label == source_label &&
492 t_usr->label == target_label) {
493 // Inspect all paths. If there is a path
494 // that respect the transitive cover prop,
495 // then discard the dependence.
496 for (k = 0; paths[k] && !is_covering(ardeps[j], paths[k]); ++k)
498 if (paths[k]) {
499 osl_relation_free(ardeps[j]->domain);
500 free(ardeps[j]);
501 if (j == 0)
502 deps = ardeps[j + 1];
503 else
504 ardeps[j - 1]->next = ardeps[j + 1];
508 for (k = 0; paths[k]; ++k)
509 free(paths[k]);
510 free(paths);
513 free(curardeps);
517 free(ardeps);
520 free(allarrays);
522 return deps;
525 #endif