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