1 #ifndef lint 2 static char *sccsid ="@(#)code.c 1.7 (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 /*ARGSUSED*/ 242 ejobcode( flag ){ 243 /* called just before final exit */ 244 /* flag is 1 if errors, 0 if none */ 245 } 246 247 #ifndef aobeg 248 aobeg(){ 249 /* called before removing automatics from stab */ 250 } 251 #endif aobeg 252 253 #ifndef aocode 254 /*ARGSUSED*/ 255 aocode(p) struct symtab *p; { 256 /* called when automatic p removed from stab */ 257 } 258 #endif aocode 259 260 #ifndef aoend 261 aoend(){ 262 /* called after removing all automatics from stab */ 263 } 264 #endif aoend 265 266 defnam( p ) register struct symtab *p; { 267 /* define the current location as the name p->sname */ 268 269 if( p->sclass == EXTDEF ){ 270 printf( " .globl %s\n", exname( p->sname ) ); 271 } 272 if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset ); 273 else printf( "%s:\n", exname( p->sname ) ); 274 275 } 276 277 bycode( t, i ){ 278 #ifdef ASSTRINGS 279 static int lastoctal = 0; 280 #endif 281 282 /* put byte i+1 in a string */ 283 284 if ( nerrors ) return; 285 #ifdef ASSTRINGS 286 287 i &= 077; 288 if ( t < 0 ){ 289 if ( i != 0 ) putstr( "\"\n" ); 290 } else { 291 if ( i == 0 ) putstr("\t.ascii\t\""); 292 if ( t == '\\' || t == '"'){ 293 lastoctal = 0; 294 printf("\\%c", t); 295 } 296 /* 297 * We escape the colon in strings so that 298 * c2 will, in its infinite wisdom, interpret 299 * the characters preceding the colon as a label. 300 * If we didn't escape the colon, c2 would 301 * throw away any trailing blanks or tabs after 302 * the colon, but reconstruct a assembly 303 * language semantically correct program. 304 * C2 hasn't been taught about strings. 305 */ 306 else if ( t == ':' || t < 040 || t >= 0177 ){ 307 lastoctal++; 308 printf("\\%o",t); 309 } 310 else if ( lastoctal && '0' <= t && t <= '9' ){ 311 lastoctal = 0; 312 printf("\"\n\t.ascii\t\"%c", t ); 313 } 314 else 315 { 316 lastoctal = 0; 317 putchar(t); 318 } 319 if ( i == 077 ) putstr("\"\n"); 320 } 321 #else 322 323 i &= 07; 324 if( t < 0 ){ /* end of the string */ 325 if( i != 0 ) putchar( '\n' ); 326 } 327 328 else { /* stash byte t into string */ 329 if( i == 0 ) putstr( " .byte " ); 330 else putchar( ',' ); 331 printf( "0x%x", t ); 332 if( i == 07 ) putchar( '\n' ); 333 } 334 #endif 335 } 336 337 zecode( n ){ 338 /* n integer words of zeros */ 339 OFFSZ temp; 340 if( n <= 0 ) return; 341 printf( " .space %d\n", (SZINT/SZCHAR)*n ); 342 temp = n; 343 inoff += temp*SZINT; 344 } 345 346 /*ARGSUSED*/ 347 fldal( t ) unsigned t; { /* return the alignment of field of type t */ 348 uerror( "illegal field type" ); 349 return( ALINT ); 350 } 351 352 /*ARGSUSED*/ 353 fldty( p ) struct symtab *p; { /* fix up type of field p */ 354 ; 355 } 356 357 /*ARGSUSED*/ 358 where(c){ /* print location of error */ 359 /* c is either 'u', 'c', or 'w' */ 360 /* GCOS version */ 361 fprintf( stderr, "%s, line %d: ", ftitle, lineno ); 362 } 363 364 365 /* tbl - toreg() returns a pointer to a char string 366 which is the correct "register move" for the passed type 367 */ 368 struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] = 369 { 370 CHAR, "cvtbl", 371 SHORT, "cvtwl", 372 INT, "movl", 373 LONG, "movl", 374 FLOAT, "movf", 375 DOUBLE, "movd", 376 UCHAR, "movzbl", 377 USHORT, "movzwl", 378 UNSIGNED, "movl", 379 ULONG, "movl", 380 0, "" 381 }; 382 383 char 384 *toreg(type) 385 TWORD type; 386 { 387 struct type_move *p; 388 389 for ( p=toreg_strs; p->fromtype != 0; p++) 390 if (p->fromtype == type) return(p->tostrng); 391 392 /* type not found, must be a pointer type */ 393 return("movl"); 394 } 395 /* tbl */ 396 397 398 main( argc, argv ) char *argv[]; { 399 #ifdef BUFSTDERR 400 char errbuf[BUFSIZ]; 401 setbuf(stderr, errbuf); 402 #endif 403 return(mainp1( argc, argv )); 404 } 405 406 struct sw heapsw[SWITSZ]; /* heap for switches */ 407 408 genswitch(p,n) register struct sw *p;{ 409 /* p points to an array of structures, each consisting 410 of a constant value and a label. 411 The first is >=0 if there is a default label; 412 its value is the label number 413 The entries p[1] to p[n] are the nontrivial cases 414 */ 415 register i; 416 register CONSZ j, range; 417 register dlab, swlab; 418 419 if( nerrors ) return; 420 range = p[n].sval-p[1].sval; 421 422 if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */ 423 424 swlab = getlab(); 425 dlab = p->slab >= 0 ? p->slab : getlab(); 426 427 /* already in r0 */ 428 printf(" casel r0,$%ld,$%ld\n", p[1].sval, range); 429 printf("L%d:\n", swlab); 430 for( i=1,j=p[1].sval; i<=n; j++) { 431 printf(" .word L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab), 432 swlab); 433 } 434 435 if( p->slab >= 0 ) branch( dlab ); 436 else printf("L%d:\n", dlab); 437 return; 438 439 } 440 441 if( n>8 ) { /* heap switch */ 442 443 heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab(); 444 makeheap(p, n, 1); /* build heap */ 445 446 walkheap(1, n); /* produce code */ 447 448 if( p->slab >= 0 ) 449 branch( dlab ); 450 else 451 printf("L%d:\n", dlab); 452 return; 453 } 454 455 /* debugging code */ 456 457 /* out for the moment 458 if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) ); 459 */ 460 461 /* simple switch code */ 462 463 for( i=1; i<=n; ++i ){ 464 /* already in r0 */ 465 466 putstr( " cmpl r0,$" ); 467 printf( CONFMT, p[i].sval ); 468 printf( "\n jeql L%d\n", p[i].slab ); 469 } 470 471 if( p->slab>=0 ) branch( p->slab ); 472 } 473 474 makeheap(p, m, n) 475 register struct sw *p; 476 { 477 register int q; 478 479 q = select(m); 480 heapsw[n] = p[q]; 481 if( q>1 ) makeheap(p, q-1, 2*n); 482 if( q<m ) makeheap(p+q, m-q, 2*n+1); 483 } 484 485 select(m) { 486 register int l,i,k; 487 488 for(i=1; ; i*=2) 489 if( (i-1) > m ) break; 490 l = ((k = i/2 - 1) + 1)/2; 491 return( l + (m-k < l ? m-k : l)); 492 } 493 494 walkheap(start, limit) 495 { 496 int label; 497 498 499 if( start > limit ) return; 500 printf(" cmpl r0,$%d\n", heapsw[start].sval); 501 printf(" jeql L%d\n", heapsw[start].slab); 502 if( (2*start) > limit ) { 503 printf(" jbr L%d\n", heapsw[0].slab); 504 return; 505 } 506 if( (2*start+1) <= limit ) { 507 label = getlab(); 508 printf(" jgtr L%d\n", label); 509 } else 510 printf(" jgtr L%d\n", heapsw[0].slab); 511 walkheap( 2*start, limit); 512 if( (2*start+1) <= limit ) { 513 printf("L%d:\n", label); 514 walkheap( 2*start+1, limit); 515 } 516 } 517