summaryrefslogtreecommitdiff
path: root/codegen.c
diff options
context:
space:
mode:
Diffstat (limited to 'codegen.c')
-rw-r--r--codegen.c74
1 files changed, 56 insertions, 18 deletions
diff --git a/codegen.c b/codegen.c
index 79deb46..f9dbc15 100644
--- a/codegen.c
+++ b/codegen.c
@@ -35,20 +35,26 @@ static const struct storage_location MULDIV_OVERFLOW_LOC = {
static struct scope* scope;
static const struct fn_decl_node* active_fn;
static unsigned long long branch_counter = 0;
+static unsigned long long loop_counter = 0;
-static void enter_scope(struct scope* child_scope) {
+static void enter_scope(
+ struct scope* child_scope,
+ unsigned long long bp_offset
+) {
if (child_scope == NULL ||
child_scope->next_out != scope)
CGEN_PANIC("enter_scope: scopes are misaligned");
scope = child_scope;
+ scope->bp_offset = bp_offset;
}
-static void exit_scope(struct scope* child_scope) {
+static void exit_scope(struct scope* child_scope, bool save_bp_offset) {
if (child_scope != scope || child_scope->next_out == NULL)
CGEN_PANIC("exit_scope: scopes are misaligned");
scope = child_scope->next_out;
+ if (save_bp_offset) scope->bp_offset = child_scope->bp_offset;
}
static struct lval_def allocate_register(const struct type_def* type) {
@@ -305,6 +311,11 @@ static struct var_def* emit_var_decl(
const struct var_decl_node* node
) {
struct lval_def var_dst = make_stack_lval(outfile, node->type.def_ref);
+
+ fprintf(outfile, "\t; '%s' lives in: ", node->def_ref->name);
+ emit_storage_loc(outfile, &var_dst.loc, var_dst.type->sz);
+ fprintf(outfile, "\n");
+
struct var_def* var_def = node->def_ref;
var_def->loc = var_dst.loc;
return var_def;
@@ -562,39 +573,63 @@ static void emit_group_contents(FILE* outfile, const struct group_node* node) {
}
static void emit_group(FILE* outfile, const struct group_node* node) {
- enter_scope(node->scope);
- scope->bp_offset = scope->next_out->bp_offset; /* don't reset bp */
+ enter_scope(node->scope, scope->bp_offset);
emit_group_contents(outfile, node);
/* don't reset sp because alloca needs to work */
scope->next_out->bp_offset = scope->bp_offset;
- exit_scope(node->scope);
+ exit_scope(node->scope, true);
}
static void emit_if(FILE* outfile, const struct if_node* node) {
- enter_scope(node->scope);
+ enter_scope(node->scope, scope->bp_offset);
struct lval_def cond_result =
allocate_temporary(outfile, node->cond->resolved_type);
emit_expr(outfile, node->cond, &cond_result);
emit_cmp_zero(outfile, &cond_result);
- unsigned long long false_branch_num = branch_counter++;
- fprintf(outfile, "\tjz branch%lld\n", false_branch_num);
+ unsigned long long branch_num = ++branch_counter;
+ fprintf(outfile, "\tjz branch_false@%lld\n", branch_num);
emit_stmt(outfile, node->true_branch);
if (node->false_branch == NULL) {
- fprintf(outfile, "branch%lld:\n", false_branch_num);
+ fprintf(outfile, "branch_false@%lld:\n", branch_num);
} else {
- unsigned long long end_branch_num = branch_counter++;
- fprintf(outfile, "\tjmp branch%lld\n", end_branch_num);
- fprintf(outfile, "branch%lld:\n", false_branch_num);
+ fprintf(outfile, "\tjmp branch_done@%lld\n", branch_num);
+ fprintf(outfile, "branch_false@%lld:\n", branch_num);
emit_stmt(outfile, node->false_branch);
- fprintf(outfile, "branch%lld:\n", end_branch_num);
+ fprintf(outfile, "branch_done@%lld:\n", branch_num);
+ }
+
+ exit_scope(node->scope, true);
+}
+
+static void emit_loop(FILE* outfile, const struct loop_node* node) {
+ enter_scope(node->scope, scope->bp_offset);
+
+ if (node->init != NULL) emit_expr(outfile, node->init, NULL);
+
+ unsigned long long loop_num = ++loop_counter;
+ if (node->cond != NULL) {
+ struct lval_def cond_dst =
+ allocate_temporary(outfile, node->cond->resolved_type);
+ fprintf(outfile, "loop_head@%lld:\n", loop_num);
+ emit_expr(outfile, node->cond, &cond_dst);
+ emit_cmp_zero(outfile, &cond_dst);
+ fprintf(outfile, "\tjz loop_done@%lld\n", loop_num);
+ } else {
+ fprintf(outfile, "loop_head@%lld:\n", loop_num);
}
- exit_scope(node->scope);
+ emit_stmt(outfile, node->body);
+ if (node->incr != NULL) emit_expr(outfile, node->incr, NULL);
+
+ fprintf(outfile, "\tjmp loop_head@%lld\n", loop_num);
+ fprintf(outfile, "loop_done@%lld:\n", loop_num);
+
+ exit_scope(node->scope, true);
}
static void emit_stmt(FILE* outfile, const struct stmt_node* node) {
@@ -616,11 +651,14 @@ static void emit_stmt(FILE* outfile, const struct stmt_node* node) {
case STMT_IF:
emit_if(outfile, &node->inner.if_);
break;
+ case STMT_LOOP:
+ emit_loop(outfile, &node->inner.loop);
+ break;
}
}
static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
- enter_scope(node->scope);
+ enter_scope(node->scope, 0);
if (active_fn != NULL)
CGEN_PANIC(
@@ -660,9 +698,9 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
emit_mov(outfile, &arg_dst, &arg_src);
}
- enter_scope(node->body.scope);
+ enter_scope(node->body.scope, scope->bp_offset);
emit_group_contents(outfile, &node->body);
- exit_scope(node->body.scope);
+ exit_scope(node->body.scope, true);
fprintf(outfile, RETURN_LABEL_FMT ":\n", node->name);
fprintf(outfile, "\tmov rsp, rbp\n");
@@ -670,7 +708,7 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
fprintf(outfile, "\tret\n");
active_fn = NULL;
- exit_scope(node->scope);
+ exit_scope(node->scope, false);
}
static void emit_root_node(FILE* outfile, const struct root_node* node) {