2 /*+-----------------------------------------------------------------**
4 **-----------------------------------------------------------------**
6 **-----------------------------------------------------------------**
7 ** First version: 30/04/2008 **
8 **-----------------------------------------------------------------**
11 *****************************************************************************
12 * OpenScop: Structures and formats for polyhedral tools to talk together *
13 *****************************************************************************
14 * ,___,,_,__,,__,,__,,__,,_,__,,_,__,,__,,___,_,__,,_,__, *
15 * / / / // // // // / / / // // / / // / /|,_, *
16 * / / / // // // // / / / // // / / // / / / /\ *
17 * |~~~|~|~~~|~~~|~~~|~~~|~|~~~|~|~~~|~~~|~~~|~|~~~|~|~~~|/_/ \ *
18 * | G |C| P | = | L | P |=| = |C| = | = | = |=| = |=| C |\ \ /\ *
19 * | R |l| o | = | e | l |=| = |a| = | = | = |=| = |=| L | \# \ /\ *
20 * | A |a| l | = | t | u |=| = |n| = | = | = |=| = |=| o | |\# \ \ *
21 * | P |n| l | = | s | t |=| = |d| = | = | = | | |=| o | | \# \ \ *
22 * | H | | y | | e | o | | = |l| | | = | | | | G | | \ \ \ *
23 * | I | | | | e | | | | | | | | | | | | | \ \ \ *
24 * | T | | | | | | | | | | | | | | | | | \ \ \ *
25 * | E | | | | | | | | | | | | | | | | | \ \ \ *
26 * | * |*| * | * | * | * |*| * |*| * | * | * |*| * |*| * | / \* \ \ *
27 * | O |p| e | n | S | c |o| p |-| L | i | b |r| a |r| y |/ \ \ / *
28 * '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---' '--' *
30 * Copyright (C) 2008 University Paris-Sud 11 and INRIA *
32 * (3-clause BSD license) *
33 * Redistribution and use in source and binary forms, with or without *
34 * modification, are permitted provided that the following conditions *
37 * 1. Redistributions of source code must retain the above copyright notice, *
38 * this list of conditions and the following disclaimer. *
39 * 2. Redistributions in binary form must reproduce the above copyright *
40 * notice, this list of conditions and the following disclaimer in the *
41 * documentation and/or other materials provided with the distribution. *
42 * 3. The name of the author may not be used to endorse or promote products *
43 * derived from this software without specific prior written permission. *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR *
46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES *
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *
48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, *
49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT *
50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, *
51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY *
52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT *
53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF *
54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
56 * OpenScop Library, a library to manipulate OpenScop formats and data *
57 * structures. Written by: *
58 * Cedric Bastoul <Cedric.Bastoul@u-psud.fr> and *
59 * Louis-Noel Pouchet <Louis-Noel.pouchet@inria.fr> *
61 *****************************************************************************/
68 # include <openscop/relation.h>
71 /*+***************************************************************************
72 * Structure display function *
73 *****************************************************************************/
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.
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
);
92 case OPENSCOP_TYPE_CONTEXT
: {
93 fprintf(file
, OPENSCOP_STRING_CONTEXT
);
96 case OPENSCOP_TYPE_DOMAIN
: {
97 fprintf(file
, OPENSCOP_STRING_DOMAIN
);
100 case OPENSCOP_TYPE_SCATTERING
: {
101 fprintf(file
, OPENSCOP_STRING_SCATTERING
);
104 case OPENSCOP_TYPE_READ
: {
105 fprintf(file
, OPENSCOP_STRING_READ
);
108 case OPENSCOP_TYPE_WRITE
: {
109 fprintf(file
, OPENSCOP_STRING_WRITE
);
112 case OPENSCOP_TYPE_MAY_WRITE
: {
113 fprintf(file
, OPENSCOP_STRING_MAY_WRITE
);
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
,
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
);
149 openscop_int_dump_precision(file
, relation
->precision
);
150 fprintf(file
, ")\n");
153 fprintf(file
, "+-- NULL relation\n");
156 while (relation
!= NULL
) {
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
);
164 openscop_int_dump_precision(file
, relation
->precision
);
165 fprintf(file
, ")\n");
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");
185 for (j
= 0; j
< relation
->nb_columns
; j
++) {
186 openscop_int_print(file
, relation
->precision
, relation
->m
[i
], j
);
190 fprintf(file
, "]\n");
193 relation
= relation
->next
;
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");
207 for (j
= 0; j
<= level
; j
++)
208 fprintf(file
, "|\t");
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
234 * \param[in] cst A boolean set to 1 if the value is a constant,
236 * \param[in] name String containing the name of the element.
237 * \return A string that contains the printing of a value.
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));
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
);
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
);
269 if (openscop_int_one(precision
, val
, 0)) {
270 sprintf(sval
, "+%s", name
);
274 openscop_int_sprint(temp
, precision
, val
, 0);
276 sprintf(temp
, "*%s", name
);
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)) {
289 openscop_int_sprint(temp
, precision
, val
, 0);
293 openscop_int_sprint(sval
, precision
, val
, 0);
306 char ** openscop_relation_strings(openscop_relation_p relation
,
307 openscop_names_p names
) {
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
);
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
]);
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
]);
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
]);
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
) {
372 char * sline
= (char *)malloc(OPENSCOP_MAX_STRING
* sizeof(char));
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]);
387 // Free the array of element strings.
388 for (i
= 0; i
< relation
->nb_columns
- 2; i
++)
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
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.
413 void openscop_relation_properties(openscop_relation_p relation
,
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
)
431 if (openscop_relation_is_access(relation
))
432 type
= OPENSCOP_TYPE_ACCESS
;
434 type
= relation
->type
;
436 // There is some redundancy but I believe the code is cleaner this way.
438 case OPENSCOP_TYPE_CONTEXT
: {
439 *nb_parameters
= relation
->nb_parameters
;
442 *nb_localdims
= relation
->nb_local_dims
;
446 case OPENSCOP_TYPE_DOMAIN
: {
447 *nb_parameters
= relation
->nb_parameters
;
448 *nb_iterators
= relation
->nb_output_dims
;
450 *nb_localdims
= relation
->nb_local_dims
;
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
;
462 case OPENSCOP_TYPE_ACCESS
: {
463 *nb_parameters
= relation
->nb_parameters
;
464 *nb_iterators
= relation
->nb_input_dims
;
466 *nb_localdims
= relation
->nb_local_dims
;
467 *array_id
= openscop_relation_get_array_id(relation
);
475 openscop_names_p
openscop_relation_names(openscop_relation_p relation
) {
482 openscop_relation_properties(relation
, &nb_parameters
, &nb_iterators
,
483 &nb_scattdims
, &nb_localdims
, &array_id
);
485 return openscop_names_generate("P", nb_parameters
,
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.
505 void openscop_relation_print_comment(FILE * file
,
506 openscop_relation_p relation
, int row
) {
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");
515 fprintf(file
, " >= 0");
517 openscop_names_free(names
);
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
) {
533 int printable_comments
;
534 openscop_relation_p r
;
536 if (relation
== NULL
) {
537 fprintf(file
, "# NULL relation\n");
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.
553 openscop_relation_print_type(file
, relation
);
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
++) {
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
);
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
);
581 openscop_relation_print_comment(file
, relation
, i
);
585 relation
= relation
->next
;
590 /*****************************************************************************
592 *****************************************************************************/
596 * openscop_relation_read_type function:
597 * this function reads a textual relation type and returns its integer
599 * \param[in] file The input stream.
600 * \return The relation type.
603 int openscop_relation_read_type(FILE * file
) {
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
;
619 if (!strcmp(strings
->string
[0], OPENSCOP_STRING_CONTEXT
)) {
620 type
= OPENSCOP_TYPE_CONTEXT
;
624 if (!strcmp(strings
->string
[0], OPENSCOP_STRING_DOMAIN
)) {
625 type
= OPENSCOP_TYPE_DOMAIN
;
629 if (!strcmp(strings
->string
[0], OPENSCOP_STRING_SCATTERING
)) {
630 type
= OPENSCOP_TYPE_SCATTERING
;
634 if (!strcmp(strings
->string
[0], OPENSCOP_STRING_READ
)) {
635 type
= OPENSCOP_TYPE_READ
;
639 if (!strcmp(strings
->string
[0], OPENSCOP_STRING_WRITE
)) {
640 type
= OPENSCOP_TYPE_WRITE
;
644 if (!strcmp(strings
->string
[0], OPENSCOP_STRING_MAY_WRITE
)) {
645 type
= OPENSCOP_TYPE_MAY_WRITE
;
649 OPENSCOP_error("relation type not supported");
652 openscop_strings_free(strings
);
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;
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
) {
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");
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.
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
);
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
);
734 // Build the linked list of union parts.
736 relation_union
= relation
;
740 previous
->next
= relation
;
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
;
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
)) {
788 OPENSCOP_malloc(p
, void **, nb_rows
* sizeof(void *));
789 OPENSCOP_malloc(q
, void *,
790 nb_rows
* nb_columns
* openscop_int_sizeof(precision
));
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
;
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
) {
833 if (relation
== NULL
)
836 nb_elements
= relation
->nb_rows
* relation
->nb_columns
;
841 for (i
= 0; i
< nb_elements
; i
++)
842 openscop_int_clear(relation
->precision
, p
, i
);
844 if (relation
->m
!= NULL
) {
846 free(relation
->m
[0]);
853 * openscop_relation_free function:
854 * this function frees the allocated memory for an openscop_relation_t
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
)
864 while (relation
!= NULL
) {
865 tmp
= relation
->next
;
866 openscop_relation_free_inside(relation
);
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
,
893 int first
= 1, all_rows
= 0;
894 openscop_relation_p clone
= NULL
, node
, previous
= NULL
;
899 while (relation
!= NULL
) {
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
,
926 previous
->next
= node
;
927 previous
= previous
->next
;
930 relation
= relation
->next
;
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
)
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
) {
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
,
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
) {
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
,
1002 for (i
= 1; i
< vector
->size
; i
++)
1003 openscop_int_add(relation
->precision
,
1004 relation
->m
[row
], i
,
1005 relation
->m
[row
], 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
) {
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,
1034 for (i
= 1; i
< vector
->size
; i
++)
1035 openscop_int_sub(relation
->precision
,
1036 relation
->m
[row
], i
,
1037 relation
->m
[row
], 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
;
1075 relation
= openscop_relation_pmalloc(vector
->precision
, 1, vector
->size
);
1076 openscop_relation_replace_vector(relation
, vector
, 0);
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
) {
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
) {
1119 openscop_relation_p temp
;
1121 if ((r1
== NULL
) || (r2
== NULL
))
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
,
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
,
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
;
1152 // Free the temp "shell".
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;
1174 return openscop_relation_clone(r2
);
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 "
1186 new = openscop_relation_pmalloc(r1
->precision
,
1187 r1
->nb_rows
+ r2
->nb_rows
,
1189 openscop_relation_replace_constraints(new, r1
, 0);
1190 openscop_relation_replace_constraints(new, r2
, r1
->nb_rows
);
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
) {
1207 while ((r1
!= NULL
) && (r2
!= NULL
)) {
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
))
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
))
1230 if (((r1
== NULL
) && (r2
!= NULL
)) || ((r1
!= NULL
) && (r2
== NULL
)))
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.
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");
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.
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;
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");
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
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
,
1328 int expected_nb_output_dims
,
1329 int expected_nb_input_dims
,
1330 int expected_nb_parameters
) {
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");
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
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
);
1436 relation
= relation
->next
;
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
))
1459 copy1
= openscop_relation_clone(r1
);
1460 copy2
= openscop_relation_clone(r2
);
1462 if ((r1
!= NULL
) && (r2
== NULL
))
1465 if ((r1
== NULL
) && (r2
!= NULL
))
1469 while (tmp
->next
!= NULL
)
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
) {
1504 int array_id
= OPENSCOP_UNDEFINED
;
1505 int reference_array_id
= OPENSCOP_UNDEFINED
;
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.
1535 for (i
= 0; i
< relation
->nb_rows
; i
++) {
1536 if (!openscop_int_zero(precision
, relation
->m
[i
], 1)) {
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.
1572 reference_array_id
= array_id
;
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
;
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
)
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
))