1745Speter /* Copyright (c) 1979 Regents of the University of California */ 2745Speter 3*12902Speter static char sccsid[] = "@(#)call.c 1.24 06/03/83"; 4745Speter 5745Speter #include "whoami.h" 6745Speter #include "0.h" 7745Speter #include "tree.h" 8745Speter #include "opcode.h" 9745Speter #include "objfmt.h" 10745Speter #ifdef PC 11745Speter # include "pc.h" 12745Speter # include "pcops.h" 13745Speter #endif PC 1411331Speter #include "tmps.h" 15745Speter 16745Speter /* 17745Speter * Call generates code for calls to 18745Speter * user defined procedures and functions 19745Speter * and is called by proc and funccod. 20745Speter * P is the result of the lookup 21745Speter * of the procedure/function symbol, 22745Speter * and porf is PROC or FUNC. 23745Speter * Psbn is the block number of p. 243065Smckusic * 253065Smckusic * the idea here is that regular scalar functions are just called, 263065Smckusic * while structure functions and formal functions have their results 273065Smckusic * stored in a temporary after the call. 283065Smckusic * structure functions do this because they return pointers 293065Smckusic * to static results, so we copy the static 303065Smckusic * and return a pointer to the copy. 313065Smckusic * formal functions do this because we have to save the result 323065Smckusic * around a call to the runtime routine which restores the display, 333065Smckusic * so we can't just leave the result lying around in registers. 343886Speter * formal calls save the address of the descriptor in a local 353886Speter * temporary, so it can be addressed for the call which restores 363886Speter * the display (FRTN). 373426Speter * calls to formal parameters pass the formal as a hidden argument 383426Speter * to a special entry point for the formal call. 393426Speter * [this is somewhat dependent on the way arguments are addressed.] 403065Smckusic * so PROCs and scalar FUNCs look like 413065Smckusic * p(...args...) 423065Smckusic * structure FUNCs look like 433065Smckusic * (temp = p(...args...),&temp) 443065Smckusic * formal FPROCs look like 454014Smckusic * ( t=p,( t -> entryaddr )(...args...,t,s),FRTN(t,s)) 463065Smckusic * formal scalar FFUNCs look like 474014Smckusic * ( t=p,temp=( t -> entryaddr )(...args...,t,s),FRTN(t,s),temp) 483065Smckusic * formal structure FFUNCs look like 494014Smckusic * (t=p,temp = ( t -> entryaddr )(...args...,t,s),FRTN(t,s),&temp) 50745Speter */ 51745Speter struct nl * 52745Speter call(p, argv, porf, psbn) 53745Speter struct nl *p; 54745Speter int *argv, porf, psbn; 55745Speter { 56745Speter register struct nl *p1, *q; 57745Speter int *r; 583065Smckusic struct nl *p_type_class = classify( p -> type ); 593297Smckusic bool chk = TRUE; 604014Smckusic struct nl *savedispnp; /* temporary to hold saved display */ 61745Speter # ifdef PC 623065Smckusic long p_p2type = p2type( p ); 633065Smckusic long p_type_p2type = p2type( p -> type ); 643065Smckusic bool noarguments; 653065Smckusic long calltype; /* type of the call */ 663065Smckusic /* 673065Smckusic * these get used if temporaries and structures are used 683065Smckusic */ 693824Speter struct nl *tempnlp; 703065Smckusic long temptype; /* type of the temporary */ 713065Smckusic long p_type_width; 723065Smckusic long p_type_align; 733362Speter char extname[ BUFSIZ ]; 743886Speter struct nl *tempdescrp; 75745Speter # endif PC 76745Speter 774014Smckusic if (p->class == FFUNC || p->class == FPROC) { 784014Smckusic /* 794014Smckusic * allocate space to save the display for formal calls 804014Smckusic */ 814014Smckusic savedispnp = tmpalloc( sizeof display , NIL , NOREG ); 824014Smckusic } 83745Speter # ifdef OBJ 843426Speter if (p->class == FFUNC || p->class == FPROC) { 854014Smckusic put(2, O_LV | cbn << 8 + INDX , 864014Smckusic (int) savedispnp -> value[ NL_OFFS ] ); 873359Smckusic put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]); 883426Speter } 893426Speter if (porf == FUNC) { 90745Speter /* 91745Speter * Push some space 92745Speter * for the function return type 93745Speter */ 943063Smckusic put(2, O_PUSH, leven(-lwidth(p->type))); 953426Speter } 96745Speter # endif OBJ 97745Speter # ifdef PC 983065Smckusic /* 993886Speter * if this is a formal call, 1003886Speter * stash the address of the descriptor 1013886Speter * in a temporary so we can find it 1023886Speter * after the FCALL for the call to FRTN 1033886Speter */ 1043886Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 1053886Speter tempdescrp = tmpalloc(sizeof( struct formalrtn *) , NIL , 1063886Speter REGOK ); 1073886Speter putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 1083886Speter tempdescrp -> extra_flags , P2PTR|P2STRTY ); 1093886Speter putRV( 0 , psbn , p -> value[ NL_OFFS ] , 1103886Speter p -> extra_flags , P2PTR|P2STRTY ); 1113886Speter putop( P2ASSIGN , P2PTR | P2STRTY ); 1123886Speter } 1133886Speter /* 1143065Smckusic * if we have to store a temporary, 1153065Smckusic * temptype will be its type, 1163065Smckusic * otherwise, it's P2UNDEF. 1173065Smckusic */ 1183065Smckusic temptype = P2UNDEF; 1193065Smckusic calltype = P2INT; 120745Speter if ( porf == FUNC ) { 1213065Smckusic p_type_width = width( p -> type ); 1223065Smckusic switch( p_type_class ) { 123745Speter case TSTR: 124745Speter case TSET: 125745Speter case TREC: 126745Speter case TFILE: 127745Speter case TARY: 1283065Smckusic calltype = temptype = P2STRTY; 1293065Smckusic p_type_align = align( p -> type ); 1303065Smckusic break; 1313065Smckusic default: 1323065Smckusic if ( p -> class == FFUNC ) { 1333065Smckusic calltype = temptype = p2type( p -> type ); 134745Speter } 1353065Smckusic break; 136745Speter } 1373065Smckusic if ( temptype != P2UNDEF ) { 1383824Speter tempnlp = tmpalloc(p_type_width, p -> type, NOREG); 1393065Smckusic /* 1403065Smckusic * temp 1413065Smckusic * for (temp = ... 1423065Smckusic */ 1433824Speter putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 1443824Speter tempnlp -> extra_flags , temptype ); 1453065Smckusic } 146745Speter } 1471195Speter switch ( p -> class ) { 1481195Speter case FUNC: 1491195Speter case PROC: 1503065Smckusic /* 1513065Smckusic * ... p( ... 1523065Smckusic */ 1533372Speter sextname( extname , p -> symbol , BLOCKNO(p -> nl_block) ); 1543362Speter putleaf( P2ICON , 0 , 0 , p2type( p ) , extname ); 1551195Speter break; 1561195Speter case FFUNC: 1571195Speter case FPROC: 1583886Speter 1591195Speter /* 1603886Speter * ... ( t -> entryaddr )( ... 1611195Speter */ 162*12902Speter /* the descriptor */ 1633886Speter putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 1643886Speter tempdescrp -> extra_flags , P2PTR | P2STRTY ); 165*12902Speter /* the entry address within the descriptor */ 1663426Speter if ( FENTRYOFFSET != 0 ) { 1673426Speter putleaf( P2ICON , FENTRYOFFSET , 0 , P2INT , 0 ); 1683426Speter putop( P2PLUS , 1693426Speter ADDTYPE( 1703426Speter ADDTYPE( ADDTYPE( p2type( p ) , P2FTN ) , 1713426Speter P2PTR ) , 1723426Speter P2PTR ) ); 1733426Speter } 174*12902Speter /* 175*12902Speter * indirect to fetch the formal entry address 176*12902Speter * with the result type of the routine. 177*12902Speter */ 178*12902Speter if (p -> class == FFUNC) { 179*12902Speter putop( P2UNARY P2MUL , 180*12902Speter ADDTYPE(ADDTYPE(p2type(p -> type), P2FTN), 181*12902Speter P2PTR)); 182*12902Speter } else { 183*12902Speter /* procedures are int returning functions */ 184*12902Speter putop( P2UNARY P2MUL , 185*12902Speter ADDTYPE(ADDTYPE(P2INT, P2FTN), P2PTR)); 186*12902Speter } 1871195Speter break; 1881195Speter default: 1891195Speter panic("call class"); 190745Speter } 1913065Smckusic noarguments = TRUE; 192745Speter # endif PC 193745Speter /* 194745Speter * Loop and process each of 195745Speter * arguments to the proc/func. 1963065Smckusic * ... ( ... args ... ) ... 197745Speter */ 1983297Smckusic for (p1 = plist(p); p1 != NIL; p1 = p1->chain) { 1993297Smckusic if (argv == NIL) { 2003297Smckusic error("Not enough arguments to %s", p->symbol); 2013297Smckusic return (NIL); 2023297Smckusic } 2033297Smckusic switch (p1->class) { 2043297Smckusic case REF: 2053297Smckusic /* 2063297Smckusic * Var parameter 2073297Smckusic */ 2083297Smckusic r = argv[1]; 2093297Smckusic if (r != NIL && r[0] != T_VAR) { 2103297Smckusic error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol); 2113361Speter chk = FALSE; 2123297Smckusic break; 2133297Smckusic } 2143372Speter q = lvalue( (int *) argv[1], MOD | ASGN , LREQ ); 2153297Smckusic if (q == NIL) { 2163297Smckusic chk = FALSE; 2173297Smckusic break; 2183297Smckusic } 2193297Smckusic if (q != p1->type) { 2203297Smckusic error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol); 2213361Speter chk = FALSE; 2223297Smckusic break; 2233297Smckusic } 2243297Smckusic break; 2253297Smckusic case VAR: 2263297Smckusic /* 2273297Smckusic * Value parameter 2283297Smckusic */ 229745Speter # ifdef OBJ 2303297Smckusic q = rvalue(argv[1], p1->type , RREQ ); 231745Speter # endif OBJ 232745Speter # ifdef PC 2333297Smckusic /* 2343297Smckusic * structure arguments require lvalues, 2353297Smckusic * scalars use rvalue. 2363297Smckusic */ 2373297Smckusic switch( classify( p1 -> type ) ) { 2383297Smckusic case TFILE: 2393297Smckusic case TARY: 2403297Smckusic case TREC: 2413297Smckusic case TSET: 2423297Smckusic case TSTR: 24310365Smckusick q = stkrval( argv[1] , p1 -> type , LREQ ); 244745Speter break; 2453297Smckusic case TINT: 2463297Smckusic case TSCAL: 2473297Smckusic case TBOOL: 2483297Smckusic case TCHAR: 2493297Smckusic precheck( p1 -> type , "_RANG4" , "_RSNG4" ); 25010365Smckusick q = stkrval( argv[1] , p1 -> type , RREQ ); 25110667Speter postcheck(p1 -> type, nl+T4INT); 252745Speter break; 25310365Smckusick case TDOUBLE: 25410365Smckusick q = stkrval( argv[1] , p1 -> type , RREQ ); 25510365Smckusick sconv(p2type(q), P2DOUBLE); 25610365Smckusick break; 2573297Smckusic default: 2583297Smckusic q = rvalue( argv[1] , p1 -> type , RREQ ); 2593297Smckusic break; 260745Speter } 2613297Smckusic # endif PC 2623297Smckusic if (q == NIL) { 2633297Smckusic chk = FALSE; 2643297Smckusic break; 2653297Smckusic } 2663297Smckusic if (incompat(q, p1->type, argv[1])) { 2673297Smckusic cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol); 2683361Speter chk = FALSE; 2693297Smckusic break; 2703297Smckusic } 271745Speter # ifdef OBJ 2723297Smckusic if (isa(p1->type, "bcsi")) 2733297Smckusic rangechk(p1->type, q); 2743297Smckusic if (q->class != STR) 2753297Smckusic convert(q, p1->type); 276745Speter # endif OBJ 277745Speter # ifdef PC 2783297Smckusic switch( classify( p1 -> type ) ) { 2793297Smckusic case TFILE: 2803297Smckusic case TARY: 2813297Smckusic case TREC: 2823297Smckusic case TSET: 2833297Smckusic case TSTR: 2843297Smckusic putstrop( P2STARG 2853297Smckusic , p2type( p1 -> type ) 2863297Smckusic , lwidth( p1 -> type ) 2873297Smckusic , align( p1 -> type ) ); 2883297Smckusic } 2891195Speter # endif PC 2903297Smckusic break; 2913297Smckusic case FFUNC: 2921195Speter /* 2933297Smckusic * function parameter 2941195Speter */ 2953297Smckusic q = flvalue( (int *) argv[1] , p1 ); 2963297Smckusic chk = (chk && fcompat(q, p1)); 2973297Smckusic break; 2983297Smckusic case FPROC: 2991195Speter /* 3003297Smckusic * procedure parameter 3011195Speter */ 3023297Smckusic q = flvalue( (int *) argv[1] , p1 ); 3033297Smckusic chk = (chk && fcompat(q, p1)); 3043297Smckusic break; 3053297Smckusic default: 3063297Smckusic panic("call"); 3071195Speter } 3083297Smckusic # ifdef PC 3093297Smckusic /* 3103297Smckusic * if this is the nth (>1) argument, 3113297Smckusic * hang it on the left linear list of arguments 3123297Smckusic */ 3133297Smckusic if ( noarguments ) { 3143297Smckusic noarguments = FALSE; 3153297Smckusic } else { 3163297Smckusic putop( P2LISTOP , P2INT ); 3173297Smckusic } 3183297Smckusic # endif PC 3193297Smckusic argv = argv[2]; 320745Speter } 3213297Smckusic if (argv != NIL) { 3223297Smckusic error("Too many arguments to %s", p->symbol); 3233297Smckusic rvlist(argv); 3243297Smckusic return (NIL); 3253297Smckusic } 3263297Smckusic if (chk == FALSE) 3273297Smckusic return NIL; 328745Speter # ifdef OBJ 3291195Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 3303359Smckusic put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]); 3314014Smckusic put(2, O_LV | cbn << 8 + INDX , 3324014Smckusic (int) savedispnp -> value[ NL_OFFS ] ); 3333297Smckusic put(1, O_FCALL); 3343063Smckusic put(2, O_FRTN, even(width(p->type))); 3351195Speter } else { 3367916Smckusick put(2, O_CALL | psbn << 8, (long)p->value[NL_ENTLOC]); 3371195Speter } 338745Speter # endif OBJ 339745Speter # ifdef PC 3403065Smckusic /* 3413426Speter * for formal calls: add the hidden argument 3423426Speter * which is the formal struct describing the 3433426Speter * environment of the routine. 3443426Speter * and the argument which is the address of the 3453426Speter * space into which to save the display. 3463426Speter */ 3473426Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 3483886Speter putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 3493886Speter tempdescrp -> extra_flags , P2PTR|P2STRTY ); 3503426Speter if ( !noarguments ) { 3513426Speter putop( P2LISTOP , P2INT ); 3523426Speter } 3533426Speter noarguments = FALSE; 3544014Smckusic putLV( 0 , cbn , savedispnp -> value[ NL_OFFS ] , 3554014Smckusic savedispnp -> extra_flags , P2PTR | P2STRTY ); 3564014Smckusic putop( P2LISTOP , P2INT ); 3573426Speter } 3583426Speter /* 3593065Smckusic * do the actual call: 3603065Smckusic * either ... p( ... ) ... 3613886Speter * or ... ( t -> entryaddr )( ... ) ... 3623065Smckusic * and maybe an assignment. 3633065Smckusic */ 364745Speter if ( porf == FUNC ) { 3653065Smckusic switch ( p_type_class ) { 366745Speter case TBOOL: 367745Speter case TCHAR: 368745Speter case TINT: 369745Speter case TSCAL: 370745Speter case TDOUBLE: 371745Speter case TPTR: 3723065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , 3733065Smckusic p_type_p2type ); 3743065Smckusic if ( p -> class == FFUNC ) { 3753065Smckusic putop( P2ASSIGN , p_type_p2type ); 376745Speter } 377745Speter break; 378745Speter default: 3793065Smckusic putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ), 3803065Smckusic ADDTYPE( p_type_p2type , P2PTR ) , 3813065Smckusic p_type_width , p_type_align ); 38211855Speter putstrop(P2STASG, ADDTYPE(p_type_p2type, P2PTR), 38311855Speter lwidth(p -> type), align(p -> type)); 384745Speter break; 385745Speter } 386745Speter } else { 3873065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT ); 3883065Smckusic } 3893065Smckusic /* 3903886Speter * ( t=p , ... , FRTN( t ) ... 3913065Smckusic */ 3923065Smckusic if ( p -> class == FFUNC || p -> class == FPROC ) { 3933886Speter putop( P2COMOP , P2INT ); 3943065Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , 3953065Smckusic "_FRTN" ); 3963886Speter putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 3973886Speter tempdescrp -> extra_flags , P2PTR | P2STRTY ); 3984014Smckusic putLV( 0 , cbn , savedispnp -> value[ NL_OFFS ] , 3994014Smckusic savedispnp -> extra_flags , P2PTR | P2STRTY ); 4004014Smckusic putop( P2LISTOP , P2INT ); 4013065Smckusic putop( P2CALL , P2INT ); 4023065Smckusic putop( P2COMOP , P2INT ); 4033065Smckusic } 4043065Smckusic /* 4053065Smckusic * if required: 4063065Smckusic * either ... , temp ) 4073065Smckusic * or ... , &temp ) 4083065Smckusic */ 4093065Smckusic if ( porf == FUNC && temptype != P2UNDEF ) { 4103065Smckusic if ( temptype != P2STRTY ) { 4113824Speter putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 4123824Speter tempnlp -> extra_flags , p_type_p2type ); 413745Speter } else { 4143824Speter putLV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 4153824Speter tempnlp -> extra_flags , p_type_p2type ); 416745Speter } 4173065Smckusic putop( P2COMOP , P2INT ); 4183065Smckusic } 4193065Smckusic if ( porf == PROC ) { 420745Speter putdot( filename , line ); 421745Speter } 422745Speter # endif PC 423745Speter return (p->type); 424745Speter } 425745Speter 426745Speter rvlist(al) 427745Speter register int *al; 428745Speter { 429745Speter 430745Speter for (; al != NIL; al = al[2]) 431745Speter rvalue( (int *) al[1], NLNIL , RREQ ); 432745Speter } 4333297Smckusic 4343297Smckusic /* 4353297Smckusic * check that two function/procedure namelist entries are compatible 4363297Smckusic */ 4373297Smckusic bool 4383297Smckusic fcompat( formal , actual ) 4393297Smckusic struct nl *formal; 4403297Smckusic struct nl *actual; 4413297Smckusic { 4423297Smckusic register struct nl *f_chain; 4433297Smckusic register struct nl *a_chain; 4443297Smckusic bool compat = TRUE; 4453297Smckusic 4463297Smckusic if ( formal == NIL || actual == NIL ) { 4473297Smckusic return FALSE; 4483297Smckusic } 4493297Smckusic for (a_chain = plist(actual), f_chain = plist(formal); 4503297Smckusic f_chain != NIL; 4513297Smckusic f_chain = f_chain->chain, a_chain = a_chain->chain) { 4523297Smckusic if (a_chain == NIL) { 4533297Smckusic error("%s %s declared on line %d has more arguments than", 4543297Smckusic parnam(formal->class), formal->symbol, 4553297Smckusic linenum(formal)); 4563297Smckusic cerror("%s %s declared on line %d", 4573297Smckusic parnam(actual->class), actual->symbol, 4583297Smckusic linenum(actual)); 4593297Smckusic return FALSE; 4603297Smckusic } 4613297Smckusic if ( a_chain -> class != f_chain -> class ) { 4623297Smckusic error("%s parameter %s of %s declared on line %d is not identical", 4633297Smckusic parnam(f_chain->class), f_chain->symbol, 4643297Smckusic formal->symbol, linenum(formal)); 4653297Smckusic cerror("with %s parameter %s of %s declared on line %d", 4663297Smckusic parnam(a_chain->class), a_chain->symbol, 4673297Smckusic actual->symbol, linenum(actual)); 4683297Smckusic compat = FALSE; 4693297Smckusic } else if (a_chain->class == FFUNC || a_chain->class == FPROC) { 4703297Smckusic compat = (compat && fcompat(f_chain, a_chain)); 4713297Smckusic } 4723297Smckusic if ((a_chain->class != FPROC && f_chain->class != FPROC) && 4733297Smckusic (a_chain->type != f_chain->type)) { 4743297Smckusic error("Type of %s parameter %s of %s declared on line %d is not identical", 4753297Smckusic parnam(f_chain->class), f_chain->symbol, 4763297Smckusic formal->symbol, linenum(formal)); 4773297Smckusic cerror("to type of %s parameter %s of %s declared on line %d", 4783297Smckusic parnam(a_chain->class), a_chain->symbol, 4793297Smckusic actual->symbol, linenum(actual)); 4803297Smckusic compat = FALSE; 4813297Smckusic } 4823297Smckusic } 4833297Smckusic if (a_chain != NIL) { 4843297Smckusic error("%s %s declared on line %d has fewer arguments than", 4853297Smckusic parnam(formal->class), formal->symbol, 4863297Smckusic linenum(formal)); 4873297Smckusic cerror("%s %s declared on line %d", 4883297Smckusic parnam(actual->class), actual->symbol, 4893297Smckusic linenum(actual)); 4903297Smckusic return FALSE; 4913297Smckusic } 4923297Smckusic return compat; 4933297Smckusic } 4943297Smckusic 4953297Smckusic char * 4963297Smckusic parnam(nltype) 4973297Smckusic int nltype; 4983297Smckusic { 4993297Smckusic switch(nltype) { 5003297Smckusic case REF: 5013297Smckusic return "var"; 5023297Smckusic case VAR: 5033297Smckusic return "value"; 5043297Smckusic case FUNC: 5053297Smckusic case FFUNC: 5063297Smckusic return "function"; 5073297Smckusic case PROC: 5083297Smckusic case FPROC: 5093297Smckusic return "procedure"; 5103297Smckusic default: 5113297Smckusic return "SNARK"; 5123297Smckusic } 5133297Smckusic } 5143297Smckusic 5153297Smckusic plist(p) 5163297Smckusic struct nl *p; 5173297Smckusic { 5183297Smckusic switch (p->class) { 5193297Smckusic case FFUNC: 5203297Smckusic case FPROC: 5213297Smckusic return p->ptr[ NL_FCHAIN ]; 5223297Smckusic case PROC: 5233297Smckusic case FUNC: 5243297Smckusic return p->chain; 5253297Smckusic default: 5263297Smckusic panic("plist"); 5273297Smckusic } 5283297Smckusic } 5293297Smckusic 5303297Smckusic linenum(p) 5313297Smckusic struct nl *p; 5323297Smckusic { 5333297Smckusic if (p->class == FUNC) 5343297Smckusic return p->ptr[NL_FVAR]->value[NL_LINENO]; 5353297Smckusic return p->value[NL_LINENO]; 5363297Smckusic } 537