#include "convert.h" #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 *); 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, ""); 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: write_string(converter, "sub"); break; case MIE_INSTR_MUL: write_string(converter, "mul"); break; case MIE_INSTR_DIV: write_string(converter, "div"); 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, ""); 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); }