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