File:  [MW Coherent from dump] / coherent / b / bin / c / n0 / fold.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Wed May 29 04:56:37 2019 UTC (7 years, 2 months ago) by root
Branches: MarkWilliams, MAIN
CVS tags: relic, HEAD
coherent

/*
 * n0/fold.c
 * Constant expression folder for the C compiler parser.
 * More of this is done in the code generator.
 * This one exists only to allow constant expressions in case labels,
 * in array bounds, and in initializers.
 */

#ifdef   vax
#include "INC$LIB:cc0.h"
#else
#include "cc0.h"
#endif

extern	lval_t	grablval();

#if	FOLD_DOUBLES
/*
 * The double folding code below assumes that the compiler host and target fp
 * representations are identical,
 * an assumption the compiler source carefully avoids making everywhere else.
 * If host fp == target fp,
 * ordinary C fp operations (+, -, *, / etc.) can be used in folding.
 * If host fp != target fp, folding requires format translation or emulation.
 * A compiler produced with this option uses fp,
 * so in particular the verison of fp it uses must run on all target systems;
 * e.g., if you compile the compiler -VNDP then the target will need
 * either an NDP or NDP emulation.
 */
extern	TREE	*foldd();
extern	double	grabdval();
#endif

/*
 * Try to fold constants.
 * The given op must be appropriate for folding,
 * the left subtree must be a constant (ICON/LCON/ZCON/DCON), and
 * the right subtree (if any) must be a constant (ICON/LCON/ZCON/DCON)
 * for folding to work.
 * Return pointer to a constant tree node,
 * or NULL if folding is impossible.
 * This code is very casual about lval_t/ulval_t bit equivalence.
 * Folds double constants if FOLD_DOUBLES.
 */
TREE *
fold0(op, lp, rp) int op; TREE *lp, *rp;
{
	register TREE *tp;
	register lval_t lv, rv;
	int bool;
	register int lt, rt, gt, uflag, zflag, lflag;

	/* Check op dope table to make sure op has a chance of folding. */
	if ((opdope[op - MIOBASE] & FOLD) == 0)
		return NULL;

	/* Check for constant left subtree. */
	if (!isconst(lp))
		return NULL;
	lt = lp->t_type;

	/* Handle ?: without further ado. */
	if (op == QUEST) {
		if (rp->t_op != COLON)
			return NULL;		/* parsing must be fubar */
		return (grablval(lp, 0)) ? rp->t_lp : rp->t_rp;
	}

	/* Handle ',' with constant on lhs without further ado. */
	if (op == COMMA)
		return rp;

	if (rp != NULL) {
		/* Check for constant right subtree. */
		if (!isconst(rp))
			return NULL;
		rt = rp->t_type;
	} else
		rt = lt;			/* Unary ops: no right subtree */

	/*
	 * Find the goal type in the conversion dope table.
	 * Watch out for shifts, right type implicitly T_INT.
	 */
	if (op == SHL || op == SHR)
		rt = T_INT;
	gt = cvdope[13 * (lt - T_CHAR) + (rt - T_CHAR)] & GOAL;

	/* Set unsigned, long, ZCON flags based on goal type. */
	uflag = (gt == T_UINT || gt == T_ULONG);
	lflag = (gt == T_LONG || gt == T_ULONG);
	zflag = (lp->t_op == ZCON || (rp != NULL && rp->t_op == ZCON));

#if	FOLD_DOUBLES
	/* Fold as doubles if goal type is double. */
	if (gt == T_DOUBLE) {
		if (opdope[op - MIOBASE] & NFLT)
			return NULL;		/* op is illegal in any case */
		return foldd(op, lp, rp);
	}
#endif

	/* Grab the left and right values as [u]lval_t. */
	lv = grablval(lp, uflag);
	if (rp != NULL)
		rv = grablval(rp, uflag);

	/* Perform the folding, computing result in lv or in bool (0 or 1). */
	bool = -1;
	switch (op) {

	case COM:	lv = ~lv;		break;
	case NEG:	lv = -lv;		break;
	case ADD:	lv += rv;		break;
	case SUB:	lv -= rv;		break;
	case MUL:	lv *= rv;		break;
	case AND:	lv &= rv;		break;
	case OR:	lv |= rv;		break;
	case XOR:	lv ^= rv;		break;
	case SHL:	lv <<= rv;		break;

	/* Ops /, % and >> are different for signed and unsigned cases. */
	case DIV:
		if (rv == 0) {
			cwarn("divide by zero");
			return NULL;
		}
		if (uflag)
			lv = ((ulval_t)lv / (ulval_t)rv);
		else
			lv /= rv;
		break;

	case REM:
		if (rv == 0) {
			cwarn("zero modulus");
			return NULL;
		}
		if (uflag)
			lv = ((ulval_t)lv % (ulval_t)rv);
		else
			lv %= rv;
		break;

	case SHR:
		if (uflag)
			lv = ((ulval_t)lv >> (ulval_t)rv);
		else
			lv >>= rv;
		break;

	/* Relations and conditionals return T_INT result in bool. */
	case NOT:	bool = !lv;		break;
	case EQ:	bool = lv == rv;	break;
	case NE:	bool = lv != rv;	break;
	case ANDAND:	bool = (lv && rv);	break;
	case OROR:	bool = (lv || rv);	break;
	/* Nonequality relations are different for signed and unsigned cases. */
	case LT:
		bool = (uflag) ? ((ulval_t)lv <  (ulval_t)rv) : (lv <  rv);
		break;
	case LE:
		bool = (uflag) ? ((ulval_t)lv <= (ulval_t)rv) : (lv <= rv);
		break;
	case GT:
		bool = (uflag) ? ((ulval_t)lv >  (ulval_t)rv) : (lv >  rv);
		break;
	case GE:
		bool = (uflag) ? ((ulval_t)lv >= (ulval_t)rv) : (lv >= rv);
		break;

	default:		/* shouldn't happen if opdope is right */
		return NULL;
	}

	/* Allocate a TREE for the result, store result, return it. */
	tp = talloc();
	if (bool != -1) {			/* boolean result */
		tp->t_op   = ICON;
		tp->t_type = T_INT;
		tp->t_ival = bool;
	} else if (lflag) {			/* [u]long result */
		tp->t_op   = LCON;
		tp->t_type = (uflag) ? T_ULONG : T_LONG;
		tp->t_lval = lv;
	} else if (zflag) {			/* size_t result */
		tp->t_op   = ZCON;
		tp->t_type = T_UINT;
		tp->t_zval = lv;
	} else {				/* [u]int result */
		tp->t_op   = ICON;
		tp->t_type = (uflag) ? T_UINT : T_INT;
		tp->t_ival = lv;
	}
	return tp;
}

/*
 * Return true if tp represents a constant (ICON, LCON, ZCON, DCON).
 */
int
isconst(tp) register TREE *tp;
{
	register int op;

	return (tp->t_dp == NULL
	     && ((op = tp->t_op) == ICON
		 || op == LCON
		 || op == ZCON
#if	FOLD_DOUBLES
		 || op == DCON
#endif
		));
}

/*
 * Grab the value of a constant as an lval_t (or ulval_t, really).
 * Zero extend if the goal type is unsigned.
 */
lval_t
grablval(tp, uflag) register TREE *tp; int uflag;
{
	switch (tp->t_op) {
	case ICON:
		return (uflag) ? (ulval_t)(uival_t)tp->t_ival : tp->t_ival;
	case ZCON:
		return (ulval_t)tp->t_zval;
	case LCON:
		return tp->t_lval;
#if	FOLD_DOUBLES
	case DCON:
		return dval_to_d(tp);
#endif
	}
	cbotch("grablval");
}

#if	FOLD_DOUBLES

/*
 * Fold double constants.
 */
TREE *
foldd(op, lp, rp) int op; TREE *lp, *rp;
{
	register TREE *tp;
	int bool;
	double lv, rv;

	lv = grabdval(lp);
	if (rp != NULL)
		rv = grabdval(rp);
 

	/* Perform the folding, leaving result in lv or in bool (0 or 1). */
	bool = -1;
	switch(op) {

	case NEG:	lv = -lv;		break;
	case ADD:	lv += rv;		break;
	case SUB:	lv -= rv;		break;
	case MUL:	lv *= rv;		break;
	case DIV:	lv /= rv;		break;

	/* Relations and conditionals return T_INT result in bool. */
	case NOT:	bool = !lv;		break;
	case EQ:	bool = lv == rv;	break;
	case NE:	bool = lv != rv;	break;
	case LT:	bool = lv <  rv;	break;
	case LE:	bool = lv <= rv;	break;
	case GT:	bool = lv >  rv;	break;
	case GE:	bool = lv >= rv;	break;
	case ANDAND:	bool = (lv && rv);	break;
	case OROR:	bool = (lv || rv);	break;

	default:		/* shouldn't happen if opdope is right */
		return NULL;
	}

	/* Allocate a TREE for the result and store the result. */
	tp = talloc();
	if (bool != -1) {			/* boolean result */
		tp->t_op  = ICON;
		tp->t_type = T_INT;
		tp->t_ival = bool;
	} else {				/* double result */
		tp->t_op  = DCON;
		tp->t_type = T_DOUBLE;
		d_to_dval(tp, lv);
	}
	return tp;
}

/*
 * Grab the value of a constant as a double.
 */
double
grabdval(tp) register TREE *tp;
{
	register int t;

	switch (tp->t_op) {
	case ICON:
		return ((t = tp->t_type) == T_UINT || t == T_ULONG)
				? (uival_t)tp->t_ival : tp->t_ival;
	case ZCON:
		return (uival_t)tp->t_zval;
	case LCON:
		return ((t = tp->t_type) == T_UINT || t == T_ULONG)
				? (ulval_t)tp->t_lval : tp->t_lval;
	case DCON:
		return dval_to_d(tp);
	}
	cbotch("grabdval");
}

#endif

/* end of n0/fold.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.