added frontend code size stats to recc

This commit is contained in:
Anthony Pesch 2016-12-15 22:09:38 -08:00
parent 3cb36fc6c4
commit 162bfce38f
6 changed files with 63 additions and 38 deletions

View File

@ -1609,6 +1609,8 @@ EMITTER(CALL_FALLBACK) {
e.call(fallback);
}
EMITTER(DEBUG_INFO) {}
void x64_backend_destroy(struct jit_backend *jit_backend) {
struct x64_backend *backend = (struct x64_backend *)jit_backend;

View File

@ -218,6 +218,9 @@ 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_callbacks[instr->op])(frontend, ir, flags, instr, delay);
}

View File

@ -21,7 +21,7 @@ static struct ir_instr *ir_alloc_instr(struct ir *ir, enum ir_op op) {
instr->op = op;
// initialize use links
/* initialize use links */
for (int i = 0; i < MAX_INSTR_ARGS; i++) {
struct ir_use *use = &instr->used[i];
use->instr = instr;
@ -43,7 +43,7 @@ struct ir_instr *ir_append_instr(struct ir *ir, enum ir_op op,
enum ir_type result_type) {
struct ir_instr *instr = ir_alloc_instr(ir, op);
// allocate result if needed
/* allocate result if needed */
if (result_type != VALUE_V) {
struct ir_value *result = ir_calloc(ir, sizeof(struct ir_value));
result->type = result_type;
@ -60,7 +60,7 @@ struct ir_instr *ir_append_instr(struct ir *ir, enum ir_op op,
}
void ir_remove_instr(struct ir *ir, struct ir_instr *instr) {
// remove arguments from the use lists of their values
/* remove arguments from the use lists of their values */
for (int i = 0; i < MAX_INSTR_ARGS; i++) {
struct ir_value *value = instr->arg[i];
@ -167,7 +167,7 @@ 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) {
// align local to natural size
/* align local to natural size */
int type_size = ir_type_size(type);
ir->locals_size = align_up(ir->locals_size, type_size);
@ -218,8 +218,8 @@ void ir_replace_use(struct ir_use *use, struct ir_value *other) {
}
}
// replace all uses of v with other
void ir_replace_uses(struct ir_value *v, struct ir_value *other) {
/* replace all uses of v with other */
CHECK_NE(v, other);
list_for_each_entry_safe(use, &v->uses, struct ir_use, it) {
@ -825,3 +825,9 @@ void ir_call_fallback(struct ir *ir, void *fallback, uint32_t addr,
ir_set_arg1(ir, instr, ir_alloc_i32(ir, 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) {
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);
}

View File

@ -41,16 +41,16 @@ enum ir_cmp {
struct ir_value;
struct ir_instr;
// use is a layer of indirection between an instruction and the values it uses
// as arguments. this indirection makes it possible to maintain a list for each
// value of the arguments that reference it
/* use is a layer of indirection between an instruction and the values it uses
as arguments. this indirection makes it possible to maintain a list for each
value of the arguments that reference it */
struct ir_use {
// the instruction that's using the value
/* the instruction that's using the value */
struct ir_instr *instr;
// pointer to the argument that's using the value. this is used to substitute
// a new value for the argument in the case that the original value is
// removed (e.g. due to constant propagation)
/* pointer to the argument that's using the value. this is used to substitute
a new value for the argument in the case that the original value is
removed (e.g. due to constant propagation) */
struct ir_value **parg;
struct list_node it;
@ -69,16 +69,16 @@ struct ir_value {
char *str;
};
// instruction that defines this value (non-constant values)
/* instruction that defines this value (non-constant values) */
struct ir_instr *def;
// instructions that use this value as an argument
/* instructions that use this value as an argument */
struct list uses;
// host register allocated for this value
/* host register allocated for this value */
int reg;
// generic meta data used by optimization passes
/* generic meta data used by optimization passes */
intptr_t tag;
};
@ -87,24 +87,24 @@ struct ir_value {
struct ir_instr {
enum ir_op op;
// values used by each argument. note, the argument / use is split into two
// separate members to ease reading the argument value (instr->arg[0] vs
// instr->arg[0].value)
/* values used by each argument. note, the argument / use is split into two
separate members to ease reading the argument value (instr->arg[0] vs
instr->arg[0].value) */
struct ir_value *arg[MAX_INSTR_ARGS];
struct ir_use used[MAX_INSTR_ARGS];
// result of the instruction. note, instruction results don't consider
// themselves users of the value (eases register allocation logic)
/* result of the instruction. note, instruction results don't consider
themselves users of the value (eases register allocation logic) */
struct ir_value *result;
// generic meta data used by optimization passes
/* generic meta data used by optimization passes */
intptr_t tag;
struct list_node it;
};
// locals are allocated for values that need to be spilled to the stack
// during register allocation
/* locals are allocated for values that need to be spilled to the stack
during register allocation */
struct ir_local {
enum ir_type type;
struct ir_value *offset;
@ -208,12 +208,12 @@ void ir_replace_uses(struct ir_value *v, struct ir_value *other);
uint64_t ir_zext_constant(const struct ir_value *v);
// direct access to host memory
/* direct access to host memory */
struct ir_value *ir_load(struct ir *ir, struct ir_value *addr,
enum ir_type type);
void ir_store(struct ir *ir, struct ir_value *addr, struct ir_value *v);
// guest memory operations
/* guest memory operations */
struct ir_value *ir_load_fast(struct ir *ir, struct ir_value *addr,
enum ir_type type);
void ir_store_fast(struct ir *ir, struct ir_value *addr, struct ir_value *v);
@ -222,16 +222,16 @@ struct ir_value *ir_load_slow(struct ir *ir, struct ir_value *addr,
enum ir_type type);
void ir_store_slow(struct ir *ir, struct ir_value *addr, struct ir_value *v);
// context operations
/* context operations */
struct ir_value *ir_load_context(struct ir *ir, size_t offset,
enum ir_type type);
void ir_store_context(struct ir *ir, size_t offset, struct ir_value *v);
// local operations
/* local operations */
struct ir_value *ir_load_local(struct ir *ir, struct ir_local *local);
void ir_store_local(struct ir *ir, struct ir_local *local, struct ir_value *v);
// cast / conversion operations
/* cast / conversion operations */
struct ir_value *ir_ftoi(struct ir *ir, struct ir_value *v,
enum ir_type dest_type);
struct ir_value *ir_itof(struct ir *ir, struct ir_value *v,
@ -247,7 +247,7 @@ struct ir_value *ir_fext(struct ir *ir, struct ir_value *v,
struct ir_value *ir_ftrunc(struct ir *ir, struct ir_value *v,
enum ir_type dest_type);
// conditionals
/* conditionals */
struct ir_value *ir_select(struct ir *ir, struct ir_value *cond,
struct ir_value *t, struct ir_value *f);
struct ir_value *ir_cmp_eq(struct ir *ir, struct ir_value *a,
@ -283,7 +283,7 @@ struct ir_value *ir_fcmp_le(struct ir *ir, struct ir_value *a,
struct ir_value *ir_fcmp_lt(struct ir *ir, struct ir_value *a,
struct ir_value *b);
// integer math operators
/* integer math operators */
struct ir_value *ir_add(struct ir *ir, struct ir_value *a, struct ir_value *b);
struct ir_value *ir_sub(struct ir *ir, struct ir_value *a, struct ir_value *b);
struct ir_value *ir_smul(struct ir *ir, struct ir_value *a, struct ir_value *b);
@ -292,7 +292,7 @@ struct ir_value *ir_div(struct ir *ir, struct ir_value *a, struct ir_value *b);
struct ir_value *ir_neg(struct ir *ir, struct ir_value *a);
struct ir_value *ir_abs(struct ir *ir, struct ir_value *a);
// floating point math operators
/* floating point math operators */
struct ir_value *ir_fadd(struct ir *ir, struct ir_value *a, struct ir_value *b);
struct ir_value *ir_fsub(struct ir *ir, struct ir_value *a, struct ir_value *b);
struct ir_value *ir_fmul(struct ir *ir, struct ir_value *a, struct ir_value *b);
@ -301,7 +301,7 @@ struct ir_value *ir_fneg(struct ir *ir, struct ir_value *a);
struct ir_value *ir_fabs(struct ir *ir, struct ir_value *a);
struct ir_value *ir_sqrt(struct ir *ir, struct ir_value *a);
// vector math operators
/* vector math operators */
struct ir_value *ir_vbroadcast(struct ir *ir, struct ir_value *a);
struct ir_value *ir_vadd(struct ir *ir, struct ir_value *a, struct ir_value *b,
enum ir_type el_type);
@ -310,7 +310,7 @@ struct ir_value *ir_vdot(struct ir *ir, struct ir_value *a, struct ir_value *b,
struct ir_value *ir_vmul(struct ir *ir, struct ir_value *a, struct ir_value *b,
enum ir_type el_type);
// bitwise operations
/* bitwise operations */
struct ir_value *ir_and(struct ir *ir, struct ir_value *a, struct ir_value *b);
struct ir_value *ir_or(struct ir *ir, struct ir_value *a, struct ir_value *b);
struct ir_value *ir_xor(struct ir *ir, struct ir_value *a, struct ir_value *b);
@ -324,14 +324,14 @@ struct ir_value *ir_lshri(struct ir *ir, struct ir_value *a, int n);
struct ir_value *ir_ashd(struct ir *ir, struct ir_value *a, struct ir_value *n);
struct ir_value *ir_lshd(struct ir *ir, struct ir_value *a, struct ir_value *n);
// branches
/* branches */
void ir_label(struct ir *ir, struct ir_value *lbl);
void ir_branch(struct ir *ir, struct ir_value *dst);
void ir_branch_false(struct ir *ir, struct ir_value *cond,
struct ir_value *dst);
void ir_branch_true(struct ir *ir, struct ir_value *cond, struct ir_value *dst);
// calls
/* calls */
void ir_call(struct ir *ir, struct ir_value *fn);
void ir_call_1(struct ir *ir, struct ir_value *fn, struct ir_value *arg0);
void ir_call_2(struct ir *ir, struct ir_value *fn, struct ir_value *arg0,
@ -339,4 +339,7 @@ void ir_call_2(struct ir *ir, struct ir_value *fn, struct ir_value *arg0,
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);
#endif

View File

@ -51,3 +51,4 @@ IR_OP(BRANCH_FALSE)
IR_OP(BRANCH_TRUE)
IR_OP(CALL)
IR_OP(CALL_FALLBACK)
IR_OP(DEBUG_INFO)

View File

@ -18,6 +18,7 @@ DEFINE_OPTION_STRING(pass, "lse,cve,esimp,dce,ra",
DEFINE_OPTION_INT(stats, 1, "Print pass stats");
DEFINE_OPTION_INT(print_after_all, 1, "Print IR after each pass");
DEFINE_STAT(frontend_size, "Frontend code size");
DEFINE_STAT(backend_size, "Backend code size");
DEFINE_STAT(num_instrs, "Total instructions");
DEFINE_STAT(num_instrs_removed, "Total instructions removed");
@ -51,12 +52,20 @@ static void process_file(struct jit *jit, const char *filename,
fclose(input);
CHECK(r);
int num_instrs_before = get_num_instrs(&ir);
/* calculate frontend input size */
list_for_each_entry(instr, &ir.instrs, struct ir_instr, it) {
if (instr->op == OP_DEBUG_INFO) {
struct ir_value *data = instr->arg[1];
STAT_frontend_size += ir_type_size(data->type);
}
}
/* run optimization passes */
char passes[MAX_OPTION_LENGTH];
strncpy(passes, OPTION_pass, sizeof(passes));
int num_instrs_before = get_num_instrs(&ir);
char *name = strtok(passes, ",");
while (name) {
if (!strcmp(name, "lse")) {
@ -85,12 +94,13 @@ static void process_file(struct jit *jit, const char *filename,
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);
}
int num_instrs_after = get_num_instrs(&ir);
STAT_num_instrs += num_instrs_before;
STAT_num_instrs_removed += num_instrs_before - num_instrs_after;