C:/Users/Dennis/src/lang/russell.orig/src/pass5c/analyze.c

Go to the documentation of this file.
00001 #define DEBUG
00002 
00003 #define VERBOSE
00004 #undef VERBOSE
00005 /*
00006  *   This uses a simple iterative data-flow analysis algorithm to
00007  * set the NO_SL, NO_PUT, NO_CALLCC, and NO_CONSTR bits of all
00008  * fc_complexity fields in a program.  The "setup" routine
00009  * initially traverses the tree.  It computes approximations
00010  * to the fc_complexity fields based only on intraprocedural
00011  * approximation, and enters all function constructions into
00012  * a call graph.  The "solve" routine then finds fc_complexity
00013  * values such that the fc_complexity value at each procedure is
00014  * the bitwise and of its local value and of those for the procedures
00015  * it calls.
00016  *   We frequently use conservative approximations, especially
00017  * in the presence of higher order functions.
00018  *   These routines are designed to be called with and/or without
00019  * previously computed information about variable allocation and
00020  * declaration accessibility.  The NO_SL information will be less conservative
00021  * with such information.
00022  *   Nflag is ignored everywhere except in the top level routine "callc_callcc".
00023  */
00024 # include "parm.h"
00025 # include <stdio.h>
00026 # include "stree/ststructs.mh"
00027 # include "codeutil.h"
00028 # include "pass3/is_local.h"
00029 
00030 # define RELEVANT (NO_SL | NO_PUT | NO_CALLCC | NO_CONSTR)
00031 
00032 # ifdef VERBOSE
00033 #   define IFVERBOSE(x) x
00034 # else
00035 #   define IFVERBOSE(x)
00036 # endif
00037 
00038 extern FILE * unparse_file;
00039 
00040 /* Is p of the form id $ id $ ... $ id? */
00041 boolean is_selected_id(p)
00042 NODE *p;
00043 {
00044     if (p -> kind != LETTERID && p -> kind != OPRID) {
00045         return(FALSE);
00046     } else if (p -> sel_type == NIL) {
00047         return(TRUE);
00048     } else {
00049         return(is_selected_id(p -> sel_type));
00050     }
00051 }
00052 
00053 # define setup(p) get_complexity(p, TRUE)
00054 
00055 extern boolean Gflag; /* Generating intermediate code */
00056 extern boolean Vflag; /* Print optimization info      */
00057 extern boolean Oflag;
00058 extern boolean hflag; /* No stack allocation.  Thus don't set NO_SL */
00059 extern boolean Fflag; /* Simple functions cant access GF */
00060 extern boolean Nflag; /* No Call/cc calls. */
00061 
00062 extern boolean finished_accessible;
00063                       /* Finished accessibility and static link */
00064                       /* analysis, as well as the allocation    */
00065                       /* pass.                                  */
00066 
00067 /* List of called functions */
00068 struct cf {
00069     NODE * cf_fc;
00070     struct cf * cf_next;
00071 };
00072 
00073 /* List of all function constructions                        */
00074 /* Note that separately compiled functions dont appear here, */
00075 /* though they may appear in the list of called functions    */
00076 struct fcs {
00077     NODE * fcs_fc;
00078     struct cf * fcs_called; /* list of called functions */
00079     struct fcs * fcs_next;
00080 } * all_fcs, * all_fcs_tail;
00081 
00082 NODE * whole_program;
00083 
00084 NODE * outer_fc = NIL;  /* Outermost function construction, excl. */
00085                         /* main function.                         */
00086 
00087 void solve();
00088 
00089 void print_fcs();
00090 
00091 void free_fcs();
00092 
00093 analyze(p)
00094 NODE *p;
00095 {
00096     whole_program = p;
00097     /* Initialize function list */
00098         all_fcs = all_fcs_tail = NIL;
00099     (void) setup(p);
00100 #   ifdef VERBOSE
00101         printf("INITIAL CALL GRAPH INFO:\n");
00102         print_fcs();
00103         printf("\nFINAL CALL GRAPH INFO:\n");
00104 #   endif
00105     solve();
00106 #   ifdef VERBOSE
00107         print_fcs();
00108 #   else
00109         if (Vflag) {
00110             print_fcs();
00111         }
00112 #   endif
00113     /* Deallocate table */
00114         free_fcs();
00115 }
00116 
00117 /* Determine whether an expression results in a call to put */
00118 /* Assumes that analyze has previously been run.            */
00119 boolean calls_put(p)
00120 NODE * p;
00121 {
00122     return((get_complexity(p, FALSE) & NO_PUT) == 0);
00123 }
00124 
00125 /* The same thing for call/cc */
00126 boolean calls_callcc(p)
00127 NODE * p;
00128 {
00129     if (Nflag) {
00130         return(FALSE);
00131     } else {
00132         return((get_complexity(p, FALSE) & NO_CALLCC) == 0);
00133     }
00134 }
00135 
00136 /* Add a function to the end of the all_fcs list  */
00137 /* Return a pointer to the newly created fcs node */
00138 struct fcs * new_fc(p)
00139 NODE *p;    /* Better be a function construction */
00140 {
00141     struct fcs * result = (struct fcs *) malloc(sizeof (struct fcs));
00142 
00143     result -> fcs_fc = p;
00144     result -> fcs_next = NIL;
00145     result -> fcs_called = NIL;
00146     if (all_fcs == NIL)  {
00147         all_fcs = all_fcs_tail = result;
00148     } else {
00149         all_fcs_tail -> fcs_next = result;
00150         all_fcs_tail = result;
00151     }
00152     return(result);
00153 }
00154 
00155 /* Add a call from the function pointed to by fcs node p to the */
00156 /* function construction q.                                     */
00157 void add_call(p, q)
00158 struct fcs *p;
00159 NODE * q;
00160 {
00161     struct cf * t = (struct cf *) malloc(sizeof (struct cf));
00162     
00163     t -> cf_fc = q;
00164     t -> cf_next = p -> fcs_called;
00165     p -> fcs_called = t;
00166 }
00167 
00168 /* Reevaluate the fc_complexity field of p, based on other fc_complexity */
00169 /* information.  Return TRUE if it changed.                              */
00170 boolean reeval(p)
00171 struct fcs *p;
00172 {
00173     int old_compl = (p -> fcs_fc -> fc_complexity) & RELEVANT;
00174     int new_compl = old_compl;
00175     struct cf * q;
00176 
00177     for (q = p -> fcs_called; q != NIL; q = q -> cf_next) {
00178         new_compl &= (q -> cf_fc -> fc_complexity) & RELEVANT;
00179     }                                                                         
00180     /* Preserve NO_CONSTR bit.  Preserve NO_SL bit if SL_ACC was used */      
00181     /* to determine its original value.                               */      
00182       if (Gflag && finished_accessible) {                                     
00183         new_compl |= (old_compl & (NO_CONSTR | NO_SL));                       
00184       } else {                                                                
00185         new_compl |= (old_compl & NO_CONSTR);
00186       }
00187     p -> fcs_fc -> fc_complexity &= ~RELEVANT;
00188     p -> fcs_fc -> fc_complexity |= new_compl;
00189     return(new_compl != old_compl);
00190 }
00191 
00192 
00193 /* Iteratively adjust various fc_complexity fields */
00194 void solve()
00195 {
00196     boolean changed = TRUE;
00197     struct fcs *p;
00198 
00199     while (changed) {
00200         changed = FALSE;
00201         for (p = all_fcs; p != NIL; p = p -> fcs_next) {
00202             changed |= reeval(p);
00203         }
00204     }
00205 }
00206 
00207 
00208 /* Print the call graph and fc_complexity fields */
00209 void print_fcs()
00210 {
00211     struct fcs *p;
00212     struct cf *q;
00213 
00214     for (p = all_fcs; p != NIL; p = p -> fcs_next) {
00215         NODE * f = p -> fcs_fc;
00216         int compl = f -> fc_complexity;
00217 
00218         printf("function %s:\n", p -> fcs_fc -> fc_code_label);
00219         if (compl & NO_SL) {
00220             printf(" - no real activ. record");
00221         }
00222         if (compl & NO_PUT) {
00223             printf(" - no put call");
00224         }
00225         if (compl & NO_CALLCC) {
00226             printf(" - no callcc call");
00227         }
00228         if (compl & NO_CONSTR) {
00229             printf(" - no nested constrs");
00230         }
00231         printf("\n");
00232 #       ifndef VERBOSE
00233         if (!Gflag)  /* -GV prints this stuff anyway */
00234 #       endif
00235           if (p -> fcs_called != NIL) {
00236             printf("- known to call:\n");
00237             for (q = p -> fcs_called; q != NIL; q = q -> cf_next) {
00238                 printf("\t%s\n", q -> cf_fc -> fc_code_label);
00239             }
00240           }
00241     }
00242 }
00243 
00244 /* Free the call graph data structure */
00245 void free_fcs()
00246 {
00247     struct fcs *p;
00248     struct cf *q;
00249 
00250     p = all_fcs;
00251     while (p != NIL) {
00252         struct fcs * Op = p;
00253 
00254         /* Free called function nodes */
00255           q = p -> fcs_called;
00256           while (q != NIL) {
00257               struct cf * Oq = q;
00258  
00259               q = q -> cf_next;
00260               free(Oq);
00261           }
00262 
00263         /* Free this node */
00264           p = p -> fcs_next;
00265           free(Op);
00266     }
00267 }
00268 
00269 
00270 struct fcs * current_fcs;  /* fcs node for current function construction */
00271 
00272 /* Determine whether a with list has a component matching given name */
00273 boolean wl_has_comp(wl, id)
00274 NODE * wl;
00275 NODE * id;
00276 {
00277     maplist(s, wl, { 
00278         if (s -> decl_id -> id_str_table_index
00279             == id -> id_str_table_index) {
00280                 IFVERBOSE(
00281                     printf("Found it as wlc\n");
00282                 )
00283                 return(TRUE);
00284         }
00285     });
00286 #   ifdef VERBOSE
00287         printf("Didnt find it as wlc\n");
00288 #   endif
00289     return(FALSE);
00290 }
00291 
00292 /* Return a type expression t1, s.t. (t1[...]...[...])$id is    */
00293 /* identical to t$id.                                           */
00294 /* Attempt to make t1 as informative as possible.               */
00295 NODE * get_type_def(t, id)
00296 NODE * t;
00297 NODE * id;
00298 {
00299     NODE * t1 = t;
00300     NODE * def;
00301 
00302     for (;;) {
00303 #       ifdef VERBOSE
00304             printf("get_type_def: type = ");
00305             unparse_file = stdout;
00306             unparse(t1);
00307             printf("\n");
00308 #       endif
00309         switch(t1 -> kind) {
00310             case LETTERID:
00311             case OPRID:
00312                 if (t1 -> sel_type != NIL) {
00313 #                   ifdef VERBOSE
00314                         printf("type selected from type\n");
00315 #                   endif
00316                     return(t1);
00317                 }
00318                 def = t1 -> id_last_definition;
00319                 switch(def -> kind) {
00320                     case DECLARATION:
00321                         if (def -> post_num < t1 -> pre_num) {
00322                             t1 = def -> decl_denotation;
00323                             continue;
00324                         } else {
00325 #                           ifdef VERBOSE
00326                                 printf("Possible cycle\n");
00327 #                           endif
00328                             /* There may be a cycle */
00329                             return(t1);
00330                         }
00331                     case MODPRIMARY:
00332                         t1 = def;
00333                         continue;
00334                     default:
00335 #                       ifdef VERBOSE
00336                             printf("Definition defies analysis:");
00337                             unparse_file = stdout;
00338                             unparse(t1);
00339                             printf("\n");
00340 #                       endif
00341                         return(t1);
00342                 }
00343             case EXTENSION:
00344                 t1 = t1 -> ext_denotation;
00345                 continue;
00346             case APPLICATION:
00347                 t1 = t1 -> ap_operator;
00348                 continue;
00349             case MODPRIMARY:
00350                 {
00351                     NODE * tm = t1 -> mp_type_modifier;
00352 
00353                     if (tm == NIL
00354                         || tm -> kind == HIDELIST
00355                         || tm -> kind == EXPORTLIST
00356                         || tm -> kind == WITHLIST
00357                            && !wl_has_comp(tm -> wl_component_list,id)){
00358                         t1 = t1 -> mp_primary;
00359 #                       ifdef VERBOSE
00360                             printf("Looking at modified type\n");
00361 #                       endif
00362                         continue;
00363                     } else {
00364 #                       ifdef VERBOSE
00365                             printf("Complicated type mod:");
00366                             unparse_file = stdout;
00367                             unparse(t1);
00368                             printf("\n");
00369 #                       endif
00370                         return(t1);
00371                     }
00372                 }
00373             default:
00374 #               ifdef VERBOSE
00375                     printf("Type expression defies analysis:");
00376                     unparse_file = stdout;
00377                     unparse(t1);
00378                     printf("\n");
00379 #               endif
00380                 return(t1);
00381         }
00382     }
00383 }
00384 
00385 /*
00386  * Determine whether the operator p is a, possible repeated, application
00387  * of, or selection from, a primitive type or function.  Accordingly,
00388  * return some combination of IS_PUT, IS_CALLCC, and IS_PRIMITIVE.
00389  * For our purposes, a function is primitive if it is not a construction,
00390  * and if we can tell if it is "put" or "Callcc".
00391  * Is_primitive may err on the side of treating a primitive as a
00392  * non-primitive.
00393  */
00394 # define IS_PRIMITIVE 1
00395 # define IS_PUT 2
00396 # define IS_CALLCC 4
00397 int is_primitive(p)
00398 NODE *p;
00399 {
00400     int i = 0; /* current approximation to result */
00401     int stp;
00402     NODE * def;
00403     int n_appls = 0;
00404 
00405     for (;;) {
00406         /* If there is "special" info, use it. */
00407             if (p -> signature -> kind == FUNCSIGNATURE) {
00408                 stp = special_tp(p -> signature -> fsig_special);
00409             } else {
00410                 stp = NOT_SPECIAL;
00411             }
00412             switch (stp) {
00413                 case NOT_SPECIAL:
00414                   break;
00415                 case STD_PUT:
00416                   return (IS_PUT | IS_PRIMITIVE);
00417                 case STD_CALLCC:
00418                   return (IS_CALLCC | IS_PRIMITIVE);
00419                 case PROD_PROJ:
00420                 case UNION_PROJ:
00421                   /* Function itself is benign, but repeated */
00422                   /* application may cause problems          */
00423                   if (n_appls == 0) {
00424                     return(IS_PRIMITIVE);
00425                   } else {
00426                     return(0);
00427                   }
00428                 default:
00429                   return(IS_PRIMITIVE);
00430             } 
00431       switch (p -> kind) {
00432         case LETTERID:
00433         case OPRID:
00434             if (p -> sel_type != NIL) {
00435                 NODE * real_tp = get_type_def(p -> sel_type, p);
00436                 extern long indx_put;
00437 
00438                 if (real_tp -> kind == LETTERID) {
00439                     NODE * def = real_tp -> id_last_definition;
00440                     if (real_tp -> sel_type != NIL) {
00441                         return(0);
00442                     } else if (def -> kind == PARAMETER
00443                                && def -> par_scope == whole_program) {
00444                         i = IS_PRIMITIVE;
00445                         if (p -> id_str_table_index == indx_put) {
00446                             i |= IS_PUT;
00447                         }
00448                         return(i);
00449                     } else {
00450                         return(0);
00451                     }
00452                 } else {
00453                     return(0);
00454                 }
00455             }
00456             def = p -> id_last_definition;
00457             switch(def -> kind) {
00458                 case DECLARATION:
00459                     if (def -> post_num < p -> pre_num) {
00460                         p = def -> decl_denotation;
00461                         continue;
00462                     } else {
00463                         /* There may be a cycle */
00464                         return(0);
00465                     }
00466                 case PARAMETER:
00467                     if (def -> par_scope == whole_program) {
00468                         return (i | IS_PRIMITIVE);
00469                     } else {
00470                         /* No idea where it came from */
00471                         return(0);
00472                     }
00473                 case RECORDCONSTRUCTION:
00474                 case UNIONCONSTRUCTION:
00475                 case PRODCONSTRUCTION:
00476                     /* Hopefully will never get here */
00477                     dbgmsg("Constr comp not marked special\n");
00478                     return(0);
00479                 case MODPRIMARY:
00480                     /* Should usually be picked up elsewhere, */
00481                     /* either by special info or should be    */
00482                     /* construction.                          */
00483 #                   ifdef VERBOSE
00484                         printf("is_primitive saw MODPRIMARY\n");
00485 #                   endif
00486                     return(0);
00487                 case TYPESIGNATURE:
00488                 default:
00489                     dbgmsg("is_primitive saw bad definition\n");
00490             }
00491 
00492         case APPLICATION:
00493             p = p -> ap_operator;
00494             n_appls++;
00495             continue;
00496 
00497         case FUNCCONSTR:
00498             if (p -> fc_body -> kind == EXTERNDEF) {
00499                 return(IS_PRIMITIVE | IS_PUT);
00500                     /* Assume it doesn't call Callcc */
00501             }
00502 
00503         case REXTERNDEF:
00504             /* Shouldn't matter.  Typically this will either be marked */
00505             /* special, or we will have had a pointer to a dummy       */
00506             /* construction enetered in the call graph.                */
00507             return(0);
00508 
00509         default:
00510             return(0);
00511       }
00512     }
00513 }
00514 
00515 /*
00516  *  Return the fc_complexity value appropriate for the subexpression p.
00517  *  If initial is true, then enter nested function constructions and
00518  *  calls into list;  if not, assume fc_complexity values are final.
00519  *  If initial is FALSE, the NO_SL bit will be very conservative, since
00520  *  we do not assume that we have correct context info.
00521  */
00522 long get_complexity(p, initial)
00523 boolean initial;
00524 register NODE * p;
00525 {
00526     NODE * v;
00527     int i;
00528     boolean is_global_id;
00529 #   define SIMPLE (NO_SL | NO_PUT | NO_CALLCC | NO_CONSTR)
00530 
00531     if (p == NIL) return;
00532 
00533     if (p -> signature -> kind == SIGNATURESIG) {
00534         /* signatures are trivial to evaluate. */
00535         return(SIMPLE);
00536     }
00537 
00538     switch ( p -> kind ) {
00539         case LETTERID:
00540         case OPRID:
00541             if (p -> sel_type != NIL) {
00542                 return(get_complexity(p -> sel_type, initial));
00543             }
00544             /* Determine whether the identifier is a global that can be */
00545             /* accessed through the global frame pointer.               */
00546             /* Note that there may be LET activation records outside    */
00547             /* the outermost function.  We can be much more precise     */
00548             /* after allocation.                                        */
00549             is_global_id = 
00550                 (!Fflag && initial
00551                  && (finished_accessible 
00552                      && p -> id_last_definition -> level == 0
00553                     || p -> id_last_definition -> kind == PARAMETER
00554                        && (outer_fc == NIL || !is_local(p, outer_fc))));
00555             if (is_global_id
00556                 || (initial && is_local(p, current_fcs -> fcs_fc))
00557                 || (Oflag && is_int_const(p))) {
00558 #               ifdef VERBOSE
00559                     printf("Found simple id: %s, outer_fc = %X, scope:\n",
00560                            getname(p -> id_str_table_index),
00561                            outer_fc);
00562                     unparse_file = stdout;
00563                     if (p -> id_last_definition -> kind == PARAMETER) {
00564                         unparse(p -> id_last_definition -> par_scope);
00565                         printf("\n");
00566                         if (initial) {
00567                             unparse(current_fcs -> fcs_fc);
00568                         } else {
00569                             printf("unknown");
00570                         }
00571                         printf("\n");
00572                     }
00573 #               endif
00574                 return(SIMPLE);
00575             } else {
00576 #               ifdef VERBOSE
00577                     extern FILE * unparse_file;
00578                     printf("Found complex id: %s, outer_fc = %X, scope:\n",
00579                            getname(p -> id_str_table_index),
00580                            outer_fc);
00581                     unparse_file = stdout;
00582                     if (p -> id_last_definition -> kind == PARAMETER) {
00583                         unparse(p -> id_last_definition -> par_scope);
00584                         printf("\n");
00585                         if (initial) {
00586                             unparse(current_fcs -> fcs_fc);
00587                         } else {
00588                             printf("unknown");
00589                         }
00590                         printf("\n");
00591                     }
00592 #               endif
00593                 return(NO_PUT | NO_CALLCC | NO_CONSTR);
00594             }
00595 
00596         case BLOCKDENOTATION :
00597                 i = SIMPLE;
00598                 maplist(s, p -> bld_declaration_list, {
00599     
00600                     ASSERT (s -> kind == DECLARATION,
00601                             "analyze: decl expected");
00602                     if (!Gflag) { i &= ~NO_SL; }
00603                     if (!finished_accessible) {
00604                         i &= ~NO_SL;
00605                         i &= get_complexity(s -> decl_denotation, initial);
00606                     } else if (s -> decl_needed) {
00607                         if (!(s -> decl_special & (VAR_IN_REG | ID_IN_REG))) {
00608                           /* Need activation record space for identifier */
00609                           i &= ~NO_SL;
00610                         }
00611                         i &= get_complexity(s -> decl_denotation, initial);
00612                     } else {
00613                         /* Declaration is not executed.            */
00614                         /* Thus r.h.s is irrelevant, unless it is  */
00615                         /* a function called from within the block,*/
00616                         /* in which case we deal with it at the    */
00617                         /* call site.                              */
00618                         if (initial) {
00619                             (void) get_complexity(s -> decl_denotation, TRUE);
00620                         }
00621                     }
00622                 });
00623                 maplist (v,p->bld_den_seq, {
00624                     i &= get_complexity(v, initial);
00625                 });
00626                 return(i);
00627 
00628         case USELIST:
00629                 i = SIMPLE;
00630                 maplist(s, p -> usl_den_seq, {
00631                     i &= get_complexity(s, initial);
00632                 });
00633                 return(i);
00634 
00635                 
00636         case APPLICATION:
00637                 {
00638                   NODE * op_sig = p -> ap_operator -> signature;
00639                   boolean has_inline, inline_usable;
00640                   extern boolean is_id();
00641                                         
00642                   has_inline = (op_sig -> fsig_inline_code != NIL)
00643                                && is_id(p -> ap_operator);
00644                                /* operator has no side effects */
00645                   inline_usable =
00646                         has_inline &&
00647                         (Gflag || index(op_sig -> fsig_inline_code, '%') == 0);
00648                         /* Can be used in Fcodegen environment */
00649                   i = SIMPLE;
00650                   /* Adjust for operator */
00651                     if ((has_inline && !inline_usable) ||
00652                         (!has_inline)) {
00653                         if (!Gflag || op_sig -> fsig_construction == NIL
00654                             || (!finished_accessible)
00655                             || (op_sig -> fsig_construction -> fc_complexity
00656                                 & SL_ACC)) {
00657                             i &= ~NO_SL;
00658                         }
00659                     }
00660                     if (op_sig -> fsig_construction == NIL) {
00661                         int is_prim = is_primitive(p -> ap_operator);
00662                         if (is_prim & IS_PRIMITIVE) {
00663                             if (is_prim & IS_PUT) {
00664                                 i &= ~NO_PUT;
00665                             } else if (is_prim & IS_CALLCC) {
00666                                 i &= ~NO_CALLCC;
00667                             }
00668                         } else {
00669                             i &= ~NO_PUT;
00670                             i &= ~NO_CALLCC;
00671                         }
00672                     } else {
00673                         if (initial) {
00674                           /* Add the call to call graph */
00675                             add_call(current_fcs,
00676                                      op_sig -> fsig_construction);
00677                             if (is_descendant(op_sig -> fsig_construction,
00678                                               current_fcs -> fcs_fc)) {
00679                                 /* Callee may be inside otherwise */
00680                                 /* unevaluated rhs of declaration */
00681                                 i &= ~NO_CONSTR;
00682                             }
00683                         } else {
00684                             i &= op_sig -> fsig_construction
00685                                         -> fc_complexity;
00686                         }
00687                     }
00688                   maplist(s, p -> ap_args, {
00689                     i &= get_complexity(s, initial);
00690                   });
00691                   if (!inline_usable
00692                       && (op_sig -> fsig_construction == NIL
00693                           || !(op_sig -> fsig_slink_known)
00694                           || !is_selected_id(p -> ap_operator) )) {
00695                     i &= get_complexity(p -> ap_operator, initial);
00696                   }
00697 #                 ifdef VERBOSE
00698                     printf("Application (%x): ", i);
00699                     unparse_file = stdout;
00700                     unparse(p);
00701                     printf("\n");
00702 #                 endif
00703                   return(i);
00704                 }  
00705 
00706         case LOOPDENOTATION:
00707         case GUARDEDLIST:
00708                 i = SIMPLE;
00709                 if (!Gflag && p -> kind == LOOPDENOTATION) {
00710                     i &= ~NO_SL;
00711                     /* Simple code generator doesn't understand loops */
00712                 }
00713                 maplist(v,p->gl_list, {
00714                     i &= get_complexity(v, initial);
00715                 });
00716 #               ifdef VERBOSE
00717                     printf("Guarded commands (%x): ", i);
00718                     unparse_file = stdout;
00719                     unparse(p);
00720                     printf("\n");
00721 #               endif
00722                 return(i);
00723 
00724         case GUARDEDELEMENT:
00725                 return(get_complexity(p -> ge_guard, initial)
00726                        & get_complexity(p -> ge_element, initial));
00727                 break;
00728 
00729         case FUNCCONSTR:
00730                 {
00731                     NODE * old_outer_fc = outer_fc;
00732                     struct fcs * old_fcs = current_fcs;
00733                     int f_compl;
00734 
00735                     if (initial) {
00736                       /* Fill in fc_code_label */
00737                         if (!Gflag && p -> fc_body -> kind == EXTERNDEF) {
00738                           p -> fc_code_label = p -> fc_body -> ext_name;
00739                            /* The Vax code generator needs this so that   */
00740                            /* the correct routine can be called directly. */
00741                            /* The -G code generator generates a stub      */
00742                            /* named by the old fc_code_label field.       */
00743                         }
00744 #                       ifdef DEBUG
00745                           if (p -> fc_code_label == NIL) {
00746                             dbgmsg("get_complexity: Missing fc_code_label\n");
00747                           }
00748 #                       endif
00749                     }
00750 
00751                     i = NO_PUT | NO_CALLCC;
00752                      
00753                     if (initial) {
00754                       if (p != whole_program && outer_fc == NIL) {
00755                         outer_fc = p;
00756                       }
00757                       current_fcs = new_fc(p);
00758                       f_compl = get_complexity(p -> fc_body, initial);
00759                       p -> fc_complexity &= ~RELEVANT;
00760                       p -> fc_complexity |= f_compl;
00761                       if (hflag) {
00762                         p -> fc_complexity &= ~NO_SL;
00763                       }
00764 #                     ifdef DEBUG
00765                         if (f_compl & (~RELEVANT)) {
00766                             dbgmsg("analyze: irrelevant bits set\n");
00767                             abort(f_compl);
00768                         }
00769 #                     endif
00770                       current_fcs = old_fcs;
00771                       outer_fc = old_outer_fc;
00772                     }
00773 
00774                     return(i);
00775                 }
00776 
00777         case MODPRIMARY:
00778                 i = SIMPLE;
00779                 if (!Gflag) {
00780                     i &= ~NO_SL;
00781                 }
00782                 i &= get_complexity(p -> mp_primary, initial);
00783                 if (p -> mp_type_modifier != NIL
00784                     && p -> mp_type_modifier -> kind == WITHLIST) {
00785                     i &= ~NO_SL;  /* Needs activation record space */
00786                     maplist (q, p -> mp_type_modifier -> wl_component_list, {
00787                         i &= get_complexity(q -> decl_denotation, initial);
00788                     });
00789                 }
00790                 return(i);
00791 
00792         case ENUMERATION:
00793         case PRODCONSTRUCTION:
00794         case UNIONCONSTRUCTION:
00795                 /* Subexpressions are not evaluated */
00796                 return(SIMPLE & ~NO_SL);
00797 
00798         case QSTR:
00799         case UQSTR:
00800                 {
00801                     NODE * tsig = p -> sel_type -> signature;
00802                     int maxlen;
00803 
00804                     ASSERT(tsig -> kind == TYPESIGNATURE,
00805                            "setup: bad string type");
00806                     if (tsig -> ts_string_max == -1) {
00807                         maxlen = MAXSTRLEN;
00808                     } else {
00809                         maxlen = tsig -> ts_string_max;
00810                     }
00811                     if (tsig -> ts_string_code != NIL
00812                         && tsig -> ts_element_code != NIL
00813                         && strlen(p -> str_string) <= maxlen) {
00814                             return(SIMPLE);
00815                             /* May be dubious on VAX ? */
00816                     } else {
00817                         if (Gflag) {
00818                             return(get_complexity(p -> str_expansion, initial));
00819                         } else {
00820                             return(get_complexity(p -> str_expansion, initial)
00821                                    & (~NO_SL));
00822                         }
00823                     }
00824                 }
00825 
00826         case WORDELSE:
00827                 return(SIMPLE);
00828 
00829         case EXTERNDEF:
00830                 /* Setting NO_SL here is counterproductive, since */
00831                 /* the resulting simple function is unlikely to   */
00832                 /* ever get called.                               */
00833                 return(NO_CALLCC);
00834 
00835         case REXTERNDEF:
00836                 {
00837                     NODE * sig = p -> signature;
00838 
00839                     ASSERT(sig -> kind == FUNCSIGNATURE,
00840                            "setup: funny REXTERN");
00841                     /* Worry about it in calling context */
00842                     return(SIMPLE);
00843                 }
00844 
00845         case RECORDCONSTRUCTION:
00846                 i = SIMPLE & ~NO_SL;
00847                 maplist(s, p -> rec_component_list, {
00848                   i &= get_complexity(s -> re_denotation, initial);
00849                 });
00850                 return(i);
00851 
00852         case EXTENSION:
00853                 return(get_complexity(p -> ext_denotation, initial) & ~NO_SL);
00854 
00855         case RECORDELEMENT:
00856         case DECLARATION:
00857         case PARAMETER:
00858         case FUNCSIGNATURE:
00859         case LISTHEADER: /* should never get here */
00860         case VARSIGNATURE:
00861         case VALSIGNATURE:
00862         case TYPESIGNATURE:
00863         case TSCOMPONENT:
00864         case DEFCHARSIGS:
00865         case WITHLIST:
00866         case EXPORTLIST:
00867         case EXPORTELEMENT:
00868         case ALLCONSTANTS:
00869         case HIDELIST:
00870         case WORDCAND:
00871         case WORDCOR:
00872         default:
00873                 dbgmsg("setup: bad kind, kind = %d\n", p -> kind);
00874                 abort();
00875 
00876     };
00877     return;
00878 }

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