📄 cceval.c
字号:
** 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 + -