1 /* Copyright (c) 1979 Regents of the University of California */ 2 3 static char sccsid[] = "@(#)fend.c 1.12 08/26/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 out = 0; 280 for (p = fp->chain; p != NIL; p = p->chain) { 281 if (strcmp(p->symbol, "input") == 0) { 282 inp++; 283 continue; 284 } 285 if (strcmp(p->symbol, "output") == 0) { 286 out++; 287 continue; 288 } 289 iop = lookup1(p->symbol); 290 if (iop == NIL || bn != cbn) { 291 error("File %s listed in program statement but not declared", p->symbol); 292 continue; 293 } 294 if (iop->class != VAR) { 295 error("File %s listed in program statement but declared as a %s", p->symbol, classes[iop->class]); 296 continue; 297 } 298 if (iop->type == NIL) 299 continue; 300 if (iop->type->class != FILET) { 301 error("File %s listed in program statement but defined as %s", 302 p->symbol, nameof(iop->type)); 303 continue; 304 } 305 # ifdef OBJ 306 put(2, O_CON24, text(iop->type) ? 0 : width(iop->type->type)); 307 i = lenstr(p->symbol,0); 308 put(2, O_CON24, i); 309 put(2, O_LVCON, i); 310 putstr(p->symbol, 0); 311 put(2, O_LV | bn<<8+INDX, (int)iop->value[NL_OFFS]); 312 put(1, O_DEFNAME); 313 # endif OBJ 314 # ifdef PC 315 putleaf( P2ICON , 0 , 0 316 , ADDTYPE( P2FTN | P2INT , P2PTR ) 317 , "_DEFNAME" ); 318 putLV( p -> symbol , bn , iop -> value[NL_OFFS] , 319 iop -> extra_flags , p2type( iop ) ); 320 putCONG( p -> symbol , strlen( p -> symbol ) 321 , LREQ ); 322 putop( P2LISTOP , P2INT ); 323 putleaf( P2ICON , strlen( p -> symbol ) 324 , 0 , P2INT , 0 ); 325 putop( P2LISTOP , P2INT ); 326 putleaf( P2ICON 327 , text(iop->type) ? 0 : width(iop->type->type) 328 , 0 , P2INT , 0 ); 329 putop( P2LISTOP , P2INT ); 330 putop( P2CALL , P2INT ); 331 putdot( filename , line ); 332 # endif PC 333 } 334 if (out == 0 && fp->chain != NIL) { 335 recovered(); 336 error("The file output must appear in the program statement file list"); 337 } 338 } 339 /* 340 * Process the prog/proc/func body 341 */ 342 noreach = 0; 343 line = bundle[1]; 344 statlist(blk); 345 # ifdef PTREE 346 { 347 pPointer Body = tCopy( blk ); 348 349 pDEF( PorFHeader[ nesting -- ] ).PorFBody = Body; 350 } 351 # endif PTREE 352 # ifdef OBJ 353 if (cbn== 1 && monflg != 0) { 354 patchfil(cntpatch - 2, (long)cnts, 2); 355 patchfil(nfppatch - 2, (long)pfcnt, 2); 356 } 357 # endif OBJ 358 # ifdef PC 359 if ( fp -> class == PROG && monflg ) { 360 putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 361 , "_PMFLUSH" ); 362 putleaf( P2ICON , cnts , 0 , P2INT , 0 ); 363 putleaf( P2ICON , pfcnt , 0 , P2INT , 0 ); 364 putop( P2LISTOP , P2INT ); 365 putLV( PCPCOUNT , 0 , 0 , NGLOBAL , P2INT ); 366 putop( P2LISTOP , P2INT ); 367 putop( P2CALL , P2INT ); 368 putdot( filename , line ); 369 } 370 # endif PC 371 if (fp->class == PROG && inp == 0 && (input->nl_flags & (NUSED|NMOD)) != 0) { 372 recovered(); 373 error("Input is used but not defined in the program statement"); 374 } 375 /* 376 * Clean up the symbol table displays and check for unresolves 377 */ 378 line = endline; 379 b = cbn; 380 Fp = fp; 381 chkref = syneflg == errcnt[cbn] && opt('w') == 0; 382 for (i = 0; i <= 077; i++) { 383 for (p = disptab[i]; p != NIL && (p->nl_block & 037) == b; p = p->nl_next) { 384 /* 385 * Check for variables defined 386 * but not referenced 387 */ 388 if (chkref && p->symbol != NIL) 389 switch (p->class) { 390 case FIELD: 391 /* 392 * If the corresponding record is 393 * unused, we shouldn't complain about 394 * the fields. 395 */ 396 default: 397 if ((p->nl_flags & (NUSED|NMOD)) == 0) { 398 warning(); 399 nerror("%s %s is neither used nor set", classes[p->class], p->symbol); 400 break; 401 } 402 /* 403 * If a var parameter is either 404 * modified or used that is enough. 405 */ 406 if (p->class == REF) 407 continue; 408 # ifdef OBJ 409 if ((p->nl_flags & NUSED) == 0) { 410 warning(); 411 nerror("%s %s is never used", classes[p->class], p->symbol); 412 break; 413 } 414 # endif OBJ 415 # ifdef PC 416 if (((p->nl_flags & NUSED) == 0) && ((p->extra_flags & NEXTERN) == 0)) { 417 warning(); 418 nerror("%s %s is never used", classes[p->class], p->symbol); 419 break; 420 } 421 # endif PC 422 if ((p->nl_flags & NMOD) == 0) { 423 warning(); 424 nerror("%s %s is used but never set", classes[p->class], p->symbol); 425 break; 426 } 427 case LABEL: 428 case FVAR: 429 case BADUSE: 430 break; 431 } 432 switch (p->class) { 433 case BADUSE: 434 cp = "s"; 435 if (p->chain->ud_next == NIL) 436 cp++; 437 eholdnl(); 438 if (p->value[NL_KINDS] & ISUNDEF) 439 nerror("%s undefined on line%s", p->symbol, cp); 440 else 441 nerror("%s improperly used on line%s", p->symbol, cp); 442 pnumcnt = 10; 443 pnums(p->chain); 444 pchr('\n'); 445 break; 446 447 case FUNC: 448 case PROC: 449 # ifdef OBJ 450 if ((p->nl_flags & NFORWD)) 451 nerror("Unresolved forward declaration of %s %s", classes[p->class], p->symbol); 452 # endif OBJ 453 # ifdef PC 454 if ((p->nl_flags & NFORWD) && ((p->extra_flags & NEXTERN) == 0)) 455 nerror("Unresolved forward declaration of %s %s", classes[p->class], p->symbol); 456 # endif PC 457 break; 458 459 case LABEL: 460 if (p->nl_flags & NFORWD) 461 nerror("label %s was declared but not defined", p->symbol); 462 break; 463 case FVAR: 464 if ((p->nl_flags & NMOD) == 0) 465 nerror("No assignment to the function variable"); 466 break; 467 } 468 } 469 /* 470 * Pop this symbol 471 * table slot 472 */ 473 disptab[i] = p; 474 } 475 476 # ifdef OBJ 477 put(1, O_END); 478 # endif OBJ 479 # ifdef PC 480 /* 481 * if there were file variables declared at this level 482 * call pclose( &__disply[ cbn ] ) to clean them up. 483 */ 484 if ( dfiles[ cbn ] ) { 485 putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) 486 , "_PCLOSE" ); 487 putRV( DISPLAYNAME , 0 , cbn * sizeof( struct dispsave ) , 488 NGLOBAL , P2PTR | P2CHAR ); 489 putop( P2CALL , P2INT ); 490 putdot( filename , line ); 491 } 492 /* 493 * if this is a function, 494 * the function variable is the return value. 495 * if it's a scalar valued function, return scalar, 496 * else, return a pointer to the structure value. 497 */ 498 if ( fp -> class == FUNC ) { 499 struct nl *fvar = fp -> ptr[ NL_FVAR ]; 500 long fvartype = p2type( fvar -> type ); 501 long label; 502 char labelname[ BUFSIZ ]; 503 504 switch ( classify( fvar -> type ) ) { 505 case TBOOL: 506 case TCHAR: 507 case TINT: 508 case TSCAL: 509 case TDOUBLE: 510 case TPTR: 511 putRV( fvar -> symbol , ( fvar -> nl_block ) & 037 , 512 fvar -> value[ NL_OFFS ] , 513 fvar -> extra_flags , 514 fvartype ); 515 break; 516 default: 517 label = getlab(); 518 sprintf( labelname , PREFIXFORMAT , 519 LABELPREFIX , label ); 520 putprintf( " .data" , 0 ); 521 putprintf( " .lcomm %s,%d" , 0 , 522 labelname , lwidth( fvar -> type ) ); 523 putprintf( " .text" , 0 ); 524 putleaf( P2NAME , 0 , 0 , fvartype , labelname ); 525 putLV( fvar -> symbol , ( fvar -> nl_block ) & 037 , 526 fvar -> value[ NL_OFFS ] , 527 fvar -> extra_flags , 528 fvartype ); 529 putstrop( P2STASG , fvartype , lwidth( fvar -> type ) , 530 align( fvar -> type ) ); 531 putdot( filename , line ); 532 putleaf( P2ICON , 0 , 0 , fvartype , labelname ); 533 break; 534 } 535 putop( P2FORCE , fvartype ); 536 putdot( filename , line ); 537 } 538 /* 539 * restore old display entry from save area 540 */ 541 542 putprintf( " movq %d(%s),%s+%d" , 0 543 , DSAVEOFFSET , P2FPNAME 544 , DISPLAYNAME , cbn * sizeof(struct dispsave) ); 545 stabrbrac( cbn ); 546 putprintf( " ret" , 0 ); 547 /* 548 * let the second pass allocate locals 549 * and registers 550 */ 551 putprintf( " .set " , 1 ); 552 putprintf( PREFIXFORMAT , 1 , LABELPREFIX , savlabel ); 553 putprintf( ", 0x%x" , 0 , savmask() ); 554 putlab( botlabel ); 555 putprintf( " subl2 $LF%d,sp" , 0 , ftnno ); 556 putrbracket( ftnno ); 557 putjbr( toplabel ); 558 /* 559 * put down the entry point for formal calls 560 * the arguments for FCALL have been passed to us 561 * as hidden parameters after the regular arguments. 562 */ 563 if ( fp -> class != PROG ) { 564 putprintf( "%s%s:" , 0 , FORMALPREFIX , extname ); 565 putprintf( " .word " , 1 ); 566 putprintf( PREFIXFORMAT , 0 , LABELPREFIX , savlabel ); 567 putleaf( P2ICON , 0 , 0 , ADDTYPE( P2FTN | P2INT , P2PTR ) , 568 "_FCALL" ); 569 putRV( 0 , cbn , 570 fp -> value[ NL_OFFS ] + sizeof( struct formalrtn * ) , 571 NPARAM , 572 P2PTR | P2STRTY ); 573 putRV( 0 , cbn , fp -> value[ NL_OFFS ] , 574 NPARAM , P2PTR|P2STRTY ); 575 putop( P2LISTOP , P2INT ); 576 putop( P2CALL , P2INT ); 577 putdot( filename , line ); 578 putjbr( botlabel ); 579 } 580 /* 581 * declare pcp counters, if any 582 */ 583 if ( monflg && fp -> class == PROG ) { 584 putprintf( " .data" , 0 ); 585 putprintf( " .comm " , 1 ); 586 putprintf( PCPCOUNT , 1 ); 587 putprintf( ",%d" , 0 , ( cnts + 1 ) * sizeof (long) ); 588 putprintf( " .text" , 0 ); 589 } 590 # endif PC 591 #ifdef DEBUG 592 dumpnl(fp->ptr[2], fp->symbol); 593 #endif 594 595 #ifdef OBJ 596 /* 597 * save the namelist for the debugger pdx 598 */ 599 600 savenl(fp->ptr[2], fp->symbol); 601 #endif 602 603 /* 604 * Restore the 605 * (virtual) name list 606 * position 607 */ 608 nlfree(fp->ptr[2]); 609 /* 610 * Proc/func has been 611 * resolved 612 */ 613 fp->nl_flags &= ~NFORWD; 614 /* 615 * Patch the beg 616 * of the proc/func to 617 * the proper variable size 618 */ 619 if (Fp == NIL) 620 elineon(); 621 # ifdef OBJ 622 patchfil(var, (long)(-sizes[cbn].om_max), 2); 623 # endif OBJ 624 cbn--; 625 if (inpflist(fp->symbol)) { 626 opop('l'); 627 } 628 } 629 630 #ifdef PC 631 /* 632 * construct the long name of a function based on it's static nesting. 633 * into a caller-supplied buffer (that should be about BUFSIZ big). 634 */ 635 sextname( buffer , name , level ) 636 char buffer[]; 637 char *name; 638 int level; 639 { 640 char *starthere; 641 int i; 642 643 starthere = &buffer[0]; 644 for ( i = 1 ; i < level ; i++ ) { 645 sprintf( starthere , EXTFORMAT , enclosing[ i ] ); 646 starthere += strlen( enclosing[ i ] ) + 1; 647 } 648 sprintf( starthere , EXTFORMAT , name ); 649 starthere += strlen( name ) + 1; 650 if ( starthere >= &buffer[ BUFSIZ ] ) { 651 panic( "sextname" ); 652 } 653 } 654 #endif PC 655