From 1d47a3f01bd5ea43ce798fa6624b65dfdc6a37c0 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Wed, 20 Feb 2019 13:22:44 -0800 Subject: Fix definitions for nested structs The QBE documentation suggested that the subtypes in an aggregate must be simple types, but they can actually be any type (this is necessary for getting the alignment and padding right between fields adjacent to the nested struct). --- qbe.c | 79 +++++++++++++++++++++++------------------------- tests/struct-passing.qbe | 3 +- 2 files changed, 39 insertions(+), 43 deletions(-) diff --git a/qbe.c b/qbe.c index 29f005b..d3d14f2 100644 --- a/qbe.c +++ b/qbe.c @@ -966,61 +966,56 @@ emitvalue(struct value *v) } static void -aggr(struct type *t) +emitrepr(struct representation *r, bool abi, bool ext) { - uint64_t i; - struct member *m; - - switch (t->kind) { - case TYPEARRAY: - if (typeprop(t->base) & PROPAGGR) { - for (i = 0; i < t->array.length; ++i) - aggr(t->base); - } else { - printf("%c %" PRIu64 ", ", t->base->repr->ext, t->array.length); - } - break; - case TYPESTRUCT: - for (m = t->structunion.members; m; m = m->next) { - if (typeprop(m->type) & PROPAGGR) - aggr(m->type); - else - printf("%c, ", m->type->repr->ext); - } - break; - default: - fatal("internal error; not an aggregate type"); + if (abi && r->abi.id) { + putchar(':'); + emitname(&r->abi); + } else if (ext) { + putchar(r->ext); + } else { + putchar(r->base); } } +/* XXX: need to consider _Alignas on struct members */ +/* XXX: this might not be right for something like +union { + struct { long long x; double y; }; + struct { double z; long long w; }; +}; +*/ static void emittype(struct type *t) { static uint64_t id; + struct member *m; + struct type *sub; + uint64_t i; - if (!t->repr || t->repr->abi.id || !(typeprop(t) & PROPAGGR)) + if (!t->repr || t->repr->abi.id || t->kind != TYPESTRUCT && t->kind != TYPEUNION) return; t->repr = xmalloc(sizeof(*t->repr)); t->repr->base = 'l'; - if (t->kind == TYPESTRUCT || t->kind == TYPEUNION) - t->repr->abi.str = t->structunion.tag; + t->repr->abi.str = t->structunion.tag; t->repr->abi.id = ++id; + for (m = t->structunion.members; m; m = m->next) { + for (sub = m->type; sub->kind == TYPEARRAY; sub = sub->base) + ; + emittype(sub); + } fputs("type :", stdout); emitname(&t->repr->abi); fputs(" = { ", stdout); - aggr(t); - puts("}"); -} - -static void -emitrepr(struct representation *r, bool abi) -{ - if (abi && r->abi.id) { - putchar(':'); - emitname(&r->abi); - } else { - putchar(r->base); + for (m = t->structunion.members; m && t->kind == TYPESTRUCT; m = m->next) { + for (i = 1, sub = m->type; sub->kind == TYPEARRAY; sub = sub->base) + i *= sub->array.length; + emitrepr(sub->repr, true, true); + if (i > 1) + printf(" %" PRIu64, i); + fputs(", ", stdout); } + puts("}"); } static void @@ -1033,7 +1028,7 @@ emitinst(struct instruction *inst) if (instdesc[inst->kind].ret && inst->res.kind) { emitvalue(&inst->res); fputs(" =", stdout); - emitrepr(inst->res.repr, inst->kind == ICALL); + emitrepr(inst->res.repr, inst->kind == ICALL, false); putchar(' '); } fputs(instdesc[inst->kind].str, stdout); @@ -1046,7 +1041,7 @@ emitinst(struct instruction *inst) if (arg != &inst->arg[1]) fputs(", ", stdout); if ((*arg)->kind != VALELLIPSIS) { - emitrepr((*arg)->repr, true); + emitrepr((*arg)->repr, true, false); putchar(' '); } emitvalue(*arg); @@ -1096,14 +1091,14 @@ emitfunc(struct function *f, bool global) puts("export"); fputs("function ", stdout); if (f->type->base != &typevoid) { - emitrepr(f->type->base->repr, true); + emitrepr(f->type->base->repr, true, false); putchar(' '); } printf("$%s(", f->name); for (p = f->type->func.params; p; p = p->next) { if (p != f->type->func.params) fputs(", ", stdout); - emitrepr(p->type->repr, true); + emitrepr(p->type->repr, true, false); putchar(' '); emitvalue(p->value); } diff --git a/tests/struct-passing.qbe b/tests/struct-passing.qbe index a01bda2..07bd483 100644 --- a/tests/struct-passing.qbe +++ b/tests/struct-passing.qbe @@ -1,4 +1,5 @@ -type :s.1 = { w, b 3, h, b 3, h, d, } +type :.2 = { b 3, h, } +type :s.1 = { w, :.2 2, d, } export function $f(:s.1 %.1) { @start.1 -- cgit v1.2.3