diff options
-rw-r--r-- | cc.h | 3 | ||||
-rw-r--r-- | decl.c | 2 | ||||
-rw-r--r-- | init.c | 29 | ||||
-rw-r--r-- | qbe.c | 54 |
4 files changed, 54 insertions, 34 deletions
@@ -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 *); @@ -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; @@ -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; @@ -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) |