X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fstat%2Ffirmstat.c;h=38c777457f94fa70ff3394d283ba7e8218f4ded7;hb=4b0d2820179bbbf6b2dc06223ed9d7ebfa547402;hp=ef7abaf5b0c006b1614cc3931a2f5888e453cbe7;hpb=854a38b1971f66bb8cfa2c16677635468cfbf934;p=libfirm diff --git a/ir/stat/firmstat.c b/ir/stat/firmstat.c index ef7abaf5b..38c777457 100644 --- a/ir/stat/firmstat.c +++ b/ir/stat/firmstat.c @@ -31,6 +31,8 @@ #include "pattern.h" #include "dags.h" #include "stat_dmp.h" +#include "xmalloc.h" +#include "irhooks.h" /* * need this to be static: @@ -42,7 +44,7 @@ */ static ir_op _op_Phi0; -/** The PhiM, just to count memorty Phi's. */ +/** The PhiM, just to count memory Phi's. */ static ir_op _op_PhiM; /** The Mul by Const node. */ @@ -60,6 +62,12 @@ static ir_op _op_DivModC; /** The memory Proj node. */ static ir_op _op_ProjM; +/** A Sel of a Sel */ +static ir_op _op_SelSel; + +/** A Sel of a Sel of a Sel */ +static ir_op _op_SelSelSel; + /* ---------------------------------------------------------------------------------- */ /** Marks the begin of a statistic (hook) function. */ @@ -74,7 +82,8 @@ static ir_op _op_ProjM; /** * global status */ -static stat_info_t _status, *status = &_status; +static const int status_disable = 0; +static stat_info_t *status = (stat_info_t *)&status_disable; /** * compare two elements of the opcode hash @@ -155,37 +164,44 @@ static void opcode_clear_entry(node_entry_t *elem) /** * Returns the associates node_entry_t for an ir_op + * + * @param op the IR operation + * @param hmap a hash map containing ir_op* -> node_entry_t* */ -static node_entry_t *opcode_get_entry(const ir_op *op, pset *set) +static node_entry_t *opcode_get_entry(const ir_op *op, hmap_node_entry_t *hmap) { node_entry_t key; node_entry_t *elem; key.op = op; - elem = pset_find(set, &key, op->code); + elem = pset_find(hmap, &key, op->code); if (elem) return elem; elem = obstack_alloc(&status->cnts, sizeof(*elem)); + memset(elem, 0, sizeof(*elem)); /* clear counter */ opcode_clear_entry(elem); elem->op = op; - return pset_insert(set, elem, op->code); + return pset_insert(hmap, elem, op->code); } /** * Returns the associates ir_op for an opcode + * + * @param code the IR opcode + * @param hmap the hash map containing opcode -> ir_op* */ -static ir_op *opcode_find_entry(opcode code, pset *set) +static ir_op *opcode_find_entry(opcode code, hmap_ir_op *hmap) { ir_op key; key.code = code; - return pset_find(set, &key, code); + return pset_find(hmap, &key, code); } /** @@ -199,16 +215,21 @@ static void graph_clear_entry(graph_entry_t *elem, int all) cnt_clr(&elem->cnt_was_inlined); cnt_clr(&elem->cnt_got_inlined); cnt_clr(&elem->cnt_strength_red); + cnt_clr(&elem->cnt_real_func_call); } cnt_clr(&elem->cnt_edges); cnt_clr(&elem->cnt_all_calls); + cnt_clr(&elem->cnt_call_with_cnst_arg); cnt_clr(&elem->cnt_indirect_calls); } /** - * Returns the acssociates graph_entry_t for an irg + * Returns the associated graph_entry_t for an IR graph. + * + * @param irg the IR graph + * @param hmap the hash map containing ir_graph* -> graph_entry_t* */ -static graph_entry_t *graph_get_entry(ir_graph *irg, pset *set) +static graph_entry_t *graph_get_entry(ir_graph *irg, hmap_graph_entry_t *hmap) { graph_entry_t key; graph_entry_t *elem; @@ -216,12 +237,13 @@ static graph_entry_t *graph_get_entry(ir_graph *irg, pset *set) key.irg = irg; - elem = pset_find(set, &key, HASH_PTR(irg)); + elem = pset_find(hmap, &key, HASH_PTR(irg)); if (elem) return elem; /* allocate a new one */ elem = obstack_alloc(&status->cnts, sizeof(*elem)); + memset(elem, 0, sizeof(*elem)); /* clear counter */ graph_clear_entry(elem, 1); @@ -235,7 +257,7 @@ static graph_entry_t *graph_get_entry(ir_graph *irg, pset *set) for (i = 0; i < sizeof(elem->opt_hash)/sizeof(elem->opt_hash[0]); ++i) elem->opt_hash[i] = new_pset(opt_cmp, 4); - return pset_insert(set, elem, HASH_PTR(irg)); + return pset_insert(hmap, elem, HASH_PTR(irg)); } /** @@ -247,27 +269,31 @@ static void opt_clear_entry(opt_entry_t *elem) } /** - * Returns the associates opt_entry_t for an ir_op + * Returns the associated opt_entry_t for an IR operation. + * + * @param op the IR operation + * @param hmap the hash map containing ir_op* -> opt_entry_t* */ -static opt_entry_t *opt_get_entry(const ir_op *op, pset *set) +static opt_entry_t *opt_get_entry(const ir_op *op, hmap_opt_entry_t *hmap) { opt_entry_t key; opt_entry_t *elem; key.op = op; - elem = pset_find(set, &key, op->code); + elem = pset_find(hmap, &key, op->code); if (elem) return elem; elem = obstack_alloc(&status->cnts, sizeof(*elem)); + memset(elem, 0, sizeof(*elem)); /* clear new counter */ opt_clear_entry(elem); elem->op = op; - return pset_insert(set, elem, op->code); + return pset_insert(hmap, elem, op->code); } /** @@ -279,36 +305,43 @@ static void block_clear_entry(block_entry_t *elem) cnt_clr(&elem->cnt_edges); cnt_clr(&elem->cnt_in_edges); cnt_clr(&elem->cnt_out_edges); + cnt_clr(&elem->cnt_phi_data); } /** - * Returns the associates block_entry_t for an block + * Returns the associated block_entry_t for an block. + * + * @param block_nr an IR block number + * @param hmap a hash map containing long -> block_entry_t */ -static block_entry_t *block_get_entry(long block_nr, pset *set) +static block_entry_t *block_get_entry(long block_nr, hmap_block_entry_t *hmap) { block_entry_t key; block_entry_t *elem; key.block_nr = block_nr; - elem = pset_find(set, &key, block_nr); + elem = pset_find(hmap, &key, block_nr); if (elem) return elem; elem = obstack_alloc(&status->cnts, sizeof(*elem)); + memset(elem, 0, sizeof(*elem)); /* clear new counter */ block_clear_entry(elem); elem->block_nr = block_nr; - return pset_insert(set, elem, block_nr); + return pset_insert(hmap, elem, block_nr); } /** * Returns the ir_op for an IR-node, - * handles special cases and return pseudo op codes + * handles special cases and return pseudo op codes. + * + * @param none an IR node */ static ir_op *stat_get_irn_op(ir_node *node) { @@ -343,6 +376,15 @@ static ir_op *stat_get_irn_op(ir_node *node) /* special case, a division/modulo by a const, count on extra counter */ op = status->op_DivModC ? status->op_DivModC : op; } + else if (op == op_Sel && get_irn_op(get_Sel_ptr(node)) == op_Sel) { + /* special case, a Sel of a Sel, count on extra counter */ + op = status->op_SelSel ? status->op_SelSel : op; + + if (get_irn_op(get_Sel_ptr(get_Sel_ptr(node))) == op_Sel) { + /* special case, a Sel of a Sel of a Sel, count on extra counter */ + op = status->op_SelSelSel ? status->op_SelSelSel : op; + } + } return op; } @@ -350,7 +392,7 @@ static ir_op *stat_get_irn_op(ir_node *node) /** * update the block counter */ -static void count_block_info(ir_node *node, graph_entry_t *graph) +static void undate_block_info(ir_node *node, graph_entry_t *graph) { ir_op *op = get_irn_op(node); ir_node *block; @@ -373,6 +415,13 @@ static void count_block_info(ir_node *node, graph_entry_t *graph) } return; } + else if (op == op_Phi && mode_is_datab(get_irn_mode(node))) { + /* count data Phi */ + ir_node *block = get_nodes_block(node); + block_entry_t *b_entry = block_get_entry(get_irn_node_nr(block), graph->block_hash); + + cnt_inc(&b_entry->cnt_phi_data); + } block = get_nodes_block(node); b_entry = block_get_entry(get_irn_node_nr(block), graph->block_hash); @@ -402,18 +451,38 @@ static void count_block_info(ir_node *node, graph_entry_t *graph) } } +/** calculates how many arguments of the call are const */ +static int cnt_const_args(ir_node *call) +{ + int i, res = 0; + int n = get_Call_n_params(call); + + for (i = 0; i < n; ++i) { + ir_node *param = get_Call_param(call, i); + ir_op *op = get_irn_op(param); + + if (op == op_Const || op == op_SymConst) + ++res; + } + return res; +} + /** * update info on calls + * + * @param call The call + * @param graph The graph entry containing the call */ -static void update_call_stat(ir_node *call, graph_entry_t *graph) +static void stat_update_call(ir_node *call, graph_entry_t *graph) { - ir_node *block = get_nodes_block(call); - ir_node *ptr = get_Call_ptr(call); - entity *ent = NULL; + ir_node *block = get_nodes_block(call); + ir_node *ptr = get_Call_ptr(call); + entity *ent = NULL; ir_graph *callee = NULL; + int num_const_args; /* - * If the block is bad, the whole subgraph will colabse later + * If the block is bad, the whole subgraph will collapse later * so do not count this call. * This happens in dead code. */ @@ -433,7 +502,7 @@ static void update_call_stat(ir_node *call, graph_entry_t *graph) /* it is recursive, if it calls at least once */ if (callee == graph->irg) - graph->is_recursive = 1; + graph->is_recursive = 1; } } else { @@ -454,7 +523,7 @@ static void update_call_stat(ir_node *call, graph_entry_t *graph) curr = get_Block_idom(curr); if (! curr || is_no_Block(curr)) - break; + break; } if (curr != block) @@ -470,20 +539,26 @@ static void update_call_stat(ir_node *call, graph_entry_t *graph) graph->is_leaf_call = LCS_NON_LEAF_CALL; } } + + /* check, if arguments of the call are const */ + num_const_args = cnt_const_args(call); + + if (num_const_args > 0) + cnt_inc(&graph->cnt_call_with_cnst_arg); } /** * update info on calls for graphs on the wait queue */ -static void update_call_stat_2(ir_node *call, graph_entry_t *graph) +static void stat_update_call_2(ir_node *call, graph_entry_t *graph) { - ir_node *block = get_nodes_block(call); - ir_node *ptr = get_Call_ptr(call); - entity *ent = NULL; + ir_node *block = get_nodes_block(call); + ir_node *ptr = get_Call_ptr(call); + entity *ent = NULL; ir_graph *callee = NULL; /* - * If the block is bad, the whole subgraph will colabse later + * If the block is bad, the whole subgraph will collapse later * so do not count this call. * This happens in dead code. */ @@ -528,15 +603,24 @@ static void update_node_stat(ir_node *node, void *env) cnt_add_i(&graph->cnt_edges, arity); /* count block edges */ - count_block_info(node, graph); + undate_block_info(node, graph); - /* check for properties that depends on calls like recursion/leaf/indirect call */ - if (op == op_Call) - update_call_stat(node, graph); + /* handle statistics for special node types */ + + if (op == op_Const) { + if (status->stat_options & FIRMSTAT_COUNT_CONSTS) { + /* check properties of constants */ + stat_update_const(status, node, graph); + } + } + else if (op == op_Call) { + /* check for properties that depends on calls like recursion/leaf/indirect call */ + stat_update_call(node, graph); + } } /** - * walker for reachable nodes count for graphs on teh wait_q + * walker for reachable nodes count for graphs on the wait_q */ static void update_node_stat_2(ir_node *node, void *env) { @@ -544,7 +628,7 @@ static void update_node_stat_2(ir_node *node, void *env) /* check for properties that depends on calls like recursion/leaf/indirect call */ if (get_irn_op(node) == op_Call) - update_call_stat_2(node, graph); + stat_update_call_2(node, graph); } /** @@ -636,7 +720,7 @@ static void mark_address_calc(ir_node *node, void *env) } /** - * Called for every graph when the graph is either deleted or stat_finish() + * Called for every graph when the graph is either deleted or stat_dump_snapshot() * is called, must recalculate all statistic info. * * @param global The global entry @@ -693,7 +777,7 @@ static void update_graph_stat(graph_entry_t *global, graph_entry_t *graph) ir_graph *rem = current_ir_graph; if (get_irg_outs_state(graph->irg) != outs_consistent) - compute_outs(graph->irg); + compute_irg_outs(graph->irg); /* Must be done an the outs graph */ current_ir_graph = graph->irg; @@ -727,7 +811,7 @@ static void update_graph_stat(graph_entry_t *global, graph_entry_t *graph) } /** - * Called for every graph that was on the wait_q in stat_finish() + * Called for every graph that was on the wait_q in stat_dump_snapshot() * must finish all statistic info calculations. * * @param global The global entry @@ -754,7 +838,7 @@ static void update_graph_stat_2(graph_entry_t *global, graph_entry_t *graph) */ static void stat_register_dumper(const dumper_t *dumper) { - dumper_t *p = malloc(sizeof(*p)); + dumper_t *p = xmalloc(sizeof(*p)); if (p) { *p = *dumper; @@ -768,7 +852,7 @@ static void stat_register_dumper(const dumper_t *dumper) } /** - * dumps an irg + * dumps an IR graph. */ static void stat_dump_graph(graph_entry_t *entry) { @@ -781,7 +865,20 @@ static void stat_dump_graph(graph_entry_t *entry) } /** - * initialise the dumper + * dumps a constant table + */ +static void stat_dump_consts(const constant_info_t *tbl) +{ + dumper_t *dumper; + + for (dumper = status->dumper; dumper; dumper = dumper->next) { + if (dumper->dump_const_tbl) + dumper->dump_const_tbl(dumper, tbl); + } +} + +/** + * initialize the dumper */ static void stat_dump_init(const char *name) { @@ -816,80 +913,13 @@ ir_op *stat_get_op_from_opcode(opcode code) return opcode_find_entry(code, status->ir_op_hash); } -/* initialize the statistics module. */ -void init_stat(unsigned enable_options) -{ -#define X(a) a, sizeof(a)-1 - - /* enable statistics */ - status->stat_options = enable_options & FIRMSTAT_ENABLED ? enable_options : 0; - - if (! status->stat_options) - return; - - obstack_init(&status->cnts); - - /* create the hash-tables */ - status->irg_hash = new_pset(graph_cmp, 8); - status->ir_op_hash = new_pset(opcode_cmp_2, 1); - - /* create the wait queue */ - status->wait_q = new_pdeq(); - - if (enable_options & FIRMSTAT_COUNT_STRONG_OP) { - /* build the pseudo-ops */ - _op_Phi0.code = get_next_ir_opcode(); - _op_Phi0.name = new_id_from_chars(X("Phi0")); - - _op_PhiM.code = get_next_ir_opcode(); - _op_PhiM.name = new_id_from_chars(X("PhiM")); - - _op_ProjM.code = get_next_ir_opcode(); - _op_ProjM.name = new_id_from_chars(X("ProjM")); - - _op_MulC.code = get_next_ir_opcode(); - _op_MulC.name = new_id_from_chars(X("MulC")); - - _op_DivC.code = get_next_ir_opcode(); - _op_DivC.name = new_id_from_chars(X("DivC")); - - _op_ModC.code = get_next_ir_opcode(); - _op_ModC.name = new_id_from_chars(X("ModC")); - - _op_DivModC.code = get_next_ir_opcode(); - _op_DivModC.name = new_id_from_chars(X("DivModC")); - - status->op_Phi0 = &_op_Phi0; - status->op_PhiM = &_op_PhiM; - status->op_ProjM = &_op_ProjM; - status->op_MulC = &_op_MulC; - status->op_DivC = &_op_DivC; - status->op_ModC = &_op_ModC; - status->op_DivModC = &_op_DivModC; - } - else { - status->op_Phi0 = NULL; - status->op_PhiM = NULL; - status->op_ProjM = NULL; - status->op_MulC = NULL; - status->op_DivC = NULL; - status->op_ModC = NULL; - status->op_DivModC = NULL; - } - - /* register the dumper */ - stat_register_dumper(&simple_dumper); - - if (enable_options & FIRMSTAT_CSV_OUTPUT) - stat_register_dumper(&csv_dumper); - - /* initialize the pattern hash */ - stat_init_pattern_history(enable_options & FIRMSTAT_PATTERN_ENABLED); -#undef X -} - -/* A new IR op is registered. */ -void stat_new_ir_op(const ir_op *op) +/** + * A new IR op is registered. + * + * @param ctx the hook context + * @param op the new IR opcode that was created. + */ +static void stat_new_ir_op(void *ctx, ir_op *op) { if (! status->stat_options) return; @@ -906,8 +936,13 @@ void stat_new_ir_op(const ir_op *op) STAT_LEAVE; } -/* An IR op is freed. */ -void stat_free_ir_op(const ir_op *op) +/** + * An IR op is freed. + * + * @param ctx the hook context + * @param op the IR opcode that is freed + */ +static void stat_free_ir_op(void *ctx, ir_op *op) { if (! status->stat_options) return; @@ -918,8 +953,14 @@ void stat_free_ir_op(const ir_op *op) STAT_LEAVE; } -/* A new node is created. */ -void stat_new_node(ir_node *node) +/** + * A new node is created. + * + * @param ctx the hook context + * @param irg the IR graph on which the node is created + * @param node the new IR node that was created + */ +static void stat_new_node(void *ctx, ir_graph *irg, ir_node *node) { if (! status->stat_options) return; @@ -947,8 +988,13 @@ void stat_new_node(ir_node *node) STAT_LEAVE; } -/* A node is changed into a Id node */ -void stat_turn_into_id(ir_node *node) +/** + * A node is changed into a Id node + * + * @param ctx the hook context + * @param node the IR node that will be turned into an ID + */ +static void stat_turn_into_id(void *ctx, ir_node *node) { if (! status->stat_options) return; @@ -972,8 +1018,14 @@ void stat_turn_into_id(ir_node *node) STAT_LEAVE; } -/* A new graph was created */ -void stat_new_graph(ir_graph *irg, entity *ent) +/** + * A new graph was created + * + * @param ctx the hook context + * @param irg the new IR graph that was created + * @param ent the entity of this graph + */ +static void stat_new_graph(void *ctx, ir_graph *irg, entity *ent) { if (! status->stat_options) return; @@ -994,10 +1046,17 @@ void stat_new_graph(ir_graph *irg, entity *ent) STAT_LEAVE; } -/* +/** * A graph will be deleted + * + * @param ctx the hook context + * @param irg the IR graph that will be deleted + * + * Note that we still hold the information for this graph + * in our hash maps, only a flag is set which prevents this + * information from being changed, it's "frozen" from now. */ -void stat_free_graph(ir_graph *irg) +static void stat_free_graph(void *ctx, ir_graph *irg) { if (! status->stat_options) return; @@ -1017,10 +1076,15 @@ void stat_free_graph(ir_graph *irg) STAT_LEAVE; } -/* +/** * A walk over a graph is initiated. Do not count walks from statistic code. + * + * @param ctx the hook context + * @param irg the IR graph that will be walked + * @param pre the pre walker + * @param post the post walker */ -void stat_irg_walk(ir_graph *irg, void *pre, void *post) +static void stat_irg_walk(void *ctx, ir_graph *irg, generic_func *pre, generic_func *post) { if (! status->stat_options) return; @@ -1034,19 +1098,30 @@ void stat_irg_walk(ir_graph *irg, void *pre, void *post) STAT_LEAVE; } -/* +/** * A walk over a graph in block-wise order is initiated. Do not count walks from statistic code. + * + * @param ctx the hook context + * @param irg the IR graph that will be walked + * @param pre the pre walker + * @param post the post walker */ -void stat_irg_walk_blkwise(ir_graph *irg, void *pre, void *post) +static void stat_irg_walk_blkwise(void *ctx, ir_graph *irg, generic_func *pre, generic_func *post) { /* for now, do NOT differentiate between blockwise and normal */ - stat_irg_walk(irg, pre, post); + stat_irg_walk(ctx, irg, pre, post); } -/* +/** * A walk over the graph's blocks is initiated. Do not count walks from statistic code. + * + * @param ctx the hook context + * @param irg the IR graph that will be walked + * @param node the IR node + * @param pre the pre walker + * @param post the post walker */ -void stat_irg_block_walk(ir_graph *irg, const ir_node *node, void *pre, void *post) +static void stat_irg_block_walk(void *ctx, ir_graph *irg, ir_node *node, generic_func *pre, generic_func *post) { if (! status->stat_options) return; @@ -1061,24 +1136,30 @@ void stat_irg_block_walk(ir_graph *irg, const ir_node *node, void *pre, void *po } /** - * called for every node that is removed due to an optimization + * called for every node that is removed due to an optimization. + * + * @param n the IR node that will be removed + * @param hmap the hash map containing ir_op* -> opt_entry_t* */ -static void removed_due_opt(ir_node *n, pset *set) +static void removed_due_opt(ir_node *n, hmap_opt_entry_t *hmap) { ir_op *op = stat_get_irn_op(n); - opt_entry_t *entry = opt_get_entry(op, set); + opt_entry_t *entry = opt_get_entry(op, hmap); /* increase global value */ cnt_inc(&entry->count); } -/* - * Some nodes were optimized into some others due to an optimization +/** + * Some nodes were optimized into some others due to an optimization. + * + * @param ctx the hook context */ -void stat_merge_nodes( +static void stat_merge_nodes( + void *ctx, ir_node **new_node_array, int new_num_entries, ir_node **old_node_array, int old_num_entries, - stat_opt_kind opt) + hook_opt_kind opt) { if (! status->stat_options) return; @@ -1089,7 +1170,7 @@ void stat_merge_nodes( graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash); if (status->reassoc_run) - opt = STAT_OPT_REASSOC; + opt = HOOK_OPT_REASSOC; for (i = 0; i < old_num_entries; ++i) { for (j = 0; j < new_num_entries; ++j) @@ -1098,17 +1179,30 @@ void stat_merge_nodes( /* nodes might be in new and old, these are NOT removed */ if (j >= new_num_entries) { - removed_due_opt(old_node_array[i], graph->opt_hash[opt]); + int xopt = opt; + + /* sometimes we did not detect, that it is replaced by a Const */ + if (opt == HOOK_OPT_CONFIRM && new_num_entries == 1) { + ir_op *op = get_irn_op(new_node_array[0]); + + if (op == op_Const || op == op_SymConst) + xopt = HOOK_OPT_CONFIRM_C; + } + + removed_due_opt(old_node_array[i], graph->opt_hash[xopt]); } } } STAT_LEAVE; } -/* - * reassociation started/stopped. +/** + * Reassociation is started/stopped. + * + * @param ctx the hook context + * @param flag if non-zero, reassociation is started else stopped */ -void stat_reassociate(int flag) +static void stat_reassociate(void *ctx, int flag) { if (! status->stat_options) return; @@ -1120,10 +1214,13 @@ void stat_reassociate(int flag) STAT_LEAVE; } -/* +/** * A node was lowered into other nodes + * + * @param ctx the hook context + * @param node the IR node that will be lowered */ -void stat_lower(ir_node *node) +static void stat_lower(void *ctx, ir_node *node) { if (! status->stat_options) return; @@ -1132,15 +1229,20 @@ void stat_lower(ir_node *node) { graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash); - removed_due_opt(node, graph->opt_hash[STAT_LOWERED]); + removed_due_opt(node, graph->opt_hash[HOOK_LOWERED]); } STAT_LEAVE; } -/* - * A graph was inlined +/** + * A graph was inlined. + * + * @param ctx the hook context + * @param call the IR call that will re changed into the body of + * the called IR graph + * @param called_irg the IR graph representing the called routine */ -void stat_inline(ir_node *call, ir_graph *called_irg) +static void stat_inline(void *ctx, ir_node *call, ir_graph *called_irg) { if (! status->stat_options) return; @@ -1157,24 +1259,31 @@ void stat_inline(ir_node *call, ir_graph *called_irg) STAT_LEAVE; } -/* +/** * A graph with tail-recursions was optimized. + * + * @param ctx the hook context */ -void stat_tail_rec(ir_graph *irg) +static void stat_tail_rec(void *ctx, ir_graph *irg, int n_calls) { if (! status->stat_options) return; STAT_ENTER; { + graph_entry_t *graph = graph_get_entry(irg, status->irg_hash); + + graph->num_tail_recursion += n_calls; } STAT_LEAVE; } -/* +/** * Strength reduction was performed on an iteration variable. + * + * @param ctx the hook context */ -void stat_strength_red(ir_graph *irg, ir_node *strong, ir_node *cmp) +static void stat_strength_red(void *ctx, ir_graph *irg, ir_node *strong, ir_node *cmp) { if (! status->stat_options) return; @@ -1184,15 +1293,17 @@ void stat_strength_red(ir_graph *irg, ir_node *strong, ir_node *cmp) graph_entry_t *graph = graph_get_entry(irg, status->irg_hash); cnt_inc(&graph->cnt_strength_red); - removed_due_opt(strong, graph->opt_hash[STAT_OPT_STRENGTH_RED]); + removed_due_opt(strong, graph->opt_hash[HOOK_OPT_STRENGTH_RED]); } STAT_LEAVE; } -/* +/** * Start the dead node elimination. + * + * @param ctx the hook context */ -void stat_dead_node_elim_start(ir_graph *irg) +static void stat_dead_node_elim_start(void *ctx, ir_graph *irg) { if (! status->stat_options) return; @@ -1200,10 +1311,12 @@ void stat_dead_node_elim_start(ir_graph *irg) ++status->in_dead_node_elim; } -/* +/** * Stops the dead node elimination. + * + * @param ctx the hook context */ -void stat_dead_node_elim_stop(ir_graph *irg) +static void stat_dead_node_elim_stop(void *ctx, ir_graph *irg) { if (! status->stat_options) return; @@ -1211,10 +1324,47 @@ void stat_dead_node_elim_stop(ir_graph *irg) --status->in_dead_node_elim; } -/* +/** + * if-conversion was tried + */ +static void stat_if_conversion(void *context, ir_graph *irg, ir_node *phi, + int pos, ir_node *mux, if_result_t reason) +{ + if (! status->stat_options) + return; + + STAT_ENTER; + { + graph_entry_t *graph = graph_get_entry(irg, status->irg_hash); + + cnt_inc(&graph->cnt_if_conv[reason]); + } + STAT_LEAVE; +} + +/** + * real function call was optimized + */ +static void stat_func_call(void *context, ir_graph *irg, ir_node *call) +{ + if (! status->stat_options) + return; + + STAT_ENTER; + { + graph_entry_t *graph = graph_get_entry(irg, status->irg_hash); + + cnt_inc(&graph->cnt_real_func_call); + } + STAT_LEAVE; +} + +/** * A multiply was replaced by a series of Shifts/Adds/Subs + * + * @param ctx the hook context */ -void stat_arch_dep_replace_mul_with_shifts(ir_node *mul) +static void stat_arch_dep_replace_mul_with_shifts(void *ctx, ir_node *mul) { if (! status->stat_options) return; @@ -1222,15 +1372,18 @@ void stat_arch_dep_replace_mul_with_shifts(ir_node *mul) STAT_ENTER; { graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash); - removed_due_opt(mul, graph->opt_hash[STAT_OPT_ARCH_DEP]); + removed_due_opt(mul, graph->opt_hash[HOOK_OPT_ARCH_DEP]); } STAT_LEAVE; } /** * A division was replaced by a series of Shifts/Muls + * + * @param ctx the hook context + * @param div the div node that will be optimized */ -void stat_arch_dep_replace_div_by_const(ir_node *div) +static void stat_arch_dep_replace_div_by_const(void *ctx, ir_node *div) { if (! status->stat_options) return; @@ -1238,15 +1391,18 @@ void stat_arch_dep_replace_div_by_const(ir_node *div) STAT_ENTER; { graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash); - removed_due_opt(div, graph->opt_hash[STAT_OPT_ARCH_DEP]); + removed_due_opt(div, graph->opt_hash[HOOK_OPT_ARCH_DEP]); } STAT_LEAVE; } /** * A modulo was replaced by a series of Shifts/Muls + * + * @param ctx the hook context + * @param mod the mod node that will be optimized */ -void stat_arch_dep_replace_mod_by_const(ir_node *mod) +static void stat_arch_dep_replace_mod_by_const(void *ctx, ir_node *mod) { if (! status->stat_options) return; @@ -1254,15 +1410,18 @@ void stat_arch_dep_replace_mod_by_const(ir_node *mod) STAT_ENTER; { graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash); - removed_due_opt(mod, graph->opt_hash[STAT_OPT_ARCH_DEP]); + removed_due_opt(mod, graph->opt_hash[HOOK_OPT_ARCH_DEP]); } STAT_LEAVE; } /** * A DivMod was replaced by a series of Shifts/Muls + * + * @param ctx the hook context + * @param divmod the divmod node that will be optimized */ -void stat_arch_dep_replace_DivMod_by_const(ir_node *divmod) +static void stat_arch_dep_replace_DivMod_by_const(void *ctx, ir_node *divmod) { if (! status->stat_options) return; @@ -1270,14 +1429,18 @@ void stat_arch_dep_replace_DivMod_by_const(ir_node *divmod) STAT_ENTER; { graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash); - removed_due_opt(divmod, graph->opt_hash[STAT_OPT_ARCH_DEP]); + removed_due_opt(divmod, graph->opt_hash[HOOK_OPT_ARCH_DEP]); } STAT_LEAVE; } -/* Finish the statistics */ -void stat_finish(const char *name) +/* Dumps a statistics snapshot */ +void stat_dump_snapshot(const char *name, const char *phase) { + char fname[2048]; + const char *p; + int l; + if (! status->stat_options) return; @@ -1286,7 +1449,47 @@ void stat_finish(const char *name) graph_entry_t *entry; graph_entry_t *global = graph_get_entry(NULL, status->irg_hash); - stat_dump_init(name); + /* + * The constant counter is only global, so we clear it here. + * Note that it does NOT contain the constants in DELETED + * graphs due to this. + */ + if (status->stat_options & FIRMSTAT_COUNT_CONSTS) + stat_const_clear(status); + + /* build the name */ + p = strrchr(name, '/'); +#ifdef _WIN32 + { + const char *q; + + q = strrchr(name, '\\'); + + /* NULL might be not the smallest pointer */ + if (q && (!p || q > p)) + p = q; + } +#endif + if (p) { + ++p; + l = p - name; + + if (l > sizeof(fname) - 1) + l = sizeof(fname) - 1; + + memcpy(fname, name, l); + fname[l] = '\0'; + } + else { + fname[0] = '\0'; + p = name; + } + strncat(fname, "firmstat-", sizeof(fname)); + strncat(fname, phase, sizeof(fname)); + strncat(fname, "-", sizeof(fname)); + strncat(fname, p, sizeof(fname)); + + stat_dump_init(fname); /* calculate the graph statistics */ for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) { @@ -1302,7 +1505,7 @@ void stat_finish(const char *name) } } - /* some calculations are dependant, we pushed them on the wait_q */ + /* some calculations are dependent, we pushed them on the wait_q */ while (! pdeq_empty(status->wait_q)) { entry = pdeq_getr(status->wait_q); @@ -1329,6 +1532,11 @@ void stat_finish(const char *name) /* dump global */ stat_dump_graph(global); + + /* dump the const info */ + if (status->stat_options & FIRMSTAT_COUNT_CONSTS) + stat_dump_consts(&status->const_info); + stat_dump_finish(); stat_finish_pattern_history(); @@ -1343,64 +1551,153 @@ void stat_finish(const char *name) /* clear all global counter */ graph_clear_entry(global, 1); } - - /* finished */ -// status->stat_options = 0; } STAT_LEAVE; } -#else +/** the hook entries for the Firm statistics module */ +static hook_entry_t stat_hooks[hook_last]; -/* need this for prototypes */ -#define FIRM_STATISTICS -#include "firmstat.h" +/* initialize the statistics module. */ +void init_stat(unsigned enable_options) +{ +#define X(a) a, sizeof(a)-1 +#define HOOK(h, fkt) \ + stat_hooks[h].hook._##h = fkt; register_hook(h, &stat_hooks[h]) -void init_stat(unsigned enable_options) {} + if (! (enable_options & FIRMSTAT_ENABLED)) + return; -void stat_finish(const char *name) {} + status = xmalloc(sizeof(*status)); + memset(status, 0, sizeof(*status)); -void stat_new_ir_op(const ir_op *op) {} + /* enable statistics */ + status->stat_options = enable_options & FIRMSTAT_ENABLED ? enable_options : 0; -void stat_free_ir_op(const ir_op *op) {} + /* register all hooks */ + HOOK(hook_new_ir_op, stat_new_ir_op); + HOOK(hook_free_ir_op, stat_free_ir_op); + HOOK(hook_new_node, stat_new_node); + HOOK(hook_turn_into_id, stat_turn_into_id); + HOOK(hook_new_graph, stat_new_graph); + HOOK(hook_free_graph, stat_free_graph); + HOOK(hook_irg_walk, stat_irg_walk); + HOOK(hook_irg_walk_blkwise, stat_irg_walk_blkwise); + HOOK(hook_irg_block_walk, stat_irg_block_walk); + HOOK(hook_merge_nodes, stat_merge_nodes); + HOOK(hook_reassociate, stat_reassociate); + HOOK(hook_lower, stat_lower); + HOOK(hook_inline, stat_inline); + HOOK(hook_tail_rec, stat_tail_rec); + HOOK(hook_strength_red, stat_strength_red); + HOOK(hook_dead_node_elim_start, stat_dead_node_elim_start); + HOOK(hook_dead_node_elim_stop, stat_dead_node_elim_stop); + HOOK(hook_if_conversion, stat_if_conversion); + HOOK(hook_func_call, stat_func_call); + HOOK(hook_arch_dep_replace_mul_with_shifts, stat_arch_dep_replace_mul_with_shifts); + HOOK(hook_arch_dep_replace_div_by_const, stat_arch_dep_replace_div_by_const); + HOOK(hook_arch_dep_replace_mod_by_const, stat_arch_dep_replace_mod_by_const); + HOOK(hook_arch_dep_replace_DivMod_by_const, stat_arch_dep_replace_DivMod_by_const); -void stat_new_node(ir_node *node) {} + obstack_init(&status->cnts); -void stat_turn_into_id(ir_node *node) {} + /* create the hash-tables */ + status->irg_hash = new_pset(graph_cmp, 8); + status->ir_op_hash = new_pset(opcode_cmp_2, 1); -void stat_new_graph(ir_graph *irg, entity *ent) {} + /* create the wait queue */ + status->wait_q = new_pdeq(); -void stat_free_graph(ir_graph *irg) {} + if (enable_options & FIRMSTAT_COUNT_STRONG_OP) { + /* build the pseudo-ops */ + _op_Phi0.code = get_next_ir_opcode(); + _op_Phi0.name = new_id_from_chars(X("Phi0")); -void stat_irg_walk(ir_graph *irg, void *pre, void *post) {} + _op_PhiM.code = get_next_ir_opcode(); + _op_PhiM.name = new_id_from_chars(X("PhiM")); -void stat_irg_block_walk(ir_graph *irg, const ir_node *node, void *pre, void *post) {} + _op_ProjM.code = get_next_ir_opcode(); + _op_ProjM.name = new_id_from_chars(X("ProjM")); -void stat_merge_nodes( - ir_node **new_node_array, int new_num_entries, - ir_node **old_node_array, int old_num_entries, - stat_opt_kind opt) {} + _op_MulC.code = get_next_ir_opcode(); + _op_MulC.name = new_id_from_chars(X("MulC")); -void stat_reassociate(int start) {} + _op_DivC.code = get_next_ir_opcode(); + _op_DivC.name = new_id_from_chars(X("DivC")); -void stat_lower(ir_node *node) {} + _op_ModC.code = get_next_ir_opcode(); + _op_ModC.name = new_id_from_chars(X("ModC")); -void stat_inline(ir_node *call, ir_graph *irg) {} + _op_DivModC.code = get_next_ir_opcode(); + _op_DivModC.name = new_id_from_chars(X("DivModC")); -void stat_tail_rec(ir_graph *irg) {} + status->op_Phi0 = &_op_Phi0; + status->op_PhiM = &_op_PhiM; + status->op_ProjM = &_op_ProjM; + status->op_MulC = &_op_MulC; + status->op_DivC = &_op_DivC; + status->op_ModC = &_op_ModC; + status->op_DivModC = &_op_DivModC; + } + else { + status->op_Phi0 = NULL; + status->op_PhiM = NULL; + status->op_ProjM = NULL; + status->op_MulC = NULL; + status->op_DivC = NULL; + status->op_ModC = NULL; + status->op_DivModC = NULL; + } -void stat_strength_red(ir_graph *irg, ir_node *strong, ir_node *cmp) {} + if (enable_options & FIRMSTAT_COUNT_SELS) { + _op_SelSel.code = get_next_ir_opcode(); + _op_SelSel.name = new_id_from_chars(X("Sel(Sel)")); -void stat_dead_node_elim_start(ir_graph *irg) {} + _op_SelSelSel.code = get_next_ir_opcode(); + _op_SelSelSel.name = new_id_from_chars(X("Sel(Sel(Sel))")); -void stat_dead_node_elim_stop(ir_graph *irg) {} + status->op_SelSel = &_op_SelSel; + status->op_SelSelSel = &_op_SelSelSel; + } + else { + status->op_SelSel = NULL; + status->op_SelSelSel = NULL; + } -void stat_arch_dep_replace_mul_with_shifts(ir_node *mul) {} + /* register the dumper */ + stat_register_dumper(&simple_dumper); -void stat_arch_dep_replace_div_by_const(ir_node *div) {} + if (enable_options & FIRMSTAT_CSV_OUTPUT) + stat_register_dumper(&csv_dumper); -void stat_arch_dep_replace_mod_by_const(ir_node *mod) {} + /* initialize the pattern hash */ + stat_init_pattern_history(enable_options & FIRMSTAT_PATTERN_ENABLED); -void stat_arch_dep_replace_DivMod_by_const(ir_node *divmod) {} + /* initialize the Const options */ + if (enable_options & FIRMSTAT_COUNT_CONSTS) + stat_init_const_cnt(status); -#endif +#undef HOOK +#undef X +} + +/* terminates the statistics module, frees all memory */ +void stat_term(void) { + if (status != (stat_info_t *)&status_disable) { + xfree(status); + status = (stat_info_t *)&status_disable; + } +} + +#else + +/* initialize the statistics module. */ +void init_stat(unsigned enable_options) {} + +/* Dumps a statistics snapshot */ +void stat_dump_snapshot(const char *name, const char *phase) {} + +/* terminates the statistics module, frees all memory */ +void stat_term(void); + +#endif /* FIRM_STATISTICS */