Support of the osl_int_t union type
[candl.git] / source / dependence.c
blob220966ea8cb0445312705da333fe10d0d0b55890
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, src->m[row][src->nb_columns - 1]);
136 row = candl_relation_get_line(targ, 0);
137 *reft = osl_int_get_si(precision, targ->m[row][targ->nb_columns - 1]);
141 /* osl_dependence_pprint function:
142 * This function prints the content of a osl_dependence_p structure (dependence)
143 * into a file (file, possibly stdout) as a Graphviz input file.
144 * See http://www.graphviz.org
145 * - 08/12/2005: first version.
147 void candl_dependence_pprint(FILE * file, osl_dependence_p dependence) {
148 int i = 0;
150 fprintf(file, "digraph G {\n");
152 fprintf(file, "# Data Dependence Graph\n");
153 fprintf(file, "# Generated by Candl "CANDL_RELEASE" "CANDL_VERSION" bits\n");
154 while (dependence != NULL) {
155 fprintf(file, " S%d -> S%d [label=\" ", dependence->label_source,
156 dependence->label_target);
157 switch (dependence->type) {
158 case OSL_UNDEFINED : fprintf(file, "UNSET"); break;
159 case OSL_DEPENDENCE_RAW : fprintf(file, "RAW") ; break;
160 case OSL_DEPENDENCE_WAR : fprintf(file, "WAR") ; break;
161 case OSL_DEPENDENCE_WAW : fprintf(file, "WAW") ; break;
162 case OSL_DEPENDENCE_RAR : fprintf(file, "RAR") ; break;
163 case OSL_DEPENDENCE_RAW_SCALPRIV :
164 fprintf(file, "RAW_SCALPRIV (scalar-priv)") ; break;
165 default : fprintf(file, "unknown"); break;
167 fprintf(file, " depth %d, ref %d->%d \"];\n", dependence->depth,
168 dependence->ref_source,
169 dependence->ref_target);
170 dependence = dependence->next;
171 i++;
174 if (i>4)
175 fprintf(file, "# Number of edges = %i\n}\n", i);
176 else
177 fprintf(file, "}\n");
181 /* candl_dependence_view function:
182 * This function uses dot (see http://www.graphviz.org) and gv (see
183 * http://wwwthep.physik.uni-mainz.de/~plass/gv) tools to display the
184 * dependence graph.
185 * - 20/03/2006: first version.
187 void candl_dependence_view(osl_dependence_p dep) {
188 FILE * temp_output;
189 temp_output = fopen(CANDL_TEMP_OUTPUT,"w+");
190 candl_dependence_pprint(temp_output, dep);
191 fclose(temp_output);
192 /* check the return to remove the warning compilation */
193 if(system("dot -Tps "CANDL_TEMP_OUTPUT" | gv - && rm -f "CANDL_TEMP_OUTPUT" &"))
198 #ifdef CANDL_SUPPORTS_ISL
200 struct isl_set* isl_set_from_piplib_matrix(struct isl_ctx* ctx,
201 osl_relation_p matrix,
202 int nparam);
203 osl_relation_p isl_set_to_piplib_matrix(struct isl_ctx* ctx,
204 struct isl_set* set,
205 int nparam);
207 * candl_dependence_isl_simplify function:
209 * This function uses ISL to simplify the dependence polyhedra.
210 * Useful for polyhedra that contain large coefficient values.
213 osl_dependence_p candl_dependence_isl_simplify(osl_dependence_p dep,
214 osl_scop_p scop) {
215 if (dep == NULL || scop == NULL)
216 return dep;
218 osl_dependence_p tmp;
219 osl_relation_p context = scop->context;
220 int nparam = context->nb_parameters;
222 struct isl_ctx* ctx = isl_ctx_alloc();
224 for (tmp = dep; tmp; tmp = tmp->next) {
225 // 1- Convert the dependence polyhedron into ISL set.
227 struct isl_set* set = isl_set_from_piplib_matrix(ctx, tmp->domain, nparam);
229 // 2- Simplify the ISL set.
230 set = isl_set_detect_equalities(set);
232 // 3- Convert back into Candl matrix representation.
233 osl_relation_p newdom = isl_set_to_piplib_matrix(ctx, set, nparam);
234 isl_set_free(set);
235 newdom->nb_output_dims = tmp->domain->nb_output_dims;
236 newdom->nb_input_dims = tmp->domain->nb_input_dims;
237 newdom->nb_local_dims = tmp->domain->nb_local_dims;
238 newdom->nb_parameters = tmp->domain->nb_parameters;
239 osl_relation_free(tmp->domain);
240 tmp->domain = newdom;
243 /// FIXME: Some dead ref.
244 //isl_ctx_free (ctx);
246 return dep;
249 #endif
252 /* candl_dependence_init_fields:
253 * Set the various other fields of the dependence structure
255 void candl_dependence_init_fields(osl_scop_p scop, osl_dependence_p dep) {
257 osl_statement_p iter;
258 candl_statement_usr_p usr;
259 osl_relation_p array_s, array_t;
261 /* source statement */
262 iter = scop->statement;
263 for (; iter != NULL ; iter = iter->next) {
264 usr = iter->usr;
265 if (usr->label == dep->label_source) {
266 dep->stmt_source_ptr = iter;
267 break;
270 if (iter == NULL) {
271 fprintf(stderr, "[Candl] Can't find the %dth label\n", dep->label_source);
272 exit(1);
275 /* target statement */
276 iter = scop->statement;
277 for (; iter != NULL ; iter = iter->next) {
278 usr = iter->usr;
279 if (usr->label == dep->label_target) {
280 dep->stmt_target_ptr = iter;
281 break;
284 if (iter == NULL) {
285 fprintf(stderr, "[Candl] Can't find the %dth label\n", dep->label_target);
286 exit(1);
289 array_s = candl_dependence_get_relation_ref_source_in_dep(dep);
290 if (array_s == NULL) {
291 fprintf(stderr, "[Candl] Can't find the %dth access of the statement :\n",
292 dep->ref_source);
293 osl_statement_dump(stderr, dep->stmt_source_ptr);
294 exit(1);
297 array_t = candl_dependence_get_relation_ref_source_in_dep(dep);
298 if (array_t == NULL) {
299 fprintf(stderr, "[Candl] Can't find the %dth access of the statement :\n",
300 dep->ref_target);
301 osl_statement_dump(stderr, dep->stmt_target_ptr);
302 exit(1);
305 dep->source_nb_output_dims_domain = dep->stmt_source_ptr->domain->nb_output_dims;
306 dep->source_nb_output_dims_access = array_s->nb_output_dims;
308 dep->target_nb_output_dims_domain = dep->stmt_target_ptr->domain->nb_output_dims;
309 dep->target_nb_output_dims_access = array_t->nb_output_dims;
311 dep->source_nb_local_dims_domain = dep->stmt_source_ptr->domain->nb_local_dims;
312 dep->source_nb_local_dims_access = array_s->nb_local_dims;
313 dep->target_nb_local_dims_domain = dep->stmt_target_ptr->domain->nb_local_dims;
314 dep->target_nb_local_dims_access = array_t->nb_local_dims;
319 * GCD computation.
321 static int candl_dependence_gcd(int a, int b) {
322 int z = 1;
324 if (a < 0)
325 a *= -1;
326 if (b < 0)
327 b *= -1;
328 if (a == 0)
329 return b;
330 if (b == 0)
331 return a;
332 if (b > a) {
333 int temp = a;
334 a = b;
335 b = temp;
338 while (z != 0) {
339 z = a % b;
340 a = b;
341 b = z;
344 return a;
351 static int candl_dependence_gcd_test_context(osl_relation_p system, int id) {
352 /* FIXME: implement me! */
354 return 1;
359 * candl_dependence_gcd_test function:
360 * This functions performs a GCD test on a dependence polyhedra
361 * represented exactly by a set of constraints 'system' organized in
362 * such a way:
363 * - first lines: iteration domain of 'source'
364 * - then: iteration domain of 'target'
365 * - then: array access equality(ies)
366 * - then (optional): precedence constraint inequality.
368 * The function returns false if the dependence is impossible, true
369 * otherwise. A series of simple checks (SIV/ZIV/MIV/bounds checking)
370 * are also performed before the actual GCD test.
373 int candl_dependence_gcd_test(osl_statement_p source,
374 osl_statement_p target,
375 osl_relation_p system,
376 int level) {
377 int i;
378 int gcd;
379 int id;
380 int value;
381 int null_iter, null_param, null_cst, pos_iter, neg_iter;
382 int precision = source->domain->precision;
383 candl_statement_usr_p s_usr = source->usr;
384 candl_statement_usr_p t_usr = target->usr;
386 /* Check that the precedence constraint, if any, is not strict in a
387 self-dependence. */
388 /* int strict_pred; */
389 /* if (source == target && */
390 /* CANDL_get_si(system->p[system->NbRows - 1][0]) == 1 && */
391 /* CANDL_get_si(system->p[system->NbRows - 1][system->NbColumns - 1]) == -1) */
392 /* strict_pred = 1; */
393 /* else */
394 /* strict_pred = 0; */
396 /* Inspect the array access function equalities. */
397 for (id = source->domain->nb_rows + target->domain->nb_rows;
398 id < system->nb_rows &&
399 osl_int_zero(precision, system->m[id][0]);
400 ++id) {
401 /* Inspect which parts of the access function equality are null,
402 positive or negative. */
403 null_iter = null_param = null_cst = pos_iter = neg_iter = 0;
405 for (i = 1; i < s_usr->depth + t_usr->depth + 1 &&
406 osl_int_zero(precision, system->m[id][i]); ++i)
409 if (i == s_usr->depth + t_usr->depth + 1)
410 null_iter = 1;
411 else
412 for (pos_iter = 1, neg_iter = 1;
413 i < s_usr->depth + t_usr->depth + 1; ++i) {
414 if (osl_int_neg(precision, system->m[id][i]))
415 pos_iter = 0;
416 else if (osl_int_pos(precision, system->m[id][i]))
417 neg_iter = 0;
419 for (; i < system->nb_columns - 1 &&
420 osl_int_zero(precision, system->m[id][i]) == 0; ++i)
422 if (i == system->nb_columns - 1)
423 null_param = 1;
424 null_cst = osl_int_zero(precision, system->m[id][system->nb_columns - 1]);
426 /* Some useful ZIV/SIV/MIV tests. */
427 if (null_iter && null_param && !null_cst)
428 return 0;
429 if (null_iter)
430 if (! candl_dependence_gcd_test_context(system, id))
431 return 0;
432 if (null_cst || !null_param)
433 continue;
434 /* FIXME: implement the loop bound check. */
435 /* /\* A clever test on access bounds. *\/ */
436 /* if (null_param && pos_iter && */
437 /* CANDL_get_si(system->p[id][system->NbColumns - 1]) > 0) */
438 /* return 0; */
439 /* if (null_param && neg_iter && */
440 /* CANDL_get_si(system->p[id][system->NbColumns - 1]) < 0) */
441 /* return 0; */
443 /* Compute GCD test for the array access equality. */
444 for (i = 1, gcd = osl_int_get_si(precision, system->m[id][i]);
445 i < s_usr->depth + t_usr->depth; ++i)
446 gcd = candl_dependence_gcd(gcd,
447 osl_int_get_si(precision, system->m[id][i + 1]));
449 value = osl_int_get_si(precision, system->m[id][system->nb_columns - 1]);
450 value = value < 0 ? -value : value;
451 if ((gcd == 0 && value != 0) || value % gcd)
452 return 0;
455 return 1;
460 * candl_dependence_build_system function:
461 * this function builds the constraint system corresponding to a data
462 * dependence, for a given statement couple (with iteration domains "source"
463 * and "target"), for a given reference couple (the source reference is array
464 * "ref_s" in "array_s" and the target reference is the array "ref_t" in
465 * "array_t"), at a given depth "depth" and knowing if the source is textually
466 * before the target (boolean "before"). The system is built... as always !
467 * See the [bastoul and Feautrier, PPL 2005] paper for details !
468 * - source is the source iteration domain,
469 * - target is the target iteration domain,
470 * - array_s is the access array for the source,
471 * - array_t is the access array for the target,
472 * - depth is the dependence depth,
473 * - before is 1 if the source is textually before the target, 0 otherwise,
475 * - 13/12/2005: first version (extracted from candl_dependence_system).
476 * - 23/02/2006: a stupid bug corrected in the subscript equality.
477 * - 07/04/2007: fix the precedence condition to respect C. Bastoul PhD thesis
479 static osl_dependence_p candl_dependence_build_system(
480 osl_statement_p source, osl_statement_p target,
481 osl_relation_p array_s, osl_relation_p array_t,
482 int depth, int before) {
483 osl_dependence_p dependence;
484 osl_relation_p system;
485 int i, j, k, c;
486 int constraint = 0;
487 int precision = source->domain->precision;
488 int nb_output_dims; // source column
489 int nb_input_dims; // target column
490 int nb_local_dims;
491 int nb_par;
492 int nb_rows, nb_columns;
493 int ind_source_local_domain;
494 int ind_source_local_access;
495 int ind_target_local_domain;
496 int ind_target_local_access;
497 int ind_params;
498 int min_depth = 0;
500 /* Create a new dependence structure */
501 dependence = osl_dependence_malloc();
503 /* Compute the maximal common depth. */
504 min_depth = CANDL_min(array_s->nb_output_dims, array_t->nb_output_dims);
506 /* Compute the system size */
507 dependence->source_nb_output_dims_domain = source->domain->nb_output_dims;
508 dependence->source_nb_output_dims_access = array_s->nb_output_dims;
510 dependence->target_nb_output_dims_domain = target->domain->nb_output_dims;
511 dependence->target_nb_output_dims_access = array_t->nb_output_dims;
513 dependence->source_nb_local_dims_domain = source->domain->nb_local_dims;
514 dependence->source_nb_local_dims_access = array_s->nb_local_dims;
515 dependence->target_nb_local_dims_domain = target->domain->nb_local_dims;
516 dependence->target_nb_local_dims_access = array_t->nb_local_dims;
518 nb_par = source->domain->nb_parameters;
519 nb_local_dims = dependence->source_nb_local_dims_domain +
520 dependence->source_nb_local_dims_access +
521 dependence->target_nb_local_dims_domain +
522 dependence->target_nb_local_dims_access;
523 nb_output_dims = dependence->source_nb_output_dims_domain +
524 dependence->source_nb_output_dims_access;
525 nb_input_dims = dependence->target_nb_output_dims_domain +
526 dependence->target_nb_output_dims_access;
528 nb_columns = nb_output_dims + nb_input_dims + nb_local_dims + nb_par + 2;
529 nb_rows = source->domain->nb_rows + target->domain->nb_rows +
530 array_s->nb_rows + array_t->nb_rows +
531 min_depth +
532 depth;
534 system = osl_relation_pmalloc(precision, nb_rows, nb_columns);
536 /* Compute some indexes */
537 ind_source_local_domain = 1 + nb_output_dims + nb_input_dims;
538 ind_source_local_access = ind_source_local_domain + dependence->source_nb_local_dims_domain;
539 ind_target_local_domain = ind_source_local_access + dependence->source_nb_local_dims_access;
540 ind_target_local_access = ind_target_local_domain + dependence->target_nb_local_dims_domain;
541 ind_params = ind_target_local_access + dependence->target_nb_local_dims_access;
543 /* 1. Copy the source domain */
544 for (i = 0 ; i < source->domain->nb_rows ; i++) {
545 /* eq/in */
546 osl_int_assign(precision,
547 &system->m[constraint][0], source->domain->m[i][0]);
548 /* output dims */
549 k = 1;
550 j = 1;
551 for (c = source->domain->nb_output_dims ; c > 0 ; c--, k++, j++)
552 osl_int_assign(precision,
553 &system->m[constraint][k], source->domain->m[i][j]);
554 /* local dims (no input in domain, so j is the same) */
555 k = ind_source_local_domain;
556 for (c = source->domain->nb_local_dims ; c > 0 ; c--, k++, j++)
557 osl_int_assign(precision,
558 &system->m[constraint][k], source->domain->m[i][j]);
559 /* params + const */
560 k = ind_params;
561 for (c = nb_par+1 ; c > 0 ; c--, k++, j++)
562 osl_int_assign(precision,
563 &system->m[constraint][k], source->domain->m[i][j]);
564 constraint++;
567 /* 2. Copy the target domain */
568 for (i = 0 ; i < target->domain->nb_rows ; i++) {
569 /* eq/in */
570 osl_int_assign(precision,
571 &system->m[constraint][0], target->domain->m[i][0]);
572 /* output dims */
573 k = 1 + nb_output_dims;
574 j = 1;
575 for (c = target->domain->nb_output_dims ; c > 0 ; c--, k++, j++)
576 osl_int_assign(precision,
577 &system->m[constraint][k], target->domain->m[i][j]);
578 /* local dims (no input in domain, so j is the same) */
579 k = ind_target_local_domain;
580 for (c = target->domain->nb_local_dims ; c > 0 ; c--, k++, j++)
581 osl_int_assign(precision,
582 &system->m[constraint][k], target->domain->m[i][j]);
583 /* params + const */
584 k = ind_params;
585 for (c = nb_par+1 ; c > 0 ; c--, k++, j++)
586 osl_int_assign(precision,
587 &system->m[constraint][k], target->domain->m[i][j]);
588 constraint++;
591 /* 3. Copy the source access */
592 for (i = 0 ; i < array_s->nb_rows ; i++) {
593 /* eq/in */
594 osl_int_assign(precision,
595 &system->m[constraint][0], array_s->m[i][0]);
596 /* output dims */
597 k = 1 + source->domain->nb_output_dims;
598 j = 1;
599 for (c = array_s->nb_output_dims ; c > 0 ; c--, k++, j++)
600 osl_int_assign(precision,
601 &system->m[constraint][k], array_s->m[i][j]);
602 /* link input dims access to the output dims domain */
603 k = 1;
604 for (c = array_s->nb_input_dims ; c > 0 ; c--, k++, j++)
605 osl_int_assign(precision,
606 &system->m[constraint][k], array_s->m[i][j]);
607 /* local dims */
608 k = ind_source_local_access;
609 for (c = array_s->nb_local_dims ; c > 0 ; c--, k++, j++)
610 osl_int_assign(precision,
611 &system->m[constraint][k], array_s->m[i][j]);
612 /* params + const */
613 k = ind_params;
614 for (c = nb_par+1 ; c > 0 ; c--, k++, j++)
615 osl_int_assign(precision,
616 &system->m[constraint][k], array_s->m[i][j]);
618 constraint++;
621 /* 4. Copy the target access */
622 for (i = 0 ; i < array_t->nb_rows ; i++) {
623 /* eq/in */
624 osl_int_assign(precision,
625 &system->m[constraint][0], array_t->m[i][0]);
626 /* output dims */
627 k = 1 + nb_output_dims + target->domain->nb_output_dims;
628 j = 1;
629 for (c = array_t->nb_output_dims ; c > 0 ; c--, k++, j++) {
630 osl_int_assign(precision,
631 &system->m[constraint][k], array_t->m[i][j]);
632 osl_int_oppose(precision,
633 &system->m[constraint][k], system->m[constraint][k]);
635 /* link input dims access to the output dims domain */
636 k = 1 + nb_output_dims;
637 for (c = array_t->nb_input_dims ; c > 0 ; c--, k++, j++) {
638 osl_int_assign(precision,
639 &system->m[constraint][k], array_t->m[i][j]);
640 osl_int_oppose(precision,
641 &system->m[constraint][k], system->m[constraint][k]);
643 /* local dims */
644 k = ind_target_local_access;
645 for (c = array_t->nb_local_dims ; c > 0 ; c--, k++, j++) {
646 osl_int_assign(precision,
647 &system->m[constraint][k], array_t->m[i][j]);
648 osl_int_oppose(precision,
649 &system->m[constraint][k], system->m[constraint][k]);
651 /* params + const */
652 k = ind_params;
653 for (c = nb_par+1 ; c > 0 ; c--, k++, j++) {
654 osl_int_assign(precision,
655 &system->m[constraint][k], array_t->m[i][j]);
656 osl_int_oppose(precision,
657 &system->m[constraint][k], system->m[constraint][k]);
659 constraint++;
663 /* 5. Set the equality between the output access */
664 /* Note here that the equality between the 2 Arr are necessarily equal */
665 k = 1 + source->domain->nb_output_dims;
666 j = 1 + nb_output_dims + target->domain->nb_output_dims;
667 for (i = 0 ; i < min_depth ; i++, k++, j++) {
668 osl_int_set_si(precision, &system->m[constraint][k], -1);
669 osl_int_set_si(precision, &system->m[constraint][j], 1);
670 constraint++;
673 /* 6. The precedence constraints */
674 int min_dim = 0;
675 while (min_dim < ((candl_statement_usr_p)source->usr)->depth &&
676 min_dim < ((candl_statement_usr_p)target->usr)->depth &&
677 ((candl_statement_usr_p)source->usr)->index[min_dim] ==
678 ((candl_statement_usr_p)target->usr)->index[min_dim])
679 ++min_dim;
681 k = 1;
682 j = 1 + nb_output_dims;
683 for (i = 0; i < depth; i++, k++, j++) {
684 /* i = i' for all dimension less than depth. */
685 osl_int_set_si(precision, &system->m[constraint][k], -1);
686 osl_int_set_si(precision, &system->m[constraint][j], 1);
687 if (i == depth - 1) {
688 /* i <= i' at dimension depth if source is textually before target. */
689 osl_int_set_si(precision, &system->m[constraint][0], 1);
690 /* If source is textually after target, this is obviously i < i'. */
691 if (before || depth < min_dim) // sub 1 for the Arr dim
692 osl_int_set_si(precision, &system->m[constraint][nb_columns - 1], -1);
695 constraint++;
698 system->nb_output_dims = nb_output_dims;
699 system->nb_input_dims = nb_input_dims;
700 system->nb_parameters = nb_par;
701 system->nb_local_dims = nb_local_dims;
702 system->type = OSL_UNDEFINED;
704 dependence->domain = system;
706 return dependence;
711 * candl_dependence_system function :
712 * this function builds a node of the dependence graph: it studies a dependence
713 * between a given statement couple, reference couple, type and depth. If a
714 * data dependence actually exists, it returns a dependence structure, it
715 * returns NULL otherwise.
716 * - source is the source statement,
717 * - target is the target statement,
718 * - context is the program context (contraints on global parameters),
719 * - array_s is the array list for the source,
720 * - array_t is the array list for the target,
721 * - ref_s is the position of the source reference in array_s,
722 * - ref_s is the position of the target reference in array_t,
723 * - depth is the dependence depth,
724 * - type is the dependence type (RAW, WAW, WAR or RAR).
726 * - 18/09/2003: first version.
727 * - 09/12/2005: few corrections and polishing.
729 osl_dependence_p candl_dependence_system(osl_statement_p source,
730 osl_statement_p target,
731 osl_relation_p context,
732 osl_relation_p array_s,
733 osl_relation_p array_t,
734 int ref_s, int ref_t,
735 int type, int depth) {
736 candl_statement_usr_p s_usr = source->usr;
737 candl_statement_usr_p t_usr = target->usr;
738 osl_dependence_p dependence = NULL;
740 /* First, a trivial case: for two different statements at depth 0, there is
741 * a dependence only if the source is textually before the target.
743 if ((source != target) && (depth == 0) &&
744 (s_usr->label > t_usr->label))
745 return NULL;
747 /* We build the system of constraints. */
748 dependence = candl_dependence_build_system(source, target,
749 array_s, array_t,
750 depth,
751 (s_usr->label >=
752 t_usr->label));
754 /* We start by simple SIV/ZIV/GCD tests. */
755 if (!candl_dependence_gcd_test(source, target, dependence->domain, depth)) {
756 osl_dependence_free(dependence);
757 return NULL;
760 if (pip_has_rational_point(dependence->domain, context, 1)) {
761 /* We set the various fields with corresponding values. */
762 dependence->ref_source = ref_s;
763 dependence->ref_target = ref_t;
764 dependence->label_source = ((candl_statement_usr_p)source->usr)->label;
765 dependence->label_target = ((candl_statement_usr_p)target->usr)->label;
766 dependence->type = type;
767 dependence->depth = depth;
768 dependence->stmt_source_ptr = source;
769 dependence->stmt_target_ptr = target;
770 dependence->ref_source_access_ptr = array_s;
771 dependence->ref_target_access_ptr = array_t;
772 } else {
773 osl_dependence_free(dependence);
774 dependence = NULL;
777 return dependence;
782 * candl_dependence_between function :
783 * this function builds the dependence list from the statement "source" to
784 * statement "target": it will study the dependence for each reference and for
785 * each depth, under a particular context (context) and according to some
786 * user options.
787 * - 18/09/2003: first version.
788 * - 07/12/2005: (debug) correction of depth bounds.
789 * - 09/12/2005: We may take commutativity into consideration.
791 osl_dependence_p candl_dependence_between(osl_statement_p source,
792 osl_statement_p target,
793 osl_relation_p context,
794 candl_options_p options) {
795 osl_dependence_p new;
796 osl_dependence_p dependence = NULL;
797 osl_dependence_p now;
798 osl_relation_list_p access_src, access_targ;
799 osl_relation_p elt_src, elt_targ;
800 candl_statement_usr_p s_usr = source->usr;
801 candl_statement_usr_p t_usr = target->usr;
802 int i, min_depth, max_depth;
803 int precision = source->scattering->precision;
804 int row_src, row_targ;
805 int ref_s, ref_t;
807 /* If the statements commute and the user asks to use this information to
808 * simplify the dependence graph, we return no dependences.
810 if (options->commute && candl_util_statement_commute(source, target))
811 return NULL;
813 /* In the case of a self-dependence, the dependence depth can be as low as 1
814 * (not 0 because at depth 0 there is no loop, thus there is only one
815 * instance of the statement !) and as high as the statement depth.
816 * In the case of different statements, the dependence depth can be as low
817 * as 0 and as high as the number of shared loops.
819 if (source == target) {
820 min_depth = 1;
821 max_depth = s_usr->depth;
822 } else {
823 /* Depth 0 is for statements that don't share any loop. */
824 if (s_usr->depth > 0 && t_usr->depth > 0)
825 min_depth = (s_usr->index[0] == t_usr->index[0]) ? 1 : 0;
826 else
827 min_depth = 0;
829 max_depth = 0;
830 while ((max_depth < s_usr->depth) &&
831 (max_depth < t_usr->depth) &&
832 (s_usr->index[max_depth] == t_usr->index[max_depth]))
833 max_depth++;
836 ref_s = 0;
837 access_src = source->access;
839 for (; access_src != NULL; access_src = access_src->next, ref_s++) {
840 elt_src = access_src->elt;
841 row_src = candl_relation_get_line(elt_src, 0);
843 switch(elt_src->type) {
845 /* Anti and input-dependences analysis. */
846 case OSL_TYPE_READ: /* source READ */
847 if (!options->war && !options->rar)
848 break;
849 access_targ = target->access;
850 ref_t = 0;
851 for (; access_targ != NULL; access_targ = access_targ->next, ref_t++) {
852 elt_targ = access_targ->elt;
853 row_targ = candl_relation_get_line(elt_targ, 0);
855 /* Anti-dependences analysis. */
856 if (elt_targ->type != OSL_TYPE_READ) { /* target WRITE | MAY_WRITE */
857 if (options->war &&
858 osl_int_eq(precision,
859 elt_src->m[row_src][elt_src->nb_columns - 1],
860 elt_targ->m[row_targ][elt_targ->nb_columns - 1])) {
861 for (i = min_depth; i <= max_depth; i++) {
862 new = candl_dependence_system(source, target, context,
863 elt_src, elt_targ,
864 ref_s, ref_t,
865 OSL_DEPENDENCE_WAR, i);
866 osl_dependence_add(&dependence, &now, new);
870 /* Input-dependences analysis. */
871 else { /* target READ */
872 if (options->rar &&
873 osl_int_eq(precision,
874 elt_src->m[row_src][elt_src->nb_columns - 1],
875 elt_targ->m[row_targ][elt_targ->nb_columns - 1])) {
876 for (i = min_depth; i <= max_depth; i++) {
877 new = candl_dependence_system(source, target, context,
878 elt_src, elt_targ,
879 ref_s, ref_t,
880 OSL_DEPENDENCE_RAR, i);
881 osl_dependence_add(&dependence, &now, new);
886 break;
888 default: /* source WRITE | MAY-WRITE */
889 if (!options->raw && !options->waw)
890 break;
891 access_targ = target->access;
892 ref_t = 0;
893 for (; access_targ != NULL; access_targ = access_targ->next, ref_t++) {
894 elt_targ = access_targ->elt;
895 row_targ = candl_relation_get_line(elt_targ, 0);
897 /* Anti-dependences analysis. */
898 if (elt_targ->type != OSL_TYPE_READ) { /* target WRITE | MAY_WRITE */
899 if (options->waw &&
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_WAW, i);
908 osl_dependence_add(&dependence, &now, new);
912 /* Input-dependences analysis. */
913 else { /* target READ */
914 if (options->raw &&
915 osl_int_eq(precision,
916 elt_src->m[row_src][elt_src->nb_columns - 1],
917 elt_targ->m[row_targ][elt_targ->nb_columns - 1])) {
918 for (i = min_depth; i <= max_depth; i++) {
919 new = candl_dependence_system(source, target, context,
920 elt_src, elt_targ,
921 ref_s, ref_t,
922 OSL_DEPENDENCE_RAW, i);
923 osl_dependence_add(&dependence, &now, new);
928 break;
932 return dependence;
937 * candl_dependence function:
938 * this function builds the dependence graph of a scop
939 * according to some user options (options).
940 * - 18/09/2003: first version.
942 osl_dependence_p candl_dependence(osl_scop_p scop, candl_options_p options) {
943 osl_dependence_p dependence = NULL;
944 osl_dependence_p new = NULL;
945 osl_dependence_p now;
946 osl_statement_p stmt_i, stmt_j;
947 osl_relation_p context = scop->context;
949 if (options->scalar_privatization || options->scalar_expansion)
950 candl_dependence_analyze_scalars(scop, options);
952 stmt_i = scop->statement;
953 for (; stmt_i != NULL; stmt_i = stmt_i->next) {
954 /* We add self dependence. */
955 /* S->S */
956 new = candl_dependence_between(stmt_i, stmt_i, context, options);
957 osl_dependence_add(&dependence, &now, new);
959 stmt_j = stmt_i->next;
960 for (; stmt_j != NULL; stmt_j = stmt_j ->next) {
961 /* And dependences with other statements. */
962 /* S1->S2 */
963 new = candl_dependence_between(stmt_i, stmt_j, context, options);
964 osl_dependence_add(&dependence, &now, new);
966 /* S2->S1 */
967 new = candl_dependence_between(stmt_j, stmt_i, context, options);
968 osl_dependence_add(&dependence, &now, new);
972 /* If scalar analysis is called, remove some useless dependences. */
973 /* LNP: This is subsubmed by the updated prune-with-privatization function. */
974 /* if (options->scalar_privatization || options->scalar_expansion || */
975 /* options->scalar_renaming) */
976 /* candl_dependence_prune_scalar_waw(scop, options, &dependence); */
978 /* Final treatment for scalar analysis. */
979 int check = 0;
980 if (options->scalar_renaming)
981 check = candl_dependence_scalar_renaming(scop, options, &dependence);
983 if (! check && options->scalar_privatization)
984 candl_dependence_prune_with_privatization(scop, options, &dependence);
986 /* Compute the last writer */
987 if (options->lastwriter)
988 candl_compute_last_writer(dependence, scop);
990 #if defined(CANDL_COMPILE_PRUNNING_C)
991 /* Remove some transitively covered dependences (experimental). */
992 if (options->prune_dups)
993 dependence = candl_dependence_prune_transitively_covered(dependence);
994 #endif
996 return dependence;
1000 /******************************************************************************
1001 * Scalar analysis functions *
1002 ******************************************************************************/
1005 * candl_dependence_var_is_scalar function:
1006 * This function returns true if the variable indexed by 'var_index'
1007 * is a scalar in the whole scop.
1009 int candl_dependence_var_is_scalar(osl_scop_p scop, int var_index) {
1010 osl_statement_p statement;
1011 osl_relation_list_p access;
1012 osl_relation_p elt;
1013 int precision = scop->context->precision;
1014 int i;
1015 int row;
1017 statement = scop->statement;
1018 while (statement != NULL) {
1019 access = statement->access;
1020 while (access != NULL) {
1021 elt = access->elt;
1022 row = candl_relation_get_line(elt, 0);
1023 if (osl_int_get_si(precision, elt->m[row][elt->nb_columns - 1]) ==
1024 var_index) {
1025 /* Ensure it is not an array. */
1026 if (elt->nb_output_dims > 1)
1027 return 0;
1028 /* Ensure the access function is '0'. */
1029 if (!osl_int_zero(precision, elt->m[row][0]))
1030 return 0;
1031 for (i = 2; i < elt->nb_columns-2; ++i) /* jmp the 'Arr' */
1032 if (!osl_int_zero(precision, elt->m[row][i]))
1033 return 0;
1035 access = access->next;
1037 statement = statement->next;
1040 return 1;
1045 * candl_dependence_expand_scalar function:
1046 * Expand the variable of index 'scalar_idx' by adding one
1047 * dimension (x becomes x[0]) to each access matrix refering this
1048 * variable in the statement list.
1051 static void candl_dependence_expand_scalar(osl_statement_p* sl,
1052 int scalar_idx) {
1053 osl_relation_list_p access;
1054 osl_relation_p elt;
1055 int tmp;
1056 int row;
1057 int precision = sl[0]->scattering->precision;
1058 int i;
1060 /* Iterate on all statements of the list. */
1061 for (i = 0; sl[i] != NULL; ++i) {
1063 /* Check if the scalar is referenced in the 'read' access
1064 function. */
1065 access = sl[i]->access;
1066 for (; access != NULL ; access = access->next) {
1067 elt = access->elt;
1068 row = candl_relation_get_line(elt, 0);
1069 tmp = osl_int_get_si(precision, elt->m[row][elt->nb_columns - 1]);
1070 if (tmp == scalar_idx) {
1071 row = elt->nb_rows;
1072 osl_relation_insert_blank_row(elt, row);
1073 osl_relation_insert_blank_column(elt, 1 + elt->nb_output_dims);
1074 osl_int_set_si(precision, &elt->m[row][1 + elt->nb_output_dims], -1);
1075 elt->nb_output_dims++;
1083 * candl_dependence_refvar_chain function:
1084 * This function returns a chain of statements as a feshly allocated
1085 * array of pointer on statements, of all statements reading or
1086 * writing the variable 'var_index', surrounded by the 'level' common
1087 * loops of 'dom'.
1088 * Output is a NULL-terminated array. We don't create a chained list,
1089 * because it demands to clone every statements each time, and we need
1090 * to clone the field usr too.
1092 osl_statement_p* candl_dependence_refvar_chain(osl_scop_p scop,
1093 osl_statement_p dom, int var_index, int level) {
1094 /* No or empty scop -> no chain! */
1095 if (scop == NULL || scop->statement == NULL)
1096 return NULL;
1098 osl_statement_p* res; /* not a chained list, but an array of statement */
1099 osl_statement_p statement;
1100 osl_relation_p scattering, scattering_dom;
1101 candl_statement_usr_p dom_usr;
1102 candl_statement_usr_p stmt_usr;
1103 int i;
1104 int buffer_size = 64;
1105 int count = 0;
1107 /* If no dominator is provided, assume we start with the first statement. */
1108 if (dom == NULL)
1109 dom = scop->statement;
1111 dom_usr = dom->usr;
1113 statement = scop->statement;
1114 while (statement != NULL && statement != dom)
1115 statement = statement->next;
1117 /* The dominator is not in the list of statements. */
1118 if (statement == NULL)
1119 return NULL;
1121 CANDL_malloc(res, osl_statement_p*, sizeof(osl_statement_p) * buffer_size);
1122 scattering_dom = dom->scattering;
1124 for (; statement != NULL; statement = statement->next) {
1125 stmt_usr = statement->usr;
1127 /* We look for exactly 'level' common loops. */
1128 if (stmt_usr->depth < level)
1129 continue;
1131 /* Ensure it has 'level' common loop(s) with the dominator. */
1132 scattering = statement->scattering;
1133 for (i = 0; i < level &&
1134 stmt_usr->index[i] == dom_usr->index[i];
1135 ++i)
1138 if (i < level)
1139 continue;
1141 /* Ensure the variable is referenced. */
1142 if (candl_dependence_var_is_ref(statement, var_index) != CANDL_VAR_UNDEF) {
1143 if (count == buffer_size) {
1144 buffer_size *= 2;
1145 CANDL_realloc(res, osl_statement_p*,
1146 sizeof(osl_statement_p) * buffer_size);
1148 res[count++] = statement;
1152 CANDL_realloc(res, osl_statement_p*,
1153 sizeof(osl_statement_p) * (count+1));
1154 res[count] = NULL;
1156 return res;
1161 * candl_dependence_var_is_ref function:
1162 * This function checks if a var 'var_index' is referenced (DEF or
1163 * USE) by the statement.
1165 int candl_dependence_var_is_ref(osl_statement_p s, int var_index) {
1166 osl_relation_list_p access;
1167 osl_relation_p elt;
1168 int row;
1169 int ret = CANDL_VAR_UNDEF;
1171 if (s) {
1172 /* read access */
1173 access = s->access;
1174 while (access != NULL) {
1175 elt = access->elt;
1176 if (elt->type == OSL_TYPE_READ) {
1177 row = candl_relation_get_line(elt, 0);
1178 if (osl_int_get_si(elt->precision, elt->m[row][elt->nb_columns - 1]) ==
1179 var_index) {
1180 ret = CANDL_VAR_IS_USED;
1181 break;
1184 access = access->next;
1187 /* right access */
1188 access = s->access;
1189 while (access != NULL) {
1190 elt = access->elt;
1191 if (elt->type != OSL_TYPE_READ) {
1192 row = candl_relation_get_line(elt, 0);
1193 if (osl_int_get_si(elt->precision, elt->m[row][elt->nb_columns - 1]) ==
1194 var_index) {
1195 if (ret == CANDL_VAR_IS_USED)
1196 ret = CANDL_VAR_IS_DEF_USED;
1197 else
1198 ret = CANDL_VAR_IS_DEF;
1199 break;
1202 access = access->next;
1206 return ret;
1211 * candl_dependence_compute_lb function:
1212 * This function assigns to the Entier 'lb' the lexmin of variable
1213 * 'col'-1 in the polyhedron 'm'.
1215 static void candl_dependence_compute_lb(osl_relation_p m, Entier* lb, int col) {
1216 PipOptions* options;
1217 PipQuast* solution;
1218 PipList* l;
1219 options = pip_options_init();
1220 options->Simplify = 1;
1221 options->Urs_parms = -1;
1222 options->Urs_unknowns = -1;
1223 /* Compute lexmin. */
1224 solution = pip_solve_osl(m, NULL, -1, options);
1226 if ((solution != NULL) &&
1227 ((solution->list != NULL) || (solution->condition != NULL))) {
1228 l = solution->list;
1229 while (col-- > 1)
1230 l = l->next;
1231 CANDL_assign(*lb, l->vector->the_vector[0]);
1233 pip_options_free(options);
1234 pip_quast_free(solution);
1239 * candl_dependence_check_domain_is_included function:
1240 * This function checks if the 'level'-first iterators of 2 domains
1241 * are in such a way that s1 is larger or equal to s2, for the
1242 * considered iterator dimensions.
1245 int candl_dependence_check_domain_is_included(osl_statement_p s1,
1246 osl_statement_p s2,
1247 osl_relation_p context,
1248 int level) {
1249 candl_statement_usr_p s1_usr = s1->usr;
1250 candl_statement_usr_p s2_usr = s2->usr;
1251 osl_relation_p matrix;
1252 int max = level;
1253 int i, j;
1254 int precision = s2->domain->precision;
1255 Entier lb;
1256 osl_int_t osl_lb;
1258 CANDL_init(lb);
1259 osl_int_init(precision, &osl_lb);
1261 if (s1_usr->depth < max) max = s1_usr->depth;
1262 if (s2_usr->depth < max) max = s2_usr->depth;
1264 matrix = osl_relation_pmalloc(precision,
1265 s2->domain->nb_rows + s2_usr->depth - max + 1,
1266 s2->domain->nb_columns);
1268 /* Duplicate s2 to the dest matrix. */
1269 for (i = 0; i < s2->domain->nb_rows; ++i) {
1270 for (j = 0; j < s2->domain->nb_columns; ++j)
1271 osl_int_assign(precision,
1272 &matrix->m[i][j], s2->domain->m[i][j]);
1275 /* Make useless dimensions equal to 1. */
1276 for (j = 0; j < s2_usr->depth - max; ++j) {
1277 candl_dependence_compute_lb(s2->domain, &lb, j + 1 + max);
1278 #ifdef LINEAR_VALUE_IS_INT
1279 osl_lb.sp = lb;
1280 #elif defined(LINEAR_VALUE_IS_LONGLONG)
1281 osl_lb.dp = lb;
1282 #elif defined(LINEAR_VALUE_IS_MP)
1283 mpz_set(*((mpz_t*)osl_lb.mp), lb);
1284 #endif
1285 osl_int_assign(precision,
1286 &matrix->m[i][matrix->nb_columns - 1], osl_lb);
1287 osl_int_set_si(precision,
1288 &matrix->m[i++][j+1+max], -1);
1291 /* Iterate on all constraints of s1, and check them. */
1292 for (i = 0; i < s1->domain->nb_rows; ++i) {
1293 /* Skip constraints defining other iterators. */
1294 for (j = max + 1; j <= s1_usr->depth; ++j) {
1295 if (!osl_int_zero(precision, s1->domain->m[i][j]))
1296 break;
1298 if (j <= s1_usr->depth)
1299 continue;
1300 /* Invert the constraint, and add it to matrix. */
1301 for (j = 0; j <= max; ++j) {
1302 osl_int_assign(precision,
1303 &matrix->m[matrix->nb_rows - 1][j],
1304 s1->domain->m[i][j]);
1305 osl_int_oppose(precision,
1306 &matrix->m[matrix->nb_rows - 1][j],
1307 matrix->m[matrix->nb_rows - 1][j]);
1309 for (j = s1_usr->depth + 1; j < s1->domain->nb_columns; ++j) {
1310 osl_int_assign(precision,
1311 &matrix->m[matrix->nb_rows - 1][j - s1_usr->depth + s2_usr->depth],
1312 s1->domain->m[i][j]);
1313 osl_int_oppose(precision,
1314 &matrix->m[matrix->nb_rows - 1][j - s1_usr->depth + s2_usr->depth],
1315 matrix->m[matrix->nb_rows - 1][j - s1_usr->depth + s2_usr->depth]);
1317 /* Make the inequality strict. */
1318 osl_int_decrement(precision,
1319 &matrix->m[matrix->nb_rows - 1][matrix->nb_columns - 1],
1320 matrix->m[matrix->nb_rows - 1][matrix->nb_columns - 1]);
1322 if (candl_matrix_check_point(matrix, context)) {
1323 /* There is a point. dom(s1) - dom(s2) > 0. */
1324 CANDL_clear(lb);
1325 osl_int_clear(precision, &osl_lb);
1326 osl_relation_free(matrix);
1327 return 0;
1331 CANDL_clear(lb);
1332 osl_int_clear(precision, &osl_lb);
1333 osl_relation_free(matrix);
1335 return 1;
1340 * candl_dependence_extract_scalar_variables function:
1341 * This functions returns a -1-terminated array of the scop scalar
1342 * variables.
1344 int* candl_dependence_extract_scalar_variables(osl_scop_p scop) {
1345 osl_statement_p statement;
1346 osl_relation_p elt;
1347 osl_relation_list_p access;
1348 int scalars[1024]; /* FIXME: implement a real buffer. */
1349 int checked[1024];
1350 int i, idx;
1351 int row;
1352 int count_s = 0, count_c = 0;
1354 /* Detect all scalar variables. */
1355 statement = scop->statement;
1356 while (statement != NULL) {
1357 access = statement->access;
1358 while (access != NULL) {
1359 elt = access->elt;
1360 row = candl_relation_get_line(elt, 0);
1361 idx = osl_int_get_si(elt->precision,
1362 elt->m[row][elt->nb_columns - 1]);
1364 for (i = 0; i < count_s && scalars[i] != idx; ++i)
1366 if (i == count_s) {
1367 for (i = 0; i < count_c && checked[i] != idx; ++i)
1369 if (i == count_c) {
1370 if (candl_dependence_var_is_scalar(scop, idx))
1371 scalars[count_s++] = idx;
1372 else
1373 checked[count_c++] = idx;
1375 if (count_s == 1024 || count_c == 1024)
1376 CANDL_error("Error: Buffer size too small");
1378 access = access->next;
1380 statement = statement->next;
1383 /* Rearrange the array to the exact size. */
1384 int *res;
1385 CANDL_malloc(res, int*, (count_s + 1) * sizeof(int));
1386 for (i = 0; i < count_s; ++i)
1387 res[i] = scalars[i];
1388 res[i] = -1;
1390 return res;
1395 * osl_dependence_prune_scalar_waw function:
1396 * This function removes all WAW dependences between the same scalar
1397 * (they are useless dependences).
1399 void osl_dependence_prune_scalar_waw(osl_scop_p scop,
1400 candl_options_p options,
1401 osl_dependence_p* deps) {
1402 int* scalars;
1403 int i;
1404 int refs, reft;
1405 osl_dependence_p tmp;
1406 osl_dependence_p next;
1407 osl_dependence_p pred = NULL;
1409 if (options->verbose)
1410 fprintf (stderr, "[Candl] Scalar Analysis: Remove all WAW between the same"
1411 " scalar\n");
1413 scalars = candl_dependence_extract_scalar_variables(scop);
1415 for (tmp = *deps; tmp; ) {
1416 candl_dependence_get_array_refs_in_dep(tmp, &refs, &reft);
1417 if (refs == reft && tmp->type == OSL_DEPENDENCE_WAW) {
1418 for (i = 0; scalars[i] != -1 && scalars[i] != refs; ++i)
1420 if (scalars[i] != -1) {
1421 osl_relation_free(tmp->domain);
1422 next = tmp->next;
1423 if (pred == NULL)
1424 *deps = next;
1425 else
1426 pred->next = next;
1427 free(tmp);
1428 tmp = next;
1429 continue;
1432 pred = tmp;
1433 tmp = tmp->next;
1436 free(scalars);
1441 * candl_dependence_scalar_renaming function:
1442 * This function renames scalars in the program. In case scalars have
1443 * been renamed, the dependence analysis is re-run.
1445 int candl_dependence_scalar_renaming(osl_scop_p scop,
1446 candl_options_p options,
1447 osl_dependence_p* deps) {
1448 osl_statement_p *statement; /* not a chained list */
1449 osl_statement_p iter;
1450 osl_statement_p defs[1024];
1451 osl_statement_p uses[1024];
1452 osl_statement_p last_def;
1453 osl_statement_p *current; /* not a chained list */
1454 osl_relation_p elt;
1455 osl_relation_list_p access;
1456 candl_statement_usr_p usr;
1457 candl_statement_usr_p last_usr;
1458 int i, j, k;
1459 int nb_statements = 0;
1460 int *parts;
1461 int defs_c, uses_c;
1462 int *scalars;
1463 int precision = scop->context->precision;
1464 int row;
1465 int tmp, has_changed = 0;
1466 int newvar = 0;
1468 if (options->verbose)
1469 fprintf (stderr, "[Candl] Scalar Analysis: Perform scalar renaming\n");
1471 /* Compute the first free variable index seed. */
1472 for (iter = scop->statement; iter != NULL; iter = iter->next) {
1473 access = iter->access;
1474 for (; access != NULL; access = access->next) {
1475 elt = access->elt;
1476 row = candl_relation_get_line(elt, 0);
1477 tmp = osl_int_get_si(precision, elt->m[row][elt->nb_columns - 1]);
1478 if (tmp >= newvar)
1479 newvar = tmp + 1;
1481 nb_statements++;
1484 /* Init */
1485 CANDL_malloc(current, osl_statement_p*, sizeof(osl_statement_p) * nb_statements);
1486 CANDL_malloc(parts, int*, sizeof(int) * nb_statements);
1488 /* Get the list of scalars. */
1489 scalars = candl_dependence_extract_scalar_variables(scop);
1491 /* Iterate on all scalars. */
1492 for (i = 0; scalars[i] != -1; ++i) {
1493 /* Get all statements referencing the scalar. */
1494 statement = candl_dependence_refvar_chain(scop, NULL, scalars[i], 0);
1496 /* If the chain starts by a USE, we can't do anything. */
1497 if (statement[0] == NULL ||
1498 candl_dependence_var_is_ref(statement[0], scalars[i])
1499 != CANDL_VAR_IS_DEF) {
1500 free(statement);
1501 continue;
1504 /* Get all defs and all uses. */
1505 defs_c = 0;
1506 uses_c = 0;
1507 for (j = 0; statement[j]; ++j) {
1508 tmp = candl_dependence_var_is_ref(statement[j], scalars[i]);
1509 switch (tmp) {
1510 case CANDL_VAR_IS_USED:
1511 case CANDL_VAR_IS_DEF_USED:
1512 uses[uses_c++] = statement[j];
1513 break;
1514 case CANDL_VAR_IS_DEF:
1515 defs[defs_c++] = statement[j];
1516 break;
1520 /* Clean buffer. */
1521 j = 0;
1522 for (iter = scop->statement; iter != NULL; iter = iter->next)
1523 current[j++] = NULL;
1525 free(statement);
1527 /* Iterate on all DEFs. */
1528 last_def = NULL;
1529 for (j = 0; j < defs_c; ++j) {
1530 if (last_def == NULL) {
1531 last_def = defs[j];
1532 } else {
1533 /* Ensure the current DEF covers all iterations covered
1534 by the last checked one. */
1535 last_usr = last_def->usr;
1536 usr = defs[j]->usr;
1537 for (k = 0; k < last_usr->depth && k < usr->depth &&
1538 last_usr->index[k] == usr->index[k];
1539 ++k)
1541 /* We only need to check when there are common loops. */
1542 if (k && ! candl_dependence_check_domain_is_included
1543 (last_def, defs[j], scop->context, k + 1)) {
1544 usr = defs[j]->usr;
1545 current[usr->label] = last_def;
1546 continue;
1547 } else {
1548 last_def = defs[j];
1551 /* Create DEF-USE table. */
1552 for (k = 0; k < uses_c; ++k) {
1553 usr = uses[k]->usr;
1554 if (usr->label > ((candl_statement_usr_p)defs[j]->usr)->label)
1555 current[usr->label] = defs[j];
1559 /* Initialize partition table. */
1560 for (j = 0; j < nb_statements; ++j)
1561 parts[j] = -1;
1563 /* Create partitions. */
1564 for (j = 0; j < defs_c; ++j) {
1565 usr = defs[j]->usr;
1566 for (k = 0; k < nb_statements; ++k)
1567 if ((current[k] && current[k] == defs[j]) ||
1568 (k == usr->label && current[usr->label] == NULL))
1569 parts[k] = j;
1572 /* Check if it is needed to rename the scalar. */
1573 tmp = -1;
1574 for (j = 0; j < nb_statements; ++j)
1575 if (tmp == -1) {
1576 if (parts[j] != -1)
1577 tmp = parts[j];
1578 } else {
1579 if (parts[j] != -1 && tmp != parts[j])
1580 break;
1583 /* Rename scalar variable. */
1584 if (j != nb_statements) {
1585 tmp = -1;
1586 j = 0;
1587 for (iter = scop->statement ; iter != NULL ; iter = iter->next) {
1588 if (parts[j] != -1) {
1589 if (tmp == -1)
1590 tmp = parts[j];
1591 else if (tmp != parts[j])
1592 has_changed = 1;
1594 access = iter->access;
1595 for (; access != NULL; access = access->next) {
1596 elt = access->elt;
1597 row = candl_relation_get_line(elt, 0);
1598 tmp = osl_int_get_si(precision, elt->m[row][elt->nb_columns - 1]);
1599 if (tmp == scalars[i]) {
1600 if (options->verbose)
1601 fprintf (stderr, "[Candl] Scalar analysis: Renamed "
1602 "variable %d to %d at statement S%d\n",
1603 scalars[i], newvar + parts[j], j);
1604 osl_int_set_si(precision,
1605 &elt->m[row][elt->nb_columns - 1],
1606 newvar + parts[j]);
1610 j++;
1613 } /* end Iterate on all scalars */
1615 /* Redo the full dependence analysis, if needed. */
1616 if (has_changed) {
1617 int bopt = options->scalar_renaming;
1618 options->scalar_renaming = 0;
1619 if (options->scalar_privatization)
1620 free(((candl_scop_usr_p)scop->usr)->scalars_privatizable);
1621 osl_dependence_free(*deps);
1622 *deps = candl_dependence(scop, options);
1623 options->scalar_renaming = bopt;
1626 free(scalars);
1627 free(current);
1628 free(parts);
1630 return has_changed;
1635 * candl_dependence_is_loop_carried function:
1636 * This function returns true if the dependence 'dep' is loop-carried
1637 * for loop 'loop_index', false otherwise.
1639 int candl_dependence_is_loop_carried(osl_scop_p scop,
1640 osl_dependence_p dep,
1641 int loop_index) {
1642 osl_relation_p msrc = NULL, mtarg = NULL;
1643 candl_statement_usr_p s_usr = dep->stmt_source_ptr->usr;
1644 candl_statement_usr_p t_usr = dep->stmt_target_ptr->usr;
1645 int i, j;
1646 int k, kp, l;
1647 int row_k, row_kp;
1648 int precision = scop->context->precision;
1650 /* Ensure source and sink share common loop 'loop_index', and that
1651 dependence depth is consistent with the considered loop. */
1652 for (i = 0; i < s_usr->depth; ++i)
1653 if (s_usr->index[i] == loop_index)
1654 break;
1655 if (i != dep->depth - 1 || i >= t_usr->depth)
1656 return 0;
1657 for (j = 0; j < t_usr->depth; ++j)
1658 if (t_usr->index[j] == loop_index)
1659 break;
1660 if (j != i)
1661 return 0;
1663 msrc = candl_dependence_get_relation_ref_source_in_dep(dep);
1664 mtarg = candl_dependence_get_relation_ref_target_in_dep(dep);
1666 /* plus one for the Arr output dim */
1667 int src_ref_iter = (candl_relation_get_line(msrc, i+1) != -1);
1668 int dst_ref_iter = (candl_relation_get_line(mtarg,j+1) != -1);
1670 /* Ensure it is not a basic loop-independent dependence (pure
1671 equality of the access functions for the surrounding iterators +
1672 parameters + constant, no occurence of the inner loop iterators,
1673 and contain the current loop iterator. */
1674 int must_test = 0;
1675 k = 1; // start after the Arr column
1676 row_k = candl_relation_get_line(msrc, k);
1677 while (!must_test &&
1678 k < msrc->nb_output_dims &&
1679 osl_int_zero(precision, msrc->m[row_k][0])) {
1681 // Ensure the reference do reference the current loop iterator
1682 // to be tested.
1683 if (!osl_int_zero(precision, msrc->m[row_k][i])) {
1684 kp = 1;
1685 row_kp = candl_relation_get_line(mtarg, kp);
1687 while (!must_test &&
1688 kp < mtarg->nb_output_dims &&
1689 osl_int_zero(precision, mtarg->m[row_kp][0])) {
1691 if (!osl_int_zero(precision, mtarg->m[row_kp][j])) {
1692 // Ensure the access functions are equal for the
1693 // surrounding loop iterators, and no inner iterator
1694 // is referenced.
1695 if (!osl_int_eq(precision,
1696 msrc->m[row_k][0], mtarg->m[row_kp][0])) {
1697 must_test = 1;
1698 } else {
1699 for (l = 1; l <= i; ++l)
1700 if (!osl_int_eq(precision,
1701 msrc->m[row_k][msrc->nb_output_dims + l],
1702 mtarg->m[row_kp][mtarg->nb_output_dims + l])) {
1703 must_test = 1;
1704 break;
1707 int m = l;
1708 if (!must_test)
1709 for (; l <= s_usr->depth+1; ++l)
1710 if (!osl_int_zero(precision, msrc->m[row_k][msrc->nb_output_dims + l])) {
1711 must_test = 1;
1712 break;
1714 if (!must_test)
1715 for (; m <= t_usr->depth+1; ++m)
1716 if (!osl_int_zero(precision, mtarg->m[row_kp][mtarg->nb_output_dims + m])) {
1717 must_test = 1;
1718 break;
1720 if (!must_test)
1721 for (; l < msrc->nb_columns-1; ++l, ++m)
1722 if (!osl_int_eq(precision,
1723 msrc->m[row_k][msrc->nb_output_dims + l],
1724 mtarg->m[row_kp][mtarg->nb_output_dims + m])) {
1725 must_test = 1;
1726 break;
1729 ++kp;
1730 row_kp = candl_relation_get_line(mtarg, kp);
1733 ++k;
1734 row_k = candl_relation_get_line(msrc, k);
1737 if (src_ref_iter && dst_ref_iter && !must_test)
1738 return 0;
1740 /* Final check. For loop i, the dependence is loop carried if there exists
1741 x_i^R != x_i^S in the dependence polyhedron, with
1742 x_{1..i-1}^R = x_{1..i-1}^S
1744 int pos;
1745 osl_relation_p mat = dep->domain;
1747 osl_relation_p testsyst = osl_relation_pmalloc(precision,
1748 mat->nb_rows + 1 + s_usr->depth,
1749 mat->nb_columns);
1750 for (pos = 0; pos < mat->nb_rows; ++pos)
1751 for (j = 0; j < mat->nb_columns; ++j)
1752 osl_int_assign(precision,
1753 &testsyst->m[pos][j], mat->m[pos][j]);
1754 for (j = 0; j < i; ++j) {
1755 osl_int_set_si(precision, &testsyst->m[pos+j+1][0], 0);
1756 osl_int_set_si(precision, &testsyst->m[pos+j+1][1+j], -1);
1757 osl_int_set_si(precision, &testsyst->m[pos+j+1][1+j+mat->nb_output_dims], 1);
1760 int has_pt = 0;
1761 // Test for '>'.
1762 osl_int_set_si(precision, &testsyst->m[pos][0], 1);
1763 osl_int_set_si(precision, &testsyst->m[pos][testsyst->nb_columns-1], -1);
1764 osl_int_set_si(precision, &testsyst->m[pos][1+i], 1);
1765 osl_int_set_si(precision, &testsyst->m[pos][1+i+mat->nb_output_dims], -1);
1767 has_pt = pip_has_rational_point(testsyst, NULL, 1);
1768 if (!has_pt) {
1769 // Test for '<'.
1770 osl_int_set_si(precision, &testsyst->m[pos][1+i], -1);
1771 osl_int_set_si(precision, &testsyst->m[pos][1+i+mat->nb_output_dims], 1);
1772 has_pt = pip_has_rational_point(testsyst, NULL, 1);
1775 return has_pt;
1777 /* LNP: OLD VERSION */
1778 /* The above is more robust. */
1779 /* /\* Final check. The dependence exists only because the loop */
1780 /* iterates. Make the loop not iterate and check if there's still */
1781 /* dependent iterations. *\/ */
1782 /* CandlMatrix* m = candl_matrix_malloc(dep->domain->NbRows + 2, */
1783 /* dep->domain->NbColumns); */
1784 /* CANDL_set_si(m->p[m->NbRows - 2][i + 1], -1); */
1785 /* CANDL_set_si(m->p[m->NbRows - 1][dep->source->depth + 1 + j], -1); */
1786 /* /\* Copy the rest of the matrix. *\/ */
1787 /* int ii, jj; */
1788 /* for (ii = 0; ii < dep->domain->NbRows; ++ii) */
1789 /* for (jj = 0; jj < dep->domain->NbColumns; ++jj) */
1790 /* CANDL_assign(m->p[ii][jj], dep->domain->p[ii][jj]); */
1791 /* /\* Compute real lb of loops. *\/ */
1792 /* Entier lb; CANDL_init(lb); */
1793 /* candl_dependence_compute_lb (m, &lb, i + 1); */
1794 /* CANDL_assign(m->p[m->NbRows - 2][m->NbColumns - 1], lb); */
1795 /* candl_dependence_compute_lb (m, &lb, dep->source->depth + 1 + j); */
1796 /* CANDL_assign(m->p[m->NbRows - 1][m->NbColumns - 1], lb); */
1797 /* int ret = candl_matrix_check_point(m, program->context); */
1798 /* CANDL_clear(lb); */
1800 /* /\* Be clean. *\/ */
1801 /* candl_matrix_free(m); */
1803 /* return !ret; */
1808 * candl_dependence_prune_with_privatization function: This function
1809 * prunes the dependence graph 'deps' by removing loop-carried
1810 * dependences involving a scalar variable privatizable for that loop.
1812 void candl_dependence_prune_with_privatization(osl_scop_p scop,
1813 candl_options_p options,
1814 osl_dependence_p* deps) {
1815 osl_dependence_p next;
1816 osl_dependence_p tmp;
1817 osl_dependence_p pred = NULL;
1818 candl_statement_usr_p s_usr;
1819 candl_statement_usr_p t_usr;
1820 candl_scop_usr_p scop_usr = scop->usr;
1821 int is_priv;
1822 int i;
1823 int row;
1824 int loop_idx = 0;
1825 int refs, reft;
1826 int loop_pos_priv;
1827 int precision = scop->context->precision;
1829 if (options->verbose)
1830 fprintf (stderr, "[Candl] Scalar Analysis: Remove loop-carried dependences"
1831 " on privatizable scalars\n");
1833 if (scop->statement == NULL)
1834 return;
1836 /* Perform the scalar analysis, if not done before. */
1837 if (scop_usr->scalars_privatizable == NULL) {
1838 candl_options_p options = candl_options_malloc();
1839 options->scalar_privatization = 1;
1840 candl_dependence_analyze_scalars(scop, options);
1841 candl_options_free(options);
1844 for (tmp = *deps; tmp; ) {
1845 s_usr = tmp->stmt_source_ptr->usr;
1846 t_usr = tmp->stmt_target_ptr->usr;
1848 /* Check if the dependence is involving a privatizable scalar. */
1849 is_priv = 1;
1850 candl_dependence_get_array_refs_in_dep(tmp, &refs, &reft);
1851 for (i = 0; i < s_usr->depth; ++i) {
1852 if (candl_dependence_scalar_is_privatizable_at(scop, refs,
1853 s_usr->index[i]))
1854 break;
1856 if (i == s_usr->depth) {
1857 for (i = 0; i < t_usr->depth; ++i) {
1858 if (candl_dependence_scalar_is_privatizable_at
1859 (scop, reft, t_usr->index[i]))
1860 break;
1862 if (i == t_usr->depth)
1863 is_priv = 0;
1864 else
1865 loop_idx = t_usr->index[i];
1866 } else {
1867 loop_idx = s_usr->index[i];
1869 loop_pos_priv = i;
1871 /* Check if the dependence is loop-carried at loop i. */
1872 if (is_priv && candl_dependence_is_loop_carried(scop, tmp, loop_idx)) {
1873 /* If so, make the dependence loop-independent. */
1874 row = tmp->domain->nb_rows;
1875 osl_relation_insert_blank_row(tmp->domain, row);
1876 osl_int_set_si(precision,
1877 &tmp->domain->m[row][1 + loop_pos_priv],
1879 osl_int_set_si(precision,
1880 &tmp->domain->m[row][1 + loop_pos_priv + s_usr->depth],
1881 -1);
1883 /* Set the type of the dependence as special
1884 scalar-privatization one. */
1885 if (tmp->type == OSL_DEPENDENCE_RAW)
1886 tmp->type = OSL_DEPENDENCE_RAW_SCALPRIV;
1887 next = tmp->next;
1888 if (!candl_matrix_check_point(tmp->domain, NULL)) {
1889 /* It is, the dependence can be removed. */
1890 osl_relation_free(tmp->domain);
1891 if (pred == NULL)
1892 *deps = next;
1893 else
1894 pred->next = next;
1895 free(tmp);
1897 pred = tmp;
1898 tmp = next;
1900 continue;
1902 /* Go to the next victim. */
1903 pred = tmp;
1904 tmp = tmp->next;
1910 * candl_dependence_is_privatizable function:
1911 * This function checks if a given scalar 'var_index' is privatizable
1912 * for loop 'loop_index'.
1914 int candl_dependence_scalar_is_privatizable_at(osl_scop_p scop,
1915 int var_index,
1916 int loop_index) {
1917 candl_scop_usr_p scop_usr = scop->usr;
1918 int i;
1920 /* If the scalar analysis wasn't performed yet, do it. */
1921 if (scop_usr->scalars_privatizable == NULL) {
1922 candl_options_p options = candl_options_malloc();
1923 options->scalar_privatization = 1;
1924 candl_dependence_analyze_scalars(scop, options);
1925 candl_options_free(options);
1928 i = 0;
1929 while (scop_usr->scalars_privatizable[i] != -1)
1930 i++;
1932 /* Check in the array of privatizable scalar variables for the tuple
1933 (var,loop). */
1934 for (i = 0; scop_usr->scalars_privatizable[i] != -1; i += 2)
1935 if (scop_usr->scalars_privatizable[i] == var_index &&
1936 scop_usr->scalars_privatizable[i + 1] == loop_index)
1937 return 1;
1939 return 0;
1944 * candl_dependence_analyze_scalars function:
1945 * This function checks, for all scalar variables of the scop, and
1946 * all loop levels, if the scalar can be privatized at that level.
1948 int candl_dependence_analyze_scalars(osl_scop_p scop,
1949 candl_options_p options) {
1950 int* scalars;
1951 osl_statement_p* statement; /* not a chained list, but an array of */
1952 osl_statement_p* fullchain; /* statement to not realloc the usr field */
1953 osl_statement_p s;
1954 osl_statement_p curlast;
1955 osl_statement_p last;
1956 osl_statement_p iter; /* used to iterate on the scop */
1957 osl_relation_list_p access;
1958 osl_relation_p elt;
1959 candl_scop_usr_p scop_usr = scop->usr;
1960 candl_statement_usr_p stmt_usr;
1961 int i, j, k;
1962 int max, is_priv, offset, was_priv;
1963 int nb_priv = 0;
1964 int priv_buff_size = 64;
1965 int row;
1967 /* Initialize the list of privatizable scalars to empty. */
1968 if (options->scalar_privatization) {
1969 CANDL_malloc(scop_usr->scalars_privatizable, int*, 2 * sizeof(int));
1970 scop_usr->scalars_privatizable[0] = -1;
1971 scop_usr->scalars_privatizable[1] = -1;
1974 /* Retrieve all scalar variables. */
1975 scalars = candl_dependence_extract_scalar_variables(scop);
1977 /* For each of those, detect (at any level) if it can be privatized
1978 / expanded / renamed. */
1979 for (i = 0; scalars[i] != -1; ++i) {
1980 /* Go to the first statement referencing the scalar in the scop. */
1981 for (iter = scop->statement; iter != NULL; iter = iter->next) {
1982 if (candl_dependence_var_is_ref(iter, scalars[i])
1983 != CANDL_VAR_UNDEF)
1984 break;
1987 /* A weird error occured. */
1988 if (iter == NULL)
1989 continue;
1991 /* Take all statements referencing the scalar. */
1992 fullchain = candl_dependence_refvar_chain(scop, iter, scalars[i], 0);
1994 /* Compute the maximum loop depth of the chain. */
1995 max = 0;
1996 for (k = 0; fullchain[k]; ++k) {
1997 stmt_usr = fullchain[k]->usr;
1998 if (max < stmt_usr->depth)
1999 max = stmt_usr->depth;
2001 last = fullchain[k-1];
2003 /* Initialize the offset for expansion. */
2004 offset = 0;
2005 was_priv = 0;
2007 /* Iterate on all possible depth for analysis. */
2008 for (j = 1; j <= max; ++j) {
2009 s = fullchain[0];
2011 if (was_priv) {
2012 ++offset;
2013 was_priv = 0;
2016 do {
2017 /* Take all statements dominated by s referencing the
2018 current scalar variable. */
2019 statement = candl_dependence_refvar_chain(scop, s, scalars[i], j);
2021 /* No more statement in the chain, exit. */
2022 if (statement[0] == NULL) {
2023 free(statement);
2024 break;
2027 int c = 0;
2029 is_priv = candl_dependence_var_is_ref(statement[0], scalars[i]) ==
2030 CANDL_VAR_IS_DEF;
2032 /* Ensure we have a use in the chain. */
2033 /* here statement[c] is not NULL */
2034 for (k = c + 1; statement[k]; ++k) {
2035 if (candl_dependence_var_is_ref(statement[k], scalars[i]) ==
2036 CANDL_VAR_IS_USED)
2037 break;
2040 if (statement[k] == NULL)
2041 is_priv = 0;
2043 /* Check for privatization, while the entry of the chain
2044 is a DEF. */
2045 while (statement[c] && candl_dependence_var_is_ref
2046 (statement[c], scalars[i]) == CANDL_VAR_IS_DEF) {
2047 /* From the current DEF node, ensure the rest of the
2048 chain covers not more than the iteration domain
2049 of the DEF. */
2050 for (k = c + 1; statement[k]; ++k) {
2051 /* FIXME: we should deal with
2052 def_1->use->def_2->use chains where dom(def_2)
2053 > dom(def_1). */
2054 if (! candl_dependence_check_domain_is_included
2055 (statement[c], statement[k], scop->context, j)) {
2056 /* dom(use) - dom(def) > 0. Check if there is
2057 another DEF to test at the entry of the
2058 block. */
2059 if (candl_dependence_var_is_ref
2060 (statement[c+1], scalars[i]) != CANDL_VAR_IS_DEF)
2061 /* No. The variable is not privatizable. */
2062 is_priv = 0;
2063 break;
2067 if (! is_priv || ! statement[k])
2068 break;
2070 /* The chain dominated by statement is not
2071 privatizable. Go for the next DEF at the
2072 beginning of the block, if any. */
2073 ++c;
2076 if (is_priv) {
2077 /* Perform the privatization / expansion. */
2078 if (options->verbose)
2079 fprintf(stderr, "[Candl] Scalar Analysis: The variable %d"
2080 " can be privatized at loop %d\n",
2081 scalars[i],
2082 ((candl_statement_usr_p)statement[0]->usr)->index[j-1]);
2084 if (options->scalar_expansion) {
2085 int precision = scop->context->precision;
2086 /* Traverse all statements in the chain. */
2087 for (k = c; statement[k]; ++k) {
2088 /* It's not the first expansion of the scalar,
2089 we need to increase its dimension all along
2090 the program. */
2091 if (!offset && !was_priv)
2092 candl_dependence_expand_scalar(fullchain,
2093 scalars[i]);
2094 /* Perform scalar expansion in the array
2095 access functions. */
2096 access = statement[k]->access;
2097 for (; access != NULL; access = access->next) {
2098 elt = access->elt;
2099 row = candl_relation_get_line(elt, 0);
2100 if (scalars[i] ==
2101 osl_int_get_si(precision, elt->m[row][elt->nb_columns-1])) {
2102 row = candl_relation_get_line(elt, offset+1);
2103 osl_int_set_si(precision, &elt->m[row][elt->nb_output_dims + j], 1);
2106 was_priv = 1;
2110 if (options->scalar_privatization) {
2111 /* Memory management for the array of
2112 privatizable scalars. */
2113 if (nb_priv == 0) {
2114 free(scop_usr->scalars_privatizable);
2115 CANDL_malloc(scop_usr->scalars_privatizable,
2116 int*, priv_buff_size * sizeof(int));
2117 for (k = 0; k < priv_buff_size; ++k)
2118 scop_usr->scalars_privatizable[k] = -1;
2121 if (nb_priv == priv_buff_size) {
2122 CANDL_realloc(scop_usr->scalars_privatizable,
2123 int*, (priv_buff_size *= 2) * sizeof(int));
2124 for (k = nb_priv; k < priv_buff_size; ++k)
2125 scop_usr->scalars_privatizable[k] = -1;
2128 /* Memorize the scalar information in the
2129 privatizable list. */
2130 scop_usr->scalars_privatizable[nb_priv++] = scalars[i];
2131 scop_usr->scalars_privatizable[nb_priv++] =
2132 ((candl_statement_usr_p)statement[0]->usr)->index[j - 1];
2135 } // end is_priv
2138 /* Go to the next block, if any. */
2139 for (k = 0; statement[k]; ++k)
2141 curlast = statement[k-1];
2143 if (curlast != last) {
2144 for (k = 0; fullchain[k]; ++k) {
2145 if (fullchain[k] == curlast) {
2146 s = fullchain[k+1];
2147 break;
2151 free(statement);
2153 } while (curlast != last);
2155 } // end iterate all possible depth
2157 free(fullchain);
2159 } // end iterate scalars
2161 return 0;
2166 * Compute last writer for a given dependence; does not make sense if the
2167 * supplied dependence is not a RAW or WAW dependence
2169 * Returns 0 if lastwriter is computed successfully and dep domain updated,
2170 * returns 1 otherwise
2172 static
2173 int candl_dep_compute_lastwriter(osl_dependence_p *dep, osl_scop_p scop) {
2174 PipQuast *lexmax;
2175 PipOptions *pipOptions = pip_options_init();
2176 candl_statement_usr_p s_usr = (*dep)->stmt_source_ptr->usr;
2177 candl_statement_usr_p t_usr = (*dep)->stmt_target_ptr->usr;
2178 osl_relation_p new_domain;
2179 int i, j;
2180 int npar = scop->context->nb_parameters;
2181 int precision;
2183 #if defined(LINEAR_VALUE_IS_INT)
2184 precision = OSL_PRECISION_SP;
2185 #elif defined(LINEAR_VALUE_IS_LONGLONG)
2186 precision = OSL_PRECISION_DP;
2187 #elif defined(LINEAR_VALUE_IS_MP)
2188 precision = OSL_PRECISION_MP;
2189 #endif
2191 if (precision != scop->context->precision) {
2192 CANDL_error("Precision not compatible with piplib ! (pip_relation2matrix)");
2195 /* We do a parametric lexmax on the source iterators
2196 * keeping the target iterators as parameters */
2197 pipOptions->Maximize = 1;
2198 pipOptions->Simplify = 1;
2199 // pipOptions->Deepest_cut = 1;
2200 // pipOptions->Urs_unknowns = -1;
2201 // pipOptions->Urs_parms = -1;
2203 /* Build a context with equalities /inequalities only on the target
2204 * variables */
2205 osl_relation_p context = osl_relation_pmalloc(precision,
2206 (*dep)->domain->nb_rows,
2207 (*dep)->stmt_target_ptr->domain->nb_columns);
2208 int nrows = 0;
2209 for (i = 0; i < (*dep)->domain->nb_rows; i++) {
2210 for (j = 1; j < s_usr->depth+1; j++) {
2212 // FIXME : new domain structure for dependence
2214 if (!osl_int_zero(precision, (*dep)->domain->m[i][j]))
2215 break;
2218 if (j == t_usr->depth+1) {
2219 /* Include this in the context */
2220 osl_int_assign(precision,
2221 &context->m[nrows][0], (*dep)->domain->m[i][0]);
2223 for (j = 1; j < (*dep)->stmt_target_ptr->domain->nb_columns; j++)
2224 osl_int_assign(precision,
2225 &context->m[nrows][j],
2226 (*dep)->domain->m[i][s_usr->depth+j]);
2228 nrows++;
2232 /* Parameteric lexmax */
2233 lexmax = pip_solve_osl((*dep)->domain, context, -1, pipOptions);
2235 pip_options_free(pipOptions);
2237 if (lexmax == NULL) {
2238 CANDL_warning("last writer failed (mostly invalid dependence): bailing out"
2239 "safely without modification");
2240 osl_relation_print(stderr, context);
2241 osl_relation_print(stderr, (*dep)->domain);
2242 return 1;
2245 int num;
2246 osl_relation_p qp = pip_quast_to_polyhedra(lexmax, s_usr->depth,
2247 t_usr->depth + npar);
2249 /* Update the dependence domains */
2250 if (num > 0) {
2251 osl_relation_p iter;
2252 osl_relation_p original_domain = (*dep)->domain;
2253 for (iter = qp ; iter != NULL ; iter = iter->next) {
2255 new_domain = osl_relation_pmalloc(precision,
2256 original_domain->nb_rows +
2257 qp->nb_rows,
2258 original_domain->nb_columns);
2260 for (i = 0; i < original_domain->nb_rows; i++)
2261 for (j = 0; j < original_domain->nb_columns; j++)
2262 osl_int_assign(precision,
2263 &new_domain->m[i][j],
2264 original_domain->m[i][j]);
2266 for (i = 0; i < qp->nb_rows; i++)
2267 for (j = 0; j < original_domain->nb_columns; j++)
2268 osl_int_assign(precision,
2269 &new_domain->m[i+original_domain->nb_rows][j],
2270 qp->m[i][j]);
2272 (*dep)->domain = new_domain;
2273 /* More than 1 pipmatrix from the quast, we need to insert
2274 new dependences to have the union of domains. */
2275 if (qp->next != NULL) {
2276 osl_dependence_p newdep = osl_dependence_malloc();
2277 newdep->stmt_source_ptr = (*dep)->stmt_source_ptr;
2278 newdep->stmt_target_ptr = (*dep)->stmt_target_ptr;
2279 newdep->depth = (*dep)->depth;
2280 newdep->type = (*dep)->type;
2281 newdep->label_source = (*dep)->label_source;
2282 newdep->label_target = (*dep)->label_target;
2283 newdep->ref_source = (*dep)->ref_source;
2284 newdep->ref_target = (*dep)->ref_target;
2285 newdep->usr = (*dep)->usr;
2286 newdep->source_nb_output_dims_domain = (*dep)->source_nb_output_dims_domain;
2287 newdep->source_nb_output_dims_access = (*dep)->source_nb_output_dims_access;
2288 newdep->target_nb_output_dims_domain = (*dep)->target_nb_output_dims_domain;
2289 newdep->target_nb_output_dims_access = (*dep)->target_nb_output_dims_access;
2290 newdep->source_nb_local_dims_domain = (*dep)->source_nb_local_dims_domain;
2291 newdep->source_nb_local_dims_access = (*dep)->source_nb_local_dims_access;
2292 newdep->target_nb_local_dims_domain = (*dep)->target_nb_local_dims_domain;
2293 newdep->target_nb_local_dims_access = (*dep)->target_nb_local_dims_access;
2294 newdep->next = (*dep)->next;
2295 (*dep)->next = newdep;
2296 *dep = newdep;
2300 osl_relation_free(original_domain);
2301 osl_relation_free(qp);
2304 pip_quast_free(lexmax);
2305 osl_relation_free(qp);
2306 osl_relation_free(context);
2308 return 0;
2312 * Compute the last writer for each RAW, WAW, and RAR dependence. This will
2313 * modify the dependence polyhedra. Be careful of any references to the old
2314 * dependence polyhedra. They are freed and new ones allocated.
2316 void candl_compute_last_writer(osl_dependence_p dep, osl_scop_p scop) {
2317 // int count=0;
2318 while (dep != NULL) {
2319 if (dep->type != OSL_DEPENDENCE_WAR) {
2320 // printf("Last writer for dep %d: %d %d\n", count++, dep->source->usr->depth, dep->target->usr->depth);
2321 // candl_matrix_print(stdout, dep->domain);
2322 candl_dep_compute_lastwriter(&dep, scop);
2323 // candl_matrix_print(stdout, dep->domain);
2325 dep = dep->next;