2 /**------ ( ----------------------------------------------------------**
4 **----- / ) --------------------------------------------------------**
5 ** ( * ( dependence.c **
6 **---- \#/ --------------------------------------------------------**
7 ** .-"#'-. First version: september 18th 2003 **
8 **--- |"-.-"| -------------------------------------------------------**
11 ******** | | *************************************************************
12 * CAnDL '-._,-' the Chunky Analyzer for Dependences in Loops (experimental) *
13 ******************************************************************************
15 * Copyright (C) 2003-2008 Cedric Bastoul *
17 * This is free software; you can redistribute it and/or modify it under the *
18 * terms of the GNU Lesser General Public License as published by the Free *
19 * Software Foundation; either version 3 of the License, or (at your option) *
20 * any later version. *
22 * This software is distributed in the hope that it will be useful, but *
23 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY *
24 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
27 * You should have received a copy of the GNU Lesser General Public License *
28 * along with software; if not, write to the Free Software Foundation, Inc., *
29 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
31 * CAnDL, the Chunky Dependence Analyzer *
32 * Written by Cedric Bastoul, Cedric.Bastoul@inria.fr *
34 ******************************************************************************/
37 * \author Cedric Bastoul and Louis-Noel Pouchet
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>
52 #include <osl/statement.h>
53 #include <osl/relation.h>
54 #include <osl/names.h>
59 #ifdef CANDL_SUPPORTS_ISL
60 # undef Q // Thank you polylib...
62 # include <isl/constraint.h>
70 * candl_dependence_get_relation_ref_source_in_dep function:
71 * This function return the corresponding osl_relation_p of
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
;
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
) {
84 if (count
== tmp
->ref_source
)
88 tmp
->ref_source_access_ptr
= elt
;
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
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
;
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
) {
106 if (count
== tmp
->ref_target
)
110 tmp
->ref_target_access_ptr
= elt
;
117 * candl_dependence_get_array_refs_in_dep function:
118 * This function return the array indices referenced in the
121 void candl_dependence_get_array_refs_in_dep(osl_dependence_p tmp
,
122 int* refs
, int* reft
) {
126 osl_relation_p src
, targ
;
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
) {
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
;
175 fprintf(file
, "# Number of edges = %i\n}\n", i
);
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
185 * - 20/03/2006: first version.
187 void candl_dependence_view(osl_dependence_p dep
) {
189 temp_output
= fopen(CANDL_TEMP_OUTPUT
,"w+");
190 candl_dependence_pprint(temp_output
, dep
);
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
,
203 osl_relation_p
isl_set_to_piplib_matrix(struct isl_ctx
* ctx
,
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
,
215 if (dep
== NULL
|| scop
== NULL
)
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
);
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);
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
) {
265 if (usr
->label
== dep
->label_source
) {
266 dep
->stmt_source_ptr
= iter
;
271 fprintf(stderr
, "[Candl] Can't find the %dth label\n", dep
->label_source
);
275 /* target statement */
276 iter
= scop
->statement
;
277 for (; iter
!= NULL
; iter
= iter
->next
) {
279 if (usr
->label
== dep
->label_target
) {
280 dep
->stmt_target_ptr
= iter
;
285 fprintf(stderr
, "[Candl] Can't find the %dth label\n", dep
->label_target
);
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",
293 osl_statement_dump(stderr
, dep
->stmt_source_ptr
);
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",
301 osl_statement_dump(stderr
, dep
->stmt_target_ptr
);
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
;
321 static int candl_dependence_gcd(int a
, int b
) {
351 static int candl_dependence_gcd_test_context(osl_relation_p system
, int id
) {
352 /* FIXME: implement me! */
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
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
,
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
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; */
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]);
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)
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
]))
416 else if (osl_int_pos(precision
, system
->m
[id
][i
]))
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)
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
)
430 if (! candl_dependence_gcd_test_context(system
, id
))
432 if (null_cst
|| !null_param
)
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) */
439 /* if (null_param && neg_iter && */
440 /* CANDL_get_si(system->p[id][system->NbColumns - 1]) < 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
)
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
;
487 int precision
= source
->domain
->precision
;
488 int nb_output_dims
; // source column
489 int nb_input_dims
; // target column
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
;
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
+
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
++) {
546 osl_int_assign(precision
,
547 &system
->m
[constraint
][0], source
->domain
->m
[i
][0]);
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
]);
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
]);
567 /* 2. Copy the target domain */
568 for (i
= 0 ; i
< target
->domain
->nb_rows
; i
++) {
570 osl_int_assign(precision
,
571 &system
->m
[constraint
][0], target
->domain
->m
[i
][0]);
573 k
= 1 + nb_output_dims
;
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
]);
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
]);
591 /* 3. Copy the source access */
592 for (i
= 0 ; i
< array_s
->nb_rows
; i
++) {
594 osl_int_assign(precision
,
595 &system
->m
[constraint
][0], array_s
->m
[i
][0]);
597 k
= 1 + source
->domain
->nb_output_dims
;
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 */
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
]);
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
]);
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
]);
621 /* 4. Copy the target access */
622 for (i
= 0 ; i
< array_t
->nb_rows
; i
++) {
624 osl_int_assign(precision
,
625 &system
->m
[constraint
][0], array_t
->m
[i
][0]);
627 k
= 1 + nb_output_dims
+ target
->domain
->nb_output_dims
;
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
]);
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
]);
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
]);
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);
673 /* 6. The precedence constraints */
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
])
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);
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
;
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
))
747 /* We build the system of constraints. */
748 dependence
= candl_dependence_build_system(source
, target
,
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
);
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
;
773 osl_dependence_free(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
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
;
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
))
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
) {
821 max_depth
= s_usr
->depth
;
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;
830 while ((max_depth
< s_usr
->depth
) &&
831 (max_depth
< t_usr
->depth
) &&
832 (s_usr
->index
[max_depth
] == t_usr
->index
[max_depth
]))
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
)
849 access_targ
= target
->access
;
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 */
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
,
865 OSL_DEPENDENCE_WAR
, i
);
866 osl_dependence_add(&dependence
, &now
, new);
870 /* Input-dependences analysis. */
871 else { /* target READ */
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
,
880 OSL_DEPENDENCE_RAR
, i
);
881 osl_dependence_add(&dependence
, &now
, new);
888 default: /* source WRITE | MAY-WRITE */
889 if (!options
->raw
&& !options
->waw
)
891 access_targ
= target
->access
;
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 */
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
,
907 OSL_DEPENDENCE_WAW
, i
);
908 osl_dependence_add(&dependence
, &now
, new);
912 /* Input-dependences analysis. */
913 else { /* target READ */
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
,
922 OSL_DEPENDENCE_RAW
, i
);
923 osl_dependence_add(&dependence
, &now
, new);
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. */
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. */
963 new = candl_dependence_between(stmt_i
, stmt_j
, context
, options
);
964 osl_dependence_add(&dependence
, &now
, new);
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. */
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
);
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
;
1013 int precision
= scop
->context
->precision
;
1017 statement
= scop
->statement
;
1018 while (statement
!= NULL
) {
1019 access
= statement
->access
;
1020 while (access
!= NULL
) {
1022 row
= candl_relation_get_line(elt
, 0);
1023 if (osl_int_get_si(precision
, elt
->m
[row
][elt
->nb_columns
- 1]) ==
1025 /* Ensure it is not an array. */
1026 if (elt
->nb_output_dims
> 1)
1028 /* Ensure the access function is '0'. */
1029 if (!osl_int_zero(precision
, elt
->m
[row
][0]))
1031 for (i
= 2; i
< elt
->nb_columns
-2; ++i
) /* jmp the 'Arr' */
1032 if (!osl_int_zero(precision
, elt
->m
[row
][i
]))
1035 access
= access
->next
;
1037 statement
= statement
->next
;
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
,
1053 osl_relation_list_p access
;
1057 int precision
= sl
[0]->scattering
->precision
;
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
1065 access
= sl
[i
]->access
;
1066 for (; access
!= NULL
; access
= access
->next
) {
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
) {
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
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
)
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
;
1104 int buffer_size
= 64;
1107 /* If no dominator is provided, assume we start with the first statement. */
1109 dom
= scop
->statement
;
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
)
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
)
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
];
1141 /* Ensure the variable is referenced. */
1142 if (candl_dependence_var_is_ref(statement
, var_index
) != CANDL_VAR_UNDEF
) {
1143 if (count
== buffer_size
) {
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));
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
;
1169 int ret
= CANDL_VAR_UNDEF
;
1174 while (access
!= NULL
) {
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]) ==
1180 ret
= CANDL_VAR_IS_USED
;
1184 access
= access
->next
;
1189 while (access
!= NULL
) {
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]) ==
1195 if (ret
== CANDL_VAR_IS_USED
)
1196 ret
= CANDL_VAR_IS_DEF_USED
;
1198 ret
= CANDL_VAR_IS_DEF
;
1202 access
= access
->next
;
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
;
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
))) {
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
,
1247 osl_relation_p context
,
1249 candl_statement_usr_p s1_usr
= s1
->usr
;
1250 candl_statement_usr_p s2_usr
= s2
->usr
;
1251 osl_relation_p matrix
;
1254 int precision
= s2
->domain
->precision
;
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
1280 #elif defined(LINEAR_VALUE_IS_LONGLONG)
1282 #elif defined(LINEAR_VALUE_IS_MP)
1283 mpz_set(*((mpz_t
*)osl_lb
.mp
), lb
);
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
]))
1298 if (j
<= s1_usr
->depth
)
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. */
1325 osl_int_clear(precision
, &osl_lb
);
1326 osl_relation_free(matrix
);
1332 osl_int_clear(precision
, &osl_lb
);
1333 osl_relation_free(matrix
);
1340 * candl_dependence_extract_scalar_variables function:
1341 * This functions returns a -1-terminated array of the scop scalar
1344 int* candl_dependence_extract_scalar_variables(osl_scop_p scop
) {
1345 osl_statement_p statement
;
1347 osl_relation_list_p access
;
1348 int scalars
[1024]; /* FIXME: implement a real buffer. */
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
) {
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
)
1367 for (i
= 0; i
< count_c
&& checked
[i
] != idx
; ++i
)
1370 if (candl_dependence_var_is_scalar(scop
, idx
))
1371 scalars
[count_s
++] = idx
;
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. */
1385 CANDL_malloc(res
, int*, (count_s
+ 1) * sizeof(int));
1386 for (i
= 0; i
< count_s
; ++i
)
1387 res
[i
] = scalars
[i
];
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
) {
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"
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
);
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 */
1455 osl_relation_list_p access
;
1456 candl_statement_usr_p usr
;
1457 candl_statement_usr_p last_usr
;
1459 int nb_statements
= 0;
1463 int precision
= scop
->context
->precision
;
1465 int tmp
, has_changed
= 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
) {
1476 row
= candl_relation_get_line(elt
, 0);
1477 tmp
= osl_int_get_si(precision
, elt
->m
[row
][elt
->nb_columns
- 1]);
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
) {
1504 /* Get all defs and all uses. */
1507 for (j
= 0; statement
[j
]; ++j
) {
1508 tmp
= candl_dependence_var_is_ref(statement
[j
], scalars
[i
]);
1510 case CANDL_VAR_IS_USED
:
1511 case CANDL_VAR_IS_DEF_USED
:
1512 uses
[uses_c
++] = statement
[j
];
1514 case CANDL_VAR_IS_DEF
:
1515 defs
[defs_c
++] = statement
[j
];
1522 for (iter
= scop
->statement
; iter
!= NULL
; iter
= iter
->next
)
1523 current
[j
++] = NULL
;
1527 /* Iterate on all DEFs. */
1529 for (j
= 0; j
< defs_c
; ++j
) {
1530 if (last_def
== NULL
) {
1533 /* Ensure the current DEF covers all iterations covered
1534 by the last checked one. */
1535 last_usr
= last_def
->usr
;
1537 for (k
= 0; k
< last_usr
->depth
&& k
< usr
->depth
&&
1538 last_usr
->index
[k
] == usr
->index
[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)) {
1545 current
[usr
->label
] = last_def
;
1551 /* Create DEF-USE table. */
1552 for (k
= 0; k
< uses_c
; ++k
) {
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
)
1563 /* Create partitions. */
1564 for (j
= 0; j
< defs_c
; ++j
) {
1566 for (k
= 0; k
< nb_statements
; ++k
)
1567 if ((current
[k
] && current
[k
] == defs
[j
]) ||
1568 (k
== usr
->label
&& current
[usr
->label
] == NULL
))
1572 /* Check if it is needed to rename the scalar. */
1574 for (j
= 0; j
< nb_statements
; ++j
)
1579 if (parts
[j
] != -1 && tmp
!= parts
[j
])
1583 /* Rename scalar variable. */
1584 if (j
!= nb_statements
) {
1587 for (iter
= scop
->statement
; iter
!= NULL
; iter
= iter
->next
) {
1588 if (parts
[j
] != -1) {
1591 else if (tmp
!= parts
[j
])
1594 access
= iter
->access
;
1595 for (; access
!= NULL
; access
= access
->next
) {
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],
1613 } /* end Iterate on all scalars */
1615 /* Redo the full dependence analysis, if needed. */
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
;
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
,
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
;
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
)
1655 if (i
!= dep
->depth
- 1 || i
>= t_usr
->depth
)
1657 for (j
= 0; j
< t_usr
->depth
; ++j
)
1658 if (t_usr
->index
[j
] == loop_index
)
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. */
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
1683 if (!osl_int_zero(precision
, msrc
->m
[row_k
][i
])) {
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
1695 if (!osl_int_eq(precision
,
1696 msrc
->m
[row_k
][0], mtarg
->m
[row_kp
][0])) {
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
])) {
1709 for (; l
<= s_usr
->depth
+1; ++l
)
1710 if (!osl_int_zero(precision
, msrc
->m
[row_k
][msrc
->nb_output_dims
+ l
])) {
1715 for (; m
<= t_usr
->depth
+1; ++m
)
1716 if (!osl_int_zero(precision
, mtarg
->m
[row_kp
][mtarg
->nb_output_dims
+ m
])) {
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
])) {
1730 row_kp
= candl_relation_get_line(mtarg
, kp
);
1734 row_k
= candl_relation_get_line(msrc
, k
);
1737 if (src_ref_iter
&& dst_ref_iter
&& !must_test
)
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
1745 osl_relation_p mat
= dep
->domain
;
1747 osl_relation_p testsyst
= osl_relation_pmalloc(precision
,
1748 mat
->nb_rows
+ 1 + s_usr
->depth
,
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);
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);
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);
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. *\/ */
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); */
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
;
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
)
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. */
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
,
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
]))
1862 if (i
== t_usr
->depth
)
1865 loop_idx
= t_usr
->index
[i
];
1867 loop_idx
= s_usr
->index
[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
],
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
;
1888 if (!candl_matrix_check_point(tmp
->domain
, NULL
)) {
1889 /* It is, the dependence can be removed. */
1890 osl_relation_free(tmp
->domain
);
1902 /* Go to the next victim. */
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
,
1917 candl_scop_usr_p scop_usr
= scop
->usr
;
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
);
1929 while (scop_usr
->scalars_privatizable
[i
] != -1)
1932 /* Check in the array of privatizable scalar variables for the tuple
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
)
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
) {
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 */
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
;
1959 candl_scop_usr_p scop_usr
= scop
->usr
;
1960 candl_statement_usr_p stmt_usr
;
1962 int max
, is_priv
, offset
, was_priv
;
1964 int priv_buff_size
= 64;
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
])
1987 /* A weird error occured. */
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. */
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. */
2007 /* Iterate on all possible depth for analysis. */
2008 for (j
= 1; j
<= max
; ++j
) {
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
) {
2029 is_priv
= candl_dependence_var_is_ref(statement
[0], scalars
[i
]) ==
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
]) ==
2040 if (statement
[k
] == NULL
)
2043 /* Check for privatization, while the entry of the chain
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
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)
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
2059 if (candl_dependence_var_is_ref
2060 (statement
[c
+1], scalars
[i
]) != CANDL_VAR_IS_DEF
)
2061 /* No. The variable is not privatizable. */
2067 if (! is_priv
|| ! statement
[k
])
2070 /* The chain dominated by statement is not
2071 privatizable. Go for the next DEF at the
2072 beginning of the block, if any. */
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",
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
2091 if (!offset
&& !was_priv
)
2092 candl_dependence_expand_scalar(fullchain
,
2094 /* Perform scalar expansion in the array
2095 access functions. */
2096 access
= statement
[k
]->access
;
2097 for (; access
!= NULL
; access
= access
->next
) {
2099 row
= candl_relation_get_line(elt
, 0);
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);
2110 if (options
->scalar_privatization
) {
2111 /* Memory management for the array of
2112 privatizable scalars. */
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];
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
) {
2153 } while (curlast
!= last
);
2155 } // end iterate all possible depth
2159 } // end iterate scalars
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
2173 int candl_dep_compute_lastwriter(osl_dependence_p
*dep
, osl_scop_p scop
) {
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
;
2180 int npar
= scop
->context
->nb_parameters
;
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
;
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
2205 osl_relation_p context
= osl_relation_pmalloc(precision
,
2206 (*dep
)->domain
->nb_rows
,
2207 (*dep
)->stmt_target_ptr
->domain
->nb_columns
);
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
]))
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
]);
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
);
2246 osl_relation_p qp
= pip_quast_to_polyhedra(lexmax
, s_usr
->depth
,
2247 t_usr
->depth
+ npar
);
2249 /* Update the dependence domains */
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
+
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
],
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
;
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
);
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
) {
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);