mirror of https://github.com/rui314/chibicc
Add _Alignof and _Alignas
This commit is contained in:
parent
27647455e4
commit
9df51789e7
|
@ -74,6 +74,7 @@ struct Obj {
|
|||
char *name; // Variable name
|
||||
Type *ty; // Type
|
||||
bool is_local; // local or global/function
|
||||
int align; // alignment
|
||||
|
||||
// Local variable
|
||||
int offset;
|
||||
|
@ -258,6 +259,7 @@ struct Member {
|
|||
Token *tok; // for error message
|
||||
Token *name;
|
||||
int idx;
|
||||
int align;
|
||||
int offset;
|
||||
};
|
||||
|
||||
|
|
|
@ -453,7 +453,7 @@ static void assign_lvar_offsets(Obj *prog) {
|
|||
int offset = 0;
|
||||
for (Obj *var = fn->locals; var; var = var->next) {
|
||||
offset += var->ty->size;
|
||||
offset = align_to(offset, var->ty->align);
|
||||
offset = align_to(offset, var->align);
|
||||
var->offset = -offset;
|
||||
}
|
||||
fn->stack_size = align_to(offset, 16);
|
||||
|
@ -466,7 +466,7 @@ static void emit_data(Obj *prog) {
|
|||
continue;
|
||||
|
||||
println(" .globl %s", var->name);
|
||||
println(" .align %d", var->ty->align);
|
||||
println(" .align %d", var->align);
|
||||
|
||||
if (var->init_data) {
|
||||
println(" .data");
|
||||
|
|
53
parse.c
53
parse.c
|
@ -54,6 +54,7 @@ typedef struct {
|
|||
bool is_typedef;
|
||||
bool is_static;
|
||||
bool is_extern;
|
||||
int align;
|
||||
} VarAttr;
|
||||
|
||||
// This struct represents a variable initializer. Since initializers
|
||||
|
@ -110,10 +111,11 @@ static Node *current_switch;
|
|||
|
||||
static bool is_typename(Token *tok);
|
||||
static Type *declspec(Token **rest, Token *tok, VarAttr *attr);
|
||||
static Type *typename(Token **rest, Token *tok);
|
||||
static Type *enum_specifier(Token **rest, Token *tok);
|
||||
static Type *type_suffix(Token **rest, Token *tok, Type *ty);
|
||||
static Type *declarator(Token **rest, Token *tok, Type *ty);
|
||||
static Node *declaration(Token **rest, Token *tok, Type *basety);
|
||||
static Node *declaration(Token **rest, Token *tok, Type *basety, VarAttr *attr);
|
||||
static void initializer2(Token **rest, Token *tok, Initializer *init);
|
||||
static Initializer *initializer(Token **rest, Token *tok, Type *ty, Type **new_ty);
|
||||
static Node *lvar_initializer(Token **rest, Token *tok, Obj *var);
|
||||
|
@ -280,6 +282,7 @@ static Obj *new_var(char *name, Type *ty) {
|
|||
Obj *var = calloc(1, sizeof(Obj));
|
||||
var->name = name;
|
||||
var->ty = ty;
|
||||
var->align = ty->align;
|
||||
push_scope(name)->var = var;
|
||||
return var;
|
||||
}
|
||||
|
@ -391,6 +394,19 @@ static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (equal(tok, "_Alignas")) {
|
||||
if (!attr)
|
||||
error_tok(tok, "_Alignas is not allowed in this context");
|
||||
tok = skip(tok->next, "(");
|
||||
|
||||
if (is_typename(tok))
|
||||
attr->align = typename(&tok, tok)->align;
|
||||
else
|
||||
attr->align = const_expr(&tok, tok);
|
||||
tok = skip(tok, ")");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle user-defined types.
|
||||
Type *ty2 = find_typedef(tok);
|
||||
if (equal(tok, "struct") || equal(tok, "union") || equal(tok, "enum") || ty2) {
|
||||
|
@ -638,7 +654,7 @@ static Type *enum_specifier(Token **rest, Token *tok) {
|
|||
}
|
||||
|
||||
// declaration = declspec (declarator ("=" expr)? ("," declarator ("=" expr)?)*)? ";"
|
||||
static Node *declaration(Token **rest, Token *tok, Type *basety) {
|
||||
static Node *declaration(Token **rest, Token *tok, Type *basety, VarAttr *attr) {
|
||||
Node head = {};
|
||||
Node *cur = &head;
|
||||
int i = 0;
|
||||
|
@ -652,6 +668,9 @@ static Node *declaration(Token **rest, Token *tok, Type *basety) {
|
|||
error_tok(tok, "variable declared void");
|
||||
|
||||
Obj *var = new_lvar(get_ident(ty->name), ty);
|
||||
if (attr && attr->align)
|
||||
var->align = attr->align;
|
||||
|
||||
if (equal(tok, "=")) {
|
||||
Node *expr = lvar_initializer(&tok, tok->next, var);
|
||||
cur = cur->next = new_unary(ND_EXPR_STMT, expr, tok);
|
||||
|
@ -1013,7 +1032,7 @@ static void gvar_initializer(Token **rest, Token *tok, Obj *var) {
|
|||
static bool is_typename(Token *tok) {
|
||||
static char *kw[] = {
|
||||
"void", "_Bool", "char", "short", "int", "long", "struct", "union",
|
||||
"typedef", "enum", "static", "extern",
|
||||
"typedef", "enum", "static", "extern", "_Alignas",
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
|
||||
|
@ -1117,7 +1136,7 @@ static Node *stmt(Token **rest, Token *tok) {
|
|||
|
||||
if (is_typename(tok)) {
|
||||
Type *basety = declspec(&tok, tok, NULL);
|
||||
node->init = declaration(&tok, tok, basety);
|
||||
node->init = declaration(&tok, tok, basety, NULL);
|
||||
} else {
|
||||
node->init = expr_stmt(&tok, tok);
|
||||
}
|
||||
|
@ -1227,7 +1246,7 @@ static Node *compound_stmt(Token **rest, Token *tok) {
|
|||
continue;
|
||||
}
|
||||
|
||||
cur = cur->next = declaration(&tok, tok, basety);
|
||||
cur = cur->next = declaration(&tok, tok, basety, &attr);
|
||||
} else {
|
||||
cur = cur->next = stmt(&tok, tok);
|
||||
}
|
||||
|
@ -1749,7 +1768,8 @@ static void struct_members(Token **rest, Token *tok, Type *ty) {
|
|||
int idx = 0;
|
||||
|
||||
while (!equal(tok, "}")) {
|
||||
Type *basety = declspec(&tok, tok, NULL);
|
||||
VarAttr attr = {};
|
||||
Type *basety = declspec(&tok, tok, &attr);
|
||||
bool first = true;
|
||||
|
||||
while (!consume(&tok, tok, ";")) {
|
||||
|
@ -1761,6 +1781,7 @@ static void struct_members(Token **rest, Token *tok, Type *ty) {
|
|||
mem->ty = declarator(&tok, tok, basety);
|
||||
mem->name = mem->ty->name;
|
||||
mem->idx = idx++;
|
||||
mem->align = attr.align ? attr.align : mem->ty->align;
|
||||
cur = cur->next = mem;
|
||||
}
|
||||
}
|
||||
|
@ -1832,12 +1853,12 @@ static Type *struct_decl(Token **rest, Token *tok) {
|
|||
// 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);
|
||||
offset = align_to(offset, mem->align);
|
||||
mem->offset = offset;
|
||||
offset += mem->ty->size;
|
||||
|
||||
if (ty->align < mem->ty->align)
|
||||
ty->align = mem->ty->align;
|
||||
if (ty->align < mem->align)
|
||||
ty->align = mem->align;
|
||||
}
|
||||
ty->size = align_to(offset, ty->align);
|
||||
return ty;
|
||||
|
@ -1855,8 +1876,8 @@ static Type *union_decl(Token **rest, Token *tok) {
|
|||
// are already initialized to zero. We need to compute the
|
||||
// alignment and the size though.
|
||||
for (Member *mem = ty->members; mem; mem = mem->next) {
|
||||
if (ty->align < mem->ty->align)
|
||||
ty->align = mem->ty->align;
|
||||
if (ty->align < mem->align)
|
||||
ty->align = mem->align;
|
||||
if (ty->size < mem->ty->size)
|
||||
ty->size = mem->ty->size;
|
||||
}
|
||||
|
@ -1983,6 +2004,7 @@ static Node *funcall(Token **rest, Token *tok) {
|
|||
// | "(" expr ")"
|
||||
// | "sizeof" "(" type-name ")"
|
||||
// | "sizeof" unary
|
||||
// | "_Alignof" "(" type-name ")"
|
||||
// | ident func-args?
|
||||
// | str
|
||||
// | num
|
||||
|
@ -2015,6 +2037,13 @@ static Node *primary(Token **rest, Token *tok) {
|
|||
return new_num(node->ty->size, tok);
|
||||
}
|
||||
|
||||
if (equal(tok, "_Alignof")) {
|
||||
tok = skip(tok->next, "(");
|
||||
Type *ty = typename(&tok, tok);
|
||||
*rest = skip(tok, ")");
|
||||
return new_num(ty->align, tok);
|
||||
}
|
||||
|
||||
if (tok->kind == TK_IDENT) {
|
||||
// Function call
|
||||
if (equal(tok->next, "("))
|
||||
|
@ -2128,6 +2157,8 @@ static Token *global_variable(Token *tok, Type *basety, VarAttr *attr) {
|
|||
Type *ty = declarator(&tok, tok, basety);
|
||||
Obj *var = new_gvar(get_ident(ty->name), ty);
|
||||
var->is_definition = !attr->is_extern;
|
||||
if (attr->align)
|
||||
var->align = attr->align;
|
||||
|
||||
if (equal(tok, "="))
|
||||
gvar_initializer(&tok, tok->next, var);
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#include "test.h"
|
||||
|
||||
int _Alignas(512) g1;
|
||||
int _Alignas(512) g2;
|
||||
char g3;
|
||||
int g4;
|
||||
long g5;
|
||||
char g6;
|
||||
|
||||
int main() {
|
||||
ASSERT(1, _Alignof(char));
|
||||
ASSERT(2, _Alignof(short));
|
||||
ASSERT(4, _Alignof(int));
|
||||
ASSERT(8, _Alignof(long));
|
||||
ASSERT(8, _Alignof(long long));
|
||||
ASSERT(1, _Alignof(char[3]));
|
||||
ASSERT(4, _Alignof(int[3]));
|
||||
ASSERT(1, _Alignof(struct {char a; char b;}[2]));
|
||||
ASSERT(8, _Alignof(struct {char a; long b;}[2]));
|
||||
|
||||
ASSERT(1, ({ _Alignas(char) char x, y; &y-&x; }));
|
||||
ASSERT(8, ({ _Alignas(long) char x, y; &y-&x; }));
|
||||
ASSERT(32, ({ _Alignas(32) char x, y; &y-&x; }));
|
||||
ASSERT(32, ({ _Alignas(32) int *x, *y; ((char *)&y)-((char *)&x); }));
|
||||
ASSERT(16, ({ struct { _Alignas(16) char x, y; } a; &a.y-&a.x; }));
|
||||
ASSERT(8, ({ struct T { _Alignas(8) char a; }; _Alignof(struct T); }));
|
||||
|
||||
ASSERT(0, (long)(char *)&g1 % 512);
|
||||
ASSERT(0, (long)(char *)&g2 % 512);
|
||||
ASSERT(0, (long)(char *)&g4 % 4);
|
||||
ASSERT(0, (long)(char *)&g5 % 8);
|
||||
|
||||
printf("OK\n");
|
||||
return 0;
|
||||
}
|
|
@ -133,7 +133,7 @@ static bool is_keyword(Token *tok) {
|
|||
"return", "if", "else", "for", "while", "int", "sizeof", "char",
|
||||
"struct", "union", "short", "long", "void", "typedef", "_Bool",
|
||||
"enum", "static", "goto", "break", "continue", "switch", "case",
|
||||
"default", "extern",
|
||||
"default", "extern", "_Alignof", "_Alignas",
|
||||
};
|
||||
|
||||
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
|
||||
|
|
Loading…
Reference in New Issue