1 #ifndef lint 2 static char sccsid[] = "@(#)code.c 1.6 (Berkeley) 05/31/88"; 3 #endif 4 5 # include "pass1.h" 6 # include <sys/types.h> 7 # include <a.out.h> 8 # include <stab.h> 9 10 int proflg = 0; /* are we generating profiling code? */ 11 int strftn = 0; /* is the current function one which returns a value */ 12 int gdebug; 13 int fdefflag; /* are we within a function definition ? */ 14 #ifndef STABDOT 15 char NULLNAME[8]; 16 #endif 17 int labelno; 18 19 # define putstr(s) fputs((s), stdout) 20 21 branch( n ){ 22 /* output a branch to label n */ 23 /* exception is an ordinary function branching to retlab: then, return */ 24 if( nerrors ) return; 25 if( n == retlab && !strftn ){ 26 register TWORD t; 27 register r; 28 /* set number of regs in assem comment field */ 29 /* so optimizers can do a better job */ 30 r = 0; 31 if( retstat & RETVAL ){ /* the function rets a val somewhere */ 32 t = (&stab[curftn])->stype; 33 t = DECREF(t); 34 r++; /* it is at least one */ 35 if(t == DOUBLE) 36 r++; /* it takes two */ 37 } else /* the fn does not ret a val */ 38 r = 2; 39 printf( " ret#%d\n", r ); 40 } 41 else printf( " jbr L%d\n", n ); 42 } 43 44 int lastloc = { -1 }; 45 46 short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3}; 47 #define LOG2SZ 9 48 49 defalign(n) { 50 /* cause the alignment to become a multiple of n */ 51 n /= SZCHAR; 52 if( lastloc != PROG && n > 1 ) printf( " .align %d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 ); 53 } 54 55 locctr( l ){ 56 register temp; 57 /* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */ 58 59 if( l == lastloc ) return(l); 60 temp = lastloc; 61 lastloc = l; 62 if( nerrors ) return(temp); 63 switch( l ){ 64 65 case PROG: 66 putstr( " .text\n" ); 67 psline(); 68 break; 69 70 case DATA: 71 case ADATA: 72 putstr( " .data\n" ); 73 break; 74 75 case STRNG: 76 putstr( " .data 1\n" ); 77 break; 78 79 case ISTRNG: 80 putstr( " .data 2\n" ); 81 break; 82 83 case STAB: 84 putstr( " .stab\n" ); 85 break; 86 87 default: 88 cerror( "illegal location counter" ); 89 } 90 91 return( temp ); 92 } 93 94 deflab( n ){ 95 /* output something to define the current position as label n */ 96 if (nerrors) return; 97 printf( "L%d:\n", n ); 98 } 99 100 int crslab = 10; 101 102 getlab(){ 103 /* return a number usable for a label */ 104 return( ++crslab ); 105 } 106 107 108 efcode(){ 109 /* code for the end of a function */ 110 111 if( strftn ){ /* copy output (in R2) to caller */ 112 register NODE *l, *r; 113 register struct symtab *p; 114 register TWORD t; 115 register int i; 116 117 p = &stab[curftn]; 118 t = p->stype; 119 t = DECREF(t); 120 121 deflab( retlab ); 122 123 i = getlab(); /* label for return area */ 124 #ifndef LCOMM 125 putstr(" .data\n" ); 126 putstr(" .align 2\n" ); 127 printf("L%d: .space %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR ); 128 putstr(" .text\n" ); 129 #else 130 { int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR; 131 if (sz % (SZINT/SZCHAR)) 132 sz += (SZINT/SZCHAR) - (sz % (SZINT/SZCHAR)); 133 printf(" .lcomm L%d,%d\n", i, sz); 134 } 135 #endif 136 psline(); 137 printf(" movab L%d,r1\n", i); 138 139 reached = 1; 140 l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); 141 l->tn.rval = 1; /* R1 */ 142 l->tn.lval = 0; /* no offset */ 143 r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); 144 r->tn.rval = 0; /* R0 */ 145 r->tn.lval = 0; 146 l = buildtree( UNARY MUL, l, NIL ); 147 r = buildtree( UNARY MUL, r, NIL ); 148 l = buildtree( ASSIGN, l, r ); 149 l->in.op = FREE; 150 ecomp( l->in.left ); 151 printf( " movab L%d,r0\n", i ); 152 /* turn off strftn flag, so return sequence will be generated */ 153 strftn = 0; 154 } 155 branch( retlab ); 156 p2bend(); 157 fdefflag = 0; 158 } 159 160 int ftlab1, ftlab2; 161 162 bfcode( a, n ) int a[]; { 163 /* code for the beginning of a function; a is an array of 164 indices in stab for the arguments; n is the number */ 165 register i; 166 register temp; 167 register struct symtab *p; 168 int off; 169 #ifdef REG_CHAR 170 char *toreg(); 171 #endif 172 char *rname(); 173 174 if( nerrors ) return; 175 (void) locctr( PROG ); 176 p = &stab[curftn]; 177 putstr( " .align 1\n"); 178 defnam( p ); 179 temp = p->stype; 180 temp = DECREF(temp); 181 strftn = (temp==STRTY) || (temp==UNIONTY); 182 183 retlab = getlab(); 184 185 /* routine prolog */ 186 187 printf( " .word L%d\n", ftnno); 188 ftlab1 = getlab(); 189 ftlab2 = getlab(); 190 printf( " jbr L%d\n", ftlab1); 191 printf( "L%d:\n", ftlab2); 192 if( proflg ) { /* profile code */ 193 i = getlab(); 194 printf(" pushl $L%d\n", i); 195 putstr(" callf $8,mcount\n"); 196 putstr(" .data\n"); 197 putstr(" .align 2\n"); 198 printf("L%d: .long 0\n", i); 199 putstr(" .text\n"); 200 psline(); 201 } 202 203 off = ARGINIT; 204 205 for( i=0; i<n; ++i ){ 206 p = &stab[a[i]]; 207 if( p->sclass == REGISTER ){ 208 temp = p->offset; /* save register number */ 209 p->sclass = PARAM; /* forget that it is a register */ 210 p->offset = NOOFFSET; 211 (void) oalloc( p, &off ); 212 #ifdef REG_CHAR 213 printf( " %s", toreg(p->stype)) ); 214 #else 215 putstr(" movl"); 216 #endif 217 printf( " %d(fp),%s\n", p->offset/SZCHAR, rname(temp) ); 218 p->offset = temp; /* remember register number */ 219 p->sclass = REGISTER; /* remember that it is a register */ 220 #ifdef REG_CHAR 221 temp = p->stype; 222 if( temp==CHAR || temp==SHORT ) 223 p->stype = INT; 224 else if( temp==UCHAR || temp==USHORT ) 225 p->stype = UNSIGNED; 226 #endif 227 } 228 else if( p->stype == STRTY || p->stype == UNIONTY ) { 229 p->offset = NOOFFSET; 230 if( oalloc( p, &off ) ) cerror( "bad argument" ); 231 SETOFF( off, ALSTACK ); 232 } 233 else { 234 if( oalloc( p, &off ) ) cerror( "bad argument" ); 235 } 236 237 } 238 if (gdebug && !nerrors) { 239 #ifdef STABDOT 240 pstabdot(N_SLINE, lineno); 241 #else 242 pstab(NULLNAME, N_SLINE); 243 printf("0,%d,LL%d\n", lineno, labelno); 244 printf("LL%d:\n", labelno++); 245 #endif 246 } 247 fdefflag = 1; 248 } 249 250 bccode(){ /* called just before the first executable statment */ 251 /* by now, the automatics and register variables are allocated */ 252 SETOFF( autooff, SZINT ); 253 /* set aside store area offset */ 254 p2bbeg( autooff, regvar ); 255 } 256 257 /*ARGSUSED*/ 258 ejobcode( flag ){ 259 /* called just before final exit */ 260 /* flag is 1 if errors, 0 if none */ 261 } 262 263 #ifndef aobeg 264 aobeg(){ 265 /* called before removing automatics from stab */ 266 } 267 #endif aobeg 268 269 #ifndef aocode 270 /*ARGSUSED*/ 271 aocode(p) struct symtab *p; { 272 /* called when automatic p removed from stab */ 273 } 274 #endif aocode 275 276 #ifndef aoend 277 aoend(){ 278 /* called after removing all automatics from stab */ 279 } 280 #endif aoend 281 282 defnam( p ) register struct symtab *p; { 283 /* define the current location as the name p->sname */ 284 285 if( p->sclass == EXTDEF ){ 286 printf( " .globl %s\n", exname( p->sname ) ); 287 } 288 if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset ); 289 else printf( "%s:\n", exname( p->sname ) ); 290 291 } 292 293 bycode( t, i ){ 294 #ifdef ASSTRINGS 295 static int lastoctal = 0; 296 #endif 297 298 /* put byte i+1 in a string */ 299 300 if ( nerrors ) return; 301 #ifdef ASSTRINGS 302 303 i &= 077; 304 if ( t < 0 ){ 305 if ( i != 0 ) putstr( "\"\n" ); 306 } else { 307 if ( i == 0 ) putstr("\t.ascii\t\""); 308 if ( t == '\\' || t == '"'){ 309 lastoctal = 0; 310 printf("\\%c", t); 311 } 312 else if ( t < 040 || t >= 0177 ){ 313 lastoctal++; 314 printf("\\%o",t); 315 } 316 else if ( lastoctal && '0' <= t && t <= '9' ){ 317 lastoctal = 0; 318 printf("\"\n\t.ascii\t\"%c", t ); 319 } 320 else 321 { 322 lastoctal = 0; 323 putchar(t); 324 } 325 if ( i == 077 ) putstr("\"\n"); 326 } 327 #else 328 329 i &= 07; 330 if( t < 0 ){ /* end of the string */ 331 if( i != 0 ) putchar( '\n' ); 332 } 333 334 else { /* stash byte t into string */ 335 if( i == 0 ) putstr( " .byte " ); 336 else putchar( ',' ); 337 printf( "0x%x", t ); 338 if( i == 07 ) putchar( '\n' ); 339 } 340 #endif 341 } 342 343 zecode( n ){ 344 /* n integer words of zeros */ 345 OFFSZ temp; 346 if( n <= 0 ) return; 347 printf( " .space %d\n", (SZINT/SZCHAR)*n ); 348 temp = n; 349 inoff += temp*SZINT; 350 } 351 352 /*ARGSUSED*/ 353 fldal( t ) unsigned t; { /* return the alignment of field of type t */ 354 uerror( "illegal field type" ); 355 return( ALINT ); 356 } 357 358 /*ARGSUSED*/ 359 fldty( p ) struct symtab *p; { /* fix up type of field p */ 360 ; 361 } 362 363 /*ARGSUSED*/ 364 where(c){ /* print location of error */ 365 /* c is either 'u', 'c', or 'w' */ 366 /* GCOS version */ 367 fprintf( stderr, "%s, line %d: ", ftitle, lineno ); 368 } 369 370 371 #ifdef REG_CHAR 372 /* tbl - toreg() returns a pointer to a char string 373 which is the correct "register move" for the passed type 374 */ 375 struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] = 376 { 377 CHAR, "cvtbl", 378 SHORT, "cvtwl", 379 UCHAR, "movzbl", 380 USHORT, "movzwl", 381 0, "movl" 382 }; 383 384 char 385 *toreg(type) 386 TWORD type; 387 { 388 struct type_move *p; 389 390 for ( p=toreg_strs; p->fromtype != 0; p++) 391 if (p->fromtype == type) return(p->tostrng); 392 393 /* type not found, must be a word type */ 394 return(p->tostrng); 395 } 396 /* tbl */ 397 #endif 398 399 400 main( argc, argv ) char *argv[]; { 401 #ifdef BUFSTDERR 402 char errbuf[BUFSIZ]; 403 setbuf(stderr, errbuf); 404 #endif 405 return(mainp1( argc, argv )); 406 } 407 408 struct sw heapsw[SWITSZ]; /* heap for switches */ 409 410 genswitch(p,n) register struct sw *p;{ 411 /* p points to an array of structures, each consisting 412 of a constant value and a label. 413 The first is >=0 if there is a default label; 414 its value is the label number 415 The entries p[1] to p[n] are the nontrivial cases 416 */ 417 register i; 418 register CONSZ j; 419 register CONSZ unsigned range; 420 register dlab, swlab; 421 422 if( nerrors ) return; 423 range = p[n].sval-p[1].sval; 424 425 if( range <= 3*n && n>=4 ){ /* implement a direct switch */ 426 427 swlab = getlab(); 428 dlab = p->slab >= 0 ? p->slab : getlab(); 429 430 /* already in r0 */ 431 putstr( " casel r0,$" ); 432 printf( CONFMT, p[1].sval ); 433 putstr(",$"); 434 printf( CONFMT, range); 435 printf("\n .align 1\nL%d:\n", swlab); 436 for( i=1,j=p[1].sval; i<=n; j++) { 437 printf(" .word L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab), 438 swlab); 439 } 440 441 if( p->slab >= 0 ) branch( dlab ); 442 else printf("L%d:\n", dlab); 443 return; 444 445 } 446 447 if( n>8 ) { /* heap switch */ 448 449 heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab(); 450 makeheap(p, n, 1); /* build heap */ 451 452 walkheap(1, n); /* produce code */ 453 454 if( p->slab >= 0 ) 455 branch( dlab ); 456 else 457 printf("L%d:\n", dlab); 458 return; 459 } 460 461 /* debugging code */ 462 463 /* out for the moment 464 if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) ); 465 */ 466 467 /* simple switch code */ 468 469 for( i=1; i<=n; ++i ){ 470 /* already in r0 */ 471 472 putstr( " cmpl r0,$" ); 473 printf( CONFMT, p[i].sval ); 474 printf( "\n jeql L%d\n", p[i].slab ); 475 } 476 477 if( p->slab>=0 ) branch( p->slab ); 478 } 479 480 makeheap(p, m, n) 481 register struct sw *p; 482 { 483 register int q; 484 485 q = selectheap(m); 486 heapsw[n] = p[q]; 487 if( q>1 ) makeheap(p, q-1, 2*n); 488 if( q<m ) makeheap(p+q, m-q, 2*n+1); 489 } 490 491 selectheap(m) { 492 register int l,i,k; 493 494 for(i=1; ; i*=2) 495 if( (i-1) > m ) break; 496 l = ((k = i/2 - 1) + 1)/2; 497 return( l + (m-k < l ? m-k : l)); 498 } 499 500 walkheap(start, limit) 501 { 502 int label; 503 504 505 if( start > limit ) return; 506 putstr( " cmpl r0,$" ); 507 printf( CONFMT, heapsw[start].sval); 508 printf("\n jeql L%d\n", heapsw[start].slab); 509 if( (2*start) > limit ) { 510 printf(" jbr L%d\n", heapsw[0].slab); 511 return; 512 } 513 if( (2*start+1) <= limit ) { 514 label = getlab(); 515 printf(" jgtr L%d\n", label); 516 } else 517 printf(" jgtr L%d\n", heapsw[0].slab); 518 walkheap( 2*start, limit); 519 if( (2*start+1) <= limit ) { 520 printf("L%d:\n", label); 521 walkheap( 2*start+1, limit); 522 } 523 } 524