aboutsummaryrefslogtreecommitdiff
path: root/bootstrap/types.c
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2022-08-04 10:07:13 +0200
committerlemon <lsof@mailbox.org>2022-08-04 10:07:13 +0200
commitc5d837d2cd9a57e453da9eaab0e41e0c185e084e (patch)
tree60539ae58df6738772f1e63e2aa58dd8002803e4 /bootstrap/types.c
parentbb1d4b4a3e51a06fb0530dfc271a97a6cd88cc73 (diff)
fold & more
Diffstat (limited to 'bootstrap/types.c')
-rw-r--r--bootstrap/types.c122
1 files changed, 122 insertions, 0 deletions
diff --git a/bootstrap/types.c b/bootstrap/types.c
index 8e735d0..401f9e6 100644
--- a/bootstrap/types.c
+++ b/bootstrap/types.c
@@ -206,3 +206,125 @@ visittypes(void (*visitor)(const struct type *, void *), void *arg) {
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;
+}