diff options
Diffstat (limited to 'codegen.c')
| -rw-r--r-- | codegen.c | 74 |
1 files changed, 56 insertions, 18 deletions
@@ -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) { |
