From 68ca789e431117335e1f8dec5b3f1d3927fe15f5 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Mon, 8 Sep 2025 16:24:29 +0100 Subject: [PATCH] lang: codegen: cond: implement implicitly returning values from an if-else expression --- lang/codegen/cond-group.c | 86 +++++++++++++++++++++++++++++++++++++++ lang/codegen/cond.c | 63 +++++++++++++++++++--------- 2 files changed, 130 insertions(+), 19 deletions(-) diff --git a/lang/codegen/cond-group.c b/lang/codegen/cond-group.c index 13ef730..c18446c 100644 --- a/lang/codegen/cond-group.c +++ b/lang/codegen/cond-group.c @@ -1,8 +1,10 @@ #include "../debug.h" #include "codegen.h" +#include #include #include +#include #include #include #include @@ -11,6 +13,7 @@ struct cond_group_codegen_state { struct code_generator_state s_base; struct mie_block *s_end; + b_queue s_edges; }; static struct code_generator_result gen_cond_group( @@ -46,6 +49,65 @@ static enum ivy_status state_init( return IVY_OK; } +static enum ivy_status get_eval_type( + struct ivy_codegen *gen, struct cond_group_codegen_state *state, + struct mie_type **out) +{ + struct mie_type *type = NULL; + + b_queue_iterator it; + b_queue_foreach (&it, &state->s_edges) { + struct mie_phi_edge *edge + = b_unbox(struct mie_phi_edge, it.entry, e_entry); + if (!edge->e_value) { + continue; + } + + struct mie_type *edge_type + = mie_value_get_type(edge->e_value, gen->c_ctx); + + if (!type) { + type = edge_type; + continue; + } + } + + *out = type; + return IVY_OK; +} + +static enum ivy_status emit_phi_instr( + struct ivy_codegen *gen, struct cond_group_codegen_state *state, + struct mie_type *type, struct mie_value **result) +{ + size_t nr_edges = b_queue_length(&state->s_edges); + if (!nr_edges) { + return IVY_OK; + } + + struct mie_phi_edge *edges = calloc(nr_edges, sizeof *edges); + if (!edges) { + return IVY_ERR_NO_MEMORY; + } + + size_t i = 0; + + b_queue_iterator it; + b_queue_foreach (&it, &state->s_edges) { + struct mie_phi_edge *edge + = b_unbox(struct mie_phi_edge, it.entry, e_entry); + + memcpy(&edges[i], edge, sizeof *edge); + i++; + } + + struct mie_value *phi = mie_builder_phi( + gen->c_builder, type, edges, nr_edges, "if.result"); + *result = phi; + + return IVY_OK; +} + static enum ivy_status state_fini( struct ivy_codegen *gen, struct code_generator_state *state, struct code_generator_value *result) @@ -56,6 +118,12 @@ static enum ivy_status state_fini( struct mie_func *func = mie_builder_get_current_func(gen->c_builder); struct mie_block *block = mie_builder_get_current_block(gen->c_builder); + struct mie_type *result_type = NULL; + enum ivy_status status = get_eval_type(gen, group, &result_type); + if (status != IVY_OK) { + return status; + } + if (!block->b_terminator) { mie_builder_br(gen->c_builder, group->s_end); } @@ -63,6 +131,19 @@ static enum ivy_status state_fini( mie_func_insert_block(func, group->s_end, NULL); mie_builder_set_insert_point(gen->c_builder, group->s_end); + struct mie_value *phi = NULL; + if (result_type) { + status = emit_phi_instr(gen, group, result_type, &phi); + } + + if (status != IVY_OK) { + return status; + } + + if (phi) { + code_generator_value_set_mie_value(result, phi); + } + return IVY_OK; } @@ -72,6 +153,11 @@ static struct code_generator_result value_received( { struct cond_group_codegen_state *cond = (struct cond_group_codegen_state *)state; + assert(value->v_type == CODE_GENERATOR_VALUE_PHI_EDGE); + + struct mie_phi_edge *edge = code_generator_value_get_phi_edge(value); + b_queue_push_back(&cond->s_edges, &edge->e_entry); + return CODEGEN_RESULT_OK(0); } diff --git a/lang/codegen/cond.c b/lang/codegen/cond.c index 3a9d4d3..1647563 100644 --- a/lang/codegen/cond.c +++ b/lang/codegen/cond.c @@ -2,13 +2,16 @@ #include "codegen.h" #include +#include #include #include #include struct cond_codegen_state { struct code_generator_state s_base; + bool s_is_else; struct mie_value *s_cond; + struct mie_value *s_result; struct mie_block *s_true; struct mie_block *s_false; struct mie_block *s_end; @@ -19,6 +22,8 @@ static struct code_generator_result gen_cond( struct ivy_ast_node *node, size_t depth) { struct cond_codegen_state *cond = (struct cond_codegen_state *)state; + struct ivy_ast_cond_node *cond_node = (struct ivy_ast_cond_node *)node; + cond->s_is_else = (cond_node->n_cond == NULL); return CODEGEN_RESULT_OK(0); } @@ -42,7 +47,6 @@ static struct code_generator_result gen_expr( } codegen_push_generator(gen, CODE_GENERATOR_EXPR, 0, NULL); - return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE); } @@ -84,7 +88,11 @@ static enum ivy_status state_fini( 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); + struct mie_block *block = mie_builder_get_current_block(gen->c_builder); + struct mie_phi_edge *edge = mie_phi_edge_create(block, cond->s_result); + + code_generator_value_set_phi_edge(result, edge); mie_builder_br(gen->c_builder, cond->s_end); if (cond->s_false) { @@ -95,15 +103,10 @@ static enum ivy_status state_fini( return IVY_OK; } -static struct code_generator_result value_received( - struct ivy_codegen *gen, struct code_generator_state *state, +static void set_cond( + struct ivy_codegen *gen, struct cond_codegen_state *cond, 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) { @@ -115,18 +118,40 @@ static struct code_generator_result value_received( = mie_builder_cmp_neq(gen->c_builder, value, zero, NULL); cond->s_cond = cmp; } +} + +static struct code_generator_result value_received( + struct ivy_codegen *gen, struct code_generator_state *state, + struct code_generator_value *value) +{ + struct cond_codegen_state *cond = (struct cond_codegen_state *)state; + if (!value) { + return CODEGEN_RESULT_OK(0); + } + + if (!cond->s_is_else && !cond->s_cond) { + set_cond(gen, cond, code_generator_value_get_mie_value(value)); + return CODEGEN_RESULT_OK(0); + } + + if (!cond->s_result) { + cond->s_result = code_generator_value_get_mie_value(value); + } 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), - }}; +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), + NODE_CODEGEN(LOOP_BREAK, gen_block), + NODE_CODEGEN(LOOP_REPEAT, gen_block), + }, +};