mirror of https://github.com/inolen/redream.git
updated recc
This commit is contained in:
parent
28650d1914
commit
a68084ffa0
|
@ -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))")
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
struct ir;
|
||||
|
||||
extern const char *cve_name;
|
||||
|
||||
void cve_run(struct ir *ir);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
struct ir;
|
||||
|
||||
extern const char *dce_name;
|
||||
|
||||
void dce_run(struct ir *ir);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
|
||||
struct ir;
|
||||
|
||||
extern const char *lse_name;
|
||||
|
||||
void lse_run(struct ir *ir);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
141
tools/recc.cc
141
tools/recc.cc
|
@ -1,141 +0,0 @@
|
|||
#include <gflags/gflags.h>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#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<std::string> split(const std::string &s, char delim) {
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
std::vector<std::string> 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<std::string> passes = split(FLAGS_pass, ',');
|
||||
for (auto name : passes) {
|
||||
std::unique_ptr<Pass> pass;
|
||||
|
||||
if (name == LoadStoreEliminationPass::NAME) {
|
||||
pass = std::unique_ptr<Pass>(new LoadStoreEliminationPass());
|
||||
} else if (name == ConversionEliminationPass::NAME) {
|
||||
pass = std::unique_ptr<Pass>(new ConversionEliminationPass());
|
||||
} else if (name == DeadCodeEliminationPass::NAME) {
|
||||
pass = std::unique_ptr<Pass>(new DeadCodeEliminationPass());
|
||||
} else if (name == RegisterAllocationPass::NAME) {
|
||||
pass = std::unique_ptr<Pass>(
|
||||
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;
|
||||
}
|
Loading…
Reference in New Issue