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
*/
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));
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,
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);
}
}
/**
- * 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;
}
/**
}
/**
- * 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;
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;
}
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->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);
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;
}
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;
/* 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);
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) {}