commit 06e663dbf4809255f74e42d88abbc7a55c289787
parent cefb2f150fc64a1a0b536d31db937803ec565c52
Author: Drew DeVault <sir@cmpwn.com>
Date: Fri, 15 Jan 2021 17:12:42 -0500
gen: implement aggregate type copy
Diffstat:
2 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/src/gen.c b/src/gen.c
@@ -76,9 +76,10 @@ binding_alloc(struct gen_context *ctx, const struct scope_object *obj,
binding->object = obj;
binding->next = ctx->bindings;
ctx->bindings = binding;
- pushc(ctx->current, "alloc binding: %s -> %%%s, =%c, indirect: %d",
+ pushc(ctx->current, "alloc binding: %s -> %%%s, =%c (%s), indirect: %d",
obj->ident.name, binding->name,
- (char)val->type->stype, val->indirect);
+ (char)val->type->stype, val->type->name,
+ val->indirect);
return binding;
}
@@ -144,7 +145,8 @@ gen_copy(struct gen_context *ctx,
const struct qbe_value *src)
{
assert(!dest->indirect && !src->indirect);
- const struct qbe_field *field = &dest->type->fields;
+ pushc(ctx->current, "begin gen_copy for type %s (is_union? %d)",
+ dest->type->name, dest->type->is_union);
struct qbe_value temp = {0}, destp = {0}, srcp = {0}, size = {0};
gen_temp(ctx, &temp, &qbe_long, "temp.%d");
@@ -153,10 +155,22 @@ gen_copy(struct gen_context *ctx,
pushi(ctx->current, &destp, Q_COPY, dest, NULL);
pushi(ctx->current, &srcp, Q_COPY, src, NULL);
+ const struct qbe_field *field = &dest->type->fields;
+ if (dest->type->is_union) {
+ size_t max = 0;
+ for (const struct qbe_field *f = &dest->type->fields;
+ f; f = f->next) {
+ if (f->type->size > max) {
+ field = f;
+ }
+ }
+ }
+
while (field) {
temp.type = field->type;
for (size_t i = field->count; i > 0; --i) {
+ struct qbe_value a, b;
switch (field->type->stype) {
case Q_BYTE:
case Q_HALF:
@@ -164,8 +178,8 @@ gen_copy(struct gen_context *ctx,
case Q_LONG:
case Q_SINGLE:
case Q_DOUBLE:
- // XXX: This may be broken for unsigned types b
- // and h
+ // TODO: This might be broken for unsigned types
+ // b and h
pushi(ctx->current, &temp,
load_for_type(field->type->stype, true),
&srcp, NULL);
@@ -174,12 +188,16 @@ gen_copy(struct gen_context *ctx,
&temp, &destp, NULL);
break;
case Q__AGGREGATE:
- assert(0); // TODO
+ a = destp, b = srcp;
+ a.type = field->type;
+ b.type = field->type;
+ gen_copy(ctx, &a, &b);
+ break;
case Q__VOID:
assert(0); // Invariant
}
- if (i > 1) {
+ if (!dest->type->is_union) {
assert(field->type->size != 0);
constl(&size, field->type->size);
pushi(ctx->current, &destp, Q_ADD, &destp, &size, NULL);
@@ -188,7 +206,14 @@ gen_copy(struct gen_context *ctx,
}
field = field->next;
+
+ if (dest->type->is_union) {
+ // We only copy the largest field in this case
+ break;
+ }
}
+
+ pushc(ctx->current, "end gen_copy for type %s", dest->type->name);
}
static void
diff --git a/src/qtype.c b/src/qtype.c
@@ -106,10 +106,11 @@ tagged_qtype(struct gen_context *ctx, const struct type *type)
def->name = name;
def->exported = false;
def->type.stype = Q__AGGREGATE;
- def->type.base = type;
+ def->type.base = NULL;
def->type.name = name;
def->type.align = SIZE_UNDEFINED;
def->type.is_union = true;
+ def->type.size = type->size - builtin_type_size.size;
struct qbe_field *field = &def->type.fields;
for (const struct type_tagged_union *tu = &type->tagged;
@@ -154,11 +155,11 @@ lookup_aggregate(struct gen_context *ctx, const struct type *type)
struct qbe_def *def = xcalloc(1, sizeof(struct qbe_def));
def->kind = Q_TYPE;
def->name = name;
- def->exported = false;
def->type.stype = Q__AGGREGATE;
def->type.base = type;
def->type.name = name;
def->type.align = SIZE_UNDEFINED;
+ def->type.size = type->size;
struct qbe_field *field = &def->type.fields;
switch (type->storage) {