harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit 4bd3edc59b5f4defe8e3fddcd0ddc4bf8bc2bf24
parent d4bd9749de1ea29690b9f9d4d9c6a04c69da05bc
Author: Drew DeVault <sir@cmpwn.com>
Date:   Fri,  6 Aug 2021 14:38:20 +0200

gen: implement cast-to-tagged case 2

Signed-off-by: Drew DeVault <sir@cmpwn.com>

Diffstat:
Minclude/type_store.h | 4++++
Msrc/gen.c | 30++++++++++++++++++++++++++++--
Msrc/type_store.c | 34++++++++++++++++++++++++++++++++++
Mtests/910-tagged.ha | 12+++++++++++-
4 files changed, 77 insertions(+), 3 deletions(-)

diff --git a/include/type_store.h b/include/type_store.h @@ -47,6 +47,10 @@ const struct type *type_store_lookup_alias(struct type_store *store, const struct type *type_store_lookup_tagged(struct type_store *store, struct type_tagged_union *tags); +// Returns a (non-tagged) union of the members of a tagged union type +const struct type *type_store_tagged_to_union( + struct type_store *store, const struct type *tagged); + const struct type *type_store_lookup_tuple(struct type_store *store, struct type_tuple *values); diff --git a/src/gen.c b/src/gen.c @@ -476,8 +476,34 @@ gen_expr_cast_at(struct gen_context *ctx, gen_expr_at(ctx, expr->cast.value, out2); return; } else if (!subtype) { - // Case 2: alignment mismatch, so (much) more work is required. - assert(0); // TODO + // Case 2: like case 1, but with an alignment mismatch; more + // work is required. + struct gen_value value = gen_expr(ctx, expr->cast.value); + struct qbe_value qval = mkqval(ctx, &value); + struct qbe_value qout = mkqval(ctx, &out); + struct qbe_value tag = mkqtmp(ctx, + qtype_lookup(ctx, &builtin_type_uint, false), "tag.%d"); + enum qbe_instr load = load_for_type(ctx, &builtin_type_uint); + enum qbe_instr store = store_for_type(ctx, &builtin_type_uint); + pushi(ctx->current, &tag, load, &qval, NULL); + pushi(ctx->current, NULL, store, &tag, &qout, NULL); + if (to->size == builtin_type_uint.size || + from->size == builtin_type_uint.size) { + // No data area to copy + return; + } + + const struct type *innertype = type_store_tagged_to_union( + ctx->store, type_dealias(to)); + struct gen_value iout = mktemp(ctx, innertype, ".%d"); + struct gen_value ival = mktemp(ctx, innertype, ".%d"); + struct qbe_value qiout = mkqval(ctx, &iout); + struct qbe_value qival = mkqval(ctx, &ival); + struct qbe_value offs = constl(to->align); + pushi(ctx->current, &qiout, Q_ADD, &qout, &offs, NULL); + offs = constl(from->align); + pushi(ctx->current, &qival, Q_ADD, &qval, &offs, NULL); + gen_copy_aligned(ctx, iout, ival); return; } diff --git a/src/type_store.c b/src/type_store.c @@ -847,6 +847,40 @@ type_store_lookup_tagged(struct type_store *store, } const struct type * +type_store_tagged_to_union(struct type_store *store, const struct type *tagged) +{ + assert(tagged->storage == STORAGE_TAGGED); + struct type type = { + .storage = STORAGE_UNION, + .flags = tagged->flags, + }; + struct struct_field **next = &type.struct_union.fields; + for (const struct type_tagged_union *tu = &tagged->tagged; + tu; tu = tu->next) { + if (tu->type->size == 0) { + continue; + } + assert(tu->type->size != SIZE_UNDEFINED); + + if (tu->type->size > type.size) { + type.size = tu->type->size; + } + if (tu->type->align > type.align) { + type.align = tu->type->align; + } + + struct struct_field *sf = + xcalloc(1, sizeof(struct struct_field)); + sf->name = "unnamed"; + sf->type = tu->type; + sf->next = *next, *next = sf; + next = &sf->next; + } + type.struct_union.c_compat = true; // XXX: Unsure about this + return type_store_lookup_type(store, &type); +} + +const struct type * type_store_lookup_tuple(struct type_store *store, struct type_tuple *values) { struct type type = { diff --git a/tests/910-tagged.ha b/tests/910-tagged.ha @@ -50,7 +50,17 @@ fn subsetcast() void = { assert(p.data.z == 1337z); // Disjoint alignment - // TODO + let x: (int | void) = 1337; + let y: (size | int | void) = x; + let p = &y: *struct { + tag: uint, + data: union { + z: size, + i: int, + }, + }; + assert(p.tag == 1737287038); + assert(p.data.i == 1337); }; export fn main() int = {