Polaris: constant.cc Source File

constant.cc

Go to the documentation of this file.
00001 ///
00002 ///
00003 /// \file constant.cc
00004 ///
00005 #include "../ProgramUnit.h"
00006 #include "../Statement/Statement.h"
00007 #include "../Statement/GotoStmt.h"
00008 #include "../Statement/AssignmentStmt.h"
00009 #include "../Symbol/Symbol.h"
00010 #include "../Collection/Map.h"
00011 #include "../Collection/Iterator.h"
00012 #include "../Collection/Mutator.h"
00013 #include "../utilities/switches_util.h"
00014 #include "../utilities/removegotos_util.h"
00015 #include "../utilities/expression_util.h"
00016 #include "../utilities/equivalence_util.h"
00017 #include "../IntElem.h"
00018 #include "../IntSet.h"
00019 #include "../Array.h"
00020 #include "../Boolean.h"
00021 #include "../Timer.h"
00022 #include "../p-assert.h"
00023 #include "../macros.h"
00024 #include "../p-setjmp.h"
00025 #include "../interface.h"
00026 #include "../Range/range_dict_util.h"
00027 
00028 #include "PropConstWS.h"
00029 #include "PropConstMap.h"
00030 #include "IPCPProcData.h"
00031 #include "constant.h"
00032 
00033 static unsigned int _pass_tag;  /// ...  Pass tag associated with this pass
00034 
00035 static int _debug_level = 0;
00036 
00037 
00038 static Boolean _substituted_var = False;
00039                 /// ...  True if expand_substituted substituted
00040                 /// ...  a variable.
00041 static Boolean _stmt_substituted_var = False;
00042                 /// ...  True if expand_substituted substituted
00043                 /// ...  a variable for the current statement.
00044 
00045 
00046 /// substitutable_type
00047 ///   Returns true if the given type may be legally substituted
00048 
00049 static inline Boolean
00050 _substitutable_type(EXPR_TYPE type, PC_REAL_BOOL subst_reals)
00051 {
00052     if (type == INTEGER_TYPE
00053     || type == LOGICAL_TYPE
00054     || (subst_reals == SUBST_REALS
00055         && (type == REAL_TYPE
00056         || type == DOUBLE_PRECISION_TYPE
00057         || type == COMPLEX_TYPE)))
00058     return True;
00059 
00060     return False;
00061 }
00062 
00063 
00064 /// add_refs -
00065 ///   Add the given set of references to the given variable set.
00066 
00067 static void
00068 _add_refs(RefSet<Symbol> &vars, const RefSet<Expression> &refs)
00069 {
00070     Iterator<Expression> iter = refs;
00071     
00072     for ( ; iter.valid(); ++iter)
00073     if (iter.current().base_variable_ref())
00074         vars.ins(*iter.current().base_variable_ref());
00075 }
00076 
00077 
00078 /// filter_vars -
00079 ///   Filter out all variables from the given set that are disallowed by
00080 ///   my switch values.
00081 
00082 static void
00083 _filter_vars(RefSet<Symbol> &vars, PC_REAL_BOOL subst_reals,
00084          PC_ARRAY_BOOL subst_arrays)
00085 {
00086     Mutator<Symbol> iter = vars;
00087 
00088     for ( ; iter.valid(); ++iter) {
00089     const Symbol &var = iter.current();
00090 
00091     if (var.sym_class() != VARIABLE_CLASS
00092         || ! _substitutable_type(var.type().data_type(), subst_reals)
00093         || (subst_arrays != SUBST_ARRAYS && var.is_array()))
00094 
00095         iter.del();
00096     }
00097 }
00098 
00099 
00100 /// init_candidates -
00101 ///   Initialize def_candidates and use_candidates to be mappings from
00102 ///   elements in def_vars or use_vars to integers.  Also initialize
00103 ///   tag_to_candidates to be a reverse mapping of def_candidates and
00104 ///   use_candidates.  Variables in use_candidates and in def_candidates
00105 ///   will be assigned the same integer for both data structures.
00106 ///   Variables in def_candidates are assigned the smallest numbers.
00107 ///   It is assumed that use_candidates is a superset of def_candidates.
00108 
00109 static void
00110 _init_candidates(const RefSet<Symbol> &def_vars,
00111             const RefSet<Symbol> &use_vars,
00112             Map<Symbol,IntElem> &def_candidates,
00113             Map<Symbol,IntElem> &use_candidates,
00114             Array<Symbol *> &tag_to_candidate)
00115 {
00116     int tag = 0;
00117     tag_to_candidate.resize(use_vars.entries());
00118 
00119     /// ...  Initialize def_candidates.
00120 
00121     Iterator<Symbol> def_iter = def_vars;
00122 
00123     for ( ; def_iter.valid(); ++def_iter) {
00124     Symbol &var = def_iter.current();
00125     tag_to_candidate[tag] = &var;
00126     def_candidates.ins(var, new IntElem(tag++));
00127     }
00128 
00129     p_assert(tag == def_candidates.entries(),
00130          "Error in Map<Symbol,IntElem>::entries().");
00131 
00132     /// ...  Initialize use_candidates.
00133 
00134     Iterator<Symbol> use_iter = use_vars;
00135 
00136     for ( ; use_iter.valid(); ++use_iter) {
00137     Symbol &var = use_iter.current();
00138     IntElem *var_tag = def_candidates.find_ref(var);
00139 
00140     if (var_tag)
00141         use_candidates.ins(var, new IntElem(var_tag->value()));
00142     else {
00143         tag_to_candidate[tag] = &var;
00144         use_candidates.ins(var, new IntElem(tag++));
00145     }
00146     }
00147 
00148     p_assert(tag == use_candidates.entries(),
00149          "Error in Map<Symbol,IntElem>::entries().");
00150 }
00151 
00152 
00153 /// collect_candidates -
00154 ///   Determine all the variables that are candidates for forward substitution
00155 ///   and initialize the _candidates and _tag_to_candidates data structures
00156 ///   to contain these variables.
00157 
00158 static void
00159 _collect_candidates(const RefSet<Symbol> &def_vars,
00160             const StmtList &stmts,
00161             const Statement &first_stmt,
00162             const Statement &last_stmt,
00163             Map<Symbol,IntElem> &def_candidates,
00164             Map<Symbol,IntElem> &use_candidates,
00165             Array<Symbol *> &tag_to_candidate)
00166 {
00167     RefSet<Symbol> use_vars = def_vars;
00168     Iterator<Statement> stmt_iter = stmts.iterator(first_stmt, last_stmt);
00169 
00170     for ( ; stmt_iter.valid(); ++stmt_iter) {
00171     const Statement &stmt = stmt_iter.current();
00172 
00173     if (stmt.stmt_class() == ASSIGNMENT_STMT
00174         && stmt.lhs().op() == ID_OP
00175         && def_vars.member(stmt.lhs().symbol()))
00176 
00177         _add_refs(use_vars, stmt.in_refs());
00178     }
00179 
00180     _init_candidates(def_vars, use_vars, def_candidates, use_candidates,
00181              tag_to_candidate);
00182 }
00183 
00184 static void
00185 _collect_candidates(const StmtList &stmts,
00186             const Statement &first_stmt,
00187             const Statement &last_stmt,
00188             Map<Symbol,IntElem> &def_candidates,
00189             Map<Symbol,IntElem> &use_candidates,
00190             Array<Symbol *> &tag_to_candidate,
00191             PC_REAL_BOOL subst_reals,
00192             PC_ARRAY_BOOL subst_arrays)
00193 {
00194     RefSet<Symbol> def_vars;
00195     RefSet<Symbol> use_vars;
00196     Iterator<Statement> stmt_iter = stmts.iterator(first_stmt, last_stmt);
00197 
00198     for ( ; stmt_iter.valid(); ++stmt_iter) {
00199     const Statement &stmt = stmt_iter.current();
00200 
00201     if (stmt.stmt_class() == ASSIGNMENT_STMT
00202         && stmt.lhs().op() == ID_OP
00203         && stmt.rhs().is_side_effect_free()) {
00204 
00205         const Symbol &var = stmt.lhs().symbol();
00206 
00207         if (var.sym_class() == VARIABLE_CLASS
00208         && ! var.is_array()
00209         && _substitutable_type(var.type().data_type(), subst_reals)) {
00210 
00211         def_vars.ins(var);
00212         use_vars.ins(var);
00213         _add_refs(use_vars, stmt.in_refs());
00214         }
00215     }
00216     }
00217 
00218     _filter_vars(use_vars, subst_reals, subst_arrays);
00219     _init_candidates(def_vars, use_vars, def_candidates, use_candidates,
00220              tag_to_candidate);
00221 }
00222 
00223 
00224 /// create_data_assigns -
00225 ///   Create a list of pseudo assignment statements which assign all variables
00226 ///   in the program unit's data statements to their constant values.
00227 
00228 static List<Statement> *
00229 _create_data_assigns(ProgramUnit &pgm,
00230              const RefSet<Symbol> *candidates,
00231              PC_REAL_BOOL subst_reals)
00232 {
00233     List<Statement> *data_assigns = new List<Statement>;
00234     Iterator<Data> data_iter = pgm.data();
00235 
00236     for ( ; data_iter.valid(); ++data_iter) {
00237     Data &data = data_iter.current();
00238 
00239     if (data.variable_list().arg_list().entries()
00240         == data.value_list().arg_list().entries()) {
00241         
00242         Iterator<Expression> var_iter = data.variable_list().arg_list();
00243         Iterator<Expression> val_iter = data.value_list().arg_list();
00244         
00245         for ( ; var_iter.valid(); ++var_iter, ++val_iter) {
00246         Symbol *var = var_iter.current().base_variable_ref();
00247         
00248         if (var && ! var->is_array()
00249             && _substitutable_type(var->type().data_type(), subst_reals)
00250             && (! candidates || candidates->member(*var))) {
00251 
00252             Statement *data_assign
00253             = new AssignmentStmt(pgm.stmts().new_tag(),
00254                          var_iter.current().clone(),
00255                          val_iter.current().clone());
00256             data_assigns->ins_last(data_assign);
00257         }
00258         }
00259     }   
00260     }
00261     
00262     return data_assigns;
00263 }
00264 
00265 
00266 /// add_data_assigns -
00267 ///   Add a list of pseudo assignment statements at the beginning of a program
00268 ///   unit which assign all variables in the program unit's data statements
00269 ///   to their constant values.  A RefList of these statements is returned for
00270 ///   future deletion.  This function will only add such assignments if the
00271 ///   program unit is the main program.
00272 
00273 static void
00274 _add_data_assigns(ProgramUnit &pgm, const RefSet<Symbol> *candidates,
00275           PC_REAL_BOOL subst_reals, RefSet<Statement> &pseudo_stmts)
00276 {
00277     if (pgm.pu_class() == PROGRAM_PU_TYPE) {
00278     List<Statement> *data_assigns
00279         = _create_data_assigns(pgm, candidates, subst_reals);
00280 
00281     if (data_assigns->entries() > 0) {
00282         Iterator<Statement> assign_iter = *data_assigns;
00283 
00284         for ( ; assign_iter.valid(); ++assign_iter)
00285         pseudo_stmts.ins(assign_iter.current());
00286 
00287         Iterator<Statement> entry_iter = pgm.stmts().iterate_entry_points();
00288         p_assert(entry_iter.valid(),
00289              "Main program does not have any entries.");
00290         pgm.stmts().ins_after(data_assigns, &entry_iter.current());
00291         ++entry_iter;
00292         p_assert(! entry_iter.valid(),
00293              "Main program has multiple entries.");
00294     }
00295     else
00296         delete data_assigns;
00297     }
00298 }
00299 
00300 
00301 /// add_control_assigns -
00302 ///   Add a list of pseudo assignment statements at the start of the loop
00303 ///   bodies of IF statements that represent constants derived from the
00304 ///   conditional statement of the IF statement.  A RefList of these statements
00305 ///   is returned for future deletion.
00306 
00307 static void
00308 _add_control_assigns(StmtList &stmts, const Statement &first_stmt,
00309              const Statement &last_stmt,
00310              const RefSet<Symbol> *candidates,
00311              RefSet<Statement> &pseudo_stmts)
00312 {
00313     Iterator<Statement> stmt_iter = stmts.iterator(first_stmt, last_stmt);
00314 
00315     for ( ; stmt_iter.valid(); ++stmt_iter) {
00316     Statement &stmt = stmt_iter.current();
00317 
00318     if (stmt.stmt_class() == IF_STMT
00319         && stmt.follow_ref()->stmt_class() != ELSEIF_STMT
00320         && (stmt.expr().op() == ID_OP
00321         || (stmt.expr().op() == NOT_OP
00322             && stmt.expr().expr_guarded().op() == ID_OP)
00323         || stmt.expr().op() == EQ_OP
00324         || stmt.expr().op() == NE_OP)) {
00325 
00326         /// ...  Make sure that we have an ELSE clause.
00327 
00328         if (stmt.follow_ref()->stmt_class() == ENDIF_STMT) {
00329         Statement *last_then_stmt = stmt.follow_ref()->prev_ref();
00330 
00331         if (last_then_stmt->stmt_class() == IMPLIED_GOTO_STMT)
00332             last_then_stmt = last_then_stmt->prev_ref();
00333 
00334         stmts.ins_ELSE_after(&stmt, last_then_stmt);
00335         pseudo_stmts.ins(*stmt.follow_ref());
00336         }
00337 
00338         p_assert(stmt.follow_ref()->stmt_class() == ELSE_STMT,
00339              "IF statement does not have an ELSE clause.");
00340 
00341         Expression *logical_var_expr = &stmt.expr();
00342 
00343         if (logical_var_expr->op() == NOT_OP)
00344         logical_var_expr = &logical_var_expr->expr_guarded();
00345             
00346         if (logical_var_expr->op() == ID_OP
00347         && logical_var_expr->symbol().type().data_type() == LOGICAL_TYPE
00348         && (! candidates
00349             || candidates->member(logical_var_expr->symbol()))) {
00350 
00351         /// ...  Handle IF (FLAG) THEN ... or IF (.NOT. FLAG) THEN ...
00352 
00353         Statement *true_assign
00354             = new AssignmentStmt(stmts.new_tag(),
00355                      logical_var_expr->clone(),
00356                      constant(".TRUE."));
00357         Statement *false_assign
00358             = new AssignmentStmt(stmts.new_tag(),
00359                      logical_var_expr->clone(),
00360                      constant(".FALSE."));
00361 
00362         if (stmt.expr().op() == NOT_OP) {
00363             stmts.ins_after(false_assign, &stmt);
00364             stmts.ins_after(true_assign, stmt.follow_ref());
00365         }
00366         else {
00367             stmts.ins_after(true_assign, &stmt);
00368             stmts.ins_after(false_assign, stmt.follow_ref());
00369         }
00370 
00371         pseudo_stmts.ins(*true_assign);
00372         pseudo_stmts.ins(*false_assign);
00373         }
00374         else if (stmt.expr().op() == EQ_OP || stmt.expr().op() == NE_OP) {
00375         /// ...  Handle IF (X .EQ. 1) THEN ... or IF (X .NE. 1) THEN ...
00376 
00377         Expression *var_expr = 0;
00378         Expression *const_expr = 0;
00379 
00380         if (stmt.expr().left_guarded().op() == ID_OP) {
00381             var_expr = &stmt.expr().left_guarded();
00382             const_expr = &stmt.expr().right_guarded();
00383         }
00384         else {
00385             var_expr = &stmt.expr().right_guarded();
00386             const_expr = &stmt.expr().left_guarded();
00387         }
00388 
00389         if (var_expr->op() == ID_OP
00390             && var_expr->symbol().type().data_type() == INTEGER_TYPE
00391             && const_expr->op() == INTEGER_CONSTANT_OP
00392             && (! candidates
00393             || candidates->member(var_expr->symbol()))) {
00394 
00395             Statement *const_assign
00396             = new AssignmentStmt(stmts.new_tag(),
00397                          var_expr->clone(),
00398                          const_expr->clone());
00399             if (stmt.expr().op() == EQ_OP)
00400             stmts.ins_after(const_assign, &stmt);
00401             else
00402             stmts.ins_after(const_assign, stmt.follow_ref());
00403 
00404             pseudo_stmts.ins(*const_assign);
00405         }
00406         }
00407     }
00408     }
00409 }
00410 
00411 
00412 /// init_workspaces
00413 ///   Initialize the workspaces for each statement in the program.
00414 ///   Note: A lot of the initialization for propagate_constants are hidden
00415 ///   in the constructor for PropConstWS.
00416 
00417 static void
00418 _init_workspaces(StmtList &stmts,
00419          const Statement &first_stmt, const Statement &last_stmt,
00420          const Map<Symbol,IntElem> &def_candidates,
00421          const Map<Symbol,IntElem> &use_candidates,
00422          const Array<Symbol *> &tag_to_candidate)
00423 {
00424     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
00425 
00426     for ( ; iter.valid(); ++iter) {
00427     PropConstWS *my_ws = new PropConstWS(_pass_tag, iter.current(),
00428                          def_candidates, use_candidates,
00429                          tag_to_candidate);
00430 
00431     iter.current().work_stack().push(my_ws);
00432     }
00433 }
00434 
00435 
00436 /// get_workspace
00437 ///   Get the workspace for the given statement.
00438 
00439 static PropConstWS &
00440 _get_workspace(const Statement &stmt)
00441 {
00442     WorkSpace *ws = stmt.work_stack().top_ref(_pass_tag);
00443 
00444     p_assert(ws, "Statement doesn't have a ConstPropWS.");
00445 
00446     return * (PropConstWS *) ws;
00447 }
00448 
00449 
00450 /// dump_workspaces
00451 ///   Dump out the data inside all of the workspaces of the program
00452 
00453 static void
00454 _dump_workspaces(ostream &o, const StmtList &stmts,
00455          const Statement &first_stmt, const Statement &last_stmt)
00456 {
00457     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
00458 
00459     for ( ; iter.valid(); ++iter) {
00460     iter.current().structures_OK();
00461     o << iter.current().tag() << ": ";
00462     iter.current().print_debug(o, 0);
00463     o << endl;
00464     _get_workspace(iter.current()).pretty_print(o);
00465     }
00466 }
00467 
00468 
00469 /// _make_nonlocals_modified_at_calls
00470 ///   Make all non-local variables be marked as potentially modified for all
00471 ///   call statements and all statements containing function calls.
00472 
00473 static void
00474 _make_nonlocals_modified_at_calls(StmtList &stmts,
00475                   const Statement &first_stmt,
00476                   const Statement &last_stmt,
00477                   const Map<Symbol,IntElem> &use_candidates,
00478                   const Array<Symbol *> &tag_to_candidate)
00479 {
00480     /// ...  Calculate the set of non-local variables.
00481 
00482     IntSet non_local_set(tag_to_candidate.entries());
00483 
00484     if (switch_value("pc_call_mods") != 1) {
00485     for (int sym_tag = 0; sym_tag < tag_to_candidate.entries(); ++sym_tag) {
00486         Symbol &var = *tag_to_candidate[sym_tag];
00487         
00488         if (var.formal() == IS_FORMAL || var.common_ref()) {
00489         non_local_set.ins(sym_tag);
00490         
00491         /// ...  Mark any variables aliased to the non-local variable
00492         /// ...  as also non-local.
00493         
00494         RefSet<Symbol> *aliases = equiv_aliases(var);
00495         
00496         if (aliases) {
00497             Iterator<Symbol> alias_iter = *aliases;
00498             
00499             for ( ; alias_iter.valid(); ++alias_iter) {
00500             const IntElem *alias_elem
00501                 = use_candidates.find_ref(alias_iter.current());
00502             
00503             if (alias_elem)
00504                 non_local_set.ins(alias_elem->value());
00505             }
00506             
00507             delete aliases;
00508         }
00509         }
00510     }
00511     }
00512 
00513     /// ...  Add the non-local variables to the mod_set of all statements that
00514     /// ...  are either call statements or contain function calls.
00515 
00516     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
00517 
00518     for ( ; iter.valid(); ++iter) {
00519     Statement &stmt = iter.current();
00520     PropConstWS &ws = _get_workspace(stmt);
00521 
00522     if (ws.unknown_call) {
00523         PropConstMap &const_map = ws.out_const_map;
00524         RefSet<Symbol> *maymods = stmt_maymods(stmt);
00525 
00526         if (maymods) {
00527         Iterator<Expression> act_iter = stmt.act_refs();
00528 
00529         for ( ; act_iter.valid(); ++act_iter) {
00530             Symbol *var_ref = act_iter.current().base_variable_ref();
00531 
00532             if (var_ref) {
00533             const IntElem *tag_elem = use_candidates.find_ref(*var_ref);
00534 
00535             if (tag_elem)
00536                 ws.mod_set.del(tag_elem->value());
00537             }
00538         }
00539 
00540         if (stmt.stmt_class() == ASSIGNMENT_STMT) {
00541             Symbol *var_ref = stmt.lhs().base_variable_ref();
00542             
00543             if (var_ref) {
00544             const IntElem *tag_elem = use_candidates.find_ref(*var_ref);
00545 
00546             if (tag_elem)
00547                 ws.mod_set.ins(tag_elem->value());
00548             }
00549         }
00550 
00551         Iterator<Symbol> nl_iter = *maymods;
00552         
00553         for ( ; nl_iter.valid(); ++nl_iter) {
00554             const IntElem *tag_elem = use_candidates.find_ref(nl_iter.current());
00555 
00556             if (tag_elem) {
00557               int sym_tag = tag_elem->value();
00558               if (sym_tag != ws.lhs_tag()){
00559             const_map[sym_tag].non_const(stmt);
00560             const_map.int_non_const(sym_tag);
00561               }
00562             }
00563         }
00564 
00565         delete maymods;
00566         }
00567         else {
00568         ws.mod_set |= non_local_set;
00569         
00570         for (int sym_tag = non_local_set.first();
00571              sym_tag != -1;
00572              sym_tag = non_local_set.next(sym_tag)) {
00573             
00574             const_map[sym_tag].non_const(stmt);
00575             const_map.int_non_const(sym_tag);
00576         }
00577         }
00578     }
00579     }
00580 }
00581 
00582 
00583 /// patch_flow_graph
00584 ///   Add flow edges from all ENDDO statements in the flow graph to the
00585 ///   statement following the ENDDO.  These edges are added so to allow constant
00586 ///   information calculated inside a DO loop to be propagated to statements
00587 ///   after a DO loop in the same iteration.  Without these additional edges,
00588 ///   constant information calculated inside a loop can affect statements
00589 ///   after the loop only on the successive iteration.  This would mean that
00590 ///   the the number of iterations required will be a multiple of the depth of
00591 ///   the maximum loop nesting of the program.
00592 
00593 static void
00594 _patch_flow_graph(StmtList &stmts,
00595           const Statement &first_stmt, const Statement &last_stmt)
00596 {
00597     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
00598 
00599     for ( ; iter.valid(); ++iter) {
00600     Statement &curr = iter.current();
00601 
00602     if (curr.stmt_class() == ENDDO_STMT) {
00603         Statement &next = * (Statement *) curr.next_ref();
00604         
00605         if (next.work_stack().top_ref(_pass_tag) != 0) {
00606         _get_workspace(curr).succ.ins(next);
00607         _get_workspace(next).pred.ins(curr);
00608         }
00609     }
00610     }
00611 }
00612 
00613 
00614 /// num_stmts_in_block
00615 ///   Return the number of statements in the given block.
00616 
00617 static int
00618 _num_stmts_in_block(const StmtList &stmts, const Statement &first_stmt,
00619             const Statement &last_stmt)
00620 {
00621     int entries = 0;
00622 
00623     if (stmts.first_ref() == &first_stmt
00624     && stmts.last_ref() == &last_stmt)
00625 
00626     entries = stmts.entries();
00627 
00628     else {
00629     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
00630     
00631     for ( ; iter.valid(); ++iter)
00632         ++entries;
00633     }
00634 
00635     return entries;
00636 }
00637 
00638 
00639 /// determine_entry_points.
00640 ///   Determine all the entry statements for the given block of statements.
00641 ///   Simultaneously, delete all predecessors and successor edges entering/
00642 ///   exiting the block.
00643 
00644 static void
00645 _determine_entry_points(StmtList &stmts, const Statement &first_stmt,
00646             const Statement &last_stmt,
00647             RefSet<Statement> &entry_points)
00648 {
00649     RefList<Statement> stmts_in_block;
00650     Boolean entire_stmt_list = (stmts.first_ref() == &first_stmt
00651                 && stmts.last_ref() == &last_stmt);
00652 
00653     if (! entire_stmt_list) {
00654     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
00655     
00656     for ( ; iter.valid(); ++iter)
00657         stmts_in_block.ins_last(iter.current());
00658     }
00659 
00660     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
00661     
00662     for ( ; iter.valid(); ++iter) {
00663     Statement &stmt = iter.current();
00664 
00665     if (stmt.stmt_class() == ENTRY_STMT
00666         || stmt.stmt_class() == FLOW_ENTRY_STMT)
00667 
00668         entry_points.ins(stmt);
00669     else if (! entire_stmt_list) {
00670         PropConstWS &ws = _get_workspace(stmt);
00671         Mutator<Statement> pred_iter = ws.pred;
00672     
00673         for ( ; pred_iter.valid(); ++pred_iter)
00674         if (! stmts_in_block.member(pred_iter.current())) {
00675             entry_points.ins(stmt);
00676             pred_iter.del();
00677         }
00678 
00679         Mutator<Statement> succ_iter = ws.succ;
00680     
00681         for ( ; succ_iter.valid(); ++succ_iter)
00682         if (! stmts_in_block.member(succ_iter.current()))
00683             succ_iter.del();
00684     }
00685     }
00686 }
00687 
00688 
00689 /// _calc_toporder
00690 ///   Calculate toporder for the flow graph.  Essentially, this algorithm
00691 ///   performs a topological sort on the flow graph, ignoring back
00692 ///   edges.
00693 
00694 static void
00695 _calc_toporder1(PropConstWS &my_ws, int &toporder)
00696 {
00697     my_ws.visited(1);
00698 
00699     Iterator<Statement> succ_iter = my_ws.succ;
00700     
00701     for ( ; succ_iter.valid(); ++succ_iter) {
00702     PropConstWS &succ_ws = _get_workspace(succ_iter.current());
00703 
00704     if (! succ_ws.visited())
00705         _calc_toporder1(succ_ws, toporder);
00706     }
00707 
00708     my_ws.toporder(toporder--);
00709 }
00710 
00711 static void
00712 _calc_toporder(StmtList &stmts, const Statement &first_stmt,
00713            const Statement &last_stmt,
00714            const RefSet<Statement> &entry_points,
00715            Array<Statement *> &toporder_to_stmt)
00716 { 
00717     /// ...  Calculate the topological order for each statement
00718 
00719     int num_stmts = _num_stmts_in_block(stmts, first_stmt, last_stmt);
00720     int toporder = num_stmts - 1;
00721 
00722     if (toporder >= 0) {
00723     Iterator<Statement> entry_iter = entry_points;
00724 
00725     for ( ; entry_iter.valid(); ++entry_iter) {
00726         PropConstWS &entry_ws = _get_workspace(entry_iter.current());
00727 
00728         if (! entry_ws.visited())
00729         _calc_toporder1(entry_ws, toporder);
00730     }
00731  
00732     p_assert(toporder >= -1,
00733          "_calc_toporder visited a stmt more than once.");
00734     }
00735 
00736     /// ...  Initialize toporder_to_stmt
00737 
00738     toporder_to_stmt.resize(num_stmts);
00739 
00740     for (int i = 0; i <= toporder; ++i)
00741     toporder_to_stmt[i] = 0;
00742 
00743     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
00744 
00745     for ( ; iter.valid(); ++iter) {
00746     int stmt_toporder = _get_workspace(iter.current()).toporder();
00747 
00748     if (stmt_toporder >= 0)
00749         toporder_to_stmt[stmt_toporder] = &iter.current();
00750     }
00751 }
00752 
00753 
00754 /// _annotate_expr
00755 ///   Annotate the substituted field of variables of the given expression with
00756 ///   their constant values.  If certain constant values must be substituted,
00757 ///   this algorithm will perform the substitution.  If any of the variables
00758 ///   that must be substituted in the given expression is non-constant, this
00759 ///   function will return NULL.
00760 
00761 static Expression *
00762 _annotate_expr(Expression *expr,
00763            const PropConstMap &orig_const_map,
00764            const PropConstMap &curr_const_map,
00765            const Map<Symbol,IntElem> &use_candidates)
00766 {
00767     if (! expr)
00768     return expr;
00769       
00770     if (expr->op() == ID_OP) {
00771     if (! expr->substituted_valid()) {
00772         const IntElem *tag_elem
00773         = use_candidates.find_ref(expr->symbol());
00774         Expression *subst_expr = 0;
00775         
00776         if (tag_elem) {
00777         int sym_tag = tag_elem->value();
00778 
00779         if (orig_const_map.int_state(sym_tag) == CONST) {
00780             int int_const = orig_const_map.int_const_val(sym_tag);
00781 
00782             if (expr->symbol().type().data_type() == LOGICAL_TYPE)
00783             if (int_const == 0)
00784                 subst_expr = constant(".FALSE.");
00785             else
00786                 subst_expr = constant(".TRUE.");
00787             else
00788             subst_expr = constant(int_const);
00789         }
00790         else {
00791             PropConstElem &curr_const = curr_const_map[sym_tag];
00792             Boolean var_is_poisoned = False;
00793 
00794             if (curr_const.state() == CONST) {
00795             PropConstWS &subst_ws = _get_workspace(*curr_const.last_mod());
00796             var_is_poisoned = subst_ws.poisoned_vars[sym_tag];
00797             
00798             if (! var_is_poisoned) {
00799                 subst_ws.poisoned_vars.ins(sym_tag);
00800                 subst_expr = curr_const.expr().clone();
00801                 clear_substituted(*subst_expr);
00802                 subst_expr = _annotate_expr(subst_expr,
00803                             orig_const_map,
00804                             subst_ws.in_const_map,
00805                             use_candidates);
00806                 subst_ws.poisoned_vars.del(sym_tag);
00807             }
00808             }
00809             
00810             PropConstElem &orig_const = orig_const_map[sym_tag];
00811             
00812             if (var_is_poisoned
00813             || orig_const.last_mod() != curr_const.last_mod()
00814             || orig_const.state() != curr_const.state()) {
00815             
00816             /// ...  We must substitute the constant value of
00817             /// ...  the variable because either an earlier
00818             /// ...  substitution poisoned the variable or the
00819             /// ...  definition point of that variable for the
00820             /// ...  given expression differs from the
00821             /// ...  definition point of that variable for the
00822             /// ...  statement being annotated.
00823             
00824             delete expr;
00825             return subst_expr;
00826             }
00827         }       
00828         }
00829 
00830         expr->substituted(subst_expr);
00831     }
00832     else {
00833         /// ...  Expression already has a filled substituted field.
00834 
00835         expr->substituted(_annotate_expr(expr->grab_substituted(),
00836                          orig_const_map, curr_const_map,
00837                          use_candidates));
00838     }
00839     }
00840     else {
00841     Mutator<Expression> iter = expr->arg_list();
00842 
00843     for ( ; iter.valid(); ++iter) {
00844         Assign<Expression> eas(iter.assign());
00845         Expression *new_expr = _annotate_expr(iter.pull(), orig_const_map,
00846                           curr_const_map,
00847                           use_candidates);
00848 
00849         if (! new_expr) {
00850         delete expr;
00851         return 0;
00852         }
00853         else
00854         eas = new_expr;
00855     }
00856     }
00857 
00858     return expr;
00859 }
00860 
00861 
00862 /// _annotate_expr
00863 ///   Annotate the substituted field of variables of the given expression with
00864 ///   their constant values.
00865 
00866 static Expression *
00867 _annotate_expr(Expression *expr, const PropConstMap &const_map,
00868            const Map<Symbol,IntElem> &use_candidates)
00869 {
00870     Expression *new_expr = _annotate_expr(expr, const_map,
00871                       const_map, use_candidates);
00872     p_assert(new_expr,
00873          "Internal Error: _annotate_expr failed for root expression.");
00874 
00875     return new_expr;
00876 }
00877 
00878 Expression *
00879 _annotate_expr(Expression *expr, const Statement &stmt,
00880            const Map<Symbol,IntElem> &use_candidates)
00881 {
00882     PropConstWS &my_ws = _get_workspace(stmt);
00883     PropConstMap &const_map = my_ws.out_const_map;
00884 
00885     return _annotate_expr(expr, const_map, use_candidates);
00886 }
00887 
00888 
00889 /// _annotate_assert
00890 ///   Annotate assertions of the given statement with the calculated constant
00891 ///   expressions
00892 
00893 static void
00894 _annotate_assert(Statement &stmt, const PropConstMap &const_map,
00895          const Map<Symbol,IntElem> &use_candidates)
00896 {
00897     Iterator<Assertion> ass_iter = stmt.assertions();
00898 
00899     for ( ; ass_iter.valid(); ++ass_iter) {
00900         if (ass_iter.current().arg_list_valid()) {
00901             Mutator<Expression> aexpr_iter
00902         = ass_iter.current().arg_list_guarded(); 
00903 
00904             for ( ; aexpr_iter.valid(); ++aexpr_iter)
00905         if (aexpr_iter.current().op() != ID_OP) {
00906             Assign<Expression> eas(aexpr_iter.assign());
00907             eas = _annotate_expr(aexpr_iter.pull(),
00908                      const_map,
00909                      use_candidates);
00910         }
00911     }
00912     }
00913 }
00914 
00915 
00916 /// _annotate_stmt
00917 ///   Annotate expressions the given statement with the calculated constant
00918 ///   expressions
00919 
00920 static void
00921 _annotate_stmt(Statement &stmt, const Map<Symbol,IntElem> &use_candidates)
00922 {
00923     if (_debug_level >= 5) {
00924     cout << "!    Before: ";
00925     stmt.print_debug(cout, 0);
00926     cout << endl;
00927     }
00928 
00929     /// ...  Create a copy of my entering constants, where all variables
00930     /// ...  modified by myself is marked as non-constant.
00931 
00932     PropConstWS &my_ws = _get_workspace(stmt);
00933     PropConstMap unmodified_const_map(my_ws.in_const_map);
00934 
00935     for (int sym_tag = my_ws.mod_set.first();
00936      sym_tag != -1;
00937      sym_tag = my_ws.mod_set.next(sym_tag)) {
00938     unmodified_const_map[sym_tag].non_const(stmt);
00939     unmodified_const_map.int_non_const(sym_tag);
00940     }
00941     
00942     /// ...  Annotate all the expressions in myself.
00943 
00944     if (stmt.stmt_class() == ASSIGNMENT_STMT
00945     && stmt.rhs().is_side_effect_free()) {
00946 
00947     Mutator<Expression> iter = stmt.iterate_expressions();
00948 
00949     /// ...  Update lhs.
00950     Assign<Expression> eas(iter.assign());
00951     eas = _annotate_expr(iter.pull(), unmodified_const_map,
00952                  use_candidates);
00953 
00954     /// ...  Update rhs, ignoring the modification to the lhs variable.
00955     ++iter;
00956     Assign<Expression> eas2(iter.assign());
00957     eas2 = _annotate_expr(iter.pull(), my_ws.in_const_map,
00958                   use_candidates);
00959     }
00960     else {
00961     Mutator<Expression> iter = stmt.iterate_expressions();
00962     
00963     for ( ; iter.valid(); ++iter) {
00964         Assign<Expression> eas3(iter.assign());
00965         eas3 = _annotate_expr(iter.pull(), unmodified_const_map,
00966                   use_candidates);
00967     }
00968     }
00969 
00970     _annotate_assert(stmt, unmodified_const_map, use_candidates);
00971 
00972     if (_debug_level >= 5) {
00973     cout << "!    After: ";
00974     stmt.print_debug(cout, 0);
00975     cout << endl;
00976     }
00977 }
00978 
00979 
00980 /// annotate_stmts
00981 ///   Annotate each statement of the given block of statements with its
00982 ///   calculated constant expressions.
00983 
00984 static void
00985 _annotate_stmts(StmtList &stmts, const Statement &first_stmt,
00986         const Statement &last_stmt,
00987         const Map<Symbol,IntElem> &use_candidates)
00988 {
00989     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
00990 
00991     for ( ; iter.valid(); ++iter)
00992     _annotate_stmt(iter.current(), use_candidates);
00993 }
00994 
00995 
00996 /// kill_bad_join_consts
00997 ///   Kill any constant expressions formed by the join of two or more
00998 ///   reaching definitions, whose constant expression is no longer
00999 ///   valid for one of these definitions.  That is, one of the variables
01000 ///   used by the constant expression was modified somewhere along a
01001 ///   control flow path from the definition to the current statement.
01002 
01003 void
01004 _kill_bad_join_consts(Statement &stmt, PropConstMap &const_map)
01005 {
01006     PropConstWS &curr_ws = _get_workspace(stmt);
01007 
01008     if (curr_ws.pred.entries() < 2)
01009     return;
01010 
01011     for (int sym_tag = 0; sym_tag < const_map.entries(); ++sym_tag) {
01012     PropConstElem &const_elem = const_map[sym_tag];
01013 
01014     if (const_elem.state() == CONST
01015         && const_elem.last_mod() == &stmt
01016         && const_elem.use_set().entries() > 0) {
01017 
01018         /// ...  We have a join of two or more definitions of a constant
01019         /// ...  symbolic expression.
01020 
01021         /// ...  Test each of its reaching definitions.
01022 
01023         Boolean has_modified_use = False;
01024         Iterator<Statement> pred_iter = curr_ws.pred;
01025 
01026         for ( ; pred_iter.valid() && ! has_modified_use; ++pred_iter) {
01027         PropConstWS &pred_ws = _get_workspace(pred_iter.current());
01028 
01029         if (pred_ws.num_visits() > 0) {
01030             PropConstMap &pred_map = pred_ws.out_const_map;
01031             PropConstElem &pred_elem = pred_map[sym_tag];
01032             
01033             if (pred_elem.state() != MAY_BE_CONST) {
01034             p_assert(pred_elem.state() == CONST,
01035                  "Predecessor of constant expression is a non-constant.");
01036             
01037             PropConstMap &last_mod_map
01038                 = _get_workspace(*pred_elem.last_mod()).out_const_map;
01039             
01040             /// ...  Test each of its uses.
01041             
01042             for (int use_tag = pred_elem.use_set().first();
01043                  use_tag != -1 && ! has_modified_use;
01044                  use_tag = pred_elem.use_set().next(use_tag))
01045                 if (last_mod_map[use_tag].last_mod()
01046                 != pred_map[use_tag].last_mod())
01047                 
01048                 has_modified_use = True;
01049             }
01050         }
01051         }
01052         
01053         if (has_modified_use)
01054         const_elem.non_const(stmt);
01055     }
01056     }
01057 }
01058 
01059 
01060 /// _const_if_took_then
01061 ///   Return true if I am an IF statement with a constant conditional
01062 ///   expression that took only the THEN clause.
01063 
01064 static Boolean
01065 _const_if_took_then(const Statement &stmt)
01066 {
01067     if (stmt.stmt_class() != IF_STMT && stmt.stmt_class() != ELSEIF_STMT)
01068     return False;
01069 
01070     const PropConstWS &ws = _get_workspace(stmt);
01071 
01072     if (ws.num_visits() == 0 || ! ws.const_cond)
01073     return False;
01074 
01075      return (_get_workspace(*stmt.next_ref()).num_visits() > 0);
01076 }
01077 
01078 
01079 /// _const_if_succ
01080 ///   If I am a constant IF statement, return my single successor.  Otherwise
01081 ///   return NULL.
01082 
01083 Statement *
01084 _const_if_succ(Statement &stmt,
01085            const Map<Symbol,IntElem> &use_candidates)
01086 {
01087     if (stmt.stmt_class() != IF_STMT
01088     && stmt.stmt_class() != ELSEIF_STMT
01089     && stmt.stmt_class() != ARITHMETIC_IF_STMT)
01090 
01091     return 0;
01092 
01093     int cond_result;
01094     const PropConstWS &ws = _get_workspace(stmt);
01095     Statement *succ = 0;
01096 
01097     if (int_const_val(stmt.expr(), ws.in_const_map, use_candidates,
01098               cond_result)) {
01099     if (stmt.stmt_class() == IF_STMT || stmt.stmt_class() == ELSEIF_STMT) {
01100         if (cond_result == 0)
01101         succ = stmt.follow_ref();
01102         else
01103         succ = stmt.next_ref();
01104     }
01105     else {
01106         if (cond_result < 0)
01107         succ = &stmt.label_list()[0];
01108         else if (cond_result == 0)
01109         succ = &stmt.label_list()[1];
01110         else
01111         succ = &stmt.label_list()[2];
01112     }
01113     }
01114 
01115     return succ;
01116 }
01117 
01118 
01119 /// put_succ_on_work_list
01120 ///   Put all of my successors on the work list.
01121 
01122 static void
01123 _put_succ_on_work_list(IntSet &work_list, Statement &stmt,
01124                const Map<Symbol,IntElem> &use_candidates)
01125 {
01126     PropConstWS &ws = _get_workspace(stmt);
01127 
01128     if (ws.const_cond) {
01129     const Statement *succ = _const_if_succ(stmt, use_candidates);
01130 
01131     if (! succ)
01132         ws.const_cond = False;
01133     else {
01134         if (_debug_level >= 5) {
01135         cout << "!    Statement: ";
01136         stmt.print_debug(cout, 0);
01137         cout << " has a constant conditional\n";
01138         }
01139 
01140         work_list.ins(_get_workspace(*succ).toporder());
01141     }
01142     }
01143 
01144     if (! ws.const_cond) {
01145     Iterator<Statement> succ_iter = ws.succ;
01146 
01147     for ( ; succ_iter.valid(); ++succ_iter)
01148         work_list.ins(_get_workspace(succ_iter.current()).toporder());
01149     }
01150 }
01151 
01152 
01153 /// iterate_to_fixed_point
01154 ///   Propagate the constants contained in the statement's const_maps until
01155 ///   a fixed point is reached.
01156 
01157 static void
01158 _iterate_to_fixed_point(StmtList & /* stmts */, 
01159             const Statement & /* first_stmt */,
01160             const Statement & /* last_stmt */,
01161             const RefSet<Statement> &entry_points,
01162             const Array<Statement *> &toporder_to_stmt,
01163             const Map<Symbol,IntElem> &use_candidates,
01164             const Array<Symbol *> &tag_to_candidate, 
01165             const Map<Symbol, Expression> &entering_constants)
01166 {
01167     /// ...  List of statements that need to be updated.
01168 
01169     IntSet work_list(toporder_to_stmt.entries());
01170 
01171     /// ...  Put all entries on the work list.
01172 
01173     Iterator<Statement> entry_iter = entry_points;
01174 
01175     for ( ; entry_iter.valid(); ++entry_iter)
01176     work_list.ins(_get_workspace(entry_iter.current()).toporder());
01177 
01178     /// ...  Iterate until there are no more elements on the work list
01179 
01180     while (work_list.entries() > 0) {
01181     /// ...  Visit each statement in the work list, in topological order
01182     
01183     for (int stmt_num = work_list.first();
01184          stmt_num != -1;
01185          stmt_num = work_list.next(stmt_num)) {
01186         
01187         Statement &curr = *toporder_to_stmt[stmt_num];
01188         work_list.del(stmt_num);
01189         PropConstWS &curr_ws = _get_workspace(curr);
01190         curr_ws.incr_num_visits();
01191         Boolean changed = False;
01192         
01193         /// ...  Generate the new constant mapping entering the statement.
01194         
01195         PropConstMap new_in_const_map(use_candidates.entries(),
01196                       tag_to_candidate);
01197         
01198         if (entry_points.member(curr)) {
01199         new_in_const_map.all_non_const(curr);
01200         curr_ws.add_consts(entering_constants);
01201         }
01202         else {
01203         Iterator<Statement> pred_iter = curr_ws.pred;
01204         
01205         for ( ; pred_iter.valid(); ++pred_iter) {
01206             PropConstWS &pred_ws = _get_workspace(pred_iter.current());
01207             
01208             if (pred_ws.num_visits() > 0
01209             && (curr.stmt_class() != ENDIF_STMT
01210                 || ! _const_if_took_then(pred_iter.current())))
01211             
01212             new_in_const_map.intersect(pred_ws.out_const_map,
01213                            curr);
01214         }
01215         }
01216         
01217         _kill_bad_join_consts(curr, new_in_const_map);
01218         
01219         if (curr_ws.num_visits() == 1
01220         || new_in_const_map != curr_ws.in_const_map) {
01221         
01222         /// ...  New entering constant mapping differs from the old
01223         /// ...  one.  So update the entering and exiting constant
01224         /// ...  mappings for the statement.
01225         
01226         if (_debug_level >= 20) {
01227             cout << "!    Statement ";
01228             curr.print_debug(cout, 0);
01229             cout << " was visited and updated.\n";
01230         }
01231         
01232         curr_ws.in_const_map = new_in_const_map;
01233         changed = curr_ws.update_out_const_map();
01234         
01235         if (! changed
01236             && curr_ws.const_cond
01237             && _const_if_succ(curr, use_candidates) == 0) {
01238             
01239             curr_ws.const_cond = False;
01240             changed = True;
01241         }
01242         
01243         if (_debug_level >= 30)
01244             curr_ws.pretty_print(cout);
01245         
01246         if (changed || curr_ws.num_visits() == 1) {
01247             /// ...  Exiting constant map has changed, so place
01248             /// ...  the statements successors on the work list so
01249             /// ...  that they can update their constant mappings
01250             /// ...  with my new constant mapping.
01251             
01252             _put_succ_on_work_list(work_list, curr, use_candidates);
01253         }
01254         }
01255     }
01256     }
01257 }
01258 
01259 
01260 /// is_block_unreachable
01261 ///   Return True if the block fo code between the given pair of statements
01262 ///   is unreachable code.
01263 
01264 static Boolean
01265 _is_block_unreachable(const StmtList &stmts,
01266               const Statement &first_stmt,
01267               const Statement &last_stmt)
01268 {
01269     /// ...  Note: implied goto statements must be ignored because the
01270     /// ...  insertion and deletion of the pseudo-ELSEs may leave visited
01271     /// ...  implied gotos.
01272 
01273     Boolean is_block_unreachable = True;
01274     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
01275 
01276     for ( ; iter.valid() && is_block_unreachable; ++iter)
01277     if (iter.current().stmt_class() != IMPLIED_GOTO_STMT
01278         && _get_workspace(iter.current()).num_visits() > 0)
01279         is_block_unreachable = False;
01280     
01281     return is_block_unreachable;
01282 }
01283 
01284 
01285 /// remove_unreachable
01286 ///   Remove any dead code in the program.
01287 
01288 static void
01289 _remove_unreachable(StmtList &stmts, 
01290             const Statement &first_stmt,
01291             const Statement &last_stmt,
01292             const Map<Symbol,IntElem> &use_candidates)
01293 {
01294     Boolean deleted_a_stmt = False;
01295 
01296     /// ...  Delete all IF statements where only one branch is taken.
01297 
01298     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
01299 
01300     for ( ; iter.valid(); ++iter)
01301     if (iter.current_valid()) {
01302         Statement &stmt = iter.current();
01303         
01304         if ((stmt.stmt_class() == IF_STMT
01305          || stmt.stmt_class() == ELSEIF_STMT
01306          || stmt.stmt_class() == ARITHMETIC_IF_STMT)
01307         && _get_workspace(stmt).num_visits() > 0
01308         && _get_workspace(stmt).const_cond) {
01309         
01310         if (_debug_level >= 5) {
01311             cout << "!    If statement: ";
01312             stmt.print_debug(cout, 0);
01313             cout << " is constant.  Attempting to remove it.\n";
01314         }
01315         
01316         Statement *target = _const_if_succ(stmt, use_candidates);
01317         p_assert(target,
01318              "IF statement does not have a constant conditional.");
01319 
01320         if (stmt.stmt_class() == ARITHMETIC_IF_STMT) {
01321             /// ...  Replace the arithmetic if with a goto to its single
01322             /// ...  successor.
01323 
01324             Statement *goto_target = new GotoStmt(stmts.new_tag(),
01325                               target);
01326             goto_target->work_stack().push(
01327             new PropConstWS(_get_workspace(stmt)));
01328             stmts.modify(stmt, goto_target);
01329         }
01330                 else if (stmt.stmt_class() == ELSEIF_STMT) {
01331                     /// ...  Currently, don't allow ELSEIF stmts to be deleted.
01332                 }
01333                 else if (stmt.stmt_class() == IF_STMT
01334                          && stmt.follow_ref()->stmt_class() == ELSEIF_STMT
01335                          && target == stmt.follow_ref()) {
01336                     
01337                     /// ...  Delete the IF part of an IF () THEN ... ELSEIF statement
01338                     /// ...  Currently, do nothing.
01339                 }
01340                 else {
01341             /// ...  Delete the IF statement only if none of the statements
01342             /// ...  in the not-taken branch is reachable.
01343 
01344             if ((target == stmt.next_ref()
01345              && _is_block_unreachable(stmts,
01346                           *stmt.follow_ref(),
01347                           *stmt.matching_endif_ref()->prev_ref()))
01348             || (target == stmt.follow_ref()
01349                 && _is_block_unreachable(stmts,
01350                              *stmt.next_ref(),
01351                              *stmt.follow_ref()->prev_ref())))
01352             stmts.del(stmt);
01353             else {
01354             /// ...  Make sure that the ELSE or ELSEIF part of IF
01355             /// ...  statement isn't deleted by marking it as reachable.
01356 
01357             if (target == stmt.next_ref()
01358                 && stmt.follow_ref()->stmt_class() != ENDIF_STMT)
01359 
01360                 _get_workspace(*stmt.follow_ref()).incr_num_visits();
01361             }
01362         }
01363                 
01364         deleted_a_stmt = True;
01365         }
01366     }
01367     
01368     /// ...  Delete all unreachable code.
01369 
01370     RefSet<Statement> unreachable_stmts;
01371 
01372     for (iter.reset(); iter.valid(); ++iter)
01373     if (iter.current().stmt_class() != FLOW_ENTRY_STMT
01374         && _get_workspace(iter.current()).num_visits() == 0)
01375         unreachable_stmts.ins(iter.current());
01376 
01377     deleted_a_stmt = deleted_a_stmt || unreachable_stmts.entries() > 0;
01378 
01379     /// ...  Check for the case of an ENDDO statement being unreachable.
01380     /// ...  In this case, if the associated DO is reachable, 
01381     /// ...  then DO will be deleted when the ENDDO is deleted, 
01382     /// ...  so we must place an assignment statement for the loop index, 
01383     /// ...  assigning the initial value of the index,
01384     /// ...  plus the loop-entry test.
01385     /// ...  If the associated DO is not reachable either, then don't
01386     /// ...  insert the assignment or the IF at all (and the
01387     /// ...  whole loop should vanish).
01388 
01389     for (Iterator<Statement> st_iter = unreachable_stmts;
01390      st_iter.valid();
01391      ++st_iter)
01392     {
01393         Statement & stmt = st_iter.current();
01394         if (stmt.stmt_class() == ENDDO_STMT) {
01395         Statement * dostmt = stmt.follow_ref();
01396         if (!unreachable_stmts.member(*dostmt)) {
01397             AssignmentStmt *assign = 
01398             new AssignmentStmt(stmts.new_tag(),
01399                        dostmt->index().clone(),
01400                        dostmt->init().clone());
01401             stmts.ins_before(assign, dostmt);
01402             /// ...             Statement &newif = 
01403             stmts.ins_IF_after (
01404                 ge(dostmt->limit().clone(),
01405                    dostmt->index().clone()),
01406                 assign,
01407                 &stmt);
01408         }
01409         }
01410     }
01411     
01412     stmts.del(unreachable_stmts);
01413 
01414     if (deleted_a_stmt) {
01415     stmts.create_flow_graph();
01416     /// ...  remove_trivial_gotos(pgm);
01417     }
01418 }
01419 
01420 
01421 /// propagate_constants1 -
01422 ///   Main routine of propagate_constants.
01423 ///   Perform forward substitution of scalar variables throughout given
01424 ///   statement block.
01425 
01426 static void
01427 _propagate_constants1(StmtList &stmts, 
01428               const Statement &first_stmt,
01429               const Statement &last_stmt,
01430               Map<Symbol,IntElem> &def_candidates,
01431               Map<Symbol,IntElem> &use_candidates,
01432               Array<Symbol *> &tag_to_candidate,
01433               RefSet<Statement> &pseudo_stmts,
01434               PC_UNREACH_BOOL remove_unreachable,
01435               int debug)
01436 {
01437     /// ...  Set of entry points into the given block of statements.
01438     RefSet<Statement> entry_points;
01439 
01440     /// ...  An array that maps integers to statements.
01441     Array<Statement *> toporder_to_stmt;
01442 
01443     _debug_level = debug;
01444     Timer tot_timer;
01445     Timer timer;
01446 
01447     /// ...  Initialize
01448 
01449     /// ...  clear_substituted_var();
01450     _pass_tag = create_pass_tag();
01451     _init_workspaces(stmts, first_stmt, last_stmt, def_candidates,
01452              use_candidates, tag_to_candidate);
01453     _make_nonlocals_modified_at_calls(stmts, first_stmt, last_stmt,
01454                       use_candidates, tag_to_candidate);
01455     _patch_flow_graph(stmts, first_stmt, last_stmt);
01456     _determine_entry_points(stmts, first_stmt, last_stmt, entry_points);
01457     _calc_toporder(stmts, first_stmt, last_stmt, entry_points,
01458            toporder_to_stmt);
01459 
01460     if (_debug_level > 0) {
01461     cout << "!  Initialization: " << timer << endl;
01462     timer.reset();
01463     }
01464 
01465     /// ...  Iteratively propagate the constants throughout the program until a
01466     /// ...  fixed point is reached.
01467 
01468     Map<Symbol,Expression> entering_constants;
01469     _iterate_to_fixed_point(stmts, first_stmt, last_stmt, entry_points,
01470                 toporder_to_stmt, use_candidates,
01471                 tag_to_candidate, entering_constants);
01472 
01473     if (_debug_level > 0) {
01474     cout << "!  Iterating to fixed point: " << timer << endl;
01475     timer.reset();
01476     }
01477 
01478     /// ...  Annotate all the expressions in the program with the calculated
01479     /// ...  constant values
01480 
01481     _annotate_stmts(stmts, first_stmt, last_stmt, use_candidates);
01482 
01483     if (_debug_level > 0)
01484     cout << "!  Annotating pgm with constants: " << timer << endl;
01485 
01486     if (_debug_level >= 10)
01487     _dump_workspaces(cout, stmts, first_stmt, last_stmt);
01488 
01489     /// ...  Remove any deadcode from the program, if desired.
01490 
01491     if (remove_unreachable == REMOVE_UNREACH_CODE) {
01492     stmts.del(pseudo_stmts);
01493     _remove_unreachable(stmts, first_stmt, last_stmt, use_candidates);
01494 
01495     if (_debug_level > 0) {
01496         cout << "!  Removing unreachable code: " << timer << endl;
01497         timer.reset();
01498     }
01499     }
01500 
01501     /// ...  Clean up
01502 
01503     Iterator<Statement> stmt_iter = stmts.iterator(first_stmt, last_stmt);
01504 
01505     for ( ; stmt_iter.valid(); ++stmt_iter)
01506     stmt_iter.current().work_stack().pop(_pass_tag);
01507 
01508     if (_debug_level > 0) {
01509     int num_stmts = _num_stmts_in_block(stmts, first_stmt, last_stmt);
01510 
01511     cout << "!  Total time: " << tot_timer << endl;
01512     cout << "!  Number of statements: " << num_stmts << endl;
01513     cout << "!  Number of candidate variables: " << use_candidates.entries() << endl;
01514     }
01515 }
01516 
01517 
01518 /// propagate_constants_all_vars
01519 ///   Perform constant propagation for all variables in the given statement
01520 ///   block.
01521 
01522 static void
01523 _propagate_constants_all_vars(StmtList &stmts, 
01524                   const Statement &first_stmt,
01525                   const Statement &last_stmt,
01526                   RefSet<Statement> &pseudo_stmts,
01527                   PC_REAL_BOOL subst_reals,
01528                   PC_ARRAY_BOOL subst_arrays,
01529                   PC_UNREACH_BOOL remove_unreachable,
01530                   int debug)
01531 {
01532     /// ...  Set of all variables that are candidates for forward substitution
01533     Map<Symbol,IntElem> def_candidates;
01534     
01535     /// ...  Set of all variables that may be in the constant symbolic values
01536     /// ...  for a variable in def_candidates.
01537     Map<Symbol,IntElem> use_candidates;
01538     
01539     /// ...  An array that maps integers to variable candidates.
01540     Array<Symbol *> tag_to_candidate;
01541     
01542     if (remove_unreachable == REMOVE_UNREACH_CODE)
01543     _add_control_assigns(stmts, first_stmt, last_stmt, 0, pseudo_stmts);
01544     
01545     _collect_candidates(stmts, first_stmt, last_stmt, def_candidates,
01546             use_candidates, tag_to_candidate, subst_reals,
01547             subst_arrays);
01548     _propagate_constants1(stmts, first_stmt, last_stmt, def_candidates,
01549               use_candidates, tag_to_candidate,
01550               pseudo_stmts, remove_unreachable, debug);
01551 }
01552 
01553 
01554 /// propagate_constants_all_vars
01555 ///   Perform constant propagation for only the variables in candidates for
01556 ///   the given statement block.
01557 
01558 static void
01559 _propagate_constants_some_vars(StmtList &stmts, 
01560                    const Statement &first_stmt,
01561                    const Statement &last_stmt,
01562                    const RefSet<Symbol> &candidates,
01563                    RefSet<Statement> &pseudo_stmts,
01564                    PC_UNREACH_BOOL remove_unreachable,
01565                    int debug)
01566 {
01567     /// ...  Set of all variables that are candidates for forward substitution
01568     Map<Symbol,IntElem> def_candidates;
01569     
01570     /// ...  Set of all variables that may be in the constant symbolic values
01571     /// ...  for a variable in def_candidates.
01572     Map<Symbol,IntElem> use_candidates;
01573     
01574     /// ...  An array that maps integers to variable candidates.
01575     Array<Symbol *> tag_to_candidate;
01576     
01577     if (remove_unreachable == REMOVE_UNREACH_CODE)
01578     _add_control_assigns(stmts, first_stmt, last_stmt,
01579                  &candidates, pseudo_stmts);
01580     
01581     _collect_candidates(candidates, stmts, first_stmt, last_stmt,
01582             def_candidates, use_candidates, tag_to_candidate);
01583     _propagate_constants1(stmts, first_stmt, last_stmt, def_candidates,
01584               use_candidates, tag_to_candidate, pseudo_stmts,
01585               remove_unreachable, debug);
01586 }
01587 
01588 
01589 /// propagate_constants -
01590 ///   Perform forward substitution of scalar variables throughout pgm.
01591 
01592 void
01593 propagate_constants(StmtList &stmts, 
01594             const Statement &first_stmt,
01595             const Statement &last_stmt,
01596             PC_REAL_BOOL subst_reals,
01597             PC_ARRAY_BOOL subst_arrays,
01598             PC_UNREACH_BOOL remove_unreachable,
01599             int debug GIV(0))
01600 {
01601     RefSet<Statement> pseudo_stmts;
01602     _propagate_constants_all_vars(stmts, first_stmt, last_stmt, pseudo_stmts,
01603                   subst_reals, subst_arrays,
01604                   remove_unreachable, debug);
01605 }
01606 
01607 void
01608 propagate_constants(ProgramUnit &pgm,
01609             PC_REAL_BOOL subst_reals,
01610             PC_ARRAY_BOOL subst_arrays,
01611             PC_UNREACH_BOOL remove_unreachable,
01612             int debug GIV(0))
01613 {
01614     if (pgm.stmts().entries() <= 0)
01615     return;
01616 
01617     StmtList &stmts = pgm.stmts();
01618     const Statement &first_stmt = *stmts.first_ref();
01619     const Statement &last_stmt = *stmts.last_ref();
01620     
01621     RefSet<Statement> pseudo_stmts;
01622     _add_data_assigns(pgm, 0, subst_reals, pseudo_stmts);
01623     
01624     _propagate_constants_all_vars(stmts, first_stmt, last_stmt, pseudo_stmts,
01625                   subst_reals, subst_arrays,
01626                   remove_unreachable, debug);
01627 
01628     if (remove_unreachable == REMOVE_UNREACH_CODE)
01629     remove_trivial_gotos(pgm);
01630 }
01631 
01632 void
01633 propagate_constants(StmtList &stmts, 
01634             const Statement &first_stmt,
01635             const Statement &last_stmt,
01636             const RefSet<Symbol> &candidates,
01637             PC_UNREACH_BOOL remove_unreachable,
01638             int debug GIV(0))
01639 {
01640     RefSet<Statement> pseudo_stmts;
01641     _propagate_constants_some_vars(stmts, first_stmt, last_stmt, candidates,
01642                    pseudo_stmts, remove_unreachable, debug);
01643 }
01644 
01645 void
01646 propagate_constants(ProgramUnit &pgm,
01647             const RefSet<Symbol> &candidates,
01648             PC_UNREACH_BOOL remove_unreachable,
01649             int debug GIV(0))
01650 {
01651     if (pgm.stmts().entries() <= 0)
01652     return;
01653 
01654     StmtList &stmts = pgm.stmts();
01655     const Statement &first_stmt = *stmts.first_ref();
01656     const Statement &last_stmt = *stmts.last_ref();
01657     
01658     RefSet<Statement> pseudo_stmts;
01659     _add_data_assigns(pgm, &candidates, SUBST_REALS, pseudo_stmts);
01660 
01661     _propagate_constants_some_vars(stmts, first_stmt, last_stmt, candidates,
01662                    pseudo_stmts, remove_unreachable, debug);
01663 
01664     if (remove_unreachable == REMOVE_UNREACH_CODE)
01665     remove_trivial_gotos(pgm);
01666 }
01667 
01668 
01669 /// propagate_constants_pu
01670 
01671 extern "C" int 
01672 propagate_constants_pu(char **data, int *len)
01673 {
01674     P_ASSERT_HANDLER(0);
01675     external_interface_init();
01676  
01677     ProgramUnit *pgm = external_program_unit( data, len );
01678     p_assert( pgm, "not a program unit" );
01679 
01680     propagate_constants(*pgm, 
01681             (PC_REAL_BOOL)    switch_value("pc_real"),
01682             (PC_ARRAY_BOOL)   switch_value("pc_array"),
01683             (PC_UNREACH_BOOL) switch_value("pc_unreach"));
01684  
01685     return setup_to_return_handle( pgm->pu_tag_ref(), data, len);
01686 }
01687 
01688 
01689 /// init_ipcp_workspaces
01690 ///   Initialize the workspaces for each statement in the program.
01691 ///   Note: A lot of the initialization for propagate_constants are hidden
01692 ///   in the constructor for PropConstWS.
01693 
01694 static void
01695 _init_ipcp_workspaces(StmtList &stmts,
01696               const IPCPProcData &proc_data,
01697               const Map<Symbol,IntElem> &def_candidates,
01698               const Map<Symbol,IntElem> &use_candidates,
01699               const Array<Symbol *> &tag_to_candidate)
01700 {
01701     Iterator<Statement> iter = stmts.iterator();
01702 
01703     for ( ; iter.valid(); ++iter) {
01704     const Statement &stmt = iter.current();
01705     PropConstWS *my_ws;
01706     const IPCPCallData *call_data = proc_data.call_data(stmt);
01707 
01708     if (call_data && call_data->data_ref()) {
01709         my_ws= new PropConstWS(_pass_tag, stmt, stmt,
01710                    *call_data->data_ref(), proc_data, True,
01711                    def_candidates, use_candidates,
01712                    tag_to_candidate);
01713         stmt.work_stack().push(my_ws);
01714         ++iter;
01715         const Statement &call_succ = iter.current();
01716         p_assert(call_succ.stmt_class() == LABEL_STMT,
01717              "Couldn't find dummy label statement after procedure call.");
01718         my_ws= new PropConstWS(_pass_tag, call_succ, stmt,
01719                    *call_data->data_ref(), proc_data, False,
01720                    def_candidates, use_candidates,
01721                    tag_to_candidate);
01722         call_succ.work_stack().push(my_ws);
01723     }
01724     else {
01725         my_ws= new PropConstWS(_pass_tag, stmt,
01726                    def_candidates, use_candidates,
01727                    tag_to_candidate);
01728         stmt.work_stack().push(my_ws);
01729     }
01730     }
01731 }
01732 
01733 
01734 /// _build_modified_vars.
01735 ///   Build and return the set of variables modified by the program,
01736 ///   ignoring the side-effect of the given statements.
01737 
01738 static RefSet<Symbol> *
01739 _build_modified_vars(const StmtList &stmts,
01740              const RefSet<Statement> &ignorable_stmts,
01741              const Array<Symbol *> &tag_to_candidate)
01742 {
01743     RefSet<Symbol> *modified_vars = new RefSet<Symbol>;
01744 
01745     Iterator<Statement> stmt_iter = stmts.iterator();
01746 
01747     for ( ; stmt_iter.valid(); ++stmt_iter) {
01748     Statement &stmt = stmt_iter.current();
01749     PropConstWS &ws = _get_workspace(stmt);
01750 
01751     if (! ignorable_stmts.member(stmt) && ws.num_visits() > 0) {
01752         for (int sym_tag = ws.mod_set.first();
01753          sym_tag != -1;
01754          sym_tag = ws.mod_set.next(sym_tag))
01755         modified_vars->ins(*tag_to_candidate[sym_tag]);
01756     }
01757     }
01758 
01759     return modified_vars;
01760 }
01761 
01762 
01763 /// alias_consts
01764 ///   Compute the set of actual parameters that are aliased to formal
01765 ///   parameters, where it is safe to replace the actual parameters with
01766 ///   the formal parameters.
01767 /// 
01768 
01769 static void
01770 _alias_consts(RefSet<Symbol> &alias_consts,
01771           RefMap<Symbol,Symbol> &alias_const_map,
01772           const RefList<Symbol> &formals,
01773           const List<Expression> &actuals,
01774           const RefSet<Symbol> &keepable_vars)
01775 {
01776     p_assert(formals.entries() == actuals.entries(),
01777          "JumpFunction::new_values():  The number of formals does not equal the number of actuals.");
01778     Iterator<Symbol> formal_iter = formals;
01779     Iterator<Expression> actual_iter = actuals;
01780 
01781     for ( ; formal_iter.valid(); ++formal_iter, ++actual_iter) {
01782     const Symbol &formal = formal_iter.current();
01783 
01784     if (actual_iter.current().op() == ID_OP) {
01785         Symbol &actual = actual_iter.current().symbol();
01786 
01787         if (! actual.is_array()
01788         && ! keepable_vars.member(actual)
01789         && ! alias_consts.member(actual)
01790         && actual.type() == formal.type()) {
01791 
01792         alias_consts.ins(actual);
01793         alias_const_map.ins(actual, formal);
01794         }
01795     }
01796     }
01797 }
01798 
01799 
01800 /// rename_alias_consts
01801 ///   Rename all variables in the given mapping to their mapped values.
01802 
01803 static void
01804 _rename_alias_consts(Expression &expr,
01805              const RefMap<Symbol,Symbol> &alias_const_map)
01806 {
01807     if (expr.op() == ID_OP) {
01808     const Symbol *val = alias_const_map.find_ref(expr.symbol());
01809 
01810     if (val)
01811         expr.symbol(*val);
01812     }
01813     else {
01814     Iterator<Expression> arg_iter = expr.arg_list();
01815 
01816     for ( ; arg_iter.valid(); ++arg_iter)
01817         _rename_alias_consts(arg_iter.current(), alias_const_map);
01818     }
01819 }
01820 
01821 
01822 /// _remove_local_effects_from_expr
01823 ///   Given an expression and a constant map, eliminate all locally modified
01824 ///   variables form the expression, so that the final expression would
01825 ///   be in terms of the initial values of the subroutine.
01826 
01827 static Expression *
01828 _remove_local_effects_from_expr1(Expression *expr,
01829                  const PropConstMap &const_map,
01830                  const Map<Symbol,IntElem> &candidates)
01831 {
01832     if (! expr)
01833     return expr;
01834       
01835     if (expr->op() == ID_OP) {
01836     const IntElem *tag_elem = candidates.find_ref(expr->symbol());
01837     p_assert(tag_elem || expr->symbol().sym_class() != VARIABLE_CLASS,
01838          "_remove_local_effects_from_expr1(): Expression contains a var not in candidates.");
01839 
01840     if (tag_elem) {
01841         int sym_tag = tag_elem->value();
01842         PropConstElem &curr_const = const_map[sym_tag];
01843         p_assert(curr_const.last_mod(),
01844              "_remove_local_effects_from_expr1(): Expression contains a var with an undefined constant value.");
01845         
01846         if (curr_const.last_mod()->stmt_class() != FLOW_ENTRY_STMT
01847         && curr_const.last_mod()->stmt_class() != ENTRY_STMT) {
01848         
01849         Expression *subst_expr = 0;
01850         
01851         if (curr_const.state() == CONST) {
01852             PropConstWS &subst_ws = _get_workspace(*curr_const.last_mod());
01853             
01854             if (! subst_ws.poisoned_vars[sym_tag]) {
01855             subst_ws.poisoned_vars.ins(sym_tag);
01856             subst_expr = curr_const.expr().clone();
01857             subst_expr
01858                 = _remove_local_effects_from_expr1(subst_expr,
01859                                    subst_ws.in_const_map,
01860                                    candidates);
01861             subst_ws.poisoned_vars.del(sym_tag);
01862             
01863             if (subst_expr && subst_expr->base_variable_ref())
01864                 subst_expr = paren(subst_expr);
01865             
01866             }
01867         }
01868         
01869         delete expr;
01870         expr = subst_expr;
01871         }
01872     }
01873     }
01874     else {
01875     Mutator<Expression> iter = expr->arg_list();
01876 
01877     for ( ; iter.valid(); ++iter) {
01878         Assign<Expression> eas(iter.assign());
01879         Expression *new_expr
01880         = _remove_local_effects_from_expr1(iter.pull(),
01881                            const_map,
01882                            candidates);
01883 
01884         if (! new_expr) {
01885         delete expr;
01886         return 0;
01887         }
01888         else
01889         eas = new_expr;
01890     }
01891     }
01892 
01893     return expr;
01894 }
01895 
01896 static Expression *
01897 _remove_local_effects_from_expr(Expression *expr,
01898                 const PropConstMap &const_map,
01899                 const Map<Symbol,IntElem> &candidates)
01900 {
01901     Expression *new_expr
01902     = _remove_local_effects_from_expr1(expr, const_map, candidates);
01903 
01904     if (! new_expr)
01905     new_expr = omega();
01906 
01907     return new_expr;
01908 }
01909 
01910 
01911 /// _create_old_const_mods
01912 ///   Create a mapping from old constants to new constants.
01913 
01914 static Map<Symbol, Expression> *
01915 _create_old_const_mods(const Map<Symbol,IntElem> &candidates,
01916                const PropConstMap &const_map,
01917                const RefSet<Symbol> &keepable_vars,
01918                const RefSet<Symbol> *modified_vars_ref)
01919 {
01920     Map<Symbol, Expression> *var_mods = new Map<Symbol, Expression>;
01921     KeyIterator<Symbol,IntElem> cand_iter = candidates;
01922 
01923     for ( ; cand_iter.valid(); ++cand_iter) {
01924     Symbol &var = cand_iter.current_key();
01925 
01926     if (keepable_vars.member(var)) {
01927         Expression *var_mod = _remove_local_effects_from_expr(id(var),
01928                                   const_map,
01929                                   candidates);
01930         
01931         if ((var_mod->op() == ID_OP && &var_mod->symbol() == &var)
01932         || (var_mod->op() == OMEGA_OP
01933             && modified_vars_ref
01934             && ! modified_vars_ref->member(var)))
01935         delete var_mod;
01936         else
01937         var_mods->ins(var, var_mod);
01938     }
01939     }
01940 
01941     return var_mods;
01942 }
01943 
01944 
01945 
01946 /// subst_unkeepable_vars
01947 ///   Substitute all unkeepable variables.
01948 
01949 static Expression *
01950 _subst_unkeepable_vars(Expression *expr, const RefSet<Symbol> &keepable_vars)
01951 {
01952     if (! expr)
01953     return expr;
01954     else if (expr->op() == ID_OP) {
01955     if (expr->symbol().sym_class() == VARIABLE_CLASS) {
01956         Expression *subst_expr = 0;
01957         
01958         if (expr->substituted_valid()) {
01959         subst_expr = _subst_unkeepable_vars(expr->grab_substituted(),
01960                             keepable_vars);
01961         
01962         if (subst_expr && subst_expr->base_variable_ref())
01963             subst_expr = paren(subst_expr);
01964         }
01965         
01966         if (subst_expr || ! keepable_vars.member(expr->symbol())) {
01967         delete expr;
01968         return subst_expr;
01969         }
01970     }
01971     }
01972     else {
01973     Mutator<Expression> iter = expr->arg_list();
01974 
01975     for ( ; iter.valid(); ++iter) {
01976         Assign<Expression> eas(iter.assign());
01977         Expression *new_arg = _subst_unkeepable_vars(iter.pull(),
01978                              keepable_vars);
01979 
01980         if (new_arg)
01981         eas = new_arg;
01982         else {
01983         delete expr;
01984         return 0;
01985         }
01986     }
01987     }
01988 
01989     return expr;
01990 }
01991 
01992 
01993 /// _create_new_consts
01994 ///   Create a set of newly generated symbolic constants.
01995 
01996 static Map<Symbol, Expression> *
01997 _create_new_consts(const Map<Symbol,IntElem> &candidates,
01998            const PropConstMap &const_map,
01999            const RefSet<Symbol> &keepable_vars)
02000 {
02001     Map<Symbol, Expression> *var_mods = new Map<Symbol, Expression>;
02002     KeyIterator<Symbol,IntElem> cand_iter = candidates;
02003 
02004     for ( ; cand_iter.valid(); ++cand_iter) {
02005     Symbol &var = cand_iter.current_key();
02006 
02007     if (keepable_vars.member(var)) {
02008         Expression *var_expr = _annotate_expr(id(var), const_map, candidates);
02009         Expression *new_const = var_expr->grab_substituted();
02010         delete var_expr;
02011         new_const = _subst_unkeepable_vars(new_const, keepable_vars);
02012         
02013         if (new_const)
02014         var_mods->ins(var, new_const);
02015     }
02016     }
02017 
02018     return var_mods;
02019 }
02020 
02021 
02022 ///  call_arg_list
02023 ///    Return a reference to the argument list of the given call site.
02024 
02025 static const List<Expression> &
02026 _call_arg_list(const Statement &call_site)
02027 {
02028     const List<Expression> *args = NULL;
02029 
02030     if (call_site.stmt_class() == CALL_STMT)
02031     args = &call_site.parameters_guarded().arg_list();
02032     else if (call_site.stmt_class() == ASSIGNMENT_STMT
02033          && call_site.rhs().op() == FUNCTION_CALL_OP)
02034     args = &call_site.rhs().parameters_guarded().arg_list();
02035     else
02036     p_abort("_call_arg_list(): Given statement is not a call statement or function call.");
02037 
02038     return *args;
02039 }
02040 
02041 
02042 ///  contains_non_candidate_vars
02043 ///    Return true if the expression contains a variable not in
02044 ///    cadidates.
02045 
02046 static Boolean
02047 _contains_non_candidate_vars(const Expression &expr,
02048                  const Map<Symbol, IntElem> &candidates)
02049 {
02050     if (expr.op() == ID_OP) {
02051     return (expr.symbol().sym_class() == VARIABLE_CLASS
02052         && ! candidates.member(expr.symbol()));
02053     }
02054     else {
02055     Iterator<Expression> arg_iter = expr.arg_list();
02056 
02057     for ( ; arg_iter.valid(); ++arg_iter)
02058         if (_contains_non_candidate_vars(arg_iter.current(), candidates))
02059         return True;
02060     }
02061 
02062     return False;
02063 }
02064 
02065 
02066 /// create_new_actual_consts
02067 ///   Build a set of new actual expressions.
02068 
02069 static List<Expression> *
02070 _create_new_actual_consts(const Map<Symbol, IntElem> &candidates,
02071               const Statement &stmt,
02072               const IPCPProcData & /* proc_data */,
02073               const IPCPProcData &call_proc_data,
02074               const RefSet<Symbol> &keepable_vars)
02075 {
02076     PropConstWS &ws = _get_workspace(stmt);
02077     const RefList<Symbol> &call_formals = call_proc_data.param_list();
02078     const List<Expression> &call_actuals = _call_arg_list(stmt);
02079 
02080     /// ...  Compute the set of variable that are allowable in the actual
02081     /// ...  expressions.
02082 
02083     RefSet<Symbol> alias_consts;
02084     RefMap<Symbol, Symbol> alias_const_map;
02085     _alias_consts(alias_consts, alias_const_map,
02086           call_formals, call_actuals, keepable_vars);
02087     RefSet<Symbol> *my_keepable_vars = new RefSet<Symbol>(keepable_vars);
02088     
02089     Iterator<Symbol> aconst_iter = alias_consts;
02090     
02091     for ( ; aconst_iter.valid(); ++aconst_iter)
02092     my_keepable_vars->ins(aconst_iter.current());
02093 
02094     /// ...  Compute the list of constant actuals.
02095 
02096     List<Expression> *actuals = new List<Expression>;
02097 
02098     p_assert(call_formals.entries() == call_actuals.entries(),
02099          "JumpFunction::new_values():  The number of formals does not equal the number of actuals.");
02100     Iterator<Symbol> formal_iter = call_formals;
02101     Iterator<Expression> actual_iter = call_actuals;
02102     
02103     for ( ; formal_iter.valid(); ++formal_iter, ++actual_iter) {
02104     const Symbol &formal = formal_iter.current();
02105     Expression *actual_expr = actual_iter.current().clone();
02106 
02107     if (_contains_non_candidate_vars(*actual_expr, candidates)) {
02108         delete actual_expr;
02109         actual_expr = omega();
02110     }
02111     else {
02112         actual_expr = _annotate_expr(actual_expr, ws.in_const_map,
02113                      candidates);
02114         actual_expr = _subst_unkeepable_vars(actual_expr, *my_keepable_vars);
02115         
02116         if (actual_expr) {
02117         _rename_alias_consts(*actual_expr, alias_const_map);
02118         
02119         if (actual_expr->base_variable_ref() == &formal) {
02120             delete actual_expr;
02121             actual_expr = omega();
02122         }
02123         }
02124         else
02125         actual_expr = omega();
02126     }
02127     
02128     actuals->ins_last(actual_expr);
02129     }
02130 
02131     delete my_keepable_vars;
02132     return actuals;
02133 }
02134 
02135 
02136 /// build_call_jump_function
02137 ///   Build a jump function for each call site.
02138 
02139 static void
02140 _build_call_jump_functions(ProgramUnit &pgm, IPCPProcData &proc_data,
02141                const Map<Symbol, IntElem> &candidates,
02142                const RefSet<Symbol> *modified_vars_ref)
02143 {
02144     RefSet<Symbol> keepable_params;
02145 
02146     Iterator<Expression> param_iter = proc_data.entry().parameters_guarded().arg_list();
02147 
02148     for ( ; param_iter.valid(); ++param_iter)
02149     keepable_params.ins(param_iter.current().symbol());
02150 
02151     Iterator<Statement> stmt_iter = pgm.stmts().iterator();
02152 
02153     for ( ; stmt_iter.valid(); ++stmt_iter) {
02154     const Statement &stmt = stmt_iter.current();
02155 
02156     if (stmt.stmt_class() == CALL_STMT
02157         || (stmt.stmt_class() == ASSIGNMENT_STMT
02158         && stmt.rhs().op() == FUNCTION_CALL_OP)) {
02159         PropConstWS &ws = _get_workspace(stmt);
02160 
02161         if (ws.num_visits() > 0) {
02162         const IPCPCallData *c_data = proc_data.call_data(stmt);
02163 
02164         if (c_data && c_data->data_ref()) {
02165             const IPCPProcData &call_proc_data = *c_data->data_ref();
02166             RefSet<Symbol> *keepable_vars
02167             = proc_data.local_vars(call_proc_data.usable_global_vars());    
02168             *keepable_vars += keepable_params;
02169             proc_data.create_jump_function(
02170             stmt,
02171             _create_old_const_mods(candidates, ws.in_const_map,
02172                            *keepable_vars,
02173                            modified_vars_ref),
02174             _create_new_consts(candidates, ws.in_const_map,
02175                        *keepable_vars),
02176             _create_new_actual_consts(candidates, stmt, proc_data,
02177                           call_proc_data,
02178                           *keepable_vars));
02179             delete keepable_vars;
02180         }
02181         }
02182     }
02183     }
02184 }
02185 
02186 
02187 /// ipcp_compute_constants
02188 ///   Compute the constants for single procedure for interprocedural
02189 ///   constant propagation.
02190 
02191 static void
02192 _ipcp_compute_constants(ProgramUnit &pgm, IPCPProcData &proc_data,
02193             const Map<Symbol,IntElem> &def_candidates,
02194             const Map<Symbol,IntElem> &use_candidates,
02195             Array<Symbol *> &tag_to_candidate,
02196             const Map<Symbol, Expression> &entering_constants)
02197 {
02198     /// ...  Set of entry points into the given block of statements.
02199     RefSet<Statement> entry_points;
02200 
02201     /// ...  An array that maps integers to statements.
02202     Array<Statement *> toporder_to_stmt;
02203 
02204     StmtList &stmts = pgm.stmts();
02205     const Statement &first_stmt = *stmts.first_ref();
02206     const Statement &last_stmt = *stmts.last_ref();
02207     Timer timer;
02208 
02209     _pass_tag = create_pass_tag();
02210     _init_ipcp_workspaces(stmts, proc_data, def_candidates, use_candidates,
02211               tag_to_candidate);
02212     _make_nonlocals_modified_at_calls(stmts, first_stmt, last_stmt,
02213                       use_candidates, tag_to_candidate);
02214     _patch_flow_graph(stmts, first_stmt, last_stmt);
02215     _determine_entry_points(stmts, first_stmt, last_stmt, entry_points);
02216     _calc_toporder(stmts, first_stmt, last_stmt, entry_points,
02217            toporder_to_stmt);
02218 
02219     if (_debug_level > 0) {
02220     cout << "!  Initialization: " << timer << endl;
02221     timer.reset();
02222     }
02223 
02224     /// ...  Iteratively propagate the constants throughout the program until a
02225     /// ...  fixed point is reached.
02226 
02227     _iterate_to_fixed_point(stmts, first_stmt, last_stmt, entry_points,
02228                 toporder_to_stmt, use_candidates,
02229                 tag_to_candidate, entering_constants);
02230 
02231     if (_debug_level > 0) {
02232     cout << "!  Iterating to fixed point: " << timer << endl;
02233     timer.reset();
02234     }
02235 
02236     if (_debug_level >= 10)
02237     _dump_workspaces(cout, stmts, first_stmt, last_stmt);
02238 }
02239 
02240 
02241 /// ipcp_build_jump_functions
02242 ///   Build the jump functions for the given proc_data object.
02243 
02244 void
02245 _ipcp_build_jump_functions(ProgramUnit &pgm, IPCPProcData &proc_data,
02246                const RefSet<Symbol> &def_vars,
02247                const RefSet<Symbol> &use_vars,
02248                const Map<Symbol, Expression> &entering_constants,
02249                int debug GIV(0))
02250 {
02251     /// ...  Set of all variables that are candidates for forward substitution
02252     Map<Symbol,IntElem> def_candidates;
02253     
02254     /// ...  Set of all variables that may be in the constant symbolic values
02255     /// ...  for a variable in def_candidates.
02256     Map<Symbol,IntElem> use_candidates;
02257     
02258     /// ...  An array that maps integers to variable candidates.
02259     Array<Symbol *> tag_to_candidate;
02260     
02261     /// ...  Set of pseudo statements inserted to represent constants from control
02262     /// ...  flow.
02263     RefSet<Statement> pseudo_stmts;
02264 
02265     StmtList &stmts = pgm.stmts();
02266     const Statement &first_stmt = *stmts.first_ref();
02267     const Statement &last_stmt = *stmts.last_ref();
02268     
02269     _debug_level = debug;
02270     Timer tot_timer;
02271     Timer timer;
02272 
02273     /// ...  Initialize
02274 
02275     _add_control_assigns(pgm.stmts(), first_stmt, last_stmt, 0, pseudo_stmts);
02276     _init_candidates(def_vars, use_vars, def_candidates, use_candidates,
02277              tag_to_candidate);
02278 
02279     /// ...  Compute my constants.
02280 
02281     _ipcp_compute_constants(pgm, proc_data, def_candidates, use_candidates,
02282                 tag_to_candidate, entering_constants);
02283  
02284     /// ...  If some pseudo-statements were added to the program, compute the
02285     /// ...  set of variables modified by the program, ignoring pseudo-statements
02286     /// ...  and unreachable statements.
02287 
02288     RefSet<Symbol> *modified_vars = 0;
02289 
02290     if (pseudo_stmts.entries() > 0)
02291     modified_vars = _build_modified_vars(pgm.stmts(), pseudo_stmts,
02292                          tag_to_candidate);
02293 
02294     /// ...  Build the jump functions.
02295 
02296     _build_call_jump_functions(pgm, proc_data, use_candidates,
02297                    modified_vars);
02298 
02299     p_assert(last_stmt.stmt_class() == FLOW_EXIT_STMT,
02300          "Last statement of program is not a flow-exit statement.");
02301     PropConstWS &flow_exit_ws = _get_workspace(last_stmt);
02302     RefSet<Symbol> *keepable_vars = proc_data.local_vars(proc_data.usable_global_vars());
02303     proc_data.create_return_jump_function(
02304     _create_old_const_mods(use_candidates, flow_exit_ws.in_const_map,
02305                    *keepable_vars, modified_vars),
02306     _create_new_consts(use_candidates, flow_exit_ws.in_const_map,
02307                *keepable_vars));
02308     delete keepable_vars;
02309     
02310     if (modified_vars)
02311     delete modified_vars;
02312 
02313     if (_debug_level > 0) {
02314     cout << "!  Building jump functions: " << timer << endl;
02315     timer.reset();
02316     }
02317 
02318     /// ...  Clean up
02319 
02320     pgm.stmts().del(pseudo_stmts);
02321 
02322     if (_debug_level > 0) {
02323     cout << "!  Removing pseudo-statements: " << timer << endl;
02324     timer.reset();
02325     }
02326 
02327     Iterator<Statement> stmt_iter = stmts.iterator(first_stmt, last_stmt);
02328 
02329     for ( ; stmt_iter.valid(); ++stmt_iter)
02330     stmt_iter.current().work_stack().pop(_pass_tag);
02331 
02332     if (_debug_level > 0) {
02333     int num_stmts = _num_stmts_in_block(stmts, first_stmt, last_stmt);
02334 
02335     cout << "!  Total time: " << tot_timer << endl;
02336     cout << "!  Number of statements: " << num_stmts << endl;
02337     cout << "!  Number of candidate variables: " << use_candidates.entries() << endl;
02338     }
02339 }
02340 
02341 
02342 /// ipcp_propagate_constants
02343 ///   Propagate constants within a single procedure for interprocedural
02344 ///   constant propagation.
02345 
02346 void
02347 _ipcp_propagate_constants(ProgramUnit &pgm, IPCPProcData &proc_data,
02348               const RefSet<Symbol> &def_vars,
02349               const RefSet<Symbol> &use_vars,
02350               PC_UNREACH_BOOL remove_unreachable,
02351               const Map<Symbol, Expression> &entering_constants,
02352               int debug GIV(0))
02353 {
02354     /// ...  Set of all variables that are candidates for forward substitution
02355     Map<Symbol,IntElem> def_candidates;
02356     
02357     /// ...  Set of all variables that may be in the constant symbolic values
02358     /// ...  for a variable in def_candidates.
02359     Map<Symbol,IntElem> use_candidates;
02360     
02361     /// ...  An array that maps integers to variable candidates.
02362     Array<Symbol *> tag_to_candidate;
02363 
02364     /// ...  Set of pseudo statements inserted to represent constants from control
02365     /// ...  flow.
02366     RefSet<Statement> pseudo_stmts;
02367 
02368     StmtList &stmts = pgm.stmts();
02369     const Statement &first_stmt = *stmts.first_ref();
02370     const Statement &last_stmt = *stmts.last_ref();
02371     
02372     _debug_level = debug;
02373     Timer tot_timer;
02374     Timer timer;
02375 
02376     /// ...  Initialize
02377 
02378     _add_control_assigns(pgm.stmts(), first_stmt, last_stmt, 0, pseudo_stmts);
02379     _init_candidates(def_vars, use_vars, def_candidates, use_candidates,
02380              tag_to_candidate);
02381 
02382     /// ...  Compute my constants.
02383 
02384     _ipcp_compute_constants(pgm, proc_data, def_candidates, use_candidates,
02385                 tag_to_candidate, entering_constants);
02386 
02387     /// ...  Annotate all the expressions in the program with the calculated
02388     /// ...  constant values
02389 
02390     _annotate_stmts(stmts, first_stmt, last_stmt, use_candidates);
02391 
02392     if (_debug_level > 0)
02393     cout << "!  Annotating pgm with constants: " << timer << endl;
02394 
02395     /// ...  Remove any deadcode from the program, if desired.
02396 
02397     pgm.stmts().del(pseudo_stmts);
02398 
02399     if (remove_unreachable == REMOVE_UNREACH_CODE)
02400     _remove_unreachable(stmts, first_stmt, last_stmt, use_candidates);
02401 
02402     if (_debug_level > 0) {
02403     cout << "!  Removing unreachable code: " << timer << endl;
02404     timer.reset();
02405     }
02406 
02407     /// ...  Clean up
02408 
02409     Iterator<Statement> stmt_iter = stmts.iterator(first_stmt, last_stmt);
02410 
02411     for ( ; stmt_iter.valid(); ++stmt_iter)
02412     stmt_iter.current().work_stack().pop(_pass_tag);
02413 
02414     if (_debug_level > 0) {
02415     int num_stmts = _num_stmts_in_block(stmts, first_stmt, last_stmt);
02416 
02417     cout << "!  Total time: " << tot_timer << endl;
02418     cout << "!  Number of statements: " << num_stmts << endl;
02419     cout << "!  Number of candidate variables: " << use_candidates.entries() << endl;
02420     }
02421 }
02422 
02423 
02424 /// _assert_clear_substituted
02425 ///   Remove all constant subexpression annotations from all expressions in
02426 ///   all assertions of the given statement.
02427 
02428 static void
02429 _assert_clear_substituted(Statement &stmt)
02430 {
02431     Iterator<Assertion> ass_iter = stmt.assertions();
02432 
02433     for ( ; ass_iter.valid(); ++ass_iter) {
02434         if (ass_iter.current().arg_list_valid()) {
02435             Mutator<Expression> aexpr_iter
02436         = ass_iter.current().arg_list_guarded(); 
02437 
02438             for ( ; aexpr_iter.valid(); ++aexpr_iter)
02439         clear_substituted(aexpr_iter.current());
02440         }
02441     }
02442 }
02443 
02444 
02445 /// clear_substituted
02446 ///   Remove all constant subexpression annotations from all expressions in
02447 ///   the given object.  This object may be a ProgramUnit, a Statement or an
02448 ///   Expression.  Ain't polymorphism grand.
02449 
02450 void
02451 clear_substituted(ProgramUnit &pgm)
02452 {
02453     if (pgm.stmts().entries())
02454     clear_substituted(pgm.stmts(), *pgm.stmts().first_ref(),
02455               *pgm.stmts().last_ref());
02456 }
02457 
02458 void
02459 clear_substituted(StmtList &stmts, const Statement &first_stmt,
02460           const Statement &last_stmt)
02461 {
02462     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
02463 
02464     for ( ; iter.valid(); ++iter)
02465     clear_substituted(iter.current());
02466 }
02467 
02468 void
02469 clear_substituted(Statement &stmt)
02470 {
02471     Iterator<Expression> iter = stmt.iterate_expressions();
02472 
02473     for ( ; iter.valid(); ++iter)
02474     clear_substituted(iter.current());
02475 
02476     _assert_clear_substituted(stmt);
02477 }
02478 
02479 void
02480 clear_substituted(Expression &expr)
02481 {
02482     if (expr.op() == ID_OP)
02483     expr.substituted(0);
02484     else {
02485     Iterator<Expression> iter = expr.arg_list();
02486 
02487     for ( ; iter.valid(); ++iter)
02488         clear_substituted(iter.current());
02489 
02490     }
02491 }
02492 
02493 extern "C" int 
02494 clear_substituted_pu(char **data, int *len)
02495 {
02496     P_ASSERT_HANDLER(0);
02497     external_interface_init();
02498  
02499     ProgramUnit *pgm = external_program_unit( data, len );
02500     p_assert( pgm, "not a program unit" );
02501 
02502     clear_substituted(*pgm);
02503 
02504     return setup_to_return_handle( pgm->pu_tag_ref(), data, len);
02505 }
02506 
02507 
02508 /// substituted_var
02509 ///   Return True if expand_substituted substituted at least one variable.
02510 
02511 Boolean
02512 substituted_var()
02513 {
02514     return _substituted_var;
02515 }
02516 
02517 
02518 /// clear_substituted_var
02519 ///   Set the substituted_var flag to false (0).
02520 
02521 void
02522 clear_substituted_var()
02523 {
02524     _substituted_var = False;
02525 }
02526 
02527 
02528 /// _assert_expand_substituted
02529 ///   Replace some variables with their precomputed constant expressions for
02530 ///   all expressions in all assertions of the given statement.
02531 
02532 ///  Do this for all assertions except INDUCTION, FIRSTVALUE, RANGEWRITTEN  assertions
02533 
02534 static void
02535 _assert_expand_substituted(Statement &stmt,
02536                Boolean (* expr_filter)(const Expression &),
02537                Boolean (* const_filter)(const Expression &))
02538 {
02539     Iterator<Assertion> ass_iter = stmt.assertions();
02540 
02541     for ( ; ass_iter.valid(); ++ass_iter) {
02542 
02543     /// ...  Don't expand in INDUCTION assertions
02544 
02545     if ((ass_iter.current().type() == AS_INDUCTION) || 
02546         (ass_iter.current().type() == AS_FIRSTVALUE) || 
02547         (ass_iter.current().type() == AS_RANGEWRITTEN)) continue;
02548     
02549         if (ass_iter.current().arg_list_valid()) {
02550             Mutator<Expression> aexpr_iter
02551         = ass_iter.current().arg_list_guarded(); 
02552 
02553             for ( ; aexpr_iter.valid(); ++aexpr_iter) {
02554         Assign<Expression> eas(aexpr_iter.assign());
02555         eas = expr_expand_substituted(aexpr_iter.pull(),
02556                           expr_filter, const_filter);
02557         }
02558         }
02559     }
02560 }
02561 
02562 
02563 /// call_args_expand_substituted
02564 ///   Expand all constants in the given list of expressions, except for
02565 ///   those constants at the top level.  This function is used to
02566 ///   make sure that potentially aliased subroutine or function arguments
02567 ///   are not removed by constant propagation.
02568 
02569 static void
02570 _call_args_expand_substituted(Expression &comma_expr,
02571                   Boolean (* expr_filter)(const Expression &),
02572                   Boolean (* const_filter)(const Expression &))
02573 {
02574     p_assert(comma_expr.op() == COMMA_OP,
02575          "Parameters to subroutine or function call is not a comma expression.");
02576     Mutator<Expression> arg_iter = comma_expr.arg_list();
02577 
02578     for ( ; arg_iter.valid(); ++arg_iter)
02579     if (arg_iter.current().op() == ID_OP)
02580         arg_iter.current().substituted(0);
02581     else {
02582         Assign<Expression> eas(arg_iter.assign());
02583         eas = expr_expand_substituted(arg_iter.pull(),
02584                       expr_filter,
02585                       const_filter);
02586     }
02587 }
02588 
02589 
02590 /// expand_substituted
02591 ///   Replace some variables with their precomputed constant expressions for
02592 ///   all expressions in the given object.  This method requires two filter
02593 ///   functions to determine whether a certain variable is to be substituted.
02594 ///   The first filter function tests a subexpression of the current expression
02595 ///   whose variables are being substituted.  If it returns false, none of the
02596 ///   variables inside this subexpression will substituted.  The second function
02597 ///   tests the constant expression associated with a variable to be
02598 ///   substituted.  If this function returns false, the variable is not
02599 ///   substituted with that expression.
02600 
02601 void
02602 expand_substituted(ProgramUnit &pgm,
02603            Boolean (* expr_filter)(const Expression &) GIV(0),
02604            Boolean (* const_filter)(const Expression &) GIV(0))
02605 {
02606     if (pgm.stmts().entries())
02607     expand_substituted(pgm.stmts(), *pgm.stmts().first_ref(),
02608                *pgm.stmts().last_ref(), expr_filter, const_filter);
02609 }
02610 
02611 void
02612 expand_substituted(StmtList &stmts, const Statement &first_stmt,
02613            const Statement &last_stmt,
02614            Boolean (* expr_filter)(const Expression &) GIV(0),
02615            Boolean (* const_filter)(const Expression &) GIV(0))
02616 {
02617     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
02618 
02619     for ( ; iter.valid(); ++iter)
02620     expand_substituted(iter.current(), expr_filter, const_filter);
02621 }
02622 
02623 void
02624 expand_substituted(Statement &stmt,
02625            Boolean (* expr_filter)(const Expression &) GIV(0),
02626            Boolean (* const_filter)(const Expression &) GIV(0))
02627 {
02628     _assert_expand_substituted(stmt, expr_filter, const_filter);
02629 
02630     _stmt_substituted_var = False;
02631 
02632     if (stmt.stmt_class() == CALL_STMT) {
02633     if (stmt.parameters_valid())
02634         _call_args_expand_substituted(stmt.parameters_guarded(),
02635                       expr_filter, const_filter);
02636     }
02637     else {
02638     Mutator<Expression> iter = stmt.iterate_expressions();
02639     
02640     for ( ; iter.valid(); ++iter) {
02641         Assign<Expression> eas(iter.assign());
02642         eas = simplify(expr_expand_substituted(iter.pull(), expr_filter,
02643                       const_filter));
02644            
02645     }
02646     }
02647 
02648     if (_stmt_substituted_var)
02649     stmt.build_refs();
02650 
02651     stmt.simplify_expressions();
02652 }
02653 
02654 extern "C" int 
02655 expand_substituted_pu(char **data, int *len)
02656 {
02657     P_ASSERT_HANDLER(0);
02658     external_interface_init();
02659  
02660     ProgramUnit *pgm = external_program_unit( data, len );
02661     p_assert( pgm, "not a program unit" );
02662 
02663     expand_substituted(*pgm);
02664 
02665     return setup_to_return_handle( pgm->pu_tag_ref(), data, len);
02666 }
02667 
02668 
02669 /// is_constant_expr
02670 ///   Return True if the given expression would simplify down to an integer
02671 ///   constant or logical constant.
02672 
02673 static Boolean
02674 _is_constant_expr(const Expression &expr)
02675 {
02676     if (expr.arg_list().entries() == 0) 
02677     return (expr.op() == INTEGER_CONSTANT_OP
02678         || expr.op() == LOGICAL_CONSTANT_OP);
02679     else if (expr.op() == INTRINSIC_CALL_OP)
02680     return _is_constant_expr(expr.parameters_guarded());
02681     else {
02682     Iterator<Expression> iter = expr.arg_list();
02683 
02684     for ( ; iter.valid(); ++iter)
02685         if (! _is_constant_expr(iter.current()))
02686         return False;
02687     }
02688 
02689     return True;
02690 }
02691 
02692 
02693 /// expr_expand_substituted
02694 ///   Acts similarly to the method expand_substituted() except that it applies
02695 ///   to only a single expression.  This method modifies the given expression
02696 ///   and returns the result.
02697 
02698 Expression *
02699 expr_expand_substituted(Expression *expr,
02700             Boolean (* expr_filter)(const Expression &) GIV(0),
02701             Boolean (* const_filter)(const Expression &) GIV(0))
02702 {
02703     if (! expr)
02704     return expr;
02705 
02706     Expression *result = expr;
02707 
02708     if (! expr_filter || expr_filter(*expr)) {
02709     if (expr->op() == ID_OP) {
02710 
02711         if (expr->substituted_valid()) {
02712         expr->substituted(expr_expand_substituted(expr->grab_substituted(),
02713                               expr_filter,
02714                               const_filter));
02715 
02716         if (_is_constant_expr(expr->substituted_guarded()))
02717             expr->substituted(simplify(expr->grab_substituted()));
02718                   
02719         if (! const_filter
02720             || const_filter(expr->substituted_guarded())) {
02721         
02722             result = expr->grab_substituted();
02723             delete expr;
02724             _substituted_var = True;
02725             _stmt_substituted_var = True;
02726         }       
02727         }
02728     }
02729     else if (expr->op() == FUNCTION_CALL_OP) {
02730         if (expr->parameters_valid())
02731         _call_args_expand_substituted(expr->parameters_guarded(),
02732                           expr_filter, const_filter);
02733     }
02734     else {
02735         Mutator<Expression> iter = expr->arg_list();
02736 
02737         for ( ; iter.valid(); ++iter) {
02738         Assign<Expression> eas(iter.assign());
02739         eas = expr_expand_substituted(iter.pull(),
02740                           expr_filter,
02741                           const_filter);
02742         }
02743     }
02744     }
02745 
02746     return result;
02747 }
02748 
02749 
02750 /// expand_linear_substituted
02751 ///   Expand the variables whose constant expressions are linear for all
02752 ///   expressions in the object.  An expression is considered linear if it
02753 ///   is made up of only additive and multiplicative operators.
02754 
02755 static inline Boolean
02756 _is_expr_top_linear(const Expression &expr)
02757 {
02758     switch(expr.op()) {
02759 
02760     case INTEGER_CONSTANT_OP:   /// ...  Let the leaf expressions be linear
02761     case REAL_CONSTANT_OP:
02762     case HOLLERITH_CONSTANT_OP:
02763     case LOGICAL_CONSTANT_OP:
02764     case COMPLEX_OP:
02765     case ARRAY_REF_OP:
02766     case ID_OP:
02767     case OMEGA_OP:
02768 
02769     case NOT_OP:        /// ...  Let the logical operations be linear
02770     case EQ_OP:
02771     case NE_OP:
02772     case LT_OP:
02773     case LE_OP:
02774     case GT_OP:
02775     case GE_OP:
02776     case OR_OP:
02777     case AND_OP:
02778     case EQV_OP:
02779     case NEQV_OP:
02780 
02781     case U_PLUS_OP:
02782     case U_MINUS_OP:
02783     case PAREN_OP:
02784     case SUB_OP:
02785     case ADD_OP:
02786     case MULT_OP:
02787     case COMMA_OP:
02788     return True;
02789     default:
02790       return False;
02791     }
02792 
02793     return False;
02794 }
02795 
02796 static Boolean
02797 _linear_const_filter(const Expression &expr)
02798 {
02799     if (! _is_expr_top_linear(expr))
02800     return False;
02801     else {
02802     Iterator<Expression> iter = expr.arg_list();
02803 
02804     for ( ; iter.valid(); ++iter)
02805         if (! _linear_const_filter(iter.current()))
02806         return False;
02807     }
02808 
02809     return True;
02810 }
02811 
02812 void
02813 expand_linear_substituted(ProgramUnit &pgm)
02814 {
02815     expand_substituted(pgm, &_is_expr_top_linear, &_linear_const_filter);
02816 }
02817 
02818 void
02819 expand_linear_substituted(StmtList &stmts, const Statement &first_stmt,
02820               const Statement &last_stmt)
02821 {
02822     expand_substituted(stmts, first_stmt, last_stmt,
02823                &_is_expr_top_linear, &_linear_const_filter);
02824 }
02825 
02826 void
02827 expand_linear_substituted(Statement &stmt)
02828 {
02829     expand_substituted(stmt, &_is_expr_top_linear, &_linear_const_filter);
02830 }
02831 
02832 Expression *
02833 expr_expand_linear_substituted(Expression *expr)
02834 {
02835     return expr_expand_substituted(expr, &_is_expr_top_linear,
02836                    &_linear_const_filter);
02837 }
02838 
02839 
02840 /// expand_small_substituted
02841 ///   Expand the variables whose constant expressions are ID expressions
02842 ///   or integer or  logical constant expressions.
02843 
02844 static Boolean
02845 _is_constant_expr_filter(const Expression &expr)
02846 {
02847     if (expr.op() == ID_OP)
02848     return (expr.substituted_valid() 
02849         && _is_constant_expr_filter(expr.substituted_guarded()));
02850     else if (expr.arg_list().entries() == 0) 
02851     return (expr.op() == INTEGER_CONSTANT_OP
02852         || expr.op() == LOGICAL_CONSTANT_OP);
02853     else if (expr.op() == INTRINSIC_CALL_OP)
02854     return _is_constant_expr_filter(expr.parameters_guarded());
02855     else {
02856     Iterator<Expression> iter = expr.arg_list();
02857 
02858     for ( ; iter.valid(); ++iter)
02859         if (! _is_constant_expr_filter(iter.current()))
02860         return False;
02861     }
02862 
02863     return True;
02864 }
02865 
02866 static Boolean
02867 _small_const_filter(const Expression &expr)
02868 {
02869     return (expr.op() == ID_OP || _is_constant_expr_filter(expr));
02870 }
02871 
02872 void
02873 expand_small_substituted(ProgramUnit &pgm)
02874 {
02875     expand_substituted(pgm, 0, &_small_const_filter);
02876 }
02877 
02878 void
02879 expand_small_substituted(StmtList &stmts, const Statement &first_stmt,
02880              const Statement &last_stmt)
02881 {
02882     expand_substituted(stmts, first_stmt, last_stmt, 0, &_small_const_filter);
02883 }
02884 
02885 void
02886 expand_small_substituted(Statement &stmt)
02887 {
02888     expand_substituted(stmt, 0, &_small_const_filter);
02889 }
02890 
02891 Expression *
02892 expr_expand_small_substituted(Expression *expr)
02893 {
02894     return expr_expand_substituted(expr, 0, &_small_const_filter);
02895 }
02896 
02897 
02898 /// has_param_in_expr
02899 ///   Return true if the given expression has a parameter variable
02900 ///   contained within it.
02901 
02902 static Boolean
02903 _has_param_in_expr(const Expression &expr)
02904 {
02905     if (expr.op() == ID_OP) {
02906     return (expr.symbol().sym_class() == SYMBOLIC_CONSTANT_CLASS);
02907     }
02908     else {
02909     Iterator<Expression> iter = expr.arg_list();
02910 
02911     for ( ; iter.valid(); ++iter)
02912         if (_has_param_in_expr(iter.current()))
02913         return True;
02914     }
02915 
02916     return False;
02917 }
02918 
02919 
02920 /// _assert_substitute_parameters
02921 ///   Substitute all precomputed values for PARAMETER constants in all
02922 ///   assertions of the given statement.
02923 
02924 static void
02925 _assert_substitute_parameters(Statement &stmt, PC_REAL_BOOL subst_reals)
02926 {
02927     Iterator<Assertion> ass_iter = stmt.assertions();
02928 
02929     for ( ; ass_iter.valid(); ++ass_iter) {
02930         if (ass_iter.current().arg_list_valid()) {
02931             Mutator<Expression> aexpr_iter
02932         = ass_iter.current().arg_list_guarded(); 
02933 
02934             for ( ; aexpr_iter.valid(); ++aexpr_iter) {
02935         Assign<Expression> eas(aexpr_iter.assign());
02936         eas = expr_substitute_parameters(aexpr_iter.pull(),
02937                          subst_reals);
02938         }
02939         }
02940     }
02941 }
02942 
02943 static void substitute_parameters_data(ProgramUnit &pgm, 
02944                        PC_REAL_BOOL subst_reals){
02945   for(Iterator<Data> dit=pgm.data(); dit.valid(); ++dit){
02946     Expression* values=dit.current().value_list().clone();
02947     values=expr_substitute_parameters(values, subst_reals);
02948     dit.current().value_list((CommaExpr*)values);
02949   }
02950 }
02951 
02952 
02953 /// substitute_parameters
02954 ///   Substitute all precomputed values for PARAMETER constants.
02955 
02956 void
02957 substitute_parameters(ProgramUnit &pgm, PC_REAL_BOOL subst_reals)
02958 {
02959     substitute_parameters(pgm.symtab(), subst_reals);
02960 
02961     /// ...  silvius: must substitute them in DATA expressions.
02962     substitute_parameters_data(pgm, subst_reals);
02963 
02964     if (pgm.stmts().entries())
02965     substitute_parameters(pgm.stmts(), *pgm.stmts().first_ref(),
02966                   *pgm.stmts().last_ref(), subst_reals);
02967 }
02968 
02969 void
02970 substitute_parameters(Symtab &symtab, PC_REAL_BOOL subst_reals)
02971 {
02972     DictionaryIter<Symbol> sym_iter = symtab.iterator();
02973 
02974     /// ...  Substitute all parameters contained inside other parameters and
02975     /// ...  simplify them down.
02976 
02977     for ( ; sym_iter.valid(); ++sym_iter) {
02978     Symbol &symbol = sym_iter.current();
02979 
02980     if (symbol.sym_class() == SYMBOLIC_CONSTANT_CLASS
02981         && _has_param_in_expr(*symbol.expr_ref())) {
02982 
02983         Expression *new_expr
02984         = expr_substitute_parameters(symbol.expr_ref()->clone(),
02985                          subst_reals);
02986         new_expr = simplify(new_expr);
02987         symbol.expr(new_expr);
02988     }
02989     }
02990 
02991     /// ...  Substitute all parameters found in the bounds of arrays.
02992 
02993     for ( sym_iter.reset(); sym_iter.valid(); ++sym_iter)
02994     if (sym_iter.current().sym_class() == VARIABLE_CLASS) {
02995         Iterator<ArrayBounds> bound_iter = sym_iter.current().dim();
02996 
02997         for ( ; bound_iter.valid(); ++bound_iter) {
02998         ArrayBounds &bound = bound_iter.current();
02999 
03000         if (bound.lower_exists()
03001             && bound.lower_ref()->op() != INTEGER_CONSTANT_OP) {
03002 
03003             Expression *new_lower
03004             = expr_substitute_parameters(bound.lower_ref()->clone(),
03005                              subst_reals);
03006             new_lower = simplify(new_lower);
03007             bound.lower(new_lower);
03008         }
03009             
03010         if (bound.upper_exists()
03011             && bound.upper_ref()->op() != INTEGER_CONSTANT_OP) {
03012 
03013             Expression *new_upper
03014             = expr_substitute_parameters(bound.upper_ref()->clone(),
03015                              subst_reals);
03016             new_upper = simplify(new_upper);
03017             bound.upper(new_upper);
03018         }
03019         }
03020     }
03021 }
03022 
03023 void
03024 substitute_parameters(StmtList &stmts, const Statement &first_stmt,
03025               const Statement &last_stmt, PC_REAL_BOOL subst_reals)
03026 {
03027     Iterator<Statement> iter = stmts.iterator(first_stmt, last_stmt);
03028 
03029     for ( ; iter.valid(); ++iter)
03030     substitute_parameters(iter.current(), subst_reals);
03031 }
03032 
03033 void
03034 substitute_parameters(Statement &stmt, PC_REAL_BOOL subst_reals)
03035 {
03036     _assert_substitute_parameters(stmt, subst_reals);
03037     Mutator<Expression> iter = stmt.iterate_expressions();
03038     _stmt_substituted_var = False;
03039 
03040     for ( ; iter.valid(); ++iter) {
03041     Assign<Expression> eas(iter.assign());
03042     eas = expr_substitute_parameters(iter.pull(), subst_reals);
03043     }
03044 
03045     if (_stmt_substituted_var)
03046     stmt.build_refs();
03047 }
03048 
03049 
03050 /// expr_substitute_parameters
03051 ///   Acts similarly to the method substitute_parameters() except that it
03052 ///   applies to only a single expression.  This method modifies the given
03053 ///   expression and returns the result.
03054 
03055 Expression *
03056 expr_substitute_parameters(Expression *expr, PC_REAL_BOOL subst_reals)
03057 {
03058     if (! expr)
03059     return 0;
03060 
03061     Expression *result = expr;
03062 
03063     if (expr->op() == ID_OP) {
03064     if (expr->symbol().sym_class() == SYMBOLIC_CONSTANT_CLASS
03065         && _substitutable_type(expr->symbol().type().data_type(),
03066                    subst_reals)) {
03067         result = expr->symbol().expr_ref()->clone();
03068         delete expr;
03069         result = expr_substitute_parameters(result, subst_reals);
03070         _stmt_substituted_var = True;
03071     }
03072     else if (expr->substituted_valid())
03073         expr->substituted(expr_substitute_parameters(
03074         expr->grab_substituted(), subst_reals));
03075     }
03076     else {
03077     Mutator<Expression> iter = expr->arg_list();
03078     
03079     for ( ; iter.valid(); ++iter) {
03080         Assign<Expression> eas(iter.assign());
03081         eas = expr_substitute_parameters(iter.pull(), subst_reals);
03082     }
03083     }
03084 
03085     return result;
03086 }
03087 
03088 extern "C" int 
03089 substitute_parameters_pu(char **data, int *len)
03090 {
03091     P_ASSERT_HANDLER(0);
03092     external_interface_init();
03093  
03094     ProgramUnit *pgm = external_program_unit( data, len );
03095     p_assert( pgm, "not a program unit" );
03096 
03097     substitute_parameters(*pgm, (PC_REAL_BOOL) switch_value("sp_real"));
03098 
03099     return setup_to_return_handle( pgm->pu_tag_ref(), data, len);
03100 }
 © 1995-2005 University of Illinois, Urbana-Champaign. All rights reserved.  Fri Mar 25 23:05:42 2005