2 /*--------------------------------------------------------------------+
4 |--------------------------------------------------------------------|
6 |--------------------------------------------------------------------|
7 | First version: 03/04/2012 |
8 +--------------------------------------------------------------------+
10 +--------------------------------------------------------------------------+
11 | / __)( ) /__\ ( \/ ) |
12 | ( (__ )(__ /(__)\ \ / Chunky Loop Alteration wizardrY |
13 | \___)(____)(__)(__)(__) |
14 +--------------------------------------------------------------------------+
15 | Copyright (C) 2012 University of Paris-Sud |
17 | This library is free software; you can redistribute it and/or modify it |
18 | under the terms of the GNU Lesser General Public License as published by |
19 | the Free Software Foundation; either version 2.1 of the License, or |
20 | (at your option) any later version. |
22 | This library is distributed in the hope that it will be useful but |
23 | WITHOUT ANY WARRANTY; without even the implied warranty of |
24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
25 | General Public License for more details. |
27 | You should have received a copy of the GNU Lesser General Public License |
28 | along with this software; if not, write to the Free Software Foundation, |
29 | Inc., 51 Franklin Street, Fifth Floor, |
30 | Boston, MA 02110-1301 USA |
32 | Clay, the Chunky Loop Alteration wizardrY |
33 | Written by Joel Poudroux, joel.poudroux@u-psud.fr |
34 +--------------------------------------------------------------------------*/
40 #include <osl/statement.h>
41 #include <osl/relation.h>
43 #include <clay/array.h>
44 #include <clay/beta.h>
45 #include <clay/macros.h>
46 #include <clay/util.h>
50 * clay_beta_sort function:
51 * The list of statements in the scop is sorted in function of the beta
54 void clay_beta_sort(osl_scop_p scop
) {
55 if (scop
== NULL
|| scop
->statement
== NULL
|| scop
->statement
->next
== NULL
)
63 osl_statement_p
*buff
;
66 CLAY_malloc(buff
, osl_statement_p
* , sizeof(osl_statement_p
) * sizebuff
);
68 for (iter
= scop
->statement
; iter
!= NULL
; iter
= iter
->next
) {
69 buff
[nb_stmt
++] = iter
;
70 if (nb_stmt
== sizebuff
) {
72 CLAY_realloc(buff
, osl_statement_p
*, sizeof(osl_statement_p
) * sizebuff
);
77 for (i
= 1 ; i
< nb_stmt
; i
++) {
79 beta
= clay_beta_get(tmp
);
80 for (j
= i
; j
> 0 && !clay_statement_is_before(buff
[j
-1], beta
) ; j
--)
83 clay_array_free(beta
);
86 scop
->statement
= buff
[0];
87 for (i
= 0 ; i
< nb_stmt
-1 ; i
++) {
88 buff
[i
]->next
= buff
[i
+1];
96 // this algo is less well because if the list is already sorted, the
97 // complexity will be maximal
99 osl_statement_p current;
101 osl_statement_p head = scop->statement;
103 while (tmp->next != NULL) {
105 beta = clay_beta_get(current);
106 if (!clay_statement_is_before(head, beta)) {
107 tmp->next = current->next;
108 current->next = head;
111 for (iter = head ; iter != tmp ; iter = iter->next) {
112 if (!clay_statement_is_before(iter->next, beta))
116 tmp->next = current->next;
117 iter->next = current;
123 clay_array_free(beta);
125 scop->statement = head;*/
130 * clay_beta_normalize function:
131 * Normalize all the beta
132 * \param[in,out] scop
134 void clay_beta_normalize(osl_scop_p scop
) {
138 osl_statement_p sout
;
139 osl_relation_p scattering
;
141 clay_array_p beta_next
;
143 int counter_loops
[CLAY_MAX_BETA_SIZE
];
147 for (i
= 0 ; i
< CLAY_MAX_BETA_SIZE
; i
++) {
148 counter_loops
[i
] = 0;
151 // TODO : we can optimize with clay_beta_sort, instead of looking for the
152 // following each time
155 beta
= clay_array_malloc(); // empty beta
156 beta_next
= clay_beta_next(scop
->statement
, beta
, &sout
);
158 // for each statement, we set the smallest beta
159 while (beta_next
!= NULL
) {
160 clay_array_free(beta
);
163 // set the smallest beta
164 for (j
= 0 ; j
< beta
->size
; j
++) {
165 //beta->data[i] = counter_loops[j];
166 scattering
= sout
->scattering
;
167 row
= clay_util_relation_get_line(scattering
, j
*2);
168 osl_int_set_si(scattering
->precision
,
169 &scattering
->m
[row
][scattering
->nb_columns
-1],
173 beta_next
= clay_beta_next(scop
->statement
, beta
, &sout
);
175 if (beta_next
== NULL
)
178 // search the first value wich is greater than the beta_last
180 while (i
< beta_next
->size
&& i
< beta
->size
) {
181 if (beta_next
->data
[i
] > beta
->data
[i
])
186 // update the counter array for the next step
187 if (i
!= beta_next
->size
)
190 // the rest is set to zero
192 while (i
< beta
->size
) {
193 counter_loops
[i
] = 0;
199 clay_array_free(beta
);
204 * clay_beta_get function:
205 * \param[in] statement Current statement
206 * \return Return the real line
208 clay_array_p
clay_beta_get(osl_statement_p statement
) {
209 if (statement
== NULL
)
212 osl_relation_p scattering
= statement
->scattering
;
213 clay_array_p beta
= clay_array_malloc();
215 int last_column
= scattering
->nb_columns
-1;
216 int precision
= scattering
->precision
;
218 for (j
= 1 ; j
< scattering
->nb_output_dims
+1 ; j
+= 2) {
219 // search the first non zero
220 for (i
= 0 ; i
< scattering
->nb_rows
; i
++) {
221 // test if the line is an equality
222 if (osl_int_zero(precision
, scattering
->m
[i
][0])) {
223 // non zero on the column
224 if (!osl_int_zero(precision
, scattering
->m
[i
][j
])) {
225 // line and column are corrects
226 if (clay_scattering_check_zeros(statement
, i
, j
)) {
227 row
= clay_util_relation_get_line(scattering
, j
-1);
229 tmp
= osl_int_get_si(scattering
->precision
,
230 scattering
->m
[row
][last_column
]);
232 clay_array_add(beta
, tmp
);
245 * clay_beta_min function:
247 * \param[in] statement List of statements
248 * \param[in] beta Beta vector parent
251 clay_array_p
clay_beta_min(osl_statement_p statement
, clay_array_p beta
) {
252 statement
= clay_beta_find(statement
, beta
);
256 clay_array_p beta_min
= clay_beta_get(statement
);
258 while (statement
!= NULL
) {
259 if (clay_beta_check(statement
, beta
) &&
260 clay_statement_is_before(statement
, beta_min
)) {
261 clay_array_free(beta_min
);
262 beta_min
= clay_beta_get(statement
);
264 statement
= statement
->next
;
272 * clay_beta_max function:
273 * Return the beta max
274 * \param[in] statement List of statements
275 * \param[in] beta Beta vector parent
278 clay_array_p
clay_beta_max(osl_statement_p statement
, clay_array_p beta
) {
279 statement
= clay_beta_find(statement
, beta
);
283 clay_array_p beta_max
= clay_beta_get(statement
);
285 while (statement
!= NULL
) {
286 if (clay_beta_check(statement
, beta
) &&
287 clay_statement_is_after(statement
, beta_max
)) {
288 clay_array_free(beta_max
);
289 beta_max
= clay_beta_get(statement
);
291 statement
= statement
->next
;
299 * clay_beta_next function:
300 * Return the beta after the given beta.
301 * \param[in] statement List of statements
302 * \param[in] beta Beta vector
303 * \param[out] sout If not NULL, this is the statement wich corresponds
304 * to the returned beta
307 clay_array_p
clay_beta_next(osl_statement_p statement
, clay_array_p beta
,
308 osl_statement_p
*sout
) {
311 clay_array_p beta_next
= NULL
;
312 const int nb_dims
= beta
->size
*2-1;
315 // Search the first statement after the beta
316 while (statement
!= NULL
) {
317 is_statement
= statement
->scattering
->nb_output_dims
<= nb_dims
;
318 if ((!is_statement
&& !clay_statement_is_before(statement
, beta
)) ||
319 (is_statement
&& clay_statement_is_after(statement
, beta
))) {
320 beta_next
= clay_beta_get(statement
);
321 if (sout
) *sout
= statement
;
324 statement
= statement
->next
;
327 if (beta_next
== NULL
) {
328 if (sout
) *sout
= NULL
;
331 /*if (is_statement &&
332 statement->scattering->nb_output_dims < beta_next->size*2-1) {
333 clay_array_free(beta_next);
334 if (sout) *sout = NULL;
338 // Search if there is an another beta before the beta we have found
339 while (statement
!= NULL
) {
340 is_statement
= statement
->scattering
->nb_output_dims
<= nb_dims
;
341 if (((!is_statement
&& !clay_statement_is_before(statement
, beta
)) ||
342 (is_statement
&& clay_statement_is_after(statement
, beta
))) &&
343 clay_statement_is_before(statement
, beta_next
)) {
344 clay_array_free(beta_next
);
345 beta_next
= clay_beta_get(statement
);
346 if (sout
) *sout
= statement
;
348 statement
= statement
->next
;
356 * clay_beta_next_part function:
357 * Return the beta after (strictly) the given beta.
358 * If the beta is a loop, the next beta is the beta which is after the loop (and
359 * not the statements inside the loop)
360 * \param[in] statement List of statements
361 * \param[in] beta Beta vector
364 clay_array_p
clay_beta_next_part(osl_statement_p statement
, clay_array_p beta
) {
368 clay_array_p beta_next
= NULL
;
370 // Search the first statement after the beta
371 while (statement
!= NULL
) {
372 if (clay_statement_is_after(statement
, beta
)) {
373 beta_next
= clay_beta_get(statement
);
376 statement
= statement
->next
;
379 if (beta_next
== NULL
)
382 // Search if there is an another beta before the beta we have found
383 while (statement
!= NULL
) {
384 if (clay_statement_is_after(statement
, beta
) &&
385 clay_statement_is_before(statement
, beta_next
)) {
386 clay_array_free(beta_next
);
387 beta_next
= clay_beta_get(statement
);
389 statement
= statement
->next
;
397 * clay_beta_find function:
398 * Return the first statement (the first checked by the beta and not the first
399 * in the list, use clay_beta_min for this purpose) which corresponds to the
401 * \param[in] statement Start statement list
402 * \param[in] beta Vector to search
403 * \return Return the first corresponding statement
405 osl_statement_p
clay_beta_find(osl_statement_p statement
,
407 while (statement
!= NULL
) {
408 if (clay_beta_check(statement
, beta
))
410 statement
= statement
->next
;
417 * clay_beta_nb_parts function:
418 * It doesn't count statements inside sub loops
427 * nb_parts in for(i) = 2 (S1 and for(j))
428 * \param[in] statement Statements list
429 * \param[in] beta Vector to search
432 int clay_beta_nb_parts(osl_statement_p statement
, clay_array_p beta
) {
434 const int column
= beta
->size
*2;
438 osl_relation_p scattering
;
439 while (statement
!= NULL
) {
440 if (clay_beta_check(statement
, beta
)) {
441 scattering
= statement
->scattering
;
442 if (column
< scattering
->nb_output_dims
) {
443 row
= clay_util_relation_get_line(scattering
, column
);
444 current_level
= osl_int_get_si(scattering
->precision
,
445 scattering
->m
[row
][scattering
->nb_columns
-1]);
446 if (current_level
!= last_level
) {
448 last_level
= current_level
;
450 } else if (column
-2 >= scattering
->nb_output_dims
-1) {
455 statement
= statement
->next
;
462 * clay_beta_shift_before function:
463 * Shift before the statement wich corresponds to the beta. It's pratically
464 * the same function as clay_beta_shift_after but it's equal or after, not
465 * strictly after. If the beta is empty, the function does nothing.
466 * \param[in,out] statement Statements list
467 * \param[in] beta Beta vector
468 * \param[in] depth Depth level to shift, >= 1
470 void clay_beta_shift_before(osl_statement_p statement
, clay_array_p beta
,
474 osl_relation_p scattering
;
475 const int column
= (depth
-1)*2; // alpha column
477 int precision
= statement
->scattering
->precision
;
479 clay_array_p beta_parent
= clay_array_clone(beta
);
480 (beta_parent
)->size
= depth
-1;
482 while (statement
!= NULL
) {
483 if (!clay_statement_is_before(statement
, beta
)) { // after or equal
484 if (clay_beta_check(statement
, beta_parent
)) {
485 scattering
= statement
->scattering
;
486 if (column
< scattering
->nb_output_dims
) {
487 row
= clay_util_relation_get_line(scattering
, column
);
488 osl_int_increment(precision
,
489 &scattering
->m
[row
][scattering
->nb_columns
-1],
490 scattering
->m
[row
][scattering
->nb_columns
-1]);
494 statement
= statement
->next
;
496 clay_array_free(beta_parent
);
501 * clay_beta_shift_after function:
502 * Shift after (strictly) the statement which corresponds to the beta.
503 * If the beta is empty, the function does nothing.
504 * \param[in,out] statement Statements list
505 * \param[in] beta Beta vector
506 * \param[in] depth Depth level to shift, >= 1
508 void clay_beta_shift_after(osl_statement_p statement
, clay_array_p beta
,
512 osl_relation_p scattering
;
513 const int column
= (depth
-1)*2; // alpha column
515 int precision
= statement
->scattering
->precision
;
517 clay_array_p beta_parent
= clay_array_clone(beta
);
518 beta_parent
->size
= depth
-1;
520 while (statement
!= NULL
) {
521 if (clay_statement_is_after(statement
, beta
)) {
522 scattering
= statement
->scattering
;
523 if (column
< scattering
->nb_output_dims
) {
524 row
= clay_util_relation_get_line(scattering
, column
);
525 osl_int_increment(precision
,
526 &scattering
->m
[row
][scattering
->nb_columns
-1],
527 scattering
->m
[row
][scattering
->nb_columns
-1]);
530 statement
= statement
->next
;
532 clay_array_free(beta_parent
);
537 * clay_statement_is_before function:
538 * Return true if the statement is before (strictly) the beta
539 * \param[in] statement
543 int clay_statement_is_before(osl_statement_p statement
, clay_array_p beta
) {
544 osl_relation_p scat
= statement
->scattering
;
545 int precision
= scat
->precision
;
550 if (scat
->nb_output_dims
>= beta
->size
*2+1)
553 end
= (scat
->nb_output_dims
+1)/2;
555 osl_int_p tmp
= osl_int_malloc(precision
);
557 for (i
= 0 ; i
< end
; i
++) {
558 row
= clay_util_relation_get_line(scat
, i
*2);
559 osl_int_add_si(precision
,
561 scat
->m
[row
][scat
->nb_columns
-1],
562 -beta
->data
[i
]); // -> substraction
563 if (osl_int_pos(precision
, *tmp
)) {
564 osl_int_free(precision
, tmp
);
566 } else if (osl_int_neg(precision
, *tmp
)) {
567 osl_int_free(precision
, tmp
);
571 osl_int_free(precision
, tmp
);
577 * clay_statement_is_after function:
578 * Return true if statement is after (strictly) the beta
579 * \param[in] statement
583 int clay_statement_is_after(osl_statement_p statement
, clay_array_p beta
) {
584 return !clay_beta_check(statement
, beta
) &&
585 !clay_statement_is_before(statement
, beta
);
590 * clay_beta_check function:
591 * check if the current statement corresponds to the beta vector
592 * \param[in] statement Statement to test
593 * \param[in] beta Vector to search
594 * \return true if correct
596 int clay_beta_check(osl_statement_p statement
, clay_array_p beta
) {
601 if (statement
->scattering
->nb_output_dims
>= beta
->size
*2+1)
604 end
= (statement
->scattering
->nb_output_dims
+1)/2;
606 //if (beta->size*2-1 > statement->scattering->nb_output_dims)
609 osl_relation_p scattering
= statement
->scattering
;
610 int last_column
= scattering
->nb_columns
-1;
614 int precision
= scattering
->precision
;
616 for (k
= 0 ; k
< end
; k
++) {
619 // search the first non zero
620 for (i
= 0 ; i
< scattering
->nb_rows
; i
++) {
622 // test if the line is an equality
623 if (osl_int_zero(precision
, scattering
->m
[i
][0])) {
625 // non zero on the column
626 if (!osl_int_zero(precision
, scattering
->m
[i
][j
])) {
627 tmp
= osl_int_get_si(precision
, scattering
->m
[i
][last_column
]);
628 if (tmp
!= beta
->data
[k
]) {
632 // line and column are corrects ?
633 if (!clay_scattering_check_zeros(statement
, i
, j
)) {
634 // errors should not happen
655 * clay_scattering_check_zeros function:
656 * check if the scattering on the first statement contains only zero at line i
657 * and column j, but not on (i,j), on the first column (equality column), and on
659 * Used to check if the line is a line of a beta vector
660 * \param[in] statement
663 * \return true if correct
665 int clay_scattering_check_zeros(osl_statement_p statement
, int i
, int j
) {
666 osl_relation_p scattering
= statement
->scattering
;
667 int precision
= scattering
->precision
;
670 for (t
= i
+1 ; t
< scattering
->nb_rows
; t
++) {
671 if (!osl_int_zero(precision
, scattering
->m
[t
][j
])) {
672 fprintf(stderr
, "[Clay] Warning: the scattering is incorrect (column %d)\n",
674 fprintf(stderr
, "[Clay] a non-zero value appear\n");
675 osl_statement_p tmp
= statement
->next
;
676 statement
->next
= NULL
;
677 osl_statement_dump(stderr
, statement
);
678 statement
->next
= tmp
;
682 for (t
= j
+1 ; t
< scattering
->nb_columns
-1 ; t
++) {
683 if (!osl_int_zero(precision
, scattering
->m
[i
][t
])) {
684 fprintf(stderr
, "[Clay] Warning: the scattering is incorrect (line %d)\n",
686 fprintf(stderr
, "[Clay] a non-zero value appear\n");
687 osl_statement_p tmp
= statement
->next
;
688 statement
->next
= NULL
;
689 osl_statement_dump(stderr
, statement
);
690 statement
->next
= tmp
;