mie: select: track all side-effect-chains in a graph; support combining them all

This commit is contained in:
2025-11-15 22:37:35 +00:00
parent ec8a1a72a3
commit 4d1918bb77
4 changed files with 170 additions and 20 deletions

View File

@@ -94,18 +94,6 @@ const struct mie_target *mie_select_builder_get_target(
return builder->b_target;
}
static void clear_node_map(struct mie_select_builder *builder)
{
b_iterator *it = b_iterator_begin(builder->b_nodes);
while (b_iterator_is_valid(it)) {
b_hashmap_item *item = b_iterator_get_value(it).v_ptr;
free(item->value.value_data);
b_iterator_erase(it);
}
b_iterator_unref(it);
}
struct mie_select_graph *mie_select_builder_finish(struct mie_select_builder *builder)
{
enum mie_status status = MIE_SUCCESS;
@@ -116,8 +104,14 @@ struct mie_select_graph *mie_select_builder_finish(struct mie_select_builder *bu
};
size_t nr_root_operands = 0;
if (graph->g_last_chain.v_node) {
root_operands[0] = &graph->g_last_chain;
struct mie_select_value incoming_chain = {};
status = mie_select_builder_collapse_chain_ends(builder, &incoming_chain);
if (status != MIE_SUCCESS) {
return NULL;
}
if (incoming_chain.v_node) {
root_operands[0] = &incoming_chain;
nr_root_operands++;
}
@@ -129,9 +123,13 @@ struct mie_select_graph *mie_select_builder_finish(struct mie_select_builder *bu
return NULL;
}
clear_node_map(builder);
b_hashmap_unref(builder->b_nodes);
builder->b_nodes = b_hashmap_create(NULL, NULL);
builder->b_graph = NULL;
b_hashmap_unref(builder->b_mem_access);
builder->b_mem_access = b_hashmap_create(NULL, NULL);
builder->b_graph = mie_select_graph_create(builder->b_ctx);
return graph;
}
@@ -251,6 +249,32 @@ static enum mie_status get_data_node(
return MIE_SUCCESS;
}
static enum mie_status get_external_value_node(
struct mie_select_builder *builder, struct mie_value *ir_val,
struct mie_select_value *out)
{
struct mie_type *type = mie_value_get_type(ir_val, builder->b_ctx);
if (!type) {
return MIE_ERR_INVALID_VALUE;
}
struct mie_select_node *node;
enum mie_status status = mie_select_graph_get_node(
builder->b_graph, mie_target_builtin(), MIE_SELECT_OP_REGISTER,
NULL, 0, &type, 1, &node);
if (status != MIE_SUCCESS) {
return status;
}
node->n_flags = MIE_SELECT_NODE_F_PVALUE;
node->n_value.v = ir_val;
mie_select_node_get_value(node, type, 0, out);
return MIE_SUCCESS;
}
struct mie_select_value *mie_select_builder_get_value(
struct mie_select_builder *builder, struct mie_value *ir_val)
{
@@ -280,6 +304,7 @@ struct mie_select_value *mie_select_builder_get_value(
status = get_data_node(builder, ir_val, select_val);
break;
default:
status = get_external_value_node(builder, ir_val, select_val);
break;
}
@@ -368,6 +393,77 @@ enum mie_status mie_select_builder_set_mem_access(
return MIE_SUCCESS;
}
enum mie_status mie_select_builder_collapse_chain_ends(
struct mie_select_builder *builder, struct mie_select_value *out)
{
size_t nr_chains = b_queue_length(&builder->b_graph->g_chain_ends);
b_queue_entry *entry = NULL;
struct mie_select_chain_end *end = NULL;
switch (nr_chains) {
case 0:
memset(out, 0x0, sizeof *out);
return MIE_SUCCESS;
case 1:
entry = b_queue_first(&builder->b_graph->g_chain_ends);
end = b_unbox(struct mie_select_chain_end, entry, c_entry);
memcpy(out, end, sizeof *out);
return MIE_SUCCESS;
default:
break;
}
struct mie_type *chain_type
= mie_ctx_get_type(builder->b_ctx, MIE_TYPE_OTHER);
struct mie_select_value **operands = calloc(nr_chains, sizeof *operands);
if (!operands) {
return MIE_ERR_NO_MEMORY;
}
entry = b_queue_first(&builder->b_graph->g_chain_ends);
size_t i = 0;
while (entry) {
end = b_unbox(struct mie_select_chain_end, entry, c_entry);
operands[i++] = &end->c_value;
entry = b_queue_next(entry);
}
struct mie_select_node *group = NULL;
enum mie_status status = mie_select_graph_get_node(
builder->b_graph, mie_target_builtin(), MIE_SELECT_OP_CHAIN_GROUP,
operands, nr_chains, &chain_type, 1, &group);
free(operands);
if (status != MIE_SUCCESS) {
return status;
}
entry = b_queue_first(&builder->b_graph->g_chain_ends);
while (entry) {
end = b_unbox(struct mie_select_chain_end, entry, c_entry);
b_queue_entry *next = b_queue_next(entry);
b_queue_delete(&builder->b_graph->g_chain_ends, entry);
free(end);
entry = next;
}
struct mie_select_chain_end *group_end = malloc(sizeof *group_end);
if (!group_end) {
return MIE_ERR_NO_MEMORY;
}
memset(group_end, 0x0, sizeof *group_end);
mie_select_node_get_value(group, chain_type, 0, &group_end->c_value);
b_queue_push_back(&builder->b_graph->g_chain_ends, &group_end->c_entry);
*out = group_end->c_value;
return MIE_SUCCESS;
}
struct mie_select_node *mie_select_builder_find_node_with_ivalue(
struct mie_select_builder *builder, const struct mie_target *target,
unsigned int opcode, long long val)