aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--ast.c1
-rw-r--r--codegen.c3
-rw-r--r--parse.c47
3 files changed, 39 insertions, 12 deletions
diff --git a/ast.c b/ast.c
index 15cc28b..d67bb01 100644
--- a/ast.c
+++ b/ast.c
@@ -142,6 +142,7 @@ typedef enum AstNodeKind AstNodeKind;
#define node_int_value __i
#define node_idx __i
#define node_op __i
+#define node_stack_offset __i
struct AstNode {
AstNodeKind kind;
diff --git a/codegen.c b/codegen.c
index 234b4e5..0a90602 100644
--- a/codegen.c
+++ b/codegen.c
@@ -268,9 +268,8 @@ void codegen_func_call(CodeGen* g, AstNode* ast) {
}
void codegen_lvar(CodeGen* g, AstNode* ast, GenMode gen_mode) {
- int offset = 8 + ast->node_idx * 8;
printf(" mov rax, rbp\n");
- printf(" sub rax, %d\n", offset);
+ printf(" sub rax, %d\n", ast->node_stack_offset);
printf(" push rax\n");
if (gen_mode == GenMode_rval) {
codegen_lval2rval(ast->ty);
diff --git a/parse.c b/parse.c
index 057d5c2..d08269e 100644
--- a/parse.c
+++ b/parse.c
@@ -3,6 +3,7 @@
struct LocalVar {
String name;
Type* ty;
+ int stack_offset;
};
typedef struct LocalVar LocalVar;
@@ -88,6 +89,38 @@ int find_lvar(Parser* p, const String* name) {
return -1;
}
+int calc_stack_offset(Parser* p, Type* ty, int is_param) {
+ int align;
+ if (is_param) {
+ if (8 < type_sizeof(ty) || 8 < type_alignof(ty)) {
+ fatal_error("too large");
+ }
+ align = 8;
+ } else {
+ align = type_alignof(ty);
+ }
+
+ int offset;
+ if (p->n_lvars == 0) {
+ offset = 0;
+ } else {
+ offset = p->lvars[p->n_lvars - 1].stack_offset;
+ }
+
+ offset += type_sizeof(ty);
+ return to_aligned(offset, align);
+}
+
+int add_lvar(Parser* p, String* name, Type* ty, int is_param) {
+ int stack_offset = calc_stack_offset(p, ty, is_param);
+ p->lvars[p->n_lvars].name.data = name->data;
+ p->lvars[p->n_lvars].name.len = name->len;
+ p->lvars[p->n_lvars].ty = ty;
+ p->lvars[p->n_lvars].stack_offset = stack_offset;
+ ++p->n_lvars;
+ return stack_offset;
+}
+
int find_gvar(Parser* p, const String* name) {
int i;
for (i = 0; i < p->n_gvars; ++i) {
@@ -217,7 +250,7 @@ AstNode* parse_primary_expr(Parser* p) {
e = ast_new(AstNodeKind_lvar);
e->name.data = name->data;
e->name.len = name->len;
- e->node_idx = lvar_idx;
+ e->node_stack_offset = p->lvars[lvar_idx].stack_offset;
e->ty = p->lvars[lvar_idx].ty;
return e;
} else {
@@ -679,17 +712,14 @@ AstNode* parse_var_decl(Parser* p) {
if (find_lvar(p, name) != -1 || find_gvar(p, name) != -1) {
fatal_error("parse_var_decl: %.*s redeclared", name->len, name->data);
}
- p->lvars[p->n_lvars].name.data = name->data;
- p->lvars[p->n_lvars].name.len = name->len;
- p->lvars[p->n_lvars].ty = ty;
- ++p->n_lvars;
+ int stack_offset = add_lvar(p, name, ty, 0);
AstNode* ret;
if (init) {
AstNode* lhs = ast_new(AstNodeKind_lvar);
lhs->name.data = name->data;
lhs->name.len = name->len;
- lhs->node_idx = p->n_lvars - 1;
+ lhs->node_stack_offset = stack_offset;
lhs->ty = ty;
AstNode* assign = ast_new_assign_expr(TokenKind_assign, lhs, init);
ret = ast_new(AstNodeKind_expr_stmt);
@@ -760,10 +790,7 @@ void register_params(Parser* p, AstNode* params) {
int i;
for (i = 0; i < params->node_len; ++i) {
AstNode* param = params->node_items + i;
- p->lvars[p->n_lvars].name.data = param->name.data;
- p->lvars[p->n_lvars].name.len = param->name.len;
- p->lvars[p->n_lvars].ty = param->ty;
- ++p->n_lvars;
+ add_lvar(p, &param->name, param->ty, 1);
}
}