diff options
| author | Carson Fleming <cflems@cflems.net> | 2026-08-06 00:24:49 -0400 |
|---|---|---|
| committer | Carson Fleming <cflems@cflems.net> | 2026-08-06 00:24:49 -0400 |
| commit | b48e27f5cc31af65d8bb92d4b81cd03a60c5bcdb (patch) | |
| tree | 0901fba9ff451968d758ed47b57ff99d1330fb8a /codegen.c | |
| parent | a207a7f39514f03ddfafbe39e52a3fae57a414b4 (diff) | |
| download | ccc-b48e27f5cc31af65d8bb92d4b81cd03a60c5bcdb.tar.gz | |
clean up yesterday's hacks + functions in type system
Diffstat (limited to 'codegen.c')
| -rw-r--r-- | codegen.c | 87 |
1 files changed, 42 insertions, 45 deletions
@@ -7,6 +7,7 @@ #include <stdlib.h> #include <stdio.h> #include <string.h> +#include <stddef.h> #define CGEN_PANIC(format, ...) {\ fprintf(\ @@ -32,7 +33,7 @@ static struct reg* MULDIV_OVERFLOW_REG = &RDX; static struct hash_map dseg; static struct scope* scope; -static const struct fn_decl_node* active_fn; +struct var_def* active_fn; static integral_t branch_counter = 0; static integral_t loop_counter = 0; @@ -90,8 +91,11 @@ static const struct data_type* get_effective_data_type( return type->data.data_type; case TP_PTR: return &long_long_type; + case TP_FN: + /* functions have size 1 I guess */ + return &char_type; } - CGEN_PANIC("unhandled type of type case"); + unreachable(); } static struct lval_def allocate_stack( @@ -132,11 +136,8 @@ static void release_temporary(FILE* outfile, const struct lval_def* tmp) { break; case STO_STACK: case STO_IMM: - case STO_FN: case STO_LABEL: break; - case STO_UNRESOLVED: - CGEN_PANIC("can't release unresolved storage"); } } @@ -149,9 +150,6 @@ static void emit_storage_loc( case STO_LABEL: fprintf(outfile, "%s", loc->label); break; - case STO_FN: - fprintf(outfile, "%s", loc->decl->name); - break; case STO_REG: if (sz > 4) fprintf(outfile, "%s", loc->reg->qword); else if (sz > 2) fprintf(outfile, "%s", loc->reg->dword); @@ -169,8 +167,6 @@ static void emit_storage_loc( case STO_IMM: fprintf(outfile, "0x%llx", loc->value); break; - case STO_UNRESOLVED: - CGEN_PANIC("can't emit unresolved storage location"); } } @@ -189,12 +185,8 @@ static bool locs_equal( return a->bp_offset == b->bp_offset; case STO_LABEL: return strcmp(a->label, b->label) == 0; - case STO_FN: - return a->decl == b->decl; - case STO_UNRESOLVED: - return false; } - CGEN_PANIC("unhandled storage type case"); + unreachable(); } static void emit_size_const(FILE* outfile, integral_t sz) { @@ -253,10 +245,8 @@ static void emit_label_lea( if (spill_reg) unspill_register(outfile, tmp_reg); else release_register(tmp_reg); return; - case STO_FN: case STO_IMM: case STO_LABEL: - case STO_UNRESOLVED: CGEN_PANIC("can't load label address into non-value storage"); } } @@ -331,9 +321,7 @@ static void emit_mov( break; case STO_LABEL: case STO_IMM: - case STO_FN: - case STO_UNRESOLVED: - CGEN_PANIC("can't move value into storage type"); + CGEN_PANIC("can't move value into non-storage type"); } fprintf(outfile, "\n"); } @@ -351,9 +339,7 @@ static void emit_cmp_zero(FILE* outfile, const struct lval_def* lval) { break; case STO_LABEL: case STO_IMM: - case STO_FN: - case STO_UNRESOLVED: - CGEN_PANIC("can't compare this storage type") + CGEN_PANIC("can't compare this non-storage type") } fprintf(outfile, ", 0\n"); } @@ -427,7 +413,7 @@ static void emit_var_ref( const struct lval_def* dst ) { if (dst != NULL) { - emit_mov(outfile, dst, &node->def_ref->loc); + emit_mov(outfile, dst, &node->def_ref->storage); } } @@ -439,7 +425,7 @@ static void emit_decl( ) { struct lval_def var_dst = allocate_stack(outfile, node->def_ref->type); - node->def_ref->loc = var_dst.loc; + node->def_ref->storage = var_dst.loc; fprintf(outfile, "\t; %s\n", node->def_ref->name); @@ -468,7 +454,7 @@ static void emit_assignment( struct var_ref_node* var_ref = &node->lval->inner.var_ref; lval_def = (struct lval_def) { .type = var_ref->def_ref->type, - .loc = var_ref->def_ref->loc, + .loc = var_ref->def_ref->storage, }; break; default: @@ -532,10 +518,14 @@ static void emit_call( } /* 3. `call <label>` */ - fprintf(outfile, "\tcall %s", node->fn_ref->name); - // TODO: this is kinda fukt we should probably keep an - // internal/external flag in the storage loc instead - if (node->fn_ref->body == NULL) fprintf(outfile, " WRT ..plt"); + /* TODO: support function pointers */ + if (node->expr->type != EXPR_VAR_REF) + CGEN_PANIC("function pointers are not supported"); + const struct var_def* fn_def = node->expr->inner.var_ref.def_ref; + fprintf(outfile, "\tcall "); + emit_storage_loc(outfile, &fn_def->storage, 0); + /* TODO: this could be a part of emit_storage_loc for labels */ + if (!fn_def->fn.resolved) fprintf(outfile, " WRT ..plt"); fprintf(outfile, "\n"); /* 4. `mov dst, rax` */ @@ -732,7 +722,7 @@ static void emit_return(FILE* outfile, const struct return_node* node) { outfile, node->ret_val, &(struct lval_def) { - .type = &active_fn->return_type, + .type = active_fn->type->fn.return_type, .loc = { .type = STO_REG, .reg = RV_REG, @@ -849,21 +839,24 @@ static void emit_stmt(FILE* outfile, const struct stmt_node* node) { } static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { - if (node->body == NULL) return; + if (!scope_get_var(scope, &active_fn, node->name)) + CGEN_PANIC("scopes are borked, missing symbol: '%s'", node->name); - if (active_fn != NULL) - CGEN_PANIC( - "can't define function %s inside function %s", - node->name, - active_fn->name); - active_fn = node; + const char* label = node->name; + active_fn->storage = (struct storage_location) { + .type = STO_LABEL, + .label = label, + }; - /* TODO: we need to account for the base pointer moving in var locs */ - fprintf(outfile, "%s:\n", node->name); - fprintf(outfile, "\tpush rbp\n"); - fprintf(outfile, "\tmov rbp, rsp\n"); + if (node->body == NULL) { + active_fn = NULL; + return; + } enter_scope(node->scope, 0); + fprintf(outfile, "%s:\n", label); + fprintf(outfile, "\tpush rbp\n"); + fprintf(outfile, "\tmov rbp, rsp\n"); sintegral_t spilled_bp_ofs = -16; // return address + spilled rbp struct arg_decl_node* arg_decl = node->args; @@ -872,7 +865,7 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { fprintf(outfile, "\t; %s\n", arg_def->name); struct lval_def arg_dst = allocate_stack(outfile, arg_def->type); - arg_def->loc = arg_dst.loc; + arg_def->storage = arg_dst.loc; struct storage_location arg_src; if (CALLING_CONV[i] != NULL) { @@ -900,8 +893,8 @@ static void emit_fn_decl(FILE* outfile, const struct fn_decl_node* node) { fprintf(outfile, "\tpop rbp\n"); fprintf(outfile, "\tret\n"); - active_fn = NULL; exit_scope(node->scope, false); + active_fn = NULL; } static void emit_root_node(FILE* outfile, const struct root_node* node) { @@ -924,7 +917,11 @@ void emit_code(struct ast* ast, const char* path) { for (; node != NULL; node = node->next) { if (node->type != ROOT_FN_DECL) continue; const struct fn_decl_node* fn = &node->inner.fn_decl; - if (fn->body != NULL) + struct var_def* fn_def; + if (!scope_get_var(scope, &fn_def, fn->name)) + CGEN_PANIC("use of undeclared function '%s'", fn->name); + + if (fn_def->fn.resolved) fprintf(outfile, "global %s\n", fn->name); else fprintf(outfile, "extern %s\n", fn->name); |
