* just be make some things clear :-), the
* poor man "generics"
*/
-#define HASH_MAP(type) pset_##type
+#define HASH_MAP(type) hmap_##type
-typedef pset pset_node_entry_t;
-typedef pset pset_graph_entry_t;
-typedef pset pset_opt_entry_t;
-typedef pset pset_block_entry_t;
+typedef pset hmap_node_entry_t;
+typedef pset hmap_graph_entry_t;
+typedef pset hmap_opt_entry_t;
+typedef pset hmap_block_entry_t;
+typedef pset hmap_ir_op;
/*
- * An entry for ir_nodes
+ * An entry for ir_nodes, used in ir_graph statistics.
*/
typedef struct _node_entry_t {
counter_t cnt_alive; /**< amount of nodes in this entry */
typedef struct _statistic_info_t {
struct obstack cnts; /**< obstack containing the counters */
HASH_MAP(graph_entry_t) *irg_hash; /**< hash map containing the counter for irgs */
+ HASH_MAP(ir_op) *ir_op_hash; /**< hash map containing all ir_ops (accessible by op_codes) */
int recursive; /**< flag for detecting recursive hook calls */
int in_dead_node_elim; /**< set, if dead node elimination runs */
ir_op *op_Phi0; /**< needed pseudo op */
return e1->block_nr != e2->block_nr;
}
+/**
+ * compare two elements of the ir_op hash
+ */
+static int opcode_cmp_2(const void *elt, const void *key)
+{
+ const ir_op *e1 = elt;
+ const ir_op *e2 = key;
+
+ return e1->code != e2->code;
+}
+
/**
* Returns the associates node_entry_t for an ir_op
*/
return pset_insert(set, elem, op->code);
}
+/**
+ * Returns the associates ir_op for an opcode
+ */
+static ir_op *opcode_find_entry(opcode code, pset *set)
+{
+ ir_op key;
+
+ key.code = code;
+ return pset_find(set, &key, code);
+}
+
/**
* calculates a hash value for an irg
* Addresses are typically aligned at 32bit, so we ignore the lowest bits
/* ---------------------------------------------------------------------- */
+/*
+ * helper: get an ir_op from an opcode
+ */
+ir_op *stat_get_op_from_opcode(opcode code)
+{
+ return opcode_find_entry(code, status->ir_op_hash);
+}
+
/* initialize the statistics module. */
void stat_init(void)
{
/* create the hash-tables */
status->irg_hash = new_pset(graph_cmp, 8);
+ status->ir_op_hash = new_pset(opcode_cmp_2, 1);
status->op_Phi0 = &_op_Phi0;
status->op_PhiM = &_op_PhiM;
stat_register_dumper(&csv_dumper, "firmstat.csv");
/* initialize the pattern hash */
- stat_init_pattern_history(status->enable & 0);
+ stat_init_pattern_history(status->enable);
#undef X
}
/* execute for side effect :-) */
opcode_get_entry(op, graph->opcode_hash);
+
+ pset_insert(status->ir_op_hash, op, op->code);
}
STAT_LEAVE;
}
STAT_LEAVE;
}
+/*
+ * A walk over a graph in block-wise order is initiated. Do not count walks from statistic code.
+ */
+void stat_irg_walk_blkwise(ir_graph *irg, void *pre, void *post)
+{
+ /* for now, do NOT differentiate between blockwise and normal */
+ stat_irg_walk(irg, pre, post);
+}
+
/*
* A walk over the graph's blocks is initiated. Do not count walks from statistic code.
*/
#include "irnode.h"
#include "irgraph.h"
+/**
+ * Finish the statistics.
+ * Never called from libFirm should be called from user.
+ */
+void stat_finish(void);
+
#ifdef FIRM_STATISTICS
typedef enum {
*/
void stat_init(void);
-/**
- * Finish the statistics.
- */
-void stat_finish(void);
-
/**
* A new IR op is registered.
*/
*/
void stat_irg_walk(ir_graph *irg, void *pre, void *post);
+/**
+ * A walk over a graph in block-wise order is initiated
+ */
+void stat_irg_walk_blkwise(ir_graph *irg, void *pre, void *post);
+
/**
* A walk over the graph's blocks is initiated
*/
*/
void stat_dead_node_elim_stop(ir_graph *irg);
+/**
+ * helper: get an ir_op from an opcode
+ *
+ * @param code the opcode
+ *
+ * @return The associated ir_op or NULL if the opcode could not be found.
+ */
+ir_op *stat_get_op_from_opcode(opcode code);
+
#else
#define stat_init()
-#define stat_finish()
#define stat_new_ir_op(op)
#define stat_free_ir_op(op)
#define stat_new_node(node)
#define stat_new_graph(irg, ent)
#define stat_free_graph(irg)
#define stat_irg_walk(irg, pre, post)
+#define stat_irg_walk_blkwise(irg, pre, post)
#define stat_irg_block_walk(irg, node, pre, post)
#define stat_merge_nodes(new_node_array, new_num_entries, old_node_array, old_num_entries, opt)
#define stat_lower(node)
VLC_32BIT = 0xF0, /**< 40 bit code, carrying 32 bits payload */
VLC_TAG_FIRST = 0xF1, /**< first possible tag value */
+ VLC_TAG_ICONST = 0xFB, /**< encodes an integer constant */
VLC_TAG_EMPTY = 0xFC, /**< encodes an empty entity */
VLC_TAG_OPTION = 0xFD, /**< options exists */
VLC_TAG_REF = 0xFE, /**< special tag, next code is an ID */
* current options
*/
enum options_t {
- OPT_WITH_MODE = 0x00000001, /**< use modes */
- OPT_ENC_GRAPH = 0x00000002, /**< encode graphs, not terms */
+ OPT_WITH_MODE = 0x00000001, /**< use modes */
+ OPT_ENC_GRAPH = 0x00000002, /**< encode graphs, not terms */
+ OPT_WITH_ICONST = 0x00000004, /**< encode integer constants */
};
set_entry *s_entry;
int i, preds;
-#if 0
opcode code = get_irn_opcode(node);
-#else
- ir_op *code = get_irn_op(node);
-#endif
/* insert the node into our ID map */
entry.addr = node;
put_code(env->buf, (unsigned)code);
+ /* do we need the mode ? */
if (env->options & OPT_WITH_MODE) {
ir_mode *mode = get_irn_mode(node);
put_tag(env->buf, VLC_TAG_EMPTY);
}
+ /* do we need integer constants */
+ if (env->options & OPT_WITH_ICONST) {
+ if (code == iro_Const) {
+ tarval *tv = get_Const_tarval(node);
+
+ if (tarval_is_long(tv)) {
+ long v = tarval_to_long(tv);
+
+ put_tag(env->buf, VLC_TAG_ICONST);
+ put_code(env->buf, v);
+ }
+ }
+ }
+
--max_depth;
if (max_depth <= 0) {
unsigned code;
unsigned op_code;
unsigned mode_code = 0;
+ long iconst;
+ int have_iconst = 0;
code = next_tag(env->buf);
if (code == VLC_TAG_REF) { /* it's a REF */
}
}
+ if (next_tag(env->buf) == VLC_TAG_ICONST) {
+ iconst = get_code(env->buf);
+ have_iconst = 1;
+ }
+
/* dump the edge */
if (parent)
pattern_dump_edge(env->dmp, env->curr_id, parent, position);
/* dump the node */
parent = env->curr_id;
- pattern_dump_node(env->dmp, parent, op_code, mode_code);
+ pattern_dump_node(env->dmp, parent, op_code, mode_code, have_iconst ? &iconst : NULL);
/* ok, we have a new ID */
++env->curr_id;
/**
* decode an IR-node
*/
-static void decode_node(BYTE *b, unsigned len)
+static void decode_node(BYTE *b, unsigned len, pattern_dumper_t *dump)
{
codec_env_t env;
CODE_BUFFER buf;
env.buf = &buf;
env.curr_id = 1; /* 0 is used for special purpose */
- env.dmp = &stdout_dump;
+ env.dmp = dump;
/* decode options */
code = next_tag(&buf);
}
/**
+ * output the collected pattern
*/
static void pattern_output(void)
{
- pattern_entry_t *entry;
- pattern_entry_t **pattern_arr;
+ pattern_entry_t *entry;
+ pattern_entry_t **pattern_arr;
+ pattern_dumper_t *dump;
int i, count = pset_count(status->pattern_hash);
printf("\n%d pattern detected\n", count);
if (count <= 0)
return;
+ /* creates a dumper */
+ dump = new_vcg_dumper("pattern.vcg", 100);
+
pattern_arr = xmalloc(sizeof(*pattern_arr) * count);
for (i = 0, entry = pset_first(status->pattern_hash);
entry && i < count;
if (entry->count.cnt[0] < status->bound)
continue;
- printf("%8d\t", entry->count.cnt[0]);
- decode_node(entry->buf, entry->len);
- printf("\n");
+ /* dump a pattern */
+ pattern_dump_new_pattern(dump, &entry->count);
+ decode_node(entry->buf, entry->len, dump);
+ pattern_dump_finish_pattern(dump);
}
+
+ /* destroy it */
+ pattern_end(dump);
}
/*
if (irg == get_const_code_irg())
return;
- env.max_depth = 4;
+ env.max_depth = 5;
irg_walk_graph(irg, calc_nodes_pattern, NULL, &env);
}
if (! enable)
return;
- status->bound = 3;
- status->options = OPT_WITH_MODE | OPT_ENC_GRAPH;
+ status->bound = 10;
+ status->options = OPT_WITH_MODE | OPT_ENC_GRAPH | OPT_WITH_ICONST;
obstack_init(&status->obst);
#endif
#include <stdio.h>
+#include <stdlib.h>
#include "ident.h"
#include "irop_t.h"
#include "irmode.h"
+#include "firmstat.h"
#include "pattern_dmp.h"
-FILE *f;
+/* dumper operations */
+typedef void (*DUMP_NEW_PATTERN_FUNC)(pattern_dumper_t *self, counter_t *cnt);
+typedef void (*DUMP_FINISH_PATTERN_FUNC)(pattern_dumper_t *self);
+typedef void (*DUMP_NODE_FUNC)(pattern_dumper_t *self, unsigned id, unsigned op_code, unsigned mode_code, void *attr);
+typedef void (*DUMP_REF_FUNC)(pattern_dumper_t *self, unsigned id);
+typedef void (*DUMP_EDGE_FUNC)(pattern_dumper_t *self, unsigned id, unsigned parent, unsigned position);
+typedef void (*DUMP_START_CHILDREN_FUNC)(pattern_dumper_t *self, unsigned id);
+typedef void (*DUMP_FINISH_CHILDREN_FUNC)(pattern_dumper_t *self, unsigned id);
+typedef void (*DUMP_START_FUNC)(pattern_dumper_t *self);
+typedef void (*DUMP_END_FUNC)(pattern_dumper_t *self);
+
+/**
+ * the pattern dumper
+ */
+struct _pattern_dumper_t {
+ DUMP_NEW_PATTERN_FUNC dump_new_pattern;
+ DUMP_FINISH_PATTERN_FUNC dump_finish_pattern;
+ DUMP_NODE_FUNC dump_node;
+ DUMP_REF_FUNC dump_ref;
+ DUMP_EDGE_FUNC dump_edge;
+ DUMP_START_CHILDREN_FUNC dump_start_children;
+ DUMP_FINISH_CHILDREN_FUNC dump_finish_children;
+ DUMP_START_FUNC dump_start;
+ DUMP_END_FUNC dump_end;
+ void *data;
+};
+
+/**
+ * VCG private data
+ */
+typedef struct _vcg_private_t {
+ FILE *f; /**< file to dump to */
+ unsigned pattern_id; /**< ID of the pattern */
+ unsigned max_pattern; /**< maximum number of pattern to be dumped */
+} vcg_private_t;
/**
* starts a new VCG graph
*/
static void vcg_dump_start(pattern_dumper_t *self)
{
- f = fopen("firmpattern.vcg", "w");
+ vcg_private_t *priv = self->data;
- fprintf(f,
+ fprintf(priv->f,
"graph: { title: \"Most found pattern\"\n"
" display_edge_labels: no\n"
" layoutalgorithm: mindepth\n"
*/
static void vcg_dump_end(pattern_dumper_t *self)
{
- fprintf(f, "}\n");
- fclose(f);
+ vcg_private_t *priv = self->data;
+
+ fprintf(priv->f, "}\n");
+ fclose(priv->f);
}
/*
*/
static void vcg_dump_new_pattern(pattern_dumper_t *self, counter_t *cnt)
{
- fprintf(f,
- " graph: { title: \"pattern cnt %u\"\n", cnt->cnt[0]
- );
+ vcg_private_t *priv = self->data;
+ static unsigned nr = 0;
+
+ if (priv->pattern_id > priv->max_pattern)
+ return;
+ fprintf(priv->f,
+ " graph: { title: \"g%u\" label: \"pattern %u\" status:clustered color:yellow\n",
+ priv->pattern_id, priv->pattern_id );
+
+ /** add a pseudo node */
+ fprintf(priv->f,
+ " node: {title: \"c%u\" label: \"cnt: %u\" color:red }\n",
+ ++nr, cnt->cnt[0]
+ );
}
/**
*/
static void vcg_dump_finish_pattern(pattern_dumper_t *self)
{
- fprintf(f, " }\n");
-}
+ vcg_private_t *priv = self->data;
+
+ if (priv->pattern_id > priv->max_pattern)
+ return;
+
+ fprintf(priv->f, " }\n");
+ if (priv->pattern_id > 0)
+ fprintf(priv->f, " edge: { sourcename: \"g%u\" targetname: \"g%u\"}\n",
+ priv->pattern_id,
+ priv->pattern_id - 1);
+ ++priv->pattern_id;
+}
+
+/**
+ * Dumps a node
+ */
static void vcg_dump_node(pattern_dumper_t *self, unsigned id,
- unsigned op_code, unsigned mode_code)
+ unsigned op_code, unsigned mode_code, void *attr)
{
- ir_op *op = (ir_op *)op_code;
- ir_mode *mode = (ir_mode *)mode_code;
-
- fprintf(f, " node: {title: \"n%u\" label: \"%s%s n%u\" }\n",
- id, get_id_str(op->name), mode ? get_mode_name(mode) : "", id);
+ vcg_private_t *priv = self->data;
+ ir_op *op = stat_get_op_from_opcode(op_code);
+ ir_mode *mode = (ir_mode *)mode_code;
+ long l = attr ? *(long *)attr : 0;
+
+ if (priv->pattern_id > priv->max_pattern)
+ return;
+
+ if (attr) {
+ fprintf(priv->f, " node: {title: \"n%u_%u\" label: \"%s%s %ld n%u\" }\n",
+ priv->pattern_id, id, get_id_str(op->name), mode ? get_mode_name(mode) : "", l, id);
+ }
+ else {
+ fprintf(priv->f, " node: {title: \"n%u_%u\" label: \"%s%s n%u\" }\n",
+ priv->pattern_id, id, get_id_str(op->name), mode ? get_mode_name(mode) : "", id);
+ }
}
+/**
+ * Dumps an edge.
+ */
static void vcg_dump_edge(pattern_dumper_t *self, unsigned id, unsigned parent, unsigned position)
{
- fprintf(f, " edge: { sourcename: \"n%u\" targetname: \"n%u\"}\n", parent, id);
+ vcg_private_t *priv = self->data;
+
+ if (priv->pattern_id > priv->max_pattern)
+ return;
+
+ fprintf(priv->f, " edge: { sourcename: \"n%u_%u\" targetname: \"n%u_%u\"}\n",
+ priv->pattern_id, parent,
+ priv->pattern_id, id);
}
/**
* The VCG dumper.
*/
-pattern_dumper_t vcg_dump = {
+static pattern_dumper_t vcg_dump = {
vcg_dump_new_pattern,
vcg_dump_finish_pattern,
vcg_dump_node,
vcg_dump_edge,
NULL,
NULL,
+ vcg_dump_start,
+ vcg_dump_end,
+ NULL
};
/**
*/
static void stdout_dump_new_pattern(pattern_dumper_t *self, counter_t *cnt)
{
- printf("%8u ", cnt->cnt[0]);
+ FILE *f = self->data;
+
+ fprintf(f, "%8u ", cnt->cnt[0]);
}
-/*
+/**
* Finishes current pattern
*/
static void stdout_dump_finish_pattern(pattern_dumper_t *self)
{
- printf("\n");
+ FILE *f = self->data;
+
+ fprintf(f, "\n");
}
/**
* Dumps a node
*/
-static void stdout_dump_node(pattern_dumper_t *self, unsigned id, unsigned op_code, unsigned mode_code)
+static void stdout_dump_node(pattern_dumper_t *self, unsigned id, unsigned op_code, unsigned mode_code, void *attr)
{
- ir_op *op = (ir_op *)op_code;
+ FILE *f = self->data;
+ ir_op *op = stat_get_op_from_opcode(op_code);
ir_mode *mode = (ir_mode *)mode_code;
/* if (env->options & OPT_ENC_GRAPH) */
- printf("%u:", id);
+ fprintf(f, "%u:", id);
- printf("%s", get_id_str(op->name));
+ fprintf(f, "%s", get_id_str(op->name));
if (mode)
- printf("%s", get_mode_name(mode));
+ fprintf(f, "%s", get_mode_name(mode));
}
/**
*/
static void stdout_dump_ref(pattern_dumper_t *self, unsigned id)
{
- printf("REF:%u", id);
+ FILE *f = self->data;
+
+ fprintf(f, "REF:%u", id);
}
/**
*/
static void stdout_dump_edge(pattern_dumper_t *self, unsigned id, unsigned parent, unsigned position)
{
+ FILE *f = self->data;
+
if (position > 0)
- printf(", ");
+ fprintf(f, ", ");
}
/**
*/
static void stdout_start_children(pattern_dumper_t *self, unsigned id)
{
- printf("(");
+ FILE *f = self->data;
+
+ fprintf(f, "(");
}
/**
*/
static void stdout_finish_children(pattern_dumper_t *self, unsigned id)
{
- printf(")");
+ FILE *f = self->data;
+
+ fprintf(f, ")");
}
/**
* The stdout dumper.
*/
-pattern_dumper_t stdout_dump = {
+static const pattern_dumper_t stdout_dump = {
stdout_dump_new_pattern,
stdout_dump_finish_pattern,
stdout_dump_node,
stdout_dump_edge,
stdout_start_children,
stdout_finish_children,
+ NULL,
+ NULL,
+ NULL
};
/* ------------------------------------ API ------------------------------------- */
/*
* Dumps a node
*/
-void pattern_dump_node(pattern_dumper_t *self, unsigned id, unsigned op_code, unsigned mode_code)
+void pattern_dump_node(pattern_dumper_t *self, unsigned id, unsigned op_code, unsigned mode_code, void *attr)
{
if (self->dump_node)
- self->dump_node(self, id, op_code, mode_code);
+ self->dump_node(self, id, op_code, mode_code, attr);
}
/*
if (self->dump_finish_children)
self->dump_finish_children(self, id);
}
+
+/*
+ * finishes the dumper
+ */
+void pattern_end(pattern_dumper_t *self)
+{
+ if (self->dump_end)
+ self->dump_end(self);
+
+ free(self);
+}
+
+/**
+ * pattern dumper factory for text dumper
+ */
+pattern_dumper_t *new_text_dumper(void)
+{
+ pattern_dumper_t *res = malloc(sizeof(*res));
+
+ if (res) {
+ memcpy(res, &stdout_dump, sizeof(*res));
+ res->data = stdout;
+
+ if (res->dump_start)
+ res->dump_start(res);
+ }
+ return res;
+}
+
+/**
+ * pattern dumper factory for vcg dumper
+ */
+pattern_dumper_t *new_vcg_dumper(const char *vcg_name, unsigned max_pattern)
+{
+ pattern_dumper_t *res = malloc(sizeof(*res) + sizeof(vcg_private_t));
+ vcg_private_t *priv;
+
+ if (res) {
+ FILE *f;
+
+ memcpy(res, &vcg_dump, sizeof(*res));
+
+ priv = (vcg_private_t *)(res + 1);
+ memset(priv, 0, sizeof(*priv));
+
+ f = fopen(vcg_name, "w");
+ priv->f = f;
+ priv->pattern_id = 0;
+ priv->max_pattern = max_pattern ? max_pattern : (unsigned)-1;
+ res->data = priv;
+
+ if (res->dump_start)
+ res->dump_start(res);
+ }
+
+ return res;
+}
#include "counter.h"
typedef struct _pattern_dumper_t pattern_dumper_t;
-typedef void (*DUMP_NEW_PATTERN_FUNC)(pattern_dumper_t *self, counter_t *cnt);
-typedef void (*DUMP_FINISH_PATTERN_FUNC)(pattern_dumper_t *self);
-typedef void (*DUMP_NODE_FUNC)(pattern_dumper_t *self, unsigned id, unsigned op_code, unsigned mode_code);
-typedef void (*DUMP_REF_FUNC)(pattern_dumper_t *self, unsigned id);
-typedef void (*DUMP_EDGE_FUNC)(pattern_dumper_t *self, unsigned id, unsigned parent, unsigned position);
-typedef void (*DUMP_START_CHILDREN_FUNC)(pattern_dumper_t *self, unsigned id);
-typedef void (*DUMP_FINISH_CHILDREN_FUNC)(pattern_dumper_t *self, unsigned id);
-
-struct _pattern_dumper_t {
- DUMP_NEW_PATTERN_FUNC dump_new_pattern;
- DUMP_FINISH_PATTERN_FUNC dump_finish_pattern;
- DUMP_NODE_FUNC dump_node;
- DUMP_REF_FUNC dump_ref;
- DUMP_EDGE_FUNC dump_edge;
- DUMP_START_CHILDREN_FUNC dump_start_children;
- DUMP_FINISH_CHILDREN_FUNC dump_finish_children;
-};
-
-extern pattern_dumper_t vcg_dump, stdout_dump;
/**
* starts a new pattern
/**
* Dumps a node
*/
-void pattern_dump_node(pattern_dumper_t *self, unsigned id, unsigned op_code, unsigned mode_code);
+void pattern_dump_node(pattern_dumper_t *self, unsigned id, unsigned op_code, unsigned mode_code, void *attr);
/**
* Dump a ref
void pattern_start_children(pattern_dumper_t *self, unsigned id);
/**
- * finishes childred dumper
+ * finishes childred dumper
*/
void pattern_finish_children(pattern_dumper_t *self, unsigned id);
+/**
+ * finishes dumper, destroyes the dumper object
+ */
+void pattern_end(pattern_dumper_t *self);
+
+/**
+ * pattern dumper factory for text dumper
+ */
+pattern_dumper_t *new_text_dumper(void);
+
+/**
+ * pattern dumper factory for vcg dumper
+ *
+ * @param vcg_name name of the VCG file
+ * @param max_pattern maximum number of pattern to be dumped
+ */
+pattern_dumper_t *new_vcg_dumper(const char *vcg_name, unsigned max_pattern);
+
#endif /* _PATTERN_DMP_H_ */