# include <stdio.h> extern int Pflag, bbcnt; # include "mfile1.h" int minrvar = 11; int wloop_level = LL_BOT; int floop_level = LL_BOT; int maxboff; int maxtemp; codgen(p) NODE *p; { extern int bothdebug; if(bothdebug) tfree(p); } /* so pcc2 stuff doesn't get loaded */ #if !defined(COMBINED) main( argc, argv ) char *argv[]; { int r; char errbuf[BUFSIZ]; setbuf(stderr, errbuf); r = mainp1( argc, argv ); flushx(); return( r ); } beg_file() { /* called as the very first thing by the parser to do machine * dependent stuff */ regvar = minrvar; dbfile(NULL); } #else /* defined(COMBINED) */ locctr(i) int i; { static int last = PROG; if (i == last) return; else if (i == PROG) printx(" .text\n"); else if (i == DATA) printx(" .data\n"); else cerror("funny location counter"); last = i; } #endif NODE * treecpy(p) /* first pass version of tcopy() */ register NODE *p; { /* make a fresh copy of p */ register NODE *q; q = talloc(); *q = *p; switch (optype(q->in.op)) { case BITYPE: q->in.right = treecpy(p->in.right); case UTYPE: q->in.left = treecpy(p->in.left); } return (q); } #if !defined(COMBINED) NODE * clocal(p) NODE *p; { register NODE *l,*ll,*r; if( p->in.op == STAR ) { /* if it looks like index mode put the */ /* offset on the right */ l = p->in.left; if( l->in.op == PLUS ) { ll = l->in.left; if( ll->in.op != MUL && ll->in.op != UNARY AND ) { if( (l->in.right)->in.op == MUL ) { r = l->in.right; l->in.right = l->in.left; l->in.left = r; } } } } #ifdef DASSOVCOL if (!asgbinop(p->in.op) && p->in.op != ASSIGN) return (p); r = p->in.right; if (optype(r->in.op) == LTYPE) return (p); l = r->in.left; if (r->in.op == QUEST || (r->in.op == CONV && l->in.op == QUEST) || (r->in.op == CONV && l->in.op == CONV && l->in.left->in.op == QUEST)) /* distribute assigns over colons */ { register NODE *pwork; NODE *pcpy = treecpy(p), *pnew; #ifndef NODBG extern int xdebug, eprint(); if (xdebug) { puts("Entering [op]=?: distribution"); eprint(p); } #endif pnew = pcpy->in.right; while (pnew->in.op != QUEST) pnew = pnew->in.left; /* * pnew is top of new tree */ if ((pwork = p)->in.right->in.op == QUEST) { tfree(pwork->in.right); pwork->in.right = pnew->in.right->in.left; pnew->in.right->in.left = pwork; /* at this point, 1/2 distributed. Tree looks like: * ASSIGN|ASGOP * LVAL QUEST * EXPR1 COLON * ASSIGN|ASGOP EXPR3 * LVAL EXPR2 * pnew "holds" new tree from QUEST node */ } else { NODE *pholdtop = pwork; pwork = pwork->in.right; while (pwork->in.left->in.op != QUEST) pwork = pwork->in.left; tfree(pwork->in.left); pwork->in.left = pnew->in.right->in.left; pnew->in.right->in.left = pholdtop; /* at this point, 1/2 distributed. Tree looks like: * ASSIGN|ASGOP * LVAL ANY # OF CONVs * QUEST * EXPR1 COLON * ASSIGN|ASGOP EXPR3 * LVAL ANY # OF CONVs * EXPR2 * pnew "holds" new tree from QUEST node */ } if ((pwork = pcpy)->in.right->in.op == QUEST) { pwork->in.right = pnew->in.right->in.right; pnew->in.right->in.right = pwork; /* * done with the easy case */ } else { NODE *pholdtop = pwork; pwork = pwork->in.right; while (pwork->in.left->in.op != QUEST) pwork = pwork->in.left; pwork->in.left = pnew->in.right->in.right; pnew->in.right->in.right = pholdtop; /* * done with the CONVs case */ } p = pnew; #ifndef NODBG if (xdebug) { puts("Leaving [op]=?: distribution"); eprint(p); } #endif } #endif return(p); } #endif cisreg( t ) TWORD t; { /* is an automatic variable of type t OK for a register variable */ if( t==INT || t==UNSIGNED || ISPTR(t) || t==CHAR || t==UCHAR || t==SHORT || t==USHORT || t==FLOAT /* (sigh) || t==STRTY || t == UNIONTY*/ ) { if( regvar >= 6 ) { nextrvar = regvar--; if( regvar < minrvar ) minrvar = regvar; return(1); } } return(0); } opbigsz( op ) { /* the size below which we do not shrink ops */ switch( op ) { default: return( SZINT ); case PLUS: case MINUS: case OR: case AND: case ER: case COMPL: case UNARY MINUS: return( SZCHAR ); } } branch(n) /* branch to label n or return */ int n; { if (!reached) /* return <expr>; } comes here 2x */ return; genubr(n); } #if !defined(COMBINED) /* direct switch beginning */ static int tablelabel; struct sw heapsw[SWITSZ]; /* heap for switches */ /* test for whether to do a direct switch */ # ifndef DSWTEST # define DSWTEST(r,n) (r>0 && r<=(3*n) && n>=4) # endif /* test for whether to do a heap switch */ # ifndef HEAPTEST # define HEAPTEST( n ) (n>8) # endif 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( DSWTEST( range, n ) ) { /* implement a direct switch */ swlab = getlab(); dlab = ((p->slab >= 0) ? p->slab : getlab()); dswbegin( n, p[1].sval, range, swlab, dlab ); for( i=1,j=p[1].sval; i<=n; j++) { if( j == p[i].sval ) { dswcase( p[i].slab ); j = p[i++].sval; } else { dswcase( dlab ); } } /* in case dswbegin changed location counters... */ locctr( PROG ); if( p->slab >= 0 ) genubr( dlab ); else deflab( dlab ); return; } if( HEAPTEST(n) ) { /* heap switch */ 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 ) genubr( dlab ); else deflab( dlab ); return; } /* simple switch code */ for( i=1; i<=n; ++i ) sswtest( p[i].sval, p[i].slab ); if( p->slab>=0 ) genubr( p->slab ); } 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; sswtest( heapsw[start].sval, heapsw[start].slab ); if( (2*start) > limit ) { genubr( heapsw[0].slab ); return; } if( (2*start+1) <= limit ) { label = getlab(); hswelse( label ); } else hswelse( heapsw[0].slab ); walkheap( 2*start, limit); if( (2*start+1) <= limit ) { deflab( label ); walkheap( 2*start+1, limit); } } dswbegin( numb, first, range, labl, dlab ) CONSZ first, range; int numb, labl, dlab; { printx(" casel r0,$%ld,$%ld\n", first, range ); printx("L%d:\n", labl ); tablelabel = labl; } dswcase( l ) int l; { printx(" .word L%d-L%d\n", l, tablelabel ); } sswtest( val, lab ) CONSZ val; int lab; { printx( " cmpl r0,$%ld\n jeql L%d\n", val, lab ); } hswelse( lab ) int lab; { printx(" jgtr L%d\n", lab ); } #endif /* COMBINED */ OFFSZ inoff; /* size of offset in structure */ static inwd; /* current bit offset in word */ static long word; /* word being built from fields */ zecode( n ) int n; { /* n integer words of zeros */ if (n <= 0) return; printx( " .space %d\n", 4*n ); inoff += n*SZINT; } vfdzero( n ){ /* define n bits of zeros in a vfd */ /* this could be done more cleverly: the following is safe */ sz_incode( (CONSZ)0, n ); } incode (p, sz) NODE *p; { sz_incode(p->tn.lval, sz); } sz_incode( val, sz ) CONSZ val; { /* generate initialization code for assigning a constant c to a field of width sz */ /* we assume that the proper alignment has been obtained */ /* inoff is updated to have the proper final value */ if((sz+inwd) > SZLONG) cerror("incode: field > long"); /* this code will have to be replaced if the size of a long on /* the target machine differs from that on the host machine */ # ifdef RTOLBYTES word |= ((unsigned)(val<<(SZLONG-sz))) >> (SZLONG-sz-inwd); # else word |= ((unsigned)(val<<(SZLONG-sz))) >> inwd; # endif inwd += sz; inoff += sz; /* if initialization can be carried out using shorts, do it */ # if (SZSHORT >= ALINIT) if(inwd == SZSHORT ) { # ifdef RTOLBYTES genshort( (short) word ); # else genshort( (short) (word>>(SZLONG-SZSHORT)) ); # endif word = inwd = 0; } else # endif if( inwd == SZLONG ) { genlong( word ); word = inwd = 0; } } fincode( d, sz ) double d; int sz; { /* output code to initialize space of size sz to the value d */ /* the proper alignment has been obtained */ /* on the target machine, write it out in hex! */ #if defined(vax) union { float f; double d; int i[2] } cheat; if (sz == SZDOUBLE) { cheat.d = d; printx("\t.long\t0x%x,0x%x\t# %.20e\n", cheat.i[0], cheat.i[1], cheat.d); } else { cheat.f = d; printx("\t.long\t0x%x\t# %.20e\n", cheat.i[0], cheat.f); } #else printx(" %s 0%c%.20e\n", sz == SZDOUBLE ? ".double" : ".float", sz == SZDOUBLE ? 'd' : 'f', d); #endif inoff += sz; } int ftlab1, ftlab2; int proflag; int ent_mask[] = { 0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0}; #if defined(COMBINED) efcode(type) int type; #else efcode() #endif { /* code for the end of a function */ long spoff; /* offset from stack pointer */ #if defined(COMBINED) deflab(retlab); repl_retval(type); printx("\tret\n"); #else genret( strftn, strftn, retlab ); #endif printx( " .set L.R%d,0x%x\n", ftnno, ent_mask[minrvar] ); #ifdef FORT spoff = maxboff; if( spoff >= BITOOR(AUTOINIT) ) spoff -= BITOOR(AUTOINIT); spoff += maxtemp; spoff /= SZCHAR; printx( " .set L.F%d,%ld\n", ftnno, spoff / SZCHAR ); #else spoff = maxboff; if( spoff >= BITOOR(AUTOINIT) ) spoff -= BITOOR(AUTOINIT); spoff += maxtemp; spoff /= SZCHAR; printx("\t.set\tL.SO%d,0x%x\n", ftnno, spoff); #endif regvar = minrvar = 11; #ifdef GDEBUG dbfunend(getlab()); #endif } bfcode( a, n ) int a[], n; { /* code for the beginning of a function; a is an array of indices in stab for the arguments; n is the number */ register i; /* routine prolog */ printx( " .word L.R%d\n", ftnno); printx("\tsubl2\t$L.SO%d,sp\n", ftnno); retlab = getlab(); if( proflag ) { /* profile code */ i = getlab(); printx(" movab L%d,r0\n", i); printx(" jsb mcount\n"); printx(" .data\n"); printx(" .align 2\n"); printx("L%d: .long 0\n", i); printx(" .text\n"); } if(Pflag) { printx("\t.data\n\t.comm _proFptr,4\n\t.text\n"); printx("\ttstl locprof+4\n\tbneq L%da\n", ++bbcnt); printx("\tmovl _proFptr,locprof+4\n\tmoval locprof,_proFptr\n"); printx("#entry %d\n", bbcnt); printf("L%da:\tincl locprof+%d\n", bbcnt, 4*(bbcnt+3)); } #ifdef GDEBUG dbfunbeg(&stab[curftn]); for (i = 0; i < n; ++i) { extern TWORD argty[]; extern int argsoff[]; struct symtab q; q = stab[a[i]]; q.sclass = PARAM; q.stype = argty[i]; q.offset = argsoff[i]; dbfunarg(&q); } #endif } defnam( psym ) register struct symtab *psym; { /* define the current location as the name psym->sname * first give the debugging info for external definitions */ /*if( psym->slevel == 0 ) /* make sure it's external */ /* ISFTN(psym->stype) ? prdef(psym,0) : prdef(psym,dsflag); */ if (psym->sclass == EXTDEF) printx( " .globl %s\n", exname(psym->sname) ); printx("%s:\n", exname(psym->sname)); } commdec(id) /* generate a .comm from stab index id */ int id; { #if !defined(COMBINED) register struct symtab *psym; OFFSZ n; psym = &stab[id]; psym->sflags |= SBSS; n = tsize(psym->stype, psym->dimoff, psym->sizoff) / SZCHAR; if (psym->sclass == STATIC) if (psym->slevel) printx(" .lcomm L%d,%ld\n", psym->offset, n); else printx(" .lcomm %s,%ld\n", exname(psym->sname), n); else if (psym->sclass == EXTERN) printx(" .comm %s,%ld\n", exname(psym->sname), n); else cerror("Non-static/external in common"); #endif } myfcon(p) NODE *p; { union { double d; int i[2]; } u; u.d = p->fpn.dval; if (u.i[1] == 0) /* no significant lo bits, shorten */ { p->fn.type = FLOAT; p->fn.csiz = FLOAT; } }