diff --git a/chibicc.h b/chibicc.h index 35ada955e13ba3b45090e05b573d1d8d3fb07834..8f6e637591c8669ab50a626d3e519321398f3ad6 100644 --- a/chibicc.h +++ b/chibicc.h @@ -158,6 +158,7 @@ typedef enum { struct Type { TypeKind kind; int size; // sizeof() value + int align; // alignment // Pointer-to or array-of type. We intentionally use the same member // to represent pointer/array duality in C. @@ -207,3 +208,4 @@ void add_type(Node *node); // void codegen(Obj *prog, FILE *out); +int align_to(int n, int align); diff --git a/codegen.c b/codegen.c index b9ebd44ce2058016e9924309de0368a7624287fa..3c002f0a8e324830a41c6b99ae236b0737250a71 100644 --- a/codegen.c +++ b/codegen.c @@ -34,7 +34,7 @@ static void pop(char *arg) { // Round up `n` to the nearest multiple of `align`. For instance, // align_to(5, 8) returns 8 and align_to(11, 8) returns 16. -static int align_to(int n, int align) { +int align_to(int n, int align) { return (n + align - 1) / align * align; } diff --git a/parse.c b/parse.c index e5b7d071e9d1bd8baf53d4ddef73cea6ed7266a6..57caf7179167d2638697f9ec94657f7c8141168c 100644 --- a/parse.c +++ b/parse.c @@ -591,14 +591,19 @@ static Type *struct_decl(Token **rest, Token *tok) { Type *ty = calloc(1, sizeof(Type)); ty->kind = TY_STRUCT; struct_members(rest, tok, ty); + ty->align = 1; // Assign offsets within the struct to members. int offset = 0; for (Member *mem = ty->members; mem; mem = mem->next) { + offset = align_to(offset, mem->ty->align); mem->offset = offset; offset += mem->ty->size; + + if (ty->align < mem->ty->align) + ty->align = mem->ty->align; } - ty->size = offset; + ty->size = align_to(offset, ty->align); return ty; } diff --git a/test/struct.c b/test/struct.c index b0b198f50c40ec99aa064a1714de9997f5234923..2877951ac548fa4d7f8980f2ae5178f21e0fc66c 100644 --- a/test/struct.c +++ b/test/struct.c @@ -24,8 +24,9 @@ int main() { ASSERT(32, ({ struct {int a;} x[4]; sizeof(x); })); ASSERT(48, ({ struct {int a[3];} x[2]; sizeof(x); })); ASSERT(2, ({ struct {char a; char b;} x; sizeof(x); })); - ASSERT(9, ({ struct {char a; int b;} x; sizeof(x); })); ASSERT(0, ({ struct {} x; sizeof(x); })); + ASSERT(16, ({ struct {char a; int b;} x; sizeof(x); })); + ASSERT(16, ({ struct {int a; char b;} x; sizeof(x); })); printf("OK\n"); return 0; diff --git a/type.c b/type.c index eb3661086e77528bc441ca1cf4e0e65f0fee2da8..bc2474038058ccfe6dc5d5c0214cf0bcb5e5dd99 100644 --- a/type.c +++ b/type.c @@ -1,7 +1,15 @@ #include "chibicc.h" -Type *ty_char = &(Type){TY_CHAR, 1}; -Type *ty_int = &(Type){TY_INT, 8}; +Type *ty_char = &(Type){TY_CHAR, 1, 1}; +Type *ty_int = &(Type){TY_INT, 8, 8}; + +static Type *new_type(TypeKind kind, int size, int align) { + Type *ty = calloc(1, sizeof(Type)); + ty->kind = kind; + ty->size = size; + ty->align = align; + return ty; +} bool is_integer(Type *ty) { return ty->kind == TY_CHAR || ty->kind == TY_INT; @@ -14,9 +22,7 @@ Type *copy_type(Type *ty) { } Type *pointer_to(Type *base) { - Type *ty = calloc(1, sizeof(Type)); - ty->kind = TY_PTR; - ty->size = 8; + Type *ty = new_type(TY_PTR, 8, 8); ty->base = base; return ty; } @@ -29,9 +35,7 @@ Type *func_type(Type *return_ty) { } Type *array_of(Type *base, int len) { - Type *ty = calloc(1, sizeof(Type)); - ty->kind = TY_ARRAY; - ty->size = base->size * len; + Type *ty = new_type(TY_ARRAY, base->size * len, base->align); ty->base = base; ty->array_len = len; return ty;