| |
| /*+-----------------------------------------------------------------** |
| ** OpenScop Library ** |
| **-----------------------------------------------------------------** |
| ** relation.c ** |
| **-----------------------------------------------------------------** |
| ** First version: 30/04/2008 ** |
| **-----------------------------------------------------------------** |
| |
| |
| ***************************************************************************** |
| * OpenScop: Structures and formats for polyhedral tools to talk together * |
| ***************************************************************************** |
| * ,___,,_,__,,__,,__,,__,,_,__,,_,__,,__,,___,_,__,,_,__, * |
| * / / / // // // // / / / // // / / // / /|,_, * |
| * / / / // // // // / / / // // / / // / / / /\ * |
| * |~~~|~|~~~|~~~|~~~|~~~|~|~~~|~|~~~|~~~|~~~|~|~~~|~|~~~|/_/ \ * |
| * | G |C| P | = | L | P |=| = |C| = | = | = |=| = |=| C |\ \ /\ * |
| * | R |l| o | = | e | l |=| = |a| = | = | = |=| = |=| L | \# \ /\ * |
| * | A |a| l | = | t | u |=| = |n| = | = | = |=| = |=| o | |\# \ \ * |
| * | P |n| l | = | s | t |=| = |d| = | = | = | | |=| o | | \# \ \ * |
| * | H | | y | | e | o | | = |l| | | = | | | | G | | \ \ \ * |
| * | I | | | | e | | | | | | | | | | | | | \ \ \ * |
| * | T | | | | | | | | | | | | | | | | | \ \ \ * |
| * | E | | | | | | | | | | | | | | | | | \ \ \ * |
| * | * |*| * | * | * | * |*| * |*| * | * | * |*| * |*| * | / \* \ \ * |
| * | O |p| e | n | S | c |o| p |-| L | i | b |r| a |r| y |/ \ \ / * |
| * '---'-'---'---'---'---'-'---'-'---'---'---'-'---'-'---' '--' * |
| * * |
| * Copyright (C) 2008 University Paris-Sud 11 and INRIA * |
| * * |
| * (3-clause BSD license) * |
| * Redistribution and use in source and binary forms, with or without * |
| * modification, are permitted provided that the following conditions * |
| * are met: * |
| * * |
| * 1. Redistributions of source code must retain the above copyright notice, * |
| * this list of conditions and the following disclaimer. * |
| * 2. Redistributions in binary form must reproduce the above copyright * |
| * notice, this list of conditions and the following disclaimer in the * |
| * documentation and/or other materials provided with the distribution. * |
| * 3. The name of the author may not be used to endorse or promote products * |
| * derived from this software without specific prior written permission. * |
| * * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * |
| * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * |
| * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * |
| * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * |
| * * |
| * OpenScop Library, a library to manipulate OpenScop formats and data * |
| * structures. Written by: * |
| * Cedric Bastoul <Cedric.Bastoul@u-psud.fr> and * |
| * Louis-Noel Pouchet <Louis-Noel.pouchet@inria.fr> * |
| * * |
| *****************************************************************************/ |
| |
| |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <ctype.h> |
| |
| #include <osl/macros.h> |
| #include <osl/int.h> |
| #include <osl/util.h> |
| #include <osl/vector.h> |
| #include <osl/strings.h> |
| #include <osl/names.h> |
| #include <osl/relation.h> |
| |
| |
| /*+*************************************************************************** |
| * Structure display function * |
| *****************************************************************************/ |
| |
| |
| /** |
| * osl_relation_sprint_type function: |
| * this function prints the textual type of an osl_relation_t structure into |
| * a string, according to the OpenScop specification, and returns that string. |
| * \param[in] relation The relation whose type has to be printed. |
| * \return A string containing the relation type. |
| */ |
| static |
| char * osl_relation_sprint_type(osl_relation_p relation) { |
| char * string = NULL; |
| |
| OSL_malloc(string, char *, OSL_MAX_STRING * sizeof(char)); |
| string[0] = '\0'; |
| |
| if (relation != NULL) { |
| switch (relation->type) { |
| case OSL_UNDEFINED: { |
| snprintf(string, OSL_MAX_STRING, OSL_STRING_UNDEFINED); |
| break; |
| } |
| case OSL_TYPE_CONTEXT: { |
| snprintf(string, OSL_MAX_STRING, OSL_STRING_CONTEXT); |
| break; |
| } |
| case OSL_TYPE_DOMAIN: { |
| snprintf(string, OSL_MAX_STRING, OSL_STRING_DOMAIN); |
| break; |
| } |
| case OSL_TYPE_SCATTERING: { |
| snprintf(string, OSL_MAX_STRING, OSL_STRING_SCATTERING); |
| break; |
| } |
| case OSL_TYPE_READ: { |
| snprintf(string, OSL_MAX_STRING, OSL_STRING_READ); |
| break; |
| } |
| case OSL_TYPE_WRITE: { |
| snprintf(string, OSL_MAX_STRING, OSL_STRING_WRITE); |
| break; |
| } |
| case OSL_TYPE_MAY_WRITE: { |
| snprintf(string, OSL_MAX_STRING, OSL_STRING_MAY_WRITE); |
| break; |
| } |
| default: { |
| OSL_warning("unknown relation type, " |
| "replaced with "OSL_STRING_UNDEFINED); |
| snprintf(string, OSL_MAX_STRING, OSL_STRING_UNDEFINED); |
| } |
| } |
| } |
| |
| return string; |
| } |
| |
| |
| /** |
| * osl_relation_print_type function: |
| * this function displays the textual type of an osl_relation_t structure into |
| * a file (file, possibly stdout), according to the OpenScop specification. |
| * \param[in] file File where informations are printed. |
| * \param[in] relation The relation whose type has to be printed. |
| */ |
| static |
| void osl_relation_print_type(FILE * file, osl_relation_p relation) { |
| char * string = osl_relation_sprint_type(relation); |
| fprintf(file, "%s", string); |
| free(string); |
| } |
| |
| |
| /** |
| * osl_relation_idump function: |
| * this function displays a osl_relation_t structure (*relation) into a |
| * file (file, possibly stdout) in a way that trends to be understandable. |
| * It includes an indentation level (level) in order to work with others |
| * idump functions. |
| * \param[in] file File where informations are printed. |
| * \param[in] relation The relation whose information has to be printed. |
| * \param[in] level Number of spaces before printing, for each line. |
| */ |
| void osl_relation_idump(FILE * file, osl_relation_p relation, int level) { |
| int i, j, first = 1; |
| |
| // Go to the right level. |
| for (j = 0; j < level; j++) |
| fprintf(file, "|\t"); |
| |
| if (relation != NULL) { |
| fprintf(file, "+-- osl_relation_t ("); |
| osl_relation_print_type(file, relation); |
| fprintf(file, ", "); |
| osl_int_dump_precision(file, relation->precision); |
| fprintf(file, ")\n"); |
| } |
| else { |
| fprintf(file, "+-- NULL relation\n"); |
| } |
| |
| while (relation != NULL) { |
| if (! first) { |
| // Go to the right level. |
| for (j = 0; j < level; j++) |
| fprintf(file, "|\t"); |
| fprintf(file, "| osl_relation_t ("); |
| osl_relation_print_type(file, relation); |
| fprintf(file, ", "); |
| osl_int_dump_precision(file, relation->precision); |
| fprintf(file, ")\n"); |
| } |
| else |
| first = 0; |
| |
| // A blank line |
| for(j = 0; j <= level; j++) |
| fprintf(file, "|\t"); |
| fprintf(file, "%d %d %d %d %d %d\n", |
| relation->nb_rows, relation->nb_columns, |
| relation->nb_output_dims, relation->nb_input_dims, |
| relation->nb_local_dims, relation->nb_parameters); |
| |
| // Display the relation. |
| for (i = 0; i < relation->nb_rows; i++) { |
| for (j = 0; j <= level; j++) |
| fprintf(file, "|\t"); |
| |
| fprintf(file, "[ "); |
| |
| for (j = 0; j < relation->nb_columns; j++) { |
| osl_int_print(file, relation->precision, relation->m[i], j); |
| fprintf(file, " "); |
| } |
| |
| fprintf(file, "]\n"); |
| } |
| |
| relation = relation->next; |
| |
| // Next line. |
| if (relation != NULL) { |
| for (j = 0; j <= level; j++) |
| fprintf(file, "|\t"); |
| fprintf(file, "|\n"); |
| for (j = 0; j <= level; j++) |
| fprintf(file, "|\t"); |
| fprintf(file, "V\n"); |
| } |
| } |
| |
| // The last line. |
| for (j = 0; j <= level; j++) |
| fprintf(file, "|\t"); |
| fprintf(file, "\n"); |
| } |
| |
| |
| /** |
| * osl_relation_dump function: |
| * this function prints the content of a osl_relation_t structure |
| * (*relation) into a file (file, possibly stdout). |
| * \param[in] file File where informations are printed. |
| * \param[in] relation The relation whose information have to be printed. |
| */ |
| void osl_relation_dump(FILE * file, osl_relation_p relation) { |
| osl_relation_idump(file, relation, 0); |
| } |
| |
| |
| /** |
| * osl_relation_expression_element function: |
| * this function returns a string containing the printing of a value (e.g., |
| * an iterator with its coefficient or a constant). |
| * \param[in] val Address of the coefficient or constant value. |
| * \param[in] precision The precision of the value. |
| * \param[in,out] first Pointer to a boolean set to 1 if the current value |
| * is the first of an expresion, 0 otherwise (maybe |
| * updated). |
| * \param[in] cst A boolean set to 1 if the value is a constant, |
| * 0 otherwise. |
| * \param[in] name String containing the name of the element. |
| * \return A string that contains the printing of a value. |
| */ |
| static |
| char * osl_relation_expression_element(void * val, |
| int precision, int * first, |
| int cst, char * name) { |
| char * temp, * body, * sval; |
| |
| OSL_malloc(temp, char *, OSL_MAX_STRING * sizeof(char)); |
| OSL_malloc(body, char *, OSL_MAX_STRING * sizeof(char)); |
| OSL_malloc(sval, char *, OSL_MAX_STRING * sizeof(char)); |
| |
| body[0] = '\0'; |
| sval[0] = '\0'; |
| |
| // statements for the 'normal' processing. |
| if (!osl_int_zero(precision, val, 0) && (!cst)) { |
| if ((*first) || osl_int_neg(precision, val, 0)) { |
| if (osl_int_one(precision, val, 0)) { // case 1 |
| sprintf(sval, "%s", name); |
| } |
| else { |
| if (osl_int_mone(precision, val, 0)) { // case -1 |
| sprintf(sval, "-%s", name); |
| } |
| else { // default case |
| osl_int_sprint(sval, precision, val, 0); |
| sprintf(temp, "*%s", name); |
| strcat(sval, temp); |
| } |
| } |
| *first = 0; |
| } |
| else { |
| if (osl_int_one(precision, val, 0)) { |
| sprintf(sval, "+%s", name); |
| } |
| else { |
| sprintf(sval, "+"); |
| osl_int_sprint_txt(temp, precision, val, 0); |
| strcat(sval, temp); |
| sprintf(temp, "*%s", name); |
| strcat(sval, temp); |
| } |
| } |
| } |
| else { |
| if (cst) { |
| if ((osl_int_zero(precision, val, 0) && (*first)) || |
| (osl_int_neg(precision, val, 0))) |
| osl_int_sprint_txt(sval, precision, val, 0); |
| if (osl_int_pos(precision, val, 0)) { |
| if (!(*first)) { |
| sprintf(sval, "+"); |
| osl_int_sprint_txt(temp, precision, val, 0); |
| strcat(sval, temp); |
| } |
| else { |
| osl_int_sprint_txt(sval, precision, val, 0); |
| } |
| } |
| } |
| } |
| free(temp); |
| free(body); |
| |
| return(sval); |
| } |
| |
| |
| /** |
| * osl_relation_strings function: |
| * this function creates a NULL-terminated array of strings from an |
| * osl_names_t structure in such a way that the ith string is the "name" |
| * corresponding to the ith column of the constraint matrix. |
| * \param[in] relation The relation for which we need an array of names. |
| * \param[in] names The set of names for each element. |
| * \return An array of strings with one string per constraint matrix column. |
| */ |
| static |
| char ** osl_relation_strings(osl_relation_p relation, osl_names_p names) { |
| char ** strings; |
| char temp[OSL_MAX_STRING]; |
| int i, offset, array_id; |
| |
| if ((relation == NULL) || (names == NULL)) { |
| OSL_debug("no names or relation to build the name array"); |
| return NULL; |
| } |
| |
| OSL_malloc(strings, char **, (relation->nb_columns + 1)*sizeof(char *)); |
| strings[relation->nb_columns] = NULL; |
| |
| // 1. Equality/inequality marker. |
| OSL_strdup(strings[0], "e/i"); |
| offset = 1; |
| |
| // 2. Output dimensions. |
| if (osl_relation_is_access(relation)) { |
| // The first output dimension is the array name. |
| array_id = osl_relation_get_array_id(relation); |
| OSL_strdup(strings[offset], names->arrays->string[array_id - 1]); |
| // The other ones are the array dimensions [1]...[n] |
| for (i = offset + 1; i < relation->nb_output_dims + offset; i++) { |
| sprintf(temp, "[%d]", i - 1); |
| OSL_strdup(strings[i], temp); |
| } |
| } |
| else |
| if (relation->type == OSL_TYPE_SCATTERING) { |
| for (i = offset; i < relation->nb_output_dims + offset; i++) { |
| OSL_strdup(strings[i], names->scatt_dims->string[i - offset]); |
| } |
| } |
| else { |
| for (i = offset; i < relation->nb_output_dims + offset; i++) { |
| OSL_strdup(strings[i], names->iterators->string[i - offset]); |
| } |
| } |
| offset += relation->nb_output_dims; |
| |
| // 3. Input dimensions. |
| for (i = offset; i < relation->nb_input_dims + offset; i++) |
| OSL_strdup(strings[i], names->iterators->string[i - offset]); |
| offset += relation->nb_input_dims; |
| |
| // 4. Local dimensions. |
| for (i = offset; i < relation->nb_local_dims + offset; i++) |
| OSL_strdup(strings[i], names->local_dims->string[i - offset]); |
| offset += relation->nb_local_dims; |
| |
| // 5. Parameters. |
| for (i = offset; i < relation->nb_parameters + offset; i++) |
| OSL_strdup(strings[i], names->parameters->string[i - offset]); |
| offset += relation->nb_parameters; |
| |
| // 6. Scalar. |
| OSL_strdup(strings[offset], "1"); |
| |
| return strings; |
| } |
| |
| |
| /** |
| * osl_relation_subexpression function: |
| * this function returns a string corresponding to an affine (sub-)expression |
| * stored at the "row"^th row of the relation pointed by "relation" between |
| * the start and stop columns. Optionnaly it may oppose the whole expression. |
| * \param[in] relation A set of linear expressions. |
| * \param[in] row The row corresponding to the expression. |
| * \param[in] start The first column for the expression (inclusive). |
| * \param[in] stop The last column for the expression (inclusive). |
| * \param[in] oppose Boolean set to 1 to negate the expression, 0 otherwise. |
| * \param[in] strings Array of textual names of the various elements. |
| * \return A string that contains the printing of an affine (sub-)expression. |
| */ |
| static |
| char * osl_relation_subexpression(osl_relation_p relation, |
| int row, int start, int stop, int oppose, |
| char ** strings) { |
| int i, first = 1, constant; |
| char * sval; |
| char * sline; |
| |
| OSL_malloc(sline, char *, OSL_MAX_STRING * sizeof(char)); |
| sline[0] = '\0'; |
| |
| // Create the expression. The constant is a special case. |
| for (i = start; i <= stop; i++) { |
| if (oppose) { |
| osl_int_oppose(relation->precision, |
| relation->m[row], i, relation->m[row], i); |
| } |
| |
| if (i == relation->nb_columns - 1) |
| constant = 1; |
| else |
| constant = 0; |
| |
| sval = osl_relation_expression_element( |
| osl_int_address(relation->precision, relation->m[row], i), |
| relation->precision, &first, constant, strings[i]); |
| |
| if (oppose) { |
| osl_int_oppose(relation->precision, |
| relation->m[row], i, relation->m[row], i); |
| } |
| strcat(sline, sval); |
| free(sval); |
| } |
| |
| return sline; |
| } |
| |
| |
| /** |
| * osl_relation_expression function: |
| * this function returns a string corresponding to an affine expression |
| * stored at the "row"^th row of the relation pointed by "relation". |
| * \param[in] relation A set of linear expressions. |
| * \param[in] row The row corresponding to the expression. |
| * \param[in] strings Array of textual names of the various elements. |
| * \return A string that contains the printing of an affine expression. |
| */ |
| char * osl_relation_expression(osl_relation_p relation, |
| int row, char ** strings) { |
| |
| return osl_relation_subexpression(relation, row, |
| 1, relation->nb_columns - 1, 0, |
| strings); |
| } |
| |
| |
| /** |
| * osl_relation_is_simple_output function: |
| * this function returns 1 or -1 if a given constraint row of a relation |
| * corresponds to an output, 0 otherwise. We call a simple output an equality |
| * constraint where exactly one output coefficient is not 0 and is either |
| * 1 (in this case the function returns 1) or -1 (in this case the function |
| * returns -1). |
| * \param[in] relation The relation to test for simple output. |
| * \param[in] row The row corresponding to the constraint to test. |
| * \return 1 or -1 if the row is a simple output, 0 otherwise. |
| */ |
| static |
| int osl_relation_is_simple_output(osl_relation_p relation, int row) { |
| int i; |
| int first = 1; |
| int sign = 0; |
| |
| if ((relation == NULL) || |
| (relation->m == NULL) || |
| (relation->nb_output_dims == 0)) |
| return 0; |
| |
| if ((row < 0) || (row > relation->nb_rows)) |
| OSL_error("the specified row does not exist in the relation"); |
| |
| // The constraint must be an equality. |
| if (!osl_int_zero(relation->precision, relation->m[row], 0)) |
| return 0; |
| |
| // Check the output part has one and only one non-zero +1 or -1 coefficient. |
| first = 1; |
| for (i = 1; i <= relation->nb_output_dims; i++) { |
| if (!osl_int_zero(relation->precision, relation->m[row], i)) { |
| if (first) |
| first = 0; |
| else |
| return 0; |
| |
| if (osl_int_one(relation->precision, relation->m[row], i)) |
| sign = 1; |
| else if (osl_int_mone(relation->precision, relation->m[row], i)) |
| sign = -1; |
| else |
| return 0; |
| } |
| } |
| |
| return sign; |
| } |
| |
| |
| /** |
| * osl_relation_sprint_comment function: |
| * this function prints into a string a comment corresponding to a constraint |
| * of a relation, according to its type, then it returns this string. This |
| * function does not check that printing the comment is possible (i.e., are |
| * there enough names ?), hence it is the responsibility of the user to ensure |
| * he/she can call this function safely. |
| * \param[in] relation The relation for which a comment has to be printed. |
| * \param[in] row The constrain row for which a comment has to be printed. |
| * \param[in] strings Array of textual names of the various elements. |
| * \return A string which contains the comment for the row. |
| */ |
| static |
| char * osl_relation_sprint_comment(osl_relation_p relation, |
| int row, char ** strings) { |
| int sign; |
| int high_water_mark = OSL_MAX_STRING; |
| char * string = NULL; |
| char * expression; |
| char buffer[OSL_MAX_STRING]; |
| |
| OSL_malloc(string, char *, high_water_mark * sizeof(char)); |
| string[0] = '\0'; |
| |
| if ((relation == NULL) || (strings == NULL)) { |
| OSL_debug("no relation or names while asked to print a comment"); |
| return string; |
| } |
| |
| if ((sign = osl_relation_is_simple_output(relation, row))) { |
| // First case : output == expression. |
| |
| expression = osl_relation_subexpression(relation, row, |
| 1, relation->nb_output_dims, |
| sign < 0, |
| strings); |
| snprintf(buffer, OSL_MAX_STRING, " ## %s", expression); |
| osl_util_safe_strcat(&string, buffer, &high_water_mark); |
| free(expression); |
| |
| // We don't print the right hand side if it's an array identifier. |
| if (!osl_relation_is_access(relation) || |
| osl_int_zero(relation->precision, relation->m[row], 1)) { |
| expression = osl_relation_subexpression(relation, row, |
| relation->nb_output_dims + 1, |
| relation->nb_columns - 1, |
| sign > 0, |
| strings); |
| snprintf(buffer, OSL_MAX_STRING, " == %s", expression); |
| osl_util_safe_strcat(&string, buffer, &high_water_mark); |
| free(expression); |
| } |
| } |
| else { |
| // Second case : general case. |
| |
| expression = osl_relation_expression(relation, row, strings); |
| snprintf(buffer, OSL_MAX_STRING, " ## %s", expression); |
| osl_util_safe_strcat(&string, buffer, &high_water_mark); |
| free(expression); |
| |
| if (osl_int_zero(relation->precision, relation->m[row], 0)) |
| snprintf(buffer, OSL_MAX_STRING, " == 0"); |
| else |
| snprintf(buffer, OSL_MAX_STRING, " >= 0"); |
| osl_util_safe_strcat(&string, buffer, &high_water_mark); |
| } |
| |
| return string; |
| } |
| |
| |
| /** |
| * osl_relation_column_string function: |
| * this function returns an OpenScop comment string showing all column |
| * names. It is designed to nicely fit a constraint matrix that would be |
| * printed just below this line. |
| * \param[in] relation The relation related to the comment line to build. |
| * \param[in] strings Array of textual names of the various elements. |
| * \return A fancy comment string with all the dimension names. |
| */ |
| static |
| char * osl_relation_column_string(osl_relation_p relation, char ** strings) { |
| int i, j; |
| int index_output_dims; |
| int index_input_dims; |
| int index_local_dims; |
| int index_parameters; |
| int index_scalar; |
| int space, length, left, right; |
| char * scolumn; |
| char temp[OSL_MAX_STRING]; |
| |
| OSL_malloc(scolumn, char *, OSL_MAX_STRING); |
| |
| index_output_dims = 1; |
| index_input_dims = index_output_dims + relation->nb_output_dims; |
| index_local_dims = index_input_dims + relation->nb_input_dims; |
| index_parameters = index_local_dims + relation->nb_local_dims; |
| index_scalar = index_parameters + relation->nb_parameters; |
| |
| // 1. The comment part. |
| sprintf(scolumn, "#"); |
| for (j = 0; j < (OSL_FMT_LENGTH - 1)/2 - 1; j++) |
| strcat(scolumn, " "); |
| |
| i = 0; |
| while (strings[i] != NULL) { |
| space = OSL_FMT_LENGTH; |
| length = (space > strlen(strings[i])) ? strlen(strings[i]) : space; |
| right = (space - length + (OSL_FMT_LENGTH % 2)) / 2; |
| left = space - length - right; |
| |
| // 2. Spaces before the name |
| for (j = 0; j < left; j++) |
| strcat(scolumn, " "); |
| |
| // 3. The (abbreviated) name |
| for (j = 0; j < length - 1; j++) { |
| sprintf(temp, "%c", strings[i][j]); |
| strcat(scolumn, temp); |
| } |
| if (length >= strlen(strings[i])) |
| sprintf(temp, "%c", strings[i][j]); |
| else |
| sprintf(temp, "."); |
| strcat(scolumn, temp); |
| |
| // 4. Spaces after the name |
| for (j = 0; j < right; j++) |
| strcat(scolumn, " "); |
| |
| i++; |
| if ((i == index_output_dims) || |
| (i == index_input_dims) || |
| (i == index_local_dims) || |
| (i == index_parameters) || |
| (i == index_scalar)) |
| strcat(scolumn, "|"); |
| else |
| strcat(scolumn, " "); |
| } |
| strcat(scolumn, "\n"); |
| |
| return scolumn; |
| } |
| |
| |
| /** |
| * osl_relation_names function: |
| * this function generates as set of names for all the dimensions |
| * involved in a given relation. |
| * \param[in] relation The relation we have to generate names for. |
| * \return A set of generated names for the input relation dimensions. |
| */ |
| static |
| osl_names_p osl_relation_names(osl_relation_p relation) { |
| int nb_parameters = OSL_UNDEFINED; |
| int nb_iterators = OSL_UNDEFINED; |
| int nb_scattdims = OSL_UNDEFINED; |
| int nb_localdims = OSL_UNDEFINED; |
| int array_id = OSL_UNDEFINED; |
| |
| osl_relation_get_attributes(relation, &nb_parameters, &nb_iterators, |
| &nb_scattdims, &nb_localdims, &array_id); |
| |
| return osl_names_generate("P", nb_parameters, |
| "i", nb_iterators, |
| "c", nb_scattdims, |
| "l", nb_localdims, |
| "A", array_id); |
| } |
| |
| |
| /** |
| * osl_relation_nb_components function: |
| * this function returns the number of component in the union of relations |
| * provided as parameter. |
| * \param[in] relation The input union of relations. |
| * \return The number of components in the input union of relations. |
| */ |
| int osl_relation_nb_components(osl_relation_p relation) { |
| int nb_components = 0; |
| |
| while (relation != NULL) { |
| nb_components++; |
| relation = relation->next; |
| } |
| |
| return nb_components; |
| } |
| |
| |
| /** |
| * osl_relation_spprint_polylib function: |
| * this function pretty-prints the content of an osl_relation_t structure |
| * (*relation) into a string in the extended polylib format, and returns this |
| * string. This format is the same as OpenScop's, minus the type. |
| * \param[in] relation The relation whose information has to be printed. |
| * \param[in] names The names of the constraint columns for comments. |
| * \return A string containing the relation pretty-printing. |
| */ |
| char * osl_relation_spprint_polylib(osl_relation_p relation, |
| osl_names_p names) { |
| int i, j; |
| int part, nb_parts; |
| int generated_names = 0; |
| int high_water_mark = OSL_MAX_STRING; |
| char * string = NULL; |
| char buffer[OSL_MAX_STRING]; |
| char ** name_array = NULL; |
| char * scolumn; |
| char * comment; |
| |
| if (relation == NULL) |
| return strdup("# NULL relation\n"); |
| |
| OSL_malloc(string, char *, high_water_mark * sizeof(char)); |
| string[0] = '\0'; |
| |
| // Generates the names for the comments if necessary. |
| if (names == NULL) { |
| generated_names = 1; |
| names = osl_relation_names(relation); |
| } |
| |
| nb_parts = osl_relation_nb_components(relation); |
| |
| if (nb_parts > 1) { |
| snprintf(buffer, OSL_MAX_STRING, "# Union with %d parts\n%d\n", |
| nb_parts, nb_parts); |
| osl_util_safe_strcat(&string, buffer, &high_water_mark); |
| } |
| |
| // Print each part of the union. |
| for (part = 1; part <= nb_parts; part++) { |
| // Prepare the array of strings for comments. |
| name_array = osl_relation_strings(relation, names); |
| |
| if (nb_parts > 1) { |
| snprintf(buffer, OSL_MAX_STRING, "# Union part No.%d\n", part); |
| osl_util_safe_strcat(&string, buffer, &high_water_mark); |
| } |
| |
| snprintf(buffer, OSL_MAX_STRING, "%d %d %d %d %d %d\n", |
| relation->nb_rows, relation->nb_columns, |
| relation->nb_output_dims, relation->nb_input_dims, |
| relation->nb_local_dims, relation->nb_parameters); |
| osl_util_safe_strcat(&string, buffer, &high_water_mark); |
| |
| if (relation->nb_rows > 0) { |
| scolumn = osl_relation_column_string(relation, name_array); |
| snprintf(buffer, OSL_MAX_STRING, "%s", scolumn); |
| osl_util_safe_strcat(&string, buffer, &high_water_mark); |
| free(scolumn); |
| } |
| |
| for (i = 0; i < relation->nb_rows; i++) { |
| for (j = 0; j < relation->nb_columns; j++) { |
| osl_int_sprint(buffer, relation->precision, relation->m[i], j); |
| osl_util_safe_strcat(&string, buffer, &high_water_mark); |
| snprintf(buffer, OSL_MAX_STRING, " "); |
| osl_util_safe_strcat(&string, buffer, &high_water_mark); |
| } |
| |
| if (name_array != NULL) { |
| comment = osl_relation_sprint_comment(relation, i, name_array); |
| osl_util_safe_strcat(&string, comment, &high_water_mark); |
| free(comment); |
| } |
| snprintf(buffer, OSL_MAX_STRING, "\n"); |
| osl_util_safe_strcat(&string, buffer, &high_water_mark); |
| } |
| |
| // Free the array of strings. |
| if (name_array != NULL) { |
| for (i = 0; i < relation->nb_columns; i++) |
| free(name_array[i]); |
| free(name_array); |
| } |
| |
| relation = relation->next; |
| } |
| |
| if (generated_names) |
| osl_names_free(names); |
| |
| return string; |
| } |
| |
| |
| /** |
| * osl_relation_spprint function: |
| * this function pretty-prints the content of an osl_relation_t structure |
| * (*relation) into a string in the OpenScop format, and returns this string. |
| * \param[in] relation The relation whose information has to be printed. |
| * \param[in] names The names of the constraint columns for comments. |
| * \return A string |
| */ |
| char * osl_relation_spprint(osl_relation_p relation, osl_names_p names) { |
| int high_water_mark = OSL_MAX_STRING; |
| char * string = NULL; |
| char * temp; |
| char buffer[OSL_MAX_STRING]; |
| OSL_malloc(string, char *, high_water_mark * sizeof(char)); |
| string[0] = '\0'; |
| |
| if (osl_relation_nb_components(relation) > 0) { |
| temp = osl_relation_sprint_type(relation); |
| osl_util_safe_strcat(&string, temp, &high_water_mark); |
| free(temp); |
| |
| snprintf(buffer, OSL_MAX_STRING, "\n"); |
| osl_util_safe_strcat(&string, buffer, &high_water_mark); |
| |
| temp = osl_relation_spprint_polylib(relation, names); |
| osl_util_safe_strcat(&string, temp, &high_water_mark); |
| free(temp); |
| } |
| |
| return string; |
| } |
| |
| |
| /** |
| * osl_relation_pprint function: |
| * this function pretty-prints the content of an osl_relation_t structure |
| * (*relation) into a file (file, possibly stdout) in the OpenScop format. |
| * \param[in] file File where informations are printed. |
| * \param[in] relation The relation whose information has to be printed. |
| * \param[in] names The names of the constraint columns for comments. |
| */ |
| void osl_relation_pprint(FILE * file, osl_relation_p relation, |
| osl_names_p names) { |
| char * string = osl_relation_spprint(relation, names); |
| fprintf(file, "%s", string); |
| free(string); |
| } |
| |
| |
| /** |
| * osl_relation_print function: |
| * this function prints the content of an osl_relation_t structure |
| * (*relation) into a file (file, possibly stdout) in the OpenScop format. |
| * \param[in] file File where informations are printed. |
| * \param[in] relation The relation whose information has to be printed. |
| */ |
| void osl_relation_print(FILE * file, osl_relation_p relation) { |
| |
| osl_relation_pprint(file, relation, NULL); |
| } |
| |
| |
| /***************************************************************************** |
| * Reading function * |
| *****************************************************************************/ |
| |
| |
| /** |
| * osl_relation_read_type function: |
| * this function reads a textual relation type and returns its integer |
| * counterpart. |
| * \param[in] file The input stream. |
| * \return The relation type. |
| */ |
| static |
| int osl_relation_read_type(FILE * file) { |
| int type; |
| osl_strings_p strings; |
| |
| strings = osl_strings_read(file); |
| if (osl_strings_size(strings) > 1) { |
| OSL_warning("uninterpreted information (after the relation type)"); |
| } |
| if (osl_strings_size(strings) == 0) |
| OSL_error("no relation type"); |
| |
| if (!strcmp(strings->string[0], OSL_STRING_UNDEFINED)) { |
| type = OSL_UNDEFINED; |
| goto return_type; |
| } |
| |
| if (!strcmp(strings->string[0], OSL_STRING_CONTEXT)) { |
| type = OSL_TYPE_CONTEXT; |
| goto return_type; |
| } |
| |
| if (!strcmp(strings->string[0], OSL_STRING_DOMAIN)) { |
| type = OSL_TYPE_DOMAIN; |
| goto return_type; |
| } |
| |
| if (!strcmp(strings->string[0], OSL_STRING_SCATTERING)) { |
| type = OSL_TYPE_SCATTERING; |
| goto return_type; |
| } |
| |
| if (!strcmp(strings->string[0], OSL_STRING_READ)) { |
| type = OSL_TYPE_READ; |
| goto return_type; |
| } |
| |
| if (!strcmp(strings->string[0], OSL_STRING_WRITE)) { |
| type = OSL_TYPE_WRITE; |
| goto return_type; |
| } |
| |
| if (!strcmp(strings->string[0], OSL_STRING_MAY_WRITE)) { |
| type = OSL_TYPE_MAY_WRITE; |
| goto return_type; |
| } |
| |
| OSL_error("relation type not supported"); |
| |
| return_type: |
| osl_strings_free(strings); |
| return type; |
| } |
| |
| |
| /** |
| * osl_relation_pread function ("precision read"): |
| * this function reads a relation into a file (foo, posibly stdin) and |
| * returns a pointer this relation. The relation is set to the maximum |
| * available precision. |
| * \param[in] foo The input stream. |
| * \param[in] precision The precision of the relation elements. |
| * \return A pointer to the relation structure that has been read. |
| */ |
| osl_relation_p osl_relation_pread(FILE * foo, int precision) { |
| int i, j, k, n, read = 0; |
| int nb_rows, nb_columns; |
| int nb_output_dims, nb_input_dims, nb_local_dims, nb_parameters; |
| int nb_union_parts = 1; |
| int may_read_nb_union_parts = 1; |
| int read_attributes = 1; |
| int first = 1; |
| int type; |
| char * c, s[OSL_MAX_STRING], str[OSL_MAX_STRING], *tmp; |
| osl_relation_p relation, relation_union = NULL, previous = NULL; |
| |
| type = osl_relation_read_type(foo); |
| |
| // Read each part of the union (the number of parts may be updated inside) |
| for (k = 0; k < nb_union_parts; k++) { |
| // Read the number of union parts or the attributes of the union part |
| while (read_attributes) { |
| read_attributes = 0; |
| |
| // Read relation attributes. |
| c = osl_util_skip_blank_and_comments(foo, s); |
| read = sscanf(c, " %d %d %d %d %d %d", &nb_rows, &nb_columns, |
| &nb_output_dims, &nb_input_dims, |
| &nb_local_dims, &nb_parameters); |
| |
| if (((read != 1) && (read != 6)) || |
| ((read == 1) && (may_read_nb_union_parts != 1))) |
| OSL_error("not 1 or 6 integers on the first relation line"); |
| |
| if (read == 1) { |
| // Only one number means a union and is the number of parts. |
| nb_union_parts = nb_rows; |
| if (nb_union_parts < 1) |
| OSL_error("negative nb of union parts"); |
| |
| // Allow to read the properties of the first part of the union. |
| read_attributes = 1; |
| } |
| |
| may_read_nb_union_parts = 0; |
| } |
| |
| // Allocate the union part and fill its properties. |
| relation = osl_relation_pmalloc(precision, nb_rows, nb_columns); |
| relation->type = type; |
| relation->nb_output_dims = nb_output_dims; |
| relation->nb_input_dims = nb_input_dims; |
| relation->nb_local_dims = nb_local_dims; |
| relation->nb_parameters = nb_parameters; |
| |
| // Read the matrix of constraints. |
| for (i = 0; i < relation->nb_rows; i++) { |
| c = osl_util_skip_blank_and_comments(foo, s); |
| if (c == NULL) |
| OSL_error("not enough rows"); |
| |
| for (j = 0; j < relation->nb_columns; j++) { |
| if (c == NULL || *c == '#' || *c == '\n') |
| OSL_error("not enough columns"); |
| if (sscanf(c, "%s%n", str, &n) == 0) |
| OSL_error("not enough rows"); |
| |
| // TODO: remove this tmp (sread updates the pointer). |
| tmp = str; |
| osl_int_sread(&tmp, precision, relation->m[i], j); |
| c += n; |
| } |
| } |
| |
| // Build the linked list of union parts. |
| if (first == 1) { |
| relation_union = relation; |
| first = 0; |
| } |
| else { |
| previous->next = relation; |
| } |
| |
| previous = relation; |
| read_attributes = 1; |
| } |
| |
| return relation_union; |
| } |
| |
| |
| /** |
| * osl_relation_read function: |
| * this function is equivalent to osl_relation_pread() except that |
| * the precision corresponds to the precision environment variable or |
| * to the highest available precision if it is not defined. |
| * \see{osl_relation_pread} |
| */ |
| osl_relation_p osl_relation_read(FILE * foo) { |
| int precision = osl_util_get_precision(); |
| return osl_relation_pread(foo, precision); |
| } |
| |
| |
| /*+*************************************************************************** |
| * Memory allocation/deallocation function * |
| *****************************************************************************/ |
| |
| |
| /** |
| * osl_relation_pmalloc function: |
| * (precision malloc) this function allocates the memory space for an |
| * osl_relation_t structure and sets its fields with default values. |
| * Then it returns a pointer to the allocated space. |
| * \param[in] precision The precision of the constraint matrix. |
| * \param[in] nb_rows The number of row of the relation to allocate. |
| * \param[in] nb_columns The number of columns of the relation to allocate. |
| * \return A pointer to an empty relation with fields set to default values |
| * and a ready-to-use constraint matrix. |
| */ |
| osl_relation_p osl_relation_pmalloc(int precision, |
| int nb_rows, int nb_columns) { |
| osl_relation_p relation; |
| void ** p, * q; |
| int i, j; |
| |
| OSL_malloc(relation, osl_relation_p, sizeof(osl_relation_t)); |
| relation->type = OSL_UNDEFINED; |
| relation->nb_rows = nb_rows; |
| relation->nb_columns = nb_columns; |
| relation->nb_output_dims = OSL_UNDEFINED; |
| relation->nb_input_dims = OSL_UNDEFINED; |
| relation->nb_parameters = OSL_UNDEFINED; |
| relation->nb_local_dims = OSL_UNDEFINED; |
| relation->precision = precision; |
| |
| if ((nb_rows == 0) || (nb_columns == 0) || |
| (nb_rows == OSL_UNDEFINED) || (nb_columns == OSL_UNDEFINED)) { |
| relation->m = NULL; |
| } |
| else { |
| OSL_malloc(p, void **, nb_rows * sizeof(void *)); |
| OSL_malloc(q, void *, |
| nb_rows * nb_columns * osl_int_sizeof(precision)); |
| relation->m = p; |
| for (i = 0; i < nb_rows; i++) { |
| relation->m[i] = osl_int_address(precision, q, i * nb_columns); |
| for (j = 0; j < nb_columns; j++) |
| osl_int_init_set_si(precision, relation->m[i], j, 0); |
| } |
| } |
| |
| relation->next = NULL; |
| |
| return relation; |
| } |
| |
| |
| /** |
| * osl_relation_malloc function: |
| * this function is equivalent to osl_relation_pmalloc() except that |
| * the precision corresponds to the precision environment variable or |
| * to the highest available precision if it is not defined. |
| * \see{osl_relation_pmalloc} |
| */ |
| osl_relation_p osl_relation_malloc(int nb_rows, int nb_columns) { |
| int precision = osl_util_get_precision(); |
| return osl_relation_pmalloc(precision, nb_rows, nb_columns); |
| } |
| |
| |
| /** |
| * osl_relation_free_inside function: |
| * this function frees the allocated memory for the inside of a |
| * osl_relation_t structure, i.e. only m. |
| * \param[in] relation The pointer to the relation we want to free internals. |
| */ |
| void osl_relation_free_inside(osl_relation_p relation) { |
| int i, nb_elements; |
| void * p; |
| |
| if (relation == NULL) |
| return; |
| |
| nb_elements = relation->nb_rows * relation->nb_columns; |
| |
| if (nb_elements > 0) |
| p = relation->m[0]; |
| |
| for (i = 0; i < nb_elements; i++) |
| osl_int_clear(relation->precision, p, i); |
| |
| if (relation->m != NULL) { |
| if (nb_elements > 0) |
| free(relation->m[0]); |
| free(relation->m); |
| } |
| } |
| |
| |
| /** |
| * osl_relation_free function: |
| * this function frees the allocated memory for an osl_relation_t |
| * structure. |
| * \param[in] relation The pointer to the relation we want to free. |
| */ |
| void osl_relation_free(osl_relation_p relation) { |
| osl_relation_p tmp; |
| |
| if (relation == NULL) |
| return; |
| |
| while (relation != NULL) { |
| tmp = relation->next; |
| osl_relation_free_inside(relation); |
| free(relation); |
| relation = tmp; |
| } |
| } |
| |
| |
| /*+*************************************************************************** |
| * Processing functions * |
| *****************************************************************************/ |
| |
| |
| /** |
| * osl_relation_nclone function: |
| * this functions builds and returns a "hard copy" (not a pointer copy) of a |
| * osl_relation_t data structure such that the clone is restricted to the |
| * "n" first rows of the relation. This applies to all the parts in the case |
| * of a relation union. |
| * \param[in] relation The pointer to the relation we want to clone. |
| * \param[in] n The number of row of the relation we want to clone (the |
| * special value -1 means "all the rows"). |
| * \return A pointer to the clone of the relation union restricted to the |
| * first n rows of constraint matrix for each part of the union. |
| */ |
| osl_relation_p osl_relation_nclone(osl_relation_p relation, int n) { |
| int i, j; |
| int first = 1, all_rows = 0; |
| osl_relation_p clone = NULL, node, previous = NULL; |
| |
| if (n == -1) |
| all_rows = 1; |
| |
| while (relation != NULL) { |
| if (all_rows) |
| n = relation->nb_rows; |
| |
| if (n > relation->nb_rows) |
| OSL_error("not enough rows to clone in the relation"); |
| |
| node = osl_relation_pmalloc(relation->precision, n, relation->nb_columns); |
| node->type = relation->type; |
| node->nb_output_dims = relation->nb_output_dims; |
| node->nb_input_dims = relation->nb_input_dims; |
| node->nb_local_dims = relation->nb_local_dims; |
| node->nb_parameters = relation->nb_parameters; |
| |
| for (i = 0; i < n; i++) |
| for (j = 0; j < relation->nb_columns; j++) |
| osl_int_assign(relation->precision, node->m[i], j, relation->m[i], j); |
| |
| if (first) { |
| first = 0; |
| clone = node; |
| previous = node; |
| } |
| else { |
| previous->next = node; |
| previous = previous->next; |
| } |
| |
| relation = relation->next; |
| } |
| |
| return clone; |
| } |
| |
| |
| /** |
| * osl_relation_clone function: |
| * this function builds and returns a "hard copy" (not a pointer copy) of an |
| * osl_relation_t data structure (the full union of relation). |
| * \param[in] relation The pointer to the relation we want to clone. |
| * \return A pointer to the clone of the union of relations. |
| */ |
| osl_relation_p osl_relation_clone(osl_relation_p relation) { |
| if (relation == NULL) |
| return NULL; |
| |
| return osl_relation_nclone(relation, -1); |
| } |
| |
| |
| /** |
| * osl_relation_replace_vector function: |
| * this function replaces the "row"^th row of a relation "relation" with the |
| * vector "vector". It directly updates the relation union part pointed |
| * by "relation" and this part only. |
| * \param[in,out] relation The relation we want to replace a row. |
| * \param[in] vector The vector that will replace a row of the relation. |
| * \param[in] row The row of the relation to be replaced. |
| */ |
| void osl_relation_replace_vector(osl_relation_p relation, |
| osl_vector_p vector, int row) { |
| int i; |
| |
| if ((relation == NULL) || (vector == NULL) || |
| (relation->precision != vector->precision) || |
| (relation->nb_columns != vector->size) || |
| (row >= relation->nb_rows) || (row < 0)) |
| OSL_error("vector cannot replace relation row"); |
| |
| for (i = 0; i < vector->size; i++) |
| osl_int_assign(relation->precision, relation->m[row], i, vector->v, i); |
| } |
| |
| |
| /** |
| * osl_relation_add_vector function: |
| * this function adds (meaning, +) a vector to the "row"^th row of a |
| * relation "relation". It directly updates the relation union part pointed |
| * by "relation" and this part only. |
| * \param[in,out] relation The relation we want to add a vector to a row. |
| * \param[in] vector The vector that will replace a row of the relation. |
| * \param[in] row The row of the relation to add the vector. |
| */ |
| void osl_relation_add_vector(osl_relation_p relation, |
| osl_vector_p vector, int row) { |
| int i; |
| |
| if ((relation == NULL) || (vector == NULL) || |
| (relation->precision != vector->precision) || |
| (relation->nb_columns != vector->size) || |
| (row >= relation->nb_rows) || (row < 0)) |
| OSL_error("vector cannot be added to relation"); |
| |
| if (osl_int_get_si(relation->precision, relation->m[row], 0) == 0) |
| osl_int_assign(relation->precision, relation->m[row], 0, vector->v, 0); |
| |
| for (i = 1; i < vector->size; i++) |
| osl_int_add(relation->precision, |
| relation->m[row], i, relation->m[row], i, vector->v, i); |
| } |
| |
| |
| /** |
| * osl_relation_sub_vector function: |
| * this function subtracts the vector "vector" to the "row"^th row of |
| * a relation "relation. It directly updates the relation union part pointed |
| * by "relation" and this part only. |
| * \param[in,out] relation The relation where to subtract a vector to a row. |
| * \param[in] vector The vector to subtract to a relation row. |
| * \param[in] row The row of the relation to subtract the vector. |
| */ |
| void osl_relation_sub_vector(osl_relation_p relation, |
| osl_vector_p vector, int row) { |
| int i; |
| |
| if ((relation == NULL) || (vector == NULL) || |
| (relation->precision != vector->precision) || |
| (relation->nb_columns != vector->size) || |
| (row >= relation->nb_rows) || (row < 0)) |
| OSL_error("vector cannot be subtracted to row"); |
| |
| if (osl_int_get_si(relation->precision, relation->m[row], 0) == 0) |
| osl_int_assign(relation->precision, relation->m[row], 0, vector->v, 0); |
| |
| for (i = 1; i < vector->size; i++) |
| osl_int_sub(relation->precision, |
| relation->m[row], i, relation->m[row], i, vector->v, i); |
| } |
| |
| |
| /** |
| * osl_relation_insert_vector function: |
| * this function inserts a new row corresponding to the vector "vector" to |
| * the relation "relation" by inserting it at the "row"^th row. It directly |
| * updates the relation union part pointed by "relation" and this part only. |
| * If "vector" (or "relation") is NULL, the relation is left unmodified. |
| * \param[in,out] relation The relation we want to extend. |
| * \param[in] vector The vector that will be added relation. |
| * \param[in] row The row where to insert the vector. |
| */ |
| void osl_relation_insert_vector(osl_relation_p relation, |
| osl_vector_p vector, int row) { |
| osl_relation_p temp; |
| |
| temp = osl_relation_from_vector(vector); |
| osl_relation_insert_constraints(relation, temp, row); |
| osl_relation_free(temp); |
| } |
| |
| |
| /** |
| * osl_relation_insert_blank_row function: |
| * this function inserts a new row filled with zeros o an existing relation |
| * union part (it only affects the first union part). |
| * \param[in,out] relation The relation to add a row in. |
| * \param[in] row The row where to insert the blank row. |
| */ |
| void osl_relation_insert_blank_row(osl_relation_p relation, int row) { |
| osl_vector_p vector; |
| |
| if (relation != NULL) { |
| vector = osl_vector_pmalloc(relation->precision, relation->nb_columns); |
| osl_relation_insert_vector(relation, vector, row); |
| osl_vector_free(vector); |
| } |
| } |
| |
| |
| /** |
| * osl_relation_insert_blank_column function: |
| * this function inserts a new column filled with zeros to an existing |
| * relation union part (it only affects the first union part). WARNING: |
| * this function does not update the relation attributes. |
| * \param[in,out] relation The relation to add a column in. |
| * \param[in] column The column where to insert the blank column. |
| */ |
| void osl_relation_insert_blank_column(osl_relation_p relation, int column) { |
| |
| int i, j; |
| osl_relation_p temp; |
| |
| if (relation == NULL) |
| return; |
| |
| if ((column < 0) || (column > relation->nb_columns)) |
| OSL_error("bad column number"); |
| |
| // We use a temporary relation just to reuse existing functions. Cleaner. |
| temp = osl_relation_pmalloc(relation->precision, |
| relation->nb_rows, relation->nb_columns + 1); |
| |
| for (i = 0; i < relation->nb_rows; i++) { |
| for (j = 0; j < column; j++) |
| osl_int_assign(relation->precision, temp->m[i], j, relation->m[i], j); |
| |
| for (j = column; j < relation->nb_columns; j++) |
| osl_int_assign(relation->precision, temp->m[i], j+1, relation->m[i], j); |
| } |
| |
| osl_relation_free_inside(relation); |
| |
| // Replace the inside of relation. |
| relation->nb_columns = temp->nb_columns; |
| relation->m = temp->m; |
| |
| // Free the temp "shell". |
| free(temp); |
| } |
| |
| |
| /** |
| * osl_relation_from_vector function: |
| * this function converts a vector "vector" to a relation with a single row |
| * and returns a pointer to that relation. |
| * \param[in] vector The vector to convert to a relation. |
| * \return A pointer to a relation resulting from the vector conversion. |
| */ |
| osl_relation_p osl_relation_from_vector(osl_vector_p vector) { |
| osl_relation_p relation; |
| |
| if (vector == NULL) |
| return NULL; |
| |
| relation = osl_relation_pmalloc(vector->precision, 1, vector->size); |
| osl_relation_replace_vector(relation, vector, 0); |
| return relation; |
| } |
| |
| |
| /** |
| * osl_relation_replace_constraints function: |
| * this function replaces some rows of a relation "r1" with the rows of |
| * the relation "r2". It begins at the "row"^th row of "r1". It directly |
| * updates the relation union part pointed by "r1" and this part only. |
| * \param[in,out] r1 The relation we want to change some rows. |
| * \param[in] r2 The relation containing the new rows. |
| * \param[in] row The first row of the relation r1 to be replaced. |
| */ |
| void osl_relation_replace_constraints(osl_relation_p r1, |
| osl_relation_p r2, int row) { |
| int i, j; |
| |
| if ((r1 == NULL) || (r2 == NULL) || |
| (r1->precision != r2->precision) || |
| (r1->nb_columns != r1->nb_columns) || |
| ((row + r2->nb_rows) > r1->nb_rows) || (row < 0)) |
| OSL_error("relation rows could not be replaced"); |
| |
| for (i = 0; i < r2->nb_rows; i++) |
| for (j = 0; j < r2->nb_columns; j++) |
| osl_int_assign(r1->precision, r1->m[i+row], j, r2->m[i], j); |
| } |
| |
| |
| /** |
| * osl_relation_insert_constraints function: |
| * this function adds new rows corresponding to the relation "r1" to |
| * the relation "r2" by inserting it at the "row"^th row. It directly |
| * updates the relation union part pointed by "r1" and this part only. |
| * If "r2" (or "r1") is NULL, the relation is left unmodified. |
| * \param[in,out] r1 The relation we want to extend. |
| * \param[in] r2 The relation to be inserted. |
| * \param[in] row The row where to insert the relation |
| */ |
| void osl_relation_insert_constraints(osl_relation_p r1, |
| osl_relation_p r2, int row) { |
| int i, j; |
| osl_relation_p temp; |
| |
| if ((r1 == NULL) || (r2 == NULL)) |
| return; |
| |
| if ((r1->nb_columns != r2->nb_columns) || |
| (r1->precision != r2->precision) || |
| (row > r1->nb_rows) || (row < 0)) |
| OSL_error("constraints cannot be inserted"); |
| |
| // We use a temporary relation just to reuse existing functions. Cleaner. |
| temp = osl_relation_pmalloc(r1->precision, |
| r1->nb_rows + r2->nb_rows, r1->nb_columns); |
| |
| for (i = 0; i < row; i++) |
| for (j = 0; j < r1->nb_columns; j++) |
| osl_int_assign(r1->precision, temp->m[i], j, r1->m[i], j); |
| |
| osl_relation_replace_constraints(temp, r2, row); |
| |
| for (i = row + r2->nb_rows; i < r2->nb_rows + r1->nb_rows; i++) |
| for (j = 0; j < r1->nb_columns; j++) |
| osl_int_assign(r1->precision, temp->m[i], j, r1->m[i-r2->nb_rows], j); |
| |
| osl_relation_free_inside(r1); |
| |
| // Replace the inside of relation. |
| r1->nb_rows = temp->nb_rows; |
| r1->m = temp->m; |
| |
| // Free the temp "shell". |
| free(temp); |
| } |
| |
| |
| /** |
| * osl_relation_insert_columns function: |
| * this function inserts new columns to an existing relation union part (it |
| * only affects the first union part). The columns are copied out from the |
| * matrix of an input relation which must have the convenient number of rows. |
| * All columns of the input matrix are copied. WARNING: this function does not |
| * update the relation attributes of the modified matrix. |
| * \param[in,out] relation The relation to add columns in. |
| * \param[in] insert The relation containing the columns to add. |
| * \param[in] column The column where to insert the new columns. |
| */ |
| void osl_relation_insert_columns(osl_relation_p relation, |
| osl_relation_p insert, int column) { |
| int i, j; |
| osl_relation_p temp; |
| |
| if ((relation == NULL) || (insert == NULL)) |
| return; |
| |
| if ((relation->precision != insert->precision) || |
| (relation->nb_rows != insert->nb_rows) || |
| (column < 0) || (column > relation->nb_columns)) |
| OSL_error("columns cannot be inserted"); |
| |
| // We use a temporary relation just to reuse existing functions. Cleaner. |
| temp = osl_relation_pmalloc(relation->precision, relation->nb_rows, |
| relation->nb_columns + insert->nb_columns); |
| |
| for (i = 0; i < relation->nb_rows; i++) { |
| for (j = 0; j < column; j++) |
| osl_int_assign(relation->precision, temp->m[i], j, relation->m[i], j); |
| |
| for (j = column; j < column + insert->nb_columns; j++) |
| osl_int_assign(relation->precision, |
| temp->m[i], j, insert->m[i], j - column); |
| |
| for (j = column + insert->nb_columns; |
| j < insert->nb_columns + relation->nb_columns; j++) |
| osl_int_assign(relation->precision, |
| temp->m[i], j, relation->m[i], j - insert->nb_columns); |
| } |
| |
| osl_relation_free_inside(relation); |
| |
| // Replace the inside of relation. |
| relation->nb_columns = temp->nb_columns; |
| relation->m = temp->m; |
| |
| // Free the temp "shell". |
| free(temp); |
| } |
| |
| |
| /** |
| * osl_relation_concat_constraints function: |
| * this function builds a new relation from two relations sent as |
| * parameters. The new set of constraints is built as the concatenation |
| * of the rows of the first elements of the two relation unions r1 and r2. |
| * This means, there is no next field in the result. |
| * \param[in] r1 The first relation. |
| * \param[in] r2 The second relation. |
| * \return A pointer to the relation resulting from the concatenation of |
| * the first elements of r1 and r2. |
| */ |
| osl_relation_p osl_relation_concat_constraints( |
| osl_relation_p r1, |
| osl_relation_p r2) { |
| osl_relation_p new; |
| |
| if (r1 == NULL) |
| return osl_relation_clone(r2); |
| |
| if (r2 == NULL) |
| return osl_relation_clone(r1); |
| |
| if (r1->nb_columns != r2->nb_columns) |
| OSL_error("incompatible sizes for concatenation"); |
| |
| if (r1->next || r2->next) |
| OSL_warning("relation concatenation is done on the first elements " |
| "of union only"); |
| |
| new = osl_relation_pmalloc(r1->precision, |
| r1->nb_rows + r2->nb_rows, r1->nb_columns); |
| osl_relation_replace_constraints(new, r1, 0); |
| osl_relation_replace_constraints(new, r2, r1->nb_rows); |
| |
| return new; |
| } |
| |
| |
| /** |
| * osl_relation_equal function: |
| * this function returns true if the two relations provided as parameters |
| * are the same, false otherwise. |
| * \param[in] r1 The first relation. |
| * \param[in] r2 The second relation. |
| * \return 1 if r1 and r2 are the same (content-wise), 0 otherwise. |
| */ |
| int osl_relation_equal(osl_relation_p r1, osl_relation_p r2) { |
| int i, j; |
| |
| while ((r1 != NULL) && (r2 != NULL)) { |
| if (r1 == r2) |
| return 1; |
| |
| if ((r1->type != r2->type) || |
| (r1->precision != r2->precision) || |
| (r1->nb_rows != r2->nb_rows) || |
| (r1->nb_columns != r2->nb_columns) || |
| (r1->nb_output_dims != r2->nb_output_dims) || |
| (r1->nb_input_dims != r2->nb_input_dims) || |
| (r1->nb_local_dims != r2->nb_local_dims) || |
| (r1->nb_parameters != r2->nb_parameters)) |
| return 0; |
| |
| for (i = 0; i < r1->nb_rows; ++i) |
| for (j = 0; j < r1->nb_columns; ++j) |
| if (osl_int_ne(r1->precision, r1->m[i], j, r2->m[i], j)) |
| return 0; |
| |
| r1 = r1->next; |
| r2 = r2->next; |
| } |
| |
| if (((r1 == NULL) && (r2 != NULL)) || ((r1 != NULL) && (r2 == NULL))) |
| return 0; |
| |
| return 1; |
| } |
| |
| |
| /** |
| * osl_relation_check_attribute internal function: |
| * This function checks whether an "actual" value is the same as an |
| * "expected" value or not. If the expected value is set to |
| * OSL_UNDEFINED, this function sets it to the "actual" value |
| * and do not report a difference has been detected. |
| * It returns 0 if a difference has been detected, 1 otherwise. |
| * \param[in,out] expected Pointer to the expected value (the value is |
| * modified if it was set to OSL_UNDEFINED). |
| * \param[in] actual Value we want to check. |
| * \return 0 if the values are not the same while the expected value was |
| * not OSL_UNDEFINED, 1 otherwise. |
| */ |
| static |
| int osl_relation_check_attribute(int * expected, int actual) { |
| if (*expected != OSL_UNDEFINED) { |
| if ((actual != OSL_UNDEFINED) && |
| (actual != *expected)) { |
| OSL_warning("unexpected atribute"); |
| return 0; |
| } |
| } |
| else { |
| *expected = actual; |
| } |
| |
| return 1; |
| } |
| |
| |
| /** |
| * osl_relation_check_nb_columns internal function: |
| * This function checks that the number of columns of a relation |
| * corresponds to some expected properties (setting an expected property to |
| * OSL_UNDEFINED makes this function unable to detect a problem). |
| * It returns 0 if the number of columns seems incorrect or 1 if no problem |
| * has been detected. |
| * \param[in] relation The relation we want to check the number of columns. |
| * \param[in] expected_nb_output_dims Expected number of output dimensions. |
| * \param[in] expected_nb_input_dims Expected number of input dimensions. |
| * \param[in] expected_nb_parameters Expected number of parameters. |
| * \return 0 if the number of columns seems incorrect, 1 otherwise. |
| */ |
| static |
| int osl_relation_check_nb_columns(osl_relation_p relation, |
| int expected_nb_output_dims, |
| int expected_nb_input_dims, |
| int expected_nb_parameters) { |
| int expected_nb_local_dims, expected_nb_columns; |
| |
| if ((expected_nb_output_dims != OSL_UNDEFINED) && |
| (expected_nb_input_dims != OSL_UNDEFINED) && |
| (expected_nb_parameters != OSL_UNDEFINED)) { |
| |
| if (relation->nb_local_dims == OSL_UNDEFINED) |
| expected_nb_local_dims = 0; |
| else |
| expected_nb_local_dims = relation->nb_local_dims; |
| |
| expected_nb_columns = expected_nb_output_dims + |
| expected_nb_input_dims + |
| expected_nb_local_dims + |
| expected_nb_parameters + |
| 2; |
| |
| if (expected_nb_columns != relation->nb_columns) { |
| OSL_warning("unexpected number of columns"); |
| return 0; |
| } |
| } |
| |
| return 1; |
| } |
| |
| |
| /** |
| * osl_relation_integrity_check function: |
| * this function checks that a relation is "well formed" according to some |
| * expected properties (setting an expected value to OSL_UNDEFINED means |
| * that we do not expect a specific value) and what the relation is supposed |
| * to represent. It returns 0 if the check failed or 1 if no problem has been |
| * detected. |
| * \param[in] relation The relation we want to check. |
| * \param[in] expected_type Semantics about this relation (domain, access...). |
| * \param[in] expected_nb_output_dims Expected number of output dimensions. |
| * \param[in] expected_nb_input_dims Expected number of input dimensions. |
| * \param[in] expected_nb_parameters Expected number of parameters. |
| * \return 0 if the integrity check fails, 1 otherwise. |
| */ |
| int osl_relation_integrity_check(osl_relation_p relation, |
| int expected_type, |
| int expected_nb_output_dims, |
| int expected_nb_input_dims, |
| int expected_nb_parameters) { |
| int i; |
| |
| // Check the NULL case. |
| if (relation == NULL) { |
| if ((expected_nb_output_dims != OSL_UNDEFINED) || |
| (expected_nb_input_dims != OSL_UNDEFINED) || |
| (expected_nb_parameters != OSL_UNDEFINED)) { |
| OSL_debug("NULL relation with some expected attibutes"); |
| //return 0; |
| } |
| |
| return 1; |
| } |
| |
| // Check the type. |
| if (((expected_type != OSL_TYPE_ACCESS) && |
| (expected_type != relation->type)) || |
| ((expected_type == OSL_TYPE_ACCESS) && |
| (!osl_relation_is_access(relation)))) { |
| OSL_warning("wrong type"); |
| osl_relation_dump(stderr, relation); |
| return 0; |
| } |
| |
| // Check that relations have no undefined atributes. |
| if ((relation->nb_output_dims == OSL_UNDEFINED) || |
| (relation->nb_input_dims == OSL_UNDEFINED) || |
| (relation->nb_local_dims == OSL_UNDEFINED) || |
| (relation->nb_parameters == OSL_UNDEFINED)) { |
| OSL_warning("all attributes should be defined"); |
| osl_relation_dump(stderr, relation); |
| return 0; |
| } |
| |
| // Check that a context has actually 0 output dimensions. |
| if ((relation->type == OSL_TYPE_CONTEXT) && |
| (relation->nb_output_dims != 0)) { |
| OSL_warning("context without 0 as number of output dimensions"); |
| osl_relation_dump(stderr, relation); |
| return 0; |
| } |
| |
| // Check that a domain or a context has actually 0 input dimensions. |
| if (((relation->type == OSL_TYPE_DOMAIN) || |
| (relation->type == OSL_TYPE_CONTEXT)) && |
| (relation->nb_input_dims != 0)) { |
| OSL_warning("domain or context without 0 input dimensions"); |
| osl_relation_dump(stderr, relation); |
| return 0; |
| } |
| |
| // Check properties according to expected values (and if expected values |
| // are undefined, define them with the first relation part properties). |
| if (!osl_relation_check_attribute(&expected_nb_output_dims, |
| relation->nb_output_dims) || |
| !osl_relation_check_attribute(&expected_nb_input_dims, |
| relation->nb_input_dims) || |
| !osl_relation_check_attribute(&expected_nb_parameters, |
| relation->nb_parameters)) { |
| osl_relation_dump(stderr, relation); |
| return 0; |
| } |
| |
| while (relation != NULL) { |
| |
| // Attributes (except the number of local dimensions) should be the same |
| // in all parts of the union. |
| if ((expected_nb_output_dims != relation->nb_output_dims) || |
| (expected_nb_input_dims != relation->nb_input_dims) || |
| (expected_nb_parameters != relation->nb_parameters)) { |
| OSL_warning("inconsistent attributes"); |
| osl_relation_dump(stderr, relation); |
| return 0; |
| } |
| |
| // Check whether the number of columns is OK or not. |
| if (!osl_relation_check_nb_columns(relation, |
| expected_nb_output_dims, |
| expected_nb_input_dims, |
| expected_nb_parameters)) { |
| osl_relation_dump(stderr, relation); |
| return 0; |
| } |
| |
| // Check the first column. The first column of a relation part should be |
| // made of 0 or 1 only. |
| if ((relation->nb_rows > 0) && (relation->nb_columns > 0)) { |
| for (i = 0; i < relation->nb_rows; i++) { |
| if (!osl_int_zero(relation->precision, relation->m[i], 0) && |
| !osl_int_one(relation->precision, relation->m[i], 0)) { |
| OSL_warning("first column of a relation is not " |
| "strictly made of 0 or 1"); |
| osl_relation_dump(stderr, relation); |
| return 0; |
| } |
| } |
| } |
| |
| // Array accesses must provide the array identifier. |
| if ((osl_relation_is_access(relation)) && |
| (osl_relation_get_array_id(relation) == OSL_UNDEFINED)) { |
| osl_relation_dump(stderr, relation); |
| return 0; |
| } |
| |
| relation = relation->next; |
| } |
| |
| return 1; |
| } |
| |
| |
| /** |
| * osl_relation_union function: |
| * this function builds a new relation from two relations provided |
| * as parameters. The new relation is built as an union of the |
| * two relations: the list of constraint sets are linked together. |
| * \param[in] r1 The first relation. |
| * \param[in] r2 The second relation. |
| * \return A new relation corresponding to the union of r1 and r2. |
| */ |
| osl_relation_p osl_relation_union(osl_relation_p r1, |
| osl_relation_p r2) { |
| osl_relation_p copy1, copy2, tmp; |
| |
| if ((r1 == NULL) && (r2 == NULL)) |
| return NULL; |
| |
| copy1 = osl_relation_clone(r1); |
| copy2 = osl_relation_clone(r2); |
| |
| if ((r1 != NULL) && (r2 == NULL)) |
| return copy1; |
| |
| if ((r1 == NULL) && (r2 != NULL)) |
| return copy2; |
| |
| tmp = copy1; |
| while (tmp->next != NULL) |
| tmp = tmp->next; |
| |
| tmp->next = copy2; |
| return copy1; |
| } |
| |
| |
| /** |
| * osl_relation_set_attributes function: |
| * this functions sets the attributes of a relation provided as a |
| * parameter. It updates the relation directly. |
| * \param[in,out] relation The relation to set the attributes. |
| * \param[in] nb_output_dims Number of output dimensions. |
| * \param[in] nb_input_dims Number of input dimensions. |
| * \param[in] nb_local_dims Number of local dimensions. |
| * \param[in] nb_parameters Number of parameters. |
| */ |
| void osl_relation_set_attributes(osl_relation_p relation, |
| int nb_output_dims, int nb_input_dims, |
| int nb_local_dims, int nb_parameters) { |
| if (relation != NULL) { |
| relation->nb_output_dims = nb_output_dims; |
| relation->nb_input_dims = nb_input_dims; |
| relation->nb_local_dims = nb_local_dims; |
| relation->nb_parameters = nb_parameters; |
| } |
| } |
| |
| |
| /** |
| * osl_relation_set_type function: |
| * this function sets the type of each relation union part in the relation |
| * to the one provided as parameter. |
| * \param relation The relation to set the type. |
| * \param type The type. |
| */ |
| void osl_relation_set_type(osl_relation_p relation, int type) { |
| |
| while (relation != NULL) { |
| relation->type = type; |
| relation = relation->next; |
| } |
| } |
| |
| |
| /** |
| * osl_relation_get_array_id function: |
| * this function returns the array identifier in a relation with access type |
| * It returns OSL_UNDEFINED if it is not able to find it (in particular |
| * if there are irregularities in the relation). |
| * \param[in] relation The relation where to find an array identifier. |
| * \return The array identifier in the relation or OSL_UNDEFINED. |
| */ |
| int osl_relation_get_array_id(osl_relation_p relation) { |
| int i; |
| int first = 1; |
| int array_id = OSL_UNDEFINED; |
| int reference_array_id = OSL_UNDEFINED; |
| int nb_array_id; |
| int row_id = 0; |
| int precision; |
| |
| if (relation == NULL) |
| return OSL_UNDEFINED; |
| |
| if (!osl_relation_is_access(relation)) { |
| OSL_warning("asked for an array id of non-array relation"); |
| return OSL_UNDEFINED; |
| } |
| |
| while (relation != NULL) { |
| precision = relation->precision; |
| |
| // There should be room to store the array identifier. |
| if ((relation->nb_rows < 1) || |
| (relation->nb_columns < 3)) { |
| OSL_warning("no array identifier in an access function"); |
| return OSL_UNDEFINED; |
| } |
| |
| // Array identifiers are m[i][#columns -1] / m[i][1], with i the only row |
| // where m[i][1] is not 0. |
| // - check there is exactly one row such that m[i][1] is not 0, |
| // - check the whole ith row if full of 0 except m[i][1] and the id, |
| // - check that (m[i][#columns -1] % m[i][1]) == 0, |
| // - check that (-m[i][#columns -1] / m[i][1]) > 0. |
| nb_array_id = 0; |
| for (i = 0; i < relation->nb_rows; i++) { |
| if (!osl_int_zero(precision, relation->m[i], 1)) { |
| nb_array_id ++; |
| row_id = i; |
| } |
| } |
| if (nb_array_id == 0) { |
| OSL_warning("no array identifier in an access function"); |
| return OSL_UNDEFINED; |
| } |
| if (nb_array_id > 1) { |
| OSL_warning("several array identifiers in one access function"); |
| return OSL_UNDEFINED; |
| } |
| for (i = 0; i < relation->nb_columns - 1; i++) { |
| if ((i != 1) && !osl_int_zero(precision, relation->m[row_id], i)) { |
| OSL_warning("non integer array identifier"); |
| return OSL_UNDEFINED; |
| } |
| } |
| if (!osl_int_divisible(precision, |
| relation->m[row_id], relation->nb_columns - 1, |
| relation->m[row_id], 1)) { |
| OSL_warning("rational array identifier"); |
| return OSL_UNDEFINED; |
| } |
| array_id = -osl_int_get_si(precision, |
| relation->m[row_id], |
| relation->nb_columns - 1); |
| array_id /= osl_int_get_si(precision, relation->m[row_id], 1); |
| if (array_id <= 0) { |
| OSL_warning("negative or 0 identifier in access function"); |
| return OSL_UNDEFINED; |
| } |
| |
| // Unions of accesses are allowed, but they should refer at the same array. |
| if (first) { |
| reference_array_id = array_id; |
| first = 0; |
| } |
| else { |
| if (reference_array_id != array_id) { |
| OSL_warning("inconsistency of array identifiers in an " |
| "union of access relations"); |
| return OSL_UNDEFINED; |
| } |
| } |
| |
| relation = relation->next; |
| } |
| |
| return array_id; |
| } |
| |
| |
| /** |
| * osl_relation_is_access function: |
| * this function returns 1 if the relation corresponds to an access relation, |
| * whatever its precise type (read, write etc.), 0 otherwise. |
| * \param relation The relation to check wheter it is an access relation or not. |
| * \return 1 if the relation is an access relation, 0 otherwise. |
| */ |
| int osl_relation_is_access(osl_relation_p relation) { |
| |
| if (relation == NULL) |
| return 0; |
| |
| if ((relation->type == OSL_TYPE_ACCESS) || |
| (relation->type == OSL_TYPE_READ) || |
| (relation->type == OSL_TYPE_WRITE) || |
| (relation->type == OSL_TYPE_MAY_WRITE)) |
| return 1; |
| |
| return 0; |
| } |
| |
| |
| /** |
| * osl_relation_get_attributes function: |
| * this function returns, through its parameters, the maximum values of the |
| * relation attributes (nb_iterators, nb_parameters etc), depending on its |
| * type. HOWEVER, it updates the parameter value iff the attribute is greater |
| * than the input parameter value. Hence it may be used to get the |
| * attributes as well as to find the maximum attributes for several relations. |
| * The array identifier 0 is used when there is no array identifier (AND this |
| * is OK), OSL_UNDEFINED is used to report it is impossible to provide the |
| * property while it should. This function is not intended for checking, the |
| * input relation should be correct. |
| * \param[in] relation The relation to extract attribute values. |
| * \param[in,out] nb_parameters Number of parameter attribute. |
| * \param[in,out] nb_iterators Number of iterators attribute. |
| * \param[in,out] nb_scattdims Number of scattering dimensions attribute. |
| * \param[in,out] nb_localdims Number of local dimensions attribute. |
| * \param[in,out] array_id Maximum array identifier attribute. |
| */ |
| void osl_relation_get_attributes(osl_relation_p relation, |
| int * nb_parameters, |
| int * nb_iterators, |
| int * nb_scattdims, |
| int * nb_localdims, |
| int * array_id) { |
| int type; |
| int local_nb_parameters = OSL_UNDEFINED; |
| int local_nb_iterators = OSL_UNDEFINED; |
| int local_nb_scattdims = OSL_UNDEFINED; |
| int local_nb_localdims = OSL_UNDEFINED; |
| int local_array_id = OSL_UNDEFINED; |
| |
| while (relation != NULL) { |
| if (osl_relation_is_access(relation)) |
| type = OSL_TYPE_ACCESS; |
| else |
| type = relation->type; |
| |
| // There is some redundancy but I believe the code is cleaner this way. |
| switch (type) { |
| case OSL_TYPE_CONTEXT: |
| local_nb_parameters = relation->nb_parameters; |
| local_nb_iterators = 0; |
| local_nb_scattdims = 0; |
| local_nb_localdims = relation->nb_local_dims; |
| local_array_id = 0; |
| break; |
| |
| case OSL_TYPE_DOMAIN: |
| local_nb_parameters = relation->nb_parameters; |
| local_nb_iterators = relation->nb_output_dims; |
| local_nb_scattdims = 0; |
| local_nb_localdims = relation->nb_local_dims; |
| local_array_id = 0; |
| break; |
| |
| case OSL_TYPE_SCATTERING: |
| local_nb_parameters = relation->nb_parameters; |
| local_nb_iterators = relation->nb_input_dims; |
| local_nb_scattdims = relation->nb_output_dims; |
| local_nb_localdims = relation->nb_local_dims; |
| local_array_id = 0; |
| break; |
| |
| case OSL_TYPE_ACCESS: |
| local_nb_parameters = relation->nb_parameters; |
| local_nb_iterators = relation->nb_input_dims; |
| local_nb_scattdims = 0; |
| local_nb_localdims = relation->nb_local_dims; |
| local_array_id = osl_relation_get_array_id(relation); |
| break; |
| } |
| |
| // Update. |
| *nb_parameters = OSL_max(*nb_parameters, local_nb_parameters); |
| *nb_iterators = OSL_max(*nb_iterators, local_nb_iterators); |
| *nb_scattdims = OSL_max(*nb_scattdims, local_nb_scattdims); |
| *nb_localdims = OSL_max(*nb_localdims, local_nb_localdims); |
| *array_id = OSL_max(*array_id, local_array_id); |
| relation = relation->next; |
| } |
| } |
| |
| |
| /** |
| * osl_relation_extend_output function: |
| * this function extends the number of output dimensions of a given relation. It |
| * returns a copy of the input relation with a number of output dimensions |
| * extended to "dim" for all its union components. The new output dimensions |
| * are simply set equal to 0. The extended number of dimensions must be higher |
| * than or equal to the original one (an error will be raised otherwise). |
| * \param[in] relation The input relation to extend. |
| * \param[in] dim The number of output dimension to reach. |
| * \return A new relation: "relation" extended to "dim" output dims. |
| */ |
| osl_relation_p osl_relation_extend_output(osl_relation_p relation, int dim) { |
| int i, j; |
| int first = 1; |
| int offset; |
| osl_relation_p extended = NULL, node, previous = NULL; |
| |
| while (relation != NULL) { |
| if (relation->nb_output_dims > dim) |
| OSL_error("Number of output dims is greater than required extension"); |
| offset = dim - relation->nb_output_dims; |
| |
| node = osl_relation_pmalloc(relation->precision, |
| relation->nb_rows + offset, |
| relation->nb_columns + offset); |
| |
| node->type = relation->type; |
| node->nb_output_dims = OSL_max(relation->nb_output_dims, dim); |
| node->nb_input_dims = relation->nb_input_dims; |
| node->nb_local_dims = relation->nb_local_dims; |
| node->nb_parameters = relation->nb_parameters; |
| |
| // Copy of the original relation with some 0 columns for the new dimensions |
| // Note that we use the fact that the matrix is initialized with zeros. |
| for (i = 0; i < relation->nb_rows; i++) { |
| for (j = 0; j <= relation->nb_output_dims; j++) |
| osl_int_assign(relation->precision, node->m[i], j, relation->m[i], j); |
| |
| for (j = relation->nb_output_dims + offset + 1; |
| j < relation->nb_columns + offset; j++) |
| osl_int_assign(relation->precision, |
| node->m[i], j, relation->m[i], j - offset); |
| } |
| |
| // New rows dedicated to the new dimensions |
| for (i = relation->nb_rows; i < relation->nb_rows + offset; i++) { |
| for (j = 0; j < relation->nb_columns + offset; j++) { |
| if ((i - relation->nb_rows) == (j - relation->nb_output_dims - 1)) |
| osl_int_set_si(relation->precision, node->m[i], j, -1); |
| } |
| } |
| |
| if (first) { |
| first = 0; |
| extended = node; |
| previous = node; |
| } |
| else { |
| previous->next = node; |
| previous = previous->next; |
| } |
| |
| relation = relation->next; |
| } |
| |
| return extended; |
| } |
| |