diff options
| author | 2022-08-03 20:24:47 +0200 | |
|---|---|---|
| committer | 2022-08-03 20:24:47 +0200 | |
| commit | 1625c50f0c0e4b1c7ba01a5df5713efaf6dce606 (patch) | |
| tree | bc5f24811413749b776964c1bbdec13a46dd9768 /bootstrap/types.c | |
initial
Diffstat (limited to 'bootstrap/types.c')
| -rw-r--r-- | bootstrap/types.c | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/bootstrap/types.c b/bootstrap/types.c new file mode 100644 index 0000000..8e735d0 --- /dev/null +++ b/bootstrap/types.c @@ -0,0 +1,208 @@ +#include "all.h" + +// set of interned types +static struct { + int size, nbuckets; + struct typesnode { + struct typesnode *next; + u32 hash; + const struct type ty; + } **buckets; + char *tags; +} types; + +void +inittypes() { + for (int i = 0; i < types.nbuckets; ++i) { + for (struct typesnode *n = types.buckets[i], *next; n; n = next) { + next = n->next; + free(n); + } + } + if (types.buckets) + free(types.buckets); + + types.size = 0; + types.buckets = calloc(types.nbuckets = 16, sizeof(struct typesnode *)); +} + +static u32 +hashtype(const struct type *ty) { + u32 h = 0; + h = jkhashv(h, ty->t); + h = jkhashv(h, ty->size); + h = jkhashv(h, ty->align); + h = jkhashv(h, ty->konst); + switch (ty->t) { + case TYvoid: case TYbool: case TYfloat: + break; + case TYint: + h = jkhashv(h, ty->int_signed); + break; + case TYptr: + case TYslice: + h = jkhashv(h, ty->child); + break; + case TYarr: + h = jkhashv(h, ty->child); + h = jkhashv(h, ty->length); + break; + case TYfn: + h = jkhashv(h, ty->fn.retty); + h = jkhashv(h, ty->fn.params.n); + for (int i = 0; i < ty->fn.params.n; ++i) + h = jkhashv(h, ty->fn.params.d[i]); + + } + return h; +} + +bool +typeeql(const struct type *lhs, const struct type *rhs) { + if (lhs == rhs) + return 1; + if (lhs->t != rhs->t || lhs->size != rhs->size + || lhs->align != rhs->align + || lhs->konst != rhs->konst) + return 0; + switch (lhs->t) { + case TYvoid: case TYbool: case TYfloat: + return 1; + case TYint: + return lhs->int_signed == rhs->int_signed; + case TYptr: + case TYslice: + return typeeql(lhs->child, rhs->child); + case TYarr: + return lhs->length == rhs->length && typeeql(lhs->child, rhs->child); + case TYfn: + if (lhs->length != rhs->length) + return 0; + for (int i = 0; i < lhs->fn.params.n; ++i) + if (!typeeql(lhs->fn.params.d[i], rhs->fn.params.d[i])) + return 0; + return 1; + } + assert(0 && "unreachable"); +} + +static const struct type * +typesfind(const struct type *key) { + u32 hash = hashtype(key); + size_t idx = hash & (types.nbuckets - 1); + for (struct typesnode *n = types.buckets[idx]; n; n = n->next) { + if (n->hash == hash && typeeql(key, &n->ty)) + return &n->ty; + } + return NULL; +} + +// !!Invariant: type should not be in the types set! +static const struct type * +typesput(const struct type *key) { + u32 hash = hashtype(key); + size_t idx = hash & (types.nbuckets - 1); + struct typesnode *n = xmalloc(sizeof *n); + types.size++; + n->hash = hash; + *(struct type *)&n->ty = *key; + n->next = types.buckets[idx]; + types.buckets[idx] = n; + return &n->ty; +} + +const struct type * +interntype(struct type ty) { + if (!ty.align) + ty.align = ty.size; + const struct type *ty2 = typesfind(&ty); + if (ty2) + return ty2; + ty2 = typesput(&ty); + assert(ty2); + return ty2; +} + +bool +completetype(const struct type *ty) { + if (ty->t == TYvoid) + return 0; + if (ty->t == TYfn) + return 0; + if (ty->t == TYarr && ty->length < 0) + return 0; + return 1; +} + +const struct type + *ty_void, *ty_bool, *ty_f32, *ty_f64, + *ty_i8, *ty_u8, *ty_i16, *ty_u16, + *ty_i32, *ty_u32, *ty_i64, *ty_u64, + *ty_int, *ty_uint, *ty_isize, *ty_usize, + *ty_iptrint, *ty_uptrint, *ty_c_int, *ty_c_uint, + *ty_c_char, *ty_c_schar, *ty_c_uchar, *ty_c_short, + *ty_c_ushort, *ty_c_long, *ty_c_ulong, *ty_c_llong, + *ty_c_ullong; + +void +putprimtypes(struct env *env) { + const struct targ t = g_targ; + const struct { + const char *name; + const struct type **gty; + struct type ty; + } types[] = { + /* name, t, size, align (0 -> = size), ... */ + {"void", &ty_void, {TYvoid, 0, 1}}, + {"bool", &ty_bool, {TYbool, 1}}, + {"f32", &ty_f32, {TYfloat, 4, t.f32align}}, + {"f64", &ty_f64, {TYfloat, 8, t.f64align}}, +#define IS .int_signed = 1 +#define IU .int_signed = 0 + {"i8", &ty_i8, {TYint, 1, 1, IS}}, + {"u8", &ty_u8, {TYint, 1, 1, IU}}, + {"i16", &ty_i16, {TYint, 2, 2, IS}}, + {"u16", &ty_u16, {TYint, 2, 2, IU}}, + {"i32", &ty_i32, {TYint, 4, 4, IS}}, + {"u32", &ty_u32, {TYint, 4, 4, IU}}, + {"i64", &ty_i64, {TYint, 8, 8, IS}}, + {"u64", &ty_u64, {TYint, 8, 8, IU}}, + {"int", &ty_int, {TYint, t.intsize, IS}}, + {"uint", &ty_uint, {TYint, t.intsize, IU}}, + {"isize", &ty_isize, {TYint, t.sizesize, IS}}, + {"usize", &ty_usize, {TYint, t.sizesize, IU}}, + {"iptrint", &ty_iptrint, {TYint, t.ptrsize, IS}}, + {"uptrint", &ty_uptrint, {TYint, t.ptrsize, IU}}, + {"c_int", &ty_c_int, {TYint, t.intsize, IS}}, + {"c_uint", &ty_c_uint, {TYint, t.intsize, IU}}, + {"c_char", &ty_c_char, {TYint, 1, .int_signed = t.charsigned}}, + {"c_schar", &ty_c_schar, {TYint, 1, IS}}, + {"c_uchar", &ty_c_uchar, {TYint, 1, IU}}, + {"c_short", &ty_c_short, {TYint, 2, IS}}, + {"c_ushort", &ty_c_ushort, {TYint, 2, IU}}, + {"c_long", &ty_c_long, {TYint, t.longsize, IS}}, + {"c_ulong", &ty_c_ulong, {TYint, t.longsize, IU}}, + {"c_llong", &ty_c_llong, {TYint, t.llongsize, IS}}, + {"c_ullong", &ty_c_ullong, {TYint, t.llongsize, IU}}, +#undef IS +#undef IU + }; + + for (int i = 0; i < ARRAY_LENGTH(types); ++i) { + struct decl decl = { + Dtype, + types[i].name, + .ty = interntype(types[i].ty), + }; + bool ok = envput(env, &decl); + *types[i].gty = decl.ty; + assert(ok && "envput prim type"); + } +} + +void +visittypes(void (*visitor)(const struct type *, void *), void *arg) { + for (int i = 0; i < types.nbuckets; ++i) + for (struct typesnode *n = types.buckets[i]; n; n = n->next) + visitor(&n->ty, arg); +} |