/* $Header:local2.c 12.0$ */
/* $ACIS:local2.c 12.0$ */
/* $Source: /ibm/acis/usr/src/lib/pcc_ca/RCS/local2.c,v $ */
#ifndef lint
static char rcsid[] = "$Header:local2.c 12.0$";
#endif
#ifdef unix
# include "mfile2.h"
# include <frame.h>
# include <ctype.h>
#else
# include "doption h *"  /* circumvention for -D problem with preprocessor */
# include "mfile2 h *"
#ifdef FORUNIX
# include "ctype h t"
#endif
#endif
 
/* a lot of the machine dependent parts of the second pass */
extern int xdebug;   /* machine dependent debugging flag */

extern struct optab *template;  /* template currently being expanded JEC */
 
# define MAXSTASG 32
 
static int *tregltmp;
# define TREGLOOP(r) for(tregltmp=tregs,reg=(*tregltmp);((*tregltmp)!=(-1));tregltmp++,reg=(*tregltmp))
/*# define TREGLOOP(r) for(r=0;r<MINRVAR;++r)*/
# define regfld(p) p->tn.rval
# define regof(p) (p->in.op==REG || p->in.op==OREG ? p->tn.rval : -1)
 
/* This table is used by reclaim() to choose a result.  If the goal (cookie)
/* matches (anded with not zero) cform, and the resultant node matches mform
/* (tshape(node, mform)), then that resultant node is used.
*/
 
struct respref respref[] = {
   /* cform */      /* mform */
   INTAREG|INTBREG, INTAREG|INTBREG,
   INAREG|INBREG,   INAREG|INBREG|SOREG|STARREG|STARNM|SNAME|SCON,
   INTEMP,          INTEMP,
   FORARG,          FORARG,
   INTEMP,          INTAREG|INAREG|INTBREG|INBREG|SOREG|STARREG|STARNM,
   0,               0
   };
 
/* This vector is used to keep track of spilled temp regs during calls to the
/* compiler support routines for mul, div, mod, and the floating point routines
*/
static pushlist[REGSZ]; /* list of temp regs to be pushed/popped */
 
 
 
where(c) register c; {
   fprintf( stderr, "%s, line %d: ", filename, lineno );
   }
 
lineid( l, fn ) register l; register char *fn; {
   /* identify line l and file fn */
    printf( " #===> line %d, file %s\n", l, fn );
   }
 
#ifdef FORT
int reg_use  = MAXRVAR;
int reg_save = MAXRVAR+1;
int reg_push = MAXRVAR+1;
int parmlbl  = 0;
int ftlab1,ftlab2;
#endif

eobl2(){
   /* Allocate the space for local variables and arguments passed to callee */
   register OFFSZ spoff;   	/* offset from stack pointer */
   register OFFSZ spargoff;   	/* offset from stack pointer */
#ifndef FORT
   extern int parmlbl; /* (ef) 11/30/85 */
#endif 
 
   spoff = maxoff;
   if( spoff >= AUTOINIT ) spoff -= AUTOINIT;	/* No effect now! XXX WFA */
   spoff /= SZCHAR;
   SETOFF(spoff,4);
#ifdef FORT
   printf( ".set .V%d, %ld # eobl2\n", ftnno, spoff );
#endif FORT

   spargoff = (maxargs<0) ? 0 : maxargs;
   SETOFF(spargoff,4);
   printf( ".set LP%d, %ld # eobl2\n", ftnno, spargoff );
   printf( ".set L%d, %ld # eobl2\n", ftnno, spargoff+spoff );
#ifdef FORT
   if ( maxtreg < reg_save )  /* save fortran register variables */
      reg_save = maxtreg;
   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 L%d,64+LREGSPACE%d\n",parmlbl,ftnno);
   parmlbl = getlab();

   printf(".text\n");
   printf(".align 2\n");
   printf(".short 0xDF07	| trace table -- marker, D_COMMON\n");
   printf(".short 0xDF%1x8	| trace table -- marker, first gpr\n",
		reg_save);
   printf(".short 0x%1x%1x%2x	| trace table -- nparms,fp,offset\n",
		4,13,(64+4*(16-(reg_save<reg_push?reg_save:reg_push))+
		      ARG_SAVE_SZ+LINK_SAVE_SZ)/4);
   reg_save = reg_push = MAXRVAR;
#else
   printf( ".set L%d, 64+LREGSPACE%d  # eobl2 parms\n",parmlbl,ftnno);
#endif
   maxargs = - ARG_SAVE_SZ;	/* WFA 7/12/85 */
   }
 
struct hoptab { int opmask; char * opstring; } ioptab[] = {
 
/*  ASG PLUS,  "add", */
    ASG PLUS,  "a",
/*  ASG MINUS, "sub", */
    ASG MINUS, "s",
    ASG OR,    "o",
    ASG ER,    "x",
    ASG AND,   "n",
/*  PLUS,      "add", */
    PLUS,      "a",
/*  MINUS,     "sub", */
    MINUS,     "s",
    OR,        "o",
    ER,        "x",
    AND,       "n",
   -1,         ""
};
 
hopcode( f, o ) register f,o; {
    /* output the appropriate string from the above table */
 
    register struct hoptab *q;
 
    for( q = ioptab;  q->opmask>=0; ++q ){
         if( q->opmask == o ){
              printf( "%s", q->opstring );
              switch( f ) {
                   case 'I':
                        printf("%c", tolower(f));
                        break;
  
                   }
              return;
              }
         }
    cerror( "no hoptab for %s", opst[o] );
    }
 
char *
rnames[] = {  /* keyed to register number tokens in mac2defs */
 
   "r0", /* scratch */
   "sp",
   "r2", "r3", /* parameters, return values. A pain to make scratch */
   "r4", "r5", /* parameters, scratch */
   "r6", /* scratch */
   "r7", "r8", "r9", "r10", "r11", "r12", /* variables */
   "r13", /* local frame pointer */
   "r14", /* local data pointer */
   "r15" /* scratch, and return address */
 
   };
 
int rstatus[] = {
   SBREG|STBREG,			      /* r0 */
   SAREG,                                     /* sp */
   SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, SAREG|STAREG, /* 2,3,4,5 */
   SAREG,  SAREG, SAREG, SAREG, SAREG, SAREG, /* 6,7,8,9,10,11 */
   SAREG|STAREG,			      /* 12 */
   SAREG, SAREG,	                      /* 13,14 */
   SAREG|STAREG				      /* 15 */
   };

/* (ef) 12/18/85 arrays various kinds of registers. All are -1 terminated */
/*    taregs = list of all temp 'A' regs, in the order they should be     */
/*             allocated.                                                 */
/*    tbregs = same for bregs                                             */

#ifndef FORT
int taregs[] = {
    12, 11, 10, 9, 8, 7, 6, 15, 2, 3, 4, 5, -1
    };
#else
int taregs[] = {
    12, 10, 9, 8, 7, 6, 15, 2, 3, 4, 5, -1
    };
#endif FORT

int tbregs[] = {
    0, -1
    };

#ifndef FORT
int tregs[] = {
    0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 15, -1
    };
#else
int tregs[] = {
    0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 15, -1
    };
#endif FORT

tlen(p) register NODE *p;
{
   switch(p->in.type) {
      case CHAR:
      case UCHAR:
         return(1);
 
      case SHORT:
      case USHORT:
         return(2);
 
      case DOUBLE:
         return(8);
 
      default:
         return(4);
      }
}
 
mixtypes(p, q) register NODE *p, *q;
{
   register tp, tq;
 
   tp = p->in.type;
   tq = q->in.type;
 
   return( (tp==FLOAT || tp==DOUBLE) !=
      (tq==FLOAT || tq==DOUBLE) );
}

/* (ef) 1/11/85 -- marks MINRVAR through regvar as temp registers     */
/*                 and regvar+1 through MAXRVAR as non-temp registers */
/* allows registers that would normally hold register variables to be */
/* used as temps if otherwise idle.                                   */

marktemps(regvar)
register int regvar;
{
register int k;
register int *lrstatus= rstatus;

    if (xdebug) 
       printf("marktemps(%d)\n",regvar);

    if (regvar>MAXRVAR)
       regvar= MAXRVAR;
    else if (regvar<MINRVAR) 
       regvar=MINRVAR;

    for (k=MINRVAR;k<regvar;k++) 
	lrstatus[k]|=STAREG;
    for (k=regvar;k<=MAXRVAR;k++)
        lrstatus[k]&=(~STAREG);
}
 
    /*\
    |* (ef) 11/24/85 -- takes node, cookie, name of source, destination,
    |*                  and temp registers and performs the appropriate
    |*                  constant multiply.  Register names are values
    |*                  for getlr, or '0' for r0.  If the p->in.op is not
    |*                  MUL or ASG MUL, the constant is moved into a 
    |*                  register, and muldiv is called with the appropriate
    |*                  arguments.
    \*/

gen_constmult( p, cookie, src, dst, tmp ) register NODE *p; 
{
register char *src_name,*dst_name,*tmp_name;

   if ( xdebug )  {
      printf("gen_constmult( %o, ",p);
      prcook(cookie);
      printf(", %c, %c, %c )\n",src,dst,tmp);
      printf("              p->in.op=  %s\n",opst[p->in.op]);
   }

   dst_name= ( dst=='0' ? "r0" : rnames[getlr( p, dst )->tn.rval] );
   switch ( p->in.op ) {
      case MUL:
      case ASG MUL: 
	   src_name= ( src=='0' ? "r0" : rnames[getlr( p, src )->tn.rval] );
	   tmp_name= ( tmp=='0' ? "r0" : rnames[getlr( p, tmp )->tn.rval] );
	   cm( src_name, dst_name, tmp_name, getlr(p,'R')->tn.lval);
           break;
      default: { NODE *r= getlr(p,'R');
	   printf(" get %s,$%d # cm op not mul!\n",dst_name,r->tn.lval);
           r->tn.op= REG;   /* (ef) 11/24/85 -- make muldiv happy */
	   r->tn.rval= ( dst=='0'? R0: getlr( p, dst )->tn.rval );
	   muldiv( p, dst );
	   r->tn.op= ICON; /* (ef) 11/24/85 -- make reclaim happy */
	   break;
     }
   } 
}

prtype(n) register NODE *n;
{
   if (n->in.op == ICON)
     if (n->tn.lval>-32768 && n->tn.lval<32767)
       {
         printf("i");
         if (n->tn.lval>0 && n->tn.lval<15)
           printf("s");
         return;
       }
   switch (n->in.type)
      {
         case FLOAT:
         case LONG:
         case ULONG:
         case INT:
         case UNSIGNED:
              return;
 
         case SHORT:
              printf("ha");
              return;
 
         case USHORT:
              printf("h");
              return;
 
         case CHAR:
         case UCHAR:
              printf("c");
              return;
 
         default:
	      if ( ISFTN( n->in.type ) ) return;
	      else if ( ISPTR( n->in.type ) ) return;
	      else cerror("zzzcode- bad type");

/*            if ( !ISPTR( n->in.type ) ) cerror("zzzcode- bad type");
              else return;		*/
         }
}
 
zzzcode( p, c, cookie ) register NODE *p; register c, cookie; {
    register m;
 
    switch( c ){
 
    case 'Q':{ /* negation of relational ops */
       static char *notrelop[] = {
          "ne",  /* EQ */
          "e",   /* NE */
          "h",   /* LE */
          "nl",  /* LT */
          "l",   /* GE */
          "nh",  /* GT */
          "h",   /* ULE */
          "nl",  /* ULT */
          "l",   /* UGE */
          "nh",  /* UGT */
          };
       if( p->in.op > UGT ) cerror( "relop out of range" );
       printf( notrelop[ p->in.op - EQ ] );
       return;
       }
 
   case 'N': /* logical ops (NOT, ANDAND, OROR) yield 0 or 1 */
      cbgen( 0, m=getlab(), 'I' );
      deflab( p->bn.label );
      printf( " lis %s,0 # zzzN\n", rnames[ getlr( p, '1' )->tn.rval ] );
      deflab( m );
      return;
 
   case 'P': /* condition branch */
      cbgen( p->in.op, p->bn.label, c );
      return;

	     /* (ef) 12/23/85 -- to correctly assign register variables */
/* JSW 8/13/86
 * define to get truncation, sign extension, etc. of shorts, chars without
 * messing up ints and longs.  This was undef'ed because it caused too many
 * useless instructions to be generated.  The code worked fine but was
 * about 10% bigger.  The bugs will stay in until we can come up with some
 * way to make PCC smarter(i.e. less retarded) so that it knows when to not
 * generate mask or sign extend instructions because the result will be
 * thrown away.
 */
#define GOODSC 1
#undef GOODSC      /* remove this line to get good shorts&chars & bigger code*/
/*
 * JSW 7/7/86 - implemented the truncation and sign extension, for left branch.
 */
   case 'A': /* Adjust contents of register to correct size */
      {
      
#ifdef GOODSC
      switch( p->in.type )
         {
         case USHORT: expand( p, FOREFF, " nilz AL,AL,0xffff # jsw - truncate unsigned short\n" ); break;

         case SHORT: expand( p, FOREFF, " exts AL,AL # jsw - truncate short\n" ); break;

         case CHAR:
         case UCHAR: expand( p, FOREFF, " nilz AL,AL,0xff # jsw - truncate unsigned char\n" ); break;

/* JSW - no signed characters
         case CHAR: expand( p, FOREFF, " mc03 AL,AL # jsw\n sari16 AL,8 # jsw - sign extend register char\n" ); break;
*/
         }
#endif
      return;
      }
 
/*
 * JSW 7/7/86 - implemented the truncation and sign extension, for right branch.
 */
   case 'a': /* Adjust contents of register to correct size */
      {
#ifdef GOODSC
      switch( p->in.type )
         {
         default: break;

         case USHORT: expand( p, FOREFF, " nilz AR,AR,0xffff # jsw - truncate unsigned short\n" ); break;

         case SHORT: expand( p, FOREFF, " exts AR,AR # jsw - truncate short\n" ); break;

         case CHAR:
         case UCHAR: expand( p, FOREFF, " nilz AR,AR,0xff # jsw - truncate unsigned char\n" ); break;

         }
#endif
      return;
      }

/*
 * JSW 7/7/86 - implemented the truncation and sign extension, for A1.
 */
   case '1': /* Adjust contents of register to correct size */
      {
#ifdef GOODSC
      switch( p->in.type )
         {
         default: break;

         case USHORT: expand( p, FOREFF, " nilz A1,A1,0xffff # jsw - truncate unsigned short\n" ); break;

         case SHORT: expand( p, FOREFF, " exts A1,A1 # jsw - truncate short\n" ); break;

         case CHAR:
         case UCHAR: expand( p, FOREFF, " nilz A1,A1,0xff # jsw - truncate unsigned char\n" ); break;

         }
#endif
      return;
      }

/*
 * JSW 7/7/86 - implemented the truncation and sign extension, for A1.
 */
   case '2': /* Adjust contents of register to correct size */
      {
#ifdef GOODSC
      switch( p->in.type )
         {
         default: break;

         case USHORT: expand( p, FOREFF, " nilz A2,A2,0xffff # jsw - truncate unsigned short\n" ); break;

         case SHORT: expand( p, FOREFF, " exts A2,A2 # jsw - truncate short\n" ); break;

         case CHAR:
         case UCHAR: expand( p, FOREFF, " nilz A2,A2,0xff # jsw - truncate unsigned char\n" ); break;

         }
#endif
      return;
      }

/*
 * JSW 7/7/86 - implemented the truncation and sign extension, for A1.
 */
   case '3': /* Adjust contents of register to correct size */
      {
#ifdef GOODSC
      switch( p->in.type )
         {
         default: break;

         case USHORT: expand( p, FOREFF, " nilz A3,A3,0xffff # jsw - truncate unsigned short\n" ); break;

         case SHORT: expand( p, FOREFF, " exts A3,A3 # jsw - truncate short\n" ); break;

         case CHAR:
         case UCHAR: expand( p, FOREFF, " nilz A3,A3,0xff # jsw - truncate unsigned char\n" ); break;

         }
#endif
      return;
      }

   case 'L':   /* type of left operand */
   case 'R':   /* type of right operand */
      {
      register NODE *n = getlr( p, c );
 
      prtype(n);
      return;
      }

   case 'O':   /* left offset for structure arguments */
      {
			/* large (>4byte) structures are passed left */
			/* aligned, so no left offset */
	 if (p->stn.stsize>=4) return;
	 else {
	    char  align[40];

	    sprintf(align," ai A1,A1,%d # right alignment\n",4-p->stn.stsize);
            expand( p, FOREFF, align );
	    return;
	 }
      }

 
   case 'T':   /* rounded structure length for arguments */
      {
      int size;
 
      size = p->stn.stsize;
      SETOFF( size, 4);
      printf("%d", size);
      return;
      }
 
   case 'S':  /* structure assignment */
      {
         register NODE *l = p->in.left;
         register NODE *r = p->in.right;
         register size, rreg = regfld( p->in.right );
 
         if( r->tn.op != REG ) cerror("STASG rhs");
         if( l->tn.op != OREG && l->tn.op != NAME ) cerror("STASG lhs");
 
         if( (size = p->stn.stsize) < 1 || size > 65535 )
            cerror("STASG size");
 
         if( p->stn.stalign!=4 || size > MAXSTASG ){
            if( rreg == R2 ){
               expand( p, FOREFF, " cal r0,AL # stasg\n" );
               regdance( R0, R2, rreg, R3, 0 );
            } else {
               expand( p, FOREFF, " cal r2,AL # stasg\n" );
               regdance( R2, R2, rreg, R3, 0 );
            }
/*          printf(" loadi r4,%d # stasg\n", size ); */
	    loadi_expand( "r4", size );

            callsubr( "blt" , regfld(l), rreg );
	    poptregs(R0,R15); /* (ef) 11/17/85 -- callsubr pops too soon for ecvt */
         } else {
            while( (size -= SZINT/SZCHAR) >= 0 ){
               printf( " get r0,%d(%s) # stasg\n", size, rnames[rreg] );
               printf( " put r0,%d+", size );
               adrput( l );
               printf( " # stasg\n" );
            }
            if( !(cookie & FOREFF) )	/* XXX this is dubious! WFA */
               expand( p, FOREFF, " cal r0,AL # stasg\n" );
         }
         return;
      }

   case 'C':   /* 12/19/85 (ef) -- call a function whose constant pool */
   	       /*                  pointer is in AL.  Can't be done    */
	       /* purely as template because AL might be r15           */
      {
      if (regof(getlr(p,'L'))==R15) {
	  printf(" cas r0,r15,r0 # zzzc\n get r15,0(r15) # zzzc\n balr r15,r15 #zzzC\n");
      }
      else {
	  expand(p, cookie, " get r15,0(AL) # zzzcx\n balrx r15,r15 # zzzcx\n cas r0,AL,r0 # zzzcx\n");
      }
      return;
      }

   case 'V':   /* print the target address of the structure assign */
      {
      extern NODE *gsc_target;
 
      adrput( gsc_target );
      return;
      }
 
   case 'U':  /* unsigned operation check */
      if( ttype( getlr(p,'L')->in.type, TUNSIGNED|TULONG|TUSHORT|TUCHAR ) ||
          ttype( getlr(p,'R')->in.type, TUNSIGNED|TULONG|TUSHORT|TUCHAR )
        ) printf("l");
      return;
 
   case '>': /* shifts (arithmetic?) (left vs right) (immediate?) */
      printf( "s" );
      if( p->in.right->in.op == ICON )
         { /* shift by constant */
            printf( "h" );
         }
      if( p->in.op == ASG LS )
         { /* left shift */
            printf( "l" );
         }
      else
         { /* right shift */
            printf( "r" );
         }
/*      if( !(ISUNSIGNED( p->in.type )) )	*/
      if( !(ISUNSIGNED( p->in.left->in.type )) ) {
	  p->in.type = p->in.left->in.type;
          printf( "a" );
      }
      return;
   case 'D': /* save returned doubles in temps */
      if ( ttype( getlr(p,'L')->in.type, TDOUBLE ) ) {
	  expand( p, cookie, " put r2,A2 # dblret\n put r3,4+A2 # dblret\n cal r2,A2 # dblret\n" );
      }
      break;

   default:
      cerror( "illegal zzzcode" );
      }
   }
 
 
loadi_expand (reg_name, size)
    char *reg_name;
    int  size;
{
    if( size <= MAXIVAL && size >= MINIVAL )
	printf(" cal %s,%d(r0) # loadi \n", reg_name, size);
    else
	printf(" get %s,$%d # loadi \n",reg_name, size);
}


callsubr(subrname, lshare, rshare)
    register char *subrname;
    register lshare, rshare;
{
    /* Only used in local2.c for calling system functions */
    /* Modified, 7/20/85, WFA for CSL */
    pushtreg(R15, lshare, rshare);
    pushtreg(R0, lshare, rshare);
    printf(" balix r15,_.%s # callsubr\n", subrname);
    printf(" get r0,$.long(_%s) # callsubr\n", subrname);
/* (ef) 11/17/85 -- if we pop here, we clobber results from ecvt's */
/*    poptregs ();*/
}
 
		/* mul, div, and mod added by JEC 10/2/83 */
muldiv( p, c ) register NODE *p; register c; {
   register NODE *l = getlr(p,'L');
   register NODE *r = getlr(p,'R');

   register unsigned mdmndx= 0, ansreg;
   unsigned commute;
 
   static char *mdmsub[] = {
     "lmul$$",   /* signed long multiply */
     "ulmul$$",  /* unsigned long multiply */
     "ldiv$$",   /* signed long divide */
     "uldiv$$",  /* unsigned long divide */
     "lrem$$",   /* signed long modulo */
     "ulrem$$",  /* unsigned long modulo */
   };
 
   if ( c == '0' )
      ansreg= R0;
   else
      ansreg= regof(getlr(p,c));

   if( (r->in.op != REG) ||
       ((l->in.op != REG) && (l = getlr(p, '1'))->in.op != REG)
     ) cerror("* / % operands not REGs");
 
   switch( p->in.op ){  /* note ordering of subcases depends on mdmsub */
      default: cerror("* / % operator unknown");
 
      case ASG MOD:
      case MOD: mdmndx += 2;
      case ASG DIV:
      case DIV: mdmndx += 2;
      case ASG MUL:
      case MUL: break;
   }
   if( p->in.type == UNSIGNED ) mdmndx += 1;
 
   pushtreg( R2, ansreg, regfld(r) );
   pushtreg( R3, ansreg, regfld(r) );
   commute = (mdmndx < 2);
   regdance( regfld(l), R2, regfld(r), R3 , commute );
 
 /*   Non-standard linkage to {u,}l{mul,div,rem} funcs, do it by hand */
 /*   callsubr( mdmsub[mdmndx] );*/
 
    pushtreg(R0, ansreg, regfld(r) );
    pushtreg(R15, ansreg, regfld(r) );
    printf(" bali r15,%s # muldiv\n", mdmsub[mdmndx]);

   if( ansreg != R2 )
      printf(" cas %s,r2,r0 # X\n", rnames[ansreg]);

/* (ef) 11/17/85 -- results are saved somewhere, we can pop */
   poptregs (R0,R15);
}
 
 
/* LOCALTMP.C STARTS here ----------------------------------------------*/
#include <machine/rtflops.h>
#define MAX_UIF_SIZE	64
int no_RTFL = 0;

# define FCMPOP (oper==FPCOML)		/* floating compare operation */
# define FBINOP (oper!=FPNEGL)		/* binary floating operations */
 
#define CVTTYPE(p) (p->in.type == DOUBLE ? 2 : (p->in.type == FLOAT ? 1 : 0))
#define OPTYPE(t) ( ((t) == 2) ? (ADDRTYPE | DBLETYPE) : ((t) == 1) ? \
				 (GREGTYPE | SGLETYPE) : (GREGTYPE | INTTYPE) )
#define S_clrbit(mask,bitnum)	(mask) &= (~(0x8000 >> (bitnum)))
 
#define FPWTFR	0xff025000  /* LAR */
#define FPRDFR	0xff02f000  /* LAR */
#define FPRDSTR	0xff00dfb8  /* LAR */
#define FPADDL	0xff010000  /* LAR */
#define FPSUBL	0xff014000  /* LAR */
#define FPMULL	0xff01c000  /* LAR */
#define FPDIVL	0xff018000  /* LAR */
#define FPNEGL	0xff015000  /* LAR */
#define FPCOML	0xff012000  /* LAR */
#define	FPCWS	0xff081c00  /* LAR */
#define	FPCWL	0xff080c00  /* LAR */
#define	FPTSW	0xff00bc00  /* LAR */
#define	FPTLW	0xff00ac00  /* LAR */
#define	FPCSIL	0xff086c00  /* LAR */
#define	FPCLIS	0xff085800  /* LAR */
#define FPIMM1  0x00080000  /* LAR */
#define FPIMM2  0x00040000  /* LAR */

#define STATEQ    0x200	/* LAR */
#define STATGT    0x400	/* LAR */
#define STATMASK  0x600	/* LAR */

#define FPLT	0x40	/* LAR */
#define FPEQ	0x20	/* LAR */
#define FPGT	0x10	/* LAR */

#define FPSTORE	printf("\t\t.long\tFPaPUT0\t\t# genf/cvtf\n")

#define FPLOAD	printf("\t\t.long\tFPaGET0\t\t# genf/cvtf\n")


#define OPERATIONS		7	/* +, -, *, /, CMP, CMPT, NEG */
#define OPERAND_PRECISIONS	4	/* DD, DS, SD, SS */
#define NUM_SLOTS		8	/* could be increased if needed */

static int RTFL_block_count = 0;	/* number of RTFL blocks generated */
static int block_operand[OPERATIONS][OPERAND_PRECISIONS][NUM_SLOTS] = {
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	},	/* NEG */
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	},	/* CMP */
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	},	/* CMPT */
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	},	/* DIV */
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	},	/* MUL */
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	},	/* SUB */
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	}	/* ADD */
};
static int block_number[OPERATIONS][OPERAND_PRECISIONS][NUM_SLOTS] = {
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	},	/* NEG */
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	},	/* CMP */
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	},	/* CMPT */
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	},	/* DIV */
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	},	/* MUL */
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	},	/* SUB */
	{	{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}, 
		{0,0,0,0,0,0,0,0}	}	/* ADD */
};


static int
add_new_block(op,lr,rr,lt,rt)
	int	op,lr,rr,lt,rt;
{
	int	i,prec,new_block_label;

	new_block_label = getlab();		/* get a label */
	prec = (lt - 1)*2 + rt - 1;
	if ((op >= OPERATIONS) || (lt == 0) || (rt == 0) ||
	    (block_number[op][prec][NUM_SLOTS - 1])) /* table full */
		return (new_block_label);
	i = 0;
	while (block_number[op][prec][i]) i++;	/* find a zero entry */
	block_operand[op][prec][i] = ((rr << 8) | (lr << 4) | prec);
	block_number[op][prec][i] = new_block_label;
	return (new_block_label);
} /* end add_new_block */


static int
get_old_block(op,lr,rr,lt,rt)
	int	op,lr,rr,lt,rt;
{
	int	i,prec,key;

	if ((op >= OPERATIONS) || (lt == 0) || (rt == 0)) return (0);
	prec = (lt - 1)*2 + rt - 1;
	key = ((rr << 8) | (lr << 4) | prec);
	for (i = 0; i < NUM_SLOTS; i++)
		if (block_operand[op][prec][i] == key)
			return(block_number[op][prec][i]);
	return (0);
} /* end get_old_block */


genfloat( p, c ) register NODE *p; { /* added 1/6/84 by JEC */
   register NODE *l = getlr(p,'L');
   register NODE *r = getlr(p,'R');
   register lreg, rreg;
   register flreg=0, frreg=2;	/* LAR -- floating reg's, left and right */
   int opimm = 0;		/* LAR	-- 0 is norm			*/
				/*	-- 1 is right arg immediate	*/
				/*	-- 2 is left arg immediate	*/
   char opprec = 'L';		/* LAR precision of operation; always L(ong) */
   char *opstrg;		/* LAR 'string' name of operation	*/
   unsigned long oper, opaddr;
   extern int ga_byteoff;  /* see genargs */  /* LAR, moved from cvtfloat() */
   int lt, rt;
   int fp_op,operation,block_label,numopnds,uif_size,current_size;
   unsigned short scratchg;
   int tmp;

printf("\n\t# Enter genfloat\n");
 
   lt = CVTTYPE(l);
   rt = FBINOP ? CVTTYPE(r) : 2;	/* for NEG, default rt = 2 */

   uif_size = MAX_UIF_SIZE;
   switch( p->in.op ){  /* note ordering of subcases depends on doer table */
      default: cerror("float operator unknown");
 
      case UNARY MINUS: oper = FPNEGL;
			fp_op = FP_NEG;
			opstrg = "NEG";
			operation = 0;
			break;
      case EQ:
      case NE:		oper = FPCOML;
			fp_op = FP_CMP;
			opstrg = "CMP";
			operation = 1;
			break;
      case LE:
      case LT:
      case GE:
      case GT:		oper = FPCOML;
			fp_op = FP_CMPT;
			opstrg = "CMPT";
			uif_size += 32;
			operation = 2;
			break;
      case ASG DIV:
      case DIV:		oper = FPDIVL;
			fp_op = FP_DIV;
			opstrg = "DIV";
			operation = 3;
			break;
      case ASG MUL:
      case MUL:		oper = FPMULL;
			fp_op = FP_MUL;
			opstrg = "MUL";
			operation = 4;
			break;
      case ASG MINUS:
      case MINUS:	oper = FPSUBL;
			fp_op = FP_SUB;
			opstrg = "SUB";
			operation = 5;
			break;
      case ASG PLUS:
      case PLUS:	oper = FPADDL;
			fp_op = FP_ADD;
			opstrg = "ADD";
			operation = 6;
			break;
      }
 
   lreg = regfld(l);
   rreg = FBINOP ? regfld(r) : -1;
 
   if( l->in.op != REG || (FBINOP && (r->in.op != REG)) )
      cerror("bad float operands");
 
   pushtreg( R15, lreg, rreg );
   pushtreg( R5, lreg, rreg );
   pushtreg( R4, lreg, rreg );
   pushtreg( R3, lreg, rreg );
   pushtreg( R2, lreg, rreg );
   pushtreg( R0, lreg, rreg );

if (no_RTFL == 0) {				/* new RTFL UIF format */
    if ((lreg == R0) || (lreg == R15)) {	/* RTFL will clobber r0,r15 */
	tmp = R2;				/* subsitute lreg by r2 */
	if (FBINOP && (rreg == tmp)) tmp = R3;	/* if conflit, use r3 instead */
	rmove( tmp, lreg );
	lreg = tmp;
    }
    if ( FBINOP && ((rreg == R0) || (rreg == R15)) ) {
	tmp = R2;
	if (lreg == tmp) tmp = R3;
	rmove( tmp, rreg );
	rreg = tmp;
    }
    block_label = get_old_block(operation,lreg,rreg,lt,rt);
						/* try to re-use old block */
    if (block_label == 0) {			/* need a new RTFL block */
	block_label = add_new_block(operation,lreg,rreg,lt,rt);
	scratchg = 0xbc01;			/* r0,2,3,4,5,15 */
	S_clrbit(scratchg,lreg);		/* at least 1 reg opnd */
	numopnds = 2;
	if (FCMPOP)
		S_clrbit(scratchg,rreg);	/* 1 more reg for cmp */
	else {
		S_clrbit(scratchg,R2);		/* result = r2//r3 = double */
		S_clrbit(scratchg,R3);
		if (FBINOP) {
		    numopnds += 1;
		    S_clrbit(scratchg,rreg);
		}
	}
	printf("\t.data\n\t.align\t2\n");
	printf("L%d:\t\t\t# RTFL %.3d %s ",block_label,++RTFL_block_count,opstrg);
	if (!(FCMPOP)) printf("D:r2//r3,");
	if (lt == 2)
		printf("D:0(r%d)",lreg);
	else if (lt == 1)
		printf("S:r%d",lreg);
	else
		printf("I:r%d",lreg);
	if (FBINOP) {
		if (rt == 2)
			printf(",D:0(r%d)",rreg);
		else if (rt == 1)
			printf(",S:r%d",rreg);
		else
			printf(",I:r%d",rreg);
	}
	printf("\n");
	printf("\t.short\t0x60f0\t# cas r0,r15,r0\n");
	printf("\t.long\tFPGLUE\n");
	printf("\t.byte\t0x%.2x\t# opcode = %s\n",fp_op,opstrg);
	printf("\t.byte\t%d\t# numopnds\n",numopnds);
	printf("\t.short\t0x%.4x\t# scratchg\n",scratchg);
	printf("\t.byte\t%d\t# mysize\n",uif_size);
	printf("\t.byte\t0xc0\t# scratchf = fr0,fr1\n");
	current_size = 12;
	if (!(FCMPOP)) {
		printf("\t.byte\t0x%.2x\t# greg double\n",(GREGTYPE | DBLETYPE));
		printf("\t.byte\t0x23\t# dst = r2//r3\n");
		current_size += 2;
	}
	printf("\t.byte\t0x%.2x\t# lreg type\n",OPTYPE(lt));
	printf("\t.byte\t%d\t# lreg num\n",lreg);
	current_size += 2;
	if (FBINOP) {
		printf("\t.byte\t0x%.2x\t# rreg type\n",OPTYPE(rt));
		printf("\t.byte\t%d\t# rreg num\n",rreg);
		current_size += 2;
	}
	printf("\t.fill\t%d,1,0\t# offsets=0, pad with 0\n",
			(uif_size - current_size));
    } /* end new RTFL block */

    printf("\t.text\n");
    printf("\tget\tr15,$L%d # genfloat %s\n",block_label,opstrg);
    printf("\tbalr\tr15,r15\t# L%d %s\n",block_label,opstrg);

    if (FCMPOP) {
	if (c == 'S') {			/* special case -- FORARG */
	    printf("\tmfs\t%s,%s\t# genfloat FCMPOP\n",rnames[R15],rnames[R2]);
	    sa_reg(R2);
	} else
	    poptregs( R3, R15);
    } else { /* not a cmp */
	if (c == 'S')			/* special case -- FORARG */
	    sa_r2r3();
	else {
	    printf("\tput\t%s,",rnames[R2]);
	    adrput(getlr(p,'1'));
	    printf("\t# genfloat dbl\n");		/* store hi half */

	    printf("\tput\t%s,4+",rnames[R3]);
	    adrput(getlr(p,'1'));
	    printf("\t# genfloat dbl\n");		/* store lo half */
	    p->in.type = DOUBLE; /* these operations always return a double */
	}
	poptregs( R3, R15);
    } /* end not a cmp */
} else {					/* old floating point format */
   if ( FBINOP )
      if ((lreg == R2) || (lreg == R3) || (lreg == R15) ||
          (rreg == R2) || (rreg == R3) || (rreg == R15))
      {
         regdance( lreg, R4, rreg, R5, 0 );
         lreg = R4;
         rreg = R5;
      }
      else;
   else if ((lreg == R2) || (lreg == R3) || (lreg == R15)) {
      rmove( R4, lreg );
      lreg = R4;
   }

   /* set up for all operations */
   if (( FBINOP )&&( rt != 2 )&&( lt == 2 )) { /* conv rt arg, but not lt */
      /* store and convert right arg */
      rmove( R2, rreg );
      if ( rt == 0 )
         printf("\t\tget\t%s,$0x%x\t# genf(LAR), CWL fr%d fr%d\n", 
			rnames[R3], FPCWL+(frreg<<6)+(frreg<<2), frreg, frreg);
      else
         printf("\t\tget\t%s,$0x%x\t# genf(LAR), CSIL fr%d fr%d\n", 
			rnames[R3], FPCSIL+(frreg<<6)+(frreg<<2), frreg, frreg);
      FPSTORE;

      /* store lo half of left arg */
      printf("\t\tget\t%s,4(%s)\t# genf(LAR)\n", rnames[R2], rnames[lreg]);
      printf("\t\tget\t%s,$0x%x\t# genf(LAR), WTFR fr%d\n", 
			rnames[R3], FPWTFR+((flreg+1)<<2), flreg+1);
      FPSTORE;

      /* set up immed binary operation, hi half of left arg is imm value */
      printf("\t\tget\t%s,0(%s)\t# genf(LAR)\n", rnames[R2], rnames[lreg]);
      opaddr = oper | FPIMM2 | (frreg << 6) | (flreg << 2);
      opimm = 2;
      }
   else { /* either types are same, or lt is double and rt needs conversion */
      if ( lt != 2 ) {
         /* store and convert left arg */
	 rmove( R2, lreg );
	 if ( lt == 0 )
            printf("\t\tget\t%s,$0x%x\t# genf(LAR), CWL fr%d fr%d\n", 
			rnames[R3], FPCWL+(flreg<<6)+(flreg<<2), flreg, flreg);
	 else
            printf("\t\tget\t%s,$0x%x\t# genf(LAR), CSIL fr%d fr%d\n", 
			rnames[R3], FPCSIL+(flreg<<6)+(flreg<<2), flreg, flreg);
         FPSTORE;
         }
      else {
         /* store hi half of left arg */
         printf("\t\tget\t%s,0(%s)\t# genf(LAR)\n", rnames[R2], rnames[lreg]);
         printf("\t\tget\t%s,$0x%x\t# genf(LAR), WTFR fr%d\n", 
			rnames[R3], FPWTFR+(flreg<<2), flreg);
         FPSTORE;

         /* store lo half of left arg */
         printf("\t\tget\t%s,4(%s)\t# genf(LAR)\n", rnames[R2], rnames[lreg]);
         printf("\t\tais\t%s,0x4\t\t# genf(LAR), WTFR fr%d\n",rnames[R3], flreg+1);
         FPSTORE;
      }
      if ( FBINOP ) {
	 if ( rt != 2 ) {
            /* store and convert right arg */
	    rmove( R2, rreg );
	    if ( rt == 0 )
               printf("\t\tget\t%s,$0x%x\t# genf(LAR), CWL fr%d fr%d\n",
			rnames[R3], FPCWL+(frreg<<6)+(frreg<<2), frreg, frreg);
	    else
               printf("\t\tget\t%s,$0x%x\t# genf(LAR), CSIL fr%d fr%d\n", 
			rnames[R3], FPCSIL+(frreg<<6)+(frreg<<2), frreg, frreg);
            FPSTORE;

            /* set up binary operation, NOT immediate  */
	    opaddr = oper | (frreg << 6) | (flreg << 2);
	 }
	 else {
	    /* store lo half of right arg */
            printf("\t\tget\t%s,4(%s)\t# genf(LAR)\n", rnames[R2], rnames[rreg]);
            printf("\t\tget\t%s,$0x%x\t# genf(LAR), WTFR fr%d\n", 
			rnames[R3], FPWTFR+((frreg+1)<<2), frreg+1);
            FPSTORE;

            /* set up imm binary operation, hi half of rgt arg is imm value */
            printf("\t\tget\t%s,0(%s)\t# genf(LAR)\n", rnames[R2], rnames[rreg]);
            opaddr = oper | FPIMM1 | (frreg << 6) | (flreg << 2);
	    opimm = 1;
	 }
      }
      else /* UNARY operation, arg is already in flreg */
	 {
	 opaddr = oper | (flreg << 6) | (flreg << 2);
	 }
   }

   /* perform oper operation */
   printf("\t\tget\t%s,$0x%x\t# genf(LAR), %s%c%c%c fr%d fr%d\n", 
		rnames[R3], opaddr, 
		opstrg, (opimm==1)?'I':'\0',opprec,(opimm==2)?'I':'\0',
		FBINOP?frreg:flreg, flreg);
   FPSTORE;

   if ( FCMPOP )
   {
      printf("\t\tget\t%s,$0x%x\t# genf(LAR), RDSTR\n", rnames[R3], FPRDSTR);
      FPLOAD;

   /* (LAR) Note that the floating compare operation compares frreg vs. flreg,
    * so the logic here is reversed:
    */
      printf("\t\tnilz\t%s,%s,%d\t# genf(LAR), (fr%d > fr%d)?\n", 
		rnames[R2], rnames[R2],STATMASK, frreg, flreg);
      printf("\t\tjne\t1f\t# genf(LAR)\n");
      printf("\t\tget\t%s,$0x%x\t# genf(LAR), fr%d > fr%d\n", 
		rnames[R2], FPGT, frreg, flreg);
      printf("\t\tj\t4f\t# genf(LAR)\n");
      printf("1:\n");
      printf("\t\tci\t%s,%d\t# genf(LAR), (fr%d == fr%d)?\n", 
		rnames[R2], STATEQ, frreg, flreg);
      printf("\t\tjne\t2f\t# genf(LAR)\n");
      printf("\t\tget\t%s,$0x%x\t# genf(LAR), fr%d == fr%d\n", 
		rnames[R2], FPEQ, frreg, flreg);
      printf("\t\tj\t4f\t# genf(LAR)\n");
      printf("2:\n");
      printf("\t\tci\t%s,%d\t# genf(LAR), (fr%d < fr%d)?\n", 
		rnames[R2], STATGT, frreg, flreg);
      printf("\t\tjne\t3f\t# genf(LAR)\n");
      printf("\t\tget\t%s,$0x%x\t# genf(LAR), fr%d < fr%d\n", 
		rnames[R2], FPLT, frreg, flreg);
      printf("\t\tj\t4f\t# genf(LAR)\n");
      printf("3:\n");
      printf("\t\tlis\t%s,%d\t# genf(LAR), fr%d ? fr%d\n", 
		rnames[R2], 0, frreg, flreg);
      printf("4:\n");

      if (c == 'S')  /* special case -- FORARG */
	 sa_reg( R2 );
      else
      {
	 poptregs( R3, R15);
      	 printf("\t\tmts\t%s,%s\t# genf(LAR) FCMPOP\n", rnames[R15], rnames[R2]);
      }
   }
   else 
   {
      /* get hi half of result */
      printf("\t\tget\t%s,$0x%x\t# genf(LAR), RDFR fr%d\n", 
		rnames[R3], FPRDFR, flreg);
      FPLOAD;

      if (c == 'S')  /* special case -- FORARG */
	 rmove( R5, R2 );		/* save value in r5 */
      else
      {
      	 printf("\t\tput\t%s,",rnames[R2]);
	 adrput(getlr(p,'1'));
	 printf("\t# genf dbl\n");
      }

      /* get lo half of result */
      printf("\t\tai\t%s,%s,0x40\t# genf(LAR), RDFR fr%d\n",
		rnames[R3], rnames[R3], flreg+1);
      FPLOAD;
      if (c == 'S')  /* special case -- FORARG */
      {
	 rmove( R3, R2 );
	 rmove( R2, R5 );
	 sa_r2r3();
      }
      else
      {
      	 printf("\t\tput\t%s,4+",rnames[R2]);
	 adrput(getlr(p,'1'));
	 printf("\t# genf dbl\n");
         p->in.type = DOUBLE; /* these operations always return a double */
      }
      poptregs( R3, R15);
   }
/***** LAR. *****/
} /* end old floating point format */

   poptregs (R0,R3);

printf("\t# Exit genfloat\n\n");

}
 
cvtfloat( p, c ) register NODE *p; { /* added 7/84 by JEC */
   register NODE *l = getlr(p,'L'); /* same as p for leaves */
   register NODE *r = getlr(p,'R'); /* same as p for leaves and unary nodes */
   register NODE *inp, *out;
   int lt, rt, it=0, ot=0, ireg, oreg, oshare;
 
   /* assume -1 is NOT a valid label number */
   static int fromint[] = {
     0,		/* int to int        0 */
     -1,	/* int to float      1 */
     -1,	/* int to double     2 */
   };
   static int fromflt[] = {
     -1,	/* float to int      0 */
     0,		/* float to float    1 */
     -1,	/* float to double   2 */
   };
   static int fromdbl[] = {
     -1,	/* double to int     0 */
     -1,	/* double to float   1 */
     0,		/* double to double  2 */
   };
 
   static int *uif_block[] = { fromint, fromflt, fromdbl };

  
 
printf("\n\t# Enter cvtfloat\n");

   lt = CVTTYPE(l);
   rt = CVTTYPE(r);
 
   switch( p->in.op ){
       case ASSIGN:
           inp = r;
           it = rt;
           out = l;
           ot = lt;
           oshare = -1;
           if( ot == 2 && regof(out) == R2 ){
               c = '?';  /* flag special case */
               oshare = R2;
           }
           break;
       case SCONV:
           inp = l;
           it = lt;
           out = getlr( p, c );
           ot = rt;
           oshare = regof(out);
           break;
       case REG:  /* special case of float FORARG */
           inp = r;
           it = rt;
           out = getlr( p, '1' );
           ot = 2;  /* double */
           oshare = -1; /* WRONG! */
           break;
   }
   if( (uif_block[it] [ot]) == 0 || inp->in.op != REG ){
       printf("\t\tit=%d, ot=%d, inp=%o\n", it, ot, inp );
       cerror("floating point conversion");
   }
   ireg = regof(inp);
   oreg = regof(out);

   pushtreg( R15, ireg, oshare );
   pushtreg( R5, ireg, oshare );
   pushtreg( R4, ireg, oshare );
   pushtreg( R3, ireg, oshare );
   pushtreg( R2, ireg, oshare );
   pushtreg( R0, ireg, oshare );
 
   if (it == 2) {
       if ( c == '?' )  /* special case (see above) */
           expand( out, FOREFF, " cal r4,AP # ecvt ?\n" );
 
       if ( ireg != R4 )
           rmove( R4, ireg );
       
       if ( ot == 0 ) {				/* cvt double to int */
	if (no_RTFL == 0) { /* src = 0(r4), dst = r2, free = r0,3,5,15 */
	    if (uif_block[it][ot] == -1) {	/* first encounter */
		uif_block[it][ot] = getlab();	/* get a label */
		printf("\t.data\n\t.align\t2\n");
		printf("L%d:\t\t\t# RTFL %.3d cvt d2i MOV I:r2,D:0(r4)\n",
				uif_block[it][ot],++RTFL_block_count);
		printf("\t.short\t0x60f0\t# cas r0,r15,r0\n");
		printf("\t.long\tFPGLUE\n");
		printf("\t.byte\t0x%.2x\t# opcode = move\n",FP_MOVE);
		printf("\t.byte\t2\t# numopnds\n");
		printf("\t.short\t0x9401\t# scratchg = r0,r3,r5,r15\n");
		printf("\t.byte\t%d\t# mysize\n",MAX_UIF_SIZE);
		printf("\t.byte\t0xc0\t# scratchf = fr0,fr1\n");
		printf("\t.byte\t0x%.2x\t# greg int\n",(GREGTYPE | INTTYPE));
		printf("\t.byte\t2\t# dst = r2\n");
		printf("\t.byte\t0x%.2x\t# addr of double\n",
			(ADDRTYPE | DBLETYPE));
		printf("\t.byte\t4\t# src = r4\n");
		printf("\t.long\t0\t# offset = 0\n");
		printf("\t.fill\t%d,1,0\t# pad with 0\n",(MAX_UIF_SIZE - 20));
		printf("\t.text\n");
	    } /* end first encounter, no else */
	    printf("\tget\tr15,$L%d # cvtfloat d2i\n",uif_block[it][ot]);
	    printf("\tbalr\tr15,r15\t# L%d MOV d2i\n",uif_block[it][ot]);
	} else {
           printf("\t\tget\t%s,0(%s)\t# cvtf(LAR) -dtoi\n",
			rnames[R2],rnames[R4]);
	   printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), WTFR fr0\n",
			rnames[R3], FPWTFR);
	   FPSTORE;

           printf("\t\tget\t%s,4(%s)\t# cvtf(LAR) -dtoi\n",
			rnames[R2],rnames[R4]);
	   printf("\t\tais\t%s,0x4\t\t# cvtf(LAR), WTFR fr1\n", rnames[R3]);
	   FPSTORE;

	   printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), TLW fr0,1 -> fr0\n", 
			rnames[R3], FPTLW);
	   FPSTORE;

	   printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), RDFR fr0\n",
			rnames[R3], FPRDFR);
	   FPLOAD;
	}
       } else { /* ot == 1 */			/* cvt double to float */
	if (no_RTFL == 0) { /* src = 0(r4), dst = r2, free = r0,3,5,15 */
	    if (uif_block[it][ot] == -1) {	/* first encounter */
		uif_block[it][ot] = getlab();	/* get a label */
		printf("\t.data\n\t.align\t2\n");
		printf("L%d:\t\t\t# RTFL %.3d cvt d2f MOV F:r2,D:0(r4)\n",
				uif_block[it][ot],++RTFL_block_count);
		printf("\t.short\t0x60f0\t# cas r0,r15,r0\n");
		printf("\t.long\tFPGLUE\n");
		printf("\t.byte\t0x%.2x\t# opcode = move\n",FP_MOVE);
		printf("\t.byte\t2\t# numopnds\n");
		printf("\t.short\t0x9401\t# scratchg = r0,r3,r5,r15\n");
		printf("\t.byte\t%d\t# mysize\n",MAX_UIF_SIZE);
		printf("\t.byte\t0xc0\t# scratchf = fr0,fr1\n");
		printf("\t.byte\t0x%.2x\t# greg float\n",(GREGTYPE | SGLETYPE));
		printf("\t.byte\t2\t# dst = r2\n");
		printf("\t.byte\t0x%.2x\t# addr of double\n",
			(ADDRTYPE | DBLETYPE));
		printf("\t.byte\t4\t# src = r4\n");
		printf("\t.long\t0\t# offset = 0\n");
		printf("\t.fill\t%d,1,0\t# pad with 0\n",(MAX_UIF_SIZE - 20));
		printf("\t.text\n");
	    } /* end first encounter, no else */
	    printf("\tget\tr15,$L%d # cvtfloat d2f\n",uif_block[it][ot]);
	    printf("\tbalr\tr15,r15\t# L%d MOV d2f\n",uif_block[it][ot]);
	} else {
           printf("\t\tget\t%s,4(%s)\t# cvtf(LAR) -dtof\n",
			rnames[R2],rnames[R4]);
	   printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), WTFR fr1\n", 
			rnames[R3],FPWTFR+0x4);
	   FPSTORE;
	   
           printf("\t\tget\t%s,0(%s)\t# cvtf(LAR) -dtof\n",
			rnames[R2],rnames[R4]);
	   printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), CLIS fr0,1 -> fr0\n", 
			rnames[R3],FPCLIS);
	   FPSTORE;

	   printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), RDFR fr0\n",
			rnames[R3], FPRDFR);
	   FPLOAD;
	}
       }
   } else if ( it == 1 ) {
       if ( c == '?' )  /* special case (see above) */
           expand( out, FOREFF, " cal r2,AP # ecvt ?\n" );
 
       if ( ireg != R2 )
           rmove( R2, ireg );

       if ( ot == 0 ) {				/* cvt float to int */
	if (no_RTFL == 0) { /* src = r2, dst = r2, free = r0,3,4,5,15 */
	    if (uif_block[it][ot] == -1) {	/* first encounter */
		uif_block[it][ot] = getlab();	/* get a label */
		printf("\t.data\n\t.align\t2\n");
		printf("L%d:\t\t\t# RTFL %.3d cvt f2i MOV I:r2,F:r2\n",
				uif_block[it][ot],++RTFL_block_count);
		printf("\t.short\t0x60f0\t# cas r0,r15,r0\n");
		printf("\t.long\tFPGLUE\n");
		printf("\t.byte\t0x%.2x\t# opcode = move\n",FP_MOVE);
		printf("\t.byte\t2\t# numopnds\n");
	        printf("\t.short\t0x9c01\t# scratchg = r0,r3,r4,r5,r15\n");
		printf("\t.byte\t%d\t# mysize\n",MAX_UIF_SIZE);
		printf("\t.byte\t0xc0\t# scratchf = fr0,fr1\n");
	        printf("\t.byte\t0x%.2x\t# greg int\n",(GREGTYPE | INTTYPE));
		printf("\t.byte\t2\t# dst = r2\n");
	        printf("\t.byte\t0x%.2x\t# greg float\n",(GREGTYPE | SGLETYPE));
	        printf("\t.byte\t2\t# src = r2\n");
		printf("\t.fill\t%d,1,0\t# pad with 0\n",(MAX_UIF_SIZE - 16));
		printf("\t.text\n");
	    } /* end first encounter, no else */
	    printf("\tget\tr15,$L%d # cvtfloat f2i\n",uif_block[it][ot]);
	    printf("\tbalr\tr15,r15\t# L%d MOV f2i\n",uif_block[it][ot]);
	} else {
	   printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), WTFR fr0\n",
			rnames[R3], FPWTFR);
	   FPSTORE;

	   printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), TSW fr0 -> fr0\n", 
			rnames[R3], FPTSW);
	   FPSTORE;

	   printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), RDFR fr0\n",
			rnames[R3], FPRDFR);
	   FPLOAD;
	}
       } else { /* ot == 2 */			/* cvt float to double */
	if (no_RTFL == 0) { /* src = r2, dst = r2//r3, free = r0,4,5,15 */
	    if (uif_block[it][ot] == -1) {	/* first encounter */
		uif_block[it][ot] = getlab();	/* get a label */
		printf("\t.data\n\t.align\t2\n");
		printf("L%d:\t\t\t# RTFL %.3d cvt f2d MOV D:r2//r3,F:r2\n",
				uif_block[it][ot],++RTFL_block_count);
		printf("\t.short\t0x60f0\t# cas r0,r15,r0\n");
		printf("\t.long\tFPGLUE\n");
		printf("\t.byte\t0x%.2x\t# opcode = move\n",FP_MOVE);
		printf("\t.byte\t2\t# numopnds\n");
	        printf("\t.short\t0x8c01\t# scratchg = r0,r4,r5,r15\n");
		printf("\t.byte\t%d\t# mysize\n",MAX_UIF_SIZE);
		printf("\t.byte\t0xc0\t# scratchf = fr0,fr1\n");
	        printf("\t.byte\t0x%.2x\t# greg double\n",(GREGTYPE | DBLETYPE));
	        printf("\t.byte\t0x23\t# dst = r2//r3\n");
	        printf("\t.byte\t0x%.2x\t# greg float\n",(GREGTYPE | SGLETYPE));
	        printf("\t.byte\t2\t# src = r2\n");
		printf("\t.fill\t%d,1,0\t# pad with 0\n",(MAX_UIF_SIZE - 16));
		printf("\t.text\n");
	    } /* end first encounter, no else */
	    printf("\tget\tr15,$L%d # cvtfloat f2d\n",uif_block[it][ot]);
	    printf("\tbalr\tr15,r15\t# L%d MOV f2d\n",uif_block[it][ot]);
	} else {
	   printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), CSIL fr0 -> fr0,1\n", 
			rnames[R3], FPCSIL);
	   FPSTORE;
	   
	   printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), RDFR fr0\n",
			rnames[R3], FPRDFR);
	   FPLOAD;

	   rmove( R4, R2 );

	   printf("\t\tai\t%s,0x40\t\t# cvtf(LAR), RDFR fr1\n", rnames[R3]);
	   FPLOAD;

	   rmove( R3, R2 );
	   rmove( R2, R4 );		/* double value now in r2,r3 */
	}
       }
   } else { /* it == 0 */
       if ( c == '?' )  /* special case (see above) */
           expand( out, FOREFF, " cal r2,AP # ecvt ?\n" );
 
       if ( ireg != R2 )
           rmove( R2, ireg );

       if ( ot == 2 ) {				/* cvt int to double */
	if (no_RTFL == 0) { /* src = r2, dst = r2//r3, free = r0,4,5,15 */
	    if (uif_block[it][ot] == -1) {	/* first encounter */
		uif_block[it][ot] = getlab();	/* get a label */
		printf("\t.data\n\t.align\t2\n");
		printf("L%d:\t\t\t# RTFL %.3d cvt i2d MOV D:r2//r3,I:r2\n",
				uif_block[it][ot],++RTFL_block_count);
		printf("\t.short\t0x60f0\t# cas r0,r15,r0\n");
		printf("\t.long\tFPGLUE\n");
		printf("\t.byte\t0x%.2x\t# opcode = move\n",FP_MOVE);
		printf("\t.byte\t2\t# numopnds\n");
	        printf("\t.short\t0x8c01\t# scratchg = r0,r4,r5,r15\n");
		printf("\t.byte\t%d\t# mysize\n",MAX_UIF_SIZE);
		printf("\t.byte\t0xc0\t# scratchf = fr0,fr1\n");
	        printf("\t.byte\t0x%.2x\t# greg double\n",(GREGTYPE | DBLETYPE));
	        printf("\t.byte\t0x23\t# dst = r2//r3\n");
	        printf("\t.byte\t0x%.2x\t# greg int\n",(GREGTYPE | INTTYPE));
	        printf("\t.byte\t2\t# src = r2\n");
		printf("\t.fill\t%d,1,0\t# pad with 0\n",(MAX_UIF_SIZE - 16));
		printf("\t.text\n");
	    } /* end first encounter, no else */
	    printf("\tget\tr15,$L%d # cvtfloat i2d\n",uif_block[it][ot]);
	    printf("\tbalr\tr15,r15\t# L%d MOV i2d\n",uif_block[it][ot]);
	} else {
           printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), CWL fr0 -> fr0,1\n", 
			rnames[R3], FPCWL);
           FPSTORE;
 
           printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), RDFR fr0\n",
			rnames[R3], FPRDFR);
           FPLOAD;

	   rmove( R4, R2 );

	   printf("\t\tai\t%s,0x40\t\t# cvtf(LAR), RDFR fr1\n", rnames[R3]);
	   FPLOAD;

	   rmove( R3, R2 );
	   rmove( R2, R4 );		/* double value now in r2,r3 */
	}
       } else { /* ot == 1 */			/* cvt int to float */
	if (no_RTFL == 0) { /* src = r2, dst = r2, free = r0,3,4,5,15 */
	    if (uif_block[it][ot] == -1) {	/* first encounter */
		uif_block[it][ot] = getlab();	/* get a label */
		printf("\t.data\n\t.align\t2\n");
		printf("L%d:\t\t\t# RTFL %.3d cvt i2f MOV F:r2,I:r2\n",
				uif_block[it][ot],++RTFL_block_count);
		printf("\t.short\t0x60f0\t# cas r0,r15,r0\n");
		printf("\t.long\tFPGLUE\n");
		printf("\t.byte\t0x%.2x\t# opcode = move\n",FP_MOVE);
		printf("\t.byte\t2\t# numopnds\n");
	        printf("\t.short\t0x9c01\t# scratchg = r0,r3,r4,r5,r15\n");
		printf("\t.byte\t%d\t# mysize\n",MAX_UIF_SIZE);
		printf("\t.byte\t0xc0\t# scratchf = fr0,fr1\n");
	        printf("\t.byte\t0x%.2x\t# greg float\n",(GREGTYPE | SGLETYPE));
	        printf("\t.byte\t2\t# dst = r2\n");
	        printf("\t.byte\t0x%.2x\t# greg int\n",(GREGTYPE | INTTYPE));
	        printf("\t.byte\t2\t# src = r2\n");
		printf("\t.fill\t%d,1,0\t# pad with 0\n",(MAX_UIF_SIZE - 16));
		printf("\t.text\n");
	    } /* end first encounter, no else */
	    printf("\tget\tr15,$L%d # cvtfloat i2f\n",uif_block[it][ot]);
	    printf("\tbalr\tr15,r15\t# L%d MOV i2f\n",uif_block[it][ot]);
	} else {
           printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), CWS fr0 -> fr0\n", 
			rnames[R3], FPCWS);
           FPSTORE;

           printf("\t\tget\t%s,$0x%x\t# cvtf(LAR), RDFR fr0\n",
			rnames[R3], FPRDFR);
           FPLOAD;
	}
       }
   }

	   
   poptregs(R4,DP);
   if ( c != '?' ) {
        if( ot == 2 ){  /* output type == TDOUBLE */
            if ( c == 'S' ) {
	       poptregs(R15,R15);
	       sa_r2r3();
            } else {
	       if ( tshape(out, REG) ) {
	          poptregs(R15,R15);
	          expand(out, FOREFF,
	           " put r2,A2 # ecvt dbl reg\n put r3,4+A2 # ecvt dbl reg\n");
                  expand(out, FOREFF,
		   " cal r2,A2 # ecvt dbl reg\n");
               } else {
		  if (out->tn.op==NAME && *out->tn.name && 
	             (strncmp(out->tn.name,"LCOM",4)==0||*out->in.name=='_')){
		     expand(out, FOREFF,
		     " get r15,$AP\n put r2,0(r15)\n get r15,$4+AP\n put r3,0(r15) # ecvt dbl\n");
		     poptregs(R15,R15);
		  } else {
		     poptregs(R15,R15);
		     expand(out, FOREFF,
	                   " put r2,AP # ecvt dbl\n put r3,4+AP # ecvt dbl\n");
                  }
	       } 
	    }
	} else {
	   if( out->in.op == REG ) {
                 if( oreg != R2 ) {
                     rmove( oreg, R2 );
                 } 
		 poptregs(R15,R15);
	   } else {
	      if ( out->in.op == OREG && oreg == R2 ) {
	         printf("\t\tget\tr15,L%d-%d(r13)\t# ecvt\n",parmlbl,(16-oreg)*4);
	         printf("\t\tput\tr2,0(r15)\t# ecvt\n" );
	         poptregs(R15,R15);
	      } else {
	         if( tshape(out, STARNM) ) {
                     expand( out, FOREFF, 
                             " get r15,$AP # ecvt\n put r2,0(r15) # ecvt\n" );
	             poptregs(R15,R15);
                 } else {
       	             poptregs(R15,R15);
                     expand( out, FOREFF, " put r2,AP # ecvt\n" );
	         }
	      }
	   }
       }
   } else {
       poptregs(R15,R15);
   }
   poptregs (R0,R3);

printf("\t# Exit cvtfloat\n\n");

}
/* LOCALTMP.C ENDS here ------------------------------------------------*/
 
   static
pushtreg( reg, lshare, rshare ) register reg; register lshare, rshare; {
#ifndef FORT
extern int reg_push;
#endif 
   /* modified for CSL to use REG_SAVE area in the stack frame WFA 7/20/85 */
 
   if (xdebug) 
       printf("pushtreg(%d,%d,%d)\n",reg,lshare,rshare);
   if ( pushlist[reg] ) { 
       if (xdebug) printf("pushtreg: already pushed\n");
       return;
   }
   if( pushlist[reg] = reginuse( reg, lshare, rshare ))  {
       extern int reg_save;
/* (ef) 12/19/85 -- registers above reg_save are saved on entry, so we */
/*      cannot clobber their space in the register save area. We need  */
/* to allocate a temp for them.  We'll store the offset of the temp in */
/* the pushlist.   Temp offsets are from the frame pointer, which is   */
/* always 64 bytes below the top of the temp area, so the largest      */
/* possible offset is 60.   It is possible that we'll be given offset  */
/* 0, in which case pushlist[reg] would be null, and would not get     */
/* popped.  To circumvent this, we'll set pushlist to be 64-tmp (which */
/* is guaranteed to be non-zero.                                       */
       if ( reg > R5 ) { int tmp= freetemp(1)/SZCHAR;
	  printf( " put %s,%d(r13) # pushtreg temp\n",rnames[reg],tmp);
	  pushlist[reg]= 64-tmp;
       }
       else 
	  printf( " put %s,L%d-%d(r13) # pushtreg\n", rnames[reg],parmlbl,
								(16-reg)*4);
      if (reg<reg_push) reg_push= reg;
      /* (ef) 1/5/86 (early am) -- hmmm. I think this makes sense, >r5 */
      /*             needs to be stm'ed on entry.                      */
      if ((reg>R5)&&(reg<reg_save)) reg_save= reg;
   }
   else if (xdebug) 
       printf("pushtreg: reginuse==0\n");

   }
 
   static
poptregs(low,high ) register low,high; {
   register reg;
 
   TREGLOOP( reg ) {  extern int reg_save;
       if ((reg<low) || (reg>high)) continue;
       if (xdebug)
          printf("poptregs: checking %d\n",reg);
       if( pushlist[reg] ) {
/* (ef) 12/19/85 -- see comments in pushtreg above */
           if ( reg>=reg_save ) 
	       printf(" get %s,%d(r13) # poptregs temp\n",rnames[reg],
       							64-pushlist[reg]);
	   else
	       printf( " get %s,L%d-%d(r13) # poptregs\n", rnames[reg],
	       				                 parmlbl,(16-reg)*4);
	   pushlist[reg] = 0;
       }
   }
}
 
/* (ef) 11/16/85 -- number of the highest arg register needed */
int  areg_needed=0;
/* (ef) 11/28/85 -- number of the lowest arg register used */
int  areg_used=0;

   static
reginuse( reg, lshare, rshare )
   register reg, lshare, rshare;
{
   register i, t, tempregs = template->needs;
 
   if( busy[reg] > 1 || (busy[reg] == 1 && lshare != reg && rshare != reg ) )
      return(1);
/* (ef) 11/28/85 Lay off of my argument registers */
   if ( areg_used && reg>=R2 && reg<=R5 && reg>=areg_used ) 
      return(1);
   for( i=0; tempregs & NACOUNT; ++i, tempregs -= NAREG )
      if( resc[i].in.op == REG ){
         t = resc[i].tn.rval;
         if( reg == t && lshare != t && rshare != t )
            return(1);
      }
   return(0);
}
 
   static
regdance( s1, t1, s2, t2, commute )
   register s1,  /* source register for 1st operand */
            t1,  /* target register for 1st operand */
            s2,  /* source register for 2nd operand */
            t2;  /* target register for 2nd operand */
{
   register exchange = 0;  /* operands exchanged */
 
   switch( (s1==t1)<<3 | (s1==t2)<<2 | (s2==t2)<<1 | (s2==t1) ){
      case 0x1: if( commute ){
                   rmove( t2, s1 );
                   exchange = 1;
                   break;
                   }
      case 0x0: rmove( t2, s2 );
      case 0x2: rmove( t1, s1 );
                break;
      case 0x4: if( commute){
                   rmove( t1, s2 );
                   exchange = 1;
                   break;
                   }
                else rmove( t1, s1 );
      case 0x8: rmove( t2, s2 );
      case 0xA: break;
 
      case 0x5: if( commute )
                   exchange = 1;
                else
                   rswap( t1, t2 );
                break;
      default:  cerror("regdance");
      }
      return( exchange );
   }
 
convtype( p, c ) register NODE *p; {  /* added 1/13/84 by JEC */
   if( odebug>3 ) printf("convtype( %o, %c )\n", p, c );
 
   switch( c ){
      case 'D': p->in.type = DOUBLE;
      }
   }
 
   static
rswap( r1, r2 ) register r1, r2; {
   printf( " x %s,%s # rswap\n", rnames[r1], rnames[r2] );
   printf( " x %s,%s # rswap\n", rnames[r2], rnames[r1] );
   printf( " x %s,%s # rswap\n", rnames[r1], rnames[r2] );
   }
 
rmove( rt, rs ) register rt, rs; {
   if( rt != rs)
/*    printf( " mr %s,%s # rmove\n", rnames[rt], rnames[rs] ); */
      printf( " cas %s,%s,r0 # rmove\n", rnames[rt], rnames[rs] );
   }
 
setregs(){ /* set up temporary registers */
   fregs = 6;  /* tbl- 6 free regs on ibm032 (0-5) */
   }
 
szty(t) register t; { /* size, in registers, needed to hold thing of type t */
/* return( (t==DOUBLE||t==FLOAT) ? 2 : 1 );
*/ return( 1 );  /* modified 1/5/84 by JEC out of fear */
   }
 
rewfld( p ) register NODE *p; {
   return(1);
   }
 
callreg(p) register NODE *p; {
   return( R2 ); /* WFA 7/15/85 should this also include R3? */
   }
 
canaddr( p ) register NODE *p; {
   register o = p->in.op;
 
    return( o==REG || o==OREG || (o==NAME && *p->tn.name && *p->tn.name != '_' && strncmp( p->tn.name, "LCOM", 4 ) != 0 ) );
   }
 
shltype( o, p ) register NODE *p; {  /* shape of leaf type */
   return( o== REG || o == NAME || o == ICON || o == OREG );
   }
 
flshape( p ) register NODE *p; {  /* shape of field type */
   return( p->in.op == REG || p->in.op == NAME || p->in.op == ICON ||
      (p->in.op == OREG && tlen(p) == 1) );
   }
 
shtemp( p ) register NODE *p; {  /* shape of tmp type */
   if( p->in.op == STARG ) p = p->in.left;
   return( p->in.op==NAME || p->in.op ==ICON || p->in.op == OREG );
   }
 
adrcon( val ) register CONSZ val; {
   printf( CONFMT, val );
   }
 
conput( p ) register NODE *p; {
   switch( p->in.op ){
 
   case ICON:
         acon( p );
         return;
 
    case REG:
         printf( "%s", rnames[p->tn.rval] );
         return;
 
    default:
         cerror( "illegal conput" );
         }
    }
 
insput( p ) register NODE *p; {
   cerror( "insput" );
   }
 
upput( p ) register NODE *p; {
   if (p->in.op == ICON  &&  p->in.name[0] == '\0')
      printf( CONFMT, p->tn.lval >> SZLONG/2 );
   else cerror( "illegal upput" );
   }
 
loput( p ) register NODE *p; {
   if (p->in.op == ICON  &&  p->in.name[0] == '\0')
      printf( CONFMT, p->tn.lval & ((1 << SZLONG/2) - 1) );
   else cerror( "illegal loput" );
   }
 
ladcon( p ) register NODE *p; {
    static int uniqueno = 9999;
 
    printf(".A%d # address constant\n", ++uniqueno);
    printf(" .data\n .align 2\n");
    printf(".A%d: .long ", uniqueno);
    adrput( p );
    printf("\n .text");
    }
extern int extern_fn;	/* WFA 7/15/85 XXX external fn names use . prefix */ 
adrput( p ) register NODE *p; {
 
   /* output an address, with offsets, from p */
   if( p->in.op == FLD ){
      p = p->in.left;
      }
 
   switch( p->in.op ){
 
   case NAME:
      /* check for constant address name (eg *(int *)0x100) JEC */
      if( *p->tn.name ){
#ifdef FORT
	 acon( p );
#else 
#ifndef FLEXNAMES
         printf("%.8s", p->tn.name);
#else
         printf("%s", p->tn.name);
#endif
#endif FORT
         return;
      }
 
   case ICON:
      acon( p );
      return;
 
   case REG:
      printf( "%s", rnames[p->tn.rval] );
      return;
 
    case OREG:
      acon(p);
      printf("(%s)",rnames[p->tn.rval]);
      return;
 
    case UNARY MUL:
      cerror( "illegal address(UNARY MUL in adrput())" );
         return;
 
   default:
      cerror( "illegal address in adrput()" );
      return;
 
      }
   }
 
acon( p ) register NODE *p; { /* print out a constant */
   register plv = p->tn.lval;
 
   if( *p->tn.name == '\0' )
       printf( (plv<0 ? "0%ld" : CONFMT), plv );
   else if( plv == 0 )
       if( extern_fn )	/* WFA 7/15/85 */
#ifndef FLEXNAMES
           printf(".%.7s", &p->tn.name[1]);
#else
           printf(".%s", &p->tn.name[1]);
#endif
        else
#ifndef FLEXNAMES
           printf( "%.8s", p->tn.name );
#else
           printf( "%s", p->tn.name );
#endif
   else {
#ifndef FLEXNAMES
       printf( (plv<0 ? "%.8s" : "%.8s+"), p->tn.name );
#else
       printf( (plv<0 ? "%s" : "%s+"), p->tn.name );
#endif
       printf( CONFMT, plv );
       }
   }
 
int gc_numbytes;  /* tbl */
 
NODE *gsc_target;  /* added 1/3/83 by JEC for ASG STCALL */
extern int argreg;  /* WFA 7/11/85 added for CSL */
 
			/* structure valued call */
genscall( p, cookie ) register NODE *p; register cookie; {
   register NODE *l = p->in.left, *p2;
   register asgcall, argspace;
 
   if( edebug>2 ){
       printf("genscall( %o, %o ): %d\n", p, cookie, (l->in.op == CM) );
       fwalk(p,eprint,0);
       }
 
   argreg = R3;  /* WFA 7/11/85 added for CSL */
   argspace = evalargs( p, 1 );
 
   if( asgcall = (l->in.op == CM) ){ /* refer to setstr for CM creation */
       p->in.left = l->in.left;         /* prune CM subtree from lhs */
       if( p2 = p->in.right ){       /* add CM subtree to rhs for reclaimed */
           p->in.right = l;
           l->in.left = p2;
           p2 = l->in.right;
           }
       else {
           p2 = p->in.right = l->in.right;
           l->in.op = FREE;
           }
       }
 
   if( p->in.left->in.op != REG && p->in.left->in.op != ICON)
       order( p->in.left, INAREG );
 
   if( asgcall )
       p->in.op = ASG STCALL;
   else
       p->in.op = STCALL;
 
   if( edebug>3 ){
       printf("genscall calling match:\n");
       fwalk(p,eprint,0);
       }
 
   /* setup gsc_target so template reference to ZV works */
   gsc_target = p2;
 
   /* setup gc_numbytes so template reference to ZC works */
   gc_numbytes = argspace; /* XXX marxargoff reset here? */
 
   return( match( p, INTAREG|INTBREG ) != MDONE );
   }
 
				/* generate the call given by p */
gencall( p, cookie ) register NODE *p; register cookie; { 
   register argspace;
 
   argreg = R2;  /* WFA 7/11/85 added for CSL */
   argspace = evalargs( p, 0 );
 
   if( p->in.left->in.op != REG && p->in.left->in.op != ICON)
       order( p->in.left, INAREG );
 
#ifdef FLOAT_IS_FLOAT
   if( p->in.type == DOUBLE ){ /* added 1/6/84 by JEC   */
#else
   if ( (p->in.type == DOUBLE) || (p->in.type == FLOAT) ) { /* (ef) 1/13/86 */
       p->in.type= DOUBLE;
#endif FLOAT_IS_FLOAT
       p->in.left->in.type = DOUBLE;            /* for table matching    */
      }
 
   /* setup gc_numbytes so template reference to ZC works */
   gc_numbytes = argspace;
 
   return( match( p, INTAREG|INTBREG|INTEMP ) != MDONE );
   }
 
   static			/* evaluate the arguements for call */
evalargs( p, push ) register NODE *p; register push; { 
   register temp = (push-REG_ARGS)*(SZINT/SZCHAR); /* WFA 7/12/85 */
   register acount = 0; 
   register NODE *pargs;
   extern NODE *genargs();
 
   if( pargs = p->in.right ){
      temp += argsize( pargs );
      for( acount=1; pargs->in.op == CM; pargs=pargs->in.left ) acount += 1;
      }
 
   if( temp > maxargs ) maxargs = temp;
 
   /* (ef) 11/16/85 -- Tell allo to keeps its grubby little hands off */
   /*                  of our argument registers                      */

   if (temp>=0) {
      areg_needed= R5;
   }
   else  if (temp>(push-REG_ARGS)*(SZINT/SZCHAR)) 
      areg_needed= ((((push-REG_ARGS)*(SZINT/SZCHAR))-temp)/-4)+1;
   else 
      areg_needed= 0;

   if ( edebug > 3 )
      printf(" # areg_needed = %s\n",areg_needed?rnames[areg_needed]:"none");

   /* ga_byteoff added 10/24/83 by JEC for single SP decr */
   /* Assumes nested calls are evaluated unnested */
   /* If not true, this would have to be a stack. */
  
   if( edebug>4 ){
       printf(" #1# evalargs( %o ): argn=%d, argo=%d\n",
          p, acount, temp);
       fwalk(p,eprint,0);
       }
 
   if( p->in.right )  /* evaluate arguments and pass values */
      p->in.right = genargs( p->in.right, acount, temp );
 
   /* (ef) 11/16/85 -- okay, you can use arg registers now */
   areg_needed= 0;
   areg_used=   0;

   if( edebug>4 ){
       printf(" #2# evalargs( %o ): argo=%d\n", p, ga_byteoff);
       fwalk(p,eprint,0);
       }
 
   return( temp );
   }


  /*\
  |* (ef) 11/26/85 -- There seem to be four different kinds of things that
  |*                  want to get stored as arguments.  The sa_<xxx> functions
  |* store each of them, and store_arg looks at an arbitrary node and figures
  |* out who to call.  The four "sa" functions are:
  |*     sa_r2r3() --           the double returned in r2/r3 should be stored 
  |*                            as the next two argument words.
  |*     sa_reg(r) --           register 'r' contains the next argument word.
  |*     sa_aligned(p,r) --     'r' is the source address of the argument
  |*                            described by 'p'.  The structure/double
  |*                            described by 'p' is fullword aligned.
  |*     sa_nonaligned(p,r) --  'r' is the source address of the argument
  |*                            described by 'p'.  The structure/double
  |*                            described by 'p' is not fullword aligned.
  |*
  |* number of bytes is determined by p's type.
  |* sa_aligned uses template register '1' as temp.
  |* All functions use ga_byteoff to determine destination address --
  |* For example, a three word structure would look like:
  |*              |     :       |
  |*              | Third word  |
  |*              | Second word |
  |*              | First word  | <- ga_byteoff
  |*              |             |
  |* So the words would be stored in ga_byteoff, ga_byteoff+4, and
  |* ga_byteoff+8 respectively.
  \*/


sa_r2r3()
{
    if ( xdebug )
       printf(" # sa_r2r3() \n");

    ga_byteoff+= 4; /* store top of word */
    sa_reg( R3 );
    ga_byteoff-= 4; /* store bottom of word */
    sa_reg( R2 );
}

sa_reg( r )
int r; 
{

    if ( xdebug )
       printf(" # sa_reg(%s)\n", rnames[r] );

    if ( ga_byteoff < 0 ) { register int reg= GETARGREG(ga_byteoff);
       rmove( reg, r );
       areg_used= reg;
    }
    else 
       printf( " put %s,%d(sp) # sa_reg\n", rnames[r], ga_byteoff);
}


sa_aligned( p, r )
NODE *p;
int   r;
{
register int   byte_count= argsize(p);
register int   temp_reg=   regof( getlr(p,'1') );
register int   stack_adr;
int tmp;

   if ( xdebug ) {
       printf(" # sa_aligned( %o, %s )\n", p, rnames[r] );
       printf(" # 	stack_adr,byte_count= %d,%d\n",stack_adr,byte_count);
       printf(" # 	temp_reg= %s\n", rnames[temp_reg] );
       printf(" #       ");
       eprint( p, 0, &tmp, &tmp );
   }

   /* Aligned structures are stored last word to first */
   /* so we need to set stack_adr to top of structure  */
   /* see diagram above sa_r2r3 if this is confusing   */

   stack_adr= ga_byteoff+byte_count-(SZINT/SZCHAR);
   while( (byte_count -= SZINT/SZCHAR) >= 0 ) {
       if( stack_adr < 0 ) {
	   int reg= GETARGREG(stack_adr);

	   printf( " get %s,%d(%s) # sa_aligned\n",rnames[reg],
                                                      byte_count,
						      rnames[r]);
	   areg_used= reg;
       }
       else {
	   printf( " get %s,%d(%s) # sa_aligned\n", rnames[temp_reg],
                                                    byte_count, rnames[r]);
           printf( " put %s,%d(sp) # sa_aligned\n", rnames[temp_reg],
	                                            stack_adr);
       }
       stack_adr -= SZINT/SZCHAR;
   }
}
   

sa_nonaligned( p, r )
NODE  *p;
int    r;
{
register int stack_adr=  ga_byteoff;
int          byte_count= argsize(p);
register int lowarg= GETARGREG(stack_adr),
             hiarg=  GETARGREG((stack_adr+byte_count-SZINT/SZCHAR));
int          tmp1;

   if ( xdebug ) {
       printf(" # sa_nonaligned( %o, %s )\n", p, rnames[r]);
       printf(" # 	stack_adr,byte_count= %d,%d\n",stack_adr,byte_count);
       printf(" #       lowarg,hiarg=         ");
       if ( lowarg <= R5 ) 	   printf( "%s, ",rnames[lowarg]);
       else                        printf( "%d(sp), ",stack_adr);
       if ( hiarg <= R5 ) 	   printf( "%s\n",rnames[hiarg]);
       else                        printf( "%d(sp)\n",stack_adr+byte_count);
       printf(" #       ");
       eprint( p, 0, &tmp1, &tmp1 );
   }

   if (lowarg>R5 || hiarg<R5)	      pushtreg( R5, -1, -1 );
   if (lowarg>R4 || hiarg<R4)         pushtreg( R4, -1, -1 );
   if (lowarg>R3 || hiarg<R3)         pushtreg( R3, -1, -1 );
   if (lowarg>R2)                     pushtreg( R2, -1, -1 );
   printf(" get r4,$%d # sa_nonaligned (len)\n",p->stn.stsize);
   printf(" cas r3,%s,r0 # sa_nonaligned (src)\n",rnames[regof(p->in.left)]);

   /* short (<4byte) structures are passed right aligned */
   if ( p->stn.stsize<=4 ) 
       printf(" cal r2,%d(sp) # sa_nonaligned short (dest)\n",
                                                   stack_adr+4-p->stn.stsize);
   else
       printf(" cal r2,%d(sp) # sa_nonaligned long (dest)\n",stack_adr);
   callsubr( "blt", -1, -1 );
   poptregs(R0,R15);
   if ((lowarg<=R5)&&(hiarg>=R5))
      printf(" get r5,-4(sp) # sa_nonaligned\n");
   if ((lowarg<=R4)&&(hiarg>=R4))
      printf(" get r4,-8(sp) # sa_nonaligned\n");
   if ((lowarg<=R3)&&(hiarg>=R3))
      printf(" get r3,-12(sp) # sa_nonaligned\n");
   if ((lowarg<=R2)&&(hiarg>=R2))
      printf(" get r2,-16(sp) # sa_nonaligned\n");
   if (lowarg<=R5)
      areg_used= lowarg;
}

store_arg(p, r) 
NODE *p;
int   r;
{  
   if (xdebug) {
       printf(" # In store_arg, p= %o, r= %s\n",p,rnames[r]);
   }

   if( p == NULL )
      sa_reg( r );
   else if ((p->in.op==STARG)&&(p->stn.stalign!=4))
      sa_nonaligned( p, r );
   else
      sa_aligned( p, r );
}


   char *
ccbranches[] = {
    " be L%d # EQ\n",
    " bne L%d # NE\n",
    " bnh L%d # LE\n",
    " bl L%d # LT\n",
    " bnl L%d # GE\n",
    " bh L%d # GT\n",
    " bnh L%d # ULE\n",  /* was bnl 10/18/83 JEC */
    " bl L%d # ULT\n",   /* was bc0 10/18/83 JEC */
    " bnl L%d # UGE\n",  /* was bnc0 10/18/83 JEC */
    " bh L%d # UGT\n",   /* was bnc0 and bne 10/18/83 JEC */
    };
/* tbl */
 
			/*   printf conditional and unconditional branches */
cbgen( o, lab, mode ) register o, lab, mode; { 
 
/* tbl */
   if( o == 0 ) printf( " b L%d # cbgen\n", lab );
/* tbl */
   else {
      if( o > UGT ) cerror( "bad conditional branch: %s", opst[o] );
      printf( ccbranches[o-EQ], lab );
      }
   }
 
/* we have failed to match p with cookie; try another */
nextcook( p, cookie )
   register NODE *p;
   register cookie;
{
   if( odebug ){
      printf( "nextcook( %o, ", p );
      prcook( cookie );
      printf( " ) = " );
      }
 
   if( cookie == FORREW )
      cookie = 0;  /* hopeless! */
   else if( !(cookie&(INTAREG|INTBREG)) )
      cookie |= INTAREG|INTBREG;
   else if( !(cookie&(INAREG|INBREG)) )
      cookie |= INAREG|INBREG;
   else if( !(cookie&INTEMP)
         && ( asgop(p->in.op) || p->in.type == FLOAT || p->in.type == DOUBLE ))
      cookie = INTEMP|INAREG|INTAREG|INTBREG|INBREG;
   else
      cookie = FORREW;
 
   if( odebug ){
      prcook( cookie );
      printf( "\n" );
      }
 
   return( cookie );
   }
 
lastchance( p, cook ) register NODE *p; register cook; {
   /* forget it! */
   return(0);
   }
 
optim2( p ) register NODE *p; {
   /* do local tree transformations and optimizations */
 
   register NODE *r;
 
   switch( p->in.op ) {
      }
   }
 
 
# ifndef ONEPASS
main( argc, argv ) char *argv[]; {
   return( mainp2( argc, argv ) );
   }
# endif
