X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=ir%2Fstat%2Ffirmstat.c;h=42dc887068b4d92b0011be2255cb528b0aec6b84;hb=9d1fda9a8933dda2c16e90f1528b68d6d8c34685;hp=1bac51828a949465d5d7fc3a91032a21032174ba;hpb=184602875611495e608c27263d0a5a8f24078a70;p=libfirm diff --git a/ir/stat/firmstat.c b/ir/stat/firmstat.c index 1bac51828..42dc88706 100644 --- a/ir/stat/firmstat.c +++ b/ir/stat/firmstat.c @@ -62,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. */ @@ -76,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 @@ -112,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) { @@ -122,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 */ @@ -173,6 +224,7 @@ static node_entry_t *opcode_get_entry(const ir_op *op, hmap_node_entry_t *hmap) return elem; elem = obstack_alloc(&status->cnts, sizeof(*elem)); + memset(elem, 0, sizeof(*elem)); /* clear counter */ opcode_clear_entry(elem); @@ -207,11 +259,25 @@ 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); + + 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); } /** @@ -229,20 +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); @@ -276,6 +353,7 @@ static opt_entry_t *opt_get_entry(const ir_op *op, hmap_opt_entry_t *hmap) return elem; elem = obstack_alloc(&status->cnts, sizeof(*elem)); + memset(elem, 0, sizeof(*elem)); /* clear new counter */ opt_clear_entry(elem); @@ -294,6 +372,7 @@ 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); } /** @@ -302,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; @@ -313,7 +392,8 @@ 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 */ block_clear_entry(elem); @@ -323,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, @@ -363,6 +570,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; } @@ -380,13 +596,13 @@ 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); @@ -395,26 +611,32 @@ static void undate_block_info(ir_node *node, graph_entry_t *graph) } block = get_nodes_block(node); - b_entry = block_get_entry(get_irn_node_nr(block), graph->block_hash); + b_entry = block_get_entry(&graph->recalc_cnts, get_irn_node_nr(block), graph->block_hash); - /* we have a new nodes */ + if (op == op_Phi && mode_is_datab(get_irn_mode(node))) { + /* count data Phi per block */ + cnt_inc(&b_entry->cnt_phi_data); + } + + /* 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); @@ -422,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) { @@ -444,7 +729,7 @@ static int cnt_const_args(ir_node *call) * @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); @@ -521,7 +806,7 @@ static void update_call_stat(ir_node *call, graph_entry_t *graph) /** * 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); @@ -576,9 +861,24 @@ static void update_node_stat(ir_node *node, void *env) /* count block edges */ 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); + /* 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) { + 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); + } } /** @@ -589,8 +889,8 @@ 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); + if (is_Call(node)) + stat_update_call_2(node, graph); } /** @@ -682,7 +982,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 @@ -703,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 */ @@ -739,7 +1051,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; @@ -773,7 +1085,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 @@ -803,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; @@ -826,6 +1138,36 @@ 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 + */ +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 */ @@ -852,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); + } +} + /* ---------------------------------------------------------------------- */ /* @@ -1033,7 +1388,7 @@ static void stat_free_graph(void *ctx, ir_graph *irg) * @param pre the pre walker * @param post the post walker */ -static void stat_irg_walk(void *ctx, 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; @@ -1055,7 +1410,7 @@ static void stat_irg_walk(void *ctx, ir_graph *irg, void *pre, void *post) * @param pre the pre walker * @param post the post walker */ -static void stat_irg_walk_blkwise(void *ctx, 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(ctx, irg, pre, post); @@ -1070,7 +1425,7 @@ static void stat_irg_walk_blkwise(void *ctx, ir_graph *irg, void *pre, void *pos * @param pre the pre walker * @param post the post walker */ -static void stat_irg_block_walk(void *ctx, ir_graph *irg, 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; @@ -1128,7 +1483,17 @@ static 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]); } } } @@ -1203,13 +1568,16 @@ static void stat_inline(void *ctx, ir_node *call, ir_graph *called_irg) * * @param ctx the hook context */ -static void stat_tail_rec(void *ctx, 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; } @@ -1219,7 +1587,7 @@ static void stat_tail_rec(void *ctx, ir_graph *irg) * * @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; @@ -1235,29 +1603,54 @@ 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; + if (start) + ++status->in_dead_node_elim; + else + --status->in_dead_node_elim; } /** - * Stops the dead node elimination. - * - * @param ctx the hook context + * if-conversion was tried */ -static void stat_dead_node_elim_stop(void *ctx, ir_graph *irg) +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; - --status->in_dead_node_elim; + 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; } /** @@ -1279,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; @@ -1292,52 +1685,149 @@ 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; +} + +/** + * Update the distribution of ready nodes of a block + * + * @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 + */ +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(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 modulo was replaced by a series of Shifts/Muls + * Update the permutation statistic of a block * - * @param ctx the hook context - * @param mod the mod 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_mod_by_const(void *ctx, ir_node *mod) +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(mod, 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; } /** - * A DivMod was replaced by a series of Shifts/Muls + * Update the permutation statistic of a single perm * - * @param ctx the hook context - * @param divmod the divmod node that will be optimized + * @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 */ -static void stat_arch_dep_replace_DivMod_by_const(void *ctx, ir_node *divmod) +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(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); + + 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; } -/* 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; @@ -1346,7 +1836,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)) { @@ -1378,8 +1908,10 @@ void stat_finish(const char *name) 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 */ @@ -1389,6 +1921,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(); @@ -1403,9 +1940,6 @@ void stat_finish(const char *name) /* clear all global counter */ graph_clear_entry(global, 1); } - - /* finished */ -// status->stat_options = 0; } STAT_LEAVE; } @@ -1414,42 +1948,46 @@ void stat_finish(const char *name) 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; + + status = xmalloc(sizeof(*status)); + memset(status, 0, sizeof(*status)); /* enable statistics */ status->stat_options = enable_options & FIRMSTAT_ENABLED ? enable_options : 0; - if (! status->stat_options) - return; - /* 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); + 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); @@ -1460,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; @@ -1499,6 +2038,21 @@ void init_stat(unsigned enable_options) status->op_DivModC = NULL; } + if (enable_options & FIRMSTAT_COUNT_SELS) { + _op_SelSel.code = --num; + _op_SelSel.name = new_id_from_chars(X("Sel(Sel)")); + + _op_SelSelSel.code = --num; + _op_SelSelSel.name = new_id_from_chars(X("Sel(Sel(Sel))")); + + status->op_SelSel = &_op_SelSel; + status->op_SelSelSel = &_op_SelSelSel; + } + else { + status->op_SelSel = NULL; + status->op_SelSelSel = NULL; + } + /* register the dumper */ stat_register_dumper(&simple_dumper); @@ -1507,13 +2061,59 @@ void init_stat(unsigned enable_options) /* initialize the pattern hash */ stat_init_pattern_history(enable_options & FIRMSTAT_PATTERN_ENABLED); + + /* initialize the Const options */ + if (enable_options & FIRMSTAT_COUNT_CONSTS) + stat_init_const_cnt(status); + #undef HOOK #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 -/* Finish the statistics */ -void stat_finish(const char *name) {} +/* initialize the statistics module. */ +void firm_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 */