/** 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. */
/**
* 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
return elem;
elem = obstack_alloc(&status->cnts, sizeof(*elem));
+ memset(elem, 0, sizeof(*elem));
/* clear counter */
opcode_clear_entry(elem);
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);
/* allocate a new one */
elem = obstack_alloc(&status->cnts, sizeof(*elem));
+ memset(elem, 0, sizeof(*elem));
/* clear counter */
graph_clear_entry(elem, 1);
return elem;
elem = obstack_alloc(&status->cnts, sizeof(*elem));
+ memset(elem, 0, sizeof(*elem));
/* clear new counter */
opt_clear_entry(elem);
cnt_clr(&elem->cnt_edges);
cnt_clr(&elem->cnt_in_edges);
cnt_clr(&elem->cnt_out_edges);
+ cnt_clr(&elem->cnt_phi_data);
}
/**
return elem;
elem = obstack_alloc(&status->cnts, sizeof(*elem));
+ memset(elem, 0, sizeof(*elem));
/* clear new counter */
block_clear_entry(elem);
/* 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;
}
}
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);
* @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);
/**
* 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);
/* 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);
+ /* 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);
+ }
}
/**
/* 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);
}
/**
}
/**
- * 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
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;
}
/**
- * 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
}
}
+/**
+ * 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
*/
* @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;
* @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);
* @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;
/* 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]);
}
}
}
*
* @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;
}
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
*
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;
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)) {
/* 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();
/* clear all global counter */
graph_clear_entry(global, 1);
}
-
- /* finished */
-// status->stat_options = 0;
}
STAT_LEAVE;
}
#define HOOK(h, fkt) \
stat_hooks[h].hook._##h = fkt; register_hook(h, &stat_hooks[h])
+ 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_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);
status->op_DivModC = NULL;
}
+ if (enable_options & FIRMSTAT_COUNT_SELS) {
+ _op_SelSel.code = get_next_ir_opcode();
+ _op_SelSel.name = new_id_from_chars(X("Sel(Sel)"));
+
+ _op_SelSelSel.code = get_next_ir_opcode();
+ _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);
/* 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
}
+/* 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
-/* Finish the statistics */
-void stat_finish(const char *name) {}
+/* 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 */