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

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

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

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

   You may contact the author at:

   mailto::camille@bluegrass.net

   or by snail mail at:

   David Lindauer
   850 Washburn Ave Apt 99
   Louisville, KY 40222
*/
/*
 * iexpr.c 
 *
 * routies to take an enode list and generate icode
 */
#include        <stdio.h>
#include				"utype.h"
#include        "lists.h"
#include        "expr.h"
#include        "c.h"
#include				"iexpr.h"
#include				"iopt.h"
#include 				"diag.h"

/*
 *      this module contains all of the code generation routines
 *      for evaluating expressions and conditions.
 */
extern int global_flag ;
extern int     retlab;
extern SYM *currentfunc ;
extern long nextlabel;
extern long bittab[32];
extern IMODE rret;
extern short intsize, addrsize, regsize;
int chksize(int lsize, int rsize)
/*
 * compare two sizes, ignoring sign during comparison
 */
{
	int l,r;
	l = lsize;
	r = rsize;
	if (l < 0) l = - l;
	if (r < 0) r = - r;
	return(l > r);
}
IMODE *make_imaddress(ENODE *node, int size)
{
   SYM *sp = node->v.sp ;
   IMODE *ap2 ;
   if (sp && sp->imaddress)
      return sp->imaddress ;
   if (sp && sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
      global_flag++ ;
   ap2 = xalloc(sizeof(IMODE));
   ap2->offset = copy_enode(node);     /* use as constant node */
   ap2->mode = i_immed;
   ap2->size = size ;
   if (sp && sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
      global_flag-- ;
   if (sp)
      sp->imaddress = ap2 ;
	return ap2;
}

IMODE    *make_bf(ENODE *node, IMODE *ap, int size)
/*
 *      construct a bit field reference for 68020 bit field instructions
 */
{
        IMODE    *ap1;
				if (node->startbit == -1)
					DIAG("Illegal bit field");
				ap->startbit = node->startbit;
				ap->bits = node->bits;
				ap->size = size;
        return ap;
}

IMODE    *make_immed(long i)
/*
 *      make a node to reference an immediate value i.
 */

{
      IMODE    *ap = xalloc(sizeof(IMODE)) ;
      ap->mode = i_immed ;
      ap->offset = makenode(en_icon,(char *)i,0) ;
      ap->size = 4 ;
      return ap ;
}
IMODE    *make_fimmed(long double i)
/*
 *      make a node to reference an immediate value i.
 */

{
      IMODE    *ap = xalloc(sizeof(IMODE)) ;
      ap->mode = i_immed ;
      ap->offset = makenode(en_lrcon,0,0) ;
      ap->offset->v.f = i ;
      ap->size = 10 ;
      return ap ;
}
IMODE 	*make_parmadj(long i)
/*
 *			make a direct immediate, e.g. for parmadj
 */
{
				ENODE *node = makenode(en_icon,(char *)i,0);
				IMODE *ap = xalloc(sizeof(IMODE));
				ap->mode = i_immed;
				ap->offset = node;
				return ap;
}
			

IMODE    *make_offset(ENODE *node)
/*
 *      make a direct reference to a node.
 */
{       IMODE    *ap;
        SYM *sp = varsp(node) ;
        if (sp && sp->imvalue)
            return sp->imvalue ;
        if (sp && sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
         global_flag++ ;
        ap = xalloc(sizeof(IMODE));
        ap->offset = copy_enode(node);
        if (sp && sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
         global_flag-- ;
        ap->mode = i_direct;
				ap->size = natural_size(node);
        if (sp)
            sp->imvalue = ap ;
        return ap;
}
        
IMODE	*genasn(ENODE *node, int size)
/*
 * Find the targe of an assigment.  if node is 0 we need a temp reg,
 * otherwise we calculate the assignment target
 */
{
	if (!node)
		return tempreg(size,0);
	return gen_expr(0,node,0,size);
}
IMODE *indnode(IMODE *ap1, int size)
/*
 * copy the address mode and change it to an indirect type
 *
 */
{
   IMODE *ap ;
   SYM *sp ;
   int hassp = FALSE ;
	if (ap1->mode == i_ind) {
      IMODE *ap2 = tempreg(size,0);
		ap2->bits = ap1->bits;
		ap2->startbit = ap1->startbit;
      gen_icode(i_assn,ap2,ap1,0);
      ap2->mode = i_ind ;
      return ap2 ;
   }
   sp = varsp(ap1->offset) ;
   if (sp && sp->imind) {
      ap = sp->imvalue ;
      ap->offset = ap1->offset ;
   } else {
      if (sp) {
         if (sp && sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
            global_flag++ ;
         ap = xalloc(sizeof(IMODE)) ;
         *ap = *ap1 ;
         ap->offset = copy_enode(ap->offset) ;
         if (sp && sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
            global_flag-- ;
      } else {
         ap = xalloc(sizeof(IMODE)) ;
         *ap = *ap1 ;
      }
      ap->mode = i_ind ;
      if (sp) 
         sp->imind = ap ;
   }
   return ap ;
}
IMODE    *gen_deref(ENODE *node, int flags,int size)
/*
 *      return the addressing mode of a dereferenced node.
 */
{       IMODE    *ap1,*ap2,*ap3,*ap4;
        int             siz1,psize ;
        SYM *sp ;
        int nt = node->v.p[0]->nodetype ;
				psize = size;
				if (psize < 0)
					psize = - psize;
				/* get size */
        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_ptr_ref:
												siz1 = addrsize;
												break;
								case en_add:
												siz1 = addrsize;
												break;
								case en_ul_ref:
                        siz1 = 4;
                        break;
                        case en_ll_ref:
                              siz1 = -6 ;
                              break ;
                        case en_ull_ref:
                              siz1 = 6 ;
                              break ;
								case en_floatref:
                                    siz1 = 7;
												break;
								case en_doubleref:
												siz1 = 8;
												break;
								case en_longdoubleref:
												siz1 = 10;
												break;
                        case en_fimaginaryref: 
                                    siz1 = 15;
												break;
                        case en_rimaginaryref: 
                                    siz1 = 16;
												break;
                        case en_lrimaginaryref:
                                    siz1 = 17;
												break;
                        case en_fcomplexref: 
                                    siz1 = 20;
												break;
                        case en_rcomplexref: 
                                    siz1 = 21;
												break;
                        case en_lrcomplexref:
                                    siz1 = 22;
												break;
								default:
												siz1 = intsize;
                }
				/* deref for add nodes */
        if( node->v.p[0]->nodetype == en_add )
                {
                ap1 = gen_expr(0,node->v.p[0],0,size);
								ap1 = indnode(ap1,siz1);
								ap1->offset->cflags = node->v.p[0]->cflags;
                return ap1;
                }
				/* deref for auto variables */
        else if( node->v.p[0]->nodetype == en_imode)
                {
                ap1 = node->v.p[0]->v.p[1];
                return ap1;
                }
				/* deref for cpu registers */
				else if (node->v.p[0]->nodetype == en_regref) {
        	ap1 = gen_expr(0,node->v.p[0],0,regsize);
					ap1->offset->cflags = node->v.p[0]->cflags;
					return ap1;
				}
				/* other deref */
        switch(nt) {
         case en_labcon:
            ap1 = xalloc(sizeof(IMODE)) ;
            ap1->mode = i_direct ;
            ap1->offset = node->v.p[0] ;
            ap1->size = siz1 ;
            break ;
         case en_nalabcon:
         case en_nacon:
         case en_napccon:
         case en_autocon:
         case en_autoreg:
         case en_absacon:
            sp = node->v.p[0]->v.sp ;
            if (sp->imvalue)
               return sp->imvalue ;
            if (sp && sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
               global_flag++ ;
            ap1 = xalloc(sizeof(IMODE)) ;
            sp->imvalue = ap1 ;
            ap1->mode = i_direct ;
            ap1->offset = copy_enode(node->v.p[0]) ;
            ap1->size = siz1 ;
            if (sp && sp->storage_class != sc_auto && sp->storage_class != sc_autoreg)
               global_flag-- ;
            break ;
         default:
            ap1 = gen_expr(0,node->v.p[0],0,siz1); /* generate address */
            ap1 = indnode(ap1,siz1);
            break ;
        }
        ap1->offset->cflags = node->v.p[0]->cflags;
        return ap1;
}

IMODE    *gen_unary(ENODE *asn, ENODE *node,int flags,int size,int op)
/*
 *      generate code to evaluate a unary minus or complement.
 */
{       IMODE    *ap,*ap1;
        ap = gen_expr(0,node->v.p[0],F_VOL,size);
        gen_icode(op,ap1=genasn(asn,size),ap,0);
        return ap1;
}

IMODE    *gen_binary(ENODE *asn, ENODE *node,int flags,int size,int op)
/*
 *      generate code to evaluate a binary node and return 
 *      the addressing mode of the result.
 */
{       IMODE    *ap,*ap1, *ap2;
        ap1 = gen_expr(0,node->v.p[0],F_VOL,size);
        ap2 = gen_expr(0,node->v.p[1],0,size);
        gen_icode(op,ap =genasn(asn,size),ap1,ap2);
        return ap;
}

IMODE * gen_pdiv(ENODE *asn, ENODE *node, int flags, int size)
/*
 *			generate code for an array/structure size compensation
 */
{
				IMODE *ap,*ap1, *ap2;
				ap1 = gen_expr(0,node->v.p[0],F_VOL,4);
				ap2 = gen_expr(0,node->v.p[1],0,2);
				gen_icode(i_udiv,ap=genasn(asn,size),ap2,ap1);
        return ap;
}			
IMODE * gen_pmul(ENODE *asn, ENODE *node, int flags, int size)
/*
 *			generate code for an array/structure size compensation
 */
{
				IMODE *ap, *ap1, *ap2;
				ap1 = gen_expr(0,node->v.p[0],F_VOL,intsize);
				ap2 = gen_expr(0,node->v.p[1],0,intsize);
				gen_icode(i_umul,ap=genasn(asn,size),ap2,ap1);
        return ap;
}			

IMODE    *gen_hook(ENODE *asn, ENODE *node, int flags, int size)
/*
 *      generate code to evaluate a condition operator node (?:)
 */
{
        IMODE *ap1,*ap2 ;
        int             false_label, end_label;
        false_label = nextlabel++;
        end_label = nextlabel++;
        flags = flags | F_VOL;
        falsejp(node->v.p[0],false_label);
        node = node->v.p[1];
        ap1 = tempreg(natural_size(node),0) ;
        ap2 = gen_expr(0,node->v.p[0],flags,size);
        gen_icode(i_assn,ap1,ap2,0);
        ap1->offset->v.sp->iglobal = TRUE ;
        gen_igoto(end_label);
        gen_label(false_label);
        ap2 = gen_expr(0,node->v.p[1],flags,size);
        gen_icode(i_assn,ap1,ap2,0);
        ap1->offset->v.sp->iglobal = TRUE ;
        gen_label(end_label);
        if (asn)
         gen_icode(i_assn,ap1=genasn(asn,size),ap1,0) ;
        return ap1;
}

IMODE *gen_asunary(ENODE *asn, ENODE *node, int flags, int size, int op)
{       IMODE    *ap;
            int nsize = natural_size(node->v.p[0]);
        ap = gen_expr(0,node->v.p[0],0,nsize);
        gen_icode(op,ap,ap,0) ;
        return ap ;
}
IMODE    *gen_asbin(ENODE *asn,ENODE *node, int flags, int size, int op)
/*
 *      generate a plus equal or a minus equal node.
 */
{       IMODE    *ap,*ap1, *ap2;
        int             ssize,rsize;
        ssize = natural_size(node->v.p[0]);
        rsize = natural_size(node->v.p[1]);
				ap1 = gen_expr(0,node->v.p[0],0,ssize);
				ap2 = gen_expr(0,node->v.p[1],0,rsize);
				gen_icode(op,ap1,ap1,ap2);
				if (asn)
					gen_icode(i_assn,genasn(asn,size),ap1,0);
				ap = xalloc(sizeof(IMODE));
				ap->bits = ap1->bits;
				ap->startbit = ap1->startbit;
				ap->offset = ap1->offset;
				ap->mode = ap1->mode;
				return(ap);
}

IMODE *gen_moveblock(ENODE *node, int flags, int size)
/*
 * Generate code to copy one structure to another
 */
{
	IMODE *ap1, *ap2;
	if (!node->size)
		return(0);
	ap1 = gen_expr(0,node->v.p[0], F_VOL, 4);
	ap2 = gen_expr(0,node->v.p[1], F_VOL,4);
   gen_icode(i_assnblock,ap1,ap2,make_immed(node->size));
	return(ap1);
}
IMODE    *gen_assign(ENODE *asn, ENODE *node, int flags, int size,int ref)
/*
 *      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.
 */
{       IMODE    *ap2;
        ENODE *enode ;
				if (ref) {
					enode = makenode(node->v.p[0]->nodetype, makenode(en_cp,node->v.p[0]->v.p[0],0),0);
				}
				else enode = node->v.p[0];
        ap2 = gen_expr(enode,node->v.p[1],0,natural_size(node));
				if (asn) 
					gen_icode(i_assn,genasn(asn,size),ap2,0);
				return ap2;
}

IMODE    *gen_aincdec(ENODE *asn, ENODE *node, int flags, int size, int op)
/*
 *      generate an auto increment or decrement node. op should be
 *      either op_add (for increment) or op_sub (for decrement).
 */
{       IMODE    *ap1;
        int             siz1;
        siz1 = natural_size(node->v.p[0]);
        if( flags & F_NOVALUE )         /* dont need result */
                {
        				ap1 = gen_expr(0,node->v.p[0],F_ADDR,siz1);
                gen_icode(op,ap1,ap1,make_immed((long)node->v.p[1]));
								return ap1;
								}
        ap1 = gen_expr(asn,node->v.p[0],F_ADDR,siz1);
        gen_icode(op,ap1,ap1,make_immed((long)node->v.p[1]));
        return ap1;
}

int push_param(ENODE *ep,int size)
/*
 *      push the operand expression onto the stack.
 */
{       IMODE    *ap;
				int rv;
				switch (ep->nodetype) {
                case en_imode:
                        ap = ep->v.p[0];
												gen_icode(i_parm,0,ap,0);
                                    rv = ap->size;
												break;
								default:
												rv = natural_size(ep);
      			  					ap = gen_expr(0,ep,F_ADDR,rv);
												gen_icode(i_parm,0,ap,0);
                                    rv = ap->size;
												break;
				}
	return(rv < 0 ? -rv : rv);
}
int push_stackblock(ENODE *ep)
/*
 * Push a structure on the stack
 */
{
	IMODE *ap;
	int sz = ep->size;
	if (!sz)
		return(0);
				switch (ep->nodetype) {
                case en_imode:
                        ap = ep->v.p[0];
												break;
								default:
      			  					ap = gen_expr(0,ep,F_ADDR,sz);
												break;
				}
	gen_icode(i_parmblock,0,ap,(IMODE *)sz);
	sz = sz <0 ? -sz : sz;
	sz+=intsize-1;
	sz/=intsize;
	sz *= intsize;
	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],size);               
                plist = plist->v.p[1];
                }
        return i;
}

IMODE    *gen_tcall(ENODE *node, int flags)
/*
 *      generate a trap call node and return the address mode
 *      of the result.
 */
{       IMODE    *ap, *result;
        int             i,siz1;
               ap = make_offset(node->v.p[0]->v.p[0]);
					ap->mode = i_immed;
					gen_igosub(i_int,ap);
				if (!(flags & F_NOVALUE))
         gen_icode(i_assn,ap=genasn(ap,ap->size),&rret,0);  
        return ap;
}
IMODE *inlinecall(ENODE *node,int flags)
{
      ENODE *nameref = node,*thisn = 0; 
      SYM *sp;
      IMODE *ap = 0 ;
      int size;
         size = currentfunc->tp->btp->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;
               IMODE *ap;
					SYM *oldcurfunc = currentfunc ;
					currentfunc = sp;
               retlab = nextlabel++;
#ifdef XXXXX
					if (sp->value.classdata.cppflags & PF_CONSTRUCTOR) {
						SYM *psp = sp->parentclass ;
                  if (psp && psp->value.classdata.baseclass->vtabsp) {
                     ENODE *ts = makenode(en_nacon,psp->value.classdata.baseclass->vtabsp, 0) ;
							thisn = makenode(en_l_ref,thisn,0);
							ts = makenode(en_assign,thisn,ts) ;
							gen_expr(ts,FALSE,TRUE,4) ;
						}
					}
#endif 
					genstmt(sp->value.classdata.inlinefunc->stmt);
				if (!(flags & F_NOVALUE))
         gen_icode(i_assn,ap=tempreg(4,0),&rret,0);  
         }
      }
      return ap;
}
IMODE    *gen_fcall(ENODE *asn, ENODE *node,int flags, int size)
/*
 *      generate a function call node and return the address mode
 *      of the result.
 */
{       IMODE    *ap;
        int             i,siz1;
        ENODE *pushthis=0 ;
				/* if it returns a structure */
            if (ap = inlinecall(node,flags))
					return ap;
				if (node->nodetype != en_callblock && node->nodetype != en_scallblock)
               if (ap = HandleIntrins(node, flags & F_NOVALUE))
						return ap;
#ifdef CPLUSPLUS
				if (node->nodetype == en_thiscall) {
					pushthis = node->v.p[0];
					node = node->v.p[1];
					i = 4;
				}
#endif
				if (node->nodetype == en_callblock || node->nodetype == en_scallblock) {
					siz1 = 4;
				}
				else {
					siz1 = node->v.p[0]->v.i;
				}
				if (node->nodetype == en_callblock) {
               i += gen_parms(node->v.p[1]->v.p[1]->v.p[1]->v.p[0],size);
      		ap = gen_expr(0,node->v.p[0],F_ADDR,addrsize);
					gen_icode(i_parm,0,ap,0);
					i+=addrsize;
					node=node->v.p[1];
					siz1 = 4;
				}
				else  {
           i += gen_parms(node->v.p[1]->v.p[1]->v.p[0],size);    /* generate parameters */
				}
				if (node->nodetype == en_trapcall) {
					/* trap call */
					gen_igosub(i_trap,make_immed(node->v.p[1]->v.p[0]->v.i));
				}
				else if (node->nodetype == en_intcall) {
					/* int call */
					ap = make_offset(node->v.p[0]);
					ap->mode = i_immed;
					gen_igosub(i_int,ap);
				}
            else if (pushthis) {
               IMODE *ap2 = gen_expr(pushthis,FALSE,TRUE,4);
               gen_icode(i_parm,0,ap2,0);
				}
				/* named function */
            if( node->v.p[1]->v.p[0]->nodetype == en_imode) {
                        ap= node->v.p[1]->v.p[0]->v.p[0]->v.sp;
       	        gen_igosub(i_gosub,ap);
				}
        else
				/* pointer to function */
                {
                ap = gen_expr(0,node->v.p[1]->v.p[0],0,4);
                gen_igosub(i_gosub,ap);
                }
            /* undo pars and make a temp for the result */
        if (node->nodetype != en_fcallb && node->nodetype != en_fcall && node->nodetype != en_callblock)
            if( i != 0 ) {
                gen_nodag(i_parmadj,0,make_parmadj(i),0);
				}
				if (!(flags & F_NOVALUE))
        	gen_icode(i_assn,ap=genasn(asn,size),&rret,0);	
        return ap;
}
IMODE    *gen_repcons(ENODE *node)
/*
 *      generate a function call node and return the address mode
 *      of the result.
 */
{       IMODE    *ax, *cx, *ap,*ap1, *ap2,*ap3,*ap4;
				ENODE *pushthis = 0,*onode = node ;
        int             i=0,siz1;
            int lab ;
				int regax,regdx,regcx;
				node = node->v.p[1] ;
#ifdef CPLUSPLUS
				if (node->nodetype == en_thiscall) {
					pushthis = node->v.p[0];
					node = node->v.p[1];
					i = 4;
				}
#endif
            ap1 = gen_expr(0,onode->v.p[0]->v.p[0],0,4) ;
            ap3 = genasn(onode->v.p[0]->v.p[0],4) ;
				if (pushthis) {
               ap2 = genasn(pushthis,4) ;
				}
				gen_label(lab = nextlabel++) ;
				
				/* named function */
            if( node->v.p[1]->v.p[0]->nodetype == en_imode) {
                        ap= node->v.p[1]->v.p[0]->v.p[0]->v.sp;
       	        gen_igosub(i_gosub,ap);
				}
        else
				/* pointer to function */
                {
                ap = gen_expr(0,node->v.p[1]->v.p[0],0,4);
                gen_igosub(i_gosub,ap);
                }
            gen_icode(i_add,ap3,ap3,make_immed((int)node->v.p[0]->v.p[1]->v.p[0])) ;
            gen_icode(i_sub,ap1,ap1,make_immed(1)) ;
            gen_icgoto(i_jg,lab,ap1,make_immed(0)) ;
}
IMODE    *gen_pfcall(ENODE *asn, ENODE *node,int flags, int size)
/*
 *      generate a function call node and return the address mode
 *      of the result.
 */
{       IMODE    *ap;
        ENODE *pushthis=0 ;
        int             i,siz1;
				ENODE * invnode = 0,*anode,*node2;
            if (ap = inlinecall(node,flags))
					return ap;
				
				/* invert the parameter list */
            if (node->nodetype == en_pcallblock || node->nodetype == en_scallblock)
					anode = node->v.p[1]->v.p[1]->v.p[1]->v.p[0];
				else
					anode = node->v.p[1]->v.p[1]->v.p[0];
				while (anode) {
					invnode = makenode(anode->nodetype,anode->v.p[0],invnode);
					anode = anode->v.p[1];
				}
				/* if it returns a structure */
#ifdef CPLUSPLUS
				if (node->nodetype == en_thiscall) {
					pushthis = node->v.p[0];
					node = node->v.p[1];
					i = 4;
				}
#endif
				if (node->nodetype == en_pcallblock || node->nodetype == en_scallblock) {
					siz1 = 4;
				}
				else {
					siz1 = node->v.p[0]->v.i;
				}
				if (pushthis) {
               IMODE *ap2 = gen_expr(pushthis,FALSE,TRUE,4);
               gen_icode(i_parm,0,ap2,0);
				}
            if (node->nodetype == en_callblock || node->nodetype == en_scallblock) {
					i = gen_parms(invnode,size);
      		ap = gen_expr(0,node->v.p[0],F_ADDR,addrsize);
					gen_icode(i_parm,0,ap,0);
					i+=addrsize;
					node=node->v.p[1];
					siz1 = 4;
				}
				else  {
	        i = gen_parms(invnode,size);    /* generate parameters */
					siz1 = natural_size(node->v.p[1]);
				}
				if (node->nodetype == en_trapcall) {
					/* trap call */
					gen_igosub(i_trap,make_immed(node->v.p[1]->v.p[0]->v.i));
				}
				else if (node->nodetype == en_intcall) {
					/* int call */
					ap = make_offset(node->v.p[0]);
					ap->mode = i_immed;
					gen_igosub(i_int,ap);
				}
				else if (pushthis) {
               IMODE *ap2 = gen_expr(0,pushthis,0,4);
               gen_icode(i_parm,0,ap2,0);
				}
				/* named function */
            if( node->v.p[1]->v.p[0]->nodetype == en_imode) {
								ap= node->v.p[1]->v.p[0]->v.p[0];
       	        gen_igosub(i_gosub,ap);
				}
            else
				/* pointer to function */
                {
                ap = gen_expr(0,node->v.p[1]->v.p[0],0,4);
                gen_igosub(i_gosub,ap);
                }
				if (!(flags & F_NOVALUE))
        	gen_icode(i_assn,ap=genasn(asn,size),&rret,0);	
        return ap;
}

IMODE    *gen_expr(ENODE *asn,ENODE *node, int flags, int size)
/*
 *      general expression evaluation. returns the addressing mode
 *      of the result.
 *
 *			The first argument of this and other routines is a target for
 *			assignmennt.  If this is 0 and a target is needed a temp will be
 *			used; otherwise the target will be evaluated annd used.
 */
{
				IMODE    *ap1, *ap2,*ap3;
            int lab0,lab1,lab2;
        int             natsize,siz1;
        if( node == 0 )
                {
                DIAG("null node in gen_expr.");
                return 0;
                }
        switch( node->nodetype )
                {
                        case en_cl_reg:
                                    ap1 = gen_expr(0,node->v.p[0],flags, size) ;
												if (asn)
                                      gen_icode(i_assn,gen_expr(0,asn,flags,size),ap1,0);
                                    return ap1 ;
								case en_cb: 
												siz1 = -1;
												goto castjoin;
                        case en_cub: 
                        case en_cbool:
												siz1 = 1;
												goto castjoin;
								case en_cw: 
												siz1 = -2;
												goto castjoin;
								case en_cuw:
												siz1 = 2;
												goto castjoin;
								case en_cl: 
												siz1 = -4;
												goto castjoin;
								case en_cul:
												siz1 = 4;
												goto castjoin;
                        case en_cll: 
                                    siz1 = -6;
                                    goto castjoin;
                        case en_cull:
                                    siz1 = 6;
												goto castjoin;
                                     
								case en_cf: 
                                    siz1 = 7;
												goto castjoin;
								case en_cd: 
												siz1 = 8;
												goto castjoin;
								case en_cld: 
												siz1 = 10;
												goto castjoin;
                        case en_cfi: 
                                    siz1 = 15;
												goto castjoin;
                        case en_cri: 
                                    siz1 = 16;
												goto castjoin;
                        case en_clri: 
                                    siz1 = 17;
												goto castjoin;
                        case en_cfc: 
                                    siz1 = 20;
												goto castjoin;
                        case en_crc: 
                                    siz1 = 21;
												goto castjoin;
                        case en_clrc: 
                                    siz1 = 22;
												goto castjoin;
								case en_cp:
												siz1 = 4;
castjoin:
												ap1 = gen_expr(0,node->v.p[0],flags,natural_size(node->v.p[0]));
												if (ap1->size == siz1)
													ap2 = ap1;
												else {
													gen_icode(i_assn, ap2 = tempreg(siz1,0),ap1,0);
												}
												if (asn)
												  gen_icode(i_assn,gen_expr(0,asn,flags,size),ap2,0);
												return ap2;
                case en_napccon:
                case en_nacon:
                case en_autocon:
                case en_autoreg:
                case en_absacon:
                case en_nalabcon:
                        ap1 = make_imaddress(node,size) ;
                        if (asn)
                           gen_icode(i_assn,gen_expr(0,asn,flags,size),ap1,0);
                        return ap1;             /* return reg */
                case en_labcon:
                        ap1 = xalloc(sizeof(IMODE)) ;
                        ap1->offset = node ;
                        ap1->mode = i_direct ;
                        ap1->size = size ;
                        if (asn)
                           gen_icode(i_assn,gen_expr(0,asn,flags,size),ap1,0);
                        return ap1;             /* return reg */
                case en_imode:
												ap2 = node->v.p[0];
												if (asn)
												  gen_icode(i_assn,gen_expr(0,asn,flags,size),ap2,0);
                        return ap2;             /* return reg */
								case en_ccon:
                case en_icon:
                case en_lcon:
								case en_lucon:
								case en_iucon:
                        case en_llcon:
                        case en_llucon:
                                    ap1 = make_immed(node->v.i);
                                    ap1->offset->nodetype = node->nodetype ;
												if (asn)
												  gen_icode(i_assn,gen_expr(0,asn,flags,size),ap1,0);
                        return ap1;
								case en_fcon:
								case en_rcon:
								case en_lrcon:
                        case en_fimaginarycon:
                        case en_rimaginarycon:
                        case en_lrimaginarycon:
                        case en_fcomplexcon:
                        case en_rcomplexcon:
                        case en_lrcomplexcon:
                                    make_fimmed(node->v.f);
                                    ap1->offset->nodetype = node->nodetype ;
												if (asn)
												  gen_icode(i_assn,gen_expr(0,asn,flags,size),ap1,0);
                        return ap1;
                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_ptr_ref:
                case en_ul_ref:
								case en_floatref:
								case en_doubleref:
								case en_longdoubleref:
                        case en_ll_ref :
                        case en_ull_ref:
                        case en_fimaginaryref:
                        case en_rimaginaryref:
                        case en_lrimaginaryref:
                        case en_fcomplexref:
                        case en_rcomplexref:
                        case en_lrcomplexref:
                        ap1 = gen_deref(node,flags,size);
												if (asn) {
													ap2 = gen_expr(0,asn,flags,size);
													gen_icode(i_assn,ap2,ap1,0);
												}
												return ap1;
                case en_regref:
                        ap1 = xalloc(sizeof(IMODE));
												ap1->offset = node;
												ap1->mode = i_direct;
												ap1->size = intsize;
												if (asn)
												  gen_icode(i_assn,gen_expr(0,asn,flags,size),ap1,0);
                        return ap1;
								case en_bits:
												size = natural_size(node->v.p[0]);
												ap1 = gen_expr(asn,node->v.p[0],0,size);
												ap1 = make_bf(node,ap1,size);
												return ap1;

                case en_asuminus:
                        return gen_asunary(asn,node,flags,size,i_neg);
                case en_ascompl:
                        return gen_asunary(asn,node,flags,size,i_not);
                case en_uminus:
                        return gen_unary(asn,node,flags,size,i_neg);
                case en_compl:
                        return gen_unary(asn,node,flags,size,i_not);
                case en_add:
                case en_addstruc:
                        return gen_binary(asn,node,flags,size,i_add);
                case en_sub:
                        return gen_binary(asn,node,flags,size,i_sub);
                case en_and:
                        return gen_binary(asn,node,flags,size,i_and);
                case en_or:
                        return gen_binary(asn,node,flags,size,i_or);
								case en_xor:
												return gen_binary(asn,node,flags,size,i_eor);
								case en_pmul:
												return gen_pmul(asn,node,flags,size);
								case en_pdiv:
												return gen_pdiv(asn,node,flags,size);
                case en_mul:
                        return gen_binary(asn,node,flags,size,i_smul);
                case en_umul:
                        return gen_binary(asn,node,flags,size,i_smul);
                case en_div:
                        return gen_binary(asn,node,flags,size,i_sdiv);
                case en_udiv:
                        return gen_binary(asn,node,flags,size,i_udiv);
                case en_mod:
                        return gen_binary(asn,node,flags,size,i_smod);
                case en_umod:
                        return gen_binary(asn,node,flags,size,i_umod);
                case en_alsh:
                        return gen_binary(asn,node,flags,size,i_asl);
                case en_arsh: case en_arshd:
                        return gen_binary(asn,node,flags,size,i_asr);
                case en_lsh:
                        return gen_binary(asn,node,flags,size,i_lsl);
                case en_rsh:
                        return gen_binary(asn,node,flags,size,i_lsr);
                case en_asadd:
                        return gen_asbin(asn,node,flags,size,i_add);
                case en_assub:
                        return gen_asbin(asn,node,flags,size,i_sub);
                case en_asand:
                        return gen_asbin(asn,node,flags,size,i_and);
                case en_asor:
                        return gen_asbin(asn,node,flags,size,i_or);
                case en_asxor:
                        return gen_asbin(asn,node,flags,size,i_eor);
                case en_aslsh:
                        return gen_asbin(asn,node,flags,size,i_lsl);
                case en_asrsh:
                        return gen_asbin(asn,node,flags,size,i_lsr);
                case en_asalsh:
                        return gen_asbin(asn,node,flags,size,i_asl);
                case en_asarsh: case en_asarshd:
                        return gen_asbin(asn,node,flags,size,i_asr);
                case en_asmul:
                        return gen_asbin(asn,node,flags,size, i_smul);
                case en_asumul:
                        return gen_asbin(asn,node,flags,size,i_umul);
                case en_asdiv:
                        return gen_asbin(asn,node,flags,size,i_sdiv);
                case en_asudiv:
                        return gen_asbin(asn,node,flags,size,i_udiv);
                case en_asmod:
                        return gen_asbin(asn,node,flags,size,i_sdiv);
                case en_asumod:
                        return gen_asbin(asn,node,flags,size,i_udiv);
                case en_assign:
                        return gen_assign(asn,node,flags,size,FALSE);
                case en_refassign:
                        return gen_assign(asn,node,flags | F_NOVALUE,size,TRUE);
                case en_moveblock:
                        return gen_moveblock(node,flags,size);
                case en_ainc:
                        return gen_aincdec(asn,node,flags,size,i_add);
                case en_adec:
                        return gen_aincdec(asn,node,flags,size,i_sub);
                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(asn,node,flags,size);
                case en_void:
                        natsize = natural_size(node->v.p[0]);
                        return gen_expr(asn,node->v.p[1],flags,size);
                case en_voidnz:
                        lab0 = nextlabel++;
                        falsejp(node->v.p[0]->v.p[0],lab0);
                        gen_void(node->v.p[1]) ;
                        gen_label(lab0);
                        return gen_expr(0,node->v.p[0]->v.p[1],0,4) ; /* will typically be part of a void tree, or top of tree */
                case en_pfcall:  case en_pfcallb: case en_pcallblock:
                        return gen_pfcall(asn,node,flags,size);
                case en_fcall:  case en_callblock: case en_fcallb:
                case en_sfcall:  case en_scallblock: case en_sfcallb:
                case en_intcall:
                case en_trapcall:
                case en_thiscall:
                        return gen_fcall(asn,node,flags,size);
                case en_repcons:
                        return gen_repcons(node) ;
                default:
                        DIAG("uncoded node in gen_expr.");
                        return 0;
                }
}

IMODE    *gen_void(ENODE *node)
{
   gen_expr(0,node,0,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_asuminus: case en_ascompl:
                        case en_bits: case en_cl_reg:
												return natural_size(node->v.p[0]);;
								case en_ccon:
												return 1;
								case en_lcon:
                case en_icon:
												return -intsize;
								case en_lucon:
                case en_iucon:
												return intsize;
								case en_rcon:
								case en_doubleref:
												return 8;
								case en_lrcon:
								case en_longdoubleref:
												return 10;
								case en_floatref:
								case en_fcon:
                                    return 7;
                        case en_fimaginaryref: 
                        case en_fimaginarycon: 
                        case en_cfi:
                           return 15;
                        case en_rimaginaryref: 
                        case en_rimaginarycon: 
                        case en_cri:
                           return 16;
                        case en_lrimaginaryref:
                        case en_lrimaginarycon:
                        case en_clri:
                           return 17;
                        case en_fcomplexref: 
                        case en_fcomplexcon: 
                        case en_cfc:
                           return 20;
                        case en_rcomplexref: 
                        case en_rcomplexcon: 
                        case en_crc:
                           return 21;
                        case en_lrcomplexref:
                        case en_lrcomplexcon:
                        case en_clrc:
                           return 22;
                        case en_llucon:
                                    return 6 ;
                        case en_llcon:
                                    return -6 ;
								case en_imode:
												return addrsize;
								case en_cl: case en_l_ref:
												return -4;
								case en_ptr_ref:
								case en_trapcall:
                case en_labcon:
                case en_nacon:  case en_autocon:
                case en_napccon:  case en_absacon: case en_nalabcon:
												return addrsize;
								case en_autoreg:
                                    return intsize;
								case en_fcall: case en_callblock: case en_fcallb:
                        case en_sfcall: case en_scallblock: case en_sfcallb:
								case en_pfcall: case en_pcallblock: case en_pfcallb:
								case en_intcall:
												return natural_size(node->v.p[1]);
								case en_tempref:
												return intsize;
								case en_regref:
												return regsize;
                        case en_ull_ref:
                        case en_cull:
                              return 6 ;
                        case en_ll_ref:
                        case en_cll:
                              return -6 ;
                case en_ul_ref:
								case en_cul:
								case en_cp:
                        return 4;
                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_lassign:
                case en_ainc:   case en_adec:
								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_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: case en_asarshd: case en_arshd:
                        siz0 = natural_size(node->v.p[0]);
                        siz1 = natural_size(node->v.p[1]);
                        if( chksize(siz1,siz0))
                                return siz1;
                        else
                                return siz0;
                case en_void:   case en_cond: case en_repcons:
                        return natural_size(node->v.p[1]);
                case en_voidnz:
                        return natural_size(node->v.p[1]) ;
                default:
                        DIAG("natural size error.");
                        break;
                }
        return 0;
}

void gen_compare(ENODE *node, int btype, int label)
/*
 *      generate code to do a comparison of the two operands of
 *      node.
 */
{       IMODE    *ap1, *ap2;
        int             size;
        size = natural_size(node);
        ap1 = gen_expr(0,node->v.p[0],0,size);
        ap2 = gen_expr(0,node->v.p[1],0,size);
        gen_icgoto(btype,label,ap1,ap2);
}
IMODE * gen_set(ENODE *node, int btype, int aa)
{
   IMODE *ap1,*ap2,*ap3 ;
   int size ;
   ap1 = gen_expr(0,node->v.p[0],0,size) ;
   ap2 = gen_expr(0,node->v.p[1],0,size);
   ap3 = tempreg(4,0) ;
   gen_icode(btype,ap3,ap2,ap1) ;

   return ap3 ;
}
IMODE *defcond(ENODE *node)
{
   IMODE *ap1, *ap2,*ap3 ;
   int size ;
   ap1 = gen_expr(0,node->v.p[0],0,size) ;
   ap2 = make_immed(0) ;
   ap3 = tempreg(4,0) ;
   gen_icode(i_setne,ap3,ap2,ap1) ;
   return ap3 ;
}


static IMODE *truerelat(ENODE *node)
{       IMODE    *ap1;
        if( node == 0 )
                return 0;
        switch( node->nodetype )
                {
                case en_eq:
                        ap1 = gen_set(node,i_sete,0);
                        break;
                case en_ne:
                        ap1 = gen_set(node,i_setne,0);
                        break;
                case en_lt:
                        ap1 = gen_set(node,i_setl,0);
                        break;
                case en_le:
                        ap1 = gen_set(node,i_setle,0);
                        break;
                case en_gt:
                        ap1 = gen_set(node,i_setg,0);
                        break;
                case en_ge:
                        ap1 = gen_set(node,i_setge,0);
                        break;
                case en_ult:
                        ap1 = gen_set(node,i_setc,0);
                        break;
                case en_ule:
                        ap1 = gen_set(node,i_setbe,0);
                        break;
                case en_ugt:
                        ap1 = gen_set(node,i_seta,0);
                        break;
                case en_uge:
                        ap1 = gen_set(node,i_setnc,0);
                        break;
                case en_not:
                        ap1 = defcond(node) ;
                        break;
                default:
												DIAG("True-relat error");
                        break;
                }
  ap1->size = 1;
	return ap1;
}
static int complex_relat(ENODE *node)
{
				if (!node)
					return 0;
        switch( node->nodetype )
                {
                case en_cl_reg:
                  return complex_relat(node->v.p[0]) ;
                case en_ull_ref:
                case en_ll_ref:
                case en_cull:
                case en_cll:
                case en_llcon: case en_llucon:
                  return 1 ;
								case en_bits:
								case en_l_ref:
								case en_cl:
                case en_ul_ref:
								case en_cul:
								case en_cp:
                case en_ub_ref:
								case en_cub:
                case en_bool_ref: case en_cbool:
                case en_b_ref:
                case en_cb:
                case en_uw_ref:
								case en_cuw:
                case en_cw:
                case en_w_ref:
								case en_cd:
								case en_cld:
								case en_cf:
                        case en_cfc: case en_crc: case en_clrc:
                        case en_cfi: case en_cri: case en_clri:
                case en_uminus: 
                case en_ainc:   case en_adec: 
								case en_moveblock: case en_stackblock:
												return complex_relat(node->v.p[0]);
                case en_icon:
								case en_lcon: 
								case en_lucon: 
								case en_iucon: 
								case en_ccon:                 
								case en_rcon:
								case en_doubleref:
								case en_lrcon:
								case en_longdoubleref:
								case en_fcon:
								case en_floatref:
                        case en_fimaginaryref: case en_rimaginaryref: case en_lrimaginaryref:
                        case en_fcomplexref: case en_rcomplexref: case en_lrcomplexref:
                        case en_fimaginarycon: case en_rimaginarycon: case en_lrimaginarycon:
                        case en_fcomplexcon: case en_rcomplexcon: case en_lrcomplexcon:
								case en_absacon:
								case en_trapcall:
                case en_labcon:
                case en_nacon:  case en_autocon:  case en_autoreg:
                case en_napccon: case en_nalabcon:
								case en_tempref:
								case en_regref:
												return 0;
                case en_eq:     case en_ne:
                case en_lt:     case en_le:
                case en_gt:     case en_ge:
								case en_ugt: case en_uge: case en_ult: case en_ule:
                case en_land:   case en_lor:
                case en_not:    case en_compl:
												return 1;
								case en_div: case en_udiv: case en_pdiv: case en_mod: case en_umod:
                        case en_assign: case en_refassign: case en_lassign:
                        case en_asuminus: case en_ascompl:
                case en_add:    case en_sub: case en_addstruc:
								case en_umul:		case en_pmul:
                case en_mul:		case en_and:
                case en_or:     case en_xor:
								case en_asalsh: case en_asarsh: case en_alsh: case en_arsh: case en_arshd: case en_asarshd:
                case en_lsh:    case en_rsh:
                case en_asadd:  case en_assub:
                case en_asmul:  case en_asdiv:
                case en_asmod:  case en_asand:
								case en_asumod: case en_asudiv: case en_asumul:
                case en_asor:   case en_aslsh:  case en_asxor:
                case en_asrsh:  case en_repcons:
												return complex_relat(node->v.p[0]) || complex_relat(node->v.p[1]);
                case en_void:   case en_cond: case en_voidnz:
												return complex_relat(node->v.p[1]);
								case en_sfcall: case en_sfcallb: case en_scallblock:
								case en_pfcall: case en_pfcallb: case en_thiscall:
								case en_fcall: case en_intcall: case en_callblock: case en_fcallb:
								case en_pcallblock:
												return 0;
                default:
                        DIAG("error in complex_relat routine.");
												return 1;
                }
}
IMODE *gen_relat(ENODE *node)
{
   long lab1,lab2;
   IMODE *ap1;
   int size = natural_size(node);
	if (node->nodetype != en_land && node->nodetype != en_lor &&
			!complex_relat(node->v.p[0]) && !complex_relat(node->v.p[1])) {
		ap1 = truerelat(node);
	}
	else {
     ap1 = tempreg(4,0) ;
     lab1 = nextlabel++, lab2 = nextlabel++;
	  truejp(node,lab1);
     gen_icode(i_assn,ap1,make_immed(0),0) ;
     gen_igoto(lab2) ;
     gen_label(lab1) ;
     gen_icode(i_assn,ap1,make_immed(1),0) ;
     gen_label(lab2) ;
	}
  return ap1;
}
void truejp(ENODE *node, int label)
/*
 *      generate a jump to label if the node passed evaluates to
 *      a true condition.
 */
{       IMODE    *ap1;
        int             siz1;
        int             lab0;
        if( node == 0 )
                return;
        switch( node->nodetype )
                {
                case en_eq:
                        gen_compare(node,i_je,label);
                        break;
                case en_ne:
                        gen_compare(node,i_jne,label);
                        break;
                case en_lt:
                        gen_compare(node,i_jl,label);
                        break;
                case en_le:
                        gen_compare(node,i_jle,label);
                        break;
                case en_gt:
                        gen_compare(node,i_jg,label);
                        break;
                case en_ge:
                        gen_compare(node,i_jge,label);
                        break;
                case en_ult:
                        gen_compare(node,i_jc,label);
                        break;
                case en_ule:
                        gen_compare(node,i_jbe,label);
                        break;
                case en_ugt:
                        gen_compare(node,i_ja,label);
                        break;
                case en_uge:
                        gen_compare(node,i_jnc,label);
                        break;
                case en_land:
                        lab0 = nextlabel++;
                        falsejp(node->v.p[0],lab0);
                        truejp(node->v.p[1],label);
                        gen_label(lab0);
                        break;
                case en_lor:
                        truejp(node->v.p[0],label);
                        truejp(node->v.p[1],label);
                        break;
                case en_not:
                        falsejp(node->v.p[0],label);
                        break;
                default:
                        siz1 = natural_size(node);    
                        ap1 = gen_expr(0,node,0,siz1);
                        gen_icgoto(i_jne,label,ap1,make_immed(0));
                        break;
                }
}

void falsejp(ENODE *node, int label)
/*
 *      generate code to execute a jump to label if the expression
 *      passed is false.
 */
{       IMODE    *ap;
        int             siz1;
        int             lab0;
        if( node == 0 )
                return;
        switch( node->nodetype )
                {
                case en_eq:
                        gen_compare(node,i_jne,label);
                        break;
                case en_ne:
                        gen_compare(node,i_je,label);
                        break;
                case en_lt:
                        gen_compare(node,i_jge,label);
                        break;
                case en_le:
                        gen_compare(node,i_jg,label);
                        break;
                case en_gt:
                        gen_compare(node,i_jle,label);
                        break;
                case en_ge:
                        gen_compare(node,i_jl,label);
                        break;
                case en_ult:
                        gen_compare(node,i_jnc,label);
                        break;
                case en_ule:
                        gen_compare(node,i_ja,label);
                        break;
                case en_ugt:
                        gen_compare(node,i_jbe,label);
                        break;
                case en_uge:
                        gen_compare(node,i_jc,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);    
                        ap = gen_expr(0,node,0,siz1);
                        gen_icgoto(i_je,label,ap,make_immed(0));
                        break;
                }
}