X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fstat%2Ffirmstat.c;h=6555ab71e504362b5b8f4b43215cef131dd7ac60;hb=b2509ebc03f0b178683087886a9d9269cb84bd03;hp=57e791b86fcac04772a52eaa4028e49b7d1e2a7b;hpb=5d2f7c6eca2173a427ccf35a4b8ac793706de2e9;p=libfirm diff --git a/ir/stat/firmstat.c b/ir/stat/firmstat.c index 57e791b86..6555ab71e 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. */ @@ -57,10 +59,18 @@ static ir_op _op_ModC; /** The Div by Const node. */ static ir_op _op_DivModC; +/** The memory Proj node. */ +static ir_op _op_ProjM; + /* ---------------------------------------------------------------------------------- */ +/** Marks the begin of a statistic (hook) function. */ #define STAT_ENTER ++status->recursive + +/** Marks the end of a statistic (hook) functions. */ #define STAT_LEAVE --status->recursive + +/** Allows to enter a statistic function only when we are not already in a hook. */ #define STAT_ENTER_SINGLE do { if (status->recursive > 0) return; ++status->recursive; } while (0) /** @@ -198,7 +208,7 @@ static void graph_clear_entry(graph_entry_t *elem, int all) } /** - * Returns the acssociates graph_entry_t for an irg + * Returns the associated graph_entry_t for an irg */ static graph_entry_t *graph_get_entry(ir_graph *irg, pset *set) { @@ -239,7 +249,7 @@ 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_op */ static opt_entry_t *opt_get_entry(const ir_op *op, pset *set) { @@ -274,7 +284,7 @@ static void block_clear_entry(block_entry_t *elem) } /** - * Returns the associates block_entry_t for an block + * Returns the associated block_entry_t for an block */ static block_entry_t *block_get_entry(long block_nr, pset *set) { @@ -306,30 +316,34 @@ static ir_op *stat_get_irn_op(ir_node *node) { ir_op *op = get_irn_op(node); - if (op->code == iro_Phi && get_irn_arity(node) == 0) { + if (op == op_Phi && get_irn_arity(node) == 0) { /* special case, a Phi0 node, count on extra counter */ - op = status->op_Phi0; + op = status->op_Phi0 ? status->op_Phi0 : op; } - else if (op->code == iro_Phi && get_irn_mode(node) == mode_M) { + else if (op == op_Phi && get_irn_mode(node) == mode_M) { /* special case, a Memory Phi node, count on extra counter */ - op = status->op_PhiM; + op = status->op_PhiM ? status->op_PhiM : op; + } + else if (op == op_Proj && get_irn_mode(node) == mode_M) { + /* special case, a Memory Proj node, count on extra counter */ + op = status->op_ProjM ? status->op_ProjM : op; } - else if (op->code == iro_Mul && + else if (op == op_Mul && (get_irn_op(get_Mul_left(node)) == op_Const || get_irn_op(get_Mul_right(node)) == op_Const)) { /* special case, a Multiply by a const, count on extra counter */ - op = status->op_MulC ? status->op_MulC : op_Mul; + op = status->op_MulC ? status->op_MulC : op; } - else if (op->code == iro_Div && get_irn_op(get_Div_right(node)) == op_Const) { + else if (op == op_Div && get_irn_op(get_Div_right(node)) == op_Const) { /* special case, a division by a const, count on extra counter */ - op = status->op_DivC ? status->op_DivC : op_Div; + op = status->op_DivC ? status->op_DivC : op; } - else if (op->code == iro_Mod && get_irn_op(get_Mod_right(node)) == op_Const) { + else if (op == op_Mod && get_irn_op(get_Mod_right(node)) == op_Const) { /* special case, a module by a const, count on extra counter */ - op = status->op_ModC ? status->op_ModC : op_Mod; + op = status->op_ModC ? status->op_ModC : op; } - else if (op->code == iro_DivMod && get_irn_op(get_DivMod_right(node)) == op_Const) { + else if (op == op_DivMod && get_irn_op(get_DivMod_right(node)) == op_Const) { /* special case, a division/modulo by a const, count on extra counter */ - op = status->op_DivModC ? status->op_DivModC : op_DivMod; + op = status->op_DivModC ? status->op_DivModC : op; } return op; @@ -398,32 +412,38 @@ static void update_call_stat(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_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 + * This happens in dead code. */ if (is_Bad(block)) return; cnt_inc(&graph->cnt_all_calls); - /* found a call, is not a leaf function */ + /* found a call, this function is not a leaf */ graph->is_leaf = 0; if (get_irn_op(ptr) == op_SymConst) { if (get_SymConst_kind(ptr) == symconst_addr_ent) { /* ok, we seems to know the entity */ ent = get_SymConst_entity(ptr); + callee = get_entity_irg(ent); - if (get_entity_irg(ent) == graph->irg) + /* it is recursive, if it calls at least once */ + if (callee == graph->irg) graph->is_recursive = 1; } } else { - /* indirect call */ + /* indirect call, be could not predict */ cnt_inc(&graph->cnt_indirect_calls); + + /* NOT a leaf call */ + graph->is_leaf_call = LCS_NON_LEAF_CALL; } /* check, if it's a chain-call: Then, the call-block @@ -442,6 +462,55 @@ static void update_call_stat(ir_node *call, graph_entry_t *graph) if (curr != block) graph->is_chain_call = 0; } + + /* check, if the callee is a leaf */ + if (callee) { + graph_entry_t *called = graph_get_entry(callee, status->irg_hash); + + if (called->is_analyzed) { + if (! called->is_leaf) + graph->is_leaf_call = LCS_NON_LEAF_CALL; + } + } +} + +/** + * update info on calls for graphs on the wait queue + */ +static void update_call_stat_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_graph *callee = NULL; + + /* + * If the block is bad, the whole subgraph will collapse later + * so do not count this call. + * This happens in dead code. + */ + if (is_Bad(block)) + return; + + if (get_irn_op(ptr) == op_SymConst) { + if (get_SymConst_kind(ptr) == symconst_addr_ent) { + /* ok, we seems to know the entity */ + ent = get_SymConst_entity(ptr); + callee = get_entity_irg(ent); + } + } + + /* check, if the callee is a leaf */ + if (callee) { + graph_entry_t *called = graph_get_entry(callee, status->irg_hash); + + assert(called->is_analyzed); + + if (! called->is_leaf) + graph->is_leaf_call = LCS_NON_LEAF_CALL; + } + else + graph->is_leaf_call = LCS_NON_LEAF_CALL; } /** @@ -464,10 +533,22 @@ static void update_node_stat(ir_node *node, void *env) count_block_info(node, graph); /* check for properties that depends on calls like recursion/leaf/indirect call */ - if (get_irn_op(node) == op_Call) + if (op == op_Call) update_call_stat(node, graph); } +/** + * walker for reachable nodes count for graphs on the wait_q + */ +static void update_node_stat_2(ir_node *node, void *env) +{ + graph_entry_t *graph = 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); +} + /** * get the current address mark */ @@ -489,10 +570,13 @@ static void set_adr_mark(graph_entry_t *graph, ir_node *node, unsigned val) } /** - * a vcg attribute hook + * a vcg attribute hook: Color a node with a different color if + * it's identified as a part of an address expression or at least referenced + * by an address expression. */ -static int stat_adr_mark_hook(FILE *F, ir_node *n) +static int stat_adr_mark_hook(FILE *F, ir_node *node, ir_node *local) { + ir_node *n = local ? local : node; ir_graph *irg = get_irn_irg(n); graph_entry_t *graph = graph_get_entry(irg, status->irg_hash); unsigned mark = get_adr_mark(graph, n); @@ -500,7 +584,7 @@ static int stat_adr_mark_hook(FILE *F, ir_node *n) if (mark & MARK_ADDRESS_CALC) fprintf(F, "color: purple"); else if ((mark & (MARK_REF_ADR | MARK_REF_NON_ADR)) == MARK_REF_ADR) - fprintf(F, "color: lightpurple"); + fprintf(F, "color: pink"); else if ((mark & (MARK_REF_ADR | MARK_REF_NON_ADR)) == (MARK_REF_ADR|MARK_REF_NON_ADR)) fprintf(F, "color: lightblue"); else @@ -545,7 +629,7 @@ static void mark_address_calc(ir_node *node, void *env) } } - /* makr all predecessors */ + /* mark all predecessors */ for (i = 0, n = get_irn_arity(node); i < n; ++i) { ir_node *pred = get_irn_n(node, i); @@ -554,8 +638,11 @@ static void mark_address_calc(ir_node *node, void *env) } /** - * called for every graph when the graph is either deleted or stat_finish() - * is called, must recalculate all statistic info + * Called for every graph when the graph is either deleted or stat_finish() + * is called, must recalculate all statistic info. + * + * @param global The global entry + * @param graph The current entry */ static void update_graph_stat(graph_entry_t *global, graph_entry_t *graph) { @@ -568,6 +655,7 @@ static void update_graph_stat(graph_entry_t *global, graph_entry_t *graph) /* set pessimistic values */ graph->is_leaf = 1; + graph->is_leaf_call = LCS_UNKNOWN; graph->is_recursive = 0; graph->is_chain_call = 1; @@ -620,6 +708,47 @@ static void update_graph_stat(graph_entry_t *global, graph_entry_t *graph) set_dump_node_vcgattr_hook(NULL); #endif } + + /* count the DAG's */ + if (status->stat_options & FIRMSTAT_COUNT_DAG) + count_dags_in_graph(global, graph); + + /* calculate the patterns of this graph */ + stat_calc_pattern_history(graph->irg); + + /* leaf function did not call others */ + if (graph->is_leaf) + graph->is_leaf_call = LCS_NON_LEAF_CALL; + else if (graph->is_leaf_call == LCS_UNKNOWN) { + /* we still don't know if this graph calls leaf-functions, so enqueue */ + pdeq_putl(status->wait_q, graph); + } + + /* we have analyzed this graph */ + graph->is_analyzed = 1; +} + +/** + * Called for every graph that was on the wait_q in stat_finish() + * must finish all statistic info calculations. + * + * @param global The global entry + * @param graph The current entry + */ +static void update_graph_stat_2(graph_entry_t *global, graph_entry_t *graph) +{ + if (graph->is_deleted) { + /* deleted, ignore */ + return; + } + + if (graph->irg) { + /* count the nodes in the graph */ + irg_walk_graph(graph->irg, update_node_stat_2, NULL, graph); + + if (graph->is_leaf_call == LCS_UNKNOWN) + graph->is_leaf_call = LCS_LEAF_CALL; + } } /** @@ -627,7 +756,7 @@ static void update_graph_stat(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; @@ -654,7 +783,7 @@ static void stat_dump_graph(graph_entry_t *entry) } /** - * initialise the dumper + * initialize the dumper */ static void stat_dump_init(const char *name) { @@ -689,73 +818,10 @@ 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) +/** A new IR op is registered. */ +static void stat_new_ir_op(void *ctx, ir_op *op) { -#define X(a) a, sizeof(a)-1 - - /* enable statistics */ - status->enable = enable_options & FIRMSTAT_ENABLED; - - if (! status->enable) - 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); - - status->op_Phi0 = &_op_Phi0; - status->op_PhiM = &_op_PhiM; - - 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_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_MulC = &_op_MulC; - status->op_DivC = &_op_DivC; - status->op_ModC = &_op_ModC; - status->op_DivModC = &_op_DivModC; - } - else { - 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) -{ - if (! status->enable) + if (! status->stat_options) return; STAT_ENTER; @@ -770,10 +836,10 @@ 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. */ +static void stat_free_ir_op(void *ctx, ir_op *op) { - if (! status->enable) + if (! status->stat_options) return; STAT_ENTER; @@ -782,10 +848,10 @@ 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. */ +static void stat_new_node(void *ctx, ir_node *node) { - if (! status->enable) + if (! status->stat_options) return; /* do NOT count during dead node elimination */ @@ -811,10 +877,10 @@ 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 */ +static void stat_turn_into_id(void *ctx, ir_node *node) { - if (! status->enable) + if (! status->stat_options) return; STAT_ENTER; @@ -836,10 +902,10 @@ 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 */ +static void stat_new_graph(void *ctx, ir_graph *irg, entity *ent) { - if (! status->enable) + if (! status->stat_options) return; STAT_ENTER; @@ -850,18 +916,20 @@ void stat_new_graph(ir_graph *irg, entity *ent) graph->ent = ent; graph->is_deleted = 0; graph->is_leaf = 0; + graph->is_leaf_call = 0; graph->is_recursive = 0; graph->is_chain_call = 0; + graph->is_analyzed = 0; } STAT_LEAVE; } -/* +/** * A graph will be deleted */ -void stat_free_graph(ir_graph *irg) +static void stat_free_graph(void *ctx, ir_graph *irg) { - if (! status->enable) + if (! status->stat_options) return; STAT_ENTER; @@ -871,24 +939,20 @@ void stat_free_graph(ir_graph *irg) graph->is_deleted = 1; - /* count the nodes of the graph yet, it will be destroyed later */ - update_graph_stat(global, graph); - - /* count the DAG's */ - //count_dags_in_graph(global, graph); - - /* calculate the pattern */ - stat_calc_pattern_history(irg); + if (status->stat_options & FIRMSTAT_COUNT_DELETED) { + /* count the nodes of the graph yet, it will be destroyed later */ + update_graph_stat(global, graph); + } } STAT_LEAVE; } -/* +/** * A walk over a graph is initiated. Do not count walks from statistic code. */ -void stat_irg_walk(ir_graph *irg, void *pre, void *post) +static void stat_irg_walk(void *ctx, ir_graph *irg, void *pre, void *post) { - if (! status->enable) + if (! status->stat_options) return; STAT_ENTER_SINGLE; @@ -900,21 +964,21 @@ 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. */ -void stat_irg_walk_blkwise(ir_graph *irg, void *pre, void *post) +static void stat_irg_walk_blkwise(void *ctx, ir_graph *irg, void *pre, void *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. */ -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, void *pre, void *post) { - if (! status->enable) + if (! status->stat_options) return; STAT_ENTER_SINGLE; @@ -938,15 +1002,16 @@ static void removed_due_opt(ir_node *n, pset *set) cnt_inc(&entry->count); } -/* +/** * Some nodes were optimized into some others due to an optimization */ -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->enable) + if (! status->stat_options) return; STAT_ENTER; @@ -955,7 +1020,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) @@ -971,12 +1036,12 @@ void stat_merge_nodes( STAT_LEAVE; } -/* +/** * reassociation started/stopped. */ -void stat_reassociate(int flag) +static void stat_reassociate(void *ctx, int flag) { - if (! status->enable) + if (! status->stat_options) return; STAT_ENTER; @@ -986,29 +1051,29 @@ void stat_reassociate(int flag) STAT_LEAVE; } -/* +/** * A node was lowered into other nodes */ -void stat_lower(ir_node *node) +static void stat_lower(void *ctx, ir_node *node) { - if (! status->enable) + if (! status->stat_options) return; STAT_ENTER; { 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 */ -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->enable) + if (! status->stat_options) return; STAT_ENTER; @@ -1023,12 +1088,12 @@ void stat_inline(ir_node *call, ir_graph *called_irg) STAT_LEAVE; } -/* +/** * A graph with tail-recursions was optimized. */ -void stat_tail_rec(ir_graph *irg) +static void stat_tail_rec(void *ctx, ir_graph *irg) { - if (! status->enable) + if (! status->stat_options) return; STAT_ENTER; @@ -1037,12 +1102,12 @@ void stat_tail_rec(ir_graph *irg) STAT_LEAVE; } -/* +/** * Strength reduction was performed on an iteration variable. */ -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->enable) + if (! status->stat_options) return; STAT_ENTER; @@ -1050,45 +1115,45 @@ 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. */ -void stat_dead_node_elim_start(ir_graph *irg) +static void stat_dead_node_elim_start(void *ctx, ir_graph *irg) { - if (! status->enable) + if (! status->stat_options) return; ++status->in_dead_node_elim; } -/* +/** * Stops the dead node elimination. */ -void stat_dead_node_elim_stop(ir_graph *irg) +static void stat_dead_node_elim_stop(void *ctx, ir_graph *irg) { - if (! status->enable) + if (! status->stat_options) return; --status->in_dead_node_elim; } -/* +/** * A multiply was replaced by a series of Shifts/Adds/Subs */ -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->enable) + if (! status->stat_options) return; 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; } @@ -1096,15 +1161,15 @@ void stat_arch_dep_replace_mul_with_shifts(ir_node *mul) /** * A division was replaced by a series of Shifts/Muls */ -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->enable) + if (! status->stat_options) return; 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; } @@ -1112,15 +1177,15 @@ void stat_arch_dep_replace_div_by_const(ir_node *div) /** * A modulo was replaced by a series of Shifts/Muls */ -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->enable) + if (! status->stat_options) return; 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; } @@ -1128,15 +1193,15 @@ void stat_arch_dep_replace_mod_by_const(ir_node *mod) /** * A DivMod was replaced by a series of Shifts/Muls */ -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->enable) + if (! status->stat_options) return; 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; } @@ -1144,7 +1209,7 @@ void stat_arch_dep_replace_DivMod_by_const(ir_node *divmod) /* Finish the statistics */ void stat_finish(const char *name) { - if (! status->enable) + if (! status->stat_options) return; STAT_ENTER; @@ -1154,7 +1219,7 @@ void stat_finish(const char *name) stat_dump_init(name); - /* dump per graph */ + /* calculate the graph statistics */ for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) { if (entry->irg == NULL) { @@ -1165,18 +1230,32 @@ void stat_finish(const char *name) if (! entry->is_deleted) { /* the graph is still alive, count the nodes on it */ update_graph_stat(global, entry); + } + } - /* count the DAG's */ - //count_dags_in_graph(global, entry); + /* some calculations are dependent, we pushed them on the wait_q */ + while (! pdeq_empty(status->wait_q)) { + entry = pdeq_getr(status->wait_q); + + update_graph_stat_2(global, entry); + } - /* calculate the pattern */ - stat_calc_pattern_history(entry->irg); + + /* dump per graph */ + for (entry = pset_first(status->irg_hash); entry; entry = pset_next(status->irg_hash)) { + + if (entry->irg == NULL) { + /* special entry for the global count */ + continue; } - stat_dump_graph(entry); + if (! entry->is_deleted || status->stat_options & FIRMSTAT_COUNT_DELETED) + stat_dump_graph(entry); - /* clear the counter that are not accumulated */ - graph_clear_entry(entry, 0); + if (! entry->is_deleted) { + /* clear the counter that are not accumulated */ + graph_clear_entry(entry, 0); + } } /* dump global */ @@ -1197,62 +1276,114 @@ void stat_finish(const char *name) } /* finished */ -// status->enable = 0; +// status->stat_options = 0; } STAT_LEAVE; } -#else - -/* need this for prototypes */ -#define FIRM_STATISTICS -#include "firmstat.h" +static hook_entry_t stat_hooks[hook_last]; -void init_stat(unsigned enable_options) {} - -void stat_finish(const char *name) {} - -void stat_new_ir_op(const ir_op *op) {} +/* 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 stat_free_ir_op(const ir_op *op) {} + /* enable statistics */ + status->stat_options = enable_options & FIRMSTAT_ENABLED ? enable_options : 0; -void stat_new_node(ir_node *node) {} + if (! status->stat_options) + return; -void stat_turn_into_id(ir_node *node) {} + /* 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_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_graph(ir_graph *irg, entity *ent) {} + obstack_init(&status->cnts); -void stat_free_graph(ir_graph *irg) {} + /* create the hash-tables */ + status->irg_hash = new_pset(graph_cmp, 8); + status->ir_op_hash = new_pset(opcode_cmp_2, 1); -void stat_irg_walk(ir_graph *irg, void *pre, void *post) {} + /* create the wait queue */ + status->wait_q = new_pdeq(); -void stat_irg_block_walk(ir_graph *irg, const ir_node *node, void *pre, void *post) {} + 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_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_PhiM.code = get_next_ir_opcode(); + _op_PhiM.name = new_id_from_chars(X("PhiM")); -void stat_reassociate(int start) {} + _op_ProjM.code = get_next_ir_opcode(); + _op_ProjM.name = new_id_from_chars(X("ProjM")); -void stat_lower(ir_node *node) {} + _op_MulC.code = get_next_ir_opcode(); + _op_MulC.name = new_id_from_chars(X("MulC")); -void stat_inline(ir_node *call, ir_graph *irg) {} + _op_DivC.code = get_next_ir_opcode(); + _op_DivC.name = new_id_from_chars(X("DivC")); -void stat_tail_rec(ir_graph *irg) {} + _op_ModC.code = get_next_ir_opcode(); + _op_ModC.name = new_id_from_chars(X("ModC")); -void stat_strength_red(ir_graph *irg, ir_node *strong, ir_node *cmp) {} + _op_DivModC.code = get_next_ir_opcode(); + _op_DivModC.name = new_id_from_chars(X("DivModC")); -void stat_dead_node_elim_start(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_dead_node_elim_stop(ir_graph *irg) {} + /* register the dumper */ + stat_register_dumper(&simple_dumper); -void stat_arch_dep_replace_mul_with_shifts(ir_node *mul) {} + if (enable_options & FIRMSTAT_CSV_OUTPUT) + stat_register_dumper(&csv_dumper); -void stat_arch_dep_replace_div_by_const(ir_node *div) {} + /* initialize the pattern hash */ + stat_init_pattern_history(enable_options & FIRMSTAT_PATTERN_ENABLED); +#undef HOOK +#undef X +} -void stat_arch_dep_replace_mod_by_const(ir_node *mod) {} +#else -void stat_arch_dep_replace_DivMod_by_const(ir_node *divmod) {} +/* Finish the statistics */ +void stat_finish(const char *name) {} -#endif +#endif /* FIRM_STATISTICS */