summaryrefslogtreecommitdiff
path: root/codegen.c
diff options
context:
space:
mode:
Diffstat (limited to 'codegen.c')
-rw-r--r--codegen.c63
1 files changed, 51 insertions, 12 deletions
diff --git a/codegen.c b/codegen.c
index bdc3cbf..44fccce 100644
--- a/codegen.c
+++ b/codegen.c
@@ -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;