OpenScop 0.8.1
|
00001 00002 /*+-----------------------------------------------------------------** 00003 ** OpenScop Library ** 00004 **-----------------------------------------------------------------** 00005 ** relation.c ** 00006 **-----------------------------------------------------------------** 00007 ** First version: 30/04/2008 ** 00008 **-----------------------------------------------------------------** 00009 00010 00011 ***************************************************************************** 00012 * OpenScop: Structures and formats for polyhedral tools to talk together * 00013 ***************************************************************************** 00014 * ,___,,_,__,,__,,__,,__,,_,__,,_,__,,__,,___,_,__,,_,__, * 00015 * / / / // // // // / / / // // / / // / /|,_, * 00016 * / / / // // // // / / / // // / / // / / / /\ * 00017 * |~~~|~|~~~|~~~|~~~|~~~|~|~~~|~|~~~|~~~|~~~|~|~~~|~|~~~|/_/ \ * 00018 * | G |C| P | = | L | P |=| = |C| = | = | = |=| = |=| C |\ \ /\ * 00019 * | R |l| o | = | e | l |=| = |a| = | = | = |=| = |=| L | \# \ /\ * 00020 * | A |a| l | = | t | u |=| = |n| = | = | = |=| = |=| o | |\# \ \ * 00021 * | P |n| l | = | s | t |=| = |d| = | = | = | | |=| o | | \# \ \ * 00022 * | H | | y | | e | o | | = |l| | | = | | | | G | | \ \ \ * 00023 * | I | | | | e | | | | | | | | | | | | | \ \ \ * 00024 * | T | | | | | | | | | | | | | | | | | \ \ \ * 00025 * | E | | | | | | | | | | | | | | | | | \ \ \ * 00026 * | * |*| * | * | * | * |*| * |*| * | * | * |*| * |*| * | / \* \ \ * 00027 * | O |p| e | n | S | c |o| p |-| L | i | b |r| a |r| y |/ \ \ / * 00028 * '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---' '--' * 00029 * * 00030 * Copyright (C) 2008 University Paris-Sud 11 and INRIA * 00031 * * 00032 * (3-clause BSD license) * 00033 * Redistribution and use in source and binary forms, with or without * 00034 * modification, are permitted provided that the following conditions * 00035 * are met: * 00036 * * 00037 * 1. Redistributions of source code must retain the above copyright notice, * 00038 * this list of conditions and the following disclaimer. * 00039 * 2. Redistributions in binary form must reproduce the above copyright * 00040 * notice, this list of conditions and the following disclaimer in the * 00041 * documentation and/or other materials provided with the distribution. * 00042 * 3. The name of the author may not be used to endorse or promote products * 00043 * derived from this software without specific prior written permission. * 00044 * * 00045 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * 00046 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * 00047 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * 00048 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * 00049 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * 00050 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * 00051 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * 00052 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * 00053 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * 00054 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 00055 * * 00056 * OpenScop Library, a library to manipulate OpenScop formats and data * 00057 * structures. Written by: * 00058 * Cedric Bastoul <Cedric.Bastoul@u-psud.fr> and * 00059 * Louis-Noel Pouchet <Louis-Noel.pouchet@inria.fr> * 00060 * * 00061 *****************************************************************************/ 00062 00063 00064 #include <stdlib.h> 00065 #include <stdio.h> 00066 #include <string.h> 00067 #include <ctype.h> 00068 00069 #include <osl/macros.h> 00070 #include <osl/int.h> 00071 #include <osl/util.h> 00072 #include <osl/vector.h> 00073 #include <osl/strings.h> 00074 #include <osl/names.h> 00075 #include <osl/relation.h> 00076 00077 00078 /*+*************************************************************************** 00079 * Structure display function * 00080 *****************************************************************************/ 00081 00082 00090 static 00091 char * osl_relation_sprint_type(osl_relation_p relation) { 00092 char * string = NULL; 00093 00094 OSL_malloc(string, char *, OSL_MAX_STRING * sizeof(char)); 00095 string[0] = '\0'; 00096 00097 if (relation != NULL) { 00098 switch (relation->type) { 00099 case OSL_UNDEFINED: { 00100 snprintf(string, OSL_MAX_STRING, OSL_STRING_UNDEFINED); 00101 break; 00102 } 00103 case OSL_TYPE_CONTEXT: { 00104 snprintf(string, OSL_MAX_STRING, OSL_STRING_CONTEXT); 00105 break; 00106 } 00107 case OSL_TYPE_DOMAIN: { 00108 snprintf(string, OSL_MAX_STRING, OSL_STRING_DOMAIN); 00109 break; 00110 } 00111 case OSL_TYPE_SCATTERING: { 00112 snprintf(string, OSL_MAX_STRING, OSL_STRING_SCATTERING); 00113 break; 00114 } 00115 case OSL_TYPE_READ: { 00116 snprintf(string, OSL_MAX_STRING, OSL_STRING_READ); 00117 break; 00118 } 00119 case OSL_TYPE_WRITE: { 00120 snprintf(string, OSL_MAX_STRING, OSL_STRING_WRITE); 00121 break; 00122 } 00123 case OSL_TYPE_MAY_WRITE: { 00124 snprintf(string, OSL_MAX_STRING, OSL_STRING_MAY_WRITE); 00125 break; 00126 } 00127 default: { 00128 OSL_warning("unknown relation type, " 00129 "replaced with "OSL_STRING_UNDEFINED); 00130 snprintf(string, OSL_MAX_STRING, OSL_STRING_UNDEFINED); 00131 } 00132 } 00133 } 00134 00135 return string; 00136 } 00137 00138 00146 static 00147 void osl_relation_print_type(FILE * file, osl_relation_p relation) { 00148 char * string = osl_relation_sprint_type(relation); 00149 fprintf(file, "%s", string); 00150 free(string); 00151 } 00152 00153 00164 void osl_relation_idump(FILE * file, osl_relation_p relation, int level) { 00165 int i, j, first = 1; 00166 00167 // Go to the right level. 00168 for (j = 0; j < level; j++) 00169 fprintf(file, "|\t"); 00170 00171 if (relation != NULL) { 00172 fprintf(file, "+-- osl_relation_t ("); 00173 osl_relation_print_type(file, relation); 00174 fprintf(file, ", "); 00175 osl_int_dump_precision(file, relation->precision); 00176 fprintf(file, ")\n"); 00177 } 00178 else { 00179 fprintf(file, "+-- NULL relation\n"); 00180 } 00181 00182 while (relation != NULL) { 00183 if (! first) { 00184 // Go to the right level. 00185 for (j = 0; j < level; j++) 00186 fprintf(file, "|\t"); 00187 fprintf(file, "| osl_relation_t ("); 00188 osl_relation_print_type(file, relation); 00189 fprintf(file, ", "); 00190 osl_int_dump_precision(file, relation->precision); 00191 fprintf(file, ")\n"); 00192 } 00193 else 00194 first = 0; 00195 00196 // A blank line 00197 for(j = 0; j <= level; j++) 00198 fprintf(file, "|\t"); 00199 fprintf(file, "%d %d %d %d %d %d\n", 00200 relation->nb_rows, relation->nb_columns, 00201 relation->nb_output_dims, relation->nb_input_dims, 00202 relation->nb_local_dims, relation->nb_parameters); 00203 00204 // Display the relation. 00205 for (i = 0; i < relation->nb_rows; i++) { 00206 for (j = 0; j <= level; j++) 00207 fprintf(file, "|\t"); 00208 00209 fprintf(file, "[ "); 00210 00211 for (j = 0; j < relation->nb_columns; j++) { 00212 osl_int_print(file, relation->precision, relation->m[i], j); 00213 fprintf(file, " "); 00214 } 00215 00216 fprintf(file, "]\n"); 00217 } 00218 00219 relation = relation->next; 00220 00221 // Next line. 00222 if (relation != NULL) { 00223 for (j = 0; j <= level; j++) 00224 fprintf(file, "|\t"); 00225 fprintf(file, "|\n"); 00226 for (j = 0; j <= level; j++) 00227 fprintf(file, "|\t"); 00228 fprintf(file, "V\n"); 00229 } 00230 } 00231 00232 // The last line. 00233 for (j = 0; j <= level; j++) 00234 fprintf(file, "|\t"); 00235 fprintf(file, "\n"); 00236 } 00237 00238 00246 void osl_relation_dump(FILE * file, osl_relation_p relation) { 00247 osl_relation_idump(file, relation, 0); 00248 } 00249 00250 00265 static 00266 char * osl_relation_expression_element(void * val, 00267 int precision, int * first, 00268 int cst, char * name) { 00269 char * temp, * body, * sval; 00270 00271 OSL_malloc(temp, char *, OSL_MAX_STRING * sizeof(char)); 00272 OSL_malloc(body, char *, OSL_MAX_STRING * sizeof(char)); 00273 OSL_malloc(sval, char *, OSL_MAX_STRING * sizeof(char)); 00274 00275 body[0] = '\0'; 00276 sval[0] = '\0'; 00277 00278 // statements for the 'normal' processing. 00279 if (!osl_int_zero(precision, val, 0) && (!cst)) { 00280 if ((*first) || osl_int_neg(precision, val, 0)) { 00281 if (osl_int_one(precision, val, 0)) { // case 1 00282 sprintf(sval, "%s", name); 00283 } 00284 else { 00285 if (osl_int_mone(precision, val, 0)) { // case -1 00286 sprintf(sval, "-%s", name); 00287 } 00288 else { // default case 00289 osl_int_sprint(sval, precision, val, 0); 00290 sprintf(temp, "*%s", name); 00291 strcat(sval, temp); 00292 } 00293 } 00294 *first = 0; 00295 } 00296 else { 00297 if (osl_int_one(precision, val, 0)) { 00298 sprintf(sval, "+%s", name); 00299 } 00300 else { 00301 sprintf(sval, "+"); 00302 osl_int_sprint_txt(temp, precision, val, 0); 00303 strcat(sval, temp); 00304 sprintf(temp, "*%s", name); 00305 strcat(sval, temp); 00306 } 00307 } 00308 } 00309 else { 00310 if (cst) { 00311 if ((osl_int_zero(precision, val, 0) && (*first)) || 00312 (osl_int_neg(precision, val, 0))) 00313 osl_int_sprint_txt(sval, precision, val, 0); 00314 if (osl_int_pos(precision, val, 0)) { 00315 if (!(*first)) { 00316 sprintf(sval, "+"); 00317 osl_int_sprint_txt(temp, precision, val, 0); 00318 strcat(sval, temp); 00319 } 00320 else { 00321 osl_int_sprint_txt(sval, precision, val, 0); 00322 } 00323 } 00324 } 00325 } 00326 free(temp); 00327 free(body); 00328 00329 return(sval); 00330 } 00331 00332 00342 static 00343 char ** osl_relation_strings(osl_relation_p relation, osl_names_p names) { 00344 char ** strings; 00345 char temp[OSL_MAX_STRING]; 00346 int i, offset, array_id; 00347 00348 if ((relation == NULL) || (names == NULL)) { 00349 OSL_debug("no names or relation to build the name array"); 00350 return NULL; 00351 } 00352 00353 OSL_malloc(strings, char **, (relation->nb_columns + 1)*sizeof(char *)); 00354 strings[relation->nb_columns] = NULL; 00355 00356 // 1. Equality/inequality marker. 00357 OSL_strdup(strings[0], "e/i"); 00358 offset = 1; 00359 00360 // 2. Output dimensions. 00361 if (osl_relation_is_access(relation)) { 00362 // The first output dimension is the array name. 00363 array_id = osl_relation_get_array_id(relation); 00364 OSL_strdup(strings[offset], names->arrays->string[array_id - 1]); 00365 // The other ones are the array dimensions [1]...[n] 00366 for (i = offset + 1; i < relation->nb_output_dims + offset; i++) { 00367 sprintf(temp, "[%d]", i - 1); 00368 OSL_strdup(strings[i], temp); 00369 } 00370 } 00371 else 00372 if (relation->type == OSL_TYPE_SCATTERING) { 00373 for (i = offset; i < relation->nb_output_dims + offset; i++) { 00374 OSL_strdup(strings[i], names->scatt_dims->string[i - offset]); 00375 } 00376 } 00377 else { 00378 for (i = offset; i < relation->nb_output_dims + offset; i++) { 00379 OSL_strdup(strings[i], names->iterators->string[i - offset]); 00380 } 00381 } 00382 offset += relation->nb_output_dims; 00383 00384 // 3. Input dimensions. 00385 for (i = offset; i < relation->nb_input_dims + offset; i++) 00386 OSL_strdup(strings[i], names->iterators->string[i - offset]); 00387 offset += relation->nb_input_dims; 00388 00389 // 4. Local dimensions. 00390 for (i = offset; i < relation->nb_local_dims + offset; i++) 00391 OSL_strdup(strings[i], names->local_dims->string[i - offset]); 00392 offset += relation->nb_local_dims; 00393 00394 // 5. Parameters. 00395 for (i = offset; i < relation->nb_parameters + offset; i++) 00396 OSL_strdup(strings[i], names->parameters->string[i - offset]); 00397 offset += relation->nb_parameters; 00398 00399 // 6. Scalar. 00400 OSL_strdup(strings[offset], "1"); 00401 00402 return strings; 00403 } 00404 00405 00419 static 00420 char * osl_relation_subexpression(osl_relation_p relation, 00421 int row, int start, int stop, int oppose, 00422 char ** strings) { 00423 int i, first = 1, constant; 00424 char * sval; 00425 char * sline; 00426 00427 OSL_malloc(sline, char *, OSL_MAX_STRING * sizeof(char)); 00428 sline[0] = '\0'; 00429 00430 // Create the expression. The constant is a special case. 00431 for (i = start; i <= stop; i++) { 00432 if (oppose) { 00433 osl_int_oppose(relation->precision, 00434 relation->m[row], i, relation->m[row], i); 00435 } 00436 00437 if (i == relation->nb_columns - 1) 00438 constant = 1; 00439 else 00440 constant = 0; 00441 00442 sval = osl_relation_expression_element( 00443 osl_int_address(relation->precision, relation->m[row], i), 00444 relation->precision, &first, constant, strings[i]); 00445 00446 if (oppose) { 00447 osl_int_oppose(relation->precision, 00448 relation->m[row], i, relation->m[row], i); 00449 } 00450 strcat(sline, sval); 00451 free(sval); 00452 } 00453 00454 return sline; 00455 } 00456 00457 00467 char * osl_relation_expression(osl_relation_p relation, 00468 int row, char ** strings) { 00469 00470 return osl_relation_subexpression(relation, row, 00471 1, relation->nb_columns - 1, 0, 00472 strings); 00473 } 00474 00475 00487 static 00488 int osl_relation_is_simple_output(osl_relation_p relation, int row) { 00489 int i; 00490 int first = 1; 00491 int sign = 0; 00492 00493 if ((relation == NULL) || 00494 (relation->m == NULL) || 00495 (relation->nb_output_dims == 0)) 00496 return 0; 00497 00498 if ((row < 0) || (row > relation->nb_rows)) 00499 OSL_error("the specified row does not exist in the relation"); 00500 00501 // The constraint must be an equality. 00502 if (!osl_int_zero(relation->precision, relation->m[row], 0)) 00503 return 0; 00504 00505 // Check the output part has one and only one non-zero +1 or -1 coefficient. 00506 first = 1; 00507 for (i = 1; i <= relation->nb_output_dims; i++) { 00508 if (!osl_int_zero(relation->precision, relation->m[row], i)) { 00509 if (first) 00510 first = 0; 00511 else 00512 return 0; 00513 00514 if (osl_int_one(relation->precision, relation->m[row], i)) 00515 sign = 1; 00516 else if (osl_int_mone(relation->precision, relation->m[row], i)) 00517 sign = -1; 00518 else 00519 return 0; 00520 } 00521 } 00522 00523 return sign; 00524 } 00525 00526 00539 static 00540 char * osl_relation_sprint_comment(osl_relation_p relation, 00541 int row, char ** strings) { 00542 int sign; 00543 int high_water_mark = OSL_MAX_STRING; 00544 char * string = NULL; 00545 char * expression; 00546 char buffer[OSL_MAX_STRING]; 00547 00548 OSL_malloc(string, char *, high_water_mark * sizeof(char)); 00549 string[0] = '\0'; 00550 00551 if ((relation == NULL) || (strings == NULL)) { 00552 OSL_debug("no relation or names while asked to print a comment"); 00553 return string; 00554 } 00555 00556 if ((sign = osl_relation_is_simple_output(relation, row))) { 00557 // First case : output == expression. 00558 00559 expression = osl_relation_subexpression(relation, row, 00560 1, relation->nb_output_dims, 00561 sign < 0, 00562 strings); 00563 snprintf(buffer, OSL_MAX_STRING, " ## %s", expression); 00564 osl_util_safe_strcat(&string, buffer, &high_water_mark); 00565 free(expression); 00566 00567 // We don't print the right hand side if it's an array identifier. 00568 if (!osl_relation_is_access(relation) || 00569 osl_int_zero(relation->precision, relation->m[row], 1)) { 00570 expression = osl_relation_subexpression(relation, row, 00571 relation->nb_output_dims + 1, 00572 relation->nb_columns - 1, 00573 sign > 0, 00574 strings); 00575 snprintf(buffer, OSL_MAX_STRING, " == %s", expression); 00576 osl_util_safe_strcat(&string, buffer, &high_water_mark); 00577 free(expression); 00578 } 00579 } 00580 else { 00581 // Second case : general case. 00582 00583 expression = osl_relation_expression(relation, row, strings); 00584 snprintf(buffer, OSL_MAX_STRING, " ## %s", expression); 00585 osl_util_safe_strcat(&string, buffer, &high_water_mark); 00586 free(expression); 00587 00588 if (osl_int_zero(relation->precision, relation->m[row], 0)) 00589 snprintf(buffer, OSL_MAX_STRING, " == 0"); 00590 else 00591 snprintf(buffer, OSL_MAX_STRING, " >= 0"); 00592 osl_util_safe_strcat(&string, buffer, &high_water_mark); 00593 } 00594 00595 return string; 00596 } 00597 00598 00608 static 00609 char * osl_relation_column_string(osl_relation_p relation, char ** strings) { 00610 int i, j; 00611 int index_output_dims; 00612 int index_input_dims; 00613 int index_local_dims; 00614 int index_parameters; 00615 int index_scalar; 00616 int space, length, left, right; 00617 char * scolumn; 00618 char temp[OSL_MAX_STRING]; 00619 00620 OSL_malloc(scolumn, char *, OSL_MAX_STRING); 00621 00622 index_output_dims = 1; 00623 index_input_dims = index_output_dims + relation->nb_output_dims; 00624 index_local_dims = index_input_dims + relation->nb_input_dims; 00625 index_parameters = index_local_dims + relation->nb_local_dims; 00626 index_scalar = index_parameters + relation->nb_parameters; 00627 00628 // 1. The comment part. 00629 sprintf(scolumn, "#"); 00630 for (j = 0; j < (OSL_FMT_LENGTH - 1)/2 - 1; j++) 00631 strcat(scolumn, " "); 00632 00633 i = 0; 00634 while (strings[i] != NULL) { 00635 space = OSL_FMT_LENGTH; 00636 length = (space > strlen(strings[i])) ? strlen(strings[i]) : space; 00637 right = (space - length + (OSL_FMT_LENGTH % 2)) / 2; 00638 left = space - length - right; 00639 00640 // 2. Spaces before the name 00641 for (j = 0; j < left; j++) 00642 strcat(scolumn, " "); 00643 00644 // 3. The (abbreviated) name 00645 for (j = 0; j < length - 1; j++) { 00646 sprintf(temp, "%c", strings[i][j]); 00647 strcat(scolumn, temp); 00648 } 00649 if (length >= strlen(strings[i])) 00650 sprintf(temp, "%c", strings[i][j]); 00651 else 00652 sprintf(temp, "."); 00653 strcat(scolumn, temp); 00654 00655 // 4. Spaces after the name 00656 for (j = 0; j < right; j++) 00657 strcat(scolumn, " "); 00658 00659 i++; 00660 if ((i == index_output_dims) || 00661 (i == index_input_dims) || 00662 (i == index_local_dims) || 00663 (i == index_parameters) || 00664 (i == index_scalar)) 00665 strcat(scolumn, "|"); 00666 else 00667 strcat(scolumn, " "); 00668 } 00669 strcat(scolumn, "\n"); 00670 00671 return scolumn; 00672 } 00673 00674 00682 static 00683 osl_names_p osl_relation_names(osl_relation_p relation) { 00684 int nb_parameters = OSL_UNDEFINED; 00685 int nb_iterators = OSL_UNDEFINED; 00686 int nb_scattdims = OSL_UNDEFINED; 00687 int nb_localdims = OSL_UNDEFINED; 00688 int array_id = OSL_UNDEFINED; 00689 00690 osl_relation_get_attributes(relation, &nb_parameters, &nb_iterators, 00691 &nb_scattdims, &nb_localdims, &array_id); 00692 00693 return osl_names_generate("P", nb_parameters, 00694 "i", nb_iterators, 00695 "c", nb_scattdims, 00696 "l", nb_localdims, 00697 "A", array_id); 00698 } 00699 00700 00708 int osl_relation_nb_components(osl_relation_p relation) { 00709 int nb_components = 0; 00710 00711 while (relation != NULL) { 00712 nb_components++; 00713 relation = relation->next; 00714 } 00715 00716 return nb_components; 00717 } 00718 00719 00729 char * osl_relation_spprint_polylib(osl_relation_p relation, 00730 osl_names_p names) { 00731 int i, j; 00732 int part, nb_parts; 00733 int generated_names = 0; 00734 int high_water_mark = OSL_MAX_STRING; 00735 char * string = NULL; 00736 char buffer[OSL_MAX_STRING]; 00737 char ** name_array = NULL; 00738 char * scolumn; 00739 char * comment; 00740 00741 if (relation == NULL) 00742 return strdup("# NULL relation\n"); 00743 00744 OSL_malloc(string, char *, high_water_mark * sizeof(char)); 00745 string[0] = '\0'; 00746 00747 // Generates the names for the comments if necessary. 00748 if (names == NULL) { 00749 generated_names = 1; 00750 names = osl_relation_names(relation); 00751 } 00752 00753 nb_parts = osl_relation_nb_components(relation); 00754 00755 if (nb_parts > 1) { 00756 snprintf(buffer, OSL_MAX_STRING, "# Union with %d parts\n%d\n", 00757 nb_parts, nb_parts); 00758 osl_util_safe_strcat(&string, buffer, &high_water_mark); 00759 } 00760 00761 // Print each part of the union. 00762 for (part = 1; part <= nb_parts; part++) { 00763 // Prepare the array of strings for comments. 00764 name_array = osl_relation_strings(relation, names); 00765 00766 if (nb_parts > 1) { 00767 snprintf(buffer, OSL_MAX_STRING, "# Union part No.%d\n", part); 00768 osl_util_safe_strcat(&string, buffer, &high_water_mark); 00769 } 00770 00771 snprintf(buffer, OSL_MAX_STRING, "%d %d %d %d %d %d\n", 00772 relation->nb_rows, relation->nb_columns, 00773 relation->nb_output_dims, relation->nb_input_dims, 00774 relation->nb_local_dims, relation->nb_parameters); 00775 osl_util_safe_strcat(&string, buffer, &high_water_mark); 00776 00777 if (relation->nb_rows > 0) { 00778 scolumn = osl_relation_column_string(relation, name_array); 00779 snprintf(buffer, OSL_MAX_STRING, "%s", scolumn); 00780 osl_util_safe_strcat(&string, buffer, &high_water_mark); 00781 free(scolumn); 00782 } 00783 00784 for (i = 0; i < relation->nb_rows; i++) { 00785 for (j = 0; j < relation->nb_columns; j++) { 00786 osl_int_sprint(buffer, relation->precision, relation->m[i], j); 00787 osl_util_safe_strcat(&string, buffer, &high_water_mark); 00788 snprintf(buffer, OSL_MAX_STRING, " "); 00789 osl_util_safe_strcat(&string, buffer, &high_water_mark); 00790 } 00791 00792 if (name_array != NULL) { 00793 comment = osl_relation_sprint_comment(relation, i, name_array); 00794 osl_util_safe_strcat(&string, comment, &high_water_mark); 00795 free(comment); 00796 } 00797 snprintf(buffer, OSL_MAX_STRING, "\n"); 00798 osl_util_safe_strcat(&string, buffer, &high_water_mark); 00799 } 00800 00801 // Free the array of strings. 00802 if (name_array != NULL) { 00803 for (i = 0; i < relation->nb_columns; i++) 00804 free(name_array[i]); 00805 free(name_array); 00806 } 00807 00808 relation = relation->next; 00809 } 00810 00811 if (generated_names) 00812 osl_names_free(names); 00813 00814 return string; 00815 } 00816 00817 00826 char * osl_relation_spprint(osl_relation_p relation, osl_names_p names) { 00827 int high_water_mark = OSL_MAX_STRING; 00828 char * string = NULL; 00829 char * temp; 00830 char buffer[OSL_MAX_STRING]; 00831 OSL_malloc(string, char *, high_water_mark * sizeof(char)); 00832 string[0] = '\0'; 00833 00834 if (osl_relation_nb_components(relation) > 0) { 00835 temp = osl_relation_sprint_type(relation); 00836 osl_util_safe_strcat(&string, temp, &high_water_mark); 00837 free(temp); 00838 00839 snprintf(buffer, OSL_MAX_STRING, "\n"); 00840 osl_util_safe_strcat(&string, buffer, &high_water_mark); 00841 00842 temp = osl_relation_spprint_polylib(relation, names); 00843 osl_util_safe_strcat(&string, temp, &high_water_mark); 00844 free(temp); 00845 } 00846 00847 return string; 00848 } 00849 00850 00859 void osl_relation_pprint(FILE * file, osl_relation_p relation, 00860 osl_names_p names) { 00861 char * string = osl_relation_spprint(relation, names); 00862 fprintf(file, "%s", string); 00863 free(string); 00864 } 00865 00866 00874 void osl_relation_print(FILE * file, osl_relation_p relation) { 00875 00876 osl_relation_pprint(file, relation, NULL); 00877 } 00878 00879 00880 /***************************************************************************** 00881 * Reading function * 00882 *****************************************************************************/ 00883 00884 00892 static 00893 int osl_relation_read_type(FILE * file) { 00894 int type; 00895 osl_strings_p strings; 00896 00897 strings = osl_strings_read(file); 00898 if (osl_strings_size(strings) > 1) { 00899 OSL_warning("uninterpreted information (after the relation type)"); 00900 } 00901 if (osl_strings_size(strings) == 0) 00902 OSL_error("no relation type"); 00903 00904 if (!strcmp(strings->string[0], OSL_STRING_UNDEFINED)) { 00905 type = OSL_UNDEFINED; 00906 goto return_type; 00907 } 00908 00909 if (!strcmp(strings->string[0], OSL_STRING_CONTEXT)) { 00910 type = OSL_TYPE_CONTEXT; 00911 goto return_type; 00912 } 00913 00914 if (!strcmp(strings->string[0], OSL_STRING_DOMAIN)) { 00915 type = OSL_TYPE_DOMAIN; 00916 goto return_type; 00917 } 00918 00919 if (!strcmp(strings->string[0], OSL_STRING_SCATTERING)) { 00920 type = OSL_TYPE_SCATTERING; 00921 goto return_type; 00922 } 00923 00924 if (!strcmp(strings->string[0], OSL_STRING_READ)) { 00925 type = OSL_TYPE_READ; 00926 goto return_type; 00927 } 00928 00929 if (!strcmp(strings->string[0], OSL_STRING_WRITE)) { 00930 type = OSL_TYPE_WRITE; 00931 goto return_type; 00932 } 00933 00934 if (!strcmp(strings->string[0], OSL_STRING_MAY_WRITE)) { 00935 type = OSL_TYPE_MAY_WRITE; 00936 goto return_type; 00937 } 00938 00939 OSL_error("relation type not supported"); 00940 00941 return_type: 00942 osl_strings_free(strings); 00943 return type; 00944 } 00945 00946 00956 osl_relation_p osl_relation_pread(FILE * foo, int precision) { 00957 int i, j, k, n, read = 0; 00958 int nb_rows, nb_columns; 00959 int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters; 00960 int nb_union_parts = 1; 00961 int may_read_nb_union_parts = 1; 00962 int read_attributes = 1; 00963 int first = 1; 00964 int type; 00965 char * c, s[OSL_MAX_STRING], str[OSL_MAX_STRING], *tmp; 00966 osl_relation_p relation, relation_union = NULL, previous = NULL; 00967 00968 type = osl_relation_read_type(foo); 00969 00970 // Read each part of the union (the number of parts may be updated inside) 00971 for (k = 0; k < nb_union_parts; k++) { 00972 // Read the number of union parts or the attributes of the union part 00973 while (read_attributes) { 00974 read_attributes = 0; 00975 00976 // Read relation attributes. 00977 c = osl_util_skip_blank_and_comments(foo, s); 00978 read = sscanf(c, " %d %d %d %d %d %d", &nb_rows, &nb_columns, 00979 &nb_output_dims, &nb_input_dims, 00980 &nb_local_dims, &nb_parameters); 00981 00982 if (((read != 1) && (read != 6)) || 00983 ((read == 1) && (may_read_nb_union_parts != 1))) 00984 OSL_error("not 1 or 6 integers on the first relation line"); 00985 00986 if (read == 1) { 00987 // Only one number means a union and is the number of parts. 00988 nb_union_parts = nb_rows; 00989 if (nb_union_parts < 1) 00990 OSL_error("negative nb of union parts"); 00991 00992 // Allow to read the properties of the first part of the union. 00993 read_attributes = 1; 00994 } 00995 00996 may_read_nb_union_parts = 0; 00997 } 00998 00999 // Allocate the union part and fill its properties. 01000 relation = osl_relation_pmalloc(precision, nb_rows, nb_columns); 01001 relation->type = type; 01002 relation->nb_output_dims = nb_output_dims; 01003 relation->nb_input_dims = nb_input_dims; 01004 relation->nb_local_dims = nb_local_dims; 01005 relation->nb_parameters = nb_parameters; 01006 01007 // Read the matrix of constraints. 01008 for (i = 0; i < relation->nb_rows; i++) { 01009 c = osl_util_skip_blank_and_comments(foo, s); 01010 if (c == NULL) 01011 OSL_error("not enough rows"); 01012 01013 for (j = 0; j < relation->nb_columns; j++) { 01014 if (c == NULL || *c == '#' || *c == '\n') 01015 OSL_error("not enough columns"); 01016 if (sscanf(c, "%s%n", str, &n) == 0) 01017 OSL_error("not enough rows"); 01018 01019 // TODO: remove this tmp (sread updates the pointer). 01020 tmp = str; 01021 osl_int_sread(&tmp, precision, relation->m[i], j); 01022 c += n; 01023 } 01024 } 01025 01026 // Build the linked list of union parts. 01027 if (first == 1) { 01028 relation_union = relation; 01029 first = 0; 01030 } 01031 else { 01032 previous->next = relation; 01033 } 01034 01035 previous = relation; 01036 read_attributes = 1; 01037 } 01038 01039 return relation_union; 01040 } 01041 01042 01050 osl_relation_p osl_relation_read(FILE * foo) { 01051 int precision = osl_util_get_precision(); 01052 return osl_relation_pread(foo, precision); 01053 } 01054 01055 01056 /*+*************************************************************************** 01057 * Memory allocation/deallocation function * 01058 *****************************************************************************/ 01059 01060 01072 osl_relation_p osl_relation_pmalloc(int precision, 01073 int nb_rows, int nb_columns) { 01074 osl_relation_p relation; 01075 void ** p, * q; 01076 int i, j; 01077 01078 OSL_malloc(relation, osl_relation_p, sizeof(osl_relation_t)); 01079 relation->type = OSL_UNDEFINED; 01080 relation->nb_rows = nb_rows; 01081 relation->nb_columns = nb_columns; 01082 relation->nb_output_dims = OSL_UNDEFINED; 01083 relation->nb_input_dims = OSL_UNDEFINED; 01084 relation->nb_parameters = OSL_UNDEFINED; 01085 relation->nb_local_dims = OSL_UNDEFINED; 01086 relation->precision = precision; 01087 01088 if ((nb_rows == 0) || (nb_columns == 0) || 01089 (nb_rows == OSL_UNDEFINED) || (nb_columns == OSL_UNDEFINED)) { 01090 relation->m = NULL; 01091 } 01092 else { 01093 OSL_malloc(p, void **, nb_rows * sizeof(void *)); 01094 OSL_malloc(q, void *, 01095 nb_rows * nb_columns * osl_int_sizeof(precision)); 01096 relation->m = p; 01097 for (i = 0; i < nb_rows; i++) { 01098 relation->m[i] = osl_int_address(precision, q, i * nb_columns); 01099 for (j = 0; j < nb_columns; j++) 01100 osl_int_init_set_si(precision, relation->m[i], j, 0); 01101 } 01102 } 01103 01104 relation->next = NULL; 01105 01106 return relation; 01107 } 01108 01109 01117 osl_relation_p osl_relation_malloc(int nb_rows, int nb_columns) { 01118 int precision = osl_util_get_precision(); 01119 return osl_relation_pmalloc(precision, nb_rows, nb_columns); 01120 } 01121 01122 01129 void osl_relation_free_inside(osl_relation_p relation) { 01130 int i, nb_elements; 01131 void * p; 01132 01133 if (relation == NULL) 01134 return; 01135 01136 nb_elements = relation->nb_rows * relation->nb_columns; 01137 01138 if (nb_elements > 0) 01139 p = relation->m[0]; 01140 01141 for (i = 0; i < nb_elements; i++) 01142 osl_int_clear(relation->precision, p, i); 01143 01144 if (relation->m != NULL) { 01145 if (nb_elements > 0) 01146 free(relation->m[0]); 01147 free(relation->m); 01148 } 01149 } 01150 01151 01158 void osl_relation_free(osl_relation_p relation) { 01159 osl_relation_p tmp; 01160 01161 if (relation == NULL) 01162 return; 01163 01164 while (relation != NULL) { 01165 tmp = relation->next; 01166 osl_relation_free_inside(relation); 01167 free(relation); 01168 relation = tmp; 01169 } 01170 } 01171 01172 01173 /*+*************************************************************************** 01174 * Processing functions * 01175 *****************************************************************************/ 01176 01177 01190 osl_relation_p osl_relation_nclone(osl_relation_p relation, int n) { 01191 int i, j; 01192 int first = 1, all_rows = 0; 01193 osl_relation_p clone = NULL, node, previous = NULL; 01194 01195 if (n == -1) 01196 all_rows = 1; 01197 01198 while (relation != NULL) { 01199 if (all_rows) 01200 n = relation->nb_rows; 01201 01202 if (n > relation->nb_rows) 01203 OSL_error("not enough rows to clone in the relation"); 01204 01205 node = osl_relation_pmalloc(relation->precision, n, relation->nb_columns); 01206 node->type = relation->type; 01207 node->nb_output_dims = relation->nb_output_dims; 01208 node->nb_input_dims = relation->nb_input_dims; 01209 node->nb_local_dims = relation->nb_local_dims; 01210 node->nb_parameters = relation->nb_parameters; 01211 01212 for (i = 0; i < n; i++) 01213 for (j = 0; j < relation->nb_columns; j++) 01214 osl_int_assign(relation->precision, node->m[i], j, relation->m[i], j); 01215 01216 if (first) { 01217 first = 0; 01218 clone = node; 01219 previous = node; 01220 } 01221 else { 01222 previous->next = node; 01223 previous = previous->next; 01224 } 01225 01226 relation = relation->next; 01227 } 01228 01229 return clone; 01230 } 01231 01232 01240 osl_relation_p osl_relation_clone(osl_relation_p relation) { 01241 if (relation == NULL) 01242 return NULL; 01243 01244 return osl_relation_nclone(relation, -1); 01245 } 01246 01247 01257 void osl_relation_replace_vector(osl_relation_p relation, 01258 osl_vector_p vector, int row) { 01259 int i; 01260 01261 if ((relation == NULL) || (vector == NULL) || 01262 (relation->precision != vector->precision) || 01263 (relation->nb_columns != vector->size) || 01264 (row >= relation->nb_rows) || (row < 0)) 01265 OSL_error("vector cannot replace relation row"); 01266 01267 for (i = 0; i < vector->size; i++) 01268 osl_int_assign(relation->precision, relation->m[row], i, vector->v, i); 01269 } 01270 01271 01281 void osl_relation_add_vector(osl_relation_p relation, 01282 osl_vector_p vector, int row) { 01283 int i; 01284 01285 if ((relation == NULL) || (vector == NULL) || 01286 (relation->precision != vector->precision) || 01287 (relation->nb_columns != vector->size) || 01288 (row >= relation->nb_rows) || (row < 0)) 01289 OSL_error("vector cannot be added to relation"); 01290 01291 if (osl_int_get_si(relation->precision, relation->m[row], 0) == 0) 01292 osl_int_assign(relation->precision, relation->m[row], 0, vector->v, 0); 01293 01294 for (i = 1; i < vector->size; i++) 01295 osl_int_add(relation->precision, 01296 relation->m[row], i, relation->m[row], i, vector->v, i); 01297 } 01298 01299 01309 void osl_relation_sub_vector(osl_relation_p relation, 01310 osl_vector_p vector, int row) { 01311 int i; 01312 01313 if ((relation == NULL) || (vector == NULL) || 01314 (relation->precision != vector->precision) || 01315 (relation->nb_columns != vector->size) || 01316 (row >= relation->nb_rows) || (row < 0)) 01317 OSL_error("vector cannot be subtracted to row"); 01318 01319 if (osl_int_get_si(relation->precision, relation->m[row], 0) == 0) 01320 osl_int_assign(relation->precision, relation->m[row], 0, vector->v, 0); 01321 01322 for (i = 1; i < vector->size; i++) 01323 osl_int_sub(relation->precision, 01324 relation->m[row], i, relation->m[row], i, vector->v, i); 01325 } 01326 01327 01338 void osl_relation_insert_vector(osl_relation_p relation, 01339 osl_vector_p vector, int row) { 01340 osl_relation_p temp; 01341 01342 temp = osl_relation_from_vector(vector); 01343 osl_relation_insert_constraints(relation, temp, row); 01344 osl_relation_free(temp); 01345 } 01346 01347 01355 void osl_relation_insert_blank_row(osl_relation_p relation, int row) { 01356 osl_vector_p vector; 01357 01358 if (relation != NULL) { 01359 vector = osl_vector_pmalloc(relation->precision, relation->nb_columns); 01360 osl_relation_insert_vector(relation, vector, row); 01361 osl_vector_free(vector); 01362 } 01363 } 01364 01365 01374 void osl_relation_insert_blank_column(osl_relation_p relation, int column) { 01375 01376 int i, j; 01377 osl_relation_p temp; 01378 01379 if (relation == NULL) 01380 return; 01381 01382 if ((column < 0) || (column > relation->nb_columns)) 01383 OSL_error("bad column number"); 01384 01385 // We use a temporary relation just to reuse existing functions. Cleaner. 01386 temp = osl_relation_pmalloc(relation->precision, 01387 relation->nb_rows, relation->nb_columns + 1); 01388 01389 for (i = 0; i < relation->nb_rows; i++) { 01390 for (j = 0; j < column; j++) 01391 osl_int_assign(relation->precision, temp->m[i], j, relation->m[i], j); 01392 01393 for (j = column; j < relation->nb_columns; j++) 01394 osl_int_assign(relation->precision, temp->m[i], j+1, relation->m[i], j); 01395 } 01396 01397 osl_relation_free_inside(relation); 01398 01399 // Replace the inside of relation. 01400 relation->nb_columns = temp->nb_columns; 01401 relation->m = temp->m; 01402 01403 // Free the temp "shell". 01404 free(temp); 01405 } 01406 01407 01415 osl_relation_p osl_relation_from_vector(osl_vector_p vector) { 01416 osl_relation_p relation; 01417 01418 if (vector == NULL) 01419 return NULL; 01420 01421 relation = osl_relation_pmalloc(vector->precision, 1, vector->size); 01422 osl_relation_replace_vector(relation, vector, 0); 01423 return relation; 01424 } 01425 01426 01436 void osl_relation_replace_constraints(osl_relation_p r1, 01437 osl_relation_p r2, int row) { 01438 int i, j; 01439 01440 if ((r1 == NULL) || (r2 == NULL) || 01441 (r1->precision != r2->precision) || 01442 (r1->nb_columns != r1->nb_columns) || 01443 ((row + r2->nb_rows) > r1->nb_rows) || (row < 0)) 01444 OSL_error("relation rows could not be replaced"); 01445 01446 for (i = 0; i < r2->nb_rows; i++) 01447 for (j = 0; j < r2->nb_columns; j++) 01448 osl_int_assign(r1->precision, r1->m[i+row], j, r2->m[i], j); 01449 } 01450 01451 01462 void osl_relation_insert_constraints(osl_relation_p r1, 01463 osl_relation_p r2, int row) { 01464 int i, j; 01465 osl_relation_p temp; 01466 01467 if ((r1 == NULL) || (r2 == NULL)) 01468 return; 01469 01470 if ((r1->nb_columns != r2->nb_columns) || 01471 (r1->precision != r2->precision) || 01472 (row > r1->nb_rows) || (row < 0)) 01473 OSL_error("constraints cannot be inserted"); 01474 01475 // We use a temporary relation just to reuse existing functions. Cleaner. 01476 temp = osl_relation_pmalloc(r1->precision, 01477 r1->nb_rows + r2->nb_rows, r1->nb_columns); 01478 01479 for (i = 0; i < row; i++) 01480 for (j = 0; j < r1->nb_columns; j++) 01481 osl_int_assign(r1->precision, temp->m[i], j, r1->m[i], j); 01482 01483 osl_relation_replace_constraints(temp, r2, row); 01484 01485 for (i = row + r2->nb_rows; i < r2->nb_rows + r1->nb_rows; i++) 01486 for (j = 0; j < r1->nb_columns; j++) 01487 osl_int_assign(r1->precision, temp->m[i], j, r1->m[i-r2->nb_rows], j); 01488 01489 osl_relation_free_inside(r1); 01490 01491 // Replace the inside of relation. 01492 r1->nb_rows = temp->nb_rows; 01493 r1->m = temp->m; 01494 01495 // Free the temp "shell". 01496 free(temp); 01497 } 01498 01499 01511 void osl_relation_insert_columns(osl_relation_p relation, 01512 osl_relation_p insert, int column) { 01513 int i, j; 01514 osl_relation_p temp; 01515 01516 if ((relation == NULL) || (insert == NULL)) 01517 return; 01518 01519 if ((relation->precision != insert->precision) || 01520 (relation->nb_rows != insert->nb_rows) || 01521 (column < 0) || (column > relation->nb_columns)) 01522 OSL_error("columns cannot be inserted"); 01523 01524 // We use a temporary relation just to reuse existing functions. Cleaner. 01525 temp = osl_relation_pmalloc(relation->precision, relation->nb_rows, 01526 relation->nb_columns + insert->nb_columns); 01527 01528 for (i = 0; i < relation->nb_rows; i++) { 01529 for (j = 0; j < column; j++) 01530 osl_int_assign(relation->precision, temp->m[i], j, relation->m[i], j); 01531 01532 for (j = column; j < column + insert->nb_columns; j++) 01533 osl_int_assign(relation->precision, 01534 temp->m[i], j, insert->m[i], j - column); 01535 01536 for (j = column + insert->nb_columns; 01537 j < insert->nb_columns + relation->nb_columns; j++) 01538 osl_int_assign(relation->precision, 01539 temp->m[i], j, relation->m[i], j - insert->nb_columns); 01540 } 01541 01542 osl_relation_free_inside(relation); 01543 01544 // Replace the inside of relation. 01545 relation->nb_columns = temp->nb_columns; 01546 relation->m = temp->m; 01547 01548 // Free the temp "shell". 01549 free(temp); 01550 } 01551 01552 01564 osl_relation_p osl_relation_concat_constraints( 01565 osl_relation_p r1, 01566 osl_relation_p r2) { 01567 osl_relation_p new; 01568 01569 if (r1 == NULL) 01570 return osl_relation_clone(r2); 01571 01572 if (r2 == NULL) 01573 return osl_relation_clone(r1); 01574 01575 if (r1->nb_columns != r2->nb_columns) 01576 OSL_error("incompatible sizes for concatenation"); 01577 01578 if (r1->next || r2->next) 01579 OSL_warning("relation concatenation is done on the first elements " 01580 "of union only"); 01581 01582 new = osl_relation_pmalloc(r1->precision, 01583 r1->nb_rows + r2->nb_rows, r1->nb_columns); 01584 osl_relation_replace_constraints(new, r1, 0); 01585 osl_relation_replace_constraints(new, r2, r1->nb_rows); 01586 01587 return new; 01588 } 01589 01590 01599 int osl_relation_equal(osl_relation_p r1, osl_relation_p r2) { 01600 int i, j; 01601 01602 while ((r1 != NULL) && (r2 != NULL)) { 01603 if (r1 == r2) 01604 return 1; 01605 01606 if ((r1->type != r2->type) || 01607 (r1->precision != r2->precision) || 01608 (r1->nb_rows != r2->nb_rows) || 01609 (r1->nb_columns != r2->nb_columns) || 01610 (r1->nb_output_dims != r2->nb_output_dims) || 01611 (r1->nb_input_dims != r2->nb_input_dims) || 01612 (r1->nb_local_dims != r2->nb_local_dims) || 01613 (r1->nb_parameters != r2->nb_parameters)) 01614 return 0; 01615 01616 for (i = 0; i < r1->nb_rows; ++i) 01617 for (j = 0; j < r1->nb_columns; ++j) 01618 if (osl_int_ne(r1->precision, r1->m[i], j, r2->m[i], j)) 01619 return 0; 01620 01621 r1 = r1->next; 01622 r2 = r2->next; 01623 } 01624 01625 if (((r1 == NULL) && (r2 != NULL)) || ((r1 != NULL) && (r2 == NULL))) 01626 return 0; 01627 01628 return 1; 01629 } 01630 01631 01645 static 01646 int osl_relation_check_attribute(int * expected, int actual) { 01647 if (*expected != OSL_UNDEFINED) { 01648 if ((actual != OSL_UNDEFINED) && 01649 (actual != *expected)) { 01650 OSL_warning("unexpected atribute"); 01651 return 0; 01652 } 01653 } 01654 else { 01655 *expected = actual; 01656 } 01657 01658 return 1; 01659 } 01660 01661 01675 static 01676 int osl_relation_check_nb_columns(osl_relation_p relation, 01677 int expected_nb_output_dims, 01678 int expected_nb_input_dims, 01679 int expected_nb_parameters) { 01680 int expected_nb_local_dims, expected_nb_columns; 01681 01682 if ((expected_nb_output_dims != OSL_UNDEFINED) && 01683 (expected_nb_input_dims != OSL_UNDEFINED) && 01684 (expected_nb_parameters != OSL_UNDEFINED)) { 01685 01686 if (relation->nb_local_dims == OSL_UNDEFINED) 01687 expected_nb_local_dims = 0; 01688 else 01689 expected_nb_local_dims = relation->nb_local_dims; 01690 01691 expected_nb_columns = expected_nb_output_dims + 01692 expected_nb_input_dims + 01693 expected_nb_local_dims + 01694 expected_nb_parameters + 01695 2; 01696 01697 if (expected_nb_columns != relation->nb_columns) { 01698 OSL_warning("unexpected number of columns"); 01699 return 0; 01700 } 01701 } 01702 01703 return 1; 01704 } 01705 01706 01721 int osl_relation_integrity_check(osl_relation_p relation, 01722 int expected_type, 01723 int expected_nb_output_dims, 01724 int expected_nb_input_dims, 01725 int expected_nb_parameters) { 01726 int i; 01727 01728 // Check the NULL case. 01729 if (relation == NULL) { 01730 if ((expected_nb_output_dims != OSL_UNDEFINED) || 01731 (expected_nb_input_dims != OSL_UNDEFINED) || 01732 (expected_nb_parameters != OSL_UNDEFINED)) { 01733 OSL_debug("NULL relation with some expected attibutes"); 01734 //return 0; 01735 } 01736 01737 return 1; 01738 } 01739 01740 // Check the type. 01741 if (((expected_type != OSL_TYPE_ACCESS) && 01742 (expected_type != relation->type)) || 01743 ((expected_type == OSL_TYPE_ACCESS) && 01744 (!osl_relation_is_access(relation)))) { 01745 OSL_warning("wrong type"); 01746 osl_relation_dump(stderr, relation); 01747 return 0; 01748 } 01749 01750 // Check that relations have no undefined atributes. 01751 if ((relation->nb_output_dims == OSL_UNDEFINED) || 01752 (relation->nb_input_dims == OSL_UNDEFINED) || 01753 (relation->nb_local_dims == OSL_UNDEFINED) || 01754 (relation->nb_parameters == OSL_UNDEFINED)) { 01755 OSL_warning("all attributes should be defined"); 01756 osl_relation_dump(stderr, relation); 01757 return 0; 01758 } 01759 01760 // Check that a context has actually 0 output dimensions. 01761 if ((relation->type == OSL_TYPE_CONTEXT) && 01762 (relation->nb_output_dims != 0)) { 01763 OSL_warning("context without 0 as number of output dimensions"); 01764 osl_relation_dump(stderr, relation); 01765 return 0; 01766 } 01767 01768 // Check that a domain or a context has actually 0 input dimensions. 01769 if (((relation->type == OSL_TYPE_DOMAIN) || 01770 (relation->type == OSL_TYPE_CONTEXT)) && 01771 (relation->nb_input_dims != 0)) { 01772 OSL_warning("domain or context without 0 input dimensions"); 01773 osl_relation_dump(stderr, relation); 01774 return 0; 01775 } 01776 01777 // Check properties according to expected values (and if expected values 01778 // are undefined, define them with the first relation part properties). 01779 if (!osl_relation_check_attribute(&expected_nb_output_dims, 01780 relation->nb_output_dims) || 01781 !osl_relation_check_attribute(&expected_nb_input_dims, 01782 relation->nb_input_dims) || 01783 !osl_relation_check_attribute(&expected_nb_parameters, 01784 relation->nb_parameters)) { 01785 osl_relation_dump(stderr, relation); 01786 return 0; 01787 } 01788 01789 while (relation != NULL) { 01790 01791 // Attributes (except the number of local dimensions) should be the same 01792 // in all parts of the union. 01793 if ((expected_nb_output_dims != relation->nb_output_dims) || 01794 (expected_nb_input_dims != relation->nb_input_dims) || 01795 (expected_nb_parameters != relation->nb_parameters)) { 01796 OSL_warning("inconsistent attributes"); 01797 osl_relation_dump(stderr, relation); 01798 return 0; 01799 } 01800 01801 // Check whether the number of columns is OK or not. 01802 if (!osl_relation_check_nb_columns(relation, 01803 expected_nb_output_dims, 01804 expected_nb_input_dims, 01805 expected_nb_parameters)) { 01806 osl_relation_dump(stderr, relation); 01807 return 0; 01808 } 01809 01810 // Check the first column. The first column of a relation part should be 01811 // made of 0 or 1 only. 01812 if ((relation->nb_rows > 0) && (relation->nb_columns > 0)) { 01813 for (i = 0; i < relation->nb_rows; i++) { 01814 if (!osl_int_zero(relation->precision, relation->m[i], 0) && 01815 !osl_int_one(relation->precision, relation->m[i], 0)) { 01816 OSL_warning("first column of a relation is not " 01817 "strictly made of 0 or 1"); 01818 osl_relation_dump(stderr, relation); 01819 return 0; 01820 } 01821 } 01822 } 01823 01824 // Array accesses must provide the array identifier. 01825 if ((osl_relation_is_access(relation)) && 01826 (osl_relation_get_array_id(relation) == OSL_UNDEFINED)) { 01827 osl_relation_dump(stderr, relation); 01828 return 0; 01829 } 01830 01831 relation = relation->next; 01832 } 01833 01834 return 1; 01835 } 01836 01837 01847 osl_relation_p osl_relation_union(osl_relation_p r1, 01848 osl_relation_p r2) { 01849 osl_relation_p copy1, copy2, tmp; 01850 01851 if ((r1 == NULL) && (r2 == NULL)) 01852 return NULL; 01853 01854 copy1 = osl_relation_clone(r1); 01855 copy2 = osl_relation_clone(r2); 01856 01857 if ((r1 != NULL) && (r2 == NULL)) 01858 return copy1; 01859 01860 if ((r1 == NULL) && (r2 != NULL)) 01861 return copy2; 01862 01863 tmp = copy1; 01864 while (tmp->next != NULL) 01865 tmp = tmp->next; 01866 01867 tmp->next = copy2; 01868 return copy1; 01869 } 01870 01871 01882 void osl_relation_set_attributes(osl_relation_p relation, 01883 int nb_output_dims, int nb_input_dims, 01884 int nb_local_dims, int nb_parameters) { 01885 if (relation != NULL) { 01886 relation->nb_output_dims = nb_output_dims; 01887 relation->nb_input_dims = nb_input_dims; 01888 relation->nb_local_dims = nb_local_dims; 01889 relation->nb_parameters = nb_parameters; 01890 } 01891 } 01892 01893 01901 void osl_relation_set_type(osl_relation_p relation, int type) { 01902 01903 while (relation != NULL) { 01904 relation->type = type; 01905 relation = relation->next; 01906 } 01907 } 01908 01909 01918 int osl_relation_get_array_id(osl_relation_p relation) { 01919 int i; 01920 int first = 1; 01921 int array_id = OSL_UNDEFINED; 01922 int reference_array_id = OSL_UNDEFINED; 01923 int nb_array_id; 01924 int row_id = 0; 01925 int precision; 01926 01927 if (relation == NULL) 01928 return OSL_UNDEFINED; 01929 01930 if (!osl_relation_is_access(relation)) { 01931 OSL_warning("asked for an array id of non-array relation"); 01932 return OSL_UNDEFINED; 01933 } 01934 01935 while (relation != NULL) { 01936 precision = relation->precision; 01937 01938 // There should be room to store the array identifier. 01939 if ((relation->nb_rows < 1) || 01940 (relation->nb_columns < 3)) { 01941 OSL_warning("no array identifier in an access function"); 01942 return OSL_UNDEFINED; 01943 } 01944 01945 // Array identifiers are m[i][#columns -1] / m[i][1], with i the only row 01946 // where m[i][1] is not 0. 01947 // - check there is exactly one row such that m[i][1] is not 0, 01948 // - check the whole ith row if full of 0 except m[i][1] and the id, 01949 // - check that (m[i][#columns -1] % m[i][1]) == 0, 01950 // - check that (-m[i][#columns -1] / m[i][1]) > 0. 01951 nb_array_id = 0; 01952 for (i = 0; i < relation->nb_rows; i++) { 01953 if (!osl_int_zero(precision, relation->m[i], 1)) { 01954 nb_array_id ++; 01955 row_id = i; 01956 } 01957 } 01958 if (nb_array_id == 0) { 01959 OSL_warning("no array identifier in an access function"); 01960 return OSL_UNDEFINED; 01961 } 01962 if (nb_array_id > 1) { 01963 OSL_warning("several array identifiers in one access function"); 01964 return OSL_UNDEFINED; 01965 } 01966 for (i = 0; i < relation->nb_columns - 1; i++) { 01967 if ((i != 1) && !osl_int_zero(precision, relation->m[row_id], i)) { 01968 OSL_warning("non integer array identifier"); 01969 return OSL_UNDEFINED; 01970 } 01971 } 01972 if (!osl_int_divisible(precision, 01973 relation->m[row_id], relation->nb_columns - 1, 01974 relation->m[row_id], 1)) { 01975 OSL_warning("rational array identifier"); 01976 return OSL_UNDEFINED; 01977 } 01978 array_id = -osl_int_get_si(precision, 01979 relation->m[row_id], 01980 relation->nb_columns - 1); 01981 array_id /= osl_int_get_si(precision, relation->m[row_id], 1); 01982 if (array_id <= 0) { 01983 OSL_warning("negative or 0 identifier in access function"); 01984 return OSL_UNDEFINED; 01985 } 01986 01987 // Unions of accesses are allowed, but they should refer at the same array. 01988 if (first) { 01989 reference_array_id = array_id; 01990 first = 0; 01991 } 01992 else { 01993 if (reference_array_id != array_id) { 01994 OSL_warning("inconsistency of array identifiers in an " 01995 "union of access relations"); 01996 return OSL_UNDEFINED; 01997 } 01998 } 01999 02000 relation = relation->next; 02001 } 02002 02003 return array_id; 02004 } 02005 02006 02014 int osl_relation_is_access(osl_relation_p relation) { 02015 02016 if (relation == NULL) 02017 return 0; 02018 02019 if ((relation->type == OSL_TYPE_ACCESS) || 02020 (relation->type == OSL_TYPE_READ) || 02021 (relation->type == OSL_TYPE_WRITE) || 02022 (relation->type == OSL_TYPE_MAY_WRITE)) 02023 return 1; 02024 02025 return 0; 02026 } 02027 02028 02047 void osl_relation_get_attributes(osl_relation_p relation, 02048 int * nb_parameters, 02049 int * nb_iterators, 02050 int * nb_scattdims, 02051 int * nb_localdims, 02052 int * array_id) { 02053 int type; 02054 int local_nb_parameters = OSL_UNDEFINED; 02055 int local_nb_iterators = OSL_UNDEFINED; 02056 int local_nb_scattdims = OSL_UNDEFINED; 02057 int local_nb_localdims = OSL_UNDEFINED; 02058 int local_array_id = OSL_UNDEFINED; 02059 02060 while (relation != NULL) { 02061 if (osl_relation_is_access(relation)) 02062 type = OSL_TYPE_ACCESS; 02063 else 02064 type = relation->type; 02065 02066 // There is some redundancy but I believe the code is cleaner this way. 02067 switch (type) { 02068 case OSL_TYPE_CONTEXT: 02069 local_nb_parameters = relation->nb_parameters; 02070 local_nb_iterators = 0; 02071 local_nb_scattdims = 0; 02072 local_nb_localdims = relation->nb_local_dims; 02073 local_array_id = 0; 02074 break; 02075 02076 case OSL_TYPE_DOMAIN: 02077 local_nb_parameters = relation->nb_parameters; 02078 local_nb_iterators = relation->nb_output_dims; 02079 local_nb_scattdims = 0; 02080 local_nb_localdims = relation->nb_local_dims; 02081 local_array_id = 0; 02082 break; 02083 02084 case OSL_TYPE_SCATTERING: 02085 local_nb_parameters = relation->nb_parameters; 02086 local_nb_iterators = relation->nb_input_dims; 02087 local_nb_scattdims = relation->nb_output_dims; 02088 local_nb_localdims = relation->nb_local_dims; 02089 local_array_id = 0; 02090 break; 02091 02092 case OSL_TYPE_ACCESS: 02093 local_nb_parameters = relation->nb_parameters; 02094 local_nb_iterators = relation->nb_input_dims; 02095 local_nb_scattdims = 0; 02096 local_nb_localdims = relation->nb_local_dims; 02097 local_array_id = osl_relation_get_array_id(relation); 02098 break; 02099 } 02100 02101 // Update. 02102 *nb_parameters = OSL_max(*nb_parameters, local_nb_parameters); 02103 *nb_iterators = OSL_max(*nb_iterators, local_nb_iterators); 02104 *nb_scattdims = OSL_max(*nb_scattdims, local_nb_scattdims); 02105 *nb_localdims = OSL_max(*nb_localdims, local_nb_localdims); 02106 *array_id = OSL_max(*array_id, local_array_id); 02107 relation = relation->next; 02108 } 02109 } 02110 02111 02123 osl_relation_p osl_relation_extend_output(osl_relation_p relation, int dim) { 02124 int i, j; 02125 int first = 1; 02126 int offset; 02127 osl_relation_p extended = NULL, node, previous = NULL; 02128 02129 while (relation != NULL) { 02130 if (relation->nb_output_dims > dim) 02131 OSL_error("Number of output dims is greater than required extension"); 02132 offset = dim - relation->nb_output_dims; 02133 02134 node = osl_relation_pmalloc(relation->precision, 02135 relation->nb_rows + offset, 02136 relation->nb_columns + offset); 02137 02138 node->type = relation->type; 02139 node->nb_output_dims = OSL_max(relation->nb_output_dims, dim); 02140 node->nb_input_dims = relation->nb_input_dims; 02141 node->nb_local_dims = relation->nb_local_dims; 02142 node->nb_parameters = relation->nb_parameters; 02143 02144 // Copy of the original relation with some 0 columns for the new dimensions 02145 // Note that we use the fact that the matrix is initialized with zeros. 02146 for (i = 0; i < relation->nb_rows; i++) { 02147 for (j = 0; j <= relation->nb_output_dims; j++) 02148 osl_int_assign(relation->precision, node->m[i], j, relation->m[i], j); 02149 02150 for (j = relation->nb_output_dims + offset + 1; 02151 j < relation->nb_columns + offset; j++) 02152 osl_int_assign(relation->precision, 02153 node->m[i], j, relation->m[i], j - offset); 02154 } 02155 02156 // New rows dedicated to the new dimensions 02157 for (i = relation->nb_rows; i < relation->nb_rows + offset; i++) { 02158 for (j = 0; j < relation->nb_columns + offset; j++) { 02159 if ((i - relation->nb_rows) == (j - relation->nb_output_dims - 1)) 02160 osl_int_set_si(relation->precision, node->m[i], j, -1); 02161 } 02162 } 02163 02164 if (first) { 02165 first = 0; 02166 extended = node; 02167 previous = node; 02168 } 02169 else { 02170 previous->next = node; 02171 previous = previous->next; 02172 } 02173 02174 relation = relation->next; 02175 } 02176 02177 return extended; 02178 } 02179