From 9e8779bfa994ce5cb3586b8062b064331be1edb9 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Thu, 3 Sep 2020 22:27:13 +0900 Subject: [PATCH] Add pointer arithmetic for VLA --- chibicc.h | 1 + codegen.c | 10 ++++++++++ parse.c | 23 ++++++++++++++++++++++- test/test.h | 1 + test/vla.c | 4 ++++ type.c | 1 + 6 files changed, 39 insertions(+), 1 deletion(-) diff --git a/chibicc.h b/chibicc.h index 5a3e190..27f2735 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 396d169..3e2ff18 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 92936ff..e7f8440 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 b558a13..c68e439 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 edc3fb4..60c6dfb 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: -- GitLab