~mcf/cproc

4acc9078f1572a611e5cf5048ed57ea6498d0bb9 — Michael Forney 2 years ago 543d67d
Start to handle overlapping initializers
5 files changed, 56 insertions(+), 24 deletions(-)

M init.c
M init.h
M qbe.c
A tests/initializer-replace.c
A tests/initializer-replace.qbe
M init.c => init.c +15 -20
@@ 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

M init.h => init.h +1 -1
@@ 1,7 1,7 @@
struct init {
	uint64_t start, end;
	struct expr *expr;
	struct init *next, *subinit;
	struct init *next;
};

struct scope;

M qbe.c => qbe.c +8 -3
@@ 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)

A tests/initializer-replace.c => tests/initializer-replace.c +10 -0
@@ 0,0 1,10 @@
void f(void) {
	struct {
		char s[6];
	} x = {
		.s[0] = 'x',
		.s[4] = 'y',
		.s = "hello",
		.s[1] = 'a',
	};
}

A tests/initializer-replace.qbe => tests/initializer-replace.qbe +22 -0
@@ 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
}