2 /**------ ( ----------------------------------------------------------**
4 **----- / ) --------------------------------------------------------**
6 **---- \#/ --------------------------------------------------------**
7 ** .-"#'-. First version: July 17th 2011 **
8 **--- |"-.-"| -------------------------------------------------------**
11 ******** | | *************************************************************
12 * CAnDL '-._,-' the Chunky Analyzer for Dependences in Loops (experimental) *
13 ******************************************************************************
15 * Copyright (C) 2003-2008 Cedric Bastoul *
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. *
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 *
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 *
31 * CAnDL, the Chunky Dependence Analyzer *
32 * Written by Cedric Bastoul, Cedric.Bastoul@inria.fr *
34 ******************************************************************************/
37 * \author Louis-Noel Pouchet
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
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'.
62 void find_paths_rec(int tgt_id
, int cur_length
, int max_length
,
64 osl_dependence_p
* alldeps
,
65 osl_dependence_p
* cur_path
,
66 osl_dependence_p
*** paths_list
) {
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.
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
) {
79 if (alldeps
[i
]->type
!= CANDL_RAR
&&
80 alldeps
[i
]->type
!= CANDL_WAR
)
85 if (alldeps
[i
]->type
!= CANDL_WAW
&&
86 alldeps
[i
]->type
!= CANDL_RAW
)
90 if (cur_length
+ 1 == max_length
) {
91 if (alldeps
[i
]->((candl_statement_usr_p
)target
->usr
)->label
== final_id
) {
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
;
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
135 osl_dependence_p
** find_dep_paths(osl_dependence_p
* ardeps
,
136 osl_statement_p source
,
137 osl_statement_p target
) {
139 for (nb_dep
= 0; ardeps
[nb_dep
]; ++nb_dep
)
143 osl_dependence_p
*cur_path
=
144 (osl_dependence_p
*) malloc(sizeof(osl_dependence_p
) *
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
);
162 * Return true if the 'size' first variables in a quast are strictly
166 int quast_are_equal (PipQuast
* q1
, PipQuast
* q2
, int size
) {
167 if (q1
== NULL
&& q2
== NULL
)
169 if (q1
== NULL
|| q2
== NULL
)
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
))
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
)
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).
193 int is_covering(osl_dependence_p dep
, osl_dependence_p
* path
) {
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
) {
204 if (path
[0]->type
!= CANDL_RAW
&& path
[0]->type
!= CANDL_RAW_SCALPRIV
&&
205 path
[0]->type
!= CANDL_WAW
)
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
)
212 if (dep
->type
== CANDL_WAW
)
213 if (path
[path_length
- 1]->type
!= CANDL_WAR
&&
214 path
[path_length
- 1]->type
!= CANDL_WAW
)
219 if (path
[0]->type
!= CANDL_WAR
&& path
[0]->type
!= CANDL_RAR
)
221 if (dep
->type
== CANDL_WAR
)
222 if (path
[path_length
- 1]->type
!= CANDL_WAW
&&
223 path
[path_length
- 1]->type
!= CANDL_WAR
)
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
)
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) */
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
;
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
;
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);
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
]);
271 iter_off
+= path
[k
]->source
->depth
;
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)
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
);
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
);
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
);
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
);
329 int is_iter_unimodular(osl_dependence_p dep
) {
330 // Check unimodular on the iterator part.
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
]);
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
]);
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
) {
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
;
375 // 1- Collect all arrays that occur in dependences.
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
;
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
)
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
) *
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
)
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];
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];
439 // d- Local pruning. Remove all dependences where source/target
440 // are not unimodular in the iterator part of the access function and
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];
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
;
457 // Ensure there exists a direct dependence between source_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
)
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
) *
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
];
485 paths
= find_dep_paths(curardeps
, source
, target
);
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
)
499 osl_relation_free(ardeps
[j
]->domain
);
502 deps
= ardeps
[j
+ 1];
504 ardeps
[j
- 1]->next
= ardeps
[j
+ 1];
508 for (k
= 0; paths
[k
]; ++k
)