1 #ifndef lint 2 static char *sccsid ="@(#)code.c 1.8 (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 deflab 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 % sizeof (int)) 125 sz += sizeof (int) - (sz % sizeof (int)); 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 char *toreg(); 170 171 if( nerrors ) return; 172 (void) locctr( PROG ); 173 p = &stab[curftn]; 174 putstr( " .align 1\n"); 175 defnam( p ); 176 temp = p->stype; 177 temp = DECREF(temp); 178 strftn = (temp==STRTY) || (temp==UNIONTY); 179 180 retlab = getlab(); 181 182 /* routine prolog */ 183 184 printf( " .word L%d\n", ftnno); 185 ftlab1 = getlab(); 186 ftlab2 = getlab(); 187 printf( " jbr L%d\n", ftlab1); 188 printf( "L%d:\n", ftlab2); 189 if( proflg ) { /* profile code */ 190 i = getlab(); 191 printf(" movab L%d,r0\n", i); 192 putstr(" jsb mcount\n"); 193 putstr(" .data\n"); 194 putstr(" .align 2\n"); 195 printf("L%d: .long 0\n", i); 196 putstr(" .text\n"); 197 psline(); 198 } 199 200 off = ARGINIT; 201 202 for( i=0; i<n; ++i ){ 203 p = &stab[a[i]]; 204 if( p->sclass == REGISTER ){ 205 temp = p->offset; /* save register number */ 206 p->sclass = PARAM; /* forget that it is a register */ 207 p->offset = NOOFFSET; 208 (void) oalloc( p, &off ); 209 /*tbl*/ printf( " %s %d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp ); 210 p->offset = temp; /* remember register number */ 211 p->sclass = REGISTER; /* remember that it is a register */ 212 } 213 else if( p->stype == STRTY || p->stype == UNIONTY ) { 214 p->offset = NOOFFSET; 215 if( oalloc( p, &off ) ) cerror( "bad argument" ); 216 SETOFF( off, ALSTACK ); 217 } 218 else { 219 if( oalloc( p, &off ) ) cerror( "bad argument" ); 220 } 221 222 } 223 if (gdebug && !nerrors) { 224 #ifdef STABDOT 225 pstabdot(N_SLINE, lineno); 226 #else 227 pstab(NULLNAME, N_SLINE); 228 printf("0,%d,LL%d\n", lineno, labelno); 229 printf("LL%d:\n", labelno++); 230 #endif 231 } 232 fdefflag = 1; 233 } 234 235 bccode(){ /* called just before the first executable statment */ 236 /* by now, the automatics and register variables are allocated */ 237 SETOFF( autooff, SZINT ); 238 /* set aside store area offset */ 239 p2bbeg( autooff, regvar ); 240 reg_use = (reg_use > regvar ? regvar : reg_use); 241 } 242 243 /*ARGSUSED*/ 244 ejobcode( flag ){ 245 /* called just before final exit */ 246 /* flag is 1 if errors, 0 if none */ 247 } 248 249 #ifndef aobeg 250 aobeg(){ 251 /* called before removing automatics from stab */ 252 } 253 #endif aobeg 254 255 #ifndef aocode 256 /*ARGSUSED*/ 257 aocode(p) struct symtab *p; { 258 /* called when automatic p removed from stab */ 259 } 260 #endif aocode 261 262 #ifndef aoend 263 aoend(){ 264 /* called after removing all automatics from stab */ 265 } 266 #endif aoend 267 268 defnam( p ) register struct symtab *p; { 269 /* define the current location as the name p->sname */ 270 271 if( p->sclass == EXTDEF ){ 272 printf( " .globl %s\n", exname( p->sname ) ); 273 } 274 if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset ); 275 else printf( "%s:\n", exname( p->sname ) ); 276 277 } 278 279 bycode( t, i ){ 280 #ifdef ASSTRINGS 281 static int lastoctal = 0; 282 #endif 283 284 /* put byte i+1 in a string */ 285 286 if ( nerrors ) return; 287 #ifdef ASSTRINGS 288 289 i &= 077; 290 if ( t < 0 ){ 291 if ( i != 0 ) putstr( "\"\n" ); 292 } else { 293 if ( i == 0 ) putstr("\t.ascii\t\""); 294 if ( t == '\\' || t == '"'){ 295 lastoctal = 0; 296 printf("\\%c", t); 297 } 298 /* 299 * We escape the colon in strings so that 300 * c2 will, in its infinite wisdom, interpret 301 * the characters preceding the colon as a label. 302 * If we didn't escape the colon, c2 would 303 * throw away any trailing blanks or tabs after 304 * the colon, but reconstruct a assembly 305 * language semantically correct program. 306 * C2 hasn't been taught about strings. 307 */ 308 else if ( t == ':' || t < 040 || t >= 0177 ){ 309 lastoctal++; 310 printf("\\%o",t); 311 } 312 else if ( lastoctal && '0' <= t && t <= '9' ){ 313 lastoctal = 0; 314 printf("\"\n\t.ascii\t\"%c", t ); 315 } 316 else 317 { 318 lastoctal = 0; 319 putchar(t); 320 } 321 if ( i == 077 ) putstr("\"\n"); 322 } 323 #else 324 325 i &= 07; 326 if( t < 0 ){ /* end of the string */ 327 if( i != 0 ) putchar( '\n' ); 328 } 329 330 else { /* stash byte t into string */ 331 if( i == 0 ) putstr( " .byte " ); 332 else putchar( ',' ); 333 printf( "0x%x", t ); 334 if( i == 07 ) putchar( '\n' ); 335 } 336 #endif 337 } 338 339 zecode( n ){ 340 /* n integer words of zeros */ 341 OFFSZ temp; 342 if( n <= 0 ) return; 343 printf( " .space %d\n", (SZINT/SZCHAR)*n ); 344 temp = n; 345 inoff += temp*SZINT; 346 } 347 348 /*ARGSUSED*/ 349 fldal( t ) unsigned t; { /* return the alignment of field of type t */ 350 uerror( "illegal field type" ); 351 return( ALINT ); 352 } 353 354 /*ARGSUSED*/ 355 fldty( p ) struct symtab *p; { /* fix up type of field p */ 356 ; 357 } 358 359 /*ARGSUSED*/ 360 where(c){ /* print location of error */ 361 /* c is either 'u', 'c', or 'w' */ 362 /* GCOS version */ 363 fprintf( stderr, "%s, line %d: ", ftitle, lineno ); 364 } 365 366 367 /* tbl - toreg() returns a pointer to a char string 368 which is the correct "register move" for the passed type 369 */ 370 struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] = 371 { 372 CHAR, "cvtbl", 373 SHORT, "cvtwl", 374 INT, "movl", 375 LONG, "movl", 376 FLOAT, "movf", 377 DOUBLE, "movd", 378 UCHAR, "movzbl", 379 USHORT, "movzwl", 380 UNSIGNED, "movl", 381 ULONG, "movl", 382 0, "" 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 pointer type */ 395 return("movl"); 396 } 397 /* tbl */ 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, range; 419 register dlab, swlab; 420 421 if( nerrors ) return; 422 range = p[n].sval-p[1].sval; 423 424 if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */ 425 426 swlab = getlab(); 427 dlab = p->slab >= 0 ? p->slab : getlab(); 428 429 /* already in r0 */ 430 printf(" casel r0,$%ld,$%ld\n", p[1].sval, range); 431 printf("L%d:\n", swlab); 432 for( i=1,j=p[1].sval; i<=n; j++) { 433 printf(" .word L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab), 434 swlab); 435 } 436 437 if( p->slab >= 0 ) branch( dlab ); 438 else printf("L%d:\n", dlab); 439 return; 440 441 } 442 443 if( n>8 ) { /* heap switch */ 444 445 heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab(); 446 makeheap(p, n, 1); /* build heap */ 447 448 walkheap(1, n); /* produce code */ 449 450 if( p->slab >= 0 ) 451 branch( dlab ); 452 else 453 printf("L%d:\n", dlab); 454 return; 455 } 456 457 /* debugging code */ 458 459 /* out for the moment 460 if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) ); 461 */ 462 463 /* simple switch code */ 464 465 for( i=1; i<=n; ++i ){ 466 /* already in r0 */ 467 468 putstr( " cmpl r0,$" ); 469 printf( CONFMT, p[i].sval ); 470 printf( "\n jeql L%d\n", p[i].slab ); 471 } 472 473 if( p->slab>=0 ) branch( p->slab ); 474 } 475 476 makeheap(p, m, n) 477 register struct sw *p; 478 { 479 register int q; 480 481 q = selectheap(m); 482 heapsw[n] = p[q]; 483 if( q>1 ) makeheap(p, q-1, 2*n); 484 if( q<m ) makeheap(p+q, m-q, 2*n+1); 485 } 486 487 selectheap(m) { 488 register int l,i,k; 489 490 for(i=1; ; i*=2) 491 if( (i-1) > m ) break; 492 l = ((k = i/2 - 1) + 1)/2; 493 return( l + (m-k < l ? m-k : l)); 494 } 495 496 walkheap(start, limit) 497 { 498 int label; 499 500 501 if( start > limit ) return; 502 printf(" cmpl r0,$%d\n", heapsw[start].sval); 503 printf(" jeql L%d\n", heapsw[start].slab); 504 if( (2*start) > limit ) { 505 printf(" jbr L%d\n", heapsw[0].slab); 506 return; 507 } 508 if( (2*start+1) <= limit ) { 509 label = getlab(); 510 printf(" jgtr L%d\n", label); 511 } else 512 printf(" jgtr L%d\n", heapsw[0].slab); 513 walkheap( 2*start, limit); 514 if( (2*start+1) <= limit ) { 515 printf("L%d:\n", label); 516 walkheap( 2*start+1, limit); 517 } 518 } 519