mie: refactor ir api into a separate sub-directory
This commit is contained in:
30
mie/ir/arg.c
Normal file
30
mie/ir/arg.c
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <mie/ir/arg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct mie_arg *mie_arg_create(struct mie_type *type)
|
||||
{
|
||||
struct mie_arg *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
|
||||
mie_value_init(&out->arg_base, MIE_VALUE_ARG);
|
||||
|
||||
out->arg_type = type;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static struct mie_type *get_type(struct mie_value *v, struct mie_ctx *ctx)
|
||||
{
|
||||
struct mie_arg *arg = MIE_ARG(v);
|
||||
return arg->arg_type;
|
||||
}
|
||||
|
||||
const struct mie_value_type arg_value_type = {
|
||||
.t_id = MIE_VALUE_ARG,
|
||||
.t_get_type = get_type,
|
||||
};
|
||||
97
mie/ir/block.c
Normal file
97
mie/ir/block.c
Normal file
@@ -0,0 +1,97 @@
|
||||
#include <mie/ir/block.h>
|
||||
#include <mie/ir/ctx.h>
|
||||
#include <mie/ir/func.h>
|
||||
#include <mie/ir/instr.h>
|
||||
#include <mie/ir/type.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct mie_block *mie_block_create(struct mie_func *parent, const char *name)
|
||||
{
|
||||
struct mie_block *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
|
||||
mie_value_init(&out->b_base, MIE_VALUE_BLOCK);
|
||||
|
||||
struct mie_value *block = MIE_VALUE(out);
|
||||
|
||||
if (parent) {
|
||||
block = mie_func_generate_value_name(parent, block, name);
|
||||
if (!block) {
|
||||
free(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b_queue_push_back(&parent->f_blocks, &block->v_entry);
|
||||
out->b_parent = parent;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
bool mie_block_add_instr(struct mie_block *block, struct mie_instr *instr)
|
||||
{
|
||||
switch (instr->i_type) {
|
||||
case MIE_INSTR_PHI:
|
||||
if (!b_queue_empty(&block->b_instr) || block->b_terminator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
b_queue_push_back(&block->b_phi, &instr->i_base.v_entry);
|
||||
return true;
|
||||
case MIE_INSTR_RET:
|
||||
case MIE_INSTR_BR:
|
||||
case MIE_INSTR_SWITCH:
|
||||
if (block->b_terminator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
block->b_terminator = instr;
|
||||
return true;
|
||||
default:
|
||||
if (block->b_terminator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
b_queue_push_back(&block->b_instr, &instr->i_base.v_entry);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static struct mie_type *get_type(struct mie_value *v, struct mie_ctx *ctx)
|
||||
{
|
||||
return mie_ctx_get_type(ctx, MIE_TYPE_LABEL);
|
||||
}
|
||||
|
||||
static void cleanup(struct mie_value *value)
|
||||
{
|
||||
struct mie_block *block = MIE_BLOCK(value);
|
||||
|
||||
b_queue_iterator it;
|
||||
b_queue_iterator_begin(&block->b_phi, &it);
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
struct mie_value *v = b_unbox(struct mie_value, it.entry, v_entry);
|
||||
b_queue_iterator_erase(&it);
|
||||
mie_value_destroy(v);
|
||||
}
|
||||
|
||||
b_queue_iterator_begin(&block->b_instr, &it);
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
struct mie_value *v = b_unbox(struct mie_value, it.entry, v_entry);
|
||||
b_queue_iterator_erase(&it);
|
||||
mie_value_destroy(v);
|
||||
}
|
||||
|
||||
if (block->b_terminator) {
|
||||
mie_value_destroy(MIE_VALUE(block->b_terminator));
|
||||
}
|
||||
}
|
||||
|
||||
const struct mie_value_type block_value_type = {
|
||||
.t_id = MIE_VALUE_BLOCK,
|
||||
.t_get_type = get_type,
|
||||
.t_cleanup = cleanup,
|
||||
};
|
||||
793
mie/ir/builder.c
Normal file
793
mie/ir/builder.c
Normal file
@@ -0,0 +1,793 @@
|
||||
#include <blue/object/string.h>
|
||||
#include <mie/ir/alloca.h>
|
||||
#include <mie/ir/block.h>
|
||||
#include <mie/ir/branch.h>
|
||||
#include <mie/ir/builder.h>
|
||||
#include <mie/ir/ctx.h>
|
||||
#include <mie/ir/data.h>
|
||||
#include <mie/ir/func.h>
|
||||
#include <mie/ir/module.h>
|
||||
#include <mie/ir/msg.h>
|
||||
#include <mie/ir/op.h>
|
||||
#include <mie/ir/ptr.h>
|
||||
#include <mie/ir/record.h>
|
||||
#include <mie/ir/type.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct mie_builder *mie_builder_create(struct mie_ctx *ctx, struct mie_module *mod)
|
||||
{
|
||||
struct mie_builder *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
out->b_ctx = ctx;
|
||||
out->b_module = mod;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void mie_builder_destroy(struct mie_builder *builder)
|
||||
{
|
||||
free(builder);
|
||||
}
|
||||
|
||||
struct mie_func *mie_builder_get_current_func(struct mie_builder *builder)
|
||||
{
|
||||
struct mie_block *block = builder->b_current_block;
|
||||
if (!block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return block->b_parent;
|
||||
}
|
||||
|
||||
struct mie_record *mie_builder_put_record(
|
||||
struct mie_builder *builder, struct mie_const *val, const char *name)
|
||||
{
|
||||
if (!builder->b_module) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b_queue_iterator it = {};
|
||||
b_queue_foreach (&it, &builder->b_module->m_records) {
|
||||
struct mie_value *rec
|
||||
= b_unbox(struct mie_value, it.entry, v_entry);
|
||||
|
||||
if (!strcmp(rec->v_name.n_str, name)) {
|
||||
/* TODO what to do about `val` here? */
|
||||
return MIE_RECORD(rec);
|
||||
}
|
||||
}
|
||||
|
||||
struct mie_record *rec = mie_record_create(val);
|
||||
rec->r_base.v_name.n_str = b_strdup(name);
|
||||
b_queue_push_back(&builder->b_module->m_records, &rec->r_base.v_entry);
|
||||
|
||||
return rec;
|
||||
}
|
||||
|
||||
struct mie_record *mie_builder_get_record(
|
||||
struct mie_builder *builder, const char *name)
|
||||
{
|
||||
if (!builder->b_module) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b_queue_iterator it = {};
|
||||
b_queue_foreach (&it, &builder->b_module->m_records) {
|
||||
struct mie_value *rec
|
||||
= b_unbox(struct mie_value, it.entry, v_entry);
|
||||
|
||||
if (!strcmp(rec->v_name.n_str, name)) {
|
||||
return MIE_RECORD(rec);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void mie_builder_put_data(struct mie_builder *builder, struct mie_data *data)
|
||||
{
|
||||
if (!builder->b_module) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *data_name = data->d_base.v_name.n_str;
|
||||
struct mie_data *v = mie_module_get_data(builder->b_module, data_name);
|
||||
if (v) {
|
||||
return;
|
||||
}
|
||||
|
||||
mie_module_put_data(builder->b_module, data);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
void mie_builder_put_type(struct mie_builder *builder, struct mie_type *type)
|
||||
{
|
||||
if (!builder->b_module) {
|
||||
return;
|
||||
}
|
||||
|
||||
const char *type_name = type->t_base.v_name.n_str;
|
||||
struct mie_data *v = mie_module_get_data(builder->b_module, type_name);
|
||||
if (v) {
|
||||
return;
|
||||
}
|
||||
|
||||
mie_module_put_data(builder->b_module, MIE_VALUE);
|
||||
}
|
||||
#endif
|
||||
|
||||
void mie_builder_set_insert_point(
|
||||
struct mie_builder *builder, struct mie_block *block)
|
||||
{
|
||||
builder->b_current_block = block;
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_get_data_ptr(
|
||||
struct mie_builder *builder, const char *data_ident)
|
||||
{
|
||||
if (!builder->b_module) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_data *data = mie_module_get_data(builder->b_module, data_ident);
|
||||
if (!data) {
|
||||
struct mie_type *id
|
||||
= mie_ctx_get_type(builder->b_ctx, MIE_TYPE_ID);
|
||||
data = mie_data_create_extern_global(id, data_ident);
|
||||
|
||||
if (!data) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_module_put_data(builder->b_module, data, data_ident);
|
||||
}
|
||||
|
||||
return MIE_VALUE(data);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_get_string_ptr(
|
||||
struct mie_builder *builder, const char *s)
|
||||
{
|
||||
if (!builder->b_module) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_data *data = mie_module_get_string_ptr(builder->b_module, s);
|
||||
if (!data) {
|
||||
struct mie_type *str
|
||||
= mie_ctx_get_type(builder->b_ctx, MIE_TYPE_STR);
|
||||
struct mie_value *value = mie_ctx_get_string(builder->b_ctx, s);
|
||||
|
||||
data = mie_data_create_const((struct mie_const *)value);
|
||||
|
||||
if (!data) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_module_put_data(builder->b_module, data, ".str");
|
||||
}
|
||||
|
||||
return MIE_VALUE(data);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_ret(struct mie_builder *builder, struct mie_value *val)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_ret *ret = malloc(sizeof *ret);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_instr_init(&ret->r_base, MIE_INSTR_RET);
|
||||
ret->r_val = val;
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &ret->r_base)) {
|
||||
free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return MIE_VALUE(ret);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_add(
|
||||
struct mie_builder *builder, struct mie_value *left,
|
||||
struct mie_value *right, const char *name)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_binary_op *add = malloc(sizeof *add);
|
||||
if (!add) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(add, 0x0, sizeof *add);
|
||||
|
||||
mie_instr_init(&add->op_base, MIE_INSTR_ADD);
|
||||
|
||||
add->op_left = left;
|
||||
add->op_right = right;
|
||||
add->op_type = mie_value_get_type(left, builder->b_ctx);
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &add->op_base)) {
|
||||
free(add);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_func_generate_value_name(
|
||||
builder->b_current_block->b_parent, MIE_VALUE(add), name);
|
||||
|
||||
return MIE_VALUE(add);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_sub(
|
||||
struct mie_builder *builder, struct mie_value *left,
|
||||
struct mie_value *right, const char *name)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_binary_op *sub = malloc(sizeof *sub);
|
||||
if (!sub) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(sub, 0x0, sizeof *sub);
|
||||
|
||||
mie_instr_init(&sub->op_base, MIE_INSTR_SUB);
|
||||
|
||||
sub->op_left = left;
|
||||
sub->op_right = right;
|
||||
sub->op_type = mie_value_get_type(left, builder->b_ctx);
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
|
||||
free(sub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_func_generate_value_name(
|
||||
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
|
||||
|
||||
return MIE_VALUE(sub);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_mul(
|
||||
struct mie_builder *builder, struct mie_value *left,
|
||||
struct mie_value *right, const char *name)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_binary_op *mul = malloc(sizeof *mul);
|
||||
if (!mul) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(mul, 0x0, sizeof *mul);
|
||||
|
||||
mie_instr_init(&mul->op_base, MIE_INSTR_MUL);
|
||||
|
||||
mul->op_left = left;
|
||||
mul->op_right = right;
|
||||
mul->op_type = mie_value_get_type(left, builder->b_ctx);
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &mul->op_base)) {
|
||||
free(mul);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_func_generate_value_name(
|
||||
builder->b_current_block->b_parent, MIE_VALUE(mul), name);
|
||||
|
||||
return MIE_VALUE(mul);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_div(
|
||||
struct mie_builder *builder, struct mie_value *left,
|
||||
struct mie_value *right, const char *name)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_binary_op *div = malloc(sizeof *div);
|
||||
if (!div) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(div, 0x0, sizeof *div);
|
||||
|
||||
mie_instr_init(&div->op_base, MIE_INSTR_DIV);
|
||||
|
||||
div->op_left = left;
|
||||
div->op_right = right;
|
||||
div->op_type = mie_value_get_type(left, builder->b_ctx);
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &div->op_base)) {
|
||||
free(div);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_func_generate_value_name(
|
||||
builder->b_current_block->b_parent, MIE_VALUE(div), name);
|
||||
|
||||
return MIE_VALUE(div);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_load(
|
||||
struct mie_builder *builder, struct mie_type *type,
|
||||
struct mie_value *src, const char *name)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_load *load = malloc(sizeof *load);
|
||||
if (!load) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_instr_init(&load->l_base, MIE_INSTR_LOAD);
|
||||
load->l_src = src;
|
||||
load->l_type = type;
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &load->l_base)) {
|
||||
free(load);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_func_generate_value_name(
|
||||
builder->b_current_block->b_parent, MIE_VALUE(load), name);
|
||||
|
||||
return MIE_VALUE(load);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_store(
|
||||
struct mie_builder *builder, struct mie_value *val, struct mie_value *dest)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_store *store = malloc(sizeof *store);
|
||||
if (!store) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_instr_init(&store->s_base, MIE_INSTR_STORE);
|
||||
store->s_val = val;
|
||||
store->s_dest = dest;
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &store->s_base)) {
|
||||
free(store);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return MIE_VALUE(store);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_alloca(
|
||||
struct mie_builder *builder, struct mie_type *type, const char *name)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_alloca *alloca = malloc(sizeof *alloca);
|
||||
if (!alloca) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_instr_init(&alloca->a_base, MIE_INSTR_ALLOCA);
|
||||
alloca->a_type = type;
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &alloca->a_base)) {
|
||||
free(alloca);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_func_generate_value_name(
|
||||
builder->b_current_block->b_parent, MIE_VALUE(alloca), name);
|
||||
|
||||
return MIE_VALUE(alloca);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_switch(
|
||||
struct mie_builder *builder, struct mie_value *cond,
|
||||
struct mie_switch_branch *branches, size_t nr_branches,
|
||||
struct mie_block *default_block)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_br(struct mie_builder *builder, struct mie_block *dest)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_branch *br = malloc(sizeof *br);
|
||||
if (!br) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(br, 0x0, sizeof *br);
|
||||
|
||||
mie_instr_init(&br->b_base, MIE_INSTR_BR);
|
||||
|
||||
br->b_dest = dest;
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &br->b_base)) {
|
||||
free(br);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return MIE_VALUE(br);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_br_if(
|
||||
struct mie_builder *builder, struct mie_value *cond,
|
||||
struct mie_block *if_true, struct mie_block *if_false)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_branch_if *br = malloc(sizeof *br);
|
||||
if (!br) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(br, 0x0, sizeof *br);
|
||||
|
||||
mie_instr_init(&br->b_base, MIE_INSTR_BR_IF);
|
||||
|
||||
br->b_cond = cond;
|
||||
br->b_true_block = if_true;
|
||||
br->b_false_block = if_false;
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &br->b_base)) {
|
||||
free(br);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return MIE_VALUE(br);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_msg(
|
||||
struct mie_builder *builder, struct mie_type *ret_type,
|
||||
struct mie_value *recipient, struct mie_value *selector,
|
||||
struct mie_value **args, size_t nr_args, enum mie_builder_flags flags,
|
||||
const char *name)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ((flags & MIE_BUILDER_IGNORE_RESULT) && name) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_msg *msg = malloc(sizeof *msg);
|
||||
if (!msg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(msg, 0x0, sizeof *msg);
|
||||
|
||||
mie_instr_init(&msg->msg_base, MIE_INSTR_MSG);
|
||||
|
||||
msg->msg_ret_type = ret_type;
|
||||
msg->msg_recipient = recipient;
|
||||
msg->msg_selector = selector;
|
||||
|
||||
msg->msg_nr_args = nr_args;
|
||||
msg->msg_args = calloc(nr_args, sizeof(struct mie_value *));
|
||||
memcpy(msg->msg_args, args, nr_args * sizeof(struct mie_value *));
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &msg->msg_base)) {
|
||||
free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(flags & MIE_BUILDER_IGNORE_RESULT)) {
|
||||
mie_func_generate_value_name(
|
||||
builder->b_current_block->b_parent, MIE_VALUE(msg), name);
|
||||
}
|
||||
|
||||
return MIE_VALUE(msg);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_cmp_eq(
|
||||
struct mie_builder *builder, struct mie_value *left,
|
||||
struct mie_value *right, const char *name)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_binary_op *sub = malloc(sizeof *sub);
|
||||
if (!sub) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(sub, 0x0, sizeof *sub);
|
||||
|
||||
mie_instr_init(&sub->op_base, MIE_INSTR_CMP_EQ);
|
||||
|
||||
sub->op_left = left;
|
||||
sub->op_right = right;
|
||||
sub->op_type = mie_value_get_type(left, builder->b_ctx);
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
|
||||
free(sub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_func_generate_value_name(
|
||||
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
|
||||
|
||||
return MIE_VALUE(sub);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_cmp_neq(
|
||||
struct mie_builder *builder, struct mie_value *left,
|
||||
struct mie_value *right, const char *name)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_binary_op *sub = malloc(sizeof *sub);
|
||||
if (!sub) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(sub, 0x0, sizeof *sub);
|
||||
|
||||
mie_instr_init(&sub->op_base, MIE_INSTR_CMP_NEQ);
|
||||
|
||||
sub->op_left = left;
|
||||
sub->op_right = right;
|
||||
sub->op_type = mie_value_get_type(left, builder->b_ctx);
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
|
||||
free(sub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_func_generate_value_name(
|
||||
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
|
||||
|
||||
return MIE_VALUE(sub);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_cmp_lt(
|
||||
struct mie_builder *builder, struct mie_value *left,
|
||||
struct mie_value *right, const char *name)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_binary_op *sub = malloc(sizeof *sub);
|
||||
if (!sub) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(sub, 0x0, sizeof *sub);
|
||||
|
||||
mie_instr_init(&sub->op_base, MIE_INSTR_CMP_LT);
|
||||
|
||||
sub->op_left = left;
|
||||
sub->op_right = right;
|
||||
sub->op_type = mie_value_get_type(left, builder->b_ctx);
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
|
||||
free(sub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_func_generate_value_name(
|
||||
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
|
||||
|
||||
return MIE_VALUE(sub);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_cmp_gt(
|
||||
struct mie_builder *builder, struct mie_value *left,
|
||||
struct mie_value *right, const char *name)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_binary_op *sub = malloc(sizeof *sub);
|
||||
if (!sub) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(sub, 0x0, sizeof *sub);
|
||||
|
||||
mie_instr_init(&sub->op_base, MIE_INSTR_CMP_GT);
|
||||
|
||||
sub->op_left = left;
|
||||
sub->op_right = right;
|
||||
sub->op_type = mie_value_get_type(left, builder->b_ctx);
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
|
||||
free(sub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_func_generate_value_name(
|
||||
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
|
||||
|
||||
return MIE_VALUE(sub);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_cmp_leq(
|
||||
struct mie_builder *builder, struct mie_value *left,
|
||||
struct mie_value *right, const char *name)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_binary_op *sub = malloc(sizeof *sub);
|
||||
if (!sub) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(sub, 0x0, sizeof *sub);
|
||||
|
||||
mie_instr_init(&sub->op_base, MIE_INSTR_CMP_LEQ);
|
||||
|
||||
sub->op_left = left;
|
||||
sub->op_right = right;
|
||||
sub->op_type = mie_value_get_type(left, builder->b_ctx);
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
|
||||
free(sub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_func_generate_value_name(
|
||||
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
|
||||
|
||||
return MIE_VALUE(sub);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_cmp_geq(
|
||||
struct mie_builder *builder, struct mie_value *left,
|
||||
struct mie_value *right, const char *name)
|
||||
{
|
||||
if (!builder->b_current_block) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (builder->b_current_block->b_terminator) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_binary_op *sub = malloc(sizeof *sub);
|
||||
if (!sub) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(sub, 0x0, sizeof *sub);
|
||||
|
||||
mie_instr_init(&sub->op_base, MIE_INSTR_CMP_GEQ);
|
||||
|
||||
sub->op_left = left;
|
||||
sub->op_right = right;
|
||||
sub->op_type = mie_value_get_type(left, builder->b_ctx);
|
||||
|
||||
if (!mie_block_add_instr(builder->b_current_block, &sub->op_base)) {
|
||||
free(sub);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mie_func_generate_value_name(
|
||||
builder->b_current_block->b_parent, MIE_VALUE(sub), name);
|
||||
|
||||
return MIE_VALUE(sub);
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_getelementptr(
|
||||
struct mie_builder *builder, struct mie_type *container_type,
|
||||
struct mie_value *container, struct mie_value *index, const char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_value *mie_builder_setelementptr(
|
||||
struct mie_builder *builder, struct mie_type *container_type,
|
||||
struct mie_value *container, struct mie_value *index)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_phi *mie_builder_phi(
|
||||
struct mie_builder *builder, struct mie_type *type,
|
||||
unsigned int nr_edges, const char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
22
mie/ir/const.c
Normal file
22
mie/ir/const.c
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <mie/ir/const.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
void mie_const_init(struct mie_const *c, struct mie_type *type)
|
||||
{
|
||||
memset(c, 0x0, sizeof *c);
|
||||
mie_value_init(&c->c_base, MIE_VALUE_CONST);
|
||||
|
||||
c->c_type = type;
|
||||
}
|
||||
|
||||
static struct mie_type *get_type(struct mie_value *v, struct mie_ctx *ctx)
|
||||
{
|
||||
struct mie_const *c = MIE_CONST(v);
|
||||
return c->c_type;
|
||||
}
|
||||
|
||||
const struct mie_value_type const_value_type = {
|
||||
.t_id = MIE_VALUE_CONST,
|
||||
.t_get_type = get_type,
|
||||
};
|
||||
7
mie/ir/convert/bitcode-read.c
Normal file
7
mie/ir/convert/bitcode-read.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "convert.h"
|
||||
|
||||
b_status read_value_from_bitcode(
|
||||
struct mie_ir_converter *converter, struct mie_value **out)
|
||||
{
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
7
mie/ir/convert/bitcode-write.c
Normal file
7
mie/ir/convert/bitcode-write.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "convert.h"
|
||||
|
||||
b_status write_value_to_bitcode(
|
||||
struct mie_ir_converter *converter, struct mie_value *value)
|
||||
{
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
217
mie/ir/convert/convert.c
Normal file
217
mie/ir/convert/convert.c
Normal file
@@ -0,0 +1,217 @@
|
||||
#include "convert.h"
|
||||
|
||||
#include <mie/ir/convert.h>
|
||||
#include <mie/ir/value.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct mie_ir_converter *mie_ir_converter_create(
|
||||
struct mie_ctx *ctx, enum mie_ir_format src, enum mie_ir_format dest)
|
||||
{
|
||||
if (src == dest) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_ir_converter *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
|
||||
out->c_ctx = ctx;
|
||||
out->c_src_format = src;
|
||||
out->c_dest_format = dest;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void mie_ir_converter_destroy(struct mie_ir_converter *converter)
|
||||
{
|
||||
free(converter);
|
||||
}
|
||||
|
||||
b_status mie_ir_converter_set_src_value(
|
||||
struct mie_ir_converter *converter, struct mie_value *value)
|
||||
{
|
||||
if (converter->c_src_format != MIE_IR_MEM) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
converter->c_src_medium = MIE_IR_CONVERTER_MIE_VALUE;
|
||||
converter->c_src.value = value;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status mie_ir_converter_set_src_bitbuffer(
|
||||
struct mie_ir_converter *converter, b_bitbuffer *bitbuffer)
|
||||
{
|
||||
if (converter->c_src_format != MIE_IR_BITCODE) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
converter->c_src_medium = MIE_IR_CONVERTER_BITBUFFER;
|
||||
converter->c_src.bitbuffer = bitbuffer;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status mie_ir_converter_set_src_stringstream(
|
||||
struct mie_ir_converter *converter, b_stringstream *stringstream)
|
||||
{
|
||||
if (converter->c_src_format != MIE_IR_TEXT) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
converter->c_src_medium = MIE_IR_CONVERTER_STRINGSTREAM;
|
||||
converter->c_src.stringstream = stringstream;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status mie_ir_converter_set_src_string(
|
||||
struct mie_ir_converter *converter, b_string *string)
|
||||
{
|
||||
if (converter->c_src_format != MIE_IR_TEXT) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
converter->c_src_medium = MIE_IR_CONVERTER_STRING;
|
||||
converter->c_src.string = string;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status mie_ir_converter_set_src_file(struct mie_ir_converter *converter, FILE *file)
|
||||
{
|
||||
if (converter->c_src_format != MIE_IR_TEXT) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
converter->c_src_medium = MIE_IR_CONVERTER_FILE;
|
||||
converter->c_src.file = file;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status mie_ir_converter_set_dest_value(
|
||||
struct mie_ir_converter *converter, struct mie_value **value)
|
||||
{
|
||||
if (converter->c_dest_format != MIE_IR_MEM) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
converter->c_dest_medium = MIE_IR_CONVERTER_MIE_VALUE;
|
||||
converter->c_dest.value = value;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status mie_ir_converter_set_dest_bitbuffer(
|
||||
struct mie_ir_converter *converter, b_bitbuffer *bitbuffer)
|
||||
{
|
||||
if (converter->c_dest_format != MIE_IR_BITCODE) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
converter->c_dest_medium = MIE_IR_CONVERTER_BITBUFFER;
|
||||
converter->c_dest.bitbuffer = bitbuffer;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status mie_ir_converter_set_dest_stringstream(
|
||||
struct mie_ir_converter *converter, b_stringstream *stringstream)
|
||||
{
|
||||
if (converter->c_dest_format != MIE_IR_TEXT) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
converter->c_dest_medium = MIE_IR_CONVERTER_STRINGSTREAM;
|
||||
converter->c_dest.stringstream = stringstream;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status mie_ir_converter_set_dest_string(
|
||||
struct mie_ir_converter *converter, b_string *string)
|
||||
{
|
||||
if (converter->c_dest_format != MIE_IR_TEXT) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
converter->c_dest_medium = MIE_IR_CONVERTER_STRING;
|
||||
converter->c_dest.string = string;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status mie_ir_converter_set_dest_file(
|
||||
struct mie_ir_converter *converter, FILE *file)
|
||||
{
|
||||
if (converter->c_dest_format != MIE_IR_TEXT) {
|
||||
return B_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
converter->c_dest_medium = MIE_IR_CONVERTER_FILE;
|
||||
converter->c_dest.file = file;
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status read_value_from_medium(
|
||||
struct mie_ir_converter *converter, struct mie_value **value)
|
||||
{
|
||||
switch (converter->c_src_format) {
|
||||
case MIE_IR_MEM:
|
||||
*value = converter->c_src.value;
|
||||
return B_SUCCESS;
|
||||
case MIE_IR_TEXT:
|
||||
return read_value_from_text(converter, value);
|
||||
case MIE_IR_BITCODE:
|
||||
return read_value_from_bitcode(converter, value);
|
||||
default:
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
static b_status write_value_to_medium(
|
||||
struct mie_ir_converter *converter, struct mie_value *value)
|
||||
{
|
||||
switch (converter->c_dest_format) {
|
||||
case MIE_IR_MEM:
|
||||
*converter->c_dest.value = value;
|
||||
return B_SUCCESS;
|
||||
case MIE_IR_TEXT:
|
||||
return write_value_to_text(converter, value);
|
||||
case MIE_IR_BITCODE:
|
||||
return write_value_to_bitcode(converter, value);
|
||||
default:
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
b_status mie_ir_converter_process(struct mie_ir_converter *converter)
|
||||
{
|
||||
b_status status = B_SUCCESS;
|
||||
struct mie_value *value = NULL;
|
||||
|
||||
status = read_value_from_medium(converter, &value);
|
||||
|
||||
if (!B_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
return B_ERR_BAD_FORMAT;
|
||||
}
|
||||
|
||||
status = write_value_to_medium(converter, value);
|
||||
|
||||
if (converter->c_src_format != MIE_IR_MEM) {
|
||||
mie_value_destroy(value);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
19
mie/ir/convert/convert.h
Normal file
19
mie/ir/convert/convert.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef _MIE_CONVERT_H_
|
||||
#define _MIE_CONVERT_H_
|
||||
|
||||
#include <mie/ir/convert.h>
|
||||
|
||||
extern b_status write_char(struct mie_ir_converter *converter, char c);
|
||||
extern b_status write_string(struct mie_ir_converter *converter, const char *s);
|
||||
|
||||
extern b_status read_value_from_text(
|
||||
struct mie_ir_converter *converter, struct mie_value **out);
|
||||
extern b_status read_value_from_bitcode(
|
||||
struct mie_ir_converter *converter, struct mie_value **out);
|
||||
|
||||
extern b_status write_value_to_text(
|
||||
struct mie_ir_converter *converter, struct mie_value *value);
|
||||
extern b_status write_value_to_bitcode(
|
||||
struct mie_ir_converter *converter, struct mie_value *value);
|
||||
|
||||
#endif
|
||||
0
mie/ir/convert/lex.c
Normal file
0
mie/ir/convert/lex.c
Normal file
0
mie/ir/convert/lex.h
Normal file
0
mie/ir/convert/lex.h
Normal file
0
mie/ir/convert/parse.c
Normal file
0
mie/ir/convert/parse.c
Normal file
0
mie/ir/convert/parse.h
Normal file
0
mie/ir/convert/parse.h
Normal file
7
mie/ir/convert/text-read.c
Normal file
7
mie/ir/convert/text-read.c
Normal file
@@ -0,0 +1,7 @@
|
||||
#include "convert.h"
|
||||
|
||||
b_status read_value_from_text(
|
||||
struct mie_ir_converter *converter, struct mie_value **out)
|
||||
{
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
751
mie/ir/convert/text-write.c
Normal file
751
mie/ir/convert/text-write.c
Normal file
@@ -0,0 +1,751 @@
|
||||
#include "convert.h"
|
||||
|
||||
#include <blue/object/hashmap.h>
|
||||
#include <blue/object/list.h>
|
||||
#include <inttypes.h>
|
||||
#include <mie/ir/alloca.h>
|
||||
#include <mie/ir/arg.h>
|
||||
#include <mie/ir/block.h>
|
||||
#include <mie/ir/branch.h>
|
||||
#include <mie/ir/const.h>
|
||||
#include <mie/ir/data.h>
|
||||
#include <mie/ir/func.h>
|
||||
#include <mie/ir/instr.h>
|
||||
#include <mie/ir/module.h>
|
||||
#include <mie/ir/msg.h>
|
||||
#include <mie/ir/op.h>
|
||||
#include <mie/ir/ptr.h>
|
||||
#include <mie/ir/record.h>
|
||||
#include <mie/ir/type.h>
|
||||
#include <mie/ir/value.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define F_INCLUDE_TYPE 0x01u
|
||||
|
||||
typedef b_status (*write_function)(struct mie_ir_converter *, struct mie_value *);
|
||||
|
||||
static void mie_type_to_string(struct mie_type *type, char *out, size_t max)
|
||||
{
|
||||
if (!type) {
|
||||
snprintf(out, max, "<no-type>");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type->t_id) {
|
||||
case MIE_TYPE_PTR:
|
||||
snprintf(out, max, "ptr");
|
||||
break;
|
||||
case MIE_TYPE_VOID:
|
||||
snprintf(out, max, "void");
|
||||
break;
|
||||
case MIE_TYPE_INT:
|
||||
snprintf(out, max, "i%u", type->t_width);
|
||||
break;
|
||||
case MIE_TYPE_ID:
|
||||
snprintf(out, max, "id");
|
||||
break;
|
||||
case MIE_TYPE_STR:
|
||||
snprintf(out, max, "str");
|
||||
break;
|
||||
case MIE_TYPE_ATOM:
|
||||
snprintf(out, max, "atom");
|
||||
break;
|
||||
case MIE_TYPE_LABEL:
|
||||
snprintf(out, max, "label");
|
||||
break;
|
||||
case MIE_TYPE_ARRAY:
|
||||
snprintf(out, max, "array");
|
||||
break;
|
||||
case MIE_TYPE_FUNC:
|
||||
snprintf(out, max, "func");
|
||||
break;
|
||||
case MIE_TYPE_SELECTOR:
|
||||
snprintf(out, max, "");
|
||||
break;
|
||||
default:
|
||||
snprintf(out, max, "<unknown-type>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
b_status write_char(struct mie_ir_converter *converter, char c)
|
||||
{
|
||||
long result = 0;
|
||||
char s[] = {c, '\0'};
|
||||
|
||||
switch (converter->c_dest_medium) {
|
||||
case MIE_IR_CONVERTER_STRINGSTREAM:
|
||||
return b_stringstream_add(converter->c_dest.stringstream, s);
|
||||
case MIE_IR_CONVERTER_STRING:
|
||||
b_string_append_cstr(converter->c_dest.string, s);
|
||||
return B_SUCCESS;
|
||||
case MIE_IR_CONVERTER_FILE:
|
||||
result = fputc(c, converter->c_dest.file);
|
||||
return result == EOF ? B_ERR_IO_FAILURE : B_SUCCESS;
|
||||
default:
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status write_string(struct mie_ir_converter *converter, const char *s)
|
||||
{
|
||||
long result = 0;
|
||||
|
||||
switch (converter->c_dest_medium) {
|
||||
case MIE_IR_CONVERTER_STRINGSTREAM:
|
||||
return b_stringstream_add(converter->c_dest.stringstream, s);
|
||||
case MIE_IR_CONVERTER_STRING:
|
||||
b_string_append_cstr(converter->c_dest.string, s);
|
||||
return B_SUCCESS;
|
||||
case MIE_IR_CONVERTER_FILE:
|
||||
result = fputs(s, converter->c_dest.file);
|
||||
return result == EOF ? B_ERR_IO_FAILURE : B_SUCCESS;
|
||||
default:
|
||||
return B_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
b_status write_string_f(struct mie_ir_converter *converter, const char *format, ...)
|
||||
{
|
||||
long result = 0;
|
||||
|
||||
char buf[512];
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
|
||||
b_status status = B_SUCCESS;
|
||||
|
||||
switch (converter->c_dest_medium) {
|
||||
case MIE_IR_CONVERTER_STRINGSTREAM:
|
||||
vsnprintf(buf, sizeof buf, format, arg);
|
||||
status = b_stringstream_add(converter->c_dest.stringstream, buf);
|
||||
break;
|
||||
case MIE_IR_CONVERTER_STRING:
|
||||
vsnprintf(buf, sizeof buf, format, arg);
|
||||
b_string_append_cstr(converter->c_dest.string, buf);
|
||||
status = B_SUCCESS;
|
||||
break;
|
||||
case MIE_IR_CONVERTER_FILE:
|
||||
result = vfprintf(converter->c_dest.file, format, arg);
|
||||
status = (result == EOF ? B_ERR_IO_FAILURE : B_SUCCESS);
|
||||
break;
|
||||
default:
|
||||
status = B_ERR_NOT_SUPPORTED;
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(arg);
|
||||
return status;
|
||||
}
|
||||
|
||||
static b_status write_operand_const(
|
||||
struct mie_ir_converter *converter, struct mie_value *value, int flags)
|
||||
{
|
||||
struct mie_const *c = MIE_CONST(value);
|
||||
|
||||
if (flags & F_INCLUDE_TYPE) {
|
||||
char type_name[64];
|
||||
mie_type_to_string(c->c_type, type_name, sizeof type_name);
|
||||
write_string_f(converter, "%s", type_name);
|
||||
|
||||
if (type_name[0] != 0) {
|
||||
write_char(converter, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
switch (c->c_type->t_id) {
|
||||
case MIE_TYPE_INT: {
|
||||
struct mie_int *v = MIE_INT(c);
|
||||
write_string_f(converter, "#%" PRId64, v->i_value);
|
||||
break;
|
||||
}
|
||||
case MIE_TYPE_PTR:
|
||||
case MIE_TYPE_ID:
|
||||
write_string_f(converter, "%%%s", value->v_name.n_str);
|
||||
break;
|
||||
case MIE_TYPE_STR: {
|
||||
struct mie_string *v = MIE_STRING(c);
|
||||
|
||||
write_string_f(converter, "\"%s\"", v->s_value);
|
||||
break;
|
||||
}
|
||||
case MIE_TYPE_ATOM: {
|
||||
struct mie_atom *v = MIE_ATOM(c);
|
||||
|
||||
write_string_f(converter, "\"%s\"", v->a_value);
|
||||
break;
|
||||
}
|
||||
case MIE_TYPE_SELECTOR: {
|
||||
struct mie_selector *v = MIE_SELECTOR(c);
|
||||
|
||||
write_string_f(converter, "\"%s\"", v->sel_value);
|
||||
break;
|
||||
}
|
||||
case MIE_TYPE_CLASS:
|
||||
write_string_f(converter, "@%s", value->v_name.n_str);
|
||||
break;
|
||||
case MIE_TYPE_ARRAY: {
|
||||
struct mie_array *array = MIE_ARRAY(value);
|
||||
b_list_iterator it;
|
||||
b_list_iterator_begin(array->a_values, &it);
|
||||
|
||||
write_char(converter, '{');
|
||||
while (b_list_iterator_is_valid(&it)) {
|
||||
if (it.i > 0) {
|
||||
write_char(converter, ',');
|
||||
}
|
||||
|
||||
write_string(converter, "\n ");
|
||||
|
||||
struct mie_value *child = it.item;
|
||||
write_operand_const(converter, child, F_INCLUDE_TYPE);
|
||||
|
||||
b_list_iterator_next(&it);
|
||||
}
|
||||
|
||||
if (!b_list_empty(array->a_values)) {
|
||||
write_char(converter, '\n');
|
||||
}
|
||||
|
||||
write_char(converter, '}');
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status write_operand_instr(
|
||||
struct mie_ir_converter *converter, struct mie_value *value, int flags)
|
||||
{
|
||||
struct mie_instr *instr = MIE_INSTR(value);
|
||||
|
||||
if (flags & F_INCLUDE_TYPE) {
|
||||
char type_name[64];
|
||||
struct mie_type *type
|
||||
= mie_value_get_type(value, converter->c_ctx);
|
||||
mie_type_to_string(type, type_name, sizeof type_name);
|
||||
write_string_f(converter, "%s ", type_name);
|
||||
}
|
||||
|
||||
write_string_f(converter, "%%%s", value->v_name.n_str);
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status write_operand_block(
|
||||
struct mie_ir_converter *converter, struct mie_value *value, int flags)
|
||||
{
|
||||
struct mie_block *block = MIE_BLOCK(value);
|
||||
|
||||
if (flags & F_INCLUDE_TYPE) {
|
||||
char type_name[64];
|
||||
struct mie_type *type
|
||||
= mie_value_get_type(value, converter->c_ctx);
|
||||
mie_type_to_string(type, type_name, sizeof type_name);
|
||||
write_string_f(converter, "%s ", type_name);
|
||||
}
|
||||
|
||||
write_string_f(converter, "%%%s", value->v_name.n_str);
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status write_operand_data(
|
||||
struct mie_ir_converter *converter, struct mie_value *value, int flags)
|
||||
{
|
||||
struct mie_const *c = MIE_CONST(value);
|
||||
|
||||
if (flags & F_INCLUDE_TYPE) {
|
||||
write_string(converter, "ptr ");
|
||||
}
|
||||
|
||||
write_string_f(converter, "@%s", value->v_name.n_str);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status write_operand_arg(
|
||||
struct mie_ir_converter *converter, struct mie_value *value, int flags)
|
||||
{
|
||||
struct mie_arg *arg = MIE_ARG(value);
|
||||
|
||||
if (flags & F_INCLUDE_TYPE) {
|
||||
char type_name[64];
|
||||
mie_type_to_string(arg->arg_type, type_name, sizeof type_name);
|
||||
write_string_f(converter, "%s ", type_name);
|
||||
}
|
||||
|
||||
write_string_f(converter, "%%%s", value->v_name.n_str);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status write_operand_func(
|
||||
struct mie_ir_converter *converter, struct mie_value *value, int flags)
|
||||
{
|
||||
struct mie_func *func = MIE_FUNC(value);
|
||||
|
||||
if (flags & F_INCLUDE_TYPE) {
|
||||
write_string(converter, "ptr ");
|
||||
}
|
||||
|
||||
write_string_f(converter, "@%s", value->v_name.n_str);
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status write_operand(
|
||||
struct mie_ir_converter *converter, struct mie_value *value, int flags)
|
||||
{
|
||||
if (!value) {
|
||||
write_string(converter, "<null>");
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
switch (value->v_type->t_id) {
|
||||
case MIE_VALUE_CONST:
|
||||
return write_operand_const(converter, value, flags);
|
||||
case MIE_VALUE_INSTR:
|
||||
return write_operand_instr(converter, value, flags);
|
||||
case MIE_VALUE_BLOCK:
|
||||
return write_operand_block(converter, value, flags);
|
||||
case MIE_VALUE_DATA:
|
||||
return write_operand_data(converter, value, flags);
|
||||
case MIE_VALUE_FUNC:
|
||||
return write_operand_func(converter, value, flags);
|
||||
case MIE_VALUE_ARG:
|
||||
return write_operand_arg(converter, value, flags);
|
||||
default:
|
||||
write_string_f(converter, "<unknown-value:%d>", value->v_type->t_id);
|
||||
return B_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static b_status write_module(
|
||||
struct mie_ir_converter *converter, struct mie_value *value)
|
||||
{
|
||||
struct mie_module *mod = MIE_MODULE(value);
|
||||
b_status status = B_SUCCESS;
|
||||
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &mod->m_records) {
|
||||
struct mie_value *record
|
||||
= b_unbox(struct mie_value, it.entry, v_entry);
|
||||
status = write_value_to_text(converter, record);
|
||||
|
||||
if (!B_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (!b_queue_empty(&mod->m_records)) {
|
||||
write_char(converter, '\n');
|
||||
}
|
||||
|
||||
b_queue_foreach (&it, &mod->m_types) {
|
||||
struct mie_value *type
|
||||
= b_unbox(struct mie_value, it.entry, v_entry);
|
||||
status = write_value_to_text(converter, type);
|
||||
|
||||
if (!B_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (!b_queue_empty(&mod->m_types)) {
|
||||
write_char(converter, '\n');
|
||||
}
|
||||
|
||||
b_hashmap_iterator it2;
|
||||
b_hashmap_foreach(&it2, mod->m_data)
|
||||
{
|
||||
struct mie_value *data = it2.value->value_data;
|
||||
status = write_value_to_text(converter, data);
|
||||
|
||||
if (!B_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
if (!b_hashmap_is_empty(mod->m_data)) {
|
||||
write_char(converter, '\n');
|
||||
}
|
||||
|
||||
unsigned long i = 0;
|
||||
b_queue_foreach (&it, &mod->m_func) {
|
||||
if (i > 0) {
|
||||
write_char(converter, '\n');
|
||||
}
|
||||
|
||||
struct mie_value *func
|
||||
= b_unbox(struct mie_value, it.entry, v_entry);
|
||||
status = write_value_to_text(converter, func);
|
||||
|
||||
if (!B_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status write_type_definition(
|
||||
struct mie_ir_converter *converter, struct mie_value *value)
|
||||
{
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status write_record(
|
||||
struct mie_ir_converter *converter, struct mie_value *value)
|
||||
{
|
||||
struct mie_record *rec = MIE_RECORD(value);
|
||||
write_string_f(converter, "record %s", rec->r_base.v_name.n_str);
|
||||
|
||||
if (rec->r_value) {
|
||||
write_string(converter, " = ");
|
||||
write_operand_const(
|
||||
converter, MIE_VALUE(rec->r_value), F_INCLUDE_TYPE);
|
||||
}
|
||||
|
||||
write_char(converter, '\n');
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status write_func_definition(
|
||||
struct mie_ir_converter *converter, struct mie_value *value)
|
||||
{
|
||||
struct mie_func *func = MIE_FUNC(value);
|
||||
|
||||
char type_name[32];
|
||||
mie_type_to_string(func->f_ret, type_name, sizeof type_name);
|
||||
|
||||
write_string_f(
|
||||
converter, "define %s @%s(", type_name, func->f_base.v_name.n_str);
|
||||
|
||||
unsigned int i = 0;
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &func->f_args) {
|
||||
struct mie_arg *arg = (struct mie_arg *)b_unbox(
|
||||
struct mie_value, it.entry, v_entry);
|
||||
|
||||
if (i > 0) {
|
||||
write_string(converter, ", ");
|
||||
}
|
||||
|
||||
mie_type_to_string(func->f_ret, type_name, sizeof type_name);
|
||||
|
||||
write_string_f(
|
||||
converter, "%s %%%s", type_name,
|
||||
arg->arg_base.v_name.n_str);
|
||||
i++;
|
||||
}
|
||||
|
||||
write_string_f(converter, ")");
|
||||
|
||||
switch (func->f_type) {
|
||||
case MIE_FUNC_STATIC:
|
||||
write_string_f(converter, " static");
|
||||
break;
|
||||
case MIE_FUNC_INSTANCE:
|
||||
write_string_f(converter, " instance");
|
||||
break;
|
||||
case MIE_FUNC_LAMBDA:
|
||||
write_string_f(converter, " lambda");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
write_string_f(converter, " {\n");
|
||||
|
||||
b_queue_foreach (&it, &func->f_blocks) {
|
||||
struct mie_value *block
|
||||
= b_unbox(struct mie_value, it.entry, v_entry);
|
||||
write_value_to_text(converter, block);
|
||||
}
|
||||
|
||||
write_string_f(converter, "}\n");
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status write_block_definition(
|
||||
struct mie_ir_converter *converter, struct mie_value *value)
|
||||
{
|
||||
struct mie_block *block = MIE_BLOCK(value);
|
||||
|
||||
write_string_f(converter, "%s:\n", block->b_base.v_name.n_str);
|
||||
b_queue_iterator it;
|
||||
b_queue_foreach (&it, &block->b_phi) {
|
||||
struct mie_value *instr
|
||||
= b_unbox(struct mie_value, it.entry, v_entry);
|
||||
write_value_to_text(converter, instr);
|
||||
}
|
||||
|
||||
b_queue_foreach (&it, &block->b_instr) {
|
||||
struct mie_value *instr
|
||||
= b_unbox(struct mie_value, it.entry, v_entry);
|
||||
write_value_to_text(converter, instr);
|
||||
}
|
||||
|
||||
if (block->b_terminator) {
|
||||
write_value_to_text(converter, MIE_VALUE(block->b_terminator));
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status write_instr(
|
||||
struct mie_ir_converter *converter, struct mie_value *value)
|
||||
{
|
||||
struct mie_instr *instr = MIE_INSTR(value);
|
||||
write_string_f(converter, "\t");
|
||||
|
||||
if (instr->i_base.v_name.n_str) {
|
||||
write_string_f(converter, "%%%s = ", instr->i_base.v_name.n_str);
|
||||
}
|
||||
|
||||
char type[128];
|
||||
|
||||
switch (instr->i_type) {
|
||||
case MIE_INSTR_RET: {
|
||||
struct mie_ret *ret = (struct mie_ret *)instr;
|
||||
write_string(converter, "ret ");
|
||||
if (!ret->r_val) {
|
||||
write_string(converter, "void");
|
||||
break;
|
||||
}
|
||||
|
||||
write_operand(converter, ret->r_val, F_INCLUDE_TYPE);
|
||||
break;
|
||||
}
|
||||
|
||||
case MIE_INSTR_ADD: {
|
||||
struct mie_binary_op *op = (struct mie_binary_op *)instr;
|
||||
mie_type_to_string(op->op_type, type, sizeof type);
|
||||
write_string_f(converter, "add %s ", type);
|
||||
write_operand(converter, op->op_left, 0);
|
||||
write_string(converter, ", ");
|
||||
write_operand(converter, op->op_right, 0);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_SUB: {
|
||||
struct mie_binary_op *op = (struct mie_binary_op *)instr;
|
||||
mie_type_to_string(op->op_type, type, sizeof type);
|
||||
write_string_f(converter, "sub %s ", type);
|
||||
write_operand(converter, op->op_left, 0);
|
||||
write_string(converter, ", ");
|
||||
write_operand(converter, op->op_right, 0);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_MUL: {
|
||||
struct mie_binary_op *op = (struct mie_binary_op *)instr;
|
||||
mie_type_to_string(op->op_type, type, sizeof type);
|
||||
write_string_f(converter, "mul %s ", type);
|
||||
write_operand(converter, op->op_left, 0);
|
||||
write_string(converter, ", ");
|
||||
write_operand(converter, op->op_right, 0);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_DIV: {
|
||||
struct mie_binary_op *op = (struct mie_binary_op *)instr;
|
||||
mie_type_to_string(op->op_type, type, sizeof type);
|
||||
write_string_f(converter, "div %s ", type);
|
||||
write_operand(converter, op->op_left, 0);
|
||||
write_string(converter, ", ");
|
||||
write_operand(converter, op->op_right, 0);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_LOAD: {
|
||||
struct mie_load *load = (struct mie_load *)instr;
|
||||
mie_type_to_string(load->l_type, type, sizeof type);
|
||||
write_string_f(converter, "load %s, ", type);
|
||||
write_operand(converter, load->l_src, F_INCLUDE_TYPE);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_STORE: {
|
||||
struct mie_store *store = (struct mie_store *)instr;
|
||||
write_string(converter, "store ");
|
||||
write_operand(converter, store->s_val, F_INCLUDE_TYPE);
|
||||
write_string(converter, ", ");
|
||||
write_operand(converter, store->s_dest, F_INCLUDE_TYPE);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_ALLOCA: {
|
||||
struct mie_alloca *alloca = (struct mie_alloca *)instr;
|
||||
mie_type_to_string(alloca->a_type, type, sizeof type);
|
||||
write_string_f(converter, "alloca %s", type);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_SWITCH:
|
||||
write_string(converter, "switch");
|
||||
break;
|
||||
case MIE_INSTR_BR: {
|
||||
struct mie_branch *br = (struct mie_branch *)instr;
|
||||
write_string(converter, "br ");
|
||||
write_operand(converter, MIE_VALUE(br->b_dest), F_INCLUDE_TYPE);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_BR_IF: {
|
||||
struct mie_branch_if *br = (struct mie_branch_if *)instr;
|
||||
write_string(converter, "br ");
|
||||
write_operand(converter, MIE_VALUE(br->b_cond), F_INCLUDE_TYPE);
|
||||
write_string(converter, ", ");
|
||||
write_operand(
|
||||
converter, MIE_VALUE(br->b_true_block), F_INCLUDE_TYPE);
|
||||
write_string(converter, ", ");
|
||||
write_operand(
|
||||
converter, MIE_VALUE(br->b_false_block), F_INCLUDE_TYPE);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_MSG: {
|
||||
struct mie_msg *msg = (struct mie_msg *)instr;
|
||||
mie_type_to_string(msg->msg_ret_type, type, sizeof type);
|
||||
write_string_f(converter, "msg %s, ", type);
|
||||
write_operand(converter, msg->msg_recipient, F_INCLUDE_TYPE);
|
||||
write_string(converter, ", ");
|
||||
write_operand(converter, msg->msg_selector, F_INCLUDE_TYPE);
|
||||
|
||||
if (msg->msg_nr_args == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
write_string(converter, " [");
|
||||
for (size_t i = 0; i < msg->msg_nr_args; i++) {
|
||||
if (i > 0) {
|
||||
write_string(converter, ", ");
|
||||
}
|
||||
|
||||
write_operand(converter, msg->msg_args[i], F_INCLUDE_TYPE);
|
||||
}
|
||||
write_string(converter, "]");
|
||||
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_CMP_EQ: {
|
||||
struct mie_binary_op *op = (struct mie_binary_op *)instr;
|
||||
mie_type_to_string(op->op_type, type, sizeof type);
|
||||
write_string_f(converter, "cmp eq %s ", type);
|
||||
write_operand(converter, op->op_left, 0);
|
||||
write_string(converter, ", ");
|
||||
write_operand(converter, op->op_right, 0);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_CMP_NEQ: {
|
||||
struct mie_binary_op *op = (struct mie_binary_op *)instr;
|
||||
mie_type_to_string(op->op_type, type, sizeof type);
|
||||
write_string_f(converter, "cmp neq %s ", type);
|
||||
write_operand(converter, op->op_left, 0);
|
||||
write_string(converter, ", ");
|
||||
write_operand(converter, op->op_right, 0);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_CMP_LT: {
|
||||
struct mie_binary_op *op = (struct mie_binary_op *)instr;
|
||||
mie_type_to_string(op->op_type, type, sizeof type);
|
||||
write_string_f(converter, "cmp lt %s ", type);
|
||||
write_operand(converter, op->op_left, 0);
|
||||
write_string(converter, ", ");
|
||||
write_operand(converter, op->op_right, 0);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_CMP_LEQ: {
|
||||
struct mie_binary_op *op = (struct mie_binary_op *)instr;
|
||||
mie_type_to_string(op->op_type, type, sizeof type);
|
||||
write_string_f(converter, "cmp leq %s ", type);
|
||||
write_operand(converter, op->op_left, 0);
|
||||
write_string(converter, ", ");
|
||||
write_operand(converter, op->op_right, 0);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_CMP_GT: {
|
||||
struct mie_binary_op *op = (struct mie_binary_op *)instr;
|
||||
mie_type_to_string(op->op_type, type, sizeof type);
|
||||
write_string_f(converter, "cmp gt %s ", type);
|
||||
write_operand(converter, op->op_left, 0);
|
||||
write_string(converter, ", ");
|
||||
write_operand(converter, op->op_right, 0);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_CMP_GEQ: {
|
||||
struct mie_binary_op *op = (struct mie_binary_op *)instr;
|
||||
mie_type_to_string(op->op_type, type, sizeof type);
|
||||
write_string_f(converter, "cmp geq %s ", type);
|
||||
write_operand(converter, op->op_left, 0);
|
||||
write_string(converter, ", ");
|
||||
write_operand(converter, op->op_right, 0);
|
||||
break;
|
||||
}
|
||||
case MIE_INSTR_GETELEMENTPTR:
|
||||
write_string(converter, "getelementptr");
|
||||
break;
|
||||
case MIE_INSTR_SETELEMENTPTR:
|
||||
write_string(converter, "setelementptr");
|
||||
break;
|
||||
case MIE_INSTR_PHI:
|
||||
write_string(converter, "phi");
|
||||
break;
|
||||
default:
|
||||
write_string_f(converter, "<unknown>");
|
||||
break;
|
||||
}
|
||||
|
||||
write_char(converter, '\n');
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static b_status write_data(
|
||||
struct mie_ir_converter *converter, struct mie_value *value)
|
||||
{
|
||||
char type_name[128];
|
||||
|
||||
struct mie_data *data = MIE_DATA(value);
|
||||
write_string_f(converter, "data @%s = ", value->v_name.n_str);
|
||||
|
||||
switch (data->d_type) {
|
||||
case MIE_DATA_EXTERN_GLOBAL:
|
||||
mie_type_to_string(
|
||||
data->d_extern_global.g_type, type_name, sizeof type_name);
|
||||
write_string_f(converter, "extern global %s", type_name);
|
||||
break;
|
||||
case MIE_DATA_CONST:
|
||||
write_operand_const(
|
||||
converter, MIE_VALUE(data->d_const.c_value),
|
||||
F_INCLUDE_TYPE);
|
||||
break;
|
||||
default:
|
||||
write_string(converter, "<unknown>");
|
||||
break;
|
||||
}
|
||||
|
||||
write_char(converter, '\n');
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
static const write_function value_writers[] = {
|
||||
[MIE_VALUE_MODULE] = write_module,
|
||||
[MIE_VALUE_TYPE] = write_type_definition,
|
||||
[MIE_VALUE_RECORD] = write_record,
|
||||
[MIE_VALUE_FUNC] = write_func_definition,
|
||||
[MIE_VALUE_ARG] = NULL,
|
||||
[MIE_VALUE_BLOCK] = write_block_definition,
|
||||
[MIE_VALUE_INSTR] = write_instr,
|
||||
[MIE_VALUE_DATA] = write_data,
|
||||
[MIE_VALUE_CONST] = NULL,
|
||||
};
|
||||
static const size_t nr_value_printers
|
||||
= sizeof value_writers / sizeof value_writers[0];
|
||||
|
||||
b_status write_value_to_text(
|
||||
struct mie_ir_converter *converter, struct mie_value *value)
|
||||
{
|
||||
write_function writer = value_writers[value->v_type->t_id];
|
||||
return writer(converter, value);
|
||||
}
|
||||
269
mie/ir/ctx.c
Normal file
269
mie/ir/ctx.c
Normal file
@@ -0,0 +1,269 @@
|
||||
#include <blue/object/hashmap.h>
|
||||
#include <blue/object/list.h>
|
||||
#include <blue/object/string.h>
|
||||
#include <mie/ir/const.h>
|
||||
#include <mie/ir/ctx.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct ctx_int_cache_entry {
|
||||
b_btree_node i_node;
|
||||
struct mie_type i_type;
|
||||
b_btree i_values;
|
||||
};
|
||||
|
||||
struct ctx_int_value_cache_entry {
|
||||
b_btree_node i_node;
|
||||
struct mie_int i_value;
|
||||
};
|
||||
|
||||
B_BTREE_DEFINE_SIMPLE_INSERT(
|
||||
struct ctx_int_cache_entry, i_node, i_type.t_width, put_cached_int_type)
|
||||
B_BTREE_DEFINE_SIMPLE_GET(
|
||||
struct ctx_int_cache_entry, unsigned int, i_node, i_type.t_width,
|
||||
get_cached_int_type)
|
||||
|
||||
B_BTREE_DEFINE_SIMPLE_INSERT(
|
||||
struct ctx_int_value_cache_entry, i_node, i_value.i_value,
|
||||
put_cached_int_value)
|
||||
B_BTREE_DEFINE_SIMPLE_GET(
|
||||
struct ctx_int_value_cache_entry, int64_t, i_node, i_value.i_value,
|
||||
get_cached_int_value)
|
||||
|
||||
struct mie_ctx *mie_ctx_create(void)
|
||||
{
|
||||
struct mie_ctx *out = malloc(sizeof *out);
|
||||
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
|
||||
out->ctx_true = MIE_CONST(mie_ctx_get_int(out, 1, 1));
|
||||
out->ctx_false = MIE_CONST(mie_ctx_get_int(out, 0, 1));
|
||||
|
||||
out->ctx_sel_cache = b_hashmap_create(free, free);
|
||||
out->ctx_string_cache = b_hashmap_create(free, free);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void mie_ctx_destroy(struct mie_ctx *ctx)
|
||||
{
|
||||
ctx->ctx_true = NULL;
|
||||
ctx->ctx_false = NULL;
|
||||
|
||||
b_btree_iterator it = {};
|
||||
b_btree_iterator_begin(&ctx->ctx_int_cache, &it);
|
||||
while (b_btree_iterator_is_valid(&it)) {
|
||||
struct ctx_int_cache_entry *entry
|
||||
= b_unbox(struct ctx_int_cache_entry, it.node, i_node);
|
||||
b_btree_iterator_erase(&it);
|
||||
|
||||
b_btree_iterator it2 = {};
|
||||
b_btree_iterator_begin(&entry->i_values, &it2);
|
||||
while (b_btree_iterator_is_valid(&it2)) {
|
||||
struct ctx_int_value_cache_entry *value = b_unbox(
|
||||
struct ctx_int_value_cache_entry, it2.node, i_node);
|
||||
b_btree_iterator_erase(&it2);
|
||||
free(value);
|
||||
}
|
||||
|
||||
free(entry);
|
||||
}
|
||||
|
||||
const size_t nr_types = sizeof ctx->ctx_types / sizeof ctx->ctx_types[0];
|
||||
for (size_t i = 0; i < nr_types; i++) {
|
||||
if (ctx->ctx_types[i]) {
|
||||
mie_value_destroy(MIE_VALUE(ctx->ctx_types[i]));
|
||||
ctx->ctx_types[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
b_hashmap_release(ctx->ctx_sel_cache);
|
||||
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
struct mie_type *mie_ctx_get_type(struct mie_ctx *ctx, enum mie_type_id type_id)
|
||||
{
|
||||
if (type_id == MIE_TYPE_INT) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ctx->ctx_types[type_id]) {
|
||||
return ctx->ctx_types[type_id];
|
||||
}
|
||||
|
||||
struct mie_type *type = malloc(sizeof *type);
|
||||
if (!type) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(type, 0x0, sizeof *type);
|
||||
|
||||
mie_value_init(&type->t_base, MIE_VALUE_TYPE);
|
||||
type->t_id = type_id;
|
||||
|
||||
ctx->ctx_types[type_id] = type;
|
||||
return type;
|
||||
}
|
||||
|
||||
struct mie_type *mie_ctx_get_int_type(struct mie_ctx *ctx, unsigned int nr_bits)
|
||||
{
|
||||
struct ctx_int_cache_entry *entry
|
||||
= get_cached_int_type(&ctx->ctx_int_cache, nr_bits);
|
||||
|
||||
if (entry) {
|
||||
return &entry->i_type;
|
||||
}
|
||||
|
||||
entry = malloc(sizeof *entry);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(entry, 0x0, sizeof *entry);
|
||||
|
||||
mie_value_init(&entry->i_type.t_base, MIE_VALUE_TYPE);
|
||||
entry->i_type.t_id = MIE_TYPE_INT;
|
||||
entry->i_type.t_width = nr_bits;
|
||||
|
||||
put_cached_int_type(&ctx->ctx_int_cache, entry);
|
||||
return &entry->i_type;
|
||||
}
|
||||
|
||||
struct mie_value *mie_ctx_get_bool(struct mie_ctx *ctx, bool val)
|
||||
{
|
||||
return MIE_VALUE(val ? ctx->ctx_true : ctx->ctx_false);
|
||||
}
|
||||
|
||||
struct mie_value *mie_ctx_get_int(
|
||||
struct mie_ctx *ctx, long long val, unsigned int nr_bits)
|
||||
{
|
||||
struct ctx_int_cache_entry *entry
|
||||
= get_cached_int_type(&ctx->ctx_int_cache, nr_bits);
|
||||
|
||||
if (!entry) {
|
||||
entry = malloc(sizeof *entry);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(entry, 0x0, sizeof *entry);
|
||||
|
||||
mie_value_init(&entry->i_type.t_base, MIE_VALUE_TYPE);
|
||||
entry->i_type.t_id = MIE_TYPE_INT;
|
||||
entry->i_type.t_width = nr_bits;
|
||||
|
||||
put_cached_int_type(&ctx->ctx_int_cache, entry);
|
||||
}
|
||||
|
||||
struct ctx_int_value_cache_entry *value
|
||||
= get_cached_int_value(&entry->i_values, val);
|
||||
if (value) {
|
||||
return MIE_VALUE(&value->i_value);
|
||||
}
|
||||
|
||||
value = malloc(sizeof *value);
|
||||
if (!value) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(value, 0x0, sizeof *value);
|
||||
|
||||
mie_const_init(&value->i_value.i_base, &entry->i_type);
|
||||
value->i_value.i_value = val;
|
||||
|
||||
put_cached_int_value(&entry->i_values, value);
|
||||
|
||||
return MIE_VALUE(&value->i_value);
|
||||
}
|
||||
|
||||
struct mie_value *mie_ctx_get_selector(struct mie_ctx *ctx, const char *sel)
|
||||
{
|
||||
b_hashmap_key key = {
|
||||
.key_data = sel,
|
||||
.key_size = strlen(sel),
|
||||
};
|
||||
|
||||
const b_hashmap_value *cache_entry
|
||||
= b_hashmap_get(ctx->ctx_sel_cache, &key);
|
||||
|
||||
if (cache_entry) {
|
||||
return cache_entry->value_data;
|
||||
}
|
||||
|
||||
struct mie_selector *sel_value = malloc(sizeof *sel_value);
|
||||
if (!sel_value) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_type *sel_type = mie_ctx_get_type(ctx, MIE_TYPE_SELECTOR);
|
||||
mie_const_init(&sel_value->sel_base, sel_type);
|
||||
sel_value->sel_value = b_strdup(sel);
|
||||
|
||||
key.key_data = sel_value->sel_value;
|
||||
|
||||
b_hashmap_value hashmap_value = {
|
||||
.value_data = sel_value,
|
||||
.value_size = sizeof *sel_value,
|
||||
};
|
||||
|
||||
b_hashmap_put(ctx->ctx_sel_cache, &key, &hashmap_value);
|
||||
|
||||
return MIE_VALUE(sel_value);
|
||||
}
|
||||
|
||||
struct mie_value *mie_ctx_get_string(struct mie_ctx *ctx, const char *s)
|
||||
{
|
||||
b_hashmap_key key = {
|
||||
.key_data = s,
|
||||
.key_size = strlen(s),
|
||||
};
|
||||
|
||||
const b_hashmap_value *cache_entry
|
||||
= b_hashmap_get(ctx->ctx_string_cache, &key);
|
||||
|
||||
if (cache_entry) {
|
||||
return cache_entry->value_data;
|
||||
}
|
||||
|
||||
struct mie_string *string_value = malloc(sizeof *string_value);
|
||||
if (!string_value) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_type *string_type = mie_ctx_get_type(ctx, MIE_TYPE_STR);
|
||||
mie_const_init(&string_value->s_base, string_type);
|
||||
string_value->s_value = b_strdup(s);
|
||||
|
||||
key.key_data = string_value->s_value;
|
||||
|
||||
b_hashmap_value hashmap_value = {
|
||||
.value_data = string_value,
|
||||
.value_size = sizeof *string_value,
|
||||
};
|
||||
|
||||
b_hashmap_put(ctx->ctx_string_cache, &key, &hashmap_value);
|
||||
|
||||
return MIE_VALUE(string_value);
|
||||
}
|
||||
|
||||
struct mie_value *mie_ctx_create_array(struct mie_ctx *ctx)
|
||||
{
|
||||
struct mie_type *array_type = mie_ctx_get_type(ctx, MIE_TYPE_ARRAY);
|
||||
struct mie_array *array = malloc(sizeof *array);
|
||||
|
||||
if (!array) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(array, 0x0, sizeof *array);
|
||||
mie_const_init(&array->a_base, array_type);
|
||||
|
||||
array->a_values = b_list_create();
|
||||
|
||||
return MIE_VALUE(array);
|
||||
}
|
||||
52
mie/ir/data.c
Normal file
52
mie/ir/data.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include <blue/object/string.h>
|
||||
#include <mie/ir/ctx.h>
|
||||
#include <mie/ir/data.h>
|
||||
#include <mie/ir/type.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct mie_data *mie_data_create_extern_global(
|
||||
struct mie_type *type, const char *ident)
|
||||
{
|
||||
struct mie_data *data = malloc(sizeof *data);
|
||||
if (!data) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(data, 0x0, sizeof *data);
|
||||
|
||||
mie_value_init(&data->d_base, MIE_VALUE_DATA);
|
||||
|
||||
data->d_type = MIE_DATA_EXTERN_GLOBAL;
|
||||
data->d_extern_global.g_type = type;
|
||||
data->d_base.v_name.n_str = b_strdup(ident);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
struct mie_data *mie_data_create_const(struct mie_const *value)
|
||||
{
|
||||
struct mie_data *data = malloc(sizeof *data);
|
||||
if (!data) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(data, 0x0, sizeof *data);
|
||||
|
||||
mie_value_init(&data->d_base, MIE_VALUE_DATA);
|
||||
|
||||
data->d_type = MIE_DATA_CONST;
|
||||
data->d_const.c_value = value;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static struct mie_type *get_type(struct mie_value *v, struct mie_ctx *ctx)
|
||||
{
|
||||
return mie_ctx_get_type(ctx, MIE_TYPE_PTR);
|
||||
}
|
||||
|
||||
const struct mie_value_type data_value_type = {
|
||||
.t_id = MIE_VALUE_DATA,
|
||||
.t_get_type = get_type,
|
||||
};
|
||||
143
mie/ir/func.c
Normal file
143
mie/ir/func.c
Normal file
@@ -0,0 +1,143 @@
|
||||
#include <blue/core/hash.h>
|
||||
#include <blue/object/string.h>
|
||||
#include <mie/ir/arg.h>
|
||||
#include <mie/ir/block.h>
|
||||
#include <mie/ir/func.h>
|
||||
#include <mie/name.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct mie_func *mie_func_create(enum mie_func_type type, struct mie_type *ret_type)
|
||||
{
|
||||
struct mie_func *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
|
||||
mie_value_init(&out->f_base, MIE_VALUE_FUNC);
|
||||
|
||||
out->f_type = type;
|
||||
out->f_ret = ret_type;
|
||||
out->f_names = mie_name_map_create();
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
struct mie_value *mie_func_add_arg(
|
||||
struct mie_func *func, struct mie_type *type, const char *name)
|
||||
{
|
||||
struct mie_arg *arg = mie_arg_create(type);
|
||||
if (!arg) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_value *v
|
||||
= mie_func_generate_value_name(func, MIE_VALUE(arg), name);
|
||||
if (!v) {
|
||||
mie_value_destroy(MIE_VALUE(arg));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
b_queue_push_back(&func->f_args, &v->v_entry);
|
||||
return v;
|
||||
}
|
||||
|
||||
struct mie_block *mie_func_create_block(struct mie_func *func, const char *name)
|
||||
{
|
||||
struct mie_block *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
|
||||
mie_value_init(&out->b_base, MIE_VALUE_BLOCK);
|
||||
|
||||
struct mie_value *block = MIE_VALUE(out);
|
||||
|
||||
block = mie_func_generate_value_name(func, block, name);
|
||||
if (!block) {
|
||||
free(out);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
out->b_parent = func;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void mie_func_insert_block(
|
||||
struct mie_func *func, struct mie_block *block, struct mie_block *after)
|
||||
{
|
||||
if (after) {
|
||||
b_queue_insert_after(
|
||||
&func->f_blocks, &block->b_base.v_entry,
|
||||
&after->b_base.v_entry);
|
||||
} else {
|
||||
b_queue_push_back(&func->f_blocks, &block->b_base.v_entry);
|
||||
}
|
||||
}
|
||||
|
||||
struct mie_value *mie_func_generate_value_name(
|
||||
struct mie_func *func, struct mie_value *val, const char *hint)
|
||||
{
|
||||
struct mie_name *name
|
||||
= mie_name_map_put(func->f_names, &val->v_name, hint, 0);
|
||||
return b_unbox(struct mie_value, name, v_name);
|
||||
}
|
||||
|
||||
struct mie_block *mie_func_get_first_block(struct mie_func *func)
|
||||
{
|
||||
b_queue_entry *entry = b_queue_first(&func->f_blocks);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (struct mie_block *)b_unbox(struct mie_value, entry, v_entry);
|
||||
}
|
||||
|
||||
struct mie_block *mie_func_get_last_block(struct mie_func *func)
|
||||
{
|
||||
b_queue_entry *entry = b_queue_last(&func->f_blocks);
|
||||
if (!entry) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (struct mie_block *)b_unbox(struct mie_value, entry, v_entry);
|
||||
}
|
||||
|
||||
static struct mie_type *get_type(struct mie_value *v, struct mie_ctx *ctx)
|
||||
{
|
||||
struct mie_func *f = MIE_FUNC(v);
|
||||
return f->f_ret;
|
||||
}
|
||||
|
||||
static void cleanup(struct mie_value *value)
|
||||
{
|
||||
struct mie_func *func = MIE_FUNC(value);
|
||||
|
||||
b_queue_iterator it;
|
||||
b_queue_iterator_begin(&func->f_args, &it);
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
struct mie_value *v = b_unbox(struct mie_value, it.entry, v_entry);
|
||||
b_queue_iterator_erase(&it);
|
||||
mie_value_destroy(v);
|
||||
}
|
||||
|
||||
b_queue_iterator_begin(&func->f_blocks, &it);
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
struct mie_value *v = b_unbox(struct mie_value, it.entry, v_entry);
|
||||
b_queue_iterator_erase(&it);
|
||||
mie_value_destroy(v);
|
||||
}
|
||||
|
||||
mie_name_map_destroy(func->f_names);
|
||||
}
|
||||
|
||||
const struct mie_value_type func_value_type = {
|
||||
.t_id = MIE_VALUE_FUNC,
|
||||
.t_get_type = get_type,
|
||||
.t_cleanup = cleanup,
|
||||
};
|
||||
55
mie/ir/instr.c
Normal file
55
mie/ir/instr.c
Normal file
@@ -0,0 +1,55 @@
|
||||
#include <mie/ir/ctx.h>
|
||||
#include <mie/ir/instr.h>
|
||||
#include <mie/ir/msg.h>
|
||||
#include <mie/ir/op.h>
|
||||
#include <mie/ir/ptr.h>
|
||||
|
||||
void mie_instr_init(struct mie_instr *instr, enum mie_instr_type type)
|
||||
{
|
||||
memset(instr, 0x0, sizeof *instr);
|
||||
mie_value_init(&instr->i_base, MIE_VALUE_INSTR);
|
||||
instr->i_type = type;
|
||||
}
|
||||
|
||||
static struct mie_type *get_type(struct mie_value *v, struct mie_ctx *ctx)
|
||||
{
|
||||
struct mie_instr *instr = MIE_INSTR(v);
|
||||
|
||||
switch (instr->i_type) {
|
||||
case MIE_INSTR_RET: {
|
||||
struct mie_ret *ret = (struct mie_ret *)instr;
|
||||
return mie_value_get_type(ret->r_val, ctx);
|
||||
}
|
||||
case MIE_INSTR_ADD:
|
||||
case MIE_INSTR_SUB:
|
||||
case MIE_INSTR_MUL:
|
||||
case MIE_INSTR_DIV: {
|
||||
struct mie_binary_op *op = (struct mie_binary_op *)instr;
|
||||
return op->op_type;
|
||||
}
|
||||
case MIE_INSTR_CMP_EQ:
|
||||
case MIE_INSTR_CMP_NEQ:
|
||||
case MIE_INSTR_CMP_LT:
|
||||
case MIE_INSTR_CMP_LEQ:
|
||||
case MIE_INSTR_CMP_GT:
|
||||
case MIE_INSTR_CMP_GEQ:
|
||||
return mie_ctx_get_int_type(ctx, 1);
|
||||
case MIE_INSTR_LOAD: {
|
||||
struct mie_load *load = (struct mie_load *)instr;
|
||||
return load->l_type;
|
||||
}
|
||||
case MIE_INSTR_ALLOCA:
|
||||
return mie_ctx_get_type(ctx, MIE_TYPE_PTR);
|
||||
case MIE_INSTR_MSG: {
|
||||
struct mie_msg *msg = (struct mie_msg *)instr;
|
||||
return msg->msg_ret_type;
|
||||
}
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const struct mie_value_type instr_value_type = {
|
||||
.t_id = MIE_VALUE_INSTR,
|
||||
.t_get_type = get_type,
|
||||
};
|
||||
148
mie/ir/module.c
Normal file
148
mie/ir/module.c
Normal file
@@ -0,0 +1,148 @@
|
||||
#include <blue/object/hashmap.h>
|
||||
#include <mie/ir/const.h>
|
||||
#include <mie/ir/data.h>
|
||||
#include <mie/ir/func.h>
|
||||
#include <mie/ir/module.h>
|
||||
#include <mie/ir/type.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct mie_module *mie_module_create(void)
|
||||
{
|
||||
struct mie_module *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
|
||||
mie_value_init(&out->m_base, MIE_VALUE_MODULE);
|
||||
|
||||
out->m_names = mie_name_map_create();
|
||||
out->m_data = b_hashmap_create(NULL, NULL);
|
||||
out->m_data_strings = b_hashmap_create(NULL, NULL);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void mie_module_add_function(
|
||||
struct mie_module *mod, struct mie_func *func, const char *name)
|
||||
{
|
||||
struct mie_value *v
|
||||
= mie_module_generate_value_name(mod, MIE_VALUE(func), name);
|
||||
if (!v) {
|
||||
return;
|
||||
}
|
||||
|
||||
b_queue_push_back(&mod->m_func, &v->v_entry);
|
||||
}
|
||||
|
||||
struct mie_data *mie_module_get_string_ptr(struct mie_module *mod, const char *s)
|
||||
{
|
||||
b_hashmap_key key = {
|
||||
.key_data = s,
|
||||
.key_size = strlen(s),
|
||||
};
|
||||
|
||||
const b_hashmap_value *entry = b_hashmap_get(mod->m_data_strings, &key);
|
||||
if (entry) {
|
||||
return entry->value_data;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct mie_data *mie_module_get_data(struct mie_module *mod, const char *name)
|
||||
{
|
||||
b_hashmap_key key = {
|
||||
.key_data = name,
|
||||
.key_size = strlen(name),
|
||||
};
|
||||
|
||||
const b_hashmap_value *entry = b_hashmap_get(mod->m_data, &key);
|
||||
if (entry) {
|
||||
return entry->value_data;
|
||||
}
|
||||
|
||||
/* don't search m_data_strings, as it is keyed by the string contents
|
||||
* rather than the data entry name, and its entries are duplicated in
|
||||
* m_data anyway */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
enum b_status mie_module_put_data(
|
||||
struct mie_module *mod, struct mie_data *data, const char *name)
|
||||
{
|
||||
struct mie_value *v
|
||||
= mie_module_generate_value_name(mod, MIE_VALUE(data), name);
|
||||
|
||||
b_hashmap_key key = {
|
||||
.key_data = v->v_name.n_str,
|
||||
.key_size = strlen(name),
|
||||
};
|
||||
|
||||
b_hashmap_value value = {
|
||||
.value_data = data,
|
||||
.value_size = sizeof *data,
|
||||
};
|
||||
|
||||
b_hashmap_put(mod->m_data, &key, &value);
|
||||
|
||||
if (data->d_type != MIE_DATA_CONST) {
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
struct mie_const *const_data = data->d_const.c_value;
|
||||
if (const_data->c_type->t_id == MIE_TYPE_STR) {
|
||||
struct mie_string *s = MIE_STRING(const_data);
|
||||
key.key_data = s->s_value;
|
||||
key.key_size = strlen(key.key_data);
|
||||
b_hashmap_put(mod->m_data_strings, &key, &value);
|
||||
}
|
||||
|
||||
return B_SUCCESS;
|
||||
}
|
||||
|
||||
struct mie_value *mie_module_generate_value_name(
|
||||
struct mie_module *mod, struct mie_value *val, const char *hint)
|
||||
{
|
||||
struct mie_name *name
|
||||
= mie_name_map_put(mod->m_names, &val->v_name, hint, 0);
|
||||
return b_unbox(struct mie_value, name, v_name);
|
||||
}
|
||||
|
||||
static void cleanup(struct mie_value *value)
|
||||
{
|
||||
struct mie_module *module = MIE_MODULE(value);
|
||||
|
||||
b_queue_iterator it;
|
||||
b_queue_iterator_begin(&module->m_records, &it);
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
struct mie_value *v = b_unbox(struct mie_value, it.entry, v_entry);
|
||||
b_queue_iterator_erase(&it);
|
||||
mie_value_destroy(v);
|
||||
}
|
||||
|
||||
b_queue_iterator_begin(&module->m_types, &it);
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
struct mie_value *v = b_unbox(struct mie_value, it.entry, v_entry);
|
||||
b_queue_iterator_erase(&it);
|
||||
mie_value_destroy(v);
|
||||
}
|
||||
|
||||
b_queue_iterator_begin(&module->m_func, &it);
|
||||
while (b_queue_iterator_is_valid(&it)) {
|
||||
struct mie_value *v = b_unbox(struct mie_value, it.entry, v_entry);
|
||||
b_queue_iterator_erase(&it);
|
||||
mie_value_destroy(v);
|
||||
}
|
||||
|
||||
b_hashmap_release(module->m_data_strings);
|
||||
b_hashmap_release(module->m_data);
|
||||
}
|
||||
|
||||
const struct mie_value_type module_value_type = {
|
||||
.t_id = MIE_VALUE_MODULE,
|
||||
.t_cleanup = cleanup,
|
||||
};
|
||||
29
mie/ir/record.c
Normal file
29
mie/ir/record.c
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <mie/ir/record.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
struct mie_record *mie_record_create(const struct mie_const *val)
|
||||
{
|
||||
struct mie_record *out = malloc(sizeof *out);
|
||||
if (!out) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memset(out, 0x0, sizeof *out);
|
||||
|
||||
mie_value_init(&out->r_base, MIE_VALUE_RECORD);
|
||||
out->r_value = val;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
static struct mie_type *get_type(struct mie_value *v, struct mie_ctx *ctx)
|
||||
{
|
||||
struct mie_record *r = MIE_RECORD(v);
|
||||
return r->r_value->c_type;
|
||||
}
|
||||
|
||||
const struct mie_value_type record_value_type = {
|
||||
.t_id = MIE_VALUE_RECORD,
|
||||
.t_get_type = get_type,
|
||||
};
|
||||
11
mie/ir/type.c
Normal file
11
mie/ir/type.c
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <mie/ir/type.h>
|
||||
|
||||
static struct mie_type *get_type(struct mie_value *v, struct mie_ctx *ctx)
|
||||
{
|
||||
return MIE_TYPE(v);
|
||||
}
|
||||
|
||||
const struct mie_value_type type_value_type = {
|
||||
.t_id = MIE_VALUE_TYPE,
|
||||
.t_get_type = get_type,
|
||||
};
|
||||
56
mie/ir/value.c
Normal file
56
mie/ir/value.c
Normal file
@@ -0,0 +1,56 @@
|
||||
#include <mie/ir/const.h>
|
||||
#include <mie/ir/value.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern const struct mie_value_type module_value_type;
|
||||
extern const struct mie_value_type type_value_type;
|
||||
extern const struct mie_value_type record_value_type;
|
||||
extern const struct mie_value_type func_value_type;
|
||||
extern const struct mie_value_type arg_value_type;
|
||||
extern const struct mie_value_type block_value_type;
|
||||
extern const struct mie_value_type instr_value_type;
|
||||
extern const struct mie_value_type const_value_type;
|
||||
extern const struct mie_value_type data_value_type;
|
||||
|
||||
static const struct mie_value_type *value_types[] = {
|
||||
[MIE_VALUE_NONE] = NULL,
|
||||
[MIE_VALUE_MODULE] = &module_value_type,
|
||||
[MIE_VALUE_TYPE] = &type_value_type,
|
||||
[MIE_VALUE_RECORD] = &record_value_type,
|
||||
[MIE_VALUE_FUNC] = &func_value_type,
|
||||
[MIE_VALUE_ARG] = &arg_value_type,
|
||||
[MIE_VALUE_BLOCK] = &block_value_type,
|
||||
[MIE_VALUE_INSTR] = &instr_value_type,
|
||||
[MIE_VALUE_CONST] = &const_value_type,
|
||||
[MIE_VALUE_DATA] = &data_value_type,
|
||||
};
|
||||
static const size_t nr_value_types = sizeof value_types / sizeof value_types[0];
|
||||
|
||||
void mie_value_init(struct mie_value *val, enum mie_value_type_id type)
|
||||
{
|
||||
memset(val, 0x0, sizeof *val);
|
||||
|
||||
val->v_type = value_types[type];
|
||||
}
|
||||
|
||||
void mie_value_destroy(struct mie_value *val)
|
||||
{
|
||||
if (val->v_type && val->v_type->t_cleanup) {
|
||||
val->v_type->t_cleanup(val);
|
||||
}
|
||||
|
||||
if (val->v_name.n_str) {
|
||||
free(val->v_name.n_str);
|
||||
}
|
||||
|
||||
free(val);
|
||||
}
|
||||
|
||||
struct mie_type *mie_value_get_type(struct mie_value *val, struct mie_ctx *ctx)
|
||||
{
|
||||
if (val->v_type->t_get_type) {
|
||||
return val->v_type->t_get_type(val, ctx);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
Reference in New Issue
Block a user