aboutsummaryrefslogtreecommitdiff
path: root/bootstrap/types.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-03 20:24:47 +0200
committerlemon <lsof@mailbox.org>2022-08-03 20:24:47 +0200
commit1625c50f0c0e4b1c7ba01a5df5713efaf6dce606 (patch)
treebc5f24811413749b776964c1bbdec13a46dd9768 /bootstrap/types.c
initial
Diffstat (limited to 'bootstrap/types.c')
-rw-r--r--bootstrap/types.c208
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);
+}