125826Ssam #ifndef lint 2*26075Ssam static char sccsid[] = "@(#)code.c 1.2 (Berkeley) 02/04/86"; 325826Ssam #endif 425826Ssam 5*26075Ssam # include "pass1.h" 625826Ssam # include <sys/types.h> 725826Ssam # include <a.out.h> 825826Ssam # include <stab.h> 925826Ssam 1025826Ssam int proflg = 0; /* are we generating profiling code? */ 1125826Ssam int strftn = 0; /* is the current function one which returns a value */ 1225826Ssam int gdebug; 1325826Ssam int fdefflag; /* are we within a function definition ? */ 1425826Ssam #ifndef STABDOT 1525826Ssam char NULLNAME[8]; 1625826Ssam #endif 1725826Ssam int labelno; 1825826Ssam 1925826Ssam branch( n ){ 2025826Ssam /* output a branch to label n */ 2125826Ssam /* exception is an ordinary function branching to retlab: then, return */ 2225826Ssam if( n == retlab && !strftn ){ 2325826Ssam register TWORD t; 2425826Ssam register r; 2525826Ssam /* set number of regs in assem comment field */ 2625826Ssam /* so optimizers can do a better job */ 2725826Ssam r = 0; 2825826Ssam if( retstat & RETVAL ){ /* the function rets a val somewhere */ 2925826Ssam t = (&stab[curftn])->stype; 3025826Ssam t = DECREF(t); 3125826Ssam r++; /* it is at least one */ 3225826Ssam if(t == DOUBLE) 3325826Ssam r++; /* it takes two */ 3425826Ssam } else /* the fn does not ret a val */ 3525826Ssam r = 2; 3625826Ssam printf( " ret#%d\n", r ); 3725826Ssam } 3825826Ssam else printf( " jbr L%d\n", n ); 3925826Ssam } 4025826Ssam 4125826Ssam int lastloc = { -1 }; 4225826Ssam 4325826Ssam short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3}; 4425826Ssam #define LOG2SZ 9 4525826Ssam 4625826Ssam defalign(n) { 4725826Ssam /* cause the alignment to become a multiple of n */ 4825826Ssam n /= SZCHAR; 4925826Ssam if( lastloc != PROG && n > 1 ) printf( " .align %d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 ); 5025826Ssam } 5125826Ssam 5225826Ssam locctr( l ){ 5325826Ssam register temp; 5425826Ssam /* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */ 5525826Ssam 5625826Ssam if( l == lastloc ) return(l); 5725826Ssam temp = lastloc; 5825826Ssam lastloc = l; 5925826Ssam switch( l ){ 6025826Ssam 6125826Ssam case PROG: 6225826Ssam printf( " .text\n" ); 6325826Ssam psline(); 6425826Ssam break; 6525826Ssam 6625826Ssam case DATA: 6725826Ssam case ADATA: 6825826Ssam printf( " .data\n" ); 6925826Ssam break; 7025826Ssam 7125826Ssam case STRNG: 7225826Ssam printf( " .data 1\n" ); 7325826Ssam break; 7425826Ssam 7525826Ssam case ISTRNG: 7625826Ssam printf( " .data 2\n" ); 7725826Ssam break; 7825826Ssam 7925826Ssam case STAB: 8025826Ssam printf( " .stab\n" ); 8125826Ssam break; 8225826Ssam 8325826Ssam default: 8425826Ssam cerror( "illegal location counter" ); 8525826Ssam } 8625826Ssam 8725826Ssam return( temp ); 8825826Ssam } 8925826Ssam 9025826Ssam deflab( n ){ 9125826Ssam /* output something to define the current position as label n */ 9225826Ssam printf( "L%d:\n", n ); 9325826Ssam } 9425826Ssam 9525826Ssam int crslab = 10; 9625826Ssam 9725826Ssam getlab(){ 9825826Ssam /* return a number usable for a label */ 9925826Ssam return( ++crslab ); 10025826Ssam } 10125826Ssam 10225826Ssam 10325826Ssam efcode(){ 10425826Ssam /* code for the end of a function */ 10525826Ssam 10625826Ssam if( strftn ){ /* copy output (in R2) to caller */ 10725826Ssam register NODE *l, *r; 10825826Ssam register struct symtab *p; 10925826Ssam register TWORD t; 11025826Ssam register int i; 11125826Ssam 11225826Ssam p = &stab[curftn]; 11325826Ssam t = p->stype; 11425826Ssam t = DECREF(t); 11525826Ssam 11625826Ssam deflab( retlab ); 11725826Ssam 11825826Ssam i = getlab(); /* label for return area */ 11925826Ssam #ifndef LCOMM 12025826Ssam printf(" .data\n" ); 12125826Ssam printf(" .align 2\n" ); 12225826Ssam printf("L%d: .space %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR ); 12325826Ssam printf(" .text\n" ); 12425826Ssam #else 12525826Ssam { int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR; 12625826Ssam if (sz % (SZINT/SZCHAR)) 12725826Ssam sz += (SZINT/SZCHAR) - (sz % (SZINT/SZCHAR)); 12825826Ssam printf(" .lcomm L%d,%d\n", i, sz); 12925826Ssam } 13025826Ssam #endif 13125826Ssam psline(); 13225826Ssam printf(" movab L%d,r1\n", i); 13325826Ssam 13425826Ssam reached = 1; 13525826Ssam l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); 13625826Ssam l->tn.rval = 1; /* R1 */ 13725826Ssam l->tn.lval = 0; /* no offset */ 13825826Ssam r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); 13925826Ssam r->tn.rval = 0; /* R0 */ 14025826Ssam r->tn.lval = 0; 14125826Ssam l = buildtree( UNARY MUL, l, NIL ); 14225826Ssam r = buildtree( UNARY MUL, r, NIL ); 14325826Ssam l = buildtree( ASSIGN, l, r ); 14425826Ssam l->in.op = FREE; 14525826Ssam ecomp( l->in.left ); 14625826Ssam printf( " movab L%d,r0\n", i ); 14725826Ssam /* turn off strftn flag, so return sequence will be generated */ 14825826Ssam strftn = 0; 14925826Ssam } 15025826Ssam branch( retlab ); 15125826Ssam p2bend(); 15225826Ssam fdefflag = 0; 15325826Ssam } 15425826Ssam 15525826Ssam int ftlab1, ftlab2; 15625826Ssam 15725826Ssam bfcode( a, n ) int a[]; { 15825826Ssam /* code for the beginning of a function; a is an array of 15925826Ssam indices in stab for the arguments; n is the number */ 16025826Ssam register i; 16125826Ssam register temp; 16225826Ssam register struct symtab *p; 16325826Ssam int off; 16425826Ssam #ifdef REG_CHAR 16525826Ssam char *toreg(); 16625826Ssam #endif 16725826Ssam char *rname(); 16825826Ssam 16925826Ssam locctr( PROG ); 17025826Ssam p = &stab[curftn]; 17125826Ssam printf( " .align 1\n"); 17225826Ssam defnam( p ); 17325826Ssam temp = p->stype; 17425826Ssam temp = DECREF(temp); 17525826Ssam strftn = (temp==STRTY) || (temp==UNIONTY); 17625826Ssam 17725826Ssam retlab = getlab(); 17825826Ssam 17925826Ssam /* routine prolog */ 18025826Ssam 18125826Ssam printf( " .word L%d\n", ftnno); 18225826Ssam if (gdebug) { 18325826Ssam #ifdef STABDOT 18425826Ssam pstabdot(N_SLINE, lineno); 18525826Ssam #else 18625826Ssam pstab(NULLNAME, N_SLINE); 18725826Ssam printf("0,%d,LL%d\n", lineno, labelno); 18825826Ssam printf("LL%d:\n", labelno++); 18925826Ssam #endif 19025826Ssam } 19125826Ssam ftlab1 = getlab(); 19225826Ssam ftlab2 = getlab(); 19325826Ssam printf( " jbr L%d\n", ftlab1); 19425826Ssam printf( "L%d:\n", ftlab2); 19525826Ssam if( proflg ) { /* profile code */ 19625826Ssam i = getlab(); 19725826Ssam printf(" pushl $L%d\n", i); 19825826Ssam printf(" callf $8,mcount\n"); 19925826Ssam printf(" .data\n"); 20025826Ssam printf(" .align 2\n"); 20125826Ssam printf("L%d: .long 0\n", i); 20225826Ssam printf(" .text\n"); 20325826Ssam psline(); 20425826Ssam } 20525826Ssam 20625826Ssam off = ARGINIT; 20725826Ssam 20825826Ssam for( i=0; i<n; ++i ){ 20925826Ssam p = &stab[a[i]]; 21025826Ssam if( p->sclass == REGISTER ){ 21125826Ssam temp = p->offset; /* save register number */ 21225826Ssam p->sclass = PARAM; /* forget that it is a register */ 21325826Ssam p->offset = NOOFFSET; 21425826Ssam oalloc( p, &off ); 21525826Ssam #ifdef REG_CHAR 21625826Ssam printf( " %s", toreg(p->stype)) ); 21725826Ssam #else 21825826Ssam printf(" movl"); 21925826Ssam #endif 22025826Ssam printf( " %d(fp),%s\n", p->offset/SZCHAR, rname(temp) ); 22125826Ssam p->offset = temp; /* remember register number */ 22225826Ssam p->sclass = REGISTER; /* remember that it is a register */ 22325826Ssam #ifdef REG_CHAR 22425826Ssam temp = p->stype; 22525826Ssam if( temp==CHAR || temp==SHORT ) 22625826Ssam p->stype = INT; 22725826Ssam else if( temp==UCHAR || temp==USHORT ) 22825826Ssam p->stype = UNSIGNED; 22925826Ssam #endif 23025826Ssam } 23125826Ssam else if( p->stype == STRTY || p->stype == UNIONTY ) { 23225826Ssam p->offset = NOOFFSET; 23325826Ssam if( oalloc( p, &off ) ) cerror( "bad argument" ); 23425826Ssam SETOFF( off, ALSTACK ); 23525826Ssam } 23625826Ssam else { 23725826Ssam if( oalloc( p, &off ) ) cerror( "bad argument" ); 23825826Ssam } 23925826Ssam 24025826Ssam } 24125826Ssam fdefflag = 1; 24225826Ssam } 24325826Ssam 24425826Ssam bccode(){ /* called just before the first executable statment */ 24525826Ssam /* by now, the automatics and register variables are allocated */ 24625826Ssam SETOFF( autooff, SZINT ); 24725826Ssam /* set aside store area offset */ 24825826Ssam p2bbeg( autooff, regvar ); 24925826Ssam } 25025826Ssam 25125826Ssam ejobcode( flag ){ 25225826Ssam /* called just before final exit */ 25325826Ssam /* flag is 1 if errors, 0 if none */ 25425826Ssam } 25525826Ssam 25625826Ssam aobeg(){ 25725826Ssam /* called before removing automatics from stab */ 25825826Ssam } 25925826Ssam 26025826Ssam aocode(p) struct symtab *p; { 26125826Ssam /* called when automatic p removed from stab */ 26225826Ssam } 26325826Ssam 26425826Ssam aoend(){ 26525826Ssam /* called after removing all automatics from stab */ 26625826Ssam } 26725826Ssam 26825826Ssam defnam( p ) register struct symtab *p; { 26925826Ssam /* define the current location as the name p->sname */ 27025826Ssam 27125826Ssam if( p->sclass == EXTDEF ){ 27225826Ssam printf( " .globl %s\n", exname( p->sname ) ); 27325826Ssam } 27425826Ssam if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset ); 27525826Ssam else printf( "%s:\n", exname( p->sname ) ); 27625826Ssam 27725826Ssam } 27825826Ssam 27925826Ssam bycode( t, i ){ 28025826Ssam #ifdef ASSTRINGS 28125826Ssam static int lastoctal = 0; 28225826Ssam #endif 28325826Ssam 28425826Ssam /* put byte i+1 in a string */ 28525826Ssam 28625826Ssam #ifdef ASSTRINGS 28725826Ssam 28825826Ssam i &= 077; 28925826Ssam if ( t < 0 ){ 29025826Ssam if ( i != 0 ) printf( "\"\n" ); 29125826Ssam } else { 29225826Ssam if ( i == 0 ) printf("\t.ascii\t\""); 29325826Ssam if ( t == '\\' || t == '"'){ 29425826Ssam lastoctal = 0; 29525826Ssam printf("\\%c", t); 29625826Ssam } 29725826Ssam else if ( t < 040 || t >= 0177 ){ 29825826Ssam lastoctal++; 29925826Ssam printf("\\%o",t); 30025826Ssam } 30125826Ssam else if ( lastoctal && '0' <= t && t <= '9' ){ 30225826Ssam lastoctal = 0; 30325826Ssam printf("\"\n\t.ascii\t\"%c", t ); 30425826Ssam } 30525826Ssam else 30625826Ssam { 30725826Ssam lastoctal = 0; 30825826Ssam putchar(t); 30925826Ssam } 31025826Ssam if ( i == 077 ) printf("\"\n"); 31125826Ssam } 31225826Ssam #else 31325826Ssam 31425826Ssam i &= 07; 31525826Ssam if( t < 0 ){ /* end of the string */ 31625826Ssam if( i != 0 ) printf( "\n" ); 31725826Ssam } 31825826Ssam 31925826Ssam else { /* stash byte t into string */ 32025826Ssam if( i == 0 ) printf( " .byte " ); 32125826Ssam else printf( "," ); 32225826Ssam printf( "0x%x", t ); 32325826Ssam if( i == 07 ) printf( "\n" ); 32425826Ssam } 32525826Ssam #endif 32625826Ssam } 32725826Ssam 32825826Ssam zecode( n ){ 32925826Ssam /* n integer words of zeros */ 33025826Ssam OFFSZ temp; 33125826Ssam if( n <= 0 ) return; 33225826Ssam printf( " .space %d\n", (SZINT/SZCHAR)*n ); 33325826Ssam temp = n; 33425826Ssam inoff += temp*SZINT; 33525826Ssam } 33625826Ssam 33725826Ssam fldal( t ) unsigned t; { /* return the alignment of field of type t */ 33825826Ssam uerror( "illegal field type" ); 33925826Ssam return( ALINT ); 34025826Ssam } 34125826Ssam 34225826Ssam fldty( p ) struct symtab *p; { /* fix up type of field p */ 34325826Ssam ; 34425826Ssam } 34525826Ssam 34625826Ssam where(c){ /* print location of error */ 34725826Ssam /* c is either 'u', 'c', or 'w' */ 34825826Ssam /* GCOS version */ 34925826Ssam fprintf( stderr, "%s, line %d: ", ftitle, lineno ); 35025826Ssam } 35125826Ssam 35225826Ssam 35325826Ssam #ifdef REG_CHAR 35425826Ssam /* tbl - toreg() returns a pointer to a char string 35525826Ssam which is the correct "register move" for the passed type 35625826Ssam */ 35725826Ssam struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] = 35825826Ssam { 35925826Ssam CHAR, "cvtbl", 36025826Ssam SHORT, "cvtwl", 36125826Ssam UCHAR, "movzbl", 36225826Ssam USHORT, "movzwl", 36325826Ssam 0, "movl" 36425826Ssam }; 36525826Ssam 36625826Ssam char 36725826Ssam *toreg(type) 36825826Ssam TWORD type; 36925826Ssam { 37025826Ssam struct type_move *p; 37125826Ssam 37225826Ssam for ( p=toreg_strs; p->fromtype != 0; p++) 37325826Ssam if (p->fromtype == type) return(p->tostrng); 37425826Ssam 37525826Ssam /* type not found, must be a word type */ 37625826Ssam return(p->tostrng); 37725826Ssam } 37825826Ssam /* tbl */ 37925826Ssam #endif 38025826Ssam 38125826Ssam 38225826Ssam main( argc, argv ) char *argv[]; { 38325826Ssam #ifdef BUFSTDERR 38425826Ssam char errbuf[BUFSIZ]; 38525826Ssam setbuf(stderr, errbuf); 38625826Ssam #endif 38725826Ssam return(mainp1( argc, argv )); 38825826Ssam } 38925826Ssam 39025826Ssam struct sw heapsw[SWITSZ]; /* heap for switches */ 39125826Ssam 39225826Ssam genswitch(p,n) register struct sw *p;{ 39325826Ssam /* p points to an array of structures, each consisting 39425826Ssam of a constant value and a label. 39525826Ssam The first is >=0 if there is a default label; 39625826Ssam its value is the label number 39725826Ssam The entries p[1] to p[n] are the nontrivial cases 39825826Ssam */ 39925826Ssam register i; 40025826Ssam register CONSZ j; 40125826Ssam register CONSZ unsigned range; 40225826Ssam register dlab, swlab; 40325826Ssam 40425826Ssam range = p[n].sval-p[1].sval; 40525826Ssam 40625826Ssam if( range <= 3*n && n>=4 ){ /* implement a direct switch */ 40725826Ssam 40825826Ssam swlab = getlab(); 40925826Ssam dlab = p->slab >= 0 ? p->slab : getlab(); 41025826Ssam 41125826Ssam /* already in r0 */ 41225826Ssam printf( " casel r0,$" ); 41325826Ssam printf( CONFMT, p[1].sval ); 41425826Ssam printf(",$"); 41525826Ssam printf( CONFMT, range); 41625826Ssam printf("\n .align 1\nL%d:\n", swlab); 41725826Ssam for( i=1,j=p[1].sval; i<=n; j++) { 41825826Ssam printf(" .word L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab), 41925826Ssam swlab); 42025826Ssam } 42125826Ssam 42225826Ssam if( p->slab >= 0 ) branch( dlab ); 42325826Ssam else printf("L%d:\n", dlab); 42425826Ssam return; 42525826Ssam 42625826Ssam } 42725826Ssam 42825826Ssam if( n>8 ) { /* heap switch */ 42925826Ssam 43025826Ssam heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab(); 43125826Ssam makeheap(p, n, 1); /* build heap */ 43225826Ssam 43325826Ssam walkheap(1, n); /* produce code */ 43425826Ssam 43525826Ssam if( p->slab >= 0 ) 43625826Ssam branch( dlab ); 43725826Ssam else 43825826Ssam printf("L%d:\n", dlab); 43925826Ssam return; 44025826Ssam } 44125826Ssam 44225826Ssam /* debugging code */ 44325826Ssam 44425826Ssam /* out for the moment 44525826Ssam if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) ); 44625826Ssam */ 44725826Ssam 44825826Ssam /* simple switch code */ 44925826Ssam 45025826Ssam for( i=1; i<=n; ++i ){ 45125826Ssam /* already in r0 */ 45225826Ssam 45325826Ssam printf( " cmpl r0,$" ); 45425826Ssam printf( CONFMT, p[i].sval ); 45525826Ssam printf( "\n jeql L%d\n", p[i].slab ); 45625826Ssam } 45725826Ssam 45825826Ssam if( p->slab>=0 ) branch( p->slab ); 45925826Ssam } 46025826Ssam 46125826Ssam makeheap(p, m, n) 46225826Ssam register struct sw *p; 46325826Ssam { 46425826Ssam register int q; 46525826Ssam 46625826Ssam q = select(m); 46725826Ssam heapsw[n] = p[q]; 46825826Ssam if( q>1 ) makeheap(p, q-1, 2*n); 46925826Ssam if( q<m ) makeheap(p+q, m-q, 2*n+1); 47025826Ssam } 47125826Ssam 47225826Ssam select(m) { 47325826Ssam register int l,i,k; 47425826Ssam 47525826Ssam for(i=1; ; i*=2) 47625826Ssam if( (i-1) > m ) break; 47725826Ssam l = ((k = i/2 - 1) + 1)/2; 47825826Ssam return( l + (m-k < l ? m-k : l)); 47925826Ssam } 48025826Ssam 48125826Ssam walkheap(start, limit) 48225826Ssam { 48325826Ssam int label; 48425826Ssam 48525826Ssam 48625826Ssam if( start > limit ) return; 48725826Ssam printf( " cmpl r0,$" ); 48825826Ssam printf( CONFMT, heapsw[start].sval); 48925826Ssam printf("\n jeql L%d\n", heapsw[start].slab); 49025826Ssam if( (2*start) > limit ) { 49125826Ssam printf(" jbr L%d\n", heapsw[0].slab); 49225826Ssam return; 49325826Ssam } 49425826Ssam if( (2*start+1) <= limit ) { 49525826Ssam label = getlab(); 49625826Ssam printf(" jgtr L%d\n", label); 49725826Ssam } else 49825826Ssam printf(" jgtr L%d\n", heapsw[0].slab); 49925826Ssam walkheap( 2*start, limit); 50025826Ssam if( (2*start+1) <= limit ) { 50125826Ssam printf("L%d:\n", label); 50225826Ssam walkheap( 2*start+1, limit); 50325826Ssam } 50425826Ssam } 505