117737Sralph #ifndef lint
2*34580Sdonn static char *sccsid ="@(#)code.c 1.10 (Berkeley) 05/31/88";
317737Sralph #endif lint
417737Sralph
518556Sralph # include "pass1.h"
69700Slinton # include <sys/types.h>
79700Slinton # include <a.out.h>
89700Slinton # include <stab.h>
99700Slinton
109700Slinton int proflg = 0; /* are we generating profiling code? */
119700Slinton int strftn = 0; /* is the current function one which returns a value */
129700Slinton int gdebug;
139700Slinton int fdefflag; /* are we within a function definition ? */
1432912Sdonn #ifndef STABDOT
159700Slinton char NULLNAME[8];
1632912Sdonn #endif
179700Slinton int labelno;
189700Slinton
1924416Smckusick # define putstr(s) fputs((s), stdout)
2024416Smckusick
branch(n)219700Slinton branch( n ){
229700Slinton /* output a branch to label n */
239700Slinton /* exception is an ordinary function branching to retlab: then, return */
2432910Sdonn if( nerrors ) return;
259700Slinton if( n == retlab && !strftn ){
2624416Smckusick putstr( " ret\n" );
279700Slinton }
289700Slinton else printf( " jbr L%d\n", n );
299700Slinton }
309700Slinton
319700Slinton int lastloc = { -1 };
329700Slinton
339700Slinton short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3};
349700Slinton #define LOG2SZ 9
359700Slinton
defalign(n)369700Slinton defalign(n) {
379700Slinton /* cause the alignment to become a multiple of n */
389700Slinton n /= SZCHAR;
399700Slinton if( lastloc != PROG && n > 1 ) printf( " .align %d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 );
409700Slinton }
419700Slinton
locctr(l)429700Slinton locctr( l ){
439700Slinton register temp;
449700Slinton /* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB */
459700Slinton
469700Slinton if( l == lastloc ) return(l);
479700Slinton temp = lastloc;
489700Slinton lastloc = l;
4932910Sdonn if( nerrors ) return(temp);
509700Slinton switch( l ){
519700Slinton
529700Slinton case PROG:
5324416Smckusick putstr( " .text\n" );
549700Slinton psline();
559700Slinton break;
569700Slinton
579700Slinton case DATA:
589700Slinton case ADATA:
5924416Smckusick putstr( " .data\n" );
609700Slinton break;
619700Slinton
629700Slinton case STRNG:
6324416Smckusick putstr( " .data 1\n" );
649700Slinton break;
659700Slinton
669700Slinton case ISTRNG:
6724416Smckusick putstr( " .data 2\n" );
689700Slinton break;
699700Slinton
709700Slinton case STAB:
7124416Smckusick putstr( " .stab\n" );
729700Slinton break;
739700Slinton
749700Slinton default:
759700Slinton cerror( "illegal location counter" );
769700Slinton }
779700Slinton
789700Slinton return( temp );
799700Slinton }
809700Slinton
deflab(n)819700Slinton deflab( n ){
829700Slinton /* output something to define the current position as label n */
83*34580Sdonn if (nerrors) return;
849700Slinton printf( "L%d:\n", n );
859700Slinton }
869700Slinton
879700Slinton int crslab = 10;
889700Slinton
getlab()899700Slinton getlab(){
909700Slinton /* return a number usable for a label */
919700Slinton return( ++crslab );
929700Slinton }
939700Slinton
949700Slinton
959700Slinton int ent_mask[] = {
969700Slinton 0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0};
979700Slinton
989700Slinton int reg_use = 11;
999700Slinton
efcode()1009700Slinton efcode(){
1019700Slinton /* code for the end of a function */
1029700Slinton
1039700Slinton if( strftn ){ /* copy output (in R2) to caller */
1049700Slinton register NODE *l, *r;
1059700Slinton register struct symtab *p;
1069700Slinton register TWORD t;
1079700Slinton int i;
1089700Slinton
1099700Slinton p = &stab[curftn];
1109700Slinton t = p->stype;
1119700Slinton t = DECREF(t);
1129700Slinton
1139700Slinton deflab( retlab );
1149700Slinton
1159700Slinton i = getlab(); /* label for return area */
1169700Slinton #ifndef LCOMM
11724416Smckusick putstr(" .data\n" );
11824416Smckusick putstr(" .align 2\n" );
1199700Slinton printf("L%d: .space %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR );
12024416Smckusick putstr(" .text\n" );
1219700Slinton #else
1229700Slinton { int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR;
12332913Sdonn if (sz % (SZINT/SZCHAR))
12432913Sdonn sz += (SZINT/SZCHAR) - (sz % (SZINT/SZCHAR));
1259700Slinton printf(" .lcomm L%d,%d\n", i, sz);
1269700Slinton }
1279700Slinton #endif
1289700Slinton psline();
1299700Slinton printf(" movab L%d,r1\n", i);
1309700Slinton
1319700Slinton reached = 1;
1329700Slinton l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
1339700Slinton l->tn.rval = 1; /* R1 */
1349700Slinton l->tn.lval = 0; /* no offset */
1359700Slinton r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
1369700Slinton r->tn.rval = 0; /* R0 */
1379700Slinton r->tn.lval = 0;
1389700Slinton l = buildtree( UNARY MUL, l, NIL );
1399700Slinton r = buildtree( UNARY MUL, r, NIL );
1409700Slinton l = buildtree( ASSIGN, l, r );
1419700Slinton l->in.op = FREE;
1429700Slinton ecomp( l->in.left );
1439700Slinton printf( " movab L%d,r0\n", i );
1449700Slinton /* turn off strftn flag, so return sequence will be generated */
1459700Slinton strftn = 0;
1469700Slinton }
1479700Slinton branch( retlab );
1489700Slinton #ifndef VMS
1499700Slinton printf( " .set L%d,0x%x\n", ftnno, ent_mask[reg_use] );
1509700Slinton #else
1519700Slinton printf( " .set L%d,%d # Hex = 0x%x\n", ftnno, 0x3c| ent_mask[reg_use], ent_mask[reg_use] );
1529700Slinton /* KLS kludge, under VMS if you use regs 2-5, you must save them. */
1539700Slinton #endif
1549700Slinton reg_use = 11;
1559700Slinton p2bend();
1569700Slinton fdefflag = 0;
1579700Slinton }
1589700Slinton
1599700Slinton int ftlab1, ftlab2;
1609700Slinton
bfcode(a,n)1619700Slinton bfcode( a, n ) int a[]; {
1629700Slinton /* code for the beginning of a function; a is an array of
1639700Slinton indices in stab for the arguments; n is the number */
1649700Slinton register i;
1659700Slinton register temp;
1669700Slinton register struct symtab *p;
1679700Slinton int off;
16832913Sdonn #ifdef TRUST_REG_CHAR_AND_REG_SHORT
1699700Slinton char *toreg();
17032913Sdonn #endif
1719700Slinton
17232910Sdonn if( nerrors ) return;
17332912Sdonn (void) locctr( PROG );
1749700Slinton p = &stab[curftn];
17524416Smckusick putstr( " .align 1\n");
1769700Slinton defnam( p );
1779700Slinton temp = p->stype;
1789700Slinton temp = DECREF(temp);
1799700Slinton strftn = (temp==STRTY) || (temp==UNIONTY);
1809700Slinton
1819700Slinton retlab = getlab();
1829700Slinton
1839700Slinton /* routine prolog */
1849700Slinton
1859700Slinton printf( " .word L%d\n", ftnno);
1869700Slinton ftlab1 = getlab();
1879700Slinton ftlab2 = getlab();
1889700Slinton printf( " jbr L%d\n", ftlab1);
1899700Slinton printf( "L%d:\n", ftlab2);
1909700Slinton if( proflg ) { /* profile code */
1919700Slinton i = getlab();
1929700Slinton printf(" movab L%d,r0\n", i);
19324416Smckusick putstr(" jsb mcount\n");
19424416Smckusick putstr(" .data\n");
19524416Smckusick putstr(" .align 2\n");
1969700Slinton printf("L%d: .long 0\n", i);
19724416Smckusick putstr(" .text\n");
1989700Slinton psline();
1999700Slinton }
2009700Slinton
2019700Slinton off = ARGINIT;
2029700Slinton
2039700Slinton for( i=0; i<n; ++i ){
2049700Slinton p = &stab[a[i]];
2059700Slinton if( p->sclass == REGISTER ){
2069700Slinton temp = p->offset; /* save register number */
2079700Slinton p->sclass = PARAM; /* forget that it is a register */
2089700Slinton p->offset = NOOFFSET;
20932912Sdonn (void) oalloc( p, &off );
21032913Sdonn #ifdef TRUST_REG_CHAR_AND_REG_SHORT /* and reg double */
2119700Slinton /*tbl*/ printf( " %s %d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp );
21232913Sdonn #else
21332913Sdonn /*tbl*/ printf( " movl %d(ap),r%d\n", p->offset/SZCHAR, temp );
21432913Sdonn #endif
2159700Slinton p->offset = temp; /* remember register number */
2169700Slinton p->sclass = REGISTER; /* remember that it is a register */
2179700Slinton }
2189700Slinton else if( p->stype == STRTY || p->stype == UNIONTY ) {
2199700Slinton p->offset = NOOFFSET;
2209700Slinton if( oalloc( p, &off ) ) cerror( "bad argument" );
2219700Slinton SETOFF( off, ALSTACK );
2229700Slinton }
2239700Slinton else {
2249700Slinton if( oalloc( p, &off ) ) cerror( "bad argument" );
2259700Slinton }
2269700Slinton
2279700Slinton }
22832910Sdonn if (gdebug && !nerrors) {
22915896Ssam #ifdef STABDOT
23015896Ssam pstabdot(N_SLINE, lineno);
23115896Ssam #else
23215896Ssam pstab(NULLNAME, N_SLINE);
23315896Ssam printf("0,%d,LL%d\n", lineno, labelno);
23415896Ssam printf("LL%d:\n", labelno++);
23515896Ssam #endif
23615896Ssam }
2379700Slinton fdefflag = 1;
2389700Slinton }
2399700Slinton
bccode()2409700Slinton bccode(){ /* called just before the first executable statment */
2419700Slinton /* by now, the automatics and register variables are allocated */
2429700Slinton SETOFF( autooff, SZINT );
2439700Slinton /* set aside store area offset */
2449700Slinton p2bbeg( autooff, regvar );
2459700Slinton reg_use = (reg_use > regvar ? regvar : reg_use);
2469700Slinton }
2479700Slinton
24832911Sdonn /*ARGSUSED*/
ejobcode(flag)2499700Slinton ejobcode( flag ){
2509700Slinton /* called just before final exit */
2519700Slinton /* flag is 1 if errors, 0 if none */
2529700Slinton }
2539700Slinton
25432910Sdonn #ifndef aobeg
aobeg()2559700Slinton aobeg(){
2569700Slinton /* called before removing automatics from stab */
2579700Slinton }
25832910Sdonn #endif aobeg
2599700Slinton
26032910Sdonn #ifndef aocode
26132911Sdonn /*ARGSUSED*/
2629700Slinton aocode(p) struct symtab *p; {
2639700Slinton /* called when automatic p removed from stab */
2649700Slinton }
26532910Sdonn #endif aocode
2669700Slinton
26732910Sdonn #ifndef aoend
aoend()2689700Slinton aoend(){
2699700Slinton /* called after removing all automatics from stab */
2709700Slinton }
27132910Sdonn #endif aoend
2729700Slinton
defnam(p)2739700Slinton defnam( p ) register struct symtab *p; {
2749700Slinton /* define the current location as the name p->sname */
2759700Slinton
2769700Slinton if( p->sclass == EXTDEF ){
2779700Slinton printf( " .globl %s\n", exname( p->sname ) );
2789700Slinton }
2799700Slinton if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset );
2809700Slinton else printf( "%s:\n", exname( p->sname ) );
2819700Slinton
2829700Slinton }
2839700Slinton
bycode(t,i)2849700Slinton bycode( t, i ){
2859700Slinton #ifdef ASSTRINGS
2869700Slinton static int lastoctal = 0;
2879700Slinton #endif
2889700Slinton
2899700Slinton /* put byte i+1 in a string */
2909700Slinton
29132910Sdonn if ( nerrors ) return;
2929700Slinton #ifdef ASSTRINGS
2939700Slinton
2949700Slinton i &= 077;
2959700Slinton if ( t < 0 ){
29624416Smckusick if ( i != 0 ) putstr( "\"\n" );
2979700Slinton } else {
29824416Smckusick if ( i == 0 ) putstr("\t.ascii\t\"");
2999700Slinton if ( t == '\\' || t == '"'){
3009700Slinton lastoctal = 0;
3019700Slinton printf("\\%c", t);
3029700Slinton }
3039700Slinton /*
3049700Slinton * We escape the colon in strings so that
3059700Slinton * c2 will, in its infinite wisdom, interpret
3069700Slinton * the characters preceding the colon as a label.
3079700Slinton * If we didn't escape the colon, c2 would
3089700Slinton * throw away any trailing blanks or tabs after
3099700Slinton * the colon, but reconstruct a assembly
3109700Slinton * language semantically correct program.
3119700Slinton * C2 hasn't been taught about strings.
3129700Slinton */
3139700Slinton else if ( t == ':' || t < 040 || t >= 0177 ){
3149700Slinton lastoctal++;
3159700Slinton printf("\\%o",t);
3169700Slinton }
3179700Slinton else if ( lastoctal && '0' <= t && t <= '9' ){
3189700Slinton lastoctal = 0;
3199700Slinton printf("\"\n\t.ascii\t\"%c", t );
3209700Slinton }
3219700Slinton else
3229700Slinton {
3239700Slinton lastoctal = 0;
3249700Slinton putchar(t);
3259700Slinton }
32624416Smckusick if ( i == 077 ) putstr("\"\n");
3279700Slinton }
3289700Slinton #else
3299700Slinton
3309700Slinton i &= 07;
3319700Slinton if( t < 0 ){ /* end of the string */
33224416Smckusick if( i != 0 ) putchar( '\n' );
3339700Slinton }
3349700Slinton
3359700Slinton else { /* stash byte t into string */
33624416Smckusick if( i == 0 ) putstr( " .byte " );
33724416Smckusick else putchar( ',' );
3389700Slinton printf( "0x%x", t );
33924416Smckusick if( i == 07 ) putchar( '\n' );
3409700Slinton }
3419700Slinton #endif
3429700Slinton }
3439700Slinton
zecode(n)3449700Slinton zecode( n ){
3459700Slinton /* n integer words of zeros */
3469700Slinton OFFSZ temp;
3479700Slinton if( n <= 0 ) return;
3489700Slinton printf( " .space %d\n", (SZINT/SZCHAR)*n );
3499700Slinton temp = n;
3509700Slinton inoff += temp*SZINT;
3519700Slinton }
3529700Slinton
35332911Sdonn /*ARGSUSED*/
fldal(t)3549700Slinton fldal( t ) unsigned t; { /* return the alignment of field of type t */
3559700Slinton uerror( "illegal field type" );
3569700Slinton return( ALINT );
3579700Slinton }
3589700Slinton
35932911Sdonn /*ARGSUSED*/
3609700Slinton fldty( p ) struct symtab *p; { /* fix up type of field p */
3619700Slinton ;
3629700Slinton }
3639700Slinton
36432911Sdonn /*ARGSUSED*/
where(c)3659700Slinton where(c){ /* print location of error */
3669700Slinton /* c is either 'u', 'c', or 'w' */
3679700Slinton /* GCOS version */
3689700Slinton fprintf( stderr, "%s, line %d: ", ftitle, lineno );
3699700Slinton }
3709700Slinton
3719700Slinton
37232913Sdonn #ifdef TRUST_REG_CHAR_AND_REG_SHORT
3739700Slinton /* tbl - toreg() returns a pointer to a char string
3749700Slinton which is the correct "register move" for the passed type
3759700Slinton */
3769700Slinton struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] =
3779700Slinton {
37832913Sdonn INT, "movl",
37932913Sdonn UNSIGNED, "movl",
38032913Sdonn DOUBLE, "movq",
3819700Slinton CHAR, "cvtbl",
3829700Slinton SHORT, "cvtwl",
3839700Slinton UCHAR, "movzbl",
3849700Slinton USHORT, "movzwl",
38517737Sralph 0, ""
3869700Slinton };
3879700Slinton
3889700Slinton char
toreg(type)3899700Slinton *toreg(type)
3909700Slinton TWORD type;
3919700Slinton {
3929700Slinton struct type_move *p;
3939700Slinton
39417737Sralph for ( p=toreg_strs; p->fromtype != 0; p++)
3959700Slinton if (p->fromtype == type) return(p->tostrng);
3969700Slinton
3979700Slinton /* type not found, must be a pointer type */
3989700Slinton return("movl");
3999700Slinton }
4009700Slinton /* tbl */
40132913Sdonn #endif
4029700Slinton
4039700Slinton
main(argc,argv)4049700Slinton main( argc, argv ) char *argv[]; {
4059700Slinton #ifdef BUFSTDERR
4069700Slinton char errbuf[BUFSIZ];
4079700Slinton setbuf(stderr, errbuf);
4089700Slinton #endif
4099700Slinton return(mainp1( argc, argv ));
4109700Slinton }
4119700Slinton
4129700Slinton struct sw heapsw[SWITSZ]; /* heap for switches */
4139700Slinton
genswitch(p,n)4149700Slinton genswitch(p,n) register struct sw *p;{
4159700Slinton /* p points to an array of structures, each consisting
4169700Slinton of a constant value and a label.
4179700Slinton The first is >=0 if there is a default label;
4189700Slinton its value is the label number
4199700Slinton The entries p[1] to p[n] are the nontrivial cases
4209700Slinton */
4219700Slinton register i;
4229700Slinton register CONSZ j, range;
4239700Slinton register dlab, swlab;
4249700Slinton
42532910Sdonn if( nerrors ) return;
4269700Slinton range = p[n].sval-p[1].sval;
4279700Slinton
4289700Slinton if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */
4299700Slinton
4309700Slinton swlab = getlab();
4319700Slinton dlab = p->slab >= 0 ? p->slab : getlab();
4329700Slinton
4339700Slinton /* already in r0 */
4349700Slinton printf(" casel r0,$%ld,$%ld\n", p[1].sval, range);
4359700Slinton printf("L%d:\n", swlab);
4369700Slinton for( i=1,j=p[1].sval; i<=n; j++) {
4379700Slinton printf(" .word L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab),
4389700Slinton swlab);
4399700Slinton }
4409700Slinton
4419700Slinton if( p->slab >= 0 ) branch( dlab );
4429700Slinton else printf("L%d:\n", dlab);
4439700Slinton return;
4449700Slinton
4459700Slinton }
4469700Slinton
4479700Slinton if( n>8 ) { /* heap switch */
4489700Slinton
4499700Slinton heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab();
4509700Slinton makeheap(p, n, 1); /* build heap */
4519700Slinton
4529700Slinton walkheap(1, n); /* produce code */
4539700Slinton
4549700Slinton if( p->slab >= 0 )
4559700Slinton branch( dlab );
4569700Slinton else
4579700Slinton printf("L%d:\n", dlab);
4589700Slinton return;
4599700Slinton }
4609700Slinton
4619700Slinton /* debugging code */
4629700Slinton
4639700Slinton /* out for the moment
4649700Slinton if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) );
4659700Slinton */
4669700Slinton
4679700Slinton /* simple switch code */
4689700Slinton
4699700Slinton for( i=1; i<=n; ++i ){
4709700Slinton /* already in r0 */
4719700Slinton
47224416Smckusick putstr( " cmpl r0,$" );
4739700Slinton printf( CONFMT, p[i].sval );
4749700Slinton printf( "\n jeql L%d\n", p[i].slab );
4759700Slinton }
4769700Slinton
4779700Slinton if( p->slab>=0 ) branch( p->slab );
4789700Slinton }
4799700Slinton
makeheap(p,m,n)4809700Slinton makeheap(p, m, n)
4819700Slinton register struct sw *p;
4829700Slinton {
4839700Slinton register int q;
4849700Slinton
48532912Sdonn q = selectheap(m);
4869700Slinton heapsw[n] = p[q];
4879700Slinton if( q>1 ) makeheap(p, q-1, 2*n);
4889700Slinton if( q<m ) makeheap(p+q, m-q, 2*n+1);
4899700Slinton }
4909700Slinton
selectheap(m)49132912Sdonn selectheap(m) {
4929700Slinton register int l,i,k;
4939700Slinton
4949700Slinton for(i=1; ; i*=2)
4959700Slinton if( (i-1) > m ) break;
4969700Slinton l = ((k = i/2 - 1) + 1)/2;
4979700Slinton return( l + (m-k < l ? m-k : l));
4989700Slinton }
4999700Slinton
walkheap(start,limit)5009700Slinton walkheap(start, limit)
5019700Slinton {
5029700Slinton int label;
5039700Slinton
5049700Slinton
5059700Slinton if( start > limit ) return;
5069700Slinton printf(" cmpl r0,$%d\n", heapsw[start].sval);
5079700Slinton printf(" jeql L%d\n", heapsw[start].slab);
5089700Slinton if( (2*start) > limit ) {
5099700Slinton printf(" jbr L%d\n", heapsw[0].slab);
5109700Slinton return;
5119700Slinton }
5129700Slinton if( (2*start+1) <= limit ) {
5139700Slinton label = getlab();
5149700Slinton printf(" jgtr L%d\n", label);
5159700Slinton } else
5169700Slinton printf(" jgtr L%d\n", heapsw[0].slab);
5179700Slinton walkheap( 2*start, limit);
5189700Slinton if( (2*start+1) <= limit ) {
5199700Slinton printf("L%d:\n", label);
5209700Slinton walkheap( 2*start+1, limit);
5219700Slinton }
5229700Slinton }
523