mirror of https://github.com/inolen/redream.git
added frontend code size stats to recc
This commit is contained in:
parent
3cb36fc6c4
commit
162bfce38f
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -51,3 +51,4 @@ IR_OP(BRANCH_FALSE)
|
|||
IR_OP(BRANCH_TRUE)
|
||||
IR_OP(CALL)
|
||||
IR_OP(CALL_FALLBACK)
|
||||
IR_OP(DEBUG_INFO)
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue