X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fstat%2Ffirmstat.c;h=42dc887068b4d92b0011be2255cb528b0aec6b84;hb=f4966a36b81eb80781aa4478d3b4987cacb28c64;hp=38c777457f94fa70ff3394d283ba7e8218f4ded7;hpb=4b0d2820179bbbf6b2dc06223ed9d7ebfa547402;p=libfirm diff --git a/ir/stat/firmstat.c b/ir/stat/firmstat.c index 38c777457..42dc88706 100644 --- a/ir/stat/firmstat.c +++ b/ir/stat/firmstat.c @@ -119,7 +119,7 @@ static int opt_cmp(const void *elt, const void *key) } /** - * compare two elements of the block hash + * compare two elements of the block/extbb hash */ static int block_cmp(const void *elt, const void *key) { @@ -129,6 +129,50 @@ static int block_cmp(const void *elt, const void *key) return e1->block_nr != e2->block_nr; } +/** + * compare two elements of the be_block hash + */ +static int be_block_cmp(const void *elt, const void *key) +{ + const be_block_entry_t *e1 = elt; + const be_block_entry_t *e2 = key; + + return e1->block_nr != e2->block_nr; +} + +/** + * compare two elements of reg pressure hash + */ +static int reg_pressure_cmp(const void *elt, const void *key) +{ + const reg_pressure_entry_t *e1 = elt; + const reg_pressure_entry_t *e2 = key; + + return e1->class_name != e2->class_name; +} + +/** + * compare two elements of the perm_stat hash + */ +static int perm_stat_cmp(const void *elt, const void *key) +{ + const perm_stat_entry_t *e1 = elt; + const perm_stat_entry_t *e2 = key; + + return e1->perm != e2->perm; +} + +/** + * compare two elements of the perm_class hash + */ +static int perm_class_cmp(const void *elt, const void *key) +{ + const perm_class_entry_t *e1 = elt; + const perm_class_entry_t *e2 = key; + + return e1->class_name != e2->class_name; +} + /** * compare two elements of the ir_op hash */ @@ -221,6 +265,19 @@ static void graph_clear_entry(graph_entry_t *elem, int all) cnt_clr(&elem->cnt_all_calls); cnt_clr(&elem->cnt_call_with_cnst_arg); cnt_clr(&elem->cnt_indirect_calls); + + if (elem->block_hash) { + del_pset(elem->block_hash); + elem->block_hash = NULL; + } + + if (elem->extbb_hash) { + del_pset(elem->extbb_hash); + elem->extbb_hash = NULL; + } + + obstack_free(&elem->recalc_cnts, NULL); + obstack_init(&elem->recalc_cnts); } /** @@ -238,21 +295,31 @@ static graph_entry_t *graph_get_entry(ir_graph *irg, hmap_graph_entry_t *hmap) key.irg = irg; elem = pset_find(hmap, &key, HASH_PTR(irg)); - if (elem) + + if (elem) { + /* create hash map backend block information */ + if (! elem->be_block_hash) + elem->be_block_hash = new_pset(be_block_cmp, 5); + return elem; + } /* allocate a new one */ elem = obstack_alloc(&status->cnts, sizeof(*elem)); memset(elem, 0, sizeof(*elem)); + obstack_init(&elem->recalc_cnts); /* clear counter */ graph_clear_entry(elem, 1); /* new hash table for opcodes here */ - elem->opcode_hash = new_pset(opcode_cmp, 5); - elem->block_hash = new_pset(block_cmp, 5); - elem->address_mark = new_set(address_mark_cmp, 5); - elem->irg = irg; + elem->opcode_hash = new_pset(opcode_cmp, 5); + elem->address_mark = new_set(address_mark_cmp, 5); + elem->irg = irg; + + /* these hash tables are created on demand */ + elem->block_hash = NULL; + elem->extbb_hash = NULL; for (i = 0; i < sizeof(elem->opt_hash)/sizeof(elem->opt_hash[0]); ++i) elem->opt_hash[i] = new_pset(opt_cmp, 4); @@ -314,7 +381,7 @@ static void block_clear_entry(block_entry_t *elem) * @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, hmap_block_entry_t *hmap) +static block_entry_t *block_get_entry(struct obstack *obst, long block_nr, hmap_block_entry_t *hmap) { block_entry_t key; block_entry_t *elem; @@ -325,7 +392,7 @@ static block_entry_t *block_get_entry(long block_nr, hmap_block_entry_t *hmap) if (elem) return elem; - elem = obstack_alloc(&status->cnts, sizeof(*elem)); + elem = obstack_alloc(obst, sizeof(*elem)); memset(elem, 0, sizeof(*elem)); /* clear new counter */ @@ -336,6 +403,133 @@ static block_entry_t *block_get_entry(long block_nr, hmap_block_entry_t *hmap) return pset_insert(hmap, elem, block_nr); } +/** + * clears all sets in be_block_entry_t + */ +static void be_block_clear_entry(be_block_entry_t *elem) +{ + if (elem->reg_pressure) + del_pset(elem->reg_pressure); + + if (elem->sched_ready) + stat_delete_distrib_tbl(elem->sched_ready); + + if (elem->perm_class_stat) + del_pset(elem->perm_class_stat); + + elem->reg_pressure = new_pset(reg_pressure_cmp, 5); + elem->sched_ready = stat_new_int_distrib_tbl(); + elem->perm_class_stat = new_pset(perm_class_cmp, 5); +} + +/** + * Returns the associated be_block_entry_t for an block. + * + * @param block_nr an IR block number + * @param hmap a hash map containing long -> be_block_entry_t + */ +static be_block_entry_t *be_block_get_entry(struct obstack *obst, long block_nr, hmap_be_block_entry_t *hmap) +{ + be_block_entry_t key; + be_block_entry_t *elem; + + key.block_nr = block_nr; + + elem = pset_find(hmap, &key, block_nr); + if (elem) + return elem; + + elem = obstack_alloc(obst, sizeof(*elem)); + memset(elem, 0, sizeof(*elem)); + + /* clear new counter */ + be_block_clear_entry(elem); + + elem->block_nr = block_nr; + + return pset_insert(hmap, elem, block_nr); +} + +/** + * clears all sets in perm_class_entry_t + */ +static void perm_class_clear_entry(perm_class_entry_t *elem) { + if (elem->perm_stat) + del_pset(elem->perm_stat); + + elem->perm_stat = new_pset(perm_stat_cmp, 5); +} + +/** + * Returns the associated perm_class entry for a register class. + * + * @param class_name the register class name + * @param hmap a hash map containing class_name -> perm_class_entry_t + */ +static perm_class_entry_t *perm_class_get_entry(struct obstack *obst, const char *class_name, + hmap_perm_class_entry_t *hmap) +{ + perm_class_entry_t key; + perm_class_entry_t *elem; + + key.class_name = class_name; + + elem = pset_find(hmap, &key, HASH_PTR(class_name)); + if (elem) + return elem; + + elem = obstack_alloc(obst, sizeof(*elem)); + memset(elem, 0, sizeof(*elem)); + + /* clear new counter */ + perm_class_clear_entry(elem); + + elem->class_name = class_name; + + return pset_insert(hmap, elem, HASH_PTR(class_name)); +} + +/** + * clears all sets in perm_stat_entry_t + */ +static void perm_stat_clear_entry(perm_stat_entry_t *elem) { + if (elem->chains) + stat_delete_distrib_tbl(elem->chains); + + if (elem->cycles) + stat_delete_distrib_tbl(elem->cycles); + + elem->chains = stat_new_int_distrib_tbl(); + elem->cycles = stat_new_int_distrib_tbl(); +} + +/** + * Returns the associated perm_stat entry for a perm. + * + * @param perm the perm node + * @param hmap a hash map containing perm -> perm_stat_entry_t + */ +static perm_stat_entry_t *perm_stat_get_entry(struct obstack *obst, ir_node *perm, hmap_perm_stat_entry_t *hmap) +{ + perm_stat_entry_t key; + perm_stat_entry_t *elem; + + key.perm = perm; + + elem = pset_find(hmap, &key, HASH_PTR(perm)); + if (elem) + return elem; + + elem = obstack_alloc(obst, sizeof(*elem)); + memset(elem, 0, sizeof(*elem)); + + /* clear new counter */ + perm_stat_clear_entry(elem); + + elem->perm = perm; + + return pset_insert(hmap, elem, HASH_PTR(perm)); +} /** * Returns the ir_op for an IR-node, @@ -402,48 +596,47 @@ static void undate_block_info(ir_node *node, graph_entry_t *graph) /* check for block */ if (op == op_Block) { arity = get_irn_arity(node); - b_entry = block_get_entry(get_irn_node_nr(node), graph->block_hash); + b_entry = block_get_entry(&graph->recalc_cnts, get_irn_node_nr(node), graph->block_hash); /* count all incoming edges */ for (i = 0; i < arity; ++i) { ir_node *pred = get_irn_n(node, i); ir_node *other_block = get_nodes_block(pred); - block_entry_t *b_entry_other = block_get_entry(get_irn_node_nr(other_block), graph->block_hash); + block_entry_t *b_entry_other = block_get_entry(&graph->recalc_cnts, get_irn_node_nr(other_block), graph->block_hash); cnt_inc(&b_entry->cnt_in_edges); /* an edge coming from another block */ cnt_inc(&b_entry_other->cnt_out_edges); } 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); + block = get_nodes_block(node); + b_entry = block_get_entry(&graph->recalc_cnts, get_irn_node_nr(block), graph->block_hash); + + if (op == op_Phi && mode_is_datab(get_irn_mode(node))) { + /* count data Phi per block */ 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); - - /* we have a new nodes */ + /* we have a new node in our block */ cnt_inc(&b_entry->cnt_nodes); + /* don't count keep-alive edges */ + if (get_irn_op(node) == op_End) + return; + arity = get_irn_arity(node); for (i = 0; i < arity; ++i) { ir_node *pred = get_irn_n(node, i); ir_node *other_block; - if (get_irn_op(pred) == op_Block) - continue; - other_block = get_nodes_block(pred); if (other_block == block) cnt_inc(&b_entry->cnt_edges); /* a in block edge */ else { - block_entry_t *b_entry_other = block_get_entry(get_irn_node_nr(other_block), graph->block_hash); + block_entry_t *b_entry_other = block_get_entry(&graph->recalc_cnts, get_irn_node_nr(other_block), graph->block_hash); cnt_inc(&b_entry->cnt_in_edges); /* an edge coming from another block */ cnt_inc(&b_entry_other->cnt_out_edges); @@ -451,6 +644,69 @@ static void undate_block_info(ir_node *node, graph_entry_t *graph) } } +/** + * update the extended block counter + */ +static void undate_extbb_info(ir_node *node, graph_entry_t *graph) +{ + ir_op *op = get_irn_op(node); + ir_extblk *extbb; + extbb_entry_t *eb_entry; + int i, arity; + + /* check for block */ + if (op == op_Block) { + extbb = get_nodes_extbb(node); + arity = get_irn_arity(node); + eb_entry = block_get_entry(&graph->recalc_cnts, get_extbb_node_nr(extbb), graph->extbb_hash); + + /* count all incoming edges */ + for (i = 0; i < arity; ++i) { + ir_node *pred = get_irn_n(node, i); + ir_extblk *other_extbb = get_nodes_extbb(pred); + + if (extbb != other_extbb) { + extbb_entry_t *eb_entry_other = block_get_entry(&graph->recalc_cnts, get_extbb_node_nr(other_extbb), graph->extbb_hash); + + cnt_inc(&eb_entry->cnt_in_edges); /* an edge coming from another extbb */ + cnt_inc(&eb_entry_other->cnt_out_edges); + } + } + return; + } + + extbb = get_nodes_extbb(node); + eb_entry = block_get_entry(&graph->recalc_cnts, get_extbb_node_nr(extbb), graph->extbb_hash); + + if (op == op_Phi && mode_is_datab(get_irn_mode(node))) { + /* count data Phi per extbb */ + cnt_inc(&eb_entry->cnt_phi_data); + } + + /* we have a new node in our block */ + cnt_inc(&eb_entry->cnt_nodes); + + /* don't count keep-alive edges */ + if (get_irn_op(node) == op_End) + return; + + arity = get_irn_arity(node); + + for (i = 0; i < arity; ++i) { + ir_node *pred = get_irn_n(node, i); + ir_extblk *other_extbb = get_nodes_extbb(pred); + + if (other_extbb == extbb) + cnt_inc(&eb_entry->cnt_edges); /* a in extbb edge */ + else { + extbb_entry_t *eb_entry_other = block_get_entry(&graph->recalc_cnts, get_extbb_node_nr(other_extbb), graph->extbb_hash); + + cnt_inc(&eb_entry->cnt_in_edges); /* an edge coming from another extbb */ + cnt_inc(&eb_entry_other->cnt_out_edges); + } + } +} + /** calculates how many arguments of the call are const */ static int cnt_const_args(ir_node *call) { @@ -605,6 +861,12 @@ static void update_node_stat(ir_node *node, void *env) /* count block edges */ undate_block_info(node, graph); + /* count extended block edges */ + if (status->stat_options & FIRMSTAT_COUNT_EXTBB) { + if (graph->irg != get_const_code_irg()) + undate_extbb_info(node, graph); + } + /* handle statistics for special node types */ if (op == op_Const) { @@ -627,7 +889,7 @@ 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) + if (is_Call(node)) stat_update_call_2(node, graph); } @@ -741,15 +1003,27 @@ static void update_graph_stat(graph_entry_t *global, graph_entry_t *graph) graph->is_recursive = 0; graph->is_chain_call = 1; + /* create new block counter */ + graph->block_hash = new_pset(block_cmp, 5); + /* we need dominator info */ - if (graph->irg != get_const_code_irg()) - if (get_irg_dom_state(graph->irg) != dom_consistent) - compute_doms(graph->irg); + if (graph->irg != get_const_code_irg()) { + assure_doms(graph->irg); + + if (status->stat_options & FIRMSTAT_COUNT_EXTBB) { + /* we need extended basic blocks */ + compute_extbb(graph->irg); + + /* create new extbb counter */ + graph->extbb_hash = new_pset(block_cmp, 5); + } + } /* count the nodes in the graph */ irg_walk_graph(graph->irg, update_node_stat, NULL, graph); #if 0 + /* Uncomment this code if chain-call means call exact one */ entry = opcode_get_entry(op_Call, graph->opcode_hash); /* check if we have more than 1 call */ @@ -841,7 +1115,7 @@ static void stat_register_dumper(const dumper_t *dumper) dumper_t *p = xmalloc(sizeof(*p)); if (p) { - *p = *dumper; + memcpy(p, dumper, sizeof(*p)); p->next = status->dumper; p->status = status; @@ -864,6 +1138,23 @@ static void stat_dump_graph(graph_entry_t *entry) } } +/** + * calls all registered functions. + */ +static void stat_dump_registered(graph_entry_t *entry) +{ + dumper_t *dumper; + + for (dumper = status->dumper; dumper; dumper = dumper->next) { + if (dumper->func_map) { + dump_graph_FUNC func; + + foreach_pset(dumper->func_map, func) + func(dumper, entry); + } + } +} + /** * dumps a constant table */ @@ -903,6 +1194,19 @@ static void stat_dump_finish(void) } } +/** + * register an additional function for all dumper + */ +void stat_register_dumper_func(dump_graph_FUNC func) { + dumper_t *dumper; + + for (dumper = status->dumper; dumper; dumper = dumper->next) { + if (! dumper->func_map) + dumper->func_map = pset_new_ptr(3); + pset_insert_ptr(dumper->func_map, func); + } +} + /* ---------------------------------------------------------------------- */ /* @@ -1283,7 +1587,7 @@ static void stat_tail_rec(void *ctx, ir_graph *irg, int n_calls) * * @param ctx the hook context */ -static void stat_strength_red(void *ctx, ir_graph *irg, ir_node *strong, ir_node *cmp) +static void stat_strength_red(void *ctx, ir_graph *irg, ir_node *strong) { if (! status->stat_options) return; @@ -1299,29 +1603,19 @@ static void stat_strength_red(void *ctx, ir_graph *irg, ir_node *strong, ir_node } /** - * Start the dead node elimination. + * Start/Stop the dead node elimination. * * @param ctx the hook context */ -static void stat_dead_node_elim_start(void *ctx, ir_graph *irg) +static void stat_dead_node_elim(void *ctx, ir_graph *irg, int start) { if (! status->stat_options) return; - ++status->in_dead_node_elim; -} - -/** - * Stops the dead node elimination. - * - * @param ctx the hook context - */ -static void stat_dead_node_elim_stop(void *ctx, ir_graph *irg) -{ - if (! status->stat_options) - return; - - --status->in_dead_node_elim; + if (start) + ++status->in_dead_node_elim; + else + --status->in_dead_node_elim; } /** @@ -1378,12 +1672,12 @@ static void stat_arch_dep_replace_mul_with_shifts(void *ctx, ir_node *mul) } /** - * A division was replaced by a series of Shifts/Muls + * A division by const was replaced * - * @param ctx the hook context - * @param div the div node that will be optimized + * @param ctx the hook context + * @param node the division node that will be optimized */ -static void stat_arch_dep_replace_div_by_const(void *ctx, ir_node *div) +static void stat_arch_dep_replace_division_by_const(void *ctx, ir_node *node) { if (! status->stat_options) return; @@ -1391,45 +1685,138 @@ static void stat_arch_dep_replace_div_by_const(void *ctx, 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[HOOK_OPT_ARCH_DEP]); + removed_due_opt(node, graph->opt_hash[HOOK_OPT_ARCH_DEP]); } STAT_LEAVE; } +/* + * Update the register pressure of a block + * + * @param irg the irg containing the block + * @param block the block for which the reg pressure should be set + * @param pressure the pressure + * @param class_name the name of the register class + */ +void stat_be_block_regpressure(ir_graph *irg, ir_node *block, int pressure, const char *class_name) +{ + if (! status->stat_options) + return; + + STAT_ENTER; + { + graph_entry_t *graph = graph_get_entry(irg, status->irg_hash); + be_block_entry_t *block_ent; + reg_pressure_entry_t *rp_ent; + + block_ent = be_block_get_entry(&status->be_data, get_irn_node_nr(block), graph->be_block_hash); + rp_ent = obstack_alloc(&status->be_data, sizeof(*rp_ent)); + memset(rp_ent, 0, sizeof(*rp_ent)); + + rp_ent->class_name = class_name; + rp_ent->pressure = pressure; + + pset_insert(block_ent->reg_pressure, rp_ent, HASH_PTR(class_name)); + } + STAT_LEAVE; +} + /** - * A modulo was replaced by a series of Shifts/Muls + * Update the distribution of ready nodes of a block * - * @param ctx the hook context - * @param mod the mod node that will be optimized + * @param irg the irg containing the block + * @param block the block for which the reg pressure should be set + * @param num_ready the number of ready nodes */ -static void stat_arch_dep_replace_mod_by_const(void *ctx, ir_node *mod) +void stat_be_block_sched_ready(ir_graph *irg, ir_node *block, int num_ready) { 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[HOOK_OPT_ARCH_DEP]); + graph_entry_t *graph = graph_get_entry(irg, status->irg_hash); + be_block_entry_t *block_ent; + + block_ent = be_block_get_entry(&status->be_data, get_irn_node_nr(block), graph->be_block_hash); + + /* increase the counter of corresponding number of ready nodes */ + stat_inc_int_distrib_tbl(block_ent->sched_ready, num_ready); } STAT_LEAVE; } /** - * A DivMod was replaced by a series of Shifts/Muls + * Update the permutation statistic of a block * - * @param ctx the hook context - * @param divmod the divmod node that will be optimized + * @param class_name the name of the register class + * @param n_regs number of registers in the register class + * @param perm the perm node + * @param block the block containing the perm + * @param size the size of the perm + * @param real_size number of pairs with different registers */ -static void stat_arch_dep_replace_DivMod_by_const(void *ctx, ir_node *divmod) +void stat_be_block_stat_perm(const char *class_name, int n_regs, ir_node *perm, ir_node *block, + int size, int real_size) { 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[HOOK_OPT_ARCH_DEP]); + graph_entry_t *graph = graph_get_entry(get_irn_irg(block), status->irg_hash); + be_block_entry_t *block_ent; + perm_class_entry_t *pc_ent; + perm_stat_entry_t *ps_ent; + + block_ent = be_block_get_entry(&status->be_data, get_irn_node_nr(block), graph->be_block_hash); + pc_ent = perm_class_get_entry(&status->be_data, class_name, block_ent->perm_class_stat); + ps_ent = perm_stat_get_entry(&status->be_data, perm, pc_ent->perm_stat); + + pc_ent->n_regs = n_regs; + + /* update information */ + ps_ent->size = size; + ps_ent->real_size = real_size; + } + STAT_LEAVE; +} + +/** + * Update the permutation statistic of a single perm + * + * @param class_name the name of the register class + * @param perm the perm node + * @param block the block containing the perm + * @param is_chain 1 if chain, 0 if cycle + * @param size length of the cycle/chain + * @param n_ops the number of ops representing this cycle/chain after lowering + */ +void stat_be_block_stat_permcycle(const char *class_name, ir_node *perm, ir_node *block, + int is_chain, int size, int n_ops) +{ + if (! status->stat_options) + return; + + STAT_ENTER; + { + graph_entry_t *graph = graph_get_entry(get_irn_irg(block), status->irg_hash); + be_block_entry_t *block_ent; + perm_class_entry_t *pc_ent; + perm_stat_entry_t *ps_ent; + + block_ent = be_block_get_entry(&status->be_data, get_irn_node_nr(block), graph->be_block_hash); + pc_ent = perm_class_get_entry(&status->be_data, class_name, block_ent->perm_class_stat); + ps_ent = perm_stat_get_entry(&status->be_data, perm, pc_ent->perm_stat); + + if (is_chain) { + ps_ent->n_copies += n_ops; + stat_inc_int_distrib_tbl(ps_ent->chains, size); + } + else { + ps_ent->n_exchg += n_ops; + stat_inc_int_distrib_tbl(ps_ent->cycles, size); + } } STAT_LEAVE; } @@ -1521,8 +1908,10 @@ void stat_dump_snapshot(const char *name, const char *phase) continue; } - if (! entry->is_deleted || status->stat_options & FIRMSTAT_COUNT_DELETED) + if (! entry->is_deleted || status->stat_options & FIRMSTAT_COUNT_DELETED) { stat_dump_graph(entry); + stat_dump_registered(entry); + } if (! entry->is_deleted) { /* clear the counter that are not accumulated */ @@ -1559,11 +1948,12 @@ void stat_dump_snapshot(const char *name, const char *phase) static hook_entry_t stat_hooks[hook_last]; /* initialize the statistics module. */ -void init_stat(unsigned enable_options) +void firm_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]) + unsigned num = 0; if (! (enable_options & FIRMSTAT_ENABLED)) return; @@ -1575,31 +1965,29 @@ void init_stat(unsigned enable_options) status->stat_options = enable_options & FIRMSTAT_ENABLED ? enable_options : 0; /* 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); + 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, stat_dead_node_elim); + 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_division_by_const, stat_arch_dep_replace_division_by_const); obstack_init(&status->cnts); + obstack_init(&status->be_data); /* create the hash-tables */ status->irg_hash = new_pset(graph_cmp, 8); @@ -1610,25 +1998,26 @@ void init_stat(unsigned enable_options) if (enable_options & FIRMSTAT_COUNT_STRONG_OP) { /* build the pseudo-ops */ - _op_Phi0.code = get_next_ir_opcode(); + + _op_Phi0.code = --num; _op_Phi0.name = new_id_from_chars(X("Phi0")); - _op_PhiM.code = get_next_ir_opcode(); + _op_PhiM.code = --num; _op_PhiM.name = new_id_from_chars(X("PhiM")); - _op_ProjM.code = get_next_ir_opcode(); + _op_ProjM.code = --num; _op_ProjM.name = new_id_from_chars(X("ProjM")); - _op_MulC.code = get_next_ir_opcode(); + _op_MulC.code = --num; _op_MulC.name = new_id_from_chars(X("MulC")); - _op_DivC.code = get_next_ir_opcode(); + _op_DivC.code = --num; _op_DivC.name = new_id_from_chars(X("DivC")); - _op_ModC.code = get_next_ir_opcode(); + _op_ModC.code = --num; _op_ModC.name = new_id_from_chars(X("ModC")); - _op_DivModC.code = get_next_ir_opcode(); + _op_DivModC.code = --num; _op_DivModC.name = new_id_from_chars(X("DivModC")); status->op_Phi0 = &_op_Phi0; @@ -1650,10 +2039,10 @@ void init_stat(unsigned enable_options) } if (enable_options & FIRMSTAT_COUNT_SELS) { - _op_SelSel.code = get_next_ir_opcode(); + _op_SelSel.code = --num; _op_SelSel.name = new_id_from_chars(X("Sel(Sel)")); - _op_SelSelSel.code = get_next_ir_opcode(); + _op_SelSelSel.code = --num; _op_SelSelSel.name = new_id_from_chars(X("Sel(Sel(Sel))")); status->op_SelSel = &_op_SelSel; @@ -1681,18 +2070,45 @@ void init_stat(unsigned enable_options) #undef X } +/** + * Frees all dumper structures; + */ +static void stat_term_dumper() { + dumper_t *dumper, *next_dumper; + + for (dumper = status->dumper; dumper; /* iteration done in loop body */ ) { + if (dumper->func_map) + del_pset(dumper->func_map); + + next_dumper = dumper->next; + free(dumper); + dumper = next_dumper; + } +} + + /* terminates the statistics module, frees all memory */ void stat_term(void) { if (status != (stat_info_t *)&status_disable) { + obstack_free(&status->be_data, NULL); + obstack_free(&status->cnts, NULL); + + stat_term_dumper(); + xfree(status); status = (stat_info_t *)&status_disable; } } +/* returns 1 if statistics were initialized, 0 otherwise */ +int stat_is_active(void) { + return status != (stat_info_t *)&status_disable; +} + #else /* initialize the statistics module. */ -void init_stat(unsigned enable_options) {} +void firm_init_stat(unsigned enable_options) {} /* Dumps a statistics snapshot */ void stat_dump_snapshot(const char *name, const char *phase) {}