117737Sralph #ifndef lint 2*32911Sdonn static char *sccsid ="@(#)code.c 1.7 (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 */ 2232910Sdonn 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; 4732910Sdonn 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 7932910Sdonn #ifndef deflab 809700Slinton deflab( n ){ 819700Slinton /* output something to define the current position as label n */ 829700Slinton printf( "L%d:\n", n ); 839700Slinton } 8432910Sdonn #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 16932910Sdonn 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 } 22132910Sdonn 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 241*32911Sdonn /*ARGSUSED*/ 2429700Slinton ejobcode( flag ){ 2439700Slinton /* called just before final exit */ 2449700Slinton /* flag is 1 if errors, 0 if none */ 2459700Slinton } 2469700Slinton 24732910Sdonn #ifndef aobeg 2489700Slinton aobeg(){ 2499700Slinton /* called before removing automatics from stab */ 2509700Slinton } 25132910Sdonn #endif aobeg 2529700Slinton 25332910Sdonn #ifndef aocode 254*32911Sdonn /*ARGSUSED*/ 2559700Slinton aocode(p) struct symtab *p; { 2569700Slinton /* called when automatic p removed from stab */ 2579700Slinton } 25832910Sdonn #endif aocode 2599700Slinton 26032910Sdonn #ifndef aoend 2619700Slinton aoend(){ 2629700Slinton /* called after removing all automatics from stab */ 2639700Slinton } 26432910Sdonn #endif aoend 2659700Slinton 2669700Slinton defnam( p ) register struct symtab *p; { 2679700Slinton /* define the current location as the name p->sname */ 2689700Slinton 2699700Slinton if( p->sclass == EXTDEF ){ 2709700Slinton printf( " .globl %s\n", exname( p->sname ) ); 2719700Slinton } 2729700Slinton if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset ); 2739700Slinton else printf( "%s:\n", exname( p->sname ) ); 2749700Slinton 2759700Slinton } 2769700Slinton 2779700Slinton bycode( t, i ){ 2789700Slinton #ifdef ASSTRINGS 2799700Slinton static int lastoctal = 0; 2809700Slinton #endif 2819700Slinton 2829700Slinton /* put byte i+1 in a string */ 2839700Slinton 28432910Sdonn if ( nerrors ) return; 2859700Slinton #ifdef ASSTRINGS 2869700Slinton 2879700Slinton i &= 077; 2889700Slinton if ( t < 0 ){ 28924416Smckusick if ( i != 0 ) putstr( "\"\n" ); 2909700Slinton } else { 29124416Smckusick if ( i == 0 ) putstr("\t.ascii\t\""); 2929700Slinton if ( t == '\\' || t == '"'){ 2939700Slinton lastoctal = 0; 2949700Slinton printf("\\%c", t); 2959700Slinton } 2969700Slinton /* 2979700Slinton * We escape the colon in strings so that 2989700Slinton * c2 will, in its infinite wisdom, interpret 2999700Slinton * the characters preceding the colon as a label. 3009700Slinton * If we didn't escape the colon, c2 would 3019700Slinton * throw away any trailing blanks or tabs after 3029700Slinton * the colon, but reconstruct a assembly 3039700Slinton * language semantically correct program. 3049700Slinton * C2 hasn't been taught about strings. 3059700Slinton */ 3069700Slinton else if ( t == ':' || t < 040 || t >= 0177 ){ 3079700Slinton lastoctal++; 3089700Slinton printf("\\%o",t); 3099700Slinton } 3109700Slinton else if ( lastoctal && '0' <= t && t <= '9' ){ 3119700Slinton lastoctal = 0; 3129700Slinton printf("\"\n\t.ascii\t\"%c", t ); 3139700Slinton } 3149700Slinton else 3159700Slinton { 3169700Slinton lastoctal = 0; 3179700Slinton putchar(t); 3189700Slinton } 31924416Smckusick if ( i == 077 ) putstr("\"\n"); 3209700Slinton } 3219700Slinton #else 3229700Slinton 3239700Slinton i &= 07; 3249700Slinton if( t < 0 ){ /* end of the string */ 32524416Smckusick if( i != 0 ) putchar( '\n' ); 3269700Slinton } 3279700Slinton 3289700Slinton else { /* stash byte t into string */ 32924416Smckusick if( i == 0 ) putstr( " .byte " ); 33024416Smckusick else putchar( ',' ); 3319700Slinton printf( "0x%x", t ); 33224416Smckusick if( i == 07 ) putchar( '\n' ); 3339700Slinton } 3349700Slinton #endif 3359700Slinton } 3369700Slinton 3379700Slinton zecode( n ){ 3389700Slinton /* n integer words of zeros */ 3399700Slinton OFFSZ temp; 3409700Slinton if( n <= 0 ) return; 3419700Slinton printf( " .space %d\n", (SZINT/SZCHAR)*n ); 3429700Slinton temp = n; 3439700Slinton inoff += temp*SZINT; 3449700Slinton } 3459700Slinton 346*32911Sdonn /*ARGSUSED*/ 3479700Slinton fldal( t ) unsigned t; { /* return the alignment of field of type t */ 3489700Slinton uerror( "illegal field type" ); 3499700Slinton return( ALINT ); 3509700Slinton } 3519700Slinton 352*32911Sdonn /*ARGSUSED*/ 3539700Slinton fldty( p ) struct symtab *p; { /* fix up type of field p */ 3549700Slinton ; 3559700Slinton } 3569700Slinton 357*32911Sdonn /*ARGSUSED*/ 3589700Slinton where(c){ /* print location of error */ 3599700Slinton /* c is either 'u', 'c', or 'w' */ 3609700Slinton /* GCOS version */ 3619700Slinton fprintf( stderr, "%s, line %d: ", ftitle, lineno ); 3629700Slinton } 3639700Slinton 3649700Slinton 3659700Slinton /* tbl - toreg() returns a pointer to a char string 3669700Slinton which is the correct "register move" for the passed type 3679700Slinton */ 3689700Slinton struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] = 3699700Slinton { 3709700Slinton CHAR, "cvtbl", 3719700Slinton SHORT, "cvtwl", 3729700Slinton INT, "movl", 3739700Slinton LONG, "movl", 3749700Slinton FLOAT, "movf", 3759700Slinton DOUBLE, "movd", 3769700Slinton UCHAR, "movzbl", 3779700Slinton USHORT, "movzwl", 3789700Slinton UNSIGNED, "movl", 3799700Slinton ULONG, "movl", 38017737Sralph 0, "" 3819700Slinton }; 3829700Slinton 3839700Slinton char 3849700Slinton *toreg(type) 3859700Slinton TWORD type; 3869700Slinton { 3879700Slinton struct type_move *p; 3889700Slinton 38917737Sralph for ( p=toreg_strs; p->fromtype != 0; p++) 3909700Slinton if (p->fromtype == type) return(p->tostrng); 3919700Slinton 3929700Slinton /* type not found, must be a pointer type */ 3939700Slinton return("movl"); 3949700Slinton } 3959700Slinton /* tbl */ 3969700Slinton 3979700Slinton 3989700Slinton main( argc, argv ) char *argv[]; { 3999700Slinton #ifdef BUFSTDERR 4009700Slinton char errbuf[BUFSIZ]; 4019700Slinton setbuf(stderr, errbuf); 4029700Slinton #endif 4039700Slinton return(mainp1( argc, argv )); 4049700Slinton } 4059700Slinton 4069700Slinton struct sw heapsw[SWITSZ]; /* heap for switches */ 4079700Slinton 4089700Slinton genswitch(p,n) register struct sw *p;{ 4099700Slinton /* p points to an array of structures, each consisting 4109700Slinton of a constant value and a label. 4119700Slinton The first is >=0 if there is a default label; 4129700Slinton its value is the label number 4139700Slinton The entries p[1] to p[n] are the nontrivial cases 4149700Slinton */ 4159700Slinton register i; 4169700Slinton register CONSZ j, range; 4179700Slinton register dlab, swlab; 4189700Slinton 41932910Sdonn if( nerrors ) return; 4209700Slinton range = p[n].sval-p[1].sval; 4219700Slinton 4229700Slinton if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */ 4239700Slinton 4249700Slinton swlab = getlab(); 4259700Slinton dlab = p->slab >= 0 ? p->slab : getlab(); 4269700Slinton 4279700Slinton /* already in r0 */ 4289700Slinton printf(" casel r0,$%ld,$%ld\n", p[1].sval, range); 4299700Slinton printf("L%d:\n", swlab); 4309700Slinton for( i=1,j=p[1].sval; i<=n; j++) { 4319700Slinton printf(" .word L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab), 4329700Slinton swlab); 4339700Slinton } 4349700Slinton 4359700Slinton if( p->slab >= 0 ) branch( dlab ); 4369700Slinton else printf("L%d:\n", dlab); 4379700Slinton return; 4389700Slinton 4399700Slinton } 4409700Slinton 4419700Slinton if( n>8 ) { /* heap switch */ 4429700Slinton 4439700Slinton heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab(); 4449700Slinton makeheap(p, n, 1); /* build heap */ 4459700Slinton 4469700Slinton walkheap(1, n); /* produce code */ 4479700Slinton 4489700Slinton if( p->slab >= 0 ) 4499700Slinton branch( dlab ); 4509700Slinton else 4519700Slinton printf("L%d:\n", dlab); 4529700Slinton return; 4539700Slinton } 4549700Slinton 4559700Slinton /* debugging code */ 4569700Slinton 4579700Slinton /* out for the moment 4589700Slinton if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) ); 4599700Slinton */ 4609700Slinton 4619700Slinton /* simple switch code */ 4629700Slinton 4639700Slinton for( i=1; i<=n; ++i ){ 4649700Slinton /* already in r0 */ 4659700Slinton 46624416Smckusick putstr( " cmpl r0,$" ); 4679700Slinton printf( CONFMT, p[i].sval ); 4689700Slinton printf( "\n jeql L%d\n", p[i].slab ); 4699700Slinton } 4709700Slinton 4719700Slinton if( p->slab>=0 ) branch( p->slab ); 4729700Slinton } 4739700Slinton 4749700Slinton makeheap(p, m, n) 4759700Slinton register struct sw *p; 4769700Slinton { 4779700Slinton register int q; 4789700Slinton 4799700Slinton q = select(m); 4809700Slinton heapsw[n] = p[q]; 4819700Slinton if( q>1 ) makeheap(p, q-1, 2*n); 4829700Slinton if( q<m ) makeheap(p+q, m-q, 2*n+1); 4839700Slinton } 4849700Slinton 4859700Slinton select(m) { 4869700Slinton register int l,i,k; 4879700Slinton 4889700Slinton for(i=1; ; i*=2) 4899700Slinton if( (i-1) > m ) break; 4909700Slinton l = ((k = i/2 - 1) + 1)/2; 4919700Slinton return( l + (m-k < l ? m-k : l)); 4929700Slinton } 4939700Slinton 4949700Slinton walkheap(start, limit) 4959700Slinton { 4969700Slinton int label; 4979700Slinton 4989700Slinton 4999700Slinton if( start > limit ) return; 5009700Slinton printf(" cmpl r0,$%d\n", heapsw[start].sval); 5019700Slinton printf(" jeql L%d\n", heapsw[start].slab); 5029700Slinton if( (2*start) > limit ) { 5039700Slinton printf(" jbr L%d\n", heapsw[0].slab); 5049700Slinton return; 5059700Slinton } 5069700Slinton if( (2*start+1) <= limit ) { 5079700Slinton label = getlab(); 5089700Slinton printf(" jgtr L%d\n", label); 5099700Slinton } else 5109700Slinton printf(" jgtr L%d\n", heapsw[0].slab); 5119700Slinton walkheap( 2*start, limit); 5129700Slinton if( (2*start+1) <= limit ) { 5139700Slinton printf("L%d:\n", label); 5149700Slinton walkheap( 2*start+1, limit); 5159700Slinton } 5169700Slinton } 517