aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--qbe.c79
-rw-r--r--tests/struct-passing.qbe3
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