~mcf/cproc

2fd7c33ae25fb6597e4659d819529a6cbdb8cf4b — Michael Forney 1 year, 7 months ago 2d2903b
Implement bit-field initializers
4 files changed, 54 insertions(+), 34 deletions(-)

M cc.h
M decl.c
M init.c
M qbe.c
M cc.h => cc.h +2 -1
@@ 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 *);

M decl.c => decl.c +1 -1
@@ 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;

M init.c => init.c +12 -17
@@ 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;

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