1 /* Copyright (c) 1979 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)fend.c 1.3 03/18/81"; 4 5 #include "whoami.h" 6 #include "0.h" 7 #include "tree.h" 8 #include "opcode.h" 9 #include "objfmt.h" 10 #include "align.h" 11 12 /* 13 * this array keeps the pxp counters associated with 14 * functions and procedures, so that they can be output 15 * when their bodies are encountered 16 */ 17 int bodycnts[ DSPLYSZ ]; 18 19 #ifdef PC 20 # include "pc.h" 21 # include "pcops.h" 22 #endif PC 23 24 #ifdef OBJ 25 int cntpatch; 26 int nfppatch; 27 #endif OBJ 28 29 struct nl *Fp; 30 int pnumcnt; 31 /* 32 * Funcend is called to 33 * finish a block by generating 34 * the code for the statements. 35 * It then looks for unresolved declarations 36 * of labels, procedures and functions, 37 * and cleans up the name list. 38 * For the program, it checks the 39 * semantics of the program 40 * statement (yuchh). 41 */ 42 funcend(fp, bundle, endline) 43 struct nl *fp; 44 int *bundle; 45 int endline; 46 { 47 register struct nl *p; 48 register int i, b; 49 int var, inp, out, *blk; 50 bool chkref; 51 struct nl *iop; 52 char *cp; 53 extern int cntstat; 54 # ifdef PC 55 int savlabel = getlab(); 56 int toplabel = getlab(); 57 int botlabel = getlab(); 58 # endif PC 59 60 cntstat = 0; 61 /* 62 * yyoutline(); 63 */ 64 if (program != NIL) 65 line = program->value[3]; 66 blk = bundle[2]; 67 if (fp == NIL) { 68 cbn--; 69 # ifdef PTREE 70 nesting--; 71 # endif PTREE 72 return; 73 } 74 #ifdef OBJ 75 /* 76 * Patch the branch to the 77 * entry point of the function 78 */ 79 patch4(fp->entloc); 80 /* 81 * Put out the block entrance code and the block name. 82 * HDRSZE is the number of bytes of info in the static 83 * BEG data area exclusive of the proc name. It is 84 * currently defined as: 85 /* struct hdr { 86 /* long framesze; /* number of bytes of local vars */ 87 /* long nargs; /* number of bytes of arguments */ 88 /* bool tests; /* TRUE => perform runtime tests */ 89 /* short offset; /* offset of procedure in source file */ 90 /* char name[1]; /* name of active procedure */ 91 /* }; 92 */ 93 # define HDRSZE (2 * sizeof(long) + sizeof(short) + sizeof(bool)) 94 var = put(2, ((lenstr(fp->symbol,0) + HDRSZE) << 8) 95 | (cbn == 1 && opt('p') == 0 ? O_NODUMP: O_BEG), (long)0); 96 /* 97 * output the number of bytes of arguments 98 * this is only checked on formal calls. 99 */ 100 put(2, O_CASE4, cbn == 1 ? (long)0 : (long)(fp->value[NL_OFFS]-DPOFF2)); 101 /* 102 * Output the runtime test mode for the routine 103 */ 104 put(2, sizeof(bool) == 2 ? O_CASE2 : O_CASE4, opt('t') ? TRUE : FALSE); 105 /* 106 * Output line number and routine name 107 */ 108 put(2, O_CASE2, bundle[1]); 109 putstr(fp->symbol, 0); 110 #endif OBJ 111 #ifdef PC 112 /* 113 * put out the procedure entry code 114 */ 115 if ( fp -> class == PROG ) { 116 putprintf( " .text" , 0 ); 117 putprintf( " .align 1" , 0 ); 118 putprintf( " .globl _main" , 0 ); 119 putprintf( "_main:" , 0 ); 120 putprintf( " .word 0" , 0 ); 121 putprintf( " calls $0,_PCSTART" , 0 ); 122 putprintf( " movl 4(ap),__argc" , 0 ); 123 putprintf( " movl 8(ap),__argv" , 0 ); 124 putprintf( " calls $0,_program" , 0 ); 125 putprintf( " calls $0,_PCEXIT" , 0 ); 126 ftnno = fp -> entloc; 127 putprintf( " .text" , 0 ); 128 putprintf( " .align 1" , 0 ); 129 putprintf( " .globl _program" , 0 ); 130 putprintf( "_program:" , 0 ); 131 stabfunc( "program" , fp -> class , bundle[1] , 0 ); 132 } else { 133 ftnno = fp -> entloc; 134 putprintf( " .text" , 0 ); 135 putprintf( " .align 1" , 0 ); 136 putprintf( " .globl " , 1 ); 137 for ( i = 1 ; i < cbn ; i++ ) { 138 putprintf( EXTFORMAT , 1 , enclosing[ i ] ); 139 } 140 putprintf( "" , 0 ); 141 for ( i = 1 ; i < cbn ; i++ ) { 142 putprintf( EXTFORMAT , 1 , enclosing[ i ] ); 143 } 144 putprintf( ":" , 0 ); 145 stabfunc( fp -> symbol , fp -> class , bundle[1] , cbn - 1 ); 146 for ( p = fp -> chain ; p != NIL ; p = p -> chain ) { 147 stabparam( p -> symbol , p2type( p -> type ) 148 , p -> value[ NL_OFFS ] , lwidth( p -> type ) ); 149 } 150 if ( fp -> class == FUNC ) { 151 /* 152 * stab the function variable 153 */ 154 p = fp -> ptr[ NL_FVAR ]; 155 stablvar( p -> symbol , p2type( p -> type ) , cbn 156 , p -> value[ NL_OFFS ] , lwidth( p -> type ) ); 157 } 158 /* 159 * stab local variables 160 * rummage down hash chain links. 161 */ 162 for ( i = 0 ; i <= 077 ; i++ ) { 163 for ( p = disptab[ i ] ; p != NIL ; p = p->nl_next) { 164 if ( ( p -> nl_block & 037 ) != cbn ) { 165 break; 166 } 167 /* 168 * stab local variables 169 * that's named variables, but not params 170 */ 171 if ( ( p -> symbol != NIL ) 172 && ( p -> class == VAR ) 173 && ( p -> value[ NL_OFFS ] < 0 ) ) { 174 stablvar( p -> symbol , p2type( p -> type ) , cbn 175 , p -> value[ NL_OFFS ] , lwidth( p -> type ) ); 176 } 177 } 178 } 179 } 180 stablbrac( cbn ); 181 /* 182 * register save mask 183 */ 184 putprintf( " .word " , 1 ); 185 putprintf( PREFIXFORMAT , 0 , LABELPREFIX , savlabel ); 186 putjbr( botlabel ); 187 putlab( toplabel ); 188 if ( profflag ) { 189 /* 190 * call mcount for profiling 191 */ 192 putprintf( " moval 1f,r0" , 0 ); 193 putprintf( " jsb mcount" , 0 ); 194 putprintf( " .data" , 0 ); 195 putprintf( " .align 2" , 0 ); 196 putprintf( "1:" , 0 ); 197 putprintf( " .long 0" , 0 ); 198 putprintf( " .text" , 0 ); 199 } 200 /* 201 * set up unwind exception vector. 202 */ 203 putprintf( " moval %s,%d(%s)" , 0 204 , UNWINDNAME , UNWINDOFFSET , P2FPNAME ); 205 /* 206 * save address of display entry, for unwind. 207 */ 208 putprintf( " moval %s+%d,%d(%s)" , 0 209 , DISPLAYNAME , cbn * sizeof(struct dispsave) 210 , DPTROFFSET , P2FPNAME ); 211 /* 212 * save old display 213 */ 214 putprintf( " movq %s+%d,%d(%s)" , 0 215 , DISPLAYNAME , cbn * sizeof(struct dispsave) 216 , DSAVEOFFSET , P2FPNAME ); 217 /* 218 * set up new display by saving AP and FP in appropriate 219 * slot in display structure. 220 */ 221 putprintf( " movq %s,%s+%d" , 0 222 , P2APNAME , DISPLAYNAME , cbn * sizeof(struct dispsave) ); 223 /* 224 * ask second pass to allocate known locals 225 */ 226 putlbracket( ftnno , -sizes[ cbn ].om_max ); 227 /* 228 * and zero them if checking is on 229 * by calling blkclr( bytes of locals , starting local address ); 230 */ 231 if ( opt( 't' ) && ( -sizes[ cbn ].om_max ) > DPOFF1 ) { 232 putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 233 , "_blkclr" ); 234 putleaf( P2ICON , ( -sizes[ cbn ].om_max ) - DPOFF1 235 , 0 , P2INT , 0 ); 236 putLV( 0 , cbn , sizes[ cbn ].om_max , P2CHAR ); 237 putop( P2LISTOP , P2INT ); 238 putop( P2CALL , P2INT ); 239 putdot( filename , line ); 240 } 241 #endif PC 242 if ( monflg ) { 243 if ( fp -> value[ NL_CNTR ] != 0 ) { 244 inccnt( fp -> value [ NL_CNTR ] ); 245 } 246 inccnt( bodycnts[ fp -> nl_block & 037 ] ); 247 } 248 if (fp->class == PROG) { 249 /* 250 * The glorious buffers option. 251 * 0 = don't buffer output 252 * 1 = line buffer output 253 * 2 = 512 byte buffer output 254 */ 255 # ifdef OBJ 256 if (opt('b') != 1) 257 put(1, O_BUFF | opt('b') << 8); 258 # endif OBJ 259 # ifdef PC 260 if ( opt( 'b' ) != 1 ) { 261 putleaf( P2ICON , 0 , 0 262 , ADDTYPE( P2FTN | P2INT , P2PTR ) , "_BUFF" ); 263 putleaf( P2ICON , opt( 'b' ) , 0 , P2INT , 0 ); 264 putop( P2CALL , P2INT ); 265 putdot( filename , line ); 266 } 267 # endif PC 268 out = 0; 269 for (p = fp->chain; p != NIL; p = p->chain) { 270 if (strcmp(p->symbol, "input") == 0) { 271 inp++; 272 continue; 273 } 274 if (strcmp(p->symbol, "output") == 0) { 275 out++; 276 continue; 277 } 278 iop = lookup1(p->symbol); 279 if (iop == NIL || bn != cbn) { 280 error("File %s listed in program statement but not declared", p->symbol); 281 continue; 282 } 283 if (iop->class != VAR) { 284 error("File %s listed in program statement but declared as a %s", p->symbol, classes[iop->class]); 285 continue; 286 } 287 if (iop->type == NIL) 288 continue; 289 if (iop->type->class != FILET) { 290 error("File %s listed in program statement but defined as %s", 291 p->symbol, nameof(iop->type)); 292 continue; 293 } 294 # ifdef OBJ 295 put(2, O_CON24, text(iop->type) ? 0 : width(iop->type->type)); 296 i = lenstr(p->symbol,0); 297 put(2, O_CON24, i); 298 put(2, O_LVCON, i); 299 putstr(p->symbol, 0); 300 put(2, O_LV | bn<<8+INDX, (int)iop->value[NL_OFFS]); 301 put(1, O_DEFNAME); 302 # endif OBJ 303 # ifdef PC 304 putleaf( P2ICON , 0 , 0 305 , ADDTYPE( P2FTN | P2INT , P2PTR ) 306 , "_DEFNAME" ); 307 putLV( p -> symbol , bn , iop -> value[NL_OFFS] 308 , p2type( iop ) ); 309 putCONG( p -> symbol , strlen( p -> symbol ) 310 , LREQ ); 311 putop( P2LISTOP , P2INT ); 312 putleaf( P2ICON , strlen( p -> symbol ) 313 , 0 , P2INT , 0 ); 314 putop( P2LISTOP , P2INT ); 315 putleaf( P2ICON 316 , text(iop->type) ? 0 : width(iop->type->type) 317 , 0 , P2INT , 0 ); 318 putop( P2LISTOP , P2INT ); 319 putop( P2CALL , P2INT ); 320 putdot( filename , line ); 321 # endif PC 322 } 323 if (out == 0 && fp->chain != NIL) { 324 recovered(); 325 error("The file output must appear in the program statement file list"); 326 } 327 } 328 /* 329 * Process the prog/proc/func body 330 */ 331 noreach = 0; 332 line = bundle[1]; 333 statlist(blk); 334 # ifdef PTREE 335 { 336 pPointer Body = tCopy( blk ); 337 338 pDEF( PorFHeader[ nesting -- ] ).PorFBody = Body; 339 } 340 # endif PTREE 341 # ifdef OBJ 342 if (cbn== 1 && monflg != 0) { 343 patchfil(cntpatch - 2, (long)cnts, 2); 344 patchfil(nfppatch - 2, (long)pfcnt, 2); 345 } 346 # endif OBJ 347 # ifdef PC 348 if ( fp -> class == PROG && monflg ) { 349 putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 350 , "_PMFLUSH" ); 351 putleaf( P2ICON , cnts , 0 , P2INT , 0 ); 352 putleaf( P2ICON , pfcnt , 0 , P2INT , 0 ); 353 putop( P2LISTOP , P2INT ); 354 putLV( PCPCOUNT , 0 , 0 , P2INT ); 355 putop( P2LISTOP , P2INT ); 356 putop( P2CALL , P2INT ); 357 putdot( filename , line ); 358 } 359 # endif PC 360 if (fp->class == PROG && inp == 0 && (input->nl_flags & (NUSED|NMOD)) != 0) { 361 recovered(); 362 error("Input is used but not defined in the program statement"); 363 } 364 /* 365 * Clean up the symbol table displays and check for unresolves 366 */ 367 line = endline; 368 b = cbn; 369 Fp = fp; 370 chkref = syneflg == errcnt[cbn] && opt('w') == 0; 371 for (i = 0; i <= 077; i++) { 372 for (p = disptab[i]; p != NIL && (p->nl_block & 037) == b; p = p->nl_next) { 373 /* 374 * Check for variables defined 375 * but not referenced 376 */ 377 if (chkref && p->symbol != NIL) 378 switch (p->class) { 379 case FIELD: 380 /* 381 * If the corresponding record is 382 * unused, we shouldn't complain about 383 * the fields. 384 */ 385 default: 386 if ((p->nl_flags & (NUSED|NMOD)) == 0) { 387 warning(); 388 nerror("%s %s is neither used nor set", classes[p->class], p->symbol); 389 break; 390 } 391 /* 392 * If a var parameter is either 393 * modified or used that is enough. 394 */ 395 if (p->class == REF) 396 continue; 397 # ifdef OBJ 398 if ((p->nl_flags & NUSED) == 0) { 399 warning(); 400 nerror("%s %s is never used", classes[p->class], p->symbol); 401 break; 402 } 403 # endif OBJ 404 # ifdef PC 405 if (((p->nl_flags & NUSED) == 0) && ((p->ext_flags & NEXTERN) == 0)) { 406 warning(); 407 nerror("%s %s is never used", classes[p->class], p->symbol); 408 break; 409 } 410 # endif PC 411 if ((p->nl_flags & NMOD) == 0) { 412 warning(); 413 nerror("%s %s is used but never set", classes[p->class], p->symbol); 414 break; 415 } 416 case LABEL: 417 case FVAR: 418 case BADUSE: 419 break; 420 } 421 switch (p->class) { 422 case BADUSE: 423 cp = "s"; 424 if (p->chain->ud_next == NIL) 425 cp++; 426 eholdnl(); 427 if (p->value[NL_KINDS] & ISUNDEF) 428 nerror("%s undefined on line%s", p->symbol, cp); 429 else 430 nerror("%s improperly used on line%s", p->symbol, cp); 431 pnumcnt = 10; 432 pnums(p->chain); 433 pchr('\n'); 434 break; 435 436 case FUNC: 437 case PROC: 438 # ifdef OBJ 439 if ((p->nl_flags & NFORWD)) 440 nerror("Unresolved forward declaration of %s %s", classes[p->class], p->symbol); 441 # endif OBJ 442 # ifdef PC 443 if ((p->nl_flags & NFORWD) && ((p->ext_flags & NEXTERN) == 0)) 444 nerror("Unresolved forward declaration of %s %s", classes[p->class], p->symbol); 445 # endif PC 446 break; 447 448 case LABEL: 449 if (p->nl_flags & NFORWD) 450 nerror("label %s was declared but not defined", p->symbol); 451 break; 452 case FVAR: 453 if ((p->nl_flags & NMOD) == 0) 454 nerror("No assignment to the function variable"); 455 break; 456 } 457 } 458 /* 459 * Pop this symbol 460 * table slot 461 */ 462 disptab[i] = p; 463 } 464 465 # ifdef OBJ 466 put(1, O_END); 467 # endif OBJ 468 # ifdef PC 469 /* 470 * if there were file variables declared at this level 471 * call pclose( &__disply[ cbn ] ) to clean them up. 472 */ 473 if ( dfiles[ cbn ] ) { 474 putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 475 , "_PCLOSE" ); 476 putRV( DISPLAYNAME , 0 , cbn * sizeof( struct dispsave ) 477 , P2PTR | P2CHAR ); 478 putop( P2CALL , P2INT ); 479 putdot( filename , line ); 480 } 481 /* 482 * if this is a function, 483 * the function variable is the return value. 484 * if it's a scalar valued function, return scalar, 485 * else, return a pointer to the structure value. 486 */ 487 if ( fp -> class == FUNC ) { 488 struct nl *fvar = fp -> ptr[ NL_FVAR ]; 489 long fvartype = p2type( fvar -> type ); 490 long label; 491 char labelname[ BUFSIZ ]; 492 493 switch ( classify( fvar -> type ) ) { 494 case TBOOL: 495 case TCHAR: 496 case TINT: 497 case TSCAL: 498 case TDOUBLE: 499 case TPTR: 500 putRV( fvar -> symbol , ( fvar -> nl_block ) & 037 501 , fvar -> value[ NL_OFFS ] , fvartype ); 502 break; 503 default: 504 label = getlab(); 505 sprintf( labelname , PREFIXFORMAT , 506 LABELPREFIX , label ); 507 putprintf( " .data" , 0 ); 508 putprintf( " .lcomm %s,%d" , 0 , 509 labelname , lwidth( fvar -> type ) ); 510 putprintf( " .text" , 0 ); 511 putleaf( P2NAME , 0 , 0 , fvartype , labelname ); 512 putLV( fvar -> symbol , ( fvar -> nl_block ) & 037 513 , fvar -> value[ NL_OFFS ] , fvartype ); 514 putstrop( P2STASG , fvartype , lwidth( fvar -> type ) , 515 align( fvar -> type ) ); 516 putdot( filename , line ); 517 putleaf( P2ICON , 0 , 0 , fvartype , labelname ); 518 break; 519 } 520 putop( P2FORCE , fvartype ); 521 putdot( filename , line ); 522 } 523 /* 524 * restore old display entry from save area 525 */ 526 527 putprintf( " movq %d(%s),%s+%d" , 0 528 , DSAVEOFFSET , P2FPNAME 529 , DISPLAYNAME , cbn * sizeof(struct dispsave) ); 530 stabrbrac( cbn ); 531 putprintf( " ret" , 0 ); 532 /* 533 * let the second pass allocate locals 534 * and registers 535 */ 536 putprintf( " .set " , 1 ); 537 putprintf( PREFIXFORMAT , 1 , LABELPREFIX , savlabel ); 538 putprintf( ", 0x%x" , 0 , savmask() ); 539 putlab( botlabel ); 540 putprintf( " subl2 $LF%d,sp" , 0 , ftnno ); 541 putrbracket( ftnno ); 542 putjbr( toplabel ); 543 /* 544 * declare pcp counters, if any 545 */ 546 if ( monflg && fp -> class == PROG ) { 547 putprintf( " .data" , 0 ); 548 putprintf( " .comm " , 1 ); 549 putprintf( PCPCOUNT , 1 ); 550 putprintf( ",%d" , 0 , ( cnts + 1 ) * sizeof (long) ); 551 putprintf( " .text" , 0 ); 552 } 553 # endif PC 554 #ifdef DEBUG 555 dumpnl(fp->ptr[2], fp->symbol); 556 #endif 557 /* 558 * Restore the 559 * (virtual) name list 560 * position 561 */ 562 nlfree(fp->ptr[2]); 563 /* 564 * Proc/func has been 565 * resolved 566 */ 567 fp->nl_flags &= ~NFORWD; 568 /* 569 * Patch the beg 570 * of the proc/func to 571 * the proper variable size 572 */ 573 if (Fp == NIL) 574 elineon(); 575 # ifdef OBJ 576 patchfil(var, (long)(-sizes[cbn].om_max), 2); 577 # endif OBJ 578 cbn--; 579 if (inpflist(fp->symbol)) { 580 opop('l'); 581 } 582 } 583