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

Go to the documentation of this file.
00001 # define OBSOLETE
00002 # undef OBSOLETE
00003 # define DEBUG
00004 
00005 # include "parm.h"
00006 # include <stdio.h>
00007 # include "stree/ststructs.mh"
00008 # include "codegen.h"
00009 # include "op_codes.h"
00010 # include "pass4/sigs.h"
00011 # include "pass3/is_local.h"
00012 
00013 extern int yydebug;
00014 extern int yynerrs;
00015 
00016 extern FILE * unparse_file;
00017 
00018 extern char str_code_buf[];
00019 
00020 extern int avail_loc;
00021 
00022 extern int Glevel;
00023 
00024 extern NODE * Gcurrent;  /* Current function construction */
00025 
00026 extern boolean Vflag;
00027 
00028 extern boolean Nflag;
00029 
00030 extern boolean Oflag;
00031 
00032 extern boolean fflag;   /* No frame pointer, can't update SP */
00033 
00034 extern boolean Fflag;   /* Same, but HINT ONS is not assumed to be */
00035                         /* understood.   (Fflag ==> fflag)         */
00036                         /* In its absence, HINT ONS followed by    */
00037                         /* HINT DEA is assumed to compile to a     */
00038                         /* noop.                                   */
00039 
00040 extern boolean hflag;   /* All activation records on heap. */
00041 
00042 extern FILE * Goutfile;
00043 
00044 extern boolean sl_available;    /* Static link available for current */
00045                                 /* function construction.            */
00046 
00047 boolean Gpush_size();
00048 
00049 boolean is_id();
00050 
00051 extern boolean is_int_const();
00052 
00053 extern NODE * equiv_expr();
00054 
00055 static int arg_loc;
00056 
00057 /* Check whether a signature describes an object containing no    */
00058 /* runtime information.  Works with either argument or parameter  */
00059 /* signature.                                                     */
00060 boolean vacuous_arg(p)
00061 NODE *p;
00062 {
00063     extern NODE * var_Void;
00064 
00065     switch (p -> kind) {
00066         case VALSIGNATURE:
00067             return(FALSE);
00068         case VARSIGNATURE:
00069             return(comp_st(p, var_Void, NIL, NIL) == 0);
00070         case FUNCSIGNATURE:
00071             return(FALSE);
00072         case TYPESIGNATURE:
00073             return(tsig_length(p) == 0);
00074         case SIGNATURESIG:
00075             return(TRUE);
00076         case LETTERID:
00077         case OPRID:
00078             if (p -> id_last_definition -> kind == DECLARATION
00079                 && p -> id_last_definition -> decl_sig_transp) {
00080                 return(vacuous_arg(p -> id_last_definition -> decl_denotation));
00081                 /* We checked in pass3 that this isn't circular */
00082             } else {
00083                 ASSERT(p -> id_last_definition -> kind == PARAMETER,
00084                        "vacuous_arg: strange signature identifier\n");
00085                 return(FALSE);
00086             }
00087         default:
00088             dbgmsg("vacuous_arg: bad argument kind\n");
00089             abort(p);
00090     }
00091 }
00092 
00093 /* A version of maprlist (see mknode.c) that applies fn          */
00094 /* to subexpressions in the list up to (and including) the last  */
00095 /* nonvacuous one with a trailing TRUE argument.  fn is invoked  */
00096 /* on the remaining list arguments with a trailing FALSE         */
00097 /* argument.                                                     */
00098 static boolean maprl1_non_vacuous(l,fn)
00099 ConsNode * l;
00100 void (*fn)();
00101 {
00102     register boolean tail_non_vacuous = FALSE;
00103 
00104     if (l != NIL) {
00105       tail_non_vacuous = maprl1_non_vacuous(cn_tail(l),fn)
00106                          || !vacuous_arg(((NODE *)cn_head(l)) -> signature);
00107       (*fn) (cn_head(l), tail_non_vacuous);
00108     }
00109     return(tail_non_vacuous);
00110 }
00111 
00112 void maprlist_non_vacuous(l, fn)
00113 LIST l;
00114 void (*fn)();
00115 {
00116     (void) maprl1_non_vacuous(l -> lh_first, fn);
00117 }
00118 
00119 boolean reg_ok = FALSE;
00120                  /* A variable allocated to a register is OK for */
00121                  /* this call to Garg_expression.  If encountered*/
00122                  /* dont generate any code.                      */
00123 /* Evaluate the argument expression p into arg_loc after         */
00124 /* decrementing it.  This is useful only because                 */
00125 /* maprlist_non_vacuous does not call functions with a location  */
00126 /* argument.  If needed is FALSE, then p does not have run-time  */
00127 /* significance, and should not be evaluated into arg_loc. It    */
00128 /* may still need to be evaluated for side effects.              */
00129 Garg_expression(p, needed)
00130 NODE *p;
00131 boolean needed;
00132 {
00133     int SAVarg_loc = arg_loc - 1;
00134     int SAVreg_ok = reg_ok;
00135 
00136     if (needed) {
00137         if (reg_ok && (p -> kind == LETTERID || p -> kind == OPRID)
00138             && p -> sel_type == NIL
00139             && p -> id_last_definition -> kind == DECLARATION
00140             && (p -> id_last_definition -> decl_special & VAR_IN_REG)) {
00141             /* Do nothing.  This is already handled by substitution into */
00142             /* the in-line code.                                         */
00143         } else {
00144             reg_ok = FALSE;
00145             Gexpression(p, SAVarg_loc, FALSE);  /* May clobber arg_loc */
00146                /* Nested functions would be good for something after all */
00147         }
00148     } else {
00149         SAVarg_loc ++;
00150         if (!is_id(p) &&
00151             (p -> signature -> kind != TYPESIGNATURE
00152              || calls_put(p))) {
00153             if (Vflag) {
00154                 printf("Evaluating vacuous argument ");
00155                 unparse_file = stdout;
00156                 unparse(p);
00157                 printf(" for effect\n");
00158             }
00159         }
00160         reg_ok = FALSE;
00161         Gexpression(p, SK, FALSE);
00162     }
00163     arg_loc = SAVarg_loc;
00164     reg_ok = SAVreg_ok;
00165 }
00166 
00167 # ifdef UNDEFINED
00168 int arg_no;
00169 
00170 /* Call Gexpression with temporary. Then issue an ARG instruction */
00171 /* with that temporary, and with argument number given by arg_no. */
00172 /* The decrement arg_no.                                          */
00173 /* This is useful only because maprlist can only call functions   */
00174 /* with one argument.                                             */
00175 Gdir_arg_expression(p, needed)
00176 NODE *p;
00177 boolean needed;
00178 {
00179     if (needed) {
00180         int SAVarg_no = arg_no;
00181         int tmp_loc = avail_loc++;
00182         
00183         gen2(DCL, tmp_loc, DCL_INT);
00184         Gexpression(p, tmp_loc, FALSE);  /* May clobber arg_no */
00185         gen2(ARG, SAVarg_no, tmp_loc);
00186         gen1(UDC, tmp_loc);
00187         arg_no = SAVarg_no - 1;
00188     } else if (!is_id(p) &&
00189                (p -> signature -> kind != TYPESIGNATURE
00190                 || calls_put(p))) {
00191         if (Vflag) {
00192             printf("Evaluating vacuous argument ");
00193             unparse_file = stdout;
00194             unparse(p);
00195             printf(" for effect\n");
00196         }
00197         Gexpression(p, SK, FALSE);
00198     }
00199 }
00200 
00201 #endif
00202 
00203 /* Evaluate p into the current location of a memory block pointed to   */
00204 /* by heap_loc. Decrement the                                          */
00205 /* current location counter (heap_offset).  The value of heap_loc      */
00206 /* is a pointer to the heap block.                                     */
00207 /* Needed has the same meaning as for Garg_expression.                 */
00208 static int heap_loc;
00209 static int heap_offset;
00210 
00211 Gheap_expression(p, needed)
00212 NODE *p;
00213 boolean needed;
00214 {
00215     if (needed) {
00216         int tmp_loc = avail_loc++;
00217         int SAVheap_loc = heap_loc;
00218         int SAVheap_offset = heap_offset;
00219 
00220         gen2(DCL, tmp_loc, DCL_INT);
00221         Gexpression(p, tmp_loc, FALSE);
00222             /* May have clobbered heap_loc, heap_offset */
00223         gen3(STI, SAVheap_loc, SAVheap_offset, tmp_loc);
00224         gen1(UDC, tmp_loc);
00225         heap_offset = SAVheap_offset - 1;
00226         heap_loc = SAVheap_loc;
00227     } else if (!is_id(p) &&
00228                (p -> signature -> kind != TYPESIGNATURE
00229                 || calls_put(p))) {
00230         if (Vflag) {
00231             printf("Evaluating vacuous argument ");
00232             unparse_file = stdout;
00233             unparse(p);
00234             printf(" for effect\n");
00235         }
00236         Gexpression(p, SK, FALSE);
00237     }
00238 }
00239 
00240 /* Genarate code for loc := abs(loc) */
00241 gen_abs(loc)
00242 int loc;
00243 {
00244 #   ifdef OBSOLETE
00245       gen3(GEI, loc, C0, TL);
00246       genl(BRT, "1f");
00247       gen2(NGI, loc, loc);
00248       genl(LBL, "1");
00249 #   else
00250       gen2(ABI, loc, loc);
00251 #   endif
00252 }
00253 
00254 /* Determine whether an expression is an identifier */
00255 boolean is_id(p)
00256 NODE *p;
00257 {
00258     if (p -> kind != LETTERID && p -> kind != OPRID) {
00259         return(FALSE);
00260     } else {
00261         return(TRUE);
00262     }
00263 }
00264 
00265 
00266 /* Generate RIC code for the function application p */
00267 /* Code leaves the result rloc.                     */
00268 /* last_expr is TRUE only if this is the last call  */
00269 /* in the function body.                            */
00270 Gappl(p, rloc, last_expr)
00271 NODE *p;
00272 int rloc;
00273 boolean last_expr;
00274 {
00275     register NODE *v;
00276     register int argcount;
00277     struct RIC_instr * in_line;     /* in-line code, NIL if not known */
00278     boolean stack_call; /* use stack for activation rec.  */
00279     boolean test_closure = TRUE;
00280                         /* If stack_call is false, generate */
00281                         /* code to check for possible stack */
00282                         /* activation record at run time    */
00283     int size_loc;       /* location for a.r. size         */
00284                         /* used only for stack based call */
00285     int ar_loc;         /* pointer to a.r.                */
00286     int fn_loc;         /* pointer to function object     */
00287     int old_sp_loc;     /* stack pointer before call        */
00288     int first_arg_loc;
00289     NODE * op = (Oflag ? equiv_expr(p -> ap_operator) : p -> ap_operator);
00290     NODE * construction  =  op -> signature
00291                                -> fsig_construction;
00292     boolean slink_known; /* used only if construction is  */
00293                          /* known.  Indicates that e.p.   */
00294                          /* can be gotten by indirecting  */
00295                          /* through current static link.  */
00296     NODE * result_sig = p -> signature;
00297     NODE * op_sig = p -> ap_operator -> signature;
00298     long op_special = op -> signature -> fsig_special;
00299     boolean op_is_id = is_id(p -> ap_operator);
00300     boolean appl_impure = impure(op_sig);
00301     boolean op_impure = (appl_impure && !op_is_id)
00302                         || calls_put(p -> ap_operator);
00303     boolean reuse_ar;   /* This is a tail recursive call that allows */
00304                         /* reuse of callers activation record.       */
00305     boolean slink_needed;  /* Callee requires full a.r.  as parameter */
00306     boolean bogus_slink_ok; /* Callee will not look at its global env. */
00307                             /* pointer.                                */
00308     boolean direct_rec_call;  /* A direct tail recursive call to the same */
00309                               /* function construction                    */
00310     int Rlevel = Glevel; /* Real static nesting level.  We may need to fix */
00311                          /* up AR during tail calls, so we temporarily     */
00312                          /* change Glevel.                                 */
00313     int i;
00314 
00315 
00316     ASSERT( !last_expr || rloc == RL, "Gappl: bad last_expr value\n");
00317 
00318     if (is_int_const(p)) {
00319         extern long int_const_val;
00320 
00321         gen2(LDN, int_const_val, rloc);
00322         return;
00323     }
00324     /* Calculate number of arguments */
00325       argcount = 0;
00326       i = 0;
00327       maplist(s, p -> ap_args, {
00328         i++;
00329         if (!vacuous_arg(s -> signature)) {
00330             argcount = i;
00331         }
00332       });
00333     /* Handle some special operations */
00334       switch (special_tp(op_special)) {
00335         case ARRAY_VALUEOF:
00336           if (Vflag) {
00337               printf("Using fast array ValueOf inside %s\n",
00338                      Gcurrent -> fc_code_label);
00339           }
00340           /* Pass argument */
00341             {
00342                 int i = avail_loc++;
00343 
00344                 gen2(DCL, i, DCL_INT);
00345                 Gexpression(first(p -> ap_args), i, FALSE);
00346                 gen2(ARG, 1, i);
00347                 gen1(UDC, i);
00348             }
00349           genl(EXT, "_fast_Array_ValueOf");
00350           genl(LBA, "_fast_Array_ValueOf");
00351           gen1(CLC, 1);
00352           gen2(MOV, RL, rloc);
00353           return;
00354         case ARRAY_STD_NEW:
00355         case ARRAY_PTR_NEW:
00356           {
00357             long size_val = special_val(op_special);
00358 
00359             if (!Gpush_size(size_val, p -> ap_operator)) {
00360                     /* Note that passing op in the above is wrong, since */
00361                     /* it can lead to recomputing id bindings, and to id */
00362                     /* references that are not in my closure.            */
00363                 /* Can't find size */
00364                 break;
00365             }
00366             switch(special_tp(op_special)) {
00367               case ARRAY_STD_NEW:
00368                 if (Vflag) {
00369                     printf("Using fast standard array allocation inside %s\n",
00370                            Gcurrent -> fc_code_label);
00371                 }
00372                 genl(EXT, "_fast_Array_New");
00373                 gen3(HINT, AL, 0, 0);
00374                 genl(LBA, "_fast_Array_New");
00375                 gen1(CLC, 1);
00376                 break;
00377               case ARRAY_PTR_NEW:
00378                 if (Vflag) {
00379                     printf("Using fast pointer array allocation inside %s\n",
00380                            Gcurrent -> fc_code_label);
00381                 }
00382                 genl(EXT, "_fast_pArray_New");
00383                 gen3(HINT, AL, 0, 0);
00384                 genl(LBA, "_fast_pArray_New");
00385                 gen1(CLC, 1);
00386                 break;
00387             }
00388             gen2(MOV, RL, rloc);
00389             return;
00390           }
00391         case RECORD_VALUEOF:
00392         case PROD_VALUEOF:
00393         case ENUM_VALUEOF:
00394         case STD_VALUEOF:
00395           {
00396             NODE * arg1 = first(p -> ap_args);
00397             NODE * def;
00398 
00399             if (arg1 -> kind != LETTERID && arg1 -> kind != OPRID
00400                 || arg1 -> sel_type != NIL) {
00401                 break;
00402             }
00403             def = arg1 -> id_last_definition;
00404             if (def -> kind != DECLARATION) {
00405                 /* Compile it normally */
00406                 break;
00407             }
00408             if (def -> decl_special & VAR_IN_REG) {
00409               /* Just move it to the desired place */
00410                 gen2(MOV, def -> displacement /* var. location */, rloc);
00411             } else if (def -> decl_special & VAR_ON_STACK) {
00412               /* Handle common case directly to save compilation time */
00413                 if (def -> level == 0) {
00414                     gen3(LDI, GF, def -> displacement, rloc);
00415                 } else if (def -> level == Glevel) {
00416                     gen3(LDI, AR, def -> displacement, rloc);
00417                 } else {
00418                     break;
00419                 }
00420             } else {
00421                 break;
00422             }
00423             return;
00424           }
00425         case ARRAY_VAR_SUB:
00426           {
00427             int size = special_val(op_special);
00428             int i, j, k, m;
00429             NODE * arg1 = first(p -> ap_args);
00430             NODE * def;
00431 
00432             if (size == 0) {
00433                 /* Not statically known */
00434                 break;
00435             }
00436             if (arg1 -> kind != LETTERID && arg1 -> kind != OPRID
00437                 || arg1 -> sel_type != NIL) {
00438                 break;
00439             }
00440             def = arg1 -> id_last_definition;
00441             if (def -> kind != DECLARATION) {
00442                 /* Compile it normally */
00443                 break;
00444             }
00445             if (!(def -> decl_special & ARRAY_CONTIG)) {
00446                 break;
00447             }
00448 
00449             /* Save an indirection by indexing directly to the particular */
00450             /* array element, rather than going through the header.       */
00451                 i = avail_loc++;
00452                 j = avail_loc++;
00453                 k = avail_loc++;
00454                 m = avail_loc++;
00455                 gen2(DCL, i, DCL_ADDR);
00456                 gen2(DCL, j, DCL_INT);  /* subscript */
00457                 gen2(DCL, k, DCL_INT);  /* size (+1) */
00458                 Gexpression(second(p -> ap_args), j, FALSE);
00459                 /* Subscript check */
00460                   gen2(HINT, OPT, 12);
00461                   gen3(GEI, j, C0, TL);
00462                   genl(BRF, "1f");
00463                   gen2(DCL, m, DCL_INT);
00464                   gen2(LDN, size, m);
00465                   gen3(LTI, j, m, TL);
00466                   gen1(UDC, m);
00467                   genl(BRT, "2f");
00468                   genl(LBL, "1");
00469                   gen2(ARG, 1, j);
00470                   genl(EXT, "_Array_error");
00471                   genl(ERR, "_Array_error");
00472                   genl(LBL, "2");
00473                 gen2(LDN, size + 1, k);
00474                 Gident(first(p -> ap_args), i);
00475                 gen3(ADP, i, k, i);
00476                 gen3(ADP, i, j, rloc);
00477                 gen1(UDC, i);
00478                 gen1(UDC, j);
00479                 gen1(UDC, k);
00480             return;
00481           }
00482 
00483         case RECORD_ASSIGN:
00484         case PROD_ASSIGN:
00485         case ENUM_ASSIGN:
00486         case STD_ASSIGN:
00487           {
00488             NODE * arg1 = first(p -> ap_args);
00489             NODE * def;
00490 
00491             if (arg1 -> kind != LETTERID && arg1 -> kind != OPRID
00492                 || arg1 -> sel_type != NIL) {
00493                 break;
00494             }
00495             def = arg1 -> id_last_definition;
00496             if (def -> kind != DECLARATION
00497                 || !(def -> decl_special & VAR_IN_REG)) {
00498                 /* Compile it normally */
00499                 break;
00500             }
00501             /* specify l.h.s as destination location */
00502                 Gexpression(second(p -> ap_args),
00503                             def -> displacement, FALSE);
00504                         /* Note: OK to compile as tail-recursive call  */
00505                         /* if otherwise appropriate,                   */
00506                         /* since lhs of assignment is guaranteed dead. */
00507                         /* But this violates some consistency checks.  */
00508                 if (rloc != SK) {
00509                     gen2(MOV, def -> displacement, rloc);
00510                 }
00511             return;
00512           }
00513         case STD_PASSIGN:
00514         case STD_MASSIGN:
00515         case STD_TASSIGN:
00516           {
00517             NODE * arg1 = first(p -> ap_args);
00518             NODE * def;
00519 
00520             if (arg1 -> kind != LETTERID && arg1 -> kind != OPRID
00521                 || arg1 -> sel_type != NIL) {
00522                 break;
00523             }
00524             def = arg1 -> id_last_definition;
00525             if (def -> kind != DECLARATION
00526                 || !(def -> decl_special & VAR_IN_REG)) {
00527                 /* Compile it normally */
00528                 break;
00529             }
00530             {
00531                 int i = avail_loc++;
00532 
00533                 gen2(DCL, i, DCL_INT);
00534                 Gexpression(second(p -> ap_args), i, FALSE);
00535                 switch (special_tp(op_special)) {
00536                     case STD_PASSIGN:
00537                         gen3(ADI, def -> displacement, i, def -> displacement);
00538                         break;
00539                     case STD_MASSIGN:
00540                         gen3(SBI, def -> displacement, i, def -> displacement);
00541                         break;
00542                     case STD_TASSIGN:
00543                         gen3(MLI, def -> displacement, i, def -> displacement);
00544                         break;
00545                 }
00546                 if (rloc != SK) {
00547                     gen2(MOV, def -> displacement, rloc);
00548                 }
00549                 gen1(UDC, i);
00550             }
00551             return;
00552           }
00553       }
00554 
00555     /* determine type of calling sequence */
00556       in_line = (struct RIC_instr *)(op -> signature -> fsig_inline_code);
00557       if (in_line == NIL) {
00558         switch(result_sig -> kind) {
00559           case TYPESIGNATURE:
00560             stack_call = FALSE;
00561             break;
00562           case FUNCSIGNATURE:
00563             stack_call = FALSE;
00564             break;
00565           case VALSIGNATURE:
00566 #           ifdef DEBUG
00567               if (!has_sig(result_sig -> val_denotation)) {
00568                 dbgmsg("codegen: Missing res. type signature\n");
00569                 prtree(p);
00570                 abort();
00571               }
00572 #           endif
00573             stack_call = result_sig -> val_denotation
00574                          -> signature -> ts_simple_type;
00575             break;
00576           case VARSIGNATURE:
00577 #           ifdef DEBUG
00578              if (!has_sig(result_sig -> val_denotation)) {
00579               dbgmsg("codegen: Missing res. type signature\n");
00580               prtree(p);
00581               abort();
00582              }
00583 #           endif
00584             stack_call = result_sig -> var_denotation
00585                          -> signature -> ts_simple_type;
00586             break;
00587         }
00588         /* Check for an impure function */
00589             if (appl_impure) {
00590                 stack_call = FALSE;
00591             }
00592         /* Check for bad VAR parameters */
00593             maplist(q, p -> ap_args, {
00594                 NODE * sig = q -> signature;
00595                 if (sig -> kind == VARSIGNATURE) {
00596                     ASSERT (has_sig(sig -> var_denotation),
00597                       "Missing argument type signature");
00598                     if (!sig -> var_denotation -> signature
00599                              -> ts_simple_type) {
00600                         stack_call = FALSE;
00601                     }
00602                 }
00603 
00604             });
00605       }
00606       if (construction != NIL) {
00607         stack_call = stack_call
00608                      || (construction -> fc_complexity & NO_SL)
00609                      || (construction -> fc_complexity & NO_AR_REFS);
00610         test_closure = FALSE;
00611       }
00612     if (hflag) {
00613         stack_call = FALSE;
00614     }
00615     if (fflag && construction == NIL
00616         || Fflag && !(construction -> fc_complexity & NO_CALLCC)) {
00617         stack_call = FALSE;
00618         /* Otherwise we might deallocate the activation record */
00619         /* more than once.                                     */
00620     }
00621     if (in_line != NIL) {
00622       /* if it is impure and not id, evaluate operator for effect */
00623           if (op_impure) {
00624               if (Vflag) {
00625                 printf("Evaluating impure operator for effect: ");
00626                 unparse_file = stdout;
00627                 unparse(p -> ap_operator);
00628                 printf("\n\t(using in-line code for call)\n");
00629               }
00630             Gexpression (p -> ap_operator, SK, FALSE);
00631           }
00632       first_arg_loc = avail_loc;
00633       arg_loc = avail_loc = avail_loc + argcount;
00634       for (i = first_arg_loc; i < arg_loc; i++) {
00635         gen2(DCL, i, DCL_INT);
00636       }
00637       reg_ok = TRUE;
00638       maprlist_non_vacuous(p -> ap_args, Garg_expression);
00639       reg_ok = FALSE;
00640       /* write in-line expansion, after adjusting for VAR_IN_REG arguments */
00641       {
00642         struct RIC_instr * revised_in_line = in_line;
00643         struct RIC_instr * RIC_tmp;
00644         int argcnt = 1;
00645         NODE * argsig;
00646 
00647         if (Oflag) {
00648           maplist(s, p -> ap_args, {
00649             if ((s -> kind == LETTERID
00650                  || s -> kind == OPRID)
00651                 && s -> sel_type == NIL
00652                 && s -> id_last_definition -> kind == DECLARATION
00653                 && (s -> id_last_definition -> decl_special & VAR_IN_REG)) {
00654                 RIC_tmp = revised_in_line;
00655                 revised_in_line = unindirect(revised_in_line, argcnt,
00656                                              s -> id_last_definition
00657                                                -> displacement);
00658                 if (RIC_tmp != in_line) {
00659                     free_RIC(RIC_tmp);
00660                 }
00661             }
00662             argcnt ++;
00663           });
00664         }
00665         write_RIC_seq(Goutfile, revised_in_line, first_arg_loc, rloc);
00666         if (revised_in_line != in_line) {
00667           free_RIC(revised_in_line);
00668         }
00669       }
00670       for (i = first_arg_loc; i < first_arg_loc + argcount; i++) {
00671         gen1(UDC, i);
00672       }
00673     } else /* not in-line */ {
00674       boolean no_ar_ref_passed =
00675                          (Gcurrent -> fc_complexity & NO_AR_REFS)
00676                          || argcount == 0;
00677                          /* No reference to the current activation      */
00678                          /* record can conceivably be passed to callee. */
00679                          /* We should probably examine the arguments    */
00680                          /* to get more precise information.            */
00681       slink_needed = ((construction == NIL)
00682                       || ((construction -> fc_complexity & NO_SL) == 0));
00683       bogus_slink_ok = (construction != NIL &&
00684                         !(construction -> fc_complexity & SL_ACC));
00685                     /* Expecting full activation record.  Need to pass */
00686                     /* AR.  However global env. ptr is not used.       */
00687       direct_rec_call = (last_expr && (construction != NIL)
00688                         && (construction -> pre_num == Gcurrent -> pre_num)
00689                         && stack_call && no_ar_ref_passed
00690                         && (construction -> pre_num != 0)
00691                         && (sl_available == slink_needed));
00692       ASSERT(!direct_rec_call || (Gcurrent -> fc_complexity & DIR_REC),
00693              "Gappl: unexpected tail recursion\n");
00694       reuse_ar = direct_rec_call ||
00695                  last_expr && stack_call && no_ar_ref_passed
00696                            && (Gcurrent -> fc_complexity & NO_AR_REFS)
00697                            && construction != NIL
00698                            && (construction -> ar_size <= Gcurrent -> ar_size)
00699                            && sl_available && slink_needed
00700                            && (construction -> ar_static_level <=
00701                                Gcurrent     -> ar_static_level
00702                                || bogus_slink_ok);
00703         /* This is safe only if no refs to current ar can be preserved. */
00704         /* That means current a.r. is on stack, and can't be reused if  */
00705         /* heap a.r. is required.                                       */
00706         /* The last condition insures that the callee cannot reference  */
00707         /* the caller through the callers static link.                  */
00708       if (Vflag) {
00709         printf("Function %s calls ", Gcurrent -> fc_code_label);
00710         if (construction == NIL) {
00711             unparse_file = stdout;
00712             unparse(p -> ap_operator);
00713         } else {
00714             printf("%s", construction -> fc_code_label);
00715         }
00716         if (direct_rec_call) {
00717           printf(" tail recursively\n");
00718         } else if (reuse_ar) {
00719           printf(" with recycled stack a.r.\n");
00720         } else if (stack_call) {
00721           if (slink_needed) {
00722             printf(" with stack a.r.\n");
00723           } else {
00724             printf(" with partial a.r.\n");
00725           }
00726         } else if (test_closure) {
00727           printf(" with stack or heap a.r.\n");
00728         } else {
00729           printf(" with heap a.r.\n");
00730         }
00731       }
00732       if (slink_needed && !reuse_ar) {
00733           size_loc = avail_loc++;
00734           gen2(DCL, size_loc, DCL_INT);
00735       }
00736       if (construction != NIL) {
00737           slink_known = p -> ap_operator -> signature
00738                           -> fsig_slink_known;
00739           if ((construction -> fc_complexity & CP_GLOBALS)
00740               /* Non-locals are copied, need real environment */
00741               /* Note: CP_GLOBALS ==> closure will be built   */
00742               || (Gcurrent -> fc_complexity & CP_GLOBALS)
00743                  && construction -> ar_static_level > 1) {
00744               /* Need static link in current closure */
00745                   ASSERT((construction -> fc_complexity & NEED_CL)
00746                          || (!slink_needed) || bogus_slink_ok,
00747                          "Gappl: reference to nonexistent closure\n");
00748                   slink_known = FALSE;
00749           }
00750       }
00751       /* Evaluate operator if necessary */
00752         if (construction == NIL
00753            || (!slink_known && slink_needed && !bogus_slink_ok)) {
00754             fn_loc = avail_loc++;
00755             gen2(DCL, fn_loc, DCL_ADDR);
00756             Gexpression (p -> ap_operator, fn_loc, FALSE);
00757         } else if (op_impure) {
00758           /* evaluate operator for side effects */
00759             if (Vflag) {
00760                 printf("\t- Operator evaluated for effect\n");
00761             }
00762             Gexpression (p -> ap_operator, SK, FALSE);
00763         } else {
00764           /* May contain needed function construction */
00765             Gtraverse (p -> ap_operator);
00766         }
00767       /* Compute size of a.r. */
00768         if (!reuse_ar) {
00769           if (construction != NIL) {
00770             if (slink_needed) {
00771                 ASSERT2(construction -> ar_size > 0,
00772                         "function %X has bad ar size field\n",
00773                         construction);
00774                 gen2(LDN, construction -> ar_size, size_loc);
00775             } /* else we dont explicitly allocate */
00776           } else {
00777             gen3(LDI, fn_loc, FO_SIZE, size_loc);
00778           }
00779         }
00780       /* allocate activation record */
00781         if (reuse_ar) {
00782           if (sl_available) {
00783               int i = Glevel - Gcurrent -> ar_static_level;
00784 
00785               if (i > 0) {
00786                 /* Set ar_loc to the act. record for the entire function. */
00787                 ar_loc = avail_loc++;
00788                 gen2(DCL, ar_loc, DCL_ADDR);
00789                 gen3(LDI, AR, 0, ar_loc);
00790                 while (--i > 0) {
00791                     gen3(LDI, ar_loc, 0, ar_loc);
00792                 }
00793               } else {
00794                 ar_loc = AR;
00795               }
00796           } else {
00797               ar_loc = -1; /* garbage, shouldnt be used */
00798           }
00799         } else if (slink_needed) {
00800           ar_loc = avail_loc++;
00801           gen2(DCL, ar_loc, DCL_ADDR);
00802           if (stack_call) {
00803             if (construction == NIL) {
00804                 gen_abs(size_loc);
00805             }
00806             if (fflag) {
00807                 gen1(HINT, ONS);
00808                 gen2(ALH, size_loc, ar_loc);
00809             } else {
00810                 gen1(ALS, size_loc);
00811                 gen2(MOV, SP, ar_loc);
00812             }
00813           } else if (test_closure && !fflag) {
00814             old_sp_loc = avail_loc++;
00815             gen2(DCL, old_sp_loc, DCL_INT);
00816             gen2(MOV, SP, old_sp_loc);
00817             gen3(GEI, size_loc, C0, TL);
00818             genl(BRT, "1f");
00819             gen2(NGI, size_loc, size_loc);
00820             gen2(ALH, size_loc, ar_loc);
00821             genl(BR, "2f");
00822             genl(LBL, "1");
00823             gen1(ALS, size_loc);
00824             gen2(MOV, SP, ar_loc);
00825             genl(LBL, "2");
00826           } else {
00827             if (construction == NIL) {
00828                 gen_abs(size_loc);
00829             }
00830             gen2(ALH, size_loc, ar_loc);
00831           }
00832         }
00833       /* evaluate arguments and put them in activation record  or */
00834       /* pass them using ARG instructions  (in reverse order).    */
00835         if (! slink_needed || reuse_ar) {
00836           /* Evaluate all arguments before we clobber old a.r. */
00837           /* If we are not building an activation record, we   */
00838           /* need to do all evaluations first, so that ARG     */
00839           /* instructions appear before the correct call.      */
00840             int next_loc;
00841             int ar_offset = 1;
00842             int cur_arg_no;
00843 
00844             /* Grab locations for all args and declare them */
00845               first_arg_loc = avail_loc;
00846               next_loc = arg_loc = avail_loc = avail_loc + argcount;
00847               for (i = first_arg_loc; i < next_loc; i++) {
00848                 gen2(DCL, i, DCL_INT);
00849               }
00850             maprlist_non_vacuous(p -> ap_args, Garg_expression);
00851             /* Now stuff them into a.r. */
00852               if (slink_needed) {
00853                 for (i = first_arg_loc; i < next_loc; i++) {
00854                   gen3(STI, ar_loc, ar_offset, i);
00855                   ar_offset++;
00856                 }
00857               } else if (!reuse_ar) {
00858                 /* Pass them with ARG instructions */
00859                   cur_arg_no = argcount;
00860                   for (i = next_loc - 1; i >= first_arg_loc; i--) {
00861                     gen2(ARG, cur_arg_no--, i);
00862                   }
00863                   ASSERT(cur_arg_no == 0, "Appl: incorrect arg count");
00864               } else {
00865                 extern int first_param_loc;
00866 
00867                 /* This must be a call to the current function */
00868                 ASSERT(first_param_loc != 0,
00869                        "Appl: bad tail recursion\n");
00870                 for (i = 0; i < argcount; i++) {
00871                   gen2(MOV, first_arg_loc + i, first_param_loc + i);
00872                 }
00873                 ASSERT(argcount == Gcurrent -> ar_size - 1,
00874                        "Appl: bad arg count for tail recursion\n");
00875               }
00876             /* undeclare argument locations */
00877               for (i = first_arg_loc; i < next_loc; i++) {
00878                 gen1(UDC, i);
00879               }
00880         } else {
00881           heap_loc = ar_loc;
00882           heap_offset = argcount;
00883           maprlist_non_vacuous (p-> ap_args, Gheap_expression);
00884         }
00885       /* store static link */
00886         if (slink_needed) {
00887           if (bogus_slink_ok) {
00888               if (!stack_call) {
00889                 /* Avoid bogus references to heap objects */
00890                 gen3(STI, ar_loc, 0, UN);
00891               } else {
00892 #               ifdef DEBUG
00893                   gen3(STI, ar_loc, 0, UN);
00894 #               endif
00895               }
00896           } else if (construction == NIL || !slink_known) {
00897               i = avail_loc++;
00898               gen2(DCL, i, DCL_INT);
00899               gen3(LDI, fn_loc, FO_EP, i);
00900               gen3(STI, ar_loc, 0, i);
00901               gen1(UDC, i);
00902           } else {
00903             if (direct_rec_call) {
00904               /* It's already there */
00905             } else {
00906               int ep_loc;
00907                   /* name of loc used for a.r. pointer */
00908 
00909 #             ifdef DEBUG
00910                 if (Glevel < ((construction -> ar_static_level) - 1)) {
00911                   dbgmsg ("Negative level difference for function call\n");
00912                   fprintf (stderr, "Current: %d; Construction: %d; Application:\n",
00913                            Glevel, (construction -> ar_static_level));
00914                   unparse_file = stderr;
00915                   unparse(p);
00916                   fprintf(stderr, "\n");
00917                   abort(p);
00918                 }
00919 #             endif
00920               DISPLAY ( ep_loc, ((construction -> ar_static_level) - 1));
00921               gen3(STI, ar_loc, 0, ep_loc);
00922               UNDISPLAY(ep_loc);
00923             }
00924           }
00925         }
00926       /* Pass AR as the only argument.  Old value is implicitly saved */
00927       /* at the time of the call.                                     */
00928           if (slink_needed && !direct_rec_call) {
00929             gen2(ARG, 1, ar_loc);
00930           }
00931       /* Make the call */
00932           if (direct_rec_call) {
00933             /* Set up correct AR */
00934               if (Glevel != Gcurrent -> ar_static_level) {
00935                 gen2(MOV, ar_loc, AR);
00936               }
00937             if (slink_needed) {
00938                 strcpy(str_code_buf, "R");
00939             } else {
00940                 strcpy(str_code_buf, "RF");
00941             }
00942             strcat(str_code_buf, construction -> fc_code_label);
00943             genl(BR, str_code_buf);
00944           } else {
00945             if (construction != NIL) {
00946               if (!slink_needed) {
00947                 strcpy(str_code_buf, "F");
00948                 strcat(str_code_buf, construction -> fc_code_label);
00949                 genl(EXT, str_code_buf);
00950 #               ifdef UNDEFINED
00951                 /* We assume that CLC can't result in CALLCC call */
00952                   if (Nflag || construction -> fc_complexity & NO_CALLCC) {
00953                     gen1(HINT, NSC);
00954                   }
00955 #               endif
00956                 genl(LBA, str_code_buf);
00957                 gen1(CLC, argcount);
00958               } else {
00959                 genl(EXT, construction -> fc_code_label);
00960                 if (Nflag || construction -> fc_complexity & NO_CALLCC) {
00961                     gen1(HINT, NSC);
00962                 }
00963                 genl(CLL, construction -> fc_code_label);
00964               }
00965             } else /* NIL construction */ {
00966               if (Nflag) {
00967                 gen1(HINT, NSC);
00968               }
00969               gen2(CLI, fn_loc, FO_IP);
00970             }
00971           }
00972       /* remove activation record */
00973           if (reuse_ar) {
00974             if (sl_available && ar_loc != AR) {
00975               gen1(UDC, ar_loc);
00976             }
00977           } else {
00978             if (stack_call) {
00979               if (slink_needed) /* otherwise CLC takes care of it */ {
00980                 if (fflag) {
00981                   /* AR is on heap, but we can explicitly deallocate */
00982                     gen1(HINT, ONS);
00983                     if (construction != NIL) {
00984                       int sz = construction -> ar_size;
00985 
00986                       if (sz < 0) { sz = -sz; }
00987                       gen3(HINT, DEA, ar_loc, construction -> ar_size);
00988                     } else {
00989                       gen3(HINT, DEA, ar_loc, 0);
00990                     }
00991                 } else {
00992                     gen3(ADP, SP, size_loc, SP);
00993                 }
00994               }
00995             } else if (test_closure && !fflag) {
00996               gen2(MOV, old_sp_loc, SP);
00997               gen1(UDC, old_sp_loc);
00998             }
00999             /* In the heap case there's nothing to do */
01000             if (slink_needed) {
01001                 gen1(UDC, ar_loc);
01002             }
01003           }
01004       /* undeclare temporaries */
01005         if (slink_needed && ! reuse_ar) {
01006             gen1(UDC, size_loc);
01007         }
01008         if (construction == NIL
01009             || (slink_needed && !slink_known && !bogus_slink_ok)) {
01010           gen1(UDC, fn_loc);
01011         }
01012       /* Put result in its place */
01013         if (rloc != RL) {
01014             gen2(MOV, RL, rloc);
01015         }
01016     }  /* end not in-line */
01017 }
01018 
01019 /*
01020  *   Generate an ARG 1 instr with the size of the array corresponding to the
01021  * type from which op is selected.  The size may either be given explicitly,
01022  * or an attempt will be made to infer it from the operator.
01023  *   Returns TRUE if it succeeded, FALSE otherwise.
01024  */
01025 boolean Gpush_size(size, op)
01026 int size;
01027 NODE * op;
01028 {
01029     NODE * sel_type_sig;
01030     NODE * size_sig;
01031     NODE * size_appl;
01032     NODE * size_id;
01033     extern NODE * id_size;
01034 
01035     if (size == 0) {
01036         /* Try to put size of array rep on top of the stack */
01037         /* using size function of the array type            */
01038           if (op -> kind != LETTERID || op -> sel_type == NIL) {
01039               return(FALSE);
01040           }
01041           sel_type_sig = op -> sel_type -> signature;
01042           size_sig = getcomp(sel_type_sig, id_size, NIL, NIL,
01043                              NIL, NIL, NIL, FALSE);
01044           if (size_sig == NIL || special_tp(size_sig -> fsig_special)
01045                                  != ARRAY_SIZE) {
01046               /* No appropriate size operation */
01047               return(FALSE);
01048           }
01049           /* Construct size application and generate code for it */
01050             size_id = copynode(id_size);
01051             initfld(&(size_id -> sel_type), op -> sel_type);
01052             size_id -> id_def_found = TRUE;
01053             size_appl = mknode(APPLICATION, size_id, emptylist());
01054             checksigs(size_appl, FALSE);
01055             {
01056                 int i = avail_loc++;
01057 
01058                 gen2(DCL, i, DCL_INT);
01059                 Gappl(size_appl, i, FALSE);
01060                 gen2(ARG, 1, i);
01061                 gen1(UDC, i);
01062             }
01063     } else {
01064       /* Pass a constant */
01065         int i = avail_loc++;
01066 
01067         gen2(DCL, i, DCL_INT);
01068         gen2(LDN, size, i);
01069         gen2(ARG, 1, i);
01070         gen1(UDC, i);
01071     }
01072     return(TRUE);
01073 }

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