summaryrefslogtreecommitdiff
path: root/codegen.c
diff options
context:
space:
mode:
Diffstat (limited to 'codegen.c')
-rw-r--r--codegen.c115
1 files changed, 82 insertions, 33 deletions
diff --git a/codegen.c b/codegen.c
index 6dfaf4a..c8a9933 100644
--- a/codegen.c
+++ b/codegen.c
@@ -61,23 +61,23 @@ static void emit_mov(
if (src->type == REGISTER && sz < 4) {
fprintf(outfile, "\tmovzx ");
emit_storage_loc(outfile, dst, FULL_REG_SZ);
- fprintf(outfile, ", ");
- emit_storage_loc(outfile, src, sz);
} else {
fprintf(outfile, "\tmov ");
emit_storage_loc(outfile, dst, sz);
- fprintf(outfile, ", ");
- emit_storage_loc(outfile, src, sz);
}
+
+ fprintf(outfile, ", ");
+ emit_storage_loc(outfile, src, sz);
break;
case BP_OFFSET:
- fprintf(outfile, "\tmov ");
if (src->type == BP_OFFSET) {
- if (sz > 4) fprintf(outfile, "qword ");
- else if (sz > 2) fprintf(outfile, "dword ");
- else if (sz > 1) fprintf(outfile, "word ");
- else fprintf(outfile, "byte ");
+ /* `mov mem, mem` is illegal in x86_64 */
+ emit_mov(outfile, &RV_LOC, src, sz);
+ emit_mov(outfile, dst, &RV_LOC, sz);
+ return;
}
+
+ fprintf(outfile, "\tmov ");
emit_storage_loc(outfile, dst, sz);
fprintf(outfile, ", ");
emit_storage_loc(outfile, src, sz);
@@ -91,6 +91,12 @@ static void emit_mov(
fprintf(outfile, "\n");
}
+static void emit_expr(
+ FILE* outfile,
+ const struct expr_node* node,
+ const struct storage_location* storage
+);
+
static void emit_int_lit(
FILE* outfile,
const struct int_lit_node* node,
@@ -107,37 +113,24 @@ static void emit_int_lit(
FULL_REG_SZ);
}
+static struct var_def get_var(const char* name) {
+ struct var_def var_def;
+ if (!scope_get_var(scope, &var_def, name))
+ CGEN_PANIC("reference to undefined variable %s", name);
+ return var_def;
+}
+
static void emit_var_ref(
FILE* outfile,
const struct var_ref_node* node,
const struct storage_location* storage
) {
if (storage != NULL) {
- struct var_def var_def;
- if (!scope_get_var(scope, &var_def, node->ident))
- CGEN_PANIC("reference to undefined variable %s", node->ident);
-
+ struct var_def var_def = get_var(node->ident);
emit_mov(outfile, storage, &var_def.loc, var_def.sz);
}
}
-static void emit_expr(
- FILE* outfile,
- const struct expr_node* node,
- const struct storage_location* storage
-) {
- switch (node->type) {
- case EXPR_EMPTY:
- break;
- case EXPR_INT_LIT:
- emit_int_lit(outfile, &node->as._int_lit, storage);
- break;
- case EXPR_VAR_REF:
- emit_var_ref(outfile, &node->as._var_ref, storage);
- break;
- }
-}
-
static void emit_stmt(FILE* outfile, const struct stmt_node* node);
static unsigned long long get_type_size(const struct type_node* type) {
@@ -150,19 +143,73 @@ static unsigned long long get_type_size(const struct type_node* type) {
return type_def.size;
}
-static void emit_var_decl(FILE* outfile, const struct var_decl_node* node) {
+static struct var_def emit_var_decl(
+ FILE* outfile,
+ const struct var_decl_node* node
+) {
unsigned long long type_sz = get_type_size(&node->type);
fprintf(outfile, "\tsub rsp, %llu\n", type_sz);
scope->bp_offset += type_sz;
- scope_define_var(scope, (struct var_def) {
+
+ struct var_def var_def = {
.name = node->ident,
.loc = {
.type = BP_OFFSET,
.offset = scope->bp_offset,
},
.sz = type_sz,
- });
+ };
+ scope_define_var(scope, var_def);
+ return var_def;
+}
+
+struct lval_def {
+ struct storage_location loc;
+ unsigned long long sz;
+};
+
+static struct lval_def emit_lval(
+ FILE* outfile,
+ const struct lval_node* node
+) {
+ struct var_def var_def;
+ switch (node->type) {
+ case LVAL_VAR_DECL:
+ var_def = emit_var_decl(outfile, &node->as._var_decl);
+ return (struct lval_def) {.loc = var_def.loc, .sz = var_def.sz};
+ case LVAL_VAR_REF:
+ var_def = get_var(node->as._var_ref.ident);
+ return (struct lval_def) {.loc = var_def.loc, .sz = var_def.sz};
+ }
+ CGEN_PANIC("unknown lval type: %d", node->type);
+}
+
+static void emit_assignment(
+ FILE* outfile,
+ const struct assign_node* node,
+ const struct storage_location* storage
+) {
+ const struct lval_def lval_def = emit_lval(outfile, &node->lval);
+ emit_expr(outfile, node->rval, &lval_def.loc);
+ if (storage != NULL) emit_mov(outfile, storage, &lval_def.loc, lval_def.sz);
+}
+
+static void emit_expr(
+ FILE* outfile,
+ const struct expr_node* node,
+ const struct storage_location* storage
+) {
+ switch (node->type) {
+ case EXPR_INT_LIT:
+ emit_int_lit(outfile, &node->as._int_lit, storage);
+ break;
+ case EXPR_VAR_REF:
+ emit_var_ref(outfile, &node->as._var_ref, storage);
+ break;
+ case EXPR_ASSIGN:
+ emit_assignment(outfile, &node->as._assign, storage);
+ }
}
static void emit_return(FILE* outfile, const struct return_node* node) {
@@ -193,6 +240,8 @@ static void emit_stmt_group(FILE* outfile, const struct group_node* node) {
static void emit_stmt(FILE* outfile, const struct stmt_node* node) {
switch (node->type) {
+ case STMT_EMPTY:
+ break;
case STMT_VAR_DECL:
emit_var_decl(outfile, &node->as._var_decl);
break;