/* 
CC386 C Compiler
Copyright 1994-2006 David Lindauer.

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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

This program is derived from the cc68k complier by 
Matthew Brandt (mailto::mattb@walkingdog.net) 

You may contact the author of this derivative at:

mailto::camille@bluegrass.net
 */
#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;
extern int prm_stackalign;

#define ABS(x) ( (x) < 0 ? -(x) : (x))
/*
 *      this module contains all of the code generation routines
 *      for evaluating expressions and conditions.
 */
extern int prm_optmult;
extern SYM *declclass;
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], sregs[3];
extern long nextlabel;
extern long lc_maxauto;
extern int prm_cmangle;
extern int prm_cplusplus;
extern int prm_farkeyword;

extern int floatstack_mode;
AMODE freg0[] = 
{
    {
        am_freg, 0
    }
};
AMODE sreg[] = 
{
    {
        am_dreg, BESZ_DWORD 
    }
};

int genning_inline;
static int ldx[] = 
{
    op_mov, 0, op_lds, op_les, op_lfs, op_lgs, op_lss
};

static int last_align;

/* 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-BESZ_IFLOAT 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;
		lc_maxauto += constv;
    }
    ap1 = xalloc(sizeof(AMODE));
    ap1->mode = am_indisp;
    ap1->preg = EBP;
    if (prm_farkeyword)
        ap1->seg = SS;
    ap1->offset = makeintnode(en_icon,  - lc_maxauto);
    ap1->length = BESZ_DWORD ;
    return ap1;
}

//-------------------------------------------------------------------------

int defseg(ENODE *node)
{
    int rv = 0; // default DS
    if (!prm_farkeyword)
        return rv;
    while (castvalue(node))
        node = node->v.p[0];
    if (node->nodetype == en_napccon)
        rv = CS;
    if (node->nodetype == en_autocon)
        rv = SS;
    return rv;
}

//-------------------------------------------------------------------------

AMODE *truncateFloat(AMODE *ap1, int size)
{
    AMODE *ap = floatconvpos();
    do_extend(ap1, size, F_FREG);
    gen_codefs(op_fstp, size, ap, 0);
    gen_codefs(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 == BESZ_BOOL)
     /* BESZ_BOOL is used for bools, which are the smallest type now */
        if (lsize == BESZ_BOOL)
            return FALSE;
        else
            return TRUE;
    if (lsize == BESZ_BOOL)
        return FALSE;
    if (rsize ==  BESZ_FARPTR)
        if (lsize ==  BESZ_FARPTR)
            return FALSE;
        else
            return l >= BESZ_QWORD;
        else
            if (lsize ==  BESZ_FARPTR)
                return r < BESZ_QWORD;
    return (l > r);
}

//-------------------------------------------------------------------------

AMODE *fstack(void)
{
    AMODE *ap = xalloc(sizeof(AMODE));
    ap->mode = am_freg;
    ap->length = BESZ_LDOUBLE;
    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))
    {
        LongLongToFPF(&ap->offset->v.f, ap->offset->v.i);
        ap->offset->nodetype = en_rcon;
        size = BESZ_FLOAT;
    }
    else
    {
        switch (ap->offset->nodetype)
        {
            case en_fcon:
                size = BESZ_FLOAT;
                break;
            case en_rcon:
                size = BESZ_DOUBLE;
                break;
            case en_lrcon:
                size = BESZ_LDOUBLE;
                break;
            case en_fimaginarycon:
                size = BESZ_IFLOAT;
                break;
            case en_rimaginarycon:
                size = BESZ_IDOUBLE;
                break;
            case en_lrimaginarycon:
                size = BESZ_ILDOUBLE;
                break;
            case en_fcomplexcon:
                size = BESZ_CFLOAT;
                break;
            case en_rcomplexcon:
                size = BESZ_CDOUBLE;
                break;
            case en_lrcomplexcon:
                size = BESZ_CLDOUBLE;
                break;
			default:
				DIAG("invalid floating constant");
				return;
        }
    }
    if (ValueIsOne(&ap->offset->v.f))
    {
        ap->mode = am_fconst;
        ap->preg = fcone;
    }
    else if (ap->offset->v.f.type == IFPF_IS_ZERO)
    {
        ap->mode = am_fconst;
        ap->preg = fczero;
    }
    else if (size >= BESZ_CFLOAT)
    {
        AMODE *ap1;
        int siz1 = size -13;
        int o = prm_optmult ;
        prm_optmult = FALSE;
        if (siz1>BESZ_DOUBLE)
            siz1++;
        ap1 = make_label(queue_floatval(&ap->offset->v.c.r, siz1));
        queue_floatval(&ap->offset->v.c.i, siz1);
        ap->mode = am_direct;
        ap->length = size;
        ap->offset = ap1->offset;
        prm_optmult = o ;
    }
    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 BESZ_BYTE:
            case  - 1: i &= 0xff;
            break;
        case BESZ_WORD:
            case  - BESZ_WORD: i &= 0xffff;
            break;
        case BESZ_DWORD :
            case  - BESZ_DWORD : 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 = 0;
    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, BESZ_WORD, ax = makedreg(EAX), copy_addr(&vv));
        gen_codes(op_or, 1, makedreg(4), make_immed(0xc));
        vv.offset = makeintnode(en_icon, BESZ_LDOUBLE);
        gen_codes(op_mov, BESZ_WORD, copy_addr(&vv), ax);
        gen_code(op_fldcw, copy_addr(&vv), 0);
        vv.offset = e0 = makeintnode(en_icon, 0);
        gen_codes(op_fistp, BESZ_DOUBLE, copy_addr(&vv), 0);
        vv.offset = e8;
        gen_code(op_fldcw, copy_addr(&vv), 0);
        vv.offset = e0;
        gen_codes(op_mov, BESZ_DWORD , makedreg(EAX), copy_addr(&vv));
        gen_code(op_add, sp, make_immed(12));

    }
    else
        call_library("__ftol");
}

//-------------------------------------------------------------------------

AMODE *complexstore(ENODE *node, AMODE *apr, int novalue, int size)
{
    AMODE *ap2 ;
    int offs = 0, siz = BESZ_BYTE;
    if (apr->mode == am_frfr)
    {
        DIAG("complexstore: double fregs");
        return apr ;
    }
    ap2 = copy_addr(apr);
    switch(apr->length)
    {
        case BESZ_CFLOAT:
            offs = 4;
            siz = BESZ_FLOAT;
            break;
        case BESZ_CDOUBLE:
            offs = 8;
            siz = BESZ_DOUBLE;
            break;
        case BESZ_CLDOUBLE:
            offs = 10;
            siz = BESZ_LDOUBLE;
            break;
    }
    ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,offs));
	if (novalue)
	{
	    gen_codefs(op_fstp,siz,apr,0);
    	gen_codefs(op_fstp,siz,ap2,0);
	}
	else if (siz == BESZ_LDOUBLE)
	{
		gen_codefs(op_fld, siz, makefreg(0), 0);
	    gen_codefs(op_fstp,siz,apr,0);
		gen_codefs(op_fxch, siz, makefreg(1), 0);
		gen_codefs(op_fld, siz, makefreg(0), 0);
    	gen_codefs(op_fstp,siz,ap2,0);
		gen_codefs(op_fxch, siz, makefreg(1), 0);
	}
	else
	{
	    gen_codefs(op_fst,siz,apr,0);
		gen_codefs(op_fxch, siz, makefreg(1), 0);
    	gen_codefs(op_fst,siz,ap2,0);
		gen_codefs(op_fxch, siz, makefreg(1), 0);
	}
    freeop(apr);
    apr->mode = am_frfr;
    apr->length = BESZ_CLDOUBLE;
    return apr;
}
//-------------------------------------------------------------------------

AMODE *floatstore(ENODE *node, AMODE *apr, int novalue, int size)
{
    if (isbit(node))
    {
        AMODE *ap1 = fstack();
        do_extend(ap1, BESZ_DWORD , F_DREG | F_VOL);
        bit_store(apr, ap1, node, novalue);
        return ap1;
    }
    else if (size <= BESZ_DWORD )
    {
        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 <= BESZ_QWORD)
    {
        gen_codef(op_fistp, apr, 0);
        if (novalue)
            freeop(apr);
        return apr;
    }
    else
    {
        if (novalue || apr->length == BESZ_LDOUBLE)
        {
			if (!novalue)
				gen_codef(op_fld, makefreg(0), 0);
            gen_codef(op_fstp, apr, 0);
            return apr;
        }
        else
        {
            gen_codef(op_fst, apr, 0);
            return makefreg(0);
        }
    }
}

//-------------------------------------------------------------------------

void complexload(AMODE *ap, int flag)
{
    AMODE *ap2 ;
    int offs = 0, siz = BESZ_BYTE;
    if (ap->mode == am_frfr)
        return;
    if (ap->mode == am_fconst)
    {
        AMODE *ap1;
        int siz1 = ap->length -13;
        int o = prm_optmult ;
        prm_optmult = FALSE;
        if (siz1>BESZ_DOUBLE)
            siz1++;
        ap1 = make_label(queue_floatval(&ap->offset->v.c.r, siz1));
        queue_floatval(&ap->offset->v.c.i, siz1);
        ap->mode = am_direct;
        ap->offset = ap1->offset;
        prm_optmult = o ;
    }
    ap2 = copy_addr(ap);
    switch(ap->length)
    {
        case BESZ_CFLOAT:
            offs = 4;
            siz = BESZ_FLOAT;
            break;
        case BESZ_CDOUBLE:
            offs = 8;
            siz = BESZ_DOUBLE;
            break;
        case BESZ_CLDOUBLE:
            offs = 10;
            siz = BESZ_LDOUBLE;
            break;
    }
    ap2->offset = makenode(en_add,ap2->offset,makeintnode(en_icon,offs));
    gen_codefs(op_fld,siz,ap2,0);
    gen_codefs(op_fld,siz,ap,0);
    freeop(ap);
    ap->mode = am_frfr;
    ap->length = BESZ_CLDOUBLE;
}
//-------------------------------------------------------------------------

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, BESZ_DWORD , 0);
            gen_codes(op_mov, BESZ_DWORD , ap1, ap);
            gen_codefs(op_fild, BESZ_DWORD, 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, BESZ_DWORD , 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, BESZ_DWORD , 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, BESZ_DWORD , 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, BESZ_DWORD , 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);
        ap2->seg = ap->seg;
        ap->seg = 0;
		if (ap->mode == am_indispscale)
		{
			if (ap->preg != ECX)
				freedata(ap->preg);
			if (ap->sreg != ECX)
				freedata(ap->sreg);
		}
		else
	        freeop(ap);
        *ap =  *ap2;
        ap->mode = am_indisp;
        ap->offset = makeintnode(en_icon, 0);
        ap->length = BESZ_QWORD;
    }
    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;
        ap2->seg = ap->seg;
        ap->seg = 0;
        freeop(ap);
        *ap =  *ap2;
    }
    return ap;
}

//-------------------------------------------------------------------------

void loadaxdx(AMODE *ap)
{
    if (ap->mode == am_immed)
    {
        tempaxdx();
        gen_codes(op_mov, BESZ_DWORD , makedreg(EAX), make_immed(ap->offset->v.i
            &0xffffffff));
        #if sizeof(ULLONG_TYPE) == 4
            gen_codes(op_mov, BESZ_DWORD , makedreg(EDX), make_immed(ap->offset->v.i < 0 
                ?  - 1: 0));
        #else 
            gen_codes(op_mov, BESZ_DWORD , makedreg(EDX), make_immed(ap->offset->v.i >>
                32));
        #endif 
    }
    else
    {
        AMODE *ap3 = aprtocx(ap);
        tempaxdx();
        gen_codes(op_mov, BESZ_DWORD , makedreg(EAX), ap3);
        ap3->offset = makenode(en_add, ap3->offset, makeintnode(en_icon, 4));
        gen_codes(op_mov, BESZ_DWORD , makedreg(EDX), ap3);
        freeop(ap3);
    }
    ap->mode = am_axdx;
    ap->length = BESZ_QWORD;
}

//-------------------------------------------------------------------------

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,  *ap3;

    int isize = ap->length;
    if (isize ==  - BESZ_BOOL)
        isize = BESZ_BOOL;
    if (osize ==  - BESZ_BOOL)
        osize = BESZ_BOOL;
    if (isize && isize != osize && isize !=  - osize && ap->mode != am_immed || osize == BESZ_CLDOUBLE && isize == BESZ_CLDOUBLE)
    {
        if (ap->mode == am_dreg && ap->preg > 3 && (osize == BESZ_BYTE || osize ==  - BESZ_BYTE)
            )
            flags |= F_VOL;
        if (ap->mode == am_dreg && (!(flags &F_VOL) || ap->tempflag) && ((osize
            != BESZ_BYTE && osize !=  - BESZ_BYTE) || ap->preg < 4))
            ap2 = ap;
        else
        {
            if (!(flags &F_NOREUSE))
                freeop(ap);
            ap2 = temp_data();
        }
        if (chksize(isize, osize))
        {
            /* moving to a lower type */
            if (isize > BESZ_QWORD)
            {
                if (isize >= BESZ_CFLOAT) 
                {
                    complexload(ap,TRUE) ;
                    if (osize < BESZ_CFLOAT)
                        if (osize >= BESZ_IFLOAT)
                        {
                            gen_codefs(op_fstp,BESZ_LDOUBLE,floatconvpos(),0);
                            ap->mode = am_freg;
                            ap->length = osize;
                            freeop(ap2);
                        }
                        else
                        {
                            gen_codef(op_fxch,0,0);
                            gen_codefs(op_fstp,BESZ_LDOUBLE,floatconvpos(),0);
                            ap->length = osize;
                            ap->mode = am_freg;
                            freeop(ap2);
                            goto join1 ;
                        }
                }
                else if (isize >= BESZ_IFLOAT)
                {
                    if (osize < BESZ_IFLOAT)
                    {
                        if (ap->mode == am_freg)
                            gen_codefs(op_fstp,BESZ_LDOUBLE,floatconvpos(),0);
                        gen_codef(op_fldz,0,0);
                        freeop(ap2);
                        ap->mode = am_freg;
                        ap->length = osize;
                        goto join1;
                    } 
                    else
                    {
                        if (ap->mode != am_freg) {
                            floatload(ap, TRUE);
                            ap->length = osize;
                            freeop(ap2);
                        }
                    }
                }
                else 
                {
                    if (ap->mode != am_freg)
                        floatload(ap, TRUE);
join1:
                    if (osize == BESZ_QWORD || osize ==  - BESZ_QWORD || osize == BESZ_BOOL)
                    {
                        freeop(ap2);
                        ap2 = floatconvpos();
    
                        memcpy(ap, ap2, sizeof(*ap));
                        gen_codes(op_fistp, BESZ_DOUBLE, ap, 0);
                        ap->length = BESZ_QWORD;
                    }
                    else if (osize < BESZ_QWORD)
                    {
                        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, BESZ_DWORD , ap2, makedreg(EAX));
                        if (pushed)
                            gen_pop(EAX, am_dreg, 0);
                        ap->mode = ap2->mode;
                        ap->preg = ap2->preg;
                        ap->tempflag = ap2->tempflag;
                        ap->seg = 0;
                        ap->length = osize;
                    }
                    else
                    {
                        freeop(ap2);
                        ap->mode = am_freg;
                        ap->preg = 0;
                        ap->tempflag = TRUE;
                        ap->seg = 0;
                    }
                }
            }
            else
            {
                int seg = 0;
                if (osize !=  BESZ_FARPTR && isize ==  BESZ_FARPTR)
                {
                    isize = BESZ_DWORD ;
                    ap->length = 0;
                    seg = temp_seg();
                }
                if (osize ==  BESZ_FARPTR)
                {
                    seg = temp_seg();
                    if (ap->mode == am_immed)
                    {
                        #if sizeof(ULLONG_TYPE) == 4
                            gen_code(op_mov, ap2, make_immed(0));
                        #else 
                            gen_code(op_mov, ap2, make_immed(ap->offset->v.i >>
                                32));
                        #endif 
                        ap3 = xalloc(sizeof(AMODE));
                        ap3->mode = am_seg;
                        ap3->seg = seg;
                        gen_code2(op_mov, BESZ_WORD, BESZ_DWORD , ap3, ap2);
                        gen_code(op_mov, ap2, make_immed(ap->offset->v.i
                            &0xffffffff));
                    }
                    else
                    {
                        ap2->length = BESZ_DWORD ;
                        ap->length = 0;
                        gen_code(ldx[seg], ap2, ap);
                        ap->length = BESZ_DWORD ;
                    }

                    ap->mode = ap2->mode;
                    ap->preg = ap2->preg;
                    ap->seg = seg;
                    ap->tempflag = ap2->tempflag;
                }
                else if (ap->mode != am_dreg || ap->preg != ap2->preg)
                {
                    if (isize == BESZ_QWORD || isize ==  - BESZ_QWORD)
                    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
                    {
                        if (seg == 0)
                            ap2->length = ap->length = BESZ_DWORD ;
                        else
                        {
                            ap2->length = BESZ_DWORD ;
                            ap->length = 0;
                        }
                        gen_code(ldx[seg], ap2, ap);
                        ap->length = BESZ_DWORD ;
                    }
                    else
                    {
                        if (seg == 0)
                            ap2->length = ap->length = isize;
                        else
                        {
                            ap2->length = BESZ_DWORD ;
                            ap->length = 0;
                        }
                        gen_code(ldx[seg], ap2, ap);
                        if (seg)
                            ap->length = BESZ_DWORD ;
                    }

                    ap->mode = ap2->mode;
                    ap->preg = ap2->preg;
                    ap->seg = seg;
                    ap->tempflag = ap2->tempflag;
                }
            }
        }
        else
        {
            /* moving up in type */
            if (isize > BESZ_QWORD)
            {
                if (isize >= BESZ_CFLOAT) {
                    complexload(ap,TRUE);
                    freeop(ap2);
                } else if (isize >=BESZ_IFLOAT)
                    if (osize >= BESZ_CFLOAT)
                    {
                        freeop(ap2);
                        if (ap->mode != am_freg)
                            floatload(ap, TRUE);
                        gen_codef(op_fldz,0,0);
                        ap->mode = am_frfr;
                        ap->length = BESZ_CLDOUBLE;
                    }
                    else if (osize < BESZ_IFLOAT)
                    {
                        if (ap->mode == am_freg)
                            gen_codefs(op_fstp,BESZ_LDOUBLE,floatconvpos(),0);
                        freeop(ap2);
                        gen_codef(op_fldz,0,0) ;
                        ap->mode = am_freg;
                        ap->length = BESZ_LDOUBLE;
                    }
                    else 
                    {
                        if (ap->mode != am_freg) 
                        {
                            floatload(ap, TRUE);
                            ap->length = osize;
                            freeop(ap2);
                        }
                    }
                else if (osize >= BESZ_CFLOAT)
                {
                    freeop(ap2);
                    gen_codef(op_fldz,0,0);
                    if (ap->mode != am_freg)
                        floatload(ap, TRUE);
                    else
                        gen_codef(op_fxch,0,0);
                    ap->mode = am_frfr;
                    ap->length = BESZ_CLDOUBLE;
                }
                else if (osize >= BESZ_IFLOAT)
                {
                    freeop(ap2);
                    if (ap->mode == am_freg)
                            gen_codefs(op_fstp,BESZ_LDOUBLE,floatconvpos(),0);
                    gen_codef(op_fldz,0,0);
                    ap->mode = am_freg;
                    ap->length = osize;
                }
                else
                {
                    if (ap->mode != am_freg)
                        floatload(ap, TRUE);
                    freeop(ap2);
                    ap->mode = am_freg;
                    ap->length = osize;
                }
            }
            else if (isize == BESZ_QWORD || isize ==  - BESZ_QWORD)
            {
                if (ap->mode == am_axdx)
                {
                    freeop(ap2);
                    ap1 = floatconvpos();
                    gen_codes(op_mov, BESZ_DWORD , ap1, makedreg(EAX));
                    ap1->offset = makenode(en_add, ap1->offset, makeintnode
                        (en_icon, 4));
                    gen_codes(op_mov, BESZ_DWORD , ap1, makedreg(EDX));
					ap1->offset = ap1->offset->v.p[0];
                }
                else
                    ap1 = ap;
                if (osize >= BESZ_CFLOAT) 
                {
                    gen_codef(op_fldz,0,0);
                    gen_codes(op_fild, BESZ_DOUBLE, ap1, 0);
                    freeop(ap2);
                    ap->mode = am_frfr;
                    ap->length = BESZ_CLDOUBLE;
                }
                else if (osize >= BESZ_IFLOAT)
                {
                    gen_codes(op_fild, BESZ_DOUBLE, ap1, 0);
                    freeop(ap2);
                    gen_codef(op_fldz,0,0);
                    ap->mode = am_freg;
                    ap->length = osize;
                } 
                else 
                {
                    gen_codes(op_fild, BESZ_DOUBLE, ap1, 0);
                    freeop(ap2);
                    ap->mode = am_freg;
                    ap->length = osize;
                }
            }
            else if (isize ==  BESZ_FARPTR)
            {
                freeop(ap2);
                if (ap->mode == am_dreg)
                {
                    if (ap->preg != EAX)
                        gen_codes(op_mov, BESZ_DWORD , makedreg(EAX), ap);
                    ap3 = xalloc(sizeof(AMODE));
                    ap3->mode = am_seg;
                    ap3->seg = ap->seg;
                    gen_codes(op_mov, BESZ_DWORD , makedreg(EDX), ap3);
                }
                else if (ap->mode == am_immed)
                {
                    #if sizeof(ULLONG_TYPE) == 4
                        gen_codes(op_mov, BESZ_DWORD , makedreg(EDX), make_immed(0));
                    #else 
                        gen_codes(op_mov, BESZ_DWORD , makedreg(EDX), make_immed((ap
                            ->offset->v.i >> 32) &0xffff));
                    #endif 
                    gen_codes(op_mov, BESZ_DWORD , makedreg(EAX), make_immed(ap->offset
                        ->v.i &0xffffffff));
                }
                else
                {
                    ap3 = copy_addr(ap);
                    ap3->offset = makenode(en_add, ap3->offset, makeintnode
                        (en_icon, 4));
                    gen_code2(op_movzx, BESZ_DWORD , BESZ_WORD, makedreg(EDX), ap3);
                    gen_codes(op_mov, BESZ_DWORD , makedreg(EAX), ap);
                }
                ap->seg = 0;
                ap->mode = am_axdx;
            }
            else if (osize > BESZ_QWORD)
            {
                if (osize >= BESZ_IFLOAT && osize < BESZ_CFLOAT) 
                {
                    freeop(ap2);
                    gen_codef(op_fldz,0,0);
                    ap->mode = am_freg;
                    ap->length = osize;
                }
                else
                {
                    if (isize != BESZ_DWORD  && isize !=  - BESZ_DWORD )
                    {
                        ap1 = floatconvpos();
                        if (ap->mode == am_seg || ap2->mode == am_seg)
                            gen_codes(op_mov, BESZ_DWORD , ap2, ap);
                        else if (isize < 0)
                            gen_code2(op_movsx, BESZ_DWORD , isize, ap2, ap);
                        else
                            gen_code2(op_movzx, BESZ_DWORD , BESZ_DWORD , ap2, ap);
                        gen_codes(op_mov, BESZ_DWORD , ap1, ap2);
                        gen_codefs(op_fild, BESZ_DWORD, ap1, 0);
                    }
                    else
                        if (ap->mode == am_direct || ap->mode == am_indisp || ap
                            ->mode == am_indispscale)
                            gen_codefs(op_fild, BESZ_DWORD , ap, 0);
                        else
                    {
                        ap1 = floatconvpos();
                        gen_codes(op_mov, BESZ_DWORD , ap1, ap);
                        gen_codefs(op_fild, BESZ_DWORD , ap1, 0);
                    }
                    if (osize >= BESZ_CFLOAT)
                    {
                        freeop(ap2);
                        gen_codef(op_fldz,0,0);
                        gen_codef(op_fxch,0,0);
                        ap->mode = am_frfr;
                        ap->length = BESZ_CLDOUBLE;
                    }
                    else
                    {
                        freeop(ap2);
                        ap->mode = am_freg;
                        ap->length = osize;
                    }
                }
            }
            else
            {
                int size6 = osize == BESZ_QWORD || osize ==  - BESZ_QWORD;
                if (osize == BESZ_QWORD || osize ==  - BESZ_QWORD)
                    osize = BESZ_DWORD ;
                if (ap->mode == am_dreg && ap->preg > 3 && (isize == BESZ_BYTE || isize
                    ==  - BESZ_BYTE))
                    gen_codes(op_mov, BESZ_DWORD , ap2, ap);
                if (size6 && (isize == BESZ_DWORD  || isize ==  - BESZ_DWORD ))
                    gen_codes(op_mov, isize, ap2, ap);
                else if (ap->mode == am_seg)
                {
                    gen_codes(op_mov, BESZ_DWORD , ap2, ap);
                }
                else if ((isize ==  - BESZ_DWORD  || isize == BESZ_DWORD ) && osize ==  BESZ_FARPTR)
                {
                    gen_codes(op_mov, BESZ_DWORD , ap2, ap);
                    ; // nothing here
                }
                else
                {
                    if (osize ==  BESZ_FARPTR)
                        osize = BESZ_DWORD ;
                    if (ap->mode == am_seg || ap2->mode == am_seg)
                        gen_codes(op_mov, BESZ_DWORD , 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, BESZ_DWORD , makedreg(EAX), ap2);
                    if (isize < 0)
                        gen_code(op_cdq, 0, 0);
                    else
                        gen_codes(op_sub, BESZ_DWORD , makedreg(EDX), makedreg(EDX));
                    ap->mode = am_axdx;
                    ap->length = BESZ_QWORD;
                    ap->seg = 0;
                    osize = BESZ_QWORD;
                }
                else
                {
                    ap->seg = 0;
                    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 < BESZ_FLOAT)
                {
                    int seg = 0;
					ap2 = reuseop(ap);
                    ap2->length = osize;
                    if (isize ==  BESZ_FARPTR)
                    {
                        seg = temp_seg();
                        ap2->length = BESZ_DWORD ;
                        ap->length = 0;
                        gen_code(ldx[seg], ap2, ap);
                        osize =  BESZ_FARPTR;
                    }
                    else
                    {
                        gen_code(op_mov, ap2, ap);
						seg = ap->seg;
                    }
                    ap->mode = ap2->mode;
                    ap->preg = ap2->preg;
                    ap->seg = seg;
                    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 == BESZ_BOOL)
    {
        int lab = nextlabel++;
        if (isize != BESZ_QWORD && isize !=  - BESZ_QWORD)
        {
            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, BESZ_DWORD , makedreg(EAX), makedreg(EDX));
            freeop(ap);
            ap2 = temp_data();
        }
        ap2->length = BESZ_BYTE;
        gen_code(op_setne, ap2, 0);
        freeop(ap);
        ap->mode = ap2->mode;
        ap->tempflag = ap2->tempflag;
        ap->length = ap2->length;
        ap->preg = ap2->preg;
        ap->seg = 0;
    }
    if (ap->mode == am_screg || ap->mode == am_sdreg || ap->mode == am_streg ||
        ap->mode == am_seg)
    {
        ap2 = temp_data();
        gen_codes(op_mov, BESZ_DWORD , ap2, ap);
        ap->mode = ap2->mode;
        ap->tempflag = ap2->tempflag;
        ap->length = ap2->length;
        ap->preg = ap2->preg;
        ap->seg = 0;
    }
    ap->length = osize;
    if (osize == BESZ_BOOL)
        ap->length = BESZ_BOOL;
}

//-------------------------------------------------------------------------

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_structret:
            return 0;
        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_ci:
		case en_cui:
        case en_cp:
        case en_cfp:
        case en_csp:
        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_a_ref:
		case en_ua_ref:
		case en_i_ref:
		case en_ui_ref:
        case en_ub_ref:
        case en_bool_ref:
        case en_b_ref:
        case en_fp_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:
        case en_substack:
		case en_loadstack:
		case en_savestack:
            return 1+depth(node->v.p[0]);
        case en_uminus:
        case en_moveblock:
        case en_stackblock:
        case en_clearblock:
            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_boolcon:
        case en_ccon:
        case en_cucon:
        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_arrayindex:
        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:
        case en_ainc:
        case en_adec:
		case en_array:
            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:
        case en_dvoid:
            return 1+depth(node->v.p[1]);
        case en_conslabel:
        case en_destlabel:
        case en_movebyref:
        case en_addcast:
            return depth(node->v.p[0]);
        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 == BESZ_QWORD || ap->length ==  - BESZ_QWORD)
            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");
		ap3 = reuseop(ap);
    }
    else
    {
        if (ap->preg ==  - 1)
        {
            if (ap->sreg >= 3)
            {
				ap3 = reuseop(ap);
            }
            else
            {
                ap3 = xalloc(sizeof(AMODE));
                ap3->mode = am_dreg;
                ap3->preg = ap->sreg;
            }
        }
        else
        {
            if (ap->preg >= 3)
            {
                if (ap->sreg >= 3)
                {
					ap3 = reuseop(ap);
                }
                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 = BESZ_DWORD ;
    gen_codes(op_lea, BESZ_DWORD , ap3, ap);
    ap3->seg = ap->seg;
	if (ap4.mode != am_none)
	    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, BESZ_DWORD );
            break;
        case en_lsh:
            if ((scale = node->v.p[1]->v.i) < 4 && scale)
            {
                ap = gen_expr(node->v.p[0], FALSE, TRUE, BESZ_DWORD );
                if (node->v.p[0]->nodetype == en_bits)
                    ap = bit_load(ap, node->v.p[0]);
                if (ap->mode != am_immed)
                    do_extend(ap, BESZ_DWORD , F_DREG);
                if (ap->mode == am_immed)
                {
                    while (--scale)
                        ap->offset->v.i <<= 1;
                }
                else
                {
                    do_extend(ap, BESZ_DWORD , 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, BESZ_DWORD );
            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 == BESZ_QWORD || nsize ==  - BESZ_QWORD)
            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 == BESZ_QWORD || nsize ==  - BESZ_QWORD)
            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, BESZ_DWORD , 0);
                ap1->sreg = ap2->preg;
                ap1->scale = 0;
                ap1->mode = am_indispscale;
                ap1->offset = makeintnode(en_icon, 0);
                if (!ap1->seg)
                    ap1->seg = ap2->seg;
                return ap1;
            case am_immed:
            case am_direct:
                ap2->preg = ap1->preg;
                ap2->mode = am_indisp;
                if (!ap2->seg)
                    ap2->seg = ap1->seg;
                return ap2;
            case am_indisp:
                ap2->sreg = ap2->preg;
                ap2->preg = ap1->preg;
                ap2->mode = am_indispscale;
                ap2->offset = ap1->offset;
                ap2->scale = 0;
                if (!ap2->seg)
                    ap2->seg = ap1->seg;
                return ap2;
            case am_indispscale:
                if (ap2->preg ==  - 1)
                {
                    ap2->preg = ap1->preg;
                    if (!ap2->seg)
                        ap2->seg = ap1->seg;
                    return ap2;
                }
                ap = indx_data(ap2);
                ap->sreg = ap1->preg;
                ap->mode = am_indispscale;
                ap->scale = 0;
                ap->offset = makeintnode(en_icon, 0);
                ap->seg = ap2->seg;

                if (!ap->seg)
                    ap->seg = ap1->seg;
                return ap;
            }
            break;
        case am_direct:
        case am_immed:
            switch (ap2->mode)
            {
            case am_dreg:
                ap2->mode = am_indisp;
                ap2->offset = ap1->offset;
                if (!ap2->seg)
                    ap2->seg = ap1->seg;
                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;
                if (!ap1->seg)
                    ap1->seg = ap2->seg;
                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);
                if (!ap2->seg)
                    ap2->seg = ap1->seg;
                return ap2;
            }
            break;
        case am_indisp:
            switch (ap2->mode)
            {
            case am_dreg:
                ap1->mode = am_indispscale;
                ap1->sreg = ap2->preg;
                ap1->scale = 0;
                if (!ap1->seg)
                    ap1->seg = ap2->seg;
                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);
                }
                if (!ap1->seg)
                    ap1->seg = ap2->seg;
                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);
                if (!ap1->seg)
                    ap1->seg = ap2->seg;
                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)
                            ;
                    if (!ap2->seg)
                        ap2->seg = ap1->seg;
                    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);
                if (!ap1->seg)
                    ap1->seg = ap2->seg;
                return ap1;
            }
            break;
        case am_indispscale:
            switch (ap2->mode)
            {
            case am_dreg:
                if (ap1->preg ==  - 1)
                {
                    ap1->preg = ap2->preg;
                    if (!ap1->seg)
                        ap1->seg = ap2->seg;
                    return ap1;
                }
                ap = indx_data(ap1);
                ap->sreg = ap2->preg;
                ap->scale = 0;
                ap->offset = ap1->offset;
                ap->seg = ap1->seg;
                if (!ap->seg)
                    ap->seg = ap2->seg;
                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);
                if (!ap1->seg)
                    ap1->seg = ap2->seg;
                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)
                            ;
                    if (!ap1->seg)
                        ap1->seg = ap2->seg;
                    return ap1;
                }
                ap = indx_data(ap1);
                ap->sreg = ap2->preg;
                ap->scale = 0;
                ap->mode = am_indispscale;
                ap->seg = ap2->seg;
                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);
                if (!ap->seg)
                    ap->seg = ap2->seg;
                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);
                        if (!ap2->seg)
                            ap2->seg = ap1->seg;
                        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);
                        if (!ap1->seg)
                            ap1->seg = ap2->seg;
                        return ap1;
                    }
                }
                if (ap1->preg ==  - 1)
                {
                    ap = indx_data(ap2);
                    ap1->preg = ap->preg;
                    if (!ap1->seg)
                        ap1->seg = ap2->seg;
                    return ap1;
                }
                else if (ap2->preg ==  - 1)
                {
                    ap = indx_data(ap1);
                    ap2->preg = ap->preg;
                    if (!ap2->seg)
                        ap2->seg = ap1->seg;
                    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);
                ap->seg = ap1->seg;
                if (!ap->seg)
                    ap->seg = ap2->seg;

                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_substack:
        case en_structret:
		case en_loadstack:
		case en_savestack:
            siz1 = BESZ_DWORD ;
            break;
        case en_fp_ref:
            siz1 =  BESZ_FARPTR;
            break;
        case en_ub_ref:
            siz1 = BESZ_BYTE;
            break;
        case en_b_ref:
            siz1 =  - 1;
            break;
        case en_bool_ref:
            siz1 = BESZ_BOOL;
            break;
        case en_uw_ref:
            siz1 = BESZ_WORD;
            break;
        case en_w_ref:
            siz1 =  - BESZ_WORD;
            break;
        case en_l_ref:
		case en_i_ref:
		case en_a_ref:
            siz1 =  - BESZ_DWORD;
            break;

        case en_ul_ref:
		case en_ui_ref:
		case en_ua_ref:
            siz1 = BESZ_DWORD;
            break;
        case en_ull_ref:
            siz1 = BESZ_QWORD;
            break;
        case en_ll_ref:
            siz1 =  - BESZ_QWORD;
            break;
        case en_floatref:
            siz1 = BESZ_FLOAT;
            break;
        case en_doubleref:
            siz1 = BESZ_DOUBLE;
            break;
        case en_longdoubleref:
            siz1 = BESZ_LDOUBLE;
            break;
        case en_fimaginaryref:
            siz1 = BESZ_IFLOAT;
            break;
        case en_rimaginaryref:
            siz1 = BESZ_IDOUBLE;
            break;
        case en_lrimaginaryref:
            siz1 = BESZ_ILDOUBLE;
            break;
        case en_fcomplexref:
            siz1 = BESZ_CFLOAT;
            break;
        case en_rcomplexref:
            siz1 = BESZ_CDOUBLE;
            break;
        case en_lrcomplexref:
            siz1 = BESZ_CLDOUBLE;
            break;
        default:
            siz1 = BESZ_DWORD ;
    }
    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;
        //                if (prm_farkeyword)
            //								if ((currentfunc->value.classdata.cppflags & PF_MEMBER) &&
            //											!(currentfunc->value.classdata.cppflags & PF_STATIC) && i > 0)
            //									i += 4;
        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 = 0;
        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, BESZ_DWORD ); /* generate address */
    if (prm_farkeyword && ap1->mode == am_axdx)
    {
        AMODE *ap2 = makedreg(0);
        ap2->seg = temp_seg();
        ap2->mode = am_seg;
        gen_codes(op_mov, BESZ_WORD, ap2, makedreg(EDX));
		freeop(ap1);
		regs[0]++;
        ap1->mode = am_dreg;
        ap1->seg = ap2->seg;
    }
    else if (ap1->mode != am_immed)
    {
        do_extend(ap1, BESZ_DWORD , F_DREG);
    }
    ap1->length = siz1;
    if (ap1->mode == am_dreg)
    {
        ap1->mode = am_indisp;
        ap1->offset = makeintnode(en_icon, 0);
        //                ap1->seg = defseg(node->v.p[0]) ;
        return ap1;
    }
    else if (ap1->mode == am_stackedtemp)
    {
        ap1->mode = am_stackedtempaddr;
        if (prm_farkeyword)
            ap1->seg = SS;
        return ap1;
    }
    ap1->mode = am_direct;
    return ap1;
}

//-------------------------------------------------------------------------

void get_size(AMODE *ap1, AMODE *ap2, int size, int flags)
{
    if (size > BESZ_QWORD)
        size = BESZ_DWORD ;
    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 !=  BESZ_FARPTR)
        size =  - size;
    if (size)
    {
        if (ap1->mode == am_immed && (ap1->length <= BESZ_DWORD  || ap1->length == BESZ_QWORD))
            ap1->length = size;
        else
            do_extend(ap1, size, flags);
        if (ap2->mode == am_immed && (ap2->length <= BESZ_DWORD  || ap2->length == BESZ_QWORD))
            ap2->length = size;
        else
            do_extend(ap2, size, flags);
    }

}

//-------------------------------------------------------------------------

void small_size(AMODE *ap1, AMODE *ap2, int size, int flags)
{
    if (ap1->length <= BESZ_QWORD && ap2->length <= BESZ_QWORD && chksize(ap2->length, ap1
        ->length))
    {
        if ((ap2->mode != am_dreg || ap2->preg < BESZ_DWORD ) && (ap2->length != BESZ_QWORD && ap2
            ->length !=  - BESZ_QWORD))
            ap2->length = ap1->length;
        else
            do_extend(ap2, ap1->length, flags);
    }
    else
        get_size(ap1, ap2, size, flags);
}

//-------------------------------------------------------------------------

int resultsize(int n1, int n2)
{
    if (n1 < 0)
        n1 =  - n1;
    if (n2 < 0)
        n1 =  - n1;
    return n1;
}

//-------------------------------------------------------------------------

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 < BESZ_QWORD && size !=  - BESZ_QWORD)
            rsize = size;
        else if (rsize < BESZ_QWORD && rsize !=  - BESZ_QWORD)
            rsize = BESZ_DWORD  * neg;
        else if (rsize != BESZ_QWORD && rsize !=  - BESZ_QWORD)
            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, 0);
}

//-------------------------------------------------------------------------

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);
    if ((*ap2)->seg)
        do_extend(*ap2, (*ap2)->length, 0);
    *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, 0);
    }
    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, 0);
    }
    *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 > BESZ_QWORD)
    {
        if (size >= BESZ_CFLOAT)
        {
            do_extend(ap, BESZ_CLDOUBLE, 0);
            gen_code(fop, 0, 0);
            gen_code(op_fxch, 0, 0);
            gen_code(fop, 0, 0);
            gen_code(op_fxch, 0, 0);
            ap = fstack();
            ap->mode = am_frfr;
            ap->length = BESZ_CLDOUBLE;
        }
        else if (size >= BESZ_IFLOAT)
        {
            do_extend(ap, BESZ_ILDOUBLE, F_FREG | F_VOL);
            gen_code(fop, 0, 0);
            ap = fstack();
            ap->length = BESZ_ILDOUBLE;
        }
        else 
        {
            do_extend(ap, BESZ_LDOUBLE, F_FREG | F_VOL);
            gen_code(fop, 0, 0);
            ap = fstack();
            ap->length = BESZ_LDOUBLE;
        }
    }
    else
    {
        if (size == 0)
            size = natural_size(node->v.p[0]);
        if (size == BESZ_QWORD || size ==  - BESZ_QWORD)
        {
            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_complexadd(ENODE *node, int fop, int fopp, int fopr, int foppr, int size, AMODE **apr)
{
        AMODE *ap1, *ap2;
        ap1 = gen_expr(node->v.p[0], FALSE, FALSE, natural_size(node->v.p[0]));
        ap2 = gen_expr(node->v.p[1], FALSE, FALSE, natural_size(node->v.p[1]));
        
        if (ap1->length < BESZ_CFLOAT && ap2->length < BESZ_CFLOAT)
        {
            int iap1 = ap1->mode == am_freg,iap2 = ap2->mode == am_freg ;
            if (!iap1 && !iap2) 
            {
                if (ap1->length < BESZ_IFLOAT) 
                {
                    do_extend(ap2,ap2->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE, F_FREG);
                    do_extend(ap1, ap1->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE,F_FREG);
                } 
                else
                {
                    do_extend(ap1, ap1->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE,F_FREG);
                    do_extend(ap2,ap2->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE, F_FREG);
                }
            } 
            else if (iap1 && !iap2)
            {
                do_extend(ap2,ap2->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE, F_FREG);
                if (ap1->length < BESZ_IFLOAT)
                    gen_codef(op_fxch,0,0);
            } 
            else if (iap2 && !iap1)
            {
                do_extend(ap1,ap1->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE, F_FREG);
                if (ap2->length < BESZ_IFLOAT)
                    gen_codef(op_fxch,0,0);
            } 
            else 
            {
                if (ap1->length < BESZ_IFLOAT)
                    gen_codef(op_fxch,0,0);
            }
            ap1 = fstack();
            ap1->mode = am_frfr;
            ap1->length = BESZ_CLDOUBLE;
            return ap1;
        } 
        else if (ap1->length < BESZ_CFLOAT && ap2->length >= BESZ_CFLOAT)
        {
            int iap1 = ap1->mode == am_freg,iap2 = ap2->mode == am_frfr ;
            if (!iap1 && !iap2) 
            {
                    do_extend(ap1, ap1->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE,F_FREG);
                    do_extend(ap2,BESZ_CLDOUBLE, 0);
                if (ap1->length >= BESZ_IFLOAT) 
                {
                    gen_codef(op_fxch,0,0);
                    gen_codef(fopp,makefreg(2),0);
                } 
                else 
                {
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(op_fxch,0,0);
                }
            } 
            else if (iap1 && !iap2)
            {
                do_extend(ap2,BESZ_CLDOUBLE,0);
                if (ap1->length >= BESZ_IFLOAT) 
                {
                    gen_codef(op_fxch,0,0);
                    gen_codef(fopp,makefreg(2),0);
                } 
                else 
                {
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(op_fxch,0,0);
                }
            } 
            else if (iap2 && !iap1)
            {
                do_extend(ap1,ap1->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE, F_FREG);
                gen_codef(op_fxch,makefreg(2),0);
                if (ap1->length >= BESZ_IFLOAT) 
                {
                    gen_codef(fopp,makefreg(2),0);
                } 
                else 
                {
                    gen_codef(op_fxch,0,0);
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(op_fxch,0,0);
                }
            } 
            else 
            {
                if (ap1->length >= BESZ_IFLOAT) 
                {
                    gen_codef(op_fxch,0,0);
                    gen_codef(fopp,makefreg(2),0);
                } 
                else 
                {
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(op_fxch,0,0);
                }
            }
            return ap2;
        } 
        else if (ap1->length >= BESZ_CFLOAT && ap2->length < BESZ_CFLOAT)
        {
            int iap1 = ap1->mode == am_frfr,iap2 = ap2->mode == am_freg ;
            if (!iap1 && !iap2) 
            {
                do_extend(ap1,BESZ_CLDOUBLE, 0);
                do_extend(ap2, ap2->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE,F_FREG);
                if (ap2->length >= BESZ_IFLOAT) 
                {
                    gen_codef(fopp,makefreg(2),0);
                } 
                else 
                {
                    gen_codef(fopp,makefreg(1),0);
                }
            } 
            else if (iap1 && !iap2)
            {
                do_extend(ap2, ap2->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE,F_FREG);
                if (ap2->length >= BESZ_IFLOAT) 
                {
                    gen_codef(fopp,makefreg(2),0);
                } 
                else 
                {
                    gen_codef(fopp,makefreg(1),0);
                }
            } 
            else if (iap2 && !iap1)
            {
                do_extend(ap1,BESZ_CLDOUBLE, 0);
                if (ap2->length >= BESZ_IFLOAT) 
                {
                    gen_codef(fop,makefreg(2),0);
                    gen_codef(op_fxch,makefreg(2),0);
                } 
                else 
                {
                    gen_codef(fop,makefreg(1),0);
                    gen_codef(op_fxch,makefreg(1),0);
                }
                gen_codefs(op_fstp,BESZ_FLOAT,floatconvpos(),0);
            } 
            else 
            {
                if (ap2->length >= BESZ_IFLOAT) 
                {
                    gen_codef(fopp,makefreg(2),0);
                } 
                else 
                {
                    gen_codef(fopp,makefreg(1),0);
                }
            }
            return ap1;
        } 
        else
        {
            do_extend(ap1, BESZ_CLDOUBLE, 0);
            do_extend(ap2, BESZ_CLDOUBLE, 0);
            gen_codef(fopp, makefreg(2),0);
            gen_codef(fopp, makefreg(2),0);
        }
        return ap1;
}
AMODE *gen_fbinary(ENODE *node, int fop, int fopp, int fopr, int foppr, int
    size, AMODE **apr)
{
    AMODE *ap1,  *ap2;
    int bits;
    int sz1 = natural_size(node->v.p[0]), sz2 = natural_size(node->v.p[1]) ;
    if (sz1 <= BESZ_LDOUBLE)
        sz1 = BESZ_LDOUBLE;
    else
        sz1 = BESZ_ILDOUBLE;
    if (sz2 <= BESZ_LDOUBLE)
        sz2 = BESZ_LDOUBLE;
    else
        sz2 = BESZ_ILDOUBLE;
    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, sz1, 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, sz1, F_FREG | F_VOL);
    if (ap1->mode == am_freg)
    {
        if (ap2->mode == am_freg)
        {
            gen_codef(fopp, makefreg(1), 0);
        }
        else if (ap2->length == BESZ_LDOUBLE)
        {
            do_extend(ap2, sz2, F_FREG);
            gen_codef(fopp, makefreg(1), 0);
        }
        else if (ap2->mode == am_dreg)
        {
            do_extend(ap2, sz2, F_FREG);
            gen_codef(fopp, makefreg(1), 0);
        }
        else if (ap2->length < BESZ_FLOAT)
        {
            do_extend(ap2, sz2, F_FREG);
            gen_codef(fopp, makefreg(1), 0);
        }
        else
            gen_code(fop, ap2, 0);
    }
    else if (ap2->mode == am_freg)
    {
        if (ap1->length == BESZ_LDOUBLE)
        {
            do_extend(ap1, sz1, F_FREG);
            gen_codef(foppr, makefreg(1), 0);
        }
        else if (ap1->mode == am_dreg)
        {
            do_extend(ap1, sz1, F_FREG);
            gen_codef(foppr, makefreg(1), 0);
        }
        else if (ap1->length < BESZ_FLOAT)
        {
            do_extend(ap1, sz1, 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 < BESZ_QWORD && size >  - BESZ_QWORD && ap1->length != BESZ_QWORD && ap1->length !=  - BESZ_QWORD)
        do_extend(ap1, size, F_DREG | F_VOL);
    else
        do_extend(ap1, BESZ_QWORD, 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 = BESZ_DWORD ;
        ap3 = ap2;
        ap4 = copy_addr(ap3);
        ap4->offset = makenode(en_add, ap4->offset, makeintnode(en_icon, 4));
    }
    if (size < BESZ_QWORD && size >  - BESZ_QWORD)
    {
        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 >= BESZ_QWORD || size ==  - BESZ_QWORD)
            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_segadd(ENODE *node)
{
    ENODE *seg,  *ofs;
    AMODE *ap1,  *ap2,  *ap3;
    if (node->v.p[0]->nodetype == en_csp)
    {
        seg = node->v.p[0];
        ofs = node->v.p[1];
    }
    else
    {
        seg = node->v.p[1];
        ofs = node->v.p[0];
    }
    ap2 = gen_expr(ofs, FALSE, FALSE, BESZ_DWORD );
    do_extend(ap2, BESZ_DWORD , F_DREG | F_VOL);
    ap1 = gen_expr(seg, FALSE, FALSE, BESZ_DWORD );
    if (ap1->mode == am_seg)
    {
        ap2->seg = ap1->seg;
        ap2->length =  BESZ_FARPTR;
    }
    else
    {
        if (ap1->mode == am_immed)
        {
            if (ap2->preg != EAX)
            {
                freeop(ap2);
                if (regs[0])
                {
                    gen_push(EAX, am_dreg, 0);
                    regs[0]++;
                }
                gen_codes(op_mov, BESZ_DWORD , makedreg(EAX), ap2);
            }
            ap3 = temp_data();
            if (ap3->preg != EDX)
            {
                AMODE *ap4 = temp_data();
                freeop(ap3);
                ap3 = ap4;
            }
            gen_code(op_mov, ap3, ap1);
        }
        else
        {
            do_extend(ap1, BESZ_DWORD , F_DREG | F_VOL);
            if (ap2->preg == EAX)
            {
                if (ap1->preg != EDX)
                {
                    ap3 = temp_data();
                    gen_codes(op_mov, BESZ_DWORD , ap3, ap1);
                    freeop(ap1);
                }
            }
            else
            {
                if (ap1->preg != EDX)
                {
                    if (ap1->preg == EAX && ap2->preg == EDX)
                        gen_codes(op_xchg, BESZ_DWORD , ap1, ap2);
                    else
                    {
                        ap3 = temp_data();
                        if (ap3->preg == EDX)
                        {
                            gen_codes(op_mov, BESZ_DWORD , ap3, ap1);
                            gen_codes(op_mov, BESZ_DWORD , ap1, ap2);
                            freeop(ap2);
                        }
                        else
                        {
                            gen_codes(op_mov, BESZ_DWORD , ap3, ap2);
                            gen_codes(op_mov, BESZ_DWORD , ap2, ap1);
                            freeop(ap1);
                        }
                    }
                }
            }
        }
        ap2->length =  - BESZ_QWORD;
        ap2->mode = am_axdx;
    }
    return ap2;
}

//-------------------------------------------------------------------------

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,  *ap4;
    int nsize = natural_size(node);
    if (prm_farkeyword && (op == op_add && (node->v.p[0]->nodetype == en_csp ||
        node->v.p[1]->nodetype == en_csp)))
    {
        return gen_segadd(node);
    }
    if (nsize == BESZ_QWORD || nsize ==  - BESZ_QWORD)
        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, BESZ_DWORD , 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, BESZ_DWORD , ap1, make_immed(vb));
                        return ap1;
                    }
                }
            }
        }
    }
    if (ap1->length ==  BESZ_FARPTR)
    {
        ap3 = copy_addr(ap1);
        ap3->length =  - BESZ_DWORD ;
    }
    else
        ap3 = ap1;
    if (ap2->length ==  BESZ_FARPTR)
    {
        ap4 = copy_addr(ap2);
        ap4->length =  - BESZ_DWORD ;
    }
    else
        ap4 = ap2;
    gen_code(op, ap3, ap4);
    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) > BESZ_QWORD) 
    {
        int n1 = natural_size(node->v.p[0]), n2 = natural_size(node->v.p[1]);
        if (n1 < BESZ_IFLOAT && n2 < BESZ_IFLOAT)
            return gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
        else if (n1 >= BESZ_IFLOAT && n1 < BESZ_CFLOAT && n2 >=BESZ_IFLOAT && n2 < BESZ_CFLOAT) 
        {
            AMODE *ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            ap1->length = BESZ_ILDOUBLE;
            return ap1;
        } else
            return gen_complexadd(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;
    if (div)
    {
        switch (size)
        {
            case BESZ_BYTE:
                case  - 1: gen_code(op_test, ap1, make_immed(0x80));
                gen_code(op_je, make_label(nextlabel), 0);
            case BESZ_WORD:
                case  - 2: gen_code(op_test, ap1, make_immed(0x8000));
                gen_code(op_je, make_label(nextlabel), 0);
                break;
            case BESZ_DWORD :
            case  - BESZ_DWORD : 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, BESZ_DWORD , 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, BESZ_DWORD , ap2, ecx);
            }
            else
            {
                gen_codes(op_mov, BESZ_DWORD , ecx, ap2);
                if (equal_address(ap1, ap2))
                    gen_codes(op, 1, ecx, ecx);
                else
                    gen_code2(op, BESZ_DWORD , 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;
	int regax, regdx, regcx;
    if (div)
    {
        // if we get in here ap2 is a const ...
	    ap2 = gen_expr(node->v.p[1], FALSE, FALSE, BESZ_DWORD );
        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 (isintconst(node->v.p[1]->nodetype))
    {
	    ap2 = gen_expr(node->v.p[1], FALSE, FALSE, BESZ_DWORD );
        if (size == BESZ_QWORD || size ==  - BESZ_QWORD || 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;
		tempaxdx();
	    regax = regs[EAX];
    	regdx = regs[EDX];
    	regcx = regs[ECX];
    	set_func_mode(1);
    	regs[0] = regs[1] = regs[2] = 0;
        if (regcx)
        {
            pushed = TRUE;
            gen_push(ECX, am_dreg, 0);
        }
	    ap2 = gen_expr(node->v.p[1], FALSE, FALSE, BESZ_DWORD );
        if (ap2->mode == am_axdx)
            gen_push(EAX, am_dreg, 0);
        else
        {
            gen_codes(op_push, BESZ_DWORD , 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 if (ap1->mode == am_immed)
        {
            #if sizeof(LLONG_TYPE) == 4
                gen_codes(op_push, BESZ_DWORD , make_immed(ap1->offset->v.i < 0 ?  - 1: 0)
                    , 0);
            #else 
                gen_codes(op_push, BESZ_DWORD , make_immed(ap1->offset->v.i >> 32), 0);
            #endif 
            gen_codes(op_push, BESZ_DWORD , make_immed(ap1->offset->v.i), 0);
        }
        else
        {
            ap2 = copy_addr(ap1);
            ap2->offset = makenode(en_add, ap2->offset, makeintnode(en_icon, 4))
                ;
            gen_codes(op_push, BESZ_DWORD , ap2, 0);
            gen_codes(op_push, BESZ_DWORD , ap1, 0);
        }
        freeop(ap1);
        if (op == op_shr)
            call_library("__LXSHR");
        else if (op == op_sar)
            call_library("__LXSAR");
        else
            call_library("__LXSHL");
	    regs[EAX] = regax;
    	regs[EDX] = regdx;
		regs[ECX] = regcx;
    	set_func_mode(0);
        if (pushed)
            gen_pop(ECX, am_dreg, 0);
    }
    ap1 = xalloc(sizeof(AMODE));
    ap1->mode = am_axdx;
    ap1->length = BESZ_QWORD;
    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 == BESZ_QWORD || size ==  - BESZ_QWORD)
        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 != BESZ_QWORD && size !=  - BESZ_QWORD)
        do_extend(ap1, BESZ_DWORD , F_DREG | F_VOL);
    if (ap2->length <= BESZ_QWORD)
        ap2->length = BESZ_DWORD ;
    else
        do_extend(ap2, BESZ_DWORD , 0);
    doshift(ap1, ap2, op, div, size);
    return ap1;
}

//-------------------------------------------------------------------------

AMODE *gen_complexdiv(ENODE *node, int fop, int fopp, int fopr, int foppr, int size, AMODE **apr)
{
        AMODE *ap1, *ap2;
        int n0 = natural_size(node->v.p[0]);
        int n1 = natural_size(node->v.p[1]);
        if (n1 >= BESZ_CFLOAT)
        {
            int limited = FALSE;
            if ((node->v.p[0]->cflags &DF_CXLIMITED) &&
                (node->v.p[1]->cflags &DF_CXLIMITED))
                limited = TRUE;
        
            gen_codes(op_sub,BESZ_DWORD ,makedreg(ESP),make_immed(40)) ;
            ap2 = gen_expr(node->v.p[1], FALSE, FALSE, size);
            do_extend(ap2, BESZ_CLDOUBLE, 0);
            gen_codefs(op_fstp,BESZ_LDOUBLE,make_stack(-20),0);
            gen_codefs(op_fstp,BESZ_LDOUBLE,make_stack(-30),0);
            
            ap1 = gen_expr(node->v.p[0], FALSE, FALSE, size);
            do_extend(ap1, BESZ_CLDOUBLE, 0);
            gen_codefs(op_fstp,BESZ_LDOUBLE,make_stack(0),0);
            gen_codefs(op_fstp,BESZ_LDOUBLE,make_stack(-10),0);
        
            if (limited)
                call_library("__CPLXDIVLIM") ;
            else    
                call_library("__CPLXDIV") ;    
            return ap1;
        }
        if (n0 < BESZ_CFLOAT && n1 < BESZ_CFLOAT)
        {
            int s1 = ap1->length, s2 = ap2->length;
            AMODE *ap3 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            if (n1 >= BESZ_IFLOAT)
                gen_codef(op_fchs,0,0);
            if (ap3->length <= BESZ_FLOAT)
                ap3->length = BESZ_IFLOAT;
            else if (ap3->length == BESZ_DOUBLE)
                ap3->length = BESZ_IDOUBLE;
            else
                ap3->length = BESZ_ILDOUBLE;
            return ap3;
        } 
        else if (n0 >= BESZ_CFLOAT && n1 < BESZ_CFLOAT)
        {
            int iap1, iap2;
            ap1 = gen_expr(node->v.p[0], FALSE, FALSE, size);
            ap2 = gen_expr(node->v.p[1], FALSE, FALSE, size);
            iap1 = ap1->mode == am_frfr;
            iap2 = ap2->mode == am_freg ;
            if (iap1 || !iap1 && !iap2) 
            {
                if (!iap1)
                    do_extend(ap1,BESZ_CLDOUBLE,0);
                if (!iap2)
                    do_extend(ap2,ap2->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE,F_FREG);
                if (ap2->length < BESZ_IFLOAT)
                {
                    gen_codef(op_fld,makefreg(0),0);
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(fopp,makefreg(2),0);
                } 
                else
                {
                    gen_codef(op_fld,makefreg(0),0);
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(op_fchs,0,0);
                    gen_codef(op_fxch,0,0);
                }
            }
            else 
            {
                do_extend(ap1,BESZ_CLDOUBLE,0);
                if (ap2->length < BESZ_IFLOAT)
                {
                    gen_codef(fop,makefreg(2),0);
                    gen_codef(op_fxch,0,0);
                    gen_codef(foppr,makefreg(2),0);
                } 
                else
                {
                    gen_codef(fop,makefreg(2),0);
                    gen_codef(op_fchs,0,0);
                    gen_codef(op_fxch,0,0);
                    gen_codef(foppr,makefreg(2),0);
                }
            }
            return ap1;
        } 
}

//-------------------------------------------------------------------------

void divprepare(int op, int size)
{
    AMODE *ah;
    if (op == op_idiv)
    switch (size)
    {
        case  - BESZ_BYTE: case BESZ_BYTE:
            gen_code(op_cbw, 0, 0);
            break;
        case BESZ_WORD:
            case  - BESZ_WORD: gen_code(op_cwd, 0, 0);
            break;
        case  - BESZ_DWORD : case BESZ_DWORD :
            gen_code(op_cdq, 0, 0);
            break;
    }
    else
    switch (size)
    {
        case  - BESZ_BYTE: case BESZ_BYTE:
            ah = makedreg(4);
            gen_codes(op_sub, BESZ_WORD, ah, ah);
            break;
        case BESZ_WORD:
            case  - BESZ_WORD: gen_codes(op_sub, BESZ_WORD, makedreg(EDX), makedreg(EDX));
            break;
        case  - BESZ_DWORD : case BESZ_DWORD :
            gen_codes(op_sub, BESZ_DWORD , 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 == BESZ_BYTE)
    {
        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 = BESZ_BYTE;
    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, BESZ_DWORD , ap2, ap2);
        else
            gen_codes(op_mov, BESZ_DWORD , ap2, make_immed(1));
        return ;
    }
    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)
            {
                freeop(ap1);
                freeop(ap2);
                gen_codes(op_xchg, BESZ_DWORD , ap2, ap1);
                divintoeax(ap1, size, op, modflag);
                break;
            }
            if (regs[0])
            {
                freeop(ap2);

                gen_push(EAX, am_dreg, 1);
                pushax = TRUE;
            }
            else
            {
                freeop(ap1);
                freeop(ap2);
            }
            gen_codes(op_xchg, BESZ_DWORD , 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, BESZ_DWORD , ap1, eax);
                freeop(ap2);
            }
            else
            {
                freeop(ap1);
                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 */
            freeop(ap1);
            freeop(ap2);
            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 = BESZ_DWORD ;
        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 = BESZ_DWORD ;
        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 = BESZ_QWORD;
    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 > BESZ_QWORD)
    {
        int n1 = natural_size(node->v.p[0]), n2 = natural_size(node->v.p[1]);
        if (n1 < BESZ_IFLOAT && n2 < BESZ_IFLOAT)
            return gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
        else if (n1 >= BESZ_IFLOAT && n1 < BESZ_CFLOAT && n2 >=BESZ_IFLOAT && n2 < BESZ_CFLOAT)
        {
            return gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
        }
        else if (n1 >= BESZ_IFLOAT && n1 < BESZ_CFLOAT && n2 < BESZ_IFLOAT) 
        {
            AMODE *ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            ap1->length = BESZ_ILDOUBLE ;
            return ap1 ;
        }
        else if (n1 <BESZ_IFLOAT && n2 >= BESZ_IFLOAT && n2 < BESZ_CFLOAT)
        {
            AMODE *ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            ap1->length = BESZ_ILDOUBLE ;
            gen_codef(op_fchs,0,0);
            return ap1 ;
        }
        else
            return gen_complexdiv(node, fop, fopp, fopr, foppr, size, 0);
    }
    if (siz1 == BESZ_QWORD || siz1 ==  - BESZ_QWORD)
        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);
}
//-------------------------------------------------------------------------

AMODE *gen_complexmul(ENODE *node, int fop, int fopp, int fopr, int foppr, int size, AMODE **apr)
{
        AMODE *ap1, *ap2;
        int n0 = natural_size(node->v.p[0]);
        int n1 = natural_size(node->v.p[1]);
        if (n0 >= BESZ_CFLOAT && n1 >= BESZ_CFLOAT)
        {
            int limited = FALSE;
            if ((node->v.p[0]->cflags &DF_CXLIMITED) &&
                (node->v.p[1]->cflags &DF_CXLIMITED))
                limited = TRUE;
            gen_codes(op_sub,BESZ_DWORD ,makedreg(ESP),make_immed(40)) ;
            ap2 = gen_expr(node->v.p[1], FALSE, FALSE, size);
            do_extend(ap2, BESZ_CLDOUBLE, 0);
            gen_codefs(op_fstp,BESZ_LDOUBLE,make_stack(-20),0);
            gen_codefs(op_fstp,BESZ_LDOUBLE,make_stack(-30),0);
            
            ap1 = gen_expr(node->v.p[0], FALSE, FALSE, size);
            do_extend(ap1, BESZ_CLDOUBLE, 0);
            gen_codefs(op_fstp,BESZ_LDOUBLE,make_stack(0),0);
            gen_codefs(op_fstp,BESZ_LDOUBLE,make_stack(-10),0);
        
            if (limited)
                call_library("__CPLXMULLIM") ;
            else    
                call_library("__CPLXMUL") ;    
            return ap1;
        }
        if (n0 < BESZ_CFLOAT && n1 < BESZ_CFLOAT)
        {
            AMODE *ap3 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            if (ap3->length <= BESZ_FLOAT)
                ap3->length = BESZ_IFLOAT;
            else if (ap3->length == BESZ_DOUBLE)
                ap3->length = BESZ_IDOUBLE;
            else
                ap3->length = BESZ_ILDOUBLE;
            return ap3;
        } 
        else if (n0 < BESZ_CFLOAT && n1 >= BESZ_CFLOAT)
        {
            int iap1, iap2;
            ap1 = gen_expr(node->v.p[0], FALSE, FALSE, size);
            ap2 = gen_expr(node->v.p[1], FALSE, FALSE, size);
            iap1 = ap1->mode == am_freg;
            iap2 = ap2->mode == am_frfr ;
            if (iap1 || !iap1 && !iap2) 
            {
                if (!iap1)
                    do_extend(ap1,ap1->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE,F_FREG);
                if (!iap2)
                    do_extend(ap2,BESZ_CLDOUBLE,0);
                if (ap1->length < BESZ_IFLOAT)
                {
                    gen_codef(fop,makefreg(2),0);
                    gen_codef(op_fxch,0,0);
                    gen_codef(fopp,makefreg(2),0);
                } 
                else
                {
                    gen_codef(fop,makefreg(2),0);
                    gen_codef(op_fxch,0,0);
                    gen_codef(op_fchs,0,0);
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(op_fxch,0,0);
                }
            }
            else 
            {
                do_extend(ap1,ap1->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE,F_FREG);
                if (ap1->length < BESZ_IFLOAT)
                {
                    gen_codef(op_fld,makefreg(0),0);
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(fopp,makefreg(2),0);
                } 
                else
                {
                    gen_codef(op_fld,makefreg(0),0);
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(op_fxch,0,0);
                    gen_codef(op_fchs,0,0);
                }
            }
            return ap2;
        } 
        else if (n0 >= BESZ_CFLOAT && n1 < BESZ_CFLOAT)
        {
            int iap1, iap2;
            ap1 = gen_expr(node->v.p[0], FALSE, FALSE, size);
            ap2 = gen_expr(node->v.p[1], FALSE, FALSE, size);
            iap1 = ap1->mode == am_frfr;
            iap2 = ap2->mode == am_freg ;
            if (iap1 || !iap1 && !iap2) 
            {
                if (!iap1)
                    do_extend(ap1,BESZ_CLDOUBLE,0);
                if (!iap2)
                    do_extend(ap2,ap2->length < BESZ_IFLOAT ? BESZ_LDOUBLE : BESZ_ILDOUBLE,F_FREG);
                if (ap2->length < BESZ_IFLOAT)
                {
                    gen_codef(op_fld,makefreg(0),0);
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(fopp,makefreg(2),0);
                } 
                else
                {
                    gen_codef(op_fld,makefreg(0),0);
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(op_fxch,0,0);
                    gen_codef(op_fchs,0,0);
                }
            }
            else 
            {
                do_extend(ap1,BESZ_CLDOUBLE,0);
                if (ap2->length < BESZ_IFLOAT)
                {
                    gen_codef(fop,makefreg(2),0);
                    gen_codef(op_fxch,0,0);
                    gen_codef(fopp,makefreg(2),0);
                } 
                else
                {
                    gen_codef(fop,makefreg(2),0);
                    gen_codef(op_fxch,0,0);
                    gen_codef(op_fchs,0,0);
                    gen_codef(fopp,makefreg(2),0);
                    gen_codef(op_fxch,0,0);
                }
            }
            return ap1;
        } 
}


/*
 * 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 != BESZ_DWORD  && ap1->length !=  - BESZ_DWORD )
        do_extend(ap1, BESZ_DWORD , F_ALL);
    if (equal_address(ap1, ap2))
    {
        if (ap1->length != BESZ_DWORD  && ap1->length !=  - BESZ_DWORD )
            do_extend(ap1, BESZ_DWORD , F_ALL);
        gen_codes(op_imul, BESZ_DWORD , ap1, ap1);
    }
    else
    {
        if (ap1->length != BESZ_DWORD  && ap1->length !=  - BESZ_DWORD )
            do_extend(ap1, BESZ_DWORD , F_ALL);
        if (ap2->length != BESZ_DWORD  && ap2->length !=  - BESZ_DWORD )
            do_extend(ap2, BESZ_DWORD , F_ALL);
        gen_codes(op_imul, BESZ_DWORD , ap1, ap2);
    }
    freeop(ap2);
    if (chksize(BESZ_DWORD , 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 = BESZ_DWORD ;
        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 = BESZ_DWORD ;
        ap2 = copy_addr(ap1);
        ap2->offset = makenode(en_add, ap2->offset, makeintnode(en_icon, BESZ_DWORD ));
        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 = BESZ_QWORD;
    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) > BESZ_QWORD)
    {
        int n1 = natural_size(node->v.p[0]), n2 = natural_size(node->v.p[1]);
        if (n1 < BESZ_IFLOAT && n2 < BESZ_IFLOAT)
            return gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
        else if (n1 >= BESZ_IFLOAT && n1 < BESZ_CFLOAT && n2 >=BESZ_IFLOAT && n2 < BESZ_CFLOAT)
        {
            AMODE *ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            gen_codef(op_fchs,0,0) ;
            return ap1;
        }
        else if (n1 >= BESZ_IFLOAT && n1 < BESZ_CFLOAT && n2 < BESZ_IFLOAT) 
        {
            AMODE *ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            ap1->length = BESZ_ILDOUBLE ;
            return ap1 ;
        }
        else if (n1 <BESZ_IFLOAT && n2 >= BESZ_IFLOAT && n2 < BESZ_CFLOAT)
        {
            AMODE *ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            ap1->length = BESZ_ILDOUBLE ;
            return ap1 ;
        }
        else
            return gen_complexmul(node, fop, fopp, fopr, foppr, size, 0);
    }
    if (size == BESZ_QWORD || size ==  - BESZ_QWORD)
        return do6mul(node, size);
    prefer(node, &ap1, &ap2, op, TRUE, BESZ_DWORD );
    do_extend(ap1, BESZ_DWORD , 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, TRUE, xsiz);
    if (xsiz == BESZ_QWORD)
        do_extend(ap1, xsiz, F_VOL | F_AXDX);
    else
        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, TRUE, xsiz);
    if (xsiz == BESZ_QWORD)
        do_extend(ap2, xsiz, F_VOL | F_AXDX);
    else
        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, BESZ_LDOUBLE, 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 sz;
    int nsize = natural_size(node->v.p[0]);
    ap = gen_expr(node->v.p[0], novalue, TRUE, nsize);
    if (ap->length > BESZ_QWORD)
    {
        AMODE *ap2 = gen_unary(node->v.p[0],op,fop,nsize);
        if (nsize >= BESZ_CFLOAT)
            return complexstore(node->v.p[0],ap,novalue,nsize);
        else
            return floatstore(node->v.p[0], ap, novalue, nsize);
    }
    else
    {
        if (ap->length == BESZ_QWORD || ap->length ==  - BESZ_QWORD)
        {
            AMODE *ap2;
            int oldlen = ap->length;
            ap->length = BESZ_DWORD ;
            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
        {
            if (ap->mode == am_screg || ap->mode == am_sdreg || ap->mode ==
                am_streg || ap->mode == am_seg)
            {
                AMODE *ap2 = temp_data();
                gen_codes(op_mov, BESZ_DWORD , ap2, ap);
                gen_code(op, ap2, 0);
                gen_codes(op_mov, BESZ_DWORD , ap, ap2);
                freeop(ap2);
            }
            else
            {
                sz = ap->length;
                if (ap->length ==  BESZ_FARPTR)
                    ap->length =  - BESZ_DWORD ;
                gen_code(op, ap, 0);
                ap->length = sz;
            }
        }
    }
    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, sz;
    int nsize = natural_size(node->v.p[0]);
    if (natural_size(node) > BESZ_QWORD)
    {
        int n1 = natural_size(node->v.p[0]), n2 = natural_size(node->v.p[1]);
        if (n1 < BESZ_IFLOAT && n2 < BESZ_IFLOAT)
            ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
        else if (n1 >= BESZ_IFLOAT && n1 < BESZ_CFLOAT && n2 >=BESZ_IFLOAT && n2 < BESZ_CFLOAT) {
            ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            ap1->length = BESZ_ILDOUBLE;
        } else
            ap1 = gen_complexadd(node, fop, fopp, fopr, foppr, size, 0);
        apr = gen_expr(node->v.p[0],FALSE,TRUE,nsize);
        if (nsize >= BESZ_CFLOAT) 
        {
            return complexstore(node->v.p[0], apr, novalue, nsize);
        }
        else if (nsize > BESZ_QWORD)
        {
            do_extend(ap1,nsize,F_FREG | F_VOL);
            return floatstore(node->v.p[0], apr, novalue, nsize);
        } 
        else
        {
            do_extend(ap1,nsize,F_DREG | F_VOL) ;
            gen_codes(op_mov, apr->length, apr, ap1);
            if (novalue)
                freeop(ap1);
            return apr;
        }
    }
    if (nsize == BESZ_QWORD || nsize ==  - BESZ_QWORD)
    {
        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, BESZ_QWORD, F_AXDX);
        oldsize = apr->length;
        apr->length = BESZ_DWORD ;
        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, F_NOREUSE);
    if (!bits)
    {
        sz = apr->length;
        apr->seg = ap1->seg;
        if (ap1->length ==  BESZ_FARPTR)
            ap1->length =  - BESZ_DWORD ;
        if (apr->length ==  BESZ_FARPTR)
            apr->length =  - BESZ_DWORD ;
        if (ap2->length ==  BESZ_FARPTR)
            ap2->length =  - BESZ_DWORD ;
        if (ap1->mode != am_dreg && ap2->mode != am_dreg && ap2->mode !=
            am_immed)
            do_extend(ap2, ap1->length, F_DREG | F_VOL);
        if (apr->mode == am_screg || apr->mode == am_sdreg || apr->mode ==
            am_streg || apr->mode == am_seg)
        {
            gen_code(op, ap1, ap2);
            gen_codes(op_mov, BESZ_DWORD , apr, ap1);
        }
        else
            gen_code(op, apr, ap2);
        if (novalue)
            freeop(ap1);
        freeop(ap2);
        apr->length = sz;
        return apr;
    }
    else
    {
        sz = ap1->length;
        if (ap1->length ==  BESZ_FARPTR)
            ap1->length =  - BESZ_DWORD ;
        if (apr->length ==  BESZ_FARPTR)
            apr->length =  - BESZ_DWORD ;
        if (ap2->length ==  BESZ_FARPTR)
            ap2->length =  - BESZ_DWORD ;
        gen_code(op, ap1, ap2);
        bit_store(apr, ap1, node->v.p[0], novalue);
        freeop(ap2);
        freeop(apr);
        if (novalue)
            freeop(ap1);
        ap1->length = sz;
        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 sz;
    int bits = isbit(node->v.p[0]);
    int nsize = natural_size(node->v.p[0]);
    if (nsize == BESZ_QWORD || nsize ==  - BESZ_QWORD)
    {
        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, BESZ_QWORD, F_AXDX);
        oldsize = apr->length;
        apr->length = BESZ_DWORD ;
        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, TRUE, 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, BESZ_DWORD , 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, BESZ_DWORD , 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, BESZ_DWORD , 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, BESZ_DWORD , ap2, 0);
            else
                freeop(ap2);
            return ap2;
        }
    }
    else
    {
        int vb;
        as_args(node, &apr, &ap1, &ap2, nsize, 0);
        small_size(ap1, ap2, nsize, F_NOREUSE);
        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)
            {
                apr->seg = ap1->seg;
                if (ap1->length ==  BESZ_FARPTR)
                    ap1->length =  - BESZ_DWORD ;
                gen_codes(op2, BESZ_DWORD , ap1, make_immed(vb));
                if (novalue)
                    freeop(ap1);
                return apr;
            }
        }
        if (apr->mode == am_screg || apr->mode == am_sdreg || apr->mode ==
            am_streg || apr->mode == am_seg)
        {
            gen_code(op, ap1, ap2);
            gen_codes(op_mov, BESZ_DWORD , apr, ap1);
        }
        else
        {
            apr->seg = ap1->seg;
            sz = apr->length;
            if (apr->length ==  BESZ_FARPTR)
                apr->length =  - BESZ_DWORD ;
            if (ap2->length ==  BESZ_FARPTR)
                ap2->length =  - BESZ_DWORD ;
            gen_code(op, apr, ap2);
            apr->length = sz;
        }
        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 == BESZ_QWORD || nsize ==  - BESZ_QWORD)
    {
        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 = BESZ_DWORD ;
        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 <= BESZ_QWORD)
        ap2->length = BESZ_DWORD ;
     /* this is kind of iffy, but bits outside CL really don't matter */
    else
        do_extend(ap2, BESZ_DWORD , 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, BESZ_DWORD , 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) > BESZ_QWORD)
    {
        int n1 = natural_size(node->v.p[0]), n2 = natural_size(node->v.p[1]);
        if (n1 < BESZ_IFLOAT && n2 < BESZ_IFLOAT)
            ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
        else if (n1 >= BESZ_IFLOAT && n1 < BESZ_CFLOAT && n2 >=BESZ_IFLOAT && n2 < BESZ_CFLOAT)
        {
            ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            gen_codef(op_fchs,0,0) ;
        }
        else if (n1 >= BESZ_IFLOAT && n1 < BESZ_CFLOAT && n2 < BESZ_IFLOAT) 
        {
            ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            ap1->length = BESZ_ILDOUBLE ;
        }
        else if (n1 <BESZ_IFLOAT && n2 >= BESZ_IFLOAT && n2 < BESZ_CFLOAT)
        {
            ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            ap1->length = BESZ_ILDOUBLE ;
        }
        else
            ap1 = gen_complexmul(node, fop, fopp, fopr, foppr, size, 0);
        apr = gen_expr(node->v.p[0],FALSE,TRUE,nsize);
        if (nsize >= BESZ_CFLOAT)
        {
            return complexstore(node->v.p[0], apr, novalue, nsize);
        }
        else if (nsize > BESZ_QWORD)
        {
            do_extend(ap1,nsize,F_FREG | F_VOL);
            return floatstore(node->v.p[0], apr, novalue, nsize);
        } 
        else
        {
            do_extend(ap1,nsize,F_DREG | F_VOL) ;
            gen_codes(op_mov, apr->length, apr, ap1);
            if (novalue)
                freeop(ap1);
            return apr;
        }
    }
    else if (natural_size(node) == BESZ_QWORD || natural_size(node) ==  - BESZ_QWORD)
    {
        int oldlen;
        apr = gen_expr(node->v.p[0], FALSE, TRUE, size);
        apr = aprtocx(apr);
        ap1 = do6mul(node, BESZ_QWORD);
        if (apr->length < BESZ_QWORD && apr->length !=  - BESZ_QWORD)
        {
            gen_codes(op_mov, apr->length, apr, makedreg(EAX));
            freeop(ap1);
            return apr;
        }
        oldlen = apr->length;
        apr->length = BESZ_DWORD ;
        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, F_NOREUSE);
    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) > BESZ_QWORD)
    {
        int n1 = natural_size(node->v.p[0]), n2 = natural_size(node->v.p[1]);
        if (n1 < BESZ_IFLOAT && n2 < BESZ_IFLOAT)
            ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
        else if (n1 >= BESZ_IFLOAT && n1 < BESZ_CFLOAT && n2 >=BESZ_IFLOAT && n2 < BESZ_CFLOAT)
        {
            ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
        }
        else if (n1 >= BESZ_IFLOAT && n1 < BESZ_CFLOAT && n2 < BESZ_IFLOAT) 
        {
            ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            ap1->length = BESZ_ILDOUBLE ;
        }
        else if (n1 <BESZ_IFLOAT && n2 >= BESZ_IFLOAT && n2 < BESZ_CFLOAT)
        {
            ap1 = gen_fbinary(node, fop, fopp, fopr, foppr, size, 0);
            ap1->length = BESZ_ILDOUBLE ;
            gen_codef(op_fchs,0,0);
        }
        else
            ap1 = gen_complexdiv(node, fop, fopp, fopr, foppr, size, 0);
        apr = gen_expr(node->v.p[0],FALSE,TRUE,nsize);
        if (nsize >= BESZ_CFLOAT) 
        {
            return complexstore(node->v.p[0], apr, novalue, nsize);
        }
        else if (nsize > BESZ_QWORD)
        {
            do_extend(ap1,nsize,F_FREG | F_VOL);
            return floatstore(node->v.p[0], apr, novalue, nsize);
        } 
        else
        {
            do_extend(ap1,nsize,F_DREG | F_VOL) ;
            gen_codes(op_mov, apr->length, apr, ap1);
            if (novalue)
                freeop(ap1);
            return apr;
        }
    }
    else if (natural_size(node) == BESZ_QWORD || natural_size(node) ==  - BESZ_QWORD)
    {
        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 < BESZ_QWORD && apr->length !=  - BESZ_QWORD)
        {
            gen_codes(op_mov, apr->length, apr, makedreg(EAX));
            freeop(ap1);
            if (novalue)
                freeop(apr);
            return apr;
        }
        else
        {
            oldlen = apr->length;
            apr->length = BESZ_DWORD ;
            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, F_NOREUSE);
    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(int reg, AMODE *dst, AMODE *src, int size)
{
    AMODE *intermed = makedreg(reg);
    gen_codes(op_mov, size, intermed, src);
    gen_codes(op_mov, size, dst, intermed);
    freeop(intermed);
    freeop(src);

}

//-------------------------------------------------------------------------

void mov2(int reg, AMODE *dst, AMODE *src, int size1, int size2)
{
    AMODE *intermed = makedreg(reg),  *dst1,  *src1;
    dst1 = copy_addr(dst);
    src1 = copy_addr(src);
    gen_codes(op_mov, size1, intermed, src);
    gen_codes(op_mov, size1, dst, intermed);
    if (src1->offset == 0)
        src1->offset = makeintnode(en_icon, 0);
    if (dst1->offset == 0)
        dst1->offset = makeintnode(en_icon, 0);
    src1->offset = makenode(en_add, src1->offset, makeintnode(en_icon, size1));
    dst1->offset = makenode(en_add, dst1->offset, makeintnode(en_icon, size1));
    gen_codes(op_mov, size2, intermed, src1);
    gen_codes(op_mov, size2, dst1, intermed);
    freeop(intermed);
    freeop(src);
}

//-------------------------------------------------------------------------

void mov3(int reg, AMODE *dst, AMODE *src, int size1, int size2, int size3)
{
    AMODE *intermed = makedreg(reg),  *dst1,  *src1;
    gen_codes(op_mov, size1, intermed, src);
    gen_codes(op_mov, size1, dst, intermed);
    dst1 = copy_addr(dst);
    src1 = copy_addr(src);
    if (src1->offset == 0)
        src1->offset = makeintnode(en_icon, 0);
    if (dst1->offset == 0)
        dst1->offset = makeintnode(en_icon, 0);
    src1->offset = makenode(en_add, src1->offset, makeintnode(en_icon, size1));
    dst1->offset = makenode(en_add, dst1->offset, makeintnode(en_icon, size1));
    gen_codes(op_mov, size2, intermed, src1);
    gen_codes(op_mov, size2, dst1, intermed);
    src1->offset = makenode(en_add, src1->offset, makeintnode(en_icon, size2));
    dst1->offset = makenode(en_add, dst1->offset, makeintnode(en_icon, size2));
    gen_codes(op_mov, size3, intermed, src1);
    gen_codes(op_mov, size3, dst1, intermed);
    freeop(intermed);
    freeop(src);
}

//-------------------------------------------------------------------------

AMODE *amode_moveblock(AMODE *ap1, AMODE *ap2, int size)
{
    int t = size &3, q = size >> 2;
    int pushds = FALSE, pushes = FALSE;
    AMODE *ap3;
	int reg = EAX, xchgreg = -1, pushed = FALSE;
	int preg1 = FALSE, sreg1 = FALSE, preg2 = FALSE, sreg2= FALSE;
	if (size <= 12 && size != 11)
	{
		int uregs[8],i;
		memset(uregs, 0 , sizeof(uregs));
		uregs[4] = uregs[5] = 1;
		if (ap1->mode == am_indisp)
			uregs[ap1->preg] = 1;
		if (ap1->mode == am_indispscale)
		{
			uregs[ap1->preg] = 1;
			if (ap1->sreg >= 0)
				uregs[ap1->sreg] = 1;
		}
		if (ap2->mode == am_indisp)
			uregs[ap2->preg] = 1;
		if (ap2->mode == am_indispscale)
		{
			uregs[ap2->preg] = 1;
			if (ap2->sreg >= 0)
				uregs[ap2->sreg] = 1;
		}
		for (i=0; i < sizeof(regs); i++)
			if (!uregs[i])
			{
				reg = i;
				break;
			}
		if (reg >= EBX || regs[reg])
		{
			pushed = TRUE;
			gen_codes(op_push, 4, makedreg(reg), NULL);
		}
		if (reg >= EBX && (size & 1))
		{
			gen_codes(op_xchg, 4, makedreg(EAX), makedreg(reg));
			xchgreg = reg;
			reg = EAX;
			if (ap1->mode == am_indisp)
				if (ap1->preg == EAX)
				{
					preg1 = TRUE;
					ap1->preg = xchgreg;
				}
			if (ap1->mode == am_indispscale)
			{
				if (ap1->preg == EAX)
				{
					preg1 = TRUE;
					ap1->preg = xchgreg;
				}
				if (ap1->sreg == EAX)
				{
					sreg1 = TRUE;
					ap1->sreg = xchgreg;
				}
			}
			if (ap2->mode == am_indisp)
				if (ap2->preg == EAX)
				{
					preg2 = TRUE;
					ap2->preg = xchgreg;
				}
			if (ap2->mode == am_indispscale)
			{
				if (ap2->preg == EAX)
				{
					preg2 = TRUE;
					ap2->preg = xchgreg;
				}
				if (ap2->sreg == EAX)
				{
					sreg2 = TRUE;
					ap2->sreg = xchgreg;
				}
			}
		}
	}
    switch (size)
    {
        case 1:
        case 2:
        case 4 :
            mov1(reg, ap1, ap2, size);
            break;
        case 3:
            mov2(reg, ap1, ap2, 2, 1);
            break;
        case 5:
            mov2(reg, ap1, ap2, BESZ_DWORD , 1);
            break;
        case 6:
            mov2(reg, ap1, ap2, BESZ_DWORD , 2);
            break;
        case 7:
            mov3(reg, ap1, ap2, BESZ_DWORD , 2, 1);
            break;
        case 8:
            mov2(reg, ap1, ap2, BESZ_DWORD , BESZ_DWORD );
            break;
        case 9:
            mov3(reg, ap1, ap2, BESZ_DWORD , BESZ_DWORD , 1);
            break;
        case 10:
            mov3(reg, ap1, ap2, BESZ_DWORD , BESZ_DWORD , 2);
            break;
        case 12:
            mov3(reg, ap1, ap2, BESZ_DWORD , BESZ_DWORD , BESZ_DWORD );
            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();
                ap3->seg = ap1->seg;
                gen_code(op_lea, ap3, ap1);
                ap3->seg = ap1->seg;
                ap1 = ap3;
            }
            gen_push(ESI, am_dreg, 0);
            gen_push(EDI, am_dreg, 0);
            freeop(ap2);
            if (regs[1])
                gen_push(ECX, am_dreg, 0);
            if (ap2->mode == am_dreg)
                gen_codes(op_mov, BESZ_DWORD , makedreg(ESI), ap2);
            else
                gen_codes(op_lea, BESZ_DWORD , makedreg(ESI), ap2);
            if (ap1->mode == am_dreg)
                gen_codes(op_mov, BESZ_DWORD , makedreg(EDI), ap1);
            else
                gen_codes(op_lea, BESZ_DWORD , makedreg(EDI), ap1);
            if (prm_farkeyword)
            {
                if (ap2->seg && ap2->seg != DS)
                {
                    pushds = TRUE;
                    gen_push(DS + 24, am_dreg, FALSE);
                }
                if (ap1->seg && ap1->seg != ES)
                {
                    pushes = TRUE;
                    gen_push(ES + 24, am_dreg, FALSE);
                }
                if (pushds)
                    gen_push(ap2->seg + 24, am_dreg, FALSE);
                if (pushes)
                {
                    gen_push(ap1->seg + 24, am_dreg, FALSE);
                    gen_pop(ES + 24, am_dreg, FALSE);
                }
                else
                {
                    gen_push(SS + 24, am_dreg, FALSE);
                    gen_pop(ES + 24, am_dreg, FALSE);
                }
                if (pushds)
                    gen_pop(DS + 24, am_dreg, FALSE);

            }
            gen_code(op_cld, 0, 0);
            if (q)
            {
                gen_codes(op_mov, BESZ_DWORD , 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 (pushes)
                gen_pop(ES + 24, am_dreg, FALSE);
            if (pushds)
                gen_pop(DS + 24, am_dreg, FALSE);
            if (regs[1])
                gen_pop(ECX, am_dreg, 0);
            gen_pop(EDI, am_dreg, 0);
            gen_pop(ESI, am_dreg, 0);
            break;
    }
	if (size <= 12 && size != 11)
	{
		if (xchgreg >= 0)
		{
			gen_codes(op_xchg, 4, makedreg(reg), makedreg(xchgreg));
			reg = xchgreg;
			if (preg1)
				ap1->preg = xchgreg;
			if (preg2)
				ap2->preg = xchgreg;
			if (sreg1)
				ap2->preg = xchgreg;
			if (sreg2)
				ap2->preg = xchgreg;
		}
		if (pushed)
		{
			gen_codes(op_pop, 4, makedreg(reg), NULL);
		}
			
	}
    freeop(ap2);
    return ap1;
}

//-------------------------------------------------------------------------

AMODE *gen_moveblock(ENODE *node)
{
    AMODE *ap1,  *ap2;
    ENODE ep1;
    if (!node->size)
        return (0);
    if (node->v.p[1]->nodetype == en_moveblock)
        ep1 =  *node->v.p[1];
    else if (node->v.p[1]->nodetype == en_movebyref)
        ep1 =  *node->v.p[1]->v.p[0];
    else
    {
        ep1.nodetype = en_a_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);
    if (node->v.p[0]->nodetype == en_moveblock)
        ep1 =  *node->v.p[0];
    else if (node->v.p[0]->nodetype == en_movebyref)
        ep1 =  *node->v.p[0]->v.p[0];
    else
    {
        ep1.nodetype = en_a_ref;
        ep1.cflags = 0;
        ep1.v.p[0] = node->v.p[0];
    }
	if (node->v.p[0]->nodetype == en_structret && ap2->preg == EAX)
	{
		AMODE *ap3 = temp_data();
		freeop(ap2);
		gen_code(op_mov, ap3, makedreg(ap2->preg));
		ap2->preg = ap3->preg;
	}
    ap1 = gen_expr(&ep1, FALSE, TRUE, 0);
    return amode_moveblock(ap1, ap2, node->size);
}
//-------------------------------------------------------------------------

AMODE *amode_clearblock(AMODE *ap1, int size)
{
    int t = size &3, q = size >> 2;
    int pushds = FALSE, pushes = FALSE;
    AMODE *ap3;

    gen_push(EDI, am_dreg, 0);
    if (regs[1])
        gen_push(ECX, am_dreg, 0);
    if (ap1->mode == am_dreg)
        gen_codes(op_mov, BESZ_DWORD , makedreg(EDI), ap1);
    else
        gen_codes(op_lea, BESZ_DWORD , makedreg(EDI), ap1);
    if (prm_farkeyword)
    {
        if (ap1->seg && ap1->seg != ES)
        {
            pushes = TRUE;
            gen_push(ES + 24, am_dreg, FALSE);
        }
        if (pushes)
        {
            gen_push(ap1->seg + 24, am_dreg, FALSE);
            gen_pop(ES + 24, am_dreg, FALSE);
        }
        else
        {
            gen_push(SS + 24, am_dreg, FALSE);
            gen_pop(ES + 24, am_dreg, FALSE);
        }
        if (pushds)
            gen_pop(DS + 24, am_dreg, FALSE);

    }
    gen_code(op_cld, 0, 0);
    if (q)
    {
        gen_codes(op_sub,BESZ_DWORD , makedreg(EAX),makedreg(EAX)) ;
        gen_codes(op_mov, BESZ_DWORD , makedreg(ECX), make_immed(q));
        gen_code(op_rep, 0, 0);
        gen_code(op_stosd, 0, 0);
    }
    if (t &2)
        gen_code(op_stosw, 0, 0);
    if (t &1)
        gen_code(op_stosb, 0, 0);
    if (pushes)
        gen_pop(ES + 24, am_dreg, FALSE);
    if (regs[1])
        gen_pop(ECX, am_dreg, 0);
    gen_pop(EDI, am_dreg, 0);
    return ap1;
}

//-------------------------------------------------------------------------

AMODE *gen_clearblock(ENODE *node)
{
    AMODE *ap1 ;
    ENODE ep1;
    if (!node->size)
        return (0);
    ap1 = gen_expr(node->v.p[0], FALSE, TRUE, 0);
    return amode_clearblock(ap1, node->size);
}

//-------------------------------------------------------------------------

void asnfloatconst(AMODE *apr, long double aa)
{
    float cc;
    double bb;
    AMODE *ap2;
            switch (apr->length)
            {
                case BESZ_FLOAT:
                case BESZ_IFLOAT:
                case BESZ_CFLOAT:
                    cc = aa;
                    ap2 = copy_addr(apr);
                    ap2->length = BESZ_DWORD ;
                    gen_code(op_mov, ap2, make_immed(*(unsigned*) &cc));
                    break;
                case BESZ_DOUBLE:
                case BESZ_IDOUBLE:
                case BESZ_CDOUBLE:
                    bb = aa;
                    ap2 = copy_addr(apr);
                    ap2->length = BESZ_DWORD ;
                    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 BESZ_LDOUBLE:
                case BESZ_ILDOUBLE:
                case BESZ_CLDOUBLE:
                    ap2 = copy_addr(apr);
                    ap2->length = BESZ_DWORD ;
                    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 = BESZ_WORD;
                    gen_code(op_mov, ap2, make_immed(*(((unsigned short*) &aa) 
                        + 4)));
                    break;
            }
}

//-------------------------------------------------------------------------

AMODE *gen_assign(ENODE *node, int novalue, int size, int stdc)
/*
->length *      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, i;
    int nsize = natural_size(node->v.p[0]);
    int rsize = assign_size(node->v.p[1], nsize);
    if (nsize == BESZ_QWORD || nsize ==  - BESZ_QWORD)
    {
        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
    {
#ifdef XXXXX
        // smart constants commented out because they violate parts of the standard
        if (nsize >= BESZ_FLOAT && (isfloatconst(node->v.p[1]->nodetype) 
            || isimaginaryconst(node->v.p[1]->nodetype)
            || iscomplexconst(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
#endif
            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 (nsize > BESZ_QWORD)
    {
#ifdef XXXXX
        if (ap2->mode == am_immed)
        {
            long double aa;
            if (apr->length >= BESZ_CFLOAT)
            {
                long double aai;
                if (ap2->offset->nodetype == en_fimaginarycon || ap2->offset->nodetype == en_rimaginarycon ||
                    ap2->offset->nodetype == en_lrimaginarycon)
                {
                    aa = 0.0;
                    aai = ap2->offset->v.f;
                } 
                else if (ap2->offset->nodetype == en_fcomplexcon || ap2->offset->nodetype == en_rcomplexcon ||
                    ap2->offset->nodetype == en_lrcomplexcon)
                {
                    aai = ap2->offset->v.c.i;
                    aa = ap2->offset->v.c.r;
                }
                else
                {
                    aa = ap2->offset->v.f;
                    aai = 0.0;
                }
                asnfloatconst(apr, aa);
                ap2 = copy_addr(apr);
                switch(apr->length)
                {
                    case BESZ_CFLOAT:
                        ap2->offset = makenode(en_add, ap2->offset, makeintnode(en_icon,4)) ;
                        break;
                    case BESZ_CDOUBLE:
                        ap2->offset = makenode(en_add, ap2->offset, makeintnode(en_icon,8)) ;
                        break;
                    case BESZ_CLDOUBLE:
                        ap2->offset = makenode(en_add, ap2->offset, makeintnode(en_icon,10)) ;
                        break;
                }
                asnfloatconst(ap2, aai);
            }
            else if (apr->length >= BESZ_IFLOAT && apr->length < BESZ_CFLOAT)
            {
                if (ap2->offset->nodetype == en_fimaginarycon || ap2->offset->nodetype == en_rimaginarycon ||
                    ap2->offset->nodetype == en_lrimaginarycon)
                {
                    aa = ap2->offset->v.f;
                } 
                else if (ap2->offset->nodetype == en_fcomplexcon || ap2->offset->nodetype == en_rcomplexcon ||
                    ap2->offset->nodetype == en_lrcomplexcon)
                    aa = ap2->offset->v.c.i;
                else
                    aa = 0.0;
                asnfloatconst(apr, aa);
            }
            else
            { 
                if (ap2->offset->nodetype == en_fimaginarycon || ap2->offset->nodetype == en_rimaginarycon ||
                    ap2->offset->nodetype == en_lrimaginarycon)
                {
                    aa = 0.0;
                }
                else if (ap2->offset->nodetype == en_fcomplexcon || ap2->offset->nodetype == en_rcomplexcon ||
                    ap2->offset->nodetype == en_lrcomplexcon)
                    aa = ap2->offset->v.c.r;
                else
                    if (isintconst(ap2->offset->nodetype))
                    {
                        aa = ap2->offset->v.i;
                    }
                    else
                    {
                        aa = ap2->offset->v.f;
                    }
                asnfloatconst(apr, aa);
            }
            if (novalue || aps)
                freeop(apr);
            if (aps)
                return aps;
            return apr;
        }
        else
        if (ap2->mode != am_freg && ap2->mode != am_frfr && ap2->length == apr->length)
        {
            int len;
            switch(apr->length)
            {
                case BESZ_FLOAT:
                    len = 4;
                    break;
                case BESZ_DOUBLE:
                    len = 8;
                    break;
                case BESZ_LDOUBLE:
                    len = 10;
                    break;
                case BESZ_IFLOAT:
                    len = 4;
                    break;
                case BESZ_IDOUBLE:
                    len = 8;
                    break;
                case BESZ_ILDOUBLE:
                    len = 10;
                    break;
                case BESZ_CFLOAT:
                    len = 8;
                    break;
                case BESZ_CDOUBLE:
                    len = 16;
                    break;
                case BESZ_CLDOUBLE:
                    len = 20;
                    break;
            }
            amode_moveblock(apr, ap2, len) ;
            if (novalue || aps)
                freeop(apr);
            if (aps)
                return aps;
            return apr;
        }
        else
#endif 
        {
            if (apr->length <= BESZ_LDOUBLE)
            {
                do_extend(ap2, BESZ_LDOUBLE, F_FREG);
                apr = floatstore(node->v.p[0], apr, novalue, nsize);
            }
            else if (apr->length < BESZ_CFLOAT)
            {
                do_extend(ap2, BESZ_ILDOUBLE, F_FREG);
                apr = floatstore(node->v.p[0], apr, novalue, nsize);
            }
            else
            {
                do_extend(ap2, BESZ_CLDOUBLE, 0);
                apr = complexstore(node->v.p[0], apr, novalue, nsize);
            }
            if (aps)
            {
                freeop(ap2);
                return aps;
            }
            return apr;
        }
    }
    if (ap2->mode != am_axdx || apr->length !=  BESZ_FARPTR)
        do_extend(ap2, resultsize(apr->length, natural_size(node->v.p[1])), 0);
    ap2->length = apr->length;
    bits = isbit(node->v.p[0]);
    if (!equal_address(apr, ap2))
    {
        if (!bits)
        {
            if (apr->length > BESZ_QWORD)
            {
                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 ==  BESZ_FARPTR)
                {
                    AMODE *ap3;
                    apr->length = BESZ_DWORD ;
                    if (ap2->mode == am_axdx)
                    {
                        ap1 = copy_addr(apr);
                        ap1->offset = makenode(en_add, ap1->offset, makeintnode
                            (en_icon, 4));
                        gen_codes(op_mov, BESZ_DWORD , apr, makedreg(EAX));
                        gen_codes(op_mov, 2, ap1, makedreg(EDX));
                    }
                    else if (ap2->mode == am_dreg)
                    {
                        ap3 = xalloc(sizeof(AMODE));
                        ap3->mode = am_seg;
                        ap3->seg = ap2->seg ? ap2->seg: (i = defseg(node
                            ->v.p[1]) ? i : DS);
                        ap1 = copy_addr(apr);
                        ap1->offset = makenode(en_add, ap1->offset, makeintnode
                            (en_icon, 4));
                        gen_code(op_mov, apr, makedreg(ap2->preg));
                        gen_codes(op_mov, 2, ap1, ap3);
                    }
                    else if (ap2->mode == am_immed)
                    {
                        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_codes(op_mov, 2, ap1, make_immed(0));
                        #else 
                            gen_codes(op_mov, 2, ap1, make_immed((ap2->offset
                                ->v.i >> 32) &0xffff));
                        #endif 
                    }
                    else
                    {
						AMODE *p = temp_data();
                        mov2(p->preg, apr, ap2, BESZ_DWORD , 2);
                    }
                    apr->length =  BESZ_FARPTR;
                    freeop(ap2);
                    if (novalue)
                        freeop(apr);
                    if (aps)
                        return aps;
                    return (apr);
                }
                else if (apr->length == BESZ_QWORD || apr->length ==  - BESZ_QWORD)
                {
                    int oldlen = apr->length, oldlen2 = ap2->length;
                    do_extend(ap2, resultsize(ap2->length, natural_size(node
                        ->v.p[1])), F_MEM | F_AXDX);
                    ap2->length = oldlen2;
                    if (ap2->mode == am_axdx)
                    {
                        apr->length = BESZ_DWORD ;
                        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 = BESZ_DWORD ;
                            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
                        {
							AMODE *p = temp_data();
                            apr->length = BESZ_DWORD ;
                            ap2->length = BESZ_DWORD ;
                            mov2(p->preg, apr, ap2, BESZ_DWORD , BESZ_DWORD );
                        }
                    }
                    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 || apr->mode == am_screg || apr
                        ->mode == am_sdreg || apr->mode == am_streg || apr
                        ->mode == am_seg)
                        do_extend(ap2, resultsize(apr->length, natural_size
                            (node->v.p[1])), F_DREG);
                    else
                        do_extend(ap2, resultsize(apr->length, natural_size
                            (node->v.p[1])), 0);
                    ap2->length = apr->length;
                    gen_codes(op_mov, apr->length, apr, ap2);
                    if (apr->mode == am_dreg && ap2->mode == am_dreg)
                        apr->seg = ap2->seg;
                }
                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 (nsize > BESZ_QWORD)
    {
        
        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);
        ap4->seg = ap2->seg;
        return ap4;
    }
    if (!equal_address(apr, ap2))
    {
        if (!bits)
        {
            if (apr->length > BESZ_QWORD)
            {
                do_extend(ap2, apr->length, F_FREG);
                return floatstore(node->v.p[0], apr, novalue, nsize);
            }
            if (apr->length == BESZ_QWORD || apr->length ==  - BESZ_QWORD)
            {
                apr = aprtocx(apr);
                do_extend(ap2, resultsize(BESZ_QWORD, natural_size(node->v.p[1])),
                    F_AXDX);
                ap2->length = BESZ_QWORD;
                ap5 = copy_addr(apr);
                ap5->offset = makenode(en_add, apr->offset, makeintnode(en_icon,
                    4));
                gen_codes(op_mov, BESZ_DWORD , apr, makedreg(EAX));
                gen_codes(op_mov, BESZ_DWORD , ap5, makedreg(EDX));
            }
            else
            {
                do_extend(ap2, resultsize(ap1->length, natural_size(node
                    ->v.p[1])), 0);
                ap2->length = ap1->length;
                gen_code(op_mov, apr, ap2);
            }
            ap4 = temp_data();
            gen_code(op_lea, ap4, apr);
            ap4->seg = apr->seg;
            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,  *ap4;
    int seg = 0;
    int pushed = FALSE, sz;
    int nsize = natural_size(node->v.p[0]);
    ap2 = gen_expr(node->v.p[1], FALSE, FALSE, BESZ_DWORD );
    if (nsize > BESZ_QWORD)
    {
        if (nsize < BESZ_CFLOAT)
        {
            AMODE apn;
            ap1 = gen_expr(node->v.p[0], FALSE, TRUE, nsize);
            sz = ap1->length;
            apn = *ap1;
            floatload(&apn, TRUE);
            make_floatconst(ap2);
            floatload(ap2, TRUE);
            if (novalue)
                gen_codef(op == op_add ? op_faddp : op_fsubp, makefreg(1), 0);
            else
                gen_codef(op == op_add ? op_faddp : op_fsubp, makefreg(1), 0);
            freeop(ap1);
            ap1 = gen_expr(node->v.p[0], FALSE, TRUE, nsize);
            floatstore(node->v.p[0], ap1, novalue, nsize);
            ap3 = fstack();
        }
        else
        {
            AMODE apn;
            ap1 = gen_expr(node->v.p[0], FALSE, TRUE, nsize);
            sz = ap1->length;
            apn = *ap1;
            complexload(&apn, TRUE);
            make_floatconst(ap2);
            floatload(ap2, TRUE);
            gen_codef(op == op_add ? op_faddp : op_fsubp, makefreg(1), 0);
            complexstore(node->v.p[0], ap1, novalue, nsize);
            freeop(ap1);
            ap3 = fstack();
            ap3->mode = am_frfr;
            ap3->length = BESZ_CLDOUBLE;
        }
    }
    else if (nsize == BESZ_QWORD || nsize ==  - BESZ_QWORD)
    {
        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 = BESZ_DWORD ;
        gen_code(op, ap1, ap2);
        ap1 = copy_addr(ap1);
        ap1->offset = makenode(en_add, ap1->offset, makeintnode(en_icon, BESZ_DWORD ));
        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);
        if (ap3->mode != am_dreg && ap2->mode != am_dreg && ap2->mode !=
            am_immed)
            do_extend(ap2, BESZ_DWORD , F_DREG | F_VOL);
        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);
        if (ap1->mode != am_dreg && ap2->mode != am_dreg && ap2->mode !=
            am_immed)
            do_extend(ap2, BESZ_DWORD , F_DREG | F_VOL);
        sz = ap1->length;
        seg = ap1->seg;
        if (ap1->length ==  BESZ_FARPTR)
            ap1->length = BESZ_DWORD ;
        if (ap2->length ==  BESZ_FARPTR)
            ap2->length = BESZ_DWORD ;
        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))
            {
                if (sz ==  BESZ_FARPTR)
                {
                    ap3 = copy_addr(ap1);
                    ap3->offset = makenode(en_add, ap3->offset, makeintnode
                        (en_icon, 4));
                    gen_codes(op_push, BESZ_DWORD , ap3, 0);
                }
                gen_codes(op_push, BESZ_DWORD , ap1, 0);
                pushed = TRUE;
            }
            else
            {
                if (!novalue)
                {
                    if (sz ==  BESZ_FARPTR)
                    {
                        ap3 = copy_addr(ap1);
                        ap3->length =  BESZ_FARPTR;
                        do_extend(ap3,  BESZ_FARPTR, F_DREG);
                        seg = ap3->seg;
                    }
                    else
                    {
                        ap3 = temp_data();
                        gen_codes(op_mov, sz, ap3, ap1);
                    }
                }
            }
        }
        gen_code(op, ap1, ap2);
        if (pushed)
        {
            ap3 = temp_data();
            gen_codes(op_pop, BESZ_DWORD , ap3, 0);
            if (sz ==  BESZ_FARPTR)
            {
                ap4 = xalloc(sizeof(AMODE));
                ap4->mode = am_seg;
                ap4->seg = seg;
                gen_code(op_pop, ap4, 0);
            }
            if (novalue)
                freeop(ap3);
        }
    }
    if (!novalue)
    {
        ap3->length = sz;
        ap3->seg = seg;
    }
    return ap3;
}

//-------------------------------------------------------------------------
#ifdef XXXXX
int pushfloatconst(int size, long double aa)
{
    float bb;
    double cc;
    int rv ;
        switch (size)
        {
            case BESZ_FLOAT:
            case BESZ_IFLOAT:
            case BESZ_CFLOAT:
                bb = aa;
                gen_codes(op_push, BESZ_DWORD , make_immed(*(unsigned*) &bb), 0);
                rv = 4;
                break;
            case BESZ_DOUBLE:
            case BESZ_IDOUBLE:
            case BESZ_CDOUBLE:
                rv = 8;
                cc = aa;
                gen_codes(op_push, BESZ_DWORD , make_immed(*(((unsigned*) &cc) + 1)), 0);
                gen_codes(op_push, BESZ_DWORD , make_immed(*(unsigned*) &cc), 0);
                break;
            case BESZ_LDOUBLE:
            case BESZ_ILDOUBLE:
                rv = 12;
                gen_codes(op_push, BESZ_DWORD , make_immed(*(((unsigned short*) &aa) + 4))
                    , 0);
                gen_codes(op_push, BESZ_DWORD , make_immed(*(((unsigned*) &aa) + 1)), 0);
                gen_codes(op_push, BESZ_DWORD , make_immed(*(unsigned*) &aa), 0);
                break;
            case BESZ_CLDOUBLE: /* only happens in pairs */
                rv = 10;
                gen_codes(op_push, 2, make_immed(*(((unsigned short*) &aa) + 4))
                    , 0);
                gen_codes(op_push, BESZ_DWORD , make_immed(*(((unsigned*) &aa) + 1)), 0);
                gen_codes(op_push, BESZ_DWORD , make_immed(*(unsigned*) &aa), 0);
                break;
        }
        return rv;
}
#endif
int push_param(ENODE *ep, int size)
/*
 *      push the operand expression onto the stack.
 */
{
    AMODE *ap,  *ap2;
    int i;
    float cc;
    double bb;
    long double aa;
    int rv;
    int nsize = natural_size(ep);
#ifdef XXXXX    
    // smart constants commented out because they violate parts of the standard
    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) || iscomplexconst(ep->v.p[0]->nodetype))
        {
            if (isintconst(ep->v.p[0]->nodetype))
                if (ep->nodetype == en_cfi || ep->nodetype == en_cri || ep->nodetype == en_clri)
                    aa = 0.0;
                else
                    aa = ep->v.p[0]->v.i;
            else if (iscomplexconst(ep->v.p[0]->nodetype))
                if (nsize >= BESZ_IFLOAT && nsize < BESZ_CFLOAT)
                    aa = ep->v.p[0]->v.c.i;
                else
                    aa = ep->v.p[0]->v.c.r;
            else if (isimaginaryconst(ep->v.p[0]->nodetype))
                if (ep->nodetype == en_cf || ep->nodetype == en_cd || ep->nodetype == en_cld)
                    aa = 0.0;
                else
                    aa = ep->v.p[0]->v.f;            
            else
                if (ep->nodetype == en_cfi || ep->nodetype == en_cri || ep->nodetype == en_clri)
                    aa = 0.0;
                else
                    aa = ep->v.p[0]->v.f;
            rv = pushfloatconst(nsize, aa);
            gen_code(op_void, 0, 0);
            return rv;
        }
    }
    else if (ep->nodetype == en_cfc || ep->nodetype == en_crc || ep->nodetype ==
        en_clrc)
        if (isfloatconst(ep->v.p[0]->nodetype) || isintconst(ep->v.p[0]->nodetype) 
            || isimaginaryconst(ep->v.p[0]->nodetype) || iscomplexconst(ep->v.p[0]->nodetype))
        {
            long double aai;
            if (isintconst(ep->v.p[0]->nodetype))
            {
                aa = ep->v.p[0]->v.i;
                aai = 0.0;
            }
            else if (isfloatconst(ep->v.p[0]->nodetype))
            {
                aa = ep->v.p[0]->v.f;
                aai = 0.0;
            }
            else if (isimaginaryconst(ep->v.p[0]->nodetype))
            {
                aa = 0.0;
                aai = ep->v.p[0]->v.f;
            }
            else
            {
                aa = ep->v.p[0]->v.c.r;
                aai = ep->v.p[0]->v.c.i;
            }
            pushfloatconst(nsize, aai);            
            pushfloatconst(nsize, aa);
            gen_code(op_void, 0, 0);
            switch (nsize) {
                case BESZ_CFLOAT:
                    return 8;
                case BESZ_CDOUBLE:
                    return BESZ_IDOUBLE;
                case BESZ_CLDOUBLE:
                    return 20;
                default:
                    DIAG("pushfloatconst: Invalid complex return size");
                    return 0;
            }
        }
#endif
    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 = BESZ_DWORD ;
            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 = BESZ_DWORD ;
            gen_code(op_push, ap, 0);
            gen_code(op_void, 0, 0);
            freeop(ap);
            break;
        case en_cfc:
        case en_fcomplexref:
            ap = gen_expr(ep, FALSE, TRUE, BESZ_CFLOAT);
            do_extend(ap, BESZ_CLDOUBLE, 0);
            gen_codes(op_sub, BESZ_DWORD , makedreg(ESP), make_immed(8));
            ap2 = make_stack(0);
            ap2->length = BESZ_FLOAT;
            gen_codef(op_fstp, ap2, 0);
            ap2 = make_stack(-4);
            ap2->length = BESZ_FLOAT;
            gen_codef(op_fstp, ap2, 0); 
            gen_codef(op_fwait, 0, 0);
            gen_code(op_void, 0, 0);
            freeop(ap);
            rv = 8;
            break;
        case en_crc:
        case en_rcomplexref:
            ap = gen_expr(ep, FALSE, TRUE, BESZ_CDOUBLE);
            do_extend(ap, BESZ_CLDOUBLE, 0);
            gen_codes(op_sub, BESZ_DWORD , makedreg(ESP), make_immed(16));
            ap2 = make_stack(0);
            ap2->length = BESZ_DOUBLE;
            gen_codef(op_fstp, ap2, 0);
            ap2 = make_stack(-8);
            ap2->length = BESZ_DOUBLE;
            gen_codef(op_fstp, ap2, 0); 
            gen_codef(op_fwait, 0, 0);
            gen_code(op_void, 0, 0);
            freeop(ap);
            rv = 16;
            break;
        case en_clrc:
        case en_lrcomplexref:
            ap = gen_expr(ep, FALSE, TRUE, BESZ_CLDOUBLE);
            do_extend(ap, BESZ_CLDOUBLE, 0);
            gen_codes(op_sub, BESZ_DWORD , makedreg(ESP), make_immed(20));
            ap2 = make_stack(0);
            ap2->length = BESZ_LDOUBLE;
            gen_codef(op_fstp, ap2, 0);
            ap2 = make_stack(-10);
            ap2->length = BESZ_LDOUBLE;
            gen_codef(op_fstp, ap2, 0); 
            gen_codef(op_fwait, 0, 0);
            gen_code(op_void, 0, 0);
            freeop(ap);
            rv = 20;
            break;
        case en_cfi:
        case en_fimaginaryref:
            ap = gen_expr(ep, FALSE, TRUE, BESZ_DWORD );
            do_extend(ap, BESZ_ILDOUBLE, F_FREG);
            gen_codes(op_sub, BESZ_DWORD , makedreg(ESP), make_immed(4));
            ap2 = make_stack(0);
            ap2->length = BESZ_FLOAT;
            gen_codef(op_fstp, ap2, 0);
            gen_codef(op_fwait, 0, 0);
            gen_code(op_void, 0, 0);
            rv = BESZ_DWORD ;
            freeop(ap);
            break;
        case en_cf:
        case en_floatref:
            ap = gen_expr(ep, FALSE, TRUE, BESZ_DWORD );
            do_extend(ap, BESZ_LDOUBLE, F_FREG);
            gen_codes(op_sub, BESZ_DWORD , makedreg(ESP), make_immed(4));
            ap2 = make_stack(0);
            ap2->length = BESZ_FLOAT;
            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:
            ap = gen_expr(ep, FALSE, TRUE, BESZ_DOUBLE);
            do_extend(ap, BESZ_LDOUBLE, F_FREG);
            gen_codes(op_sub, BESZ_DWORD , makedreg(ESP), make_immed(8));
            ap2 = make_stack(0);
            ap2->length = BESZ_DOUBLE;
            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_cri:
        case en_rimaginaryref:
            ap = gen_expr(ep, FALSE, TRUE, BESZ_DOUBLE);
            do_extend(ap, BESZ_ILDOUBLE, F_FREG);
            gen_codes(op_sub, BESZ_DWORD , makedreg(ESP), make_immed(8));
            ap2 = make_stack(0);
            ap2->length = BESZ_DOUBLE;
            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:
            ap = gen_expr(ep, FALSE, TRUE, BESZ_LDOUBLE);
            do_extend(ap, BESZ_LDOUBLE, F_FREG);
            gen_codes(op_sub, BESZ_DWORD , makedreg(ESP), make_immed(12));
            ap2 = make_stack(0);
            ap2->length = BESZ_LDOUBLE;
            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_clri:
        case en_lrimaginaryref:
            ap = gen_expr(ep, FALSE, TRUE, BESZ_LDOUBLE);
            do_extend(ap, BESZ_ILDOUBLE, F_FREG);
            gen_codes(op_sub, BESZ_DWORD , makedreg(ESP), make_immed(12));
            ap2 = make_stack(0);
            ap2->length = BESZ_LDOUBLE;
            gen_codef(op_fstp, ap2, 0);
            gen_codef(op_fwait, 0, 0);
            gen_code(op_void, 0, 0);
            rv = 12;
            freeop(ap);
            break;
#ifdef XXXXX
        case en_fcon:
        case en_fimaginarycon:
            rv = pushfloatconst(BESZ_FLOAT,ep->v.f);
            break;
        case en_rcon:
        case en_rimaginarycon:
            rv = pushfloatconst(BESZ_DOUBLE,ep->v.f);
            break;
        case en_lrcon:
        case en_lrimaginarycon:
            rv = pushfloatconst(BESZ_LDOUBLE,ep->v.f);
            break;

        case en_fcomplexcon:
            rv = 20;
            pushfloatconst(BESZ_CFLOAT,ep->v.c.i);
            pushfloatconst(BESZ_CFLOAT,ep->v.c.r);
            break;
        case en_rcomplexcon:
            rv = BESZ_CDOUBLE;
            pushfloatconst(BESZ_CDOUBLE,ep->v.c.i);
            pushfloatconst(BESZ_CDOUBLE,ep->v.c.r);
            break;
        case en_lrcomplexcon:
            rv = BESZ_CLDOUBLE;
            pushfloatconst(BESZ_CLDOUBLE,ep->v.c.i);
            pushfloatconst(BESZ_CLDOUBLE,ep->v.c.r);
            break;
#endif
        case en_cfp:
        case en_fp_ref:
            ap = gen_expr(ep, FALSE, TRUE,  BESZ_FARPTR);
            if (ap->mode == am_axdx)
            {
                gen_codes(op_push, BESZ_DWORD , makedreg(EDX), 0);
                gen_codes(op_push, BESZ_DWORD , makedreg(EAX), 0);
            }
            else if (ap->mode == am_dreg)
            {
                if (ap->seg == 0)
                    ap->seg = (i = defseg(ep->v.p[0]) ? i : DS);
                gen_push(ap->seg + 24, am_dreg, FALSE);
                gen_push(ap->preg, am_dreg, FALSE);
            }
            else
            {
                ap2 = copy_addr(ap);
                ap2->offset = makenode(en_add, ap2->offset, makeintnode(en_icon,
                    4));
                gen_codes(op_push, BESZ_DWORD , ap2, 0);
                gen_codes(op_push, BESZ_DWORD , ap, 0);
            }
            rv = 8;
            freeop(ap);
            break;
            break;
        case en_csp:
            if (!prm_farkeyword)
            {
                gen_codes(op_push, BESZ_DWORD , make_immed(0), 0);
            }
            else
            {
                ap = gen_expr(ep->v.p[0], FALSE, FALSE, BESZ_DWORD );
                freeop(ap);
                if (ap->mode != am_immed && ap->mode != am_seg)
                {
                    if ((ap->mode == am_indisp || ap->mode == am_indispscale ||
                        ap->mode == am_direct) && ap->length ==  BESZ_FARPTR)
                    {
                        ap->offset = makenode(en_add, ap->offset, makeintnode
                            (en_icon, 4));
                        ap->length = BESZ_DWORD ;
                    }
                    else if (ap->length ==  BESZ_FARPTR)
                    {
                        ap->mode = am_seg;
                    }
                    else
                    {
                        ap->length = BESZ_DWORD ;
                    }
                }
                gen_code(op_push, ap, 0);
            }
            rv = 4;
            break;
        default:
            ap = gen_expr(ep, FALSE, FALSE, size);
            if (ep->nodetype == en_thiscall && ep->v.p[0]->nodetype ==
                en_substack)
            {
                freeop(ap);
                rv = ep->v.p[0]->v.p[0]->v.p[0]->v.i; // assume an icon node
                break;
            }
            if (size == BESZ_QWORD || size ==  - BESZ_QWORD)
            {
                do_extend(ap, size, F_AXDX | F_MEM);
                if (ap->mode == am_axdx)
                {
                    gen_codes(op_push, BESZ_DWORD , makedreg(EDX), 0);
                    gen_codes(op_push, BESZ_DWORD , makedreg(EAX), 0);
                }
                else if (ap->mode == am_immed)
                {
                    #if sizeof(LLONG_TYPE) == 4
                        gen_codes(op_push, BESZ_DWORD , make_immed(ap->offset->v.i < 0 ? 
                            - 1: 0), 0);
                    #else 
                        gen_codes(op_push, BESZ_DWORD , make_immed(ap->offset->v.i >> 32),
                            0);
                    #endif 
                    gen_codes(op_push, BESZ_DWORD , make_immed(ap->offset->v.i), 0);
                }
                else
                {
                    ap2 = copy_addr(ap);
                    ap2->offset = makenode(en_add, ap2->offset, makeintnode
                        (en_icon, BESZ_DWORD ));
                    gen_codes(op_push, BESZ_DWORD , ap2, 0);
                    gen_codes(op_push, BESZ_DWORD , ap, 0);
                }
                rv = 8;
            }
            else if (size <= BESZ_BOOL)
            {
                while (castvalue(ep))
                    ep = ep->v.p[0];
                if (isbit(ep))
                    ap = bit_load(ap, ep);
                do_extend(ap, BESZ_DWORD , 0);
                gen_codes(op_push, BESZ_DWORD , ap, 0);
                rv = 4;
            }
            else if (size >= BESZ_CFLOAT)
            {
                int sz ;
                complexload(ap ,FALSE);
                rv = 8,sz = BESZ_FLOAT;
                if (size == BESZ_CDOUBLE)
                    rv = 16,sz = BESZ_DOUBLE;
                if (size == BESZ_CLDOUBLE)
                    rv = 24,sz = BESZ_LDOUBLE;
                gen_codes(op_sub, BESZ_DWORD , makedreg(ESP), make_immed(rv));
                ap2 = make_stack(0);
                ap2->length = sz;
                gen_codef(op_fstp, ap2, 0);
                ap2 = make_stack(-rv/2);
                ap2->length = sz ;
                gen_codef(op_fstp, ap2, 0);
                gen_codef(op_fwait, 0, 0);
            }
            else
            {
                floatload(ap, TRUE);
                rv = 8;
                if (size == BESZ_FLOAT || size == BESZ_IFLOAT)
                    rv = 4;
                if (size == BESZ_LDOUBLE || size == BESZ_IDOUBLE)
                    rv = 12;
                gen_codes(op_sub, BESZ_DWORD , 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,  *ap1;
    SYM *sp;
    int x;
    int sz = (ep->size + 3) &-4;
    int pushds = 0;
    if (!sz)
        return (0);
    if (sz > 24)
    {
        gen_codes(op_sub, BESZ_DWORD , makedreg(ESP), make_immed(sz));
        gen_codes(op_push, BESZ_DWORD , makedreg(ESI), 0);
        gen_codes(op_push, BESZ_DWORD , 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, BESZ_DWORD , ap1 = makedreg(ESI), ap);
                ap1->seg = ap->seg;

                break;
            case en_absacon:
                ep->v.i = ep->v.sp->value.i;
                ap = xalloc(sizeof(AMODE));
                ap->mode = am_direct;
                ap->seg = 0;
                ap->offset = ep; /* use as constant node */
                gen_codes(op_lea, BESZ_DWORD , ap1 = makedreg(ESI), ap);
                ap1->seg = ap->seg;
                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, BESZ_DWORD , ap1 = makedreg(ESI), ap);
                if (prm_farkeyword)
                    ap1->seg = SS;
                break;
            default:
                ep = makenode(en_a_ref, ep, 0);
                ap = gen_expr(ep, FALSE, FALSE, BESZ_DWORD );
                if (ap->mode == am_dreg)
                    gen_codes(op_mov, BESZ_DWORD , makedreg(ESI), ap);
                else
                {
                    gen_codes(op_lea, BESZ_DWORD , ap1 = makedreg(ESI), ap);
                    ap1->seg = ap->seg;
                }
                if (ap->length ==  BESZ_FARPTR)
                {
                    AMODE *ap3 = copy_addr(ap);
                    AMODE *ap4 = xalloc(sizeof(AMODE));
                    ap4->mode = am_seg;
                    ap4->seg = 0;
                    ap3->offset = makenode(en_add, ap3->offset, makeintnode
                        (en_icon, 4));
                    pushds = TRUE;
                    gen_push(DS + 24, am_dreg, FALSE);
                    gen_codes(op_mov, 2, ap4, ap3);
                }
                break;
        }
        gen_codes(op_lea, BESZ_DWORD , ap1 = makedreg(EDI), make_stack( - 8));
        if (prm_farkeyword)
            ap1->seg = SS;
        freeop(ap);
        if (prm_farkeyword)
        {
            gen_push(SS + 24, am_dreg, 0);
            gen_pop(ES + 24, am_dreg, 0);
        }
        if (regs[1])
            gen_push(ECX, am_dreg, 0);
        gen_code(op_cld, 0, 0);
        gen_codes(op_mov, BESZ_DWORD , 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);
        if (pushds)
            gen_pop(DS + 24, am_dreg, FALSE);
        gen_codes(op_pop, BESZ_DWORD , makedreg(EDI), 0);
        gen_codes(op_pop, BESZ_DWORD , 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 = 0;
                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:
                ep = makenode(en_a_ref, ep, 0);
                ap = gen_expr(ep, 0, FALSE, BESZ_DWORD );
                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, BESZ_DWORD , 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)
    {
		int l;
        if (plist->nodetype == en_stackblock)
            l = push_stackblock(plist->v.p[0]);
        else
            l = push_param(plist->v.p[0], natural_size(plist->v.p[0]));
		i += l;
		last_align -= l;
		if (last_align < 0)
			last_align -= 16 * (last_align/16 - 1);
        plist = plist->v.p[1];
    }
    return i;
}

int parmsize(ENODE *plist)
{
    int i;
    i = 0;
    while (plist != 0)
    {
        if (plist->nodetype == en_stackblock)
		{
            i += (plist->size + 3) & -4;
		}
        else
		{
			int size = natural_size(plist->v.p[0]);
		    switch (plist->nodetype)
    		{
				
        		case en_absacon:
					i += 4;
					break;
		        case en_napccon:
        		case en_nacon:
		        case en_labcon:
        		case en_nalabcon:
					i += 4;
					break;
		        case en_cfc:
        		case en_fcomplexref:
					i += 8;
					break;
		        case en_crc:
        		case en_rcomplexref:
					i += 16;
		            break;
		        case en_clrc:
        		case en_lrcomplexref:
					i += 20;
					break;
		        case en_cfi:
        		case en_fimaginaryref:
					i += 4;
		            break;
		        case en_cf:
        		case en_floatref:
					i += 4;
					break;
		        case en_cd:
        		case en_doubleref:
					i += 8;
					break;
		        case en_cri:
        		case en_rimaginaryref:
					i += 8;
					break;
		        case en_cld:
        		case en_longdoubleref:
					i += 12;
					break;
		        case en_clri:
        		case en_lrimaginaryref:
					i += 12;
					break;
		        case en_cfp:
        		case en_fp_ref:
					i += 8;
					break;
		        case en_csp:
					i += 4;
		            break;
        		default:
		            if (plist->nodetype == en_thiscall && plist->v.p[0]->nodetype ==
        		        en_substack)
		            {
                		i += plist->v.p[0]->v.p[0]->v.p[0]->v.i; // assume an icon node
		                break;
        		    }
		            if (size == BESZ_QWORD || size ==  - BESZ_QWORD)
        		    {
                		i += 8;
            		}
		            else if (size <= BESZ_BOOL)
        		    {
						i += 4;
		            }
		            else if (size >= BESZ_CFLOAT)
        		    {
						if (size == BESZ_CDOUBLE)
							i += 16;
						else if (size == BESZ_CLDOUBLE)
							i += 24;
						else
							i += 8;
					}
		            else
        		    {
						
		                if (size == BESZ_FLOAT || size == BESZ_IFLOAT)
        		            i += 4;
                		else if (size == BESZ_LDOUBLE || size == BESZ_IDOUBLE)
                    		i += 12;
						else 
							i += 8;
		            }
		            break;
    		}
		}
        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;
    int regfs, reggs, reges;
    regax = regs[0];
    regcx = regs[1];
    regdx = regs[2];
    regfs = sregs[0];
    reggs = sregs[1];
    reges = sregs[2];
    if (regfs)
        gen_push(FS + 24, am_dreg, 0);
    if (reggs)
        gen_push(GS + 24, am_dreg, 0);
    if (reges)
        gen_push(ES + 24, am_dreg, 0);
    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;
    sregs[0] = sregs[1] = sregs[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;
    sregs[0] = regfs;
    regs[1] = reggs;
    regs[2] = reges;
    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);
    if (reges)
        gen_pop(ES + 24, am_dreg, 0);
    if (reggs)
        gen_pop(GS + 24, am_dreg, 0);
    if (regfs)
        gen_pop(FS + 24, am_dreg, 0);
    return result;
}

//-------------------------------------------------------------------------

AMODE *inlinecall(ENODE *node)
{
    ENODE *nameref = node,  *thisn = 0;
    SYM *sp;
    int size;
    int dregs[3];
    int selreg;
    int i;
    memcpy(dregs, regs, sizeof(dregs));
    if (nameref->nodetype == en_thiscall)
    {
        thisn = nameref->v.p[0];
        nameref = nameref->v.p[1];
    }

    if (nameref->nodetype == en_callblock || nameref->nodetype == en_scallblock)
    {
        size = 4;
        nameref = nameref->v.p[1];
    }
    else
        size = nameref->v.p[0]->v.i;
    nameref = nameref->v.p[1]->v.p[0]->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;
            genning_inline++;
            if (size == BESZ_QWORD || size ==  - BESZ_QWORD)
                tempaxdx();
            currentfunc = sp;
            retlab = nextlabel++;
            genstmt(sp->value.classdata.inlinefunc->stmt);
            genreturn(0, 3);
            genning_inline--;
            selreg = 0;
            for (i = 0; i < 3; i++)
                dregs[i] -= regs[i];
            for (i = 0; i < 3; i++)
                if (dregs[i] < dregs[selreg])
                    selreg = i;
            if (size >= 100)
            {
                ap = makedreg(selreg);
                ;
                ap->length = size - 100000;
                ap->mode = am_indisp;
            }
            else if (size ==  BESZ_FARPTR)
            {
                ap = makedreg(EDX);
                gen_code(op_push, ap, 0);
                ap->mode = am_seg;
                ap->seg = FS;
                gen_code(op_pop, ap, 0);
                ap->preg = EAX;
                ap->mode = am_dreg;
                ap->length =  BESZ_FARPTR;
            }
            else if (size == BESZ_QWORD || size ==  - BESZ_QWORD)
            {
                ap = xalloc(sizeof(AMODE));
                ap->length = size < 0 ?  - BESZ_QWORD: BESZ_QWORD;
                ap->mode = am_axdx;
                regs[0]++;
                regs[2]++;
            }
            else if (size > BESZ_QWORD && size < BESZ_CFLOAT)
            {
                ap = fstack();
                ap->length = size;
            }
            else if (size >= BESZ_CFLOAT)
            {
                ap = fstack();
                ap->mode = am_frfr;
                ap->length = BESZ_CLDOUBLE;
            }
            else
            {
                if (size != 0)
                {
                    ap = makedreg(selreg);
                    ap->length = size;
                }
                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,  *app = 0;
	OCODE *sa;
    ENODE *pushthis = 0;
	int save_last_align;
	int parm_size = 0, relsize = 0;
    int refret = FALSE;
    int i = 0, siz1;
    int regax, regdx, regcx;
    int regfs, reggs, reges;
    if (ap = inlinecall(node))
        return ap;
    if (node->nodetype != en_callblock && node->nodetype != en_scallblock)
        if (ap = HandleIntrins(node, novalue))
            return ap;
        if (node->nodetype == en_thiscall)
        {
            pushthis = node->v.p[0];
            node = node->v.p[1];
            i = 4;
        }
    if (node->nodetype == en_callblock || node->nodetype == en_scallblock)
    {
        siz1 = 4;
    }
    else
    {
        siz1 = node->v.p[0]->v.i;
        if (siz1 > 100)
        {
            siz1 -= 100000;
            refret = TRUE;
        }
    }
    regax = regs[0];
    regcx = regs[1];
    regdx = regs[2];
    regfs = sregs[0];
    reggs = sregs[1];
    reges = sregs[2];
	if (prm_stackalign)
	{
		save_last_align = last_align;
		gen_code(op_add, makedreg(ESP), make_immed(0)); // will be filled in later
		sa = peep_tail;
	}
    if (regfs)
	{
        gen_push(FS + 24, am_dreg, 0);
		parm_size += 4;
	}
    if (reggs)
	{
        gen_push(GS + 24, am_dreg, 0);
		parm_size += 4;
	}
    if (reges)
	{
        gen_push(ES + 24, am_dreg, 0);
		parm_size += 4;
	}
    if ((siz1 == BESZ_QWORD || siz1 ==  - BESZ_QWORD) && (regax && regdx))
        tempaxdx();
    else
    {
        if (regdx)
		{
            gen_push(EDX, am_dreg, 0);
			parm_size += 4;
		}
        if (regax)
		{
            gen_push(EAX, am_dreg, 0);
			parm_size += 4;
		}
    }
    if (regcx)
        gen_push(ECX, am_dreg, 0);
    regs[0] = regs[1] = regs[2] = 0;
    sregs[0] = sregs[1] = sregs[2] = 0;
    set_func_mode(1);
    if (pushthis && pushthis->nodetype == en_substack)
        app = gen_expr(pushthis, FALSE, TRUE, BESZ_DWORD );
    if (node->nodetype == en_callblock || node->nodetype == en_scallblock)
    {
		if (prm_stackalign)
		{
			int l;
			parm_size += 4 + parmsize(node->v.p[1]->v.p[1]->v.p[1]->v.p[0]);
			l = 16 - parm_size % 16;
			l = (l + 8 + last_align) % 16;
			relsize = l;
			last_align = 16 - l;
		}
       	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, BESZ_DWORD );
        gen_codes(op_push, BESZ_DWORD , ap, 0);
        i += 4;
        node = node->v.p[1];
        freeop(ap);
    }
    else
    {
		if (prm_stackalign)
		{
			int l;
			parm_size += parmsize(node->v.p[1]->v.p[1]->v.p[0]);
			l = 16 - parm_size % 16;
			l = (l + 8 + last_align) % 16;
			relsize = l;
			last_align = 16 - l;
		}
        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)
    {
        if (!app)
            app = gen_expr(pushthis, FALSE, TRUE, BESZ_DWORD );
        gen_codes(op_push, BESZ_DWORD , app, 0);
        freeop(app);
    }

    if (node->v.p[1]->v.p[0]->v.p[0]->nodetype == en_nacon || node->v.p[1]
        ->v.p[0]->v.p[0]->nodetype == en_napccon)
    {
        SYM *sp = node->v.p[1]->v.p[0]->v.p[0]->v.sp;
        if (sp->inreg)
        {
            ap = makedreg(sp->value.i);
        }
        else
        {
            node->v.p[1]->v.p[0]->v.p[0]->v.sp = sp;
            ap = make_offset(node->v.p[1]->v.p[0]->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]->v.p[0], FALSE, FALSE, BESZ_DWORD );
        freeop(ap);
        if (ap->mode == am_axdx)
        {
            AMODE *ap1 = floatconvpos();
            AMODE *ap2 = copy_addr(ap1);
            ap2->offset = makenode(en_add, ap2->offset, makeintnode(en_icon, 4))
                ;
            gen_codes(op_mov, BESZ_DWORD , ap2, makedreg(EDX));
            gen_codes(op_mov, BESZ_DWORD , ap1, makedreg(EAX));
            gen_codes(op_call, BESZ_BEFARPTR, ap1, 0);
        }
        else
            gen_codes(op_call, ap->length ==  BESZ_FARPTR ? BESZ_BEFARPTR : BESZ_DWORD , 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, BESZ_DWORD , makedreg(ECX), 0);
        else
            gen_code(op_add, makedreg(ESP), make_immed(i));
    }
    regs[0] = regax;
    regs[1] = regcx;
    regs[2] = regdx;
    sregs[0] = regfs;
    sregs[1] = reggs;
    sregs[2] = reges;
    set_func_mode(0);
    if (refret)
    {
        result = temp_data();
        result->length = siz1;
        if (result->preg != EAX)
            gen_codes(op_mov, siz1, result, makedreg(EAX));
        result->mode = am_indisp;
    }
    else if (siz1 ==  BESZ_FARPTR)
    {
        result = makedreg(EDX);
        gen_code(op_push, result, 0);
        result->mode = am_seg;
        result->seg = FS;
        gen_code(op_pop, result, 0);
        result->preg = EAX;
        result->mode = am_dreg;
        result->length =  BESZ_FARPTR;
    }
    else if (siz1 == BESZ_QWORD || siz1 ==  - BESZ_QWORD)
    {
        result = xalloc(sizeof(AMODE));
        result->length = siz1 < 0 ?  - BESZ_QWORD: BESZ_QWORD;
        result->mode = am_axdx;
        regs[0]++;
        regs[2]++;
    }
    else if (siz1 > BESZ_QWORD && siz1 < BESZ_CFLOAT)
    {
        result = fstack();
        result->length = siz1;
        if (novalue)
            gen_codefs(op_fstp,BESZ_LDOUBLE,floatconvpos(),0); // avoid exceptions
    }
    else if (siz1 >= BESZ_CFLOAT)
    {
        result = fstack();
        result->mode = am_frfr;
        result->length = BESZ_CLDOUBLE;
        if (novalue) 
        {
            gen_codefs(op_fstp,BESZ_LDOUBLE,floatconvpos(),0); // avoid exceptions
            gen_codefs(op_fstp,BESZ_LDOUBLE,floatconvpos(),0); // avoid exceptions
        }
    }
    else
    {
        if (siz1 != 0)
        {
            result = temp_data();
            result->length = siz1;
            if (result->preg != EAX)
                gen_codes(op_mov, siz1, result, makedreg(EAX));
        }
        else
            result = makedreg(EAX);
    }
    if (regcx)
        gen_pop(ECX, am_dreg, 0);
    if (siz1 !=  - BESZ_QWORD && siz1 != BESZ_QWORD)
    {
        if (regax)
            gen_pop(EAX, am_dreg, 0);
        if (regdx)
            gen_pop(EDX, am_dreg, 0);
    }
    if (reges)
        gen_pop(ES + 24, am_dreg, 0);
    if (reggs)
        gen_pop(GS + 24, am_dreg, 0);
    if (regfs)
        gen_pop(FS + 24, am_dreg, 0);
	if (prm_stackalign)
	{
		if (relsize)
		{
			sa->oper2->offset->v.i = -relsize;
	        if (relsize == 4)
    	        gen_codes(op_pop, BESZ_DWORD , makedreg(ECX), 0);
        	else
				gen_code(op_add, makedreg(ESP), make_immed(relsize));
		}
		else
			remove_peep_entry(sa);
		last_align = save_last_align;
	}

    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];
        if (node->nodetype == en_thiscall)
        {
            pushthis = node->v.p[0];
            node = node->v.p[1];
            i = 4;
        }
    ap1 = gen_expr(onode->v.p[0]->v.p[0], FALSE, FALSE, BESZ_DWORD );
    gen_codes(op_mov, BESZ_DWORD , cx = makedreg(ECX), ap1);
    if (pushthis)
    {
        AMODE *ap2 = gen_expr(pushthis, FALSE, TRUE, BESZ_DWORD );
        gen_codes(op_mov, BESZ_DWORD , ax = makedreg(EAX), ap2);
        freeop(ap2);
    }
    gen_label(lab = nextlabel++);

    gen_codes(op_push, BESZ_DWORD , cx, 0);
    gen_codes(op_push, BESZ_DWORD , ax, 0);

    if (node->v.p[1]->v.p[0]->v.p[0]->nodetype == en_nacon || node->v.p[1]
        ->v.p[0]->v.p[0]->nodetype == en_napccon)
    {
        SYM *sp = node->v.p[1]->v.p[0]->v.p[0]->v.sp;
        if (sp->inreg)
        {
            ap = makedreg(sp->value.i);
        }
        else
        {
            node->v.p[1]->v.p[0]->v.p[0]->v.sp = sp;
            ap = make_offset(node->v.p[1]->v.p[0]->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]->v.p[0], FALSE, FALSE, BESZ_DWORD );
        freeop(ap);

        gen_codes(op_call, BESZ_DWORD , ap, 0);
    }
    gen_codes(op_pop, BESZ_DWORD , ax, 0);
    gen_codes(op_pop, BESZ_DWORD , cx, 0);
    gen_codes(op_add, BESZ_DWORD , 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,  *app = 0;
    int i = 0, siz1;
    int refret = FALSE;
    ENODE *invnode = 0,  *anode;
    ENODE *pushthis = 0;
    int regax, regdx, regcx;
    int regfs, reggs, reges;
    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];
    }
        if (node->nodetype == en_thiscall)
        {
            pushthis = node->v.p[0];
            node = node->v.p[1];
            i = 4;
        }
    if (node->nodetype == en_pcallblock || node->nodetype == en_scallblock)
    {
        siz1 = 4;
    }
    else
    {
        if (siz1 > 100)
        {
            siz1 -= 100000;
            refret = TRUE;
        }
        siz1 = node->v.p[0]->v.i;
    }
    regax = regs[0];
    regcx = regs[1];
    regdx = regs[2];
    regfs = sregs[0];
    reggs = sregs[1];
    reges = sregs[2];
    set_func_mode(1);
    if (regfs)
        gen_push(FS + 24, am_dreg, 0);
    if (reggs)
        gen_push(GS + 24, am_dreg, 0);
    if (reges)
        gen_push(ES + 24, am_dreg, 0);
    if ((siz1 == BESZ_QWORD || siz1 ==  - BESZ_QWORD) && (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;
    sregs[0] = sregs[1] = sregs[2] = 0;
    if (pushthis)
    {
        app = gen_expr(pushthis, FALSE, TRUE, BESZ_DWORD );
        gen_codes(op_push, BESZ_DWORD , app, 0);
        freeop(app);
    }
    if (node->nodetype == en_pcallblock || node->nodetype == en_scallblock)
    {
        ap = gen_expr(node->v.p[0], FALSE, FALSE, BESZ_DWORD );
        gen_codes(op_push, BESZ_DWORD , 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]->v.p[0]->nodetype == en_nacon || node->v.p[1]
        ->v.p[0]->v.p[0]->nodetype == en_napccon)
    {
        SYM *sp = node->v.p[1]->v.p[0]->v.p[0]->v.sp;
        if (sp->inreg)
        {
            ap = makedreg(sp->value.i);
        }
        else
        {
            node->v.p[1]->v.p[0]->v.p[0]->v.sp = sp;
            ap = make_offset(node->v.p[1]->v.p[0]->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]->v.p[0], FALSE, FALSE, BESZ_DWORD );
        freeop(ap);
        if (ap->mode == am_axdx)
        {
            AMODE *ap1 = floatconvpos();
            AMODE *ap2 = copy_addr(ap1);
            ap2->offset = makenode(en_add, ap2->offset, makeintnode(en_icon, 4))
                ;
            gen_codes(op_mov, BESZ_DWORD , ap2, makedreg(EDX));
            gen_codes(op_mov, BESZ_DWORD , ap1, makedreg(EAX));
            gen_codes(op_call, BESZ_BEFARPTR, ap1, 0);
        }
        else
            gen_codes(op_call, ap->length ==  BESZ_FARPTR ? BESZ_BEFARPTR : BESZ_DWORD , ap, 0);
    }
    regs[0] = regax;
    regs[1] = regcx;
    regs[2] = regdx;
    sregs[0] = regfs;
    sregs[1] = reggs;
    sregs[2] = reges;
    set_func_mode(0);
    if (refret)
    {
        result = temp_data();
        result->length = siz1;
        if (result->preg != EAX)
            gen_codes(op_mov, siz1, result, makedreg(EAX));
        //               result->mode = am_indisp ;
    }
    else if (siz1 ==  BESZ_FARPTR)
    {
        result = makedreg(EDX);
        gen_code(op_push, result, 0);
        result->mode = am_seg;
        result->seg = FS;
        gen_code(op_pop, result, 0);
        result->preg = EAX;
        result->mode = am_dreg;
        result->length =  BESZ_FARPTR;
    }
    else if (siz1 ==  - BESZ_QWORD || siz1 == BESZ_QWORD)
    {
        result = xalloc(sizeof(AMODE));
        result->length = siz1 < 0 ?  - BESZ_QWORD: BESZ_QWORD;
        ;
        result->mode = am_axdx;
        regs[0]++;
        regs[2]++;
    }
    else if (siz1 > BESZ_QWORD && siz1 < BESZ_CFLOAT)
    {
        result = fstack();
        result->length = siz1;
        if (novalue)
            gen_codefs(op_fstp,BESZ_LDOUBLE,floatconvpos(),0); // avoid exceptions
    }
    else if (siz1 >= BESZ_CFLOAT)
    {
        result = fstack();
        result->mode = am_frfr;
        result->length = BESZ_CLDOUBLE;
        if (novalue)
        {
            gen_codefs(op_fstp,BESZ_LDOUBLE,floatconvpos(),0); // avoid exceptions
            gen_codefs(op_fstp,BESZ_LDOUBLE,floatconvpos(),0); // avoid exceptions
        }
    }
    else
    {
        if (siz1 != 0)
        {
            result = temp_data();
            result->length = siz1;
            if (result->preg != EAX)
                gen_codes(op_mov, siz1, result, makedreg(EAX));
        }
        else
            result = makedreg(EAX);
    }
    if (regcx)
        gen_pop(ECX, am_dreg, 0);
    if (siz1 != BESZ_QWORD && siz1 !=  - BESZ_QWORD)
    {
        if (regax)
            gen_pop(EAX, am_dreg, 0);
        if (regdx)
            gen_pop(EDX, am_dreg, 0);
    }
    if (reges)
        gen_pop(ES + 24, am_dreg, 0);
    if (reggs)
        gen_pop(GS + 24, am_dreg, 0);
    if (regfs)
        gen_pop(FS + 24, 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, BESZ_DWORD , 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:
            ap1 = gen_expr(node->v.p[0], novalue, adronly, natural_size(node
                ->v.p[0]));
                
//            if (ap1->length == BESZ_FLOAT || ap1->length == BESZ_IFLOAT)
//            {
//            }
            /* else*/ if (ap1->length > BESZ_FLOAT && ap1->length <=BESZ_LDOUBLE /*< BESZ_CFLOAT*/)
            {
                if (!adronly)
                    ap1 = truncateFloat(ap1, BESZ_FLOAT);
            }
            else
                if (!adronly)
                    do_extend(ap1, size, F_VOL);
            return ap1;
        case en_cfi:
            ap1 = gen_expr(node->v.p[0], novalue, adronly, natural_size(node
                ->v.p[0]));
//            if (ap1->length == BESZ_FLOAT || ap1->length == BESZ_IFLOAT)
//            {
//            }
            /*else */if (ap1->length > /*BESZ_FLOAT*/BESZ_IFLOAT && ap1->length <= BESZ_ILDOUBLE /*< BESZ_CFLOAT*/)
            {
                if (!adronly)
                    ap1 = truncateFloat(ap1, BESZ_IFLOAT);
            }
            else
                if (!adronly)
                    do_extend(ap1, size, F_VOL);
            return ap1;
        case en_cd:
            ap1 = gen_expr(node->v.p[0], novalue, adronly, natural_size(node
                ->v.p[0]));
//            if (ap1->length == BESZ_DOUBLE || ap1->length == BESZ_IDOUBLE)
//            {
//            }
            /*else*/ if (ap1->length == BESZ_FLOAT /*|| ap1->length == BESZ_IFLOAT*/)
            {
                if (!adronly)
                {
                    ap1->length = BESZ_FLOAT;
                    do_extend(ap1, size, F_VOL);
                }
            }
            else if (ap1->length == BESZ_LDOUBLE  /*|| ap1->length == BESZ_ILDOUBLE*/)
            {
                if (!adronly)
                {
                    ap1->length = BESZ_LDOUBLE;
                    ap1 = truncateFloat(ap1, BESZ_DOUBLE);
                }
            }
            else
                if (!adronly)
                    do_extend(ap1, size, F_VOL);
            return ap1;
        case en_cri:
            ap1 = gen_expr(node->v.p[0], novalue, adronly, natural_size(node
                ->v.p[0]));
//            if (ap1->length == BESZ_DOUBLE || ap1->length == BESZ_IDOUBLE)
//            {
//            }
            /*else*/ if (/*ap1->length == BESZ_FLOAT ||*/ ap1->length == BESZ_IFLOAT)
            {
                if (!adronly)
                {
                    ap1->length = BESZ_IFLOAT;
                    do_extend(ap1, size, F_VOL);
                }
            }
            else if (/*ap1->length == BESZ_LDOUBLE ||*/ ap1->length == BESZ_ILDOUBLE)
            {
                if (!adronly)
                {
                    ap1->length = BESZ_ILDOUBLE;
                    ap1 = truncateFloat(ap1, BESZ_IDOUBLE);
                }
            }
            else
                if (!adronly)
                    do_extend(ap1, size, F_VOL);
            return ap1;
        case en_cld:
            ap1 = gen_expr(node->v.p[0], novalue, adronly, natural_size(node
                ->v.p[0]));
//            if (ap1->length == BESZ_LDOUBLE || ap1->length == BESZ_ILDOUBLE)
//            {
//            }
            /* else */ if (ap1->length >= BESZ_FLOAT && ap1->length < BESZ_LDOUBLE/*< BESZ_CFLOAT*/)
            {
                if (!adronly)
                {
                    ap1->length = ap1->length == BESZ_FLOAT ? BESZ_FLOAT : BESZ_DOUBLE ; //(ap1->length == BESZ_FLOAT || ap1->length == BESZ_IFLOAT) ? BESZ_FLOAT : BESZ_DOUBLE;
                    do_extend(ap1, size, F_VOL);
                }
            }
            else if (!adronly)
                do_extend(ap1, natural_size(node), F_VOL);
            return ap1;
        case en_clri:
            ap1 = gen_expr(node->v.p[0], novalue, adronly, natural_size(node
                ->v.p[0]));
//            if (ap1->length == BESZ_LDOUBLE || ap1->length == BESZ_ILDOUBLE)
//            {
//            }
            /* else */ if (ap1->length >= BESZ_IFLOAT/*BESZ_FLOAT*/ && ap1->length < BESZ_ILDOUBLE /*< BESZ_CFLOAT*/)
            {
                if (!adronly)
                {
                    ap1->length = ap1->length == BESZ_IFLOAT ? BESZ_IFLOAT : BESZ_IDOUBLE ; //(ap1->length == BESZ_FLOAT || ap1->length == BESZ_IFLOAT) ? BESZ_IFLOAT : BESZ_IDOUBLE;
                    do_extend(ap1, size, F_VOL);
                }
            }
            else if (!adronly)
                do_extend(ap1, natural_size(node), F_VOL);
            return ap1;
        case en_csp:
            if (!prm_farkeyword)
            {
                ap1 = make_immed(0);
            }
            else
            {
                ap1 = gen_expr(node->v.p[0], FALSE, FALSE, BESZ_DWORD );

                if ((ap1->mode != am_immed) && (ap1->mode != am_seg))
                {
                    if ((ap1->mode == am_indisp || ap1->mode == am_indispscale 
                        || ap1->mode == am_direct) && ap1->length ==  BESZ_FARPTR)
                    {
                        ap1->offset = makenode(en_add, ap1->offset, makeintnode
                            (en_icon, 4));
                        freeop(ap1);
                        ap1->length = BESZ_WORD;
                        do_extend(ap1, BESZ_DWORD , F_DREG | F_VOL);
                    }
                    else if (ap1->length ==  BESZ_FARPTR)
                    {
                        int seg = ap1->seg;
                        ap1->length = BESZ_DWORD ;
                        ap1->seg = 0;
                        freeop(ap1);
                        ap1->mode = am_seg;
                        ap1->seg = seg;
                    }
                }
            }
            return ap1;
        case en_cfp:
            ap1 = gen_expr(node->v.p[0], novalue, adronly, natural_size(node
                ->v.p[0]));
            if (!adronly && !(ap1->mode == am_axdx && natural_size(node) ==  -
                11))
                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_ci:
		case en_cui:
        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;
			ap1 = xalloc(sizeof(AMODE));
			ap1->mode = am_immed;
			ap1->offset = node;
			return ap1;
        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, BESZ_DWORD , ap1, ap2);
            ap1->seg = defseg(node);
            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:
        case en_boolcon:
        case en_cucon:
            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 = 0;
            ap2->offset = node; /* use as constant node */
            gen_codes(op_lea, BESZ_DWORD , ap1, ap2);
            ap1->seg = ap2->seg;
            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;
                //												if (i > 0 && (currentfunc->value.classdata.cppflags & PF_MEMBER) &&
                //															!(currentfunc->value.classdata.cppflags & PF_STATIC))
                //													i += 4;
            ap2->offset = makeintnode(en_icon, i);
            gen_codes(op_lea, BESZ_DWORD , ap1, ap2);
            if (prm_farkeyword)
                ap1->seg = SS;
            return ap1; /* return reg */
        case en_substack:
            ap1 = gen_expr(node->v.p[0], FALSE, FALSE, BESZ_DWORD );
            if (ap1->mode == am_immed && (ap1->offset->v.i < 4096))
            {
                if (ap1->offset->v.i < 0)
                    ap1->offset->v.i -= stackadd;
                else
                    ap1->offset->v.i += stackadd;
                ap1->offset->v.i &= stackmod;
                gen_codes(op_sub, BESZ_DWORD , makedreg(ESP), ap1);
            }
            else
            {
                gen_codes(op_mov, BESZ_DWORD , makedreg(ECX), ap1);
                call_library("___substack");
            }
            ap1 = temp_data();
            gen_codes(op_mov, BESZ_DWORD , ap1, makedreg(ESP));
            return ap1;
		case en_loadstack:
            ap1 = gen_expr(node->v.p[0], FALSE, FALSE, BESZ_DWORD );
			gen_codes(op_mov, BESZ_DWORD, makedreg(ESP), ap1);
			return ap1;
		case en_savestack:
            ap1 = gen_expr(node->v.p[0], FALSE, FALSE, BESZ_DWORD );
			gen_codes(op_mov, BESZ_DWORD, ap1, makedreg(ESP));
			return ap1;
        case en_structret:
            ap1 = xalloc(sizeof(AMODE));
            ap1->preg = EBP;
            ap1->mode = am_indisp;
            if ((currentfunc->pascaldefn || currentfunc->isstdcall) &&
                currentfunc->tp->lst.head && currentfunc->tp->lst.head != (SYM*)
                - 1)
                ap1->offset = makeintnode(en_icon, (currentfunc->tp->lst.head
                    ->value.i + ((currentfunc->tp->lst.head->tp->size + 3)
                    &0xFFFFFFFCL)));
            else
                    if (declclass && !(currentfunc->value.classdata.cppflags
                        &PF_STATIC))
                        ap1->offset = makeintnode(en_icon, 12+(currentfunc
                            ->farproc *4));
                    else
                    ap1->offset = makeintnode(en_icon, 8+(currentfunc->farproc
                        *4));
            ap2 = temp_data();
			if (ap2-> preg != 0)
				DIAG("gen_expr:  EAX not used for structured return");
            gen_codes(op_mov, BESZ_DWORD , ap2, ap1);
            return ap2;
        case en_fp_ref:
        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_a_ref:
		case en_ua_ref:
		case en_i_ref:
		case en_ui_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, BESZ_DWORD );
        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->seg = (node->v.i >> 8) & 0xff;
                ap1->tempflag = 1;
            }
            else
            if ((node->v.i &0xff) < 24)
            {
                ap1->mode = am_dreg;
                ap1->preg = (node->v.i &0xff) - 12;
            }
            else if ((node->v.i &0xff) < 32)
            {
                ap1->mode = am_seg;
                ap1->seg = (node->v.i &0xff) - 24+1;
            }
            else if ((node->v.i &0xff) >= 64)
            {
                ap1->mode = am_streg;
                ap1->preg = (node->v.i &0xff) - 64;
            }
            else if ((node->v.i &0xff) >= 56)
            {
                ap1->mode = am_sdreg;
                ap1->preg = (node->v.i &0xff) - 56;
            }
            else if ((node->v.i &0xff) >= 48)
            {
                ap1->mode = am_screg;
                ap1->preg = (node->v.i &0xff) - 48;
            }
            else
            {
                ap1->mode = am_freg;
                ap1->preg = (node->v.i &0xff) - 32;
            }
            ap1->tempflag = 0; /* not a temporary */
            ap1->length = (node->v.i >> 16);
            if (ap1->mode != am_seg)
                ap1->seg = (node->v.i >> 8) &0xff;
            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:
		case en_array:
            return gen_binary(node, op_add, op_faddp, op_fadd, op_faddp,
                op_fadd, size);
        case en_addcast:
            ap1 = gen_expr(node->v.p[0], FALSE, FALSE, size);
            do_extend(ap1, BESZ_DWORD , F_DREG | F_VOL);
            gen_codes(op_test, BESZ_DWORD , ap1, ap1);
            lab0 = nextlabel++;
            gen_branch(op_je, make_label(lab0));
            ap2 = gen_expr(node->v.p[1], FALSE, FALSE, size); 
                // will always be constant
            gen_codes(op_add, BESZ_DWORD , ap1, ap2);
            gen_label(lab0);
            return ap1;
        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:
		case en_arrayindex:
            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_clearblock:
            return gen_clearblock(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, BESZ_DWORD ); /* 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_dvoid:
            ap1 = gen_expr(node->v.p[0], TRUE, FALSE, natural_size(node));
            gen_expr(node->v.p[1], TRUE, FALSE, natural_size(node));
            return ap1;
        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);
        case en_conslabel:
            if (node->v.p[1]->v.sp->nullsym)
                return 0;
            node->v.p[1]->v.sp->value.classdata.conslabel = lab0 = nextlabel++;
            ap1 = gen_expr(node->v.p[0], novalue, adronly, size);
            gen_label(lab0);
            return ap1;
        case en_destlabel:
            if (node->v.p[1]->v.sp->nullsym)
                return 0;
            node->v.p[1]->v.sp->value.classdata.destlabel = nextlabel;
            gen_label(nextlabel++);
            return gen_expr(node->v.p[0], novalue, adronly, size);
        case en_movebyref:
             /* explicitly uncoded */
        default:
            DIAG("uncoded node in gen_expr.");
            return makedreg(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_substack:
        case en_structret:
		case en_loadstack:
		case en_savestack:
            return BESZ_DWORD ;
        case en_bits:
        case en_cl_reg:
            return natural_size(node->v.p[0]);
        case en_icon:
        case en_lcon:
            return  - BESZ_DWORD ;
        case en_lucon:
        case en_iucon:
            return BESZ_DWORD ;
        case en_boolcon:
            return BESZ_BOOL;
        case en_llcon:
            return  - BESZ_QWORD;
        case en_llucon:
            return BESZ_QWORD;
        case en_ccon:
        case en_cucon:
            return BESZ_DWORD ;
        case en_rcon:
        case en_doubleref:
            return BESZ_DOUBLE;
        case en_lrcon:
        case en_longdoubleref:
            return BESZ_LDOUBLE;
        case en_fcon:
        case en_floatref:
            return BESZ_FLOAT;
        case en_fimaginaryref:
        case en_fimaginarycon:
        case en_cfi:
            return BESZ_IFLOAT;
        case en_rimaginaryref:
        case en_rimaginarycon:
        case en_cri:
            return BESZ_IDOUBLE;
        case en_lrimaginaryref:
        case en_lrimaginarycon:
        case en_clri:
            return BESZ_ILDOUBLE;
        case en_fcomplexref:
        case en_fcomplexcon:
        case en_cfc:
            return BESZ_CFLOAT;
        case en_rcomplexref:
        case en_rcomplexcon:
        case en_crc:
            return BESZ_CDOUBLE;
        case en_lrcomplexref:
        case en_lrcomplexcon:
        case en_clrc:
            return BESZ_CLDOUBLE;
        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_i_ref:
		case en_a_ref:
        case en_cl:
		case en_ci:
            return  - BESZ_DWORD ;
        case en_thiscall:
            return natural_size(node->v.p[0]);
        case en_sfcallb:
        case en_sfcall:
        case en_pfcall:
        case en_pfcallb:
             /* ignore pascal style now */
        case en_fcall:
        case en_fcallb:
        case en_intcall:
            return node->v.p[0]->v.i;
        case en_callblock:
        case en_pcallblock:
        case en_scallblock:
			return BESZ_DWORD ;
        case en_tempref:
        case en_regref:
            return node->v.i >> 16;
        case en_ul_ref:
        case en_cul:
		case en_cui:
		case en_ui_ref:
		case en_ua_ref:
            return BESZ_DWORD ;
        case en_csp:
            return 2;
        case en_cfp:
            return  BESZ_FARPTR;
        case en_fp_ref:
            return  BESZ_FARPTR;

        case en_cp:
            return stdaddrsize;
        case en_bool_ref:
        case en_cbool:
            return BESZ_BOOL;
        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 BESZ_DOUBLE;
        case en_cld:
            return 10;
        case en_cf:
            return BESZ_FLOAT;
        case en_cll:
        case en_ll_ref:
            return  - BESZ_QWORD;
        case en_cull:
        case en_ull_ref:
            return BESZ_QWORD;
        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:
        case en_movebyref:
        case en_clearblock:
            return natural_size(node->v.p[0]);
        case en_add:
        case en_sub:
        case en_addstruc:
        case en_asadd:
        case en_assub:
            siz0 = natural_size(node->v.p[0]);
            siz1 = natural_size(node->v.p[1]);
            if (siz0 <= 10 && siz1 >= BESZ_IFLOAT && siz1 < BESZ_CFLOAT)
            {
                if (siz0 <= BESZ_FLOAT && siz1 ==BESZ_IFLOAT)
                    return BESZ_CFLOAT;
                if (siz0 <=BESZ_DOUBLE && siz1 <= BESZ_IDOUBLE)
                    return BESZ_CDOUBLE;
                return BESZ_CLDOUBLE;
            }
            if (siz1 <= 10 && siz0 >= BESZ_IFLOAT && siz0 < BESZ_CFLOAT)
            {
                if (siz1 <= BESZ_FLOAT && siz0 ==BESZ_IFLOAT)
                    return BESZ_CFLOAT;
                if (siz1 <=BESZ_DOUBLE && siz0 <= BESZ_IDOUBLE)
                    return BESZ_CDOUBLE;
                return BESZ_CLDOUBLE;
            }
            if (chksize(siz1, siz0))
                return siz1;
            else
                return siz0;
        case en_umul:
        case en_udiv:
        case en_umod:
        case en_pmul:
		case en_arrayindex:
        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_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_array:
			return BESZ_DWORD;
        case en_void:
        case en_cond:
        case en_repcons:
            return natural_size(node->v.p[1]);
        case en_voidnz:
        case en_conslabel:
        case en_destlabel:
        case en_addcast:
        case en_dvoid:
            return natural_size(node->v.p[0]);
        default:
            DIAG("natural size error.");
            return BESZ_DWORD ;
    }
    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)) > BESZ_QWORD)
    {
        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 == BESZ_QWORD || nsiz ==  - BESZ_QWORD)
    {
        ap1 = gen_expr(node, FALSE, FALSE, nsiz);
		if (ap1->mode == am_axdx)
		{
    	    gen_codes(op_or, BESZ_DWORD , makedreg(EAX), makedreg(EDX));
		}
		else
		{
			AMODE *ap2 = temp_data();
			AMODE *ap3 = xalloc(sizeof(AMODE));
			*ap3 = *ap1;
    	    gen_codes(op_mov, BESZ_DWORD , ap2, ap1);
			ap3->offset = makenode(en_add, ap3->offset, makenode(en_icon, (void *)4, 0));
			gen_codes(op_or, BESZ_DWORD, ap2, ap3);
			freeop(ap2);
		}
    }
    else
    {
        if (isbit(node))
        {
            ap1 = gen_expr(node, FALSE, TRUE, 0);
            if (node->bits == 1)
            {
                rv = 1;
                gen_codes(op_bt, BESZ_DWORD , 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 || ap1->mode == am_screg || ap1->mode ==
                am_sdreg || ap1->mode == am_streg || ap1->mode == am_seg)
                do_extend(ap1, ap1->length, F_DREG | F_VOL);
            if (ap1->length ==  BESZ_FARPTR)
                ap1->length ==  - BESZ_DWORD ;
            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 = BESZ_BYTE;
    return ap1;
}

//-------------------------------------------------------------------------

static int complex_relat(ENODE *node)
{
    if (!node)
        return 0;
    switch (node->nodetype)
    {
        case en_substack:
		case en_loadstack:
		case en_savestack:
        case en_structret:
            return 0;
        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_a_ref:
		case en_ua_ref:
		case en_i_ref:
		case en_ui_ref:
        case en_bits:
        case en_l_ref:
        case en_cl:
        case en_ul_ref:
        case en_cul:
		case en_ci:
		case en_cui:
        case en_cp:
        case en_cfp:
        case en_csp:
        case en_ub_ref:
        case en_cub:
        case en_bool_ref:
        case en_cbool:
        case en_b_ref:
        case en_fp_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:
        case en_movebyref:
        case en_clearblock:
            return complex_relat(node->v.p[0]);
        case en_icon:
        case en_lcon:
        case en_lucon:
        case en_iucon:
        case en_boolcon:
        case en_ccon:
        case en_cucon:
        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_arrayindex:
        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:
		case en_array:
            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_dvoid:
            return complex_relat(node->v.p[0]);
        case en_conslabel:
        case en_destlabel:
        case en_addcast:
            return complex_relat(node->v.p[0]);
        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 >= BESZ_QWORD || size ==  - BESZ_QWORD)
        size = BESZ_DWORD ;
    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, BESZ_DWORD , 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, BESZ_DWORD , ap1, ap1);
            gen_codes(op_inc, BESZ_DWORD , 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)) > BESZ_QWORD)
    {
        ap1 = gen_expr(node->v.p[0], FALSE, TRUE, size);
        do_extend(ap1, BESZ_LDOUBLE, F_FREG | F_VOL);
        ap2 = gen_expr(node->v.p[1], FALSE, TRUE, size);
        do_extend(ap2, BESZ_LDOUBLE, 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 = BESZ_BYTE;
            gen_code(fbtype1, ap1, 0);
        }
        return ap1;

    }
    if (size == BESZ_QWORD || size ==  - BESZ_QWORD)
    {
        ap2 = gen_expr(node->v.p[1], FALSE, FALSE, size);
        ap2 = aprtocx(ap2);
        do_extend(ap2, BESZ_QWORD, 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, BESZ_DWORD , ap4, makedreg(EAX));
            gen_codes(op_mov, BESZ_DWORD , 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));
        }
        if (btype1 == op_je || btype1 == op_sete || btype1 == op_jne || btype1 
            == op_setne)
        {
			if (isintconst(node->v.p[0]->nodetype) && node->v.p[0]->v.i == 0)
			{
		        ap1 = gen_expr(node->v.p[1], FALSE, FALSE, size);
				if (ap1->mode == am_axdx)
				{
					gen_codes(op_or, BESZ_DWORD, makedreg(EAX), makedreg(EDX));
					freeop(ap1);
				}
				else
				{
					AMODE *ap3 = xalloc(sizeof(AMODE));
					*ap3 = *ap1;
					ap2 = temp_data();
					gen_codes(op_mov, BESZ_DWORD, ap2, ap1);
					ap3->offset = makenode(en_add, ap3->offset, makenode(en_icon, (void *)4, 0));
					gen_codes(op_or, BESZ_DWORD, ap2, ap3);
					freeop(ap2);
				}
			}
			else if (isintconst(node->v.p[1]->nodetype) && node->v.p[1]->v.i == 0)
			{
		        ap1 = gen_expr(node->v.p[0], FALSE, FALSE, size);
				if (ap1->mode == am_axdx)
				{
					gen_codes(op_or, BESZ_DWORD, makedreg(EAX), makedreg(EDX));
					freeop(ap1);
				}
				else
				{
					AMODE *ap3 = xalloc(sizeof(AMODE));
					*ap3 = *ap1;
					ap2 = temp_data();
					gen_codes(op_mov, BESZ_DWORD, ap2, ap1);
					ap3->offset = makenode(en_add, ap3->offset, makenode(en_icon, (void *)4, 0));
					gen_codes(op_or, BESZ_DWORD, ap2, ap3);
					freeop(ap2);
				}
			}
			else
			{
		        ap1 = gen_expr(node->v.p[0], FALSE, FALSE, size);
	    	    do_extend(ap1, BESZ_QWORD, F_AXDX);
	            ap2->length = ap3->length = BESZ_DWORD ;
	            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 = BESZ_BYTE;
                gen_code(fbtype1, ap1, 0);
            }
        }
        else
        {
            int templab = nextlabel++;
	        ap1 = gen_expr(node->v.p[0], FALSE, FALSE, size);
    	    do_extend(ap1, BESZ_QWORD, F_AXDX);
            if (label)
            {
                gen_codes(op_cmp, BESZ_DWORD , makedreg(EDX), ap3);
                gen_branch(btype3, make_label(label));
                gen_branch(btype4, make_label(templab));
                gen_codes(op_cmp, BESZ_DWORD , 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, BESZ_DWORD , makedreg(EDX), ap3);
                gen_codes(btype1, 1, ap4, 0);
                gen_codes(op_cmp, BESZ_DWORD , makedreg(EAX), ap2);
                gen_codes(btype1, 1, ap5, 0);
                freeop(ap1);
                freeop(ap2);
                ap1 = temp_data();
                ap1->length = BESZ_BYTE;
                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, BESZ_DWORD );
            noids(ap2);
            ap1 = gen_expr(xnode = node->v.p[0], FALSE, TRUE, BESZ_DWORD );
        }
        else
        {
            ap2 = gen_expr(node->v.p[0], FALSE, FALSE, BESZ_DWORD );
            noids(ap2);
            ap1 = gen_expr(xnode = node->v.p[1], FALSE, TRUE, BESZ_DWORD );
        }
        if (ap1->length ==  BESZ_FARPTR)
            ap1->length =  - BESZ_DWORD ;
        if (ap2->length ==  BESZ_FARPTR)
            ap2->length =  - BESZ_DWORD ;
        if (ap2->mode == am_immed)
        {
            if (xnode->bits == BESZ_BYTE)
            {
                if (!(ap2->offset->v.i &1))
                {
                    gen_codes(op_bt, BESZ_DWORD , 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, BESZ_DWORD , 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 (ap1->length ==  BESZ_FARPTR)
            ap1->length =  - BESZ_DWORD ;
        if (ap2->length ==  BESZ_FARPTR)
            ap2->length =  - BESZ_DWORD ;
        if (ap1->mode == am_screg || ap1->mode == am_sdreg || ap1->mode ==
            am_streg || ap1->mode == am_seg)
            do_extend(ap1, BESZ_DWORD , F_DREG | F_VOL);
        if (ap2->mode == am_screg || ap2->mode == am_sdreg || ap2->mode ==
            am_streg || ap2->mode == am_seg)
            do_extend(ap2, BESZ_DWORD , F_DREG | F_VOL);
        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, BESZ_DWORD , 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 = BESZ_BYTE;
        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_jae, op_jbe,
                label);
            break;
        case en_gt:
            gen_compare(node, op_jg, op_jl, op_jg, op_jl, op_jb, op_ja, 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_jae, 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_jae, 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;
    }
}
