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/macros.h>
43 #include <osl/strings.h>
45 #include <osl/statement.h>
46 #include <osl/relation.h>
47 #include <osl/generic.h>
48 #include <osl/extensions/scatnames.h>
49 #include <osl/extensions/arrays.h>
50 #include <osl/extensions/extbody.h>
52 #include <clay/transformation.h>
53 #include <clay/array.h>
54 #include <clay/list.h>
55 #include <clay/macros.h>
56 #include <clay/options.h>
57 #include <clay/errors.h>
58 #include <clay/beta.h>
59 #include <clay/util.h>
62 /*****************************************************************************\
63 * Loop transformations *
64 `****************************************************************************/
67 * clay_reorder function:
68 * Reorders the statements in the loop
70 * \param[in] beta_loop Loop beta vector
71 * \param[in] order Array to reorder the statements
75 int clay_reorder(osl_scop_p scop
,
76 clay_array_p beta_loop
, clay_array_p neworder
,
77 clay_options_p options
) {
78 // Replace element in the nested beta-vectors with respect to the values in
79 // the neworder array.
81 osl_relation_p scattering
;
82 osl_statement_p statement
;
84 const int column
= beta_loop
->size
* 2; // relation_get_line adds 1 -> beta
88 // Ensure that beta-vectors are normalized since we use their elements as
89 // indices to neworder array.
90 clay_beta_normalize(scop
);
92 statement
= clay_beta_find(scop
->statement
, beta_loop
);
94 return CLAY_ERROR_BETA_NOT_FOUND
;
96 precision
= statement
->scattering
->precision
;
97 while (statement
!= NULL
) {
98 scattering
= statement
->scattering
;
99 while (scattering
!= NULL
) {
100 // Select all the parts of relation union that match current beta.
101 if (!clay_beta_check_relation(scattering
, beta_loop
)) {
102 scattering
= scattering
->next
;
105 CLAY_BETA_IS_LOOP(beta_loop
, scattering
);
107 row
= clay_util_relation_get_line(scattering
, column
);
109 // Get the beta value.
110 index
= osl_int_get_si(precision
,
111 scattering
->m
[row
][scattering
->nb_columns
- 1]);
113 if (index
>= neworder
->size
)
114 return CLAY_ERROR_REORDER_ARRAY_TOO_SMALL
;
116 osl_int_set_si(precision
,
117 &scattering
->m
[row
][scattering
->nb_columns
- 1],
118 neworder
->data
[index
]);
119 scattering
= scattering
->next
;
121 statement
= statement
->next
;
124 // Normalize again if asked (useful if the neworder was not normalized).
125 if (options
&& options
->normalize
)
126 clay_beta_normalize(scop
);
133 * clay_reverse function:
134 * Reverse the direction of the loop
135 * \param[in,out] scop
136 * \param[in] beta Beta vector
140 int clay_reverse(osl_scop_p scop
, clay_array_p beta
, unsigned int depth
,
141 clay_options_p options
) {
142 // Oppose the output_dims column at the `depth'th level.
145 return CLAY_ERROR_BETA_EMPTY
;
147 return CLAY_ERROR_DEPTH_OVERFLOW
;
149 osl_relation_p scattering
;
150 osl_statement_p statement
= scop
->statement
;
152 int column
= depth
*2 - 1; // iterator column
155 statement
= clay_beta_find(statement
, beta
);
157 return CLAY_ERROR_BETA_NOT_FOUND
;
159 while (statement
!= NULL
) {
160 scattering
= statement
->scattering
;
161 while (scattering
!= NULL
) {
162 precision
= scattering
->precision
;
163 CLAY_BETA_CHECK_DEPTH(beta
, depth
, scattering
);
164 if (clay_beta_check_relation(scattering
, beta
)) {
165 for (i
= 0; i
< scattering
->nb_rows
; i
++) {
166 osl_int_oppose(precision
,
167 &scattering
->m
[i
][column
+ 1],
168 scattering
->m
[i
][column
+ 1]);
171 scattering
= scattering
->next
;
173 statement
= statement
->next
;
181 * clay_interchange function:
182 * On each statement which belongs to the `beta', the loops that match the
183 * `depth_1'th and the `depth_2' are interchanged
184 * /!\ If you want to interchange 2 loops, you must give the inner beta loop
185 * and not the outer !
186 * \param[in,out] scop
187 * \param[in] beta Beta vector (inner loop or statement)
188 * \param[in] depth_1 >= 1
189 * \param[in] depth_2 >= 1
190 * \param[in] pretty 1 or 0 : update the scatnames
194 int clay_interchange(osl_scop_p scop
,
196 unsigned int depth_1
, unsigned int depth_2
,
198 clay_options_p options
) {
199 // Swap the two output_dims columns.
202 return CLAY_ERROR_BETA_EMPTY
;
203 if (depth_1
<= 0 || depth_2
<= 0)
204 return CLAY_ERROR_DEPTH_OVERFLOW
;
206 osl_statement_p statement
= scop
->statement
;
207 osl_relation_p scattering
;
209 const int column_1
= depth_1
*2 - 1; // iterator column
210 const int column_2
= depth_2
*2 - 1;
214 statement
= clay_beta_find(statement
, beta
);
216 return CLAY_ERROR_BETA_NOT_FOUND
;
218 scattering
= statement
->scattering
;
219 while (scattering
!= NULL
) {
220 if (scattering
->nb_output_dims
<= 1)
221 return CLAY_ERROR_DEPTH_OVERFLOW
;
222 CLAY_BETA_CHECK_DEPTH(beta
, depth_1
, scattering
);
223 CLAY_BETA_CHECK_DEPTH(beta
, depth_2
, scattering
);
224 scattering
= scattering
->next
;
227 // Swapping with itself doesn't affect the scattering.
228 if (depth_1
== depth_2
)
231 precision
= statement
->scattering
->precision
;
232 while (statement
!= NULL
) {
233 scattering
= statement
->scattering
;
234 while (scattering
!= NULL
) {
235 if (clay_beta_check_relation(scattering
, beta
)) {
236 // Swap the two columns.
237 matrix
= scattering
->m
;
238 for (i
= 0 ; i
< scattering
->nb_rows
; i
++)
239 osl_int_swap(precision
,
240 &matrix
[i
][column_1
+1],
241 &matrix
[i
][column_2
+1]);
243 scattering
= scattering
->next
;
245 statement
= statement
->next
;
248 // swap the two variables
250 osl_scatnames_p scat
;
252 scat
= osl_generic_lookup(scop
->extension
, OSL_URI_SCATNAMES
);
256 for (ii
= 0 ; names
->string
[ii
] ; ii
++)
259 int c1
= depth_1
* 2 - 1;
260 int c2
= depth_2
* 2 - 1;
262 if (c1
< ii
&& c2
< ii
) {
263 char *tmp
= names
->string
[c1
];
264 names
->string
[c1
] = names
->string
[c2
];
265 names
->string
[c2
] = tmp
;
274 * clay_split function:
275 * Split the loop in two parts at the `depth'th level from the statement
276 * \param[in,out] scop
277 * \param[in] beta Beta vector
278 * \param[in] depth >= 1
282 int clay_split(osl_scop_p scop
, clay_array_p beta
, unsigned int depth
,
283 clay_options_p options
) {
286 * Add one on the beta at the `depth'th level.
290 return CLAY_ERROR_BETA_EMPTY
;
291 if (beta
->size
<= 1 || depth
<= 0 || depth
>= beta
->size
)
292 return CLAY_ERROR_DEPTH_OVERFLOW
;
294 osl_statement_p statement
= scop
->statement
;
295 statement
= clay_beta_find(statement
, beta
);
297 return CLAY_ERROR_BETA_NOT_FOUND
;
299 clay_beta_shift_after(scop
->statement
, beta
, depth
);
301 if (options
&& options
->normalize
)
302 clay_beta_normalize(scop
);
309 * clay_fuse function:
310 * Fuse loop with the first loop after
311 * \param[in,out] scop
312 * \param[in] beta_loop Loop beta vector
316 int clay_fuse(osl_scop_p scop
, clay_array_p beta_loop
,
317 clay_options_p options
) {
320 * Set the same beta (only at the level of the beta_loop) on the next loop.
323 if (beta_loop
->size
== 0)
324 return CLAY_ERROR_BETA_EMPTY
;
326 osl_relation_p scattering
;
327 osl_statement_p statement
;
328 clay_array_p beta_max
;
329 clay_array_p beta_next
;
331 const int depth
= beta_loop
->size
;
332 const int column
= beta_loop
->size
*2; // alpha column
335 statement
= clay_beta_find(scop
->statement
, beta_loop
);
337 return CLAY_ERROR_BETA_NOT_FOUND
;
339 scattering
= statement
->scattering
;
340 while (scattering
!= NULL
) {
341 if (clay_beta_check_relation(scattering
, beta_loop
)) {
342 CLAY_BETA_IS_LOOP(beta_loop
, scattering
);
344 scattering
= scattering
->next
;
347 precision
= statement
->scattering
->precision
;
349 beta_max
= clay_beta_max(statement
, beta_loop
);
350 beta_next
= clay_beta_next_part(scop
->statement
, beta_loop
);
352 if (beta_next
!= NULL
) {
353 beta_next
->size
= depth
;
354 statement
= scop
->statement
;
355 while (statement
!= NULL
) {
356 scattering
= statement
->scattering
;
357 while (scattering
!= NULL
) {
358 if (clay_beta_check_relation(scattering
, beta_next
)) {
359 if (column
< scattering
->nb_output_dims
) {
360 // Set the loop level
361 row
= clay_util_relation_get_line(scattering
, column
-2);
362 osl_int_set_si(precision
,
363 &scattering
->m
[row
][scattering
->nb_columns
-1],
364 beta_loop
->data
[depth
-1]);
366 // Reorder the statement
367 row
= clay_util_relation_get_line(scattering
, column
);
368 osl_int_add_si(precision
,
369 &scattering
->m
[row
][scattering
->nb_columns
-1],
370 scattering
->m
[row
][scattering
->nb_columns
-1],
371 beta_max
->data
[depth
]+1);
374 scattering
= scattering
->next
;
376 statement
= statement
->next
;
378 clay_array_free(beta_next
);
381 clay_array_free(beta_max
);
383 if (options
&& options
->normalize
)
384 clay_beta_normalize(scop
);
391 * Skew the loop, i.e. add an outer iterator of the loop nest multiplied by the
392 * coefficient to the current loop iterator. Use the beta-prefix length to
393 * identify the "target" iteartor, use #depth to identify the outer loop
394 * ("source") iterator.
395 * (i, j) -> (i, j+i*coeff).
396 * Skew applies only to loops by definition. To perform the skewing
397 * transformation for a statement, split it and then do the skewing, or call
399 * \param[in,out] scop
400 * \param[in] beta Beta-prefix that identifies the loop to skew
401 * \param[in] depth Depth of the "source" loop iterator (between 1 and length of beta-prefix)
402 * \param[in] coeff Coefficient for the "source" iterator.
403 * \param[in] options Clay options
406 int clay_skew(osl_scop_p scop
,
407 clay_array_p beta
, unsigned int depth
, unsigned int coeff
,
408 clay_options_p options
) {
411 * This is a special case of shifting, where params and constant
414 * Call clay_shift with the same beta, depth = beta_size and a vector set up
415 * so that it corresponds to 1*i + coeff*j shifting, i.e. it contains the
416 * value coeff at depth-s index and 1 at the end, all the other elements
419 * Individual statements cannot be skewed because we do not have information.
420 * The length of the beta-prefix is used to indentify the loop to skew, which
421 * would require an addiitonal parameter in case of beta-vector for
426 return CLAY_ERROR_BETA_EMPTY
;
427 if (depth
<= 0 || depth
>= beta
->size
)
428 return CLAY_ERROR_DEPTH_OVERFLOW
;
430 return CLAY_ERROR_WRONG_COEFF
;
434 osl_statement_p statement
;
435 osl_relation_p scattering
;
437 // Check if beta matches only loops.
438 statement
= clay_beta_find(scop
->statement
, beta
);
439 while (statement
!= NULL
) {
440 for (scattering
= statement
->scattering
;
442 scattering
= scattering
->next
) {
443 if (!clay_beta_check_relation(scattering
, beta
))
445 CLAY_BETA_IS_LOOP(beta
, scattering
);
447 statement
= statement
->next
;
451 vector
= clay_list_malloc();
454 clay_list_add(vector
, clay_array_malloc());
455 clay_list_add(vector
, clay_array_malloc());
456 clay_list_add(vector
, clay_array_malloc());
459 for (i
= 0 ; i
< depth
-1 ; i
++)
460 clay_array_add(vector
->data
[0], 0);
461 clay_array_add(vector
->data
[0], coeff
);
462 for (i
= depth
+ 1; i
< beta
->size
; i
++)
463 clay_array_add(vector
->data
[0], 0);
464 clay_array_add(vector
->data
[0], 1);
466 ret
= clay_shift(scop
, beta
, beta
->size
, vector
, options
);
467 clay_list_free(vector
);
475 * Split the loop (or statement) depending of an inequation.
476 * Warning: in the output part, don't put the alpha columns
477 * example: if the output dims are : 0 i 0 j 0, just do Ni, Nj
478 * \param[in,out] scop
479 * \param[in] beta_loop Beta loop
480 * \param[in] inequation array {(([output, ...],) [param, ...],) [const]}
481 * \param[out] beta_max If NULL, the beta_max will not be returned.
482 * If function terminated successfully, the last
483 * beta which has the prefix beta_loop, NULL
488 int clay_iss(osl_scop_p scop
,
489 clay_array_p beta_loop
, clay_list_p inequ
,
490 clay_array_p
*ret_beta_max
,
491 clay_options_p options
) {
494 * Add the inequality to each scattering relation union that corresponds to
498 if (beta_loop
->size
== 0)
499 return CLAY_ERROR_BETA_EMPTY
;
501 return CLAY_ERROR_INEQU
;
503 osl_statement_p statement
;
504 osl_relation_p scattering
;
505 clay_array_p beta_max
;
506 int nb_output_dims
, nb_parameters
;
507 int order
; // new loop order for the clones
509 // search a statement
510 statement
= clay_beta_find(scop
->statement
, beta_loop
);
512 return CLAY_ERROR_BETA_NOT_FOUND
;
513 if (statement
->scattering
->nb_input_dims
== 0)
514 return CLAY_ERROR_BETA_NOT_IN_A_LOOP
;
516 // decompose the inequation
517 nb_parameters
= scop
->context
->nb_parameters
;
518 nb_output_dims
= statement
->scattering
->nb_output_dims
;
520 if (inequ
->size
== 3) {
522 clay_util_array_output_dims_pad_zero(inequ
->data
[0]);
524 if (inequ
->data
[0]->size
> nb_output_dims
||
525 inequ
->data
[1]->size
> nb_parameters
||
526 inequ
->data
[2]->size
> 1)
527 return CLAY_ERROR_INEQU
;
529 } else if (inequ
->size
== 2) {
530 if (inequ
->data
[0]->size
> nb_parameters
||
531 inequ
->data
[1]->size
> 1)
532 return CLAY_ERROR_INEQU
;
534 } else if (inequ
->size
== 1) {
535 if (inequ
->data
[0]->size
> 1)
536 return CLAY_ERROR_INEQU
;
539 // set the beginning of 'order'
540 beta_max
= clay_beta_max(statement
, beta_loop
);
541 order
= beta_max
->data
[beta_loop
->size
] + 1; // beta_loop->size is in range
542 // since loop contains statements
543 if (ret_beta_max
!= NULL
) {
544 *ret_beta_max
= beta_max
;
547 // ensure ret_beta_max is set up before returning success
548 if (inequ
->size
== 0) {
549 clay_array_free(beta_max
);
553 // insert the inequation on each statements
554 while (statement
!= NULL
) {
555 if (clay_beta_check(statement
, beta_loop
)) {
557 osl_relation_p last
= statement
->scattering
;
558 while (last
->next
!= NULL
) {
561 last
->next
= osl_relation_clone(statement
->scattering
);
563 scattering
= statement
->scattering
;
564 while (last
!= NULL
) {
565 CLAY_BETA_IS_LOOP(beta_loop
, scattering
);
566 clay_util_relation_insert_inequation(scattering
, inequ
);
567 clay_util_relation_insert_inequation(last
, inequ
);
568 clay_util_relation_negate_row(last
, last
->nb_rows
- 1);
570 clay_array_p new_beta
= clay_array_clone(beta_max
);
571 new_beta
->data
[beta_loop
->size
]++; //# ?= order
572 clay_util_scattering_update_beta(scattering
, new_beta
);
573 clay_array_free(new_beta
);
576 scattering
= scattering
->next
;
579 statement
= statement
->next
;
582 if (options
&& options
->normalize
)
583 clay_beta_normalize(scop
);
590 * clay_stripmine function:
591 * Decompose a single loop into two nested loop
592 * \param[in,out] scop
593 * \param[in] beta Beta vector (loop or statement)
594 * \param[in] size Block size of the inner loop
595 * \param[in] pretty If true, clay will keep the variables name
599 int clay_stripmine(osl_scop_p scop
, clay_array_p beta
,
600 unsigned int depth
, unsigned int size
,
601 int pretty
, clay_options_p options
) {
604 * Add two inequality for the stripmining.
605 * The new dependance with the loop is done on an output_dim.
606 * If pretty is true, we add for each statements (not only the beta) two
607 * output_dims (one for the iterator and one for the 2*n+1).
611 return CLAY_ERROR_BETA_EMPTY
;
613 return CLAY_ERROR_WRONG_BLOCK_SIZE
;
615 return CLAY_ERROR_DEPTH_OVERFLOW
;
617 osl_relation_p scattering
;
618 osl_statement_p statement
= scop
->statement
;
619 osl_scatnames_p scat
;
621 int column
= (depth
-1)*2; // alpha column
626 char buffer
[OSL_MAX_STRING
];
630 statement
= clay_beta_find(statement
, beta
);
632 return CLAY_ERROR_BETA_NOT_FOUND
;
633 if (statement
->scattering
->nb_output_dims
< 3)
634 return CLAY_ERROR_BETA_NOT_IN_A_LOOP
;
636 precision
= statement
->scattering
->precision
;
638 statement
= scop
->statement
; // TODO optimization...
640 while (statement
!= NULL
) {
641 scattering
= statement
->scattering
;
642 while (scattering
!= NULL
) {
643 CLAY_BETA_CHECK_DEPTH(beta
, depth
, scattering
);
644 if (clay_beta_check_relation(scattering
, beta
)) {
646 // set the strip mine
647 row
= clay_util_relation_get_line(scattering
, column
);
649 osl_relation_insert_blank_column(scattering
, column
+1);
650 osl_relation_insert_blank_column(scattering
, column
+1);
652 osl_relation_insert_blank_row(scattering
, column
);
653 osl_relation_insert_blank_row(scattering
, column
);
654 osl_relation_insert_blank_row(scattering
, column
);
657 osl_int_set_si(precision
, &scattering
->m
[row
+0][column
+1], -1);
658 osl_int_set_si(precision
, &scattering
->m
[row
+1][column
+2], -size
);
659 osl_int_set_si(precision
, &scattering
->m
[row
+2][column
+2], size
);
660 osl_int_set_si(precision
,
661 &scattering
->m
[row
+2][scattering
->nb_columns
-1],
665 osl_int_set_si(precision
, &scattering
->m
[row
+1][0], 1);
666 osl_int_set_si(precision
, &scattering
->m
[row
+2][0], 1);
668 // iterator dependance
669 osl_int_set_si(precision
, &scattering
->m
[row
+1][column
+4], 1);
670 osl_int_set_si(precision
, &scattering
->m
[row
+2][column
+4], -1);
672 scattering
->nb_output_dims
+= 2;
675 row_next
= clay_util_relation_get_line(scattering
, column
+2);
676 osl_int_assign(precision
,
677 &scattering
->m
[row
][scattering
->nb_columns
-1],
678 scattering
->m
[row_next
][scattering
->nb_columns
-1]);
680 osl_int_set_si(precision
,
681 &scattering
->m
[row_next
][scattering
->nb_columns
-1],
684 } else if (pretty
&& column
< scattering
->nb_output_dims
) {
685 // add 2 empty dimensions
686 row
= clay_util_relation_get_line(scattering
, column
);
688 osl_relation_insert_blank_column(scattering
, column
+1);
689 osl_relation_insert_blank_column(scattering
, column
+1);
691 osl_relation_insert_blank_row(scattering
, column
);
692 osl_relation_insert_blank_row(scattering
, column
);
695 osl_int_set_si(precision
, &scattering
->m
[row
][column
+1], -1);
696 osl_int_set_si(precision
, &scattering
->m
[row
+1][column
+2], -1);
698 scattering
->nb_output_dims
+= 2;
701 row_next
= clay_util_relation_get_line(scattering
, column
+2);
702 osl_int_assign(precision
,
703 &scattering
->m
[row
][scattering
->nb_columns
-1],
704 scattering
->m
[row_next
][scattering
->nb_columns
-1]);
706 osl_int_set_si(precision
,
707 &scattering
->m
[row_next
][scattering
->nb_columns
-1],
711 scattering
= scattering
->next
;
713 statement
= statement
->next
;
716 // get the list of scatnames
717 scat
= osl_generic_lookup(scop
->extension
, OSL_URI_SCATNAMES
);
720 // generate iterator variable name
723 sprintf(buffer
, "__%s%s%d", names
->string
[column
+1],
724 names
->string
[column
+1], i
);
726 } while (clay_util_scatnames_exists(scat
, buffer
));
727 new_var_iter
= strdup(buffer
);
729 // generate beta variable name
732 sprintf(buffer
, "__b%d", i
);
734 } while (clay_util_scatnames_exists(scat
, buffer
));
735 new_var_beta
= strdup(buffer
);
737 // insert the two variables
738 nb_strings
= osl_strings_size(names
) + 2;
739 osl_strings_p newnames
= osl_strings_malloc();
740 CLAY_malloc(newnames
->string
, char**, sizeof(char**) * (nb_strings
+ 1));
742 for (i
= 0 ; i
< column
; i
++)
743 newnames
->string
[i
] = names
->string
[i
];
745 newnames
->string
[i
] = new_var_beta
;
746 newnames
->string
[i
+1] = new_var_iter
;
748 for (i
= i
+2 ; i
< nb_strings
; i
++)
749 newnames
->string
[i
] = names
->string
[i
-2];
751 newnames
->string
[i
] = NULL
; // end of the list
753 // replace the scatnames
756 scat
->names
= newnames
;
758 osl_scop_print(stderr
, scop
);
759 if (options
&& options
->normalize
)
760 clay_beta_normalize(scop
);
766 /** clay_unroll function: Unroll a loop \param[in,out] scop \param[in]
767 * beta_loop Loop beta vector \param[in] factor > 0 \param[in]
768 * setepilog if true the epilog will be added \param[in] options \return
771 int clay_unroll(osl_scop_p scop
, clay_array_p beta_loop
, unsigned int factor
,
772 int setepilog
, clay_options_p options
) {
775 * Clone statements in the beta_loop, and recreate the body.
776 * Generate an epilog where the lower bound was removed.
779 if (beta_loop
->size
== 0)
780 return CLAY_ERROR_BETA_EMPTY
;
782 return CLAY_ERROR_WRONG_FACTOR
;
786 osl_relation_p scattering
;
787 osl_relation_p domain
;
788 osl_relation_p epilog_domain
= NULL
;
789 osl_statement_p statement
;
790 osl_statement_p newstatement
;
791 osl_statement_p original_stmt
;
792 osl_statement_p epilog_stmt
;
793 clay_array_p beta_max
;
794 int column
= beta_loop
->size
*2;
799 int max
; // last value of beta_max
801 int order_epilog
= 0; // order juste after the beta_loop
802 int current_stmt
= 0; // counter of statements
806 osl_body_p body
= NULL
;
807 osl_extbody_p ext_body
= NULL
;
808 osl_body_p newbody
= NULL
;
809 osl_extbody_p newextbody
= NULL
;
810 osl_body_p tmpbody
= NULL
;
811 osl_generic_p gen
= NULL
;
817 char substitution
[] = "@0@";
819 int iterator_index
= beta_loop
->size
-1;
824 statement
= clay_beta_find(scop
->statement
, beta_loop
);
826 return CLAY_ERROR_BETA_NOT_FOUND
;
828 precision
= statement
->scattering
->precision
;
830 // alloc an array of string, wich will contain the current iterator and NULL
831 // used for osl_util_identifier_substitution with only one variable
832 CLAY_malloc(iterator
, char**, sizeof(char*)*2);
835 // infos used to reorder cloned statements
836 nb_stmts
= clay_beta_nb_parts(statement
, beta_loop
);
837 beta_max
= clay_beta_max(statement
, beta_loop
);
838 max
= beta_max
->data
[beta_max
->size
-1];
839 clay_array_free(beta_max
);
842 // shift to let the place for the epilog loop
843 clay_beta_shift_after(scop
->statement
, beta_loop
, beta_loop
->size
);
844 order_epilog
= beta_loop
->data
[beta_loop
->size
-1] + 1;
847 while (statement
!= NULL
) {
848 scattering
= statement
->scattering
;
850 if (clay_beta_check(statement
, beta_loop
)) {
852 // create the body with symbols for the substitution
853 original_stmt
= statement
;
855 ext_body
= osl_generic_lookup(statement
->extension
,
858 body
= ext_body
->body
;
861 body
= (osl_body_p
) osl_generic_lookup(statement
->extension
,
865 CLAY_error("Missing statement body\n");
867 expression
= body
->expression
->string
[0];
868 iterator
[0] = (char*) body
->iterators
->string
[iterator_index
];
869 iterator_size
= strlen(iterator
[0]);
870 substitued
= osl_util_identifier_substitution(expression
, iterator
);
872 CLAY_malloc(replacement
, char*, 1 + iterator_size
+ 1 + 16 + 1 + 1);
875 // Clone the statment with only those parts of scattering relation
876 // union, that match the given beta, and modify these parts
878 epilog_stmt
= osl_statement_malloc();
879 epilog_stmt
->domain
= osl_relation_clone(original_stmt
->domain
);
880 epilog_stmt
->access
= osl_relation_list_clone(original_stmt
->access
);
881 epilog_stmt
->extension
= osl_generic_clone(original_stmt
->extension
);
882 epilog_stmt
->scattering
= NULL
;
883 epilog_stmt
->next
= NULL
;
884 osl_relation_p scat
= original_stmt
->scattering
;
885 osl_relation_p ptr
= NULL
;
886 while (scat
!= NULL
) {
887 if (clay_beta_check_relation(scat
, beta_loop
)) {
888 CLAY_BETA_IS_LOOP(beta_loop
, scat
);
890 epilog_stmt
->scattering
= osl_relation_nclone(scat
, 1);
891 ptr
= epilog_stmt
->scattering
;
893 ptr
->next
= osl_relation_nclone(scat
, 1);
897 row
= clay_util_relation_get_line(scat
, column
- 2);
898 osl_int_set_si(precision
,
899 &ptr
->m
[row
][ptr
->nb_columns
-1],
902 //# AZ: fixing up post-iss changes to scattering union, that would be
903 //translated into loop boundary changes, namely removing presumably
904 //lower bound (FIXME!) conditions on the alpha dimension corresponding
905 //to the unrolled iterator. Other possible solution: take the lower
906 //bound from unrolled statements, add +1 and transformed to the lower
908 osl_relation_print(stderr
, ptr
);
909 for (i
= 0; i
< ptr
->nb_rows
; i
++) {
910 if (osl_int_pos(precision
, ptr
->m
[i
][(iterator_index
+1)*2])) {
911 osl_int_set_si(precision
, &ptr
->m
[i
][(iterator_index
+1)*2], 0);
913 int j
, to_remove
= 1;
914 for (j
= 0; j
< ptr
->nb_output_dims
; j
++) {
915 if (!osl_int_zero(precision
, ptr
->m
[i
][j
+1])) {
921 osl_relation_remove_row(ptr
, i
);
929 // the order is not important in the statements list
930 epilog_stmt
->next
= statement
->next
;
931 statement
->next
= epilog_stmt
;
932 statement
= epilog_stmt
;
935 // modify the matrix domain
936 domain
= original_stmt
->domain
;
939 epilog_domain
= epilog_stmt
->domain
;
942 while (domain
!= NULL
) {
944 for (i
= domain
->nb_rows
-1 ; i
>= 0 ; i
--) {
945 if (!osl_int_zero(precision
, domain
->m
[i
][0])) {
947 // remove the lower bound on the epilog statement
949 osl_int_pos(precision
, domain
->m
[i
][iterator_index
+1])) {
950 osl_relation_remove_row(epilog_domain
, i
);
952 // remove the upper bound on the original statement
953 if (osl_int_neg(precision
, domain
->m
[i
][iterator_index
+1])) {
954 osl_int_add_si(precision
,
955 &domain
->m
[i
][domain
->nb_columns
-1],
956 domain
->m
[i
][domain
->nb_columns
-1],
962 // Don't add local dimension to the domain since it may affect other
963 // parts of the statement scattered with different betas.
965 domain
= domain
->next
;
968 epilog_domain
= epilog_domain
->next
;
971 // clone factor-1 times the original statement
973 // FIXME: here scattering was pointing to the scattering of epilog (probably bug)
974 // FIXME: I don't see much sense in this magic: it sets current_stmt to 1
975 // (instead of 0) unless the last value of the beta-vector for epilog (if
976 // requested) or original statement was -1. Leave it as is.
977 row
= clay_util_relation_get_line(original_stmt
->scattering
, column
);
978 current_level
= osl_int_get_si(scattering
->precision
,
979 scattering
->m
[row
][scattering
->nb_columns
-1]);
980 if (last_level
!= current_level
) {
982 last_level
= current_level
;
985 // Update those scattering relation union
986 scattering
= original_stmt
->scattering
;
987 while (scattering
!= NULL
) {
988 if (clay_beta_check_relation(scattering
, beta_loop
)) {
989 // Insert local dimension.
990 osl_relation_insert_blank_column(scattering
, scattering
->nb_output_dims
+ scattering
->nb_input_dims
+ 1);
991 (scattering
->nb_local_dims
)++;
992 osl_relation_insert_blank_row(scattering
, scattering
->nb_rows
);
993 osl_int_set_si(scattering
->precision
,
994 &scattering
->m
[scattering
->nb_rows
- 1][(iterator_index
+1)*2],
996 osl_int_set_si(scattering
->precision
,
997 &scattering
->m
[scattering
->nb_rows
- 1][scattering
->nb_output_dims
+ scattering
->nb_input_dims
+ 1],
1000 scattering
= scattering
->next
;
1003 for (i
= 0 ; i
< factor
-1 ; i
++) {
1004 // Clone the expression with only matching parts.
1005 newstatement
= osl_statement_malloc();
1006 newstatement
->domain
= osl_relation_clone(original_stmt
->domain
);
1007 newstatement
->access
= osl_relation_list_clone(original_stmt
->access
);
1008 newstatement
->extension
= osl_generic_clone(original_stmt
->extension
);
1009 newstatement
->next
= NULL
;
1010 newstatement
->scattering
= NULL
;
1011 osl_relation_p ptr
= NULL
;
1012 osl_relation_p scat
= original_stmt
->scattering
;
1013 while (scat
!= NULL
) {
1014 if (clay_beta_check_relation(scat
, beta_loop
)) {
1016 newstatement
->scattering
= osl_relation_nclone(scat
, 1);
1017 ptr
= newstatement
->scattering
;
1019 ptr
->next
= osl_relation_nclone(scat
, 1);
1026 scattering
= newstatement
->scattering
;
1028 while (scattering
!= NULL
) {
1029 order
= current_stmt
+ max
+ nb_stmts
*i
;
1030 osl_int_set_si(precision
,
1031 &scattering
->m
[row
][scattering
->nb_columns
-1],
1033 scattering
= scattering
->next
;
1037 sprintf(replacement
, "(%s+%d)", iterator
[0], i
+1);
1038 newexpression
= clay_util_string_replace(substitution
, replacement
,
1042 newextbody
= osl_generic_lookup(newstatement
->extension
,
1044 newbody
= newextbody
->body
;
1047 newbody
= osl_generic_lookup(newstatement
->extension
, OSL_URI_BODY
);
1050 free(newbody
->expression
->string
[0]);
1051 newbody
->expression
->string
[0] = newexpression
;
1053 // synchronize extbody and body (if both are different)
1055 tmpbody
= osl_generic_lookup(newstatement
->extension
, OSL_URI_BODY
);
1057 osl_generic_remove(&newstatement
->extension
, OSL_URI_BODY
);
1058 tmpbody
= osl_body_clone(newbody
);
1059 gen
= osl_generic_shell(tmpbody
, osl_body_interface());
1060 osl_generic_add(&newstatement
->extension
, gen
);
1064 // the order is not important in the statements list
1065 newstatement
->next
= statement
->next
;
1066 statement
->next
= newstatement
;
1067 statement
= newstatement
;
1072 statement
= statement
->next
;
1076 if (options
&& options
->normalize
)
1077 clay_beta_normalize(scop
);
1079 return CLAY_SUCCESS
;
1084 * clay_tile function:
1085 * Apply a stripmine then an interchange.
1086 * The stripmine is at the `depth'th level. Next interchange the level `depth'
1088 * \param[in,out] scop
1089 * \param[in] beta Beta vector
1090 * \param[in] depth >=1
1091 * \param[in] size >=1
1092 * \param[in] depth_outer >=1
1093 * \param[in] pretty See stripmine
1094 * \param[in] options
1097 int clay_tile(osl_scop_p scop
,
1098 clay_array_p beta
, unsigned int depth
, unsigned int depth_outer
,
1099 unsigned int size
, int pretty
, clay_options_p options
) {
1102 * stripmine + interchange
1105 if (beta
->size
== 0)
1106 return CLAY_ERROR_BETA_EMPTY
;
1108 return CLAY_ERROR_WRONG_BLOCK_SIZE
;
1109 if (depth
<= 0 || depth_outer
<= 0)
1110 return CLAY_ERROR_DEPTH_OVERFLOW
;
1111 if (depth_outer
> depth
)
1112 return CLAY_ERROR_DEPTH_OUTER
;
1115 ret
= clay_stripmine(scop
, beta
, depth
, size
, pretty
, options
);
1117 if (ret
== CLAY_SUCCESS
) {
1118 ret
= clay_interchange(scop
, beta
, depth
, depth_outer
, pretty
, options
);
1126 * clay_shift function:
1127 * Shift the iteration domain
1128 * Warning: in the output part, don't put the alpha columns
1129 * example: if the output dims are : 0 i 0 j 0, just do Ni, Nj
1130 * \param[in,out] scop
1131 * \param[in] beta Beta vector (loop or statement)
1132 * \param[in] depth >=1
1133 * \param[in] vector {(([output, ...],) [param, ...],) [const]}
1134 * \param[in] options
1137 int clay_shift(osl_scop_p scop
,
1138 clay_array_p beta
, unsigned int depth
, clay_list_p vector
,
1139 clay_options_p options
) {
1142 * Add a vector on each statements.
1145 if (beta
->size
== 0)
1146 return CLAY_ERROR_BETA_EMPTY
;
1147 if (vector
->size
== 0)
1148 return CLAY_ERROR_VECTOR_EMPTY
;
1150 return CLAY_ERROR_DEPTH_OVERFLOW
;
1151 if (vector
->size
> 3)
1152 return CLAY_ERROR_VECTOR
;
1153 if (vector
->size
== 0)
1154 return CLAY_SUCCESS
;
1156 osl_statement_p statement
;
1157 osl_relation_p scattering
;
1158 const int column
= depth
*2 - 1; // iterator column
1159 int nb_parameters
, nb_output_dims
;
1161 statement
= clay_beta_find(scop
->statement
, beta
);
1163 return CLAY_ERROR_BETA_NOT_FOUND
;
1165 // decompose the vector
1166 nb_parameters
= scop
->context
->nb_parameters
;
1167 nb_output_dims
= statement
->scattering
->nb_output_dims
;
1169 if (vector
->size
== 3) {
1171 clay_util_array_output_dims_pad_zero(vector
->data
[0]);
1173 if (vector
->data
[0]->size
> nb_output_dims
||
1174 vector
->data
[1]->size
> nb_parameters
||
1175 vector
->data
[2]->size
> 1)
1176 return CLAY_ERROR_VECTOR
;
1178 } else if (vector
->size
== 2) {
1179 if (vector
->data
[0]->size
> nb_parameters
||
1180 vector
->data
[1]->size
> 1)
1181 return CLAY_ERROR_VECTOR
;
1183 } else if (vector
->size
== 1) {
1184 if (vector
->data
[0]->size
> 1)
1185 return CLAY_ERROR_VECTOR
;
1188 // add the vector for each statements
1189 while (statement
!= NULL
) {
1190 scattering
= statement
->scattering
;
1191 while (scattering
!= NULL
) {
1192 if (clay_beta_check_relation(scattering
, beta
)) {
1193 CLAY_BETA_CHECK_DEPTH(beta
, depth
, scattering
);
1194 if (scattering
->nb_input_dims
== 0) {
1195 return CLAY_ERROR_BETA_NOT_IN_A_LOOP
;
1198 clay_util_relation_set_vector(scattering
, vector
, column
);
1200 scattering
= scattering
->next
;
1202 statement
= statement
->next
;
1205 if (options
&& options
->normalize
)
1206 clay_beta_normalize(scop
);
1208 return CLAY_SUCCESS
;
1213 * clay_peel function:
1214 * Removes the first or last iteration of the loop into separate code.
1215 * This is equivalent to an iss (without output dims) and a spliting
1216 * \param[in,out] scop
1217 * \param[in] beta_loop Loop beta vector
1218 * \param[in] peeling list { ([param, ...],) [const] }
1219 * \param[in] options
1222 int clay_peel(osl_scop_p scop
,
1223 clay_array_p beta_loop
, clay_list_p peeling
,
1224 clay_options_p options
) {
1226 if (beta_loop
->size
== 0)
1227 return CLAY_ERROR_BETA_EMPTY
;
1228 if (peeling
->size
>= 3)
1229 return CLAY_ERROR_INEQU
;
1230 if (peeling
->size
== 0)
1231 return CLAY_SUCCESS
;
1233 clay_array_p arr_dims
, beta_max
;
1234 clay_list_p new_peeling
;
1237 // create output dims
1238 arr_dims
= clay_array_malloc();
1239 for (i
= 0 ; i
< beta_loop
->size
-1 ; i
++)
1240 clay_array_add(arr_dims
, 0);
1241 clay_array_add(arr_dims
, 1);
1243 // create new peeling list
1244 new_peeling
= clay_list_malloc();
1245 clay_list_add(new_peeling
, arr_dims
);
1246 if (peeling
->size
== 2) {
1247 clay_list_add(new_peeling
, peeling
->data
[0]);
1248 clay_list_add(new_peeling
, peeling
->data
[1]);
1250 clay_list_add(new_peeling
, clay_array_malloc()); // empty params
1251 clay_list_add(new_peeling
, peeling
->data
[0]);
1254 // index-set spliting
1255 ret
= clay_iss(scop
, beta_loop
, new_peeling
, &beta_max
, options
);
1257 // we don't free ALL with clay_list_free, because there are arrays in
1258 // common with `peeling'
1259 clay_array_free(arr_dims
);
1260 if (peeling
->size
== 1)
1261 clay_array_free(new_peeling
->data
[1]);
1262 free(new_peeling
->data
);
1265 if (ret
== CLAY_SUCCESS
) {
1267 clay_beta_shift_after(scop
->statement
, beta_max
,
1269 clay_array_free(beta_max
);
1272 if (options
&& options
->normalize
)
1273 clay_beta_normalize(scop
);
1280 * clay_context function:
1281 * Add a line to the context
1282 * \param[in,out] scop
1283 * \param[in] vector [param1, param2, ..., 1]
1284 * \param[in] options
1287 int clay_context(osl_scop_p scop
, clay_array_p vector
,
1288 clay_options_p options
) {
1291 * Add a new line in the context matrix.
1294 if (vector
->size
< 2)
1295 return CLAY_ERROR_VECTOR
;
1296 if (scop
->context
->nb_parameters
!= vector
->size
-2)
1297 return CLAY_ERROR_VECTOR
;
1299 osl_relation_p context
;
1304 context
= scop
->context
;
1305 precision
= context
->precision
;
1306 row
= context
->nb_rows
;
1307 osl_relation_insert_blank_row(context
, row
);
1309 osl_int_set_si(precision
,
1310 &context
->m
[row
][0],
1313 j
= 1 + context
->nb_output_dims
+ context
->nb_input_dims
+
1314 context
->nb_local_dims
;
1315 for (i
= 1 ; i
< vector
->size
; i
++) {
1316 osl_int_set_si(precision
,
1317 &context
->m
[row
][j
],
1322 return CLAY_SUCCESS
;
1326 static int clay_dimreorder_aux(osl_relation_list_p access
,
1328 clay_array_p neworder
= args
;
1329 osl_relation_p a
= access
->elt
;
1331 if (a
->nb_output_dims
-1 != neworder
->size
) {
1332 fprintf(stderr
, "[Clay] Warning: can't reorder dims on this statement: ");
1333 return CLAY_ERROR_REORDER_ARRAY_SIZE
;
1336 osl_relation_p tmp
= osl_relation_nclone(a
, 1);
1339 for (i
= 0 ; i
< neworder
->size
; i
++) {
1340 if (neworder
->data
[i
] < 0 ||
1341 neworder
->data
[i
] >= a
->nb_output_dims
-1)
1342 return CLAY_ERROR_REORDER_OVERFLOW_VALUE
;
1344 if (i
+2 != neworder
->data
[i
]+2)
1345 for (j
= 0 ; j
< a
->nb_rows
; j
++)
1346 osl_int_assign(a
->precision
,
1348 a
->m
[j
][neworder
->data
[i
]+2]);
1351 osl_relation_free(a
);
1354 return CLAY_SUCCESS
;
1359 * clay_dimreorder function:
1360 * Reorder the dimensions of access_ident
1361 * \param[in,out] scop
1363 * \param[in] access_ident ident of the access array
1364 * \param[in] neworder reorder the dims
1365 * \param[in] options
1368 int clay_dimreorder(osl_scop_p scop
,
1370 unsigned int access_ident
,
1371 clay_array_p neworder
,
1372 clay_options_p options
) {
1375 * Swap the columns in the output dims (access arrays)
1376 * The first output dim is not used ( => access name)
1379 // core of the function : clay_dimreorder_aux
1381 return clay_util_foreach_access(scop
, beta
, access_ident
,
1382 clay_dimreorder_aux
, neworder
, 1);
1386 static int clay_dimprivatize_aux(osl_relation_list_p access
, void *args
) {
1387 int depth
= *((int*) args
);
1388 osl_relation_p a
= access
->elt
;
1390 // check if the iterator is not used
1392 for (i
= 0 ; i
< a
->nb_rows
; i
++) {
1393 if (!osl_int_zero(a
->precision
, a
->m
[i
][a
->nb_output_dims
+ depth
])) {
1395 "[Clay] Warning: can't privatize this statement\n"
1396 " the dim (depth=%d) seems to be already used\n"
1397 " the depth is the depth in the loops\n"
1399 return CLAY_ERROR_CANT_PRIVATIZE
;
1403 a
->nb_output_dims
++;
1405 osl_relation_insert_blank_column(a
, a
->nb_output_dims
);
1406 osl_relation_insert_blank_row(a
, a
->nb_rows
);
1408 osl_int_set_si(a
->precision
,
1409 &a
->m
[a
->nb_rows
-1][a
->nb_output_dims
],
1412 osl_int_set_si(a
->precision
,
1413 &a
->m
[a
->nb_rows
-1][a
->nb_output_dims
+ depth
],
1416 return CLAY_SUCCESS
;
1421 * clay_dimprivatize function:
1422 * Privatize an access
1423 * \param[in,out] scop
1425 * \param[in] access_ident ident of the access array
1427 * \param[in] options
1430 int clay_dimprivatize(osl_scop_p scop
,
1432 unsigned int access_ident
,
1434 clay_options_p options
) {
1437 * Add an output dim on each access which are in the beta vector
1441 return CLAY_ERROR_DEPTH_OVERFLOW
;
1443 osl_statement_p stmt
= clay_beta_find(scop
->statement
, beta
);
1445 return CLAY_ERROR_BETA_NOT_FOUND
;
1447 // FIXME: asserting that depth holds for any scattering
1448 osl_relation_p scattering
= stmt
->scattering
;
1449 for ( ; scattering
!= NULL
; scattering
= scattering
->next
) {
1450 CLAY_BETA_CHECK_DEPTH(beta
, depth
, scattering
);
1453 // core of the function : clay_dimprivatize_aux
1455 return clay_util_foreach_access(scop
, beta
, access_ident
,
1456 clay_dimprivatize_aux
, &depth
, 1);
1460 static int clay_dimcontract_aux(osl_relation_list_p access
, void *args
) {
1461 int depth
= *((int*) args
);
1462 osl_relation_p a
= access
->elt
;
1464 int row
= clay_util_relation_get_line(a
, depth
);
1466 osl_relation_remove_row(a
, row
);
1467 osl_relation_remove_column(a
, depth
+1); // remove output dim
1468 a
->nb_output_dims
--;
1471 return CLAY_SUCCESS
;
1476 * clay_dimcontract function:
1477 * Contract an access (remove a dimension)
1478 * \param[in,out] scop
1480 * \param[in] access_ident ident of the access array
1482 * \param[in] options
1485 int clay_dimcontract(osl_scop_p scop
,
1487 unsigned int access_ident
,
1489 clay_options_p options
) {
1491 * Remove the line/column at the depth level
1495 return CLAY_ERROR_DEPTH_OVERFLOW
;
1497 osl_statement_p stmt
= clay_beta_find(scop
->statement
, beta
);
1499 return CLAY_ERROR_BETA_NOT_FOUND
;
1501 // FIXME: asserting that depth holds for any scattering
1502 osl_relation_p scattering
= stmt
->scattering
;
1503 for ( ; scattering
!= NULL
; scattering
= scattering
->next
) {
1504 CLAY_BETA_CHECK_DEPTH(beta
, depth
, scattering
);
1507 // core of the function : clay_dimcontract_aux
1509 return clay_util_foreach_access(scop
, beta
, access_ident
,
1510 clay_dimcontract_aux
, &depth
, 1);
1515 * clay_add_array function:
1516 * Add a new array in the arrays extensions.
1517 * \param[in,out] scop
1518 * \param[in] name string name
1519 * \param[in] result return the new id
1520 * \param[in] options
1523 int clay_add_array(osl_scop_p scop
,
1526 clay_options_p options
) {
1528 osl_arrays_p arrays
= osl_generic_lookup(scop
->extension
, OSL_URI_ARRAYS
);
1530 return CLAY_ERROR_ARRAYS_EXT_EMPTY
;
1533 int sz
= arrays
->nb_names
;
1536 return CLAY_SUCCESS
;
1538 for (i
= 0 ; i
< sz
; i
++)
1539 if (strcmp(arrays
->names
[i
], name
) == 0)
1540 return CLAY_ERROR_ID_EXISTS
;
1542 int id
= arrays
->id
[0];
1544 for (i
= 1 ; i
< sz
; i
++)
1545 if (arrays
->id
[i
] > id
)
1550 // I don't know why, there is a valgrind warning when I use CLAY_realloc
1551 arrays
->id
= realloc(arrays
->id
, sizeof(int) * (sz
+1));
1552 arrays
->names
= realloc(arrays
->names
, sizeof(char*) * (sz
+1));
1556 arrays
->id
[sz
] = id
;
1557 arrays
->names
[sz
] = strdup(name
);
1561 return CLAY_SUCCESS
;
1565 * clay_get_array_id function:
1566 * Search the array name in the arrays extension
1567 * \param[in,out] scop
1568 * \param[in] name string name
1569 * \param[in] result return the id
1570 * \param[in] options
1573 int clay_get_array_id(osl_scop_p scop
,
1576 clay_options_p options
) {
1578 osl_arrays_p arrays
= osl_generic_lookup(scop
->extension
, OSL_URI_ARRAYS
);
1580 return CLAY_ERROR_ARRAYS_EXT_EMPTY
;
1583 int sz
= arrays
->nb_names
;
1586 for (i
= 0 ; i
< sz
; i
++)
1587 if (strcmp(arrays
->names
[i
], name
) == 0) {
1593 return CLAY_ERROR_ARRAY_NOT_FOUND
;
1597 return CLAY_SUCCESS
;
1601 static int clay_replace_array_aux(osl_relation_list_p access
, void *args
) {
1602 int new_id
= *((int*) args
);
1603 osl_relation_p a
= access
->elt
;
1605 // here row is != -1, because the function aux shouldn't be called
1606 int row
= clay_util_relation_get_line(a
, 0);
1607 osl_int_set_si(a
->precision
, &a
->m
[row
][a
->nb_columns
-1], new_id
);
1609 return CLAY_SUCCESS
;
1613 * clay_replace_array function:
1614 * Replace an ident array by another in each access
1615 * \param[in,out] scop
1616 * \param[in] last_id
1618 * \param[in] options
1621 int clay_replace_array(osl_scop_p scop
,
1622 unsigned int last_id
,
1623 unsigned int new_id
,
1624 clay_options_p options
) {
1626 // core of the function : clay_replace_array_aux
1628 clay_array_p beta
= clay_array_malloc();
1629 int ret
= clay_util_foreach_access(scop
, beta
, last_id
,
1630 clay_replace_array_aux
, &new_id
, 1);
1631 clay_array_free(beta
);
1638 * clay_datacopy function:
1639 * This function will generate a loop to copy all data from the array
1640 * `array_id_original' to a new array `array_id_copy'. Use the function
1641 * add_array to insert a new array in the scop. A domain and a scattering
1642 * is needed to generate the loop to copy the data. They is a copy
1643 * from the domain/scattering of the first statement which corresponds
1644 * to the `beta_get_domain'. There is just a modification on the domain to
1645 * remove unused loops (iter >= 1 && iter <= -1 is set). The orignal id or
1646 * the copy id must be in this beta (in the list of access relation). Genarally
1647 * you will use replace_array before calling datacopy, that's why the
1648 * array_id_copy can be in the scop. The first access relation which is found
1649 * will be used to generate an access for the original id and the copy id.
1650 * \param[in,out] scop
1651 * \param[in] array_id_copy new variable
1652 * \param[in] array_id_original
1653 * \param[in] beta the loop is insert after the beta
1654 * \param[in] beta_get_domain domain/scattering are copied from this beta
1655 * the original or copy id must be in the list of
1656 * access of this beta
1657 * \param[in] options
1660 int clay_datacopy(osl_scop_p scop
,
1661 unsigned int array_id_copy
,
1662 unsigned int array_id_original
,
1663 clay_array_p beta_insert
,
1665 clay_array_p beta_get_domain
,
1666 clay_options_p options
) {
1669 * - search the statement S beta_get_domain
1670 * - search the array array_id_original or array_id_copy in the list of
1671 * access in the given statement
1672 * - clone the found access array
1673 * - reclone this access and put the other array id (it depends which
1674 * id is found in the second step)
1675 * - search the beta_insert
1676 * - shift all the beta after or before beta_insert to let the place of the
1678 * - copy domain + scattering of S in a new statement (and add this one in
1680 * - for each unused iterators we put iter >= 1 && iter <= -1 in the domain
1681 * to remove the loop at the generation of code
1682 * - put the 2 access arrays in this statement
1686 osl_relation_p scattering
, ptr
= NULL
;
1689 // TODO : global vars ??
1690 osl_arrays_p arrays
;
1691 osl_scatnames_p scatnames
;
1692 osl_strings_p params
;
1693 osl_body_p body
= NULL
;
1694 osl_extbody_p extbody
= NULL
;
1696 osl_generic_p gen
= NULL
;
1697 arrays
= osl_generic_lookup(scop
->extension
, OSL_URI_ARRAYS
);
1698 scatnames
= osl_generic_lookup(scop
->extension
, OSL_URI_SCATNAMES
);
1699 params
= osl_generic_lookup(scop
->parameters
, OSL_URI_STRINGS
);
1701 if (beta_insert
->size
== 0)
1702 return CLAY_ERROR_BETA_EMPTY
;
1704 // search the beta where we have to insert the new loop
1705 osl_statement_p stmt_1
= clay_beta_find(scop
->statement
, beta_insert
);
1707 return CLAY_ERROR_BETA_NOT_FOUND
;
1709 // search the beta which is need to copy the domain and scattering
1710 osl_statement_p stmt_2
= clay_beta_find(scop
->statement
, beta_get_domain
);
1712 return CLAY_ERROR_BETA_NOT_FOUND
;
1714 // copy the domain/scattering
1715 osl_statement_p copy
= osl_statement_malloc();
1716 copy
->domain
= osl_relation_clone(stmt_2
->domain
);
1717 //copy->scattering = osl_relation_clone(stmt_2->scattering);
1718 copy
->scattering
= NULL
;
1719 scattering
= stmt_2
->scattering
;
1720 while (scattering
!= NULL
) {
1721 if (clay_beta_check_relation(scattering
, beta_get_domain
)) {
1723 copy
->scattering
= osl_relation_nclone(scattering
, 1);
1724 ptr
= copy
->scattering
;
1726 ptr
->next
= osl_relation_nclone(scattering
, 1);
1730 scattering
= scattering
->next
;
1733 // create an extbody and copy the original iterators
1734 osl_extbody_p ebody
= osl_extbody_malloc();
1735 ebody
->body
= osl_body_malloc();
1737 // body string (it will be regenerated)
1738 ebody
->body
->expression
= osl_strings_encapsulate(strdup("@ = @;"));
1741 extbody
= osl_generic_lookup(stmt_2
->extension
, OSL_URI_EXTBODY
);
1743 ebody
->body
->iterators
= osl_strings_clone(extbody
->body
->iterators
);
1747 body
= osl_generic_lookup(stmt_2
->extension
, OSL_URI_BODY
);
1748 ebody
->body
->iterators
= osl_strings_clone(body
->iterators
);
1751 // 2 access coordinates
1752 osl_extbody_add(ebody
, 0, 1);
1753 osl_extbody_add(ebody
, 4, 1);
1755 gen
= osl_generic_shell(ebody
, osl_extbody_interface());
1756 osl_generic_add(©
->extension
, gen
);
1757 // not creating a ebody's corresponding "body" in the new copy statement
1760 // search the array_id in the beta_get_domain
1762 osl_relation_list_p access
= stmt_2
->access
;
1768 id
= osl_relation_get_array_id(a
);
1769 if (id
== array_id_original
|| id
== array_id_copy
)
1771 access
= access
->next
;
1775 return CLAY_ERROR_ARRAY_NOT_FOUND_IN_THE_BETA
;
1777 // matrix of the copied array
1778 a
= osl_relation_nclone(a
, 1);
1779 a
->type
= OSL_TYPE_WRITE
;
1780 osl_int_set_si(a
->precision
, &a
->m
[0][a
->nb_columns
-1], array_id_copy
);
1781 copy
->access
= osl_relation_list_malloc();
1782 copy
->access
->elt
= a
;
1784 clay_util_body_regenerate_access(ebody
, a
, 0, arrays
, scatnames
, params
);
1786 // matrix of the original array
1787 a
= osl_relation_nclone(a
, 1);
1788 a
->type
= OSL_TYPE_READ
;
1789 copy
->access
->next
= osl_relation_list_malloc();
1790 copy
->access
->next
->elt
= a
;
1791 copy
->access
->next
->next
= NULL
;
1792 osl_int_set_si(a
->precision
, &a
->m
[0][a
->nb_columns
-1], array_id_original
);
1794 clay_util_body_regenerate_access(ebody
, a
, 1, arrays
, scatnames
, params
);
1797 // remove the unused dim in the scatterin (modify the domain of the loop)
1798 for (j
= 0 ; j
< a
->nb_input_dims
; j
++) {
1801 // search an unused input dims (if there is only 0 on the row)
1802 for (i
= 0 ; i
< a
->nb_rows
; i
++) {
1803 if (!osl_int_zero(a
->precision
, a
->m
[i
][1 + a
->nb_output_dims
+ j
])) {
1812 osl_relation_p domain
= copy
->domain
;
1813 for (i
= 0 ; i
< domain
->nb_rows
; i
++) {
1814 t
= osl_int_get_si(domain
->precision
, domain
->m
[i
][1 + j
]);
1817 for (k
= 1 ; k
< domain
->nb_columns
-1 ; k
++)
1819 osl_int_set_si(domain
->precision
, &domain
->m
[i
][k
], 0);
1821 // set iter <= -1 && iter >= 1 ==> no solutions, so no loop !
1823 osl_int_set_si(domain
->precision
, &domain
->m
[i
][k
], -1);
1825 osl_int_set_si(domain
->precision
, &domain
->m
[i
][k
], 1);
1832 // let the place to the new loop
1834 scattering
= copy
->scattering
;
1835 if (insert_before
) {
1836 clay_beta_shift_before(scop
->statement
, beta_insert
, 1);
1838 // set the beta : it's the beta[0]
1839 while (scattering
!= NULL
) {
1840 // we know that copy has only scattering union parts that match the
1842 row
= clay_util_relation_get_line(scattering
, 0);
1843 osl_int_set_si(scattering
->precision
,
1844 &scattering
->m
[row
][scattering
->nb_columns
-1],
1845 beta_insert
->data
[0]);
1846 scattering
= scattering
->next
;
1849 clay_beta_shift_after(scop
->statement
, beta_insert
, 1);
1851 // set the beta : it's the beta[0] + 1
1852 while (scattering
!= NULL
) {
1853 row
= clay_util_relation_get_line(scattering
, 0);
1854 osl_int_set_si(scattering
->precision
,
1855 &scattering
->m
[row
][scattering
->nb_columns
-1],
1856 beta_insert
->data
[0]+1);
1857 scattering
= scattering
->next
;
1861 copy
->next
= scop
->statement
;
1862 scop
->statement
= copy
;
1864 if (options
&& options
->normalize
)
1865 clay_beta_normalize(scop
);
1867 return CLAY_SUCCESS
;
1872 * clay_block function:
1873 * \param[in,out] scop
1874 * \param[in] beta_stmt1
1875 * \param[in] beta_stmt2
1876 * \param[in] options
1879 int clay_block(osl_scop_p scop
,
1880 clay_array_p beta_stmt1
,
1881 clay_array_p beta_stmt2
,
1882 clay_options_p options
) {
1885 * concat '{' + body(stmt_1) + body(stmt_2) + '}'
1886 * update extbody if needed
1887 * concat access(stmt_1) + access(stmt_2)
1890 if (beta_stmt1
->size
!= beta_stmt2
->size
)
1891 return CLAY_ERROR_BETAS_NOT_SAME_DIMS
;
1893 // search statements and check betas
1894 osl_statement_p stmt_1
= clay_beta_find(scop
->statement
, beta_stmt1
);
1896 return CLAY_ERROR_BETA_NOT_FOUND
;
1898 osl_statement_p stmt_2
= clay_beta_find(scop
->statement
, beta_stmt2
);
1900 return CLAY_ERROR_BETA_NOT_FOUND
;
1902 // We can only merge full statements, because we change the body so it would
1903 // affect other parts with different scatterings.
1904 osl_relation_p scattering
= stmt_1
->scattering
;
1905 while (scattering
!= NULL
) {
1906 CLAY_BETA_IS_STMT(beta_stmt1
, scattering
);
1907 scattering
= scattering
->next
;
1909 scattering
= stmt_2
->scattering
;
1910 while (scattering
!= NULL
) {
1911 CLAY_BETA_IS_STMT(beta_stmt2
, scattering
);
1912 scattering
= scattering
->next
;
1915 if (!osl_relation_equal(stmt_1
->domain
, stmt_2
->domain
))
1916 return CLAY_ERROR_BETAS_NOT_SAME_DOMAIN
;
1919 int is_extbody_1
= 0;
1920 int is_extbody_2
= 0;
1926 osl_extbody_p ebody_1
, ebody_2
;
1927 osl_body_p body_1
, body_2
;
1928 osl_generic_p gen
= NULL
;
1930 // get the body string
1932 ebody_1
= osl_generic_lookup(stmt_1
->extension
, OSL_URI_EXTBODY
);
1937 body_1
= osl_generic_lookup(stmt_1
->extension
, OSL_URI_BODY
);
1940 ebody_2
= osl_generic_lookup(stmt_2
->extension
, OSL_URI_EXTBODY
);
1945 body_2
= osl_generic_lookup(stmt_2
->extension
, OSL_URI_BODY
);
1948 if (is_extbody_1
!= is_extbody_2
)
1949 return CLAY_ERROR_ONE_HAS_EXTBODY
;
1952 expr_left
= is_extbody_1
1953 ? ebody_1
->body
->expression
->string
1954 : body_1
->expression
->string
;
1956 expr_right
= is_extbody_2
1957 ? ebody_2
->body
->expression
->string
1958 : body_2
->expression
->string
;
1963 // shift for the '{'
1964 for (i
= 0 ; i
< ebody_1
->nb_access
; i
++) {
1965 if (ebody_1
->start
[i
] != -1)
1966 ebody_1
->start
[i
]++;
1969 int offset
= 1 + strlen(expr_left
[0]);
1971 // shift the right part
1972 for (i
= 0 ; i
< ebody_2
->nb_access
; i
++) {
1973 if (ebody_2
->start
[i
] != -1)
1974 ebody_2
->start
[i
] += offset
;
1976 // concat with the extbody 2
1977 osl_extbody_add(ebody_1
, ebody_2
->start
[i
], ebody_2
->length
[i
]);
1982 // generate the new body string
1983 new_expr
= (char*) malloc(strlen(expr_left
[0]) + strlen(expr_right
[0]) + 3);
1984 strcpy(new_expr
, "{");
1985 strcat(new_expr
, expr_left
[0]);
1986 strcat(new_expr
, expr_right
[0]);
1987 strcat(new_expr
, "}");
1990 expr_left
[0] = new_expr
;
1992 // concat all the access array
1993 osl_relation_list_p access
= stmt_1
->access
;
1995 while (access
->next
)
1996 access
= access
->next
;
1998 access
->next
= stmt_2
->access
;
1999 stmt_2
->access
= NULL
;
2001 // synchronize extbody with body for stmt_1
2003 body_1
= osl_generic_lookup(stmt_1
->extension
, OSL_URI_BODY
);
2005 osl_generic_remove(&stmt_1
->extension
, OSL_URI_BODY
);
2006 body_1
= osl_body_clone(ebody_1
->body
);
2007 gen
= osl_generic_shell(body_1
, osl_body_interface());
2008 osl_generic_add(&stmt_1
->extension
, gen
);
2012 // Remove the scattering parts of stmt_2 that match the beta2.
2013 scattering
= stmt_2
->scattering
;
2015 if (clay_beta_check_relation(scattering
, beta_stmt2
)) {
2016 osl_relation_p to_delete
= scattering
;
2017 to_delete
->next
= NULL
;
2018 stmt_2
->scattering
= scattering
->next
;
2019 scattering
= scattering
->next
;
2020 osl_relation_free(to_delete
);
2023 // These branches must not be merged, scattering is overwritten inside!
2025 while (scattering
->next
!= NULL
) {
2026 osl_relation_p to_delete
= NULL
;
2027 if (clay_beta_check_relation(scattering
->next
, beta_stmt2
)) {
2028 to_delete
= scattering
->next
;
2029 to_delete
->next
= NULL
;
2030 scattering
->next
= scattering
->next
->next
;
2032 scattering
= scattering
->next
;
2033 osl_relation_free(to_delete
);
2036 // Remove stmt_2 completely if it has no more scatterings (i.e. was only a statement).
2037 if (stmt_2
->scattering
== NULL
) {
2038 osl_statement_p s
= scop
->statement
;
2041 scop
->statement
= s
->next
;
2042 stmt_2
->next
= NULL
;
2043 osl_statement_free(stmt_2
);
2048 if (s
!= NULL
&& stmt_2
!= NULL
) {
2049 while (s
->next
!= NULL
) {
2050 if (s
->next
== stmt_2
) {
2051 s
->next
= s
->next
->next
;
2052 stmt_2
->next
= NULL
; // prevent free from removing chained statements
2053 osl_statement_free(stmt_2
);
2061 if (options
&& options
->normalize
)
2062 clay_beta_normalize(scop
);
2064 return CLAY_SUCCESS
;