#ifndef lint
static char rcsid[] = "$Header:order.c 12.0$";
#endif
/* $Source: /ibm/acis/usr/src/lib/pcc_ca/RCS/order.c,v $ */
#ifdef unix
# include "mfile2.h"
#else
# include "doption h *"  /* circumvention for -D problem with preprocessor */
# include "mfile2 h *"
#endif
 
/* The following procs added 12/21/83 by JEC for bit field assigns */
 
extern NODE *talloc(), *tcopy();
extern NODE *block(), *makety();
 
shftfld( p ) register NODE *p;{/* calculate shift based on size of bitfield */
    switch(p->tn.type) {
    case INT:
    case UNSIGNED:
        return(  SZINT - UPKFSZ( p->tn.rval ) - UPKFOFF( p->tn.rval )%SZINT );
    case CHAR:
    case UCHAR:
	return(  SZCHAR - UPKFSZ( p->tn.rval ) - UPKFOFF( p->tn.rval )%SZCHAR );
    case SHORT:
    case USHORT:
	return(  SZSHORT - UPKFSZ( p->tn.rval ) - UPKFOFF( p->tn.rval )%SZSHORT );
        }
    }
 
maxvfld( p ) register NODE *p; {
    return( (1 << UPKFSZ( p->tn.rval )) - 1 );
    }
 
maskfld( p ) register NODE *p; {
    return( maxvfld( p ) << shftfld( p ) );
    }
 
    NODE *
newnode( newop, newty, lhs, rhs )
    register int newop;
    register TWORD newty;
    register NODE *lhs;
    register NODE *rhs;
{
    register NODE *p;
 
    p = talloc();
    p->in.op = newop;
    p->in.rall = NOPREF;
    p->in.type = newty;
    p->in.left = lhs;
    p->in.right = rhs;
#ifndef FLEXNAMES
    p->in.name[0] = '\0';
#else
    p->in.name = "";
#endif
    return( p );
}
 
/* The foregoing procs added 12/21/83 by JEC for bit field assigns */
 
int maxargs = -ARG_SAVE_SZ;	/* WFA 85 */
 
stoasg( p, o ) register NODE *p; register o; {
   /* should the assignment op p be stored,
      given that it lies as the right operand of o
      (or the left, if o==UNARY MUL) */

   if( p->in.op == INCR || p->in.op == DECR ) return;
   if( o==UNARY MUL && p->in.left->in.op == REG && !isbreg(p->in.left->tn.rval) ) SETSTO(p,INAREG);
 
   }
 
   /* should we delay the INCR or DECR operation of p */
deltest( p ) register NODE *p; {  /* This may need tuning for ibm032 -- JEC */
   return( p->in.left->in.op == REG );
   }
 
autoincr( p ) register NODE *p; {  /* Decipher this one some day -- JEC */
                          /* Called only from delay2 in reader.c */
   register NODE *q = p->in.left, *r;
 
   if( q->in.op == INCR && (r=q->in.left)->in.op == REG &&
       ISPTR(q->in.type) && p->in.type == DECREF(q->in.type) &&
       tlen(p) == q->in.right->tn.lval ) return(1);
 
   return(0);
   }
 
mkadrs(p) register NODE *p; {
   register o;
 
   o = p->in.op;
 
   if( asgop(o) ){
      if( p->in.left->in.su >= p->in.right->in.su ){
         if( p->in.left->in.op == UNARY MUL ){
            SETSTO( p->in.left->in.left, INTEMP );
            }
         else if( p->in.left->in.op == FLD && p->in.left->in.left->in.op == UNARY MUL ){
            SETSTO( p->in.left->in.left->in.left, INTEMP );
            }
         else { /* should be only structure assignment */
            SETSTO( p->in.left, INTEMP );
            }
         }
      else SETSTO( p->in.right, INTEMP );
      }
   else {
      if( p->in.left->in.su > p->in.right->in.su ){
         SETSTO( p->in.left, INTEMP );
         }
      else {
         SETSTO( p->in.right, INTEMP );
         }
      }
   }
 
notoff( t, r, off, cp) register t,r; register CONSZ off; register char *cp; {
   /* is it legal to make an OREG or NAME entry which has an
   /* offset of off, (from a register of r), if the
   /* resulting thing had type t */
#ifndef BUG3
   if( odebug>1 )
      printf( "notoff( 0%o, %d, 0%o, %c )\n", t, r, off, *cp );
#endif
   if( r == R0 || off > 32767 || off < -32768 )
      return(1); /* no  */
   return(0);    /* yes */
   }
 
# define max(x,y) ((x)<(y)?(y):(x))
 
sucomp( p ) register NODE *p; {
 
   /* set the su field in the node to the sethi-ullman
      number, or local equivalent */
 
   register o, ty, sul, sur, r;
 
   o = p->in.op;
   ty = optype( o );
   p->in.su = szty( p->in.type );
 
   if( ty == LTYPE ){
      if( o == OREG ){
         r = p->tn.rval;
         /* oreg cost is (worst case) 1 + number of temp registers used */
         if( R2TEST(r) ){
            if( R2UPK1(r)!=100 && istreg(R2UPK1(r)) ) ++p->in.su;
            if( istreg(R2UPK2(r)) ) ++p->in.su;
            }
         else {
            if( istreg( r ) ) ++p->in.su;
            }
         }
      if( p->in.su == szty(p->in.type) &&
         (p->in.op!=REG || !istreg(p->tn.rval)) &&
         (p->in.type==INT || p->in.type==UNSIGNED || p->in.type==DOUBLE) )
         p->in.su = 1;                    /*  Changed from o to 1 dpr. */
      return;
      }
 
   else if( ty == UTYPE ){
      switch( o ) {
      case UNARY CALL:
      case UNARY STCALL:
         p->in.su = fregs;  /* all regs needed */
         return;
 
      default:
         p->in.su =  p->in.left->in.su + (szty( p->in.type ) > 1 ? 2 : 1) ;/*  Changed 0 to
                                           1 dpr. */
         return;
         }
      }
 
 
   /* If rhs needs n, lhs needs m, regular su computation */
 
   sul = p->in.left->in.su;
   sur = p->in.right->in.su;
 
   if( o == ASSIGN ){
      /* computed by doing right, then left (if not in mem), then doing it */
      p->in.su = max(sur,sul+1);
      return;
      }
 
   if( o == CALL || o == STCALL ){
      /* in effect, takes all free registers */
      p->in.su = fregs;
      return;
      }
 
   if( o == STASG ){
      /* right, then left */
      p->in.su = max( max( 1+sul, sur), fregs );
      return;
      }
 
   if( asgop(o) ){
      /* computed by doing right, doing left address, doing left, op, and store */
      p->in.su = max(sur,sul+2);
/*
      if( o==ASG MUL || o==ASG DIV || o==ASG MOD) p->in.su = max(p->in.su,fregs);
 */
      return;
      }
 
   switch( o ){
   case ANDAND:
   case OROR:
   case QUEST:
   case COLON:
   case COMOP:
      p->in.su = max( max(sul,sur), 1);
      return;
 
/* case COMOP:  /* + 1 added 10/24/83 by JEC for passing args in regs */
/*    p->in.su = max( max(sul,sur), 1) + 1;
/*    return;
*/
   case PLUS:
   case OR:
   case ER:
      /* commutative ops; put harder on left */
      if( p->in.right->in.su > p->in.left->in.su && !istnode(p->in.left) ){
         register NODE *temp;
         temp = p->in.left;
         p->in.left = p->in.right;
         p->in.right = temp;
         }
      break;
      }
 
   /* binary op, computed by left, then right, then do op */
   p->in.su = max(sul,szty(p->in.right->in.type)+sur);
/*
   if( o==MUL||o==DIV||o==MOD) p->in.su = max(p->in.su,fregs);
 */
 
   }
 
int radebug = 0;
 
   /*\
   |* converts both sides of a conditional expression to the same type
   \*/

#define NC	255
static char conversion[16][16] = {
/*            v   f   c   s   i   l   f   d   s   u   e   m   u   u   u   u  */
/*            o   a   h   h   n   o   l   o   t   n   n   o   c   s   i   l  */
/*            i   r   a   o   t   n   o   u   r   i   u   e   h   h   n   o  */
/*            d   g   r   r       g   a   b   c   o   m   t   a   r   t   n  */
/*                        t           t   l   t   n       y   r   t       g  */
/*                                                                           */
/* void  */   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
/* farg  */   0, NC, NC, NC, NC, NC,  6,  7,  0,  0, NC, NC, NC, NC, NC, NC,
/* char  */   0, NC, NC,  3,  4,  5,  6,  7,  0,  0, NC, NC, NC, NC, NC, NC,
/* short */   0, NC,  3, NC,  4,  5,  6,  7,  0,  0, NC, NC, NC, NC, NC, NC,
/* int   */   0, NC,  4,  4, NC, NC,  6,  7,  0,  0, NC, NC, NC, NC, NC, NC,
/* long  */   0, NC,  5,  5, NC, NC,  6,  7,  0,  0, NC, NC, NC, NC, NC, NC,
/* float */   0,  6,  6,  6,  7,  7, NC,  7,  0,  0,  6,  6,  6,  6,  7,  7,
/* dubl  */   0,  7,  7,  7,  7,  7,  7, NC,  0,  0,  7,  7,  7,  7,  7,  7,
/* strct */   0,  0,  0,  0,  0,  0,  0,  0, NC,  8,  0,  0,  0,  0,  0,  0,
/* union */   0,  0,  0,  0,  0,  0,  0,  0,  9, NC,  0,  0,  0,  0,  0,  0,
/* enum  */   0, NC, NC, NC, NC, NC,  6,  7,  0,  0, NC, NC, NC, NC, NC, NC,
/* moety */   0, NC, NC, NC, NC, NC,  6,  7,  0,  0, NC, NC, NC, NC, NC, NC,
/* uchar */   0, NC, NC, NC, NC, NC,  6,  7,  0,  0, NC, NC, NC, NC, NC, NC,
/* ushrt */   0, NC, NC, NC, NC, NC,  6,  7,  0,  0, NC, NC, NC, NC, NC, NC,
/* unsgn */   0, NC, NC, NC, NC, NC,  7,  7,  0,  0, NC, NC, NC, NC, NC, NC,
/* ulong */   0, NC, NC, NC, NC, NC,  7,  7,  0,  0, NC, NC, NC, NC, NC, NC};

condcast( p, lft, lbl )  register NODE *p;  register TWORD lft; register lbl;  {
   register TWORD  result_type;

   if (ISPTR(lft)||(ISPTR(p->in.right->in.type))||
       ISFTN(lft)||(ISFTN(p->in.right->in.type))||
       ISARY(lft)||(ISARY(p->in.right->in.type))) {
           deflab( lbl ); /* no conversion for pointer, function, or array */
           return( 1 );
   } 
   result_type= conversion[lft&0xF][p->in.right->in.type&0xF];
   if (!result_type) {
      werror("Illegal type conversion in conditional expression\n");
      deflab( lbl );
      return( 1 );
   }
   if (result_type==NC) {
      deflab(lbl);
      return(1);
   }
   if (result_type!=p->in.right->in.type) {
      p->in.right= makety(p->in.right,result_type,0,result_type);
      p->in.right->in.rall= p->in.right->in.left->tn.rval|MUSTDO;
      order(p->in.right,INTAREG|INTBREG);
   }
   if (result_type!=lft) {
      int  end_label;
      NODE *lft_node=block(REG,NIL,NIL,lft,0,lft);

      lft_node->tn.rval= p->in.right->tn.rval;
      cbgen( 0, end_label=getlab(), 'I' );
      deflab( lbl );
      p->in.left= makety(lft_node,result_type,0,result_type);
      p->in.left->in.rall= p->in.right->tn.rval|MUSTDO;
      order(p->in.left,INTAREG|INTBREG);
      deflab( end_label );
      tfree(p->in.left);
   }
   else {
      deflab( lbl );
   }
   return( 1 );
}
 
rallo( p, down ) register NODE *p; {
   /* do register allocation */
   register o, type, down1, down2, ty;
#ifndef BUG3
   if( radebug ) printf( "rallo( %o, %d )\n", p, down );
#endif
   down2 = NOPREF;
   p->in.rall = down;
   down1 = ( down &= ~MUSTDO );
 
   ty = optype( o = p->in.op );
   type = p->in.type;
 
   if( type == DOUBLE || type == FLOAT ){
      if( o == FORCE ) down1 = R2|MUSTDO;	/* WFA 7/10/85 R2 for fn retn */
      }
   else switch( o ) {
   case ASSIGN:
      down1 = NOPREF;
      down2 = down;
      break;
 
/* below recommented by JEC (assume special hardware for some machine) */
/* case MUL:
/* case DIV:
/* case MOD:
/*    down1 = R3|MUSTDO;
/*    down2 = R5|MUSTDO;
/*    break;
/*
/* case ASG MUL:
/* case ASG DIV:
/* case ASG MOD:
/*    p->in.left->in.rall = down1 = R3|MUSTDO;
/*    if( p->in.left->in.op == UNARY MUL )
/*       rallo( p->in.left->in.left, R4|MUSTDO );
/*
/*    else if( p->in.left->in.op == FLD  && p->in.left->in.left->in.op == UNARY MUL )
/*       rallo( p->in.left->in.left->in.left, R4|MUSTDO );
/*
/*    else rallo( p->in.left, R3|MUSTDO );
/*    rallo( p->in.right, R5|MUSTDO );
/*    return;
/* above recommented by JEC (assume special hardware for some machine) */
 
   case STASG:{  /* added 12/28/83 by JEC */
      register rop = p->in.right->in.op;
 
      if( rop != STCALL && rop != UNARY STCALL ){
          down1 = R2;
          down2 = R3;
          }
      break;
      }
 
   case CALL:
   case EQ:
   case NE:
   case GT:
   case GE:
   case LT:
   case LE:
   case NOT:
   case ANDAND:
   case OROR:
      down1 = NOPREF;
      break;
 
   case FORCE:
      down1 = R2|MUSTDO;	/* WFA 7/10/85 R2 for fn retn */
      break;
 
      }
 
   if( ty != LTYPE ) rallo( p->in.left, down1 );
   if( ty == BITYPE ) rallo( p->in.right, down2 );
 
   }
 
offstar( p ) register NODE *p; {
 
/* The following mass of code commented-out 11/1/83 by JEC out of ignorance.
/*
/* if( p->in.op == PLUS ) {
/*    if( p->in.left->in.su == fregs ) {
/*       order( p->in.left, INTAREG|INAREG );
/*       return;
/*    } else if( p->in.right->in.su == fregs ) {
/*       order( p->in.right, INTAREG|INAREG );
/*       return;
/*    }
/*    if( p->in.left->in.op==LS &&
/*      (p->in.left->in.left->in.op!=REG || tlen(p->in.left->in.left)!=sizeof(int) ) ) {
/*       order( p->in.left->in.left, INTAREG|INAREG );
/*       return;
/*    }
/*    if( p->in.right->in.op==LS &&
/*      (p->in.right->in.left->in.op!=REG || tlen(p->in.right->in.left)!=sizeof(int) ) ) {
/*       order( p->in.right->in.left, INTAREG|INAREG );
/*       return;
/*    }
/*    if( p->in.type == (PTR|CHAR) || p->in.type == (PTR|UCHAR) ) {
/*       if( p->in.left->in.op!=REG || tlen(p->in.left)!=sizeof(int) ) {
/*          order( p->in.left, INTAREG|INAREG );
/*          return;
/*       }
/*       else if( p->in.right->in.op!=REG || tlen(p->in.right)!=sizeof(int) ) {
/*          order(p->in.right, INTAREG|INAREG);
/*          return;
/*       }
/*    }
/* }
 */

   if( p->in.op == PLUS || p->in.op == MINUS ){
      if( p->in.right->in.op == ICON && !istnode(p->in.left) ){
         p = p->in.left;
         order( p , INTAREG|INAREG);
         return;
         }
      }
 
   if( p->in.op == UNARY MUL /* && !canaddr(p) This is always true on RT */) {
			     /* canaddr is different from pcc on vax --KAS */
      offstar( p->in.left );
      return;
      }
   order( p, INTAREG );  /* WARNING: result must end up in an index reg */
   }
 
setincr( p ) register NODE *p; {
   return( 0 );  /* for the moment, don't bother */
   }
 
setbin( p ) register NODE *p; {
   register lo = p->in.left->in.op;
   register ro = p->in.right->in.op;
#ifndef BUG3
   if (edebug>1)
      printf("setbin(%o)\n", p);
#endif
   switch(p->in.op) {
      case MOD:
      case DIV:
      case MUL:
         if( lo != REG ) {
            order( p->in.left, INTAREG|INTBREG );
            return(1);
         }
         else if( ro != REG ) {
            order( p->in.right, INTAREG|INTBREG );
            return(1);
         }
         else return(0);
 
      case MINUS:
         if( tshape( p->in.left, SSCON ) && ro != REG ){  /* use sfi inst */
            order( p->in.right, INTAREG|INTBREG );
            return(1);
            }
         break;
 
      case PLUS:
      case OR:
      case ER:
      case AND:
         /* added 11/2/83 by JEC to keep r0 free if possible */
         if( lo == REG && ro == REG &&
             p->in.left->tn.rval == R0 && istreg( p->in.right->tn.rval )
           ){
            register NODE *tp = p->in.right;
            p->in.right = p->in.left;
            p->in.left = tp;
            return(0);
            }
         break;
 
      case EQ:
      case NE:
      case LE:
      case LT:
      case GE:
      case GT:
      case ULE:
      case ULT:
      case UGE:
      case UGT:
         if( lo != REG ){
            order( p->in.left, INTAREG|INTBREG );
            return(1);
         }
         if( ro != REG && !tshape( p->in.right, SSCON ) ){
            order( p->in.right, INTAREG|INTBREG );
            return(1);
            }
         return(0);
      }
 
   if( p->in.left->in.su == fregs ){
      order( p->in.left, INTAREG|INTBREG );
      return(1);
      }
 
   if( ro == ICON && !tshape( p->in.right, SSCON ) ){
      order( p->in.right, INTAREG|INTBREG );
      return(1);
      }
 
   if( lo == ICON && !tshape( p->in.left, SSCON ) ){
      order( p->in.left, INTAREG|INTBREG );
      return(1);
      }
 
   if( !istnode( p->in.left ) ){
      order( p->in.left, INTAREG|INTBREG );
      return(1);
      }
 
   if( ro != REG && !tshape( p->in.right, SSCON ) ){
      order( p->in.right, INTAREG|INTBREG );
      return(1);
      }
 
   return(0); /* rewrite */
   }
 
makestar( p ) register NODE *p; { /* added 1/16/84 by JEC */
   register NODE* p1 = talloc();
   register NODE* p2 = talloc();
 
   ncopy( p1, p );  /* make a copy of p */
   ncopy( p2, p );  /* make a copy of p */
 
   p->in.op = UNARY MUL;
   p->in.left = p1;
   p->in.right = NULL;
   p1->in.op = UNARY AND;
   p1->in.type = (TWORD) INCREF( p2->in.type );
   p1->in.left = p2;
   p1->in.right = NULL;
   }
 
setstr( p ) register NODE *p; { /* structure assignment */
   register NODE *l = p->in.left;
   register NODE *r = p->in.right;
   register NODE *pcm;
   register result = 0;
 
 /*
 * JSW 7/3/86 - changed so that right side of structure assignment is 
 * evaluated first, before left side.  This is how the vax does it and is 
 * necessary for the case when the rhs is a function call.  This is a fix 
 * for apar #77
 */

   if( r->in.op == STCALL || r->in.op == UNARY STCALL ){
       ncopy( pcm = talloc(), p );            /* why not use struct assign */
       ncopy( p, r );                         /* why not use struct assign */
       pcm->in.op = CM;               /* create COMMA node for asg stcall  */
       pcm->in.left = r->in.left;     /* left(COMMA) is function address   */
       pcm->in.right = l;             /* right(COMMA) is target struct adr */
       p->in.left = pcm;
       r->in.op = FREE;               /* old STCALL node no longer needed  */

/* Fix for Apar #260
 * JSW 8/21/86 - In the case of a structure assignment where the rhs is a
 * function returning a structure allow a temp register to hold the address
 * where the result should be placed.  This register is only needed long 
 * enough to copy it into R2 where it is passed to the function as a hidden
 * argument.  I can't just put it into R2 because the other parms may
 * require function calls, which would trash r2.  Was R5 but that caused
 * the same problem.
 */
       if( !canaddr( l ) ) {
           if( l->in.op == NAME )
               makestar( l );
           if( l->in.op == UNARY MUL ) {
	       rallo( l, NOPREF );     /* WFA 6/10/85 - Avoid R2 and R3 */
               offstar( l );
	       }
           else cerror( "STASG lhs" );
           }
       result = 1;
       return(result);
       }

/*** end of fix for apar #260 ***/

   else if( r->in.op != REG ){
       order(r,INTAREG/*|INTBREG 6/28/85 WFA deleted for struct assign bug*/);
       result = 1;
       }
 
   if( !canaddr( l ) ){
       if( l->in.op == NAME )
           makestar( l );
       if( l->in.op == UNARY MUL ) {
	   rallo( l, R5|MUSTDO);     /* WFA 6/10/85 - Avoid R2 and R3 */
           offstar( l );
	   }
       else cerror( "STASG lhs" );
       result = 1;
       }

   return( result );
   }
 
setasg( p ) register NODE *p; {  /* setup for assignment operator */
   register lo = p->in.left->in.op;
   register ro = p->in.right->in.op;
#ifndef BUG3
   if (edebug>1)
      printf("setasg(%o) lo=%d, ro=%d\n", p, lo, ro );
#endif
   /* special check for assign to bit fields added 12/21/83 by JEC */
 
   if( lo == FLD ){
       register NODE *lhs = p->in.left;
       register NODE *rhs = p->in.right;
       register NODE *bvtree;
       register TWORD ty = p->in.left->in.type;
 
       if( rhs->in.su >= fregs ){  /* added 9/84 for call on rhs */
           order( rhs, INTAREG|INTBREG );
           return(1);
           }
 
       if( !canaddr( lhs->in.left ) ){
           if( lhs->in.left->in.op != UNARY MUL ) cerror( "bad fld assign" );
           offstar( lhs->in.left );
           return(1);
           }

       /* If thing to be assigned != SZINT, process it some more --KAS */
       if( rhs->in.type!=INT && rhs->in.type!=UNSIGNED){
	   order( p->in.right, INAREG);
	   return(1);
	   }

       if( ro == ICON && rhs->in.name[0] == '\0' ){
           rhs->tn.lval = ( rhs->tn.lval & maxvfld( lhs ) ) << shftfld( lhs );
	   bvtree = rhs;
           }
       else {
           bvtree =
               newnode( LS, ty,    /* position value of rhs to bit field  */
                   newnode( AND, ty, /* truncate value of rhs to max val  */
                       rhs,
                       newnode( ICON, ty, maxvfld( lhs ), 0 )),
                   newnode( ICON, ty, shftfld( lhs ), 0 ));
       }

       p->in.left = lhs->in.left;     /* prune FLD node from lefthand side */
       p->in.right =
           newnode( OR, ty,           /* set new value of bit field        */
               newnode( AND, ty,      /* zero old value bit field          */
                   tcopy( lhs->in.left ),
                   newnode( ICON, ty, ~maskfld( lhs ), 0 )),
               bvtree );
       lhs->in.op = FREE;
       return(1);
       }

   /* end special check for assign to bit fields */
 
   if( ro != REG && p->in.right->in.su != 0 ) {
      order( p->in.right, INTAREG|INTBREG|
         (p->in.type == FLOAT || p->in.type == DOUBLE ? INTEMP : 0) );
      return(1);
      }
 
   if( lo == UNARY MUL ){
      offstar(p->in.left);
      return(1);
      }
 
   /* put right into reg unless:
   /*   1. right is already in a reg, or
   /*   2. left is a reg, and right is an SSCON
   */
 
   if( ro != REG &&
       ( lo != REG ||
         (ro != ICON || p->in.right->tn.lval > 32767 ||
                        p->in.right->tn.lval < -32768)
       )
     ){
#ifndef BUG3
      if (edebug>1)
         printf("setasg(%o) special check\n", p);
#endif
      order( p->in.right, INTAREG|INTBREG );
      return(1);
      }

   if (p->in.left->in.type!=p->in.right->in.type) {
#ifndef FORT
      p->in.right= block(SCONV,p->in.right,NIL,p->in.left->in.type,p->in.left->fn.cdim,p->in.left->fn.csiz);
#endif 
      return(1);
   }

   return(0);
   }
 
setasop( p ) register NODE *p; {/* setup for op= */
    register lo = p->in.left->in.op;
    register ro = p->in.right->in.op;

#ifndef BUG3
    if( edebug>1 )
        printf("setasop(%o) n", p);
#endif
 
    switch( p->in.op ){
        case ASG MOD:
        case ASG DIV:
        case ASG MUL:
           if( ro != REG ) {
               order( p->in.right, INTAREG|INTBREG );
               return(1);
           }
    }
    return( setasg( p ) );
 
    /* NOTE: If this function returns zero, there may be no side effects
    /* in the lhs, as order() will rewrite the tree as lhs = lhs op rhs.
    */
}
 
int crslab = 9999;  /* Honeywell */
 
getlab(){
   return( crslab-- );
   }
 
deflab( l ) register l; {
   printf( "L%d:\n", l );
   }
 
/* return NODE* added 10/25/83 by JEC for passing args in regs */
/* argn    parm added 12/30/83 by JEC for passing structures   */
/* byteoff parm added 10/25/83 by JEC for passing args in regs */
/* argroot      added 10/25/83 by JEC for passing args in regs */
/* ga_byteoff   added 12/30/83 by JEC for passing structures   */
 
int ga_byteoff;            /* byte offset of current arguement */
int argreg;    /* next register for arguments, added 7/11/85 WFA */
 
   NODE *			/* generate code for arguments */
genargs( p,argn,byteoff ) register NODE *p; register argn, byteoff; { 
   register NODE *argroot;
   register asize;
#ifndef BUG3
   if( edebug>2 ) printf("genargs( %o, %d, %d )\n", p, argn, byteoff);
#endif
   /*  first, do the arguments on the right */
 

   for( argroot = p; p->in.op == CM; p = p->in.left ){
      asize = argsize( p->in.right );
      if( (p->in.right = genargs( p->in.right, argn, byteoff )) == NIL ){
         argroot = p->in.left;
         p->in.op = FREE;
         }
      byteoff -= asize;
      argn -= 1;
      }
 

   if( (ga_byteoff = byteoff - argsize(p)) < -ARG_SAVE_SZ )
      cerror("bad argument offset");

   /* ga_byteoff (current arg offset) is used by store_arg */
   if( (ga_byteoff < 0) && (ARGINREG(p->in.type)) ) {
      extern areg_used;
       
      /* force the argument directly into the register */
      p->in.rall = MUSTDO | GETARGREG(ga_byteoff);
      order( p, INAREG );
      areg_used= GETARGREG(ga_byteoff);
      }
   else {
       order( p, FORARG );
       if ( p->in.op != FREE )
          cerror("FORARG not FREE");
       else { /* reallocate a dummy node for the arument subtree */
          p->in.op= ICON;
	  p->in.type= INT;
       }
   }

   return( argroot );
   }
 
argsize( p ) register NODE *p; {
   register t = 0;
 
   if( p->in.op == CM ){
      t = argsize( p->in.left );
      p = p->in.right;
      }
   if( p->in.type == DOUBLE || p->in.type == FLOAT ){
      SETOFF( t, 4 );
      return( t+8 );
      }
   else if( p->in.op == STARG ){
      SETOFF( t, 4 );  /* alignment */
      return( t + ((p->stn.stsize+3)/4)*4 );  /* size */
      }
   else {
      SETOFF( t, 4 );
      return( t+4 );
      }
   }
