Skip to content

Commit

Permalink
Add pointer arithmetic for VLA
Browse files Browse the repository at this point in the history
  • Loading branch information
rui314 committed Dec 7, 2020
1 parent e8667af commit 07f9010
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 1 deletion.
1 change: 1 addition & 0 deletions chibicc.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,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
Expand Down
10 changes: 10 additions & 0 deletions codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,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);
Expand Down Expand Up @@ -126,6 +132,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");
Expand All @@ -138,6 +147,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
Expand Down
23 changes: 22 additions & 1 deletion parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,12 @@ static Node *new_var_node(Obj *var, Token *tok) {
return node;
}

static Node *new_vla_ptr(Obj *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);

Expand Down Expand Up @@ -870,7 +876,7 @@ static Node *declaration(Token **rest, Token *tok, Type *basety, VarAttr *attr)
// x = alloca(tmp)`.
Obj *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);

Expand Down Expand Up @@ -2247,6 +2253,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_long(lhs->ty->base->size, tok), tok);
return new_binary(ND_ADD, lhs, rhs, tok);
Expand All @@ -2261,6 +2273,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_long(lhs->ty->base->size, tok), tok);
Expand Down
1 change: 1 addition & 0 deletions test/test.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
4 changes: 4 additions & 0 deletions test/vla.c
Original file line number Diff line number Diff line change
Expand Up @@ -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; i<sizeof(x)/4; i++) p[i]=i; x[0][0]; }));
ASSERT(5, ({ int n=10; int x[n+1][n+6]; int *p=x; for (int i = 0; i<sizeof(x)/4; i++) p[i]=i; x[0][5]; }));
ASSERT(5*16+2, ({ int n=10; int x[n+1][n+6]; int *p=x; for (int i = 0; i<sizeof(x)/4; i++) p[i]=i; x[5][2]; }));

printf("OK\n");
return 0;
}
1 change: 1 addition & 0 deletions type.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ void add_type(Node *node) {
node->ty = node->lhs->ty;
return;
case ND_VAR:
case ND_VLA_PTR:
node->ty = node->var->ty;
return;
case ND_COND:
Expand Down

0 comments on commit 07f9010

Please sign in to comment.