summaryrefslogtreecommitdiff
path: root/cloog-core/source/loop.c
diff options
context:
space:
mode:
Diffstat (limited to 'cloog-core/source/loop.c')
-rw-r--r--cloog-core/source/loop.c2483
1 files changed, 2483 insertions, 0 deletions
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);
+}
+