1745Speter /* Copyright (c) 1979 Regents of the University of California */ 2745Speter 3*10365Smckusick static char sccsid[] = "@(#)call.c 1.20 01/17/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 14745Speter 15745Speter /* 16745Speter * Call generates code for calls to 17745Speter * user defined procedures and functions 18745Speter * and is called by proc and funccod. 19745Speter * P is the result of the lookup 20745Speter * of the procedure/function symbol, 21745Speter * and porf is PROC or FUNC. 22745Speter * Psbn is the block number of p. 233065Smckusic * 243065Smckusic * the idea here is that regular scalar functions are just called, 253065Smckusic * while structure functions and formal functions have their results 263065Smckusic * stored in a temporary after the call. 273065Smckusic * structure functions do this because they return pointers 283065Smckusic * to static results, so we copy the static 293065Smckusic * and return a pointer to the copy. 303065Smckusic * formal functions do this because we have to save the result 313065Smckusic * around a call to the runtime routine which restores the display, 323065Smckusic * so we can't just leave the result lying around in registers. 333886Speter * formal calls save the address of the descriptor in a local 343886Speter * temporary, so it can be addressed for the call which restores 353886Speter * the display (FRTN). 363426Speter * calls to formal parameters pass the formal as a hidden argument 373426Speter * to a special entry point for the formal call. 383426Speter * [this is somewhat dependent on the way arguments are addressed.] 393065Smckusic * so PROCs and scalar FUNCs look like 403065Smckusic * p(...args...) 413065Smckusic * structure FUNCs look like 423065Smckusic * (temp = p(...args...),&temp) 433065Smckusic * formal FPROCs look like 444014Smckusic * ( t=p,( t -> entryaddr )(...args...,t,s),FRTN(t,s)) 453065Smckusic * formal scalar FFUNCs look like 464014Smckusic * ( t=p,temp=( t -> entryaddr )(...args...,t,s),FRTN(t,s),temp) 473065Smckusic * formal structure FFUNCs look like 484014Smckusic * (t=p,temp = ( t -> entryaddr )(...args...,t,s),FRTN(t,s),&temp) 49745Speter */ 50745Speter struct nl * 51745Speter call(p, argv, porf, psbn) 52745Speter struct nl *p; 53745Speter int *argv, porf, psbn; 54745Speter { 55745Speter register struct nl *p1, *q; 56745Speter int *r; 573065Smckusic struct nl *p_type_class = classify( p -> type ); 583297Smckusic bool chk = TRUE; 594014Smckusic struct nl *savedispnp; /* temporary to hold saved display */ 60745Speter # ifdef PC 613065Smckusic long p_p2type = p2type( p ); 623065Smckusic long p_type_p2type = p2type( p -> type ); 633065Smckusic bool noarguments; 643065Smckusic long calltype; /* type of the call */ 653065Smckusic /* 663065Smckusic * these get used if temporaries and structures are used 673065Smckusic */ 683824Speter struct nl *tempnlp; 693065Smckusic long temptype; /* type of the temporary */ 703065Smckusic long p_type_width; 713065Smckusic long p_type_align; 723362Speter char extname[ BUFSIZ ]; 733886Speter struct nl *tempdescrp; 74745Speter # endif PC 75745Speter 764014Smckusic if (p->class == FFUNC || p->class == FPROC) { 774014Smckusic /* 784014Smckusic * allocate space to save the display for formal calls 794014Smckusic */ 804014Smckusic savedispnp = tmpalloc( sizeof display , NIL , NOREG ); 814014Smckusic } 82745Speter # ifdef OBJ 833426Speter if (p->class == FFUNC || p->class == FPROC) { 844014Smckusic put(2, O_LV | cbn << 8 + INDX , 854014Smckusic (int) savedispnp -> value[ NL_OFFS ] ); 863359Smckusic put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]); 873426Speter } 883426Speter if (porf == FUNC) { 89745Speter /* 90745Speter * Push some space 91745Speter * for the function return type 92745Speter */ 933063Smckusic put(2, O_PUSH, leven(-lwidth(p->type))); 943426Speter } 95745Speter # endif OBJ 96745Speter # ifdef PC 973065Smckusic /* 983886Speter * if this is a formal call, 993886Speter * stash the address of the descriptor 1003886Speter * in a temporary so we can find it 1013886Speter * after the FCALL for the call to FRTN 1023886Speter */ 1033886Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 1043886Speter tempdescrp = tmpalloc(sizeof( struct formalrtn *) , NIL , 1053886Speter REGOK ); 1063886Speter putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 1073886Speter tempdescrp -> extra_flags , P2PTR|P2STRTY ); 1083886Speter putRV( 0 , psbn , p -> value[ NL_OFFS ] , 1093886Speter p -> extra_flags , P2PTR|P2STRTY ); 1103886Speter putop( P2ASSIGN , P2PTR | P2STRTY ); 1113886Speter } 1123886Speter /* 1133065Smckusic * if we have to store a temporary, 1143065Smckusic * temptype will be its type, 1153065Smckusic * otherwise, it's P2UNDEF. 1163065Smckusic */ 1173065Smckusic temptype = P2UNDEF; 1183065Smckusic calltype = P2INT; 119745Speter if ( porf == FUNC ) { 1203065Smckusic p_type_width = width( p -> type ); 1213065Smckusic switch( p_type_class ) { 122745Speter case TSTR: 123745Speter case TSET: 124745Speter case TREC: 125745Speter case TFILE: 126745Speter case TARY: 1273065Smckusic calltype = temptype = P2STRTY; 1283065Smckusic p_type_align = align( p -> type ); 1293065Smckusic break; 1303065Smckusic default: 1313065Smckusic if ( p -> class == FFUNC ) { 1323065Smckusic calltype = temptype = p2type( p -> type ); 133745Speter } 1343065Smckusic break; 135745Speter } 1363065Smckusic if ( temptype != P2UNDEF ) { 1373824Speter tempnlp = tmpalloc(p_type_width, p -> type, NOREG); 1383065Smckusic /* 1393065Smckusic * temp 1403065Smckusic * for (temp = ... 1413065Smckusic */ 1423824Speter putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 1433824Speter tempnlp -> extra_flags , temptype ); 1443065Smckusic } 145745Speter } 1461195Speter switch ( p -> class ) { 1471195Speter case FUNC: 1481195Speter case PROC: 1493065Smckusic /* 1503065Smckusic * ... p( ... 1513065Smckusic */ 1523372Speter sextname( extname , p -> symbol , BLOCKNO(p -> nl_block) ); 1533362Speter putleaf( P2ICON , 0 , 0 , p2type( p ) , extname ); 1541195Speter break; 1551195Speter case FFUNC: 1561195Speter case FPROC: 1573886Speter 1581195Speter /* 1593886Speter * ... ( t -> entryaddr )( ... 1601195Speter */ 1613886Speter putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 1623886Speter tempdescrp -> extra_flags , P2PTR | P2STRTY ); 1633426Speter if ( FENTRYOFFSET != 0 ) { 1643426Speter putleaf( P2ICON , FENTRYOFFSET , 0 , P2INT , 0 ); 1653426Speter putop( P2PLUS , 1663426Speter ADDTYPE( 1673426Speter ADDTYPE( ADDTYPE( p2type( p ) , P2FTN ) , 1683426Speter P2PTR ) , 1693426Speter P2PTR ) ); 1703426Speter } 1713426Speter putop( P2UNARY P2MUL , 1723426Speter ADDTYPE( ADDTYPE( p2type( p ) , P2FTN ) , P2PTR ) ); 1731195Speter break; 1741195Speter default: 1751195Speter panic("call class"); 176745Speter } 1773065Smckusic noarguments = TRUE; 178745Speter # endif PC 179745Speter /* 180745Speter * Loop and process each of 181745Speter * arguments to the proc/func. 1823065Smckusic * ... ( ... args ... ) ... 183745Speter */ 1843297Smckusic for (p1 = plist(p); p1 != NIL; p1 = p1->chain) { 1853297Smckusic if (argv == NIL) { 1863297Smckusic error("Not enough arguments to %s", p->symbol); 1873297Smckusic return (NIL); 1883297Smckusic } 1893297Smckusic switch (p1->class) { 1903297Smckusic case REF: 1913297Smckusic /* 1923297Smckusic * Var parameter 1933297Smckusic */ 1943297Smckusic r = argv[1]; 1953297Smckusic if (r != NIL && r[0] != T_VAR) { 1963297Smckusic error("Expression given (variable required) for var parameter %s of %s", p1->symbol, p->symbol); 1973361Speter chk = FALSE; 1983297Smckusic break; 1993297Smckusic } 2003372Speter q = lvalue( (int *) argv[1], MOD | ASGN , LREQ ); 2013297Smckusic if (q == NIL) { 2023297Smckusic chk = FALSE; 2033297Smckusic break; 2043297Smckusic } 2053297Smckusic if (q != p1->type) { 2063297Smckusic error("Parameter type not identical to type of var parameter %s of %s", p1->symbol, p->symbol); 2073361Speter chk = FALSE; 2083297Smckusic break; 2093297Smckusic } 2103297Smckusic break; 2113297Smckusic case VAR: 2123297Smckusic /* 2133297Smckusic * Value parameter 2143297Smckusic */ 215745Speter # ifdef OBJ 2163297Smckusic q = rvalue(argv[1], p1->type , RREQ ); 217745Speter # endif OBJ 218745Speter # ifdef PC 2193297Smckusic /* 2203297Smckusic * structure arguments require lvalues, 2213297Smckusic * scalars use rvalue. 2223297Smckusic */ 2233297Smckusic switch( classify( p1 -> type ) ) { 2243297Smckusic case TFILE: 2253297Smckusic case TARY: 2263297Smckusic case TREC: 2273297Smckusic case TSET: 2283297Smckusic case TSTR: 229*10365Smckusick q = stkrval( argv[1] , p1 -> type , LREQ ); 230745Speter break; 2313297Smckusic case TINT: 2323297Smckusic case TSCAL: 2333297Smckusic case TBOOL: 2343297Smckusic case TCHAR: 2353297Smckusic precheck( p1 -> type , "_RANG4" , "_RSNG4" ); 236*10365Smckusick q = stkrval( argv[1] , p1 -> type , RREQ ); 237*10365Smckusick postcheck(p1 -> type, P2INT); 238745Speter break; 239*10365Smckusick case TDOUBLE: 240*10365Smckusick q = stkrval( argv[1] , p1 -> type , RREQ ); 241*10365Smckusick sconv(p2type(q), P2DOUBLE); 242*10365Smckusick break; 2433297Smckusic default: 2443297Smckusic q = rvalue( argv[1] , p1 -> type , RREQ ); 2453297Smckusic break; 246745Speter } 2473297Smckusic # endif PC 2483297Smckusic if (q == NIL) { 2493297Smckusic chk = FALSE; 2503297Smckusic break; 2513297Smckusic } 2523297Smckusic if (incompat(q, p1->type, argv[1])) { 2533297Smckusic cerror("Expression type clashed with type of value parameter %s of %s", p1->symbol, p->symbol); 2543361Speter chk = FALSE; 2553297Smckusic break; 2563297Smckusic } 257745Speter # ifdef OBJ 2583297Smckusic if (isa(p1->type, "bcsi")) 2593297Smckusic rangechk(p1->type, q); 2603297Smckusic if (q->class != STR) 2613297Smckusic convert(q, p1->type); 262745Speter # endif OBJ 263745Speter # ifdef PC 2643297Smckusic switch( classify( p1 -> type ) ) { 2653297Smckusic case TFILE: 2663297Smckusic case TARY: 2673297Smckusic case TREC: 2683297Smckusic case TSET: 2693297Smckusic case TSTR: 2703297Smckusic putstrop( P2STARG 2713297Smckusic , p2type( p1 -> type ) 2723297Smckusic , lwidth( p1 -> type ) 2733297Smckusic , align( p1 -> type ) ); 2743297Smckusic } 2751195Speter # endif PC 2763297Smckusic break; 2773297Smckusic case FFUNC: 2781195Speter /* 2793297Smckusic * function parameter 2801195Speter */ 2813297Smckusic q = flvalue( (int *) argv[1] , p1 ); 2823297Smckusic chk = (chk && fcompat(q, p1)); 2833297Smckusic break; 2843297Smckusic case FPROC: 2851195Speter /* 2863297Smckusic * procedure parameter 2871195Speter */ 2883297Smckusic q = flvalue( (int *) argv[1] , p1 ); 2893297Smckusic chk = (chk && fcompat(q, p1)); 2903297Smckusic break; 2913297Smckusic default: 2923297Smckusic panic("call"); 2931195Speter } 2943297Smckusic # ifdef PC 2953297Smckusic /* 2963297Smckusic * if this is the nth (>1) argument, 2973297Smckusic * hang it on the left linear list of arguments 2983297Smckusic */ 2993297Smckusic if ( noarguments ) { 3003297Smckusic noarguments = FALSE; 3013297Smckusic } else { 3023297Smckusic putop( P2LISTOP , P2INT ); 3033297Smckusic } 3043297Smckusic # endif PC 3053297Smckusic argv = argv[2]; 306745Speter } 3073297Smckusic if (argv != NIL) { 3083297Smckusic error("Too many arguments to %s", p->symbol); 3093297Smckusic rvlist(argv); 3103297Smckusic return (NIL); 3113297Smckusic } 3123297Smckusic if (chk == FALSE) 3133297Smckusic return NIL; 314745Speter # ifdef OBJ 3151195Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 3163359Smckusic put(2, PTR_RV | psbn << 8+INDX, (int)p->value[NL_OFFS]); 3174014Smckusic put(2, O_LV | cbn << 8 + INDX , 3184014Smckusic (int) savedispnp -> value[ NL_OFFS ] ); 3193297Smckusic put(1, O_FCALL); 3203063Smckusic put(2, O_FRTN, even(width(p->type))); 3211195Speter } else { 3227916Smckusick put(2, O_CALL | psbn << 8, (long)p->value[NL_ENTLOC]); 3231195Speter } 324745Speter # endif OBJ 325745Speter # ifdef PC 3263065Smckusic /* 3273426Speter * for formal calls: add the hidden argument 3283426Speter * which is the formal struct describing the 3293426Speter * environment of the routine. 3303426Speter * and the argument which is the address of the 3313426Speter * space into which to save the display. 3323426Speter */ 3333426Speter if ( p -> class == FFUNC || p -> class == FPROC ) { 3343886Speter putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 3353886Speter tempdescrp -> extra_flags , P2PTR|P2STRTY ); 3363426Speter if ( !noarguments ) { 3373426Speter putop( P2LISTOP , P2INT ); 3383426Speter } 3393426Speter noarguments = FALSE; 3404014Smckusic putLV( 0 , cbn , savedispnp -> value[ NL_OFFS ] , 3414014Smckusic savedispnp -> extra_flags , P2PTR | P2STRTY ); 3424014Smckusic putop( P2LISTOP , P2INT ); 3433426Speter } 3443426Speter /* 3453065Smckusic * do the actual call: 3463065Smckusic * either ... p( ... ) ... 3473886Speter * or ... ( t -> entryaddr )( ... ) ... 3483065Smckusic * and maybe an assignment. 3493065Smckusic */ 350745Speter if ( porf == FUNC ) { 3513065Smckusic switch ( p_type_class ) { 352745Speter case TBOOL: 353745Speter case TCHAR: 354745Speter case TINT: 355745Speter case TSCAL: 356745Speter case TDOUBLE: 357745Speter case TPTR: 3583065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , 3593065Smckusic p_type_p2type ); 3603065Smckusic if ( p -> class == FFUNC ) { 3613065Smckusic putop( P2ASSIGN , p_type_p2type ); 362745Speter } 363745Speter break; 364745Speter default: 3653065Smckusic putstrop( ( noarguments ? P2UNARY P2STCALL : P2STCALL ), 3663065Smckusic ADDTYPE( p_type_p2type , P2PTR ) , 3673065Smckusic p_type_width , p_type_align ); 3683065Smckusic putstrop( P2STASG , p_type_p2type , lwidth( p -> type ) 369745Speter , align( p -> type ) ); 370745Speter break; 371745Speter } 372745Speter } else { 3733065Smckusic putop( ( noarguments ? P2UNARY P2CALL : P2CALL ) , P2INT ); 3743065Smckusic } 3753065Smckusic /* 3763886Speter * ( t=p , ... , FRTN( t ) ... 3773065Smckusic */ 3783065Smckusic if ( p -> class == FFUNC || p -> class == FPROC ) { 3793886Speter putop( P2COMOP , P2INT ); 3803065Smckusic putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , 3813065Smckusic "_FRTN" ); 3823886Speter putRV( 0 , cbn , tempdescrp -> value[ NL_OFFS ] , 3833886Speter tempdescrp -> extra_flags , P2PTR | P2STRTY ); 3844014Smckusic putLV( 0 , cbn , savedispnp -> value[ NL_OFFS ] , 3854014Smckusic savedispnp -> extra_flags , P2PTR | P2STRTY ); 3864014Smckusic putop( P2LISTOP , P2INT ); 3873065Smckusic putop( P2CALL , P2INT ); 3883065Smckusic putop( P2COMOP , P2INT ); 3893065Smckusic } 3903065Smckusic /* 3913065Smckusic * if required: 3923065Smckusic * either ... , temp ) 3933065Smckusic * or ... , &temp ) 3943065Smckusic */ 3953065Smckusic if ( porf == FUNC && temptype != P2UNDEF ) { 3963065Smckusic if ( temptype != P2STRTY ) { 3973824Speter putRV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 3983824Speter tempnlp -> extra_flags , p_type_p2type ); 399745Speter } else { 4003824Speter putLV( 0 , cbn , tempnlp -> value[ NL_OFFS ] , 4013824Speter tempnlp -> extra_flags , p_type_p2type ); 402745Speter } 4033065Smckusic putop( P2COMOP , P2INT ); 4043065Smckusic } 4053065Smckusic if ( porf == PROC ) { 406745Speter putdot( filename , line ); 407745Speter } 408745Speter # endif PC 409745Speter return (p->type); 410745Speter } 411745Speter 412745Speter rvlist(al) 413745Speter register int *al; 414745Speter { 415745Speter 416745Speter for (; al != NIL; al = al[2]) 417745Speter rvalue( (int *) al[1], NLNIL , RREQ ); 418745Speter } 4193297Smckusic 4203297Smckusic /* 4213297Smckusic * check that two function/procedure namelist entries are compatible 4223297Smckusic */ 4233297Smckusic bool 4243297Smckusic fcompat( formal , actual ) 4253297Smckusic struct nl *formal; 4263297Smckusic struct nl *actual; 4273297Smckusic { 4283297Smckusic register struct nl *f_chain; 4293297Smckusic register struct nl *a_chain; 4303297Smckusic bool compat = TRUE; 4313297Smckusic 4323297Smckusic if ( formal == NIL || actual == NIL ) { 4333297Smckusic return FALSE; 4343297Smckusic } 4353297Smckusic for (a_chain = plist(actual), f_chain = plist(formal); 4363297Smckusic f_chain != NIL; 4373297Smckusic f_chain = f_chain->chain, a_chain = a_chain->chain) { 4383297Smckusic if (a_chain == NIL) { 4393297Smckusic error("%s %s declared on line %d has more arguments than", 4403297Smckusic parnam(formal->class), formal->symbol, 4413297Smckusic linenum(formal)); 4423297Smckusic cerror("%s %s declared on line %d", 4433297Smckusic parnam(actual->class), actual->symbol, 4443297Smckusic linenum(actual)); 4453297Smckusic return FALSE; 4463297Smckusic } 4473297Smckusic if ( a_chain -> class != f_chain -> class ) { 4483297Smckusic error("%s parameter %s of %s declared on line %d is not identical", 4493297Smckusic parnam(f_chain->class), f_chain->symbol, 4503297Smckusic formal->symbol, linenum(formal)); 4513297Smckusic cerror("with %s parameter %s of %s declared on line %d", 4523297Smckusic parnam(a_chain->class), a_chain->symbol, 4533297Smckusic actual->symbol, linenum(actual)); 4543297Smckusic compat = FALSE; 4553297Smckusic } else if (a_chain->class == FFUNC || a_chain->class == FPROC) { 4563297Smckusic compat = (compat && fcompat(f_chain, a_chain)); 4573297Smckusic } 4583297Smckusic if ((a_chain->class != FPROC && f_chain->class != FPROC) && 4593297Smckusic (a_chain->type != f_chain->type)) { 4603297Smckusic error("Type of %s parameter %s of %s declared on line %d is not identical", 4613297Smckusic parnam(f_chain->class), f_chain->symbol, 4623297Smckusic formal->symbol, linenum(formal)); 4633297Smckusic cerror("to type of %s parameter %s of %s declared on line %d", 4643297Smckusic parnam(a_chain->class), a_chain->symbol, 4653297Smckusic actual->symbol, linenum(actual)); 4663297Smckusic compat = FALSE; 4673297Smckusic } 4683297Smckusic } 4693297Smckusic if (a_chain != NIL) { 4703297Smckusic error("%s %s declared on line %d has fewer arguments than", 4713297Smckusic parnam(formal->class), formal->symbol, 4723297Smckusic linenum(formal)); 4733297Smckusic cerror("%s %s declared on line %d", 4743297Smckusic parnam(actual->class), actual->symbol, 4753297Smckusic linenum(actual)); 4763297Smckusic return FALSE; 4773297Smckusic } 4783297Smckusic return compat; 4793297Smckusic } 4803297Smckusic 4813297Smckusic char * 4823297Smckusic parnam(nltype) 4833297Smckusic int nltype; 4843297Smckusic { 4853297Smckusic switch(nltype) { 4863297Smckusic case REF: 4873297Smckusic return "var"; 4883297Smckusic case VAR: 4893297Smckusic return "value"; 4903297Smckusic case FUNC: 4913297Smckusic case FFUNC: 4923297Smckusic return "function"; 4933297Smckusic case PROC: 4943297Smckusic case FPROC: 4953297Smckusic return "procedure"; 4963297Smckusic default: 4973297Smckusic return "SNARK"; 4983297Smckusic } 4993297Smckusic } 5003297Smckusic 5013297Smckusic plist(p) 5023297Smckusic struct nl *p; 5033297Smckusic { 5043297Smckusic switch (p->class) { 5053297Smckusic case FFUNC: 5063297Smckusic case FPROC: 5073297Smckusic return p->ptr[ NL_FCHAIN ]; 5083297Smckusic case PROC: 5093297Smckusic case FUNC: 5103297Smckusic return p->chain; 5113297Smckusic default: 5123297Smckusic panic("plist"); 5133297Smckusic } 5143297Smckusic } 5153297Smckusic 5163297Smckusic linenum(p) 5173297Smckusic struct nl *p; 5183297Smckusic { 5193297Smckusic if (p->class == FUNC) 5203297Smckusic return p->ptr[NL_FVAR]->value[NL_LINENO]; 5213297Smckusic return p->value[NL_LINENO]; 5223297Smckusic } 523