mie: implement instruction selection graph generation for binary ops and load/store
This commit is contained in:
@@ -2,10 +2,26 @@
|
||||
#define MIE_SELECT_BUILDER_H_
|
||||
|
||||
#include <mie/misc.h>
|
||||
#include <mie/status.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
#include <blue/core/queue.h>
|
||||
#include <mie/misc.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
34
mie/include/mie/target/select.h
Normal file
34
mie/include/mie/target/select.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef MIE_TARGET_SELECT_H_
|
||||
#define MIE_TARGET_SELECT_H_
|
||||
|
||||
#include <mie/misc.h>
|
||||
#include <mie/status.h>
|
||||
#include <stddef.h>
|
||||
|
||||
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
|
||||
@@ -1,7 +1,14 @@
|
||||
#ifndef MIE_TARGET_TARGET_H_
|
||||
#define MIE_TARGET_TARGET_H_
|
||||
|
||||
#include <mie/misc.h>
|
||||
#include <mie/target/select.h>
|
||||
|
||||
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
|
||||
|
||||
@@ -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
|
||||
|
||||
33
mie/select/alloca.c
Normal file
33
mie/select/alloca.c
Normal file
@@ -0,0 +1,33 @@
|
||||
#include "builder.h"
|
||||
|
||||
#include <mie/ctx.h>
|
||||
#include <mie/ir/alloca.h>
|
||||
#include <mie/select/graph.h>
|
||||
#include <mie/select/node.h>
|
||||
|
||||
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,
|
||||
};
|
||||
54
mie/select/binary-op.c
Normal file
54
mie/select/binary-op.c
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "builder.h"
|
||||
|
||||
#include <mie/ir/op.h>
|
||||
#include <mie/select/graph.h>
|
||||
|
||||
#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);
|
||||
298
mie/select/builder.c
Normal file
298
mie/select/builder.c
Normal file
@@ -0,0 +1,298 @@
|
||||
#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;
|
||||
}
|
||||
36
mie/select/builder.h
Normal file
36
mie/select/builder.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef _SELECT_BUILDER_H_
|
||||
#define _SELECT_BUILDER_H_
|
||||
|
||||
#include <mie/ir/instr.h>
|
||||
#include <mie/select/builder.h>
|
||||
#include <mie/select/opcode.h>
|
||||
#include <mie/status.h>
|
||||
|
||||
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
|
||||
278
mie/select/dump.c
Normal file
278
mie/select/dump.c
Normal file
@@ -0,0 +1,278 @@
|
||||
#include <blue/io/file.h>
|
||||
#include <blue/io/path.h>
|
||||
#include <inttypes.h>
|
||||
#include <mie/ir/const.h>
|
||||
#include <mie/ir/value.h>
|
||||
#include <mie/select/graph.h>
|
||||
#include <mie/select/node.h>
|
||||
#include <mie/target/select.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
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, "<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, "<unknown-value:%d>", 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, "<in%zu> %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, "<Name> %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, "<out%zu> ", 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);
|
||||
}
|
||||
100
mie/select/graph.c
Normal file
100
mie/select/graph.c
Normal file
@@ -0,0 +1,100 @@
|
||||
#include <assert.h>
|
||||
#include <mie/ctx.h>
|
||||
#include <mie/select/graph.h>
|
||||
#include <mie/select/node.h>
|
||||
#include <mie/select/opcode.h>
|
||||
#include <mie/status.h>
|
||||
#include <mie/target/target.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
32
mie/select/instr.c
Normal file
32
mie/select/instr.c
Normal file
@@ -0,0 +1,32 @@
|
||||
#include "builder.h"
|
||||
|
||||
#include <mie/select/opcode.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#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];
|
||||
}
|
||||
140
mie/select/node.c
Normal file
140
mie/select/node.c
Normal file
@@ -0,0 +1,140 @@
|
||||
#include "builder.h"
|
||||
|
||||
#include <mie/select/graph.h>
|
||||
#include <mie/select/node.h>
|
||||
#include <mie/select/opcode.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
85
mie/select/ptr.c
Normal file
85
mie/select/ptr.c
Normal file
@@ -0,0 +1,85 @@
|
||||
#include "builder.h"
|
||||
|
||||
#include <mie/ctx.h>
|
||||
#include <mie/ir/ptr.h>
|
||||
#include <mie/select/graph.h>
|
||||
|
||||
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,
|
||||
};
|
||||
85
mie/target/select.c
Normal file
85
mie/target/select.c
Normal file
@@ -0,0 +1,85 @@
|
||||
#include <mie/select/opcode.h>
|
||||
#include <mie/target/select.h>
|
||||
#include <mie/target/target.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
13
mie/target/target.c
Normal file
13
mie/target/target.c
Normal file
@@ -0,0 +1,13 @@
|
||||
#include <mie/target/target.h>
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user