Polaris: lambda_util.cc Source File

lambda_util.cc

Go to the documentation of this file.
00001 ///
00002 ///
00003 #include "../ProgramUnit.h"
00004 #include "../Collection/List.h"
00005 #include "../Collection/RefDatabase.h"
00006 #include "../Expression/LambdaCallExpr.h"
00007 #include "../Expression/UnaryExpr.h"
00008 #include "../Expression/replace.h"
00009 #include "../Info.h"
00010 #include "../macros.h"
00011 #include "../Wildcard/AnyOfType.h"
00012 #include "../Wildcard/WildcardOr.h"
00013 
00014 #include "precalc_util.h"
00015 #include "lambda_util.h"
00016 
00017 template class Info<int>;
00018 template class Info<LambdaInfo *>;
00019 
00020 /// Definitions for lambda call replacement code
00021 
00022 enum ARG_EVAL_TYPE {
00023     NON_STRICT,                 /// ...  Argument need not be evaluated
00024      STRICT                     /// ...  Argument must be evaluated
00025 };
00026 
00027 enum STRICT_BOOL {
00028     PRESERVE_TYPE = 0,
00029     MAKE_NON_STRICT = 1
00030 };
00031 
00032 typedef         RefDatabase<int, Expression>ArgDatabase;
00033 
00034 template class Info<ArgDatabase *>;
00035 
00036 /// An ArgExprElem points to an ArgNumberExpr for a formal reference.
00037 /// It also contains the type of evaluation for this reference.
00038 ///
00039 /// If an ArgExprElem is marked LAZY, it means that this formal reference
00040 /// need not be evaluated.
00041 ///
00042 /// If an ArgExprElem is marked STRICT, it means that this formal reference
00043 /// must be evaluated.
00044 
00045 class ArgExprElem : public Listable {
00046 
00047  private:
00048     Expression * _e;            /// ...  Pointer to expression
00049 
00050     ARG_EVAL_TYPE   _eval_type; /// ...  Type of argument evaluation
00051 
00052     friend inline ostream & operator << (ostream & o, const ArgExprElem & h) 
00053         { h.print(o); return o; }
00054 
00055  public:
00056     ArgExprElem();
00057     ArgExprElem(Expression & e, ARG_EVAL_TYPE eval_type);
00058     ArgExprElem(const ArgExprElem & other);
00059 
00060     ArgExprElem & operator = (const ArgExprElem & other);
00061 
00062     virtual ~ArgExprElem();
00063 
00064     Expression & expr() const;
00065 
00066     ARG_EVAL_TYPE   eval_type() const;
00067     void            eval_type(ARG_EVAL_TYPE change_type);
00068 
00069     virtual void    print(ostream & o) const;
00070     virtual Listable *listable_clone() const;
00071 };
00072 
00073 ArgExprElem::ArgExprElem()
00074 {
00075     /// ...  nothing to do
00076 }
00077 
00078 ArgExprElem::ArgExprElem(Expression & e,
00079                          ARG_EVAL_TYPE eval_type)
00080 {
00081     _e = &e;
00082     _eval_type = eval_type;
00083 }
00084 
00085 ArgExprElem::ArgExprElem(const ArgExprElem & other)
00086 {
00087     *this = other;
00088 }
00089 
00090 ArgExprElem &
00091 ArgExprElem::operator = (const ArgExprElem & other) 
00092 {
00093     _e = other._e;
00094     _eval_type = other._eval_type;
00095 
00096     return *this;
00097 }
00098 
00099 ArgExprElem::~ArgExprElem()
00100 {
00101     /// ...  nothing to do
00102 }
00103 
00104 Expression &
00105 ArgExprElem::expr() const
00106 {
00107     return *_e;
00108 }
00109 
00110 ARG_EVAL_TYPE
00111 ArgExprElem::eval_type() const
00112 {
00113     return _eval_type;
00114 }
00115 
00116 void
00117 ArgExprElem::eval_type(ARG_EVAL_TYPE change_type)
00118 {
00119     _eval_type = change_type;
00120 }
00121 
00122 void
00123 ArgExprElem::print(ostream & o) const
00124 {
00125     _e->print(o);
00126 
00127     o << ": ";
00128 
00129     if (_eval_type == NON_STRICT)
00130         o << "Non-Strict";
00131     else
00132         o << "Strict";
00133 }
00134 
00135 Listable       *
00136 ArgExprElem::listable_clone() const
00137 {
00138     return new ArgExprElem(*this);
00139 }
00140 
00141 template class TypedCollection<ArgExprElem>;
00142 template class List<ArgExprElem>;
00143 template ostream & operator << (ostream &, const List<ArgExprElem> &);
00144 template class Assign<ArgExprElem>;
00145 
00146 template class Iterator<ArgExprElem>;
00147 template class Mutator<ArgExprElem>;
00148 
00149 /// A CollectPair is a pair of an owned list of formal expression
00150 /// references and a replacement pattern.
00151 
00152 class CollectPair {
00153  public:
00154     Expression       &pattern;
00155     List<ArgExprElem> list;
00156 
00157     CollectPair(Expression & replacement_pattern);
00158 
00159     void absorb(CollectPair * absorbed,
00160                 STRICT_BOOL lazy = PRESERVE_TYPE);
00161 };
00162 
00163 CollectPair::CollectPair(Expression & replacement_pattern)
00164 :pattern(replacement_pattern)
00165 {
00166     /// ...  Nothing to do
00167 }
00168 
00169 /// Miscellaneous class functions
00170 
00171 /// Absorb a CollectPair into this object
00172 
00173 void
00174 CollectPair::absorb(CollectPair * absorbed,
00175                     STRICT_BOOL lazy GIV(PRESERVE_TYPE))
00176 {
00177     /// ...  Grab each ArgExprElem from the CollectPair to be absorbed
00178 
00179     for (Mutator<ArgExprElem> list_iter = absorbed->list;
00180                                list_iter.valid(); ++list_iter) {
00181         /// ...  Grab current element from list
00182         ArgExprElem    *grabbed = list_iter.grab();
00183 
00184         /// ...  Override grabbed element to be evaluated non-strictly if
00185         /// ...  requested
00186 
00187         if (lazy == MAKE_NON_STRICT)
00188             grabbed->eval_type(NON_STRICT);
00189 
00190         /// ...  Insert grabbed element into this object's formal list
00191         list.ins_last(grabbed);
00192     }
00193 
00194     /// ...  Delete other object
00195     delete absorbed;
00196 }
00197 
00198 template class Info<CollectPair *>;
00199 
00200 /* collect_lambda_formals summarizes the formal/actual substitutions
00201    needed to evaluate an expression wherever those subtitutions arise
00202    due to calls to statement functions.
00203  
00204    A close reading of F77 sections 6.6, 10.1,2,4, and 15.4 is recommended
00205    before tinkering (Jaxon)... and a sanity check (Grout).
00206 
00207    A LambdaCallExpr contains a lambda expression (the pattern into which
00208    substitution is made) and a parameter expression (a list of arguments
00209    which are substituted into the pattern).
00210 
00211    collect_lambda_formals is originally passed the lambda expression of
00212    the LambdaCallExpr currently being replaced.  All the formal expressions,
00213    represented by ArgNumberExprs, which correspond to the LambdaCallExpr
00214    currently being replaced are precisely those within the lambda expression
00215    which are not hidden from view by a nested LambdaCallExpr.
00216 
00217    A LambdaCallExpr hides any ArgNumberExprs found in its
00218    lambda expression from view (all these must correspond to that or
00219    a more deeply nested LambdaCallExpr), but does not hide any
00220    unhidden ArgNumberExprs found in its parameter expression from
00221    view (all those must correspond to the LambdaCallExpr
00222    currently being evaluated).
00223 
00224    Treatment of non-strict operators is discussed in the F77 sections
00225    mentioned above. */
00226 
00227 /// (Note:  This function is a traverse_action_func_t function)
00228 
00229 void
00230 collect_lambda_formals(const Expression & e,
00231                        ExtraInfo & extra_info)
00232 {
00233     /// ...  Point to CollectPair
00234     CollectPair & collect_pair = *((Info<CollectPair * >&) extra_info).data();
00235 
00236     switch (e.op()) {
00237     case ARG_OP:
00238       {
00239     /// ...  Create an argument expression element
00240     ArgExprElem    *arg_e 
00241       = new ArgExprElem( CASTAWAY(Expression &) e, STRICT);
00242 
00243     /// ...  Insert the argument expression element into formal_list
00244     collect_pair.list.ins_last(arg_e);
00245     break;
00246       }
00247 
00248     case LAMBDA_CALL_OP:
00249       {
00250     /// ...  Create a new collect pair
00251     CollectPair    *new_collect_pair
00252       = new CollectPair(collect_pair.pattern);
00253 
00254     /// ...  Recursively invoke collect_lambda_formals on parameter
00255     /// ...  subexpression (whose unhidden lambda call args, if any,
00256     /// ...  are ours)
00257 
00258     Info<CollectPair *> inf(new_collect_pair);
00259 
00260     traverse(CASTAWAY(Expression &) e.arg_list()[1],
00261          new_collect_pair->pattern,
00262          collect_lambda_formals,
00263          inf, NON_RECURSIVE_REPLACE, PREORDER_REPLACE);
00264 
00265     /// ...  Absorb the new collect_pair into the existing one
00266 
00267     collect_pair.absorb(new_collect_pair);
00268     break;
00269       }
00270 
00271     case MULT_OP:
00272     case OR_OP:
00273     case AND_OP:
00274       {
00275     /// ...  Create a new collect pair
00276     CollectPair    *new_collect_pair
00277       = new CollectPair(collect_pair.pattern);
00278 
00279     /// ...  Recursively invoke collect_lambda_formals on subexpressions
00280 
00281     for (Iterator<Expression> expr_iter = e.arg_list();
00282          expr_iter.valid(); ++expr_iter) {
00283 
00284       Info<CollectPair *> inf(new_collect_pair);
00285 
00286       traverse(expr_iter.current(),
00287            new_collect_pair->pattern,
00288            collect_lambda_formals,
00289            inf, NON_RECURSIVE_REPLACE, PREORDER_REPLACE);
00290     }
00291 
00292     /// ...  Absorb the new collect_pair into the existing one, making
00293     /// ...  the new variable references NON_STRICT
00294 
00295     collect_pair.absorb(new_collect_pair, MAKE_NON_STRICT);
00296       }
00297     break;
00298     default: break;
00299     }
00300 
00301 return;
00302 }
00303 
00304 /// Replace an ArgNumberExpr with a clone from the corresponding data
00305 /// in the RefDatabase.
00306 
00307 /// Replace a LambdaCallExpr with itself to prevent further checking of its
00308 /// subexpressions
00309 
00310 Expression     *
00311 replace_lambda_call_expr(Expression * e, ExtraInfo & extra_info)
00312 {
00313     static AnyOfType *lambda_pattern = new AnyOfType(LAMBDA_CALL_OP);
00314     static AnyOfType *arg_pattern = new AnyOfType(ARG_OP);
00315     static WildcardOr *replace_pattern = new WildcardOr(lambda_pattern,
00316                             arg_pattern);
00317 
00318     Expression * return_expr;
00319 
00320     /// ...  If lambda call, recursively examine its parameter expression
00321 
00322     switch(e->op()) {
00323     case LAMBDA_CALL_OP: {
00324       Assign<Expression> expr_as(e->arg_list().assign(1));
00325       expr_as = replace(e->arg_list().pull(1), *replace_pattern,
00326             replace_lambda_call_expr, extra_info,
00327             NON_RECURSIVE_REPLACE, PREORDER_REPLACE);
00328       return_expr = e;
00329       break;
00330     }
00331     default: {       
00332       /// ...  Point at argument map
00333       ArgDatabase & argument_map = *((Info<ArgDatabase *>&) extra_info).data();
00334       Expression     *reference_ptr = argument_map.find_ref(e->value());
00335       p_assert(reference_ptr, "Missing argument in replace_lambda_call_expr");
00336       /// ...  Delete the old expression
00337       delete e;
00338       /// ...  Return a clone to caller
00339       return_expr = reference_ptr->clone();
00340     }
00341     }
00342     return return_expr;
00343 }
00344 
00345 /// replace_lambda_call returns the fully-substituted lambda expression
00346 /// from LAMBDA_CALL expression e.
00347 
00348 Expression     *
00349 replace_lambda_call(Expression * e,
00350                     ExtraInfo & extra_info)
00351 {
00352     /// ...  patterns for LAMBDA_CALL replacement
00353 
00354     static AnyOfType *lambda_pattern = new AnyOfType(LAMBDA_CALL_OP);
00355     static AnyOfType *arg_pattern = new AnyOfType(ARG_OP);
00356     static AnyOfType *mult_pattern = new AnyOfType(MULT_OP);
00357     static AnyOfType *OR_pattern = new AnyOfType(OR_OP);
00358     static AnyOfType *AND_pattern = new AnyOfType(AND_OP);
00359     static WildcardOr *logical_pattern = new WildcardOr(OR_pattern, AND_pattern);
00360     static WildcardOr *non_strict_pattern = new WildcardOr(mult_pattern,
00361                                logical_pattern);
00362     static WildcardOr *replace_pattern = new WildcardOr(lambda_pattern, arg_pattern);
00363     static WildcardOr *collect_pattern = new WildcardOr(replace_pattern, non_strict_pattern);
00364 
00365     /// ...  Retrieve parameters from argument
00366 
00367     LambdaInfo & arg_map = *((Info<LambdaInfo * >&) extra_info).data();
00368 
00369     ProgramUnit & pgm = *arg_map.program_ref;
00370     Statement     & s = *arg_map.stmt_ref;
00371     LC_TYPE   lc_type = arg_map.lc_type;
00372 
00373     LambdaCallExpr & lambda_call_expr = *(LambdaCallExpr *) e;
00374 
00375     /// ...  Reinvoke recursive search on the parameter expression
00376 
00377     if (lambda_call_expr.parameters_valid()) {
00378       Assign<Expression> lambda_as(lambda_call_expr.arg_list().assign(1));
00379       lambda_as = replace(lambda_call_expr.arg_list().pull(1),
00380               *lambda_pattern, replace_lambda_call, extra_info,
00381               RECURSIVE_REPLACE, PREORDER_REPLACE);
00382     }
00383 
00384     /// ...  Set up list to collect data
00385     CollectPair     collect_pair(*collect_pattern);
00386 
00387     /// ...  Collect lambda formals from lambda expression, grabbing lambda
00388     /// ...  expression out of its containing list
00389 
00390     Expression     *repl_lambda_expr = lambda_call_expr.arg_list().pull(0);
00391 
00392     Info<CollectPair *> inf(&collect_pair);
00393 
00394     traverse(*repl_lambda_expr, collect_pair.pattern, collect_lambda_formals,
00395              inf, NON_RECURSIVE_REPLACE, PREORDER_REPLACE);
00396 
00397     /// ...  Define the argument map
00398     ArgDatabase     argument_map;
00399 
00400     /// ...  Define the list of precalculated ID node prototypes
00401     List<Expression>ID_prototype_list;
00402 
00403     /// ...  Set the initial argument reference number
00404     int             arg_num = 1;
00405 
00406     if (lambda_call_expr.parameters_valid())
00407         /// ...  Iterate over the LAMBDA_CALL's parameter expression (which may
00408         /// ...  have been changed by earlier LAMBDA_CALLs)
00409 
00410         for (Iterator<Expression> expr_iter
00411                 = lambda_call_expr.parameters_guarded().arg_list();
00412                                   expr_iter.valid(); ++expr_iter) {
00413             /// ...  Grab corresponding arguments from collect_pair to
00414             /// ...  formal_list
00415 
00416             List<ArgExprElem> formal_list;
00417 
00418             for (Mutator<ArgExprElem> elem_iter = collect_pair.list;
00419                                       elem_iter.valid(); ++elem_iter) {
00420                 if (elem_iter.current_valid()) {
00421                     if (elem_iter.current().expr().value() == arg_num)
00422                         formal_list.ins_last(elem_iter.pull());
00423                 }
00424             }
00425 
00426             /// ...  Find correct actual parameter
00427             Expression     *actual_parm = &expr_iter.current();
00428 
00429             while (actual_parm->op() == PAREN_OP)
00430                 actual_parm = &actual_parm->expr_guarded();
00431 
00432             /// ...  Handle actual parameter cases
00433 
00434             switch (actual_parm->op()) {
00435             case INTEGER_CONSTANT_OP:
00436             case REAL_CONSTANT_OP:
00437             case COMPLEX_OP:
00438             case ID_OP:
00439                 {
00440                     /// ...  Handle constant and ID actual parameters.  Insert
00441                     /// ...  reference to actual parameter into argument map
00442 
00443                     argument_map.ins(arg_num, *actual_parm);
00444                     break;
00445                 }
00446 
00447             default:
00448                 {
00449                     /// ...  If there is more than one formal reference to
00450                     /// ...  parameter, or there is only one non-strict
00451                     /// ...  reference which is not side-effect free, 
00452                     /// ...  precalculate parameter.
00453 
00454                     if ((formal_list.entries()>1) ||
00455                         ((formal_list.entries() == 1) &&
00456                          ((formal_list[0].eval_type() == NON_STRICT) &&
00457                           (!actual_parm->is_side_effect_free())))) {
00458 
00459                         /// ...  Precalculate parameter, getting an ID node in
00460                         /// ...  return
00461 
00462                         Expression     *ID_prototype
00463                                     = get_precalc(actual_parm->clone(), pgm, s);
00464 
00465                         /// ...  Put ID node on owning list (for later cleanup)
00466 
00467                         ID_prototype_list.ins_last(ID_prototype);
00468 
00469                         /// ...  Insert reference to ID node prototype into
00470                         /// ...  argument map.
00471 
00472                         argument_map.ins(arg_num, *ID_prototype);
00473                     }
00474                     else {
00475                         /// ...  Insert reference to actual parameter into
00476                         /// ...  argument map.
00477                         argument_map.ins(arg_num, *actual_parm);
00478                     }
00479                 }
00480             }
00481             /// ...  Increment argument number
00482             ++arg_num;
00483         }
00484 
00485     /// ...  Substitute all arguments in lambda expression. Use preorder search,
00486     /// ...  a wildcard which matches on ArgNumberExprs and LambdaCallExprs, and
00487     /// ...  non-recursion.
00488 
00489     {
00490         Info<ArgDatabase *> inf(&argument_map);
00491 
00492         repl_lambda_expr =
00493             replace(repl_lambda_expr, *replace_pattern,
00494                     replace_lambda_call_expr, 
00495                     inf, NON_RECURSIVE_REPLACE, PREORDER_REPLACE);
00496     }
00497 
00498     /// ...  Simplification is too dangerous here when inlining (where not
00499     /// ...  all variables with the same name are the same!)
00500     /// ...  If this is a statement function call, simplify fully-substituted
00501     /// ...  lambda expression before return and put parentheses around the
00502     /// ...  expression to prevent inadvertant call-by-reference access
00503 
00504     if (lc_type == STMT_FUNCTION_CALL) {
00505         repl_lambda_expr = simplify(repl_lambda_expr);
00506         repl_lambda_expr = new UnaryExpr(PAREN_OP, repl_lambda_expr->type(),
00507                                          repl_lambda_expr);
00508     }
00509 
00510     return repl_lambda_expr;
00511 }
00512 
00513 /// remove_lambda_calls removes all LAMBDA_CALL expressions in expression
00514 /// tree e, possibly inserting assignment(s) to precalc_variable(s) before
00515 /// stmt of pgm.  Precalculation is avoided for constant expressions (IDs
00516 /// are constant thanks to F77 pg 6-15 ln 55!) and for formals referenced 
00517 /// once or not at all.
00518 
00519 Expression     *
00520 remove_lambda_calls(Expression * e, LambdaInfo & lambda)
00521 {
00522     /// ...  pattern for LAMBDA_CALL replacement
00523 
00524     static AnyOfType lambda_pattern(LAMBDA_CALL_OP);
00525 
00526     /// ...  Call replace to recursively replace LAMBDA_CALL expressions
00527 
00528     Info<LambdaInfo *> inf(&lambda);
00529 
00530     return replace(e, lambda_pattern, replace_lambda_call,
00531                    inf, RECURSIVE_REPLACE, PREORDER_REPLACE);
00532 }
00533 
00534 /// The scanner turns statement function references into LAMBDA_CALLs to a
00535 /// copy of the statement function definition.  The bound variables have
00536 /// no names; they are identified positionally.  A LAMBDA_CALL node
00537 /// resembles a FUNCTION_CALL node, with the function ID replaced by the
00538 /// statement function definition.
00539 /// Remove all statement functions from program and rebuild in-out refs
00540 
00541 void
00542 remove_all_statement_functions(ProgramUnit & pgm)
00543 {
00544     /// ...  Initialize LambdaInfo object
00545 
00546     LambdaInfo lambda(NULL, NULL, STMT_FUNCTION_CALL);
00547 
00548     lambda.program_ref = &pgm;
00549 
00550     /// ...  Iterate over statements
00551 
00552     for (Iterator<Statement> stmt_iter = pgm.stmts().iterator();
00553                              stmt_iter.valid(); ++stmt_iter) {
00554         Statement      *stmt_ref = &stmt_iter.current();
00555 
00556         lambda.stmt_ref = stmt_ref;
00557 
00558         /// ...  Iterate over expressions and remove statement functions
00559 
00560         for (Mutator<Expression> expr_mutr = stmt_ref->iterate_expressions();
00561                                   expr_mutr.valid(); ++expr_mutr) {
00562             if (expr_mutr.current_valid()) {
00563           Assign<Expression> expr_as(expr_mutr.assign());
00564           expr_as = remove_lambda_calls(expr_mutr.pull(), lambda);
00565           }
00566         }
00567 
00568         /// ...  Rebuild statement references
00569         stmt_ref->build_refs();
00570     }
00571 }
 © 1995-2005 University of Illinois, Urbana-Champaign. All rights reserved.  Fri Mar 25 23:05:58 2005