diff options
| -rw-r--r-- | decl.c | 79 | ||||
| -rw-r--r-- | type.h | 6 | ||||
| -rw-r--r-- | util.h | 3 | 
3 files changed, 65 insertions, 23 deletions
| @@ -60,6 +60,7 @@ enum funcspec {  struct structbuilder {  	struct type *type;  	struct member **last; +	int bits;  /* number of bits remaining in the last byte */  };  struct decl * @@ -206,6 +207,7 @@ tagspec(struct scope *s)  	case TYPEUNION:  		b.type = t;  		b.last = &t->structunion.members; +		b.bits = 0;  		do structdecl(s, &b);  		while (tok.kind != TRBRACE);  		next(); @@ -640,29 +642,59 @@ paramdecl(struct scope *s, struct param *params)  }  static void -addmember(struct structbuilder *b, struct type *mt, char *name, int align) +addmember(struct structbuilder *b, struct type *mt, char *name, int align, uint64_t width)  {  	struct type *t = b->type;  	struct member *m; - -	m = xmalloc(sizeof(*m)); -	m->type = mt; -	m->name = name; -	m->next = NULL; -	*b->last = m; -	b->last = &m->next; +	size_t end;  	assert(mt->align > 0); -	if (align < mt->align) +	if (name || width == -1) { +		m = xmalloc(sizeof(*m)); +		m->type = mt; +		m->name = name; +		m->next = NULL; +		*b->last = m; +		b->last = &m->next; +	} +	if (width == -1) { +		m->bits.before = 0; +		m->bits.after = 0; +		if (align < mt->align) +			align = mt->align; +		t->size = ALIGNUP(t->size, align); +		if (t->kind == TYPESTRUCT) { +			m->offset = t->size; +			t->size += mt->size; +		} else { +			m->offset = 0; +			if (t->size < mt->size) +				t->size = mt->size; +		} +	} else {  /* bit-field */ +		if (!(typeprop(mt) & PROPINT)) +			error(&tok.loc, "bit-field has invalid type"); +		if (align) +			error(&tok.loc, "alignment specified for bit-field"); +		if (!width && name) +			error(&tok.loc, "bit-field with zero width must not have declarator"); +		if (width > mt->size * 8) +			error(&tok.loc, "bit-field exceeds width of underlying type"); +		/* calculate end of the storage-unit for this bit-field */ +		end = ALIGNUP(t->size, mt->size); +		if (!width || width > (end - t->size) * 8 + b->bits) { +			/* no room, allocate a new storage-unit */ +			t->size = end; +			b->bits = 0; +		} +		if (width) { +			m->offset = ALIGNDOWN(t->size - !!b->bits, mt->size); +			m->bits.before = (t->size - m->offset) * 8 - b->bits; +			m->bits.after = mt->size * 8 - width - m->bits.before; +			t->size += (width - b->bits + 7) / 8; +			b->bits = m->bits.after % 8; +		}  		align = mt->align; -	t->size = ALIGNUP(t->size, align); -	if (t->kind == TYPESTRUCT) { -		m->offset = t->size; -		t->size += mt->size; -	} else { -		m->offset = 0; -		if (t->size < mt->size) -			t->size = mt->size;  	}  	if (t->align < align)  		t->align = align; @@ -673,6 +705,7 @@ structdecl(struct scope *s, struct structbuilder *b)  {  	struct type *base, *mt;  	char *name; +	uint64_t width;  	int align;  	base = declspecs(s, NULL, NULL, &align); @@ -682,16 +715,18 @@ structdecl(struct scope *s, struct structbuilder *b)  		if ((base->kind != TYPESTRUCT && base->kind != TYPEUNION) || base->structunion.tag)  			error(&tok.loc, "struct declaration must declare at least one member");  		next(); -		addmember(b, base, NULL, align); +		addmember(b, base, NULL, align, -1);  		return;  	}  	for (;;) { -		if (tok.kind != TCOLON) { +		if (consume(TCOLON)) { +			width = intconstexpr(s, false); +			addmember(b, base, NULL, 0, width); +		} else {  			mt = declarator(s, base, &name, false); -			addmember(b, mt, name, align); +			width = consume(TCOLON) ? intconstexpr(s, false) : -1; +			addmember(b, mt, name, align, width);  		} -		if (tok.kind == TCOLON) -			error(&tok.loc, "bit-fields are not yet supported");  		if (tok.kind == TSEMICOLON)  			break;  		expect(TCOMMA, "or ';' after declarator"); @@ -41,10 +41,16 @@ struct param {  	struct param *next;  }; +struct bitfield { +	short before;  /* number of bits in the storage unit before the bit-field */ +	short after;   /* number of bits in the storage unit after the bit-field */ +}; +  struct member {  	char *name;  	struct type *type;  	uint64_t offset; +	struct bitfield bits;  	struct member *next;  }; @@ -10,7 +10,8 @@ struct array {  extern char *argv0;  #define LEN(a) (sizeof(a) / sizeof((a)[0])) -#define ALIGNUP(x, n) (((x) + (n) - 1) & ~((n) - 1)) +#define ALIGNDOWN(x, n) ((x) & -(n)) +#define ALIGNUP(x, n) ALIGNDOWN((x) + (n) - 1, n)  void warn(const char *, ...);  _Noreturn void fatal(const char *fmt, ...); | 
