redream/tools/recc/main.c

193 lines
5.1 KiB
C

#include "core/core.h"
#include "core/filesystem.h"
#include "core/option.h"
#include "jit/backend/x64/x64_backend.h"
#include "jit/ir/ir.h"
#include "jit/jit.h"
#include "jit/jit_guest.h"
#include "jit/pass_stats.h"
#include "jit/passes/constant_propagation_pass.h"
#include "jit/passes/control_flow_analysis_pass.h"
#include "jit/passes/dead_code_elimination_pass.h"
#include "jit/passes/expression_simplification_pass.h"
#include "jit/passes/load_store_elimination_pass.h"
#include "jit/passes/register_allocation_pass.h"
DEFINE_OPTION_STRING(pass, "cfa,lse,cprop,esimp,dce,ra",
"Comma-separated list of passes to run");
DEFINE_PASS_STAT(ir_instrs_total, "total ir instructions");
DEFINE_PASS_STAT(ir_instrs_removed, "removed ir instructions");
DEFINE_JIT_CODE_BUFFER(code);
static uint8_t ir_buffer[1024 * 1024];
static int get_num_instrs(const struct ir *ir) {
int n = 0;
list_for_each_entry(block, &ir->blocks, struct ir_block, it) {
list_for_each_entry(instr, &block->instrs, struct ir_instr, it) {
((void)instr);
n++;
}
}
return n;
}
static void sanitize_ir(struct ir *ir) {
list_for_each_entry(block, &ir->blocks, struct ir_block, it) {
list_for_each_entry(instr, &block->instrs, struct ir_instr, it) {
if (instr->op != OP_CALL && instr->op != OP_FALLBACK) {
continue;
}
/* ensure that address are within 2 GB of the code buffer */
uint64_t addr = instr->arg[0]->i64;
addr = (uint64_t)code | (addr & 0x7fffffff);
ir_set_arg0(ir, instr, ir_alloc_i64(ir, addr));
}
}
}
static void process_file(struct jit_backend *backend, const char *filename,
int disable_dumps) {
struct ir ir = {0};
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);
/* sanitize absolute addresses in the ir */
sanitize_ir(&ir);
/* run optimization passes */
char passes[OPTION_MAX_LENGTH];
strncpy(passes, OPTION_pass, sizeof(passes));
int num_instrs_before = get_num_instrs(&ir);
char *name = strtok(passes, ",");
while (name) {
if (!strcmp(name, "cfa")) {
struct cfa *cfa = cfa_create();
cfa_run(cfa, &ir);
cfa_destroy(cfa);
} else if (!strcmp(name, "lse")) {
struct lse *lse = lse_create();
lse_run(lse, &ir);
lse_destroy(lse);
} else if (!strcmp(name, "cprop")) {
struct cprop *cprop = cprop_create();
cprop_run(cprop, &ir);
cprop_destroy(cprop);
} else if (!strcmp(name, "dce")) {
struct dce *dce = dce_create();
dce_run(dce, &ir);
dce_destroy(dce);
} else if (!strcmp(name, "esimp")) {
struct esimp *esimp = esimp_create();
esimp_run(esimp, &ir);
esimp_destroy(esimp);
} else if (!strcmp(name, "ra")) {
struct ra *ra = ra_create(backend->registers, backend->num_registers,
backend->emitters, backend->num_emitters);
ra_run(ra, &ir);
ra_destroy(ra);
} else {
LOG_WARNING("unknown pass %s", name);
}
/* print ir after each pass if requested */
if (!disable_dumps) {
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);
/* assemble backend code */
backend->reset(backend);
uint8_t *host_addr = NULL;
int host_size = 0;
int res =
backend->assemble_code(backend, &ir, &host_addr, &host_size, NULL, NULL);
CHECK(res);
if (!disable_dumps) {
LOG_INFO("===-----------------------------------------------------===");
LOG_INFO("x64 code");
LOG_INFO("===-----------------------------------------------------===");
backend->dump_code(backend, host_addr, host_size, stdout);
LOG_INFO("");
}
/* update stats */
STAT_ir_instrs_total += num_instrs_before;
STAT_ir_instrs_removed += num_instrs_before - num_instrs_after;
}
static void process_dir(struct jit_backend *backend, const char *path) {
DIR *dir = opendir(path);
if (!dir) {
LOG_WARNING("failed to open directory %s", path);
return;
}
struct dirent *ent = NULL;
while ((ent = readdir(dir)) != NULL) {
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(backend, filename, 1);
}
closedir(dir);
}
int main(int argc, char **argv) {
if (!options_parse(&argc, &argv)) {
return EXIT_FAILURE;
}
const char *path = argv[1];
struct jit_guest guest = {0};
guest.addr_mask = 0xff;
struct jit_backend *backend = x64_backend_create(&guest, code, sizeof(code));
if (fs_isfile(path)) {
process_file(backend, path, 0);
} else {
process_dir(backend, path);
}
LOG_INFO("");
pass_stats_dump();
backend->destroy(backend);
return EXIT_SUCCESS;
}