#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); } const struct type * constify(const struct type *ty) { struct type ty2 = *ty; if (ty->konst) return ty; if (ty2.t != TYfn) ty2.konst = 1; return interntype(ty2); } const struct type * unconstify(const struct type *ty) { struct type ty2 = *ty; if (!ty->konst) return ty; ty2.konst = 0; return interntype(ty2); } const struct type * constifychild(const struct type *ty) { struct type ty2 = *ty; const struct type *child = constify(ty->child); if (child == ty->child) return ty; ty2.child = child; return interntype(ty2); } static const struct type * arraydecay(const struct type *ty) { struct type ty2 = *ty; if (ty->t != TYarr) return ty; ty2.t = TYptr; return interntype(ty2); } int numtype2rank(const struct type *a) { if (a->t == TYint) { if (a->size < g_targ.intsize || a == ty_int) return 0; if (a == ty_uint) return 1; if (a == ty_i32) return 2; if (a == ty_u32) return 3; if (a == ty_i64) return 4; if (a == ty_u64) return 5; } if (a == ty_f32) return 6; if (a == ty_f64) return 7; return -1; } const struct type * rank2numtype(int r) { static const struct type **types[] = { &ty_int, &ty_uint, &ty_i32, &ty_u32, &ty_i64, &ty_u64, &ty_f32, &ty_f64, }; assert(r >= 0 && r < ARRAY_LENGTH(types)); return *types[r]; } bool isnumtype(const struct type *a) { return a->t == TYint || a->t == TYfloat; } // peer type resolution const struct type * typeof2(const struct type *a, const struct type *b) { if (isnumtype(a) && isnumtype(b)) { int ra = numtype2rank(a), rb = numtype2rank(b); return rank2numtype(MAX(ra, rb)); } if (a == b) return a; if (unconstify(a) == b) return a; if (a == unconstify(b)) return b; if (a->t == TYarr && b->t == TYarr) a = arraydecay(a); if (a->t == TYptr && b->t == TYarr) b = arraydecay(b); if (a->t == TYarr && b->t == TYptr) a = arraydecay(a); if (a->t == TYptr && b->t == TYptr) { bool akonst = a->child->konst, bkonst = b->child->konst; const struct type *uac = unconstify(a->child), *ubc = unconstify(b->child); if (uac == ubc) return akonst ? a : b; if (uac == ty_void) { if (bkonst && !akonst) return constifychild(a); return a; } if (ubc == ty_void) { if (akonst && !bkonst) return constifychild(b); return b; } if (uac == ty_u8) { if (bkonst && !akonst) return constifychild(a); return a; } if (ubc == ty_u8) { if (akonst && !bkonst) return constifychild(b); return b; } } return NULL; }