diff options
Diffstat (limited to 'omegalib/code_gen/src/CG.cc')
| -rw-r--r-- | omegalib/code_gen/src/CG.cc | 1163 | 
1 files changed, 1163 insertions, 0 deletions
| diff --git a/omegalib/code_gen/src/CG.cc b/omegalib/code_gen/src/CG.cc new file mode 100644 index 0000000..42bd172 --- /dev/null +++ b/omegalib/code_gen/src/CG.cc @@ -0,0 +1,1163 @@ +/***************************************************************************** + Copyright (C) 1994-2000 the Omega Project Team + Copyright (C) 2005-2011 Chun Chen + All Rights Reserved. + + Purpose: + CG node classes, used to build AST tree from polyhedra scanning. + + Notes: + Parameter "restriction" is always tighter than "known" since CG_split + node does not correspond to any code for enforcement. This property is + destroyed after hoistGuard since "restriction" is not used anymore. + CG node's children are guaranteed not to be NULL, either NULL child is + removed from the children or the parent node itself becomes NULL. + + History: + 04/20/96 printRepr added by D people. Lei Zhou + 10/24/06 hoistGuard added by chun + 08/03/10 collect CG classes into one place, by Chun Chen + 08/04/10 track dynamically substituted variables in printRepr, by chun + 04/02/11 rewrite the CG node classes, by chun + *****************************************************************************/ + +#include <typeinfo> +#include <assert.h> +#include <omega.h> +#include <code_gen/codegen.h> +#include <code_gen/CG.h> +#include <code_gen/CG_outputBuilder.h> +#include <code_gen/CG_stringBuilder.h> +#include <code_gen/CG_utils.h> +#include <code_gen/codegen_error.h> +#include <stack> +#include <string.h> + +namespace omega { + +extern std::vector<std::vector<int> > smtNonSplitLevels; +extern std::vector<std::vector<std::string> > loopIdxNames; //per stmt +extern std::vector<std::pair<int, std::string> > syncs; + +extern int checkLoopLevel; +extern int stmtForLoopCheck; +extern int upperBoundForLevel; +extern int lowerBoundForLevel; +extern bool fillInBounds; + +//----------------------------------------------------------------------------- +// Class: CG_result +//----------------------------------------------------------------------------- + +CG_outputRepr *CG_result::printRepr(CG_outputBuilder *ocg, +		const std::vector<CG_outputRepr *> &stmts) const { +	return printRepr(1, ocg, stmts, +			std::vector<std::pair<CG_outputRepr *, int> >(num_level(), +					std::make_pair(static_cast<CG_outputRepr *>(NULL), 0))); +} + +std::string CG_result::printString() const { +	CG_stringBuilder ocg; +	std::vector<CG_outputRepr *> stmts(codegen_->xforms_.size()); +	for (int i = 0; i < stmts.size(); i++) +		stmts[i] = new CG_stringRepr("s" + to_string(i)); +	CG_stringRepr *repr = static_cast<CG_stringRepr *>(printRepr(&ocg, stmts)); +	for (int i = 0; i < stmts.size(); i++) +		delete stmts[i]; + +	if (repr != NULL) { +		std::string s = repr->GetString(); +		delete repr; +		return s; +	} else +		return std::string(); +} + +int CG_result::num_level() const { +	return codegen_->num_level(); +} + +//----------------------------------------------------------------------------- +// Class: CG_split +//----------------------------------------------------------------------------- + +CG_result *CG_split::recompute(const BoolSet<> &parent_active, +		const Relation &known, const Relation &restriction) { +	active_ &= parent_active; +	if (active_.empty()) { +		delete this; +		return NULL; +	} + + +	int i = 0; +	while (i < restrictions_.size()) { +		Relation new_restriction = Intersection(copy(restrictions_[i]), +				copy(restriction)); + +		new_restriction.simplify(2, 4); +		//new_restriction.simplify(); +		clauses_[i] = clauses_[i]->recompute(active_, copy(known), +				new_restriction); +		if (clauses_[i] == NULL) { +			restrictions_.erase(restrictions_.begin() + i); +			clauses_.erase(clauses_.begin() + i); +		} else +			i++; +	} + + +	if (restrictions_.size() == 0) { +		delete this; +		return NULL; +	} else +		return this; +} + +int CG_split::populateDepth() { +	int max_depth = 0; +	for (int i = 0; i < clauses_.size(); i++) { +		int t = clauses_[i]->populateDepth(); +		if (t > max_depth) +			max_depth = t; +	} +	return max_depth; +} + +std::pair<CG_result *, Relation> CG_split::liftOverhead(int depth, +		bool propagate_up) { +	for (int i = 0; i < clauses_.size();) { +		std::pair<CG_result *, Relation> result = clauses_[i]->liftOverhead( +				depth, propagate_up); +		if (result.first == NULL) +			clauses_.erase(clauses_.begin() + i); +		else { +			clauses_[i] = result.first; +			if (!result.second.is_obvious_tautology()) +				return std::make_pair(this, result.second); +			i++; +		} + +	} + +	if (clauses_.size() == 0) { +		delete this; +		return std::make_pair(static_cast<CG_result *>(NULL), +				Relation::True(num_level())); +	} else +		return std::make_pair(this, Relation::True(num_level())); +} + +Relation CG_split::hoistGuard() { +	std::vector<Relation> guards; +	for (int i = 0; i < clauses_.size(); i++) +		guards.push_back(clauses_[i]->hoistGuard()); + +	return SimpleHull(guards, true, true); +} + +void CG_split::removeGuard(const Relation &guard) { +	for (int i = 0; i < clauses_.size(); i++) +		clauses_[i]->removeGuard(guard); +} + +std::vector<CG_result *> CG_split::findNextLevel() const { +	std::vector<CG_result *> result; +	for (int i = 0; i < clauses_.size(); i++) { +		CG_split *splt = dynamic_cast<CG_split *>(clauses_[i]); +		if (splt != NULL) { +			std::vector<CG_result *> t = splt->findNextLevel(); +			result.insert(result.end(), t.begin(), t.end()); +		} else +			result.push_back(clauses_[i]); +	} + +	return result; +} + +CG_outputRepr *CG_split::printRepr(int indent, CG_outputBuilder *ocg, +		const std::vector<CG_outputRepr *> &stmts, +		const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const { +	CG_outputRepr *stmtList = NULL; +	std::vector<CG_result *> next_level = findNextLevel(); + +	std::vector<CG_loop *> cur_loops; +	for (int i = 0; i < next_level.size(); i++) { +		CG_loop *lp = dynamic_cast<CG_loop *>(next_level[i]); +		if (lp != NULL) { +			cur_loops.push_back(lp); +		} else { +			stmtList = ocg->StmtListAppend(stmtList, +					loop_print_repr(cur_loops, 0, cur_loops.size(), +							Relation::True(num_level()), NULL, indent, ocg, +							stmts, assigned_on_the_fly)); +			stmtList = ocg->StmtListAppend(stmtList, +					next_level[i]->printRepr(indent, ocg, stmts, +							assigned_on_the_fly)); +			cur_loops.clear(); +		} +	} + +	stmtList = ocg->StmtListAppend(stmtList, +			loop_print_repr(cur_loops, 0, cur_loops.size(), +					Relation::True(num_level()), NULL, indent, ocg, stmts, +					assigned_on_the_fly)); +	return stmtList; +} + +CG_result *CG_split::clone() const { +	std::vector<CG_result *> clauses(clauses_.size()); +	for (int i = 0; i < clauses_.size(); i++) +		clauses[i] = clauses_[i]->clone(); +	return new CG_split(codegen_, active_, restrictions_, clauses); +} + +void CG_split::dump(int indent) const { +	std::string prefix; +	for (int i = 0; i < indent; i++) +		prefix += "  "; +	std::cout << prefix << "SPLIT: " << active_ << std::endl; +	for (int i = 0; i < restrictions_.size(); i++) { +		std::cout << prefix << "restriction: "; +		const_cast<CG_split *>(this)->restrictions_[i].print(); +		clauses_[i]->dump(indent + 1); +	} + +} + +//----------------------------------------------------------------------------- +// Class: CG_loop +//----------------------------------------------------------------------------- + +CG_result *CG_loop::recompute(const BoolSet<> &parent_active, +		const Relation &known, const Relation &restriction) { +	known_ = copy(known); +	restriction_ = copy(restriction); +	active_ &= parent_active; + +	std::vector<Relation> Rs; +	for (BoolSet<>::iterator i = active_.begin(); i != active_.end(); i++) { +		Relation r = Intersection(copy(restriction), +				copy(codegen_->projected_IS_[level_ - 1][*i])); + +		//r.simplify(2, 4); +		r.simplify(); +		if (!r.is_upper_bound_satisfiable()) { +			active_.unset(*i); +			continue; +		} +		Rs.push_back(copy(r)); +	} + +	if (active_.empty()) { +		delete this; +		return NULL; +	} + +	Relation hull = SimpleHull(Rs, true, true); + +	//hull.simplify(2,4); + +	// check if actual loop is needed +	std::pair<EQ_Handle, int> result = find_simplest_assignment(hull, +			hull.set_var(level_)); +	if (result.second < INT_MAX) { +		needLoop_ = false; + +		bounds_ = Relation(hull.n_set()); +		F_Exists *f_exists = bounds_.add_and()->add_exists(); +		F_And *f_root = f_exists->add_and(); +		std::map<Variable_ID, Variable_ID> exists_mapping; +		EQ_Handle h = f_root->add_EQ(); +		for (Constr_Vars_Iter cvi(result.first); cvi; cvi++) { +			Variable_ID v = cvi.curr_var(); +			switch (v->kind()) { +			case Input_Var: +				h.update_coef(bounds_.input_var(v->get_position()), +						cvi.curr_coef()); +				break; +			case Wildcard_Var: { +				Variable_ID v2 = replicate_floor_definition(hull, v, bounds_, +						f_exists, f_root, exists_mapping); +				h.update_coef(v2, cvi.curr_coef()); +				break; +			} +			case Global_Var: { +				Global_Var_ID g = v->get_global_var(); +				Variable_ID v2; +				if (g->arity() == 0) +					v2 = bounds_.get_local(g); +				else +					v2 = bounds_.get_local(g, v->function_of()); +				h.update_coef(v2, cvi.curr_coef()); +				break; +			} +			default: +				assert(false); +			} +		} +		h.update_const(result.first.get_const()); +		bounds_.simplify(); +	} +	// loop iterates more than once, extract bounds now +	else { +		needLoop_ = true; + +		bounds_ = Relation(hull.n_set()); +		F_Exists *f_exists = bounds_.add_and()->add_exists(); +		F_And *f_root = f_exists->add_and(); +		std::map<Variable_ID, Variable_ID> exists_mapping; + +		Relation b = Gist(copy(hull), copy(known), 1); +		bool has_unresolved_bound = false; + +		std::set<Variable_ID> excluded_floor_vars; +		excluded_floor_vars.insert(b.set_var(level_)); +		for (GEQ_Iterator e(b.single_conjunct()->GEQs()); e; e++) +			if ((*e).get_coef(b.set_var(level_)) != 0) { +				bool is_bound = true; +				for (Constr_Vars_Iter cvi(*e, true); cvi; cvi++) { +					std::pair<bool, GEQ_Handle> result = find_floor_definition( +							b, cvi.curr_var(), excluded_floor_vars); +					if (!result.first) { +						is_bound = false; +						has_unresolved_bound = true; +						break; +					} +				} + +				if (!is_bound) +					continue; + +				GEQ_Handle h = f_root->add_GEQ(); +				for (Constr_Vars_Iter cvi(*e); cvi; cvi++) { +					Variable_ID v = cvi.curr_var(); +					switch (v->kind()) { +					case Input_Var: +						h.update_coef(bounds_.input_var(v->get_position()), +								cvi.curr_coef()); +						break; +					case Wildcard_Var: { +						Variable_ID v2 = replicate_floor_definition(b, v, +								bounds_, f_exists, f_root, exists_mapping); +						h.update_coef(v2, cvi.curr_coef()); +						break; +					} +					case Global_Var: { +						Global_Var_ID g = v->get_global_var(); +						Variable_ID v2; +						if (g->arity() == 0) +							v2 = bounds_.get_local(g); +						else +							v2 = bounds_.get_local(g, v->function_of()); +						h.update_coef(v2, cvi.curr_coef()); +						break; +					} +					default: +						assert(false); +					} +				} +				h.update_const((*e).get_const()); +			} + +		if (has_unresolved_bound) { +			b = Approximate(b); +			b.simplify(2, 4); +			//Simplification of Hull +			hull = Approximate(hull); +			hull.simplify(2, 4); +			//end : Anand +			for (GEQ_Iterator e(b.single_conjunct()->GEQs()); e; e++) +				if ((*e).get_coef(b.set_var(level_)) != 0) +					f_root->add_GEQ(*e); +		} +		bounds_.simplify(); +                hull.simplify(2,4); +		// Since current SimpleHull does not support max() upper bound or min() lower bound, +		// we have to forcefully split the loop when hull approximation does not return any bound. +		bool has_lb = false; +		bool has_ub = false; +		for (GEQ_Iterator e = bounds_.single_conjunct()->GEQs(); e; e++) { +			if ((*e).get_coef(bounds_.set_var(level_)) > 0) +				has_lb = true; +			else if ((*e).get_coef(bounds_.set_var(level_)) < 0) +				has_ub = true; +			if (has_lb && has_ub) +				break; +		} + +		if (!has_lb) { +			for (int i = 0; i < Rs.size(); i++) { +				Relation r = Approximate(copy(Rs[i])); +				r.simplify(2, 4); +				for (GEQ_Iterator e = r.single_conjunct()->GEQs(); e; e++) +					if ((*e).get_coef(r.input_var(level_)) > 0) { +						Relation r2 = Relation::True(num_level()); +						r2.and_with_GEQ(*e); +						r2.simplify(); +						std::vector<Relation> restrictions(2); +						restrictions[0] = Complement(copy(r2)); +						restrictions[0].simplify(); +						restrictions[1] = r2; +						std::vector<CG_result *> clauses(2); +						clauses[0] = this; +						clauses[1] = this->clone(); +						CG_result *cgr = new CG_split(codegen_, active_, +								restrictions, clauses); +						cgr = cgr->recompute(active_, copy(known), +								copy(restriction)); +						return cgr; +					} +			} +			for (int i = 0; i < Rs.size(); i++) { +				Relation r = Approximate(copy(Rs[i])); +				r.simplify(2, 4); +				for (EQ_Iterator e = r.single_conjunct()->EQs(); e; e++) +					if ((*e).get_coef(r.input_var(level_)) != 0) { +						Relation r2 = Relation::True(num_level()); +						r2.and_with_GEQ(*e); +						r2.simplify(); +						std::vector<Relation> restrictions(2); +						if ((*e).get_coef(r.input_var(level_)) > 0) { +							restrictions[0] = Complement(copy(r2)); +							restrictions[0].simplify(); +							restrictions[1] = r2; +						} else { +							restrictions[0] = r2; +							restrictions[1] = Complement(copy(r2)); +							restrictions[1].simplify(); +						} +						std::vector<CG_result *> clauses(2); +						clauses[0] = this; +						clauses[1] = this->clone(); +						CG_result *cgr = new CG_split(codegen_, active_, +								restrictions, clauses); +						cgr = cgr->recompute(active_, copy(known), +								copy(restriction)); +						return cgr; +					} +			} +		} else if (!has_ub) { +			for (int i = 0; i < Rs.size(); i++) { +				Relation r = Approximate(copy(Rs[i])); +				r.simplify(2, 4); +				for (GEQ_Iterator e = r.single_conjunct()->GEQs(); e; e++) +					if ((*e).get_coef(r.input_var(level_)) < 0) { +						Relation r2 = Relation::True(num_level()); +						r2.and_with_GEQ(*e); +						r2.simplify(); +						std::vector<Relation> restrictions(2); +						restrictions[1] = Complement(copy(r2)); +						restrictions[1].simplify(); +						restrictions[0] = r2; +						std::vector<CG_result *> clauses(2); +						clauses[0] = this; +						clauses[1] = this->clone(); +						CG_result *cgr = new CG_split(codegen_, active_, +								restrictions, clauses); +						cgr = cgr->recompute(active_, copy(known), +								copy(restriction)); +						return cgr; +					} +			} +			for (int i = 0; i < Rs.size(); i++) { +				Relation r = Approximate(copy(Rs[i])); +				r.simplify(2, 4); +				for (EQ_Iterator e = r.single_conjunct()->EQs(); e; e++) +					if ((*e).get_coef(r.input_var(level_)) != 0) { +						Relation r2 = Relation::True(num_level()); +						r2.and_with_GEQ(*e); +						r2.simplify(); +						std::vector<Relation> restrictions(2); +						if ((*e).get_coef(r.input_var(level_)) > 0) { +							restrictions[0] = Complement(copy(r2)); +							restrictions[0].simplify(); +							restrictions[1] = r2; +						} else { +							restrictions[0] = r2; +							restrictions[1] = Complement(copy(r2)); +							restrictions[1].simplify(); +						} +						std::vector<CG_result *> clauses(2); +						clauses[0] = this; +						clauses[1] = this->clone(); +						CG_result *cgr = new CG_split(codegen_, active_, +								restrictions, clauses); +						cgr = cgr->recompute(active_, copy(known), +								copy(restriction)); +						return cgr; +					} +			} +		} + +		if (!has_lb && !has_ub) +			throw codegen_error( +					"can't find any bound at loop level " + to_string(level_)); +		else if (!has_lb) +			throw codegen_error( +					"can't find lower bound at loop level " +							+ to_string(level_)); +		else if (!has_ub) +			throw codegen_error( +					"can't find upper bound at loop level " +							+ to_string(level_)); +	} +	bounds_.copy_names(hull); +	bounds_.setup_names(); + +	// additional guard/stride condition extraction +	if (needLoop_) { +		Relation cur_known = Intersection(copy(bounds_), copy(known_)); +		cur_known.simplify(); +		hull = Gist(hull, copy(cur_known), 1); + +		std::pair<EQ_Handle, Variable_ID> result = find_simplest_stride(hull, +				hull.set_var(level_)); +		if (result.second != NULL) +			if (abs(result.first.get_coef(hull.set_var(level_))) == 1) { +				F_Exists *f_exists = bounds_.and_with_and()->add_exists(); +				F_And *f_root = f_exists->add_and(); +				std::map<Variable_ID, Variable_ID> exists_mapping; +				EQ_Handle h = f_root->add_EQ(); +				for (Constr_Vars_Iter cvi(result.first); cvi; cvi++) { +					Variable_ID v = cvi.curr_var(); +					switch (v->kind()) { +					case Input_Var: +						h.update_coef(bounds_.input_var(v->get_position()), +								cvi.curr_coef()); +						break; +					case Wildcard_Var: { +						Variable_ID v2; +						if (v == result.second) +							v2 = f_exists->declare(); +						else +							v2 = replicate_floor_definition(hull, v, bounds_, +									f_exists, f_root, exists_mapping); +						h.update_coef(v2, cvi.curr_coef()); +						break; +					} +					case Global_Var: { +						Global_Var_ID g = v->get_global_var(); +						Variable_ID v2; +						if (g->arity() == 0) +							v2 = bounds_.get_local(g); +						else +							v2 = bounds_.get_local(g, v->function_of()); +						h.update_coef(v2, cvi.curr_coef()); +						break; +					} +					default: +						assert(false); +					} +				} +				h.update_const(result.first.get_const()); +			} else { +				// since gist is not powerful enough on modular constraints for now, +				// make an educated guess +				coef_t stride = abs(result.first.get_coef(result.second)) +						/ gcd(abs(result.first.get_coef(result.second)), +								abs( +										result.first.get_coef( +												hull.set_var(level_)))); + +				Relation r1(hull.n_inp()); +				F_Exists *f_exists = r1.add_and()->add_exists(); +				F_And *f_root = f_exists->add_and(); +				std::map<Variable_ID, Variable_ID> exists_mapping; +				EQ_Handle h = f_root->add_EQ(); +				for (Constr_Vars_Iter cvi(result.first); cvi; cvi++) { +					Variable_ID v = cvi.curr_var(); +					switch (v->kind()) { +					case Input_Var: +						h.update_coef(r1.input_var(v->get_position()), +								cvi.curr_coef()); +						break; +					case Wildcard_Var: { +						Variable_ID v2; +						if (v == result.second) +							v2 = f_exists->declare(); +						else +							v2 = replicate_floor_definition(hull, v, r1, +									f_exists, f_root, exists_mapping); +						h.update_coef(v2, cvi.curr_coef()); +						break; +					} +					case Global_Var: { +						Global_Var_ID g = v->get_global_var(); +						Variable_ID v2; +						if (g->arity() == 0) +							v2 = r1.get_local(g); +						else +							v2 = r1.get_local(g, v->function_of()); +						h.update_coef(v2, cvi.curr_coef()); +						break; +					} +					default: +						assert(false); +					} +				} +				h.update_const(result.first.get_const()); +				r1.simplify(); + +				bool guess_success = false; +				for (GEQ_Iterator e(bounds_.single_conjunct()->GEQs()); e; e++) +					if ((*e).get_coef(bounds_.set_var(level_)) == 1) { +						Relation r2(hull.n_inp()); +						F_Exists *f_exists = r2.add_and()->add_exists(); +						F_And *f_root = f_exists->add_and(); +						std::map<Variable_ID, Variable_ID> exists_mapping; +						EQ_Handle h = f_root->add_EQ(); +						h.update_coef(f_exists->declare(), stride); +						for (Constr_Vars_Iter cvi(*e); cvi; cvi++) { +							Variable_ID v = cvi.curr_var(); +							switch (v->kind()) { +							case Input_Var: +								h.update_coef(r2.input_var(v->get_position()), +										cvi.curr_coef()); +								break; +							case Wildcard_Var: { +								Variable_ID v2 = replicate_floor_definition( +										hull, v, r2, f_exists, f_root, +										exists_mapping); +								h.update_coef(v2, 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(false); +							} +						} +						h.update_const((*e).get_const()); +						r2.simplify(); + +						if (Gist(copy(r1), +								Intersection(copy(cur_known), copy(r2)), 1).is_obvious_tautology() +								&& Gist(copy(r2), +										Intersection(copy(cur_known), copy(r1)), +										1).is_obvious_tautology()) { +							bounds_ = Intersection(bounds_, r2); +							bounds_.simplify(); +							guess_success = true; +							break; +						} +					} + +				// this is really a stride with non-unit coefficient for this loop variable +				if (!guess_success) { +					// TODO: for stride ax = b mod n it might be beneficial to +					//       generate modular linear equation solver code for +					//       runtime to get the starting position in printRepr, +					//       and stride would be n/gcd(|a|,n), thus this stride +					//       can be put into bounds_ too. +				} + +			} + +		hull = Project(hull, hull.set_var(level_)); +		hull.simplify(2, 4); +		guard_ = Gist(hull, Intersection(copy(bounds_), copy(known_)), 1); +	} +	// don't generate guard for non-actual loop, postpone it. otherwise +	// redundant if-conditions might be generated since for-loop semantics +	// includes implicit comparison checking.  -- by chun 09/14/10 +	else +		guard_ = Relation::True(num_level()); +	guard_.copy_names(bounds_); +	guard_.setup_names(); + +        //guard_.simplify();   +	// recursively down the AST +	Relation new_known = Intersection(copy(known), +			Intersection(copy(bounds_), copy(guard_))); +	new_known.simplify(2, 4); +	Relation new_restriction = Intersection(copy(restriction), +			Intersection(copy(bounds_), copy(guard_))); +	new_restriction.simplify(2, 4); +	body_ = body_->recompute(active_, new_known, new_restriction); +	if (body_ == NULL) { +		delete this; +		return NULL; +	} else +		return this; +} + +int CG_loop::populateDepth() { +	int depth = body_->populateDepth(); +	if (needLoop_) +		depth_ = depth + 1; +	else +		depth_ = depth; +	return depth_; +} + +std::pair<CG_result *, Relation> CG_loop::liftOverhead(int depth, +		bool propagate_up) { +	if (depth_ > depth) { +		assert(propagate_up == false); +		std::pair<CG_result *, Relation> result = body_->liftOverhead(depth, +				false); +		body_ = result.first; +		return std::make_pair(this, Relation::True(num_level())); +	} else { // (depth_ <= depth) +		if (propagate_up) { +			Relation r = pick_one_guard(guard_, level_); +			if (!r.is_obvious_tautology()) +				return std::make_pair(this, r); +		} + +		std::pair<CG_result *, Relation> result; +		if (propagate_up || needLoop_) +			result = body_->liftOverhead(depth, true); +		else +			result = body_->liftOverhead(depth, false); +		body_ = result.first; +		if (result.second.is_obvious_tautology()) +			return std::make_pair(this, result.second); + +		// loop is an assignment, replace this loop variable in overhead condition +		if (!needLoop_) { +			result.second = Intersection(result.second, copy(bounds_)); +			result.second = Project(result.second, +					result.second.set_var(level_)); +			result.second.simplify(2, 4); +		} + + +		int max_level = 0; +		bool has_wildcard = false; +		bool direction = true; +		for (EQ_Iterator e(result.second.single_conjunct()->EQs()); e; e++) +			if ((*e).has_wildcards()) { +				if (has_wildcard) +					assert(false); +				else +					has_wildcard = true; +				for (Constr_Vars_Iter cvi(*e); cvi; cvi++) +					if (cvi.curr_var()->kind() == Input_Var +							&& cvi.curr_var()->get_position() > max_level) +						max_level = cvi.curr_var()->get_position(); +			} else +				assert(false); + +		if (!has_wildcard) { +			int num_simple_geq = 0; +			for (GEQ_Iterator e(result.second.single_conjunct()->GEQs()); e; +					e++) +				if (!(*e).has_wildcards()) { +					num_simple_geq++; +					for (Constr_Vars_Iter cvi(*e); cvi; cvi++) +						if (cvi.curr_var()->kind() == Input_Var +								&& cvi.curr_var()->get_position() > max_level) { +							max_level = cvi.curr_var()->get_position(); +							direction = (cvi.curr_coef() < 0) ? true : false; +						} +				} else { +					has_wildcard = true; +					for (Constr_Vars_Iter cvi(*e); cvi; cvi++) +						if (cvi.curr_var()->kind() == Input_Var +								&& cvi.curr_var()->get_position() > max_level) { +							max_level = cvi.curr_var()->get_position(); +						} +				} +			assert( +					(has_wildcard && num_simple_geq == 0) || (!has_wildcard && num_simple_geq == 1)); +		} + +		// check if this is the top loop level for splitting for this overhead +		if (!propagate_up || (has_wildcard && max_level == level_ - 1) +				|| (!has_wildcard && max_level == level_)) { +			std::vector<Relation> restrictions(2); +			std::vector<CG_result *> clauses(2); +			int saved_num_level = num_level(); +			if (has_wildcard || direction) { +				restrictions[1] = Complement(copy(result.second)); +				restrictions[1].simplify(); +				clauses[1] = this->clone(); +				restrictions[0] = result.second; +				clauses[0] = this; +			} else { +				restrictions[0] = Complement(copy(result.second)); +				restrictions[0].simplify(); +				clauses[0] = this->clone(); +				restrictions[1] = result.second; +				clauses[1] = this; +			} +			CG_result *cgr = new CG_split(codegen_, active_, restrictions, +					clauses); +			CG_result *new_cgr = cgr->recompute(active_, copy(known_), +					copy(restriction_)); +			new_cgr->populateDepth(); +			assert(new_cgr==cgr); +			if (static_cast<CG_split *>(new_cgr)->clauses_.size() == 1) +				// infinite recursion detected, bail out +				return std::make_pair(new_cgr, Relation::True(saved_num_level)); +			else +				return cgr->liftOverhead(depth, propagate_up); +		} else +			return std::make_pair(this, result.second); +	} +} + +Relation CG_loop::hoistGuard() { + +	Relation r = body_->hoistGuard(); + +	// TODO: should bookkeep catched contraints in loop output as enforced and check if anything missing +	// if (!Gist(copy(b), copy(enforced)).is_obvious_tautology()) { +	//   fprintf(stderr, "need to generate extra guard inside the loop\n"); +	// } + +	  if (!needLoop_) +	    r = Intersection(r, copy(bounds_)); +	  r = Project(r, r.set_var(level_)); +	  r = Gist(r, copy(known_), 1); + +	  Relation eliminate_existentials_r; +	  Relation eliminate_existentials_known; + +	  eliminate_existentials_r = copy(r); +	  if (!r.is_obvious_tautology()) { +		  eliminate_existentials_r = Approximate(copy(r)); +		  eliminate_existentials_r.simplify(2,4); +		  eliminate_existentials_known = Approximate(copy(known_)); +		  eliminate_existentials_known.simplify(2,4); + +		  eliminate_existentials_r = Gist( eliminate_existentials_r, eliminate_existentials_known, 1); +	  } +           + +	  if (!eliminate_existentials_r.is_obvious_tautology()) { +	 // if (!r.is_obvious_tautology()) { +	    body_->removeGuard(r); +	    guard_ = Intersection(guard_, copy(r)); +	    guard_.simplify(); +	  } + +	  return guard_; + +	//   return ifList; +	// } + + +} + +void CG_loop::removeGuard(const Relation &guard) { +	known_ = Intersection(known_, copy(guard)); +	known_.simplify(); + +	guard_ = Gist(guard_, copy(known_), 1); +	guard_.copy_names(known_); +	guard_.setup_names(); +} + +CG_outputRepr *CG_loop::printRepr(int indent, CG_outputBuilder *ocg, +		const std::vector<CG_outputRepr *> &stmts, +		const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const { +	return printRepr(true, indent, ocg, stmts, assigned_on_the_fly); +} + +CG_outputRepr *CG_loop::printRepr(bool do_print_guard, int indent, +		CG_outputBuilder *ocg, const std::vector<CG_outputRepr *> &stmts, +		const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const { +	CG_outputRepr *guardRepr; +	if (do_print_guard) +		guardRepr = output_guard(ocg, guard_, assigned_on_the_fly); +	else +		guardRepr = NULL; + +	Relation cur_known = Intersection(copy(known_), copy(guard_)); +	cur_known.simplify(); +	if (needLoop_) { + +		if (checkLoopLevel) +			if (level_ == checkLoopLevel) +				if (active_.get(stmtForLoopCheck)) +					fillInBounds = true; + +		CG_outputRepr *ctrlRepr = output_loop(ocg, bounds_, level_, cur_known, +				assigned_on_the_fly); + +		fillInBounds = false; + +		CG_outputRepr *bodyRepr = body_->printRepr( +				(guardRepr == NULL) ? indent + 1 : indent + 2, ocg, stmts, +				assigned_on_the_fly); +		CG_outputRepr * loopRepr; + +		if (guardRepr == NULL) +			loopRepr = ocg->CreateLoop(indent, ctrlRepr, bodyRepr); +		else +			loopRepr = ocg->CreateLoop(indent + 1, ctrlRepr, bodyRepr); + +		if (!smtNonSplitLevels.empty()) { +			bool blockLoop = false; +			bool threadLoop = false; +			bool sync = false; +			int firstActiveStmt = -1; +			for (int s = 0; s < active_.size(); s++) { +				if (active_.get(s)) { +					if (firstActiveStmt < 0) +						firstActiveStmt = s; +					//We assume smtNonSplitLevels is only used to mark the first of +					//the block or thread loops to be reduced in CUDA-CHiLL. Here we +					//place some comments to help with final code generation. +					//int idx = smtNonSplitLevels[s].index(level_); + +					if (s < smtNonSplitLevels.size()) { +						if (smtNonSplitLevels[s].size() > 0) +							if (smtNonSplitLevels[s][0] == level_) { +								blockLoop = true; +							} +						//Assume every stmt marked with a thread loop index also has a block loop idx +						if (smtNonSplitLevels[s].size() > 1) +							if (smtNonSplitLevels[s][1] == level_) { +								threadLoop = true; +							} +					} +				} +			} +			if (blockLoop && threadLoop) { +				fprintf(stderr, +						"Warning, have %d level more than once in smtNonSplitLevels\n", +						level_); +				threadLoop = false; +			} +			std::string preferredIdx; +			if (loopIdxNames.size() +					&& (level_ / 2) - 1 < loopIdxNames[firstActiveStmt].size()) +				preferredIdx = loopIdxNames[firstActiveStmt][(level_ / 2) - 1]; +			for (int s = 0; s < active_.size(); s++) { +				if (active_.get(s)) { +					for (int i = 0; i < syncs.size(); i++) { +						if (syncs[i].first == s +								&& strcmp(syncs[i].second.c_str(), +										preferredIdx.c_str()) == 0) { +							sync = true; +							//printf("FOUND SYNC\n"); +						} + +					} +				} +		 +			} +			if (threadLoop || blockLoop || preferredIdx.length() != 0) { +				char buf[1024]; +				std::string loop; +				if (blockLoop) +					loop = "blockLoop "; +				if (threadLoop) +					loop = "threadLoop "; +				if (preferredIdx.length() != 0 && sync) { +					sprintf(buf, "~cuda~ %spreferredIdx: %s sync", loop.c_str(), +							preferredIdx.c_str()); +				} else if (preferredIdx.length() != 0) { +					sprintf(buf, "~cuda~ %spreferredIdx: %s", loop.c_str(), +							preferredIdx.c_str()); +				} else { +					sprintf(buf, "~cuda~ %s", loop.c_str()); +				} + + +				loopRepr = ocg->CreateAttribute(loopRepr, buf); +			} + +		} +		if (guardRepr == NULL) +			return loopRepr; +		else +			return ocg->CreateIf(indent, guardRepr, loopRepr, NULL); +	} else { +		std::pair<CG_outputRepr *, std::pair<CG_outputRepr *, int> > result = +				output_assignment(ocg, bounds_, level_, cur_known, +						assigned_on_the_fly); +		guardRepr = ocg->CreateAnd(guardRepr, result.first); + +		if (result.second.second < CodeGen::var_substitution_threshold) { +			std::vector<std::pair<CG_outputRepr *, int> > atof = +					assigned_on_the_fly; +			atof[level_ - 1] = result.second; +			CG_outputRepr *bodyRepr = body_->printRepr( +					(guardRepr == NULL) ? indent : indent + 1, ocg, stmts, +					atof); +			delete atof[level_ - 1].first; +			if (guardRepr == NULL) +				return bodyRepr; +			else +				return ocg->CreateIf(indent, guardRepr, bodyRepr, NULL); +		} else { +			CG_outputRepr *assignRepr = ocg->CreateAssignment( +					(guardRepr == NULL) ? indent : indent + 1, +					output_ident(ocg, bounds_, +							const_cast<CG_loop *>(this)->bounds_.set_var( +									level_), assigned_on_the_fly), +					result.second.first); +			CG_outputRepr *bodyRepr = body_->printRepr( +					(guardRepr == NULL) ? indent : indent + 1, ocg, stmts, +					assigned_on_the_fly); +			if (guardRepr == NULL) +				return ocg->StmtListAppend(assignRepr, bodyRepr); +			else +				return ocg->CreateIf(indent, guardRepr, +						ocg->StmtListAppend(assignRepr, bodyRepr), NULL); +		} + +	} +} + +CG_result *CG_loop::clone() const { +	return new CG_loop(codegen_, active_, level_, body_->clone()); +} + +void CG_loop::dump(int indent) const { +	std::string prefix; +	for (int i = 0; i < indent; i++) +		prefix += "  "; +	std::cout << prefix << "LOOP (level " << level_ << "): " << active_ +			<< std::endl; +	std::cout << prefix << "known: "; +	const_cast<CG_loop *>(this)->known_.print(); +	std::cout << prefix << "restriction: "; +	const_cast<CG_loop *>(this)->restriction_.print(); +	std::cout << prefix << "bounds: "; +	const_cast<CG_loop *>(this)->bounds_.print(); +	std::cout << prefix << "guard: "; +	const_cast<CG_loop *>(this)->guard_.print(); +	body_->dump(indent + 1); +} + +//----------------------------------------------------------------------------- +// Class: CG_leaf +//----------------------------------------------------------------------------- + +CG_result* CG_leaf::recompute(const BoolSet<> &parent_active, +		const Relation &known, const Relation &restriction) { +	active_ &= parent_active; +	known_ = copy(known); + +	guards_.clear(); +	for (BoolSet<>::iterator i = active_.begin(); i != active_.end(); i++) { +		Relation r = Intersection( +				copy(codegen_->projected_IS_[num_level() - 1][*i]), +				copy(restriction)); +		r.simplify(2, 4); +		if (!r.is_upper_bound_satisfiable()) +			active_.unset(*i); +		else { +			r = Gist(r, copy(known), 1); +			if (!r.is_obvious_tautology()) { +				guards_[*i] = r; +				guards_[*i].copy_names(known); +				guards_[*i].setup_names(); +			} +		} +	} + + +	if (active_.empty()) { +		delete this; +		return NULL; +	} else +		return this; +} + +std::pair<CG_result *, Relation> CG_leaf::liftOverhead(int depth, bool) { +	if (depth == 0) +		return std::make_pair(this, Relation::True(num_level())); + +	for (std::map<int, Relation>::iterator i = guards_.begin(); +			i != guards_.end(); i++) { +		Relation r = pick_one_guard(i->second); +		if (!r.is_obvious_tautology()) { +			bool has_wildcard = false; +			int max_level = 0; +			for (EQ_Iterator e(r.single_conjunct()->EQs()); e; e++) { +				if ((*e).has_wildcards()) +					has_wildcard = true; +				for (Constr_Vars_Iter cvi(*e); cvi; cvi++) +					if (cvi.curr_var()->kind() == Input_Var +							&& cvi.curr_var()->get_position() > max_level) +						max_level = cvi.curr_var()->get_position(); +			} +			for (GEQ_Iterator e(r.single_conjunct()->GEQs()); e; e++) { +				if ((*e).has_wildcards()) +					has_wildcard = true; +				for (Constr_Vars_Iter cvi(*e); cvi; cvi++) +					if (cvi.curr_var()->kind() == Input_Var +							&& cvi.curr_var()->get_position() > max_level) +						max_level = cvi.curr_var()->get_position(); +			} + +			if (!(has_wildcard && max_level == codegen_->num_level())) +				return std::make_pair(this, r); +		} +	} + +	return std::make_pair(this, Relation::True(num_level())); +} + +Relation CG_leaf::hoistGuard() { +	std::vector<Relation> guards; +	for (BoolSet<>::iterator i = active_.begin(); i != active_.end(); i++) { +		std::map<int, Relation>::iterator j = guards_.find(*i); +		if (j == guards_.end()) { +			Relation r = Relation::True(num_level()); +			r.copy_names(known_); +			r.setup_names(); +			return r; +		} else { +			guards.push_back(j->second); +		} +	} + +	return SimpleHull(guards, true, true); +} + +void CG_leaf::removeGuard(const Relation &guard) { +	known_ = Intersection(known_, copy(guard)); +	known_.simplify(); + +	std::map<int, Relation>::iterator i = guards_.begin(); +	while (i != guards_.end()) { +		i->second = Gist(i->second, copy(known_), 1); +		if (i->second.is_obvious_tautology()) +			guards_.erase(i++); +		else +			++i; +	} +} + +CG_outputRepr *CG_leaf::printRepr(int indent, CG_outputBuilder *ocg, +		const std::vector<CG_outputRepr *> &stmts, +		const std::vector<std::pair<CG_outputRepr *, int> > &assigned_on_the_fly) const { +	return leaf_print_repr(active_, guards_, NULL, known_, indent, ocg, +			codegen_->remap_, codegen_->xforms_, stmts, assigned_on_the_fly); +} + +CG_result *CG_leaf::clone() const { +	return new CG_leaf(codegen_, active_); +} + +void CG_leaf::dump(int indent) const { +	std::string prefix; +	for (int i = 0; i < indent; i++) +		prefix += "  "; +	std::cout << prefix << "LEAF: " << active_ << std::endl; +	std::cout << prefix << "known: "; +	const_cast<CG_leaf *>(this)->known_.print(); +	for (std::map<int, Relation>::const_iterator i = guards_.begin(); +			i != guards_.end(); i++) { +		std::cout << prefix << "guard #" << i->first << ":"; +		const_cast<Relation &>(i->second).print(); +	} +} + +} | 
