Fix a wrong index in the dependence system construction
[candl.git] / source / dependence.c
bloba9c19b054d8435ae5de61e76cb4be70973976bb9
2 /**------ ( ----------------------------------------------------------**
3 ** )\ CAnDL **
4 **----- / ) --------------------------------------------------------**
5 ** ( * ( dependence.c **
6 **---- \#/ --------------------------------------------------------**
7 ** .-"#'-. First version: september 18th 2003 **
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 dependence.c
37 * \author Cedric Bastoul and Louis-Noel Pouchet
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <candl/candl.h>
44 #include <candl/dependence.h>
45 #include <candl/scop.h>
46 #include <candl/statement.h>
47 #include <candl/util.h>
48 #include <candl/matrix.h>
49 #include <candl/piplib-wrapper.h>
50 #include <osl/macros.h>
51 #include <osl/scop.h>
52 #include <osl/statement.h>
53 #include <osl/relation.h>
54 #include <osl/names.h>
55 #include <osl/util.h>
57 #include <assert.h>
59 #ifdef CANDL_SUPPORTS_ISL
60 # undef Q // Thank you polylib...
61 # include <isl/int.h>
62 # include <isl/constraint.h>
63 # include <isl/ctx.h>
64 # include <isl/set.h>
65 #endif
69 /**
70 * candl_dependence_get_relation_ref_source_in_dep function:
71 * This function return the corresponding osl_relation_p of
72 * the ref_source
74 osl_relation_p
75 candl_dependence_get_relation_ref_source_in_dep(osl_dependence_p tmp) {
76 if (tmp->ref_source_access_ptr != NULL)
77 return tmp->ref_source_access_ptr;
78 int count = 0;
79 osl_relation_p elt = NULL;
80 osl_relation_list_p access;
81 access = tmp->stmt_source_ptr->access;
82 for (; access != NULL ; access = access->next) {
83 elt = access->elt;
84 if (count == tmp->ref_source)
85 break;
86 count++;
88 tmp->ref_source_access_ptr = elt;
89 return elt;
92 /**
93 * candl_dependence_get_relation_ref_target_in_dep function:
94 * same as candl_dependence_get_relation_ref_source_in_dep but for the target
96 osl_relation_p
97 candl_dependence_get_relation_ref_target_in_dep(osl_dependence_p tmp) {
98 if (tmp->ref_target_access_ptr != NULL)
99 return tmp->ref_target_access_ptr;
100 int count = 0;
101 osl_relation_list_p access;
102 osl_relation_p elt = NULL;
103 access = tmp->stmt_target_ptr->access;
104 for (; access != NULL ; access = access->next) {
105 elt = access->elt;
106 if (count == tmp->ref_target)
107 break;
108 count++;
110 tmp->ref_target_access_ptr = elt;
111 return elt;
117 * candl_dependence_get_array_refs_in_dep function:
118 * This function return the array indices referenced in the
119 * dependence.
121 void candl_dependence_get_array_refs_in_dep(osl_dependence_p tmp,
122 int* refs, int* reft) {
123 if (! tmp)
124 return;
126 osl_relation_p src, targ;
127 int row;
128 int precision = tmp->domain->precision;
130 src = candl_dependence_get_relation_ref_source_in_dep(tmp);
131 targ = candl_dependence_get_relation_ref_target_in_dep(tmp);
133 row = candl_relation_get_line(src, 0);
134 *refs = osl_int_get_si(precision,
135 src->m[row],
136 src->nb_columns-1);
138 row = candl_relation_get_line(targ, 0);
139 *reft = osl_int_get_si(precision,
140 targ->m[row],
141 targ->nb_columns-1);
145 /* osl_dependence_pprint function:
146 * This function prints the content of a osl_dependence_p structure (dependence)
147 * into a file (file, possibly stdout) as a Graphviz input file.
148 * See http://www.graphviz.org
149 * - 08/12/2005: first version.
151 void candl_dependence_pprint(FILE * file, osl_dependence_p dependence) {
152 int i = 0;
154 fprintf(file, "digraph G {\n");
156 fprintf(file, "# Data Dependence Graph\n");
157 fprintf(file, "# Generated by Candl "CANDL_RELEASE" "CANDL_VERSION" bits\n");
158 while (dependence != NULL) {
159 fprintf(file, " S%d -> S%d [label=\" ", dependence->label_source,
160 dependence->label_target);
161 switch (dependence->type) {
162 case OSL_UNDEFINED : fprintf(file, "UNSET"); break;
163 case OSL_DEPENDENCE_RAW : fprintf(file, "RAW") ; break;
164 case OSL_DEPENDENCE_WAR : fprintf(file, "WAR") ; break;
165 case OSL_DEPENDENCE_WAW : fprintf(file, "WAW") ; break;
166 case OSL_DEPENDENCE_RAR : fprintf(file, "RAR") ; break;
167 case OSL_DEPENDENCE_RAW_SCALPRIV :
168 fprintf(file, "RAW_SCALPRIV (scalar-priv)") ; break;
169 default : fprintf(file, "unknown"); break;
171 fprintf(file, " depth %d, ref %d->%d \"];\n", dependence->depth,
172 dependence->ref_source,
173 dependence->ref_target);
174 dependence = dependence->next;
175 i++;
178 if (i>4)
179 fprintf(file, "# Number of edges = %i\n}\n", i);
180 else
181 fprintf(file, "}\n");
185 /* candl_dependence_view function:
186 * This function uses dot (see http://www.graphviz.org) and gv (see
187 * http://wwwthep.physik.uni-mainz.de/~plass/gv) tools to display the
188 * dependence graph.
189 * - 20/03/2006: first version.
191 void candl_dependence_view(osl_dependence_p dep) {
192 FILE * temp_output;
193 temp_output = fopen(CANDL_TEMP_OUTPUT,"w+");
194 candl_dependence_pprint(temp_output, dep);
195 fclose(temp_output);
196 /* check the return to remove the warning compilation */
197 if(system("dot -Tps "CANDL_TEMP_OUTPUT" | gv - && rm -f "CANDL_TEMP_OUTPUT" &"))
202 #ifdef CANDL_SUPPORTS_ISL
204 struct isl_set* isl_set_from_piplib_matrix(struct isl_ctx* ctx,
205 osl_relation_p matrix,
206 int nparam);
207 osl_relation_p isl_set_to_piplib_matrix(struct isl_ctx* ctx,
208 struct isl_set* set,
209 int nparam);
211 * candl_dependence_isl_simplify function:
213 * This function uses ISL to simplify the dependence polyhedra.
214 * Useful for polyhedra that contain large coefficient values.
217 osl_dependence_p candl_dependence_isl_simplify(osl_dependence_p dep,
218 osl_scop_p scop) {
219 if (dep == NULL || scop == NULL)
220 return dep;
222 osl_dependence_p tmp;
223 osl_relation_p context = scop->context;
224 int nparam = context->nb_parameters;
226 struct isl_ctx* ctx = isl_ctx_alloc();
228 for (tmp = dep; tmp; tmp = tmp->next) {
229 // 1- Convert the dependence polyhedron into ISL set.
231 struct isl_set* set = isl_set_from_piplib_matrix(ctx, tmp->domain, nparam);
233 // 2- Simplify the ISL set.
234 set = isl_set_detect_equalities(set);
236 // 3- Convert back into Candl matrix representation.
237 osl_relation_p newdom = isl_set_to_piplib_matrix(ctx, set, nparam);
238 isl_set_free(set);
239 newdom->nb_output_dims = tmp->domain->nb_output_dims;
240 newdom->nb_input_dims = tmp->domain->nb_input_dims;
241 newdom->nb_local_dims = tmp->domain->nb_local_dims;
242 newdom->nb_parameters = tmp->domain->nb_parameters;
243 osl_relation_free(tmp->domain);
244 tmp->domain = newdom;
247 /// FIXME: Some dead ref.
248 //isl_ctx_free (ctx);
250 return dep;
253 #endif
256 /* candl_dependence_init_fields:
257 * Set the various other fields of the dependence structure
259 void candl_dependence_init_fields(osl_scop_p scop, osl_dependence_p dep) {
261 osl_statement_p iter;
262 candl_statement_usr_p usr;
263 osl_relation_p array_s, array_t;
265 /* source statement */
266 iter = scop->statement;
267 for (; iter != NULL ; iter = iter->next) {
268 usr = iter->usr;
269 if (usr->label == dep->label_source) {
270 dep->stmt_source_ptr = iter;
271 break;
274 if (iter == NULL) {
275 fprintf(stderr, "[Candl] Can't find the %dth label\n", dep->label_source);
276 exit(1);
279 /* target statement */
280 iter = scop->statement;
281 for (; iter != NULL ; iter = iter->next) {
282 usr = iter->usr;
283 if (usr->label == dep->label_target) {
284 dep->stmt_target_ptr = iter;
285 break;
288 if (iter == NULL) {
289 fprintf(stderr, "[Candl] Can't find the %dth label\n", dep->label_target);
290 exit(1);
293 array_s = candl_dependence_get_relation_ref_source_in_dep(dep);
294 if (array_s == NULL) {
295 fprintf(stderr, "[Candl] Can't find the %dth access of the statement :\n",
296 dep->ref_source);
297 osl_statement_dump(stderr, dep->stmt_source_ptr);
298 exit(1);
301 array_t = candl_dependence_get_relation_ref_source_in_dep(dep);
302 if (array_t == NULL) {
303 fprintf(stderr, "[Candl] Can't find the %dth access of the statement :\n",
304 dep->ref_target);
305 osl_statement_dump(stderr, dep->stmt_target_ptr);
306 exit(1);
309 dep->source_nb_output_dims_domain = dep->stmt_source_ptr->domain->nb_output_dims;
310 dep->source_nb_output_dims_access = array_s->nb_output_dims;
312 dep->target_nb_output_dims_domain = dep->stmt_target_ptr->domain->nb_output_dims;
313 dep->target_nb_output_dims_access = array_t->nb_output_dims;
315 dep->source_nb_local_dims_domain = dep->stmt_source_ptr->domain->nb_local_dims;
316 dep->source_nb_local_dims_access = array_s->nb_local_dims;
317 dep->target_nb_local_dims_domain = dep->stmt_target_ptr->domain->nb_local_dims;
318 dep->target_nb_local_dims_access = array_t->nb_local_dims;
323 * GCD computation.
325 static int candl_dependence_gcd(int a, int b) {
326 int z = 1;
328 if (a < 0)
329 a *= -1;
330 if (b < 0)
331 b *= -1;
332 if (a == 0)
333 return b;
334 if (b == 0)
335 return a;
336 if (b > a) {
337 int temp = a;
338 a = b;
339 b = temp;
342 while (z != 0) {
343 z = a % b;
344 a = b;
345 b = z;
348 return a;
355 static int candl_dependence_gcd_test_context(osl_relation_p system, int id) {
356 /* FIXME: implement me! */
358 return 1;
363 * candl_dependence_gcd_test function:
364 * This functions performs a GCD test on a dependence polyhedra
365 * represented exactly by a set of constraints 'system' organized in
366 * such a way:
367 * - first lines: iteration domain of 'source'
368 * - then: iteration domain of 'target'
369 * - then: array access equality(ies)
370 * - then (optional): precedence constraint inequality.
372 * The function returns false if the dependence is impossible, true
373 * otherwise. A series of simple checks (SIV/ZIV/MIV/bounds checking)
374 * are also performed before the actual GCD test.
377 int candl_dependence_gcd_test(osl_statement_p source,
378 osl_statement_p target,
379 osl_relation_p system,
380 int level) {
381 int i;
382 int gcd;
383 int id;
384 int value;
385 int null_iter, null_param, null_cst, pos_iter, neg_iter;
386 int precision = source->domain->precision;
387 candl_statement_usr_p s_usr = source->usr;
388 candl_statement_usr_p t_usr = target->usr;
390 /* Check that the precedence constraint, if any, is not strict in a
391 self-dependence. */
392 /* int strict_pred; */
393 /* if (source == target && */
394 /* CANDL_get_si(system->p[system->NbRows - 1][0]) == 1 && */
395 /* CANDL_get_si(system->p[system->NbRows - 1][system->NbColumns - 1]) == -1) */
396 /* strict_pred = 1; */
397 /* else */
398 /* strict_pred = 0; */
400 /* Inspect the array access function equalities. */
401 for (id = source->domain->nb_rows + target->domain->nb_rows;
402 id < system->nb_rows &&
403 osl_int_zero(precision, system->m[id], 0);
404 ++id) {
405 /* Inspect which parts of the access function equality are null,
406 positive or negative. */
407 null_iter = null_param = null_cst = pos_iter = neg_iter = 0;
409 for (i = 1; i < s_usr->depth + t_usr->depth + 1 &&
410 osl_int_zero(precision, system->m[id], i); ++i)
413 if (i == s_usr->depth + t_usr->depth + 1)
414 null_iter = 1;
415 else
416 for (pos_iter = 1, neg_iter = 1;
417 i < s_usr->depth + t_usr->depth + 1; ++i) {
418 if (osl_int_neg(precision, system->m[id], i))
419 pos_iter = 0;
420 else if (osl_int_pos(precision, system->m[id], i))
421 neg_iter = 0;
423 for (; i < system->nb_columns - 1 &&
424 osl_int_zero(precision, system->m[id], i) == 0; ++i)
426 if (i == system->nb_columns - 1)
427 null_param = 1;
428 null_cst = osl_int_zero(precision, system->m[id], system->nb_columns - 1);
430 /* Some useful ZIV/SIV/MIV tests. */
431 if (null_iter && null_param && !null_cst)
432 return 0;
433 if (null_iter)
434 if (! candl_dependence_gcd_test_context(system, id))
435 return 0;
436 if (null_cst || !null_param)
437 continue;
438 /* FIXME: implement the loop bound check. */
439 /* /\* A clever test on access bounds. *\/ */
440 /* if (null_param && pos_iter && */
441 /* CANDL_get_si(system->p[id][system->NbColumns - 1]) > 0) */
442 /* return 0; */
443 /* if (null_param && neg_iter && */
444 /* CANDL_get_si(system->p[id][system->NbColumns - 1]) < 0) */
445 /* return 0; */
447 /* Compute GCD test for the array access equality. */
448 for (i = 1, gcd = osl_int_get_si(precision, system->m[id], i);
449 i < s_usr->depth + t_usr->depth; ++i)
450 gcd = candl_dependence_gcd(gcd, osl_int_get_si(precision,
451 system->m[id],
452 i + 1));
454 value = osl_int_get_si(precision, system->m[id], system->nb_columns - 1);
455 value = value < 0 ? -value : value;
456 if ((gcd == 0 && value != 0) || value % gcd)
457 return 0;
460 return 1;
465 * candl_dependence_build_system function:
466 * this function builds the constraint system corresponding to a data
467 * dependence, for a given statement couple (with iteration domains "source"
468 * and "target"), for a given reference couple (the source reference is array
469 * "ref_s" in "array_s" and the target reference is the array "ref_t" in
470 * "array_t"), at a given depth "depth" and knowing if the source is textually
471 * before the target (boolean "before"). The system is built... as always !
472 * See the [bastoul and Feautrier, PPL 2005] paper for details !
473 * - source is the source iteration domain,
474 * - target is the target iteration domain,
475 * - array_s is the access array for the source,
476 * - array_t is the access array for the target,
477 * - depth is the dependence depth,
478 * - before is 1 if the source is textually before the target, 0 otherwise,
480 * - 13/12/2005: first version (extracted from candl_dependence_system).
481 * - 23/02/2006: a stupid bug corrected in the subscript equality.
482 * - 07/04/2007: fix the precedence condition to respect C. Bastoul PhD thesis
484 static osl_dependence_p candl_dependence_build_system(
485 osl_statement_p source, osl_statement_p target,
486 osl_relation_p array_s, osl_relation_p array_t,
487 int depth, int before) {
488 osl_dependence_p dependence;
489 osl_relation_p system;
490 int i, j, k, c;
491 int constraint = 0;
492 int precision = source->domain->precision;
493 int nb_output_dims; // source column
494 int nb_input_dims; // target column
495 int nb_local_dims;
496 int nb_par;
497 int nb_rows, nb_columns;
498 int ind_source_local_domain;
499 int ind_source_local_access;
500 int ind_target_local_domain;
501 int ind_target_local_access;
502 int ind_params;
503 int min_depth = 0;
505 /* Create a new dependence structure */
506 dependence = osl_dependence_malloc();
508 /* Compute the maximal common depth. */
509 min_depth = CANDL_min(array_s->nb_output_dims, array_t->nb_output_dims);
511 /* Compute the system size */
512 dependence->source_nb_output_dims_domain = source->domain->nb_output_dims;
513 dependence->source_nb_output_dims_access = array_s->nb_output_dims;
515 dependence->target_nb_output_dims_domain = target->domain->nb_output_dims;
516 dependence->target_nb_output_dims_access = array_t->nb_output_dims;
518 dependence->source_nb_local_dims_domain = source->domain->nb_local_dims;
519 dependence->source_nb_local_dims_access = array_s->nb_local_dims;
520 dependence->target_nb_local_dims_domain = target->domain->nb_local_dims;
521 dependence->target_nb_local_dims_access = array_t->nb_local_dims;
523 nb_par = source->domain->nb_parameters;
524 nb_local_dims = dependence->source_nb_local_dims_domain +
525 dependence->source_nb_local_dims_access +
526 dependence->target_nb_local_dims_domain +
527 dependence->target_nb_local_dims_access;
528 nb_output_dims = dependence->source_nb_output_dims_domain +
529 dependence->source_nb_output_dims_access;
530 nb_input_dims = dependence->target_nb_output_dims_domain +
531 dependence->target_nb_output_dims_access;
533 nb_columns = nb_output_dims + nb_input_dims + nb_local_dims + nb_par + 2;
534 nb_rows = source->domain->nb_rows + target->domain->nb_rows +
535 array_s->nb_rows + array_t->nb_rows +
536 min_depth +
537 depth;
539 system = osl_relation_pmalloc(precision, nb_rows, nb_columns);
541 /* Compute some indexes */
542 ind_source_local_domain = 1 + nb_output_dims + nb_input_dims;
543 ind_source_local_access = ind_source_local_domain + dependence->source_nb_local_dims_domain;
544 ind_target_local_domain = ind_source_local_access + dependence->source_nb_local_dims_access;
545 ind_target_local_access = ind_target_local_domain + dependence->target_nb_local_dims_domain;
546 ind_params = ind_target_local_access + dependence->target_nb_local_dims_access;
548 /* 1. Copy the source domain */
549 for (i = 0 ; i < source->domain->nb_rows ; i++) {
550 /* eq/in */
551 osl_int_assign(precision,
552 system->m[constraint], 0,
553 source->domain->m[i], 0);
554 /* output dims */
555 k = 1;
556 j = 1;
557 for (c = source->domain->nb_output_dims ; c > 0 ; c--, k++, j++)
558 osl_int_assign(precision,
559 system->m[constraint], k,
560 source->domain->m[i], j);
561 /* local dims (no input in domain, so j is the same) */
562 k = ind_source_local_domain;
563 for (c = source->domain->nb_local_dims ; c > 0 ; c--, k++, j++)
564 osl_int_assign(precision,
565 system->m[constraint], k,
566 source->domain->m[i], j);
567 /* params + const */
568 k = ind_params;
569 for (c = nb_par+1 ; c > 0 ; c--, k++, j++)
570 osl_int_assign(precision,
571 system->m[constraint], k,
572 source->domain->m[i], j);
573 constraint++;
576 /* 2. Copy the target domain */
577 for (i = 0 ; i < target->domain->nb_rows ; i++) {
578 /* eq/in */
579 osl_int_assign(precision,
580 system->m[constraint], 0,
581 target->domain->m[i], 0);
582 /* output dims */
583 k = 1 + nb_output_dims;
584 j = 1;
585 for (c = target->domain->nb_output_dims ; c > 0 ; c--, k++, j++)
586 osl_int_assign(precision,
587 system->m[constraint], k,
588 target->domain->m[i], j);
589 /* local dims (no input in domain, so j is the same) */
590 k = ind_target_local_domain;
591 for (c = target->domain->nb_local_dims ; c > 0 ; c--, k++, j++)
592 osl_int_assign(precision,
593 system->m[constraint], k,
594 target->domain->m[i], j);
595 /* params + const */
596 k = ind_params;
597 for (c = nb_par+1 ; c > 0 ; c--, k++, j++)
598 osl_int_assign(precision,
599 system->m[constraint], k,
600 target->domain->m[i], j);
601 constraint++;
604 /* 3. Copy the source access */
605 for (i = 0 ; i < array_s->nb_rows ; i++) {
606 /* eq/in */
607 osl_int_assign(precision,
608 system->m[constraint], 0,
609 array_s->m[i], 0);
610 /* output dims */
611 k = 1 + source->domain->nb_output_dims;
612 j = 1;
613 for (c = array_s->nb_output_dims ; c > 0 ; c--, k++, j++)
614 osl_int_assign(precision,
615 system->m[constraint], k,
616 array_s->m[i], j);
617 /* link input dims access to the output dims domain */
618 k = 1;
619 for (c = array_s->nb_input_dims ; c > 0 ; c--, k++, j++)
620 osl_int_assign(precision,
621 system->m[constraint], k,
622 array_s->m[i], j);
623 /* local dims */
624 k = ind_source_local_access;
625 for (c = array_s->nb_local_dims ; c > 0 ; c--, k++, j++)
626 osl_int_assign(precision,
627 system->m[constraint], k,
628 array_s->m[i], j);
629 /* params + const */
630 k = ind_params;
631 for (c = nb_par+1 ; c > 0 ; c--, k++, j++)
632 osl_int_assign(precision,
633 system->m[constraint], k,
634 array_s->m[i], j);
636 constraint++;
639 /* 4. Copy the target access */
640 for (i = 0 ; i < array_t->nb_rows ; i++) {
641 /* eq/in */
642 osl_int_assign(precision,
643 system->m[constraint], 0,
644 array_t->m[i], 0);
645 /* output dims */
646 k = 1 + nb_output_dims + target->domain->nb_output_dims;
647 j = 1;
648 for (c = array_t->nb_output_dims ; c > 0 ; c--, k++, j++) {
649 osl_int_assign(precision,
650 system->m[constraint], k,
651 array_t->m[i], j);
652 osl_int_oppose(precision,
653 system->m[constraint], k,
654 system->m[constraint], k);
656 /* link input dims access to the output dims domain */
657 k = 1 + nb_output_dims;
658 for (c = array_t->nb_input_dims ; c > 0 ; c--, k++, j++) {
659 osl_int_assign(precision,
660 system->m[constraint], k,
661 array_t->m[i], j);
662 osl_int_oppose(precision,
663 system->m[constraint], k,
664 system->m[constraint], k);
666 /* local dims */
667 k = ind_target_local_access;
668 for (c = array_t->nb_local_dims ; c > 0 ; c--, k++, j++) {
669 osl_int_assign(precision,
670 system->m[constraint], k,
671 array_t->m[i], j);
672 osl_int_oppose(precision,
673 system->m[constraint], k,
674 system->m[constraint], k);
676 /* params + const */
677 k = ind_params;
678 for (c = nb_par+1 ; c > 0 ; c--, k++, j++) {
679 osl_int_assign(precision,
680 system->m[constraint], k,
681 array_t->m[i], j);
682 osl_int_oppose(precision,
683 system->m[constraint], k,
684 system->m[constraint], k);
686 constraint++;
690 /* 5. Set the equality between the output access */
691 /* Note here that the equality between the 2 Arr are necessarily equal */
692 k = 1 + source->domain->nb_output_dims;
693 j = 1 + nb_output_dims + target->domain->nb_output_dims;
694 for (i = 0 ; i < min_depth ; i++, k++, j++) {
695 osl_int_set_si(precision, system->m[constraint], k, -1);
696 osl_int_set_si(precision, system->m[constraint], j, 1);
697 constraint++;
700 /* 6. The precedence constraints */
701 int min_dim = 0;
702 while (min_dim < ((candl_statement_usr_p)source->usr)->depth &&
703 min_dim < ((candl_statement_usr_p)target->usr)->depth &&
704 ((candl_statement_usr_p)source->usr)->index[min_dim] ==
705 ((candl_statement_usr_p)target->usr)->index[min_dim])
706 ++min_dim;
708 k = 1;
709 j = 1 + nb_output_dims;
710 for (i = 0; i < depth; i++, k++, j++) {
711 /* i = i' for all dimension less than depth. */
712 osl_int_set_si(precision, system->m[constraint], k, -1);
713 osl_int_set_si(precision, system->m[constraint], j, 1);
714 if (i == depth - 1) {
715 /* i <= i' at dimension depth if source is textually before target. */
716 osl_int_set_si(precision, system->m[constraint], 0, 1);
717 /* If source is textually after target, this is obviously i < i'. */
718 if (before || depth < min_dim) // sub 1 for the Arr dim
719 osl_int_set_si(precision, system->m[constraint], nb_columns - 1, -1);
722 constraint++;
725 system->nb_output_dims = nb_output_dims;
726 system->nb_input_dims = nb_input_dims;
727 system->nb_parameters = nb_par;
728 system->nb_local_dims = nb_local_dims;
729 system->type = OSL_UNDEFINED;
731 dependence->domain = system;
733 return dependence;
738 * candl_dependence_system function :
739 * this function builds a node of the dependence graph: it studies a dependence
740 * between a given statement couple, reference couple, type and depth. If a
741 * data dependence actually exists, it returns a dependence structure, it
742 * returns NULL otherwise.
743 * - source is the source statement,
744 * - target is the target statement,
745 * - context is the program context (contraints on global parameters),
746 * - array_s is the array list for the source,
747 * - array_t is the array list for the target,
748 * - ref_s is the position of the source reference in array_s,
749 * - ref_s is the position of the target reference in array_t,
750 * - depth is the dependence depth,
751 * - type is the dependence type (RAW, WAW, WAR or RAR).
753 * - 18/09/2003: first version.
754 * - 09/12/2005: few corrections and polishing.
756 osl_dependence_p candl_dependence_system(osl_statement_p source,
757 osl_statement_p target,
758 osl_relation_p context,
759 osl_relation_p array_s,
760 osl_relation_p array_t,
761 int ref_s, int ref_t,
762 int type, int depth) {
763 candl_statement_usr_p s_usr = source->usr;
764 candl_statement_usr_p t_usr = target->usr;
765 osl_dependence_p dependence = NULL;
767 /* First, a trivial case: for two different statements at depth 0, there is
768 * a dependence only if the source is textually before the target.
770 if ((source != target) && (depth == 0) &&
771 (s_usr->label > t_usr->label))
772 return NULL;
774 /* We build the system of constraints. */
775 dependence = candl_dependence_build_system(source, target,
776 array_s, array_t,
777 depth,
778 (s_usr->label >=
779 t_usr->label));
781 /* We start by simple SIV/ZIV/GCD tests. */
782 if (!candl_dependence_gcd_test(source, target, dependence->domain, depth)) {
783 osl_dependence_free(dependence);
784 return NULL;
787 if (pip_has_rational_point(dependence->domain, context, 1)) {
788 /* We set the various fields with corresponding values. */
789 dependence->ref_source = ref_s;
790 dependence->ref_target = ref_t;
791 dependence->label_source = ((candl_statement_usr_p)source->usr)->label;
792 dependence->label_target = ((candl_statement_usr_p)target->usr)->label;
793 dependence->type = type;
794 dependence->depth = depth;
795 dependence->stmt_source_ptr = source;
796 dependence->stmt_target_ptr = target;
797 dependence->ref_source_access_ptr = array_s;
798 dependence->ref_target_access_ptr = array_t;
799 } else {
800 osl_dependence_free(dependence);
801 dependence = NULL;
804 return dependence;
809 * candl_dependence_between function :
810 * this function builds the dependence list from the statement "source" to
811 * statement "target": it will study the dependence for each reference and for
812 * each depth, under a particular context (context) and according to some
813 * user options.
814 * - 18/09/2003: first version.
815 * - 07/12/2005: (debug) correction of depth bounds.
816 * - 09/12/2005: We may take commutativity into consideration.
818 osl_dependence_p candl_dependence_between(osl_statement_p source,
819 osl_statement_p target,
820 osl_relation_p context,
821 candl_options_p options) {
822 osl_dependence_p new;
823 osl_dependence_p dependence = NULL;
824 osl_dependence_p now;
825 osl_relation_list_p access_src, access_targ;
826 osl_relation_p elt_src, elt_targ;
827 candl_statement_usr_p s_usr = source->usr;
828 candl_statement_usr_p t_usr = target->usr;
829 int i, min_depth, max_depth;
830 int precision = source->scattering->precision;
831 int row_src, row_targ;
832 int ref_s, ref_t;
834 /* If the statements commute and the user asks to use this information to
835 * simplify the dependence graph, we return no dependences.
837 if (options->commute && candl_util_statement_commute(source, target))
838 return NULL;
840 /* In the case of a self-dependence, the dependence depth can be as low as 1
841 * (not 0 because at depth 0 there is no loop, thus there is only one
842 * instance of the statement !) and as high as the statement depth.
843 * In the case of different statements, the dependence depth can be as low
844 * as 0 and as high as the number of shared loops.
846 if (source == target) {
847 min_depth = 1;
848 max_depth = s_usr->depth;
849 } else {
850 /* Depth 0 is for statements that don't share any loop. */
851 if (s_usr->depth > 0 && t_usr->depth > 0)
852 min_depth = (s_usr->index[0] == t_usr->index[0]) ? 1 : 0;
853 else
854 min_depth = 0;
856 max_depth = 0;
857 while ((max_depth < s_usr->depth) &&
858 (max_depth < t_usr->depth) &&
859 (s_usr->index[max_depth] == t_usr->index[max_depth]))
860 max_depth++;
863 ref_s = 0;
864 access_src = source->access;
866 for (; access_src != NULL; access_src = access_src->next, ref_s++) {
867 elt_src = access_src->elt;
868 row_src = candl_relation_get_line(elt_src, 0);
870 switch(elt_src->type) {
872 /* Anti and input-dependences analysis. */
873 case OSL_TYPE_READ: /* source READ */
874 if (!options->war && !options->rar)
875 break;
876 access_targ = target->access;
877 ref_t = 0;
878 for (; access_targ != NULL; access_targ = access_targ->next, ref_t++) {
879 elt_targ = access_targ->elt;
880 row_targ = candl_relation_get_line(elt_targ, 0);
882 /* Anti-dependences analysis. */
883 if (elt_targ->type != OSL_TYPE_READ) { /* target WRITE | MAY_WRITE */
884 if (options->war &&
885 osl_int_eq(precision,
886 elt_src->m[row_src], elt_src->nb_columns-1,
887 elt_targ->m[row_targ], elt_targ->nb_columns-1)) {
888 for (i = min_depth; i <= max_depth; i++) {
889 new = candl_dependence_system(source, target, context,
890 elt_src, elt_targ,
891 ref_s, ref_t,
892 OSL_DEPENDENCE_WAR, i);
893 osl_dependence_add(&dependence, &now, new);
897 /* Input-dependences analysis. */
898 else { /* target READ */
899 if (options->rar &&
900 osl_int_eq(precision,
901 elt_src->m[row_src], elt_src->nb_columns-1,
902 elt_targ->m[row_targ], elt_targ->nb_columns-1)) {
903 for (i = min_depth; i <= max_depth; i++) {
904 new = candl_dependence_system(source, target, context,
905 elt_src, elt_targ,
906 ref_s, ref_t,
907 OSL_DEPENDENCE_RAR, i);
908 osl_dependence_add(&dependence, &now, new);
913 break;
915 default: /* source WRITE | MAY-WRITE */
916 if (!options->raw && !options->waw)
917 break;
918 access_targ = target->access;
919 ref_t = 0;
920 for (; access_targ != NULL; access_targ = access_targ->next, ref_t++) {
921 elt_targ = access_targ->elt;
922 row_targ = candl_relation_get_line(elt_targ, 0);
924 /* Anti-dependences analysis. */
925 if (elt_targ->type != OSL_TYPE_READ) { /* target WRITE | MAY_WRITE */
926 if (options->waw &&
927 osl_int_eq(precision,
928 elt_src->m[row_src], elt_src->nb_columns-1,
929 elt_targ->m[row_targ], elt_targ->nb_columns-1)) {
930 for (i = min_depth; i <= max_depth; i++) {
931 new = candl_dependence_system(source, target, context,
932 elt_src, elt_targ,
933 ref_s, ref_t,
934 OSL_DEPENDENCE_WAW, i);
935 osl_dependence_add(&dependence, &now, new);
939 /* Input-dependences analysis. */
940 else { /* target READ */
941 if (options->raw &&
942 osl_int_eq(precision,
943 elt_src->m[row_src], elt_src->nb_columns-1,
944 elt_targ->m[row_targ], elt_targ->nb_columns-1)) {
945 for (i = min_depth; i <= max_depth; i++) {
946 new = candl_dependence_system(source, target, context,
947 elt_src, elt_targ,
948 ref_s, ref_t,
949 OSL_DEPENDENCE_RAW, i);
950 osl_dependence_add(&dependence, &now, new);
955 break;
959 return dependence;
964 * candl_dependence function:
965 * this function builds the dependence graph of a scop
966 * according to some user options (options).
967 * - 18/09/2003: first version.
969 osl_dependence_p candl_dependence(osl_scop_p scop, candl_options_p options) {
970 osl_dependence_p dependence = NULL;
971 osl_dependence_p new = NULL;
972 osl_dependence_p now;
973 osl_statement_p stmt_i, stmt_j;
974 osl_relation_p context = scop->context;
976 if (options->scalar_privatization || options->scalar_expansion)
977 candl_dependence_analyze_scalars(scop, options);
979 stmt_i = scop->statement;
980 for (; stmt_i != NULL; stmt_i = stmt_i->next) {
981 /* We add self dependence. */
982 /* S->S */
983 new = candl_dependence_between(stmt_i, stmt_i, context, options);
984 osl_dependence_add(&dependence, &now, new);
986 stmt_j = stmt_i->next;
987 for (; stmt_j != NULL; stmt_j = stmt_j ->next) {
988 /* And dependences with other statements. */
989 /* S1->S2 */
990 new = candl_dependence_between(stmt_i, stmt_j, context, options);
991 osl_dependence_add(&dependence, &now, new);
993 /* S2->S1 */
994 new = candl_dependence_between(stmt_j, stmt_i, context, options);
995 osl_dependence_add(&dependence, &now, new);
999 /* If scalar analysis is called, remove some useless dependences. */
1000 /* LNP: This is subsubmed by the updated prune-with-privatization function. */
1001 /* if (options->scalar_privatization || options->scalar_expansion || */
1002 /* options->scalar_renaming) */
1003 /* candl_dependence_prune_scalar_waw(scop, options, &dependence); */
1005 /* Final treatment for scalar analysis. */
1006 int check = 0;
1007 if (options->scalar_renaming)
1008 check = candl_dependence_scalar_renaming(scop, options, &dependence);
1010 if (! check && options->scalar_privatization)
1011 candl_dependence_prune_with_privatization(scop, options, &dependence);
1013 /* Compute the last writer */
1014 if (options->lastwriter)
1015 candl_compute_last_writer(dependence, scop);
1017 #if defined(CANDL_COMPILE_PRUNNING_C)
1018 /* Remove some transitively covered dependences (experimental). */
1019 if (options->prune_dups)
1020 dependence = candl_dependence_prune_transitively_covered(dependence);
1021 #endif
1023 return dependence;
1027 /******************************************************************************
1028 * Scalar analysis functions *
1029 ******************************************************************************/
1032 * candl_dependence_var_is_scalar function:
1033 * This function returns true if the variable indexed by 'var_index'
1034 * is a scalar in the whole scop.
1036 int candl_dependence_var_is_scalar(osl_scop_p scop, int var_index) {
1037 osl_statement_p statement;
1038 osl_relation_list_p access;
1039 osl_relation_p elt;
1040 int precision = scop->context->precision;
1041 int i;
1042 int row;
1044 statement = scop->statement;
1045 while (statement != NULL) {
1046 access = statement->access;
1047 while (access != NULL) {
1048 elt = access->elt;
1049 row = candl_relation_get_line(elt, 0);
1050 if (osl_int_get_si(precision, elt->m[row], elt->nb_columns-1) ==
1051 var_index) {
1052 /* Ensure it is not an array. */
1053 if (elt->nb_output_dims > 1)
1054 return 0;
1055 /* Ensure the access function is '0'. */
1056 if (!osl_int_zero(precision, elt->m[row], 0))
1057 return 0;
1058 for (i = 2; i < elt->nb_columns-2; ++i) /* jmp the 'Arr' */
1059 if (!osl_int_zero(precision, elt->m[row], i))
1060 return 0;
1062 access = access->next;
1064 statement = statement->next;
1067 return 1;
1072 * candl_dependence_expand_scalar function:
1073 * Expand the variable of index 'scalar_idx' by adding one
1074 * dimension (x becomes x[0]) to each access matrix refering this
1075 * variable in the statement list.
1078 static void candl_dependence_expand_scalar(osl_statement_p* sl,
1079 int scalar_idx) {
1080 osl_relation_list_p access;
1081 osl_relation_p elt;
1082 int tmp;
1083 int row;
1084 int precision = sl[0]->scattering->precision;
1085 int i;
1087 /* Iterate on all statements of the list. */
1088 for (i = 0; sl[i] != NULL; ++i) {
1090 /* Check if the scalar is referenced in the 'read' access
1091 function. */
1092 access = sl[i]->access;
1093 for (; access != NULL ; access = access->next) {
1094 elt = access->elt;
1095 row = candl_relation_get_line(elt, 0);
1096 tmp = osl_int_get_si(precision,
1097 elt->m[row],
1098 elt->nb_columns-1);
1099 if (tmp == scalar_idx) {
1100 row = elt->nb_rows;
1101 osl_relation_insert_blank_row(elt, row);
1102 osl_relation_insert_blank_column(elt, 1 + elt->nb_output_dims);
1103 osl_int_set_si(precision, elt->m[row], 1 + elt->nb_output_dims, -1);
1104 elt->nb_output_dims++;
1112 * candl_dependence_refvar_chain function:
1113 * This function returns a chain of statements as a feshly allocated
1114 * array of pointer on statements, of all statements reading or
1115 * writing the variable 'var_index', surrounded by the 'level' common
1116 * loops of 'dom'.
1117 * Output is a NULL-terminated array. We don't create a chained list,
1118 * because it demands to clone every statements each time, and we need
1119 * to clone the field usr too.
1121 osl_statement_p* candl_dependence_refvar_chain(osl_scop_p scop,
1122 osl_statement_p dom, int var_index, int level) {
1123 /* No or empty scop -> no chain! */
1124 if (scop == NULL || scop->statement == NULL)
1125 return NULL;
1127 osl_statement_p* res; /* not a chained list, but an array of statement */
1128 osl_statement_p statement;
1129 osl_relation_p scattering, scattering_dom;
1130 candl_statement_usr_p dom_usr;
1131 candl_statement_usr_p stmt_usr;
1132 int i;
1133 int buffer_size = 64;
1134 int count = 0;
1136 /* If no dominator is provided, assume we start with the first statement. */
1137 if (dom == NULL)
1138 dom = scop->statement;
1140 dom_usr = dom->usr;
1142 statement = scop->statement;
1143 while (statement != NULL && statement != dom)
1144 statement = statement->next;
1146 /* The dominator is not in the list of statements. */
1147 if (statement == NULL)
1148 return NULL;
1150 CANDL_malloc(res, osl_statement_p*, sizeof(osl_statement_p) * buffer_size);
1151 scattering_dom = dom->scattering;
1153 for (; statement != NULL; statement = statement->next) {
1154 stmt_usr = statement->usr;
1156 /* We look for exactly 'level' common loops. */
1157 if (stmt_usr->depth < level)
1158 continue;
1160 /* Ensure it has 'level' common loop(s) with the dominator. */
1161 scattering = statement->scattering;
1162 for (i = 0; i < level &&
1163 stmt_usr->index[i] == dom_usr->index[i];
1164 ++i)
1167 if (i < level)
1168 continue;
1170 /* Ensure the variable is referenced. */
1171 if (candl_dependence_var_is_ref(statement, var_index) != CANDL_VAR_UNDEF) {
1172 if (count == buffer_size) {
1173 buffer_size *= 2;
1174 CANDL_realloc(res, osl_statement_p*,
1175 sizeof(osl_statement_p) * buffer_size);
1177 res[count++] = statement;
1181 CANDL_realloc(res, osl_statement_p*,
1182 sizeof(osl_statement_p) * (count+1));
1183 res[count] = NULL;
1185 return res;
1190 * candl_dependence_var_is_ref function:
1191 * This function checks if a var 'var_index' is referenced (DEF or
1192 * USE) by the statement.
1194 int candl_dependence_var_is_ref(osl_statement_p s, int var_index) {
1195 osl_relation_list_p access;
1196 osl_relation_p elt;
1197 int row;
1198 int ret = CANDL_VAR_UNDEF;
1200 if (s) {
1201 /* read access */
1202 access = s->access;
1203 while (access != NULL) {
1204 elt = access->elt;
1205 if (elt->type == OSL_TYPE_READ) {
1206 row = candl_relation_get_line(elt, 0);
1207 if (osl_int_get_si(elt->precision, elt->m[row], elt->nb_columns-1) ==
1208 var_index) {
1209 ret = CANDL_VAR_IS_USED;
1210 break;
1213 access = access->next;
1216 /* right access */
1217 access = s->access;
1218 while (access != NULL) {
1219 elt = access->elt;
1220 if (elt->type != OSL_TYPE_READ) {
1221 row = candl_relation_get_line(elt, 0);
1222 if (osl_int_get_si(elt->precision, elt->m[row], elt->nb_columns-1) ==
1223 var_index) {
1224 if (ret == CANDL_VAR_IS_USED)
1225 ret = CANDL_VAR_IS_DEF_USED;
1226 else
1227 ret = CANDL_VAR_IS_DEF;
1228 break;
1231 access = access->next;
1235 return ret;
1240 * candl_dependence_compute_lb function:
1241 * This function assigns to the Entier 'lb' the lexmin of variable
1242 * 'col'-1 in the polyhedron 'm'.
1244 static void candl_dependence_compute_lb(osl_relation_p m, Entier* lb, int col) {
1245 PipOptions* options;
1246 PipQuast* solution;
1247 PipList* l;
1248 options = pip_options_init();
1249 options->Simplify = 1;
1250 options->Urs_parms = -1;
1251 options->Urs_unknowns = -1;
1252 /* Compute lexmin. */
1253 solution = pip_solve_osl(m, NULL, -1, options);
1255 if ((solution != NULL) &&
1256 ((solution->list != NULL) || (solution->condition != NULL))) {
1257 l = solution->list;
1258 while (col-- > 1)
1259 l = l->next;
1260 CANDL_assign(*lb, l->vector->the_vector[0]);
1262 pip_options_free(options);
1263 pip_quast_free(solution);
1268 * candl_dependence_check_domain_is_included function:
1269 * This function checks if the 'level'-first iterators of 2 domains
1270 * are in such a way that s1 is larger or equal to s2, for the
1271 * considered iterator dimensions.
1274 int candl_dependence_check_domain_is_included(osl_statement_p s1,
1275 osl_statement_p s2,
1276 osl_relation_p context,
1277 int level) {
1278 candl_statement_usr_p s1_usr = s1->usr;
1279 candl_statement_usr_p s2_usr = s2->usr;
1280 osl_relation_p matrix;
1281 int max = level;
1282 int i, j;
1283 int precision = s2->domain->precision;
1284 Entier lb;
1285 CANDL_init(lb);
1287 if (s1_usr->depth < max) max = s1_usr->depth;
1288 if (s2_usr->depth < max) max = s2_usr->depth;
1290 matrix = osl_relation_pmalloc(precision,
1291 s2->domain->nb_rows + s2_usr->depth - max + 1,
1292 s2->domain->nb_columns);
1294 /* Duplicate s2 to the dest matrix. */
1295 for (i = 0; i < s2->domain->nb_rows; ++i) {
1296 for (j = 0; j < s2->domain->nb_columns; ++j)
1297 osl_int_assign(precision,
1298 matrix->m[i], j,
1299 s2->domain->m[i], j);
1302 /* Make useless dimensions equal to 1. */
1303 for (j = 0; j < s2_usr->depth - max; ++j) {
1304 candl_dependence_compute_lb(s2->domain, &lb, j + 1 + max);
1305 osl_int_assign(precision,
1306 matrix->m[i], matrix->nb_columns-1,
1307 (void*) &lb, 0);
1308 osl_int_set_si(precision,
1309 matrix->m[i++], j+1+max,
1310 -1);
1313 /* Iterate on all constraints of s1, and check them. */
1314 for (i = 0; i < s1->domain->nb_rows; ++i) {
1315 /* Skip constraints defining other iterators. */
1316 for (j = max + 1; j <= s1_usr->depth; ++j) {
1317 if (!osl_int_zero(precision, s1->domain->m[i], j))
1318 break;
1320 if (j <= s1_usr->depth)
1321 continue;
1322 /* Invert the constraint, and add it to matrix. */
1323 for (j = 0; j <= max; ++j) {
1324 osl_int_assign(precision,
1325 matrix->m[matrix->nb_rows-1], j,
1326 s1->domain->m[i], j);
1327 osl_int_oppose(precision,
1328 matrix->m[matrix->nb_rows-1], j,
1329 matrix->m[matrix->nb_rows-1], j);
1331 for (j = s1_usr->depth + 1; j < s1->domain->nb_columns; ++j) {
1332 osl_int_assign(precision,
1333 matrix->m[matrix->nb_rows-1],
1334 j - s1_usr->depth + s2_usr->depth,
1335 s1->domain->m[i], j);
1336 osl_int_oppose(precision,
1337 matrix->m[matrix->nb_rows-1],
1338 j - s1_usr->depth + s2_usr->depth,
1339 matrix->m[matrix->nb_rows-1],
1340 j - s1_usr->depth + s2_usr->depth);
1342 /* Make the inequality strict. */
1343 osl_int_decrement(precision,
1344 matrix->m[matrix->nb_rows-1], matrix->nb_columns-1,
1345 matrix->m[matrix->nb_rows-1], matrix->nb_columns-1);
1347 if (candl_matrix_check_point(matrix, context)) {
1348 /* There is a point. dom(s1) - dom(s2) > 0. */
1349 CANDL_clear(lb);
1350 osl_relation_free(matrix);
1351 return 0;
1355 CANDL_clear(lb);
1356 osl_relation_free(matrix);
1358 return 1;
1363 * candl_dependence_extract_scalar_variables function:
1364 * This functions returns a -1-terminated array of the scop scalar
1365 * variables.
1367 int* candl_dependence_extract_scalar_variables(osl_scop_p scop) {
1368 osl_statement_p statement;
1369 osl_relation_p elt;
1370 osl_relation_list_p access;
1371 int scalars[1024]; /* FIXME: implement a real buffer. */
1372 int checked[1024];
1373 int i, idx;
1374 int row;
1375 int count_s = 0, count_c = 0;
1377 /* Detect all scalar variables. */
1378 statement = scop->statement;
1379 while (statement != NULL) {
1380 access = statement->access;
1381 while (access != NULL) {
1382 elt = access->elt;
1383 row = candl_relation_get_line(elt, 0);
1384 idx = osl_int_get_si(elt->precision,
1385 elt->m[row],
1386 elt->nb_columns-1);
1388 for (i = 0; i < count_s && scalars[i] != idx; ++i)
1390 if (i == count_s) {
1391 for (i = 0; i < count_c && checked[i] != idx; ++i)
1393 if (i == count_c) {
1394 if (candl_dependence_var_is_scalar(scop, idx))
1395 scalars[count_s++] = idx;
1396 else
1397 checked[count_c++] = idx;
1399 if (count_s == 1024 || count_c == 1024)
1400 CANDL_error("Error: Buffer size too small");
1402 access = access->next;
1404 statement = statement->next;
1407 /* Rearrange the array to the exact size. */
1408 int *res;
1409 CANDL_malloc(res, int*, (count_s + 1) * sizeof(int));
1410 for (i = 0; i < count_s; ++i)
1411 res[i] = scalars[i];
1412 res[i] = -1;
1414 return res;
1419 * osl_dependence_prune_scalar_waw function:
1420 * This function removes all WAW dependences between the same scalar
1421 * (they are useless dependences).
1423 void osl_dependence_prune_scalar_waw(osl_scop_p scop,
1424 candl_options_p options,
1425 osl_dependence_p* deps) {
1426 int* scalars;
1427 int i;
1428 int refs, reft;
1429 osl_dependence_p tmp;
1430 osl_dependence_p next;
1431 osl_dependence_p pred = NULL;
1433 if (options->verbose)
1434 fprintf (stderr, "[Candl] Scalar Analysis: Remove all WAW between the same"
1435 " scalar\n");
1437 scalars = candl_dependence_extract_scalar_variables(scop);
1439 for (tmp = *deps; tmp; ) {
1440 candl_dependence_get_array_refs_in_dep(tmp, &refs, &reft);
1441 if (refs == reft && tmp->type == OSL_DEPENDENCE_WAW) {
1442 for (i = 0; scalars[i] != -1 && scalars[i] != refs; ++i)
1444 if (scalars[i] != -1) {
1445 osl_relation_free(tmp->domain);
1446 next = tmp->next;
1447 if (pred == NULL)
1448 *deps = next;
1449 else
1450 pred->next = next;
1451 free(tmp);
1452 tmp = next;
1453 continue;
1456 pred = tmp;
1457 tmp = tmp->next;
1460 free(scalars);
1465 * candl_dependence_scalar_renaming function:
1466 * This function renames scalars in the program. In case scalars have
1467 * been renamed, the dependence analysis is re-run.
1469 int candl_dependence_scalar_renaming(osl_scop_p scop,
1470 candl_options_p options,
1471 osl_dependence_p* deps) {
1472 osl_statement_p *statement; /* not a chained list */
1473 osl_statement_p iter;
1474 osl_statement_p defs[1024];
1475 osl_statement_p uses[1024];
1476 osl_statement_p last_def;
1477 osl_statement_p *current; /* not a chained list */
1478 osl_relation_p elt;
1479 osl_relation_list_p access;
1480 candl_statement_usr_p usr;
1481 candl_statement_usr_p last_usr;
1482 int i, j, k;
1483 int nb_statements = 0;
1484 int *parts;
1485 int defs_c, uses_c;
1486 int *scalars;
1487 int precision = scop->context->precision;
1488 int row;
1489 int tmp, has_changed = 0;
1490 int newvar = 0;
1492 if (options->verbose)
1493 fprintf (stderr, "[Candl] Scalar Analysis: Perform scalar renaming\n");
1495 /* Compute the first free variable index seed. */
1496 for (iter = scop->statement; iter != NULL; iter = iter->next) {
1497 access = iter->access;
1498 for (; access != NULL; access = access->next) {
1499 elt = access->elt;
1500 row = candl_relation_get_line(elt, 0);
1501 tmp = osl_int_get_si(precision,
1502 elt->m[row],
1503 elt->nb_columns-1);
1504 if (tmp >= newvar)
1505 newvar = tmp + 1;
1507 nb_statements++;
1510 /* Init */
1511 CANDL_malloc(current, osl_statement_p*, sizeof(osl_statement_p) * nb_statements);
1512 CANDL_malloc(parts, int*, sizeof(int) * nb_statements);
1514 /* Get the list of scalars. */
1515 scalars = candl_dependence_extract_scalar_variables(scop);
1517 /* Iterate on all scalars. */
1518 for (i = 0; scalars[i] != -1; ++i) {
1519 /* Get all statements referencing the scalar. */
1520 statement = candl_dependence_refvar_chain(scop, NULL, scalars[i], 0);
1522 /* If the chain starts by a USE, we can't do anything. */
1523 if (statement[0] == NULL ||
1524 candl_dependence_var_is_ref(statement[0], scalars[i])
1525 != CANDL_VAR_IS_DEF) {
1526 free(statement);
1527 continue;
1530 /* Get all defs and all uses. */
1531 defs_c = 0;
1532 uses_c = 0;
1533 for (j = 0; statement[j]; ++j) {
1534 tmp = candl_dependence_var_is_ref(statement[j], scalars[i]);
1535 switch (tmp) {
1536 case CANDL_VAR_IS_USED:
1537 case CANDL_VAR_IS_DEF_USED:
1538 uses[uses_c++] = statement[j];
1539 break;
1540 case CANDL_VAR_IS_DEF:
1541 defs[defs_c++] = statement[j];
1542 break;
1546 /* Clean buffer. */
1547 j = 0;
1548 for (iter = scop->statement; iter != NULL; iter = iter->next)
1549 current[j++] = NULL;
1551 free(statement);
1553 /* Iterate on all DEFs. */
1554 last_def = NULL;
1555 for (j = 0; j < defs_c; ++j) {
1556 if (last_def == NULL) {
1557 last_def = defs[j];
1558 } else {
1559 /* Ensure the current DEF covers all iterations covered
1560 by the last checked one. */
1561 last_usr = last_def->usr;
1562 usr = defs[j]->usr;
1563 for (k = 0; k < last_usr->depth && k < usr->depth &&
1564 last_usr->index[k] == usr->index[k];
1565 ++k)
1567 /* We only need to check when there are common loops. */
1568 if (k && ! candl_dependence_check_domain_is_included
1569 (last_def, defs[j], scop->context, k + 1)) {
1570 usr = defs[j]->usr;
1571 current[usr->label] = last_def;
1572 continue;
1573 } else {
1574 last_def = defs[j];
1577 /* Create DEF-USE table. */
1578 for (k = 0; k < uses_c; ++k) {
1579 usr = uses[k]->usr;
1580 if (usr->label > ((candl_statement_usr_p)defs[j]->usr)->label)
1581 current[usr->label] = defs[j];
1585 /* Initialize partition table. */
1586 for (j = 0; j < nb_statements; ++j)
1587 parts[j] = -1;
1589 /* Create partitions. */
1590 for (j = 0; j < defs_c; ++j) {
1591 usr = defs[j]->usr;
1592 for (k = 0; k < nb_statements; ++k)
1593 if ((current[k] && current[k] == defs[j]) ||
1594 (k == usr->label && current[usr->label] == NULL))
1595 parts[k] = j;
1598 /* Check if it is needed to rename the scalar. */
1599 tmp = -1;
1600 for (j = 0; j < nb_statements; ++j)
1601 if (tmp == -1) {
1602 if (parts[j] != -1)
1603 tmp = parts[j];
1604 } else {
1605 if (parts[j] != -1 && tmp != parts[j])
1606 break;
1609 /* Rename scalar variable. */
1610 if (j != nb_statements) {
1611 tmp = -1;
1612 j = 0;
1613 for (iter = scop->statement ; iter != NULL ; iter = iter->next) {
1614 if (parts[j] != -1) {
1615 if (tmp == -1)
1616 tmp = parts[j];
1617 else if (tmp != parts[j])
1618 has_changed = 1;
1620 access = iter->access;
1621 for (; access != NULL; access = access->next) {
1622 elt = access->elt;
1623 row = candl_relation_get_line(elt, 0);
1624 tmp = osl_int_get_si(precision,
1625 elt->m[row],
1626 elt->nb_columns-1);
1627 if (tmp == scalars[i]) {
1628 if (options->verbose)
1629 fprintf (stderr, "[Candl] Scalar analysis: Renamed "
1630 "variable %d to %d at statement S%d\n",
1631 scalars[i], newvar + parts[j], j);
1632 osl_int_set_si(precision,
1633 elt->m[row],
1634 elt->nb_columns-1,
1635 newvar + parts[j]);
1639 j++;
1642 } /* end Iterate on all scalars */
1644 /* Redo the full dependence analysis, if needed. */
1645 if (has_changed) {
1646 int bopt = options->scalar_renaming;
1647 options->scalar_renaming = 0;
1648 if (options->scalar_privatization)
1649 free(((candl_scop_usr_p)scop->usr)->scalars_privatizable);
1650 osl_dependence_free(*deps);
1651 *deps = candl_dependence(scop, options);
1652 options->scalar_renaming = bopt;
1655 free(scalars);
1656 free(current);
1657 free(parts);
1659 return has_changed;
1664 * candl_dependence_is_loop_carried function:
1665 * This function returns true if the dependence 'dep' is loop-carried
1666 * for loop 'loop_index', false otherwise.
1668 int candl_dependence_is_loop_carried(osl_scop_p scop,
1669 osl_dependence_p dep,
1670 int loop_index) {
1671 osl_relation_p msrc = NULL, mtarg = NULL;
1672 candl_statement_usr_p s_usr = dep->stmt_source_ptr->usr;
1673 candl_statement_usr_p t_usr = dep->stmt_target_ptr->usr;
1674 int i, j;
1675 int k, kp, l;
1676 int row_k, row_kp;
1677 int precision = scop->context->precision;
1679 /* Ensure source and sink share common loop 'loop_index', and that
1680 dependence depth is consistent with the considered loop. */
1681 for (i = 0; i < s_usr->depth; ++i)
1682 if (s_usr->index[i] == loop_index)
1683 break;
1684 if (i != dep->depth - 1 || i >= t_usr->depth)
1685 return 0;
1686 for (j = 0; j < t_usr->depth; ++j)
1687 if (t_usr->index[j] == loop_index)
1688 break;
1689 if (j != i)
1690 return 0;
1692 msrc = candl_dependence_get_relation_ref_source_in_dep(dep);
1693 mtarg = candl_dependence_get_relation_ref_target_in_dep(dep);
1695 /* plus one for the Arr output dim */
1696 int src_ref_iter = (candl_relation_get_line(msrc, i+1) != -1);
1697 int dst_ref_iter = (candl_relation_get_line(mtarg,j+1) != -1);
1699 /* Ensure it is not a basic loop-independent dependence (pure
1700 equality of the access functions for the surrounding iterators +
1701 parameters + constant, no occurence of the inner loop iterators,
1702 and contain the current loop iterator. */
1703 int must_test = 0;
1704 k = 1; // start after the Arr column
1705 row_k = candl_relation_get_line(msrc, k);
1706 while (!must_test &&
1707 k < msrc->nb_output_dims &&
1708 osl_int_zero(precision, msrc->m[row_k], 0)) {
1710 // Ensure the reference do reference the current loop iterator
1711 // to be tested.
1712 if (!osl_int_zero(precision, msrc->m[row_k], i)) {
1713 kp = 1;
1714 row_kp = candl_relation_get_line(mtarg, kp);
1716 while (!must_test &&
1717 kp < mtarg->nb_output_dims &&
1718 osl_int_zero(precision, mtarg->m[row_kp], 0)) {
1720 if (!osl_int_zero(precision, mtarg->m[row_kp], j)) {
1721 // Ensure the access functions are equal for the
1722 // surrounding loop iterators, and no inner iterator
1723 // is referenced.
1724 if (!osl_int_eq(precision,
1725 msrc->m[row_k], 0,
1726 mtarg->m[row_kp], 0)) {
1727 must_test = 1;
1728 } else {
1729 for (l = 1; l <= i; ++l)
1730 if (!osl_int_eq(precision,
1731 msrc->m[row_k], msrc->nb_output_dims + l,
1732 mtarg->m[row_kp], mtarg->nb_output_dims + l)) {
1733 must_test = 1;
1734 break;
1737 int m = l;
1738 if (!must_test)
1739 for (; l <= s_usr->depth+1; ++l)
1740 if (!osl_int_zero(precision, msrc->m[row_k], msrc->nb_output_dims + l)) {
1741 must_test = 1;
1742 break;
1744 if (!must_test)
1745 for (; m <= t_usr->depth+1; ++m)
1746 if (!osl_int_zero(precision, mtarg->m[row_kp], mtarg->nb_output_dims + m)) {
1747 must_test = 1;
1748 break;
1750 if (!must_test)
1751 for (; l < msrc->nb_columns-1; ++l, ++m)
1752 if (!osl_int_eq(precision,
1753 msrc->m[row_k], msrc->nb_output_dims + l,
1754 mtarg->m[row_kp], mtarg->nb_output_dims + m)) {
1755 must_test = 1;
1756 break;
1759 ++kp;
1760 row_kp = candl_relation_get_line(mtarg, kp);
1763 ++k;
1764 row_k = candl_relation_get_line(msrc, k);
1767 if (src_ref_iter && dst_ref_iter && !must_test)
1768 return 0;
1770 /* Final check. For loop i, the dependence is loop carried if there exists
1771 x_i^R != x_i^S in the dependence polyhedron, with
1772 x_{1..i-1}^R = x_{1..i-1}^S
1774 int pos;
1775 osl_relation_p mat = dep->domain;
1777 osl_relation_p testsyst = osl_relation_pmalloc(precision,
1778 mat->nb_rows + 1 + s_usr->depth,
1779 mat->nb_columns);
1780 for (pos = 0; pos < mat->nb_rows; ++pos)
1781 for (j = 0; j < mat->nb_columns; ++j)
1782 osl_int_assign(precision,
1783 testsyst->m[pos], j,
1784 mat->m[pos], j);
1785 for (j = 0; j < i; ++j) {
1786 osl_int_set_si(precision, testsyst->m[pos+j+1], 0, 0);
1787 osl_int_set_si(precision, testsyst->m[pos+j+1], 1+j, -1);
1788 osl_int_set_si(precision, testsyst->m[pos+j+1], 1+j+mat->nb_output_dims, 1);
1791 int has_pt = 0;
1792 // Test for '>'.
1793 osl_int_set_si(precision,testsyst->m[pos], 0, 1);
1794 osl_int_set_si(precision,testsyst->m[pos], testsyst->nb_columns-1, -1);
1795 osl_int_set_si(precision,testsyst->m[pos], 1+i, 1);
1796 osl_int_set_si(precision,testsyst->m[pos], 1+i+mat->nb_output_dims, -1);
1798 has_pt = pip_has_rational_point(testsyst, NULL, 1);
1799 if (!has_pt) {
1800 // Test for '<'.
1801 osl_int_set_si(precision, testsyst->m[pos], 1+i, -1);
1802 osl_int_set_si(precision, testsyst->m[pos], 1+i+mat->nb_output_dims, 1);
1803 has_pt = pip_has_rational_point(testsyst, NULL, 1);
1806 return has_pt;
1808 /* LNP: OLD VERSION */
1809 /* The above is more robust. */
1810 /* /\* Final check. The dependence exists only because the loop */
1811 /* iterates. Make the loop not iterate and check if there's still */
1812 /* dependent iterations. *\/ */
1813 /* CandlMatrix* m = candl_matrix_malloc(dep->domain->NbRows + 2, */
1814 /* dep->domain->NbColumns); */
1815 /* CANDL_set_si(m->p[m->NbRows - 2][i + 1], -1); */
1816 /* CANDL_set_si(m->p[m->NbRows - 1][dep->source->depth + 1 + j], -1); */
1817 /* /\* Copy the rest of the matrix. *\/ */
1818 /* int ii, jj; */
1819 /* for (ii = 0; ii < dep->domain->NbRows; ++ii) */
1820 /* for (jj = 0; jj < dep->domain->NbColumns; ++jj) */
1821 /* CANDL_assign(m->p[ii][jj], dep->domain->p[ii][jj]); */
1822 /* /\* Compute real lb of loops. *\/ */
1823 /* Entier lb; CANDL_init(lb); */
1824 /* candl_dependence_compute_lb (m, &lb, i + 1); */
1825 /* CANDL_assign(m->p[m->NbRows - 2][m->NbColumns - 1], lb); */
1826 /* candl_dependence_compute_lb (m, &lb, dep->source->depth + 1 + j); */
1827 /* CANDL_assign(m->p[m->NbRows - 1][m->NbColumns - 1], lb); */
1828 /* int ret = candl_matrix_check_point(m, program->context); */
1829 /* CANDL_clear(lb); */
1831 /* /\* Be clean. *\/ */
1832 /* candl_matrix_free(m); */
1834 /* return !ret; */
1839 * candl_dependence_prune_with_privatization function: This function
1840 * prunes the dependence graph 'deps' by removing loop-carried
1841 * dependences involving a scalar variable privatizable for that loop.
1843 void candl_dependence_prune_with_privatization(osl_scop_p scop,
1844 candl_options_p options,
1845 osl_dependence_p* deps) {
1846 osl_dependence_p next;
1847 osl_dependence_p tmp;
1848 osl_dependence_p pred = NULL;
1849 candl_statement_usr_p s_usr;
1850 candl_statement_usr_p t_usr;
1851 candl_scop_usr_p scop_usr = scop->usr;
1852 int is_priv;
1853 int i;
1854 int row;
1855 int loop_idx = 0;
1856 int refs, reft;
1857 int loop_pos_priv;
1858 int precision = scop->context->precision;
1860 if (options->verbose)
1861 fprintf (stderr, "[Candl] Scalar Analysis: Remove loop-carried dependences"
1862 " on privatizable scalars\n");
1864 if (scop->statement == NULL)
1865 return;
1867 /* Perform the scalar analysis, if not done before. */
1868 if (scop_usr->scalars_privatizable == NULL) {
1869 candl_options_p options = candl_options_malloc();
1870 options->scalar_privatization = 1;
1871 candl_dependence_analyze_scalars(scop, options);
1872 candl_options_free(options);
1875 for (tmp = *deps; tmp; ) {
1876 s_usr = tmp->stmt_source_ptr->usr;
1877 t_usr = tmp->stmt_target_ptr->usr;
1879 /* Check if the dependence is involving a privatizable scalar. */
1880 is_priv = 1;
1881 candl_dependence_get_array_refs_in_dep(tmp, &refs, &reft);
1882 for (i = 0; i < s_usr->depth; ++i) {
1883 if (candl_dependence_scalar_is_privatizable_at(scop, refs,
1884 s_usr->index[i]))
1885 break;
1887 if (i == s_usr->depth) {
1888 for (i = 0; i < t_usr->depth; ++i) {
1889 if (candl_dependence_scalar_is_privatizable_at
1890 (scop, reft, t_usr->index[i]))
1891 break;
1893 if (i == t_usr->depth)
1894 is_priv = 0;
1895 else
1896 loop_idx = t_usr->index[i];
1897 } else {
1898 loop_idx = s_usr->index[i];
1900 loop_pos_priv = i;
1902 /* Check if the dependence is loop-carried at loop i. */
1903 if (is_priv && candl_dependence_is_loop_carried(scop, tmp, loop_idx)) {
1904 /* If so, make the dependence loop-independent. */
1905 row = tmp->domain->nb_rows;
1906 osl_relation_insert_blank_row(tmp->domain, row);
1907 osl_int_set_si(precision,
1908 tmp->domain->m[row], 1 + loop_pos_priv,
1910 osl_int_set_si(precision,
1911 tmp->domain->m[row], 1 + loop_pos_priv +
1912 s_usr->depth,
1913 -1);
1915 /* Set the type of the dependence as special
1916 scalar-privatization one. */
1917 if (tmp->type == OSL_DEPENDENCE_RAW)
1918 tmp->type = OSL_DEPENDENCE_RAW_SCALPRIV;
1919 next = tmp->next;
1920 if (!candl_matrix_check_point(tmp->domain, NULL)) {
1921 /* It is, the dependence can be removed. */
1922 osl_relation_free(tmp->domain);
1923 if (pred == NULL)
1924 *deps = next;
1925 else
1926 pred->next = next;
1927 free(tmp);
1929 pred = tmp;
1930 tmp = next;
1932 continue;
1934 /* Go to the next victim. */
1935 pred = tmp;
1936 tmp = tmp->next;
1942 * candl_dependence_is_privatizable function:
1943 * This function checks if a given scalar 'var_index' is privatizable
1944 * for loop 'loop_index'.
1946 int candl_dependence_scalar_is_privatizable_at(osl_scop_p scop,
1947 int var_index,
1948 int loop_index) {
1949 candl_scop_usr_p scop_usr = scop->usr;
1950 int i;
1952 /* If the scalar analysis wasn't performed yet, do it. */
1953 if (scop_usr->scalars_privatizable == NULL) {
1954 candl_options_p options = candl_options_malloc();
1955 options->scalar_privatization = 1;
1956 candl_dependence_analyze_scalars(scop, options);
1957 candl_options_free(options);
1960 i = 0;
1961 while (scop_usr->scalars_privatizable[i] != -1)
1962 i++;
1964 /* Check in the array of privatizable scalar variables for the tuple
1965 (var,loop). */
1966 for (i = 0; scop_usr->scalars_privatizable[i] != -1; i += 2)
1967 if (scop_usr->scalars_privatizable[i] == var_index &&
1968 scop_usr->scalars_privatizable[i + 1] == loop_index)
1969 return 1;
1971 return 0;
1976 * candl_dependence_analyze_scalars function:
1977 * This function checks, for all scalar variables of the scop, and
1978 * all loop levels, if the scalar can be privatized at that level.
1980 int candl_dependence_analyze_scalars(osl_scop_p scop,
1981 candl_options_p options) {
1982 int* scalars;
1983 osl_statement_p* statement; /* not a chained list, but an array of */
1984 osl_statement_p* fullchain; /* statement to not realloc the usr field */
1985 osl_statement_p s;
1986 osl_statement_p curlast;
1987 osl_statement_p last;
1988 osl_statement_p iter; /* used to iterate on the scop */
1989 osl_relation_list_p access;
1990 osl_relation_p elt;
1991 candl_scop_usr_p scop_usr = scop->usr;
1992 candl_statement_usr_p stmt_usr;
1993 int i, j, k;
1994 int max, is_priv, offset, was_priv;
1995 int nb_priv = 0;
1996 int priv_buff_size = 64;
1997 int row;
1999 /* Initialize the list of privatizable scalars to empty. */
2000 if (options->scalar_privatization) {
2001 CANDL_malloc(scop_usr->scalars_privatizable, int*, 2 * sizeof(int));
2002 scop_usr->scalars_privatizable[0] = -1;
2003 scop_usr->scalars_privatizable[1] = -1;
2006 /* Retrieve all scalar variables. */
2007 scalars = candl_dependence_extract_scalar_variables(scop);
2009 /* For each of those, detect (at any level) if it can be privatized
2010 / expanded / renamed. */
2011 for (i = 0; scalars[i] != -1; ++i) {
2012 /* Go to the first statement referencing the scalar in the scop. */
2013 for (iter = scop->statement; iter != NULL; iter = iter->next) {
2014 if (candl_dependence_var_is_ref(iter, scalars[i])
2015 != CANDL_VAR_UNDEF)
2016 break;
2019 /* A weird error occured. */
2020 if (iter == NULL)
2021 continue;
2023 /* Take all statements referencing the scalar. */
2024 fullchain = candl_dependence_refvar_chain(scop, iter, scalars[i], 0);
2026 /* Compute the maximum loop depth of the chain. */
2027 max = 0;
2028 for (k = 0; fullchain[k]; ++k) {
2029 stmt_usr = fullchain[k]->usr;
2030 if (max < stmt_usr->depth)
2031 max = stmt_usr->depth;
2033 last = fullchain[k-1];
2035 /* Initialize the offset for expansion. */
2036 offset = 0;
2037 was_priv = 0;
2039 /* Iterate on all possible depth for analysis. */
2040 for (j = 1; j <= max; ++j) {
2041 s = fullchain[0];
2043 if (was_priv) {
2044 ++offset;
2045 was_priv = 0;
2048 do {
2049 /* Take all statements dominated by s referencing the
2050 current scalar variable. */
2051 statement = candl_dependence_refvar_chain(scop, s, scalars[i], j);
2053 /* No more statement in the chain, exit. */
2054 if (statement[0] == NULL) {
2055 free(statement);
2056 break;
2059 int c = 0;
2061 is_priv = candl_dependence_var_is_ref(statement[0], scalars[i]) ==
2062 CANDL_VAR_IS_DEF;
2064 /* Ensure we have a use in the chain. */
2065 /* here statement[c] is not NULL */
2066 for (k = c + 1; statement[k]; ++k) {
2067 if (candl_dependence_var_is_ref(statement[k], scalars[i]) ==
2068 CANDL_VAR_IS_USED)
2069 break;
2072 if (statement[k] == NULL)
2073 is_priv = 0;
2075 /* Check for privatization, while the entry of the chain
2076 is a DEF. */
2077 while (statement[c] && candl_dependence_var_is_ref
2078 (statement[c], scalars[i]) == CANDL_VAR_IS_DEF) {
2079 /* From the current DEF node, ensure the rest of the
2080 chain covers not more than the iteration domain
2081 of the DEF. */
2082 for (k = c + 1; statement[k]; ++k) {
2083 /* FIXME: we should deal with
2084 def_1->use->def_2->use chains where dom(def_2)
2085 > dom(def_1). */
2086 if (! candl_dependence_check_domain_is_included
2087 (statement[c], statement[k], scop->context, j)) {
2088 /* dom(use) - dom(def) > 0. Check if there is
2089 another DEF to test at the entry of the
2090 block. */
2091 if (candl_dependence_var_is_ref
2092 (statement[c+1], scalars[i]) != CANDL_VAR_IS_DEF)
2093 /* No. The variable is not privatizable. */
2094 is_priv = 0;
2095 break;
2099 if (! is_priv || ! statement[k])
2100 break;
2102 /* The chain dominated by statement is not
2103 privatizable. Go for the next DEF at the
2104 beginning of the block, if any. */
2105 ++c;
2108 if (is_priv) {
2109 /* Perform the privatization / expansion. */
2110 if (options->verbose)
2111 fprintf(stderr, "[Candl] Scalar Analysis: The variable %d"
2112 " can be privatized at loop %d\n",
2113 scalars[i],
2114 ((candl_statement_usr_p)statement[0]->usr)->index[j-1]);
2116 if (options->scalar_expansion) {
2117 int precision = scop->context->precision;
2118 /* Traverse all statements in the chain. */
2119 for (k = c; statement[k]; ++k) {
2120 /* It's not the first expansion of the scalar,
2121 we need to increase its dimension all along
2122 the program. */
2123 if (!offset && !was_priv)
2124 candl_dependence_expand_scalar(fullchain,
2125 scalars[i]);
2126 /* Perform scalar expansion in the array
2127 access functions. */
2128 access = statement[k]->access;
2129 for (; access != NULL; access = access->next) {
2130 elt = access->elt;
2131 row = candl_relation_get_line(elt, 0);
2132 if (scalars[i] ==
2133 osl_int_get_si(precision, elt->m[row], elt->nb_columns-1)) {
2134 row = candl_relation_get_line(elt, offset+1);
2135 osl_int_set_si(precision, elt->m[row], elt->nb_output_dims + j, 1);
2138 was_priv = 1;
2142 if (options->scalar_privatization) {
2143 /* Memory management for the array of
2144 privatizable scalars. */
2145 if (nb_priv == 0) {
2146 free(scop_usr->scalars_privatizable);
2147 CANDL_malloc(scop_usr->scalars_privatizable,
2148 int*, priv_buff_size * sizeof(int));
2149 for (k = 0; k < priv_buff_size; ++k)
2150 scop_usr->scalars_privatizable[k] = -1;
2153 if (nb_priv == priv_buff_size) {
2154 CANDL_realloc(scop_usr->scalars_privatizable,
2155 int*, (priv_buff_size *= 2) * sizeof(int));
2156 for (k = nb_priv; k < priv_buff_size; ++k)
2157 scop_usr->scalars_privatizable[k] = -1;
2160 /* Memorize the scalar information in the
2161 privatizable list. */
2162 scop_usr->scalars_privatizable[nb_priv++] = scalars[i];
2163 scop_usr->scalars_privatizable[nb_priv++] =
2164 ((candl_statement_usr_p)statement[0]->usr)->index[j - 1];
2167 } // end is_priv
2170 /* Go to the next block, if any. */
2171 for (k = 0; statement[k]; ++k)
2173 curlast = statement[k-1];
2175 if (curlast != last) {
2176 for (k = 0; fullchain[k]; ++k) {
2177 if (fullchain[k] == curlast) {
2178 s = fullchain[k+1];
2179 break;
2183 free(statement);
2185 } while (curlast != last);
2187 } // end iterate all possible depth
2189 free(fullchain);
2191 } // end iterate scalars
2193 return 0;
2198 * Compute last writer for a given dependence; does not make sense if the
2199 * supplied dependence is not a RAW or WAW dependence
2201 * Returns 0 if lastwriter is computed successfully and dep domain updated,
2202 * returns 1 otherwise
2204 static
2205 int candl_dep_compute_lastwriter(osl_dependence_p *dep, osl_scop_p scop) {
2206 PipQuast *lexmax;
2207 PipOptions *pipOptions = pip_options_init();
2208 candl_statement_usr_p s_usr = (*dep)->stmt_source_ptr->usr;
2209 candl_statement_usr_p t_usr = (*dep)->stmt_target_ptr->usr;
2210 osl_relation_p new_domain;
2211 int i, j;
2212 int npar = scop->context->nb_parameters;
2213 int precision;
2215 #if defined(LINEAR_VALUE_IS_INT)
2216 precision = OSL_PRECISION_SP;
2217 #elif defined(LINEAR_VALUE_IS_LONGLONG)
2218 precision = OSL_PRECISION_DP;
2219 #elif defined(LINEAR_VALUE_IS_MP)
2220 precision = OSL_PRECISION_MP;
2221 #endif
2223 if (precision != scop->context->precision) {
2224 CANDL_error("Precision not compatible with piplib ! (pip_relation2matrix)");
2227 /* We do a parametric lexmax on the source iterators
2228 * keeping the target iterators as parameters */
2229 pipOptions->Maximize = 1;
2230 pipOptions->Simplify = 1;
2231 // pipOptions->Deepest_cut = 1;
2232 // pipOptions->Urs_unknowns = -1;
2233 // pipOptions->Urs_parms = -1;
2235 /* Build a context with equalities /inequalities only on the target
2236 * variables */
2237 osl_relation_p context = osl_relation_pmalloc(precision,
2238 (*dep)->domain->nb_rows,
2239 (*dep)->stmt_target_ptr->domain->nb_columns);
2240 int nrows = 0;
2241 for (i = 0; i < (*dep)->domain->nb_rows; i++) {
2242 for (j = 1; j < s_usr->depth+1; j++) {
2244 // FIXME : new domain structure for dependence
2246 if (!osl_int_zero(precision, (*dep)->domain->m[i], j))
2247 break;
2250 if (j == t_usr->depth+1) {
2251 /* Include this in the context */
2252 osl_int_assign(precision,
2253 context->m[nrows], 0,
2254 (*dep)->domain->m[i], 0);
2256 for (j = 1; j < (*dep)->stmt_target_ptr->domain->nb_columns; j++)
2257 osl_int_assign(precision,
2258 context->m[nrows], j,
2259 (*dep)->domain->m[i], s_usr->depth+j);
2261 nrows++;
2265 /* Parameteric lexmax */
2266 lexmax = pip_solve_osl((*dep)->domain, context, -1, pipOptions);
2268 pip_options_free(pipOptions);
2270 if (lexmax == NULL) {
2271 CANDL_warning("last writer failed (mostly invalid dependence): bailing out"
2272 "safely without modification");
2273 osl_relation_print(stderr, context);
2274 osl_relation_print(stderr, (*dep)->domain);
2275 return 1;
2278 int num;
2279 osl_relation_p qp = pip_quast_to_polyhedra(lexmax, s_usr->depth,
2280 t_usr->depth + npar);
2282 /* Update the dependence domains */
2283 if (num > 0) {
2284 osl_relation_p iter;
2285 osl_relation_p original_domain = (*dep)->domain;
2286 for (iter = qp ; iter != NULL ; iter = iter->next) {
2288 new_domain = osl_relation_pmalloc(precision,
2289 original_domain->nb_rows +
2290 qp->nb_rows,
2291 original_domain->nb_columns);
2293 for (i = 0; i < original_domain->nb_rows; i++)
2294 for (j = 0; j < original_domain->nb_columns; j++)
2295 osl_int_assign(precision,
2296 new_domain->m[i], j,
2297 original_domain->m[i], j);
2299 for (i = 0; i < qp->nb_rows; i++)
2300 for (j = 0; j < original_domain->nb_columns; j++)
2301 osl_int_assign(precision,
2302 new_domain->m[i+original_domain->nb_rows], j,
2303 qp->m[i], j);
2305 (*dep)->domain = new_domain;
2306 /* More than 1 pipmatrix from the quast, we need to insert
2307 new dependences to have the union of domains. */
2308 if (qp->next != NULL) {
2309 osl_dependence_p newdep = osl_dependence_malloc();
2310 newdep->stmt_source_ptr = (*dep)->stmt_source_ptr;
2311 newdep->stmt_target_ptr = (*dep)->stmt_target_ptr;
2312 newdep->depth = (*dep)->depth;
2313 newdep->type = (*dep)->type;
2314 newdep->label_source = (*dep)->label_source;
2315 newdep->label_target = (*dep)->label_target;
2316 newdep->ref_source = (*dep)->ref_source;
2317 newdep->ref_target = (*dep)->ref_target;
2318 newdep->usr = (*dep)->usr;
2319 newdep->source_nb_output_dims_domain = (*dep)->source_nb_output_dims_domain;
2320 newdep->source_nb_output_dims_access = (*dep)->source_nb_output_dims_access;
2321 newdep->target_nb_output_dims_domain = (*dep)->target_nb_output_dims_domain;
2322 newdep->target_nb_output_dims_access = (*dep)->target_nb_output_dims_access;
2323 newdep->source_nb_local_dims_domain = (*dep)->source_nb_local_dims_domain;
2324 newdep->source_nb_local_dims_access = (*dep)->source_nb_local_dims_access;
2325 newdep->target_nb_local_dims_domain = (*dep)->target_nb_local_dims_domain;
2326 newdep->target_nb_local_dims_access = (*dep)->target_nb_local_dims_access;
2327 newdep->next = (*dep)->next;
2328 (*dep)->next = newdep;
2329 *dep = newdep;
2333 osl_relation_free(original_domain);
2334 osl_relation_free(qp);
2337 pip_quast_free(lexmax);
2338 osl_relation_free(qp);
2339 osl_relation_free(context);
2341 return 0;
2345 * Compute the last writer for each RAW, WAW, and RAR dependence. This will
2346 * modify the dependence polyhedra. Be careful of any references to the old
2347 * dependence polyhedra. They are freed and new ones allocated.
2349 void candl_compute_last_writer(osl_dependence_p dep, osl_scop_p scop) {
2350 // int count=0;
2351 while (dep != NULL) {
2352 if (dep->type != OSL_DEPENDENCE_WAR) {
2353 // printf("Last writer for dep %d: %d %d\n", count++, dep->source->usr->depth, dep->target->usr->depth);
2354 // candl_matrix_print(stdout, dep->domain);
2355 candl_dep_compute_lastwriter(&dep, scop);
2356 // candl_matrix_print(stdout, dep->domain);
2358 dep = dep->next;