Polaris: AIRangeDict.cc Source File

AIRangeDict.cc

Go to the documentation of this file.
00001 ///
00002 ///
00003 /// \file AIRangeDict.cc
00004 ///
00005 #include "../Program.h"
00006 #include "../ProgramUnit.h"
00007 #include "../Statement/Statement.h"
00008 #include "../Symbol/Symbol.h"
00009 #include "../Symtab.h"
00010 #include "../Expression/Expression.h"
00011 #include "../Directive/Assertion.h"
00012 #include "../utilities/switches_util.h"
00013 #include "../utilities/invariant_util.h"
00014 #include "../utilities/expression_util.h"
00015 #include "../Dictionary.h"
00016 #include "../utilities/equivalence_util.h"
00017 #include "../Array.h"
00018 #include "../IntSet.h"
00019 #include "../Timer.h"
00020 #include "../Traverser.h"
00021 #include "../p-assert.h"
00022 
00023 #include "AIRangeDict.h"
00024 #include "PropRangeWS.h"
00025 #include "PropRangeEdge.h"
00026 #include "RangeExpr.h"
00027 #include "range_util.h"
00028 #include "range_dict_util.h"
00029 
00030 //#include "PropRangeWS.cc"
00031 
00032 #define MAX_SELECTIVE_WIDENING 6
00033 /// The maximum number of visits to this node in which the selective
00034 /// widening of ranges will be allowed.  This bound is a hack
00035 /// to allow selective widening yet preventing the pass from going into
00036 /// an infinite loop in rare cases.  This hack can be justified because
00037 /// the selective widening operator is itself a hack to avoid the loss
00038 /// of information because of unnecessary widenings.
00039 
00040 static unsigned int _pass_tag;  /// ...  Pass tag associated with this pass
00041 
00042 static int _debug_level = 0;
00043 
00044 static int _refine_ranges = -1;
00045 
00046 /// Template instantiations
00047 
00048 template class TypedBaseMap<String,StmtRanges>;
00049 template class ProtoDatabase<String,StmtRanges>;
00050 template class Database<String,StmtRanges>;
00051 template ostream & operator << (ostream &,
00052                                 const Database<String,StmtRanges> &);
00053 template class KeyIterator<String,StmtRanges>;
00054 
00055 
00056 /// init_workspaces
00057 ///   Initialize the workspaces for each statement in the program.
00058 ///   Note: A lot of the initialization for propagate_constants are hidden
00059 ///   in the constructor for PropConstWS.
00060 
00061 static void
00062 _init_workspaces(StmtList &stmts)
00063 {
00064     Iterator<Statement> iter = stmts.iterator();
00065 
00066     for ( ; iter.valid(); ++iter) {
00067     PropRangeWS *my_ws = new PropRangeWS(_pass_tag, iter.current());
00068     iter.current().work_stack().push(my_ws);
00069     }
00070 }
00071 
00072 
00073 /// get_workspace
00074 ///   Get the workspace for the given statement.
00075 
00076 static PropRangeWS &
00077 _get_workspace(const Statement &stmt)
00078 {
00079     WorkSpace *ws = stmt.work_stack().top_ref(_pass_tag);
00080 
00081     p_assert(ws, "Statement doesn't have a RangeWS.");
00082 
00083     return * (PropRangeWS *) ws;
00084 }
00085 
00086 
00087 /// dump_workspaces
00088 ///   Dump out the data inside all of the workspaces of the program
00089 
00090 static void
00091 _dump_workspaces(ostream &o, const StmtList &stmts)
00092 {
00093     Iterator<Statement> iter = stmts.iterator();
00094 
00095     for ( ; iter.valid(); ++iter) {
00096     iter.current().structures_OK();
00097         o << iter.current().tag() << ": ";
00098     int zero = 0;
00099         iter.current().fortran_write(o, zero);
00100         o << "\n   ";
00101     _get_workspace(iter.current()).print(o);
00102     o << endl;
00103     }
00104 }
00105 
00106 
00107 /// colect_stats
00108 ///   Collect various statistics about the pass.  These statistics are the
00109 ///   average number of visits to a node, and the weighted average number of
00110 ///   entries in the constraint dictionaries.
00111 
00112 static void
00113 _collect_stats(const StmtList &stmts, float &avg_visits, float &avg_cd_entries)
00114 {
00115     int num_visits = 0;
00116     int num_cd_entries = 0;
00117     int weighted_stmt_entries = 0;
00118 
00119     Iterator<Statement> iter = stmts.iterator();
00120 
00121     for ( ; iter.valid(); ++iter) {
00122     PropRangeWS &ws = _get_workspace(iter.current());
00123     num_visits += ws.num_visits();
00124     if (ws.ranges_ref())
00125         num_cd_entries += ws.num_visits() * ws.ranges_ref()->entries();
00126     weighted_stmt_entries += ws.num_visits();
00127     }
00128 
00129     avg_visits = (float) num_visits / (float) stmts.entries();
00130     avg_cd_entries = (float) num_cd_entries / (float) weighted_stmt_entries;
00131 }
00132 
00133 
00134 /// _make_nonlocals_modified_at_calls
00135 ///   Make all non-local variables be marked as potentially modified for all
00136 ///   call statements and all statements containing function calls.
00137 
00138 static void
00139 _make_nonlocals_modified_at_calls(ProgramUnit &pgm)
00140 {
00141     /// ...  Calculate the set of non-local variables.
00142 
00143     RefSet<Symbol> non_local_set;
00144     DictionaryIter<Symbol> sym_iter = pgm.symtab().iterator();
00145 
00146     for ( ; sym_iter.valid(); ++sym_iter) {
00147     Symbol &symbol = sym_iter.current();
00148 
00149     if (symbol.sym_class() == VARIABLE_CLASS
00150         && (symbol.formal() == IS_FORMAL || symbol.common_ref())) {
00151 
00152         if (symbol.type().data_type() == INTEGER_TYPE)
00153         non_local_set.ins(symbol);
00154 
00155         /// ...  Also place any aliased variables in the set.
00156         
00157             RefSet<Symbol> *aliases = equiv_aliases(symbol);
00158 
00159             if (aliases) {
00160                 Iterator<Symbol> alias_iter = *aliases;
00161 
00162                 for ( ; alias_iter.valid(); ++alias_iter) {
00163                     Symbol &alias_symbol = alias_iter.current();
00164 
00165             if (alias_symbol.type().data_type() == INTEGER_TYPE)
00166             non_local_set.ins(alias_symbol);
00167                 }
00168 
00169                 delete aliases;
00170             }
00171     }
00172     }
00173 
00174     /// ...  Add the non-local variables to the mod_set of all statements that
00175     /// ...  are either call statements or contain function calls.
00176 
00177     Iterator<Statement> stmt_iter = pgm.stmts().iterator();
00178 
00179     for ( ; stmt_iter.valid(); ++stmt_iter) {
00180     Statement &stmt = stmt_iter.current();
00181 
00182     if (stmt.stmt_class() == CALL_STMT || contains_func_call(stmt)) {
00183         RefSet<Symbol> &mod_set = _get_workspace(stmt).mod_set();
00184         RefSet<Symbol> *maymods = stmt_maymods(stmt);
00185 
00186         if (maymods) {
00187         Iterator<Expression> act_iter = stmt.act_refs();
00188 
00189         for ( ; act_iter.valid(); ++act_iter) {
00190             Symbol *var_ref = act_iter.current().base_variable_ref();
00191 
00192             if (var_ref)
00193             mod_set.del(*var_ref);
00194         }
00195 
00196         if (stmt.stmt_class() == ASSIGNMENT_STMT) {
00197             Symbol *var_ref = stmt.lhs().base_variable_ref();
00198             
00199             if (var_ref)
00200             mod_set.ins(*var_ref);
00201         }
00202 
00203         Iterator<Symbol> nl_iter = *maymods;
00204         
00205         for ( ; nl_iter.valid(); ++nl_iter)
00206             mod_set.ins(nl_iter.current());
00207 
00208         delete maymods;
00209         }
00210         else {
00211         Iterator<Symbol> nl_iter = non_local_set;
00212         
00213         for ( ; nl_iter.valid(); ++nl_iter)
00214             mod_set.ins(nl_iter.current());
00215         }
00216     }
00217     }
00218 }
00219 
00220 
00221 /// add_flow_edges
00222 ///   Add flow edges to all of the workspace objects
00223 
00224 static void
00225 _add_flow_edges(StmtList &stmts)
00226 {
00227     Iterator<Statement> stmt_iter = stmts.iterator();
00228 
00229     for ( ; stmt_iter.valid(); ++stmt_iter) {
00230     Statement &stmt = stmt_iter.current();
00231     PropRangeWS &curr_ws = _get_workspace(stmt);
00232     Iterator<Statement> succ_iter = stmt.succ();
00233 
00234     for ( ; succ_iter.valid(); ++succ_iter) {
00235         Statement &succ = succ_iter.current();
00236         PropRangeEdge *edge = new PropRangeEdge(stmt, succ);
00237         curr_ws.succ().ins_last(edge);
00238         _get_workspace(succ).pred().ins(*edge);
00239     }
00240     }
00241 }
00242 
00243 
00244 /// patch_flow_graph
00245 ///   Add flow edges from all ENDDO statements in the flow graph to the
00246 ///   statement following the ENDDO.  These edges are added so to allow constant
00247 ///   information calculated inside a DO loop to be propagated to statements
00248 ///   after a DO loop in the same iteration.  Without these additional edges,
00249 ///   constant information calculated inside a loop can affect statements
00250 ///   after the loop only on the successive iteration.  This would mean that
00251 ///   the the number of iterations required will be a multiple of the depth of
00252 ///   the maximum loop nesting of the program.
00253 
00254 static void
00255 _patch_flow_graph(StmtList &stmts)
00256 {
00257     Iterator<Statement> iter = stmts.stmts_of_type(ENDDO_STMT);
00258 
00259     for ( ; iter.valid(); ++iter) {
00260     Statement &curr = iter.current();
00261     Statement &next = * (Statement *) curr.next_ref();
00262     PropRangeEdge *enddo_edge = new PropRangeEdge(curr, next);
00263 
00264     _get_workspace(curr).succ().ins_last(enddo_edge);
00265     _get_workspace(next).pred().ins(*enddo_edge);
00266     }
00267 }
00268 
00269 
00270 /// _calc_toporder
00271 ///   Calculate toporder for the flow graph.  Essentially, this algorithm
00272 ///   performs a topological sort on the flow graph, ignoring back
00273 ///   edges.
00274 
00275 static void
00276 _calc_toporder1(PropRangeWS &my_ws, int &toporder)
00277 {
00278     my_ws.visited(1);
00279 
00280     Iterator<PropRangeEdge> succ_iter = my_ws.succ();
00281     
00282     for ( ; succ_iter.valid(); ++succ_iter) {
00283     PropRangeWS &succ_ws = _get_workspace(succ_iter.current().succ());
00284 
00285     if (! succ_ws.visited())
00286         _calc_toporder1(succ_ws, toporder);
00287     }
00288 
00289     my_ws.toporder(toporder--);
00290 }
00291 
00292 static void
00293 _calc_toporder(StmtList &stmts, Array<Statement *> &toporder_to_stmt)
00294 { 
00295     /// ...  Calculate the topological order for each statement
00296 
00297     int toporder = stmts.entries() - 1;
00298 
00299     if (toporder >= 0) {
00300     Iterator<Statement> entry_iter = stmts.iterate_entry_points();
00301 
00302     for ( ; entry_iter.valid(); ++entry_iter) {
00303         PropRangeWS &entry_ws = _get_workspace(entry_iter.current());
00304 
00305         if (! entry_ws.visited())
00306         _calc_toporder1(entry_ws, toporder);
00307     }
00308  
00309     p_assert(toporder >= -1,
00310          "_calc_toporder visited a stmt more than once.");
00311     }
00312 
00313     /// ...  Initialize toporder_to_stmt
00314 
00315     toporder_to_stmt.resize(stmts.entries());
00316 
00317     for (int i = 0; i <= toporder; ++i)
00318     toporder_to_stmt[i] = 0;
00319 
00320     Iterator<Statement> iter = stmts.iterator();
00321 
00322     for ( ; iter.valid(); ++iter) {
00323     int stmt_toporder = _get_workspace(iter.current()).toporder();
00324 
00325     if (stmt_toporder >= 0)
00326         toporder_to_stmt[stmt_toporder] = &iter.current();
00327     }
00328 }
00329 
00330 
00331 /// set_needs_widening
00332 ///   Initialize the needs_widener field for all statement's workspaces.
00333 ///   A statement's constraint dictionary eventually needs the widening
00334 ///   operator if it has any back-edges.
00335 
00336 static void
00337 _set_needs_widening(StmtList &stmts)
00338 {
00339     Iterator<Statement> stmt_iter = stmts.iterator();
00340 
00341     for ( ; stmt_iter.valid(); ++stmt_iter) {
00342     PropRangeWS &curr_ws = _get_workspace(stmt_iter.current());
00343     int stmt_toporder = curr_ws.toporder();
00344     Iterator<PropRangeEdge> pred_iter = curr_ws.pred();
00345 
00346     for ( ; pred_iter.valid(); ++pred_iter)
00347         if (stmt_toporder <= _get_workspace(
00348         pred_iter.current().pred()).toporder()) {
00349 
00350         curr_ws.needs_widening(true);
00351         break;
00352         }
00353     }
00354 }
00355 
00356 static void
00357 _calc_loop_variants(StmtList &stmts)
00358 {
00359     Iterator<Statement> stmt_iter = stmts.stmts_of_type(DO_STMT);
00360 
00361     for ( ; stmt_iter.valid(); ++stmt_iter) {
00362     Statement &do_loop = stmt_iter.current();
00363     RefSet<Symbol> *loop_variants = loop_variant_vars(stmts, do_loop);
00364     p_assert(loop_variants,
00365          "Internal error: loop_variant_vars() returned NULL.");
00366     _get_workspace(do_loop).loop_variants(loop_variants);
00367     }
00368 }
00369 
00370 
00371 /// put_succ_on_work_list
00372 ///   Put all of my successors on the work list.
00373 
00374 static void
00375 _put_succ_on_work_list(IntSet &work_list, PropRangeWS &my_ws)
00376 {
00377     Iterator<PropRangeEdge> succ_iter = my_ws.succ();
00378     
00379     for ( ; succ_iter.valid(); ++succ_iter)
00380     work_list.ins(_get_workspace(succ_iter.current().succ()).toporder());
00381 }
00382 
00383 
00384 /// use_widening_operator
00385 ///   The given workspace's constraint dictionary needs the use of the widening
00386 ///   operator if this method returns true.
00387 
00388 static bool
00389 _use_widening_operator(PropRangeWS &curr_ws)
00390 {
00391     if (curr_ws.needs_widening())
00392     if (curr_ws.use_widener())
00393         return true;
00394     else {
00395         bool preds_have_ranges = true;
00396 
00397         Iterator<PropRangeEdge> pred_iter = curr_ws.pred();
00398     
00399         for ( ; pred_iter.valid(); ++pred_iter)
00400         if (! pred_iter.current().ranges_ref()) {
00401             preds_have_ranges = false;
00402             break;
00403         }
00404 
00405         curr_ws.use_widener(preds_have_ranges);
00406     }
00407 
00408     return false;
00409 }
00410 
00411 static Boolean
00412 is_ARRAY_OP (const Expression & expr)
00413 {
00414     if (expr.op() == ARRAY_REF_OP) { 
00415     return True;
00416     } else {
00417     return False;
00418     }
00419 }
00420 
00421 
00422 /// _add_subscript_constraints_to_ranges
00423 ///   Intersect any relation assertions for the given statement with the
00424 ///   given constraint dictionary.
00425 
00426 static void
00427 _add_subscript_constraints_to_ranges(Statement &stmt, StmtRanges &ranges)
00428 {
00429     Iterator<Expression> expr_iter = stmt.iterate_expressions();
00430 
00431     for ( ; expr_iter.valid(); ++expr_iter) {
00432     
00433     Traverser trav (expr_iter.current(), is_ARRAY_OP);
00434     for ( ; trav.valid(); ++trav) {
00435 
00436         const Expression &expr = trav.current();
00437 
00438         Iterator<Expression>  subscr_iter  = expr.subscript().arg_list();
00439         Iterator<ArrayBounds> declare_iter = expr.array().symbol().dim();
00440 
00441         int num_dims = expr.array().symbol().dim().entries();
00442 
00443         for (int which_dim = 0; subscr_iter.valid() && declare_iter.valid(); 
00444          ++subscr_iter,++declare_iter,++which_dim) {
00445 
00446         Expression & expr = subscr_iter.current();
00447         ArrayBounds & bounds = declare_iter.current();
00448 
00449         Expression * upper = 0;
00450 
00451         if (bounds.upper_exists() && (which_dim < num_dims-1)) {
00452             upper = bounds.upper_guarded().clone();
00453         }
00454 
00455         Expression * lower;
00456         
00457         if (bounds.lower_exists()) {
00458             lower = bounds.lower_guarded().clone();
00459         } else {
00460             lower = constant(1);
00461         }
00462 
00463         RefSet<Symbol> symset;
00464         apply_limits(expr, lower, upper, ranges, symset);
00465 
00466         symset.clear();
00467         if (lower) {
00468             apply_limits(*lower, 0, upper, ranges, symset);
00469             symset.clear();
00470         }
00471         if (upper) {
00472             apply_limits(*upper, lower, 0, ranges, symset);
00473         }
00474         }
00475     }
00476     }
00477 }
00478 
00479 
00480 /// add_asserts_to_ranges
00481 ///   Intersect any relation assertions for the given statement with the
00482 ///   given constraint dictionary.
00483 
00484 static void
00485 _add_asserts_to_ranges(const Statement &stmt, StmtRanges &ranges)
00486 {
00487     Iterator<Assertion> assert_iter = stmt.assertions();
00488 
00489     for ( ; assert_iter.valid(); ++assert_iter) {
00490         const Assertion &assert = assert_iter.current();
00491 
00492         if (assert.type() == AS_RELATION) {
00493             Iterator<Expression> arg_iter = assert.arg_list_guarded();
00494 
00495             for ( ; arg_iter.valid(); ++arg_iter)
00496         ranges.extract_ranges(arg_iter.current());
00497         }
00498     }
00499 }
00500 
00501 
00502 /// invert_expr
00503 ///   Given an expression of the form "lhs_var = rhs", where rhs is an
00504 ///   expression of the form "<expr>*lhs_var + ...", calculate the expression
00505 ///   to map the old value of lhs to its new value.  For example, if the
00506 ///   expression is of the form "i = 2*i + 1", this function returns "(i-1)/2".
00507 ///   If the arguments cannot be fitted into the above form, this method
00508 ///   returns 0.
00509 
00510 static Expression *
00511 _invert_expr(const Expression &rhs, const Symbol &lhs_var)
00512 {
00513     /// ...  Remove the single multiplicative term containing lhs_var from the
00514     /// ...  the other terms in the expression
00515 
00516     Expression *terms = rhs.clone();
00517     Expression *lhs_term = 0;
00518 
00519     if (terms->op() == ID_OP || terms->op() == MULT_OP
00520     || terms->op() == DIV_OP) {
00521 
00522     lhs_term = terms;
00523     terms = 0;
00524     }
00525     else if (terms->op() == ADD_OP) {
00526     Mutator<Expression> iter = terms->arg_list();
00527 
00528     for ( ; iter.valid(); ++iter)
00529         if (is_var_in_expr(iter.current(), lhs_var))
00530         if (! lhs_term)
00531             lhs_term = iter.grab();
00532         else {
00533             delete lhs_term;
00534             delete terms;
00535             return 0;
00536         }
00537     }
00538 
00539     if (! lhs_term) {
00540     delete terms;
00541     return 0;
00542     }
00543 
00544     /// ...  Break the lhs_term into the lhs variable and its factor.
00545 
00546     Expression *lhs_expr = 0;
00547     Expression *factor = 0;
00548     Expression *divisor = 0;
00549 
00550     if (lhs_term->op() == ID_OP)
00551     lhs_expr = lhs_term;
00552     else if (lhs_term->op() == MULT_OP) {
00553     lhs_expr = lhs_term->member_ref(&lhs_var);
00554 
00555     if (lhs_expr) {
00556         lhs_term->arg_list().grab(*lhs_expr);
00557 
00558         if (is_var_in_expr(*lhs_term, lhs_var)) {
00559         delete lhs_expr;
00560         lhs_expr = 0;
00561         }
00562         else
00563         factor = lhs_term;
00564     }
00565     }
00566     else if (lhs_term->op() == DIV_OP
00567          && lhs_term->left_guarded().op() == ID_OP
00568          && &lhs_term->left_guarded().symbol() == &lhs_var
00569          && lhs_term->right_guarded().op() == INTEGER_CONSTANT_OP) {
00570     lhs_expr = lhs_term->grab_left();
00571     divisor = lhs_term->grab_right();
00572     delete lhs_term;
00573     }
00574 
00575     if (! lhs_expr) {
00576     if (terms) delete terms;
00577     if (lhs_term) delete lhs_term;
00578     if (factor) delete factor;
00579     if (divisor) delete divisor;
00580     return 0;
00581     }
00582 
00583     /// ...  Generate and return the inverted expression
00584 
00585     Expression *inverted_expr = lhs_expr;
00586 
00587     if (terms)
00588     inverted_expr = sub(inverted_expr, terms);
00589 
00590     if (factor)
00591     inverted_expr = div(inverted_expr, factor);
00592 
00593     if (divisor) {
00594     int max_abs_mod;
00595 
00596     if (divisor->value() >= 0)
00597         max_abs_mod = divisor->value() - 1;
00598     else
00599         max_abs_mod = 1 - divisor->value();
00600 
00601     inverted_expr = mul(divisor, inverted_expr);
00602     inverted_expr = new RangeExpr(inverted_expr,
00603                       add(inverted_expr->clone(),
00604                       constant(max_abs_mod)));
00605     }
00606 
00607     inverted_expr = simplify(inverted_expr);
00608     return inverted_expr;
00609 }
00610 
00611 
00612 /// update_assign_succs
00613 ///   Update the output ranges and possibly the successors of the given
00614 ///   assignment statement.  Return true if the successors is updated.
00615 
00616 static bool
00617 _update_assign_succs(Statement &stmt, StmtRanges *out_ranges)
00618 {
00619 ///    PropRangeWS &curr_ws = _get_workspace(stmt);
00620     const Symbol *lhs_name = stmt.lhs().base_variable_ref();
00621 
00622     if (lhs_name) {
00623     const Expression *old_lhs_range
00624         = out_ranges->get_range_ref(*lhs_name);
00625     
00626     if (is_int_scalar(*lhs_name)
00627         && stmt.rhs().is_side_effect_free()
00628         && stmt.rhs().type().data_type() == INTEGER_TYPE) {
00629         
00630         Expression *assign_expr = stmt.rhs().clone();
00631         
00632         if (is_var_in_expr(*assign_expr, *lhs_name)) {
00633         Expression *inverted_assign = _invert_expr(*assign_expr,
00634                                *lhs_name);
00635         if (inverted_assign) {
00636             out_ranges->subst_in_ranges(*lhs_name,
00637                              inverted_assign);
00638             delete inverted_assign;
00639         }
00640         else
00641             out_ranges->subst_in_ranges(*lhs_name,
00642                              old_lhs_range);
00643         
00644         assign_expr = out_ranges->subst_var_and_simplify(
00645             assign_expr, *lhs_name, old_lhs_range);
00646         }
00647         else {
00648         out_ranges->subst_in_ranges(*lhs_name, old_lhs_range);
00649         assign_expr = simplify(assign_expr);
00650         }
00651         
00652         out_ranges->set_range(*lhs_name, assign_expr);
00653     }
00654     else {
00655         out_ranges->subst_in_ranges(*lhs_name, old_lhs_range);
00656         out_ranges->del_range(*lhs_name);
00657     }
00658     }
00659 
00660     return false;
00661 }
00662 
00663 
00664 /// update_if_succs
00665 ///   Update the output ranges and possibly the successors of the given
00666 ///   IF statement.  Return true if the successors is updated.
00667 
00668 static bool
00669 _update_if_succs(Statement &stmt, StmtRanges *out_ranges)
00670 {
00671     if (! stmt.expr().is_side_effect_free())
00672     return false;
00673 
00674     PropRangeWS &curr_ws = _get_workspace(stmt);
00675     p_assert(curr_ws.succ().entries() == 2,
00676          "If statement does not have two flow successors.");
00677     PropRangeEdge *then_edge = NULL, *else_edge = NULL;
00678     
00679     if (stmt.next_ref() == &curr_ws.succ().first_ref()->succ()) {
00680     then_edge = curr_ws.succ().first_ref();
00681     else_edge = curr_ws.succ().last_ref();
00682     }
00683     else if (stmt.next_ref() == &curr_ws.succ().last_ref()->succ()) {
00684     then_edge = curr_ws.succ().last_ref();
00685     else_edge = curr_ws.succ().first_ref();
00686     }
00687     else
00688     p_abort("Internal Error in _update_succ_edges");
00689     
00690     then_edge->ranges(new StmtRanges(*out_ranges));
00691     then_edge->ranges_ref()->extract_ranges(stmt.expr(), false);
00692     
00693     else_edge->ranges(out_ranges);
00694     else_edge->ranges_ref()->extract_ranges(stmt.expr(), true);
00695     
00696     return true;
00697 }
00698 
00699 
00700 /// exit_range
00701 ///   Compute the exit range for the index variable of the given loop.
00702 
00703 static Expression *
00704 _exit_range(const Statement &do_loop, EXPR_SIGN step_sign)
00705 {
00706     Expression *exit_range;
00707 
00708     if (step_sign == POS_EXPR) {
00709     if (do_loop.step().op() == INTEGER_CONSTANT_OP
00710         && do_loop.step().value() == 1)
00711         
00712         exit_range = add(do_loop.limit().clone(), constant(1));
00713     else
00714         exit_range = new RangeExpr(add(do_loop.limit().clone(),
00715                        constant(1)),
00716                        add(do_loop.limit().clone(),
00717                        do_loop.step().clone()));
00718     }
00719     else {
00720     if (do_loop.step().op() == INTEGER_CONSTANT_OP
00721         && do_loop.step().value() == -1)
00722         
00723         exit_range = add(do_loop.limit().clone(), constant(-1));
00724     else
00725         exit_range = new RangeExpr(add(do_loop.limit().clone(),
00726                        do_loop.step().clone()),
00727                        add(do_loop.limit().clone(),
00728                        constant(-1)));
00729     }
00730 
00731     exit_range = simplify(exit_range);
00732 
00733     return exit_range;
00734 }
00735 
00736 
00737 /// update_do_succs
00738 ///   Update the output ranges and possibly the successors of the given
00739 ///   DO statement.  Return true if the successors is updated.
00740 
00741 static bool
00742 _update_do_succs(Statement &stmt, StmtRanges *out_ranges)
00743 {
00744     EXPR_SIGN step_sign = out_ranges->sign(stmt.step());
00745     
00746     if (step_sign == POS_NEG_EXPR || contains_func_call(stmt)
00747     || stmt.index().type().data_type() != INTEGER_TYPE)
00748     return false;
00749     
00750     PropRangeWS &curr_ws = _get_workspace(stmt);
00751     p_assert(curr_ws.succ().entries() == 2,
00752          "Do statement does not have two flow successors.");
00753     PropRangeEdge *body_edge = NULL, *exit_edge = NULL;
00754     
00755     if (stmt.next_ref() == &curr_ws.succ().first_ref()->succ()) {
00756     body_edge = curr_ws.succ().first_ref();
00757     exit_edge = curr_ws.succ().last_ref();
00758     }
00759     else if (stmt.next_ref() == &curr_ws.succ().last_ref()->succ()) {
00760     body_edge = curr_ws.succ().last_ref();
00761     exit_edge = curr_ws.succ().first_ref();
00762     }
00763     else
00764     p_abort("Internal Error in _update_succ_edges");
00765     
00766     Expression *bound_cond, *index_range;
00767     
00768     if (step_sign == POS_EXPR) {
00769     bound_cond = le(stmt.init().clone(), stmt.limit().clone());
00770     index_range = new RangeExpr(stmt.init().clone(), stmt.limit().clone());
00771     }
00772     else {
00773     bound_cond = ge(stmt.init().clone(), stmt.limit().clone());
00774     index_range = new RangeExpr(stmt.limit().clone(), stmt.init().clone());
00775     }
00776 
00777     index_range = simplify(index_range);
00778     body_edge->ranges(new StmtRanges(*out_ranges));
00779     body_edge->ranges_ref()->extract_ranges(*bound_cond);
00780     body_edge->ranges_ref()->set_range(stmt.index().symbol(), index_range);
00781     delete bound_cond;
00782 
00783     /// ...  Expression *exit_range = _exit_range(stmt, step_sign);
00784     /// ...  exit_edge->ranges(out_ranges);
00785     /// ...  exit_edge->ranges_ref()->set_range(stmt.index().symbol(), exit_range);
00786 
00787     exit_edge->ranges(out_ranges);
00788     exit_edge->ranges_ref()->del_range(stmt.index().symbol());
00789     
00790     return true;
00791 }
00792 
00793 
00794 /// update_enddo_succs
00795 ///   Update the output ranges and possibly the successors of the given
00796 ///   ENDDO statement.  Return true if the successors is updated.
00797 
00798 static bool
00799 _update_enddo_succs(Statement &stmt, StmtRanges *out_ranges)
00800 {
00801     Statement &matching_do = *stmt.follow_ref();
00802     EXPR_SIGN step_sign = out_ranges->sign(matching_do.step());
00803     
00804     if (step_sign == POS_NEG_EXPR || contains_func_call(matching_do))
00805     return false;
00806     
00807     PropRangeWS &curr_ws = _get_workspace(stmt);
00808     p_assert(curr_ws.succ().entries() == 2,
00809          "Enddo statement does not have two flow successors.");
00810     PropRangeEdge *back_edge = NULL, *exit_edge = NULL;
00811     
00812     if (&curr_ws.succ().first_ref()->succ() == &matching_do) {
00813     back_edge = curr_ws.succ().first_ref();
00814     exit_edge = curr_ws.succ().last_ref();
00815     }
00816     else if (&curr_ws.succ().last_ref()->succ() == &matching_do) {
00817     back_edge = curr_ws.succ().last_ref();
00818     exit_edge = curr_ws.succ().first_ref();
00819     }
00820     else
00821     p_abort("Internal Error in _update_succ_edges");
00822     
00823     back_edge->ranges(new StmtRanges(*out_ranges));
00824     
00825     Expression *exit_range = _exit_range(matching_do, step_sign);
00826     exit_edge->ranges(out_ranges);
00827     exit_edge->ranges_ref()->set_range(matching_do.index().symbol(),
00828                         exit_range);
00829     
00830     return true;
00831 }
00832 
00833 
00834 /// update_succ_edges
00835 ///   Update the constraint dictionaries of the successor edges of the given
00836 ///   statement.
00837 
00838 static void
00839 _update_succ_edges(Statement &stmt)
00840 {
00841     PropRangeWS &curr_ws = _get_workspace(stmt);
00842 
00843     /// ...  First, discard any ranges belonging to possibly modified variables
00844 
00845     p_assert(curr_ws.ranges_ref(),
00846          "Internal Error: Workspace has NULL StmtRanges pointer.");
00847 
00848     StmtRanges *out_ranges
00849     = new StmtRanges(*curr_ws.ranges_ref());
00850 
00851     if (stmt.stmt_class() == DO_STMT)
00852     out_ranges->subst_in_ranges(stmt.index().symbol(), 0);
00853 
00854     Iterator<Symbol> mod_iter = curr_ws.mod_set();
00855 
00856     for ( ; mod_iter.valid(); ++mod_iter)
00857     if (stmt.stmt_class() != ASSIGNMENT_STMT
00858         || ! stmt.lhs().base_variable_ref()
00859         || stmt.lhs().base_variable_ref() != &mod_iter.current()) {
00860 
00861         const Expression *range
00862         = out_ranges->get_range_ref(mod_iter.current());
00863 
00864         out_ranges->subst_in_ranges(mod_iter.current(), range);
00865         out_ranges->del_range(mod_iter.current());
00866     }
00867 
00868     _add_asserts_to_ranges(stmt, *out_ranges);
00869 
00870     /// ...  Now, update the successors constraint dictionaries.
00871 
00872     bool already_updated_succs = false;
00873 
00874     switch (stmt.stmt_class()) {
00875 
00876     case ASSIGNMENT_STMT:
00877     already_updated_succs = _update_assign_succs(stmt, out_ranges);
00878     break;
00879 
00880     case IF_STMT:
00881     case ELSEIF_STMT:
00882     already_updated_succs = _update_if_succs(stmt, out_ranges);
00883     break;
00884 
00885     case DO_STMT:
00886     already_updated_succs = _update_do_succs(stmt, out_ranges);
00887     break;
00888 
00889     case ENDDO_STMT:
00890     /// ...  already_updated_succs = _update_enddo_succs(stmt, out_ranges);
00891     break;
00892 
00893     case BLOCK_ENTRY_STMT:
00894     case BLOCK_EXIT_STMT:
00895     if (switch_value("range_block") > 0)
00896         out_ranges->clear();
00897     break;
00898 
00899     default:
00900     /// ...  Do nothing
00901     break;
00902     }
00903 
00904     /// ...  If the previous functions did not update the constraint dictionaries of
00905     /// ...  my successor edges, do so now.
00906 
00907     if (! already_updated_succs) {
00908     Iterator<PropRangeEdge> succ_iter = curr_ws.succ();
00909     
00910     if (succ_iter.valid()) {
00911         succ_iter.current().ranges(out_ranges);
00912         ++succ_iter;
00913         
00914         for ( ; succ_iter.valid(); ++succ_iter)
00915         succ_iter.current().ranges(new StmtRanges(*out_ranges));
00916     }
00917     else
00918         delete out_ranges;
00919     }
00920 }
00921 
00922 
00923 /// iterate_to_fixed_point_phase
00924 ///   Propagate the constants contained in the statement's const_maps until
00925 ///   a fixed point is reached.
00926 
00927 static void
00928 _iterate_to_fixed_point_phase(ProgramUnit &pgm, 
00929                   const Array<Statement *> &toporder_to_stmt,
00930                   const IntSet &start_stmts,
00931                   bool widening_phase)
00932 {
00933     /// ...  Read switch value first time through
00934 
00935     if (_refine_ranges == -1) {
00936     _refine_ranges = switch_value("refine_ranges");
00937     }
00938 
00939     IntSet work_list(start_stmts);
00940     /// ...  List of statements that need to be updated.
00941 
00942     /// ...  Iterate until there are no more elements on the work list
00943 
00944     while (work_list.entries() > 0) {
00945     for (int stmt_num = work_list.first();
00946          stmt_num != -1;
00947          stmt_num = work_list.next(stmt_num)) {
00948 
00949         Statement &curr = *toporder_to_stmt[stmt_num];
00950         work_list.del(stmt_num);
00951         PropRangeWS &curr_ws = _get_workspace(curr);
00952         curr_ws.incr_num_visits();
00953         StmtRanges *new_ranges = 0;
00954         Iterator<PropRangeEdge> pred_iter = curr_ws.pred();
00955 
00956         if (curr_ws.pred().entries() == 1) {
00957         /// ...  Optimization to decrease number of StmtRanges copies.
00958         
00959         new_ranges = pred_iter.current().grab_ranges();
00960         p_assert(! curr_ws.needs_widening(),
00961              "Internal Error: Stmts with single predecesors should never need to be widened.");
00962         p_assert(new_ranges || ! curr_ws.ranges_ref(),
00963              "Internal Error: Constraint information was lost.");
00964         }
00965         else {
00966         for ( ; pred_iter.valid(); ++pred_iter) {
00967             PropRangeEdge &pred_edge = pred_iter.current();
00968             StmtRanges *pred_ranges = pred_edge.ranges_ref();
00969             
00970             if (pred_ranges)
00971             if (new_ranges)
00972                 new_ranges->union_ranges(*pred_ranges);
00973             else
00974                 new_ranges = new StmtRanges(*pred_ranges);
00975         }
00976         }       
00977 
00978         if (! new_ranges)
00979         new_ranges = new StmtRanges(pgm.symtab());
00980 
00981         /// ...  Add ranges from any array subscripting in the statement
00982         if (_refine_ranges && (curr_ws.num_visits() == 1)) {
00983         _add_subscript_constraints_to_ranges(curr, *new_ranges);
00984         }
00985         
00986         if (curr_ws.ranges_ref()
00987         && curr_ws.needs_widening()) {
00988         
00989         StmtRanges &old_ranges = *curr_ws.ranges_ref();
00990         
00991         if (widening_phase) {
00992             if (_use_widening_operator(curr_ws))
00993             if (curr_ws.loop_variants_ref()
00994                 && curr_ws.num_visits() <= MAX_SELECTIVE_WIDENING) {
00995               new_ranges->widen_some_ranges(old_ranges,
00996                             *curr_ws.loop_variants_ref());
00997             }
00998             else
00999                 new_ranges->widen_ranges(old_ranges);
01000         }
01001         else
01002             new_ranges->narrow_ranges(old_ranges);
01003         }           
01004         
01005         if (! curr_ws.ranges_ref()
01006         || *new_ranges != *curr_ws.ranges_ref()) {
01007         
01008         curr_ws.ranges(new_ranges);
01009         
01010         if (_debug_level >= 20) {
01011             int zero = 0;
01012             curr.write(cout, zero);
01013             cout << "        ";
01014             curr_ws.ranges_ref()->pretty_print(cout);
01015             cout << endl;
01016         }
01017         
01018         _update_succ_edges(curr);
01019         _put_succ_on_work_list(work_list, curr_ws);
01020         }
01021         else
01022         delete new_ranges;
01023     }
01024     }
01025 }
01026 
01027 
01028 /// iterate_to_fixed_point
01029 ///   Propagate the constants contained in the statement's const_maps until
01030 ///   a fixed point is reached.
01031 
01032 static void
01033 _iterate_to_fixed_point(ProgramUnit &pgm, 
01034             const Array<Statement *> &toporder_to_stmt)
01035 {
01036     /// ...  Widening phase:
01037     /// ...    This phase iterates to a fixed point, applying the widening operator
01038     /// ...    on the constraint dictionaries of all statements with back edges.
01039     /// ...    The widening operator makes an overly conservative estimate of the
01040     /// ...    fixed point value, so as to guarrantee convergence.
01041 
01042     if (_debug_level >= 20)
01043     cout << "\nWidening Phase:\n";
01044 
01045     IntSet entry_stmts(toporder_to_stmt.entries());
01046     Iterator<Statement> entry_iter = pgm.stmts().iterate_entry_points();
01047 
01048     for ( ; entry_iter.valid(); ++entry_iter) {
01049     PropRangeWS &ws = _get_workspace(entry_iter.current());
01050 
01051         entry_stmts.ins(ws.toporder());
01052     }
01053 
01054     _iterate_to_fixed_point_phase(pgm, toporder_to_stmt, entry_stmts, true);
01055 
01056     /// ...  Narrowing phase:
01057     /// ...    This phase iterates to a fixed point, applying the narrowing operator
01058     /// ...    on the constraint dictionaries of all statements with back edges.
01059     /// ...    The narrowing operator attempts to regain some of the information
01060     /// ...    lost by the widening operator.
01061 
01062     if (_debug_level >= 20)
01063     cout << "\nNarrowing Phase:\n";
01064 
01065     IntSet widened_stmts(toporder_to_stmt.entries());
01066     Iterator<Statement> stmt_iter = pgm.stmts().iterator();
01067 
01068     for ( ; stmt_iter.valid(); ++stmt_iter) {
01069     PropRangeWS &ws = _get_workspace(stmt_iter.current());
01070 
01071     if (ws.toporder() >= 0 && ws.needs_widening())
01072         widened_stmts.ins(ws.toporder());
01073     }
01074     
01075     _iterate_to_fixed_point_phase(pgm, toporder_to_stmt, widened_stmts, false);
01076 }
01077 
01078 
01079 /// _add_safe_cond_ranges
01080 ///   Add any SafeCondition ranges to the PropRangeWS ranges on each statement
01081 ///   within a loop body.
01082 
01083 void
01084 AIRangeDict::_add_safe_cond_ranges(const ProgramUnit &pgm)
01085 {
01086     Iterator<Statement> iter = pgm.stmts().iterator();
01087 
01088     for ( ; iter.valid(); ++iter) {
01089     Statement &stmt = iter.current();
01090 
01091     if (stmt.stmt_class() == DO_STMT) {
01092         Iterator<Assertion> assert_iter = stmt.assertions();
01093 
01094         for ( ; assert_iter.valid(); ++assert_iter) {
01095         const Assertion &assert = assert_iter.current();
01096         
01097         if (assert.type() == AS_SAFE_CONDITION) {
01098             for (Iterator<Statement> do_iter = pgm.stmts().iterate_loop_body(&stmt);
01099              do_iter.valid();
01100              ++do_iter) {
01101 
01102             Statement & body_stmt = do_iter.current();
01103 
01104             PropRangeWS &ws = _get_workspace(body_stmt);
01105             Iterator<Expression> arg_iter = assert.arg_list_guarded();
01106 
01107             for ( ; arg_iter.valid(); ++arg_iter) {
01108                 if (ws.ranges_ref()) {
01109                 ws.ranges_ref()->extract_ranges(arg_iter.current());
01110                 }
01111             }
01112             }
01113         }
01114         }
01115     }
01116     }
01117 }
01118 
01119 
01120 
01121 
01122 /// generate_map
01123 ///   Generate the mapping between variables and ranges.
01124 
01125 void
01126 AIRangeDict::_generate_map(const ProgramUnit &pgm)
01127 {
01128     Iterator<Statement> iter = pgm.stmts().iterator();
01129 
01130     for ( ; iter.valid(); ++iter) {
01131     Statement &stmt = iter.current();
01132     PropRangeWS &ws = _get_workspace(stmt);
01133 
01134     if (ws.ranges_ref())
01135         _stmt_ranges.ins(stmt.tag(), ws.grab_ranges());
01136     else
01137         _stmt_ranges.ins(stmt.tag(), new StmtRanges(pgm.symtab()));
01138     }
01139 }
01140 
01141 
01142 /// AIRangeDict
01143 
01144 AIRangeDict::AIRangeDict(ProgramUnit &pgm, int debug GIV(0))
01145 : RangeDict(pgm.symtab())
01146 {
01147     #ifdef CLASS_INSTANCE_REGISTRY
01148     register_instance(AIRANGE_DICT, sizeof(AIRangeDict), this);
01149     #endif
01150 
01151     if (switch_value("range_off") > 0) return;
01152 
01153     /// ...  Silvius: force insertion of ranges according to the Fortran 77
01154     /// ...  standard for the following case:
01155     /// ...  DIMENSION A(m,n:p,*)
01156     /// ...  DO i=1,k
01157     /// ...    DO j=h,100
01158     /// ...      A(i,j,...)=...
01159     /// ...  In this case, since the access on A must be within bounds we
01160     /// ...  will add to the dictionary the following ranges:
01161     /// ...  k=[1,m] and h=[n:p].
01162     /// ...  Silvius: since I do not want to get to the guts of the AIRangeDict,
01163     /// ...  we will force the insertionof the ranges by inserting some guards in
01164     /// ...  the code, such as:
01165     /// ...  IF (1.LE.k.AND.k.LE.m) THEN
01166     /// ...    DO i=1,k
01167     RefList<Statement> new_ifs;
01168     enforce_standard_within_bounds(pgm, new_ifs);
01169 
01170 
01171     /// ...  An array that maps integers to statements.
01172     Array<Statement *> toporder_to_stmt;
01173 
01174     _debug_level = debug;
01175     Timer tot_timer;
01176     Timer timer;
01177     float avg_visits, avg_cd_entries;
01178 
01179     /// ...  Initialize
01180 
01181     remove_min_max_var_conflicts(pgm.symtab());
01182 
01183     ::_pass_tag = create_pass_tag();
01184     _init_workspaces(pgm.stmts());
01185 
01186     if (switch_value("pc_call_mods") != 1)
01187     _make_nonlocals_modified_at_calls(pgm);
01188 
01189     _add_flow_edges(pgm.stmts());
01190     /// ...  _patch_flow_graph(pgm.stmts());
01191     _calc_toporder(pgm.stmts(), toporder_to_stmt);
01192     _set_needs_widening(pgm.stmts());
01193     _calc_loop_variants(pgm.stmts());
01194 
01195     if (_debug_level > 0) {
01196     cout << "!  Initialization: " << timer << endl;
01197     timer.reset();
01198     }
01199 
01200     /// ...  Iteratively propagate the constants throughout the program until a
01201     /// ...  fixed point is reached.
01202 
01203     _iterate_to_fixed_point(pgm, toporder_to_stmt);
01204 
01205     if (_debug_level > 0) {
01206     cout << "!  Iterating to fixed point: " << timer << endl;
01207     _collect_stats(pgm.stmts(), avg_visits, avg_cd_entries);
01208     timer.reset();
01209     }
01210 
01211     /// ...  Dump ranges from the SafeCondition assertions into the PropRangeWS
01212     /// ...  on each statement of a loop body.  This may change in the future with
01213     /// ...  the demand-driven structure.  We may want to keep the SafeCondition
01214     /// ...  assertions separate, and use them only if we can't prove a loop parallel
01215     /// ...  with the "known" ranges.
01216 
01217     _add_safe_cond_ranges(pgm);
01218 
01219     /// ...  Generate the mapping between statements and ranges
01220 
01221     _generate_map(pgm);
01222 
01223     if (_debug_level > 0)
01224     cout << "!  Generating stmt_ranges: " << timer << endl;
01225 
01226     if (_debug_level >= 10)
01227     _dump_workspaces(cout, pgm.stmts());
01228 
01229     /// ...  Clean up
01230 
01231     pgm.clean_workspace(::_pass_tag);
01232     clean_after_standard_enforcement(pgm, new_ifs);
01233 
01234     if (_debug_level > 0) {
01235     cout << "!  Total time: " << tot_timer << endl;
01236     cout << "!  Number of statements: " << pgm.stmts().entries() << endl;
01237     cout << "!  Average num visits: " << avg_visits << endl;
01238     cout << "!  Average StmtRanges entries (weighted): "
01239         << avg_cd_entries << endl;
01240     }
01241 }
01242 
01243 AIRangeDict::AIRangeDict(const AIRangeDict &other)
01244 : RangeDict(other)
01245 {
01246     #ifdef CLASS_INSTANCE_REGISTRY
01247     register_instance(AIRANGE_DICT, sizeof(AIRangeDict), this);
01248     #endif
01249 
01250     *this = other;
01251 }
01252 
01253 
01254 /// Destructor
01255 
01256 AIRangeDict::~AIRangeDict()
01257 {
01258     #ifdef CLASS_INSTANCE_REGISTRY
01259     unregister_instance(AIRANGE_DICT, this);
01260     #endif
01261 
01262     /// ...  nothing to do
01263 }
01264 
01265 
01266 /// operator =
01267 
01268 AIRangeDict &
01269 AIRangeDict::operator = (const AIRangeDict &other)
01270 {
01271     if (this != &other) {
01272     RangeDict::operator=(other);
01273     _stmt_ranges = other._stmt_ranges;
01274     }
01275 
01276     return *this;
01277 }
01278 
01279 
01280 /// range_vars
01281 /// 
01282 /// Return the set of symbols in the range dictionary for a given statement
01283 /// If no symbols exist for a statement, return 0.
01284 
01285 RefSet<Symbol> *
01286 AIRangeDict::range_vars( const String & tag ) const
01287 {
01288     const StmtRanges * ranges = _stmt_ranges.find_ref(tag);
01289 
01290     if (ranges) {
01291     return ranges->range_vars( );
01292     } else {
01293     return 0;
01294     }
01295 }
01296 
01297 
01298 /// elim_known_facts
01299 
01300 Expression *
01301 AIRangeDict::elim_known_facts( const String & tag, Expression * expr)
01302 {
01303     StmtRanges * ranges = _stmt_ranges.find_ref(tag);
01304 
01305     return ::elim_known_facts (expr, *ranges);
01306 }
01307 
01308 
01309 /// set_range
01310 
01311 void
01312 AIRangeDict::_set_range(const Symbol &var,
01313             const Statement &stmt, Expression *range)
01314 {
01315     StmtRanges *ranges = _stmt_ranges.find_ref(stmt.tag());
01316 
01317     if (! ranges) {
01318     ranges = new StmtRanges(symtab());
01319     _stmt_ranges.ins(stmt.tag(), ranges);
01320     }
01321 
01322     ranges->set_range(var, range);
01323 }
01324 
01325   
01326 
01327 /// del_range
01328 
01329 void
01330 AIRangeDict::_del_range(const Symbol &var, const Statement &stmt)
01331 {
01332     StmtRanges *ranges = _stmt_ranges.find_ref(stmt.tag());
01333 
01334     if (ranges)
01335     ranges->del_range(var);
01336 }
01337 
01338 
01339 
01340 /// get_range_ref
01341 
01342 const Expression *
01343 AIRangeDict::_get_range_ref(const Symbol &var, const Statement &stmt)
01344 {
01345     StmtRanges *ranges = _stmt_ranges.find_ref(stmt.tag());
01346 
01347     if (ranges)
01348     return ranges->get_range_ref(var);
01349 
01350     return 0;
01351 }
01352 
01353 
01354 
01355 /// print
01356 
01357 void
01358 AIRangeDict::print(ostream & o) const
01359 {
01360     KeyIterator<String, StmtRanges> iter = _stmt_ranges;
01361 
01362     for ( ; iter.valid(); ++iter)
01363     o << iter.current_key() << ": " << iter.current_data() << endl;
01364 }
01365 
01366 
01367 
01368 /// pretty_print
01369 
01370 void
01371 AIRangeDict::pretty_print(ostream & o, const Statement &stmt) const
01372 {
01373     const StmtRanges *ranges = _stmt_ranges.find_ref(stmt.tag());
01374 
01375     if (ranges)
01376     ranges->pretty_print(o);
01377     else
01378     o << "{}";
01379 }
01380 
01381 
01382 /// listable_clone
01383 
01384 Listable *
01385 AIRangeDict::listable_clone(void) const
01386 {
01387     return new AIRangeDict(*this);
01388 }
01389 
01390 
01391 
01392 /// structures_OK
01393 
01394 int
01395 AIRangeDict::structures_OK() const
01396 {
01397     return _stmt_ranges.structures_OK();
01398 }
01399 
01400 /// Return a reference to the StmtRanges object associated with
01401 /// the given statement tag.
01402 StmtRanges & 
01403 AIRangeDict::_s_ranges(const String & tag)
01404 {
01405     return _stmt_ranges[tag];
01406 }
01407 
01408 #if 0
01409 
01410 /// calc_loop_range
01411 ///   Determine the contraints that hold for the body of the given loop.
01412 
01413 static void
01414 _calc_loop_range(const Statement &do_loop, const StmtList &stmts,
01415          Database<String,StmtRanges> &stmt_ranges,
01416          Database<String,StmtRanges> &loop_ranges)
01417 {
01418     StmtRanges *result = 0;
01419 
01420     const Statement *stmt = stmts.next_ref(do_loop);
01421     
01422     while (stmt && stmt != do_loop.follow_ref()) {
01423     if (stmt->pred().entries() > 0) {
01424         StmtRanges *ranges
01425         = stmt_ranges.find_ref(stmt->tag());
01426 
01427         if (ranges)
01428         if (result)
01429             result->union_ranges(*ranges);
01430         else
01431             result = new StmtRanges(*ranges);
01432     }
01433     
01434     if (stmt->stmt_class() == DO_STMT) {
01435         _calc_loop_range(*stmt, stmts, stmt_ranges, loop_ranges);
01436         result->union_ranges(*loop_ranges.find_ref(stmt->tag()));
01437         stmt = stmt->follow_ref();
01438     }
01439     else
01440         stmt = stmts.next_ref(*stmt);
01441     }
01442 
01443     loop_ranges.ins(do_loop.tag(), result);
01444 }
01445 
01446 
01447 /// determine_loop_ranges
01448 ///   Print out all of the ranges for the given statement list
01449 
01450 void
01451 determine_loop_ranges(const StmtList &stmts,
01452               Database<String,StmtRanges> &stmt_ranges,
01453               Database<String,StmtRanges> &loop_ranges)
01454 {
01455     const Statement *stmt = stmts.first_ref();
01456     
01457     while (stmt) {
01458     if (stmt->stmt_class() == DO_STMT) {
01459         _calc_loop_range(*stmt, stmts, stmt_ranges, loop_ranges);
01460         stmt = stmt->follow_ref();
01461     }
01462     else
01463         stmt = stmts.next_ref(*stmt);
01464     }
01465 }
01466 
01467 #endif
 © 1995-2005 University of Illinois, Urbana-Champaign. All rights reserved.  Fri Mar 25 23:05:36 2005