1 #ifndef lint 2 static char *sccsid ="@(#)code.c 1.9 (Berkeley) 12/11/87"; 3 #endif lint 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 putstr( " ret\n" ); 27 } 28 else printf( " jbr L%d\n", n ); 29 } 30 31 int lastloc = { -1 }; 32 33 short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3}; 34 #define LOG2SZ 9 35 36 defalign(n) { 37 /* cause the alignment to become a multiple of n */ 38 n /= SZCHAR; 39 if( lastloc != PROG && n > 1 ) printf( " .align %d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 ); 40 } 41 42 locctr( l ){ 43 register temp; 44 /* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */ 45 46 if( l == lastloc ) return(l); 47 temp = lastloc; 48 lastloc = l; 49 if( nerrors ) return(temp); 50 switch( l ){ 51 52 case PROG: 53 putstr( " .text\n" ); 54 psline(); 55 break; 56 57 case DATA: 58 case ADATA: 59 putstr( " .data\n" ); 60 break; 61 62 case STRNG: 63 putstr( " .data 1\n" ); 64 break; 65 66 case ISTRNG: 67 putstr( " .data 2\n" ); 68 break; 69 70 case STAB: 71 putstr( " .stab\n" ); 72 break; 73 74 default: 75 cerror( "illegal location counter" ); 76 } 77 78 return( temp ); 79 } 80 81 #ifndef deflab 82 deflab( n ){ 83 /* output something to define the current position as label n */ 84 printf( "L%d:\n", n ); 85 } 86 #endif 87 88 int crslab = 10; 89 90 getlab(){ 91 /* return a number usable for a label */ 92 return( ++crslab ); 93 } 94 95 96 int ent_mask[] = { 97 0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0}; 98 99 int reg_use = 11; 100 101 efcode(){ 102 /* code for the end of a function */ 103 104 if( strftn ){ /* copy output (in R2) to caller */ 105 register NODE *l, *r; 106 register struct symtab *p; 107 register TWORD t; 108 int i; 109 110 p = &stab[curftn]; 111 t = p->stype; 112 t = DECREF(t); 113 114 deflab( retlab ); 115 116 i = getlab(); /* label for return area */ 117 #ifndef LCOMM 118 putstr(" .data\n" ); 119 putstr(" .align 2\n" ); 120 printf("L%d: .space %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR ); 121 putstr(" .text\n" ); 122 #else 123 { int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR; 124 if (sz % (SZINT/SZCHAR)) 125 sz += (SZINT/SZCHAR) - (sz % (SZINT/SZCHAR)); 126 printf(" .lcomm L%d,%d\n", i, sz); 127 } 128 #endif 129 psline(); 130 printf(" movab L%d,r1\n", i); 131 132 reached = 1; 133 l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); 134 l->tn.rval = 1; /* R1 */ 135 l->tn.lval = 0; /* no offset */ 136 r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); 137 r->tn.rval = 0; /* R0 */ 138 r->tn.lval = 0; 139 l = buildtree( UNARY MUL, l, NIL ); 140 r = buildtree( UNARY MUL, r, NIL ); 141 l = buildtree( ASSIGN, l, r ); 142 l->in.op = FREE; 143 ecomp( l->in.left ); 144 printf( " movab L%d,r0\n", i ); 145 /* turn off strftn flag, so return sequence will be generated */ 146 strftn = 0; 147 } 148 branch( retlab ); 149 #ifndef VMS 150 printf( " .set L%d,0x%x\n", ftnno, ent_mask[reg_use] ); 151 #else 152 printf( " .set L%d,%d # Hex = 0x%x\n", ftnno, 0x3c| ent_mask[reg_use], ent_mask[reg_use] ); 153 /* KLS kludge, under VMS if you use regs 2-5, you must save them. */ 154 #endif 155 reg_use = 11; 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 TRUST_REG_CHAR_AND_REG_SHORT 170 char *toreg(); 171 #endif 172 173 if( nerrors ) return; 174 (void) locctr( PROG ); 175 p = &stab[curftn]; 176 putstr( " .align 1\n"); 177 defnam( p ); 178 temp = p->stype; 179 temp = DECREF(temp); 180 strftn = (temp==STRTY) || (temp==UNIONTY); 181 182 retlab = getlab(); 183 184 /* routine prolog */ 185 186 printf( " .word L%d\n", ftnno); 187 ftlab1 = getlab(); 188 ftlab2 = getlab(); 189 printf( " jbr L%d\n", ftlab1); 190 printf( "L%d:\n", ftlab2); 191 if( proflg ) { /* profile code */ 192 i = getlab(); 193 printf(" movab L%d,r0\n", i); 194 putstr(" jsb mcount\n"); 195 putstr(" .data\n"); 196 putstr(" .align 2\n"); 197 printf("L%d: .long 0\n", i); 198 putstr(" .text\n"); 199 psline(); 200 } 201 202 off = ARGINIT; 203 204 for( i=0; i<n; ++i ){ 205 p = &stab[a[i]]; 206 if( p->sclass == REGISTER ){ 207 temp = p->offset; /* save register number */ 208 p->sclass = PARAM; /* forget that it is a register */ 209 p->offset = NOOFFSET; 210 (void) oalloc( p, &off ); 211 #ifdef TRUST_REG_CHAR_AND_REG_SHORT /* and reg double */ 212 /*tbl*/ printf( " %s %d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp ); 213 #else 214 /*tbl*/ printf( " movl %d(ap),r%d\n", p->offset/SZCHAR, temp ); 215 #endif 216 p->offset = temp; /* remember register number */ 217 p->sclass = REGISTER; /* remember that it is a register */ 218 } 219 else if( p->stype == STRTY || p->stype == UNIONTY ) { 220 p->offset = NOOFFSET; 221 if( oalloc( p, &off ) ) cerror( "bad argument" ); 222 SETOFF( off, ALSTACK ); 223 } 224 else { 225 if( oalloc( p, &off ) ) cerror( "bad argument" ); 226 } 227 228 } 229 if (gdebug && !nerrors) { 230 #ifdef STABDOT 231 pstabdot(N_SLINE, lineno); 232 #else 233 pstab(NULLNAME, N_SLINE); 234 printf("0,%d,LL%d\n", lineno, labelno); 235 printf("LL%d:\n", labelno++); 236 #endif 237 } 238 fdefflag = 1; 239 } 240 241 bccode(){ /* called just before the first executable statment */ 242 /* by now, the automatics and register variables are allocated */ 243 SETOFF( autooff, SZINT ); 244 /* set aside store area offset */ 245 p2bbeg( autooff, regvar ); 246 reg_use = (reg_use > regvar ? regvar : reg_use); 247 } 248 249 /*ARGSUSED*/ 250 ejobcode( flag ){ 251 /* called just before final exit */ 252 /* flag is 1 if errors, 0 if none */ 253 } 254 255 #ifndef aobeg 256 aobeg(){ 257 /* called before removing automatics from stab */ 258 } 259 #endif aobeg 260 261 #ifndef aocode 262 /*ARGSUSED*/ 263 aocode(p) struct symtab *p; { 264 /* called when automatic p removed from stab */ 265 } 266 #endif aocode 267 268 #ifndef aoend 269 aoend(){ 270 /* called after removing all automatics from stab */ 271 } 272 #endif aoend 273 274 defnam( p ) register struct symtab *p; { 275 /* define the current location as the name p->sname */ 276 277 if( p->sclass == EXTDEF ){ 278 printf( " .globl %s\n", exname( p->sname ) ); 279 } 280 if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset ); 281 else printf( "%s:\n", exname( p->sname ) ); 282 283 } 284 285 bycode( t, i ){ 286 #ifdef ASSTRINGS 287 static int lastoctal = 0; 288 #endif 289 290 /* put byte i+1 in a string */ 291 292 if ( nerrors ) return; 293 #ifdef ASSTRINGS 294 295 i &= 077; 296 if ( t < 0 ){ 297 if ( i != 0 ) putstr( "\"\n" ); 298 } else { 299 if ( i == 0 ) putstr("\t.ascii\t\""); 300 if ( t == '\\' || t == '"'){ 301 lastoctal = 0; 302 printf("\\%c", t); 303 } 304 /* 305 * We escape the colon in strings so that 306 * c2 will, in its infinite wisdom, interpret 307 * the characters preceding the colon as a label. 308 * If we didn't escape the colon, c2 would 309 * throw away any trailing blanks or tabs after 310 * the colon, but reconstruct a assembly 311 * language semantically correct program. 312 * C2 hasn't been taught about strings. 313 */ 314 else if ( t == ':' || t < 040 || t >= 0177 ){ 315 lastoctal++; 316 printf("\\%o",t); 317 } 318 else if ( lastoctal && '0' <= t && t <= '9' ){ 319 lastoctal = 0; 320 printf("\"\n\t.ascii\t\"%c", t ); 321 } 322 else 323 { 324 lastoctal = 0; 325 putchar(t); 326 } 327 if ( i == 077 ) putstr("\"\n"); 328 } 329 #else 330 331 i &= 07; 332 if( t < 0 ){ /* end of the string */ 333 if( i != 0 ) putchar( '\n' ); 334 } 335 336 else { /* stash byte t into string */ 337 if( i == 0 ) putstr( " .byte " ); 338 else putchar( ',' ); 339 printf( "0x%x", t ); 340 if( i == 07 ) putchar( '\n' ); 341 } 342 #endif 343 } 344 345 zecode( n ){ 346 /* n integer words of zeros */ 347 OFFSZ temp; 348 if( n <= 0 ) return; 349 printf( " .space %d\n", (SZINT/SZCHAR)*n ); 350 temp = n; 351 inoff += temp*SZINT; 352 } 353 354 /*ARGSUSED*/ 355 fldal( t ) unsigned t; { /* return the alignment of field of type t */ 356 uerror( "illegal field type" ); 357 return( ALINT ); 358 } 359 360 /*ARGSUSED*/ 361 fldty( p ) struct symtab *p; { /* fix up type of field p */ 362 ; 363 } 364 365 /*ARGSUSED*/ 366 where(c){ /* print location of error */ 367 /* c is either 'u', 'c', or 'w' */ 368 /* GCOS version */ 369 fprintf( stderr, "%s, line %d: ", ftitle, lineno ); 370 } 371 372 373 #ifdef TRUST_REG_CHAR_AND_REG_SHORT 374 /* tbl - toreg() returns a pointer to a char string 375 which is the correct "register move" for the passed type 376 */ 377 struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] = 378 { 379 INT, "movl", 380 UNSIGNED, "movl", 381 DOUBLE, "movq", 382 CHAR, "cvtbl", 383 SHORT, "cvtwl", 384 UCHAR, "movzbl", 385 USHORT, "movzwl", 386 0, "" 387 }; 388 389 char 390 *toreg(type) 391 TWORD type; 392 { 393 struct type_move *p; 394 395 for ( p=toreg_strs; p->fromtype != 0; p++) 396 if (p->fromtype == type) return(p->tostrng); 397 398 /* type not found, must be a pointer type */ 399 return("movl"); 400 } 401 /* tbl */ 402 #endif 403 404 405 main( argc, argv ) char *argv[]; { 406 #ifdef BUFSTDERR 407 char errbuf[BUFSIZ]; 408 setbuf(stderr, errbuf); 409 #endif 410 return(mainp1( argc, argv )); 411 } 412 413 struct sw heapsw[SWITSZ]; /* heap for switches */ 414 415 genswitch(p,n) register struct sw *p;{ 416 /* p points to an array of structures, each consisting 417 of a constant value and a label. 418 The first is >=0 if there is a default label; 419 its value is the label number 420 The entries p[1] to p[n] are the nontrivial cases 421 */ 422 register i; 423 register CONSZ j, range; 424 register dlab, swlab; 425 426 if( nerrors ) return; 427 range = p[n].sval-p[1].sval; 428 429 if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */ 430 431 swlab = getlab(); 432 dlab = p->slab >= 0 ? p->slab : getlab(); 433 434 /* already in r0 */ 435 printf(" casel r0,$%ld,$%ld\n", p[1].sval, range); 436 printf("L%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 printf(" cmpl r0,$%d\n", heapsw[start].sval); 508 printf(" 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