/** * clay_util_scop_export_body function: * Convert each extbody to a body structure * \param[in] scop */ void clay_util_scop_export_body(osl_scop_p scop) { if (scop == NULL) return; osl_statement_p stmt = scop->statement; osl_extbody_p ebody = NULL; osl_body_p body = NULL; osl_generic_p gen = NULL; while (stmt) { ebody = osl_generic_lookup(stmt->extension, OSL_URI_EXTBODY); if (ebody!=NULL) { body = osl_generic_lookup(stmt->extension, OSL_URI_BODY); if (body) { osl_generic_remove(&stmt->extension, OSL_URI_BODY); } body = osl_body_clone(ebody->body); gen = osl_generic_shell(body, osl_body_interface()); osl_generic_add(&stmt->extension, gen); osl_generic_remove(&stmt->extension, OSL_URI_EXTBODY); ebody=NULL; body=NULL; } stmt = stmt->next; } }
/** * clay_util_statement_find_iterator function: * Return the index if iter is found in the original iterators list. * \param[in] scop * \param[in] iter name of the original iterator we want to search * \return */ int clay_util_statement_find_iterator(osl_statement_p statement, char *iter) { osl_body_p body; osl_extbody_p extbody = NULL; extbody = osl_generic_lookup(statement->extension, OSL_URI_EXTBODY); if (extbody) body = extbody->body; else body = osl_generic_lookup(statement->extension, OSL_URI_BODY); char **ptr = body->iterators->string; int i = 0; while (*ptr != NULL) { if (strcmp(*ptr, iter) == 0) return i; ptr++; i++; } return -1; }
/** * clan_scop_generate_scatnames function: * this function generates a scatnames extension for the scop passed as * an argument. Since Clan use a "2d+1" scattering strategy, the * scattering dimension names are generated by reusing the original * iterator names of the deepest statement and by inserting between those * names some beta vector elements (the Xth beta element is called bX). * \param[in,out] scop The scop to add a scatnames extension to. */ void clan_scop_generate_scatnames(osl_scop_p scop) { osl_statement_p current, deepest; osl_scatnames_p scatnames; osl_strings_p iterators = NULL; osl_strings_p names = NULL; osl_generic_p extension; osl_body_p body = NULL; char buffer[CLAN_MAX_STRING]; int max_depth = -1; int i; // Find the deepest statement to reuse its original iterators. current = scop->statement; while (current != NULL) { if (current->domain->nb_output_dims > max_depth) { max_depth = current->domain->nb_output_dims; deepest = current; body = (osl_body_p)osl_generic_lookup(deepest->extension, OSL_URI_BODY); if (body) iterators = body->iterators; } current = current->next; } // It there are no scattering dimension, do nothing. if (max_depth <= 0) return; // Create the NULL-terminated list of scattering dimension names. names = osl_strings_malloc(); for (i = 0; i < max_depth; i++) { sprintf(buffer, "b%d", i); osl_strings_add(names, buffer); osl_strings_add(names, iterators->string[i]); } sprintf(buffer, "b%d", max_depth); osl_strings_add(names, buffer); // Build the scatnames extension. scatnames = osl_scatnames_malloc(); scatnames->names = names; // Build the generic extension and insert it to the extension list. extension = osl_generic_malloc(); extension->interface = osl_scatnames_interface(); extension->data = scatnames; osl_generic_add(&scop->extension, extension); }
/** * clan_scop_update_coordinates function: * this function replaces the values in the coordinates extension of * each SCoP of the list 'scop' by those in the 'coordinates' array. * The rows of the coordinates array have the following meaning: * 0: line start, 1: line end, 2: column start, 3: column end, * 4: boolean set to 1 for an auto-discovered scop, 0 for user-scop. * The ith column of the coordinates array describes the coordinates * of the ith SCoP. * \param[in,out] scop SCoP list to update the coordinates. * \param[in] coordinates Array of coordinates. */ void clan_scop_update_coordinates(osl_scop_p scop, int coordinates[5][CLAN_MAX_SCOPS]) { int i = 0; osl_coordinates_p old; while (scop != NULL) { if (i > CLAN_MAX_SCOPS) CLAN_error("too many SCoPs! Change CLAN_MAX_SCOPS and recompile Clan."); old = osl_generic_lookup(scop->extension, OSL_URI_COORDINATES); if (old == NULL) CLAN_error("coordinates extension not present"); // When columns are at 0, it means the scop has not been autodetected. // - The line starts at +1 (after the pragma scop) if no autodetection, // - The column stops at -1 (previous read char) if autodetection. old->line_start = coordinates[0][i] + ((coordinates[2][i] == 0)? 1 : 0); old->line_end = coordinates[1][i]; old->column_start = coordinates[2][i]; old->column_end = coordinates[3][i] - ((coordinates[3][i] > 0)? 1 : 0); i++; scop = scop->next; } }
/** * osl_scop_print function: * this function prints the content of an osl_scop_t structure (*scop) * into a file (file, possibly stdout) in the OpenScop 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(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", OSL_RELEASE); } if (osl_scop_integrity_check(scop) == 0) OSL_warning("OpenScop integrity check failed. Something may go wrong."); // 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, "\n"OSL_TAG_START_SCOP"\n\n"); fprintf(file, "# =============================================== " "Global\n"); fprintf(file, "# Language\n"); fprintf(file, "%s\n\n", scop->language); fprintf(file, "# Context\n"); osl_relation_pprint(file, scop->context, names); fprintf(file, "\n"); osl_util_print_provided(file, osl_generic_has_URI(scop->parameters, OSL_URI_STRINGS), "Parameters are"); osl_generic_print(file, scop->parameters); fprintf(file, "\n# Number of statements\n"); fprintf(file, "%d\n\n",osl_statement_number(scop->statement)); osl_statement_pprint(file, scop->statement, names); if (scop->extension) { fprintf(file, "# =============================================== " "Extensions\n"); osl_generic_print(file, scop->extension); } fprintf(file, "\n"OSL_TAG_END_SCOP"\n\n"); // 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); }
/** * clay_util_foreach_access function: * Execute func on each access which corresponds to access_name * \param[in,out] scop * \param[in] beta * \param[in] access_name The id to search * \param[in] func The function to execute for each access * The function takes an osl_relation_list_p in * parameter (the elt can be modified) and must * return a define error or CLAY_SUCCESS * \param[in] args args of `func' * \param[in] regenerate_body If 1: after each call to func, * clay_util_body_regenerate_access is also called * \return Return a define error or CLAY_SUCCESS */ int clay_util_foreach_access(osl_scop_p scop, clay_array_p beta, unsigned int access_name, int (*func)(osl_relation_list_p, void*), void *args, int regenerate_body) { osl_statement_p stmt = scop->statement; osl_relation_list_p access; osl_relation_p a; osl_extbody_p ebody = NULL; osl_body_p body = NULL; osl_generic_p gen= NULL; int count_access; int found = 0; int ret; // TODO : global vars ? osl_arrays_p arrays; osl_scatnames_p scatnames; osl_strings_p params; arrays = osl_generic_lookup(scop->extension, OSL_URI_ARRAYS); scatnames = osl_generic_lookup(scop->extension, OSL_URI_SCATNAMES); params = osl_generic_lookup(scop->parameters, OSL_URI_STRINGS); if (!arrays || !scatnames || !params) CLAY_warning("no arrays or scatnames extension"); stmt = clay_beta_find(scop->statement, beta); if (!stmt) return CLAY_ERROR_BETA_NOT_FOUND; // for each access in the beta, we search the access_name while (stmt != NULL) { if (clay_beta_check(stmt, beta)) { access = stmt->access; count_access = 0; while (access) { a = access->elt; if (osl_relation_get_array_id(a) == access_name) { found = 1; ebody = osl_generic_lookup(stmt->extension, OSL_URI_EXTBODY); if (ebody==NULL) { CLAY_error("extbody uri not found on this statement"); fprintf(stderr, "%s\n", ebody->body->expression->string[0]); } // call the function ret = (*func)(access, args); if (ret != CLAY_SUCCESS) { fprintf(stderr, "%s\n", ebody->body->expression->string[0]); return ret; } // re-generate the body if (regenerate_body) { clay_util_body_regenerate_access( ebody, access->elt, count_access, arrays, scatnames, params); //synchronize extbody with body body = osl_generic_lookup(stmt->extension, OSL_URI_BODY); if (body) { osl_generic_remove(&stmt->extension, OSL_URI_BODY); body = osl_body_clone(ebody->body); gen = osl_generic_shell(body, osl_body_interface()); osl_generic_add(&stmt->extension, gen); } } } ebody = NULL; body = NULL; access = access->next; count_access++; } } stmt = stmt->next; } if (!found) fprintf(stderr,"[Clay] Warning: access number %d not found\n", access_name); return CLAY_SUCCESS; }
/** * clan_scop_insert_pragmas function: * inserts "#pragma scop" and "#pragma endscop" in a source file * around the SCoPs related in the input SCoP list that have no * surrounding pragmas in the file. * \param[in] scop The list of SCoPS. * \param[in] filename Name of the file where to insert pragmas. * \param[in] test 0 to insert, 1 to leave the result in the * CLAN_AUTOPRAGMA_FILE temporary file. */ void clan_scop_insert_pragmas(osl_scop_p scop, char* filename, int test) { int i, j, n = 0; int infos[5][CLAN_MAX_SCOPS]; int tmp[5]; osl_coordinates_p coordinates; FILE* input, *output; size_t size; char buffer[BUFSIZ]; // Get coordinate information from the list of SCoPS. while (scop != NULL) { coordinates = osl_generic_lookup(scop->extension, OSL_URI_COORDINATES); infos[0][n] = coordinates->line_start; infos[1][n] = coordinates->line_end; infos[2][n] = coordinates->column_start; infos[3][n] = coordinates->column_end + 1; infos[4][n] = clan_scop_no_pragma(filename, coordinates->line_start); n++; scop = scop->next; } // Dirty and inefficient bubble sort to ensure the SCoP ordering is correct // (this is ensured in Clan, but not if it is called from outside...). for (i = n - 2; i >= 0; i--) { for (j = 0; j <= i; j++) { if (infos[0][j] > infos[0][j+1]) { tmp[0]=infos[0][j]; infos[0][j]=infos[0][j+1]; infos[0][j+1]=tmp[0]; tmp[1]=infos[1][j]; infos[1][j]=infos[1][j+1]; infos[1][j+1]=tmp[1]; tmp[2]=infos[2][j]; infos[2][j]=infos[2][j+1]; infos[2][j+1]=tmp[2]; tmp[3]=infos[3][j]; infos[3][j]=infos[3][j+1]; infos[3][j+1]=tmp[3]; tmp[4]=infos[4][j]; infos[4][j]=infos[4][j+1]; infos[4][j+1]=tmp[4]; } } } // Quick check that there is no scop interleaving. for (i = 0; i < n - 1; i++) if (infos[1][i] > infos[0][i+1]) CLAN_error("SCoP interleaving"); // Generate the temporary file with the pragma inserted. if (!(input = fopen(filename, "r"))) CLAN_error("unable to read the input file"); clan_scop_print_autopragma(input, n, infos); fclose(input); // Replace the original file, or keep the temporary file. if (!test) { if (!(input = fopen(CLAN_AUTOPRAGMA_FILE, "rb"))) CLAN_error("unable to read the temporary file"); if (!(output = fopen(filename, "wb"))) CLAN_error("unable to write the output file"); while ((size = fread(buffer, 1, BUFSIZ, input))) { fwrite(buffer, 1, size, output); } fclose(input); fclose(output); } }
/** * @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; }