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