diff options
Diffstat (limited to 'codegen.c')
| -rw-r--r-- | codegen.c | 63 |
1 files changed, 51 insertions, 12 deletions
@@ -34,6 +34,7 @@ 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 struct lval_def allocate_register(unsigned long long sz) { return (struct lval_def) { @@ -173,19 +174,33 @@ static void emit_mov( emit_storage_loc(outfile, src, dst->sz); break; case STO_LABEL: - CGEN_PANIC("can't move value into label %s", dst->loc.label); - case STO_FN: - CGEN_PANIC( - "can't move value into function %s", dst->loc.decl->name); case STO_IMM: - CGEN_PANIC( - "can't move value into immediate value %lld", dst->loc.value); + case STO_FN: case STO_UNRESOLVED: - CGEN_PANIC("can't move value into unresolved storage"); + CGEN_PANIC("can't move value into storage type"); } fprintf(outfile, "\n"); } +static void emit_cmp_zero(FILE* outfile, const struct lval_def* lval) { + fprintf(outfile, "\tcmp "); + switch (lval->loc.type) { + case STO_REG: + emit_storage_loc(outfile, &lval->loc, lval->sz); + break; + case STO_STACK: + emit_size_const(outfile, lval->sz); + emit_storage_loc(outfile, &lval->loc, lval->sz); + break; + case STO_LABEL: + case STO_IMM: + case STO_FN: + case STO_UNRESOLVED: + CGEN_PANIC("can't compare this storage type") + } + fprintf(outfile, ", 0\n"); +} + /* TODO: move this utility to the type checker and use evaluated_type */ static unsigned long long get_type_size(const struct type_node* type) { if (type->ptr_level > 0) return PTR_SIZE; @@ -524,7 +539,7 @@ static void emit_return(FILE* outfile, const struct return_node* node) { fprintf(outfile, "\tjmp " RETURN_LABEL_FMT "\n", active_fn->name); } -static void emit_group(FILE* outfile, const struct group_node* node) { +static void emit_group_contents(FILE* outfile, const struct group_node* node) { const struct stmt_node* body_node = node->head; while (body_node != NULL) { emit_stmt(outfile, body_node); @@ -532,19 +547,40 @@ static void emit_group(FILE* outfile, const struct group_node* node) { } } -static void emit_stmt_group(FILE* outfile, const struct group_node* node) { +static void emit_group(FILE* outfile, const struct group_node* node) { if (node->scope->next_out != scope) CGEN_PANIC("scopes are misaligned"); scope = node->scope; scope->bp_offset = scope->next_out->bp_offset; /* don't reset bp */ - emit_group(outfile, node); + emit_group_contents(outfile, node); /* don't reset sp because alloca needs to work */ scope->next_out->bp_offset = scope->bp_offset; scope = scope->next_out; } +static void emit_if(FILE* outfile, const struct if_node* node) { + /* TODO: use type checked cond result size; using full reg size causes a segfault */ + struct lval_def cond_result = allocate_temporary(outfile, FULL_REG_SZ); + 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); + emit_stmt(outfile, node->true_branch); + + if (node->false_branch == NULL) { + fprintf(outfile, "branch%lld:\n", false_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); + emit_stmt(outfile, node->false_branch); + fprintf(outfile, "branch%lld:\n", end_branch_num); + } +} + static void emit_stmt(FILE* outfile, const struct stmt_node* node) { switch (node->type) { case STMT_EMPTY: @@ -559,7 +595,10 @@ static void emit_stmt(FILE* outfile, const struct stmt_node* node) { emit_expr(outfile, &node->inner.expr, NULL); break; case STMT_GROUP: - emit_stmt_group(outfile, &node->inner.group); + emit_group(outfile, &node->inner.group); + break; + case STMT_IF: + emit_if(outfile, &node->inner.if_); break; } } @@ -613,7 +652,7 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { arg_decl = arg_decl->next; } - emit_group(outfile, &node->body); + emit_group_contents(outfile, &node->body); scope = scope->next_out; |
