Solve a memory leak for cloned scops
[openscop.git] / source / relation.c
blob7675b3a1534275d48a23be0a8e1dab302b052b41
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_MAY_WRITE: {
113 fprintf(file, OPENSCOP_STRING_MAY_WRITE);
114 break;
116 default: {
117 OPENSCOP_warning("unknown relation type, "
118 "replaced with "OPENSCOP_STRING_UNDEFINED);
119 fprintf(file, OPENSCOP_STRING_UNDEFINED);
127 * openscop_relation_idump function:
128 * this function displays a openscop_relation_t structure (*relation) into a
129 * file (file, possibly stdout) in a way that trends to be understandable.
130 * It includes an indentation level (level) in order to work with others
131 * print_structure functions.
132 * \param[in] file File where informations are printed.
133 * \param[in] relation The relation whose information has to be printed.
134 * \param[in] level Number of spaces before printing, for each line.
136 void openscop_relation_idump(FILE * file,
137 openscop_relation_p relation,
138 int level) {
139 int i, j, first = 1;
141 // Go to the right level.
142 for (j = 0; j < level; j++)
143 fprintf(file, "|\t");
145 if (relation != NULL) {
146 fprintf(file, "+-- openscop_relation_t (");
147 openscop_relation_print_type(file, relation);
148 fprintf(file, ", ");
149 openscop_int_dump_precision(file, relation->precision);
150 fprintf(file, ")\n");
152 else {
153 fprintf(file, "+-- NULL relation\n");
156 while (relation != NULL) {
157 if (! first) {
158 // Go to the right level.
159 for (j = 0; j < level; j++)
160 fprintf(file, "|\t");
161 fprintf(file, "| openscop_relation_t (");
162 openscop_relation_print_type(file, relation);
163 fprintf(file, ", ");
164 openscop_int_dump_precision(file, relation->precision);
165 fprintf(file, ")\n");
167 else
168 first = 0;
170 // A blank line
171 for(j = 0; j <= level; j++)
172 fprintf(file, "|\t");
173 fprintf(file, "%d %d %d %d %d %d\n",
174 relation->nb_rows, relation->nb_columns,
175 relation->nb_output_dims, relation->nb_input_dims,
176 relation->nb_local_dims, relation->nb_parameters);
178 // Display the relation.
179 for (i = 0; i < relation->nb_rows; i++) {
180 for (j = 0; j <= level; j++)
181 fprintf(file, "|\t");
183 fprintf(file, "[ ");
185 for (j = 0; j < relation->nb_columns; j++) {
186 openscop_int_print(file, relation->precision, relation->m[i], j);
187 fprintf(file, " ");
190 fprintf(file, "]\n");
193 relation = relation->next;
195 // Next line.
196 if (relation != NULL) {
197 for (j = 0; j <= level; j++)
198 fprintf(file, "|\t");
199 fprintf(file, "|\n");
200 for (j = 0; j <= level; j++)
201 fprintf(file, "|\t");
202 fprintf(file, "V\n");
206 // The last line.
207 for (j = 0; j <= level; j++)
208 fprintf(file, "|\t");
209 fprintf(file, "\n");
214 * openscop_relation_dump function:
215 * this function prints the content of a openscop_relation_t structure
216 * (*relation) into a file (file, possibly stdout).
217 * \param[in] file File where informations are printed.
218 * \param[in] relation The relation whose information have to be printed.
220 void openscop_relation_dump(FILE * file, openscop_relation_p relation) {
221 openscop_relation_idump(file, relation, 0);
226 * openscop_relation_expression_element function:
227 * this function returns a string containing the printing of a value (e.g.,
228 * an iterator with its coefficient or a constant).
229 * \param[in] val Address of the coefficient or constant value.
230 * \param[in] precision The precision of the value.
231 * \param[in,out] first Pointer to a boolean set to 1 if the current value
232 * is the first of an expresion, 0 otherwise (maybe
233 * updated).
234 * \param[in] cst A boolean set to 1 if the value is a constant,
235 * 0 otherwise.
236 * \param[in] name String containing the name of the element.
237 * \return A string that contains the printing of a value.
239 static
240 char * openscop_relation_expression_element(void * val,
241 int precision, int * first,
242 int cst, char * name) {
243 char * temp = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
244 char * body = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
245 char * sval = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
247 body[0] = '\0';
248 sval[0] = '\0';
250 // statements for the 'normal' processing.
251 if (openscop_int_notzero(precision, val, 0) && (!cst)) {
252 if ((*first) || openscop_int_neg(precision, val, 0)) {
253 if (openscop_int_one(precision, val, 0)) { // case 1
254 sprintf(sval, "%s", name);
256 else {
257 if (openscop_int_mone(precision, val, 0)) { // case -1
258 sprintf(sval, "-%s", name);
260 else { // default case
261 openscop_int_sprint(sval, precision, val, 0);
262 sprintf(temp, "*%s", name);
263 strcat(sval, temp);
266 *first = 0;
268 else {
269 if (openscop_int_one(precision, val, 0)) {
270 sprintf(sval, "+%s", name);
272 else {
273 sprintf(sval, "+");
274 openscop_int_sprint(temp, precision, val, 0);
275 strcat(sval, temp);
276 sprintf(temp, "*%s", name);
277 strcat(sval, temp);
281 else {
282 if (cst) {
283 if ((openscop_int_zero(precision, val, 0) && (*first)) ||
284 (openscop_int_neg(precision, val, 0)))
285 openscop_int_sprint(sval, precision, val, 0);
286 if (openscop_int_pos(precision, val, 0)) {
287 if (!(*first)) {
288 sprintf(sval, "+");
289 openscop_int_sprint(temp, precision, val, 0);
290 strcat(sval, temp);
292 else {
293 openscop_int_sprint(sval, precision, val, 0);
298 free(temp);
299 free(body);
301 return(sval);
305 static
306 char ** openscop_relation_strings(openscop_relation_p relation,
307 openscop_names_p names) {
308 char ** strings;
309 char temp[OPENSCOP_MAX_STRING];
310 int i, offset, array_id;
312 OPENSCOP_malloc(strings, char **, (relation->nb_columns - 1)*sizeof(char *));
313 strings[relation->nb_columns - 2] = NULL;
315 // 1. Output dimensions.
316 if (openscop_relation_is_access(relation)) {
317 // The first output dimension is the array name.
318 array_id = openscop_relation_get_array_id(relation);
319 strings[0] = strdup(names->arrays->string[array_id - 1]);
320 // The other ones are the array dimensions [1]...[n]
321 for (i = 1; i < relation->nb_output_dims; i++) {
322 sprintf(temp, "[%d]", i);
323 strings[i] = strdup(temp);
326 else
327 if (relation->type == OPENSCOP_TYPE_SCATTERING) {
328 for (i = 0; i < relation->nb_output_dims; i++) {
329 strings[i] = strdup(names->scatt_dims->string[i]);
332 else {
333 for (i = 0; i < relation->nb_output_dims; i++) {
334 strings[i] = strdup(names->iterators->string[i]);
338 // 2. Input dimensions.
339 offset = relation->nb_output_dims;
340 for (i = offset; i < relation->nb_input_dims + offset; i++)
341 strings[i] = strdup(names->iterators->string[i - offset]);
343 // 3. Local dimensions.
344 offset += relation->nb_input_dims;
345 for (i = offset; i < relation->nb_local_dims + offset; i++)
346 strings[i] = strdup(names->local_dims->string[i - offset]);
348 // 4. Parameters.
349 offset += relation->nb_local_dims;
350 for (i = offset; i < relation->nb_parameters + offset; i++)
351 strings[i] = strdup(names->parameters->string[i - offset]);
353 return strings;
358 * openscop_relation_expression function:
359 * this function returns a string corresponding to an affine expression
360 * stored at the "row"^th row of the relation pointed by "relation".
361 * \param[in] relation A set of linear expressions.
362 * \param[in] row The row corresponding to the expression.
363 * \param[in] names The textual names of the various elements.
364 * Set to NULL if printing comments is not needed.
365 * \return A string that contains the printing of an affine expression.
367 char * openscop_relation_expression(openscop_relation_p relation,
368 int row, openscop_names_p names) {
369 int i, first = 1;
370 char ** strings;
371 char * sval;
372 char * sline = (char *)malloc(OPENSCOP_MAX_STRING * sizeof(char));
373 sline[0] = '\0';
375 // Create the array of element strings.
376 strings = openscop_relation_strings(relation, names);
378 // Create the expression.
379 for (i = 1; i <= relation->nb_columns - 2; i++) {
380 sval = openscop_relation_expression_element(
381 openscop_int_address(relation->precision, relation->m[row], i),
382 relation->precision, &first, 0, strings[i-1]);
383 strcat(sline, sval);
384 free(sval);
387 // Free the array of element strings.
388 for (i = 0; i < relation->nb_columns - 2; i++)
389 free(strings[i]);
390 free(strings);
392 return sline;
397 * openscop_relation_properties function:
398 * this function returns, through its parameters, the values of the relation
399 * attributes (nb_iterators, nb_parameters etc), depending on its value and
400 * its type. The array identifier 0 is used when there is no array
401 * identifier (AND this is OK), OPENSCOP_UNDEFINED is used to report it
402 * is impossible to provide the property while it should.
403 * This function is not intended for checking, the input relation should be
404 * correct.
405 * \param[in] relation The relation to extract property values.
406 * \param[out] nb_parameters Number of parameter property.
407 * \param[out] nb_iterators Number of iterators property.
408 * \param[out] nb_scattdims Number of scattering dimensions property.
409 * \param[out] nb_localdims Number of local dimensions property.
410 * \param[out] array_id Array identifier property.
412 static
413 void openscop_relation_properties(openscop_relation_p relation,
414 int * nb_parameters,
415 int * nb_iterators,
416 int * nb_scattdims,
417 int * nb_localdims,
418 int * array_id) {
420 int type;
422 *nb_parameters = OPENSCOP_UNDEFINED;
423 *nb_iterators = OPENSCOP_UNDEFINED;
424 *nb_scattdims = OPENSCOP_UNDEFINED;
425 *nb_localdims = OPENSCOP_UNDEFINED;
426 *array_id = OPENSCOP_UNDEFINED;
428 if (relation == NULL)
429 return;
431 if (openscop_relation_is_access(relation))
432 type = OPENSCOP_TYPE_ACCESS;
433 else
434 type = relation->type;
436 // There is some redundancy but I believe the code is cleaner this way.
437 switch (type) {
438 case OPENSCOP_TYPE_CONTEXT: {
439 *nb_parameters = relation->nb_parameters;
440 *nb_iterators = 0;
441 *nb_scattdims = 0;
442 *nb_localdims = relation->nb_local_dims;
443 *array_id = 0;
444 break;
446 case OPENSCOP_TYPE_DOMAIN: {
447 *nb_parameters = relation->nb_parameters;
448 *nb_iterators = relation->nb_output_dims;
449 *nb_scattdims = 0;
450 *nb_localdims = relation->nb_local_dims;
451 *array_id = 0;
452 break;
454 case OPENSCOP_TYPE_SCATTERING: {
455 *nb_parameters = relation->nb_parameters;
456 *nb_iterators = relation->nb_input_dims;
457 *nb_scattdims = relation->nb_output_dims;
458 *nb_localdims = relation->nb_local_dims;
459 *array_id = 0;
460 break;
462 case OPENSCOP_TYPE_ACCESS: {
463 *nb_parameters = relation->nb_parameters;
464 *nb_iterators = relation->nb_input_dims;
465 *nb_scattdims = 0;
466 *nb_localdims = relation->nb_local_dims;
467 *array_id = openscop_relation_get_array_id(relation);
468 break;
474 static
475 openscop_names_p openscop_relation_names(openscop_relation_p relation) {
476 int nb_parameters;
477 int nb_iterators;
478 int nb_scattdims;
479 int nb_localdims;
480 int array_id;
482 openscop_relation_properties(relation, &nb_parameters, &nb_iterators,
483 &nb_scattdims, &nb_localdims, &array_id);
485 return openscop_names_generate("P", nb_parameters,
486 "i", nb_iterators,
487 "t", nb_scattdims,
488 "l", nb_localdims,
489 "A", array_id);
494 * openscop_relation_print_comment function:
495 * this function prints a comment corresponding to a constraint of a relation,
496 * according to its type. This function does not check that printing the
497 * comment is possible (i.e., are there enough names ?), hence it is the
498 * responsibility of the user to ensure he/she can call this function safely.
499 * \param[in] file File where informations are printed.
500 * \param[in] relation The relation for which a comment has to be printed.
501 * \param[in] row The constrain row for which a comment has to be printed.
502 * \param[in] names The textual names of the various elements.
504 static
505 void openscop_relation_print_comment(FILE * file,
506 openscop_relation_p relation, int row) {
507 char * expression;
508 openscop_names_p names = openscop_relation_names(relation);
510 expression = openscop_relation_expression(relation, row, names);
511 fprintf(file, " ## %s", expression);
512 if (openscop_int_zero(relation->precision, relation->m[row], 0))
513 fprintf(file, " == 0");
514 else
515 fprintf(file, " >= 0");
517 openscop_names_free(names);
518 free(expression);
523 * openscop_relation_print function:
524 * this function prints the content of an openscop_relation_t structure
525 * (*relation) into a file (file, possibly stdout) in the OpenScop format.
526 * \param[in] file File where informations are printed.
527 * \param[in] relation The relation whose information has to be printed.
529 void openscop_relation_print(FILE * file,
530 openscop_relation_p relation) {
531 int i, j;
532 int part, nb_parts;
533 int printable_comments;
534 openscop_relation_p r;
536 if (relation == NULL) {
537 fprintf(file, "# NULL relation\n");
538 return;
541 //printable_comments = openscop_relation_printable_comments(relation, names);
542 printable_comments = 0;
544 // Count the number of parts in the union and print it if it is not 1.
545 r = relation;
546 nb_parts = 0;
547 while (r != NULL) {
548 nb_parts++;
549 r = r->next;
552 if (nb_parts > 0) {
553 openscop_relation_print_type(file, relation);
554 fprintf(file, "\n");
557 if (nb_parts > 1)
558 fprintf(file, "# Union with %d parts\n%d\n", nb_parts, nb_parts);
560 // Print each part of the union.
561 for (part = 1; part <= nb_parts; part++) {
562 if (nb_parts > 1)
563 fprintf(file, "# Union part No.%d\n", part);
564 if ((relation->nb_output_dims == OPENSCOP_UNDEFINED) &&
565 (relation->nb_input_dims == OPENSCOP_UNDEFINED) &&
566 (relation->nb_local_dims == OPENSCOP_UNDEFINED) &&
567 (relation->nb_parameters == OPENSCOP_UNDEFINED))
568 fprintf(file, "%d %d\n", relation->nb_rows, relation->nb_columns);
569 else
570 fprintf(file, "%d %d %d %d %d %d\n",
571 relation->nb_rows, relation->nb_columns,
572 relation->nb_output_dims, relation->nb_input_dims,
573 relation->nb_local_dims, relation->nb_parameters);
575 for (i = 0; i < relation->nb_rows; i++) {
576 for (j = 0; j < relation->nb_columns; j++) {
577 openscop_int_print(file, relation->precision, relation->m[i], j);
578 fprintf(file, " ");
581 openscop_relation_print_comment(file, relation, i);
583 fprintf(file, "\n");
585 relation = relation->next;
590 /*****************************************************************************
591 * Reading function *
592 *****************************************************************************/
596 * openscop_relation_read_type function:
597 * this function reads a textual relation type and returns its integer
598 * counterpart.
599 * \param[in] file The input stream.
600 * \return The relation type.
602 static
603 int openscop_relation_read_type(FILE * file) {
604 int type;
605 openscop_strings_p strings;
607 strings = openscop_strings_read(file);
608 if (openscop_strings_size(strings) > 1) {
609 OPENSCOP_warning("uninterpreted information (after the relation type)");
611 if (openscop_strings_size(strings) == 0)
612 OPENSCOP_error("no relation type");
614 if (!strcmp(strings->string[0], OPENSCOP_STRING_UNDEFINED)) {
615 type = OPENSCOP_UNDEFINED;
616 goto return_type;
619 if (!strcmp(strings->string[0], OPENSCOP_STRING_CONTEXT)) {
620 type = OPENSCOP_TYPE_CONTEXT;
621 goto return_type;
624 if (!strcmp(strings->string[0], OPENSCOP_STRING_DOMAIN)) {
625 type = OPENSCOP_TYPE_DOMAIN;
626 goto return_type;
629 if (!strcmp(strings->string[0], OPENSCOP_STRING_SCATTERING)) {
630 type = OPENSCOP_TYPE_SCATTERING;
631 goto return_type;
634 if (!strcmp(strings->string[0], OPENSCOP_STRING_READ)) {
635 type = OPENSCOP_TYPE_READ;
636 goto return_type;
639 if (!strcmp(strings->string[0], OPENSCOP_STRING_WRITE)) {
640 type = OPENSCOP_TYPE_WRITE;
641 goto return_type;
644 if (!strcmp(strings->string[0], OPENSCOP_STRING_MAY_WRITE)) {
645 type = OPENSCOP_TYPE_MAY_WRITE;
646 goto return_type;
649 OPENSCOP_error("relation type not supported");
651 return_type:
652 openscop_strings_free(strings);
653 return type;
658 * openscop_relation_read function:
659 * this function reads a relation into a file (foo, posibly stdin) and
660 * returns a pointer this relation. The relation is set to the maximum
661 * available precision.
662 * \param[in] file The input stream.
663 * \return A pointer to the relation structure that has been read.
665 openscop_relation_p openscop_relation_read(FILE * foo) {
666 int i, j, k, n, read = 0;
667 int nb_rows, nb_columns;
668 int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters;
669 int nb_union_parts = 1;
670 int may_read_nb_union_parts = 1;
671 int read_properties = 1;
672 int first = 1;
673 int type;
674 int precision = openscop_util_get_precision();
675 char * c, s[OPENSCOP_MAX_STRING], str[OPENSCOP_MAX_STRING];
676 openscop_relation_p relation, relation_union = NULL, previous = NULL;
678 type = openscop_relation_read_type(foo);
680 // Read each part of the union (the number of parts may be updated inside)
681 for (k = 0; k < nb_union_parts; k++) {
682 // Read the number of union parts or the properties of the union part
683 while (read_properties) {
684 read_properties = 0;
686 // Read relation properties.
687 c = openscop_util_skip_blank_and_comments(foo, s);
688 read = sscanf(c, " %d %d %d %d %d %d", &nb_rows, &nb_columns,
689 &nb_output_dims, &nb_input_dims,
690 &nb_local_dims, &nb_parameters);
692 if (((read != 1) && (read != 6)) ||
693 ((read == 1) && (may_read_nb_union_parts != 1)))
694 OPENSCOP_error("not 1 or 6 integers on the first relation line");
696 if (read == 1) {
697 // Only one number means a union and is the number of parts.
698 nb_union_parts = nb_rows;
699 if (nb_union_parts < 1)
700 OPENSCOP_error("negative nb of union parts");
702 // Allow to read the properties of the first part of the union.
703 read_properties = 1;
706 may_read_nb_union_parts = 0;
709 // Allocate the union part and fill its properties.
710 relation = openscop_relation_pmalloc(precision, nb_rows, nb_columns);
711 relation->type = type;
712 relation->nb_output_dims = nb_output_dims;
713 relation->nb_input_dims = nb_input_dims;
714 relation->nb_local_dims = nb_local_dims;
715 relation->nb_parameters = nb_parameters;
717 // Read the matrix of constraints.
718 for (i = 0; i < relation->nb_rows; i++) {
719 c = openscop_util_skip_blank_and_comments(foo, s);
720 if (c == NULL)
721 OPENSCOP_error("not enough rows");
723 for (j = 0; j < relation->nb_columns; j++) {
724 if (c == NULL || *c == '#' || *c == '\n')
725 OPENSCOP_error("not enough columns");
726 if (sscanf(c, "%s%n", str, &n) == 0)
727 OPENSCOP_error("not enough rows");
729 openscop_int_sread(str, precision, relation->m[i], j);
730 c += n;
734 // Build the linked list of union parts.
735 if (first == 1) {
736 relation_union = relation;
737 first = 0;
739 else {
740 previous->next = relation;
743 previous = relation;
744 read_properties = 1;
747 return relation_union;
751 /*+***************************************************************************
752 * Memory allocation/deallocation function *
753 *****************************************************************************/
757 * openscop_relation_pmalloc function:
758 * (precision malloc) this function allocates the memory space for an
759 * openscop_relation_t structure and sets its fields with default values.
760 * Then it returns a pointer to the allocated space.
761 * \param[in] precision The precision of the constraint matrix.
762 * \param[in] nb_rows The number of row of the relation to allocate.
763 * \param[in] nb_columns The number of columns of the relation to allocate.
764 * \return A pointer to an empty relation with fields set to default values
765 * and a ready-to-use constraint matrix.
767 openscop_relation_p openscop_relation_pmalloc(int precision,
768 int nb_rows, int nb_columns) {
769 openscop_relation_p relation;
770 void ** p, * q;
771 int i, j;
773 OPENSCOP_malloc(relation, openscop_relation_p, sizeof(openscop_relation_t));
774 relation->type = OPENSCOP_UNDEFINED;
775 relation->nb_rows = nb_rows;
776 relation->nb_columns = nb_columns;
777 relation->nb_output_dims = OPENSCOP_UNDEFINED;
778 relation->nb_input_dims = OPENSCOP_UNDEFINED;
779 relation->nb_parameters = OPENSCOP_UNDEFINED;
780 relation->nb_local_dims = OPENSCOP_UNDEFINED;
781 relation->precision = precision;
783 if ((nb_rows == 0) || (nb_columns == 0) ||
784 (nb_rows == OPENSCOP_UNDEFINED) || (nb_columns == OPENSCOP_UNDEFINED)) {
785 relation->m = NULL;
787 else {
788 OPENSCOP_malloc(p, void **, nb_rows * sizeof(void *));
789 OPENSCOP_malloc(q, void *,
790 nb_rows * nb_columns * openscop_int_sizeof(precision));
791 relation->m = p;
792 for (i = 0; i < nb_rows; i++) {
793 relation->m[i] = openscop_int_address(precision, q, i * nb_columns);
794 for (j = 0; j < nb_columns; j++)
795 openscop_int_init_set_si(precision, relation->m[i], j, 0);
799 relation->next = NULL;
801 return relation;
806 * openscop_relation_malloc function:
807 * this function allocates the memory space for an openscop_relation_t
808 * structure and sets its fields with default values. Then it returns a
809 * pointer to the allocated space. The precision of the constraint matrix
810 * elements corresponds to the precision environment variable or to the
811 * highest available precision if it is not defined.
812 * \param[in] nb_rows The number of row of the relation to allocate.
813 * \param[in] nb_columns The number of columns of the relation to allocate.
814 * \return A pointer to an empty relation with fields set to default values
815 * and a ready-to-use constraint matrix.
817 openscop_relation_p openscop_relation_malloc(int nb_rows, int nb_columns) {
818 int precision = openscop_util_get_precision();
819 return openscop_relation_pmalloc(precision, nb_rows, nb_columns);
824 * openscop_relation_free_inside function:
825 * this function frees the allocated memory for the inside of a
826 * openscop_relation_t structure, i.e. only m.
827 * \param[in] relation The pointer to the relation we want to free internals.
829 void openscop_relation_free_inside(openscop_relation_p relation) {
830 int i, nb_elements;
831 void * p;
833 if (relation == NULL)
834 return;
836 nb_elements = relation->nb_rows * relation->nb_columns;
838 if (nb_elements > 0)
839 p = relation->m[0];
841 for (i = 0; i < nb_elements; i++)
842 openscop_int_clear(relation->precision, p, i);
844 if (relation->m != NULL) {
845 if (nb_elements > 0)
846 free(relation->m[0]);
847 free(relation->m);
853 * openscop_relation_free function:
854 * this function frees the allocated memory for an openscop_relation_t
855 * structure.
856 * \param[in] relation The pointer to the relation we want to free.
858 void openscop_relation_free(openscop_relation_p relation) {
859 openscop_relation_p tmp;
861 if (relation == NULL)
862 return;
864 while (relation != NULL) {
865 tmp = relation->next;
866 openscop_relation_free_inside(relation);
867 free(relation);
868 relation = tmp;
873 /*+***************************************************************************
874 * Processing functions *
875 *****************************************************************************/
879 * openscop_relation_nclone function:
880 * this functions builds and returns a "hard copy" (not a pointer copy) of a
881 * openscop_relation_t data structure such that the clone is restricted to the
882 * "n" first rows of the relation. This applies to all the parts in the case
883 * of a relation union.
884 * \param[in] relation The pointer to the relation we want to clone.
885 * \param[in] n The number of row of the relation we want to clone (the
886 * special value -1 means "all the rows").
887 * \return A pointer to the clone of the relation union restricted to the
888 * first n rows of constraint matrix for each part of the union.
890 openscop_relation_p openscop_relation_nclone(openscop_relation_p relation,
891 int n) {
892 int i, j;
893 int first = 1, all_rows = 0;
894 openscop_relation_p clone = NULL, node, previous = NULL;
896 if (n == -1)
897 all_rows = 1;
899 while (relation != NULL) {
900 if (all_rows)
901 n = relation->nb_rows;
903 if (n > relation->nb_rows)
904 OPENSCOP_error("not enough rows to clone in the relation");
906 node = openscop_relation_pmalloc(relation->precision,
907 n, relation->nb_columns);
908 node->type = relation->type;
909 node->nb_output_dims = relation->nb_output_dims;
910 node->nb_input_dims = relation->nb_input_dims;
911 node->nb_local_dims = relation->nb_local_dims;
912 node->nb_parameters = relation->nb_parameters;
914 for (i = 0; i < n; i++)
915 for (j = 0; j < relation->nb_columns; j++)
916 openscop_int_assign(relation->precision,
917 node->m[i], j,
918 relation->m[i], j);
920 if (first) {
921 first = 0;
922 clone = node;
923 previous = node;
925 else {
926 previous->next = node;
927 previous = previous->next;
930 relation = relation->next;
933 return clone;
938 * openscop_relation_clone function:
939 * this function builds and returns a "hard copy" (not a pointer copy) of an
940 * openscop_relation_t data structure (the full union of relation).
941 * \param[in] relation The pointer to the relation we want to clone.
942 * \return A pointer to the clone of the union of relations.
944 openscop_relation_p openscop_relation_clone(openscop_relation_p relation) {
945 if (relation == NULL)
946 return NULL;
948 return openscop_relation_nclone(relation, -1);
953 * openscop_relation_replace_vector function:
954 * this function replaces the "row"^th row of a relation "relation" with the
955 * vector "vector". It directly updates the relation union part pointed
956 * by "relation" and this part only.
957 * \param[in,out] relation The relation we want to replace a row.
958 * \param[in] vector The vector that will replace a row of the relation.
959 * \param[in] row The row of the relation to be replaced.
961 void openscop_relation_replace_vector(openscop_relation_p relation,
962 openscop_vector_p vector, int row) {
963 int i;
965 if ((relation == NULL) || (vector == NULL) ||
966 (relation->precision != vector->precision) ||
967 (relation->nb_columns != vector->size) ||
968 (row >= relation->nb_rows) || (row < 0))
969 OPENSCOP_error("vector cannot replace relation row");
971 for (i = 0; i < vector->size; i++)
972 openscop_int_assign(relation->precision,
973 relation->m[row], i,
974 vector->v, i);
979 * openscop_relation_add_vector function:
980 * this function adds (meaning, +) a vector to the "row"^th row of a
981 * relation "relation". It directly updates the relation union part pointed
982 * by "relation" and this part only.
983 * \param[in,out] relation The relation we want to add a vector to a row.
984 * \param[in] vector The vector that will replace a row of the relation.
985 * \param[in] row The row of the relation to be replaced.
987 void openscop_relation_add_vector(openscop_relation_p relation,
988 openscop_vector_p vector, int row) {
989 int i;
991 if ((relation == NULL) || (vector == NULL) ||
992 (relation->precision != vector->precision) ||
993 (relation->nb_columns != vector->size) ||
994 (row >= relation->nb_rows) || (row < 0))
995 OPENSCOP_error("vector cannot be added to relation");
997 if (openscop_int_get_si(relation->precision, relation->m[row], 0) == 0)
998 openscop_int_assign(relation->precision,
999 relation->m[row], 0,
1000 vector->v, 0);
1002 for (i = 1; i < vector->size; i++)
1003 openscop_int_add(relation->precision,
1004 relation->m[row], i,
1005 relation->m[row], i,
1006 vector->v, i);
1011 * openscop_relation_sub_vector function:
1012 * this function subtracts the vector "vector" to the "row"^th row of
1013 * a relation "relation. It directly updates the relation union part pointed
1014 * by "relation" and this part only.
1015 * \param[in,out] relation The relation where to subtract a vector to a row.
1016 * \param[in] vector The vector to subtract to a relation row.
1017 * \param[in] row The row of the relation to subtract the vector.
1019 void openscop_relation_sub_vector(openscop_relation_p relation,
1020 openscop_vector_p vector, int row) {
1021 int i;
1023 if ((relation == NULL) || (vector == NULL) ||
1024 (relation->precision != vector->precision) ||
1025 (relation->nb_columns != vector->size) ||
1026 (row >= relation->nb_rows) || (row < 0))
1027 OPENSCOP_error("vector cannot be subtracted to row");
1029 if (openscop_int_get_si(relation->precision, relation->m[row], 0) == 0)
1030 openscop_int_assign(relation->precision,
1031 relation->m[row], 0,
1032 vector->v, 0);
1034 for (i = 1; i < vector->size; i++)
1035 openscop_int_sub(relation->precision,
1036 relation->m[row], i,
1037 relation->m[row], i,
1038 vector->v, i);
1043 * openscop_relation_insert_vector function:
1044 * this function inserts a new row corresponding to the vector "vector" to
1045 * the relation "relation" by inserting it at the "row"^th row. It directly
1046 * updates the relation union part pointed by "relation" and this part only.
1047 * If "vector" (or "relation") is NULL, the relation is left unmodified.
1048 * \param[in,out] relation The relation we want to extend.
1049 * \param[in] vector The vector that will be added relation.
1050 * \param[in] row The row where to insert the vector.
1052 void openscop_relation_insert_vector(openscop_relation_p relation,
1053 openscop_vector_p vector, int row) {
1054 openscop_relation_p temp;
1056 temp = openscop_relation_from_vector(vector);
1057 openscop_relation_insert_constraints(relation, temp, row);
1058 openscop_relation_free(temp);
1063 * openscop_relation_from_vector function:
1064 * this function converts a vector "vector" to a relation with a single row
1065 * and returns a pointer to that relation.
1066 * \param[in] vector The vector to convert to a relation.
1067 * \return A pointer to a relation resulting from the vector conversion.
1069 openscop_relation_p openscop_relation_from_vector(openscop_vector_p vector) {
1070 openscop_relation_p relation;
1072 if (vector == NULL)
1073 return NULL;
1075 relation = openscop_relation_pmalloc(vector->precision, 1, vector->size);
1076 openscop_relation_replace_vector(relation, vector, 0);
1077 return relation;
1082 * openscop_relation_replace_constraints function:
1083 * this function replaces some rows of a relation "r1" with the rows of
1084 * the relation "r2". It begins at the "row"^th row of "r1". It directly
1085 * updates the relation union part pointed by "r1" and this part only.
1086 * \param[in,out] r1 The relation we want to change some rows.
1087 * \param[in] r2 The relation containing the new rows.
1088 * \param[in] row The first row of the relation r1 to be replaced.
1090 void openscop_relation_replace_constraints(openscop_relation_p r1,
1091 openscop_relation_p r2, int row) {
1092 int i, j;
1094 if ((r1 == NULL) || (r2 == NULL) ||
1095 (r1->precision != r2->precision) ||
1096 (r1->nb_columns != r1->nb_columns) ||
1097 ((row + r2->nb_rows) > r1->nb_rows) || (row < 0))
1098 OPENSCOP_error("relation rows could not be replaced");
1100 for (i = 0; i < r2->nb_rows; i++)
1101 for (j = 0; j < r2->nb_columns; j++)
1102 openscop_int_assign(r1->precision, r1->m[i+row], j, r2->m[i], j);
1107 * openscop_relation_insert_constraints function:
1108 * this function adds new rows corresponding to the relation "r1" to
1109 * the relation "r2" by inserting it at the "row"^th row. It directly
1110 * updates the relation union part pointed by "r1" and this part only.
1111 * If "r2" (or "r1") is NULL, the relation is left unmodified.
1112 * \param[in,out] r1 The relation we want to extend.
1113 * \param[in] r2 The relation to be inserted.
1114 * \param[in] row The row where to insert the relation
1116 void openscop_relation_insert_constraints(openscop_relation_p r1,
1117 openscop_relation_p r2, int row) {
1118 int i, j;
1119 openscop_relation_p temp;
1121 if ((r1 == NULL) || (r2 == NULL))
1122 return;
1124 if ((r1->nb_columns != r2->nb_columns) ||
1125 (r1->precision != r2->precision) ||
1126 (row > r1->nb_rows) || (row < 0))
1127 OPENSCOP_error("constraints cannot be inserted");
1129 // We use a temporary relation just to reuse existing functions. Cleaner.
1130 temp = openscop_relation_pmalloc(r1->precision,
1131 r1->nb_rows + r2->nb_rows,
1132 r1->nb_columns);
1134 for (i = 0; i < row; i++)
1135 for (j = 0; j < r1->nb_columns; j++)
1136 openscop_int_assign(r1->precision, temp->m[i], j, r1->m[i], j);
1138 openscop_relation_replace_constraints(temp, r2, row);
1140 for (i = row + r2->nb_rows; i < r2->nb_rows + r1->nb_rows; i++)
1141 for (j = 0; j < r1->nb_columns; j++)
1142 openscop_int_assign(r1->precision,
1143 temp->m[i], j,
1144 r1->m[i-r2->nb_rows], j);
1146 openscop_relation_free_inside(r1);
1148 // Replace the inside of relation.
1149 r1->nb_rows = temp->nb_rows;
1150 r1->m = temp->m;
1152 // Free the temp "shell".
1153 free(temp);
1158 * openscop_relation_concat_constraints function:
1159 * this function builds a new relation from two relations sent as
1160 * parameters. The new set of constraints is built as the concatenation
1161 * of the rows of the first elements of the two relation unions r1 and r2.
1162 * This means, there is no next field in the result.
1163 * \param[in] r1 The first relation.
1164 * \param[in] r2 The second relation.
1165 * \return A pointer to the relation resulting from the concatenation of
1166 * the first elements of r1 and r2.
1168 openscop_relation_p openscop_relation_concat_constraints(
1169 openscop_relation_p r1,
1170 openscop_relation_p r2) {
1171 openscop_relation_p new;
1173 if (r1 == NULL)
1174 return openscop_relation_clone(r2);
1176 if (r2 == NULL)
1177 return openscop_relation_clone(r1);
1179 if (r1->nb_columns != r2->nb_columns)
1180 OPENSCOP_error("incompatible sizes for concatenation");
1182 if (r1->next || r2->next)
1183 OPENSCOP_warning("relation concatenation is done on the first elements "
1184 "of union only");
1186 new = openscop_relation_pmalloc(r1->precision,
1187 r1->nb_rows + r2->nb_rows,
1188 r1->nb_columns);
1189 openscop_relation_replace_constraints(new, r1, 0);
1190 openscop_relation_replace_constraints(new, r2, r1->nb_rows);
1192 return new;
1197 * openscop_relation_equal function:
1198 * this function returns true if the two relations provided as parameters
1199 * are the same, false otherwise.
1200 * \param[in] r1 The first relation.
1201 * \param[in] r2 The second relation.
1202 * \return 1 if r1 and r2 are the same (content-wise), 0 otherwise.
1204 int openscop_relation_equal(openscop_relation_p r1, openscop_relation_p r2) {
1205 int i, j;
1207 while ((r1 != NULL) && (r2 != NULL)) {
1208 if (r1 == r2)
1209 return 1;
1211 if ((r1->type != r2->type) ||
1212 (r1->precision != r2->precision) ||
1213 (r1->nb_rows != r2->nb_rows) ||
1214 (r1->nb_columns != r2->nb_columns) ||
1215 (r1->nb_output_dims != r2->nb_output_dims) ||
1216 (r1->nb_input_dims != r2->nb_input_dims) ||
1217 (r1->nb_local_dims != r2->nb_local_dims) ||
1218 (r1->nb_parameters != r2->nb_parameters))
1219 return 0;
1221 for (i = 0; i < r1->nb_rows; ++i)
1222 for (j = 0; j < r1->nb_columns; ++j)
1223 if (openscop_int_ne(r1->precision, r1->m[i], j, r2->m[i], j))
1224 return 0;
1226 r1 = r1->next;
1227 r2 = r2->next;
1230 if (((r1 == NULL) && (r2 != NULL)) || ((r1 != NULL) && (r2 == NULL)))
1231 return 0;
1233 return 1;
1238 * openscop_relation_check_attribute internal function:
1239 * This function checks whether an "actual" value is the same as an
1240 * "expected" value or not. If the expected value is set to
1241 * OPENSCOP_UNDEFINED, this function sets it to the "actual" value
1242 * and do not report a difference has been detected.
1243 * It returns 0 if a difference has been detected, 1 otherwise.
1244 * \param[in,out] expected Pointer to the expected value (the value is
1245 * modified if it was set to OPENSCOP_UNDEFINED).
1246 * \param[in] actual Value we want to check.
1247 * \return 0 if the values are not the same while the expected value was
1248 * not OPENSCOP_UNDEFINED, 1 otherwise.
1250 static
1251 int openscop_relation_check_attribute(int * expected, int actual) {
1252 if (*expected != OPENSCOP_UNDEFINED) {
1253 if ((actual != OPENSCOP_UNDEFINED) &&
1254 (actual != *expected)) {
1255 OPENSCOP_warning("unexpected atribute");
1256 return 0;
1259 else {
1260 *expected = actual;
1263 return 1;
1268 * openscop_relation_check_nb_columns internal function:
1269 * This function checks that the number of columns of a relation
1270 * corresponds to some expected properties (setting an expected property to
1271 * OPENSCOP_UNDEFINED makes this function unable to detect a problem).
1272 * It returns 0 if the number of columns seems incorrect or 1 if no problem
1273 * has been detected.
1274 * \param[in] relation The relation we want to check the number of columns.
1275 * \param[in] expected_nb_output_dims Expected number of output dimensions.
1276 * \param[in] expected_nb_input_dims Expected number of input dimensions.
1277 * \param[in] expected_nb_parameters Expected number of parameters.
1278 * \return 0 if the number of columns seems incorrect, 1 otherwise.
1280 static
1281 int openscop_relation_check_nb_columns(openscop_relation_p relation,
1282 int expected_nb_output_dims,
1283 int expected_nb_input_dims,
1284 int expected_nb_parameters) {
1285 int expected_nb_local_dims, expected_nb_columns;
1287 if ((expected_nb_output_dims != OPENSCOP_UNDEFINED) &&
1288 (expected_nb_input_dims != OPENSCOP_UNDEFINED) &&
1289 (expected_nb_parameters != OPENSCOP_UNDEFINED)) {
1291 if (relation->nb_local_dims == OPENSCOP_UNDEFINED)
1292 expected_nb_local_dims = 0;
1293 else
1294 expected_nb_local_dims = relation->nb_local_dims;
1296 expected_nb_columns = expected_nb_output_dims +
1297 expected_nb_input_dims +
1298 expected_nb_local_dims +
1299 expected_nb_parameters +
1302 if (expected_nb_columns != relation->nb_columns) {
1303 OPENSCOP_warning("unexpected number of columns");
1304 return 0;
1308 return 1;
1313 * openscop_relation_integrity_check function:
1314 * this function checks that a relation is "well formed" according to some
1315 * expected properties (setting an expected value to OPENSCOP_UNDEFINED means
1316 * that we do not expect a specific value) and what the relation is supposed
1317 * to represent. It returns 0 if the check failed or 1 if no problem has been
1318 * detected.
1319 * \param[in] relation The relation we want to check.
1320 * \param[in] type Semantics about this relation (domain, access...).
1321 * \param[in] expected_nb_output_dims Expected number of output dimensions.
1322 * \param[in] expected_nb_input_dims Expected number of input dimensions.
1323 * \param[in] expected_nb_parameters Expected number of parameters.
1324 * \return 0 if the integrity check fails, 1 otherwise.
1326 int openscop_relation_integrity_check(openscop_relation_p relation,
1327 int expected_type,
1328 int expected_nb_output_dims,
1329 int expected_nb_input_dims,
1330 int expected_nb_parameters) {
1331 int i;
1333 // Check the NULL case.
1334 if (relation == NULL) {
1335 if ((expected_nb_output_dims != OPENSCOP_UNDEFINED) ||
1336 (expected_nb_input_dims != OPENSCOP_UNDEFINED) ||
1337 (expected_nb_parameters != OPENSCOP_UNDEFINED)) {
1338 OPENSCOP_warning("NULL relation with some expected attibutes");
1339 //return 0;
1342 return 1;
1345 // Check the type.
1346 if (((expected_type != OPENSCOP_TYPE_ACCESS) &&
1347 (expected_type != relation->type)) ||
1348 ((expected_type == OPENSCOP_TYPE_ACCESS) &&
1349 (!openscop_relation_is_access(relation)))) {
1350 OPENSCOP_warning("wrong type");
1351 openscop_relation_dump(stderr, relation);
1352 return 0;
1355 // Check that relations have no undefined atributes.
1356 if ((relation->nb_output_dims == OPENSCOP_UNDEFINED) ||
1357 (relation->nb_input_dims == OPENSCOP_UNDEFINED) ||
1358 (relation->nb_local_dims == OPENSCOP_UNDEFINED) ||
1359 (relation->nb_parameters == OPENSCOP_UNDEFINED)) {
1360 OPENSCOP_warning("all attributes should be defined");
1361 openscop_relation_dump(stderr, relation);
1362 return 0;
1365 // Check that a context has actually 0 output dimensions.
1366 if ((relation->type == OPENSCOP_TYPE_CONTEXT) &&
1367 (relation->nb_output_dims != 0)) {
1368 OPENSCOP_warning("context without 0 as number of output dimensions");
1369 openscop_relation_dump(stderr, relation);
1370 return 0;
1373 // Check that a domain or a context has actually 0 input dimensions.
1374 if (((relation->type == OPENSCOP_TYPE_DOMAIN) ||
1375 (relation->type == OPENSCOP_TYPE_CONTEXT)) &&
1376 (relation->nb_input_dims != 0)) {
1377 OPENSCOP_warning("domain or context without 0 input dimensions");
1378 openscop_relation_dump(stderr, relation);
1379 return 0;
1382 // Check properties according to expected values (and if expected values
1383 // are undefined, define them with the first relation part properties).
1384 if (!openscop_relation_check_attribute(&expected_nb_output_dims,
1385 relation->nb_output_dims) ||
1386 !openscop_relation_check_attribute(&expected_nb_input_dims,
1387 relation->nb_input_dims) ||
1388 !openscop_relation_check_attribute(&expected_nb_parameters,
1389 relation->nb_parameters)) {
1390 openscop_relation_dump(stderr, relation);
1391 return 0;
1394 while (relation != NULL) {
1396 // Attributes (except the number of local dimensions) should be the same
1397 // in all parts of the union.
1398 if ((expected_nb_output_dims != relation->nb_output_dims) ||
1399 (expected_nb_input_dims != relation->nb_input_dims) ||
1400 (expected_nb_parameters != relation->nb_parameters)) {
1401 OPENSCOP_warning("inconsistent attributes");
1402 openscop_relation_dump(stderr, relation);
1403 return 0;
1406 // Check whether the number of columns is OK or not.
1407 if (!openscop_relation_check_nb_columns(relation,
1408 expected_nb_output_dims,
1409 expected_nb_input_dims,
1410 expected_nb_parameters)) {
1411 openscop_relation_dump(stderr, relation);
1412 return 0;
1415 // Check the first column. The first column of a relation part should be
1416 // made of 0 or 1 only.
1417 if ((relation->nb_rows > 0) && (relation->nb_columns > 0)) {
1418 for (i = 0; i < relation->nb_rows; i++) {
1419 if (!openscop_int_zero(relation->precision, relation->m[i], 0) &&
1420 !openscop_int_one(relation->precision, relation->m[i], 0)) {
1421 OPENSCOP_warning("first column of a relation is not "
1422 "strictly made of 0 or 1");
1423 openscop_relation_dump(stderr, relation);
1424 return 0;
1429 // Array accesses must provide the array identifier.
1430 if ((openscop_relation_is_access(relation)) &&
1431 (openscop_relation_get_array_id(relation) == OPENSCOP_UNDEFINED)) {
1432 openscop_relation_dump(stderr, relation);
1433 return 0;
1436 relation = relation->next;
1439 return 1;
1444 * openscop_relation_union function:
1445 * this function builds a new relation from two relations provided
1446 * as parameters. The new relation is built as an union of the
1447 * two relations: the list of constraint sets are linked together.
1448 * \param[in] r1 The first relation.
1449 * \param[in] r2 The second relation.
1450 * \return A new relation corresponding to the union of r1 and r2.
1452 openscop_relation_p openscop_relation_union(openscop_relation_p r1,
1453 openscop_relation_p r2) {
1454 openscop_relation_p copy1, copy2, tmp;
1456 if ((r1 == NULL) && (r2 == NULL))
1457 return NULL;
1459 copy1 = openscop_relation_clone(r1);
1460 copy2 = openscop_relation_clone(r2);
1462 if ((r1 != NULL) && (r2 == NULL))
1463 return copy1;
1465 if ((r1 == NULL) && (r2 != NULL))
1466 return copy2;
1468 tmp = copy1;
1469 while (tmp->next != NULL)
1470 tmp = tmp->next;
1472 tmp->next = copy2;
1473 return copy1;
1477 /**
1478 * openscop_relation_set_type function:
1479 * this function sets the type of each relation union part in the relation
1480 * to the one provided as parameter.
1481 * \param relation The relation to set the type.
1482 * \param type The type.
1484 void openscop_relation_set_type(openscop_relation_p relation, int type) {
1486 while (relation != NULL) {
1487 relation->type = type;
1488 relation = relation->next;
1494 * openscop_relation_get_array_id function:
1495 * this function returns the array identifier in a relation with access type
1496 * It returns OPENSCOP_UNDEFINED if it is not able to find it (in particular
1497 * if there are irregularities in the relation).
1498 * \param[in] relation The relation where to find an array identifier.
1499 * \return The array identifier in the relation or OPENSCOP_UNDEFINED.
1501 int openscop_relation_get_array_id(openscop_relation_p relation) {
1502 int i;
1503 int first = 1;
1504 int array_id = OPENSCOP_UNDEFINED;
1505 int reference_array_id = OPENSCOP_UNDEFINED;
1506 int nb_array_id;
1507 int row_id = 0;
1508 int precision;
1510 if (relation == NULL)
1511 return OPENSCOP_UNDEFINED;
1513 if (!openscop_relation_is_access(relation)) {
1514 OPENSCOP_warning("asked for an array id of non-array relation");
1515 return OPENSCOP_UNDEFINED;
1518 while (relation != NULL) {
1519 precision = relation->precision;
1521 // There should be room to store the array identifier.
1522 if ((relation->nb_rows < 1) ||
1523 (relation->nb_columns < 3)) {
1524 OPENSCOP_warning("no array identifier in an access function");
1525 return OPENSCOP_UNDEFINED;
1528 // Array identifiers are m[i][#columns -1] / m[i][1], with i the only row
1529 // where m[i][1] is not 0.
1530 // - check there is exactly one row such that m[i][1] is not 0,
1531 // - check the whole ith row if full of 0 except m[i][1] and the id,
1532 // - check that (m[i][#columns -1] % m[i][1]) == 0,
1533 // - check that (-m[i][#columns -1] / m[i][1]) > 0.
1534 nb_array_id = 0;
1535 for (i = 0; i < relation->nb_rows; i++) {
1536 if (!openscop_int_zero(precision, relation->m[i], 1)) {
1537 nb_array_id ++;
1538 row_id = i;
1541 if (nb_array_id == 0) {
1542 OPENSCOP_warning("no array identifier in an access function");
1543 return OPENSCOP_UNDEFINED;
1545 if (nb_array_id > 1) {
1546 OPENSCOP_warning("several array identifiers in one access function");
1547 return OPENSCOP_UNDEFINED;
1549 for (i = 0; i < relation->nb_columns - 1; i++) {
1550 if ((i != 1) && !openscop_int_zero(precision, relation->m[row_id], i)) {
1551 OPENSCOP_warning("non integer array identifier");
1552 return OPENSCOP_UNDEFINED;
1555 if (!openscop_int_divisible(precision,
1556 relation->m[row_id], relation->nb_columns - 1,
1557 relation->m[row_id], 1)) {
1558 OPENSCOP_warning("rational array identifier");
1559 return OPENSCOP_UNDEFINED;
1561 array_id = -openscop_int_get_si(precision,
1562 relation->m[row_id],
1563 relation->nb_columns - 1);
1564 array_id /= openscop_int_get_si(precision, relation->m[row_id], 1);
1565 if (array_id <= 0) {
1566 OPENSCOP_warning("negative or 0 identifier in access function");
1567 return OPENSCOP_UNDEFINED;
1570 // Unions of accesses are allowed, but they should refer at the same array.
1571 if (first) {
1572 reference_array_id = array_id;
1573 first = 0;
1575 else {
1576 if (reference_array_id != array_id) {
1577 OPENSCOP_warning("inconsistency of array identifiers in an "
1578 "union of access relations");
1579 return OPENSCOP_UNDEFINED;
1583 relation = relation->next;
1586 return array_id;
1591 * openscop_relation_is_access function:
1592 * this function returns 1 if the relation corresponds to an access relation,
1593 * whatever its precise type (read, write etc.), 0 otherwise.
1594 * \param relation The relation to check wheter it is an access relation or not.
1595 * \return 1 if the relation is an access relation, 0 otherwise.
1597 int openscop_relation_is_access(openscop_relation_p relation) {
1599 if (relation == NULL)
1600 return 0;
1602 if ((relation->type == OPENSCOP_TYPE_ACCESS) ||
1603 (relation->type == OPENSCOP_TYPE_READ) ||
1604 (relation->type == OPENSCOP_TYPE_WRITE) ||
1605 (relation->type == OPENSCOP_TYPE_MAY_WRITE))
1606 return 1;
1608 return 0;