C:/Users/Dennis/src/lang/russell.orig/src/pass5d/cl_analyze.c

Go to the documentation of this file.
00001 #define DEBUG
00002 
00003 #define VERBOSE
00004 #undef VERBOSE
00005 
00006 #define MAXFREEIDS 6  /* Maximum number of non-local (& non-global) */
00007                       /* free variables that can appear inside a    */
00008                       /* closure containing copied identifier       */
00009                       /* bindings rather than a static link.        */
00010 
00011 /*
00012  *  Set the CP_GLOBALS, NO_AR_REFS, and DIR_REC bits in FUNCCONSTR
00013  * nodes.  (See stree/streedefs.h for definition.)  Build the fc_free_vars
00014  * lists in those function constructions that will use closures
00015  * with copied globals.
00016  *  Clear NO_SL bit if Oflag is clear and cflag is set.  Thus code size is
00017  *  minimized.
00018  */
00019 # include "parm.h"
00020 # include <stdio.h>
00021 # include "stree/ststructs.mh"
00022 # include "pass3/is_local.h"
00023 # include "codegen.h"
00024 
00025 extern FILE * unparse_file;
00026 
00027 extern boolean fflag;
00028 
00029 extern boolean Vflag;
00030 
00031 extern boolean Oflag;
00032 
00033 extern boolean cflag;
00034 
00035 static int nestlevel;     /* Static nesting level of current function */
00036 
00037 static NODE * current_fc;  /* Innermost construction currently being */
00038                            /* analyzed.                              */
00039 
00040 static NODE * current_free_ids;   /* List of free identifiers for current */
00041                                   /* function construction.               */
00042 
00043 static int num_free_ids;    /* length(current_free_ids) */
00044 
00045 static boolean ar_refs;     /* Pointer to current activation record */
00046                             /* may be needed.                       */
00047 
00048 static boolean fast_calls;  /* Function contains calls to functions */
00049                             /* that do not have closures allocated  */
00050 
00051 static boolean forward_refs;  /* current_fc contains forward references */
00052                               /* to non_local ids.                      */
00053 
00054 /* Test whether                                                        */
00055 /* compiling subexpression p might result in a reference to a nonlocal */
00056 /* that has no previous nonlocal references,  and thus may not be      */
00057 /* accessible, e.g. because it is in a register.                       */
00058 boolean needs_new_nonl(p)
00059 NODE *p;
00060 {
00061     boolean result;
00062 
00063     switch(p -> kind) {
00064         case LETTERID:
00065         case OPRID:
00066             if (p -> sel_type == NIL) {
00067                 if (p -> id_last_definition -> kind == DECLARATION
00068                     && !(p -> id_last_definition -> decl_special 
00069                          & ID_IMPORTED)
00070                     && p -> id_last_definition -> level < nestlevel) {
00071                     result = TRUE;
00072                 } else {
00073                     result = FALSE;
00074                 }
00075             } else {
00076                 result = needs_new_nonl(p -> sel_type);
00077             }
00078             break;
00079         default:
00080             result = TRUE;
00081     }
00082 #   ifdef VERBOSE
00083         printf("needs_new_nonl(");
00084         unparse_file = stdout;
00085         unparse(p);
00086         printf(") returning %d level = %d, id level = %d\n",
00087                result, nestlevel,
00088                p -> id_last_definition? p -> id_last_definition -> level : 0);
00089 #   endif
00090     return(result);
00091 }
00092 
00093 /* Add a (non-slected) identifier to current_free_vars, if there is  */
00094 /* any chance the list will be needed.                               */
00095 /* Do nothing if we can determine that the acces can't really occur. */
00096 add_id_fv(id)
00097 NODE *id;
00098 {
00099     boolean already_there;
00100 
00101     if (id -> id_last_definition -> kind == DECLARATION
00102         && !(id -> id_last_definition -> decl_special & ID_IMPORTED)) {
00103         /* The accessibility check decided that this access was impossible; */
00104         /* We'll believe it.                                                */
00105 #           ifdef VERBOSE
00106                 printf("Discarding bogus global reference.\n");
00107 #           endif
00108             return;
00109     }
00110     if (((current_fc -> fc_complexity) & NO_CONSTR) != 0
00111         && num_free_ids <= MAXFREEIDS
00112         && ! forward_refs) {
00113       /* Globals should potentially be copied.  */
00114       /* Add p to list of free variables.       */
00115         already_there = FALSE;
00116         maplist(s, current_free_ids, {
00117             if (s -> id_last_definition -> pre_num
00118                 == id -> id_last_definition -> pre_num)
00119                 /* s and id are really the same */ {
00120                 already_there = TRUE;
00121                 break;
00122             }
00123         });
00124         if (!already_there) {
00125 #         ifdef VERBOSE
00126             printf("Adding non-local %s for fn %s\n",
00127                    getname(id -> id_str_table_index),
00128                    current_fc -> fc_code_label);
00129 #         endif
00130           addright(current_free_ids, id);
00131           num_free_ids++;
00132         }
00133     }
00134 }
00135 
00136 
00137 /*
00138  *  Set fields in the tree headed by p.  Lst is true if p is the
00139  * last subexpression executed as part of the current function.
00140  */
00141 cl_analyze(p, lst)
00142 register NODE * p;
00143 boolean lst;
00144 {
00145     NODE * v;
00146     int i;
00147 
00148     if (p == NIL) return;
00149 
00150     if (p -> signature -> kind == SIGNATURESIG) {
00151         /* signature evaluation doesn't reference anything. */
00152         return;
00153     }
00154 
00155     switch ( p -> kind ) {
00156         case LETTERID:
00157         case OPRID:
00158                 if (p -> sel_type != NIL) {
00159                     cl_analyze(p -> sel_type, FALSE);
00160                 } else {
00161                     if (!is_local(p, current_fc) &&
00162                         (p -> id_last_definition -> level != 0)) {
00163                         add_id_fv(p);
00164                         /* Is this a forward reference? */
00165                             if (current_fc -> ar_static_level
00166                                 > (p -> id_last_definition -> level) + 1) {
00167                                 /* There is an intervening function */
00168                                 /* construction.  This implies      */
00169                                 /* that id_forward_ref is accurate  */
00170                                 /* even in the presence of copied   */
00171                                 /* bindings.  (see decl_sort.c)     */
00172                                     if (p -> id_forward_ref) {
00173                                         forward_refs = TRUE;
00174                                     }
00175                             } else {
00176                                 /* Use a simple, very conservative test: */
00177                                 if (p -> id_last_definition -> post_num
00178                                     > current_fc -> post_num) {
00179                                     forward_refs = TRUE;
00180                                 }
00181                             }
00182                     }
00183                 }
00184                 break;
00185 
00186         case BLOCKDENOTATION :
00187                 maplist (v, p->bld_declaration_list, {
00188                     ASSERT (v->kind == DECLARATION,
00189                             "cl_analyze: decl expected");
00190                     cl_analyze(v-> decl_denotation, FALSE);
00191                 });
00192                 maplist (v,p->bld_den_seq, {
00193                     if (v == last(p -> bld_den_seq)) {
00194                         cl_analyze(v, lst);
00195                     } else {
00196                         cl_analyze(v, FALSE);
00197                     }
00198                 });
00199                 break;
00200 
00201         case USELIST:
00202                 maplist(s, p -> usl_den_seq, {
00203                     if (s == last(p -> usl_den_seq)) {
00204                         cl_analyze(s, lst);
00205                     } else {
00206                         cl_analyze(s, FALSE);
00207                     }
00208                 });
00209                 break;
00210                 
00211         case APPLICATION:
00212                 {
00213                   NODE * constr = p -> ap_operator -> signature
00214                                       -> fsig_construction;
00215                   /* Set DIR_REC bit, if appropriate */
00216                     if (lst && constr != NIL
00217                         && constr -> pre_num == current_fc -> pre_num
00218                         && constr -> pre_num != 0 /* bogus, e.g. external */) {
00219                         current_fc -> fc_complexity |= DIR_REC;
00220 #                       ifdef VERBOSE
00221                             printf("Directly recursive:\n");
00222                             unparse_file = stdout;
00223                             unparse(p);
00224                             printf("\nSetting recursion bit in %s (%d)\n",
00225                                    current_fc -> fc_code_label,
00226                                    current_fc -> pre_num);
00227 #                       endif
00228                     }
00229                   /* Check if this call could require operator value */
00230                   /* cl_analyze the operator if necessary.           */
00231                     {
00232                       extern boolean is_id();
00233                       NODE * op_sig = p -> ap_operator -> signature;
00234                       boolean is_ident = is_id(p -> ap_operator);
00235                       boolean no_op_val =
00236                              is_ident
00237                              && (op_sig -> fsig_inline_code != NIL
00238                                  || (constr != NIL &&
00239                                      (constr -> ar_static_level == 1
00240                                       || constr -> fc_complexity & NO_SL)));
00241                       if (!no_op_val) {
00242                           if (is_ident
00243                               && constr != NIL
00244                               && op_sig -> fsig_slink_known) {
00245                             if (constr -> ar_static_level > 1
00246                                 && (constr -> fc_complexity & SL_ACC)
00247                                 && !(constr -> fc_complexity & NO_SL)) {
00248                                 /* Call code requires static link */
00249                                 if(!(constr -> fc_complexity & NEED_CL)
00250                                    || needs_new_nonl(p -> ap_operator)) {
00251                                   /* Already made choices that make it        */
00252                                   /* impossible to compute closure for callee.*/
00253                                   /* If we copied globals, we couldn't get    */
00254                                   /* static link, thus there would be no way  */
00255                                   /* to compile the call.                     */
00256 #                                 ifdef VERBOSE
00257                                     unparse_file = stdout;
00258                                     printf("\nfast call: ");
00259                                     unparse(p);
00260                                     printf("\n");
00261 #                                 endif
00262                                   fast_calls = TRUE;
00263                                 } else {
00264                                   /* I do need the binding */
00265                                     cl_analyze(p -> ap_operator, FALSE);
00266                                 }
00267                             }  /* Otherwise I don't need the binding */
00268                           } else {
00269                               cl_analyze(p -> ap_operator, FALSE);
00270                           }
00271                       }
00272                     }
00273                 }
00274                 maplist(s, p -> ap_args, {
00275                     cl_analyze(s, FALSE);
00276                 });
00277                 break;
00278 
00279         case LOOPDENOTATION:
00280                 maplist(v,p->gl_list, {
00281                     cl_analyze(v, FALSE);
00282                 });
00283                 break;
00284 
00285         case GUARDEDLIST:
00286                 maplist(v,p->gl_list, {
00287                     cl_analyze(v, lst);
00288                 });
00289                 break;
00290 
00291         case GUARDEDELEMENT:
00292                 cl_analyze(p -> ge_guard, FALSE);
00293                 cl_analyze(p -> ge_element, lst);
00294                 break;
00295 
00296         case FUNCCONSTR:
00297                 {
00298                     NODE * old_fc = current_fc;
00299                     NODE * old_free_ids = current_free_ids;
00300                     int old_num_free_ids = num_free_ids;
00301                     boolean old_ar_refs = ar_refs;
00302                     boolean old_forward_refs = forward_refs;
00303                     boolean old_fast_calls = fast_calls;
00304 
00305                     boolean need_closure;           /* new function */
00306                     boolean cp_globals;             /* new function */
00307 
00308                     need_closure = ((p -> fc_complexity & NEED_CL) != 0);
00309 
00310                     current_fc = p;
00311                     nestlevel = current_fc -> ar_static_level;
00312                     current_free_ids = lock(emptylist());
00313                     num_free_ids = 0;
00314                     ar_refs = FALSE;
00315                     forward_refs = FALSE;
00316                     fast_calls = FALSE;
00317 
00318                     cl_analyze(p -> fc_body, TRUE);
00319 
00320                     cp_globals = ((p -> fc_complexity & NO_CONSTR)
00321                                   && (num_free_ids < MAXFREEIDS)
00322                                   && need_closure
00323                                   && !(p -> fc_complexity
00324                                        & (DIR_CALL | NESTED_AR_BLOCK))
00325                                   && !forward_refs
00326                                   && !fast_calls
00327                                   && p -> ar_static_level != 0);
00328                     if (Vflag && forward_refs) {
00329                         printf("%s contains embedded forward references\n",
00330                                p -> fc_code_label);
00331                     }
00332                     if (Vflag && fast_calls) {
00333                         printf("%s contains calls requiring static link\n",
00334                                p -> fc_code_label);
00335                     }
00336                     if (cp_globals) {
00337                         p -> fc_complexity |= CP_GLOBALS;
00338                         p -> fc_free_vars = current_free_ids;
00339                                 /* not ref counted */
00340                         if (Vflag) {
00341                             printf("%s closure contains copies of %d non-locals\n",
00342                                    p -> fc_code_label,
00343                                    length(current_free_ids));
00344                         }
00345                         /* Make sure that none of the non-locals are vars */
00346                         /* allocated directly in activation record.       */
00347                         maplist(s, current_free_ids, {
00348                             if (s -> id_last_definition -> kind == DECLARATION
00349                                 && (s -> id_last_definition -> decl_special
00350                                     & VAR_ON_STACK)) {
00351                                 s -> id_last_definition -> decl_special
00352                                         &= ~VAR_ON_STACK;
00353                                 if (Vflag) {
00354                                     printf("\tForcing heap allocation of %s\n",
00355                                            getname(s -> id_str_table_index));
00356                                 }
00357                             }
00358                         });
00359                     } else {
00360                         if (current_free_ids != NIL) {
00361                             vfree(unlock(current_free_ids));
00362                         }
00363                     }
00364                     if (!ar_refs) {
00365                         p -> fc_complexity |= NO_AR_REFS;
00366                     }
00367 
00368                     if (cflag && !Oflag) {
00369                         p -> fc_complexity &= (~NO_SL);
00370                         /* Otherwise we would probably generate code twice */
00371                     }
00372 
00373                     if (cp_globals) {
00374                         ar_refs = old_ar_refs;
00375                     } else if (!need_closure) {
00376                         ar_refs |= old_ar_refs;
00377                     } else {
00378                         if (Vflag && old_fc != NIL) {
00379                             printf("%s may need a.r. pointer for %s\n",
00380                                    p -> fc_code_label,
00381                                    old_fc -> fc_code_label);
00382                         }
00383                         ar_refs = TRUE;
00384                     }
00385 
00386                     if (Vflag && !(p -> fc_complexity & SL_ACC)) {
00387                         printf("%s contains no indirections through slink\n",
00388                                p -> fc_code_label);
00389                     }
00390 
00391                     current_fc = old_fc;
00392                     if (current_fc != NIL) {
00393                       nestlevel = current_fc -> ar_static_level;
00394                     }
00395                     current_free_ids = old_free_ids;
00396                     num_free_ids = old_num_free_ids;
00397                     forward_refs = old_forward_refs;
00398                     fast_calls = old_fast_calls;
00399                     break;
00400                 }
00401 
00402         case MODPRIMARY:
00403                 cl_analyze(p -> mp_primary, FALSE);
00404                 if (p -> mp_type_modifier != NIL
00405                     && p -> mp_type_modifier -> kind == WITHLIST) {
00406                     maplist (q, p -> mp_type_modifier -> wl_component_list, {
00407                         cl_analyze(q -> decl_denotation, FALSE);
00408                     });
00409                 }
00410                 break;
00411 
00412         case ENUMERATION:
00413         case PRODCONSTRUCTION:
00414         case UNIONCONSTRUCTION:
00415                 /* Subexpressions are not evaluated */
00416                 break;
00417 
00418         case QSTR:
00419         case UQSTR:
00420                 {
00421                     NODE * tsig = p -> sel_type -> signature;
00422 
00423                     ASSERT(tsig -> kind == TYPESIGNATURE,
00424                            "cl_analyze: bad string type");
00425                     if (tsig -> ts_string_code != NIL
00426                         && tsig -> ts_element_code != NIL
00427                         && strlen(p -> str_string) <= MAXSTRLEN) {
00428                             break;
00429                             /* May be dubious on VAX ? */
00430                     } else {
00431                         cl_analyze(p -> str_expansion, lst);
00432                     }
00433                     break;
00434                 }
00435 
00436         case WORDELSE:
00437                 break;
00438 
00439         case EXTERNDEF:
00440                 break;
00441 
00442         case REXTERNDEF:
00443                 break;
00444 
00445         case RECORDCONSTRUCTION:
00446                 maplist(s, p -> rec_component_list, {
00447                     cl_analyze(s -> re_denotation, FALSE);
00448                 });
00449                 break;
00450 
00451         case EXTENSION:
00452                 cl_analyze(p -> ext_denotation, FALSE);
00453                 break;
00454 
00455         case RECORDELEMENT:
00456         case DECLARATION:
00457         case PARAMETER:
00458         case FUNCSIGNATURE:
00459         case LISTHEADER: /* should never get here */
00460         case VARSIGNATURE:
00461         case VALSIGNATURE:
00462         case TYPESIGNATURE:
00463         case TSCOMPONENT:
00464         case DEFCHARSIGS:
00465         case WITHLIST:
00466         case EXPORTLIST:
00467         case EXPORTELEMENT:
00468         case ALLCONSTANTS:
00469         case HIDELIST:
00470         case WORDCAND:
00471         case WORDCOR:
00472         default:
00473                 dbgmsg("cl_analyze: bad kind, kind = %d\n", p -> kind);
00474                 abort();
00475 
00476     };
00477     return;
00478 }

Generated on Fri Jan 25 10:39:47 2008 for russell by  doxygen 1.5.4