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