diff options
| author | Tuowen Zhao <ztuowen@gmail.com> | 2016-09-19 21:14:58 +0000 | 
|---|---|---|
| committer | Tuowen Zhao <ztuowen@gmail.com> | 2016-09-19 21:14:58 +0000 | 
| commit | 210f77d2c32f14d2e99577fd3c9842bb19d47e50 (patch) | |
| tree | 5edb327c919b8309e301c3440fb6668a0075c8ef /lib/codegen/src/codegen.cc | |
| parent | a66ce5cd670c4d3c0dc449720f5bc45dd4c281b8 (diff) | |
| download | chill-210f77d2c32f14d2e99577fd3c9842bb19d47e50.tar.gz chill-210f77d2c32f14d2e99577fd3c9842bb19d47e50.tar.bz2 chill-210f77d2c32f14d2e99577fd3c9842bb19d47e50.zip | |
Moved most modules into lib
Diffstat (limited to 'lib/codegen/src/codegen.cc')
| -rwxr-xr-x | lib/codegen/src/codegen.cc | 378 | 
1 files changed, 378 insertions, 0 deletions
| diff --git a/lib/codegen/src/codegen.cc b/lib/codegen/src/codegen.cc new file mode 100755 index 0000000..92ca702 --- /dev/null +++ b/lib/codegen/src/codegen.cc @@ -0,0 +1,378 @@ +/***************************************************************************** + Copyright (C) 1994-2000 the Omega Project Team + Copyright (C) 2005-2011 Chun Chen + All Rights Reserved. + + Purpose: +   CodeGen class as entry point for code generation. + + Notes: +   Loop variable name prefix should not cause any possible name conflicts + with original loop variables wrapped in statement holder. This guarantees + that variable substitution done correctly in the generated code. + + History: +   04/24/96 MMGenerateCode, added by Fortran D people. Lei Zhou +   09/17/08 loop overhead removal based on actual nesting depth -- by chun +   03/05/11 fold MMGenerateCode into CodeGen class, Chun Chen +*****************************************************************************/ + +#include <typeinfo> +#include <omega.h> +#include <basic/util.h> +#include <math.h> +#include <vector> +#include <algorithm> + +#include <code_gen/CG.h> +#include <code_gen/codegen.h> +#include <code_gen/CG_outputBuilder.h> +#include <code_gen/codegen_error.h> + +namespace omega { + +const std::string CodeGen::loop_var_name_prefix = "t"; +const int CodeGen::var_substitution_threshold = 10; + +//Anand--adding stuff to make Chun's code work with Gabe's +std::vector< std::vector<int> > smtNonSplitLevels; +std::vector< std::vector<std::string> > loopIdxNames;//per stmt +std::vector< std::pair<int, std::string> > syncs; + + + +CodeGen::CodeGen(const std::vector<Relation> &xforms, const std::vector<Relation> &IS, const Relation &known, std::vector< std::vector<int> > smtNonSplitLevels_ , std::vector< std::vector<std::string> > loopIdxNames_,  std::vector< std::pair<int, std::string> > syncs_) { +  // check for sanity of parameters +  int num_stmt = IS.size(); +  if (xforms.size() != num_stmt) +    throw std::invalid_argument("number of iteration spaces does not match number of transformations"); +  known_ = copy(known); +  if (known_.n_out() != 0) +    throw std::invalid_argument("known condition must be a set relation"); +  if (known_.is_null()) +    known_ = Relation::True(0); +  else +    known_.simplify(2, 4); +  if (!known_.is_upper_bound_satisfiable()) +    return; +  if (known_.number_of_conjuncts() > 1) +    throw std::invalid_argument("only one conjunct allowed in known condition"); +  xforms_ = xforms; +  for (int i = 0; i < num_stmt; i++) { +    xforms_[i].simplify(); +    if (!xforms_[i].has_single_conjunct()) +      throw std::invalid_argument("mapping relation must have only one conjunct"); +    if (xforms_[i].n_inp() != IS[i].n_inp() || IS[i].n_out() != 0) +      throw std::invalid_argument("illegal iteration space or transformation arity"); +  } + + +  //protonu-- +  //easier to handle this as a global +  smtNonSplitLevels = smtNonSplitLevels_; +  syncs = syncs_; +  loopIdxNames = loopIdxNames_; +  //end-protonu + + + +  // find the maximum iteration space dimension we are going to operate on +  int num_level = known_.n_inp(); +  for (int i = 0; i < num_stmt; i++) +    if (xforms_[i].n_out() > num_level) +      num_level = xforms_[i].n_out(); +  known_ = Extend_Set(known_, num_level-known_.n_inp()); +  for (int i = 1; i <= num_level; i++) +    known_.name_set_var(i, loop_var_name_prefix + to_string(i)); +  known_.setup_names(); + +  // split disjoint conjunctions in original iteration spaces +  std::vector<Relation> new_IS; +  for (int i = 0; i < num_stmt; i++) { +    for (int j = 1; j <= IS[i].n_inp(); j++) +      xforms_[i].name_input_var(j, const_cast<std::vector<Relation> &>(IS)[i].input_var(j)->name()); +    for (int j = 1; j <= xforms_[i].n_out(); j++) +      xforms_[i].name_output_var(j, loop_var_name_prefix + to_string(j)); +    xforms_[i].setup_names(); + +    Relation R = Range(Restrict_Domain(copy(xforms_[i]), copy(IS[i]))); +    R = Intersection(Extend_Set(R, num_level-R.n_inp()), copy(known_)); +    R.simplify(2, 4); +    if (R.is_inexact()) +      throw codegen_error("cannot generate code for inexact iteration spaces"); + +    while(R.is_upper_bound_satisfiable()) { +      DNF *dnf = R.query_DNF(); +      DNF_Iterator c(dnf); +      Relation R2 = Relation(R, *c); +      R2.simplify(); +      new_IS.push_back(copy(R2)); +      remap_.push_back(i); +      c.next(); +      if (!c.live())  +        break; +      Relation remainder(R, *c); +      c.next(); +      while (c.live()) { +        remainder = Union(remainder, Relation(R, *c)); +        c.next(); +      } +      R = Difference(remainder, R2); +      R.simplify(2, 4); +    } +  } + +  // number of new statements after splitting +  num_stmt = new_IS.size(); +  if(!smtNonSplitLevels.empty()) +      smtNonSplitLevels.resize(num_stmt); +  // assign a dummy value to loops created for the purpose of expanding to maximum dimension +  for (int i = 0; i < num_stmt; i++) { +    if (xforms[remap_[i]].n_out() < num_level) { +      F_And *f_root = new_IS[i].and_with_and(); +      for (int j = xforms[remap_[i]].n_out()+1; j <= num_level; j++) { +        EQ_Handle h = f_root->add_EQ(); +        h.update_coef(new_IS[i].set_var(j), 1); +        h.update_const(posInfinity); +      } +      new_IS[i].simplify(); +    }    +  } + +  // calculate projected subspaces for each loop level once and save for CG tree manipulation later +  projected_IS_ = std::vector<std::vector<Relation> >(num_level); +  for (int i = 0; i < num_level; i++) +    projected_IS_[i] = std::vector<Relation>(num_stmt); +  for (int i = 0; i < num_stmt; i++) { +    if (num_level > 0) +      projected_IS_[num_level-1][i] = new_IS[i]; +    for (int j = num_level-1; j >= 1; j--) { +      projected_IS_[j-1][i] = Project(copy(projected_IS_[j][i]), j+1, Set_Var); +      projected_IS_[j-1][i].simplify(2, 4); +    } +  } +} + + +CG_result *CodeGen::buildAST(int level, const BoolSet<> &active, bool split_on_const, const Relation &restriction) { +  if (level > num_level()) +    return new CG_leaf(this, active); + +  int num_active_stmt = active.num_elem(); +  if (num_active_stmt == 0) +    return NULL; +  else if (num_active_stmt == 1) +    return new CG_loop(this, active, level, buildAST(level+1, active, true, restriction)); + +  // use estimated constant bounds for fast non-overlap iteration space splitting +  if (split_on_const) { +    std::vector<std::pair<std::pair<coef_t, coef_t>, int> > bounds; + +    for (BoolSet<>::const_iterator i = active.begin(); i != active.end(); i++) { +      Relation r = Intersection(copy(projected_IS_[level-1][*i]), copy(restriction)); +      r.simplify(2, 4); +      if (!r.is_upper_bound_satisfiable()) +        continue; +      coef_t lb, ub; +      r.single_conjunct()->query_variable_bounds(r.set_var(level),lb,ub); +      bounds.push_back(std::make_pair(std::make_pair(lb, ub), *i)); +    } +    sort(bounds.begin(), bounds.end()); + +    std::vector<Relation> split_cond; +    std::vector<CG_result *> split_child; + +    coef_t prev_val = -posInfinity; +    coef_t next_val = bounds[0].first.second; +    BoolSet<> next_active(active.size()); +    int i = 0; +    while (i < bounds.size()) { +      if (bounds[i].first.first <= next_val) { +        next_active.set(bounds[i].second); +        next_val = max(next_val, bounds[i].first.second); +        i++; +      } +      else { +        Relation r(num_level()); +        F_And *f_root = r.add_and(); +        if (prev_val != -posInfinity) { +          GEQ_Handle h = f_root->add_GEQ(); +          h.update_coef(r.set_var(level), 1); +          h.update_const(-prev_val-1); +        } +        if (next_val != posInfinity) { +          GEQ_Handle h = f_root->add_GEQ(); +          h.update_coef(r.set_var(level), -1); +          h.update_const(next_val); +        } +        r.simplify(); + +        Relation new_restriction = Intersection(copy(r), copy(restriction)); +        new_restriction.simplify(2, 4); +        CG_result *child = buildAST(level, next_active, false, new_restriction); +        if (child != NULL) { +          split_cond.push_back(copy(r)); +          split_child.push_back(child); +        } +        next_active.unset_all(); +        prev_val = next_val; +        next_val = bounds[i].first.second; +      } +    } +    if (!next_active.empty()) { +      Relation r = Relation::True(num_level()); +      if (prev_val != -posInfinity) { +        F_And *f_root = r.and_with_and(); +        GEQ_Handle h = f_root->add_GEQ(); +        h.update_coef(r.set_var(level), 1); +        h.update_const(-prev_val-1); +        r.simplify(); +      } +      Relation new_restriction = Intersection(copy(r), copy(restriction)); +      new_restriction.simplify(2, 4); +      CG_result *child = buildAST(level, next_active, false, new_restriction); +      if (child != NULL) { +        split_cond.push_back(copy(r)); +        split_child.push_back(child); +      } +    } + +    if (split_child.size() == 0) +      return NULL; +    else if (split_child.size() == 1) +      return split_child[0]; +    else +      return new CG_split(this, active, split_cond, split_child); +  } +  // check bound conditions exhaustively for non-overlap iteration space splitting +  else { +    std::vector<Relation> Rs(active.size()); +    for (BoolSet<>::const_iterator i = active.begin(); i != active.end(); i++) { +      Rs[*i] = Intersection(Approximate(copy(projected_IS_[level-1][*i])), copy(restriction)); +      Rs[*i].simplify(2, 4); +    } +    Relation hull = SimpleHull(Rs); + +    //protonu-warn Chun about this change +  //This does some fancy splitting of statements into loops with the +  //fewest dimentions, but that's not necessarily what we want when +  //code-gening for CUDA. smtNonSplitLevels keeps track per-statment of +  //the levels that should not be split on. +  bool checkForSplits = true; + for (BoolSet<>::const_iterator i = active.begin(); i != active.end(); i++) { +      if(*i  < smtNonSplitLevels.size()) +         for(int k = 0; k <smtNonSplitLevels[*i].size();  k++) +           if(smtNonSplitLevels[*i][k] == (level-2)){ +               checkForSplits = false; +              break; +      } +    } +   + + + +    for (BoolSet<>::const_iterator i = active.begin(); i != active.end() && checkForSplits; i++) { +      Relation r = Gist(copy(Rs[*i]), copy(hull), 1); +      if (r.is_obvious_tautology()) +        continue; +      r = EQs_to_GEQs(r); + +      for (GEQ_Iterator e = r.single_conjunct()->GEQs(); e; e++) { +        if ((*e).has_wildcards()) +          continue; +             +        Relation cond = Relation::True(num_level()); +        BoolSet<> first_chunk(active.size()); +        BoolSet<> second_chunk(active.size()); + +        if ((*e).get_coef(hull.set_var(level)) > 0) { +          cond.and_with_GEQ(*e); +          cond = Complement(cond);; +          cond.simplify(); +          second_chunk.set(*i); +        } +        else if ((*e).get_coef(hull.set_var(level)) < 0) { +          cond.and_with_GEQ(*e); +          cond.simplify(); +          first_chunk.set(*i); +        } +        else +          continue; + +        bool is_proper_split_cond = true; +        for (BoolSet<>::const_iterator j = active.begin(); j != active.end(); j++) +          if ( *j != *i) { +          bool in_first = Intersection(copy(Rs[*j]), copy(cond)).is_upper_bound_satisfiable(); +          bool in_second = Difference(copy(Rs[*j]), copy(cond)).is_upper_bound_satisfiable(); + +          if (in_first && in_second) { +            is_proper_split_cond = false; +            break; +          } + +          if (in_first) +            first_chunk.set(*j); +          else if (in_second) +            second_chunk.set(*j); +          } + +        if (is_proper_split_cond && first_chunk.num_elem() != 0 && second_chunk.num_elem() != 0) { +          CG_result *first_cg = buildAST(level, first_chunk, false, copy(cond)); +          CG_result *second_cg = buildAST(level, second_chunk, false, Complement(copy(cond))); +          if (first_cg == NULL) +            return second_cg; +          else if (second_cg == NULL) +            return first_cg; +          else { +            std::vector<Relation> split_cond; +            std::vector<CG_result *> split_child; +            split_cond.push_back(copy(cond)); +            split_child.push_back(first_cg); +            split_cond.push_back(Complement(copy(cond))); +            split_child.push_back(second_cg); + +            return new CG_split(this, active, split_cond, split_child); +          } +        } +      } +    } +    return new CG_loop(this, active, level, buildAST(level+1, active, true, restriction)); +  } +} + + +CG_result *CodeGen::buildAST(int effort) { +  if (remap_.size() == 0) +    return NULL; + +  CG_result *cgr = buildAST(1, ~BoolSet<>(remap_.size()), true, Relation::True(num_level())); +  if (cgr == NULL) +    return NULL; + + +  // break down the complete iteration space condition to levels of bound/guard condtions +  cgr = cgr->recompute(cgr->active_, copy(known_), copy(known_)); + + + +  if (cgr == NULL) +    return NULL; + +  // calculate each loop's nesting depth +  int depth = cgr->populateDepth(); + + +  // redistribute guard condition locations by additional splittings +  std::pair<CG_result *, Relation> result = cgr->liftOverhead(min(effort,depth), false); + +  // since guard conditions are postponed for non-loop levels, hoist them now. +  // this enables proper if-condition simplication when outputting actual code. +  result.first->hoistGuard(); + + + + +  return result.first; +} + +} | 
