Deactivate totally relation comments
[openscop.git] / source / relation.c
blob99d62515c0a24a6b64e7ddd5586c531d3d5b317d
2 /*+-----------------------------------------------------------------**
3 ** OpenScop Library **
4 **-----------------------------------------------------------------**
5 ** relation.c **
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 * '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---' '--' *
29 * *
30 * Copyright (C) 2008 University Paris-Sud 11 and INRIA *
31 * *
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 *
35 * are met: *
36 * *
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. *
44 * *
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. *
55 * *
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> *
60 * *
61 *****************************************************************************/
64 # include <stdlib.h>
65 # include <stdio.h>
66 # include <string.h>
67 # include <ctype.h>
68 # include <openscop/relation.h>
71 /*+***************************************************************************
72 * Structure display function *
73 *****************************************************************************/
76 /**
77 * openscop_relation_print_type function:
78 * this function displays the textual type of an openscop_relation_t structure
79 * into a file (file, possibly stdout), accoding to the OpenScop specification.
80 * \param[in] file File where informations are printed.
81 * \param[in] relation The relation whose type has to be printed.
83 static
84 void openscop_relation_print_type(FILE * file, openscop_relation_p relation) {
86 if (relation != NULL) {
87 switch (relation->type) {
88 case OPENSCOP_UNDEFINED: {
89 fprintf(file, OPENSCOP_STRING_UNDEFINED);
90 break;
92 case OPENSCOP_TYPE_CONTEXT: {
93 fprintf(file, OPENSCOP_STRING_CONTEXT);
94 break;
96 case OPENSCOP_TYPE_DOMAIN: {
97 fprintf(file, OPENSCOP_STRING_DOMAIN);
98 break;
100 case OPENSCOP_TYPE_SCATTERING: {
101 fprintf(file, OPENSCOP_STRING_SCATTERING);
102 break;
104 case OPENSCOP_TYPE_READ: {
105 fprintf(file, OPENSCOP_STRING_READ);
106 break;
108 case OPENSCOP_TYPE_WRITE: {
109 fprintf(file, OPENSCOP_STRING_WRITE);
110 break;
112 case OPENSCOP_TYPE_RDWR: {
113 fprintf(file, OPENSCOP_STRING_RDWR);
114 break;
116 case OPENSCOP_TYPE_MAY_READ: {
117 fprintf(file, OPENSCOP_STRING_MAY_READ);
118 break;
120 case OPENSCOP_TYPE_MAY_WRITE: {
121 fprintf(file, OPENSCOP_STRING_MAY_WRITE);
122 break;
124 case OPENSCOP_TYPE_MAY_RDWR: {
125 fprintf(file, OPENSCOP_STRING_MAY_RDWR);
126 break;
128 default: {
129 fprintf(stderr, "[OpenScop] Warning: unknown relation type (%d) "
130 "replaced with "OPENSCOP_STRING_UNDEFINED".\n",
131 relation->type);
132 fprintf(file, OPENSCOP_STRING_UNDEFINED);
140 * openscop_relation_idump function:
141 * this function displays a openscop_relation_t structure (*relation) into a
142 * file (file, possibly stdout) in a way that trends to be understandable.
143 * It includes an indentation level (level) in order to work with others
144 * print_structure functions.
145 * \param[in] file File where informations are printed.
146 * \param[in] relation The relation whose information has to be printed.
147 * \param[in] level Number of spaces before printing, for each line.
149 void openscop_relation_idump(FILE * file,
150 openscop_relation_p relation,
151 int level) {
152 int i, j, first = 1;
154 // Go to the right level.
155 for (j = 0; j < level; j++)
156 fprintf(file, "|\t");
158 if (relation != NULL) {
159 fprintf(file, "+-- openscop_relation_t (");
160 openscop_relation_print_type(file, relation);
161 fprintf(file, ")\n");
163 else {
164 fprintf(file, "+-- NULL relation\n");
167 while (relation != NULL) {
168 if (! first) {
169 // Go to the right level.
170 for (j = 0; j < level; j++)
171 fprintf(file, "|\t");
172 fprintf(file, "| openscop_relation_t (");
173 openscop_relation_print_type(file, relation);
174 fprintf(file, ")\n");
176 else
177 first = 0;
179 // A blank line
180 for(j = 0; j <= level; j++)
181 fprintf(file, "|\t");
182 fprintf(file, "%d %d %d %d %d %d\n",
183 relation->nb_rows, relation->nb_columns,
184 relation->nb_output_dims, relation->nb_input_dims,
185 relation->nb_local_dims, relation->nb_parameters);
187 // Display the relation.
188 for (i = 0; i < relation->nb_rows; i++) {
189 for (j = 0; j <= level; j++)
190 fprintf(file, "|\t");
192 fprintf(file, "[ ");
194 for (j = 0; j < relation->nb_columns; j++) {
195 SCOPINT_dump(file, OPENSCOP_FMT, relation->m[i][j]);
196 fprintf(file, " ");
199 fprintf(file, "]\n");
202 relation = relation->next;
204 // Next line.
205 if (relation != NULL) {
206 for (j = 0; j <= level; j++)
207 fprintf(file, "|\t");
208 fprintf(file, "|\n");
209 for (j = 0; j <= level; j++)
210 fprintf(file, "|\t");
211 fprintf(file, "V\n");
215 // The last line.
216 for (j = 0; j <= level; j++)
217 fprintf(file, "|\t");
218 fprintf(file, "\n");
223 * openscop_relation_dump function:
224 * this function prints the content of a openscop_relation_t structure
225 * (*relation) into a file (file, possibly stdout).
226 * \param[in] file File where informations are printed.
227 * \param[in] relation The relation whose information have to be printed.
229 void openscop_relation_dump(FILE * file, openscop_relation_p relation) {
230 openscop_relation_idump(file, relation, 0);
236 * openscop_relation_expression_element function:
237 * this function returns a string containing the printing of a value (possibly
238 * an iterator or a parameter with its coefficient or a constant).
239 * \param[in] val The coefficient or constant value.
240 * \param[in,out] first Pointer to a boolean set to 1 if the current value is
241 * the first of an expresion, 0 otherwise (maybe updated).
242 * \param[in] cst A boolean set to 1 if the value is a constant,
243 * 0 otherwise.
244 * \param[in] name String containing the name of the element.
245 * \return A string that contains the printing of a value.
247 static
248 char * openscop_relation_expression_element(openscop_int_t val, int * first,
249 int cst, char * name) {
250 char * temp = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
251 char * body = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
252 char * sval = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
254 body[0] = '\0';
255 sval[0] = '\0';
257 // statements for the 'normal' processing.
258 if (SCOPINT_notzero_p(val) && (!cst)) {
259 if ((*first) || SCOPINT_neg_p(val)) {
260 if (SCOPINT_one_p(val)) { // case 1
261 sprintf(sval, "%s", name);
263 else {
264 if (SCOPINT_mone_p(val)) { // case -1
265 sprintf(sval, "-%s", name);
267 else { // default case
268 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
269 sprintf(temp, "*%s", name);
270 strcat(sval, temp);
273 *first = 0;
275 else {
276 if (SCOPINT_one_p(val)) {
277 sprintf(sval, "+%s", name);
279 else {
280 sprintf(sval, "+");
281 SCOPINT_sprint(temp, OPENSCOP_FMT_TXT, val);
282 strcat(sval, temp);
283 sprintf(temp, "*%s", name);
284 strcat(sval, temp);
288 else {
289 if (cst) {
290 if ((SCOPINT_zero_p(val) && (*first)) || SCOPINT_neg_p(val))
291 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
292 if (SCOPINT_pos_p(val)) {
293 if (!(*first)) {
294 SCOPINT_sprint(sval, "+"OPENSCOP_FMT_TXT, val); // Block macro !
296 else {
297 SCOPINT_sprint(sval, OPENSCOP_FMT_TXT, val);
302 free(temp);
303 free(body);
305 return(sval);
310 * openscop_relation_expression function:
311 * this function returns a string corresponding to an affine expression
312 * stored at the "row"^th row of the relation pointed by "relation".
313 * \param[in] relation A set of linear expressions.
314 * \param[in] row The row corresponding to the expression.
315 * \param[in] names The textual names of the various elements. Is is
316 * important that names->nb_parameters is exact if the
317 * matrix representation is used. Set to NULL if
318 * printing comments is not needed.
319 * \return A string that contains the printing of an affine expression.
321 char * openscop_relation_expression(openscop_relation_p relation,
322 int row, openscop_names_p names) {
323 int i, first = 1;
324 char * sval;
325 char * sline = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
326 sline[0] = '\0';
328 // First the iterator part.
329 for (i = 1; i <= names->nb_iterators; i++) {
330 sval = openscop_relation_expression_element(
331 relation->m[row][i], &first, 0, names->iterators[i-1]);
332 strcat(sline, sval);
333 free(sval);
336 // Next the local dims part.
337 for (i = names->nb_iterators + 1;
338 i <= names->nb_iterators + names->nb_localdims; i++) {
339 sval = openscop_relation_expression_element(
340 relation->m[row][i], &first, 0,
341 names->localdims[i - names->nb_iterators - 1]);
342 strcat(sline, sval);
343 free(sval);
346 // Next the parameter part.
347 for (i = names->nb_iterators + names->nb_localdims + 1;
348 i <= names->nb_iterators + names->nb_localdims + names->nb_parameters;
349 i++) {
350 sval = openscop_relation_expression_element(
351 relation->m[row][i], &first, 0,
352 names->parameters[i - names->nb_iterators - names->nb_localdims - 1]);
353 strcat(sline, sval);
354 free(sval);
357 // Finally the constant part (yes, I reused it).
358 sval = openscop_relation_expression_element(relation->m[row][i],
359 &first, 1, NULL);
360 strcat(sline, sval);
361 free(sval);
363 return sline;
368 * openscop_relation_properties function:
369 * this function returns, through its parameters, the values of every possible
370 * "property" (nb_iterators, nb_parameters etc) of a relation, depending on
371 * its value, its representation and its type. The array identifier 0 is used
372 * when there is no array identifier (AND this is OK), OPENSCOP_UNDEFINED is
373 * used to report it is impossible to provide the property while it should.
374 * This function is not intended for checking, the input relation should be
375 * correct. The parameter nb_parameters is an input in matrix representation.
376 * \param[in] relation The relation to extract property values.
377 * \param[in,out] nb_parameters Number of parameter property.
378 * \param[out] nb_iterators Number of iterators property.
379 * \param[out] nb_scattdims Number of scattering dimensions property.
380 * \param[out] nb_localdims Number of local dimensions property.
381 * \param[out] array_id Array identifier property.
383 static
384 void openscop_relation_properties(openscop_relation_p relation,
385 int * nb_parameters,
386 int * nb_iterators,
387 int * nb_scattdims,
388 int * nb_localdims,
389 int * array_id) {
391 int is_matrix = openscop_relation_is_matrix(relation);
392 int type;
394 if (!is_matrix)
395 *nb_parameters = OPENSCOP_UNDEFINED;
396 *nb_iterators = OPENSCOP_UNDEFINED;
397 *nb_scattdims = OPENSCOP_UNDEFINED;
398 *nb_localdims = OPENSCOP_UNDEFINED;
399 *array_id = OPENSCOP_UNDEFINED;
401 if (relation == NULL)
402 return;
404 if (openscop_relation_is_access(relation))
405 type = OPENSCOP_TYPE_ACCESS;
406 else
407 type = relation->type;
409 // There is some redundancy but I believe the code is cleaner this way.
410 switch (type) {
411 case OPENSCOP_TYPE_CONTEXT: {
412 if (is_matrix) {
413 *nb_parameters = *nb_parameters;
414 *nb_iterators = 0;
415 *nb_scattdims = 0;
416 *nb_localdims = 0;
417 *array_id = 0;
419 else {
420 *nb_parameters = relation->nb_parameters;
421 *nb_iterators = 0;
422 *nb_scattdims = 0;
423 *nb_localdims = relation->nb_local_dims;
424 *array_id = 0;
426 break;
428 case OPENSCOP_TYPE_DOMAIN: {
429 if (is_matrix) {
430 *nb_parameters = *nb_parameters;
431 *nb_iterators = relation->nb_columns - *nb_parameters - 2;
432 *nb_scattdims = 0;
433 *nb_localdims = 0;
434 *array_id = 0;
436 else {
437 *nb_parameters = relation->nb_parameters;
438 *nb_iterators = relation->nb_output_dims;
439 *nb_scattdims = 0;
440 *nb_localdims = relation->nb_local_dims;
441 *array_id = 0;
443 break;
445 case OPENSCOP_TYPE_SCATTERING: {
446 if (is_matrix) {
447 *nb_parameters = *nb_parameters;
448 *nb_iterators = relation->nb_columns - *nb_parameters - 2;
449 *nb_scattdims = relation->nb_rows;
450 *nb_localdims = 0;
451 *array_id = 0;
453 else {
454 *nb_parameters = relation->nb_parameters;
455 *nb_iterators = relation->nb_input_dims;
456 *nb_scattdims = relation->nb_output_dims;
457 *nb_localdims = relation->nb_local_dims;
458 *array_id = 0;
460 break;
462 case OPENSCOP_TYPE_ACCESS: {
463 if (is_matrix) {
464 *nb_parameters = *nb_parameters;
465 *nb_iterators = relation->nb_columns - *nb_parameters - 2;
466 *nb_scattdims = 0;
467 *nb_localdims = 0;
468 *array_id = openscop_relation_get_array_id(relation);
470 else {
471 *nb_parameters = relation->nb_parameters;
472 *nb_iterators = relation->nb_input_dims;
473 *nb_scattdims = 0;
474 *nb_localdims = relation->nb_local_dims;
475 *array_id = openscop_relation_get_array_id(relation);
477 break;
484 * openscop_relation_printable_comments function:
485 * this function returns 1 if we can print safely the comments for the
486 * relation provided as parameter (in the OpenScop file), 0 otherwise.
487 * \param[in] relation The relation we want to know if we can print comments.
488 * \param[in] names The names used for comment printing.
489 * \return 1 if we can print the comments safely, 0 otherwise.
491 static
492 int openscop_relation_printable_comments(openscop_relation_p relation,
493 openscop_names_p names) {
494 int nb_parameters;
495 int nb_iterators;
496 int nb_scattdims;
497 int nb_localdims;
498 int array_id;
500 if ((relation == NULL) || (names == NULL))
501 return 0;
503 // TODO: remove this !!!
504 // Temporarily deactivate comments for relations, to finish OpenScop
505 // RFC first.
506 //if (!openscop_relation_is_matrix(relation))
507 return 0;
509 // We cannot print comments if the names are not textual.
510 if (names->textual != 1)
511 return 0;
513 // We cannot print comments if the relation is not of one known type.
514 if (!(relation->type == OPENSCOP_TYPE_DOMAIN) &&
515 !(relation->type == OPENSCOP_TYPE_SCATTERING) &&
516 !(relation->type == OPENSCOP_TYPE_ACCESS))
517 return 0;
519 // We cannot print comments if we are not sure we have enough names.
520 nb_parameters = names->nb_parameters;
521 openscop_relation_properties(relation, &nb_parameters, &nb_iterators,
522 &nb_scattdims, &nb_localdims, &array_id);
524 if ((nb_parameters == OPENSCOP_UNDEFINED) ||
525 (nb_iterators == OPENSCOP_UNDEFINED) ||
526 (nb_scattdims == OPENSCOP_UNDEFINED) ||
527 (nb_localdims == OPENSCOP_UNDEFINED) ||
528 (array_id == OPENSCOP_UNDEFINED) ||
529 (nb_parameters > names->nb_parameters) ||
530 (nb_iterators > names->nb_iterators) ||
531 (nb_scattdims > names->nb_scattdims) ||
532 (nb_localdims > names->nb_localdims) ||
533 (array_id > names->nb_arrays)) {
535 fprintf(stderr, "[OpenScop] Warning: something is wrong with the names or "
536 "an array identifier, printing comments deactivated.\n");
537 return 0;
540 return 1;
545 * openscop_relation_print_comment function:
546 * this function prints a comment corresponding to a constraint of a relation,
547 * according to its type and representation. This function does not check that
548 * printing the comment is possible (i.e., are there enough names ?), hence it
549 * is the responsibility of the user to ensure he/she can call this function
550 * safely.
551 * \param[in] file File where informations are printed.
552 * \param[in] relation The relation for which a comment has to be printed.
553 * \param[in] row The constrain row for which a comment has to be printed.
554 * \param[in] names The textual names of the various elements. Is is
555 * important that names->nb_parameters is exact if the
556 * matrix representation is used.
558 static
559 void openscop_relation_print_comment(FILE * file,
560 openscop_relation_p relation, int row,
561 openscop_names_p names) {
562 int k;
563 int type;
564 char * expression;
566 if (openscop_relation_is_access(relation))
567 type = OPENSCOP_TYPE_ACCESS;
568 else
569 type = relation->type;
571 switch (type) {
572 case OPENSCOP_TYPE_DOMAIN: {
573 expression = openscop_relation_expression(relation, row, names);
574 fprintf(file, " ## %s", expression);
575 free(expression);
576 if (SCOPINT_zero_p(relation->m[row][0]))
577 fprintf(file, " == 0");
578 else
579 fprintf(file, " >= 0");
580 break;
582 case OPENSCOP_TYPE_SCATTERING: {
583 expression = openscop_relation_expression(relation, row, names);
584 fprintf(file, " ## %s", expression);
585 free(expression);
586 break;
588 case OPENSCOP_TYPE_ACCESS: {
589 //TODO: works only for matrix: use openscop_relation_get_array_id
590 if (SCOPINT_notzero_p(relation->m[row][0])) {
591 if (strncmp(names->arrays[SCOPINT_get_si(relation->m[row][0]) - 1],
592 OPENSCOP_FAKE_ARRAY, strlen(OPENSCOP_FAKE_ARRAY)))
593 fprintf(file, " ## %s",
594 names->arrays[SCOPINT_get_si(relation->m[row][0]) - 1]);
595 k = row;
596 do {
597 expression = openscop_relation_expression(relation, k, names);
598 fprintf(file, "[%s]", expression);
599 free(expression);
600 k++;
602 while ((k < relation->nb_rows) &&
603 SCOPINT_zero_p(relation->m[k][0]));
605 else {
606 fprintf(file, " ##");
614 * openscop_relation_print function:
615 * this function prints the content of a openscop_relation_t structure
616 * (*relation) into a file (file, possibly stdout) in the OpenScop format.
617 * \param[in] file File where informations are printed.
618 * \param[in] relation The relation whose information has to be printed.
619 * \param[in] names The textual names of the various elements. Is is
620 * important that names->nb_parameters is exact if the
621 * matrix representation is used. Set to NULL if printing
622 * comments is not needed.
624 void openscop_relation_print(FILE * file,
625 openscop_relation_p relation,
626 openscop_names_p names) {
627 int i, j;
628 int part, nb_parts;
629 int printable_comments;
630 openscop_relation_p r;
632 if (relation == NULL) {
633 fprintf(file, "# NULL relation\n");
634 return;
637 printable_comments = openscop_relation_printable_comments(relation, names);
639 // Count the number of parts in the union and print it if it is not 1.
640 r = relation;
641 nb_parts = 0;
642 while (r != NULL) {
643 nb_parts++;
644 r = r->next;
647 if (nb_parts > 0) {
648 openscop_relation_print_type(file, relation);
649 fprintf(file, "\n");
652 if (nb_parts > 1)
653 fprintf(file, "# Union with %d parts\n%d\n", nb_parts, nb_parts);
655 // Print each part of the union.
656 for (part = 1; part <= nb_parts; part++) {
657 if (nb_parts > 1)
658 fprintf(file, "# Union part No.%d\n", part);
659 if ((relation->nb_output_dims == OPENSCOP_UNDEFINED) &&
660 (relation->nb_input_dims == OPENSCOP_UNDEFINED) &&
661 (relation->nb_local_dims == OPENSCOP_UNDEFINED) &&
662 (relation->nb_parameters == OPENSCOP_UNDEFINED))
663 fprintf(file, "%d %d\n", relation->nb_rows, relation->nb_columns);
664 else
665 fprintf(file, "%d %d %d %d %d %d\n",
666 relation->nb_rows, relation->nb_columns,
667 relation->nb_output_dims, relation->nb_input_dims,
668 relation->nb_local_dims, relation->nb_parameters);
670 for (i = 0; i < relation->nb_rows; i++) {
671 for (j = 0; j < relation->nb_columns; j++) {
672 SCOPINT_dump(file, OPENSCOP_FMT, relation->m[i][j]);
673 fprintf(file, " ");
676 if (printable_comments)
677 openscop_relation_print_comment(file, relation, i, names);
679 fprintf(file, "\n");
681 relation = relation->next;
686 /*****************************************************************************
687 * Reading function *
688 *****************************************************************************/
692 * openscop_relation_read_type function:
693 * this function reads a textual relation type and returns its integer
694 * counterpart.
695 * \param[in] file The input stream.
696 * \return The relation type.
698 static
699 int openscop_relation_read_type(FILE * file) {
700 int nb_strings;
701 int type;
702 char ** strings;
704 strings = openscop_util_strings_read(file, &nb_strings);
705 if (nb_strings > 1) {
706 fprintf(stderr, "[OpenScop] Warning: uninterpreted information "
707 "(after relation type).\n");
709 if (nb_strings == 0) {
710 fprintf(stderr, "[OpenScop] Error: no relation type.\n");
711 exit(1);
714 if (!strcmp(strings[0], OPENSCOP_STRING_UNDEFINED)) {
715 type = OPENSCOP_UNDEFINED;
716 goto return_type;
719 if (!strcmp(strings[0], OPENSCOP_STRING_CONTEXT)) {
720 type = OPENSCOP_TYPE_CONTEXT;
721 goto return_type;
724 if (!strcmp(strings[0], OPENSCOP_STRING_DOMAIN)) {
725 type = OPENSCOP_TYPE_DOMAIN;
726 goto return_type;
729 if (!strcmp(strings[0], OPENSCOP_STRING_SCATTERING)) {
730 type = OPENSCOP_TYPE_SCATTERING;
731 goto return_type;
734 if (!strcmp(strings[0], OPENSCOP_STRING_READ)) {
735 type = OPENSCOP_TYPE_READ;
736 goto return_type;
739 if (!strcmp(strings[0], OPENSCOP_STRING_WRITE)) {
740 type = OPENSCOP_TYPE_WRITE;
741 goto return_type;
744 if (!strcmp(strings[0], OPENSCOP_STRING_RDWR)) {
745 type = OPENSCOP_TYPE_RDWR;
746 goto return_type;
749 if (!strcmp(strings[0], OPENSCOP_STRING_MAY_READ)) {
750 type = OPENSCOP_TYPE_MAY_READ;
751 goto return_type;
754 if (!strcmp(strings[0], OPENSCOP_STRING_MAY_WRITE)) {
755 type = OPENSCOP_TYPE_MAY_WRITE;
756 goto return_type;
759 if (!strcmp(strings[0], OPENSCOP_STRING_MAY_RDWR)) {
760 type = OPENSCOP_TYPE_CONTEXT;
761 goto return_type;
764 fprintf(stderr, "[OpenScop] Error: relation type not supported "
765 "(%s).\n", strings[0]);
766 exit(1);
768 return_type:
769 openscop_util_strings_free(strings, nb_strings);
770 return type;
775 * openscop_relation_read function:
776 * this function reads a relation into a file (foo, posibly stdin) and
777 * returns a pointer this relation.
778 * \param[in] file The input stream.
779 * \return A pointer to the relation structure that has been read.
781 openscop_relation_p openscop_relation_read(FILE * foo) {
782 int i, j, k, n, read = 0;
783 int nb_rows, nb_columns;
784 int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters;
785 int nb_union_parts = 1;
786 int may_read_nb_union_parts = 1;
787 int read_properties = 1;
788 int first = 1;
789 int type;
790 char * c, s[OPENSCOP_MAX_STRING], str[OPENSCOP_MAX_STRING];
791 openscop_relation_p relation, relation_union = NULL, previous = NULL;
792 openscop_int_t * p = NULL;
794 type = openscop_relation_read_type(foo);
796 // Read each part of the union (the number of parts may be updated inside)
797 for (k = 0; k < nb_union_parts; k++) {
798 // Read the number of union parts or the properties of the union part
799 while (read_properties) {
800 read_properties = 0;
802 // Read relation properties.
803 c = openscop_util_skip_blank_and_comments(foo, s);
804 read = sscanf(c, " %d %d %d %d %d %d", &nb_rows, &nb_columns,
805 &nb_output_dims, &nb_input_dims,
806 &nb_local_dims, &nb_parameters);
808 if (((read != 1) && (read != 2) && (read != 6)) ||
809 ((read == 1) && (may_read_nb_union_parts != 1))) {
810 fprintf(stderr, "[OpenScop] Error: badly formated relation.\n");
811 fprintf(stderr, "(%d properties while it should be either "
812 "1 -number of union parts, 2 -matrix representation "
813 " or 6 -relation representation)\n", read);
814 exit(1);
817 if (read == 1) {
818 // Only one number means a union and is the number of parts.
819 nb_union_parts = nb_rows;
820 if (nb_union_parts < 1) {
821 fprintf(stderr, "[OpenScop] Error: negative nb of union parts.\n");
822 exit(1);
824 // Allow to read the properties of the first part of the union.
825 read_properties = 1;
828 if (read == 2) {
829 nb_output_dims = OPENSCOP_UNDEFINED;
830 nb_input_dims = OPENSCOP_UNDEFINED;
831 nb_local_dims = OPENSCOP_UNDEFINED;
832 nb_parameters = OPENSCOP_UNDEFINED;
835 may_read_nb_union_parts = 0;
838 // Allocate the union part and fill its properties.
839 relation = openscop_relation_malloc(nb_rows, nb_columns);
840 relation->type = type;
841 relation->nb_output_dims = nb_output_dims;
842 relation->nb_input_dims = nb_input_dims;
843 relation->nb_local_dims = nb_local_dims;
844 relation->nb_parameters = nb_parameters;
846 // Read the matrix of constraints.
847 if ((relation->nb_rows != 0) && (relation->nb_columns != 0))
848 p = relation->m[0];
850 for (i = 0; i < relation->nb_rows; i++) {
851 c = openscop_util_skip_blank_and_comments(foo, s);
852 if (c == NULL) {
853 fprintf(stderr, "[OpenScop] Error: not enough rows.\n");
854 exit(1);
857 for (j = 0; j < relation->nb_columns; j++) {
858 if (c == NULL || *c == '#' || *c == '\n') {
859 fprintf(stderr, "[OpenScop] Error: not enough columns.\n");
860 exit(1);
862 if (sscanf(c, "%s%n", str, &n) == 0) {
863 fprintf(stderr, "[OpenScop] Error: not enough rows.\n");
864 exit(1);
866 #if defined(OPENSCOP_INT_T_IS_MP)
867 long long val;
868 if (sscanf(str, "%lld", &val) == 0) {
869 fprintf(stderr, "[OpenScop] Error: failed to read an integer.\n");
870 exit(1);
872 mpz_set_si(*p++, val);
873 #else
874 if (sscanf(str, OPENSCOP_FMT_TXT, p++) == 0) {
875 fprintf(stderr, "[OpenScop] Error: failed to read an integer.\n");
876 exit(1);
878 #endif
879 c += n;
883 // Build the linked list of union parts.
884 if (first == 1) {
885 relation_union = relation;
886 first = 0;
888 else {
889 previous->next = relation;
892 previous = relation;
893 read_properties = 1;
896 return relation_union;
900 /*+***************************************************************************
901 * Memory allocation/deallocation function *
902 *****************************************************************************/
906 * openscop_relation_malloc function:
907 * this function allocates the memory space for a openscop_relation_t
908 * structure and sets its fields with default values. Then it returns a
909 * pointer to the allocated space.
910 * \param[in] nb_rows The number of row of the relation to allocate.
911 * \param[in] nb_columns The number of columns of the relation to allocate.
912 * \return A pointer to an empty relation with fields set to default values
913 * and a ready-to-use constraint matrix.
915 openscop_relation_p openscop_relation_malloc(int nb_rows, int nb_columns) {
916 openscop_relation_p relation;
917 openscop_int_t ** p, * q;
918 int i, j;
920 relation = (openscop_relation_p)malloc(sizeof(openscop_relation_t));
921 if (relation == NULL) {
922 fprintf(stderr, "[OpenScop] Error: memory Overflow.\n");
923 exit(1);
926 relation->type = OPENSCOP_UNDEFINED;
927 relation->nb_rows = nb_rows;
928 relation->nb_columns = nb_columns;
929 relation->nb_output_dims = OPENSCOP_UNDEFINED;
930 relation->nb_input_dims = OPENSCOP_UNDEFINED;
931 relation->nb_parameters = OPENSCOP_UNDEFINED;
932 relation->nb_local_dims = OPENSCOP_UNDEFINED;
934 if ((nb_rows == 0) || (nb_columns == 0) ||
935 (nb_rows == OPENSCOP_UNDEFINED) || (nb_columns == OPENSCOP_UNDEFINED)) {
936 relation->m = NULL;
938 else {
939 p = (openscop_int_t **)malloc(nb_rows * sizeof(openscop_int_t *));
940 if (p == NULL) {
941 fprintf(stderr, "[OpenScop] Error: memory Overflow.\n");
942 exit(1);
944 q = (openscop_int_t *)malloc(nb_rows*nb_columns*sizeof(openscop_int_t));
945 if (q == NULL) {
946 fprintf(stderr, "[OpenScop] Error: memory Overflow.\n");
947 exit(1);
949 relation->m = p;
950 for (i = 0; i < nb_rows; i++) {
951 *p++ = q;
952 for (j = 0; j < nb_columns; j++)
953 SCOPINT_init_set_si(*(q+j),0);
954 q += nb_columns;
958 relation->next = NULL;
960 return relation;
965 * openscop_relation_free_inside function:
966 * this function frees the allocated memory for the inside of a
967 * openscop_relation_t structure, i.e. only m.
968 * \param[in] relation The pointer to the relation we want to free internals.
970 void openscop_relation_free_inside(openscop_relation_p relation) {
971 int i, nb_elements;
972 openscop_int_t * p;
974 if (relation == NULL)
975 return;
977 nb_elements = relation->nb_rows * relation->nb_columns;
979 if (nb_elements > 0)
980 p = relation->m[0];
982 for (i = 0; i < nb_elements; i++)
983 SCOPINT_clear(*p++);
985 if (relation->m != NULL) {
986 if (nb_elements > 0)
987 free(relation->m[0]);
988 free(relation->m);
994 * openscop_relation_free function:
995 * this function frees the allocated memory for a openscop_relation_t
996 * structure.
997 * \param[in] relation The pointer to the relation we want to free.
999 void openscop_relation_free(openscop_relation_p relation) {
1000 openscop_relation_p tmp;
1002 if (relation == NULL)
1003 return;
1005 while (relation != NULL) {
1006 tmp = relation->next;
1007 openscop_relation_free_inside(relation);
1008 free(relation);
1009 relation = tmp;
1014 /*+***************************************************************************
1015 * Processing functions *
1016 *****************************************************************************/
1020 * openscop_relation_is_matrix function:
1021 * this function returns 1 if the relation provided as parameter corresponds
1022 * to a "matrix" representation (see documentation), -1 if it is NULL and
1023 * 0 in all other cases.
1024 * \param[in] relation The relation we want to know if it is a matrix or not.
1025 * \return 1 if the relation has "matrix" representation, -1 if it is NULL,
1026 * 0 in all other cases.
1028 int openscop_relation_is_matrix(openscop_relation_p relation) {
1029 if (relation == NULL)
1030 return -1;
1032 // A relation has matrix representation if all nb_local_dims fields
1033 // of all parts of the union is OPENSCOP_UNDEFINED.
1034 while (relation != NULL) {
1035 if (relation->nb_local_dims != OPENSCOP_UNDEFINED)
1036 return 0;
1038 relation = relation->next;
1041 return 1;
1046 * openscop_relation_ncopy function:
1047 * this functions builds and returns a "hard copy" (not a pointer copy) of a
1048 * openscop_relation_t data structure such that the copy is restricted to the
1049 * "n" first rows of the relation. This applies to all the parts in the case
1050 * of a relation union.
1051 * \param[in] relation The pointer to the relation we want to copy.
1052 * \param[in] n The number of row of the relation we want to copy (the
1053 * special value -1 means "all the rows").
1054 * \return A pointer to the full copy of the relation union restricted to the
1055 * first n rows of constraint matrix for each part of the union.
1057 openscop_relation_p openscop_relation_ncopy(openscop_relation_p relation,
1058 int n) {
1059 int i, j;
1060 int first = 1, all_rows = 0;
1061 openscop_relation_p copy = NULL, node, previous = NULL;
1063 if (n == -1)
1064 all_rows = 1;
1066 while (relation != NULL) {
1067 if (all_rows)
1068 n = relation->nb_rows;
1070 if (n > relation->nb_rows) {
1071 fprintf(stderr,"[OpenScop] Error: not enough rows in the relation\n");
1072 exit(1);
1075 node = openscop_relation_malloc(n, relation->nb_columns);
1076 node->type = relation->type;
1077 node->nb_output_dims = relation->nb_output_dims;
1078 node->nb_input_dims = relation->nb_input_dims;
1079 node->nb_local_dims = relation->nb_local_dims;
1080 node->nb_parameters = relation->nb_parameters;
1082 for (i = 0; i < n; i++)
1083 for (j = 0; j < relation->nb_columns; j++)
1084 SCOPINT_assign(node->m[i][j], relation->m[i][j]);
1086 if (first) {
1087 first = 0;
1088 copy = node;
1089 previous = node;
1091 else {
1092 previous->next = node;
1093 previous = previous->next;
1096 relation = relation->next;
1099 return copy;
1104 * openscop_relation_copy function:
1105 * this function builds and returns a "hard copy" (not a pointer copy) of an
1106 * openscop_relation_t data structure (the full union of relation).
1107 * \param[in] relation The pointer to the relation we want to copy.
1108 * \return A pointer to the copy of the union of relations.
1110 openscop_relation_p openscop_relation_copy(openscop_relation_p relation) {
1111 if (relation == NULL)
1112 return NULL;
1114 return openscop_relation_ncopy(relation, -1);
1119 * openscop_relation_replace_vector function:
1120 * this function replaces the "row"^th row of a relation "relation" with the
1121 * vector "vector". It directly updates the relation union part pointed
1122 * by "relation" and this part only.
1123 * \param[in,out] relation The relation we want to replace a row.
1124 * \param[in] vector The vector that will replace a row of the relation.
1125 * \param[in] row The row of the relation to be replaced.
1127 void openscop_relation_replace_vector(openscop_relation_p relation,
1128 openscop_vector_p vector, int row) {
1129 int i;
1131 if ((relation == NULL) || (vector == NULL) ||
1132 (relation->nb_columns != vector->size) ||
1133 (row >= relation->nb_rows) || (row < 0)) {
1134 fprintf(stderr,"[OpenScop] Error: vector cannot replace relation row.\n");
1135 exit(1);
1138 for (i = 0; i < vector->size; i++)
1139 SCOPINT_assign(relation->m[row][i], vector->v[i]);
1144 * openscop_relation_add_vector function:
1145 * this function adds (meaning, +) a vector to the "row"^th row of a
1146 * relation "relation". It directly updates the relation union part pointed
1147 * by "relation" and this part only.
1148 * \param[in,out] relation The relation we want to add a vector to a row.
1149 * \param[in] vector The vector that will replace a row of the relation.
1150 * \param[in] row The row of the relation to be replaced.
1152 void openscop_relation_add_vector(openscop_relation_p relation,
1153 openscop_vector_p vector, int row) {
1154 int i;
1156 if ((relation == NULL) || (vector == NULL) ||
1157 (relation->nb_columns != vector->size) ||
1158 (row >= relation->nb_rows) || (row < 0)) {
1159 fprintf(stderr,"[OpenScop] Error: vector cannot be added to relation.\n");
1160 exit(1);
1163 if (SCOPINT_get_si(relation->m[row][0]) == 0)
1164 SCOPINT_assign(relation->m[row][0], vector->v[0]);
1166 for (i = 1; i < vector->size; i++)
1167 SCOPINT_addto(relation->m[row][i], relation->m[row][i], vector->v[i]);
1172 * openscop_relation_sub_vector function:
1173 * this function subtracts the vector "vector" to the "row"^th row of
1174 * a relation "relation. It directly updates the relation union part pointed
1175 * by "relation" and this part only.
1176 * \param[in,out] relation The relation where to subtract a vector to a row.
1177 * \param[in] vector The vector to subtract to a relation row.
1178 * \param[in] row The row of the relation to subtract the vector.
1180 void openscop_relation_sub_vector(openscop_relation_p relation,
1181 openscop_vector_p vector, int row) {
1182 int i;
1184 if ((relation == NULL) || (vector == NULL) ||
1185 (relation->nb_columns != vector->size) ||
1186 (row >= relation->nb_rows) || (row < 0)) {
1187 fprintf(stderr,"[OpenScop] Error: vector cannot be subtracted to row.\n");
1188 exit(1);
1191 if (SCOPINT_get_si(relation->m[row][0]) == 0)
1192 SCOPINT_assign(relation->m[row][0], vector->v[0]);
1194 for (i = 1; i < vector->size; i++)
1195 SCOPINT_subtract(relation->m[row][i], relation->m[row][i], vector->v[i]);
1200 * openscop_relation_insert_vector function:
1201 * this function inserts a new row corresponding to the vector "vector" to
1202 * the relation "relation" by inserting it at the "row"^th row. It directly
1203 * updates the relation union part pointed by "relation" and this part only.
1204 * If "vector" (or "relation") is NULL, the relation is left unmodified.
1205 * \param[in,out] relation The relation we want to extend.
1206 * \param[in] vector The vector that will be added relation.
1207 * \param[in] row The row where to insert the vector.
1209 void openscop_relation_insert_vector(openscop_relation_p relation,
1210 openscop_vector_p vector, int row) {
1211 openscop_relation_p temp;
1213 temp = openscop_relation_from_vector(vector);
1214 openscop_relation_insert_relation(relation, temp, row);
1215 openscop_relation_free(temp);
1220 * openscop_relation_from_vector function:
1221 * this function converts a vector "vector" to a relation with a single row
1222 * and returns a pointer to that relation.
1223 * \param[in] vector The vector to convert to a relation.
1224 * \return A pointer to a relation resulting from the vector conversion.
1226 openscop_relation_p openscop_relation_from_vector(openscop_vector_p vector) {
1227 openscop_relation_p relation;
1229 if (vector == NULL)
1230 return NULL;
1232 relation = openscop_relation_malloc(1, vector->size);
1233 openscop_relation_replace_vector(relation, vector, 0);
1234 return relation;
1239 * openscop_relation_replace_relation function:
1240 * this function replaces some rows of a relation "r1" with the rows of
1241 * the relation "r2". It begins at the "row"^th row of "r1". It directly
1242 * updates the relation union part pointed by "r1" and this part only.
1243 * \param[in,out] r1 The relation we want to change some rows.
1244 * \param[in] r2 The relation containing the new rows.
1245 * \param[in] row The first row of the relation r1 to be replaced.
1247 void openscop_relation_replace_relation(openscop_relation_p r1,
1248 openscop_relation_p r2, int row) {
1249 int i, j;
1251 if ((r1 == NULL) || (r2 == NULL) ||
1252 (r1->nb_columns != r1->nb_columns) ||
1253 ((row + r2->nb_rows) > r1->nb_rows) || (row < 0)) {
1254 fprintf(stderr,"[OpenScop] Error: relation rows could not be replaced.\n");
1255 exit(1);
1258 for (i = 0; i < r2->nb_rows; i++)
1259 for (j = 0; j < r2->nb_columns; j++)
1260 SCOPINT_assign(r1->m[i+row][j], r2->m[i][j]);
1265 * openscop_relation_insert_relation function:
1266 * this function adds new rows corresponding to the relation "r1" to
1267 * the relation "r2" by inserting it at the "row"^th row. It directly
1268 * updates the relation union part pointed by "r1" and this part only.
1269 * If "r2" (or "r1") is NULL, the relation is left unmodified.
1270 * \param[in,out] r1 The relation we want to extend.
1271 * \param[in] r2 The relation to be inserted.
1272 * \param[in] row The row where to insert the relation
1274 void openscop_relation_insert_relation(openscop_relation_p r1,
1275 openscop_relation_p r2, int row) {
1276 int i, j;
1277 openscop_relation_p temp;
1279 if ((r1 == NULL) || (r2 == NULL))
1280 return;
1282 if ((r1->nb_columns != r2->nb_columns) ||
1283 (row > r1->nb_rows) || (row < 0)) {
1284 fprintf(stderr,"[OpenScop] Error: constraints cannot be inserted.\n");
1285 exit(1);
1288 // We use a temporary relation just to reuse existing functions. Cleaner.
1289 temp = openscop_relation_malloc(r1->nb_rows+r2->nb_rows, r1->nb_columns);
1291 for (i = 0; i < row; i++)
1292 for (j = 0; j < r1->nb_columns; j++)
1293 SCOPINT_assign(temp->m[i][j], r1->m[i][j]);
1295 openscop_relation_replace_relation(temp, r2, row);
1297 for (i = row + r2->nb_rows; i < r2->nb_rows + r1->nb_rows; i++)
1298 for (j = 0; j < r1->nb_columns; j++)
1299 SCOPINT_assign(temp->m[i][j], r1->m[i-r2->nb_rows][j]);
1301 openscop_relation_free_inside(r1);
1303 // Replace the inside of relation.
1304 r1->nb_rows = temp->nb_rows;
1305 r1->m = temp->m;
1307 // Free the temp "shell".
1308 free(temp);
1313 * openscop_relation_concat function:
1314 * this function builds a new relation from two relations sent as
1315 * parameters. The new set of constraints is built as the concatenation
1316 * of the rows of the first elements of the two relation unions r1 and r2.
1317 * This means, there is no next field in the result.
1318 * \param[in] r1 The first relation.
1319 * \param[in] r2 The second relation.
1320 * \return A pointer to the relation resulting from the concatenation of
1321 * the first elements of r1 and r2.
1323 openscop_relation_p openscop_relation_concat(openscop_relation_p r1,
1324 openscop_relation_p r2) {
1325 openscop_relation_p new;
1327 if (r1 == NULL)
1328 return openscop_relation_copy(r2);
1330 if (r2 == NULL)
1331 return openscop_relation_copy(r1);
1333 if (r1->nb_columns != r2->nb_columns) {
1334 fprintf(stderr, "[OpenScop] Error: incompatible sizes "
1335 "for concatenation.\n");
1336 exit(1);
1338 if (r1->next || r2->next) {
1339 fprintf(stderr, "[OpenScop] Warning: relation concatenation is done "
1340 "on the first elements only.\n");
1343 new = openscop_relation_malloc(r1->nb_rows+r2->nb_rows, r1->nb_columns);
1344 openscop_relation_replace_relation(new, r1, 0);
1345 openscop_relation_replace_relation(new, r2, r1->nb_rows);
1347 return new;
1352 * openscop_relation_equal function:
1353 * this function returns true if the two relations provided as parameters
1354 * are the same, false otherwise.
1355 * \param[in] r1 The first relation.
1356 * \param[in] r2 The second relation.
1357 * \return 1 if r1 and r2 are the same (content-wise), 0 otherwise.
1359 int openscop_relation_equal(openscop_relation_p r1, openscop_relation_p r2) {
1360 int i, j;
1362 while ((r1 != NULL) && (r2 != NULL)) {
1363 if (r1 == r2)
1364 return 1;
1366 if ((r1->type != r2->type) ||
1367 (r1->nb_rows != r2->nb_rows) ||
1368 (r1->nb_columns != r2->nb_columns) ||
1369 (r1->nb_output_dims != r2->nb_output_dims) ||
1370 (r1->nb_input_dims != r2->nb_input_dims) ||
1371 (r1->nb_local_dims != r2->nb_local_dims) ||
1372 (r1->nb_parameters != r2->nb_parameters))
1373 return 0;
1375 for (i = 0; i < r1->nb_rows; ++i)
1376 for (j = 0; j < r1->nb_columns; ++j)
1377 if (SCOPINT_ne(r1->m[i][j], r2->m[i][j]))
1378 return 0;
1380 r1 = r1->next;
1381 r2 = r2->next;
1384 if (((r1 == NULL) && (r2 != NULL)) || ((r1 != NULL) && (r2 == NULL)))
1385 return 0;
1387 return 1;
1392 * openscop_relation_check_property internal function:
1393 * This function checks whether an "actual" value is the same as an
1394 * "expected" value or not. If the expected value is set to
1395 * OPENSCOP_UNDEFINED, this function sets it to the "actual" value
1396 * and do not report a difference has been detected.
1397 * It returns 0 if a difference has been detected, 1 otherwise.
1398 * \param[in,out] expected Pointer to the expected value (the value is
1399 * modified if it was set to OPENSCOP_UNDEFINED).
1400 * \param[in] actual Value we want to check.
1401 * \return 0 if the values are not the same while the expected value was
1402 * not OPENSCOP_UNDEFINED, 1 otherwise.
1404 static
1405 int openscop_relation_check_property(int * expected, int actual) {
1406 if (*expected != OPENSCOP_UNDEFINED) {
1407 if ((actual != OPENSCOP_UNDEFINED) &&
1408 (actual != *expected)) {
1409 fprintf(stderr, "[OpenScop] Warning: unexpected property.\n");
1410 return 0;
1413 else {
1414 *expected = actual;
1417 return 1;
1422 * openscop_relation_check_nb_columns internal function:
1423 * This function checks that the number of columns of a relation
1424 * corresponds to some expected properties (setting an expected property to
1425 * OPENSCOP_UNDEFINED makes this function unable to detect a problem).
1426 * It returns 0 if the number of columns seems incorrect or 1 if no problem
1427 * has been detected.
1428 * \param[in] relation The relation we want to check the number of columns.
1429 * \param[in] expected_nb_output_dims Expected number of output dimensions.
1430 * \param[in] expected_nb_input_dims Expected number of input dimensions.
1431 * \param[in] expected_nb_parameters Expected number of parameters.
1432 * \return 0 if the number of columns seems incorrect, 1 otherwise.
1434 static
1435 int openscop_relation_check_nb_columns(openscop_relation_p relation,
1436 int expected_nb_output_dims,
1437 int expected_nb_input_dims,
1438 int expected_nb_parameters) {
1439 int expected_nb_local_dims, expected_nb_columns;
1441 if ((expected_nb_output_dims != OPENSCOP_UNDEFINED) &&
1442 (expected_nb_input_dims != OPENSCOP_UNDEFINED) &&
1443 (expected_nb_parameters != OPENSCOP_UNDEFINED)) {
1445 if (relation->nb_local_dims == OPENSCOP_UNDEFINED)
1446 expected_nb_local_dims = 0;
1447 else
1448 expected_nb_local_dims = relation->nb_local_dims;
1450 expected_nb_columns = expected_nb_output_dims +
1451 expected_nb_input_dims +
1452 expected_nb_local_dims +
1453 expected_nb_parameters +
1456 if (expected_nb_columns != relation->nb_columns) {
1457 fprintf(stderr, "[OpenScop] Warning: unexpected number of columns.\n");
1458 return 0;
1462 return 1;
1467 * openscop_relation_format_consistency function:
1468 * this function checks that each part of an union of relations use the same
1469 * representation type (either matrix or relation representation). It returns
1470 * 1 if it is the case, 0 otherwise.
1471 * \param[in] r The relation to check for representation consistency.
1472 * \return 0 if the representation consistency check fails, 1 if it succeeds.
1474 static
1475 int openscop_relation_format_consistency(openscop_relation_p r) {
1476 int matrix = 0;
1477 int relation = 0;
1479 while (r != NULL) {
1480 if (r->nb_local_dims == OPENSCOP_UNDEFINED)
1481 matrix = 1;
1482 else
1483 relation = 1;
1485 r = r->next;
1488 return (matrix == relation) ? 0 : 1;
1493 * openscop_relation_integrity_check function:
1494 * this function checks that a relation is "well formed" according to some
1495 * expected properties (setting an expected value to OPENSCOP_UNDEFINED means
1496 * that we do not expect a specific value) and what the relation is supposed
1497 * to represent. It returns 0 if the check failed or 1 if no problem has been
1498 * detected.
1499 * \param[in] relation The relation we want to check.
1500 * \param[in] type Semantics about this relation (domain, access...).
1501 * \param[in] expected_nb_output_dims Expected number of output dimensions.
1502 * \param[in] expected_nb_input_dims Expected number of input dimensions.
1503 * \param[in] expected_nb_parameters Expected number of parameters.
1504 * \return 0 if the integrity check fails, 1 otherwise.
1506 int openscop_relation_integrity_check(openscop_relation_p relation,
1507 int expected_type,
1508 int expected_nb_output_dims,
1509 int expected_nb_input_dims,
1510 int expected_nb_parameters) {
1511 int i, is_matrix;
1513 // Check the NULL case.
1514 if (relation == NULL) {
1515 if ((expected_nb_output_dims != OPENSCOP_UNDEFINED) ||
1516 (expected_nb_input_dims != OPENSCOP_UNDEFINED) ||
1517 (expected_nb_parameters != OPENSCOP_UNDEFINED)) {
1518 fprintf(stderr, "[OpenScop] Warning: NULL relation with "
1519 "some expected properties.\n");
1520 return 0;
1523 return 1;
1526 // Check the type.
1527 if (((expected_type != OPENSCOP_TYPE_ACCESS) &&
1528 (expected_type != relation->type)) ||
1529 ((expected_type == OPENSCOP_TYPE_ACCESS) &&
1530 (!openscop_relation_is_access(relation)))) {
1531 fprintf(stderr, "[OpenScop] Warning: wrong type.\n");
1532 return 0;
1535 // Check the relation is using either matrix or relation representation.
1536 if (!openscop_relation_format_consistency(relation)) {
1537 fprintf(stderr, "[OpenScop] Warning: inconsistent representation "
1538 "(both matrix and relation).\n");
1539 return 0;
1542 is_matrix = openscop_relation_is_matrix(relation);
1544 // Check that relations have no undefined properties.
1545 if (!is_matrix &&
1546 ((relation->nb_output_dims == OPENSCOP_UNDEFINED) ||
1547 (relation->nb_input_dims == OPENSCOP_UNDEFINED) ||
1548 (relation->nb_local_dims == OPENSCOP_UNDEFINED) ||
1549 (relation->nb_parameters == OPENSCOP_UNDEFINED))) {
1550 fprintf(stderr, "[OpenScop] Warning: undefined property for a "
1551 "relation representation.\n");
1552 return 0;
1555 // Check that a context has actually 0 or an undefined #output dimensions.
1556 if ((relation->type == OPENSCOP_TYPE_CONTEXT) &&
1557 (relation->nb_output_dims != 0) &&
1558 (relation->nb_output_dims != OPENSCOP_UNDEFINED)) {
1559 fprintf(stderr, "[OpenScop] Warning: context without 0 "
1560 "as number of output dimensions.\n");
1561 openscop_relation_dump(stdout, relation);
1562 return 0;
1565 // Check that a domain has actually 0 or an undefined #input dimensions.
1566 if (((relation->type == OPENSCOP_TYPE_DOMAIN) ||
1567 (relation->type == OPENSCOP_TYPE_CONTEXT)) &&
1568 (relation->nb_input_dims != 0) &&
1569 (relation->nb_input_dims != OPENSCOP_UNDEFINED)) {
1570 fprintf(stderr, "[OpenScop] Warning: domain or context without 0 "
1571 "as number of input dimensions.\n");
1572 return 0;
1575 // Check properties according to expected values (and if expected values
1576 // are undefined, define them with the first relation part properties).
1577 if (!openscop_relation_check_property(&expected_nb_output_dims,
1578 relation->nb_output_dims) ||
1579 !openscop_relation_check_property(&expected_nb_input_dims,
1580 relation->nb_input_dims) ||
1581 !openscop_relation_check_property(&expected_nb_parameters,
1582 relation->nb_parameters))
1583 return 0;
1585 while (relation != NULL) {
1587 // Properties (except the number of local dimensions) should be the same
1588 // in all parts.
1589 if ((expected_nb_output_dims != relation->nb_output_dims) ||
1590 (expected_nb_input_dims != relation->nb_input_dims) ||
1591 (expected_nb_parameters != relation->nb_parameters)) {
1592 fprintf(stderr, "[OpenScop] Warning: inconsistent properties.\n");
1593 return 0;
1596 // Check whether the number of columns is OK or not.
1597 if (!openscop_relation_check_nb_columns(relation,
1598 expected_nb_output_dims,
1599 expected_nb_input_dims,
1600 expected_nb_parameters))
1601 return 0;
1603 // Check the first column. The first column of a relation part should be
1604 // made of 0 or 1 only, except for scattering and access relations in
1605 // "matrix" representation, the first column is made only of 0.
1606 if ((relation->nb_rows > 0) && (relation->nb_columns > 0)) {
1607 for (i = 0; i < relation->nb_rows; i++) {
1608 if (is_matrix &&
1609 ((openscop_relation_is_access(relation)) ||
1610 (relation->type == OPENSCOP_TYPE_SCATTERING))) {
1611 if (!SCOPINT_zero_p(relation->m[i][0])) {
1612 fprintf(stderr, "[OpenScop] Warning: first column of a scattering "
1613 "or access function not made of 0s.\n");
1614 openscop_relation_dump(stdout, relation);
1615 return 0;
1618 else {
1619 if (!SCOPINT_zero_p(relation->m[i][0]) &&
1620 !SCOPINT_one_p(relation->m[i][0])) {
1621 fprintf(stderr, "[OpenScop] Warning: first column of a "
1622 "relation is not strictly made of 0 or 1.\n");
1623 return 0;
1629 // Array accesses must provide the array identifier.
1630 if ((openscop_relation_is_access(relation)) &&
1631 (openscop_relation_get_array_id(relation) == OPENSCOP_UNDEFINED))
1632 return 0;
1634 relation = relation->next;
1637 return 1;
1642 * openscop_relation_union function:
1643 * this function builds a new relation from two relations provided
1644 * as parameters. The new relation is built as an union of the
1645 * two relations: the list of constraint sets are linked together.
1646 * \param[in] r1 The first relation.
1647 * \param[in] r2 The second relation.
1648 * \return A new relation corresponding to the union of r1 and r2.
1650 openscop_relation_p openscop_relation_union(openscop_relation_p r1,
1651 openscop_relation_p r2) {
1652 openscop_relation_p copy1, copy2, tmp;
1654 if ((r1 == NULL) && (r2 == NULL))
1655 return NULL;
1657 copy1 = openscop_relation_copy(r1);
1658 copy2 = openscop_relation_copy(r2);
1660 if ((r1 != NULL) && (r2 == NULL))
1661 return copy1;
1663 if ((r1 == NULL) && (r2 != NULL))
1664 return copy2;
1666 tmp = copy1;
1667 while (tmp->next != NULL)
1668 tmp = tmp->next;
1670 tmp->next = copy2;
1671 return copy1;
1675 /**
1676 * openscop_relation_set_type function:
1677 * this function sets the type of each relation union part in the relation
1678 * to the one provided as parameter.
1679 * \param relation The relation to set the type.
1680 * \param type The type.
1682 void openscop_relation_set_type(openscop_relation_p relation, int type) {
1684 while (relation != NULL) {
1685 relation->type = type;
1686 relation = relation->next;
1692 * openscop_relation_get_array_id function:
1693 * this function returns the array identifier in a relation with access type
1694 * It returns OPENSCOP_UNDEFINED if it is not able to find it (in particular
1695 * if there are irregularities in the relation).
1696 * \param[in] relation The relation where to find an array identifier.
1697 * \return The array identifier in the relation or OPENSCOP_UNDEFINED.
1699 int openscop_relation_get_array_id(openscop_relation_p relation) {
1700 int i;
1701 int first = 1;
1702 int is_matrix = openscop_relation_is_matrix(relation);
1703 int array_id = OPENSCOP_UNDEFINED;
1704 int reference_array_id = OPENSCOP_UNDEFINED;
1705 int nb_array_id;
1706 int row_id = 0;
1708 if (relation == NULL)
1709 return OPENSCOP_UNDEFINED;
1711 if (!openscop_relation_is_access(relation)) {
1712 fprintf(stderr, "[OpenScop] Warning: asked array id of non-array "
1713 "relation.\n");
1714 return OPENSCOP_UNDEFINED;
1717 while (relation != NULL) {
1718 // There should be room to store the array identifier.
1719 if ((relation->nb_rows < 1) ||
1720 (is_matrix && (relation->nb_columns < 2)) ||
1721 (!is_matrix && (relation->nb_columns < 3))) {
1722 fprintf(stderr, "[OpenScop] Warning: no array identifier in "
1723 "an access function.\n");
1724 return OPENSCOP_UNDEFINED;
1727 if (is_matrix) {
1728 // In matrix format, the array identifier is the last element of the
1729 // first row (m[0][#columns -1]), it should be greater than 0 and be
1730 // the only non-zero element in the row.
1731 for (i = 0; i < relation->nb_columns - 1; i++) {
1732 if (!SCOPINT_zero_p(relation->m[0][i])) {
1733 fprintf(stderr, "[OpenScop] Warning: non integer array "
1734 "identifier.\n");
1735 return OPENSCOP_UNDEFINED;
1738 array_id = SCOPINT_get_si(relation->m[0][relation->nb_columns - 1]);
1739 if (array_id <= 0) {
1740 fprintf(stderr, "[OpenScop] Warning: negative or 0 identifier "
1741 "in access function.\n");
1742 return OPENSCOP_UNDEFINED;
1745 else {
1746 // In relation format, array identifiers are
1747 // m[i][#columns -1] / m[i][1], with i the only row
1748 // where m[i][1] is not 0.
1749 // - check there is exactly one row such that m[i][1] is not 0,
1750 // - check the whole ith row if full of 0 except m[i][1] and the id,
1751 // - check that (m[i][#columns -1] % m[i][1]) == 0,
1752 // - check that (-m[i][#columns -1] / m[i][1]) > 0.
1753 nb_array_id = 0;
1754 for (i = 0; i < relation->nb_rows; i++) {
1755 if (!SCOPINT_zero_p(relation->m[i][1])) {
1756 nb_array_id ++;
1757 row_id = i;
1760 if (nb_array_id == 0) {
1761 fprintf(stderr, "[OpenScop] Warning: no array identifier in "
1762 "an access function.\n");
1763 return OPENSCOP_UNDEFINED;
1765 if (nb_array_id > 1) {
1766 fprintf(stderr, "[OpenScop] Warning: several array identification "
1767 "rows in one access function.\n");
1768 return OPENSCOP_UNDEFINED;
1770 for (i = 0; i < relation->nb_columns - 1; i++) {
1771 if ((i != 1) && !SCOPINT_zero_p(relation->m[row_id][i])) {
1772 fprintf(stderr, "[OpenScop] Warning: non integer array "
1773 "identifier.\n");
1774 return OPENSCOP_UNDEFINED;
1777 if (!SCOPINT_divisible(relation->m[row_id][relation->nb_columns - 1],
1778 relation->m[row_id][1])) {
1779 fprintf(stderr, "[OpenScop] Warning: rational array identifier.\n");
1780 return OPENSCOP_UNDEFINED;
1782 array_id = -SCOPINT_get_si(relation->m[row_id][relation->nb_columns-1]);
1783 array_id /= SCOPINT_get_si(relation->m[row_id][1]);
1784 if (array_id <= 0) {
1785 fprintf(stderr, "[OpenScop] Warning: negative or 0 identifier "
1786 "in access function.\n");
1787 return OPENSCOP_UNDEFINED;
1791 // Unions of accesses are allowed, but they should refer the same array.
1792 if (first) {
1793 reference_array_id = array_id;
1794 first = 0;
1796 else {
1797 if (reference_array_id != array_id) {
1798 fprintf(stderr, "[OpenScop] Warning: inconsistency of array "
1799 "identifiers in an union of access relations.\n");
1800 return OPENSCOP_UNDEFINED;
1804 relation = relation->next;
1807 return array_id;
1812 * openscop_relation_is_access function:
1813 * this function returns 1 if the relation corresponds to an access relation,
1814 * whatever its precise type (read, write etc.), 0 otherwise.
1815 * \param relation The relation to check wheter it is an access relation or not.
1816 * \return 1 if the relation is an access relation, 0 otherwise.
1818 int openscop_relation_is_access(openscop_relation_p relation) {
1820 if (relation == NULL)
1821 return 0;
1823 if ((relation->type == OPENSCOP_TYPE_ACCESS) ||
1824 (relation->type == OPENSCOP_TYPE_READ) ||
1825 (relation->type == OPENSCOP_TYPE_WRITE) ||
1826 (relation->type == OPENSCOP_TYPE_RDWR) ||
1827 (relation->type == OPENSCOP_TYPE_MAY_READ) ||
1828 (relation->type == OPENSCOP_TYPE_MAY_WRITE) ||
1829 (relation->type == OPENSCOP_TYPE_MAY_RDWR))
1830 return 1;
1832 return 0;