117737Sralph #ifndef lint 2*24416Smckusick static char *sccsid ="@(#)code.c 1.5 (Berkeley) 08/23/85"; 317737Sralph #endif lint 417737Sralph 518556Sralph # include "pass1.h" 69700Slinton # include <sys/types.h> 79700Slinton # include <a.out.h> 89700Slinton # include <stab.h> 99700Slinton 109700Slinton int proflg = 0; /* are we generating profiling code? */ 119700Slinton int strftn = 0; /* is the current function one which returns a value */ 129700Slinton int gdebug; 139700Slinton int fdefflag; /* are we within a function definition ? */ 149700Slinton char NULLNAME[8]; 159700Slinton int labelno; 169700Slinton 17*24416Smckusick # define putstr(s) fputs((s), stdout) 18*24416Smckusick 199700Slinton branch( n ){ 209700Slinton /* output a branch to label n */ 219700Slinton /* exception is an ordinary function branching to retlab: then, return */ 229700Slinton if( n == retlab && !strftn ){ 23*24416Smckusick putstr( " ret\n" ); 249700Slinton } 259700Slinton else printf( " jbr L%d\n", n ); 269700Slinton } 279700Slinton 289700Slinton int lastloc = { -1 }; 299700Slinton 309700Slinton short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3}; 319700Slinton #define LOG2SZ 9 329700Slinton 339700Slinton defalign(n) { 349700Slinton /* cause the alignment to become a multiple of n */ 359700Slinton n /= SZCHAR; 369700Slinton if( lastloc != PROG && n > 1 ) printf( " .align %d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 ); 379700Slinton } 389700Slinton 399700Slinton locctr( l ){ 409700Slinton register temp; 419700Slinton /* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */ 429700Slinton 439700Slinton if( l == lastloc ) return(l); 449700Slinton temp = lastloc; 459700Slinton lastloc = l; 469700Slinton switch( l ){ 479700Slinton 489700Slinton case PROG: 49*24416Smckusick putstr( " .text\n" ); 509700Slinton psline(); 519700Slinton break; 529700Slinton 539700Slinton case DATA: 549700Slinton case ADATA: 55*24416Smckusick putstr( " .data\n" ); 569700Slinton break; 579700Slinton 589700Slinton case STRNG: 59*24416Smckusick putstr( " .data 1\n" ); 609700Slinton break; 619700Slinton 629700Slinton case ISTRNG: 63*24416Smckusick putstr( " .data 2\n" ); 649700Slinton break; 659700Slinton 669700Slinton case STAB: 67*24416Smckusick putstr( " .stab\n" ); 689700Slinton break; 699700Slinton 709700Slinton default: 719700Slinton cerror( "illegal location counter" ); 729700Slinton } 739700Slinton 749700Slinton return( temp ); 759700Slinton } 769700Slinton 779700Slinton deflab( n ){ 789700Slinton /* output something to define the current position as label n */ 799700Slinton printf( "L%d:\n", n ); 809700Slinton } 819700Slinton 829700Slinton int crslab = 10; 839700Slinton 849700Slinton getlab(){ 859700Slinton /* return a number usable for a label */ 869700Slinton return( ++crslab ); 879700Slinton } 889700Slinton 899700Slinton 909700Slinton int ent_mask[] = { 919700Slinton 0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0}; 929700Slinton 939700Slinton int reg_use = 11; 949700Slinton 959700Slinton efcode(){ 969700Slinton /* code for the end of a function */ 979700Slinton 989700Slinton if( strftn ){ /* copy output (in R2) to caller */ 999700Slinton register NODE *l, *r; 1009700Slinton register struct symtab *p; 1019700Slinton register TWORD t; 1029700Slinton int i; 1039700Slinton 1049700Slinton p = &stab[curftn]; 1059700Slinton t = p->stype; 1069700Slinton t = DECREF(t); 1079700Slinton 1089700Slinton deflab( retlab ); 1099700Slinton 1109700Slinton i = getlab(); /* label for return area */ 1119700Slinton #ifndef LCOMM 112*24416Smckusick putstr(" .data\n" ); 113*24416Smckusick putstr(" .align 2\n" ); 1149700Slinton printf("L%d: .space %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR ); 115*24416Smckusick putstr(" .text\n" ); 1169700Slinton #else 1179700Slinton { int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR; 1189700Slinton if (sz % sizeof (int)) 1199700Slinton sz += sizeof (int) - (sz % sizeof (int)); 1209700Slinton printf(" .lcomm L%d,%d\n", i, sz); 1219700Slinton } 1229700Slinton #endif 1239700Slinton psline(); 1249700Slinton printf(" movab L%d,r1\n", i); 1259700Slinton 1269700Slinton reached = 1; 1279700Slinton l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); 1289700Slinton l->tn.rval = 1; /* R1 */ 1299700Slinton l->tn.lval = 0; /* no offset */ 1309700Slinton r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); 1319700Slinton r->tn.rval = 0; /* R0 */ 1329700Slinton r->tn.lval = 0; 1339700Slinton l = buildtree( UNARY MUL, l, NIL ); 1349700Slinton r = buildtree( UNARY MUL, r, NIL ); 1359700Slinton l = buildtree( ASSIGN, l, r ); 1369700Slinton l->in.op = FREE; 1379700Slinton ecomp( l->in.left ); 1389700Slinton printf( " movab L%d,r0\n", i ); 1399700Slinton /* turn off strftn flag, so return sequence will be generated */ 1409700Slinton strftn = 0; 1419700Slinton } 1429700Slinton branch( retlab ); 1439700Slinton #ifndef VMS 1449700Slinton printf( " .set L%d,0x%x\n", ftnno, ent_mask[reg_use] ); 1459700Slinton #else 1469700Slinton printf( " .set L%d,%d # Hex = 0x%x\n", ftnno, 0x3c| ent_mask[reg_use], ent_mask[reg_use] ); 1479700Slinton /* KLS kludge, under VMS if you use regs 2-5, you must save them. */ 1489700Slinton #endif 1499700Slinton reg_use = 11; 1509700Slinton p2bend(); 1519700Slinton fdefflag = 0; 1529700Slinton } 1539700Slinton 1549700Slinton int ftlab1, ftlab2; 1559700Slinton 1569700Slinton bfcode( a, n ) int a[]; { 1579700Slinton /* code for the beginning of a function; a is an array of 1589700Slinton indices in stab for the arguments; n is the number */ 1599700Slinton register i; 1609700Slinton register temp; 1619700Slinton register struct symtab *p; 1629700Slinton int off; 1639700Slinton char *toreg(); 1649700Slinton 1659700Slinton locctr( PROG ); 1669700Slinton p = &stab[curftn]; 167*24416Smckusick putstr( " .align 1\n"); 1689700Slinton defnam( p ); 1699700Slinton temp = p->stype; 1709700Slinton temp = DECREF(temp); 1719700Slinton strftn = (temp==STRTY) || (temp==UNIONTY); 1729700Slinton 1739700Slinton retlab = getlab(); 1749700Slinton 1759700Slinton /* routine prolog */ 1769700Slinton 1779700Slinton printf( " .word L%d\n", ftnno); 1789700Slinton ftlab1 = getlab(); 1799700Slinton ftlab2 = getlab(); 1809700Slinton printf( " jbr L%d\n", ftlab1); 1819700Slinton printf( "L%d:\n", ftlab2); 1829700Slinton if( proflg ) { /* profile code */ 1839700Slinton i = getlab(); 1849700Slinton printf(" movab L%d,r0\n", i); 185*24416Smckusick putstr(" jsb mcount\n"); 186*24416Smckusick putstr(" .data\n"); 187*24416Smckusick putstr(" .align 2\n"); 1889700Slinton printf("L%d: .long 0\n", i); 189*24416Smckusick putstr(" .text\n"); 1909700Slinton psline(); 1919700Slinton } 1929700Slinton 1939700Slinton off = ARGINIT; 1949700Slinton 1959700Slinton for( i=0; i<n; ++i ){ 1969700Slinton p = &stab[a[i]]; 1979700Slinton if( p->sclass == REGISTER ){ 1989700Slinton temp = p->offset; /* save register number */ 1999700Slinton p->sclass = PARAM; /* forget that it is a register */ 2009700Slinton p->offset = NOOFFSET; 2019700Slinton oalloc( p, &off ); 2029700Slinton /*tbl*/ printf( " %s %d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp ); 2039700Slinton p->offset = temp; /* remember register number */ 2049700Slinton p->sclass = REGISTER; /* remember that it is a register */ 2059700Slinton } 2069700Slinton else if( p->stype == STRTY || p->stype == UNIONTY ) { 2079700Slinton p->offset = NOOFFSET; 2089700Slinton if( oalloc( p, &off ) ) cerror( "bad argument" ); 2099700Slinton SETOFF( off, ALSTACK ); 2109700Slinton } 2119700Slinton else { 2129700Slinton if( oalloc( p, &off ) ) cerror( "bad argument" ); 2139700Slinton } 2149700Slinton 2159700Slinton } 21615896Ssam if (gdebug) { 21715896Ssam #ifdef STABDOT 21815896Ssam pstabdot(N_SLINE, lineno); 21915896Ssam #else 22015896Ssam pstab(NULLNAME, N_SLINE); 22115896Ssam printf("0,%d,LL%d\n", lineno, labelno); 22215896Ssam printf("LL%d:\n", labelno++); 22315896Ssam #endif 22415896Ssam } 2259700Slinton fdefflag = 1; 2269700Slinton } 2279700Slinton 2289700Slinton bccode(){ /* called just before the first executable statment */ 2299700Slinton /* by now, the automatics and register variables are allocated */ 2309700Slinton SETOFF( autooff, SZINT ); 2319700Slinton /* set aside store area offset */ 2329700Slinton p2bbeg( autooff, regvar ); 2339700Slinton reg_use = (reg_use > regvar ? regvar : reg_use); 2349700Slinton } 2359700Slinton 2369700Slinton ejobcode( flag ){ 2379700Slinton /* called just before final exit */ 2389700Slinton /* flag is 1 if errors, 0 if none */ 2399700Slinton } 2409700Slinton 2419700Slinton aobeg(){ 2429700Slinton /* called before removing automatics from stab */ 2439700Slinton } 2449700Slinton 2459700Slinton aocode(p) struct symtab *p; { 2469700Slinton /* called when automatic p removed from stab */ 2479700Slinton } 2489700Slinton 2499700Slinton aoend(){ 2509700Slinton /* called after removing all automatics from stab */ 2519700Slinton } 2529700Slinton 2539700Slinton defnam( p ) register struct symtab *p; { 2549700Slinton /* define the current location as the name p->sname */ 2559700Slinton 2569700Slinton if( p->sclass == EXTDEF ){ 2579700Slinton printf( " .globl %s\n", exname( p->sname ) ); 2589700Slinton } 2599700Slinton if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset ); 2609700Slinton else printf( "%s:\n", exname( p->sname ) ); 2619700Slinton 2629700Slinton } 2639700Slinton 2649700Slinton bycode( t, i ){ 2659700Slinton #ifdef ASSTRINGS 2669700Slinton static int lastoctal = 0; 2679700Slinton #endif 2689700Slinton 2699700Slinton /* put byte i+1 in a string */ 2709700Slinton 2719700Slinton #ifdef ASSTRINGS 2729700Slinton 2739700Slinton i &= 077; 2749700Slinton if ( t < 0 ){ 275*24416Smckusick if ( i != 0 ) putstr( "\"\n" ); 2769700Slinton } else { 277*24416Smckusick if ( i == 0 ) putstr("\t.ascii\t\""); 2789700Slinton if ( t == '\\' || t == '"'){ 2799700Slinton lastoctal = 0; 2809700Slinton printf("\\%c", t); 2819700Slinton } 2829700Slinton /* 2839700Slinton * We escape the colon in strings so that 2849700Slinton * c2 will, in its infinite wisdom, interpret 2859700Slinton * the characters preceding the colon as a label. 2869700Slinton * If we didn't escape the colon, c2 would 2879700Slinton * throw away any trailing blanks or tabs after 2889700Slinton * the colon, but reconstruct a assembly 2899700Slinton * language semantically correct program. 2909700Slinton * C2 hasn't been taught about strings. 2919700Slinton */ 2929700Slinton else if ( t == ':' || t < 040 || t >= 0177 ){ 2939700Slinton lastoctal++; 2949700Slinton printf("\\%o",t); 2959700Slinton } 2969700Slinton else if ( lastoctal && '0' <= t && t <= '9' ){ 2979700Slinton lastoctal = 0; 2989700Slinton printf("\"\n\t.ascii\t\"%c", t ); 2999700Slinton } 3009700Slinton else 3019700Slinton { 3029700Slinton lastoctal = 0; 3039700Slinton putchar(t); 3049700Slinton } 305*24416Smckusick if ( i == 077 ) putstr("\"\n"); 3069700Slinton } 3079700Slinton #else 3089700Slinton 3099700Slinton i &= 07; 3109700Slinton if( t < 0 ){ /* end of the string */ 311*24416Smckusick if( i != 0 ) putchar( '\n' ); 3129700Slinton } 3139700Slinton 3149700Slinton else { /* stash byte t into string */ 315*24416Smckusick if( i == 0 ) putstr( " .byte " ); 316*24416Smckusick else putchar( ',' ); 3179700Slinton printf( "0x%x", t ); 318*24416Smckusick if( i == 07 ) putchar( '\n' ); 3199700Slinton } 3209700Slinton #endif 3219700Slinton } 3229700Slinton 3239700Slinton zecode( n ){ 3249700Slinton /* n integer words of zeros */ 3259700Slinton OFFSZ temp; 3269700Slinton if( n <= 0 ) return; 3279700Slinton printf( " .space %d\n", (SZINT/SZCHAR)*n ); 3289700Slinton temp = n; 3299700Slinton inoff += temp*SZINT; 3309700Slinton } 3319700Slinton 3329700Slinton fldal( t ) unsigned t; { /* return the alignment of field of type t */ 3339700Slinton uerror( "illegal field type" ); 3349700Slinton return( ALINT ); 3359700Slinton } 3369700Slinton 3379700Slinton fldty( p ) struct symtab *p; { /* fix up type of field p */ 3389700Slinton ; 3399700Slinton } 3409700Slinton 3419700Slinton where(c){ /* print location of error */ 3429700Slinton /* c is either 'u', 'c', or 'w' */ 3439700Slinton /* GCOS version */ 3449700Slinton fprintf( stderr, "%s, line %d: ", ftitle, lineno ); 3459700Slinton } 3469700Slinton 3479700Slinton 3489700Slinton /* tbl - toreg() returns a pointer to a char string 3499700Slinton which is the correct "register move" for the passed type 3509700Slinton */ 3519700Slinton struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] = 3529700Slinton { 3539700Slinton CHAR, "cvtbl", 3549700Slinton SHORT, "cvtwl", 3559700Slinton INT, "movl", 3569700Slinton LONG, "movl", 3579700Slinton FLOAT, "movf", 3589700Slinton DOUBLE, "movd", 3599700Slinton UCHAR, "movzbl", 3609700Slinton USHORT, "movzwl", 3619700Slinton UNSIGNED, "movl", 3629700Slinton ULONG, "movl", 36317737Sralph 0, "" 3649700Slinton }; 3659700Slinton 3669700Slinton char 3679700Slinton *toreg(type) 3689700Slinton TWORD type; 3699700Slinton { 3709700Slinton struct type_move *p; 3719700Slinton 37217737Sralph for ( p=toreg_strs; p->fromtype != 0; p++) 3739700Slinton if (p->fromtype == type) return(p->tostrng); 3749700Slinton 3759700Slinton /* type not found, must be a pointer type */ 3769700Slinton return("movl"); 3779700Slinton } 3789700Slinton /* tbl */ 3799700Slinton 3809700Slinton 3819700Slinton main( argc, argv ) char *argv[]; { 3829700Slinton #ifdef BUFSTDERR 3839700Slinton char errbuf[BUFSIZ]; 3849700Slinton setbuf(stderr, errbuf); 3859700Slinton #endif 3869700Slinton return(mainp1( argc, argv )); 3879700Slinton } 3889700Slinton 3899700Slinton struct sw heapsw[SWITSZ]; /* heap for switches */ 3909700Slinton 3919700Slinton genswitch(p,n) register struct sw *p;{ 3929700Slinton /* p points to an array of structures, each consisting 3939700Slinton of a constant value and a label. 3949700Slinton The first is >=0 if there is a default label; 3959700Slinton its value is the label number 3969700Slinton The entries p[1] to p[n] are the nontrivial cases 3979700Slinton */ 3989700Slinton register i; 3999700Slinton register CONSZ j, range; 4009700Slinton register dlab, swlab; 4019700Slinton 4029700Slinton range = p[n].sval-p[1].sval; 4039700Slinton 4049700Slinton if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */ 4059700Slinton 4069700Slinton swlab = getlab(); 4079700Slinton dlab = p->slab >= 0 ? p->slab : getlab(); 4089700Slinton 4099700Slinton /* already in r0 */ 4109700Slinton printf(" casel r0,$%ld,$%ld\n", p[1].sval, range); 4119700Slinton printf("L%d:\n", swlab); 4129700Slinton for( i=1,j=p[1].sval; i<=n; j++) { 4139700Slinton printf(" .word L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab), 4149700Slinton swlab); 4159700Slinton } 4169700Slinton 4179700Slinton if( p->slab >= 0 ) branch( dlab ); 4189700Slinton else printf("L%d:\n", dlab); 4199700Slinton return; 4209700Slinton 4219700Slinton } 4229700Slinton 4239700Slinton if( n>8 ) { /* heap switch */ 4249700Slinton 4259700Slinton heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab(); 4269700Slinton makeheap(p, n, 1); /* build heap */ 4279700Slinton 4289700Slinton walkheap(1, n); /* produce code */ 4299700Slinton 4309700Slinton if( p->slab >= 0 ) 4319700Slinton branch( dlab ); 4329700Slinton else 4339700Slinton printf("L%d:\n", dlab); 4349700Slinton return; 4359700Slinton } 4369700Slinton 4379700Slinton /* debugging code */ 4389700Slinton 4399700Slinton /* out for the moment 4409700Slinton if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) ); 4419700Slinton */ 4429700Slinton 4439700Slinton /* simple switch code */ 4449700Slinton 4459700Slinton for( i=1; i<=n; ++i ){ 4469700Slinton /* already in r0 */ 4479700Slinton 448*24416Smckusick putstr( " cmpl r0,$" ); 4499700Slinton printf( CONFMT, p[i].sval ); 4509700Slinton printf( "\n jeql L%d\n", p[i].slab ); 4519700Slinton } 4529700Slinton 4539700Slinton if( p->slab>=0 ) branch( p->slab ); 4549700Slinton } 4559700Slinton 4569700Slinton makeheap(p, m, n) 4579700Slinton register struct sw *p; 4589700Slinton { 4599700Slinton register int q; 4609700Slinton 4619700Slinton q = select(m); 4629700Slinton heapsw[n] = p[q]; 4639700Slinton if( q>1 ) makeheap(p, q-1, 2*n); 4649700Slinton if( q<m ) makeheap(p+q, m-q, 2*n+1); 4659700Slinton } 4669700Slinton 4679700Slinton select(m) { 4689700Slinton register int l,i,k; 4699700Slinton 4709700Slinton for(i=1; ; i*=2) 4719700Slinton if( (i-1) > m ) break; 4729700Slinton l = ((k = i/2 - 1) + 1)/2; 4739700Slinton return( l + (m-k < l ? m-k : l)); 4749700Slinton } 4759700Slinton 4769700Slinton walkheap(start, limit) 4779700Slinton { 4789700Slinton int label; 4799700Slinton 4809700Slinton 4819700Slinton if( start > limit ) return; 4829700Slinton printf(" cmpl r0,$%d\n", heapsw[start].sval); 4839700Slinton printf(" jeql L%d\n", heapsw[start].slab); 4849700Slinton if( (2*start) > limit ) { 4859700Slinton printf(" jbr L%d\n", heapsw[0].slab); 4869700Slinton return; 4879700Slinton } 4889700Slinton if( (2*start+1) <= limit ) { 4899700Slinton label = getlab(); 4909700Slinton printf(" jgtr L%d\n", label); 4919700Slinton } else 4929700Slinton printf(" jgtr L%d\n", heapsw[0].slab); 4939700Slinton walkheap( 2*start, limit); 4949700Slinton if( (2*start+1) <= limit ) { 4959700Slinton printf("L%d:\n", label); 4969700Slinton walkheap( 2*start+1, limit); 4979700Slinton } 4989700Slinton } 499