diff --git a/CMakeLists.txt b/CMakeLists.txt index 9844a8ba..af720eff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -247,7 +247,7 @@ endif() #-------------------------------------------------- # tools #-------------------------------------------------- -set(RECC_SOURCES tools/recc.cc) +set(RECC_SOURCES tools/recc.c) foreach(file ${REDREAM_SOURCES}) if(file MATCHES "(deps|src/(core|jit|sys))") diff --git a/src/jit/backend/x64/x64_backend.h b/src/jit/backend/x64/x64_backend.h index 55ed9010..836631aa 100644 --- a/src/jit/backend/x64/x64_backend.h +++ b/src/jit/backend/x64/x64_backend.h @@ -1,8 +1,10 @@ #ifndef X64_BACKEND_H #define X64_BACKEND_H -struct jit_backend; -struct mem_interface; +#include "jit/backend/backend.h" + +extern const struct register_def x64_registers[]; +extern const int x64_num_registers; struct jit_backend *x64_backend_create(const struct mem_interface *memif); void x64_backend_destroy(struct jit_backend *b); diff --git a/src/jit/ir/ir.h b/src/jit/ir/ir.h index 86679d14..714b3fcc 100644 --- a/src/jit/ir/ir.h +++ b/src/jit/ir/ir.h @@ -173,7 +173,7 @@ static inline bool ir_is_vector(enum ir_type type) { return type == VALUE_V128; } -bool ir_read(FILE *input, struct ir *ir); +int ir_read(FILE *input, struct ir *ir); void ir_write(struct ir *ir, FILE *output); struct ir_instr *ir_append_instr(struct ir *ir, enum ir_op op, diff --git a/src/jit/ir/ir_read.c b/src/jit/ir/ir_read.c index 757e8c10..4b04f9a4 100644 --- a/src/jit/ir/ir_read.c +++ b/src/jit/ir/ir_read.c @@ -145,10 +145,10 @@ static void ir_lex_next(struct ir_parser *p) { return; } -bool ir_parse_type(struct ir_parser *p, struct ir *ir, enum ir_type *type) { +int ir_parse_type(struct ir_parser *p, struct ir *ir, enum ir_type *type) { if (p->tok != TOK_TYPE) { LOG_INFO("Unexpected token %d when parsing type", p->tok); - return false; + return 0; } // eat token @@ -156,13 +156,13 @@ bool ir_parse_type(struct ir_parser *p, struct ir *ir, enum ir_type *type) { *type = p->val.ty; - return true; + return 1; } -bool ir_parse_op(struct ir_parser *p, struct ir *ir, enum ir_op *op) { +int ir_parse_op(struct ir_parser *p, struct ir *ir, enum ir_op *op) { if (p->tok != TOK_IDENTIFIER) { LOG_INFO("Unexpected token %d when parsing op", p->tok); - return false; + return 0; } const char *op_str = p->val.s; @@ -177,7 +177,7 @@ bool ir_parse_op(struct ir_parser *p, struct ir *ir, enum ir_op *op) { if (i == NUM_OPS) { LOG_INFO("Unexpected op '%s'", op_str); - return false; + return 0; } // eat token @@ -185,15 +185,15 @@ bool ir_parse_op(struct ir_parser *p, struct ir *ir, enum ir_op *op) { *op = (enum ir_op)i; - return true; + return 1; } -bool ir_parse_value(struct ir_parser *p, struct ir *ir, - struct ir_value **value) { +int ir_parse_value(struct ir_parser *p, struct ir *ir, + struct ir_value **value) { // parse value type enum ir_type type; if (!ir_parse_type(p, ir, &type)) { - return false; + return 0; } // parse value @@ -201,7 +201,7 @@ bool ir_parse_value(struct ir_parser *p, struct ir *ir, const char *ident = p->val.s; if (ident[0] != '%') { - return false; + return 0; } // lookup the slot slowly @@ -248,21 +248,21 @@ bool ir_parse_value(struct ir_parser *p, struct ir *ir, break; } } else { - return false; + return 0; } // eat token ir_lex_next(p); - return true; + return 1; } -bool ir_parse_operator(struct ir_parser *p, struct ir *ir) { +int ir_parse_operator(struct ir_parser *p, struct ir *ir) { const char *op_str = p->val.s; if (strcmp(op_str, "=")) { LOG_INFO("Unexpected operator '%s'", op_str); - return false; + return 0; } // eat token @@ -270,10 +270,10 @@ bool ir_parse_operator(struct ir_parser *p, struct ir *ir) { // nothing to do, there's only one operator token - return true; + return 1; } -bool ir_parse_instr(struct ir_parser *p, struct ir *ir) { +int ir_parse_instr(struct ir_parser *p, struct ir *ir) { int slot = -1; enum ir_type type = VALUE_V; struct ir_value *arg[3] = {}; @@ -281,31 +281,31 @@ bool ir_parse_instr(struct ir_parser *p, struct ir *ir) { // parse result type and slot number if (p->tok == TOK_TYPE) { if (!ir_parse_type(p, ir, &type)) { - return false; + return 0; } const char *ident = p->val.s; if (ident[0] != '%') { - return false; + return 0; } slot = atoi(&ident[1]); ir_lex_next(p); if (!ir_parse_operator(p, ir)) { - return false; + return 0; } } // parse op enum ir_op op; if (!ir_parse_op(p, ir, &op)) { - return false; + return 0; } // parse arguments for (int i = 0; i < 3; i++) { if (!ir_parse_value(p, ir, &arg[i])) { - return false; + return 0; } if (p->tok != TOK_COMMA) { @@ -325,14 +325,14 @@ bool ir_parse_instr(struct ir_parser *p, struct ir *ir) { instr->tag = slot; - return true; + return 1; } -bool ir_read(FILE *input, struct ir *ir) { +int ir_read(FILE *input, struct ir *ir) { struct ir_parser p = {}; p.input = input; - while (true) { + while (1) { ir_lex_next(&p); if (p.tok == TOK_EOF) { @@ -340,9 +340,9 @@ bool ir_read(FILE *input, struct ir *ir) { } if (!ir_parse_instr(&p, ir)) { - return false; + return 0; } } - return true; + return 1; } diff --git a/src/jit/ir/ir_write.c b/src/jit/ir/ir_write.c index 40554690..7bc27f5a 100644 --- a/src/jit/ir/ir_write.c +++ b/src/jit/ir/ir_write.c @@ -89,7 +89,7 @@ static void ir_write_instr(const struct ir_instr *instr, FILE *output) { fprintf(output, " "); // print each argument - bool need_comma = false; + int need_comma = 0; for (int i = 0; i < 3; i++) { const struct ir_value *arg = instr->arg[i]; @@ -100,12 +100,12 @@ static void ir_write_instr(const struct ir_instr *instr, FILE *output) { if (need_comma) { fprintf(output, ", "); - need_comma = false; + need_comma = 0; } ir_write_value(arg, output); - need_comma = true; + need_comma = 1; } // fprintf(output, "[tag %" PRId64 ", reg %d]", instr->tag, instr->reg); diff --git a/src/jit/ir/passes/conversion_elimination_pass.h b/src/jit/ir/passes/conversion_elimination_pass.h index f89ab5a8..cfc6788d 100644 --- a/src/jit/ir/passes/conversion_elimination_pass.h +++ b/src/jit/ir/passes/conversion_elimination_pass.h @@ -3,8 +3,6 @@ struct ir; -extern const char *cve_name; - void cve_run(struct ir *ir); #endif diff --git a/src/jit/ir/passes/dead_code_elimination_pass.h b/src/jit/ir/passes/dead_code_elimination_pass.h index 21d2549e..86ab1f55 100644 --- a/src/jit/ir/passes/dead_code_elimination_pass.h +++ b/src/jit/ir/passes/dead_code_elimination_pass.h @@ -3,8 +3,6 @@ struct ir; -extern const char *dce_name; - void dce_run(struct ir *ir); #endif diff --git a/src/jit/ir/passes/load_store_elimination_pass.h b/src/jit/ir/passes/load_store_elimination_pass.h index 389c6dd3..66bc9b40 100644 --- a/src/jit/ir/passes/load_store_elimination_pass.h +++ b/src/jit/ir/passes/load_store_elimination_pass.h @@ -3,8 +3,6 @@ struct ir; -extern const char *lse_name; - void lse_run(struct ir *ir); #endif diff --git a/src/jit/ir/passes/register_allocation_pass.h b/src/jit/ir/passes/register_allocation_pass.h index ebf07d6a..abc5cfc5 100644 --- a/src/jit/ir/passes/register_allocation_pass.h +++ b/src/jit/ir/passes/register_allocation_pass.h @@ -4,8 +4,6 @@ struct ir; struct register_def; -extern const char *ra_name; - void ra_run(struct ir *ir, const struct register_def *registers, int num_registers); diff --git a/tools/recc.c b/tools/recc.c new file mode 100644 index 00000000..655308be --- /dev/null +++ b/tools/recc.c @@ -0,0 +1,135 @@ +#include "core/log.h" +#include "core/option.h" +#include "jit/backend/x64/x64_backend.h" +#include "jit/frontend/sh4/sh4_frontend.h" +#include "jit/ir/ir.h" +#include "jit/ir/passes/conversion_elimination_pass.h" +#include "jit/ir/passes/dead_code_elimination_pass.h" +#include "jit/ir/passes/load_store_elimination_pass.h" +#include "jit/ir/passes/pass_stat.h" +#include "jit/ir/passes/register_allocation_pass.h" +#include "sys/filesystem.h" + +DEFINE_OPTION_BOOL(help, false, "Show help"); +DEFINE_OPTION_STRING(pass, "lse,cve,dce,ra", + "Comma-separated list of passes to run"); +DEFINE_OPTION_BOOL(print_after_all, true, "Print IR after each pass"); +DEFINE_OPTION_BOOL(stats, true, "Display pass stats"); + +DEFINE_STAT(num_instrs, "Total number of instructions"); +DEFINE_STAT(num_instrs_removed, "Number of instructions removed"); + +static uint8_t ir_buffer[1024 * 1024]; + +static int get_num_instrs(const struct ir *ir) { + int n = 0; + + list_for_each_entry(instr, &ir->instrs, struct ir_instr, it) { + ((void)instr); + n++; + } + + return n; +} + +static void process_file(const char *filename, bool disable_ir_dump) { + struct ir ir = {}; + ir.buffer = ir_buffer; + ir.capacity = sizeof(ir_buffer); + + // read in the input ir + FILE *input = fopen(filename, "r"); + CHECK(input); + int r = ir_read(input, &ir); + fclose(input); + CHECK(r); + + int num_instrs_before = get_num_instrs(&ir); + + // run optimization passes + char passes[MAX_OPTION_LENGTH]; + strncpy(passes, OPTION_pass, sizeof(passes)); + + char *name = strtok(passes, ","); + while (name) { + if (!strcmp(name, "lse")) { + lse_run(&ir); + } else if (!strcmp(name, "cve")) { + cve_run(&ir); + } else if (!strcmp(name, "dce")) { + dce_run(&ir); + } else if (!strcmp(name, "ra")) { + ra_run(&ir, x64_registers, x64_num_registers); + } else { + LOG_WARNING("Unknown pass %s", name); + } + + // print IR after each pass if requested + if (!disable_ir_dump && OPTION_print_after_all) { + LOG_INFO("===-----------------------------------------------------==="); + LOG_INFO("IR after %s", name); + LOG_INFO("===-----------------------------------------------------==="); + ir_write(&ir, stdout); + LOG_INFO(""); + } + + name = strtok(NULL, ","); + } + + int num_instrs_after = get_num_instrs(&ir); + + // print out the final IR + if (!disable_ir_dump && !OPTION_print_after_all) { + ir_write(&ir, stdout); + } + + STAT_num_instrs += num_instrs_before; + STAT_num_instrs_removed += num_instrs_before - num_instrs_after; +} + +static void process_dir(const char *path) { + DIR *dir = opendir(path); + + if (dir) { + struct dirent *ent = readdir(dir); + + while (ent) { + if (!(ent->d_type & DT_REG)) { + continue; + } + + char filename[PATH_MAX]; + snprintf(filename, sizeof(filename), "%s" PATH_SEPARATOR "%s", path, + ent->d_name); + + LOG_INFO("processing %s", filename); + + process_file(filename, true); + } + + closedir(dir); + } +} + +int main(int argc, char **argv) { + options_parse(&argc, &argv); + + if (OPTION_help) { + options_print_help(); + return EXIT_SUCCESS; + } + + const char *path = argv[1]; + + if (fs_isfile(path)) { + process_file(path, false); + } else { + process_dir(path); + } + + if (OPTION_stats) { + pass_stat_print_all(); + } + + return EXIT_SUCCESS; +} diff --git a/tools/recc.cc b/tools/recc.cc deleted file mode 100644 index 9f184b4a..00000000 --- a/tools/recc.cc +++ /dev/null @@ -1,141 +0,0 @@ -#include -#include -#include -#include -#include -#include "jit/backend/x64/x64_backend.h" -#include "jit/frontend/sh4/sh4_frontend.h" -#include "jit/ir/ir_builder.h" -#include "jit/ir/ir_reader.h" -#include "jit/ir/passes/conversion_elimination_pass.h" -#include "jit/ir/passes/dead_code_elimination_pass.h" -#include "jit/ir/passes/load_store_elimination_pass.h" -#include "jit/ir/passes/register_allocation_pass.h" -#include "sys/filesystem.h" - -using namespace re; -using namespace re::jit::backend; -using namespace re::jit::backend::x64; -using namespace re::jit::ir; -using namespace re::jit::ir::passes; -using namespace re::sys; - -DEFINE_string(pass, "lse,cve,dce,ra", "Comma-separated list of passes to run"); -DEFINE_bool(print_after_all, true, "Print IR after each pass"); -DEFINE_bool(stats, true, "Display pass stats"); - -DEFINE_STAT(num_instrs, "Total number of instructions"); -DEFINE_STAT(num_instrs_removed, "Number of instructions removed"); - -static std::vector split(const std::string &s, char delim) { - std::stringstream ss(s); - std::string item; - std::vector elems; - while (std::getline(ss, item, delim)) { - elems.push_back(std::move(item)); - } - return elems; -} - -static int get_num_instrs(IRBuilder &builder) { - int n = 0; - - for (auto instr : builder.instrs()) { - ((void)instr); - n++; - } - - return n; -} - -static void process_file(const char *filename, bool disable_ir_dump) { - Arena arena(4096); - IRBuilder builder(arena); - - // read in the input ir - IRReader reader; - std::ifstream input_stream(filename); - CHECK(reader.Parse(input_stream, builder)); - - int num_instrs_before = get_num_instrs(builder); - - // run optimization passes - std::vector passes = split(FLAGS_pass, ','); - for (auto name : passes) { - std::unique_ptr pass; - - if (name == LoadStoreEliminationPass::NAME) { - pass = std::unique_ptr(new LoadStoreEliminationPass()); - } else if (name == ConversionEliminationPass::NAME) { - pass = std::unique_ptr(new ConversionEliminationPass()); - } else if (name == DeadCodeEliminationPass::NAME) { - pass = std::unique_ptr(new DeadCodeEliminationPass()); - } else if (name == RegisterAllocationPass::NAME) { - pass = std::unique_ptr( - new RegisterAllocationPass(x64_registers, x64_num_registers)); - } else { - LOG_WARNING("Unknown pass %s", name.c_str()); - } - pass->Run(builder); - - // print IR after each pass if requested - if (!disable_ir_dump && FLAGS_print_after_all) { - LOG_INFO("===-----------------------------------------------------==="); - LOG_INFO("IR after %s", pass->name()); - LOG_INFO("===-----------------------------------------------------==="); - builder.Dump(); - LOG_INFO(""); - } - } - - int num_instrs_after = get_num_instrs(builder); - - // print out the final IR - if (!disable_ir_dump && !FLAGS_print_after_all) { - builder.Dump(); - LOG_INFO(""); - } - - num_instrs += num_instrs_before; - num_instrs_removed += num_instrs_before - num_instrs_after; -} - -static void process_dir(const char *path) { - if (DIR *dir = opendir(path)) { - while (struct dirent *ent = readdir(dir)) { - if (!(ent->d_type & DT_REG)) { - continue; - } - - char filename[PATH_MAX]; - snprintf(filename, sizeof(filename), "%s" PATH_SEPARATOR "%s", path, - ent->d_name); - - LOG_INFO("processing %s", filename); - - process_file(filename, true); - } - - closedir(dir); - } -} - -int main(int argc, char **argv) { - google::ParseCommandLineFlags(&argc, &argv, true); - - const char *path = argv[1]; - - if (IsFile(path)) { - process_file(path, false); - } else { - process_dir(path); - } - - if (FLAGS_stats) { - DumpStats(); - } - - google::ShutDownCommandLineFlags(); - - return 0; -}