From 64d1015a3ce1be2c6df1abb495c4298750682332 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Mon, 28 Apr 2025 15:44:44 +0100 Subject: [PATCH] lang: codegen: implement cond-group code generation --- lang/codegen/codegen.c | 4 +- lang/codegen/codegen.h | 2 + lang/codegen/cond-group.c | 88 +++++++++++++++++++++++++ lang/codegen/cond.c | 132 ++++++++++++++++++++++++++++++++++++++ lang/codegen/expr.c | 90 ++++++++++++++++++++++---- lang/codegen/generator.c | 4 ++ lang/codegen/unit.c | 26 ++++++-- lang/codegen/var.c | 3 +- 8 files changed, 327 insertions(+), 22 deletions(-) create mode 100644 lang/codegen/cond-group.c create mode 100644 lang/codegen/cond.c diff --git a/lang/codegen/codegen.c b/lang/codegen/codegen.c index f4dac1e..de0b971 100644 --- a/lang/codegen/codegen.c +++ b/lang/codegen/codegen.c @@ -239,7 +239,7 @@ static struct code_generator_state *get_current_generator_state( return b_unbox(struct code_generator_state, entry, s_entry); } -enum ivy_status ivy_codegen_create(struct ivy_codegen **out) +enum ivy_status ivy_codegen_create(struct mie_ctx *ctx, struct ivy_codegen **out) { struct ivy_codegen *gen = malloc(sizeof *gen); if (!gen) { @@ -248,7 +248,7 @@ enum ivy_status ivy_codegen_create(struct ivy_codegen **out) memset(gen, 0x0, sizeof *gen); - gen->c_ctx = mie_ctx_create(); + gen->c_ctx = ctx; *out = gen; return IVY_OK; diff --git a/lang/codegen/codegen.h b/lang/codegen/codegen.h index cd1ad29..adfa6c2 100644 --- a/lang/codegen/codegen.h +++ b/lang/codegen/codegen.h @@ -45,6 +45,8 @@ enum code_generator_type { CODE_GENERATOR_FSTRING, CODE_GENERATOR_LAMBDA, CODE_GENERATOR_RETURN, + CODE_GENERATOR_COND_GROUP, + CODE_GENERATOR_COND, }; enum code_generator_scope_type { diff --git a/lang/codegen/cond-group.c b/lang/codegen/cond-group.c new file mode 100644 index 0000000..a825c57 --- /dev/null +++ b/lang/codegen/cond-group.c @@ -0,0 +1,88 @@ +#include "../debug.h" +#include "codegen.h" + +#include +#include +#include +#include +#include +#include + +struct cond_group_codegen_state { + struct code_generator_state s_base; + struct mie_block *s_end; +}; + +static struct code_generator_result gen_cond_group( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node, size_t depth) +{ + struct cond_group_codegen_state *group + = (struct cond_group_codegen_state *)state; + + return CODEGEN_RESULT_OK(0); +} + +static struct code_generator_result gen_cond( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node, size_t depth) +{ + struct cond_group_codegen_state *group + = (struct cond_group_codegen_state *)state; + + codegen_push_generator(gen, CODE_GENERATOR_COND, 0, group->s_end); + return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE); +} + +static enum ivy_status state_init( + struct ivy_codegen *gen, struct code_generator_state *state, + uintptr_t argv, void *argp) +{ + debug_printf("codegen: start of cond group\n"); + struct cond_group_codegen_state *group + = (struct cond_group_codegen_state *)state; + struct mie_func *func = mie_builder_get_current_func(gen->c_builder); + group->s_end = mie_func_create_block(func, "if.end"); + return IVY_OK; +} + +static enum ivy_status state_fini( + struct ivy_codegen *gen, struct code_generator_state *state, + struct mie_value **result) +{ + debug_printf("codegen: end of cond group\n"); + struct cond_group_codegen_state *group + = (struct cond_group_codegen_state *)state; + struct mie_func *func = mie_builder_get_current_func(gen->c_builder); + struct mie_block *block = mie_builder_get_current_block(gen->c_builder); + + if (!block->b_terminator) { + mie_builder_br(gen->c_builder, group->s_end); + } + + mie_func_insert_block(func, group->s_end, NULL); + mie_builder_set_insert_point(gen->c_builder, group->s_end); + + return IVY_OK; +} + +static struct code_generator_result value_received( + struct ivy_codegen *gen, struct code_generator_state *state, + struct mie_value *value) +{ + struct cond_group_codegen_state *cond + = (struct cond_group_codegen_state *)state; + return CODEGEN_RESULT_OK(0); +} + +struct code_generator cond_group_generator = { + .g_type = CODE_GENERATOR_COND_GROUP, + .g_state_size = sizeof(struct cond_group_codegen_state), + .g_state_init = state_init, + .g_state_fini = state_fini, + .g_value_received = value_received, + .g_node_generators = { + NODE_CODEGEN(COND_GROUP, gen_cond_group), + NODE_CODEGEN(COND, gen_cond), + }, +}; diff --git a/lang/codegen/cond.c b/lang/codegen/cond.c new file mode 100644 index 0000000..23d1038 --- /dev/null +++ b/lang/codegen/cond.c @@ -0,0 +1,132 @@ +#include "../debug.h" +#include "codegen.h" + +#include +#include +#include +#include + +struct cond_codegen_state { + struct code_generator_state s_base; + struct mie_value *s_cond; + struct mie_block *s_true; + struct mie_block *s_false; + struct mie_block *s_end; +}; + +static struct code_generator_result gen_cond( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node, size_t depth) +{ + struct cond_codegen_state *cond = (struct cond_codegen_state *)state; + return CODEGEN_RESULT_OK(0); +} + +static struct code_generator_result gen_expr( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node, size_t depth) +{ + struct cond_codegen_state *cond = (struct cond_codegen_state *)state; + struct mie_func *func = mie_builder_get_current_func(gen->c_builder); + /* this is either the if-condition, or the if-body for an inline + * if-statement */ + + if (cond->s_cond) { + cond->s_true = mie_func_create_block(func, "if.true"); + cond->s_false = mie_func_create_block(func, "if.false"); + + mie_builder_br_if( + gen->c_builder, cond->s_cond, cond->s_true, cond->s_false); + mie_func_insert_block(func, cond->s_true, NULL); + mie_builder_set_insert_point(gen->c_builder, cond->s_true); + } + + codegen_push_generator(gen, CODE_GENERATOR_EXPR, 0, NULL); + + return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE); +} + +static struct code_generator_result gen_block( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node, size_t depth) +{ + struct cond_codegen_state *cond = (struct cond_codegen_state *)state; + struct mie_func *func = mie_builder_get_current_func(gen->c_builder); + + if (cond->s_cond) { + cond->s_true = mie_func_create_block(func, "if.true"); + cond->s_false = mie_func_create_block(func, "if.false"); + + mie_builder_br_if( + gen->c_builder, cond->s_cond, cond->s_true, cond->s_false); + mie_func_insert_block(func, cond->s_true, NULL); + mie_builder_set_insert_point(gen->c_builder, cond->s_true); + } + + codegen_push_generator(gen, CODE_GENERATOR_BLOCK, 0, NULL); + return CODEGEN_RESULT_OK(0); +} + +static enum ivy_status state_init( + struct ivy_codegen *gen, struct code_generator_state *state, + uintptr_t argv, void *argp) +{ + debug_printf("codegen: start of cond\n"); + struct cond_codegen_state *cond = (struct cond_codegen_state *)state; + cond->s_end = argp; + return IVY_OK; +} + +static enum ivy_status state_fini( + struct ivy_codegen *gen, struct code_generator_state *state, + struct mie_value **result) +{ + debug_printf("codegen: end of cond\n"); + struct cond_codegen_state *cond = (struct cond_codegen_state *)state; + struct mie_func *func = mie_builder_get_current_func(gen->c_builder); + + mie_builder_br(gen->c_builder, cond->s_end); + + if (cond->s_false) { + mie_func_insert_block(func, cond->s_false, NULL); + mie_builder_set_insert_point(gen->c_builder, cond->s_false); + } + + return IVY_OK; +} + +static struct code_generator_result value_received( + struct ivy_codegen *gen, struct code_generator_state *state, + struct mie_value *value) +{ + struct cond_codegen_state *cond = (struct cond_codegen_state *)state; + if (!value) { + return CODEGEN_RESULT_OK(0); + } + + struct mie_type *cond_type = mie_value_get_type(value, gen->c_ctx); + + if (cond_type->t_id == MIE_TYPE_INT && cond_type->t_width == 1) { + /* this is already a boolean */ + cond->s_cond = value; + } else { + struct mie_value *zero = mie_ctx_get_int(gen->c_ctx, 0, 32); + struct mie_value *cmp + = mie_builder_cmp_neq(gen->c_builder, value, zero, NULL); + cond->s_cond = cmp; + } + + return CODEGEN_RESULT_OK(0); +} + +struct code_generator cond_generator + = {.g_type = CODE_GENERATOR_COND, + .g_state_size = sizeof(struct cond_codegen_state), + .g_state_init = state_init, + .g_state_fini = state_fini, + .g_value_received = value_received, + .g_expr_generator = gen_expr, + .g_node_generators = { + NODE_CODEGEN(COND, gen_cond), + NODE_CODEGEN(BLOCK, gen_block), + }}; diff --git a/lang/codegen/expr.c b/lang/codegen/expr.c index df1e5a3..556e149 100644 --- a/lang/codegen/expr.c +++ b/lang/codegen/expr.c @@ -11,10 +11,17 @@ enum expr_item_type { EXPR_OPERAND, }; +enum expr_operand_type { + EXPR_OPERAND_OTHER, + EXPR_OPERAND_VAR, +}; + struct expr_item { b_queue_entry i_entry; enum expr_item_type i_type; + enum expr_operand_type i_operand_type; struct ivy_ast_node *i_node; + struct codegen_var i_var; struct mie_value *i_value; }; @@ -41,7 +48,7 @@ static struct code_generator_result check_expr_root( static enum ivy_status push_operand( struct expr_codegen_state *expr, struct ivy_ast_node *node, - struct mie_value *value) + struct mie_value *value, const struct codegen_var *var) { struct expr_item *item = malloc(sizeof *item); if (!item) { @@ -54,6 +61,11 @@ static enum ivy_status push_operand( item->i_node = node; item->i_value = value; + if (var) { + memcpy(&item->i_var, var, sizeof item->i_var); + item->i_operand_type = EXPR_OPERAND_VAR; + } + b_queue_push_back(&expr->s_item_queue, &item->i_entry); return IVY_OK; } @@ -85,7 +97,7 @@ static struct code_generator_result gen_int( 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); - enum ivy_status status = push_operand(expr, node, value); + enum ivy_status status = push_operand(expr, node, value, NULL); if (status != IVY_OK) { return CODEGEN_RESULT_ERR(status); } @@ -108,7 +120,7 @@ static struct code_generator_result gen_string( struct mie_type *str = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_STR); struct mie_value *var_value = mie_builder_load(gen->c_builder, str, var_ptr, NULL); - enum ivy_status status = push_operand(expr, node, var_value); + enum ivy_status status = push_operand(expr, node, var_value, NULL); if (status != IVY_OK) { return CODEGEN_RESULT_ERR(status); @@ -199,12 +211,8 @@ static struct code_generator_result gen_var_reference( struct mie_value *var_value = mie_builder_load(gen->c_builder, id, var_ptr, NULL); #endif - struct mie_value *var_value = codegen_load_variable(gen, &var); - if (!var_value) { - return CODEGEN_RESULT_ERR(IVY_ERR_INTERNAL_FAILURE); - } - status = push_operand(expr, node, var_value); + status = push_operand(expr, node, NULL, &var); if (status != IVY_OK) { return CODEGEN_RESULT_ERR(status); @@ -213,6 +221,14 @@ static struct code_generator_result gen_var_reference( return CODEGEN_RESULT_OK(0); } +static struct code_generator_result gen_cond_group( + struct ivy_codegen *gen, struct code_generator_state *state, + struct ivy_ast_node *node, size_t depth) +{ + codegen_push_generator(gen, CODE_GENERATOR_COND_GROUP, 0, NULL); + return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE); +} + #if 0 static struct code_generator_result gen_var_ref( struct ivy_codegen *gen, struct code_generator_state *state, @@ -363,29 +379,70 @@ static enum ivy_status state_fini( struct expr_item *right = b_unbox(struct expr_item, right_entry, i_entry); + struct mie_value *left_value = left->i_value; + struct mie_value *right_value = left->i_value; + + if (left->i_operand_type == EXPR_OPERAND_VAR) { + left_value = codegen_load_variable(gen, &left->i_var); + } + + if (right->i_operand_type == EXPR_OPERAND_VAR) { + right_value = codegen_load_variable(gen, &right->i_var); + } + struct mie_value *op_value = NULL; switch (op->n_op->op_id) { case IVY_OP_ADD: op_value = mie_builder_add( - gen->c_builder, left->i_value, right->i_value, + gen->c_builder, left_value, right_value, "addtmp"); break; case IVY_OP_SUBTRACT: op_value = mie_builder_sub( - gen->c_builder, left->i_value, right->i_value, + gen->c_builder, left_value, right_value, "subtmp"); break; case IVY_OP_MULTIPLY: op_value = mie_builder_mul( - gen->c_builder, left->i_value, right->i_value, + gen->c_builder, left_value, right_value, "multmp"); break; case IVY_OP_DIVIDE: op_value = mie_builder_div( - gen->c_builder, left->i_value, right->i_value, + gen->c_builder, left_value, right_value, "divtmp"); break; + case IVY_OP_EQUAL: + op_value = mie_builder_cmp_eq( + gen->c_builder, left_value, right_value, + "cmptmp"); + break; + case IVY_OP_NOT_EQUAL: + op_value = mie_builder_cmp_neq( + gen->c_builder, left_value, right_value, + "cmptmp"); + break; + case IVY_OP_LESS_THAN: + op_value = mie_builder_cmp_lt( + gen->c_builder, left_value, right_value, + "cmptmp"); + break; + case IVY_OP_LESS_EQUAL: + op_value = mie_builder_cmp_leq( + gen->c_builder, left_value, right_value, + "cmptmp"); + break; + case IVY_OP_GREATER_THAN: + op_value = mie_builder_cmp_gt( + gen->c_builder, left_value, right_value, + "cmptmp"); + break; + case IVY_OP_GREATER_EQUAL: + op_value = mie_builder_cmp_geq( + gen->c_builder, left_value, right_value, + "cmptmp"); + break; default: return IVY_ERR_NOT_SUPPORTED; } @@ -407,7 +464,11 @@ static enum ivy_status state_fini( } struct expr_item *result_item = b_unbox(struct expr_item, cur, i_entry); - *result = result_item->i_value; + if (result_item->i_operand_type == EXPR_OPERAND_VAR) { + *result = codegen_load_variable(gen, &result_item->i_var); + } else { + *result = result_item->i_value; + } free(result_item); return IVY_OK; @@ -420,7 +481,7 @@ static struct code_generator_result value_received( struct expr_codegen_state *expr = (struct expr_codegen_state *)state; debug_printf("codegen: got sub-expr\n"); - enum ivy_status status = push_operand(expr, NULL, value); + enum ivy_status status = push_operand(expr, NULL, value, NULL); if (status != IVY_OK) { return CODEGEN_RESULT_ERR(status); } @@ -442,5 +503,6 @@ struct code_generator expr_generator = { NODE_CODEGEN(STRING, gen_string), NODE_CODEGEN(FSTRING, gen_fstring), NODE_CODEGEN(IDENT, gen_var_reference), + NODE_CODEGEN(COND_GROUP, gen_cond_group), }, }; diff --git a/lang/codegen/generator.c b/lang/codegen/generator.c index 602bdb5..4297812 100644 --- a/lang/codegen/generator.c +++ b/lang/codegen/generator.c @@ -10,6 +10,8 @@ extern const struct code_generator msg_generator; extern const struct code_generator fstring_generator; extern const struct code_generator lambda_generator; extern const struct code_generator return_generator; +extern const struct code_generator cond_generator; +extern const struct code_generator cond_group_generator; static const struct code_generator *code_generators[] = { [CODE_GENERATOR_UNIT] = &unit_generator, @@ -20,6 +22,8 @@ static const struct code_generator *code_generators[] = { [CODE_GENERATOR_FSTRING] = &fstring_generator, [CODE_GENERATOR_LAMBDA] = &lambda_generator, [CODE_GENERATOR_RETURN] = &return_generator, + [CODE_GENERATOR_COND] = &cond_generator, + [CODE_GENERATOR_COND_GROUP] = &cond_group_generator, }; static const size_t nr_code_generators = sizeof code_generators / sizeof code_generators[0]; diff --git a/lang/codegen/unit.c b/lang/codegen/unit.c index 31c6774..d5e851f 100644 --- a/lang/codegen/unit.c +++ b/lang/codegen/unit.c @@ -9,6 +9,10 @@ #include #include +enum { + ENSURE_OPEN_BLOCK = 0x01u, +}; + struct unit_codegen_state { struct code_generator_state s_base; struct code_generator_scope *s_scope; @@ -19,7 +23,7 @@ struct unit_codegen_state { }; static enum ivy_status switch_to_immediate_func( - struct ivy_codegen *gen, struct unit_codegen_state *unit) + struct ivy_codegen *gen, struct unit_codegen_state *unit, long flags) { if (!unit->s_immediate) { struct mie_type *ret_type @@ -46,7 +50,7 @@ static enum ivy_status switch_to_immediate_func( mie_func_insert_block(unit->s_immediate, block, NULL); } - if (mie_block_is_terminated(block)) { + if (mie_block_is_terminated(block) && (flags & ENSURE_OPEN_BLOCK)) { block = mie_func_create_block(unit->s_immediate, NULL); mie_func_insert_block(unit->s_immediate, block, NULL); } @@ -82,7 +86,7 @@ static struct code_generator_result gen_expr( enum ivy_status status = IVY_OK; if (!current || current != unit->s_immediate) { - status = switch_to_immediate_func(gen, unit); + status = switch_to_immediate_func(gen, unit, ENSURE_OPEN_BLOCK); } if (status != IVY_OK) { @@ -172,7 +176,7 @@ static struct code_generator_result gen_var_declaration( enum ivy_status status = IVY_OK; if (!current || current != unit->s_immediate) { - status = switch_to_immediate_func(gen, unit); + status = switch_to_immediate_func(gen, unit, ENSURE_OPEN_BLOCK); } if (status != IVY_OK) { @@ -193,7 +197,7 @@ static struct code_generator_result gen_return( enum ivy_status status = IVY_OK; if (!current || current != unit->s_immediate) { - status = switch_to_immediate_func(gen, unit); + status = switch_to_immediate_func(gen, unit, ENSURE_OPEN_BLOCK); } if (status != IVY_OK) { @@ -258,6 +262,18 @@ static enum ivy_status state_fini( struct unit_codegen_state *unit = (struct unit_codegen_state *)state; codegen_var_map_fini(&unit->s_vars); + struct mie_func *current = mie_builder_get_current_func(gen->c_builder); + + enum ivy_status status = IVY_OK; + if (!current || current != unit->s_immediate) { + status = switch_to_immediate_func(gen, unit, 0); + } + + struct mie_block *block = mie_builder_get_current_block(gen->c_builder); + if (!block->b_terminator) { + mie_builder_ret(gen->c_builder, NULL); + } + return IVY_OK; } diff --git a/lang/codegen/var.c b/lang/codegen/var.c index eca700e..405958d 100644 --- a/lang/codegen/var.c +++ b/lang/codegen/var.c @@ -109,7 +109,7 @@ static enum ivy_status state_fini( const char *ident = var->s_var_ident->n_content->t_str; struct mie_type *type = NULL; if (var->s_value) { - type = mie_value_get_type(var->s_value); + type = mie_value_get_type(var->s_value, gen->c_ctx); } else { type = mie_ctx_get_type(gen->c_ctx, MIE_TYPE_ID); } @@ -117,6 +117,7 @@ static enum ivy_status state_fini( struct codegen_var var_info = { .v_node = (struct ivy_ast_node *)var->s_var_ident, .v_type = type, + .v_flags = CODEGEN_VAR_F_PTR, .v_value = var->s_var_ptr, };