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