#include "convert.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define F_INCLUDE_TYPE 0x01u typedef b_status (*write_function)(struct mie_ir_converter *, struct mie_value *); 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_stream_write_string( converter->c_dest.stringstream, s, NULL); 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_stream_write_string( converter->c_dest.stringstream, s, NULL); 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_stream_write_string( converter->c_dest.stringstream, buf, NULL); 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_iterator *it = b_list_begin(array->a_values); write_char(converter, '{'); size_t i = 0; b_foreach(void *, item, it) { if (i > 0) { write_char(converter, ','); } write_string(converter, "\n "); struct mie_value *child = item; write_operand_const(converter, child, F_INCLUDE_TYPE); i++; } b_iterator_unref(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, ""); return B_SUCCESS; } switch (value->v_type->t_id) { case MIE_VALUE_NONE: write_string(converter, "null"); return B_SUCCESS; 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, "", 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_entry *entry = b_queue_first(&mod->m_records); while (entry) { struct mie_value *record = b_unbox(struct mie_value, entry, v_entry); status = write_value_to_text(converter, record); if (!B_OK(status)) { return status; } entry = b_queue_next(entry); } if (!b_queue_empty(&mod->m_records)) { write_char(converter, '\n'); } entry = b_queue_first(&mod->m_types); while (entry) { struct mie_value *type = b_unbox(struct mie_value, entry, v_entry); status = write_value_to_text(converter, type); if (!B_OK(status)) { return status; } entry = b_queue_next(entry); } if (!b_queue_empty(&mod->m_types)) { write_char(converter, '\n'); } b_iterator *it = b_iterator_begin(mod->m_data); b_foreach_ptr(b_hashmap_item, item, it) { struct mie_value *data = item->value.value_data; status = write_value_to_text(converter, data); if (!B_OK(status)) { return status; } } b_iterator_unref(it); if (!b_hashmap_is_empty(mod->m_data)) { write_char(converter, '\n'); } unsigned long i = 0; entry = b_queue_first(&mod->m_func); while (entry) { if (i > 0) { write_char(converter, '\n'); } struct mie_value *func = b_unbox(struct mie_value, entry, v_entry); status = write_value_to_text(converter, func); if (!B_OK(status)) { return status; } i++; entry = b_queue_next(entry); } 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; struct b_queue_entry *entry = b_queue_first(&func->f_args); while (entry) { struct mie_arg *arg = (struct mie_arg *)b_unbox( struct mie_value, 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++; entry = b_queue_next(entry); } 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"); entry = b_queue_first(&func->f_blocks); while (entry) { struct mie_value *block = b_unbox(struct mie_value, entry, v_entry); write_value_to_text(converter, block); entry = b_queue_next(entry); } 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_entry *entry = b_queue_first(&block->b_phi); while (entry) { struct mie_value *instr = b_unbox(struct mie_value, entry, v_entry); write_value_to_text(converter, instr); entry = b_queue_next(entry); } entry = b_queue_first(&block->b_instr); while (entry) { struct mie_value *instr = b_unbox(struct mie_value, entry, v_entry); write_value_to_text(converter, instr); entry = b_queue_next(entry); } 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: { struct mie_phi *phi = (struct mie_phi *)instr; mie_type_to_string(phi->p_type, type, sizeof type); write_string_f(converter, "phi %s ", type); for (size_t i = 0; i < phi->p_nr_edges; i++) { if (i > 0) { write_string(converter, ", "); } write_string(converter, "[ "); write_operand( converter, MIE_VALUE(phi->p_edges[i].e_incoming_block), 0); write_string(converter, ", "); write_operand(converter, phi->p_edges[i].e_value, 0); write_string(converter, " ]"); } break; } default: write_string_f(converter, ""); 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, ""); 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); }