/* $Header:code.c 12.0$ */
/* $ACIS:code.c 12.0$ */
/* $Source: /ibm/acis/usr/src/lib/pcc_ca/RCS/code.c,v $ */
#ifndef lint
static char rcsid[] = "$Header:code.c 12.0$";
#endif
#ifdef unix
# include "mfile1.h"
# include <a.out.h>
# include <stab.h>
# include <ctype.h>
#else
# include "doption h *"  /* circumvention for -D problem with preprocessor */
# include "mfile1 h *"
#ifdef FORUNIX
# include "ctype h t"
# include "aout h t"
# include "stab h t"
#else
# include "aout h *"
# include "stab h *"
#endif
#endif
 
static int anyprocs=0;
int proflg = 0;  /* are we generating profiling code? */
int aaflg  = 0;  /* (ef) 1/4/86 -- alloca enabled? */
int strftn = 0;  /* does the current function returns an aggregate? */
int dblftn = 0;  /* does the current function returns a double? */
int gdebug;
int fdefflag;  /* are we within a function definition ? */
char NULLNAME[8];
int labelno;
int sdebug;  /* added 12/30/83 by JEC for structure operations */
extern int optize;  /* added 6/84 by JEC for ibm032 optimizer */
 
branch( n ) register n;{  /* output a branch to label n */
/* if( n == retlab && !strftn ){ */
/* exception is an ordinary function branching to retlab: then, return */
/*	printf(" | no branch\n");
/*      }
/* else printf( " b L%d | immediate branch\n", n);
*/
  
   printf( " b L%d # branch\n", n);
  
   }
 
int lastloc = { -1 };
 
/* defalign rewritten 11/16/83 by JEC */
defalign(n) register n; {  /* cause the alignment to become a multiple of n */
   if( n==8 );
   else if( n==16 ) printf(" .align 1\n");
   else if( n==32 ) printf(" .align 2\n");
   else {
      printf("defalign( %d )\n", n);
      cerror("trouble in defalign");
      }
   }
 
locctr( l ) register l; {
   register temp;
   /* l is PROG, ADATA, DATA, STRNG, ISTRNG, or STAB (BSS added by JEC) */
 
   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 STAB:
      printf( " .stab\n" );
      break;
 
   case BSS:
      printf( " .bss\n" );
      cerror( "No bss segment supported");
      break;
 
   case STRNG: /* a string inside a function */
      printf( " .data 1\n");
      break;

   case ISTRNG: /* a string outside a function */
      printf( " .data 2\n");
      break;

   default:
      printf( "locctr( %d )\n", l );
      cerror( "illegal location counter" );
      }
 
   return( temp );
   }
 
deflab( n ) register n; {
   /* output something to define the current position as label n */
   printf( "L%d:\n", n );
   }
 
		/* added 10/20/83 by JEC for string literals */
defequ( n ) register n; {  
   /* output something to define the label n as an equated symbol */
   /* printf( "L%d = ", n ); */
   printf( "L%d: ", n ); 
   }
 
int crslab = 99;
 
getlab(){
   /* return a number usable for a label */
   return( ++crslab );
   }
 
/* (ef) 11/28/85 -- reg_use is lowest register variable, reg_save */
/*                  is callers lowest register that needs to be   */
/* reg_push is the lowest temp register that was pushed. We need  */
/* to save space in the stack frame for reg_pushed through r15,   */
/* but only do a store multiple from reg_save on up.              */
/* (ef) 2/12/86  -- These variables are declared in local2.c for  */
/*                  the fortran compiler -- if the initialization */
/* values are changed here, make sure the other declarations      */
/* (which are ifdef'ed FORT) are updated as well.                 */
int reg_use  = MAXRVAR;
int reg_save = MAXRVAR+1;
int reg_push = MAXRVAR+1;

/* (ef) 12/3/85 -- number of words of parameters */
static int   nparms=0;

/*\
|* (ef) 1/28/86 -- braindamage to insure that taking the address of a
|*      parameter works.  proinst is PRO_NADA if no instruction need
|*      be inserted into the prologue, PRO_BRANCH if a branch needs to
|*      be inserted, and PRO_CAL for a cal. If proinst is not PRO_NADA
|*      a ".long LI101" will be emitted in the prolog for the appropriate
|*      instruction.  LI101 (and other necessary code) will be handled in
|*      in the epilogue.
\*/

#define PRO_NADA   0
#define PRO_BRANCH 1
#define PRO_CAL	   2
static int   proinst;

efcode(){
   /* code for the end of a function */
   register struct symtab *p = &stab[curftn];
   extern int parmlbl;

   deflab( retlab );
 
   if( strftn ){  /* copy output, address in R2, to caller -- 7/8/85 by WFA */
 
       printf(" cas r3,r2,r0 # efcode\n");
       printf(" get r2,L%d+%d(r13) # efcode\n", parmlbl, 
					LINK_SAVE_SZ+ARG_SAVE_SZ+ARG1_OFFSET);
       printf(" get r4,$%d # efcode\n",
           tsize( DECREF( p->stype ), p->dimoff, p->sizoff) / SZCHAR );
       printf(" balix r15,_.blt # efcode\n");
       printf(" get r0,$_blt # efcode\n");
       strftn = 0;
       }
   else if( dblftn ){  /* copy output, address in R2, to R2,R3 -- 7/9/85 WFA */
       printf(" get r3,4(r2) # efcode\n");
       printf(" get r2,0(r2) # efcode\n");
       dblftn = 0;
       }

   if( optize ){  /* tell optimizer end of function, and free reg vars */
       printf(".set LOWREGVAR%d, %d # optimized\n", ftnno, reg_use + 1);
       printf(".set LOWREG%d, r%d\n", ftnno, reg_save );
       if( reg_use < MINRVAR )
           printf("_efunct\n" );
       else
           printf("_efunct %d,%d\n", MINRVAR, reg_use );
   }

 /* (ef) 12/11/85 -- reset SP from FP so we can implement alloca       */
 /*      which means save frame pointer (FP gets restored by lm).      */
 /* (ef) 1/4/86   -- optionally */

   if (aaflg) { /* alloca enabled? */
       printf(" cas r4,r13,r0 # epilogue\n");
       printf(" lm %%LR%d,LOWREG%d*4-64+L%d(r13) # epilogue\n",ftnno,ftnno,
								     parmlbl);
       printf(" brx r15 # epilogue\n");
       printf(" cal sp,%d+L%d(r4) # epilogue\n",
   					    LINK_SAVE_SZ+ARG_SAVE_SZ,parmlbl);
   }
   else {
       printf(" lm %%LR%d,LOWREG%d*4-64+L%d(r13) # epilogue\n",ftnno,ftnno,
								     parmlbl);
       printf(" brx r15 # epilogue\n");
       printf(" ai sp,sp,L%d+LREGSPACE%d+%d # epilogue\n",ftnno,ftnno,
						    LINK_SAVE_SZ+ARG_SAVE_SZ);
   }
 
   /* (ef) 1/28/86 -- deal with extra parameters that have to be pushed */
   if (proinst==PRO_BRANCH) {
       register int knt;
       register int off= LINK_SAVE_SZ+(SZINT/SZCHAR)*nparms;

       printf(" # we have to push arg registers, somebody used &arg\n");
       printf("LY%d: cal r13,L%d-64(sp)\n",ftnno,ftnno);
       
       for (knt=nparms+MINARGREG;knt<MAXARGREG;knt++) {
          printf(" put r%d,%d+L%d(r13) # bfcode(efcode) \n",knt,off,
	  							     parmlbl);
	  off+= (SZINT/SZCHAR);
       }
       printf(" bx LX%d # epi-prologue\n",ftnno);
       printf(" put r%d,%d+L%d(r13) # bfcode(efcode)\n",MAXARGREG,off,
       								     parmlbl);
   }
	  
   /* (ef) 12/3/85 -- trace table info */
   printf(" .align 2\n");
   printf(" .short 0xDF07	# trace table -- marker, D_COMMON\n");
   printf(" .short 0xDF%1x8	# trace table -- marker, (first gpr,wxyz)\n",
							reg_save);
   printf(" .short 0x%1x%1x%2x	# trace table -- nparms, fp, offset\n",
			       (nparms>15?15:nparms),FPREG,
			       (64+4*(16-(reg_save>reg_push?reg_push:reg_save))+ARG_SAVE_SZ+LINK_SAVE_SZ)/4);

   if( !optize ) {
       printf(".set LOWREGVAR%d, %d # not optimized\n", ftnno, reg_use + 1);
       printf(".set LOWREG%d, r%d\n", ftnno, reg_save);
   }
   printf(".set LREGSPACE%d, %d\n",ftnno, 
                    (16-(reg_save>reg_push?reg_push:reg_save))*(SZINT/SZCHAR));
   printf(".set LR%d, LOWREG%d\n", ftnno, ftnno);
 
   reg_use = MAXRVAR;
   reg_save= MAXRVAR+1;
   reg_push= MAXRVAR+1;
   p2bend();

   /*\
   |* (ef) 1/28/86 -- we don't have to push any parameters, set up the
   |*      approriate cal or branch instruction.  This has to happen
   |*      *after* L<ftnno> is defined. i.e. after p2bend.  That's why
   |*      this is down here, instead of up where the actual code to
   |*      push extra arguments is generated.
   \*/

   if (proinst==PRO_CAL)
       printf(" .set LI%d,0xc8d10000+0xffff&(L%d-64) # cal r13,L%d-64(sp)\n",
							   ftnno,ftnno,ftnno);
   else if (proinst==PRO_BRANCH)
       printf(" .set LI%d,0x88800000+(LY%d-LX%d+4)>>1 # b LY%d\n",ftnno,
   							   ftnno,ftnno,ftnno);
   fdefflag = 0;
 
   locctr( DATA );
   printf(" .align 2\n");
   printf(" .ltorg\n");
   printf(" .align 2\n");
 
   }
 
#define LAST_REG_OFFSET	((LINK_SAVE_SZ+ARG_SAVE_SZ+ARG4_OFFSET)*SZCHAR)
#define		PARAM_REG(off)	((off-LAST_REG_OFFSET)/SZPOINT+5)

bfcode( a, n ) register n; register 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;
   extern int parmlbl;
 
   if( !anyprocs ){
       ++anyprocs;
       locctr( DATA );
       printf(" .align 2\n .ltorg\n");
   }
 
   locctr( PROG );
   p = &stab[curftn];
#ifndef FLEXNAMES
   printf(" .ascii \"<%.8s>\"\n", p->sname);
#else
   printf(" .ascii \"<%s>\"\n", p->sname);
#endif
   printf(" .align 2\n");

   if( gdebug ){
#ifdef STABDOT
       pstabdot(N_SLINE, lineno);
#else
       pstab(NULLNAME, N_SLINE);
       printf("0,%d,LL%d\n", lineno, labelno);
       printf("LL%d:\n", labelno++);
#endif STABDOT
    }
 
   defentry( p );
 
   locctr( DATA );
   defdata(p);	/* WFA 7/8/85 */
   locctr( PROG );
   temp = p->stype;
   temp = DECREF(temp);
#ifdef FLOAT_IS_FLOAT  /* (ef) 1/13/86 */
   dblftn = (temp==DOUBLE);
#else
   dblftn = (temp==DOUBLE)||(temp==FLOAT);
#endif FLOAT_IS_FLOAT
 
   retlab = getlab();
 
   /* routine prologue */
 
#ifndef FLEXNAMES
   printf(" #-----------------| %.8s |-------------------#\n", p->sname);
#else
   printf(" #-----------------| %s |-------------------#\n", p->sname);
#endif
   /*
   /* save register variables, and return address  and
   /* bss pointers.
   */
   printf(" stm %%LR%d,%d+LOWREG%d*4(sp) # prologue\n",
       ftnno, REG_OFFSET, ftnno);
   /*
   /* decrement stack pointer by space for FRAME save areas, plus space for  
   /* local variables, plus space for parameters passed to callee
   */
   printf(" ai sp,sp,-L%d-LREGSPACE%d-%d # prologue\n", ftnno, ftnno,
						LINK_SAVE_SZ+ARG_SAVE_SZ);
   printf(" .using %s,r14 # prologue\n", exname( p->sname ) );
/* (ef) 1/28/86 -- attempt to deal with braindamage to allow non-portable */
/*      argument list manipulation.  (i.e. pointer into argument list)    */

   printf(" cas r14,r0,r0      # prologue (setup dp)\n");
   if (n>=4) {
       printf(" cal r13,L%d-64(sp) # prologue (setup fp)\n", ftnno);
       proinst= PRO_NADA;
   }
   else {
       printf(" .long LI%d # usually cal r13,L%d-64(sp)\nLX%d: ",ftnno,ftnno,
       								      ftnno);
       proinst= PRO_CAL;
   }
 
   if (proflg) {/* (ef) 1/4/86 -- profiling support */
      printf(" cas r0,r15,r0 # profiling\n");
      printf(" bali r15,mcount   # profiling\n");
   }

   if( optize ){
       printf("_funct\n");
       dump_parm_syms();
   }

   if( gdebug ){
#ifdef STABDOT
       pstabdot(N_SLINE, lineno);
#else
       pstab(NULLNAME, N_SLINE);
       printf("0,%d,LL%d\n", lineno, labelno);
       printf("LL%d:\n", labelno++);
#endif STABDOT
    }
 
   off = ARGINIT;
   nparms= 0;

    /* (ef) 11/28/85 -- adjust offset to take hidden arg into account */
   if ( strftn ) {
      off+= SZPOINT;
      printf(" put r2,%d+L%d(r13) # bfcode (hidden)\n",LINK_SAVE_SZ,parmlbl);
      nparms++;
   }
 
   for( i=0; i<n; ++i ) { register int old_off;
      p = &stab[a[i]];
      old_off= off;
#ifndef BUG0
      if( sdebug>1 ){
         printf("Symbol table entry for parm %d:\n  ", i);
         hexdump( p, sizeof(struct symtab) );
	 printf("(p->sclass=%d)\n",p->sclass);
         }
#endif
      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 );
	 SETOFF( off, SZINT );

         if( old_off<= LAST_REG_OFFSET )
            printf(" cas r%d,r%d,r0 # bfcode reg(%d)\n",temp,
	    						PARAM_REG(old_off),i);
         else
            printf(" get r%d,L%d+%d(r13) # bfcode reg(%d)\n",temp, parmlbl,
	    						   old_off/SZCHAR,i);
 
         p->offset = temp;         /* remember register number         */
         p->sclass = REGISTER;     /* remember that it is a register   */
      }
      else {
         if( oalloc( p, &off ) ) cerror( "bad argument" );
	 SETOFF( off, SZINT );

	 while ((old_off<off)&&(PARAM_REG(old_off)<=5)) {
		 printf(" put r%d,%d+L%d(r13) # bfcode auto (%d)\n",
	     			PARAM_REG(old_off),old_off/SZCHAR,parmlbl,i);
                 old_off+= SZPOINT;
	 }
      }
   }
   nparms= (off-ARGINIT)/SZPOINT;
   fdefflag = 1;
}
 
bccode(){ /* called just before the first executable statment */
          /* by now, the automatics and register variables are allocated */
   register k;

   SETOFF( autooff, SZINT );
   /* set aside store area offset */
   p2bbeg( autooff, regvar );
   reg_use = (reg_use > regvar ?   regvar     : reg_use);
   if (( reg_use!=MAXRVAR ) && (reg_save>reg_use+1))
      reg_save= reg_use+1;
   marktemps(reg_use+1);
   }
 
ejobcode( flag ) register flag; {
   /* called just before final exit */
   /* flag is 1 if errors, 0 if none */
 
   if( !anyprocs ){ /* added 10/20/83 by JEC for string literals */
       locctr( DATA );
       printf(" .align 2\n .ltorg\n");
       }
   if( flag )
      printf(" # try again\n");
   else {
	printf(".globl .oVpcc\n.globl .oVncs\n");
        printf(".set .oVpcc, 0\n.set .oVncs, 0\n # Academic Information Systems 4.2 for the IBM RT PC\n");
	}
   }
 
aobeg(){
   /* called before removing automatics from stab */
   }
 
aocode(p) register struct symtab *p; {
   /* called when automatic p removed from stab */
   }
 
aoend(){
   /* called after removing all automatics from stab */
   }
 
defname( p ) register struct symtab *p; {
   /* define the current location  as the name p->sname */
 
   if( p->sclass == EXTDEF )
       printf( " .globl %s # defname\n", exname( p->sname ) );
 
   if( p->sclass == STATIC && p->slevel>1 ) deflab( p->offset );
   else printf( "%s: \n", exname( p->sname ) );
 
   }

defentry( p ) register struct symtab *p; {
   /* define the current location as the function entry point .p->sname */
   /* WFA 7/18/85 */
   char *q = entryname( p->sname );
 
   if( p->sclass == EXTDEF )
       printf( " .globl %s # defentry\n", q );	
   printf( "%s: \n", q );
 
   }

defdata( p ) register struct symtab *p; {
   /* define the current location as the data area for p->sname */
   /* and place the address of the entry point in the data area */
 
   if( p->sclass == EXTDEF )
       printf( " .globl %s # defdata\n", exname( p->sname ) );
   printf( "%s: ", exname( p->sname ) );
   printf( ".long %s\n", entryname( p->sname ) );
   /* (ef) 1/4/86 -- profiling support */
   if ((proflg)||(aaflg))
      printf( ".long 0 # %s profiling word\n",(proflg?"":"dummy"));
   /* (ef) 12/11/85 -- put out size of argument area for alloca */
   /* (ef) 1/4/86   -- optionally, and put magic no. in high halfword */
   if (aaflg)
      printf( ".short 0xf690, LP%d # defdata\n", ftnno );
   }
 
bycode( t, i ) register 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 ){
			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( "," );
		printf( "0x%x", t );
		if( i == 07 ) printf( "\n" );
		}
#endif
	}


/* (ef) 1/28/86 -- Somebody tried to take the address of a parameter. */
/*	Deal with it locally, if necessary.			      */

parmadr(p)
register NODE *p;
{
    if (nparms<REG_ARGS) {
#ifdef BITCHY
       werror("Argument list access through a pointer is non-portable.");
#endif
       proinst= PRO_BRANCH;
    }
    return(1);
}
 
zecode( n ) register n; {
   /* n integer words of zeros */
   register OFFSZ temp;
   if( n <= 0 ) return;
   printf( " .fill %d,4,0\n", n );
   temp = n;
   inoff += temp*SZINT;
   }
 
			/* return the alignment of field of type t */
fldal( t ) register unsigned t; { 
   uerror( "illegal field type" );
   return( ALINT );
   }
 
fldty( p ) register struct symtab *p; { /* fix up type of field p */
   ;
   }
 
where(c) register 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, "lc",
/*  SHORT, "lha",
/*  INT, "l",
/*  LONG, "l",
/*  FLOAT, "movf",
/*  DOUBLE, "movd",
/*  UCHAR,    "lc",
/*  USHORT,   "lh",
/*  UNSIGNED, "l",
/*  ULONG,    "l",
/*  -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[]; {
#ifdef BUFSTDERR
    char errbuf[BUFSIZ];
    setbuf(stderr, errbuf);
#endif
    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
      */
 
   /* Note: generated code assumes r15 is free (added by JEC) */
 
   register i;
   register CONSZ j, range;
   register dlab, swlab;
   struct symtab *pf = &stab[curftn];	/* WFA 7/20/85 */
 
   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();
        swlab = getlab();
 
        /* already in r2 */
        printf(" # switch using vector \n");
/*      opr2val( "sub", p[1].sval ); */
        opr2val( "s", p[1].sval );
        opr2val( "cl", range );
/*      printf(" jh  ._E%ld\n", swlab); */
        printf(" jh  ._E%ld\n", swlab);
/*        printf(" shl r0,2\n");*/
        printf(" shl r2,2\n");  /* (ef) 11/8/85 FORCE forces to r2 in NCS */
/*        printf(" cas r15,r0,r14\n");*/
        printf(" cas r15,r2,r14\n"); /* (ef) 11/8/85 FORCE to r2 */
        /* WFA 7/20/85, modified for new calling convention: */
        printf(" .using %s,r15 \n", exname( pf->sname ) );  /* lie a little */
        printf(" get r15,L%d\n", swlab);
        /* WFA 7/20/85, modified for new calling convention: */
        printf(" .using %s,r14\n", exname( pf->sname ) );  /* restore truth */
        printf(" br  r15\n");
        locctr( DATA );
        printf(" .align 2\nL%d:\n", swlab);
        for( i=1,j=p[1].sval; i<=n; j++) {
          printf(" .int L%d\n",
                (j == p[i].sval ? p[i++].slab : dlab))
          ;
        }
        locctr( PROG );
/*      printf("._E%d:\n", swlab); */
        printf("._E%d:\n", swlab);
 
        if( p->slab >= 0 ) branch( dlab );
        else printf("L%d:\n", dlab);
        return;
 
    }
 
    if( n>8 ) { /* heap switch */
 
        printf(" # switch using heap \n");
 
        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 */
    /* already in r0 */
    printf(" # switch using brute force \n");
 
    for( i=1; i<=n; ++i ){
/*      opr2val( "comp", p[i].sval ); */
        opr2val( "c", p[i].sval );
        printf( " be L%d\n", p[i].slab );
    }
 
    if( p->slab>=0 ) branch( p->slab );
}
 
makeheap(p, m, n)
register struct sw *p;
register m, n;

{
   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 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)
register start, limit;
{
   register int label;
 
 
   if( start > limit ) return;
/*  opr2val("comp", heapsw[start].sval); */
    opr2val("c", heapsw[start].sval);
    printf(" be L%d\n",  heapsw[start].slab);
   if( (2*start) > limit ) {
         printf(" b L%d\n",  heapsw[0].slab);
      return;
   }
   if( (2*start+1) <= limit ) {
      label = getlab();
         printf(" bh L%d\n", label);
   } else
         printf(" bh 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);
   }
}
 

/* (ef) 11/8/85 -- changed opr0val to opr2val */
/* it appears that opr0val was only called for switches    */
/* the value to be switched upon is FORCE'd by the grammar */
/* in OCS, FORCE stuffed values into r0, in NCS FORCE uses */
/* r2 -- hence all references to r0 in switch generation   */
/* should in fact refer to r2.  Whew.                      */
opr2val( op, val )
    register char *op;
    register CONSZ val;
{
 
    if( val <= MAXIVAL &&  val >= MINIVAL ){
/*      printf( " %si r0," , op ); */
	if( strcmp( op, "s" ) )
/*            printf( " %si r0," , op );  (ef) 11/8/85 */
            printf( " %si r2," , op );
	else
/*	    printf( "%si r0,r0,", op); (ef) 11/8/85 */
	    printf( "%si r2,r2,", op);
        printf( CONFMT, val );
        printf( "\n" );
    } else {
/*      printf( " loadi r15," );
/*      printf( CONFMT, val );
*/
        printf( " get r15,$" );
        printf( CONFMT, val );
/*        printf( ") \n %s r0,r15\n", op ); (ef) 11/8/85 */
        printf( " \n %s r2,r15\n", op );
    }
}
 
dns_sym( sp )
    register struct symtab *sp;
{
    register bytes = dimtab[sp->sizoff] / SZCHAR;
    register hightype = sp->stype & ~BTMASK;  /* non-basic type */
    register basictype = sp->stype & BTMASK;  /* basic type */
 
    while( hightype != (hightype & TMASK) )   /* highest level type */
        hightype = (hightype >> TSHIFT) & ~BTMASK;
    if( hightype == PTR )        /* if this is really a pointer   */
        bytes = SZPOINT/SZCHAR;  /* then it's as big as a pointer */
 
    if( dimtab[sp->dimoff]
     || basictype == STRTY
     || basictype == UNIONTY
     || basictype == MOETY
      ) return;
 
    switch( sp->sclass ){
        case AUTO:
            printf( "_sym %d,\"%d\"", bytes, sp->offset/SZCHAR );
#ifndef FLEXNAMES
            printf( " # %.8s\n", sp->sname );
#else
            printf( " # %s\n", sp->sname );
#endif
            break;
        case PARAM:
            printf( "_sym %d,\"L%d+%d\"", bytes, ftnno, sp->offset/SZCHAR );
#ifndef FLEXNAMES
            printf( " # %.8s\n", sp->sname );
#else
            printf( " # %s\n", sp->sname );
#endif
            break;
    }
}
 
dump_parm_syms( )
{
    register struct symtab *sp;
 
    for( sp=stab; sp < &stab[SYMTSZ]; ++sp ){
 
        if( sp->stype == TNULL )
            continue;
        if( sp->sclass == PARAM )
            dns_sym( sp );
    }
}
 
/****************************************************************************/
 
hexdump( p, n ) register char *p; register n;{
   register i;
 
   while (n--)
      if( (i = *p++) < 16 )
         printf("0%x ", i);
      else
         printf("%x ", i);
   printf("\n");
}
 
#ifdef notdef
dumpsymb( sp )
    register struct symtab *sp;
{
#ifndef FLEXNAMES
    printf( "%.8s", p->sname );
#else
    printf( sp->sname );
#endif
printf( " type=0x%x class=%d level=%d flags=0x%x offset=%d, dim=%d size=%d\n",
sp->stype, sp->sclass, sp->slevel, sp->sflags, sp->offset/8,
dimtab[sp->dimoff]/8, dimtab[sp->sizoff]/8, sp->suse );
}
#endif
