static char rcsid[] = "$Id: C-opt-expv.c,v 1.1 2002/02/06 16:05:00 msato Exp $";
/* 
 * $RWC_Release: Omni-1.6 $
 * $RWC_Copyright:
 *  Omni Compiler Software Version 1.5-1.6
 *  Copyright (C) 2002 PC Cluster Consortium
 *  
 *  This software is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License version
 *  2.1 published by the Free Software Foundation.
 *  
 *  Omni Compiler Software Version 1.0-1.4
 *  Copyright (C) 1999, 2000, 2001.
 *   Tsukuba Research Center, Real World Computing Partnership, Japan.
 *  
 *  Please check the Copyright and License information in the files named
 *  COPYRIGHT and LICENSE under the top  directory of the Omni Compiler
 *  Software release kit.
 *  
 *  
 *  $
 */
#include "C-front.h"

/*
 * optimize expression value
 */
static expv 	expv_reduce_conv_int _ANSI_ARGS_((TYPE_DESC tp, int i));
static expv 	expv_reduce_conv_float _ANSI_ARGS_((TYPE_DESC tp, double d));
static expv 	expv_inline_function _ANSI_ARGS_((expv left, expv right));

expv    expv_reduce(v)
    expv    v;
{
    enum expr_code code;
    TYPE_DESC tp;
    expv    left, right, rv;

    if (v == NULL) return (v);		/* error recovery */

    code = EXPV_CODE(v);
    tp = EXPV_TYPE(v);

    /* check for terminal */
    if (EXPR_CODE_IS_TERMINAL(code))
	return v;

    if(code == CONDITIONAL_EXPR){
	/* reduction on conditional expression */
	/* internal node */
	left = expv_reduce(EXPV_LEFT(v));
	if (EXPV_CODE(left) == INT_CONSTANT){
	    if(EXPV_INT_VALUE(left)) 
		return expv_reduce(EXPV_LEFT(EXPV_RIGHT(v)));
	    else
		return expv_reduce(EXPV_RIGHT(EXPV_RIGHT(v)));
	}
	return v; /* cannot reduce ! */
    }

    if (EXPR_CODE_IS_LIST(code)) {
	return v;
	/* fatal("expv_reduce: cannot reduce on LIST"); */
    }

    /* internal node */
    left = expv_reduce(EXPV_LEFT(v));
    right = EXPV_RIGHT(v);
    if (right != NULL)
	right = expv_reduce(right);

    /* constant folding */
    switch (code) {
#ifdef not
    case POINTER_REF:
	/* (POITNER_REF (LABEL_CONSTANT *) => IDENT */
	if (EXPV_CODE(left) == LABEL_CONSTANT)
	    return (expv_term(IDENT, tp, EXPV_NAME(left), EXPV_OFFSET(left)));
	break;
#endif
    case CAST_EXPR:
	if (EXPV_CODE(left) == INT_CONSTANT)
	    if ((rv = expv_reduce_conv_int(tp, EXPV_INT_VALUE(left))) != NULL)
		return (rv);
	if (EXPV_CODE(left) == FLOAT_CONSTANT)
	    if ((rv = expv_reduce_conv_float(tp, EXPV_FLOAT_VALUE(left))) != NULL)
		return (rv);

	if(EXPV_CODE(left) == MOE_CONSTANT){    /* get constant value */
	    ID id = lookup_ident(left);
	    if(id == NULL || ID_CLASS(id) != MOE) break; /* error ?*/
	    if ((rv = expv_reduce_conv_int(tp, EXPV_INT_VALUE(ID_BASE(id))))
		!= NULL)
		return (rv);
	}
	break;

     case MUL_EXPR:
	 if (EXPV_IS_ZERO(left) || EXPV_IS_ZERO(right))
	     return (expv_constant_0);	/* x*0 = 0 */
	 if (EXPV_IS_ZERO_FLOAT(left) || EXPV_IS_ZERO_FLOAT(right))
	     return (expv_float_0);	/* x*0 = 0 */
	 if (EXPV_IS_ONE(left) || EXPV_IS_ONE_FLOAT(left))
	     return (right);	/* x*1 = x */
	 if (EXPV_IS_ONE(right) || EXPV_IS_ONE_FLOAT(right))
	     return (left);	/* 1*x = x */

	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT) {
	     if (IS_UNSIGNED(EXPV_TYPE(left)))
		 return (expv_int_term(INT_CONSTANT, tp,
				       EXPV_UINT_VALUE(left) *
				       EXPV_UINT_VALUE(right)));
	     return (expv_int_term(INT_CONSTANT, EXPV_TYPE(v),
			      EXPV_INT_VALUE(left) * EXPV_INT_VALUE(right)));
	 }
	 if (EXPV_CODE(left) == FLOAT_CONSTANT &&
	     EXPV_CODE(right) == FLOAT_CONSTANT)
	     return (expv_float_term(EXPV_TYPE(v),
			  EXPV_FLOAT_VALUE(left) * EXPV_FLOAT_VALUE(right)));
	 break;

     case DIV_EXPR:
	 if (EXPV_IS_ZERO(left))
	     return (expv_constant_0);	/* 0/x = 0 */
	 if (EXPV_IS_ZERO_FLOAT(left))
	     return (expv_float_0);	/* 0/x = 0 */
	 if (EXPV_IS_ZERO(right) || EXPV_IS_ZERO_FLOAT(left)) {
	     error_at_node(v,"divide by zero");	/* x/0 = error */
	     return (v);
	 }
	 if (EXPV_IS_ONE(right) || EXPV_IS_ONE_FLOAT(right))
	     return (left);	/* x/1 = x */

	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT) {
	     if (IS_UNSIGNED(tp))
		 return (expv_int_term(INT_CONSTANT, EXPV_TYPE(v),
				       EXPV_UINT_VALUE(left) /
				       EXPV_UINT_VALUE(right)));
	     return (expv_int_term(INT_CONSTANT, EXPV_TYPE(v),
			      EXPV_INT_VALUE(left) / EXPV_INT_VALUE(right)));
	 }
	 if (EXPV_CODE(left) == FLOAT_CONSTANT &&
	     EXPV_CODE(right) == FLOAT_CONSTANT)
	     return (expv_float_term(EXPV_TYPE(v),
			  EXPV_FLOAT_VALUE(left) / EXPV_FLOAT_VALUE(right)));
	 break;

     case PLUS_EXPR:
	 if (EXPV_IS_ZERO(left) || EXPV_IS_ZERO_FLOAT(left))
	     return (right);	/* 0 + x = x */
	 if (EXPV_IS_ZERO(right) || EXPV_IS_ZERO_FLOAT(right))
	     return (left);	/* x + 0 = x */

	 if (EXPV_CODE(left) == INT_CONSTANT &&
		 EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, EXPV_TYPE(v),
			      EXPV_INT_VALUE(left) + EXPV_INT_VALUE(right)));
	 if (EXPV_CODE(left) == FLOAT_CONSTANT &&
		 EXPV_CODE(right) == FLOAT_CONSTANT)
	     return (expv_float_term(EXPV_TYPE(v),
			  EXPV_FLOAT_VALUE(left) + EXPV_FLOAT_VALUE(right)));

	 if (EXPV_CODE(left) == LONGLONG_CONSTANT &&
		 EXPV_CODE(right) == LONGLONG_CONSTANT)
	     return (expv_longlong_term(EXPV_TYPE(v),
					longlong_add(EXPV_LLINT_VALUE(left),
						  EXPV_LLINT_VALUE(right))));
#ifdef not
	 /* address calculation */
	 if (EXPV_CODE(left) == LABEL_CONSTANT &&
		 EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_term(LABEL_CONSTANT, tp, EXPV_NAME(left),
			       EXPV_OFFSET(left) + EXPV_INT_VALUE(right)));
	 if (EXPV_CODE(right) == LABEL_CONSTANT &&
		 EXPV_CODE(left) == INT_CONSTANT)
	     return (expv_term(LABEL_CONSTANT, tp, EXPV_NAME(right),
			       EXPV_OFFSET(right) + EXPV_INT_VALUE(left)));
#endif
	 /* (PLUS (PLUS x c1) c2) => (PLUS x c1+c2) */
	 if (EXPV_CODE(right) == INT_CONSTANT &&
		 EXPV_CODE(left) == PLUS_EXPR &&
		 EXPV_CODE(EXPV_RIGHT(left)) == INT_CONSTANT)
	     return (expv_cons(code, tp, EXPV_LEFT(left),
			       expv_int_term(INT_CONSTANT, EXPV_TYPE(right),
					     EXPV_INT_VALUE(right) +
					 EXPV_INT_VALUE(EXPV_RIGHT(left)))));
	 break;

     case MINUS_EXPR:
	 if (EXPV_IS_ZERO(left) || EXPV_IS_ZERO_FLOAT(left)) {
	     /* 0 - x -> unary minus */
	     code = UNARY_MINUS_EXPR;
	     left = right;
	     right = NULL;
	     break;
	 }
	 if (EXPV_IS_ZERO(right) || EXPV_IS_ZERO_FLOAT(right))
	     return (left);	/* x - 0 = x */

	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, EXPV_TYPE(v),
			      EXPV_INT_VALUE(left) - EXPV_INT_VALUE(right)));
	 if (EXPV_CODE(left) == FLOAT_CONSTANT &&
	     EXPV_CODE(right) == FLOAT_CONSTANT)
	     return (expv_float_term(EXPV_TYPE(v),
			  EXPV_FLOAT_VALUE(left) - EXPV_FLOAT_VALUE(right)));

	 if (EXPV_CODE(left) == LONGLONG_CONSTANT &&
	     EXPV_CODE(right) == LONGLONG_CONSTANT)
	     return (expv_longlong_term(EXPV_TYPE(v),
					longlong_sub(EXPV_LLINT_VALUE(left),
						  EXPV_LLINT_VALUE(right))));
 #ifdef not
	 /* address calcuation */
	 if (EXPV_CODE(left) == LABEL_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_term(LABEL_CONSTANT, tp, EXPV_NAME(left),
			       EXPV_OFFSET(left) - EXPV_INT_VALUE(right)));
 #endif
	 break;

     case UNARY_MINUS_EXPR:
	 if (EXPV_CODE(left) == INT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, EXPV_TYPE(v),
				   -EXPV_INT_VALUE(left)));
	 if (EXPV_CODE(left) == FLOAT_CONSTANT)
	     return (expv_float_term(EXPV_TYPE(v),
				     -EXPV_FLOAT_VALUE(left)));
	 if (EXPV_CODE(left) == LONGLONG_CONSTANT)
	     return (expv_longlong_term(EXPV_TYPE(v),
				   longlong_uminus(EXPV_LLINT_VALUE(left))));
	 break;

     case MOD_EXPR:
	 if (EXPV_IS_ONE(right))
	     return (expv_constant_0);	/* x%1 = 0 */
	 if (EXPV_IS_MINUS_ONE(right))
	     return (expv_constant_0);	/* x%-1 = 0 */
	 if (EXPV_IS_ZERO(right)) {	/* x%0 = error */
	     error_at_node(v, "mod by zero");
	     return (v);
	 }
	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT) {
	     if (IS_UNSIGNED(tp))
		 return (expv_int_term(INT_CONSTANT, tp,
			    EXPV_UINT_VALUE(left) % EXPV_UINT_VALUE(right)));
	     else
		 return (expv_int_term(INT_CONSTANT, tp,
			      EXPV_INT_VALUE(left) % EXPV_INT_VALUE(right)));
	 }
	 break;

     case LSHIFT_EXPR:
	 if (EXPV_IS_ZERO(right))/* x<<0 = x */
	     return (left);
	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			     EXPV_INT_VALUE(left) << EXPV_INT_VALUE(right)));
	 if (EXPV_CODE(left) == LONGLONG_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_longlong_term(EXPV_TYPE(v),
				      longlong_lshift(EXPV_LLINT_VALUE(left),
						    EXPV_INT_VALUE(right))));
	 break;

     case RSHIFT_EXPR:
	 if (EXPV_IS_ZERO(right))/* x>>0 = x */
	     return (left);

	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT) {
	     if (code == RSHIFT_EXPR)
		 return (expv_int_term(INT_CONSTANT, tp,
				       EXPV_UINT_VALUE(left) >>
				       EXPV_INT_VALUE(right)));
	     return (expv_int_term(INT_CONSTANT, tp,
			     EXPV_INT_VALUE(left) >> EXPV_INT_VALUE(right)));
	 }
	 if (EXPV_CODE(left) == LONGLONG_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_longlong_term(EXPV_TYPE(v),
				      longlong_rshift(EXPV_LLINT_VALUE(left),
						    EXPV_INT_VALUE(right))));
	 break;

     case BIT_AND_EXPR:
	 if (EXPV_IS_ZERO(right) || EXPV_IS_ZERO(left))	/* x & 0 = 0 */
	     return (expv_constant_0);
	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			      EXPV_INT_VALUE(left) & EXPV_INT_VALUE(right)));
	 if (EXPV_CODE(left) == LONGLONG_CONSTANT &&
	     EXPV_CODE(right) == LONGLONG_CONSTANT)
	     return (expv_longlong_term(EXPV_TYPE(v),
					longlong_and(EXPV_LLINT_VALUE(left),
						  EXPV_LLINT_VALUE(right))));
	 break;

     case BIT_OR_EXPR:
	 if (EXPV_IS_MINUS_ONE(right) || EXPV_IS_MINUS_ONE(left))
	     return (expv_constant_m1);	/* x * -1 = -1 */
	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			      EXPV_INT_VALUE(left) | EXPV_INT_VALUE(right)));
	 if (EXPV_CODE(left) == LONGLONG_CONSTANT &&
	     EXPV_CODE(right) == LONGLONG_CONSTANT)
	     return (expv_longlong_term(EXPV_TYPE(v),
					longlong_or(EXPV_LLINT_VALUE(left),
						  EXPV_LLINT_VALUE(right))));
	 break;

     case BIT_XOR_EXPR:
	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			      EXPV_INT_VALUE(left) ^ EXPV_INT_VALUE(right)));

	 if (EXPV_CODE(left) == LONGLONG_CONSTANT &&
	     EXPV_CODE(right) == LONGLONG_CONSTANT)
	     return (expv_longlong_term(EXPV_TYPE(v),
					longlong_xor(EXPV_LLINT_VALUE(left),
						  EXPV_LLINT_VALUE(right))));
	 break;

     case BIT_NOT_EXPR:
	 if (EXPV_CODE(left) == INT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp, ~EXPV_INT_VALUE(left)));
	 if (EXPV_CODE(left) == LONGLONG_CONSTANT)
	     return (expv_longlong_term(EXPV_TYPE(v),
				      longlong_not(EXPV_LLINT_VALUE(left))));
	 break;

     case LOG_EQ_EXPR:
	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			     EXPV_INT_VALUE(left) == EXPV_INT_VALUE(right)));
	 if (EXPV_CODE(left) == FLOAT_CONSTANT &&
	     EXPV_CODE(right) == FLOAT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			 EXPV_FLOAT_VALUE(left) == EXPV_FLOAT_VALUE(right)));
	 break;

     case LOG_NEQ_EXPR:
	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			     EXPV_INT_VALUE(left) != EXPV_INT_VALUE(right)));
	 if (EXPV_CODE(left) == FLOAT_CONSTANT &&
	     EXPV_CODE(right) == FLOAT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			 EXPV_FLOAT_VALUE(left) != EXPV_FLOAT_VALUE(right)));
	 break;

     case LOG_GE_EXPR:
	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT) {
	     return (expv_int_term(INT_CONSTANT, tp,
			     EXPV_INT_VALUE(left) >= EXPV_INT_VALUE(right)));
	 }
	 if (EXPV_CODE(left) == FLOAT_CONSTANT &&
	     EXPV_CODE(right) == FLOAT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			 EXPV_FLOAT_VALUE(left) >= EXPV_FLOAT_VALUE(right)));
	 break;

     case LOG_GT_EXPR:
	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT) {
	     return (expv_int_term(INT_CONSTANT, tp, 
			      EXPV_INT_VALUE(left) > EXPV_INT_VALUE(right)));
	 }
	 if (EXPV_CODE(left) == FLOAT_CONSTANT &&
	     EXPV_CODE(right) == FLOAT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			  EXPV_FLOAT_VALUE(left) > EXPV_FLOAT_VALUE(right)));
	 break;

     case LOG_LE_EXPR:
	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT) {
	     return (expv_int_term(INT_CONSTANT, tp,
			     EXPV_INT_VALUE(left) <= EXPV_INT_VALUE(right)));
	 }
	 if (EXPV_CODE(left) == FLOAT_CONSTANT &&
	     EXPV_CODE(right) == FLOAT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			 EXPV_FLOAT_VALUE(left) <= EXPV_FLOAT_VALUE(right)));
	 break;

     case LOG_LT_EXPR:
	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT) {
#ifdef xxx			/* problem??? */
	     return (expv_term(INT_CONSTANT, tp, NULL,
			       EXPV_UINT_VALUE(left) <
			       EXPV_UINT_VALUE(right)));
#endif
	     return (expv_int_term(INT_CONSTANT, tp,
			      EXPV_INT_VALUE(left) < EXPV_INT_VALUE(right)));
	 }
	 if (EXPV_CODE(left) == FLOAT_CONSTANT &&
	     EXPV_CODE(right) == FLOAT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			  EXPV_FLOAT_VALUE(left) < EXPV_FLOAT_VALUE(right)));
	 break;

     case LOG_AND_EXPR:
	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			     EXPV_INT_VALUE(left) && EXPV_INT_VALUE(right)));
	 break;

     case LOG_OR_EXPR:
	 if (EXPV_CODE(left) == INT_CONSTANT &&
	     EXPV_CODE(right) == INT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp,
			     EXPV_INT_VALUE(left) || EXPV_INT_VALUE(right)));
	 break;

     case LOG_NOT_EXPR:
	 if(EXPV_CODE(left) == INT_CONSTANT)
	     return (expv_int_term(INT_CONSTANT, tp, !EXPV_INT_VALUE(left)));
	 break;

     case FUNCTION_CALL:	/* call node, check in-line/built-in */
	 if((rv = expv_inline_function(left, right)) != NULL)
	     return (rv);

     default:
	 break;
     }

     if (code == EXPV_CODE(v) && tp == EXPV_TYPE(v) &&
		 left == EXPV_LEFT(v) && right == EXPV_RIGHT(v))
	 return (v);		/* no change */
     else			/* re-construct */
	 return (expv_cons(code, tp, left, right));
    }


static expv
expv_reduce_conv_int(tp, i)
     TYPE_DESC	tp;
     int	i;
{
     switch (TYPE_DESC_CODE(tp)) {
     case BASIC_TYPE_NODE:
	 switch (TYPE_BASIC_TYPE(tp)) {
	 case FLOAT:
	 case DOUBLE:
	     return (expv_float_term(tp, (double) i));

	 case CHAR:
	     i = (char) i;
	     break;

	 case UNSIGNED_CHAR:
	     i = (unsigned char) i;
	     break;

	 case SHORT:
	     i = (short) i;
	     break;

	 case UNSIGNED_SHORT:
	     i = (unsigned short) i;
	     break;

	 case INT:
	 case SIGNED:
	 case UNSIGNED:
	     break;

	 case LONG:
	     i = (long) i;
	     break;

	 case UNSIGNED_LONG:
	     i = (unsigned long) i;
	     break;

	 case LONGLONG:
	 case UNSIGNED_LONGLONG:
	     {
		 longlong ll;
		 if (i >= 0) {
		     ll.h = 0;
		     ll.l = i;
		 }
		 else {
		     ll.h = -1;
		     ll.l = i;
		 }
		 return (expv_longlong_term(longlong_type, ll));
	     }
	 /* NOT REACHED HARE*//* break; */

	 default:
	     fatal("expv_reduce_conv_int: bad arithmetic type");
	 }
	 break;

     case POINTER_DECL:
	 break;

     case ENUM_TYPE:
	 break;

     default:
	 fatal("expv_reduce_conv_int: bad type");
     }

     return (expv_int_term(INT_CONSTANT, tp, i));
}

static expv    expv_reduce_conv_float(tp, d)
     TYPE_DESC tp;
     double  d;
{
    int     i = (int)d;

    switch (TYPE_DESC_CODE(tp)) {
     case BASIC_TYPE_NODE:
	 switch (TYPE_BASIC_TYPE(tp)) {
	 case FLOAT:
	 case DOUBLE:
	     return (expv_float_term(tp, d));
	 case CHAR:
	     i = (char) d;
	     break;
	 case UNSIGNED_CHAR:
	     i = (unsigned char) d;
	     break;
	 case SHORT:
	     i = (short) d;
	     break;
	 case UNSIGNED_SHORT:
	     i = (unsigned short) d;
	     break;
	 case INT:
	     i = (int) d;
	     break;
	case SIGNED:
	    i = (signed) d;
	    break;
	case UNSIGNED:
	    i = (unsigned) d;
	    break;
	case LONG: {
	    long li = (long) d;
	    return expv_long_term(LONG_CONSTANT, tp, li);
	}
	case UNSIGNED_LONG: {
	    unsigned long li = (unsigned long) d;
	    return expv_long_term(LONG_CONSTANT, tp, (long)li);
	}
	case LONGLONG:
	case UNSIGNED_LONGLONG:
	    return (NULL);	/* not supported yet */

	default:
	    fatal("expv_reduce_conv_float: bad arithmetic type");
	}
	break;
    default:
	fatal("expv_reduce_conv_float: bad type");
    }
    return (expv_int_term(INT_CONSTANT, tp, i));
}

static expv    expv_inline_function(left, right)
    expv    left, right;
{
#ifdef not
    TYPE_DESC tp;
    char   *name;
    int     d, incr;

    if (EXPV_CODE(left) != LABEL_CONSTANT)
	return (NULL);
    name = EXPV_NAME(left);
    if (strcmp(name, "__builtin_va_arg_incr") == 0) {
	if (EXPV_CODE(right) == ARGLIST ||
	    !IS_POINTER(EXPV_TYPE(right))) {
	    error("bad usage, __builtin_va_arg_incr");
	    return (NULL);
	}
	tp = EXPV_TYPE(right);
	d = TYPE_SIZE(TYPE_REF(tp));
	incr = ROUND(d, PARAM_ALIGN);
	/*
	 * __builtin_va_arg_incr(ap)
	 * => (MINUS_EXPR (INCR ap ARG_SIZE) TYPE_SIZE)
	 */
	if (d == incr)
	    return (expv_cons(POST_INCR_EXPR, tp, right,
			      expv_term(INT_CONSTANT, int_type, NULL, d)));
	else
	    return (expv_cons(MINUS_EXPR, tp,
			      expv_cons(ASG_PLUS_EXPR, tp, right,
				     expv_term(INT_CONSTANT, int_type, NULL,
					       incr)),
			      expv_term(INT_CONSTANT, int_type, NULL, d)));
    }
    else
#endif
	return (NULL);
}

/*
 * longlong routine
 */
longlong longlong_add(ll1, ll2)
    longlong ll1, ll2;
{
    union {
	longlong ll;
	unsigned short int s[4];
    }       x, y;
    unsigned long t;
    x.ll = ll1;
    y.ll = ll2;

    /* for big, endian */
    t = x.s[3] + y.s[3];
    x.s[3] = t;
    t = t >> 16;
    t = t + x.s[2] + y.s[2];
    x.s[2] = t;
    t = t >> 16;
    t = t + x.s[1] + y.s[1];
    x.s[1] = t;
    t = t >> 16;
    x.s[0] = t + x.s[0] + y.s[0];
    return (x.ll);
}

longlong longlong_uminus(ll)
    longlong ll;
{
    longlong t;
    ll.h = ~ll.h;
    ll.l = ~ll.l;
    t.h = 0;
    t.l = 1;
    return (longlong_add(ll, t));
}

longlong longlong_sub(ll1, ll2)
    longlong ll1, ll2;
{
    return (longlong_add(ll1, longlong_uminus(ll2)));
}

/* i must be positive */
longlong longlong_lshift(ll, i)
     longlong ll;
     int i;
{
    long    t;
    t = ll.l >> (32 - i);
    ll.l = ll.l << i;
    ll.h = ((ll.h << i) | t);
    return (ll);
}

longlong longlong_rshift(ll, i)
     longlong ll;
     int i;
{
    long    t;
    t = ll.h << (32 - i);
    ll.h = ll.h >> i;
    ll.l = ((ll.l >> i) | t);
    return (ll);
}

longlong longlong_and(ll1, ll2)
    longlong ll1, ll2;
{
    ll1.h &= ll2.h;
    ll1.l &= ll2.l;
    return (ll1);
}

longlong longlong_or(ll1, ll2)
    longlong ll1, ll2;
{
    ll1.h |= ll2.h;
    ll1.l |= ll2.l;
    return (ll1);
}

longlong longlong_xor(ll1, ll2)
    longlong ll1, ll2;
{
    ll1.h ^= ll2.h;
    ll1.l ^= ll2.l;
    return (ll1);
}

longlong longlong_not(ll)
    longlong ll;
{
    ll.h = ~ll.h;
    ll.l = ~ll.l;
    return (ll);
}
