497 lines
12 KiB
C
497 lines
12 KiB
C
#include "convert.h"
|
|
|
|
#include <inttypes.h>
|
|
#include <mie/alloca.h>
|
|
#include <mie/arg.h>
|
|
#include <mie/block.h>
|
|
#include <mie/branch.h>
|
|
#include <mie/const.h>
|
|
#include <mie/func.h>
|
|
#include <mie/instr.h>
|
|
#include <mie/module.h>
|
|
#include <mie/op.h>
|
|
#include <mie/ptr.h>
|
|
#include <mie/type.h>
|
|
#include <mie/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)
|
|
{
|
|
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;
|
|
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);
|
|
}
|
|
|
|
switch (c->c_type->t_id) {
|
|
case MIE_TYPE_INT:
|
|
write_string_f(converter, "#%" PRId64, c->c_v.v_int);
|
|
break;
|
|
case MIE_TYPE_PTR:
|
|
case MIE_TYPE_ID:
|
|
write_string_f(converter, "%%%s", value->v_name.n_str);
|
|
break;
|
|
case MIE_TYPE_STR:
|
|
case MIE_TYPE_ATOM:
|
|
write_string(converter, c->c_v.v_str);
|
|
break;
|
|
case MIE_TYPE_CLASS:
|
|
write_string_f(converter, "@%s", value->v_name.n_str);
|
|
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);
|
|
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);
|
|
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(
|
|
struct mie_ir_converter *converter, struct mie_value *value, int flags)
|
|
{
|
|
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);
|
|
default:
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
b_queue_foreach (&it, &mod->m_data) {
|
|
struct mie_value *data
|
|
= b_unbox(struct mie_value, it.entry, v_entry);
|
|
status = write_value_to_text(converter, data);
|
|
|
|
if (!B_OK(status)) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
b_queue_foreach (&it, &mod->m_func) {
|
|
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;
|
|
}
|
|
}
|
|
|
|
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)
|
|
{
|
|
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) {
|
|
puts(", ");
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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_MSG:
|
|
write_string(converter, "msg");
|
|
break;
|
|
case MIE_INSTR_CMP_EQ:
|
|
write_string(converter, "cmp eq");
|
|
break;
|
|
case MIE_INSTR_CMP_LT:
|
|
write_string(converter, "cmp lt");
|
|
break;
|
|
case MIE_INSTR_CMP_GT:
|
|
write_string(converter, "cmp gt");
|
|
break;
|
|
case MIE_INSTR_CMP_LEQ:
|
|
write_string(converter, "cmp leq");
|
|
break;
|
|
case MIE_INSTR_CMP_GEQ:
|
|
write_string(converter, "cmp geq");
|
|
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 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_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);
|
|
}
|