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