/** * osl_util_read_string function: * reads a string on the input 'file' or the input string 'str' depending on * which one is not NULL (exactly one of them must not be NULL). * \param[in] file The file where to read a string (if not NULL). * \param[in,out] str The string where to read a string (if not NULL). This * pointer is updated to reflect the read and points * after the string in the input string. * \return The string that has been read. */ char * osl_util_read_string(FILE * file, char ** str) { char s[OSL_MAX_STRING], * start; char * res; int i = 0; if ((file != NULL && str != NULL) || (file == NULL && str == NULL)) OSL_error("one and only one of the two parameters can be non-NULL"); OSL_malloc(res, char *, OSL_MAX_STRING * sizeof(char)); if (file != NULL) { // Parse from a file. start = osl_util_skip_blank_and_comments(file, s); if (sscanf(start, " %s", res) != 1) OSL_error("a string was expected"); } else { // Parse from a string. // Skip blank/commented lines. osl_util_sskip_blank_and_comments(str); // Build the chain to analyze. while (**str && !isspace(**str) && **str != '\n' && **str != '#') s[i++] = *((*str)++); s[i] = '\0'; if (sscanf(s, "%s", res) != 1) OSL_error("a string was expected"); } OSL_realloc(res, char *, strlen(res) + 1); return res; }
/** * osl_scop_check_compatible_scoplib function: * This function checks that a scop is "well formed". It returns 0 if the * check failed or 1 if no problem has been detected. * \param scop The scop we want to check. * \return 0 if the integrity check fails, 1 otherwise. */ int osl_scop_check_compatible_scoplib(osl_scop_p scop) { if (!osl_scop_integrity_check(scop)) return 0; if (scop->next != NULL) return 0; if (scop == NULL || scop->statement == NULL) return 1; osl_relation_p domain; osl_statement_p statement; osl_relation_p scattering; int precision = scop->statement->scattering->precision; int i, j; statement = scop->statement; while (statement != NULL) { scattering = statement->scattering; if (scattering->nb_local_dims != 0) { OSL_error("Local dims in scattering matrix"); return 0; } domain = statement->domain; while (domain != NULL) { if (domain->nb_local_dims != 0) { OSL_error("Local dims in domain matrix"); return 0; } domain = domain->next; } // Check if there is only the -Identity in the output_dims // and the lines MUST be in the right order for (i = 0 ; i < scattering->nb_rows ; i++) { for (j = 0 ; j < scattering->nb_output_dims ; j++) { if (i == j) { // -1 if (!osl_int_mone(precision, scattering->m[i][j+1])) { OSL_error("Wrong -Identity"); return 0; } } else { // 0 if (!osl_int_zero(precision, scattering->m[i][j+1])) { OSL_error("Wrong -Identity"); return 0; } } } } statement = statement->next; } return 1; }
/** * osl_util_read_int internal function: * reads a tag (the form of a tag with name "name" is \<name\>) on the input * 'file' or the input string 'str' depending on which one is not NULL (exactly * one of them must not be NULL). It returns the name of the tag (thus without * the < and > as a string. Note that in the case of an ending tag, e.g., * \</foo\>, the slash is returned as a part of the name, e.g., /foo. If no * tag is found the function returns NULL. * \param[in] file The file where to read a tag (if not NULL). * \param[in,out] str The string where to read a tag (if not NULL). This * pointer is updated to reflect the read and points * after the tag in the input string. * \return The tag name that has been read. */ char * osl_util_read_tag(FILE * file, char ** str) { char s[OSL_MAX_STRING], * start; char * res; int i = 0; if ((file != NULL && str != NULL) || (file == NULL && str == NULL)) OSL_error("one and only one of the two parameters can be non-NULL"); // Skip blank/commented lines. if (file != NULL) { start = osl_util_skip_blank_and_comments(file, s); str = &start; } else { osl_util_sskip_blank_and_comments(str); } // If the end of the input has been reached, return NULL. if (((file != NULL) && (feof(file))) || ((str != NULL) && (**str == '\0'))) return NULL; // Pass the starting '<'. if (**str != '<') OSL_error("a \"<\" to start a tag was expected"); (*str)++; // Read the tag. OSL_malloc(res, char *, (OSL_MAX_STRING + 1) * sizeof(char)); res[OSL_MAX_STRING] = '\0'; while (**str && **str != '>') { if (((**str >= 'A') && (**str <= 'Z')) || ((**str >= 'a') && (**str <= 'z')) || ((**str == '/') && (i == 0)) || (**str == '_')) { res[i++] = *((*str)++); res[i] = '\0'; } else { OSL_error("illegal character in the tag name"); } } // Check we actually end up with a '>' and pass it. if (**str != '>') OSL_error("a \">\" to end a tag was expected"); (*str)++; return res; }
/** * osl_textual_sprint function: * this function prints the content of an osl_textual_t structure * (*textual) into a string (returned) in the OpenScop textual format. * \param[in] textual The textual structure to be printed. * \return A string containing the OpenScop dump of the textual structure. */ char * osl_textual_sprint(osl_textual_p textual) { char * string = NULL; if ((textual != NULL) && (textual->textual != NULL)) { if (strlen(textual->textual) > OSL_MAX_STRING) OSL_error("textual too long"); string = strdup(textual->textual); if (string == NULL) OSL_error("memory overflow"); } return string; }
/** * osl_util_read_uptoflag function: * this function reads a string up to a given flag (the flag is read) * on the input 'file' or the input string 'str' depending on which one is * not NULL (exactly one of them must not be NULL) and returns that string * without the flag. It returns NULL if the flag is not found. * \param[in] file The file where to read up to flag (if not NULL). * \param[in,out] str The string where to read up to flag (if not NULL). This * pointer is updated to reflect the read and points * after the flag in the input string. * \param[in] flag The flag which, when reached, stops the reading. * \return The string that has been read. */ char * osl_util_read_uptoflag(FILE * file, char ** str, char * flag) { int high_water_mark = OSL_MAX_STRING; int nb_chars = 0; int lenflag = strlen(flag), lenstr; int flag_found = 0; char * res; if ((file != NULL && str != NULL) || (file == NULL && str == NULL)) OSL_error("one and only one of the two parameters can be non-NULL"); OSL_malloc(res, char *, high_water_mark * sizeof(char)); // Copy everything to the res string. if (str != NULL) lenstr = strlen(*str); while (((str != NULL) && (nb_chars != lenstr)) || ((file != NULL) && (!feof(file)))) { res[nb_chars++] = (str != NULL) ? *((*str)++) : fgetc(file); if ((nb_chars >= lenflag) && (!strncmp(&res[nb_chars - lenflag], flag, lenflag))) { flag_found = 1; break; } if (nb_chars >= high_water_mark) { high_water_mark += high_water_mark; OSL_realloc(res, char *, high_water_mark * sizeof(char)); } }
/** * osl_util_read_line function: * reads a line on the input 'file' or the input string 'str' depending on * which one is not NULL (exactly one of them must not be NULL). A line * is defined as the array of characters before the comment tag or the end of * line (it may include spaces). * \param[in] file The file where to read a line (if not NULL). * \param[in,out] str The string where to read a line (if not NULL). This * pointer is updated to reflect the read and points * after the line in the input string. * \return The line that has been read. */ char * osl_util_read_line(FILE * file, char ** str) { char s[OSL_MAX_STRING], * start; char * res; int i = 0; if ((file != NULL && str != NULL) || (file == NULL && str == NULL)) OSL_error("one and only one of the two parameters can be non-NULL"); OSL_malloc(res, char *, OSL_MAX_STRING * sizeof(char)); if (file != NULL) { // Parse from a file. start = osl_util_skip_blank_and_comments(file, s); while (*start && *start != '\n' && *start != '#' && i < OSL_MAX_STRING) res[i++] = *start++; } else { // Parse from a string. osl_util_sskip_blank_and_comments(str); while (**str && **str != '\n' && **str != '#' && i < OSL_MAX_STRING) res[i++] = *((*str)++); } res[i] = '\0'; OSL_realloc(res, char *, strlen(res) + 1); return res; }
/** * @brief Fusion two osl_body into a third one. * The two osl_body must have the same iterators or the program will fail. * * @param body1 The first osl_body. * @param body2 The second osl_body. * * @return An osl_body with the same iteratar as the parameters, but with * their "code" fusionned. */ struct osl_body * substrate_osl_body_fusion( struct osl_body * body1, struct osl_body * body2) { struct osl_body * res = NULL; size_t body1_size = 0, body2_size = 0; body1_size = osl_strings_size(body1->iterators); body2_size = osl_strings_size(body2->iterators); res = osl_body_malloc(); if((osl_strings_equal(body1->iterators, body2->iterators)) || (body1_size==0) || (body2_size==0)) { res->iterators = osl_strings_clone(body1->iterators); substrate_osl_strings_concat( &res->expression, body1->expression, body2->expression); } else { //TODO Maybe fuse when iterators don't match ? (I'm not really sure). OSL_error("Can't fusion body"); } return res; }
static void printf_in_buf(char **buf, size_t *buf_size, size_t *offset, const char *fmt, ...) { va_list va; va_start(va, fmt); do { int printed = vsnprintf((*buf) + *offset, *buf_size - *offset, fmt, va); if (printed < 0) OSL_error( "snprintf encountered an error while writing inside a local buffer"); size_t retval = (size_t)printed; if (retval < *buf_size - *offset) { *offset += retval; break; } OSL_realloc(*buf, char *, *buf_size * 2); *buf_size *= 2; } while (1); va_end(va); }
/** * osl_scop_pread function ("precision read"): * this function reads a list of scop structures from a file (possibly stdin) * complying to the OpenScop textual format and returns a pointer to this * scop list. If some relation properties (number of input/output/local * dimensions and number of parameters) are undefined, it will define them * according to the available information. * \param[in] file The file where the scop has to be read. * \param[in] registry The list of known interfaces (others are ignored). * \param[in] precision The precision of the relation elements. * \return A pointer to the scop structure that has been read. */ osl_scop_p osl_scop_pread(FILE * file, osl_interface_p registry, int precision) { osl_scop_p list = NULL, current = NULL, scop; osl_statement_p stmt = NULL; osl_statement_p prev = NULL; osl_strings_p language; int nb_statements; char * tmp; int first = 1; int i; if (file == NULL) return NULL; while(1) { // // I. START TAG // tmp = osl_util_read_uptotag(file, OSL_TAG_START_SCOP); if (tmp == NULL) { OSL_debug("no more scop in the file"); break; } else { free(tmp); } scop = osl_scop_malloc(); scop->registry = osl_interface_clone(registry); // // II. CONTEXT PART // // Read the language. language = osl_strings_read(file); if (osl_strings_size(language) == 0) OSL_error("no language (backend) specified"); if (osl_strings_size(language) > 1) OSL_warning("uninterpreted information (after language)"); if (language != NULL) { scop->language = strdup(language->string[0]); osl_strings_free(language); } // Read the context domain. scop->context = osl_relation_pread(file, precision); // Read the parameters. if (osl_util_read_int(file, NULL) > 0) scop->parameters = osl_generic_read_one(file, scop->registry); // // III. STATEMENT PART // // Read the number of statements. nb_statements = osl_util_read_int(file, NULL); for (i = 0; i < nb_statements; i++) { // Read each statement. stmt = osl_statement_pread(file, scop->registry, precision); if (scop->statement == NULL) scop->statement = stmt; else prev->next = stmt; prev = stmt; } // // IV. EXTENSION PART (TO THE END TAG) // // Read up the end tag (if any), and store extensions. scop->extension = osl_generic_read(file, scop->registry); // Add the new scop to the list. if (first) { list = scop; first = 0; } else { current->next = scop; } current = scop; } if (!osl_scop_integrity_check(list)) OSL_warning("scop integrity check failed"); return list; }
/** * osl_scop_print_scoplib function: * this function prints the content of an osl_scop_t structure (*scop) * into a file (file, possibly stdout) in the ScopLib textual format. * \param file The file where the information has to be printed. * \param scop The scop structure whose information has to be printed. */ void osl_scop_print_scoplib(FILE * file, osl_scop_p scop) { int parameters_backedup = 0; int arrays_backedup = 0; osl_strings_p parameters_backup = NULL; osl_strings_p arrays_backup = NULL; osl_names_p names; osl_arrays_p arrays; if (scop == NULL) { fprintf(file, "# NULL scop\n"); return; } else { fprintf(file, "# [File generated by the OpenScop Library %s]\n" "# [SCoPLib format]\n", OSL_RELEASE); } if (osl_scop_check_compatible_scoplib(scop) == 0) { OSL_error("SCoP integrity check failed. Something may go wrong."); exit(1); } // Generate the names for the various dimensions. names = osl_scop_names(scop); while (scop != NULL) { // If possible, replace parameter names with scop parameter names. if (osl_generic_has_URI(scop->parameters, OSL_URI_STRINGS)) { parameters_backedup = 1; parameters_backup = names->parameters; names->parameters = scop->parameters->data; } // If possible, replace array names with arrays extension names. arrays = osl_generic_lookup(scop->extension, OSL_URI_ARRAYS); if (arrays != NULL) { arrays_backedup = 1; arrays_backup = names->arrays; names->arrays = osl_arrays_to_strings(arrays); } fprintf(file, "\nSCoP\n\n"); fprintf(file, "# =============================================== " "Global\n"); fprintf(file, "# Language\n"); fprintf(file, "%s\n\n", scop->language); fprintf(file, "# Context\n"); osl_relation_pprint_scoplib(file, scop->context, names, 0, 0); fprintf(file, "\n"); osl_util_print_provided(file, osl_generic_has_URI(scop->parameters, OSL_URI_STRINGS), "Parameters are"); if (scop->parameters) { fprintf(file, "# Parameter names\n"); osl_strings_print(file, scop->parameters->data); } fprintf(file, "\n# Number of statements\n"); fprintf(file, "%d\n\n",osl_statement_number(scop->statement)); osl_statement_pprint_scoplib(file, scop->statement, names); if (scop->extension) { fprintf(file, "# =============================================== " "Options\n"); osl_generic_print_options_scoplib(file, scop->extension); } // If necessary, switch back parameter names. if (parameters_backedup) { parameters_backedup = 0; names->parameters = parameters_backup; } // If necessary, switch back array names. if (arrays_backedup) { arrays_backedup = 0; osl_strings_free(names->arrays); names->arrays = arrays_backup; } scop = scop->next; } osl_names_free(names); }
/** * @brief Allocate and construct the vectorization profile by analyzing the * osl_statement. * * @param[in] scop The scop of the analyzed osl_statement. * @param[in] statement The analyzed osl_statement. * * @return A constructed vectorization profile. */ struct substrate_vectorization_profile substrate_vectorization_profile_constructor( struct osl_scop * scop, struct osl_statement * statement) { struct substrate_vectorization_profile res = {NULL,0}; unsigned int i = 0; struct osl_relation_list *relation_list_cursor = NULL; struct osl_relation *relation_cursor = NULL; unsigned col = 0; unsigned line = 0; osl_int_t val; unsigned common_iterators_vectorized_dim[statement->domain->nb_output_dims]; int precision = statement->domain->precision; struct candl_options *candl_options = NULL; struct osl_dependence *candl_dep = NULL, *candl_dep_cursor = NULL; struct osl_scop *candl_scop = NULL; //Preparing and allocating the vectorization structure. res.size = statement->domain->nb_output_dims; res.vectorizable_loops = (bool*) malloc(res.size * sizeof(bool)); memset(res.vectorizable_loops,false,res.size); //For every possible iterator, we select only those that are used in the //vectorized output dimension (the first if column major, last if row major). // //If an access relation of the statement doesn't used the i^th iterator, //then this iterator can be used to vectorize the statement. for(i=0 ; i<res.size ; i++) { common_iterators_vectorized_dim[i] = true; relation_list_cursor = statement->access; while((relation_list_cursor != NULL) && (common_iterators_vectorized_dim[i])) { relation_cursor = relation_list_cursor->elt; while((relation_cursor != NULL) && (common_iterators_vectorized_dim[i])) { col = g_substrate_options.row_major ? relation_cursor->nb_output_dims-1 : 1; line = candl_util_relation_get_line(relation_cursor, col); val = relation_cursor->m[line][1 + relation_cursor->nb_output_dims + i]; common_iterators_vectorized_dim[i] = !osl_int_zero(precision, val); relation_cursor = relation_cursor->next; } relation_list_cursor = relation_list_cursor->next; } } //Creating a dummy scop with only the current analyzed statement for candl. //Also reset the beta depth of the statement, because it's supposed to be //alone now. candl_scop = substrate_osl_scop_nclone_except_statement(scop, 1); candl_scop->statement = osl_statement_nclone(statement,1); substrate_reset_beta_depth(candl_scop->statement); //Initiating candl, then using it to generate the dependences, //and finally extracting them to use later. candl_options = candl_options_malloc(); candl_scop_usr_init(candl_scop); candl_dependence_add_extension(candl_scop, candl_options); candl_dep = osl_generic_lookup(candl_scop->extension, OSL_URI_DEPENDENCE); for(i=0 ; i<res.size; i++) { if( common_iterators_vectorized_dim[i] == false ) continue; res.vectorizable_loops[i] = true; candl_dep_cursor = candl_dep; while( (candl_dep_cursor != NULL) && (res.vectorizable_loops[i]) ) { if(candl_dependence_is_loop_carried(candl_dep_cursor, i)) { switch(candl_dep_cursor->type) { //If the dependence is RaR (which should not be encountered because //we only analyze the self-dependence of the statement) or WaR, //then we don't care : these types doesn't prevent vectorization. case OSL_DEPENDENCE_RAR : case OSL_DEPENDENCE_WAR : break; //If a dependence is RaW or WaW, the i^th cannot be vectorized //because these type of dependence prevent it. case OSL_DEPENDENCE_RAW : case OSL_DEPENDENCE_WAW : res.vectorizable_loops[i] = false; break; default : OSL_error("In function substrate_vectorization_profile_constructor :" " an osl_dependence without a type has been encountered"); break; } } candl_dep_cursor = candl_dep_cursor->next; } } candl_options_free(candl_options); candl_scop_usr_cleanup(candl_scop); osl_scop_free(candl_scop); return res; }