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