/* 
   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
*/
/* no support for complex.  Floating point currently commented out */
/*
 * this module combines constants at compile time.  Integer constants
 * will get combined slightly better than floating point ones
 */
#include        <stdio.h>
#include				<string.h>
#include        "lists.h"
#include        "expr.h"
#include        "c.h"

static ENODE *asidehead,**asidetail ;
int maxinttype(ENODE *ep1, ENODE *ep2)
{
	int type1=ep1->nodetype;
	int type2 = ep2->nodetype;
   if (type1 == en_llucon || type2 == en_llucon)
      return en_llucon;
   if (type1 == en_llcon || type2 == en_llcon)
      return en_llcon;
	if (type1 == en_lucon || type2 == en_lucon)
		return en_lucon;
	if (type1 == en_lcon || type2 == en_lcon)
		return en_lcon;
	if (type1 == en_iucon || type2 == en_iucon)
		return en_iucon;
	if (type1 == en_icon || type2 == en_icon)
		return en_icon;
	return en_ccon;
}
int isunsigned(ENODE *ep1)
{
	switch(ep1->nodetype) {
		case en_lucon:
		case en_iucon:
      case en_llucon:
			return TRUE ;
		default:
			return FALSE ;
	}
}
int maxfloattype(ENODE *ep1, ENODE *ep2)
{
	int type1=ep1->nodetype;
	int type2 = ep2->nodetype;
	if (type1 == en_lrcon || type2 == en_lrcon)
		return en_lrcon;
	if (type1 == en_rcon || type2 == en_rcon)
		return en_rcon;
	return en_fcon;
}
int getmode(ENODE *ep1,ENODE *ep2)
/*
 * get the constant mode of a pair of nodes
 * 0 = Neither node is a constant
 * 1 = icon,icon
 * 2 = icon,rcon
 * 3 = rcon,icon
 * 4 = rcon,rcon
 * 5 = icon,nothing
 * 6 = rcon,nothing
 * 7 = nothing,icon
 * 8 = nothing,rcon
 */
{
				int mode = 0;
				if (isintconst(ep1->nodetype) )
					if (ep2)  {
						if (isintconst(ep2->nodetype))
							mode = 1;
                  else  if (ep2->nodetype == en_rcon || ep2->nodetype == en_lrcon || ep2->nodetype == en_fcon)
                     mode = 2;
						else mode = 5;
					}
					else
						mode = 5;
				else if (ep1->nodetype == en_rcon || ep1->nodetype == en_lrcon || ep1->nodetype == en_fcon)
					if (ep2)  {
						if (isintconst(ep2->nodetype))
							mode = 3;
                  else  if (ep2->nodetype == en_rcon || ep2->nodetype == en_lrcon || ep2->nodetype == en_fcon)
                     mode = 4;
						else mode = 6;
					}
					else
						mode = 6;
				else if (ep2)
					if (isintconst(ep2->nodetype))
						mode = 7;
               else  if (ep2->nodetype == en_rcon || ep2->nodetype == en_lrcon || ep2->nodetype == en_fcon)
                  mode = 8;
	return(mode);
}
	
void dooper(ENODE ** node, int mode)
/*
 *      dooper will execute a constant operation in a node and
 *      modify the node to be the result of the operation.
 *			It will also cast integers to floating point values when
 *			necessary
 */                             
{     ENODE    *ep,*ep1,*ep2;
      ep = *node;
			ep1 = ep->v.p[0];
			ep2 = ep->v.p[1];
			if (mode ==5) {
					if (floatrecurse(ep2)) {
					ep1->v.f = ep1->v.i;
					ep1->nodetype = en_rcon;
				}
				return;
			}
			else if (mode == 7) {
				if (floatrecurse(ep1)) {
					ep2->v.f = ep2->v.i;
					ep2->nodetype = en_rcon;
				}
				return;
			}
			else if (mode == 6 || mode == 8)
				return;
			else
        switch( ep->nodetype ) {
                case en_add:  case en_addstruc:
										 		switch (mode) {
													case 1:	
                        		ep->nodetype = maxinttype(ep1,ep2);
                        		ep->v.i = ep1->v.i + ep2->v.i;
														break;
													case 2:	
                        		ep->nodetype = maxfloattype(ep1,ep2);
                        		ep->v.f = ep1->v.i + ep2->v.f;
														break;
													case 3:	
                        		ep->nodetype = maxfloattype(ep1,ep2);
                        		ep->v.f = ep1->v.f + ep2->v.i;
														break;
													case 4:	
                        		ep->nodetype = maxfloattype(ep1,ep2);
                        		ep->v.f = ep1->v.f + ep2->v.f;
														break;
                        }
												break;
                case en_sub:
										 		switch (mode) {
													case 1:	
                        		ep->nodetype = maxinttype(ep1,ep2);
                        		ep->v.i = ep1->v.i - ep2->v.i;
														break;
													case 2:	
                        		ep->nodetype = maxfloattype(ep1,ep2);
                        		ep->v.f = ep1->v.i - ep2->v.f;
														break;
													case 3:	
                        		ep->nodetype = maxfloattype(ep1,ep2);
                        		ep->v.f = ep1->v.f - ep2->v.i;
														break;
													case 4:	
                        		ep->nodetype = maxfloattype(ep1,ep2);
                        		ep->v.f = ep1->v.f - ep2->v.f;
														break;
												}
                        break;
								case en_pmul:
								case en_umul:
                case en_mul:
										 		switch (mode) {
													case 1:	
                        		ep->nodetype = maxinttype(ep1,ep2);
                        		ep->v.i = ep1->v.i * ep2->v.i;
														break;
													case 2:	
                        		ep->nodetype = maxfloattype(ep1,ep2);
                        		ep->v.f = ep1->v.i * ep2->v.f;
														break;
													case 3:	
                        		ep->nodetype = maxfloattype(ep1,ep2);
                        		ep->v.f = ep1->v.f * ep2->v.i;
														break;
													case 4:	
                        		ep->nodetype = maxfloattype(ep1,ep2);
                        		ep->v.f = ep1->v.f * ep2->v.f;
														break;
												}
                        break;
								case en_pdiv:
                case en_div:
                case en_udiv:
										 		switch (mode) {
													case 1:	
                        		ep->nodetype = maxinttype(ep1,ep2);
														if (isunsigned(ep1) || isunsigned(ep2))
                        		  ep->v.i = (unsigned)ep1->v.i / (unsigned)ep2->v.i;
														else
                        		  ep->v.i = ep1->v.i / ep2->v.i;
														break;
													case 2:	
                        		ep->nodetype = maxfloattype(ep1,ep2);
														if (isunsigned(ep1))
                        			ep->v.f = (unsigned)ep1->v.i / ep2->v.f;
														else
                        			ep->v.f = ep1->v.i / ep2->v.f;
														break;
													case 3:	
                        		ep->nodetype = maxfloattype(ep1,ep2);
														if (isunsigned(ep2))
                        			ep->v.f = ep1->v.f / (unsigned)ep2->v.i;
														else
                        			ep->v.f = ep1->v.f / ep2->v.i;
														break;
													case 4:	
                        		ep->nodetype = maxfloattype(ep1,ep2);
   		                     		ep->v.f = ep1->v.f / ep2->v.f;
														break;
												}
                        break;
								case en_mod:
                        		ep->nodetype = maxinttype(ep1,ep2);
	
												if (isunsigned(ep1) || isunsigned(ep2))
													ep->v.i = (unsigned)ep1->v.i % (unsigned)ep2->v.i;
												else
													ep->v.i = ep1->v.i % ep2->v.i;
												break;
                case en_lsh:
								case en_alsh:
                        		ep->nodetype = maxinttype(ep1,ep2);
                        ep->v.i = ep1->v.i << ep2->v.i;
                        break;
                case en_rsh:
								case en_arsh:
								case en_arshd:
                        		ep->nodetype = maxinttype(ep1,ep2);
                        ep->v.i = ep1->v.i >> ep2->v.i;
                        break;
                case en_and:
                        		ep->nodetype = maxinttype(ep1,ep2);
                        ep->v.i = ep1->v.i & ep2->v.i;
                        break;
                case en_or:
                        		ep->nodetype = maxinttype(ep1,ep2);
                        ep->v.i = ep1->v.i | ep2->v.i;
                        break;
                case en_xor:
                        		ep->nodetype = maxinttype(ep1,ep2);
                        ep->v.i = ep1->v.i ^ ep2->v.i;
                        break;
                }
}
/*
 * this stuff has been superceded by a lookup table
 * I'll fix it eventually
 */
int     pwrof2(LLONG_TYPE i)
/*
 *      return which power of two i is or -1.
 */
{       LLONG_TYPE     q;
        int p ;
        q = 2;
        p = 1;
        while( q > 0 )
                {
                if( q == i )
                        return p;
                q <<= 1;
                ++p;
                }
        return -1;
}

LLONG_TYPE     mod_mask(int i)
/*
 *      make a mod mask for a power of two.
 */
{       LLONG_TYPE     m;
        m = 0;
        while( i-- )
                m = (m << 1) | 1;
        return m;

}
void addaside (ENODE *node)
{
   *asidetail =  makenode(en_void,node,0) ;
   asidetail = &(*asidetail)->v.p[1] ;
}
void opt0(ENODE ** node)
/*
 *      opt0 - delete useless expressions and combine constants.
 *
 *      opt0 will delete expressions such as x + 0, x - 0, x * 0,
 *      x * 1, 0 / x, x / 1, x mod 0, etc from the tree pointed to
 *      by node and combine obvious constant operations. It cannot
 *      combine name and label constants but will combine icon type
 *      nodes.
 *
 * en_addstruc is not optimized to keep from optimizing struct members
 * into regs later...  just en: en_addstruc is now equiv to en_add
 * again.  I have fixed the optimize struct thing another way...
 * leaving en_addstruc in in case we need it later.
 */
{       ENODE    *ep;
        LLONG_TYPE             val;
        int sc ;
				int mode;
				double dval;
				int negtype = en_uminus;
				
        ep = *node;
				
        if( ep == 0 )
                return;
				switch (ep->nodetype) {
					case en_asumul:
					case en_asmul:
					case en_asudiv:
					case en_asdiv:
						negtype = en_asuminus;
				}
        switch( ep->nodetype ) {
                case en_bool_ref: case en_cbool:
                case en_b_ref:
                case en_w_ref:          /* optimize unary node */
                case en_ub_ref:
                case en_uw_ref:          /* optimize unary node */
                case en_l_ref:
								case en_ul_ref:
                        case en_ll_ref: case en_ull_ref:
								case en_floatref: case en_doubleref: case en_longdoubleref:
                        case en_fimaginaryref: case en_rimaginaryref: case en_lrimaginaryref:
                        case en_fcomplexref: case en_rcomplexref: case en_lrcomplexref:
                case en_cb: case en_cub:
								case en_cw: case en_cuw:
                        case en_cl: case en_cul: case en_cll: case en_cull:
								case en_cf: case en_cd: case en_cp: case en_bits: case en_cld:
				case en_ainc:
            case en_adec: case en_cl_reg:
                        opt0( &((*node)->v.p[0]));
                        return;
            case en_ascompl:
				case en_compl:
                        opt0( &(ep->v.p[0]));
                        if( isintconst(ep->v.p[0]->nodetype))
                                {
                                ep->nodetype = ep->v.p[0]->nodetype;
                                ep->v.i = ~ep->v.p[0]->v.i;
                                }
												return;

								case en_uminus:
								case en_asuminus:
                        opt0( &(ep->v.p[0]));
                        if( isintconst(ep->v.p[0]->nodetype))
                                {
                                ep->nodetype = ep->v.p[0]->nodetype;
                                ep->v.i = -ep->v.p[0]->v.i;
                                }
                        else if( ep->v.p[0]->nodetype == en_rcon || ep->v.p[0]->nodetype == en_fcon || ep->v.p[0]->nodetype == en_lrcon)
                                {
                                ep->nodetype = ep->v.p[0]->nodetype;
                                ep->v.f = -ep->v.p[0]->v.f;
                                }
                        return;
                case en_add: case en_addstruc:
                case en_sub:
								case en_asadd:
								case en_assub:
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1: case 2: case 3: case 4:
														dooper(node,mode);
														break;
													case 5:
														if (ep->v.p[0]->v.i == 0) {
															if (ep->v.p[0]->nodetype != en_autocon)
																if (ep->nodetype == en_sub) 
																	*node = makenode(en_uminus,ep->v.p[1],0);
																else *node = ep->v.p[1];
														}
														else dooper(node,mode);
														break;
													case 6:
														if (ep->v.p[0]->v.f == 0) {
															if (ep->nodetype == en_sub) {
																*node = ep->v.p[1];
																ep->v.p[1]->v.f = - ep->v.p[1]->v.f;

															}
															else *node = ep->v.p[1];
														}
														else dooper(node,mode);
														break;
												  case 7:
														if (ep->v.p[1]->v.i == 0) {
															if (ep->v.p[0]->nodetype != en_autocon)
																*node = ep->v.p[0];
														}
														else dooper(node,mode);
														break;
													case 8:
														if (ep->v.p[1]->v.f == 0) {
															*node = ep->v.p[0];
														}
														else dooper(node,mode);
														break;
												}
                        return;
                case en_mul:
								case en_umul:
								case en_pmul:
								case en_asmul: case en_asumul:
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch(mode) {
													case 1: case 2: case 3: case 4:
														dooper(node,mode);
														break;
													case 5:
														if (!floatrecurse(ep->v.p[1])) {
                                sc = pwrof2(ep->v.p[0]->v.i);
                                if( sc != -1 )
                                        {
																				ENODE *temp = ep->v.p[0];
																				ep->v.p[0 ] = ep->v.p[1];
																				ep->v.p[1] = temp;
                                        ep->v.p[1]->v.i = sc;
																				switch(ep->nodetype) {
																					case en_mul:
																						ep->nodetype = en_alsh;
																						break;
																					case en_asmul:
																						ep->nodetype = en_asalsh;
																						break;
																					case en_umul:
																					case en_pmul:
																						ep->nodetype = en_lsh;
																						break;
																					case en_asumul:
																						ep->nodetype = en_aslsh;
																						break;
																				}
																				break;
                                        }
                            }
														val = ep->v.p[0]->v.i;
                                          if (val == 0) {
                                             addaside(ep->v.p[1]) ;
															*node = ep->v.p[0];
                                          } else if (val == 1)
															*node = ep->v.p[1];
														else if (val == -1)
															*node = makenode(negtype,(char *)ep->v.p[1],0);
														else dooper(node,mode);
														break;
													case 6:
														dval = ep->v.p[0]->v.f;
                                          if (dval == 0) {
                                             addaside(ep->v.p[1]) ;
															*node = ep->v.p[0];
                                          } else if (dval == 1)
															*node = ep->v.p[1];
														else if (dval == -1)
															*node = makenode(negtype,(char *)ep->v.p[1],0);
														else dooper(node,mode);
														break;
													case 7:
														if (!floatrecurse(ep->v.p[0])) {
                                sc = pwrof2(ep->v.p[1]->v.i);
                                if( sc != -1 )
                                        {
                                        ep->v.p[1]->v.i = sc;
																				switch(ep->nodetype) {
																					case en_mul:
																						ep->nodetype = en_alsh;
																						break;
																					case en_asmul:
																						ep->nodetype = en_asalsh;
																						break;
																					case en_umul:
																					case en_pmul:
																						ep->nodetype = en_lsh;
																						break;
																					case en_asumul:
																						ep->nodetype = en_aslsh;
																						break;
																				}
																				break;
                                        }
                            }
														val = ep->v.p[1]->v.i;
                                          if (val == 0) {
                                             addaside(ep->v.p[0]) ;
															*node = ep->v.p[1];
                                          } else if (val == 1)
															*node = ep->v.p[0];
														else if (val == -1)
															*node = makenode(negtype,(char *)ep->v.p[0],0);
														else dooper(node,mode);
														break;
													case 8:
														dval = ep->v.p[1]->v.f;
                                          if (dval == 0) {
															*node = ep->v.p[1];
                                             addaside(ep->v.p[0]) ;
                                          }else if (dval == 1)
															*node = ep->v.p[0];
														else if (dval == -1)
															*node = makenode(negtype,(char *)ep->v.p[0],0);
														else dooper(node,mode);
														break;
												}
                        break;
								case en_pdiv:
                case en_div:
								case en_udiv:
								case en_asdiv:
								case en_asudiv:
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch(mode) {
													case 1:
													case 2:
													case 3:
													case 4: 
														dooper(node,mode);
														break;
													case 5:
                                          if (ep->v.p[0]->v.i == 0) {
                                             addaside(ep->v.p[1]) ;
															*node = ep->v.p[0];
                                          } else
															dooper(node,mode);
														break;
													case 6:
                                          if (ep->v.p[0]->v.f == 0) {
                                             addaside(ep->v.p[1]) ;
															*node = ep->v.p[0];
                                          } else
															dooper(node,mode);
														break;
													case 7:
														if (!floatrecurse(ep->v.p[0])) {
                                sc = pwrof2(ep->v.p[1]->v.i);
                                if( sc != -1 )
                                        {
                                        ep->v.p[1]->v.i = sc;
																				switch(ep->nodetype) {
																					case en_div:
																					case en_pdiv:
																						ep->nodetype = en_arshd;
																						break;
																					case en_asdiv:
																						ep->nodetype = en_asarshd;
																						break;
																					case en_udiv:
																						ep->nodetype = en_rsh;
																						break;
																					case en_asudiv:
																						ep->nodetype = en_asrsh;
																						break;
																				}
																				break;
                                        }
                            }
														val = ep->v.p[1]->v.i;
														if (val == 1)
															*node = ep->v.p[0];
														else if (val == -1)
															*node = makenode(negtype,(char *)ep->v.p[0],0);
														else dooper(node,mode);
														break;
													case 8:
														dval = ep->v.p[1]->v.f;
														if (dval == 1)
															*node = ep->v.p[0];
														else if (dval == -1)
															*node = makenode(negtype,(char *)ep->v.p[0],0);
														else dooper(node,mode);
														break;
												}
                        break;
                case en_mod:
								case en_umod:
								case en_asmod: case en_asumod:
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch(mode) {
													case 7:
														if (!floatrecurse(ep->v.p[0])) {
                                sc = pwrof2(ep->v.p[1]->v.i);
                                if( sc != -1 )
                                        {
                                        ep->v.p[1]->v.i = mod_mask(sc);
																				if (ep->nodetype == en_asmod || ep->nodetype == en_asumod)
                                        	ep->nodetype = en_asand;
																				else
                                        	ep->nodetype = en_and;
																				break;
                                        }
                                }
													case 1:
													case 2:
													case 3:
													case 4: 
													case 5: case 6: case 8:
														dooper(node,mode);
												}
                        break;
								case en_and:
								case en_asand:
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
														dooper(node,mode);
														break;
													case 5:
														if (ep->v.p[0]->v.i == 0) {
                                             addaside(ep->v.p[1]) ;
															*node = ep->v.p[0];
														}
														else dooper(node,mode);
														break;
												  case 7:
														if (ep->v.p[1]->v.i == 0) {
                                             addaside(ep->v.p[0]) ;
															*node = ep->v.p[1];
														}
														else dooper(node,mode);
														break;
												}
                        break;
								case en_or:
                case en_xor:    
								case en_asor:
                case en_asxor:    
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
														dooper(node,mode);
														break;
													case 5:
														if (ep->v.p[0]->v.i == 0) {
															*node = ep->v.p[1];
														}
														else dooper(node,mode);
														break;
												  case 7:
														if (ep->v.p[1]->v.i == 0) {
															*node = ep->v.p[0];
														}
														else dooper(node,mode);
														break;
												}
                        break;
								case en_asrsh:
								case en_rsh:
                case en_lsh:    case en_arsh: case en_alsh: case en_arshd:
                case en_aslsh:    case en_asarsh: case en_asalsh: case en_asarshd:
                        opt0(&(ep->v.p[0]));
                        if (isintconst(ep->v.p[0]->nodetype) && ep->v.p[1]->nodetype == en_cl_reg)
                           if (isintconst(ep->v.p[1]->v.p[0]->nodetype))
                              ep->v.p[1] = ep->v.p[1]->v.p[0] ;
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
														dooper(node,mode);
														break;
													case 5:
														if (ep->v.p[0]->v.i == 0) {
                                             addaside(ep->v.p[1] );
															*node = ep->v.p[0];
														}
														else dooper(node,mode);
														break;
												  case 7:
														if (ep->v.p[1]->v.i == 0) {
															*node = ep->v.p[0];
														}
														else dooper(node,mode);
														break;
												}
                        break;
                case en_land:
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
                                          *node = makeintnode(en_icon,(ep->v.p[0]->v.i && ep->v.p[1]->v.i));
														break;
													case 5:
														if (ep->v.p[0]->v.i == 0) {
                                             addaside(ep->v.p[1] );
                                             *node = makeintnode(en_icon,0);
														}
														break;
												  case 7:
														if (ep->v.p[1]->v.i == 0) {
                                             addaside(ep->v.p[0]) ;
                                             *node = makeintnode(en_icon,0);
														}
														break;
												}
                        break;
								case en_lor:
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
                                          *node = makeintnode(en_icon,(ep->v.p[0]->v.i || ep->v.p[1]->v.i));
														break;
													case 5:
														if (ep->v.p[0]->v.i == 0) {
                                             addaside(ep->v.p[1]) ;
                                             *node = makeintnode(en_icon, (ep->v.p[1]->v.i != 0));
														}
														break;
												  case 7:
														if (ep->v.p[1]->v.i == 0) {
                                             addaside(ep->v.p[0]) ;
                                             *node = makeintnode(en_icon,(ep->v.p[1]->v.i != 0));
														}
														break;
												}
                        break;
								case en_not:
                        opt0(&(ep->v.p[0]));
												if (isintconst(ep->v.p[0]->nodetype)) {
                                       *node = makeintnode(en_icon,(!ep->v.p[0]->v.i));
												}
												break;
								case en_eq:		
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
                                          *node = makeintnode(en_icon,(ep->v.p[0]->v.i == ep->v.p[1]->v.i));
														break;
												}
                        break;
								case en_ne:
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
                                          *node = makeintnode(en_icon,(ep->v.p[0]->v.i != ep->v.p[1]->v.i));
														break;
												}
                        break;
								case en_lt:		
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
                                          *node = makeintnode(en_icon,(ep->v.p[0]->v.i < ep->v.p[1]->v.i));
														break;
												}
                        break;
								case en_le:
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
                                          *node = makeintnode(en_icon,(ep->v.p[0]->v.i <= ep->v.p[1]->v.i));
														break;
												}
                        break;
								case en_ugt:	
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
                                          *node = makeintnode(en_icon,((unsigned)ep->v.p[0]->v.i > (unsigned)ep->v.p[1]->v.i));
														break;
												}
                        break;
								case en_uge: 
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
                                          *node = makeintnode(en_icon,((unsigned)ep->v.p[0]->v.i >= (unsigned)ep->v.p[1]->v.i));
														break;
												}
                        break;
								case en_ult: 
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
                                          *node = makeintnode(en_icon,((unsigned)ep->v.p[0]->v.i < (unsigned)ep->v.p[1]->v.i));
														break;
												}
                        break;
								case en_ule:
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
                                          *node = makeintnode(en_icon,((unsigned)ep->v.p[0]->v.i <= (unsigned)ep->v.p[1]->v.i));
														break;
												}
                        break;
								case en_gt:		
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
                                          *node = makeintnode(en_icon,(ep->v.p[0]->v.i > ep->v.p[1]->v.i));
														break;
												}
                        break;
								case en_ge:
                        opt0(&(ep->v.p[0]));
                        opt0(&(ep->v.p[1]));
												mode = getmode(ep->v.p[0],ep->v.p[1]);
												switch (mode) {
													case 1:
                                          *node = makeintnode(en_icon,(ep->v.p[0]->v.i >= ep->v.p[1]->v.i));
														break;
												}
                        break;


								case en_cond:
                case en_fcall:  case en_void: case en_intcall: case en_voidnz:
								case en_pfcall: case en_pfcallb:
								case en_sfcall: case en_sfcallb: case en_scallblock:
                case en_assign: case en_moveblock: case en_stackblock: case en_callblock:
								case en_fcallb: case en_refassign: case en_pcallblock:
                        case en_lassign:
								case en_thiscall:
								case en_repcons:
                        opt0(&(ep->v.p[1]));
								case en_trapcall:
                        opt0(&(ep->v.p[0]));
                        break;
                }
}
LLONG_TYPE     xfold(ENODE * node)
/*
 *      xfold will remove constant nodes and return the values to
 *      the calling routines.
 */
{       LLONG_TYPE     i;
        if( node == 0 )
                return 0;
        switch( node->nodetype )
                {
                case en_icon:
								case en_lcon:
								case en_iucon:
								case en_lucon:
								case en_ccon:
                        case en_llucon:
                        case en_llcon:
                        i = node->v.i;
                        node->v.i = 0;
                        return i;
                        case en_ascompl:
								case en_compl:
												fold_const(&node->v.p[0]);
																		
												if (isintconst (node->v.p[0]->nodetype)) {
                        	i = ~node->v.p[0]->v.i;
													node->nodetype = node->v.p[0]->nodetype;
                        	node->v.i = 0;
                        	return i;
												}
												return 0;
								case en_not:
												fold_const(&node->v.p[0]);
																		
												if (isintconst (node->v.p[0]->nodetype)) {
                        	i = !node->v.p[0]->v.i;
													node->nodetype = node->v.p[0]->nodetype;
                        	node->v.i = 0;
                        	return i;
												}
												return 0;
                case en_add:  case en_addstruc:
                        return xfold(node->v.p[0]) + xfold(node->v.p[1]);
                case en_sub:
                        return xfold(node->v.p[0]) - xfold(node->v.p[1]);
                case en_uminus:
								case en_asuminus:
                        return - xfold(node->v.p[0]);
								case en_or:
								case en_xor:
                case en_mul:
								case en_pmul:
								case en_umul:
                case en_lsh:
								case en_alsh:
								case en_asalsh: case en_asarsh: case en_arsh: case en_arshd: case en_asarshd:
                case en_rsh:    case en_div:  case en_pdiv:
                case en_mod:    case en_asadd:
                case en_assub:  case en_asmul:
                case en_asdiv:  case en_asmod:
                case en_land: case en_lor:
                case en_asand:	case en_and:
                case en_asor:   case en_void:  case en_asxor: case en_voidnz:
								case en_pfcall: case en_pfcallb:
								case en_sfcall: case en_sfcallb:
                case en_fcall:  case en_assign: case en_moveblock: case en_lassign:
								case en_stackblock: case en_intcall: case en_callblock: case en_fcallb:
								case en_asumul: case en_asudiv: case en_asumod: case en_refassign:
								case en_udiv: case en_pcallblock:
								case en_eq:		
								case en_ne:
								case en_lt:		
								case en_le:
								case en_ugt:	
								case en_uge: 
								case en_ult: 
								case en_ule:
								case en_gt:		
								case en_ge:
								case en_thiscall:
								case en_repcons:
                        fold_const(&node->v.p[1]);
                        case en_trapcall: case en_cl_reg:
                        fold_const(&node->v.p[0]);
                        return 0;
                case en_bool_ref: case en_cbool:
                case en_b_ref:  case en_w_ref:
                case en_ub_ref:  case en_uw_ref:
                case en_l_ref:  case en_ul_ref:
								case en_floatref: case en_doubleref: case en_longdoubleref:
                        case en_fimaginaryref: case en_rimaginaryref: case en_lrimaginaryref:
                        case en_fcomplexref: case en_rcomplexref: case en_lrcomplexref:
                        case en_ull_ref: case en_ll_ref:
                        case en_cull: case en_cll:
                        case en_cfi: case en_cri: case en_clri:
                        case en_cfc: case en_crc: case en_clrc:
								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_cp: case en_bits: case en_cld:
                        fold_const(&node->v.p[0]);
                        return 0;
                }
        return 0;
}

void fold_const(ENODE ** node)
/*
 *      reorganize an expression for optimal constant grouping.
 */
{       ENODE    *ep;
        LLONG_TYPE   i;
        ep = *node;
        if( ep == 0 )
                return;
				switch (ep->nodetype) {
						case en_add:  case en_addstruc:
								if (ep->v.p[0]->nodetype == en_cp && isintconst(ep->v.p[0]->v.p[0]->nodetype)) {
												ep->v.p[0]->v.p[0]->v.i += xfold(ep->v.p[1]);
												return;
												}
								else if (ep->v.p[1]->nodetype == en_cp && isintconst(ep->v.p[1]->v.p[0]->nodetype)) {
												ep->v.p[1]->v.p[0]->v.i += xfold(ep->v.p[1]);
												return;
												}
                else if( isintconst(ep->v.p[0]->nodetype))
                        {
                        ep->v.p[0]->v.i += xfold(ep->v.p[1]);
                        return;
                        }

								break;
						case en_sub:
								if (ep->v.p[0]->nodetype == en_cp && isintconst(ep->v.p[0]->v.p[0]->nodetype)) {
												ep->v.p[0]->v.p[0]->v.i -= xfold(ep->v.p[1]);
												return;
												}
								else if (ep->v.p[1]->nodetype == en_cp && isintconst(ep->v.p[1]->v.p[0]->nodetype)) {
												ep->v.p[1]->v.p[0]->v.i -= xfold(ep->v.p[1]);
												return;
												}
                else if( isintconst(ep->v.p[0]->nodetype))
                        {
                        ep->v.p[0]->v.i -= xfold(ep->v.p[1]);
                        return;
                        }
                else if( isintconst(ep->v.p[1]->nodetype))
                        {
                        ep->v.p[1]->v.i -= xfold(ep->v.p[0]);
                        return;
                        }
								break;
				}
        i = xfold(ep);
        if( i != 0 ) {
									ep = xalloc(sizeof(ENODE));
									ep->nodetype = en_icon;
									ep->v.i = i;
                	ep = makenode(en_add,ep,*node);
                *node = ep;
        }
}
void opt4(ENODE ** node)
/*
 *      apply all constant optimizations.
 */
{
      asidehead = 0 ;
      asidetail = &asidehead ;
		opt0(node);

        fold_const(node);
        opt0(node);
      if (asidehead) {
         *asidetail = *node ;
         *node = asidehead ;
      }
}
#ifdef ICODE
void constscan(SNODE *block)
/*
 *      constscan will gather all optimizable expressions into the expression
 *      list for a block of statements.
 */
{       while( block != 0 ) {
                switch( block->stype ) {
                        case st_return:
                        case st_expr:
                                opt4(&block->exp);
                                break;
                        case st_while:
                        case st_do:
                                opt4(&block->exp);
                                constscan(block->s1);
                                break;
                        case st_for:
                                opt4(&block->label);
                                opt4(&block->exp);
                                constscan(block->s1);
                                opt4(&block->s2);
                                break;
                        case st_if:
                                opt4(&block->exp);
                                constscan(block->s1);
                                constscan(block->s2);
                                break;
                        case st_switch:
                                opt4(&block->exp);
                                constscan(block->s1);
                                break;
                        case st_case:
                                constscan(block->s1);
                                break;
                        case st_block:
                                constscan(block->exp);
                                break;
                        }
                block = block->next;
                }
}
#endif