- detect non-strict functions
[libfirm] / ir / stat / firmstat.c
index eacad20..1e7dd4b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1995-2007 University of Karlsruhe.  All right reserved.
+ * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
  *
  * This file is part of libFirm.
  *
@@ -73,6 +73,9 @@ static ir_op _op_ModC;
 /** The Div by Const node. */
 static ir_op _op_DivModC;
 
+/** The Quot by Const node. */
+static ir_op _op_QuotC;
+
 /** The memory Proj node. */
 static ir_op _op_ProjM;
 
@@ -96,7 +99,7 @@ static ir_op _op_SelSelSel;
 /**
  * global status
  */
-static const int status_disable = 0;
+static const unsigned status_disable = 0;
 static stat_info_t *status = (stat_info_t *)&status_disable;
 
 /**
@@ -136,6 +139,7 @@ static int block_cmp(const void *elt, const void *key) {
        const block_entry_t *e1 = elt;
        const block_entry_t *e2 = key;
 
+       /* it's enough to compare the block number */
        return e1->block_nr != e2->block_nr;
 }  /* block_cmp */
 
@@ -259,7 +263,7 @@ static ir_op *opcode_find_entry(ir_opcode code, hmap_ir_op *hmap) {
 static void graph_clear_entry(graph_entry_t *elem, int all) {
        int i;
 
-       /* clear accumulated / non-acumulated counter */
+       /* clear accumulated / non-accumulated counter */
        for (i = all ? 0 : _gcnt_non_acc; i < _gcnt_last; ++i) {
                cnt_clr(&elem->cnt[i]);
        }  /* for */
@@ -526,6 +530,15 @@ static perm_stat_entry_t *perm_stat_get_entry(struct obstack *obst, ir_node *per
        return pset_insert(hmap, elem, HASH_PTR(perm));
 }  /* perm_stat_get_entry */
 
+/**
+ * Clear optimizations counter,
+ */
+static void clear_optimization_counter(void)  {
+       int i;
+       for (i = 0; i < FS_OPT_MAX; ++i)
+               cnt_clr(&status->num_opts[i]);
+}
+
 /**
  * Returns the ir_op for an IR-node,
  * handles special cases and return pseudo op codes.
@@ -554,34 +567,40 @@ static ir_op *stat_get_irn_op(ir_node *node)
                }  /* if */
                break;
        case iro_Mul:
-               if (get_irn_op(get_Mul_left(node)) == op_Const || get_irn_op(get_Mul_right(node)) == op_Const) {
+               if (is_Const(get_Mul_left(node)) || is_Const(get_Mul_right(node))) {
                        /* special case, a Multiply by a const, count on extra counter */
                        op = status->op_MulC ? status->op_MulC : op;
                }  /* if */
                break;
        case iro_Div:
-               if (get_irn_op(get_Div_right(node)) == op_Const) {
+               if (is_Const(get_Div_right(node))) {
                        /* special case, a division by a const, count on extra counter */
                        op = status->op_DivC ? status->op_DivC : op;
                }  /* if */
                break;
        case iro_Mod:
-               if (get_irn_op(get_Mod_right(node)) == op_Const) {
+               if (is_Const(get_Mod_right(node))) {
                        /* special case, a module by a const, count on extra counter */
                        op = status->op_ModC ? status->op_ModC : op;
                }  /* if */
                break;
        case iro_DivMod:
-               if (get_irn_op(get_DivMod_right(node)) == op_Const) {
+               if (is_Const(get_DivMod_right(node))) {
                        /* special case, a division/modulo by a const, count on extra counter */
                        op = status->op_DivModC ? status->op_DivModC : op;
                }  /* if */
                break;
+       case iro_Quot:
+               if (is_Const(get_Quot_right(node))) {
+                       /* special case, a floating point division by a const, count on extra counter */
+                       op = status->op_QuotC ? status->op_QuotC : op;
+               }  /* 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 */
@@ -608,6 +627,11 @@ static void undate_block_info(ir_node *node, graph_entry_t *graph)
        if (op == op_Block) {
                arity = get_irn_arity(node);
                b_entry = block_get_entry(&graph->recalc_cnts, get_irn_node_nr(node), graph->block_hash);
+               /* mark start end block to allow to filter them out */
+               if (node == get_irg_start_block(graph->irg))
+                       b_entry->is_start = 1;
+               else if (node == get_irg_end_block(graph->irg))
+                       b_entry->is_end = 1;
 
                /* count all incoming edges */
                for (i = 0; i < arity; ++i) {
@@ -633,7 +657,7 @@ static void undate_block_info(ir_node *node, graph_entry_t *graph)
        cnt_inc(&b_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);
@@ -698,7 +722,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);
@@ -780,7 +804,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);
@@ -789,6 +813,8 @@ static void stat_update_call(ir_node *call, graph_entry_t *graph)
                        /* it is recursive, if it calls at least once */
                        if (callee == graph->irg)
                                graph->is_recursive = 1;
+                       if (callee == NULL)
+                               cnt_inc(&graph->cnt[gcnt_external_calls]);
                }  /* if */
        } else {
                /* indirect call, be could not predict */
@@ -799,7 +825,7 @@ static void stat_update_call(ir_node *call, graph_entry_t *graph)
        }  /* if */
 
        /* check, if it's a chain-call: Then, the call-block
-       * must dominate the end block. */
+        * must dominate the end block. */
        {
                ir_node *curr = get_irg_end_block(graph->irg);
                int depth = get_Block_dom_depth(block);
@@ -846,7 +872,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);
@@ -944,7 +970,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);
 
@@ -963,12 +989,6 @@ static void update_node_stat(ir_node *node, void *env)
        /* handle statistics for special node types */
 
        switch (op->code) {
-       case iro_Const:
-               if (status->stat_options & FIRMSTAT_COUNT_CONSTS) {
-                       /* check properties of constants */
-                       stat_update_const(status, node, graph);
-               }  /* if */
-               break;
        case iro_Call:
                /* check for properties that depends on calls like recursion/leaf/indirect call */
                stat_update_call(node, graph);
@@ -981,9 +1001,33 @@ 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 */
+
+       /* we want to count the constant IN nodes, not the CSE'ed constant's itself */
+       if (status->stat_options & FIRMSTAT_COUNT_CONSTS) {
+               int i;
+
+               for (i = get_irn_arity(node) - 1; i >= 0; --i) {
+                       ir_node *pred = get_irn_n(node, i);
+
+                       if (is_Const(pred)) {
+                               /* check properties of constants */
+                               stat_update_const(status, pred, graph);
+                       }  /* if */
+               }  /* for */
+       }  /* if */
 }  /* update_node_stat */
 
 /**
@@ -1152,6 +1196,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);
@@ -1265,15 +1310,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 */
@@ -1325,10 +1368,22 @@ static void stat_dump_param_tbl(const distrib_tbl_t *tbl, graph_entry_t *global)
        dumper_t *dumper;
 
        for (dumper = status->dumper; dumper; dumper = dumper->next) {
-               if (dumper->dump_const_tbl)
+               if (dumper->dump_param_tbl)
                        dumper->dump_param_tbl(dumper, tbl, global);
        }  /* for */
-}
+}  /* stat_dump_param_tbl */
+
+/**
+ * Dumps the optimization counter
+ */
+static void stat_dump_opt_cnt(const counter_t *tbl, unsigned len) {
+       dumper_t *dumper;
+
+       for (dumper = status->dumper; dumper; dumper = dumper->next) {
+               if (dumper->dump_opt_cnt)
+                       dumper->dump_opt_cnt(dumper, tbl, len);
+       }  /* for */
+}  /* stat_dump_opt_cnt */
 
 /**
  * Initialize the dumper.
@@ -1506,6 +1561,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;
@@ -1612,12 +1668,18 @@ static void stat_irg_block_walk(void *ctx, ir_graph *irg, ir_node *node, generic
  *
  * @param n     the IR node that will be removed
  * @param hmap  the hash map containing ir_op* -> opt_entry_t*
+ * @param kind  the optimization kind
  */
-static void removed_due_opt(ir_node *n, hmap_opt_entry_t *hmap) {
-       ir_op *op          = stat_get_irn_op(n);
-       opt_entry_t *entry = opt_get_entry(op, hmap);
+static void removed_due_opt(ir_node *n, hmap_opt_entry_t *hmap, hook_opt_kind kind) {
+       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 */
 
@@ -1641,6 +1703,7 @@ static void stat_merge_nodes(
                int i, j;
                graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
 
+               cnt_inc(&status->num_opts[opt]);
                if (status->reassoc_run)
                        opt = HOOK_OPT_REASSOC;
 
@@ -1662,7 +1725,7 @@ static void stat_merge_nodes(
                                                xopt = HOOK_OPT_CONFIRM_C;
                                }  /* if */
 
-                               removed_due_opt(old_node_array[i], graph->opt_hash[xopt]);
+                               removed_due_opt(old_node_array[i], graph->opt_hash[xopt], xopt);
                        }  /* if */
                }  /* for */
        }
@@ -1702,7 +1765,7 @@ static void stat_lower(void *ctx, ir_node *node) {
        {
                graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
 
-               removed_due_opt(node, graph->opt_hash[HOOK_LOWERED]);
+               removed_due_opt(node, graph->opt_hash[HOOK_LOWERED], HOOK_LOWERED);
        }
        STAT_LEAVE;
 }  /* stat_lower */
@@ -1767,7 +1830,7 @@ static void stat_strength_red(void *ctx, ir_graph *irg, ir_node *strong) {
                graph_entry_t *graph = graph_get_entry(irg, status->irg_hash);
                cnt_inc(&graph->cnt[gcnt_acc_strength_red]);
 
-               removed_due_opt(strong, graph->opt_hash[HOOK_OPT_STRENGTH_RED]);
+               removed_due_opt(strong, graph->opt_hash[HOOK_OPT_STRENGTH_RED], HOOK_OPT_STRENGTH_RED);
        }
        STAT_LEAVE;
 }  /* stat_strength_red */
@@ -1840,7 +1903,7 @@ static void stat_arch_dep_replace_mul_with_shifts(void *ctx, ir_node *mul) {
        STAT_ENTER;
        {
                graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
-               removed_due_opt(mul, graph->opt_hash[HOOK_OPT_ARCH_DEP]);
+               removed_due_opt(mul, graph->opt_hash[HOOK_OPT_ARCH_DEP], HOOK_OPT_ARCH_DEP);
        }
        STAT_LEAVE;
 }  /* stat_arch_dep_replace_mul_with_shifts */
@@ -1859,7 +1922,7 @@ static void stat_arch_dep_replace_division_by_const(void *ctx, ir_node *node) {
        STAT_ENTER;
        {
                graph_entry_t *graph = graph_get_entry(current_ir_graph, status->irg_hash);
-               removed_due_opt(node, graph->opt_hash[HOOK_OPT_ARCH_DEP]);
+               removed_due_opt(node, graph->opt_hash[HOOK_OPT_ARCH_DEP], HOOK_OPT_ARCH_DEP);
        }
        STAT_LEAVE;
 }  /* stat_arch_dep_replace_division_by_const */
@@ -2097,6 +2160,10 @@ void stat_dump_snapshot(const char *name, const char *phase)
                /* 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);
@@ -2129,8 +2196,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;
@@ -2191,6 +2257,9 @@ void firm_init_stat(unsigned enable_options)
                _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;
@@ -2198,6 +2267,7 @@ void firm_init_stat(unsigned enable_options)
                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;
@@ -2206,6 +2276,7 @@ void firm_init_stat(unsigned enable_options)
                status->op_DivC    = NULL;
                status->op_ModC    = NULL;
                status->op_DivModC = NULL;
+               status->op_QuotC   = NULL;
        }  /* if */
 
        /* for Florian: count the Sel depth */
@@ -2239,6 +2310,8 @@ void firm_init_stat(unsigned enable_options)
        /* distribution table for parameter counts */
        status->dist_param_cnt = stat_new_int_distrib_tbl();
 
+       clear_optimization_counter();
+
 #undef HOOK
 #undef X
 }  /* firm_init_stat */