mirror of
https://github.com/DrBeef/ioq3quest.git
synced 2024-11-27 22:33:10 +00:00
587 lines
16 KiB
C
587 lines
16 KiB
C
#include "c.h"
|
|
#include <float.h>
|
|
|
|
|
|
#define foldcnst(TYPE,VAR,OP) \
|
|
if (l->op == CNST+TYPE && r->op == CNST+TYPE) \
|
|
return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR)
|
|
#define commute(L,R) \
|
|
if (generic(R->op) == CNST && generic(L->op) != CNST) \
|
|
do { Tree t = L; L = R; R = t; } while(0)
|
|
#define xfoldcnst(TYPE,VAR,OP,FUNC)\
|
|
if (l->op == CNST+TYPE && r->op == CNST+TYPE\
|
|
&& FUNC(l->u.v.VAR,r->u.v.VAR,\
|
|
ty->u.sym->u.limits.min.VAR,\
|
|
ty->u.sym->u.limits.max.VAR, needconst)) \
|
|
return cnsttree(ty, l->u.v.VAR OP r->u.v.VAR)
|
|
#define xcvtcnst(FTYPE,SRC,DST,VAR,EXPR) \
|
|
if (l->op == CNST+FTYPE) do {\
|
|
if (!explicitCast\
|
|
&& ((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\
|
|
warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, DST);\
|
|
if (needconst\
|
|
|| !((SRC) < DST->u.sym->u.limits.min.VAR || (SRC) > DST->u.sym->u.limits.max.VAR))\
|
|
return cnsttree(ty, (EXPR)); } while(0)
|
|
#define identity(X,Y,TYPE,VAR,VAL) \
|
|
if (X->op == CNST+TYPE && X->u.v.VAR == VAL) return Y
|
|
#define zerofield(OP,TYPE,VAR) \
|
|
if (l->op == FIELD \
|
|
&& r->op == CNST+TYPE && r->u.v.VAR == 0)\
|
|
return eqtree(OP, bittree(BAND, l->kids[0],\
|
|
cnsttree(unsignedtype, \
|
|
(unsigned long)fieldmask(l->u.field)<<fieldright(l->u.field))), r)
|
|
#define cfoldcnst(TYPE,VAR,OP) \
|
|
if (l->op == CNST+TYPE && r->op == CNST+TYPE) \
|
|
return cnsttree(inttype, (long)(l->u.v.VAR OP r->u.v.VAR))
|
|
#define foldaddp(L,R,RTYPE,VAR) \
|
|
if (L->op == CNST+P && R->op == CNST+RTYPE) { \
|
|
Tree e = tree(CNST+P, ty, NULL, NULL);\
|
|
e->u.v.p = (char *)L->u.v.p + R->u.v.VAR;\
|
|
return e; }
|
|
#define ufoldcnst(TYPE,EXP) if (l->op == CNST+TYPE) return EXP
|
|
#define sfoldcnst(OP) \
|
|
if (l->op == CNST+U && r->op == CNST+I \
|
|
&& r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) \
|
|
return cnsttree(ty, (unsigned long)(l->u.v.u OP r->u.v.i))
|
|
#define geu(L,R,V) \
|
|
if (R->op == CNST+U && R->u.v.u == 0) do { \
|
|
warning("result of unsigned comparison is constant\n"); \
|
|
return tree(RIGHT, inttype, root(L), cnsttree(inttype, (long)(V))); } while(0)
|
|
#define idempotent(OP) if (l->op == OP) return l->kids[0]
|
|
|
|
int needconst;
|
|
int explicitCast;
|
|
static int addi(long x, long y, long min, long max, int needconst) {
|
|
int cond = x == 0 || y == 0
|
|
|| (x < 0 && y < 0 && x >= min - y)
|
|
|| (x < 0 && y > 0)
|
|
|| (x > 0 && y < 0)
|
|
|| (x > 0 && y > 0 && x <= max - y);
|
|
if (!cond && needconst) {
|
|
warning("overflow in constant expression\n");
|
|
cond = 1;
|
|
}
|
|
return cond;
|
|
|
|
|
|
}
|
|
|
|
static int addd(double x, double y, double min, double max, int needconst) {
|
|
int cond = x == 0 || y == 0
|
|
|| (x < 0 && y < 0 && x >= min - y)
|
|
|| (x < 0 && y > 0)
|
|
|| (x > 0 && y < 0)
|
|
|| (x > 0 && y > 0 && x <= max - y);
|
|
if (!cond && needconst) {
|
|
warning("overflow in constant expression\n");
|
|
cond = 1;
|
|
}
|
|
return cond;
|
|
|
|
|
|
}
|
|
|
|
static Tree addrtree(Tree e, long n, Type ty) {
|
|
Symbol p = e->u.sym, q;
|
|
|
|
if (p->scope == GLOBAL
|
|
|| p->sclass == STATIC || p->sclass == EXTERN)
|
|
NEW0(q, PERM);
|
|
else
|
|
NEW0(q, FUNC);
|
|
q->name = stringd(genlabel(1));
|
|
q->sclass = p->sclass;
|
|
q->scope = p->scope;
|
|
assert(isptr(ty) || isarray(ty));
|
|
q->type = isptr(ty) ? ty->type : ty;
|
|
q->temporary = p->temporary;
|
|
q->generated = p->generated;
|
|
q->addressed = p->addressed;
|
|
q->computed = 1;
|
|
q->defined = 1;
|
|
q->ref = 1;
|
|
if (p->scope == GLOBAL
|
|
|| p->sclass == STATIC || p->sclass == EXTERN) {
|
|
if (p->sclass == AUTO)
|
|
q->sclass = STATIC;
|
|
(*IR->address)(q, p, n);
|
|
} else {
|
|
Code cp;
|
|
addlocal(p);
|
|
cp = code(Address);
|
|
cp->u.addr.sym = q;
|
|
cp->u.addr.base = p;
|
|
cp->u.addr.offset = n;
|
|
}
|
|
e = tree(e->op, ty, NULL, NULL);
|
|
e->u.sym = q;
|
|
return e;
|
|
}
|
|
|
|
/* div[id] - return 1 if min <= x/y <= max, 0 otherwise */
|
|
static int divi(long x, long y, long min, long max, int needconst) {
|
|
int cond = y != 0 && !(x == min && y == -1);
|
|
if (!cond && needconst) {
|
|
warning("overflow in constant expression\n");
|
|
cond = 1;
|
|
}
|
|
return cond;
|
|
|
|
|
|
}
|
|
|
|
static int divd(double x, double y, double min, double max, int needconst) {
|
|
int cond;
|
|
|
|
if (x < 0) x = -x;
|
|
if (y < 0) y = -y;
|
|
cond = y != 0 && !(y < 1 && x > max*y);
|
|
if (!cond && needconst) {
|
|
warning("overflow in constant expression\n");
|
|
cond = 1;
|
|
}
|
|
return cond;
|
|
|
|
}
|
|
|
|
/* mul[id] - return 1 if min <= x*y <= max, 0 otherwise */
|
|
static int muli(long x, long y, long min, long max, int needconst) {
|
|
int cond = (x > -1 && x <= 1) || (y > -1 && y <= 1)
|
|
|| (x < 0 && y < 0 && -x <= max/-y)
|
|
|| (x < 0 && y > 0 && x >= min/y)
|
|
|| (x > 0 && y < 0 && y >= min/x)
|
|
|| (x > 0 && y > 0 && x <= max/y);
|
|
if (!cond && needconst) {
|
|
warning("overflow in constant expression\n");
|
|
cond = 1;
|
|
}
|
|
return cond;
|
|
|
|
|
|
}
|
|
|
|
static int muld(double x, double y, double min, double max, int needconst) {
|
|
int cond = (x >= -1 && x <= 1) || (y >= -1 && y <= 1)
|
|
|| (x < 0 && y < 0 && -x <= max/-y)
|
|
|| (x < 0 && y > 0 && x >= min/y)
|
|
|| (x > 0 && y < 0 && y >= min/x)
|
|
|| (x > 0 && y > 0 && x <= max/y);
|
|
if (!cond && needconst) {
|
|
warning("overflow in constant expression\n");
|
|
cond = 1;
|
|
}
|
|
return cond;
|
|
|
|
|
|
}
|
|
/* sub[id] - return 1 if min <= x-y <= max, 0 otherwise */
|
|
static int subi(long x, long y, long min, long max, int needconst) {
|
|
return addi(x, -y, min, max, needconst);
|
|
}
|
|
|
|
static int subd(double x, double y, double min, double max, int needconst) {
|
|
return addd(x, -y, min, max, needconst);
|
|
}
|
|
Tree constexpr(int tok) {
|
|
Tree p;
|
|
|
|
needconst++;
|
|
p = expr1(tok);
|
|
needconst--;
|
|
return p;
|
|
}
|
|
|
|
int intexpr(int tok, int n) {
|
|
Tree p = constexpr(tok);
|
|
|
|
needconst++;
|
|
if (p->op == CNST+I || p->op == CNST+U)
|
|
n = cast(p, inttype)->u.v.i;
|
|
else
|
|
error("integer expression must be constant\n");
|
|
needconst--;
|
|
return n;
|
|
}
|
|
Tree simplify(int op, Type ty, Tree l, Tree r) {
|
|
int n;
|
|
|
|
if (optype(op) == 0)
|
|
op = mkop(op, ty);
|
|
switch (op) {
|
|
case ADD+U:
|
|
foldcnst(U,u,+);
|
|
commute(r,l);
|
|
identity(r,l,U,u,0);
|
|
break;
|
|
case ADD+I:
|
|
xfoldcnst(I,i,+,addi);
|
|
commute(r,l);
|
|
identity(r,l,I,i,0);
|
|
break;
|
|
case CVI+I:
|
|
xcvtcnst(I,l->u.v.i,ty,i,(long)extend(l->u.v.i,ty));
|
|
break;
|
|
case CVU+I:
|
|
if (l->op == CNST+U) {
|
|
if (!explicitCast && l->u.v.u > ty->u.sym->u.limits.max.i)
|
|
warning("overflow in converting constant expression from `%t' to `%t'\n", l->type, ty);
|
|
if (needconst || !(l->u.v.u > ty->u.sym->u.limits.max.i))
|
|
return cnsttree(ty, (long)extend(l->u.v.u,ty));
|
|
}
|
|
break;
|
|
case CVP+U:
|
|
xcvtcnst(P,(unsigned long)l->u.v.p,ty,u,(unsigned long)l->u.v.p);
|
|
break;
|
|
case CVU+P:
|
|
xcvtcnst(U,(void*)l->u.v.u,ty,p,(void*)l->u.v.u);
|
|
break;
|
|
case CVP+P:
|
|
xcvtcnst(P,l->u.v.p,ty,p,l->u.v.p);
|
|
break;
|
|
case CVI+U:
|
|
xcvtcnst(I,l->u.v.i,ty,u,((unsigned long)l->u.v.i)&ones(8*ty->size));
|
|
break;
|
|
case CVU+U:
|
|
xcvtcnst(U,l->u.v.u,ty,u,l->u.v.u&ones(8*ty->size));
|
|
break;
|
|
|
|
case CVI+F:
|
|
xcvtcnst(I,l->u.v.i,ty,d,(double)l->u.v.i);
|
|
case CVU+F:
|
|
xcvtcnst(U,l->u.v.u,ty,d,(double)l->u.v.u);
|
|
break;
|
|
case CVF+I:
|
|
xcvtcnst(F,l->u.v.d,ty,i,(long)l->u.v.d);
|
|
break;
|
|
case CVF+F: {
|
|
float d = 0.0f;
|
|
if (l->op == CNST+F) {
|
|
if (l->u.v.d < ty->u.sym->u.limits.min.d)
|
|
d = ty->u.sym->u.limits.min.d;
|
|
else if (l->u.v.d > ty->u.sym->u.limits.max.d)
|
|
d = ty->u.sym->u.limits.max.d;
|
|
else
|
|
d = l->u.v.d;
|
|
}
|
|
xcvtcnst(F,l->u.v.d,ty,d,(double)d);
|
|
break;
|
|
}
|
|
case BAND+U:
|
|
foldcnst(U,u,&);
|
|
commute(r,l);
|
|
identity(r,l,U,u,ones(8*ty->size));
|
|
if (r->op == CNST+U && r->u.v.u == 0)
|
|
return tree(RIGHT, ty, root(l), cnsttree(ty, 0UL));
|
|
break;
|
|
case BAND+I:
|
|
foldcnst(I,i,&);
|
|
commute(r,l);
|
|
identity(r,l,I,i,ones(8*ty->size));
|
|
if (r->op == CNST+I && r->u.v.u == 0)
|
|
return tree(RIGHT, ty, root(l), cnsttree(ty, 0L));
|
|
break;
|
|
|
|
case MUL+U:
|
|
commute(l,r);
|
|
if (l->op == CNST+U && (n = ispow2(l->u.v.u)) != 0)
|
|
return simplify(LSH, ty, r, cnsttree(inttype, (long)n));
|
|
foldcnst(U,u,*);
|
|
identity(r,l,U,u,1);
|
|
break;
|
|
case NE+I:
|
|
cfoldcnst(I,i,!=);
|
|
commute(r,l);
|
|
zerofield(NE,I,i);
|
|
break;
|
|
|
|
case EQ+I:
|
|
cfoldcnst(I,i,==);
|
|
commute(r,l);
|
|
zerofield(EQ,I,i);
|
|
break;
|
|
case ADD+P:
|
|
foldaddp(l,r,I,i);
|
|
foldaddp(l,r,U,u);
|
|
foldaddp(r,l,I,i);
|
|
foldaddp(r,l,U,u);
|
|
commute(r,l);
|
|
identity(r,retype(l,ty),I,i,0);
|
|
identity(r,retype(l,ty),U,u,0);
|
|
if (isaddrop(l->op)
|
|
&& ((r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i
|
|
&& r->u.v.i >= longtype->u.sym->u.limits.min.i)
|
|
|| (r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i)))
|
|
return addrtree(l, cast(r, longtype)->u.v.i, ty);
|
|
if (l->op == ADD+P && isaddrop(l->kids[1]->op)
|
|
&& ((r->op == CNST+I && r->u.v.i <= longtype->u.sym->u.limits.max.i
|
|
&& r->u.v.i >= longtype->u.sym->u.limits.min.i)
|
|
|| (r->op == CNST+U && r->u.v.u <= longtype->u.sym->u.limits.max.i)))
|
|
return simplify(ADD+P, ty, l->kids[0],
|
|
addrtree(l->kids[1], cast(r, longtype)->u.v.i, ty));
|
|
if ((l->op == ADD+I || l->op == SUB+I)
|
|
&& l->kids[1]->op == CNST+I && isaddrop(r->op))
|
|
return simplify(ADD+P, ty, l->kids[0],
|
|
simplify(generic(l->op)+P, ty, r, l->kids[1]));
|
|
if (l->op == ADD+P && generic(l->kids[1]->op) == CNST
|
|
&& generic(r->op) == CNST)
|
|
return simplify(ADD+P, ty, l->kids[0],
|
|
simplify(ADD, l->kids[1]->type, l->kids[1], r));
|
|
if (l->op == ADD+I && generic(l->kids[1]->op) == CNST
|
|
&& r->op == ADD+P && generic(r->kids[1]->op) == CNST)
|
|
return simplify(ADD+P, ty, l->kids[0],
|
|
simplify(ADD+P, ty, r->kids[0],
|
|
simplify(ADD, r->kids[1]->type, l->kids[1], r->kids[1])));
|
|
if (l->op == RIGHT && l->kids[1])
|
|
return tree(RIGHT, ty, l->kids[0],
|
|
simplify(ADD+P, ty, l->kids[1], r));
|
|
else if (l->op == RIGHT && l->kids[0])
|
|
return tree(RIGHT, ty,
|
|
simplify(ADD+P, ty, l->kids[0], r), NULL);
|
|
break;
|
|
|
|
case ADD+F:
|
|
xfoldcnst(F,d,+,addd);
|
|
commute(r,l);
|
|
break;
|
|
case AND+I:
|
|
op = AND;
|
|
ufoldcnst(I,l->u.v.i ? cond(r) : l); /* 0&&r => 0, 1&&r => r */
|
|
break;
|
|
case OR+I:
|
|
op = OR;
|
|
/* 0||r => r, 1||r => 1 */
|
|
ufoldcnst(I,l->u.v.i ? cnsttree(ty, 1L) : cond(r));
|
|
break;
|
|
case BCOM+I:
|
|
ufoldcnst(I,cnsttree(ty, (long)extend((~l->u.v.i)&ones(8*ty->size), ty)));
|
|
idempotent(BCOM+U);
|
|
break;
|
|
case BCOM+U:
|
|
ufoldcnst(U,cnsttree(ty, (unsigned long)((~l->u.v.u)&ones(8*ty->size))));
|
|
idempotent(BCOM+U);
|
|
break;
|
|
case BOR+U:
|
|
foldcnst(U,u,|);
|
|
commute(r,l);
|
|
identity(r,l,U,u,0);
|
|
break;
|
|
case BOR+I:
|
|
foldcnst(I,i,|);
|
|
commute(r,l);
|
|
identity(r,l,I,i,0);
|
|
break;
|
|
case BXOR+U:
|
|
foldcnst(U,u,^);
|
|
commute(r,l);
|
|
identity(r,l,U,u,0);
|
|
break;
|
|
case BXOR+I:
|
|
foldcnst(I,i,^);
|
|
commute(r,l);
|
|
identity(r,l,I,i,0);
|
|
break;
|
|
case DIV+F:
|
|
xfoldcnst(F,d,/,divd);
|
|
break;
|
|
case DIV+I:
|
|
identity(r,l,I,i,1);
|
|
if ((r->op == CNST+I && r->u.v.i == 0)
|
|
|| (l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i
|
|
&& r->op == CNST+I && r->u.v.i == -1))
|
|
break;
|
|
xfoldcnst(I,i,/,divi);
|
|
break;
|
|
case DIV+U:
|
|
identity(r,l,U,u,1);
|
|
if (r->op == CNST+U && r->u.v.u == 0)
|
|
break;
|
|
if (r->op == CNST+U && (n = ispow2(r->u.v.u)) != 0)
|
|
return simplify(RSH, ty, l, cnsttree(inttype, (long)n));
|
|
foldcnst(U,u,/);
|
|
break;
|
|
case EQ+F:
|
|
cfoldcnst(F,d,==);
|
|
commute(r,l);
|
|
break;
|
|
case EQ+U:
|
|
cfoldcnst(U,u,==);
|
|
commute(r,l);
|
|
zerofield(EQ,U,u);
|
|
break;
|
|
case GE+F: cfoldcnst(F,d,>=); break;
|
|
case GE+I: cfoldcnst(I,i,>=); break;
|
|
case GE+U:
|
|
geu(l,r,1); /* l >= 0 => (l,1) */
|
|
cfoldcnst(U,u,>=);
|
|
if (l->op == CNST+U && l->u.v.u == 0) /* 0 >= r => r == 0 */
|
|
return eqtree(EQ, r, l);
|
|
break;
|
|
case GT+F: cfoldcnst(F,d, >); break;
|
|
case GT+I: cfoldcnst(I,i, >); break;
|
|
case GT+U:
|
|
geu(r,l,0); /* 0 > r => (r,0) */
|
|
cfoldcnst(U,u, >);
|
|
if (r->op == CNST+U && r->u.v.u == 0) /* l > 0 => l != 0 */
|
|
return eqtree(NE, l, r);
|
|
break;
|
|
case LE+F: cfoldcnst(F,d,<=); break;
|
|
case LE+I: cfoldcnst(I,i,<=); break;
|
|
case LE+U:
|
|
geu(r,l,1); /* 0 <= r => (r,1) */
|
|
cfoldcnst(U,u,<=);
|
|
if (r->op == CNST+U && r->u.v.u == 0) /* l <= 0 => l == 0 */
|
|
return eqtree(EQ, l, r);
|
|
break;
|
|
case LSH+I:
|
|
identity(r,l,I,i,0);
|
|
if (l->op == CNST+I && r->op == CNST+I
|
|
&& r->u.v.i >= 0 && r->u.v.i < 8*l->type->size
|
|
&& muli(l->u.v.i, 1<<r->u.v.i, ty->u.sym->u.limits.min.i, ty->u.sym->u.limits.max.i, needconst))
|
|
return cnsttree(ty, (long)(l->u.v.i<<r->u.v.i));
|
|
if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
|
|
warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case LSH+U:
|
|
identity(r,l,I,i,0);
|
|
sfoldcnst(<<);
|
|
if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
|
|
warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case LT+F: cfoldcnst(F,d, <); break;
|
|
case LT+I: cfoldcnst(I,i, <); break;
|
|
case LT+U:
|
|
geu(l,r,0); /* l < 0 => (l,0) */
|
|
cfoldcnst(U,u, <);
|
|
if (l->op == CNST+U && l->u.v.u == 0) /* 0 < r => r != 0 */
|
|
return eqtree(NE, r, l);
|
|
break;
|
|
case MOD+I:
|
|
if (r->op == CNST+I && r->u.v.i == 1) /* l%1 => (l,0) */
|
|
return tree(RIGHT, ty, root(l), cnsttree(ty, 0L));
|
|
if ((r->op == CNST+I && r->u.v.i == 0)
|
|
|| (l->op == CNST+I && l->u.v.i == ty->u.sym->u.limits.min.i
|
|
&& r->op == CNST+I && r->u.v.i == -1))
|
|
break;
|
|
xfoldcnst(I,i,%,divi);
|
|
break;
|
|
case MOD+U:
|
|
if (r->op == CNST+U && ispow2(r->u.v.u)) /* l%2^n => l&(2^n-1) */
|
|
return bittree(BAND, l, cnsttree(ty, r->u.v.u - 1));
|
|
if (r->op == CNST+U && r->u.v.u == 0)
|
|
break;
|
|
foldcnst(U,u,%);
|
|
break;
|
|
case MUL+F:
|
|
xfoldcnst(F,d,*,muld);
|
|
commute(l,r);
|
|
break;
|
|
case MUL+I:
|
|
commute(l,r);
|
|
xfoldcnst(I,i,*,muli);
|
|
if (l->op == CNST+I && r->op == ADD+I && r->kids[1]->op == CNST+I)
|
|
/* c1*(x + c2) => c1*x + c1*c2 */
|
|
return simplify(ADD, ty, simplify(MUL, ty, l, r->kids[0]),
|
|
simplify(MUL, ty, l, r->kids[1]));
|
|
if (l->op == CNST+I && r->op == SUB+I && r->kids[1]->op == CNST+I)
|
|
/* c1*(x - c2) => c1*x - c1*c2 */
|
|
return simplify(SUB, ty, simplify(MUL, ty, l, r->kids[0]),
|
|
simplify(MUL, ty, l, r->kids[1]));
|
|
if (l->op == CNST+I && l->u.v.i > 0 && (n = ispow2(l->u.v.i)) != 0)
|
|
/* 2^n * r => r<<n */
|
|
return simplify(LSH, ty, r, cnsttree(inttype, (long)n));
|
|
identity(r,l,I,i,1);
|
|
break;
|
|
case NE+F:
|
|
cfoldcnst(F,d,!=);
|
|
commute(r,l);
|
|
break;
|
|
case NE+U:
|
|
cfoldcnst(U,u,!=);
|
|
commute(r,l);
|
|
zerofield(NE,U,u);
|
|
break;
|
|
case NEG+F:
|
|
ufoldcnst(F,cnsttree(ty, -l->u.v.d));
|
|
idempotent(NEG+F);
|
|
break;
|
|
case NEG+I:
|
|
if (l->op == CNST+I) {
|
|
if (needconst && l->u.v.i == ty->u.sym->u.limits.min.i)
|
|
warning("overflow in constant expression\n");
|
|
if (needconst || l->u.v.i != ty->u.sym->u.limits.min.i)
|
|
return cnsttree(ty, -l->u.v.i);
|
|
}
|
|
idempotent(NEG+I);
|
|
break;
|
|
case NOT+I:
|
|
op = NOT;
|
|
ufoldcnst(I,cnsttree(ty, !l->u.v.i));
|
|
break;
|
|
case RSH+I:
|
|
identity(r,l,I,i,0);
|
|
if (l->op == CNST+I && r->op == CNST+I
|
|
&& r->u.v.i >= 0 && r->u.v.i < 8*l->type->size) {
|
|
long n = l->u.v.i>>r->u.v.i;
|
|
if (l->u.v.i < 0)
|
|
n |= ~0UL<<(8*l->type->size - r->u.v.i);
|
|
return cnsttree(ty, n);
|
|
}
|
|
if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
|
|
warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case RSH+U:
|
|
identity(r,l,I,i,0);
|
|
sfoldcnst(>>);
|
|
if (r->op == CNST+I && (r->u.v.i >= 8*ty->size || r->u.v.i < 0)) {
|
|
warning("shifting an `%t' by %d bits is undefined\n", ty, r->u.v.i);
|
|
break;
|
|
}
|
|
|
|
break;
|
|
case SUB+F:
|
|
xfoldcnst(F,d,-,subd);
|
|
break;
|
|
case SUB+I:
|
|
xfoldcnst(I,i,-,subi);
|
|
identity(r,l,I,i,0);
|
|
break;
|
|
case SUB+U:
|
|
foldcnst(U,u,-);
|
|
identity(r,l,U,u,0);
|
|
break;
|
|
case SUB+P:
|
|
if (l->op == CNST+P && r->op == CNST+P)
|
|
return cnsttree(ty, (long)((char *)l->u.v.p - (char *)r->u.v.p));
|
|
if (r->op == CNST+I || r->op == CNST+U)
|
|
return simplify(ADD, ty, l,
|
|
cnsttree(inttype, r->op == CNST+I ? -r->u.v.i : -(long)r->u.v.u));
|
|
if (isaddrop(l->op) && r->op == ADD+I && r->kids[1]->op == CNST+I)
|
|
/* l - (x + c) => l-c - x */
|
|
return simplify(SUB, ty,
|
|
simplify(SUB, ty, l, r->kids[1]), r->kids[0]);
|
|
break;
|
|
default:assert(0);
|
|
}
|
|
return tree(op, ty, l, r);
|
|
}
|
|
/* ispow2 - if u > 1 && u == 2^n, return n, otherwise return 0 */
|
|
int ispow2(unsigned long u) {
|
|
int n;
|
|
|
|
if (u > 1 && (u&(u-1)) == 0)
|
|
for (n = 0; u; u >>= 1, n++)
|
|
if (u&1)
|
|
return n;
|
|
return 0;
|
|
}
|
|
|