diff --git a/chibicc.h b/chibicc.h index 5a3e190886ee36b99dc198604130d349af18d320..27f2735b56ac67eb967cb46931caa446f368794d 100644 --- a/chibicc.h +++ b/chibicc.h @@ -209,6 +209,7 @@ typedef enum { ND_EXPR_STMT, // Expression statement ND_STMT_EXPR, // Statement expression ND_VAR, // Variable + ND_VLA_PTR, // VLA designator ND_NUM, // Integer ND_CAST, // Type cast ND_MEMZERO, // Zero-clear a stack variable diff --git a/codegen.c b/codegen.c index 396d1697921a64b132ae7d22b2e2ac7823e8ca8f..3e2ff187da6bd700d06bf24d0e2cb51af01687a3 100644 --- a/codegen.c +++ b/codegen.c @@ -60,6 +60,12 @@ int align_to(int n, int align) { static void gen_addr(Node *node) { switch (node->kind) { case ND_VAR: + // Variable-length array, which is always local. + if (node->var->ty->kind == TY_VLA) { + println(" mov %d(%%rbp), %%rax", node->var->offset); + return; + } + // Local variable if (node->var->is_local) { println(" lea %d(%%rbp), %%rax", node->var->offset); @@ -125,6 +131,9 @@ static void gen_addr(Node *node) { return; } break; + case ND_VLA_PTR: + println(" lea %d(%%rbp), %%rax", node->var->offset); + return; } error_tok(node->tok, "not an lvalue"); @@ -137,6 +146,7 @@ static void load(Type *ty) { case TY_STRUCT: case TY_UNION: case TY_FUNC: + case TY_VLA: // If it is an array, do not attempt to load a value to the // register because in general we can't load an entire array to a // register. As a result, the result of an evaluation of an array diff --git a/parse.c b/parse.c index 92936ffec4c7ded0371482f98e9c38dba67b223d..e7f844026a23f57f06a4035830f0ee1f22b48267 100644 --- a/parse.c +++ b/parse.c @@ -245,6 +245,12 @@ static Node *new_var_node(Var *var, Token *tok) { return node; } +static Node *new_vla_ptr(Var *var, Token *tok) { + Node *node = new_node(ND_VLA_PTR, tok); + node->var = var; + return node; +} + Node *new_cast(Node *expr, Type *ty) { add_type(expr); @@ -869,7 +875,7 @@ static Node *declaration(Token **rest, Token *tok, Type *basety, VarAttr *attr) // x = alloca(tmp)`. Var *var = new_lvar(get_ident(ty->name), ty); Token *tok = ty->name; - Node *expr = new_binary(ND_ASSIGN, new_var_node(var, tok), + Node *expr = new_binary(ND_ASSIGN, new_vla_ptr(var, tok), new_alloca(new_var_node(ty->vla_size, tok)), tok); @@ -2236,6 +2242,12 @@ static Node *new_add(Node *lhs, Node *rhs, Token *tok) { rhs = tmp; } + // VLA + num + if (lhs->ty->base->kind == TY_VLA) { + rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok), tok); + return new_binary(ND_ADD, lhs, rhs, tok); + } + // ptr + num rhs = new_binary(ND_MUL, rhs, new_num(lhs->ty->base->size, tok), tok); return new_binary(ND_ADD, lhs, rhs, tok); @@ -2250,6 +2262,15 @@ static Node *new_sub(Node *lhs, Node *rhs, Token *tok) { if (is_numeric(lhs->ty) && is_numeric(rhs->ty)) return new_binary(ND_SUB, lhs, rhs, tok); + // VLA + num + if (lhs->ty->base->kind == TY_VLA) { + rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok), tok); + add_type(rhs); + Node *node = new_binary(ND_SUB, lhs, rhs, tok); + node->ty = lhs->ty; + return node; + } + // ptr - num if (lhs->ty->base && is_integer(rhs->ty)) { rhs = new_binary(ND_MUL, rhs, new_num(lhs->ty->base->size, tok), tok); diff --git a/test/test.h b/test/test.h index b558a13ebae9294cc6cf2794abc6a6fc7ea77ede..c68e4399eb0fdee8fd2aaa4eda1cad54b493fc74 100644 --- a/test/test.h +++ b/test/test.h @@ -11,3 +11,4 @@ void exit(int n); int vsprintf(); long strlen(char *s); void *memcpy(void *dest, void *src, long n); +void *memset(void *s, int c, long n); diff --git a/test/vla.c b/test/vla.c index edc3fb43f10270246a6612d7b01842f9730433fc..60c6dfbf1c00c78209a5b79a65fa8367f9d9de2c 100644 --- a/test/vla.c +++ b/test/vla.c @@ -15,6 +15,10 @@ int main() { ASSERT(60, ({ char n=3; int x[n][5]; sizeof(x); })); ASSERT(20, ({ char n=3; int x[n][5]; sizeof(*x); })); + ASSERT(0, ({ int n=10; int x[n+1][n+6]; int *p=x; for (int i = 0; ity = node->lhs->ty; return; case ND_VAR: + case ND_VLA_PTR: node->ty = node->var->ty; return; case ND_COND: