summaryrefslogtreecommitdiff
path: root/codegen.c
diff options
context:
space:
mode:
authorCarson Fleming <cflems@cflems.net>2026-07-17 12:40:59 -0700
committerCarson Fleming <cflems@cflems.net>2026-07-17 12:40:59 -0700
commit424be65858999a894a18e1972fa9649fbc4c1df8 (patch)
treea878fe623546a2e3fcaf204d5977991995b21c3c /codegen.c
parent155d1971b7cd56d3206808c36c6b40357bc31cbb (diff)
downloadccc-424be65858999a894a18e1972fa9649fbc4c1df8.tar.gz
improve type system sorta
Diffstat (limited to 'codegen.c')
-rw-r--r--codegen.c145
1 files changed, 72 insertions, 73 deletions
diff --git a/codegen.c b/codegen.c
index 44fccce..e1e534c 100644
--- a/codegen.c
+++ b/codegen.c
@@ -15,8 +15,8 @@
}
struct lval_def {
+ const struct type_def* type;
struct storage_location loc;
- unsigned long long sz;
};
static const struct storage_location RV_LOC = {
@@ -36,39 +36,42 @@ 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) {
+static struct lval_def allocate_register(const struct type_def* type) {
return (struct lval_def) {
.loc = {
.type = STO_REG,
.reg = &RAX, /* TODO: no real register coloring happening LOL */
},
- .sz = sz,
+ .type = type,
};
}
-static struct lval_def allocate_stack(FILE* outfile, unsigned long long sz) {
- fprintf(outfile, "\tsub rsp, %llu\n", sz);
- scope->bp_offset += sz;
+static struct lval_def allocate_stack(
+ FILE* outfile,
+ const struct type_def* type
+) {
+ fprintf(outfile, "\tsub rsp, %llu\n", type->sz);
+ scope->bp_offset += type->sz;
return (struct lval_def) {
.loc = {
.type = STO_STACK,
.bp_offset = scope->bp_offset,
},
- .sz = sz,
+ .type = type,
};
}
static struct lval_def allocate_temporary(
FILE* outfile,
- unsigned long long sz
+ const struct type_def* type
) {
- return allocate_stack(outfile, sz);
+ return allocate_stack(outfile, type);
}
static void deallocate_temporary(FILE* outfile, const struct lval_def* tmp) {
if (tmp->loc.type == STO_STACK) {
- fprintf(outfile, "\tadd rsp, %llu\n", tmp->sz);
- scope->bp_offset -= tmp->sz;
+ fprintf(outfile, "\tadd rsp, %llu\n", tmp->type->sz);
+ scope->bp_offset -= tmp->type->sz;
}
}
@@ -146,32 +149,32 @@ static void emit_mov(
switch (dst->loc.type) {
case STO_REG:
- if (src->type == STO_REG && dst->sz < 4) {
+ if (src->type == STO_REG && dst->type->sz < 4) {
fprintf(outfile, "\tmovzx ");
emit_storage_loc(outfile, &dst->loc, FULL_REG_SZ);
} else {
fprintf(outfile, "\tmov ");
- emit_storage_loc(outfile, &dst->loc, dst->sz);
+ emit_storage_loc(outfile, &dst->loc, dst->type->sz);
}
fprintf(outfile, ", ");
- emit_storage_loc(outfile, src, dst->sz);
+ emit_storage_loc(outfile, src, dst->type->sz);
break;
case STO_STACK:
if (src->type == STO_STACK) {
/* `mov mem, mem` is illegal in x86_64 */
- struct lval_def tmp = allocate_register(dst->sz);
+ struct lval_def tmp = allocate_register(dst->type);
emit_mov(outfile, &tmp, src);
emit_mov(outfile, dst, &tmp.loc);
return;
}
fprintf(outfile, "\tmov ");
- if (src->type == STO_IMM) emit_size_const(outfile, dst->sz);
+ if (src->type == STO_IMM) emit_size_const(outfile, dst->type->sz);
- emit_storage_loc(outfile, &dst->loc, dst->sz);
+ emit_storage_loc(outfile, &dst->loc, dst->type->sz);
fprintf(outfile, ", ");
- emit_storage_loc(outfile, src, dst->sz);
+ emit_storage_loc(outfile, src, dst->type->sz);
break;
case STO_LABEL:
case STO_IMM:
@@ -186,11 +189,11 @@ 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);
+ emit_storage_loc(outfile, &lval->loc, lval->type->sz);
break;
case STO_STACK:
- emit_size_const(outfile, lval->sz);
- emit_storage_loc(outfile, &lval->loc, lval->sz);
+ emit_size_const(outfile, lval->type->sz);
+ emit_storage_loc(outfile, &lval->loc, lval->type->sz);
break;
case STO_LABEL:
case STO_IMM:
@@ -201,17 +204,17 @@ static void emit_cmp_zero(FILE* outfile, const struct lval_def* lval) {
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) {
+/* TODO: move this utility to the type checker and use resolved_type */
+static unsigned long long get_type_size(const struct type_ref_node* type) {
if (type->ptr_level > 0) return PTR_SIZE;
- return type->def->sz;
+ return type->def_ref->sz;
}
static inline struct lval_def make_stack_lval(
FILE* outfile,
- const struct type_node* type
+ const struct type_def* type
) {
- return allocate_stack(outfile, get_type_size(type));
+ return allocate_stack(outfile, type);
}
static void emit_expr(
@@ -270,8 +273,8 @@ static void emit_str_lit(
}
}
-static struct var_def get_var(const char* name) {
- struct var_def var_def;
+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;
@@ -283,25 +286,19 @@ static void emit_var_ref(
const struct lval_def* dst
) {
if (dst != NULL) {
- struct var_def var_def = get_var(node->ident);
- emit_mov(outfile, dst, &var_def.loc);
+ emit_mov(outfile, dst, &get_var(node->ident)->loc);
}
}
static void emit_stmt(FILE* outfile, const struct stmt_node* node);
-static struct var_def emit_var_decl(
+static struct var_def* emit_var_decl(
FILE* outfile,
const struct var_decl_node* node
) {
- /* TODO: type checker should define vars, we just set their loc */
- struct lval_def var_dst = make_stack_lval(outfile, &node->type);
- struct var_def var_def = {
- .name = node->ident,
- .loc = var_dst.loc,
- .sz = var_dst.sz,
- };
- scope_define_var(scope, var_def);
+ struct lval_def var_dst = make_stack_lval(outfile, node->type.def_ref);
+ struct var_def* var_def = node->def_ref;
+ var_def->loc = var_dst.loc;
return var_def;
}
@@ -309,14 +306,20 @@ static struct lval_def emit_lval(
FILE* outfile,
const struct lval_node* node
) {
- struct var_def var_def;
+ struct var_def* var_def;
switch (node->type) {
case LVAL_VAR_DECL:
var_def = emit_var_decl(outfile, &node->inner.var_decl);
- return (struct lval_def) {.loc = var_def.loc, .sz = var_def.sz};
+ return (struct lval_def) {
+ .loc = var_def->loc,
+ .type = var_def->resolved_type,
+ };
case LVAL_VAR_REF:
var_def = get_var(node->inner.var_ref.ident);
- return (struct lval_def) {.loc = var_def.loc, .sz = var_def.sz};
+ return (struct lval_def) {
+ .loc = var_def->loc,
+ .type = var_def->resolved_type,
+ };
}
CGEN_PANIC("unknown lval type: %d", node->type);
}
@@ -343,7 +346,7 @@ static void emit_call(
struct args_eval_node* arg_eval = node->args;
while (arg_decl != NULL && arg_eval != NULL) {
struct lval_def arg_dst =
- make_stack_lval(outfile, &arg_decl->decl->type);
+ make_stack_lval(outfile, arg_decl->decl->type.def_ref);
emit_expr(outfile, arg_eval->expr, &arg_dst);
arg_decl = arg_decl->next;
@@ -368,14 +371,14 @@ static void emit_call(
struct lval_def arg_dst;
if (arg_regnum < CC_N_REGS)
arg_dst = (struct lval_def) {
+ .type = arg_decl->decl->type.def_ref,
.loc = (struct storage_location) {
.type = STO_REG,
.reg = CALLING_CONV[arg_regnum++],
},
- .sz = type_sz,
};
else
- arg_dst = make_stack_lval(outfile, &arg_decl->decl->type);
+ arg_dst = make_stack_lval(outfile, arg_decl->decl->type.def_ref);
emit_mov(outfile, &arg_dst, &(struct storage_location) {
.type = STO_STACK,
@@ -411,8 +414,11 @@ static void emit_unary(
switch (node->op) {
case UNARY_NEG:
fprintf(outfile, "\tneg ");
- if (dst->loc.type == STO_STACK) emit_size_const(outfile, dst->sz);
- emit_storage_loc(outfile, &dst->loc, dst->sz);
+
+ if (dst->loc.type == STO_STACK)
+ emit_size_const(outfile, dst->type->sz);
+
+ emit_storage_loc(outfile, &dst->loc, dst->type->sz);
fprintf(outfile, "\n");
break;
}
@@ -431,29 +437,29 @@ static void emit_binary(
}
/* LHS goes in RAX explicitly because imul and idiv are weird */
- struct lval_def rhs_dst = allocate_temporary(outfile, dst->sz);
+ struct lval_def rhs_dst = allocate_temporary(outfile, dst->type);
emit_expr(outfile, node->rhs, &rhs_dst);
struct lval_def lhs_dst = (struct lval_def) {
.loc = MULDIV_LOC,
- .sz = dst->sz,
+ .type = dst->type,
};
emit_expr(outfile, node->lhs, &lhs_dst);
switch (node->op) {
case BINARY_ADD:
fprintf(outfile, "\tadd ");
- emit_storage_loc(outfile, &lhs_dst.loc, dst->sz);
+ emit_storage_loc(outfile, &lhs_dst.loc, dst->type->sz);
fprintf(outfile, ", ");
break;
case BINARY_SUB:
fprintf(outfile, "\tsub ");
- emit_storage_loc(outfile, &lhs_dst.loc, dst->sz);
+ emit_storage_loc(outfile, &lhs_dst.loc, dst->type->sz);
fprintf(outfile, ", ");
break;
case BINARY_MUL:
fprintf(outfile, "\timul ");
if (rhs_dst.loc.type == STO_STACK)
- emit_size_const(outfile, dst->sz);
+ emit_size_const(outfile, dst->type->sz);
break;
case BINARY_DIV:
/* nothing in the top half reg */
@@ -465,11 +471,11 @@ static void emit_binary(
fprintf(outfile, "\tidiv ");
if (rhs_dst.loc.type == STO_STACK)
- emit_size_const(outfile, dst->sz);
+ emit_size_const(outfile, dst->type->sz);
break;
}
- emit_storage_loc(outfile, &rhs_dst.loc, dst->sz);
+ emit_storage_loc(outfile, &rhs_dst.loc, dst->type->sz);
fprintf(outfile, "\n");
/* TODO: deal with RDX overflow shit for imul and idiv */
@@ -517,10 +523,10 @@ static void emit_expr(
static void emit_return(FILE* outfile, const struct return_node* node) {
if (active_fn == NULL) CGEN_PANIC("must be inside a function to return");
- unsigned long long return_type_sz = get_type_size(&active_fn->return_type);
+ const struct type_def* return_type = active_fn->return_type.def_ref;
if (node->ret_val != NULL) {
- if (return_type_sz == 0)
+ if (return_type->sz == 0)
CGEN_PANIC(
"returning a value from void function %s", active_fn->name);
@@ -529,9 +535,9 @@ static void emit_return(FILE* outfile, const struct return_node* node) {
node->ret_val,
&(struct lval_def) {
.loc = RV_LOC,
- .sz = return_type_sz,
+ .type = return_type,
});
- } else if (return_type_sz > 0) {
+ } else if (return_type > 0) {
CGEN_PANIC(
"non-void function %s should return a value", active_fn->name);
}
@@ -561,8 +567,9 @@ static void emit_group(FILE* outfile, const struct group_node* node) {
}
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);
+ /* TODO: make type checking real so we aren't passing a null pointer here */
+ 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);
@@ -622,17 +629,11 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
long long spilled_bp_ofs = -16; // return address + old bp
unsigned char arg_regnum = 0;
struct args_decl_node* arg_decl = node->args;
- while (arg_decl != NULL) {
+ for (; arg_decl != NULL; arg_decl = arg_decl->next) {
+ struct var_def* arg_def = arg_decl->decl->def_ref;
struct lval_def arg_dst =
- make_stack_lval(outfile, &arg_decl->decl->type);
- /* TODO: type checker should define vars, we just set their loc */
- scope_define_var(
- scope,
- (struct var_def) {
- .name = arg_decl->decl->ident,
- .loc = arg_dst.loc,
- .sz = arg_dst.sz,
- });
+ make_stack_lval(outfile, arg_decl->decl->type.def_ref);
+ arg_def->loc = arg_dst.loc;
struct storage_location arg_src;
if (arg_regnum < CC_N_REGS) {
@@ -645,11 +646,9 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) {
.type = STO_STACK,
.bp_offset = spilled_bp_ofs,
};
- spilled_bp_ofs -= arg_dst.sz;
+ spilled_bp_ofs -= arg_decl->decl->type.def_ref->sz;
}
emit_mov(outfile, &arg_dst, &arg_src);
-
- arg_decl = arg_decl->next;
}
emit_group_contents(outfile, &node->body);