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