From 923f6d78056f1d287565bcf491c38f654ae9f7be Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Fri, 10 May 2019 14:40:51 -0700 Subject: qbe: Fix QBE types for structs containing bit-fields --- qbe.c | 27 ++++++++++++++++++++------- test/struct-passing-bitfield.c | 7 +++++++ test/struct-passing-bitfield.qbe | 7 +++++++ 3 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 test/struct-passing-bitfield.c create mode 100644 test/struct-passing-bitfield.qbe diff --git a/qbe.c b/qbe.c index e707942..4389e27 100644 --- a/qbe.c +++ b/qbe.c @@ -1063,9 +1063,9 @@ static void emittype(struct type *t) { static uint64_t id; - struct member *m; + struct member *m, *other; struct type *sub; - uint64_t i; + uint64_t i, off; if (!t->repr || t->repr->abi.id || t->kind != TYPESTRUCT && t->kind != TYPEUNION) return; @@ -1081,18 +1081,31 @@ emittype(struct type *t) fputs("type :", stdout); emitname(&t->repr->abi); fputs(" = { ", stdout); - for (m = t->structunion.members; m; m = m->next) { - if (t->kind == TYPEUNION) + for (m = t->structunion.members, off = 0; m;) { + if (t->kind == TYPESTRUCT) { + /* look for a subsequent member with a larger storage unit */ + for (other = m->next; other && other->offset < ALIGNUP(m->offset + 1, 8); other = other->next) { + if (other->offset <= m->offset) + m = other; + } + off = m->offset + m->type->size; + } else { fputs("{ ", stdout); + } 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); - if (t->kind == TYPEUNION) - fputs(" } ", stdout); - else + if (t->kind == TYPESTRUCT) { fputs(", ", stdout); + /* skip subsequent members contained within the same storage unit */ + do m = m->next; + while (m && m->offset < off); + } else { + fputs(" } ", stdout); + m = m->next; + } } puts("}"); } diff --git a/test/struct-passing-bitfield.c b/test/struct-passing-bitfield.c new file mode 100644 index 0000000..fbda34a --- /dev/null +++ b/test/struct-passing-bitfield.c @@ -0,0 +1,7 @@ +struct s { + char x, y; + long long z : 48; +}; + +void f(struct s s) { +} diff --git a/test/struct-passing-bitfield.qbe b/test/struct-passing-bitfield.qbe new file mode 100644 index 0000000..2bd9a3c --- /dev/null +++ b/test/struct-passing-bitfield.qbe @@ -0,0 +1,7 @@ +type :s.1 = { l, } +export +function $f(:s.1 %.1) { +@start.1 +@body.2 + ret +} -- cgit v1.2.3