diff --git a/frontend/cmd/compile.c b/frontend/cmd/compile.c index 7849582..a2576bc 100644 --- a/frontend/cmd/compile.c +++ b/frontend/cmd/compile.c @@ -3,8 +3,10 @@ #include "mie/select/builder.h" #include +#include #include #include +#include #include #include #include @@ -29,9 +31,29 @@ enum { OPT_SHOW_ISEL_POST, }; -struct codegen_args { - struct ivy_codegen *args_gen; - bool args_print_ast; +enum compile_flags { + FLAG_SHOW_LEX_TOKENS = 0x01u, + FLAG_SHOW_AST_NODES = 0x02u, + FLAG_SHOW_IR = 0x04u, + FLAG_SHOW_PRE_SELECT_GRAPH = 0x08u, + FLAG_SHOW_POST_SELECT_GRAPH = 0x10u, +}; + +struct compile_ctx { + enum compile_flags flags; + const char *src_path; + struct ivy_file *src; + struct ivy_diag_ctx *diag; + struct ivy_diag_stream diag_stream; + + struct ivy_lexer *lex; + struct ivy_parser *parser; + struct ivy_codegen *codegen; + + struct mie_ctx *mie_ctx; + struct mie_select_builder *select; + + struct mie_module *mod; }; static enum ivy_status node_codegen( @@ -42,224 +64,324 @@ static enum ivy_status node_codegen( return IVY_OK; } - struct codegen_args *args = arg; - struct ivy_codegen *gen = args->args_gen; - if (args->args_print_ast) { - print_ast_node(node, iteration_type, it, NULL); + struct compile_ctx *ctx = arg; + return ivy_codegen_push_node(ctx->codegen, node, node->n_it.it_depth); +} + +static b_result compile_ctx_init(struct compile_ctx *ctx, const b_arglist *args) +{ + memset(ctx, 0x0, sizeof *ctx); + + b_arglist_get_count(args, OPT_SHOW_LEX_TOKENS, B_COMMAND_INVALID_ID) + && (ctx->flags |= FLAG_SHOW_LEX_TOKENS); + b_arglist_get_count(args, OPT_SHOW_AST_NODES, B_COMMAND_INVALID_ID) + && (ctx->flags |= FLAG_SHOW_AST_NODES); + b_arglist_get_count(args, OPT_SHOW_IR, B_COMMAND_INVALID_ID) + && (ctx->flags |= FLAG_SHOW_IR); + b_arglist_get_count(args, OPT_SHOW_ISEL_PRE, B_COMMAND_INVALID_ID) + && (ctx->flags |= FLAG_SHOW_PRE_SELECT_GRAPH); + b_arglist_get_count(args, OPT_SHOW_ISEL_POST, B_COMMAND_INVALID_ID) + && (ctx->flags |= FLAG_SHOW_POST_SELECT_GRAPH); + + enum mie_status mie_status = MIE_SUCCESS; + enum ivy_status ivy_status = IVY_OK; + + ctx->mie_ctx = mie_ctx_create(); + + ivy_status = ivy_diag_ctx_create(&ctx->diag); + ivy_status = ivy_lexer_create(&ctx->lex); + ivy_status = ivy_parser_create(&ctx->parser); + ivy_status = ivy_codegen_create(ctx->mie_ctx, &ctx->codegen); + ctx->select + = mie_select_builder_create(ctx->mie_ctx, ivy_asm_mie_target()); + + ivy_lang_diag_ctx_init(ctx->diag); + ivy_diag_stream_init_tty(&ctx->diag_stream, b_stdtty); + ivy_lexer_set_diag_ctx(ctx->lex, ctx->diag); + ivy_parser_set_diag_ctx(ctx->parser, ctx->diag); + + return B_RESULT_SUCCESS; +} + +static b_result compile_ctx_cleanup(struct compile_ctx *ctx) +{ + if (ctx->mod) { + mie_value_destroy(MIE_VALUE(ctx->mod)); } - return ivy_codegen_push_node(gen, node, node->n_it.it_depth); + if (ctx->src) { + ivy_diag_ctx_set_line_source(ctx->diag, NULL); + ivy_lexer_set_source(ctx->lex, NULL); + ivy_file_close(ctx->src); + } + + if (ctx->select) { + mie_select_builder_destroy(ctx->select); + } + + if (ctx->codegen) { + ivy_codegen_destroy(ctx->codegen); + } + + if (ctx->parser) { + ivy_parser_destroy(ctx->parser, NULL); + } + + if (ctx->lex) { + ivy_lexer_destroy(ctx->lex); + } + + if (ctx->diag) { + ivy_diag_ctx_destroy(ctx->diag); + } + + if (ctx->mie_ctx) { + mie_ctx_destroy(ctx->mie_ctx); + } + + return B_RESULT_SUCCESS; +} + +static b_result open_file(struct compile_ctx *ctx, const char *path) +{ + enum ivy_status status = ivy_file_open(path, &ctx->src); + + ivy_diag_ctx_set_line_source(ctx->diag, &ctx->src->f_base); + ivy_lexer_set_source(ctx->lex, &ctx->src->f_base); + + ctx->src_path = path; + + return B_RESULT_SUCCESS; +} + +static b_result parse_file_tokens(struct compile_ctx *ctx) +{ + enum ivy_status status = IVY_OK; + + while (true) { + struct ivy_token *tok = ivy_lexer_read(ctx->lex); + status = ivy_lexer_get_status(ctx->lex); + + if (status != IVY_OK && status != IVY_ERR_EOF) { + ivy_diag_ctx_write( + ctx->diag, IVY_DIAG_FORMAT_PRETTY, + &ctx->diag_stream); + return b_error_with_code( + IVY_ERROR_VENDOR, IVY_ERR_BAD_SYNTAX); + } + + if (tok && (ctx->flags & FLAG_SHOW_LEX_TOKENS)) { + print_lex_token(tok); + } + + status = ivy_parser_push_token(ctx->parser, tok); + + if (status == IVY_ERR_BAD_SYNTAX) { + ivy_diag_ctx_write( + ctx->diag, IVY_DIAG_FORMAT_PRETTY, + &ctx->diag_stream); + ivy_token_destroy(tok); + return b_error_with_code( + IVY_ERROR_VENDOR, IVY_ERR_BAD_SYNTAX); + } + + if (status != IVY_OK) { + return b_error_caused_by_code( + IVY_ERROR_VENDOR, IVY_ERR_PARSE_FAILURE, + IVY_ERROR_VENDOR, status); + } + + if (!tok) { + break; + } + } + + return B_RESULT_SUCCESS; +} + +static b_result generate_mie_ir(struct compile_ctx *ctx) +{ + ivy_codegen_start_module(ctx->codegen); + + struct ivy_ast_node *node = ivy_parser_root_node(ctx->parser); + struct ivy_ast_node_iterator it = {0}; + + enum ivy_status status + = ivy_ast_node_iterate(node, &it, node_codegen, ctx); + if (status != IVY_OK) { + return b_error_caused_by_code( + IVY_ERROR_VENDOR, IVY_ERR_CODEGEN_FAILURE, + IVY_ERROR_VENDOR, status); + } + + status = ivy_codegen_push_eof(ctx->codegen); + if (status != IVY_OK) { + return b_error_caused_by_code( + IVY_ERROR_VENDOR, IVY_ERR_CODEGEN_FAILURE, + IVY_ERROR_VENDOR, status); + } + + ivy_codegen_end_module(ctx->codegen, &ctx->mod); + + return B_RESULT_SUCCESS; +} + +static b_result build_block_isel_graph( + struct compile_ctx *ctx, struct mie_func *func, struct mie_block *block) +{ + b_queue_iterator instr_it; + b_queue_foreach (&instr_it, &block->b_phi) { + struct mie_value *instr_v + = b_unbox(struct mie_value, instr_it.entry, v_entry); + mie_select_builder_push_instr( + ctx->select, (struct mie_instr *)instr_v); + } + + b_queue_foreach (&instr_it, &block->b_instr) { + struct mie_value *instr_v + = b_unbox(struct mie_value, instr_it.entry, v_entry); + mie_select_builder_push_instr( + ctx->select, (struct mie_instr *)instr_v); + } + + if (block->b_terminator) { + mie_select_builder_push_instr(ctx->select, block->b_terminator); + } + + struct mie_select_graph *graph = mie_select_builder_finish(ctx->select); + + if (ctx->flags & FLAG_SHOW_PRE_SELECT_GRAPH) { + printf("%s.%s instruction graph:\n", func->f_base.v_name.n_str, + block->b_base.v_name.n_str); + mie_select_graph_dump_dot(graph); + mie_select_graph_destroy(graph); + } + + return B_RESULT_SUCCESS; +} + +static b_result build_func_isel_graph(struct compile_ctx *ctx, struct mie_func *func) +{ + b_queue_iterator it; + b_queue_foreach (&it, &func->f_blocks) { + struct mie_value *block_v + = b_unbox(struct mie_value, it.entry, v_entry); + struct mie_block *block = (struct mie_block *)block_v; + + b_result result = build_block_isel_graph(ctx, func, block); + if (b_result_is_error(result)) { + return b_result_propagate(result); + } + } + + return B_RESULT_SUCCESS; +} + +static b_result build_isel_graph(struct compile_ctx *ctx) +{ + b_queue_iterator it; + + b_queue_foreach (&it, &ctx->mod->m_func) { + struct mie_value *func_v + = b_unbox(struct mie_value, it.entry, v_entry); + struct mie_func *func = (struct mie_func *)func_v; + + b_result result = build_func_isel_graph(ctx, func); + if (b_result_is_error(result)) { + return b_result_propagate(result); + } + } + + return B_RESULT_SUCCESS; +} + +static b_result dump_ast(struct compile_ctx *ctx) +{ + struct ivy_ast_node *node = ivy_parser_root_node(ctx->parser); + struct ivy_ast_node_iterator it = {0}; + struct print_ast_node_args args = { + .indent = true, + }; + + ivy_ast_node_iterate(node, &it, print_ast_node, &args); + + return B_RESULT_SUCCESS; +} + +static b_result dump_ir(struct compile_ctx *ctx) +{ + struct mie_ir_converter *convert + = mie_ir_converter_create(ctx->mie_ctx, MIE_IR_MEM, MIE_IR_TEXT); + mie_ir_converter_set_src_value(convert, MIE_VALUE(ctx->mod)); + mie_ir_converter_set_dest_file(convert, stdout); + mie_ir_converter_process(convert); + + mie_ir_converter_destroy(convert); + + return B_RESULT_SUCCESS; } static int compile_file(const char *path, const b_arglist *args) { - bool show_lex = b_arglist_get_count( - args, OPT_SHOW_LEX_TOKENS, B_COMMAND_INVALID_ID) - > 0; - bool show_ast = b_arglist_get_count( - args, OPT_SHOW_AST_NODES, B_COMMAND_INVALID_ID) - > 0; - bool show_ir - = b_arglist_get_count(args, OPT_SHOW_IR, B_COMMAND_INVALID_ID) > 0; - bool show_isel_pre - = b_arglist_get_count(args, OPT_SHOW_ISEL_PRE, B_COMMAND_INVALID_ID) - > 0; - enum ivy_status status = IVY_OK; +#define THROW_AND_RETURN(result, error_code) \ + do { \ + if (b_result_is(result, IVY_ERROR_VENDOR, IVY_ERR_BAD_SYNTAX)) { \ + return error_code; \ + } \ + if (b_result_is_error(result)) { \ + b_throw(result); \ + return error_code; \ + } \ + } while (0) - struct ivy_file *src = NULL; - status = ivy_file_open(path, &src); - if (!src) { - b_err("cannot open source file '%s'", path); - b_i("reason: %s", ivy_status_to_string(status)); - return -1; + struct compile_ctx ctx; + b_result result = compile_ctx_init(&ctx, args); + THROW_AND_RETURN(result, -1); + + int progress = 0; + (ctx.flags & FLAG_SHOW_LEX_TOKENS) && (progress = 1); + (ctx.flags & FLAG_SHOW_AST_NODES) && (progress = 1); + (ctx.flags & FLAG_SHOW_IR) && (progress = 2); + (ctx.flags & FLAG_SHOW_PRE_SELECT_GRAPH) && (progress = 3); + (ctx.flags & FLAG_SHOW_POST_SELECT_GRAPH) && (progress = 4); + + result = open_file(&ctx, path); + THROW_AND_RETURN(result, -1); + + result = parse_file_tokens(&ctx); + THROW_AND_RETURN(result, -1); + + if (ctx.flags & FLAG_SHOW_AST_NODES) { + dump_ast(&ctx); } - struct ivy_diag_stream diag_stream; - ivy_diag_stream_init_tty(&diag_stream, b_stdtty); - - struct ivy_diag_ctx *diag = NULL; - status = ivy_diag_ctx_create(&diag); - if (status != IVY_OK) { - b_err("failed to initialise Ivy diagnostic context"); - ivy_file_close(src); - return -1; + if (progress == 1) { + return 0; } - ivy_lang_diag_ctx_init(diag); - ivy_diag_ctx_set_line_source(diag, &src->f_base); + result = generate_mie_ir(&ctx); + THROW_AND_RETURN(result, -1); - struct ivy_lexer *lex = NULL; - if (ivy_lexer_create(&lex) != IVY_OK) { - b_err("failed to initialise Ivy lexer"); - ivy_file_close(src); - return -1; + if (ctx.flags & FLAG_SHOW_IR) { + dump_ir(&ctx); } - ivy_lexer_set_source(lex, &src->f_base); - ivy_lexer_set_diag_ctx(lex, diag); - - struct ivy_parser *parser = NULL; - status = ivy_parser_create(&parser); - - if (status != IVY_OK) { - b_err("failed to initialise Ivy parser"); - ivy_lexer_destroy(lex); - ivy_file_close(src); - return -1; + if (progress == 2) { + return 0; } - ivy_parser_set_diag_ctx(parser, diag); + result = build_isel_graph(&ctx); + THROW_AND_RETURN(result, -1); - struct mie_ctx *ctx = mie_ctx_create(); - - struct ivy_codegen *codegen; - status = ivy_codegen_create(ctx, &codegen); - - if (status != IVY_OK) { - b_err("failed to initialise Ivy code generator"); - ivy_parser_destroy(parser, NULL); - ivy_lexer_destroy(lex); - ivy_file_close(src); - return -1; + if (progress == 3) { + return 0; } - while (true) { - struct ivy_token *tok = ivy_lexer_read(lex); - status = ivy_lexer_get_status(lex); - if (status == IVY_ERR_EOF) { - break; - } +end: + compile_ctx_cleanup(&ctx); - if (status != IVY_OK) { - ivy_diag_ctx_write( - diag, IVY_DIAG_FORMAT_PRETTY, &diag_stream); - break; - } - - if (show_lex) { - print_lex_token(tok); - } - - status = ivy_parser_push_token(parser, tok); - - if (status == IVY_ERR_BAD_SYNTAX) { - ivy_diag_ctx_write( - diag, IVY_DIAG_FORMAT_PRETTY, &diag_stream); - ivy_token_destroy(tok); - break; - } - - if (status != IVY_OK) { - b_err("failed to parse '%s'", path); - b_i("reason: parse error (%s)", - ivy_status_to_string(status)); - ivy_token_destroy(tok); - break; - } - } - - int r = (status == IVY_OK || status == IVY_ERR_EOF) ? 0 : -1; - ivy_file_close(src); - ivy_lexer_destroy(lex); - - if (r != 0) { - return r; - } - - if (r != 0) { - ivy_parser_destroy(parser, NULL); - return r; - } - - if (show_ast && !show_ir) { - struct ivy_ast_node *root = ivy_parser_root_node(parser); - struct ivy_ast_node_iterator it = {0}; - ivy_ast_node_iterate(root, &it, print_ast_node, NULL); - } - - ivy_codegen_start_module(codegen); - - struct ivy_ast_node *node = ivy_parser_root_node(parser); - struct ivy_ast_node_iterator it = {0}; - struct codegen_args gen_args = { - .args_gen = codegen, - .args_print_ast = show_ast, - }; - - status = ivy_ast_node_iterate(node, &it, node_codegen, &gen_args); - if (status != IVY_OK) { - printf("codegen failed: error %s\n", ivy_status_to_string(status)); - return -1; - } - - ivy_codegen_push_eof(codegen); - - struct mie_module *mod = NULL; - ivy_codegen_end_module(codegen, &mod); - - if (show_ir) { - struct mie_ir_converter *convert - = mie_ir_converter_create(ctx, MIE_IR_MEM, MIE_IR_TEXT); - mie_ir_converter_set_src_value(convert, MIE_VALUE(mod)); - mie_ir_converter_set_dest_file(convert, stdout); - mie_ir_converter_process(convert); - - mie_ir_converter_destroy(convert); - } - - struct mie_select_builder *builder = mie_select_builder_create(ctx); - - b_queue_iterator func_it; - b_queue_foreach (&func_it, &mod->m_func) { - struct mie_value *func_v - = b_unbox(struct mie_value, func_it.entry, v_entry); - struct mie_func *func = (struct mie_func *)func_v; - - b_queue_iterator block_it; - b_queue_foreach (&block_it, &func->f_blocks) { - struct mie_value *block_v = b_unbox( - struct mie_value, block_it.entry, v_entry); - struct mie_block *block = (struct mie_block *)block_v; - - b_queue_iterator instr_it; - b_queue_foreach (&instr_it, &block->b_phi) { - struct mie_value *instr_v = b_unbox( - struct mie_value, instr_it.entry, v_entry); - mie_select_builder_push_instr( - builder, (struct mie_instr *)instr_v); - } - - b_queue_foreach (&instr_it, &block->b_instr) { - struct mie_value *instr_v = b_unbox( - struct mie_value, instr_it.entry, v_entry); - mie_select_builder_push_instr( - builder, (struct mie_instr *)instr_v); - } - - if (block->b_terminator) { - mie_select_builder_push_instr( - builder, block->b_terminator); - } - - struct mie_select_graph *graph - = mie_select_builder_finish(builder); - - if (show_isel_pre) { - printf("%s.%s instruction graph:\n", - func->f_base.v_name.n_str, - block->b_base.v_name.n_str); - mie_select_graph_dump_dot(graph); - mie_select_graph_destroy(graph); - } - } - } - - mie_value_destroy(MIE_VALUE(mod)); - ivy_codegen_destroy(codegen); - - ivy_parser_destroy(parser, NULL); - - return r; +#undef THROW_AND_RETURN + return 0; } static int compile(const b_command *cmd, const b_arglist *args, const b_array *_)