#ifndef lint static char sccsid[] = "@(#)code.c 1.1 86/02/03 SMI"; #endif # include "cpass1.h" # include <sys/types.h> # include <a.out.h> # include <stab.h> #ifndef VAX extern char *rnames[]; #endif #ifndef ONEPASS int usedregs; int usedfpregs; #endif !ONEPASS int proflg = 0; /* are we generating profiling code? */ int strftn = 0; /* is the current function one which returns a value */ int fltfun = 0; /* is function float or double? */ int optimize = 0; /* is optimization enabled? If so, no SLINEs for you */ #ifdef STACKPROBE int noprobe= 1; /* are we not generating 68000 stack probes? */ #endif int gdebug; int fdefflag; /* are we within a function definition ? */ char NULLNAME[8]; int labelno; branch( n ) { /* output a branch to label n */ /* exception is an ordinary function branching to retlab: then, return */ if( n == retlab && !strftn ){ #ifdef VAX printf( " ret\n" ); #else printf( " jra LE%d\n", ftnno ); #endif } else #ifdef VAX printf( " jbr L%d\n", n ); #else printf(" jra L%d\n", n ); #endif } int lastloc = { -1 }; #ifdef VAX short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3}; #define LOG2SZ 9 #endif defalign(n) { /* cause the alignment to become a multiple of n */ #ifdef VAX n /= SZCHAR; if( lastloc != PROG && n > 1 ) printf( " .align %d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 ); #else if ( lastloc != PROG && n > 1 ) printf(" .even\n"); #endif } locctr( l ) { register temp; /* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */ if( l == lastloc ) return(l); temp = lastloc; lastloc = l; switch( l ){ case PROG: printf( " .text\n" ); break; case DATA: case ADATA: if (temp != DATA && temp != ADATA) printf( " .data\n" ); break; /* The following levels of .data statements will be problems if there is ever any relocation required. */ case STRNG: #ifdef VAX printf( " .data 1\n" ); #else printf( " .data1\n" ); #endif break; case ISTRNG: #ifdef VAX printf( " .data 2\n" ); #else printf( " .data2\n" ); #endif break; case STAB: printf( " .stab\n" ); break; default: cerror( "illegal location counter" ); } return( temp ); } deflab( n ) { /* output something to define the current position as label n */ printf( "L%d:\n", n ); } int crslab = 10; getlab() { /* return a number usable for a label */ return( ++crslab ); } #ifdef VAX int ent_mask[] = { 0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0}; int reg_use = 11; #else extern int regsused; #endif efcode() { /* code for the end of a function */ #ifdef VAX if( strftn ){ /* copy output (in R2) to caller */ register NODE *l, *r; register struct symtab *p; register TWORD t; register int j; int i; p = STP(curftn); t = p->stype; t = DECREF(t); deflab( retlab ); i = getlab(); /* label for return area */ #ifndef LCOMM printf(" .data\n" ); printf(" .align 2\n" ); printf("L%d: .space %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR ); printf(" .text\n" ); #else { int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR; if (sz % sizeof (int)) sz += sizeof (int) - (sz % sizeof (int)); printf(" .lcomm L%d,%d\n", i, sz); } #endif psline(lineno); printf(" movab L%d,r1\n", i); reached = 1; l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); l->tn.rval = 1; /* R1 */ l->tn.lval = 0; /* no offset */ r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); r->tn.rval = 0; /* R0 */ r->tn.lval = 0; l = buildtree( UNARY MUL, l, NIL ); r = buildtree( UNARY MUL, r, NIL ); l = buildtree( ASSIGN, l, r ); l->in.op = FREE; ecomp( l->in.left ); printf( " movab L%d,r0\n", i ); /* turn off strftn flag, so return sequence will be generated */ strftn = 0; } branch( retlab ); #ifndef VMS printf( " .set L%d,0x%x\n", ftnno, ent_mask[reg_use] ); #else printf( " .set L%d,%d # Hex = 0x%x\n", ftnno, 0x3c| ent_mask[reg_use], ent_mask[reg_use] ); /* KLS kludge, under VMS if you use regs 2-5, you must save them. */ #endif reg_use = 11; p2bend(); fdefflag = 0; #else /* 68k code */ /* NOTE: We still have to add FTN and stab support here */ if( strftn ){ /* copy output (in r0) to caller */ register struct symtab *p; register int stlab; register int count; int size; p = STP(curftn); deflab( retlab ); stlab = getlab(); printf( " movl d0,a0\n" ); printf( " movl #L%d,a1\n", stlab ); size = tsize( DECREF(p->stype), p->dimoff, p->sizoff ) / SZCHAR; printf( " .bss\nL%d: .=.+%d\n .text\n", stlab, size ); if (size <= 20) { count = size/2; while( size ){ /* simple load/store loop */ count = (size > 2) ? 4 : 2; printf(" mov%c a0@+,a1@+\n", count==2 ? 'w' : 'l'); size -= count; } } else { int residue; count = size / sizeof(long); residue = size % sizeof(long); if (count > 0x7fff) { printf(" movl #%d,d0\n", count-1); printf("1: movl a0@+,a1@+\n"); printf(" dbra d0,1b\n"); printf(" subql #1,d0\n"); printf(" jcc 1b\n"); } else { printf(" movw #%d,d0\n", count-1); printf("1: movl a0@+,a1@+\n"); printf(" dbra d0,1b\n"); } switch(residue) { case 1: printf(" movb a0@+,a1@+\n"); break; case 2: printf(" movw a0@+,a1@+\n"); break; case 3: printf(" movw a0@+,a1@+\n"); printf(" movb a0@+,a1@+\n"); break; default: break; } } printf( " movl #L%d,d0\n", stlab ); /* turn off strftn flag, so return sequence will be generated */ strftn = 0; } /* branch( retlab ); */ p2bend(); dbfunend(labelno++); fdefflag = 0; #endif } int ftlab1, ftlab2; bfcode( a, n ) int a[]; { /* code for the beginning of a function; a is an array of indices in stab for the arguments; n is the number */ register i; register temp; register struct symtab *p; int off; char *toreg(); locctr( PROG ); p = STP(curftn); if (p == NULL) return; temp = p->stype; temp = DECREF(temp); #ifdef VAX printf( " .align 1\n"); #else /* magic cookie for c2 */ /* uses old (pre-TERROR) type format */ printf( "|#PROC# %#o\n", (temp&BTMASK) | ((temp&~BTMASK)>>2) ); #endif defnam( p ); strftn = (temp==STRTY) || (temp==UNIONTY); fltfun = (temp==FLOAT) || (temp==DOUBLE); retlab = getlab(); /* routine prolog */ #ifdef VAX printf( " .word L%d\n", ftnno); #else !VAX printf(" link a6,#0\n"); printf(" addl #-LF%d,sp\n", ftnno); #ifdef STACKPROBE if (noprobe!=1){ printf(" tstb sp@(-LP%d)\n",ftnno); } #endif printf(" moveml #LS%d,sp@\n",ftnno); if (use68881) { /* * save floating registers used for variables */ if (use68020) { printf(" fmovem #LSS%d,a6@(-LFF%d:l)\n", ftnno, ftnno); } else { /* 68881 without 68020; unlikely combination */ printf(" movl #-LFF%d,a0\n", ftnno); printf(" fmovem #LSS%d,a6@(0,a0:l)\n", ftnno); } } #endif !VAX #ifdef VAX ftlab1 = getlab(); ftlab2 = getlab(); printf( " jbr L%d\n", ftlab1); printf( "L%d:\n", ftlab2); #endif if( proflg ) { /* profile code */ i = getlab(); #ifdef VAX printf(" movab L%d,r0\n", i); printf(" jsb mcount\n"); printf(" .data\n"); printf(" .align 2\n"); printf("L%d: .long 0\n", i); printf(" .text\n"); #else printf(" movl #L%d,a0\n",i); printf(" jsr mcount\n"); printf(" .bss\n .even\n"); printf("L%d: .skip 4\n .text\n",i); #endif psline(lineno); } off = ARGINIT; for( i=0; i<n; ++i ){ #ifndef VAX char type; #endif p = STP(a[i]); if( p->sclass == REGISTER ){ temp = p->offset; /* save register number */ p->sclass = PARAM; /* forget that it is a register */ p->offset = NOOFFSET; oalloc( p, &off ); #ifdef VAX /*tbl*/ printf( " %s %d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp ); #else printf( " %s a6@(%d),%s\n", toreg(p->stype), p->offset/SZCHAR, rnames[temp]); markused(temp); #endif p->offset = temp; /* remember register number */ p->sclass = REGISTER; /* remember that it is a register */ } /* The 68k doesn't have this code. I'll try it for a while */ #ifdef VAX else if( p->stype == STRTY || p->stype == UNIONTY ) { p->offset = NOOFFSET; if( oalloc( p, &off ) ) cerror( "bad argument" ); SETOFF( off, ALSTACK ); } #endif else { if( oalloc( p, &off ) ) cerror( "bad argument" ); } } fdefflag = 1; } bccode() { /* called just before the first executable statment */ /* by now, the automatics and register variables are allocated */ SETOFF( autooff, SZINT ); /* set aside store area offset */ p2bbeg( autooff, regvar ); #ifdef VAX reg_use = (reg_use > regvar ? regvar : reg_use); #endif } ejobcode( flag ) { /* called just before final exit */ /* flag is 1 if errors, 0 if none */ ejsdb(); } aobeg() { /* called before removing automatics from stab */ } aocode(p) struct symtab *p; { /* called when automatic p removed from stab */ } aoend() { /* called after removing all automatics from stab */ } defnam( p ) register struct symtab *p; { /* define the current location as the name p->sname */ if( p->sclass == EXTDEF ){ printf( " .globl %s\n", exname( p->sname ) ); } if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset ); else printf( "%s:\n", exname( p->sname ) ); } bycode( t, i ) { #ifdef ASSTRINGS static int lastoctal = 0; #endif /* put byte i+1 in a string */ #ifdef ASSTRINGS i &= 077; if ( t < 0 ){ if ( i != 0 ) printf( "\"\n" ); } else { if ( i == 0 ) printf("\t.ascii\t\""); if ( t == '\\' || t == '"'){ lastoctal = 0; printf("\\%c", t); } /* * We escape the colon in strings so that * c2 will, in its infinite wisdom, interpret * the characters preceding the colon as a label. * If we didn't escape the colon, c2 would * throw away any trailing blanks or tabs after * the colon, but reconstruct a assembly * language semantically correct program. * C2 hasn't been taught about strings. */ else if ( t == ':' || t < 040 || t >= 0177 || t == '|' || t == ';' ){ lastoctal++; printf("\\%o",t); } else if ( lastoctal && '0' <= t && t <= '9' ){ lastoctal = 0; printf("\"\n\t.ascii\t\"%c", t ); } else { lastoctal = 0; putchar(t); } if ( i == 077 ) printf("\"\n"); } #else i &= 07; if( t < 0 ){ /* end of the string */ if( i != 0 ) printf( "\n" ); } else { /* stash byte t into string */ if( i == 0 ) printf( " .byte " ); else printf( "," ); #ifdef VAX printf( "0x%x", t ); #else printf( "0x%x", t ); #endif if( i == 07 ) printf( "\n" ); } #endif } zecode( n ) { /* n integer words of zeros */ OFFSZ temp; #ifndef VAX register i; #endif if( n <= 0 ) return; #ifdef VAX printf( " .space %d\n", (SZINT/SZCHAR)*n ); #else printf( " .skip %d\n", (SZINT/SZCHAR)*n ); #endif temp = n; inoff += temp*SZINT; } fldal( t ) unsigned t; { /* return the alignment of field of type t */ uerror( "illegal field type" ); return( ALINT ); } fldty( p ) struct symtab *p; { /* fix up type of field p */ ; } where(c) { /* print location of error */ /* c is either 'u', 'c', or 'w' */ /* GCOS version */ fprintf( stderr, "%s, line %d: ", ftitle, lineno ); } /* tbl - toreg() returns a pointer to a char string which is the correct "register move" for the passed type */ struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] = { #ifdef VAX CHAR, "cvtbl", SHORT, "cvtwl", INT, "movl", LONG, "movl", FLOAT, "movf", DOUBLE, "movd", UCHAR, "movzbl", USHORT, "movzwl", UNSIGNED, "movl", ULONG, "movl", #else CHAR, "movb", UCHAR, "movb", SHORT, "movw", USHORT, "movw", #endif -1, "" }; char *toreg(type) TWORD type; { struct type_move *p; for ( p=toreg_strs; p->fromtype > 0; p++) if (p->fromtype == type) return(p->tostrng); /* type not found, must be a pointer type */ if (use68881 && type == FLOAT) { return("fmoves"); } if (use68881 && type == DOUBLE) { return("fmoved"); } return("movl"); } /* tbl */ main( argc, argv ) char *argv[]; { int v; #ifdef BUFSTDERR char errbuf[BUFSIZ]; setbuf(stderr, errbuf); #endif /* ffloat_(); /* HACK -- avoid sky board even if present */ v = mainp1( argc, argv ); floatnote(); exit( v ); } struct sw heapsw[SWITSZ]; /* heap for switches */ genswitch(p,n) register struct sw *p; { /* p points to an array of structures, each consisting of a constant value and a label. The first is >=0 if there is a default label; its value is the label number The entries p[1] to p[n] are the nontrivial cases */ register i; register CONSZ j, range; register dlab, swlab; range = p[n].sval-p[1].sval; if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */ dlab = p->slab >= 0 ? p->slab : getlab(); #ifdef VAX swlab = getlab(); /* already in r0 */ printf(" casel r0,$%ld,$%ld\n", p[1].sval, range); printf("L%d:\n", swlab); for( i=1,j=p[1].sval; i<=n; j++) { printf(" .word L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab), swlab); } if( p->slab >= 0 ) branch( dlab ); else printf("L%d:\n", dlab); #else if( p[1].sval ){ printf( " subl #" ); printf( CONFMT, p[1].sval ); printf( ",d0\n" ); } /* note that this is a cl; it thus checks for numbers below range as well as out of range. */ printf( " cmpl #%ld,d0\n", range ); printf( " jhi L%d\n", dlab ); if (use68020) { printf( " movw pc@(6,d0:w:2),d0\n" ); } else { printf( " addw d0,d0\n" ); printf( " movw pc@(6,d0:w),d0\n" ); } printf( " jmp pc@(2,d0:w)\n" ); /* output table */ /* printf( "L%d = \n", swlab=getlab() ); */ printf( "L%d: \n", swlab=getlab() ); for( i=1,j=p[1].sval; i<=n; ++j ) printf( " .word L%d-L%d\n", ( j == p[i].sval ) ? p[i++].slab : dlab, swlab ); if( p->slab< 0 ) deflab( dlab ); #endif return; } if( n>8 ) { /* heap switch */ #ifdef VAX heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab(); makeheap(p, n, 1); /* build heap */ walkheap(1, n); /* produce code */ if( p->slab >= 0 ) branch( dlab ); else printf("L%d:\n", dlab); return; #else /* drop comparison loop, then switch table, then comparison table */ int tbllab, llab; int biggest, smallest, range; char sizechar; char *sizeword; int unsgned = 1; tbllab = getlab(); dlab = p->slab>=0 ? p->slab : getlab(); biggest = p[n].sval; smallest = p[1].sval; range = biggest-smallest; if (biggest<=0377 && smallest>=0){ sizechar = 'b';sizeword = ".byte"; smallest = 0; }else if ( range<=0377 && range > 0 ){ sizechar = 'b';sizeword = ".byte"; }else if (biggest<=0177777 && smallest>=0){ sizechar = 'w';sizeword = ".word"; smallest = 0; }else if ( range<=0177777 && range > 0 ){ sizechar = 'w';sizeword = ".word"; }else{ sizechar = 'l';sizeword = ".long"; smallest = 0; unsgned = 0; } if( smallest ){ printf( " %sl #%d,d0\n", smallest<0?"add":"sub", abs(smallest) ); printf( " cmpl #%d,d0\n", range ); printf( " jhi L%d\n", dlab ); } else if (sizechar != 'l' ){ printf( " cmpl #%d,d0\n", biggest ); printf( " jhi L%d\n", dlab ); } printf( " lea L%d,a0\n mov%s #%d,d1\n", tbllab, (n<=128)?"eq":"w",n-1); llab = getlab(); printf( "L%d: cmp%c a0@+,d0\n db%s d1,L%d\n", llab, sizechar, unsgned?"cc":"ge", llab); printf( " jne L%d\n", dlab ); if (use68020) { printf( " movw pc@(6,d1:w:2),d0\n" ); } else { printf( " addw d1,d1\n" ); printf( " movw pc@(6,d1:w),d0\n" ); } printf( " jmp pc@(2,d0:w)\n" ); /* put out statement list forwards, comparison table backwards*/ printf( "L%d: \n", swlab=getlab() ); for( i=1; i<=n; i++ ) printf( " .word L%d-L%d\n", p[i].slab, swlab ); printf( "L%d: \n", tbllab ); for( i=n; i>=1; i-- ) printf( " %s %d\n", sizeword, p[i].sval-smallest ); if (sizechar == 'b') printf(" .even\n"); if( p->slab< 0 ) deflab( dlab ); return; #endif } /* debugging code */ /* out for the moment if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) ); */ /* simple switch code */ for( i=1; i<=n; ++i ){ /* already in r0 */ #ifdef VAX printf( " cmpl r0,$" ); #else printf( " cmpl #" ); #endif printf( CONFMT, p[i].sval ); #ifdef VAX printf( "\n jeql L%d\n", p[i].slab ); #else printf( ",d0\n jeq L%d\n", p[i].slab ); #endif } if( p->slab>=0 ) branch( p->slab ); } #ifdef VAX makeheap(p, m, n) register struct sw *p; { register int q; q = select(m); heapsw[n] = p[q]; if( q>1 ) makeheap(p, q-1, 2*n); if( q<m ) makeheap(p+q, m-q, 2*n+1); } select(m) { register int l,i,k; for(i=1; ; i*=2) if( (i-1) > m ) break; l = ((k = i/2 - 1) + 1)/2; return( l + (m-k < l ? m-k : l)); } walkheap(start, limit) { int label; if( start > limit ) return; #ifdef VAX printf( " cmpl r0,$" ); #else printf( " cmpl #" ); #endif printf( CONFMT, heapsw[start].sval ); #ifdef VAX printf( "\n jeql L%d\n", heapsw[start].slab ); #else printf( ",d0\n beq L%d\n", heapsw[start].slab ); #endif if( (2*start) > limit ) { #ifdef VAX printf(" jbr L%d\n", heapsw[0].slab); #else printf(" bra L%d\n", heapsw[0].slab); #endif return; } if( (2*start+1) <= limit ) { label = getlab(); #ifdef VAX printf(" jgtr L%d\n", label); #else printf(" bgt L%d\n", label); #endif } else #ifdef VAX printf(" jgtr L%d\n", heapsw[0].slab); #else printf(" bgt L%d\n", heapsw[0].slab); #endif walkheap( 2*start, limit); if( (2*start+1) <= limit ) { printf("L%d:\n", label); walkheap( 2*start+1, limit); } } #endif VAX heap code