diff options
| author | 2026-03-17 13:22:00 +0100 | |
|---|---|---|
| committer | 2026-03-17 13:22:00 +0100 | |
| commit | a8d6f8bf30c07edb775e56889f568ca20240bedf (patch) | |
| tree | b5a452b2675b2400f15013617291fe6061180bbf /c/eval.c | |
| parent | 24f14b7ad1af08d872971d72ce089a529911f657 (diff) | |
REFACTOR: move sources to src/
Diffstat (limited to 'c/eval.c')
| -rw-r--r-- | c/eval.c | 437 |
1 files changed, 0 insertions, 437 deletions
diff --git a/c/eval.c b/c/eval.c deleted file mode 100644 index 3dfbbfb..0000000 --- a/c/eval.c +++ /dev/null @@ -1,437 +0,0 @@ -#include "c.h" -#include "../ir/ir.h" -#include <limits.h> - -static int -targ2hosttype(enum typetag t) -{ - if (t == TYPTR) t = targ_64bit ? TYUVLONG : TYUINT; - if (isintt(t)) { - int siz = targ_primsizes[t]; - int sgn = issignedt(t); -#define U(Ty,Tag) if (!sgn & (siz == sizeof(unsigned Ty))) return Tag; -#define S(Ty,Tag) if ( sgn & (siz == sizeof(signed Ty))) return Tag; - U(char, TYUCHAR) - S(char, TYSCHAR) - U(short, TYUSHORT) - S(short, TYSHORT) - U(int, TYUINT) - S(int, TYINT) - U(long long, TYUVLONG) - S(long long, TYVLONG) -#undef U -#undef S - } else if (t == TYLDOUBLE) return TYDOUBLE; - else if (isfltt(t) || iscomplext(t)) return t; - return 0; -} - -static bool -numcast(union type ty, struct expr *dst, const struct expr *src) -{ - enum typetag td = targ2hosttype(scalartypet(ty)), - ts = targ2hosttype(scalartypet(src->ty)); - vlong isrc; - struct expr tmp; - if (src == dst) tmp = *src, src = &tmp; - - assert(src->t == ENUMLIT); -#define TT(d,s) (td == d && ts == s) -#define TF(d) (td == d && isfltt(ts)) - if (!ts || !td) return 0; - else if (TT(TYFLOAT, TYFLOAT)) dst->f = (float) src->f; - else if (TT(TYFLOAT, TYDOUBLE)) dst->f = (float) src->f; - else if (TT(TYDOUBLE, TYFLOAT)) dst->f = src->f; - else if (TT(TYDOUBLE, TYDOUBLE)) dst->f = src->f; - else if (TT(TYFLOAT, TYUVLONG)) dst->f = (float) src->u; - else if (TT(TYDOUBLE, TYUVLONG)) dst->f = (double) src->u; - else if (td == TYFLOAT) dst->f = (float) src->i; - else if (td == TYDOUBLE) dst->f = (double) src->i; - else if (TF(TYUVLONG)) dst->u = src->f; - else if (TF(TYBOOL)) dst->i = (bool) src->f; - else if (isfltt(ts)) { isrc = src->f; goto Narrow; } - else { - isrc = src->i; - Narrow: - switch (td) { -#define I(Ty, Tag) case Tag: dst->i = (Ty) isrc; break; - I(bool, TYBOOL) - I(signed char, TYSCHAR) - I(unsigned char, TYUCHAR) - I(signed short, TYSHORT) - I(unsigned short, TYUSHORT) - I(signed int, TYINT) - I(unsigned int, TYUINT) - I(signed long long, TYVLONG) - I(unsigned long long, TYUVLONG) -#undef I - case TYFLOAT: dst->f = (float) src->f; break; - case TYDOUBLE: dst->f = src->f; break; - default: assert(0 && "bad cast?"); - } - } -#undef TT -#undef TF - - dst->t = ENUMLIT; - dst->ty = ty; - return 1; -} - -static struct expr * -lit2ssym(struct expr *ex) -{ - ex->ssym.sym = xcon2sym(expraddr(NULL, ex).i); - ex->ssym.local = 1; - ex->ssym.func = ex->ssym.off = 0; - ex->t = ESSYMREF; - return ex; -} - -static struct expr -staticaddrof(struct expr *ex, enum evalmode mode) -{ - struct expr ret = { .ty = mkptrtype(ex->ty, ex->qual), .span = ex->span }; - if (ex->t == ESYM && ex->ty.t < NTYPETAG) { - const struct decl *decl = &declsbuf.p[ex->decl]; - if (decl->sym && (decl->scls & (SCAUTO|SCREGISTER)) == 0) { - ret.t = ESSYMREF; - ret.ssym.sym = decl->sym; - ret.ssym.off = 0; - ret.ssym.func = decl->ty.t == TYFUNC; - ret.ssym.local = (decl->scls == SCSTATIC || decl->isdef); - } - } else if (ex->t == EDEREF && eval(ex->sub, EVSTATICINI)) { - ret = *ex->sub; - } else if (ex->t == EGETF && (ret = staticaddrof(ex->sub, mode)).t) { - if (ret.t == ESSYMREF) { - ex->t = ESSYMREF; - vlong off = (vlong) ret.ssym.off + ex->fld.off; - if ((int) off != off) return ret.t = 0, ret; - ret.ssym.off = off; - } else if (ret.t == ENUMLIT) { - ret.u += ex->fld.off; - } else assert(0); - } else if (ex->t == ESTRLIT || (mode == EVSTATICINI && ex->t == EINIT)) { - ret = *lit2ssym(ex); - } else if (ex->t == ENUMLIT || ex->t == ESSYMREF) ret = *ex; - return ret; -} - -static bool -isstaticlval(const struct expr *ex, enum evalmode mode) -{ - return ex->t == ESTRLIT || ex->t == ESSYMREF || (mode == EVSTATICINI && ex->t == EINIT); -} - -static bool -truthy(const struct expr *ex) -{ - switch (ex->t) { - default: assert(0 && "!scalar?"); - case ENUMLIT: - return isflt(ex->ty) ? ex->f != 0.0 : ex->u != 0; - case ESTRLIT: case ESSYMREF: - return 1; - } -} - -static bool -unop(struct expr *ex, enum evalmode mode) -{ - struct expr *sub = ex->sub; - - if (mode >= EVSTATICINI && ex->t == EDEREF) { - uvlong off; - uchar *p; - uint len; - uint csiz; - /* HACK */ - if (sub->t == ESTRLIT) { - /* *"s" */ - off = 0; - p = sub->s.p, len = sub->s.n; - csiz = typesize(typechild(sub->ty)); - StrRead: - if (off > len) return 0; - ex->t = ENUMLIT; - ex->ty = mktype(TYINT); - if (off == len) ex->u = 0; - else if (csiz == 1) ex->u = p[off]; - else if (csiz == 2) ex->u = ((short *)p)[off]; - else if (csiz == 4) ex->u = ((int *)p)[off]; - return 1; - } else if (sub->t == EADD && sub->sub[0].t == ESTRLIT && eval(&sub->sub[1], EVINTCONST)) { - /* "s"[0] */ - assert(sub->sub[1].t == ENUMLIT && isint(sub->sub[1].ty)); - off = sub->sub[1].u; - p = sub->sub[0].s.p, len = sub->sub[0].s.n; - csiz = typesize(typechild(sub->sub[0].ty)); - goto StrRead; - } else if (sub->t == EADD && sub->sub[1].t == ESTRLIT && eval(&sub->sub[0], EVINTCONST)) { - /* 0["s"] */ - assert(sub->sub[0].t == ENUMLIT && isint(sub->sub[0].ty)); - off = sub->sub[0].u; - p = sub->sub[1].s.p, len = sub->sub[1].s.n; - csiz = typesize(typechild(sub->sub[1].ty)); - goto StrRead; - } else return 0; - } else if (ex->t == EADDROF) { - assert(ex->ty.t == TYPTR); - struct expr ex2 = staticaddrof(ex->sub, mode); - if (!ex2.t) return 0; - ex2.span = ex->span; - ex2.ty = ex->ty; - *ex = ex2; - return 1; - } else if (ex->t == EGETF && !ex->fld.bitsiz) { - /* <lvalue>.memb -> is an address lvalue if 'memb' is of array type */ - if (ex->ty.t == TYARRAY) { - struct expr ex2; - if ((ex2 = staticaddrof(ex->sub, mode)).t) { - if (ex2.t == ENUMLIT) { - ex->t = ENUMLIT; - ex->u = ex2.u + ex->fld.off; - return 1; - } else { - assert(ex2.t == ESSYMREF); - ex->t = ESSYMREF; - vlong off = (vlong) sub->ssym.off + ex->fld.off; - if ((int) off != off) return 0; - ex->ssym = ex2.ssym; - ex->ssym.off = off; - return mode >= EVSTATICINI; - } - } - } - return 0; - } - if (!eval(sub, mode)) return 0; - switch (ex->t) { - case ECAST: - if (ex->ty.t == TYPTR && sub->t == ENUMLIT) { - ex->t = ENUMLIT; - ex->u = sub->u; - return 1; - } else if (isstaticlval(sub, mode) - && (ex->ty.t == TYPTR || (isint(ex->ty) && typesize(ex->ty) == targ_primsizes[TYPTR]))) { - /* ptr -> int */ - if (sub->t == ESTRLIT || sub->t == EINIT) - lit2ssym(sub); - sub->span = ex->span, sub->ty = ex->ty; - *ex = *sub; - return 1; - } - break; - case EPLUS: - break; - case ENEG: - if (sub->t != ENUMLIT) return 0; - if (isint(sub->ty)) sub->u = -sub->u; - else assert(isflt(sub->ty)), sub->f = -sub->f; - break; - case ECOMPL: - if (sub->t != ENUMLIT) return 0; - assert(isint(sub->ty)); - sub->u = ~sub->u; - break; - case ELOGNOT: - sub->u = !truthy(sub); - sub->t = ENUMLIT; - break; - default: - return 0; - } - if (sub->t != ENUMLIT || !numcast(ex->ty, ex, sub)) return 0; - return 1; -} - -static bool -binop(struct expr *ex, enum evalmode mode) -{ - struct expr *a = &ex->sub[0], *b = &ex->sub[1]; - if (!eval(a, mode)) return 0; - union type opty; - if (in_range(ex->t, EADD, ESHR)) - opty = ex->ty; - else /* compare, logical, set (result type != operation type) */ - opty = cvtarith(a->ty, b->ty); - if (isstaticlval(a, mode)) { - if ((ex->t == EADD || ex->t == ESUB) && eval(b, mode) && b->t == ENUMLIT) { - assert(isint(b->ty)); - assert(in_range(a->ty.t, TYPTR, TYARRAY)); - if (a->t == ESTRLIT) { - lit2ssym(a); - } else assert(a->t == ESSYMREF); - vlong addend = b->i * typesize(typechild(a->ty)), - off = a->ssym.off + (uvlong) (ex->t == EADD ? addend : -addend); - ex->t = ESSYMREF; - if ((int) off != off) return 0; - ex->ssym = a->ssym; - ex->ssym.off = off; - return 1; - } - return 0; - } - - enum { U = 0, S = 1<<8 , F = 1<<9 }; - int op = issigned(opty)<<8 | isflt(opty)<<9 | ex->t; - bool c; - if (ex->t != ELOGAND && ex->t != ELOGIOR) { - if (!numcast(opty, a, a)) return 0; - if (!eval(b, mode) || !numcast(opty, b, b)) return 0; - } - switch (op) { - case EADD|U: - case EADD|S: a->u += opty.t == TYPTR ? b->u * typesize(typechild(opty)) : b->u; break; - case EADD|F: a->f += b->f; break; - - case ESUB|U: - case ESUB|S: if (opty.t == TYPTR) { - assert(a->t == ENUMLIT && b->t == ENUMLIT); - assert(!isincomplete(typechild(ex->ty))); - a->u = (a->u - b->u) / typesize(typechild(ex->ty)); - } else a->u -= b->u; - break; - case ESUB|F: a->f -= b->f; break; - - case EMUL|U: - case EMUL|S: a->u *= b->u; break; - case EMUL|F: a->f *= b->f; break; - - case EDIV|U: if (!b->u) return 0; - a->u /= b->u; - break; - case EDIV|S: if (!b->i) return 0; - if (a->i == LLONG_MIN && b->i == -1) break; - a->i /= b->i; - break; - case EDIV|F: a->f /= b->f; break; - - case EREM|U: if (!b->u) return 0; - a->u %= b->u; - break; - case EREM|S: if (!b->i) return 0; - if (a->i == LLONG_MIN && b->i == -1) a->i = 0; - a->i %= b->i; - break; - - case EBAND|U: - case EBAND|S: a->u &= b->u; break; - - case EBIOR|U: - case EBIOR|S: a->u |= b->u; break; - - case EXOR|U: - case EXOR|S: a->u ^= b->u; break; - - case ESHL|S: if (a->i < 0) return 0; - case ESHL|U: if (b->u >= 8*targ_primsizes[opty.t]) return 0; - a->u <<= b->u; - break; - - case ESHR|U: if (b->u >= 8*targ_primsizes[opty.t]) return 0; - a->u >>= b->i; - break; - case ESHR|S: if (b->u >= 8*targ_primsizes[opty.t]) return 0; - a->i >>= b->i; - break; - - case EEQU|U: - case EEQU|S: a->u = a->u == b->u; break; - case EEQU|F: a->u = a->f == b->f; break; - - case ENEQ|U: - case ENEQ|S: a->u = a->u != b->u; break; - case ENEQ|F: a->u = a->f != b->f; break; - - case ELTH|U: a->u = a->u < b->u; break; - case ELTH|S: a->u = a->i < b->i; break; - case ELTH|F: a->u = a->f < b->f; break; - - case EGTH|U: a->u = a->u > b->u; break; - case EGTH|S: a->u = a->i > b->i; break; - case EGTH|F: a->u = a->f > b->f; break; - - case ELTE|U: a->u = a->u <= b->u; break; - case ELTE|S: a->u = a->i <= b->i; break; - case ELTE|F: a->u = a->f <= b->f; break; - - case EGTE|U: a->u = a->u >= b->u; break; - case EGTE|S: a->u = a->i >= b->i; break; - case EGTE|F: a->u = a->f >= b->f; break; - - case ELOGAND|U: - case ELOGAND|S: - case ELOGAND|F: - c = (op & F) ? a->f : a->u; - if (c) { - if (!eval(b, mode) || !numcast(opty, b, b)) return 0; - c = (op & F) ? b->f : b->u; - } - a->u = c; - break; - - case ELOGIOR|U: - case ELOGIOR|S: - case ELOGIOR|F: - c = op & F ? a->f : a->u; - if (!c) { - if (!eval(b, mode) || !numcast(opty, b, b)) return 0; - c = (op & F) ? b->f : b->u; - } - a->u = c; - break; - default: return 0; - } - - if (!in_range(ex->t, EADD, ESHR)) { - a->t = ENUMLIT; - a->ty = mktype(TYINT); - } - return numcast(ex->ty, ex, a); -} - -bool -eval(struct expr *ex, enum evalmode mode) -{ - switch (ex->t) { - case EGETF: goto Unop; - case ESEQ: - if (!eval(&ex->sub[0], mode)) return 0; - *ex = ex->sub[1]; - return eval(ex, mode); - case ECOND: - if (!eval(&ex->sub[0], mode)) return 0; - *ex = ex->sub[2-truthy(&ex->sub[0])]; - return eval(ex, mode); - case EINIT: - for (struct initval *v = ex->init->vals; v; v = v->next) { - if (!eval(&v->ex, mode)) return 0; - } - return 1; - case ENUMLIT: - if (mode <= EVINTCONST) return !isflt(ex->ty); - return 1; - case ESYM: - if (in_range(ex->ty.t, TYARRAY, TYFUNC) - && mode >= EVSTATICINI) { - struct expr ex2 = staticaddrof(ex, mode); - if (ex2.t) { - union type ty = ex->ty; - *ex = ex2; - ex->ty = ty; - return 1; - } - } - return 0; - case ESTRLIT: case ESSYMREF: - return mode >= EVSTATICINI; - default: - if (isunop(ex->t)) Unop: return unop(ex, mode); - if (isbinop(ex->t)) return binop(ex, mode); - } - return 0; -} - -/* vim:set ts=3 sw=3 expandtab: */ |