⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cceval.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 4 页
字号:
/*	CCEVAL.C - Evaluate and optimize expression parse trees
**
**	(c) Copyright Ken Harrenstien 1989
**		All changes after v.24, 11-Jan-1988 including CCFOLD merge
**		All CCFOLD changes after v.116, 29-Apr-1988
**	(c) Copyright Ken Harrenstien, SRI International 1985, 1986
**		All changes after v.7, 8-Aug-1985
**		All CCFOLD changes after v.17, 8-Aug-1985
**
** Original CCEVAL by David Eppstein / Stanford University / 28-Jul-84
** Original CCFOLD (C) 1981  K. Chen
*/

#define NEW 3	/* temporary to allow shutting advanced optimiz off if buggy */

#include "cc.h"

/* Exported functions */
NODE *evalexpr(NODE *e);
NODE *evaldiscard(NODE *n);
int sideffp(NODE *n);				/* Used here and CCGEN2 */
INT istrue(NODE *test, NODE *bindings);		/* CCGEN1's gfor() */

/* Imported functions */
extern NODE *ndef(int op, TYPE *t, int f, NODE *l, NODE *r);	/* CCSTMT */
extern NODE *convbinary(NODE *), *convnullcomb(NODE *);	/* CCTYPE */
extern INT binexp(unsigned INT);		/* CCOUT */
extern int hash(char *);		/* CCSYM */

/* Internal functions */
static NODE *copyflag(NODE *, NODE *), *setlog(NODE *, int);
static INT ecanon(NODE *);
static NODE *eseqdisc(NODE *, NODE *), *evalcast(NODE *);
static long value(NODE *, NODE *);
static NODE *lookup(SYMBOL *, NODE *);
static NODE *eval(NODE *), *evalunop(NODE *), *evalbinop(NODE *);
static NODE *evalb1op(NODE *), *evallog(NODE *), *evalfun(NODE *);
static NODE *evalasop(NODE *);
static int evalbool(NODE *);
static NODE *edisc(NODE *);	/* Auxiliary routine that does the work */
static long tolong(TYPE *, long);
static NODE *evalincdec(NODE *, int);
#if 0
static NODE *edisc();	/* Auxiliary routine that does the work */
static long tolong();
static NODE *evalincdec();
static NODE *copyflag(), *setlog(), *evalcast(), *eseqdisc();
static INT ecanon();
static long value();
static NODE *lookup();
static NODE *eval();
static NODE *evalunop(), *evalbinop(), *evalb1op(), *evallog(), *evalfun();
static NODE *evalasop();
static int evalbool();
#endif

/* Handy macro to see if an operand node is a hackable constant */
#define eisconst(e) \
	(e->Nop == N_ICONST || e->Nop == N_PCONST || e->Nop == N_FCONST)
#define eisiconst(e) (e->Nop == N_ICONST)

/* EVALEXPR(e) - Evaluates a parse-tree expression, folding constants and
**	reducing it as far as possible.  This includes discarding unused
**	values in sequential (comma) expressions.
*/
NODE *
evalexpr(e)
NODE *e;
{
    ecanon(e = eval(e));
    return e;
}

static NODE *
eval(NODE *e)
{
    if (e) switch (tok[e->Nop].tktype) {

    case TKTY_RWOP:			/* Built-in Reserved-Word ops */
	break;				/* Only Q_ASM for now */

    case TKTY_PRIMARY:
	switch (e->Nop) {
	    case N_FNCALL:
		return evalfun(e);
	    case Q_DOT:
	    case Q_MEMBER:
		e->Nleft = eval(e->Nleft);
	}
	break;				/* Return e */

    case TKTY_SEQ:			/* Just one op, N_EXPRLIST (,) */
	e->Nright = eval(e->Nright);	/* Fold current expression */
	if ((e->Nleft = evaldiscard(eval(e->Nleft))) == NULL) /* Fold previous */
	    return e->Nright;		/* May have flushed Nleft */
	break;				/* Return e */

    case TKTY_UNOP:
	e->Nleft = eval(e->Nleft);
	if (eisconst(e->Nleft))
	    return evalunop(e);		/* Do unary op on constant */
	break;

    /* Assignment ops have side effects, so can't eliminate them completely.
    ** However, it may be possible to optimize a non-simple assignment into
    ** a simple assignment, if the right operand is a specific constant
    ** (notably 0).
    ** Also, things like +=1 and -=1 should be turned into ++ and -- since the
    ** code generator has special optimizations for those.
    */
    case TKTY_ASOP:			/* Assignment ops */
	e->Nleft  = eval(e->Nleft);	/* Fold destination */
	e->Nright = eval(e->Nright);	/* Fold right operand, and */
	if (eisconst(e->Nright))	/* check further if it's a constant */
	    return evalasop(e);
	break;				/* return e */

    case TKTY_BINOP:			/* Ordinary binary ops */
	e->Nleft  = eval(e->Nleft);	/* First fold operands */
	e->Nright = eval(e->Nright);
	if (eisconst(e->Nleft)) {
	    if (eisconst(e->Nright))
		return evalbinop(e);	/* Do binary op on two constants */
	    /* Have one constant on left -- not on right.
	    ** ecanon() should have put the constant on right, but
	    ** constant evaluation here may have changed things.
	    */
	    return evalb1op(e);		/* Do binary op on one constant */
	} else if (eisconst(e->Nright))	/* Have one constant on right? */
	    return evalb1op(e);		/* Do binary op on one constant */
	break;			/* Neither operand is a constant. */


    case TKTY_BOOLOP:			/* Relational & logical binary ops */
	e->Nleft  = eval(e->Nleft);

	if (e->Nop == Q_LAND || e->Nop == Q_LOR)      /* Logical operator? */
	    if (eisconst(e->Nleft))
		return evallog(e);

	e->Nright = eval(e->Nright);

	/* Relational or equality op.  Both operands must be constants
	** if we are to evaluate further.
	** Actually, there are a few special cases which could still
	** be optimized if one operand is a constant.  For example,
	** unsigned comparison with 0.
	*/
	if (eisconst(e->Nleft) && eisconst(e->Nright))
	    return evalbinop(e);
	break;

    case TKTY_BOOLUN:			/* Just one op, Q_NOT (!) */
	e->Nleft = eval(e->Nleft);
	if (eisconst(e->Nleft))		/* Is operand a constant? */
	    return setlog(e, !evalbool(e->Nleft));	/* Yes, win */
	break;				/* Return e */

    case TKTY_TERNARY:			/* Just one op, Q_QUERY (?:) */
	e->Nleft = eval(e->Nleft);
	if (eisconst(e->Nleft))		/* Is operand a constant? */
	    return (evalbool(e->Nleft)	/* Yes, return proper branch */
			? eval(e->Nright->Nleft)
			: eval(e->Nright->Nright));

	/* Conditional isn't a constant, so fold both results */
	e->Nright->Nleft = eval(e->Nright->Nleft);
	e->Nright->Nright = eval(e->Nright->Nright);
	break;				/* Return e */

    default:
	int_warn("eval: bad expr op %N", e);
	break;				/* Return e anyway */
    }
    return e;		/* This returns NULL if e was null */
}

/* EVALFUN - Evaluate function call.
*/
static NODE *
evalfun(NODE *e)
{
    NODE *list;
    e->Nleft = eval(e->Nleft);		/* First do function addr */
    for (list = e->Nright; list; list = list->Nleft) {
	if (list->Nop == N_EXPRLIST)
	    list->Nright = eval(list->Nright);
	else {
	    int_warn("evalfun: bad arglist %N", list);
	    break;
	}
    }
    return e;
}

/* EVALBOOL - find boolean truth value of node.
**    Only scalar constants are acceptable.  (float, int, pointer, enum)
**	+1 - TRUE
**	0  - FALSE
**	-1 - not a scalar constant
*/
static int
evalbool(NODE *e)
{
    switch (e->Nop) {
	case N_PCONST:		/* Pointer constant same as int constant */
	case N_ICONST:	return (e->Niconst ? 1 : 0);
	case N_FCONST:	return (e->Nfconst ? 1 : 0);
    }
    return -1;
}

/* EVALLOG - Evaluate a logical binary expression, either && or ||.
*/
static NODE *
evallog(NODE *e)
{
    NODE *etmp;
    int torf;

    if ((torf = evalbool(e->Nleft)) < 0)
	return e;			/* 1st operand not constant. */
    if (e->Nop == Q_LAND) {		/* For logical AND, */
	if (torf == 0)			/* if 1st operand false, */
	    return setlog(e, 0);	/* entire result is false. */
    } else {				/* For logical OR, */
	if (torf != 0)			/* if 1st operand true, */
	    return setlog(e, 1);	/* entire result is true. */
    }
    e->Nright = eval(e->Nright);	/* No joy; must now eval right */
    e->Nop = Q_NEQ;			/* Transform 1&&e or 0||e */
    e->Nleft->Ntype = inttype;		/* into (0 != e) */
    setlog(e->Nleft, 0);
    etmp = e->Nleft;			/* Swap to make (e != 0) */
    e->Nleft = e->Nright;
    e->Nright = etmp;
    e = convnullcomb(convbinary(e));
    e->Ntype = inttype;			/* Result of != is int */

    if (eisconst(e->Nleft))		/* If both sides now constant, */
	return evalbinop(e);		/* evaluate (e != 0) */
    return e;
}

/* EVALOP - evaluate operators of type TKTY_BINOP and TKTY_BOOLOP
**	with the exception of the logical operators (&& and ||).
**	All operands are known to be constants; "good" constants
**	are N_ICONST, N_PCONST, N_FCONST.
**
**	Relational/Equality ops:
**		== != < > <= >=
**	Arithmetic & Bitwise ops:
**		* / % + - << >> & ^ |
**
** Note that the comparison ops can have scalar arguments,
** as can the additive (+ -).
** Also, four ops (+ - << >>) can have operands which differ in type; this
** needs to be checked for.
*/

#if SYS_CSI			/* FEW 2A(40) 29-Jul-92 */
static int
chkovf(int unsign, int subtra)	/* check for arithmetic overflow */
#else
static int
chkovf(void)			/* check for arithmetic overflow */
#endif
{		
#ifdef __COMPILER_KCC__
    asm("\tSETO	1,\n");		/* PREPARE TO RETURN TRUE (OVERFLOW) */
#if SYS_CSI			/* FEW 2A(40) 29-Jul-92 */
    if (unsign)
	{
	asm ("\tJCRY0 .+2\n");	/* for unsigned overflow, check CARRY0 */

	if (subtra)
	    asm ("\tPOPJ 17,\n"); /* unsigned subtraction: true if clear */
	}
    else
	asm("\tJFCL   11, .+2\n");	/* JUMP IF OVERFLOW (AND CLEAR FLAG) */
#else
    asm("\tJFCL   11, .+2\n");	/* JUMP IF OVERFLOW (AND CLEAR FLAG) */
#endif
    asm("\tSETZ	1,\n");		/* IF NO OVERFLOW, RETURN FALSE      */
#else
    return 0;			/* assumes no overflow */
#endif
}

static NODE *
evalbinop(NODE *e)
{
    long	l, l2;
    unsigned long ul, ul2;
    float	f, f2;
    double	d, d2;
    int log = -1;
    NODE *eleft = e->Nleft;
#if SYS_CSI			/* FEW 2A(40) 29-Jul-92 */
    int unsign = 0, subtra = 0;
#endif

#if SYS_CSI			/* FEW 2A(40) 29-Jul-92 */
    chkovf(unsign, subtra);		/* clear machine overflow flags */
#else
    chkovf();				/* clear machine overflow flags */
#endif    

    switch (eleft->Ntype->Tspec) {
    case TS_INT:
    case TS_LONG:
	l = eleft->Niconst;
	l2 = e->Nright->Niconst;
	switch (e->Nop) {
	case Q_PLUS:	if (eleft->Ntype != e->Nright->Ntype)
			    return e;		/* Give up if int+ptr */
			l += l2;	break;
	case Q_MINUS:	l -= l2;	break;	/* l integ, so l2 is integ */
	case Q_MPLY:	l *= l2;	break;
	case Q_DIV:	if (l2 == 0)
			    error("divide by zero");
			else
			    l /= l2;
			break;
	case Q_MOD:	if (l2 == 0)
			    error("divide by zero");
			else
			    l %= l2;
			break;
	case Q_ANDT:	l &= l2;	break;
	case Q_OR:	l |= l2;	break;
	case Q_XORT:	l ^= l2;	break;
	case Q_LSHFT:	l <<= l2;	break;
	case Q_RSHFT:	l >>= l2;	break;

	case Q_EQUAL:	log = l == l2;	break;
	case Q_NEQ:	log = l != l2;	break;
	case Q_LESS:	log = l  < l2;	break;
	case Q_GREAT:	log = l  > l2;	break;
	case Q_LEQ:	log = l <= l2;	break;
	case Q_GEQ:	log = l >= l2;	break;
	default:
	    return e;
	}
	if (log >= 0) return setlog(e, log);
	eleft->Niconst = l;
	break;

    case TS_UINT:
    case TS_ULONG:
	ul = eleft->Niconst;
	ul2 = e->Nright->Niconst;
	switch (e->Nop) {
	case Q_PLUS:
#if SYS_CSI			/* FEW 2A(40) 29-Jul-92 */	    
			unsign = 1;
#endif	
			if (eleft->Ntype != e->Nright->Ntype)
			    return e;		/* Give up if int+ptr */
			ul += ul2;	break;
	case Q_MINUS:
#if SYS_CSI			/* FEW 2A(40) 29-Jul-92 */	    
			unsign = 1;
			subtra = 1;
#endif	
			ul -= ul2;	break;	/* ul integ, so ul2 is integ */
	case Q_MPLY:	ul *= ul2;	break;
	case Q_DIV:	if (ul2 == 0)
			    error("divide by zero");
			else
			    ul /= ul2;
			break;
	case Q_MOD:	if (ul2 == 0)
			    error("divide by zero");
			else
			    ul %= ul2;
			break;
	case Q_ANDT:	ul &= ul2;	break;
	case Q_OR:	ul |= ul2;	break;
	case Q_XORT:	ul ^= ul2;	break;
		/* For shifts, don't apply convs to right operand! */
	case Q_LSHFT:	ul <<= e->Nright->Niconst;	break;
	case Q_RSHFT:	ul >>= e->Nright->Niconst;	break;

	case Q_EQUAL:	log = ul == ul2;	break;
	case Q_NEQ:	log = ul != ul2;	break;
	case Q_LESS:	log = ul  < ul2;	break;
	case Q_GREAT:	log = ul  > ul2;	break;
	case Q_LEQ:	log = ul <= ul2;	break;
	case Q_GEQ:	log = ul >= ul2;	break;
	default:
	    return e;
	}
	if (log >= 0) return setlog(e, log);
	eleft->Niconst = ul;
	break;

    case TS_FLOAT:
	f = (float) eleft->Nfconst;			// FW KCC-NT
	f2 = (float) e->Nright->Nfconst;	// FW KCC-NT
	switch (e->Nop) {
	case Q_PLUS:	f += f2;	break;
	case Q_MINUS:	f -= f2;	break;
	case Q_MPLY:	f *= f2;	break;
	case Q_DIV:	if (f2 == 0)
			    error("divide by zero");
			else
			    f /= f2;
			break;

	case Q_EQUAL:	log = f == f2;	break;
	case Q_NEQ:	log = f != f2;	break;
	case Q_LESS:	log = f  < f2;	break;
	case Q_GREAT:	log = f  > f2;	break;
	case Q_LEQ:	log = f <= f2;	break;
	case Q_GEQ:	log = f >= f2;	break;
	default:
	    return e;
	}
	if (log >= 0) return setlog(e, log);
	eleft->Nfconst = f;
	break;

    case TS_DOUBLE:
    case TS_LNGDBL:
	d = eleft->Nfconst;
	d2 = e->Nright->Nfconst;
	switch (e->Nop) {
	case Q_PLUS:	d += d2;	break;
	case Q_MINUS:	d -= d2;	break;
	case Q_MPLY:	d *= d2;	break;
	case Q_DIV:	if (d2 == 0)
			    error("divide by zero");
			else
			    d /= d2;
			break;

	case Q_EQUAL:	log = d == d2;	break;
	case Q_NEQ:	log = d != d2;	break;
	case Q_LESS:	log = d  < d2;	break;
	case Q_GREAT:	log = d  > d2;	break;
	case Q_LEQ:	log = d <= d2;	break;
	case Q_GEQ:	log = d >= d2;	break;
	default:
	    return e;
	}
	if (log >= 0) return setlog(e, log);
	eleft->Nfconst = d;
	break;

    case TS_PTR:
	/* Operations on constant pointers are tricky because the result

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -