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