summaryrefslogtreecommitdiff
path: root/omega/code_gen/src/output_repr.cc
diff options
context:
space:
mode:
Diffstat (limited to 'omega/code_gen/src/output_repr.cc')
-rw-r--r--omega/code_gen/src/output_repr.cc1931
1 files changed, 1931 insertions, 0 deletions
diff --git a/omega/code_gen/src/output_repr.cc b/omega/code_gen/src/output_repr.cc
new file mode 100644
index 0000000..955cc14
--- /dev/null
+++ b/omega/code_gen/src/output_repr.cc
@@ -0,0 +1,1931 @@
+/*****************************************************************************
+ Copyright (C) 1994-2000 University of Maryland
+ Copyright (C) 2008 University of Southern California
+ Copyright (C) 2009-2010 University of Utah
+ All Rights Reserved.
+
+ Purpose:
+ utility functions for outputing CG_outputReprs
+
+ Notes:
+
+ History:
+ 07/30/10 collect various code outputing into one place, by Chun Chen
+*****************************************************************************/
+
+#include <omega.h>
+#include <code_gen/CG_stringBuilder.h>
+#include <code_gen/output_repr.h>
+#include <basic/omega_error.h>
+#include <math.h>
+#include <stack>
+#include <typeinfo>
+
+namespace omega {
+
+extern Tuple<Tuple<Relation> > projected_nIS;
+int var_substitution_threshold = 100;
+//protonu.
+extern int upperBoundForLevel;
+extern int lowerBoundForLevel;
+extern bool fillInBounds;
+//end--protonu.
+
+}
+
+
+namespace omega {
+
+std::pair<EQ_Handle, int> find_simplest_assignment(const Relation &R_, Variable_ID v, const std::vector<CG_outputRepr *> &assigned_on_the_fly);
+
+
+namespace {
+
+
+
+
+void get_stride(const Constraint_Handle &h, Variable_ID &wc, coef_t &step){
+ wc = 0;
+ for(Constr_Vars_Iter i(h,true); i; i++) {
+ assert(wc == 0);
+ wc = (*i).var;
+ step = ((*i).coef);
+ }
+}
+
+}
+
+CG_outputRepr* outputIdent(CG_outputBuilder* ocg, const Relation &R_, Variable_ID v, const std::vector<CG_outputRepr *> &assigned_on_the_fly) {
+ Relation &R = const_cast<Relation &>(R_);
+
+ switch (v->kind()) {
+ case Set_Var: {
+ int pos = v->get_position();
+ if (assigned_on_the_fly[pos-1] != NULL)
+ return assigned_on_the_fly[pos-1]->clone();
+ else
+ return ocg->CreateIdent(v->name());
+ break;
+ }
+ case Global_Var: {
+ if (v->get_global_var()->arity() == 0)
+ return ocg->CreateIdent(v->name());
+ else {
+ /* This should be improved to take into account the possible elimination
+ of the set variables. */
+ int arity = v->get_global_var()->arity();
+ //assert(arity <= last_level);
+ Tuple<CG_outputRepr *> argList;
+ // Relation R = Relation::True(arity);
+
+ // name_codegen_vars(R); // easy way to make sure the names are correct.
+ for(int i = 1; i <= arity; i++)
+ argList.append(ocg->CreateIdent(R.set_var(i)->name()));
+ CG_outputRepr *call = ocg->CreateInvoke(v->get_global_var()->base_name(), argList);
+ return call;
+ }
+ break;
+ }
+ default:
+ throw std::invalid_argument("wrong variable type");
+ }
+}
+
+
+//----------------------------------------------------------------------------
+// Translate equality constraints to if-condition and assignment.
+// return.first is right-hand-side of assignment, return.second
+// is true if assignment is required.
+// -- by chun 07/29/2010
+// ----------------------------------------------------------------------------
+std::pair<CG_outputRepr *, bool> outputAssignment(CG_outputBuilder *ocg, const Relation &R_, Variable_ID v, Relation &enforced, CG_outputRepr *&if_repr, const std::vector<CG_outputRepr *> &assigned_on_the_fly) {
+ Relation &R = const_cast<Relation &>(R_);
+
+ Conjunct *c = R.query_DNF()->single_conjunct();
+
+ // check whether to generate if-conditions from equality constraints
+ for (EQ_Iterator ei(c); ei; ei++)
+ if (!(*ei).has_wildcards() && abs((*ei).get_coef(v)) > 1) {
+ Relation r(R.n_set());
+ F_And *f_super_root = r.add_and();
+ F_Exists *fe = f_super_root->add_exists();
+ Variable_ID e = fe->declare();
+ F_And *f_root = fe->add_and();
+ EQ_Handle h = f_root->add_EQ();
+ for (Constr_Vars_Iter cvi(*ei); cvi; cvi++)
+ switch ((*cvi).var->kind()) {
+ case Input_Var: {
+ if ((*cvi).var == v)
+ h.update_coef(e, (*cvi).coef);
+ else
+ h.update_coef(r.set_var((*cvi).var->get_position()), (*cvi).coef);
+ break;
+ }
+ case Global_Var: {
+ Global_Var_ID g = (*cvi).var->get_global_var();
+ Variable_ID v2;
+ if (g->arity() == 0)
+ v2 = r.get_local(g);
+ else
+ v2 = r.get_local(g, (*cvi).var->function_of());
+ h.update_coef(v2, (*cvi).coef);
+ break;
+ }
+ default:
+ assert(0);
+ }
+ h.update_const((*ei).get_const());
+
+ r.copy_names(R);
+ r.setup_names();
+
+ // need if-condition to make sure this loop variable has integer value
+ if (!Gist(r, copy(enforced), 1).is_obvious_tautology()) {
+ coef_t coef = (*ei).get_coef(v);
+ coef_t sign = -((coef>0)?1:-1);
+ coef = abs(coef);
+
+ CG_outputRepr *term = NULL;
+ for (Constr_Vars_Iter cvi(*ei); cvi; cvi++)
+ if ((*cvi).var != v) {
+ CG_outputRepr *varRepr = outputIdent(ocg, R, (*cvi).var, assigned_on_the_fly);
+ coef_t t = sign*(*cvi).coef;
+ if (t == 1)
+ term = ocg->CreatePlus(term, varRepr);
+ else if (t == -1)
+ term = ocg->CreateMinus(term, varRepr);
+ else if (t > 0)
+ term = ocg->CreatePlus(term, ocg->CreateTimes(ocg->CreateInt(t), varRepr));
+ else if (t < 0)
+ term = ocg->CreateMinus(term, ocg->CreateTimes(ocg->CreateInt(-t), varRepr));
+ }
+ coef_t t = sign*(*ei).get_const();
+ if (t > 0)
+ term = ocg->CreatePlus(term, ocg->CreateInt(t));
+ else if (t < 0)
+ term = ocg->CreateMinus(term, ocg->CreateInt(-t));
+
+ term = ocg->CreateIntegerMod(term, ocg->CreateInt(coef));
+ term = ocg->CreateEQ(term, ocg->CreateInt(0));
+
+ if_repr = ocg->CreateAnd(if_repr, term);
+ }
+
+ enforced.and_with_EQ(*ei);
+ enforced.simplify();
+ }
+
+ // find the simplest assignment
+ std::pair<EQ_Handle, int> a = find_simplest_assignment(R, v, assigned_on_the_fly);
+
+ // now generate assignment
+ if (a.second < INT_MAX) {
+ EQ_Handle eq = a.first;
+ CG_outputRepr *rop_repr = NULL;
+
+ coef_t divider = eq.get_coef(v);
+ int sign = 1;
+ if (divider < 0) {
+ divider = -divider;
+ sign = -1;
+ }
+
+ for (Constr_Vars_Iter cvi(eq); cvi; cvi++)
+ if ((*cvi).var != v) {
+ CG_outputRepr *var_repr = outputIdent(ocg, R, (*cvi).var, assigned_on_the_fly);
+ coef_t coef = (*cvi).coef;
+ if (-sign * coef == -1)
+ rop_repr = ocg->CreateMinus(rop_repr, var_repr);
+ else if (-sign * coef < -1)
+ rop_repr = ocg->CreateMinus(rop_repr, ocg->CreateTimes(ocg->CreateInt(sign * coef), var_repr));
+ else if (-sign * coef == 1)
+ rop_repr = ocg->CreatePlus(rop_repr, var_repr);
+ else // -sign * coef > 1
+ rop_repr = ocg->CreatePlus(rop_repr, ocg->CreateTimes(ocg->CreateInt(-sign * coef), var_repr));
+ }
+
+ coef_t c_term = -(eq.get_const() * sign);
+
+ if (c_term > 0)
+ rop_repr = ocg->CreatePlus(rop_repr, ocg->CreateInt(c_term));
+ else if (c_term < 0)
+ rop_repr = ocg->CreateMinus(rop_repr, ocg->CreateInt(-c_term));
+ else if (rop_repr == NULL)
+ rop_repr = ocg->CreateInt(0);
+
+ if (divider != 1)
+ rop_repr = ocg->CreateIntegerDivide(rop_repr, ocg->CreateInt(divider));
+
+ enforced.and_with_EQ(eq);
+ enforced.simplify();
+
+ if (a.second > var_substitution_threshold)
+ return std::make_pair(rop_repr, true);
+ else
+ return std::make_pair(rop_repr, false);
+ }
+ else
+ return std::make_pair(static_cast<CG_outputRepr *>(NULL), false);
+}
+
+
+//----------------------------------------------------------------------------
+// Don't use Substitutions class since it can't handle integer
+// division. Instead, use relation mapping to a single output
+// variable to get substitution. -- by chun, 07/19/2007
+//----------------------------------------------------------------------------
+Tuple<CG_outputRepr*> outputSubstitution(CG_outputBuilder* ocg, const Relation &R_, const std::vector<CG_outputRepr *> &assigned_on_the_fly) {
+ Relation &R = const_cast<Relation &>(R_);
+
+ const int n = R.n_out();
+ Tuple<CG_outputRepr*> oReprList;
+
+ // Find substitution for each output variable
+ for (int i = 1; i <= n; i++) {
+ Relation mapping(n, 1);
+ F_And *f_root = mapping.add_and();
+ EQ_Handle h = f_root->add_EQ();
+ h.update_coef(mapping.output_var(1), 1);
+ h.update_coef(mapping.input_var(i), -1);
+
+ Relation S = Composition(mapping, copy(R));
+
+ std::pair<EQ_Handle, int> a = find_simplest_assignment(S, S.output_var(1), assigned_on_the_fly);
+
+ if (a.second < INT_MAX) {
+ while (a.second > 0) {
+ EQ_Handle eq = a.first;
+ std::set<int> candidates;
+ for (Constr_Vars_Iter cvi(eq); cvi; cvi++)
+ if ((*cvi).var->kind() == Input_Var)
+ candidates.insert((*cvi).var->get_position());
+
+ bool changed = false;
+ for (std::set<int>::iterator j = candidates.begin(); j != candidates.end(); j++) {
+ Relation S2 = Project(copy(S), *j, Input_Var);
+ std::pair<EQ_Handle, int> a2 = find_simplest_assignment(S2, S2.output_var(1), assigned_on_the_fly);
+ if (a2.second <= a.second) {
+ S = S2;
+ a = a2;
+ changed = true;
+ break;
+ }
+ }
+ if (!changed)
+ break;
+ }
+ }
+
+ if (a.second < INT_MAX) {
+ CG_outputRepr *repr = NULL;
+ EQ_Handle eq = a.first;
+ Variable_ID v = S.output_var(1);
+
+ for (int j = 1; j <= S.n_inp(); j++)
+ S.name_input_var(j, R.input_var(j)->name());
+ S.setup_names();
+
+ int d = eq.get_coef(v);
+ assert(d != 0);
+ int sign = (d>0)?-1:1;
+ d = -sign * d;
+ for (Constr_Vars_Iter cvi(eq); cvi; cvi++)
+ if ((*cvi).var != v) {
+ int coef = sign * (*cvi).coef;
+ CG_outputRepr *op = outputIdent(ocg, S, (*cvi).var, assigned_on_the_fly);
+ if (coef > 1)
+ op = ocg->CreateTimes(ocg->CreateInt(coef), op);
+ else if (coef < -1)
+ op = ocg->CreateTimes(ocg->CreateInt(-coef), op);
+ if (coef > 0)
+ repr = ocg->CreatePlus(repr, op);
+ else if (coef < 0)
+ repr = ocg->CreateMinus(repr, op);
+ }
+
+ int c = sign * eq.get_const();
+ if (c > 0)
+ repr = ocg->CreatePlus(repr, ocg->CreateInt(c));
+ else if (c < 0)
+ repr = ocg->CreateMinus(repr, ocg->CreateInt(-c));
+ else if (repr == NULL)
+ repr = ocg->CreateInt(0);
+
+ if (d != 1)
+ repr = ocg->CreateIntegerDivide(repr, ocg->CreateInt(d));
+
+ oReprList.append(repr);
+ }
+ else
+ oReprList.append(NULL);
+ }
+
+ return oReprList;
+}
+
+namespace {
+
+Relation create_stride_on_bound(int n, const std::map<Variable_ID, coef_t> &lb, coef_t stride) {
+ Relation result(n);
+ F_And *f_root = result.add_and();
+ EQ_Handle h = f_root->add_stride(stride);
+
+ for (std::map<Variable_ID, coef_t>::const_iterator i = lb.begin(); i != lb.end(); i++) {
+ if (i->first == NULL)
+ h.update_const(i->second);
+ else {
+ switch(i->first->kind()) {
+ case Input_Var: {
+ int pos = i->first->get_position();
+ h.update_coef(result.set_var(pos), i->second);
+ break;
+ }
+ case Global_Var: {
+ Global_Var_ID g = i->first->get_global_var();
+ Variable_ID v;
+ if (g->arity() == 0)
+ v = result.get_local(g);
+ else
+ v = result.get_local(g, i->first->function_of());
+ h.update_coef(v, i->second);
+ break;
+ }
+ default:
+ assert(0);
+ }
+ }
+ }
+
+ return result;
+}
+
+}
+
+//----------------------------------------------------------------------------
+// Find the most restrictive common stride constraint for a set of
+// relations. -- by chun, 05/20/09
+// ----------------------------------------------------------------------------
+Relation greatest_common_step(const Tuple<Relation> &I, const Tuple<int> &active, int level, const Relation &known) {
+ assert(I.size() == active.size());
+ int n = 0;
+
+ std::vector<Relation> I1, I2;
+ for (int i = 1; i <= I.size(); i++)
+ if (active[i]) {
+ if (n == 0)
+ n = I[i].n_set();
+
+ Relation r1;
+ if (known.is_null())
+ r1 = copy(I[i]);
+ else {
+ r1 = Intersection(copy(I[i]), copy(known));
+ r1.simplify();
+ }
+ I1.push_back(r1);
+ Relation r2 = Gist(copy(I[i]), copy(known));
+ assert(r2.is_upper_bound_satisfiable());
+ if (r2.is_obvious_tautology())
+ return Relation::True(n);
+ I2.push_back(r2);
+ }
+
+ std::vector<bool> is_exact(I2.size(), true);
+ std::vector<coef_t> step(I2.size(), 0);
+ std::vector<coef_t> messy_step(I2.size(), 0);
+ Variable_ID t_col = set_var(level);
+ std::map<Variable_ID, coef_t> lb;
+
+ // first check all clean strides: t_col = ... (mod step)
+ for (size_t i = 0; i < I2.size(); i++) {
+ Conjunct *c = I2[i].query_DNF()->single_conjunct();
+
+ bool is_degenerated = false;
+ for (EQ_Iterator e = c->EQs(); e; e++) {
+ coef_t coef = abs((*e).get_coef(t_col));
+ if (coef != 0 && !(*e).has_wildcards()) {
+ is_degenerated = true;
+ break;
+ }
+ }
+ if (is_degenerated)
+ continue;
+
+ for (EQ_Iterator e = c->EQs(); e; e++) {
+ if ((*e).has_wildcards()) {
+ coef_t coef = abs((*e).get_coef(t_col));
+ if (coef == 0)
+ continue;
+ if (coef != 1) {
+ is_exact[i] = false;
+ continue;
+ }
+
+ coef_t this_step = abs(Constr_Vars_Iter(*e, true).curr_coef());
+ assert(this_step != 1);
+
+ if (lb.size() != 0) {
+ Relation test = create_stride_on_bound(n, lb, this_step);
+ if (Gist(test, copy(I1[i])).is_obvious_tautology()) {
+ if (step[i] == 0)
+ step[i] = this_step;
+ else
+ step[i] = lcm(step[i], this_step);
+ }
+ else
+ is_exact[i] = false;
+ }
+ else {
+ // try to find a lower bound that hits on stride
+ Conjunct *c = I2[i].query_DNF()->single_conjunct();
+ for (GEQ_Iterator ge = c->GEQs(); ge; ge++) {
+ if ((*ge).has_wildcards() || (*ge).get_coef(t_col) != 1)
+ continue;
+
+ std::map<Variable_ID, coef_t> cur_lb;
+ for (Constr_Vars_Iter cv(*ge); cv; cv++)
+ cur_lb[cv.curr_var()] = cv.curr_coef();
+ cur_lb[NULL] = (*ge).get_const();
+
+ Relation test = create_stride_on_bound(n, cur_lb, this_step);
+ if (Gist(test, copy(I1[i])).is_obvious_tautology()) {
+ if (step[i] == 0)
+ step[i] = this_step;
+ else
+ step[i] = lcm(step[i], this_step);
+
+ lb = cur_lb;
+ break;
+ }
+ }
+
+ // no clean lower bound, thus we use this modular constraint as is
+ if (lb.size() == 0) {
+ std::map<Variable_ID, coef_t> cur_lb;
+ int wild_count = 0;
+ for (Constr_Vars_Iter cv(*e); cv; cv++)
+ if (cv.curr_var()->kind() == Wildcard_Var)
+ wild_count++;
+ else
+ cur_lb[cv.curr_var()] = cv.curr_coef();
+ cur_lb[NULL] = (*e).get_const();
+
+ if (wild_count == 1) {
+ lb = cur_lb;
+ if (step[i] == 0)
+ step[i] = this_step;
+ else
+ step[i] = lcm(step[i], this_step);
+ }
+ }
+
+ if (lb.size() == 0)
+ is_exact[i] = false;
+ }
+ }
+ }
+ }
+
+ // aggregate all exact steps
+ coef_t global_step = 0;
+ for (size_t i = 0; i < is_exact.size(); i++)
+ if (is_exact[i])
+ global_step = gcd(global_step, step[i]);
+ if (global_step == 1)
+ return Relation::True(n);
+
+ // now check all messy strides: a*t_col = ... (mod step)
+ for (size_t i = 0; i < I2.size(); i++)
+ if (!is_exact[i]) {
+ Conjunct *c = I2[i].query_DNF()->single_conjunct();
+ for (EQ_Iterator e = c->EQs(); e; e++) {
+ coef_t coef = abs((*e).get_coef(t_col));
+ if (coef == 0 || coef == 1)
+ continue;
+
+ // make a guess for messy stride condition -- by chun 07/27/2007
+ coef_t this_step = abs(Constr_Vars_Iter(*e, true).curr_coef());
+ this_step /= gcd(this_step, coef);
+ this_step = gcd(global_step, this_step);
+ if (this_step == 1)
+ continue;
+
+ if (lb.size() != 0) {
+ Relation test = create_stride_on_bound(n, lb, this_step);
+ if (Gist(test, copy(I1[i])).is_obvious_tautology()) {
+ if (step[i] == 0)
+ step[i] = this_step;
+ else
+ step[i] = lcm(step[i], this_step);
+ }
+ }
+ else {
+ // try to find a lower bound that hits on stride
+ Conjunct *c = I2[i].query_DNF()->single_conjunct();
+ for (GEQ_Iterator ge = c->GEQs(); ge; ge++) {
+ if ((*ge).has_wildcards() || (*ge).get_coef(t_col) != 1)
+ continue;
+
+ std::map<Variable_ID, coef_t> cur_lb;
+
+ for (Constr_Vars_Iter cv(*ge); cv; cv++)
+ cur_lb[cv.curr_var()] = cv.curr_coef();
+
+ cur_lb[NULL] = (*ge).get_const();
+
+ Relation test = create_stride_on_bound(n, cur_lb, this_step);
+ if (Gist(test, copy(I1[i])).is_obvious_tautology()) {
+ if (step[i] == 0)
+ step[i] = this_step;
+ else
+ step[i] = lcm(step[i], this_step);
+
+ lb = cur_lb;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // aggregate all non-exact steps
+ for (size_t i = 0; i < is_exact.size(); i++)
+ if (!is_exact[i])
+ global_step = gcd(global_step, step[i]);
+ if (global_step == 1 || global_step == 0)
+ return Relation::True(n);
+
+ Relation result = create_stride_on_bound(n, lb, global_step);
+
+ // check for statements that haven't been factored into global step
+ for (size_t i = 0; i < I1.size(); i++)
+ if (step[i] == 0) {
+ if (!Gist(copy(result), copy(I1[i])).is_obvious_tautology())
+ return Relation::True(n);
+ }
+
+ return result;
+}
+
+
+//-----------------------------------------------------------------------------
+// Substitute variables in a statement according to mapping function.
+//-----------------------------------------------------------------------------
+CG_outputRepr* outputStatement(CG_outputBuilder *ocg, CG_outputRepr *stmt, int indent, const Relation &mapping_, const Relation &known_, const std::vector<CG_outputRepr *> &assigned_on_the_fly) {
+ Relation mapping = copy(mapping_);
+ Relation known = copy(known_);
+ Tuple<std::string> loop_vars;
+
+ for (int i = 1; i <= mapping.n_inp(); i++)
+ loop_vars.append(mapping.input_var(i)->name());
+
+ // discard non-existant variables from iteration spaces -- by chun 12/31/2008
+ if (known.n_set() > mapping.n_out()) {
+ Relation r(known.n_set(), mapping.n_out());
+ F_And *f_root = r.add_and();
+ for (int i = 1; i <= mapping.n_out(); i++) {
+ EQ_Handle h = f_root->add_EQ();
+ h.update_coef(r.input_var(i), 1);
+ h.update_coef(r.output_var(i), -1);
+ }
+ known = Range(Restrict_Domain(r, known));
+ known.simplify();
+ }
+
+ // remove modular constraints from known to simplify mapping process -- by chun 11/10/2008
+ Relation k(known.n_set());
+ F_And *f_root = k.add_and();
+ Conjunct *c = known.query_DNF()->single_conjunct();
+ for (EQ_Iterator e = c->EQs(); e; e++) {
+ if (!(*e).has_wildcards())
+ f_root->add_EQ(*e);
+ }
+ k.simplify();
+
+ // get variable substituion list
+ Relation Inv_mapping = Restrict_Domain(Inverse(mapping), k);
+ Tuple<CG_outputRepr*> sList = outputSubstitution(ocg, Inv_mapping, assigned_on_the_fly);
+
+ return ocg->CreatePlaceHolder(indent, stmt, sList, loop_vars);
+}
+
+
+// find floor definition for variable such as m-3 <= 4v <= m
+bool findFloorInequality(Relation &r, Variable_ID v, GEQ_Handle &h, Variable_ID excluded) {
+ Conjunct *c = r.single_conjunct();
+
+ std::set<Variable_ID> var_checked;
+ std::stack<Variable_ID> var_checking;
+ var_checking.push(v);
+
+ while (!var_checking.empty()) {
+ Variable_ID v2 = var_checking.top();
+ var_checking.pop();
+
+ bool is_floor = false;
+ for (GEQ_Iterator gi(c); gi; gi++) {
+ if (excluded != NULL && (*gi).get_coef(excluded) != 0)
+ continue;
+
+ coef_t a = (*gi).get_coef(v2);
+ if (a < 0) {
+ for (GEQ_Iterator gi2(c); gi2; gi2++) {
+ coef_t b = (*gi2).get_coef(v2);
+ if (b == -a && (*gi).get_const()+(*gi2).get_const() < -a) {
+ bool match = true;
+ for (Constr_Vars_Iter cvi(*gi); cvi; cvi++)
+ if ((*gi2).get_coef((*cvi).var) != -(*cvi).coef) {
+ match = false;
+ break;
+ }
+ if (!match)
+ continue;
+ for (Constr_Vars_Iter cvi(*gi2); cvi; cvi++)
+ if ((*gi).get_coef((*cvi).var) != -(*cvi).coef) {
+ match = false;
+ break;
+ }
+ if (match) {
+ var_checked.insert(v2);
+ is_floor = true;
+ if (v == v2)
+ h = *gi;
+
+ for (Constr_Vars_Iter cvi(*gi); cvi; cvi++)
+ if (((*cvi).var->kind() == Exists_Var || (*cvi).var->kind() == Wildcard_Var) &&
+ var_checked.find((*cvi).var) == var_checked.end())
+ var_checking.push((*cvi).var);
+
+ break;
+ }
+ }
+ }
+ if (is_floor)
+ break;
+ }
+ }
+ if (!is_floor)
+ return false;
+ }
+ return true;
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Output a reqular equality or inequality to conditions.
+// e.g. (i=5*j)
+//-----------------------------------------------------------------------------
+CG_outputRepr* output_as_guard(CG_outputBuilder* ocg, const Relation &guards_in, Constraint_Handle e, bool is_equality, const std::vector<CG_outputRepr *> &assigned_on_the_fly) {
+ Relation &guards = const_cast<Relation &>(guards_in);
+ if (e.has_wildcards())
+ throw std::invalid_argument("constraint must not have wildcard");
+
+ Variable_ID v = (*Constr_Vars_Iter(e)).var;
+
+ coef_t saved_coef = ((e).get_coef(v));
+ int sign = saved_coef < 0 ? -1 : 1;
+
+ (e).update_coef_during_simplify(v, -saved_coef+sign);
+ CG_outputRepr* rop = outputEasyBoundAsRepr(ocg, guards, e, v, false, 0, assigned_on_the_fly);
+ (e).update_coef_during_simplify(v,saved_coef-sign);
+
+ CG_outputRepr* lop = outputIdent(ocg, guards, v, assigned_on_the_fly);
+ if (abs(saved_coef) != 1)
+ lop = ocg->CreateTimes(ocg->CreateInt(abs(saved_coef)), lop);
+
+
+ if (is_equality) {
+ return ocg->CreateEQ(lop, rop);
+ }
+ else {
+ if (saved_coef < 0)
+ return ocg->CreateLE(lop, rop);
+ else
+ return ocg->CreateGE(lop, rop);
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Output stride conditions from equalities.
+// e.g. (exists alpha: i = 5*alpha)
+//-----------------------------------------------------------------------------
+CG_outputRepr *output_EQ_strides(CG_outputBuilder* ocg, const Relation &guards_in, const std::vector<CG_outputRepr *> &assigned_on_the_fly) {
+ Relation guards = const_cast<Relation &>(guards_in);
+ Conjunct *c = guards.single_conjunct();
+
+ CG_outputRepr *eqRepr = NULL;
+
+ for (EQ_Iterator ei(c->EQs()); ei; ei++) {
+ Variable_ID wc = NULL;
+ for (Constr_Vars_Iter cvi((*ei), true); cvi; cvi++) {
+ if (wc != NULL)
+ throw codegen_error("Can't generate equality condition with multiple wildcards");
+ else
+ wc = (*cvi).var;
+ }
+ if (wc == NULL)
+ continue;
+
+ coef_t step = (*ei).get_coef(wc);
+
+ (*ei).update_coef_during_simplify(wc, 1-step);
+ CG_outputRepr* lop = outputEasyBoundAsRepr(ocg, guards, (*ei), wc, false, 0, assigned_on_the_fly);
+ (*ei).update_coef_during_simplify(wc, step-1);
+
+ CG_outputRepr* rop = ocg->CreateInt(abs(step));
+ CG_outputRepr* intMod = ocg->CreateIntegerMod(lop, rop);
+ CG_outputRepr* eqNode = ocg->CreateEQ(intMod, ocg->CreateInt(0));
+
+ eqRepr = ocg->CreateAnd(eqRepr, eqNode);
+ }
+
+ return eqRepr;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Output hole conditions created by inequalities involving wildcards.
+// e.g. (exists alpha: 4*alpha <= i <= 5*alpha)
+// Collect wildcards
+// For each whildcard
+// collect lower and upper bounds in which wildcard appears
+// For each lower bound
+// create constraint with each upper bound
+//-----------------------------------------------------------------------------
+CG_outputRepr *output_GEQ_strides(CG_outputBuilder* ocg, const Relation &guards_in, const std::vector<CG_outputRepr *> &assigned_on_the_fly) {
+ Relation guards = const_cast<Relation &>(guards_in);
+ Conjunct *c = guards.single_conjunct();
+
+ CG_outputRepr* geqRepr = NULL;
+
+ std::set<Variable_ID> non_orphan_wildcard;
+ for (GEQ_Iterator gi(c); gi; gi++) {
+ int num_wild = 0;
+ Variable_ID first_one;
+ for (Constr_Vars_Iter cvi(*gi, true); cvi; cvi++) {
+ num_wild++;
+ if (num_wild == 1)
+ first_one = (*cvi).var;
+ else
+ non_orphan_wildcard.insert((*cvi).var);
+ }
+ if (num_wild > 1)
+ non_orphan_wildcard.insert(first_one);
+ }
+
+ for (int i = 1; i <= (*(c->variables())).size(); i++) {
+ Variable_ID wc = (*(c->variables()))[i];
+ if (wc->kind() == Wildcard_Var && non_orphan_wildcard.find(wc) == non_orphan_wildcard.end()) {
+ Tuple<GEQ_Handle> lower, upper;
+ for (GEQ_Iterator gi(c); gi; gi++) {
+ if((*gi).get_coef(wc) > 0)
+ lower.append(*gi);
+ else if((*gi).get_coef(wc) < 0)
+ upper.append(*gi);
+ }
+
+ // low: c*alpha - x >= 0
+ // up: -d*alpha + y >= 0
+ for (Tuple_Iterator<GEQ_Handle> low(lower); low; low++) {
+ for (Tuple_Iterator<GEQ_Handle> up(upper); up; up++) {
+ coef_t low_coef = (*low).get_coef(wc);
+ coef_t up_coef = (*up).get_coef(wc);
+
+ (*low).update_coef_during_simplify(wc, 1-low_coef);
+ CG_outputRepr* lowExpr = outputEasyBoundAsRepr(ocg, guards, *low, wc, false, 0, assigned_on_the_fly);
+ (*low).update_coef_during_simplify(wc, low_coef-1);
+
+ (*up).update_coef_during_simplify(wc, -1-up_coef);
+ CG_outputRepr* upExpr = outputEasyBoundAsRepr(ocg, guards, *up, wc, false, 0, assigned_on_the_fly);
+ (*up).update_coef_during_simplify(wc, up_coef+1);
+
+ CG_outputRepr* intDiv = ocg->CreateIntegerDivide(upExpr, ocg->CreateInt(-up_coef));
+ CG_outputRepr* rop = ocg->CreateTimes(ocg->CreateInt(low_coef), intDiv);
+ CG_outputRepr* geqNode = ocg->CreateLE(lowExpr, rop);
+
+ geqRepr = ocg->CreateAnd(geqRepr, geqNode);
+ }
+ }
+ }
+ }
+
+ if (non_orphan_wildcard.size() > 0) {
+ // e.g. c*alpha - x >= 0 (*)
+ // -d*alpha + y >= 0 (*)
+ // e1*alpha + f1*beta + g1 >= 0 (**)
+ // e2*alpha + f2*beta + g2 >= 0 (**)
+ // ...
+ // TODO: should generate a testing loop for alpha using its lower and
+ // upper bounds from (*) constraints and do the same if-condition test
+ // for beta from each pair of opposite (**) constraints as above,
+ // and exit the loop when if-condition satisfied.
+ throw codegen_error("Can't generate multiple wildcard GEQ guards right now");
+ }
+
+ return geqRepr;
+}
+
+
+//-----------------------------------------------------------------------------
+// Translate all constraints in a relation to guard conditions.
+//-----------------------------------------------------------------------------
+CG_outputRepr *outputGuard(CG_outputBuilder* ocg, const Relation &guards_in, const std::vector<CG_outputRepr *> &assigned_on_the_fly) {
+ Relation &guards = const_cast<Relation &>(guards_in);
+ if (guards.is_null() || guards.is_obvious_tautology())
+ return NULL;
+
+ CG_outputRepr* nodeRepr = NULL;
+
+ CG_outputRepr *eqStrideRepr = output_EQ_strides(ocg, guards, assigned_on_the_fly);
+ nodeRepr = ocg->CreateAnd(nodeRepr, eqStrideRepr);
+
+ CG_outputRepr *geqStrideRepr = output_GEQ_strides(ocg, guards, assigned_on_the_fly);
+ nodeRepr = ocg->CreateAnd(nodeRepr, geqStrideRepr);
+
+ Conjunct *c = guards.single_conjunct();
+ for(EQ_Iterator ei(c->EQs()); ei; ei++)
+ if (!(*ei).has_wildcards()) {
+ CG_outputRepr *eqRepr = output_as_guard(ocg, guards, (*ei), true, assigned_on_the_fly);
+ nodeRepr = ocg->CreateAnd(nodeRepr, eqRepr);
+ }
+ for(GEQ_Iterator gi(c->GEQs()); gi; gi++)
+ if (!(*gi).has_wildcards()) {
+ CG_outputRepr *geqRepr = output_as_guard(ocg, guards, (*gi), false, assigned_on_the_fly);
+ nodeRepr = ocg->CreateAnd(nodeRepr, geqRepr);
+ }
+
+ return nodeRepr;
+}
+
+
+//-----------------------------------------------------------------------------
+// one is 1 for LB
+// this function is overloaded should replace the original one
+//-----------------------------------------------------------------------------
+CG_outputRepr *outputLBasRepr(CG_outputBuilder* ocg, const GEQ_Handle &g,
+ Relation &bounds, Variable_ID v,
+ coef_t stride, const EQ_Handle &strideEQ,
+ Relation known, const std::vector<CG_outputRepr *> &assigned_on_the_fly) {
+#if ! defined NDEBUG
+ coef_t v_coef;
+ assert((v_coef = g.get_coef(v)) > 0);
+#endif
+
+ std::string s;
+ CG_outputRepr *lbRepr;
+ if (stride == 1) {
+ lbRepr = outputEasyBoundAsRepr(ocg, bounds, g, v, false, 1, assigned_on_the_fly);
+ }
+ else {
+ if (!boundHitsStride(g,v,strideEQ,stride,known)) {
+ bounds.setup_names(); // boundsHitsStride resets variable names
+
+ CG_stringBuilder oscg;
+ std::string c = GetString(outputEasyBoundAsRepr(&oscg, bounds, strideEQ, v, true, 0, assigned_on_the_fly));
+ CG_outputRepr *cRepr = NULL;
+ if (c != std::string("0"))
+ cRepr = outputEasyBoundAsRepr(ocg, bounds, strideEQ, v, true, 0, assigned_on_the_fly);
+ std::string LoverM = GetString(outputEasyBoundAsRepr(&oscg, bounds, g, v, false, 1, assigned_on_the_fly));
+ CG_outputRepr *LoverMRepr = NULL;
+ if (LoverM != std::string("0"))
+ LoverMRepr = outputEasyBoundAsRepr(ocg, bounds, g, v, false, 1, assigned_on_the_fly);
+
+ if (code_gen_debug > 2) {
+ fprintf(DebugFile,"::: LoverM is %s\n", LoverM.c_str());
+ fprintf(DebugFile,"::: c is %s\n", c.c_str());
+ }
+
+ int complexity1 = 0, complexity2 = 0;
+ for (size_t i = 0; i < c.length(); i++)
+ if (c[i] == '+' || c[i] == '-' || c[i] == '*' || c[i] == '/')
+ complexity1++;
+ else if (c[i] == ',')
+ complexity1 += 2;
+ for (size_t i = 0; i < LoverM.length(); i++)
+ if (LoverM[i] == '+' || LoverM[i] == '-' || LoverM[i] == '*' || LoverM[i] == '/')
+ complexity2++;
+ else if (LoverM[i] == ',')
+ complexity2 += 2;
+
+ if (complexity1 < complexity2) {
+ CG_outputRepr *idUp = LoverMRepr;
+ CG_outputRepr *c1Repr = ocg->CreateCopy(cRepr);
+ idUp = ocg->CreateMinus(idUp, c1Repr);
+ idUp = ocg->CreatePlus(idUp, ocg->CreateInt(stride-1));
+ CG_outputRepr *idLow = ocg->CreateInt(stride);
+ lbRepr = ocg->CreateTimes(ocg->CreateInt(stride),
+ ocg->CreateIntegerDivide(idUp, idLow));
+ lbRepr = ocg->CreatePlus(lbRepr, cRepr);
+ }
+ else {
+ CG_outputRepr *LoverM1Repr = ocg->CreateCopy(LoverMRepr);
+ CG_outputRepr *imUp = ocg->CreateMinus(cRepr, LoverM1Repr);
+ CG_outputRepr *imLow = ocg->CreateInt(stride);
+ CG_outputRepr *intMod = ocg->CreateIntegerMod(imUp, imLow);
+ lbRepr = ocg->CreatePlus(LoverMRepr, intMod);
+ }
+ }
+ else {
+ // boundsHitsStride resets variable names
+ bounds.setup_names();
+ lbRepr = outputEasyBoundAsRepr(ocg, bounds, g, v, false, 0, assigned_on_the_fly);
+ }
+ }
+
+ return lbRepr;
+}
+
+//-----------------------------------------------------------------------------
+// one is -1 for UB
+// this function is overloaded should replace the original one
+//-----------------------------------------------------------------------------
+CG_outputRepr *outputUBasRepr(CG_outputBuilder* ocg, const GEQ_Handle &g,
+ Relation & bounds,
+ Variable_ID v,
+ coef_t /*stride*/, // currently unused
+ const EQ_Handle &/*strideEQ*/, //currently unused
+ const std::vector<CG_outputRepr *> &assigned_on_the_fly) {
+ assert(g.get_coef(v) < 0);
+ CG_outputRepr* upRepr = outputEasyBoundAsRepr(ocg, bounds, g, v, false, 0, assigned_on_the_fly);
+ return upRepr;
+}
+
+//-----------------------------------------------------------------------------
+// Print the expression for the variable given as v. Works for both
+// GEQ's and EQ's, but produces intDiv (not intMod) when v has a nonunit
+// coefficient. So it is OK for loop bounds, but for checking stride
+// constraints, you want to make sure the coef of v is 1, and insert the
+// intMod yourself.
+//
+// original name is outputEasyBound
+//-----------------------------------------------------------------------------
+CG_outputRepr* outputEasyBoundAsRepr(CG_outputBuilder* ocg, Relation &bounds,
+ const Constraint_Handle &g, Variable_ID v,
+ bool ignoreWC,
+ int ceiling,
+ const std::vector<CG_outputRepr *> &assigned_on_the_fly) {
+ // assert ignoreWC => g is EQ
+ // rewrite constraint as foo (== or <= or >=) v, return foo as string
+
+ CG_outputRepr* easyBoundRepr = NULL;
+
+ coef_t v_coef = g.get_coef(v);
+ int v_sign = v_coef > 0 ? 1 : -1;
+ v_coef *= v_sign;
+ assert(v_coef > 0);
+ // foo is (-constraint)/v_sign/v_coef
+
+ int sign_adj = -v_sign;
+
+ //----------------------------------------------------------------------
+ // the following generates +- cf*varName
+ //----------------------------------------------------------------------
+ for(Constr_Vars_Iter c2(g, false); c2; c2++) {
+ if ((*c2).var != v && (!ignoreWC || (*c2).var->kind()!=Wildcard_Var)) {
+
+ coef_t cf = (*c2).coef*sign_adj;
+ assert(cf != 0);
+
+ CG_outputRepr *varName;
+ if ((*c2).var->kind() == Wildcard_Var) {
+ GEQ_Handle h;
+ if (!findFloorInequality(bounds, (*c2).var, h, v)) {
+ if (easyBoundRepr != NULL) {
+ easyBoundRepr->clear();
+ delete easyBoundRepr;
+ }
+ return NULL;
+ }
+ varName = outputEasyBoundAsRepr(ocg, bounds, h, (*c2).var, false, 0, assigned_on_the_fly);
+ }
+ else {
+ varName = outputIdent(ocg, bounds, (*c2).var, assigned_on_the_fly);
+ }
+ CG_outputRepr *cfRepr = NULL;
+
+ if (cf > 1) {
+ cfRepr = ocg->CreateInt(cf);
+ CG_outputRepr* rbRepr = ocg->CreateTimes(cfRepr, varName);
+ easyBoundRepr = ocg->CreatePlus(easyBoundRepr, rbRepr);
+ }
+ else if (cf < -1) {
+ cfRepr = ocg->CreateInt(-cf);
+ CG_outputRepr* rbRepr = ocg->CreateTimes(cfRepr, varName);
+ easyBoundRepr = ocg->CreateMinus(easyBoundRepr, rbRepr);
+ }
+ else if (cf == 1) {
+ easyBoundRepr = ocg->CreatePlus(easyBoundRepr, varName);
+ }
+ else if (cf == -1) {
+ easyBoundRepr = ocg->CreateMinus(easyBoundRepr, varName);
+ }
+ }
+ }
+
+ if (g.get_const()) {
+ coef_t cf = g.get_const()*sign_adj;
+ assert(cf != 0);
+ if (cf > 0) {
+ easyBoundRepr = ocg->CreatePlus(easyBoundRepr, ocg->CreateInt(cf));
+ }
+ else {
+ easyBoundRepr = ocg->CreateMinus(easyBoundRepr, ocg->CreateInt(-cf));
+ }
+ }
+ else {
+ if(easyBoundRepr == NULL) {
+ easyBoundRepr = ocg->CreateInt(0);
+ }
+ }
+
+ if (v_coef > 1) {
+ assert(ceiling >= 0);
+ if (ceiling) {
+ easyBoundRepr= ocg->CreatePlus(easyBoundRepr, ocg->CreateInt(v_coef-1));
+ }
+ easyBoundRepr = ocg->CreateIntegerDivide(easyBoundRepr, ocg->CreateInt(v_coef));
+ }
+
+ return easyBoundRepr;
+}
+
+
+//----------------------------------------------------------------------------
+// Translate inequality constraints to loop or assignment.
+// if return.second is true, return.first is loop structure,
+// otherwise it is assignment.
+// ----------------------------------------------------------------------------
+std::pair<CG_outputRepr *, bool> outputBounds(CG_outputBuilder* ocg, const Relation &bounds, Variable_ID v, int indent, Relation &enforced, const std::vector<CG_outputRepr *> &assigned_on_the_fly) {
+ Relation b = copy(bounds);
+ Conjunct *c = b.query_DNF()->single_conjunct();
+
+ // Elaborate stride simplification which is complementary to gist function
+ // since we further target the specific loop variable. -- by chun 08/07/2008
+ Relation r1 = Relation::True(b.n_set()), r2 = Relation::True(b.n_set());
+ for (EQ_Iterator ei(c); ei; ei++) {
+ if ((*ei).get_coef(v) != 0 && (*ei).has_wildcards()) { // stride condition found
+ coef_t sign;
+ if ((*ei).get_coef(v) > 0)
+ sign = 1;
+ else
+ sign = -1;
+
+ coef_t stride = 0;
+ for (Constr_Vars_Iter cvi(*ei, true); cvi; cvi++)
+ if ((*cvi).var->kind() == Wildcard_Var) {
+ stride = abs((*cvi).coef);
+ break;
+ }
+
+ // check if stride hits lower bound
+ bool found_match = false;
+ if (abs((*ei).get_coef(v)) != 1) { // expensive matching for non-clean stride condition
+ coef_t d = stride / gcd(abs((*ei).get_coef(v)), stride);
+ Relation r3 = Relation::True(b.n_set());
+ r3.and_with_EQ(*ei);
+
+ for (GEQ_Iterator gi(c); gi; gi++) {
+ if ((*gi).get_coef(v) == 1 && !(*gi).has_wildcards()) {
+ Relation r4(b.n_set());
+ F_And *f_root = r4.add_and();
+ Stride_Handle h = f_root->add_stride(d);
+
+ for (Constr_Vars_Iter cvi(*gi); cvi; cvi++)
+ switch ((*cvi).var->kind()) {
+ case Input_Var: {
+ int pos = (*cvi).var->get_position();
+ h.update_coef(r4.set_var(pos), (*cvi).coef);
+ break;
+ }
+ case Global_Var: {
+ Global_Var_ID g = (*cvi).var->get_global_var();
+ Variable_ID v;
+ if (g->arity() == 0)
+ v = r4.get_local(g);
+ else
+ v = r4.get_local(g, (*cvi).var->function_of());
+ h.update_coef(v, (*cvi).coef);
+ break;
+ }
+ default:
+ fprintf(DebugFile, "can't deal with the variable type in lower bound\n");
+ return std::make_pair(static_cast<CG_outputRepr *>(NULL), false);
+ }
+ h.update_const((*gi).get_const());
+
+ Relation r5 = Gist(copy(r3), Intersection(copy(r4), copy(enforced)));
+
+ // replace original stride condition with striding from this lower bound
+ if (r5.is_obvious_tautology()) {
+ r1 = Intersection(r1, r4);
+ found_match = true;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ for (GEQ_Iterator gi(c); gi; gi++) {
+ if ((*gi).get_coef(v) == abs((*ei).get_coef(v)) && !(*gi).has_wildcards()) { // potential matching lower bound found
+ Relation r(b.n_set());
+ Stride_Handle h = r.add_and()->add_stride(stride);
+
+ for (Constr_Vars_Iter cvi(*gi); cvi; cvi++)
+ switch ((*cvi).var->kind()) {
+ case Input_Var: {
+ int pos = (*cvi).var->get_position();
+ if ((*cvi).var != v) {
+ int t1 = int_mod((*cvi).coef, stride);
+ if (t1 != 0) {
+ coef_t t2 = enforced.query_variable_mod(enforced.set_var(pos), stride);
+ if (t2 != posInfinity)
+ h.update_const(t1*t2);
+ else
+ h.update_coef(r.set_var(pos), t1);
+ }
+ }
+ else
+ h.update_coef(r.set_var(pos), (*cvi).coef);
+ break;
+ }
+ case Global_Var: {
+ Global_Var_ID g = (*cvi).var->get_global_var();
+ Variable_ID v;
+ if (g->arity() == 0)
+ v = enforced.get_local(g);
+ else
+ v = enforced.get_local(g, (*cvi).var->function_of());
+ coef_t t = enforced.query_variable_mod(v, stride);
+ if (t != posInfinity)
+ h.update_const(t*(*cvi).coef);
+ else {
+ Variable_ID v2;
+ if (g->arity() == 0)
+ v2 = r.get_local(g);
+ else
+ v2 = r.get_local(g, (*cvi).var->function_of());
+ h.update_coef(v2, (*cvi).coef);
+ }
+ break;
+ }
+ default:
+ fprintf(DebugFile, "can't deal with the variable type in lower bound\n");
+ return std::make_pair(static_cast<CG_outputRepr *>(NULL), false);
+ }
+ h.update_const((*gi).get_const());
+
+ bool t = true;
+ {
+ Conjunct *c2 = r.query_DNF()->single_conjunct();
+ EQ_Handle h2;
+ for (EQ_Iterator ei2(c2); ei2; ei2++) {
+ h2 = *ei2;
+ break;
+ }
+
+ int sign;
+ if (h2.get_coef(v) == (*ei).get_coef(v))
+ sign = 1;
+ else
+ sign = -1;
+
+ t = int_mod(h2.get_const() - sign * (*ei).get_const(), stride) == 0;
+
+ if (t != false)
+ for (Constr_Vars_Iter cvi(h2); cvi; cvi++)
+ if ((*cvi).var->kind() != Wildcard_Var &&
+ int_mod((*cvi).coef - sign * (*ei).get_coef((*cvi).var), stride) != 0) {
+ t = false;
+ break;
+ }
+
+ if (t != false)
+ for (Constr_Vars_Iter cvi(*ei); cvi; cvi++)
+ if ((*cvi).var->kind() != Wildcard_Var &&
+ int_mod((*cvi).coef - sign * h2.get_coef((*cvi).var), stride) != 0) {
+ t = false;
+ break;
+ }
+
+ }
+
+ if (t) {
+ // replace original stride condition with striding from this lower bound
+ F_And *f_root = r1.and_with_and();
+ Stride_Handle h = f_root->add_stride(stride);
+ for (Constr_Vars_Iter cvi(*gi); cvi; cvi++)
+ switch ((*cvi).var->kind()) {
+ case Input_Var: {
+ h.update_coef(r1.set_var((*cvi).var->get_position()), (*cvi).coef);
+ break;
+ }
+ case Global_Var: {
+ Global_Var_ID g = (*cvi).var->get_global_var();
+ Variable_ID v;
+ if (g->arity() == 0)
+ v = r1.get_local(g);
+ else
+ v = r1.get_local(g, (*cvi).var->function_of());
+ h.update_coef(v, (*cvi).coef);
+ break;
+ }
+ default:
+ fprintf(DebugFile, "can't deal with the variable type in lower bound\n");
+ return std::make_pair(static_cast<CG_outputRepr *>(NULL), false);
+ }
+ h.update_const((*gi).get_const());
+
+ found_match = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!found_match)
+ r1.and_with_EQ(*ei);
+ }
+ else if ((*ei).get_coef(v) == 0) {
+ Relation r3 = Relation::True(b.n_set());
+ r3.and_with_EQ(*ei);
+ Relation r4 = Gist(r3, copy(enforced));
+ if (!r4.is_obvious_tautology())
+ r2.and_with_EQ(*ei);
+ }
+ else
+ r2.and_with_EQ(*ei);
+ }
+
+ // restore remaining inequalities
+ {
+ std::map<Variable_ID, Variable_ID> exists_mapping;
+ F_Exists *fe = r2.and_with_and()->add_exists();
+ F_And *f_root = fe->add_and();
+ for (GEQ_Iterator gi(c); gi; gi++) {
+ GEQ_Handle h = f_root->add_GEQ();
+ for (Constr_Vars_Iter cvi(*gi); cvi; cvi++) {
+ Variable_ID v = cvi.curr_var();
+ switch (v->kind()) {
+ case Input_Var: {
+ int pos = v->get_position();
+ h.update_coef(r2.set_var(pos), cvi.curr_coef());
+ break;
+ }
+ case Exists_Var:
+ case Wildcard_Var: {
+ std::map<Variable_ID, Variable_ID>::iterator p = exists_mapping.find(v);
+ Variable_ID e;
+ if (p == exists_mapping.end()) {
+ e = fe->declare();
+ exists_mapping[v] = e;
+ }
+ else
+ e = (*p).second;
+ h.update_coef(e, cvi.curr_coef());
+ break;
+ }
+ case Global_Var: {
+ Global_Var_ID g = v->get_global_var();
+ Variable_ID v2;
+ if (g->arity() == 0)
+ v2 = r2.get_local(g);
+ else
+ v2 = r2.get_local(g, v->function_of());
+ h.update_coef(v2, cvi.curr_coef());
+ break;
+ }
+ default:
+ assert(0);
+ }
+ }
+ h.update_const((*gi).get_const());
+ }
+ }
+
+ // overwrite original bounds
+ {
+ r1.simplify();
+ r2.simplify();
+ Relation b2 = Intersection(r1, r2);
+ b2.simplify();
+ for (int i = 1; i <= b.n_set(); i++)
+ b2.name_set_var(i, b.set_var(i)->name());
+ b2.setup_names();
+ b = b2;
+ c = b.query_DNF()->single_conjunct();
+ }
+
+
+ // get loop strides
+ EQ_Handle strideEQ;
+ bool foundStride = false; // stride that can be translated to loop
+ bool foundSimpleStride = false; // stride that starts from const value
+ coef_t step = 1;
+ int num_stride = 0;
+
+ for (EQ_Iterator ei(c); ei; ei++) {
+ if ((*ei).get_coef(v) != 0 && (*ei).has_wildcards()) {
+ num_stride++;
+
+ if (abs((*ei).get_coef(v)) != 1)
+ continue;
+
+ bool t = true;
+ coef_t d = 1;
+ for (Constr_Vars_Iter cvi(*ei); cvi; cvi++)
+ if ((*cvi).var->kind() == Wildcard_Var) {
+ assert(d==1);
+ d = abs((*cvi).coef);
+ }
+ else if ((*cvi).var->kind() == Input_Var) {
+ if ((*cvi).var != v)
+ t = false;
+ }
+ else
+ t = false;
+
+ if (d > step) {
+ step = d;
+ foundSimpleStride = t;
+ strideEQ = *ei;
+ foundStride = true;
+ }
+ }
+ }
+
+ // More than one stride or complex stride found, we should move all
+ // but strideEQ to body's guard condition. alas, not implemented.
+ if (!(num_stride == 0 || (num_stride == 1 && foundStride)))
+ return std::make_pair(static_cast<CG_outputRepr *>(NULL), false);
+
+ // get loop bounds
+ int lower_bounds = 0, upper_bounds = 0;
+ Tuple<CG_outputRepr *> lbList;
+ Tuple<CG_outputRepr *> ubList;
+ coef_t const_lb = negInfinity, const_ub = posInfinity;
+ for (GEQ_Iterator g(c); g; g++) {
+ coef_t coef = (*g).get_coef(v);
+ if (coef == 0)
+ continue;
+ else if (coef > 0) { // lower bound
+ lower_bounds++;
+ if ((*g).is_const(v) && !foundStride) {
+ //no variables but v in constr
+ coef_t L,m;
+ L = -((*g).get_const());
+
+ m = (*g).get_coef(v);
+ coef_t sb = (int) (ceil(((float) L) /m));
+ set_max(const_lb, sb);
+ }
+ else if ((*g).is_const(v) && foundSimpleStride) {
+ // no variables but v in constr
+ //make LB fit the stride constraint
+ coef_t L,m,s,c;
+ L = -((*g).get_const());
+ m = (*g).get_coef(v);
+ s = step;
+ c = strideEQ.get_const();
+ coef_t sb = (s * (int) (ceil( (float) (L - (c * m)) /(s*m))))+ c;
+ set_max(const_lb, sb);
+ }
+ else
+ lbList.append(outputLBasRepr(ocg, *g, b, v, step, strideEQ, enforced, assigned_on_the_fly));
+ }
+ else { // upper bound
+ upper_bounds++;
+ if ((*g).is_const(v)) {
+ // no variables but v in constraint
+ set_min(const_ub,-(*g).get_const()/(*g).get_coef(v));
+ }
+ else
+ ubList.append(outputUBasRepr(ocg, *g, b, v, step, strideEQ, assigned_on_the_fly));
+ }
+ }
+
+ CG_outputRepr *lbRepr = NULL;
+ CG_outputRepr *ubRepr = NULL;
+ if (const_lb != negInfinity)
+ lbList.append(ocg->CreateInt(const_lb));
+ if (lbList.size() > 1)
+ lbRepr = ocg->CreateInvoke("max", lbList);
+ else if (lbList.size() == 1)
+ lbRepr = lbList[1];
+
+ //protonu
+ if(fillInBounds && lbList.size() == 1 && const_lb != negInfinity)
+ lowerBoundForLevel = const_lb;
+ //end-protonu
+
+ if (const_ub != posInfinity)
+ ubList.append(ocg->CreateInt(const_ub));
+ if (ubList.size() > 1)
+ ubRepr = ocg->CreateInvoke("min", ubList);
+ else if (ubList.size() == 1)
+ ubRepr = ubList[1];
+
+ //protonu
+ if(fillInBounds && const_ub != posInfinity)
+ upperBoundForLevel = const_ub;
+ //end-protonu
+
+ if (upper_bounds == 0 || lower_bounds == 0) {
+ return std::make_pair(static_cast<CG_outputRepr *>(NULL), false);
+ }
+ else {
+ // bookkeeping catched constraints in new_knwon
+ F_Exists *fe = enforced.and_with_and()->add_exists();
+ F_And *f_root = fe->add_and();
+ std::map<Variable_ID, Variable_ID> exists_mapping;
+ std::stack<std::pair<GEQ_Handle, Variable_ID> > floor_geq_stack;
+ std::set<Variable_ID> floor_var_set;
+
+ if (foundStride) {
+ EQ_Handle h = f_root->add_EQ();
+ for (Constr_Vars_Iter cvi(strideEQ); cvi; cvi++)
+ switch ((*cvi).var->kind()) {
+ case Input_Var: {
+ int pos = (*cvi).var->get_position();
+ h.update_coef(enforced.set_var(pos), (*cvi).coef);
+ break;
+ }
+ case Exists_Var:
+ case Wildcard_Var: {
+ std::map<Variable_ID, Variable_ID>::iterator p = exists_mapping.find((*cvi).var);
+ Variable_ID e;
+ if (p == exists_mapping.end()) {
+ e = fe->declare();
+ exists_mapping[(*cvi).var] = e;
+ }
+ else
+ e = (*p).second;
+ h.update_coef(e, (*cvi).coef);
+ break;
+ }
+ case Global_Var: {
+ Global_Var_ID g = (*cvi).var->get_global_var();
+ Variable_ID e;
+ if (g->arity() == 0)
+ e = enforced.get_local(g);
+ else
+ e = enforced.get_local(g, (*cvi).var->function_of());
+ h.update_coef(e, (*cvi).coef);
+ break;
+ }
+ default:
+ assert(0);
+ }
+ h.update_const(strideEQ.get_const());
+ }
+
+ for (GEQ_Iterator gi(c); gi; gi++)
+ if ((*gi).get_coef(v) != 0) {
+ GEQ_Handle h = f_root->add_GEQ();
+ for (Constr_Vars_Iter cvi(*gi); cvi; cvi++)
+ switch ((*cvi).var->kind()) {
+ case Input_Var: {
+ int pos = (*cvi).var->get_position();
+ h.update_coef(enforced.set_var(pos), (*cvi).coef);
+ break;
+ }
+ case Exists_Var:
+ case Wildcard_Var: {
+ std::map<Variable_ID, Variable_ID>::iterator p = exists_mapping.find((*cvi).var);
+ Variable_ID e;
+ if (p == exists_mapping.end()) {
+ e = fe->declare();
+ exists_mapping[(*cvi).var] = e;
+ }
+ else
+ e = (*p).second;
+ h.update_coef(e, (*cvi).coef);
+
+ if (floor_var_set.find((*cvi).var) == floor_var_set.end()) {
+ GEQ_Handle h2;
+ findFloorInequality(b, (*cvi).var, h2, v);
+ floor_geq_stack.push(std::make_pair(h2, (*cvi).var));
+ floor_var_set.insert((*cvi).var);
+ }
+ break;
+ }
+ case Global_Var: {
+ Global_Var_ID g = (*cvi).var->get_global_var();
+ Variable_ID e;
+ if (g->arity() == 0)
+ e = enforced.get_local(g);
+ else
+ e = enforced.get_local(g, (*cvi).var->function_of());
+ h.update_coef(e, (*cvi).coef);
+ break;
+ }
+ default:
+ assert(0);
+ }
+ h.update_const((*gi).get_const());
+ }
+
+ // add floor definition involving variables appeared in bounds
+ while (!floor_geq_stack.empty()) {
+ std::pair<GEQ_Handle, Variable_ID> p = floor_geq_stack.top();
+ floor_geq_stack.pop();
+
+ GEQ_Handle h1 = f_root->add_GEQ();
+ GEQ_Handle h2 = f_root->add_GEQ();
+ for (Constr_Vars_Iter cvi(p.first); cvi; cvi++) {
+ switch ((*cvi).var->kind()) {
+ case Input_Var: {
+ int pos = (*cvi).var->get_position();
+ h1.update_coef(enforced.input_var(pos), (*cvi).coef);
+ h2.update_coef(enforced.input_var(pos), -(*cvi).coef);
+ break;
+ }
+ case Exists_Var:
+ case Wildcard_Var: {
+ std::map<Variable_ID, Variable_ID>::iterator p2 = exists_mapping.find((*cvi).var);
+ Variable_ID e;
+ if (p2 == exists_mapping.end()) {
+ e = fe->declare();
+ exists_mapping[(*cvi).var] = e;
+ }
+ else
+ e = (*p2).second;
+ h1.update_coef(e, (*cvi).coef);
+ h2.update_coef(e, -(*cvi).coef);
+
+ if (floor_var_set.find((*cvi).var) == floor_var_set.end()) {
+ GEQ_Handle h3;
+ findFloorInequality(b, (*cvi).var, h3, v);
+ floor_geq_stack.push(std::make_pair(h3, (*cvi).var));
+ floor_var_set.insert((*cvi).var);
+ }
+ break;
+ }
+ case Global_Var: {
+ Global_Var_ID g = (*cvi).var->get_global_var();
+ Variable_ID e;
+ if (g->arity() == 0)
+ e = enforced.get_local(g);
+ else
+ e = enforced.get_local(g, (*cvi).var->function_of());
+ h1.update_coef(e, (*cvi).coef);
+ h2.update_coef(e, -(*cvi).coef);
+ break;
+ }
+ default:
+ assert(0);
+ }
+ }
+ h1.update_const(p.first.get_const());
+ h2.update_const(-p.first.get_const());
+ h2.update_const(-p.first.get_coef(p.second)-1);
+ }
+ enforced.simplify();
+
+ CG_outputRepr *stRepr = NULL;
+ if (step != 1)
+ stRepr = ocg->CreateInt(abs(step));
+ CG_outputRepr *indexRepr = outputIdent(ocg, b, v, assigned_on_the_fly);
+ CG_outputRepr *ctrlRepr = ocg->CreateInductive(indexRepr, lbRepr, ubRepr, stRepr);
+
+ return std::make_pair(ctrlRepr, true);
+ }
+}
+
+
+Relation project_onto_levels(Relation R, int last_level, bool wildcards) {
+ assert(last_level >= 0 && R.is_set() && last_level <= R.n_set());
+ if (last_level == R.n_set()) return R;
+
+ int orig_vars = R.n_set();
+ int num_projected = orig_vars - last_level;
+ R = Extend_Set(R,num_projected
+ ); // Project out vars numbered > last_level
+ Mapping m1 = Mapping::Identity(R.n_set()); // now orig_vars+num_proj
+
+ for(int i=last_level+1; i <= orig_vars; i++) {
+ m1.set_map(Set_Var, i, Exists_Var, i);
+ m1.set_map(Set_Var, i+num_projected, Set_Var, i);
+ }
+
+ MapRel1(R, m1, Comb_Id);
+ R.finalize();
+ R.simplify();
+ if (!wildcards)
+ R = Approximate(R,1);
+ assert(R.is_set());
+ return R;
+}
+
+
+// Check if the lower bound already enforces the stride by
+// (Where m is coef of v in g and L is the bound on m*v):
+// Check if m divides L evenly and Check if this l.bound on v implies strideEQ
+bool boundHitsStride(const GEQ_Handle &g, Variable_ID v,
+ const EQ_Handle &strideEQ,
+ coef_t /*stride*/, // currently unused
+ Relation known) {
+/* m = coef of v in g;
+ L = bound on v part of g;
+*/
+ // Check if m divides L evenly
+ coef_t m = g.get_coef(v);
+ Relation test(known.n_set());
+ F_Exists *e = test.add_exists(); // g is "L >= mv"
+ Variable_ID alpha = e->declare(); // want: "l = m alpha"
+ F_And *a = e->add_and();
+ EQ_Handle h = a->add_EQ();
+ for(Constr_Vars_Iter I(g,false); I; I++)
+ if((*I).var != v) {
+ if((*I).var->kind() != Global_Var)
+ h.update_coef((*I).var, (*I).coef);
+ else
+ h.update_coef(test.get_local((*I).var->get_global_var()), (*I).coef);
+ }
+
+ h.update_const(g.get_const());
+ h.update_coef(alpha,m); // set alpha's coef to m
+ if (!(Gist(test,copy(known)).is_obvious_tautology()))
+ return false;
+ // Check if this lower bound on v implies the strideEQ
+ Relation boundRel = known; // want: "known and l = m v"
+ boundRel.and_with_EQ(g); // add in l = mv
+ Relation strideRel(known.n_set());
+ strideRel.and_with_EQ(strideEQ);
+ return Gist(strideRel, boundRel).is_obvious_tautology();
+}
+
+
+// // Return true if there are no variables in g except wildcards & v
+bool isSimpleStride(const EQ_Handle &g, Variable_ID v) {
+ EQ_Handle gg = g; // should not be necessary, but iterators are
+ // a bit brain-dammaged
+ bool is_simple=true;
+ for(Constr_Vars_Iter cvi(gg, false); cvi && is_simple; cvi++)
+ is_simple = ((*cvi).coef == 0 || (*cvi).var == v
+ || (*cvi).var->kind() == Wildcard_Var);
+ return is_simple;
+}
+
+
+int countStrides(Conjunct *c, Variable_ID v, EQ_Handle &strideEQ,
+ bool &simple) {
+ int strides=0;
+ for(EQ_Iterator G(c); G; G++)
+ for(Constr_Vars_Iter I(*G, true); I; I++)
+ if (((*I).coef != 0) && (*G).get_coef(v) != 0) {
+ strides++;
+ simple = isSimpleStride(*G,v);
+ strideEQ = *G;
+ break;
+ }
+ return strides;
+}
+
+namespace {
+
+bool hasEQ(Relation r, int level) {
+ r.simplify();
+ Variable_ID v = set_var(level);
+ Conjunct *s_conj = r.single_conjunct();
+ for(EQ_Iterator G(s_conj); G; G++)
+ if ((*G).get_coef(v))
+ return true;
+ return false;
+}
+
+
+
+static Relation pickEQ(Relation r, int level) {
+ r.simplify();
+ Variable_ID v = set_var(level);
+ Conjunct *s_conj = r.single_conjunct();
+ for(EQ_Iterator E(s_conj); E; E++)
+ if ((*E).get_coef(v)) {
+ Relation test_rel(r.n_set());
+ test_rel.and_with_EQ(*E);
+ return test_rel;
+ }
+ assert(0);
+ return r;
+}
+
+/* pickBound will return an EQ as a GEQ if it finds one */
+Relation pickBound(Relation r, int level, int UB) {
+ r.simplify();
+ Variable_ID v = set_var(level);
+ Conjunct *s_conj = r.single_conjunct();
+ for(GEQ_Iterator G(s_conj); G; G++) {
+ if ((UB && (*G).get_coef(v) < 0)
+ || (!UB && (*G).get_coef(v) > 0) ) {
+ Relation test_rel(r.n_set());
+ test_rel.and_with_GEQ(*G);
+ return test_rel;
+ }
+ }
+ for(EQ_Iterator E(s_conj); E; E++) {
+ if ((*E).get_coef(v)) {
+ Relation test_rel(r.n_set());
+ test_rel.and_with_GEQ(*E);
+ if ((UB && (*E).get_coef(v) > 0)
+ || (!UB && (*E).get_coef(v) < 0) )
+ test_rel = Complement(test_rel);
+ return test_rel;
+ }
+ }
+ assert(0);
+ return r;
+}
+
+}
+
+Relation pickOverhead(Relation r, int liftTo) {
+ r.simplify();
+ Conjunct *s_conj = r.single_conjunct();
+ for(GEQ_Iterator G(s_conj); G; G++) {
+ Relation test_rel(r.n_set());
+ test_rel.and_with_GEQ(*G);
+ Variable_ID v;
+ coef_t pos = -1;
+ coef_t c= 0;
+ for(Constr_Vars_Iter cvi(*G, false); cvi; cvi++)
+ if ((*cvi).coef && (*cvi).var->kind() == Input_Var
+ && (*cvi).var->get_position() > pos) {
+ v = (*cvi).var;
+ pos = (*cvi).var->get_position();
+ c = (*cvi).coef;
+ }
+#if 0
+ fprintf(DebugFile,"Coef = %d, constraint = %s\n",
+ c,(const char *)test_rel.print_formula_to_string());
+#endif
+ return test_rel;
+ }
+ for(EQ_Iterator E(s_conj); E; E++) {
+ assert(liftTo >= 1);
+ int pos = max((*E).max_tuple_pos(),max_fs_arity(*E)+1);
+
+/* Pick stride constraints only when the variables with stride are outer
+ loop variables */
+ if ((*E).has_wildcards() && pos < liftTo) {
+ Relation test_rel(r.n_set());
+ test_rel.and_with_EQ(*E);
+ return test_rel;
+ }
+ else if (!(*E).has_wildcards() && pos <= liftTo) {
+ Relation test_rel(r.n_set());
+ test_rel.and_with_EQ(*E);
+ test_rel.simplify();
+ test_rel = EQs_to_GEQs(test_rel,true);
+ return pickOverhead(test_rel,liftTo);
+ }
+ }
+ if (code_gen_debug>1) {
+ fprintf(DebugFile,"Could not find overhead:\n");
+ r.prefix_print(DebugFile);
+ }
+ return Relation::True(r.n_set());
+}
+
+
+
+bool hasBound(Relation r, int level, int UB) {
+ r.simplify();
+ Variable_ID v = set_var(level);
+ Conjunct *s_conj = r.single_conjunct();
+ for(GEQ_Iterator G(s_conj); G; G++) {
+ if (UB && (*G).get_coef(v) < 0) return true;
+ if (!UB && (*G).get_coef(v) > 0) return true;
+ }
+ for(EQ_Iterator E(s_conj); E; E++) {
+ if ((*E).get_coef(v)) return true;
+ }
+ return false;
+}
+
+bool find_any_constraint(int s, int level, Relation &kr, int direction,
+ Relation &S, bool approx) {
+ /* If we don't intersect I with restrictions, the combination
+ of S and restrictions can be unsatisfiable, which means that
+ the new split node gets pruned away and we still don't have
+ finite bounds -> infinite recursion. */
+
+ Relation I = projected_nIS[level][s];
+ I = Gist(I,copy(kr));
+ if(approx) I = Approximate(I);
+ if (hasBound(I,level,direction)) {
+ Relation pickfrom;
+ if(has_nonstride_EQ(I,level))
+ pickfrom = pickEQ(I,level);
+ else
+ pickfrom = pickBound(I,level,direction);
+ S = pickOverhead(pickfrom,level);
+ if(S.is_obvious_tautology()) S = Relation::Null();
+ return !S.is_null();
+ }
+ return false;
+}
+
+
+bool has_nonstride_EQ(Relation r, int level) {
+ r.simplify();
+ Variable_ID v = set_var(level);
+ Conjunct *s_conj = r.single_conjunct();
+ for(EQ_Iterator G(s_conj); G; G++)
+ if ((*G).get_coef(v) && !(*G).has_wildcards())
+ return true;
+ return false;
+}
+
+
+Relation minMaxOverhead(Relation r, int level) {
+ r.finalize();
+ r.simplify();
+ Conjunct *s_conj = r.single_conjunct();
+ GEQ_Handle LBs[50],UBs[50];
+ int numLBs = 0;
+ int numUBs = 0;
+ Variable_ID v = set_var(level);
+ for(GEQ_Iterator G(s_conj); G; G++) if ((*G).get_coef(v)) {
+ GEQ_Handle g = *G;
+ if (g.get_coef(v) > 0) LBs[numLBs++] = g;
+ else UBs[numUBs++] = g;
+ }
+ if (numLBs <= 1 && numUBs <= 1) {
+ return Relation::True(r.n_set());
+ }
+ Relation r1(r.n_set());
+ Relation r2(r.n_set());
+ if (numLBs > 1) {
+ // remove a max in lower bound
+ r1.and_with_GEQ(LBs[0]);
+ r2.and_with_GEQ(LBs[1]);
+ r1 = project_onto_levels(Difference(r1,r2),level-1,0);
+ }
+ else {
+ // remove a min in upper bound
+ r1.and_with_GEQ(UBs[0]);
+ r2.and_with_GEQ(UBs[1]);
+ r1 = project_onto_levels(Difference(r1,r2),level-1,0);
+ }
+#if 0
+ fprintf(DebugFile,"Testing %s\n",(const char *)r1.print_formula_to_string());
+ fprintf(DebugFile,"will removed overhead on bounds of t%d: %s\n",level,
+ (const char *)r.print_formula_to_string());
+#endif
+
+ return pickOverhead(r1, -1);
+}
+
+std::pair<EQ_Handle, int> find_simplest_assignment(const Relation &R_, Variable_ID v, const std::vector<CG_outputRepr *> &assigned_on_the_fly) {
+ Relation &R = const_cast<Relation &>(R_);
+ Conjunct *c = R.single_conjunct();
+
+ int min_cost = INT_MAX;
+ EQ_Handle eq;
+ for (EQ_Iterator ei(c->EQs()); ei; ei++)
+ if (!(*ei).has_wildcards() && (*ei).get_coef(v) != 0) {
+ int cost = 0;
+
+ if (abs((*ei).get_coef(v)) != 1)
+ cost += 4; // divide cost
+
+ int num_var = 0;
+ for (Constr_Vars_Iter cvi(*ei); cvi; cvi++)
+ if ((*cvi).var != v) {
+ num_var++;
+ if ((*cvi).var->kind() == Global_Var && (*cvi).var->get_global_var()->arity() > 0) {
+ cost += 10; // function cost
+ }
+ if (abs((*cvi).coef) != 1)
+ cost += 2; // multiply cost
+ if ((*cvi).var->kind() == Input_Var && assigned_on_the_fly[(*cvi).var->get_position()-1] != NULL) {
+ cost += 5; // substituted variable cost
+ }
+ }
+ if ((*ei).get_const() != 0)
+ num_var++;
+ if (num_var > 1)
+ cost += num_var - 1; // addition cost
+
+ if (cost < min_cost) {
+ min_cost = cost;
+ eq = *ei;
+ }
+ }
+
+ return std::make_pair(eq, min_cost);
+}
+
+int max_fs_arity(const Constraint_Handle &c) {
+ int max_arity=0;
+ for(Constr_Vars_Iter cv(c); cv; cv++)
+ if((*cv).var->kind() == Global_Var)
+ max_arity = max(max_arity,(*cv).var->get_global_var()->arity());
+ return max_arity;
+}
+
+}