aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/icode/hipe_icode_instruction_counter.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hipe/icode/hipe_icode_instruction_counter.erl')
-rw-r--r--lib/hipe/icode/hipe_icode_instruction_counter.erl135
1 files changed, 135 insertions, 0 deletions
diff --git a/lib/hipe/icode/hipe_icode_instruction_counter.erl b/lib/hipe/icode/hipe_icode_instruction_counter.erl
new file mode 100644
index 0000000000..92658d294a
--- /dev/null
+++ b/lib/hipe/icode/hipe_icode_instruction_counter.erl
@@ -0,0 +1,135 @@
+%% -*- erlang-indent-level: 2 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%-------------------------------------------------------------------
+%% File : icode_instruction_counter.erl
+%% Author : Andreas Hasselberg <[email protected]>
+%% Purpose : This module counts the number of different instructions
+%% in a function. It is useful when you want to know if
+%% your Icode analysis or specialization is good, bad or
+%% simply unlucky :)
+%%
+%% Created : 2 Oct 2006 by Andreas Hasselberg <[email protected]>
+%%-------------------------------------------------------------------
+
+-module(hipe_icode_instruction_counter).
+
+-export([cfg/3, compare/3]).
+
+-include("../main/hipe.hrl").
+-include("hipe_icode.hrl").
+-include("../flow/cfg.hrl").
+
+%%-------------------------------------------------------------------
+%% A general CFG instruction walktrough
+%%-------------------------------------------------------------------
+
+-spec cfg(#cfg{}, mfa(), comp_options()) -> [_].
+
+cfg(Cfg, _IcodeFun, _Options) ->
+ Labels = hipe_icode_cfg:labels(Cfg),
+ %% Your Info init function goes here
+ InitInfo = counter__init_info(),
+ Info = lists:foldl(fun (Label, InfoAcc) ->
+ BB = hipe_icode_cfg:bb(Cfg, Label),
+ Code = hipe_bb:code(BB),
+ walktrough_bb(Code, InfoAcc)
+ end, InitInfo, Labels),
+ %% counter__output_info(IcodeFun, Info),
+ Info.
+
+walktrough_bb(BB, Info) ->
+ lists:foldl(fun (Insn, InfoAcc) ->
+ %% Your analysis function here
+ counter__analys_insn(Insn, InfoAcc)
+ end, Info, BB).
+
+%%-------------------------------------------------------------------
+%% The counter specific functions
+%%-------------------------------------------------------------------
+
+-spec compare(gb_tree(), gb_tree(), gb_tree()) -> gb_tree().
+
+compare(Name, Old, New) ->
+ NewList = gb_trees:to_list(New),
+ OldList = gb_trees:to_list(Old),
+ TempTree = compare_one_way(NewList, Old, added, gb_trees:empty()),
+ DiffTree = compare_one_way(OldList, New, removed, TempTree),
+ DiffList = gb_trees:to_list(DiffTree),
+ if DiffList =:= [] ->
+ ok;
+ true ->
+ io:format("~p: ~p ~n", [Name, DiffList])
+ end,
+ DiffTree.
+
+compare_one_way(List, Tree, Key, Fold_tree) ->
+ lists:foldl(fun({Insn, ListCount}, DiffAcc) when is_integer(ListCount) ->
+ DiffCount =
+ case gb_trees:lookup(Insn, Tree) of
+ {value, TreeCount} when is_integer(TreeCount) ->
+ ListCount - TreeCount;
+ none ->
+ ListCount
+ end,
+ if DiffCount > 0 ->
+ gb_trees:insert({Key, Insn}, DiffCount, DiffAcc);
+ true ->
+ DiffAcc
+ end
+ end,
+ Fold_tree,
+ List).
+
+counter__init_info() ->
+ gb_trees:empty().
+
+counter__analys_insn(Insn, Info) ->
+ Key = counter__insn_get_key(Insn),
+ counter__increase_key(Key, Info).
+
+counter__insn_get_key(If = #icode_if{}) -> {'if', hipe_icode:if_op(If)};
+counter__insn_get_key(Call = #icode_call{}) -> {call, hipe_icode:call_fun(Call)};
+counter__insn_get_key(#icode_enter{}) -> enter;
+counter__insn_get_key(#icode_return{}) -> return;
+counter__insn_get_key(#icode_type{}) -> type;
+counter__insn_get_key(#icode_switch_val{}) -> switch_val;
+counter__insn_get_key(#icode_switch_tuple_arity{}) -> switch_tuple_arity;
+counter__insn_get_key(#icode_goto{}) -> goto;
+counter__insn_get_key(#icode_move{}) -> move;
+counter__insn_get_key(#icode_phi{}) -> phi;
+counter__insn_get_key(#icode_begin_try{}) -> begin_try;
+counter__insn_get_key(#icode_end_try{}) -> end_try;
+counter__insn_get_key(#icode_begin_handler{}) -> begin_handler;
+counter__insn_get_key(#icode_fail{}) -> fail;
+counter__insn_get_key(#icode_comment{}) -> comment.
+
+counter__increase_key(Key, Info) ->
+ NewCounter =
+ case gb_trees:lookup(Key, Info) of
+ {value, Counter} when is_integer(Counter) ->
+ Counter + 1;
+ none ->
+ 1
+ end,
+ gb_trees:enter(Key, NewCounter, Info).
+
+%%counter__output_info(IcodeFun, Info) ->
+%% InfoList = gb_trees:to_list(Info),
+%% io:format("~p instructions : ~p ~n", [IcodeFun, InfoList]).