From a8d6f8bf30c07edb775e56889f568ca20240bedf Mon Sep 17 00:00:00 2001 From: lemon Date: Tue, 17 Mar 2026 13:22:00 +0100 Subject: REFACTOR: move sources to src/ --- src/c_type.c | 311 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 311 insertions(+) create mode 100644 src/c_type.c (limited to 'src/c_type.c') diff --git a/src/c_type.c b/src/c_type.c new file mode 100644 index 0000000..e8a5b1e --- /dev/null +++ b/src/c_type.c @@ -0,0 +1,311 @@ +#include "type.h" + +struct typedata typedata[1<<13]; +internstr ttypenames[1<<10]; + +static ushort +hashtd(const struct typedata *td) +{ + uint h = td->t*33; + bool t; + switch (td->t) { + case TYARRAY: + h = hashb(h, &td->arrlen, sizeof td->arrlen); + /* fallthru */ + case TYPTR: + h = hashb(h, &td->child, sizeof td->child); + break; + case TYSTRUCT: + case TYUNION: + case TYENUM: + h = hashb(h, &td->id, sizeof td->id); + break; + case TYFUNC: + h = hashb(h, &td->ret, sizeof td->ret); + h = hashb(h, &td->nmemb, sizeof td->nmemb); + h = hashb(h, (t = td->kandr, &t), sizeof t); + h = hashb(h, (t = td->variadic, &t), sizeof t); + for (int i = 0; i < td->nmemb; ++i) { + h = hashb(h, &td->param[i], sizeof *td->param); + } + break; + default: + assert(0 && "bad typedata tag"); + } + return h ^ h>>16; +} + +static bool +tdequ(const struct typedata *a, const struct typedata *b) +{ + if (a->t != b->t) return 0; + switch (a->t) { + case TYARRAY: + return a->arrlen == b->arrlen && a->child.bits == b->child.bits; + case TYPTR: + return a->child.bits == b->child.bits; + case TYSTRUCT: + case TYUNION: + case TYENUM: + return a->id == b->id; + case TYFUNC: + if (a->ret.bits != b->ret.bits) return 0; + if (a->nmemb != b->nmemb) return 0; + if (a->variadic != b->variadic) return 0; + if (a->kandr != b->kandr) return 0; + for (int i = 0; i < a->nmemb; ++i) { + if (a->param[i].bits != b->param[i].bits) + return 0; + } + return 1; + default: + assert(0 && "bad typedata tag"); + } +} + +static ushort +interntd(const struct typedata *td) +{ + uint h, i, n = countof(typedata); + for (i = h = hashtd(td); n--; ++i) { + struct typedata *slot = &typedata[i &= countof(typedata) - 1]; + if (!slot->t) { + uint nmemb; + static struct arena *datarena; + if (!datarena) { + enum { N = 1<<12 }; + static union { char m[sizeof(struct arena) + N]; struct arena *_align; } amem; + datarena = (void *)amem.m, datarena->cap = N; + } + + Copy: + nmemb = td->nmemb; + *slot = *td; + switch (slot->t) { + case TYENUM: + if (slot->var) + slot->var = alloccopy(&datarena, td->var, nmemb * sizeof *slot->var, 0); + break; + case TYSTRUCT: + case TYUNION: + if (slot->fld) + slot->fld = alloccopy(&datarena, td->fld, nmemb * sizeof *slot->fld, 0); + break; + case TYFUNC: + if (slot->param) + slot->param = alloccopy(&datarena, td->param, nmemb * sizeof *slot->param, 0); + } + return i; + } else if (tdequ(slot, td)) { + if (td->t == TYSTRUCT || td->t == TYUNION || td->t == TYENUM) + goto Copy; + return i; + } + } + assert(0 && "typedata[] full"); +} + +bool +isincomplete(union type t) +{ + switch (t.t) { + case TYVOID: return 1; + case TYARRAY: return !typearrlen(t); + case TYSTRUCT: + case TYUNION: + return typedata[t.dat].nmemb == 0; + case TYENUM: + return !typedata[t.dat].backing; + } + return 0; +} + +uint +typesize(union type t) +{ + if (isprim(t) || t.t == TYPTR) return targ_primsizes[t.t]; + switch (t.t) { + case TYENUM: + return targ_primsizes[typedata[t.dat].backing]; + case TYARRAY: + if (t.flag & TFCHLDPRIM) + return targ_primsizes[t.child] * t.arrlen; + /* fallthru */ + case TYSTRUCT: + case TYUNION: + return typedata[t.dat].siz; + } + return 0; +} + +uint +typealign(union type t) +{ + if (isprim(t) || t.t == TYPTR) return targ_primalign[t.t]; + switch (t.t) { + case TYENUM: + return targ_primalign[typedata[t.dat].backing]; + case TYARRAY: + return typealign(typechild(t)); + case TYSTRUCT: + case TYUNION: + return typedata[t.dat].align; + } + return 0; +} + +union type +mkptrtype(union type t, int qual) +{ + if (isprim(t)) + return mktype(TYPTR, .flag = TFCHLDPRIM | (qual & TFCHLDQUAL), .child = t.t); + else if (t.t == TYENUM || t.t == TYFUNC || isagg(t)) + return mktype(TYPTR, .flag = TFCHLDISDAT | (qual & TFCHLDQUAL), .dat = t.dat); + return mktype(TYPTR, .flag = qual & TFCHLDQUAL, + .dat = interntd(&(struct typedata) { TYPTR, .child = t })); +} + +union type +mkarrtype(union type t, int qual, uint n) +{ + if (isprim(t) && n < 256) + return mktype(TYARRAY, .flag = TFCHLDPRIM | (qual & TFCHLDQUAL), .child = t.t, .arrlen = n); + return mktype(TYARRAY, .flag = qual & TFCHLDQUAL, + .dat = interntd(&(struct typedata) { TYARRAY, .child = t, .arrlen = n, .siz = n * typesize(t) })); +} + +union type +mkfntype(union type ret, uint n, const union type *par, bool kandr, bool variadic) +{ + struct typedata td = { TYFUNC, .ret = ret, .nmemb = n, .param = par }; + td.kandr = kandr, td.variadic = variadic; + return mktype(TYFUNC, .dat = interntd(&td)); +} + +union type +completetype(internstr name, int id, struct typedata *td) +{ + assert(td->t == TYENUM || td->t == TYSTRUCT || td->t == TYUNION); + td->id = id; + assert(id < countof(ttypenames) && "too many tag types"); + if (ttypenames[id]) + assert(ttypenames[id] == name && "bad redefn"); + else + ttypenames[id] = name; + return mktype(td->t, .dat = interntd(td), .backing = td->t == TYENUM ? td->backing : 0); +} + +union type +mktagtype(internstr name, struct typedata *td) +{ + static int id; + return completetype(name, id++, td); +} + +static bool +getfieldrec(struct fielddata *res, uint off, const struct typedata *td, internstr name) +{ +Begin: + for (int i = 0; i < td->nmemb; ++i) { + struct namedfield *fld = &td->fld[i]; + if (fld->name == name) { /* match */ + *res = fld->f; + res->off += off; + return 1; + } else if (!fld->name) { /* anonymous struct/union */ + const struct typedata *ftd = &typedata[fld->f.t.dat]; + assert(isagg(fld->f.t)); + if (i == td->nmemb - 1) { /* last field, tail recurse */ + off += fld->f.off; + td = ftd; + goto Begin; + } else if (getfieldrec(res, off + fld->f.off, ftd, name)) + return 1; + } + } + return 0; +} + +bool +getfield(struct fielddata *res, union type ty, internstr name) +{ + assert(isagg(ty)); + return getfieldrec(res, 0, &typedata[ty.dat], name); +} + +union type +typedecay(union type t) +{ + if (t.t == TYARRAY) + return mkptrtype(typechild(t), t.flag & TFCHLDQUAL); + if (t.t == TYFUNC) + return mkptrtype(t, 0); + return t; +} + +bool /* 6.5.16.1 Simple assignment Constraints */ +assigncompat(union type dst, union type src) +{ + if (dst.bits == src.bits) return 1; + if (isarith(dst) && isarith(src)) return 1; + if (dst.t == TYPTR && src.t == TYPTR) { + union type ds = typechild(dst), ss = typechild(src); + if (ds.bits == ss.bits) return 1; /* T* with different qualifiers */ + if (ss.t == TYVOID || ds.t == TYVOID) return 1; /* T* <-> void* */ + enum typetag dt = scalartypet(ds), /* handle enums */ + st = scalartypet(ss); + if (!dt || !st) return 0; /* unequal incomplete enums */ + /* plain char exception */ + if (st == TYCHAR && in_range(dt, TYUCHAR, TYSCHAR)) return 1; + if (dt == TYCHAR && in_range(st, TYUCHAR, TYSCHAR)) return 1; + } else if (dst.t == TYBOOL && src.t == TYPTR) + return 1; + return 0; +} + +enum typetag +intpromote(enum typetag t) +{ + static int intisshort = -1; + if (intisshort < 0) intisshort = targ_primsizes[TYINT] == targ_primsizes[TYSHORT]; + if (intisshort && t == TYUSHORT) return TYUINT; + return t < TYINT ? TYINT : t; +} + +union type /* 6.3.1.8 Usual arithmetic conversions */ +cvtarith(union type a, union type b) +{ + const union type none = {0}; + + if (!isarith(a) || !isarith(b)) return none; + if (a.t == TYENUM) a = typechild(a); + if (b.t == TYENUM) b = typechild(b); + if (isflt(a) || isflt(b)) { + /* when one type is float, choose type with greatest rank */ + /* enumeration order of type tags reflects arithmetic type rank */ + return a.t > b.t ? a : b; + } + a.t = intpromote(a.t); + b.t = intpromote(b.t); + if (a.bits == b.bits) return a; + + if (issigned(a) == issigned(b)) { + /* when both are integers with same signage, choose type with greatest rank */ + return a.t > b.t ? a : b; + } + /* if the signed type can represent all values of the unsigned type, + * choose it, otherwise choose its corresponding unsigned type */ + /* so long long + unsigned = long long; + * but long long + unsigned long = unsigned long long */ + if (issigned(a)) { + if (targ_primsizes[a.t] <= targ_primsizes[b.t]) + a.t += 1; /* make unsigned */ + return a.t > b.t ? a : b; + } else { + if (targ_primsizes[b.t] <= targ_primsizes[a.t]) + b.t += 1; /* make unsigned */ + return b.t > a.t ? b : a; + } +} + +/* vim:set ts=3 sw=3 expandtab: */ -- cgit v1.2.3