From 670b7c5a337939e993022ffca535607e67fcfec6 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Mon, 14 Apr 2025 20:15:05 +0100 Subject: [PATCH] lang: codegen: redesign codegen to use a stack-based state machine --- lang/codegen/codegen.c | 141 ++++++++++++++++++++++++++++++++ lang/codegen/codegen.h | 73 ++++++++++++++++- lang/codegen/expr.c | 127 ++++++++++++++++++++++++++++ lang/codegen/generator.c | 20 +++++ lang/codegen/try.c | 12 +++ lang/codegen/unit.c | 68 +++++++++++++++ lang/include/ivy/lang/codegen.h | 5 +- 7 files changed, 442 insertions(+), 4 deletions(-) create mode 100644 lang/codegen/expr.c create mode 100644 lang/codegen/generator.c create mode 100644 lang/codegen/try.c create mode 100644 lang/codegen/unit.c diff --git a/lang/codegen/codegen.c b/lang/codegen/codegen.c index 2268530..23bbcaa 100644 --- a/lang/codegen/codegen.c +++ b/lang/codegen/codegen.c @@ -3,9 +3,98 @@ #include #include #include +#include #include #include +enum ivy_status codegen_push_generator( + struct ivy_codegen *gen, enum code_generator_type gen_type, void *arg) +{ + const struct code_generator *generator = get_code_generator(gen_type); + if (!generator) { + return IVY_ERR_INVALID_VALUE; + } + + if (generator->g_state_size < sizeof(struct code_generator_state)) { + return IVY_ERR_INTERNAL_FAILURE; + } + + struct code_generator_state *state = malloc(generator->g_state_size); + if (!state) { + return IVY_ERR_NO_MEMORY; + } + + memset(state, 0x0, generator->g_state_size); + + state->s_gen = generator; + state->s_arg = arg; + + enum ivy_status status = IVY_OK; + + if (generator->g_state_init) { + status = generator->g_state_init(gen, state); + } + + if (status != IVY_OK) { + free(state); + return status; + } + + b_queue_push_back(&gen->c_state, &state->s_entry); + + return IVY_OK; +} + +enum ivy_status codegen_pop_generator(struct ivy_codegen *gen) +{ + b_queue_entry *entry = b_queue_pop_back(&gen->c_state); + if (!entry) { + return IVY_ERR_BAD_STATE; + } + + struct code_generator_state *state + = b_unbox(struct code_generator_state, entry, s_entry); + + enum ivy_status status = IVY_OK; + + if (state->s_gen->g_state_fini) { + status = state->s_gen->g_state_fini(gen, state); + } + + if (status != IVY_OK) { + return status; + } + + free(state); + return IVY_OK; +} + +void codegen_push_value(struct ivy_codegen *gen, struct mie_value *value) +{ + b_queue_push_back(&gen->c_ir_values, &value->v_entry); +} + +struct mie_value *codegen_pop_value(struct ivy_codegen *gen) +{ + b_queue_entry *entry = b_queue_pop_back(&gen->c_ir_values); + if (!entry) { + return NULL; + } + + return b_unbox(struct mie_value, entry, v_entry); +} + +static struct code_generator_state *get_current_generator_state( + struct ivy_codegen *gen) +{ + b_queue_entry *entry = b_queue_last(&gen->c_state); + if (!entry) { + return NULL; + } + + return b_unbox(struct code_generator_state, entry, s_entry); +} + enum ivy_status ivy_codegen_create(struct ivy_codegen **out) { struct ivy_codegen *gen = malloc(sizeof *gen); @@ -17,6 +106,8 @@ enum ivy_status ivy_codegen_create(struct ivy_codegen **out) gen->c_ctx = mie_ctx_create(); + codegen_push_generator(gen, CODE_GENERATOR_UNIT, NULL); + *out = gen; return IVY_OK; } @@ -67,3 +158,53 @@ enum ivy_status ivy_codegen_end_module( return IVY_OK; } + +struct mie_module *ivy_codegen_get_current_module(struct ivy_codegen *gen) +{ + return gen->c_module; +} + +enum ivy_status ivy_codegen_push_node( + struct ivy_codegen *gen, struct ivy_ast_node *node, + enum ivy_ast_iteration_type node_type) +{ + if (!gen->c_builder) { + return IVY_ERR_BAD_STATE; + } + + while (true) { + struct code_generator_state *state + = get_current_generator_state(gen); + + if (!state) { + return IVY_ERR_BAD_STATE; + } + + const struct code_generator *generator = state->s_gen; + + code_generator_node_callback func; + switch (node_type) { + case IVY_AST_ITERATION_PRE: + func = generator->g_node_generators_pre[node->n_type]; + break; + case IVY_AST_ITERATION_POST: + func = generator->g_node_generators_post[node->n_type]; + break; + default: + return IVY_ERR_INVALID_VALUE; + } + + if (!func) { + return IVY_ERR_INVALID_VALUE; + } + + struct code_generator_result result = func(gen, state, node); + if (result.r_flags & CODEGEN_REPEAT_NODE) { + continue; + } + + return result.r_status; + } + + return IVY_OK; +} diff --git a/lang/codegen/codegen.h b/lang/codegen/codegen.h index 4b52a9f..057b9da 100644 --- a/lang/codegen/codegen.h +++ b/lang/codegen/codegen.h @@ -2,17 +2,84 @@ #define _LANG_CODEGEN_H_ #include +#include +#include +#include -struct mie_builder; -struct mie_ctx; +#define CODEGEN_RESULT_OK(flags) \ + (struct code_generator_result) \ + { \ + .r_status = (IVY_OK), .r_flags = (flags) \ + } +#define CODEGEN_RESULT_ERR(status) \ + (struct code_generator_result) \ + { \ + .r_status = (status), .r_flags = (0) \ + } + +struct ivy_codegen; +struct ivy_ast_node; + +struct mie_value; struct mie_func; +enum code_generator_type { + CODE_GENERATOR_NONE = 0, + CODE_GENERATOR_UNIT, + CODE_GENERATOR_EXPR, +}; + +struct code_generator_result { + enum ivy_status r_status; + + enum code_generator_result_flags { + CODEGEN_REPEAT_NODE = 0x01u, + } r_flags; +}; + +struct code_generator_state; + +typedef enum ivy_status (*code_generator_state_init_callback)( + struct ivy_codegen *, struct code_generator_state *); +typedef enum ivy_status (*code_generator_state_fini_callback)( + struct ivy_codegen *, struct code_generator_state *); +typedef struct code_generator_result (*code_generator_callback)( + struct ivy_codegen *); +typedef struct code_generator_result (*code_generator_node_callback)( + struct ivy_codegen *, struct code_generator_state *, struct ivy_ast_node *); + +struct code_generator { + enum code_generator_type g_type; + size_t g_state_size; + + code_generator_state_init_callback g_state_init; + code_generator_state_fini_callback g_state_fini; + code_generator_node_callback g_node_generators_pre[IVY_AST_TYPE_COUNT]; + code_generator_node_callback g_node_generators_post[IVY_AST_TYPE_COUNT]; +}; + +struct code_generator_state { + b_queue_entry s_entry; + void *s_arg; + const struct code_generator *s_gen; +}; + struct ivy_codegen { b_queue c_ir_values; + b_queue c_state; struct mie_builder *c_builder; struct mie_ctx *c_ctx; struct mie_module *c_module; - struct mie_func *c_immediate; }; +extern const struct code_generator *get_code_generator( + enum code_generator_type type); + +extern enum ivy_status codegen_push_generator( + struct ivy_codegen *gen, enum code_generator_type gen_type, void *arg); +extern enum ivy_status codegen_pop_generator(struct ivy_codegen *gen); + +extern void codegen_push_value(struct ivy_codegen *gen, struct mie_value *value); +extern struct mie_value *codegen_pop_value(struct ivy_codegen *gen); + #endif diff --git a/lang/codegen/expr.c b/lang/codegen/expr.c new file mode 100644 index 0000000..370f3d6 --- /dev/null +++ b/lang/codegen/expr.c @@ -0,0 +1,127 @@ +#include "codegen.h" + +#include + +struct expr_codegen_state { + struct code_generator_state s_base; + struct ivy_ast_node *s_expr_root; +}; + +static struct code_generator_result check_expr_root( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node) +{ + struct expr_codegen_state *expr = (struct expr_codegen_state *)state; + if (!expr->s_expr_root) { + expr->s_expr_root = node; + } + + return CODEGEN_RESULT_OK(0); +} + +static struct code_generator_result gen_int( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node) +{ + struct expr_codegen_state *expr = (struct expr_codegen_state *)state; + + printf("codegen: got int\n"); + + struct ivy_ast_int_node *int_node = (struct ivy_ast_int_node *)node; + struct mie_value *value + = mie_ctx_get_int(gen->c_ctx, int_node->n_value->t_int, 32); + + codegen_push_value(gen, value); + + if (node == expr->s_expr_root) { + codegen_pop_generator(gen); + } + + return CODEGEN_RESULT_OK(0); +} + +static struct code_generator_result gen_op( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node) +{ + struct expr_codegen_state *expr = (struct expr_codegen_state *)state; + + printf("codegen: got operator\n"); + + struct mie_value *left = codegen_pop_value(gen); + struct mie_value *right = codegen_pop_value(gen); + + if (!left || !right) { + return CODEGEN_RESULT_ERR(IVY_ERR_INVALID_VALUE); + } + + struct ivy_ast_op_node *op_node = (struct ivy_ast_op_node *)node; + const struct ivy_operator *op = op_node->n_op; + struct mie_value *op_instr = NULL; + + switch (op->op_id) { + case IVY_OP_ADD: + op_instr + = mie_builder_add(gen->c_builder, left, right, "addtmp"); + break; + case IVY_OP_SUBTRACT: + op_instr + = mie_builder_sub(gen->c_builder, left, right, "subtmp"); + break; + case IVY_OP_MULTIPLY: + op_instr + = mie_builder_mul(gen->c_builder, left, right, "multmp"); + break; + case IVY_OP_DIVIDE: + op_instr + = mie_builder_div(gen->c_builder, left, right, "divtmp"); + break; + default: + mie_value_destroy(left); + mie_value_destroy(right); + return CODEGEN_RESULT_ERR(IVY_ERR_NOT_SUPPORTED); + } + + if (!op_instr) { + mie_value_destroy(left); + mie_value_destroy(right); + return CODEGEN_RESULT_ERR(IVY_ERR_NO_MEMORY); + } + + codegen_push_value(gen, op_instr); + + if (node == expr->s_expr_root) { + codegen_pop_generator(gen); + } + + return CODEGEN_RESULT_OK(0); +} + +static enum ivy_status state_init( + struct ivy_codegen *gen, struct code_generator_state *state) +{ + printf("codegen: start of expression\n"); + return IVY_OK; +} + +static enum ivy_status state_fini( + struct ivy_codegen *gen, struct code_generator_state *state) +{ + printf("codegen: end of expression\n"); + return IVY_OK; +} + +struct code_generator expr_generator = { + .g_type = CODE_GENERATOR_UNIT, + .g_state_size = sizeof(struct expr_codegen_state), + .g_state_init = state_init, + .g_state_fini = state_fini, + .g_node_generators_pre = { + [IVY_AST_INT] = check_expr_root, + [IVY_AST_OP] = check_expr_root, + }, + .g_node_generators_post = { + [IVY_AST_INT] = gen_int, + [IVY_AST_OP] = gen_op, + }, +}; diff --git a/lang/codegen/generator.c b/lang/codegen/generator.c new file mode 100644 index 0000000..9eadb36 --- /dev/null +++ b/lang/codegen/generator.c @@ -0,0 +1,20 @@ +#include "codegen.h" + +extern const struct code_generator unit_generator; +extern const struct code_generator expr_generator; + +static const struct code_generator *code_generators[] = { + [CODE_GENERATOR_UNIT] = &unit_generator, + [CODE_GENERATOR_EXPR] = &expr_generator, +}; +static const size_t nr_code_generators + = sizeof code_generators / sizeof code_generators[0]; + +const struct code_generator *get_code_generator(enum code_generator_type type) +{ + if (type >= nr_code_generators) { + return NULL; + } + + return code_generators[type]; +} diff --git a/lang/codegen/try.c b/lang/codegen/try.c new file mode 100644 index 0000000..6e4fff6 --- /dev/null +++ b/lang/codegen/try.c @@ -0,0 +1,12 @@ +#include "codegen.h" + +enum ivy_status try_code_generator(struct ivy_codegen *gen, struct ivy_ast_node *node) +{ + return IVY_ERR_NOT_SUPPORTED; +} + +enum ivy_status try_catch_code_generator( + struct ivy_codegen *gen, struct ivy_ast_node *node) +{ + return IVY_ERR_NOT_SUPPORTED; +} diff --git a/lang/codegen/unit.c b/lang/codegen/unit.c new file mode 100644 index 0000000..6dd9c69 --- /dev/null +++ b/lang/codegen/unit.c @@ -0,0 +1,68 @@ +#include "codegen.h" + +#include +#include +#include + +struct unit_codegen_state { + struct code_generator_state s_base; + /* function for top-level statements */ + struct mie_func *s_immediate; +}; + +static enum ivy_status switch_to_immediate_func( + struct ivy_codegen *gen, struct unit_codegen_state *unit) +{ + if (!unit->s_immediate) { + struct mie_type *ret_type + = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_VOID); + unit->s_immediate = mie_func_create( + "init", MIE_FUNC_STATIC, ret_type, NULL, 0); + + if (!unit->s_immediate) { + return IVY_ERR_NO_MEMORY; + } + + mie_module_add_function(gen->c_module, unit->s_immediate); + } + + struct mie_block *block = mie_func_get_last_block(unit->s_immediate); + if (!block || mie_block_is_terminated(block)) { + block = mie_func_create_block(unit->s_immediate, NULL); + mie_func_insert_block(unit->s_immediate, block, NULL); + } + + mie_builder_set_insert_point(gen->c_builder, block); + + return IVY_OK; +} + +static struct code_generator_result gen_expr( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node) +{ + struct unit_codegen_state *unit = (struct unit_codegen_state *)state; + struct mie_builder *builder = gen->c_builder; + struct mie_func *current = mie_builder_get_current_func(builder); + + enum ivy_status status = IVY_OK; + if (!current || current != unit->s_immediate) { + status = switch_to_immediate_func(gen, unit); + } + + if (status != IVY_OK) { + return CODEGEN_RESULT_ERR(status); + } + + codegen_push_generator(gen, CODE_GENERATOR_EXPR, NULL); + return CODEGEN_RESULT_OK(CODEGEN_REPEAT_NODE); +} + +struct code_generator unit_generator = { + .g_type = CODE_GENERATOR_UNIT, + .g_state_size = sizeof(struct unit_codegen_state), + .g_node_generators_pre = { + [IVY_AST_INT] = gen_expr, + [IVY_AST_OP] = gen_expr, + }, +}; diff --git a/lang/include/ivy/lang/codegen.h b/lang/include/ivy/lang/codegen.h index 9667626..8d24de0 100644 --- a/lang/include/ivy/lang/codegen.h +++ b/lang/include/ivy/lang/codegen.h @@ -6,6 +6,7 @@ struct ivy_codegen; struct ivy_ast_node; +enum ivy_ast_iteration_type; struct mie_module; @@ -15,8 +16,10 @@ IVY_API void ivy_codegen_destroy(struct ivy_codegen *gen); IVY_API enum ivy_status ivy_codegen_start_module(struct ivy_codegen *gen); IVY_API enum ivy_status ivy_codegen_end_module( struct ivy_codegen *gen, struct mie_module **out); +IVY_API struct mie_module *ivy_codegen_get_current_module(struct ivy_codegen *gen); IVY_API enum ivy_status ivy_codegen_push_node( - struct ivy_codegen *gen, struct ivy_ast_node *node); + struct ivy_codegen *gen, struct ivy_ast_node *node, + enum ivy_ast_iteration_type node_type); #endif