/*                                                
 * 68K/386 32-bit C compiler.
 *
 * copyright (c) 1997, David Lindauer
 * 
 * This compiler is intended for educational use.  It may not be used
 * for profit without the express written consent of the author.
 *
 * It may be freely redistributed, as long as this notice remains intact
 * and either the original sources or derived sources 
 * are distributed along with any executables derived from the originals.
 *
 * The author is not responsible for any damages that may arise from use
 * of this software, either idirect or consequential.
 *
 * V2.05 June 2002
 * David Lindauer, camille@bluegrass.net
 *
 * Credits to Mathew Brandt for original K&R C compiler
 *
 */
#include        <stdio.h>
#include				<string.h>
#include        "lists.h"
#include        "expr.h"
#include        "c.h"
#include        "gen68.h"
#include 				"diag.h"

#define ABS(x) ( (x) < 0 ? -(x) : (x))
/*
 *      this module contains all of the code generation routines
 *      for evaluating expressions and conditions.
 */
extern int stdinttype,stdunstype,stdintsize, stdldoublesize,stdaddrsize;
extern int cf_freeaddress, cf_freedata;
extern int linkreg,basereg,stackadd,stackmod;
extern long stackdepth,framedepth;
extern int prm_largedata, prm_68020,prm_phiform,prm_linkreg, prm_coldfire;
extern int prm_smallcode, prm_rel, prm_smalldata;
extern AMODE     push[], pop[];
extern int prm_68020, prm_cmangle ;
extern SYM *currentfunc;
extern long lc_maxauto;
extern long nextlabel;
extern char regstack[], rsold[], rsodepth,rsdepth;
extern int retlab;
extern int dregs[3],aregs[3],fregs[3] ;
extern long bittab[32];

static char opcomb[] = {
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
};
int chksize(int lsize, int rsize)
{
	int l,r;
	l = lsize;
	r = rsize;
	if (l < 0) l = - l;
	if (r < 0) r = - r;
  if (rsize == 5) /* 5 is used for bools, which are the smallest type now */
    if (lsize == 5)
      return FALSE;
    else
      return TRUE;
  if (lsize == 5)
    return FALSE;
	return(l > r);
}
AMODE    *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_direct;
        ap->offset = lnode;
        return ap;
}
AMODE    *makebf(ENODE *node, AMODE *ap1, int size)
/*
 *      construct a bit field reference for 68020 bit field instructions
 */
{
        AMODE    *ap;
				if (node->startbit == -1)
					DIAG("Illegal bit field");
        ap = xalloc(sizeof(AMODE));
        ap->mode = am_bf;
				ap->preg = node->startbit;
				ap->sreg = node->bits;
				switch (size) {
					case 1:
					case -1:
				 		ap->preg =8-node->startbit-node->bits;
						break;
					case 2:
					case -2:
				 		ap->preg =16-node->startbit-node->bits;
						break;
					case 4:
					case -4:
				 		ap->preg =32-node->startbit-node->bits;
						break;
				}
        return ap;
}

AMODE    *make_immed(long i)
/*
 *      make a node to reference an immediate value i.
 */
{       AMODE    *ap;
        ENODE    *ep;
        ep = xalloc(sizeof(ENODE));
        ep->nodetype = en_icon;
        ep->v.i = i;
        ap = xalloc(sizeof(AMODE));
        ap->mode = am_immed;
        ap->offset = ep;
        return ap;
}

AMODE    *make_immedt(long i, int size)
/*
 *      make a node to reference an immediate value i.
 */
{
				switch (size) {
					case 1:
					case -1:
						i &= 0xff;
						break;
					case 2:
					case -2:
						i &= 0xffff;
						break;
				}
				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;
        return ap;
}
        
void tofloat(AMODE *ap,int size)
{
	AMODE *ap2;
	if (ap->mode == am_freg)
		return ;
								if (ap->mode == am_areg)  {
									freeop(ap) ;
									ap2 = temp_data() ;
									gen_codes(op_move,4,ap,ap2) ;
									ap->preg = ap2->preg ;
									ap->mode = ap2->mode ;
								}
								freeop(ap) ;
								ap2 = temp_float();
                gen_codef(op_fmove,ap->length,ap,ap2);
                ap->mode = am_freg;
                ap->preg = ap2->preg;
                ap->tempflag = 1;
								ap->length = 10 ;
	return ;
}
AMODE * floatstore(ENODE *e1, AMODE *ap, int novalue)
{
	AMODE *ap1 = gen_expr(e1,FALSE,TRUE,4) ;
	if (isbit(e1)) {
		do_extend(ap,4,F_DREG | F_VOL);
		bit_store(ap,ap1,e1,novalue);
		freeop(ap1) ;
		if (novalue)
			freeop(ap);
		return ap;
	}
	
	gen_codef(op_fmove,natural_size(e1),ap,ap1) ;
	return ap ;
}
void doshift(int op, AMODE *ap2, AMODE *ap1, int size)
{
				if (ap2->mode == am_immed) {
					int temp = ap2->offset->v.i;
					while (temp >8) {
						temp = temp-8;
                  gen_codes(op,size,make_immed(8),ap1);
					}
               if (temp != 0)
                  gen_codes(op,size,make_immed(temp),ap1);
				}
				else
               gen_codes(op,size,ap2,ap1);
}
void bit_store(AMODE *ap1,AMODE *ap2,ENODE *node, int novalue)
{
		if (prm_68020 && !prm_coldfire) {
			AMODE *ap3;
			if (ap1->mode != am_dreg || !ap1->tempflag) {
				ap3 = temp_data();
				ap3->tempflag = 1;
			}
			else
				ap3 = copy_addr(ap1);
			gen_code3(op_bfextu,0,ap1,makebf(node,ap3,ap1->length),ap3);	
			ap1->mode = ap3->mode;
			ap1->preg = ap3->preg;
			ap1->tempflag = ap3->tempflag;
		} else if (ap1->mode == am_immed) {
			int vb;
			AMODE *ap3 ;
         if (prm_coldfire)
				do_extend(ap2,4,F_DREG | F_VOL) ;
			ap3 = make_immed(ap1->offset->v.i & bittab[node->bits-1]);
			if (node->bits == 1)
				gen_codes(op_bclr,4,make_immed(node->startbit),ap2);
			else
				gen_code(op_and,make_immed(~(bittab[node->bits-1]<<node->startbit)),ap2);
			if ((vb = single_bit(ap1->offset->v.i)) != -1) {
				gen_codes(op_bset,4,make_immed(vb+node->startbit),ap2);
			}else if (ap3->offset->v.i) {
				ap3->offset->v.i <<= node->startbit;
				gen_codes(op_or,ap2->length,ap3,ap2);
			}
			ap1->mode = ap2->mode;
			ap1->preg = ap2->preg;
			ap1->tempflag = ap2->tempflag;
		}
		else {
			do_extend(ap1,ap2->length,F_DREG | F_VOL);
			gen_code(op_and,make_immed(bittab[node->bits-1]),ap1);
			if (!novalue)
				gen_codes(op_move,4,ap1,push);
			if (node->startbit)
				doshift(op_asl,make_immed(node->startbit),ap1,ap1->length);
			gen_code(op_and,make_immed(~(bittab[node->bits-1]<<node->startbit)),ap2);
			gen_code(op_or,ap1,ap2);
			if (!novalue)
				gen_codes(op_move,4,pop,ap1);
		}
}
AMODE *bit_load(AMODE *ap,ENODE *node, int size)
{
	if (prm_68020 && !prm_coldfire) {
		AMODE *ap1 = temp_data();
		ap1->tempflag = TRUE;
		gen_code3(op_bfextu,0,ap,makebf(node,ap,size),ap1);
		return ap1;
	}
	else {
		do_extend(ap,ap->length,F_DREG | F_VOL);
		if (node->startbit)
			doshift(op_asr,make_immed(node->startbit),ap,ap->length);
		gen_codes(op_andi,ap->length,make_immed(bittab[node->bits-1]),ap);
		return ap;
	}
}

void do_extend(AMODE *ap,int osize,int flags)
/*
 *      if isize is not equal to osize then the operand ap will be
 *      loaded into a register (if not already) and if osize is
 *      greater than isize it will be extended to match.
 */
{				AMODE *ap2,*ap1;

				int isize = ap->length;
				if (isize && isize != osize && isize != -osize && ap->mode !=am_immed) {
						if (ap->mode == am_dreg && (!(flags & F_VOL) || ap->tempflag))
							ap2 = ap;
						else {
							freeop(ap);
							ap2 = temp_data();
						}
						if (chksize(isize,osize)) {
							/* moving to a lower type */
							if (isize > 5) {
								tofloat(ap,isize);
                if (osize <= 5) {
									int pushed = FALSE;
									gen_codes(op_fmove,osize,ap,ap2) ;
									ap->mode = ap2->mode;
									ap->preg = ap2->preg;
									ap->length = osize ;
									ap->tempflag = ap2->tempflag;
									
								} 	
							} 	
							else {
								if (ap->mode != am_dreg || ap->preg != ap2->preg)
									gen_codes(op_move,isize,ap,ap2);
								ap->mode = ap2->mode;
								ap->preg = ap2->preg;
								ap->length = osize ;
								ap->tempflag = ap2->tempflag;
							} 	
						}
						else {
							/* moving up in type */
              if (isize > 5) {
								tofloat(ap,isize);
								freeop(ap2);
							}
							else if (osize > 5) {
								tofloat(ap,isize) ;
								ap->tempflag = TRUE;
							} else {
								if (isize != osize && isize != -osize) {
										if (osize < 0) {
											if (!equal_address(ap,ap2))
												gen_codes(op_move,isize,ap,ap2) ;
											if ((isize == 1 || isize == -1) && osize == -4 && (prm_68020 || prm_coldfire))
												gen_code(op_extb,ap2,0) ;
											else {
													if (isize == 1 || isize == -1)
														gen_codes(op_ext,2,ap2,0) ;
													if (osize == -4)
														gen_codes(op_ext,4,ap2,0) ;
											}
										} else {
											if (equal_address(ap,ap2))
												ap2 = temp_data() ;
											gen_codes(op_moveq,0,make_immed(0),ap2) ;
											gen_codes(op_move,ap->length,ap,ap2) ;
										}
										freeop(ap) ;
										ap->mode = am_dreg ;
										ap->preg = ap2->preg ;
										ap->tempflag = ap2->tempflag ;
										ap->length = osize ;
								}
							}
						}
				}
        if( ((flags & F_VOL) == 0) || ap->tempflag )
                {
                switch( ap->mode )
                        {
												case am_freg:
																if (flags & F_FREG)
																		return;
																break;
                        case am_immed:
                                if( flags & F_IMMED )
                                        return;         /* mode ok */
                                break;
                        case am_areg:
                                if( flags & F_AREG )
                                        return;
                                break;
                        case am_dreg:
                                if( flags & F_DREG )
                                        return;
                                break;
												case am_indx:
												case am_ind:
                        case am_baseindxdata: 
                        case am_baseindxaddr:
												case am_adirect:
												case am_ainc: case am_adec:
																if (flags & F_MEM)
																				return;
												case am_direct:
                        case am_pcindx:
                                if( flags & F_MEM )
                                        return;
                                break;
                        }
                }
				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) {
								freeop(ap);
								ap2 = temp_data();
								ap2->length = osize;
								gen_code(op_move,ap,ap2);
								ap->mode = ap2->mode;
								ap->preg = ap2->preg;
								ap->tempflag = ap2->tempflag;
							}
					}
					else if (ap->mode != am_freg) {
						tofloat(ap,TRUE ) ;
					}
				} if (flags & F_AREG) {
        	if( isize == -1 )
                {
                freeop(ap);
                ap2 = temp_data();
                gen_codes(op_move,1,ap,ap2);
                gen_codes(op_ext,2,ap2,0);
                ap->mode = ap2->mode;
                ap->preg = ap2->preg;
								ap->tempflag = 1;
                isize = -2;
                }
        	if( isize == 1 )
                {
                freeop(ap);
                ap2 = temp_data();
                gen_codes(op_move,1,ap,ap2);
                gen_codes(op_and,2,make_immed(0xff),ap2);
                ap->mode = ap2->mode;
                ap->preg = ap2->preg;
								ap->tempflag = 1;
                isize = 2;
                }
        	freeop(ap);
        	ap2 = temp_addr();
        	gen_codes(op_move,isize,ap,ap2);
        	ap->mode = am_areg;
        	ap->preg = ap2->preg;
        	ap->tempflag = 1;
				}
        if (osize != isize && osize == 5) {
          int lab = nextlabel++;
					ap2 = temp_data();
					gen_code(op_eor,ap2,ap2);
          gen_code(op_cmp,make_immed(0),ap);
          gen_code(op_beq,make_label(lab),0);
          gen_codes(op_move,1,make_immed(1),ap2);
          gen_label(lab);
					freeop(ap);
					ap->mode = ap->mode;
					ap->tempflag = ap2->tempflag;
					ap->length = ap2->length;
					ap->preg = ap2->preg;
        }     
        ap->length = osize;
				if (osize == 5)
					ap->length = 1;
}

int     isshort(ENODE *node)
/*
 *      return true if the node passed can be generated as a short
 *      offset.
 */
{       return (isintconst(node->nodetype) || node->nodetype == en_absacon)&&
                (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);
}

int isamshort(AMODE *ap)
{
	long v;
	if (ap->offset->nodetype != en_icon)
		return TRUE;
	v = ap->offset->v.i;
	return (v >=-32768L && v < 32767);
}
int isamshort2(AMODE *ap, AMODE *ap2)
{
	long v;
	if (ap->offset->nodetype != en_icon || ap2->offset->nodetype != en_icon)
		return TRUE;
	v = ap->offset->v.i + ap2->offset->v.i;
	return (v >=-32768L && v < 32767);
}
int isambyte(AMODE *ap)
{
	long v;
	if (ap->offset->nodetype != en_icon)
		return FALSE;
	v = ap->offset->v.i;
	return (v >=-128 && v < 128);
}
int isambyte2(AMODE *ap, AMODE *ap2)
{
	long v;
	if (ap->offset->nodetype != en_icon || ap2->offset->nodetype != en_icon)
		return FALSE;
	v = ap->offset->v.i + ap2->offset->v.i;
	return (v >=-128 && v < 128);
}                            

static int depth(ENODE *node)
{
				int a,b;
				if (!node)
					return 0;
        switch( node->nodetype )
                {
                        case en_cll: case en_cull:
								case en_cl:
								case en_cul:
								case en_cp:
                case en_cbool:
								case en_cub:
								case en_cb:
								case en_cuw:
                case en_cw:
								case en_cd:
								case en_cld:
								case en_cf:
								case en_bits:
                        case en_ll_ref: case en_ull_ref:
								case en_l_ref:
                case en_ul_ref:
                case en_ub_ref:
                case en_bool_ref:
                case en_b_ref:
                case en_uw_ref:
                case en_w_ref:
								case en_longdoubleref:
								case en_doubleref:
								case en_floatref:
												return 1 + depth(node->v.p[0]);
                case en_uminus: 
                case en_ainc:   case en_adec: 
								case en_moveblock: case en_stackblock:
												return 1+depth(node->v.p[0]);
                case en_llcon:
                case en_llucon:
                case en_icon:
								case en_lcon: 
								case en_lucon: 
								case en_iucon: 
								case en_ccon:                 
								case en_rcon:
								case en_lrcon:
								case en_fcon:
								case en_absacon:
								case en_trapcall:
                case en_labcon:
                case en_nacon:  case en_autocon:  case en_autoreg:
                case en_napccon: case en_nalabcon:
								case en_tempref:
								case en_regref:
												return 1;
                case en_not:    case en_compl:
												return 1+depth(node->v.p[0]);
                case en_eq:     case en_ne:
                case en_lt:     case en_le:
                case en_gt:     case en_ge:
								case en_ugt: case en_uge: case en_ult: case en_ule:
                case en_land:   case en_lor:
								case en_div: case en_udiv: case en_pdiv: case en_mod: case en_umod:
								case en_assign: case en_refassign:
                        case en_asuminus: case en_ascompl:
                case en_add:    case en_sub: case en_addstruc:
								case en_umul:		case en_pmul:
                case en_mul:		case en_and:
                case en_or:     case en_xor:
								case en_asalsh: case en_asarsh: case en_alsh: case en_arsh: case en_arshd: case en_asarshd:
                case en_lsh:    case en_rsh:
                case en_asadd:  case en_assub:
                case en_asmul:  case en_asdiv:
                case en_asmod:  case en_asand:
								case en_asumod: case en_asudiv: case en_asumul:
                case en_asor:   case en_aslsh:  case en_asxor:
                case en_asrsh:
												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_repcons:
												return 1 + depth(node->v.p[1]);
								case en_sfcall: case en_sfcallb: case en_scallblock:
								case en_pfcall: case en_pfcallb: 
								case en_fcall: case en_intcall: case en_callblock: case en_fcallb:
								case en_pcallblock: case en_thiscall:
												return 1;
                case en_cl_reg:
                        return depth(node->v.p[0]) ;
                default:
                        DIAG("error in depth routine.");
												return 1;
                }
}
	
void noids(AMODE *ap)
{
	if (ap->mode == am_baseindxaddr||ap->mode == am_baseindxdata)
		do_extend(ap,ap->length,F_DREG | F_VOL);
}
AMODE *indx_data(AMODE *ap)
{
	AMODE *ap3;
	freeop(ap);
	ap3 = temp_data();
		gen_codes(op_lea,4,ap,ap3);
		ap3->mode = am_indx;
		ap3->offset = makenode(en_icon,0,0);
		return ap3;
}
AMODE *doindex(ENODE *node, enum e_node type)
{
				AMODE *ap, *ap2,*ap3;
				ENODE node2;
				int scale;
				switch (node->nodetype) {
					case en_icon:
						ap = gen_expr(node,FALSE,TRUE,4);
						break;
					case en_lsh:
						if ((prm_68020 && (scale = node->v.p[1]->v.i) < 4 && scale)  &&
                        (!prm_coldfire || (scale <3))){
							ap = gen_expr(node->v.p[0],FALSE,TRUE,4);
							if (ap->mode != am_immed)
								do_extend(ap,4,F_DREG);
							if (ap->mode == am_immed) {
								while (--scale)
									ap->offset->v.i <<=1;
							}
							else {
								do_extend(ap,4,F_DREG) ;
								if (ap->mode == am_dreg)
									ap->mode = am_baseindxdata;
								else
									ap->mode = am_baseindxaddr;
								ap->sreg = ap->preg;
								ap->preg = -1;
								ap->scale = scale;
								ap->offset = makenode(en_icon,0,0);
							}
							break;
						}
					default:
						node2.v.p[0] = node;
						node2.nodetype = type;
						ap = gen_deref(&node2,4);
						switch (ap->mode) {
							case am_ainc:
							case am_adec:
								ap2 = temp_addr();
								gen_lea(ap->length,ap,ap2);
								freeop(ap);
								ap = ap2;
							case am_baseindxdata:
							case am_baseindxaddr:
								if (ap->sreg >=0 && ap->preg >= 0) {
									freeop(ap);
									ap3 = temp_addr();
									gen_lea(4,ap,ap3);
									ap3->mode = am_ind;
									ap = ap3;
								}
						
						}
						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, *ap3, *ap;
				ENODE node2;

				int a = depth(node->v.p[1]) - depth(node->v.p[0]);
				if (a <= 2 ) {
					ap1 = doindex(node->v.p[0],node->nodetype);
					ap2 = doindex(node->v.p[1],node->nodetype);
				}
				else {
					ap2 = doindex(node->v.p[1],node->nodetype);
					ap1 = doindex(node->v.p[0],node->nodetype);
				}
tryagain:
				switch(ap1->mode) {
					case am_areg:
						switch (ap2->mode) {
							case am_areg:
								ap1->sreg = ap2->preg;
								ap1->mode = am_baseindxaddr;
								ap1->offset = makenode(en_icon,0,0);
								ap1->scale = 0;
								return ap1;
							case am_dreg:
								ap1->sreg = ap2->preg;
								ap1->mode = am_baseindxdata;
								ap1->offset = makenode(en_icon,0,0);
								ap1->scale = 0;
								return ap1;
							case am_adirect:
								if ((!prm_largedata && (prm_rel || !prm_smalldata)) || prm_68020) {
									ap1->mode = am_indx;
									ap1->offset = ap2->offset;
									return ap1;
								}
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap1->mode = am_baseindxaddr;
								ap1->offset = makenode(en_icon,0,0);
								ap1->scale = 0;
								ap1->sreg = ap->preg;
								return ap1;
							case am_immed:
								if ((!prm_largedata && (prm_rel || !prm_smalldata)) || prm_68020) {
									ap1->mode = am_indx;
									ap1->offset = ap2->offset;
									return ap1;
								}
								ap = temp_data();
								gen_codes(op_move,4,ap2,ap);
								ap1->mode = am_baseindxdata;
								ap1->offset = makenode(en_icon,0,0);
								ap1->scale = 0;
								ap1->sreg = ap->preg;
								return ap1;
							case am_indx:
								if (prm_68020 || isambyte(ap2)) {
									ap1->mode = am_baseindxaddr;
									ap1->offset = ap2->offset;
									ap1->scale = 0;
									ap1->sreg = ap2->preg;
									return ap1;
								}
								freeop(ap2);
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap->mode = am_baseindxaddr;
								ap->sreg = ap1->preg;
								ap->scale = 0;
								ap->offset = makenode(en_icon,0,0);
								return ap;
							case am_ind:
								ap1->mode = am_baseindxaddr;
								ap1->offset = makenode(en_icon,0,0);
								ap1->scale = 0;
								ap1->sreg = ap2->preg;
								return ap1;
							case am_baseindxaddr:
							case am_baseindxdata:
								if (ap2->preg == -1) {
									ap2->preg = ap1->preg;
									return ap2;
								}
								freeop(ap2);
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap1->mode = am_baseindxaddr;
								ap1->scale = 0;
								ap1->offset = makenode(en_icon,0,0);
								ap1->sreg = ap->preg;
								return ap1;
						}
						break;
					case am_dreg:
						switch (ap2->mode) {
							case am_areg:
								ap2->sreg = ap1->preg;
								ap2->mode = am_baseindxdata;
								ap2->offset = makenode(en_icon,0,0);
								ap2->scale = 0;
								return ap2;
							case am_dreg:
								freeop(ap2);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap->sreg = ap1->preg;
								ap->mode = am_baseindxdata;
								ap->offset = makenode(en_icon,0,0);
								ap->scale = 0;
								return ap;
							case am_adirect:
								if ((!prm_largedata && (prm_rel || !prm_smalldata)) || prm_68020) {
									freeop(ap1);
									ap = temp_addr();
									gen_codes(op_move,4,ap1,ap);
									ap->mode = am_indx;
									ap->offset = ap2->offset;
									return ap;
								}
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap->mode = am_baseindxdata;
								ap->offset = makenode(en_icon,0,0);
								ap->scale = 0;
								ap->sreg = ap1->preg;
								return ap;
							case am_immed:
								if (prm_68020 || isamshort(ap2)) {
									freeop(ap1);
									ap = temp_addr();
									gen_codes(op_move,4,ap1,ap);
									ap->mode = am_indx;
									ap->offset = ap2->offset;
									return ap;
								}
								ap = temp_addr();
								gen_code(op_move,ap2,ap);
								ap->mode = am_baseindxdata;
								ap->offset = makenode(en_icon,0,0);
								ap->scale = 0;
								ap->sreg = ap1->preg;
								return ap;
							case am_indx:
								if (prm_68020 || isambyte(ap2)) {
									ap2->mode = am_baseindxdata;
									ap2->scale = 0;
									ap2->sreg = ap1->preg;
									return ap2;
								}
								freeop(ap2);
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap->mode = am_baseindxdata;
								ap->sreg = ap1->preg;
								ap->scale = 0;
								ap->offset = makenode(en_icon,0,0);
								return ap;
							case am_ind:
								ap2->mode = am_baseindxdata;
								ap2->offset = makenode(en_icon,0,0);
								ap2->scale = 0;
								ap2->sreg = ap1->preg;
								return ap2;
							case am_baseindxaddr:
							case am_baseindxdata:
								if (ap2->preg == -1) {
									ap = temp_addr();
									gen_codes(op_move,4,ap1,ap);
									ap2->preg = ap->preg;
									return ap2;
								}
								freeop(ap2);
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap->mode = am_baseindxdata;
								ap->scale = 0;
								ap->offset = makenode(en_icon,0,0);
								ap->sreg = ap1->preg;
								return ap;
						}
						break;
					case am_adirect:
						switch (ap2->mode) {
							case am_areg:
								if ((!prm_largedata && (prm_rel || !prm_smalldata)) || prm_68020) {
									ap2->mode = am_indx;
									ap2->offset = ap1->offset;
									return ap2;
								}
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap2->mode = am_baseindxaddr;
								ap2->offset = makenode(en_icon,0,0);
								ap2->scale = 0;
								ap2->sreg = ap->preg;
								return ap2;
							case am_dreg:
								if ((!prm_largedata && (prm_rel || !prm_smalldata)) || prm_68020) {
									freeop(ap1);
									ap = temp_addr();
									gen_codes(op_move,4,ap2,ap);
									ap->mode = am_indx;
									ap->offset = ap1->offset;
									return ap;
								}
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap->mode = am_baseindxdata;
								ap->offset = makenode(en_icon,0,0);
								ap->scale = 0;
								ap->sreg = ap2->preg;
								return ap;
							case am_adirect:
								ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
								return ap1;
							case am_immed:
								ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
								return ap1;
							case am_indx:
								if ((!prm_largedata && (prm_rel || !prm_smalldata)) || prm_68020) {
									ap2->offset = makenode(en_add,ap2->offset,ap1->offset);
									return ap2;
								}
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap2->mode = am_baseindxaddr;
								ap2->sreg = ap->preg;
								ap2->scale = 0;
								return ap2;
							case am_ind:
								if ((!prm_largedata && (prm_rel || !prm_smalldata)) || prm_68020) {
									ap2->offset = ap1->offset;
									ap2->mode = am_indx;
									return ap2;
								}
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap2->mode = am_baseindxaddr;
								ap2->sreg = ap->preg;
								ap2->scale = 0;
								ap2->offset = makenode(en_icon,0,0);
								return ap2;
							case am_baseindxaddr:
							case am_baseindxdata:
								if (prm_68020) {
									ap2->offset = makenode(en_add,ap2->offset,ap1->offset);
									return ap2;
								}
								if (ap2->preg == -1) {
									ap = temp_addr();
									ap2->preg = ap->preg;
									gen_lea(0,ap1,ap);
									return ap2;
								}
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap2->mode = am_baseindxaddr;
								ap2->sreg = ap->preg;
								ap2->scale = 0;
								ap2->offset = makenode(en_icon,0,0);
								return ap2;
						}
						break;
					case am_immed:
						switch (ap2->mode) {
							case am_areg:
								if (prm_68020 || isamshort(ap1)) {
									ap2->mode = am_indx;
									ap2->offset = ap1->offset;
									return ap2;
								}
								ap = temp_data();
								gen_codes(op_move,4,ap1,ap);
								ap2->mode = am_baseindxdata;
								ap2->offset = makenode(en_icon,0,0);
								ap2->scale = 0;
								ap2->sreg = ap->preg;
								return ap2;
							case am_dreg:
								if (prm_68020 || isamshort(ap1)) {
									freeop(ap2);
									ap = temp_addr();
									gen_codes(op_move,4,ap2,ap);
									ap->mode = am_indx;
									ap->offset = ap1->offset;
									return ap;
								}
								ap = temp_addr();
								gen_codes(op_move,4,ap1,ap);
								ap->mode = am_baseindxdata;
								ap->offset = makenode(en_icon,0,0);
								ap->scale = 0;
								ap->sreg = ap2->preg;
								return ap;
							case am_adirect:
								ap2->offset = makenode(en_add,ap2->offset,ap1->offset);
								return ap2;
							case am_immed:
								if (prm_68020 || isamshort2(ap1,ap2)) {
									ap1->offset->v.i += ap2->offset->v.i;
									return ap1;
								}
								if (isamshort(ap1)) {
									ap = temp_addr();
									gen_codes(op_move,4,ap2,ap);
									ap->mode = am_indx;
									ap->offset = ap1->offset;
									return ap;
								}
								if (isamshort(ap2)) {
									ap = temp_addr();
									gen_codes(op_move,4,ap1,ap);
									ap->mode = am_indx;
									ap->offset = ap2->offset;
									return ap;
								}
								ap = temp_addr();
								ap3 = temp_data();
								gen_codes(op_move,4,ap1,ap);
								gen_codes(op_move,4,ap2,ap3);
								ap->mode = am_baseindxdata;
								ap->sreg = ap3->preg;
								ap->scale = 0;
								ap->offset = makenode(en_icon,0,0);
								return ap;
							case am_indx:
								if (prm_68020 || isamshort2(ap1,ap2)) {
									if (ap2->offset->nodetype == en_icon)
										ap2->offset->v.i += ap1->offset->v.i;
									else
										ap2->offset = makenode(en_add,ap2->offset,ap1->offset);
									return ap2;
								}
								ap = temp_data();
								gen_codes(op_move,4,ap2,ap);
								ap1->mode = am_baseindxdata;
								ap1->scale = 0;
								ap1->sreg = ap->preg;
								return ap1;
							case am_baseindxaddr:
							case am_baseindxdata:
								if (ap2->preg == -1 && !prm_68020) {
									ap = temp_addr();
									gen_codes(op_move,4,ap1,ap);
									ap2->preg = ap->preg;
									return ap2;
								}
								if (prm_68020 || isambyte2(ap1,ap2)) {
									if (ap2->offset->nodetype == am_immed)
										ap2->offset->v.i += ap1->offset->v.i;
									else
										ap2->offset = makenode(en_add,ap2->offset,ap1->offset);
									return ap2;
								}
								freeop(ap2);
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap->mode = am_ind;
								ap2 = ap;
								/* drop through */
							case am_ind:
								if (prm_68020 || isamshort(ap1)) {
									ap2->offset = ap1->offset;
									ap2->mode = am_indx;
									return ap2;
								}
								ap = temp_data();
								gen_codes(op_move,4,ap1,ap);
								ap2->mode = am_baseindxdata;
								ap2->scale = 0;
								ap2->sreg = ap->preg;
								ap2->offset = makenode(en_icon,0,0);
								return ap2;
						}
						break;
					case am_indx:
						switch (ap2->mode) {
							case am_areg:
								if (prm_68020 || isambyte(ap1)) {
									ap2->mode = am_baseindxaddr;
									ap2->offset = ap1->offset;
									ap2->scale = 0;
									ap2->sreg = ap2->preg;
									return ap2;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap->mode = am_baseindxaddr;
								ap->sreg = ap2->preg;
								ap->scale = 0;
								ap->offset = makenode(en_icon,0,0);
								return ap;
							case am_dreg:
								if (prm_68020 || isambyte(ap1)) {
									ap1->mode = am_baseindxdata;
									ap1->scale = 0;
									ap1->sreg = ap2->preg;
									return ap1;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap->mode = am_baseindxdata;
								ap->sreg = ap2->preg;
								ap->scale = 0;
								ap->offset = makenode(en_icon,0,0);
								return ap;
							case am_adirect:
								if ((!prm_largedata && (prm_rel || !prm_smalldata)) || prm_68020) {
									ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
									return ap1;
								}
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap1->mode = am_baseindxaddr;
								ap1->sreg = ap->preg;
								ap1->scale = 0;
								return ap1;
							case am_immed:
								if (prm_68020 || isamshort2(ap1,ap2)) {
									if (ap1->offset->nodetype == am_immed)
										ap1->offset->v.i += ap2->offset->v.i;
									else
										ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
									return ap1;
								}
								ap = temp_data();
								gen_codes(op_move,4,ap2,ap);
								ap1->mode = am_baseindxdata;
								ap1->scale = 0;
								ap1->sreg = ap->preg;
								return ap1;
							case am_indx:
								if (isambyte2(ap1,ap2) || prm_68020) {
									if (ap1->offset->nodetype == am_immed && ap2->offset->nodetype)
										ap1->offset->v.i += ap2->offset->v.i;
									else
										ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
									ap1->mode = am_baseindxaddr;
									ap1->sreg = ap2->preg;
									ap1->scale = 0;
									ap1->offset = makenode(en_icon,0,0);
									return ap1;
								}
								if (isambyte(ap1)) {
									freeop(ap2);
									ap = temp_addr();
							    gen_lea(0,ap2,ap);
									ap1->mode = am_baseindxaddr;
									ap1->sreg = ap->preg;
									ap1->scale = 0;
									ap1->offset = makenode(en_icon,0,0);
									return ap1;
								}
								if (isambyte(ap2)) {
									freeop(ap1);
									ap = temp_addr();
							    gen_lea(0,ap1,ap);
									ap2->mode = am_baseindxaddr;
									ap2->sreg = ap->preg;
									ap2->scale = 0;
									ap2->offset = makenode(en_icon,0,0);
									return ap2;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								freeop(ap2);
								ap1 = temp_addr();
								gen_lea(0,ap2,ap1);
								ap1->sreg = ap->preg;
								ap1->mode = am_baseindxaddr;
								ap1->scale = 0;
								ap1->offset = makenode(en_icon,0,0);
								return ap1;
							case am_ind:
								if (isambyte(ap1) || prm_68020) {
									ap1->mode = am_baseindxaddr;
									ap1->sreg = ap2->preg;
									ap1->scale = 0;
									return ap1;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap2->sreg = ap->preg;
								ap2->mode = am_baseindxaddr;
								ap2->scale = 0;
								ap2->offset = makenode(en_icon,0,0);
								return ap2;
							case am_baseindxaddr:
							case am_baseindxdata:
								if (prm_68020 || isambyte2(ap1,ap2)) {
									if (ap2->preg == -1) {
										ap2->preg = ap1->preg;
										if (ap2->offset->nodetype == am_immed && ap1->offset->nodetype == am_immed)
											ap2->offset->v.i+= ap1->offset->v.i;
										else
											ap2->offset = makenode(en_add,ap2->offset, ap1->offset);
										return ap2;
									}
									freeop(ap2);
									ap = temp_addr();
									gen_lea(0,ap2,ap);
									ap->mode = am_baseindxaddr;
									ap->sreg = ap1->preg;
									ap->scale = 0;
									ap->offset = ap1->offset;
									return ap;
								}
								if (ap2->preg == -1) {
									ap3 = xalloc(sizeof(AMODE));
									ap3->preg = ap2->sreg;
									if (ap2->mode == am_baseindxdata) {
										ap3->mode = F_DREG;
										if (ap3->preg < cf_freedata)
											ap3->tempflag = 1;
									}
									else {
										ap3->mode = F_AREG;
										if (ap3->preg < cf_freeaddress)
											ap3->tempflag = 1;
									}
									if (ap2->scale) {
										do_extend(ap3,4,F_DREG|F_VOL);
										gen_codes(op_asl,4,ap3,make_immed(ap2->scale));
										do_extend(ap3,4,F_AREG|F_VOL);
									}
									else
										do_extend(ap3,4,F_AREG);
									ap2->preg = ap3->preg;
									ap2->mode = am_indx;
									return ap2;
								}
								freeop(ap2);
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap2 = temp_data();
								gen_codes(op_move,4,ap,ap2);
								freeop(ap1);
								gen_lea(0,ap1,ap);
								ap->mode = am_baseindxdata;
								ap->sreg = ap2->preg;
								ap->scale = 0;
								ap->offset = makenode(en_icon,0,0);
								return ap;
						}
						break;
					case am_ind:
						switch (ap2->mode) {
							case am_areg:
								ap2->mode = am_baseindxaddr;
								ap2->offset = makenode(en_icon,0,0);
								ap2->scale = 0;
								ap2->sreg = ap1->preg;
								return ap2;
							case am_dreg:
								ap1->mode = am_baseindxdata;
								ap1->offset = makenode(en_icon,0,0);
								ap1->scale = 0;
								ap1->sreg = ap2->preg;
								return ap1;
							case am_adirect:
								if ((!prm_largedata && (prm_rel || !prm_smalldata)) || prm_68020) {
									ap1->offset = ap2->offset;
									ap1->mode = am_indx;
									return ap1;
								}
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap1->mode = am_baseindxaddr;
								ap1->sreg = ap->preg;
								ap1->scale = 0;
								ap1->offset = makenode(en_icon,0,0);
								return ap1;
							case am_immed:
								if (prm_68020 || isamshort(ap2)) {
									ap1->offset = ap2->offset;
									ap1->mode = am_indx;
									return ap1;
								}
								ap = temp_data();
								gen_codes(op_move,4,ap2,ap);
								ap1->mode = am_baseindxdata;
								ap1->scale = 0;
								ap1->sreg = ap->preg;
								ap1->offset = makenode(en_icon,0,0);
								return ap1;
							case am_indx:
								if (isambyte(ap2) || prm_68020) {
									ap2->mode = am_baseindxaddr;
									ap2->sreg = ap1->preg;
									return ap2;
								}
								freeop(ap2);
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap1->sreg = ap->preg;
								ap1->mode = am_baseindxaddr;
								ap1->scale = 0;
								ap1->offset = makenode(en_icon,0,0);
								return ap1;
							case am_ind:
								ap1->mode = am_baseindxaddr;
								ap1->sreg= ap2->preg;
								ap1->scale = 0;
								ap1->offset = makenode(en_icon,0,0);
								return ap1;
							case am_baseindxaddr:
							case am_baseindxdata:
								if (ap2->preg == -1) {
									ap2->preg = ap1->preg;
									return ap2;
								}
								freeop(ap2);
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap->mode = am_baseindxaddr;
								ap->sreg = ap1->preg;
								ap->scale = 0;
								ap->offset = makenode(en_icon,0,0);
								return ap;
						}
						break;
					case am_baseindxaddr:
						switch (ap2->mode) {
							case am_areg:
								if (ap1->preg == -1) {
									ap1->preg = ap2->preg;
									return ap1;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap2->mode = am_baseindxaddr;
								ap2->scale = 0;
								ap2->offset = makenode(en_icon,0,0);
								ap2->sreg = ap->preg;
								return ap2;
							case am_dreg:
								if (ap1->preg == -1) {
									ap = temp_addr();
									gen_codes(op_move,4,ap2,ap);
									ap1->preg = ap->preg;
									return ap1;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap->mode = am_baseindxdata;
								ap->scale = 0;
								ap->offset = makenode(en_icon,0,0);
								ap->sreg = ap2->preg;
								return ap;
							case am_adirect:
								if (prm_68020) {
									ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
									return ap1;
								}
								if (ap1->preg == -1) {
									ap = temp_addr();
									ap1->preg = ap->preg;
									gen_lea(0,ap2,ap);
									return ap1;
								}
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap1->mode = am_baseindxaddr;
								ap1->sreg = ap->preg;
								ap1->scale = 0;
								ap1->offset = makenode(en_icon,0,0);
								return ap1;
							case am_immed:
								if (!prm_68020 && ap1->preg == -1) {
									ap = temp_addr();
									gen_codes(op_move,4,ap2,ap);
									ap1->preg = ap->preg;
									return ap1;
								}
								if (prm_68020 || isambyte2(ap1,ap2)) {
									if (ap1->offset->nodetype == am_immed)
										ap1->offset->v.i += ap2->offset->v.i;
									else
										ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
									return ap1;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								if ((!prm_largedata && (prm_rel || !prm_smalldata)) || prm_68020) {
									ap->mode = am_indx;
									ap->offset = ap2->offset;
									return ap;
								}
								ap1 = temp_data();
								ap1->mode = am_baseindxdata;
								ap1->sreg = ap->preg;
								ap1->scale = 0;
								ap1->offset = makenode(en_icon,0,0);
								return ap1;
							case am_indx:
								if (prm_68020 || isambyte2(ap1,ap2)) {
									if (ap1->preg == -1) {
										ap1->preg = ap2->preg;
										if (ap2->offset->nodetype == am_immed && ap1->offset->nodetype == am_immed)
											ap1->offset->v.i+= ap2->offset->v.i;
										else
											ap1->offset = makenode(en_add,ap1->offset, ap2->offset);
										return ap1;
									}
									freeop(ap1);
									ap = temp_addr();
									gen_lea(0,ap1,ap);
									ap->mode = am_baseindxaddr;
									ap->sreg = ap2->preg;
									ap->scale = 0;
									ap->offset = ap2->offset;
									return ap;
								}
								if (ap1->preg == -1) {
									ap3 = xalloc(sizeof(AMODE));
									ap3->preg = ap1->sreg;
									if (ap1->mode == am_baseindxdata) {
										ap3->mode = F_DREG;
										if (ap3->preg < cf_freedata)
											ap3->tempflag = 1;
									}
									else {
										ap3->mode = F_AREG;
										if (ap3->preg < cf_freeaddress)
											ap3->tempflag = 1;
									}
									if (ap1->scale) {
										do_extend(ap3,4,F_DREG|F_VOL);
										gen_codes(op_asl,4,ap3,make_immed(ap1->scale));
										do_extend(ap3,4,F_AREG|F_VOL);
									}
									else
										do_extend(ap3,4,F_AREG);
									ap1->preg = ap3->preg;
									ap1->mode = am_indx;
									return ap1;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap1 = temp_data();
								gen_codes(op_move,4,ap,ap1);
								freeop(ap2);
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap->mode = am_baseindxdata;
								ap->sreg = ap1->preg;
								ap->scale = 0;
								ap->offset = makenode(en_icon,0,0);
								return ap;
							case am_ind:
								if (ap1->preg == -1) {
									ap1->preg = ap2->preg;
									return ap1;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap->mode = am_baseindxaddr;
								ap->sreg = ap2->preg;
								ap->scale = 0;
								ap->offset = ap1->offset;
								return ap;
							case am_baseindxaddr:
							case am_baseindxdata:
								if (prm_68020 || (ap1->preg != -1 && ap2->preg != -1)) {
									freeop(ap1);
									ap = temp_addr();
									gen_lea(0,ap1,ap);
									ap1 = temp_data();
									gen_codes(op_move,4,ap,ap1);
									freeop(ap2);
									gen_lea(0,ap2,ap);
									ap->mode = am_baseindxdata;
									ap->sreg = ap1->preg;
									ap->scale = 0;
									ap->offset = makenode(en_icon,0,0);
									return ap;
								}
								if (ap1->preg == -1) {
									ap3 = xalloc(sizeof(AMODE));
									ap3->preg = ap1->sreg;
									if (ap1->mode == am_baseindxdata) {
										ap3->mode = F_DREG;
										if (ap3->preg < cf_freedata)
											ap3->tempflag = 1;
									}
									else {
										ap3->mode = F_AREG;
										if (ap3->preg < cf_freeaddress)
											ap3->tempflag = 1;
									}
									if (ap1->scale) {
										do_extend(ap3,4,F_DREG|F_VOL);
										gen_codes(op_asl,4,ap3,make_immed(ap1->scale));
										do_extend(ap3,4,F_AREG|F_VOL);
									}
									else
										do_extend(ap3,4,F_AREG);
									ap1->preg = ap3->preg;
									ap1->mode = am_indx;
								}
								if (ap2->preg == -1) {
									ap3 = xalloc(sizeof(AMODE));
									ap3->preg = ap2->sreg;
									if (ap2->mode == am_baseindxdata) {
										ap3->mode = F_DREG;
										if (ap3->preg < cf_freedata)
											ap3->tempflag = 1;
									}
									else {
										ap3->mode = F_AREG;
										if (ap3->preg < cf_freeaddress)
											ap3->tempflag = 1;
									}
									if (ap2->scale) {
										do_extend(ap3,4,F_DREG|F_VOL);
										gen_codes(op_asl,4,ap3,make_immed(ap2->scale));
										do_extend(ap3,4,F_AREG|F_VOL);
									}
									else
										do_extend(ap3,4,F_AREG);
									ap2->preg = ap3->preg;
									ap2->mode = am_indx;
								}
								goto tryagain;
						}
						break;
					case am_baseindxdata:
						switch (ap2->mode) {
							case am_areg:
								if (ap1->preg == -1) {
									ap1->preg = ap2->preg;
									return ap1;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap2->mode = am_baseindxaddr;
								ap2->scale = 0;
								ap2->offset = makenode(en_icon,0,0);
								ap2->sreg = ap->preg;
								return ap2;
							case am_dreg:
								if (ap1->preg == -1) {
									ap = temp_addr();
									gen_codes(op_move,4,ap2,ap);
									ap1->preg = ap->preg;
									return ap1;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap->mode = am_baseindxdata;
								ap->scale = 0;
								ap->offset = makenode(en_icon,0,0);
								ap->sreg = ap2->preg;
								return ap;
							case am_adirect:
								if (prm_68020) {
									ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
									return ap1;
								}
								if (ap1->preg == -1) {
									ap = temp_addr();
									ap1->preg = ap->preg;
									gen_lea(0,ap2,ap);
									return ap1;
								}
								ap = temp_addr();
								gen_lea(0,ap2,ap);
								ap1->mode = am_baseindxaddr;
								ap1->sreg = ap->preg;
								ap1->scale = 0;
								ap1->offset = makenode(en_icon,0,0);
								return ap1;
							case am_immed:
								if (!prm_68020 && ap1->preg == -1) {
									ap = temp_addr();
									gen_codes(op_move,4,ap2,ap);
									ap1->preg = ap->preg;
									return ap1;
								}
								if (prm_68020 || isambyte2(ap1,ap2)) {
									if (ap1->offset->nodetype == am_immed)
										ap1->offset->v.i += ap2->offset->v.i;
									else
										ap1->offset = makenode(en_add,ap1->offset,ap2->offset);
									return ap1;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								if ((!prm_largedata && (prm_rel || !prm_smalldata)) || prm_68020) {
									ap->mode = am_indx;
									ap->offset = ap2->offset;
									return ap;
								}
								ap1 = temp_data();
								ap1->mode = am_baseindxdata;
								ap1->sreg = ap->preg;
								ap1->scale = 0;
								ap1->offset = makenode(en_icon,0,0);
								return ap1;
							case am_indx:
								if (prm_68020 || isambyte2(ap1,ap2)) {
									if (ap1->preg == -1) {
										ap1->preg = ap2->preg;
										if (ap2->offset->nodetype == am_immed && ap1->offset->nodetype == am_immed)
											ap1->offset->v.i+= ap2->offset->v.i;
										else
											ap1->offset = makenode(en_add,ap1->offset, ap2->offset);
										return ap1;
									}
									freeop(ap1);
									ap = temp_addr();
									gen_lea(0,ap1,ap);
									ap->mode = am_baseindxaddr;
									ap->sreg = ap2->preg;
									ap->scale = 0;
									ap->offset = ap2->offset;
									return ap;
								}
								if (ap1->preg == -1) {
									ap3 = xalloc(sizeof(AMODE));
									ap3->preg = ap1->sreg;
									if (ap1->mode == am_baseindxdata) {
										ap3->mode = F_DREG;
										if (ap3->preg < cf_freedata)
											ap3->tempflag = 1;
									}
									else {
										ap3->mode = F_AREG;
										if (ap3->preg < cf_freeaddress)
											ap3->tempflag = 1;
									}
									if (ap3->preg < cf_freedata)
										ap3->tempflag = 1;
									if (ap1->scale) {
										do_extend(ap3,4,F_DREG|F_VOL);
										gen_codes(op_asl,4,ap3,make_immed(ap1->scale));
										do_extend(ap3,4,F_AREG|F_VOL);
									}
									else
										do_extend(ap3,4,F_AREG);
									ap1->preg = ap3->preg;
									ap1->mode = am_indx;
									return ap1;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap1 = temp_data();
								gen_codes(op_move,4,ap,ap1);
								freeop(ap2);
								gen_lea(0,ap2,ap);
								ap->mode = am_baseindxdata;
								ap->sreg = ap1->preg;
								ap->scale = 0;
								ap->offset = makenode(en_icon,0,0);
								return ap;
							case am_ind:
								if (ap1->preg == -1) {
									ap1->preg = ap2->preg;
									return ap1;
								}
								freeop(ap1);
								ap = temp_addr();
								gen_lea(0,ap1,ap);
								ap->mode = am_baseindxaddr;
								ap->sreg = ap2->preg;
								ap->scale = 0;
								ap->offset = ap1->offset;
								return ap;
							case am_baseindxaddr:
							case am_baseindxdata:
								if (prm_68020 || (ap1->preg != -1 && ap2->preg != -1)) {
									freeop(ap1);
									ap = temp_addr();
									gen_lea(0,ap1,ap);
									ap1 = temp_data();
									gen_codes(op_move,4,ap,ap1);
									freeop(ap2);
									gen_lea(0,ap2,ap);
									ap->mode = am_baseindxdata;
									ap->sreg = ap->preg;
									ap->scale = 0;
									ap->offset = makenode(en_icon,0,0);
									return ap;
								}
								if (ap1->preg == -1) {
									ap3 = xalloc(sizeof(AMODE));
									ap3->preg = ap1->sreg;
									if (ap1->mode == am_baseindxdata) {
										ap3->mode = F_DREG;
										if (ap3->preg < cf_freedata)
											ap3->tempflag = 1;
									}
									else {
										ap3->mode = F_AREG;
										if (ap3->preg < cf_freeaddress)
											ap3->tempflag = 1;
									}
									if (ap1->scale) {
										do_extend(ap3,4,F_DREG|F_VOL);
										gen_codes(op_asl,4,ap3,make_immed(ap1->scale));
										do_extend(ap3,4,F_AREG|F_VOL);
									}
									else
										do_extend(ap3,4,F_AREG);
									ap1->preg = ap3->preg;
									ap1->mode = am_indx;
								}
								if (ap2->preg == -1) {
									ap3 = xalloc(sizeof(AMODE));
									ap3->preg = ap2->sreg;
									if (ap2->mode == am_baseindxdata) {
										ap3->mode = F_DREG;
										if (ap3->preg < cf_freedata)
											ap3->tempflag = 1;
									}
									else {
										ap3->mode = F_AREG;
										if (ap3->preg < cf_freeaddress)
											ap3->tempflag = 1;
									}
									if (ap2->scale) {
										do_extend(ap3,4,F_DREG|F_VOL);
										gen_codes(op_asl,4,ap3,make_immed(ap2->scale));
										do_extend(ap3,4,F_AREG|F_VOL);
									}
									else
										do_extend(ap3,4,F_AREG);
									ap2->preg = ap3->preg;
									ap2->mode = am_indx;
								}
								goto tryagain;
						}
						break;
				}
				DIAG("invalid index conversion");
}
AMODE    *gen_deref(ENODE *node, int size)
/*
 *      return the addressing mode of a dereferenced node.
 */
{       AMODE    *ap1,*ap2;
        int             siz1;
        switch( node->nodetype )        /* get load size */
                {
                case en_bool_ref:
                case en_ub_ref:
                        siz1 = 1;
                        break;
                case en_b_ref:
                        siz1 = -1;
                        break;
                case en_uw_ref:
                        siz1 = 2;
                        break;
                case en_w_ref:
                        siz1 = -2;
                        break;
                case en_l_ref:
												siz1 = -4;
												break;
								case en_add:  case en_addstruc:
								case en_ul_ref:
                        siz1 = 4;
                        break;
								case en_floatref:
												siz1 = 6;
												break;
								case en_doubleref:
												siz1 = 8;
												break;
								case en_longdoubleref:
												siz1 = 10;
												break;
								default:
												siz1 = 4;
                }
        if( node->v.p[0]->nodetype == en_add || node->v.p[0]->nodetype == en_addstruc )
                {
                	ap1 = gen_index(node->v.p[0]); 
									ap1->length = siz1;
                	return ap1;
                }
        else if( node->v.p[0]->nodetype == en_autocon  || node->v.p[0]->nodetype == en_autoreg)
                {
                ap1 = xalloc(sizeof(AMODE));
                ap1->mode = am_indx;
								if (prm_linkreg && !currentfunc->intflag) {
                		ap1->preg = linkreg;
                		ap1->offset = makenode(en_icon,(char *)((SYM *)node->v.p[0]->v.p[0])->value.i,0);
								}
								else if (((SYM *)node->v.p[0]->v.p[0])->funcparm) {
									if (prm_phiform || currentfunc->intflag) {
                		ap1->preg = linkreg;
                		ap1->offset = makenode(en_icon,(char *)((SYM *)node->v.p[0]->v.p[0])->value.i,0);
									}
									else {
                		ap1->preg = 7;
                		ap1->offset = makenode(en_icon,(char *)(((SYM *)node->v.p[0]->v.p[0])->value.i+framedepth+stackdepth),0);
									}
#ifdef CPLUSPLUS
									if ((currentfunc->value.classdata.cppflags & PF_MEMBER) &&
												!(currentfunc->value.classdata.cppflags & PF_STATIC) && ap1->offset->v.i > 0)
										ap1->offset->v.i += 4;
#endif
								}
								else {
                	ap1->preg = 7;
                	ap1->offset = makenode(en_icon,(char *)(((SYM *)node->v.p[0]->v.p[0])->value.i+stackdepth+lc_maxauto),0);
								}
								ap1->length = siz1 ;
                return ap1;
                }
        else if( node->v.p[0]->nodetype == en_nacon)
                {
      	        ap1 = xalloc(sizeof(AMODE));
								if (prm_rel) {
        	        ap1->preg = basereg;
          	      ap1->offset = makenode(node->v.p[0]->nodetype,((SYM *)node->v.p[0]->v.sp),0);
					        if (prm_largedata) {
										ap2 = temp_addr();
										ap1->mode = am_areg;
										gen_codes(op_move,4,ap1,ap2);
										ap1->mode = am_immed;
										gen_codes(op_add,4,ap1,ap2);
										ap1 = ap2;
										ap1->mode = am_ind;
									}
									else {
  	              	ap1->mode = am_indx;
									}
								}
								else {
									ap1->mode = am_adirect;
          	      ap1->offset = makenode(node->v.p[0]->nodetype,((SYM *)node->v.p[0]->v.sp),0);
									if (prm_smalldata)
										ap1->preg = 2;
									else
										ap1->preg = 4;
								}
								ap1->length = siz1 ;
                return ap1;
                }
        else if( node->v.p[0]->nodetype == en_nalabcon)
                {
      	        ap1 = xalloc(sizeof(AMODE));
								if (prm_rel) {
        	        ap1->preg = basereg;
          	      ap1->offset = makenode(node->v.p[0]->nodetype,(char *)node->v.p[0]->v.i,0);
					        if (prm_largedata) {
										ap2 = temp_addr();
										ap1->mode = am_areg;
										gen_codes(op_move,4,ap1,ap2);
										ap1->mode = am_immed;
										gen_codes(op_add,4,ap1,ap2);
										ap1 = ap2;
										ap1->mode = am_ind;
									}
									else {
  	              	ap1->mode = am_indx;
									}
								}
								else {
									ap1->mode = am_adirect;
          	      ap1->offset = makenode(node->v.p[0]->nodetype,(char *)node->v.p[0]->v.i,0);
									if (prm_smalldata)
										ap1->preg = 2;
									else
										ap1->preg = 4;
								}
								ap1->length = siz1 ;
                return ap1;
                }
        else if( node->v.p[0]->nodetype == en_labcon || node->v.p[0]->nodetype == en_napccon)
                {
	                ap1 = xalloc(sizeof(AMODE));
									if (prm_rel)
  	              	ap1->mode = am_pcindx;
									else {
										ap1->mode = am_adirect;
										if (prm_smallcode)
											ap1->preg = 2;
										else
											ap1->preg = 4;
									}
									if (node->v.p[0]->nodetype == en_labcon)
    	            	ap1->offset = makenode(node->v.p[0]->nodetype,(char *)node->v.p[0]->v.i,0);
									else
    	            	ap1->offset = makenode(node->v.p[0]->nodetype,node->v.p[0]->v.sp,0);
								ap1->length = siz1 ;
                return ap1;
                }
				else if (node->v.p[0]->nodetype == en_absacon) {
								ap1 = xalloc(sizeof(AMODE));
								ap1->mode = am_adirect;
								ap1->preg = isshort(node->v.p[0]) ? 2 : 4;
								ap1->offset = makenode(en_absacon,(char *)((SYM *)node->v.p[0]->v.p[0])->value.i,0);
								ap1->length = siz1 ;
                return ap1;

				}
				else if (node->v.p[0]->nodetype == en_regref) {
        	ap1 = gen_expr(node->v.p[0],FALSE,TRUE,4);
					return ap1;
				}
			
       	ap1 = gen_expr(node->v.p[0],FALSE,TRUE,4); /* generate address */
				do_extend(ap1,4,F_AREG|F_IMMED) ;
				/* AINCDEC for example may return an indirect mode already */
				if (ap1->mode == am_areg || ap1->mode == am_immed) {
        	if( ap1->mode == am_areg )
          	      {
            	    ap1->mode = am_ind;
                	return ap1;
                	}
        	ap1->mode = am_direct;
				}
        return ap1;
}

void get_size(AMODE *ap1, AMODE *ap2,int size)
{
   if (size > 5)
		size = 4;
   if (chksize(size,ap1->length)) {
      if (!chksize(size,ap2->length))
         size = ap2->length ;
   } else
      if (chksize(ap1->length,ap2->length))
         size = ap1->length ;
      else
         size = ap2->length ;
   if (ap1->length >0 || ap2->length >0 && size < 0)
      size = - size ;
	if (size) {
      if (ap1->mode == am_immed && (ap1->length <= 4 || ap1->length == 6))
			ap1->length = size;
      else
         do_extend(ap1,size ,0);
      if (ap2->mode == am_immed && (ap2->length <= 4 || ap2->length == 6))
			ap2->length = size;
      else
         do_extend(ap2,size ,0);
	}
}
void small_size(AMODE *ap1, AMODE *ap2, int size)
{
	if (ap1->length <= 4 && ap2->length <= 4 && chksize(ap2->length, ap1->length)) {
//      if (ap2->mode!= am_dreg || ap2->preg < 4)
			ap2->length = ap1->length;
//      else
//         do_extend(ap2,ap1->length,0) ;
   } else
		get_size(ap1,ap2,size);
}
int assign_size(ENODE *node, int size)
{
   int rsize = natural_size(node) ;
   int neg = 0;
   if (rsize < 0)
      neg = -1 ;
   if (chksize(size, rsize))
      if (size < 6 && size != -6)
         rsize = size ;      
      else if (rsize < 6 && rsize != -6)
         rsize = 4*neg ;
      else if (rsize != 6 && rsize != -6)
         rsize = size ;
      
   return rsize ;
}
void resolve_binary(ENODE *node,AMODE **ap1, AMODE **ap2, int size)
{
  	*ap2 = gen_expr(node->v.p[1],FALSE,FALSE, size);
		noids(*ap2);
  	*ap1 = gen_expr(node->v.p[0],FALSE,FALSE, size);
		get_size(*ap1,*ap2,size);
}
static int isbit(ENODE *node)
{
	return node->nodetype == en_bits;
}
static int as_args(ENODE *node,AMODE **apr,AMODE **ap1,AMODE **ap2, int size)
{
	int rv = isbit(node->v.p[0]);
	*ap2 = gen_expr(node->v.p[1],FALSE,FALSE,size);
	noids(ap2);
	*apr = gen_expr(node->v.p[0],FALSE,TRUE,size);
	if (rv)
		*ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size);
	else
		*ap1 = copy_addr(*apr);
	return rv;
}
static int prefer(ENODE *node,AMODE **ap2, AMODE **ap3, int op, int dosizing, int size)
{                   
	AMODE *ap2x, *ap3x;
	int rv = 0;
	int a = depth(node->v.p[1]) - depth(node->v.p[0]);
	if (a <= 2 ) {
  	ap2x = gen_expr(node->v.p[0],FALSE,FALSE,size);
		noids(ap2x);
  	ap3x = gen_expr(node->v.p[1],FALSE,FALSE,size);
		if (dosizing)
			get_size(ap2x,ap3x,size);
	}
	else {
  	ap3x = gen_expr(node->v.p[1],FALSE,FALSE,size);
		noids(ap3x);
  	ap2x = gen_expr(node->v.p[0],FALSE,FALSE,size);
		if (dosizing)
			get_size(ap2x,ap3x,size);
	}
	*ap3 = ap3x;
	*ap2 = ap2x;
	if (ap2x->mode != am_dreg || !ap2x->tempflag) {
		if (op != op_sub && op != op_divs && op != op_divu && op != op_divsl && op != op_divul) {
		  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 > 5) {
					do_extend(ap,10,F_FREG | F_VOL);
					gen_code(fop,ap,0);
				}
				else {
              if (!size)
               size = natural_size(node) ;
				  do_extend(ap,prm_coldfire ? 4 : ap->length,F_DREG | F_VOL);
          gen_code(op,ap,0);
				}
        return ap;
}

AMODE *gen_fbinary(ENODE *node , int fop, int size)
{
		AMODE *ap1, *ap2 ;
					prefer(node,&ap1,&ap2,fop,FALSE,size);
					tofloat(ap1,ap1->length) ;
					tofloat(ap2,ap2->length) ;
     			gen_code(fop,ap2,ap1);
					freeop(ap2);
					return ap1 ;
}
AMODE    *gen_binary(ENODE *node,int op, int fop,int size)
/*
 *      generate code to evaluate a binary node and return 
 *      the addressing mode of the result.
 */
{       AMODE    *ap1, *ap2, *ap3;
				if (natural_size(node->v.p[0]) <=5 && natural_size(node->v.p[1]) <= 5) {
					ap1 = gen_xbin(node,op,0,size) ;
				
				} else {
					ap1 = gen_fbinary(node,op,size) ;
				}
				return(ap1);
}

AMODE    *gen_xbin(ENODE *node,int op, int op2,int size)
/*
 *      generate code to evaluate a restricted binary node and return 
 *      the addressing mode of the result.
 */
{
					AMODE *ap1, *ap2,*ap3 ;
               prefer(node,&ap1,&ap2,op,TRUE,size);
				
					if (op == op_sub) {
						do_extend(ap1,ap1->length,F_DREG | F_VOL);
					}
					else {
						if ((ap1->mode != am_dreg) || !ap1->tempflag) {
							if (ap2->mode == am_dreg && ap2->tempflag) {
								ap3 = ap1;
								ap1 = ap2;
								ap2 = ap3;
							}
							else {
								int vb;
								do_extend(ap1,ap1->length,F_DREG | F_VOL);
								if (ap2->mode == am_immed) {
									if (op == op_and && (vb = single_bit(~ap2->offset->v.i)) != -1) {
										gen_codes(op2,4,make_immed(vb),ap1);                        	
										return ap1;
									}
									else if ((op == op_or || op == op_eor ) && (vb = single_bit(ap2->offset->v.i))!= -1) {
										gen_codes(op2,4,make_immed(vb),ap1);
										return ap1;
									}
								}
							}
						}
					}
				gen_codes(op,prm_coldfire ? 4 : ap1->length,ap2,ap1) ;
        return ap1;
}
AMODE    *gen_shift(ENODE *node, int op, int size)
/*
 *      generate code to evaluate a shift node and return the
 *      address mode of the result.
 */
{       AMODE    *ap1, *ap2;
        ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size);
				noids(ap1);
        ap2 = gen_expr(node->v.p[1],FALSE,FALSE,size);
				do_extend(ap1,prm_coldfire ? 4 : ap1->length,F_DREG | F_VOL);
				doshift(op,ap2,ap1,ap1->length);
        return ap1;
}

AMODE    *gen_modiv(ENODE *node, int op, int fop, int size, int modflag)
/*
 *      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,*ap3;
				int temp;
				int sz1 = natural_size(node->v.p[0]);
				int sz2 = natural_size(node->v.p[0]);
				int psize;

				if (size > 5) {
					return gen_fbinary(node,fop,size);
				}
				if (sz1 < 0)  sz1 = - sz1;
				if (sz2 < 0)  sz2 = - sz2;
				psize = sz2 > sz1 ? sz2 : sz1;
				if (psize < 2) psize = 2;
				if (op == op_divs)  psize = -psize;
				
				if (prm_68020 ||prm_coldfire || psize ==2 || psize == -2) {
				
					if (!prm_coldfire && psize != 2 && psize != -2)
						if (op == op_divs)
							op = op_divsl;
						else
							op = op_divul;
					resolve_binary(node,&ap1,&ap2,size);
					do_extend(ap1,ap1->length,F_DREG | F_VOL);
					if (prm_coldfire)
                  do_extend(ap2,ap2->length,F_DIVL) ;
					if (psize !=2 && psize != -2) {
						ap3 = temp_data();
						temp = ap3->preg;
						if  (prm_coldfire)
							ap3->mode = am_dreg ;
						else
							ap3->mode = am_divsl;
        		if( modflag ) {
							if (prm_coldfire) {
								ap3->mode = am_divsl;
								if (op == op_divs) {
									op = op_rems;
								}
								else op = op_remu;
							}
							ap3->sreg = ap3->preg = ap1->sreg;
						}
						else {
							ap3->sreg = ap3->preg = ap1->sreg;
						}
						gen_codes(op,psize,ap2,ap3);
						ap3->mode = am_dreg;
						ap3->preg = temp;
						if (modflag && !prm_coldfire)
							gen_code(op_exg,ap1,ap3);
        		freeop(ap3);
					}
					else {
						gen_codes(op,2,ap2,ap1);
						if (modflag) {
							gen_code(op_swap,ap1,0);
						}
					}
        	freeop(ap2);
        	return ap1;
					
				}		
				flush_for_libcall();
				if (op == op_divs) {
        	ap1 = gen_expr(node->v.p[0],FALSE,FALSE,-4);
				}
				else {
        	ap1 = gen_expr(node->v.p[0],FALSE,FALSE,4);
				}
				if (op == op_divs) {
        	ap2 = gen_expr(node->v.p[1],FALSE,FALSE,-4);
				}
				else {
        	ap2 = gen_expr(node->v.p[1],FALSE,FALSE,4);
				}
				do_extend(ap1,4,F_ALL) ;
				gen_codes(op_move,4,ap1,push);
        freeop(ap1);
				do_extend(ap2,4,F_ALL) ;
				gen_codes(op_move,4,ap2,push);
				
				freeop(ap2);
				if (op == op_divs)
					if (modflag) {
						ap1 = call_library("__mods",8);
					}
					else {
						ap1 = call_library("__divs",8);
					}
				else
					if (modflag) {
						ap1 = call_library("__modu",8);
					}
					else {
						ap1 = call_library("__divu",8);
					}
        return ap1;
}

void swap_nodes(ENODE *node)
/*
 *      exchange the two operands in a node.
 */
{       ENODE    *temp;
        temp = node->v.p[0];
        node->v.p[0] = node->v.p[1];
        node->v.p[1] = temp;
}

AMODE * gen_pdiv(ENODE *node, int size)
{
				if (prm_68020)
					return gen_modiv(node,op_divul,op_fdiv,size,FALSE ) ;
				else
					return gen_modiv(node,op_divu,op_fdiv,size,FALSE ) ;
}			
AMODE * gen_pmul(ENODE *node, int size)
{
				AMODE *ap1, *ap2;
				if (isintconst(node->v.p[0]->nodetype))
					swap_nodes(node);
				prefer(node,&ap1,&ap2,op_mulu,FALSE,prm_68020||prm_coldfire ? size : 2) ;
				gen_code(op_muls,ap2,ap1);
				freeop(ap2);
        return ap1;
}			
AMODE    *gen_mul(ENODE *node, int op, int fop, 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;
				int sz1 = natural_size(node->v.p[0]);
				int sz2 = natural_size(node->v.p[0]);
				int psize;

				if (sz1 < 0)  sz1 = - sz1;
				if (sz2 < 0)  sz2 = - sz2;
				psize = sz2 > sz1 ? sz2 : sz1;
				if (psize < 2) psize = 2;
				if (op == op_muls)  psize = -psize;
				
				if (size > 5) {
					return gen_fbinary(node,fop,size);
				}
				if (prm_68020 ||prm_coldfire|| psize == -2 || psize == 2) {
					if (isintconst(node->v.p[0]->nodetype))
						swap_nodes(node);
					prefer(node,&ap1,&ap2,op,FALSE,size) ;
					if (prm_coldfire)
						if (psize == 4 || psize == -4)
                     do_extend(ap2,ap2->length,F_DALT) ;
						else
							do_extend(ap2,ap2->length,F_DIVL);
					gen_codes(op,psize,ap2,ap1);
					freeop(ap2);
        	return ap1;
				}
				flush_for_libcall();
				if (isintconst(node->v.p[0]->nodetype))
					swap_nodes(node);
				if (op == op_muls) {
        	ap1 = gen_expr(node->v.p[0],FALSE,FALSE,-4);
				}
				else {
        	ap1 = gen_expr(node->v.p[0],FALSE,FALSE,4);
				}
				if (op == op_muls) {
        	ap2 = gen_expr(node->v.p[1],FALSE,FALSE,-4);
				}
				else {
        	ap2 = gen_expr(node->v.p[1],FALSE,FALSE,4);
				}
				do_extend(ap1,4,F_ALL) ;
				gen_codes(op_move,4,ap1,push);
        freeop(ap1);
				do_extend(ap2,4,F_ALL) ;
				gen_codes(op_move,4,ap2,push);
				freeop(ap2);
				if (op == op_muls) {
					ap1 = call_library("__muls",8);
				}
				else {
					ap1 = call_library("__mulu",8);
				}
        return ap1;
}

AMODE    *gen_hook(ENODE *node, int size)
/*
 *      generate code to evaluate a condition operator node (?:)
 */
{       AMODE    *ap1, *ap2;
        int             false_label, end_label;
				int sizl,sizr,xsiz;
				sizr = natural_size(node->v.p[1]->v.p[1]);
				sizl = natural_size(node->v.p[1]->v.p[0]);
				sizl = sizl < 0 ? - sizl : sizl;
				sizr = sizr < 0 ? - sizr : sizr;
				if (sizl < sizr)
					xsiz = sizr;
				else 
					xsiz = sizl;
        false_label = nextlabel++;
        end_label = nextlabel++;
        falsejp(node->v.p[0],false_label);
        node = node->v.p[1];
        ap1 = gen_expr(node->v.p[0],FALSE,FALSE,size);
				do_extend(ap1,xsiz,F_DREG | F_VOL);
				freeop(ap1);
        gen_codes(op_jmp,0,make_label(end_label),0);
        gen_label(false_label);
        ap2 = gen_expr(node->v.p[1],FALSE,FALSE,size);
				do_extend(ap2,xsiz,F_DREG | F_VOL);
        if( !equal_address(ap1,ap2) )
                {
								/* if both are floating they won't get here */
								if (ap1->mode == am_freg) {
									do_extend(ap2,10,F_FREG| F_VOL);
								}
								else {
									if (ap2->mode == am_freg) {
										if (ap1->length == 5 || ap1->length != 4 && ap1->length != -4)
											do_extend(ap1,4,F_DREG | F_VOL) ;
										gen_codef(op_fmove,ap1->length,ap2,ap1) ;
									} else
										gen_code(op_move,ap2,ap1);
									freeop(ap2);
									ap2->mode = ap1->mode;
									ap2->preg = ap1->preg;
									dregs[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.
 */
{       AMODE    *ap,*ap1;
				int nsize = natural_size(node->v.p[0]);
        ap = gen_expr(node->v.p[0],novalue,TRUE,nsize);
				if (size > 5) {
					AMODE ap1 = *ap ;
					tofloat(ap,ap->length);
					gen_codef(fop,ap->length,ap,0);
					gen_code(op_fmove,ap,&ap1) ;
				}
				else {
        	gen_codes(op,size,ap,0);
				}
        return ap;
}
AMODE    *gen_asadd(ENODE *node, int novalue, int op, int fop, int size)
/*
 *      generate a plus equal or a minus equal node.
 */
{       AMODE    *ap1, *ap2, *apr;
				int bits;
				int nsize = natural_size(node->v.p[0]);
				if (natural_size(node) > 5) {
					ap1 = gen_fbinary(node,fop,nsize);
					return floatstore(node->v.p[0],ap1,novalue);
				}
				bits = as_args(node,&apr,&ap1,&ap2,nsize);
				small_size(ap1,ap2,nsize);
				if (!bits) {
					if (ap1->mode != am_dreg && ap2->mode != am_dreg && ap2->mode != am_immed)
						do_extend(ap2,ap1->length,F_DREG);
               if (prm_coldfire && nsize < 4 && nsize != -4) {
                  AMODE *ap3 = copy_addr(apr) ;
                  do_extend(ap3,4,F_DREG | F_VOL) ;
                  gen_code(op,ap2,ap3) ;
                  ap3->length = nsize ;
                  gen_code(op_move,ap3,apr) ;
               } else
                  gen_code(op,ap2,apr);
					freeop(ap1);
					freeop(ap2);
					return apr;
				}
				else {
					gen_code(op,ap2,ap1);
					bit_store(ap1,apr,node->v.p[0],novalue);
					freeop(ap2);
					freeop(apr);
					return ap1;
				}
}

AMODE    *gen_aslogic(ENODE *node, int novalue, int op, int op2,int size )
/*
 *      generate a and equal or a or equal node.
 */
{       AMODE    *ap1, *ap2, *apr, *ap3;
				int bits = isbit(node->v.p[0]);
				int nsize = natural_size(node->v.p[0]);
				if (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 &= bittab[node1->bits-1];
						ap3 = make_immed(ap2->offset->v.i << node1->startbit);
						if (op == op_and) {
							ap3->offset->v.i |= ~(bittab[node1->bits-1] << node1->startbit);
							ap3->offset->v.i = ~ap3->offset->v.i;
							vb = single_bit(ap3->offset->v.i);
                     if (!prm_coldfire && vb != -1 && apr->mode == am_dreg)
								gen_codes(op_bclr,4,make_immed(vb),apr);
							else {
								ap3->offset->v.i = ~ap3->offset->v.i;
                        if (prm_coldfire && nsize < 4 && nsize != -4) {
                           AMODE *ap4 = copy_addr(apr) ;
                           do_extend(ap4,4,F_DREG | F_VOL) ;
                           gen_code(op_and,ap3,ap4) ;
                           ap4->length = nsize ;
                           gen_code(op_move,ap4,apr) ;
                        } else
                           gen_code(op_and,ap3,apr);
							}
						}
						else {
							vb = single_bit(ap3->offset->v.i);
                     if (!prm_coldfire && vb != -1 && apr->mode == am_dreg)
								gen_codes(op2,4,make_immed(vb),apr);
							else
                        if (prm_coldfire && nsize < 4 && nsize != -4) {
                           AMODE *ap4 = copy_addr(apr) ;
                           do_extend(ap4,4,F_DREG | F_VOL) ;
                           gen_code(op_and,ap3,ap4) ;
                           ap4->length = nsize ;
                           gen_code(op_move,ap4,apr) ;
                        } else
                           gen_code(op,ap3,apr);
						}
						return ap2;
					}
					else {
						do_extend(ap2,ap2->length,F_DREG | F_VOL);
						gen_code(op_and,make_immed(bittab[node->v.p[0]->bits-1]),ap2);
						if (chksize(ap2->length,apr->length))
							ap2->length = apr->length;
						if (!novalue)
							gen_codes(op_move,4,ap2,push);
						if (node->v.p[0]->startbit)
							doshift(op_asl,make_immed(node->v.p[0]->startbit),ap2,ap2->length);
						if (op == op_and)
							gen_code(op_or,make_immed(~(bittab[node->v.p[0]->bits-1] << node->v.p[0]->startbit)),ap2);
                  if (prm_coldfire && nsize < 4 && nsize != -4) {
                     AMODE *ap4 = copy_addr(apr) ;
                     do_extend(ap4,4,F_DREG | F_VOL) ;
                     gen_code(op_and,ap2,ap4) ;
                     ap4->length = nsize ;
                     gen_code(op_move,ap4,apr) ;
                  } else
                     gen_code(op,ap2,apr);
						freeop(apr);
						if (!novalue)
							gen_codes(op_move,4,pop,ap2);
						else freeop(ap2);
						return ap2;
					}
				}
				else {
					int vb;
					as_args(node,&apr,&ap1, &ap2,nsize);
					small_size(ap1,ap2,nsize);
					if (ap1->mode != am_dreg && ap2->mode != am_dreg && ap2->mode != am_immed)
						do_extend(ap2,ap2->length,F_DREG | F_VOL);
					if (ap2->mode == am_immed) {
						if (op == op_and && (vb = single_bit(~ap2->offset->v.i))!= -1 && ap1->mode == am_dreg) {
							gen_codes(op2,4,make_immed(vb),ap1);                        	
							freeop(ap1);
							return apr;
						}
						else if ((vb = single_bit(ap2->offset->v.i)) != -1 && ap1->mode == am_dreg){
							gen_codes(op2,4,make_immed(vb),ap1);
							freeop(ap1);
							return apr;
						}
					}
               if (prm_coldfire && nsize < 4 && nsize != -4) {
                  AMODE *ap4 = copy_addr(apr) ;
                  do_extend(ap4,4,F_DREG | F_VOL) ;
                  gen_code(op_and,ap2,ap4) ;
                  ap4->length = nsize ;
                  gen_code(op_move,ap4,apr) ;
               } else
                  gen_code(op,ap2,apr);
					freeop(ap1);
					freeop(ap2);
        	return apr;
				}
}

AMODE *gen_asshift(ENODE *node, int novalue, int op, int size)
/*
 *      generate shift equals operators.
 */
{       AMODE    *ap1, *ap2, *apr;
				int nsize = natural_size(node->v.p[0]);
				int bits = as_args(node,&apr,&ap1,&ap2,nsize);
				
				if (op == op_asl || op == op_lsl)
					small_size(ap1,ap2,nsize);
				else
					get_size(ap1,ap2,nsize);
				if (!bits) {
               if (prm_coldfire && nsize < 4 && nsize != -4) {
                  AMODE *ap4 = copy_addr(apr) ;
                  do_extend(ap4,4,F_DREG | F_VOL) ;
                  gen_code(op_and,ap2,ap4) ;
                  ap4->length = nsize ;
                  gen_code(op_move,ap4,apr) ;
               } else
                  doshift(op,ap2,apr,nsize);
               freeop(ap2) ;
					return apr;
				}
				else {
					do_extend(ap1,4,F_DREG | F_VOL);
					doshift(op,ap2,ap1,nsize);
					bit_store(ap1,apr,node->v.p[0],novalue);
					freeop(apr);
					return ap1;
				}
}

AMODE    *gen_asmul(ENODE *node, int novalue, int op, int fop, int size)
/*
 *      generate a *= node.
 */
{       AMODE    *ap1, *ap2, *ap3, *ap4,*apr;
				int bits ;
				int nsize = natural_size(node->v.p[0]);
				if (natural_size(node) > 5) {
					ap1 = gen_fbinary(node,fop,nsize);
					return floatstore(node->v.p[0],ap1,novalue);
				}
            if (prm_coldfire || prm_68020 || nsize == 2 || nsize == -2) {
					bits = as_args(node,&apr,&ap1,&ap2,nsize);
					small_size(ap1,ap2,nsize);
					if (!bits) {
						if (ap1->mode != am_dreg) {
							if (ap2->mode != am_dreg) 
								do_extend(ap2,ap2->length,F_DREG | F_VOL);
							gen_code(op_mulu,ap1,ap2) ;
							freeop(ap1);
							gen_code(op_move,ap2,apr);
							if (novalue)
								freeop(ap2);
							return ap2;
						}
						else {
							gen_code(op_mulu,ap2,ap1) ;
							freeop(ap2);
							if (!equal_address(ap1,apr)) {
								gen_code(op_move, ap1,apr);
								if (novalue)
							 		freeop(ap1);
								return ap1;
							}
							freeop(ap1);
						}
						return apr;
					} else {
						gen_code(op_mulu,ap2,ap1) ;
						bit_store(ap1,apr,node->v.p[0],novalue);
						freeop(ap2);
						freeop(apr);
						return ap1;
					}
				}
				flush_for_libcall();
				bits = as_args(node,&apr,&ap1,&ap2,nsize);
				small_size(ap1,ap2,nsize);
					
				if (op == op_muls) {
					do_extend(ap2,-4,F_ALL);
				}
				else {
					do_extend(ap2,4,F_ALL);
				}
				gen_codes(op_move,4,ap2,push);
        freeop(ap2);
				if (op == op_muls) {
					do_extend(ap1,-4,F_ALL) ;
				}
				else {
					do_extend(ap1,4,F_ALL) ;
				}
				gen_codes(op_move,4,ap1,push);
				freeop(ap1);
				if (op == op_muls) {
					ap1 = call_library("__muls",8);
				}
				else {
					ap1 = call_library("__mulu",8);
				}
				if (node->v.p[0]->nodetype == en_bits)
					bit_store(ap1,apr,node->v.p[0],novalue);
				else
        	gen_codes(op_move,nsize,ap1,apr);
				if (novalue)
					freeop(ap1);
        return ap1;
}

AMODE    *gen_asmodiv(ENODE *node, int novalue,int op, int fop, int size, int modflag)
/*
 *      generate /= and %= nodes.
 */
{       AMODE    *ap1, *ap2, *ap3 = 0, *ap4,*ap5,*apr;
        int             siz1,temp;
				int bits;
				int nsize = natural_size(node->v.p[0]);
				if (natural_size(node) > 5) {
					ap1 = gen_fbinary(node,fop,nsize);
					return floatstore(node->v.p[0],ap1,novalue);
				}
            if (prm_coldfire || prm_68020 || nsize == 2 || nsize == -2) {
					bits = as_args(node,&apr,&ap1,&ap2,nsize);
					small_size(ap1,ap2,nsize);
               if (!prm_coldfire && ap1->length !=2 && ap1->length != -2)
						if (op == op_divs) 
							op = op_divsl;
						else
							op = op_divul;
					if (!bits) { 
						do_extend(ap1,nsize,F_DREG | F_VOL) ;
						if (nsize != 2 && nsize != -2) {
							ap4 = temp_data();
							ap4->tempflag = TRUE;
                     if (prm_coldfire)
                        ap4->mode = am_divsl ;
							temp = ap4->preg;
      	  		if( modflag ) {
								gen_codes(op_move,4,ap1,ap4);
								ap4->sreg = ap1->preg;
                        if (prm_coldfire) {
                           if (op == op_divs) {
                              op = op_rems;
                           }
                           else {
                              op = op_remu;
                           }
                        }
							}
							else {
								ap4->sreg = ap4->preg = ap1->preg;
							}
							ap4->mode = am_divsl;
							gen_codes(op,nsize,ap3,ap4);
							ap4->mode = am_dreg;
							ap4->preg = temp;
							freeop(ap4);
      	  		freeop(ap3);
						}
						else {
							gen_codes(op,nsize,ap3,ap1);
							if (modflag)
								gen_codes(op_swap,0,ap1,0);
						}
						freeop(ap3);
					}
					if (node->v.p[0]->nodetype == en_bits)
						bit_store(ap1,apr,node->v.p[0],size);
					else
  	      	gen_codes(op_move,siz1,ap1,apr);
					if (novalue)
						freeop(ap1);
					return ap1 ;
				}
				flush_for_libcall();
				bits = as_args(node,&apr,&ap1,&ap2,nsize);
				small_size(ap1,ap2,nsize);
				if (op == op_divs) {
					do_extend(ap2,- 4,F_ALL);
				}
				else {
					do_extend(ap2,4,F_ALL);
				}
				gen_codes(op_move,4,ap2,push);
        freeop(ap2);
				if (op == op_divs) {
					do_extend(ap1,- 4,F_ALL);
				}
				else {
					do_extend(ap1,4,F_ALL);
				}
				gen_codes(op_move,4,ap1,push);
				freeop(ap1);
				if (modflag)
					if (op == op_divs)
						ap1=call_library("__mods",8);
					else
						ap1=call_library("__modu",8);
				else
					if (op == op_divs)
						ap1=call_library("__divs",8);
					else
						ap1=call_library("__divu",8);
				if (node->v.p[0]->nodetype == en_bits)
					bit_store(ap1,apr,node->v.p[0],nsize);
				else
  	     	gen_codes(op_move,nsize,ap1,apr);
				if (novalue)
					freeop(ap1);
        return ap1;
}
void mov1(AMODE *src, AMODE *dst, int size)
{
	gen_codes(op_move,size,src,dst);
	freeop(src);
	freeop(dst);
	
}
void mov2(AMODE *src, AMODE *dst, int size1,int size2)
{
	AMODE *dst1,*src1;
	gen_codes(op_move,size1,src,dst);
	src->offset = makenode(en_add,src->offset,makenode(en_icon,(char *)size1,0));
	dst->offset = makenode(en_add,dst->offset,makenode(en_icon,(char *)size1,0));
	gen_codes(op_move,size2,src,dst);
	freeop(src);
	freeop(dst);
}
void mov3(AMODE *src, AMODE *dst, int size1,int size2,int size3) 
{
	AMODE *dst1,*src1;
	gen_codes(op_move,size1,src,dst);
	src->offset = makenode(en_add,src->offset,makenode(en_icon,(char *)size1,0));
	dst->offset = makenode(en_add,dst->offset,makenode(en_icon,(char *)size1,0));
	gen_codes(op_move,size2,src,dst);
	src->offset = makenode(en_add,src->offset,makenode(en_icon,(char *)size2,0));
	dst->offset = makenode(en_add,dst->offset,makenode(en_icon,(char *)size2,0));
	gen_codes(op_move,size3,src,dst);
	freeop(src);
	freeop(dst);
}
AMODE *amode_moveblock(AMODE *ap1, AMODE *ap2, int size)
{
	int lbl;
	long v,tp,sz;
	int t = size & 3,q=size >> 2;
	AMODE *ap3,*ap4,apcount;

	switch(size) {
		case 1:
		case 2:
		case 4:
			mov1(ap1,ap2,size);
			break;
		case 3:
			mov2(ap1,ap2,2,1);
			break;
		case 5:
			mov2(ap1,ap2,4,1);
			break;
		case 6:
			mov2(ap1,ap2,4,2);
			break;
		case 7:
			mov3(ap1,ap2,4,2,1);
			break;
		case 8:
			mov2(ap1,ap2,4,4);
			break;
		case 9:
			mov3(ap1,ap2,4,4,1);
			break;
		case 10:
			mov3(ap1,ap2,4,4,2);
			break;
		case 12:
			mov3(ap1,ap2,4,4,4);
			break;
		default:
			if (!(sz=size))
				return(0);
			if (sz & 1) {
				tp = 1;
			}
			else if (sz & 2) {
				tp = 2;
			}
			else {
				tp = 4;
			}
			v = sz/tp;
			if (v < 65536)
				v--;
			lbl = nextlabel++;
			if (ap1->mode != am_areg) {
				ap3 = temp_addr() ;
				gen_code(op_lea,ap1,ap3) ;
				freeop(ap1) ;
				ap1->preg = ap3->preg ;
				ap1->length = 4 ;
			}
			if (ap2->mode != am_areg) {
				ap3 = temp_addr() ;
				gen_code(op_lea,ap2,ap3) ;
				freeop(ap2) ;
				ap2->preg = ap3->preg ;
				ap2->length = 4 ;
			}
			ap3 = temp_data();
			ap2->mode = am_ainc;
			ap1->mode = am_ainc;
			gen_codes(op_move,v < 65536 ? 2 : 4,make_immed(v),ap3);
			gen_label(lbl);
			gen_codes(op_move,tp,ap1,ap2);
			if (v < 65536) 
				gen_codes(op_dbra,0,ap3,make_label(lbl));
			else {
				gen_codes(op_sub,4,make_immed(1),ap3);
				gen_codes(op_bne,0,make_label(lbl),0);
			}
			freeop(ap3);
			freeop(ap1);
			freeop(ap2);
			return(ap2);
	}
	freeop(ap2);
	freeop(ap1);
}
AMODE *gen_moveblock(ENODE *node)      
{                                                           
	AMODE *ap1, *ap2;
	ENODE ep1 ;
	if (!node->size)                                          
		return(0);
	ep1.nodetype = en_l_ref ;
	ep1.cflags = 0;
	ep1.v.p[0] = node->v.p[1] ;
	ap2 = gen_expr(&ep1,FALSE,TRUE,0);                     
	noids(ap2);
	ep1.nodetype = en_l_ref ;
	ep1.cflags = 0;
	ep1.v.p[0] = node->v.p[0] ;
	ap1 = gen_expr(&ep1,FALSE,TRUE,0); 
	return amode_moveblock(ap1,ap2,node->size);
}
int count_regs(AMODE *ap1, AMODE *ap2)
{
	int r = 0;
	switch(ap1->mode) {
		case am_baseindxaddr:
			if (ap1->sreg < cf_freeaddress && ap1->sreg != -1)
				r++;
		case am_baseindxdata:
		case am_ind:
		case am_indx:
		case am_areg:
			if (ap1->preg < cf_freeaddress && ap1->preg != -1)
				r++;
			break;
	}
	switch(ap2->mode) {
		case am_baseindxaddr:
			if (ap2->sreg < cf_freeaddress && ap2->sreg != -1)
				r++;
		case am_baseindxdata:
		case am_ind:
		case am_indx:
		case am_areg:
			if (ap2->preg < cf_freeaddress && ap2->preg != -1)
				r++;
			break;
	}
	return r;
}
AMODE    *gen_assign(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    *ap2, *apr, *ap3;
				int bits;
				int nsize = natural_size(node->v.p[0]);
				ap2 = gen_expr(node->v.p[1],FALSE,FALSE,nsize);
				noids(ap2);
				apr = gen_expr(node->v.p[0],FALSE,TRUE,nsize);
				if (ap2->length > 5) {
					do_extend(ap2,10,F_FREG);
					if (isbit(node->v.p[0])) {
						ap3 = temp_data() ;
						gen_codef(op_fmove,4,ap2,ap3) ;
						bit_store(ap3,apr,node->v.p[0],natural_size(apr)) ;
						freeop(ap3) ;
				
					} else
						gen_codef(op_fmove,apr->length,ap2,apr) ;
					freeop(apr) ;
					return ap2 ;
				}
				small_size(apr,ap2,nsize);
				bits = isbit(node->v.p[0]);
				if (!equal_address(apr,ap2)	) {
					if (!bits) {
						if (apr->length > 5) {
							do_extend(ap2,apr->length,F_FREG);
							gen_codef(op_fmove,apr->length,ap2,apr) ;
							freeop(ap2) ;
							return apr ;
						}
						else {
							do_extend(ap2,apr->length,F_ALL);
                     if (!prm_coldfire)
                        gen_codes(op_move,apr->length,ap2,apr);
                     else {
                           if (opcomb[(ap2->mode*43) + apr->mode])
                           /* Check here for ColdFire move restrictions */
                                gen_code(op_move,ap2,apr);
                              else
                              {
                                /* Check for #0,<mode> and allow since clr will replace */
                                if (ap2->mode == am_immed && ap2->offset->v.i == 0)
                                {              
                                   gen_codes(op_move,nsize,ap2,apr);
                                }
                                else
                                {
                                   do_extend(ap2,nsize,F_DREG|F_VOL) ;
                                   gen_codes(op_move,nsize,ap2,apr);
                                }
                              }
                     }
							if (!novalue && (ap2->mode == am_dreg || ap2->mode == am_immed)) {
								freeop(apr);
								return ap2;
							}
							freeop(ap2);
							return apr;
						}
					}
					else {
						bit_store(ap2,apr,node->v.p[0],novalue);
						freeop(apr);
						return ap2;
					}
				}
				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, *ap3;
				int nsize = natural_size(node->v.p[0]);
				int bits = as_args(node,&apr,&ap1,&ap2,nsize);
				if (natural_size(node->v.p[0]) > 5) {
					do_extend(ap2,ap1->length,F_FREG);
					if (isbit(node->v.p[0])) {
						ap3 = temp_data() ;
						gen_codef(op_fmove,4,ap2,ap3) ;
						bit_store(ap3,apr,node->v.p[1],natural_size(apr)) ;
						freeop(ap3) ;
				
					} else
						gen_codef(op_fmove,apr->length,ap2,apr) ;
					ap4 = temp_addr();
					gen_code(op_lea,apr,ap4);
					freeop(apr) ;
					return ap4;
				}
				if (!equal_address(apr,ap2)	) {
					if (!bits) {
						if (apr->length > 5) {
							gen_codef(op_fmove,apr->length,ap2,apr) ;
							ap4 = temp_data() ;
							gen_code(op_lea,apr,ap2) ;
							return ap4 ;
						}
						do_extend(ap2,ap1->length,F_ALL);
						gen_code(op_move,ap2,apr);
						ap4 = temp_data();
						gen_code(op_lea,apr,ap4);
						freeop(ap1);
						freeop(ap2);
						freeop(apr);
						return ap4;
					}
					else {
						bit_store(ap2,apr,node->v.p[0],novalue);
						freeop(ap1);
						freeop(apr);
						return ap2;
					}
				}
				freeop(ap1);
				freeop(ap2);
				return apr;
}

AMODE    *gen_aincdec(ENODE *node, int novalue, int op,int fop, int size)
/*
 *      generate an auto increment or decrement node. op should be
 *      either op_add (for increment) or op_sub (for decrement).
 */
{       AMODE    *ap1,*ap2,*ap3;
				int pushed = FALSE,sz;
				int nsize = natural_size(node->v.p[0]);
				ap2 = make_immed((long)node->v.p[1]);
				ap1 = gen_expr(node->v.p[0],FALSE,FALSE,nsize);
				sz = ap1->length;
				if (sz > 5) {
					tofloat(ap1,sz) ;
					tofloat(ap2,ap2->length) ;
					gen_codef(fop,10,ap1,ap2); 	
					freeop(ap1);
					return ap2 ;
				}
				else if (isbit(node->v.p[0])) {
               ap3 = gen_expr(node->v.p[0],FALSE,FALSE,sz);
               gen_codes(op,prm_coldfire ? 4 : sz,ap2,ap3);
					bit_store(ap3,ap1,node->v.p[0],novalue);
					freeop(ap1);
					if (novalue)
						freeop(ap3);
					return ap3 ;
				}
				else {
					freeop(ap1);
					if (!novalue) {
						int reg = next_dreg();
/*FIXME*/
						if ((ap1->mode == am_ind  || ap1->mode == am_indx || ap1->mode == am_ainc || ap1->mode== am_adec) && ap1->preg == reg ||
								(ap1->mode == am_baseindxdata || ap1->mode == am_baseindxaddr)&& (ap1->preg == reg || ap1->sreg == reg) ||
								(ap1->mode == am_pcindxdata || ap1->mode == am_pcindxaddr) && ap1->preg == reg) {
							gen_codes(op_move,4,ap1,push);
							pushed = TRUE;
						}
						else {
							ap3 = temp_data();
							gen_codes(op_move,sz,ap1,ap3);
						}
					}
               gen_codes(op,prm_coldfire ? 4 : sz,ap2,ap1);
					if (pushed) {
						ap3 = temp_data();
						gen_codes(op_move,4,pop,ap3);
					}
				}
				if (!novalue)
					ap3->length = sz;
				return ap3;
}

int push_param(ENODE *ep,int size)
/*
 *      push the operand expression onto the stack.
 */
{       AMODE    *ap,*ap1;
				int rv = size;
				if (rv < 0) rv = - rv;
				switch (ep->nodetype) {
                case en_napccon:
												ep->v.p[0] = ep->v.sp;
                case en_labcon:
                        ap = xalloc(sizeof(AMODE));
												if (prm_rel)
			  	              	ap->mode = am_pcindx;
												else {
													ap->mode = am_adirect;
													if (prm_smallcode)
														ap->preg = 2;
													else
														ap->preg = 4;
												}
                        ap->offset = ep;     /* use as constant node */
                        gen_codes(op_pea,0,ap,0);
												gen_code(op_void,0,0);
												rv = 4;
												break;
								case en_absacon:
                        ap = xalloc(sizeof(AMODE));
                        ap->mode = am_adirect;
												ep->v.i = ((SYM *)ep->v.p[0])->value.i;
												ap->preg = isshort(ep) ? 2 : 4;
                        ap->offset = ep;     /* use as constant node */
                        gen_codes(op_pea,0,ap,0);
												gen_code(op_void,0,0);
												rv = 4;
												break;
                case en_nacon:
												ep->v.p[0] = ep->v.sp;
								case en_nalabcon:
                        ap = xalloc(sizeof(AMODE));
												if (prm_rel) {
	                        ap->preg = basereg;          /* frame pointer */
													if (prm_largedata) {
														ap1 = temp_addr();
														ap->mode = am_areg;
														gen_codes(op_move,4,ap,ap1);
														ap->mode = am_immed;
														ap->offset = ep;
														gen_codes(op_add,4,ap,ap1);
														ap = ap1;
														ap->mode = am_ind;
                    	    	gen_codes(op_move,4,ap,push);
												    ap->mode = am_areg;
														freeop(ap);
														gen_code(op_void,0,0);
													}                  
													else {
                        		ap->mode = am_indx;
	                        	ap->offset = ep;     /* use as constant node */
														gen_codes(op_pea,4,ap,0);
														gen_code(op_void,0,0);
													}          
												}
												else {
													ap->mode = am_adirect;
					          	    ap->offset = ep;
													if (prm_smalldata) {
														ap->preg = 2;
													}
													else {
														ap->preg = 4;
													}
												  gen_codes(op_pea,4,ap,0);
													gen_code(op_void,0,0);
												}
												rv = 4;
												break;
								case en_cf:
								case en_floatref:
								case en_fcon:
												ap = gen_expr(ep,FALSE,TRUE,6);
												do_extend(ap,6,F_FREG|F_MEM) ;
												if (ap->mode == am_freg)
													gen_codef(op_fmove,6,ap,push);
												else
													gen_codes(op_move,6,ap,push);
												gen_code(op_void,0,0);
												rv = 4;
												break;
								case en_cd:
								case en_doubleref:
								case en_rcon:
												ap = gen_expr(ep,FALSE,TRUE,8);
												do_extend(ap,8,F_FREG) ;
												gen_codef(op_fmove,8,ap,push);
													gen_code(op_void,0,0);
												rv = 8;
												break;
								case en_lrcon:
								case en_cld:
								case en_longdoubleref:
												ap = gen_expr(ep,FALSE,TRUE,10);
												do_extend(ap,10,F_FREG) ;
												gen_codef(op_fmove,10,ap,push);
													gen_code(op_void,0,0);
												rv = 12;
												break;
								default:
      			  					ap = gen_expr(ep,FALSE,TRUE,size);
												if (size <= 5) {
													while(castvalue(ep))
														ep = ep->v.p[0] ;
													if (isbit(ep))
														ap = bit_load(ap,ep,4) ;
												}
												if ((size < 4 || size == 5) && size >-4 && ap->mode != am_immed)  {
													do_extend(ap,4,F_DREG);
													rv = 4;
												}
												if (ap->mode == am_freg) {
													if (rv == 6)
														rv = 4;
													if (rv == 10)
														rv = 12;
													gen_codef(op_fmove,size,ap,push);
												}
												else {
													gen_codes(op_move,rv,ap,push);
													rv = 4;
												}
												gen_code(op_void,0,0);
												break;
				}
        freeop(ap);
	stackdepth += rv;
	return(rv);
}
int push_stackblock(ENODE *ep)
{
	AMODE *ap,*ap1,*ap2;
	SYM *sp;
	int x,lbl,v;
	int sz = (ep->size + stackadd) &stackmod;
	if (!sz)
		return(0);
	if (sz > 24) {
				switch (ep->nodetype) {
                case en_napccon:
												ep->v.p[0] = ep->v.sp;
                case en_labcon:
                        ap = xalloc(sizeof(AMODE));
												if (prm_rel)
			  	              	ap->mode = am_pcindx;
												else {
													ap->mode = am_adirect;
													if (prm_smallcode)
														ap->preg = 2;
													else
														ap->preg = 4;
												}
                        ap->offset = makenode(en_add,ep,makenode(en_icon,(char *)sz,0));     /* use as constant node */
                        gen_lea(0,ap,ap2 = temp_addr());
												break;
								case en_absacon:
												ep->v.i = ep->v.sp->value.i;
                        ap = xalloc(sizeof(AMODE));
                        ap->mode = am_adirect;
												ap->preg = isshort(ep) ? 2 : 4;
                        ap->offset = makenode(en_add,ep,makenode(en_icon,(char *)sz,0));     /* use as constant node */
                        gen_lea(0,ap,ap2 = temp_addr());
												break;
                case en_nacon:
												ep->v.p[0] = ep->v.sp;
								case en_nalabcon:
												ap1 = 0;
                        ap = xalloc(sizeof(AMODE));
												if (prm_rel) {
	                        ap->preg = basereg;          /* frame pointer */
							
													if (prm_largedata) {
														ap1 = temp_addr();
														ap->mode = am_areg;
														gen_codes(op_move,4,ap,ap1);
														ap->mode = am_immed;
														ap->offset = ep;
														gen_codes(op_add,4,ap,ap1);
														ap = ap1;
														ap->mode = am_ind;
													}
													else {
                        		ap->mode = am_indx;
	                        	ap->offset = ep;     /* use as constant node */
													}
												}
												else {
													ap->mode = am_adirect;
					          	    ap->offset = ep;
													if (prm_smalldata) {
														ap->preg = 2;
													}
													else {
														ap->preg = 4;
													}
												}
                        ap->offset = makenode(en_add,ep,makenode(en_icon,(char *)sz,0));     /* use as constant node */
                        gen_lea(0,ap,ap2 = temp_addr());
												if (ap1) {
													ap1->mode = am_areg;
													freeop(ap1);
												}
												break;
                case en_autocon:
                case en_autoreg:
												ep->v.i = ep->v.sp->value.i;
                        ap = xalloc(sizeof(AMODE));
                        ap->mode = am_indx;
												if (prm_linkreg && !currentfunc->intflag) {
			                		ap->preg = linkreg;
                        	ap->offset = makenode(en_add,ep,makenode(en_icon,(char *)sz,0));     /* use as constant node */
												}
					 							else if (ep->v.sp->funcparm ) {
													if (prm_phiform || currentfunc->intflag) {
                        		ap->preg = linkreg;          /* frame pointer */
                        		ap->offset = makenode(en_add,ep,makenode(en_icon,(char *)sz,0));     /* use as constant node */
													}
													else {
														ap->preg = 7;
                        		ap->offset = makenode(en_add,ep,makenode(en_icon,(char *)(sz+stackdepth+framedepth),0));     /* use as constant node */
													}
                				}
												else {
													ap->preg = 7;
                        	ap->offset = makenode(en_add,ep,makenode(en_icon,(char *)(sz+stackdepth+lc_maxauto),0));     /* use as constant node */
												}
                        gen_lea(0,ap,ap2 = temp_addr());
												break;
								default:
												ap = 0;
      			  					ap2 = gen_expr(ep,FALSE,TRUE,0);
												do_extend(ap2,4,F_AREG | F_VOL) ;
												gen_codes(op_add,4,make_immed(sz),ap2);
												break;
				}
				lbl = nextlabel++;
				ap1 = temp_data();
  			v = sz/4;
				if (v < 65536)
					v--;
				gen_codes(op_move,v < 65536 ? 2 : 4,make_immed(v),ap1);
				gen_label(lbl);
				ap2->mode = am_adec;
				gen_codes(op_move,4,ap2,push);
            if (!prm_coldfire && v < 65536) {
					gen_codes(op_dbra,0,ap1,make_label(lbl));
				}
				else {
					gen_codes(op_sub,4,make_immed(1),ap1);
					gen_codes(op_bne,0,make_label(lbl),0);
				}
				freeop(ap1);
				freeop(ap2);
				if (ap)
  				freeop(ap);
	} else {
				int i = ((sz +3)/4)*4;
				switch (ep->nodetype) {
                case en_napccon:
												ep->v.p[0] = ep->v.sp;
                case en_labcon:
                        ap = xalloc(sizeof(AMODE));
												if (prm_rel)
			  	              	ap->mode = am_pcindx;
												else {
													ap->mode = am_adirect;
													if (prm_smallcode)
														ap->preg = 2;
													else
														ap->preg = 4;
												}
                        ap->offset = ep ;
												break;
								case en_absacon:
												ep->v.i = ep->v.sp->value.i;
                        ap = xalloc(sizeof(AMODE));
                        ap->mode = am_adirect;
												ap->preg = isshort(ep) ? 2 : 4;
                        ap->offset = ep ;
												break;
                case en_nacon:
												ep->v.p[0] = ep->v.sp;
								case en_nalabcon:
												ap1 = 0;
                        ap = xalloc(sizeof(AMODE));
												if (prm_rel) {
	                        ap->preg = basereg;          /* frame pointer */
							
													if (prm_largedata) {
														ap1 = temp_addr();
														ap->mode = am_areg;
														gen_codes(op_move,4,ap,ap1);
														ap->mode = am_immed;
														ap->offset = ep;
														gen_codes(op_add,4,ap,ap1);
														ap = ap1;
														ap->mode = am_ind;
													}
													else {
                        		ap->mode = am_indx;
	                        	ap->offset = ep;     /* use as constant node */
													}
												}
												else {
													ap->mode = am_adirect;
					          	    ap->offset = ep;
													if (prm_smalldata) {
														ap->preg = 2;
													}
													else {
														ap->preg = 4;
													}
												}
                        ap->offset = ep ;
												if (ap1) {
													ap1->mode = am_areg;
													freeop(ap1);
												}
												break;
                case en_autocon:
                case en_autoreg:
												ep->v.i = ep->v.sp->value.i;
                        ap = xalloc(sizeof(AMODE));
                        ap->mode = am_indx;
												if (prm_linkreg && !currentfunc->intflag) {
			                		ap->preg = linkreg;
                        	ap->offset = ep ;     /* use as constant node */
												}
					 							else if (ep->v.sp->funcparm ) {
													if (prm_phiform || currentfunc->intflag) {
                        		ap->preg = linkreg;          /* frame pointer */
                        		ap->offset = ep ;
													}
													else {
														ap->preg = 7;
                        		ap->offset = makenode(en_add,ep,makenode(en_icon,(char *)(stackdepth+framedepth),0));     /* use as constant node */
													}
                				}
												else {
													ap->preg = 7;
                        	ap->offset = makenode(en_add,ep,makenode(en_icon,(char *)(stackdepth+lc_maxauto),0));     /* use as constant node */
												}
												break;
								default:
												ap = 0;
      			  					ap = gen_expr(ep,FALSE,TRUE,4);
												do_extend(ap,4,F_ALL) ;
												break;
				}
				while (i > 0) {
					AMODE *ap1 = xalloc(sizeof(AMODE));
					memcpy(ap1,ap,sizeof(AMODE));
					ap1->offset = makenode(en_addstruc,ap->offset,makenode(en_icon,(char *)(i-4),0));
					gen_codes(op_move,4,ap1,push);
					i = i - 4;
				}
				
	}
	return(sz);
}

int     gen_parms(ENODE *plist,int size)
/*
 *      push a list of parameters onto the stack and return the
 *      size of parameters pushed.
 */
{       int     i;
        i = 0;
        while( plist != 0 )
                {         	
								if (plist->nodetype == en_stackblock)
									i+=push_stackblock(plist->v.p[0]);
								else
                	i+=push_param(plist->v.p[0],natural_size(plist->v.p[0]));
                plist = plist->v.p[1];
                }
        return i;
}
#ifdef CPLUSPLUS
AMODE *inlinecall(ENODE *node)
{
      ENODE *nameref = node,*thisn = 0; 
      SYM *sp;
      int size;
			
      if (nameref->nodetype == en_thiscall) {
				thisn = nameref->v.p[0] ;
        nameref = nameref->v.p[1];
			}
				
      nameref = nameref->v.p[1]->v.p[0];
      if (nameref->nodetype == en_nacon || nameref->nodetype == en_napccon) {  
        sp = nameref->v.sp;
				if (sp && (sp->value.classdata.cppflags & PF_INLINE)) {
					int oldretlab = retlab;
					AMODE *ap;
					SYM *oldcurfunc = currentfunc ;
					currentfunc = sp;
					retlab = -1;
					if (sp->value.classdata.cppflags & PF_CONSTRUCTOR) {
						SYM *psp = sp->parentclass ;
						if (psp && psp->value.classdata.vtabsp) {
							ENODE *ts = makenode(en_nacon,psp->value.classdata.vtabsp, 0) ;
							thisn = makenode(en_l_ref,thisn,0);
							ts = makenode(en_assign,thisn,ts) ;
							gen_expr(ts,FALSE,TRUE,4) ;
						}
					}
					genstmt(sp->value.classdata.inlinefunc->stmt);
					genreturn(0,3);
									size = currentfunc->tp->btp->size;
									if (size > 5) {
										ap = makefreg(0);
									}
            	    else {
											ap = makedreg(0);
									}
					currentfunc = oldcurfunc;
					retlab = oldretlab;
					return ap;
				}
      }
      return 0;
}
#endif
AMODE    *gen_fcall(ENODE *node,int novalue)
/*
 *      generate a function call node and return the address mode
 *      of the result.
 */
{       AMODE    *ap, *result, *ap1;
				ENODE *pushthis = 0;
        int             i,siz1;
				char xdregs[3],xaregs[3],xfregs[3] ;
				for (i=0; i < 3 ; i++) {
					if (xdregs[i] = dregs[i])
						gen_push(i,am_dreg,0) ;
				}
				for (i=0; i < 3 ; i++) {
					if (xaregs[i] = aregs[i])
						gen_push(i,am_areg,0) ;
				}
				for (i=0; i < 3 ; i++) {
					if (xfregs[i] = fregs[i])
						gen_push(i,am_freg,0) ;
				}
						
#ifdef CPLUSPLUS
				if (ap = inlinecall(node))
					return ap;
#endif
#ifdef CPLUSPLUS
				if (node->nodetype == en_thiscall) {
					pushthis = node->v.p[0];
					node = node->v.p[1];
					i = 4;
				} else
					i = 0 ;
#endif
				if (node->nodetype == en_callblock || node->nodetype == en_scallblock) {
					i = gen_parms(node->v.p[1]->v.p[1]->v.p[1]->v.p[0],0);
      		ap = gen_expr(node->v.p[0],FALSE,TRUE,4);
					gen_codes(op_move,4,ap,push);
					i+=4;
					stackdepth+=4;
					node=node->v.p[1];
					freeop(ap);
					siz1 = 4;
				}
				else {
	        i = gen_parms(node->v.p[1]->v.p[1]->v.p[0],0);    /* generate parameters */
					siz1 = node->v.p[0]->v.i;
				}
				if ((prm_phiform || node->nodetype == en_trapcall || node->nodetype == en_intcall) && i)
					gen_codes(op_move,4,makeareg(7),makeareg(0));
				if (node->nodetype == en_trapcall) {
					gen_codes(op_trap,0,make_immed(node->v.p[1]->v.p[0]->v.i),0);
				}
				else if (node->nodetype == en_intcall) {
					/* This is one case where we can generate code that will run
					 * on a 68000 but not on a 68020 or vice versa*/
					int curlabel = nextlabel++;
					DIAG("Direct calls to interrups not portable across processors");
					if (prm_68020) {
						gen_codes(op_clr,2,push,0);
					}
					ap1 = make_label(curlabel);
					if (prm_rel)
			  	 	ap1->mode = am_pcindx;
					else {
						ap1->mode = am_adirect;
					  if (prm_smallcode)
							ap1->preg = 2;
						else
							ap1->preg = 4;
					}
					gen_codes(op_pea,4,ap1,0);
					ap1 = xalloc(sizeof(AMODE));
					ap1->mode = am_sr;
					gen_codes(op_move,2,ap1,push);	/* May cause an exception on an 020 */
					gen_codes(op_bra,0,make_offset(node->v.p[1]->v.p[0]),0);
					gen_label(curlabel);
					freeop(ap1);
				}
     	  else {
					if (pushthis) {
						AMODE *ap2 = gen_expr(pushthis,FALSE,TRUE,4);
						gen_codes(op_move,4,ap2,push);
						freeop(ap2);
					}
					if( node->v.p[1]->v.p[0]->nodetype == en_nacon || node->v.p[1]->v.p[0]->nodetype == en_napccon ) {
						SYM * sp = node->v.p[1]->v.p[0]->v.p[0];
						if (sp->inreg) {
							if (sp->value.i < 8)
								ap1 = makedreg(sp->value.i);
							else
								ap1 = makeareg(sp->value.i & 7);
							do_extend(ap1,4,F_AREG);
							ap1->mode = am_ind;
							gen_codes(op_jsr,0,ap1,0);
						}
						else {
							node->v.p[1]->v.p[0]->v.p[0] = sp;
							if (prm_rel)
       	    		gen_codes(op_bsr,0,make_offset(node->v.p[1]->v.p[0]),0);
							else {
								ap1 = xalloc(sizeof(AMODE));
								ap1->mode = am_adirect;
          			ap1->offset = node->v.p[1]->v.p[0];
								if (prm_smallcode) {
									ap1->preg = 2;
								}
								else {
									ap1->preg = 4;
								}
								gen_codes(op_jsr,0,ap1,0);
							}
						}
					}
        	else
                {
                ap = gen_expr(node->v.p[1]->v.p[0],FALSE,TRUE,4);
								do_extend(ap,4,F_AREG) ;
								ap->mode = am_ind;
                freeop(ap);
                gen_codes(op_jsr,0,ap,0);
                }
		    }
				if (node->nodetype == en_fcall || node->nodetype == en_fcallb || node->nodetype == en_callblock)
        		if( i != 0 ) {
								if (i > 8) {
									AMODE *ap = xalloc(sizeof(AMODE)); 
									ap->mode = am_indx;
									ap->offset = makenode(en_icon,(char *)i,0);
									ap->preg = 7;
                	gen_lea(0,ap,makeareg(7));
								}
								else
                	gen_codes(op_add,4,make_immed(i),makeareg(7));
								stackdepth -= i;
				}
				if (siz1 > 4) {
						result = temp_float();
						if (result->preg != 0)
							gen_codef(op_fmove,8,makefreg(0),result);
				}
				else {
          result = temp_data();
        	if( result->preg != 0)
                gen_codes(op_move,4,makedreg(0),result);
				}
				for (i=2; i >= 0 ; i--) {
					if (xfregs[i])
						gen_pop(i,am_freg,0) ;
				}
				for (i=2; i >= 0 ; i--) {
					if (xaregs[i])
						gen_pop(i,am_areg,0) ;
				}
				for (i=2; i >= 0 ; i--) {
					if (xdregs[i])
						gen_pop(i,am_dreg,0) ;
				}
				result->tempflag = 1;
        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	loop = node->v.p[0],lab ;
				int regax,regdx,regcx;
				node = node->v.p[1] ;
#ifdef CPLUSPLUS
				if (node->nodetype == en_thiscall) {
					pushthis = node->v.p[0];
					node = node->v.p[1];
					i = 4;
				}
#endif
				gen_codes(op_move,4,make_immed(loop), cx = makedreg(0)) ;
				if (pushthis) {
					AMODE *ap2 = gen_expr(pushthis,FALSE,TRUE,4);
					gen_codes(op_move,4,ap2,ax = makedreg(0)) ;
					freeop(ap2);
				}
				gen_label(lab = nextlabel++) ;
				
					gen_codes(op_move,4,cx,push);
					gen_codes(op_move,4,ax,push);
									
					if( node->v.p[1]->v.p[0]->nodetype == en_nacon || node->v.p[1]->v.p[0]->nodetype == en_napccon ) {
						SYM * sp = node->v.p[1]->v.p[0]->v.p[0];
						if (sp->inreg) {
							if (sp->value.i < 8)
								ap1 = makedreg(sp->value.i);
							else
								ap1 = makeareg(sp->value.i & 7);
							do_extend(ap1,4,F_AREG);
							ap1->mode = am_ind;
							gen_codes(op_jsr,0,ap1,0);
						}
						else {
							node->v.p[1]->v.p[0]->v.p[0] = sp ;
							if (prm_rel)
       	    		gen_codes(op_bsr,0,make_offset(node->v.p[1]->v.p[0]),0);
							else {
								ap1 = xalloc(sizeof(AMODE));
								ap1->mode = am_adirect;
          			ap1->offset = node->v.p[1]->v.p[0];
								if (prm_smallcode) {
									ap1->preg = 2;
								}
								else {
									ap1->preg = 4;
								}
								gen_codes(op_jsr,0,ap1,0);
							}
						}
					}
        	else
                {
                ap = gen_expr(node->v.p[1]->v.p[0],FALSE,TRUE,4);
								do_extend(ap,4,F_AREG) ;
								ap->mode = am_ind;
                freeop(ap);
                gen_codes(op_jsr,0,ap,0);
                }
				gen_codes(op_move,4,pop,ax);
				gen_codes(op_move,4,pop,cx);
				gen_codes(op_add,4,make_immed(pushthis->v.sp->tp->size/loop),ax) ;
				gen_codes(op_sub,4,make_immed(1),cx) ;
				gen_code(op_bne,make_label(lab),0 );
}
AMODE    *gen_pfcall(ENODE *node,int size)
/*
 *      generate a function call node for pascal function calls
	*			and return the address mode of the result.
 */
{       AMODE    *ap, *result, *ap1;
        int             i,siz1;
				ENODE * invnode = 0,*anode,*pushthis;
				
				char xdregs[3],xaregs[3],xfregs[3] ;
				for (i=0; i < 3 ; i++) {
					if (xdregs[i] = dregs[i])
						gen_push(i,am_dreg,0) ;
				}
				for (i=0; i < 3 ; i++) {
					if (xaregs[i] = aregs[i])
						gen_push(i,am_areg,0) ;
				}
				for (i=0; i < 3 ; i++) {
					if (xfregs[i] = fregs[i])
						gen_push(i,am_freg,0) ;
				}
#ifdef CPLUSPLUS
				if (ap = inlinecall(node))
					return ap;
#endif
				/* invert the parameter list */
				if (node->nodetype == en_pcallblock || node->nodetype == en_scallblock)
					anode = node->v.p[1]->v.p[1]->v.p[1]->v.p[0];
				else
					anode = node->v.p[1]->v.p[1]->v.p[0];
				while (anode) {
					invnode = makenode(anode->nodetype,anode->v.p[0],invnode);
					anode = anode->v.p[1];
				}
#ifdef CPLUSPLUS
				if (node->nodetype == en_thiscall) {
					pushthis = node->v.p[0];
					node = node->v.p[1];
					i = 4;
				}
#endif
				if (pushthis) {
					AMODE *ap2 = gen_expr(pushthis,FALSE,TRUE,4);
					gen_codes(op_move,4,ap2,push);
					freeop(ap2);
				}
				if (node->nodetype == en_pcallblock || node->nodetype == en_scallblock) {
      		ap = gen_expr(node->v.p[0],FALSE,TRUE,4);
					gen_codes(op_move,4,ap,push);
					freeop(ap);
					i =4;
					stackdepth+=4;
					i += gen_parms(invnode,size);
					node=node->v.p[1];
						siz1 = 4;
				}
				else {
	        i = gen_parms(invnode,size);    /* generate parameters */
					siz1 = node->v.p[0]->v.i;
				}
				if ((prm_phiform || node->nodetype == en_trapcall || node->nodetype == en_intcall) && i)
					gen_codes(op_move,4,makeareg(7),makeareg(0));
     	  if( node->v.p[1]->v.p[0]->nodetype == en_nacon || node->v.p[1]->v.p[0]->nodetype == en_napccon ) {
					SYM * sp = node->v.p[1]->v.p[0]->v.p[0];
					if (sp->inreg) {
						if (sp->value.i < 8)
							ap1 = makedreg(sp->value.i);
						else
							ap1 = makeareg(sp->value.i & 7);
						do_extend(ap1,size,F_AREG);
						ap1->mode = am_ind;
						gen_codes(op_jsr,0,ap1,0);
					}
					else {
						node->v.p[1]->v.p[0]->v.p[0] = sp;
						if (prm_rel)
       	    	gen_codes(op_bsr,0,make_offset(node->v.p[1]->v.p[0]),0);
						else {
							ap1 = xalloc(sizeof(AMODE));
							ap1->mode = am_adirect;
          		ap1->offset = node->v.p[1]->v.p[0];
							if (prm_smallcode) {
								ap1->preg = 2;
							}
							else {
								ap1->preg = 4;
							}
							gen_codes(op_jsr,0,ap1,0);
						}
					}
		    }
        else
                {
                ap = gen_expr(node->v.p[1]->v.p[0],FALSE,TRUE,4);
								do_extend(ap,4,F_AREG) ;
								ap->mode = am_ind;
                freeop(ap);
                gen_codes(op_jsr,0,ap,0);
                }
				stackdepth -= i;
				if (siz1 > 4) {
						result = temp_float();
						if (result->preg != 0)
							gen_codef(op_fmove,8,makefreg(0),result);
				}
				else {
          result = temp_data();
        	if( result->preg != 0)
                gen_codes(op_move,4,makedreg(0),result);
				}
				for (i=2; i >= 0 ; i--) {
					if (xfregs[i])
						gen_pop(i,am_freg,0) ;
				}
				for (i=2; i >= 0 ; i--) {
					if (xaregs[i])
						gen_pop(i,am_areg,0) ;
				}
				for (i=2; i >= 0 ; i--) {
					if (xdregs[i])
						gen_pop(i,am_dreg,0) ;
				}
				result->tempflag = 1;
        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;
        int             natsize,fconst=0;
				SYM *sp ;
        if( node == 0 )
                {
                DIAG("null node in gen_expr.");
                return 0;
                }
        switch( node->nodetype )
                {
								case en_bits:
												ap1 = gen_expr(node->v.p[0],novalue,adronly,size);
												if (!adronly)
													ap1 = bit_load(ap1,node,natural_size(node));
												return ap1;
                case en_cl_reg:
                        return gen_expr(node->v.p[0],novalue,adronly,natural_size(node->v.p[0]));
                case en_cbool:
								case en_cb: 
								case en_cub:
								case en_cw: 
								case en_cuw:
								case en_cl: 
								case en_cul:
								case en_cf: 
								case en_cd: 
								case en_cld: 
								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_ALL);
												return ap1;
                case en_napccon:
												node->v.p[0] = node->v.sp ;
                case en_labcon:
                        ap1 = temp_addr();
												ap1->tempflag = TRUE;
                        ap2 = xalloc(sizeof(AMODE));
												if (prm_rel)
										  	 	ap2->mode = am_pcindx;
												else {
													ap2->mode = am_adirect;
												  if (prm_smallcode)
														ap2->preg = 2;
													else
														ap2->preg = 4;
												}
                        ap2->offset = node;     /* use as constant node */
                        gen_lea(0,ap2,ap1);
												ap1->length = 4 ;
                        return ap1;             /* return reg */
								case en_absacon:
												node->v.i = node->v.sp->value.i;
                        ap1 = temp_addr();
												ap1->tempflag = TRUE;
                        ap2 = xalloc(sizeof(AMODE));
                        ap2->mode = am_adirect;
												ap2->preg = isshort(node) ? 2 : 4;
                        ap2->offset = node;     /* use as constant node */
                        gen_lea(0,ap2,ap1);
												ap1->length = 4 ;
                        return ap1;             /* return reg */
                case en_nacon:
												node->v.p[0] = node->v.sp;
								case en_nalabcon:
	                      ap1 = temp_addr();
												ap1->tempflag = TRUE;
    	                  ap2 = xalloc(sizeof(AMODE));
												if (prm_rel) {
  	  	                  ap2->preg = basereg;          /* frame pointer */
													if (prm_largedata) {
														ap2->mode = am_areg;
														gen_codes(op_move,0,ap2,ap1);
														ap2->mode = am_immed;
														ap2->offset = node;
														gen_codes(op_add,0,ap2,ap1);
													}
													else {
	                      	  ap2->mode = am_indx;
    	                    	ap2->offset = node;     /* use as constant node */
	      	                  gen_lea(0,ap2,ap1);
													}
												}
												else {
													ap2->mode = am_adirect;
					          	    ap2->offset = node;
													if (prm_smalldata) {
														ap2->preg = 2;
													}
													else {
														ap2->preg = 4;
													}
	      	                gen_lea(0,ap2,ap1);
												}
												ap1->length = 4 ;
                        return ap1;             /* return reg */
								case en_rcon:
								case en_lrcon: case en_fcon:
                        ap1 = xalloc(sizeof(AMODE));
                        ap1->mode = am_immed;
                        ap1->offset = node;
												ap1->length = natural_size(node) ;
												return ap1 ;
                case en_icon:
								case en_lcon: 
								case en_lucon: 
								case en_iucon: 
								case en_ccon:                 
                        ap1 = xalloc(sizeof(AMODE));
                        ap1->mode = am_immed;
                        ap1->offset = node;
												ap1->length = natural_size(node) ;
                        return ap1;
                case en_autocon:
                case en_autoreg:
                        ap1 = temp_addr();
												ap1->tempflag = TRUE;
                        ap2 = xalloc(sizeof(AMODE));
                        ap2->mode = am_indx;
												if (prm_linkreg && !currentfunc->intflag) {
			                		ap2->preg = linkreg;
      			          		ap2->offset = makenode(en_icon,(char *)((SYM *)node->v.p[0])->value.i,0);
												}
					 							else if (((SYM *)node->v.p[0])->funcparm ) {
													int i = 0 ;
#ifdef CPLUSPLUS
													if ((currentfunc->value.classdata.cppflags & PF_MEMBER) &&
															!(currentfunc->value.classdata.cppflags & PF_STATIC))
														i += 4;
#endif
													if (prm_phiform || currentfunc->intflag) {
                        		ap2->preg = linkreg;          /* frame pointer */
														ap2->offset = makenode(en_icon,(char *)(((SYM *)node->v.p[0])->value.i+4),0);
													}
													else {
														ap2->preg = 7;
														ap2->offset = makenode(en_icon,(char *)(((SYM *)node->v.p[0])->value.i+4+stackdepth+framedepth),0);
													}
                				}
												else {
													ap2->preg = 7;
													ap2->offset = makenode(en_icon,(char *)(((SYM *)node->v.p[0])->value.i+stackdepth+lc_maxauto),0);
												}
                        gen_lea(0,ap2,ap1);
												ap1->length = 4 ;
                        return ap1;             /* return reg */
                case en_bool_ref:
                case en_b_ref:
                case en_w_ref:
                case en_ub_ref:
                case en_uw_ref:
                case en_l_ref:
                case en_ul_ref:
								case en_floatref:
								case en_doubleref:
								case en_longdoubleref:
                       	ap1 = gen_deref(node,4);
												return ap1;
                case en_tempref:
                case en_regref:
                        ap1 = xalloc(sizeof(AMODE));
                        if( (node->v.i & 0xff) < 16 )
                                {
                                ap1->mode = am_dreg;
                                ap1->preg = node->v.i & 0xff;
                                }
                        else
													if ((node->v.i &0xff) < 32)
                                {
                                ap1->mode = am_areg;
                                ap1->preg = (node->v.i & 0xff) - 16;
                                }
													else
                                {
                                ap1->mode = am_freg;
                                ap1->preg = (node->v.i &0xff)- 32;
                                }
                        ap1->tempflag = 0;      /* not a temporary */
												ap1->length = node->v.i >> 8;
                        return ap1;
                case en_asuminus:
                        return gen_asunary(node,novalue,op_neg, op_fneg,size);
                case en_ascompl:
                        return gen_asunary(node,novalue,op_not, op_not,size);
                case en_uminus:
                        return gen_unary(node,op_neg, op_fneg,size);
                case en_compl:
                        return gen_unary(node,op_not, op_not,size);
                case en_add: case en_addstruc:
                        return gen_binary(node,op_add,op_fadd,size);
                case en_sub:
                        return gen_binary(node,op_sub,op_fsub,size);
                case en_and:
                        return gen_xbin(node,op_and,op_and,size);
                case en_or:
                        return gen_xbin(node,op_or,op_or,size);
				case en_xor:
						return gen_xbin(node,op_eor,op_eor,size);
								case en_pmul:
												return gen_pmul(node,size);
								case en_pdiv:
												return gen_pdiv(node,size);
                case en_mul:
                        return gen_mul(node,op_muls,op_fmul,size);
                case en_umul:
                        return gen_mul(node,op_mulu,op_fmul,size);
                case en_div:
                        return gen_modiv(node,op_divs,op_fdiv,size,0);
                case en_udiv:
                        return gen_modiv(node,op_divu,op_fdiv,size,0);
                case en_mod:
                        return gen_modiv(node,op_divs,op_fdiv,size,1);
                case en_umod:
                        return gen_modiv(node,op_divu,op_fdiv,size,1);
                case en_alsh:
                        return gen_shift(node,op_asl,size);
                case en_arsh: case en_arshd:
                        return gen_shift(node,op_asr,size);
                case en_lsh:
                        return gen_shift(node,op_lsl,size);
                case en_rsh:
                        return gen_shift(node,op_lsr,size);
                case en_asadd:
                        return gen_asadd(node,novalue,op_add,op_fadd,size);
                case en_assub:
                        return gen_asadd(node,novalue,op_sub,op_fsub,size);
                case en_asand:
                        return gen_aslogic(node,novalue,op_and,op_bclr,size);
                case en_asor:
                        return gen_aslogic(node,novalue,op_or,op_bset,size);
                case en_asxor:                           
                        return gen_aslogic(node,novalue,op_eor,op_bchg,size);
                case en_aslsh:
                        return gen_asshift(node,novalue,op_lsl,size);
                case en_asrsh:
                        return gen_asshift(node,novalue,op_lsr,size);
                case en_asalsh:
                        return gen_asshift(node,novalue,op_asl,size);
                case en_asarsh: case en_asarshd:
												return gen_asshift(node,novalue,op_asr,size);
                case en_asmul:
                        return gen_asmul(node,novalue,op_muls,op_fmul,size);
                case en_asumul:
                        return gen_asmul(node,novalue,op_mulu,op_fmul,size);
                case en_asdiv:
                        return gen_asmodiv(node,novalue,op_divs,op_fdiv,size,FALSE);
                case en_asudiv:
                        return gen_asmodiv(node,novalue,op_divu,op_fdiv,size,FALSE);
                case en_asmod:
                        return gen_asmodiv(node,novalue,op_divs,op_fdiv,size,TRUE);
                case en_asumod:
                        return gen_asmodiv(node,novalue,op_divu,op_fdiv,size,TRUE);
                case en_assign:
                        return gen_assign(node,novalue,size);
                case en_refassign:
                        return gen_refassign(node,novalue,size);
                case en_moveblock:
                        return gen_moveblock(node);
                case en_ainc:
                        return gen_aincdec(node,novalue,op_add,op_fadd,size);
                case en_adec:
                        return gen_aincdec(node,novalue,op_sub,op_fsub,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_void:
                        natsize = natural_size(node->v.p[0]);
                        gen_void(node->v.p[0]);
												initstack() ;
                        return gen_expr(node->v.p[1],TRUE,FALSE,natural_size(node));
								case en_pfcall: case en_pfcallb:
								case en_pcallblock:
                        return gen_pfcall(node,novalue);
								case en_sfcall: case en_sfcallb: case en_scallblock:
                case en_fcall:  case en_callblock: case en_fcallb:
                case en_intcall:  case en_thiscall:
                case en_trapcall:
                        return gen_fcall(node,novalue);
                default:
								case en_repcons:
                        DIAG("uncoded node in gen_expr.");
                        return 0;
                }
}

AMODE	   *gen_void(ENODE *node)
{
	gen_expr(node,TRUE,FALSE,natural_size(node));
	gen_code(op_void,0,0);
	return 0;
}
int     natural_size(ENODE *node)
/*
 *      return the natural evaluation size of a node.
 */
{       int     siz0, siz1;
        if( node == 0 )
                return 0;
        switch( node->nodetype )
                {
                        case en_bits: case en_cl_reg:
                                    return natural_size(node->v.p[0]) ;
                case en_icon:
								case en_lcon:
												return -4; 
								case en_lucon: 
                case en_iucon:
												return 4;
								case en_ccon:                 
												return 4;
								case en_rcon:
								case en_doubleref:
												return 8;

								case en_lrcon:
								case en_longdoubleref:
												return 10;
								case en_fcon:
								case en_floatref:
												return 6;
                        case en_llcon:
                                    return - 8;
                        case en_llucon:
                                    return 8 ;
								case en_trapcall:
                case en_labcon:
                case en_nacon:  case en_autocon:  case en_autoreg:
                case en_napccon:  case en_absacon: case en_nalabcon:
												return stdaddrsize;
								case en_l_ref:
								case en_cl:
												return -4;
                        case en_ll_ref:
                        case en_cll:
                                    return - 20 ;
                        case en_ull_ref:
                        case en_cull:
                                    return 20 ;
								case en_thiscall:
												return natural_size(node->v.p[1]);
								case en_scallblock: case en_sfcallb: case en_sfcall:
								case en_pfcall: case en_pfcallb: /* ignore pascal style now */
								case en_pcallblock:
								case en_fcall: case en_callblock: case en_fcallb:
								case en_intcall:
												return natural_size(node->v.p[1]);
								case en_tempref:
								case en_regref:
												return node->v.i >> 8;
                case en_ul_ref:
								case en_cul:
                        return 4;
								case en_cp:
												return stdaddrsize;
                case en_bool_ref: case en_cbool:
                case en_ub_ref:
								case en_cub:
												return 1;
                case en_b_ref:
								case en_cb:
                        return -1;
                case en_uw_ref:
								case en_cuw:
												return 2;
                case en_cw:
                case en_w_ref:
                        return -2;
								case en_cd:
												return 8;
								case en_cld:
												return 10;
								case en_cf:
												return 6;
                case en_not:    case en_compl:
                case en_uminus: case en_assign: case en_refassign:
                case en_ainc:   case en_adec: case en_asuminus: case en_ascompl:
								case en_moveblock: case en_stackblock:
                        return natural_size(node->v.p[0]);
                case en_add:    case en_sub: case en_addstruc:
								case en_umul:		case en_udiv:	case en_umod: case en_pmul:
                case en_mul:    case en_div:  case en_pdiv:
                case en_mod:    case en_and:
                case en_or:     case en_xor:
								case en_asalsh: case en_asarsh: case en_alsh: case en_arsh: case en_arshd: case en_asarshd:
                case en_lsh:    case en_rsh:
                case en_eq:     case en_ne:
                case en_lt:     case en_le:
                case en_gt:     case en_ge:
								case en_ugt: case en_uge: case en_ult: case en_ule:
                case en_land:   case en_lor:
                case en_asadd:  case en_assub:
                case en_asmul:  case en_asdiv:
                case en_asmod:  case en_asand:
								case en_asumod: case en_asudiv: case en_asumul:
                case en_asor:   case en_aslsh:  case en_asxor:
                case en_asrsh:
                        siz0 = natural_size(node->v.p[0]);
                        siz1 = natural_size(node->v.p[1]);
                        if( chksize(siz1,siz0))
                                return siz1;
                        else
                                return siz0;
                case en_void:   case en_cond: case en_repcons:
                        return natural_size(node->v.p[1]);
                default:
                        DIAG("natural size error.");
                        break;
                }
        return 0;
}

/*
 * subroutine evaluates a node determining how to test it for
 * non-zero
 */
static int defcond(ENODE *node) 
{
  AMODE *ap1;
	int rv = 0;
	if (natural_size(node) > 5) {
  	ap1 = gen_expr(node,FALSE,FALSE,4);
	 	do_extend(ap1,10,F_FREG);
		gen_codef(op_fcmp,4,make_immed(0),ap1);
	}
	else {
		if (isbit(node)) {
  		ap1 = gen_expr(node,FALSE,TRUE,0);
			if (node->bits == 1) {
				rv = 1;
				do_extend(ap1,4,F_DREG) ;
				gen_codes(op_btst,4,make_immed(node->startbit),ap1);
			} else
				gen_code(op_tst,make_immed(bittab[node->bits-1]<<node->startbit),ap1);
		}
		else {
  		ap1 = gen_expr(node,FALSE,FALSE,0);
			gen_code(op_cmp,make_immed(0),ap1);
		}
	}
  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_seq,op_seq,op_fseq,op_fseq,0);
                        break;
                case en_ne:
                        ap1 = gen_compare(node,op_sne,op_sne,op_fsne,op_fsne,0);
                        break;
                case en_lt:
                        ap1 = gen_compare(node,op_slt,op_sgt,op_fslt,op_fsnle,0);
                        break;
                case en_le:
                        ap1 = gen_compare(node,op_sle,op_sge,op_fsle,op_fsnlt,0);
                        break;
                case en_gt:
                        ap1 = gen_compare(node,op_sgt,op_slt,op_fsgt,op_fsnge,0);
                        break;
                case en_ge:
                        ap1 = gen_compare(node,op_sge,op_sle,op_fsge,op_fsngt,0);
                        break;
                case en_ult:
                        ap1 = gen_compare(node,op_slo,op_shi,op_fslt,op_fsnle,0);
                        break;
                case en_ule:
                        ap1 = gen_compare(node,op_sls,op_shs,op_fsle,op_fsnlt,0);
                        break;
                case en_ugt:
                        ap1 = gen_compare(node,op_shi,op_slo,op_fsgt,op_fsnge,0);
                        break;
                case en_uge:
                        ap1 = gen_compare(node,op_shs,op_sls,op_fsge,op_fsngt,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;
												}
												ap1 = temp_data();
												gen_codes(op_moveq,0,make_immed(0),ap1) ;
												if (defcond(node->v.p[0])) {
													gen_codes(op_scc,1,ap1,0);
												} else {
													gen_codes(op_seq,1,ap1,0);
												} 
												gen_codes(op_neg,1,ap1,0) ;
                        break;
                default:
												DIAG("True-relat error");
                        break;
                }
  ap1->length = 4;
	return ap1;
}
static int complex_relat(ENODE *node)
{
				if (!node)
					return 0;
        switch( node->nodetype )
                {
                        case en_cl_reg:
                              return complex_relat(node->v.p[0]) ;
								case en_bits:
								case en_l_ref:
								case en_cl:
                case en_ul_ref:
								case en_cul:
								case en_cp:
                case en_ub_ref:
								case en_cub:
                case en_bool_ref: case en_cbool:
                case en_b_ref:
                case en_cb:
                case en_uw_ref:
								case en_cuw:
                case en_cw:
                case en_w_ref:
								case en_cd:
								case en_cld:
								case en_cf:
                case en_uminus: 
                case en_ainc:   case en_adec: 
								case en_moveblock: case en_stackblock:
												return complex_relat(node->v.p[0]);
                case en_icon:
								case en_lcon: 
								case en_lucon: 
								case en_iucon: 
								case en_ccon:                 
								case en_rcon:
								case en_doubleref:
								case en_lrcon:
								case en_longdoubleref:
								case en_fcon:
								case en_floatref:
								case en_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_asuminus: case en_ascompl:
                case en_add:    case en_sub: case en_addstruc:
								case en_umul:		case en_pmul:
                case en_mul:		case en_and:
                case en_or:     case en_xor:
								case en_asalsh: case en_asarsh: case en_alsh: case en_arsh: case en_arshd: case en_asarshd:
                case en_lsh:    case en_rsh:
                case en_asadd:  case en_assub:
                case en_asmul:  case en_asdiv:
                case en_asmod:  case en_asand:
								case en_asumod: case en_asudiv: case en_asumul:
                case en_asor:   case en_aslsh:  case en_asxor:
                case en_asrsh:
												return complex_relat(node->v.p[0]) || complex_relat(node->v.p[1]);
                case en_void:   case en_cond: case en_repcons:
												return complex_relat(node->v.p[1]);
								case en_sfcall: case en_sfcallb: case en_scallblock:
								case en_pfcall: case en_pfcallb: case en_thiscall:
								case en_fcall: case en_intcall: case en_callblock: case en_fcallb:
								case en_pcallblock:
												return 0;
                default:
                        DIAG("error in complex_relat routine.");
												return 1;
                }
}
AMODE *gen_relat(ENODE *node)
{
	long lab1;
	AMODE *ap1;
	int size = natural_size(node);
	if (size > 5)
		size = 4;
   if (!prm_coldfire && 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 {
			int lab2 = nextlabel++ ;
			gen_codes(op_moveq,0,make_immed(0),ap1) ;
			gen_code(op_bra,make_label(lab2),0) ;
			gen_label(lab1) ;
	  	gen_codes(op_moveq,0,make_immed(1),ap1);
			gen_label(lab2) ;
			ap1->length = 4;
		}
	}
  return ap1;
}
AMODE * gen_compare(ENODE *node, int btype1, int btype2, int fbtype1, int fbtype2, int label)
/*
 *      generate code to do a comparison of the two operands of
 *      node.
 */
{       AMODE    *ap1, *ap2,  *ap3,*apx = 0;
        int             size;
				int btype = btype1, bitted = FALSE;
				ap3 = 0;
        size = natural_size(node);
            if (size > 5) {
					resolve_binary(node,&ap1,&ap2,natural_size(node));
					do_extend(ap1,ap1->length, F_FREG) ;
					do_extend(ap2,ap2->length, F_FREG) ;
						if (!label) {
							apx = temp_data() ;
							gen_codes(op_moveq,0,make_immed(0),apx) ;
						}
        		gen_codef(op_fcmp,size,ap2,ap1);
						if (label) {
								gen_branch(fbtype1,make_label(label));
						}
						else {
								apx->length = 4;
								gen_codes(fbtype1,1,apx,0);
								gen_codes(op_neg,1,apx,0) ;
						
						}
						freeop(ap2) ;
						freeop(ap1) ;
						return apx ;
				}
				if ((isbit(node->v.p[0]) || isbit(node->v.p[1])) && (btype1 == op_beq || btype1 == op_bne || btype1 == op_seq || btype1 == op_sne)) {
					ENODE *xnode;
					bitted = TRUE ;
					if (isbit(node->v.p[0])) {
  					ap2 = gen_expr(node->v.p[1],FALSE,FALSE,4);
						noids(ap2);
  					ap1 = gen_expr(xnode = node->v.p[0],FALSE,TRUE,4);
					} else {
  					ap2 = gen_expr(node->v.p[0],FALSE,FALSE,4);
						noids(ap2);
  					ap1 = gen_expr(xnode = node->v.p[1],FALSE,TRUE,4);
					}
					if (ap2->mode == am_immed && (ap1->mode == am_dreg || xnode->startbit < 8)) {
						if (xnode->bits == 1) {
							if (!(ap2->offset->v.i & 1)) {
								if (!label) {
									apx = temp_data() ;
									gen_codes(op_moveq,0,make_immed(0),apx) ;
								}
								gen_codes(op_btst,4,make_immed(xnode->startbit),ap1);
								switch (btype1) {
									case op_beq:
										btype = op_bcc;
										break;
									case op_bne:
										btype = op_bcs;
										break;
									case op_seq:
										btype = op_scc;
										break;
									case op_sne:
										btype = op_scs;
										break;
								}
							} else {
								if (!label) {
									apx = temp_data() ;
									gen_codes(op_moveq,0,make_immed(0),apx) ;
								}
								gen_codes(op_btst,4,make_immed(xnode->startbit),ap1);
								switch (btype1) {
									case op_beq:
										btype = op_bcs;
										break;
									case op_bne:
										btype = op_bcc;
										break;
									case op_seq:
                              btype = op_scs;
										break;
									case op_sne:
										btype = op_scc;
										break;
								}
							}
						} else goto join;
					}
					else {
join:
						ap1=bit_load(ap1,xnode,4);
						goto join2;
					}
				} else {
					resolve_binary(node,&ap1,&ap2,0) ;
join2:
					if (ap1->mode != am_dreg && ap1->mode != am_areg) {
						if (ap2->mode == am_immed)  {
							if (ap1->mode == am_immed)
								goto cmp2;
						}
						else {
							if (ap2->mode == am_dreg || ap2->mode == am_areg) {
swapit:
								ap3 = ap2;
								ap2 = ap1;
								ap1 = ap3;
								ap3 = 0;
								btype = btype2;
							}
							else  
								if (ap1->mode == am_immed) {
									goto swapit;
								}
								else {
cmp2:
									ap3 = ap1;
  	            	ap1 = temp_data();
									gen_codes(op_move,size,ap3,ap1);
									freeop(ap3) ;
									do_extend(ap1,size,F_DREG) ;
								}
						}
					}
					if (!label) {
						apx = temp_data() ;
						gen_codes(op_moveq,0,make_immed(0),apx) ;
					}
               if (prm_coldfire && size < 4 && size > -4) {
                  do_extend(ap1,4,F_DREG | F_VOL) ;
                  do_extend(ap2,4,F_DREG | F_VOL) ;
               }
               gen_codes(op_cmp,prm_coldfire ? 4 : size,ap2,ap1);
				}
				freeop(ap1);
				freeop(ap2);
				if (!bitted && ap2->mode == am_immed && ap2->offset->v.i == 0) {
					switch(btype) {
						case op_shi:
							btype = op_sne ;
							break ;
						case op_scc:
							gen_code (op_move,makedreg(0),makedreg(0));
							break ;
						case op_scs:
							gen_code (op_move,makedreg(0),makedreg(0));
							break ;
						case op_slo:
							btype = op_seq ;
							break ;
						case op_bhi :
							btype = op_beq ;
							break ;
						case op_bcc:
							btype = op_bra ; /* Following code never gets executed */
							break ;
						case op_bcs: /* Following code always gets executed */
							return ap1;
						case op_blo :
							btype = op_beq ;
							break ;
					}
				}						
				if (label) {
						gen_branch(btype,make_label(label));
				}
				else {
                     apx->length = 4;
                     gen_codes(btype,1,apx,0);
                     gen_codes(op_neg,1,apx,0) ;
						
				}
        freeop(ap2);
       	freeop(ap1);
				return apx;
}

void truejp(ENODE *node, int label)
/*
 *      generate a jump to label if the node passed evaluates to
 *      a true condition.
 */
{       AMODE    *ap1;
        int             siz1;
        int             lab0;
        if( node == 0 )
                return;
        switch( node->nodetype )
                {
                case en_eq:
                        gen_compare(node,op_beq,op_beq,op_fbeq,op_fbeq,label);
                        break;
                case en_ne:
                        gen_compare(node,op_bne,op_bne,op_fbne,op_fbne,label);
                        break;
                case en_lt:
                        gen_compare(node,op_blt,op_bgt,op_fblt,op_fbnle,label);
                        break;
                case en_le:
                        gen_compare(node,op_ble,op_bge,op_fble,op_fbnlt,label);
                        break;
                case en_gt:
                        gen_compare(node,op_bgt,op_blt,op_fbgt,op_fbnge,label);
                        break;
                case en_ge:
                        gen_compare(node,op_bge,op_ble,op_fbge,op_fbngt,label);
                        break;
                case en_ult:
                        gen_compare(node,op_blo,op_bhi,op_fblt,op_fbnle,label);
                        break;
                case en_ule:
                        gen_compare(node,op_bls,op_bhs,op_fble,op_fbnlt,label);
                        break;
                case en_ugt:
                        gen_compare(node,op_bhi,op_blo,op_fbgt,op_fbnge,label);
                        break;
                case en_uge:
                        gen_compare(node,op_bhs,op_bls,op_fbge,op_fbngt,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:
												siz1 = natural_size(node) ;
												if (isintconst(node->nodetype)) {
													if (node->v.i != 0) 
                        		gen_code(op_bra,make_label(label),0);
													break;
												}
												if (siz1 > 5)
				 									if (defcond(node))
  	                      	gen_branch(op_fbge,make_label(label));
													else
      	                  	gen_branch(op_fbne,make_label(label));
												else
			 										if (defcond(node))
          	              	gen_branch(op_bcc,make_label(label));
													else
              	          	gen_branch(op_bne,make_label(label));
                        break;
                }
}

void falsejp(ENODE *node, int label)
/*
 *      generate code to execute a jump to label if the expression
 *      passed is false.
 */
{       AMODE    *ap;
        int             siz1;
        int             lab0;
        if( node == 0 )
                return;
        switch( node->nodetype )
                {
                case en_eq:
                        gen_compare(node,op_bne,op_bne,op_fbne,op_fbne,label);
                        break;
                case en_ne:
                        gen_compare(node,op_beq,op_beq,op_fbeq,op_fbeq,label);
                        break;
                case en_lt:
                        gen_compare(node,op_bge,op_ble,op_fbge,op_fbngt,label);
                        break;
                case en_le:
                        gen_compare(node,op_bgt,op_blt,op_fbgt,op_fbnge,label);
                        break;
                case en_gt:
                        gen_compare(node,op_ble,op_bge,op_fble,op_fbnlt,label);
                        break;
                case en_ge:
                        gen_compare(node,op_blt,op_bgt,op_fblt,op_fbnle,label);
                        break;
                case en_ult:
                        gen_compare(node,op_bhs,op_bls,op_fbge,op_fbngt,label);
                        break;
                case en_ule:
                        gen_compare(node,op_bhi,op_blo,op_fbgt,op_fbnge,label);
                        break;
                case en_ugt:
                        gen_compare(node,op_bls,op_bhs,op_fble,op_fbnlt,label);
                        break;
                case en_uge:
                        gen_compare(node,op_blo,op_bhi,op_fblt,op_fbnle,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:
												siz1 = natural_size(node) ;
												if (isintconst(node->nodetype)) {
													if (node->v.i == 0) 
                        		gen_code(op_bra,make_label(label),0);
													break;
												}
												if (siz1 > 5)
													if (defcond(node))
  	                      	gen_branch(op_fbge,make_label(label));
													else
      	                  	gen_branch(op_fbeq,make_label(label));
												else
													if (defcond(node))
  	                      	gen_branch(op_bcc,make_label(label));
													else
      	                  	gen_branch(op_beq,make_label(label));
                        break;
                }
}