2
/*+-----------------------------------------------------------------**
4
**-----------------------------------------------------------------**
6
**-----------------------------------------------------------------**
7
** First version: 30/04/2008 **
8
**-----------------------------------------------------------------**
11
*****************************************************************************
12
* OpenScop: Structures and formats for polyhedral tools to talk together *
13
*****************************************************************************
14
* ,___,,_,__,,__,,__,,__,,_,__,,_,__,,__,,___,_,__,,_,__, *
15
* / / / // // // // / / / // // / / // / /|,_, *
16
* / / / // // // // / / / // // / / // / / / /\ *
17
* |~~~|~|~~~|~~~|~~~|~~~|~|~~~|~|~~~|~~~|~~~|~|~~~|~|~~~|/_/ \ *
18
* | G |C| P | = | L | P |=| = |C| = | = | = |=| = |=| C |\ \ /\ *
19
* | R |l| o | = | e | l |=| = |a| = | = | = |=| = |=| L | \# \ /\ *
20
* | A |a| l | = | t | u |=| = |n| = | = | = |=| = |=| o | |\# \ \ *
21
* | P |n| l | = | s | t |=| = |d| = | = | = | | |=| o | | \# \ \ *
22
* | H | | y | | e | o | | = |l| | | = | | | | G | | \ \ \ *
23
* | I | | | | e | | | | | | | | | | | | | \ \ \ *
24
* | T | | | | | | | | | | | | | | | | | \ \ \ *
25
* | E | | | | | | | | | | | | | | | | | \ \ \ *
26
* | * |*| * | * | * | * |*| * |*| * | * | * |*| * |*| * | / \* \ \ *
27
* | O |p| e | n | S | c |o| p |-| L | i | b |r| a |r| y |/ \ \ / *
28
* '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---' '--' *
30
* Copyright (C) 2008 University Paris-Sud 11 and INRIA *
32
* (3-clause BSD license) *
33
* Redistribution and use in source and binary forms, with or without *
34
* modification, are permitted provided that the following conditions *
37
* 1. Redistributions of source code must retain the above copyright notice, *
38
* this list of conditions and the following disclaimer. *
39
* 2. Redistributions in binary form must reproduce the above copyright *
40
* notice, this list of conditions and the following disclaimer in the *
41
* documentation and/or other materials provided with the distribution. *
42
* 3. The name of the author may not be used to endorse or promote products *
43
* derived from this software without specific prior written permission. *
45
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR *
46
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES *
47
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *
48
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, *
49
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *
50
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
51
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
52
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
53
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *
54
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
56
* OpenScop Library, a library to manipulate OpenScop formats and data *
57
* structures. Written by: *
58
* Cedric Bastoul <Cedric.Bastoul@u-psud.fr> and *
59
* Louis-Noel Pouchet <Louis-Noel.pouchet@inria.fr> *
61
*****************************************************************************/
69
#include <osl/macros.h>
72
#include <osl/vector.h>
73
#include <osl/strings.h>
74
#include <osl/names.h>
75
#include <osl/relation.h>
78
/*+***************************************************************************
79
* Structure display function *
80
*****************************************************************************/
84
* osl_relation_sprint_type function:
85
* this function prints the textual type of an osl_relation_t structure into
86
* a string, according to the OpenScop specification, and returns that string.
87
* \param[in] relation The relation whose type has to be printed.
88
* \return A string containing the relation type.
91
char * osl_relation_sprint_type(osl_relation_p relation) {
94
OSL_malloc(string, char *, OSL_MAX_STRING * sizeof(char));
97
if (relation != NULL) {
98
switch (relation->type) {
100
snprintf(string, OSL_MAX_STRING, OSL_STRING_UNDEFINED);
103
case OSL_TYPE_CONTEXT: {
104
snprintf(string, OSL_MAX_STRING, OSL_STRING_CONTEXT);
107
case OSL_TYPE_DOMAIN: {
108
snprintf(string, OSL_MAX_STRING, OSL_STRING_DOMAIN);
111
case OSL_TYPE_SCATTERING: {
112
snprintf(string, OSL_MAX_STRING, OSL_STRING_SCATTERING);
115
case OSL_TYPE_READ: {
116
snprintf(string, OSL_MAX_STRING, OSL_STRING_READ);
119
case OSL_TYPE_WRITE: {
120
snprintf(string, OSL_MAX_STRING, OSL_STRING_WRITE);
123
case OSL_TYPE_MAY_WRITE: {
124
snprintf(string, OSL_MAX_STRING, OSL_STRING_MAY_WRITE);
128
OSL_warning("unknown relation type, "
129
"replaced with "OSL_STRING_UNDEFINED);
130
snprintf(string, OSL_MAX_STRING, OSL_STRING_UNDEFINED);
140
* osl_relation_print_type function:
141
* this function displays the textual type of an osl_relation_t structure into
142
* a file (file, possibly stdout), according to the OpenScop specification.
143
* \param[in] file File where informations are printed.
144
* \param[in] relation The relation whose type has to be printed.
147
void osl_relation_print_type(FILE * file, osl_relation_p relation) {
148
char * string = osl_relation_sprint_type(relation);
149
fprintf(file, "%s", string);
155
* osl_relation_idump function:
156
* this function displays a osl_relation_t structure (*relation) into a
157
* file (file, possibly stdout) in a way that trends to be understandable.
158
* It includes an indentation level (level) in order to work with others
160
* \param[in] file File where informations are printed.
161
* \param[in] relation The relation whose information has to be printed.
162
* \param[in] level Number of spaces before printing, for each line.
164
void osl_relation_idump(FILE * file, osl_relation_p relation, int level) {
167
// Go to the right level.
168
for (j = 0; j < level; j++)
169
fprintf(file, "|\t");
171
if (relation != NULL) {
172
fprintf(file, "+-- osl_relation_t (");
173
osl_relation_print_type(file, relation);
175
osl_int_dump_precision(file, relation->precision);
176
fprintf(file, ")\n");
179
fprintf(file, "+-- NULL relation\n");
182
while (relation != NULL) {
184
// Go to the right level.
185
for (j = 0; j < level; j++)
186
fprintf(file, "|\t");
187
fprintf(file, "| osl_relation_t (");
188
osl_relation_print_type(file, relation);
190
osl_int_dump_precision(file, relation->precision);
191
fprintf(file, ")\n");
197
for(j = 0; j <= level; j++)
198
fprintf(file, "|\t");
199
fprintf(file, "%d %d %d %d %d %d\n",
200
relation->nb_rows, relation->nb_columns,
201
relation->nb_output_dims, relation->nb_input_dims,
202
relation->nb_local_dims, relation->nb_parameters);
204
// Display the relation.
205
for (i = 0; i < relation->nb_rows; i++) {
206
for (j = 0; j <= level; j++)
207
fprintf(file, "|\t");
211
for (j = 0; j < relation->nb_columns; j++) {
212
osl_int_print(file, relation->precision, relation->m[i][j]);
216
fprintf(file, "]\n");
219
relation = relation->next;
222
if (relation != NULL) {
223
for (j = 0; j <= level; j++)
224
fprintf(file, "|\t");
225
fprintf(file, "|\n");
226
for (j = 0; j <= level; j++)
227
fprintf(file, "|\t");
228
fprintf(file, "V\n");
233
for (j = 0; j <= level; j++)
234
fprintf(file, "|\t");
240
* osl_relation_dump function:
241
* this function prints the content of a osl_relation_t structure
242
* (*relation) into a file (file, possibly stdout).
243
* \param[in] file File where informations are printed.
244
* \param[in] relation The relation whose information have to be printed.
246
void osl_relation_dump(FILE * file, osl_relation_p relation) {
247
osl_relation_idump(file, relation, 0);
252
* osl_relation_expression_element function:
253
* this function returns a string containing the printing of a value (e.g.,
254
* an iterator with its coefficient or a constant).
255
* \param[in] val Coefficient or constant value.
256
* \param[in] precision The precision of the value.
257
* \param[in,out] first Pointer to a boolean set to 1 if the current value
258
* is the first of an expresion, 0 otherwise (maybe
260
* \param[in] cst A boolean set to 1 if the value is a constant,
262
* \param[in] name String containing the name of the element.
263
* \return A string that contains the printing of a value.
266
char * osl_relation_expression_element(osl_int_t val,
267
int precision, int * first,
268
int cst, char * name) {
269
char * temp, * body, * sval;
271
OSL_malloc(temp, char *, OSL_MAX_STRING * sizeof(char));
272
OSL_malloc(body, char *, OSL_MAX_STRING * sizeof(char));
273
OSL_malloc(sval, char *, OSL_MAX_STRING * sizeof(char));
278
// statements for the 'normal' processing.
279
if (!osl_int_zero(precision, val) && (!cst)) {
280
if ((*first) || osl_int_neg(precision, val)) {
281
if (osl_int_one(precision, val)) { // case 1
282
sprintf(sval, "%s", name);
285
if (osl_int_mone(precision, val)) { // case -1
286
sprintf(sval, "-%s", name);
288
else { // default case
289
osl_int_sprint_txt(sval, precision, val);
290
sprintf(temp, "*%s", name);
297
if (osl_int_one(precision, val)) {
298
sprintf(sval, "+%s", name);
302
osl_int_sprint_txt(temp, precision, val);
304
sprintf(temp, "*%s", name);
311
if ((osl_int_zero(precision, val) && (*first)) ||
312
(osl_int_neg(precision, val)))
313
osl_int_sprint_txt(sval, precision, val);
314
if (osl_int_pos(precision, val)) {
317
osl_int_sprint_txt(temp, precision, val);
321
osl_int_sprint_txt(sval, precision, val);
334
* osl_relation_strings function:
335
* this function creates a NULL-terminated array of strings from an
336
* osl_names_t structure in such a way that the ith string is the "name"
337
* corresponding to the ith column of the constraint matrix.
338
* \param[in] relation The relation for which we need an array of names.
339
* \param[in] names The set of names for each element.
340
* \return An array of strings with one string per constraint matrix column.
343
char ** osl_relation_strings(osl_relation_p relation, osl_names_p names) {
345
char temp[OSL_MAX_STRING];
348
if ((relation == NULL) || (names == NULL)) {
349
OSL_debug("no names or relation to build the name array");
353
OSL_malloc(strings, char **, (relation->nb_columns + 1)*sizeof(char *));
354
strings[relation->nb_columns] = NULL;
356
// 1. Equality/inequality marker.
357
OSL_strdup(strings[0], "e/i");
360
// 2. Output dimensions.
361
if (osl_relation_is_access(relation)) {
362
// The first output dimension is the array name.
363
OSL_strdup(strings[offset], "Arr");
364
// The other ones are the array dimensions [1]...[n]
365
for (i = offset + 1; i < relation->nb_output_dims + offset; i++) {
366
sprintf(temp, "[%d]", i - 1);
367
OSL_strdup(strings[i], temp);
371
if ((relation->type == OSL_TYPE_DOMAIN) ||
372
(relation->type == OSL_TYPE_CONTEXT)) {
373
for (i = offset; i < relation->nb_output_dims + offset; i++) {
374
OSL_strdup(strings[i], names->iterators->string[i - offset]);
378
for (i = offset; i < relation->nb_output_dims + offset; i++) {
379
OSL_strdup(strings[i], names->scatt_dims->string[i - offset]);
382
offset += relation->nb_output_dims;
384
// 3. Input dimensions.
385
for (i = offset; i < relation->nb_input_dims + offset; i++)
386
OSL_strdup(strings[i], names->iterators->string[i - offset]);
387
offset += relation->nb_input_dims;
389
// 4. Local dimensions.
390
for (i = offset; i < relation->nb_local_dims + offset; i++)
391
OSL_strdup(strings[i], names->local_dims->string[i - offset]);
392
offset += relation->nb_local_dims;
395
for (i = offset; i < relation->nb_parameters + offset; i++)
396
OSL_strdup(strings[i], names->parameters->string[i - offset]);
397
offset += relation->nb_parameters;
400
OSL_strdup(strings[offset], "1");
407
* osl_relation_subexpression function:
408
* this function returns a string corresponding to an affine (sub-)expression
409
* stored at the "row"^th row of the relation pointed by "relation" between
410
* the start and stop columns. Optionally it may oppose the whole expression.
411
* \param[in] relation A set of linear expressions.
412
* \param[in] row The row corresponding to the expression.
413
* \param[in] start The first column for the expression (inclusive).
414
* \param[in] stop The last column for the expression (inclusive).
415
* \param[in] oppose Boolean set to 1 to negate the expression, 0 otherwise.
416
* \param[in] strings Array of textual names of the various elements.
417
* \return A string that contains the printing of an affine (sub-)expression.
420
char * osl_relation_subexpression(osl_relation_p relation,
421
int row, int start, int stop, int oppose,
423
int i, first = 1, constant;
427
OSL_malloc(sline, char *, OSL_MAX_STRING * sizeof(char));
430
// Create the expression. The constant is a special case.
431
for (i = start; i <= stop; i++) {
433
osl_int_oppose(relation->precision,
434
&relation->m[row][i], relation->m[row][i]);
437
if (i == relation->nb_columns - 1)
442
sval = osl_relation_expression_element(relation->m[row][i],
443
relation->precision, &first, constant, strings[i]);
446
osl_int_oppose(relation->precision,
447
&relation->m[row][i], relation->m[row][i]);
458
* osl_relation_expression function:
459
* this function returns a string corresponding to an affine expression
460
* stored at the "row"^th row of the relation pointed by "relation".
461
* \param[in] relation A set of linear expressions.
462
* \param[in] row The row corresponding to the expression.
463
* \param[in] strings Array of textual names of the various elements.
464
* \return A string that contains the printing of an affine expression.
466
char * osl_relation_expression(osl_relation_p relation,
467
int row, char ** strings) {
469
return osl_relation_subexpression(relation, row,
470
1, relation->nb_columns - 1, 0,
476
* osl_relation_is_simple_output function:
477
* this function returns 1 or -1 if a given constraint row of a relation
478
* corresponds to an output, 0 otherwise. We call a simple output an equality
479
* constraint where exactly one output coefficient is not 0 and is either
480
* 1 (in this case the function returns 1) or -1 (in this case the function
482
* \param[in] relation The relation to test for simple output.
483
* \param[in] row The row corresponding to the constraint to test.
484
* \return 1 or -1 if the row is a simple output, 0 otherwise.
487
int osl_relation_is_simple_output(osl_relation_p relation, int row) {
492
if ((relation == NULL) ||
493
(relation->m == NULL) ||
494
(relation->nb_output_dims == 0))
497
if ((row < 0) || (row > relation->nb_rows))
498
OSL_error("the specified row does not exist in the relation");
500
// The constraint must be an equality.
501
if (!osl_int_zero(relation->precision, relation->m[row][0]))
504
// Check the output part has one and only one non-zero +1 or -1 coefficient.
506
for (i = 1; i <= relation->nb_output_dims; i++) {
507
if (!osl_int_zero(relation->precision, relation->m[row][i])) {
513
if (osl_int_one(relation->precision, relation->m[row][i]))
515
else if (osl_int_mone(relation->precision, relation->m[row][i]))
527
* osl_relation_sprint_comment function:
528
* this function prints into a string a comment corresponding to a constraint
529
* of a relation, according to its type, then it returns this string. This
530
* function does not check that printing the comment is possible (i.e., are
531
* there enough names ?), hence it is the responsibility of the user to ensure
532
* he/she can call this function safely.
533
* \param[in] relation The relation for which a comment has to be printed.
534
* \param[in] row The constrain row for which a comment has to be printed.
535
* \param[in] strings Array of textual names of the various elements.
536
* \param[in] arrays Array of textual identifiers of the arrays.
537
* \return A string which contains the comment for the row.
540
char * osl_relation_sprint_comment(osl_relation_p relation, int row,
541
char ** strings, char ** arrays) {
543
int high_water_mark = OSL_MAX_STRING;
544
char * string = NULL;
546
char buffer[OSL_MAX_STRING];
548
OSL_malloc(string, char *, high_water_mark * sizeof(char));
551
if ((relation == NULL) || (strings == NULL)) {
552
OSL_debug("no relation or names while asked to print a comment");
556
if ((sign = osl_relation_is_simple_output(relation, row))) {
557
// First case : output == expression.
559
expression = osl_relation_subexpression(relation, row,
560
1, relation->nb_output_dims,
563
snprintf(buffer, OSL_MAX_STRING, " ## %s", expression);
564
osl_util_safe_strcat(&string, buffer, &high_water_mark);
567
// We don't print the right hand side if it's an array identifier.
568
if (!osl_relation_is_access(relation) ||
569
osl_int_zero(relation->precision, relation->m[row][1])) {
570
expression = osl_relation_subexpression(relation, row,
571
relation->nb_output_dims + 1,
572
relation->nb_columns - 1,
575
snprintf(buffer, OSL_MAX_STRING, " == %s", expression);
576
osl_util_safe_strcat(&string, buffer, &high_water_mark);
580
snprintf(buffer, OSL_MAX_STRING, " == %s",
581
arrays[osl_relation_get_array_id(relation) - 1]);
582
osl_util_safe_strcat(&string, buffer, &high_water_mark);
586
// Second case : general case.
588
expression = osl_relation_expression(relation, row, strings);
589
snprintf(buffer, OSL_MAX_STRING, " ## %s", expression);
590
osl_util_safe_strcat(&string, buffer, &high_water_mark);
593
if (osl_int_zero(relation->precision, relation->m[row][0]))
594
snprintf(buffer, OSL_MAX_STRING, " == 0");
596
snprintf(buffer, OSL_MAX_STRING, " >= 0");
597
osl_util_safe_strcat(&string, buffer, &high_water_mark);
605
* osl_relation_column_string function:
606
* this function returns an OpenScop comment string showing all column
607
* names. It is designed to nicely fit a constraint matrix that would be
608
* printed just below this line.
609
* \param[in] relation The relation related to the comment line to build.
610
* \param[in] strings Array of textual names of the various elements.
611
* \return A fancy comment string with all the dimension names.
614
char * osl_relation_column_string(osl_relation_p relation, char ** strings) {
616
int index_output_dims;
617
int index_input_dims;
618
int index_local_dims;
619
int index_parameters;
621
int space, length, left, right;
623
char temp[OSL_MAX_STRING];
625
OSL_malloc(scolumn, char *, OSL_MAX_STRING);
627
index_output_dims = 1;
628
index_input_dims = index_output_dims + relation->nb_output_dims;
629
index_local_dims = index_input_dims + relation->nb_input_dims;
630
index_parameters = index_local_dims + relation->nb_local_dims;
631
index_scalar = index_parameters + relation->nb_parameters;
633
// 1. The comment part.
634
sprintf(scolumn, "#");
635
for (j = 0; j < (OSL_FMT_LENGTH - 1)/2 - 1; j++)
636
strcat(scolumn, " ");
639
while (strings[i] != NULL) {
640
space = OSL_FMT_LENGTH;
641
length = (space > strlen(strings[i])) ? strlen(strings[i]) : space;
642
right = (space - length + (OSL_FMT_LENGTH % 2)) / 2;
643
left = space - length - right;
645
// 2. Spaces before the name
646
for (j = 0; j < left; j++)
647
strcat(scolumn, " ");
649
// 3. The (abbreviated) name
650
for (j = 0; j < length - 1; j++) {
651
sprintf(temp, "%c", strings[i][j]);
652
strcat(scolumn, temp);
654
if (length >= strlen(strings[i]))
655
sprintf(temp, "%c", strings[i][j]);
658
strcat(scolumn, temp);
660
// 4. Spaces after the name
661
for (j = 0; j < right; j++)
662
strcat(scolumn, " ");
665
if ((i == index_output_dims) ||
666
(i == index_input_dims) ||
667
(i == index_local_dims) ||
668
(i == index_parameters) ||
670
strcat(scolumn, "|");
672
strcat(scolumn, " ");
674
strcat(scolumn, "\n");
681
* osl_relation_column_string_scoplib function:
682
* this function returns an OpenScop comment string showing all column
683
* names. It is designed to nicely fit a constraint matrix that would be
684
* printed just below this line.
685
* \param[in] relation The relation related to the comment line to build.
686
* \param[in] strings Array of textual names of the various elements.
687
* \return A fancy comment string with all the dimension names.
690
char * osl_relation_column_string_scoplib(osl_relation_p relation,
693
int index_output_dims;
694
int index_input_dims;
695
int index_local_dims;
696
int index_parameters;
698
int space, length, left, right;
700
char temp[OSL_MAX_STRING];
702
OSL_malloc(scolumn, char *, OSL_MAX_STRING);
704
index_output_dims = 1;
705
index_input_dims = index_output_dims + relation->nb_output_dims;
706
index_local_dims = index_input_dims + relation->nb_input_dims;
707
index_parameters = index_local_dims + relation->nb_local_dims;
708
index_scalar = index_parameters + relation->nb_parameters;
710
// 1. The comment part.
711
sprintf(scolumn, "#");
712
for (j = 0; j < (OSL_FMT_LENGTH - 1)/2 - 1; j++)
713
strcat(scolumn, " ");
716
while (strings[i] != NULL) {
719
(relation->type != OSL_TYPE_DOMAIN && i >= index_input_dims) ||
720
(relation->type == OSL_TYPE_DOMAIN && i <= index_output_dims) ||
721
i >= index_parameters) {
722
space = OSL_FMT_LENGTH;
723
length = (space > strlen(strings[i])) ? strlen(strings[i]) : space;
724
right = (space - length + (OSL_FMT_LENGTH % 2)) / 2;
725
left = space - length - right;
727
// 2. Spaces before the name
728
for (j = 0; j < left; j++)
729
strcat(scolumn, " ");
731
// 3. The (abbreviated) name
732
for (j = 0; j < length - 1; j++) {
733
sprintf(temp, "%c", strings[i][j]);
734
strcat(scolumn, temp);
736
if (length >= strlen(strings[i]))
737
sprintf(temp, "%c", strings[i][j]);
740
strcat(scolumn, temp);
742
// 4. Spaces after the name
743
for (j = 0; j < right; j++)
744
strcat(scolumn, " ");
746
if ((i == index_output_dims-1) ||
747
(i == index_input_dims-1) ||
748
(i == index_local_dims-1) ||
749
(i == index_parameters-1) ||
750
(i == index_scalar-1))
751
strcat(scolumn, "|");
753
strcat(scolumn, " ");
758
strcat(scolumn, "\n");
765
* osl_relation_names function:
766
* this function generates as set of names for all the dimensions
767
* involved in a given relation.
768
* \param[in] relation The relation we have to generate names for.
769
* \return A set of generated names for the input relation dimensions.
772
osl_names_p osl_relation_names(osl_relation_p relation) {
773
int nb_parameters = OSL_UNDEFINED;
774
int nb_iterators = OSL_UNDEFINED;
775
int nb_scattdims = OSL_UNDEFINED;
776
int nb_localdims = OSL_UNDEFINED;
777
int array_id = OSL_UNDEFINED;
779
osl_relation_get_attributes(relation, &nb_parameters, &nb_iterators,
780
&nb_scattdims, &nb_localdims, &array_id);
782
return osl_names_generate("P", nb_parameters,
791
* osl_relation_nb_components function:
792
* this function returns the number of component in the union of relations
793
* provided as parameter.
794
* \param[in] relation The input union of relations.
795
* \return The number of components in the input union of relations.
797
int osl_relation_nb_components(osl_relation_p relation) {
798
int nb_components = 0;
800
while (relation != NULL) {
802
relation = relation->next;
805
return nb_components;
810
* osl_relation_spprint_polylib function:
811
* this function pretty-prints the content of an osl_relation_t structure
812
* (*relation) into a string in the extended polylib format, and returns this
813
* string. This format is the same as OpenScop's, minus the type.
814
* \param[in] relation The relation whose information has to be printed.
815
* \param[in] names The names of the constraint columns for comments.
816
* \return A string containing the relation pretty-printing.
818
char * osl_relation_spprint_polylib(osl_relation_p relation,
822
int generated_names = 0;
823
int high_water_mark = OSL_MAX_STRING;
824
char * string = NULL;
825
char buffer[OSL_MAX_STRING];
826
char ** name_array = NULL;
830
if (relation == NULL)
831
return strdup("# NULL relation\n");
833
OSL_malloc(string, char *, high_water_mark * sizeof(char));
836
// Generates the names for the comments if necessary.
839
names = osl_relation_names(relation);
842
nb_parts = osl_relation_nb_components(relation);
845
snprintf(buffer, OSL_MAX_STRING, "# Union with %d parts\n%d\n",
847
osl_util_safe_strcat(&string, buffer, &high_water_mark);
850
// Print each part of the union.
851
for (part = 1; part <= nb_parts; part++) {
852
// Prepare the array of strings for comments.
853
name_array = osl_relation_strings(relation, names);
856
snprintf(buffer, OSL_MAX_STRING, "# Union part No.%d\n", part);
857
osl_util_safe_strcat(&string, buffer, &high_water_mark);
860
snprintf(buffer, OSL_MAX_STRING, "%d %d %d %d %d %d\n",
861
relation->nb_rows, relation->nb_columns,
862
relation->nb_output_dims, relation->nb_input_dims,
863
relation->nb_local_dims, relation->nb_parameters);
864
osl_util_safe_strcat(&string, buffer, &high_water_mark);
866
if (relation->nb_rows > 0) {
867
scolumn = osl_relation_column_string(relation, name_array);
868
snprintf(buffer, OSL_MAX_STRING, "%s", scolumn);
869
osl_util_safe_strcat(&string, buffer, &high_water_mark);
873
for (i = 0; i < relation->nb_rows; i++) {
874
for (j = 0; j < relation->nb_columns; j++) {
875
osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
876
osl_util_safe_strcat(&string, buffer, &high_water_mark);
877
snprintf(buffer, OSL_MAX_STRING, " ");
878
osl_util_safe_strcat(&string, buffer, &high_water_mark);
881
if (name_array != NULL) {
882
comment = osl_relation_sprint_comment(relation, i, name_array,
883
names->arrays->string);
884
osl_util_safe_strcat(&string, comment, &high_water_mark);
887
snprintf(buffer, OSL_MAX_STRING, "\n");
888
osl_util_safe_strcat(&string, buffer, &high_water_mark);
891
// Free the array of strings.
892
if (name_array != NULL) {
893
for (i = 0; i < relation->nb_columns; i++)
898
relation = relation->next;
902
osl_names_free(names);
909
* osl_relation_spprint_polylib_scoplib function:
910
* this function pretty-prints the content of an osl_relation_t structure
911
* (*relation) into a string in the extended polylib format, and returns this
913
* \param[in] relation The relation whose information has to be printed.
914
* \param[in] names The names of the constraint columns for comments.
915
* \param[in] print_nth_part Print the value of `n' (used for domain union)
916
* \param[in] add_fakeiter
917
* \return A string containing the relation pretty-printing.
919
char * osl_relation_spprint_polylib_scoplib(osl_relation_p relation,
925
int generated_names = 0;
927
int high_water_mark = OSL_MAX_STRING;
928
int start_row; // for removing the first line in the access matrix
929
int index_output_dims;
930
int index_input_dims;
932
char * string = NULL;
933
char buffer[OSL_MAX_STRING];
934
char ** name_array = NULL;
938
if (relation == NULL)
939
return strdup("# NULL relation\n");
941
OSL_malloc(string, char *, high_water_mark * sizeof(char));
944
// Generates the names for the comments if necessary.
947
names = osl_relation_names(relation);
950
nb_parts = osl_relation_nb_components(relation);
952
snprintf(buffer, OSL_MAX_STRING, "# Union with %d parts\n%d\n",
954
osl_util_safe_strcat(&string, buffer, &high_water_mark);
957
is_access_array = (relation->type == OSL_TYPE_READ ||
958
relation->type == OSL_TYPE_WRITE ? 1 : 0);
960
// Print each part of the union.
962
for (part = 1; part <= nb_parts; part++) {
964
index_output_dims = 1;
965
index_input_dims = index_output_dims + relation->nb_output_dims;
966
index_params = index_input_dims + relation->nb_input_dims;
968
// Prepare the array of strings for comments.
969
name_array = osl_relation_strings(relation, names);
972
snprintf(buffer, OSL_MAX_STRING, "# Union part No.%d\n", part);
973
osl_util_safe_strcat(&string, buffer, &high_water_mark);
976
if (print_nth_part) {
977
snprintf(buffer, OSL_MAX_STRING, "%d\n", part);
978
osl_util_safe_strcat(&string, buffer, &high_water_mark);
981
// Don't print the array size for access array
982
// (the total size is printed in osl_relation_list_pprint_access_array_scoplib)
983
if (!is_access_array) {
986
if (relation->type == OSL_TYPE_DOMAIN) {
990
snprintf(buffer, OSL_MAX_STRING, "%d %d\n",
991
relation->nb_rows+1, relation->nb_columns -
992
relation->nb_input_dims + 1);
993
osl_util_safe_strcat(&string, buffer, &high_water_mark);
995
// add the fakeiter line
996
snprintf(buffer, OSL_MAX_STRING, " 0 ");
997
osl_util_safe_strcat(&string, buffer, &high_water_mark);
998
snprintf(buffer, OSL_MAX_STRING, " 1 "); // fakeiter
999
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1001
for (i = 0 ; i < relation->nb_parameters ; i++) {
1002
snprintf(buffer, OSL_MAX_STRING, " 0 ");
1003
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1006
snprintf(buffer, OSL_MAX_STRING, " 0 ## fakeiter == 0\n");
1007
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1010
snprintf(buffer, OSL_MAX_STRING, "%d %d\n",
1011
relation->nb_rows, relation->nb_columns -
1012
relation->nb_input_dims);
1013
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1016
} else { // SCATTERING
1019
snprintf(buffer, OSL_MAX_STRING, "%d %d\n",
1020
relation->nb_rows+2, relation->nb_columns -
1021
relation->nb_output_dims + 1);
1022
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1024
snprintf(buffer, OSL_MAX_STRING, "%d %d\n",
1025
relation->nb_rows, relation->nb_columns -
1026
relation->nb_output_dims);
1027
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1031
// Print column names in comment
1032
if (relation->nb_rows > 0) {
1033
scolumn = osl_relation_column_string_scoplib(relation, name_array);
1034
snprintf(buffer, OSL_MAX_STRING, "%s", scolumn);
1035
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1043
if (relation->nb_rows == 1) // for non array variables
1045
else // Remove the 'Arr' line
1050
for (i = start_row; i < relation->nb_rows; i++) {
1053
if (!is_access_array) {
1054
// array index name for scoplib
1055
osl_int_sprint(buffer, relation->precision, relation->m[i][0]);
1056
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1057
snprintf(buffer, OSL_MAX_STRING, " ");
1058
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1061
// The first column represents the array index name in openscop
1063
osl_int_sprint(buffer, relation->precision,
1064
relation->m[0][relation->nb_columns-1]);
1066
snprintf(buffer, OSL_MAX_STRING, " 0 ");
1068
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1069
snprintf(buffer, OSL_MAX_STRING, " ");
1070
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1073
// Rest of the array
1074
if (relation->type == OSL_TYPE_DOMAIN) {
1076
for (j = 1; j < index_input_dims; j++) {
1077
osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
1078
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1079
snprintf(buffer, OSL_MAX_STRING, " ");
1080
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1084
for (j = index_params; j < relation->nb_columns; j++) {
1085
osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
1086
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1087
snprintf(buffer, OSL_MAX_STRING, " ");
1088
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1094
for (j = index_input_dims; j < index_params; j++) {
1095
if (is_access_array && relation->nb_rows == 1 &&
1096
j == relation->nb_columns-1) {
1097
snprintf(buffer, OSL_MAX_STRING, " 0 ");
1098
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1100
osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
1101
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1102
snprintf(buffer, OSL_MAX_STRING, " ");
1103
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1108
snprintf(buffer, OSL_MAX_STRING, " 0 ");
1109
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1112
for (; j < relation->nb_columns; j++) {
1113
if (is_access_array && relation->nb_rows == 1 &&
1114
j == relation->nb_columns-1) {
1115
snprintf(buffer, OSL_MAX_STRING, " 0 ");
1116
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1118
osl_int_sprint(buffer, relation->precision, relation->m[i][j]);
1119
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1120
snprintf(buffer, OSL_MAX_STRING, " ");
1121
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1126
// equation in comment
1127
if (name_array != NULL) {
1128
comment = osl_relation_sprint_comment(relation, i, name_array,
1129
names->arrays->string);
1130
osl_util_safe_strcat(&string, comment, &high_water_mark);
1132
snprintf(buffer, OSL_MAX_STRING, "\n");
1133
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1136
// add the lines in the scattering if we need the fakeiter
1137
if (relation->nb_rows > 0 && add_fakeiter &&
1138
relation->type == OSL_TYPE_SCATTERING) {
1140
for (i = 0 ; i < 2 ; i++) {
1141
for (j = 0; j < relation->nb_columns; j++) {
1142
if (j == index_output_dims && i == 0)
1143
snprintf(buffer, OSL_MAX_STRING, " 1 "); // fakeiter
1145
snprintf(buffer, OSL_MAX_STRING, " 0 ");
1146
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1148
snprintf(buffer, OSL_MAX_STRING, "\n");
1149
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1155
// Free the array of strings.
1156
if (name_array != NULL) {
1157
for (i = 0; i < relation->nb_columns; i++)
1158
free(name_array[i]);
1162
relation = relation->next;
1165
if (generated_names)
1166
osl_names_free(names);
1173
* osl_relation_spprint function:
1174
* this function pretty-prints the content of an osl_relation_t structure
1175
* (*relation) into a string in the OpenScop format, and returns this string.
1176
* \param[in] relation The relation whose information has to be printed.
1177
* \param[in] names The names of the constraint columns for comments.
1180
char * osl_relation_spprint(osl_relation_p relation, osl_names_p names) {
1181
int high_water_mark = OSL_MAX_STRING;
1182
char * string = NULL;
1184
char buffer[OSL_MAX_STRING];
1185
OSL_malloc(string, char *, high_water_mark * sizeof(char));
1188
if (osl_relation_nb_components(relation) > 0) {
1189
temp = osl_relation_sprint_type(relation);
1190
osl_util_safe_strcat(&string, temp, &high_water_mark);
1193
snprintf(buffer, OSL_MAX_STRING, "\n");
1194
osl_util_safe_strcat(&string, buffer, &high_water_mark);
1196
temp = osl_relation_spprint_polylib(relation, names);
1197
osl_util_safe_strcat(&string, temp, &high_water_mark);
1206
* osl_relation_spprint_scoplib function:
1207
* this function pretty-prints the content of an osl_relation_t structure
1208
* (*relation) into a string in the SCoPLib format, and returns this string.
1209
* \param[in] relation The relation whose information has to be printed.
1210
* \param[in] names The names of the constraint columns for comments.
1211
* \param[in] print_nth_part Print the value of `n' (used for domain union)
1212
* \param[in] add_fakeiter
1215
char * osl_relation_spprint_scoplib(osl_relation_p relation, osl_names_p names,
1216
int print_nth_part, int add_fakeiter) {
1217
int high_water_mark = OSL_MAX_STRING;
1218
char * string = NULL;
1220
OSL_malloc(string, char *, high_water_mark * sizeof(char));
1224
temp = osl_relation_spprint_polylib_scoplib(relation, names,
1225
print_nth_part, add_fakeiter);
1226
osl_util_safe_strcat(&string, temp, &high_water_mark);
1235
* osl_relation_pprint function:
1236
* this function pretty-prints the content of an osl_relation_t structure
1237
* (*relation) into a file (file, possibly stdout) in the OpenScop format.
1238
* \param[in] file File where informations are printed.
1239
* \param[in] relation The relation whose information has to be printed.
1240
* \param[in] names The names of the constraint columns for comments.
1242
void osl_relation_pprint(FILE * file, osl_relation_p relation,
1243
osl_names_p names) {
1244
char * string = osl_relation_spprint(relation, names);
1245
fprintf(file, "%s", string);
1251
* osl_relation_pprint_scoplib function:
1252
* this function pretty-prints the content of an osl_relation_t structure
1253
* (*relation) into a file (file, possibly stdout) in the SCoPLibformat.
1254
* \param[in] file File where informations are printed.
1255
* \param[in] relation The relation whose information has to be printed.
1256
* \param[in] names The names of the constraint columns for comments.
1257
* \param[in] print_nth_part
1258
* \param[in] add_fakeiter
1260
void osl_relation_pprint_scoplib(FILE * file, osl_relation_p relation,
1261
osl_names_p names, int print_nth_part,
1263
char * string = osl_relation_spprint_scoplib(relation, names,
1264
print_nth_part, add_fakeiter);
1265
fprintf(file, "%s", string);
1271
* osl_relation_sprint function:
1272
* this function prints the content of an osl_relation_t structure
1273
* (*relation) into a string (returned) in the OpenScop textual format.
1274
* \param[in] relation The relation structure to print.
1275
* \return A string containing the OpenScop dump of the relation structure.
1277
char * osl_relation_sprint(osl_relation_p relation) {
1279
return osl_relation_spprint(relation, NULL);
1284
* osl_relation_print function:
1285
* this function prints the content of an osl_relation_t structure
1286
* (*relation) into a file (file, possibly stdout) in the OpenScop format.
1287
* \param[in] file File where informations are printed.
1288
* \param[in] relation The relation whose information has to be printed.
1290
void osl_relation_print(FILE * file, osl_relation_p relation) {
1292
osl_relation_pprint(file, relation, NULL);
1296
/*****************************************************************************
1297
* Reading function *
1298
*****************************************************************************/
1302
* osl_relation_read_type function:
1303
* this function reads a textual relation type on the input 'file' or the
1304
* input string 'str' depending on which one is not NULL (exactly
1305
* one of them must not be NULL). It returns its integer counterpart.
1306
* \param[in] file The file where to read a relation type (if not NULL).
1307
* \param[in,out] str The string where to read a relation type (if not NULL).
1308
* This pointer is updated to reflect the read and points
1309
* after the tag in the input string.
1310
* \return The relation type.
1313
int osl_relation_read_type(FILE * file, char ** str) {
1315
osl_strings_p strings;
1317
if ((file != NULL && str != NULL) || (file == NULL && str == NULL))
1318
OSL_error("one and only one of the two parameters can be non-NULL");
1321
strings = osl_strings_read(file);
1323
strings = osl_strings_sread(str);
1325
if (osl_strings_size(strings) > 1) {
1326
OSL_warning("uninterpreted information (after the relation type)");
1328
if (osl_strings_size(strings) == 0)
1329
OSL_error("no relation type");
1331
if (!strcmp(strings->string[0], OSL_STRING_UNDEFINED)) {
1332
type = OSL_UNDEFINED;
1336
if (!strcmp(strings->string[0], OSL_STRING_CONTEXT)) {
1337
type = OSL_TYPE_CONTEXT;
1341
if (!strcmp(strings->string[0], OSL_STRING_DOMAIN)) {
1342
type = OSL_TYPE_DOMAIN;
1346
if (!strcmp(strings->string[0], OSL_STRING_SCATTERING)) {
1347
type = OSL_TYPE_SCATTERING;
1351
if (!strcmp(strings->string[0], OSL_STRING_READ)) {
1352
type = OSL_TYPE_READ;
1356
if (!strcmp(strings->string[0], OSL_STRING_WRITE)) {
1357
type = OSL_TYPE_WRITE;
1361
if (!strcmp(strings->string[0], OSL_STRING_MAY_WRITE)) {
1362
type = OSL_TYPE_MAY_WRITE;
1366
OSL_error("relation type not supported");
1369
osl_strings_free(strings);
1375
* osl_relation_pread function ("precision read"):
1376
* this function reads a relation into a file (foo, posibly stdin) and
1377
* returns a pointer this relation.
1378
* \param[in] foo The input stream.
1379
* \param[in] precision The precision of the relation elements.
1380
* \return A pointer to the relation structure that has been read.
1382
osl_relation_p osl_relation_pread(FILE * foo, int precision) {
1383
int i, j, k, n, read = 0;
1384
int nb_rows, nb_columns;
1385
int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters;
1386
int nb_union_parts = 1;
1387
int may_read_nb_union_parts = 1;
1388
int read_attributes = 1;
1391
char * c, s[OSL_MAX_STRING], str[OSL_MAX_STRING], *tmp;
1392
osl_relation_p relation, relation_union = NULL, previous = NULL;
1394
type = osl_relation_read_type(foo, NULL);
1396
// Read each part of the union (the number of parts may be updated inside)
1397
for (k = 0; k < nb_union_parts; k++) {
1398
// Read the number of union parts or the attributes of the union part
1399
while (read_attributes) {
1400
read_attributes = 0;
1402
// Read relation attributes.
1403
c = osl_util_skip_blank_and_comments(foo, s);
1404
read = sscanf(c, " %d %d %d %d %d %d", &nb_rows, &nb_columns,
1405
&nb_output_dims, &nb_input_dims,
1406
&nb_local_dims, &nb_parameters);
1408
if (((read != 1) && (read != 6)) ||
1409
((read == 1) && (may_read_nb_union_parts != 1)))
1410
OSL_error("not 1 or 6 integers on the first relation line");
1413
// Only one number means a union and is the number of parts.
1414
nb_union_parts = nb_rows;
1415
if (nb_union_parts < 1)
1416
OSL_error("negative nb of union parts");
1418
// Allow to read the properties of the first part of the union.
1419
read_attributes = 1;
1422
may_read_nb_union_parts = 0;
1425
// Allocate the union part and fill its properties.
1426
relation = osl_relation_pmalloc(precision, nb_rows, nb_columns);
1427
relation->type = type;
1428
relation->nb_output_dims = nb_output_dims;
1429
relation->nb_input_dims = nb_input_dims;
1430
relation->nb_local_dims = nb_local_dims;
1431
relation->nb_parameters = nb_parameters;
1433
// Read the matrix of constraints.
1434
for (i = 0; i < relation->nb_rows; i++) {
1435
c = osl_util_skip_blank_and_comments(foo, s);
1437
OSL_error("not enough rows");
1439
for (j = 0; j < relation->nb_columns; j++) {
1440
if (c == NULL || *c == '#' || *c == '\n')
1441
OSL_error("not enough columns");
1442
if (sscanf(c, "%s%n", str, &n) == 0)
1443
OSL_error("not enough rows");
1445
// TODO: remove this tmp (sread updates the pointer).
1447
osl_int_sread(&tmp, precision, &relation->m[i][j]);
1452
// Build the linked list of union parts.
1454
relation_union = relation;
1458
previous->next = relation;
1461
previous = relation;
1462
read_attributes = 1;
1465
return relation_union;
1470
* osl_relation_psread function ("precision read"):
1471
* this function reads a relation from a string complying to the OpenScop
1472
* textual format and returns a pointer this relation. The input parameter
1473
* is updated to the position in the input string this function reach right
1474
* after reading the generic structure.
1475
* \param[in,out] input The input string where to find a relation.
1476
* Updated to the position after what has been read.
1477
* \param[in] precision The precision of the relation elements.
1478
* \return A pointer to the relation structure that has been read.
1480
osl_relation_p osl_relation_psread(char ** input, int precision) {
1481
int i, j, k, n, read = 0;
1482
int nb_rows, nb_columns;
1483
int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters;
1484
int nb_union_parts = 1;
1485
int may_read_nb_union_parts = 1;
1486
int read_attributes = 1;
1489
char str[OSL_MAX_STRING], *tmp;
1490
osl_relation_p relation, relation_union = NULL, previous = NULL;
1492
type = osl_relation_read_type(NULL, input);
1494
// Read each part of the union (the number of parts may be updated inside)
1495
for (k = 0; k < nb_union_parts; k++) {
1496
// Read the number of union parts or the attributes of the union part
1497
while (read_attributes) {
1498
read_attributes = 0;
1500
// Read relation attributes.
1501
osl_util_sskip_blank_and_comments(input);
1503
read = sscanf(*input, " %d %d %d %d %d %d%n",
1504
&nb_rows, &nb_columns,
1505
&nb_output_dims, &nb_input_dims,
1506
&nb_local_dims, &nb_parameters, &n);
1509
if (((read != 1) && (read != 6)) ||
1510
((read == 1) && (may_read_nb_union_parts != 1)))
1511
OSL_error("not 1 or 6 integers on the first relation line");
1514
// Only one number means a union and is the number of parts.
1515
nb_union_parts = nb_rows;
1516
if (nb_union_parts < 1)
1517
OSL_error("negative nb of union parts");
1519
// Allow to read the properties of the first part of the union.
1520
read_attributes = 1;
1523
may_read_nb_union_parts = 0;
1526
// Allocate the union part and fill its properties.
1527
relation = osl_relation_pmalloc(precision, nb_rows, nb_columns);
1528
relation->type = type;
1529
relation->nb_output_dims = nb_output_dims;
1530
relation->nb_input_dims = nb_input_dims;
1531
relation->nb_local_dims = nb_local_dims;
1532
relation->nb_parameters = nb_parameters;
1534
// Read the matrix of constraints.
1535
for (i = 0; i < relation->nb_rows; i++) {
1536
osl_util_sskip_blank_and_comments(input);
1538
OSL_error("not enough rows");
1540
for (j = 0; j < relation->nb_columns; j++) {
1541
if (*input == NULL || **input == '#' || **input == '\n')
1542
OSL_error("not enough columns");
1543
if (sscanf(*input, "%s%n", str, &n) == 0)
1544
OSL_error("not enough rows");
1546
// TODO: remove this tmp (sread updates the pointer).
1548
osl_int_sread(&tmp, precision, &relation->m[i][j]);
1553
// Build the linked list of union parts.
1555
relation_union = relation;
1559
previous->next = relation;
1562
previous = relation;
1563
read_attributes = 1;
1566
return relation_union;
1571
* osl_relation_sread function:
1572
* this function is equivalent to osl_relation_psread() except that
1573
* the precision corresponds to the precision environment variable or
1574
* to the highest available precision if it is not defined.
1575
* \see{osl_relation_psread}
1577
osl_relation_p osl_relation_sread(char ** input) {
1578
int precision = osl_util_get_precision();
1579
return osl_relation_psread(input, precision);
1584
* osl_relation_read function:
1585
* this function is equivalent to osl_relation_pread() except that
1586
* the precision corresponds to the precision environment variable or
1587
* to the highest available precision if it is not defined.
1588
* \see{osl_relation_pread}
1590
osl_relation_p osl_relation_read(FILE * foo) {
1591
int precision = osl_util_get_precision();
1592
return osl_relation_pread(foo, precision);
1596
/*+***************************************************************************
1597
* Memory allocation/deallocation function *
1598
*****************************************************************************/
1602
* osl_relation_pmalloc function:
1603
* (precision malloc) this function allocates the memory space for an
1604
* osl_relation_t structure and sets its fields with default values.
1605
* Then it returns a pointer to the allocated space.
1606
* \param[in] precision The precision of the constraint matrix.
1607
* \param[in] nb_rows The number of row of the relation to allocate.
1608
* \param[in] nb_columns The number of columns of the relation to allocate.
1609
* \return A pointer to an empty relation with fields set to default values
1610
* and a ready-to-use constraint matrix.
1612
osl_relation_p osl_relation_pmalloc(int precision,
1613
int nb_rows, int nb_columns) {
1614
osl_relation_p relation;
1615
osl_int_t ** p, * q;
1618
if ((precision != OSL_PRECISION_SP) &&
1619
(precision != OSL_PRECISION_DP) &&
1620
(precision != OSL_PRECISION_MP))
1621
OSL_error("unknown precision");
1623
if ((nb_rows < 0) || (nb_columns < 0))
1624
OSL_error("negative sizes");
1626
OSL_malloc(relation, osl_relation_p, sizeof(osl_relation_t));
1627
relation->type = OSL_UNDEFINED;
1628
relation->nb_rows = nb_rows;
1629
relation->nb_columns = nb_columns;
1630
relation->nb_output_dims = OSL_UNDEFINED;
1631
relation->nb_input_dims = OSL_UNDEFINED;
1632
relation->nb_parameters = OSL_UNDEFINED;
1633
relation->nb_local_dims = OSL_UNDEFINED;
1634
relation->precision = precision;
1636
if ((nb_rows == 0) || (nb_columns == 0) ||
1637
(nb_rows == OSL_UNDEFINED) || (nb_columns == OSL_UNDEFINED)) {
1641
OSL_malloc(p, osl_int_t**, nb_rows * sizeof(osl_int_t*));
1642
OSL_malloc(q, osl_int_t*, nb_rows * nb_columns * sizeof(osl_int_t));
1644
for (i = 0; i < nb_rows; i++) {
1645
relation->m[i] = q + i * nb_columns ;
1646
for (j = 0; j < nb_columns; j++)
1647
osl_int_init_set_si(precision, &relation->m[i][j], 0);
1651
relation->next = NULL;
1658
* osl_relation_malloc function:
1659
* this function is equivalent to osl_relation_pmalloc() except that
1660
* the precision corresponds to the precision environment variable or
1661
* to the highest available precision if it is not defined.
1662
* \see{osl_relation_pmalloc}
1664
osl_relation_p osl_relation_malloc(int nb_rows, int nb_columns) {
1665
int precision = osl_util_get_precision();
1666
return osl_relation_pmalloc(precision, nb_rows, nb_columns);
1671
* osl_relation_free_inside function:
1672
* this function frees the allocated memory for the inside of a
1673
* osl_relation_t structure, i.e. only m.
1674
* \param[in] relation The pointer to the relation we want to free internals.
1676
void osl_relation_free_inside(osl_relation_p relation) {
1679
if (relation == NULL)
1682
nb_elements = relation->nb_rows * relation->nb_columns;
1684
for (i = 0; i < nb_elements; i++)
1685
osl_int_clear(relation->precision, &relation->m[0][i]);
1687
if (relation->m != NULL) {
1688
if (nb_elements > 0)
1689
free(relation->m[0]);
1696
* osl_relation_free function:
1697
* this function frees the allocated memory for an osl_relation_t
1699
* \param[in] relation The pointer to the relation we want to free.
1701
void osl_relation_free(osl_relation_p relation) {
1704
while (relation != NULL) {
1705
tmp = relation->next;
1706
osl_relation_free_inside(relation);
1713
/*+***************************************************************************
1714
* Processing functions *
1715
*****************************************************************************/
1719
* osl_relation_nclone function:
1720
* this functions builds and returns a "hard copy" (not a pointer copy) of the
1721
* first n parts of a relation union.
1722
* \param[in] relation The pointer to the relation we want to clone.
1723
* \param[in] n The number of union parts of the relation we want to
1724
* clone (the special value -1 means "all the parts").
1725
* \return A pointer to the clone of the relation union restricted to the
1726
* first n parts of the relation union.
1728
osl_relation_p osl_relation_nclone(osl_relation_p relation, int n) {
1730
int first = 1, nb_components, nb_parts;
1731
osl_relation_p clone = NULL, node, previous = NULL;
1733
nb_components = osl_relation_nb_components(relation);
1734
nb_parts = (n == -1) ? nb_components : n;
1735
if (nb_components < nb_parts)
1736
OSL_error("not enough union parts to clone");
1738
for (k = 0; k < nb_parts; k++) {
1739
node = osl_relation_pmalloc(relation->precision,
1740
relation->nb_rows, relation->nb_columns);
1741
node->type = relation->type;
1742
node->nb_output_dims = relation->nb_output_dims;
1743
node->nb_input_dims = relation->nb_input_dims;
1744
node->nb_local_dims = relation->nb_local_dims;
1745
node->nb_parameters = relation->nb_parameters;
1747
for (i = 0; i < relation->nb_rows; i++)
1748
for (j = 0; j < relation->nb_columns; j++)
1749
osl_int_assign(relation->precision,
1750
&node->m[i][j], relation->m[i][j]);
1758
previous->next = node;
1759
previous = previous->next;
1762
relation = relation->next;
1770
* osl_relation_clone_nconstraints function:
1771
* this functions builds and returns a "hard copy" (not a pointer copy) of a
1772
* osl_relation_t data structure such that the clone is restricted to the
1773
* "n" first rows of the relation. This applies to all the parts in the case
1774
* of a relation union.
1775
* \param[in] relation The pointer to the relation we want to clone.
1776
* \param[in] n The number of row of the relation we want to clone (the
1777
* special value -1 means "all the rows").
1778
* \return A pointer to the clone of the relation union restricted to the
1779
* first n rows of constraint matrix for each part of the union.
1781
osl_relation_p osl_relation_clone_nconstraints(osl_relation_p relation,
1784
int first = 1, all_rows = 0;
1785
osl_relation_p clone = NULL, node, previous = NULL;
1790
while (relation != NULL) {
1792
n = relation->nb_rows;
1794
if (n > relation->nb_rows)
1795
OSL_error("not enough rows to clone in the relation");
1797
node = osl_relation_pmalloc(relation->precision, n, relation->nb_columns);
1798
node->type = relation->type;
1799
node->nb_output_dims = relation->nb_output_dims;
1800
node->nb_input_dims = relation->nb_input_dims;
1801
node->nb_local_dims = relation->nb_local_dims;
1802
node->nb_parameters = relation->nb_parameters;
1804
for (i = 0; i < n; i++)
1805
for (j = 0; j < relation->nb_columns; j++)
1806
osl_int_assign(relation->precision,
1807
&node->m[i][j], relation->m[i][j]);
1815
previous->next = node;
1816
previous = previous->next;
1819
relation = relation->next;
1827
* osl_relation_clone function:
1828
* this function builds and returns a "hard copy" (not a pointer copy) of an
1829
* osl_relation_t data structure (the full union of relation).
1830
* \param[in] relation The pointer to the relation we want to clone.
1831
* \return A pointer to the clone of the union of relations.
1833
osl_relation_p osl_relation_clone(osl_relation_p relation) {
1834
if (relation == NULL)
1837
return osl_relation_nclone(relation, -1);
1842
* osl_relation_add function:
1843
* this function adds a relation (union) at the end of the relation (union)
1844
* pointed by r1. No new relation is created: this functions links the two
1845
* input unions. If the first relation is NULL, it is set to the
1847
* \param[in,out] r1 Pointer to the first relation (union).
1848
* \param[in] r2 The second relation (union).
1850
void osl_relation_add(osl_relation_p *r1, osl_relation_p r2) {
1852
r1 = &((*r1)->next);
1859
* osl_relation_union function:
1860
* this function builds a new relation from two relations provided
1861
* as parameters. The new relation is built as an union of the
1862
* two relations: the list of constraint sets are linked together.
1863
* \param[in] r1 The first relation.
1864
* \param[in] r2 The second relation.
1865
* \return A new relation corresponding to the union of r1 and r2.
1867
osl_relation_p osl_relation_union(osl_relation_p r1,
1868
osl_relation_p r2) {
1869
osl_relation_p copy1, copy2;
1871
if ((r1 == NULL) && (r2 == NULL))
1874
copy1 = osl_relation_clone(r1);
1875
copy2 = osl_relation_clone(r2);
1876
osl_relation_add(©1, copy2);
1883
* osl_relation_replace_vector function:
1884
* this function replaces the "row"^th row of a relation "relation" with the
1885
* vector "vector". It directly updates the relation union part pointed
1886
* by "relation" and this part only.
1887
* \param[in,out] relation The relation we want to replace a row.
1888
* \param[in] vector The vector that will replace a row of the relation.
1889
* \param[in] row The row of the relation to be replaced.
1891
void osl_relation_replace_vector(osl_relation_p relation,
1892
osl_vector_p vector, int row) {
1895
if ((relation == NULL) || (vector == NULL) ||
1896
(relation->precision != vector->precision) ||
1897
(relation->nb_columns != vector->size) ||
1898
(row >= relation->nb_rows) || (row < 0))
1899
OSL_error("vector cannot replace relation row");
1901
for (i = 0; i < vector->size; i++)
1902
osl_int_assign(relation->precision, &relation->m[row][i], vector->v[i]);
1907
* osl_relation_add_vector function:
1908
* this function adds (meaning, +) a vector to the "row"^th row of a
1909
* relation "relation". It directly updates the relation union part pointed
1910
* by "relation" and this part only.
1911
* \param[in,out] relation The relation we want to add a vector to a row.
1912
* \param[in] vector The vector that will replace a row of the relation.
1913
* \param[in] row The row of the relation to add the vector.
1915
void osl_relation_add_vector(osl_relation_p relation,
1916
osl_vector_p vector, int row) {
1919
if ((relation == NULL) || (vector == NULL) ||
1920
(relation->precision != vector->precision) ||
1921
(relation->nb_columns != vector->size) ||
1922
(row >= relation->nb_rows) || (row < 0))
1923
OSL_error("vector cannot be added to relation");
1925
if (osl_int_get_si(relation->precision, relation->m[row][0]) == 0)
1926
osl_int_assign(relation->precision, &relation->m[row][0], vector->v[0]);
1928
for (i = 1; i < vector->size; i++)
1929
osl_int_add(relation->precision,
1930
&relation->m[row][i], relation->m[row][i], vector->v[i]);
1935
* osl_relation_sub_vector function:
1936
* this function subtracts the vector "vector" to the "row"^th row of
1937
* a relation "relation. It directly updates the relation union part pointed
1938
* by "relation" and this part only.
1939
* \param[in,out] relation The relation where to subtract a vector to a row.
1940
* \param[in] vector The vector to subtract to a relation row.
1941
* \param[in] row The row of the relation to subtract the vector.
1943
void osl_relation_sub_vector(osl_relation_p relation,
1944
osl_vector_p vector, int row) {
1947
if ((relation == NULL) || (vector == NULL) ||
1948
(relation->precision != vector->precision) ||
1949
(relation->nb_columns != vector->size) ||
1950
(row >= relation->nb_rows) || (row < 0))
1951
OSL_error("vector cannot be subtracted to row");
1953
if (osl_int_get_si(relation->precision, relation->m[row][0]) == 0)
1954
osl_int_assign(relation->precision, &relation->m[row][0], vector->v[0]);
1956
for (i = 1; i < vector->size; i++)
1957
osl_int_sub(relation->precision,
1958
&relation->m[row][i], relation->m[row][i], vector->v[i]);
1963
* osl_relation_insert_vector function:
1964
* this function inserts a new row corresponding to the vector "vector" to
1965
* the relation "relation" by inserting it at the "row"^th row of
1966
* "relation" (-1 is a shortcut to insert the vector after the constraints
1967
* of the relation). It directly updates the relation union part pointed
1968
* by "relation" and this part only. If "vector" (or "relation") is NULL,
1969
* the relation is left unmodified.
1970
* \param[in,out] relation The relation we want to extend.
1971
* \param[in] vector The vector that will be added relation.
1972
* \param[in] row The row where to insert the vector (-1 to
1973
* insert it after the relation constraints).
1975
void osl_relation_insert_vector(osl_relation_p relation,
1976
osl_vector_p vector, int row) {
1977
osl_relation_p temp;
1979
temp = osl_relation_from_vector(vector);
1980
osl_relation_insert_constraints(relation, temp, row);
1981
osl_relation_free(temp);
1986
* osl_relation_concat_vector function:
1987
* this function builds a new relation from one relation and a vector sent as
1988
* parameters. The new set of constraints is built as the concatenation
1989
* of the rows of the first part of the relation and of the vector
1990
* constraint. This means, there is no next field in the result.
1991
* \param[in] r The input relation.
1992
* \param[in] v The input vector.
1993
* \return A pointer to the relation resulting from the concatenation of
1994
* the constraints of the relation and of the vector.
1996
osl_relation_p osl_relation_concat_vector(osl_relation_p relation,
1997
osl_vector_p vector) {
1998
osl_relation_p new, temp;
2000
temp = osl_relation_from_vector(vector);
2001
new = osl_relation_concat_constraints(relation, temp);
2002
osl_relation_free(temp);
2008
* osl_relation_insert_blank_row function:
2009
* this function inserts a new row filled with zeros o an existing relation
2010
* union part (it only affects the first union part).
2011
* \param[in,out] relation The relation to add a row in.
2012
* \param[in] row The row where to insert the blank row.
2014
void osl_relation_insert_blank_row(osl_relation_p relation, int row) {
2015
osl_vector_p vector;
2017
if (relation != NULL) {
2018
vector = osl_vector_pmalloc(relation->precision, relation->nb_columns);
2019
osl_relation_insert_vector(relation, vector, row);
2020
osl_vector_free(vector);
2026
* osl_relation_insert_blank_column function:
2027
* this function inserts a new column filled with zeros to an existing
2028
* relation union part (it only affects the first union part). WARNING:
2029
* this function does not update the relation attributes.
2030
* \param[in,out] relation The relation to add a column in.
2031
* \param[in] column The column where to insert the blank column.
2033
void osl_relation_insert_blank_column(osl_relation_p relation, int column) {
2036
osl_relation_p temp;
2038
if (relation == NULL)
2041
if ((column < 0) || (column > relation->nb_columns))
2042
OSL_error("bad column number");
2044
// We use a temporary relation just to reuse existing functions. Cleaner.
2045
temp = osl_relation_pmalloc(relation->precision,
2046
relation->nb_rows, relation->nb_columns + 1);
2048
for (i = 0; i < relation->nb_rows; i++) {
2049
for (j = 0; j < column; j++)
2050
osl_int_assign(relation->precision, &temp->m[i][j], relation->m[i][j]);
2052
for (j = column; j < relation->nb_columns; j++)
2053
osl_int_assign(relation->precision, &temp->m[i][j+1], relation->m[i][j]);
2056
osl_relation_free_inside(relation);
2058
// Replace the inside of relation.
2059
relation->nb_columns = temp->nb_columns;
2060
relation->m = temp->m;
2062
// Free the temp "shell".
2068
* osl_relation_from_vector function:
2069
* this function converts a vector "vector" to a relation with a single row
2070
* and returns a pointer to that relation.
2071
* \param[in] vector The vector to convert to a relation.
2072
* \return A pointer to a relation resulting from the vector conversion.
2074
osl_relation_p osl_relation_from_vector(osl_vector_p vector) {
2075
osl_relation_p relation;
2080
relation = osl_relation_pmalloc(vector->precision, 1, vector->size);
2081
osl_relation_replace_vector(relation, vector, 0);
2087
* osl_relation_replace_constraints function:
2088
* this function replaces some rows of a relation "r1" with the rows of
2089
* the relation "r2". It begins at the "row"^th row of "r1". It directly
2090
* updates the relation union part pointed by "r1" and this part only.
2091
* \param[in,out] r1 The relation we want to change some rows.
2092
* \param[in] r2 The relation containing the new rows.
2093
* \param[in] row The first row of the relation r1 to be replaced.
2095
void osl_relation_replace_constraints(osl_relation_p r1,
2096
osl_relation_p r2, int row) {
2099
if ((r1 == NULL) || (r2 == NULL) ||
2100
(r1->precision != r2->precision) ||
2101
(r1->nb_columns != r1->nb_columns) ||
2102
((row + r2->nb_rows) > r1->nb_rows) || (row < 0))
2103
OSL_error("relation rows could not be replaced");
2105
for (i = 0; i < r2->nb_rows; i++)
2106
for (j = 0; j < r2->nb_columns; j++)
2107
osl_int_assign(r1->precision, &r1->m[i+row][j], r2->m[i][j]);
2112
* osl_relation_insert_constraints function:
2113
* this function inserts the rows of the relation "r2" to the relation
2114
* "r1", starting from the "row"^th row of "r1" (-1 is a
2115
* shortcut to insert the "r2" constraints after the constraints of r1).
2116
* It directly updates the relation union part pointed by "r1" and this
2117
* part only. If "r2" (or "r1") is NULL, the relation is left unmodified.
2118
* \param[in,out] r1 The relation we want to extend.
2119
* \param[in] r2 The relation to be inserted.
2120
* \param[in] row The row where to insert the constraints (-1 to
2121
* insert them after those of "r1").
2123
void osl_relation_insert_constraints(osl_relation_p r1,
2124
osl_relation_p r2, int row) {
2126
osl_relation_p temp;
2128
if ((r1 == NULL) || (r2 == NULL))
2134
if ((r1->nb_columns != r2->nb_columns) ||
2135
(r1->precision != r2->precision) ||
2136
(row > r1->nb_rows) || (row < 0))
2137
OSL_error("constraints cannot be inserted");
2139
// We use a temporary relation just to reuse existing functions. Cleaner.
2140
temp = osl_relation_pmalloc(r1->precision,
2141
r1->nb_rows + r2->nb_rows, r1->nb_columns);
2143
for (i = 0; i < row; i++)
2144
for (j = 0; j < r1->nb_columns; j++)
2145
osl_int_assign(r1->precision, &temp->m[i][j], r1->m[i][j]);
2147
osl_relation_replace_constraints(temp, r2, row);
2149
for (i = row + r2->nb_rows; i < r2->nb_rows + r1->nb_rows; i++)
2150
for (j = 0; j < r1->nb_columns; j++)
2151
osl_int_assign(r1->precision, &temp->m[i][j], r1->m[i-r2->nb_rows][j]);
2153
osl_relation_free_inside(r1);
2155
// Replace the inside of relation.
2156
r1->nb_rows = temp->nb_rows;
2159
// Free the temp "shell".
2165
* osl_relation_swap_constraints function:
2166
* this function swaps two constraints (i.e., rows) of the relation matrix.
2167
* This function updates the relation directly.
2168
* \param[in,out] relation The relation to swap two rows (modified).
2169
* \param[in] c1 The row corresponding to the first constraint.
2170
* \param[in] c2 The row corresponding to the second constraint.
2172
void osl_relation_swap_constraints(osl_relation_p relation, int c1, int c2) {
2175
if ((relation == NULL) || (c1 == c2))
2178
if ((c1 >= relation->nb_rows) || (c1 < 0) ||
2179
(c2 >= relation->nb_rows) || (c2 < 0))
2180
OSL_error("bad constraint rows");
2182
for (i = 0; i < relation->nb_columns; i++)
2183
osl_int_swap(relation->precision,
2184
&relation->m[c1][i], &relation->m[c2][i]);
2189
* osl_relation_remove_row function:
2190
* this function removes a given row to the relation "r". It directly
2191
* updates the relation union part pointed by "r" and this part only.
2192
* \param[in,out] r The relation to remove a row.
2193
* \param[in] row The row number to remove.
2195
void osl_relation_remove_row(osl_relation_p r, int row) {
2197
osl_relation_p temp;
2202
if ((row < 0) || (row >= r->nb_rows))
2203
OSL_error("bad row number");
2205
// We use a temporary relation just to reuse existing functions. Cleaner.
2206
temp = osl_relation_pmalloc(r->precision,
2207
r->nb_rows - 1, r->nb_columns);
2209
for (i = 0; i < row; i++)
2210
for (j = 0; j < r->nb_columns; j++)
2211
osl_int_assign(r->precision, &temp->m[i][j], r->m[i][j]);
2213
for (i = row + 1; i < r->nb_rows; i++)
2214
for (j = 0; j < r->nb_columns; j++)
2215
osl_int_assign(r->precision, &temp->m[i - 1][j], r->m[i][j]);
2217
osl_relation_free_inside(r);
2219
// Replace the inside of relation.
2220
r->nb_rows = temp->nb_rows;
2223
// Free the temp "shell".
2229
* osl_relation_remove_column function:
2230
* this function removes a given column to the relation "r". It directly
2231
* updates the relation union part pointed by "r" and this part only.
2232
* \param[in,out] r The relation to remove a column.
2233
* \param[in] column The column number to remove.
2235
void osl_relation_remove_column(osl_relation_p r, int column) {
2237
osl_relation_p temp;
2242
if ((column < 0) || (column >= r->nb_columns))
2243
OSL_error("bad column number");
2245
// We use a temporary relation just to reuse existing functions. Cleaner.
2246
temp = osl_relation_pmalloc(r->precision,
2247
r->nb_rows, r->nb_columns - 1);
2249
for (i = 0; i < r->nb_rows; i++) {
2250
for (j = 0; j < column; j++)
2251
osl_int_assign(r->precision, &temp->m[i][j], r->m[i][j]);
2253
for (j = column + 1; j < r->nb_columns; j++)
2254
osl_int_assign(r->precision, &temp->m[i][j - 1], r->m[i][j]);
2257
osl_relation_free_inside(r);
2259
// Replace the inside of relation.
2260
r->nb_rows = temp->nb_rows;
2263
// Free the temp "shell".
2269
* osl_relation_insert_columns function:
2270
* this function inserts new columns to an existing relation union part (it
2271
* only affects the first union part). The columns are copied out from the
2272
* matrix of an input relation which must have the convenient number of rows.
2273
* All columns of the input matrix are copied. WARNING: this function does not
2274
* update the relation attributes of the modified matrix.
2275
* \param[in,out] relation The relation to add columns in.
2276
* \param[in] insert The relation containing the columns to add.
2277
* \param[in] column The column where to insert the new columns.
2279
void osl_relation_insert_columns(osl_relation_p relation,
2280
osl_relation_p insert, int column) {
2282
osl_relation_p temp;
2284
if ((relation == NULL) || (insert == NULL))
2287
if ((relation->precision != insert->precision) ||
2288
(relation->nb_rows != insert->nb_rows) ||
2289
(column < 0) || (column > relation->nb_columns))
2290
OSL_error("columns cannot be inserted");
2292
// We use a temporary relation just to reuse existing functions. Cleaner.
2293
temp = osl_relation_pmalloc(relation->precision, relation->nb_rows,
2294
relation->nb_columns + insert->nb_columns);
2296
for (i = 0; i < relation->nb_rows; i++) {
2297
for (j = 0; j < column; j++)
2298
osl_int_assign(relation->precision, &temp->m[i][j], relation->m[i][j]);
2300
for (j = column; j < column + insert->nb_columns; j++)
2301
osl_int_assign(relation->precision,
2302
&temp->m[i][j], insert->m[i][j - column]);
2304
for (j = column + insert->nb_columns;
2305
j < insert->nb_columns + relation->nb_columns; j++)
2306
osl_int_assign(relation->precision,
2307
&temp->m[i][j], relation->m[i][j - insert->nb_columns]);
2310
osl_relation_free_inside(relation);
2312
// Replace the inside of relation.
2313
relation->nb_columns = temp->nb_columns;
2314
relation->m = temp->m;
2316
// Free the temp "shell".
2322
* osl_relation_concat_constraints function:
2323
* this function builds a new relation from two relations sent as
2324
* parameters. The new set of constraints is built as the concatenation
2325
* of the rows of the first elements of the two relation unions r1 and r2.
2326
* This means, there is no next field in the result.
2327
* \param[in] r1 The first relation.
2328
* \param[in] r2 The second relation.
2329
* \return A pointer to the relation resulting from the concatenation of
2330
* the first elements of r1 and r2.
2332
osl_relation_p osl_relation_concat_constraints(
2334
osl_relation_p r2) {
2338
return osl_relation_clone(r2);
2341
return osl_relation_clone(r1);
2343
if (r1->nb_columns != r2->nb_columns)
2344
OSL_error("incompatible sizes for concatenation");
2346
if (r1->next || r2->next)
2347
OSL_warning("relation concatenation is done on the first elements "
2350
new = osl_relation_pmalloc(r1->precision,
2351
r1->nb_rows + r2->nb_rows, r1->nb_columns);
2352
osl_relation_replace_constraints(new, r1, 0);
2353
osl_relation_replace_constraints(new, r2, r1->nb_rows);
2360
* osl_relation_part_equal function:
2361
* this function returns true if the two relations parts provided as
2362
* parameters are the same, false otherwise. In the case of relation
2363
* unions, only the first part of the two relations are tested.
2364
* \param[in] r1 The first relation.
2365
* \param[in] r2 The second relation.
2366
* \return 1 if r1 and r2 are the same (content-wise), 0 otherwise.
2368
int osl_relation_part_equal(osl_relation_p r1, osl_relation_p r2) {
2374
if (((r1 == NULL) && (r2 != NULL)) ||
2375
((r1 != NULL) && (r2 == NULL)))
2378
if ((r1->type != r2->type) ||
2379
(r1->precision != r2->precision) ||
2380
(r1->nb_rows != r2->nb_rows) ||
2381
(r1->nb_columns != r2->nb_columns) ||
2382
(r1->nb_output_dims != r2->nb_output_dims) ||
2383
(r1->nb_input_dims != r2->nb_input_dims) ||
2384
(r1->nb_local_dims != r2->nb_local_dims) ||
2385
(r1->nb_parameters != r2->nb_parameters))
2388
for (i = 0; i < r1->nb_rows; ++i)
2389
for (j = 0; j < r1->nb_columns; ++j)
2390
if (osl_int_ne(r1->precision, r1->m[i][j], r2->m[i][j]))
2398
* osl_relation_equal function:
2399
* this function returns true if the two relations provided as parameters
2400
* are the same, false otherwise.
2401
* \param[in] r1 The first relation.
2402
* \param[in] r2 The second relation.
2403
* \return 1 if r1 and r2 are the same (content-wise), 0 otherwise.
2405
int osl_relation_equal(osl_relation_p r1, osl_relation_p r2) {
2406
while ((r1 != NULL) && (r2 != NULL)) {
2407
if (!osl_relation_part_equal(r1, r2))
2414
if (((r1 == NULL) && (r2 != NULL)) || ((r1 != NULL) && (r2 == NULL)))
2422
* osl_relation_check_attribute internal function:
2423
* This function checks whether an "actual" value is the same as an
2424
* "expected" value or not. If the expected value is set to
2425
* OSL_UNDEFINED, this function sets it to the "actual" value
2426
* and do not report a difference has been detected.
2427
* It returns 0 if a difference has been detected, 1 otherwise.
2428
* \param[in,out] expected Pointer to the expected value (the value is
2429
* modified if it was set to OSL_UNDEFINED).
2430
* \param[in] actual Value we want to check.
2431
* \return 0 if the values are not the same while the expected value was
2432
* not OSL_UNDEFINED, 1 otherwise.
2435
int osl_relation_check_attribute(int * expected, int actual) {
2436
if (*expected != OSL_UNDEFINED) {
2437
if ((actual != OSL_UNDEFINED) &&
2438
(actual != *expected)) {
2439
OSL_warning("unexpected atribute");
2452
* osl_relation_check_nb_columns internal function:
2453
* This function checks that the number of columns of a relation
2454
* corresponds to some expected properties (setting an expected property to
2455
* OSL_UNDEFINED makes this function unable to detect a problem).
2456
* It returns 0 if the number of columns seems incorrect or 1 if no problem
2457
* has been detected.
2458
* \param[in] relation The relation we want to check the number of columns.
2459
* \param[in] expected_nb_output_dims Expected number of output dimensions.
2460
* \param[in] expected_nb_input_dims Expected number of input dimensions.
2461
* \param[in] expected_nb_parameters Expected number of parameters.
2462
* \return 0 if the number of columns seems incorrect, 1 otherwise.
2465
int osl_relation_check_nb_columns(osl_relation_p relation,
2466
int expected_nb_output_dims,
2467
int expected_nb_input_dims,
2468
int expected_nb_parameters) {
2469
int expected_nb_local_dims, expected_nb_columns;
2471
if ((expected_nb_output_dims != OSL_UNDEFINED) &&
2472
(expected_nb_input_dims != OSL_UNDEFINED) &&
2473
(expected_nb_parameters != OSL_UNDEFINED)) {
2475
if (relation->nb_local_dims == OSL_UNDEFINED)
2476
expected_nb_local_dims = 0;
2478
expected_nb_local_dims = relation->nb_local_dims;
2480
expected_nb_columns = expected_nb_output_dims +
2481
expected_nb_input_dims +
2482
expected_nb_local_dims +
2483
expected_nb_parameters +
2486
if (expected_nb_columns != relation->nb_columns) {
2487
OSL_warning("unexpected number of columns");
2497
* osl_relation_integrity_check function:
2498
* this function checks that a relation is "well formed" according to some
2499
* expected properties (setting an expected value to OSL_UNDEFINED means
2500
* that we do not expect a specific value) and what the relation is supposed
2501
* to represent. It returns 0 if the check failed or 1 if no problem has been
2503
* \param[in] relation The relation we want to check.
2504
* \param[in] expected_type Semantics about this relation (domain, access...).
2505
* \param[in] expected_nb_output_dims Expected number of output dimensions.
2506
* \param[in] expected_nb_input_dims Expected number of input dimensions.
2507
* \param[in] expected_nb_parameters Expected number of parameters.
2508
* \return 0 if the integrity check fails, 1 otherwise.
2510
int osl_relation_integrity_check(osl_relation_p relation,
2512
int expected_nb_output_dims,
2513
int expected_nb_input_dims,
2514
int expected_nb_parameters) {
2517
// Check the NULL case.
2518
if (relation == NULL) {
2519
if ((expected_nb_output_dims != OSL_UNDEFINED) ||
2520
(expected_nb_input_dims != OSL_UNDEFINED) ||
2521
(expected_nb_parameters != OSL_UNDEFINED)) {
2522
OSL_debug("NULL relation with some expected attibutes");
2530
if (((expected_type != OSL_TYPE_ACCESS) &&
2531
(expected_type != relation->type)) ||
2532
((expected_type == OSL_TYPE_ACCESS) &&
2533
(!osl_relation_is_access(relation)))) {
2534
OSL_warning("wrong type");
2535
osl_relation_dump(stderr, relation);
2539
// Check that relations have no undefined atributes.
2540
if ((relation->nb_output_dims == OSL_UNDEFINED) ||
2541
(relation->nb_input_dims == OSL_UNDEFINED) ||
2542
(relation->nb_local_dims == OSL_UNDEFINED) ||
2543
(relation->nb_parameters == OSL_UNDEFINED)) {
2544
OSL_warning("all attributes should be defined");
2545
osl_relation_dump(stderr, relation);
2549
// Check that a context has actually 0 output dimensions.
2550
if ((relation->type == OSL_TYPE_CONTEXT) &&
2551
(relation->nb_output_dims != 0)) {
2552
OSL_warning("context without 0 as number of output dimensions");
2553
osl_relation_dump(stderr, relation);
2557
// Check that a domain or a context has actually 0 input dimensions.
2558
if (((relation->type == OSL_TYPE_DOMAIN) ||
2559
(relation->type == OSL_TYPE_CONTEXT)) &&
2560
(relation->nb_input_dims != 0)) {
2561
OSL_warning("domain or context without 0 input dimensions");
2562
osl_relation_dump(stderr, relation);
2566
// Check properties according to expected values (and if expected values
2567
// are undefined, define them with the first relation part properties).
2568
if (!osl_relation_check_attribute(&expected_nb_output_dims,
2569
relation->nb_output_dims) ||
2570
!osl_relation_check_attribute(&expected_nb_input_dims,
2571
relation->nb_input_dims) ||
2572
!osl_relation_check_attribute(&expected_nb_parameters,
2573
relation->nb_parameters)) {
2574
osl_relation_dump(stderr, relation);
2578
while (relation != NULL) {
2580
// Attributes (except the number of local dimensions) should be the same
2581
// in all parts of the union.
2582
if ((expected_nb_output_dims != relation->nb_output_dims) ||
2583
(expected_nb_input_dims != relation->nb_input_dims) ||
2584
(expected_nb_parameters != relation->nb_parameters)) {
2585
OSL_warning("inconsistent attributes");
2586
osl_relation_dump(stderr, relation);
2590
// Check whether the number of columns is OK or not.
2591
if (!osl_relation_check_nb_columns(relation,
2592
expected_nb_output_dims,
2593
expected_nb_input_dims,
2594
expected_nb_parameters)) {
2595
osl_relation_dump(stderr, relation);
2599
// Check the first column. The first column of a relation part should be
2600
// made of 0 or 1 only.
2601
if ((relation->nb_rows > 0) && (relation->nb_columns > 0)) {
2602
for (i = 0; i < relation->nb_rows; i++) {
2603
if (!osl_int_zero(relation->precision, relation->m[i][0]) &&
2604
!osl_int_one(relation->precision, relation->m[i][0])) {
2605
OSL_warning("first column of a relation is not "
2606
"strictly made of 0 or 1");
2607
osl_relation_dump(stderr, relation);
2613
// Array accesses must provide the array identifier.
2614
if ((osl_relation_is_access(relation)) &&
2615
(osl_relation_get_array_id(relation) == OSL_UNDEFINED)) {
2616
osl_relation_dump(stderr, relation);
2620
relation = relation->next;
2628
* osl_relation_set_attributes_one function:
2629
* this functions sets the attributes of a relation part provided as a
2630
* parameter. It updates the relation directly.
2631
* \param[in,out] relation The relation (union part) to set the attributes.
2632
* \param[in] nb_output_dims Number of output dimensions.
2633
* \param[in] nb_input_dims Number of input dimensions.
2634
* \param[in] nb_local_dims Number of local dimensions.
2635
* \param[in] nb_parameters Number of parameters.
2637
void osl_relation_set_attributes_one(osl_relation_p relation,
2638
int nb_output_dims, int nb_input_dims,
2639
int nb_local_dims, int nb_parameters) {
2640
if (relation != NULL) {
2641
relation->nb_output_dims = nb_output_dims;
2642
relation->nb_input_dims = nb_input_dims;
2643
relation->nb_local_dims = nb_local_dims;
2644
relation->nb_parameters = nb_parameters;
2650
* osl_relation_set_attributes function:
2651
* this functions sets the attributes of a relation (union) provided
2652
* as a parameter. It updates the relation directly.
2653
* \param[in,out] relation The relation (union) to set the attributes.
2654
* \param[in] nb_output_dims Number of output dimensions.
2655
* \param[in] nb_input_dims Number of input dimensions.
2656
* \param[in] nb_local_dims Number of local dimensions.
2657
* \param[in] nb_parameters Number of parameters.
2659
void osl_relation_set_attributes(osl_relation_p relation,
2660
int nb_output_dims, int nb_input_dims,
2661
int nb_local_dims, int nb_parameters) {
2662
while (relation != NULL) {
2663
osl_relation_set_attributes_one(relation,
2664
nb_output_dims, nb_input_dims,
2665
nb_local_dims, nb_parameters);
2666
relation = relation->next;
2672
* osl_relation_set_type function:
2673
* this function sets the type of each relation union part in the relation
2674
* to the one provided as parameter.
2675
* \param relation The relation to set the type.
2676
* \param type The type.
2678
void osl_relation_set_type(osl_relation_p relation, int type) {
2680
while (relation != NULL) {
2681
relation->type = type;
2682
relation = relation->next;
2688
* osl_relation_get_array_id function:
2689
* this function returns the array identifier in a relation with access type
2690
* It returns OSL_UNDEFINED if it is not able to find it (in particular
2691
* if there are irregularities in the relation).
2692
* \param[in] relation The relation where to find an array identifier.
2693
* \return The array identifier in the relation or OSL_UNDEFINED.
2695
int osl_relation_get_array_id(osl_relation_p relation) {
2698
int array_id = OSL_UNDEFINED;
2699
int reference_array_id = OSL_UNDEFINED;
2704
if (relation == NULL)
2705
return OSL_UNDEFINED;
2707
if (!osl_relation_is_access(relation)) {
2708
OSL_warning("asked for an array id of non-array relation");
2709
return OSL_UNDEFINED;
2712
while (relation != NULL) {
2713
precision = relation->precision;
2715
// There should be room to store the array identifier.
2716
if ((relation->nb_rows < 1) ||
2717
(relation->nb_columns < 3)) {
2718
OSL_warning("no array identifier in an access function");
2719
return OSL_UNDEFINED;
2722
// Array identifiers are m[i][#columns -1] / m[i][1], with i the only row
2723
// where m[i][1] is not 0.
2724
// - check there is exactly one row such that m[i][1] is not 0,
2725
// - check the whole ith row if full of 0 except m[i][1] and the id,
2726
// - check that (m[i][#columns -1] % m[i][1]) == 0,
2727
// - check that (-m[i][#columns -1] / m[i][1]) > 0.
2729
for (i = 0; i < relation->nb_rows; i++) {
2730
if (!osl_int_zero(precision, relation->m[i][1])) {
2735
if (nb_array_id == 0) {
2736
OSL_warning("no array identifier in an access function");
2737
return OSL_UNDEFINED;
2739
if (nb_array_id > 1) {
2740
OSL_warning("several array identifiers in one access function");
2741
return OSL_UNDEFINED;
2743
for (i = 0; i < relation->nb_columns - 1; i++) {
2744
if ((i != 1) && !osl_int_zero(precision, relation->m[row_id][i])) {
2745
OSL_warning("non integer array identifier");
2746
return OSL_UNDEFINED;
2749
if (!osl_int_divisible(precision,
2750
relation->m[row_id][relation->nb_columns - 1],
2751
relation->m[row_id][1])) {
2752
OSL_warning("rational array identifier");
2753
return OSL_UNDEFINED;
2755
array_id = -osl_int_get_si(precision,
2756
relation->m[row_id][relation->nb_columns - 1]);
2757
array_id /= osl_int_get_si(precision, relation->m[row_id][1]);
2758
if (array_id <= 0) {
2759
OSL_warning("negative or 0 identifier in access function");
2760
return OSL_UNDEFINED;
2763
// Unions of accesses are allowed, but they should refer at the same array.
2765
reference_array_id = array_id;
2769
if (reference_array_id != array_id) {
2770
OSL_warning("inconsistency of array identifiers in an "
2771
"union of access relations");
2772
return OSL_UNDEFINED;
2776
relation = relation->next;
2784
* osl_relation_is_access function:
2785
* this function returns 1 if the relation corresponds to an access relation,
2786
* whatever its precise type (read, write etc.), 0 otherwise.
2787
* \param relation The relation to check wheter it is an access relation or not.
2788
* \return 1 if the relation is an access relation, 0 otherwise.
2790
int osl_relation_is_access(osl_relation_p relation) {
2792
if (relation == NULL)
2795
if ((relation->type == OSL_TYPE_ACCESS) ||
2796
(relation->type == OSL_TYPE_READ) ||
2797
(relation->type == OSL_TYPE_WRITE) ||
2798
(relation->type == OSL_TYPE_MAY_WRITE))
2806
* osl_relation_get_attributes function:
2807
* this function returns, through its parameters, the maximum values of the
2808
* relation attributes (nb_iterators, nb_parameters etc), depending on its
2809
* type. HOWEVER, it updates the parameter value iff the attribute is greater
2810
* than the input parameter value. Hence it may be used to get the
2811
* attributes as well as to find the maximum attributes for several relations.
2812
* The array identifier 0 is used when there is no array identifier (AND this
2813
* is OK), OSL_UNDEFINED is used to report it is impossible to provide the
2814
* property while it should. This function is not intended for checking, the
2815
* input relation should be correct.
2816
* \param[in] relation The relation to extract attribute values.
2817
* \param[in,out] nb_parameters Number of parameter attribute.
2818
* \param[in,out] nb_iterators Number of iterators attribute.
2819
* \param[in,out] nb_scattdims Number of scattering dimensions attribute.
2820
* \param[in,out] nb_localdims Number of local dimensions attribute.
2821
* \param[in,out] array_id Maximum array identifier attribute.
2823
void osl_relation_get_attributes(osl_relation_p relation,
2824
int * nb_parameters,
2830
int local_nb_parameters = OSL_UNDEFINED;
2831
int local_nb_iterators = OSL_UNDEFINED;
2832
int local_nb_scattdims = OSL_UNDEFINED;
2833
int local_nb_localdims = OSL_UNDEFINED;
2834
int local_array_id = OSL_UNDEFINED;
2836
while (relation != NULL) {
2837
if (osl_relation_is_access(relation))
2838
type = OSL_TYPE_ACCESS;
2840
type = relation->type;
2842
// There is some redundancy but I believe the code is cleaner this way.
2844
case OSL_TYPE_CONTEXT:
2845
local_nb_parameters = relation->nb_parameters;
2846
local_nb_iterators = 0;
2847
local_nb_scattdims = 0;
2848
local_nb_localdims = relation->nb_local_dims;
2852
case OSL_TYPE_DOMAIN:
2853
local_nb_parameters = relation->nb_parameters;
2854
local_nb_iterators = relation->nb_output_dims;
2855
local_nb_scattdims = 0;
2856
local_nb_localdims = relation->nb_local_dims;
2860
case OSL_TYPE_SCATTERING:
2861
local_nb_parameters = relation->nb_parameters;
2862
local_nb_iterators = relation->nb_input_dims;
2863
local_nb_scattdims = relation->nb_output_dims;
2864
local_nb_localdims = relation->nb_local_dims;
2868
case OSL_TYPE_ACCESS:
2869
local_nb_parameters = relation->nb_parameters;
2870
local_nb_iterators = relation->nb_input_dims;
2871
local_nb_scattdims = 0;
2872
local_nb_localdims = relation->nb_local_dims;
2873
local_array_id = osl_relation_get_array_id(relation);
2877
local_nb_parameters = relation->nb_parameters;
2878
local_nb_iterators = relation->nb_input_dims;
2879
local_nb_scattdims = relation->nb_output_dims;
2880
local_nb_localdims = relation->nb_local_dims;
2885
*nb_parameters = OSL_max(*nb_parameters, local_nb_parameters);
2886
*nb_iterators = OSL_max(*nb_iterators, local_nb_iterators);
2887
*nb_scattdims = OSL_max(*nb_scattdims, local_nb_scattdims);
2888
*nb_localdims = OSL_max(*nb_localdims, local_nb_localdims);
2889
*array_id = OSL_max(*array_id, local_array_id);
2890
relation = relation->next;
2896
* osl_relation_extend_output function:
2897
* this function extends the number of output dimensions of a given relation. It
2898
* returns a copy of the input relation with a number of output dimensions
2899
* extended to "dim" for all its union components. The new output dimensions
2900
* are simply set equal to 0. The extended number of dimensions must be higher
2901
* than or equal to the original one (an error will be raised otherwise).
2902
* \param[in] relation The input relation to extend.
2903
* \param[in] dim The number of output dimension to reach.
2904
* \return A new relation: "relation" extended to "dim" output dims.
2906
osl_relation_p osl_relation_extend_output(osl_relation_p relation, int dim) {
2910
int precision = relation->precision;
2911
osl_relation_p extended = NULL, node, previous = NULL;
2913
while (relation != NULL) {
2914
if (relation->nb_output_dims > dim)
2915
OSL_error("Number of output dims is greater than required extension");
2916
offset = dim - relation->nb_output_dims;
2918
node = osl_relation_pmalloc(precision,
2919
relation->nb_rows + offset,
2920
relation->nb_columns + offset);
2922
node->type = relation->type;
2923
node->nb_output_dims = OSL_max(relation->nb_output_dims, dim);
2924
node->nb_input_dims = relation->nb_input_dims;
2925
node->nb_local_dims = relation->nb_local_dims;
2926
node->nb_parameters = relation->nb_parameters;
2928
// Copy of the original relation with some 0 columns for the new dimensions
2929
// Note that we use the fact that the matrix is initialized with zeros.
2930
for (i = 0; i < relation->nb_rows; i++) {
2931
for (j = 0; j <= relation->nb_output_dims; j++)
2932
osl_int_assign(precision, &node->m[i][j], relation->m[i][j]);
2934
for (j = relation->nb_output_dims + offset + 1;
2935
j < relation->nb_columns + offset; j++)
2936
osl_int_assign(precision, &node->m[i][j], relation->m[i][j - offset]);
2939
// New rows dedicated to the new dimensions
2940
for (i = relation->nb_rows; i < relation->nb_rows + offset; i++) {
2941
for (j = 0; j < relation->nb_columns + offset; j++) {
2942
if ((i - relation->nb_rows) == (j - relation->nb_output_dims - 1))
2943
osl_int_set_si(precision, &node->m[i][j], -1);
2953
previous->next = node;
2954
previous = previous->next;
2957
relation = relation->next;
2965
* osl_relation_interface function:
2966
* this function creates an interface structure corresponding to the relation
2968
* \return An interface structure for the relation structure.
2970
osl_interface_p osl_relation_interface() {
2971
osl_interface_p interface = osl_interface_malloc();
2973
interface->URI = strdup(OSL_URI_RELATION);
2974
interface->idump = (osl_idump_f)osl_relation_idump;
2975
interface->sprint = (osl_sprint_f)osl_relation_sprint;
2976
interface->sread = (osl_sread_f)osl_relation_sread;
2977
interface->malloc = (osl_malloc_f)osl_relation_malloc;
2978
interface->free = (osl_free_f)osl_relation_free;
2979
interface->clone = (osl_clone_f)osl_relation_clone;
2980
interface->equal = (osl_equal_f)osl_relation_equal;