summaryrefslogtreecommitdiff
path: root/cloog-core/source
diff options
context:
space:
mode:
Diffstat (limited to 'cloog-core/source')
-rw-r--r--cloog-core/source/block.c404
-rw-r--r--cloog-core/source/clast.c1857
-rw-r--r--cloog-core/source/cloog.c98
-rw-r--r--cloog-core/source/input.c177
-rw-r--r--cloog-core/source/int.c177
-rw-r--r--cloog-core/source/isl/backend.c37
-rw-r--r--cloog-core/source/isl/constraints.c804
-rw-r--r--cloog-core/source/isl/domain.c1669
-rw-r--r--cloog-core/source/loop.c2483
-rw-r--r--cloog-core/source/matrix.c213
-rw-r--r--cloog-core/source/matrix/constraintset.c1049
-rw-r--r--cloog-core/source/mp_get_memory_functions.c14
-rw-r--r--cloog-core/source/names.c528
-rw-r--r--cloog-core/source/options.c461
-rw-r--r--cloog-core/source/pprint.c423
-rw-r--r--cloog-core/source/program.c1077
-rw-r--r--cloog-core/source/state.c52
-rw-r--r--cloog-core/source/statement.c280
-rw-r--r--cloog-core/source/stride.c70
-rw-r--r--cloog-core/source/union_domain.c298
-rw-r--r--cloog-core/source/version.c24
-rw-r--r--cloog-core/source/version.c.in24
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;
+}