diff options
-rw-r--r-- | init.c | 35 | ||||
-rw-r--r-- | init.h | 2 | ||||
-rw-r--r-- | qbe.c | 11 | ||||
-rw-r--r-- | tests/initializer-replace.c | 10 | ||||
-rw-r--r-- | tests/initializer-replace.qbe | 22 |
5 files changed, 56 insertions, 24 deletions
@@ -46,29 +46,24 @@ mkinit(uint64_t start, uint64_t end, struct expr *expr) static void initadd(struct init **init, struct init *new) { - struct init *next, *sub, *last; - uint64_t offset; + struct init *old; - while (*init && new->start >= (*init)->end) - init = &(*init)->next; - next = *init; - if (next && next->start <= new->start && new->end < next->end) { - initadd(&next->subinit, new); - last = NULL; /* silence gcc, we know that next->subinit has at least one member */ - for (offset = next->start, sub = next->subinit; sub; offset = sub->end, last = sub, sub = sub->next) { - if (sub->start != offset) - return; - } - if (offset == next->end) { - *init = next->subinit; - last->next = next->next; + for (; old = *init; init = &old->next) { + if (new->start >= old->end) + continue; + /* no overlap, insert before `old` */ + if (new->end <= old->start) + break; + /* replace any initializers that `new` covers */ + if (new->end >= old->end) { + do old = old->next; + while (old && new->end >= old->end); + break; } - } else { - *init = new; - while (next && next->start < (*init)->end) - next = next->next; - (*init)->next = next; + /* `old` covers `new`, keep looking */ } + new->next = old; + *init = new; } static void @@ -1,7 +1,7 @@ struct init { uint64_t start, end; struct expr *expr; - struct init *next, *subinit; + struct init *next; }; struct scope; @@ -892,7 +892,7 @@ void funcinit(struct func *func, struct decl *d, struct init *init) { struct value *src, *dst; - uint64_t offset = 0; + uint64_t offset = 0, max = 0; size_t i; funcalloc(func, d); @@ -912,8 +912,10 @@ funcinit(struct func *func, struct decl *d, struct init *init) funcstore(func, init->expr->type, dst, src); offset = init->end; } + if (max < offset) + max = offset; } - zero(func, d->value, d->type->align, offset, d->type->size); + zero(func, d->value, d->type->align, max, d->type->size); } static void @@ -1203,12 +1205,15 @@ emitdata(struct decl *d, struct init *init) emitvalue(d->value); printf(" = align %d { ", d->align); - for (; init; offset = init->end, init = init->next) { + for (; init; init = init->next) { + if (init->start < offset) /* XXX: sub-initializer may overlap */ + continue; if (offset < init->start) printf("z %" PRIu64 ", ", init->start - offset); printf("%c ", init->expr->type->kind == TYPEARRAY ? init->expr->type->base->repr->ext : init->expr->type->repr->ext); dataitem(init->expr, init->end - init->start); fputs(", ", stdout); + offset = init->end; } assert(offset <= d->type->size); if (offset < d->type->size) diff --git a/tests/initializer-replace.c b/tests/initializer-replace.c new file mode 100644 index 0000000..8b93ef2 --- /dev/null +++ b/tests/initializer-replace.c @@ -0,0 +1,10 @@ +void f(void) { + struct { + char s[6]; + } x = { + .s[0] = 'x', + .s[4] = 'y', + .s = "hello", + .s[1] = 'a', + }; +} diff --git a/tests/initializer-replace.qbe b/tests/initializer-replace.qbe new file mode 100644 index 0000000..72ad90a --- /dev/null +++ b/tests/initializer-replace.qbe @@ -0,0 +1,22 @@ +export +function $f() { +@start.1 + %.1 =l alloc4 6 +@body.2 + %.2 =l add %.1, 0 + storeb 104, %.2 + %.3 =l add %.1, 1 + storeb 101, %.3 + %.4 =l add %.1, 2 + storeb 108, %.4 + %.5 =l add %.1, 3 + storeb 108, %.5 + %.6 =l add %.1, 4 + storeb 111, %.6 + %.7 =l add %.1, 1 + %.8 =w copy 97 + storeb %.8, %.7 + %.9 =l add %.1, 5 + storeb 0, %.9 + ret +} |