mie: select: track all side-effect-chains in a graph; support combining them all
This commit is contained in:
@@ -49,4 +49,7 @@ MIE_API enum mie_status mie_select_builder_set_mem_access(
|
|||||||
struct mie_select_builder *builder, struct mie_value *ir_val,
|
struct mie_select_builder *builder, struct mie_value *ir_val,
|
||||||
struct mie_select_value *graph_val);
|
struct mie_select_value *graph_val);
|
||||||
|
|
||||||
|
MIE_API enum mie_status mie_select_builder_collapse_chain_ends(
|
||||||
|
struct mie_select_builder *builder, struct mie_select_value *out);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -21,11 +21,16 @@ struct mie_select_use {
|
|||||||
b_queue_entry u_entry;
|
b_queue_entry u_entry;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct mie_select_chain_end {
|
||||||
|
struct mie_select_value c_value;
|
||||||
|
b_queue_entry c_entry;
|
||||||
|
};
|
||||||
|
|
||||||
struct mie_select_graph {
|
struct mie_select_graph {
|
||||||
b_queue g_nodes;
|
b_queue g_nodes;
|
||||||
struct mie_select_node *g_root;
|
struct mie_select_node *g_root;
|
||||||
struct mie_select_value g_entry;
|
struct mie_select_value g_entry;
|
||||||
struct mie_select_value g_last_chain;
|
b_queue g_chain_ends;
|
||||||
size_t g_frame_index;
|
size_t g_frame_index;
|
||||||
size_t g_node_id;
|
size_t g_node_id;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -94,18 +94,6 @@ const struct mie_target *mie_select_builder_get_target(
|
|||||||
return builder->b_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)
|
struct mie_select_graph *mie_select_builder_finish(struct mie_select_builder *builder)
|
||||||
{
|
{
|
||||||
enum mie_status status = MIE_SUCCESS;
|
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;
|
size_t nr_root_operands = 0;
|
||||||
|
|
||||||
if (graph->g_last_chain.v_node) {
|
struct mie_select_value incoming_chain = {};
|
||||||
root_operands[0] = &graph->g_last_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++;
|
nr_root_operands++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,9 +123,13 @@ struct mie_select_graph *mie_select_builder_finish(struct mie_select_builder *bu
|
|||||||
return NULL;
|
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;
|
return graph;
|
||||||
}
|
}
|
||||||
@@ -251,6 +249,32 @@ static enum mie_status get_data_node(
|
|||||||
return MIE_SUCCESS;
|
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_value *mie_select_builder_get_value(
|
||||||
struct mie_select_builder *builder, struct mie_value *ir_val)
|
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);
|
status = get_data_node(builder, ir_val, select_val);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
status = get_external_value_node(builder, ir_val, select_val);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,6 +393,77 @@ enum mie_status mie_select_builder_set_mem_access(
|
|||||||
return MIE_SUCCESS;
|
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_node *mie_select_builder_find_node_with_ivalue(
|
||||||
struct mie_select_builder *builder, const struct mie_target *target,
|
struct mie_select_builder *builder, const struct mie_target *target,
|
||||||
unsigned int opcode, long long val)
|
unsigned int opcode, long long val)
|
||||||
|
|||||||
@@ -62,6 +62,43 @@ void mie_select_graph_destroy(struct mie_select_graph *graph)
|
|||||||
free(graph);
|
free(graph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum mie_status update_chain_ends(
|
||||||
|
struct mie_select_graph *graph, struct mie_select_value *new_chain)
|
||||||
|
{
|
||||||
|
struct mie_select_node *new_node = new_chain->v_node;
|
||||||
|
|
||||||
|
b_queue_entry *entry = b_queue_first(&graph->g_chain_ends);
|
||||||
|
while (entry) {
|
||||||
|
struct mie_select_chain_end *end
|
||||||
|
= b_unbox(struct mie_select_chain_end, entry, c_entry);
|
||||||
|
struct mie_select_node *value_node = end->c_value.v_node;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < new_node->n_nr_operands; i++) {
|
||||||
|
struct mie_select_node *operand_node
|
||||||
|
= new_node->n_operands[i].u_value.v_node;
|
||||||
|
|
||||||
|
if (value_node == operand_node) {
|
||||||
|
memcpy(&end->c_value, new_chain, sizeof *new_chain);
|
||||||
|
return MIE_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = b_queue_next(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct mie_select_chain_end *end = malloc(sizeof *end);
|
||||||
|
if (!end) {
|
||||||
|
return MIE_ERR_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(end, 0x0, sizeof *end);
|
||||||
|
memcpy(&end->c_value, new_chain, sizeof *new_chain);
|
||||||
|
|
||||||
|
b_queue_push_back(&graph->g_chain_ends, &end->c_entry);
|
||||||
|
|
||||||
|
return MIE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
enum mie_status mie_select_graph_get_node(
|
enum mie_status mie_select_graph_get_node(
|
||||||
struct mie_select_graph *graph, const struct mie_target *target,
|
struct mie_select_graph *graph, const struct mie_target *target,
|
||||||
unsigned int op, struct mie_select_value **operands, size_t nr_operands,
|
unsigned int op, struct mie_select_value **operands, size_t nr_operands,
|
||||||
@@ -87,9 +124,18 @@ enum mie_status mie_select_graph_get_node(
|
|||||||
node->n_target = target;
|
node->n_target = target;
|
||||||
|
|
||||||
for (size_t i = 0; i < nr_values; i++) {
|
for (size_t i = 0; i < nr_values; i++) {
|
||||||
if (values[i]->t_id == MIE_TYPE_OTHER) {
|
if (values[i]->t_id != MIE_TYPE_OTHER) {
|
||||||
graph->g_last_chain.v_node = node;
|
continue;
|
||||||
graph->g_last_chain.v_index = i;
|
}
|
||||||
|
|
||||||
|
struct mie_select_value chain = {
|
||||||
|
.v_node = node,
|
||||||
|
.v_index = i,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mie_status status = update_chain_ends(graph, &chain);
|
||||||
|
if (status != MIE_SUCCESS) {
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user