lang: codegen: cond: implement implicitly returning values from an if-else expression
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
#include "../debug.h"
|
#include "../debug.h"
|
||||||
#include "codegen.h"
|
#include "codegen.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <mie/ir/block.h>
|
#include <mie/ir/block.h>
|
||||||
#include <mie/ir/func.h>
|
#include <mie/ir/func.h>
|
||||||
|
#include <mie/ir/phi.h>
|
||||||
#include <mie/ir/value.h>
|
#include <mie/ir/value.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -11,6 +13,7 @@
|
|||||||
struct cond_group_codegen_state {
|
struct cond_group_codegen_state {
|
||||||
struct code_generator_state s_base;
|
struct code_generator_state s_base;
|
||||||
struct mie_block *s_end;
|
struct mie_block *s_end;
|
||||||
|
b_queue s_edges;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct code_generator_result gen_cond_group(
|
static struct code_generator_result gen_cond_group(
|
||||||
@@ -46,6 +49,65 @@ static enum ivy_status state_init(
|
|||||||
return IVY_OK;
|
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(
|
static enum ivy_status state_fini(
|
||||||
struct ivy_codegen *gen, struct code_generator_state *state,
|
struct ivy_codegen *gen, struct code_generator_state *state,
|
||||||
struct code_generator_value *result)
|
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_func *func = mie_builder_get_current_func(gen->c_builder);
|
||||||
struct mie_block *block = mie_builder_get_current_block(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) {
|
if (!block->b_terminator) {
|
||||||
mie_builder_br(gen->c_builder, group->s_end);
|
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_func_insert_block(func, group->s_end, NULL);
|
||||||
mie_builder_set_insert_point(gen->c_builder, group->s_end);
|
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;
|
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 *cond
|
||||||
= (struct cond_group_codegen_state *)state;
|
= (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);
|
return CODEGEN_RESULT_OK(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,16 @@
|
|||||||
#include "codegen.h"
|
#include "codegen.h"
|
||||||
|
|
||||||
#include <mie/ir/func.h>
|
#include <mie/ir/func.h>
|
||||||
|
#include <mie/ir/phi.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
struct cond_codegen_state {
|
struct cond_codegen_state {
|
||||||
struct code_generator_state s_base;
|
struct code_generator_state s_base;
|
||||||
|
bool s_is_else;
|
||||||
struct mie_value *s_cond;
|
struct mie_value *s_cond;
|
||||||
|
struct mie_value *s_result;
|
||||||
struct mie_block *s_true;
|
struct mie_block *s_true;
|
||||||
struct mie_block *s_false;
|
struct mie_block *s_false;
|
||||||
struct mie_block *s_end;
|
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 ivy_ast_node *node, size_t depth)
|
||||||
{
|
{
|
||||||
struct cond_codegen_state *cond = (struct cond_codegen_state *)state;
|
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);
|
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);
|
codegen_push_generator(gen, CODE_GENERATOR_EXPR, 0, NULL);
|
||||||
|
|
||||||
return CODEGEN_RESULT_OK(CODEGEN_R_REPEAT_NODE);
|
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");
|
debug_printf("codegen: end of cond\n");
|
||||||
struct cond_codegen_state *cond = (struct cond_codegen_state *)state;
|
struct cond_codegen_state *cond = (struct cond_codegen_state *)state;
|
||||||
struct mie_func *func = mie_builder_get_current_func(gen->c_builder);
|
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);
|
mie_builder_br(gen->c_builder, cond->s_end);
|
||||||
|
|
||||||
if (cond->s_false) {
|
if (cond->s_false) {
|
||||||
@@ -95,15 +103,10 @@ static enum ivy_status state_fini(
|
|||||||
return IVY_OK;
|
return IVY_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct code_generator_result value_received(
|
static void set_cond(
|
||||||
struct ivy_codegen *gen, struct code_generator_state *state,
|
struct ivy_codegen *gen, struct cond_codegen_state *cond,
|
||||||
struct mie_value *value)
|
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);
|
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) {
|
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);
|
= mie_builder_cmp_neq(gen->c_builder, value, zero, NULL);
|
||||||
cond->s_cond = cmp;
|
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);
|
return CODEGEN_RESULT_OK(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct code_generator cond_generator
|
struct code_generator cond_generator = {
|
||||||
= {.g_type = CODE_GENERATOR_COND,
|
.g_type = CODE_GENERATOR_COND,
|
||||||
.g_state_size = sizeof(struct cond_codegen_state),
|
.g_state_size = sizeof(struct cond_codegen_state),
|
||||||
.g_state_init = state_init,
|
.g_state_init = state_init,
|
||||||
.g_state_fini = state_fini,
|
.g_state_fini = state_fini,
|
||||||
.g_value_received = value_received,
|
.g_value_received = value_received,
|
||||||
.g_expr_generator = gen_expr,
|
.g_expr_generator = gen_expr,
|
||||||
.g_node_generators = {
|
.g_node_generators = {
|
||||||
NODE_CODEGEN(COND, gen_cond),
|
NODE_CODEGEN(COND, gen_cond),
|
||||||
NODE_CODEGEN(BLOCK, gen_block),
|
NODE_CODEGEN(BLOCK, gen_block),
|
||||||
}};
|
NODE_CODEGEN(LOOP_BREAK, gen_block),
|
||||||
|
NODE_CODEGEN(LOOP_REPEAT, gen_block),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user