125826Ssam #ifndef lint
2*34582Sdonn static char sccsid[] = "@(#)code.c 1.6 (Berkeley) 05/31/88";
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
1932866Sdonn # define putstr(s) fputs((s), stdout)
2032866Sdonn
branch(n)2125826Ssam branch( n ){
2225826Ssam /* output a branch to label n */
2325826Ssam /* exception is an ordinary function branching to retlab: then, return */
2432866Sdonn 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
defalign(n)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
locctr(l)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;
6232866Sdonn 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
deflab(n)9425826Ssam deflab( n ){
9525826Ssam /* output something to define the current position as label n */
96*34582Sdonn if (nerrors) return;
9725826Ssam printf( "L%d:\n", n );
9825826Ssam }
9925826Ssam
10025826Ssam int crslab = 10;
10125826Ssam
getlab()10225826Ssam getlab(){
10325826Ssam /* return a number usable for a label */
10425826Ssam return( ++crslab );
10525826Ssam }
10625826Ssam
10725826Ssam
efcode()10825826Ssam efcode(){
10925826Ssam /* code for the end of a function */
11025826Ssam
11125826Ssam if( strftn ){ /* copy output (in R2) to caller */
11225826Ssam register NODE *l, *r;
11325826Ssam register struct symtab *p;
11425826Ssam register TWORD t;
11525826Ssam register int i;
11625826Ssam
11725826Ssam p = &stab[curftn];
11825826Ssam t = p->stype;
11925826Ssam t = DECREF(t);
12025826Ssam
12125826Ssam deflab( retlab );
12225826Ssam
12325826Ssam i = getlab(); /* label for return area */
12425826Ssam #ifndef LCOMM
12526162Ssam putstr(" .data\n" );
12626162Ssam putstr(" .align 2\n" );
12725826Ssam printf("L%d: .space %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR );
12826162Ssam putstr(" .text\n" );
12925826Ssam #else
13025826Ssam { int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR;
13125826Ssam if (sz % (SZINT/SZCHAR))
13225826Ssam sz += (SZINT/SZCHAR) - (sz % (SZINT/SZCHAR));
13325826Ssam printf(" .lcomm L%d,%d\n", i, sz);
13425826Ssam }
13525826Ssam #endif
13625826Ssam psline();
13725826Ssam printf(" movab L%d,r1\n", i);
13825826Ssam
13925826Ssam reached = 1;
14025826Ssam l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
14125826Ssam l->tn.rval = 1; /* R1 */
14225826Ssam l->tn.lval = 0; /* no offset */
14325826Ssam r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
14425826Ssam r->tn.rval = 0; /* R0 */
14525826Ssam r->tn.lval = 0;
14625826Ssam l = buildtree( UNARY MUL, l, NIL );
14725826Ssam r = buildtree( UNARY MUL, r, NIL );
14825826Ssam l = buildtree( ASSIGN, l, r );
14925826Ssam l->in.op = FREE;
15025826Ssam ecomp( l->in.left );
15125826Ssam printf( " movab L%d,r0\n", i );
15225826Ssam /* turn off strftn flag, so return sequence will be generated */
15325826Ssam strftn = 0;
15425826Ssam }
15525826Ssam branch( retlab );
15625826Ssam p2bend();
15725826Ssam fdefflag = 0;
15825826Ssam }
15925826Ssam
16025826Ssam int ftlab1, ftlab2;
16125826Ssam
bfcode(a,n)16225826Ssam bfcode( a, n ) int a[]; {
16325826Ssam /* code for the beginning of a function; a is an array of
16425826Ssam indices in stab for the arguments; n is the number */
16525826Ssam register i;
16625826Ssam register temp;
16725826Ssam register struct symtab *p;
16825826Ssam int off;
16925826Ssam #ifdef REG_CHAR
17025826Ssam char *toreg();
17125826Ssam #endif
17225826Ssam char *rname();
17325826Ssam
17432866Sdonn if( nerrors ) return;
17532866Sdonn (void) locctr( PROG );
17625826Ssam p = &stab[curftn];
17726162Ssam putstr( " .align 1\n");
17825826Ssam defnam( p );
17925826Ssam temp = p->stype;
18025826Ssam temp = DECREF(temp);
18125826Ssam strftn = (temp==STRTY) || (temp==UNIONTY);
18225826Ssam
18325826Ssam retlab = getlab();
18425826Ssam
18525826Ssam /* routine prolog */
18625826Ssam
18725826Ssam printf( " .word L%d\n", ftnno);
18825826Ssam ftlab1 = getlab();
18925826Ssam ftlab2 = getlab();
19025826Ssam printf( " jbr L%d\n", ftlab1);
19125826Ssam printf( "L%d:\n", ftlab2);
19225826Ssam if( proflg ) { /* profile code */
19325826Ssam i = getlab();
19425826Ssam printf(" pushl $L%d\n", i);
19526162Ssam putstr(" callf $8,mcount\n");
19626162Ssam putstr(" .data\n");
19726162Ssam putstr(" .align 2\n");
19825826Ssam printf("L%d: .long 0\n", i);
19926162Ssam putstr(" .text\n");
20025826Ssam psline();
20125826Ssam }
20225826Ssam
20325826Ssam off = ARGINIT;
20425826Ssam
20525826Ssam for( i=0; i<n; ++i ){
20625826Ssam p = &stab[a[i]];
20725826Ssam if( p->sclass == REGISTER ){
20825826Ssam temp = p->offset; /* save register number */
20925826Ssam p->sclass = PARAM; /* forget that it is a register */
21025826Ssam p->offset = NOOFFSET;
21132866Sdonn (void) oalloc( p, &off );
21225826Ssam #ifdef REG_CHAR
21325826Ssam printf( " %s", toreg(p->stype)) );
21425826Ssam #else
21526162Ssam putstr(" movl");
21625826Ssam #endif
21725826Ssam printf( " %d(fp),%s\n", p->offset/SZCHAR, rname(temp) );
21825826Ssam p->offset = temp; /* remember register number */
21925826Ssam p->sclass = REGISTER; /* remember that it is a register */
22025826Ssam #ifdef REG_CHAR
22125826Ssam temp = p->stype;
22225826Ssam if( temp==CHAR || temp==SHORT )
22325826Ssam p->stype = INT;
22425826Ssam else if( temp==UCHAR || temp==USHORT )
22525826Ssam p->stype = UNSIGNED;
22625826Ssam #endif
22725826Ssam }
22825826Ssam else if( p->stype == STRTY || p->stype == UNIONTY ) {
22925826Ssam p->offset = NOOFFSET;
23025826Ssam if( oalloc( p, &off ) ) cerror( "bad argument" );
23125826Ssam SETOFF( off, ALSTACK );
23225826Ssam }
23325826Ssam else {
23425826Ssam if( oalloc( p, &off ) ) cerror( "bad argument" );
23525826Ssam }
23625826Ssam
23725826Ssam }
23832866Sdonn if (gdebug && !nerrors) {
23931753Ssam #ifdef STABDOT
24031753Ssam pstabdot(N_SLINE, lineno);
24131753Ssam #else
24231753Ssam pstab(NULLNAME, N_SLINE);
24331753Ssam printf("0,%d,LL%d\n", lineno, labelno);
24431753Ssam printf("LL%d:\n", labelno++);
24531753Ssam #endif
24632866Sdonn }
24725826Ssam fdefflag = 1;
24825826Ssam }
24925826Ssam
bccode()25025826Ssam bccode(){ /* called just before the first executable statment */
25125826Ssam /* by now, the automatics and register variables are allocated */
25225826Ssam SETOFF( autooff, SZINT );
25325826Ssam /* set aside store area offset */
25425826Ssam p2bbeg( autooff, regvar );
25525826Ssam }
25625826Ssam
25732866Sdonn /*ARGSUSED*/
ejobcode(flag)25825826Ssam ejobcode( flag ){
25925826Ssam /* called just before final exit */
26025826Ssam /* flag is 1 if errors, 0 if none */
26125826Ssam }
26225826Ssam
26332866Sdonn #ifndef aobeg
aobeg()26425826Ssam aobeg(){
26525826Ssam /* called before removing automatics from stab */
26625826Ssam }
26732866Sdonn #endif aobeg
26825826Ssam
26932866Sdonn #ifndef aocode
27032866Sdonn /*ARGSUSED*/
27125826Ssam aocode(p) struct symtab *p; {
27225826Ssam /* called when automatic p removed from stab */
27325826Ssam }
27432866Sdonn #endif aocode
27525826Ssam
27632866Sdonn #ifndef aoend
aoend()27725826Ssam aoend(){
27825826Ssam /* called after removing all automatics from stab */
27925826Ssam }
28032866Sdonn #endif aoend
28125826Ssam
defnam(p)28225826Ssam defnam( p ) register struct symtab *p; {
28325826Ssam /* define the current location as the name p->sname */
28425826Ssam
28525826Ssam if( p->sclass == EXTDEF ){
28625826Ssam printf( " .globl %s\n", exname( p->sname ) );
28725826Ssam }
28825826Ssam if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset );
28925826Ssam else printf( "%s:\n", exname( p->sname ) );
29025826Ssam
29125826Ssam }
29225826Ssam
bycode(t,i)29325826Ssam bycode( t, i ){
29425826Ssam #ifdef ASSTRINGS
29525826Ssam static int lastoctal = 0;
29625826Ssam #endif
29725826Ssam
29825826Ssam /* put byte i+1 in a string */
29925826Ssam
30032866Sdonn if ( nerrors ) return;
30125826Ssam #ifdef ASSTRINGS
30225826Ssam
30325826Ssam i &= 077;
30425826Ssam if ( t < 0 ){
30526162Ssam if ( i != 0 ) putstr( "\"\n" );
30625826Ssam } else {
30726162Ssam if ( i == 0 ) putstr("\t.ascii\t\"");
30825826Ssam if ( t == '\\' || t == '"'){
30925826Ssam lastoctal = 0;
31025826Ssam printf("\\%c", t);
31125826Ssam }
31225826Ssam else if ( t < 040 || t >= 0177 ){
31325826Ssam lastoctal++;
31425826Ssam printf("\\%o",t);
31525826Ssam }
31625826Ssam else if ( lastoctal && '0' <= t && t <= '9' ){
31725826Ssam lastoctal = 0;
31825826Ssam printf("\"\n\t.ascii\t\"%c", t );
31925826Ssam }
32025826Ssam else
32125826Ssam {
32225826Ssam lastoctal = 0;
32325826Ssam putchar(t);
32425826Ssam }
32526162Ssam if ( i == 077 ) putstr("\"\n");
32625826Ssam }
32725826Ssam #else
32825826Ssam
32925826Ssam i &= 07;
33025826Ssam if( t < 0 ){ /* end of the string */
33126162Ssam if( i != 0 ) putchar( '\n' );
33225826Ssam }
33325826Ssam
33425826Ssam else { /* stash byte t into string */
33526162Ssam if( i == 0 ) putstr( " .byte " );
33626162Ssam else putchar( ',' );
33725826Ssam printf( "0x%x", t );
33826162Ssam if( i == 07 ) putchar( '\n' );
33925826Ssam }
34025826Ssam #endif
34125826Ssam }
34225826Ssam
zecode(n)34325826Ssam zecode( n ){
34425826Ssam /* n integer words of zeros */
34525826Ssam OFFSZ temp;
34625826Ssam if( n <= 0 ) return;
34725826Ssam printf( " .space %d\n", (SZINT/SZCHAR)*n );
34825826Ssam temp = n;
34925826Ssam inoff += temp*SZINT;
35025826Ssam }
35125826Ssam
35232866Sdonn /*ARGSUSED*/
fldal(t)35325826Ssam fldal( t ) unsigned t; { /* return the alignment of field of type t */
35425826Ssam uerror( "illegal field type" );
35525826Ssam return( ALINT );
35625826Ssam }
35725826Ssam
35832866Sdonn /*ARGSUSED*/
35925826Ssam fldty( p ) struct symtab *p; { /* fix up type of field p */
36025826Ssam ;
36125826Ssam }
36225826Ssam
36332866Sdonn /*ARGSUSED*/
where(c)36425826Ssam where(c){ /* print location of error */
36525826Ssam /* c is either 'u', 'c', or 'w' */
36625826Ssam /* GCOS version */
36725826Ssam fprintf( stderr, "%s, line %d: ", ftitle, lineno );
36825826Ssam }
36925826Ssam
37025826Ssam
37125826Ssam #ifdef REG_CHAR
37225826Ssam /* tbl - toreg() returns a pointer to a char string
37325826Ssam which is the correct "register move" for the passed type
37425826Ssam */
37525826Ssam struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] =
37625826Ssam {
37725826Ssam CHAR, "cvtbl",
37825826Ssam SHORT, "cvtwl",
37925826Ssam UCHAR, "movzbl",
38025826Ssam USHORT, "movzwl",
38125826Ssam 0, "movl"
38225826Ssam };
38325826Ssam
38425826Ssam char
toreg(type)38525826Ssam *toreg(type)
38625826Ssam TWORD type;
38725826Ssam {
38825826Ssam struct type_move *p;
38925826Ssam
39025826Ssam for ( p=toreg_strs; p->fromtype != 0; p++)
39125826Ssam if (p->fromtype == type) return(p->tostrng);
39225826Ssam
39325826Ssam /* type not found, must be a word type */
39425826Ssam return(p->tostrng);
39525826Ssam }
39625826Ssam /* tbl */
39725826Ssam #endif
39825826Ssam
39925826Ssam
main(argc,argv)40025826Ssam main( argc, argv ) char *argv[]; {
40125826Ssam #ifdef BUFSTDERR
40225826Ssam char errbuf[BUFSIZ];
40325826Ssam setbuf(stderr, errbuf);
40425826Ssam #endif
40525826Ssam return(mainp1( argc, argv ));
40625826Ssam }
40725826Ssam
40825826Ssam struct sw heapsw[SWITSZ]; /* heap for switches */
40925826Ssam
genswitch(p,n)41025826Ssam genswitch(p,n) register struct sw *p;{
41125826Ssam /* p points to an array of structures, each consisting
41225826Ssam of a constant value and a label.
41325826Ssam The first is >=0 if there is a default label;
41425826Ssam its value is the label number
41525826Ssam The entries p[1] to p[n] are the nontrivial cases
41625826Ssam */
41725826Ssam register i;
41825826Ssam register CONSZ j;
41925826Ssam register CONSZ unsigned range;
42025826Ssam register dlab, swlab;
42125826Ssam
42232866Sdonn if( nerrors ) return;
42325826Ssam range = p[n].sval-p[1].sval;
42425826Ssam
42525826Ssam if( range <= 3*n && n>=4 ){ /* implement a direct switch */
42625826Ssam
42725826Ssam swlab = getlab();
42825826Ssam dlab = p->slab >= 0 ? p->slab : getlab();
42925826Ssam
43025826Ssam /* already in r0 */
43126162Ssam putstr( " casel r0,$" );
43225826Ssam printf( CONFMT, p[1].sval );
43326162Ssam putstr(",$");
43425826Ssam printf( CONFMT, range);
43525826Ssam printf("\n .align 1\nL%d:\n", swlab);
43625826Ssam for( i=1,j=p[1].sval; i<=n; j++) {
43725826Ssam printf(" .word L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab),
43825826Ssam swlab);
43925826Ssam }
44025826Ssam
44125826Ssam if( p->slab >= 0 ) branch( dlab );
44225826Ssam else printf("L%d:\n", dlab);
44325826Ssam return;
44425826Ssam
44525826Ssam }
44625826Ssam
44725826Ssam if( n>8 ) { /* heap switch */
44825826Ssam
44925826Ssam heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab();
45025826Ssam makeheap(p, n, 1); /* build heap */
45125826Ssam
45225826Ssam walkheap(1, n); /* produce code */
45325826Ssam
45425826Ssam if( p->slab >= 0 )
45525826Ssam branch( dlab );
45625826Ssam else
45725826Ssam printf("L%d:\n", dlab);
45825826Ssam return;
45925826Ssam }
46025826Ssam
46125826Ssam /* debugging code */
46225826Ssam
46325826Ssam /* out for the moment
46425826Ssam if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) );
46525826Ssam */
46625826Ssam
46725826Ssam /* simple switch code */
46825826Ssam
46925826Ssam for( i=1; i<=n; ++i ){
47025826Ssam /* already in r0 */
47125826Ssam
47226162Ssam putstr( " cmpl r0,$" );
47325826Ssam printf( CONFMT, p[i].sval );
47425826Ssam printf( "\n jeql L%d\n", p[i].slab );
47525826Ssam }
47625826Ssam
47725826Ssam if( p->slab>=0 ) branch( p->slab );
47825826Ssam }
47925826Ssam
makeheap(p,m,n)48025826Ssam makeheap(p, m, n)
48125826Ssam register struct sw *p;
48225826Ssam {
48325826Ssam register int q;
48425826Ssam
48532866Sdonn q = selectheap(m);
48625826Ssam heapsw[n] = p[q];
48725826Ssam if( q>1 ) makeheap(p, q-1, 2*n);
48825826Ssam if( q<m ) makeheap(p+q, m-q, 2*n+1);
48925826Ssam }
49025826Ssam
selectheap(m)49132866Sdonn selectheap(m) {
49225826Ssam register int l,i,k;
49325826Ssam
49425826Ssam for(i=1; ; i*=2)
49525826Ssam if( (i-1) > m ) break;
49625826Ssam l = ((k = i/2 - 1) + 1)/2;
49725826Ssam return( l + (m-k < l ? m-k : l));
49825826Ssam }
49925826Ssam
walkheap(start,limit)50025826Ssam walkheap(start, limit)
50125826Ssam {
50225826Ssam int label;
50325826Ssam
50425826Ssam
50525826Ssam if( start > limit ) return;
50626162Ssam putstr( " cmpl r0,$" );
50725826Ssam printf( CONFMT, heapsw[start].sval);
50825826Ssam printf("\n jeql L%d\n", heapsw[start].slab);
50925826Ssam if( (2*start) > limit ) {
51025826Ssam printf(" jbr L%d\n", heapsw[0].slab);
51125826Ssam return;
51225826Ssam }
51325826Ssam if( (2*start+1) <= limit ) {
51425826Ssam label = getlab();
51525826Ssam printf(" jgtr L%d\n", label);
51625826Ssam } else
51725826Ssam printf(" jgtr L%d\n", heapsw[0].slab);
51825826Ssam walkheap( 2*start, limit);
51925826Ssam if( (2*start+1) <= limit ) {
52025826Ssam printf("L%d:\n", label);
52125826Ssam walkheap( 2*start+1, limit);
52225826Ssam }
52325826Ssam }
524