aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/icode/hipe_icode_heap_test.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hipe/icode/hipe_icode_heap_test.erl')
-rw-r--r--lib/hipe/icode/hipe_icode_heap_test.erl200
1 files changed, 200 insertions, 0 deletions
diff --git a/lib/hipe/icode/hipe_icode_heap_test.erl b/lib/hipe/icode/hipe_icode_heap_test.erl
new file mode 100644
index 0000000000..92d5f023fa
--- /dev/null
+++ b/lib/hipe/icode/hipe_icode_heap_test.erl
@@ -0,0 +1,200 @@
+%% -*- erlang-indent-level: 2 -*-
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2001-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%
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Copyright (c) 2000 by Erik Johansson. All Rights Reserved
+%% ====================================================================
+%% Filename : hipe_icode_heap_test.erl
+%% Module : hipe_icode_heap_test
+%% Purpose :
+%% Notes :
+%% History : * 2000-11-07 Erik Johansson ([email protected]):
+%% Created.
+%%
+%% $Id$
+%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-module(hipe_icode_heap_test).
+
+-export([cfg/1]).
+
+-define(DO_ASSERT,true).
+
+-include("../main/hipe.hrl").
+-include("hipe_icode.hrl").
+-include("hipe_icode_primops.hrl").
+-include("../flow/cfg.hrl").
+-include("../rtl/hipe_literals.hrl").
+
+%-------------------------------------------------------------------------
+
+-spec cfg(#cfg{}) -> #cfg{}.
+
+cfg(CFG) ->
+ Icode = hipe_icode_cfg:cfg_to_linear(CFG),
+ Code = hipe_icode:icode_code(Icode),
+ ActualVmax = hipe_icode:highest_var(Code),
+ ActualLmax = hipe_icode:highest_label(Code),
+ hipe_gensym:set_label(icode, ActualLmax+1),
+ hipe_gensym:set_var(icode, ActualVmax+1),
+ EBBs = hipe_icode_ebb:cfg(CFG),
+ {EBBcode,_Visited} = ebbs(EBBs, [], CFG),
+ NewCode = add_gc_tests(EBBcode),
+ NewIcode = hipe_icode:icode_code_update(Icode, NewCode),
+ NewCFG = hipe_icode_cfg:linear_to_cfg(NewIcode),
+ %% hipe_icode_cfg:pp(NewCFG),
+ NewCFG.
+
+ebbs([EBB|EBBs], Visited, CFG) ->
+ case hipe_icode_ebb:type(EBB) of
+ node ->
+ L = hipe_icode_ebb:node_label(EBB),
+ case visited(L, Visited) of
+ true ->
+ ebbs(EBBs, Visited, CFG);
+ false ->
+ EBBCode = hipe_bb:code(hipe_icode_cfg:bb(CFG, L)),
+ case hipe_icode_ebb:node_successors(EBB) of
+ [Succ|Succs] ->
+ {[SuccCode|More], Visited1} =
+ ebbs([Succ], [L|Visited], CFG),
+ {[OtherCode|MoreOther], Visited2} =
+ ebbs(Succs ++ EBBs, Visited1, CFG),
+ {[[hipe_icode:mk_label(L)|EBBCode] ++ SuccCode|
+ More] ++ [OtherCode|MoreOther],
+ Visited2};
+ [] ->
+ {OtherCode, Visited1} = ebbs(EBBs, [L|Visited], CFG),
+ {[[hipe_icode:mk_label(L)|EBBCode] | OtherCode], Visited1}
+ end
+ end;
+ leaf ->
+ ebbs(EBBs, Visited, CFG)
+ end;
+ebbs([], Visited,_) ->
+ {[[]], Visited}.
+
+visited(L, Visited) ->
+ lists:member(L, Visited).
+
+add_gc_tests([[]|EBBCodes]) -> add_gc_tests(EBBCodes);
+add_gc_tests([EBBCode|EBBCodes]) ->
+ case need(EBBCode, 0, []) of
+ {Need, RestCode, [Lbl|Code]} ->
+ if Need > 0 ->
+ [Lbl] ++ gc_test(Need) ++ Code ++ add_gc_tests([RestCode|EBBCodes]);
+ true ->
+ [Lbl|Code] ++ add_gc_tests([RestCode|EBBCodes])
+ end;
+ {0, RestCode, []} ->
+ add_gc_tests([RestCode|EBBCodes])
+ end;
+add_gc_tests([]) -> [].
+
+need([I|Is] , Need, Code) ->
+ case split(I) of
+ true ->
+ case I of
+ #icode_call{} ->
+ case hipe_icode:call_continuation(I) of
+ [] -> %% Was fallthrough.
+ NewLab = hipe_icode:mk_new_label(),
+ LabName = hipe_icode:label_name(NewLab),
+ NewCall = hipe_icode:call_set_continuation(I,LabName),
+ {Need + need(I), [NewLab|Is], lists:reverse([NewCall|Code])};
+ _ ->
+ {Need + need(I), Is, lists:reverse([I|Code])}
+ end;
+ _ ->
+ {Need + need(I), Is, lists:reverse([I|Code])}
+ end;
+ false ->
+ need(Is, Need + need(I), [I|Code])
+ end;
+need([], Need, Code) ->
+ {Need, [], lists:reverse(Code)}.
+
+need(I) ->
+ case I of
+ #icode_call{} ->
+ primop_need(hipe_icode:call_fun(I), hipe_icode:call_args(I));
+ #icode_enter{} ->
+ primop_need(hipe_icode:enter_fun(I), hipe_icode:enter_args(I));
+ _ ->
+ 0
+ end.
+
+primop_need(Op, As) ->
+ case Op of
+ cons ->
+ 2;
+ mktuple ->
+ length(As) + 1;
+ #mkfun{} ->
+ NumFree = length(As),
+ ?ERL_FUN_SIZE + NumFree;
+ unsafe_tag_float ->
+ 3;
+ _ ->
+ 0
+ end.
+
+gc_test(Need) ->
+ L = hipe_icode:mk_new_label(),
+ [hipe_icode:mk_primop([], #gc_test{need=Need}, [],
+ hipe_icode:label_name(L),
+ hipe_icode:label_name(L)),
+ L].
+
+split(I) ->
+ case I of
+ #icode_call{} -> not known_heap_need(hipe_icode:call_fun(I));
+ #icode_enter{} -> not known_heap_need(hipe_icode:enter_fun(I));
+ _ -> false
+ end.
+
+known_heap_need(Name) ->
+ case Name of
+ %% Primops
+ cons -> true;
+ fcheckerror -> true;
+ fclearerror -> true;
+ fnegate -> true;
+ fp_add -> true;
+ fp_div -> true;
+ fp_mul -> true;
+ fp_sub -> true;
+ mktuple -> true;
+ unsafe_hd -> true;
+ unsafe_tag_float -> true;
+ unsafe_tl -> true;
+ unsafe_untag_float -> true;
+ #element{} -> true;
+ #unsafe_element{} -> true;
+ #unsafe_update_element{} -> true;
+
+ %% MFAs
+ {erlang, element, 2} -> true;
+ {erlang, length, 1} -> true;
+ {erlang, self, 0} -> true;
+ {erlang, size, 1} -> true;
+
+ _ -> false
+ end.