fix weak external functions
[libfirm] / ir / stat / firmstat.c
index e1d6fa1..e05961f 100644 (file)
  * @author  Michael Beck
  * @version $Id$
  */
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+#include "config.h"
 
 #ifdef FIRM_STATISTICS
 
 #include <stdio.h>
-
-#ifdef HAVE_STDLIB_H
-# include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-# include <string.h>
-#endif
+#include <stdlib.h>
+#include <string.h>
 
 #include "irouts.h"
 #include "irdump.h"
 #include "hashptr.h"
 #include "firmstat_t.h"
+#include "irpass_t.h"
 #include "pattern.h"
 #include "dags.h"
 #include "stat_dmp.h"
@@ -212,10 +206,12 @@ static void opcode_clear_entry(node_entry_t *elem) {
        cnt_clr(&elem->cnt_alive);
        cnt_clr(&elem->new_node);
        cnt_clr(&elem->into_Id);
+       cnt_clr(&elem->normalized);
 }  /* opcode_clear_entry */
 
 /**
- * Returns the associates node_entry_t for an ir_op
+ * Returns the associates node_entry_t for an ir_op (and allocates
+ * one if not yet available).
  *
  * @param op    the IR operation
  * @param hmap  a hash map containing ir_op* -> node_entry_t*
@@ -230,8 +226,7 @@ static node_entry_t *opcode_get_entry(const ir_op *op, hmap_node_entry_t *hmap)
        if (elem)
                return elem;
 
-       elem = obstack_alloc(&status->cnts, sizeof(*elem));
-       memset(elem, 0, sizeof(*elem));
+       elem = OALLOCZ(&status->cnts, node_entry_t);
 
        /* clear counter */
        opcode_clear_entry(elem);
@@ -285,7 +280,7 @@ static void graph_clear_entry(graph_entry_t *elem, int all) {
 /**
  * Returns the associated graph_entry_t for an IR graph.
  *
- * @param irg   the IR graph
+ * @param irg   the IR graph, NULL for the global counter
  * @param hmap  the hash map containing ir_graph* -> graph_entry_t*
  */
 static graph_entry_t *graph_get_entry(ir_graph *irg, hmap_graph_entry_t *hmap)
@@ -307,8 +302,7 @@ static graph_entry_t *graph_get_entry(ir_graph *irg, hmap_graph_entry_t *hmap)
        }  /* if */
 
        /* allocate a new one */
-       elem = obstack_alloc(&status->cnts, sizeof(*elem));
-       memset(elem, 0, sizeof(*elem));
+       elem = OALLOCZ(&status->cnts, graph_entry_t);
        obstack_init(&elem->recalc_cnts);
 
        /* clear counter */
@@ -353,8 +347,7 @@ static opt_entry_t *opt_get_entry(const ir_op *op, hmap_opt_entry_t *hmap)
        if (elem)
                return elem;
 
-       elem = obstack_alloc(&status->cnts, sizeof(*elem));
-       memset(elem, 0, sizeof(*elem));
+       elem = OALLOCZ(&status->cnts, opt_entry_t);
 
        /* clear new counter */
        opt_clear_entry(elem);
@@ -391,8 +384,7 @@ static block_entry_t *block_get_entry(struct obstack *obst, long block_nr, hmap_
        if (elem)
                return elem;
 
-       elem = obstack_alloc(obst, sizeof(*elem));
-       memset(elem, 0, sizeof(*elem));
+       elem = OALLOCZ(obst, block_entry_t);
 
        /* clear new counter */
        block_clear_entry(elem);
@@ -438,8 +430,7 @@ static be_block_entry_t *be_block_get_entry(struct obstack *obst, long block_nr,
        if (elem)
                return elem;
 
-       elem = obstack_alloc(obst, sizeof(*elem));
-       memset(elem, 0, sizeof(*elem));
+       elem = OALLOCZ(obst, be_block_entry_t);
 
        /* clear new counter */
        be_block_clear_entry(elem);
@@ -477,8 +468,7 @@ static perm_class_entry_t *perm_class_get_entry(struct obstack *obst, const char
        if (elem)
                return elem;
 
-       elem = obstack_alloc(obst, sizeof(*elem));
-       memset(elem, 0, sizeof(*elem));
+       elem = OALLOCZ(obst, perm_class_entry_t);
 
        /* clear new counter */
        perm_class_clear_entry(elem);
@@ -519,8 +509,7 @@ static perm_stat_entry_t *perm_stat_get_entry(struct obstack *obst, ir_node *per
        if (elem)
                return elem;
 
-       elem = obstack_alloc(obst, sizeof(*elem));
-       memset(elem, 0, sizeof(*elem));
+       elem = OALLOCZ(obst, perm_stat_entry_t);
 
        /* clear new counter */
        perm_stat_clear_entry(elem);
@@ -597,10 +586,10 @@ static ir_op *stat_get_irn_op(ir_node *node)
                }  /* if */
                break;
        case iro_Sel:
-               if (get_irn_op(get_Sel_ptr(node)) == op_Sel) {
+               if (is_Sel(get_Sel_ptr(node))) {
                        /* 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) {
+                       if (is_Sel(get_Sel_ptr(get_Sel_ptr(node)))) {
                                /* special case, a Sel of a Sel of a Sel, count on extra counter */
                                op = status->op_SelSelSel ? status->op_SelSelSel : op;
                        }  /* if */
@@ -722,7 +711,7 @@ static void update_extbb_info(ir_node *node, graph_entry_t *graph)
        cnt_inc(&eb_entry->cnt[bcnt_nodes]);
 
        /* don't count keep-alive edges */
-       if (get_irn_op(node) == op_End)
+       if (is_End(node))
                return;
 
        arity = get_irn_arity(node);
@@ -804,7 +793,7 @@ static void stat_update_call(ir_node *call, graph_entry_t *graph)
        /* found a call, this function is not a leaf */
        graph->is_leaf = 0;
 
-       if (get_irn_op(ptr) == op_SymConst) {
+       if (is_SymConst(ptr)) {
                if (get_SymConst_kind(ptr) == symconst_addr_ent) {
                        /* ok, we seems to know the entity */
                        ent = get_SymConst_entity(ptr);
@@ -872,7 +861,7 @@ static void stat_update_call_2(ir_node *call, graph_entry_t *graph)
        if (is_Bad(block))
                return;
 
-       if (get_irn_op(ptr) == op_SymConst) {
+       if (is_SymConst(ptr)) {
                if (get_SymConst_kind(ptr) == symconst_addr_ent) {
                        /* ok, we seems to know the entity */
                        ent = get_SymConst_entity(ptr);
@@ -970,7 +959,7 @@ static void update_node_stat(ir_node *node, void *env)
        node_entry_t *entry;
 
        ir_op *op = stat_get_irn_op(node);
-       int arity = get_irn_arity(node);
+       int i, arity = get_irn_arity(node);
 
        entry = opcode_get_entry(op, graph->opcode_hash);
 
@@ -1001,6 +990,16 @@ static void update_node_stat(ir_node *node, void *env)
                /* check address properties */
                stat_update_address(get_Store_ptr(node), graph);
                break;
+       case iro_Phi:
+               /* check for non-strict Phi nodes */
+               for (i = arity - 1; i >= 0; --i) {
+                       ir_node *pred = get_Phi_pred(node, i);
+                       if (is_Unknown(pred)) {
+                               /* found an Unknown predecessor, graph is not strict */
+                               graph->is_strict = 0;
+                               break;
+                       }
+               }
        default:
                ;
        }  /* switch */
@@ -1186,6 +1185,7 @@ static void update_graph_stat(graph_entry_t *global, graph_entry_t *graph)
        graph->is_leaf_call  = LCS_UNKNOWN;
        graph->is_recursive  = 0;
        graph->is_chain_call = 1;
+       graph->is_strict     = 1;
 
        /* create new block counter */
        graph->block_hash = new_pset(block_cmp, 5);
@@ -1299,15 +1299,13 @@ static void update_graph_stat_2(graph_entry_t *global, graph_entry_t *graph)
  * Register a dumper.
  */
 static void stat_register_dumper(const dumper_t *dumper) {
-       dumper_t *p = xmalloc(sizeof(*p));
+       dumper_t *p = XMALLOC(dumper_t);
 
-       if (p) {
-               memcpy(p, dumper, sizeof(*p));
+       memcpy(p, dumper, sizeof(*p));
 
-               p->next        = status->dumper;
-               p->status      = status;
-               status->dumper = p;
-       }
+       p->next        = status->dumper;
+       p->status      = status;
+       status->dumper = p;
 
        /* FIXME: memory leak */
 }  /* stat_register_dumper */
@@ -1529,6 +1527,36 @@ static void stat_turn_into_id(void *ctx, ir_node *node) {
        STAT_LEAVE;
 }  /* stat_turn_into_id */
 
+/**
+ * Hook: A node is normalized
+ *
+ * @param ctx   the hook context
+ * @param node  the IR node that was normalized
+ */
+static void stat_normalize(void *ctx, ir_node *node) {
+       (void) ctx;
+       if (! status->stat_options)
+               return;
+
+       STAT_ENTER;
+       {
+               node_entry_t *entry;
+               graph_entry_t *graph;
+               ir_op *op = stat_get_irn_op(node);
+
+               /* increase global value */
+               graph = graph_get_entry(NULL, status->irg_hash);
+               entry = opcode_get_entry(op, graph->opcode_hash);
+               cnt_inc(&entry->normalized);
+
+               /* increase local value */
+               graph = graph_get_entry(current_ir_graph, status->irg_hash);
+               entry = opcode_get_entry(op, graph->opcode_hash);
+               cnt_inc(&entry->normalized);
+       }
+       STAT_LEAVE;
+}  /* stat_normalize */
+
 /**
  * Hook: A new graph was created
  *
@@ -1552,6 +1580,7 @@ static void stat_new_graph(void *ctx, ir_graph *irg, ir_entity *ent) {
                graph->is_leaf_call  = 0;
                graph->is_recursive  = 0;
                graph->is_chain_call = 0;
+               graph->is_strict     = 1;
                graph->is_analyzed   = 0;
        }
        STAT_LEAVE;
@@ -1661,14 +1690,15 @@ static void stat_irg_block_walk(void *ctx, ir_graph *irg, ir_node *node, generic
  * @param kind  the optimization kind
  */
 static void removed_due_opt(ir_node *n, hmap_opt_entry_t *hmap, hook_opt_kind kind) {
-       ir_op *op          = stat_get_irn_op(n);
-       opt_entry_t *entry = opt_get_entry(op, hmap);
+       opt_entry_t *entry;
+       ir_op *op = stat_get_irn_op(n);
 
        /* ignore CSE for Constants */
        if (kind == HOOK_OPT_CSE && (is_Const(n) || is_SymConst(n)))
                return;
 
        /* increase global value */
+       entry = opt_get_entry(op, hmap);
        cnt_inc(&entry->count);
 }  /* removed_due_opt */
 
@@ -1936,8 +1966,7 @@ void stat_be_block_regpressure(ir_graph *irg, ir_node *block, int pressure, cons
                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    = OALLOCZ(&status->be_data, reg_pressure_entry_t);
 
                rp_ent->class_name = class_name;
                rp_ent->pressure   = pressure;
@@ -2095,10 +2124,10 @@ void stat_dump_snapshot(const char *name, const char *phase)
                        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));
+               strncat(fname, "firmstat-", sizeof(fname)-1);
+               strncat(fname, phase, sizeof(fname)-1);
+               strncat(fname, "-", sizeof(fname)-1);
+               strncat(fname, p, sizeof(fname)-1);
 
                stat_dump_init(fname);
 
@@ -2157,7 +2186,7 @@ void stat_dump_snapshot(const char *name, const char *phase)
 
                stat_finish_pattern_history(fname);
 
-               /* clear the global counter here */
+               /* clear the global counters here */
                {
                        node_entry_t *entry;
 
@@ -2165,12 +2194,66 @@ void stat_dump_snapshot(const char *name, const char *phase)
                                opcode_clear_entry(entry);
                        }  /* for */
                        /* clear all global counter */
-                       graph_clear_entry(global, 1);
+                       graph_clear_entry(global, /*all=*/1);
                }
        }
        STAT_LEAVE;
 }  /* stat_dump_snapshot */
 
+struct pass_t {
+       ir_prog_pass_t pass;
+       const char     *fname;
+       const char     *phase;
+};
+
+/**
+ * Wrapper to run stat_dump_snapshot() as a ir_prog wrapper.
+ */
+static int stat_dump_snapshot_wrapper(ir_prog *irp, void *context) {
+       struct pass_t *pass = context;
+
+       (void)irp;
+       stat_dump_snapshot(pass->fname, pass->phase);
+       return 0;
+}  /* stat_dump_snapshot_wrapper */
+
+/**
+ * Ensure that no verifier is run from the wrapper.
+ */
+static int no_verify(ir_prog *prog, void *ctx)
+{
+       (void)prog;
+       (void)ctx;
+       return 0;
+}
+
+/**
+ * Ensure that no dumper is run from the wrapper.
+ */
+static void no_dump(ir_prog *prog, void *ctx, unsigned idx)
+{
+       (void)prog;
+       (void)ctx;
+       (void)idx;
+}
+
+/* create an ir_pog pass */
+ir_prog_pass_t *stat_dump_snapshot_pass(
+       const char *name, const char *fname, const char *phase) {
+       struct pass_t *pass = XMALLOCZ(struct pass_t);
+
+       def_prog_pass_constructor(
+               &pass->pass, name ? name : "stat_snapshot", stat_dump_snapshot_wrapper);
+       pass->fname = fname;
+       pass->phase = phase;
+
+       /* no dump/verify */
+       pass->pass.dump_irprog   = no_dump;
+       pass->pass.verify_irprog = no_verify;
+
+       return &pass->pass;
+}  /* stat_dump_snapshot_pass */
+
 /** the hook entries for the Firm statistics module */
 static hook_entry_t stat_hooks[hook_last];
 
@@ -2185,8 +2268,7 @@ void firm_init_stat(unsigned enable_options)
        if (! (enable_options & FIRMSTAT_ENABLED))
                return;
 
-       status = xmalloc(sizeof(*status));
-       memset(status, 0, sizeof(*status));
+       status = XMALLOCZ(stat_info_t);
 
        /* enable statistics */
        status->stat_options = enable_options & FIRMSTAT_ENABLED ? enable_options : 0;
@@ -2196,6 +2278,7 @@ void firm_init_stat(unsigned enable_options)
        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_normalize,                          stat_normalize);
        HOOK(hook_new_graph,                          stat_new_graph);
        HOOK(hook_free_graph,                         stat_free_graph);
        HOOK(hook_irg_walk,                           stat_irg_walk);