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