aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cc.h3
-rw-r--r--decl.c2
-rw-r--r--init.c29
-rw-r--r--qbe.c54
4 files changed, 54 insertions, 34 deletions
diff --git a/cc.h b/cc.h
index 80cf344..25a5fc0 100644
--- a/cc.h
+++ b/cc.h
@@ -367,6 +367,7 @@ struct expr {
struct init {
uint64_t start, end;
struct expr *expr;
+ struct bitfield bits;
struct init *next;
};
@@ -458,7 +459,7 @@ struct expr *eval(struct expr *);
/* init */
-struct init *mkinit(uint64_t, uint64_t, struct expr *);
+struct init *mkinit(uint64_t, uint64_t, struct bitfield, struct expr *);
struct init *parseinit(struct scope *, struct type *);
void stmt(struct func *, struct scope *);
diff --git a/decl.c b/decl.c
index bfe1435..12e8029 100644
--- a/decl.c
+++ b/decl.c
@@ -958,7 +958,7 @@ struct decl *stringdecl(struct expr *expr)
if (!d) {
d = mkdecl(DECLOBJECT, expr->type, QUALNONE, LINKNONE);
d->value = mkglobal("string", true);
- emitdata(d, mkinit(0, expr->type->size, expr));
+ emitdata(d, mkinit(0, expr->type->size, (struct bitfield){0}, expr));
*entry = d;
}
return d;
diff --git a/init.c b/init.c
index a968886..beba85f 100644
--- a/init.c
+++ b/init.c
@@ -24,7 +24,7 @@ struct initparser {
};
struct init *
-mkinit(uint64_t start, uint64_t end, struct expr *expr)
+mkinit(uint64_t start, uint64_t end, struct bitfield bits, struct expr *expr)
{
struct init *init;
@@ -32,6 +32,7 @@ mkinit(uint64_t start, uint64_t end, struct expr *expr)
init->start = start;
init->end = end;
init->expr = expr;
+ init->bits = bits;
init->next = NULL;
return init;
@@ -44,15 +45,15 @@ initadd(struct initparser *p, struct init *new)
init = p->last;
for (; old = *init; init = &old->next) {
- if (new->start >= old->end)
+ if (old->end * 8 - old->bits.after <= new->start * 8 + new->bits.before)
continue;
/* no overlap, insert before `old` */
- if (new->end <= old->start)
+ if (new->end * 8 - new->bits.after <= old->start * 8 + old->bits.before)
break;
/* replace any initializers that `new` covers */
- if (new->end >= old->end) {
+ if (old->end * 8 - old->bits.after <= new->end * 8 - new->bits.after) {
do old = old->next;
- while (old && new->end >= old->end);
+ while (old && old->end * 8 - old->bits.after <= new->end * 8 - new->bits.after);
break;
}
/* `old` covers `new`, keep looking */
@@ -199,12 +200,6 @@ advance(struct initparser *p)
}
}
-static bool
-isbitfield(struct member *m)
-{
- return m->bits.before || m->bits.after;
-}
-
/* 6.7.9 Initialization */
struct init *
parseinit(struct scope *s, struct type *t)
@@ -212,6 +207,7 @@ parseinit(struct scope *s, struct type *t)
struct initparser p;
struct expr *expr;
struct type *base;
+ struct bitfield bits;
p.cur = NULL;
p.sub = p.obj;
@@ -268,12 +264,11 @@ parseinit(struct scope *s, struct type *t)
focus(&p);
}
add:
- if (p.sub > p.obj) {
- t = p.sub[-1].type;
- if ((t->kind == TYPESTRUCT || t->kind == TYPEUNION) && isbitfield(p.sub[-1].mem))
- error(&tok.loc, "bit-field initializers are not yet supported");
- }
- initadd(&p, mkinit(p.sub->offset, p.sub->offset + p.sub->type->size, expr));
+ if (p.sub > p.obj && (p.sub[-1].type->kind == TYPESTRUCT || p.sub[-1].type->kind == TYPEUNION))
+ bits = p.sub[-1].mem->bits;
+ else
+ bits = (struct bitfield){0};
+ initadd(&p, mkinit(p.sub->offset, p.sub->offset + p.sub->type->size, bits, expr));
for (;;) {
if (p.sub->type->kind == TYPEARRAY && p.sub->type->incomplete)
p.sub->type->incomplete = false;
diff --git a/qbe.c b/qbe.c
index 4d24581..f12a024 100644
--- a/qbe.c
+++ b/qbe.c
@@ -920,7 +920,8 @@ zero(struct func *func, struct value *addr, int align, uint64_t offset, uint64_t
void
funcinit(struct func *func, struct decl *d, struct init *init)
{
- struct value *src, *dst;
+ struct lvalue dst;
+ struct value *src;
uint64_t offset = 0, max = 0;
size_t i;
@@ -929,17 +930,19 @@ funcinit(struct func *func, struct decl *d, struct init *init)
return;
for (; init; init = init->next) {
zero(func, d->value, d->type->align, offset, init->start);
- offset = init->start;
+ dst.bits = init->bits;
if (init->expr->kind == EXPRSTRING) {
for (i = 0; i < init->expr->string.size && i < init->end - init->start; ++i) {
- dst = funcinst(func, IADD, &iptr, d->value, mkintconst(&iptr, init->start + i));
- funcinst(func, ISTOREB, NULL, mkintconst(&i8, init->expr->string.data[i]), dst);
+ dst.addr = funcinst(func, IADD, &iptr, d->value, mkintconst(&iptr, init->start + i));
+ funcstore(func, &typechar, QUALNONE, dst, mkintconst(&i8, init->expr->string.data[i]));
}
- offset += i;
+ offset = init->start + i;
} else {
- dst = funcinst(func, IADD, &iptr, d->value, mkintconst(&iptr, init->start));
+ if (offset < init->end && (dst.bits.before || dst.bits.after))
+ zero(func, d->value, d->type->align, offset, init->end);
+ dst.addr = funcinst(func, IADD, &iptr, d->value, mkintconst(&iptr, init->start));
src = funcexpr(func, init->expr);
- funcstore(func, init->expr->type, QUALNONE, (struct lvalue){dst}, src);
+ funcstore(func, init->expr->type, QUALNONE, dst, src);
offset = init->end;
}
if (max < offset)
@@ -1222,8 +1225,8 @@ dataitem(struct expr *expr, uint64_t size)
void
emitdata(struct decl *d, struct init *init)
{
- uint64_t offset = 0;
struct init *cur;
+ uint64_t offset = 0, start, end, bits = 0;
if (!d->align)
d->align = d->type->align;
@@ -1239,7 +1242,7 @@ emitdata(struct decl *d, struct init *init)
while (init) {
cur = init;
- while (init = init->next, init && init->start < cur->end) {
+ while (init = init->next, init && init->start * 8 + init->bits.before < cur->end * 8 - cur->bits.after) {
/*
XXX: Currently, if multiple union members are
initialized, these assertions may not hold.
@@ -1249,12 +1252,33 @@ emitdata(struct decl *d, struct init *init)
assert(init->expr->kind == EXPRCONST);
cur->expr->string.data[init->start - cur->start] = init->expr->constant.i;
}
- if (offset < cur->start)
- printf("z %" PRIu64 ", ", cur->start - offset);
- printf("%c ", cur->expr->type->kind == TYPEARRAY ? cur->expr->type->base->repr->ext : cur->expr->type->repr->ext);
- dataitem(cur->expr, cur->end - cur->start);
- fputs(", ", stdout);
- offset = cur->end;
+ start = cur->start + cur->bits.before / 8;
+ end = cur->end - (cur->bits.after + 7) / 8;
+ if (offset < start && bits) {
+ printf("b %u, ", (unsigned)bits); /* unfinished byte from previous bit-field */
+ ++offset;
+ bits = 0;
+ }
+ if (offset < start)
+ printf("z %" PRIu64 ", ", start - offset);
+ if (cur->bits.before || cur->bits.after) {
+ /* XXX: little-endian specific */
+ assert(typeprop(cur->expr->type) & PROPINT);
+ assert(cur->expr->kind == EXPRCONST);
+ bits |= cur->expr->constant.i << cur->bits.before % 8;
+ for (offset = start; offset < end; ++offset, bits >>= 8)
+ printf("b %u, ", (unsigned)bits & 0xff);
+ bits &= 0xff >> cur->bits.after % 8;
+ } else {
+ printf("%c ", cur->expr->type->kind == TYPEARRAY ? cur->expr->type->base->repr->ext : cur->expr->type->repr->ext);
+ dataitem(cur->expr, cur->end - cur->start);
+ fputs(", ", stdout);
+ }
+ offset = end;
+ }
+ if (bits) {
+ printf("b %u, ", (unsigned)bits);
+ ++offset;
}
assert(offset <= d->type->size);
if (offset < d->type->size)