mirror of https://github.com/inolen/redream.git
add emitter stats to recc
This commit is contained in:
parent
37b9f52b6c
commit
f67f5c5b12
|
@ -214,9 +214,10 @@ set(REDREAM_SOURCES
|
|||
src/jit/ir/passes/dead_code_elimination_pass.c
|
||||
src/jit/ir/passes/expression_simplification_pass.c
|
||||
src/jit/ir/passes/load_store_elimination_pass.c
|
||||
src/jit/ir/passes/pass_stat.c
|
||||
src/jit/ir/passes/register_allocation_pass.c
|
||||
src/jit/emit_stats.c
|
||||
src/jit/jit.c
|
||||
src/jit/pass_stats.c
|
||||
src/sys/exception_handler.c
|
||||
src/sys/filesystem.c
|
||||
src/sys/memory.c
|
||||
|
|
|
@ -228,11 +228,16 @@ static void sh4_debug_menu(struct device *dev, struct nk_context *ctx) {
|
|||
jit_invalidate_blocks(sh4->jit);
|
||||
}
|
||||
|
||||
int dumping = jit_is_dumping(sh4->jit);
|
||||
if (!dumping && nk_button_label(ctx, "start dumping blocks")) {
|
||||
jit_toggle_dumping(sh4->jit);
|
||||
} else if (dumping && nk_button_label(ctx, "stop dumping blocks")) {
|
||||
jit_toggle_dumping(sh4->jit);
|
||||
struct jit *jit = sh4->jit;
|
||||
if (!jit->dump_blocks) {
|
||||
if (nk_button_label(ctx, "start dumping blocks")) {
|
||||
jit->dump_blocks = 1;
|
||||
jit_invalidate_blocks(jit);
|
||||
}
|
||||
} else {
|
||||
if (nk_button_label(ctx, "stop dumping blocks")) {
|
||||
jit->dump_blocks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
nk_menu_end(ctx);
|
||||
|
|
|
@ -22,8 +22,7 @@ struct jit_backend {
|
|||
|
||||
void (*reset)(struct jit_backend *base);
|
||||
void *(*assemble_code)(struct jit_backend *base, struct ir *ir, int *size);
|
||||
void (*disassemble_code)(struct jit_backend *base, const uint8_t *code,
|
||||
int size, int dump, int *num_instrs);
|
||||
void (*dump_code)(struct jit_backend *base, const uint8_t *code, int size);
|
||||
|
||||
int (*handle_exception)(struct jit_backend *base, struct exception *ex);
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ extern "C" {
|
|||
#include "jit/backend/jit_backend.h"
|
||||
#include "jit/backend/x64/x64_backend.h"
|
||||
#include "jit/backend/x64/x64_disassembler.h"
|
||||
#include "jit/emit_stats.h"
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/jit.h"
|
||||
#include "sys/exception_handler.h"
|
||||
|
@ -154,11 +155,14 @@ struct x64_backend {
|
|||
int stack_size;
|
||||
Xbyak::CodeGenerator *codegen;
|
||||
|
||||
csh capstone_handle;
|
||||
Xbyak::Label xmm_const[NUM_XMM_CONST];
|
||||
void (*load_thunk[16])();
|
||||
void (*store_thunk)();
|
||||
int num_temps;
|
||||
|
||||
csh capstone_handle;
|
||||
struct ir_instr *last_op;
|
||||
void *last_op_begin;
|
||||
};
|
||||
|
||||
static const Xbyak::Reg x64_backend_register(struct x64_backend *backend,
|
||||
|
@ -279,6 +283,12 @@ static const Xbyak::Address x64_backend_xmm_constant(
|
|||
return e.ptr[e.rip + backend->xmm_const[c]];
|
||||
}
|
||||
|
||||
static void x64_backend_label_name(char *name, size_t size,
|
||||
struct ir_value *v) {
|
||||
/* all ir labels are local labels */
|
||||
snprintf(name, size, ".%s", v->str);
|
||||
}
|
||||
|
||||
static int x64_backend_can_encode_imm(const struct ir_value *v) {
|
||||
if (!ir_is_constant(v)) {
|
||||
return 0;
|
||||
|
@ -287,11 +297,34 @@ static int x64_backend_can_encode_imm(const struct ir_value *v) {
|
|||
return v->type <= VALUE_I32;
|
||||
}
|
||||
|
||||
void *x64_backend_emit(struct x64_backend *backend, struct ir *ir, int *size) {
|
||||
PROF_ENTER("cpu", "x64_backend_emit");
|
||||
static void x64_backend_emit_stats(struct x64_backend *backend,
|
||||
struct ir_instr *op) {
|
||||
if (!backend->base.jit->emit_stats) {
|
||||
return;
|
||||
}
|
||||
|
||||
void *curr = backend->codegen->getCurr<void *>();
|
||||
|
||||
if (backend->last_op) {
|
||||
cs_insn *insns;
|
||||
size_t size = (int)((uint8_t *)curr - (uint8_t *)backend->last_op_begin);
|
||||
size_t count =
|
||||
cs_disasm(backend->capstone_handle, (uint8_t *)backend->last_op_begin,
|
||||
size, 0, 0, &insns);
|
||||
cs_free(insns, count);
|
||||
|
||||
const char *desc = backend->last_op->arg[0]->str;
|
||||
emit_stats_add(desc, count);
|
||||
}
|
||||
|
||||
backend->last_op = op;
|
||||
backend->last_op_begin = curr;
|
||||
}
|
||||
|
||||
static void *x64_backend_emit(struct x64_backend *backend, struct ir *ir,
|
||||
int *size) {
|
||||
auto &e = *backend->codegen;
|
||||
void *fn = (void *)backend->codegen->getCurr();
|
||||
void *code = (void *)backend->codegen->getCurr();
|
||||
|
||||
CHECK_LT(ir->locals_size, backend->stack_size);
|
||||
|
||||
|
@ -301,7 +334,12 @@ void *x64_backend_emit(struct x64_backend *backend, struct ir *ir, int *size) {
|
|||
x64_emit_cb emit = x64_backend_emitters[instr->op];
|
||||
CHECK_NOTNULL(emit);
|
||||
|
||||
// reset temp count used by GetRegister
|
||||
/* track stats for each guest op */
|
||||
if (instr->op == OP_DEBUG_INFO) {
|
||||
x64_backend_emit_stats(backend, instr);
|
||||
}
|
||||
|
||||
/* reset temp count used by x64_backend_get_register */
|
||||
backend->num_temps = 0;
|
||||
|
||||
emit(backend, *backend->codegen, instr);
|
||||
|
@ -309,11 +347,12 @@ void *x64_backend_emit(struct x64_backend *backend, struct ir *ir, int *size) {
|
|||
|
||||
e.outLocalLabel();
|
||||
|
||||
*size = (int)((uint8_t *)backend->codegen->getCurr() - (uint8_t *)fn);
|
||||
*size = (int)((uint8_t *)backend->codegen->getCurr() - (uint8_t *)code);
|
||||
|
||||
PROF_LEAVE();
|
||||
/* flush stats for last op */
|
||||
x64_backend_emit_stats(backend, NULL);
|
||||
|
||||
return fn;
|
||||
return code;
|
||||
}
|
||||
|
||||
static void x64_backend_emit_thunks(struct x64_backend *backend) {
|
||||
|
@ -364,55 +403,6 @@ static void x64_backend_emit_constants(struct x64_backend *backend) {
|
|||
e.dq(INT64_C(0x8000000000000000));
|
||||
}
|
||||
|
||||
static void x64_backend_reset(struct jit_backend *base) {
|
||||
struct x64_backend *backend = container_of(base, struct x64_backend, base);
|
||||
|
||||
backend->codegen->reset();
|
||||
|
||||
x64_backend_emit_thunks(backend);
|
||||
x64_backend_emit_constants(backend);
|
||||
}
|
||||
|
||||
static void *x64_backend_assemble_code(struct jit_backend *base, struct ir *ir,
|
||||
int *size) {
|
||||
struct x64_backend *backend = container_of(base, struct x64_backend, base);
|
||||
|
||||
// try to generate the x64 code. if the code buffer overflows let the backend
|
||||
// know so it can reset the cache and try again
|
||||
void *fn = NULL;
|
||||
|
||||
try {
|
||||
fn = x64_backend_emit(backend, ir, size);
|
||||
} catch (const Xbyak::Error &e) {
|
||||
if (e != Xbyak::ERR_CODE_IS_TOO_BIG) {
|
||||
LOG_FATAL("X64 codegen failure, %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
return fn;
|
||||
}
|
||||
|
||||
static void x64_backend_disassemble_code(struct jit_backend *base,
|
||||
const uint8_t *code, int size,
|
||||
int dump, int *num_instrs) {
|
||||
struct x64_backend *backend = container_of(base, struct x64_backend, base);
|
||||
|
||||
cs_insn *insns;
|
||||
size_t count = cs_disasm(backend->capstone_handle, code, size, 0, 0, &insns);
|
||||
CHECK(count);
|
||||
*num_instrs = count;
|
||||
|
||||
if (dump) {
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
cs_insn &insn = insns[i];
|
||||
LOG_INFO("0x%" PRIx64 ":\t%s\t\t%s", insn.address, insn.mnemonic,
|
||||
insn.op_str);
|
||||
}
|
||||
}
|
||||
|
||||
cs_free(insns, count);
|
||||
}
|
||||
|
||||
static int x64_backend_handle_exception(struct jit_backend *base,
|
||||
struct exception *ex) {
|
||||
struct x64_backend *backend = container_of(base, struct x64_backend, base);
|
||||
|
@ -499,10 +489,53 @@ static int x64_backend_handle_exception(struct jit_backend *base,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void x64_backend_label_name(char *name, size_t size,
|
||||
struct ir_value *v) {
|
||||
/* all ir labels are local labels */
|
||||
snprintf(name, size, ".%s", v->str);
|
||||
static void x64_backend_dump_code(struct jit_backend *base, const uint8_t *code,
|
||||
int size) {
|
||||
struct x64_backend *backend = container_of(base, struct x64_backend, base);
|
||||
|
||||
cs_insn *insns;
|
||||
size_t count = cs_disasm(backend->capstone_handle, code, size, 0, 0, &insns);
|
||||
CHECK(count);
|
||||
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
cs_insn &insn = insns[i];
|
||||
LOG_INFO("0x%" PRIx64 ":\t%s\t\t%s", insn.address, insn.mnemonic,
|
||||
insn.op_str);
|
||||
}
|
||||
|
||||
cs_free(insns, count);
|
||||
}
|
||||
|
||||
static void *x64_backend_assemble_code(struct jit_backend *base, struct ir *ir,
|
||||
int *size) {
|
||||
PROF_ENTER("cpu", "x64_backend_assemble_code");
|
||||
|
||||
struct x64_backend *backend = container_of(base, struct x64_backend, base);
|
||||
|
||||
// try to generate the x64 code. if the code buffer overflows let the backend
|
||||
// know so it can reset the cache and try again
|
||||
void *code = NULL;
|
||||
|
||||
try {
|
||||
code = x64_backend_emit(backend, ir, size);
|
||||
} catch (const Xbyak::Error &e) {
|
||||
if (e != Xbyak::ERR_CODE_IS_TOO_BIG) {
|
||||
LOG_FATAL("X64 codegen failure, %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
PROF_LEAVE();
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
static void x64_backend_reset(struct jit_backend *base) {
|
||||
struct x64_backend *backend = container_of(base, struct x64_backend, base);
|
||||
|
||||
backend->codegen->reset();
|
||||
|
||||
x64_backend_emit_thunks(backend);
|
||||
x64_backend_emit_constants(backend);
|
||||
}
|
||||
|
||||
EMITTER(LOAD) {
|
||||
|
@ -1545,7 +1578,7 @@ EMITTER(LABEL) {
|
|||
}
|
||||
|
||||
EMITTER(BRANCH) {
|
||||
if (instr->arg[0]->type == VALUE_LABEL) {
|
||||
if (instr->arg[0]->type == VALUE_STRING) {
|
||||
char name[128];
|
||||
x64_backend_label_name(name, sizeof(name), instr->arg[0]);
|
||||
e.jmp(name);
|
||||
|
@ -1560,7 +1593,7 @@ EMITTER(BRANCH_FALSE) {
|
|||
|
||||
e.test(cond, cond);
|
||||
|
||||
if (instr->arg[0]->type == VALUE_LABEL) {
|
||||
if (instr->arg[0]->type == VALUE_STRING) {
|
||||
char name[128];
|
||||
x64_backend_label_name(name, sizeof(name), instr->arg[0]);
|
||||
e.jz(name);
|
||||
|
@ -1575,7 +1608,7 @@ EMITTER(BRANCH_TRUE) {
|
|||
|
||||
e.test(cond, cond);
|
||||
|
||||
if (instr->arg[0]->type == VALUE_LABEL) {
|
||||
if (instr->arg[0]->type == VALUE_STRING) {
|
||||
char name[128];
|
||||
x64_backend_label_name(name, sizeof(name), instr->arg[0]);
|
||||
e.jnz(name);
|
||||
|
@ -1634,7 +1667,7 @@ struct jit_backend *x64_backend_create(struct jit *jit, void *code,
|
|||
backend->base.num_registers = array_size(x64_registers);
|
||||
backend->base.reset = &x64_backend_reset;
|
||||
backend->base.assemble_code = &x64_backend_assemble_code;
|
||||
backend->base.disassemble_code = &x64_backend_disassemble_code;
|
||||
backend->base.dump_code = &x64_backend_dump_code;
|
||||
backend->base.handle_exception = &x64_backend_handle_exception;
|
||||
|
||||
backend->code = code;
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
#include "jit/emit_stats.h"
|
||||
#include "core/assert.h"
|
||||
#include "core/math.h"
|
||||
#include "core/string.h"
|
||||
|
||||
#define EMIT_STATS_MAX 512
|
||||
|
||||
struct emit_stat {
|
||||
char name[32];
|
||||
int n;
|
||||
int count;
|
||||
};
|
||||
|
||||
static struct emit_stat stats[EMIT_STATS_MAX];
|
||||
static int num_stats;
|
||||
|
||||
static struct emit_stat *emit_stats_demand(const char *name) {
|
||||
/* this is terribly slow, should really be using a hashtable,
|
||||
but this is currently only used when debugging with recc */
|
||||
for (int i = 0; i < num_stats; i++) {
|
||||
struct emit_stat *stat = &stats[i];
|
||||
if (!strcmp(stat->name, name)) {
|
||||
return stat;
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_LT(num_stats, EMIT_STATS_MAX);
|
||||
struct emit_stat *stat = &stats[num_stats++];
|
||||
strncpy(stat->name, name, sizeof(stat->name));
|
||||
return stat;
|
||||
}
|
||||
|
||||
void emit_stats_add(const char *name, int count) {
|
||||
struct emit_stat *stat = emit_stats_demand(name);
|
||||
stat->count += count;
|
||||
stat->n++;
|
||||
}
|
||||
|
||||
void emit_stats_dump() {
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
LOG_INFO("Emit stats");
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
|
||||
int w = 5; /* TOTAL */
|
||||
int total_n = 0;
|
||||
int total_count = 0;
|
||||
float total_avg = 0.0f;
|
||||
|
||||
for (int i = 0; i < num_stats; i++) {
|
||||
struct emit_stat *stat = &stats[i];
|
||||
int l = (int)strlen(stat->name);
|
||||
w = MAX(l, w);
|
||||
total_n += stat->n;
|
||||
total_count += stat->count;
|
||||
}
|
||||
|
||||
if (total_n) {
|
||||
total_avg = total_count / (float)total_n;
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_stats; i++) {
|
||||
struct emit_stat *stat = &stats[i];
|
||||
float avg = stat->n ? stat->count / (float)stat->n : 0.0f;
|
||||
LOG_INFO("%*s, %9d, %9.2f", w, stat->name, stat->n, avg);
|
||||
}
|
||||
|
||||
LOG_INFO("%*s, %9d, %9.2f", w, "TOTAL", total_n, total_avg);
|
||||
LOG_INFO("");
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef EMIT_STATS_H
|
||||
#define EMIT_STATS_H
|
||||
|
||||
void emit_stats_add(const char *name, int count);
|
||||
void emit_stats_dump();
|
||||
|
||||
#endif
|
|
@ -11,8 +11,8 @@ static void armv3_frontend_translate_code(struct jit_frontend *base,
|
|||
frontend->translate(frontend->data, addr, ir, flags);
|
||||
}
|
||||
|
||||
static void armv3_frontend_disassemble_code(struct jit_frontend *base,
|
||||
uint32_t addr, int size) {
|
||||
static void armv3_frontend_dump_code(struct jit_frontend *base, uint32_t addr,
|
||||
int size) {
|
||||
struct armv3_frontend *frontend = (struct armv3_frontend *)base;
|
||||
struct jit_guest *guest = frontend->jit->guest;
|
||||
|
||||
|
@ -33,7 +33,7 @@ struct jit_frontend *armv3_frontend_create(struct jit *jit) {
|
|||
|
||||
frontend->jit = jit;
|
||||
frontend->translate_code = &armv3_frontend_translate_code;
|
||||
frontend->disassemble_code = &armv3_frontend_disassemble_code;
|
||||
frontend->dump_code = &armv3_frontend_dump_code;
|
||||
|
||||
return (struct jit_frontend *)frontend;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ struct jit_frontend {
|
|||
struct jit *jit;
|
||||
void (*translate_code)(struct jit_frontend *base, uint32_t addr,
|
||||
struct ir *ir, int fastmem, int *size);
|
||||
void (*disassemble_code)(struct jit_frontend *base, uint32_t addr, int size);
|
||||
void (*dump_code)(struct jit_frontend *base, uint32_t addr, int size);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,26 +2,14 @@
|
|||
#include "core/assert.h"
|
||||
#include "core/string.h"
|
||||
|
||||
struct sh4_opdef {
|
||||
enum sh4_op op;
|
||||
const char *desc;
|
||||
const char *sig;
|
||||
int cycles;
|
||||
int flags;
|
||||
uint16_t opcode_mask;
|
||||
uint16_t imm_mask, imm_shift;
|
||||
uint16_t disp_mask, disp_shift;
|
||||
uint16_t rm_mask, rm_shift;
|
||||
uint16_t rn_mask, rn_shift;
|
||||
};
|
||||
static struct sh4_opdef *sh4_opdef_lookup[UINT16_MAX];
|
||||
|
||||
static struct sh4_opdef s_opdefs[NUM_SH4_OPS] = {
|
||||
struct sh4_opdef sh4_opdefs[NUM_SH4_OPS] = {
|
||||
#define SH4_INSTR(name, desc, sig, cycles, flags) \
|
||||
{SH4_OP_##name, desc, #sig, cycles, flags, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
{SH4_OP_##name, #name, desc, #sig, cycles, flags, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
#include "jit/frontend/sh4/sh4_instr.inc"
|
||||
#undef SH4_INSTR
|
||||
};
|
||||
static struct sh4_opdef *s_opdef_lookup[UINT16_MAX];
|
||||
|
||||
static void sh4_arg_mask(const char *instr_code, char c, uint16_t *mask,
|
||||
uint16_t *shift) {
|
||||
|
@ -58,7 +46,7 @@ static void sh4_init_opdefs() {
|
|||
* from signatures
|
||||
*/
|
||||
for (int i = 1 /* skip SH4_OP_INVALID */; i < NUM_SH4_OPS; i++) {
|
||||
struct sh4_opdef *def = &s_opdefs[i];
|
||||
struct sh4_opdef *def = &sh4_opdefs[i];
|
||||
|
||||
sh4_arg_mask(def->sig, 'i', &def->imm_mask, &def->imm_shift);
|
||||
sh4_arg_mask(def->sig, 'd', &def->disp_mask, &def->disp_shift);
|
||||
|
@ -75,12 +63,12 @@ static void sh4_init_opdefs() {
|
|||
uint16_t value = w + x + y + z;
|
||||
|
||||
for (int i = 1 /* skip SH4_OP_INVALID */; i < NUM_SH4_OPS; i++) {
|
||||
struct sh4_opdef *def = &s_opdefs[i];
|
||||
struct sh4_opdef *def = &sh4_opdefs[i];
|
||||
uint16_t arg_mask =
|
||||
def->imm_mask | def->disp_mask | def->rm_mask | def->rn_mask;
|
||||
|
||||
if ((value & ~arg_mask) == def->opcode_mask) {
|
||||
s_opdef_lookup[value] = def;
|
||||
sh4_opdef_lookup[value] = def;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -93,7 +81,7 @@ static void sh4_init_opdefs() {
|
|||
int sh4_disasm(struct sh4_instr *i) {
|
||||
sh4_init_opdefs();
|
||||
|
||||
struct sh4_opdef *def = s_opdef_lookup[i->opcode];
|
||||
struct sh4_opdef *def = sh4_opdef_lookup[i->opcode];
|
||||
|
||||
if (!def) {
|
||||
i->op = SH4_OP_INVALID;
|
||||
|
@ -125,7 +113,7 @@ void sh4_format(const struct sh4_instr *i, char *buffer, size_t buffer_size) {
|
|||
uint32_t pcmask;
|
||||
|
||||
/* copy initial formatted description */
|
||||
snprintf(buffer, buffer_size, "%08x %s", i->addr, s_opdefs[i->op].desc);
|
||||
snprintf(buffer, buffer_size, "%08x %s", i->addr, sh4_opdefs[i->op].desc);
|
||||
|
||||
/* used by mov operators with displacements */
|
||||
if (strnstr(buffer, ".b", buffer_size)) {
|
||||
|
|
|
@ -22,6 +22,20 @@ enum sh4_op {
|
|||
NUM_SH4_OPS,
|
||||
};
|
||||
|
||||
struct sh4_opdef {
|
||||
enum sh4_op op;
|
||||
const char *name;
|
||||
const char *desc;
|
||||
const char *sig;
|
||||
int cycles;
|
||||
int flags;
|
||||
uint16_t opcode_mask;
|
||||
uint16_t imm_mask, imm_shift;
|
||||
uint16_t disp_mask, disp_shift;
|
||||
uint16_t rm_mask, rm_shift;
|
||||
uint16_t rn_mask, rn_shift;
|
||||
};
|
||||
|
||||
struct sh4_instr {
|
||||
uint32_t addr;
|
||||
uint16_t opcode;
|
||||
|
@ -35,6 +49,8 @@ struct sh4_instr {
|
|||
uint16_t imm;
|
||||
};
|
||||
|
||||
extern struct sh4_opdef sh4_opdefs[NUM_SH4_OPS];
|
||||
|
||||
int sh4_disasm(struct sh4_instr *i);
|
||||
void sh4_format(const struct sh4_instr *i, char *buffer, size_t buffer_size);
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@ static void sh4_frontend_translate_code(struct jit_frontend *base,
|
|||
PROF_LEAVE();
|
||||
}
|
||||
|
||||
static void sh4_frontend_disassemble_code(struct jit_frontend *base,
|
||||
uint32_t addr, int size) {
|
||||
static void sh4_frontend_dump_code(struct jit_frontend *base, uint32_t addr,
|
||||
int size) {
|
||||
struct sh4_frontend *frontend = (struct sh4_frontend *)base;
|
||||
struct jit_guest *guest = frontend->jit->guest;
|
||||
|
||||
|
@ -57,7 +57,7 @@ struct jit_frontend *sh4_frontend_create(struct jit *jit) {
|
|||
|
||||
frontend->jit = jit;
|
||||
frontend->translate_code = &sh4_frontend_translate_code;
|
||||
frontend->disassemble_code = &sh4_frontend_disassemble_code;
|
||||
frontend->dump_code = &sh4_frontend_dump_code;
|
||||
|
||||
return (struct jit_frontend *)frontend;
|
||||
}
|
||||
|
|
|
@ -200,7 +200,7 @@ static void ir_branch_guest(struct sh4_frontend *frontend, struct ir *ir,
|
|||
static void ir_branch_false_guest(struct sh4_frontend *frontend, struct ir *ir,
|
||||
struct ir_value *addr,
|
||||
struct ir_value *cond) {
|
||||
struct ir_value *skip = ir_alloc_label(ir, "skip_%p", addr);
|
||||
struct ir_value *skip = ir_alloc_str(ir, "skip_%p", addr);
|
||||
ir_branch_true(ir, skip, cond);
|
||||
ir_store_context(ir, offsetof(struct sh4_ctx, pc), addr);
|
||||
ir_label(ir, skip);
|
||||
|
@ -208,7 +208,7 @@ static void ir_branch_false_guest(struct sh4_frontend *frontend, struct ir *ir,
|
|||
|
||||
static void ir_branch_true_guest(struct sh4_frontend *frontend, struct ir *ir,
|
||||
struct ir_value *addr, struct ir_value *cond) {
|
||||
struct ir_value *skip = ir_alloc_label(ir, "skip_%p", addr);
|
||||
struct ir_value *skip = ir_alloc_str(ir, "skip_%p", addr);
|
||||
ir_branch_false(ir, skip, cond);
|
||||
ir_store_context(ir, offsetof(struct sh4_ctx, pc), addr);
|
||||
ir_label(ir, skip);
|
||||
|
@ -217,8 +217,11 @@ static void ir_branch_true_guest(struct sh4_frontend *frontend, struct ir *ir,
|
|||
void sh4_emit_instr(struct sh4_frontend *frontend, struct ir *ir, int flags,
|
||||
const struct sh4_instr *instr,
|
||||
const struct sh4_instr *delay) {
|
||||
/* emit debug info op for recc metrics */
|
||||
ir_debug_info(ir, instr->addr, ir_alloc_i16(ir, instr->opcode));
|
||||
/* emit extra debug info for recc */
|
||||
if (frontend->jit->dump_blocks) {
|
||||
const char *name = sh4_opdefs[instr->op].name;
|
||||
ir_debug_info(ir, name, instr->addr, instr->opcode);
|
||||
}
|
||||
|
||||
(emit_callbacks[instr->op])(frontend, ir, flags, instr, delay);
|
||||
}
|
||||
|
@ -1503,7 +1506,7 @@ EMITTER(PREF) {
|
|||
struct ir_value *addr = load_gpr(i->Rn, VALUE_I32);
|
||||
struct ir_value *cond = ir_lshr(ir, addr, ir_alloc_i32(ir, 26));
|
||||
cond = ir_cmp_ne(ir, cond, ir_alloc_i32(ir, 0x38));
|
||||
struct ir_value *skip = ir_alloc_label(ir, "skip_%p", cond);
|
||||
struct ir_value *skip = ir_alloc_str(ir, "skip_%p", cond);
|
||||
ir_branch_true(ir, skip, cond);
|
||||
|
||||
struct ir_value *data = ir_alloc_ptr(ir, frontend->data);
|
||||
|
|
|
@ -144,17 +144,13 @@ struct ir_value *ir_alloc_f64(struct ir *ir, double c) {
|
|||
return v;
|
||||
}
|
||||
|
||||
struct ir_value *ir_alloc_ptr(struct ir *ir, void *c) {
|
||||
return ir_alloc_i64(ir, (uint64_t)c);
|
||||
}
|
||||
|
||||
struct ir_value *ir_alloc_label(struct ir *ir, const char *format, ...) {
|
||||
struct ir_value *ir_alloc_str(struct ir *ir, const char *format, ...) {
|
||||
struct ir_value *v = ir_calloc(ir, sizeof(struct ir_value));
|
||||
|
||||
v->type = VALUE_LABEL;
|
||||
v->type = VALUE_STRING;
|
||||
v->reg = NO_REGISTER;
|
||||
|
||||
/* format the label name */
|
||||
/* format the string */
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
|
@ -170,6 +166,10 @@ struct ir_value *ir_alloc_label(struct ir *ir, const char *format, ...) {
|
|||
return v;
|
||||
}
|
||||
|
||||
struct ir_value *ir_alloc_ptr(struct ir *ir, void *c) {
|
||||
return ir_alloc_i64(ir, (uint64_t)c);
|
||||
}
|
||||
|
||||
struct ir_local *ir_alloc_local(struct ir *ir, enum ir_type type) {
|
||||
/* align local to natural size */
|
||||
int type_size = ir_type_size(type);
|
||||
|
@ -765,14 +765,14 @@ struct ir_value *ir_lshd(struct ir *ir, struct ir_value *a,
|
|||
}
|
||||
|
||||
void ir_label(struct ir *ir, struct ir_value *lbl) {
|
||||
CHECK(lbl->type == VALUE_LABEL);
|
||||
CHECK(lbl->type == VALUE_STRING);
|
||||
|
||||
struct ir_instr *instr = ir_append_instr(ir, OP_LABEL, VALUE_V);
|
||||
ir_set_arg0(ir, instr, lbl);
|
||||
}
|
||||
|
||||
void ir_branch(struct ir *ir, struct ir_value *dst) {
|
||||
CHECK(dst->type == VALUE_LABEL || dst->type == VALUE_I64);
|
||||
CHECK(dst->type == VALUE_STRING || dst->type == VALUE_I64);
|
||||
|
||||
struct ir_instr *instr = ir_append_instr(ir, OP_BRANCH, VALUE_V);
|
||||
ir_set_arg0(ir, instr, dst);
|
||||
|
@ -780,7 +780,7 @@ void ir_branch(struct ir *ir, struct ir_value *dst) {
|
|||
|
||||
void ir_branch_false(struct ir *ir, struct ir_value *dst,
|
||||
struct ir_value *cond) {
|
||||
CHECK(dst->type == VALUE_LABEL || dst->type == VALUE_I64);
|
||||
CHECK(dst->type == VALUE_STRING || dst->type == VALUE_I64);
|
||||
|
||||
struct ir_instr *instr = ir_append_instr(ir, OP_BRANCH_FALSE, VALUE_V);
|
||||
ir_set_arg0(ir, instr, dst);
|
||||
|
@ -789,7 +789,7 @@ void ir_branch_false(struct ir *ir, struct ir_value *dst,
|
|||
|
||||
void ir_branch_true(struct ir *ir, struct ir_value *dst,
|
||||
struct ir_value *cond) {
|
||||
CHECK(dst->type == VALUE_LABEL || dst->type == VALUE_I64);
|
||||
CHECK(dst->type == VALUE_STRING || dst->type == VALUE_I64);
|
||||
|
||||
struct ir_instr *instr = ir_append_instr(ir, OP_BRANCH_TRUE, VALUE_V);
|
||||
ir_set_arg0(ir, instr, dst);
|
||||
|
@ -830,8 +830,10 @@ void ir_call_fallback(struct ir *ir, void *fallback, uint32_t addr,
|
|||
ir_set_arg2(ir, instr, ir_alloc_i32(ir, raw_instr));
|
||||
}
|
||||
|
||||
void ir_debug_info(struct ir *ir, uint32_t addr, struct ir_value *data) {
|
||||
void ir_debug_info(struct ir *ir, const char *desc, uint32_t addr,
|
||||
uint32_t raw_instr) {
|
||||
struct ir_instr *instr = ir_append_instr(ir, OP_DEBUG_INFO, VALUE_V);
|
||||
ir_set_arg0(ir, instr, ir_alloc_i32(ir, addr));
|
||||
ir_set_arg1(ir, instr, data);
|
||||
ir_set_arg0(ir, instr, ir_alloc_str(ir, desc));
|
||||
ir_set_arg1(ir, instr, ir_alloc_i32(ir, addr));
|
||||
ir_set_arg2(ir, instr, ir_alloc_i32(ir, raw_instr));
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ enum ir_type {
|
|||
VALUE_F32,
|
||||
VALUE_F64,
|
||||
VALUE_V128,
|
||||
VALUE_LABEL,
|
||||
VALUE_STRING,
|
||||
VALUE_NUM,
|
||||
};
|
||||
|
||||
|
@ -192,8 +192,8 @@ struct ir_value *ir_alloc_i32(struct ir *ir, int32_t c);
|
|||
struct ir_value *ir_alloc_i64(struct ir *ir, int64_t c);
|
||||
struct ir_value *ir_alloc_f32(struct ir *ir, float c);
|
||||
struct ir_value *ir_alloc_f64(struct ir *ir, double c);
|
||||
struct ir_value *ir_alloc_str(struct ir *ir, const char *format, ...);
|
||||
struct ir_value *ir_alloc_ptr(struct ir *ir, void *c);
|
||||
struct ir_value *ir_alloc_label(struct ir *ir, const char *format, ...);
|
||||
struct ir_local *ir_alloc_local(struct ir *ir, enum ir_type type);
|
||||
struct ir_local *ir_reuse_local(struct ir *ir, struct ir_value *offset,
|
||||
enum ir_type type);
|
||||
|
@ -341,6 +341,7 @@ void ir_call_fallback(struct ir *ir, void *fallback, uint32_t addr,
|
|||
uint32_t raw_instr);
|
||||
|
||||
/* debug */
|
||||
void ir_debug_info(struct ir *ir, uint32_t addr, struct ir_value *data);
|
||||
void ir_debug_info(struct ir *ir, const char *desc, uint32_t addr,
|
||||
uint32_t instr);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,7 +24,7 @@ struct ir_parser {
|
|||
};
|
||||
|
||||
static const char *typenames[] = {"", "i8", "i16", "i32", "i64",
|
||||
"f32", "f64", "v128", "lbl"};
|
||||
"f32", "f64", "v128", "str"};
|
||||
static const int num_typenames = sizeof(typenames) / sizeof(typenames[0]);
|
||||
|
||||
static char ir_lex_get(struct ir_parser *p) {
|
||||
|
@ -216,11 +216,9 @@ int ir_parse_value(struct ir_parser *p, struct ir *ir,
|
|||
CHECK_NOTNULL(instr);
|
||||
|
||||
*value = instr->result;
|
||||
} else if (ident[0] == '.') {
|
||||
} else {
|
||||
/* label reference */
|
||||
const char *label = &ident[1];
|
||||
|
||||
*value = ir_alloc_label(ir, "%s", label);
|
||||
*value = ir_alloc_str(ir, ident);
|
||||
}
|
||||
} else if (p->tok == TOK_INTEGER) {
|
||||
switch (type) {
|
||||
|
|
|
@ -25,8 +25,8 @@ static void ir_write_type(enum ir_type type, FILE *output) {
|
|||
case VALUE_V128:
|
||||
fprintf(output, "v128");
|
||||
break;
|
||||
case VALUE_LABEL:
|
||||
fprintf(output, "lbl");
|
||||
case VALUE_STRING:
|
||||
fprintf(output, "str");
|
||||
break;
|
||||
default:
|
||||
LOG_FATAL("Unexpected value type");
|
||||
|
@ -71,8 +71,8 @@ static void ir_write_value(const struct ir_value *value, FILE *output) {
|
|||
double v = value->f64;
|
||||
fprintf(output, "0x%" PRIx64, *(uint64_t *)&v);
|
||||
} break;
|
||||
case VALUE_LABEL: {
|
||||
fprintf(output, ".%s", value->str);
|
||||
case VALUE_STRING: {
|
||||
fprintf(output, "%s", value->str);
|
||||
} break;
|
||||
default:
|
||||
LOG_FATAL("Unexpected value type");
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include "jit/ir/passes/conversion_elimination_pass.h"
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/ir/passes/pass_stat.h"
|
||||
#include "jit/pass_stats.h"
|
||||
|
||||
DEFINE_STAT(sext_removed, "Sign extends eliminated");
|
||||
DEFINE_STAT(zext_removed, "Zero extends eliminated");
|
||||
DEFINE_STAT(trunc_removed, "Truncations eliminated");
|
||||
DEFINE_STAT(sext_removed, "sign extends eliminated");
|
||||
DEFINE_STAT(zext_removed, "zero extends eliminated");
|
||||
DEFINE_STAT(trunc_removed, "truncations eliminated");
|
||||
|
||||
void cve_run(struct ir *ir) {
|
||||
list_for_each_entry_safe(instr, &ir->instrs, struct ir_instr, it) {
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "jit/ir/passes/dead_code_elimination_pass.h"
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/ir/passes/pass_stat.h"
|
||||
#include "jit/pass_stats.h"
|
||||
|
||||
DEFINE_STAT(dead_removed, "Dead instructions eliminated");
|
||||
DEFINE_STAT(dead_removed, "dead instructions eliminated");
|
||||
|
||||
void dce_run(struct ir *ir) {
|
||||
/* iterate in reverse in order to remove groups of dead instructions that
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#include "jit/ir/passes/expression_simplification_pass.h"
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/ir/passes/pass_stat.h"
|
||||
#include "jit/pass_stats.h"
|
||||
|
||||
DEFINE_STAT(zero_properties_removed, "Zero properties removed");
|
||||
DEFINE_STAT(zero_identities_removed, "Zero identities removed");
|
||||
DEFINE_STAT(one_identities_removed, "One identities removed");
|
||||
DEFINE_STAT(bitwise_identities_removed, "Bitwise identities removed");
|
||||
DEFINE_STAT(bitwise_identities_removed, "bitwise identities removed");
|
||||
DEFINE_STAT(zero_properties_removed, "zero properties removed");
|
||||
DEFINE_STAT(zero_identities_removed, "zero identities removed");
|
||||
DEFINE_STAT(one_identities_removed, "one identities removed");
|
||||
|
||||
void esimp_run(struct ir *ir) {
|
||||
list_for_each_entry(instr, &ir->instrs, struct ir_instr, it) {
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#include "jit/ir/passes/load_store_elimination_pass.h"
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/ir/passes/pass_stat.h"
|
||||
#include "jit/pass_stats.h"
|
||||
|
||||
DEFINE_STAT(loads_removed, "Context loads eliminated");
|
||||
DEFINE_STAT(stores_removed, "Context stores eliminated");
|
||||
DEFINE_STAT(loads_removed, "context loads eliminated");
|
||||
DEFINE_STAT(stores_removed, "context stores eliminated");
|
||||
|
||||
#define MAX_OFFSET 16384
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
#include "core/mm_heap.h"
|
||||
#include "jit/backend/jit_backend.h"
|
||||
#include "jit/ir/ir.h"
|
||||
#include "jit/ir/passes/pass_stat.h"
|
||||
#include "jit/pass_stats.h"
|
||||
|
||||
DEFINE_STAT(gprs_spilled, "GPRs spilled");
|
||||
DEFINE_STAT(fprs_spilled, "FPRs spilled");
|
||||
DEFINE_STAT(gprs_spilled, "gprs spilled");
|
||||
DEFINE_STAT(fprs_spilled, "fprs spilled");
|
||||
|
||||
#define MAX_REGISTERS 32
|
||||
|
||||
|
@ -389,7 +389,7 @@ void ra_run(struct ir *ir, const struct jit_register *registers,
|
|||
/* only allocate registers for results, assume constants can always be
|
||||
encoded as immediates or that the backend has registers reserved
|
||||
for storing the constants */
|
||||
if (!result || result->type == VALUE_LABEL) {
|
||||
if (!result) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -319,7 +319,7 @@ void jit_compile_block(struct jit *jit, uint32_t guest_addr) {
|
|||
&guest_size);
|
||||
|
||||
/* dump unoptimized block */
|
||||
if (jit->dump_compiled_blocks) {
|
||||
if (jit->dump_blocks) {
|
||||
jit_dump_block(jit, guest_addr, &ir);
|
||||
}
|
||||
|
||||
|
@ -353,21 +353,6 @@ void jit_compile_block(struct jit *jit, uint32_t guest_addr) {
|
|||
PROF_LEAVE();
|
||||
}
|
||||
|
||||
void jit_toggle_dumping(struct jit *jit) {
|
||||
int enabled = !jit->dump_compiled_blocks;
|
||||
|
||||
if (enabled) {
|
||||
/* invalidate current blocks so they recompile and dump on the next run */
|
||||
jit_invalidate_blocks(jit);
|
||||
}
|
||||
|
||||
jit->dump_compiled_blocks = enabled;
|
||||
}
|
||||
|
||||
int jit_is_dumping(struct jit *jit) {
|
||||
return jit->dump_compiled_blocks;
|
||||
}
|
||||
|
||||
static int jit_handle_exception(void *data, struct exception *ex) {
|
||||
struct jit *jit = data;
|
||||
|
||||
|
|
|
@ -45,11 +45,14 @@ struct jit {
|
|||
struct rb_tree blocks;
|
||||
struct rb_tree reverse_blocks;
|
||||
|
||||
/* debug flag for dumping blocks as they are compiled */
|
||||
int dump_compiled_blocks;
|
||||
|
||||
/* compiled block perf map */
|
||||
FILE *perf_map;
|
||||
|
||||
/* dump ir to application directory as blocks compile */
|
||||
int dump_blocks;
|
||||
|
||||
/* track emitter stats as blocks compile */
|
||||
int emit_stats;
|
||||
};
|
||||
|
||||
struct jit *jit_create(const char *tag);
|
||||
|
@ -58,9 +61,6 @@ void jit_destroy(struct jit *jit);
|
|||
int jit_init(struct jit *jit, struct jit_guest *guest,
|
||||
struct jit_frontend *frontend, struct jit_backend *backend);
|
||||
|
||||
int jit_is_dumping(struct jit *jit);
|
||||
void jit_toggle_dumping(struct jit *jit);
|
||||
|
||||
void jit_compile_block(struct jit *jit, uint32_t guest_addr);
|
||||
void jit_add_edge(struct jit *jit, void *code, uint32_t dst);
|
||||
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
#include "jit/ir/passes/pass_stat.h"
|
||||
#include "jit/pass_stats.h"
|
||||
#include "core/assert.h"
|
||||
#include "core/math.h"
|
||||
#include "core/string.h"
|
||||
|
||||
static struct list stats;
|
||||
|
||||
void pass_stat_register(struct pass_stat *stat) {
|
||||
void pass_stats_register(struct pass_stat *stat) {
|
||||
list_add(&stats, &stat->it);
|
||||
}
|
||||
|
||||
void pass_stat_unregister(struct pass_stat *stat) {
|
||||
void pass_stats_unregister(struct pass_stat *stat) {
|
||||
list_remove(&stats, &stat->it);
|
||||
}
|
||||
|
||||
void pass_stat_print_all() {
|
||||
void pass_stats_dump() {
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
LOG_INFO("Pass stats");
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
|
@ -27,4 +27,6 @@ void pass_stat_print_all() {
|
|||
list_for_each_entry(stat, &stats, struct pass_stat, it) {
|
||||
LOG_INFO("%-*s %d", w, stat->desc, *stat->n);
|
||||
}
|
||||
|
||||
LOG_INFO("");
|
||||
}
|
|
@ -8,10 +8,10 @@
|
|||
static int STAT_##name; \
|
||||
static struct pass_stat STAT_T_##name = {#name, desc, &STAT_##name, {0}}; \
|
||||
CONSTRUCTOR(STAT_REGISTER_##name) { \
|
||||
pass_stat_register(&STAT_T_##name); \
|
||||
pass_stats_register(&STAT_T_##name); \
|
||||
} \
|
||||
DESTRUCTOR(STAT_UNREGISTER_##name) { \
|
||||
pass_stat_unregister(&STAT_T_##name); \
|
||||
pass_stats_unregister(&STAT_T_##name); \
|
||||
}
|
||||
|
||||
struct pass_stat {
|
||||
|
@ -21,8 +21,8 @@ struct pass_stat {
|
|||
struct list_node it;
|
||||
};
|
||||
|
||||
void pass_stat_register(struct pass_stat *stat);
|
||||
void pass_stat_unregister(struct pass_stat *stat);
|
||||
void pass_stat_print_all();
|
||||
void pass_stats_register(struct pass_stat *stat);
|
||||
void pass_stats_unregister(struct pass_stat *stat);
|
||||
void pass_stats_dump();
|
||||
|
||||
#endif
|
|
@ -1,27 +1,24 @@
|
|||
#include "core/log.h"
|
||||
#include "core/option.h"
|
||||
#include "jit/backend/x64/x64_backend.h"
|
||||
#include "jit/frontend/sh4/sh4_frontend.h"
|
||||
#include "jit/emit_stats.h"
|
||||
#include "jit/frontend/sh4/sh4_disasm.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/expression_simplification_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 "jit/jit.h"
|
||||
#include "jit/pass_stats.h"
|
||||
#include "sys/filesystem.h"
|
||||
|
||||
DEFINE_OPTION_INT(help, 0, "Show help");
|
||||
DEFINE_OPTION_STRING(pass, "lse,cve,esimp,dce,ra",
|
||||
"Comma-separated list of passes to run");
|
||||
DEFINE_OPTION_INT(stats, 1, "Print pass stats");
|
||||
DEFINE_OPTION_INT(print_after_all, 1, "Print IR after each pass");
|
||||
|
||||
DEFINE_STAT(guest_instrs, "Guest instructions");
|
||||
DEFINE_STAT(host_instrs, "Host instructions");
|
||||
DEFINE_STAT(ir_instrs, "IR instructions");
|
||||
DEFINE_STAT(ir_instrs_removed, "IR instructions removed");
|
||||
DEFINE_STAT(ir_instrs_total, "total ir instructions");
|
||||
DEFINE_STAT(ir_instrs_removed, "removed ir instructions");
|
||||
|
||||
static uint8_t ir_buffer[1024 * 1024];
|
||||
static uint8_t code[1024 * 1024];
|
||||
|
@ -70,14 +67,6 @@ static void process_file(struct jit *jit, const char *filename,
|
|||
/* sanitize absolute addresses in the ir */
|
||||
sanitize_ir(&ir);
|
||||
|
||||
/* calculate number of guest instructions */
|
||||
int guest_num_instrs = 0;
|
||||
list_for_each_entry(instr, &ir.instrs, struct ir_instr, it) {
|
||||
if (instr->op == OP_DEBUG_INFO) {
|
||||
guest_num_instrs++;
|
||||
}
|
||||
}
|
||||
|
||||
/* run optimization passes */
|
||||
char passes[MAX_OPTION_LENGTH];
|
||||
strncpy(passes, OPTION_pass, sizeof(passes));
|
||||
|
@ -101,7 +90,7 @@ static void process_file(struct jit *jit, const char *filename,
|
|||
}
|
||||
|
||||
/* print ir after each pass if requested */
|
||||
if (!disable_dumps && OPTION_print_after_all) {
|
||||
if (!disable_dumps) {
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
LOG_INFO("IR after %s", name);
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
|
@ -114,14 +103,8 @@ static void process_file(struct jit *jit, const char *filename,
|
|||
|
||||
int num_instrs_after = get_num_instrs(&ir);
|
||||
|
||||
/* print out the final ir */
|
||||
if (!disable_dumps && !OPTION_print_after_all) {
|
||||
ir_write(&ir, stdout);
|
||||
}
|
||||
|
||||
/* assemble backend code */
|
||||
int host_size = 0;
|
||||
int host_num_instrs = 0;
|
||||
uint8_t *host_code = NULL;
|
||||
|
||||
jit->backend->reset(jit->backend);
|
||||
|
@ -131,17 +114,12 @@ static void process_file(struct jit *jit, const char *filename,
|
|||
LOG_INFO("===-----------------------------------------------------===");
|
||||
LOG_INFO("X64 code");
|
||||
LOG_INFO("===-----------------------------------------------------===");
|
||||
jit->backend->disassemble_code(jit->backend, host_code, host_size, 1,
|
||||
&host_num_instrs);
|
||||
} else {
|
||||
jit->backend->disassemble_code(jit->backend, host_code, host_size, 0,
|
||||
&host_num_instrs);
|
||||
jit->backend->dump_code(jit->backend, host_code, host_size);
|
||||
LOG_INFO("");
|
||||
}
|
||||
|
||||
/* update stats */
|
||||
STAT_guest_instrs += guest_num_instrs;
|
||||
STAT_host_instrs += host_num_instrs;
|
||||
STAT_ir_instrs += num_instrs_before;
|
||||
STAT_ir_instrs_total += num_instrs_before;
|
||||
STAT_ir_instrs_removed += num_instrs_before - num_instrs_after;
|
||||
}
|
||||
|
||||
|
@ -185,6 +163,7 @@ int main(int argc, char **argv) {
|
|||
/* initailize jit, stubbing out guest interfaces that are used during
|
||||
assembly to a valid address */
|
||||
struct jit *jit = jit_create("recc");
|
||||
jit->emit_stats = 1;
|
||||
|
||||
struct jit_guest guest = {0};
|
||||
guest.r8 = (void *)code;
|
||||
|
@ -205,9 +184,9 @@ int main(int argc, char **argv) {
|
|||
process_dir(jit, path);
|
||||
}
|
||||
|
||||
if (OPTION_stats) {
|
||||
pass_stat_print_all();
|
||||
}
|
||||
LOG_INFO("");
|
||||
emit_stats_dump();
|
||||
pass_stats_dump();
|
||||
|
||||
jit_destroy(jit);
|
||||
x64_backend_destroy(backend);
|
||||
|
|
Loading…
Reference in New Issue