+ pc_ent->n_regs = n_regs;
+
+ /* update information */
+ ps_ent->size = size;
+ ps_ent->real_size = real_size;
+ }
+ STAT_LEAVE;
+} /* stat_be_block_stat_perm */
+
+/**
+ * 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);
+ } /* if */
+ }
+ STAT_LEAVE;
+} /* stat_be_block_stat_permcycle */
+
+/* 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;
+
+ STAT_ENTER;
+ {
+ graph_entry_t *entry;
+ graph_entry_t *global = graph_get_entry(NULL, status->irg_hash);
+
+ /*
+ * 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 /* _WIN32 */
+ if (p) {
+ ++p;
+ l = p - name;
+
+ if (l > (int) (sizeof(fname) - 1))
+ l = sizeof(fname) - 1;
+
+ memcpy(fname, name, l);
+ fname[l] = '\0';
+ } else {
+ fname[0] = '\0';
+ p = name;
+ } /* if */
+ 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)) {
+ if (entry->irg == NULL) {
+ /* special entry for the global count */
+ continue;
+ } /* if */
+ if (! entry->is_deleted) {
+ /* the graph is still alive, count the nodes on it */
+ update_graph_stat(global, entry);
+ } /* if */
+ } /* for */
+
+ /* 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);
+ } /* while */
+
+ /* 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;
+ } /* if */
+
+ if (! entry->is_deleted || status->stat_options & FIRMSTAT_COUNT_DELETED) {
+ stat_dump_graph(entry);
+ stat_dump_registered(entry);
+ } /* if */
+
+ if (! entry->is_deleted) {
+ /* clear the counter that are not accumulated */
+ graph_clear_entry(entry, 0);
+ } /* if */
+ } /* for */
+
+ /* dump global */
+ stat_dump_graph(global);
+
+ /* dump the const info */
+ if (status->stat_options & FIRMSTAT_COUNT_CONSTS)
+ stat_dump_consts(&status->const_info);
+
+ /* dump the parameter distribution */
+ stat_dump_param_tbl(status->dist_param_cnt, global);
+
+ /* dump the optimization counter and clear them */
+ stat_dump_opt_cnt(status->num_opts, ARR_SIZE(status->num_opts));
+ clear_optimization_counter();
+
+ stat_dump_finish();
+
+ stat_finish_pattern_history(fname);
+
+ /* clear the global counter here */
+ {
+ node_entry_t *entry;
+
+ for (entry = pset_first(global->opcode_hash); entry; entry = pset_next(global->opcode_hash)) {
+ opcode_clear_entry(entry);
+ } /* for */
+ /* clear all global counter */
+ graph_clear_entry(global, 1);
+ }
+ }
+ STAT_LEAVE;
+} /* stat_dump_snapshot */
+
+/** the hook entries for the Firm statistics module */
+static hook_entry_t stat_hooks[hook_last];
+
+/* initialize the statistics module. */
+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;
+
+ /* 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, 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);
+ status->ir_op_hash = new_pset(opcode_cmp_2, 1);
+
+ /* create the wait queue */
+ status->wait_q = new_pdeq();
+
+ if (enable_options & FIRMSTAT_COUNT_STRONG_OP) {
+ /* build the pseudo-ops */
+
+ _op_Phi0.code = --num;
+ _op_Phi0.name = new_id_from_chars(X("Phi0"));
+
+ _op_PhiM.code = --num;
+ _op_PhiM.name = new_id_from_chars(X("PhiM"));
+
+ _op_ProjM.code = --num;
+ _op_ProjM.name = new_id_from_chars(X("ProjM"));
+
+ _op_MulC.code = --num;
+ _op_MulC.name = new_id_from_chars(X("MulC"));
+
+ _op_DivC.code = --num;
+ _op_DivC.name = new_id_from_chars(X("DivC"));
+
+ _op_ModC.code = --num;
+ _op_ModC.name = new_id_from_chars(X("ModC"));
+
+ _op_DivModC.code = --num;
+ _op_DivModC.name = new_id_from_chars(X("DivModC"));
+
+ _op_QuotC.code = --num;
+ _op_QuotC.name = new_id_from_chars(X("QuotC"));
+
+ 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;
+ status->op_QuotC = &_op_QuotC;
+ } 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;
+ status->op_QuotC = NULL;
+ } /* if */
+
+ /* for Florian: count the Sel depth */
+ 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;
+ } /* if */
+
+ /* 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);
+
+ /* initialize the Const options */
+ if (enable_options & FIRMSTAT_COUNT_CONSTS)
+ stat_init_const_cnt(status);
+
+ /* distribution table for parameter counts */
+ status->dist_param_cnt = stat_new_int_distrib_tbl();
+
+ clear_optimization_counter();
+
+#undef HOOK
+#undef X
+} /* firm_init_stat */