harec

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

commit 9c2ad2b58a6cdb6012fb559a90a45c681390e85a
parent 727c5de862700a15dabb3863167bbbf6ddecadd7
Author: Drew DeVault <sir@cmpwn.com>
Date:   Sat, 13 Feb 2021 11:32:43 -0500

gen: more casts between alignment-distinct taggeds

Diffstat:
Msrc/gen.c | 30+++++++++++++++++++++++++++++-
Mtests/18-match.ha | 3+++
2 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/src/gen.c b/src/gen.c @@ -1085,7 +1085,35 @@ gen_cast_to_tagged(struct gen_context *ctx, struct qbe_value tag = {0}, ptr = {0}, offs = {0}; constl(&offs, expr->result->align); - if (!subtype) { + if (!subtype && type_dealias(from)->storage == TYPE_STORAGE_TAGGED + && from->align != tagged->align + && type_dealias(tagged)->size != builtin_type_uint.size + && type_dealias(from)->size != builtin_type_uint.size) { + // If the alignment differs, we can't use a straight-up copy + struct qbe_value src = {0}, dest = {0}; + pushc(ctx->current, "to_tagged; converting incompatible"); + alloc_temp(ctx, &src, from, "to_tagged.from.%d"); + qval_deref(&src); + gen_expression(ctx, expr->cast.value, &src); + + gen_temp(ctx, &dest, + qtype_for_type(ctx, tagged, false), "to_tagged.to.%d"); + pushi(ctx->current, &dest, Q_COPY, out, NULL); + + gen_temp(ctx, &tag, &qbe_word, "to_tagged.tag.%d"); + pushi(ctx->current, &tag, Q_LOADUW, &src, NULL); + pushi(ctx->current, NULL, Q_STOREW, &tag, &dest, NULL); + + constl(&offs, tagged->align); + pushi(ctx->current, &dest, Q_ADD, &dest, &offs, NULL); + constl(&offs, from->align); + pushi(ctx->current, &src, Q_ADD, &src, &offs, NULL); + + dest.type = dest.type->fields.next->type; + src.type = src.type->fields.next->type; + gen_copy(ctx, &dest, &src); + return; + } else if (!subtype) { pushc(ctx->current, "to_tagged; no subtype"); alloc_temp(ctx, &ptr, tagged, "to_tagged.from.%d"); qval_deref(&ptr); diff --git a/tests/18-match.ha b/tests/18-match.ha @@ -190,6 +190,9 @@ export fn alignment_conversion() void = { y: align_4 => assert(y as int == 1234), * => abort(), }; + let y: align_4 = 4321i; + x = y: align_8; + assert(x as int == 4321); }; export fn main() void = {