/**-------------------------------------------------------------------** ** CLooG ** **-------------------------------------------------------------------** ** program.c ** **-------------------------------------------------------------------** ** First version: october 25th 2001 ** **-------------------------------------------------------------------**/ /****************************************************************************** * CLooG : the Chunky Loop Generator (experimental) * ****************************************************************************** * * * Copyright (C) 2001-2005 Cedric Bastoul * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or (at your option) any later version. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, * * Boston, MA 02110-1301 USA * * * * CLooG, the Chunky Loop Generator * * Written by Cedric Bastoul, Cedric.Bastoul@inria.fr * * * ******************************************************************************/ /* CAUTION: the english used for comments is probably the worst you ever read, * please feel free to correct and improve it ! */ # include # include #include # include # include # include # include # include # include "../include/cloog/cloog.h" #ifdef CLOOG_RUSAGE # include #endif #define ALLOC(type) (type*)malloc(sizeof(type)) #ifdef OSL_SUPPORT #include #include #endif /****************************************************************************** * Structure display function * ******************************************************************************/ /** * cloog_program_print function: * this function is a human-friendly way to display the CloogProgram data * structure, it shows all the different fields and includes an indentation * level (level) in order to work with others print_structure functions. * - July 1st 2005: first version based on the old cloog_program_print function. */ void cloog_program_print_structure(file, program, level) FILE * file ; CloogProgram * program ; int level ; { int i, j ; /* Go to the right level. */ for (i=0; ilanguage) ; /* A blank line. */ for (i=0; i<=level+1; i++) fprintf(file,"|\t") ; fprintf(file,"\n") ; /* Print the scattering dimension number. */ for (i=0; i<=level; i++) fprintf(file,"|\t") ; fprintf(file,"Scattering dimension number: %d\n",program->nb_scattdims) ; /* A blank line. */ for (i=0; i<=level+1; i++) fprintf(file,"|\t") ; fprintf(file,"\n") ; /* Print the scalar scattering dimension informations. */ for (i=0; i<=level; i++) fprintf(file,"|\t") ; if (program->scaldims != NULL) { fprintf(file,"Scalar dimensions:") ; for (i=0;inb_scattdims;i++) fprintf(file," %d:%d ",i,program->scaldims[i]) ; fprintf(file,"\n") ; } else fprintf(file,"No scalar scattering dimensions\n") ; /* A blank line. */ for (i=0; i<=level+1; i++) fprintf(file,"|\t") ; fprintf(file,"\n") ; /* Print the parameter and the iterator names. */ cloog_names_print_structure(file,program->names,level+1) ; /* A blank line. */ for (i=0; i<=level+1; i++) fprintf(file,"|\t") ; fprintf(file,"\n") ; /* Print the context. */ cloog_domain_print_structure(file, program->context, level+1, "Context"); /* Print the loop. */ cloog_loop_print_structure(file,program->loop,level+1) ; /* One more time something that is here only for a better look. */ for (j=0; j<2; j++) { for (i=0; i<=level; i++) fprintf(file,"|\t") ; fprintf(file,"\n") ; } } /** * cloog_program_dump_cloog function: * This function dumps a CloogProgram structure supposed to be completely * filled in a CLooG input file (foo possibly stdout) such as CLooG can * rebuild almost exactly the data structure from the input file. * * If the scattering is already applied, the scattering parameter is supposed to * be NULL. In this case the number of scattering functions is lost, since they * are included inside the iteration domains. This can only lead to a less * beautiful pretty printing. * * In case the scattering is not yet applied it can be passed to this function * and will be included in the CLooG input file dump. */ void cloog_program_dump_cloog(FILE * foo, CloogProgram * program, CloogScatteringList *scattering) { int i; CloogLoop * loop ; CloogScatteringList *tmp_scatt; fprintf(foo, "# CLooG -> CLooG\n" "# This is an automatic dump of a CLooG input file from a CloogProgram data\n" "# structure. WARNING: it is highly dangerous and MAY be correct ONLY if\n" "# - it has been dumped before loop generation.\n" "# - option -noscalars is used (it removes scalar dimensions otherwise)\n" "# - option -l is at least the original scattering dimension number\n" "# ASK THE AUTHOR IF YOU *NEED* SOMETHING MORE ROBUST\n") ; /* Language. */ if (program->language == 'c') fprintf(foo,"# Language: C\n") ; else fprintf(foo,"# Language: FORTRAN\n") ; fprintf(foo,"%c\n\n",program->language) ; /* Context. */ fprintf(foo, "# Context (%d parameter(s)):\n", program->names->nb_parameters); cloog_domain_print_constraints(foo, program->context, 0); fprintf(foo,"1 # Parameter name(s)\n") ; for (i=0;inames->nb_parameters;i++) fprintf(foo,"%s ",program->names->parameters[i]) ; /* Statement number. */ i = 0 ; loop = program->loop ; while (loop != NULL) { i++ ; loop = loop->next ; } fprintf(foo,"\n\n# Statement number:\n%d\n\n",i) ; /* Iteration domains. */ i = 1 ; loop = program->loop ; while (loop != NULL) { /* Name of the domain. */ fprintf(foo,"# Iteration domain of statement %d.\n",i) ; cloog_domain_print_constraints(foo, loop->domain, 1); fprintf(foo,"0 0 0 # For future options.\n\n") ; i++ ; loop = loop->next ; } fprintf(foo,"\n1 # Iterator name(s)\n") ; /* Scattering already applied? In this case print the scattering names as * additional iterator names. */ if (!scattering) for (i = 0; i < program->names->nb_scattering; i++) fprintf(foo, "%s ", program->names->scattering[i]); for (i=0;inames->nb_iterators;i++) fprintf(foo,"%s ",program->names->iterators[i]); fprintf(foo,"\n\n") ; /* Exit, if scattering is already applied. */ if (!scattering) { fprintf(foo, "# No scattering functions.\n0\n\n"); return; } /* Scattering relations. */ fprintf(foo, "# --------------------- SCATTERING --------------------\n"); i = 0; for (tmp_scatt = scattering; tmp_scatt; tmp_scatt = tmp_scatt->next) i++; fprintf(foo, "%d # Scattering functions", i); for (tmp_scatt = scattering; tmp_scatt; tmp_scatt = tmp_scatt->next) cloog_scattering_print_constraints(foo, tmp_scatt->scatt); fprintf(foo, "\n1 # Scattering dimension name(s)\n"); for (i = 0; i < program->names->nb_scattering; i++) fprintf(foo, "%s ", program->names->scattering[i]); } /** * cloog_program_print function: * This function prints the content of a CloogProgram structure (program) into a * file (file, possibly stdout). * - July 1st 2005: Now this very old function (probably as old as CLooG) is * only a frontend to cloog_program_print_structure, with a * quite better human-readable representation. */ void cloog_program_print(FILE * file, CloogProgram * program) { cloog_program_print_structure(file,program,0) ; } static void print_comment(FILE *file, CloogOptions *options, const char *fmt, ...) { va_list args; va_start(args, fmt); if (options->language == CLOOG_LANGUAGE_FORTRAN) { fprintf(file, "! "); vfprintf(file, fmt, args); fprintf(file, "\n"); } else { fprintf(file, "/* "); vfprintf(file, fmt, args); fprintf(file, " */\n"); } } static void print_macros(FILE *file) { fprintf(file, "/* Useful macros. */\n") ; fprintf(file, "#define floord(n,d) (((n)<0) ? -((-(n)+(d)-1)/(d)) : (n)/(d))\n"); fprintf(file, "#define ceild(n,d) (((n)<0) ? -((-(n))/(d)) : ((n)+(d)-1)/(d))\n"); fprintf(file, "#define max(x,y) ((x) > (y) ? (x) : (y))\n") ; fprintf(file, "#define min(x,y) ((x) < (y) ? (x) : (y))\n\n") ; } static void print_declarations(FILE *file, int n, char **names) { int i; fprintf(file, " int %s", names[0]); for (i = 1; i < n; i++) fprintf(file, ", %s", names[i]); fprintf(file, ";\n"); } static void print_iterator_declarations(FILE *file, CloogProgram *program, CloogOptions *options) { CloogNames *names = program->names; if (names->nb_scattering) { fprintf(file, " /* Scattering iterators. */\n"); print_declarations(file, names->nb_scattering, names->scattering); } if (names->nb_iterators) { fprintf(file, " /* Original iterators. */\n"); print_declarations(file, names->nb_iterators, names->iterators); } } static void print_callable_preamble(FILE *file, CloogProgram *program, CloogOptions *options) { int j; CloogBlockList *blocklist; CloogBlock *block; CloogStatement *statement; fprintf(file, "extern void hash(int);\n\n"); print_macros(file); for (blocklist = program->blocklist; blocklist; blocklist = blocklist->next) { block = blocklist->block; for (statement = block->statement; statement; statement = statement->next) { fprintf(file, "#define S%d(", statement->number); if (block->depth > 0) { fprintf(file, "%s", program->names->iterators[0]); for(j = 1; j < block->depth; j++) fprintf(file, ",%s", program->names->iterators[j]); } fprintf(file,") { hash(%d);", statement->number); for(j = 0; j < block->depth; j++) fprintf(file, " hash(%s);", program->names->iterators[j]); fprintf(file, " }\n"); } } fprintf(file, "\nvoid test("); if (program->names->nb_parameters > 0) { fprintf(file, "int %s", program->names->parameters[0]); for(j = 1; j < program->names->nb_parameters; j++) fprintf(file, ", int %s", program->names->parameters[j]); } fprintf(file, ")\n{\n"); print_iterator_declarations(file, program, options); } static void print_callable_postamble(FILE *file, CloogProgram *program) { fprintf(file, "}\n"); } /** * cloog_program_osl_pprint function: * this function pretty-prints the C or FORTRAN code generated from an * OpenScop specification by overwriting SCoP in a given code, if the * options -compilable or -callable are not set. The SCoP coordinates are * provided through the OpenScop "Coordinates" extension. It returns 1 if * it succeeds to find an OpenScop coordinates information * to pretty-print the generated code, 0 otherwise. * \param[in] file The output stream (possibly stdout). * \param[in] program The generated pseudo-AST to pretty-print. * \param[in] options CLooG options (contains the OpenSCop specification). * \return 1 on success to pretty-print at the place of a SCoP, 0 otherwise. */ int cloog_program_osl_pprint(FILE * file, CloogProgram * program, CloogOptions * options) { #ifdef OSL_SUPPORT int lines = 0; int read = 1; char c; osl_scop_p scop = options->scop; osl_coordinates_p coordinates; struct clast_stmt *root; FILE * original; if (scop && !options->compilable && !options->callable) { coordinates = osl_generic_lookup(scop->extension, OSL_URI_COORDINATES); if (coordinates) { original = fopen(coordinates->name, "r"); if (!original) { cloog_msg(options, CLOOG_WARNING, "unable to open the file specified in the SCoP " "coordinates\n"); return 0; } /* Print the macros the generated code may need. */ print_macros(file); /* Print what was before the SCoP in the original file. */ while ((lines < coordinates->start) && (read != EOF)) { read = fscanf(original, "%c", &c); if (read != EOF) { if (c == '\n') lines ++; fprintf(file, "%c", c); } } /* Generate the clast from the pseudo-AST then pretty-print it. */ root = cloog_clast_create(program, options); clast_pprint(file, root, coordinates->indent, options); cloog_clast_free(root); /* Print what was after the SCoP in the original file. */ while (read != EOF) { read = fscanf(original, "%c", &c); if (read != EOF) { if (lines >= coordinates->end - 1) fprintf(file, "%c", c); if (c == '\n') lines ++; } } fclose(original); return 1; } } #endif return 0; } /** * cloog_program_pprint function: * This function prints the content of a CloogProgram structure (program) into a * file (file, possibly stdout), in a C-like language. * - June 22nd 2005: Adaptation for GMP. */ void cloog_program_pprint(file, program, options) FILE * file ; CloogProgram * program ; CloogOptions * options ; { int i, j, indentation = 0; CloogStatement * statement ; CloogBlockList * blocklist ; CloogBlock * block ; struct clast_stmt *root; if (cloog_program_osl_pprint(file, program, options)) return; if (program->language == 'f') options->language = CLOOG_LANGUAGE_FORTRAN ; else options->language = CLOOG_LANGUAGE_C ; #ifdef CLOOG_RUSAGE print_comment(file, options, "Generated from %s by %s in %.2fs.", options->name, cloog_version(), options->time); #else print_comment(file, options, "Generated from %s by %s.", options->name, cloog_version()); #endif #ifdef CLOOG_MEMORY print_comment(file, options, "CLooG asked for %d KBytes.", options->memory); cloog_msg(CLOOG_INFO, "%.2fs and %dKB used for code generation.\n", options->time,options->memory); #endif /* If the option "compilable" is set, we provide the whole stuff to generate * a compilable code. This code just do nothing, but now the user can edit * the source and set the statement macros and parameters values. */ if (options->compilable && (program->language == 'c')) { /* The headers. */ fprintf(file,"/* DON'T FORGET TO USE -lm OPTION TO COMPILE. */\n\n") ; fprintf(file,"/* Useful headers. */\n") ; fprintf(file,"#include \n") ; fprintf(file,"#include \n") ; fprintf(file,"#include \n\n") ; /* The value of parameters. */ fprintf(file,"/* Parameter value. */\n") ; for (i = 1; i <= program->names->nb_parameters; i++) fprintf(file, "#define PARVAL%d %d\n", i, options->compilable); /* The macros. */ print_macros(file); /* The statement macros. */ fprintf(file,"/* Statement macros (please set). */\n") ; blocklist = program->blocklist ; while (blocklist != NULL) { block = blocklist->block ; statement = block->statement ; while (statement != NULL) { fprintf(file,"#define S%d(",statement->number) ; if (block->depth > 0) { fprintf(file,"%s",program->names->iterators[0]) ; for(j=1;jdepth;j++) fprintf(file,",%s",program->names->iterators[j]) ; } fprintf(file,") {total++;") ; if (block->depth > 0) { fprintf(file, " printf(\"S%d %%d", statement->number); for(j=1;jdepth;j++) fprintf(file, " %%d"); fprintf(file,"\\n\",%s",program->names->iterators[0]) ; for(j=1;jdepth;j++) fprintf(file,",%s",program->names->iterators[j]) ; fprintf(file,");") ; } fprintf(file,"}\n") ; statement = statement->next ; } blocklist = blocklist->next ; } /* The iterator and parameter declaration. */ fprintf(file,"\nint main() {\n") ; print_iterator_declarations(file, program, options); if (program->names->nb_parameters > 0) { fprintf(file," /* Parameters. */\n") ; fprintf(file, " int %s=PARVAL1",program->names->parameters[0]); for(i=2;i<=program->names->nb_parameters;i++) fprintf(file, ", %s=PARVAL%d", program->names->parameters[i-1], i); fprintf(file,";\n"); } fprintf(file," int total=0;\n"); fprintf(file,"\n") ; /* And we adapt the identation. */ indentation += 2 ; } else if (options->callable && program->language == 'c') { print_callable_preamble(file, program, options); indentation += 2; } root = cloog_clast_create(program, options); clast_pprint(file, root, indentation, options); cloog_clast_free(root); /* The end of the compilable code in case of 'compilable' option. */ if (options->compilable && (program->language == 'c')) { fprintf(file, "\n printf(\"Number of integral points: %%d.\\n\",total);"); fprintf(file, "\n return 0;\n}\n"); } else if (options->callable && program->language == 'c') print_callable_postamble(file, program); } /****************************************************************************** * Memory deallocation function * ******************************************************************************/ /** * cloog_program_free function: * This function frees the allocated memory for a CloogProgram structure. */ void cloog_program_free(CloogProgram * program) { cloog_names_free(program->names) ; cloog_loop_free(program->loop) ; cloog_domain_free(program->context) ; cloog_block_list_free(program->blocklist) ; if (program->scaldims != NULL) free(program->scaldims) ; free(program) ; } /****************************************************************************** * Reading function * ******************************************************************************/ static void cloog_program_construct_block_list(CloogProgram *p) { CloogLoop *loop; CloogBlockList **next = &p->blocklist; for (loop = p->loop; loop; loop = loop->next) { *next = cloog_block_list_alloc(loop->block); next = &(*next)->next; } } /** * Construct a CloogProgram structure from a given context and * union domain representing the iteration domains and scattering functions. */ CloogProgram *cloog_program_alloc(CloogDomain *context, CloogUnionDomain *ud, CloogOptions *options) { int i; char prefix[] = "c"; CloogScatteringList * scatteringl; CloogNames *n; CloogProgram * p ; /* Memory allocation for the CloogProgram structure. */ p = cloog_program_malloc() ; if (options->language == CLOOG_LANGUAGE_FORTRAN) p->language = 'f'; else p->language = 'c'; p->names = n = cloog_names_alloc(); /* We then read the context data. */ p->context = context; n->nb_parameters = ud->n_name[CLOOG_PARAM]; /* First part of the CloogNames structure: the parameter names. */ if (ud->name[CLOOG_PARAM]) { n->parameters = ud->name[CLOOG_PARAM]; ud->name[CLOOG_PARAM] = NULL; } else n->parameters = cloog_names_generate_items(n->nb_parameters, NULL, FIRST_PARAMETER); n->nb_iterators = ud->n_name[CLOOG_ITER]; if (ud->name[CLOOG_ITER]) { n->iterators = ud->name[CLOOG_ITER]; ud->name[CLOOG_ITER] = NULL; } else n->iterators = cloog_names_generate_items(n->nb_iterators, NULL, FIRST_ITERATOR); if (ud->domain) { CloogNamedDomainList *l; CloogLoop **next = &p->loop; CloogScatteringList **next_scat = &scatteringl; scatteringl = NULL; for (i = 0, l = ud->domain; l; ++i, l = l->next) { *next = cloog_loop_from_domain(options->state, l->domain, i); l->domain = NULL; (*next)->block->statement->name = l->name; (*next)->block->statement->usr = l->usr; l->name = NULL; if (l->scattering) { *next_scat = ALLOC(CloogScatteringList); (*next_scat)->scatt = l->scattering; l->scattering = NULL; (*next_scat)->next = NULL; next_scat = &(*next_scat)->next; } next = &(*next)->next; } if (scatteringl != NULL) { p->nb_scattdims = cloog_scattering_dimension(scatteringl->scatt, p->loop->domain); n->nb_scattering = p->nb_scattdims; if (ud->name[CLOOG_SCAT]) { n->scattering = ud->name[CLOOG_SCAT]; ud->name[CLOOG_SCAT] = NULL; } else n->scattering = cloog_names_generate_items(n->nb_scattering, prefix, -1); /* The boolean array for scalar dimensions is created and set to 0. */ p->scaldims = (int *)malloc(p->nb_scattdims*(sizeof(int))) ; if (p->scaldims == NULL) cloog_die("memory overflow.\n"); for (i=0;inb_scattdims;i++) p->scaldims[i] = 0 ; /* We try to find blocks in the input problem to reduce complexity. */ if (!options->noblocks) cloog_program_block(p, scatteringl, options); if (!options->noscalars) cloog_program_extract_scalars(p, scatteringl, options); cloog_program_scatter(p, scatteringl, options); cloog_scattering_list_free(scatteringl); if (!options->noblocks) p->loop = cloog_loop_block(p->loop, p->scaldims, p->nb_scattdims); } else { p->nb_scattdims = 0 ; p->scaldims = NULL ; } cloog_names_scalarize(p->names,p->nb_scattdims,p->scaldims) ; cloog_program_construct_block_list(p); } else { p->loop = NULL ; p->blocklist = NULL ; p->scaldims = NULL ; } cloog_union_domain_free(ud); return(p) ; } /** * cloog_program_read function: * This function read the informations to put in a CloogProgram structure from * a file (file, possibly stdin). It returns a pointer to a CloogProgram * structure containing the read informations. * - October 25th 2001: first version. * - September 9th 2002: - the big reading function is now split in several * functions (one per read data structure). * - adaptation to the new file format with naming. */ CloogProgram *cloog_program_read(FILE *file, CloogOptions *options) { CloogInput *input; CloogProgram *p; input = cloog_input_read(file, options); p = cloog_program_alloc(input->context, input->ud, options); free(input); return p; } /****************************************************************************** * Processing functions * ******************************************************************************/ /** * cloog_program_malloc function: * This function allocates the memory space for a CloogProgram structure and * sets its fields with default values. Then it returns a pointer to the * allocated space. * - November 21th 2005: first version. */ CloogProgram * cloog_program_malloc() { CloogProgram * program ; /* Memory allocation for the CloogProgram structure. */ program = (CloogProgram *)malloc(sizeof(CloogProgram)) ; if (program == NULL) cloog_die("memory overflow.\n"); /* We set the various fields with default values. */ program->language = 'c' ; program->nb_scattdims = 0 ; program->context = NULL ; program->loop = NULL ; program->names = NULL ; program->blocklist = NULL ; program->scaldims = NULL ; program->usr = NULL; return program ; } /** * cloog_program_generate function: * This function calls the Quillere algorithm for loop scanning. (see the * Quillere paper) and calls the loop simplification function. * - depth is the loop depth we want to optimize (guard free as possible), * the first loop depth is 1 and anegative value is the infinity depth. * - sep_level is the level number where we want to start loop separation. ** * - October 26th 2001: first version. * - April 19th 2005: some basic fixes and memory usage feature. * - April 29th 2005: (bug fix, bug found by DaeGon Kim) see case 2 below. */ CloogProgram * cloog_program_generate(program, options) CloogProgram * program ; CloogOptions * options ; { #ifdef CLOOG_RUSAGE float time; struct rusage start, end ; #endif CloogLoop * loop ; #ifdef CLOOG_MEMORY char status_path[MAX_STRING_VAL] ; FILE * status ; /* We initialize the memory need to 0. */ options->memory = 0 ; #endif if (options->override) { cloog_msg(options, CLOOG_WARNING, "you are using -override option, be aware that the " "generated\n code may be incorrect.\n") ; } else { /* Playing with options may be dangerous, here are two possible issues : * 1. Using -l option less than scattering dimension number may lead to * an illegal target code (since the scattering is not respected), if * it is the case, we set -l depth to the first acceptable value. */ if ((program->nb_scattdims > options->l) && (options->l >= 0)) { cloog_msg(options, CLOOG_WARNING, "-l depth is less than the scattering dimension number " "(the \n generated code may be incorrect), it has been " "automaticaly set\n to this value (use option -override " "to override).\n") ; options->l = program->nb_scattdims ; } /* 2. Using -f option greater than one while -l depth is greater than the * scattering dimension number may lead to iteration duplication (try * test/daegon_lu_osp.cloog with '-f 3' to test) because of the step 4b * of the cloog_loop_generate function, if it is the case, we set -l to * the first acceptable value. */ if (((options->f > 1) || (options->f < 0)) && ((options->l > program->nb_scattdims) || (options->l < 0))) { cloog_msg(options, CLOOG_WARNING, "-f depth is more than one, -l depth has been " "automaticaly set\n to the scattering dimension number " "(target code may have\n duplicated iterations), -l depth " "has been automaticaly set to\n this value (use option " "-override to override).\n") ; options->l = program->nb_scattdims ; } } #ifdef CLOOG_RUSAGE getrusage(RUSAGE_SELF, &start) ; #endif if (program->loop != NULL) { loop = program->loop ; /* Here we go ! */ loop = cloog_loop_generate(loop, program->context, 0, 0, program->scaldims, program->nb_scattdims, options); #ifdef CLOOG_MEMORY /* We read into the status file of the process how many memory it uses. */ sprintf(status_path,"/proc/%d/status",getpid()) ; status = fopen(status_path, "r") ; while (fscanf(status,"%s",status_path) && strcmp(status_path,"VmData:")!=0); fscanf(status,"%d",&(options->memory)) ; fclose(status) ; #endif if ((!options->nosimplify) && (program->loop != NULL)) loop = cloog_loop_simplify(loop, program->context, 0, program->nb_scattdims, options); program->loop = loop ; } #ifdef CLOOG_RUSAGE getrusage(RUSAGE_SELF, &end) ; /* We calculate the time spent in code generation. */ time = (end.ru_utime.tv_usec - start.ru_utime.tv_usec)/(float)(MEGA) ; time += (float)(end.ru_utime.tv_sec - start.ru_utime.tv_sec) ; options->time = time ; #endif return program ; } /** * cloog_program_block function: * this function gives a last chance to the lazy user to consider statement * blocks instead of some statement lists where the whole list may be * considered as a single statement from a code generation point of view. * For instance two statements with the same iteration domain and the same * scattering functions may be considered as a block. This function is lazy * and can only find very simple forms of trivial blocks (see * cloog_domain_lazy_block function for more details). The useless loops and * scattering functions are removed and freed while the statement list of * according blocks are filled. * - program is the whole program structure (befaore applying scattering), * - scattering is the list of scattering functions. ** * - April 30th 2005: first attempt. * - June 10-11th 2005: first working version. */ void cloog_program_block(CloogProgram *program, CloogScatteringList *scattering, CloogOptions *options) { int blocked_reference=0, blocked=0, nb_blocked=0 ; CloogLoop * reference, * start, * loop ; CloogScatteringList * scatt_reference, * scatt_loop, * scatt_start; if ((program->loop == NULL) || (program->loop->next == NULL)) return ; /* The process will use three variables for the linked list : * - 'start' is the starting point of a new block, * - 'reference' is the node of the block used for the block checking, * - 'loop' is the candidate to be inserted inside the block. * At the beginning of the process, the linked lists are as follow: * O------>O------>O------>O------>NULL * | | * start loop * reference */ reference = program->loop ; start = program->loop ; loop = reference->next ; scatt_reference = scattering ; scatt_start = scattering ; scatt_loop = scattering->next ; while (loop != NULL) { if (cloog_domain_lazy_equal(reference->domain,loop->domain) && cloog_scattering_lazy_block(scatt_reference->scatt, scatt_loop->scatt, scattering,program->nb_scattdims)) { /* If we find a block we update the links: * +---------------+ * | v * O O------>O------>O------>NULL * | | * start loop * reference */ blocked = 1 ; nb_blocked ++ ; cloog_block_merge(start->block,loop->block); /* merge frees loop->block */ loop->block = NULL ; start->next = loop->next ; scatt_start->next = scatt_loop->next ; } else { /* If we didn't find a block, the next start of a block is updated: * O------>O------>O------>O------>NULL * | | * reference start * loop */ blocked= 0 ; start = loop ; scatt_start = scatt_loop ; } /* If the reference node has been included into a block, we can free it. */ if (blocked_reference) { reference->next = NULL ; cloog_loop_free(reference) ; cloog_scattering_free(scatt_reference->scatt); free(scatt_reference) ; } /* The reference and the loop are now updated for the next try, the * starting position depends on the previous step. * O ? O------>O------>O------>NULL * | | * reference loop */ reference = loop ; loop = loop->next ; scatt_reference = scatt_loop ; scatt_loop = scatt_loop->next ; /* We mark the new reference as being blocked or not, if will be freed * during the next while loop execution. */ if (blocked) blocked_reference = 1 ; else blocked_reference = 0 ; } /* We free the last blocked reference if any (since in the while loop it was * freed during the next loop execution, it was not possible to free the * last one inside). */ if (blocked_reference) { reference->next = NULL ; cloog_loop_free(reference) ; cloog_scattering_free(scatt_reference->scatt); free(scatt_reference) ; } if (nb_blocked != 0) cloog_msg(options, CLOOG_INFO, "%d domains have been blocked.\n", nb_blocked); } /** * cloog_program_extract_scalars function: * this functions finds and removes the dimensions of the scattering functions * when they are scalar (i.e. of the shape "dim + scalar = 0") for all * scattering functions. The reason is that the processing of such dimensions * is trivial and do not need neither a row and a column in the matrix * representation of the domain (this will save memory) neither the full * Quillere processing (this will save time). The scalar dimensions data are * dispatched in the CloogProgram structure (the boolean vector scaldims will * say which original dimensions are scalar or not) and to the CloogBlock * structures (each one has a scaldims vector that contains the scalar values). * - June 14th 2005: first developments. * - June 30th 2005: first version. */ void cloog_program_extract_scalars(CloogProgram *program, CloogScatteringList *scattering, CloogOptions *options) { int i, j, scalar, current, nb_scaldims=0 ; CloogScatteringList *start; CloogScattering *old; CloogLoop *loop; CloogBlock * block ; start = scattering ; for (i=0;inb_scattdims;i++) { scalar = 1 ; scattering = start ; while (scattering != NULL) { if (!cloog_scattering_lazy_isscalar(scattering->scatt, i, NULL)) { scalar = 0 ; break ; } scattering = scattering->next ; } if (scalar) { nb_scaldims ++ ; program->scaldims[i] = 1 ; } } /* If there are no scalar dimensions, we can continue directly. */ if (!nb_scaldims) return ; /* Otherwise, in each block, we have to put the number of scalar dimensions, * and to allocate the memory for the scalar values. */ for (loop = program->loop; loop; loop = loop->next) { block = loop->block; block->nb_scaldims = nb_scaldims ; block->scaldims = (cloog_int_t *)malloc(nb_scaldims*sizeof(cloog_int_t)); for (i=0;iscaldims[i]); } /* Then we have to fill these scalar values, so we can erase those dimensions * from the scattering functions. It's easier to begin with the last one, * since there would be an offset otherwise (if we remove the i^th dimension, * then the next one is not the (i+1)^th but still the i^th...). */ current = nb_scaldims - 1 ; for (i=program->nb_scattdims-1;i>=0;i--) if (program->scaldims[i]) { scattering = start ; for (loop = program->loop; loop; loop = loop->next) { block = loop->block; if (!cloog_scattering_lazy_isscalar(scattering->scatt, i, &block->scaldims[current])) { /* We should have found a scalar value: if not, there is an error. */ cloog_die("dimension %d is not scalar as expected.\n", i); } scattering = scattering->next ; } scattering = start ; while (scattering != NULL) { old = scattering->scatt; scattering->scatt = cloog_scattering_erase_dimension(old, i); cloog_scattering_free(old); scattering = scattering->next ; } current-- ; } /* We postprocess the scaldims array in such a way that each entry is how * many scalar dimensions follows + 1 (the current one). This will make * some other processing easier (e.g. knowledge of some offsets). */ for (i=0;inb_scattdims-1;i++) { if (program->scaldims[i]) { j = i + 1 ; while ((j < program->nb_scattdims) && program->scaldims[j]) { program->scaldims[i] ++ ; j ++ ; } } } if (nb_scaldims != 0) cloog_msg(options, CLOOG_INFO, "%d dimensions (over %d) are scalar.\n", nb_scaldims,program->nb_scattdims) ; } /** * cloog_program_scatter function: * This function adds the scattering (scheduling) informations in a program. * If names is NULL, this function create names itself such that the i^th * name is ci. * - November 6th 2001: first version. */ void cloog_program_scatter(CloogProgram *program, CloogScatteringList *scattering, CloogOptions *options) { int scattering_dim, scattering_dim2, not_enough_constraints=0 ; CloogLoop * loop ; if ((program != NULL) && (scattering != NULL)) { loop = program->loop ; /* We compute the scattering dimension and check it is >=0. */ scattering_dim = cloog_scattering_dimension(scattering->scatt, loop->domain); if (scattering_dim < 0) cloog_die("scattering has not enough dimensions.\n"); if (!cloog_scattering_fully_specified(scattering->scatt, loop->domain)) not_enough_constraints ++ ; /* The scattering dimension may have been modified by scalar extraction. */ scattering_dim = cloog_scattering_dimension(scattering->scatt, loop->domain); /* Finally we scatter all loops. */ cloog_loop_scatter(loop, scattering->scatt); loop = loop->next ; scattering = scattering->next ; while ((loop != NULL) && (scattering != NULL)) { scattering_dim2 = cloog_scattering_dimension(scattering->scatt, loop->domain); if (scattering_dim2 != scattering_dim) cloog_die("scattering dimensions are not the same.\n") ; if (!cloog_scattering_fully_specified(scattering->scatt, loop->domain)) not_enough_constraints ++ ; cloog_loop_scatter(loop, scattering->scatt); loop = loop->next ; scattering = scattering->next ; } if ((loop != NULL) || (scattering != NULL)) cloog_msg(options, CLOOG_WARNING, "there is not a scattering for each statement.\n"); if (not_enough_constraints) cloog_msg(options, CLOOG_WARNING, "not enough constraints for " "%d scattering function(s).\n",not_enough_constraints) ; } }