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