Replace openscop_ prefix with osl_ to ease 80 columns programming
[openscop.git] / source / relation.c
blob00b26c575a55db7b1f54354391044159735b3212
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 <osl/relation.h>
71 /*+***************************************************************************
72 * Structure display function *
73 *****************************************************************************/
76 /**
77 * osl_relation_print_type function:
78 * this function displays the textual type of an osl_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 osl_relation_print_type(FILE * file, osl_relation_p relation) {
86 if (relation != NULL) {
87 switch (relation->type) {
88 case OSL_UNDEFINED: {
89 fprintf(file, OSL_STRING_UNDEFINED);
90 break;
92 case OSL_TYPE_CONTEXT: {
93 fprintf(file, OSL_STRING_CONTEXT);
94 break;
96 case OSL_TYPE_DOMAIN: {
97 fprintf(file, OSL_STRING_DOMAIN);
98 break;
100 case OSL_TYPE_SCATTERING: {
101 fprintf(file, OSL_STRING_SCATTERING);
102 break;
104 case OSL_TYPE_READ: {
105 fprintf(file, OSL_STRING_READ);
106 break;
108 case OSL_TYPE_WRITE: {
109 fprintf(file, OSL_STRING_WRITE);
110 break;
112 case OSL_TYPE_MAY_WRITE: {
113 fprintf(file, OSL_STRING_MAY_WRITE);
114 break;
116 default: {
117 OSL_warning("unknown relation type, "
118 "replaced with "OSL_STRING_UNDEFINED);
119 fprintf(file, OSL_STRING_UNDEFINED);
127 * osl_relation_idump function:
128 * this function displays a osl_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 osl_relation_idump(FILE * file, osl_relation_p relation, int level) {
137 int i, j, first = 1;
139 // Go to the right level.
140 for (j = 0; j < level; j++)
141 fprintf(file, "|\t");
143 if (relation != NULL) {
144 fprintf(file, "+-- osl_relation_t (");
145 osl_relation_print_type(file, relation);
146 fprintf(file, ", ");
147 osl_int_dump_precision(file, relation->precision);
148 fprintf(file, ")\n");
150 else {
151 fprintf(file, "+-- NULL relation\n");
154 while (relation != NULL) {
155 if (! first) {
156 // Go to the right level.
157 for (j = 0; j < level; j++)
158 fprintf(file, "|\t");
159 fprintf(file, "| osl_relation_t (");
160 osl_relation_print_type(file, relation);
161 fprintf(file, ", ");
162 osl_int_dump_precision(file, relation->precision);
163 fprintf(file, ")\n");
165 else
166 first = 0;
168 // A blank line
169 for(j = 0; j <= level; j++)
170 fprintf(file, "|\t");
171 fprintf(file, "%d %d %d %d %d %d\n",
172 relation->nb_rows, relation->nb_columns,
173 relation->nb_output_dims, relation->nb_input_dims,
174 relation->nb_local_dims, relation->nb_parameters);
176 // Display the relation.
177 for (i = 0; i < relation->nb_rows; i++) {
178 for (j = 0; j <= level; j++)
179 fprintf(file, "|\t");
181 fprintf(file, "[ ");
183 for (j = 0; j < relation->nb_columns; j++) {
184 osl_int_print(file, relation->precision, relation->m[i], j);
185 fprintf(file, " ");
188 fprintf(file, "]\n");
191 relation = relation->next;
193 // Next line.
194 if (relation != NULL) {
195 for (j = 0; j <= level; j++)
196 fprintf(file, "|\t");
197 fprintf(file, "|\n");
198 for (j = 0; j <= level; j++)
199 fprintf(file, "|\t");
200 fprintf(file, "V\n");
204 // The last line.
205 for (j = 0; j <= level; j++)
206 fprintf(file, "|\t");
207 fprintf(file, "\n");
212 * osl_relation_dump function:
213 * this function prints the content of a osl_relation_t structure
214 * (*relation) into a file (file, possibly stdout).
215 * \param[in] file File where informations are printed.
216 * \param[in] relation The relation whose information have to be printed.
218 void osl_relation_dump(FILE * file, osl_relation_p relation) {
219 osl_relation_idump(file, relation, 0);
224 * osl_relation_expression_element function:
225 * this function returns a string containing the printing of a value (e.g.,
226 * an iterator with its coefficient or a constant).
227 * \param[in] val Address of the coefficient or constant value.
228 * \param[in] precision The precision of the value.
229 * \param[in,out] first Pointer to a boolean set to 1 if the current value
230 * is the first of an expresion, 0 otherwise (maybe
231 * updated).
232 * \param[in] cst A boolean set to 1 if the value is a constant,
233 * 0 otherwise.
234 * \param[in] name String containing the name of the element.
235 * \return A string that contains the printing of a value.
237 static
238 char * osl_relation_expression_element(void * val,
239 int precision, int * first,
240 int cst, char * name) {
241 char * temp = (char *)malloc(OSL_MAX_STRING * sizeof(char));
242 char * body = (char *)malloc(OSL_MAX_STRING * sizeof(char));
243 char * sval = (char *)malloc(OSL_MAX_STRING * sizeof(char));
245 body[0] = '\0';
246 sval[0] = '\0';
248 // statements for the 'normal' processing.
249 if (osl_int_notzero(precision, val, 0) && (!cst)) {
250 if ((*first) || osl_int_neg(precision, val, 0)) {
251 if (osl_int_one(precision, val, 0)) { // case 1
252 sprintf(sval, "%s", name);
254 else {
255 if (osl_int_mone(precision, val, 0)) { // case -1
256 sprintf(sval, "-%s", name);
258 else { // default case
259 osl_int_sprint(sval, precision, val, 0);
260 sprintf(temp, "*%s", name);
261 strcat(sval, temp);
264 *first = 0;
266 else {
267 if (osl_int_one(precision, val, 0)) {
268 sprintf(sval, "+%s", name);
270 else {
271 sprintf(sval, "+");
272 osl_int_sprint(temp, precision, val, 0);
273 strcat(sval, temp);
274 sprintf(temp, "*%s", name);
275 strcat(sval, temp);
279 else {
280 if (cst) {
281 if ((osl_int_zero(precision, val, 0) && (*first)) ||
282 (osl_int_neg(precision, val, 0)))
283 osl_int_sprint(sval, precision, val, 0);
284 if (osl_int_pos(precision, val, 0)) {
285 if (!(*first)) {
286 sprintf(sval, "+");
287 osl_int_sprint(temp, precision, val, 0);
288 strcat(sval, temp);
290 else {
291 osl_int_sprint(sval, precision, val, 0);
296 free(temp);
297 free(body);
299 return(sval);
303 static
304 char ** osl_relation_strings(osl_relation_p relation, osl_names_p names) {
305 char ** strings;
306 char temp[OSL_MAX_STRING];
307 int i, offset, array_id;
309 OSL_malloc(strings, char **, (relation->nb_columns - 1)*sizeof(char *));
310 strings[relation->nb_columns - 2] = NULL;
312 // 1. Output dimensions.
313 if (osl_relation_is_access(relation)) {
314 // The first output dimension is the array name.
315 array_id = osl_relation_get_array_id(relation);
316 strings[0] = strdup(names->arrays->string[array_id - 1]);
317 // The other ones are the array dimensions [1]...[n]
318 for (i = 1; i < relation->nb_output_dims; i++) {
319 sprintf(temp, "[%d]", i);
320 strings[i] = strdup(temp);
323 else
324 if (relation->type == OSL_TYPE_SCATTERING) {
325 for (i = 0; i < relation->nb_output_dims; i++) {
326 strings[i] = strdup(names->scatt_dims->string[i]);
329 else {
330 for (i = 0; i < relation->nb_output_dims; i++) {
331 strings[i] = strdup(names->iterators->string[i]);
335 // 2. Input dimensions.
336 offset = relation->nb_output_dims;
337 for (i = offset; i < relation->nb_input_dims + offset; i++)
338 strings[i] = strdup(names->iterators->string[i - offset]);
340 // 3. Local dimensions.
341 offset += relation->nb_input_dims;
342 for (i = offset; i < relation->nb_local_dims + offset; i++)
343 strings[i] = strdup(names->local_dims->string[i - offset]);
345 // 4. Parameters.
346 offset += relation->nb_local_dims;
347 for (i = offset; i < relation->nb_parameters + offset; i++)
348 strings[i] = strdup(names->parameters->string[i - offset]);
350 return strings;
355 * osl_relation_expression function:
356 * this function returns a string corresponding to an affine expression
357 * stored at the "row"^th row of the relation pointed by "relation".
358 * \param[in] relation A set of linear expressions.
359 * \param[in] row The row corresponding to the expression.
360 * \param[in] names The textual names of the various elements.
361 * Set to NULL if printing comments is not needed.
362 * \return A string that contains the printing of an affine expression.
364 char * osl_relation_expression(osl_relation_p relation,
365 int row, osl_names_p names) {
366 int i, first = 1;
367 char ** strings;
368 char * sval;
369 char * sline = (char *)malloc(OSL_MAX_STRING * sizeof(char));
370 sline[0] = '\0';
372 // Create the array of element strings.
373 strings = osl_relation_strings(relation, names);
375 // Create the expression.
376 for (i = 1; i <= relation->nb_columns - 2; i++) {
377 sval = osl_relation_expression_element(
378 osl_int_address(relation->precision, relation->m[row], i),
379 relation->precision, &first, 0, strings[i-1]);
380 strcat(sline, sval);
381 free(sval);
384 // Free the array of element strings.
385 for (i = 0; i < relation->nb_columns - 2; i++)
386 free(strings[i]);
387 free(strings);
389 return sline;
394 * osl_relation_properties function:
395 * this function returns, through its parameters, the values of the relation
396 * attributes (nb_iterators, nb_parameters etc), depending on its value and
397 * its type. The array identifier 0 is used when there is no array
398 * identifier (AND this is OK), OSL_UNDEFINED is used to report it
399 * is impossible to provide the property while it should.
400 * This function is not intended for checking, the input relation should be
401 * correct.
402 * \param[in] relation The relation to extract property values.
403 * \param[out] nb_parameters Number of parameter property.
404 * \param[out] nb_iterators Number of iterators property.
405 * \param[out] nb_scattdims Number of scattering dimensions property.
406 * \param[out] nb_localdims Number of local dimensions property.
407 * \param[out] array_id Array identifier property.
409 static
410 void osl_relation_properties(osl_relation_p relation,
411 int * nb_parameters,
412 int * nb_iterators,
413 int * nb_scattdims,
414 int * nb_localdims,
415 int * array_id) {
416 int type;
418 *nb_parameters = OSL_UNDEFINED;
419 *nb_iterators = OSL_UNDEFINED;
420 *nb_scattdims = OSL_UNDEFINED;
421 *nb_localdims = OSL_UNDEFINED;
422 *array_id = OSL_UNDEFINED;
424 if (relation == NULL)
425 return;
427 if (osl_relation_is_access(relation))
428 type = OSL_TYPE_ACCESS;
429 else
430 type = relation->type;
432 // There is some redundancy but I believe the code is cleaner this way.
433 switch (type) {
434 case OSL_TYPE_CONTEXT: {
435 *nb_parameters = relation->nb_parameters;
436 *nb_iterators = 0;
437 *nb_scattdims = 0;
438 *nb_localdims = relation->nb_local_dims;
439 *array_id = 0;
440 break;
442 case OSL_TYPE_DOMAIN: {
443 *nb_parameters = relation->nb_parameters;
444 *nb_iterators = relation->nb_output_dims;
445 *nb_scattdims = 0;
446 *nb_localdims = relation->nb_local_dims;
447 *array_id = 0;
448 break;
450 case OSL_TYPE_SCATTERING: {
451 *nb_parameters = relation->nb_parameters;
452 *nb_iterators = relation->nb_input_dims;
453 *nb_scattdims = relation->nb_output_dims;
454 *nb_localdims = relation->nb_local_dims;
455 *array_id = 0;
456 break;
458 case OSL_TYPE_ACCESS: {
459 *nb_parameters = relation->nb_parameters;
460 *nb_iterators = relation->nb_input_dims;
461 *nb_scattdims = 0;
462 *nb_localdims = relation->nb_local_dims;
463 *array_id = osl_relation_get_array_id(relation);
464 break;
470 static
471 osl_names_p osl_relation_names(osl_relation_p relation) {
472 int nb_parameters;
473 int nb_iterators;
474 int nb_scattdims;
475 int nb_localdims;
476 int array_id;
478 osl_relation_properties(relation, &nb_parameters, &nb_iterators,
479 &nb_scattdims, &nb_localdims, &array_id);
481 return osl_names_generate("P", nb_parameters,
482 "i", nb_iterators,
483 "t", nb_scattdims,
484 "l", nb_localdims,
485 "A", array_id);
490 * osl_relation_print_comment function:
491 * this function prints a comment corresponding to a constraint of a relation,
492 * according to its type. This function does not check that printing the
493 * comment is possible (i.e., are there enough names ?), hence it is the
494 * responsibility of the user to ensure he/she can call this function safely.
495 * \param[in] file File where informations are printed.
496 * \param[in] relation The relation for which a comment has to be printed.
497 * \param[in] row The constrain row for which a comment has to be printed.
498 * \param[in] names The textual names of the various elements.
500 static
501 void osl_relation_print_comment(FILE * file,
502 osl_relation_p relation, int row) {
503 char * expression;
504 osl_names_p names = osl_relation_names(relation);
506 expression = osl_relation_expression(relation, row, names);
507 fprintf(file, " ## %s", expression);
508 if (osl_int_zero(relation->precision, relation->m[row], 0))
509 fprintf(file, " == 0");
510 else
511 fprintf(file, " >= 0");
513 osl_names_free(names);
514 free(expression);
519 * osl_relation_print function:
520 * this function prints the content of an osl_relation_t structure
521 * (*relation) into a file (file, possibly stdout) in the OpenScop format.
522 * \param[in] file File where informations are printed.
523 * \param[in] relation The relation whose information has to be printed.
525 void osl_relation_print(FILE * file, osl_relation_p relation) {
526 int i, j;
527 int part, nb_parts;
528 int printable_comments;
529 osl_relation_p r;
531 if (relation == NULL) {
532 fprintf(file, "# NULL relation\n");
533 return;
536 //printable_comments = osl_relation_printable_comments(relation, names);
537 printable_comments = 0;
539 // Count the number of parts in the union and print it if it is not 1.
540 r = relation;
541 nb_parts = 0;
542 while (r != NULL) {
543 nb_parts++;
544 r = r->next;
547 if (nb_parts > 0) {
548 osl_relation_print_type(file, relation);
549 fprintf(file, "\n");
552 if (nb_parts > 1)
553 fprintf(file, "# Union with %d parts\n%d\n", nb_parts, nb_parts);
555 // Print each part of the union.
556 for (part = 1; part <= nb_parts; part++) {
557 if (nb_parts > 1)
558 fprintf(file, "# Union part No.%d\n", part);
559 if ((relation->nb_output_dims == OSL_UNDEFINED) &&
560 (relation->nb_input_dims == OSL_UNDEFINED) &&
561 (relation->nb_local_dims == OSL_UNDEFINED) &&
562 (relation->nb_parameters == OSL_UNDEFINED))
563 fprintf(file, "%d %d\n", relation->nb_rows, relation->nb_columns);
564 else
565 fprintf(file, "%d %d %d %d %d %d\n",
566 relation->nb_rows, relation->nb_columns,
567 relation->nb_output_dims, relation->nb_input_dims,
568 relation->nb_local_dims, relation->nb_parameters);
570 for (i = 0; i < relation->nb_rows; i++) {
571 for (j = 0; j < relation->nb_columns; j++) {
572 osl_int_print(file, relation->precision, relation->m[i], j);
573 fprintf(file, " ");
576 //osl_relation_print_comment(file, relation, i);
578 fprintf(file, "\n");
580 relation = relation->next;
585 /*****************************************************************************
586 * Reading function *
587 *****************************************************************************/
591 * osl_relation_read_type function:
592 * this function reads a textual relation type and returns its integer
593 * counterpart.
594 * \param[in] file The input stream.
595 * \return The relation type.
597 static
598 int osl_relation_read_type(FILE * file) {
599 int type;
600 osl_strings_p strings;
602 strings = osl_strings_read(file);
603 if (osl_strings_size(strings) > 1) {
604 OSL_warning("uninterpreted information (after the relation type)");
606 if (osl_strings_size(strings) == 0)
607 OSL_error("no relation type");
609 if (!strcmp(strings->string[0], OSL_STRING_UNDEFINED)) {
610 type = OSL_UNDEFINED;
611 goto return_type;
614 if (!strcmp(strings->string[0], OSL_STRING_CONTEXT)) {
615 type = OSL_TYPE_CONTEXT;
616 goto return_type;
619 if (!strcmp(strings->string[0], OSL_STRING_DOMAIN)) {
620 type = OSL_TYPE_DOMAIN;
621 goto return_type;
624 if (!strcmp(strings->string[0], OSL_STRING_SCATTERING)) {
625 type = OSL_TYPE_SCATTERING;
626 goto return_type;
629 if (!strcmp(strings->string[0], OSL_STRING_READ)) {
630 type = OSL_TYPE_READ;
631 goto return_type;
634 if (!strcmp(strings->string[0], OSL_STRING_WRITE)) {
635 type = OSL_TYPE_WRITE;
636 goto return_type;
639 if (!strcmp(strings->string[0], OSL_STRING_MAY_WRITE)) {
640 type = OSL_TYPE_MAY_WRITE;
641 goto return_type;
644 OSL_error("relation type not supported");
646 return_type:
647 osl_strings_free(strings);
648 return type;
653 * osl_relation_read function:
654 * this function reads a relation into a file (foo, posibly stdin) and
655 * returns a pointer this relation. The relation is set to the maximum
656 * available precision.
657 * \param[in] file The input stream.
658 * \return A pointer to the relation structure that has been read.
660 osl_relation_p osl_relation_read(FILE * foo) {
661 int i, j, k, n, read = 0;
662 int nb_rows, nb_columns;
663 int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters;
664 int nb_union_parts = 1;
665 int may_read_nb_union_parts = 1;
666 int read_properties = 1;
667 int first = 1;
668 int type;
669 int precision = osl_util_get_precision();
670 char * c, s[OSL_MAX_STRING], str[OSL_MAX_STRING];
671 osl_relation_p relation, relation_union = NULL, previous = NULL;
673 type = osl_relation_read_type(foo);
675 // Read each part of the union (the number of parts may be updated inside)
676 for (k = 0; k < nb_union_parts; k++) {
677 // Read the number of union parts or the properties of the union part
678 while (read_properties) {
679 read_properties = 0;
681 // Read relation properties.
682 c = osl_util_skip_blank_and_comments(foo, s);
683 read = sscanf(c, " %d %d %d %d %d %d", &nb_rows, &nb_columns,
684 &nb_output_dims, &nb_input_dims,
685 &nb_local_dims, &nb_parameters);
687 if (((read != 1) && (read != 6)) ||
688 ((read == 1) && (may_read_nb_union_parts != 1)))
689 OSL_error("not 1 or 6 integers on the first relation line");
691 if (read == 1) {
692 // Only one number means a union and is the number of parts.
693 nb_union_parts = nb_rows;
694 if (nb_union_parts < 1)
695 OSL_error("negative nb of union parts");
697 // Allow to read the properties of the first part of the union.
698 read_properties = 1;
701 may_read_nb_union_parts = 0;
704 // Allocate the union part and fill its properties.
705 relation = osl_relation_pmalloc(precision, nb_rows, nb_columns);
706 relation->type = type;
707 relation->nb_output_dims = nb_output_dims;
708 relation->nb_input_dims = nb_input_dims;
709 relation->nb_local_dims = nb_local_dims;
710 relation->nb_parameters = nb_parameters;
712 // Read the matrix of constraints.
713 for (i = 0; i < relation->nb_rows; i++) {
714 c = osl_util_skip_blank_and_comments(foo, s);
715 if (c == NULL)
716 OSL_error("not enough rows");
718 for (j = 0; j < relation->nb_columns; j++) {
719 if (c == NULL || *c == '#' || *c == '\n')
720 OSL_error("not enough columns");
721 if (sscanf(c, "%s%n", str, &n) == 0)
722 OSL_error("not enough rows");
724 osl_int_sread(str, precision, relation->m[i], j);
725 c += n;
729 // Build the linked list of union parts.
730 if (first == 1) {
731 relation_union = relation;
732 first = 0;
734 else {
735 previous->next = relation;
738 previous = relation;
739 read_properties = 1;
742 return relation_union;
746 /*+***************************************************************************
747 * Memory allocation/deallocation function *
748 *****************************************************************************/
752 * osl_relation_pmalloc function:
753 * (precision malloc) this function allocates the memory space for an
754 * osl_relation_t structure and sets its fields with default values.
755 * Then it returns a pointer to the allocated space.
756 * \param[in] precision The precision of the constraint matrix.
757 * \param[in] nb_rows The number of row of the relation to allocate.
758 * \param[in] nb_columns The number of columns of the relation to allocate.
759 * \return A pointer to an empty relation with fields set to default values
760 * and a ready-to-use constraint matrix.
762 osl_relation_p osl_relation_pmalloc(int precision,
763 int nb_rows, int nb_columns) {
764 osl_relation_p relation;
765 void ** p, * q;
766 int i, j;
768 OSL_malloc(relation, osl_relation_p, sizeof(osl_relation_t));
769 relation->type = OSL_UNDEFINED;
770 relation->nb_rows = nb_rows;
771 relation->nb_columns = nb_columns;
772 relation->nb_output_dims = OSL_UNDEFINED;
773 relation->nb_input_dims = OSL_UNDEFINED;
774 relation->nb_parameters = OSL_UNDEFINED;
775 relation->nb_local_dims = OSL_UNDEFINED;
776 relation->precision = precision;
778 if ((nb_rows == 0) || (nb_columns == 0) ||
779 (nb_rows == OSL_UNDEFINED) || (nb_columns == OSL_UNDEFINED)) {
780 relation->m = NULL;
782 else {
783 OSL_malloc(p, void **, nb_rows * sizeof(void *));
784 OSL_malloc(q, void *,
785 nb_rows * nb_columns * osl_int_sizeof(precision));
786 relation->m = p;
787 for (i = 0; i < nb_rows; i++) {
788 relation->m[i] = osl_int_address(precision, q, i * nb_columns);
789 for (j = 0; j < nb_columns; j++)
790 osl_int_init_set_si(precision, relation->m[i], j, 0);
794 relation->next = NULL;
796 return relation;
801 * osl_relation_malloc function:
802 * this function allocates the memory space for an osl_relation_t
803 * structure and sets its fields with default values. Then it returns a
804 * pointer to the allocated space. The precision of the constraint matrix
805 * elements corresponds to the precision environment variable or to the
806 * highest available precision if it is not defined.
807 * \param[in] nb_rows The number of row of the relation to allocate.
808 * \param[in] nb_columns The number of columns of the relation to allocate.
809 * \return A pointer to an empty relation with fields set to default values
810 * and a ready-to-use constraint matrix.
812 osl_relation_p osl_relation_malloc(int nb_rows, int nb_columns) {
813 int precision = osl_util_get_precision();
814 return osl_relation_pmalloc(precision, nb_rows, nb_columns);
819 * osl_relation_free_inside function:
820 * this function frees the allocated memory for the inside of a
821 * osl_relation_t structure, i.e. only m.
822 * \param[in] relation The pointer to the relation we want to free internals.
824 void osl_relation_free_inside(osl_relation_p relation) {
825 int i, nb_elements;
826 void * p;
828 if (relation == NULL)
829 return;
831 nb_elements = relation->nb_rows * relation->nb_columns;
833 if (nb_elements > 0)
834 p = relation->m[0];
836 for (i = 0; i < nb_elements; i++)
837 osl_int_clear(relation->precision, p, i);
839 if (relation->m != NULL) {
840 if (nb_elements > 0)
841 free(relation->m[0]);
842 free(relation->m);
848 * osl_relation_free function:
849 * this function frees the allocated memory for an osl_relation_t
850 * structure.
851 * \param[in] relation The pointer to the relation we want to free.
853 void osl_relation_free(osl_relation_p relation) {
854 osl_relation_p tmp;
856 if (relation == NULL)
857 return;
859 while (relation != NULL) {
860 tmp = relation->next;
861 osl_relation_free_inside(relation);
862 free(relation);
863 relation = tmp;
868 /*+***************************************************************************
869 * Processing functions *
870 *****************************************************************************/
874 * osl_relation_nclone function:
875 * this functions builds and returns a "hard copy" (not a pointer copy) of a
876 * osl_relation_t data structure such that the clone is restricted to the
877 * "n" first rows of the relation. This applies to all the parts in the case
878 * of a relation union.
879 * \param[in] relation The pointer to the relation we want to clone.
880 * \param[in] n The number of row of the relation we want to clone (the
881 * special value -1 means "all the rows").
882 * \return A pointer to the clone of the relation union restricted to the
883 * first n rows of constraint matrix for each part of the union.
885 osl_relation_p osl_relation_nclone(osl_relation_p relation, int n) {
886 int i, j;
887 int first = 1, all_rows = 0;
888 osl_relation_p clone = NULL, node, previous = NULL;
890 if (n == -1)
891 all_rows = 1;
893 while (relation != NULL) {
894 if (all_rows)
895 n = relation->nb_rows;
897 if (n > relation->nb_rows)
898 OSL_error("not enough rows to clone in the relation");
900 node = osl_relation_pmalloc(relation->precision, n, relation->nb_columns);
901 node->type = relation->type;
902 node->nb_output_dims = relation->nb_output_dims;
903 node->nb_input_dims = relation->nb_input_dims;
904 node->nb_local_dims = relation->nb_local_dims;
905 node->nb_parameters = relation->nb_parameters;
907 for (i = 0; i < n; i++)
908 for (j = 0; j < relation->nb_columns; j++)
909 osl_int_assign(relation->precision, node->m[i], j, relation->m[i], j);
911 if (first) {
912 first = 0;
913 clone = node;
914 previous = node;
916 else {
917 previous->next = node;
918 previous = previous->next;
921 relation = relation->next;
924 return clone;
929 * osl_relation_clone function:
930 * this function builds and returns a "hard copy" (not a pointer copy) of an
931 * osl_relation_t data structure (the full union of relation).
932 * \param[in] relation The pointer to the relation we want to clone.
933 * \return A pointer to the clone of the union of relations.
935 osl_relation_p osl_relation_clone(osl_relation_p relation) {
936 if (relation == NULL)
937 return NULL;
939 return osl_relation_nclone(relation, -1);
944 * osl_relation_replace_vector function:
945 * this function replaces the "row"^th row of a relation "relation" with the
946 * vector "vector". It directly updates the relation union part pointed
947 * by "relation" and this part only.
948 * \param[in,out] relation The relation we want to replace a row.
949 * \param[in] vector The vector that will replace a row of the relation.
950 * \param[in] row The row of the relation to be replaced.
952 void osl_relation_replace_vector(osl_relation_p relation,
953 osl_vector_p vector, int row) {
954 int i;
956 if ((relation == NULL) || (vector == NULL) ||
957 (relation->precision != vector->precision) ||
958 (relation->nb_columns != vector->size) ||
959 (row >= relation->nb_rows) || (row < 0))
960 OSL_error("vector cannot replace relation row");
962 for (i = 0; i < vector->size; i++)
963 osl_int_assign(relation->precision, relation->m[row], i, vector->v, i);
968 * osl_relation_add_vector function:
969 * this function adds (meaning, +) a vector to the "row"^th row of a
970 * relation "relation". It directly updates the relation union part pointed
971 * by "relation" and this part only.
972 * \param[in,out] relation The relation we want to add a vector to a row.
973 * \param[in] vector The vector that will replace a row of the relation.
974 * \param[in] row The row of the relation to be replaced.
976 void osl_relation_add_vector(osl_relation_p relation,
977 osl_vector_p vector, int row) {
978 int i;
980 if ((relation == NULL) || (vector == NULL) ||
981 (relation->precision != vector->precision) ||
982 (relation->nb_columns != vector->size) ||
983 (row >= relation->nb_rows) || (row < 0))
984 OSL_error("vector cannot be added to relation");
986 if (osl_int_get_si(relation->precision, relation->m[row], 0) == 0)
987 osl_int_assign(relation->precision, relation->m[row], 0, vector->v, 0);
989 for (i = 1; i < vector->size; i++)
990 osl_int_add(relation->precision,
991 relation->m[row], i, relation->m[row], i, vector->v, i);
996 * osl_relation_sub_vector function:
997 * this function subtracts the vector "vector" to the "row"^th row of
998 * a relation "relation. It directly updates the relation union part pointed
999 * by "relation" and this part only.
1000 * \param[in,out] relation The relation where to subtract a vector to a row.
1001 * \param[in] vector The vector to subtract to a relation row.
1002 * \param[in] row The row of the relation to subtract the vector.
1004 void osl_relation_sub_vector(osl_relation_p relation,
1005 osl_vector_p vector, int row) {
1006 int i;
1008 if ((relation == NULL) || (vector == NULL) ||
1009 (relation->precision != vector->precision) ||
1010 (relation->nb_columns != vector->size) ||
1011 (row >= relation->nb_rows) || (row < 0))
1012 OSL_error("vector cannot be subtracted to row");
1014 if (osl_int_get_si(relation->precision, relation->m[row], 0) == 0)
1015 osl_int_assign(relation->precision, relation->m[row], 0, vector->v, 0);
1017 for (i = 1; i < vector->size; i++)
1018 osl_int_sub(relation->precision,
1019 relation->m[row], i, relation->m[row], i, vector->v, i);
1024 * osl_relation_insert_vector function:
1025 * this function inserts a new row corresponding to the vector "vector" to
1026 * the relation "relation" by inserting it at the "row"^th row. It directly
1027 * updates the relation union part pointed by "relation" and this part only.
1028 * If "vector" (or "relation") is NULL, the relation is left unmodified.
1029 * \param[in,out] relation The relation we want to extend.
1030 * \param[in] vector The vector that will be added relation.
1031 * \param[in] row The row where to insert the vector.
1033 void osl_relation_insert_vector(osl_relation_p relation,
1034 osl_vector_p vector, int row) {
1035 osl_relation_p temp;
1037 temp = osl_relation_from_vector(vector);
1038 osl_relation_insert_constraints(relation, temp, row);
1039 osl_relation_free(temp);
1044 * osl_relation_from_vector function:
1045 * this function converts a vector "vector" to a relation with a single row
1046 * and returns a pointer to that relation.
1047 * \param[in] vector The vector to convert to a relation.
1048 * \return A pointer to a relation resulting from the vector conversion.
1050 osl_relation_p osl_relation_from_vector(osl_vector_p vector) {
1051 osl_relation_p relation;
1053 if (vector == NULL)
1054 return NULL;
1056 relation = osl_relation_pmalloc(vector->precision, 1, vector->size);
1057 osl_relation_replace_vector(relation, vector, 0);
1058 return relation;
1063 * osl_relation_replace_constraints function:
1064 * this function replaces some rows of a relation "r1" with the rows of
1065 * the relation "r2". It begins at the "row"^th row of "r1". It directly
1066 * updates the relation union part pointed by "r1" and this part only.
1067 * \param[in,out] r1 The relation we want to change some rows.
1068 * \param[in] r2 The relation containing the new rows.
1069 * \param[in] row The first row of the relation r1 to be replaced.
1071 void osl_relation_replace_constraints(osl_relation_p r1,
1072 osl_relation_p r2, int row) {
1073 int i, j;
1075 if ((r1 == NULL) || (r2 == NULL) ||
1076 (r1->precision != r2->precision) ||
1077 (r1->nb_columns != r1->nb_columns) ||
1078 ((row + r2->nb_rows) > r1->nb_rows) || (row < 0))
1079 OSL_error("relation rows could not be replaced");
1081 for (i = 0; i < r2->nb_rows; i++)
1082 for (j = 0; j < r2->nb_columns; j++)
1083 osl_int_assign(r1->precision, r1->m[i+row], j, r2->m[i], j);
1088 * osl_relation_insert_constraints function:
1089 * this function adds new rows corresponding to the relation "r1" to
1090 * the relation "r2" by inserting it at the "row"^th row. It directly
1091 * updates the relation union part pointed by "r1" and this part only.
1092 * If "r2" (or "r1") is NULL, the relation is left unmodified.
1093 * \param[in,out] r1 The relation we want to extend.
1094 * \param[in] r2 The relation to be inserted.
1095 * \param[in] row The row where to insert the relation
1097 void osl_relation_insert_constraints(osl_relation_p r1,
1098 osl_relation_p r2, int row) {
1099 int i, j;
1100 osl_relation_p temp;
1102 if ((r1 == NULL) || (r2 == NULL))
1103 return;
1105 if ((r1->nb_columns != r2->nb_columns) ||
1106 (r1->precision != r2->precision) ||
1107 (row > r1->nb_rows) || (row < 0))
1108 OSL_error("constraints cannot be inserted");
1110 // We use a temporary relation just to reuse existing functions. Cleaner.
1111 temp = osl_relation_pmalloc(r1->precision,
1112 r1->nb_rows + r2->nb_rows, r1->nb_columns);
1114 for (i = 0; i < row; i++)
1115 for (j = 0; j < r1->nb_columns; j++)
1116 osl_int_assign(r1->precision, temp->m[i], j, r1->m[i], j);
1118 osl_relation_replace_constraints(temp, r2, row);
1120 for (i = row + r2->nb_rows; i < r2->nb_rows + r1->nb_rows; i++)
1121 for (j = 0; j < r1->nb_columns; j++)
1122 osl_int_assign(r1->precision, temp->m[i], j, r1->m[i-r2->nb_rows], j);
1124 osl_relation_free_inside(r1);
1126 // Replace the inside of relation.
1127 r1->nb_rows = temp->nb_rows;
1128 r1->m = temp->m;
1130 // Free the temp "shell".
1131 free(temp);
1136 * osl_relation_concat_constraints function:
1137 * this function builds a new relation from two relations sent as
1138 * parameters. The new set of constraints is built as the concatenation
1139 * of the rows of the first elements of the two relation unions r1 and r2.
1140 * This means, there is no next field in the result.
1141 * \param[in] r1 The first relation.
1142 * \param[in] r2 The second relation.
1143 * \return A pointer to the relation resulting from the concatenation of
1144 * the first elements of r1 and r2.
1146 osl_relation_p osl_relation_concat_constraints(
1147 osl_relation_p r1,
1148 osl_relation_p r2) {
1149 osl_relation_p new;
1151 if (r1 == NULL)
1152 return osl_relation_clone(r2);
1154 if (r2 == NULL)
1155 return osl_relation_clone(r1);
1157 if (r1->nb_columns != r2->nb_columns)
1158 OSL_error("incompatible sizes for concatenation");
1160 if (r1->next || r2->next)
1161 OSL_warning("relation concatenation is done on the first elements "
1162 "of union only");
1164 new = osl_relation_pmalloc(r1->precision,
1165 r1->nb_rows + r2->nb_rows, r1->nb_columns);
1166 osl_relation_replace_constraints(new, r1, 0);
1167 osl_relation_replace_constraints(new, r2, r1->nb_rows);
1169 return new;
1174 * osl_relation_equal function:
1175 * this function returns true if the two relations provided as parameters
1176 * are the same, false otherwise.
1177 * \param[in] r1 The first relation.
1178 * \param[in] r2 The second relation.
1179 * \return 1 if r1 and r2 are the same (content-wise), 0 otherwise.
1181 int osl_relation_equal(osl_relation_p r1, osl_relation_p r2) {
1182 int i, j;
1184 while ((r1 != NULL) && (r2 != NULL)) {
1185 if (r1 == r2)
1186 return 1;
1188 if ((r1->type != r2->type) ||
1189 (r1->precision != r2->precision) ||
1190 (r1->nb_rows != r2->nb_rows) ||
1191 (r1->nb_columns != r2->nb_columns) ||
1192 (r1->nb_output_dims != r2->nb_output_dims) ||
1193 (r1->nb_input_dims != r2->nb_input_dims) ||
1194 (r1->nb_local_dims != r2->nb_local_dims) ||
1195 (r1->nb_parameters != r2->nb_parameters))
1196 return 0;
1198 for (i = 0; i < r1->nb_rows; ++i)
1199 for (j = 0; j < r1->nb_columns; ++j)
1200 if (osl_int_ne(r1->precision, r1->m[i], j, r2->m[i], j))
1201 return 0;
1203 r1 = r1->next;
1204 r2 = r2->next;
1207 if (((r1 == NULL) && (r2 != NULL)) || ((r1 != NULL) && (r2 == NULL)))
1208 return 0;
1210 return 1;
1215 * osl_relation_check_attribute internal function:
1216 * This function checks whether an "actual" value is the same as an
1217 * "expected" value or not. If the expected value is set to
1218 * OSL_UNDEFINED, this function sets it to the "actual" value
1219 * and do not report a difference has been detected.
1220 * It returns 0 if a difference has been detected, 1 otherwise.
1221 * \param[in,out] expected Pointer to the expected value (the value is
1222 * modified if it was set to OSL_UNDEFINED).
1223 * \param[in] actual Value we want to check.
1224 * \return 0 if the values are not the same while the expected value was
1225 * not OSL_UNDEFINED, 1 otherwise.
1227 static
1228 int osl_relation_check_attribute(int * expected, int actual) {
1229 if (*expected != OSL_UNDEFINED) {
1230 if ((actual != OSL_UNDEFINED) &&
1231 (actual != *expected)) {
1232 OSL_warning("unexpected atribute");
1233 return 0;
1236 else {
1237 *expected = actual;
1240 return 1;
1245 * osl_relation_check_nb_columns internal function:
1246 * This function checks that the number of columns of a relation
1247 * corresponds to some expected properties (setting an expected property to
1248 * OSL_UNDEFINED makes this function unable to detect a problem).
1249 * It returns 0 if the number of columns seems incorrect or 1 if no problem
1250 * has been detected.
1251 * \param[in] relation The relation we want to check the number of columns.
1252 * \param[in] expected_nb_output_dims Expected number of output dimensions.
1253 * \param[in] expected_nb_input_dims Expected number of input dimensions.
1254 * \param[in] expected_nb_parameters Expected number of parameters.
1255 * \return 0 if the number of columns seems incorrect, 1 otherwise.
1257 static
1258 int osl_relation_check_nb_columns(osl_relation_p relation,
1259 int expected_nb_output_dims,
1260 int expected_nb_input_dims,
1261 int expected_nb_parameters) {
1262 int expected_nb_local_dims, expected_nb_columns;
1264 if ((expected_nb_output_dims != OSL_UNDEFINED) &&
1265 (expected_nb_input_dims != OSL_UNDEFINED) &&
1266 (expected_nb_parameters != OSL_UNDEFINED)) {
1268 if (relation->nb_local_dims == OSL_UNDEFINED)
1269 expected_nb_local_dims = 0;
1270 else
1271 expected_nb_local_dims = relation->nb_local_dims;
1273 expected_nb_columns = expected_nb_output_dims +
1274 expected_nb_input_dims +
1275 expected_nb_local_dims +
1276 expected_nb_parameters +
1279 if (expected_nb_columns != relation->nb_columns) {
1280 OSL_warning("unexpected number of columns");
1281 return 0;
1285 return 1;
1290 * osl_relation_integrity_check function:
1291 * this function checks that a relation is "well formed" according to some
1292 * expected properties (setting an expected value to OSL_UNDEFINED means
1293 * that we do not expect a specific value) and what the relation is supposed
1294 * to represent. It returns 0 if the check failed or 1 if no problem has been
1295 * detected.
1296 * \param[in] relation The relation we want to check.
1297 * \param[in] type Semantics about this relation (domain, access...).
1298 * \param[in] expected_nb_output_dims Expected number of output dimensions.
1299 * \param[in] expected_nb_input_dims Expected number of input dimensions.
1300 * \param[in] expected_nb_parameters Expected number of parameters.
1301 * \return 0 if the integrity check fails, 1 otherwise.
1303 int osl_relation_integrity_check(osl_relation_p relation,
1304 int expected_type,
1305 int expected_nb_output_dims,
1306 int expected_nb_input_dims,
1307 int expected_nb_parameters) {
1308 int i;
1310 // Check the NULL case.
1311 if (relation == NULL) {
1312 if ((expected_nb_output_dims != OSL_UNDEFINED) ||
1313 (expected_nb_input_dims != OSL_UNDEFINED) ||
1314 (expected_nb_parameters != OSL_UNDEFINED)) {
1315 OSL_warning("NULL relation with some expected attibutes");
1316 //return 0;
1319 return 1;
1322 // Check the type.
1323 if (((expected_type != OSL_TYPE_ACCESS) &&
1324 (expected_type != relation->type)) ||
1325 ((expected_type == OSL_TYPE_ACCESS) &&
1326 (!osl_relation_is_access(relation)))) {
1327 OSL_warning("wrong type");
1328 osl_relation_dump(stderr, relation);
1329 return 0;
1332 // Check that relations have no undefined atributes.
1333 if ((relation->nb_output_dims == OSL_UNDEFINED) ||
1334 (relation->nb_input_dims == OSL_UNDEFINED) ||
1335 (relation->nb_local_dims == OSL_UNDEFINED) ||
1336 (relation->nb_parameters == OSL_UNDEFINED)) {
1337 OSL_warning("all attributes should be defined");
1338 osl_relation_dump(stderr, relation);
1339 return 0;
1342 // Check that a context has actually 0 output dimensions.
1343 if ((relation->type == OSL_TYPE_CONTEXT) &&
1344 (relation->nb_output_dims != 0)) {
1345 OSL_warning("context without 0 as number of output dimensions");
1346 osl_relation_dump(stderr, relation);
1347 return 0;
1350 // Check that a domain or a context has actually 0 input dimensions.
1351 if (((relation->type == OSL_TYPE_DOMAIN) ||
1352 (relation->type == OSL_TYPE_CONTEXT)) &&
1353 (relation->nb_input_dims != 0)) {
1354 OSL_warning("domain or context without 0 input dimensions");
1355 osl_relation_dump(stderr, relation);
1356 return 0;
1359 // Check properties according to expected values (and if expected values
1360 // are undefined, define them with the first relation part properties).
1361 if (!osl_relation_check_attribute(&expected_nb_output_dims,
1362 relation->nb_output_dims) ||
1363 !osl_relation_check_attribute(&expected_nb_input_dims,
1364 relation->nb_input_dims) ||
1365 !osl_relation_check_attribute(&expected_nb_parameters,
1366 relation->nb_parameters)) {
1367 osl_relation_dump(stderr, relation);
1368 return 0;
1371 while (relation != NULL) {
1373 // Attributes (except the number of local dimensions) should be the same
1374 // in all parts of the union.
1375 if ((expected_nb_output_dims != relation->nb_output_dims) ||
1376 (expected_nb_input_dims != relation->nb_input_dims) ||
1377 (expected_nb_parameters != relation->nb_parameters)) {
1378 OSL_warning("inconsistent attributes");
1379 osl_relation_dump(stderr, relation);
1380 return 0;
1383 // Check whether the number of columns is OK or not.
1384 if (!osl_relation_check_nb_columns(relation,
1385 expected_nb_output_dims,
1386 expected_nb_input_dims,
1387 expected_nb_parameters)) {
1388 osl_relation_dump(stderr, relation);
1389 return 0;
1392 // Check the first column. The first column of a relation part should be
1393 // made of 0 or 1 only.
1394 if ((relation->nb_rows > 0) && (relation->nb_columns > 0)) {
1395 for (i = 0; i < relation->nb_rows; i++) {
1396 if (!osl_int_zero(relation->precision, relation->m[i], 0) &&
1397 !osl_int_one(relation->precision, relation->m[i], 0)) {
1398 OSL_warning("first column of a relation is not "
1399 "strictly made of 0 or 1");
1400 osl_relation_dump(stderr, relation);
1401 return 0;
1406 // Array accesses must provide the array identifier.
1407 if ((osl_relation_is_access(relation)) &&
1408 (osl_relation_get_array_id(relation) == OSL_UNDEFINED)) {
1409 osl_relation_dump(stderr, relation);
1410 return 0;
1413 relation = relation->next;
1416 return 1;
1421 * osl_relation_union function:
1422 * this function builds a new relation from two relations provided
1423 * as parameters. The new relation is built as an union of the
1424 * two relations: the list of constraint sets are linked together.
1425 * \param[in] r1 The first relation.
1426 * \param[in] r2 The second relation.
1427 * \return A new relation corresponding to the union of r1 and r2.
1429 osl_relation_p osl_relation_union(osl_relation_p r1,
1430 osl_relation_p r2) {
1431 osl_relation_p copy1, copy2, tmp;
1433 if ((r1 == NULL) && (r2 == NULL))
1434 return NULL;
1436 copy1 = osl_relation_clone(r1);
1437 copy2 = osl_relation_clone(r2);
1439 if ((r1 != NULL) && (r2 == NULL))
1440 return copy1;
1442 if ((r1 == NULL) && (r2 != NULL))
1443 return copy2;
1445 tmp = copy1;
1446 while (tmp->next != NULL)
1447 tmp = tmp->next;
1449 tmp->next = copy2;
1450 return copy1;
1454 /**
1455 * osl_relation_set_type function:
1456 * this function sets the type of each relation union part in the relation
1457 * to the one provided as parameter.
1458 * \param relation The relation to set the type.
1459 * \param type The type.
1461 void osl_relation_set_type(osl_relation_p relation, int type) {
1463 while (relation != NULL) {
1464 relation->type = type;
1465 relation = relation->next;
1471 * osl_relation_get_array_id function:
1472 * this function returns the array identifier in a relation with access type
1473 * It returns OSL_UNDEFINED if it is not able to find it (in particular
1474 * if there are irregularities in the relation).
1475 * \param[in] relation The relation where to find an array identifier.
1476 * \return The array identifier in the relation or OSL_UNDEFINED.
1478 int osl_relation_get_array_id(osl_relation_p relation) {
1479 int i;
1480 int first = 1;
1481 int array_id = OSL_UNDEFINED;
1482 int reference_array_id = OSL_UNDEFINED;
1483 int nb_array_id;
1484 int row_id = 0;
1485 int precision;
1487 if (relation == NULL)
1488 return OSL_UNDEFINED;
1490 if (!osl_relation_is_access(relation)) {
1491 OSL_warning("asked for an array id of non-array relation");
1492 return OSL_UNDEFINED;
1495 while (relation != NULL) {
1496 precision = relation->precision;
1498 // There should be room to store the array identifier.
1499 if ((relation->nb_rows < 1) ||
1500 (relation->nb_columns < 3)) {
1501 OSL_warning("no array identifier in an access function");
1502 return OSL_UNDEFINED;
1505 // Array identifiers are m[i][#columns -1] / m[i][1], with i the only row
1506 // where m[i][1] is not 0.
1507 // - check there is exactly one row such that m[i][1] is not 0,
1508 // - check the whole ith row if full of 0 except m[i][1] and the id,
1509 // - check that (m[i][#columns -1] % m[i][1]) == 0,
1510 // - check that (-m[i][#columns -1] / m[i][1]) > 0.
1511 nb_array_id = 0;
1512 for (i = 0; i < relation->nb_rows; i++) {
1513 if (!osl_int_zero(precision, relation->m[i], 1)) {
1514 nb_array_id ++;
1515 row_id = i;
1518 if (nb_array_id == 0) {
1519 OSL_warning("no array identifier in an access function");
1520 return OSL_UNDEFINED;
1522 if (nb_array_id > 1) {
1523 OSL_warning("several array identifiers in one access function");
1524 return OSL_UNDEFINED;
1526 for (i = 0; i < relation->nb_columns - 1; i++) {
1527 if ((i != 1) && !osl_int_zero(precision, relation->m[row_id], i)) {
1528 OSL_warning("non integer array identifier");
1529 return OSL_UNDEFINED;
1532 if (!osl_int_divisible(precision,
1533 relation->m[row_id], relation->nb_columns - 1,
1534 relation->m[row_id], 1)) {
1535 OSL_warning("rational array identifier");
1536 return OSL_UNDEFINED;
1538 array_id = -osl_int_get_si(precision,
1539 relation->m[row_id],
1540 relation->nb_columns - 1);
1541 array_id /= osl_int_get_si(precision, relation->m[row_id], 1);
1542 if (array_id <= 0) {
1543 OSL_warning("negative or 0 identifier in access function");
1544 return OSL_UNDEFINED;
1547 // Unions of accesses are allowed, but they should refer at the same array.
1548 if (first) {
1549 reference_array_id = array_id;
1550 first = 0;
1552 else {
1553 if (reference_array_id != array_id) {
1554 OSL_warning("inconsistency of array identifiers in an "
1555 "union of access relations");
1556 return OSL_UNDEFINED;
1560 relation = relation->next;
1563 return array_id;
1568 * osl_relation_is_access function:
1569 * this function returns 1 if the relation corresponds to an access relation,
1570 * whatever its precise type (read, write etc.), 0 otherwise.
1571 * \param relation The relation to check wheter it is an access relation or not.
1572 * \return 1 if the relation is an access relation, 0 otherwise.
1574 int osl_relation_is_access(osl_relation_p relation) {
1576 if (relation == NULL)
1577 return 0;
1579 if ((relation->type == OSL_TYPE_ACCESS) ||
1580 (relation->type == OSL_TYPE_READ) ||
1581 (relation->type == OSL_TYPE_WRITE) ||
1582 (relation->type == OSL_TYPE_MAY_WRITE))
1583 return 1;
1585 return 0;