diff options
Diffstat (limited to 'lib/hipe/ssa/hipe_ssa_copy_prop.inc')
-rw-r--r-- | lib/hipe/ssa/hipe_ssa_copy_prop.inc | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/lib/hipe/ssa/hipe_ssa_copy_prop.inc b/lib/hipe/ssa/hipe_ssa_copy_prop.inc new file mode 100644 index 0000000000..311940a1fc --- /dev/null +++ b/lib/hipe/ssa/hipe_ssa_copy_prop.inc @@ -0,0 +1,198 @@ +%%% -*- Erlang -*- +%%% -*- erlang-indent-level: 2 -*- +%%% +%%% %CopyrightBegin% +%%% +%%% Copyright Ericsson AB 2003-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 : hipe_ssa_copy_prop.inc +%%% Author : Tobias Lindahl <[email protected]> +%%% Description : Copy propagation on SSA form. +%%% +%%% Created : 4 Apr 2003 by Tobias Lindahl <[email protected]> +%%%------------------------------------------------------------------- + +-export([cfg/1]). + +%%-------------------------------------------------------------------- +%% Two passes through the code visiting the blocks in reverse +%% postorder. The first pass binds all destinations of copying moves +%% to the sources, and the second propagates the copies and removes +%% the copying moves. +%% +%% Problem: +%% Since phi-nodes are implemented as instructions they are not +%% atomic. If we are not careful we can get the situation (after propagation): +%% +%% v0 = phi(v0, v2) +%% v1 = phi(v0, v3) +%% ^^ +%% where the underlined v0 really corresponds to the v0 before the first +%% phi-instruction. +%% +%% Solution: +%% * Find all dependencies between the uses of a phi-instruction to +%% the destination of any earlier phi-instruction in the same phi-node; +%% * Keep the copying move that defines the variable used in the +%% latter phi-instruction; and +%% * Do not propagate the copy into the phi-instruction +%% +%%-------------------------------------------------------------------- + +-spec cfg(#cfg{}) -> #cfg{}. + +cfg(Cfg) -> + Labels = ?cfg:reverse_postorder(Cfg), + {Info,PhiDep} = analyse(Labels, Cfg, gb_trees:empty(), gb_trees:empty()), + rewrite(Labels, Cfg, Info, PhiDep). + +analyse([Label|Left], Cfg, Info, PhiDep) -> + BB = ?cfg:bb(Cfg, Label), + Code = hipe_bb:code(BB), + NewPhiDep = get_phi_dep(Code, gb_sets:empty(), PhiDep), + NewInfo = analyse_code(Code, Info), + analyse(Left, Cfg, NewInfo, NewPhiDep); +analyse([], _Cfg, Info, PhiDep) -> + {Info,PhiDep}. + +get_phi_dep([I|Left], Defined, Dep) -> + case ?code:is_phi(I) of + true -> + Use = ?code:uses(I), + [Def] = ?code:defines(I), + NewDep = add_dep(Use, Defined, Dep), + get_phi_dep(Left, gb_sets:insert(Def, Defined), NewDep); + false -> + Dep + end; +get_phi_dep([], _Defined, Dep) -> + Dep. + +add_dep([Use|Left], Defined, Dep) -> + case gb_trees:lookup(Use, Dep) of + none -> + add_dep(Left, Defined, gb_trees:insert(Use, Defined, Dep)); + {value, Set} -> + NewSet = gb_sets:union(Defined, Set), + add_dep(Left, Defined, gb_trees:enter(Use, NewSet, Dep)) + end; +add_dep([], _Defined, Dep) -> + Dep. + +has_dep(Use, Def, Dep) -> + case gb_trees:lookup(Use, Dep) of + none -> + false; + {value, Set} -> + gb_sets:is_member(Def, Set) + end. + +analyse_code([I|Left], Info) -> + case ?code:is_move(I) of + true -> + NewInfo = get_info_move(I, Info), + analyse_code(Left, NewInfo); + false -> + analyse_code(Left, Info) + end; +analyse_code([], Info) -> + Info. + +get_info_move(I, Info) -> + case ?code:uses(I) of + [] -> %% Constant. + Info; + [Src] -> + add_binding(?code:defines(I), Src, Info) + end. + +rewrite([Label|Left], Cfg, Info, PhiDep) -> + BB = ?cfg:bb(Cfg, Label), + Code = hipe_bb:code(BB), + NewCode = rewrite_code(Code, Info, PhiDep, []), + NewBB = hipe_bb:code_update(BB, NewCode), + rewrite(Left, ?cfg:bb_add(Cfg, Label, NewBB), Info, PhiDep); +rewrite([], Cfg, _Info, _PhiDep) -> + Cfg. + +rewrite_code([I|Left], Info, PhiDep, Acc) -> + case ?code:is_move(I) of + true -> + Fun = fun(X, Y) -> ?code:mk_move(X, Y) end, + NewI = rewrite_move(I, Fun, Info, PhiDep), + rewrite_code(Left, Info, PhiDep, NewI++Acc); + false -> + NewI = rewrite_instr(I, Info, PhiDep), + rewrite_code(Left, Info, PhiDep, [NewI|Acc]) + end; +rewrite_code([], _Info, _PhiDep, Acc) -> + lists:reverse(Acc). + +rewrite_move(I, Fun, Info, PhiDep) -> + case ?code:uses(I) of + [] ->%% Constant move. Keep it! + [I]; + _ -> + Dst = hd(?code:defines(I)), + case gb_trees:lookup(Dst, Info) of + {value, Root} -> + case has_dep(Dst, Root, PhiDep) of + true -> %% Must keep the copying move! + [Fun(Dst, Root)]; + false -> + [] + end; + none -> + [] + end + end. + +rewrite_instr(I, Info, PhiDep) -> + rewrite_instr0(I, ?code:uses(I), Info, PhiDep, []). + +rewrite_instr0(I, [Key|Left], Info, PhiDep, UpdateInfo) -> + case gb_trees:lookup(Key, Info) of + none -> + rewrite_instr0(I, Left, Info, PhiDep, UpdateInfo); + {value, Root} -> + case gb_trees:lookup(Key, Info) of + {value, Root} -> + case has_dep(Key, Root, PhiDep) of + true -> %% Must keep Key! + rewrite_instr0(I, Left, Info, PhiDep, UpdateInfo); + false -> + rewrite_instr0(I, Left, Info, PhiDep, [{Key, Root}|UpdateInfo]) + end; + _ -> + rewrite_instr0(I, Left, Info, PhiDep, UpdateInfo) + end + end; +rewrite_instr0(I, [], _Info, _PhiDep, UpdateInfo) -> + ?code:subst(UpdateInfo, I). + +add_binding([Key|Left], Val, Info) -> + %% Make sure the key is bound to the end of any copy-chains. + NewInfo = + case gb_trees:lookup(Val, Info) of + {value, NewVal} -> + gb_trees:insert(Key, NewVal, Info); + none -> + gb_trees:insert(Key, Val, Info) + end, + add_binding(Left, Val, NewInfo); +add_binding([], _, Info) -> + Info. |