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