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