diff options
Diffstat (limited to 'cloog-core/source')
-rw-r--r-- | cloog-core/source/block.c | 404 | ||||
-rw-r--r-- | cloog-core/source/clast.c | 1857 | ||||
-rw-r--r-- | cloog-core/source/cloog.c | 98 | ||||
-rw-r--r-- | cloog-core/source/input.c | 177 | ||||
-rw-r--r-- | cloog-core/source/int.c | 177 | ||||
-rw-r--r-- | cloog-core/source/isl/backend.c | 37 | ||||
-rw-r--r-- | cloog-core/source/isl/constraints.c | 804 | ||||
-rw-r--r-- | cloog-core/source/isl/domain.c | 1669 | ||||
-rw-r--r-- | cloog-core/source/loop.c | 2483 | ||||
-rw-r--r-- | cloog-core/source/matrix.c | 213 | ||||
-rw-r--r-- | cloog-core/source/matrix/constraintset.c | 1049 | ||||
-rw-r--r-- | cloog-core/source/mp_get_memory_functions.c | 14 | ||||
-rw-r--r-- | cloog-core/source/names.c | 528 | ||||
-rw-r--r-- | cloog-core/source/options.c | 461 | ||||
-rw-r--r-- | cloog-core/source/pprint.c | 423 | ||||
-rw-r--r-- | cloog-core/source/program.c | 1077 | ||||
-rw-r--r-- | cloog-core/source/state.c | 52 | ||||
-rw-r--r-- | cloog-core/source/statement.c | 280 | ||||
-rw-r--r-- | cloog-core/source/stride.c | 70 | ||||
-rw-r--r-- | cloog-core/source/union_domain.c | 298 | ||||
-rw-r--r-- | cloog-core/source/version.c | 24 | ||||
-rw-r--r-- | cloog-core/source/version.c.in | 24 |
22 files changed, 12219 insertions, 0 deletions
diff --git a/cloog-core/source/block.c b/cloog-core/source/block.c new file mode 100644 index 0000000..08fe807 --- /dev/null +++ b/cloog-core/source/block.c @@ -0,0 +1,404 @@ + + /**-------------------------------------------------------------------** + ** CLooG ** + **-------------------------------------------------------------------** + ** block.c ** + **-------------------------------------------------------------------** + ** First version: june 11th 2005 ** + **-------------------------------------------------------------------**/ + + +/****************************************************************************** + * 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 <stdlib.h> +# include <stdio.h> +# include "../include/cloog/cloog.h" + + +/****************************************************************************** + * Memory leaks hunting * + ******************************************************************************/ + + +/** + * These functions and global variables are devoted to memory leaks hunting: we + * want to know at each moment how many CloogBlock structures had been allocated + * (cloog_block_allocated) and how many had been freed (cloog_block_freed). + * Each time a CloogBlock structure is allocated, a call to the function + * cloog_block_leak_up() must be carried out, and respectively + * cloog_block_leak_down() when a CloogBlock structure is freed. The special + * variable cloog_block_max gives the maximal number of CloogBlock structures + * simultaneously alive (i.e. allocated and non-freed) in memory. + * - June 11th 2005: first version. + */ + + +static void cloog_block_leak_up(CloogState *state) +{ + state->block_allocated++; + if ((state->block_allocated - state->block_freed) > state->block_max) + state->block_max = state->block_allocated - state->block_freed; +} + + +static void cloog_block_leak_down(CloogState *state) +{ + state->block_freed++; +} + + +/****************************************************************************** + * Structure display function * + ******************************************************************************/ + + +/** + * cloog_domain_print_structure : + * this function is a human-friendly way to display the CloogDomain data + * structure, it includes an indentation level (level) in order to work with + * others print_structure functions. + * - June 16th 2005: first version. + */ +void cloog_block_print_structure(FILE * file, CloogBlock * block, int level) +{ int i ; + + /* Go to the right level. */ + for (i=0; i<level; i++) + fprintf(file,"|\t") ; + + if (block != NULL) + { fprintf(file,"+-- CloogBlock\n") ; + + /* A blank line. */ + for (i=0; i<level+2; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print statement list. */ + cloog_statement_print_structure(file,block->statement,level+1) ; + + /* A blank line. */ + for (i=0; i<level+2; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print scattering function. */ + for(i=0; i<level+1; i++) + fprintf(file,"|\t") ; + + fprintf(file,"+-- Null scattering function\n") ; + + /* A blank line. */ + for (i=0; i<level+2; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print scalar dimensions. */ + for (i=0; i<level+1; i++) + fprintf(file,"|\t") ; + + if (block->nb_scaldims == 0) + fprintf(file,"No scalar dimensions\n") ; + else + { fprintf(file,"Scalar dimensions (%d):",block->nb_scaldims) ; + for (i = 0; i < block->nb_scaldims; i++) { + fprintf(file, " "); + cloog_int_print(file, block->scaldims[i]); + } + fprintf(file,"\n") ; + } + + /* A blank line. */ + for (i=0; i<level+2; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print depth. */ + for (i=0; i<level+1; i++) + fprintf(file,"|\t") ; + fprintf(file,"Depth: %d\n",block->depth) ; + + /* A blank line. */ + for (i=0; i<level+1; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + } + else + fprintf(file,"+-- Null CloogBlock\n") ; +} + + +/** + * cloog_block_print function: + * This function prints the content of a CloogBlock structure (block) into a + * file (file, possibly stdout). + * - June 11th 2005: first version. + * - June 16th 2005: now just a call to cloog_block_print_structure. + */ +void cloog_block_print(FILE * file, CloogBlock * block) +{ cloog_block_print_structure(file,block,0) ; +} + + +/** + * cloog_block_list_print function: + * This function prints the content of a CloogBlock structure (block) into a + * file (file, possibly stdout). + * - June 16th 2005: first version. + */ +void cloog_block_list_print(FILE * file, CloogBlockList * blocklist) +{ int i=0 ; + + while (blocklist != NULL) + { fprintf(file,"+-- CloogBlockList node %d\n",i) ; + cloog_block_print_structure(file,blocklist->block,1) ; + blocklist = blocklist->next ; + i++ ; + } +} + + +/****************************************************************************** + * Memory deallocation function * + ******************************************************************************/ + + +/** + * cloog_block_free function: + * This function frees the allocated memory for a CloogStatement structure. + * - June 11th 2005: first version. + * - June 30th 2005: scaldims field management. + */ +void cloog_block_free(CloogBlock * block) +{ int i ; + + if (block != NULL) + { block->references -- ; + + if (block->references == 0) { + cloog_block_leak_down(block->state); + if (block->scaldims != NULL) + { for (i=0;i<block->nb_scaldims;i++) + cloog_int_clear(block->scaldims[i]); + + free(block->scaldims) ; + } + if (block->statement) + cloog_statement_free(block->statement); + free(block) ; + } + } +} + + +/** + * cloog_block_list_free function: + * This function frees the allocated memory for a CloogBlockList structure. + * - June 11th 2005: first version. + */ +void cloog_block_list_free(CloogBlockList * blocklist) +{ CloogBlockList * temp ; + + while (blocklist != NULL) + { temp = blocklist->next ; + cloog_block_free(blocklist->block) ; + free(blocklist) ; + blocklist = temp ; + } +} + + +/****************************************************************************** + * Processing functions * + ******************************************************************************/ + +/** + * cloog_block_malloc function: + * This function allocates the memory space for a CloogBlock structure and + * sets its fields with default values. Then it returns a pointer to the + * allocated space. + * - November 21th 2005: first version. + */ +CloogBlock *cloog_block_malloc(CloogState *state) +{ CloogBlock * block ; + + /* Memory allocation for the CloogBlock structure. */ + block = (CloogBlock *)malloc(sizeof(CloogBlock)) ; + if (block == NULL) + cloog_die("memory overflow.\n"); + cloog_block_leak_up(state); + + /* We set the various fields with default values. */ + block->state = state; + block->statement = NULL ; + block->nb_scaldims = 0 ; + block->scaldims = NULL ; + block->depth = 0 ; + block->references = 1 ; + block->usr = NULL; + + return block ; +} + + +/** + * cloog_block_alloc function: + * This function allocates the memory space for a CloogBlock structure and + * sets its fields with those given as input. Then it returns a pointer to the + * allocated space. The two parameters nb_scaldims and scaldims are for internal + * service, put to respectively 0 and NULL if you don't know what they are + * useful for ! + * - statement is the statement list of the block, + * - scattering is the scattering function for the block (NULL if unsure !), + * - nb_scaldims is the number of scalar dimensions (0 if unsure !), + * - scaldims is the array with the scalar dimensions values (NULL if unsure !), + * - depth is the original block depth (the number of outer loops). + ** + * - June 11th 2005: first version. + * - June 30th 2005: addition of the nb_scaldims and scaldims parameters. + * - November 21th 2005: use of cloog_block_malloc. + */ +CloogBlock *cloog_block_alloc(CloogStatement *statement, int nb_scaldims, + cloog_int_t *scaldims, int depth) +{ CloogBlock * block ; + + /* Block allocation. */ + block = cloog_block_malloc(statement->state); + + block->statement = statement ; + block->nb_scaldims = nb_scaldims ; + block->scaldims = scaldims ; + block->depth = depth ; + block->references = 1 ; + + return block ; +} + + +/** + * cloog_block_list_malloc function: + * This function allocates the memory space for a CloogBlockList structure and + * sets its fields with default values. Then it returns a pointer to the + * allocated space. + * - November 21th 2005: first version. + */ +CloogBlockList * cloog_block_list_malloc() +{ CloogBlockList * blocklist ; + + /* Memory allocation for the CloogBlock structure. */ + blocklist = (CloogBlockList *)malloc(sizeof(CloogBlockList)) ; + if (blocklist == NULL) + cloog_die("memory overflow.\n"); + + /* We set the various fields with default values. */ + blocklist->block = NULL ; + blocklist->next = NULL ; + + return blocklist ; +} + + +/** + * cloog_block_list_alloc function: + * This function allocates the memory space for a CloogBlockList structure and + * sets its fields with those given as input. Then it returns a pointer to the + * allocated space. + * - block is the block element of the list node, + ** + * - June 11th 2005: first version. + * - November 21th 2005: use of cloog_block_list_malloc. + */ +CloogBlockList * cloog_block_list_alloc(CloogBlock * block) +{ CloogBlockList * blocklist ; + + /* Block list node allocation. */ + blocklist = cloog_block_list_malloc() ; + + blocklist->block = block ; + blocklist->block->references ++ ; /* The block has a new reference to it. */ + blocklist->next = NULL ; + + return blocklist ; +} + + +/** + * cloog_block_copy function: + * This function returns a copy of a CloogBlock structure 'block'. To save + * memory this is not a memory copy but we increment a counter of active + * references inside the structure, then return a pointer to that structure. + */ +CloogBlock * cloog_block_copy(CloogBlock * block) +{ if (block == NULL) + return NULL ; + + block->references ++ ; + return block ; +} + + +/** + * cloog_block_merge function: + * this function adds at the end of the statement list of the block 'block', + * the statement list of the block 'merged'. Then the CloogBlock structure + * of 'merged' is freed (obviously not its statement list that is now + * included in 'block'). + * - June 11th 2005: first version. + */ +void cloog_block_merge(CloogBlock * block, CloogBlock * merged) +{ CloogStatement * statement ; + + if ((block == NULL) || (merged == NULL)) + return ; + + if (block->statement != NULL) + { statement = block->statement ; + + while (statement->next != NULL) + statement = statement->next ; + + statement->next = merged->statement ; + } + else + block->statement = merged->statement ; + + merged->statement = NULL; + cloog_block_free(merged); +} + + + + + + + + + + diff --git a/cloog-core/source/clast.c b/cloog-core/source/clast.c new file mode 100644 index 0000000..33e0a7b --- /dev/null +++ b/cloog-core/source/clast.c @@ -0,0 +1,1857 @@ +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "../include/cloog/cloog.h" + +#define ALLOC(type) (type*)malloc(sizeof(type)) +#define ALLOCN(type,n) (type*)malloc((n)*sizeof(type)) + +/** + * CloogInfos structure: + * this structure contains all the informations necessary for pretty printing, + * they come from the original CloogProgram structure (language, names), from + * genereral options (options) or are built only for pretty printing (stride). + * This structure is mainly there to reduce the number of function parameters, + * since most pprint.c functions need most of its field. + */ +struct clooginfos { + CloogState *state; /**< State. */ + CloogStride **stride; + int stride_level; /**< Number of valid entries in stride array. */ + int nb_scattdims ; /**< Scattering dimension number. */ + int * scaldims ; /**< Boolean array saying whether a given + * scattering dimension is scalar or not. + */ + CloogNames * names ; /**< Names of iterators and parameters. */ + CloogOptions * options ; /**< Options on CLooG's behaviour. */ + CloogEqualities *equal; /**< Matrix of equalities. */ +} ; + +typedef struct clooginfos CloogInfos ; + +static int clast_expr_cmp(struct clast_expr *e1, struct clast_expr *e2); +static int clast_term_cmp(struct clast_term *t1, struct clast_term *t2); +static int clast_binary_cmp(struct clast_binary *b1, struct clast_binary *b2); +static int clast_reduction_cmp(struct clast_reduction *r1, + struct clast_reduction *r2); + +static struct clast_expr *clast_expr_copy(struct clast_expr *e); + +static int clast_equal_add(CloogEqualities *equal, + CloogConstraintSet *constraints, + int level, CloogConstraint *constraint, + CloogInfos *infos); + +static struct clast_stmt *clast_equal(int level, CloogInfos *infos); +static struct clast_expr *clast_minmax(CloogConstraintSet *constraints, + int level, int max, int guard, + int lower_bound, + CloogInfos *infos); +static void insert_guard(CloogConstraintSet *constraints, int level, + struct clast_stmt ***next, CloogInfos *infos); +static int insert_modulo_guard(CloogConstraint *upper, + CloogConstraint *lower, int level, + struct clast_stmt ***next, CloogInfos *infos); +static int insert_equation(CloogDomain *domain, CloogConstraint *upper, + CloogConstraint *lower, int level, + struct clast_stmt ***next, CloogInfos *infos); +static int insert_for(CloogDomain *domain, CloogConstraintSet *constraints, + int level, int otl, struct clast_stmt ***next, + CloogInfos *infos); +static void insert_block(CloogDomain *domain, CloogBlock *block, int level, + struct clast_stmt ***next, CloogInfos *infos); +static void insert_loop(CloogLoop * loop, int level, + struct clast_stmt ***next, CloogInfos *infos); + + +struct clast_name *new_clast_name(const char *name) +{ + struct clast_name *n = malloc(sizeof(struct clast_name)); + n->expr.type = clast_expr_name; + n->name = name; + return n; +} + +struct clast_term *new_clast_term(cloog_int_t c, struct clast_expr *v) +{ + struct clast_term *t = malloc(sizeof(struct clast_term)); + t->expr.type = clast_expr_term; + cloog_int_init(t->val); + cloog_int_set(t->val, c); + t->var = v; + return t; +} + +struct clast_binary *new_clast_binary(enum clast_bin_type t, + struct clast_expr *lhs, cloog_int_t rhs) +{ + struct clast_binary *b = malloc(sizeof(struct clast_binary)); + b->expr.type = clast_expr_bin; + b->type = t; + b->LHS = lhs; + cloog_int_init(b->RHS); + cloog_int_set(b->RHS, rhs); + return b; +} + +struct clast_reduction *new_clast_reduction(enum clast_red_type t, int n) +{ + int i; + struct clast_reduction *r; + r = malloc(sizeof(struct clast_reduction)+(n-1)*sizeof(struct clast_expr *)); + r->expr.type = clast_expr_red; + r->type = t; + r->n = n; + for (i = 0; i < n; ++i) + r->elts[i] = NULL; + return r; +} + +static void free_clast_root(struct clast_stmt *s); + +const struct clast_stmt_op stmt_root = { free_clast_root }; + +static void free_clast_root(struct clast_stmt *s) +{ + struct clast_root *r = (struct clast_root *)s; + assert(CLAST_STMT_IS_A(s, stmt_root)); + cloog_names_free(r->names); + free(r); +} + +struct clast_root *new_clast_root(CloogNames *names) +{ + struct clast_root *r = malloc(sizeof(struct clast_root)); + r->stmt.op = &stmt_root; + r->stmt.next = NULL; + r->names = cloog_names_copy(names); + return r; +} + +static void free_clast_assignment(struct clast_stmt *s); + +const struct clast_stmt_op stmt_ass = { free_clast_assignment }; + +static void free_clast_assignment(struct clast_stmt *s) +{ + struct clast_assignment *a = (struct clast_assignment *)s; + assert(CLAST_STMT_IS_A(s, stmt_ass)); + free_clast_expr(a->RHS); + free(a); +} + +struct clast_assignment *new_clast_assignment(const char *lhs, + struct clast_expr *rhs) +{ + struct clast_assignment *a = malloc(sizeof(struct clast_assignment)); + a->stmt.op = &stmt_ass; + a->stmt.next = NULL; + a->LHS = lhs; + a->RHS = rhs; + return a; +} + +static void free_clast_user_stmt(struct clast_stmt *s); + +const struct clast_stmt_op stmt_user = { free_clast_user_stmt }; + +static void free_clast_user_stmt(struct clast_stmt *s) +{ + struct clast_user_stmt *u = (struct clast_user_stmt *)s; + assert(CLAST_STMT_IS_A(s, stmt_user)); + cloog_domain_free(u->domain); + cloog_statement_free(u->statement); + cloog_clast_free(u->substitutions); + free(u); +} + +struct clast_user_stmt *new_clast_user_stmt(CloogDomain *domain, + CloogStatement *stmt, struct clast_stmt *subs) +{ + struct clast_user_stmt *u = malloc(sizeof(struct clast_user_stmt)); + u->stmt.op = &stmt_user; + u->stmt.next = NULL; + u->domain = cloog_domain_copy(domain); + u->statement = cloog_statement_copy(stmt); + u->substitutions = subs; + return u; +} + +static void free_clast_block(struct clast_stmt *b); + +const struct clast_stmt_op stmt_block = { free_clast_block }; + +static void free_clast_block(struct clast_stmt *s) +{ + struct clast_block *b = (struct clast_block *)s; + assert(CLAST_STMT_IS_A(s, stmt_block)); + cloog_clast_free(b->body); + free(b); +} + +struct clast_block *new_clast_block() +{ + struct clast_block *b = malloc(sizeof(struct clast_block)); + b->stmt.op = &stmt_block; + b->stmt.next = NULL; + b->body = NULL; + return b; +} + +static void free_clast_for(struct clast_stmt *s); + +const struct clast_stmt_op stmt_for = { free_clast_for }; + +static void free_clast_for(struct clast_stmt *s) +{ + struct clast_for *f = (struct clast_for *)s; + assert(CLAST_STMT_IS_A(s, stmt_for)); + cloog_domain_free(f->domain); + free_clast_expr(f->LB); + free_clast_expr(f->UB); + cloog_int_clear(f->stride); + cloog_clast_free(f->body); + free(f); +} + +struct clast_for *new_clast_for(CloogDomain *domain, const char *it, + struct clast_expr *LB, struct clast_expr *UB, + CloogStride *stride) +{ + struct clast_for *f = malloc(sizeof(struct clast_for)); + f->stmt.op = &stmt_for; + f->stmt.next = NULL; + f->domain = cloog_domain_copy(domain); + f->iterator = it; + f->LB = LB; + f->UB = UB; + f->body = NULL; + cloog_int_init(f->stride); + if (stride) + cloog_int_set(f->stride, stride->stride); + else + cloog_int_set_si(f->stride, 1); + return f; +} + +static void free_clast_guard(struct clast_stmt *s); + +const struct clast_stmt_op stmt_guard = { free_clast_guard }; + +static void free_clast_guard(struct clast_stmt *s) +{ + int i; + struct clast_guard *g = (struct clast_guard *)s; + assert(CLAST_STMT_IS_A(s, stmt_guard)); + cloog_clast_free(g->then); + for (i = 0; i < g->n; ++i) { + free_clast_expr(g->eq[i].LHS); + free_clast_expr(g->eq[i].RHS); + } + free(g); +} + +struct clast_guard *new_clast_guard(int n) +{ + int i; + struct clast_guard *g = malloc(sizeof(struct clast_guard) + + (n-1) * sizeof(struct clast_equation)); + g->stmt.op = &stmt_guard; + g->stmt.next = NULL; + g->then = NULL; + g->n = n; + for (i = 0; i < n; ++i) { + g->eq[i].LHS = NULL; + g->eq[i].RHS = NULL; + } + return g; +} + +void free_clast_name(struct clast_name *n) +{ + free(n); +} + +void free_clast_term(struct clast_term *t) +{ + cloog_int_clear(t->val); + free_clast_expr(t->var); + free(t); +} + +void free_clast_binary(struct clast_binary *b) +{ + cloog_int_clear(b->RHS); + free_clast_expr(b->LHS); + free(b); +} + +void free_clast_reduction(struct clast_reduction *r) +{ + int i; + for (i = 0; i < r->n; ++i) + free_clast_expr(r->elts[i]); + free(r); +} + +void free_clast_expr(struct clast_expr *e) +{ + if (!e) + return; + switch (e->type) { + case clast_expr_name: + free_clast_name((struct clast_name*) e); + break; + case clast_expr_term: + free_clast_term((struct clast_term*) e); + break; + case clast_expr_red: + free_clast_reduction((struct clast_reduction*) e); + break; + case clast_expr_bin: + free_clast_binary((struct clast_binary*) e); + break; + default: + assert(0); + } +} + +void free_clast_stmt(struct clast_stmt *s) +{ + assert(s->op); + assert(s->op->free); + s->op->free(s); +} + +void cloog_clast_free(struct clast_stmt *s) +{ + struct clast_stmt *next; + while (s) { + next = s->next; + free_clast_stmt(s); + s = next; + } +} + +static int clast_name_cmp(struct clast_name *n1, struct clast_name *n2) +{ + return n1->name == n2->name ? 0 : strcmp(n1->name, n2->name); +} + +static int clast_term_cmp(struct clast_term *t1, struct clast_term *t2) +{ + int c; + if (!t1->var && t2->var) + return -1; + if (t1->var && !t2->var) + return 1; + c = clast_expr_cmp(t1->var, t2->var); + if (c) + return c; + return cloog_int_cmp(t1->val, t2->val); +} + +static int clast_binary_cmp(struct clast_binary *b1, struct clast_binary *b2) +{ + int c; + + if (b1->type != b2->type) + return b1->type - b2->type; + if ((c = cloog_int_cmp(b1->RHS, b2->RHS))) + return c; + return clast_expr_cmp(b1->LHS, b2->LHS); +} + +static int clast_reduction_cmp(struct clast_reduction *r1, struct clast_reduction *r2) +{ + int i; + int c; + + if (r1->n == 1 && r2->n == 1) + return clast_expr_cmp(r1->elts[0], r2->elts[0]); + if (r1->type != r2->type) + return r1->type - r2->type; + if (r1->n != r2->n) + return r1->n - r2->n; + for (i = 0; i < r1->n; ++i) + if ((c = clast_expr_cmp(r1->elts[i], r2->elts[i]))) + return c; + return 0; +} + +static int clast_expr_cmp(struct clast_expr *e1, struct clast_expr *e2) +{ + if (!e1 && !e2) + return 0; + if (!e1) + return -1; + if (!e2) + return 1; + if (e1->type != e2->type) + return e1->type - e2->type; + switch (e1->type) { + case clast_expr_name: + return clast_name_cmp((struct clast_name*) e1, + (struct clast_name*) e2); + case clast_expr_term: + return clast_term_cmp((struct clast_term*) e1, + (struct clast_term*) e2); + case clast_expr_bin: + return clast_binary_cmp((struct clast_binary*) e1, + (struct clast_binary*) e2); + case clast_expr_red: + return clast_reduction_cmp((struct clast_reduction*) e1, + (struct clast_reduction*) e2); + default: + assert(0); + } +} + +int clast_expr_equal(struct clast_expr *e1, struct clast_expr *e2) +{ + return clast_expr_cmp(e1, e2) == 0; +} + +/** + * Return 1 is both expressions are constant terms and e1 is bigger than e2. + */ +int clast_expr_is_bigger_constant(struct clast_expr *e1, struct clast_expr *e2) +{ + struct clast_term *t1, *t2; + struct clast_reduction *r; + + if (!e1 || !e2) + return 0; + if (e1->type == clast_expr_red) { + r = (struct clast_reduction *)e1; + return r->n == 1 && clast_expr_is_bigger_constant(r->elts[0], e2); + } + if (e2->type == clast_expr_red) { + r = (struct clast_reduction *)e2; + return r->n == 1 && clast_expr_is_bigger_constant(e1, r->elts[0]); + } + if (e1->type != clast_expr_term || e2->type != clast_expr_term) + return 0; + t1 = (struct clast_term *)e1; + t2 = (struct clast_term *)e2; + if (t1->var || t2->var) + return 0; + return cloog_int_gt(t1->val, t2->val); +} + +static int qsort_expr_cmp(const void *p1, const void *p2) +{ + return clast_expr_cmp(*(struct clast_expr **)p1, *(struct clast_expr **)p2); +} + +static void clast_reduction_sort(struct clast_reduction *r) +{ + qsort(&r->elts[0], r->n, sizeof(struct clast_expr *), qsort_expr_cmp); +} + +static int qsort_eq_cmp(const void *p1, const void *p2) +{ + struct clast_equation *eq1 = (struct clast_equation *)p1; + struct clast_equation *eq2 = (struct clast_equation *)p2; + int cmp; + + cmp = clast_expr_cmp(eq1->LHS, eq2->LHS); + if (cmp) + return cmp; + + cmp = clast_expr_cmp(eq1->RHS, eq2->RHS); + if (cmp) + return cmp; + + return eq1->sign - eq2->sign; +} + +/** + * Sort equations in a clast_guard. + */ +static void clast_guard_sort(struct clast_guard *g) +{ + qsort(&g->eq[0], g->n, sizeof(struct clast_equation), qsort_eq_cmp); +} + + +/** + * Construct a (deep) copy of an expression clast. + */ +static struct clast_expr *clast_expr_copy(struct clast_expr *e) +{ + if (!e) + return NULL; + switch (e->type) { + case clast_expr_name: { + struct clast_name* n = (struct clast_name*) e; + return &new_clast_name(n->name)->expr; + } + case clast_expr_term: { + struct clast_term* t = (struct clast_term*) e; + return &new_clast_term(t->val, clast_expr_copy(t->var))->expr; + } + case clast_expr_red: { + int i; + struct clast_reduction *r = (struct clast_reduction*) e; + struct clast_reduction *r2 = new_clast_reduction(r->type, r->n); + for (i = 0; i < r->n; ++i) + r2->elts[i] = clast_expr_copy(r->elts[i]); + return &r2->expr; + } + case clast_expr_bin: { + struct clast_binary *b = (struct clast_binary*) e; + return &new_clast_binary(b->type, clast_expr_copy(b->LHS), b->RHS)->expr; + } + default: + assert(0); + } +} + + +/****************************************************************************** + * Equalities spreading functions * + ******************************************************************************/ + + +/** + * clast_equal_allow function: + * This function checks whether the options allow us to spread the equality or + * not. It returns 1 if so, 0 otherwise. + * - equal is the matrix of equalities, + * - level is the column number in equal of the element which is 'equal to', + * - line is the line number in equal of the constraint we want to study, + * - the infos structure gives the user all options on code printing and more. + ** + * - October 27th 2005: first version (extracted from old pprint_equal_add). + */ +static int clast_equal_allow(CloogEqualities *equal, int level, int line, + CloogInfos *infos) +{ + if (level < infos->options->fsp) + return 0 ; + + if ((cloog_equal_type(equal, level) == EQTYPE_EXAFFINE) && + !infos->options->esp) + return 0 ; + + return 1 ; +} + + +/** + * clast_equal_add function: + * This function updates the row (level-1) of the equality matrix (equal) with + * the row that corresponds to the row (line) of the matrix (matrix). It returns + * 1 if the row can be updated, 0 otherwise. + * - equal is the matrix of equalities, + * - matrix is the matrix of constraints, + * - level is the column number in matrix of the element which is 'equal to', + * - line is the line number in matrix of the constraint we want to study, + * - the infos structure gives the user all options on code printing and more. + */ +static int clast_equal_add(CloogEqualities *equal, + CloogConstraintSet *constraints, + int level, CloogConstraint *constraint, + CloogInfos *infos) +{ + cloog_equal_add(equal, constraints, level, constraint, + infos->names->nb_parameters); + + return clast_equal_allow(equal, level, level-1, infos); +} + + + +/** + * clast_equal function: + * This function prints the substitution data of a statement into a clast_stmt. + * Using this function instead of pprint_equal is useful for generating + * a compilable pseudo-code by using preprocessor macro for each statement. + * By opposition to pprint_equal, the result is less human-readable. For + * instance this function will print (i,i+3,k,3) where pprint_equal would + * return (j=i+3,l=3). + * - level is the number of loops enclosing the statement, + * - the infos structure gives the user all options on code printing and more. + ** + * - March 12th 2004: first version. + * - November 21th 2005: (debug) now works well with GMP version. + */ +static struct clast_stmt *clast_equal(int level, CloogInfos *infos) +{ + int i ; + struct clast_expr *e; + struct clast_stmt *a = NULL; + struct clast_stmt **next = &a; + CloogEqualities *equal = infos->equal; + CloogConstraint *equal_constraint; + + for (i=infos->names->nb_scattering;i<level-1;i++) + { if (cloog_equal_type(equal, i+1)) { + equal_constraint = cloog_equal_constraint(equal, i); + e = clast_bound_from_constraint(equal_constraint, i+1, infos->names); + cloog_constraint_release(equal_constraint); + } else { + e = &new_clast_term(infos->state->one, &new_clast_name( + cloog_names_name_at_level(infos->names, i+1))->expr)->expr; + } + *next = &new_clast_assignment(NULL, e)->stmt; + next = &(*next)->next; + } + + return a; +} + + +/** + * clast_bound_from_constraint function: + * This function returns a clast_expr containing the printing of the + * 'right part' of a constraint according to an element. + * For instance, for the constraint -3*i + 2*j - M >=0 and the element j, + * we have j >= (3*i + M)/2. As we are looking for integral solutions, this + * function should return 'ceild(3*i+M,2)'. + * - matrix is the polyhedron containing all the constraints, + * - line_num is the line number in domain of the constraint we want to print, + * - level is the column number in domain of the element we want to use, + * - names structure gives the user some options about code printing, + * the number of parameters in domain (nb_par), and the arrays of iterator + * names and parameters (iters and params). + ** + * - November 2nd 2001: first version. + * - June 27th 2003: 64 bits version ready. + */ +struct clast_expr *clast_bound_from_constraint(CloogConstraint *constraint, + int level, CloogNames *names) +{ + int i, sign, nb_elts=0, len; + cloog_int_t *line, numerator, denominator, temp, division; + struct clast_expr *e = NULL; + struct cloog_vec *line_vector; + + len = cloog_constraint_total_dimension(constraint) + 2; + line_vector = cloog_vec_alloc(len); + line = line_vector->p; + cloog_constraint_copy_coefficients(constraint, line+1); + cloog_int_init(temp); + cloog_int_init(numerator); + cloog_int_init(denominator); + + if (!cloog_int_is_zero(line[level])) { + struct clast_reduction *r; + /* Maybe we need to invert signs in such a way that the element sign is>0.*/ + sign = -cloog_int_sgn(line[level]); + + for (i = 1, nb_elts = 0; i <= len - 1; ++i) + if (i != level && !cloog_int_is_zero(line[i])) + nb_elts++; + r = new_clast_reduction(clast_red_sum, nb_elts); + nb_elts = 0; + + /* First, we have to print the iterators and the parameters. */ + for (i = 1; i <= len - 2; i++) { + struct clast_expr *v; + + if (i == level || cloog_int_is_zero(line[i])) + continue; + + v = cloog_constraint_variable_expr(constraint, i, names); + + if (sign == -1) + cloog_int_neg(temp,line[i]); + else + cloog_int_set(temp,line[i]); + + r->elts[nb_elts++] = &new_clast_term(temp, v)->expr; + } + + if (sign == -1) { + cloog_int_neg(numerator, line[len - 1]); + cloog_int_set(denominator, line[level]); + } + else { + cloog_int_set(numerator, line[len - 1]); + cloog_int_neg(denominator, line[level]); + } + + /* Finally, the constant, and the final printing. */ + if (nb_elts) { + if (!cloog_int_is_zero(numerator)) + r->elts[nb_elts++] = &new_clast_term(numerator, NULL)->expr; + + if (!cloog_int_is_one(line[level]) && !cloog_int_is_neg_one(line[level])) + { if (!cloog_constraint_is_equality(constraint)) + { if (cloog_int_is_pos(line[level])) + e = &new_clast_binary(clast_bin_cdiv, &r->expr, denominator)->expr; + else + e = &new_clast_binary(clast_bin_fdiv, &r->expr, denominator)->expr; + } else + e = &new_clast_binary(clast_bin_div, &r->expr, denominator)->expr; + } + else + e = &r->expr; + } else { + free_clast_reduction(r); + if (cloog_int_is_zero(numerator)) + e = &new_clast_term(numerator, NULL)->expr; + else + { if (!cloog_int_is_one(denominator)) + { if (!cloog_constraint_is_equality(constraint)) { /* useful? */ + if (cloog_int_is_divisible_by(numerator, denominator)) { + cloog_int_divexact(temp, numerator, denominator); + e = &new_clast_term(temp, NULL)->expr; + } + else { + cloog_int_init(division); + cloog_int_tdiv_q(division, numerator, denominator); + if (cloog_int_is_neg(numerator)) { + if (cloog_int_is_pos(line[level])) { + /* nb<0 need max */ + e = &new_clast_term(division, NULL)->expr; + } else { + /* nb<0 need min */ + cloog_int_sub_ui(temp, division, 1); + e = &new_clast_term(temp, NULL)->expr; + } + } + else + { if (cloog_int_is_pos(line[level])) + { /* nb>0 need max */ + cloog_int_add_ui(temp, division, 1); + e = &new_clast_term(temp, NULL)->expr; + } + else + /* nb>0 need min */ + e = &new_clast_term(division, NULL)->expr; + } + cloog_int_clear(division); + } + } + else + e = &new_clast_binary(clast_bin_div, + &new_clast_term(numerator, NULL)->expr, + denominator)->expr; + } + else + e = &new_clast_term(numerator, NULL)->expr; + } + } + } + + cloog_vec_free(line_vector); + + cloog_int_clear(temp); + cloog_int_clear(numerator); + cloog_int_clear(denominator); + + return e; +} + + +/* Temporary structure for communication between clast_minmax and + * its cloog_constraint_set_foreach_constraint callback functions. + */ +struct clast_minmax_data { + int level; + int max; + int guard; + int lower_bound; + CloogInfos *infos; + int n; + struct clast_reduction *r; +}; + + +/* Should constraint "c" be considered by clast_minmax? + */ +static int valid_bound(CloogConstraint *c, struct clast_minmax_data *d) +{ + if (d->max && !cloog_constraint_is_lower_bound(c, d->level - 1)) + return 0; + if (!d->max && !cloog_constraint_is_upper_bound(c, d->level - 1)) + return 0; + if (cloog_constraint_is_equality(c)) + return 0; + if (d->guard && cloog_constraint_involves(c, d->guard - 1)) + return 0; + + return 1; +} + + +/* Increment n for each bound that should be considered by clast_minmax. + */ +static int count_bounds(CloogConstraint *c, void *user) +{ + struct clast_minmax_data *d = (struct clast_minmax_data *) user; + + if (!valid_bound(c, d)) + return 0; + + d->n++; + + return 0; +} + + +/* Update the given lower bound based on stride information. + * In some backends, the lower bounds are updated from within + * cloog_loop_stride, but other backends leave the updating to + * this function. In the later case, the original lower bound + * is known to be a constant. + * If the bound turns out not to be a constant, we know we + * are in the former case and nothing needs to be done. + * If the bound has already been updated and it just happens + * to be a constant, then this function performs an identity + * operation on the constant. + */ +static void update_lower_bound(struct clast_expr *expr, int level, + CloogStride *stride) +{ + struct clast_term *t; + if (stride->constraint) + return; + if (expr->type != clast_expr_term) + return; + t = (struct clast_term *)expr; + if (t->var) + return; + cloog_int_sub(t->val, t->val, stride->offset); + cloog_int_cdiv_q(t->val, t->val, stride->stride); + cloog_int_mul(t->val, t->val, stride->stride); + cloog_int_add(t->val, t->val, stride->offset); +} + + +/* Add all relevant bounds to r->elts and update lower bounds + * based on stride information. + */ +static int collect_bounds(CloogConstraint *c, void *user) +{ + struct clast_minmax_data *d = (struct clast_minmax_data *) user; + + if (!valid_bound(c, d)) + return 0; + + d->r->elts[d->n] = clast_bound_from_constraint(c, d->level, + d->infos->names); + if (d->lower_bound && d->infos->stride[d->level - 1]) { + update_lower_bound(d->r->elts[d->n], d->level, + d->infos->stride[d->level - 1]); + } + + d->n++; + + return 0; +} + + +/** + * clast_minmax function: + * This function returns a clast_expr containing the printing of a minimum or a + * maximum of the 'right parts' of all constraints according to an element. + * For instance consider the constraints: + * -3*i +2*j -M >= 0 + * 2*i +j >= 0 + * -i -j +2*M >= 0 + * if we are looking for the minimum for the element j, the function should + * return 'max(ceild(3*i+M,2),-2*i)'. + * - constraints is the constraints, + * - level is the column number in domain of the element we want to use, + * - max is a boolean set to 1 if we are looking for a maximum, 0 for a minimum, + * - guard is set to 0 if there is no guard, and set to the level of the element + * with a guard otherwise (then the function gives the max or the min only + * for the constraint where the guarded coefficient is 0), + * - lower is set to 1 if the maximum is to be used a lower bound on a loop + * - the infos structure gives the user some options about code printing, + * the number of parameters in domain (nb_par), and the arrays of iterator + * names and parameters (iters and params). + ** + * - November 2nd 2001: first version. + */ +static struct clast_expr *clast_minmax(CloogConstraintSet *constraints, + int level, int max, int guard, + int lower_bound, + CloogInfos *infos) +{ + struct clast_minmax_data data = { level, max, guard, lower_bound, infos }; + + data.n = 0; + + cloog_constraint_set_foreach_constraint(constraints, count_bounds, &data); + + if (!data.n) + return NULL; + data.r = new_clast_reduction(max ? clast_red_max : clast_red_min, data.n); + + data.n = 0; + cloog_constraint_set_foreach_constraint(constraints, collect_bounds, &data); + + clast_reduction_sort(data.r); + return &data.r->expr; +} + + +/** + * Insert modulo guards defined by existentially quantified dimensions, + * not involving the given level. + * + * This function is called from within insert_guard. + * Any constraint used in constructing a modulo guard is removed + * from the constraint set to avoid insert_guard + * adding a duplicate (pair of) constraint(s). + */ +static void insert_extra_modulo_guards(CloogConstraintSet *constraints, + int level, struct clast_stmt ***next, CloogInfos *infos) +{ + int i; + int nb_iter; + int total_dim; + CloogConstraint *upper, *lower; + + total_dim = cloog_constraint_set_total_dimension(constraints); + nb_iter = cloog_constraint_set_n_iterators(constraints, + infos->names->nb_parameters); + + for (i = total_dim - infos->names->nb_parameters; i >= nb_iter + 1; i--) { + if (cloog_constraint_is_valid(upper = + cloog_constraint_set_defining_equality(constraints, i))) { + if (!level || (nb_iter < level) || + !cloog_constraint_involves(upper, level-1)) { + insert_modulo_guard(upper, + cloog_constraint_invalid(), i, next, infos); + cloog_constraint_clear(upper); + } + cloog_constraint_release(upper); + } else if (cloog_constraint_is_valid(upper = + cloog_constraint_set_defining_inequalities(constraints, + i, &lower, infos->names->nb_parameters))) { + if (!level || (nb_iter < level) || + !cloog_constraint_involves(upper, level-1)) { + insert_modulo_guard(upper, lower, i, next, infos); + cloog_constraint_clear(upper); + cloog_constraint_clear(lower); + } + cloog_constraint_release(upper); + cloog_constraint_release(lower); + } + } +} + + +static int clear_lower_bound_at_level(CloogConstraint *c, void *user) +{ + int level = *(int *)user; + + if (cloog_constraint_is_lower_bound(c, level - 1)) + cloog_constraint_clear(c); + + return 0; +} + + +static int clear_upper_bound_at_level(CloogConstraint *c, void *user) +{ + int level = *(int *)user; + + if (cloog_constraint_is_upper_bound(c, level - 1)) + cloog_constraint_clear(c); + + return 0; +} + + +/* Temporary structure for communication between insert_guard and + * its cloog_constraint_set_foreach_constraint callback function. + */ +struct clast_guard_data { + int level; + CloogInfos *infos; + int n; + int i; + int nb_iter; + CloogConstraintSet *copy; + struct clast_guard *g; +}; + + +static int guard_count_bounds(CloogConstraint *c, void *user) +{ + struct clast_guard_data *d = (struct clast_guard_data *) user; + + d->n++; + + return 0; +} + + +/* Insert a guard, if necesessary, for constraint j. + */ +static int insert_guard_constraint(CloogConstraint *j, void *user) +{ + struct clast_guard_data *d = (struct clast_guard_data *) user; + int minmax = -1; + struct clast_expr *v; + struct clast_term *t; + + if (!cloog_constraint_involves(j, d->i - 1)) + return 0; + + if (d->level && d->nb_iter >= d->level && + cloog_constraint_involves(j, d->level - 1)) + return 0; + + v = cloog_constraint_variable_expr(j, d->i, d->infos->names); + d->g->eq[d->n].LHS = &(t = new_clast_term(d->infos->state->one, v))->expr; + if (!d->level || cloog_constraint_is_equality(j)) { + /* put the "denominator" in the LHS */ + cloog_constraint_coefficient_get(j, d->i - 1, &t->val); + cloog_constraint_coefficient_set(j, d->i - 1, d->infos->state->one); + if (cloog_int_is_neg(t->val)) { + cloog_int_neg(t->val, t->val); + cloog_constraint_coefficient_set(j, d->i - 1, d->infos->state->negone); + } + if (d->level || cloog_constraint_is_equality(j)) + d->g->eq[d->n].sign = 0; + else if (cloog_constraint_is_lower_bound(j, d->i - 1)) + d->g->eq[d->n].sign = 1; + else + d->g->eq[d->n].sign = -1; + d->g->eq[d->n].RHS = clast_bound_from_constraint(j, d->i, d->infos->names); + } else { + int guarded; + + if (cloog_constraint_is_lower_bound(j, d->i - 1)) { + minmax = 1; + d->g->eq[d->n].sign = 1; + } else { + minmax = 0; + d->g->eq[d->n].sign = -1; + } + + guarded = (d->nb_iter >= d->level) ? d->level : 0 ; + d->g->eq[d->n].RHS = clast_minmax(d->copy, d->i, minmax, guarded, 0, + d->infos); + } + d->n++; + + /* 'elimination' of the current constraint, this avoid to use one + * constraint more than once. The current line is always eliminated, + * and the next lines if they are in a min or a max. + */ + cloog_constraint_clear(j); + + if (minmax == -1) + return 0; + if (minmax == 1) + cloog_constraint_set_foreach_constraint(d->copy, + clear_lower_bound_at_level, &d->i); + else if (minmax == 0) + cloog_constraint_set_foreach_constraint(d->copy, + clear_upper_bound_at_level, &d->i); + + return 0; +} + + +/** + * insert_guard function: + * This function inserts a guard in the clast. + * A guard on an element (level) is : + * -> the conjunction of all the existing constraints where the coefficient of + * this element is 0 if the element is an iterator, + * -> the conjunction of all the existing constraints if the element isn't an + * iterator. + * For instance, considering these constraints and the element j: + * -3*i +2*j -M >= 0 + * 2*i +M >= 0 + * this function should return 'if (2*i+M>=0) {'. + * - matrix is the polyhedron containing all the constraints, + * - level is the column number of the element in matrix we want to use, + * - the infos structure gives the user some options about code printing, + * the number of parameters in matrix (nb_par), and the arrays of iterator + * names and parameters (iters and params). + ** + * - November 3rd 2001: first version. + * - November 14th 2001: a lot of 'purifications'. + * - July 31th 2002: (debug) some guard parts are no more redundants. + * - August 12th 2002: polyhedra union ('or' conditions) are now supported. + * - October 27th 2005: polyhedra union ('or' conditions) are no more supported + * (the need came from loop_simplify that may result in + * domain unions, now it should be fixed directly in + * cloog_loop_simplify). + */ +static void insert_guard(CloogConstraintSet *constraints, int level, + struct clast_stmt ***next, CloogInfos *infos) +{ + int total_dim; + struct clast_guard_data data = { level, infos, 0 }; + + if (!constraints) + return; + + data.copy = cloog_constraint_set_copy(constraints); + + insert_extra_modulo_guards(data.copy, level, next, infos); + + cloog_constraint_set_foreach_constraint(constraints, + guard_count_bounds, &data); + + data.g = new_clast_guard(data.n); + data.n = 0; + + /* Well, it looks complicated because I wanted to have a particular, more + * readable, ordering, obviously this function may be far much simpler ! + */ + data.nb_iter = cloog_constraint_set_n_iterators(constraints, + infos->names->nb_parameters); + + /* We search for guard parts. */ + total_dim = cloog_constraint_set_total_dimension(constraints); + for (data.i = 1; data.i <= total_dim; data.i++) + cloog_constraint_set_foreach_constraint(data.copy, + insert_guard_constraint, &data); + + cloog_constraint_set_free(data.copy); + + data.g->n = data.n; + if (data.n) { + clast_guard_sort(data.g); + **next = &data.g->stmt; + *next = &data.g->then; + } else + free_clast_stmt(&data.g->stmt); +} + +/** + * Check if the constant "cst" satisfies the modulo guard that + * would be introduced by insert_computed_modulo_guard. + * The constant is assumed to have been reduced prior to calling + * this function. + */ +static int constant_modulo_guard_is_satisfied(CloogConstraint *lower, + cloog_int_t bound, cloog_int_t cst) +{ + if (cloog_constraint_is_valid(lower)) + return cloog_int_le(cst, bound); + else + return cloog_int_is_zero(cst); +} + +/** + * Insert a modulo guard "r % mod == 0" or "r % mod <= bound", + * depending on whether lower represents a valid constraint. + */ +static void insert_computed_modulo_guard(struct clast_reduction *r, + CloogConstraint *lower, cloog_int_t mod, cloog_int_t bound, + struct clast_stmt ***next) +{ + struct clast_expr *e; + struct clast_guard *g; + + e = &new_clast_binary(clast_bin_mod, &r->expr, mod)->expr; + g = new_clast_guard(1); + if (!cloog_constraint_is_valid(lower)) { + g->eq[0].LHS = e; + cloog_int_set_si(bound, 0); + g->eq[0].RHS = &new_clast_term(bound, NULL)->expr; + g->eq[0].sign = 0; + } else { + g->eq[0].LHS = e; + g->eq[0].RHS = &new_clast_term(bound, NULL)->expr; + g->eq[0].sign = -1; + } + + **next = &g->stmt; + *next = &g->then; +} + + +/* Try and eliminate coefficients from a modulo constraint based on + * stride information of an earlier level. + * The modulo of the constraint being constructed is "m". + * The stride information at level "level" is given by "stride" + * and indicated that the iterator i at level "level" is equal to + * some expression modulo stride->stride. + * If stride->stride is a multiple of "m' then i is also equal to + * the expression modulo m and so we can eliminate the coefficient of i. + * + * If stride->constraint is NULL, then i has a constant value modulo m, stored + * stride->offset. We simply multiply this constant with the coefficient + * of i and add the result to the constant term, reducing it modulo m. + * + * If stride->constraint is not NULL, then it is a constraint of the form + * + * e + k i = s a + * + * with s equal to stride->stride, e an expression in terms of the + * parameters and earlier iterators and a some arbitrary expression + * in terms of existentially quantified variables. + * stride->factor is a value f such that f * k = -1 mod s. + * Adding stride->constraint f * c times to the current modulo constraint, + * with c the coefficient of i eliminates i in favor of parameters and + * earlier variables. + */ +static void eliminate_using_stride_constraint(cloog_int_t *line, int len, + int nb_iter, CloogStride *stride, int level, cloog_int_t m) +{ + if (!stride) + return; + if (!cloog_int_is_divisible_by(stride->stride, m)) + return; + + if (stride->constraint) { + int i, s_len; + cloog_int_t t, v; + + cloog_int_init(t); + cloog_int_init(v); + cloog_int_mul(t, line[level], stride->factor); + for (i = 1; i < level; ++i) { + cloog_constraint_coefficient_get(stride->constraint, + i - 1, &v); + cloog_int_addmul(line[i], t, v); + cloog_int_fdiv_r(line[i], line[i], m); + } + s_len = cloog_constraint_total_dimension(stride->constraint)+2; + for (i = nb_iter + 1; i <= len - 2; ++i) { + cloog_constraint_coefficient_get(stride->constraint, + i - (len - s_len) - 1, &v); + cloog_int_addmul(line[i], t, v); + cloog_int_fdiv_r(line[i], line[i], m); + } + cloog_constraint_constant_get(stride->constraint, &v); + cloog_int_addmul(line[len - 1], t, v); + cloog_int_fdiv_r(line[len - 1], line[len - 1], m); + cloog_int_clear(v); + cloog_int_clear(t); + } else { + cloog_int_addmul(line[len - 1], line[level], stride->offset); + cloog_int_fdiv_r(line[len - 1], line[len - 1], m); + } + + cloog_int_set_si(line[level], 0); +} + + +/* Temporary structure for communication between insert_modulo_guard and + * its cloog_constraint_set_foreach_constraint callback function. + */ +struct clast_modulo_guard_data { + CloogConstraint *lower; + int level; + struct clast_stmt ***next; + CloogInfos *infos; + int empty; + cloog_int_t val, bound; +}; + + +/* Insert a modulo guard for constraint c. + * The constraint may be either an equality or an inequality. + * Since this function returns -1, it is only called on a single constraint. + * In case of an inequality, the constraint is usually an upper bound + * on d->level. However, if this variable is an existentially + * quantified variable, the upper bound constraint may get removed + * as trivially holding and then this function is called with + * a lower bound instead. In this case, we need to adjust the constraint + * based on the sum of the constant terms of the lower and upper bound + * stored in d->bound. + */ +static int insert_modulo_guard_constraint(CloogConstraint *c, void *user) +{ + struct clast_modulo_guard_data *d = (struct clast_modulo_guard_data *) user; + int level = d->level; + CloogInfos *infos = d->infos; + int i, nb_elts = 0, len, len2, nb_iter, nb_par; + int constant; + struct cloog_vec *line_vector; + cloog_int_t *line; + + len = cloog_constraint_total_dimension(c) + 2; + len2 = cloog_equal_total_dimension(infos->equal) + 2; + nb_par = infos->names->nb_parameters; + nb_iter = len - 2 - nb_par; + + line_vector = cloog_vec_alloc(len); + line = line_vector->p; + cloog_constraint_copy_coefficients(c, line + 1); + + if (cloog_int_is_pos(line[level])) { + cloog_seq_neg(line + 1, line + 1, len - 1); + if (!cloog_constraint_is_equality(c)) + cloog_int_add(line[len - 1], line[len - 1], d->bound); + } + cloog_int_neg(line[level], line[level]); + assert(cloog_int_is_pos(line[level])); + + nb_elts = 0; + for (i = 1; i <= len-1; ++i) { + if (i == level) + continue; + cloog_int_fdiv_r(line[i], line[i], line[level]); + if (cloog_int_is_zero(line[i])) + continue; + if (i == len-1) + continue; + + nb_elts++; + } + + if (nb_elts || !cloog_int_is_zero(line[len-1])) { + struct clast_reduction *r; + const char *name; + + r = new_clast_reduction(clast_red_sum, nb_elts + 1); + nb_elts = 0; + + /* First, the modulo guard : the iterators... */ + i = level - 1; + if (i > infos->stride_level) + i = infos->stride_level; + for (; i >= 1; --i) + eliminate_using_stride_constraint(line, len, nb_iter, + infos->stride[i - 1], i, line[level]); + for (i=1;i<=nb_iter;i++) { + if (i == level || cloog_int_is_zero(line[i])) + continue; + + name = cloog_names_name_at_level(infos->names, i); + + r->elts[nb_elts++] = &new_clast_term(line[i], + &new_clast_name(name)->expr)->expr; + } + + /* ...the parameters... */ + for (i=nb_iter+1;i<=len-2;i++) { + if (cloog_int_is_zero(line[i])) + continue; + + name = infos->names->parameters[i-nb_iter-1] ; + r->elts[nb_elts++] = &new_clast_term(line[i], + &new_clast_name(name)->expr)->expr; + } + + constant = nb_elts == 0; + /* ...the constant. */ + if (!cloog_int_is_zero(line[len-1])) + r->elts[nb_elts++] = &new_clast_term(line[len-1], NULL)->expr; + + /* our initial computation may have been an overestimate */ + r->n = nb_elts; + + if (constant) { + d->empty = !constant_modulo_guard_is_satisfied(d->lower, d->bound, + line[len - 1]); + free_clast_reduction(r); + } else + insert_computed_modulo_guard(r, d->lower, line[level], d->bound, + d->next); + } + + cloog_vec_free(line_vector); + + return -1; +} + + +/** + * insert_modulo_guard: + * This function inserts a modulo guard corresponding to an equality + * or a pair of inequalities. + * Returns 0 if the modulo guard is discovered to be unsatisfiable. + * + * See insert_equation. + * - matrix is the polyhedron containing all the constraints, + * - upper and lower are the line numbers of the constraint in matrix + * we want to print; in particular, if we want to print an equality, + * then lower == -1 and upper is the row of the equality; if we want + * to print an inequality, then upper is the row of the upper bound + * and lower in the row of the lower bound + * - level is the column number of the element in matrix we want to use, + * - the infos structure gives the user some options about code printing, + * the number of parameters in matrix (nb_par), and the arrays of iterator + * names and parameters (iters and params). + */ +static int insert_modulo_guard(CloogConstraint *upper, + CloogConstraint *lower, int level, + struct clast_stmt ***next, CloogInfos *infos) +{ + int nb_par; + CloogConstraintSet *set; + struct clast_modulo_guard_data data = { lower, level, next, infos, 0 }; + + cloog_int_init(data.val); + cloog_constraint_coefficient_get(upper, level-1, &data.val); + if (cloog_int_is_one(data.val) || cloog_int_is_neg_one(data.val)) { + cloog_int_clear(data.val); + return 1; + } + + nb_par = infos->names->nb_parameters; + + cloog_int_init(data.bound); + /* Check if would be emitting the redundant constraint mod(e,m) <= m-1 */ + if (cloog_constraint_is_valid(lower)) { + cloog_constraint_constant_get(upper, &data.val); + cloog_constraint_constant_get(lower, &data.bound); + cloog_int_add(data.bound, data.val, data.bound); + cloog_constraint_coefficient_get(lower, level-1, &data.val); + cloog_int_sub_ui(data.val, data.val, 1); + if (cloog_int_eq(data.val, data.bound)) { + cloog_int_clear(data.val); + cloog_int_clear(data.bound); + return 1; + } + } + + if (cloog_constraint_needs_reduction(upper, level)) { + set = cloog_constraint_set_for_reduction(upper, lower); + set = cloog_constraint_set_reduce(set, level, infos->equal, + nb_par, &data.bound); + cloog_constraint_set_foreach_constraint(set, + insert_modulo_guard_constraint, &data); + cloog_constraint_set_free(set); + } else + insert_modulo_guard_constraint(upper, &data); + + cloog_int_clear(data.val); + cloog_int_clear(data.bound); + + return !data.empty; +} + + +/** + * We found an equality or a pair of inequalities identifying + * a loop with a single iteration, but the user wants us to generate + * a loop anyway, so we do it here. + */ +static int insert_equation_as_loop(CloogDomain *domain, CloogConstraint *upper, + CloogConstraint *lower, int level, struct clast_stmt ***next, + CloogInfos *infos) +{ + const char *iterator = cloog_names_name_at_level(infos->names, level); + struct clast_expr *e1, *e2; + struct clast_for *f; + + e2 = clast_bound_from_constraint(upper, level, infos->names); + if (!cloog_constraint_is_valid(lower)) + e1 = clast_expr_copy(e2); + else + e1 = clast_bound_from_constraint(lower, level, infos->names); + + f = new_clast_for(domain, iterator, e1, e2, infos->stride[level-1]); + **next = &f->stmt; + *next = &f->body; + + cloog_constraint_release(lower); + cloog_constraint_release(upper); + return 1; +} + + +/** + * insert_equation function: + * This function inserts an equality + * constraint according to an element in the clast. + * Returns 1 if the calling function should recurse into inner loops. + * + * An equality can be preceded by a 'modulo guard'. + * For instance, consider the constraint i -2*j = 0 and the + * element j: pprint_equality should return 'if(i%2==0) { j = i/2 ;'. + * - matrix is the polyhedron containing all the constraints, + * - num is the line number of the constraint in matrix we want to print, + * - level is the column number of the element in matrix we want to use, + * - the infos structure gives the user some options about code printing, + * the number of parameters in matrix (nb_par), and the arrays of iterator + * names and parameters (iters and params). + ** + * - November 13th 2001: first version. + * - June 26th 2003: simplification of the modulo guards (remove parts such as + * modulo is 0, compare vivien or vivien2 with a previous + * version for an idea). + * - June 29th 2003: non-unit strides support. + * - July 14th 2003: (debug) no more print the constant in the modulo guard when + * it was previously included in a stride calculation. + */ +static int insert_equation(CloogDomain *domain, CloogConstraint *upper, + CloogConstraint *lower, int level, struct clast_stmt + ***next, CloogInfos *infos) +{ + struct clast_expr *e; + struct clast_assignment *ass; + + if (!infos->options->otl) + return insert_equation_as_loop(domain, upper, lower, level, next, infos); + + if (!insert_modulo_guard(upper, lower, level, next, infos)) { + cloog_constraint_release(lower); + cloog_constraint_release(upper); + + return 0; + } + + if (cloog_constraint_is_valid(lower) || + !clast_equal_add(infos->equal, NULL, level, upper, infos)) + { /* Finally, the equality. */ + + /* If we have to make a block by dimension, we start the block. Function + * pprint knows if there is an equality, if this is the case, it checks + * for the same following condition to close the brace. + */ + if (infos->options->block) { + struct clast_block *b = new_clast_block(); + **next = &b->stmt; + *next = &b->body; + } + + e = clast_bound_from_constraint(upper, level, infos->names); + ass = new_clast_assignment(cloog_names_name_at_level(infos->names, level), e); + + **next = &ass->stmt; + *next = &(**next)->next; + } + + cloog_constraint_release(lower); + cloog_constraint_release(upper); + + return 1; +} + + +/** + * Insert a loop that is executed exactly once as an assignment. + * In particular, the loop + * + * for (i = e; i <= e; ++i) { + * S; + * } + * + * is generated as + * + * i = e; + * S; + * + */ +static void insert_otl_for(CloogConstraintSet *constraints, int level, + struct clast_expr *e, struct clast_stmt ***next, CloogInfos *infos) +{ + const char *iterator; + + iterator = cloog_names_name_at_level(infos->names, level); + + if (!clast_equal_add(infos->equal, constraints, level, + cloog_constraint_invalid(), infos)) { + struct clast_assignment *ass; + if (infos->options->block) { + struct clast_block *b = new_clast_block(); + **next = &b->stmt; + *next = &b->body; + } + ass = new_clast_assignment(iterator, e); + **next = &ass->stmt; + *next = &(**next)->next; + } else { + free_clast_expr(e); + } +} + + +/** + * Insert a loop that is executed at most once as an assignment followed + * by a guard. In particular, the loop + * + * for (i = e1; i <= e2; ++i) { + * S; + * } + * + * is generated as + * + * i = e1; + * if (i <= e2) { + * S; + * } + * + */ +static void insert_guarded_otl_for(CloogConstraintSet *constraints, int level, + struct clast_expr *e1, struct clast_expr *e2, + struct clast_stmt ***next, CloogInfos *infos) +{ + const char *iterator; + struct clast_assignment *ass; + struct clast_guard *guard; + + iterator = cloog_names_name_at_level(infos->names, level); + + if (infos->options->block) { + struct clast_block *b = new_clast_block(); + **next = &b->stmt; + *next = &b->body; + } + ass = new_clast_assignment(iterator, e1); + **next = &ass->stmt; + *next = &(**next)->next; + + guard = new_clast_guard(1); + guard->eq[0].sign = -1; + guard->eq[0].LHS = &new_clast_term(infos->state->one, + &new_clast_name(iterator)->expr)->expr; + guard->eq[0].RHS = e2; + + **next = &guard->stmt; + *next = &guard->then; +} + + +/** + * insert_for function: + * This function inserts a for loop in the clast. + * Returns 1 if the calling function should recurse into inner loops. + * + * A loop header according to an element is the conjunction of a minimum and a + * maximum on a given element (they give the loop bounds). + * For instance, considering these constraints and the element j: + * i + j -9*M >= 0 + * -j +5*M >= 0 + * j -4*M >= 0 + * this function should return 'for (j=max(-i+9*M,4*M),j<=5*M;j++) {'. + * - constraints contains all constraints, + * - level is the column number of the element in matrix we want to use, + * - otl is set if the loop is executed at most once, + * - the infos structure gives the user some options about code printing, + * the number of parameters in matrix (nb_par), and the arrays of iterator + * names and parameters (iters and params). + */ +static int insert_for(CloogDomain *domain, CloogConstraintSet *constraints, + int level, int otl, struct clast_stmt ***next, + CloogInfos *infos) +{ + const char *iterator; + struct clast_expr *e1; + struct clast_expr *e2; + + e1 = clast_minmax(constraints, level, 1, 0, 1, infos); + e2 = clast_minmax(constraints, level, 0, 0, 0, infos); + + if (clast_expr_is_bigger_constant(e1, e2)) { + free_clast_expr(e1); + free_clast_expr(e2); + return 0; + } + + /* If min and max are not equal there is a 'for' else, there is a '='. + * In the special case e1 = e2 = NULL, this is an infinite loop + * so this is not a '='. + */ + if (e1 && e2 && infos->options->otl && clast_expr_equal(e1, e2)) { + free_clast_expr(e2); + insert_otl_for(constraints, level, e1, next, infos); + } else if (otl) { + insert_guarded_otl_for(constraints, level, e1, e2, next, infos); + } else { + struct clast_for *f; + iterator = cloog_names_name_at_level(infos->names, level); + + f = new_clast_for(domain, iterator, e1, e2, infos->stride[level-1]); + **next = &f->stmt; + *next = &f->body; + } + + return 1; +} + + +/** + * insert_block function: + * This function inserts a statement block. + * - block is the statement block, + * - level is the number of loops enclosing the statement, + * - the infos structure gives the user some options about code printing, + * the number of parameters in domain (nb_par), and the arrays of iterator + * names and parameters (iters and params). + ** + * - September 21th 2003: first version (pick from pprint function). + */ +static void insert_block(CloogDomain *domain, CloogBlock *block, int level, + struct clast_stmt ***next, CloogInfos *infos) +{ + CloogStatement * statement ; + struct clast_stmt *subs; + + if (!block) + return; + + for (statement = block->statement; statement; statement = statement->next) { + CloogStatement *s_next = statement->next; + + subs = clast_equal(level,infos); + + statement->next = NULL; + **next = &new_clast_user_stmt(domain, statement, subs)->stmt; + statement->next = s_next; + *next = &(**next)->next; + } +} + + +/** + * insert_loop function: + * This function converts the content of a CloogLoop structure (loop) into a + * clast_stmt (inserted at **next). + * The iterator (level) of + * the current loop is given by 'level': this is the column number of the + * domain corresponding to the current loop iterator. The data of a loop are + * written in this order: + * 1. The guard of the loop, i.e. each constraint in the domain that does not + * depend on the iterator (when the entry in the column 'level' is 0). + * 2. The iteration domain of the iterator, given by the constraints in the + * domain depending on the iterator, i.e.: + * * an equality if the iterator has only one value (possibly preceded by + * a guard verifying if this value is integral), *OR* + * * a loop from the minimum possible value of the iterator to the maximum + * possible value. + * 3. The included statement block. + * 4. The inner loops (recursive call). + * 5. The following loops (recursive call). + * - level is the recursion level or the iteration level that we are printing, + * - the infos structure gives the user some options about code printing, + * the number of parameters in domain (nb_par), and the arrays of iterator + * names and parameters (iters and params). + ** + * - November 2nd 2001: first version. + * - March 6th 2003: infinite domain support. + * - April 19th 2003: (debug) NULL loop support. + * - June 29th 2003: non-unit strides support. + * - April 28th 2005: (debug) level is level+equality when print statement! + * - June 16th 2005: (debug) the N. Vasilache normalization step has been + * added to avoid iteration duplication (see DaeGon Kim + * bug in cloog_program_generate). Try vasilache.cloog + * with and without the call to cloog_polylib_matrix_normalize, + * using -f 8 -l 9 options for an idea. + * - September 15th 2005: (debug) don't close equality braces when unnecessary. + * - October 16th 2005: (debug) scalar value is saved for next loops. + */ +static void insert_loop(CloogLoop * loop, int level, + struct clast_stmt ***next, CloogInfos *infos) +{ + int equality = 0; + CloogConstraintSet *constraints, *temp; + struct clast_stmt **top = *next; + CloogConstraint *i, *j; + int empty_loop = 0; + + /* It can happen that loop be NULL when an input polyhedron is empty. */ + if (loop == NULL) + return; + + /* The constraints do not always have a shape that allows us to generate code from it, + * thus we normalize it, we also simplify it with the equalities. + */ + temp = cloog_domain_constraints(loop->domain); + cloog_constraint_set_normalize(temp,level); + constraints = cloog_constraint_set_simplify(temp,infos->equal,level, + infos->names->nb_parameters); + cloog_constraint_set_free(temp); + if (level) { + infos->stride[level - 1] = loop->stride; + infos->stride_level++; + } + + /* First of all we have to print the guard. */ + insert_guard(constraints,level, next, infos); + + if (level && cloog_constraint_set_contains_level(constraints, level, + infos->names->nb_parameters)) { + /* We scan all the constraints to know in which case we are : + * [[if] equation] or [for]. + */ + if (cloog_constraint_is_valid(i = + cloog_constraint_set_defining_equality(constraints, level))) { + empty_loop = !insert_equation(loop->unsimplified, i, + cloog_constraint_invalid(), level, next, + infos); + equality = 1 ; + } else if (cloog_constraint_is_valid(i = + cloog_constraint_set_defining_inequalities(constraints, + level, &j, infos->names->nb_parameters))) { + empty_loop = !insert_equation(loop->unsimplified, i, j, level, next, + infos); + } else + empty_loop = !insert_for(loop->unsimplified, constraints, level, + loop->otl, next, infos); + } + + if (!empty_loop) { + /* Finally, if there is an included statement block, print it. */ + insert_block(loop->unsimplified, loop->block, level+equality, next, infos); + + /* Go to the next level. */ + if (loop->inner != NULL) + insert_loop(loop->inner, level+1, next, infos); + } + + if (level) { + cloog_equal_del(infos->equal,level); + infos->stride_level--; + } + cloog_constraint_set_free(constraints); + + /* Go to the next loop on the same level. */ + while (*top) + top = &(*top)->next; + if (loop->next != NULL) + insert_loop(loop->next, level, &top,infos); +} + + +struct clast_stmt *cloog_clast_create(CloogProgram *program, + CloogOptions *options) +{ + CloogInfos *infos = ALLOC(CloogInfos); + int nb_levels; + struct clast_stmt *root = &new_clast_root(program->names)->stmt; + struct clast_stmt **next = &root->next; + + infos->state = options->state; + infos->names = program->names; + infos->options = options; + infos->scaldims = program->scaldims; + infos->nb_scattdims = program->nb_scattdims; + + /* Allocation for the array of strides, there is a +1 since the statement can + * be included inside an external loop without iteration domain. + */ + nb_levels = program->names->nb_scattering+program->names->nb_iterators+1; + infos->stride = ALLOCN(CloogStride *, nb_levels); + infos->stride_level = 0; + + infos->equal = cloog_equal_alloc(nb_levels, + nb_levels, program->names->nb_parameters); + + insert_loop(program->loop, 0, &next, infos); + + cloog_equal_free(infos->equal); + + free(infos->stride); + free(infos); + + return root; +} + + +struct clast_stmt *cloog_clast_create_from_input(CloogInput *input, + CloogOptions *options) +{ + CloogProgram *program; + struct clast_stmt *root; + + program = cloog_program_alloc(input->context, input->ud, options); + free(input); + + program = cloog_program_generate(program, options); + + root = cloog_clast_create(program, options); + cloog_program_free(program); + + return root; +} diff --git a/cloog-core/source/cloog.c b/cloog-core/source/cloog.c new file mode 100644 index 0000000..0a42a67 --- /dev/null +++ b/cloog-core/source/cloog.c @@ -0,0 +1,98 @@ + + /**-------------------------------------------------------------------** + ** CLooG ** + **-------------------------------------------------------------------** + ** cloog.c ** + **-------------------------------------------------------------------** + ** First version: october 25th 2001, CLooG's birth date ! ** + **-------------------------------------------------------------------**/ + + +/****************************************************************************** + * 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 * + * * + ******************************************************************************/ + + +# include <stdlib.h> +# include <stdio.h> +# include "../include/cloog/cloog.h" + + +int main(int argv, char * argc[]) +{ CloogProgram * program ; + CloogOptions * options ; + CloogState *state; + FILE * input, * output ; + + state = cloog_state_malloc(); + + /* Options and input/output file setting. */ + cloog_options_read(state, argv, argc, &input, &output, &options); + + /* Reading the program informations. */ + program = cloog_program_read(input,options) ; + fclose(input) ; + + /* Generating and printing the code. */ + program = cloog_program_generate(program,options) ; + if (options->structure) + cloog_program_print(stdout,program) ; + cloog_program_pprint(output,program,options) ; + cloog_program_free(program) ; + + /* Printing the allocation statistics if asked. */ + if (options->leaks) { + fprintf(output,"/* Domains : allocated=%5d, freed=%5d, max=%5d. */\n", + state->domain_allocated, state->domain_freed, state->domain_max); + fprintf(output,"/* Loops : allocated=%5d, freed=%5d, max=%5d. */\n", + state->loop_allocated, state->loop_freed, state->loop_max); + fprintf(output,"/* Statements : allocated=%5d, freed=%5d, max=%5d. */\n", + state->statement_allocated, state->statement_freed, state->statement_max); + fprintf(output,"/* Blocks : allocated=%5d, freed=%5d, max=%5d. */\n", + state->block_allocated, state->block_freed, state->block_max); + } + + /* Inform the user in case of a problem with the allocation statistics. */ + if ((state->domain_allocated != state->domain_freed) || + (state->loop_allocated != state->loop_freed) || + (state->statement_allocated != state->statement_freed) || + (state->block_allocated != state->block_freed)) + { + cloog_msg(options, CLOOG_INFO, + "an internal problem has been detected (it should have" + " no\n consequence on the correctness of the output)." + " Please send (if\n you can) your input file, the first line " + "given by typing 'cloog -v'\n and your full command " + "line call to CLooG including options to\n <cedric.bastoul" + "@inria.fr>. Thank you for your participation to get\n" + " CLooG better and safer.\n") ; + } + + cloog_options_free(options) ; + cloog_state_free(state); + fclose(output) ; + return 0; +} + diff --git a/cloog-core/source/input.c b/cloog-core/source/input.c new file mode 100644 index 0000000..1b83a97 --- /dev/null +++ b/cloog-core/source/input.c @@ -0,0 +1,177 @@ +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include "../include/cloog/cloog.h" + +#define ALLOC(type) (type*)malloc(sizeof(type)) + +static char *next_line(FILE *input, char *line, unsigned len) +{ + char *p; + + do { + if (!(p = fgets(line, len, input))) + return NULL; + while (isspace(*p) && *p != '\n') + ++p; + } while (*p == '#' || *p == '\n'); + + return p; +} + +/** + * Read input from a .cloog file, putting most of the information + * in the returned CloogInput. The chosen language is put in + * options->language. + */ +CloogInput *cloog_input_read(FILE *file, CloogOptions *options) +{ + char line[MAX_STRING]; + char language; + CloogDomain *context; + CloogUnionDomain *ud; + int nb_par; + + /* First of all, we read the language to use. */ + if (!next_line(file, line, sizeof(line))) + cloog_die("Input error.\n"); + if (sscanf(line, "%c", &language) != 1) + cloog_die("Input error.\n"); + + if (language == 'f') + options->language = LANGUAGE_FORTRAN; + else + options->language = LANGUAGE_C; + + /* We then read the context data. */ + context = cloog_domain_read_context(options->state, file); + nb_par = cloog_domain_parameter_dimension(context); + + ud = cloog_union_domain_read(file, nb_par, options); + + return cloog_input_alloc(context, ud); +} + +/** + * Create a CloogInput from a CloogDomain context and a CloogUnionDomain. + */ +CloogInput *cloog_input_alloc(CloogDomain *context, CloogUnionDomain *ud) +{ + CloogInput *input; + + input = ALLOC(CloogInput); + if (!input) + cloog_die("memory overflow.\n"); + + input->context = context; + input->ud = ud; + + return input; +} + +void cloog_input_free(CloogInput *input) +{ + cloog_domain_free(input->context); + cloog_union_domain_free(input->ud); + free(input); +} + +static void print_names(FILE *file, CloogUnionDomain *ud, + enum cloog_dim_type type, const char *name) +{ + int i; + + fprintf(file, "\n%d # %s name(s)\n", ud->name[type] ? 1 : 0, name); + if (!ud->name[type]) + return; + + for (i = 0; i < ud->n_name[type]; i++) + fprintf(file, "%s ", ud->name[type][i]); + + fprintf(file, "\n"); +} + +/** + * Dump the .cloog description of a CloogInput and a CloogOptions data structure + * into a file. The generated .cloog file will contain the same information as + * the data structures. The file can be used to run the cloog program on the + * example. + */ +void cloog_input_dump_cloog(FILE *file, CloogInput *input, CloogOptions *opt) +{ + int i, num_statements; + CloogUnionDomain *ud = input->ud; + CloogNamedDomainList *ndl = ud->domain; + + fprintf(file, + "# CLooG -> CLooG\n" + "# This is an automatic dump of a CLooG input file from a " + "CloogInput data\n" + "# structure.\n\n"); + + /* Language. */ + if (opt->language == LANGUAGE_FORTRAN) { + fprintf(file, "# Language: FORTRAN\n"); + fprintf(file, "f\n\n"); + } else { + fprintf(file, "# Language: C\n"); + fprintf(file, "c\n\n"); + } + + /* Context. */ + fprintf(file, "# Context:\n"); + cloog_domain_print_constraints(file, input->context, 1); + + print_names(file, ud, CLOOG_PARAM, "Parameter"); + + /* Statement number. */ + i = 0; + while (ndl != NULL) { + i++; + ndl = ndl->next; + } + num_statements = i; + fprintf(file, "\n# Statement number:\n%d\n\n", num_statements); + + /* Iteration domains. */ + i = 1; + ndl = ud->domain; + while (ndl != NULL) { + fprintf(file, "# Iteration domain of statement %d (%s).\n", i, + ndl->name); + + cloog_domain_print_constraints(file, ndl->domain, 1); + fprintf(file,"\n0 0 0 # For future options.\n\n"); + + i++; + ndl = ndl->next; + } + + print_names(file, ud, CLOOG_ITER, "Iterator"); + + /* Exit, if no scattering is supplied. */ + if (!ud->domain || !ud->domain->scattering) { + fprintf(file, "# No scattering functions.\n0\n\n"); + return; + } + + /* Scattering relations. */ + fprintf(file, + "# --------------------- SCATTERING --------------------\n"); + + fprintf(file, "%d # Scattering functions\n", num_statements); + + i = 1; + ndl = ud->domain; + while (ndl != NULL) { + fprintf(file, "\n# Scattering of statement %d (%s).\n", i, + ndl->name); + + cloog_scattering_print_constraints(file, ndl->scattering); + + i++; + ndl = ndl->next; + } + + print_names(file, ud, CLOOG_SCAT, "Scattering dimension"); +} diff --git a/cloog-core/source/int.c b/cloog-core/source/int.c new file mode 100644 index 0000000..67f62df --- /dev/null +++ b/cloog-core/source/int.c @@ -0,0 +1,177 @@ +#include <stdlib.h> +#include "../include/cloog/cloog.h" + +#define ALLOC(type) (type*)malloc(sizeof(type)) +#define ALLOCN(type,n) (type*)malloc((n)*sizeof(type)) + +#if defined(CLOOG_INT_INT) || \ + defined(CLOOG_INT_LONG) || \ + defined(CLOOG_INT_LONG_LONG) + +cloog_int_t cloog_gcd(cloog_int_t a, cloog_int_t b) +{ + while (a) { + cloog_int_t t = b % a; + b = a; + a = t; + } + if (b < 0) + b = -b; + return b; +} + +#endif + +struct cloog_vec *cloog_vec_alloc(unsigned size) +{ + int i; + struct cloog_vec *vec; + + vec = ALLOC(struct cloog_vec); + if (!vec) + return NULL; + + vec->p = ALLOCN(cloog_int_t, size); + if (!vec->p) + goto error; + vec->size = size; + + for (i = 0; i < size; ++i) + cloog_int_init(vec->p[i]); + + return vec; +error: + free(vec); + return NULL; +} + +void cloog_vec_free(struct cloog_vec *vec) +{ + int i; + + if (!vec) + return; + + for (i = 0; i < vec->size; ++i) + cloog_int_clear(vec->p[i]); + free(vec->p); + free(vec); +} + +void cloog_vec_dump(struct cloog_vec *vec) +{ + int i; + + for (i = 0; i < vec->size; ++i) { + cloog_int_print(stderr, vec->p[i]); + fprintf(stderr, " "); + } + fprintf(stderr, "\n"); +} + +int cloog_seq_first_non_zero(cloog_int_t *p, unsigned len) +{ + int i; + + for (i = 0; i < len; ++i) + if (!cloog_int_is_zero(p[i])) + return i; + return -1; +} + +void cloog_seq_neg(cloog_int_t *dst, cloog_int_t *src, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + cloog_int_neg(dst[i], src[i]); +} + +void cloog_seq_cpy(cloog_int_t *dst, cloog_int_t *src, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + cloog_int_set(dst[i], src[i]); +} + +static void cloog_seq_scale_down(cloog_int_t *dst, cloog_int_t *src, cloog_int_t m, unsigned len) +{ + int i; + for (i = 0; i < len; ++i) + cloog_int_divexact(dst[i], src[i], m); +} + +void cloog_seq_combine(cloog_int_t *dst, cloog_int_t m1, cloog_int_t *src1, + cloog_int_t m2, cloog_int_t *src2, unsigned len) +{ + int i; + cloog_int_t tmp; + + cloog_int_init(tmp); + for (i = 0; i < len; ++i) { + cloog_int_mul(tmp, m1, src1[i]); + cloog_int_addmul(tmp, m2, src2[i]); + cloog_int_set(dst[i], tmp); + } + cloog_int_clear(tmp); +} + +static int cloog_seq_abs_min_non_zero(cloog_int_t *p, unsigned len) +{ + int i, min = cloog_seq_first_non_zero(p, len); + if (min < 0) + return -1; + for (i = min + 1; i < len; ++i) { + if (cloog_int_is_zero(p[i])) + continue; + if (cloog_int_abs_lt(p[i], p[min])) + min = i; + } + return min; +} + +void cloog_seq_gcd(cloog_int_t *p, unsigned len, cloog_int_t *gcd) +{ + int i, min = cloog_seq_abs_min_non_zero(p, len); + + if (min < 0) { + cloog_int_set_si(*gcd, 0); + return; + } + cloog_int_abs(*gcd, p[min]); + for (i = 0; cloog_int_cmp_si(*gcd, 1) > 0 && i < len; ++i) { + if (i == min) + continue; + if (cloog_int_is_zero(p[i])) + continue; + cloog_int_gcd(*gcd, *gcd, p[i]); + } +} + +int cloog_seq_is_neg(cloog_int_t *p1, cloog_int_t *p2, unsigned len) +{ + int i; + + for (i = 0; i < len; ++i) { + if (cloog_int_abs_ne(p1[i], p2[i])) + return 0; + if (cloog_int_is_zero(p1[i])) + continue; + if (cloog_int_eq(p1[i], p2[i])) + return 0; + } + return 1; +} + +void cloog_seq_normalize(cloog_int_t *p, unsigned len) +{ + cloog_int_t gcd; + + if (len == 0) + return; + + cloog_int_init(gcd); + cloog_seq_gcd(p, len, &gcd); + if (!cloog_int_is_zero(gcd) && !cloog_int_is_one(gcd)) + cloog_seq_scale_down(p, p, gcd, len); + cloog_int_clear(gcd); +} diff --git a/cloog-core/source/isl/backend.c b/cloog-core/source/isl/backend.c new file mode 100644 index 0000000..6ddb9f9 --- /dev/null +++ b/cloog-core/source/isl/backend.c @@ -0,0 +1,37 @@ +#include <cloog/isl/cloog.h> + +/** + * Allocate and initialize full state. + */ +CloogState *cloog_state_malloc(void) +{ + return cloog_isl_state_malloc(NULL); +} + +/** + * Allocate and initialize full state for isl backend. + */ +CloogState *cloog_isl_state_malloc(struct isl_ctx *ctx) +{ + CloogState *state; + int allocated = !ctx; + + state = cloog_core_state_malloc(); + if (!ctx) + ctx = isl_ctx_alloc(); + state->backend = isl_alloc_type(ctx, CloogBackend); + state->backend->ctx = ctx; + state->backend->ctx_allocated = allocated; + return state; +} + +/** + * Free state and backend independent parts. + */ +void cloog_state_free(CloogState *state) +{ + if (state->backend->ctx_allocated) + isl_ctx_free(state->backend->ctx); + free(state->backend); + cloog_core_state_free(state); +} diff --git a/cloog-core/source/isl/constraints.c b/cloog-core/source/isl/constraints.c new file mode 100644 index 0000000..9893c61 --- /dev/null +++ b/cloog-core/source/isl/constraints.c @@ -0,0 +1,804 @@ +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <cloog/isl/cloog.h> +#include <cloog/isl/backend.h> +#include <isl/set.h> + + +#define ALLOC(type) (type*)malloc(sizeof(type)) +#define ALLOCN(type,n) (type*)malloc((n)*sizeof(type)) + +CloogConstraintSet *cloog_constraint_set_from_isl_basic_set(struct isl_basic_set *bset) +{ + return (CloogConstraintSet *)bset; +} + +CloogConstraint *cloog_constraint_from_isl_constraint(struct isl_constraint *constraint) +{ + return (CloogConstraint *)constraint; +} + +isl_basic_set *cloog_constraints_set_to_isl(CloogConstraintSet *constraints) +{ + return (isl_basic_set *)constraints; +} + + +/****************************************************************************** + * Memory leaks hunting * + ******************************************************************************/ + + + +void cloog_constraint_set_free(CloogConstraintSet *constraints) +{ + isl_basic_set_free(cloog_constraints_set_to_isl(constraints)); +} + + +int cloog_constraint_set_contains_level(CloogConstraintSet *constraints, + int level, int nb_parameters) +{ + isl_basic_set *bset; + bset = cloog_constraints_set_to_isl(constraints); + return isl_basic_set_dim(bset, isl_dim_set) >= level; +} + +struct cloog_isl_dim { + enum isl_dim_type type; + int pos; +}; + +static struct cloog_isl_dim basic_set_cloog_dim_to_isl_dim( + __isl_keep isl_basic_set *bset, int pos) +{ + enum isl_dim_type types[] = { isl_dim_set, isl_dim_div, isl_dim_param }; + int i; + struct cloog_isl_dim ci_dim; + + for (i = 0; i < 3; ++i) { + unsigned dim = isl_basic_set_dim(bset, types[i]); + if (pos < dim) { + ci_dim.type = types[i]; + ci_dim.pos = pos; + return ci_dim; + } + pos -= dim; + } + assert(0); +} + +static struct cloog_isl_dim set_cloog_dim_to_isl_dim( + CloogConstraintSet *constraints, int pos) +{ + isl_basic_set *bset; + + bset = cloog_constraints_set_to_isl(constraints); + return basic_set_cloog_dim_to_isl_dim(bset, pos); +} + +/* Check if the variable at position level is defined by an + * equality. If so, return the row number. Otherwise, return -1. + */ +CloogConstraint *cloog_constraint_set_defining_equality( + CloogConstraintSet *constraints, int level) +{ + struct isl_constraint *c; + struct cloog_isl_dim dim; + isl_basic_set *bset; + + bset = cloog_constraints_set_to_isl(constraints); + dim = set_cloog_dim_to_isl_dim(constraints, level - 1); + if (isl_basic_set_has_defining_equality(bset, dim.type, dim.pos, &c)) + return cloog_constraint_from_isl_constraint(c); + else + return NULL; +} + + +/* Check if the variable (e) at position level is defined by a + * pair of inequalities + * <a, i> + -m e + <b, p> + k1 >= 0 + * <-a, i> + m e + <-b, p> + k2 >= 0 + * with 0 <= k1 + k2 < m + * If so return the row number of the upper bound and set *lower + * to the row number of the lower bound. If not, return -1. + * + * If the variable at position level occurs in any other constraint, + * then we currently return -1. The modulo guard that we would generate + * would still be correct, but we would also need to generate + * guards corresponding to the other constraints, and this has not + * been implemented yet. + */ +CloogConstraint *cloog_constraint_set_defining_inequalities( + CloogConstraintSet *constraints, + int level, CloogConstraint **lower, int nb_par) +{ + struct isl_constraint *u; + struct isl_constraint *l; + struct isl_constraint *c; + struct cloog_isl_dim dim; + struct isl_basic_set *bset; + + bset = cloog_constraints_set_to_isl(constraints); + dim = set_cloog_dim_to_isl_dim(constraints, level - 1); + if (!isl_basic_set_has_defining_inequalities(bset, dim.type, dim.pos, + &l, &u)) + return cloog_constraint_invalid(); + for (c = isl_basic_set_first_constraint(isl_basic_set_copy(bset)); c; + c = isl_constraint_next(c)) { + if (isl_constraint_is_equal(c, l)) + continue; + if (isl_constraint_is_equal(c, u)) + continue; + *lower = cloog_constraint_from_isl_constraint(c); + if (cloog_constraint_involves(*lower, level-1)) { + isl_constraint_free(l); + isl_constraint_free(u); + *lower = NULL; + isl_constraint_free(c); + return NULL; + } + } + *lower = cloog_constraint_from_isl_constraint(l); + return cloog_constraint_from_isl_constraint(u); +} + +int cloog_constraint_set_total_dimension(CloogConstraintSet *constraints) +{ + isl_basic_set *bset; + bset = cloog_constraints_set_to_isl(constraints); + return isl_basic_set_total_dim(bset); +} + +int cloog_constraint_set_n_iterators(CloogConstraintSet *constraints, int n_par) +{ + isl_basic_set *bset; + bset = cloog_constraints_set_to_isl(constraints); + return isl_basic_set_dim(bset, isl_dim_set); +} + + +/****************************************************************************** + * Equalities spreading functions * + ******************************************************************************/ + + +/* Equalities are stored inside a Matrix data structure called "equal". + * This matrix has (nb_scattering + nb_iterators + 1) rows (i.e. total + * dimensions + 1, the "+ 1" is because a statement can be included inside an + * external loop without iteration domain), and (nb_scattering + nb_iterators + + * nb_parameters + 2) columns (all unknowns plus the scalar plus the equality + * type). The ith row corresponds to the equality "= 0" for the ith dimension + * iterator. The first column gives the equality type (0: no equality, then + * EQTYPE_* -see pprint.h-). At each recursion of pprint, if an equality for + * the current level is found, the corresponding row is updated. Then the + * equality if it exists is used to simplify expressions (e.g. if we have + * "i+1" while we know that "i=2", we simplify it in "3"). At the end of + * the pprint call, the corresponding row is reset to zero. + */ + +CloogEqualities *cloog_equal_alloc(int n, int nb_levels, int nb_parameters) +{ + int i; + CloogEqualities *equal = ALLOC(CloogEqualities); + + equal->total_dim = nb_levels - 1 + nb_parameters; + equal->n = n; + equal->constraints = ALLOCN(CloogConstraintSet *, n); + equal->types = ALLOCN(int, n); + for (i = 0; i < n; ++i) { + equal->constraints[i] = NULL; + equal->types[i] = EQTYPE_NONE; + } + return equal; +} + +int cloog_equal_total_dimension(CloogEqualities *equal) +{ + return equal->total_dim; +} + +void cloog_equal_free(CloogEqualities *equal) +{ + int i; + isl_basic_set *bset; + + for (i = 0; i < equal->n; ++i) { + bset = cloog_constraints_set_to_isl(equal->constraints[i]); + isl_basic_set_free(bset); + } + free(equal->constraints); + free(equal->types); + free(equal); +} + +int cloog_equal_count(CloogEqualities *equal) +{ + return equal->n; +} + + +/** + * cloog_constraint_equal_type function : + * This function returns the type of the equality in the constraint (line) of + * (constraints) for the element (level). An equality is 'constant' iff all + * other factors are null except the constant one. It is a 'pure item' iff + * it is equal or opposite to a single variable or parameter. + * Otherwise it is an 'affine expression'. + * For instance: + * i = -13 is constant, i = j, j = -M are pure items, + * j = 2*M, i = j+1, 2*j = M are affine expressions. + * + * - constraints is the matrix of constraints, + * - level is the column number in equal of the element which is 'equal to', + */ +static int cloog_constraint_equal_type(CloogConstraint *cc, int level) +{ + int i; + isl_int c; + int type = EQTYPE_NONE; + struct isl_constraint *constraint = &cc->isl; + + isl_int_init(c); + isl_constraint_get_constant(constraint, &c); + if (!isl_int_is_zero(c)) + type = EQTYPE_CONSTANT; + isl_constraint_get_coefficient(constraint, isl_dim_set, level - 1, &c); + if (!isl_int_is_one(c) && !isl_int_is_negone(c)) + type = EQTYPE_EXAFFINE; + for (i = 0; i < isl_constraint_dim(constraint, isl_dim_param); ++i) { + isl_constraint_get_coefficient(constraint, isl_dim_param, i, &c); + if (isl_int_is_zero(c)) + continue; + if ((!isl_int_is_one(c) && !isl_int_is_negone(c)) || + type != EQTYPE_NONE) { + type = EQTYPE_EXAFFINE; + break; + } + type = EQTYPE_PUREITEM; + } + for (i = 0; i < isl_constraint_dim(constraint, isl_dim_set); ++i) { + if (i == level - 1) + continue; + isl_constraint_get_coefficient(constraint, isl_dim_set, i, &c); + if (isl_int_is_zero(c)) + continue; + if ((!isl_int_is_one(c) && !isl_int_is_negone(c)) || + type != EQTYPE_NONE) { + type = EQTYPE_EXAFFINE; + break; + } + type = EQTYPE_PUREITEM; + } + for (i = 0; i < isl_constraint_dim(constraint, isl_dim_div); ++i) { + isl_constraint_get_coefficient(constraint, isl_dim_div, i, &c); + if (isl_int_is_zero(c)) + continue; + if ((!isl_int_is_one(c) && !isl_int_is_negone(c)) || + type != EQTYPE_NONE) { + type = EQTYPE_EXAFFINE; + break; + } + type = EQTYPE_PUREITEM; + } + isl_int_clear(c); + + if (type == EQTYPE_NONE) + type = EQTYPE_CONSTANT; + + return type; +} + + +int cloog_equal_type(CloogEqualities *equal, int level) +{ + return equal->types[level-1]; +} + + +/** + * cloog_equal_add function: + * This function updates the row (level-1) of the equality matrix (equal) with + * the row that corresponds to the row (line) of the matrix (matrix). + * - equal is the matrix of equalities, + * - matrix is the matrix of constraints, + * - level is the column number in matrix of the element which is 'equal to', + * - line is the line number in matrix of the constraint we want to study, + * - the infos structure gives the user all options on code printing and more. + ** + * line is set to an invalid constraint for equalities that CLooG itself has + * discovered because the lower and upper bound of a loop happened to be equal. + * This situation shouldn't happen in the isl port since isl should + * have found the equality itself. + */ +void cloog_equal_add(CloogEqualities *equal, CloogConstraintSet *matrix, + int level, CloogConstraint *line, int nb_par) +{ + struct isl_basic_set *bset; + unsigned nparam; + assert(cloog_constraint_is_valid(line)); + + equal->types[level-1] = cloog_constraint_equal_type(line, level); + bset = isl_basic_set_from_constraint(isl_constraint_copy(&line->isl)); + nparam = isl_basic_set_n_param(bset); + bset = isl_basic_set_extend(bset, nparam, + equal->total_dim - nparam, 0, 0, 0); + bset = isl_basic_set_finalize(bset); + equal->constraints[level-1] = + cloog_constraint_set_from_isl_basic_set(bset); +} + + +/** + * cloog_equal_del function : + * This function reset the equality corresponding to the iterator (level) + * in the equality matrix (equal). + * - July 2nd 2002: first version. + */ +void cloog_equal_del(CloogEqualities *equal, int level) +{ + isl_basic_set *bset; + bset = cloog_constraints_set_to_isl(equal->constraints[level - 1]); + equal->types[level-1] = EQTYPE_NONE; + isl_basic_set_free(bset); + equal->constraints[level-1] = NULL; +} + + + +/****************************************************************************** + * Processing functions * + ******************************************************************************/ + +/** + * Function cloog_constraint_set_normalize: + * This function will modify the constraint system in such a way that when + * there is an equality depending on the element at level 'level', there are + * no more (in)equalities depending on this element. + * + * The simplified form of isl automatically satisfies this condition. + */ +void cloog_constraint_set_normalize(CloogConstraintSet *matrix, int level) +{ +} + + + +/** + * cloog_constraint_set_copy function: + * this functions builds and returns a "hard copy" (not a pointer copy) of a + * CloogConstraintSet data structure. + */ +CloogConstraintSet *cloog_constraint_set_copy(CloogConstraintSet *constraints) +{ + isl_basic_set *bset; + bset = cloog_constraints_set_to_isl(constraints); + return cloog_constraint_set_from_isl_basic_set(isl_basic_set_dup(bset)); +} + + +/** + * cloog_constraint_set_simplify function: + * this function simplify all constraints inside the matrix "matrix" thanks to + * an equality matrix "equal" that gives for some elements of the affine + * constraint an equality with other elements, preferably constants. + * For instance, if a row of the matrix contains i+j+3>=0 and the equality + * matrix gives i=n and j=2, the constraint is simplified to n+3>=0. The + * simplified constraints are returned back inside a new simplified matrix. + * - matrix is the set of constraints to simplify, + * - equal is the matrix of equalities, + * - level is a level we don't want to simplify (-1 if none), + * - nb_par is the number of parameters of the program. + ** + * isl should have performed these simplifications already in isl_set_gist. + */ +CloogConstraintSet *cloog_constraint_set_simplify(CloogConstraintSet *matrix, + CloogEqualities *equal, int level, int nb_par) +{ + return cloog_constraint_set_copy(matrix); +} + + +static struct cloog_isl_dim constraint_cloog_dim_to_isl_dim( + CloogConstraint *constraint, int pos) +{ + enum isl_dim_type types[] = { isl_dim_set, isl_dim_div, isl_dim_param }; + int i; + struct cloog_isl_dim ci_dim; + + for (i = 0; i < 3; ++i) { + unsigned dim = isl_constraint_dim(&constraint->isl, types[i]); + if (pos < dim) { + ci_dim.type = types[i]; + ci_dim.pos = pos; + return ci_dim; + } + pos -= dim; + } + assert(0); +} + +static struct clast_expr *div_expr(CloogConstraint *constraint, int pos, + CloogNames *names) +{ + int i, nb_elts; + unsigned dim = cloog_constraint_total_dimension(constraint); + cloog_int_t c; + struct clast_reduction *r; + struct clast_expr *e = NULL; + struct isl_div *div; + + div = isl_constraint_div(&constraint->isl, pos); + + cloog_int_init(c); + for (i = 0, nb_elts = 0; i < dim; ++i) { + struct cloog_isl_dim dim; + + dim = constraint_cloog_dim_to_isl_dim(constraint, i); + isl_div_get_coefficient(div, dim.type, dim.pos, &c); + if (!cloog_int_is_zero(c)) + ++nb_elts; + } + isl_div_get_constant(div, &c); + if (!cloog_int_is_zero(c)) + ++nb_elts; + + r = new_clast_reduction(clast_red_sum, nb_elts); + for (i = 0, nb_elts = 0; i < dim; ++i) { + struct clast_expr *v; + struct cloog_isl_dim dim; + + dim = constraint_cloog_dim_to_isl_dim(constraint, i); + isl_div_get_coefficient(div, dim.type, dim.pos, &c); + if (cloog_int_is_zero(c)) + continue; + + v = cloog_constraint_variable_expr(constraint, 1 + i, names); + + r->elts[nb_elts++] = &new_clast_term(c, v)->expr; + } + isl_div_get_constant(div, &c); + if (!cloog_int_is_zero(c)) + r->elts[nb_elts++] = &new_clast_term(c, NULL)->expr; + + isl_div_get_denominator(div, &c); + e = &new_clast_binary(clast_bin_fdiv, &r->expr, c)->expr; + + cloog_int_clear(c); + + isl_div_free(div); + + return e; +} + +/** + * Return clast_expr corresponding to the variable "level" (1 based) in + * the given constraint. + */ +struct clast_expr *cloog_constraint_variable_expr(CloogConstraint *constraint, + int level, CloogNames *names) +{ + struct cloog_isl_dim dim; + const char *name; + + assert(constraint); + + dim = constraint_cloog_dim_to_isl_dim(constraint, level - 1); + if (dim.type == isl_dim_div) + return div_expr(constraint, dim.pos, names); + + if (dim.type == isl_dim_set) + name = cloog_names_name_at_level(names, level); + else + name = names->parameters[dim.pos]; + + return &new_clast_name(name)->expr; +} + + +/** + * Return true if constraint c involves variable v (zero-based). + */ +int cloog_constraint_involves(CloogConstraint *constraint, int v) +{ + isl_int c; + int res; + + isl_int_init(c); + cloog_constraint_coefficient_get(constraint, v, &c); + res = !isl_int_is_zero(c); + isl_int_clear(c); + return res; +} + +int cloog_constraint_is_lower_bound(CloogConstraint *constraint, int v) +{ + isl_int c; + int res; + + isl_int_init(c); + cloog_constraint_coefficient_get(constraint, v, &c); + res = isl_int_is_pos(c); + isl_int_clear(c); + return res; +} + +int cloog_constraint_is_upper_bound(CloogConstraint *constraint, int v) +{ + isl_int c; + int res; + + isl_int_init(c); + cloog_constraint_coefficient_get(constraint, v, &c); + res = isl_int_is_neg(c); + isl_int_clear(c); + return res; +} + +int cloog_constraint_is_equality(CloogConstraint *constraint) +{ + return isl_constraint_is_equality(&constraint->isl); +} + +void cloog_constraint_clear(CloogConstraint *constraint) +{ + isl_constraint_clear(&constraint->isl); +} + +void cloog_constraint_coefficient_get(CloogConstraint *constraint, + int var, cloog_int_t *val) +{ + struct cloog_isl_dim dim; + + if (!constraint) + return; + + dim = constraint_cloog_dim_to_isl_dim(constraint, var); + isl_constraint_get_coefficient(&constraint->isl, dim.type, dim.pos, val); +} + +void cloog_constraint_coefficient_set(CloogConstraint *constraint, + int var, cloog_int_t val) +{ + struct cloog_isl_dim dim; + + assert(constraint); + + dim = constraint_cloog_dim_to_isl_dim(constraint, var); + isl_constraint_set_coefficient(&constraint->isl, dim.type, dim.pos, val); +} + +void cloog_constraint_constant_get(CloogConstraint *constraint, cloog_int_t *val) +{ + isl_constraint_get_constant(&constraint->isl, val); +} + +/** + * Copy the coefficient of constraint c into dst in PolyLib order, + * i.e., first the coefficients of the variables, then the coefficients + * of the parameters and finally the constant. + */ +void cloog_constraint_copy_coefficients(CloogConstraint *constraint, + cloog_int_t *dst) +{ + int i; + unsigned dim; + + dim = isl_constraint_dim(&constraint->isl, isl_dim_all); + + for (i = 0; i < dim; ++i) + cloog_constraint_coefficient_get(constraint, i, dst+i); + cloog_constraint_constant_get(constraint, dst+dim); +} + +CloogConstraint *cloog_constraint_invalid(void) +{ + return NULL; +} + +int cloog_constraint_is_valid(CloogConstraint *constraint) +{ + return constraint != NULL; +} + +int cloog_constraint_total_dimension(CloogConstraint *constraint) +{ + return isl_constraint_dim(&constraint->isl, isl_dim_all); +} + + +/** + * Check whether there is any need for the constraint "upper" on + * "level" to get reduced. + * In case of the isl backend, there should be no need to do so + * if the level corresponds to an existentially quantified variable. + * Moreover, the way reduction is performed does not work for such + * variables since its position might chance during the construction + * of a set for reduction. + */ +int cloog_constraint_needs_reduction(CloogConstraint *upper, int level) +{ + isl_basic_set *bset; + struct cloog_isl_dim dim; + + bset = isl_basic_set_from_constraint(isl_constraint_copy(&upper->isl)); + dim = basic_set_cloog_dim_to_isl_dim(bset, level - 1); + isl_basic_set_free(bset); + + return dim.type == isl_dim_set; +} + + +/** + * Create a CloogConstraintSet containing enough information to perform + * a reduction on the upper equality (in this case lower is an invalid + * CloogConstraint) or the pair of inequalities upper and lower + * from within insert_modulo_guard. + * In the isl backend, we return a CloogConstraintSet containing both + * bounds, as the stride may change during the reduction and we may + * need to recompute the bound on the modulo expression. + */ +CloogConstraintSet *cloog_constraint_set_for_reduction(CloogConstraint *upper, + CloogConstraint *lower) +{ + struct isl_basic_set *bset; + + bset = isl_basic_set_from_constraint(isl_constraint_copy(&upper->isl)); + if (cloog_constraint_is_valid(lower)) + bset = isl_basic_set_add_constraint(bset, + isl_constraint_copy(&lower->isl)); + return cloog_constraint_set_from_isl_basic_set(bset); +} + + +static int add_constant_term(CloogConstraint *c, void *user) +{ + isl_int *bound = (isl_int *)user; + isl_int v; + + isl_int_init(v); + + cloog_constraint_constant_get(c, &v); + isl_int_add(*bound, *bound, v); + + isl_int_clear(v); + + return 0; +} + +/** + * Reduce the modulo guard expressed by "constraints" using equalities + * found in outer nesting levels (stored in "equal"). + * The modulo guard may be an equality or a pair of inequalities. + * In case of a pair of inequalities, *bound contains the bound on the + * corresponding modulo expression. If any reduction is performed + * then this bound is recomputed. + * + * "level" may not correspond to an existentially quantified variable. + * + * We first check if there are any equalities we can use. If not, + * there is again nothing to reduce. + * For the actual reduction, we use isl_basic_set_gist, but this + * function will only perform the reduction we want hear if the + * the variable that imposes the modulo constraint has been projected + * out (i.e., turned into an existentially quantified variable). + * After the call to isl_basic_set_gist, we need to move the + * existential variable back into the position where the calling + * function expects it (assuming there are any constraints left). + * We do this by adding equality between the given dimension and + * the existentially quantified variable. + */ +CloogConstraintSet *cloog_constraint_set_reduce(CloogConstraintSet *constraints, + int level, CloogEqualities *equal, int nb_par, cloog_int_t *bound) +{ + int j; + isl_ctx *ctx; + struct isl_basic_set *eq; + struct isl_basic_map *id; + struct cloog_isl_dim dim; + struct isl_constraint *c; + struct isl_div *div; + unsigned constraints_dim; + int pos; + isl_basic_set *bset; + + bset = cloog_constraints_set_to_isl(constraints); + ctx = isl_basic_set_get_ctx(bset); + dim = set_cloog_dim_to_isl_dim(constraints, level - 1); + assert(dim.type == isl_dim_set); + + eq = NULL; + for (j = 0; j < level - 1; ++j) { + isl_basic_set *bset_j; + if (equal->types[j] != EQTYPE_EXAFFINE) + continue; + bset_j = cloog_constraints_set_to_isl(equal->constraints[j]); + if (!eq) + eq = isl_basic_set_copy(bset_j); + else + eq = isl_basic_set_intersect(eq, + isl_basic_set_copy(bset_j)); + } + if (!eq) + return constraints; + + id = isl_basic_map_identity(isl_basic_set_get_dim(bset)); + id = isl_basic_map_remove_dims(id, isl_dim_out, dim.pos, 1); + bset = isl_basic_set_apply(bset, isl_basic_map_copy(id)); + bset = isl_basic_set_apply(bset, isl_basic_map_reverse(id)); + + constraints_dim = isl_basic_set_dim(bset, isl_dim_set); + eq = isl_basic_set_remove_dims(eq, isl_dim_set, constraints_dim, + isl_basic_set_dim(eq, isl_dim_set) - constraints_dim); + bset = isl_basic_set_gist(bset, eq); + if (isl_basic_set_dim(bset, isl_dim_div) != 1) + return cloog_constraint_set_from_isl_basic_set(bset); + + div = isl_basic_set_div(isl_basic_set_copy(bset), 0); + c = isl_equality_alloc(isl_basic_set_get_dim(bset)); + c = isl_constraint_add_div(c, div, &pos); + isl_constraint_set_coefficient(c, isl_dim_set, dim.pos, ctx->one); + isl_constraint_set_coefficient(c, isl_dim_div, pos, ctx->negone); + bset = isl_basic_set_add_constraint(bset, c); + + isl_int_set_si(*bound, 0); + constraints = cloog_constraint_set_from_isl_basic_set(bset); + cloog_constraint_set_foreach_constraint(constraints, + add_constant_term, bound); + + return cloog_constraint_set_from_isl_basic_set(bset); +} + +CloogConstraint *cloog_constraint_copy(CloogConstraint *constraint) +{ + return cloog_constraint_from_isl_constraint( + isl_constraint_copy(&constraint->isl)); +} + +void cloog_constraint_release(CloogConstraint *constraint) +{ + isl_constraint_free(&constraint->isl); +} + +struct cloog_isl_foreach { + int (*fn)(CloogConstraint *constraint, void *user); + void *user; +}; + +static int cloog_isl_foreach_cb(__isl_take isl_constraint *c, void *user) +{ + struct cloog_isl_foreach *data = (struct cloog_isl_foreach *)user; + int ret; + + if (isl_constraint_is_div_constraint(c)) { + isl_constraint_free(c); + return 0; + } + + ret = data->fn(cloog_constraint_from_isl_constraint(c), data->user); + + isl_constraint_free(c); + + return ret; +} + +int cloog_constraint_set_foreach_constraint(CloogConstraintSet *constraints, + int (*fn)(CloogConstraint *constraint, void *user), void *user) +{ + struct cloog_isl_foreach data = { fn, user }; + isl_basic_set *bset; + + bset = cloog_constraints_set_to_isl(constraints); + return isl_basic_set_foreach_constraint(bset, + cloog_isl_foreach_cb, &data); +} + +CloogConstraint *cloog_equal_constraint(CloogEqualities *equal, int j) +{ + isl_basic_set *bset; + bset = cloog_constraints_set_to_isl(equal->constraints[j]); + return cloog_constraint_from_isl_constraint( + isl_basic_set_first_constraint(isl_basic_set_copy(bset))); +} diff --git a/cloog-core/source/isl/domain.c b/cloog-core/source/isl/domain.c new file mode 100644 index 0000000..ce695d8 --- /dev/null +++ b/cloog-core/source/isl/domain.c @@ -0,0 +1,1669 @@ +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <cloog/isl/cloog.h> +#include <isl/list.h> +#include <isl/constraint.h> +#include <isl/div.h> + +CloogDomain *cloog_domain_from_isl_set(struct isl_set *set) +{ + set = isl_set_detect_equalities(set); + set = isl_set_compute_divs(set); + return (CloogDomain *)set; +} + +__isl_give isl_set *isl_set_from_cloog_domain(CloogDomain *domain) +{ + return (isl_set *)domain; +} + +CloogScattering *cloog_scattering_from_isl_map(struct isl_map *map) +{ + return (CloogScattering *)map; +} + +__isl_give isl_map *isl_map_from_cloog_scattering(CloogScattering *scattering) +{ + return (isl_map *)scattering; +} + + +/** + * Returns true if each scattering dimension is defined in terms + * of the original iterators. + */ +int cloog_scattering_fully_specified(CloogScattering *scattering, + CloogDomain *domain) +{ + isl_map *map = isl_map_from_cloog_scattering(scattering); + return isl_map_is_single_valued(map); +} + + +CloogConstraintSet *cloog_domain_constraints(CloogDomain *domain) +{ + isl_basic_set *bset; + isl_set *set = isl_set_from_cloog_domain(domain); + assert(isl_set_n_basic_set(set) == 1); + bset = isl_set_copy_basic_set(set); + return cloog_constraint_set_from_isl_basic_set(bset); +} + + +void cloog_domain_print_constraints(FILE *foo, CloogDomain *domain, + int print_number) +{ + isl_basic_set *bset; + isl_set *set = isl_set_from_cloog_domain(domain); + + if (print_number) + isl_set_print(set, foo, 0, ISL_FORMAT_EXT_POLYLIB); + else { + assert(isl_set_n_basic_set(set) == 1); + bset = isl_set_copy_basic_set(set); + isl_basic_set_print(bset, foo, + 0, NULL, NULL, ISL_FORMAT_POLYLIB); + isl_basic_set_free(bset); + } +} + + +void cloog_scattering_print_constraints(FILE *foo, CloogScattering *scattering) +{ + isl_map *map = isl_map_from_cloog_scattering(scattering); + isl_map_print(map, foo, 0, ISL_FORMAT_EXT_POLYLIB); +} + + +void cloog_domain_free(CloogDomain * domain) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + isl_set_free(set); +} + + +void cloog_scattering_free(CloogScattering *scatt) +{ + isl_map *map = isl_map_from_cloog_scattering(scatt); + isl_map_free(map); +} + + +CloogDomain * cloog_domain_copy(CloogDomain * domain) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + return cloog_domain_from_isl_set(isl_set_copy(set)); +} + + +/** + * cloog_domain_convex function: + * Computes the convex hull of domain. + */ +CloogDomain *cloog_domain_convex(CloogDomain *domain) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + set = isl_set_from_basic_set(isl_set_convex_hull(isl_set_copy(set))); + return cloog_domain_from_isl_set(set); +} + + +/** + * cloog_domain_simple_convex: + * Given a list (union) of polyhedra, this function returns a "simple" + * convex hull of this union. In particular, the constraints of the + * the returned polyhedron consist of (parametric) lower and upper + * bounds on individual variables and constraints that appear in the + * original polyhedra. + */ +CloogDomain *cloog_domain_simple_convex(CloogDomain *domain) +{ + struct isl_basic_set *hull; + isl_set *set = isl_set_from_cloog_domain(domain); + unsigned dim = isl_set_dim(set, isl_dim_set); + + if (cloog_domain_isconvex(domain)) + return cloog_domain_copy(domain); + + if (dim == 0) + return cloog_domain_convex(domain); + + hull = isl_set_bounded_simple_hull(isl_set_copy(set)); + return cloog_domain_from_isl_set(isl_set_from_basic_set(hull)); +} + + +/** + * cloog_domain_simplify function: + * Given two polyhedral domains (dom1) and (dom2), + * this function finds the largest domain set (or the smallest list + * of non-redundant constraints), that when intersected with polyhedral + * domain (dom2) equals (dom1)intersect(dom2). The output is a new CloogDomain + * structure with a polyhedral domain with the "redundant" constraints removed. + * NB: the second domain is required not to be a union. + */ +CloogDomain *cloog_domain_simplify(CloogDomain *dom1, CloogDomain *dom2) +{ + isl_set *set1 = isl_set_from_cloog_domain(dom1); + isl_set *set2 = isl_set_from_cloog_domain(dom2); + set1 = isl_set_gist(isl_set_copy(set1), isl_set_copy(set2)); + return cloog_domain_from_isl_set(set1); +} + + +/** + * cloog_domain_union function: + * This function returns a new polyhedral domain which is the union of + * two polyhedral domains (dom1) U (dom2). + * Frees dom1 and dom2; + */ +CloogDomain *cloog_domain_union(CloogDomain *dom1, CloogDomain *dom2) +{ + isl_set *set1 = isl_set_from_cloog_domain(dom1); + isl_set *set2 = isl_set_from_cloog_domain(dom2); + set1 = isl_set_union(set1, set2); + return cloog_domain_from_isl_set(set1); +} + + + +/** + * cloog_domain_intersection function: + * This function returns a new polyhedral domain which is the intersection of + * two polyhedral domains (dom1) \cap (dom2). + */ +CloogDomain *cloog_domain_intersection(CloogDomain *dom1, CloogDomain *dom2) +{ + isl_set *set1 = isl_set_from_cloog_domain(dom1); + isl_set *set2 = isl_set_from_cloog_domain(dom2); + set1 = isl_set_intersect(isl_set_copy(set1), isl_set_copy(set2)); + return cloog_domain_from_isl_set(set1); +} + + +/** + * cloog_domain_difference function: + * Returns the set difference domain \ minus. + */ +CloogDomain *cloog_domain_difference(CloogDomain *domain, CloogDomain *minus) +{ + isl_set *set1 = isl_set_from_cloog_domain(domain); + isl_set *set2 = isl_set_from_cloog_domain(minus); + set1 = isl_set_subtract(isl_set_copy(set1), isl_set_copy(set2)); + return cloog_domain_from_isl_set(set1); +} + + +/** + * cloog_domain_sort function: + * This function topologically sorts (nb_doms) domains. Here (doms) is an + * array of pointers to CloogDomains, (nb_doms) is the number of domains, + * (level) is the level to consider for partial ordering (nb_par) is the + * parameter space dimension, (permut) if not NULL, is an array of (nb_doms) + * integers that contains a permutation specification after call in order to + * apply the topological sorting. + */ +void cloog_domain_sort(CloogDomain **doms, unsigned nb_doms, unsigned level, + int *permut) +{ + int i, j, k, cmp; + struct isl_ctx *ctx; + unsigned char **follows; + isl_set *set_i, *set_j; + isl_basic_set *bset_i, *bset_j; + + if (!nb_doms) + return; + set_i = isl_set_from_cloog_domain(doms[0]); + ctx = isl_set_get_ctx(set_i); + for (i = 0; i < nb_doms; i++) { + set_i = isl_set_from_cloog_domain(doms[i]); + assert(isl_set_n_basic_set(set_i) == 1); + } + + follows = isl_alloc_array(ctx, unsigned char *, nb_doms); + assert(follows); + for (i = 0; i < nb_doms; ++i) { + follows[i] = isl_alloc_array(ctx, unsigned char, nb_doms); + assert(follows[i]); + for (j = 0; j < nb_doms; ++j) + follows[i][j] = 0; + } + + for (i = 1; i < nb_doms; ++i) { + for (j = 0; j < i; ++j) { + if (follows[i][j] || follows[j][i]) + continue; + set_i = isl_set_from_cloog_domain(doms[i]); + set_j = isl_set_from_cloog_domain(doms[j]); + bset_i = isl_set_copy_basic_set(set_i); + bset_j = isl_set_copy_basic_set(set_j); + cmp = isl_basic_set_compare_at(bset_i, bset_j, level-1); + isl_basic_set_free(bset_i); + isl_basic_set_free(bset_j); + if (!cmp) + continue; + if (cmp > 0) { + follows[i][j] = 1; + for (k = 0; k < i; ++k) + follows[i][k] |= follows[j][k]; + } else { + follows[j][i] = 1; + for (k = 0; k < i; ++k) + follows[k][i] |= follows[k][j]; + } + } + } + + for (i = 0, j = 0; i < nb_doms; j = (j + 1) % nb_doms) { + for (k = 0; k < nb_doms; ++k) + if (follows[j][k]) + break; + if (k < nb_doms) + continue; + for (k = 0; k < nb_doms; ++k) + follows[k][j] = 0; + follows[j][j] = 1; + permut[i] = 1 + j; + ++i; + } + + for (i = 0; i < nb_doms; ++i) + free(follows[i]); + free(follows); +} + + +/** + * Check whether there is or may be any value of dom1 at the given level + * that is greater than or equal to a value of dom2 at the same level. + * + * Return + * 1 is there is or may be a greater-than pair. + * 0 if there is no greater-than pair, but there may be an equal-to pair + * -1 if there is definitely no such pair + */ +int cloog_domain_follows(CloogDomain *dom1, CloogDomain *dom2, unsigned level) +{ + isl_set *set1 = isl_set_from_cloog_domain(dom1); + isl_set *set2 = isl_set_from_cloog_domain(dom2); + int follows; + + follows = isl_set_follows_at(set1, set2, level - 1); + assert(follows >= -1); + + return follows; +} + + +/** + * cloog_domain_empty function: + * Returns an empty domain of the same dimensions as template. + */ +CloogDomain *cloog_domain_empty(CloogDomain *template) +{ + isl_set *set = isl_set_from_cloog_domain(template); + return cloog_domain_from_isl_set(isl_set_empty_like(set)); +} + + +/** + * Return 1 if the specified dimension has both an upper and a lower bound. + */ +int cloog_domain_is_bounded(CloogDomain *dom, unsigned level) +{ + isl_set *set = isl_set_from_cloog_domain(dom); + return isl_set_dim_is_bounded(set, isl_dim_set, level - 1); +} + + +/****************************************************************************** + * Structure display function * + ******************************************************************************/ + + +/** + * cloog_domain_print_structure : + * this function is a more human-friendly way to display the CloogDomain data + * structure, it only shows the constraint system and includes an indentation + * level (level) in order to work with others print_structure functions. + */ +void cloog_domain_print_structure(FILE *file, CloogDomain *domain, int level, + const char *name) +{ + int i ; + isl_set *set = isl_set_from_cloog_domain(domain); + + /* Go to the right level. */ + for (i = 0; i < level; i++) + fprintf(file, "|\t"); + + if (!set) { + fprintf(file, "+-- Null CloogDomain\n"); + return; + } + fprintf(file, "+-- %s\n", name); + for (i = 0; i < level+1; ++i) + fprintf(file, "|\t"); + + isl_set_print(set, file, 0, ISL_FORMAT_ISL); + + fprintf(file, "\n"); +} + + +/****************************************************************************** + * Memory deallocation function * + ******************************************************************************/ + + +void cloog_domain_list_free(CloogDomainList *list) +{ + CloogDomainList *next; + + for ( ; list; list = next) { + next = list->next; + cloog_domain_free(list->domain); + free(list); + } +} + + +/** + * cloog_scattering_list_free function: + * This function frees the allocated memory for a CloogScatteringList structure. + */ +void cloog_scattering_list_free(CloogScatteringList *list) +{ + while (list != NULL) { + CloogScatteringList *temp = list->next; + isl_map *map = isl_map_from_cloog_scattering(list->scatt); + isl_map_free(map); + free(list); + list = temp; + } +} + + +/****************************************************************************** + * Reading function * + ******************************************************************************/ + + +/** + * cloog_domain_read_context function: + * Read parameter domain. + */ +CloogDomain *cloog_domain_read_context(CloogState *state, FILE *input) +{ + struct isl_ctx *ctx = state->backend->ctx; + isl_set *set; + + set = isl_set_read_from_file(ctx, input, 0); + set = isl_set_move_dims(set, isl_dim_param, 0, + isl_dim_set, 0, isl_set_dim(set, isl_dim_set)); + + return cloog_domain_from_isl_set(set); +} + + +/** + * cloog_domain_from_context + * Reinterpret context by turning parameters into variables. + */ +CloogDomain *cloog_domain_from_context(CloogDomain *context) +{ + isl_set *set = isl_set_from_cloog_domain(context); + + set = isl_set_move_dims(set, isl_dim_set, 0, + isl_dim_param, 0, isl_set_dim(set, isl_dim_param)); + + return cloog_domain_from_isl_set(set); +} + + +/** + * cloog_domain_union_read function: + * This function reads a union of polyhedra into a file (input) and + * returns a pointer to a CloogDomain containing the read information. + */ +CloogDomain *cloog_domain_union_read(CloogState *state, + FILE *input, int nb_parameters) +{ + struct isl_ctx *ctx = state->backend->ctx; + struct isl_set *set; + + set = isl_set_read_from_file(ctx, input, nb_parameters); + return cloog_domain_from_isl_set(set); +} + + +/** + * cloog_domain_read_scattering function: + * This function reads in a scattering function from the file input. + * + * We try to read the scattering relation as a map, but if it is + * specified in the original PolyLib format, then isl_map_read_from_file + * will treat the input as a set return a map with zero input dimensions. + * In this case, we need to decompose the set into a map from + * scattering dimensions to domain dimensions and then invert the + * resulting map. + */ +CloogScattering *cloog_domain_read_scattering(CloogDomain *domain, FILE *input) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + isl_ctx *ctx = isl_set_get_ctx(set); + struct isl_map *scat; + unsigned nparam; + unsigned dim; + unsigned n_scat; + + dim = isl_set_dim(set, isl_dim_set); + nparam = isl_set_dim(set, isl_dim_param); + scat = isl_map_read_from_file(ctx, input, nparam); + if (isl_map_dim(scat, isl_dim_in) != dim) { + n_scat = isl_map_dim(scat, isl_dim_out) - dim; + scat = isl_map_move_dims(scat, isl_dim_in, 0, + isl_dim_out, n_scat, dim); + } + return cloog_scattering_from_isl_map(scat); +} + +/****************************************************************************** + * CloogMatrix Reading function * + ******************************************************************************/ + +/** + * isl_constraint_read_from_matrix: + * Convert a single line of a matrix to a isl_constraint. + * Returns a pointer to the constraint if successful; NULL otherwise. + */ +static struct isl_constraint *isl_constraint_read_from_matrix( + struct isl_dim *dim, cloog_int_t *row) +{ + struct isl_constraint *constraint; + int j; + int nvariables = isl_dim_size(dim, isl_dim_set); + int nparam = isl_dim_size(dim, isl_dim_param); + + if (cloog_int_is_zero(row[0])) + constraint = isl_equality_alloc(dim); + else + constraint = isl_inequality_alloc(dim); + + for (j = 0; j < nvariables; ++j) + isl_constraint_set_coefficient(constraint, isl_dim_out, j, + row[1 + j]); + + for (j = 0; j < nparam; ++j) + isl_constraint_set_coefficient(constraint, isl_dim_param, j, + row[1 + nvariables + j]); + + isl_constraint_set_constant(constraint, row[1 + nvariables + nparam]); + + return constraint; +} + +/** + * isl_basic_set_read_from_matrix: + * Convert matrix to basic_set. The matrix contains nparam parameter columns. + * Returns a pointer to the basic_set if successful; NULL otherwise. + */ +static struct isl_basic_set *isl_basic_set_read_from_matrix(struct isl_ctx *ctx, + CloogMatrix* matrix, int nparam) +{ + struct isl_dim *dim; + struct isl_basic_set *bset; + int i; + unsigned nrows, ncolumns; + + nrows = matrix->NbRows; + ncolumns = matrix->NbColumns; + int nvariables = ncolumns - 2 - nparam; + + dim = isl_dim_set_alloc(ctx, nparam, nvariables); + + bset = isl_basic_set_universe(isl_dim_copy(dim)); + + for (i = 0; i < nrows; ++i) { + cloog_int_t *row = matrix->p[i]; + struct isl_constraint *constraint = + isl_constraint_read_from_matrix(isl_dim_copy(dim), row); + bset = isl_basic_set_add_constraint(bset, constraint); + } + + isl_dim_free(dim); + + return bset; +} + +/** + * cloog_domain_from_cloog_matrix: + * Create a CloogDomain containing the constraints described in matrix. + * nparam is the number of parameters contained in the domain. + * Returns a pointer to the CloogDomain if successful; NULL otherwise. + */ +CloogDomain *cloog_domain_from_cloog_matrix(CloogState *state, + CloogMatrix *matrix, int nparam) +{ + struct isl_ctx *ctx = state->backend->ctx; + struct isl_basic_set *bset; + + bset = isl_basic_set_read_from_matrix(ctx, matrix, nparam); + + return cloog_domain_from_isl_set(isl_set_from_basic_set(bset)); +} + +/** + * cloog_scattering_from_cloog_matrix: + * Create a CloogScattering containing the constraints described in matrix. + * nparam is the number of parameters contained in the domain. + * Returns a pointer to the CloogScattering if successful; NULL otherwise. + */ +CloogScattering *cloog_scattering_from_cloog_matrix(CloogState *state, + CloogMatrix *matrix, int nb_scat, int nb_par) +{ + struct isl_ctx *ctx = state->backend->ctx; + struct isl_basic_set *bset; + struct isl_basic_map *scat; + struct isl_dim *dims; + unsigned dim; + + bset = isl_basic_set_read_from_matrix(ctx, matrix, nb_par); + dim = isl_basic_set_n_dim(bset) - nb_scat; + dims = isl_dim_alloc(ctx, nb_par, nb_scat, dim); + + scat = isl_basic_map_from_basic_set(bset, dims); + scat = isl_basic_map_reverse(scat); + return cloog_scattering_from_isl_map(isl_map_from_basic_map(scat)); +} + + +/****************************************************************************** + * Processing functions * + ******************************************************************************/ + + + +/** + * cloog_domain_isempty function: + */ +int cloog_domain_isempty(CloogDomain *domain) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + return isl_set_is_empty(set); +} + + +/** + * cloog_domain_universe function: + * This function returns the complete dim-dimensional space. + */ +CloogDomain *cloog_domain_universe(CloogState *state, unsigned dim) +{ + struct isl_dim *dims; + struct isl_basic_set *bset; + + dims = isl_dim_set_alloc(state->backend->ctx, 0, dim); + bset = isl_basic_set_universe(dims); + return cloog_domain_from_isl_set(isl_set_from_basic_set(bset)); +} + + +/** + * cloog_domain_project function: + * This function returns the projection of + * (domain) on the (level) first dimensions (i.e. outer loops). + */ +CloogDomain *cloog_domain_project(CloogDomain *domain, int level) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + set = isl_set_remove_dims(isl_set_copy(set), isl_dim_set, + level, isl_set_n_dim(set) - level); + set = isl_set_compute_divs(set); + if (level > 0) + set = isl_set_remove_divs_involving_dims(set, + isl_dim_set, level - 1, 1); + return cloog_domain_from_isl_set(set); +} + + +/** + * cloog_domain_extend function: + * This function returns the (domain) given as input with (dim) + * dimensions and (nb_par) parameters. + * This function does not free (domain), and returns a new CloogDomain. + */ +CloogDomain *cloog_domain_extend(CloogDomain *domain, int dim) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + set = isl_set_extend(isl_set_copy(set), isl_set_n_param(set), dim); + return cloog_domain_from_isl_set(set); +} + + +/** + * cloog_domain_never_integral function: + * For us, an equality like 3*i -4 = 0 is always false since 4%3 != 0. + * There is no need to check for such constraints explicitly for the isl + * backend. + */ +int cloog_domain_never_integral(CloogDomain * domain) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + return isl_set_is_empty(set); +} + + +/** + * Check whether the loop at "level" is executed at most once. + * We construct a map that maps all remaining variables to this iterator + * and check whether this map is single valued. + * + * Alternatively, we could have mapped the domain through a mapping + * [p] -> { [..., i] -> [..., i'] : i' > i } + * and then taken the intersection of the original domain and the transformed + * domain. If this intersection is empty, then the corresponding + * loop is executed at most once. + */ +int cloog_domain_is_otl(CloogDomain *domain, int level) +{ + int otl; + isl_set *set = isl_set_from_cloog_domain(domain); + isl_map *map; + + map = isl_map_from_domain(isl_set_copy(set)); + map = isl_map_move_dims(map, isl_dim_out, 0, isl_dim_in, level - 1, 1); + otl = isl_map_is_single_valued(map); + isl_map_free(map); + + return otl; +} + + +/** + * cloog_domain_stride function: + * This function finds the stride imposed to unknown with the column number + * 'strided_level' in order to be integral. For instance, if we have a + * constraint like -i - 2j + 2k = 0, and we consider k, then k can be integral + * only if (i + 2j)%2 = 0. Then only if i%2 = 0. Then k imposes a stride 2 to + * the unknown i. The function returns the imposed stride in a parameter field. + * - domain is the set of constraint we have to consider, + * - strided_level is the column number of the unknown for which a stride have + * to be found, + * - looking_level is the column number of the unknown that impose a stride to + * the first unknown. + * - stride is the stride that is returned back as a function parameter. + * - offset is the value of the constant c if the condition is of the shape + * (i + c)%s = 0, s being the stride. + */ +void cloog_domain_stride(CloogDomain *domain, int strided_level, + cloog_int_t *stride, cloog_int_t *offset) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + isl_set_dim_residue_class(set, strided_level - 1, stride, offset); + if (!isl_int_is_zero(*offset)) + isl_int_sub(*offset, *stride, *offset); + return; +} + + +struct cloog_can_stride { + int level; + int can_stride; +}; + +static int constraint_can_stride(__isl_take isl_constraint *c, void *user) +{ + struct cloog_can_stride *ccs = (struct cloog_can_stride *)user; + int i; + isl_int v; + unsigned n_div; + + isl_int_init(v); + isl_constraint_get_coefficient(c, isl_dim_set, ccs->level - 1, &v); + if (isl_int_is_pos(v)) { + n_div = isl_constraint_dim(c, isl_dim_div); + for (i = 0; i < n_div; ++i) { + isl_constraint_get_coefficient(c, isl_dim_div, i, &v); + if (!isl_int_is_zero(v)) + break; + } + if (i < n_div) + ccs->can_stride = 0; + } + isl_int_clear(v); + isl_constraint_free(c); + + return 0; +} + +static int basic_set_can_stride(__isl_take isl_basic_set *bset, void *user) +{ + struct cloog_can_stride *ccs = (struct cloog_can_stride *)user; + int r; + + r = isl_basic_set_foreach_constraint(bset, constraint_can_stride, ccs); + isl_basic_set_free(bset); + return r; +} + + +/** + * Return 1 if CLooG is allowed to perform stride detection on level "level" + * and 0 otherwise. + * Currently, stride detection is only allowed when none of the lower + * bound constraints involve any existentially quantified variables. + * The reason is that the current isl interface does not make it + * easy to construct an integer division that depends on other integer + * divisions. + * By not allowing existentially quantified variables in the constraints, + * we can ignore them in cloog_domain_stride_lower_bound. + */ +int cloog_domain_can_stride(CloogDomain *domain, int level) +{ + struct cloog_can_stride ccs = { level, 1 }; + isl_set *set = isl_set_from_cloog_domain(domain); + int r; + r = isl_set_foreach_basic_set(set, basic_set_can_stride, &ccs); + assert(r == 0); + return ccs.can_stride; +} + + +struct cloog_stride_lower { + int level; + CloogStride *stride; + isl_set *set; + isl_basic_set *bounds; +}; + +/* If the given constraint is a lower bound on csl->level, then add + * a lower bound to csl->bounds that makes sure that the remainder + * of the smallest value on division by csl->stride is equal to csl->offset. + * + * In particular, the given lower bound is of the form + * + * a i + f >= 0 + * + * where f may depend on the parameters and other iterators. + * The stride is s and the offset is d. + * The lower bound -f/a may not satisfy the above condition. In fact, + * it may not even be integral. We want to round this value of i up + * to the nearest value that satisfies the condition and add the corresponding + * lower bound constraint. This nearest value is obtained by rounding + * i - d up to the nearest multiple of s. + * That is, we first subtract d + * + * i' = -f/a - d + * + * then we round up to the nearest multiple of s + * + * i'' = s * ceil(i'/s) + * + * and finally, we add d again + * + * i''' = i'' + d + * + * and impose the constraint i >= i'''. + * + * We find + * + * i'' = s * ceil((-f - a * d)/(a * s)) = - s * floor((f + a * d)/(a * s)) + * + * i >= - s * floor((f + a * d)/(a * s)) + d + * + * or + * i + s * floor((f + a * d)/(a * s)) - d >= 0 + */ +static int constraint_stride_lower(__isl_take isl_constraint *c, void *user) +{ + struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user; + int i; + isl_int v; + isl_int t; + isl_constraint *bound; + isl_div *div; + int pos; + unsigned nparam, nvar; + + isl_int_init(v); + isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v); + if (!isl_int_is_pos(v)) { + isl_int_clear(v); + isl_constraint_free(c); + + return 0; + } + + isl_int_init(t); + + nparam = isl_constraint_dim(c, isl_dim_param); + nvar = isl_constraint_dim(c, isl_dim_set); + bound = isl_inequality_alloc(isl_basic_set_get_dim(csl->bounds)); + div = isl_div_alloc(isl_basic_set_get_dim(csl->bounds)); + isl_int_mul(t, v, csl->stride->stride); + isl_div_set_denominator(div, t); + for (i = 0; i < nparam; ++i) { + isl_constraint_get_coefficient(c, isl_dim_param, i, &t); + isl_div_set_coefficient(div, isl_dim_param, i, t); + } + for (i = 0; i < nvar; ++i) { + if (i == csl->level - 1) + continue; + isl_constraint_get_coefficient(c, isl_dim_set, i, &t); + isl_div_set_coefficient(div, isl_dim_set, i, t); + } + isl_constraint_get_constant(c, &t); + isl_int_addmul(t, v, csl->stride->offset); + isl_div_set_constant(div, t); + + bound = isl_constraint_add_div(bound, div, &pos); + isl_int_set_si(t, 1); + isl_constraint_set_coefficient(bound, isl_dim_set, + csl->level - 1, t); + isl_constraint_set_coefficient(bound, isl_dim_div, pos, + csl->stride->stride); + isl_int_neg(t, csl->stride->offset); + isl_constraint_set_constant(bound, t); + csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound); + + isl_int_clear(v); + isl_int_clear(t); + isl_constraint_free(c); + + return 0; +} + +/* This functions performs essentially the same operation as + * constraint_stride_lower, the only difference being that the offset d + * is not a constant, but an affine expression in terms of the parameters + * and earlier variables. In particular the affine expression is equal + * to the coefficients of stride->constraint multiplied by stride->factor. + * As in constraint_stride_lower, we add an extra bound + * + * i + s * floor((f + a * d)/(a * s)) - d >= 0 + * + * for each lower bound + * + * a i + f >= 0 + * + * where d is not the aforementioned affine expression. + */ +static int constraint_stride_lower_c(__isl_take isl_constraint *c, void *user) +{ + struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user; + int i; + isl_int v; + isl_int t, u; + isl_constraint *bound; + isl_constraint *csl_c; + isl_div *div; + int pos; + unsigned nparam, nvar; + + isl_int_init(v); + isl_constraint_get_coefficient(c, isl_dim_set, csl->level - 1, &v); + if (!isl_int_is_pos(v)) { + isl_int_clear(v); + isl_constraint_free(c); + + return 0; + } + + csl_c = &csl->stride->constraint->isl; + + isl_int_init(t); + isl_int_init(u); + + nparam = isl_constraint_dim(c, isl_dim_param); + nvar = isl_constraint_dim(c, isl_dim_set); + bound = isl_inequality_alloc(isl_basic_set_get_dim(csl->bounds)); + div = isl_div_alloc(isl_basic_set_get_dim(csl->bounds)); + isl_int_mul(t, v, csl->stride->stride); + isl_div_set_denominator(div, t); + for (i = 0; i < nparam; ++i) { + isl_constraint_get_coefficient(c, isl_dim_param, i, &t); + isl_constraint_get_coefficient(csl_c, isl_dim_param, i, &u); + isl_int_mul(u, u, csl->stride->factor); + isl_int_addmul(t, v, u); + isl_div_set_coefficient(div, isl_dim_param, i, t); + isl_int_neg(u, u); + isl_constraint_set_coefficient(bound, isl_dim_param, i, u); + } + for (i = 0; i < nvar; ++i) { + if (i == csl->level - 1) + continue; + isl_constraint_get_coefficient(c, isl_dim_set, i, &t); + isl_constraint_get_coefficient(csl_c, isl_dim_set, i, &u); + isl_int_mul(u, u, csl->stride->factor); + isl_int_addmul(t, v, u); + isl_div_set_coefficient(div, isl_dim_set, i, t); + isl_int_neg(u, u); + isl_constraint_set_coefficient(bound, isl_dim_set, i, u); + } + isl_constraint_get_constant(c, &t); + isl_constraint_get_constant(csl_c, &u); + isl_int_mul(u, u, csl->stride->factor); + isl_int_addmul(t, v, u); + isl_div_set_constant(div, t); + isl_int_neg(u, u); + isl_constraint_set_constant(bound, u); + + bound = isl_constraint_add_div(bound, div, &pos); + isl_int_set_si(t, 1); + isl_constraint_set_coefficient(bound, isl_dim_set, + csl->level - 1, t); + isl_constraint_set_coefficient(bound, isl_dim_div, pos, + csl->stride->stride); + csl->bounds = isl_basic_set_add_constraint(csl->bounds, bound); + + isl_int_clear(u); + isl_int_clear(t); + isl_int_clear(v); + isl_constraint_free(c); + + return 0; +} + +static int basic_set_stride_lower(__isl_take isl_basic_set *bset, void *user) +{ + struct cloog_stride_lower *csl = (struct cloog_stride_lower *)user; + int r; + + csl->bounds = isl_basic_set_universe_like(bset); + if (csl->stride->constraint) + r = isl_basic_set_foreach_constraint(bset, + &constraint_stride_lower_c, csl); + else + r = isl_basic_set_foreach_constraint(bset, + &constraint_stride_lower, csl); + bset = isl_basic_set_intersect(bset, csl->bounds); + csl->set = isl_set_union(csl->set, isl_set_from_basic_set(bset)); + + return r; +} + +/** + * Update the lower bounds at level "level" to the given stride information. + * That is, make sure that the remainder on division by "stride" + * is equal to "offset". + */ +CloogDomain *cloog_domain_stride_lower_bound(CloogDomain *domain, int level, + CloogStride *stride) +{ + struct cloog_stride_lower csl; + isl_set *set = isl_set_from_cloog_domain(domain); + int r; + + csl.stride = stride; + csl.level = level; + csl.set = isl_set_empty_like(set); + + r = isl_set_foreach_basic_set(set, basic_set_stride_lower, &csl); + assert(r == 0); + + cloog_domain_free(domain); + return cloog_domain_from_isl_set(csl.set); +} + + +/** + * cloog_domain_lazy_equal function: + * This function returns 1 if the domains given as input are the same, 0 if it + * is unable to decide. + */ +int cloog_domain_lazy_equal(CloogDomain *d1, CloogDomain *d2) +{ + isl_set *set1 = isl_set_from_cloog_domain(d1); + isl_set *set2 = isl_set_from_cloog_domain(d2); + return isl_set_fast_is_equal(set1, set2); +} + +struct cloog_bound_split { + isl_set *set; + int level; + int lower; + int upper; +}; + +static int constraint_bound_split(__isl_take isl_constraint *c, void *user) +{ + struct cloog_bound_split *cbs = (struct cloog_bound_split *)user; + isl_int v; + int i; + int handle = 0; + + isl_int_init(v); + isl_constraint_get_coefficient(c, isl_dim_set, cbs->level - 1, &v); + if (!cbs->lower && isl_int_is_pos(v)) + cbs->lower = handle = 1; + else if (!cbs->upper && isl_int_is_neg(v)) + cbs->upper = handle = 1; + if (handle) { + for (i = 0; i < isl_set_dim(cbs->set, isl_dim_param); ++i) { + isl_constraint_get_coefficient(c, isl_dim_param, i, &v); + if (isl_int_is_zero(v)) + continue; + cbs->set = isl_set_split_dims(cbs->set, + isl_dim_param, i, 1); + } + } + isl_int_clear(v); + isl_constraint_free(c); + + return (cbs->lower && cbs->upper) ? -1 : 0; +} + +static int basic_set_bound_split(__isl_take isl_basic_set *bset, void *user) +{ + struct cloog_bound_split *cbs = (struct cloog_bound_split *)user; + int r; + + cbs->lower = 0; + cbs->upper = 0; + r = isl_basic_set_foreach_constraint(bset, constraint_bound_split, cbs); + isl_basic_set_free(bset); + return ((!cbs->lower || !cbs->upper) && r < 0) ? -1 : 0; +} + +/** + * Return a union of sets S_i such that the convex hull of "dom", + * when intersected with one the sets S_i, will have an upper and + * lower bound for the dimension at "level" (provided "dom" itself + * has such bounds for the dimensions). + * + * We currently take a very simple approach. For each of the basic + * sets in "dom" we pick a lower and an upper bound and split the + * range of any parameter involved in these two bounds in a + * nonnegative and a negative part. This ensures that the symbolic + * constant in these two constraints are themselves bounded and + * so there will be at least one upper and one lower bound + * in the convex hull. + */ +CloogDomain *cloog_domain_bound_splitter(CloogDomain *dom, int level) +{ + struct cloog_bound_split cbs; + isl_set *set = isl_set_from_cloog_domain(dom); + int r; + cbs.level = level; + cbs.set = isl_set_universe_like(set); + r = isl_set_foreach_basic_set(set, basic_set_bound_split, &cbs); + assert(r == 0); + return cloog_domain_from_isl_set(cbs.set); +} + + +/** + * cloog_scattering_lazy_block function: + * This function returns 1 if the two scattering functions s1 and s2 given + * as input are the same (except possibly for the final dimension, where we + * allow a difference of 1), assuming that the domains on which this + * scatterings are applied are the same. + * In fact this function answers the question "can I + * safely consider the two domains as only one with two statements (a block) ?". + * - s1 and s2 are the two domains to check for blocking, + * - scattering is the linked list of all domains, + * - scattdims is the total number of scattering dimentions. + */ +int cloog_scattering_lazy_block(CloogScattering *s1, CloogScattering *s2, + CloogScatteringList *scattering, int scattdims) +{ + int i; + struct isl_dim *dim; + struct isl_map *rel; + struct isl_set *delta; + isl_map *map1 = isl_map_from_cloog_scattering(s1); + isl_map *map2 = isl_map_from_cloog_scattering(s2); + int fixed, block; + isl_int cst; + unsigned n_scat; + + n_scat = isl_map_dim(map1, isl_dim_out); + if (n_scat != isl_map_dim(map2, isl_dim_out)) + return 0; + + dim = isl_map_get_dim(map1); + dim = isl_dim_domain(dim); + rel = isl_map_identity(dim); + rel = isl_map_apply_domain(rel, isl_map_copy(map1)); + rel = isl_map_apply_range(rel, isl_map_copy(map2)); + delta = isl_map_deltas(rel); + isl_int_init(cst); + for (i = 0; i < n_scat; ++i) { + fixed = isl_set_fast_dim_is_fixed(delta, i, &cst); + if (fixed != 1) + break; + if (i+1 < n_scat && !isl_int_is_zero(cst)) + break; + if (!isl_int_is_zero(cst) && !isl_int_is_one(cst)) + break; + } + block = i >= n_scat; + isl_int_clear(cst); + isl_set_free(delta); + return block; +} + + +/** + * cloog_domain_lazy_disjoint function: + * This function returns 1 if the domains given as input are disjoint, 0 if it + * is unable to decide. + */ +int cloog_domain_lazy_disjoint(CloogDomain *d1, CloogDomain *d2) +{ + isl_set *set1 = isl_set_from_cloog_domain(d1); + isl_set *set2 = isl_set_from_cloog_domain(d2); + return isl_set_fast_is_disjoint(set1, set2); +} + + +/** + * cloog_scattering_list_lazy_same function: + * This function returns 1 if two domains in the list are the same, 0 if it + * is unable to decide. + */ +int cloog_scattering_list_lazy_same(CloogScatteringList *list) +{ + CloogScatteringList *one, *other; + isl_map *one_map, *other_map; + + for (one = list; one; one = one->next) { + one_map = isl_map_from_cloog_scattering(one->scatt); + for (other = one->next; other; other = other->next) { + other_map = isl_map_from_cloog_scattering(other->scatt); + if (isl_map_fast_is_equal(one_map, other_map)) + return 1; + } + } + return 0; +} + +int cloog_domain_dimension(CloogDomain * domain) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + return isl_set_dim(set, isl_dim_set); +} + +int cloog_domain_parameter_dimension(CloogDomain *domain) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + return isl_set_dim(set, isl_dim_param); +} + +int cloog_scattering_dimension(CloogScattering *scatt, CloogDomain *domain) +{ + isl_map *map = isl_map_from_cloog_scattering(scatt); + return isl_map_dim(map, isl_dim_out); +} + +int cloog_domain_isconvex(CloogDomain * domain) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + return isl_set_n_basic_set(set) <= 1; +} + + +/** + * cloog_domain_cut_first function: + * This function splits off and returns the first convex set in the + * union "domain". The remainder of the union is returned in rest. + * The original "domain" itself is destroyed and may not be used + * after a call to this function. + */ +CloogDomain *cloog_domain_cut_first(CloogDomain *domain, CloogDomain **rest) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + struct isl_basic_set *first; + + first = isl_set_copy_basic_set(set); + set = isl_set_drop_basic_set(set, first); + *rest = cloog_domain_from_isl_set(set); + + return cloog_domain_from_isl_set(isl_set_from_basic_set(first)); +} + + +/** + * Given a union domain, try to find a simpler representation + * using fewer sets in the union. + * The original "domain" itself is destroyed and may not be used + * after a call to this function. + */ +CloogDomain *cloog_domain_simplify_union(CloogDomain *domain) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + return cloog_domain_from_isl_set(isl_set_coalesce(set)); +} + + +/** + * cloog_scattering_lazy_isscalar function: + * this function returns 1 if the scattering dimension 'dimension' in the + * scattering 'scatt' is constant. + * If value is not NULL, then it is set to the constant value of dimension. + */ +int cloog_scattering_lazy_isscalar(CloogScattering *scatt, int dimension, + cloog_int_t *value) +{ + isl_map *map = isl_map_from_cloog_scattering(scatt); + return isl_map_fast_is_fixed(map, isl_dim_out, dimension, value); +} + + +/** + * cloog_domain_lazy_isconstant function: + * this function returns 1 if the dimension 'dimension' in the + * domain 'domain' is constant. + * If value is not NULL, then it is set to the constant value of dimension. + */ +int cloog_domain_lazy_isconstant(CloogDomain *domain, int dimension, + cloog_int_t *value) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + return isl_set_fast_dim_is_fixed(set, dimension, value); +} + + +/** + * cloog_scattering_erase_dimension function: + * this function returns a CloogDomain structure builds from 'domain' where + * we removed the dimension 'dimension' and every constraint involving this + * dimension. + */ +CloogScattering *cloog_scattering_erase_dimension(CloogScattering *scattering, + int dimension) +{ + isl_map *map = isl_map_from_cloog_scattering(scattering); + map = isl_map_remove_dims(isl_map_copy(map), isl_dim_out, dimension, 1); + return cloog_scattering_from_isl_map(map); +} + +/** + * cloog_domain_cube: + * Construct and return a dim-dimensional cube, with values ranging + * between min and max in each dimension. + */ +CloogDomain *cloog_domain_cube(CloogState *state, + int dim, cloog_int_t min, cloog_int_t max) +{ + int i; + struct isl_basic_set *cube; + struct isl_basic_set *interval; + struct isl_basic_set_list *list; + + if (dim == 0) + return cloog_domain_universe(state, dim); + + interval = isl_basic_set_interval(state->backend->ctx, min, max); + list = isl_basic_set_list_alloc(state->backend->ctx, dim); + for (i = 0; i < dim; ++i) + list = isl_basic_set_list_add(list, isl_basic_set_copy(interval)); + isl_basic_set_free(interval); + cube = isl_basic_set_product(list); + return cloog_domain_from_isl_set(isl_set_from_basic_set(cube)); +} + + +/** + * cloog_domain_scatter function: + * This function add the scattering (scheduling) informations to a domain. + */ +CloogDomain *cloog_domain_scatter(CloogDomain *domain, CloogScattering *scatt) +{ + isl_set *set = isl_set_from_cloog_domain(domain); + isl_map *map = isl_map_from_cloog_scattering(scatt); + + map = isl_map_reverse(isl_map_copy(map)); + map = isl_map_intersect_range(map, set); + return cloog_domain_from_isl_set(isl_set_from_map(map)); +} + +static int add_domain_from_map(__isl_take isl_map *map, void *user) +{ + isl_dim *dim; + const char *name; + CloogDomain *domain; + CloogScattering *scat; + CloogUnionDomain **ud = (CloogUnionDomain **)user; + + dim = isl_map_get_dim(map); + name = isl_dim_get_tuple_name(dim, isl_dim_in); + domain = cloog_domain_from_isl_set(isl_map_domain(isl_map_copy(map))); + scat = cloog_scattering_from_isl_map(map); + *ud = cloog_union_domain_add_domain(*ud, name, domain, scat, NULL); + isl_dim_free(dim); + + return 0; +} + +/** + * Construct a CloogUnionDomain from an isl_union_map representing + * a global scattering function. The input is a mapping from different + * spaces (different tuple names and possibly different dimensions) + * to a common space. The iteration domains are set to the domains + * in each space. The statement names are set to the names of the + * spaces. The parameter names of the result are set to those of + * the input, but the iterator and scattering dimension names are + * left unspecified. + */ +CloogUnionDomain *cloog_union_domain_from_isl_union_map( + __isl_take isl_union_map *umap) +{ + int i; + int nparam; + isl_dim *dim; + CloogUnionDomain *ud; + + dim = isl_union_map_get_dim(umap); + nparam = isl_dim_size(dim, isl_dim_param); + + ud = cloog_union_domain_alloc(nparam); + + for (i = 0; i < nparam; ++i) { + const char *s = isl_dim_get_name(dim, isl_dim_param, i); + ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s); + } + isl_dim_free(dim); + + if (isl_union_map_foreach_map(umap, &add_domain_from_map, &ud) < 0) { + isl_union_map_free(umap); + cloog_union_domain_free(ud); + assert(0); + } + + isl_union_map_free(umap); + + return ud; +} + +static int count_same_name(__isl_keep isl_dim *dim, + enum isl_dim_type type, unsigned pos, const char *name) +{ + enum isl_dim_type t; + unsigned p, s; + int count = 0; + int len = strlen(name); + + for (t = isl_dim_param; t <= type && t <= isl_dim_out; ++t) { + s = t == type ? pos : isl_dim_size(dim, t); + for (p = 0; p < s; ++p) { + const char *n = isl_dim_get_name(dim, t, p); + if (n && !strncmp(n, name, len)) + count++; + } + } + return count; +} + +static int add_domain(__isl_take isl_set *set, void *user) +{ + int i, nvar; + isl_ctx *ctx; + isl_dim *dim; + char buffer[20]; + const char *name; + CloogDomain *domain; + CloogUnionDomain **ud = (CloogUnionDomain **)user; + + ctx = isl_set_get_ctx(set); + dim = isl_set_get_dim(set); + name = isl_dim_get_tuple_name(dim, isl_dim_set); + set = isl_set_flatten(set); + set = isl_set_set_tuple_name(set, NULL); + domain = cloog_domain_from_isl_set(set); + *ud = cloog_union_domain_add_domain(*ud, name, domain, NULL, NULL); + + nvar = isl_dim_size(dim, isl_dim_set); + for (i = 0; i < nvar; ++i) { + char *long_name = NULL; + int n; + + name = isl_dim_get_name(dim, isl_dim_set, i); + if (!name) { + snprintf(buffer, sizeof(buffer), "i%d", i); + name = buffer; + } + n = count_same_name(dim, isl_dim_set, i, name); + if (n) { + int size = strlen(name) + 10; + long_name = isl_alloc_array(ctx, char, size); + if (!long_name) + cloog_die("memory overflow.\n"); + snprintf(long_name, size, "%s_%d", name, n); + name = long_name; + } + *ud = cloog_union_domain_set_name(*ud, CLOOG_ITER, i, name); + free(long_name); + } + isl_dim_free(dim); + + return 0; +} + +/** + * Construct a CloogUnionDomain from an isl_union_set. + * The statement names are set to the names of the + * spaces. The parameter and iterator names of the result are set to those of + * the input, but the scattering dimension names are left unspecified. + */ +CloogUnionDomain *cloog_union_domain_from_isl_union_set( + __isl_take isl_union_set *uset) +{ + int i; + int nparam; + isl_dim *dim; + CloogUnionDomain *ud; + + dim = isl_union_set_get_dim(uset); + nparam = isl_dim_size(dim, isl_dim_param); + + ud = cloog_union_domain_alloc(nparam); + + for (i = 0; i < nparam; ++i) { + const char *s = isl_dim_get_name(dim, isl_dim_param, i); + ud = cloog_union_domain_set_name(ud, CLOOG_PARAM, i, s); + } + isl_dim_free(dim); + + if (isl_union_set_foreach_set(uset, &add_domain, &ud) < 0) { + isl_union_set_free(uset); + cloog_union_domain_free(ud); + assert(0); + } + + isl_union_set_free(uset); + + return ud; +} + +/* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */ +static void Euclid(cloog_int_t a, cloog_int_t b, + cloog_int_t *x, cloog_int_t *y, cloog_int_t *g) +{ + cloog_int_t c, d, e, f, tmp; + + cloog_int_init(c); + cloog_int_init(d); + cloog_int_init(e); + cloog_int_init(f); + cloog_int_init(tmp); + cloog_int_abs(c, a); + cloog_int_abs(d, b); + cloog_int_set_si(e, 1); + cloog_int_set_si(f, 0); + while (cloog_int_is_pos(d)) { + cloog_int_tdiv_q(tmp, c, d); + cloog_int_mul(tmp, tmp, f); + cloog_int_sub(e, e, tmp); + cloog_int_tdiv_q(tmp, c, d); + cloog_int_mul(tmp, tmp, d); + cloog_int_sub(c, c, tmp); + cloog_int_swap(c, d); + cloog_int_swap(e, f); + } + cloog_int_set(*g, c); + if (cloog_int_is_zero(a)) + cloog_int_set_si(*x, 0); + else if (cloog_int_is_pos(a)) + cloog_int_set(*x, e); + else cloog_int_neg(*x, e); + if (cloog_int_is_zero(b)) + cloog_int_set_si(*y, 0); + else { + cloog_int_mul(tmp, a, *x); + cloog_int_sub(tmp, c, tmp); + cloog_int_divexact(*y, tmp, b); + } + cloog_int_clear(c); + cloog_int_clear(d); + cloog_int_clear(e); + cloog_int_clear(f); + cloog_int_clear(tmp); +} + +/* Construct a CloogStride from the given constraint for the given level, + * if possible. + * We first compute the gcd of the coefficients of the existentially + * quantified variables and then remove any common factors it has + * with the coefficient at the given level. + * The result is the value of the stride and if it is not one, + * the it is possible to construct a CloogStride. + * The constraint leading to the stride is stored in the CloogStride + * as well a value (factor) such that the product of this value + * and the coefficient at the given level is equal to -1 modulo the stride. + */ +static CloogStride *construct_stride(isl_constraint *c, int level) +{ + int i, n, sign; + isl_int v, m, gcd, stride, factor; + CloogStride *s; + + if (!c) + return NULL; + + isl_int_init(v); + isl_int_init(m); + isl_int_init(gcd); + isl_int_init(factor); + isl_int_init(stride); + + isl_constraint_get_coefficient(c, isl_dim_set, level - 1, &v); + sign = isl_int_sgn(v); + isl_int_abs(m, v); + + isl_int_set_si(gcd, 0); + n = isl_constraint_dim(c, isl_dim_div); + for (i = 0; i < n; ++i) { + isl_constraint_get_coefficient(c, isl_dim_div, i, &v); + isl_int_gcd(gcd, gcd, v); + } + + isl_int_gcd(v, m, gcd); + isl_int_divexact(stride, gcd, v); + + if (isl_int_is_zero(stride) || isl_int_is_one(stride)) + s = NULL; + else { + Euclid(m, stride, &factor, &v, &gcd); + if (sign > 0) + isl_int_neg(factor, factor); + + c = isl_constraint_copy(c); + s = cloog_stride_alloc_from_constraint(stride, + cloog_constraint_from_isl_constraint(c), factor); + } + + isl_int_clear(stride); + isl_int_clear(factor); + isl_int_clear(gcd); + isl_int_clear(m); + isl_int_clear(v); + + return s; +} + +struct cloog_isl_find_stride_data { + int level; + CloogStride *stride; +}; + +/* Check if the given constraint can be used to derive + * a stride on the iterator identified by data->level. + * We first check that there are some existentially quantified variables + * and that the coefficient at data->level is non-zero. + * Then we call construct_stride for further checks and the actual + * construction of the CloogStride. + */ +static int find_stride(__isl_take isl_constraint *c, void *user) +{ + struct cloog_isl_find_stride_data *data; + int n; + isl_int v; + + data = (struct cloog_isl_find_stride_data *)user; + + if (data->stride) { + isl_constraint_free(c); + return 0; + } + + n = isl_constraint_dim(c, isl_dim_div); + if (n == 0) { + isl_constraint_free(c); + return 0; + } + + isl_int_init(v); + + isl_constraint_get_coefficient(c, isl_dim_set, data->level - 1, &v); + if (!isl_int_is_zero(v)) + data->stride = construct_stride(c, data->level); + + isl_int_clear(v); + + isl_constraint_free(c); + + return 0; +} + +/* Check if the given list of domains has a common stride on the given level. + * If so, return a pointer to a CloogStride object. If not, return NULL. + * + * We project out all later variables, take the union and compute + * the affine hull of the union. Then we check the (equality) + * constraints in this affine hull for imposing a stride. + */ +CloogStride *cloog_domain_list_stride(CloogDomainList *list, int level) +{ + struct cloog_isl_find_stride_data data = { level, NULL }; + isl_set *set; + isl_basic_set *aff; + int first = level; + int n; + int r; + + set = isl_set_from_cloog_domain(list->domain); + n = isl_set_dim(set, isl_dim_set) - first; + set = isl_set_project_out(isl_set_copy(set), isl_dim_set, first, n); + + for (list = list->next; list; list = list->next) { + isl_set *set_i = isl_set_from_cloog_domain(list->domain); + n = isl_set_dim(set_i, isl_dim_set) - first; + set_i = isl_set_project_out(isl_set_copy(set_i), + isl_dim_set, first, n); + set = isl_set_union(set, set_i); + } + aff = isl_set_affine_hull(set); + + r = isl_basic_set_foreach_constraint(aff, &find_stride, &data); + assert(r == 0); + + isl_basic_set_free(aff); + + return data.stride; +} diff --git a/cloog-core/source/loop.c b/cloog-core/source/loop.c new file mode 100644 index 0000000..176a655 --- /dev/null +++ b/cloog-core/source/loop.c @@ -0,0 +1,2483 @@ + + /**-------------------------------------------------------------------** + ** CLooG ** + **-------------------------------------------------------------------** + ** loop.c ** + **-------------------------------------------------------------------** + ** First version: october 26th 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 <stdlib.h> +# include <stdio.h> +# include "../include/cloog/cloog.h" + +#define ALLOC(type) (type*)malloc(sizeof(type)) + + +/****************************************************************************** + * Memory leaks hunting * + ******************************************************************************/ + + +/** + * These functions and global variables are devoted to memory leaks hunting: we + * want to know at each moment how many CloogLoop structures had been allocated + * (cloog_loop_allocated) and how many had been freed (cloog_loop_freed). + * Each time a CloogLoog structure is allocated, a call to the function + * cloog_loop_leak_up() must be carried out, and respectively + * cloog_loop_leak_down() when a CloogLoop structure is freed. The special + * variable cloog_loop_max gives the maximal number of CloogLoop structures + * simultaneously alive (i.e. allocated and non-freed) in memory. + * - July 3rd->11th 2003: first version (memory leaks hunt and correction). + */ + + +static void cloog_loop_leak_up(CloogState *state) +{ + state->loop_allocated++; + if ((state->loop_allocated - state->loop_freed) > state->loop_max) + state->loop_max = state->loop_allocated - state->loop_freed; +} + + +static void cloog_loop_leak_down(CloogState *state) +{ + state->loop_freed++; +} + + +/****************************************************************************** + * Structure display function * + ******************************************************************************/ + + +/** + * cloog_loop_print_structure function: + * Displays a loop structure in a way that trends to be understandable without + * falling in a deep depression or, for the lucky ones, getting a headache... + * Written by Olivier Chorier, Luc Marchaud, Pierre Martin and Romain Tartiere. + * - April 24th 2005: Initial version. + * - May 21rd 2005: - New parameter `F' for destination file (ie stdout), + * - Minor tweaks. + * - May 26th 2005: Memory leak hunt. + * - June 2nd 2005: (Ced) Integration and minor fixes. + * -June 22nd 2005: (Ced) Adaptation for GMP. + */ +void cloog_loop_print_structure(FILE * file, CloogLoop * loop, int level) +{ int i, j, first=1 ; + + if (loop) + { /* Go to the right level. */ + for (i=0; i<level; i++) + fprintf(file,"|\t") ; + + fprintf(file,"+-- CloogLoop\n") ; + } + + /* For each loop. */ + while (loop) + { if (!first) + { /* Go to the right level. */ + for (i=0; i<level; i++) + fprintf(file,"|\t") ; + + fprintf(file,"| CloogLoop\n") ; + } + else + first = 0 ; + + /* A blank line. */ + for(j=0; j<=level+1; j++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print the domain. */ + cloog_domain_print_structure(file, loop->domain, level+1, "CloogDomain"); + + /* Print the stride. */ + for(j=0; j<=level; j++) + fprintf(file,"|\t") ; + if (loop->stride) { + fprintf(file, "Stride: "); + cloog_int_print(file, loop->stride->stride); + fprintf(file, "\n"); + fprintf(file, "Offset: "); + cloog_int_print(file, loop->stride->offset); + fprintf(file, "\n"); + } + + /* A blank line. */ + for(j=0; j<=level+1; j++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print the block. */ + cloog_block_print_structure(file,loop->block,level+1) ; + + /* A blank line. */ + for (i=0; i<=level+1; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print inner if any. */ + if (loop->inner) + cloog_loop_print_structure(file,loop->inner,level+1) ; + + /* And let's go for the next one. */ + loop = loop->next ; + + /* One more time something that is here only for a better look. */ + if (!loop) + { /* Two blank lines if this is the end of the linked list. */ + for (j=0; j<2; j++) + { for (i=0; i<=level; i++) + fprintf(file,"|\t") ; + + fprintf(file,"\n") ; + } + } + else + { /* A special blank line if the is a next loop. */ + for (i=0; i<=level; i++) + fprintf(file,"|\t") ; + fprintf(file,"V\n") ; + } + } +} + + +/** + * cloog_loop_print function: + * This function prints the content of a CloogLoop structure (start) into a + * file (file, possibly stdout). + * - June 2nd 2005: Now this very old function (probably as old as CLooG) is + * only a frontend to cloog_loop_print_structure, with a quite + * better human-readable representation. + */ +void cloog_loop_print(FILE * file, CloogLoop * loop) +{ cloog_loop_print_structure(file,loop,0) ; +} + + +/****************************************************************************** + * Memory deallocation function * + ******************************************************************************/ + + +/** + * cloog_loop_free function: + * This function frees the allocated memory for a CloogLoop structure (loop), + * and frees its inner loops and its next loops. + * - June 22nd 2005: Adaptation for GMP. + */ +void cloog_loop_free(CloogLoop * loop) +{ CloogLoop * next ; + + while (loop != NULL) { + cloog_loop_leak_down(loop->state); + + next = loop->next ; + cloog_domain_free(loop->domain) ; + cloog_domain_free(loop->unsimplified); + cloog_block_free(loop->block) ; + if (loop->inner != NULL) + cloog_loop_free(loop->inner) ; + + cloog_stride_free(loop->stride); + free(loop) ; + loop = next ; + } +} + + +/** + * cloog_loop_free_parts function: + * This function frees the allocated memory for some parts of a CloogLoop + * structure (loop), each other argument is a boolean having to be set to 1 if + * we want to free the corresponding part, 0 otherwise. This function applies + * the same freeing policy to its inner ans next loops recursively. + * - July 3rd 2003: first version. + * - June 22nd 2005: Adaptation for GMP. + */ +void cloog_loop_free_parts(loop, domain, block, inner, next) +CloogLoop * loop ; +int domain, block, inner, next ; +{ CloogLoop * follow ; + + while (loop != NULL) { + cloog_loop_leak_down(loop->state); + follow = loop->next ; + + if (domain) + cloog_domain_free(loop->domain) ; + + if (block) + cloog_block_free(loop->block) ; + + if ((inner) && (loop->inner != NULL)) + cloog_loop_free_parts(loop->inner,domain,block,inner,1) ; + + cloog_stride_free(loop->stride); + free(loop) ; + if (next) + loop = follow ; + else + loop = NULL ; + } +} + + +/****************************************************************************** + * Reading functions * + ******************************************************************************/ + + +/** + * Construct a CloogLoop structure from a given iteration domain + * and statement number. + */ +CloogLoop *cloog_loop_from_domain(CloogState *state, CloogDomain *domain, + int number) +{ + int nb_iterators; + CloogLoop * loop ; + CloogStatement * statement ; + + /* Memory allocation and information reading for the first domain: */ + loop = cloog_loop_malloc(state); + /* domain. */ + loop->domain = domain; + if (loop->domain != NULL) + nb_iterators = cloog_domain_dimension(loop->domain); + else + nb_iterators = 0 ; + /* included statement block. */ + statement = cloog_statement_alloc(state, number + 1); + loop->block = cloog_block_alloc(statement, 0, NULL, nb_iterators); + + return loop ; +} + + +/** + * cloog_loop_read function: + * This function reads loop data from a file (foo, possibly stdin) and + * returns a pointer to a CloogLoop structure containing the read information. + * This function can be used only for input file reading, when one loop is + * associated with one statement. + * - number is the statement block number carried by the loop (-1 if none). + * - nb_parameters is the number of parameters. + ** + * - September 9th 2002: first version. + * - April 16th 2005: adaptation to new CloogStatement struct (with number). + * - June 11th 2005: adaptation to new CloogBlock structure. + * - June 22nd 2005: Adaptation for GMP. + */ +CloogLoop *cloog_loop_read(CloogState *state, + FILE *foo, int number, int nb_parameters) +{ + int op1, op2, op3; + char s[MAX_STRING]; + CloogDomain *domain; + + domain = cloog_domain_union_read(state, foo, nb_parameters); + + /* To read that stupid "0 0 0" line. */ + while (fgets(s,MAX_STRING,foo) == 0) ; + while ((*s=='#' || *s=='\n') || (sscanf(s," %d %d %d",&op1,&op2,&op3)<3)) + fgets(s,MAX_STRING,foo) ; + + return cloog_loop_from_domain(state, domain, number); +} + + +/****************************************************************************** + * Processing functions * + ******************************************************************************/ + + +/** + * cloog_loop_malloc function: + * This function allocates the memory space for a CloogLoop structure and + * sets its fields with default values. Then it returns a pointer to the + * allocated space. + * - November 21th 2005: first version. + */ +CloogLoop *cloog_loop_malloc(CloogState *state) +{ CloogLoop * loop ; + + /* Memory allocation for the CloogLoop structure. */ + loop = (CloogLoop *)malloc(sizeof(CloogLoop)) ; + if (loop == NULL) + cloog_die("memory overflow.\n"); + cloog_loop_leak_up(state); + + + /* We set the various fields with default values. */ + loop->state = state; + loop->domain = NULL ; + loop->unsimplified = NULL; + loop->block = NULL ; + loop->usr = NULL; + loop->inner = NULL ; + loop->next = NULL ; + loop->otl = 0; + loop->stride = NULL; + + return loop ; +} + + +/** + * cloog_loop_alloc function: + * This function allocates the memory space for a CloogLoop structure and + * sets its fields with those given as input. Then it returns a pointer to the + * allocated space. + * - October 27th 2001: first version. + * - June 22nd 2005: Adaptation for GMP. + * - November 21th 2005: use of cloog_loop_malloc. + */ +CloogLoop *cloog_loop_alloc(CloogState *state, + CloogDomain *domain, int otl, CloogStride *stride, + CloogBlock *block, CloogLoop *inner, CloogLoop *next) +{ CloogLoop * loop ; + + loop = cloog_loop_malloc(state); + + loop->domain = domain ; + loop->block = block ; + loop->inner = inner ; + loop->next = next ; + loop->otl = otl; + loop->stride = cloog_stride_copy(stride); + + return(loop) ; +} + + +/** + * cloog_loop_add function: + * This function adds a CloogLoop structure (loop) at a given place (now) of a + * NULL terminated list of CloogLoop structures. The beginning of this list + * is (start). This function updates (now) to (loop), and updates (start) if the + * added element is the first one -that is when (start) is NULL-. + * - October 28th 2001: first version. + */ +void cloog_loop_add(CloogLoop ** start, CloogLoop ** now, CloogLoop * loop) +{ if (*start == NULL) + { *start = loop ; + *now = *start ; + } + else + { (*now)->next = loop ; + *now = (*now)->next ; + } +} + + +/** + * cloog_loop_add function: + * This function adds a CloogLoop structure (loop) at a given place (now) of a + * NULL terminated list of CloogLoop structures. The beginning of this list + * is (start). This function updates (now) to the end of the loop list (loop), + * and updates (start) if the added element is the first one -that is when + * (start) is NULL-. + * - September 9th 2005: first version. + */ +void cloog_loop_add_list(CloogLoop ** start, CloogLoop ** now, CloogLoop * loop) +{ if (*start == NULL) + { *start = loop ; + *now = *start ; + } + else + { (*now)->next = loop ; + *now = (*now)->next ; + } + + while ((*now)->next != NULL) + *now = (*now)->next ; +} + + +/** + * cloog_loop_copy function: + * This function returns a copy of the CloogLoop structure given as input. In + * fact, there is just new allocations for the CloogLoop structures, but their + * contents are the same. + * - October 28th 2001: first version. + * - July 3rd->11th 2003: memory leaks hunt and correction. + */ +CloogLoop * cloog_loop_copy(CloogLoop * source) +{ CloogLoop * loop ; + CloogBlock * block ; + CloogDomain * domain ; + + loop = NULL ; + if (source != NULL) + { domain = cloog_domain_copy(source->domain) ; + block = cloog_block_copy(source->block) ; + loop = cloog_loop_alloc(source->state, domain, source->otl, + source->stride, block, NULL, NULL); + loop->usr = source->usr; + loop->inner = cloog_loop_copy(source->inner) ; + loop->next = cloog_loop_copy(source->next) ; + } + return(loop) ; +} + + +/** + * cloog_loop_add_disjoint function: + * This function adds some CloogLoop structures at a given place (now) of a + * NULL terminated list of CloogLoop structures. The beginning of this list + * is (start). (loop) can be an union of polyhedra, this function separates the + * union into a list of *disjoint* polyhedra then adds the list. This function + * updates (now) to the end of the list and updates (start) if first added + * element is the first of the principal list -that is when (start) is NULL-. + * (loop) can be freed by this function, basically when its domain is actually + * a union of polyhedra, but don't worry, all the useful data are now stored + * inside the list (start). We do not use PolyLib's Domain_Disjoint function, + * since the number of union components is often higher (thus code size too). + * - October 28th 2001: first version. + * - November 14th 2001: bug correction (this one was hard to find !). + * - July 3rd->11th 2003: memory leaks hunt and correction. + * - June 22nd 2005: Adaptation for GMP. + * - October 27th 2005: (debug) included blocks were not copied for new loops. + */ +void cloog_loop_add_disjoint(start, now, loop) +CloogLoop ** start, ** now, * loop ; +{ + CloogLoop * sep, * inner ; + CloogDomain *domain, *seen, *temp, *rest; + CloogBlock * block ; + + if (cloog_domain_isconvex(loop->domain)) + cloog_loop_add(start,now,loop) ; + else { + domain = cloog_domain_simplify_union(loop->domain); + loop->domain = NULL ; + + /* We separate the first element of the rest of the union. */ + domain = cloog_domain_cut_first(domain, &rest); + + /* This first element is the first of the list of disjoint polyhedra. */ + sep = cloog_loop_alloc(loop->state, domain, 0, NULL, + loop->block, loop->inner, NULL); + cloog_loop_add(start,now,sep) ; + + seen = cloog_domain_copy(domain); + while (!cloog_domain_isempty(domain = rest)) { + temp = cloog_domain_cut_first(domain, &rest); + domain = cloog_domain_difference(temp, seen); + cloog_domain_free(temp); + + if (cloog_domain_isempty(domain)) { + cloog_domain_free(domain); + continue; + } + + /* Each new loop will have its own life, for instance we can free its + * inner loop and included block. Then each one must have its own copy + * of both 'inner' and 'block'. + */ + inner = cloog_loop_copy(loop->inner) ; + block = cloog_block_copy(loop->block) ; + + sep = cloog_loop_alloc(loop->state, cloog_domain_copy(domain), + 0, NULL, block, inner, NULL); + /* domain can be an union too. If so: recursion. */ + if (cloog_domain_isconvex(domain)) + cloog_loop_add(start,now,sep) ; + else + cloog_loop_add_disjoint(start,now,sep) ; + + if (cloog_domain_isempty(rest)) { + cloog_domain_free(domain); + break; + } + + seen = cloog_domain_union(seen, domain); + } + cloog_domain_free(rest); + cloog_domain_free(seen); + cloog_loop_free_parts(loop,0,0,0,0) ; + } +} + + +/** + * cloog_loop_disjoint function: + * This function returns a list of loops such that each loop with non-convex + * domain in the input list (loop) is separated into several loops where the + * domains are the components of the union of *disjoint* polyhedra equivalent + * to the original non-convex domain. See cloog_loop_add_disjoint comments + * for more details. + * - September 16th 2005: first version. + */ +CloogLoop * cloog_loop_disjoint(CloogLoop * loop) +{ CloogLoop *res=NULL, * now=NULL, * next ; + + /* Because this is often the case, don't waste time ! */ + if (loop && !loop->next && cloog_domain_isconvex(loop->domain)) + return loop ; + + while (loop != NULL) + { next = loop->next ; + loop->next = NULL ; + cloog_loop_add_disjoint(&res,&now,loop) ; + loop = next ; + } + + return res ; +} + + +/** + * cloog_loop_restrict function: + * This function returns the (loop) in the context of (context): it makes the + * intersection between the (loop) domain and the (context), then it returns + * a pointer to a new loop, with this intersection as domain. + ** + * - October 27th 2001: first version. + * - June 15th 2005: a memory leak fixed (domain was not freed when empty). + * - June 22nd 2005: Adaptation for GMP. + */ +CloogLoop *cloog_loop_restrict(CloogLoop *loop, CloogDomain *context) +{ int new_dimension ; + CloogDomain * domain, * extended_context, * new_domain ; + CloogLoop * new_loop ; + + domain = loop->domain ; + if (cloog_domain_dimension(domain) > cloog_domain_dimension(context)) + { + new_dimension = cloog_domain_dimension(domain); + extended_context = cloog_domain_extend(context, new_dimension); + new_domain = cloog_domain_intersection(extended_context,loop->domain) ; + cloog_domain_free(extended_context) ; + } + else + new_domain = cloog_domain_intersection(context,loop->domain) ; + + if (cloog_domain_isempty(new_domain)) + { cloog_domain_free(new_domain) ; + return(NULL) ; + } + else { + new_loop = cloog_loop_alloc(loop->state, new_domain, + 0, NULL, loop->block, loop->inner, NULL); + return(new_loop) ; + } +} + + +/** + * Call cloog_loop_restrict on each loop in the list "loop" and return + * the concatenated result. + */ +CloogLoop *cloog_loop_restrict_all(CloogLoop *loop, CloogDomain *context) +{ + CloogLoop *next; + CloogLoop *res = NULL; + CloogLoop **res_next = &res; + + for (; loop; loop = next) { + next = loop->next; + + *res_next = cloog_loop_restrict(loop, context); + if (*res_next) { + res_next = &(*res_next)->next; + cloog_loop_free_parts(loop, 1, 0, 0, 0); + } else { + loop->next = NULL; + cloog_loop_free(loop); + } + } + + return res; +} + + +/** + * Restrict the domains of the inner loops of each loop l in the given + * list of loops to the domain of the loop l. If the domains of all + * inner loops of a given loop l turn out to be empty, then remove l + * from the list. + */ +CloogLoop *cloog_loop_restrict_inner(CloogLoop *loop) +{ + CloogLoop *next; + CloogLoop *res; + CloogLoop **res_next = &res; + + for (; loop; loop = next) { + next = loop->next; + + loop->inner = cloog_loop_restrict_all(loop->inner, loop->domain); + if (loop->inner) { + *res_next = loop; + res_next = &(*res_next)->next; + } else { + loop->next = NULL; + cloog_loop_free(loop); + } + } + + *res_next = NULL; + + return res; +} + +/** + * cloog_loop_project function: + * This function returns the projection of (loop) on the (level) first + * dimensions (outer loops). It makes the projection of the (loop) domain, + * then it returns a pointer to a new loop, with this projection as domain. + ** + * - October 27th 2001: first version. + * - July 3rd->11th 2003: memory leaks hunt and correction. + * - June 22nd 2005: Adaptation for GMP. + */ +CloogLoop * cloog_loop_project(CloogLoop * loop, int level) +{ + CloogDomain * new_domain ; + CloogLoop * new_loop, * copy ; + + copy = cloog_loop_alloc(loop->state, loop->domain, loop->otl, loop->stride, + loop->block, loop->inner, NULL); + + if (cloog_domain_dimension(loop->domain) == level) + new_domain = cloog_domain_copy(loop->domain) ; + else + new_domain = cloog_domain_project(loop->domain, level); + + new_loop = cloog_loop_alloc(loop->state, new_domain, 0, NULL, + NULL, copy, NULL); + + return(new_loop) ; +} + + +/** + * Call cloog_loop_project on each loop in the list "loop" and return + * the concatenated result. + */ +CloogLoop *cloog_loop_project_all(CloogLoop *loop, int level) +{ + CloogLoop *next; + CloogLoop *res = NULL; + CloogLoop **res_next = &res; + + for (; loop; loop = next) { + next = loop->next; + + *res_next = cloog_loop_project(loop, level); + res_next = &(*res_next)->next; + cloog_loop_free_parts(loop, 0, 0, 0, 0); + } + + return res; +} + + +/** + * cloog_loop_concat function: + * This function returns a pointer to the concatenation of the + * CloogLoop lists given as input. + * - October 28th 2001: first version. + */ +CloogLoop * cloog_loop_concat(CloogLoop * a, CloogLoop * b) +{ CloogLoop * loop, * temp ; + + loop = a ; + temp = loop ; + if (loop != NULL) + { while (temp->next != NULL) + temp = temp->next ; + temp->next = b ; + } + else + loop = b ; + + return(loop) ; +} + + +/** + * cloog_loop_combine: + * Combine consecutive loops with identical domains into + * a single loop with the concatenation of their inner loops + * as inner loop. + */ +CloogLoop *cloog_loop_combine(CloogLoop *loop) +{ + CloogLoop *first, *second; + + for (first = loop; first; first = first->next) { + while (first->next) { + if (!cloog_domain_lazy_equal(first->domain, first->next->domain)) + break; + second = first->next; + first->inner = cloog_loop_concat(first->inner, second->inner); + first->next = second->next; + cloog_loop_free_parts(second, 1, 0, 0, 0); + } + } + + return loop; +} + +/** + * Remove loops from list that have an empty domain. + */ +CloogLoop *cloog_loop_remove_empty_domain_loops(CloogLoop *loop) +{ + CloogLoop *l, *res, *next, **res_next; + + res = NULL; + res_next = &res; + for (l = loop; l; l = next) { + next = l->next; + if (cloog_domain_isempty(l->domain)) + cloog_loop_free_parts(l, 1, 1, 1, 0); + else { + *res_next = l; + res_next = &(*res_next)->next; + } + } + *res_next = NULL; + + return res; +} + +CloogLoop *cloog_loop_decompose_inner(CloogLoop *loop, + int level, int scalar, int *scaldims, int nb_scattdims); + +/* For each loop with only one inner loop, replace the domain + * of the loop with the projection of the domain of the inner + * loop. To increase the number of loops with a single inner + * we first decompose the inner loops into strongly connected + * components. + */ +CloogLoop *cloog_loop_specialize(CloogLoop *loop, + int level, int scalar, int *scaldims, int nb_scattdims) +{ + int dim; + CloogDomain *domain; + CloogLoop *l; + + loop = cloog_loop_decompose_inner(loop, level, scalar, + scaldims, nb_scattdims); + + for (l = loop; l; l = l->next) { + if (l->inner->next) + continue; + if (!cloog_domain_isconvex(l->inner->domain)) + continue; + + dim = cloog_domain_dimension(l->domain); + domain = cloog_domain_project(l->inner->domain, dim); + if (cloog_domain_isconvex(domain)) { + cloog_domain_free(l->domain); + l->domain = domain; + } else { + cloog_domain_free(domain); + } + } + + return cloog_loop_remove_empty_domain_loops(loop); +} + +/** + * cloog_loop_separate function: + * This function implements the Quillere algorithm for separation of multiple + * loops: for a given set of polyhedra (loop), it computes a set of disjoint + * polyhedra such that the unions of these sets are equal, and returns this set. + * - October 28th 2001: first version. + * - November 14th 2001: elimination of some unused blocks. + * - August 13th 2002: (debug) in the case of union of polyhedra for one + * loop, redundant constraints are fired. + * - July 3rd->11th 2003: memory leaks hunt and correction. + * - June 22nd 2005: Adaptation for GMP. + * - October 16th 2005: Removal of the non-shared constraint elimination when + * there is only one loop in the list (seems to work + * without now, DomainSimplify may have been improved). + * The problem was visible with test/iftest2.cloog. + */ +CloogLoop * cloog_loop_separate(CloogLoop * loop) +{ int lazy_equal=0, disjoint = 0; + CloogLoop * new_loop, * new_inner, * res, * now, * temp, * Q, + * inner, * old /*, * previous, * next*/ ; + CloogDomain *UQ, *domain; + + if (loop == NULL) + return NULL ; + + loop = cloog_loop_combine(loop); + + if (loop->next == NULL) + return cloog_loop_disjoint(loop) ; + + UQ = cloog_domain_copy(loop->domain) ; + domain = cloog_domain_copy(loop->domain) ; + res = cloog_loop_alloc(loop->state, domain, 0, NULL, + loop->block, loop->inner, NULL); + + old = loop ; + while((loop = loop->next) != NULL) + { temp = NULL ; + + /* For all Q, add Q-loop associated with the blocks of Q alone, + * and Q inter loop associated with the blocks of Q and loop. + */ + for (Q = res; Q; Q = Q->next) { + /* Add (Q inter loop). */ + if ((disjoint = cloog_domain_lazy_disjoint(Q->domain,loop->domain))) + domain = NULL ; + else + { if ((lazy_equal = cloog_domain_lazy_equal(Q->domain,loop->domain))) + domain = cloog_domain_copy(Q->domain) ; + else + domain = cloog_domain_intersection(Q->domain,loop->domain) ; + + if (!cloog_domain_isempty(domain)) + { new_inner = cloog_loop_concat(cloog_loop_copy(Q->inner), + cloog_loop_copy(loop->inner)) ; + new_loop = cloog_loop_alloc(loop->state, domain, 0, NULL, + NULL, new_inner, NULL); + cloog_loop_add_disjoint(&temp,&now,new_loop) ; + } + else { + disjoint = 1; + cloog_domain_free(domain); + } + } + + /* Add (Q - loop). */ + if (disjoint) + domain = cloog_domain_copy(Q->domain) ; + else + { if (lazy_equal) + domain = cloog_domain_empty(Q->domain); + else + domain = cloog_domain_difference(Q->domain,loop->domain) ; + } + + if (!cloog_domain_isempty(domain)) { + new_loop = cloog_loop_alloc(loop->state, domain, 0, NULL, + NULL, Q->inner, NULL); + cloog_loop_add_disjoint(&temp,&now,new_loop) ; + } + else + { cloog_domain_free(domain) ; + /* If Q->inner is no more useful, we can free it. */ + inner = Q->inner ; + Q->inner = NULL ; + cloog_loop_free(inner) ; + } + } + + /* Add loop-UQ associated with the blocks of loop alone.*/ + if (cloog_domain_lazy_disjoint(loop->domain,UQ)) + domain = cloog_domain_copy(loop->domain) ; + else + { if (cloog_domain_lazy_equal(loop->domain,UQ)) + domain = cloog_domain_empty(UQ); + else + domain = cloog_domain_difference(loop->domain,UQ) ; + } + + if (!cloog_domain_isempty(domain)) { + new_loop = cloog_loop_alloc(loop->state, domain, 0, NULL, + NULL, loop->inner, NULL); + cloog_loop_add_disjoint(&temp,&now,new_loop) ; + } + else + { cloog_domain_free(domain) ; + /* If loop->inner is no more useful, we can free it. */ + cloog_loop_free(loop->inner) ; + } + + loop->inner = NULL ; + + if (loop->next != NULL) + UQ = cloog_domain_union(UQ, cloog_domain_copy(loop->domain)); + else + cloog_domain_free(UQ); + + cloog_loop_free_parts(res,1,0,0,1) ; + + res = temp ; + } + cloog_loop_free_parts(old,1,0,0,1) ; + + return(res) ; +} + + +static CloogDomain *bounding_domain(CloogDomain *dom, CloogOptions *options) +{ + if (options->sh) + return cloog_domain_simple_convex(dom); + else + return cloog_domain_convex(dom); +} + + +/** + * cloog_loop_merge function: + * This function is the 'soft' version of loop_separate if we are looking for + * a code much simpler (and less efficicient). This function returns the new + * CloogLoop list. + * - October 29th 2001: first version. + * - July 3rd->11th 2003: memory leaks hunt and correction. + * - June 22nd 2005: Adaptation for GMP. + */ +CloogLoop *cloog_loop_merge(CloogLoop *loop, int level, CloogOptions *options) +{ + CloogLoop *res, *new_inner, *old; + CloogDomain *new_domain, *temp; + + if (loop == NULL) + return loop; + + if (loop->next == NULL && cloog_domain_isconvex(loop->domain)) + return loop; + + old = loop; + temp = loop->domain; + loop->domain = NULL; + new_inner = loop->inner; + + for (loop = loop->next; loop; loop = loop->next) { + temp = cloog_domain_union(temp, loop->domain); + loop->domain = NULL; + new_inner = cloog_loop_concat(new_inner, loop->inner); + } + + new_domain = bounding_domain(temp, options); + + if (level > 0 && !cloog_domain_is_bounded(new_domain, level) && + cloog_domain_is_bounded(temp, level)) { + CloogDomain *splitter, *t2; + + cloog_domain_free(new_domain); + splitter = cloog_domain_bound_splitter(temp, level); + + res = NULL; + while (!cloog_domain_isconvex(splitter)) { + CloogDomain *first, *rest; + first = cloog_domain_cut_first(splitter, &rest); + splitter = rest; + t2 = cloog_domain_intersection(first, temp); + cloog_domain_free(first); + + new_domain = bounding_domain(t2, options); + cloog_domain_free(t2); + + if (cloog_domain_isempty(new_domain)) { + cloog_domain_free(new_domain); + continue; + } + res = cloog_loop_alloc(old->state, new_domain, 0, NULL, + NULL, cloog_loop_copy(new_inner), res); + } + + t2 = cloog_domain_intersection(splitter, temp); + cloog_domain_free(splitter); + + new_domain = bounding_domain(t2, options); + cloog_domain_free(t2); + + if (cloog_domain_isempty(new_domain)) { + cloog_domain_free(new_domain); + cloog_loop_free(new_inner); + } else + res = cloog_loop_alloc(old->state, new_domain, 0, NULL, + NULL, new_inner, res); + } else { + res = cloog_loop_alloc(old->state, new_domain, 0, NULL, + NULL, new_inner, NULL); + } + cloog_domain_free(temp); + + cloog_loop_free_parts(old, 0, 0, 0, 1); + + return res; +} + + +static int cloog_loop_count(CloogLoop *loop) +{ + int nb_loops; + + for (nb_loops = 0; loop; loop = loop->next) + nb_loops++; + + return nb_loops; +} + + +/** + * cloog_loop_sort function: + * Adaptation from LoopGen 0.4 by F. Quillere. This function sorts a list of + * parameterized disjoint polyhedra, in order to not have lexicographic order + * violation (see Quillere paper). + * - September 16th 2005: inclusion of cloog_loop_number (October 29th 2001). + */ +CloogLoop *cloog_loop_sort(CloogLoop *loop, int level) +{ + CloogLoop *res, *now, **loop_array; + CloogDomain **doms; + int i, nb_loops=0, * permut ; + + /* There is no need to sort the parameter domains. */ + if (!level) + return loop; + + /* We will need to know how many loops are in the list. */ + nb_loops = cloog_loop_count(loop); + + /* If there is only one loop, it's the end. */ + if (nb_loops == 1) + return(loop) ; + + /* We have to allocate memory for some useful components: + * - loop_array: the loop array, + * - doms: the array of domains to sort, + * - permut: will give us a possible sort (maybe not the only one). + */ + loop_array = (CloogLoop **)malloc(nb_loops*sizeof(CloogLoop *)) ; + doms = (CloogDomain **)malloc(nb_loops*sizeof(CloogDomain *)); + permut = (int *)malloc(nb_loops*sizeof(int)) ; + + /* We fill up the loop and domain arrays. */ + for (i=0;i<nb_loops;i++,loop=loop->next) + { loop_array[i] = loop ; + doms[i] = loop_array[i]->domain; + } + + /* cloog_domain_sort will fill up permut. */ + cloog_domain_sort(doms, nb_loops, level, permut); + + /* With permut and loop_array we build the sorted list. */ + res = NULL ; + for (i=0;i<nb_loops;i++) + { /* To avoid pointer looping... loop_add will rebuild the list. */ + loop_array[permut[i]-1]->next = NULL ; + cloog_loop_add(&res,&now,loop_array[permut[i]-1]) ; + } + + free(permut) ; + free(doms); + free(loop_array) ; + + return res; +} + + +/** + * cloog_loop_nest function: + * This function changes the loop list in such a way that we have no more than + * one dimension added by level. It returns an equivalent loop list with + * this property. + * - October 29th 2001: first version. + * - July 3rd->11th 2003: memory leaks hunt and correction. + * - June 22nd 2005: Adaptation for GMP. + * - November 21th 2005: (debug) now OK when cloog_loop_restrict returns NULL. + */ +CloogLoop *cloog_loop_nest(CloogLoop *loop, CloogDomain *context, int level) +{ int l ; + CloogLoop * p, * temp, * res, * now, * next ; + CloogDomain * new_domain ; + + loop = cloog_loop_disjoint(loop); + + res = NULL ; + /* Each domain is changed by its intersection with the context. */ + while (loop != NULL) + { p = cloog_loop_restrict(loop, context); + next = loop->next ; + + if (p != NULL) + { cloog_loop_free_parts(loop,1,0,0,0) ; + + temp = cloog_loop_alloc(p->state, p->domain, 0, NULL, + p->block, p->inner, NULL); + + /* If the intersection dimension is too big, we make projections smaller + * and smaller, and each projection includes the preceding projection + * (thus, in the target list, dimensions are added one by one). + */ + if (cloog_domain_dimension(p->domain) >= level) + for (l = cloog_domain_dimension(p->domain); l >= level; l--) { + new_domain = cloog_domain_project(p->domain, l); + temp = cloog_loop_alloc(p->state, new_domain, 0, NULL, + NULL, temp, NULL); + } + + /* p is no more useful (but its content yes !). */ + cloog_loop_free_parts(p,0,0,0,0) ; + + cloog_loop_add(&res,&now,temp) ; + } + else + cloog_loop_free_parts(loop,1,1,1,0) ; + + loop = next ; + } + + return(res) ; +} + + +/* Check if the domains of the inner loops impose a stride constraint + * on the given level. + * The core of the search is implemented in cloog_domain_list_stride. + * Here, we simply construct a list of domains to pass to this function + * and if a stride is found, we adjust the lower bounds by calling + * cloog_domain_stride_lower_bound. + */ +static int cloog_loop_variable_offset_stride(CloogLoop *loop, int level) +{ + CloogDomainList *list = NULL; + CloogLoop *inner; + CloogStride *stride; + + for (inner = loop->inner; inner; inner = inner->next) { + CloogDomainList *entry = ALLOC(CloogDomainList); + entry->domain = cloog_domain_copy(inner->domain); + entry->next = list; + list = entry; + } + + stride = cloog_domain_list_stride(list, level); + + cloog_domain_list_free(list); + + if (!stride) + return 0; + + loop->stride = stride; + loop->domain = cloog_domain_stride_lower_bound(loop->domain, level, stride); + + return 1; +} + + +/** + * cloog_loop_stride function: + * This function will find the stride of a loop for the iterator at the column + * number 'level' in the constraint matrix. It will update the lower bound of + * the iterator accordingly. Basically, the function will try to find in the + * inner loops a common condition on this iterator for the inner loop iterators + * to be integral. For instance, let us consider a loop with the iterator i, + * the iteration domain -4<=i<=n, and its two inner loops with the iterator j. + * The first inner loop has the constraint 3j=i, and the second one has the + * constraint 6j=i. Then the common constraint on i for j to be integral is + * i%3=0, the stride for i is 3. Lastly, we have to find the new lower bound + * for i: the first value satisfying the common constraint: -3. At the end, the + * iteration domain for i is -3<=i<=n and the stride for i is 3. + * + * The algorithm implemented in this function only allows for strides + * on loops with a lower bound that has a constant remainder on division + * by the stride. Before initiating this procedure, we first check + * if we can find a stride with a lower bound with a variable offset in + * cloog_loop_variable_offset_stride. + * + * - loop is the loop including the iteration domain of the considered iterator, + * - level is the column number of the iterator in the matrix of contraints. + ** + * - June 29th 2003: first version (work in progress since June 26th 2003). + * - July 14th 2003: simpler version. + * - June 22nd 2005: Adaptation for GMP (from S. Verdoolaege's 0.12.1 version). + */ +void cloog_loop_stride(CloogLoop * loop, int level) +{ int first_search ; + cloog_int_t stride, ref_offset, offset, potential; + CloogLoop * inner ; + + if (!cloog_domain_can_stride(loop->domain, level)) + return; + + if (cloog_loop_variable_offset_stride(loop, level)) + return; + + cloog_int_init(stride); + cloog_int_init(ref_offset); + cloog_int_init(offset); + cloog_int_init(potential); + + cloog_int_set_si(ref_offset, 0); + cloog_int_set_si(offset, 0); + + /* Default stride. */ + cloog_int_set_si(stride, 1); + first_search = 1 ; + inner = loop->inner ; + + while (inner != NULL) + { /* If the minimun stride has not been found yet, find the stride. */ + if ((first_search) || (!cloog_int_is_one(stride))) + { + cloog_domain_stride(inner->domain, level, &potential, &offset); + if (!cloog_int_is_one(potential) && (!first_search)) + { /* Offsets must be the same for common stride. */ + cloog_int_gcd(stride, potential, stride); + if (!cloog_int_is_zero(stride)) { + cloog_int_fdiv_r(offset, offset, stride); + cloog_int_fdiv_r(ref_offset, ref_offset, stride); + } + if (cloog_int_ne(offset,ref_offset)) + cloog_int_set_si(stride, 1); + } + else { + cloog_int_set(stride, potential); + cloog_int_set(ref_offset, offset); + } + + first_search = 0 ; + } + + inner = inner->next ; + } + + if (cloog_int_is_zero(stride)) + cloog_int_set_si(stride, 1); + + /* Update the values if necessary. */ + if (!cloog_int_is_one(stride)) + { /* Update the stride value. */ + if (!cloog_int_is_zero(offset)) + cloog_int_sub(offset, stride, offset); + loop->stride = cloog_stride_alloc(stride, offset); + loop->domain = cloog_domain_stride_lower_bound(loop->domain, level, + loop->stride); + } + + cloog_int_clear(stride); + cloog_int_clear(ref_offset); + cloog_int_clear(offset); + cloog_int_clear(potential); +} + + +void cloog_loop_otl(CloogLoop *loop, int level) +{ + if (cloog_domain_is_otl(loop->domain, level)) + loop->otl = 1; +} + + +/** + * cloog_loop_stop function: + * This function implements the 'stop' option : each domain of each loop + * in the list 'loop' is replaced by 'context'. 'context' should be the + * domain of the outer loop. By using this method, there are no more dimensions + * to scan and the simplification step will automaticaly remove the domains + * since they are the same as the corresponding contexts. The effect of this + * function is to stop the code generation at the level this function is called, + * the resulting code do not consider the next dimensions. + * - January 11th 2005: first version. + */ +CloogLoop * cloog_loop_stop(CloogLoop * loop, CloogDomain * context) +{ if (loop == NULL) + return NULL ; + else + { cloog_domain_free(loop->domain) ; + loop->domain = cloog_domain_copy(context) ; + loop->next = cloog_loop_stop(loop->next, context) ; + } + + return loop ; +} + + +static int level_is_constant(int level, int scalar, int *scaldims, int nb_scattdims) +{ + return level && (level+scalar <= nb_scattdims) && (scaldims[level+scalar-1]); +} + + +/** + * Compare the constant dimensions of loops 'l1' and 'l2' starting at 'scalar' + * and return -1 if the vector of constant dimensions of 'l1' is smaller + * than that of 'l2', 0 if they are the same and +1 if that of 'l1' is + * greater than that of 'l2'. + * This function should be called on the innermost loop (the loop + * containing a block). + * \param l1 Loop to be compared with l2. + * \param l2 Loop to be compared with l1. + * \param level Current non-scalar dimension. + * \param scaldims Boolean array saying whether a dimension is scalar or not. + * \param nb_scattdims Size of the scaldims array. + * \param scalar Current scalar dimension. + * \return -1 if (l1 < l2), 0 if (l1 == l2) and +1 if (l1 > l2) + */ +int cloog_loop_constant_cmp(CloogLoop *l1, CloogLoop *l2, int level, + int *scaldims, int nb_scattdims, int scalar) +{ + CloogBlock *b1, *b2; + b1 = l1->block; + b2 = l2->block; + while (level_is_constant(level, scalar, scaldims, nb_scattdims)) { + int cmp = cloog_int_cmp(b1->scaldims[scalar], b2->scaldims[scalar]); + if (cmp) + return cmp; + scalar++; + } + return 0; +} + + +/** + * cloog_loop_scalar_gt function: + * This function returns 1 if loop 'l1' is greater than loop 'l2' for the + * scalar dimension vector that begins at dimension 'scalar', 0 otherwise. What + * we want to know is whether a loop is scheduled before another one or not. + * This function solves the problem when the considered dimension for scheduling + * is a scalar dimension. Since there may be a succession of scalar dimensions, + * this function will reason about the vector of scalar dimension that begins + * at dimension 'level+scalar' and finish to the first non-scalar dimension. + * \param l1 Loop to be compared with l2. + * \param l2 Loop to be compared with l1. + * \param level Current non-scalar dimension. + * \param scaldims Boolean array saying whether a dimension is scalar or not. + * \param nb_scattdims Size of the scaldims array. + * \param scalar Current scalar dimension. + * \return 1 if (l1 > l2), 0 otherwise. + ** + * - September 9th 2005: first version. + * - October 15nd 2007: now "greater than" instead of "greater or equal". + */ +int cloog_loop_scalar_gt(l1, l2, level, scaldims, nb_scattdims, scalar) +CloogLoop * l1, * l2 ; +int level, * scaldims, nb_scattdims, scalar ; +{ + return cloog_loop_constant_cmp(l1, l2, level, scaldims, nb_scattdims, scalar) > 0; +} + + +/** + * cloog_loop_scalar_eq function: + * This function returns 1 if loop 'l1' is equal to loop 'l2' for the scalar + * dimension vector that begins at dimension 'scalar', 0 otherwise. What we want + * to know is whether two loops are scheduled for the same time or not. + * This function solves the problem when the considered dimension for scheduling + * is a scalar dimension. Since there may be a succession of scalar dimensions, + * this function will reason about the vector of scalar dimension that begins + * at dimension 'level+scalar' and finish to the first non-scalar dimension. + * - l1 and l2 are the loops to compare, + * - level is the current non-scalar dimension, + * - scaldims is the boolean array saying whether a dimension is scalar or not, + * - nb_scattdims is the size of the scaldims array, + * - scalar is the current scalar dimension. + ** + * - September 9th 2005 : first version. + */ +int cloog_loop_scalar_eq(l1, l2, level, scaldims, nb_scattdims, scalar) +CloogLoop * l1, * l2 ; +int level, * scaldims, nb_scattdims, scalar ; +{ + return cloog_loop_constant_cmp(l1, l2, level, scaldims, nb_scattdims, scalar) == 0; +} + + +/** + * cloog_loop_scalar_sort function: + * This function sorts a linked list of loops (loop) with respect to the + * scalar dimension vector that begins at dimension 'scalar'. Since there may + * be a succession of scalar dimensions, this function will reason about the + * vector of scalar dimension that begins at dimension 'level+scalar' and + * finish to the first non-scalar dimension. + * \param loop Loop list to sort. + * \param level Current non-scalar dimension. + * \param scaldims Boolean array saying whether a dimension is scalar or not. + * \param nb_scattdims Size of the scaldims array. + * \param scalar Current scalar dimension. + * \return A pointer to the sorted list. + ** + * - July 2nd 2005: first developments. + * - September 2nd 2005: first version. + * - October 15nd 2007: complete rewrite to remove bugs, now a bubble sort. + */ +CloogLoop * cloog_loop_scalar_sort(loop, level, scaldims, nb_scattdims, scalar) +CloogLoop * loop ; +int level, * scaldims, nb_scattdims, scalar ; +{ int ok ; + CloogLoop **current; + + do { + ok = 1; + for (current = &loop; (*current)->next; current = &(*current)->next) { + CloogLoop *next = (*current)->next; + if (cloog_loop_scalar_gt(*current,next,level,scaldims,nb_scattdims,scalar)) { + ok = 0; + (*current)->next = next->next; + next->next = *current; + *current = next; + } + } + } while (!ok); + + return loop ; +} + + +/** + * cloog_loop_generate_backtrack function: + * adaptation from LoopGen 0.4 by F. Quillere. This function implements the + * backtrack of the Quillere et al. algorithm (see the Quillere paper). + * It eliminates unused iterations of the current level for the new one. See the + * example called linearity-1-1 example with and without this part for an idea. + * - October 26th 2001: first version in cloog_loop_generate_general. + * - July 31th 2002: (debug) no more parasite loops (REALLY hard !). + * - October 30th 2005: extraction from cloog_loop_generate_general. + */ +CloogLoop *cloog_loop_generate_backtrack(CloogLoop *loop, + int level, CloogOptions *options) +{ + CloogDomain * domain ; + CloogLoop * now, * now2, * next, * next2, * end, * temp, * l, * inner, + * new_loop ; + + temp = loop ; + loop = NULL ; + + while (temp != NULL) + { l = NULL ; + inner = temp->inner ; + + while (inner != NULL) + { next = inner->next ; + /* This 'if' and its first part is the debug of july 31th 2002. */ + if (inner->block != NULL) { + end = cloog_loop_alloc(temp->state, inner->domain, 0, NULL, + inner->block, NULL, NULL); + domain = cloog_domain_copy(temp->domain) ; + new_loop = cloog_loop_alloc(temp->state, domain, 0, NULL, + NULL, end, NULL); + } + else + new_loop = cloog_loop_project(inner, level); + + cloog_loop_free_parts(inner,0,0,0,0) ; + cloog_loop_add(&l,&now2,new_loop) ; + inner = next ; + } + + temp->inner = NULL ; + + if (l != NULL) + { l = cloog_loop_separate(l) ; + l = cloog_loop_sort(l, level); + while (l != NULL) { + l->stride = cloog_stride_copy(l->stride); + cloog_loop_add(&loop,&now,l) ; + l = l->next ; + } + } + next2 = temp->next ; + cloog_loop_free_parts(temp,1,0,0,0) ; + temp = next2 ; + } + + return loop ; +} + + +/** + * Return 1 if we need to continue recursing to the specified level. + */ +int cloog_loop_more(CloogLoop *loop, int level, int scalar, int nb_scattdims) +{ + return level + scalar <= nb_scattdims || + cloog_domain_dimension(loop->domain) >= level; +} + +/** + * Return 1 if the domains of all loops in the given linked list + * have a fixed value at the given level. + * In principle, there would be no need to check that the fixed value is + * the same for each of these loops because this function is only + * called on a component. However, not all backends perform a proper + * decomposition into components. + */ +int cloog_loop_is_constant(CloogLoop *loop, int level) +{ + cloog_int_t c1, c2; + int r = 1; + + cloog_int_init(c1); + cloog_int_init(c2); + + if (!cloog_domain_lazy_isconstant(loop->domain, level - 1, &c1)) + r = 0; + + for (loop = loop->next; r && loop; loop = loop->next) { + if (!cloog_domain_lazy_isconstant(loop->domain, level - 1, &c2)) + r = 0; + else if (cloog_int_ne(c1, c2)) + r = 0; + } + + cloog_int_clear(c1); + cloog_int_clear(c2); + + return r; +} + +/** + * Assuming all domains in the given linked list of loop + * have a fixed values at level, return a single loop with + * a domain corresponding to this fixed value and with as + * list of inner loops the concatenation of all inner loops + * in the original list. + */ +CloogLoop *cloog_loop_constant(CloogLoop *loop, int level) +{ + CloogLoop *res, *inner, *tmp; + CloogDomain *domain, *context, *t; + + if (!loop) + return loop; + + inner = loop->inner; + for (tmp = loop->next; tmp; tmp = tmp->next) + inner = cloog_loop_concat(inner, tmp->inner); + + domain = cloog_domain_copy(loop->domain); + domain = cloog_domain_simple_convex(t = domain); + cloog_domain_free(t); + context = cloog_domain_project(domain, level - 1); + context = cloog_domain_extend(t = context, level); + cloog_domain_free(t); + domain = cloog_domain_simplify(t = domain, context); + cloog_domain_free(t); + cloog_domain_free(context); + + res = cloog_loop_alloc(loop->state, domain, 0, NULL, NULL, inner, NULL); + + cloog_loop_free_parts(loop, 1, 0, 0, 1); + + return res; +} + +CloogLoop *cloog_loop_generate_restricted_or_stop(CloogLoop *loop, + CloogDomain *context, + int level, int scalar, int *scaldims, int nb_scattdims, + CloogOptions *options); + +/** + * cloog_loop_generate_general function: + * Adaptation from LoopGen 0.4 by F. Quillere. This function implements the + * Quillere algorithm for polyhedron scanning from step 3 to 5. + * (see the Quillere paper). + * - loop is the loop for which we have to generate a scanning code, + * - level is the current non-scalar dimension, + * - scalar is the current scalar dimension, + * - scaldims is the boolean array saying whether a dimension is scalar or not, + * - nb_scattdims is the size of the scaldims array, + * - options are the general code generation options. + ** + * - October 26th 2001: first version. + * - July 3rd->11th 2003: memory leaks hunt and correction. + * - June 22nd 2005: Adaptation for GMP. + * - September 2nd 2005: The function have been cutted out in two pieces: + * cloog_loop_generate and this one, in order to handle + * the scalar dimension case more efficiently with + * cloog_loop_generate_scalar. + * - November 15th 2005: (debug) the result of the cloog_loop_generate call may + * be a list of polyhedra (especially if stop option is + * used): cloog_loop_add_list instead of cloog_loop_add. + */ +CloogLoop *cloog_loop_generate_general(CloogLoop *loop, + int level, int scalar, int *scaldims, int nb_scattdims, + CloogOptions *options) +{ + CloogLoop * res, * now, * temp, * l, * new_loop, * inner, * now2, * end, + * next, * into ; + CloogDomain * domain ; + int separate = 0; + + /* 3. Separate all projections into disjoint polyhedra. */ + if (level > 0 && cloog_loop_is_constant(loop, level)) + res = cloog_loop_constant(loop, level); + else if ((options->f > level+scalar) || (options->f < 0)) + res = cloog_loop_merge(loop, level, options); + else { + res = cloog_loop_separate(loop); + separate = 1; + } + + /* 3b. -correction- sort the loops to determine their textual order. */ + res = cloog_loop_sort(res, level); + + res = cloog_loop_restrict_inner(res); + + if (separate) + res = cloog_loop_specialize(res, level, scalar, scaldims, nb_scattdims); + + /* 4. Recurse for each loop with the current domain as context. */ + temp = res ; + res = NULL ; + if (!level || (level+scalar < options->l) || (options->l < 0)) + while(temp != NULL) + { if (level && options->strides) + cloog_loop_stride(temp, level); + if (level && options->otl) + cloog_loop_otl(temp, level); + inner = temp->inner ; + domain = temp->domain ; + into = NULL ; + while (inner != NULL) + { /* 4b. -ced- recurse for each sub-list of non terminal loops. */ + if (cloog_loop_more(inner, level + 1, scalar, nb_scattdims)) { + end = inner; + while ((end->next != NULL) && + cloog_loop_more(end->next, level + 1, scalar, nb_scattdims)) + end = end->next ; + + next = end->next ; + end->next = NULL ; + + l = cloog_loop_generate_restricted_or_stop(inner, domain, + level + 1, scalar, scaldims, nb_scattdims, options); + + if (l != NULL) + cloog_loop_add_list(&into,&now,l) ; + + inner = next ; + } + else + { cloog_loop_add(&into,&now,inner) ; + inner = inner->next ; + } + } + next = temp->next ; + temp->next = NULL ; + temp->inner = into ; + cloog_loop_add(&res,&now2,temp) ; + temp = next ; + } + else + while (temp != NULL) + { next = temp->next ; + l = cloog_loop_nest(temp->inner, temp->domain, level+1); + new_loop = cloog_loop_alloc(temp->state, temp->domain, 0, NULL, + NULL, l, NULL); + temp->inner = NULL ; + temp->next = NULL ; + cloog_loop_free_parts(temp,0,0,0,0) ; + cloog_loop_add(&res,&now,new_loop) ; + temp = next ; + } + + /* 5. eliminate unused iterations of the current level for the new one. See + * the example called linearity-1-1 example with and without this part + * for an idea. + */ + if (options->backtrack && level && + ((level+scalar < options->l) || (options->l < 0)) && + ((options->f <= level+scalar) && !(options->f < 0))) + res = cloog_loop_generate_backtrack(res, level, options); + + /* Pray for my new paper to be accepted somewhere since the following stuff + * is really amazing :-) ! + * Far long later: The paper has been accepted to PACT 2004 :-))). But there + * are still some bugs and I have no time to fix them. Thus now you have to + * pray for me to get an academic position for that really amazing stuff :-) ! + * Later again: OK, I get my academic position, but still I have not enough + * time to fix and clean this part... Pray again :-) !!! + */ + /* res = cloog_loop_unisolate(res,level) ;*/ + + return(res) ; +} + + +CloogLoop *cloog_loop_generate_restricted(CloogLoop *loop, + int level, int scalar, int *scaldims, int nb_scattdims, + CloogOptions *options); + + +/** + * cloog_loop_generate_scalar function: + * This function applies the simplified code generation scheme in the trivial + * case of scalar dimensions. When dealing with scalar dimensions, there is + * no need of costly polyhedral operations for separation or sorting: sorting + * is a question of comparing scalar vectors and separation amounts to consider + * only loops with the same scalar vector for the next step of the code + * generation process. This function achieves the separation/sorting process + * for the vector of scalar dimension that begins at dimension 'level+scalar' + * and finish to the first non-scalar dimension. + * - loop is the loop for which we have to generate a scanning code, + * - level is the current non-scalar dimension, + * - scalar is the current scalar dimension, + * - scaldims is the boolean array saying whether a dimension is scalar or not, + * - nb_scattdims is the size of the scaldims array, + * - options are the general code generation options. + ** + * - September 2nd 2005: First version. + */ +CloogLoop *cloog_loop_generate_scalar(CloogLoop *loop, + int level, int scalar, int *scaldims, int nb_scattdims, + CloogOptions *options) +{ CloogLoop * res, * now, * temp, * l, * end, * next, * ref ; + int scalar_new; + + /* We sort the loop list with respect to the current scalar vector. */ + res = cloog_loop_scalar_sort(loop,level,scaldims,nb_scattdims,scalar) ; + + scalar_new = scalar + scaldims[level + scalar - 1]; + + temp = res ; + res = NULL ; + while (temp != NULL) + { /* Then we will appy the general code generation process to each sub-list + * of loops with the same scalar vector. + */ + end = temp ; + ref = temp ; + + while((end->next != NULL) && + cloog_loop_more(end->next, level, scalar_new, nb_scattdims) && + cloog_loop_scalar_eq(ref,end->next,level,scaldims,nb_scattdims,scalar)) + end = end->next ; + + next = end->next ; + end->next = NULL ; + + /* For the next dimension, scalar value is updated by adding the scalar + * vector size, which is stored at scaldims[level+scalar-1]. + */ + if (cloog_loop_more(temp, level, scalar_new, nb_scattdims)) { + l = cloog_loop_generate_restricted(temp, level, scalar_new, + scaldims, nb_scattdims, options); + + if (l != NULL) + cloog_loop_add_list(&res, &now, l); + } else + cloog_loop_add(&res, &now, temp); + + temp = next ; + } + + return res ; +} + + +/* Compare loop with the next loop based on their constant dimensions. + * The result is < 0, == 0 or > 0 depending on whether the constant + * dimensions of loop are lexicographically smaller, equal or greater + * than those of loop->next. + * If loop is the last in the list, then it is assumed to be smaller + * than the "next" one. + */ +static int cloog_loop_next_scal_cmp(CloogLoop *loop) +{ + int i; + int nb_scaldims; + + if (!loop->next) + return -1; + + nb_scaldims = loop->block->nb_scaldims; + if (loop->next->block->nb_scaldims < nb_scaldims) + nb_scaldims = loop->next->block->nb_scaldims; + + for (i = 0; i < nb_scaldims; ++i) { + int cmp = cloog_int_cmp(loop->block->scaldims[i], + loop->next->block->scaldims[i]); + if (cmp) + return cmp; + } + return loop->block->nb_scaldims - loop->next->block->nb_scaldims; +} + + +/* Check whether the globally constant dimensions of a and b + * have the same value for all globally constant dimensions + * that are situated before any (locally) non-constant dimension. + */ +static int cloog_loop_equal_prefix(CloogLoop *a, CloogLoop *b, + int *scaldims, int nb_scattdims) +{ + int i; + int cst = 0; + int dim = 0; + + for (i = 0; i < nb_scattdims; ++i) { + if (!scaldims[i]) { + dim++; + continue; + } + if (!cloog_int_eq(a->block->scaldims[cst], b->block->scaldims[cst])) + break; + cst++; + } + for (i = i + 1; i < nb_scattdims; ++i) { + if (scaldims[i]) + continue; + if (!cloog_domain_lazy_isconstant(a->domain, dim, NULL)) + return 0; + /* No need to check that dim is also constant in b and that the + * constant values are equal. That will happen during the check + * whether the two domains are equal. + */ + dim++; + } + return 1; +} + + +/* Try to block adjacent loops in the loop list "loop". + * We only attempt blocking if the constant dimensions of the loops + * in the least are (not necessarily strictly) increasing. + * Then we look for a sublist such that the first (begin) has constant + * dimensions strictly larger than the previous loop in the complete + * list and such that the loop (end) after the last loop in the sublist + * has constant dimensions strictly larger than the last loop in the sublist. + * Furthermore, all loops in the sublist should have the same domain + * (with globally constant dimensions removed) and the difference + * (if any) in constant dimensions may only occur after all the + * (locally) constant dimensions. + * If we find such a sublist, then the blocks of all but the first + * are merged into the block of the first. + * + * Note that this function can only be called before the global + * blocklist has been created because it may otherwise modify and destroy + * elements on that list. + */ +CloogLoop *cloog_loop_block(CloogLoop *loop, int *scaldims, int nb_scattdims) +{ + CloogLoop *begin, *end, *l; + int begin_after_previous; + int end_after_previous; + + if (!loop->next) + return loop; + for (begin = loop; begin; begin = begin->next) { + if (!begin->block || !begin->block->scaldims) + return loop; + if (cloog_loop_next_scal_cmp(begin) > 0) + return loop; + } + + begin_after_previous = 1; + for (begin = loop; begin; begin = begin->next) { + if (!begin_after_previous) { + begin_after_previous = cloog_loop_next_scal_cmp(begin) < 0; + continue; + } + + end_after_previous = cloog_loop_next_scal_cmp(begin) < 0; + for (end = begin->next; end; end = end->next) { + if (!cloog_loop_equal_prefix(begin, end, scaldims, nb_scattdims)) + break; + if (!cloog_domain_lazy_equal(begin->domain, end->domain)) + break; + end_after_previous = cloog_loop_next_scal_cmp(end) < 0; + } + if (end != begin->next && end_after_previous) { + for (l = begin->next; l != end; l = begin->next) { + cloog_block_merge(begin->block, l->block); + begin->next = l->next; + cloog_loop_free_parts(l, 1, 0, 1, 0); + } + } + + begin_after_previous = cloog_loop_next_scal_cmp(begin) < 0; + } + + return loop; +} + + +/** + * Check whether for any fixed iteration of the outer loops, + * there is an iteration of loop1 that is lexicographically greater + * than an iteration of loop2. + * Return 1 if there exists (or may exist) such a pair. + * Return 0 if all iterations of loop1 are lexicographically smaller + * than the iterations of loop2. + * If no iteration is lexicographically greater, but if there are + * iterations that are equal to iterations of loop2, then return "def". + * This is useful for ensuring that such statements are not reordered. + * Some users, including the test_run target in test, expect + * the statements at a given point to be run in the original order. + * Passing the value "0" for "def" would allow such statements to be reordered + * and would allow for the detection of more components. + */ +int cloog_loop_follows(CloogLoop *loop1, CloogLoop *loop2, + int level, int scalar, int *scaldims, int nb_scattdims, int def) +{ + int dim1, dim2; + + dim1 = cloog_domain_dimension(loop1->domain); + dim2 = cloog_domain_dimension(loop2->domain); + while ((level <= dim1 && level <= dim2) || + level_is_constant(level, scalar, scaldims, nb_scattdims)) { + if (level_is_constant(level, scalar, scaldims, nb_scattdims)) { + int cmp = cloog_loop_constant_cmp(loop1, loop2, level, scaldims, + nb_scattdims, scalar); + if (cmp > 0) + return 1; + if (cmp < 0) + return 0; + scalar += scaldims[level + scalar - 1]; + } else { + int follows = cloog_domain_follows(loop1->domain, loop2->domain, + level); + if (follows > 0) + return 1; + if (follows < 0) + return 0; + level++; + } + } + + return def; +} + + +/* Structure for representing the nodes in the graph being traversed + * using Tarjan's algorithm. + * index represents the order in which nodes are visited. + * min_index is the index of the root of a (sub)component. + * on_stack indicates whether the node is currently on the stack. + */ +struct cloog_loop_sort_node { + int index; + int min_index; + int on_stack; +}; +/* Structure for representing the graph being traversed + * using Tarjan's algorithm. + * len is the number of nodes + * node is an array of nodes + * stack contains the nodes on the path from the root to the current node + * sp is the stack pointer + * index is the index of the last node visited + * order contains the elements of the components separated by -1 + * op represents the current position in order + */ +struct cloog_loop_sort { + int len; + struct cloog_loop_sort_node *node; + int *stack; + int sp; + int index; + int *order; + int op; +}; + +/* Allocate and initialize cloog_loop_sort structure. + */ +static struct cloog_loop_sort *cloog_loop_sort_alloc(int len) +{ + struct cloog_loop_sort *s; + int i; + + s = (struct cloog_loop_sort *)malloc(sizeof(struct cloog_loop_sort)); + assert(s); + s->len = len; + s->node = (struct cloog_loop_sort_node *) + malloc(len * sizeof(struct cloog_loop_sort_node)); + assert(s->node); + for (i = 0; i < len; ++i) + s->node[i].index = -1; + s->stack = (int *)malloc(len * sizeof(int)); + assert(s->stack); + s->order = (int *)malloc(2 * len * sizeof(int)); + assert(s->order); + + s->sp = 0; + s->index = 0; + s->op = 0; + + return s; +} + +/* Free cloog_loop_sort structure. + */ +static void cloog_loop_sort_free(struct cloog_loop_sort *s) +{ + free(s->node); + free(s->stack); + free(s->order); + free(s); +} + + +/* Check whether for any fixed iteration of the outer loops, + * there is an iteration of loop1 that is lexicographically greater + * than an iteration of loop2, where the iteration domains are + * available in the inner loops of the arguments. + * + * By using this functions to detect components, we ensure that + * two CloogLoops appear in the same component if some iterations of + * each loop should be executed before some iterations of the other loop. + * Since we also want two CloogLoops that have exactly the same + * iteration domain at the current level to be placed in the same component, + * we first check if these domains are indeed the same. + */ +static int inner_loop_follows(CloogLoop *loop1, CloogLoop *loop2, + int level, int scalar, int *scaldims, int nb_scattdims, int def) +{ + int f; + + f = cloog_domain_lazy_equal(loop1->domain, loop2->domain); + if (!f) + f = cloog_loop_follows(loop1->inner, loop2->inner, + level, scalar, scaldims, nb_scattdims, def); + + return f; +} + + +/* Perform Tarjan's algorithm for computing the strongly connected components + * in the graph with the individual CloogLoops as vertices. + * Two CloopLoops appear in the same component if they both (indirectly) + * "follow" each other, where the following relation is determined + * by the follows function. + */ +static void cloog_loop_components_tarjan(struct cloog_loop_sort *s, + CloogLoop **loop_array, int i, int level, int scalar, int *scaldims, + int nb_scattdims, + int (*follows)(CloogLoop *loop1, CloogLoop *loop2, + int level, int scalar, int *scaldims, int nb_scattdims, int def)) +{ + int j; + + s->node[i].index = s->index; + s->node[i].min_index = s->index; + s->node[i].on_stack = 1; + s->index++; + s->stack[s->sp++] = i; + + for (j = s->len - 1; j >= 0; --j) { + int f; + + if (j == i) + continue; + if (s->node[j].index >= 0 && + (!s->node[j].on_stack || + s->node[j].index > s->node[i].min_index)) + continue; + + f = follows(loop_array[i], loop_array[j], + level, scalar, scaldims, nb_scattdims, i > j); + if (!f) + continue; + + if (s->node[j].index < 0) { + cloog_loop_components_tarjan(s, loop_array, j, level, scalar, + scaldims, nb_scattdims, follows); + if (s->node[j].min_index < s->node[i].min_index) + s->node[i].min_index = s->node[j].min_index; + } else if (s->node[j].index < s->node[i].min_index) + s->node[i].min_index = s->node[j].index; + } + + if (s->node[i].index != s->node[i].min_index) + return; + + do { + j = s->stack[--s->sp]; + s->node[j].on_stack = 0; + s->order[s->op++] = j; + } while (j != i); + s->order[s->op++] = -1; +} + + +static int qsort_index_cmp(const void *p1, const void *p2) +{ + return *(int *)p1 - *(int *)p2; +} + +/* Sort the elements of the component starting at list. + * The list is terminated by a -1. + */ +static void sort_component(int *list) +{ + int len; + + for (len = 0; list[len] != -1; ++len) + ; + + qsort(list, len, sizeof(int), qsort_index_cmp); +} + +/* Given an array of indices "list" into the "loop_array" array, + * terminated by -1, construct a linked list of the corresponding + * entries and put the result in *res. + * The value returned is the number of CloogLoops in the (linked) list + */ +static int extract_component(CloogLoop **loop_array, int *list, CloogLoop **res) +{ + int i = 0; + + sort_component(list); + while (list[i] != -1) { + *res = loop_array[list[i]]; + res = &(*res)->next; + ++i; + } + *res = NULL; + + return i; +} + + +/** + * Call cloog_loop_generate_scalar or cloog_loop_generate_general + * on each of the strongly connected components in the list of CloogLoops + * pointed to by "loop". + * + * We use Tarjan's algorithm to find the strongly connected components. + * Note that this algorithm also topologically sorts the components. + * + * The components are treated separately to avoid spurious separations. + * The concatentation of the results may contain successive loops + * with the same bounds, so we try to combine such loops. + */ +CloogLoop *cloog_loop_generate_components(CloogLoop *loop, + int level, int scalar, int *scaldims, int nb_scattdims, + CloogOptions *options) +{ + int i, nb_loops; + CloogLoop *tmp; + CloogLoop *res, **res_next; + CloogLoop **loop_array; + struct cloog_loop_sort *s; + + if (level == 0 || !loop->next) + return cloog_loop_generate_general(loop, level, scalar, + scaldims, nb_scattdims, options); + + nb_loops = cloog_loop_count(loop); + + loop_array = (CloogLoop **)malloc(nb_loops * sizeof(CloogLoop *)); + assert(loop_array); + + for (i = 0, tmp = loop; i < nb_loops; i++, tmp = tmp->next) + loop_array[i] = tmp; + + s = cloog_loop_sort_alloc(nb_loops); + for (i = nb_loops - 1; i >= 0; --i) { + if (s->node[i].index >= 0) + continue; + cloog_loop_components_tarjan(s, loop_array, i, level, scalar, scaldims, + nb_scattdims, &inner_loop_follows); + } + + i = 0; + res = NULL; + res_next = &res; + while (nb_loops) { + int n = extract_component(loop_array, &s->order[i], &tmp); + i += n + 1; + nb_loops -= n; + *res_next = cloog_loop_generate_general(tmp, level, scalar, + scaldims, nb_scattdims, options); + while (*res_next) + res_next = &(*res_next)->next; + } + + cloog_loop_sort_free(s); + + free(loop_array); + + res = cloog_loop_combine(res); + + return res; +} + + +/* For each loop in the list "loop", decompose the list of + * inner loops into strongly connected components and put + * the components into separate loops at the top level. + */ +CloogLoop *cloog_loop_decompose_inner(CloogLoop *loop, + int level, int scalar, int *scaldims, int nb_scattdims) +{ + CloogLoop *l, *tmp; + CloogLoop **loop_array; + int i, n_loops, max_loops = 0; + struct cloog_loop_sort *s; + + for (l = loop; l; l = l->next) { + n_loops = cloog_loop_count(l->inner); + if (max_loops < n_loops) + max_loops = n_loops; + } + + if (max_loops <= 1) + return loop; + + loop_array = (CloogLoop **)malloc(max_loops * sizeof(CloogLoop *)); + assert(loop_array); + + for (l = loop; l; l = l->next) { + int n; + + for (i = 0, tmp = l->inner; tmp; i++, tmp = tmp->next) + loop_array[i] = tmp; + n_loops = i; + if (n_loops <= 1) + continue; + + s = cloog_loop_sort_alloc(n_loops); + for (i = n_loops - 1; i >= 0; --i) { + if (s->node[i].index >= 0) + continue; + cloog_loop_components_tarjan(s, loop_array, i, level, scalar, + scaldims, nb_scattdims, &cloog_loop_follows); + } + + n = extract_component(loop_array, s->order, &l->inner); + n_loops -= n; + i = n + 1; + while (n_loops) { + CloogLoop *inner; + + n = extract_component(loop_array, &s->order[i], &inner); + n_loops -= n; + i += n + 1; + tmp = cloog_loop_alloc(l->state, cloog_domain_copy(l->domain), + l->otl, l->stride, l->block, inner, l->next); + l->next = tmp; + l = tmp; + } + + cloog_loop_sort_free(s); + } + + free(loop_array); + + return loop; +} + + +CloogLoop *cloog_loop_generate_restricted(CloogLoop *loop, + int level, int scalar, int *scaldims, int nb_scattdims, + CloogOptions *options) +{ + /* To save both time and memory, we switch here depending on whether the + * current dimension is scalar (simplified processing) or not (general + * processing). + */ + if (level_is_constant(level, scalar, scaldims, nb_scattdims)) + return cloog_loop_generate_scalar(loop, level, scalar, + scaldims, nb_scattdims, options); + /* + * 2. Compute the projection of each polyhedron onto the outermost + * loop variable and the parameters. + */ + loop = cloog_loop_project_all(loop, level); + + return cloog_loop_generate_components(loop, level, scalar, scaldims, + nb_scattdims, options); +} + + +CloogLoop *cloog_loop_generate_restricted_or_stop(CloogLoop *loop, + CloogDomain *context, + int level, int scalar, int *scaldims, int nb_scattdims, + CloogOptions *options) +{ + /* If the user asked to stop code generation at this level, let's stop. */ + if ((options->stop >= 0) && (level+scalar >= options->stop+1)) + return cloog_loop_stop(loop,context) ; + + return cloog_loop_generate_restricted(loop, level, scalar, scaldims, + nb_scattdims, options); +} + + +/** + * cloog_loop_generate function: + * Adaptation from LoopGen 0.4 by F. Quillere. This function implements the + * Quillere algorithm for polyhedron scanning from step 1 to 2. + * (see the Quillere paper). + * - loop is the loop for which we have to generate a scanning code, + * - context is the context of the current loop (constraints on parameter and/or + * on outer loop counters), + * - level is the current non-scalar dimension, + * - scalar is the current scalar dimension, + * - scaldims is the boolean array saying whether a dimension is scalar or not, + * - nb_scattdims is the size of the scaldims array, + * - options are the general code generation options. + ** + * - October 26th 2001: first version. + * - July 3rd->11th 2003: memory leaks hunt and correction. + * - June 15th 2005: a memory leak fixed (loop was not entirely freed when + * the result of cloog_loop_restrict was NULL). + * - June 22nd 2005: Adaptation for GMP. + * - September 2nd 2005: The function have been cutted out in two pieces: + * cloog_loop_generate and this one, in order to handle + * the scalar dimension case more efficiently with + * cloog_loop_generate_scalar. + * - November 15th 2005: (debug) Condition for stop option no more take care of + * further scalar dimensions. + */ +CloogLoop *cloog_loop_generate(CloogLoop *loop, CloogDomain *context, + int level, int scalar, int *scaldims, int nb_scattdims, + CloogOptions *options) +{ + /* 1. Replace each polyhedron by its intersection with the context. + */ + loop = cloog_loop_restrict_all(loop, context); + if (!loop) + return NULL; + + return cloog_loop_generate_restricted_or_stop(loop, context, + level, scalar, scaldims, nb_scattdims, options); +} + + +/* + * Internal function for simplifying a single loop in a list of loops. + * See cloog_loop_simplify. + */ +static CloogLoop *loop_simplify(CloogLoop *loop, CloogDomain *context, + int level, int nb_scattdims, CloogOptions *options) +{ + int domain_dim; + CloogBlock * new_block ; + CloogLoop *simplified, *inner; + CloogDomain * domain, * simp, * inter, * extended_context ; + + if (!cloog_domain_isconvex(loop->domain)) + loop->domain = cloog_domain_simplify_union(loop->domain); + + domain = loop->domain ; + + domain_dim = cloog_domain_dimension(domain); + extended_context = cloog_domain_extend(context, domain_dim); + inter = cloog_domain_intersection(domain,extended_context) ; + simp = cloog_domain_simplify(domain, extended_context); + cloog_domain_free(extended_context) ; + + /* If the constraint system is never true, go to the next one. */ + if (cloog_domain_never_integral(simp)) { + cloog_loop_free(loop->inner); + cloog_domain_free(inter); + cloog_domain_free(simp); + return NULL; + } + + inner = cloog_loop_simplify(loop->inner, inter, level+1, nb_scattdims, + options); + + if ((inner == NULL) && (loop->block == NULL)) { + cloog_domain_free(inter); + cloog_domain_free(simp); + return NULL; + } + + new_block = cloog_block_copy(loop->block) ; + + simplified = cloog_loop_alloc(loop->state, simp, loop->otl, loop->stride, + new_block, inner, NULL); + + /* Only save the domains, if their level is still a scattering level. */ + if (options->save_domains && level <= nb_scattdims) + simplified->unsimplified = inter; + else + cloog_domain_free(inter); + + return(simplified) ; +} + + +/** + * cloog_loop_simplify function: + * This function implements the part 6. of the Quillere algorithm, it + * recursively simplifies each loop in the context of the preceding loop domain. + * It returns a pointer to the simplified loop list. + * The cloog_domain_simplify (DomainSimplify) behaviour is really bad with + * polyhedra union and some really awful sidesteppings were written, I plan + * to solve that... + * - October 31th 2001: first version. + * - July 3rd->11th 2003: memory leaks hunt and correction. + * - April 16th 2005: a memory leak fixed (extended_context was not freed). + * - June 15th 2005: a memory leak fixed (loop was not conveniently freed + * when the constraint system is never true). + * - October 27th 2005: - this function called before cloog_loop_fast_simplify + * is now the official cloog_loop_simplify function in + * replacement of a slower and more complex one (after + * deep changes in the pretty printer). + * - we use cloog_loop_disjoint to fix the problem when + * simplifying gives a union of polyhedra (before, it + * was under the responsibility of the pretty printer). + */ +CloogLoop *cloog_loop_simplify(CloogLoop *loop, CloogDomain *context, int level, + int nb_scattdims, CloogOptions *options) +{ + CloogLoop *now; + CloogLoop *res = NULL; + CloogLoop **next = &res; + + for (now = loop; now; now = now->next) { + *next = loop_simplify(now, context, level, nb_scattdims, options); + + now->inner = NULL; /* For loop integrity. */ + cloog_domain_free(now->domain); + now->domain = NULL; + + if (*next) + next = &(*next)->next; + } + cloog_loop_free(loop); + + /* Examples like test/iftest2.cloog give unions of polyhedra after + * simplifying, thus we have to make them disjoint. Another good reason to + * put the simplifying step in the Quillere backtrack. + */ + res = cloog_loop_disjoint(res); + + return res; +} + + +/** + * cloog_loop_scatter function: + * This function add the scattering (scheduling) informations in a loop. + */ +void cloog_loop_scatter(CloogLoop * loop, CloogScattering *scatt) +{ + loop->domain = cloog_domain_scatter(loop->domain, scatt); +} + diff --git a/cloog-core/source/matrix.c b/cloog-core/source/matrix.c new file mode 100644 index 0000000..43c2380 --- /dev/null +++ b/cloog-core/source/matrix.c @@ -0,0 +1,213 @@ + /**-------------------------------------------------------------------** + ** CLooG ** + **-------------------------------------------------------------------** + ** cloogmatrix.c ** + **-------------------------------------------------------------------**/ + + +/****************************************************************************** + * 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 * + * * + ******************************************************************************/ + +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include "../include/cloog/cloog.h" + +/** + * cloog_matrix_alloc: + * Allocate a CloogMatrix data structure with NbRows rows and NbColumns columns. + * All values are initialized to 0. + * This method returns a pointer to the data structure if successful or a NULL + * pointer otherwise. + */ +CloogMatrix *cloog_matrix_alloc(unsigned NbRows, unsigned NbColumns) +{ + CloogMatrix *matrix; + cloog_int_t **p, *q; + int i, j; + + matrix = (CloogMatrix *)malloc(sizeof(CloogMatrix)); + + if (!matrix) + return NULL; + + matrix->NbRows = NbRows; + matrix->NbColumns = NbColumns; + + if (!NbRows || !NbColumns) { + matrix->p = NULL; + matrix->p_Init = NULL; + return matrix; + } + + p = (cloog_int_t **)malloc(NbRows * sizeof(cloog_int_t *)); + + if (p == NULL) { + free (matrix); + return NULL; + } + + q = (cloog_int_t *)malloc(NbRows * NbColumns * sizeof(cloog_int_t)); + + if (q == NULL) { + free (matrix); + free (p); + return NULL; + } + + matrix->p = p; + matrix->p_Init = q; + + for (i = 0; i < NbRows; i++) { + *p++ = q; + for (j = 0; j < NbColumns; j++) { + cloog_int_init(*(q+j)); + cloog_int_set_si(*(q+j), 0); + } + q += NbColumns; + } + + return matrix; +} + +/** + * cloog_matrix_free: + * Free matrix. + */ +void cloog_matrix_free(CloogMatrix * matrix) +{ + int i; + cloog_int_t *p; + int size = matrix->NbRows * matrix->NbColumns; + + p = matrix->p_Init; + + for (i = 0; i < size; i++) + cloog_int_clear(*p++); + + if (matrix) { + free(matrix->p_Init); + free(matrix->p); + free(matrix); + } +} + + +/** + * Print the elements of CloogMatrix M to file, with each row prefixed + * by prefix and suffixed by suffix. + */ +void cloog_matrix_print_structure(FILE *file, CloogMatrix *M, + const char *prefix, const char *suffix) +{ + int i, j; + + for (i = 0; i < M->NbRows; ++i) { + fprintf(file, "%s", prefix); + for (j = 0; j < M->NbColumns; ++j) { + cloog_int_print(file, M->p[i][j]); + fprintf(file, " "); + } + fprintf(file, "%s\n", suffix); + } +} + +/** + * cloog_matrix_print function: + * This function prints the content of a CloogMatrix structure (matrix) into a + * file (foo, possibly stdout). + */ +void cloog_matrix_print(FILE* foo, CloogMatrix* m) +{ + if (!m) + fprintf(foo, "(null)\n"); + + fprintf(foo, "%d %d\n", m->NbRows, m->NbColumns); + cloog_matrix_print_structure(foo, m, "", ""); + fflush(foo); +} + + +static char *next_line(FILE *input, char *line, unsigned len) +{ + char *p; + + do { + if (!(p = fgets(line, len, input))) + return NULL; + while (isspace(*p) && *p != '\n') + ++p; + } while (*p == '#' || *p == '\n'); + + return p; +} + +CloogMatrix *cloog_matrix_read(FILE *input) +{ + unsigned n_row, n_col; + char line[1024]; + + if (!next_line(input, line, sizeof(line))) + cloog_die("Input error.\n"); + if (sscanf(line, "%u %u", &n_row, &n_col) != 2) + cloog_die("Input error.\n"); + + return cloog_matrix_read_of_size(input, n_row, n_col); +} + +/** + * Read a matrix in PolyLib format from input. + */ +CloogMatrix *cloog_matrix_read_of_size(FILE *input, + unsigned n_row, unsigned n_col) +{ + CloogMatrix *M; + int i, j; + char line[1024]; + char val[1024]; + char *p; + + M = cloog_matrix_alloc(n_row, n_col); + if (!M) + cloog_die("memory overflow.\n"); + for (i = 0; i < n_row; ++i) { + int offset; + int n; + + p = next_line(input, line, sizeof(line)); + if (!p) + cloog_die("Input error.\n"); + for (j = 0; j < n_col; ++j) { + n = sscanf(p, "%s%n", val, &offset); + if (!n) + cloog_die("Input error.\n"); + cloog_int_read(M->p[i][j], val); + p += offset; + } + } + + return M; +} diff --git a/cloog-core/source/matrix/constraintset.c b/cloog-core/source/matrix/constraintset.c new file mode 100644 index 0000000..94ac41c --- /dev/null +++ b/cloog-core/source/matrix/constraintset.c @@ -0,0 +1,1049 @@ + + /**-------------------------------------------------------------------** + ** CLooG ** + **-------------------------------------------------------------------** + ** constraintset.c ** + **-------------------------------------------------------------------** + ** First version: april 17th 2005 ** + **-------------------------------------------------------------------**/ + + +/****************************************************************************** + * CLooG : the Chunky Loop Generator (experimental) * + ****************************************************************************** + * * + * Copyright (C) 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 <stdlib.h> +# include <stdio.h> +# include <ctype.h> +#include <cloog/cloog.h> +#include <cloog/matrix/constraintset.h> + + +#define ALLOC(type) (type*)malloc(sizeof(type)) +#define ALLOCN(type,n) (type*)malloc((n)*sizeof(type)) + + +CloogConstraint *cloog_constraint_first(CloogConstraintSet *constraints); +CloogConstraint *cloog_constraint_next(CloogConstraint *constraint); + + +CloogConstraintSet *cloog_constraint_set_from_cloog_matrix(CloogMatrix *M) +{ + return (CloogConstraintSet *)M; +} + + +void cloog_constraint_set_free(CloogConstraintSet *constraints) +{ + cloog_matrix_free(&constraints->M); +} + +int cloog_constraint_set_contains_level(CloogConstraintSet *constraints, + int level, int nb_parameters) +{ + return constraints->M.NbColumns - 2 - nb_parameters >= level; +} + +/* Check if the variable at position level is defined by an + * equality. If so, return the row number. Otherwise, return -1. + * + * If there is an equality, we can print it directly -no ambiguity-. + * PolyLib can give more than one equality, we use just the first one + * (this is a PolyLib problem, but all equalities are equivalent). + */ +CloogConstraint *cloog_constraint_set_defining_equality(CloogConstraintSet *constraints, int level) +{ + CloogConstraint *constraint = ALLOC(CloogConstraint); + int i; + + constraint->set = constraints; + for (i = 0; i < constraints->M.NbRows; i++) + if (cloog_int_is_zero(constraints->M.p[i][0]) && + !cloog_int_is_zero(constraints->M.p[i][level])) { + constraint->line = &constraints->M.p[i]; + return constraint; + } + free(constraint); + return cloog_constraint_invalid(); +} + +/* Check if the variable (e) at position level is defined by a + * pair of inequalities + * <a, i> + -m e + <b, p> + k1 >= 0 + * <-a, i> + m e + <-b, p> + k2 >= 0 + * with 0 <= k1 + k2 < m + * If so return the row number of the upper bound and set *lower + * to the row number of the lower bound. If not, return -1. + * + * If the variable at position level occurs in any other constraint, + * then we currently return -1. The modulo guard that we would generate + * would still be correct, but we would also need to generate + * guards corresponding to the other constraints, and this has not + * been implemented yet. + */ +CloogConstraint *cloog_constraint_set_defining_inequalities(CloogConstraintSet *constraints, + int level, CloogConstraint **lower, int nb_par) +{ + int i, j, k; + cloog_int_t m; + CloogMatrix *matrix = &constraints->M; + unsigned len = matrix->NbColumns - 2; + unsigned nb_iter = len - nb_par; + CloogConstraint *constraint; + + for (i = 0; i < matrix->NbRows; i++) { + if (cloog_int_is_zero(matrix->p[i][level])) + continue; + if (cloog_int_is_zero(matrix->p[i][0])) + return cloog_constraint_invalid(); + if (cloog_int_is_one(matrix->p[i][level])) + return cloog_constraint_invalid(); + if (cloog_int_is_neg_one(matrix->p[i][level])) + return cloog_constraint_invalid(); + if (cloog_seq_first_non_zero(matrix->p[i]+level+1, + (1+nb_iter)-(level+1)) != -1) + return cloog_constraint_invalid(); + for (j = i+1; j < matrix->NbRows; ++j) { + if (cloog_int_is_zero(matrix->p[j][level])) + continue; + if (cloog_int_is_zero(matrix->p[j][0])) + return cloog_constraint_invalid(); + if (cloog_int_is_one(matrix->p[j][level])) + return cloog_constraint_invalid(); + if (cloog_int_is_neg_one(matrix->p[j][level])) + return cloog_constraint_invalid(); + if (cloog_seq_first_non_zero(matrix->p[j]+level+1, + (1+nb_iter)-(level+1)) != -1) + return cloog_constraint_invalid(); + + cloog_int_init(m); + cloog_int_add(m, matrix->p[i][1+len], matrix->p[j][1+len]); + if (cloog_int_is_neg(m) || + cloog_int_abs_ge(m, matrix->p[i][level])) { + cloog_int_clear(m); + return cloog_constraint_invalid(); + } + cloog_int_clear(m); + + if (!cloog_seq_is_neg(matrix->p[i]+1, matrix->p[j]+1, + len)) + return cloog_constraint_invalid(); + for (k = j+1; k < matrix->NbRows; ++k) + if (!cloog_int_is_zero(matrix->p[k][level])) + return cloog_constraint_invalid(); + *lower = ALLOC(CloogConstraint); + constraint = ALLOC(CloogConstraint); + (*lower)->set = constraints; + constraint->set = constraints; + if (cloog_int_is_pos(matrix->p[i][level])) { + (*lower)->line = &matrix->p[i]; + constraint->line = &matrix->p[j]; + } else { + (*lower)->line = &matrix->p[j]; + constraint->line = &matrix->p[i]; + } + return constraint; + } + } + return cloog_constraint_invalid(); +} + +int cloog_constraint_set_total_dimension(CloogConstraintSet *constraints) +{ + return constraints->M.NbColumns - 2; +} + +int cloog_constraint_set_n_iterators(CloogConstraintSet *constraint, int nb_par) +{ + return cloog_constraint_set_total_dimension(constraint) - nb_par; +} + +int cloog_equal_total_dimension(CloogEqualities *equal) +{ + return cloog_constraint_set_total_dimension(equal->constraints); +} + +int cloog_constraint_total_dimension(CloogConstraint *constraint) +{ + return cloog_constraint_set_total_dimension(constraint->set); +} + + + +/****************************************************************************** + * Equalities spreading functions * + ******************************************************************************/ + + +/* Equalities are stored inside a CloogMatrix data structure called "equal". + * This matrix has (nb_scattering + nb_iterators + 1) rows (i.e. total + * dimensions + 1, the "+ 1" is because a statement can be included inside an + * external loop without iteration domain), and (nb_scattering + nb_iterators + + * nb_parameters + 2) columns (all unknowns plus the scalar plus the equality + * type). The ith row corresponds to the equality "= 0" for the ith dimension + * iterator. The first column gives the equality type (0: no equality, then + * EQTYPE_* -see pprint.h-). At each recursion of pprint, if an equality for + * the current level is found, the corresponding row is updated. Then the + * equality if it exists is used to simplify expressions (e.g. if we have + * "i+1" while we know that "i=2", we simplify it in "3"). At the end of + * the pprint call, the corresponding row is reset to zero. + */ + +CloogEqualities *cloog_equal_alloc(int n, int nb_levels, + int nb_parameters) +{ + int i; + CloogEqualities *equal = ALLOC(CloogEqualities); + + equal->constraints = cloog_constraint_set_from_cloog_matrix( + cloog_matrix_alloc(n, nb_levels + nb_parameters + 1)); + equal->types = ALLOCN(int, n); + for (i = 0; i < n; ++i) + equal->types[i] = EQTYPE_NONE; + return equal; +} + +void cloog_equal_free(CloogEqualities *equal) +{ + cloog_matrix_free(&equal->constraints->M); + free(equal->types); + free(equal); +} + +int cloog_equal_count(CloogEqualities *equal) +{ + return equal->constraints->M.NbRows; +} + +CloogConstraintSet *cloog_equal_constraints(CloogEqualities *equal) +{ + return equal->constraints; +} + + +/** + * cloog_constraint_equal_type function : + * This function returns the type of the equality in the constraint (line) of + * (constraints) for the element (level). An equality is 'constant' iff all + * other factors are null except the constant one. It is a 'pure item' iff + * it is equal or opposite to a single variable or parameter. + * Otherwise it is an 'affine expression'. + * For instance: + * i = -13 is constant, i = j, j = -M are pure items, + * j = 2*M, i = j+1, 2*j = M are affine expressions. + * + * - constraints is the matrix of constraints, + * - level is the column number in equal of the element which is 'equal to', + ** + * - July 3rd 2002: first version, called pprint_equal_isconstant. + * - July 6th 2002: adaptation for the 3 types. + * - June 15th 2005: (debug) expr = domain->Constraint[line] was evaluated + * before checking if line != ONE_TIME_LOOP. Since + * ONE_TIME_LOOP is -1, an invalid read was possible. + * - October 19th 2005: Removal of the once-time-loop specific processing. + */ +static int cloog_constraint_equal_type(CloogConstraint *constraint, int level) +{ + int i, one=0 ; + cloog_int_t *expr; + + expr = *constraint->line; + + if (!cloog_int_is_one(expr[level]) && !cloog_int_is_neg_one(expr[level])) + return EQTYPE_EXAFFINE; + + /* There is only one non null factor, and it must be +1 or -1 for + * iterators or parameters. + */ + for (i = 1;i <= constraint->set->M.NbColumns-2; i++) + if (!cloog_int_is_zero(expr[i]) && (i != level)) { + if ((!cloog_int_is_one(expr[i]) && !cloog_int_is_neg_one(expr[i])) || (one != 0)) + return EQTYPE_EXAFFINE ; + else + one = 1 ; + } + /* if the constant factor is non null, it must be alone. */ + if (one != 0) { + if (!cloog_int_is_zero(expr[constraint->set->M.NbColumns-1])) + return EQTYPE_EXAFFINE ; + } + else + return EQTYPE_CONSTANT ; + + return EQTYPE_PUREITEM ; +} + + +int cloog_equal_type(CloogEqualities *equal, int level) +{ + return equal->types[level-1]; +} + + +/** + * cloog_equal_update function: + * this function updates a matrix of equalities where each row corresponds to + * the equality "=0" of an affine expression such that the entry at column + * "row" (="level") is not zero. This matrix is upper-triangular, except the + * row number "level-1" which has to be updated for the matrix to be triangular. + * This function achieves the processing. + * - equal is the matrix to be updated, + * - level gives the row that has to be updated (it is actually row "level-1"), + * - nb_par is the number of parameters of the program. + ** + * - September 20th 2005: first version. + */ +static void cloog_equal_update(CloogEqualities *equal, int level, int nb_par) +{ int i, j ; + cloog_int_t gcd, factor_level, factor_outer, temp_level, temp_outer; + + cloog_int_init(gcd); + cloog_int_init(temp_level); + cloog_int_init(temp_outer); + cloog_int_init(factor_level); + cloog_int_init(factor_outer); + + /* For each previous level, */ + for (i=level-2;i>=0;i--) + { /* if the corresponding iterator is inside the current equality and is equal + * to something, + */ + if (!cloog_int_is_zero(equal->constraints->M.p[level-1][i+1]) && equal->types[i]) + { /* Compute the Greatest Common Divisor. */ + cloog_int_gcd(gcd, equal->constraints->M.p[level-1][i+1], + equal->constraints->M.p[i][i+1]); + + /* Compute the factors to apply to each row vector element. */ + cloog_int_divexact(factor_level, equal->constraints->M.p[i][i+1], gcd); + cloog_int_divexact(factor_outer, equal->constraints->M.p[level-1][i+1], gcd); + + /* Now update the row 'level'. */ + /* - the iterators, up to level, */ + for (j = 1; j <= level; j++) { + cloog_int_mul(temp_level, factor_level, + equal->constraints->M.p[level-1][j]); + cloog_int_mul(temp_outer, factor_outer, equal->constraints->M.p[i][j]); + cloog_int_sub(equal->constraints->M.p[level-1][j], temp_level, temp_outer); + } + /* - between last useful iterator (level) and the first parameter, the + * matrix is sparse (full of zeroes), we just do nothing there. + * - the parameters and the scalar. + */ + for (j = 0; j < nb_par + 1; j++) { + cloog_int_mul(temp_level,factor_level, + equal->constraints->M.p[level-1] + [equal->constraints->M.NbColumns-j-1]); + cloog_int_mul(temp_outer,factor_outer, + equal->constraints->M.p[i][equal->constraints->M.NbColumns-j-1]); + cloog_int_sub(equal->constraints->M.p[level-1] + [equal->constraints->M.NbColumns-j-1], + temp_level,temp_outer) ; + } + } + } + + /* Normalize (divide by GCD of all elements) the updated equality. */ + cloog_seq_normalize(&(equal->constraints->M.p[level-1][1]), + equal->constraints->M.NbColumns-1); + + cloog_int_clear(gcd); + cloog_int_clear(temp_level); + cloog_int_clear(temp_outer); + cloog_int_clear(factor_level); + cloog_int_clear(factor_outer); +} + + +/** + * cloog_equal_add function: + * This function updates the row (level-1) of the equality matrix (equal) with + * the row that corresponds to the row (line) of the matrix (matrix). + * - equal is the matrix of equalities, + * - matrix is the matrix of constraints, + * - level is the column number in matrix of the element which is 'equal to', + * - line is the line number in matrix of the constraint we want to study, + * - the infos structure gives the user all options on code printing and more. + ** + * - July 2nd 2002: first version. + * - October 19th 2005: Addition of the once-time-loop specific processing. + */ +void cloog_equal_add(CloogEqualities *equal, CloogConstraintSet *constraints, + int level, CloogConstraint *line, int nb_par) +{ + int j; + CloogConstraint *i = cloog_constraint_invalid(); + CloogMatrix *matrix = &constraints->M; + + /* If we are in the case of a loop running once, this means that the equality + * comes from an inequality. Here we find this inequality. + */ + if (!cloog_constraint_is_valid(line)) + { for (i = cloog_constraint_first(constraints); + cloog_constraint_is_valid(i); i = cloog_constraint_next(i)) + if ((!cloog_int_is_zero(i->line[0][0]))&& (!cloog_int_is_zero(i->line[0][level]))) + { line = i ; + + /* Since in once-time-loops, equalities derive from inequalities, we + * may have to offset the values. For instance if we have 2i>=3, the + * equality is in fact i=2. This may happen when the level coefficient is + * not 1 or -1 and the scalar value is not zero. In any other case (e.g., + * if the inequality is an expression including outer loop counters or + * parameters) the once time loop would not have been detected + * because of floord and ceild functions. + */ + if (cloog_int_ne_si(i->line[0][level],1) && + cloog_int_ne_si(i->line[0][level],-1) && + !cloog_int_is_zero(i->line[0][matrix->NbColumns-1])) { + cloog_int_t denominator; + + cloog_int_init(denominator); + cloog_int_abs(denominator, i->line[0][level]); + cloog_int_fdiv_q(i->line[0][matrix->NbColumns-1], + i->line[0][matrix->NbColumns-1], denominator); + cloog_int_set_si(i->line[0][level], cloog_int_sgn(i->line[0][level])); + cloog_int_clear(denominator); + } + + break ; + } + } + assert(cloog_constraint_is_valid(line)); + + /* We update the line of equal corresponding to level: + * - the first element gives the equality type, + */ + equal->types[level-1] = cloog_constraint_equal_type(line, level); + /* - the other elements corresponding to the equality itself + * (the iterators up to level, then the parameters and the scalar). + */ + for (j=1;j<=level;j++) + cloog_int_set(equal->constraints->M.p[level-1][j], line->line[0][j]); + for (j = 0; j < nb_par + 1; j++) + cloog_int_set(equal->constraints->M.p[level-1][equal->constraints->M.NbColumns-j-1], + line->line[0][line->set->M.NbColumns-j-1]); + + if (cloog_constraint_is_valid(i)) + cloog_constraint_release(line); + cloog_equal_update(equal, level, nb_par); +} + + +/** + * cloog_equal_del function : + * This function reset the equality corresponding to the iterator (level) + * in the equality matrix (equal). + * - July 2nd 2002: first version. + */ +void cloog_equal_del(CloogEqualities *equal, int level) +{ + equal->types[level-1] = EQTYPE_NONE; +} + + + +/****************************************************************************** + * Processing functions * + ******************************************************************************/ + +/** + * Function cloog_constraint_set_normalize: + * This function will modify the constraint system in such a way that when + * there is an equality depending on the element at level 'level', there are + * no more (in)equalities depending on this element. For instance, try + * test/valilache.cloog with options -f 8 -l 9, with and without the call + * to this function. At a given moment, for the level L we will have + * 32*P=L && L>=1 (P is a lower level), this constraint system cannot be + * translated directly into a source code. Thus, we normalize the domain to + * remove L from the inequalities. In our example, this leads to + * 32*P=L && 32*P>=1, that can be transated to the code + * if (P>=1) { L=32*P ; ... }. This function solves the DaeGon Kim bug. + * WARNING: Remember that if there is another call to Polylib after a call to + * this function, we have to recall this function. + * -June 16th 2005: first version (adaptation from URGent June-7th-2005 by + * N. Vasilache). + * - June 21rd 2005: Adaptation for GMP. + * - November 4th 2005: Complete rewriting, simpler and faster. It is no more an + * adaptation from URGent. + */ +void cloog_constraint_set_normalize(CloogConstraintSet *constraints, int level) +{ int ref, i, j ; + cloog_int_t factor_i, factor_ref, temp_i, temp_ref, gcd; + CloogMatrix *matrix = &constraints->M; + + if (matrix == NULL) + return ; + + /* Don't "normalize" the constant term. */ + if (level == matrix->NbColumns-1) + return; + + /* Let us find an equality for the current level that can be propagated. */ + for (ref=0;ref<matrix->NbRows;ref++) + if (cloog_int_is_zero(matrix->p[ref][0]) && !cloog_int_is_zero(matrix->p[ref][level])) { + cloog_int_init(gcd); + cloog_int_init(temp_i); + cloog_int_init(temp_ref); + cloog_int_init(factor_i); + cloog_int_init(factor_ref); + + /* Row "ref" is the reference equality, now let us find a row to simplify.*/ + for (i=ref+1;i<matrix->NbRows;i++) + if (!cloog_int_is_zero(matrix->p[i][level])) { + /* Now let us set to 0 the "level" coefficient of row "j" using "ref". + * First we compute the factors to apply to each row vector element. + */ + cloog_int_gcd(gcd, matrix->p[ref][level], matrix->p[i][level]); + cloog_int_divexact(factor_i, matrix->p[ref][level], gcd); + cloog_int_divexact(factor_ref, matrix->p[i][level], gcd); + + /* Maybe we are simplifying an inequality: factor_i must not be <0. */ + if (cloog_int_is_neg(factor_i)) { + cloog_int_abs(factor_i, factor_i); + cloog_int_neg(factor_ref, factor_ref); + } + + /* Now update the vector. */ + for (j=1;j<matrix->NbColumns;j++) { + cloog_int_mul(temp_i, factor_i, matrix->p[i][j]); + cloog_int_mul(temp_ref, factor_ref, matrix->p[ref][j]); + cloog_int_sub(matrix->p[i][j], temp_i, temp_ref); + } + + /* Normalize (divide by GCD of all elements) the updated vector. */ + cloog_seq_normalize(&(matrix->p[i][1]), matrix->NbColumns-1); + } + + cloog_int_clear(gcd); + cloog_int_clear(temp_i); + cloog_int_clear(temp_ref); + cloog_int_clear(factor_i); + cloog_int_clear(factor_ref); + break ; + } +} + + + +/** + * cloog_constraint_set_copy function: + * this functions builds and returns a "hard copy" (not a pointer copy) of a + * CloogMatrix data structure. + * - October 26th 2005: first version. + */ +CloogConstraintSet *cloog_constraint_set_copy(CloogConstraintSet *constraints) +{ int i, j ; + CloogMatrix *copy; + CloogMatrix *matrix = &constraints->M; + + copy = cloog_matrix_alloc(matrix->NbRows, matrix->NbColumns); + + for (i=0;i<matrix->NbRows;i++) + for (j=0;j<matrix->NbColumns;j++) + cloog_int_set(copy->p[i][j], matrix->p[i][j]); + + return cloog_constraint_set_from_cloog_matrix(copy); +} + + +/** + * cloog_equal_vector_simplify function: + * this function simplify an affine expression with its coefficients in + * "vector" of length "length" thanks to an equality matrix "equal" that gives + * for some elements of the affine expression an equality with other elements, + * preferably constants. For instance, if the vector contains i+j+3 and the + * equality matrix gives i=n and j=2, the vector is simplified to n+3 and is + * returned in a new vector. + * - vector is the array of affine expression coefficients + * - equal is the matrix of equalities, + * - length is the vector length, + * - level is a level we don't want to simplify (-1 if none), + * - nb_par is the number of parameters of the program. + ** + * - September 20th 2005: first version. + * - November 2nd 2005: (debug) we are simplifying inequalities, thus we are + * not allowed to multiply the vector by a negative + * constant.Problem found after a report of Michael + * Classen. + */ +struct cloog_vec *cloog_equal_vector_simplify(CloogEqualities *equal, cloog_int_t *vector, + int length, int level, int nb_par) +{ int i, j ; + cloog_int_t gcd, factor_vector, factor_equal, temp_vector, temp_equal; + struct cloog_vec *simplified; + + simplified = cloog_vec_alloc(length); + cloog_seq_cpy(simplified->p, vector, length); + + cloog_int_init(gcd); + cloog_int_init(temp_vector); + cloog_int_init(temp_equal); + cloog_int_init(factor_vector); + cloog_int_init(factor_equal); + + /* For each non-null coefficient in the vector, */ + for (i=length-nb_par-2;i>0;i--) + if (i != level) + { /* if the coefficient in not null, and there exists a useful equality */ + if ((!cloog_int_is_zero(simplified->p[i])) && equal->types[i-1]) + { /* Compute the Greatest Common Divisor. */ + cloog_int_gcd(gcd, simplified->p[i], equal->constraints->M.p[i-1][i]); + + /* Compute the factors to apply to each row vector element. */ + cloog_int_divexact(factor_vector, equal->constraints->M.p[i-1][i], gcd); + cloog_int_divexact(factor_equal, simplified->p[i], gcd); + + /* We are simplifying an inequality: factor_vector must not be <0. */ + if (cloog_int_is_neg(factor_vector)) { + cloog_int_abs(factor_vector, factor_vector); + cloog_int_neg(factor_equal, factor_equal); + } + + /* Now update the vector. */ + /* - the iterators, up to the current level, */ + for (j=1;j<=length-nb_par-2;j++) { + cloog_int_mul(temp_vector, factor_vector, simplified->p[j]); + cloog_int_mul(temp_equal, factor_equal, equal->constraints->M.p[i-1][j]); + cloog_int_sub(simplified->p[j], temp_vector, temp_equal); + } + /* - between last useful iterator (i) and the first parameter, the equal + * matrix is sparse (full of zeroes), we just do nothing there. + * - the parameters and the scalar. + */ + for (j = 0; j < nb_par + 1; j++) { + cloog_int_mul(temp_vector, factor_vector, simplified->p[length-1-j]); + cloog_int_mul(temp_equal,factor_equal, + equal->constraints->M.p[i-1][equal->constraints->M.NbColumns-j-1]); + cloog_int_sub(simplified->p[length-1-j],temp_vector,temp_equal) ; + } + } + } + + /* Normalize (divide by GCD of all elements) the updated vector. */ + cloog_seq_normalize(&simplified->p[1], length - 1); + + cloog_int_clear(gcd); + cloog_int_clear(temp_vector); + cloog_int_clear(temp_equal); + cloog_int_clear(factor_vector); + cloog_int_clear(factor_equal); + + return simplified ; +} + + +/** + * cloog_constraint_set_simplify function: + * this function simplify all constraints inside the matrix "matrix" thanks to + * an equality matrix "equal" that gives for some elements of the affine + * constraint an equality with other elements, preferably constants. + * For instance, if a row of the matrix contains i+j+3>=0 and the equality + * matrix gives i=n and j=2, the constraint is simplified to n+3>=0. The + * simplified constraints are returned back inside a new simplified matrix. + * - matrix is the set of constraints to simplify, + * - equal is the matrix of equalities, + * - level is a level we don't want to simplify (-1 if none), + * - nb_par is the number of parameters of the program. + ** + * - November 4th 2005: first version. + */ +CloogConstraintSet *cloog_constraint_set_simplify(CloogConstraintSet *constraints, + CloogEqualities *equal, int level, int nb_par) +{ int i, j, k ; + struct cloog_vec *vector; + CloogMatrix *simplified; + CloogMatrix *matrix = &constraints->M; + + if (matrix == NULL) + return NULL ; + + /* The simplified matrix is such that each row has been simplified thanks + * tho the "equal" matrix. We allocate the memory for the simplified matrix, + * then for each row of the original matrix, we compute the simplified + * vector and we copy its content into the according simplified row. + */ + simplified = cloog_matrix_alloc(matrix->NbRows, matrix->NbColumns); + for (i=0;i<matrix->NbRows;i++) + { vector = cloog_equal_vector_simplify(equal, matrix->p[i], + matrix->NbColumns, level, nb_par); + for (j=0;j<matrix->NbColumns;j++) + cloog_int_set(simplified->p[i][j], vector->p[j]); + + cloog_vec_free(vector); + } + + /* After simplification, it may happen that few constraints are the same, + * we remove them here by replacing them with 0=0 constraints. + */ + for (i=0;i<simplified->NbRows;i++) + for (j=i+1;j<simplified->NbRows;j++) + { for (k=0;k<simplified->NbColumns;k++) + if (cloog_int_ne(simplified->p[i][k],simplified->p[j][k])) + break ; + + if (k == matrix->NbColumns) + { for (k=0;k<matrix->NbColumns;k++) + cloog_int_set_si(simplified->p[j][k],0); + } + } + + return cloog_constraint_set_from_cloog_matrix(simplified); +} + + +/** + * Return clast_expr corresponding to the variable "level" (1 based) in + * the given constraint. + */ +struct clast_expr *cloog_constraint_variable_expr(CloogConstraint *constraint, + int level, CloogNames *names) +{ + int total_dim, nb_iter; + const char *name; + + total_dim = cloog_constraint_total_dimension(constraint); + nb_iter = total_dim - names->nb_parameters; + + if (level <= nb_iter) + name = cloog_names_name_at_level(names, level); + else + name = names->parameters[level - (nb_iter+1)] ; + + return &new_clast_name(name)->expr; +} + + +/** + * Return true if constraint c involves variable v (zero-based). + */ +int cloog_constraint_involves(CloogConstraint *constraint, int v) +{ + return !cloog_int_is_zero(constraint->line[0][1+v]); +} + +int cloog_constraint_is_lower_bound(CloogConstraint *constraint, int v) +{ + return cloog_int_is_pos(constraint->line[0][1+v]); +} + +int cloog_constraint_is_upper_bound(CloogConstraint *constraint, int v) +{ + return cloog_int_is_neg(constraint->line[0][1+v]); +} + +int cloog_constraint_is_equality(CloogConstraint *constraint) +{ + return cloog_int_is_zero(constraint->line[0][0]); +} + +void cloog_constraint_clear(CloogConstraint *constraint) +{ + int k; + + for (k = 1; k <= constraint->set->M.NbColumns - 2; k++) + cloog_int_set_si(constraint->line[0][k], 0); +} + +void cloog_constraint_coefficient_get(CloogConstraint *constraint, + int var, cloog_int_t *val) +{ + cloog_int_set(*val, constraint->line[0][1+var]); +} + +void cloog_constraint_coefficient_set(CloogConstraint *constraint, + int var, cloog_int_t val) +{ + cloog_int_set(constraint->line[0][1+var], val); +} + +void cloog_constraint_constant_get(CloogConstraint *constraint, cloog_int_t *val) +{ + cloog_int_set(*val, constraint->line[0][constraint->set->M.NbColumns-1]); +} + +/** + * Copy the coefficient of constraint c into dst in PolyLib order, + * i.e., first the coefficients of the variables, then the coefficients + * of the parameters and finally the constant. + */ +void cloog_constraint_copy_coefficients(CloogConstraint *constraint, + cloog_int_t *dst) +{ + cloog_seq_cpy(dst, constraint->line[0]+1, constraint->set->M.NbColumns-1); +} + +CloogConstraint *cloog_constraint_invalid(void) +{ + return NULL; +} + +int cloog_constraint_is_valid(CloogConstraint *constraint) +{ + return constraint != NULL; +} + + +/** + * Check whether there is any need for the constraint "upper" on + * "level" to get reduced. + * Yes. + */ +int cloog_constraint_needs_reduction(CloogConstraint *upper, int level) +{ + return 1; +} + + +/** + * Create a CloogConstraintSet containing enough information to perform + * a reduction on the upper equality (in this case lower is an invalid + * CloogConstraint) or the pair of inequalities upper and lower + * from within insert_modulo_guard. + * In the PolyLib backend, we return a CloogConstraintSet containting only + * the upper bound. The reduction will not change the stride so there + * will be no need to recompute the bound on the modulo expression. + */ +CloogConstraintSet *cloog_constraint_set_for_reduction(CloogConstraint *upper, + CloogConstraint *lower) +{ + CloogConstraintSet *set; + + set = cloog_constraint_set_from_cloog_matrix( + cloog_matrix_alloc(1, upper->set->M.NbColumns)); + cloog_seq_cpy(set->M.p[0], upper->line[0], set->M.NbColumns); + return set; +} + + +/* Computes x, y and g such that g = gcd(a,b) and a*x+b*y = g */ +static void Euclid(cloog_int_t a, cloog_int_t b, + cloog_int_t *x, cloog_int_t *y, cloog_int_t *g) +{ + cloog_int_t c, d, e, f, tmp; + + cloog_int_init(c); + cloog_int_init(d); + cloog_int_init(e); + cloog_int_init(f); + cloog_int_init(tmp); + cloog_int_abs(c, a); + cloog_int_abs(d, b); + cloog_int_set_si(e, 1); + cloog_int_set_si(f, 0); + while (cloog_int_is_pos(d)) { + cloog_int_tdiv_q(tmp, c, d); + cloog_int_mul(tmp, tmp, f); + cloog_int_sub(e, e, tmp); + cloog_int_tdiv_q(tmp, c, d); + cloog_int_mul(tmp, tmp, d); + cloog_int_sub(c, c, tmp); + cloog_int_swap(c, d); + cloog_int_swap(e, f); + } + cloog_int_set(*g, c); + if (cloog_int_is_zero(a)) + cloog_int_set_si(*x, 0); + else if (cloog_int_is_pos(a)) + cloog_int_set(*x, e); + else cloog_int_neg(*x, e); + if (cloog_int_is_zero(b)) + cloog_int_set_si(*y, 0); + else { + cloog_int_mul(tmp, a, *x); + cloog_int_sub(tmp, c, tmp); + cloog_int_divexact(*y, tmp, b); + } + cloog_int_clear(c); + cloog_int_clear(d); + cloog_int_clear(e); + cloog_int_clear(f); + cloog_int_clear(tmp); +} + +/** + * Reduce the modulo guard expressed by "contraints" using equalities + * found in outer nesting levels (stored in "equal"). + * The modulo guard may be an equality or a pair of inequalities. + * In case of a pair of inequalities, "constraints" only contains the + * upper bound and *bound contains the bound on the + * corresponding modulo expression. The bound is left untouched by + * this function. + */ +CloogConstraintSet *cloog_constraint_set_reduce(CloogConstraintSet *constraints, + int level, CloogEqualities *equal, int nb_par, cloog_int_t *bound) +{ + int i, j, k, len, len2, nb_iter; + struct cloog_vec *line_vector2; + cloog_int_t *line, *line2, val, x, y, g; + + len = constraints->M.NbColumns; + len2 = cloog_equal_total_dimension(equal) + 2; + nb_iter = len - 2 - nb_par; + + cloog_int_init(val); + cloog_int_init(x); + cloog_int_init(y); + cloog_int_init(g); + + line_vector2 = cloog_vec_alloc(len2); + line2 = line_vector2->p; + + line = constraints->M.p[0]; + if (cloog_int_is_pos(line[level])) + cloog_seq_neg(line+1, line+1, len-1); + cloog_int_neg(line[level], line[level]); + assert(cloog_int_is_pos(line[level])); + + for (i = nb_iter; i >= 1; --i) { + if (i == level) + continue; + cloog_int_fdiv_r(line[i], line[i], line[level]); + if (cloog_int_is_zero(line[i])) + continue; + + /* Look for an earlier variable that is also a multiple of line[level] + * and check whether we can use the corresponding affine expression + * to "reduce" the modulo guard, where reduction means that we eliminate + * a variable, possibly at the expense of introducing other variables + * with smaller index. + */ + for (j = level-1; j >= 0; --j) { + CloogConstraint *equal_constraint; + if (cloog_equal_type(equal, j+1) != EQTYPE_EXAFFINE) + continue; + equal_constraint = cloog_equal_constraint(equal, j); + cloog_constraint_coefficient_get(equal_constraint, j, &val); + if (!cloog_int_is_divisible_by(val, line[level])) { + cloog_constraint_release(equal_constraint); + continue; + } + cloog_constraint_coefficient_get(equal_constraint, i-1, &val); + if (cloog_int_is_divisible_by(val, line[level])) { + cloog_constraint_release(equal_constraint); + continue; + } + for (k = j; k > i; --k) { + cloog_constraint_coefficient_get(equal_constraint, k-1, &val); + if (cloog_int_is_zero(val)) + continue; + if (!cloog_int_is_divisible_by(val, line[level])) + break; + } + if (k > i) { + cloog_constraint_release(equal_constraint); + continue; + } + cloog_constraint_coefficient_get(equal_constraint, i-1, &val); + Euclid(val, line[level], &x, &y, &g); + if (!cloog_int_is_divisible_by(val, line[i])) { + cloog_constraint_release(equal_constraint); + continue; + } + cloog_int_divexact(val, line[i], g); + cloog_int_neg(val, val); + cloog_int_mul(val, val, x); + cloog_int_set_si(y, 1); + /* Add (equal->p[j][i])^{-1} * line[i] times the equality */ + cloog_constraint_copy_coefficients(equal_constraint, line2+1); + cloog_seq_combine(line+1, y, line+1, val, line2+1, i); + cloog_seq_combine(line+len-nb_par-1, y, line+len-nb_par-1, + val, line2+len2-nb_par-1, nb_par+1); + cloog_constraint_release(equal_constraint); + break; + } + } + + cloog_vec_free(line_vector2); + + cloog_int_clear(val); + cloog_int_clear(x); + cloog_int_clear(y); + cloog_int_clear(g); + + /* Make sure the line is not inverted again in the calling function. */ + cloog_int_neg(line[level], line[level]); + + return constraints; +} + +CloogConstraint *cloog_constraint_first(CloogConstraintSet *constraints) +{ + CloogConstraint *c; + if (constraints->M.NbRows == 0) + return cloog_constraint_invalid(); + c = ALLOC(CloogConstraint); + c->set = constraints; + c->line = &constraints->M.p[0]; + return c; +} + +CloogConstraint *cloog_constraint_next(CloogConstraint *constraint) +{ + constraint->line++; + if (constraint->line == constraint->set->M.p + constraint->set->M.NbRows) { + cloog_constraint_release(constraint); + return NULL; + } + return constraint; +} + +CloogConstraint *cloog_constraint_copy(CloogConstraint *constraint) +{ + CloogConstraint *c = ALLOC(CloogConstraint); + c->set = constraint->set; + c->line = constraint->line; + return c; +} + +void cloog_constraint_release(CloogConstraint *constraint) +{ + free(constraint); +} + +int cloog_constraint_set_foreach_constraint(CloogConstraintSet *constraints, + int (*fn)(CloogConstraint *constraint, void *user), void *user) +{ + CloogConstraint *c; + + for (c = cloog_constraint_first(constraints); + cloog_constraint_is_valid(c); c = cloog_constraint_next(c)) + if (fn(c, user) < 0) { + cloog_constraint_release(c); + return -1; + } + + return 0; +} + +CloogConstraint *cloog_equal_constraint(CloogEqualities *equal, int j) +{ + CloogConstraint *c = ALLOC(CloogConstraint); + c->set = equal->constraints; + c->line = &equal->constraints->M.p[j]; + return c; +} diff --git a/cloog-core/source/mp_get_memory_functions.c b/cloog-core/source/mp_get_memory_functions.c new file mode 100644 index 0000000..e14e336 --- /dev/null +++ b/cloog-core/source/mp_get_memory_functions.c @@ -0,0 +1,14 @@ +#include <gmp.h> + +void mp_get_memory_functions( + void *(**alloc_func_ptr) (size_t), + void *(**realloc_func_ptr) (void *, size_t, size_t), + void (**free_func_ptr) (void *, size_t)) +{ + if (alloc_func_ptr) + *alloc_func_ptr = __gmp_allocate_func; + if (realloc_func_ptr) + *realloc_func_ptr = __gmp_reallocate_func; + if (free_func_ptr) + *free_func_ptr = __gmp_free_func; +} diff --git a/cloog-core/source/names.c b/cloog-core/source/names.c new file mode 100644 index 0000000..53e39b2 --- /dev/null +++ b/cloog-core/source/names.c @@ -0,0 +1,528 @@ + + /**-------------------------------------------------------------------** + ** CLooG ** + **-------------------------------------------------------------------** + ** names.c ** + **-------------------------------------------------------------------** + ** First version: august 1st 2002 ** + **-------------------------------------------------------------------**/ + + +/****************************************************************************** + * CLooG : the Chunky Loop Generator (experimental) * + ****************************************************************************** + * * + * Copyright (C) 2002-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 <stdlib.h> +# include <stdio.h> +# include <ctype.h> +# include "../include/cloog/cloog.h" + + +/****************************************************************************** + * Structure display function * + ******************************************************************************/ + + +/** + * cloog_names_print function: + * this function is a human-friendly way to display the CloogNames 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_names_print function, + * it was the first modification in this file since two years ! + */ +void cloog_names_print_structure(FILE * file, CloogNames * names, int level) +{ int i ; + + /* Go to the right level. */ + for (i=0; i<level; i++) + fprintf(file,"|\t") ; + + if (names != NULL) + { fprintf(file,"+-- CloogNames\n") ; + + /* A blank line. */ + for (i=0; i<=level+1; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print the scalar dimension number. */ + for (i=0; i<=level; i++) + fprintf(file,"|\t") ; + fprintf(file,"Scalar dimension number ---: %d\n",names->nb_scalars) ; + + /* A blank line. */ + for (i=0; i<=level+1; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print the scalar iterators. */ + for (i=0; i<=level; i++) + fprintf(file,"|\t") ; + if (names->nb_scalars > 0) + { fprintf(file,"+-- Scalar iterator strings:") ; + for (i=0;i<names->nb_scalars;i++) + fprintf(file," %s",names->scalars[i]) ; + fprintf(file,"\n") ; + } + else + fprintf(file,"+-- No scalar string\n") ; + + /* 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",names->nb_scattering) ; + + /* A blank line. */ + for (i=0; i<=level+1; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print the scattering iterators. */ + for (i=0; i<=level; i++) + fprintf(file,"|\t") ; + if (names->nb_scattering > 0) + { fprintf(file,"+-- Scattering strings ----:") ; + for (i=0;i<names->nb_scattering;i++) + fprintf(file," %s",names->scattering[i]) ; + fprintf(file,"\n") ; + } + else + fprintf(file,"+-- No scattering string\n") ; + + /* A blank line. */ + for (i=0; i<=level+1; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print the iterator number. */ + for (i=0; i<=level; i++) + fprintf(file,"|\t") ; + fprintf(file,"Iterator number -----------: %d\n",names->nb_iterators) ; + + /* A blank line. */ + for (i=0; i<=level+1; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print the iterators. */ + for (i=0; i<=level; i++) + fprintf(file,"|\t") ; + if (names->nb_iterators > 0) + { fprintf(file,"+-- Iterator strings ------:") ; + for (i=0;i<names->nb_iterators;i++) + fprintf(file," %s",names->iterators[i]) ; + fprintf(file,"\n") ; + } + else + fprintf(file,"+-- No iterators\n") ; + + /* A blank line. */ + for (i=0; i<=level+1; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print the parameter number. */ + for (i=0; i<=level; i++) + fprintf(file,"|\t") ; + fprintf(file,"Parameter number ----------: %d\n",names->nb_parameters) ; + + /* A blank line. */ + for (i=0; i<=level+1; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print the parameters. */ + for (i=0; i<=level; i++) + fprintf(file,"|\t") ; + if (names->nb_parameters > 0) + { fprintf(file,"+-- Parameter strings -----:") ; + for (i=0;i<names->nb_parameters;i++) + fprintf(file," %s",names->parameters[i]) ; + fprintf(file,"\n") ; + } + else + fprintf(file,"No parameters\n") ; + + } + else + fprintf(file,"+-- No CloogNames\n") ; + fprintf(file, "Number of active references: %d\n", names->references); +} + + +/** + * cloog_names_print function: + * This function prints the content of a CloogNames structure (names) into a + * file (file, possibly stdout). + * - July 1st 2005: Now this function is only a frontend to + * cloog_program_print_structure, with a quite better + * human-readable representation. + */ +void cloog_names_print(FILE * file, CloogNames * names) +{ cloog_names_print_structure(file,names,0) ; +} + + +/****************************************************************************** + * Memory deallocation function * + ******************************************************************************/ + + +/** + * cloog_names_free function: + * This function decrements the number of active references to + * a CloogNames structure and frees the allocated memory for this structure + * if the count drops to zero. + */ +void cloog_names_free(CloogNames * names) +{ int i ; + + if (--names->references) + return; + + if (names->scalars != NULL) + { for (i=0;i<names->nb_scalars;i++) + free(names->scalars[i]) ; + free(names->scalars) ; + } + + if (names->scattering != NULL) + { for (i=0;i<names->nb_scattering;i++) + free(names->scattering[i]) ; + free(names->scattering) ; + } + + if (names->iterators != NULL) + { for (i=0;i<names->nb_iterators;i++) + free(names->iterators[i]) ; + free(names->iterators) ; + } + + if (names->parameters != NULL) + { for (i=0;i<names->nb_parameters;i++) + free(names->parameters[i]) ; + free(names->parameters) ; + } + free(names) ; +} + + +/** + * cloog_names_copy function: + * As usual in CLooG, "copy" means incrementing the reference count. + */ +CloogNames *cloog_names_copy(CloogNames *names) +{ + names->references++; + return names; +} + + +/****************************************************************************** + * Reading functions * + ******************************************************************************/ + + +/** + * cloog_names_read_strings function: + * This function reads names data from a file (file, possibly stdin). It first + * reads the naming option to know if whether it can read the names from the + * file. If not, NULL is returned. Otherwise, the names are stored + * into an array of strings, and a pointer to this array is returned. + * - nb_items is the number of names the function will have to read if the + * naming option is set to read. + */ +char ** cloog_names_read_strings(FILE *file, int nb_items) +{ int i, option, n ; + char s[MAX_STRING], str[MAX_STRING], * c, **names = NULL; + + /* We first read name option. */ + while (fgets(s,MAX_STRING,file) == 0) ; + while ((*s=='#' || *s=='\n') || (sscanf(s," %d",&option)<1)) + fgets(s,MAX_STRING,file) ; + + /* If there is no item to read, then return NULL. */ + if (nb_items == 0) + return NULL ; + + /* If option is to read them in the file, then we do it and put them into + * the array. + */ + if (option) + { /* Memory allocation. */ + names = (char **)malloc(nb_items*sizeof(char *)) ; + if (names == NULL) + cloog_die("memory overflow.\n"); + for (i=0;i<nb_items;i++) + { names[i] = (char *)malloc(MAX_NAME*sizeof(char)) ; + if (names[i] == NULL) + cloog_die("memory overflow.\n"); + } + + do /* Skip the comments, spaces and empty lines... */ + { c = fgets(s,MAX_STRING,file) ; + while ((c != NULL) && isspace(*c) && (*c != '\n')) + c++ ; + } + while (c != NULL && (*c == '#' || *c == '\n')); + + if (c == NULL) + cloog_die("no names in input file.\n"); + for (i=0;i<nb_items;i++) + { /* All names must be on the same line. */ + while (isspace(*c)) + c++ ; + if (!*c || *c == '#' || *c == '\n') + cloog_die("not enough names in input file.\n"); + /* n is strlen(str). */ + if (sscanf(c,"%s%n",str,&n) == 0) + cloog_die("no names in input file.\n"); + sscanf(str,"%s",names[i]) ; + c += n ; + } + } + + return names ; +} + + +/****************************************************************************** + * Processing functions * + ******************************************************************************/ + + +/** + * cloog_names_malloc function: + * This function allocates the memory space for a CloogNames structure and + * sets its fields with default values. Then it returns a pointer to the + * allocated space. + * - November 21th 2005: first version. + */ +CloogNames * cloog_names_malloc() +{ CloogNames * names ; + + /* Memory allocation for the CloogNames structure. */ + names = (CloogNames *)malloc(sizeof(CloogNames)) ; + if (names == NULL) + cloog_die("memory overflow.\n"); + + /* We set the various fields with default values. */ + names->nb_scalars = 0 ; + names->nb_scattering = 0 ; + names->nb_iterators = 0 ; + names->nb_parameters = 0 ; + names->scalars = NULL ; + names->scattering = NULL ; + names->iterators = NULL ; + names->parameters = NULL ; + names->references = 1; + + return names ; +} + + +/** + * cloog_names_alloc function: + * This function allocates the memory space for a CloogNames structure and + * sets its fields with those given as input. Then it returns a pointer to the + * allocated space. + * - July 7th 2005: first version. + * - September 11th 2005: addition of both scalar and scattering informations. + * - November 21th 2005: use of cloog_names_malloc. + */ +CloogNames * cloog_names_alloc() +{ CloogNames * names ; + + /* Memory allocation for the CloogNames structure. */ + names = cloog_names_malloc() ; + + names->nb_scalars = 0; + names->nb_scattering = 0; + names->nb_iterators = 0; + names->nb_parameters = 0; + names->scalars = NULL; + names->scattering = NULL; + names->iterators = NULL; + names->parameters = NULL; + + return names ; +} + + +/** + * cloog_names_generate_items function: + * This function returns a pointer to an array of strings with entries set + * based on the function's parameters. + * - nb_items will be the number of entries in the string array. + * - prefix is the name prefix of each item or NULL. + * If not NULL, then the remainder of the name will be an integer + * in the range [0, nb_items-1]. + * - first_item is the name of the first item (if prefix == NULL), + * the nb_items-1 following items will be the nb_items-1 + * following letters in ASCII code. + ** + * - September 9th 2002 : first version, extracted from cloog_names_generate. + */ +char ** cloog_names_generate_items(int nb_items, char * prefix, char first_item) +{ int i ; + char ** names ; + + if (nb_items == 0) + return NULL ; + + names = (char **)malloc(nb_items*sizeof(char *)) ; + if (names == NULL) + cloog_die("memory overflow.\n"); + for (i=0;i<nb_items;i++) + { names[i] = (char *)malloc(MAX_NAME*sizeof(char)) ; + if (names[i] == NULL) + cloog_die("memory overflow.\n"); + if (prefix == NULL) + sprintf(names[i],"%c",first_item+i) ; + else + sprintf(names[i], "%s%d", prefix, 1+i); + } + + return names ; +} + + +/** + * cloog_names_generate function: + * This function returns a pointer to a CloogNames structure with fields set + * thanks to the function's parameters. + * - nb_scalars will be the number of scalar dimensions in the structure. + * - nb_scattering will be the number of scattering dimensions in the structure. + * - nb_iterators will be the number of iterators in the CloogNames structure. + * - nb_parameters will be the number of parameters in the CloogNames structure. + * - first_s is the name of the first scalar iterator, the nb_scalars-1 + * following iterators will be the nb_scalars-1 following letters in ASCII. + * - first_t is the name of the first scattering iterator, the nb_scattering-1 + * following iterators will be the nb_scattering-1 following letters in ASCII. + * - first_i is the name of the first iterator, the nb_iterators-1 following + * iterators will be the nb_iterators-1 following letters in ASCII code. + * - first_i is the name of the first iterator, the nb_iterators-1 following + * iterators will be the nb_iterators-1 following letters in ASCII code. + * - first_p is the name of the first parameter, the nb_parameters-1 following + * parameters will be the nb_parameters-1 following letters in ASCII code. + ** + * - July 1st 2002 : first version. + * - September 9th 2002 : use of cloog_names_generate_items. + * - September 11th 2005 : addition of both scalar and scattering informations. + */ +CloogNames * cloog_names_generate( + nb_scalars, nb_scattering, nb_iterators, nb_parameters, + first_s, first_t, first_i, first_p) +int nb_scalars, nb_scattering, nb_iterators, nb_parameters ; +char first_s, first_t, first_i, first_p ; +{ CloogNames * names ; + + names = (CloogNames *)malloc(sizeof(CloogNames)) ; + if (names == NULL) + cloog_die("memory overflow.\n"); + + names->nb_scalars = nb_scalars ; + names->nb_scattering = nb_scattering ; + names->nb_parameters = nb_parameters ; + names->nb_iterators = nb_iterators ; + names->scalars = cloog_names_generate_items(nb_scalars, NULL,first_s); + names->scattering = cloog_names_generate_items(nb_scattering,NULL,first_t); + names->parameters = cloog_names_generate_items(nb_parameters,NULL,first_p); + names->iterators = cloog_names_generate_items(nb_iterators, NULL,first_i); + + return names ; +} + + +/* Lastly we update the CLoogNames structure: the iterators corresponding to + * scalar dimensions have to be removed since these dimensions have been + * erased and do not need to be print. We copy all the iterator names except + * the scalar ones in a new string array. + * - September 12th 2005: first version. + */ +void cloog_names_scalarize(CloogNames * names, int nb_scattdims, int * scaldims) +{ int nb_scalars, nb_scattering, i, current_scalar, current_scattering ; + char ** scalars, ** scattering ; + + if (!nb_scattdims || (scaldims == NULL)) + return ; + + nb_scalars = 0 ; + for (i=0;i<nb_scattdims;i++) + if (scaldims[i]) + nb_scalars ++ ; + + if (!nb_scalars) + return ; + + nb_scattering = names->nb_scattering - nb_scalars ; + scattering = (char **)malloc(nb_scattering * sizeof(char *)) ; + if (scattering == NULL) + cloog_die("memory overflow.\n"); + scalars = (char **)malloc(nb_scalars * sizeof(char *)) ; + if (scalars == NULL) + cloog_die("memory overflow.\n"); + + current_scalar = 0 ; + current_scattering = 0 ; + for (i=0;i<nb_scattdims;i++) + { if (!scaldims[i]) + { scattering[current_scattering] = names->scattering[i] ; + current_scattering ++ ; + } + else + { scalars[current_scalar] = names->scattering[i] ; + current_scalar ++ ; + } + } + + free(names->scattering) ; + names->scattering = scattering ; + names->scalars = scalars ; + names->nb_scattering = nb_scattering ; + names->nb_scalars = nb_scalars ; +} + +/** + * Return the name at a given level (starting at one). + * May be a scattering dimension or an iterator of the original domain. + */ +const char *cloog_names_name_at_level(CloogNames *names, int level) +{ + if (level <= names->nb_scattering) + return names->scattering[level - 1]; + else + return names->iterators[level - names->nb_scattering - 1]; +} diff --git a/cloog-core/source/options.c b/cloog-core/source/options.c new file mode 100644 index 0000000..75d44a9 --- /dev/null +++ b/cloog-core/source/options.c @@ -0,0 +1,461 @@ + + /**-------------------------------------------------------------------** + ** CLooG ** + **-------------------------------------------------------------------** + ** options.c ** + **-------------------------------------------------------------------** + ** First version: april 19th 2003 ** + **-------------------------------------------------------------------**/ + + +/****************************************************************************** + * 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 * + * * + ******************************************************************************/ + + +#include <stdarg.h> +# include <stdlib.h> +# include <stdio.h> +# include <string.h> +# include "../include/cloog/cloog.h" + + +/****************************************************************************** + * Error reporting functions * + ******************************************************************************/ + +void cloog_vmsg(CloogOptions *options, enum cloog_msg_type type, + const char *msg, va_list ap) +{ + const char *type_msg; + + if (options && options->quiet && + (type == CLOOG_WARNING || type == CLOOG_INFO)) + return; + + switch(type) { + case CLOOG_WARNING: + type_msg = "WARNING"; + break; + case CLOOG_INFO: + type_msg = "INFO"; + break; + case CLOOG_ERROR: + default: + type_msg = "ERROR"; + break; + } + fprintf(stderr, "[CLooG] %s: ", type_msg); + vfprintf(stderr, msg, ap); +} + +/** + * Print message to stderr. + * @param msg printf format string + */ +void cloog_msg(CloogOptions *options, enum cloog_msg_type type, + const char *msg, ...) +{ + va_list args; + + va_start(args, msg); + cloog_vmsg(options, type, msg, args); + va_end(args); +} + +/** + * Print error message to stderr and exit. + * @param msg printf format string + */ +void cloog_die(const char *msg, ...) +{ + va_list args; + + va_start(args, msg); + cloog_vmsg(NULL, CLOOG_ERROR, msg, args); + va_end(args); + exit(1); +} + +/****************************************************************************** + * Structure display function * + ******************************************************************************/ + + +/** + * cloog_option_print function: + * This function prints the content of a CloogOptions structure (program) into + * a file (foo, possibly stdout). + * - April 19th 2003: first version. + */ +void cloog_options_print(FILE * foo, CloogOptions * options) +{ fprintf(foo,"Options:\n") ; + fprintf(foo,"OPTIONS FOR LOOP GENERATION\n") ; + fprintf(foo,"l = %3d,\n",options->l) ; + fprintf(foo,"f = %3d,\n",options->f) ; + fprintf(foo,"stop = %3d,\n",options->stop) ; + fprintf(foo,"strides = %3d,\n",options->strides) ; + fprintf(foo,"sh = %3d,\n",options->sh); + fprintf(foo,"OPTIONS FOR PRETTY PRINTING\n") ; + fprintf(foo,"esp = %3d,\n",options->esp) ; + fprintf(foo,"fsp = %3d,\n",options->fsp) ; + fprintf(foo,"otl = %3d.\n",options->otl) ; + fprintf(foo,"block = %3d.\n",options->block) ; + fprintf(foo,"compilable = %3d.\n",options->compilable) ; + fprintf(foo,"callable = %3d.\n",options->callable) ; + fprintf(foo,"UNDOCUMENTED OPTIONS FOR THE AUTHOR ONLY\n") ; + fprintf(foo,"leaks = %3d.\n",options->leaks) ; + fprintf(foo,"backtrack = %3d.\n",options->backtrack); + fprintf(foo,"override = %3d.\n",options->override) ; + fprintf(foo,"structure = %3d.\n",options->structure) ; + fprintf(foo,"noscalars = %3d.\n",options->noscalars) ; + fprintf(foo,"noblocks = %3d.\n",options->noblocks) ; + fprintf(foo,"nosimplify = %3d.\n",options->nosimplify) ; +} + + +/****************************************************************************** + * Memory deallocation function * + ******************************************************************************/ + + +/** + * cloog_options_free function: + * This function frees the allocated memory for a CloogOptions structure. + * - April 19th 2003: first version. + */ +void cloog_options_free(CloogOptions *options) +{ + free(options); +} + + +/****************************************************************************** + * Processing functions * + ******************************************************************************/ + + +/** + * cloog_options_help function: + * This function displays the quick help when the user set the option -help + * while calling cloog. Prints are cutted to respect the 509 characters + * limitation of the ISO C 89 compilers. + * - August 5th 2002: first version. + */ +void cloog_options_help() +{ printf( + "Usage: cloog [ options | file ] ...\n" + "Options for code generation:\n" + " -l <depth> Last loop depth to optimize (-1: infinity)\n" + " (default setting: -1).\n" + " -f <depth> First loop depth to start loop separation (-1: " + "infinity)\n (default setting: 1).\n") ; + printf( + " -stop <depth> Loop depth to stop code generation (-1: infinity)" + "\n (default setting: -1).\n" + " -strides <boolean> Handle non-unit strides (1) or not (0)\n" + " (default setting: 0).\n") ; + printf( + "\nOptions for pretty printing:\n" + " -otl <boolean> Simplify loops running one time (1) or not (0)\n" + " (default setting: 1).\n") ; + printf( + " -esp <boolean> Allow complex equalities spreading (1) or not (0)\n" + " (default setting: 0).\n"); + printf( + " -fsp <level> First level to begin the spreading\n" + " (default setting: 1).\n" + " -block <boolean> Make a new statement block per iterator in C\n" + " programs (1) or not (0) (default setting: 0).\n") ; + printf( + " -compilable <number> Compilable code by using preprocessor (not 0) or" + "\n not (0), number being the value of the parameters" + "\n (default setting: 0).\n" + " -callable <boolean> Testable code by using preprocessor (not 0) or" + "\n not (0) (default setting: 0).\n"); + printf( + "\nGeneral options:\n" + " -o <output> Name of the output file; 'stdout' is a special\n" + " value: when used, output is standard output\n" + " (default setting: stdout).\n" + " -v, --version Display the version information (and more).\n" + " -q, --quiet Don't print any informational messages.\n" + " -h, --help Display this information.\n\n") ; + printf( + "The special value 'stdin' for 'file' makes CLooG to read data on\n" + "standard input.\n\n" + "For bug reporting or any suggestions, please send an email to the author\n" + "<cedric.bastoul@inria.fr>.\n") ; +} + + +/** + * cloog_options_version function: + * This function displays some version informations when the user set the + * option -version while calling cloog. Prints are cutted to respect the 509 + * characters limitation of the ISO C 89 compilers. + * - August 5th 2002: first version. + */ +void cloog_options_version() +{ printf("%s The Chunky Loop Generator\n", cloog_version()); + printf( + "-----\n" + "This is a loop generator for scanning Z-polyhedra. It is based on the " + "work of\nF. Quillere and C. Bastoul on high level code generation and of " + "the PolyLib Team\non polyhedral computation. This program is distributed " + "under the terms of the\nGNU Lesser General Public License " + "(details at http://www.gnu.org/licenses/lgpl-2.1.html).\n" + "-----\n") ; + printf( + "It would be fair to refer the following paper in any publication " + "resulting from\nthe use of this software or its library:\n" + "@InProceedings{Bas04,\n" + "author = {Cedric Bastoul},\n" + "title = {Code Generation in the Polyhedral Model Is Easier Than You " + "Think},\n" + "booktitle = {PACT'13 IEEE International Conference on Parallel " + "Architecture\n and Compilation Techniques},\n" + "pages = {7--16},\n" + "month = {september},\n" + "year = 2004,\n" + "address = {Juan-les-Pins}\n" + "}\n" + "-----\n" + "For any information, please ask the author at " + "<cedric.bastoul@inria.fr>.\n") ; +} + + +/** + * cloog_options_set function: + * This function sets the value of an option thanks to the user's calling line. + * - option is the value to set, + * - argc are the elements of the user's calling line, + * - number is the number of the element corresponding to the considered option, + * this function adds 1 to number to pass away the option value. + ** + * - August 5th 2002: first version. + * - June 29th 2003: (debug) lack of argument now detected. + */ +void cloog_options_set(int * option, int argv, char ** argc, int * number) +{ char ** endptr ; + + if (*number+1 >= argv) + cloog_die("an option lacks of argument.\n"); + + endptr = NULL ; + *option = strtol(argc[*number+1],endptr,10) ; + if (endptr != NULL) + cloog_die("value '%s' for option '%s' is not valid.\n", + argc[*number+1], argc[*number]); + *number = *number + 1 ; +} + + +/** + * cloog_options_malloc function: + * This functions allocate the memory space for a CLoogOptions structure and + * fill its fields with the defaults values. It returns a pointer to the + * allocated CloogOptions structure. + * - April 19th 2003: first version. + * - November 21th 2005: name changed (before it was cloog_options_init). + */ +CloogOptions *cloog_options_malloc(CloogState *state) +{ CloogOptions * options ; + + /* Memory allocation for the CloogOptions structure. */ + options = (CloogOptions *)malloc(sizeof(CloogOptions)) ; + if (options == NULL) + cloog_die("memory overflow.\n"); + + options->state = state; + + /* We set the various fields with default values. */ + /* OPTIONS FOR LOOP GENERATION */ + options->l = -1 ; /* Last level to optimize: infinity. */ + options->f = 1 ; /* First level to optimize: the first. */ + options->stop = -1 ; /* Generate all the code. */ + options->strides = 0 ; /* Generate a code with unit strides. */ + options->sh = 0; /* Compute actual convex hull. */ + options->name = ""; + /* OPTIONS FOR PRETTY PRINTING */ + options->esp = 1 ; /* We don't want Equality SPreading.*/ + options->fsp = 1 ; /* The First level to SPread is the first. */ + options->otl = 1 ; /* We want to fire One Time Loops. */ + options->block = 0 ; /* We don't want to force statement blocks. */ + options->compilable = 0 ; /* No compilable code. */ + options->callable = 0 ; /* No callable code. */ + options->quiet = 0; /* Do print informational messages. */ + options->language = LANGUAGE_C; /* The default output language is C. */ + options->save_domains = 0; /* Don't save domains. */ + /* UNDOCUMENTED OPTIONS FOR THE AUTHOR ONLY */ + options->leaks = 0 ; /* I don't want to print allocation statistics.*/ + options->backtrack = 0; /* Perform backtrack in Quillere's algorithm.*/ + options->override = 0 ; /* I don't want to override CLooG decisions.*/ + options->structure = 0 ; /* I don't want to print internal structure.*/ + options->noblocks = 0 ; /* I do want to make statement blocks.*/ + options->noscalars = 0 ; /* I do want to use scalar dimensions.*/ + options->nosimplify = 0 ; /* I do want to simplify polyhedra.*/ + + return options ; +} + + + +/** + * cloog_options_read function: + * This functions reads all the options and the input/output files thanks + * the the user's calling line elements (in argc). It fills a CloogOptions + * structure and the FILE structure corresponding to input and output files. + * - August 5th 2002: first version. + * - April 19th 2003: now in options.c and support of the CloogOptions structure. + */ +void cloog_options_read(CloogState *state, int argc, char **argv, + FILE **input, FILE **output, CloogOptions **options) +{ int i, infos=0, input_is_set=0 ; + + /* CloogOptions structure allocation and initialization. */ + *options = cloog_options_malloc(state); + + /* The default output is the standard output. */ + *output = stdout ; + + for (i=1;i<argc;i++) + if (argv[i][0] == '-') + { if (strcmp(argv[i],"-l") == 0) + cloog_options_set(&(*options)->l,argc,argv,&i) ; + else + if (strcmp(argv[i],"-f") == 0) + cloog_options_set(&(*options)->f,argc,argv,&i) ; + else + if (strcmp(argv[i],"-stop") == 0) + cloog_options_set(&(*options)->stop,argc,argv,&i) ; + else + if (strcmp(argv[i],"-strides") == 0) + cloog_options_set(&(*options)->strides,argc,argv,&i) ; + else if (strcmp(argv[i],"-sh") == 0) + cloog_options_set(&(*options)->sh,argc,argv,&i) ; + else + if (strcmp(argv[i],"-otl") == 0) + cloog_options_set(&(*options)->otl,argc,argv,&i) ; + else + if (strcmp(argv[i],"-esp") == 0) + cloog_options_set(&(*options)->esp,argc,argv,&i) ; + else + if (strcmp(argv[i],"-fsp") == 0) + cloog_options_set(&(*options)->fsp,argc,argv,&i) ; + else + if (strcmp(argv[i],"-block") == 0) + cloog_options_set(&(*options)->block,argc,argv,&i) ; + else + if (strcmp(argv[i],"-compilable") == 0) + cloog_options_set(&(*options)->compilable, argc, argv, &i); + else if (strcmp(argv[i], "-callable") == 0) + cloog_options_set(&(*options)->callable, argc, argv, &i); + else + if (strcmp(argv[i],"-loopo") == 0) /* Special option for the LooPo team ! */ + { (*options)->esp = 0 ; + (*options)->block = 1 ; + } + else + if (strcmp(argv[i],"-bipbip") == 0)/* Special option for the author only !*/ + (*options)->backtrack = 0; + else + if (strcmp(argv[i],"-leaks") == 0) + (*options)->leaks = 1 ; + else + if (strcmp(argv[i],"-nobacktrack") == 0) + (*options)->backtrack = 0; + else if (strcmp(argv[i], "-backtrack") == 0) + (*options)->backtrack = 1; + else + if (strcmp(argv[i],"-override") == 0) + (*options)->override = 1 ; + else + if (strcmp(argv[i],"-noblocks") == 0) + (*options)->noblocks = 1 ; + else + if (strcmp(argv[i],"-noscalars") == 0) + (*options)->noscalars = 1 ; + else + if (strcmp(argv[i],"-nosimplify") == 0) + (*options)->nosimplify = 1 ; + else + if ((strcmp(argv[i],"-struct") == 0) || (strcmp(argv[i],"-structure") == 0)) + (*options)->structure = 1 ; + else + if ((strcmp(argv[i],"--help") == 0) || (strcmp(argv[i],"-h") == 0)) + { cloog_options_help() ; + infos = 1 ; + } + else + if ((strcmp(argv[i],"--version") == 0) || (strcmp(argv[i],"-v") == 0)) + { cloog_options_version() ; + infos = 1 ; + } else if ((strcmp(argv[i],"--quiet") == 0) || (strcmp(argv[i],"-q") == 0)) + (*options)->quiet = 1; + else + if (strcmp(argv[i],"-o") == 0) + { if (i+1 >= argc) + cloog_die("no output name for -o option.\n"); + + /* stdout is a special value, when used, we set output to standard + * output. + */ + if (strcmp(argv[i+1],"stdout") == 0) + *output = stdout ; + else + { *output = fopen(argv[i+1],"w") ; + if (*output == NULL) + cloog_die("can't create output file %s.\n", argv[i+1]); + } + i ++ ; + } + else + cloog_msg(*options, CLOOG_WARNING, "unknown %s option.\n", argv[i]); + } + else + { if (!input_is_set) + { input_is_set = 1 ; + (*options)->name = argv[i] ; + /* stdin is a special value, when used, we set input to standard input. */ + if (strcmp(argv[i],"stdin") == 0) + *input = stdin ; + else + { *input = fopen(argv[i],"r") ; + if (*input == NULL) + cloog_die("%s file does not exist.\n", argv[i]); + } + } + else + cloog_die("multiple input files.\n"); + } + if (!input_is_set) + { if (!infos) + cloog_die("no input file (-h for help).\n"); + exit(1) ; + } +} + diff --git a/cloog-core/source/pprint.c b/cloog-core/source/pprint.c new file mode 100644 index 0000000..3dacec2 --- /dev/null +++ b/cloog-core/source/pprint.c @@ -0,0 +1,423 @@ + + /**-------------------------------------------------------------------** + ** CLooG ** + **-------------------------------------------------------------------** + ** pprint.c ** + **-------------------------------------------------------------------** + ** First version: october 26th 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 ! + */ + +/* June 22nd 2005: General adaptation for GMP. + * October 26th 2005: General adaptation from CloogDomain to Matrix data + * structure for all constraint systems. + * October 27th 2005: General adaptation from CloogEqual to Matrix data + * structure for equality spreading. + */ + +# include <stdlib.h> +# include <stdio.h> +# include <string.h> +#include <assert.h> +# include "../include/cloog/cloog.h" + + +static void pprint_name(FILE *dst, struct clast_name *n); +static void pprint_term(struct cloogoptions *i, FILE *dst, struct clast_term *t); +static void pprint_sum(struct cloogoptions *opt, + FILE *dst, struct clast_reduction *r); +static void pprint_binary(struct cloogoptions *i, + FILE *dst, struct clast_binary *b); +static void pprint_minmax_f(struct cloogoptions *info, + FILE *dst, struct clast_reduction *r); +static void pprint_minmax_c(struct cloogoptions *info, + FILE *dst, struct clast_reduction *r); +static void pprint_reduction(struct cloogoptions *i, + FILE *dst, struct clast_reduction *r); +static void pprint_expr(struct cloogoptions *i, FILE *dst, struct clast_expr *e); +static void pprint_equation(struct cloogoptions *i, + FILE *dst, struct clast_equation *eq); +static void pprint_assignment(struct cloogoptions *i, FILE *dst, + struct clast_assignment *a); +static void pprint_user_stmt(struct cloogoptions *options, FILE *dst, + struct clast_user_stmt *u); +static void pprint_guard(struct cloogoptions *options, FILE *dst, int indent, + struct clast_guard *g); +static void pprint_for(struct cloogoptions *options, FILE *dst, int indent, + struct clast_for *f); +static void pprint_stmt_list(struct cloogoptions *options, FILE *dst, int indent, + struct clast_stmt *s); + + +void pprint_name(FILE *dst, struct clast_name *n) +{ + fprintf(dst, "%s", n->name); +} + +/** + * This function returns a string containing the printing of a value (possibly + * an iterator or a parameter with its coefficient or a constant). + * - val is the coefficient or constant value, + * - name is a string containing the name of the iterator or of the parameter, + */ +void pprint_term(struct cloogoptions *i, FILE *dst, struct clast_term *t) +{ + if (t->var) { + int group = t->var->type == clast_expr_red && + ((struct clast_reduction*) t->var)->n > 1; + if (cloog_int_is_one(t->val)) + ; + else if (cloog_int_is_neg_one(t->val)) + fprintf(dst, "-"); + else { + cloog_int_print(dst, t->val); + fprintf(dst, "*"); + } + if (group) + fprintf(dst, "("); + pprint_expr(i, dst, t->var); + if (group) + fprintf(dst, ")"); + } else + cloog_int_print(dst, t->val); +} + +void pprint_sum(struct cloogoptions *opt, FILE *dst, struct clast_reduction *r) +{ + int i; + struct clast_term *t; + + assert(r->n >= 1); + assert(r->elts[0]->type == clast_expr_term); + t = (struct clast_term *) r->elts[0]; + pprint_term(opt, dst, t); + + for (i = 1; i < r->n; ++i) { + assert(r->elts[i]->type == clast_expr_term); + t = (struct clast_term *) r->elts[i]; + if (cloog_int_is_pos(t->val)) + fprintf(dst, "+"); + pprint_term(opt, dst, t); + } +} + +void pprint_binary(struct cloogoptions *i, FILE *dst, struct clast_binary *b) +{ + const char *s1 = NULL, *s2 = NULL, *s3 = NULL; + int group = b->LHS->type == clast_expr_red && + ((struct clast_reduction*) b->LHS)->n > 1; + if (i->language == LANGUAGE_FORTRAN) { + switch (b->type) { + case clast_bin_fdiv: + s1 = "FLOOR(REAL(", s2 = ")/REAL(", s3 = "))"; + break; + case clast_bin_cdiv: + s1 = "CEILING(REAL(", s2 = ")/REAL(", s3 = "))"; + break; + case clast_bin_div: + if (group) + s1 = "(", s2 = ")/", s3 = ""; + else + s1 = "", s2 = "/", s3 = ""; + break; + case clast_bin_mod: + s1 = "MOD(", s2 = ", ", s3 = ")"; + break; + } + } else { + switch (b->type) { + case clast_bin_fdiv: + s1 = "floord(", s2 = ",", s3 = ")"; + break; + case clast_bin_cdiv: + s1 = "ceild(", s2 = ",", s3 = ")"; + break; + case clast_bin_div: + if (group) + s1 = "(", s2 = ")/", s3 = ""; + else + s1 = "", s2 = "/", s3 = ""; + break; + case clast_bin_mod: + if (group) + s1 = "(", s2 = ")%", s3 = ""; + else + s1 = "", s2 = "%", s3 = ""; + break; + } + } + fprintf(dst, "%s", s1); + pprint_expr(i, dst, b->LHS); + fprintf(dst, "%s", s2); + cloog_int_print(dst, b->RHS); + fprintf(dst, "%s", s3); +} + +void pprint_minmax_f(struct cloogoptions *info, FILE *dst, struct clast_reduction *r) +{ + int i; + if (r->n == 0) + return; + fprintf(dst, r->type == clast_red_max ? "MAX(" : "MIN("); + pprint_expr(info, dst, r->elts[0]); + for (i = 1; i < r->n; ++i) { + fprintf(dst, ","); + pprint_expr(info, dst, r->elts[i]); + } + fprintf(dst, ")"); +} + +void pprint_minmax_c(struct cloogoptions *info, FILE *dst, struct clast_reduction *r) +{ + int i; + for (i = 1; i < r->n; ++i) + fprintf(dst, r->type == clast_red_max ? "max(" : "min("); + if (r->n > 0) + pprint_expr(info, dst, r->elts[0]); + for (i = 1; i < r->n; ++i) { + fprintf(dst, ","); + pprint_expr(info, dst, r->elts[i]); + fprintf(dst, ")"); + } +} + +void pprint_reduction(struct cloogoptions *i, FILE *dst, struct clast_reduction *r) +{ + switch (r->type) { + case clast_red_sum: + pprint_sum(i, dst, r); + break; + case clast_red_min: + case clast_red_max: + if (r->n == 1) { + pprint_expr(i, dst, r->elts[0]); + break; + } + if (i->language == LANGUAGE_FORTRAN) + pprint_minmax_f(i, dst, r); + else + pprint_minmax_c(i, dst, r); + break; + default: + assert(0); + } +} + +void pprint_expr(struct cloogoptions *i, FILE *dst, struct clast_expr *e) +{ + if (!e) + return; + switch (e->type) { + case clast_expr_name: + pprint_name(dst, (struct clast_name*) e); + break; + case clast_expr_term: + pprint_term(i, dst, (struct clast_term*) e); + break; + case clast_expr_red: + pprint_reduction(i, dst, (struct clast_reduction*) e); + break; + case clast_expr_bin: + pprint_binary(i, dst, (struct clast_binary*) e); + break; + default: + assert(0); + } +} + +void pprint_equation(struct cloogoptions *i, FILE *dst, struct clast_equation *eq) +{ + pprint_expr(i, dst, eq->LHS); + if (eq->sign == 0) + fprintf(dst, " == "); + else if (eq->sign > 0) + fprintf(dst, " >= "); + else + fprintf(dst, " <= "); + pprint_expr(i, dst, eq->RHS); +} + +void pprint_assignment(struct cloogoptions *i, FILE *dst, + struct clast_assignment *a) +{ + if (a->LHS) + fprintf(dst, "%s = ", a->LHS); + pprint_expr(i, dst, a->RHS); +} + +void pprint_user_stmt(struct cloogoptions *options, FILE *dst, + struct clast_user_stmt *u) +{ + struct clast_stmt *t; + if (u->statement->name) + fprintf(dst, "%s", u->statement->name); + else + fprintf(dst, "S%d", u->statement->number); + fprintf(dst, "("); + for (t = u->substitutions; t; t = t->next) { + assert(CLAST_STMT_IS_A(t, stmt_ass)); + pprint_assignment(options, dst, (struct clast_assignment *)t); + if (t->next) + fprintf(dst, ","); + } + fprintf(dst, ")"); + if (options->language != LANGUAGE_FORTRAN) + fprintf(dst, ";"); + fprintf(dst, "\n"); +} + +void pprint_guard(struct cloogoptions *options, FILE *dst, int indent, + struct clast_guard *g) +{ + int k; + if (options->language == LANGUAGE_FORTRAN) + fprintf(dst,"IF "); + else + fprintf(dst,"if "); + if (g->n > 1) + fprintf(dst,"("); + for (k = 0; k < g->n; ++k) { + if (k > 0) { + if (options->language == LANGUAGE_FORTRAN) + fprintf(dst," .AND. "); + else + fprintf(dst," && "); + } + fprintf(dst,"("); + pprint_equation(options, dst, &g->eq[k]); + fprintf(dst,")"); + } + if (g->n > 1) + fprintf(dst,")"); + if (options->language == LANGUAGE_FORTRAN) + fprintf(dst," THEN\n"); + else + fprintf(dst," {\n"); + + pprint_stmt_list(options, dst, indent + INDENT_STEP, g->then); + + fprintf(dst, "%*s", indent, ""); + if (options->language == LANGUAGE_FORTRAN) + fprintf(dst,"END IF\n"); + else + fprintf(dst,"}\n"); +} + +void pprint_for(struct cloogoptions *options, FILE *dst, int indent, + struct clast_for *f) +{ + if (options->language == LANGUAGE_FORTRAN) + fprintf(dst, "DO "); + else + fprintf(dst, "for ("); + + if (f->LB) { + fprintf(dst, "%s=", f->iterator); + pprint_expr(options, dst, f->LB); + } else if (options->language == LANGUAGE_FORTRAN) + cloog_die("unbounded loops not allowed in FORTRAN.\n"); + + if (options->language == LANGUAGE_FORTRAN) + fprintf(dst,", "); + else + fprintf(dst,";"); + + if (f->UB) { + if (options->language != LANGUAGE_FORTRAN) + fprintf(dst,"%s<=", f->iterator); + pprint_expr(options, dst, f->UB); + } else if (options->language == LANGUAGE_FORTRAN) + cloog_die("unbounded loops not allowed in FORTRAN.\n"); + + if (options->language == LANGUAGE_FORTRAN) { + if (cloog_int_gt_si(f->stride, 1)) + cloog_int_print(dst, f->stride); + fprintf(dst,"\n"); + } + else { + if (cloog_int_gt_si(f->stride, 1)) { + fprintf(dst,";%s+=", f->iterator); + cloog_int_print(dst, f->stride); + fprintf(dst, ") {\n"); + } else + fprintf(dst, ";%s++) {\n", f->iterator); + } + + pprint_stmt_list(options, dst, indent + INDENT_STEP, f->body); + + fprintf(dst, "%*s", indent, ""); + if (options->language == LANGUAGE_FORTRAN) + fprintf(dst,"END DO\n") ; + else + fprintf(dst,"}\n") ; +} + +void pprint_stmt_list(struct cloogoptions *options, FILE *dst, int indent, + struct clast_stmt *s) +{ + for ( ; s; s = s->next) { + if (CLAST_STMT_IS_A(s, stmt_root)) + continue; + fprintf(dst, "%*s", indent, ""); + if (CLAST_STMT_IS_A(s, stmt_ass)) { + pprint_assignment(options, dst, (struct clast_assignment *) s); + if (options->language != LANGUAGE_FORTRAN) + fprintf(dst, ";"); + fprintf(dst, "\n"); + } else if (CLAST_STMT_IS_A(s, stmt_user)) { + pprint_user_stmt(options, dst, (struct clast_user_stmt *) s); + } else if (CLAST_STMT_IS_A(s, stmt_for)) { + pprint_for(options, dst, indent, (struct clast_for *) s); + } else if (CLAST_STMT_IS_A(s, stmt_guard)) { + pprint_guard(options, dst, indent, (struct clast_guard *) s); + } else if (CLAST_STMT_IS_A(s, stmt_block)) { + fprintf(dst, "{\n"); + pprint_stmt_list(options, dst, indent + INDENT_STEP, + ((struct clast_block *)s)->body); + fprintf(dst, "%*s", indent, ""); + fprintf(dst, "}\n"); + } else { + assert(0); + } + } +} + + +/****************************************************************************** + * Pretty Printing (dirty) functions * + ******************************************************************************/ + +void clast_pprint(FILE *foo, struct clast_stmt *root, + int indent, CloogOptions *options) +{ + pprint_stmt_list(options, foo, indent, root); +} diff --git a/cloog-core/source/program.c b/cloog-core/source/program.c new file mode 100644 index 0000000..e5aa4fc --- /dev/null +++ b/cloog-core/source/program.c @@ -0,0 +1,1077 @@ + + /**-------------------------------------------------------------------** + ** 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 <sys/types.h> +# include <sys/time.h> +#include <stdarg.h> +# include <stdlib.h> +# include <stdio.h> +# include <string.h> +# include <ctype.h> +# include <unistd.h> +# include "../include/cloog/cloog.h" +#ifdef CLOOG_RUSAGE +# include <sys/resource.h> +#endif + +#define ALLOC(type) (type*)malloc(sizeof(type)) + + +/****************************************************************************** + * 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; i<level; i++) + fprintf(file,"|\t") ; + + fprintf(file,"+-- CloogProgram\n") ; + + /* A blank line. */ + for (i=0; i<=level+1; i++) + fprintf(file,"|\t") ; + fprintf(file,"\n") ; + + /* Print the language. */ + for (i=0; i<=level; i++) + fprintf(file,"|\t") ; + fprintf(file, "Language: %c\n",program->language) ; + + /* 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;i<program->nb_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;i<program->names->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;i<program->names->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 == 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_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, nb_scattering, indentation=0 ; + CloogStatement * statement ; + CloogBlockList * blocklist ; + CloogBlock * block ; + struct clast_stmt *root; + + if (program->language == 'f') + options->language = LANGUAGE_FORTRAN ; + else + options->language = 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. + */ + nb_scattering = program->nb_scattdims ; + 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 <stdio.h>\n") ; + fprintf(file,"#include <stdlib.h>\n") ; + fprintf(file,"#include <math.h>\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;j<block->depth;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;j<block->depth;j++) + fprintf(file, " %%d"); + + fprintf(file,"\\n\",%s",program->names->iterators[0]) ; + for(j=1;j<block->depth;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 == 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;i<p->nb_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;i<program->nb_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;i<nb_scaldims;i++) + cloog_int_init(block->scaldims[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;i<program->nb_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) ; + } +} diff --git a/cloog-core/source/state.c b/cloog-core/source/state.c new file mode 100644 index 0000000..7f3fff8 --- /dev/null +++ b/cloog-core/source/state.c @@ -0,0 +1,52 @@ +#include <stdlib.h> +#include "../include/cloog/cloog.h" + +/** + * Allocate state and initialize backend independent part. + */ +CloogState *cloog_core_state_malloc(void) +{ + CloogState *state; + + state = (CloogState *)malloc(sizeof(CloogState)); + if (!state) + cloog_die("memory overflow.\n"); + + state->backend = NULL; + + cloog_int_init(state->zero); + cloog_int_set_si(state->zero, 0); + cloog_int_init(state->one); + cloog_int_set_si(state->one, 1); + cloog_int_init(state->negone); + cloog_int_set_si(state->negone, -1); + + state->block_allocated = 0; + state->block_freed = 0; + state->block_max = 0; + + state->domain_allocated = 0; + state->domain_freed = 0; + state->domain_max = 0; + + state->loop_allocated = 0; + state->loop_freed = 0; + state->loop_max = 0; + + state->statement_allocated = 0; + state->statement_freed = 0; + state->statement_max = 0; + + return state; +} + +/** + * Free state. + */ +void cloog_core_state_free(CloogState *state) +{ + cloog_int_clear(state->zero); + cloog_int_clear(state->one); + cloog_int_clear(state->negone); + free(state); +} diff --git a/cloog-core/source/statement.c b/cloog-core/source/statement.c new file mode 100644 index 0000000..1c6af4e --- /dev/null +++ b/cloog-core/source/statement.c @@ -0,0 +1,280 @@ + + /**-------------------------------------------------------------------** + ** CLooG ** + **-------------------------------------------------------------------** + ** statement.c ** + **-------------------------------------------------------------------** + ** First version: november 4th 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 <stdlib.h> +# include <stdio.h> +# include <string.h> +# include "../include/cloog/cloog.h" + + +/****************************************************************************** + * Memory leaks hunting * + ******************************************************************************/ + + +/** + * These functions and global variables are devoted to memory leaks hunting: we + * want to know at each moment how many CloogStatement structures had been + * allocated (cloog_statement_allocated) and how many had been freed + * (cloog_statement_freed). Each time a CloogStatement structure is allocated, + * a call to the function cloog_statement_leak_up() must be carried out, and + * respectively cloog_statement_leak_down() when a CloogStatement structure is + * freed. The special variable cloog_statement_max gives the maximal number of + * CloogStatement structures simultaneously alive (i.e. allocated and + * non-freed) in memory. + * - July 3rd->11th 2003: first version (memory leaks hunt and correction). + */ + + +static void cloog_statement_leak_up(CloogState *state) +{ + state->statement_allocated++; + if ((state->statement_allocated - state->statement_freed) > state->statement_max) + state->statement_max = state->statement_allocated - state->statement_freed ; +} + + +static void cloog_statement_leak_down(CloogState *state) +{ + state->statement_freed++; +} + + +/****************************************************************************** + * Structure display function * + ******************************************************************************/ + + +/** + * cloog_domain_print_structure : + * this function is a human-friendly way to display the CloogDomain data + * structure, it includes an indentation level (level) in order to work with + * others print_structure functions. + * - June 16th 2005: first version. + */ +void cloog_statement_print_structure(file, statement, level) +FILE * file ; +CloogStatement * statement ; +int level ; +{ int i ; + + if (statement != NULL) + { /* Go to the right level. */ + for (i=0; i<level; i++) + fprintf(file,"|\t") ; + fprintf(file,"+-- CloogStatement %d \n",statement->number) ; + + statement = statement->next ; + + while (statement != NULL) + { for (i=0; i<level; i++) + fprintf(file,"|\t") ; + fprintf(file,"| |\n"); + for (i=0; i<level; i++) + fprintf(file,"|\t") ; + fprintf(file,"| V\n"); + + for (i=0; i<level; i++) + fprintf(file,"|\t") ; + fprintf(file,"| CloogStatement %d \n",statement->number) ; + statement = statement->next ; + } + } + else + { for (i=0; i<level; i++) + fprintf(file,"|\t") ; + + fprintf(file,"+-- No CloogStatement\n") ; + } +} + + +/** + * cloog_statement_print function: + * This function prints the content of a CloogStatement structure (statement) + * into a file (file, possibly stdout). + */ +void cloog_statement_print(FILE * file, CloogStatement * statement) +{ cloog_statement_print_structure(file,statement,0) ; +} + + +/****************************************************************************** + * Memory deallocation function * + ******************************************************************************/ + + +/** + * cloog_statement_free function: + * This function frees the allocated memory for a CloogStatement structure. + */ +void cloog_statement_free(CloogStatement * statement) +{ CloogStatement * next ; + + while (statement != NULL) { + cloog_statement_leak_down(statement->state); + + next = statement->next ; + /* free(statement->usr) ; Actually, this is user's job ! */ + free(statement->name); + free(statement) ; + statement = next ; + } +} + + +/****************************************************************************** + * Processing functions * + ******************************************************************************/ + + +/** + * cloog_statement_malloc function: + * This function allocates the memory space for a CloogStatement structure and + * sets its fields with default values. Then it returns a pointer to the + * allocated space. + * - November 21th 2005: first version. + */ +CloogStatement *cloog_statement_malloc(CloogState *state) +{ CloogStatement * statement ; + + /* Memory allocation for the CloogStatement structure. */ + statement = (CloogStatement *)malloc(sizeof(CloogStatement)) ; + if (statement == NULL) + cloog_die("memory overflow.\n"); + cloog_statement_leak_up(state); + + /* We set the various fields with default values. */ + statement->state = state; + statement->number = 0; + statement->name = NULL; + statement->usr = NULL ; /* To fill it is actually user's job ! */ + statement->next = NULL ; + + return statement ; +} + + +/** + * cloog_statement_alloc function: + * This function allocates the memory space for a CloogStatement structure and + * sets its fields with those given as input. Then it returns a pointer to the + * allocated space. + * - number is the statement number. + ** + * - September 9th 2002: first version. + * - March 17th 2003: fix for the usr field in CloogStatement structure. + * - April 16th 2005: adaptation to new CloogStatement structure (with + * number), cloog_statement_read becomes + * cloog_statement_alloc sincethere is nothing more to + * read on a file. + * - November 21th 2005: use of cloog_statement_malloc. + */ +CloogStatement *cloog_statement_alloc(CloogState *state, int number) +{ CloogStatement * statement ; + + /* Memory allocation and initialization of the structure. */ + statement = cloog_statement_malloc(state); + + statement->number = number ; + + return statement ; +} + + +/** + * cloog_statement_copy function: + * This function returns a copy of the CloogStatement structure given as input. + * - October 28th 2001: first version (in loop.c). + * - March 17th 2003: fix for the usr field in CloogStatement structure. + * - April 16th 2005: adaptation to new CloogStatement struct (with number). + */ +CloogStatement * cloog_statement_copy(CloogStatement * source) +{ CloogStatement * statement, * temp, * now = NULL ; + + statement = NULL ; + + while (source != NULL) { + cloog_statement_leak_up(source->state); + + temp = (CloogStatement *)malloc(sizeof(CloogStatement)) ; + if (temp == NULL) + cloog_die("memory overflow.\n"); + + temp->state = source->state; + temp->number = source->number ; + temp->name = source->name ? strdup(source->name) : NULL; + temp->usr = source->usr ; + temp->next = NULL ; + + if (statement == NULL) + { statement = temp ; + now = statement ; + } + else + { now->next = temp ; + now = now->next ; + } + source = source->next ; + } + return(statement) ; +} + + +/** + * cloog_statement_add function: + * This function adds a CloogStatement structure (statement) at a given place + * (now) of a NULL terminated list of CloogStatement structures. The beginning + * of this list is (start). This function updates (now) to (loop), and + * updates (start) if the added element is the first one -that is when (start) + * is NULL-. + * - March 27th 2004: first version. + */ +void cloog_statement_add(start, now, statement) +CloogStatement ** start, ** now, * statement ; +{ if (*start == NULL) + { *start = statement ; + *now = *start ; + } + else + { (*now)->next = statement ; + *now = (*now)->next ; + } +} + diff --git a/cloog-core/source/stride.c b/cloog-core/source/stride.c new file mode 100644 index 0000000..d7358a0 --- /dev/null +++ b/cloog-core/source/stride.c @@ -0,0 +1,70 @@ +#include <stdlib.h> +#include <cloog/cloog.h> + +#define ALLOC(type) (type*)malloc(sizeof(type)) + +CloogStride *cloog_stride_malloc() +{ + CloogStride *s; + + s = ALLOC(CloogStride); + if (!s) + cloog_die("memory overflow.\n"); + + s->references = 1; + cloog_int_init(s->stride); + cloog_int_init(s->offset); + cloog_int_init(s->factor); + s->constraint = cloog_constraint_invalid(); + + return s; +} + +CloogStride *cloog_stride_alloc(cloog_int_t stride, cloog_int_t offset) +{ + CloogStride *s = cloog_stride_malloc(); + + cloog_int_set(s->stride, stride); + cloog_int_set(s->offset, offset); + cloog_int_set_si(s->factor, 0); + + return s; +} + +CloogStride *cloog_stride_alloc_from_constraint(cloog_int_t stride, + CloogConstraint *constraint, cloog_int_t factor) +{ + CloogStride *s = cloog_stride_malloc(); + + cloog_int_set(s->stride, stride); + cloog_int_set(s->factor, factor); + cloog_int_set_si(s->offset, -1); + s->constraint = constraint; + + return s; +} + +CloogStride *cloog_stride_copy(CloogStride *stride) +{ + if (!stride) + return stride; + + stride->references++; + return stride; +} + +void cloog_stride_free(CloogStride *stride) +{ + if (!stride) + return; + + stride->references--; + if (stride->references > 0) + return; + + cloog_int_clear(stride->stride); + cloog_int_clear(stride->offset); + cloog_int_clear(stride->factor); + cloog_constraint_release(stride->constraint); + free(stride); +} diff --git a/cloog-core/source/union_domain.c b/cloog-core/source/union_domain.c new file mode 100644 index 0000000..32b0087 --- /dev/null +++ b/cloog-core/source/union_domain.c @@ -0,0 +1,298 @@ +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include "../include/cloog/cloog.h" + +#define ALLOC(type) (type*)malloc(sizeof(type)) +#define ALLOCN(type,n) (type*)malloc((n)*sizeof(type)) + +void cloog_named_domain_list_free(CloogNamedDomainList *list) +{ + while (list != NULL) { + CloogNamedDomainList *temp = list->next; + cloog_domain_free(list->domain); + cloog_scattering_free(list->scattering); + free(list->name); + free(list); + list = temp; + } +} + +CloogUnionDomain *cloog_union_domain_alloc(int nb_par) +{ + CloogUnionDomain *ud; + + ud = ALLOC(CloogUnionDomain); + if (!ud) + cloog_die("memory overflow.\n"); + + ud->domain = NULL; + ud->next_domain = &ud->domain; + + ud->n_name[CLOOG_PARAM] = nb_par; + ud->n_name[CLOOG_ITER] = 0; + ud->n_name[CLOOG_SCAT] = 0; + + ud->name[CLOOG_PARAM] = NULL; + ud->name[CLOOG_ITER] = NULL; + ud->name[CLOOG_SCAT] = NULL; + + return ud; +} + +void cloog_union_domain_free(CloogUnionDomain *ud) +{ + int i; + int j; + + if (!ud) + return; + + for (i = 0; i < 3; ++i) { + if (!ud->name[i]) + continue; + for (j = 0; j < ud->n_name[i]; ++i) + free(ud->name[i][j]); + free(ud->name[i]); + } + + cloog_named_domain_list_free(ud->domain); + + free(ud); +} + +/** + * Add a domain with scattering function to the union of domains. + * name may be NULL and is duplicated if it is not. + * domain and scattering are taken over by the CloogUnionDomain. + * scattering may be NULL. + */ +CloogUnionDomain *cloog_union_domain_add_domain(CloogUnionDomain *ud, + const char *name, CloogDomain *domain, CloogScattering *scattering, + void *usr) +{ + CloogNamedDomainList *named; + int n; + + if (!ud) + return NULL; + + named = ALLOC(CloogNamedDomainList); + if (!named) + cloog_die("memory overflow.\n"); + + if (ud->name[CLOOG_ITER]) + cloog_die("iterator names must be set after adding domains.\n"); + if (ud->name[CLOOG_SCAT]) + cloog_die("scattering names must be set after adding domains.\n"); + + n = cloog_domain_dimension(domain); + if (n > ud->n_name[CLOOG_ITER]) + ud->n_name[CLOOG_ITER] = n; + + if (scattering) { + n = cloog_scattering_dimension(scattering, domain); + if (n > ud->n_name[CLOOG_SCAT]) + ud->n_name[CLOOG_SCAT] = n; + } + + named->domain = domain; + named->scattering = scattering; + named->name = name ? strdup(name) : NULL; + named->usr = usr; + named->next = NULL; + + *ud->next_domain = named; + ud->next_domain = &named->next; + + return ud; +} + +/** + * Set the name of parameter, iterator or scattering dimension + * at the specified position. The name is duplicated. + */ +CloogUnionDomain *cloog_union_domain_set_name(CloogUnionDomain *ud, + enum cloog_dim_type type, int index, const char *name) +{ + int i; + + if (!ud) + return ud; + + if (type != CLOOG_PARAM && + type != CLOOG_ITER && + type != CLOOG_SCAT) + cloog_die("invalid dim type\n"); + + if (index < 0 || index >= ud->n_name[type]) + cloog_die("index out of range\n"); + + if (!ud->name[type]) { + ud->name[type] = ALLOCN(char *, ud->n_name[type]); + if (!ud->name[type]) + cloog_die("memory overflow.\n"); + for (i = 0; i < ud->n_name[type]; ++i) + ud->name[type][i] = NULL; + } + + free(ud->name[type][index]); + ud->name[type][index] = strdup(name); + if (!ud->name[type][index]) + cloog_die("memory overflow.\n"); + + return ud; +} + +static char *next_line(FILE *input, char *line, unsigned len) +{ + char *p; + + do { + if (!(p = fgets(line, len, input))) + return NULL; + while (isspace(*p) && *p != '\n') + ++p; + } while (*p == '#' || *p == '\n'); + + return p; +} + +/** + * cloog_scattering_list_read + * Read in a list of scattering functions for the nb_statements + * domains in loop. + */ +static CloogScatteringList *cloog_scattering_list_read(FILE * foo, + CloogDomain **domain, int nb_statements, int nb_parameters) +{ + int nb_scat = 0; + char s[MAX_STRING]; + CloogScatteringList *list = NULL, **next = &list; + + /* We read first the number of scattering functions in the list. */ + do { + if (!fgets(s, MAX_STRING, foo)) + break; + } while ((*s=='#' || *s=='\n') || (sscanf(s, " %d", &nb_scat) < 1)); + + if (nb_scat == 0) + return NULL; + + if (nb_scat != nb_statements) + cloog_die("wrong number of scattering functions.\n"); + + while (nb_scat--) { + *next = (CloogScatteringList *)malloc(sizeof(CloogScatteringList)); + (*next)->scatt = cloog_domain_read_scattering(*domain, foo); + (*next)->next = NULL; + + next = &(*next)->next; + domain++; + } + return list; +} + +static CloogUnionDomain *set_names_from_list(CloogUnionDomain *ud, + enum cloog_dim_type type, int n, char **names) +{ + int i; + + if (!names) + return ud; + + for (i = 0; i < n; ++i) { + ud = cloog_union_domain_set_name(ud, type, i, names[i]); + free(names[i]); + } + free(names); + + return ud; +} + +/** + * Fill up a CloogUnionDomain from information in a CLooG input file. + * The language and the context are assumed to have been read from + * the input file already. + */ +CloogUnionDomain *cloog_union_domain_read(FILE *file, int nb_par, + CloogOptions *options) +{ + int op1, op2, op3; + char line[MAX_STRING]; + CloogDomain **domain; + CloogUnionDomain *ud; + CloogScatteringList *scatteringl; + int i; + int n_iter = -1; + int n_dom; + char **names; + + ud = cloog_union_domain_alloc(nb_par); + + names = cloog_names_read_strings(file, nb_par); + ud = set_names_from_list(ud, CLOOG_PARAM, nb_par, names); + + /* We read the number of statements. */ + if (!next_line(file, line, sizeof(line))) + cloog_die("Input error.\n"); + if (sscanf(line, "%d", &n_dom) != 1) + cloog_die("Input error.\n"); + + domain = ALLOCN(CloogDomain *, n_dom); + if (!domain) + cloog_die("memory overflow.\n"); + + for (i = 0; i < n_dom; ++i) { + int dim; + + domain[i] = cloog_domain_union_read(options->state, file, + nb_par); + dim = cloog_domain_dimension(domain[i]); + if (dim > n_iter) + n_iter = dim; + + /* To read that stupid "0 0 0" line. */ + if (!next_line(file, line, sizeof(line))) + cloog_die("Input error.\n"); + if (sscanf(line, " %d %d %d", &op1, &op2, &op3) != 3) + cloog_die("Input error.\n"); + } + + /* Reading of the iterator names. */ + names = cloog_names_read_strings(file, n_iter); + + /* Reading and putting the scattering data in program structure. */ + scatteringl = cloog_scattering_list_read(file, domain, n_dom, nb_par); + + if (scatteringl) { + CloogScatteringList *is, *next; + + if (cloog_scattering_list_lazy_same(scatteringl)) + cloog_msg(options, CLOOG_WARNING, + "some scattering functions are similar.\n"); + + for (i = 0, is = scatteringl; i < n_dom; ++i, is = next) { + next = is->next; + ud = cloog_union_domain_add_domain(ud, NULL, domain[i], + is->scatt, NULL); + free(is); + } + } else { + for (i = 0; i < n_dom; ++i) + ud = cloog_union_domain_add_domain(ud, NULL, domain[i], + NULL, NULL); + } + + ud = set_names_from_list(ud, CLOOG_ITER, n_iter, names); + + if (scatteringl) { + int n_scat = ud->n_name[CLOOG_SCAT]; + names = cloog_names_read_strings(file, n_scat); + ud = set_names_from_list(ud, CLOOG_SCAT, n_scat, names); + } + + free(domain); + + return ud; +} diff --git a/cloog-core/source/version.c b/cloog-core/source/version.c new file mode 100644 index 0000000..f1b86e2 --- /dev/null +++ b/cloog-core/source/version.c @@ -0,0 +1,24 @@ +#include "version.h" +#include "cloog/version.h" + +#define CLOOG_BITS "gmp" + +const char *cloog_version(void) +{ + return "CLooG "CLOOG_HEAD" "CLOOG_BITS" bits"; +} + +int cloog_version_major(void) +{ + return CLOOG_VERSION_MAJOR; +} + +int cloog_version_minor(void) +{ + return CLOOG_VERSION_MINOR; +} + +int cloog_version_revision(void) +{ + return CLOOG_VERSION_REVISION; +} diff --git a/cloog-core/source/version.c.in b/cloog-core/source/version.c.in new file mode 100644 index 0000000..f5d026e --- /dev/null +++ b/cloog-core/source/version.c.in @@ -0,0 +1,24 @@ +#include "version.h" +#include "cloog/version.h" + +#define CLOOG_BITS "@BITS@" + +const char *cloog_version(void) +{ + return "CLooG "CLOOG_HEAD" "CLOOG_BITS" bits"; +} + +int cloog_version_major(void) +{ + return CLOOG_VERSION_MAJOR; +} + +int cloog_version_minor(void) +{ + return CLOOG_VERSION_MINOR; +} + +int cloog_version_revision(void) +{ + return CLOOG_VERSION_REVISION; +} |