diff --git a/mie/include/mie/select/builder.h b/mie/include/mie/select/builder.h index b530f26..647060b 100644 --- a/mie/include/mie/select/builder.h +++ b/mie/include/mie/select/builder.h @@ -2,10 +2,26 @@ #define MIE_SELECT_BUILDER_H_ #include +#include +struct mie_ctx; +struct mie_instr; +struct mie_value; struct mie_select_builder; +struct mie_select_node; +struct mie_select_graph; -MIE_API struct mie_select_builder *mie_select_builder_create(void); +MIE_API struct mie_select_builder *mie_select_builder_create(struct mie_ctx *ctx); MIE_API void mie_select_builder_destroy(struct mie_select_builder *builder); +MIE_API struct mie_select_graph *mie_select_builder_get_graph( + struct mie_select_builder *builder); +MIE_API struct mie_ctx *mie_select_builder_get_ctx( + struct mie_select_builder *builder); +MIE_API struct mie_select_graph *mie_select_builder_finish( + struct mie_select_builder *builder); + +MIE_API enum mie_status mie_select_builder_push_instr( + struct mie_select_builder *builder, struct mie_instr *instr); + #endif diff --git a/mie/include/mie/select/graph.h b/mie/include/mie/select/graph.h index fd538e9..d08322d 100644 --- a/mie/include/mie/select/graph.h +++ b/mie/include/mie/select/graph.h @@ -5,7 +5,9 @@ #include #include -struct mie_select_value; +struct mie_ctx; +struct mie_type; +struct mie_instr; struct mie_select_value { struct mie_select_node *v_node; @@ -15,15 +17,42 @@ struct mie_select_value { struct mie_select_use { struct mie_select_node *u_user; struct mie_select_value u_value; - b_queue u_entry; + b_queue_entry u_entry; }; struct mie_select_graph { b_queue g_nodes; - b_queue g_use; + struct mie_select_value g_root; + struct mie_select_value g_entry; + struct mie_select_value g_last_chain; + size_t g_frame_index; + size_t g_node_id; }; -MIE_API struct mie_select_graph *mie_select_graph_create(void); +struct mie_select_use_iterator { + b_queue_iterator it_base; +}; + +#define mie_select_use_foreach(it, q) b_queue_foreach (&(it)->it_base, q) + +static inline struct mie_select_use *mie_select_use_iterator_unbox( + struct mie_select_use_iterator *it) +{ + return b_unbox(struct mie_select_use, it->it_base.entry, u_entry); +} +MIE_API void mie_select_use_iterator_next(struct mie_select_use_iterator *it); +MIE_API bool mie_select_use_iterator_is_valid( + const struct mie_select_use_iterator *it); + +MIE_API struct mie_select_graph *mie_select_graph_create(struct mie_ctx *ctx); MIE_API void mie_select_graph_destroy(struct mie_select_graph *graph); +MIE_API enum mie_status mie_select_graph_get_node( + struct mie_select_graph *graph, unsigned int op, + struct mie_select_value **operands, size_t nr_operands, + struct mie_type **values, size_t nr_values, struct mie_select_value *out); + +MIE_API void mie_select_graph_dump_text(struct mie_select_graph *graph); +MIE_API void mie_select_graph_dump_dot(struct mie_select_graph *graph); + #endif diff --git a/mie/include/mie/select/node.h b/mie/include/mie/select/node.h index 8a94e82..65f0a00 100644 --- a/mie/include/mie/select/node.h +++ b/mie/include/mie/select/node.h @@ -7,15 +7,86 @@ #define MIE_SELECT_NODE_OUTPUT_MAX 4 -struct mie_backend; +struct mie_target; struct mie_value; +struct mie_select_value; -struct mie_select_node { - unsigned long n_opcode; - struct mie_value *n_value; - b_queue n_entry; - struct mie_backend *n_backend; - const struct mie_type t_outputs[MIE_SELECT_NODE_OUTPUT_MAX]; +enum mie_select_node_flags { + MIE_SELECT_NODE_F_IVALUE = 0x01u, + MIE_SELECT_NODE_F_PVALUE = 0x02u, }; +struct mie_select_node { + size_t n_id; + unsigned long n_opcode; + enum mie_select_node_flags n_flags; + + /* certain "builtin" parameters that can be used by opcodes */ + struct mie_value *n_value_p; + long long n_value_i; + + /* queue entry, links to mie_select_graph.g_nodes */ + b_queue_entry n_entry; + + /* linked lists of struct mie_select_use, + * listing all the places where this node is being used as an + * operand. + * these pointers point to data in another node's n_operands, + * and the memory belongs to these other nodes, not us. + */ + b_queue n_use; + + /* array of struct mie_select_use + * listing all the nodes that are being used as operands by + * this node. other nodes hold pointers to these mie_select_use array + * entries as part of their n_use queue. + */ + struct mie_select_use *n_operands; + size_t n_nr_operands; + + /* array of struct mie_type pointers + * listing the types of the values that are produced as outputs by + * this node. the type pointers themselves are owned by a mie_ctx. + */ + struct mie_type **n_results; + size_t n_nr_results; + + /* the target system that provides the operation described by n_opcode. */ + const struct mie_target *n_target; +}; + +struct mie_select_node_iterator { + b_queue_iterator it_base; +}; + +static inline struct mie_select_node *mie_select_node_iterator_unbox( + struct mie_select_node_iterator *it) +{ + return b_unbox(struct mie_select_node, it->it_base.entry, n_entry); +} + +MIE_API void mie_select_node_iterator_next(struct mie_select_node_iterator *it); +MIE_API bool mie_select_node_iterator_is_valid( + const struct mie_select_node_iterator *it); + +MIE_API struct mie_select_node *mie_select_node_create( + const struct mie_target *target, unsigned int op, + struct mie_type **results, size_t nr_results); +MIE_API void mie_select_node_destroy(struct mie_select_node *node); + +MIE_API enum mie_status mie_select_node_set_operands( + struct mie_select_node *node, struct mie_select_value *operands, + size_t nr_operands); +MIE_API enum mie_status mie_select_node_clear_operands(struct mie_select_node *node); + +MIE_API void mie_select_node_get_users( + struct mie_select_node *node, struct mie_select_node_iterator *it); +MIE_API void mie_select_node_get_uses( + struct mie_select_node *node, struct mie_select_node_iterator *it); + +MIE_API struct mie_select_node *mie_select_node_get_glued_node( + struct mie_select_node *node); +MIE_API struct mie_select_node *mie_select_node_get_glued_user( + struct mie_select_node *node); + #endif diff --git a/mie/include/mie/select/opcode.h b/mie/include/mie/select/opcode.h index 25d0203..f2b5bd3 100644 --- a/mie/include/mie/select/opcode.h +++ b/mie/include/mie/select/opcode.h @@ -4,10 +4,23 @@ enum mie_select_opcode { MIE_SELECT_OP_NONE = 0, MIE_SELECT_OP_ENTRY, + MIE_SELECT_OP_ROOT, + MIE_SELECT_OP_BLOCK, + MIE_SELECT_OP_CONSTANT, + MIE_SELECT_OP_FRAME_INDEX, + MIE_SELECT_OP_REGISTER, + MIE_SELECT_OP_COPY_FROM_REG, + MIE_SELECT_OP_COPY_TO_REG, + MIE_SELECT_OP_GLOBAL_ADDRESS, + MIE_SELECT_OP_LOAD, + MIE_SELECT_OP_STORE, MIE_SELECT_OP_ADD, MIE_SELECT_OP_SUB, MIE_SELECT_OP_MUL, MIE_SELECT_OP_DIV, + MIE_SELECT_OP_XOR, + MIE_SELECT_OP_BR, + MIE_SELECT_OP_BR_COND, }; #endif diff --git a/mie/include/mie/status.h b/mie/include/mie/status.h index 415a1a3..f3b0c24 100644 --- a/mie/include/mie/status.h +++ b/mie/include/mie/status.h @@ -2,7 +2,11 @@ #define MIE_STATUS_H_ enum mie_status { - MIE_OK = 0, + MIE_SUCCESS = 0, + MIE_ERR_NOT_SUPPORTED, + MIE_ERR_INVALID_VALUE, + MIE_ERR_NO_MEMORY, + MIE_ERR_NO_ENTRY, }; #endif diff --git a/mie/include/mie/target/select.h b/mie/include/mie/target/select.h new file mode 100644 index 0000000..d6b3a7c --- /dev/null +++ b/mie/include/mie/target/select.h @@ -0,0 +1,34 @@ +#ifndef MIE_TARGET_SELECT_H_ +#define MIE_TARGET_SELECT_H_ + +#include +#include +#include + +struct mie_target; +struct mie_instr; +struct mie_select_builder; + +struct mie_target_select_ops { + size_t (*s_node_name)( + const struct mie_target *, unsigned int, char *, size_t); + enum mie_status (*s_lower_call)( + const struct mie_target *, struct mie_select_builder *, + struct mie_instr *); + enum mie_status (*s_lower_msg)( + const struct mie_target *, struct mie_select_builder *, + struct mie_instr *); +}; + +MIE_API size_t mie_target_select_node_name( + const struct mie_target *target, unsigned int opcode, char *out, + size_t max); + +MIE_API enum mie_status mie_target_select_lower_call( + const struct mie_target *target, struct mie_select_builder *builder, + struct mie_instr *instr); +MIE_API enum mie_status mie_target_select_lower_msg( + const struct mie_target *target, struct mie_select_builder *builder, + struct mie_instr *instr); + +#endif diff --git a/mie/include/mie/target/target.h b/mie/include/mie/target/target.h index 4002d43..e4e28d1 100644 --- a/mie/include/mie/target/target.h +++ b/mie/include/mie/target/target.h @@ -1,7 +1,14 @@ #ifndef MIE_TARGET_TARGET_H_ #define MIE_TARGET_TARGET_H_ +#include +#include + struct mie_target { + const char *t_name; + const struct mie_target_select_ops *t_select; }; +MIE_API const struct mie_target *mie_target_builtin(void); + #endif diff --git a/mie/include/mie/type.h b/mie/include/mie/type.h index ea75b05..612bcea 100644 --- a/mie/include/mie/type.h +++ b/mie/include/mie/type.h @@ -35,4 +35,6 @@ struct mie_type { extern struct mie_type *mie_type_create(void); +MIE_API void mie_type_to_string(const struct mie_type *type, char *out, size_t max); + #endif diff --git a/mie/select/alloca.c b/mie/select/alloca.c new file mode 100644 index 0000000..5d6515e --- /dev/null +++ b/mie/select/alloca.c @@ -0,0 +1,33 @@ +#include "builder.h" + +#include +#include +#include +#include + +static enum mie_status push( + struct mie_select_builder *builder, struct mie_instr *instr) +{ + struct mie_alloca *alloca = (struct mie_alloca *)instr; + struct mie_select_graph *graph = mie_select_builder_get_graph(builder); + + struct mie_type *ptr_type = mie_ctx_get_type( + mie_select_builder_get_ctx(builder), MIE_TYPE_PTR); + struct mie_select_value frame_index; + enum mie_status status = mie_select_graph_get_node( + graph, MIE_SELECT_OP_FRAME_INDEX, NULL, 0, &ptr_type, 1, + &frame_index); + + if (status != MIE_SUCCESS) { + return status; + } + + frame_index.v_node->n_flags = MIE_SELECT_NODE_F_IVALUE; + frame_index.v_node->n_value_i = graph->g_frame_index++; + + return select_builder_set_value(builder, MIE_VALUE(instr), &frame_index); +} + +struct select_instr_type select_alloca = { + .i_push = push, +}; diff --git a/mie/select/binary-op.c b/mie/select/binary-op.c new file mode 100644 index 0000000..a1864f5 --- /dev/null +++ b/mie/select/binary-op.c @@ -0,0 +1,54 @@ +#include "builder.h" + +#include +#include + +#define DEFINE_PUSH_FUNCTION(name, op) \ + static enum mie_status push_##name( \ + struct mie_select_builder *builder, struct mie_instr *instr) \ + { \ + return push_op(op, builder, instr); \ + } + +#define DEFINE_OP(name) \ + struct select_instr_type select_##name = { \ + .i_push = push_##name, \ + } + +static enum mie_status push_op( + unsigned int opcode, struct mie_select_builder *builder, + struct mie_instr *instr) +{ + struct mie_binary_op *op = (struct mie_binary_op *)instr; + + struct mie_select_value *operands[] = { + select_builder_get_value(builder, op->op_left), + select_builder_get_value(builder, op->op_right), + }; + size_t nr_operands = sizeof operands / sizeof operands[0]; + + struct mie_type *result[] = { + op->op_type, + }; + size_t nr_results = sizeof result / sizeof result[0]; + + struct mie_select_value node = {0}; + enum mie_status status = mie_select_graph_get_node( + mie_select_builder_get_graph(builder), opcode, operands, + nr_operands, result, nr_results, &node); + if (status != MIE_SUCCESS) { + return status; + } + + return select_builder_set_value(builder, MIE_VALUE(instr), &node); +} + +DEFINE_PUSH_FUNCTION(add, MIE_SELECT_OP_ADD); +DEFINE_PUSH_FUNCTION(sub, MIE_SELECT_OP_SUB); +DEFINE_PUSH_FUNCTION(mul, MIE_SELECT_OP_MUL); +DEFINE_PUSH_FUNCTION(div, MIE_SELECT_OP_DIV); + +DEFINE_OP(add); +DEFINE_OP(sub); +DEFINE_OP(mul); +DEFINE_OP(div); diff --git a/mie/select/builder.c b/mie/select/builder.c new file mode 100644 index 0000000..08a787c --- /dev/null +++ b/mie/select/builder.c @@ -0,0 +1,298 @@ +#include "builder.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; +} diff --git a/mie/select/builder.h b/mie/select/builder.h new file mode 100644 index 0000000..b4d89e0 --- /dev/null +++ b/mie/select/builder.h @@ -0,0 +1,36 @@ +#ifndef _SELECT_BUILDER_H_ +#define _SELECT_BUILDER_H_ + +#include +#include +#include +#include + +struct mie_select_value; +struct mie_select_builder; + +struct select_instr_type { + enum mie_status (*i_push)(struct mie_select_builder *, struct mie_instr *); +}; + +struct select_node_type { +}; + +extern const struct select_instr_type *select_type_for_instr( + enum mie_instr_type instr); +extern const struct select_node_type *select_type_for_node( + enum mie_select_opcode node); + +extern struct mie_select_value *select_builder_get_value( + struct mie_select_builder *builder, struct mie_value *ir_val); +extern enum mie_status select_builder_set_value( + struct mie_select_builder *builder, struct mie_value *ir_val, + struct mie_select_value *graph_val); + +extern struct mie_select_value *select_builder_get_mem_access( + struct mie_select_builder *builder, struct mie_value *ir_val); +extern enum mie_status select_builder_set_mem_access( + struct mie_select_builder *builder, struct mie_value *ir_val, + struct mie_select_value *graph_val); + +#endif diff --git a/mie/select/dump.c b/mie/select/dump.c new file mode 100644 index 0000000..55209c7 --- /dev/null +++ b/mie/select/dump.c @@ -0,0 +1,278 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static b_status write_operand_const(struct mie_value *value, b_stream *out) +{ + struct mie_const *c = MIE_CONST(value); + + switch (c->c_type->t_id) { + case MIE_TYPE_INT: { + struct mie_int *v = MIE_INT(c); + b_stream_write_fmt(out, NULL, "%" PRId64, v->i_value); + break; + } + case MIE_TYPE_PTR: + case MIE_TYPE_ID: + b_stream_write_fmt(out, NULL, "%%%s", value->v_name.n_str); + break; + case MIE_TYPE_STR: { + struct mie_string *v = MIE_STRING(c); + + b_stream_write_fmt(out, NULL, "\"%s\"", v->s_value); + break; + } + case MIE_TYPE_ATOM: { + struct mie_atom *v = MIE_ATOM(c); + + b_stream_write_fmt(out, NULL, "\"%s\"", v->a_value); + break; + } + case MIE_TYPE_SELECTOR: { + struct mie_selector *v = MIE_SELECTOR(c); + + b_stream_write_fmt(out, NULL, "\"%s\"", v->sel_value); + break; + } + case MIE_TYPE_CLASS: + b_stream_write_fmt(out, NULL, "@%s", value->v_name.n_str); + break; + default: + break; + } + + return B_SUCCESS; +} + +static void write_operand(struct mie_value *value, b_stream *out) +{ + if (!value) { + b_stream_write_fmt(out, NULL, ""); + return; + } + + switch (value->v_type->t_id) { + case MIE_VALUE_CONST: + write_operand_const(value, out); + break; + case MIE_VALUE_INSTR: + case MIE_VALUE_BLOCK: + case MIE_VALUE_ARG: + b_stream_write_fmt(out, NULL, "%%%s", value->v_name.n_str); + break; + case MIE_VALUE_DATA: + case MIE_VALUE_FUNC: + b_stream_write_fmt(out, NULL, "@%s", value->v_name.n_str); + break; + default: + b_stream_write_fmt( + out, NULL, "", value->v_type->t_id); + break; + } +} + +static void node_dump_text(struct mie_select_node *node) +{ + printf("N%zu: ", node->n_id); + char tmp[128]; + + for (size_t i = 0; i < node->n_nr_results; i++) { + if (i > 0) { + printf(","); + } + + if (node->n_results[i]->t_id == MIE_TYPE_OTHER) { + printf("ch"); + } else { + mie_type_to_string(node->n_results[i], tmp, sizeof tmp); + printf("%s", tmp); + } + } + + if (node->n_nr_results > 0) { + printf(" = "); + } + + mie_target_select_node_name(node->n_target, node->n_opcode, tmp, sizeof tmp); + printf("%s", tmp); + + if (node->n_flags & (MIE_SELECT_NODE_F_IVALUE | MIE_SELECT_NODE_F_PVALUE)) { + printf("<"); + } + + if (node->n_flags & MIE_SELECT_NODE_F_IVALUE) { + printf("%lld", node->n_value_i); + } + + if ((node->n_flags & MIE_SELECT_NODE_F_IVALUE) + && (node->n_flags & MIE_SELECT_NODE_F_PVALUE)) { + printf(","); + } + + if (node->n_flags & MIE_SELECT_NODE_F_PVALUE) { + write_operand(node->n_value_p, b_stdout); + } + + if (node->n_flags & (MIE_SELECT_NODE_F_IVALUE | MIE_SELECT_NODE_F_PVALUE)) { + printf(">"); + } + + if (node->n_nr_operands) { + printf("("); + } + + for (size_t i = 0; i < node->n_nr_operands; i++) { + if (i > 0) { + printf(", "); + } + + const struct mie_select_value *value = &node->n_operands[i].u_value; + printf("N%zu:%u", value->v_node->n_id, value->v_index); + } + + if (node->n_nr_operands) { + printf(")"); + } + + printf("\n"); +} + +static void node_dump_dot(struct mie_select_node *node, b_stream *out) +{ + b_stream_write_fmt(out, NULL, "\tN%zu [label=\"{", node->n_id); + + if (node->n_nr_operands > 0) { + b_stream_write_string(out, "{", NULL); + } + + for (size_t i = 0; i < node->n_nr_operands; i++) { + if (i > 0) { + b_stream_write_string(out, "|", NULL); + } + + b_stream_write_fmt(out, NULL, " %zu", i, i); + } + + if (node->n_nr_operands > 0) { + b_stream_write_string(out, "}|", NULL); + } + + char tmp[256]; + mie_target_select_node_name(node->n_target, node->n_opcode, tmp, sizeof tmp); + b_stream_write_fmt(out, NULL, " %s", tmp); + + if (node->n_flags & (MIE_SELECT_NODE_F_IVALUE | MIE_SELECT_NODE_F_PVALUE)) { + b_stream_write_string(out, "\\<", NULL); + } + + if (node->n_flags & MIE_SELECT_NODE_F_IVALUE) { + b_stream_write_fmt(out, NULL, "%lld", node->n_value_i); + } + + if ((node->n_flags & MIE_SELECT_NODE_F_IVALUE) + && (node->n_flags & MIE_SELECT_NODE_F_PVALUE)) { + b_stream_write_string(out, ",", NULL); + } + + if (node->n_flags & MIE_SELECT_NODE_F_PVALUE) { + write_operand(node->n_value_p, out); + } + + if (node->n_flags & (MIE_SELECT_NODE_F_IVALUE | MIE_SELECT_NODE_F_PVALUE)) { + b_stream_write_string(out, "\\>", NULL); + } + + b_stream_write_fmt(out, NULL, "|{N%zu}", node->n_id); + + if (node->n_nr_results > 0) { + b_stream_write_string(out, "|{", NULL); + } + + for (size_t i = 0; i < node->n_nr_results; i++) { + if (i > 0) { + b_stream_write_string(out, "|", NULL); + } + + b_stream_write_fmt(out, NULL, " ", i, i); + + if (node->n_results[i]->t_id == MIE_TYPE_OTHER) { + b_stream_write_string(out, "ch", NULL); + } else { + mie_type_to_string(node->n_results[i], tmp, sizeof tmp); + b_stream_write_string(out, tmp, NULL); + } + } + + if (node->n_nr_results > 0) { + b_stream_write_string(out, "}", NULL); + } + + b_stream_write_string(out, "}\"];\n", NULL); +} + +static void node_links_dump_dot(struct mie_select_node *node, b_stream *out) +{ + for (size_t i = 0; i < node->n_nr_operands; i++) { + struct mie_select_use *use = &node->n_operands[i]; + b_stream_write_fmt( + out, NULL, "\tN%zu:in%zu -> N%zu:out%zu", node->n_id, i, + use->u_value.v_node->n_id, use->u_value.v_index); + + if (use->u_value.v_node->n_results[use->u_value.v_index]->t_id + == MIE_TYPE_OTHER) { + b_stream_write_string( + out, "[style=dashed,color=blue]", NULL); + } + + b_stream_write_string(out, ";\n", NULL); + } +} + +void mie_select_graph_dump_text(struct mie_select_graph *graph) +{ + b_queue_iterator it; + b_queue_foreach (&it, &graph->g_nodes) { + struct mie_select_node *node + = b_unbox(struct mie_select_node, it.entry, n_entry); + node_dump_text(node); + } +} + +void mie_select_graph_dump_dot(struct mie_select_graph *graph) +{ + FILE *fp = fopen("graph.dot", "w"); + + b_stream *tmpstream = b_stream_open_fp(fp); + + b_stream_write_string(tmpstream, "digraph G {\n", NULL); + b_stream_write_string(tmpstream, "\tnode [shape=Mrecord];\n", NULL); + b_stream_write_string(tmpstream, "\trankdir=\"BT\";\n", NULL); + + b_queue_iterator it; + b_queue_foreach (&it, &graph->g_nodes) { + struct mie_select_node *node + = b_unbox(struct mie_select_node, it.entry, n_entry); + node_dump_dot(node, tmpstream); + } + + b_queue_foreach (&it, &graph->g_nodes) { + struct mie_select_node *node + = b_unbox(struct mie_select_node, it.entry, n_entry); + node_links_dump_dot(node, tmpstream); + } + + b_stream_write_string(tmpstream, "}\n", NULL); + + b_stream_close(tmpstream); + + system("open graph.dot"); + + fclose(fp); +} diff --git a/mie/select/graph.c b/mie/select/graph.c new file mode 100644 index 0000000..673b38c --- /dev/null +++ b/mie/select/graph.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct mie_select_graph *mie_select_graph_create(struct mie_ctx *ctx) +{ + struct mie_select_graph *out = malloc(sizeof *out); + if (!out) { + return NULL; + } + + memset(out, 0x0, sizeof *out); + + enum mie_status status = MIE_SUCCESS; + struct mie_select_value entry; + + struct mie_type *entry_values[] = { + mie_ctx_get_type(ctx, MIE_TYPE_OTHER), + mie_ctx_get_type(ctx, MIE_TYPE_GLUE), + }; + const size_t nr_entry_values + = sizeof entry_values / sizeof entry_values[0]; + + status = mie_select_graph_get_node( + out, MIE_SELECT_OP_ENTRY, NULL, 0, entry_values, + nr_entry_values, &entry); + if (status != MIE_SUCCESS) { + free(out); + return NULL; + } + + out->g_entry.v_node = entry.v_node; + + return out; +} + +void mie_select_graph_destroy(struct mie_select_graph *graph) +{ + b_queue_iterator it; + b_queue_iterator_begin(&graph->g_nodes, &it); + while (b_queue_iterator_is_valid(&it)) { + struct mie_select_node *node + = b_unbox(struct mie_select_node, it.entry, n_entry); + b_queue_iterator_erase(&it); + +#if 0 + if (node->n_value) { + mie_value_destroy(node->n_value); + } +#endif + + free(node); + } + + free(graph); +} + +enum mie_status mie_select_graph_get_node( + struct mie_select_graph *graph, unsigned int op, + struct mie_select_value **operands, size_t nr_operands, + struct mie_type **values, size_t nr_values, struct mie_select_value *out) +{ + struct mie_select_node *node = mie_select_node_create( + mie_target_builtin(), op, values, nr_values); + if (!node) { + return MIE_ERR_NO_MEMORY; + } + + struct mie_select_value *operands2 + = calloc(nr_operands, sizeof *operands2); + for (size_t i = 0; i < nr_operands; i++) { + assert(operands[i]); + memcpy(&operands2[i], operands[i], sizeof *operands2); + } + + mie_select_node_set_operands(node, operands2, nr_operands); + free(operands2); + + node->n_id = graph->g_node_id++; + + for (size_t i = 0; i < nr_values; i++) { + if (values[i]->t_id == MIE_TYPE_OTHER) { + graph->g_last_chain.v_node = node; + graph->g_last_chain.v_index = i; + } + } + + b_queue_push_back(&graph->g_nodes, &node->n_entry); + + out->v_node = node; + out->v_index = 0; + + return MIE_SUCCESS; +} diff --git a/mie/select/instr.c b/mie/select/instr.c new file mode 100644 index 0000000..5db495e --- /dev/null +++ b/mie/select/instr.c @@ -0,0 +1,32 @@ +#include "builder.h" + +#include +#include + +#define DECLARE_INSTR_TYPE(name) extern struct select_instr_type select_##name +#define INSTR_TYPE_ENTRY(op, name) [MIE_INSTR_##op] = &select_##name + +DECLARE_INSTR_TYPE(alloca); +DECLARE_INSTR_TYPE(add); +DECLARE_INSTR_TYPE(sub); +DECLARE_INSTR_TYPE(mul); +DECLARE_INSTR_TYPE(div); +DECLARE_INSTR_TYPE(load); +DECLARE_INSTR_TYPE(store); + +static const struct select_instr_type *instr_types[] = { + INSTR_TYPE_ENTRY(ALLOCA, alloca), INSTR_TYPE_ENTRY(ADD, add), + INSTR_TYPE_ENTRY(SUB, sub), INSTR_TYPE_ENTRY(MUL, mul), + INSTR_TYPE_ENTRY(DIV, div), INSTR_TYPE_ENTRY(LOAD, load), + INSTR_TYPE_ENTRY(STORE, store), +}; +static const size_t nr_instr_types = sizeof instr_types / sizeof instr_types[0]; + +const struct select_instr_type *select_type_for_instr(enum mie_instr_type instr) +{ + if (instr < 0 || instr >= nr_instr_types) { + return NULL; + } + + return instr_types[instr]; +} diff --git a/mie/select/node.c b/mie/select/node.c new file mode 100644 index 0000000..d7c6e0a --- /dev/null +++ b/mie/select/node.c @@ -0,0 +1,140 @@ +#include "builder.h" + +#include +#include +#include +#include +#include +#include + +static const struct select_node_type *node_types[] = { + +}; +static const size_t nr_node_types = sizeof node_types / sizeof node_types[0]; + +const struct select_node_type *select_type_for_node(enum mie_select_opcode node) +{ + if (node < 0 || node >= nr_node_types) { + return NULL; + } + + return node_types[node]; +} + +void mie_select_node_iterator_next(struct mie_select_node_iterator *it) +{ + b_queue_iterator_next(&it->it_base); +} + +bool mie_select_node_iterator_is_valid(const struct mie_select_node_iterator *it) +{ + return b_queue_iterator_is_valid(&it->it_base); +} + +struct mie_select_node *mie_select_node_create( + const struct mie_target *target, unsigned int op, + struct mie_type **results, size_t nr_results) +{ + struct mie_select_node *out = malloc(sizeof *out); + if (!out) { + return NULL; + } + + memset(out, 0x0, sizeof *out); + + out->n_target = target; + out->n_opcode = op; + out->n_results = calloc(nr_results, sizeof(struct mie_type *)); + if (!out->n_results) { + free(out); + return NULL; + } + + out->n_nr_results = nr_results; + memcpy(out->n_results, results, nr_results * sizeof(struct mie_type *)); + + return out; +} + +void mie_select_node_destroy(struct mie_select_node *node) +{ + if (node->n_results) { + free(node->n_results); + } + + mie_select_node_clear_operands(node); + + free(node); +} + +enum mie_status mie_select_node_set_operands( + struct mie_select_node *node, struct mie_select_value *operands, + size_t nr_operands) +{ + mie_select_node_clear_operands(node); + if (!nr_operands) { + return MIE_SUCCESS; + } + + struct mie_select_use *uses = calloc(nr_operands, sizeof *uses); + if (!uses) { + return MIE_ERR_NO_MEMORY; + } + + memset(uses, 0x0, sizeof *uses); + + for (size_t i = 0; i < nr_operands; i++) { + struct mie_select_node *operand_node = operands[i].v_node; + + uses[i].u_user = node; + uses[i].u_value = operands[i]; + + b_queue_push_back(&operand_node->n_use, &uses[i].u_entry); + } + + node->n_operands = uses; + node->n_nr_operands = nr_operands; + + return MIE_SUCCESS; +} + +enum mie_status mie_select_node_clear_operands(struct mie_select_node *node) +{ + struct mie_select_use_iterator it; + mie_select_use_foreach(&it, &node->n_use) + { + struct mie_select_use *use = mie_select_use_iterator_unbox(&it); + if (use->u_value.v_node == node) { + memset(&use->u_value, 0x0, sizeof use->u_value); + } + } + + if (node->n_operands) { + free(node->n_operands); + } + + node->n_operands = NULL; + node->n_nr_operands = 0; + + return MIE_SUCCESS; +} + +void mie_select_node_get_users( + struct mie_select_node *node, struct mie_select_node_iterator *it) +{ +} + +void mie_select_node_get_uses( + struct mie_select_node *node, struct mie_select_node_iterator *it) +{ +} + +struct mie_select_node *mie_select_node_get_glued_node(struct mie_select_node *node) +{ + return NULL; +} + +struct mie_select_node *mie_select_node_get_glued_user(struct mie_select_node *node) +{ + return NULL; +} diff --git a/mie/select/ptr.c b/mie/select/ptr.c new file mode 100644 index 0000000..ac032de --- /dev/null +++ b/mie/select/ptr.c @@ -0,0 +1,85 @@ +#include "builder.h" + +#include +#include +#include + +static enum mie_status push_load( + struct mie_select_builder *builder, struct mie_instr *instr) +{ + struct mie_select_graph *graph = mie_select_builder_get_graph(builder); + struct mie_load *load = (struct mie_load *)instr; + + struct mie_select_value *chain + = select_builder_get_mem_access(builder, load->l_src); + if (!chain) { + chain = &graph->g_entry; + } + + struct mie_select_value *operands[] = { + chain, + select_builder_get_value(builder, load->l_src), + }; + size_t nr_operands = sizeof operands / sizeof operands[0]; + + struct mie_type *result[] = { + load->l_type, + mie_ctx_get_type(mie_select_builder_get_ctx(builder), MIE_TYPE_OTHER), + }; + size_t nr_results = sizeof result / sizeof result[0]; + + struct mie_select_value node = {0}; + enum mie_status status = mie_select_graph_get_node( + graph, MIE_SELECT_OP_LOAD, operands, nr_operands, result, + nr_results, &node); + if (status != MIE_SUCCESS) { + return status; + } + + select_builder_set_mem_access(builder, load->l_src, &node); + return select_builder_set_value(builder, MIE_VALUE(instr), &node); +} + +static enum mie_status push_store( + struct mie_select_builder *builder, struct mie_instr *instr) +{ + struct mie_store *store = (struct mie_store *)instr; + struct mie_select_graph *graph = mie_select_builder_get_graph(builder); + + struct mie_select_value *chain + = select_builder_get_mem_access(builder, store->s_dest); + if (!chain) { + chain = &graph->g_entry; + } + + struct mie_select_value *operands[] = { + chain, + select_builder_get_value(builder, store->s_val), + select_builder_get_value(builder, store->s_dest), + }; + size_t nr_operands = sizeof operands / sizeof operands[0]; + + struct mie_type *result[] = { + mie_ctx_get_type(mie_select_builder_get_ctx(builder), MIE_TYPE_OTHER), + }; + size_t nr_results = sizeof result / sizeof result[0]; + + struct mie_select_value node = {0}; + enum mie_status status = mie_select_graph_get_node( + graph, MIE_SELECT_OP_STORE, operands, nr_operands, result, + nr_results, &node); + if (status != MIE_SUCCESS) { + return status; + } + + select_builder_set_mem_access(builder, store->s_dest, &node); + return select_builder_set_value(builder, MIE_VALUE(instr), &node); +} + +struct select_instr_type select_load = { + .i_push = push_load, +}; + +struct select_instr_type select_store = { + .i_push = push_store, +}; diff --git a/mie/target/select.c b/mie/target/select.c new file mode 100644 index 0000000..f815d58 --- /dev/null +++ b/mie/target/select.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +#define NODE_NAME(op, name) \ + case MIE_SELECT_OP_##op: \ + return snprintf(out, max, name) + +static size_t node_name( + const struct mie_target *target, unsigned int opcode, char *out, size_t max) +{ + switch (opcode) { + NODE_NAME(ENTRY, "Entry"); + NODE_NAME(ROOT, "Root"); + NODE_NAME(BLOCK, "Root"); + NODE_NAME(CONSTANT, "Constant"); + NODE_NAME(FRAME_INDEX, "FrameIndex"); + NODE_NAME(REGISTER, "Register"); + NODE_NAME(COPY_FROM_REG, "CopyFromReg"); + NODE_NAME(COPY_TO_REG, "CopyToReg"); + NODE_NAME(GLOBAL_ADDRESS, "GlobalAddress"); + NODE_NAME(LOAD, "Load"); + NODE_NAME(STORE, "Store"); + NODE_NAME(ADD, "Add"); + NODE_NAME(SUB, "Sub"); + NODE_NAME(MUL, "Mul"); + NODE_NAME(DIV, "Div"); + NODE_NAME(XOR, "Xor"); + NODE_NAME(BR, "Branch"); + NODE_NAME(BR_COND, "CondBranch"); + default: + return snprintf(out, max, "UNKNOWN"); + } + + return 0; +} + +const struct mie_target_select_ops __mie_builtin_select_ops = { + .s_node_name = node_name, +}; + +size_t mie_target_select_node_name( + const struct mie_target *target, unsigned int opcode, char *out, size_t max) +{ + size_t w = snprintf(out, max, "%s::", target->t_name); + + if (w < max) { + max -= w; + } else { + max = 0; + } + + out += w; + + if (target->t_select && target->t_select->s_node_name) { + w += target->t_select->s_node_name(target, opcode, out, max); + } else { + w += snprintf(out, max, "%u", opcode); + } + + return w; +} + +enum mie_status mie_target_select_lower_call( + const struct mie_target *target, struct mie_select_builder *builder, + struct mie_instr *instr) +{ + if (!target->t_select || !target->t_select->s_lower_call) { + return MIE_ERR_NOT_SUPPORTED; + } + + return target->t_select->s_lower_call(target, builder, instr); +} + +enum mie_status mie_target_select_lower_msg( + const struct mie_target *target, struct mie_select_builder *builder, + struct mie_instr *instr) +{ + if (!target->t_select || !target->t_select->s_lower_msg) { + return MIE_ERR_NOT_SUPPORTED; + } + + return target->t_select->s_lower_call(target, builder, instr); +} diff --git a/mie/target/target.c b/mie/target/target.c new file mode 100644 index 0000000..2df6bd3 --- /dev/null +++ b/mie/target/target.c @@ -0,0 +1,13 @@ +#include + +const struct mie_target_select_ops __mie_builtin_select_ops; + +static const struct mie_target builtin_target = { + .t_name = "Mie", + .t_select = &__mie_builtin_select_ops, +}; + +const struct mie_target *mie_target_builtin(void) +{ + return &builtin_target; +}