Files
ivy/mie/ir/convert/text-write.c

752 lines
19 KiB
C

#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);
}