00001 #define DEBUG
00002
00003 #define VERBOSE
00004 #undef VERBOSE
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
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;
00056 extern boolean Vflag;
00057 extern boolean Oflag;
00058 extern boolean hflag;
00059 extern boolean Fflag;
00060 extern boolean Nflag;
00061
00062 extern boolean finished_accessible;
00063
00064
00065
00066
00067
00068 struct cf {
00069 NODE * cf_fc;
00070 struct cf * cf_next;
00071 };
00072
00073
00074
00075
00076 struct fcs {
00077 NODE * fcs_fc;
00078 struct cf * fcs_called;
00079 struct fcs * fcs_next;
00080 } * all_fcs, * all_fcs_tail;
00081
00082 NODE * whole_program;
00083
00084 NODE * outer_fc = NIL;
00085
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
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
00114 free_fcs();
00115 }
00116
00117
00118
00119 boolean calls_put(p)
00120 NODE * p;
00121 {
00122 return((get_complexity(p, FALSE) & NO_PUT) == 0);
00123 }
00124
00125
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
00137
00138 struct fcs * new_fc(p)
00139 NODE *p;
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
00156
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
00169
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
00181
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
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
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)
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
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
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
00264 p = p -> fcs_next;
00265 free(Op);
00266 }
00267 }
00268
00269
00270 struct fcs * current_fcs;
00271
00272
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
00293
00294
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
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
00387
00388
00389
00390
00391
00392
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;
00401 int stp;
00402 NODE * def;
00403 int n_appls = 0;
00404
00405 for (;;) {
00406
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
00422
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
00464 return(0);
00465 }
00466 case PARAMETER:
00467 if (def -> par_scope == whole_program) {
00468 return (i | IS_PRIMITIVE);
00469 } else {
00470
00471 return(0);
00472 }
00473 case RECORDCONSTRUCTION:
00474 case UNIONCONSTRUCTION:
00475 case PRODCONSTRUCTION:
00476
00477 dbgmsg("Constr comp not marked special\n");
00478 return(0);
00479 case MODPRIMARY:
00480
00481
00482
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
00501 }
00502
00503 case REXTERNDEF:
00504
00505
00506
00507 return(0);
00508
00509 default:
00510 return(0);
00511 }
00512 }
00513 }
00514
00515
00516
00517
00518
00519
00520
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
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
00545
00546
00547
00548
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
00609 i &= ~NO_SL;
00610 }
00611 i &= get_complexity(s -> decl_denotation, initial);
00612 } else {
00613
00614
00615
00616
00617
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
00645 inline_usable =
00646 has_inline &&
00647 (Gflag || index(op_sig -> fsig_inline_code, '%') == 0);
00648
00649 i = SIMPLE;
00650
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
00675 add_call(current_fcs,
00676 op_sig -> fsig_construction);
00677 if (is_descendant(op_sig -> fsig_construction,
00678 current_fcs -> fcs_fc)) {
00679
00680
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
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
00737 if (!Gflag && p -> fc_body -> kind == EXTERNDEF) {
00738 p -> fc_code_label = p -> fc_body -> ext_name;
00739
00740
00741
00742
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;
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
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
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
00831
00832
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
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:
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 }