299 lines
6.8 KiB
C
299 lines
6.8 KiB
C
|
|
#include "builder.h"
|
||
|
|
|
||
|
|
#include <blue/object/hashmap.h>
|
||
|
|
#include <mie/ctx.h>
|
||
|
|
#include <mie/ir/const.h>
|
||
|
|
#include <mie/ir/data.h>
|
||
|
|
#include <mie/ir/instr.h>
|
||
|
|
#include <mie/select/builder.h>
|
||
|
|
#include <mie/select/graph.h>
|
||
|
|
#include <mie/select/node.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
struct mie_select_builder {
|
||
|
|
struct mie_ctx *b_ctx;
|
||
|
|
struct mie_select_graph *b_graph;
|
||
|
|
/* map of mie_instr* to mie_select_value*, defining the graph node that
|
||
|
|
* corresponds to each value-producing instruction */
|
||
|
|
b_hashmap *b_nodes;
|
||
|
|
/* map of mie_instr* to mie_select_value*, defining the graph node that
|
||
|
|
* last accessed a memory location defined by a particular instruction. */
|
||
|
|
b_hashmap *b_mem_access;
|
||
|
|
};
|
||
|
|
|
||
|
|
struct mie_select_builder *mie_select_builder_create(struct mie_ctx *ctx)
|
||
|
|
{
|
||
|
|
struct mie_select_builder *out = malloc(sizeof *out);
|
||
|
|
if (!out) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
memset(out, 0x0, sizeof *out);
|
||
|
|
|
||
|
|
out->b_ctx = ctx;
|
||
|
|
out->b_graph = mie_select_graph_create(ctx);
|
||
|
|
if (!out->b_graph) {
|
||
|
|
free(out);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
out->b_nodes = b_hashmap_create(NULL, NULL);
|
||
|
|
if (!out->b_nodes) {
|
||
|
|
mie_select_graph_destroy(out->b_graph);
|
||
|
|
free(out);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
out->b_mem_access = b_hashmap_create(NULL, NULL);
|
||
|
|
if (!out->b_mem_access) {
|
||
|
|
b_hashmap_release(out->b_nodes);
|
||
|
|
mie_select_graph_destroy(out->b_graph);
|
||
|
|
free(out);
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
return out;
|
||
|
|
}
|
||
|
|
|
||
|
|
void mie_select_builder_destroy(struct mie_select_builder *builder)
|
||
|
|
{
|
||
|
|
if (builder->b_nodes) {
|
||
|
|
b_hashmap_release(builder->b_nodes);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (builder->b_mem_access) {
|
||
|
|
b_hashmap_release(builder->b_mem_access);
|
||
|
|
}
|
||
|
|
|
||
|
|
mie_select_graph_destroy(builder->b_graph);
|
||
|
|
free(builder);
|
||
|
|
}
|
||
|
|
|
||
|
|
struct mie_select_graph *mie_select_builder_get_graph(
|
||
|
|
struct mie_select_builder *builder)
|
||
|
|
{
|
||
|
|
return builder->b_graph;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct mie_ctx *mie_select_builder_get_ctx(struct mie_select_builder *builder)
|
||
|
|
{
|
||
|
|
return builder->b_ctx;
|
||
|
|
}
|
||
|
|
|
||
|
|
static void clear_node_map(struct mie_select_builder *builder)
|
||
|
|
{
|
||
|
|
b_hashmap_iterator it;
|
||
|
|
b_hashmap_iterator_begin(builder->b_nodes, &it);
|
||
|
|
while (b_hashmap_iterator_is_valid(&it)) {
|
||
|
|
free(it.value->value_data);
|
||
|
|
b_hashmap_iterator_erase(&it);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
struct mie_select_graph *mie_select_builder_finish(struct mie_select_builder *builder)
|
||
|
|
{
|
||
|
|
enum mie_status status = MIE_SUCCESS;
|
||
|
|
struct mie_select_graph *graph = builder->b_graph;
|
||
|
|
|
||
|
|
struct mie_select_value *root_operands[] = {
|
||
|
|
NULL,
|
||
|
|
};
|
||
|
|
size_t nr_root_operands = 0;
|
||
|
|
|
||
|
|
if (graph->g_last_chain.v_node) {
|
||
|
|
root_operands[0] = &graph->g_last_chain;
|
||
|
|
nr_root_operands++;
|
||
|
|
}
|
||
|
|
|
||
|
|
status = mie_select_graph_get_node(
|
||
|
|
graph, MIE_SELECT_OP_ROOT, root_operands, nr_root_operands,
|
||
|
|
NULL, 0, &graph->g_root);
|
||
|
|
|
||
|
|
if (status != MIE_SUCCESS) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
clear_node_map(builder);
|
||
|
|
|
||
|
|
builder->b_graph = NULL;
|
||
|
|
|
||
|
|
return graph;
|
||
|
|
}
|
||
|
|
|
||
|
|
enum mie_status mie_select_builder_push_instr(
|
||
|
|
struct mie_select_builder *builder, struct mie_instr *instr)
|
||
|
|
{
|
||
|
|
const struct select_instr_type *i_type
|
||
|
|
= select_type_for_instr(instr->i_type);
|
||
|
|
if (!i_type) {
|
||
|
|
return MIE_ERR_INVALID_VALUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
return i_type->i_push(builder, instr);
|
||
|
|
}
|
||
|
|
|
||
|
|
static enum mie_status get_const_node(
|
||
|
|
struct mie_select_builder *builder, struct mie_value *ir_val,
|
||
|
|
struct mie_select_value *out)
|
||
|
|
{
|
||
|
|
struct mie_const *c = (struct mie_const *)ir_val;
|
||
|
|
enum mie_status status = mie_select_graph_get_node(
|
||
|
|
builder->b_graph, MIE_SELECT_OP_CONSTANT, NULL, 0, &c->c_type,
|
||
|
|
1, out);
|
||
|
|
if (status != MIE_SUCCESS) {
|
||
|
|
return status;
|
||
|
|
}
|
||
|
|
|
||
|
|
out->v_node->n_flags = MIE_SELECT_NODE_F_PVALUE;
|
||
|
|
out->v_node->n_value_p = ir_val;
|
||
|
|
|
||
|
|
return MIE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
static enum mie_status get_data_node(
|
||
|
|
struct mie_select_builder *builder, struct mie_value *ir_val,
|
||
|
|
struct mie_select_value *out)
|
||
|
|
{
|
||
|
|
struct mie_data *data = (struct mie_data *)ir_val;
|
||
|
|
unsigned int opcode = 0;
|
||
|
|
struct mie_type *type = NULL;
|
||
|
|
|
||
|
|
switch (data->d_type) {
|
||
|
|
case MIE_DATA_EXTERN_GLOBAL:
|
||
|
|
opcode = MIE_SELECT_OP_GLOBAL_ADDRESS;
|
||
|
|
type = mie_ctx_get_type(builder->b_ctx, MIE_TYPE_PTR);
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
return MIE_ERR_INVALID_VALUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
enum mie_status status = mie_select_graph_get_node(
|
||
|
|
builder->b_graph, opcode, NULL, 0, &type, 1, out);
|
||
|
|
if (status != MIE_SUCCESS) {
|
||
|
|
return status;
|
||
|
|
}
|
||
|
|
|
||
|
|
out->v_node->n_flags = MIE_SELECT_NODE_F_PVALUE;
|
||
|
|
out->v_node->n_value_p = ir_val;
|
||
|
|
|
||
|
|
return MIE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct mie_select_value *select_builder_get_value(
|
||
|
|
struct mie_select_builder *builder, struct mie_value *ir_val)
|
||
|
|
{
|
||
|
|
b_hashmap_key key = {
|
||
|
|
.key_flags = B_HASHMAP_KEY_F_INTVALUE,
|
||
|
|
.key_data = ir_val,
|
||
|
|
.key_size = sizeof(struct mie_value *),
|
||
|
|
};
|
||
|
|
|
||
|
|
const b_hashmap_value *val = b_hashmap_get(builder->b_nodes, &key);
|
||
|
|
if (val) {
|
||
|
|
return val->value_data;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct mie_select_value *select_val = malloc(sizeof *select_val);
|
||
|
|
if (!select_val) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
enum mie_status status = MIE_ERR_INVALID_VALUE;
|
||
|
|
|
||
|
|
switch (ir_val->v_type->t_id) {
|
||
|
|
case MIE_VALUE_CONST:
|
||
|
|
status = get_const_node(builder, ir_val, select_val);
|
||
|
|
break;
|
||
|
|
case MIE_VALUE_DATA:
|
||
|
|
status = get_data_node(builder, ir_val, select_val);
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (status != MIE_SUCCESS) {
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
key.key_data = ir_val;
|
||
|
|
key.key_size = sizeof(struct mie_value *);
|
||
|
|
|
||
|
|
b_hashmap_value hashmap_val = {
|
||
|
|
.value_data = select_val,
|
||
|
|
.value_size = sizeof *select_val,
|
||
|
|
};
|
||
|
|
b_hashmap_put(builder->b_nodes, &key, &hashmap_val);
|
||
|
|
|
||
|
|
return select_val;
|
||
|
|
}
|
||
|
|
|
||
|
|
enum mie_status select_builder_set_value(
|
||
|
|
struct mie_select_builder *builder, struct mie_value *ir_val,
|
||
|
|
struct mie_select_value *graph_val)
|
||
|
|
{
|
||
|
|
struct mie_select_value *graph_val2 = malloc(sizeof *graph_val2);
|
||
|
|
if (!graph_val2) {
|
||
|
|
return MIE_ERR_NO_MEMORY;
|
||
|
|
}
|
||
|
|
|
||
|
|
memcpy(graph_val2, graph_val, sizeof *graph_val);
|
||
|
|
|
||
|
|
b_hashmap_key key = {
|
||
|
|
.key_flags = B_HASHMAP_KEY_F_INTVALUE,
|
||
|
|
.key_data = ir_val,
|
||
|
|
.key_size = sizeof(struct mie_value *),
|
||
|
|
};
|
||
|
|
|
||
|
|
b_hashmap_value hashmap_val = {
|
||
|
|
.value_data = graph_val2,
|
||
|
|
.value_size = sizeof *graph_val2,
|
||
|
|
};
|
||
|
|
|
||
|
|
b_hashmap_put(builder->b_nodes, &key, &hashmap_val);
|
||
|
|
return MIE_SUCCESS;
|
||
|
|
}
|
||
|
|
|
||
|
|
struct mie_select_value *select_builder_get_mem_access(
|
||
|
|
struct mie_select_builder *builder, struct mie_value *ir_val)
|
||
|
|
{
|
||
|
|
b_hashmap_key key = {
|
||
|
|
.key_flags = B_HASHMAP_KEY_F_INTVALUE,
|
||
|
|
.key_data = ir_val,
|
||
|
|
.key_size = sizeof(struct mie_value *),
|
||
|
|
};
|
||
|
|
|
||
|
|
const b_hashmap_value *val = b_hashmap_get(builder->b_mem_access, &key);
|
||
|
|
if (val) {
|
||
|
|
return val->value_data;
|
||
|
|
}
|
||
|
|
|
||
|
|
return NULL;
|
||
|
|
}
|
||
|
|
|
||
|
|
enum mie_status select_builder_set_mem_access(
|
||
|
|
struct mie_select_builder *builder, struct mie_value *ir_val,
|
||
|
|
struct mie_select_value *graph_val)
|
||
|
|
{
|
||
|
|
struct mie_select_value *graph_val2 = malloc(sizeof *graph_val2);
|
||
|
|
if (!graph_val2) {
|
||
|
|
return MIE_ERR_NO_MEMORY;
|
||
|
|
}
|
||
|
|
|
||
|
|
memcpy(graph_val2, graph_val, sizeof *graph_val);
|
||
|
|
|
||
|
|
b_hashmap_key key = {
|
||
|
|
.key_flags = B_HASHMAP_KEY_F_INTVALUE,
|
||
|
|
.key_data = ir_val,
|
||
|
|
.key_size = sizeof(struct mie_value *),
|
||
|
|
};
|
||
|
|
|
||
|
|
b_hashmap_value hashmap_val = {
|
||
|
|
.value_data = graph_val2,
|
||
|
|
.value_size = sizeof *graph_val2,
|
||
|
|
};
|
||
|
|
|
||
|
|
b_hashmap_put(builder->b_mem_access, &key, &hashmap_val);
|
||
|
|
return MIE_SUCCESS;
|
||
|
|
}
|