/* 
   Copyright 1994-2003 Free Software Foundation, Inc.

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.  

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222
*/
#include        <stdio.h>
#include				<string.h>
#include        "lists.h"
#include        "expr.h"
#include        "c.h"
#include        "gen386.h"
#include 				"diag.h"
extern OCODE *peep_tail, *frame_ins;
extern SYM *currentfunc;
extern int retlab;

#define ABS(x) ( (x) < 0 ? -(x) : (x))
/*
 *      this module contains all of the code generation routines
 *      for evaluating expressions and conditions.
 */
extern int stdinttype,stdunstype,stdintsize, stdldoublesize;
extern int stdaddrsize;
extern int stackadd,stackmod;
extern int prm_largedata;
extern AMODE     push[], pop[];
extern int prm_68020, prm_intrinsic;
extern int regs[3];
extern long nextlabel;
extern long lc_maxauto;
extern int prm_cmangle;
extern int prm_cplusplus;
       
extern int floatstack_mode;
AMODE freg0[] = { { am_freg, 0 } };
AMODE sreg[] = { { am_dreg,4 } };

/* little ditty to allocate stack space for floating point
 * conversions and return a pointer to it
 * it will be at the bottom for standard stack frames; top for 
 * using ESP for frames
 * 0-7 used for fistp, 8-15 used for long intermediate values
 */
AMODE *floatconvpos(void)
{
	AMODE *ap1;
   int constv = 16;
//   if (prm_cplusplus)
//      constv = 12;
	if (!floatstack_mode) {
		if (!lc_maxauto) {
        OCODE * new = xalloc(sizeof(OCODE));
        new->opcode = op_sub;
        new->oper1 = makedreg(ESP);
        new->oper2 = make_immed(constv);
				new->back = frame_ins;
				new->fwd = frame_ins->fwd;
				frame_ins->fwd->back = new;
				frame_ins->fwd = new;
		}
		else {
			frame_ins->oper2->offset->v.i += constv;
		}
		floatstack_mode += constv;
	}
  ap1 = xalloc(sizeof(AMODE));
  ap1->mode = am_indisp;
	ap1->preg = EBP;
  ap1->offset = makeintnode(en_icon, -lc_maxauto-constv);
	ap1->length = 4;
  return ap1;
}
AMODE *truncateFloat(AMODE *ap1, int size)
{
   AMODE *ap = floatconvpos() ;
   do_extend(ap1,size,F_FREG) ;
   gen_codes(op_fstp,size,ap,0) ;
   gen_codes(op_fld,size,ap,0) ;
   return ap1 ;
}
int chksize(int lsize, int rsize)
{
	int l,r;
	l = lsize;
	r = rsize;
	if (l < 0) l = - l;
	if (r < 0) r = - r;
  if (rsize == 5) /* 5 is used for bools, which are the smallest type now */
    if (lsize == 5)
      return FALSE;
    else
      return TRUE;
  if (lsize == 5)
    return FALSE;
	return(l > r);
}
AMODE *fstack(void)
{
	AMODE *ap = xalloc(sizeof(AMODE));
	ap->mode = am_freg;
	ap->length = 10;
	ap->preg = 0;
	ap->sreg = 0;
	ap->offset = 0;
	ap->tempflag = TRUE;
	return(ap);
}
AMODE		*make_muldivval(AMODE *ap)
{
			int temp;
			AMODE *ap1 = make_label(queue_muldivval(ap->offset->v.i));
			ap1->mode = am_direct;
			return(ap1);
}
void make_floatconst(AMODE *ap)
{
	int size = ap->length;
	if (isintconst(ap->offset->nodetype)) {
		ap->offset->v.f = ap->offset->v.i;
		ap->offset->nodetype = en_rcon;
      size = 7;
   } else {
      switch(ap->offset->nodetype) {
         case en_fcon:
            size = 7 ;
            break ;
         case en_rcon:
            size = 8 ;
            break ;
         case en_lrcon:
            size = 10 ;
            break ;
         case en_fimaginarycon:
            size = 15 ;
            break ;
         case en_rimaginarycon:
            size = 16 ;
            break ;
         case en_lrimaginarycon:
            size = 17 ;
            break ;
      } 
   }
	if (ap->offset->v.f == 1.0) {
		ap->mode = am_fconst;
		ap->preg = fcone;
	}
	else if (ap->offset->v.f == 0.0) {
		ap->mode = am_fconst;
		ap->preg = fczero;
	}
	else {
		AMODE *ap1 = make_label(queue_floatval(ap->offset->v.f,size));
		ap->mode = am_direct;
		ap->length = size;
		ap->offset = ap1->offset;
	}
}
AMODE    *make_label(int lab)
/*
 *      construct a reference node for an internal label number.
 */
{       ENODE    *lnode;
        AMODE    *ap;
        lnode = xalloc(sizeof(ENODE));
        lnode->nodetype = en_labcon;
        lnode->v.i = lab;
        ap = xalloc(sizeof(AMODE));
        ap->mode = am_immed;
        ap->offset = lnode;
        return ap;
}

AMODE *makesegreg(int seg)
{
		AMODE *ap = xalloc(sizeof(AMODE));
		ap->mode = am_seg ;
		ap->seg = seg ;
		return ap;
}
AMODE    *make_immed(long i)
/*
 *      make a node to reference an immediate value i.
 */
{       AMODE    *ap;
        ENODE    *ep;
        ep = xalloc(sizeof(ENODE));
        ep->nodetype = en_icon;
        ep->v.i = i;
        ap = xalloc(sizeof(AMODE));
        ap->mode = am_immed;
        ap->offset = ep;
        return ap;
}
AMODE    *make_immedt(long i, int size)
/*
 *      make a node to reference an immediate value i.
 */
{
				switch (size) {
					case 1:
					case -1:
						i &= 0xff;
						break;
					case 2:
					case -2:
						i &= 0xffff;
						break;
               case 4:
               case -4:
                  i &= 0xffffffff ;
                  break ;
				}
				return make_immed(i);
}

AMODE    *make_offset(ENODE *node)
/*
 *      make a direct reference to a node.
 */
{       AMODE    *ap;
        ap = xalloc(sizeof(AMODE));
        ap->mode = am_direct;
        ap->offset = node;
        ap->seg = 2 ;
        return ap;
}
AMODE *make_stack(int number)
{
	AMODE *ap = xalloc(sizeof(AMODE));        
	ENODE *ep = xalloc(sizeof(ENODE));
	ep->nodetype = en_icon;
	ep->v.i = -number;
	ap->mode = am_indisp;
	ap->preg = ESP;
	ap->offset = ep;
	return(ap);
}
void do_ftol(void)
{
		if (prm_intrinsic) {
			AMODE *sp,vv,*e8,*e0, *ax ;
			gen_code(op_sub,sp = makedreg(ESP),make_immed(12) ) ;
			memset(&vv,0,sizeof(vv)) ;
			vv.mode = am_indisp ;
			vv.preg = ESP ;
         vv.offset = e8 = makeintnode(en_icon,8) ;
			gen_code(op_fnstcw,copy_addr(&vv),0) ;
			gen_codes(op_mov,2,ax = makedreg(EAX),copy_addr(&vv) ) ;
			gen_codes(op_or,1,makedreg(4),make_immed(0xc) ) ;
         vv.offset = makeintnode(en_icon,10) ;
			gen_codes(op_mov,2, copy_addr(&vv),ax) ;
			gen_code(op_fldcw,copy_addr(&vv),0) ;  	
         vv.offset = e0 = makeintnode(en_icon,0) ;
			gen_codes(op_fistp,8, copy_addr(&vv), 0) ;
			vv.offset = e8 ;
         gen_code(op_fldcw,copy_addr(&vv),0) ; 
			vv.offset = e0 ;
			gen_codes(op_mov,4,makedreg(EAX),copy_addr(&vv)) ;
			gen_code(op_add,sp,make_immed(12)) ; 	
			
      } else
         call_library("__ftol");
}
AMODE * floatstore(ENODE *node, AMODE *apr, int novalue, int size)
{
	if (isbit(node)) {
		AMODE *ap1 = fstack();
		do_extend(ap1,4,F_DREG | F_VOL);
		bit_store(apr,ap1,node,novalue);
		return ap1;
	}
	else if ( size <= 4) {
		int pushed = FALSE;
		if (regs[0] && apr->preg != 0) {
			pushed = 1;
			gen_push(EAX,am_dreg,0);
		}
		do_ftol() ;
		if (apr->mode != am_dreg || apr->preg != 0)
			gen_codes(op_mov,size,apr,makedreg(EAX));
		if (pushed)
			gen_pop(EAX,am_dreg,0);
      if (novalue)
         freeop(apr) ;
		return apr;
	}
	else if (size <= 4) {
		gen_codef(op_fistp,apr,0);
      if (novalue)
         freeop(apr) ;
		return apr;
	}
	else {
      if (novalue) {
			gen_codef(op_fstp,apr,0);
         return apr;
      } else {
			gen_codef(op_fst,apr,0);
         return makefreg(0) ;
      }
	}
}
void floatload(AMODE *ap, int flag)
{
	if (ap->mode == am_fconst) {
						switch (ap->preg) {
							case fczero:
								gen_codef(op_fldz,0,0);
								break;
							case fcone:
								gen_codef(op_fld1,0,0);
								break;
						}
						ap->mode = am_freg;
						ap->preg = 0;
	}
	else
		if (flag && ap->mode != am_freg) {
			if (ap->mode == am_dreg) {
				AMODE *ap1 = floatconvpos();
				do_extend(ap,4,0);
				gen_codes(op_mov,4,ap1,ap);
				gen_codefs(op_fild,4,ap1,0);
			} else
				gen_codef(op_fld,ap,0);
			freeop(ap);
						ap->mode = am_freg;
						ap->preg = 0;
		}
}
int is_memory(AMODE *ap)
{
	switch(ap->mode) {
												case am_indisp: case am_indispscale: 
												case am_direct:
		return TRUE;
	}
	return FALSE;
}
AMODE *bit_load(AMODE *ap,ENODE *node)
{
   if (ap->mode == am_dreg)
      return ap ;
	do_extend(ap,ap->length,F_DREG | F_VOL);
		if (node->startbit)
			gen_code(op_shr,ap,make_immed(node->startbit));
      gen_code(op_and,ap,make_immed(mod_mask(node->bits)));
		return ap;
}
void bit_store(AMODE *ap2, AMODE *ap1, ENODE *node, int novalue)
{
		AMODE *ap3;
		if (ap1->mode == am_immed) {
			int vb;
         ap3 = make_immed(ap1->offset->v.i & mod_mask(node->bits));
#ifdef XXXXX
			if (node->bits == 1)
				gen_codes(op_btr,4,ap2,make_immed(node->startbit));
			else
#endif
            gen_code(op_and,ap2,make_immed(~(mod_mask(node->bits)<<node->startbit)));
#ifdef XXXXX
			if ((vb = single_bit(ap1->offset->v.i)) != -1) {
				gen_codes(op_bts,4,ap2,make_immed(vb+node->startbit));
         }else 
#endif
            if (ap3->offset->v.i) {
               ap3->offset->v.i <<= node->startbit;
               gen_codes(op_or,ap2->length,ap2,ap3);
            }
		}
		else {
			do_extend(ap1,ap2->length,F_DREG | F_VOL);
         gen_code(op_and,ap1,make_immed(mod_mask(node->bits)));
			if (!novalue)
				gen_codes(op_push,4,ap1,0);
			if (node->startbit)
				gen_code(op_shl,ap1,make_immed(node->startbit));
         gen_code(op_and,ap2,make_immed(~(mod_mask(node->bits)<<node->startbit)));
			gen_code(op_or,ap2,ap1);
			if (!novalue)
				gen_codes(op_pop,4,ap1,0);
		}
      if (novalue)
         freeop(ap2) ;
}
AMODE *aprtocx(AMODE *ap)
{
   AMODE *ap2 ;
   if (ap->mode == am_indisp && (ap->preg == EAX || ap->preg == EDX)
         || ap->mode == am_indispscale && (ap->preg == EAX || ap->preg == EDX ||
               ap->sreg == EAX || ap->sreg == EDX)) { 
//         || ap->mode == am_dreg && (ap->preg == EAX || ap->preg == EDX)) {
      ap2 = tempcx() ;
      if (ap->mode == am_dreg)
         gen_code(op_mov,ap2,ap) ;
      else
         gen_code(op_lea,ap2,ap) ;
      freeop(ap) ;
      *ap = *ap2 ;
      ap->mode = am_indisp ;
      ap->offset = makeintnode(en_icon,0) ;
      ap->length = 6 ;
   } else if (ap->mode == am_dreg && (ap->preg == EAX || ap->preg == EDX)) {
      ap2 = tempcx() ;
      if (ap->mode == am_dreg)
         gen_code(op_mov,ap2,ap) ;
      else
         gen_code(op_lea,ap2,ap) ;
      ap2->length = ap->length ;
      freeop(ap) ;
      *ap = *ap2 ;
   }
   return ap ;
}
void loadaxdx(AMODE *ap)
{
   if (ap->mode == am_immed) {
      tempaxdx() ;
     gen_codes(op_mov,4,makedreg(EAX),make_immed(ap->offset->v.i & 0xffffffff)) ;
#if sizeof(ULLONG_TYPE) == 4
     gen_codes(op_mov,4,makedreg(EDX),make_immed(ap->offset->v.i < 0 ? -1 : 0)) ;
#else
     gen_codes(op_mov,4,makedreg(EDX),make_immed(ap->offset->v.i >> 32)) ;
#endif
   } else {
     AMODE *ap3 = aprtocx(ap) ;
     tempaxdx() ;
     gen_codes(op_mov,4,makedreg(EAX),ap3) ;
     ap3->offset = makenode(en_add,ap3->offset,makeintnode(en_icon,4));
     gen_codes(op_mov,4,makedreg(EDX),ap3) ;
     freeop(ap3) ;
   }
   ap->mode = am_axdx ;
   ap->length = 6 ;
}
void do_extend(AMODE *ap,int osize,int flags)
/*
 *      if isize is not equal to osize then the operand ap will be
 *      loaded into a register (if not already) and if osize is
 *      greater than isize it will be extended to match.
 */
{				AMODE *ap2,*ap1;

				int isize = ap->length;
				if (isize && isize != osize && isize != -osize && ap->mode !=am_immed) {
						if (ap->mode == am_dreg && ap->preg > 3 && (osize == 1 || osize == -1))
							flags |= F_VOL ;
                  if (ap->mode == am_dreg && (!(flags & F_VOL) || ap->tempflag) &&
                           ((osize != 1 && osize != -1) || ap->preg < 4))
							ap2 = ap;
						else {
                     freeop(ap);
							ap2 = temp_data();
						}
						if (chksize(isize,osize)) {
							/* moving to a lower type */
                     if (isize > 6) {
								if (ap->mode != am_freg)
									floatload(ap,TRUE);
                        if (osize == 6 || osize == -6) {
                           freeop(ap2) ;
                           ap2 = floatconvpos() ;

                           memcpy(ap,ap2,sizeof(*ap)) ;
                           gen_codes(op_fistp,8,ap,0) ;
                           ap->length = 6 ;
                        } else if (osize < 6) {
									int pushed = FALSE;
									if (regs[0] && ap2->preg != 0) {
										pushed = 1;
										gen_push(EAX,am_dreg,0);
									}
									do_ftol() ;
									if (ap2->preg != 0)
										gen_codes(op_mov,4,ap2,makedreg(EAX));
									if (pushed)
										gen_pop(EAX,am_dreg,0);
									ap->mode = ap2->mode;
									ap->preg = ap2->preg;
									ap->tempflag = ap2->tempflag;
								} 	
								else {
									freeop(ap2);
									ap->mode = am_freg;
									ap->preg = 0;
									ap->tempflag = TRUE;
								}
							} 	
							else {
								if (ap->mode != am_dreg || ap->preg != ap2->preg)
                           if (isize == 6 || isize == -6)
                             if (ap->mode == am_axdx) {
                               if (ap2->preg != EAX) {
                                 regs[ap2->preg]-- ;
                                 regs[EAX]++ ;
                               }
                               ap2->mode = am_dreg ;
                               ap2->preg = EAX ;
                               ap2->tempflag = 1 ;
                             }else
                              gen_codes(op_mov,4,ap2,ap) ;
                           else
                             gen_codes(op_mov,isize,ap2,ap);
								
								ap->mode = ap2->mode;
								ap->preg = ap2->preg;
								ap->tempflag = ap2->tempflag;
							} 	
						}
						else {
							/* moving up in type */
                     if (isize > 6) {
								if (ap->mode != am_freg)
									floatload(ap,TRUE);
								freeop(ap2);
								ap->mode = am_freg;
								ap->preg = 0;
								ap->tempflag = TRUE;
                     } else if (isize == 6 || isize == -6) {
                        if (ap->mode == am_axdx) {
                           freeop(ap2) ;
                           ap1 = floatconvpos() ;
                           gen_codes(op_mov,4,ap1,makedreg(EAX)) ;
                           ap1->offset = makenode (en_add, ap1->offset,makeintnode(en_icon,4)) ;
                           gen_codes(op_mov,4,ap1,makedreg(EDX)) ;
                           freeop(ap) ;
                        } else
                           ap1 = ap ;
                        gen_codes(op_fild,8,ap1,0) ;
                        freeop(ap2) ;
                        ap->mode = am_freg ;
                        ap->preg = 0 ;

                     } else if (osize > 6) {
								if (isize != 4 && isize != -4) {
									ap1 = floatconvpos();
							  	if (isize < 0)
				 				  	gen_code2(op_movsx,4,isize,ap2,ap);
						  		else
						 	  		gen_code2(op_movzx,4,isize,ap2,ap);
									gen_codes(op_mov,4,ap1,ap2);
									gen_codefs(op_fild,4,ap1,0);
								}
								else
									if (ap->mode == am_direct || ap->mode == am_indisp || ap->mode == am_indispscale)
										gen_codefs(op_fild,4,ap,0);
									else {
										ap1 = floatconvpos();
										gen_codes(op_mov,4,ap1,ap);
										gen_codefs(op_fild,4,ap1,0);
									}
								freeop(ap2);
								ap->mode = am_freg;
								ap->preg = 0;
								ap->tempflag = TRUE;
                     } else {
                        int size6 = osize == 6  || osize == -6;
                        if (osize == 6 || osize == -6)
                           osize = 4 ;
                        if (ap->mode == am_dreg && ap->preg > 3 && (isize == 1 || isize == -1))
                           gen_codes(op_mov,4,ap2,ap) ;
                        if (size6 && (isize == 4 || isize == -4))
                           gen_codes(op_mov,isize,ap2,ap) ;
                        else if (isize < 0)
                           gen_code2(op_movsx,osize,isize,ap2,ap);
                        else
                           gen_code2(op_movzx,osize,isize,ap2,ap);
                        if (size6) {
                           freeop(ap2) ;
                           tempaxdx() ;
                           if (ap2->preg != EAX)
                              gen_codes(op_mov,4,makedreg(EAX),ap2) ;
                           if (isize < 0)
                              gen_code(op_cdq,0,0) ;
                           else
                              gen_codes(op_sub,4,makedreg(EDX), makedreg(EDX)) ;
                           ap->mode = am_axdx ;
                           ap->length = 6 ;
                           osize = 6 ;
                        } else {
                           ap->mode = am_dreg;
                           ap->preg = ap2->preg;
                           ap->tempflag = ap2->tempflag;
                        }
							}
						}
				}
				if (flags & (F_FREG | F_DREG)) {
					if (flags & F_DREG) {
						if (ap->mode != am_dreg || !ap->tempflag && (flags & F_VOL))
							if (isize == osize || isize == -osize || ap->mode == am_immed) {
                        if (osize < 7) {
                           freeop(ap);
									ap2 = temp_data();
									ap2->length = osize;
									gen_code(op_mov,ap2,ap);
									ap->mode = ap2->mode;
									ap->preg = ap2->preg;
									ap->tempflag = ap2->tempflag;
								} else {
                           if (ap->mode==am_immed)
                              make_floatconst(ap) ;
									floatload(ap,TRUE) ;
								}
							}
					}
					else if (ap->mode != am_freg) {
						if (ap->mode == am_immed)
							make_floatconst(ap);
						floatload(ap,TRUE);
					}
				}		
        if ((flags & F_AXDX) && !(flags & (F_MEM | F_IMMED)) && ap->mode != am_axdx)
           loadaxdx(ap) ;
        if (osize != isize && osize == 5) {
          int lab = nextlabel++;
          if (isize != 6 && isize != -6) {
               ap2 = temp_data();
               gen_codes(op_mov,ap->length,ap2,ap);
               gen_codes(op_or,ap->length,ap2,ap2) ;
          } else {
            if (ap->mode != am_axdx)
               loadaxdx(ap) ;
            gen_codes(op_or,4,makedreg(EAX),makedreg(EDX)) ;
            freeop(ap) ;
            ap2 = temp_data();
          }
          gen_codes(op_mov,4,ap2,make_immed(0)) ;
          gen_code(op_jz,make_label(lab),0);
          gen_codes(op_inc,1,ap2,0);
          gen_label(lab);
					freeop(ap);
					ap->mode = ap->mode;
					ap->tempflag = ap2->tempflag;
					ap->length = ap2->length;
					ap->preg = ap2->preg;
        }     
        ap->length = osize;
				if (osize == 5)
					ap->length = 1;
}

int     isshort(ENODE *node)
/*
 *      return true if the node passed can be generated as a short
 *      offset.
 */
{       return (isintconst(node->nodetype) &&
                (node->v.i >= -32768L && node->v.i <= 32767L));
}
														
int     isbyte(ENODE *node)
/*
 *      return true if the node passed can be evaluated as a byte
 *      offset.
 */
{       return isintconst(node->nodetype) &&
                (-128 <= node->v.i && node->v.i <= 127);
}

static int depth(ENODE *node)
{
				int a,b;
				if (!node)
					return 0;
        switch( node->nodetype )
                {
                        case en_cl_reg:
                             return depth(node->v.p[0]) ;
                        case en_cfi: case en_cfc:
                        case en_cri: case en_crc:
                        case en_clri: case en_clrc:
								case en_cl:
								case en_cul:
								case en_cp:
                case en_cbool:
								case en_cub:
								case en_cb:
								case en_cuw:
                case en_cw:
								case en_cd:
								case en_cld:
								case en_cf:
                        case en_cll:
                        case en_cull:
								case en_bits:
                        case en_ll_ref:
                        case en_ull_ref:
								case en_l_ref:
                case en_ul_ref:
                case en_ub_ref:
                case en_bool_ref:
                case en_b_ref:
                case en_uw_ref:
                case en_w_ref:
								case en_longdoubleref:
								case en_doubleref:
								case en_floatref:
                        case en_fimaginaryref: case en_rimaginaryref: case en_lrimaginaryref:
                        case en_fcomplexref: case en_rcomplexref: case en_lrcomplexref:
												return 1 + depth(node->v.p[0]);
                case en_uminus: 
                case en_ainc:   case en_adec: 
								case en_moveblock: case en_stackblock:
												return 1+depth(node->v.p[0]);
                case en_fimaginarycon: case en_rimaginarycon: case en_lrimaginarycon:
                case en_fcomplexcon: case en_rcomplexcon: case en_lrcomplexcon:
                case en_llcon:
                case en_llucon:
                case en_icon:
								case en_lcon: 
								case en_lucon: 
								case en_iucon: 
								case en_ccon:                 
								case en_rcon:
								case en_lrcon:
								case en_fcon:
								case en_absacon:
								case en_trapcall:
                case en_labcon:
                case en_nacon:  case en_autocon:  case en_autoreg:
                case en_napccon: case en_nalabcon:
								case en_tempref:
								case en_regref:
												return 1;
                case en_not:    case en_compl:
												return 1+depth(node->v.p[0]);
                case en_eq:     case en_ne:
                case en_lt:     case en_le:
                case en_gt:     case en_ge:
								case en_ugt: case en_uge: case en_ult: case en_ule:
                case en_land:   case en_lor:
								case en_div: case en_udiv: case en_pdiv: case en_mod: case en_umod:
                        case en_assign: case en_refassign: case en_lassign:
                        case en_asuminus: case en_ascompl:
                case en_add:    case en_sub: case en_addstruc:
								case en_umul:		case en_pmul:
                case en_mul:		case en_and:
                case en_or:     case en_xor:
								case en_asalsh: case en_asarsh: case en_alsh: case en_arsh: case en_arshd: case en_asarshd:
                case en_lsh:    case en_rsh:
                case en_asadd:  case en_assub:
                case en_asmul:  case en_asdiv:
                case en_asmod:  case en_asand:
								case en_asumod: case en_asudiv: case en_asumul:
                case en_asor:   case en_aslsh:  case en_asxor:
                case en_asrsh:  case en_repcons:
												a = depth(node->v.p[0]) ;
												b = depth(node->v.p[1]);
												if (a > b)
													return 1 + a;
												return 1 + b;
                case en_void:   case en_cond: case en_voidnz:
												return 1 + depth(node->v.p[1]);
								case en_sfcall: case en_sfcallb: case en_scallblock:
								case en_pfcall: case en_pfcallb: 
								case en_fcall: case en_intcall: case en_callblock: case en_fcallb:
								case en_pcallblock: case en_thiscall:
												return 1;
                default:
                        DIAG("error in depth routine.");
												return 1;
                }
}
	
void noids(AMODE *ap)
{
	if (ap->mode == am_indispscale)
      if (ap->length == 6 || ap->length == -6)
         do_extend(ap,ap->length,F_AXDX) ;
      else
         do_extend(ap,ap->length,F_DREG | F_VOL);
}
AMODE *indx_data(AMODE *ap)
{
   // we have to go to all this work to prevent accidental pops
   AMODE *ap3=0,ap4,ap5;
   int preg, sreg ;
   memset(&ap4,0,sizeof(ap4)) ;
   ap4.mode = am_none ;
   if (ap->mode != am_indispscale) {
      DIAG("indx_data: unscaled mode") ;
      freeop(ap);
      ap3 = temp_data();
   } else {
      if (ap->preg == -1) {
         if (ap->sreg >= 3) {
            freeop(ap) ;
            ap3 = temp_data() ;
         } else {
            ap3 = xalloc(sizeof(AMODE)) ;
            ap3->mode = am_dreg ;
            ap3->preg = ap->sreg ;
         }
      } else {
         if (ap->preg >= 3) {
            if (ap->sreg >= 3) {
               freeop(ap) ;
               ap3 = temp_data() ;
            } else {
               ap3 = xalloc(sizeof(AMODE)) ;
               ap3->mode = am_dreg ;
               ap3->preg = ap->sreg ;
            }
         } else {
            ap3 = xalloc(sizeof(AMODE)) ;
            ap3->mode = am_dreg ;
            ap3->preg = ap->preg ;
            ap4.mode = am_dreg ;
            ap4.preg = ap->sreg ;
         }
      }
   }
   ap3->length = 4 ;
   gen_codes(op_lea,4,ap3,ap);
   freeop(&ap4) ;
   ap3->mode = am_indisp;
   ap3->offset = makeintnode(en_icon,0);
   return ap3;
}
AMODE *doindex(ENODE *node, enum e_node type)
{
				AMODE *ap, *ap3;
				ENODE node2;
				int scale;
				switch (node->nodetype) {
					case en_icon:
						ap = gen_expr(node,FALSE,TRUE,4);
						break;
					case en_lsh:
						if ((scale = node->v.p[1]->v.i) < 4 && scale) {
							ap = gen_expr(node->v.p[0],FALSE,TRUE,4);
                     if (node->v.p[0]->nodetype == en_bits)
                        ap = bit_load(ap,node->v.p[0]) ;
							if (ap->mode != am_immed)
								do_extend(ap,4,F_DREG);
							if (ap->mode == am_immed) {
								while (--scale)
									ap->offset->v.i <<=1;
							}
							else {
								do_extend(ap,4,0);
								ap->mode = am_indispscale;
								ap->sreg = ap->preg;
								ap->preg = -1;
								ap->scale = scale;
                        ap->offset = makeintnode(en_icon,0);
							}
							break;
						}
					default:
						node2.v.p[0] = node;
						node2.nodetype = type;
						ap = gen_deref(&node2,4);
						switch (ap->mode) {
							default:
								break;
							case am_indispscale:
								if (ap->sreg >=0 && ap->preg >= 0) {
									ap = indx_data(ap);
								}
						}
						
						break;
				}
				return ap;
}
AMODE    *gen_index(ENODE *node)
/*
 *      generate code to evaluate an index node (^+) and return
 *      the addressing mode of the result. This routine takes no
 *      flags since it always returns either am_ind or am_indx.
 */
{       AMODE    *ap1,*ap2, *ap, *ap3;
				ENODE node2;

				int a = depth(node->v.p[1]) - depth(node->v.p[0]);
            int nsize ;
				if (a <= 2 ) {
					ap1 = doindex(node->v.p[0],node->nodetype);
               nsize = natural_size(node->v.p[1]) ;
               if (nsize == 6 || nsize == -6)
                  aprtocx(ap1) ;
					ap2 = doindex(node->v.p[1],node->nodetype);
				}
				else {
					ap2 = doindex(node->v.p[1],node->nodetype);
               nsize = natural_size(node->v.p[0]) ;
               if (nsize == 6 || nsize == -6)
                  aprtocx(ap2) ;
					ap1 = doindex(node->v.p[0],node->nodetype);
				}
				switch(ap1->mode) {
					case am_dreg:
						switch (ap2->mode) {
							case am_dreg:
								do_extend(ap1,4,0);
								ap1->sreg = ap2->preg;
								ap1->scale = 0;
								ap1->mode = am_indispscale;
                        ap1->offset = makeintnode(en_icon,0);
								return ap1;
							case am_immed:
							case am_direct:
								ap2->preg = ap1->preg;
								ap2->mode = am_indisp;
								return ap2;	
							case am_indisp:
								ap2->sreg = ap2->preg;
								ap2->preg = ap1->preg;
								ap2->mode = am_indispscale;
								ap2->offset = ap1->offset;
								ap2->scale = 0;
								return ap2;
							case am_indispscale:
								if (ap2->preg == -1) {
									ap2->preg = ap1->preg;
									return ap2;
								}
								ap = indx_data(ap2);
								ap->sreg = ap1->preg;
								ap->mode = am_indispscale;
								ap->scale = 0;
                        ap->offset = makeintnode(en_icon,0);
								return ap;
						}
						break;
					case am_direct:
					case am_immed:
						switch (ap2->mode) {
							case am_dreg:
								ap2->mode = am_indisp;
								ap2->offset = ap1->offset;
								return ap2;
							case am_immed:
							case am_direct:
								if (ap1->offset->nodetype == en_icon && ap2->offset->nodetype == en_icon)
									ap1->offset->v.i += ap2->offset->v.i;
								else
									ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
							  ap1->mode = am_direct;
								return ap1;
							case am_indisp:
							case am_indispscale:
								if (ap1->offset->nodetype == en_icon && ap2->offset->nodetype == en_icon)
									ap2->offset->v.i += ap1->offset->v.i;
								else
									ap2->offset = makenode(en_add,ap1->offset,ap2->offset);
								return ap2;
						}
						break;
					case am_indisp:
						switch (ap2->mode) {
							case am_dreg:
								ap1->mode = am_indispscale;
								ap1->sreg = ap2->preg;
								ap1->scale = 0;
								return ap1;
							case am_immed:
							case am_direct:
								if (ap1->offset->nodetype == en_icon && ap2->offset->nodetype == en_icon)
									ap1->offset->v.i += ap2->offset->v.i;
                        else {
									ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
                        }
								return ap1;	
							case am_indisp:
								ap1->mode = am_indispscale;
								ap1->sreg = ap2->preg;
								ap1->scale = 0;
								if (ap1->offset->nodetype == en_icon && ap2->offset->nodetype == en_icon)
									ap1->offset->v.i += ap2->offset->v.i;
								else
									ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
								return ap1;
							case am_indispscale:
								if (ap2->preg == -1) {
									ap2->preg = ap1->preg;
									if (ap1->offset->nodetype == en_icon && ap2->offset->nodetype == en_icon)
										ap2->offset->v.i += ap1->offset->v.i;
									else
										ap2->offset = makenode(en_add,ap1->offset,ap2->offset);
									return ap2;
								}
								ap = indx_data(ap2);
								ap1->sreg = ap->preg;
								ap1->scale = 0;
								ap1->mode = am_indispscale;
								if (ap1->offset->nodetype == en_icon && ap2->offset->nodetype == en_icon)
									ap1->offset->v.i += ap2->offset->v.i;
								else
									ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
								return ap1;
						}
						break;
					case am_indispscale:
						switch (ap2->mode) {
							case am_dreg:
								if (ap1->preg == -1) {
									ap1->preg = ap2->preg;
									return ap1;
								}
								ap = indx_data(ap1);
								ap->sreg = ap2->preg;
								ap->scale = 0;
								ap->offset = ap1->offset;
								return ap;
							case am_immed:
							case am_direct:
								if (ap1->offset->nodetype == en_icon && ap2->offset->nodetype == en_icon)
									ap1->offset->v.i += ap2->offset->v.i;
								else
									ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
								return ap1;
							case am_indisp:
								if (ap1->preg == -1) {
									ap1->preg = ap2->preg;
									if (ap1->offset->nodetype == en_icon && ap2->offset->nodetype == en_icon)
										ap1->offset->v.i += ap2->offset->v.i;
									else
										ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
									return ap1;
								}
								ap = indx_data(ap1);
								ap->sreg = ap2->preg;
								ap->scale = 0;
								ap->mode = am_indispscale;
								if (ap1->offset->nodetype == en_icon && ap2->offset->nodetype == en_icon)
									ap->offset->v.i = ap2->offset->v.i +ap1->offset->v.i;
								else
									ap->offset = makenode(en_add,ap1->offset,ap2->offset);
								return ap;
							case am_indispscale:
								if (ap1->preg == -1 && ap2->preg == -1) {
									if (ap1->scale == 0) {
										ap2->preg = ap1->sreg;
										if (ap1->offset->nodetype == en_icon && ap2->offset->nodetype == en_icon)
											ap2->offset->v.i += ap1->offset->v.i;
										else
											ap2->offset = makenode(en_add,ap1->offset,ap2->offset);
										return ap2;
									} else if (ap2->scale == 0) {
										ap1->preg = ap2->sreg;
										if (ap1->offset->nodetype == en_icon && ap2->offset->nodetype == en_icon)
											ap1->offset->v.i += ap2->offset->v.i;
										else
											ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
										return ap1;
									}
								}
								if (ap1->preg == -1) {
									ap = indx_data(ap2);
									ap1->preg = ap->preg;
									return ap1;
								}
								else if (ap2->preg == -1) {
									ap = indx_data(ap1);
									ap2->preg = ap->preg;
									return ap2;
								}
								ap = indx_data(ap1);
								ap1 = indx_data(ap2);
								ap->mode = am_indispscale;
								ap->sreg = ap1->preg;
								ap->scale = 0;
                        ap->offset = makeintnode(en_icon,0);
								return ap;
						}
						break;           
				}
				DIAG("invalid index conversion");
				return 0;
}

AMODE    *gen_deref(ENODE *node, int size)
/*
 *      return the addressing mode of a dereferenced node.
 */
{       AMODE    *ap1;
        int             siz1;
        switch( node->nodetype )        /* get load size */
                {
                case en_bool_ref:
                case en_ub_ref:
                        siz1 = 1;
                        break;
                case en_b_ref:
                        siz1 = -1;
                        break;
                case en_uw_ref:
                        siz1 = 2;
                        break;
                case en_w_ref:
                        siz1 = -2;
                        break;
                case en_l_ref:
												siz1 = -4;
												break;
								case en_ul_ref:
                        siz1 = 4;
                        break;
                        case en_ull_ref:
                           siz1 = 6 ;
                           break ;
                        case en_ll_ref:
                           siz1 = -6 ;
                           break ;
								case en_floatref:
                                    siz1 = 7;
												break;
								case en_doubleref:
												siz1 = 8;
												break;
								case en_longdoubleref:
												siz1 = 10;
												break;
                        case en_fimaginaryref: 
                                    siz1 = 15;
												break;
                        case en_rimaginaryref: 
                                    siz1 = 16;
												break;
                        case en_lrimaginaryref:
                                    siz1 = 17;
												break;
                        case en_fcomplexref: 
                                    siz1 = 20;
												break;
                        case en_rcomplexref: 
                                    siz1 = 21;
												break;
                        case en_lrcomplexref:
                                    siz1 = 22;
												break;
								default:
												siz1 = 4;
                }
        if( node->v.p[0]->nodetype == en_add || node->v.p[0]->nodetype == en_addstruc)
                {
                	ap1 = gen_index(node->v.p[0]); 
									ap1->length = siz1;
                	return ap1;
								}
				else if( node->v.p[0]->nodetype == en_autocon  || node->v.p[0]->nodetype == en_autoreg)
                {
								SYM *sp = node->v.p[0]->v.sp;
								int i = sp->value.i;
                ap1 = xalloc(sizeof(AMODE));
                ap1->mode = am_indisp;
			          ap1->preg = EBP;
#ifdef CPLUSPLUS
								if ((currentfunc->value.classdata.cppflags & PF_MEMBER) &&
											!(currentfunc->value.classdata.cppflags & PF_STATIC) && i > 0)
									i += 4;
#endif
                   ap1->offset = makeintnode(en_icon,i);
								ap1->length = siz1;
                return ap1;
                }
        else if( node->v.p[0]->nodetype == en_nacon || node->v.p[0]->nodetype == en_napccon)
                {
                ap1 = xalloc(sizeof(AMODE));
                ap1->offset = makenode(node->v.p[0]->nodetype,(void *)node->v.p[0]->v.sp,0);
                ap1->mode = am_direct;
								ap1->length = siz1;
                return ap1;
                }
        else if( node->v.p[0]->nodetype == en_nalabcon)
                {
                ap1 = xalloc(sizeof(AMODE));
                ap1->offset = makenode(node->v.p[0]->nodetype,node->v.p[0]->v.sp,0);
                ap1->mode = am_direct;
								ap1->length = siz1;
                return ap1;
                }
        else if( node->v.p[0]->nodetype == en_labcon)
                {
                ap1 = xalloc(sizeof(AMODE));
                ap1->mode = am_direct;
                ap1->offset = makeintnode(node->v.p[0]->nodetype,node->v.p[0]->v.i);
								ap1->length = siz1;
                return ap1;
                }
				else if (node->v.p[0]->nodetype == en_absacon) {
								ap1 = xalloc(sizeof(AMODE));
								ap1->mode = am_direct;
                        ap1->seg = 2 ;
                        ap1->offset = makeintnode(en_absacon,node->v.p[0]->v.sp->value.i);
								ap1->length = siz1;
                return ap1;

				}
				else if (node->v.p[0]->nodetype == en_regref) {
         ap1 = gen_expr(node->v.p[0],FALSE,TRUE,siz1);
					return ap1;
				}
        ap1 = gen_expr(node->v.p[0],FALSE,TRUE,4); /* generate address */
				if (ap1->mode != am_immed) {
					do_extend(ap1,4,F_DREG);
				}
				ap1->length = siz1;
        if( ap1->mode == am_dreg )
                {
                ap1->mode = am_indisp;
                        ap1->offset = makeintnode(en_icon,0);
                return ap1;
                }
				else if (ap1->mode == am_stackedtemp) {
                ap1->mode = am_stackedtempaddr;
                return ap1;
				}
        ap1->mode = am_direct;
        ap1->seg = 2 ;
        return ap1;
}

void get_size(AMODE *ap1, AMODE *ap2,int size)
{
   if (size > 6)
		size = 4;
   if (chksize(size,ap1->length)) {
      if (!chksize(size,ap2->length))
         size = ap2->length ;
   } else
      if (chksize(ap1->length,ap2->length))
         size = ap1->length ;
      else
         size = ap2->length ;
   if (ap1->length >0 || ap2->length >0 && size < 0)
      size = - size ;
	if (size) {
      if (ap1->mode == am_immed && (ap1->length <= 4 || ap1->length == 6))
			ap1->length = size;
      else
         do_extend(ap1,size ,0);
      if (ap2->mode == am_immed && (ap2->length <= 4 || ap2->length == 6))
			ap2->length = size;
      else
         do_extend(ap2,size ,0);
	}
	
}
void small_size(AMODE *ap1, AMODE *ap2, int size)
{
   if (ap1->length <= 6 && ap2->length <= 6 && chksize(ap2->length, ap1->length)) {
      if ((ap2->mode != am_dreg || ap2->preg < 4) && (ap2->length != 6 && ap2->length != -6))
			ap2->length = ap1->length;
		else
			do_extend(ap2,ap1->length,0) ;
   } else
		get_size(ap1,ap2,size);
}
int assign_size(ENODE *node, int size)
{
   int rsize = natural_size(node) ;
   int neg = 0;
   if (rsize < 0)
      neg = -1 ;
   if (chksize(size, rsize))
      if (size < 6 && size != -6)
         rsize = size ;
      else if (rsize < 6 && rsize != -6)
         rsize = 4*neg ;
      else if (rsize != 6 && rsize != -6)
         rsize = size ;
      
   return rsize ;
}
void resolve_binary(ENODE *node,AMODE **ap1, AMODE **ap2, int size)
{
  	*ap2 = gen_expr(node->v.p[1],FALSE,FALSE, size);
		noids(*ap2);
  	*ap1 = gen_expr(node->v.p[0],FALSE,FALSE, size);
		get_size(*ap1,*ap2,size);
}
static int isbit(ENODE *node)
{
	return node->nodetype == en_bits;
}
static int as_args(ENODE *node,AMODE **apr,AMODE **ap1,AMODE **ap2, int size,int shift)
{
	int rv = isbit(node->v.p[0]);
   int rsize = assign_size(node->v.p[1],size) ;
   *ap2 = gen_expr(node->v.p[1],FALSE,FALSE,rsize);
	noids(ap2);
	*apr = gen_expr(node->v.p[0],FALSE,TRUE,size);
	if (rv)
		*ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size);
	else
		*ap1 = copy_addr(*apr);
	return rv;
}
static int prefer(ENODE *node,AMODE **ap2, AMODE **ap3, int op, int dosizing, int size)
{                   
	AMODE *ap2x, *ap3x;
	int rv = 0;
	int a = depth(node->v.p[1]) - depth(node->v.p[0]);
	if (a <= 2 ) {
  	ap2x = gen_expr(node->v.p[0],FALSE,FALSE,size);
		noids(ap2x);
  	ap3x = gen_expr(node->v.p[1],FALSE,FALSE,size);
		if (dosizing)
			get_size(ap2x,ap3x,size);
	}
	else {
  	ap3x = gen_expr(node->v.p[1],FALSE,FALSE,size);
		noids(ap3x);
  	ap2x = gen_expr(node->v.p[0],FALSE,FALSE,size);
		if (dosizing)
			get_size(ap2x,ap3x,size);
	}
	*ap3 = ap3x;
	*ap2 = ap2x;
	if (ap2x->mode != am_dreg || !ap2x->tempflag) {
		if (op != op_sub && op != op_div) {
		  if (ap3x->mode == am_dreg && ap3x->tempflag) {
				*ap3 = ap2x;
				*ap2 = ap3x;
				rv = !rv;
			}
			else
				if (ap2x->mode == am_immed) {
					*ap3 = ap2x;
					*ap2 = ap3x;
					rv = !rv;
			}
		}
	}		
	return rv;
}
AMODE    *gen_unary(ENODE *node,int op, int fop, int size)
/*
 *      generate code to evaluate a unary minus or complement.
 */
{       AMODE    *ap;
				int xchg;
        ap = gen_expr(node->v.p[0],FALSE,FALSE,size);
            if (size > 6) {
					do_extend(ap,10,F_FREG | F_VOL);
					gen_code(fop,0,0);
					ap = fstack();
            } else {
              if (size == 0)
                size = natural_size(node->v.p[0]) ;
              if (size == 6 || size == -6) {
                do_extend(ap,size,F_AXDX) ;
                gen_code(op,makedreg(EDX),0) ;
                gen_code(op,makedreg(EAX),0) ;
                if (op == op_neg)
                  gen_code(op_sbb,makedreg(EDX),make_immed(0)) ;
              } else  {
                do_extend(ap,size,F_DREG | F_VOL);
                gen_code(op,ap,0);
              }
				}
        return ap;
}
AMODE *gen_fbinary(ENODE *node,int fop, int fopp, int fopr,int foppr,int size, AMODE **apr)
{
		AMODE *ap1,*ap2;
      int bits ;
      if (apr)
         bits = as_args(node,apr,&ap1,&ap2,natural_size(node->v.p[0]),0) ;
      else if (fop == op_fdiv || fop == op_fsub) {
         ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size);
		  do_extend(ap1,10,F_FREG);
         ap2 = gen_expr(node->v.p[1],FALSE,FALSE,size);
		}
		else {
			prefer(node,&ap1,&ap2,fop,FALSE,size);
		}
		if (ap1->mode == am_immed)
			make_floatconst(ap1);
		if (ap2->mode == am_immed)
			make_floatconst(ap2);
		floatload(ap1,FALSE);
    floatload(ap2,FALSE);
		if (ap1->mode != am_freg && ap2->mode != am_freg)
			do_extend(ap1,10,F_FREG | F_VOL);
		if (ap1->mode == am_freg) {
			if (ap2->mode == am_freg) {
				gen_codef(fopp,makefreg(1),0);             	
			}
			else if (ap2->length == 10) {
				do_extend(ap2,10,F_FREG);
				gen_codef(fopp,makefreg(1),0);             	
			}
			else if (ap2->mode == am_dreg) {
				do_extend(ap2,10,F_FREG);
				gen_codef(fopp,makefreg(1),0);             	
			}
         else if (ap2->length < 7) {
				do_extend(ap2,10,F_FREG);
				gen_codef(fopp,makefreg(1),0);             	
			}
			else
				gen_code(fop,ap2,0);
		} else if (ap2->mode == am_freg) {
			if (ap1->length == 10) {
				do_extend(ap1,10,F_FREG);
				gen_codef(foppr,makefreg(1),0);             	
			}
			else if (ap1->mode == am_dreg) {
				do_extend(ap1,10,F_FREG);
				gen_codef(foppr,makefreg(1),0);             	
			}
         else if (ap1->length < 7) {
				do_extend(ap1,10,F_FREG);
				gen_codef(fopp,makefreg(1),0);             	
			}
			else
				gen_code(fopr,ap1,0);
		} 
		ap1 = fstack();
		return ap1;
}

AMODE *gen_6bin(ENODE *node, int op, int size)
{       AMODE    *ap1, *ap2,*ap3,*ap4 ;
            int pushed = FALSE ;

            ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size) ;
            if (size < 6 && size > -6 && ap1->length != 6 && ap1->length != -6)
               do_extend(ap1,size,F_DREG | F_VOL) ;
            else
               do_extend(ap1,6,F_AXDX) ;
            ap2 = gen_expr(node->v.p[1],FALSE,FALSE,natural_size(node->v.p[1])) ;
            do_extend(ap2,size,0) ;
               
            if (ap2->mode == am_immed) {
               ap3 = make_immed(ap2->offset->v.i & 0xffffffffL) ;
#if sizeof(ULLONG_TYPE) == 4
               ap4 = make_immed(ap2->offset->v.i < 0 ? -1 : 0) ;
#else
               ap4 = make_immed(ap2->offset->v.i >> 32) ;
#endif
            } else if (ap1->mode == am_axdx && ap2->mode == am_axdx) {
               ap3 = make_stack(0) ;
               ap4 = make_stack(-4) ;
            } else {
               ap2->length = 4 ;
               ap3 = ap2 ;
               ap4 = copy_addr(ap3) ;
               ap4->offset = makenode(en_add,ap4->offset,makeintnode(en_icon,4)) ;
            }
            if (size < 6 && size > -6) {
               gen_code(op,ap1,ap2) ;
            } else if (ap1->mode == am_axdx && ap2->mode == am_axdx) {
               gen_code(op,ap3,makedreg(EAX)) ;
               if (op == op_add)
                  gen_code(op_adc,ap4,makedreg(EDX)) ;
               else if (op == op_sub)
                  gen_code(op_sbb,ap4,makedreg(EDX)) ;
               else
                  gen_code(op,ap4,makedreg(EDX)) ;
            } else {
               gen_code(op,makedreg(EAX),ap3) ;
               if (size >= 6 || size == -6)
                  if (op == op_add)
                     gen_code(op_adc,makedreg(EDX),ap4) ;
                  else if (op == op_sub)
                     gen_code(op_sbb,makedreg(EDX),ap4) ;
                  else
                     gen_code(op,makedreg(EDX),ap4) ;
           }
           freeop(ap2) ;
           return ap1 ;
}
AMODE    *gen_xbin(ENODE *node,int op,int op2, int size)
/*
 *      generate code to evaluate a restricted binary node and return 
 *      the addressing mode of the result.
 *		  restriction is: integers only.  We also use this for add,sub,mul
 */
{       AMODE    *ap1, *ap2, *ap3;
         int nsize = natural_size(node) ;
            if (nsize == 6 || nsize == -6)
               return gen_6bin(node,op,nsize) ;
            prefer(node,&ap1,&ap2,op,TRUE,nsize);
				if (op == op_sub) {
					do_extend(ap1,ap1->length,F_DREG | F_VOL);
				}
				else {
					if ((ap1->mode != am_dreg) || !ap1->tempflag) {
						if (ap2->mode == am_dreg && ap2->tempflag) {
							ap3 = ap1;
							ap1 = ap2;
							ap2 = ap3;
						}
						else {
							int vb;
							do_extend(ap1,ap1->length,F_DREG | F_VOL);
							if (ap2->mode == am_immed) {
								if (op == op_and && (vb = single_bit(~ap2->offset->v.i)) != -1) {
									gen_codes(op2,4,ap1,make_immed(vb));                        	
									return ap1;
								}
								else if ((op == op_or || op == op_xor ) && (vb = single_bit(ap2->offset->v.i))!= -1) {
									gen_codes(op2,4,ap1,make_immed(vb));
									return ap1;
								}
							}
						}
					}
				}
     		gen_code(op,ap1,ap2);
				freeop(ap2);
				return(ap1);
}
AMODE    *gen_binary(ENODE *node,int op, int fopp, int fop, int foppr, int fopr, int size)
/*
 *      generate code to evaluate a binary node and return 
 *      the addressing mode of the result.
 */
{
            if (natural_size(node) > 6)
               return gen_fbinary(node,fop,fopp,fopr,foppr, size,0);
            else
					return gen_xbin(node,op,0,size);
}
void doshift(AMODE *ap1, AMODE *ap2, int op, int div, int size)
{       AMODE   *ecx = makedreg(ECX),*ap3;
				freeop(ap2);
				if (div) {
               switch(size) {
						case 1:
						case -1:
							gen_code(op_test,ap1,make_immed(0x80)) ;
							gen_code(op_je,make_label(nextlabel),0);
						case 2:
						case -2:
							gen_code(op_test,ap1,make_immed(0x8000)) ;
							gen_code(op_je,make_label(nextlabel),0);
							break ;
						case 4:
						case -4:
						default:
							if (ap2->mode == am_immed && ap2->offset->v.i == 1 && ap1->mode == am_dreg) {
								gen_code(op_sar,ap1,ap2);
								gen_code(op_jns,make_label(nextlabel),0);
								gen_code(op_adc,ap1,make_immed(0));
								gen_label(nextlabel++);
								return ;
							} else {
								if (ap1->mode == am_dreg)
									gen_code(op_test,ap1,ap1) ;
								else
									gen_code(op_test,ap1,make_immed(0x80000000));
								gen_code(op_jns,make_label(nextlabel),0);
								break ;
							}
					}
               if (ap2->mode == am_immed) {
						AMODE *ap3 = copy_addr(ap2) ;
                  ap3->offset = makeintnode(en_icon,((1<<ap2->offset->v.i)-1));
						ap3->length = ap2->length ;
						gen_code(op_add,ap1,ap3);
					} else {
/* FIXME - this won't work. */
						gen_code(op_add,ap1,ap2) ;
						gen_code(op_dec,ap1,0);
					}
					gen_label(nextlabel++);
				}
				if (ap2->mode == am_immed) {
                 gen_codes2(op,1,ap1,ap2);
            } else if (ap2->mode == am_dreg) {
						if (ap2->preg != ECX) {
							if (regs[1]) {
								gen_codes(op_xchg,4,ap2,ecx);
		 						if (equal_address(ap1,ap2))
									gen_codes(op,1,ecx,ecx);
								else
                           gen_code2(op,ap1->length,1,ap2,ecx);
								if (!regs[ap2->preg] && ap1->mode == am_dreg && ap1->tempflag) {
									freeop(ap1);
									regs[ap2->preg]++;
									ap1->preg = ap2->preg;
									ap1->tempflag = ap2->tempflag;
									return;
									
								}
								else	
									gen_codes(op_xchg,4,ap2,ecx);
							}
							else {
								gen_codes(op_mov,4,ecx,ap2);
		 						if (equal_address(ap1,ap2))
									gen_codes(op,1,ecx,ecx);
								else
                           gen_code2(op,4,1,ap1,ecx);
							}
						}
						else
							gen_codes2(op,1,ap1,ecx);
					}
					else {
							if (regs[1])
								gen_push(ECX,am_dreg,0);
                     gen_codes(op_mov,1,ecx,ap2);
							if (ap1->mode == am_dreg && ap1->preg == ECX) {
								AMODE *ap3 = xalloc(sizeof(AMODE)) ;
								ap3->mode = am_indisp ;
								ap3->preg = ESP ;
                        ap3->offset = makeintnode(en_icon,0) ;
								ap3->length = ap1->length ;
								gen_codes2(op,1,ap3,ecx) ;
							} else {
						  	gen_codes2(op,1,ap1,ecx);
							}

							if (regs[1])
								gen_pop(ECX,am_dreg,0);
					}
					freeop(ap2);
}
AMODE *do6shift(ENODE *node, int novalue, int op, int div, int size)
{       AMODE   *ecx = makedreg(ECX),*ap1=0,*ap2,*ap3;
         LLONG_TYPE t ;
            ap2 = gen_expr(node->v.p[1],FALSE,FALSE,4) ;
            if (div) { // if we get in here ap2 is a const ...
               ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size) ;
               do_extend(ap1,size,F_AXDX) ;
               gen_code(op_test,makedreg(EDX),make_immed(0x80000000)) ;
               gen_code(op_je,make_label(nextlabel),0);
               {
                  AMODE *ap3 = copy_addr(ap2) ;
                  AMODE *ap4 = copy_addr(ap2) ;

                  t = (1 << ap2->offset->v.i)-1 ;
#if sizeof(ULLONG_TYPE) == 4
                  ap3->offset = makeintnode(en_icon, t < 0 ? -1 : 0) ;
#else
                  ap3->offset = makeintnode(en_icon,t>>32);
#endif
                  ap4->offset = makeintnode(en_icon,t) ;
                  ap3->length = ap2->length ;
                  ap4->length = ap2->length ;
                  gen_code(op_add,makedreg(EAX),ap4);
                  gen_code(op_adc,makedreg(EDX),ap3) ;
               }
					gen_label(nextlabel++);
				}
				if (ap2->mode == am_immed) {
               if (size == 6 || size == -6 || ap1->mode == am_axdx) {
                  if (!ap1)
                     ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size) ;
                  do_extend(ap1,size,F_AXDX) ;
                  if (ap2->offset->v.i >= 32) {
                     if (op == op_shr || op == op_sar) {
                        gen_code(op_mov,makedreg(EAX),makedreg(EDX)) ;
                        if (ap2->offset->v.i != 32 )
                           gen_code(op,makedreg(EAX),make_immed(ap2->offset->v.i-32)) ;
                        if (op == op_sar)
                           gen_code(op_cdq,0,0) ;
                        else
                           gen_code(op_sub,makedreg(EDX),makedreg(EDX)) ;
                     } else {
                        gen_code(op_mov,makedreg(EDX),makedreg(EAX)) ;
                        if (ap2->offset->v.i != 32 )
                          gen_code(op,makedreg(EDX),make_immed(ap2->offset->v.i-32)) ;
                        gen_code(op_sub,makedreg(EAX),makedreg(EAX)) ;
                     }
                  }
                  else if (ap2->offset->v.i) {
                    if (op == op_shr || op == op_sar) {
                       gen_code3(op_shrd,makedreg(EAX),makedreg(EDX),make_immed(ap2->offset->v.i)) ;
                       gen_code(op,makedreg(EDX), make_immed(ap2->offset->v.i)) ;
                    } else {
                       gen_code3(op_shld,makedreg(EDX),makedreg(EAX),make_immed(ap2->offset->v.i)) ;
                       gen_code(op,makedreg(EAX), make_immed(ap2->offset->v.i)) ;
                    }
                  }
               }
				}
            else {
                  int xchg = -1 ;
                  int pushed = FALSE ;
                  if (regs[ECX] && ap2->mode != am_dreg && ap2->preg != ECX) {
                     pushed = TRUE ;
                     gen_push(ECX,am_dreg,0) ;
                  }
                  if (ap2->mode == am_axdx)
                     gen_push(EAX,am_dreg,0) ;
                  else {
                     gen_codes(op_push,4,ap2,0) ;
                  }
                  freeop(ap2) ;
                  if (!ap1)
                     ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size) ;
                  if (ap1->mode == am_axdx) {
                     gen_push(EDX,am_dreg,0) ;
                     gen_push(EAX,am_dreg,0) ;
                  } else {
                     ap2 = copy_addr(ap1) ;
                     ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,4)) ;
                     gen_codes(op_push,4,ap2,0) ;
                     gen_codes(op_push,4,ap1,0) ;
                  }
                  freeop(ap1) ;
                  if (op == op_shr)
                     call_library("__LXSHR") ;
                  else if (op == op_sar)
                     call_library("__LXSAR") ;
                  else
                     call_library("__LXSHL") ;
                  if (pushed) 
                     gen_pop(ECX,am_dreg,0) ;
                  regs[EDX] ++ ;
                  regs[EAX] ++ ;
					}
               ap1 = xalloc(sizeof(AMODE)) ;
               ap1->mode = am_axdx ;
               ap1->length = 6 ;
               return ap1 ;
}
AMODE    *gen_shift(ENODE *node, int op,int size, int div)
/*
 *      generate code to evaluate a shift node and return the
 *      address mode of the result.
 */
{       AMODE    *ap1, *ap2;

        if (size == 6 || size == -6)
            return do6shift(node, FALSE, op,div,size) ;
        ap2 = gen_expr(node->v.p[1],FALSE,FALSE,size);
            noids(ap2);
        ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size);
        if (size != 6 && size != -6)
				do_extend(ap1,4,F_DREG | F_VOL);
        if (ap2->length <= 6)
            ap2->length = 4;
        else
            do_extend(ap2,4,0) ;
        doshift(ap1,ap2,op, div,size);
        return ap1;
}
void divprepare(int op, int size) 
{
   AMODE *ah ;
				if (op == op_idiv)
               switch(size) {
                  case -1:
                  case 1:
                     gen_code(op_cbw,0,0);
                     break ;
                  case 2:
                  case -2:
                     gen_code(op_cwd,0,0) ;
                     break ;
                  case -4:
                  case 4:
                     gen_code(op_cdq,0,0);
                     break ;
               }
				else
               switch(size) {
                  case -1:
                  case 1:
                     ah = makedreg(4);
                     gen_codes(op_sub,1,ah,ah);
                     break ;
                  case 2:
                  case -2:
                     gen_codes(op_sub,2,makedreg(EDX),makedreg(EDX));
                     break ;
                  case -4:
                  case 4:
                     gen_codes(op_sub,4,makedreg(EDX),makedreg(EDX));
                     break ;
               }
}
void divintoeax(AMODE *ap1, int size, int op, int modflag)
{
	AMODE *eax = makedreg(EAX), *edx = makedreg(EDX), *ecx = makedreg(ECX);
	AMODE *ah = makedreg(4);
	int pushdx = FALSE, pushcx = FALSE;
			if ((ap1->mode == am_dreg || ap1->mode == am_indisp || ap1->mode == am_indispscale) && ap1->preg == EDX
					|| ap1->mode == am_indispscale && ap1->sreg == EDX) {
				if (size > 1) {
					if (regs[1]) {
						gen_push(ECX,am_dreg,1);
						pushcx = 1;
					}
					gen_codes(op_mov,size,makedreg(ECX),ap1);
				}
            divprepare(op,size) ;
				gen_codes(op,size,ecx,0);
				if (pushcx)
					gen_pop(ECX,am_dreg,0);
			}
			else {
				if (regs[2] && size > 1) {
					gen_push(EDX,am_dreg,1);
					pushdx = 1;
				}
            divprepare(op,size) ;
				gen_codes(op,size,ap1,0);
			}
eaxjoin:
			ap1->mode = am_dreg;
			ap1->preg = EAX;
			ap1->tempflag = TRUE;
			ap1->length = size;
			if (modflag)
				if (size == 1) {
					gen_codes(op_mov,1,eax,ah);
					regs[0]++;
				}
				else if (pushdx) {
					gen_code(op_mov,eax,edx);
					regs[0]++;
				}
				else {
					regs[2]++;
					ap1->preg = EDX;
				}
			else
				regs[0]++;
			if (pushdx)
				gen_pop(EDX,am_dreg,0);
}
void dodiv(AMODE *ap1, AMODE *ap2, int op,int modflag)
{
	AMODE *eax = makedreg(EAX), *edx = makedreg(EDX), *ecx = makedreg(ECX);
	AMODE *ah = makedreg(4);
	int size = ap1->length,pushax = FALSE;
	ah->length = 1;
	if (size < 0)
		size = -size;
	if (ap2->mode == am_immed) {
		ap2 = make_muldivval(ap2);
	}
	/* divide by self */
	if (ap2->mode == am_dreg && ap1->preg == ap2->preg) {
		if (modflag)
			gen_codes(op_sub,4,ap2,ap2);
		else
			gen_codes(op_mov,4,ap2,make_immed(1));
		return;
	}
	freeop(ap1);
	freeop(ap2);
	switch (ap1->preg) {
		case ESI:
		case EDI:
		case EBX:
			/* only gets here if /= with source reg */
		case EDX:
		case ECX:
			if (ap2->mode == am_dreg && ap2->preg == EAX) {
				gen_codes(op_xchg,4,ap2,ap1);
				divintoeax(ap1,size,op,modflag);
				break;
			}
			if (regs[0]) {
				gen_push(EAX,am_dreg,1);
				pushax = TRUE;
			}
			gen_codes(op_xchg,4,eax,ap1);
			if (ap2->mode == am_indisp && ap2->preg == EAX)
				ap2->preg = ap1->preg;
			else if (ap2->mode == am_indispscale) {
				if (ap2->preg == EAX)
					ap2->preg = ap1->preg;
				if (ap2->sreg == EAX)
					ap2->sreg = ap1->preg;
			}
			divintoeax(ap2,size,op,modflag);
			if (pushax && ap2->preg == EAX)
				gen_codes(op_mov,4,ap1,eax);
			else {
				ap1->preg = ap2->preg;
				ap1->length = ap2->length;
				ap1->mode = ap2->mode;
			}
			if (pushax)
				gen_pop(EAX,am_dreg,0);
			break;
		case EAX:
			/* case for eax/val */
			divintoeax(ap2,size,op,modflag);
			ap1->preg = ap2->preg;
			ap1->length = ap2->length;
			ap1->mode = ap2->mode;
			break;
	}
}
AMODE *do6div(ENODE *node,int op,int modflag,int size) 
{
   AMODE *ap1, *ap2 ;
   int regax,regdx,regcx ;
   int pushed = 0 ;
   tempaxdx() ;
   if (regs[ECX]) {
      gen_push(ECX,am_dreg,FALSE) ;
      pushed = 1 ;
   }
   regax = regs[EAX] ;
   regdx = regs[EDX] ;
   regcx = regs[ECX] ;
   set_func_mode(1) ;
   regs[0] = regs[1] = regs[2] = 0 ;
   ap1 = gen_expr(node->v.p[1],FALSE,FALSE,size) ;
   if (ap1->mode != am_immed)
      do_extend(ap1,size,0) ;
   noids(ap1) ;
   if (ap1->mode == am_axdx) {
      gen_code(op_push,makedreg(EDX),0) ;
      gen_code(op_push,makedreg(EAX),0) ;
   } else if (ap1->mode == am_immed) {
#if sizeof(ULLONG_TYPE) == 4
      gen_code(op_push,make_immed(ap1->offset->v.i < 0 ? -1 : 0),0) ;
#else
      gen_code(op_push,make_immed(ap1->offset->v.i >> 32),0) ;
#endif
      gen_code(op_push,make_immed(ap1->offset->v.i & 0xffffffffL),0) ;
   } else {
      AMODE *ap2 ;
      ap1->length = 4 ;
      ap2 = copy_addr(ap1) ;
      ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,4)) ;
      gen_code(op_push,ap2,0) ;
      gen_code(op_push,ap1,0) ;
   }
   if (ap1->mode == am_axdx) {
      regs[EDX] -- ;
      regs[EAX] -- ;
   } else
      freeop(ap1) ;
   ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size) ;
   if (ap1->mode != am_immed)
      do_extend(ap1,size,0) ;
   noids(ap1) ;
   if (ap1->mode == am_axdx) {
      gen_code(op_push,makedreg(EDX),0) ;
      gen_code(op_push,makedreg(EAX),0) ;
   } else if (ap1->mode == am_immed) {
#if sizeof(ULLONG_TYPE) == 4
      gen_code(op_push,make_immed(ap1->offset->v.i < 0 ? -1 : 0),0) ;
#else
      gen_code(op_push,make_immed(ap1->offset->v.i >> 32),0) ;
#endif
      gen_code(op_push,make_immed(ap1->offset->v.i & 0xffffffffL),0) ;
   } else {
      AMODE *ap2 ;
      ap1->length = 4 ;
      ap2 = copy_addr(ap1) ;
      ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,4)) ;
      gen_code(op_push,ap2,0) ;
      gen_code(op_push,ap1,0) ;
   }
   if (ap1->mode == am_axdx) {
      regs[EDX] -- ;
      regs[EAX] -- ;
   } else
      freeop(ap1) ;
   if (op==op_idiv)
      if (modflag)
         call_library("__LXMODS") ;
      else
         call_library("__LXDIVS") ;
   else
      if (modflag)
         call_library("__LXMODU") ;
      else
         call_library("__LXDIVU") ;
   regs[EAX] = regax ;
   regs[EDX] = regdx ;
   regs[ECX] = regcx ;
   set_func_mode(0) ;
   if (pushed)
      gen_pop(ECX,am_dreg,FALSE) ;
   ap2 = xalloc(sizeof(AMODE)) ;
   ap2->mode = am_axdx ;
   ap2->length = 6 ;
   return ap2 ;
}
AMODE    *gen_modiv(ENODE *node, int op, int fopp, int fop, int foppr, int fopr, int modflag,int size)
/*
 *      generate code to evaluate a mod operator or a divide
 *      operator. these operations are done on only long
 *      divisors and word dividends so that the 68000 div
 *      instruction can be used.
 */
{       AMODE    *ap1, *ap2;
         int siz1 = natural_size(node) ;
            if (siz1 > 6)
               return gen_fbinary(node,fop,fopp,fopr,foppr,size,0);
            if (siz1 == 6 || siz1 == -6)
               return do6div(node,op,modflag,siz1) ;
				resolve_binary(node,&ap1,&ap2,size);
				do_extend(ap1,ap1->length,F_DREG | F_VOL);
            dodiv(ap1,ap2,op,modflag);
        return ap1;
					
}
AMODE * gen_pdiv(ENODE *node,int size)
{
            return gen_modiv(node, op_idiv,op_fdivp,op_fdiv,op_fdivrp, op_fdivr,FALSE,size);
}			

/*
 * generate a multiply using the 386 extended IMUL.
 * rather than push EDX, we just use the extended form when EDX
 * is in use since that does not modify edx
 * at LEAST one of the args to this must be a DREG!!!!!!
 *
 */
int domul(AMODE *ap1, AMODE *ap2, int op)
{
	int size = ap1->length;
	if (ap1->length != 4 && ap1->length != -4)
		do_extend(ap1,4,F_ALL) ;
	if (equal_address(ap1,ap2)) {
		if (ap1->length != 4 && ap1->length != -4)
			do_extend(ap1,4,F_ALL) ;
		gen_codes(op_imul,4,ap1,ap1);
	}
	else {
		if (ap1->length != 4 && ap1->length != -4)
			do_extend(ap1,4,F_ALL) ;
		if (ap2->length != 4 && ap2->length != -4)
			do_extend(ap2,4,F_ALL) ;
		gen_codes(op_imul,4,ap1,ap2);
	}
	freeop(ap2);
	if (chksize(4,ap1->length))
		ap1->length = 2 * ap1->length;
	return 0;
}
int do6mul(ENODE *node, int size)
{
   AMODE *ap1, *ap2 ;
   int regax,regdx,regcx ;
   int pushed = 0 ;
   tempaxdx() ;
   if (regs[ECX]) {
      gen_push(ECX,am_dreg,FALSE) ;
      pushed = 1 ;
   }
   regax = regs[EAX] ;
   regdx = regs[EDX] ;
   regcx = regs[ECX] ;
   set_func_mode(1) ;
   regs[0] = regs[1] = regs[2] = 0 ;
   ap1 = gen_expr(node->v.p[1],FALSE,FALSE,size) ;
   if (ap1->mode != am_immed)
      do_extend(ap1,size,0) ;
   noids(ap1) ;
   if (ap1->mode == am_axdx) {
      gen_code(op_push,makedreg(EDX),0) ;
      gen_code(op_push,makedreg(EAX),0) ;
   } else if (ap1->mode == am_immed) {
#if sizeof(ULLONG_TYPE) == 4
      gen_code(op_push,make_immed(ap1->offset->v.i < 0 ? -1 : 0),0) ;
#else
      gen_code(op_push,make_immed(ap1->offset->v.i >> 32),0) ;
#endif
      gen_code(op_push,make_immed(ap1->offset->v.i & 0xffffffffL),0) ;
   } else {
      AMODE *ap2 ;
      ap1->length = 4 ;
      ap2 = copy_addr(ap1) ;
      ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,4)) ;
      gen_code(op_push,ap2,0) ;
      gen_code(op_push,ap1,0) ;
   }
   if (ap1->mode == am_axdx) {
      regs[EDX] -- ;
      regs[EAX] -- ;
   } else
      freeop(ap1) ;
   ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size) ;
   if (ap1->mode != am_immed)
      do_extend(ap1,size,0) ;
   if (ap1->mode == am_axdx) {
      gen_code(op_push,makedreg(EDX),0) ;
      gen_code(op_push,makedreg(EAX),0) ;
   } else if (ap1->mode == am_immed) {
#if sizeof(ULLONG_TYPE) == 4
      gen_code(op_push,make_immed(ap1->offset->v.i < 0 ? -1 : 0),0) ;
#else
      gen_code(op_push,make_immed(ap1->offset->v.i >> 32),0) ;
#endif
      gen_code(op_push,make_immed(ap1->offset->v.i & 0xffffffffL),0) ;
   } else {
      AMODE *ap2 ;
      ap1->length = 4 ;
      ap2 = copy_addr(ap1) ;
      ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,4)) ;
      gen_code(op_push,ap2,0) ;
      gen_code(op_push,ap1,0) ;
   }
   if (ap1->mode == am_axdx) {
      regs[EDX] -- ;
      regs[EAX] -- ;
   } else
      freeop(ap1) ;
   call_library("__LXMUL") ;
   regs[EAX] = regax ;
   regs[EDX] = regdx ;
   regs[ECX] = regcx ;
   set_func_mode(0) ;
   if (pushed)
      gen_pop(ECX,am_dreg,FALSE) ;
   ap2 = xalloc(sizeof(AMODE)) ;
   ap2->mode = am_axdx ;
   ap2->length = 6 ;
   return ap2 ;
}
AMODE * gen_pmul(ENODE *node,int size)
{
				return gen_mul(node,op_mul, op_fmulp,op_fmul, op_fmulp, op_fmul,size);
}			
AMODE    *gen_mul(ENODE *node, int op,int fopp,int fop, int foppr, int fopr, int size)
/*
 *      generate code to evaluate a multiply node. both operands
 *      are treated as words and the result is long and is always
 *      in a register so that the 68000 mul instruction can be used.
 */
{       AMODE    *ap1, *ap2;
            if (natural_size(node) > 6) {
               return gen_fbinary(node,op_fmul, op_fmulp, op_fmul, op_fmulp, natural_size(node),0);
				}
            if (size == 6 || size == -6)
               return do6mul(node,size) ;
            prefer(node,&ap1,&ap2,op,TRUE,4);
            do_extend(ap1,4,F_DREG | F_VOL);
				domul(ap1,ap2,op);
        return ap1;
					
}
AMODE    *gen_hook(ENODE *node,int size)
/*
 *      generate code to evaluate a condition operator node (?:)
 */
{       AMODE    *ap1, *ap2;
        int             false_label, end_label;
				int sizl,sizr,xsiz;
            sizr = natural_size(node->v.p[1]->v.p[1]);
            sizl = natural_size(node->v.p[1]->v.p[0]);
				sizl = sizl < 0 ? - sizl : sizl;
				sizr = sizr < 0 ? - sizr : sizr;
				if (sizl < sizr)
					xsiz = sizr;
				else 
					xsiz = sizl;
        false_label = nextlabel++;
        end_label = nextlabel++;
        falsejp(node->v.p[0],false_label);
        node = node->v.p[1];
        ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size);
				do_extend(ap1,xsiz,F_DREG | F_VOL);
				freeop(ap1);
        gen_codes(op_jmp,0,make_label(end_label),0);
        gen_label(false_label);
        ap2 = gen_expr(node->v.p[1],FALSE,FALSE,size);
				do_extend(ap2,xsiz,F_DREG | F_VOL);
        if( !equal_address(ap1,ap2) )
                {
								/* if both are floating they won't get here */
								if (ap1->mode == am_freg) {
									do_extend(ap2,10,F_FREG);
								}
								else {
									gen_code(op_mov,ap1,ap2);
									freeop(ap2);
									ap2->mode = am_dreg;
									ap2->preg = ap1->preg;
									regs[ap2->preg]++;
                }
				}
        gen_label(end_label);
        return ap2;
}

AMODE    *gen_asunary(ENODE *node,int novalue,int op, int fop, int size)
/*
 *      generate code to evaluate a unary minus or complement of an address
 */
{       AMODE    *ap;
            int nsize = natural_size(node->v.p[0]);
        ap = gen_expr(node->v.p[0],novalue,TRUE,nsize);
            if (ap->length > 6) {
               AMODE *ap2 = copy_addr(ap) ;
               floatload(ap2,TRUE);
					gen_codef(fop,0,0);
               return floatstore(node->v.p[0],ap,novalue,nsize);
				}
				else {
               if (ap->length == 6 || ap->length == -6) {
                  AMODE *ap2 ;
                  int oldlen = ap->length ;
                  ap->length =4 ;
                  ap2 = copy_addr(ap) ;
                  ap2->offset = makenode(en_add, ap2->offset, makeintnode(en_icon,4)) ;
                  gen_code(op,ap2,0);
                  gen_code(op,ap,0);
                  if (op == op_neg)
                     gen_code(op_sbb,ap2,make_immed(0)) ;
                  ap->length = oldlen ;
               } else
                  gen_code(op,ap,0);
				}
        if (novalue)
         freeop(ap) ;
        return ap;
}
AMODE    *gen_asadd(ENODE *node,int novalue,int op,int fopp,int fop, int foppr, int fopr,int size)
/*
 *      generate a plus equal or a minus equal node.
 */
{       AMODE    *ap1, *ap2, *apr;
				int bits;
            int nsize = natural_size(node->v.p[0]);
            if (natural_size(node) > 6) {
               ap1 = gen_fbinary(node,fop,fopp,fopr,foppr,nsize,&apr);
               return floatstore(node->v.p[0],apr,novalue,nsize);
				}
            if (nsize == 6 || nsize == -6) {
               int pushed = FALSE,oldsize ;
               int rsize = assign_size(node->v.p[1],size) ;
               apr = gen_expr(node->v.p[0],FALSE,TRUE,size);
               apr = aprtocx(apr) ;
               ap2 = gen_expr(node->v.p[1],FALSE,FALSE,rsize);
               if (ap2->mode != am_immed)
                  do_extend(ap2,6,F_AXDX) ;
               oldsize = apr->length ;
               apr->length = 4 ;
               if (ap2->mode == am_immed) {
                  gen_code(op,apr,make_immed(ap2->offset->v.i & 0xffffffffUL)) ;
                  ap1 = copy_addr(apr) ;
                  ap1->offset = makenode(en_add,ap1->offset,makeintnode(en_icon,4)) ;
#if sizeof(ULLONG_TYPE) == 4      
                  gen_code(op == op_add ? op_adc : op_sbb,ap1,make_immed(ap2->offset->v.i < 0 ? -1 : 0)) ;
#else
                  gen_code(op == op_add ? op_adc : op_sbb, ap1, make_immed(ap2->offset->v.i >> 32)) ;
#endif
               } else {
                  gen_code(op,apr,makedreg(EAX)) ;
                  ap1 = copy_addr(apr) ;
                  ap1->offset = makenode(en_add,ap1->offset,makeintnode(en_icon,4)) ;
                  gen_code(op == op_add ? op_adc : op_sbb, ap1, makedreg(EDX)) ;
               }
               freeop(ap2) ;
               apr->length = oldsize ;
               if (novalue)
                  freeop(apr) ;
               return apr ;
            }
            bits = as_args(node,&apr,&ap1,&ap2,nsize,0);
				small_size(ap1,ap2,nsize);
				if (!bits) {
					if (ap1->mode != am_dreg && ap2->mode != am_dreg && ap2->mode != am_immed)
                  do_extend(ap2,ap1->length,F_DREG | F_VOL);
					gen_code(op,apr,ap2);
               if (novalue)
                  freeop(ap1);
					freeop(ap2);
					return apr;
				}
				else {
					gen_code(op,ap1,ap2);
					bit_store(apr,ap1,node->v.p[0],novalue);
					freeop(ap2);
					freeop(apr);
               if (novalue)
                  freeop(ap1) ;
					return ap1;
				}
}

AMODE    *gen_aslogic(ENODE *node, int novalue, int op, int op2, int size)
/*
 *      generate a and equal or a or equal node.
 */
{       AMODE    *ap1, *ap2, *apr, *ap3;
				int bits = isbit(node->v.p[0]);
            int nsize = natural_size(node->v.p[0]);
            if (nsize == 6 || nsize == -6) {
               int pushed = FALSE,oldsize ;
               int rsize = assign_size(node->v.p[1],size) ;
               apr = gen_expr(node->v.p[0],FALSE,TRUE,size);
               apr = aprtocx(apr) ;
               ap2 = gen_expr(node->v.p[1],FALSE,FALSE,rsize);
               if (ap2->mode != am_immed)
                  do_extend(ap2,6,F_AXDX) ;
               oldsize = apr->length ;
               apr->length = 4 ;
               if (ap2->mode == am_immed) {
                  gen_code(op,apr,make_immed(ap2->offset->v.i & 0xffffffffUL)) ;
                  ap1 = copy_addr(apr) ;
                  ap1->offset = makenode(en_add,ap1->offset,makeintnode(en_icon,4)) ;
#if sizeof(ULLONG_TYPE) == 4      
                  gen_code(op ,ap1,make_immed(ap2->offset->v.i < 0 ? -1 : 0)) ;
#else
                  gen_code(op , ap1, make_immed(ap2->offset->v.i >> 32)) ;
#endif
               } else {
                  gen_code(op,apr,makedreg(EAX)) ;
                  ap1 = copy_addr(apr) ;
                  ap1->offset = makenode(en_add,ap1->offset,makeintnode(en_icon,4)) ;
                  gen_code(op, ap1, makedreg(EDX)) ;
               }
               freeop(ap2) ;
               apr->length = oldsize ;
               if (novalue)
                  freeop(apr) ;
               return apr ;
            }
				if (bits) {
					ap2 = gen_expr(node->v.p[1],FALSE,FALSE,nsize);
					noids(ap2);
					apr = gen_expr(node->v.p[0],FALSE,FALSE,nsize);
					if (ap2->mode == am_immed) {
						ENODE *node1 = node->v.p[0];
						int vb;
                  ap2->offset->v.i &= mod_mask(node1->bits);
						ap3 = make_immed(ap2->offset->v.i << node1->startbit);
						if (op == op_and) {
                     ap3->offset->v.i |= ~(mod_mask(node1->bits) << node1->startbit);
							ap3->offset->v.i = ~ap3->offset->v.i;
							vb = single_bit(ap3->offset->v.i);
							if (vb != -1)
								gen_codes(op_btr,4,apr,make_immed(vb));
							else {
								ap3->offset->v.i = ~ap3->offset->v.i;
								gen_code(op_and,apr,ap3);
							}
						}
						else {
							vb = single_bit(ap3->offset->v.i);
							if (vb != -1)
								gen_codes(op2,4,apr,make_immed(vb));
							else
								gen_code(op,apr,ap3);
						}
                  if (novalue)
                    freeop(ap2) ;
						return ap2;
					}
					else {
						do_extend(ap2,ap2->length,F_DREG | F_VOL);
                  gen_code(op_and,ap2,make_immed(mod_mask(node->v.p[0]->bits)));
						if (chksize(ap2->length,apr->length))
							ap2->length = apr->length;
						if (!novalue)
							gen_codes(op_push,4,ap2,0);
						if (node->v.p[0]->startbit)
							gen_code(op_shl,ap2,make_immed(node->v.p[0]->startbit));
						if (op == op_and)
                     gen_code(op_or,ap2,make_immed(~(mod_mask(node->v.p[0]->bits) << node->v.p[0]->startbit)));
						gen_code(op,apr,ap2);
						freeop(apr);
						if (!novalue)
							gen_codes(op_pop,4,ap2,0);
                  else 
                     freeop(ap2);
						return ap2;
					}
				}
				else {
					int vb;
               as_args(node,&apr,&ap1, &ap2,nsize,0);
					small_size(ap1,ap2,nsize);
					if (ap1->mode != am_dreg && ap2->mode != am_dreg && ap2->mode != am_immed)
						do_extend(ap2,ap2->length,F_DREG | F_VOL);
					if (ap2->mode == am_immed) {
						if (op == op_and && (vb = single_bit(~ap2->offset->v.i))!= -1) {
							gen_codes(op2,4,ap1,make_immed(vb));                        	
                     if (novalue)
                        freeop(ap1);
							return apr;
						}
						else if ((vb = single_bit(ap2->offset->v.i)) != -1){
							gen_codes(op2,4,ap1,make_immed(vb));
                     if (novalue)
                        freeop(ap1);
							return apr;
						}
					}
               gen_code(op,apr,ap2);
               if (novalue)
                  freeop(ap1);
					freeop(ap2);
               return apr;
				}
}

AMODE *gen_asshift(ENODE *node, int novalue,int op, int size,int div)
/*
 *      generate shift equals operators.
 */
{       AMODE    *ap1, *ap2, *apr;
            int bits ;
            int nsize = natural_size(node->v.p[0]);
            if (nsize == 6 || nsize == -6) {
               int oldsize ;
               apr = gen_expr(node->v.p[0],FALSE,TRUE,size);
               apr = aprtocx(apr) ;
               ap1 = do6shift(node,novalue,op,div,size) ;
               oldsize = apr->length ;
               apr->length = 4 ;
               ap2 = copy_addr(apr) ;
               ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,4)) ;
               gen_code(op_mov,apr,makedreg(EAX)) ;
               gen_code(op_mov,ap2,makedreg(EDX)) ;
               apr->length = oldsize ;
               freeop(apr) ;
               apr = ap1 ;
               if (novalue)
                  freeop(apr) ;
               return apr ;
            }
            bits = as_args(node,&apr,&ap1,&ap2,nsize,1);
            if (ap2->length <= 6)
               ap2->length = 4 ; /* this is kind of iffy, but bits outside CL really don't matter */
            else 
               do_extend(ap2,4,0) ;
//            if (op == op_sal || op == op_shl)
//               small_size(ap1,ap2,nsize);
//            else
//               get_size(ap1,ap2,nsize);
				if (!bits) {
               doshift(ap1,ap2,op,div,nsize);
               if (ap1->mode == am_axdx)
                 gen_codes(op_mov,apr->length,apr,makedreg(EAX)) ;
               else
                 gen_codes(op_mov,apr->length,apr,ap1) ;
               if (novalue)
                  freeop(ap1) ;
					return apr;
				}
				else {
					do_extend(ap1,4,0);
               doshift(ap1,ap2,op,div,nsize);
					bit_store(apr,ap1,node->v.p[0],novalue);
               if (novalue)
                  freeop(ap1) ;
					return ap1;
				}
}

AMODE    *gen_asmul(ENODE *node, int novalue,int op, int foppr, int fopr, int fopp, int fop,int size)
/*
 *      generate a *= node.
 */
{       AMODE    *ap1, *ap2, *apr, *ap3;
				int bits;
            int nsize = natural_size(node->v.p[0]);
            if (natural_size(node) > 6) {
               ap1 = gen_fbinary(node,fop,fopp,fopr,foppr,nsize,&apr);
               return floatstore(node->v.p[0],apr,novalue,nsize);
            } else if (natural_size(node) == 6 || natural_size(node) == -6) {
               int oldlen ;
               apr = gen_expr(node->v.p[0],FALSE,TRUE,size);
               apr = aprtocx(apr) ;
               ap1 = do6mul(node,6) ;
               if (apr->length < 6 && apr->length != -6) {
                  gen_codes(op_mov,apr->length,apr,makedreg(EAX)) ;
                  freeop(ap1) ;
                  return apr ;
               }
               oldlen = apr->length ;
               apr->length = 4 ;
               ap2 = copy_addr(apr) ;
               ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,4)) ;
               gen_code(op_mov,apr,makedreg(EAX)) ;
               gen_code(op_mov,ap2,makedreg(EDX)) ;
               apr->length = oldlen ;
               freeop(apr) ;
               if (novalue)
                  freeop(ap1) ;
               return ap1 ;
            }
            bits = as_args(node,&apr,&ap1,&ap2,nsize,0);
				small_size(ap1,ap2,nsize);
				if (!bits) {
					if (ap1->mode != am_dreg) {
                  ap3 = temp_data() ;
                  gen_codes(op_mov,ap1->length,ap3,ap1) ;
                  domul(ap3,ap2,op);
                  do_extend(ap3,apr->length,F_DREG | F_VOL) ;
                  gen_code(op_mov,apr,ap3);
						if (novalue)
                     freeop(ap3);
                  freeop(ap1) ;
                  return ap3;
					}
					else {
						domul(ap1,ap2,op);
						if (!equal_address(ap1,apr)) {
							gen_code(op_mov, apr,ap1);
							if (novalue)
								freeop(ap1);
							return ap1;
						}
						freeop(ap1);
					}
					return apr;
				}
				else {
					domul(ap1,ap2,op);
					bit_store(apr,ap1,node->v.p[0],novalue);
					freeop(ap2);
					freeop(apr);
               if (novalue)
                  freeop(ap1) ;
					return ap1;
				}
}

AMODE    *gen_asmodiv(ENODE *node, int novalue, int op, int fopp, int fop, int foppr, int fopr, int modflag, int size)
/*
 *      generate /= and %= nodes.
 */
{       AMODE    *ap1, *ap2, *apr;
				int bits;
            int nsize = natural_size(node->v.p[0]);
            if (natural_size(node) > 6) {
               ap1 = gen_fbinary(node,fop,fopp,fopr,foppr,nsize,&apr);
               return floatstore(node->v.p[0],apr,novalue,nsize);
            } else if (natural_size(node) == 6 || natural_size(node) == -6) {
               int oldlen ;
               apr = gen_expr(node->v.p[0],FALSE,TRUE,size);
               apr = aprtocx(apr) ;
               ap1 = do6div(node,op,modflag,natural_size(node)) ;
               if (apr->length < 6 && apr->length != -6) {
                  gen_codes(op_mov,apr->length,apr,makedreg(EAX)) ;
                  freeop(ap1) ;
                  if (novalue)
                     freeop(apr) ;
                  return apr ;
               } else {
                  oldlen = apr->length ;
                  apr->length = 4 ;
                  ap2 = copy_addr(apr) ;
                  ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,4)) ;
                  gen_code(op_mov,apr,makedreg(EAX)) ;
                  gen_code(op_mov,ap2,makedreg(EDX)) ;
                  freeop(apr) ;
                  apr->length = oldlen ;
                  if (novalue)
                     freeop(ap1) ;
                  return ap1 ;
               }
            }
            bits = as_args(node,&apr,&ap1,&ap2,nsize,0);
				get_size(ap1,ap2,nsize);
				if (!bits) {
					if (ap1->mode != am_dreg)
						do_extend(ap1,ap1->length,F_DREG | F_VOL);
               dodiv(ap1,ap2,op,modflag);
					if (chksize(ap1->length,apr->length))
						ap1->length = apr->length;
					if (!equal_address(ap1,apr))
						gen_code(op_mov,apr,ap1);
					freeop(apr);
               if (novalue)
                  freeop(ap1) ;
					return ap1;
				}
				else {
               dodiv(ap1,ap2,op,modflag);
					bit_store(apr,ap1,node->v.p[0],novalue);
					freeop(apr);
               if (novalue)
                  freeop(ap1) ;
					return ap1;
				}
}
void mov1(AMODE *dst, AMODE *src, int size)
{
	AMODE *intermed = temp_data();
	gen_codes(op_mov,size,intermed,src);
	gen_codes(op_mov,size,dst,intermed);
	freeop(intermed);
	freeop(src);
	freeop(dst);
	
}
void mov2(AMODE *dst, AMODE *src, int size1,int size2)
{
	AMODE *intermed = temp_data(),*dst1,*src1;
	gen_codes(op_mov,size1,intermed,src);
	gen_codes(op_mov,size1,dst,intermed);
   src->offset = makenode(en_add,src->offset,makeintnode(en_icon,size1));
   dst->offset = makenode(en_add,dst->offset,makeintnode(en_icon,size1));
	gen_codes(op_mov,size2,intermed,src);
	gen_codes(op_mov,size2,dst,intermed);
	freeop(intermed);
	freeop(src);
	freeop(dst);
}
void mov3(AMODE *dst, AMODE *src, int size1,int size2,int size3)
{
	AMODE *intermed = temp_data(),*dst1,*src1;
	gen_codes(op_mov,size1,intermed,src);
	gen_codes(op_mov,size1,dst,intermed);
   src->offset = makenode(en_add,src->offset,makeintnode(en_icon,size1));
   dst->offset = makenode(en_add,dst->offset,makeintnode(en_icon,size1));
	gen_codes(op_mov,size2,intermed,src);
	gen_codes(op_mov,size2,dst,intermed);
   src->offset = makenode(en_add,src->offset,makeintnode(en_icon,size2));
   dst->offset = makenode(en_add,dst->offset,makeintnode(en_icon,size2));
	gen_codes(op_mov,size3,intermed,src);
	gen_codes(op_mov,size3,dst,intermed);
	freeop(intermed);
	freeop(src);
	freeop(dst);
}
AMODE *amode_moveblock(AMODE *ap1, AMODE *ap2, int size)
{
	int t = size & 3,q=size >> 2;
	AMODE *ap3;

	switch(size) {
		case 1:
		case 2:
		case 4:
			mov1(ap1,ap2,size);
			break;
		case 3:
			mov2(ap1,ap2,2,1);
			break;
		case 5:
			mov2(ap1,ap2,4,1);
			break;
      case 6:
			mov2(ap1,ap2,4,2);
			break;
		case 7:
			mov3(ap1,ap2,4,2,1);
			break;
		case 8:
			mov2(ap1,ap2,4,4);
			break;
		case 9:
			mov3(ap1,ap2,4,4,1);
			break;
		case 10:
			mov3(ap1,ap2,4,4,2);
			break;
		case 12:
			mov3(ap1,ap2,4,4,4);
			break;
		default:
			if (ap1->mode == am_indisp && ap1->preg == ESI ||
					(ap1->mode == am_indispscale && (ap1->preg == ESI || ap2->preg == ESI)) ||
					(ap1->mode == am_dreg && ap1->preg == ESI)) {
				ap3 = temp_data();
				gen_code(op_lea,ap3,ap1);
				freeop(ap1);
				ap1 = ap3;
			}
			gen_push(ESI,am_dreg,0);                                  
			gen_push(EDI,am_dreg,0);                                  
			freeop(ap2);
			freeop(ap1);
			if (regs[1])                                              
				gen_push(ECX,am_dreg,0);                                
			if (ap2->mode == am_dreg)
				gen_codes(op_mov,4,makedreg(ESI),ap2);		                  
			else
				gen_codes(op_lea,4,makedreg(ESI),ap2);		                  
			if (ap1->mode == am_dreg)
				gen_codes(op_mov,4,makedreg(EDI),ap1);                     
			else
				gen_codes(op_lea,4,makedreg(EDI),ap1);                     
			gen_code(op_cld,0,0);
			if (q) {
				gen_codes(op_mov,4,makedreg(ECX),make_immed(q));  
				gen_code(op_rep,0,0);                                   
				gen_code(op_movsd,0,0);
			}
			if (t & 2)
				gen_code(op_movsw,0,0);
			if (t & 1)
				gen_code(op_movsb,0,0);
			if (regs[1])                                              
				gen_pop(ECX,am_dreg,0);
			gen_pop(EDI,am_dreg,0);
			gen_pop(ESI,am_dreg,0);
			break;
	}
	freeop(ap2);
	freeop(ap1);
}
AMODE *gen_moveblock(ENODE *node)      
{                                                           
	AMODE *ap1, *ap2;
	ENODE ep1 ;
	if (!node->size)                                          
		return(0);
	ep1.nodetype = en_l_ref ;
	ep1.cflags = 0;
	ep1.v.p[0] = node->v.p[1] ;
	ap2 = gen_expr(&ep1,FALSE,TRUE,0);                     
   if (ap2->mode == am_indispscale)
      ap2 = indx_data(ap2) ;
	ep1.nodetype = en_l_ref ;
	ep1.cflags = 0;
	ep1.v.p[0] = node->v.p[0] ;
	ap1 = gen_expr(&ep1,FALSE,TRUE,0); 
	return amode_moveblock(ap1,ap2,node->size);
}
AMODE    *gen_assign(ENODE *node, int novalue,int size, int stdc)
/*
 *      generate code for an assignment node. if the size of the
 *      assignment destination is larger than the size passed then
 *      everything below this node will be evaluated with the
 *      assignment size.
 */
{       AMODE    *ap1, *ap2, *apr, *aps=0;
				int bits;
            int nsize = natural_size(node->v.p[0]);
            int rsize = assign_size(node->v.p[1],nsize) ;
            if (nsize == 6 || nsize == -6) {
               apr = gen_expr(node->v.p[0],FALSE,TRUE,size);
               apr = aprtocx(apr) ;
               if (!novalue && !stdc) {
                  aps = copy_addr(apr) ;
                  do_extend(aps,nsize,F_AXDX) ;
               }
               ap2 = gen_expr(node->v.p[1],FALSE,FALSE,rsize) ;
            }else {
               if (isfloatconst(node->v.p[1]->nodetype)) {
                  ap2 = xalloc(sizeof(AMODE)) ;
                  ap2->mode = am_immed ;
                  ap2->offset = node->v.p[1] ;
                  ap2->length = natural_size(ap2->offset) ;
               } else
                  ap2 = gen_expr(node->v.p[1],FALSE,FALSE,rsize);
               noids(ap2);
               if (!novalue && !stdc) {
                  aps = gen_expr(node->v.p[0],FALSE,TRUE,nsize);
                  do_extend(aps,nsize,F_DREG | F_FREG) ;
               }
               apr = gen_expr(node->v.p[0],FALSE,TRUE,nsize);
            }
            if (natural_size(node->v.p[0]) > 6) {
              if (ap2->mode == am_immed) {
                 long double aa ;
                 double bb ;
                 float cc ;
                 if (isintconst(ap2->offset->nodetype)) {
                    aa = ap2->offset->v.i ;
                 } else {
                    aa = ap2->offset->v.f ;
                 }
                 switch(apr->length) {
                    case 7:
                       cc = aa ;
                       ap2 = copy_addr(apr) ;
                       ap2->length = 4 ;
                       gen_code(op_mov,ap2,make_immed(*(unsigned *)&cc)) ;
                       break ;   
                    case 8:
                       bb = aa ;
                       ap2 = copy_addr(apr) ;
                       ap2->length = 4 ;
                       gen_code(op_mov,ap2,make_immed(*(unsigned *)&bb)) ;
                       ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,4)) ;
                       gen_code(op_mov,ap2,make_immed(*(((unsigned *)&bb)+1))) ;
                       break ;
                    case 10:
                       ap2 = copy_addr(apr) ;
                       ap2->length = 4 ;
                       gen_code(op_mov,ap2,make_immed(*(unsigned *)&aa)) ;
                       ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,4)) ;
                       gen_code(op_mov,ap2,make_immed(*(((unsigned *)&aa)+1))) ;
                       ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,4)) ;
                       ap2->length = 2 ;
                       gen_code(op_mov,ap2,make_immed(*(((unsigned short *)&aa)+4))) ;
                       break ;
                 }
                 if (novalue || aps)
                  freeop(apr) ;
                 if (aps)
                  return aps ;
                 return apr ;
              } else if (ap2->mode != am_freg && ap2->length == apr->length) {
                 amode_moveblock(apr,ap2,apr->length == 7 ? 4 : apr->length) ;
                 if (novalue|| aps)
                  freeop(apr) ;
                 if (aps)
                  return aps ;
                 return apr ;
              } else {
					do_extend(ap2,10,F_FREG);
               apr = floatstore(node->v.p[0],apr,novalue,nsize);
               if (aps) {
                freeop(ap2) ;
                return aps ;
               }
               return apr ;
              }
            } 
            do_extend(ap2,apr->length,0) ;
				bits = isbit(node->v.p[0]);
				if (!equal_address(apr,ap2)	) {
					if (!bits) {
                  if (apr->length > 6) {
                        do_extend(ap2,apr->length,F_FREG);
                        apr = floatstore(node->v.p[0],apr,novalue,nsize);
                        if (aps)
                           return aps ;
                        return apr ;
						}
						else {
						
                     if (apr->length == 6 || apr->length == -6) {
                        int oldlen = apr->length,oldlen2 = ap2->length ;
                        do_extend(ap2,ap2->length,F_MEM | F_AXDX) ;
                        if (ap2->mode == am_axdx) {
                          apr->length = 4 ;
                          ap1 = copy_addr(apr) ;
                          ap1->offset = makenode(en_add,ap1->offset,makeintnode(en_icon,4)) ;
                          gen_code(op_mov,apr,makedreg(EAX)) ;
                          gen_code(op_mov,ap1,makedreg(EDX)) ;
                        } else {
                           if (ap2->mode == am_immed) {
                              apr->length = 4 ;
                              ap1 = copy_addr(apr) ;
                              ap1->offset = makenode(en_add,ap1->offset,makeintnode(en_icon,4)) ;
                              gen_code(op_mov,apr,make_immed(ap2->offset->v.i & 0xffffffff)) ;
#if sizeof(ULLONG_TYPE) == 4
                              gen_code(op_mov,ap1,make_immed(ap2->offset->v.i < 0 ? -1 : 0)) ;
#else
                              gen_code(op_mov,ap1,make_immed(ap2->offset->v.i >> 32)) ;
#endif
                           } else {
                              apr->length = 4 ;
                              ap2->length = 4 ;
                              mov2(apr,ap2,4,4) ;
                           }
                        }
                        apr->length = oldlen ;
                        freeop(ap2) ;
                        if (novalue)
                           freeop(apr) ;
                        if (aps)
                           return aps ;
                        return (apr) ;
                     } else {
                        if (apr->mode != am_dreg && ap2->mode != am_dreg && ap2->mode != am_immed)
                           do_extend(ap2,apr->length,F_DREG);
                        else
                           do_extend(ap2,apr->length,0);
                        gen_codes(op_mov,apr->length,apr,ap2);
                     }
							if (!novalue && (ap2->mode == am_dreg || ap2->mode == am_immed)) {
								freeop(apr);
                        if (aps) {
                           freeop(ap2) ;
                           return aps ;
                        }
								return ap2;
							}
							freeop(ap2);
                     if (novalue|| aps)
                        freeop(apr) ;
                     if (aps)
                        return aps ;
							return apr;
						}
					}
					else {
						bit_store(apr,ap2,node->v.p[0],novalue);
						freeop(apr);
                  if (aps) {
                     freeop(ap2) ;
                     return aps ;
                  }
						return ap2;
					}
				}
            if (aps) {
                  freeop(apr) ;
                 return aps ;
            }
            return apr;
}
AMODE    *gen_refassign(ENODE *node, int novalue, int size)
/*
 *      generate code for an assignment node. if the size of the
 *      assignment destination is larger than the size passed then
 *      everything below this node will be evaluated with the
 *      assignment size.
 */
{       AMODE    *ap1, *ap2, *apr,*ap4,*ap5;
            int nsize = natural_size(node->v.p[0]);
            int bits = as_args(node,&apr,&ap1,&ap2,nsize,0);
            if (natural_size(node->v.p[0]) > 6) {
					do_extend(ap2,ap1->length,0);
					floatload(ap2,TRUE);
               ap2 = floatstore(node->v.p[0],apr,novalue,nsize);
					ap4 = temp_data();
					gen_code(op_lea,ap4,ap2);
					return ap4;
				}
				if (!equal_address(apr,ap2)	) {
					if (!bits) {
                  if (apr->length > 6) {
							do_extend(ap2,apr->length,F_FREG);
                     return floatstore(node->v.p[0],apr,novalue,nsize);
						}
                  if (apr->length == 6 || apr->length == -6) {
                     apr = aprtocx(apr) ;
                     do_extend(ap2,6,F_AXDX) ;
                     ap5 = copy_addr(apr) ;
                     ap5->offset = makenode(en_add,apr->offset,makeintnode(en_icon,4)) ;
                     gen_codes(op_mov,4,apr,makedreg(EAX)) ;
                     gen_codes(op_mov,4,ap5,makedreg(EDX)) ;
                  } else {
                     do_extend(ap2,ap1->length,0);
                     gen_code(op_mov,apr,ap2);
                  }
						ap4 = temp_data();
						gen_code(op_lea,ap4,apr);
						freeop(ap1);
						freeop(ap2);
						freeop(apr);
                  if (novalue)
                     freeop(ap4) ;
						return ap4;
					}
					else {
						bit_store(apr,ap2,node->v.p[0],novalue);
						freeop(ap1);
						freeop(apr);
                  if (novalue)
                     freeop(ap2) ;
						return ap2;
					}
				}
				freeop(ap1);
				freeop(ap2);
				return apr;
}

AMODE    *gen_aincdec(ENODE *node, int novalue, int op, int size)
/*
 *      generate an auto increment or decrement node. op should be
 *      either op_add (for increment) or op_sub (for decrement).
 */
{       AMODE    *ap1,*ap2,*ap3;
				int pushed = FALSE,sz;
            int nsize = natural_size(node->v.p[0]);
				ap2 = make_immed((long)node->v.p[1]);
            if (nsize > 6) {
               ap1 = gen_expr(node->v.p[0],FALSE,TRUE,nsize);
               sz = ap1->length;
					floatload(ap1,TRUE);
					make_floatconst(ap2);
					floatload(ap2,TRUE);
					if (novalue)
						gen_codef(op_faddp,0,0);
					else
						gen_codef(op_fadd,makefreg(1),0);
               floatstore(node->v.p[0],ap1,TRUE,nsize);
					freeop(ap1);
               ap3 = fstack();
            } else if (nsize == 6 || nsize == -6) {
               ap1 = gen_expr(node->v.p[0],FALSE,FALSE,nsize) ;
               sz = ap1->length ;
               freeop(ap1) ;
               if (!novalue) {
                  ap1 = aprtocx(ap1) ;
                  ap3 = copy_addr(ap1) ;
                  do_extend(ap3,nsize,F_AXDX) ;
               }
               ap1->length = 4 ;
               gen_code(op,ap1,ap2) ;
               ap1 = copy_addr(ap1) ;
               ap1->offset = makenode(en_add,ap1->offset,makeintnode(en_icon,4)) ;
               gen_code(op == op_add ? op_adc : op_sbb,ap1,make_immed(0)) ;
               freeop(ap1) ;
               freeop(ap2) ;
            } else if (isbit(node->v.p[0])) {
					ap3 = gen_expr(node->v.p[0],FALSE,FALSE,size);
					gen_code(op,ap3,ap2);
					bit_store(ap1,ap3,node->v.p[0],novalue);
					freeop(ap1);
               if (novalue)
                  freeop(ap3) ;
				}
				else {
               ap1 = gen_expr(node->v.p[0],FALSE,FALSE,nsize);
               sz = ap1->length;
					freeop(ap1);
					if (!novalue) {
						int reg = next_dreg();
/*FIXME*/
						if (ap1->mode == am_indisp && ap1->preg == reg ||
								ap1->mode == am_indispscale && (ap1->preg == reg || ap1->sreg == reg)) {
							gen_codes(op_push,4,ap1,0);
							pushed = TRUE;
						}
						else {
                     if (!novalue) {
                        ap3 = temp_data();
                        gen_codes(op_mov,sz,ap3,ap1);
                     }
						}
					}
					gen_code(op,ap1,ap2);
					if (pushed) {
						ap3 = temp_data();
						gen_codes(op_pop,4,ap3,0);
                  if (novalue)
                     freeop(ap3) ;
					}
				}
				if (!novalue)
					ap3->length = sz;
				return ap3;
}

int push_param(ENODE *ep, int size)
/*
 *      push the operand expression onto the stack.
 */
{       AMODE    *ap, *ap2;
        float cc ;
        double bb ;
        long double aa ;
				int rv;
            int nsize = natural_size(ep);
            if (ep->nodetype == en_cf || ep->nodetype == en_cd || ep->nodetype == en_cld
               || ep->nodetype == en_cfi || ep->nodetype == en_cri || ep->nodetype == en_clri)
               if (isfloatconst(ep->v.p[0]->nodetype) || isintconst(ep->v.p[0]->nodetype)
                     || isimaginaryconst(ep->v.p[0]->nodetype)) {
                  switch(ep->nodetype) {
                        case en_cf: 
                        case en_cfi:
                                    if (isintconst(ep->v.p[0]->nodetype))
                                       cc = ep->v.p[0]->v.i ;
                                    else
                                       cc = ep->v.p[0]->v.f ;
                                    gen_codes(op_push,4,make_immed(*(unsigned *)&cc),0) ;
                                    rv = 7;
                                    break ;
                        case en_cd:
                        case en_cri:
                                    rv = 8;
                                    if (isintconst(ep->v.p[0]->nodetype))
                                       bb = ep->v.p[0]->v.i ;
                                    else
                                       bb = ep->v.p[0]->v.f ;
                                    gen_codes(op_push,4,make_immed(*(((unsigned *)&bb)+1)),0) ;
                                    gen_codes(op_push,4,make_immed(*(unsigned *)&bb),0) ;
                                    break ;
                        case en_cld:
                        case en_clri:
                                    rv = 10;
                                    if (isintconst(ep->v.p[0]->nodetype))
                                       aa = ep->v.p[0]->v.i ;
                                    else
                                       aa = ep->v.p[0]->v.f ;
                                    gen_codes(op_push,4,make_immed(*(((unsigned short *)&aa))+4),0) ;
                                    gen_codes(op_push,4,make_immed(*(((unsigned *)&aa)+1)),0) ;
                                    gen_codes(op_push,4,make_immed(*(unsigned *)&aa),0) ;
                                    break ;
                  }
                  gen_code(op_void,0,0) ;
                  return rv ;
               }
				switch (ep->nodetype) {
								case en_absacon:
												ep->v.i = ep->v.sp->value.i;
                        ap = xalloc(sizeof(AMODE));
                        ap->mode = am_immed;
                        ap->offset = ep;     /* use as constant node */
												ap->length = rv = 4;
                        gen_code(op_push,ap,0);
												rv = 4;
                                    freeop(ap);
												break;
                case en_napccon:
                case en_nacon:
												ep->v.p[0] = ep->v.sp;
                case en_labcon:
                case en_nalabcon:
                        ap = xalloc(sizeof(AMODE));
                        ap->mode = am_immed;
                        ap->offset = ep;     /* use as constant node */
												ap->length = rv = 4;
                        gen_code(op_push,ap,0);
												gen_code(op_void,0,0);
                                    freeop(ap);
												break;
                        case en_cfc:
                        case en_fcomplexref:
                        case en_fcomplexcon:
                        case en_crc:
                        case en_rcomplexref:
                        case en_rcomplexcon:
                        case en_clrc:
                        case en_lrcomplexref:
                        case en_lrcomplexcon:
                              rv = 4 ;
                              break ;
								case en_cf:
								case en_floatref:
                        case en_cfi:
                        case en_fimaginaryref:
												ap = gen_expr(ep,FALSE,TRUE,4);
												do_extend(ap,10,F_FREG);
												gen_codes(op_sub,4,makedreg(ESP),make_immed(4));
												ap2 = make_stack(0);
                                    ap2->length = 7;
												gen_codef(op_fstp,ap2,0);
												gen_codef(op_fwait,0,0);
												gen_code(op_void,0,0);
												rv = 4;
                                    freeop(ap);
												break;
								case en_cd:
								case en_doubleref:
                        case en_cri:
                        case en_rimaginaryref:
												ap = gen_expr(ep,FALSE,TRUE,8);
												do_extend(ap,10,F_FREG);
												gen_codes(op_sub,4,makedreg(ESP),make_immed(8));
												ap2 = make_stack(0);
												ap2->length = 8;
												gen_codef(op_fstp,ap2,0);
												gen_codef(op_fwait,0,0);
												gen_code(op_void,0,0);
												rv = 8;
                                    freeop(ap);
												break;
								case en_cld:
								case en_longdoubleref:
                        case en_clri:
                        case en_lrimaginaryref:
												ap = gen_expr(ep,FALSE,TRUE,10);
												do_extend(ap,10,F_FREG);
												gen_codes(op_sub,4,makedreg(ESP),make_immed(12));
												ap2 = make_stack(0);
												ap2->length = 10;
												gen_codef(op_fstp,ap2,0);
												gen_codef(op_fwait,0,0);
												gen_code(op_void,0,0);
												rv = 12;
                                    freeop(ap);
												break;
                        case en_fcon: 
                        case en_fimaginarycon:
                                    if (isintconst(ep->nodetype))
                                       cc = ep->v.i ;
                                    else
                                       cc = ep->v.f ;
                                    gen_codes(op_push,4,make_immed(*(unsigned *)&cc),0) ;
                                    rv = 7;
                                    break ;
                        case en_rcon:
                        case en_rimaginarycon:
                                    rv = 8;
                                    if (isintconst(ep->nodetype))
                                       bb = ep->v.i ;
                                    else
                                       bb = ep->v.f ;
                                    gen_codes(op_push,4,make_immed(*(((unsigned *)&bb)+1)),0) ;
                                    gen_codes(op_push,4,make_immed(*(unsigned *)&bb),0) ;
                                    break ;
								case en_lrcon:
                        case en_lrimaginarycon:
                                    rv = 10;
                                    if (isintconst(ep->nodetype))
                                       aa = ep->v.i ;
                                    else
                                       aa = ep->v.f ;
                                    gen_codes(op_push,4,make_immed(*(((unsigned short *)&aa))+4),0) ;
                                    gen_codes(op_push,4,make_immed(*(((unsigned *)&aa)+1)),0) ;
                                    gen_codes(op_push,4,make_immed(*(unsigned *)&aa),0) ;
                                    break ;
								default:
                              ap = gen_expr(ep,FALSE,FALSE,size);
                                    if (size == 6 || size == -6) {
                                       do_extend(ap,size,F_AXDX | F_MEM) ;
                                       if (ap->mode == am_axdx) {
                                          gen_codes(op_push,4,makedreg(EDX),0) ;
                                          gen_codes(op_push,4,makedreg(EAX),0) ;
                                       } else if (ap->mode == am_immed) {
#if sizeof(LLONG_TYPE) == 4
                                          gen_codes(op_push,4,make_immed(ap->offset->v.i < 0 ? -1 : 0),0) ;
#else
                                          gen_codes(op_push,4,make_immed(ap->offset->v.i >> 32),0) ;
#endif
                                          gen_codes(op_push,4,make_immed(ap->offset->v.i),0) ;
                                       } else {
                                          ap2 = copy_addr(ap) ;
                                          ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,4)) ;
                                          gen_codes(op_push,4,ap2,0) ;
                                          gen_codes(op_push,4,ap,0) ;
                                       }
                                       rv = 8 ;
                                    } else if (size <=5) {
													while(castvalue(ep))
														ep = ep->v.p[0] ;
													if (isbit(ep))
														ap = bit_load(ap,ep) ;
													do_extend(ap,4,0);
                                       gen_codes(op_push,4,ap,0);
													rv = 4;
												}
												else {
													floatload(ap,FALSE);
													rv = 8;
                                       if (size == 7) rv= 4;
													if (size == 10) rv= 12;
													gen_codes(op_sub,4,makedreg(ESP),make_immed(rv));
													ap2 = make_stack(0);
													ap2->length = size;
													gen_codef(op_fstp,ap2,0);
													gen_codef(op_fwait,0,0);
												}
                                    freeop(ap);
												break;
				}
				gen_code(op_void,0,0);
	return(rv);
}
int push_stackblock(ENODE *ep)
{
	AMODE *ap;
	SYM *sp;
	int x;
	int sz = (ep->size + stackadd) &stackmod;
	if (!sz)
		return(0);
	if (sz > 24) {
				gen_codes(op_sub,4,makedreg(ESP),make_immed(sz));
				gen_codes(op_push,4,makedreg(ESI),0);
				gen_codes(op_push,4,makedreg(EDI),0);
				switch (ep->nodetype) {
                case en_napccon:
                case en_nacon:
												ep->v.p[0] = ep->v.sp;
                case en_nalabcon:
                case en_labcon:
                        ap = xalloc(sizeof(AMODE));
                        ap->mode = am_direct;
                        ap->offset = ep;     /* use as constant node */
                        gen_codes(op_lea,4,makedreg(ESI),ap);
												break;
                case en_absacon:
                        ep->v.i = ep->v.sp->value.i;
                        ap = xalloc(sizeof(AMODE));
                        ap->mode = am_direct;
                        ap->seg = 2 ;
                        ap->offset = ep;     /* use as constant node */
                        gen_codes(op_lea,4,makedreg(ESI),ap);
                        break;
                case en_autocon:
                        sp = ep->v.p[0] = ep->v.sp;
                        x = sp->value.i;
                        ap = xalloc(sizeof(AMODE));
                        ap->mode = am_indisp;
                        ap->preg = EBP;
                        ap->offset = makeintnode(en_icon,x);
                        gen_codes(op_lea,4,makedreg(ESI),ap);
                        break;
                default:
                        ap = gen_expr(ep,F_DREG | F_MEM | F_IMMED,TRUE,4);
                        if (ap->mode == am_dreg)
                           gen_codes(op_mov,4,makedreg(ESI),ap);
                        else
                           gen_codes(op_lea,4,makedreg(ESI),ap);
                        break;
				}
				gen_codes(op_lea,4,makedreg(EDI),make_stack(-8));
				freeop(ap);
				if (regs[1])
					gen_push(ECX,am_dreg,0);
				gen_code(op_cld,0,0);
				gen_codes(op_mov,4,makedreg(ECX),make_immed(sz>>2));  
				gen_code(op_rep,0,0);                                   
            gen_code(op_movsd,0,0); // always room for dwords on stack
				if (regs[1])
					gen_pop(ECX,am_dreg,0);
				gen_codes(op_pop,4,makedreg(EDI),0);
				gen_codes(op_pop,4,makedreg(ESI),0);
				gen_code(op_void,0,0);
	} else {
				int i = ((sz +3)/4)*4;
				switch (ep->nodetype) {
                case en_napccon:
                case en_nacon:
												ep->v.p[0] = ep->v.sp;
                case en_nalabcon:
                case en_labcon:
                        ap = xalloc(sizeof(AMODE));
                        ap->mode = am_direct;
                        ap->offset = ep;     /* use as constant node */
												break;
								case en_absacon:
												ep->v.i = ep->v.sp->value.i;
                        ap = xalloc(sizeof(AMODE));
                        ap->mode = am_direct;
                        ap->seg = 2 ;
                        ap->offset = ep;     /* use as constant node */
												break;
								case en_autocon:
												sp = ep->v.p[0] = ep->v.sp;
												x = sp->value.i;
                        ap = xalloc(sizeof(AMODE));
                        ap->mode = am_indisp;
			          				ap->preg = EBP;
                              ap->offset = makeintnode(en_icon,x);
												break;
								default:
      			  					ap = gen_expr(ep,F_DREG | F_MEM | F_IMMED,FALSE,4);
                              if (ap->mode == am_dreg) {
                                 ap->mode = am_indisp ;
                                 ap->offset = makeintnode(en_icon,0);
                              }
												break;
				}
				while (i > 0) {
					AMODE *ap1 = xalloc(sizeof(AMODE));
					memcpy(ap1,ap,sizeof(AMODE));
               ap1->offset = makenode(en_addstruc,ap->offset,makeintnode(en_icon,(i-4)));
               gen_codes(op_push,4,ap1,0);
					i = i - 4;
				}
				
	}
	return(sz);
}

int     gen_parms(ENODE *plist)
/*
 *      push a list of parameters onto the stack and return the
 *      size of parameters pushed.
 */
{       int     i;
        i = 0;
        while( plist != 0 )
                {         	
								if (plist->nodetype == en_stackblock)
									i+=push_stackblock(plist->v.p[0]);
								else
                  i+=push_param(plist->v.p[0],natural_size(plist->v.p[0]));
                plist = plist->v.p[1];
                }
        return i;
}

AMODE    *gen_tcall(ENODE *node, int novalue)
/*
 *      generate a trap call node and return the address mode
 *      of the result.
 */
{       AMODE    *ap, *result;
        int             i,siz1;
				int regax,regdx,regcx;
				regax = regs[0]; regcx = regs[1]; regdx = regs[2];
				if (regcx)
					gen_push(ECX,am_dreg,0);
				if (regdx)
					gen_push(EDX,am_dreg,0);
				if (regax)
					gen_push(EAX,am_dreg,0);
				regs[0] = regs[1] = regs[2] = 0;
				siz1 = node->v.p[0]->v.i;
				gen_code(op_int,make_immed((int)node->v.p[0]->v.p[0]),0);
				regs[0] = regax; regs[1] = regcx; regs[2] = regdx;
				if (!novalue) {
               result = temp_data();
               result->length = siz1;
               if(result->preg != EAX)
                  gen_codes(op_mov,siz1,result,makedreg(EAX));
				}
				if (regax)
					gen_pop(EAX,am_dreg,0);
				if (regdx)
					gen_pop(EDX,am_dreg,0);
				if (regcx)
					gen_pop(ECX,am_dreg,0);
        return result;
}
AMODE *inlinecall(ENODE *node)
{
      ENODE *nameref = node,*thisn = 0; 
      SYM *sp;
      int size;
         size = currentfunc->tp->btp->size;
      if (size == -8)
         tempaxdx() ;
			
      if (nameref->nodetype == en_thiscall) {
				thisn = nameref->v.p[0] ;
        nameref = nameref->v.p[1];
			}
				
      nameref = nameref->v.p[1]->v.p[0];
      if (nameref->nodetype == en_nacon || nameref->nodetype == en_napccon) {  
        sp = nameref->v.sp;
				if (sp && (sp->value.classdata.cppflags & PF_INLINE)) {
					int oldretlab = retlab;
					AMODE *ap;
					SYM *oldcurfunc = currentfunc ;
					currentfunc = sp;
               retlab = nextlabel++;
#ifdef XXXXX
					if (sp->value.classdata.cppflags & PF_CONSTRUCTOR) {
						SYM *psp = sp->parentclass ;
                  if (psp && psp->value.classdata.baseclass->vtabsp) {
                     ENODE *ts = makenode(en_nacon,psp->value.classdata.baseclass->vtabsp, 0) ;
							thisn = makenode(en_l_ref,thisn,0);
							ts = makenode(en_assign,thisn,ts) ;
							gen_expr(ts,FALSE,TRUE,4) ;
						}
					}
#endif 
					genstmt(sp->value.classdata.inlinefunc->stmt);
					genreturn(0,3);
                           if (size == -8) {
                              ap = xalloc(sizeof(AMODE)) ;
                              ap->length = currentfunc->tp->btp->type == bt_long ? -6 : 6 ; ;
                              ap->mode = am_axdx ;
                           } else if (size >= 6) {
										ap = makefreg(0);
                           } else {
											ap = makedreg(EAX);
									}
					currentfunc = oldcurfunc;
					retlab = oldretlab;
					return ap;
				}
      }
      return 0;
}
AMODE    *gen_fcall(ENODE *node, int novalue)
/*
 *      generate a function call node and return the address mode
 *      of the result.
 */
{       AMODE    *ap, *result;
				ENODE *pushthis = 0;
        int             i=0,siz1;
				int regax,regdx,regcx;
				if (ap = inlinecall(node))
					return ap;
				if (node->nodetype != en_callblock && node->nodetype != en_scallblock)
					if (ap = HandleIntrins(node, novalue))
						return ap;
#ifdef CPLUSPLUS
				if (node->nodetype == en_thiscall) {
					pushthis = node->v.p[0];
					node = node->v.p[1];
					i = 4;
				}
#endif
				if (node->nodetype == en_callblock || node->nodetype == en_scallblock) {
					siz1 = 4;
				}
				else {
					siz1 = node->v.p[0]->v.i;
				}
				regax = regs[0]; regcx = regs[1]; regdx = regs[2];
            if ((siz1 == 6 || siz1 == -6) && (regax && regdx))
               tempaxdx() ;
            else {
               if (regdx)
                  gen_push(EDX,am_dreg,0);
               if (regax)
                  gen_push(EAX,am_dreg,0);
            }
            if (regcx)
               gen_push(ECX,am_dreg,0);
				regs[0] = regs[1] = regs[2] = 0;
            set_func_mode(1) ;  
				if (node->nodetype == en_callblock || node->nodetype == en_scallblock) {
					i = i + gen_parms(node->v.p[1]->v.p[1]->v.p[1]->v.p[0]);
               ap = gen_expr(node->v.p[0],FALSE,TRUE,4);
					gen_codes(op_push,4,ap,0);
					i+=4;
					node = node->v.p[1];
					freeop(ap);
				}
				else {
               i = i + gen_parms(node->v.p[1]->v.p[1]->v.p[0]);    /* generate parameters */
				}
				if (node->nodetype == en_intcall) {
					AMODE *ap2 = xalloc(sizeof(AMODE));
					ap2->mode = am_seg;
					ap2->seg = e_cs;
					gen_code(op_pushfd,0,0);
					gen_code(op_push,ap2,0);
				}
				else if (pushthis) {
					AMODE *ap2 = gen_expr(pushthis,FALSE,TRUE,4);
					gen_codes(op_push,4,ap2,0);
					freeop(ap2);
				}
									
   	    if( node->v.p[1]->v.p[0]->nodetype == en_nacon || node->v.p[1]->v.p[0]->nodetype == en_napccon ) {
                   SYM *sp= node->v.p[1]->v.p[0]->v.sp;
								if (sp->inreg) {
									ap = makedreg(sp->value.i);
								}
								else {
									node->v.p[1]->v.p[0]->v.p[0] = sp;
     	          	ap = make_offset(node->v.p[1]->v.p[0]);
									if (sp->indirect)
										ap->mode = am_direct ;
									else
										ap->mode = am_immed;
								}
								if (sp->farproc)
									gen_code(op_push,makesegreg(CS),0);
         	      gen_codes(op_call,0,ap,0);
				}
 	      else
   	            {
     	          ap = gen_expr(node->v.p[1]->v.p[0],FALSE,FALSE,4);
       	        freeop(ap);
									
         	      gen_codes(op_call,4,ap,0);
                }
				if (node->nodetype == en_fcall || node->nodetype == en_fcallb || node->nodetype == en_callblock)
            if( i != 0 ) {
								if (i == 4)
									gen_codes(op_pop,4,makedreg(ECX),0);
								else
                	 gen_code(op_add,makedreg(ESP),make_immed(i));
				}
				regs[0] = regax; regs[1] = regcx; regs[2] = regdx;
            set_func_mode(0) ;
            if (siz1 == 6 || siz1 == -6) {
                              result = xalloc(sizeof(AMODE)) ;
                              result->length = siz1 < 0 ? -6 : 6 ;
                              result->mode = am_axdx ;
                              regs[0]++ ;
                              regs[2]++ ;
            } else if (siz1 > 6)
						result = fstack();
				else {
               result = temp_data();
					result->length = siz1;
               if( result->preg != EAX)
                  gen_codes(op_mov,siz1,result,makedreg(EAX));
				}
				if (regcx)
					gen_pop(ECX,am_dreg,0);
            if (siz1 != -6 && siz1 != 6) {
               if (regax)
                  gen_pop(EAX,am_dreg,0);
               if (regdx)
                  gen_pop(EDX,am_dreg,0);
            }
        return result;
}
AMODE    *gen_repcons(ENODE *node)
/*
 *      generate a function call node and return the address mode
 *      of the result.
 */
{       AMODE    *ax, *cx, *ap,*ap1;
				ENODE *pushthis = 0,*onode = node ;
        int             i=0,siz1;
            int lab ;
				int regax,regdx,regcx;
				node = node->v.p[1] ;
#ifdef CPLUSPLUS
				if (node->nodetype == en_thiscall) {
					pushthis = node->v.p[0];
					node = node->v.p[1];
					i = 4;
				}
#endif
            ap1 = gen_expr(onode->v.p[0]->v.p[0],FALSE,FALSE,4) ;
            gen_codes(op_mov,4,cx = makedreg(ECX),ap1) ;
				if (pushthis) {
					AMODE *ap2 = gen_expr(pushthis,FALSE,TRUE,4);
					gen_codes(op_mov,4,ax = makedreg(EAX),ap2) ;
					freeop(ap2);
				}
				gen_label(lab = nextlabel++) ;
				
					gen_codes(op_push,4,cx,0);
					gen_codes(op_push,4,ax,0);
									
   	    if( node->v.p[1]->v.p[0]->nodetype == en_nacon || node->v.p[1]->v.p[0]->nodetype == en_napccon ) {
								SYM *sp= node->v.p[1]->v.p[0]->v.sp;
								if (sp->inreg) {
									ap = makedreg(sp->value.i);
								}
								else {
									node->v.p[1]->v.p[0]->v.p[0] = sp;
     	          	ap = make_offset(node->v.p[1]->v.p[0]);
									if (sp->indirect)
										ap->mode = am_direct ;
									else
										ap->mode = am_immed;
								}
								if (sp->farproc)
									gen_code(op_push,makesegreg(CS),0);
         	      gen_codes(op_call,0,ap,0);
				}
 	      else
   	            {
     	          ap = gen_expr(node->v.p[1]->v.p[0],FALSE,FALSE,4);
       	        freeop(ap);
									
         	      gen_codes(op_call,4,ap,0);
                }
				gen_codes(op_pop,4,ax,0);
				gen_codes(op_pop,4,cx,0);
            gen_codes(op_add,4,ax,make_immed((int)onode->v.p[0]->v.p[1]->v.p[0])) ;
				gen_code(op_loop,make_label(lab),0 );
}
AMODE    *gen_pfcall(ENODE *node, int novalue)
/*
 *      generate a function call node to a pascal function
 *			and return the address mode of the result.
 */
{       AMODE    *ap, *result;
        int             i=0,siz1;
				ENODE * invnode = 0,*anode;
				ENODE *pushthis = 0;
				int regax,regdx,regcx;
				if (ap = inlinecall(node))
					return ap;
				
				/* invert the parameter list */
				if (node->nodetype == en_pcallblock || node->nodetype == en_scallblock)
					anode = node->v.p[1]->v.p[1]->v.p[1]->v.p[0];
				else
					anode = node->v.p[1]->v.p[1]->v.p[0];
				while (anode) {
					invnode = makenode(anode->nodetype,anode->v.p[0],invnode);
					anode = anode->v.p[1];
				}
#ifdef CPLUSPLUS
				if (node->nodetype == en_thiscall) {
					pushthis = node->v.p[0];
					node = node->v.p[1];
					i = 4;
				}
#endif
				if (node->nodetype == en_pcallblock || node->nodetype == en_scallblock) {
					siz1 = 4;
				}
				else {
					siz1 = node->v.p[0]->v.i;
				}
				regax = regs[0]; regcx = regs[1]; regdx = regs[2];
            set_func_mode(1) ;
            if ((siz1 == 6 || siz1 == -6) && (regax && regdx))  {
               tempaxdx() ;
            } else {
               if (regdx)
                  gen_push(EDX,am_dreg,0);
               if (regax)
                  gen_push(EAX,am_dreg,0);
            }
				if (regcx)
					gen_push(ECX,am_dreg,0);
				regs[0] = regs[1] = regs[2] = 0;
				if (pushthis) {
					AMODE *ap2 = gen_expr(pushthis,FALSE,TRUE,4);
					gen_codes(op_push,4,ap2,0);
					freeop(ap2);
				}
				if (node->nodetype == en_pcallblock || node->nodetype == en_scallblock) {
               ap = gen_expr(node->v.p[0],FALSE,FALSE,4);
					gen_codes(op_push,4,ap,0);
					freeop(ap);
					i= i +4;
					i += gen_parms(invnode);
					node = node->v.p[1];
				}
				else {
               i = i + gen_parms(invnode);    /* generate parameters */
				}
									
   	    if( node->v.p[1]->v.p[0]->nodetype == en_nacon || node->v.p[1]->v.p[0]->nodetype == en_napccon ) {
								SYM *sp= node->v.p[1]->v.p[0]->v.sp;
								if (sp->inreg) {
									ap = makedreg(sp->value.i);
								}
								else {
									node->v.p[1]->v.p[0]->v.p[0] = sp;
     	          	ap = make_offset(node->v.p[1]->v.p[0]);
									if (sp->indirect)
										ap->mode = am_direct ;
									else
										ap->mode = am_immed;
								}
								if (sp->farproc)
									gen_code(op_push,makesegreg(CS),0);
         	      gen_codes(op_call,0,ap,0);
				}
 	      else
   	            {
     	          ap = gen_expr(node->v.p[1]->v.p[0],FALSE,FALSE,4);
       	        freeop(ap);
									
         	      gen_codes(op_call,4,ap,0);
                }
				regs[0] = regax; regs[1] = regcx; regs[2] = regdx;
            set_func_mode(0) ;
            if (siz1 == -6 || siz1 == 6) {
                              result = xalloc(sizeof(AMODE)) ;
                              result->length = siz1 < 0 ? -6 : 6 ; ;
                              result->mode = am_axdx ;
                              regs[0]++ ;
                              regs[2]++ ;
				}
            else if (siz1 >= 6)
						result = fstack();
				else {
               result = temp_data();
               result->length = siz1;
               if( result->preg != EAX)
                  gen_codes(op_mov,siz1,result,makedreg(EAX));
				}
				if (regcx)
					gen_pop(ECX,am_dreg,0);
            if (siz1 != 6 && siz1 != -6) {
               if (regax)
                  gen_pop(EAX,am_dreg,0);
               if (regdx)
                  gen_pop(EDX,am_dreg,0);
            }
        return result;
}
AMODE    *gen_expr(ENODE *node, int novalue, int adronly, int size)
/*
 *      general expression evaluation. returns the addressing mode
 *      of the result.
 */
{
				AMODE    *ap1, *ap2;
        int             lab0, lab1,i;
				SYM *sp ;
        if( node == 0 )
                {
                // CPP generates null nodes for cons & des sometimes
//                DIAG("null node in gen_expr.");
                return 0;
                }
        switch( node->nodetype )
                {
                  case en_cl_reg:
                     ap1 = gen_expr(node->v.p[0],novalue,adronly, size) ;
                     if (ap1->mode == am_axdx) {
                        ap2 = tempcx() ;
                        gen_codes(op_mov,1,ap2,makedreg(EAX)) ;
                        freeop(ap1);
                        return ap2 ;
                     } else if (ap1->mode == am_dreg && ap1->preg != ECX) {
                        ap2= tempcx() ;
                        gen_codes(op_mov,4,ap2,ap1) ;
                        freeop(ap1);
                        return ap2 ;
                     }
                     return ap1 ;
								case en_bits:
												ap1 = gen_expr(node->v.p[0],novalue,adronly,size);
                                    if (!adronly)
													ap1 = bit_load(ap1,node);
												return ap1;
								case en_cf: 
                        case en_cfi:
                                    ap1 = gen_expr(node->v.p[0],novalue,adronly,natural_size(node->v.p[0]));
                                    if (size > 7) {
                                       if (!adronly)
                                          ap1 = truncateFloat(ap1,7) ;
                                    } else
                                       if (!adronly)
                                          do_extend(ap1,natural_size(node),F_VOL);
												return ap1;
								case en_cd: 
                        case en_cri:
                                    ap1 = gen_expr(node->v.p[0],novalue,adronly,natural_size(node->v.p[0]));
                                    if (size > 8) {
                                       if (!adronly)
                                          ap1 = truncateFloat(ap1,8) ;
                                    } else
                                       if (!adronly)
                                          do_extend(ap1,natural_size(node),F_VOL);
												return ap1;
                case en_cbool:
								case en_cb: 
								case en_cub:
								case en_cw: 
								case en_cuw:
								case en_cl: 
								case en_cul:
                        case en_cld:
                        case en_cfc:
                        case en_crc:
                        case en_clrc: 
								case en_cp:
                        case en_cll:
                        case en_cull:
                                    ap1 = gen_expr(node->v.p[0],novalue,adronly,natural_size(node->v.p[0]));
												if (!adronly)
                              do_extend(ap1,natural_size(node),F_VOL);
												return ap1;
                case en_napccon:
                case en_nacon:
												node->v.p[0] = node->v.sp;
                case en_nalabcon:
                case en_labcon:
                        ap1 = temp_data();
                        ap2 = xalloc(sizeof(AMODE));
                        ap2->mode = am_direct;
                        ap2->offset = node;     /* use as constant node */
                        gen_codes(op_lea,4,ap1,ap2);
                        return ap1;             /* return reg */
								case en_rcon: 
								case en_lrcon: 
								case en_fcon:
                        case en_fimaginarycon: case en_rimaginarycon: case en_lrimaginarycon:
                        case en_fcomplexcon: case en_rcomplexcon: case en_lrcomplexcon:
                        ap1 = xalloc(sizeof(AMODE));
                        ap1->mode = am_immed;
                        ap1->offset = node;
                                    ap1->length = natural_size(node);
												make_floatconst(ap1);
                        return ap1;
                case en_icon: case en_llcon: case en_llucon:
								case en_lcon: case en_lucon: case en_iucon: 
								case en_ccon:
                        ap1 = xalloc(sizeof(AMODE));
                        ap1->mode = am_immed;
                        ap1->offset = node;
                                    ap1->length = natural_size(node);
                        return ap1;
                case en_absacon:
                        node->v.i = node->v.sp->value.i;
                        ap1 = temp_data();
                        ap2 = xalloc(sizeof(AMODE));
                        ap2->mode = am_direct;
                        ap2->seg = 2 ;
                        ap2->offset = node;     /* use as constant node */
                        gen_codes(op_lea,4,ap1,ap2);
                        return ap1;             /* return reg */
                case en_autocon:
                case en_autoreg:
                        ap1 = temp_data();
                        ap2 = xalloc(sizeof(AMODE));
				                ap2->mode = am_indisp;
			  				        	ap2->preg = EBP;
													sp = node->v.sp;
													i = sp->value.i;
#ifdef CPLUSPLUS
												if ((currentfunc->value.classdata.cppflags & PF_MEMBER) &&
															!(currentfunc->value.classdata.cppflags & PF_STATIC))
													i += 4;
#endif
                              ap2->offset = makeintnode(en_icon,i);
                        gen_codes(op_lea,4,ap1,ap2);
                        return ap1;             /* return reg */
                case en_bool_ref:
                case en_b_ref:
                case en_w_ref:
                case en_ub_ref:
                case en_uw_ref:
                case en_l_ref:
                case en_ul_ref:
								case en_floatref:
								case en_doubleref:
								case en_longdoubleref:
                        case en_fimaginaryref: case en_rimaginaryref: case en_lrimaginaryref:
                        case en_fcomplexref: case en_rcomplexref: case en_lrcomplexref:
                        case en_ll_ref:
                        case en_ull_ref:
                        return gen_deref(node,4);
                case en_tempref:
                case en_regref:
                        ap1 = xalloc(sizeof(AMODE));
												ap1->tempflag = 0;
                        if( (node->v.i & 0xff) < 16 )
                                {
                                ap1->mode = am_dreg;
                                ap1->preg = node->v.i & 0xff;
																ap1->tempflag = 1;
                                }
                        else
													if ((node->v.i &0xff) < 32)
                                {
                                ap1->mode = am_dreg;
                                ap1->preg = (node->v.i & 0xff)- 12;
                                }
													else
                                {
                                ap1->mode = am_freg;
                                ap1->preg = (node->v.i & 0xff) - 32;
                                }
                        ap1->tempflag = 0;      /* not a temporary */
												ap1->length = node->v.i >> 8;
                        return ap1;
								case en_asuminus:
                        return gen_asunary(node,novalue,op_neg, op_fchs,size);
                        case en_ascompl:
                        return gen_asunary(node,novalue,op_not, op_not,size);
                case en_uminus:
                        return gen_unary(node,op_neg, op_fchs,size);
                case en_compl:
                        return gen_unary(node,op_not, op_not,size);
                case en_add:
								case en_addstruc:
                        return gen_binary(node,op_add,op_faddp,op_fadd, op_faddp, op_fadd,size);
                case en_sub:
                        return gen_binary(node,op_sub,op_fsubp,op_fsub,op_fsubrp, op_fsubr,size);
                case en_and:
                        return gen_xbin(node,op_and,op_btr,size);
                case en_or:
                        return gen_xbin(node,op_or,op_bts,size);
				case en_xor:
						return gen_xbin(node,op_xor,op_btc,size);
								case en_pmul:
												return gen_pmul(node,size);
								case en_pdiv:
												return gen_pdiv(node,size);
                case en_mul:
                        return gen_mul(node,op_imul,op_fmulp,op_fmul,op_fmulp,op_fmul,size);
                case en_umul:
                        return gen_mul(node,op_mul,op_fmulp,op_fmul,op_fmulp, op_fmul,size);
                case en_div:
                        return gen_modiv(node,op_idiv,op_fdivp,op_fdiv,op_fdivrp, op_fdivr, 0,size);
                case en_udiv:
                        return gen_modiv(node,op_div,op_fdivp,op_fdiv,op_fdivrp, op_fdivr, 0,size);
                case en_mod:
                        return gen_modiv(node,op_idiv,op_fdivp,op_fdiv,op_fdivrp,op_fdivr, 1,size);
                case en_umod:
                        return gen_modiv(node,op_div,op_fdivp,op_fdiv,op_fdivrp, op_fdivr, 1,size);
                case en_alsh:
                        return gen_shift(node,op_sal,size,FALSE);
                case en_arsh:
                        return gen_shift(node,op_sar,size,FALSE);
                case en_arshd:
                        return gen_shift(node,op_sar,size,TRUE);
                case en_lsh:
                        return gen_shift(node,op_shl,size,FALSE);
                case en_rsh:
                        return gen_shift(node,op_shr,size,FALSE);
                case en_asadd:
                        return gen_asadd(node,novalue,op_add,op_faddp,op_fadd,op_faddp,op_fadd,size);
                case en_assub:
                        return gen_asadd(node,novalue,op_sub,op_fsubp,op_fsub,op_fsubrp,op_fsubr,size);
                case en_asand:
                        return gen_aslogic(node,novalue,op_and,op_btr,size);
                case en_asor:
                        return gen_aslogic(node,novalue,op_or,op_bts,size);
                case en_asxor:
                        return gen_aslogic(node,novalue,op_xor,op_btc,size);
                case en_aslsh:
                        return gen_asshift(node,novalue,op_shl,size,FALSE);
                case en_asrsh:
                        return gen_asshift(node,novalue,op_shr,size,FALSE);
                case en_asalsh:
                        return gen_asshift(node,novalue,op_sal,size,FALSE);
                case en_asarsh:
                        return gen_asshift(node,novalue,op_sar,size,FALSE);
                case en_asarshd:
                        return gen_asshift(node,novalue,op_sar,size,TRUE);
                case en_asmul:
                        return gen_asmul(node, novalue,op_imul,op_fmulp,op_fmul, op_fmulp, op_fmul,size);
                case en_asumul:
                        return gen_asmul(node,novalue,op_mul,op_fmulp,op_fmul,op_fmulp, op_fmul,size);
                case en_asdiv:
                        return gen_asmodiv(node,novalue,op_idiv,op_fdivp,op_fdiv,op_fdivrp, op_fdivr, FALSE,size);
                case en_asudiv:
                        return gen_asmodiv(node,novalue,op_div,op_fdivp,op_fdiv,op_fdivrp, op_fdivr, FALSE,size);
                case en_asmod:
                        return gen_asmodiv(node,novalue,op_idiv,op_fdivp,op_fdiv,op_fdivrp, op_fdivr, TRUE,size);
                case en_asumod:
                        return gen_asmodiv(node,novalue,op_div,op_fdivp,op_fdiv,op_fdivrp, op_fdivr, TRUE,size);
                case en_assign:
                        return gen_assign(node,novalue,size,TRUE);
                case en_lassign:
                        return gen_assign(node,novalue,size,FALSE);
                case en_refassign:
                        return gen_refassign(node,novalue,size);
                case en_moveblock:
                        return gen_moveblock(node);
                case en_ainc:
                        return gen_aincdec(node,novalue,op_add,size);
                case en_adec:
                        return gen_aincdec(node,novalue,op_sub,size);
                case en_land:   case en_lor:
                case en_eq:     case en_ne:
                case en_lt:     case en_le:
                case en_gt:     case en_ge:
                case en_ult:    case en_ule:
                case en_ugt:    case en_uge:
                case en_not:
												return gen_relat(node);
                case en_cond:
                        return gen_hook(node,size);
                case en_voidnz:
                        lab0 = nextlabel++;
                        falsejp(node->v.p[0]->v.p[0],lab0);
                        initstack() ;
                        gen_void(node->v.p[1]) ;
                        gen_label(lab0);
                        return gen_expr(node->v.p[0]->v.p[1],FALSE,FALSE,4) ; /* will typically be part of a void tree, or top of tree */
                case en_void:
                        gen_void(node->v.p[0]);
												initstack() ;
                        return gen_expr(node->v.p[1],TRUE,FALSE,natural_size(node));
								case en_pfcall: case en_pfcallb:  case en_pcallblock:
												return gen_pfcall(node,novalue);
								case en_sfcall: case en_sfcallb:  case en_scallblock:
                case en_fcall:  case en_callblock: case en_fcallb:
								case en_intcall: case en_thiscall:
                        return gen_fcall(node,novalue);
                case en_trapcall:
												return gen_tcall(node, novalue);
								case en_repcons:
												initstack() ;
												return gen_repcons(node) ;
                default:
                        DIAG("uncoded node in gen_expr.");
                        return 0;
                }
}
AMODE	   *gen_void(ENODE *node)
{
   gen_expr(node,TRUE,FALSE,natural_size(node));
	gen_code(op_void,0,0);
	return 0;
}

int     natural_size(ENODE *node)
/*
 *      return the natural evaluation size of a node.
 */
{       int     siz0, siz1;
        if( node == 0 )
                return 0;
        switch( node->nodetype )
                {
                        case en_bits: case en_cl_reg:
                                    return natural_size(node->v.p[0]) ;
                case en_icon:
								case en_lcon:
												return -4; 
								case en_lucon: 
                case en_iucon:
												return 4;
                        case en_llcon:
                                    return -6 ;
                        case en_llucon:
                                    return 6 ;
								case en_ccon:                 
												return 4;
								case en_rcon:
								case en_doubleref:
												return 8;
								case en_lrcon:
								case en_longdoubleref:
												return 10;
								case en_fcon:
								case en_floatref:
                                    return 7;
                        case en_fimaginaryref: 
                        case en_fimaginarycon: 
                        case en_cfi:
                           return 15;
                        case en_rimaginaryref: 
                        case en_rimaginarycon: 
                        case en_cri:
                           return 16;
                        case en_lrimaginaryref:
                        case en_lrimaginarycon:
                        case en_clri:
                           return 17;
                        case en_fcomplexref: 
                        case en_fcomplexcon: 
                        case en_cfc:
                           return 20;
                        case en_rcomplexref: 
                        case en_rcomplexcon: 
                        case en_crc:
                           return 21;
                        case en_lrcomplexref:
                        case en_lrcomplexcon:
                        case en_clrc:
                           return 22;
								case en_trapcall:
                case en_labcon:
                case en_nacon:  case en_autocon:  case en_autoreg:
                case en_napccon:  case en_absacon: case en_nalabcon:
												return stdaddrsize;
								case en_l_ref:
								case en_cl:
												return -4;
								case en_thiscall:
                                    return natural_size(node->v.p[0]);
								case en_scallblock: case en_sfcallb: case en_sfcall:
								case en_pfcall: case en_pfcallb: /* ignore pascal style now */
								case en_pcallblock:
								case en_fcall: case en_callblock: case en_fcallb:
								case en_intcall:
                                    return natural_size(node->v.p[1]);
								case en_tempref:
								case en_regref:
												return node->v.i >> 8;
                case en_ul_ref:
								case en_cul:
                        return 4;
								case en_cp:
												return stdaddrsize;
                case en_bool_ref: case en_cbool:
                        return 5;
                case en_ub_ref:
								case en_cub:
												return 1;
                case en_b_ref:
								case en_cb:
                        return -1;
                case en_uw_ref:
								case en_cuw:
												return 2;
                case en_cw:
                case en_w_ref:
                        return -2;
								case en_cd:
												return 8;
								case en_cld:
												return 10;
								case en_cf:
                                    return 7;  
                case en_cll:
                case en_ll_ref:
                        return -6 ;
                case en_cull:
                case en_ull_ref:
                        return 6 ;
                case en_not:    case en_compl:
                case en_uminus: case en_assign: case en_refassign: case en_lassign:
                case en_ainc:   case en_adec: case en_asuminus: case en_ascompl:
								case en_moveblock: case en_stackblock:
                        return natural_size(node->v.p[0]);
                case en_add:    case en_sub: case en_addstruc:
								case en_umul:		case en_udiv:	case en_umod: case en_pmul:
                case en_mul:    case en_div:  case en_pdiv:
                case en_mod:    case en_and:
                case en_or:     case en_xor:
								case en_asalsh: case en_asarsh: case en_alsh: case en_arsh: case en_arshd: case en_asarshd:
                case en_lsh:    case en_rsh:
                case en_eq:     case en_ne:
                case en_lt:     case en_le:
                case en_gt:     case en_ge:
								case en_ugt: case en_uge: case en_ult: case en_ule:
                case en_land:   case en_lor:
                case en_asadd:  case en_assub:
                case en_asmul:  case en_asdiv:
                case en_asmod:  case en_asand:
								case en_asumod: case en_asudiv: case en_asumul:
                case en_asor:   case en_aslsh:  case en_asxor:
                case en_asrsh:
                        siz0 = natural_size(node->v.p[0]);
                        siz1 = natural_size(node->v.p[1]);
                        if( chksize(siz1,siz0))
                                return siz1;
                        else
                                return siz0;
                case en_void:   case en_cond:  case en_repcons:
                        return natural_size(node->v.p[1]);
                case en_voidnz:
                        return natural_size(node->v.p[0]);
                default:
                        DIAG("natural size error.");
                        break;
                }
        return 0;
}

/*
 * subroutine evaluates a node determining how to test it for
 * non-zero
 */
static int defcond(ENODE *node) 
{
  AMODE *ap1;
	int rv = 0;
   int nsiz;
   if ((nsiz = natural_size(node)) > 6) {
      ap1 = gen_expr(node,FALSE,FALSE,nsiz);
	 	do_extend(ap1,10,F_FREG | F_VOL);
		gen_codef(op_fldz,0,0);
		gen_codef(op_fcompp,0,0);
		if (regs[0])
			gen_push(EAX,am_dreg,0);
	  gen_codefs(op_fstsw,2,makedreg(EAX),0);
		gen_codef(op_fwait,0,0);
		gen_code(op_sahf,0,0);
		if (regs[0])
			gen_pop(EAX,am_dreg,0);
	}
   else if (nsiz == 6 || nsiz == -6) {
      ap1 = gen_expr(node,FALSE,FALSE,nsiz);
      do_extend(ap1,6,F_AXDX);
      gen_codes(op_or,4,makedreg(EAX),makedreg(EDX)) ;
   } else {
		if (isbit(node)) {
         ap1 = gen_expr(node,FALSE,TRUE,0);
			if (node->bits == 1) {
				rv = 1;
				gen_codes(op_bt,4,ap1,make_immed(node->startbit));
			} else
            gen_code(op_test,ap1,make_immed(mod_mask(node->bits)<<node->startbit));
		}
		else {
         ap1 = gen_expr(node,FALSE,FALSE,0);
         if (ap1->mode == am_immed)
            do_extend(ap1,ap1->length,F_DREG | F_VOL) ;
			gen_code(op_cmp,ap1,make_immed(0));
		}
	}
  freeop(ap1);
	return rv;
}
static AMODE *truerelat(ENODE *node)
{       AMODE    *ap1;
        if( node == 0 )
                return 0;
        switch( node->nodetype )
                {
                case en_eq:
                        ap1 = gen_compare(node,op_sete,op_sete,0,0,op_sete,op_sete,0);
                        break;
                case en_ne:
                        ap1 = gen_compare(node,op_setne,op_setne,0,0,op_setne,op_setne,0);
                        break;
                case en_lt:
                        ap1 = gen_compare(node,op_setl,op_setg,0,0,op_seta,op_setb,0);
                        break;
                case en_le:
                        ap1 = gen_compare(node,op_setle,op_setge,0,0,op_setnc,op_setbe,0);
                        break;
                case en_gt:
                        ap1 = gen_compare(node,op_setg,op_setl,0,0,op_setb,op_seta,0);
                        break;
                case en_ge:
                        ap1 = gen_compare(node,op_setge,op_setle,0,0,op_setbe,op_setnc,0);
                        break;
                case en_ult:
                        ap1 = gen_compare(node,op_setb,op_seta,0,0,op_seta,op_setb,0);
                        break;
                case en_ule:
                        ap1 = gen_compare(node,op_setbe,op_setnc,0,0,op_setnc,op_setbe,0);
                        break;
                case en_ugt:
                        ap1 = gen_compare(node,op_seta,op_setb,0,0,op_setb,op_seta,0);
                        break;
                case en_uge:
                        ap1 = gen_compare(node,op_setnc,op_setbe,0,0,op_setbe,op_setnc,0);
                        break;
                case en_not:
												if (isintconst(node->nodetype)) {
													ap1 = gen_expr(node,FALSE,FALSE,0);
													ap1->offset->v.i = !ap1->offset->v.i;
													break;
												}
												if (defcond(node->v.p[0])) {
													ap1 = temp_data();
													gen_codes(op_setnc,1,ap1,0);
												} else {
													ap1 = temp_data();
													gen_codes(op_sete,1,ap1,0);
												} 
                        break;
                default:
												DIAG("True-relat error");
                        break;
                }
  ap1->length = 1;
	return ap1;
}
static int complex_relat(ENODE *node)
{
				if (!node)
					return 0;
        switch( node->nodetype )
                {
                case en_cl_reg:
                  return complex_relat(node->v.p[0]) ;
                case en_ull_ref:
                case en_ll_ref:
                case en_cull:
                case en_cll:
                case en_llcon: case en_llucon:
                  return 1 ;
								case en_bits:
								case en_l_ref:
								case en_cl:
                case en_ul_ref:
								case en_cul:
								case en_cp:
                case en_ub_ref:
								case en_cub:
                case en_bool_ref: case en_cbool:
                case en_b_ref:
                case en_cb:
                case en_uw_ref:
								case en_cuw:
                case en_cw:
                case en_w_ref:
								case en_cd:
								case en_cld:
								case en_cf:
                        case en_cfc: case en_crc: case en_clrc:
                        case en_cfi: case en_cri: case en_clri:
                case en_uminus: 
                case en_ainc:   case en_adec: 
								case en_moveblock: case en_stackblock:
												return complex_relat(node->v.p[0]);
                case en_icon:
								case en_lcon: 
								case en_lucon: 
								case en_iucon: 
								case en_ccon:                 
								case en_rcon:
								case en_doubleref:
								case en_lrcon:
								case en_longdoubleref:
								case en_fcon:
								case en_floatref:
                        case en_fimaginaryref: case en_rimaginaryref: case en_lrimaginaryref:
                        case en_fcomplexref: case en_rcomplexref: case en_lrcomplexref:
                        case en_fimaginarycon: case en_rimaginarycon: case en_lrimaginarycon:
                        case en_fcomplexcon: case en_rcomplexcon: case en_lrcomplexcon:
								case en_absacon:
								case en_trapcall:
                case en_labcon:
                case en_nacon:  case en_autocon:  case en_autoreg:
                case en_napccon: case en_nalabcon:
								case en_tempref:
								case en_regref:
												return 0;
                case en_eq:     case en_ne:
                case en_lt:     case en_le:
                case en_gt:     case en_ge:
								case en_ugt: case en_uge: case en_ult: case en_ule:
                case en_land:   case en_lor:
                case en_not:    case en_compl:
												return 1;
								case en_div: case en_udiv: case en_pdiv: case en_mod: case en_umod:
                        case en_assign: case en_refassign: case en_lassign:
                        case en_asuminus: case en_ascompl:
                case en_add:    case en_sub: case en_addstruc:
								case en_umul:		case en_pmul:
                case en_mul:		case en_and:
                case en_or:     case en_xor:
								case en_asalsh: case en_asarsh: case en_alsh: case en_arsh: case en_arshd: case en_asarshd:
                case en_lsh:    case en_rsh:
                case en_asadd:  case en_assub:
                case en_asmul:  case en_asdiv:
                case en_asmod:  case en_asand:
								case en_asumod: case en_asudiv: case en_asumul:
                case en_asor:   case en_aslsh:  case en_asxor:
                case en_asrsh:  case en_repcons:
												return complex_relat(node->v.p[0]) || complex_relat(node->v.p[1]);
                case en_void:   case en_cond: case en_voidnz:
												return complex_relat(node->v.p[1]);
								case en_sfcall: case en_sfcallb: case en_scallblock:
								case en_pfcall: case en_pfcallb: case en_thiscall:
								case en_fcall: case en_intcall: case en_callblock: case en_fcallb:
								case en_pcallblock:
												return 0;
                default:
                        DIAG("error in complex_relat routine.");
												return 1;
                }
}
AMODE *gen_relat(ENODE *node)
{
	long lab1;
	AMODE *ap1;
   int size = natural_size(node);
   if (size >= 6 || size == -6)
		size = 4;
	if (node->nodetype != en_land && node->nodetype != en_lor &&
			!complex_relat(node->v.p[0]) && !complex_relat(node->v.p[1])) {
		ap1 = truerelat(node);
	}
	else {
	  lab1 = nextlabel++;
	  truejp(node,lab1);
	  ap1 = temp_data();
		if (ap1->mode != am_dreg) {
			DIAG("gen_relat: No free temp regs");
		}
		else {
	  	gen_codes(op_sub,4,ap1,ap1);
gen_comment("; TEST EAX,IMMED (branches around next four bytes of code)\n");
			gen_codes(op_genword,0,make_immed(0xa9),0);
			gen_label(lab1);
			gen_codes(op_sub,4,ap1,ap1);
			gen_codes(op_inc,4,ap1,0);
			gen_codes(op_nop,0,0,0);
			ap1->length = size;
		}
	}
  return ap1;
}
AMODE *gen_compare(ENODE *node, int btype1, int btype2, int btype3, int btype4, int fbtype1, int fbtype2,int label)
/*
 *      generate code to do a comparison of the two operands of
 *      node.
 */
{       AMODE    *ap1, *ap2, *ap3, *ap4, *ap5;
				int btype = btype1;
				int bitted = FALSE ;
            int size ;
				/* can't use PREFER here because evaluation ordering is 
				 * strict... we won't be using sets unless we have already
				 * qualified this as a very short sequence that can be fully
	       * evaluated
				 */
            if ((size = natural_size(node)) > 6) {
               ap2 = gen_expr(node->v.p[1],FALSE,FALSE, size);
               noids(ap2);
               ap1 = gen_expr(node->v.p[0],FALSE,FALSE, size);
					do_extend(ap1,10,F_FREG | F_VOL);
					do_extend(ap2,10,F_FREG | F_VOL);
					gen_codef(op_fcompp,0,0);
					if (regs[0])
						gen_push(EAX,am_dreg,0);
					gen_codefs(op_fstsw,2,makedreg(EAX),0);
					gen_codef(op_fwait,0,0);
					gen_code(op_sahf,0,0);
					if (regs[0])
						gen_pop(EAX,am_dreg,0);
					freeop(ap1);
					freeop(ap2);
					if (label) {
							gen_branch(fbtype1,make_label(label));
					}
					else {
                     ap1 = temp_data() ;
							ap1->length = 1;
							gen_code(fbtype1,ap1,0);
					}
					return ap1;

            }                            
            if (size == 6 || size == -6) {
               ap2 = gen_expr(node->v.p[1],FALSE,FALSE,size) ;
               ap2 = aprtocx(ap2) ;
               do_extend(ap2,6, F_MEM | F_AXDX) ;
               if (ap2->mode == am_axdx) {
                  ap4 = floatconvpos() ;
                  ap4->offset = makenode(en_add,ap4->offset,makeintnode(en_icon,8)) ;
                  ap3 = copy_addr(ap4) ;
                  ap3->offset = makenode(en_add,ap3->offset,makeintnode(en_icon,4)) ;
                  freeop(ap2) ;
                  gen_codes(op_mov,4,ap4,makedreg(EAX));
                  gen_codes(op_mov,4,ap3,makedreg(EDX));
                  ap2 = ap4 ;
               } else {
                  ap3 = copy_addr(ap2) ;
                  if (ap2->mode == am_immed) {
                     ap3->offset = copy_enode(ap2->offset) ;
                     ap3->offset->v.i >>= 16 ;
                     ap2->offset->v.i &= 0xffffffff ;
                  } else
                     ap3->offset = makenode(en_add, ap2->offset, makeintnode(en_icon,4)) ;
               }
               ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size) ;
               do_extend(ap1,6, F_AXDX) ;
               if (btype1 == op_je || btype1 == op_sete || btype1 == op_jne || btype1 == op_setne) {
                  ap2->length = ap3->length = 4 ;
                  gen_code(op_sub,makedreg(EAX),ap2) ;
                  gen_code(op_sbb,makedreg(EDX),ap3) ;
                  gen_code(op_or,makedreg(EAX),makedreg(EDX));
                  freeop(ap1) ;
                  freeop(ap2) ;
                  if (label) {
                     gen_branch(fbtype1,make_label(label));
                  }
                  else {
                     ap1 = temp_data() ;
							ap1->length = 1;
							gen_code(fbtype1,ap1,0);
                  }
               } else {
                  int templab = nextlabel++ ;
                  if (label) {
                     gen_codes(op_cmp,4,makedreg(EDX),ap3) ;
                     gen_branch(btype3,make_label(label)) ;
                     gen_branch(btype4,make_label(templab)) ;
                     gen_codes(op_cmp,4,makedreg(EAX),ap2) ;
                     gen_branch(fbtype2,make_label(label)) ;
                     gen_label(templab) ;
                     freeop(ap1) ;
                     freeop(ap2) ;
                  } else {
                     ap4 = floatconvpos() ;
                     ap5 = copy_addr(ap4) ;
                     ap5->offset = makenode(en_add,ap4->offset,makeintnode(en_icon,1)) ;
                     gen_codes(op_cmp,4,makedreg(EDX),ap3) ;
                     gen_codes(btype1,1,ap4,0) ;
                     gen_codes(op_cmp,4,makedreg(EAX),ap2) ;
                     gen_codes(btype1,1,ap5,0) ;
                     freeop(ap1) ;
                     freeop(ap2) ;
                     ap1 = temp_data() ;
							ap1->length = 1;
                     gen_codes(op_mov,1,ap1,ap4) ;
                     gen_codes(op_or,1,ap1,ap1) ;
                     gen_branch(op_jz,make_label(templab)) ;
                     gen_codes(op_mov,1,ap1,ap5) ;
                     gen_label(templab) ;
                     
                  }
               }
               return ap1 ;
            }
				if ((isbit(node->v.p[0]) || isbit(node->v.p[1])) && (btype1 == op_je || btype1 == op_jne || btype1 == op_sete || btype1 == op_setne)) {
					ENODE *xnode;
					bitted = TRUE ;
					if (isbit(node->v.p[0])) {
  					ap2 = gen_expr(node->v.p[1],FALSE,FALSE,4);
						noids(ap2);
  					ap1 = gen_expr(xnode = node->v.p[0],FALSE,TRUE,4);
					} else {
  					ap2 = gen_expr(node->v.p[0],FALSE,FALSE,4);
						noids(ap2);
  					ap1 = gen_expr(xnode = node->v.p[1],FALSE,TRUE,4);
					}
					if (ap2->mode == am_immed) {
						if (xnode->bits == 1) {
							if (!(ap2->offset->v.i & 1)) {
								gen_codes(op_bt,4,ap1,make_immed(xnode->startbit));
								switch (btype1) {
									case op_je:
										btype = op_jnc;
										break;
									case op_jne:
										btype = op_jb;
										break;
									case op_sete:
										btype = op_setnc;
										break;
									case op_setne:
										btype = op_setb;
										break;
								}
							} else {
								gen_codes(op_bt,4,ap1,make_immed(xnode->startbit));
								switch (btype1) {
									case op_je:
										btype = op_jb;
										break;
									case op_jne:
										btype = op_jnc;
										break;
									case op_sete:
										btype = op_setb;
										break;
									case op_setne:
										btype = op_setnc;
										break;
								}
							}
						} else goto join;
					}
					else {
join:
						ap1=bit_load(ap1,xnode);
						goto join2;
					}
				}
				else {
               resolve_binary(node,&ap1,&ap2,natural_size(node));
join2:
               if (is_memory(ap1) && is_memory(ap2) || ap1->mode == am_immed && ap2->mode == am_immed) {
						do_extend(ap1,ap2->length,F_DREG | F_VOL);
						gen_code(op_cmp,ap1,ap2);
					}
					else {
						if (ap1->mode == am_immed) {
							btype = btype2;
							do_extend(ap2,4,F_DREG);
							gen_code(op_cmp,ap2,ap1);
						}
						else
							gen_code(op_cmp,ap1,ap2);
					}
				}
						/* Cmp turns into test int peep386... or goes away altogether
 						 * if comparing against zero to support this and the
						 * sub->dec optimization we have to tiddle with the branch
						 * code when comparing unsigneds against zero */
				freeop(ap1);
				freeop(ap2);
				if (!bitted && ap2->mode == am_immed && ap2->offset->v.i == 0) {
					switch(btype) {
						case op_seta:
							btype = op_setnz ;
							break ;
						case op_setae:
							gen_code (op_clc,0,0);
							break ;
						case op_setb:
							gen_code (op_clc,0,0);
							break ;
						case op_setbe:
							btype = op_sete ;
							break ;
						case op_ja :
							btype = op_jnz ;
							break ;
						case op_jae:
							btype = op_jmp ; /* Following code never gets executed */
							break ;
						case op_jb: /* Following code always gets executed */
							return ap1;
						case op_jbe :
							btype = op_jz ;
							break ;
					}
				}						
				if (label) {
						gen_branch(btype,make_label(label));
				}
				else {
						ap1 = temp_data();
						ap1->length = 1;
						gen_code(btype,ap1,0);
				}
				return ap1;
}

void truejp(ENODE *node, int label)
/*
 *      generate a jump to label if the node passed evaluates to
 *      a true condition.
 */
{
        int             lab0;
        if( node == 0 )
                return;
        switch( node->nodetype )
                {
                case en_eq:
                        gen_compare(node,op_je,op_je,op_je,op_je,op_je,op_je,label);
                        break;
                case en_ne:
                        gen_compare(node,op_jne,op_jne,op_jne,op_jne,op_jne,op_jne,label);
                        break;
                case en_lt:
                        gen_compare(node,op_jl,op_jg,op_jl,op_jg,op_ja,op_jb,label);
                        break;
                case en_le:
                        gen_compare(node,op_jle,op_jge,op_jl,op_jg,op_jnc,op_jbe,label);
                        break;
                case en_gt:
                        gen_compare(node,op_jg,op_jl,op_jg,op_jl,op_jb,op_jnc,label);
                        break;
                case en_ge:
                        gen_compare(node,op_jge,op_jle,op_jg,op_jl,op_jbe,op_jnc,label);
                        break;
                case en_ult:
                        gen_compare(node,op_jb,op_ja,op_jb,op_ja,op_ja,op_jb,label);
                        break;
                case en_ule:
                        gen_compare(node,op_jbe,op_jnc,op_jb,op_ja,op_jnc,op_jbe,label);
                        break;
                case en_ugt:
                        gen_compare(node,op_ja,op_jb,op_ja,op_jb,op_jb,op_ja,label);
                        break;
                case en_uge:
                        gen_compare(node,op_jnc,op_jbe,op_ja,op_jb,op_jbe,op_jnc,label);
                        break;
                case en_land:
                        lab0 = nextlabel++;
                        falsejp(node->v.p[0],lab0);
                        truejp(node->v.p[1],label);
                        gen_label(lab0);
                        break;
                case en_lor:
                        truejp(node->v.p[0],label);
                        truejp(node->v.p[1],label);
                        break;
                case en_not:
                        falsejp(node->v.p[0],label);
                        break;
                default:
												if (isintconst(node->nodetype)) {
													if (node->v.i != 0) 
                        		gen_code(op_jmp,make_label(label),0);
													break;
												}
			 									if (defcond(node))
                        	gen_branch(op_jc,make_label(label));
												else
                        	gen_branch(op_jne,make_label(label));
                        break;
                }
}

void falsejp(ENODE *node, int label)
/*
 *      generate code to execute a jump to label if the expression
 *      passed is false.
 */
{       
        int             lab0;
        if( node == 0 )
                return;
        switch( node->nodetype )
                {
                case en_eq:
                        gen_compare(node,op_jne,op_jne,op_jne,op_jne,op_jne,op_jne,label);
                        break;
                case en_ne:
                        gen_compare(node,op_je,op_je,op_je,op_je,op_je,op_je,label);
                        break;
                case en_lt:
                        gen_compare(node,op_jge,op_jle,op_jg,op_jl,op_jbe,op_jnc,label);
                        break;
                case en_le:
                        gen_compare(node,op_jg,op_jl,op_jg,op_jl,op_jb,op_ja,label);
                        break;
                case en_gt:
                        gen_compare(node,op_jle,op_jge,op_jl,op_jg,op_jnc,op_jbe,label);
                        break;
                case en_ge:
                        gen_compare(node,op_jl,op_jg,op_jl,op_jg,op_ja,op_jb,label);
                        break;
                case en_ult:
                        gen_compare(node,op_jnc,op_jbe,op_ja,op_jb,op_jbe,op_jnc,label);
                        break;
                case en_ule:
                        gen_compare(node,op_ja,op_jb,op_ja,op_jb,op_jb,op_ja,label);
                        break;
                case en_ugt:
                        gen_compare(node,op_jbe,op_jnc,op_jb,op_ja,op_jae,op_jbe,label);
                        break;
                case en_uge:
                        gen_compare(node,op_jb,op_ja,op_jb,op_ja,op_ja,op_jb,label);
                        break;
                case en_land:
                        falsejp(node->v.p[0],label);
                        falsejp(node->v.p[1],label);
                        break;
                case en_lor:
                        lab0 = nextlabel++;
                        truejp(node->v.p[0],lab0);
                        falsejp(node->v.p[1],label);
                        gen_label(lab0);
                        break;
                case en_not:
                        truejp(node->v.p[0],label);
                        break;
                default:
												if (isintconst(node->nodetype)) {
													if (node->v.i == 0) 
                        		gen_code(op_jmp,make_label(label),0);
													break;
												}
												if (defcond(node))
                        	gen_branch(op_jnc,make_label(label));
												else
                        	gen_branch(op_je,make_label(label));
                        break;
                }
}