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

📄 cceval.c

📁 KCC , a good c compiler, write by Ken Harrenstien
💻 C
📖 第 1 页 / 共 4 页
字号:
	** can depend on the runtime environment (whether running
	** with extended addressing or not, using OWGBPs or not).  However,
	** compile-time comparisons can be done in a way that
	** duplicates the machine-independent code generated for
	** runtime comparisons.
	*/
	ul = eleft->Niconst;
	ul2 = e->Nright->Niconst;
	l  = (ul  << 6) | (ul  >> (TGSIZ_WORD-6));	/* Set up L and L2 */
	l2 = (ul2 << 6) | (ul2 >> (TGSIZ_WORD-6));	/* for comparisons */
	if (l  & 040) l  ^= 077;
	if (l2 & 040) l2 ^= 077;
	switch (e->Nop) {
	case Q_PLUS:			/* Give up if pointer arith */
	case Q_MINUS:
	default:
	    return e;

	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;
	}
	return setlog(e, log);

    default:
	int_warn("evalbinop: bad type %N", e);
	return e;
    }

    /* 
     * Now check hardware flags for numeric overflow
     */

#if SYS_CSI
    if (chkovf(unsign, subtra))
#else
    if (chkovf())
#endif
	error("constant expression overflow");

    return copyflag(eleft, e);
}

/* EVALUNOP - Evaluate operators of type TKTY_UNOP (unary operators),
**	where operand is a constant.
**	Unary ops:
**		(cast) ~ -
*/
static NODE *
evalunop(NODE *e)
{
    switch (e->Nop) {
    case N_CAST:
	return evalcast(e);	/* Handles all types */

    case Q_COMPL:
	switch (e->Ntype->Tspec) {
	case TS_INT:
	case TS_LONG:
		e->Nleft->Niconst = ~ e->Nleft->Niconst;
		break;
	case TS_UINT:
	case TS_ULONG:
		e->Nleft->Niconst = ~ (unsigned long)e->Nleft->Niconst;
		break;
	default:
	    int_warn("evalunop: bad ~ %N", e);
	}
	return copyflag(e->Nleft, e);

    case N_NEG:
	switch (e->Ntype->Tspec) {
	case TS_INT:
	case TS_LONG:
		e->Nleft->Niconst = -(e->Nleft->Niconst);
		break;
	case TS_UINT:
	case TS_ULONG:
		e->Nleft->Niconst = -(e->Nleft->Niconst); // FW KCC-NT
		break;
	case TS_FLOAT:
		e->Nleft->Nfconst = - (float) e->Nleft->Nfconst;
		break;
	case TS_DOUBLE:
	case TS_LNGDBL:
		e->Nleft->Nfconst = - (double) e->Nleft->Nfconst;
		break;
	default:
	    int_warn("evalunop: bad - %N", e);
	    return e;
	}
	return copyflag(e->Nleft, e);

    case N_PTR:
	break;			/* Don't try to hack pointer constants! */
    default:
	int_warn("evalunop: bad op %N", e);
    }
    return e;
}

/* EVALB1OP - Handle binary ops where one operand isn't a constant.
**	The operator will be one of * / % + - << >> & | ^.
**	Ops which are commutative & associative (+ * & | ^) can still be folded
**	with constants farther along.
**	The bitwise ops (&^|) are always OK for unsigned ops, and OK
**	for signed if twos-complement representation is used. (True for KCC)
**	It is only OK for signed/float + and * if there is no overflow.
**		This is hard to be sure of, though.
** WARNING: non-constant operands with side effects, like "volatile",
** require special handling!
** This is why anything that reduces to a constant value calls eseqdisc()
** to turn the expression into a comma-expr if the non-constant part has
** side effects.
**
** Special cases:
**		e = any valid type (pointer, float, integral)
**		fi = float or integral
**		i = integral type (signed or unsigned)
**		ui = unsigned integral
**		si = signed integral
** Zero		   One		~Zero (-1)		Power-of-2
** fi*0 => (fi,0)  fi*1 => fi	fi*(-1) => -fi		ui*log2(n) => ui<<n
** 0/fi => (fi,0)  fi/1 => fi	fi/(-1) => -fi		ui/log2(n) => ui>>n
** 0%i  => (i,0)   i%1  =>(i,0)	si%(-1) => (si,0)	ui%log2(n) => ui&(n-1)
** fi/0	fi Warning
** i%0	(i,0) Warning
** e+0  => e
** e-0  => e
** 0-fi  => -fi
** 0<<i => (i,0)
** 0>>i => (i,0)
** i<<0 => i
** i>>0 => i
** i&0  => (i,0)		i&-1	=> i
** i|0  => i			i|-1	=> (i,-1)
** i^0  => i			i^-1	=> ~i
*/	
#define ekeepright(e) eseqdisc((e)->Nleft, (e)->Nright)
#define ekeepleft(e)  eseqdisc((e)->Nright, (e)->Nleft)

static NODE *
evalb1op(NODE *e)
{
    NODE *eleft, *elast, *er, *elr;
    int assocf = 0;

    /* First see whether operator is commutative & associative,
    ** and if so we make sure the constant is on the right.  This both
    ** reduces complexity of the rest of the code and helps optimize the
    ** code generation as many PDP10 operators can take immediate
    ** constant values, which CCGEN2 tends to generate because it does the
    ** left-hand node first.
    */
    if (e->Nop == Q_PLUS || e->Nop == Q_MPLY
	  || e->Nop == Q_OR || e->Nop == Q_ANDT || e->Nop == Q_XORT) {
	assocf = 1;
	if (!eisconst(e->Nright)) {	/* Commute to get constant on right */
	    NODE *t;
	    t = e->Nleft;
	    e->Nleft = e->Nright;
	    e->Nright = t;
	}
    }

    /* At this point all we know is that the operator is a binary op and
    ** one of its operands is a constant.  If it is not an associative op, all
    ** we can do is check for special cases (see comments at start of page).
    */
#if NEW > 1
    if (tisinteg(e->Ntype)) {		/* Check integral types */
	long icon;			/* Get value of the constant */
	icon = (e->Nleft->Nop == N_ICONST
			? e->Nleft->Niconst : e->Nright->Niconst);
	if (icon >= -1 && icon <= 1)	/* Test for winning constant vals */
	switch (e->Nop) {
	case Q_MPLY:			/* Cuz commuted, const on right */
		if (icon == 0)
		    return ekeepright(e);	/* i*0 => (i,0) */
		if (icon == 1)
		    return e->Nleft;	/* i*1 => i */
		e->Nop = N_NEG;		/* i*(-1) => -i */
		return e;
	case Q_DIV:
		if (icon == 0) {
		    if (eisiconst(e->Nleft))
			return ekeepleft(e);	/* 0/i => (i,0)*/
		    advise("Division by zero ignored");
		    return e->Nleft;		/* i/0 => i */
		}
		if (eisiconst(e->Nright)) {
		    if (icon == 1)
			return e->Nleft;	/* i/1 => i */
		    if (tissigned(e->Ntype)) {
			e->Nop = N_NEG;		/* si/(-1) => -si */
			return e;
		    } else break;		/* Cannot do ui/(-1) */
		}
		break;
	case Q_MOD:
		if (icon == 0) {
		    if (eisiconst(e->Nright))
			advise("Division by zero");
		    return ekeepleft(e);	/* 0%i => (i,0)*/
		    				/* i%0 => (i,0) */
		}
		if (!eisiconst(e->Nright))	/* Ensure icon on right */
		    break;
		if (icon == 1 || tissigned(e->Ntype)) {
						/* i%1    => (i,0) */
		    e->Nright->Niconst = 0;	/* si%(-1) => (si,0) */
		    return ekeepright(e);
		}				/* Note ui%(-1) is variable! */
		break;
	case Q_PLUS:
		if (icon == 0)		/* Cuz commuted, const on rt */
		    return e->Nleft;	/* e+0 => e */
		break;
	case Q_MINUS:
		if (icon == 0 && e->Nleft->Nop==N_ICONST) {
		    e->Nop = N_NEG;	/* 0-e => -e */
		    e->Nleft = e->Nright;
		    return e;
		}
		break;
	case Q_LSHFT:			/* << same as >> here */
	case Q_RSHFT:			/* If either operand 0, */
		if (icon == 0)		/* always return left val! */
		    return ekeepleft(e);
		break;			/* Cuz 0<<i is (i,0), i<<0 is (0,i) */
	case Q_ANDT:
		if (icon == 0)		/* Cuz commuted, const on rt */
		    return ekeepright(e);	/* i&0 => (i,0) */
		if (icon == -1)
		    return e->Nleft;	/* i&(-1) => i */
		break;
	case Q_OR:
		if (icon == 0)		/* Cuz commuted, const on rt */
		    return e->Nleft;	/* i|0 => i */
		if (icon == -1)
		    return ekeepright(e);	/* i|(-1) => (i,-1)*/
		break;
	case Q_XORT:
		if (icon == 0)		/* Cuz commuted, const on rt */
		    return e->Nleft;	/* i^0 => i */
		if (icon == -1) {
		    e->Nop = Q_COMPL;	/* i^(-1) => ~i */
		    return e;
		}
		break;

	} else if (e->Nright->Nop == N_ICONST
		 && (icon&(icon-1))==0
		 && tisunsign(e->Ntype)) {
	    /* Last hope - if constant is right-hand and a power of 2,
	    ** (yes, that expression works as a test!) then
	    ** good optimizations are possible for unsigned *,/,%.
	    */
	    if (e->Nop == Q_MPLY) {	/* ui*log2(n) becomes ui<<n */
		e->Nop = Q_LSHFT;
		e->Nright->Niconst = binexp(icon);
		e->Nright->Ntype = inttype;	/* Be safe */
		return e;
	    } else if (e->Nop == Q_DIV) {	/* ui/log2(n) => ui>>n */
		e->Nop = Q_RSHFT;
		e->Nright->Niconst = binexp(icon);
		e->Nright->Ntype = inttype;
		return e;
	    } else if (e->Nop == Q_MOD) {	/* ui%log2(n) => ui&(n-1) */
		e->Nop = Q_ANDT;
		e->Nright->Niconst = icon-1;
		/* preserve prior type of constant */
		return e;
	    }
	}
    } else if (tisfloat(e->Ntype)) {	/* Check floating types */
	if (e->Ntype->Tspec != TS_LNGDBL)	/* Someday may be different */
	    switch (e->Nop) {
	    case Q_DIV:
		if (eisconst(e->Nleft) && e->Nleft->Nfconst == 0.0)
		    return ekeepleft(e);	/* 0/f => (f,0) */

		/* Drop thru to check for f/0, f/1 and f/(-1) */
	    case Q_MPLY:
		if (!eisconst(e->Nright))
		    break;
		if (e->Nright->Nfconst == 0.0) {
		    if (e->Nop == Q_DIV) {
			advise("Division by zero ignored");
			return e->Nleft;
		    }
		    return ekeepright(e);	/* f*0 => (f,0) */
		}
		if (e->Nright->Nfconst == 1.0)
		    return e->Nleft;		/* f*1 or f/1 => f */
		if (e->Nright->Nfconst == -1.0) {
		    e->Nop = N_NEG;		/* f*(-1) or f/(-1) => -f */
		    return e;
		}
		break;
	    case Q_PLUS:
		if (e->Nright->Nfconst == 0.0)
		    return e->Nleft;		/* f+0 => f */
		break;
	    case Q_MINUS:
		if (eisconst(e->Nleft) && e->Nleft->Nfconst == 0.0) {
		    e->Nop = N_NEG;
		    e->Nleft = e->Nright;
		    return e;			/* 0-f => -f */
		}
		break;
	    }
    } else {				/* Assume pointer, check + and - */
	if (eisiconst(e->Nright)	/* 0 will be on right if at all */
	  && e->Nright->Niconst == 0) {	/* (because 0+e already commuted) */
	    /* Won, e+0 or e-0 !!  But beware of funny array type conversion
	    ** sometimes applied to plus/minus pointer arithmetic; result type
	    ** may not be same as operand type.  Keep result type.
	    */
	    e->Nleft->Ntype = e->Ntype;	/* Propagate result type */
	    return e->Nleft;
	}
    }
#endif


    /* See if we can do anything associative.
    ** Move down the left-hand side of expression as long as the operator
    ** is identical to current one, and check for constant on right-hand side.
    ** If one is found, merge it in to existing constant and flush that
    ** operator instance.
    */
    if (!assocf) return e;		/* If op not assoc, that's all */
    elast = e;
    eleft = e->Nleft;
    for (; eleft->Nop == e->Nop; elast = eleft, eleft = eleft->Nleft)
	if (eisconst(eleft->Nright)) {
	    assocf = 0;			/* Zap back */
	    break;
	}
    if (assocf) return e;		/* No further ops */

    /* Win, eleft->Nright and e->Nright can be merged!
    ** do the op on them, replace e->Nright with the new result, and
    ** replace eleft's op with just eleft.  eleft's parent is elast.
    */
    er = e->Nright;
    elr = eleft->Nright;
    switch (e->Ntype->Tspec) {
    case TS_UINT:
    case TS_ULONG:
	switch (e->Nop) {
	case Q_PLUS:	er->Niconst += (unsigned long) elr->Niconst;	break;
	case Q_MPLY:	er->Niconst *= (unsigned long) elr->Niconst;	break;
	case Q_ANDT:	er->Niconst &= (unsigned long) elr->Niconst;	break;
	case Q_OR:	er->Niconst |= (unsigned long) elr->Niconst;	break;
	case Q_XORT:	er->Niconst ^= (unsigned long) elr->Niconst;	break;
	default:	return e;
	}
	break;
    case TS_INT:
    case TS_LONG:
	switch (e->Nop) {
	case Q_PLUS:	er->Niconst += (long) elr->Niconst;	break;
	case Q_MPLY:	er->Niconst *= (long) elr->Niconst;	break;
	case Q_ANDT:	er->Niconst &= (long) elr->Niconst;	break;
	case Q_OR:	er->Niconst |= (long) elr->Niconst;	break;
	case Q_XORT:	er->Niconst ^= (long) elr->Niconst;	break;
	default:	return e;
	}
	break;
    case TS_FLOAT:
	switch (e->Nop) {
	case Q_PLUS:	er->Nfconst += (float) elr->Nfconst;	break;
	case Q_MPLY:	er->Nfconst *= (float) elr->Nfconst;	break;
	default:	return e;
	}
	break;
    case TS_DOUBLE:
    case TS_LNGDBL:
	switch (e->Nop) {
	case Q_PLUS:	er->Nfconst += (double) elr->Nfconst;	break;
	case Q_MPLY:	er->Nfconst *= (double) elr->Nfconst;	break;
	default:	return e;
	}
	break;

    default:
	return e;		/* Can't do operation?? Barf and return. */
    }
    /* Now take out the eleft op */
    elast->Nleft = eleft->Nleft;
    return e;
}

/* EVALASOP - Handle assignment ops where right-hand operand is a constant.
**	The operator will be one of = *= /= %= += -= <<= >>= &= |= ^=.
**	Assignment ops always have side effects and so cannot be eliminated
**	completely -- normally.  But when the right-hand operand is a
**	constant (notably 0 or 1), some improvement is sometimes possible.
**
**	The special cases and cautions here are similar to those for
**	EVALB1OP above.  If the left-hand operand has type "volatile"
**	then improvement is never attempted because it might not result
**	in the behavior the user wanted.
**
** Special cases:
**		e = any valid type (pointer, float, integral)
**		fi = float or integral
**		i = integral type (signed or unsigned)
**		ui = unsigned integral
**		si = signed integral
Zero		One		~Zero (-1)	     Power-of-2
fi*=0 => fi=0	fi*=1	=> fi	fi*=(-1) => fi= -fi  ui*=log2(n) => ui<<=n
fi/=0	fi Warn	fi/=1	=> fi	fi/=(-1) => fi= -fi  ui/=log2(n) => ui>>=n
i%=0   i=0 Warn	i%=1	=> i=0	si%=(-1) => si=0     ui%=log2(n) => ui&=(n-1)
e+=0  => e	e+=1 => ++e	e+=-1 => --e
e-=0  => e	e-=1 => --e	e-=-1 => ++e
i<<=0 => i
i>>=0 => i
i&=0  => i=0			i&=-1	=> i
i|=0  => i			i|=-1	=> i= -1
i^=0  => i			i^=-1	=> i= ~i

*/

static NODE *
evalasop(NODE *e)
{

#if NEW > 2
    if (tisvolatile(e->Nleft->Ntype))	/* If volatile dest expr, */
	return e;			/* leave whole thing alone, sigh. */

    if (tisinteg(e->Ntype)) {		/* Check integral types */
	long icon;			/* Get value of the constant */
	if (e->Nright->Nop != N_ICONST)
	    return e;			/* May be an error */
	icon = e->Nright->Niconst;
	if (icon >= -1 && icon <= 1)	/* Test for winning constant vals */
	switch (e->Nop) {
	case Q_ASMPLY:			/* Check integral *= */
		if (icon == 0)
		    e->Nop = Q_ASGN;	/* i*=0 => i=0 */
		else if (icon == 1)
		    return e->Nleft;	/* i*=1 => i */
		else e->Nop = N_NEG;	/* i*=(-1) => -i */
		break;

⌨️ 快捷键说明

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