117737Sralph #ifndef lint 2*32913Sdonn static char *sccsid ="@(#)code.c 1.9 (Berkeley) 12/11/87"; 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 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 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 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 8132910Sdonn #ifndef deflab 829700Slinton deflab( n ){ 839700Slinton /* output something to define the current position as label n */ 849700Slinton printf( "L%d:\n", n ); 859700Slinton } 86*32913Sdonn #endif 879700Slinton 889700Slinton int crslab = 10; 899700Slinton 909700Slinton getlab(){ 919700Slinton /* return a number usable for a label */ 929700Slinton return( ++crslab ); 939700Slinton } 949700Slinton 959700Slinton 969700Slinton int ent_mask[] = { 979700Slinton 0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0}; 989700Slinton 999700Slinton int reg_use = 11; 1009700Slinton 1019700Slinton efcode(){ 1029700Slinton /* code for the end of a function */ 1039700Slinton 1049700Slinton if( strftn ){ /* copy output (in R2) to caller */ 1059700Slinton register NODE *l, *r; 1069700Slinton register struct symtab *p; 1079700Slinton register TWORD t; 1089700Slinton int i; 1099700Slinton 1109700Slinton p = &stab[curftn]; 1119700Slinton t = p->stype; 1129700Slinton t = DECREF(t); 1139700Slinton 1149700Slinton deflab( retlab ); 1159700Slinton 1169700Slinton i = getlab(); /* label for return area */ 1179700Slinton #ifndef LCOMM 11824416Smckusick putstr(" .data\n" ); 11924416Smckusick putstr(" .align 2\n" ); 1209700Slinton printf("L%d: .space %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR ); 12124416Smckusick putstr(" .text\n" ); 1229700Slinton #else 1239700Slinton { int sz = tsize(t, p->dimoff, p->sizoff) / SZCHAR; 124*32913Sdonn if (sz % (SZINT/SZCHAR)) 125*32913Sdonn sz += (SZINT/SZCHAR) - (sz % (SZINT/SZCHAR)); 1269700Slinton printf(" .lcomm L%d,%d\n", i, sz); 1279700Slinton } 1289700Slinton #endif 1299700Slinton psline(); 1309700Slinton printf(" movab L%d,r1\n", i); 1319700Slinton 1329700Slinton reached = 1; 1339700Slinton l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); 1349700Slinton l->tn.rval = 1; /* R1 */ 1359700Slinton l->tn.lval = 0; /* no offset */ 1369700Slinton r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff ); 1379700Slinton r->tn.rval = 0; /* R0 */ 1389700Slinton r->tn.lval = 0; 1399700Slinton l = buildtree( UNARY MUL, l, NIL ); 1409700Slinton r = buildtree( UNARY MUL, r, NIL ); 1419700Slinton l = buildtree( ASSIGN, l, r ); 1429700Slinton l->in.op = FREE; 1439700Slinton ecomp( l->in.left ); 1449700Slinton printf( " movab L%d,r0\n", i ); 1459700Slinton /* turn off strftn flag, so return sequence will be generated */ 1469700Slinton strftn = 0; 1479700Slinton } 1489700Slinton branch( retlab ); 1499700Slinton #ifndef VMS 1509700Slinton printf( " .set L%d,0x%x\n", ftnno, ent_mask[reg_use] ); 1519700Slinton #else 1529700Slinton printf( " .set L%d,%d # Hex = 0x%x\n", ftnno, 0x3c| ent_mask[reg_use], ent_mask[reg_use] ); 1539700Slinton /* KLS kludge, under VMS if you use regs 2-5, you must save them. */ 1549700Slinton #endif 1559700Slinton reg_use = 11; 1569700Slinton p2bend(); 1579700Slinton fdefflag = 0; 1589700Slinton } 1599700Slinton 1609700Slinton int ftlab1, ftlab2; 1619700Slinton 1629700Slinton bfcode( a, n ) int a[]; { 1639700Slinton /* code for the beginning of a function; a is an array of 1649700Slinton indices in stab for the arguments; n is the number */ 1659700Slinton register i; 1669700Slinton register temp; 1679700Slinton register struct symtab *p; 1689700Slinton int off; 169*32913Sdonn #ifdef TRUST_REG_CHAR_AND_REG_SHORT 1709700Slinton char *toreg(); 171*32913Sdonn #endif 1729700Slinton 17332910Sdonn if( nerrors ) return; 17432912Sdonn (void) locctr( PROG ); 1759700Slinton p = &stab[curftn]; 17624416Smckusick putstr( " .align 1\n"); 1779700Slinton defnam( p ); 1789700Slinton temp = p->stype; 1799700Slinton temp = DECREF(temp); 1809700Slinton strftn = (temp==STRTY) || (temp==UNIONTY); 1819700Slinton 1829700Slinton retlab = getlab(); 1839700Slinton 1849700Slinton /* routine prolog */ 1859700Slinton 1869700Slinton printf( " .word L%d\n", ftnno); 1879700Slinton ftlab1 = getlab(); 1889700Slinton ftlab2 = getlab(); 1899700Slinton printf( " jbr L%d\n", ftlab1); 1909700Slinton printf( "L%d:\n", ftlab2); 1919700Slinton if( proflg ) { /* profile code */ 1929700Slinton i = getlab(); 1939700Slinton printf(" movab L%d,r0\n", i); 19424416Smckusick putstr(" jsb mcount\n"); 19524416Smckusick putstr(" .data\n"); 19624416Smckusick putstr(" .align 2\n"); 1979700Slinton printf("L%d: .long 0\n", i); 19824416Smckusick putstr(" .text\n"); 1999700Slinton psline(); 2009700Slinton } 2019700Slinton 2029700Slinton off = ARGINIT; 2039700Slinton 2049700Slinton for( i=0; i<n; ++i ){ 2059700Slinton p = &stab[a[i]]; 2069700Slinton if( p->sclass == REGISTER ){ 2079700Slinton temp = p->offset; /* save register number */ 2089700Slinton p->sclass = PARAM; /* forget that it is a register */ 2099700Slinton p->offset = NOOFFSET; 21032912Sdonn (void) oalloc( p, &off ); 211*32913Sdonn #ifdef TRUST_REG_CHAR_AND_REG_SHORT /* and reg double */ 2129700Slinton /*tbl*/ printf( " %s %d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp ); 213*32913Sdonn #else 214*32913Sdonn /*tbl*/ printf( " movl %d(ap),r%d\n", p->offset/SZCHAR, temp ); 215*32913Sdonn #endif 2169700Slinton p->offset = temp; /* remember register number */ 2179700Slinton p->sclass = REGISTER; /* remember that it is a register */ 2189700Slinton } 2199700Slinton else if( p->stype == STRTY || p->stype == UNIONTY ) { 2209700Slinton p->offset = NOOFFSET; 2219700Slinton if( oalloc( p, &off ) ) cerror( "bad argument" ); 2229700Slinton SETOFF( off, ALSTACK ); 2239700Slinton } 2249700Slinton else { 2259700Slinton if( oalloc( p, &off ) ) cerror( "bad argument" ); 2269700Slinton } 2279700Slinton 2289700Slinton } 22932910Sdonn if (gdebug && !nerrors) { 23015896Ssam #ifdef STABDOT 23115896Ssam pstabdot(N_SLINE, lineno); 23215896Ssam #else 23315896Ssam pstab(NULLNAME, N_SLINE); 23415896Ssam printf("0,%d,LL%d\n", lineno, labelno); 23515896Ssam printf("LL%d:\n", labelno++); 23615896Ssam #endif 23715896Ssam } 2389700Slinton fdefflag = 1; 2399700Slinton } 2409700Slinton 2419700Slinton bccode(){ /* called just before the first executable statment */ 2429700Slinton /* by now, the automatics and register variables are allocated */ 2439700Slinton SETOFF( autooff, SZINT ); 2449700Slinton /* set aside store area offset */ 2459700Slinton p2bbeg( autooff, regvar ); 2469700Slinton reg_use = (reg_use > regvar ? regvar : reg_use); 2479700Slinton } 2489700Slinton 24932911Sdonn /*ARGSUSED*/ 2509700Slinton ejobcode( flag ){ 2519700Slinton /* called just before final exit */ 2529700Slinton /* flag is 1 if errors, 0 if none */ 2539700Slinton } 2549700Slinton 25532910Sdonn #ifndef aobeg 2569700Slinton aobeg(){ 2579700Slinton /* called before removing automatics from stab */ 2589700Slinton } 25932910Sdonn #endif aobeg 2609700Slinton 26132910Sdonn #ifndef aocode 26232911Sdonn /*ARGSUSED*/ 2639700Slinton aocode(p) struct symtab *p; { 2649700Slinton /* called when automatic p removed from stab */ 2659700Slinton } 26632910Sdonn #endif aocode 2679700Slinton 26832910Sdonn #ifndef aoend 2699700Slinton aoend(){ 2709700Slinton /* called after removing all automatics from stab */ 2719700Slinton } 27232910Sdonn #endif aoend 2739700Slinton 2749700Slinton defnam( p ) register struct symtab *p; { 2759700Slinton /* define the current location as the name p->sname */ 2769700Slinton 2779700Slinton if( p->sclass == EXTDEF ){ 2789700Slinton printf( " .globl %s\n", exname( p->sname ) ); 2799700Slinton } 2809700Slinton if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset ); 2819700Slinton else printf( "%s:\n", exname( p->sname ) ); 2829700Slinton 2839700Slinton } 2849700Slinton 2859700Slinton bycode( t, i ){ 2869700Slinton #ifdef ASSTRINGS 2879700Slinton static int lastoctal = 0; 2889700Slinton #endif 2899700Slinton 2909700Slinton /* put byte i+1 in a string */ 2919700Slinton 29232910Sdonn if ( nerrors ) return; 2939700Slinton #ifdef ASSTRINGS 2949700Slinton 2959700Slinton i &= 077; 2969700Slinton if ( t < 0 ){ 29724416Smckusick if ( i != 0 ) putstr( "\"\n" ); 2989700Slinton } else { 29924416Smckusick if ( i == 0 ) putstr("\t.ascii\t\""); 3009700Slinton if ( t == '\\' || t == '"'){ 3019700Slinton lastoctal = 0; 3029700Slinton printf("\\%c", t); 3039700Slinton } 3049700Slinton /* 3059700Slinton * We escape the colon in strings so that 3069700Slinton * c2 will, in its infinite wisdom, interpret 3079700Slinton * the characters preceding the colon as a label. 3089700Slinton * If we didn't escape the colon, c2 would 3099700Slinton * throw away any trailing blanks or tabs after 3109700Slinton * the colon, but reconstruct a assembly 3119700Slinton * language semantically correct program. 3129700Slinton * C2 hasn't been taught about strings. 3139700Slinton */ 3149700Slinton else if ( t == ':' || t < 040 || t >= 0177 ){ 3159700Slinton lastoctal++; 3169700Slinton printf("\\%o",t); 3179700Slinton } 3189700Slinton else if ( lastoctal && '0' <= t && t <= '9' ){ 3199700Slinton lastoctal = 0; 3209700Slinton printf("\"\n\t.ascii\t\"%c", t ); 3219700Slinton } 3229700Slinton else 3239700Slinton { 3249700Slinton lastoctal = 0; 3259700Slinton putchar(t); 3269700Slinton } 32724416Smckusick if ( i == 077 ) putstr("\"\n"); 3289700Slinton } 3299700Slinton #else 3309700Slinton 3319700Slinton i &= 07; 3329700Slinton if( t < 0 ){ /* end of the string */ 33324416Smckusick if( i != 0 ) putchar( '\n' ); 3349700Slinton } 3359700Slinton 3369700Slinton else { /* stash byte t into string */ 33724416Smckusick if( i == 0 ) putstr( " .byte " ); 33824416Smckusick else putchar( ',' ); 3399700Slinton printf( "0x%x", t ); 34024416Smckusick if( i == 07 ) putchar( '\n' ); 3419700Slinton } 3429700Slinton #endif 3439700Slinton } 3449700Slinton 3459700Slinton zecode( n ){ 3469700Slinton /* n integer words of zeros */ 3479700Slinton OFFSZ temp; 3489700Slinton if( n <= 0 ) return; 3499700Slinton printf( " .space %d\n", (SZINT/SZCHAR)*n ); 3509700Slinton temp = n; 3519700Slinton inoff += temp*SZINT; 3529700Slinton } 3539700Slinton 35432911Sdonn /*ARGSUSED*/ 3559700Slinton fldal( t ) unsigned t; { /* return the alignment of field of type t */ 3569700Slinton uerror( "illegal field type" ); 3579700Slinton return( ALINT ); 3589700Slinton } 3599700Slinton 36032911Sdonn /*ARGSUSED*/ 3619700Slinton fldty( p ) struct symtab *p; { /* fix up type of field p */ 3629700Slinton ; 3639700Slinton } 3649700Slinton 36532911Sdonn /*ARGSUSED*/ 3669700Slinton where(c){ /* print location of error */ 3679700Slinton /* c is either 'u', 'c', or 'w' */ 3689700Slinton /* GCOS version */ 3699700Slinton fprintf( stderr, "%s, line %d: ", ftitle, lineno ); 3709700Slinton } 3719700Slinton 3729700Slinton 373*32913Sdonn #ifdef TRUST_REG_CHAR_AND_REG_SHORT 3749700Slinton /* tbl - toreg() returns a pointer to a char string 3759700Slinton which is the correct "register move" for the passed type 3769700Slinton */ 3779700Slinton struct type_move {TWORD fromtype; char tostrng[8];} toreg_strs[] = 3789700Slinton { 379*32913Sdonn INT, "movl", 380*32913Sdonn UNSIGNED, "movl", 381*32913Sdonn DOUBLE, "movq", 3829700Slinton CHAR, "cvtbl", 3839700Slinton SHORT, "cvtwl", 3849700Slinton UCHAR, "movzbl", 3859700Slinton USHORT, "movzwl", 38617737Sralph 0, "" 3879700Slinton }; 3889700Slinton 3899700Slinton char 3909700Slinton *toreg(type) 3919700Slinton TWORD type; 3929700Slinton { 3939700Slinton struct type_move *p; 3949700Slinton 39517737Sralph for ( p=toreg_strs; p->fromtype != 0; p++) 3969700Slinton if (p->fromtype == type) return(p->tostrng); 3979700Slinton 3989700Slinton /* type not found, must be a pointer type */ 3999700Slinton return("movl"); 4009700Slinton } 4019700Slinton /* tbl */ 402*32913Sdonn #endif 4039700Slinton 4049700Slinton 4059700Slinton main( argc, argv ) char *argv[]; { 4069700Slinton #ifdef BUFSTDERR 4079700Slinton char errbuf[BUFSIZ]; 4089700Slinton setbuf(stderr, errbuf); 4099700Slinton #endif 4109700Slinton return(mainp1( argc, argv )); 4119700Slinton } 4129700Slinton 4139700Slinton struct sw heapsw[SWITSZ]; /* heap for switches */ 4149700Slinton 4159700Slinton genswitch(p,n) register struct sw *p;{ 4169700Slinton /* p points to an array of structures, each consisting 4179700Slinton of a constant value and a label. 4189700Slinton The first is >=0 if there is a default label; 4199700Slinton its value is the label number 4209700Slinton The entries p[1] to p[n] are the nontrivial cases 4219700Slinton */ 4229700Slinton register i; 4239700Slinton register CONSZ j, range; 4249700Slinton register dlab, swlab; 4259700Slinton 42632910Sdonn if( nerrors ) return; 4279700Slinton range = p[n].sval-p[1].sval; 4289700Slinton 4299700Slinton if( range>0 && range <= 3*n && n>=4 ){ /* implement a direct switch */ 4309700Slinton 4319700Slinton swlab = getlab(); 4329700Slinton dlab = p->slab >= 0 ? p->slab : getlab(); 4339700Slinton 4349700Slinton /* already in r0 */ 4359700Slinton printf(" casel r0,$%ld,$%ld\n", p[1].sval, range); 4369700Slinton printf("L%d:\n", swlab); 4379700Slinton for( i=1,j=p[1].sval; i<=n; j++) { 4389700Slinton printf(" .word L%d-L%d\n", (j == p[i].sval ? ((j=p[i++].sval), p[i-1].slab) : dlab), 4399700Slinton swlab); 4409700Slinton } 4419700Slinton 4429700Slinton if( p->slab >= 0 ) branch( dlab ); 4439700Slinton else printf("L%d:\n", dlab); 4449700Slinton return; 4459700Slinton 4469700Slinton } 4479700Slinton 4489700Slinton if( n>8 ) { /* heap switch */ 4499700Slinton 4509700Slinton heapsw[0].slab = dlab = p->slab >= 0 ? p->slab : getlab(); 4519700Slinton makeheap(p, n, 1); /* build heap */ 4529700Slinton 4539700Slinton walkheap(1, n); /* produce code */ 4549700Slinton 4559700Slinton if( p->slab >= 0 ) 4569700Slinton branch( dlab ); 4579700Slinton else 4589700Slinton printf("L%d:\n", dlab); 4599700Slinton return; 4609700Slinton } 4619700Slinton 4629700Slinton /* debugging code */ 4639700Slinton 4649700Slinton /* out for the moment 4659700Slinton if( n >= 4 ) werror( "inefficient switch: %d, %d", n, (int) (range/n) ); 4669700Slinton */ 4679700Slinton 4689700Slinton /* simple switch code */ 4699700Slinton 4709700Slinton for( i=1; i<=n; ++i ){ 4719700Slinton /* already in r0 */ 4729700Slinton 47324416Smckusick putstr( " cmpl r0,$" ); 4749700Slinton printf( CONFMT, p[i].sval ); 4759700Slinton printf( "\n jeql L%d\n", p[i].slab ); 4769700Slinton } 4779700Slinton 4789700Slinton if( p->slab>=0 ) branch( p->slab ); 4799700Slinton } 4809700Slinton 4819700Slinton makeheap(p, m, n) 4829700Slinton register struct sw *p; 4839700Slinton { 4849700Slinton register int q; 4859700Slinton 48632912Sdonn q = selectheap(m); 4879700Slinton heapsw[n] = p[q]; 4889700Slinton if( q>1 ) makeheap(p, q-1, 2*n); 4899700Slinton if( q<m ) makeheap(p+q, m-q, 2*n+1); 4909700Slinton } 4919700Slinton 49232912Sdonn selectheap(m) { 4939700Slinton register int l,i,k; 4949700Slinton 4959700Slinton for(i=1; ; i*=2) 4969700Slinton if( (i-1) > m ) break; 4979700Slinton l = ((k = i/2 - 1) + 1)/2; 4989700Slinton return( l + (m-k < l ? m-k : l)); 4999700Slinton } 5009700Slinton 5019700Slinton walkheap(start, limit) 5029700Slinton { 5039700Slinton int label; 5049700Slinton 5059700Slinton 5069700Slinton if( start > limit ) return; 5079700Slinton printf(" cmpl r0,$%d\n", heapsw[start].sval); 5089700Slinton printf(" jeql L%d\n", heapsw[start].slab); 5099700Slinton if( (2*start) > limit ) { 5109700Slinton printf(" jbr L%d\n", heapsw[0].slab); 5119700Slinton return; 5129700Slinton } 5139700Slinton if( (2*start+1) <= limit ) { 5149700Slinton label = getlab(); 5159700Slinton printf(" jgtr L%d\n", label); 5169700Slinton } else 5179700Slinton printf(" jgtr L%d\n", heapsw[0].slab); 5189700Slinton walkheap( 2*start, limit); 5199700Slinton if( (2*start+1) <= limit ) { 5209700Slinton printf("L%d:\n", label); 5219700Slinton walkheap( 2*start+1, limit); 5229700Slinton } 5239700Slinton } 524