+# include "mfile1"
+#include <a.out.h>
+
+int proflg = 0; /* are we generating profiling code? */
+int strftn = 0; /* is the current function one which returns a value */
+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 ){
+ printf( " ret\n" );
+ }
+ else printf( " jbr L%d\n", n );
+ }
+
+int lastloc = { -1 };
+
+short log2tab[] = {0, 0, 1, 2, 2, 3, 3, 3, 3};
+#define LOG2SZ 9
+
+defalign(n) {
+ /* cause the alignment to become a multiple of n */
+ n /= SZCHAR;
+ if( lastloc != PROG && n > 1 ) printf( " .align %d\n", n >= 0 && n < LOG2SZ ? log2tab[n] : 0 );
+ }
+
+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" );
+ psline();
+ break;
+
+ case DATA:
+ case ADATA:
+ printf( " .data\n" );
+ break;
+
+ case STRNG:
+ printf( " .data 1\n" );
+ break;
+
+ case ISTRNG:
+ printf( " .data 2\n" );
+ 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 );
+ }
+
+
+int ent_mask[] = {
+ 0,0,0,0,0, 0xfc0, 0xf80, 0xf00, 0xe00, 0xc00, 0x800, 0};
+
+int reg_use = 11;
+
+efcode(){
+ /* code for the end of a function */
+
+ 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 = &stab[curftn];
+ t = p->stype;
+ t = DECREF(t);
+
+ deflab( retlab );
+
+ i = getlab(); /* label for return area */
+ printf(" .data\n" );
+ printf(" .align 2\n" );
+ printf("L%d: .space %d\n", i, tsize(t, p->dimoff, p->sizoff)/SZCHAR );
+ printf(" .text\n" );
+ psline();
+ printf(" movab L%d,r1\n", i);
+
+ reached = 1;
+ l = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
+ l->rval = 1; /* R1 */
+ l->lval = 0; /* no offset */
+ r = block( REG, NIL, NIL, PTR|t, p->dimoff, p->sizoff );
+ r->rval = 0; /* R0 */
+ r->lval = 0;
+ l = buildtree( UNARY MUL, l, NIL );
+ r = buildtree( UNARY MUL, r, NIL );
+ l = buildtree( ASSIGN, l, r );
+ l->op = FREE;
+ ecomp( l->left );
+ printf( " movab L%d,r0\n", i );
+ /* turn off strftn flag, so return sequence will be generated */
+ strftn = 0;
+ }
+ branch( retlab );
+ printf( " .set .R%d,0x%x\n", ftnno, ent_mask[reg_use] );
+ reg_use = 11;
+ p2bend();
+ fdefflag = 0;
+ }
+
+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 = &stab[curftn];
+ printf( " .align 1\n");
+ defnam( p );
+ temp = p->stype;
+ temp = DECREF(temp);
+ strftn = (temp==STRTY) || (temp==UNIONTY);
+
+ retlab = getlab();
+
+ /* routine prolog */
+
+ printf( " .word .R%d\n", ftnno);
+ if (gdebug) {
+ pstab(NULLNAME, N_SLINE);
+ printf("0,%d,LL%d\n", lineno, labelno);
+ printf("LL%d:\n", labelno++);
+ }
+ printf( " subl2 $.F%d,sp\n", ftnno);
+ if( proflg ) { /* profile code */
+ i = getlab();
+ 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");
+ psline();
+ }
+
+ off = ARGINIT;
+
+ for( i=0; i<n; ++i ){
+ p = &stab[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 );
+/*tbl*/ printf( " %s %d(ap),r%d\n", toreg(p->stype), p->offset/SZCHAR, temp );
+ p->offset = temp; /* remember register number */
+ p->sclass = REGISTER; /* remember that it is a register */
+ }
+ 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 );
+ reg_use = (reg_use > regvar ? regvar : reg_use);
+ }
+
+ejobcode( flag ){
+ /* called just before final exit */
+ /* flag is 1 if errors, 0 if none */
+ }
+
+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 ){
+ /* put byte i+1 in a string */
+
+ 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( "," );
+ printf( "0x%x", t );
+ if( i == 07 ) printf( "\n" );
+ }
+ }
+
+zecode( n ){
+ /* n integer words of zeros */
+ OFFSZ temp;
+ if( n <= 0 ) return;
+ printf( " .space %d\n", (SZINT/SZCHAR)*n );
+ 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[] =
+ {
+ CHAR, "cvtbl",
+ SHORT, "cvtwl",
+ INT, "movl",
+ LONG, "movl",
+ FLOAT, "movf",
+ DOUBLE, "movd",
+ UCHAR, "movzbl",
+ USHORT, "movzwl",
+ UNSIGNED, "movl",
+ ULONG, "movl",
+ -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 */
+ return("movl");
+}
+/* tbl */
+
+
+main( argc, argv ) char *argv[]; {
+ return(mainp1( argc, argv ));
+ }
+
+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 */
+
+ swlab = getlab();
+ dlab = p->slab >= 0 ? p->slab : 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);
+ return;
+
+ }
+
+ if( n>8 ) { /* 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 )
+ branch( dlab );
+ else
+ printf("L%d:\n", dlab);
+ return;
+ }
+
+ /* 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 */
+
+ printf( " cmpl r0,$" );
+ printf( CONFMT, p[i].sval );
+ printf( "\n jeql L%d\n", p[i].slab );
+ }
+
+ if( p->slab>=0 ) branch( 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;
+ printf(" cmpl r0,$%d\n", heapsw[start].sval);
+ printf(" jeql L%d\n", heapsw[start].slab);
+ if( (2*start) > limit ) {
+ printf(" jbr L%d\n", heapsw[0].slab);
+ return;
+ }
+ if( (2*start+1) <= limit ) {
+ label = getlab();
+ printf(" jgtr L%d\n", label);
+ } else
+ printf(" jgtr L%d\n", heapsw[0].slab);
+ walkheap( 2*start, limit);
+ if( (2*start+1) <= limit ) {
+ printf("L%d:\n", label);
+ walkheap( 2*start+1, limit);
+ }
+}