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